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> 1619a81c14SSteve Longerbeam #include <linux/module.h> 1719a81c14SSteve Longerbeam #include <linux/of_device.h> 1841d8d7f5SHugues Fruchet #include <linux/regulator/consumer.h> 1919a81c14SSteve Longerbeam #include <linux/slab.h> 2019a81c14SSteve Longerbeam #include <linux/types.h> 2119a81c14SSteve Longerbeam #include <media/v4l2-async.h> 2219a81c14SSteve Longerbeam #include <media/v4l2-ctrls.h> 2319a81c14SSteve Longerbeam #include <media/v4l2-device.h> 242d18fbc5SAkinobu Mita #include <media/v4l2-event.h> 2519a81c14SSteve Longerbeam #include <media/v4l2-fwnode.h> 2619a81c14SSteve Longerbeam #include <media/v4l2-subdev.h> 2719a81c14SSteve Longerbeam 2819a81c14SSteve Longerbeam /* min/typical/max system clock (xclk) frequencies */ 2919a81c14SSteve Longerbeam #define OV5640_XCLK_MIN 6000000 3041cb1c73SPhilipp Puschmann #define OV5640_XCLK_MAX 54000000 3119a81c14SSteve Longerbeam 3219a81c14SSteve Longerbeam #define OV5640_DEFAULT_SLAVE_ID 0x3c 3319a81c14SSteve Longerbeam 343c28588fSJacopo Mondi #define OV5640_LINK_RATE_MAX 490000000U 353c28588fSJacopo Mondi 36d47c4126SHugues Fruchet #define OV5640_REG_SYS_RESET02 0x3002 37d47c4126SHugues Fruchet #define OV5640_REG_SYS_CLOCK_ENABLE02 0x3006 38f22996dbSHugues Fruchet #define OV5640_REG_SYS_CTRL0 0x3008 393b987d70SLad Prabhakar #define OV5640_REG_SYS_CTRL0_SW_PWDN 0x42 403b987d70SLad Prabhakar #define OV5640_REG_SYS_CTRL0_SW_PWUP 0x02 4119a81c14SSteve Longerbeam #define OV5640_REG_CHIP_ID 0x300a 42f22996dbSHugues Fruchet #define OV5640_REG_IO_MIPI_CTRL00 0x300e 43f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE01 0x3017 44f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE02 0x3018 4519a81c14SSteve Longerbeam #define OV5640_REG_PAD_OUTPUT00 0x3019 46f22996dbSHugues Fruchet #define OV5640_REG_SYSTEM_CONTROL1 0x302e 4719a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL0 0x3034 4819a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL1 0x3035 4919a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL2 0x3036 5019a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL3 0x3037 5119a81c14SSteve Longerbeam #define OV5640_REG_SLAVE_ID 0x3100 52f22996dbSHugues Fruchet #define OV5640_REG_SCCB_SYS_CTRL1 0x3103 5319a81c14SSteve Longerbeam #define OV5640_REG_SYS_ROOT_DIVIDER 0x3108 5419a81c14SSteve Longerbeam #define OV5640_REG_AWB_R_GAIN 0x3400 5519a81c14SSteve Longerbeam #define OV5640_REG_AWB_G_GAIN 0x3402 5619a81c14SSteve Longerbeam #define OV5640_REG_AWB_B_GAIN 0x3404 5719a81c14SSteve Longerbeam #define OV5640_REG_AWB_MANUAL_CTRL 0x3406 5819a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_HI 0x3500 5919a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_MED 0x3501 6019a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_LO 0x3502 6119a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_MANUAL 0x3503 6219a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_REAL_GAIN 0x350a 6319a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_VTS 0x350c 643145efcdSJacopo Mondi #define OV5640_REG_TIMING_HS 0x3800 653145efcdSJacopo Mondi #define OV5640_REG_TIMING_VS 0x3802 663145efcdSJacopo Mondi #define OV5640_REG_TIMING_HW 0x3804 673145efcdSJacopo Mondi #define OV5640_REG_TIMING_VH 0x3806 6886633417SMaxime Ripard #define OV5640_REG_TIMING_DVPHO 0x3808 6986633417SMaxime Ripard #define OV5640_REG_TIMING_DVPVO 0x380a 7019a81c14SSteve Longerbeam #define OV5640_REG_TIMING_HTS 0x380c 7119a81c14SSteve Longerbeam #define OV5640_REG_TIMING_VTS 0x380e 723145efcdSJacopo Mondi #define OV5640_REG_TIMING_HOFFS 0x3810 733145efcdSJacopo Mondi #define OV5640_REG_TIMING_VOFFS 0x3812 74ce85705aSHugues Fruchet #define OV5640_REG_TIMING_TC_REG20 0x3820 7519a81c14SSteve Longerbeam #define OV5640_REG_TIMING_TC_REG21 0x3821 7619a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL00 0x3a00 7719a81c14SSteve Longerbeam #define OV5640_REG_AEC_B50_STEP 0x3a08 7819a81c14SSteve Longerbeam #define OV5640_REG_AEC_B60_STEP 0x3a0a 7919a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0D 0x3a0d 8019a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0E 0x3a0e 8119a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0F 0x3a0f 8219a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL10 0x3a10 8319a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL11 0x3a11 8419a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1B 0x3a1b 8519a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1E 0x3a1e 8619a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1F 0x3a1f 8719a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL00 0x3c00 8819a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL01 0x3c01 8919a81c14SSteve Longerbeam #define OV5640_REG_SIGMADELTA_CTRL0C 0x3c0c 9019a81c14SSteve Longerbeam #define OV5640_REG_FRAME_CTRL01 0x4202 91e3ee691dSHugues Fruchet #define OV5640_REG_FORMAT_CONTROL00 0x4300 927cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_HSIZE 0x4602 937cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_VSIZE 0x4604 942b5c18f9SChen-Yu Tsai #define OV5640_REG_JPG_MODE_SELECT 0x4713 954039b037SLad Prabhakar #define OV5640_REG_CCIR656_CTRL00 0x4730 96f22996dbSHugues Fruchet #define OV5640_REG_POLARITY_CTRL00 0x4740 9719a81c14SSteve Longerbeam #define OV5640_REG_MIPI_CTRL00 0x4800 9819a81c14SSteve Longerbeam #define OV5640_REG_DEBUG_MODE 0x4814 996c957ed7SJacopo Mondi #define OV5640_REG_PCLK_PERIOD 0x4837 100e3ee691dSHugues Fruchet #define OV5640_REG_ISP_FORMAT_MUX_CTRL 0x501f 10119a81c14SSteve Longerbeam #define OV5640_REG_PRE_ISP_TEST_SET1 0x503d 10219a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL0 0x5580 10319a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL1 0x5581 10419a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL3 0x5583 10519a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL4 0x5584 10619a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL5 0x5585 10719a81c14SSteve Longerbeam #define OV5640_REG_AVG_READOUT 0x56a1 10819a81c14SSteve Longerbeam 10919a81c14SSteve Longerbeam enum ov5640_mode_id { 11032ea5e05SHugues Fruchet OV5640_MODE_QQVGA_160_120 = 0, 11132ea5e05SHugues Fruchet OV5640_MODE_QCIF_176_144, 11219a81c14SSteve Longerbeam OV5640_MODE_QVGA_320_240, 11319a81c14SSteve Longerbeam OV5640_MODE_VGA_640_480, 11419a81c14SSteve Longerbeam OV5640_MODE_NTSC_720_480, 11519a81c14SSteve Longerbeam OV5640_MODE_PAL_720_576, 11619a81c14SSteve Longerbeam OV5640_MODE_XGA_1024_768, 11719a81c14SSteve Longerbeam OV5640_MODE_720P_1280_720, 11819a81c14SSteve Longerbeam OV5640_MODE_1080P_1920_1080, 11919a81c14SSteve Longerbeam OV5640_MODE_QSXGA_2592_1944, 12019a81c14SSteve Longerbeam OV5640_NUM_MODES, 12119a81c14SSteve Longerbeam }; 12219a81c14SSteve Longerbeam 12319a81c14SSteve Longerbeam enum ov5640_frame_rate { 12419a81c14SSteve Longerbeam OV5640_15_FPS = 0, 12519a81c14SSteve Longerbeam OV5640_30_FPS, 126e823fb16SMaxime Ripard OV5640_60_FPS, 12719a81c14SSteve Longerbeam OV5640_NUM_FRAMERATES, 12819a81c14SSteve Longerbeam }; 12919a81c14SSteve Longerbeam 13022845bf2SJacopo Mondi enum ov5640_pixel_rate_id { 13122845bf2SJacopo Mondi OV5640_PIXEL_RATE_168M, 13222845bf2SJacopo Mondi OV5640_PIXEL_RATE_148M, 13322845bf2SJacopo Mondi OV5640_PIXEL_RATE_124M, 13422845bf2SJacopo Mondi OV5640_PIXEL_RATE_96M, 13522845bf2SJacopo Mondi OV5640_PIXEL_RATE_48M, 13622845bf2SJacopo Mondi OV5640_NUM_PIXEL_RATES, 13722845bf2SJacopo Mondi }; 13822845bf2SJacopo Mondi 13922845bf2SJacopo Mondi /* 14022845bf2SJacopo Mondi * The chip manual suggests 24/48/96/192 MHz pixel clocks. 14122845bf2SJacopo Mondi * 14222845bf2SJacopo Mondi * 192MHz exceeds the sysclk limits; use 168MHz as maximum pixel rate for 14322845bf2SJacopo Mondi * full resolution mode @15 FPS. 14422845bf2SJacopo Mondi */ 14522845bf2SJacopo Mondi static const u32 ov5640_pixel_rates[] = { 14622845bf2SJacopo Mondi [OV5640_PIXEL_RATE_168M] = 168000000, 14722845bf2SJacopo Mondi [OV5640_PIXEL_RATE_148M] = 148000000, 14822845bf2SJacopo Mondi [OV5640_PIXEL_RATE_124M] = 124000000, 14922845bf2SJacopo Mondi [OV5640_PIXEL_RATE_96M] = 96000000, 15022845bf2SJacopo Mondi [OV5640_PIXEL_RATE_48M] = 48000000, 15122845bf2SJacopo Mondi }; 15222845bf2SJacopo Mondi 1537a3b8d4bSJacopo Mondi /* 1547a3b8d4bSJacopo Mondi * MIPI CSI-2 link frequencies. 1557a3b8d4bSJacopo Mondi * 1567a3b8d4bSJacopo Mondi * Derived from the above defined pixel rate for bpp = (8, 16, 24) and 1577a3b8d4bSJacopo Mondi * data_lanes = (1, 2) 1587a3b8d4bSJacopo Mondi * 1597a3b8d4bSJacopo Mondi * link_freq = (pixel_rate * bpp) / (2 * data_lanes) 1607a3b8d4bSJacopo Mondi */ 1617a3b8d4bSJacopo Mondi static const s64 ov5640_csi2_link_freqs[] = { 1627a3b8d4bSJacopo Mondi 992000000, 888000000, 768000000, 744000000, 672000000, 672000000, 1637a3b8d4bSJacopo Mondi 592000000, 592000000, 576000000, 576000000, 496000000, 496000000, 1647a3b8d4bSJacopo Mondi 384000000, 384000000, 384000000, 336000000, 296000000, 288000000, 1657a3b8d4bSJacopo Mondi 248000000, 192000000, 192000000, 192000000, 96000000, 1667a3b8d4bSJacopo Mondi }; 1677a3b8d4bSJacopo Mondi 1687a3b8d4bSJacopo Mondi /* Link freq for default mode: UYVY 16 bpp, 2 data lanes. */ 1697a3b8d4bSJacopo Mondi #define OV5640_DEFAULT_LINK_FREQ 13 1707a3b8d4bSJacopo Mondi 171b7ed3abdSLoic Poulain enum ov5640_format_mux { 172b7ed3abdSLoic Poulain OV5640_FMT_MUX_YUV422 = 0, 173b7ed3abdSLoic Poulain OV5640_FMT_MUX_RGB, 174b7ed3abdSLoic Poulain OV5640_FMT_MUX_DITHER, 175b7ed3abdSLoic Poulain OV5640_FMT_MUX_RAW_DPC, 176b7ed3abdSLoic Poulain OV5640_FMT_MUX_SNR_RAW, 177b7ed3abdSLoic Poulain OV5640_FMT_MUX_RAW_CIP, 178b7ed3abdSLoic Poulain }; 179b7ed3abdSLoic Poulain 1802d7671f6SJacopo Mondi static const struct ov5640_pixfmt { 181e3ee691dSHugues Fruchet u32 code; 182e3ee691dSHugues Fruchet u32 colorspace; 1832d7671f6SJacopo Mondi u8 bpp; 1842d7671f6SJacopo Mondi } ov5640_formats[] = { 1852d7671f6SJacopo Mondi { 1862d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_JPEG_1X8, 1872d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_JPEG, 1882d7671f6SJacopo Mondi .bpp = 16, 1892d7671f6SJacopo Mondi }, { 1902d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_UYVY8_2X8, 1912d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 1922d7671f6SJacopo Mondi .bpp = 16, 1932d7671f6SJacopo Mondi }, { 1942d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_UYVY8_1X16, 1952d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 1962d7671f6SJacopo Mondi .bpp = 16, 1972d7671f6SJacopo Mondi }, { 1982d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_YUYV8_2X8, 1992d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2002d7671f6SJacopo Mondi .bpp = 16, 2012d7671f6SJacopo Mondi }, { 2022d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_YUYV8_1X16, 2032d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2042d7671f6SJacopo Mondi .bpp = 16, 2052d7671f6SJacopo Mondi }, { 2062d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_RGB565_2X8_LE, 2072d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2082d7671f6SJacopo Mondi .bpp = 16, 2092d7671f6SJacopo Mondi }, { 2102d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_RGB565_2X8_BE, 2112d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2122d7671f6SJacopo Mondi .bpp = 16, 2132d7671f6SJacopo Mondi }, { 2142d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_SBGGR8_1X8, 2152d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2162d7671f6SJacopo Mondi .bpp = 8, 2172d7671f6SJacopo Mondi }, { 2182d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_SGBRG8_1X8, 2192d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2202d7671f6SJacopo Mondi .bpp = 8 2212d7671f6SJacopo Mondi }, { 2222d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_SGRBG8_1X8, 2232d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2242d7671f6SJacopo Mondi .bpp = 8, 2252d7671f6SJacopo Mondi }, { 2262d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_SRGGB8_1X8, 2272d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2282d7671f6SJacopo Mondi .bpp = 8, 2292d7671f6SJacopo Mondi }, 230e3ee691dSHugues Fruchet }; 231e3ee691dSHugues Fruchet 2323c28588fSJacopo Mondi static u32 ov5640_code_to_bpp(u32 code) 2333c28588fSJacopo Mondi { 2343c28588fSJacopo Mondi unsigned int i; 2353c28588fSJacopo Mondi 2363c28588fSJacopo Mondi for (i = 0; i < ARRAY_SIZE(ov5640_formats); ++i) { 2373c28588fSJacopo Mondi if (ov5640_formats[i].code == code) 2383c28588fSJacopo Mondi return ov5640_formats[i].bpp; 2393c28588fSJacopo Mondi } 2403c28588fSJacopo Mondi 2413c28588fSJacopo Mondi return 0; 2423c28588fSJacopo Mondi } 2433c28588fSJacopo Mondi 24419a81c14SSteve Longerbeam /* 24519a81c14SSteve Longerbeam * FIXME: remove this when a subdev API becomes available 24619a81c14SSteve Longerbeam * to set the MIPI CSI-2 virtual channel. 24719a81c14SSteve Longerbeam */ 24819a81c14SSteve Longerbeam static unsigned int virtual_channel; 2498670d70aSHugues Fruchet module_param(virtual_channel, uint, 0444); 25019a81c14SSteve Longerbeam MODULE_PARM_DESC(virtual_channel, 25119a81c14SSteve Longerbeam "MIPI CSI-2 virtual channel (0..3), default 0"); 25219a81c14SSteve Longerbeam 25319a81c14SSteve Longerbeam static const int ov5640_framerates[] = { 25419a81c14SSteve Longerbeam [OV5640_15_FPS] = 15, 25519a81c14SSteve Longerbeam [OV5640_30_FPS] = 30, 256e823fb16SMaxime Ripard [OV5640_60_FPS] = 60, 25719a81c14SSteve Longerbeam }; 25819a81c14SSteve Longerbeam 25919a81c14SSteve Longerbeam /* regulator supplies */ 26019a81c14SSteve Longerbeam static const char * const ov5640_supply_name[] = { 26141d8d7f5SHugues Fruchet "DOVDD", /* Digital I/O (1.8V) supply */ 26219a81c14SSteve Longerbeam "AVDD", /* Analog (2.8V) supply */ 26324c8ac89SFabio Estevam "DVDD", /* Digital Core (1.5V) supply */ 26419a81c14SSteve Longerbeam }; 26519a81c14SSteve Longerbeam 26619a81c14SSteve Longerbeam #define OV5640_NUM_SUPPLIES ARRAY_SIZE(ov5640_supply_name) 26719a81c14SSteve Longerbeam 26819a81c14SSteve Longerbeam /* 26919a81c14SSteve Longerbeam * Image size under 1280 * 960 are SUBSAMPLING 27019a81c14SSteve Longerbeam * Image size upper 1280 * 960 are SCALING 27119a81c14SSteve Longerbeam */ 27219a81c14SSteve Longerbeam enum ov5640_downsize_mode { 27319a81c14SSteve Longerbeam SUBSAMPLING, 27419a81c14SSteve Longerbeam SCALING, 27519a81c14SSteve Longerbeam }; 27619a81c14SSteve Longerbeam 27719a81c14SSteve Longerbeam struct reg_value { 27819a81c14SSteve Longerbeam u16 reg_addr; 27919a81c14SSteve Longerbeam u8 val; 28019a81c14SSteve Longerbeam u8 mask; 28119a81c14SSteve Longerbeam u32 delay_ms; 28219a81c14SSteve Longerbeam }; 28319a81c14SSteve Longerbeam 28419a81c14SSteve Longerbeam struct ov5640_mode_info { 28519a81c14SSteve Longerbeam enum ov5640_mode_id id; 28619a81c14SSteve Longerbeam enum ov5640_downsize_mode dn_mode; 28722845bf2SJacopo Mondi enum ov5640_pixel_rate_id pixel_rate; 2883145efcdSJacopo Mondi /* Analog crop rectangle. */ 2893145efcdSJacopo Mondi struct v4l2_rect analog_crop; 2903145efcdSJacopo Mondi /* Visibile crop: from analog crop top-left corner. */ 2913145efcdSJacopo Mondi struct v4l2_rect crop; 2923145efcdSJacopo Mondi /* Total pixels per line: crop.width + fixed hblank. */ 293476dec01SMaxime Ripard u32 htot; 2943145efcdSJacopo Mondi /* Default vertical blanking: frame height = crop.height + vblank. */ 2953145efcdSJacopo Mondi u32 vblank_def; 29619a81c14SSteve Longerbeam const struct reg_value *reg_data; 29719a81c14SSteve Longerbeam u32 reg_data_size; 2983145efcdSJacopo Mondi /* DVP only; ignored in MIPI mode. */ 2995554c80eSAdam Ford u32 max_fps; 30019a81c14SSteve Longerbeam }; 30119a81c14SSteve Longerbeam 30219a81c14SSteve Longerbeam struct ov5640_ctrls { 30319a81c14SSteve Longerbeam struct v4l2_ctrl_handler handler; 304cc196e48SBenoit Parrot struct v4l2_ctrl *pixel_rate; 3057a3b8d4bSJacopo Mondi struct v4l2_ctrl *link_freq; 30619a81c14SSteve Longerbeam struct { 30719a81c14SSteve Longerbeam struct v4l2_ctrl *auto_exp; 30819a81c14SSteve Longerbeam struct v4l2_ctrl *exposure; 30919a81c14SSteve Longerbeam }; 31019a81c14SSteve Longerbeam struct { 31119a81c14SSteve Longerbeam struct v4l2_ctrl *auto_wb; 31219a81c14SSteve Longerbeam struct v4l2_ctrl *blue_balance; 31319a81c14SSteve Longerbeam struct v4l2_ctrl *red_balance; 31419a81c14SSteve Longerbeam }; 31519a81c14SSteve Longerbeam struct { 31619a81c14SSteve Longerbeam struct v4l2_ctrl *auto_gain; 31719a81c14SSteve Longerbeam struct v4l2_ctrl *gain; 31819a81c14SSteve Longerbeam }; 31919a81c14SSteve Longerbeam struct v4l2_ctrl *brightness; 3201068fecaSMylène Josserand struct v4l2_ctrl *light_freq; 32119a81c14SSteve Longerbeam struct v4l2_ctrl *saturation; 32219a81c14SSteve Longerbeam struct v4l2_ctrl *contrast; 32319a81c14SSteve Longerbeam struct v4l2_ctrl *hue; 32419a81c14SSteve Longerbeam struct v4l2_ctrl *test_pattern; 325ce85705aSHugues Fruchet struct v4l2_ctrl *hflip; 326ce85705aSHugues Fruchet struct v4l2_ctrl *vflip; 32719a81c14SSteve Longerbeam }; 32819a81c14SSteve Longerbeam 32919a81c14SSteve Longerbeam struct ov5640_dev { 33019a81c14SSteve Longerbeam struct i2c_client *i2c_client; 33119a81c14SSteve Longerbeam struct v4l2_subdev sd; 33219a81c14SSteve Longerbeam struct media_pad pad; 33319a81c14SSteve Longerbeam struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */ 33419a81c14SSteve Longerbeam struct clk *xclk; /* system clock to OV5640 */ 33519a81c14SSteve Longerbeam u32 xclk_freq; 33619a81c14SSteve Longerbeam 33719a81c14SSteve Longerbeam struct regulator_bulk_data supplies[OV5640_NUM_SUPPLIES]; 33819a81c14SSteve Longerbeam struct gpio_desc *reset_gpio; 33919a81c14SSteve Longerbeam struct gpio_desc *pwdn_gpio; 340c3f3ba3eSHugues Fruchet bool upside_down; 34119a81c14SSteve Longerbeam 34219a81c14SSteve Longerbeam /* lock to protect all members below */ 34319a81c14SSteve Longerbeam struct mutex lock; 34419a81c14SSteve Longerbeam 34519a81c14SSteve Longerbeam int power_count; 34619a81c14SSteve Longerbeam 34719a81c14SSteve Longerbeam struct v4l2_mbus_framefmt fmt; 348fb98e29fSHugues Fruchet bool pending_fmt_change; 34919a81c14SSteve Longerbeam 35019a81c14SSteve Longerbeam const struct ov5640_mode_info *current_mode; 351985cdcb0SHugues Fruchet const struct ov5640_mode_info *last_mode; 35219a81c14SSteve Longerbeam enum ov5640_frame_rate current_fr; 35319a81c14SSteve Longerbeam struct v4l2_fract frame_interval; 3543c28588fSJacopo Mondi s64 current_link_freq; 35519a81c14SSteve Longerbeam 35619a81c14SSteve Longerbeam struct ov5640_ctrls ctrls; 35719a81c14SSteve Longerbeam 35819a81c14SSteve Longerbeam u32 prev_sysclk, prev_hts; 35919a81c14SSteve Longerbeam u32 ae_low, ae_high, ae_target; 36019a81c14SSteve Longerbeam 36119a81c14SSteve Longerbeam bool pending_mode_change; 36219a81c14SSteve Longerbeam bool streaming; 36319a81c14SSteve Longerbeam }; 36419a81c14SSteve Longerbeam 36519a81c14SSteve Longerbeam static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd) 36619a81c14SSteve Longerbeam { 36719a81c14SSteve Longerbeam return container_of(sd, struct ov5640_dev, sd); 36819a81c14SSteve Longerbeam } 36919a81c14SSteve Longerbeam 37019a81c14SSteve Longerbeam static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) 37119a81c14SSteve Longerbeam { 37219a81c14SSteve Longerbeam return &container_of(ctrl->handler, struct ov5640_dev, 37319a81c14SSteve Longerbeam ctrls.handler)->sd; 37419a81c14SSteve Longerbeam } 37519a81c14SSteve Longerbeam 3768e823f5cSJacopo Mondi static inline bool ov5640_is_csi2(const struct ov5640_dev *sensor) 3778e823f5cSJacopo Mondi { 3788e823f5cSJacopo Mondi return sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY; 3798e823f5cSJacopo Mondi } 3808e823f5cSJacopo Mondi 38119a81c14SSteve Longerbeam /* 38219a81c14SSteve Longerbeam * FIXME: all of these register tables are likely filled with 38319a81c14SSteve Longerbeam * entries that set the register to their power-on default values, 38419a81c14SSteve Longerbeam * and which are otherwise not touched by this driver. Those entries 38519a81c14SSteve Longerbeam * should be identified and removed to speed register load time 38619a81c14SSteve Longerbeam * over i2c. 38719a81c14SSteve Longerbeam */ 388fb98e29fSHugues Fruchet /* YUV422 UYVY VGA@30fps */ 38919a81c14SSteve Longerbeam static const struct reg_value ov5640_init_setting_30fps_VGA[] = { 39019a81c14SSteve Longerbeam {0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0}, 391576f5d4bSLad Prabhakar {0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0}, 39219a81c14SSteve Longerbeam {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0}, 39319a81c14SSteve Longerbeam {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0}, 39419a81c14SSteve Longerbeam {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0}, 39519a81c14SSteve Longerbeam {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0}, 39619a81c14SSteve Longerbeam {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0}, 39719a81c14SSteve Longerbeam {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0}, 39819a81c14SSteve Longerbeam {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0}, 39919a81c14SSteve Longerbeam {0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0}, 40019a81c14SSteve Longerbeam {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0}, 40119a81c14SSteve Longerbeam {0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0}, 40219a81c14SSteve Longerbeam {0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0}, 40319a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 40419a81c14SSteve Longerbeam {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, 4053145efcdSJacopo Mondi {0x3815, 0x31, 0, 0}, 40619a81c14SSteve Longerbeam {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 40719a81c14SSteve Longerbeam {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 40819a81c14SSteve Longerbeam {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 40919a81c14SSteve Longerbeam {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 41019a81c14SSteve Longerbeam {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 41119a81c14SSteve Longerbeam {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0}, 41219a81c14SSteve Longerbeam {0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0}, 413aa4bb8b8SJacopo Mondi {0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0}, 4142b5c18f9SChen-Yu Tsai {0x501f, 0x00, 0, 0}, {0x4407, 0x04, 0, 0}, 41519a81c14SSteve Longerbeam {0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 416aa4bb8b8SJacopo Mondi {0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0}, 41719a81c14SSteve Longerbeam {0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0}, 41819a81c14SSteve Longerbeam {0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0}, 41919a81c14SSteve Longerbeam {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0}, 42019a81c14SSteve Longerbeam {0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0}, 42119a81c14SSteve Longerbeam {0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0}, 42219a81c14SSteve Longerbeam {0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0}, 42319a81c14SSteve Longerbeam {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, 42419a81c14SSteve Longerbeam {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, 42519a81c14SSteve Longerbeam {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, 42619a81c14SSteve Longerbeam {0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, 42719a81c14SSteve Longerbeam {0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0}, 42819a81c14SSteve Longerbeam {0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0}, 42919a81c14SSteve Longerbeam {0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0}, 43019a81c14SSteve Longerbeam {0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0}, 43119a81c14SSteve Longerbeam {0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0}, 43219a81c14SSteve Longerbeam {0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0}, 43319a81c14SSteve Longerbeam {0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0}, 43419a81c14SSteve Longerbeam {0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0}, 43519a81c14SSteve Longerbeam {0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0}, 43619a81c14SSteve Longerbeam {0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0}, 43719a81c14SSteve Longerbeam {0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0}, 43819a81c14SSteve Longerbeam {0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0}, 43919a81c14SSteve Longerbeam {0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0}, 44019a81c14SSteve Longerbeam {0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0}, 44119a81c14SSteve Longerbeam {0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0}, 44219a81c14SSteve Longerbeam {0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0}, 44319a81c14SSteve Longerbeam {0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0}, 44419a81c14SSteve Longerbeam {0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0}, 44519a81c14SSteve Longerbeam {0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0}, 44619a81c14SSteve Longerbeam {0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0}, 44719a81c14SSteve Longerbeam {0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0}, 44819a81c14SSteve Longerbeam {0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0}, 44919a81c14SSteve Longerbeam {0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0}, 45019a81c14SSteve Longerbeam {0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0}, 45119a81c14SSteve Longerbeam {0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0}, 45219a81c14SSteve Longerbeam {0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0}, 45319a81c14SSteve Longerbeam {0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0}, 45419a81c14SSteve Longerbeam {0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0}, 45519a81c14SSteve Longerbeam {0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0}, 45619a81c14SSteve Longerbeam {0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0}, 45719a81c14SSteve Longerbeam {0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0}, 45819a81c14SSteve Longerbeam {0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0}, 45919a81c14SSteve Longerbeam {0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0}, 46019a81c14SSteve Longerbeam {0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0}, 46119a81c14SSteve Longerbeam {0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0}, 46219a81c14SSteve Longerbeam {0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0}, 46319a81c14SSteve Longerbeam {0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0}, 46419a81c14SSteve Longerbeam {0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0}, 46519a81c14SSteve Longerbeam {0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0}, 46619a81c14SSteve Longerbeam {0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300}, 46719a81c14SSteve Longerbeam }; 46819a81c14SSteve Longerbeam 469086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_VGA_640_480[] = { 470c14d107eSMaxime Ripard {0x3c07, 0x08, 0, 0}, 47119a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 472ce85705aSHugues Fruchet {0x3814, 0x31, 0, 0}, 4733145efcdSJacopo Mondi {0x3815, 0x31, 0, 0}, 47419a81c14SSteve Longerbeam {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 47519a81c14SSteve Longerbeam {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 47619a81c14SSteve Longerbeam {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 47719a81c14SSteve Longerbeam {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 47819a81c14SSteve Longerbeam {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 4792b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 48019a81c14SSteve Longerbeam {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 48119a81c14SSteve Longerbeam {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, 48219a81c14SSteve Longerbeam }; 48319a81c14SSteve Longerbeam 484086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_XGA_1024_768[] = { 485c14d107eSMaxime Ripard {0x3c07, 0x08, 0, 0}, 48619a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 487ce85705aSHugues Fruchet {0x3814, 0x31, 0, 0}, 4883145efcdSJacopo Mondi {0x3815, 0x31, 0, 0}, 48919a81c14SSteve Longerbeam {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 49019a81c14SSteve Longerbeam {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 49119a81c14SSteve Longerbeam {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 49219a81c14SSteve Longerbeam {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 49319a81c14SSteve Longerbeam {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 4942b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 49519a81c14SSteve Longerbeam {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 49686633417SMaxime Ripard {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, 49719a81c14SSteve Longerbeam }; 49819a81c14SSteve Longerbeam 499086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QVGA_320_240[] = { 500c14d107eSMaxime Ripard {0x3c07, 0x08, 0, 0}, 50119a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 502ce85705aSHugues Fruchet {0x3814, 0x31, 0, 0}, 5033145efcdSJacopo Mondi {0x3815, 0x31, 0, 0}, 50419a81c14SSteve Longerbeam {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 50519a81c14SSteve Longerbeam {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 50619a81c14SSteve Longerbeam {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 50719a81c14SSteve Longerbeam {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 50819a81c14SSteve Longerbeam {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 5092b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 51019a81c14SSteve Longerbeam {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 51119a81c14SSteve Longerbeam {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, 51219a81c14SSteve Longerbeam }; 51319a81c14SSteve Longerbeam 51432ea5e05SHugues Fruchet static const struct reg_value ov5640_setting_QQVGA_160_120[] = { 51532ea5e05SHugues Fruchet {0x3c07, 0x08, 0, 0}, 51632ea5e05SHugues Fruchet {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 51732ea5e05SHugues Fruchet {0x3814, 0x31, 0, 0}, 5183145efcdSJacopo Mondi {0x3815, 0x31, 0, 0}, 51932ea5e05SHugues Fruchet {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 52032ea5e05SHugues Fruchet {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 52132ea5e05SHugues Fruchet {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 52232ea5e05SHugues Fruchet {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 52332ea5e05SHugues Fruchet {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 52432ea5e05SHugues Fruchet {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 52532ea5e05SHugues Fruchet {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, 52632ea5e05SHugues Fruchet }; 52732ea5e05SHugues Fruchet 528086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QCIF_176_144[] = { 529c14d107eSMaxime Ripard {0x3c07, 0x08, 0, 0}, 53019a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 531ce85705aSHugues Fruchet {0x3814, 0x31, 0, 0}, 5323145efcdSJacopo Mondi {0x3815, 0x31, 0, 0}, 53319a81c14SSteve Longerbeam {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 53419a81c14SSteve Longerbeam {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 53519a81c14SSteve Longerbeam {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 53619a81c14SSteve Longerbeam {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 53719a81c14SSteve Longerbeam {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 5382b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 53919a81c14SSteve Longerbeam {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 54019a81c14SSteve Longerbeam {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, 54119a81c14SSteve Longerbeam }; 54219a81c14SSteve Longerbeam 543086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_NTSC_720_480[] = { 544c14d107eSMaxime Ripard {0x3c07, 0x08, 0, 0}, 54519a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 546ce85705aSHugues Fruchet {0x3814, 0x31, 0, 0}, 5473145efcdSJacopo Mondi {0x3815, 0x31, 0, 0}, 54819a81c14SSteve Longerbeam {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 54919a81c14SSteve Longerbeam {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 55019a81c14SSteve Longerbeam {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 55119a81c14SSteve Longerbeam {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 55219a81c14SSteve Longerbeam {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 5532b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 55419a81c14SSteve Longerbeam {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 55519a81c14SSteve Longerbeam {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, 55619a81c14SSteve Longerbeam }; 55719a81c14SSteve Longerbeam 558086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_PAL_720_576[] = { 559c14d107eSMaxime Ripard {0x3c07, 0x08, 0, 0}, 56019a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 561ce85705aSHugues Fruchet {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}, 5682b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 56919a81c14SSteve Longerbeam {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 57019a81c14SSteve Longerbeam {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, 57119a81c14SSteve Longerbeam }; 57219a81c14SSteve Longerbeam 573086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_720P_1280_720[] = { 574c14d107eSMaxime Ripard {0x3c07, 0x07, 0, 0}, 57519a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 576ce85705aSHugues Fruchet {0x3814, 0x31, 0, 0}, 5773145efcdSJacopo Mondi {0x3815, 0x31, 0, 0}, 57819a81c14SSteve Longerbeam {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 57919a81c14SSteve Longerbeam {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, 58019a81c14SSteve Longerbeam {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0}, 58119a81c14SSteve Longerbeam {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0}, 58219a81c14SSteve Longerbeam {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0}, 5832b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 58419a81c14SSteve Longerbeam {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, 58519a81c14SSteve Longerbeam {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, 58619a81c14SSteve Longerbeam }; 58719a81c14SSteve Longerbeam 588086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_1080P_1920_1080[] = { 589c14d107eSMaxime Ripard {0x3c07, 0x08, 0, 0}, 59019a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 591ce85705aSHugues Fruchet {0x3814, 0x11, 0, 0}, 5923145efcdSJacopo Mondi {0x3815, 0x11, 0, 0}, 59319a81c14SSteve Longerbeam {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, 59419a81c14SSteve Longerbeam {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, 59519a81c14SSteve Longerbeam {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 59619a81c14SSteve Longerbeam {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 59719a81c14SSteve Longerbeam {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 5982b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, 59919a81c14SSteve Longerbeam {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 600c14d107eSMaxime Ripard {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, 601c14d107eSMaxime Ripard {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0}, 60219a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 603476dec01SMaxime Ripard {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0}, 60419a81c14SSteve Longerbeam {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0}, 60519a81c14SSteve Longerbeam {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0}, 60619a81c14SSteve Longerbeam {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0}, 6072b5c18f9SChen-Yu Tsai {0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0}, 60819a81c14SSteve Longerbeam {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0}, 60992b9096cSBenoit Parrot {0x4005, 0x1a, 0, 0}, 61019a81c14SSteve Longerbeam }; 61119a81c14SSteve Longerbeam 612086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = { 613c14d107eSMaxime Ripard {0x3c07, 0x08, 0, 0}, 61419a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 615ce85705aSHugues Fruchet {0x3814, 0x11, 0, 0}, 6163145efcdSJacopo Mondi {0x3815, 0x11, 0, 0}, 61719a81c14SSteve Longerbeam {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, 61819a81c14SSteve Longerbeam {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, 61919a81c14SSteve Longerbeam {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 62019a81c14SSteve Longerbeam {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 62119a81c14SSteve Longerbeam {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 6222b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, 62319a81c14SSteve Longerbeam {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 62419a81c14SSteve Longerbeam {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70}, 62519a81c14SSteve Longerbeam }; 62619a81c14SSteve Longerbeam 62719a81c14SSteve Longerbeam /* power-on sensor init reg table */ 62819a81c14SSteve Longerbeam static const struct ov5640_mode_info ov5640_mode_init_data = { 6293145efcdSJacopo Mondi .id = 0, 6303145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 6313145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_96M, 6323145efcdSJacopo Mondi .analog_crop = { 6333145efcdSJacopo Mondi .left = 0, 6343145efcdSJacopo Mondi .top = 4, 6353145efcdSJacopo Mondi .width = 2624, 6363145efcdSJacopo Mondi .height = 1944, 6373145efcdSJacopo Mondi }, 6383145efcdSJacopo Mondi .crop = { 6393145efcdSJacopo Mondi .left = 16, 6403145efcdSJacopo Mondi .top = 6, 6413145efcdSJacopo Mondi .width = 640, 6423145efcdSJacopo Mondi .height = 480, 6433145efcdSJacopo Mondi }, 6443145efcdSJacopo Mondi .htot = 1896, 6453145efcdSJacopo Mondi .vblank_def = 504, 6463145efcdSJacopo Mondi .reg_data = ov5640_init_setting_30fps_VGA, 6473145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_init_setting_30fps_VGA), 6483145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 64919a81c14SSteve Longerbeam }; 65019a81c14SSteve Longerbeam 65119a81c14SSteve Longerbeam static const struct ov5640_mode_info 652086c25f8SMaxime Ripard ov5640_mode_data[OV5640_NUM_MODES] = { 6538409d017SJacopo Mondi { 6548409d017SJacopo Mondi /* 160x120 */ 6553145efcdSJacopo Mondi .id = OV5640_MODE_QQVGA_160_120, 6563145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 6573145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_48M, 6583145efcdSJacopo Mondi .analog_crop = { 6593145efcdSJacopo Mondi .left = 0, 6603145efcdSJacopo Mondi .top = 4, 6613145efcdSJacopo Mondi .width = 2624, 6623145efcdSJacopo Mondi .height = 1944, 6633145efcdSJacopo Mondi }, 6643145efcdSJacopo Mondi .crop = { 6653145efcdSJacopo Mondi .left = 16, 6663145efcdSJacopo Mondi .top = 6, 6673145efcdSJacopo Mondi .width = 160, 6683145efcdSJacopo Mondi .height = 120, 6693145efcdSJacopo Mondi }, 6703145efcdSJacopo Mondi .htot = 1896, 6713145efcdSJacopo Mondi .vblank_def = 864, 6723145efcdSJacopo Mondi .reg_data = ov5640_setting_QQVGA_160_120, 6733145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_QQVGA_160_120), 6743145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 6758409d017SJacopo Mondi }, { 6768409d017SJacopo Mondi /* 176x144 */ 6773145efcdSJacopo Mondi .id = OV5640_MODE_QCIF_176_144, 6783145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 6793145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_48M, 6803145efcdSJacopo Mondi .analog_crop = { 6813145efcdSJacopo Mondi .left = 0, 6823145efcdSJacopo Mondi .top = 4, 6833145efcdSJacopo Mondi .width = 2624, 6843145efcdSJacopo Mondi .height = 1944, 6853145efcdSJacopo Mondi }, 6863145efcdSJacopo Mondi .crop = { 6873145efcdSJacopo Mondi .left = 16, 6883145efcdSJacopo Mondi .top = 6, 6893145efcdSJacopo Mondi .width = 176, 6903145efcdSJacopo Mondi .height = 144, 6913145efcdSJacopo Mondi }, 6923145efcdSJacopo Mondi .htot = 1896, 6933145efcdSJacopo Mondi .vblank_def = 840, 6943145efcdSJacopo Mondi .reg_data = ov5640_setting_QCIF_176_144, 6953145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_QCIF_176_144), 6963145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 6978409d017SJacopo Mondi }, { 6988409d017SJacopo Mondi /* 320x240 */ 6993145efcdSJacopo Mondi .id = OV5640_MODE_QVGA_320_240, 7003145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 7013145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_48M, 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 = 320, 7123145efcdSJacopo Mondi .height = 240, 7133145efcdSJacopo Mondi }, 7143145efcdSJacopo Mondi .htot = 1896, 7153145efcdSJacopo Mondi .vblank_def = 744, 7163145efcdSJacopo Mondi .reg_data = ov5640_setting_QVGA_320_240, 7173145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_QVGA_320_240), 7183145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 7198409d017SJacopo Mondi }, { 7208409d017SJacopo Mondi /* 640x480 */ 7213145efcdSJacopo Mondi .id = OV5640_MODE_VGA_640_480, 7223145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 7233145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_48M, 7243145efcdSJacopo Mondi .analog_crop = { 7253145efcdSJacopo Mondi .left = 0, 7263145efcdSJacopo Mondi .top = 4, 7273145efcdSJacopo Mondi .width = 2624, 7283145efcdSJacopo Mondi .height = 1944, 7293145efcdSJacopo Mondi }, 7303145efcdSJacopo Mondi .crop = { 7313145efcdSJacopo Mondi .left = 16, 7323145efcdSJacopo Mondi .top = 6, 7333145efcdSJacopo Mondi .width = 640, 7343145efcdSJacopo Mondi .height = 480, 7353145efcdSJacopo Mondi }, 7363145efcdSJacopo Mondi .htot = 1896, 7373145efcdSJacopo Mondi .vblank_def = 600, 7383145efcdSJacopo Mondi .reg_data = ov5640_setting_VGA_640_480, 7393145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_VGA_640_480), 7403145efcdSJacopo Mondi .max_fps = OV5640_60_FPS 7418409d017SJacopo Mondi }, { 7428409d017SJacopo Mondi /* 720x480 */ 7433145efcdSJacopo Mondi .id = OV5640_MODE_NTSC_720_480, 7443145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 7453145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_96M, 7463145efcdSJacopo Mondi .analog_crop = { 7473145efcdSJacopo Mondi .left = 0, 7483145efcdSJacopo Mondi .top = 4, 7493145efcdSJacopo Mondi .width = 2624, 7503145efcdSJacopo Mondi .height = 1944, 7513145efcdSJacopo Mondi }, 7523145efcdSJacopo Mondi .crop = { 753*e74ef55bSJacopo Mondi .left = 56, 7543145efcdSJacopo Mondi .top = 60, 7553145efcdSJacopo Mondi .width = 720, 7563145efcdSJacopo Mondi .height = 480, 7573145efcdSJacopo Mondi }, 7583145efcdSJacopo Mondi .htot = 1896, 7593145efcdSJacopo Mondi .vblank_def = 504, 7603145efcdSJacopo Mondi .reg_data = ov5640_setting_NTSC_720_480, 7613145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_NTSC_720_480), 7623145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 7638409d017SJacopo Mondi }, { 7648409d017SJacopo Mondi /* 720x576 */ 7653145efcdSJacopo Mondi .id = OV5640_MODE_PAL_720_576, 7663145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 7673145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_96M, 7683145efcdSJacopo Mondi .analog_crop = { 7693145efcdSJacopo Mondi .left = 0, 7703145efcdSJacopo Mondi .top = 4, 7713145efcdSJacopo Mondi .width = 2624, 7723145efcdSJacopo Mondi .height = 1944, 7733145efcdSJacopo Mondi }, 7743145efcdSJacopo Mondi .crop = { 7753145efcdSJacopo Mondi .left = 56, 7763145efcdSJacopo Mondi .top = 6, 7773145efcdSJacopo Mondi .width = 720, 7783145efcdSJacopo Mondi .height = 576, 7793145efcdSJacopo Mondi }, 7803145efcdSJacopo Mondi .htot = 1896, 7813145efcdSJacopo Mondi .vblank_def = 408, 7823145efcdSJacopo Mondi .reg_data = ov5640_setting_PAL_720_576, 7833145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_PAL_720_576), 7843145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 7858409d017SJacopo Mondi }, { 7868409d017SJacopo Mondi /* 1024x768 */ 7873145efcdSJacopo Mondi .id = OV5640_MODE_XGA_1024_768, 7883145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 7893145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_96M, 7903145efcdSJacopo Mondi .analog_crop = { 7913145efcdSJacopo Mondi .left = 0, 7923145efcdSJacopo Mondi .top = 4, 7933145efcdSJacopo Mondi .width = 2624, 7943145efcdSJacopo Mondi .height = 1944, 7953145efcdSJacopo Mondi }, 7963145efcdSJacopo Mondi .crop = { 7973145efcdSJacopo Mondi .left = 16, 7983145efcdSJacopo Mondi .top = 6, 7993145efcdSJacopo Mondi .width = 1024, 8003145efcdSJacopo Mondi .height = 768, 8013145efcdSJacopo Mondi }, 8023145efcdSJacopo Mondi .htot = 1896, 8033145efcdSJacopo Mondi .vblank_def = 312, 8043145efcdSJacopo Mondi .reg_data = ov5640_setting_XGA_1024_768, 8053145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_XGA_1024_768), 8063145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 8078409d017SJacopo Mondi }, { 8088409d017SJacopo Mondi /* 1280x720 */ 8093145efcdSJacopo Mondi .id = OV5640_MODE_720P_1280_720, 8103145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 8113145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_124M, 8123145efcdSJacopo Mondi .analog_crop = { 8133145efcdSJacopo Mondi .left = 0, 8143145efcdSJacopo Mondi .top = 250, 8153145efcdSJacopo Mondi .width = 2624, 8163145efcdSJacopo Mondi .height = 1456, 8173145efcdSJacopo Mondi }, 8183145efcdSJacopo Mondi .crop = { 8193145efcdSJacopo Mondi .left = 16, 8203145efcdSJacopo Mondi .top = 4, 8213145efcdSJacopo Mondi .width = 1280, 8223145efcdSJacopo Mondi .height = 720, 8233145efcdSJacopo Mondi }, 8243145efcdSJacopo Mondi .htot = 1892, 8253145efcdSJacopo Mondi .vblank_def = 20, 8263145efcdSJacopo Mondi .reg_data = ov5640_setting_720P_1280_720, 8273145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_720P_1280_720), 8283145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 8298409d017SJacopo Mondi }, { 8308409d017SJacopo Mondi /* 1920x1080 */ 8313145efcdSJacopo Mondi .id = OV5640_MODE_1080P_1920_1080, 8323145efcdSJacopo Mondi .dn_mode = SCALING, 8333145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_148M, 8343145efcdSJacopo Mondi .analog_crop = { 8353145efcdSJacopo Mondi .left = 336, 8363145efcdSJacopo Mondi .top = 434, 8373145efcdSJacopo Mondi .width = 1952, 8383145efcdSJacopo Mondi .height = 1088, 8393145efcdSJacopo Mondi }, 8403145efcdSJacopo Mondi .crop = { 8413145efcdSJacopo Mondi .left = 16, 8423145efcdSJacopo Mondi .top = 4, 8433145efcdSJacopo Mondi .width = 1920, 8443145efcdSJacopo Mondi .height = 1080, 8453145efcdSJacopo Mondi }, 8463145efcdSJacopo Mondi .htot = 2500, 8473145efcdSJacopo Mondi .vblank_def = 40, 8483145efcdSJacopo Mondi .reg_data = ov5640_setting_1080P_1920_1080, 8493145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_1080P_1920_1080), 8503145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 8518409d017SJacopo Mondi }, { 8528409d017SJacopo Mondi /* 2592x1944 */ 8533145efcdSJacopo Mondi .id = OV5640_MODE_QSXGA_2592_1944, 8543145efcdSJacopo Mondi .dn_mode = SCALING, 8553145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_168M, 8563145efcdSJacopo Mondi .analog_crop = { 8573145efcdSJacopo Mondi .left = 0, 8583145efcdSJacopo Mondi .top = 0, 8593145efcdSJacopo Mondi .width = 2624, 8603145efcdSJacopo Mondi .height = 1952, 8613145efcdSJacopo Mondi }, 8623145efcdSJacopo Mondi .crop = { 8633145efcdSJacopo Mondi .left = 16, 8643145efcdSJacopo Mondi .top = 4, 8653145efcdSJacopo Mondi .width = 2592, 8663145efcdSJacopo Mondi .height = 1944, 8673145efcdSJacopo Mondi }, 8683145efcdSJacopo Mondi .htot = 2844, 8693145efcdSJacopo Mondi .vblank_def = 24, 8703145efcdSJacopo Mondi .reg_data = ov5640_setting_QSXGA_2592_1944, 8713145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944), 8723145efcdSJacopo Mondi .max_fps = OV5640_15_FPS 8738409d017SJacopo Mondi }, 87419a81c14SSteve Longerbeam }; 87519a81c14SSteve Longerbeam 87619a81c14SSteve Longerbeam static int ov5640_init_slave_id(struct ov5640_dev *sensor) 87719a81c14SSteve Longerbeam { 87819a81c14SSteve Longerbeam struct i2c_client *client = sensor->i2c_client; 87919a81c14SSteve Longerbeam struct i2c_msg msg; 88019a81c14SSteve Longerbeam u8 buf[3]; 88119a81c14SSteve Longerbeam int ret; 88219a81c14SSteve Longerbeam 88319a81c14SSteve Longerbeam if (client->addr == OV5640_DEFAULT_SLAVE_ID) 88419a81c14SSteve Longerbeam return 0; 88519a81c14SSteve Longerbeam 88619a81c14SSteve Longerbeam buf[0] = OV5640_REG_SLAVE_ID >> 8; 88719a81c14SSteve Longerbeam buf[1] = OV5640_REG_SLAVE_ID & 0xff; 88819a81c14SSteve Longerbeam buf[2] = client->addr << 1; 88919a81c14SSteve Longerbeam 89019a81c14SSteve Longerbeam msg.addr = OV5640_DEFAULT_SLAVE_ID; 89119a81c14SSteve Longerbeam msg.flags = 0; 89219a81c14SSteve Longerbeam msg.buf = buf; 89319a81c14SSteve Longerbeam msg.len = sizeof(buf); 89419a81c14SSteve Longerbeam 89519a81c14SSteve Longerbeam ret = i2c_transfer(client->adapter, &msg, 1); 89619a81c14SSteve Longerbeam if (ret < 0) { 89719a81c14SSteve Longerbeam dev_err(&client->dev, "%s: failed with %d\n", __func__, ret); 89819a81c14SSteve Longerbeam return ret; 89919a81c14SSteve Longerbeam } 90019a81c14SSteve Longerbeam 90119a81c14SSteve Longerbeam return 0; 90219a81c14SSteve Longerbeam } 90319a81c14SSteve Longerbeam 90419a81c14SSteve Longerbeam static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val) 90519a81c14SSteve Longerbeam { 90619a81c14SSteve Longerbeam struct i2c_client *client = sensor->i2c_client; 90719a81c14SSteve Longerbeam struct i2c_msg msg; 90819a81c14SSteve Longerbeam u8 buf[3]; 90919a81c14SSteve Longerbeam int ret; 91019a81c14SSteve Longerbeam 91119a81c14SSteve Longerbeam buf[0] = reg >> 8; 91219a81c14SSteve Longerbeam buf[1] = reg & 0xff; 91319a81c14SSteve Longerbeam buf[2] = val; 91419a81c14SSteve Longerbeam 91519a81c14SSteve Longerbeam msg.addr = client->addr; 91619a81c14SSteve Longerbeam msg.flags = client->flags; 91719a81c14SSteve Longerbeam msg.buf = buf; 91819a81c14SSteve Longerbeam msg.len = sizeof(buf); 91919a81c14SSteve Longerbeam 92019a81c14SSteve Longerbeam ret = i2c_transfer(client->adapter, &msg, 1); 92119a81c14SSteve Longerbeam if (ret < 0) { 9223924c623SHugues Fruchet dev_err(&client->dev, "%s: error: reg=%x, val=%x\n", 92319a81c14SSteve Longerbeam __func__, reg, val); 92419a81c14SSteve Longerbeam return ret; 92519a81c14SSteve Longerbeam } 92619a81c14SSteve Longerbeam 92719a81c14SSteve Longerbeam return 0; 92819a81c14SSteve Longerbeam } 92919a81c14SSteve Longerbeam 93019a81c14SSteve Longerbeam static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val) 93119a81c14SSteve Longerbeam { 93219a81c14SSteve Longerbeam struct i2c_client *client = sensor->i2c_client; 93319a81c14SSteve Longerbeam struct i2c_msg msg[2]; 93419a81c14SSteve Longerbeam u8 buf[2]; 93519a81c14SSteve Longerbeam int ret; 93619a81c14SSteve Longerbeam 93719a81c14SSteve Longerbeam buf[0] = reg >> 8; 93819a81c14SSteve Longerbeam buf[1] = reg & 0xff; 93919a81c14SSteve Longerbeam 94019a81c14SSteve Longerbeam msg[0].addr = client->addr; 94119a81c14SSteve Longerbeam msg[0].flags = client->flags; 94219a81c14SSteve Longerbeam msg[0].buf = buf; 94319a81c14SSteve Longerbeam msg[0].len = sizeof(buf); 94419a81c14SSteve Longerbeam 94519a81c14SSteve Longerbeam msg[1].addr = client->addr; 94619a81c14SSteve Longerbeam msg[1].flags = client->flags | I2C_M_RD; 94719a81c14SSteve Longerbeam msg[1].buf = buf; 94819a81c14SSteve Longerbeam msg[1].len = 1; 94919a81c14SSteve Longerbeam 95019a81c14SSteve Longerbeam ret = i2c_transfer(client->adapter, msg, 2); 9513924c623SHugues Fruchet if (ret < 0) { 9523924c623SHugues Fruchet dev_err(&client->dev, "%s: error: reg=%x\n", 9533924c623SHugues Fruchet __func__, reg); 95419a81c14SSteve Longerbeam return ret; 9553924c623SHugues Fruchet } 95619a81c14SSteve Longerbeam 95719a81c14SSteve Longerbeam *val = buf[0]; 95819a81c14SSteve Longerbeam return 0; 95919a81c14SSteve Longerbeam } 96019a81c14SSteve Longerbeam 96119a81c14SSteve Longerbeam static int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val) 96219a81c14SSteve Longerbeam { 96319a81c14SSteve Longerbeam u8 hi, lo; 96419a81c14SSteve Longerbeam int ret; 96519a81c14SSteve Longerbeam 96619a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, reg, &hi); 96719a81c14SSteve Longerbeam if (ret) 96819a81c14SSteve Longerbeam return ret; 96919a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, reg + 1, &lo); 97019a81c14SSteve Longerbeam if (ret) 97119a81c14SSteve Longerbeam return ret; 97219a81c14SSteve Longerbeam 97319a81c14SSteve Longerbeam *val = ((u16)hi << 8) | (u16)lo; 97419a81c14SSteve Longerbeam return 0; 97519a81c14SSteve Longerbeam } 97619a81c14SSteve Longerbeam 97719a81c14SSteve Longerbeam static int ov5640_write_reg16(struct ov5640_dev *sensor, u16 reg, u16 val) 97819a81c14SSteve Longerbeam { 97919a81c14SSteve Longerbeam int ret; 98019a81c14SSteve Longerbeam 98119a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, reg, val >> 8); 98219a81c14SSteve Longerbeam if (ret) 98319a81c14SSteve Longerbeam return ret; 98419a81c14SSteve Longerbeam 98519a81c14SSteve Longerbeam return ov5640_write_reg(sensor, reg + 1, val & 0xff); 98619a81c14SSteve Longerbeam } 98719a81c14SSteve Longerbeam 98819a81c14SSteve Longerbeam static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg, 98919a81c14SSteve Longerbeam u8 mask, u8 val) 99019a81c14SSteve Longerbeam { 99119a81c14SSteve Longerbeam u8 readval; 99219a81c14SSteve Longerbeam int ret; 99319a81c14SSteve Longerbeam 99419a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, reg, &readval); 99519a81c14SSteve Longerbeam if (ret) 99619a81c14SSteve Longerbeam return ret; 99719a81c14SSteve Longerbeam 99819a81c14SSteve Longerbeam readval &= ~mask; 99919a81c14SSteve Longerbeam val &= mask; 100019a81c14SSteve Longerbeam val |= readval; 100119a81c14SSteve Longerbeam 100219a81c14SSteve Longerbeam return ov5640_write_reg(sensor, reg, val); 100319a81c14SSteve Longerbeam } 100419a81c14SSteve Longerbeam 1005aa288248SMaxime Ripard /* 1006aa288248SMaxime Ripard * After trying the various combinations, reading various 1007f8a7647dSMauro Carvalho Chehab * documentations spread around the net, and from the various 1008aa288248SMaxime Ripard * feedback, the clock tree is probably as follows: 1009aa288248SMaxime Ripard * 1010aa288248SMaxime Ripard * +--------------+ 1011aa288248SMaxime Ripard * | Ext. Clock | 1012aa288248SMaxime Ripard * +-+------------+ 1013aa288248SMaxime Ripard * | +----------+ 1014aa288248SMaxime Ripard * +->| PLL1 | - reg 0x3036, for the multiplier 1015aa288248SMaxime Ripard * +-+--------+ - reg 0x3037, bits 0-3 for the pre-divider 1016aa288248SMaxime Ripard * | +--------------+ 1017aa288248SMaxime Ripard * +->| System Clock | - reg 0x3035, bits 4-7 1018aa288248SMaxime Ripard * +-+------------+ 1019aa288248SMaxime Ripard * | +--------------+ 1020aa288248SMaxime Ripard * +->| MIPI Divider | - reg 0x3035, bits 0-3 1021aa288248SMaxime Ripard * | +-+------------+ 1022aa288248SMaxime Ripard * | +----------------> MIPI SCLK 1023aa288248SMaxime Ripard * | + +-----+ 1024aa288248SMaxime Ripard * | +->| / 2 |-------> MIPI BIT CLK 1025aa288248SMaxime Ripard * | +-----+ 1026aa288248SMaxime Ripard * | +--------------+ 1027aa288248SMaxime Ripard * +->| PLL Root Div | - reg 0x3037, bit 4 1028aa288248SMaxime Ripard * +-+------------+ 1029aa288248SMaxime Ripard * | +---------+ 10304c85f628SPaul Kocialkowski * +->| Bit Div | - reg 0x3034, bits 0-3 1031aa288248SMaxime Ripard * +-+-------+ 1032aa288248SMaxime Ripard * | +-------------+ 1033aa288248SMaxime Ripard * +->| SCLK Div | - reg 0x3108, bits 0-1 1034aa288248SMaxime Ripard * | +-+-----------+ 1035aa288248SMaxime Ripard * | +---------------> SCLK 1036aa288248SMaxime Ripard * | +-------------+ 1037aa288248SMaxime Ripard * +->| SCLK 2X Div | - reg 0x3108, bits 2-3 1038aa288248SMaxime Ripard * | +-+-----------+ 1039aa288248SMaxime Ripard * | +---------------> SCLK 2X 1040aa288248SMaxime Ripard * | +-------------+ 1041aa288248SMaxime Ripard * +->| PCLK Div | - reg 0x3108, bits 4-5 1042aa288248SMaxime Ripard * ++------------+ 1043aa288248SMaxime Ripard * + +-----------+ 1044aa288248SMaxime Ripard * +->| P_DIV | - reg 0x3035, bits 0-3 1045aa288248SMaxime Ripard * +-----+-----+ 1046aa288248SMaxime Ripard * +------------> PCLK 1047aa288248SMaxime Ripard * 10486c957ed7SJacopo Mondi * There seems to be also constraints: 1049aa288248SMaxime Ripard * - the PLL pre-divider output rate should be in the 4-27MHz range 1050aa288248SMaxime Ripard * - the PLL multiplier output rate should be in the 500-1000MHz range 1051aa288248SMaxime Ripard * - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG 1052aa288248SMaxime Ripard */ 1053aa288248SMaxime Ripard 1054aa288248SMaxime Ripard /* 1055aa288248SMaxime Ripard * This is supposed to be ranging from 1 to 8, but the value is always 1056aa288248SMaxime Ripard * set to 3 in the vendor kernels. 1057aa288248SMaxime Ripard */ 1058aa288248SMaxime Ripard #define OV5640_PLL_PREDIV 3 1059aa288248SMaxime Ripard 1060aa288248SMaxime Ripard #define OV5640_PLL_MULT_MIN 4 1061aa288248SMaxime Ripard #define OV5640_PLL_MULT_MAX 252 1062aa288248SMaxime Ripard 1063aa288248SMaxime Ripard /* 1064aa288248SMaxime Ripard * This is supposed to be ranging from 1 to 16, but the value is 1065aa288248SMaxime Ripard * always set to either 1 or 2 in the vendor kernels. 1066aa288248SMaxime Ripard */ 1067aa288248SMaxime Ripard #define OV5640_SYSDIV_MIN 1 1068aa288248SMaxime Ripard #define OV5640_SYSDIV_MAX 16 1069aa288248SMaxime Ripard 1070aa288248SMaxime Ripard /* 1071aa288248SMaxime Ripard * This is supposed to be ranging from 1 to 2, but the value is always 1072aa288248SMaxime Ripard * set to 2 in the vendor kernels. 1073aa288248SMaxime Ripard */ 1074aa288248SMaxime Ripard #define OV5640_PLL_ROOT_DIV 2 1075aa288248SMaxime Ripard #define OV5640_PLL_CTRL3_PLL_ROOT_DIV_2 BIT(4) 1076aa288248SMaxime Ripard 1077aa288248SMaxime Ripard /* 1078aa288248SMaxime Ripard * We only supports 8-bit formats at the moment 1079aa288248SMaxime Ripard */ 1080aa288248SMaxime Ripard #define OV5640_BIT_DIV 2 1081aa288248SMaxime Ripard #define OV5640_PLL_CTRL0_MIPI_MODE_8BIT 0x08 1082aa288248SMaxime Ripard 1083aa288248SMaxime Ripard /* 1084aa288248SMaxime Ripard * This is supposed to be ranging from 1 to 8, but the value is always 1085aa288248SMaxime Ripard * set to 2 in the vendor kernels. 1086aa288248SMaxime Ripard */ 1087aa288248SMaxime Ripard #define OV5640_SCLK_ROOT_DIV 2 1088aa288248SMaxime Ripard 1089aa288248SMaxime Ripard /* 1090aa288248SMaxime Ripard * This is hardcoded so that the consistency is maintained between SCLK and 1091aa288248SMaxime Ripard * SCLK 2x. 1092aa288248SMaxime Ripard */ 1093aa288248SMaxime Ripard #define OV5640_SCLK2X_ROOT_DIV (OV5640_SCLK_ROOT_DIV / 2) 1094aa288248SMaxime Ripard 1095aa288248SMaxime Ripard /* 1096aa288248SMaxime Ripard * This is supposed to be ranging from 1 to 8, but the value is always 1097aa288248SMaxime Ripard * set to 1 in the vendor kernels. 1098aa288248SMaxime Ripard */ 1099aa288248SMaxime Ripard #define OV5640_PCLK_ROOT_DIV 1 1100aa288248SMaxime Ripard #define OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS 0x00 1101aa288248SMaxime Ripard 1102aa288248SMaxime Ripard static unsigned long ov5640_compute_sys_clk(struct ov5640_dev *sensor, 1103aa288248SMaxime Ripard u8 pll_prediv, u8 pll_mult, 1104aa288248SMaxime Ripard u8 sysdiv) 1105aa288248SMaxime Ripard { 1106aa288248SMaxime Ripard unsigned long sysclk = sensor->xclk_freq / pll_prediv * pll_mult; 1107aa288248SMaxime Ripard 1108aa288248SMaxime Ripard /* PLL1 output cannot exceed 1GHz. */ 1109aa288248SMaxime Ripard if (sysclk / 1000000 > 1000) 1110aa288248SMaxime Ripard return 0; 1111aa288248SMaxime Ripard 1112aa288248SMaxime Ripard return sysclk / sysdiv; 1113aa288248SMaxime Ripard } 1114aa288248SMaxime Ripard 1115aa288248SMaxime Ripard static unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor, 1116aa288248SMaxime Ripard unsigned long rate, 1117aa288248SMaxime Ripard u8 *pll_prediv, u8 *pll_mult, 1118aa288248SMaxime Ripard u8 *sysdiv) 1119aa288248SMaxime Ripard { 1120aa288248SMaxime Ripard unsigned long best = ~0; 1121aa288248SMaxime Ripard u8 best_sysdiv = 1, best_mult = 1; 1122aa288248SMaxime Ripard u8 _sysdiv, _pll_mult; 1123aa288248SMaxime Ripard 1124aa288248SMaxime Ripard for (_sysdiv = OV5640_SYSDIV_MIN; 1125aa288248SMaxime Ripard _sysdiv <= OV5640_SYSDIV_MAX; 1126aa288248SMaxime Ripard _sysdiv++) { 1127aa288248SMaxime Ripard for (_pll_mult = OV5640_PLL_MULT_MIN; 1128aa288248SMaxime Ripard _pll_mult <= OV5640_PLL_MULT_MAX; 1129aa288248SMaxime Ripard _pll_mult++) { 1130aa288248SMaxime Ripard unsigned long _rate; 1131aa288248SMaxime Ripard 1132aa288248SMaxime Ripard /* 1133aa288248SMaxime Ripard * The PLL multiplier cannot be odd if above 1134aa288248SMaxime Ripard * 127. 1135aa288248SMaxime Ripard */ 1136aa288248SMaxime Ripard if (_pll_mult > 127 && (_pll_mult % 2)) 1137aa288248SMaxime Ripard continue; 1138aa288248SMaxime Ripard 1139aa288248SMaxime Ripard _rate = ov5640_compute_sys_clk(sensor, 1140aa288248SMaxime Ripard OV5640_PLL_PREDIV, 1141aa288248SMaxime Ripard _pll_mult, _sysdiv); 1142aa288248SMaxime Ripard 1143aa288248SMaxime Ripard /* 1144aa288248SMaxime Ripard * We have reached the maximum allowed PLL1 output, 1145aa288248SMaxime Ripard * increase sysdiv. 1146aa288248SMaxime Ripard */ 11472e3df204SAdam Ford if (!_rate) 1148aa288248SMaxime Ripard break; 1149aa288248SMaxime Ripard 1150aa288248SMaxime Ripard /* 1151aa288248SMaxime Ripard * Prefer rates above the expected clock rate than 1152aa288248SMaxime Ripard * below, even if that means being less precise. 1153aa288248SMaxime Ripard */ 1154aa288248SMaxime Ripard if (_rate < rate) 1155aa288248SMaxime Ripard continue; 1156aa288248SMaxime Ripard 1157aa288248SMaxime Ripard if (abs(rate - _rate) < abs(rate - best)) { 1158aa288248SMaxime Ripard best = _rate; 1159aa288248SMaxime Ripard best_sysdiv = _sysdiv; 1160aa288248SMaxime Ripard best_mult = _pll_mult; 1161aa288248SMaxime Ripard } 1162aa288248SMaxime Ripard 1163aa288248SMaxime Ripard if (_rate == rate) 1164aa288248SMaxime Ripard goto out; 1165aa288248SMaxime Ripard } 1166aa288248SMaxime Ripard } 1167aa288248SMaxime Ripard 1168aa288248SMaxime Ripard out: 1169aa288248SMaxime Ripard *sysdiv = best_sysdiv; 1170aa288248SMaxime Ripard *pll_prediv = OV5640_PLL_PREDIV; 1171aa288248SMaxime Ripard *pll_mult = best_mult; 1172aa288248SMaxime Ripard 1173aa288248SMaxime Ripard return best; 1174aa288248SMaxime Ripard } 1175aa288248SMaxime Ripard 1176aa288248SMaxime Ripard /* 1177aa288248SMaxime Ripard * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values 1178aa288248SMaxime Ripard * for the MIPI CSI-2 output. 1179aa288248SMaxime Ripard */ 11806c957ed7SJacopo Mondi static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor) 1181aa288248SMaxime Ripard { 11826c957ed7SJacopo Mondi u8 bit_div, mipi_div, pclk_div, sclk_div, sclk2x_div, root_div; 1183aa288248SMaxime Ripard u8 prediv, mult, sysdiv; 11846c957ed7SJacopo Mondi unsigned long link_freq; 11856c957ed7SJacopo Mondi unsigned long sysclk; 11866c957ed7SJacopo Mondi u8 pclk_period; 11876c957ed7SJacopo Mondi u32 sample_rate; 11886c957ed7SJacopo Mondi u32 num_lanes; 1189aa288248SMaxime Ripard int ret; 1190aa288248SMaxime Ripard 11916c957ed7SJacopo Mondi /* Use the link freq computed at ov5640_update_pixel_rate() time. */ 11926c957ed7SJacopo Mondi link_freq = sensor->current_link_freq; 11936c957ed7SJacopo Mondi 1194aa288248SMaxime Ripard /* 11956c957ed7SJacopo Mondi * - mipi_div - Additional divider for the MIPI lane clock. 11966c957ed7SJacopo Mondi * 11976c957ed7SJacopo Mondi * Higher link frequencies would make sysclk > 1GHz. 11986c957ed7SJacopo Mondi * Keep the sysclk low and do not divide in the MIPI domain. 1199aa288248SMaxime Ripard */ 12006c957ed7SJacopo Mondi if (link_freq > OV5640_LINK_RATE_MAX) 12016c957ed7SJacopo Mondi mipi_div = 1; 1202aa288248SMaxime Ripard else 12036c957ed7SJacopo Mondi mipi_div = 2; 1204aa288248SMaxime Ripard 12056c957ed7SJacopo Mondi sysclk = link_freq * mipi_div; 12066c957ed7SJacopo Mondi ov5640_calc_sys_clk(sensor, sysclk, &prediv, &mult, &sysdiv); 1207aa288248SMaxime Ripard 12086c957ed7SJacopo Mondi /* 12096c957ed7SJacopo Mondi * Adjust PLL parameters to maintain the MIPI_SCLK-to-PCLK ratio. 12106c957ed7SJacopo Mondi * 12116c957ed7SJacopo Mondi * - root_div = 2 (fixed) 12126c957ed7SJacopo Mondi * - bit_div : MIPI 8-bit = 2; MIPI 10-bit = 2.5 12136c957ed7SJacopo Mondi * - pclk_div = 1 (fixed) 12146c957ed7SJacopo Mondi * - p_div = (2 lanes ? mipi_div : 2 * mipi_div) 12156c957ed7SJacopo Mondi * 12166c957ed7SJacopo Mondi * This results in the following MIPI_SCLK depending on the number 12176c957ed7SJacopo Mondi * of lanes: 12186c957ed7SJacopo Mondi * 12196c957ed7SJacopo Mondi * - 2 lanes: MIPI_SCLK = (4 or 5) * PCLK 12206c957ed7SJacopo Mondi * - 1 lanes: MIPI_SCLK = (8 or 10) * PCLK 12216c957ed7SJacopo Mondi */ 12226c957ed7SJacopo Mondi root_div = OV5640_PLL_CTRL3_PLL_ROOT_DIV_2; 12236c957ed7SJacopo Mondi bit_div = OV5640_PLL_CTRL0_MIPI_MODE_8BIT; 12246c957ed7SJacopo Mondi pclk_div = ilog2(OV5640_PCLK_ROOT_DIV); 1225aa288248SMaxime Ripard 12266c957ed7SJacopo Mondi /* 12276c957ed7SJacopo Mondi * Scaler clock: 12286c957ed7SJacopo Mondi * - YUV: PCLK >= 2 * SCLK 12296c957ed7SJacopo Mondi * - RAW or JPEG: PCLK >= SCLK 12306c957ed7SJacopo Mondi * - sclk2x_div = sclk_div / 2 12316c957ed7SJacopo Mondi */ 12326c957ed7SJacopo Mondi sclk_div = ilog2(OV5640_SCLK_ROOT_DIV); 12336c957ed7SJacopo Mondi sclk2x_div = ilog2(OV5640_SCLK2X_ROOT_DIV); 12346c957ed7SJacopo Mondi 12356c957ed7SJacopo Mondi /* 12366c957ed7SJacopo Mondi * Set the pixel clock period expressed in ns with 1-bit decimal 12376c957ed7SJacopo Mondi * (0x01=0.5ns). 12386c957ed7SJacopo Mondi * 12396c957ed7SJacopo Mondi * The register is very briefly documented. In the OV5645 datasheet it 12406c957ed7SJacopo Mondi * is described as (2 * pclk period), and from testing it seems the 12416c957ed7SJacopo Mondi * actual definition is 2 * 8-bit sample period. 12426c957ed7SJacopo Mondi * 12436c957ed7SJacopo Mondi * 2 * sample_period = (mipi_clk * 2 * num_lanes / bpp) * (bpp / 8) / 2 12446c957ed7SJacopo Mondi */ 12456c957ed7SJacopo Mondi num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes; 12466c957ed7SJacopo Mondi sample_rate = (link_freq * mipi_div * num_lanes * 2) / 16; 12476c957ed7SJacopo Mondi pclk_period = 2000000000UL / sample_rate; 12486c957ed7SJacopo Mondi 12496c957ed7SJacopo Mondi /* Program the clock tree registers. */ 12506c957ed7SJacopo Mondi ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 0x0f, bit_div); 12516c957ed7SJacopo Mondi if (ret) 12526c957ed7SJacopo Mondi return ret; 12536c957ed7SJacopo Mondi 12546c957ed7SJacopo Mondi ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0xff, 12556c957ed7SJacopo Mondi (sysdiv << 4) | mipi_div); 1256aa288248SMaxime Ripard if (ret) 1257aa288248SMaxime Ripard return ret; 1258aa288248SMaxime Ripard 1259aa288248SMaxime Ripard ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 0xff, mult); 1260aa288248SMaxime Ripard if (ret) 1261aa288248SMaxime Ripard return ret; 1262aa288248SMaxime Ripard 12636c957ed7SJacopo Mondi ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 0x1f, 12646c957ed7SJacopo Mondi root_div | prediv); 1265aa288248SMaxime Ripard if (ret) 1266aa288248SMaxime Ripard return ret; 1267aa288248SMaxime Ripard 12686c957ed7SJacopo Mondi ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f, 12696c957ed7SJacopo Mondi (pclk_div << 4) | (sclk2x_div << 2) | sclk_div); 12706c957ed7SJacopo Mondi if (ret) 12716c957ed7SJacopo Mondi return ret; 12726c957ed7SJacopo Mondi 12736c957ed7SJacopo Mondi return ov5640_write_reg(sensor, OV5640_REG_PCLK_PERIOD, pclk_period); 12746c957ed7SJacopo Mondi } 12756c957ed7SJacopo Mondi 12766c957ed7SJacopo Mondi static u32 ov5640_calc_pixel_rate(struct ov5640_dev *sensor) 12776c957ed7SJacopo Mondi { 12783145efcdSJacopo Mondi const struct ov5640_mode_info *mode = sensor->current_mode; 12796c957ed7SJacopo Mondi u32 rate; 12806c957ed7SJacopo Mondi 12813145efcdSJacopo Mondi rate = mode->htot * (mode->crop.height + mode->vblank_def); 12826c957ed7SJacopo Mondi rate *= ov5640_framerates[sensor->current_fr]; 12836c957ed7SJacopo Mondi 12846c957ed7SJacopo Mondi return rate; 1285aa288248SMaxime Ripard } 1286aa288248SMaxime Ripard 1287aa288248SMaxime Ripard static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor, 1288aa288248SMaxime Ripard unsigned long rate, 1289aa288248SMaxime Ripard u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv, 1290aa288248SMaxime Ripard u8 *pll_rdiv, u8 *bit_div, u8 *pclk_div) 1291aa288248SMaxime Ripard { 1292aa288248SMaxime Ripard unsigned long _rate = rate * OV5640_PLL_ROOT_DIV * OV5640_BIT_DIV * 1293aa288248SMaxime Ripard OV5640_PCLK_ROOT_DIV; 1294aa288248SMaxime Ripard 1295aa288248SMaxime Ripard _rate = ov5640_calc_sys_clk(sensor, _rate, pll_prediv, pll_mult, 1296aa288248SMaxime Ripard sysdiv); 1297aa288248SMaxime Ripard *pll_rdiv = OV5640_PLL_ROOT_DIV; 1298aa288248SMaxime Ripard *bit_div = OV5640_BIT_DIV; 1299aa288248SMaxime Ripard *pclk_div = OV5640_PCLK_ROOT_DIV; 1300aa288248SMaxime Ripard 1301aa288248SMaxime Ripard return _rate / *pll_rdiv / *bit_div / *pclk_div; 1302aa288248SMaxime Ripard } 1303aa288248SMaxime Ripard 13046c957ed7SJacopo Mondi static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor) 1305aa288248SMaxime Ripard { 1306aa288248SMaxime Ripard u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div; 13076c957ed7SJacopo Mondi u32 rate; 1308aa288248SMaxime Ripard int ret; 1309aa288248SMaxime Ripard 13106c957ed7SJacopo Mondi rate = ov5640_calc_pixel_rate(sensor); 13116c957ed7SJacopo Mondi rate *= ov5640_code_to_bpp(sensor->fmt.code); 13126c957ed7SJacopo Mondi rate /= sensor->ep.bus.parallel.bus_width; 13136c957ed7SJacopo Mondi 1314aa288248SMaxime Ripard ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv, 1315aa288248SMaxime Ripard &bit_div, &pclk_div); 1316aa288248SMaxime Ripard 1317aa288248SMaxime Ripard if (bit_div == 2) 1318aa288248SMaxime Ripard bit_div = 8; 1319aa288248SMaxime Ripard 1320aa288248SMaxime Ripard ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 1321aa288248SMaxime Ripard 0x0f, bit_div); 1322aa288248SMaxime Ripard if (ret) 1323aa288248SMaxime Ripard return ret; 1324aa288248SMaxime Ripard 1325aa288248SMaxime Ripard /* 1326aa288248SMaxime Ripard * We need to set sysdiv according to the clock, and to clear 1327aa288248SMaxime Ripard * the MIPI divider. 1328aa288248SMaxime Ripard */ 1329aa288248SMaxime Ripard ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 1330aa288248SMaxime Ripard 0xff, sysdiv << 4); 1331aa288248SMaxime Ripard if (ret) 1332aa288248SMaxime Ripard return ret; 1333aa288248SMaxime Ripard 1334aa288248SMaxime Ripard ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 1335aa288248SMaxime Ripard 0xff, mult); 1336aa288248SMaxime Ripard if (ret) 1337aa288248SMaxime Ripard return ret; 1338aa288248SMaxime Ripard 1339aa288248SMaxime Ripard ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 1340aa288248SMaxime Ripard 0x1f, prediv | ((pll_rdiv - 1) << 4)); 1341aa288248SMaxime Ripard if (ret) 1342aa288248SMaxime Ripard return ret; 1343aa288248SMaxime Ripard 1344aa288248SMaxime Ripard return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x30, 1345aa288248SMaxime Ripard (ilog2(pclk_div) << 4)); 1346aa288248SMaxime Ripard } 1347aa288248SMaxime Ripard 13487cb013b1SChen-Yu Tsai /* set JPEG framing sizes */ 13497cb013b1SChen-Yu Tsai static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor, 13507cb013b1SChen-Yu Tsai const struct ov5640_mode_info *mode) 13517cb013b1SChen-Yu Tsai { 13527cb013b1SChen-Yu Tsai int ret; 13537cb013b1SChen-Yu Tsai 13542b5c18f9SChen-Yu Tsai /* 13552b5c18f9SChen-Yu Tsai * compression mode 3 timing 13562b5c18f9SChen-Yu Tsai * 13572b5c18f9SChen-Yu Tsai * Data is transmitted with programmable width (VFIFO_HSIZE). 13582b5c18f9SChen-Yu Tsai * No padding done. Last line may have less data. Varying 13592b5c18f9SChen-Yu Tsai * number of lines per frame, depending on amount of data. 13602b5c18f9SChen-Yu Tsai */ 13612b5c18f9SChen-Yu Tsai ret = ov5640_mod_reg(sensor, OV5640_REG_JPG_MODE_SELECT, 0x7, 0x3); 13622b5c18f9SChen-Yu Tsai if (ret < 0) 13632b5c18f9SChen-Yu Tsai return ret; 13642b5c18f9SChen-Yu Tsai 13653145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, 13663145efcdSJacopo Mondi mode->crop.width); 13677cb013b1SChen-Yu Tsai if (ret < 0) 13687cb013b1SChen-Yu Tsai return ret; 13697cb013b1SChen-Yu Tsai 13703145efcdSJacopo Mondi return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, 13713145efcdSJacopo Mondi mode->crop.height); 13727cb013b1SChen-Yu Tsai } 13737cb013b1SChen-Yu Tsai 137419a81c14SSteve Longerbeam /* download ov5640 settings to sensor through i2c */ 1375bad1774eSJacopo Mondi static int ov5640_set_timings(struct ov5640_dev *sensor, 1376bad1774eSJacopo Mondi const struct ov5640_mode_info *mode) 1377bad1774eSJacopo Mondi { 13783145efcdSJacopo Mondi const struct v4l2_rect *analog_crop = &mode->analog_crop; 13793145efcdSJacopo Mondi const struct v4l2_rect *crop = &mode->crop; 1380bad1774eSJacopo Mondi int ret; 1381bad1774eSJacopo Mondi 13827cb013b1SChen-Yu Tsai if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) { 13837cb013b1SChen-Yu Tsai ret = ov5640_set_jpeg_timings(sensor, mode); 13847cb013b1SChen-Yu Tsai if (ret < 0) 13857cb013b1SChen-Yu Tsai return ret; 13867cb013b1SChen-Yu Tsai } 13877cb013b1SChen-Yu Tsai 13883145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HS, 13893145efcdSJacopo Mondi analog_crop->left); 1390bad1774eSJacopo Mondi if (ret < 0) 1391bad1774eSJacopo Mondi return ret; 1392bad1774eSJacopo Mondi 13933145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VS, 13943145efcdSJacopo Mondi analog_crop->top); 13953145efcdSJacopo Mondi if (ret < 0) 13963145efcdSJacopo Mondi return ret; 13973145efcdSJacopo Mondi 13983145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HW, 13993145efcdSJacopo Mondi analog_crop->left + analog_crop->width - 1); 14003145efcdSJacopo Mondi if (ret < 0) 14013145efcdSJacopo Mondi return ret; 14023145efcdSJacopo Mondi 14033145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VH, 14043145efcdSJacopo Mondi analog_crop->top + analog_crop->height - 1); 14053145efcdSJacopo Mondi if (ret < 0) 14063145efcdSJacopo Mondi return ret; 14073145efcdSJacopo Mondi 14083145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HOFFS, crop->left); 14093145efcdSJacopo Mondi if (ret < 0) 14103145efcdSJacopo Mondi return ret; 14113145efcdSJacopo Mondi 14123145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VOFFS, crop->top); 14133145efcdSJacopo Mondi if (ret < 0) 14143145efcdSJacopo Mondi return ret; 14153145efcdSJacopo Mondi 14163145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, crop->width); 14173145efcdSJacopo Mondi if (ret < 0) 14183145efcdSJacopo Mondi return ret; 14193145efcdSJacopo Mondi 14203145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, crop->height); 1421bad1774eSJacopo Mondi if (ret < 0) 1422bad1774eSJacopo Mondi return ret; 1423bad1774eSJacopo Mondi 1424bad1774eSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, mode->htot); 1425bad1774eSJacopo Mondi if (ret < 0) 1426bad1774eSJacopo Mondi return ret; 1427bad1774eSJacopo Mondi 14283145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, 14293145efcdSJacopo Mondi crop->height + mode->vblank_def); 14303145efcdSJacopo Mondi if (ret < 0) 14313145efcdSJacopo Mondi return ret; 14323145efcdSJacopo Mondi 14333145efcdSJacopo Mondi return 0; 1434bad1774eSJacopo Mondi } 1435bad1774eSJacopo Mondi 143619a81c14SSteve Longerbeam static int ov5640_load_regs(struct ov5640_dev *sensor, 143719a81c14SSteve Longerbeam const struct ov5640_mode_info *mode) 143819a81c14SSteve Longerbeam { 143919a81c14SSteve Longerbeam const struct reg_value *regs = mode->reg_data; 144019a81c14SSteve Longerbeam unsigned int i; 144119a81c14SSteve Longerbeam u32 delay_ms; 144219a81c14SSteve Longerbeam u16 reg_addr; 144319a81c14SSteve Longerbeam u8 mask, val; 144419a81c14SSteve Longerbeam int ret = 0; 144519a81c14SSteve Longerbeam 144619a81c14SSteve Longerbeam for (i = 0; i < mode->reg_data_size; ++i, ++regs) { 144719a81c14SSteve Longerbeam delay_ms = regs->delay_ms; 144819a81c14SSteve Longerbeam reg_addr = regs->reg_addr; 144919a81c14SSteve Longerbeam val = regs->val; 145019a81c14SSteve Longerbeam mask = regs->mask; 145119a81c14SSteve Longerbeam 14523b987d70SLad Prabhakar /* remain in power down mode for DVP */ 14533b987d70SLad Prabhakar if (regs->reg_addr == OV5640_REG_SYS_CTRL0 && 14543b987d70SLad Prabhakar val == OV5640_REG_SYS_CTRL0_SW_PWUP && 14558e823f5cSJacopo Mondi !ov5640_is_csi2(sensor)) 14563b987d70SLad Prabhakar continue; 14573b987d70SLad Prabhakar 145819a81c14SSteve Longerbeam if (mask) 145919a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, reg_addr, mask, val); 146019a81c14SSteve Longerbeam else 146119a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, reg_addr, val); 146219a81c14SSteve Longerbeam if (ret) 146319a81c14SSteve Longerbeam break; 146419a81c14SSteve Longerbeam 146519a81c14SSteve Longerbeam if (delay_ms) 146619a81c14SSteve Longerbeam usleep_range(1000 * delay_ms, 1000 * delay_ms + 100); 146719a81c14SSteve Longerbeam } 146819a81c14SSteve Longerbeam 1469bad1774eSJacopo Mondi return ov5640_set_timings(sensor, mode); 147019a81c14SSteve Longerbeam } 147119a81c14SSteve Longerbeam 1472dc29a1c1SHugues Fruchet static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on) 1473dc29a1c1SHugues Fruchet { 1474dc29a1c1SHugues Fruchet return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL, 1475dc29a1c1SHugues Fruchet BIT(0), on ? 0 : BIT(0)); 1476dc29a1c1SHugues Fruchet } 1477dc29a1c1SHugues Fruchet 147819a81c14SSteve Longerbeam /* read exposure, in number of line periods */ 147919a81c14SSteve Longerbeam static int ov5640_get_exposure(struct ov5640_dev *sensor) 148019a81c14SSteve Longerbeam { 148119a81c14SSteve Longerbeam int exp, ret; 148219a81c14SSteve Longerbeam u8 temp; 148319a81c14SSteve Longerbeam 148419a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_HI, &temp); 148519a81c14SSteve Longerbeam if (ret) 148619a81c14SSteve Longerbeam return ret; 148719a81c14SSteve Longerbeam exp = ((int)temp & 0x0f) << 16; 148819a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_MED, &temp); 148919a81c14SSteve Longerbeam if (ret) 149019a81c14SSteve Longerbeam return ret; 149119a81c14SSteve Longerbeam exp |= ((int)temp << 8); 149219a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_LO, &temp); 149319a81c14SSteve Longerbeam if (ret) 149419a81c14SSteve Longerbeam return ret; 149519a81c14SSteve Longerbeam exp |= (int)temp; 149619a81c14SSteve Longerbeam 149719a81c14SSteve Longerbeam return exp >> 4; 149819a81c14SSteve Longerbeam } 149919a81c14SSteve Longerbeam 150019a81c14SSteve Longerbeam /* write exposure, given number of line periods */ 150119a81c14SSteve Longerbeam static int ov5640_set_exposure(struct ov5640_dev *sensor, u32 exposure) 150219a81c14SSteve Longerbeam { 150319a81c14SSteve Longerbeam int ret; 150419a81c14SSteve Longerbeam 150519a81c14SSteve Longerbeam exposure <<= 4; 150619a81c14SSteve Longerbeam 150719a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, 150819a81c14SSteve Longerbeam OV5640_REG_AEC_PK_EXPOSURE_LO, 150919a81c14SSteve Longerbeam exposure & 0xff); 151019a81c14SSteve Longerbeam if (ret) 151119a81c14SSteve Longerbeam return ret; 151219a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, 151319a81c14SSteve Longerbeam OV5640_REG_AEC_PK_EXPOSURE_MED, 151419a81c14SSteve Longerbeam (exposure >> 8) & 0xff); 151519a81c14SSteve Longerbeam if (ret) 151619a81c14SSteve Longerbeam return ret; 151719a81c14SSteve Longerbeam return ov5640_write_reg(sensor, 151819a81c14SSteve Longerbeam OV5640_REG_AEC_PK_EXPOSURE_HI, 151919a81c14SSteve Longerbeam (exposure >> 16) & 0x0f); 152019a81c14SSteve Longerbeam } 152119a81c14SSteve Longerbeam 152219a81c14SSteve Longerbeam static int ov5640_get_gain(struct ov5640_dev *sensor) 152319a81c14SSteve Longerbeam { 152419a81c14SSteve Longerbeam u16 gain; 152519a81c14SSteve Longerbeam int ret; 152619a81c14SSteve Longerbeam 152719a81c14SSteve Longerbeam ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, &gain); 152819a81c14SSteve Longerbeam if (ret) 152919a81c14SSteve Longerbeam return ret; 153019a81c14SSteve Longerbeam 153119a81c14SSteve Longerbeam return gain & 0x3ff; 153219a81c14SSteve Longerbeam } 153319a81c14SSteve Longerbeam 15343cca8ef5SHugues Fruchet static int ov5640_set_gain(struct ov5640_dev *sensor, int gain) 15353cca8ef5SHugues Fruchet { 15363cca8ef5SHugues Fruchet return ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, 15373cca8ef5SHugues Fruchet (u16)gain & 0x3ff); 15383cca8ef5SHugues Fruchet } 15393cca8ef5SHugues Fruchet 15403cca8ef5SHugues Fruchet static int ov5640_set_autogain(struct ov5640_dev *sensor, bool on) 15413cca8ef5SHugues Fruchet { 15423cca8ef5SHugues Fruchet return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL, 15433cca8ef5SHugues Fruchet BIT(1), on ? 0 : BIT(1)); 15443cca8ef5SHugues Fruchet } 15453cca8ef5SHugues Fruchet 1546f22996dbSHugues Fruchet static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on) 1547f22996dbSHugues Fruchet { 15483b987d70SLad Prabhakar return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ? 15493b987d70SLad Prabhakar OV5640_REG_SYS_CTRL0_SW_PWUP : 15503b987d70SLad Prabhakar OV5640_REG_SYS_CTRL0_SW_PWDN); 1551f22996dbSHugues Fruchet } 1552f22996dbSHugues Fruchet 1553f22996dbSHugues Fruchet static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on) 155419a81c14SSteve Longerbeam { 155519a81c14SSteve Longerbeam int ret; 155619a81c14SSteve Longerbeam 1557aa4bb8b8SJacopo Mondi /* 1558aa4bb8b8SJacopo Mondi * Enable/disable the MIPI interface 1559aa4bb8b8SJacopo Mondi * 1560aa4bb8b8SJacopo Mondi * 0x300e = on ? 0x45 : 0x40 1561aa4bb8b8SJacopo Mondi * 1562aa4bb8b8SJacopo Mondi * FIXME: the sensor manual (version 2.03) reports 1563aa4bb8b8SJacopo Mondi * [7:5] = 000 : 1 data lane mode 1564aa4bb8b8SJacopo Mondi * [7:5] = 001 : 2 data lanes mode 1565aa4bb8b8SJacopo Mondi * But this settings do not work, while the following ones 1566aa4bb8b8SJacopo Mondi * have been validated for 2 data lanes mode. 1567aa4bb8b8SJacopo Mondi * 1568aa4bb8b8SJacopo Mondi * [7:5] = 010 : 2 data lanes mode 1569aa4bb8b8SJacopo Mondi * [4] = 0 : Power up MIPI HS Tx 1570aa4bb8b8SJacopo Mondi * [3] = 0 : Power up MIPI LS Rx 1571aa4bb8b8SJacopo Mondi * [2] = 1/0 : MIPI interface enable/disable 1572aa4bb8b8SJacopo Mondi * [1:0] = 01/00: FIXME: 'debug' 1573aa4bb8b8SJacopo Mondi */ 1574aa4bb8b8SJacopo Mondi ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 1575aa4bb8b8SJacopo Mondi on ? 0x45 : 0x40); 157619a81c14SSteve Longerbeam if (ret) 157719a81c14SSteve Longerbeam return ret; 157819a81c14SSteve Longerbeam 157919a81c14SSteve Longerbeam return ov5640_write_reg(sensor, OV5640_REG_FRAME_CTRL01, 158019a81c14SSteve Longerbeam on ? 0x00 : 0x0f); 158119a81c14SSteve Longerbeam } 158219a81c14SSteve Longerbeam 158319a81c14SSteve Longerbeam static int ov5640_get_sysclk(struct ov5640_dev *sensor) 158419a81c14SSteve Longerbeam { 158519a81c14SSteve Longerbeam /* calculate sysclk */ 158619a81c14SSteve Longerbeam u32 xvclk = sensor->xclk_freq / 10000; 158719a81c14SSteve Longerbeam u32 multiplier, prediv, VCO, sysdiv, pll_rdiv; 158819a81c14SSteve Longerbeam u32 sclk_rdiv_map[] = {1, 2, 4, 8}; 158919a81c14SSteve Longerbeam u32 bit_div2x = 1, sclk_rdiv, sysclk; 159019a81c14SSteve Longerbeam u8 temp1, temp2; 159119a81c14SSteve Longerbeam int ret; 159219a81c14SSteve Longerbeam 159319a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL0, &temp1); 159419a81c14SSteve Longerbeam if (ret) 159519a81c14SSteve Longerbeam return ret; 159619a81c14SSteve Longerbeam temp2 = temp1 & 0x0f; 159719a81c14SSteve Longerbeam if (temp2 == 8 || temp2 == 10) 159819a81c14SSteve Longerbeam bit_div2x = temp2 / 2; 159919a81c14SSteve Longerbeam 160019a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL1, &temp1); 160119a81c14SSteve Longerbeam if (ret) 160219a81c14SSteve Longerbeam return ret; 160319a81c14SSteve Longerbeam sysdiv = temp1 >> 4; 160419a81c14SSteve Longerbeam if (sysdiv == 0) 160519a81c14SSteve Longerbeam sysdiv = 16; 160619a81c14SSteve Longerbeam 160719a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL2, &temp1); 160819a81c14SSteve Longerbeam if (ret) 160919a81c14SSteve Longerbeam return ret; 161019a81c14SSteve Longerbeam multiplier = temp1; 161119a81c14SSteve Longerbeam 161219a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL3, &temp1); 161319a81c14SSteve Longerbeam if (ret) 161419a81c14SSteve Longerbeam return ret; 161519a81c14SSteve Longerbeam prediv = temp1 & 0x0f; 161619a81c14SSteve Longerbeam pll_rdiv = ((temp1 >> 4) & 0x01) + 1; 161719a81c14SSteve Longerbeam 161819a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, &temp1); 161919a81c14SSteve Longerbeam if (ret) 162019a81c14SSteve Longerbeam return ret; 162119a81c14SSteve Longerbeam temp2 = temp1 & 0x03; 162219a81c14SSteve Longerbeam sclk_rdiv = sclk_rdiv_map[temp2]; 162319a81c14SSteve Longerbeam 162419a81c14SSteve Longerbeam if (!prediv || !sysdiv || !pll_rdiv || !bit_div2x) 162519a81c14SSteve Longerbeam return -EINVAL; 162619a81c14SSteve Longerbeam 162719a81c14SSteve Longerbeam VCO = xvclk * multiplier / prediv; 162819a81c14SSteve Longerbeam 162919a81c14SSteve Longerbeam sysclk = VCO / sysdiv / pll_rdiv * 2 / bit_div2x / sclk_rdiv; 163019a81c14SSteve Longerbeam 163119a81c14SSteve Longerbeam return sysclk; 163219a81c14SSteve Longerbeam } 163319a81c14SSteve Longerbeam 163419a81c14SSteve Longerbeam static int ov5640_set_night_mode(struct ov5640_dev *sensor) 163519a81c14SSteve Longerbeam { 163619a81c14SSteve Longerbeam /* read HTS from register settings */ 163719a81c14SSteve Longerbeam u8 mode; 163819a81c14SSteve Longerbeam int ret; 163919a81c14SSteve Longerbeam 164019a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_AEC_CTRL00, &mode); 164119a81c14SSteve Longerbeam if (ret) 164219a81c14SSteve Longerbeam return ret; 164319a81c14SSteve Longerbeam mode &= 0xfb; 164419a81c14SSteve Longerbeam return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL00, mode); 164519a81c14SSteve Longerbeam } 164619a81c14SSteve Longerbeam 164719a81c14SSteve Longerbeam static int ov5640_get_hts(struct ov5640_dev *sensor) 164819a81c14SSteve Longerbeam { 164919a81c14SSteve Longerbeam /* read HTS from register settings */ 165019a81c14SSteve Longerbeam u16 hts; 165119a81c14SSteve Longerbeam int ret; 165219a81c14SSteve Longerbeam 165319a81c14SSteve Longerbeam ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_HTS, &hts); 165419a81c14SSteve Longerbeam if (ret) 165519a81c14SSteve Longerbeam return ret; 165619a81c14SSteve Longerbeam return hts; 165719a81c14SSteve Longerbeam } 165819a81c14SSteve Longerbeam 165919a81c14SSteve Longerbeam static int ov5640_get_vts(struct ov5640_dev *sensor) 166019a81c14SSteve Longerbeam { 166119a81c14SSteve Longerbeam u16 vts; 166219a81c14SSteve Longerbeam int ret; 166319a81c14SSteve Longerbeam 166419a81c14SSteve Longerbeam ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_VTS, &vts); 166519a81c14SSteve Longerbeam if (ret) 166619a81c14SSteve Longerbeam return ret; 166719a81c14SSteve Longerbeam return vts; 166819a81c14SSteve Longerbeam } 166919a81c14SSteve Longerbeam 167019a81c14SSteve Longerbeam static int ov5640_set_vts(struct ov5640_dev *sensor, int vts) 167119a81c14SSteve Longerbeam { 167219a81c14SSteve Longerbeam return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, vts); 167319a81c14SSteve Longerbeam } 167419a81c14SSteve Longerbeam 167519a81c14SSteve Longerbeam static int ov5640_get_light_freq(struct ov5640_dev *sensor) 167619a81c14SSteve Longerbeam { 167719a81c14SSteve Longerbeam /* get banding filter value */ 167819a81c14SSteve Longerbeam int ret, light_freq = 0; 167919a81c14SSteve Longerbeam u8 temp, temp1; 168019a81c14SSteve Longerbeam 168119a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL01, &temp); 168219a81c14SSteve Longerbeam if (ret) 168319a81c14SSteve Longerbeam return ret; 168419a81c14SSteve Longerbeam 168519a81c14SSteve Longerbeam if (temp & 0x80) { 168619a81c14SSteve Longerbeam /* manual */ 168719a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL00, 168819a81c14SSteve Longerbeam &temp1); 168919a81c14SSteve Longerbeam if (ret) 169019a81c14SSteve Longerbeam return ret; 169119a81c14SSteve Longerbeam if (temp1 & 0x04) { 169219a81c14SSteve Longerbeam /* 50Hz */ 169319a81c14SSteve Longerbeam light_freq = 50; 169419a81c14SSteve Longerbeam } else { 169519a81c14SSteve Longerbeam /* 60Hz */ 169619a81c14SSteve Longerbeam light_freq = 60; 169719a81c14SSteve Longerbeam } 169819a81c14SSteve Longerbeam } else { 169919a81c14SSteve Longerbeam /* auto */ 170019a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_SIGMADELTA_CTRL0C, 170119a81c14SSteve Longerbeam &temp1); 170219a81c14SSteve Longerbeam if (ret) 170319a81c14SSteve Longerbeam return ret; 170419a81c14SSteve Longerbeam 170519a81c14SSteve Longerbeam if (temp1 & 0x01) { 170619a81c14SSteve Longerbeam /* 50Hz */ 170719a81c14SSteve Longerbeam light_freq = 50; 170819a81c14SSteve Longerbeam } else { 170919a81c14SSteve Longerbeam /* 60Hz */ 171019a81c14SSteve Longerbeam } 171119a81c14SSteve Longerbeam } 171219a81c14SSteve Longerbeam 171319a81c14SSteve Longerbeam return light_freq; 171419a81c14SSteve Longerbeam } 171519a81c14SSteve Longerbeam 171619a81c14SSteve Longerbeam static int ov5640_set_bandingfilter(struct ov5640_dev *sensor) 171719a81c14SSteve Longerbeam { 171819a81c14SSteve Longerbeam u32 band_step60, max_band60, band_step50, max_band50, prev_vts; 171919a81c14SSteve Longerbeam int ret; 172019a81c14SSteve Longerbeam 172119a81c14SSteve Longerbeam /* read preview PCLK */ 172219a81c14SSteve Longerbeam ret = ov5640_get_sysclk(sensor); 172319a81c14SSteve Longerbeam if (ret < 0) 172419a81c14SSteve Longerbeam return ret; 172519a81c14SSteve Longerbeam if (ret == 0) 172619a81c14SSteve Longerbeam return -EINVAL; 172719a81c14SSteve Longerbeam sensor->prev_sysclk = ret; 172819a81c14SSteve Longerbeam /* read preview HTS */ 172919a81c14SSteve Longerbeam ret = ov5640_get_hts(sensor); 173019a81c14SSteve Longerbeam if (ret < 0) 173119a81c14SSteve Longerbeam return ret; 173219a81c14SSteve Longerbeam if (ret == 0) 173319a81c14SSteve Longerbeam return -EINVAL; 173419a81c14SSteve Longerbeam sensor->prev_hts = ret; 173519a81c14SSteve Longerbeam 173619a81c14SSteve Longerbeam /* read preview VTS */ 173719a81c14SSteve Longerbeam ret = ov5640_get_vts(sensor); 173819a81c14SSteve Longerbeam if (ret < 0) 173919a81c14SSteve Longerbeam return ret; 174019a81c14SSteve Longerbeam prev_vts = ret; 174119a81c14SSteve Longerbeam 174219a81c14SSteve Longerbeam /* calculate banding filter */ 174319a81c14SSteve Longerbeam /* 60Hz */ 174419a81c14SSteve Longerbeam band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100 / 120; 174519a81c14SSteve Longerbeam ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B60_STEP, band_step60); 174619a81c14SSteve Longerbeam if (ret) 174719a81c14SSteve Longerbeam return ret; 174819a81c14SSteve Longerbeam if (!band_step60) 174919a81c14SSteve Longerbeam return -EINVAL; 175019a81c14SSteve Longerbeam max_band60 = (int)((prev_vts - 4) / band_step60); 175119a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0D, max_band60); 175219a81c14SSteve Longerbeam if (ret) 175319a81c14SSteve Longerbeam return ret; 175419a81c14SSteve Longerbeam 175519a81c14SSteve Longerbeam /* 50Hz */ 175619a81c14SSteve Longerbeam band_step50 = sensor->prev_sysclk * 100 / sensor->prev_hts; 175719a81c14SSteve Longerbeam ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B50_STEP, band_step50); 175819a81c14SSteve Longerbeam if (ret) 175919a81c14SSteve Longerbeam return ret; 176019a81c14SSteve Longerbeam if (!band_step50) 176119a81c14SSteve Longerbeam return -EINVAL; 176219a81c14SSteve Longerbeam max_band50 = (int)((prev_vts - 4) / band_step50); 176319a81c14SSteve Longerbeam return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0E, max_band50); 176419a81c14SSteve Longerbeam } 176519a81c14SSteve Longerbeam 176619a81c14SSteve Longerbeam static int ov5640_set_ae_target(struct ov5640_dev *sensor, int target) 176719a81c14SSteve Longerbeam { 176819a81c14SSteve Longerbeam /* stable in high */ 176919a81c14SSteve Longerbeam u32 fast_high, fast_low; 177019a81c14SSteve Longerbeam int ret; 177119a81c14SSteve Longerbeam 177219a81c14SSteve Longerbeam sensor->ae_low = target * 23 / 25; /* 0.92 */ 177319a81c14SSteve Longerbeam sensor->ae_high = target * 27 / 25; /* 1.08 */ 177419a81c14SSteve Longerbeam 177519a81c14SSteve Longerbeam fast_high = sensor->ae_high << 1; 177619a81c14SSteve Longerbeam if (fast_high > 255) 177719a81c14SSteve Longerbeam fast_high = 255; 177819a81c14SSteve Longerbeam 177919a81c14SSteve Longerbeam fast_low = sensor->ae_low >> 1; 178019a81c14SSteve Longerbeam 178119a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0F, sensor->ae_high); 178219a81c14SSteve Longerbeam if (ret) 178319a81c14SSteve Longerbeam return ret; 178419a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL10, sensor->ae_low); 178519a81c14SSteve Longerbeam if (ret) 178619a81c14SSteve Longerbeam return ret; 178719a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1B, sensor->ae_high); 178819a81c14SSteve Longerbeam if (ret) 178919a81c14SSteve Longerbeam return ret; 179019a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1E, sensor->ae_low); 179119a81c14SSteve Longerbeam if (ret) 179219a81c14SSteve Longerbeam return ret; 179319a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL11, fast_high); 179419a81c14SSteve Longerbeam if (ret) 179519a81c14SSteve Longerbeam return ret; 179619a81c14SSteve Longerbeam return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1F, fast_low); 179719a81c14SSteve Longerbeam } 179819a81c14SSteve Longerbeam 1799c2c3f42dSHugues Fruchet static int ov5640_get_binning(struct ov5640_dev *sensor) 180019a81c14SSteve Longerbeam { 180119a81c14SSteve Longerbeam u8 temp; 180219a81c14SSteve Longerbeam int ret; 180319a81c14SSteve Longerbeam 180419a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_TIMING_TC_REG21, &temp); 180519a81c14SSteve Longerbeam if (ret) 180619a81c14SSteve Longerbeam return ret; 1807c2c3f42dSHugues Fruchet 1808c2c3f42dSHugues Fruchet return temp & BIT(0); 180919a81c14SSteve Longerbeam } 181019a81c14SSteve Longerbeam 1811ce85705aSHugues Fruchet static int ov5640_set_binning(struct ov5640_dev *sensor, bool enable) 1812ce85705aSHugues Fruchet { 1813ce85705aSHugues Fruchet int ret; 1814ce85705aSHugues Fruchet 1815ce85705aSHugues Fruchet /* 1816ce85705aSHugues Fruchet * TIMING TC REG21: 1817ce85705aSHugues Fruchet * - [0]: Horizontal binning enable 1818ce85705aSHugues Fruchet */ 1819ce85705aSHugues Fruchet ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21, 1820ce85705aSHugues Fruchet BIT(0), enable ? BIT(0) : 0); 1821ce85705aSHugues Fruchet if (ret) 1822ce85705aSHugues Fruchet return ret; 1823ce85705aSHugues Fruchet /* 1824ce85705aSHugues Fruchet * TIMING TC REG20: 1825ce85705aSHugues Fruchet * - [0]: Undocumented, but hardcoded init sequences 1826ce85705aSHugues Fruchet * are always setting REG21/REG20 bit 0 to same value... 1827ce85705aSHugues Fruchet */ 1828ce85705aSHugues Fruchet return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20, 1829ce85705aSHugues Fruchet BIT(0), enable ? BIT(0) : 0); 1830ce85705aSHugues Fruchet } 1831ce85705aSHugues Fruchet 183219a81c14SSteve Longerbeam static int ov5640_set_virtual_channel(struct ov5640_dev *sensor) 183319a81c14SSteve Longerbeam { 18348670d70aSHugues Fruchet struct i2c_client *client = sensor->i2c_client; 183519a81c14SSteve Longerbeam u8 temp, channel = virtual_channel; 183619a81c14SSteve Longerbeam int ret; 183719a81c14SSteve Longerbeam 18388670d70aSHugues Fruchet if (channel > 3) { 18398670d70aSHugues Fruchet dev_err(&client->dev, 18408670d70aSHugues Fruchet "%s: wrong virtual_channel parameter, expected (0..3), got %d\n", 18418670d70aSHugues Fruchet __func__, channel); 184219a81c14SSteve Longerbeam return -EINVAL; 18438670d70aSHugues Fruchet } 184419a81c14SSteve Longerbeam 184519a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_DEBUG_MODE, &temp); 184619a81c14SSteve Longerbeam if (ret) 184719a81c14SSteve Longerbeam return ret; 184819a81c14SSteve Longerbeam temp &= ~(3 << 6); 184919a81c14SSteve Longerbeam temp |= (channel << 6); 185019a81c14SSteve Longerbeam return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp); 185119a81c14SSteve Longerbeam } 185219a81c14SSteve Longerbeam 185319a81c14SSteve Longerbeam static const struct ov5640_mode_info * 185419a81c14SSteve Longerbeam ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr, 185519a81c14SSteve Longerbeam int width, int height, bool nearest) 185619a81c14SSteve Longerbeam { 18573c4a7372SHugues Fruchet const struct ov5640_mode_info *mode; 185819a81c14SSteve Longerbeam 1859086c25f8SMaxime Ripard mode = v4l2_find_nearest_size(ov5640_mode_data, 1860086c25f8SMaxime Ripard ARRAY_SIZE(ov5640_mode_data), 18613145efcdSJacopo Mondi crop.width, crop.height, width, height); 186219a81c14SSteve Longerbeam 18633c4a7372SHugues Fruchet if (!mode || 18643145efcdSJacopo Mondi (!nearest && 18653145efcdSJacopo Mondi (mode->crop.width != width || mode->crop.height != height))) 18663c4a7372SHugues Fruchet return NULL; 186719a81c14SSteve Longerbeam 18685554c80eSAdam Ford /* Check to see if the current mode exceeds the max frame rate */ 18695554c80eSAdam Ford if (ov5640_framerates[fr] > ov5640_framerates[mode->max_fps]) 1870981e4454SBenoit Parrot return NULL; 1871981e4454SBenoit Parrot 187219a81c14SSteve Longerbeam return mode; 187319a81c14SSteve Longerbeam } 187419a81c14SSteve Longerbeam 187519a81c14SSteve Longerbeam /* 187619a81c14SSteve Longerbeam * sensor changes between scaling and subsampling, go through 187719a81c14SSteve Longerbeam * exposure calculation 187819a81c14SSteve Longerbeam */ 187941d8d7f5SHugues Fruchet static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor, 188041d8d7f5SHugues Fruchet const struct ov5640_mode_info *mode) 188119a81c14SSteve Longerbeam { 188219a81c14SSteve Longerbeam u32 prev_shutter, prev_gain16; 188319a81c14SSteve Longerbeam u32 cap_shutter, cap_gain16; 188419a81c14SSteve Longerbeam u32 cap_sysclk, cap_hts, cap_vts; 188519a81c14SSteve Longerbeam u32 light_freq, cap_bandfilt, cap_maxband; 188619a81c14SSteve Longerbeam u32 cap_gain16_shutter; 188719a81c14SSteve Longerbeam u8 average; 188819a81c14SSteve Longerbeam int ret; 188919a81c14SSteve Longerbeam 189041d8d7f5SHugues Fruchet if (!mode->reg_data) 189119a81c14SSteve Longerbeam return -EINVAL; 189219a81c14SSteve Longerbeam 189319a81c14SSteve Longerbeam /* read preview shutter */ 189419a81c14SSteve Longerbeam ret = ov5640_get_exposure(sensor); 189519a81c14SSteve Longerbeam if (ret < 0) 189619a81c14SSteve Longerbeam return ret; 189719a81c14SSteve Longerbeam prev_shutter = ret; 1898c2c3f42dSHugues Fruchet ret = ov5640_get_binning(sensor); 189919a81c14SSteve Longerbeam if (ret < 0) 190019a81c14SSteve Longerbeam return ret; 190119a81c14SSteve Longerbeam if (ret && mode->id != OV5640_MODE_720P_1280_720 && 190219a81c14SSteve Longerbeam mode->id != OV5640_MODE_1080P_1920_1080) 190319a81c14SSteve Longerbeam prev_shutter *= 2; 190419a81c14SSteve Longerbeam 190519a81c14SSteve Longerbeam /* read preview gain */ 190619a81c14SSteve Longerbeam ret = ov5640_get_gain(sensor); 190719a81c14SSteve Longerbeam if (ret < 0) 190819a81c14SSteve Longerbeam return ret; 190919a81c14SSteve Longerbeam prev_gain16 = ret; 191019a81c14SSteve Longerbeam 191119a81c14SSteve Longerbeam /* get average */ 191219a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_AVG_READOUT, &average); 191319a81c14SSteve Longerbeam if (ret) 191419a81c14SSteve Longerbeam return ret; 191519a81c14SSteve Longerbeam 191619a81c14SSteve Longerbeam /* turn off night mode for capture */ 191719a81c14SSteve Longerbeam ret = ov5640_set_night_mode(sensor); 191819a81c14SSteve Longerbeam if (ret < 0) 191919a81c14SSteve Longerbeam return ret; 192019a81c14SSteve Longerbeam 192119a81c14SSteve Longerbeam /* Write capture setting */ 192219a81c14SSteve Longerbeam ret = ov5640_load_regs(sensor, mode); 192319a81c14SSteve Longerbeam if (ret < 0) 192419a81c14SSteve Longerbeam return ret; 192519a81c14SSteve Longerbeam 192619a81c14SSteve Longerbeam /* read capture VTS */ 192719a81c14SSteve Longerbeam ret = ov5640_get_vts(sensor); 192819a81c14SSteve Longerbeam if (ret < 0) 192919a81c14SSteve Longerbeam return ret; 193019a81c14SSteve Longerbeam cap_vts = ret; 193119a81c14SSteve Longerbeam ret = ov5640_get_hts(sensor); 193219a81c14SSteve Longerbeam if (ret < 0) 193319a81c14SSteve Longerbeam return ret; 193419a81c14SSteve Longerbeam if (ret == 0) 193519a81c14SSteve Longerbeam return -EINVAL; 193619a81c14SSteve Longerbeam cap_hts = ret; 193719a81c14SSteve Longerbeam 193819a81c14SSteve Longerbeam ret = ov5640_get_sysclk(sensor); 193919a81c14SSteve Longerbeam if (ret < 0) 194019a81c14SSteve Longerbeam return ret; 194119a81c14SSteve Longerbeam if (ret == 0) 194219a81c14SSteve Longerbeam return -EINVAL; 194319a81c14SSteve Longerbeam cap_sysclk = ret; 194419a81c14SSteve Longerbeam 194519a81c14SSteve Longerbeam /* calculate capture banding filter */ 194619a81c14SSteve Longerbeam ret = ov5640_get_light_freq(sensor); 194719a81c14SSteve Longerbeam if (ret < 0) 194819a81c14SSteve Longerbeam return ret; 194919a81c14SSteve Longerbeam light_freq = ret; 195019a81c14SSteve Longerbeam 195119a81c14SSteve Longerbeam if (light_freq == 60) { 195219a81c14SSteve Longerbeam /* 60Hz */ 195319a81c14SSteve Longerbeam cap_bandfilt = cap_sysclk * 100 / cap_hts * 100 / 120; 195419a81c14SSteve Longerbeam } else { 195519a81c14SSteve Longerbeam /* 50Hz */ 195619a81c14SSteve Longerbeam cap_bandfilt = cap_sysclk * 100 / cap_hts; 195719a81c14SSteve Longerbeam } 195819a81c14SSteve Longerbeam 195919a81c14SSteve Longerbeam if (!sensor->prev_sysclk) { 196019a81c14SSteve Longerbeam ret = ov5640_get_sysclk(sensor); 196119a81c14SSteve Longerbeam if (ret < 0) 196219a81c14SSteve Longerbeam return ret; 196319a81c14SSteve Longerbeam if (ret == 0) 196419a81c14SSteve Longerbeam return -EINVAL; 196519a81c14SSteve Longerbeam sensor->prev_sysclk = ret; 196619a81c14SSteve Longerbeam } 196719a81c14SSteve Longerbeam 196819a81c14SSteve Longerbeam if (!cap_bandfilt) 196919a81c14SSteve Longerbeam return -EINVAL; 197019a81c14SSteve Longerbeam 197119a81c14SSteve Longerbeam cap_maxband = (int)((cap_vts - 4) / cap_bandfilt); 197219a81c14SSteve Longerbeam 197319a81c14SSteve Longerbeam /* calculate capture shutter/gain16 */ 197419a81c14SSteve Longerbeam if (average > sensor->ae_low && average < sensor->ae_high) { 197519a81c14SSteve Longerbeam /* in stable range */ 197619a81c14SSteve Longerbeam cap_gain16_shutter = 197719a81c14SSteve Longerbeam prev_gain16 * prev_shutter * 197819a81c14SSteve Longerbeam cap_sysclk / sensor->prev_sysclk * 197919a81c14SSteve Longerbeam sensor->prev_hts / cap_hts * 198019a81c14SSteve Longerbeam sensor->ae_target / average; 198119a81c14SSteve Longerbeam } else { 198219a81c14SSteve Longerbeam cap_gain16_shutter = 198319a81c14SSteve Longerbeam prev_gain16 * prev_shutter * 198419a81c14SSteve Longerbeam cap_sysclk / sensor->prev_sysclk * 198519a81c14SSteve Longerbeam sensor->prev_hts / cap_hts; 198619a81c14SSteve Longerbeam } 198719a81c14SSteve Longerbeam 198819a81c14SSteve Longerbeam /* gain to shutter */ 198919a81c14SSteve Longerbeam if (cap_gain16_shutter < (cap_bandfilt * 16)) { 199019a81c14SSteve Longerbeam /* shutter < 1/100 */ 199119a81c14SSteve Longerbeam cap_shutter = cap_gain16_shutter / 16; 199219a81c14SSteve Longerbeam if (cap_shutter < 1) 199319a81c14SSteve Longerbeam cap_shutter = 1; 199419a81c14SSteve Longerbeam 199519a81c14SSteve Longerbeam cap_gain16 = cap_gain16_shutter / cap_shutter; 199619a81c14SSteve Longerbeam if (cap_gain16 < 16) 199719a81c14SSteve Longerbeam cap_gain16 = 16; 199819a81c14SSteve Longerbeam } else { 199919a81c14SSteve Longerbeam if (cap_gain16_shutter > (cap_bandfilt * cap_maxband * 16)) { 200019a81c14SSteve Longerbeam /* exposure reach max */ 200119a81c14SSteve Longerbeam cap_shutter = cap_bandfilt * cap_maxband; 200219a81c14SSteve Longerbeam if (!cap_shutter) 200319a81c14SSteve Longerbeam return -EINVAL; 200419a81c14SSteve Longerbeam 200519a81c14SSteve Longerbeam cap_gain16 = cap_gain16_shutter / cap_shutter; 200619a81c14SSteve Longerbeam } else { 200719a81c14SSteve Longerbeam /* 1/100 < (cap_shutter = n/100) =< max */ 200819a81c14SSteve Longerbeam cap_shutter = 200919a81c14SSteve Longerbeam ((int)(cap_gain16_shutter / 16 / cap_bandfilt)) 201019a81c14SSteve Longerbeam * cap_bandfilt; 201119a81c14SSteve Longerbeam if (!cap_shutter) 201219a81c14SSteve Longerbeam return -EINVAL; 201319a81c14SSteve Longerbeam 201419a81c14SSteve Longerbeam cap_gain16 = cap_gain16_shutter / cap_shutter; 201519a81c14SSteve Longerbeam } 201619a81c14SSteve Longerbeam } 201719a81c14SSteve Longerbeam 201819a81c14SSteve Longerbeam /* set capture gain */ 20193cca8ef5SHugues Fruchet ret = ov5640_set_gain(sensor, cap_gain16); 202019a81c14SSteve Longerbeam if (ret) 202119a81c14SSteve Longerbeam return ret; 202219a81c14SSteve Longerbeam 202319a81c14SSteve Longerbeam /* write capture shutter */ 202419a81c14SSteve Longerbeam if (cap_shutter > (cap_vts - 4)) { 202519a81c14SSteve Longerbeam cap_vts = cap_shutter + 4; 202619a81c14SSteve Longerbeam ret = ov5640_set_vts(sensor, cap_vts); 202719a81c14SSteve Longerbeam if (ret < 0) 202819a81c14SSteve Longerbeam return ret; 202919a81c14SSteve Longerbeam } 203019a81c14SSteve Longerbeam 203119a81c14SSteve Longerbeam /* set exposure */ 20323cca8ef5SHugues Fruchet return ov5640_set_exposure(sensor, cap_shutter); 203319a81c14SSteve Longerbeam } 203419a81c14SSteve Longerbeam 203519a81c14SSteve Longerbeam /* 203619a81c14SSteve Longerbeam * if sensor changes inside scaling or subsampling 203719a81c14SSteve Longerbeam * change mode directly 203819a81c14SSteve Longerbeam */ 203919a81c14SSteve Longerbeam static int ov5640_set_mode_direct(struct ov5640_dev *sensor, 20403cca8ef5SHugues Fruchet const struct ov5640_mode_info *mode) 204119a81c14SSteve Longerbeam { 204241d8d7f5SHugues Fruchet if (!mode->reg_data) 204319a81c14SSteve Longerbeam return -EINVAL; 204419a81c14SSteve Longerbeam 204519a81c14SSteve Longerbeam /* Write capture setting */ 20463cca8ef5SHugues Fruchet return ov5640_load_regs(sensor, mode); 204719a81c14SSteve Longerbeam } 204819a81c14SSteve Longerbeam 2049985cdcb0SHugues Fruchet static int ov5640_set_mode(struct ov5640_dev *sensor) 205019a81c14SSteve Longerbeam { 205119a81c14SSteve Longerbeam const struct ov5640_mode_info *mode = sensor->current_mode; 2052985cdcb0SHugues Fruchet const struct ov5640_mode_info *orig_mode = sensor->last_mode; 205319a81c14SSteve Longerbeam enum ov5640_downsize_mode dn_mode, orig_dn_mode; 20543cca8ef5SHugues Fruchet bool auto_gain = sensor->ctrls.auto_gain->val == 1; 2055dc29a1c1SHugues Fruchet bool auto_exp = sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO; 205619a81c14SSteve Longerbeam int ret; 205719a81c14SSteve Longerbeam 205819a81c14SSteve Longerbeam dn_mode = mode->dn_mode; 205919a81c14SSteve Longerbeam orig_dn_mode = orig_mode->dn_mode; 206019a81c14SSteve Longerbeam 206119a81c14SSteve Longerbeam /* auto gain and exposure must be turned off when changing modes */ 20623cca8ef5SHugues Fruchet if (auto_gain) { 20633cca8ef5SHugues Fruchet ret = ov5640_set_autogain(sensor, false); 206419a81c14SSteve Longerbeam if (ret) 206519a81c14SSteve Longerbeam return ret; 20663cca8ef5SHugues Fruchet } 2067bf4a4b51SMaxime Ripard 20683cca8ef5SHugues Fruchet if (auto_exp) { 2069dc29a1c1SHugues Fruchet ret = ov5640_set_autoexposure(sensor, false); 207019a81c14SSteve Longerbeam if (ret) 20713cca8ef5SHugues Fruchet goto restore_auto_gain; 20723cca8ef5SHugues Fruchet } 207319a81c14SSteve Longerbeam 20746c957ed7SJacopo Mondi if (ov5640_is_csi2(sensor)) 20756c957ed7SJacopo Mondi ret = ov5640_set_mipi_pclk(sensor); 20766c957ed7SJacopo Mondi else 20776c957ed7SJacopo Mondi ret = ov5640_set_dvp_pclk(sensor); 2078aa288248SMaxime Ripard if (ret < 0) 2079aa288248SMaxime Ripard return 0; 2080aa288248SMaxime Ripard 208119a81c14SSteve Longerbeam if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) || 208219a81c14SSteve Longerbeam (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) { 208319a81c14SSteve Longerbeam /* 208419a81c14SSteve Longerbeam * change between subsampling and scaling 20853cca8ef5SHugues Fruchet * go through exposure calculation 208619a81c14SSteve Longerbeam */ 208719a81c14SSteve Longerbeam ret = ov5640_set_mode_exposure_calc(sensor, mode); 208819a81c14SSteve Longerbeam } else { 208919a81c14SSteve Longerbeam /* 209019a81c14SSteve Longerbeam * change inside subsampling or scaling 209119a81c14SSteve Longerbeam * download firmware directly 209219a81c14SSteve Longerbeam */ 20933cca8ef5SHugues Fruchet ret = ov5640_set_mode_direct(sensor, mode); 209419a81c14SSteve Longerbeam } 209519a81c14SSteve Longerbeam if (ret < 0) 20963cca8ef5SHugues Fruchet goto restore_auto_exp_gain; 20973cca8ef5SHugues Fruchet 20983cca8ef5SHugues Fruchet /* restore auto gain and exposure */ 20993cca8ef5SHugues Fruchet if (auto_gain) 21003cca8ef5SHugues Fruchet ov5640_set_autogain(sensor, true); 21013cca8ef5SHugues Fruchet if (auto_exp) 21023cca8ef5SHugues Fruchet ov5640_set_autoexposure(sensor, true); 210319a81c14SSteve Longerbeam 2104ce85705aSHugues Fruchet ret = ov5640_set_binning(sensor, dn_mode != SCALING); 2105ce85705aSHugues Fruchet if (ret < 0) 2106ce85705aSHugues Fruchet return ret; 210719a81c14SSteve Longerbeam ret = ov5640_set_ae_target(sensor, sensor->ae_target); 210819a81c14SSteve Longerbeam if (ret < 0) 210919a81c14SSteve Longerbeam return ret; 211019a81c14SSteve Longerbeam ret = ov5640_get_light_freq(sensor); 211119a81c14SSteve Longerbeam if (ret < 0) 211219a81c14SSteve Longerbeam return ret; 211319a81c14SSteve Longerbeam ret = ov5640_set_bandingfilter(sensor); 211419a81c14SSteve Longerbeam if (ret < 0) 211519a81c14SSteve Longerbeam return ret; 211619a81c14SSteve Longerbeam ret = ov5640_set_virtual_channel(sensor); 211719a81c14SSteve Longerbeam if (ret < 0) 211819a81c14SSteve Longerbeam return ret; 211919a81c14SSteve Longerbeam 212019a81c14SSteve Longerbeam sensor->pending_mode_change = false; 2121985cdcb0SHugues Fruchet sensor->last_mode = mode; 212219a81c14SSteve Longerbeam 212319a81c14SSteve Longerbeam return 0; 21243cca8ef5SHugues Fruchet 21253cca8ef5SHugues Fruchet restore_auto_exp_gain: 21263cca8ef5SHugues Fruchet if (auto_exp) 21273cca8ef5SHugues Fruchet ov5640_set_autoexposure(sensor, true); 21283cca8ef5SHugues Fruchet restore_auto_gain: 21293cca8ef5SHugues Fruchet if (auto_gain) 21303cca8ef5SHugues Fruchet ov5640_set_autogain(sensor, true); 21313cca8ef5SHugues Fruchet 21323cca8ef5SHugues Fruchet return ret; 213319a81c14SSteve Longerbeam } 213419a81c14SSteve Longerbeam 213519ad26f9SAkinobu Mita static int ov5640_set_framefmt(struct ov5640_dev *sensor, 213619ad26f9SAkinobu Mita struct v4l2_mbus_framefmt *format); 213719ad26f9SAkinobu Mita 213819a81c14SSteve Longerbeam /* restore the last set video mode after chip power-on */ 213919a81c14SSteve Longerbeam static int ov5640_restore_mode(struct ov5640_dev *sensor) 214019a81c14SSteve Longerbeam { 214119a81c14SSteve Longerbeam int ret; 214219a81c14SSteve Longerbeam 214319a81c14SSteve Longerbeam /* first load the initial register values */ 214419a81c14SSteve Longerbeam ret = ov5640_load_regs(sensor, &ov5640_mode_init_data); 214519a81c14SSteve Longerbeam if (ret < 0) 214619a81c14SSteve Longerbeam return ret; 2147985cdcb0SHugues Fruchet sensor->last_mode = &ov5640_mode_init_data; 214819a81c14SSteve Longerbeam 21498f57c2f8SMaxime Ripard ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f, 21507851fe7aSMaxime Ripard (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) | 21517851fe7aSMaxime Ripard ilog2(OV5640_SCLK_ROOT_DIV)); 21528f57c2f8SMaxime Ripard if (ret) 21538f57c2f8SMaxime Ripard return ret; 21548f57c2f8SMaxime Ripard 215519a81c14SSteve Longerbeam /* now restore the last capture mode */ 2156985cdcb0SHugues Fruchet ret = ov5640_set_mode(sensor); 215719ad26f9SAkinobu Mita if (ret < 0) 215819ad26f9SAkinobu Mita return ret; 215919ad26f9SAkinobu Mita 216019ad26f9SAkinobu Mita return ov5640_set_framefmt(sensor, &sensor->fmt); 216119a81c14SSteve Longerbeam } 216219a81c14SSteve Longerbeam 216319a81c14SSteve Longerbeam static void ov5640_power(struct ov5640_dev *sensor, bool enable) 216419a81c14SSteve Longerbeam { 21651fddc5daSHugues Fruchet gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1); 216619a81c14SSteve Longerbeam } 216719a81c14SSteve Longerbeam 216819a81c14SSteve Longerbeam static void ov5640_reset(struct ov5640_dev *sensor) 216919a81c14SSteve Longerbeam { 217019a81c14SSteve Longerbeam if (!sensor->reset_gpio) 217119a81c14SSteve Longerbeam return; 217219a81c14SSteve Longerbeam 21731fddc5daSHugues Fruchet gpiod_set_value_cansleep(sensor->reset_gpio, 0); 217419a81c14SSteve Longerbeam 217519a81c14SSteve Longerbeam /* camera power cycle */ 217619a81c14SSteve Longerbeam ov5640_power(sensor, false); 217719a81c14SSteve Longerbeam usleep_range(5000, 10000); 217819a81c14SSteve Longerbeam ov5640_power(sensor, true); 217919a81c14SSteve Longerbeam usleep_range(5000, 10000); 218019a81c14SSteve Longerbeam 21811fddc5daSHugues Fruchet gpiod_set_value_cansleep(sensor->reset_gpio, 1); 218219a81c14SSteve Longerbeam usleep_range(1000, 2000); 218319a81c14SSteve Longerbeam 21841fddc5daSHugues Fruchet gpiod_set_value_cansleep(sensor->reset_gpio, 0); 21851d4c41f3SLoic Poulain usleep_range(20000, 25000); 218619a81c14SSteve Longerbeam } 218719a81c14SSteve Longerbeam 21880f7acb52SHugues Fruchet static int ov5640_set_power_on(struct ov5640_dev *sensor) 218919a81c14SSteve Longerbeam { 21900f7acb52SHugues Fruchet struct i2c_client *client = sensor->i2c_client; 21910f7acb52SHugues Fruchet int ret; 219219a81c14SSteve Longerbeam 21930f7acb52SHugues Fruchet ret = clk_prepare_enable(sensor->xclk); 21940f7acb52SHugues Fruchet if (ret) { 21950f7acb52SHugues Fruchet dev_err(&client->dev, "%s: failed to enable clock\n", 21960f7acb52SHugues Fruchet __func__); 21970f7acb52SHugues Fruchet return ret; 21980f7acb52SHugues Fruchet } 219919a81c14SSteve Longerbeam 220019a81c14SSteve Longerbeam ret = regulator_bulk_enable(OV5640_NUM_SUPPLIES, 220119a81c14SSteve Longerbeam sensor->supplies); 22020f7acb52SHugues Fruchet if (ret) { 22030f7acb52SHugues Fruchet dev_err(&client->dev, "%s: failed to enable regulators\n", 22040f7acb52SHugues Fruchet __func__); 220519a81c14SSteve Longerbeam goto xclk_off; 22060f7acb52SHugues Fruchet } 220719a81c14SSteve Longerbeam 220819a81c14SSteve Longerbeam ov5640_reset(sensor); 220919a81c14SSteve Longerbeam ov5640_power(sensor, true); 221019a81c14SSteve Longerbeam 221119a81c14SSteve Longerbeam ret = ov5640_init_slave_id(sensor); 221219a81c14SSteve Longerbeam if (ret) 221319a81c14SSteve Longerbeam goto power_off; 221419a81c14SSteve Longerbeam 22150f7acb52SHugues Fruchet return 0; 22160f7acb52SHugues Fruchet 22170f7acb52SHugues Fruchet power_off: 22180f7acb52SHugues Fruchet ov5640_power(sensor, false); 22190f7acb52SHugues Fruchet regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies); 22200f7acb52SHugues Fruchet xclk_off: 22210f7acb52SHugues Fruchet clk_disable_unprepare(sensor->xclk); 22220f7acb52SHugues Fruchet return ret; 22230f7acb52SHugues Fruchet } 22240f7acb52SHugues Fruchet 22250f7acb52SHugues Fruchet static void ov5640_set_power_off(struct ov5640_dev *sensor) 22260f7acb52SHugues Fruchet { 22270f7acb52SHugues Fruchet ov5640_power(sensor, false); 22280f7acb52SHugues Fruchet regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies); 22290f7acb52SHugues Fruchet clk_disable_unprepare(sensor->xclk); 22300f7acb52SHugues Fruchet } 22310f7acb52SHugues Fruchet 2232b1751ae6SLad Prabhakar static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on) 2233b1751ae6SLad Prabhakar { 2234b1751ae6SLad Prabhakar int ret; 2235b1751ae6SLad Prabhakar 2236b1751ae6SLad Prabhakar if (!on) { 2237b1751ae6SLad Prabhakar /* Reset MIPI bus settings to their default values. */ 2238b1751ae6SLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58); 2239b1751ae6SLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x04); 2240b1751ae6SLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x00); 2241b1751ae6SLad Prabhakar return 0; 2242b1751ae6SLad Prabhakar } 2243b1751ae6SLad Prabhakar 2244b1751ae6SLad Prabhakar /* 2245b1751ae6SLad Prabhakar * Power up MIPI HS Tx and LS Rx; 2 data lanes mode 2246b1751ae6SLad Prabhakar * 2247b1751ae6SLad Prabhakar * 0x300e = 0x40 2248b1751ae6SLad Prabhakar * [7:5] = 010 : 2 data lanes mode (see FIXME note in 2249b1751ae6SLad Prabhakar * "ov5640_set_stream_mipi()") 2250b1751ae6SLad Prabhakar * [4] = 0 : Power up MIPI HS Tx 2251b1751ae6SLad Prabhakar * [3] = 0 : Power up MIPI LS Rx 2252b1751ae6SLad Prabhakar * [2] = 0 : MIPI interface disabled 2253b1751ae6SLad Prabhakar */ 2254b1751ae6SLad Prabhakar ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x40); 2255b1751ae6SLad Prabhakar if (ret) 2256b1751ae6SLad Prabhakar return ret; 2257b1751ae6SLad Prabhakar 2258b1751ae6SLad Prabhakar /* 2259b1751ae6SLad Prabhakar * Gate clock and set LP11 in 'no packets mode' (idle) 2260b1751ae6SLad Prabhakar * 2261b1751ae6SLad Prabhakar * 0x4800 = 0x24 2262b1751ae6SLad Prabhakar * [5] = 1 : Gate clock when 'no packets' 2263b1751ae6SLad Prabhakar * [2] = 1 : MIPI bus in LP11 when 'no packets' 2264b1751ae6SLad Prabhakar */ 2265b1751ae6SLad Prabhakar ret = ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x24); 2266b1751ae6SLad Prabhakar if (ret) 2267b1751ae6SLad Prabhakar return ret; 2268b1751ae6SLad Prabhakar 2269b1751ae6SLad Prabhakar /* 2270b1751ae6SLad Prabhakar * Set data lanes and clock in LP11 when 'sleeping' 2271b1751ae6SLad Prabhakar * 2272b1751ae6SLad Prabhakar * 0x3019 = 0x70 2273b1751ae6SLad Prabhakar * [6] = 1 : MIPI data lane 2 in LP11 when 'sleeping' 2274b1751ae6SLad Prabhakar * [5] = 1 : MIPI data lane 1 in LP11 when 'sleeping' 2275b1751ae6SLad Prabhakar * [4] = 1 : MIPI clock lane in LP11 when 'sleeping' 2276b1751ae6SLad Prabhakar */ 2277b1751ae6SLad Prabhakar ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x70); 2278b1751ae6SLad Prabhakar if (ret) 2279b1751ae6SLad Prabhakar return ret; 2280b1751ae6SLad Prabhakar 2281b1751ae6SLad Prabhakar /* Give lanes some time to coax into LP11 state. */ 2282b1751ae6SLad Prabhakar usleep_range(500, 1000); 2283b1751ae6SLad Prabhakar 2284b1751ae6SLad Prabhakar return 0; 2285b1751ae6SLad Prabhakar } 2286b1751ae6SLad Prabhakar 2287576f5d4bSLad Prabhakar static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on) 2288576f5d4bSLad Prabhakar { 2289311a6408SLad Prabhakar unsigned int flags = sensor->ep.bus.parallel.flags; 229068579b32SHugues Fruchet bool bt656 = sensor->ep.bus_type == V4L2_MBUS_BT656; 229168579b32SHugues Fruchet u8 polarities = 0; 2292576f5d4bSLad Prabhakar int ret; 2293576f5d4bSLad Prabhakar 2294576f5d4bSLad Prabhakar if (!on) { 2295576f5d4bSLad Prabhakar /* Reset settings to their default values. */ 229668579b32SHugues Fruchet ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 0x00); 2297311a6408SLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58); 2298311a6408SLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, 0x20); 2299576f5d4bSLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x00); 2300576f5d4bSLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0x00); 2301576f5d4bSLad Prabhakar return 0; 2302576f5d4bSLad Prabhakar } 2303576f5d4bSLad Prabhakar 2304576f5d4bSLad Prabhakar /* 2305311a6408SLad Prabhakar * Note about parallel port configuration. 2306311a6408SLad Prabhakar * 2307311a6408SLad Prabhakar * When configured in parallel mode, the OV5640 will 2308311a6408SLad Prabhakar * output 10 bits data on DVP data lines [9:0]. 2309311a6408SLad Prabhakar * If only 8 bits data are wanted, the 8 bits data lines 2310311a6408SLad Prabhakar * of the camera interface must be physically connected 2311311a6408SLad Prabhakar * on the DVP data lines [9:2]. 2312311a6408SLad Prabhakar * 2313311a6408SLad Prabhakar * Control lines polarity can be configured through 2314311a6408SLad Prabhakar * devicetree endpoint control lines properties. 2315311a6408SLad Prabhakar * If no endpoint control lines properties are set, 2316311a6408SLad Prabhakar * polarity will be as below: 2317311a6408SLad Prabhakar * - VSYNC: active high 2318311a6408SLad Prabhakar * - HREF: active low 2319311a6408SLad Prabhakar * - PCLK: active low 232068579b32SHugues Fruchet * 232168579b32SHugues Fruchet * VSYNC & HREF are not configured if BT656 bus mode is selected 2322311a6408SLad Prabhakar */ 232368579b32SHugues Fruchet 232468579b32SHugues Fruchet /* 232568579b32SHugues Fruchet * BT656 embedded synchronization configuration 232668579b32SHugues Fruchet * 232768579b32SHugues Fruchet * CCIR656 CTRL00 232868579b32SHugues Fruchet * - [7]: SYNC code selection (0: auto generate sync code, 232968579b32SHugues Fruchet * 1: sync code from regs 0x4732-0x4735) 233068579b32SHugues Fruchet * - [6]: f value in CCIR656 SYNC code when fixed f value 233168579b32SHugues Fruchet * - [5]: Fixed f value 233268579b32SHugues Fruchet * - [4:3]: Blank toggle data options (00: data=1'h040/1'h200, 233368579b32SHugues Fruchet * 01: data from regs 0x4736-0x4738, 10: always keep 0) 233468579b32SHugues Fruchet * - [1]: Clip data disable 233568579b32SHugues Fruchet * - [0]: CCIR656 mode enable 233668579b32SHugues Fruchet * 233768579b32SHugues Fruchet * Default CCIR656 SAV/EAV mode with default codes 233868579b32SHugues Fruchet * SAV=0xff000080 & EAV=0xff00009d is enabled here with settings: 233968579b32SHugues Fruchet * - CCIR656 mode enable 234068579b32SHugues Fruchet * - auto generation of sync codes 234168579b32SHugues Fruchet * - blank toggle data 1'h040/1'h200 234268579b32SHugues Fruchet * - clip reserved data (0x00 & 0xff changed to 0x01 & 0xfe) 234368579b32SHugues Fruchet */ 234468579b32SHugues Fruchet ret = ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 234568579b32SHugues Fruchet bt656 ? 0x01 : 0x00); 234668579b32SHugues Fruchet if (ret) 234768579b32SHugues Fruchet return ret; 234868579b32SHugues Fruchet 2349311a6408SLad Prabhakar /* 2350311a6408SLad Prabhakar * configure parallel port control lines polarity 2351311a6408SLad Prabhakar * 2352311a6408SLad Prabhakar * POLARITY CTRL0 2353311a6408SLad Prabhakar * - [5]: PCLK polarity (0: active low, 1: active high) 2354311a6408SLad Prabhakar * - [1]: HREF polarity (0: active low, 1: active high) 2355311a6408SLad Prabhakar * - [0]: VSYNC polarity (mismatch here between 2356311a6408SLad Prabhakar * datasheet and hardware, 0 is active high 2357311a6408SLad Prabhakar * and 1 is active low...) 2358311a6408SLad Prabhakar */ 235968579b32SHugues Fruchet if (!bt656) { 2360311a6408SLad Prabhakar if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) 236168579b32SHugues Fruchet polarities |= BIT(1); 2362311a6408SLad Prabhakar if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) 236368579b32SHugues Fruchet polarities |= BIT(0); 236468579b32SHugues Fruchet } 236568579b32SHugues Fruchet if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) 236668579b32SHugues Fruchet polarities |= BIT(5); 2367311a6408SLad Prabhakar 236868579b32SHugues Fruchet ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, polarities); 2369311a6408SLad Prabhakar if (ret) 2370311a6408SLad Prabhakar return ret; 2371311a6408SLad Prabhakar 2372311a6408SLad Prabhakar /* 237368579b32SHugues Fruchet * powerdown MIPI TX/RX PHY & enable DVP 2374311a6408SLad Prabhakar * 2375311a6408SLad Prabhakar * MIPI CONTROL 00 237668579b32SHugues Fruchet * [4] = 1 : Power down MIPI HS Tx 237768579b32SHugues Fruchet * [3] = 1 : Power down MIPI LS Rx 237868579b32SHugues Fruchet * [2] = 0 : DVP enable (MIPI disable) 2379311a6408SLad Prabhakar */ 2380311a6408SLad Prabhakar ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x18); 2381311a6408SLad Prabhakar if (ret) 2382311a6408SLad Prabhakar return ret; 2383311a6408SLad Prabhakar 2384311a6408SLad Prabhakar /* 2385576f5d4bSLad Prabhakar * enable VSYNC/HREF/PCLK DVP control lines 2386576f5d4bSLad Prabhakar * & D[9:6] DVP data lines 2387576f5d4bSLad Prabhakar * 2388576f5d4bSLad Prabhakar * PAD OUTPUT ENABLE 01 2389576f5d4bSLad Prabhakar * - 6: VSYNC output enable 2390576f5d4bSLad Prabhakar * - 5: HREF output enable 2391576f5d4bSLad Prabhakar * - 4: PCLK output enable 2392576f5d4bSLad Prabhakar * - [3:0]: D[9:6] output enable 2393576f5d4bSLad Prabhakar */ 23944039b037SLad Prabhakar ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 239568579b32SHugues Fruchet bt656 ? 0x1f : 0x7f); 2396576f5d4bSLad Prabhakar if (ret) 2397576f5d4bSLad Prabhakar return ret; 2398576f5d4bSLad Prabhakar 2399576f5d4bSLad Prabhakar /* 2400576f5d4bSLad Prabhakar * enable D[5:0] DVP data lines 2401576f5d4bSLad Prabhakar * 2402576f5d4bSLad Prabhakar * PAD OUTPUT ENABLE 02 2403576f5d4bSLad Prabhakar * - [7:2]: D[5:0] output enable 2404576f5d4bSLad Prabhakar */ 2405576f5d4bSLad Prabhakar return ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0xfc); 2406576f5d4bSLad Prabhakar } 2407576f5d4bSLad Prabhakar 24080f7acb52SHugues Fruchet static int ov5640_set_power(struct ov5640_dev *sensor, bool on) 24090f7acb52SHugues Fruchet { 24100f7acb52SHugues Fruchet int ret = 0; 24110f7acb52SHugues Fruchet 24120f7acb52SHugues Fruchet if (on) { 24130f7acb52SHugues Fruchet ret = ov5640_set_power_on(sensor); 24140f7acb52SHugues Fruchet if (ret) 24150f7acb52SHugues Fruchet return ret; 24160f7acb52SHugues Fruchet 241719a81c14SSteve Longerbeam ret = ov5640_restore_mode(sensor); 241819a81c14SSteve Longerbeam if (ret) 241919a81c14SSteve Longerbeam goto power_off; 2420b1751ae6SLad Prabhakar } 242119a81c14SSteve Longerbeam 2422576f5d4bSLad Prabhakar if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY) 2423b1751ae6SLad Prabhakar ret = ov5640_set_power_mipi(sensor, on); 2424576f5d4bSLad Prabhakar else 2425576f5d4bSLad Prabhakar ret = ov5640_set_power_dvp(sensor, on); 2426b1751ae6SLad Prabhakar if (ret) 2427b1751ae6SLad Prabhakar goto power_off; 2428aa4bb8b8SJacopo Mondi 2429b1751ae6SLad Prabhakar if (!on) 2430aa4bb8b8SJacopo Mondi ov5640_set_power_off(sensor); 243119a81c14SSteve Longerbeam 243219a81c14SSteve Longerbeam return 0; 243319a81c14SSteve Longerbeam 243419a81c14SSteve Longerbeam power_off: 24350f7acb52SHugues Fruchet ov5640_set_power_off(sensor); 243619a81c14SSteve Longerbeam return ret; 243719a81c14SSteve Longerbeam } 243819a81c14SSteve Longerbeam 243919a81c14SSteve Longerbeam /* --------------- Subdev Operations --------------- */ 244019a81c14SSteve Longerbeam 244119a81c14SSteve Longerbeam static int ov5640_s_power(struct v4l2_subdev *sd, int on) 244219a81c14SSteve Longerbeam { 244319a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 244419a81c14SSteve Longerbeam int ret = 0; 244519a81c14SSteve Longerbeam 244619a81c14SSteve Longerbeam mutex_lock(&sensor->lock); 244719a81c14SSteve Longerbeam 244819a81c14SSteve Longerbeam /* 244919a81c14SSteve Longerbeam * If the power count is modified from 0 to != 0 or from != 0 to 0, 245019a81c14SSteve Longerbeam * update the power state. 245119a81c14SSteve Longerbeam */ 245219a81c14SSteve Longerbeam if (sensor->power_count == !on) { 245319a81c14SSteve Longerbeam ret = ov5640_set_power(sensor, !!on); 245419a81c14SSteve Longerbeam if (ret) 245519a81c14SSteve Longerbeam goto out; 245619a81c14SSteve Longerbeam } 245719a81c14SSteve Longerbeam 245819a81c14SSteve Longerbeam /* Update the power count. */ 245919a81c14SSteve Longerbeam sensor->power_count += on ? 1 : -1; 246019a81c14SSteve Longerbeam WARN_ON(sensor->power_count < 0); 246119a81c14SSteve Longerbeam out: 246219a81c14SSteve Longerbeam mutex_unlock(&sensor->lock); 246319a81c14SSteve Longerbeam 246419a81c14SSteve Longerbeam if (on && !ret && sensor->power_count == 1) { 246519a81c14SSteve Longerbeam /* restore controls */ 246619a81c14SSteve Longerbeam ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler); 246719a81c14SSteve Longerbeam } 246819a81c14SSteve Longerbeam 246919a81c14SSteve Longerbeam return ret; 247019a81c14SSteve Longerbeam } 247119a81c14SSteve Longerbeam 247219a81c14SSteve Longerbeam static int ov5640_try_frame_interval(struct ov5640_dev *sensor, 247319a81c14SSteve Longerbeam struct v4l2_fract *fi, 247419a81c14SSteve Longerbeam u32 width, u32 height) 247519a81c14SSteve Longerbeam { 247619a81c14SSteve Longerbeam const struct ov5640_mode_info *mode; 24776530a5ebSJagan Teki enum ov5640_frame_rate rate = OV5640_15_FPS; 2478f6cc192fSMaxime Ripard int minfps, maxfps, best_fps, fps; 2479f6cc192fSMaxime Ripard int i; 248019a81c14SSteve Longerbeam 248119a81c14SSteve Longerbeam minfps = ov5640_framerates[OV5640_15_FPS]; 2482e823fb16SMaxime Ripard maxfps = ov5640_framerates[OV5640_60_FPS]; 248319a81c14SSteve Longerbeam 248419a81c14SSteve Longerbeam if (fi->numerator == 0) { 248519a81c14SSteve Longerbeam fi->denominator = maxfps; 248619a81c14SSteve Longerbeam fi->numerator = 1; 2487e823fb16SMaxime Ripard rate = OV5640_60_FPS; 2488e823fb16SMaxime Ripard goto find_mode; 248919a81c14SSteve Longerbeam } 249019a81c14SSteve Longerbeam 2491f6cc192fSMaxime Ripard fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator), 2492f6cc192fSMaxime Ripard minfps, maxfps); 2493f6cc192fSMaxime Ripard 2494f6cc192fSMaxime Ripard best_fps = minfps; 2495f6cc192fSMaxime Ripard for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) { 2496f6cc192fSMaxime Ripard int curr_fps = ov5640_framerates[i]; 2497f6cc192fSMaxime Ripard 2498f6cc192fSMaxime Ripard if (abs(curr_fps - fps) < abs(best_fps - fps)) { 2499f6cc192fSMaxime Ripard best_fps = curr_fps; 2500f6cc192fSMaxime Ripard rate = i; 2501f6cc192fSMaxime Ripard } 2502f6cc192fSMaxime Ripard } 250319a81c14SSteve Longerbeam 250419a81c14SSteve Longerbeam fi->numerator = 1; 2505f6cc192fSMaxime Ripard fi->denominator = best_fps; 250619a81c14SSteve Longerbeam 2507e823fb16SMaxime Ripard find_mode: 25085a3ad937SMaxime Ripard mode = ov5640_find_mode(sensor, rate, width, height, false); 25095a3ad937SMaxime Ripard return mode ? rate : -EINVAL; 251019a81c14SSteve Longerbeam } 251119a81c14SSteve Longerbeam 251219a81c14SSteve Longerbeam static int ov5640_get_fmt(struct v4l2_subdev *sd, 25130d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 251419a81c14SSteve Longerbeam struct v4l2_subdev_format *format) 251519a81c14SSteve Longerbeam { 251619a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 251719a81c14SSteve Longerbeam struct v4l2_mbus_framefmt *fmt; 251819a81c14SSteve Longerbeam 251919a81c14SSteve Longerbeam if (format->pad != 0) 252019a81c14SSteve Longerbeam return -EINVAL; 252119a81c14SSteve Longerbeam 252219a81c14SSteve Longerbeam mutex_lock(&sensor->lock); 252319a81c14SSteve Longerbeam 252419a81c14SSteve Longerbeam if (format->which == V4L2_SUBDEV_FORMAT_TRY) 25250d346d2aSTomi Valkeinen fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state, 252619a81c14SSteve Longerbeam format->pad); 252719a81c14SSteve Longerbeam else 252819a81c14SSteve Longerbeam fmt = &sensor->fmt; 252919a81c14SSteve Longerbeam 253019a81c14SSteve Longerbeam format->format = *fmt; 253119a81c14SSteve Longerbeam 253219a81c14SSteve Longerbeam mutex_unlock(&sensor->lock); 253319a81c14SSteve Longerbeam 253419a81c14SSteve Longerbeam return 0; 253519a81c14SSteve Longerbeam } 253619a81c14SSteve Longerbeam 253719a81c14SSteve Longerbeam static int ov5640_try_fmt_internal(struct v4l2_subdev *sd, 253819a81c14SSteve Longerbeam struct v4l2_mbus_framefmt *fmt, 253919a81c14SSteve Longerbeam enum ov5640_frame_rate fr, 254019a81c14SSteve Longerbeam const struct ov5640_mode_info **new_mode) 254119a81c14SSteve Longerbeam { 254219a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 254319a81c14SSteve Longerbeam const struct ov5640_mode_info *mode; 2544e3ee691dSHugues Fruchet int i; 254519a81c14SSteve Longerbeam 254619a81c14SSteve Longerbeam mode = ov5640_find_mode(sensor, fr, fmt->width, fmt->height, true); 254719a81c14SSteve Longerbeam if (!mode) 254819a81c14SSteve Longerbeam return -EINVAL; 25493145efcdSJacopo Mondi fmt->width = mode->crop.width; 25503145efcdSJacopo Mondi fmt->height = mode->crop.height; 255119a81c14SSteve Longerbeam 255219a81c14SSteve Longerbeam if (new_mode) 255319a81c14SSteve Longerbeam *new_mode = mode; 2554e3ee691dSHugues Fruchet 2555e3ee691dSHugues Fruchet for (i = 0; i < ARRAY_SIZE(ov5640_formats); i++) 2556e3ee691dSHugues Fruchet if (ov5640_formats[i].code == fmt->code) 2557e3ee691dSHugues Fruchet break; 2558e3ee691dSHugues Fruchet if (i >= ARRAY_SIZE(ov5640_formats)) 2559e6441fdeSHugues Fruchet i = 0; 2560e6441fdeSHugues Fruchet 2561e6441fdeSHugues Fruchet fmt->code = ov5640_formats[i].code; 2562e6441fdeSHugues Fruchet fmt->colorspace = ov5640_formats[i].colorspace; 2563e6441fdeSHugues Fruchet fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); 2564e6441fdeSHugues Fruchet fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; 2565e6441fdeSHugues Fruchet fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace); 2566e3ee691dSHugues Fruchet 256719a81c14SSteve Longerbeam return 0; 256819a81c14SSteve Longerbeam } 256919a81c14SSteve Longerbeam 25703c28588fSJacopo Mondi static int ov5640_update_pixel_rate(struct ov5640_dev *sensor) 25713c28588fSJacopo Mondi { 25723c28588fSJacopo Mondi const struct ov5640_mode_info *mode = sensor->current_mode; 25733c28588fSJacopo Mondi enum ov5640_pixel_rate_id pixel_rate_id = mode->pixel_rate; 25743c28588fSJacopo Mondi struct v4l2_mbus_framefmt *fmt = &sensor->fmt; 25753c28588fSJacopo Mondi unsigned int i = 0; 25763c28588fSJacopo Mondi u32 pixel_rate; 25773c28588fSJacopo Mondi s64 link_freq; 25783c28588fSJacopo Mondi u32 num_lanes; 25793c28588fSJacopo Mondi u32 bpp; 25803c28588fSJacopo Mondi 25813c28588fSJacopo Mondi /* 25823c28588fSJacopo Mondi * Update the pixel rate control value. 25833c28588fSJacopo Mondi * 25843c28588fSJacopo Mondi * For DVP mode, maintain the pixel rate calculation using fixed FPS. 25853c28588fSJacopo Mondi */ 25863c28588fSJacopo Mondi if (!ov5640_is_csi2(sensor)) { 25873c28588fSJacopo Mondi __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, 25883c28588fSJacopo Mondi ov5640_calc_pixel_rate(sensor)); 25893c28588fSJacopo Mondi 25903c28588fSJacopo Mondi return 0; 25913c28588fSJacopo Mondi } 25923c28588fSJacopo Mondi 25933c28588fSJacopo Mondi /* 25943c28588fSJacopo Mondi * The MIPI CSI-2 link frequency should comply with the CSI-2 25953c28588fSJacopo Mondi * specification and be lower than 1GHz. 25963c28588fSJacopo Mondi * 25973c28588fSJacopo Mondi * Start from the suggested pixel_rate for the current mode and 25983c28588fSJacopo Mondi * progressively slow it down if it exceeds 1GHz. 25993c28588fSJacopo Mondi */ 26003c28588fSJacopo Mondi num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes; 26013c28588fSJacopo Mondi bpp = ov5640_code_to_bpp(fmt->code); 26023c28588fSJacopo Mondi do { 26033c28588fSJacopo Mondi pixel_rate = ov5640_pixel_rates[pixel_rate_id]; 26043c28588fSJacopo Mondi link_freq = pixel_rate * bpp / (2 * num_lanes); 26053c28588fSJacopo Mondi } while (link_freq >= 1000000000U && 26063c28588fSJacopo Mondi ++pixel_rate_id < OV5640_NUM_PIXEL_RATES); 26073c28588fSJacopo Mondi 26083c28588fSJacopo Mondi sensor->current_link_freq = link_freq; 26093c28588fSJacopo Mondi 26103c28588fSJacopo Mondi /* 26113c28588fSJacopo Mondi * Higher link rates require the clock tree to be programmed with 26123c28588fSJacopo Mondi * 'mipi_div' = 1; this has the effect of halving the actual output 26133c28588fSJacopo Mondi * pixel rate in the MIPI domain. 26143c28588fSJacopo Mondi * 26153c28588fSJacopo Mondi * Adjust the pixel rate and link frequency control value to report it 26163c28588fSJacopo Mondi * correctly to userspace. 26173c28588fSJacopo Mondi */ 26183c28588fSJacopo Mondi if (link_freq > OV5640_LINK_RATE_MAX) { 26193c28588fSJacopo Mondi pixel_rate /= 2; 26203c28588fSJacopo Mondi link_freq /= 2; 26213c28588fSJacopo Mondi } 26223c28588fSJacopo Mondi 26233c28588fSJacopo Mondi for (i = 0; i < ARRAY_SIZE(ov5640_csi2_link_freqs); ++i) { 26243c28588fSJacopo Mondi if (ov5640_csi2_link_freqs[i] == link_freq) 26253c28588fSJacopo Mondi break; 26263c28588fSJacopo Mondi } 26273c28588fSJacopo Mondi WARN_ON(i == ARRAY_SIZE(ov5640_csi2_link_freqs)); 26283c28588fSJacopo Mondi 26293c28588fSJacopo Mondi __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, pixel_rate); 26303c28588fSJacopo Mondi __v4l2_ctrl_s_ctrl(sensor->ctrls.link_freq, i); 26313c28588fSJacopo Mondi 26323c28588fSJacopo Mondi return 0; 26333c28588fSJacopo Mondi } 26343c28588fSJacopo Mondi 263519a81c14SSteve Longerbeam static int ov5640_set_fmt(struct v4l2_subdev *sd, 26360d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 263719a81c14SSteve Longerbeam struct v4l2_subdev_format *format) 263819a81c14SSteve Longerbeam { 263919a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 264019a81c14SSteve Longerbeam const struct ov5640_mode_info *new_mode; 2641e6441fdeSHugues Fruchet struct v4l2_mbus_framefmt *mbus_fmt = &format->format; 264219a81c14SSteve Longerbeam int ret; 264319a81c14SSteve Longerbeam 264419a81c14SSteve Longerbeam if (format->pad != 0) 264519a81c14SSteve Longerbeam return -EINVAL; 264619a81c14SSteve Longerbeam 264719a81c14SSteve Longerbeam mutex_lock(&sensor->lock); 264819a81c14SSteve Longerbeam 264919a81c14SSteve Longerbeam if (sensor->streaming) { 265019a81c14SSteve Longerbeam ret = -EBUSY; 265119a81c14SSteve Longerbeam goto out; 265219a81c14SSteve Longerbeam } 265319a81c14SSteve Longerbeam 2654e6441fdeSHugues Fruchet ret = ov5640_try_fmt_internal(sd, mbus_fmt, 265519a81c14SSteve Longerbeam sensor->current_fr, &new_mode); 265619a81c14SSteve Longerbeam if (ret) 265719a81c14SSteve Longerbeam goto out; 265819a81c14SSteve Longerbeam 2659e738f5ddSMirela Rabulea if (format->which == V4L2_SUBDEV_FORMAT_TRY) { 2660e738f5ddSMirela Rabulea *v4l2_subdev_get_try_format(sd, sd_state, 0) = *mbus_fmt; 2661e738f5ddSMirela Rabulea goto out; 2662e738f5ddSMirela Rabulea } 266319a81c14SSteve Longerbeam 26646949d864SHugues Fruchet if (new_mode != sensor->current_mode) { 266519a81c14SSteve Longerbeam sensor->current_mode = new_mode; 266619a81c14SSteve Longerbeam sensor->pending_mode_change = true; 26676949d864SHugues Fruchet } 266807115449SJacopo Mondi if (mbus_fmt->code != sensor->fmt.code) 2669fb98e29fSHugues Fruchet sensor->pending_fmt_change = true; 267007115449SJacopo Mondi 2671e738f5ddSMirela Rabulea /* update format even if code is unchanged, resolution might change */ 2672e738f5ddSMirela Rabulea sensor->fmt = *mbus_fmt; 2673e738f5ddSMirela Rabulea 26743c28588fSJacopo Mondi ov5640_update_pixel_rate(sensor); 26753c28588fSJacopo Mondi 267619a81c14SSteve Longerbeam out: 267719a81c14SSteve Longerbeam mutex_unlock(&sensor->lock); 267819a81c14SSteve Longerbeam return ret; 267919a81c14SSteve Longerbeam } 268019a81c14SSteve Longerbeam 2681e3ee691dSHugues Fruchet static int ov5640_set_framefmt(struct ov5640_dev *sensor, 2682e3ee691dSHugues Fruchet struct v4l2_mbus_framefmt *format) 2683e3ee691dSHugues Fruchet { 2684e3ee691dSHugues Fruchet int ret = 0; 2685d47c4126SHugues Fruchet bool is_jpeg = false; 2686b7ed3abdSLoic Poulain u8 fmt, mux; 2687e3ee691dSHugues Fruchet 2688e3ee691dSHugues Fruchet switch (format->code) { 26891536fbdbSXavier Roumegue case MEDIA_BUS_FMT_UYVY8_1X16: 2690e3ee691dSHugues Fruchet case MEDIA_BUS_FMT_UYVY8_2X8: 2691e3ee691dSHugues Fruchet /* YUV422, UYVY */ 2692b7ed3abdSLoic Poulain fmt = 0x3f; 2693b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_YUV422; 2694e3ee691dSHugues Fruchet break; 26951536fbdbSXavier Roumegue case MEDIA_BUS_FMT_YUYV8_1X16: 2696e3ee691dSHugues Fruchet case MEDIA_BUS_FMT_YUYV8_2X8: 2697e3ee691dSHugues Fruchet /* YUV422, YUYV */ 2698b7ed3abdSLoic Poulain fmt = 0x30; 2699b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_YUV422; 2700e3ee691dSHugues Fruchet break; 2701e3ee691dSHugues Fruchet case MEDIA_BUS_FMT_RGB565_2X8_LE: 2702e3ee691dSHugues Fruchet /* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */ 2703b7ed3abdSLoic Poulain fmt = 0x6F; 2704b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_RGB; 2705e3ee691dSHugues Fruchet break; 2706e3ee691dSHugues Fruchet case MEDIA_BUS_FMT_RGB565_2X8_BE: 2707e3ee691dSHugues Fruchet /* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */ 2708b7ed3abdSLoic Poulain fmt = 0x61; 2709b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_RGB; 2710e3ee691dSHugues Fruchet break; 2711d47c4126SHugues Fruchet case MEDIA_BUS_FMT_JPEG_1X8: 2712d47c4126SHugues Fruchet /* YUV422, YUYV */ 2713b7ed3abdSLoic Poulain fmt = 0x30; 2714b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_YUV422; 2715d47c4126SHugues Fruchet is_jpeg = true; 2716d47c4126SHugues Fruchet break; 2717b7ed3abdSLoic Poulain case MEDIA_BUS_FMT_SBGGR8_1X8: 2718b7ed3abdSLoic Poulain /* Raw, BGBG... / GRGR... */ 2719b7ed3abdSLoic Poulain fmt = 0x00; 2720b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_RAW_DPC; 2721b7ed3abdSLoic Poulain break; 2722b7ed3abdSLoic Poulain case MEDIA_BUS_FMT_SGBRG8_1X8: 2723b7ed3abdSLoic Poulain /* Raw bayer, GBGB... / RGRG... */ 2724b7ed3abdSLoic Poulain fmt = 0x01; 2725b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_RAW_DPC; 2726b7ed3abdSLoic Poulain break; 2727b7ed3abdSLoic Poulain case MEDIA_BUS_FMT_SGRBG8_1X8: 2728b7ed3abdSLoic Poulain /* Raw bayer, GRGR... / BGBG... */ 2729b7ed3abdSLoic Poulain fmt = 0x02; 2730b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_RAW_DPC; 2731b7ed3abdSLoic Poulain break; 2732b7ed3abdSLoic Poulain case MEDIA_BUS_FMT_SRGGB8_1X8: 2733b7ed3abdSLoic Poulain /* Raw bayer, RGRG... / GBGB... */ 2734b7ed3abdSLoic Poulain fmt = 0x03; 2735b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_RAW_DPC; 2736b7ed3abdSLoic Poulain break; 2737e3ee691dSHugues Fruchet default: 2738e3ee691dSHugues Fruchet return -EINVAL; 2739e3ee691dSHugues Fruchet } 2740e3ee691dSHugues Fruchet 2741e3ee691dSHugues Fruchet /* FORMAT CONTROL00: YUV and RGB formatting */ 2742b7ed3abdSLoic Poulain ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, fmt); 2743e3ee691dSHugues Fruchet if (ret) 2744e3ee691dSHugues Fruchet return ret; 2745e3ee691dSHugues Fruchet 2746e3ee691dSHugues Fruchet /* FORMAT MUX CONTROL: ISP YUV or RGB */ 2747b7ed3abdSLoic Poulain ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, mux); 2748d47c4126SHugues Fruchet if (ret) 2749d47c4126SHugues Fruchet return ret; 2750d47c4126SHugues Fruchet 2751d47c4126SHugues Fruchet /* 2752d47c4126SHugues Fruchet * TIMING TC REG21: 2753d47c4126SHugues Fruchet * - [5]: JPEG enable 2754d47c4126SHugues Fruchet */ 2755d47c4126SHugues Fruchet ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21, 2756d47c4126SHugues Fruchet BIT(5), is_jpeg ? BIT(5) : 0); 2757d47c4126SHugues Fruchet if (ret) 2758d47c4126SHugues Fruchet return ret; 2759d47c4126SHugues Fruchet 2760d47c4126SHugues Fruchet /* 2761d47c4126SHugues Fruchet * SYSTEM RESET02: 2762d47c4126SHugues Fruchet * - [4]: Reset JFIFO 2763d47c4126SHugues Fruchet * - [3]: Reset SFIFO 2764d47c4126SHugues Fruchet * - [2]: Reset JPEG 2765d47c4126SHugues Fruchet */ 2766d47c4126SHugues Fruchet ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_RESET02, 2767d47c4126SHugues Fruchet BIT(4) | BIT(3) | BIT(2), 2768d47c4126SHugues Fruchet is_jpeg ? 0 : (BIT(4) | BIT(3) | BIT(2))); 2769d47c4126SHugues Fruchet if (ret) 2770d47c4126SHugues Fruchet return ret; 2771d47c4126SHugues Fruchet 2772d47c4126SHugues Fruchet /* 2773d47c4126SHugues Fruchet * CLOCK ENABLE02: 2774d47c4126SHugues Fruchet * - [5]: Enable JPEG 2x clock 2775d47c4126SHugues Fruchet * - [3]: Enable JPEG clock 2776d47c4126SHugues Fruchet */ 2777d47c4126SHugues Fruchet return ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE02, 2778d47c4126SHugues Fruchet BIT(5) | BIT(3), 2779d47c4126SHugues Fruchet is_jpeg ? (BIT(5) | BIT(3)) : 0); 2780e3ee691dSHugues Fruchet } 278119a81c14SSteve Longerbeam 278219a81c14SSteve Longerbeam /* 278319a81c14SSteve Longerbeam * Sensor Controls. 278419a81c14SSteve Longerbeam */ 278519a81c14SSteve Longerbeam 278619a81c14SSteve Longerbeam static int ov5640_set_ctrl_hue(struct ov5640_dev *sensor, int value) 278719a81c14SSteve Longerbeam { 278819a81c14SSteve Longerbeam int ret; 278919a81c14SSteve Longerbeam 279019a81c14SSteve Longerbeam if (value) { 279119a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, 279219a81c14SSteve Longerbeam BIT(0), BIT(0)); 279319a81c14SSteve Longerbeam if (ret) 279419a81c14SSteve Longerbeam return ret; 279519a81c14SSteve Longerbeam ret = ov5640_write_reg16(sensor, OV5640_REG_SDE_CTRL1, value); 279619a81c14SSteve Longerbeam } else { 279719a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(0), 0); 279819a81c14SSteve Longerbeam } 279919a81c14SSteve Longerbeam 280019a81c14SSteve Longerbeam return ret; 280119a81c14SSteve Longerbeam } 280219a81c14SSteve Longerbeam 280319a81c14SSteve Longerbeam static int ov5640_set_ctrl_contrast(struct ov5640_dev *sensor, int value) 280419a81c14SSteve Longerbeam { 280519a81c14SSteve Longerbeam int ret; 280619a81c14SSteve Longerbeam 280719a81c14SSteve Longerbeam if (value) { 280819a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, 280919a81c14SSteve Longerbeam BIT(2), BIT(2)); 281019a81c14SSteve Longerbeam if (ret) 281119a81c14SSteve Longerbeam return ret; 281219a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL5, 281319a81c14SSteve Longerbeam value & 0xff); 281419a81c14SSteve Longerbeam } else { 281519a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(2), 0); 281619a81c14SSteve Longerbeam } 281719a81c14SSteve Longerbeam 281819a81c14SSteve Longerbeam return ret; 281919a81c14SSteve Longerbeam } 282019a81c14SSteve Longerbeam 282119a81c14SSteve Longerbeam static int ov5640_set_ctrl_saturation(struct ov5640_dev *sensor, int value) 282219a81c14SSteve Longerbeam { 282319a81c14SSteve Longerbeam int ret; 282419a81c14SSteve Longerbeam 282519a81c14SSteve Longerbeam if (value) { 282619a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, 282719a81c14SSteve Longerbeam BIT(1), BIT(1)); 282819a81c14SSteve Longerbeam if (ret) 282919a81c14SSteve Longerbeam return ret; 283019a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL3, 283119a81c14SSteve Longerbeam value & 0xff); 283219a81c14SSteve Longerbeam if (ret) 283319a81c14SSteve Longerbeam return ret; 283419a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL4, 283519a81c14SSteve Longerbeam value & 0xff); 283619a81c14SSteve Longerbeam } else { 283719a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(1), 0); 283819a81c14SSteve Longerbeam } 283919a81c14SSteve Longerbeam 284019a81c14SSteve Longerbeam return ret; 284119a81c14SSteve Longerbeam } 284219a81c14SSteve Longerbeam 284319a81c14SSteve Longerbeam static int ov5640_set_ctrl_white_balance(struct ov5640_dev *sensor, int awb) 284419a81c14SSteve Longerbeam { 284519a81c14SSteve Longerbeam int ret; 284619a81c14SSteve Longerbeam 284719a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_AWB_MANUAL_CTRL, 284819a81c14SSteve Longerbeam BIT(0), awb ? 0 : 1); 284919a81c14SSteve Longerbeam if (ret) 285019a81c14SSteve Longerbeam return ret; 285119a81c14SSteve Longerbeam 285219a81c14SSteve Longerbeam if (!awb) { 285319a81c14SSteve Longerbeam u16 red = (u16)sensor->ctrls.red_balance->val; 285419a81c14SSteve Longerbeam u16 blue = (u16)sensor->ctrls.blue_balance->val; 285519a81c14SSteve Longerbeam 285619a81c14SSteve Longerbeam ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_R_GAIN, red); 285719a81c14SSteve Longerbeam if (ret) 285819a81c14SSteve Longerbeam return ret; 285919a81c14SSteve Longerbeam ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_B_GAIN, blue); 286019a81c14SSteve Longerbeam } 286119a81c14SSteve Longerbeam 286219a81c14SSteve Longerbeam return ret; 286319a81c14SSteve Longerbeam } 286419a81c14SSteve Longerbeam 28653cca8ef5SHugues Fruchet static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor, 28663cca8ef5SHugues Fruchet enum v4l2_exposure_auto_type auto_exposure) 286719a81c14SSteve Longerbeam { 286819a81c14SSteve Longerbeam struct ov5640_ctrls *ctrls = &sensor->ctrls; 28693cca8ef5SHugues Fruchet bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO); 287019a81c14SSteve Longerbeam int ret = 0; 287119a81c14SSteve Longerbeam 287219a81c14SSteve Longerbeam if (ctrls->auto_exp->is_new) { 28733cca8ef5SHugues Fruchet ret = ov5640_set_autoexposure(sensor, auto_exp); 287419a81c14SSteve Longerbeam if (ret) 287519a81c14SSteve Longerbeam return ret; 287619a81c14SSteve Longerbeam } 287719a81c14SSteve Longerbeam 28783cca8ef5SHugues Fruchet if (!auto_exp && ctrls->exposure->is_new) { 287919a81c14SSteve Longerbeam u16 max_exp; 288019a81c14SSteve Longerbeam 288119a81c14SSteve Longerbeam ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_VTS, 288219a81c14SSteve Longerbeam &max_exp); 288319a81c14SSteve Longerbeam if (ret) 288419a81c14SSteve Longerbeam return ret; 288519a81c14SSteve Longerbeam ret = ov5640_get_vts(sensor); 288619a81c14SSteve Longerbeam if (ret < 0) 288719a81c14SSteve Longerbeam return ret; 288819a81c14SSteve Longerbeam max_exp += ret; 28896146fde3SHugues Fruchet ret = 0; 289019a81c14SSteve Longerbeam 289119a81c14SSteve Longerbeam if (ctrls->exposure->val < max_exp) 289219a81c14SSteve Longerbeam ret = ov5640_set_exposure(sensor, ctrls->exposure->val); 289319a81c14SSteve Longerbeam } 289419a81c14SSteve Longerbeam 289519a81c14SSteve Longerbeam return ret; 289619a81c14SSteve Longerbeam } 289719a81c14SSteve Longerbeam 28983cca8ef5SHugues Fruchet static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain) 289919a81c14SSteve Longerbeam { 290019a81c14SSteve Longerbeam struct ov5640_ctrls *ctrls = &sensor->ctrls; 290119a81c14SSteve Longerbeam int ret = 0; 290219a81c14SSteve Longerbeam 290319a81c14SSteve Longerbeam if (ctrls->auto_gain->is_new) { 29043cca8ef5SHugues Fruchet ret = ov5640_set_autogain(sensor, auto_gain); 290519a81c14SSteve Longerbeam if (ret) 290619a81c14SSteve Longerbeam return ret; 290719a81c14SSteve Longerbeam } 290819a81c14SSteve Longerbeam 29093cca8ef5SHugues Fruchet if (!auto_gain && ctrls->gain->is_new) 29103cca8ef5SHugues Fruchet ret = ov5640_set_gain(sensor, ctrls->gain->val); 291119a81c14SSteve Longerbeam 291219a81c14SSteve Longerbeam return ret; 291319a81c14SSteve Longerbeam } 291419a81c14SSteve Longerbeam 29159f6d7bacSChen-Yu Tsai static const char * const test_pattern_menu[] = { 29169f6d7bacSChen-Yu Tsai "Disabled", 29179f6d7bacSChen-Yu Tsai "Color bars", 2918bddc5cdfSChen-Yu Tsai "Color bars w/ rolling bar", 2919bddc5cdfSChen-Yu Tsai "Color squares", 2920bddc5cdfSChen-Yu Tsai "Color squares w/ rolling bar", 29219f6d7bacSChen-Yu Tsai }; 29229f6d7bacSChen-Yu Tsai 2923a0c29afbSChen-Yu Tsai #define OV5640_TEST_ENABLE BIT(7) 2924a0c29afbSChen-Yu Tsai #define OV5640_TEST_ROLLING BIT(6) /* rolling horizontal bar */ 2925a0c29afbSChen-Yu Tsai #define OV5640_TEST_TRANSPARENT BIT(5) 2926a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE_BW BIT(4) /* black & white squares */ 2927a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_STANDARD (0 << 2) 2928a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_1 (1 << 2) 2929a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_HOR_CHANGE (2 << 2) 2930a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_2 (3 << 2) 2931a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR (0 << 0) 2932a0c29afbSChen-Yu Tsai #define OV5640_TEST_RANDOM (1 << 0) 2933a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE (2 << 0) 2934a0c29afbSChen-Yu Tsai #define OV5640_TEST_BLACK (3 << 0) 2935a0c29afbSChen-Yu Tsai 2936a0c29afbSChen-Yu Tsai static const u8 test_pattern_val[] = { 2937a0c29afbSChen-Yu Tsai 0, 29382aff1fc3SChen-Yu Tsai OV5640_TEST_ENABLE | OV5640_TEST_BAR_VERT_CHANGE_1 | 2939a0c29afbSChen-Yu Tsai OV5640_TEST_BAR, 2940bddc5cdfSChen-Yu Tsai OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | 2941bddc5cdfSChen-Yu Tsai OV5640_TEST_BAR_VERT_CHANGE_1 | OV5640_TEST_BAR, 2942bddc5cdfSChen-Yu Tsai OV5640_TEST_ENABLE | OV5640_TEST_SQUARE, 2943bddc5cdfSChen-Yu Tsai OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | OV5640_TEST_SQUARE, 2944a0c29afbSChen-Yu Tsai }; 2945a0c29afbSChen-Yu Tsai 294619a81c14SSteve Longerbeam static int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value) 294719a81c14SSteve Longerbeam { 2948a0c29afbSChen-Yu Tsai return ov5640_write_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1, 2949a0c29afbSChen-Yu Tsai test_pattern_val[value]); 295019a81c14SSteve Longerbeam } 295119a81c14SSteve Longerbeam 29521068fecaSMylène Josserand static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value) 29531068fecaSMylène Josserand { 29541068fecaSMylène Josserand int ret; 29551068fecaSMylène Josserand 29561068fecaSMylène Josserand ret = ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL01, BIT(7), 29571068fecaSMylène Josserand (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) ? 29581068fecaSMylène Josserand 0 : BIT(7)); 29591068fecaSMylène Josserand if (ret) 29601068fecaSMylène Josserand return ret; 29611068fecaSMylène Josserand 29621068fecaSMylène Josserand return ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL00, BIT(2), 29631068fecaSMylène Josserand (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) ? 29641068fecaSMylène Josserand BIT(2) : 0); 29651068fecaSMylène Josserand } 29661068fecaSMylène Josserand 2967ce85705aSHugues Fruchet static int ov5640_set_ctrl_hflip(struct ov5640_dev *sensor, int value) 2968ce85705aSHugues Fruchet { 2969ce85705aSHugues Fruchet /* 2970c3f3ba3eSHugues Fruchet * If sensor is mounted upside down, mirror logic is inversed. 2971c3f3ba3eSHugues Fruchet * 2972ce85705aSHugues Fruchet * Sensor is a BSI (Back Side Illuminated) one, 2973ce85705aSHugues Fruchet * so image captured is physically mirrored. 2974ce85705aSHugues Fruchet * This is why mirror logic is inversed in 2975ce85705aSHugues Fruchet * order to cancel this mirror effect. 2976ce85705aSHugues Fruchet */ 2977ce85705aSHugues Fruchet 2978ce85705aSHugues Fruchet /* 2979ce85705aSHugues Fruchet * TIMING TC REG21: 2980ce85705aSHugues Fruchet * - [2]: ISP mirror 2981ce85705aSHugues Fruchet * - [1]: Sensor mirror 2982ce85705aSHugues Fruchet */ 2983ce85705aSHugues Fruchet return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21, 2984ce85705aSHugues Fruchet BIT(2) | BIT(1), 2985c3f3ba3eSHugues Fruchet (!(value ^ sensor->upside_down)) ? 2986c3f3ba3eSHugues Fruchet (BIT(2) | BIT(1)) : 0); 2987ce85705aSHugues Fruchet } 2988ce85705aSHugues Fruchet 2989ce85705aSHugues Fruchet static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value) 2990ce85705aSHugues Fruchet { 2991c3f3ba3eSHugues Fruchet /* If sensor is mounted upside down, flip logic is inversed */ 2992c3f3ba3eSHugues Fruchet 2993ce85705aSHugues Fruchet /* 2994ce85705aSHugues Fruchet * TIMING TC REG20: 2995ce85705aSHugues Fruchet * - [2]: ISP vflip 2996ce85705aSHugues Fruchet * - [1]: Sensor vflip 2997ce85705aSHugues Fruchet */ 2998ce85705aSHugues Fruchet return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20, 2999ce85705aSHugues Fruchet BIT(2) | BIT(1), 3000c3f3ba3eSHugues Fruchet (value ^ sensor->upside_down) ? 3001c3f3ba3eSHugues Fruchet (BIT(2) | BIT(1)) : 0); 3002ce85705aSHugues Fruchet } 3003ce85705aSHugues Fruchet 300419a81c14SSteve Longerbeam static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl) 300519a81c14SSteve Longerbeam { 300619a81c14SSteve Longerbeam struct v4l2_subdev *sd = ctrl_to_sd(ctrl); 300719a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 300819a81c14SSteve Longerbeam int val; 300919a81c14SSteve Longerbeam 301019a81c14SSteve Longerbeam /* v4l2_ctrl_lock() locks our own mutex */ 301119a81c14SSteve Longerbeam 301219a81c14SSteve Longerbeam switch (ctrl->id) { 301319a81c14SSteve Longerbeam case V4L2_CID_AUTOGAIN: 301419a81c14SSteve Longerbeam val = ov5640_get_gain(sensor); 301519a81c14SSteve Longerbeam if (val < 0) 301619a81c14SSteve Longerbeam return val; 301719a81c14SSteve Longerbeam sensor->ctrls.gain->val = val; 301819a81c14SSteve Longerbeam break; 301919a81c14SSteve Longerbeam case V4L2_CID_EXPOSURE_AUTO: 302019a81c14SSteve Longerbeam val = ov5640_get_exposure(sensor); 302119a81c14SSteve Longerbeam if (val < 0) 302219a81c14SSteve Longerbeam return val; 302319a81c14SSteve Longerbeam sensor->ctrls.exposure->val = val; 302419a81c14SSteve Longerbeam break; 302519a81c14SSteve Longerbeam } 302619a81c14SSteve Longerbeam 302719a81c14SSteve Longerbeam return 0; 302819a81c14SSteve Longerbeam } 302919a81c14SSteve Longerbeam 303019a81c14SSteve Longerbeam static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) 303119a81c14SSteve Longerbeam { 303219a81c14SSteve Longerbeam struct v4l2_subdev *sd = ctrl_to_sd(ctrl); 303319a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 303419a81c14SSteve Longerbeam int ret; 303519a81c14SSteve Longerbeam 303619a81c14SSteve Longerbeam /* v4l2_ctrl_lock() locks our own mutex */ 303719a81c14SSteve Longerbeam 303819a81c14SSteve Longerbeam /* 303919a81c14SSteve Longerbeam * If the device is not powered up by the host driver do 304019a81c14SSteve Longerbeam * not apply any controls to H/W at this time. Instead 304119a81c14SSteve Longerbeam * the controls will be restored right after power-up. 304219a81c14SSteve Longerbeam */ 304319a81c14SSteve Longerbeam if (sensor->power_count == 0) 304419a81c14SSteve Longerbeam return 0; 304519a81c14SSteve Longerbeam 304619a81c14SSteve Longerbeam switch (ctrl->id) { 304719a81c14SSteve Longerbeam case V4L2_CID_AUTOGAIN: 304819a81c14SSteve Longerbeam ret = ov5640_set_ctrl_gain(sensor, ctrl->val); 304919a81c14SSteve Longerbeam break; 305019a81c14SSteve Longerbeam case V4L2_CID_EXPOSURE_AUTO: 305119a81c14SSteve Longerbeam ret = ov5640_set_ctrl_exposure(sensor, ctrl->val); 305219a81c14SSteve Longerbeam break; 305319a81c14SSteve Longerbeam case V4L2_CID_AUTO_WHITE_BALANCE: 305419a81c14SSteve Longerbeam ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val); 305519a81c14SSteve Longerbeam break; 305619a81c14SSteve Longerbeam case V4L2_CID_HUE: 305719a81c14SSteve Longerbeam ret = ov5640_set_ctrl_hue(sensor, ctrl->val); 305819a81c14SSteve Longerbeam break; 305919a81c14SSteve Longerbeam case V4L2_CID_CONTRAST: 306019a81c14SSteve Longerbeam ret = ov5640_set_ctrl_contrast(sensor, ctrl->val); 306119a81c14SSteve Longerbeam break; 306219a81c14SSteve Longerbeam case V4L2_CID_SATURATION: 306319a81c14SSteve Longerbeam ret = ov5640_set_ctrl_saturation(sensor, ctrl->val); 306419a81c14SSteve Longerbeam break; 306519a81c14SSteve Longerbeam case V4L2_CID_TEST_PATTERN: 306619a81c14SSteve Longerbeam ret = ov5640_set_ctrl_test_pattern(sensor, ctrl->val); 306719a81c14SSteve Longerbeam break; 30681068fecaSMylène Josserand case V4L2_CID_POWER_LINE_FREQUENCY: 30691068fecaSMylène Josserand ret = ov5640_set_ctrl_light_freq(sensor, ctrl->val); 30701068fecaSMylène Josserand break; 3071ce85705aSHugues Fruchet case V4L2_CID_HFLIP: 3072ce85705aSHugues Fruchet ret = ov5640_set_ctrl_hflip(sensor, ctrl->val); 3073ce85705aSHugues Fruchet break; 3074ce85705aSHugues Fruchet case V4L2_CID_VFLIP: 3075ce85705aSHugues Fruchet ret = ov5640_set_ctrl_vflip(sensor, ctrl->val); 3076ce85705aSHugues Fruchet break; 307719a81c14SSteve Longerbeam default: 307819a81c14SSteve Longerbeam ret = -EINVAL; 307919a81c14SSteve Longerbeam break; 308019a81c14SSteve Longerbeam } 308119a81c14SSteve Longerbeam 308219a81c14SSteve Longerbeam return ret; 308319a81c14SSteve Longerbeam } 308419a81c14SSteve Longerbeam 308519a81c14SSteve Longerbeam static const struct v4l2_ctrl_ops ov5640_ctrl_ops = { 308619a81c14SSteve Longerbeam .g_volatile_ctrl = ov5640_g_volatile_ctrl, 308719a81c14SSteve Longerbeam .s_ctrl = ov5640_s_ctrl, 308819a81c14SSteve Longerbeam }; 308919a81c14SSteve Longerbeam 309019a81c14SSteve Longerbeam static int ov5640_init_controls(struct ov5640_dev *sensor) 309119a81c14SSteve Longerbeam { 309222845bf2SJacopo Mondi const struct ov5640_mode_info *mode = sensor->current_mode; 309319a81c14SSteve Longerbeam const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops; 309419a81c14SSteve Longerbeam struct ov5640_ctrls *ctrls = &sensor->ctrls; 309519a81c14SSteve Longerbeam struct v4l2_ctrl_handler *hdl = &ctrls->handler; 309619a81c14SSteve Longerbeam int ret; 309719a81c14SSteve Longerbeam 309819a81c14SSteve Longerbeam v4l2_ctrl_handler_init(hdl, 32); 309919a81c14SSteve Longerbeam 310019a81c14SSteve Longerbeam /* we can use our own mutex for the ctrl lock */ 310119a81c14SSteve Longerbeam hdl->lock = &sensor->lock; 310219a81c14SSteve Longerbeam 3103cc196e48SBenoit Parrot /* Clock related controls */ 3104cc196e48SBenoit Parrot ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE, 310522845bf2SJacopo Mondi ov5640_pixel_rates[OV5640_NUM_PIXEL_RATES - 1], 310622845bf2SJacopo Mondi ov5640_pixel_rates[0], 1, 310722845bf2SJacopo Mondi ov5640_pixel_rates[mode->pixel_rate]); 3108cc196e48SBenoit Parrot 31097a3b8d4bSJacopo Mondi ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops, 31107a3b8d4bSJacopo Mondi V4L2_CID_LINK_FREQ, 31117a3b8d4bSJacopo Mondi ARRAY_SIZE(ov5640_csi2_link_freqs) - 1, 31127a3b8d4bSJacopo Mondi OV5640_DEFAULT_LINK_FREQ, 31137a3b8d4bSJacopo Mondi ov5640_csi2_link_freqs); 31147a3b8d4bSJacopo Mondi 311519a81c14SSteve Longerbeam /* Auto/manual white balance */ 311619a81c14SSteve Longerbeam ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops, 311719a81c14SSteve Longerbeam V4L2_CID_AUTO_WHITE_BALANCE, 311819a81c14SSteve Longerbeam 0, 1, 1, 1); 311919a81c14SSteve Longerbeam ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE, 312019a81c14SSteve Longerbeam 0, 4095, 1, 0); 312119a81c14SSteve Longerbeam ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE, 312219a81c14SSteve Longerbeam 0, 4095, 1, 0); 312319a81c14SSteve Longerbeam /* Auto/manual exposure */ 312419a81c14SSteve Longerbeam ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops, 312519a81c14SSteve Longerbeam V4L2_CID_EXPOSURE_AUTO, 312619a81c14SSteve Longerbeam V4L2_EXPOSURE_MANUAL, 0, 312719a81c14SSteve Longerbeam V4L2_EXPOSURE_AUTO); 312819a81c14SSteve Longerbeam ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, 312919a81c14SSteve Longerbeam 0, 65535, 1, 0); 313019a81c14SSteve Longerbeam /* Auto/manual gain */ 313119a81c14SSteve Longerbeam ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN, 313219a81c14SSteve Longerbeam 0, 1, 1, 1); 313319a81c14SSteve Longerbeam ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, 313419a81c14SSteve Longerbeam 0, 1023, 1, 0); 313519a81c14SSteve Longerbeam 313619a81c14SSteve Longerbeam ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, 313719a81c14SSteve Longerbeam 0, 255, 1, 64); 313819a81c14SSteve Longerbeam ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE, 313919a81c14SSteve Longerbeam 0, 359, 1, 0); 314019a81c14SSteve Longerbeam ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, 314119a81c14SSteve Longerbeam 0, 255, 1, 0); 314219a81c14SSteve Longerbeam ctrls->test_pattern = 314319a81c14SSteve Longerbeam v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN, 314419a81c14SSteve Longerbeam ARRAY_SIZE(test_pattern_menu) - 1, 314519a81c14SSteve Longerbeam 0, 0, test_pattern_menu); 3146ce85705aSHugues Fruchet ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 3147ce85705aSHugues Fruchet 0, 1, 1, 0); 3148ce85705aSHugues Fruchet ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 3149ce85705aSHugues Fruchet 0, 1, 1, 0); 315019a81c14SSteve Longerbeam 31511068fecaSMylène Josserand ctrls->light_freq = 31521068fecaSMylène Josserand v4l2_ctrl_new_std_menu(hdl, ops, 31531068fecaSMylène Josserand V4L2_CID_POWER_LINE_FREQUENCY, 31541068fecaSMylène Josserand V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, 31551068fecaSMylène Josserand V4L2_CID_POWER_LINE_FREQUENCY_50HZ); 31561068fecaSMylène Josserand 315719a81c14SSteve Longerbeam if (hdl->error) { 315819a81c14SSteve Longerbeam ret = hdl->error; 315919a81c14SSteve Longerbeam goto free_ctrls; 316019a81c14SSteve Longerbeam } 316119a81c14SSteve Longerbeam 3162cc196e48SBenoit Parrot ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY; 31637a3b8d4bSJacopo Mondi ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; 316419a81c14SSteve Longerbeam ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE; 316519a81c14SSteve Longerbeam ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE; 316619a81c14SSteve Longerbeam 316719a81c14SSteve Longerbeam v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false); 316819a81c14SSteve Longerbeam v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true); 316919a81c14SSteve Longerbeam v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true); 317019a81c14SSteve Longerbeam 317119a81c14SSteve Longerbeam sensor->sd.ctrl_handler = hdl; 317219a81c14SSteve Longerbeam return 0; 317319a81c14SSteve Longerbeam 317419a81c14SSteve Longerbeam free_ctrls: 317519a81c14SSteve Longerbeam v4l2_ctrl_handler_free(hdl); 317619a81c14SSteve Longerbeam return ret; 317719a81c14SSteve Longerbeam } 317819a81c14SSteve Longerbeam 317919a81c14SSteve Longerbeam static int ov5640_enum_frame_size(struct v4l2_subdev *sd, 31800d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 318119a81c14SSteve Longerbeam struct v4l2_subdev_frame_size_enum *fse) 318219a81c14SSteve Longerbeam { 318319a81c14SSteve Longerbeam if (fse->pad != 0) 318419a81c14SSteve Longerbeam return -EINVAL; 318519a81c14SSteve Longerbeam if (fse->index >= OV5640_NUM_MODES) 318619a81c14SSteve Longerbeam return -EINVAL; 318719a81c14SSteve Longerbeam 31883145efcdSJacopo Mondi fse->min_width = ov5640_mode_data[fse->index].crop.width; 318941d8d7f5SHugues Fruchet fse->max_width = fse->min_width; 31903145efcdSJacopo Mondi fse->min_height = ov5640_mode_data[fse->index].crop.height; 319141d8d7f5SHugues Fruchet fse->max_height = fse->min_height; 319219a81c14SSteve Longerbeam 319319a81c14SSteve Longerbeam return 0; 319419a81c14SSteve Longerbeam } 319519a81c14SSteve Longerbeam 319619a81c14SSteve Longerbeam static int ov5640_enum_frame_interval( 319719a81c14SSteve Longerbeam struct v4l2_subdev *sd, 31980d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 319919a81c14SSteve Longerbeam struct v4l2_subdev_frame_interval_enum *fie) 320019a81c14SSteve Longerbeam { 320119a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 320219a81c14SSteve Longerbeam struct v4l2_fract tpf; 320319a81c14SSteve Longerbeam int ret; 320419a81c14SSteve Longerbeam 320519a81c14SSteve Longerbeam if (fie->pad != 0) 320619a81c14SSteve Longerbeam return -EINVAL; 320719a81c14SSteve Longerbeam if (fie->index >= OV5640_NUM_FRAMERATES) 320819a81c14SSteve Longerbeam return -EINVAL; 320919a81c14SSteve Longerbeam 321019a81c14SSteve Longerbeam tpf.numerator = 1; 321119a81c14SSteve Longerbeam tpf.denominator = ov5640_framerates[fie->index]; 321219a81c14SSteve Longerbeam 321319a81c14SSteve Longerbeam ret = ov5640_try_frame_interval(sensor, &tpf, 321419a81c14SSteve Longerbeam fie->width, fie->height); 321519a81c14SSteve Longerbeam if (ret < 0) 321619a81c14SSteve Longerbeam return -EINVAL; 321719a81c14SSteve Longerbeam 321819a81c14SSteve Longerbeam fie->interval = tpf; 321919a81c14SSteve Longerbeam return 0; 322019a81c14SSteve Longerbeam } 322119a81c14SSteve Longerbeam 322219a81c14SSteve Longerbeam static int ov5640_g_frame_interval(struct v4l2_subdev *sd, 322319a81c14SSteve Longerbeam struct v4l2_subdev_frame_interval *fi) 322419a81c14SSteve Longerbeam { 322519a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 322619a81c14SSteve Longerbeam 322719a81c14SSteve Longerbeam mutex_lock(&sensor->lock); 322819a81c14SSteve Longerbeam fi->interval = sensor->frame_interval; 322919a81c14SSteve Longerbeam mutex_unlock(&sensor->lock); 323019a81c14SSteve Longerbeam 323119a81c14SSteve Longerbeam return 0; 323219a81c14SSteve Longerbeam } 323319a81c14SSteve Longerbeam 323419a81c14SSteve Longerbeam static int ov5640_s_frame_interval(struct v4l2_subdev *sd, 323519a81c14SSteve Longerbeam struct v4l2_subdev_frame_interval *fi) 323619a81c14SSteve Longerbeam { 323719a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 323819a81c14SSteve Longerbeam const struct ov5640_mode_info *mode; 323919a81c14SSteve Longerbeam int frame_rate, ret = 0; 324019a81c14SSteve Longerbeam 324119a81c14SSteve Longerbeam if (fi->pad != 0) 324219a81c14SSteve Longerbeam return -EINVAL; 324319a81c14SSteve Longerbeam 324419a81c14SSteve Longerbeam mutex_lock(&sensor->lock); 324519a81c14SSteve Longerbeam 324619a81c14SSteve Longerbeam if (sensor->streaming) { 324719a81c14SSteve Longerbeam ret = -EBUSY; 324819a81c14SSteve Longerbeam goto out; 324919a81c14SSteve Longerbeam } 325019a81c14SSteve Longerbeam 325119a81c14SSteve Longerbeam mode = sensor->current_mode; 325219a81c14SSteve Longerbeam 325319a81c14SSteve Longerbeam frame_rate = ov5640_try_frame_interval(sensor, &fi->interval, 32543145efcdSJacopo Mondi mode->crop.width, 32553145efcdSJacopo Mondi mode->crop.height); 3256e823fb16SMaxime Ripard if (frame_rate < 0) { 3257e823fb16SMaxime Ripard /* Always return a valid frame interval value */ 3258e823fb16SMaxime Ripard fi->interval = sensor->frame_interval; 3259e823fb16SMaxime Ripard goto out; 3260e823fb16SMaxime Ripard } 326119a81c14SSteve Longerbeam 32623145efcdSJacopo Mondi mode = ov5640_find_mode(sensor, frame_rate, mode->crop.width, 32633145efcdSJacopo Mondi mode->crop.height, true); 32643c4a7372SHugues Fruchet if (!mode) { 32653c4a7372SHugues Fruchet ret = -EINVAL; 32663c4a7372SHugues Fruchet goto out; 32673c4a7372SHugues Fruchet } 32683c4a7372SHugues Fruchet 32690929983eSHugues Fruchet if (mode != sensor->current_mode || 32700929983eSHugues Fruchet frame_rate != sensor->current_fr) { 32710929983eSHugues Fruchet sensor->current_fr = frame_rate; 32720929983eSHugues Fruchet sensor->frame_interval = fi->interval; 32733c4a7372SHugues Fruchet sensor->current_mode = mode; 327419a81c14SSteve Longerbeam sensor->pending_mode_change = true; 3275cc196e48SBenoit Parrot 3276cc196e48SBenoit Parrot __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, 3277cc196e48SBenoit Parrot ov5640_calc_pixel_rate(sensor)); 32786949d864SHugues Fruchet } 327919a81c14SSteve Longerbeam out: 328019a81c14SSteve Longerbeam mutex_unlock(&sensor->lock); 328119a81c14SSteve Longerbeam return ret; 328219a81c14SSteve Longerbeam } 328319a81c14SSteve Longerbeam 328419a81c14SSteve Longerbeam static int ov5640_enum_mbus_code(struct v4l2_subdev *sd, 32850d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 328619a81c14SSteve Longerbeam struct v4l2_subdev_mbus_code_enum *code) 328719a81c14SSteve Longerbeam { 328819a81c14SSteve Longerbeam if (code->pad != 0) 328919a81c14SSteve Longerbeam return -EINVAL; 3290e3ee691dSHugues Fruchet if (code->index >= ARRAY_SIZE(ov5640_formats)) 329119a81c14SSteve Longerbeam return -EINVAL; 329219a81c14SSteve Longerbeam 3293e3ee691dSHugues Fruchet code->code = ov5640_formats[code->index].code; 329419a81c14SSteve Longerbeam return 0; 329519a81c14SSteve Longerbeam } 329619a81c14SSteve Longerbeam 329719a81c14SSteve Longerbeam static int ov5640_s_stream(struct v4l2_subdev *sd, int enable) 329819a81c14SSteve Longerbeam { 329919a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 330019a81c14SSteve Longerbeam int ret = 0; 330119a81c14SSteve Longerbeam 330219a81c14SSteve Longerbeam mutex_lock(&sensor->lock); 330319a81c14SSteve Longerbeam 330419a81c14SSteve Longerbeam if (sensor->streaming == !enable) { 330519a81c14SSteve Longerbeam if (enable && sensor->pending_mode_change) { 3306985cdcb0SHugues Fruchet ret = ov5640_set_mode(sensor); 330719a81c14SSteve Longerbeam if (ret) 330819a81c14SSteve Longerbeam goto out; 3309fb98e29fSHugues Fruchet } 3310e3ee691dSHugues Fruchet 3311fb98e29fSHugues Fruchet if (enable && sensor->pending_fmt_change) { 3312e3ee691dSHugues Fruchet ret = ov5640_set_framefmt(sensor, &sensor->fmt); 3313e3ee691dSHugues Fruchet if (ret) 3314e3ee691dSHugues Fruchet goto out; 3315fb98e29fSHugues Fruchet sensor->pending_fmt_change = false; 331619a81c14SSteve Longerbeam } 331719a81c14SSteve Longerbeam 33188e823f5cSJacopo Mondi if (ov5640_is_csi2(sensor)) 3319f22996dbSHugues Fruchet ret = ov5640_set_stream_mipi(sensor, enable); 3320f22996dbSHugues Fruchet else 3321f22996dbSHugues Fruchet ret = ov5640_set_stream_dvp(sensor, enable); 3322f22996dbSHugues Fruchet 332319a81c14SSteve Longerbeam if (!ret) 332419a81c14SSteve Longerbeam sensor->streaming = enable; 332519a81c14SSteve Longerbeam } 332619a81c14SSteve Longerbeam out: 332719a81c14SSteve Longerbeam mutex_unlock(&sensor->lock); 332819a81c14SSteve Longerbeam return ret; 332919a81c14SSteve Longerbeam } 333019a81c14SSteve Longerbeam 333119a81c14SSteve Longerbeam static const struct v4l2_subdev_core_ops ov5640_core_ops = { 333219a81c14SSteve Longerbeam .s_power = ov5640_s_power, 33332d18fbc5SAkinobu Mita .log_status = v4l2_ctrl_subdev_log_status, 33342d18fbc5SAkinobu Mita .subscribe_event = v4l2_ctrl_subdev_subscribe_event, 33352d18fbc5SAkinobu Mita .unsubscribe_event = v4l2_event_subdev_unsubscribe, 333619a81c14SSteve Longerbeam }; 333719a81c14SSteve Longerbeam 333819a81c14SSteve Longerbeam static const struct v4l2_subdev_video_ops ov5640_video_ops = { 333919a81c14SSteve Longerbeam .g_frame_interval = ov5640_g_frame_interval, 334019a81c14SSteve Longerbeam .s_frame_interval = ov5640_s_frame_interval, 334119a81c14SSteve Longerbeam .s_stream = ov5640_s_stream, 334219a81c14SSteve Longerbeam }; 334319a81c14SSteve Longerbeam 334419a81c14SSteve Longerbeam static const struct v4l2_subdev_pad_ops ov5640_pad_ops = { 334519a81c14SSteve Longerbeam .enum_mbus_code = ov5640_enum_mbus_code, 334619a81c14SSteve Longerbeam .get_fmt = ov5640_get_fmt, 334719a81c14SSteve Longerbeam .set_fmt = ov5640_set_fmt, 334819a81c14SSteve Longerbeam .enum_frame_size = ov5640_enum_frame_size, 334919a81c14SSteve Longerbeam .enum_frame_interval = ov5640_enum_frame_interval, 335019a81c14SSteve Longerbeam }; 335119a81c14SSteve Longerbeam 335219a81c14SSteve Longerbeam static const struct v4l2_subdev_ops ov5640_subdev_ops = { 335319a81c14SSteve Longerbeam .core = &ov5640_core_ops, 335419a81c14SSteve Longerbeam .video = &ov5640_video_ops, 335519a81c14SSteve Longerbeam .pad = &ov5640_pad_ops, 335619a81c14SSteve Longerbeam }; 335719a81c14SSteve Longerbeam 335819a81c14SSteve Longerbeam static int ov5640_get_regulators(struct ov5640_dev *sensor) 335919a81c14SSteve Longerbeam { 336019a81c14SSteve Longerbeam int i; 336119a81c14SSteve Longerbeam 336219a81c14SSteve Longerbeam for (i = 0; i < OV5640_NUM_SUPPLIES; i++) 336319a81c14SSteve Longerbeam sensor->supplies[i].supply = ov5640_supply_name[i]; 336419a81c14SSteve Longerbeam 336519a81c14SSteve Longerbeam return devm_regulator_bulk_get(&sensor->i2c_client->dev, 336619a81c14SSteve Longerbeam OV5640_NUM_SUPPLIES, 336719a81c14SSteve Longerbeam sensor->supplies); 336819a81c14SSteve Longerbeam } 336919a81c14SSteve Longerbeam 33700f7acb52SHugues Fruchet static int ov5640_check_chip_id(struct ov5640_dev *sensor) 33710f7acb52SHugues Fruchet { 33720f7acb52SHugues Fruchet struct i2c_client *client = sensor->i2c_client; 33730f7acb52SHugues Fruchet int ret = 0; 33740f7acb52SHugues Fruchet u16 chip_id; 33750f7acb52SHugues Fruchet 33760f7acb52SHugues Fruchet ret = ov5640_set_power_on(sensor); 33770f7acb52SHugues Fruchet if (ret) 33780f7acb52SHugues Fruchet return ret; 33790f7acb52SHugues Fruchet 33800f7acb52SHugues Fruchet ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id); 33810f7acb52SHugues Fruchet if (ret) { 33820f7acb52SHugues Fruchet dev_err(&client->dev, "%s: failed to read chip identifier\n", 33830f7acb52SHugues Fruchet __func__); 33840f7acb52SHugues Fruchet goto power_off; 33850f7acb52SHugues Fruchet } 33860f7acb52SHugues Fruchet 33870f7acb52SHugues Fruchet if (chip_id != 0x5640) { 33880f7acb52SHugues Fruchet dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n", 33890f7acb52SHugues Fruchet __func__, chip_id); 33900f7acb52SHugues Fruchet ret = -ENXIO; 33910f7acb52SHugues Fruchet } 33920f7acb52SHugues Fruchet 33930f7acb52SHugues Fruchet power_off: 33940f7acb52SHugues Fruchet ov5640_set_power_off(sensor); 33950f7acb52SHugues Fruchet return ret; 33960f7acb52SHugues Fruchet } 33970f7acb52SHugues Fruchet 3398e6714993SKieran Bingham static int ov5640_probe(struct i2c_client *client) 339919a81c14SSteve Longerbeam { 340019a81c14SSteve Longerbeam struct device *dev = &client->dev; 340119a81c14SSteve Longerbeam struct fwnode_handle *endpoint; 340219a81c14SSteve Longerbeam struct ov5640_dev *sensor; 3403e6441fdeSHugues Fruchet struct v4l2_mbus_framefmt *fmt; 3404c3f3ba3eSHugues Fruchet u32 rotation; 340519a81c14SSteve Longerbeam int ret; 340619a81c14SSteve Longerbeam 340719a81c14SSteve Longerbeam sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); 340819a81c14SSteve Longerbeam if (!sensor) 340919a81c14SSteve Longerbeam return -ENOMEM; 341019a81c14SSteve Longerbeam 341119a81c14SSteve Longerbeam sensor->i2c_client = client; 3412fb98e29fSHugues Fruchet 3413fb98e29fSHugues Fruchet /* 3414fb98e29fSHugues Fruchet * default init sequence initialize sensor to 3415fb98e29fSHugues Fruchet * YUV422 UYVY VGA@30fps 3416fb98e29fSHugues Fruchet */ 3417e6441fdeSHugues Fruchet fmt = &sensor->fmt; 3418fb98e29fSHugues Fruchet fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; 3419fb98e29fSHugues Fruchet fmt->colorspace = V4L2_COLORSPACE_SRGB; 3420e6441fdeSHugues Fruchet fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); 3421e6441fdeSHugues Fruchet fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; 3422e6441fdeSHugues Fruchet fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace); 3423e6441fdeSHugues Fruchet fmt->width = 640; 3424e6441fdeSHugues Fruchet fmt->height = 480; 3425e6441fdeSHugues Fruchet fmt->field = V4L2_FIELD_NONE; 342619a81c14SSteve Longerbeam sensor->frame_interval.numerator = 1; 342719a81c14SSteve Longerbeam sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS]; 342819a81c14SSteve Longerbeam sensor->current_fr = OV5640_30_FPS; 342919a81c14SSteve Longerbeam sensor->current_mode = 3430086c25f8SMaxime Ripard &ov5640_mode_data[OV5640_MODE_VGA_640_480]; 3431985cdcb0SHugues Fruchet sensor->last_mode = sensor->current_mode; 34323c28588fSJacopo Mondi sensor->current_link_freq = OV5640_DEFAULT_LINK_FREQ; 343319a81c14SSteve Longerbeam 343419a81c14SSteve Longerbeam sensor->ae_target = 52; 343519a81c14SSteve Longerbeam 3436c3f3ba3eSHugues Fruchet /* optional indication of physical rotation of sensor */ 3437c3f3ba3eSHugues Fruchet ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation", 3438c3f3ba3eSHugues Fruchet &rotation); 3439c3f3ba3eSHugues Fruchet if (!ret) { 3440c3f3ba3eSHugues Fruchet switch (rotation) { 3441c3f3ba3eSHugues Fruchet case 180: 3442c3f3ba3eSHugues Fruchet sensor->upside_down = true; 34431771e9fbSGustavo A. R. Silva fallthrough; 3444c3f3ba3eSHugues Fruchet case 0: 3445c3f3ba3eSHugues Fruchet break; 3446c3f3ba3eSHugues Fruchet default: 3447c3f3ba3eSHugues Fruchet dev_warn(dev, "%u degrees rotation is not supported, ignoring...\n", 3448c3f3ba3eSHugues Fruchet rotation); 3449c3f3ba3eSHugues Fruchet } 3450c3f3ba3eSHugues Fruchet } 3451c3f3ba3eSHugues Fruchet 3452ce96bcf5SSakari Ailus endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), 3453ce96bcf5SSakari Ailus NULL); 345419a81c14SSteve Longerbeam if (!endpoint) { 345519a81c14SSteve Longerbeam dev_err(dev, "endpoint node not found\n"); 345619a81c14SSteve Longerbeam return -EINVAL; 345719a81c14SSteve Longerbeam } 345819a81c14SSteve Longerbeam 345919a81c14SSteve Longerbeam ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep); 346019a81c14SSteve Longerbeam fwnode_handle_put(endpoint); 346119a81c14SSteve Longerbeam if (ret) { 346219a81c14SSteve Longerbeam dev_err(dev, "Could not parse endpoint\n"); 346319a81c14SSteve Longerbeam return ret; 346419a81c14SSteve Longerbeam } 346519a81c14SSteve Longerbeam 34662c61e48dSLad Prabhakar if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL && 34672c61e48dSLad Prabhakar sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY && 34682c61e48dSLad Prabhakar sensor->ep.bus_type != V4L2_MBUS_BT656) { 34692c61e48dSLad Prabhakar dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type); 34702c61e48dSLad Prabhakar return -EINVAL; 34712c61e48dSLad Prabhakar } 34722c61e48dSLad Prabhakar 347319a81c14SSteve Longerbeam /* get system clock (xclk) */ 347419a81c14SSteve Longerbeam sensor->xclk = devm_clk_get(dev, "xclk"); 347519a81c14SSteve Longerbeam if (IS_ERR(sensor->xclk)) { 347619a81c14SSteve Longerbeam dev_err(dev, "failed to get xclk\n"); 347719a81c14SSteve Longerbeam return PTR_ERR(sensor->xclk); 347819a81c14SSteve Longerbeam } 347919a81c14SSteve Longerbeam 348019a81c14SSteve Longerbeam sensor->xclk_freq = clk_get_rate(sensor->xclk); 348119a81c14SSteve Longerbeam if (sensor->xclk_freq < OV5640_XCLK_MIN || 348219a81c14SSteve Longerbeam sensor->xclk_freq > OV5640_XCLK_MAX) { 348319a81c14SSteve Longerbeam dev_err(dev, "xclk frequency out of range: %d Hz\n", 348419a81c14SSteve Longerbeam sensor->xclk_freq); 348519a81c14SSteve Longerbeam return -EINVAL; 348619a81c14SSteve Longerbeam } 348719a81c14SSteve Longerbeam 348819a81c14SSteve Longerbeam /* request optional power down pin */ 348919a81c14SSteve Longerbeam sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown", 349019a81c14SSteve Longerbeam GPIOD_OUT_HIGH); 34918791a102SFabio Estevam if (IS_ERR(sensor->pwdn_gpio)) 34928791a102SFabio Estevam return PTR_ERR(sensor->pwdn_gpio); 34938791a102SFabio Estevam 349419a81c14SSteve Longerbeam /* request optional reset pin */ 349519a81c14SSteve Longerbeam sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset", 349619a81c14SSteve Longerbeam GPIOD_OUT_HIGH); 34978791a102SFabio Estevam if (IS_ERR(sensor->reset_gpio)) 34988791a102SFabio Estevam return PTR_ERR(sensor->reset_gpio); 349919a81c14SSteve Longerbeam 350019a81c14SSteve Longerbeam v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops); 350119a81c14SSteve Longerbeam 35022d18fbc5SAkinobu Mita sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | 35032d18fbc5SAkinobu Mita V4L2_SUBDEV_FL_HAS_EVENTS; 350419a81c14SSteve Longerbeam sensor->pad.flags = MEDIA_PAD_FL_SOURCE; 350519a81c14SSteve Longerbeam sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; 350619a81c14SSteve Longerbeam ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); 350719a81c14SSteve Longerbeam if (ret) 350819a81c14SSteve Longerbeam return ret; 350919a81c14SSteve Longerbeam 351019a81c14SSteve Longerbeam ret = ov5640_get_regulators(sensor); 351119a81c14SSteve Longerbeam if (ret) 351219a81c14SSteve Longerbeam return ret; 351319a81c14SSteve Longerbeam 351419a81c14SSteve Longerbeam mutex_init(&sensor->lock); 351519a81c14SSteve Longerbeam 35160f7acb52SHugues Fruchet ret = ov5640_check_chip_id(sensor); 35170f7acb52SHugues Fruchet if (ret) 35180f7acb52SHugues Fruchet goto entity_cleanup; 35190f7acb52SHugues Fruchet 352019a81c14SSteve Longerbeam ret = ov5640_init_controls(sensor); 352119a81c14SSteve Longerbeam if (ret) 352219a81c14SSteve Longerbeam goto entity_cleanup; 352319a81c14SSteve Longerbeam 352415786f7bSSakari Ailus ret = v4l2_async_register_subdev_sensor(&sensor->sd); 352519a81c14SSteve Longerbeam if (ret) 352619a81c14SSteve Longerbeam goto free_ctrls; 352719a81c14SSteve Longerbeam 352819a81c14SSteve Longerbeam return 0; 352919a81c14SSteve Longerbeam 353019a81c14SSteve Longerbeam free_ctrls: 353119a81c14SSteve Longerbeam v4l2_ctrl_handler_free(&sensor->ctrls.handler); 353219a81c14SSteve Longerbeam entity_cleanup: 353319a81c14SSteve Longerbeam media_entity_cleanup(&sensor->sd.entity); 3534bfcba38dSTomi Valkeinen mutex_destroy(&sensor->lock); 353519a81c14SSteve Longerbeam return ret; 353619a81c14SSteve Longerbeam } 353719a81c14SSteve Longerbeam 353819a81c14SSteve Longerbeam static int ov5640_remove(struct i2c_client *client) 353919a81c14SSteve Longerbeam { 354019a81c14SSteve Longerbeam struct v4l2_subdev *sd = i2c_get_clientdata(client); 354119a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 354219a81c14SSteve Longerbeam 354319a81c14SSteve Longerbeam v4l2_async_unregister_subdev(&sensor->sd); 354419a81c14SSteve Longerbeam media_entity_cleanup(&sensor->sd.entity); 354519a81c14SSteve Longerbeam v4l2_ctrl_handler_free(&sensor->ctrls.handler); 3546bfcba38dSTomi Valkeinen mutex_destroy(&sensor->lock); 354719a81c14SSteve Longerbeam 354819a81c14SSteve Longerbeam return 0; 354919a81c14SSteve Longerbeam } 355019a81c14SSteve Longerbeam 355119a81c14SSteve Longerbeam static const struct i2c_device_id ov5640_id[] = { 355219a81c14SSteve Longerbeam {"ov5640", 0}, 355319a81c14SSteve Longerbeam {}, 355419a81c14SSteve Longerbeam }; 355519a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(i2c, ov5640_id); 355619a81c14SSteve Longerbeam 355719a81c14SSteve Longerbeam static const struct of_device_id ov5640_dt_ids[] = { 355819a81c14SSteve Longerbeam { .compatible = "ovti,ov5640" }, 355919a81c14SSteve Longerbeam { /* sentinel */ } 356019a81c14SSteve Longerbeam }; 356119a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(of, ov5640_dt_ids); 356219a81c14SSteve Longerbeam 356319a81c14SSteve Longerbeam static struct i2c_driver ov5640_i2c_driver = { 356419a81c14SSteve Longerbeam .driver = { 356519a81c14SSteve Longerbeam .name = "ov5640", 356619a81c14SSteve Longerbeam .of_match_table = ov5640_dt_ids, 356719a81c14SSteve Longerbeam }, 356819a81c14SSteve Longerbeam .id_table = ov5640_id, 3569e6714993SKieran Bingham .probe_new = ov5640_probe, 357019a81c14SSteve Longerbeam .remove = ov5640_remove, 357119a81c14SSteve Longerbeam }; 357219a81c14SSteve Longerbeam 357319a81c14SSteve Longerbeam module_i2c_driver(ov5640_i2c_driver); 357419a81c14SSteve Longerbeam 357519a81c14SSteve Longerbeam MODULE_DESCRIPTION("OV5640 MIPI Camera Subdev Driver"); 357619a81c14SSteve Longerbeam MODULE_LICENSE("GPL"); 3577