18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. 48c2ecf20Sopenharmony_ci * Copyright (C) 2014-2017 Mentor Graphics Inc. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/clk.h> 88c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 98c2ecf20Sopenharmony_ci#include <linux/clkdev.h> 108c2ecf20Sopenharmony_ci#include <linux/ctype.h> 118c2ecf20Sopenharmony_ci#include <linux/delay.h> 128c2ecf20Sopenharmony_ci#include <linux/device.h> 138c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 148c2ecf20Sopenharmony_ci#include <linux/i2c.h> 158c2ecf20Sopenharmony_ci#include <linux/init.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/of_device.h> 188c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 198c2ecf20Sopenharmony_ci#include <linux/slab.h> 208c2ecf20Sopenharmony_ci#include <linux/types.h> 218c2ecf20Sopenharmony_ci#include <media/v4l2-async.h> 228c2ecf20Sopenharmony_ci#include <media/v4l2-ctrls.h> 238c2ecf20Sopenharmony_ci#include <media/v4l2-device.h> 248c2ecf20Sopenharmony_ci#include <media/v4l2-event.h> 258c2ecf20Sopenharmony_ci#include <media/v4l2-fwnode.h> 268c2ecf20Sopenharmony_ci#include <media/v4l2-subdev.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* min/typical/max system clock (xclk) frequencies */ 298c2ecf20Sopenharmony_ci#define OV5640_XCLK_MIN 6000000 308c2ecf20Sopenharmony_ci#define OV5640_XCLK_MAX 54000000 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define OV5640_DEFAULT_SLAVE_ID 0x3c 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define OV5640_REG_SYS_RESET02 0x3002 358c2ecf20Sopenharmony_ci#define OV5640_REG_SYS_CLOCK_ENABLE02 0x3006 368c2ecf20Sopenharmony_ci#define OV5640_REG_SYS_CTRL0 0x3008 378c2ecf20Sopenharmony_ci#define OV5640_REG_SYS_CTRL0_SW_PWDN 0x42 388c2ecf20Sopenharmony_ci#define OV5640_REG_SYS_CTRL0_SW_PWUP 0x02 398c2ecf20Sopenharmony_ci#define OV5640_REG_CHIP_ID 0x300a 408c2ecf20Sopenharmony_ci#define OV5640_REG_IO_MIPI_CTRL00 0x300e 418c2ecf20Sopenharmony_ci#define OV5640_REG_PAD_OUTPUT_ENABLE01 0x3017 428c2ecf20Sopenharmony_ci#define OV5640_REG_PAD_OUTPUT_ENABLE02 0x3018 438c2ecf20Sopenharmony_ci#define OV5640_REG_PAD_OUTPUT00 0x3019 448c2ecf20Sopenharmony_ci#define OV5640_REG_SYSTEM_CONTROL1 0x302e 458c2ecf20Sopenharmony_ci#define OV5640_REG_SC_PLL_CTRL0 0x3034 468c2ecf20Sopenharmony_ci#define OV5640_REG_SC_PLL_CTRL1 0x3035 478c2ecf20Sopenharmony_ci#define OV5640_REG_SC_PLL_CTRL2 0x3036 488c2ecf20Sopenharmony_ci#define OV5640_REG_SC_PLL_CTRL3 0x3037 498c2ecf20Sopenharmony_ci#define OV5640_REG_SLAVE_ID 0x3100 508c2ecf20Sopenharmony_ci#define OV5640_REG_SCCB_SYS_CTRL1 0x3103 518c2ecf20Sopenharmony_ci#define OV5640_REG_SYS_ROOT_DIVIDER 0x3108 528c2ecf20Sopenharmony_ci#define OV5640_REG_AWB_R_GAIN 0x3400 538c2ecf20Sopenharmony_ci#define OV5640_REG_AWB_G_GAIN 0x3402 548c2ecf20Sopenharmony_ci#define OV5640_REG_AWB_B_GAIN 0x3404 558c2ecf20Sopenharmony_ci#define OV5640_REG_AWB_MANUAL_CTRL 0x3406 568c2ecf20Sopenharmony_ci#define OV5640_REG_AEC_PK_EXPOSURE_HI 0x3500 578c2ecf20Sopenharmony_ci#define OV5640_REG_AEC_PK_EXPOSURE_MED 0x3501 588c2ecf20Sopenharmony_ci#define OV5640_REG_AEC_PK_EXPOSURE_LO 0x3502 598c2ecf20Sopenharmony_ci#define OV5640_REG_AEC_PK_MANUAL 0x3503 608c2ecf20Sopenharmony_ci#define OV5640_REG_AEC_PK_REAL_GAIN 0x350a 618c2ecf20Sopenharmony_ci#define OV5640_REG_AEC_PK_VTS 0x350c 628c2ecf20Sopenharmony_ci#define OV5640_REG_TIMING_DVPHO 0x3808 638c2ecf20Sopenharmony_ci#define OV5640_REG_TIMING_DVPVO 0x380a 648c2ecf20Sopenharmony_ci#define OV5640_REG_TIMING_HTS 0x380c 658c2ecf20Sopenharmony_ci#define OV5640_REG_TIMING_VTS 0x380e 668c2ecf20Sopenharmony_ci#define OV5640_REG_TIMING_TC_REG20 0x3820 678c2ecf20Sopenharmony_ci#define OV5640_REG_TIMING_TC_REG21 0x3821 688c2ecf20Sopenharmony_ci#define OV5640_REG_AEC_CTRL00 0x3a00 698c2ecf20Sopenharmony_ci#define OV5640_REG_AEC_B50_STEP 0x3a08 708c2ecf20Sopenharmony_ci#define OV5640_REG_AEC_B60_STEP 0x3a0a 718c2ecf20Sopenharmony_ci#define OV5640_REG_AEC_CTRL0D 0x3a0d 728c2ecf20Sopenharmony_ci#define OV5640_REG_AEC_CTRL0E 0x3a0e 738c2ecf20Sopenharmony_ci#define OV5640_REG_AEC_CTRL0F 0x3a0f 748c2ecf20Sopenharmony_ci#define OV5640_REG_AEC_CTRL10 0x3a10 758c2ecf20Sopenharmony_ci#define OV5640_REG_AEC_CTRL11 0x3a11 768c2ecf20Sopenharmony_ci#define OV5640_REG_AEC_CTRL1B 0x3a1b 778c2ecf20Sopenharmony_ci#define OV5640_REG_AEC_CTRL1E 0x3a1e 788c2ecf20Sopenharmony_ci#define OV5640_REG_AEC_CTRL1F 0x3a1f 798c2ecf20Sopenharmony_ci#define OV5640_REG_HZ5060_CTRL00 0x3c00 808c2ecf20Sopenharmony_ci#define OV5640_REG_HZ5060_CTRL01 0x3c01 818c2ecf20Sopenharmony_ci#define OV5640_REG_SIGMADELTA_CTRL0C 0x3c0c 828c2ecf20Sopenharmony_ci#define OV5640_REG_FRAME_CTRL01 0x4202 838c2ecf20Sopenharmony_ci#define OV5640_REG_FORMAT_CONTROL00 0x4300 848c2ecf20Sopenharmony_ci#define OV5640_REG_VFIFO_HSIZE 0x4602 858c2ecf20Sopenharmony_ci#define OV5640_REG_VFIFO_VSIZE 0x4604 868c2ecf20Sopenharmony_ci#define OV5640_REG_JPG_MODE_SELECT 0x4713 878c2ecf20Sopenharmony_ci#define OV5640_REG_CCIR656_CTRL00 0x4730 888c2ecf20Sopenharmony_ci#define OV5640_REG_POLARITY_CTRL00 0x4740 898c2ecf20Sopenharmony_ci#define OV5640_REG_MIPI_CTRL00 0x4800 908c2ecf20Sopenharmony_ci#define OV5640_REG_DEBUG_MODE 0x4814 918c2ecf20Sopenharmony_ci#define OV5640_REG_ISP_FORMAT_MUX_CTRL 0x501f 928c2ecf20Sopenharmony_ci#define OV5640_REG_PRE_ISP_TEST_SET1 0x503d 938c2ecf20Sopenharmony_ci#define OV5640_REG_SDE_CTRL0 0x5580 948c2ecf20Sopenharmony_ci#define OV5640_REG_SDE_CTRL1 0x5581 958c2ecf20Sopenharmony_ci#define OV5640_REG_SDE_CTRL3 0x5583 968c2ecf20Sopenharmony_ci#define OV5640_REG_SDE_CTRL4 0x5584 978c2ecf20Sopenharmony_ci#define OV5640_REG_SDE_CTRL5 0x5585 988c2ecf20Sopenharmony_ci#define OV5640_REG_AVG_READOUT 0x56a1 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cienum ov5640_mode_id { 1018c2ecf20Sopenharmony_ci OV5640_MODE_QCIF_176_144 = 0, 1028c2ecf20Sopenharmony_ci OV5640_MODE_QVGA_320_240, 1038c2ecf20Sopenharmony_ci OV5640_MODE_VGA_640_480, 1048c2ecf20Sopenharmony_ci OV5640_MODE_NTSC_720_480, 1058c2ecf20Sopenharmony_ci OV5640_MODE_PAL_720_576, 1068c2ecf20Sopenharmony_ci OV5640_MODE_XGA_1024_768, 1078c2ecf20Sopenharmony_ci OV5640_MODE_720P_1280_720, 1088c2ecf20Sopenharmony_ci OV5640_MODE_1080P_1920_1080, 1098c2ecf20Sopenharmony_ci OV5640_MODE_QSXGA_2592_1944, 1108c2ecf20Sopenharmony_ci OV5640_NUM_MODES, 1118c2ecf20Sopenharmony_ci}; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cienum ov5640_frame_rate { 1148c2ecf20Sopenharmony_ci OV5640_15_FPS = 0, 1158c2ecf20Sopenharmony_ci OV5640_30_FPS, 1168c2ecf20Sopenharmony_ci OV5640_60_FPS, 1178c2ecf20Sopenharmony_ci OV5640_NUM_FRAMERATES, 1188c2ecf20Sopenharmony_ci}; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cienum ov5640_format_mux { 1218c2ecf20Sopenharmony_ci OV5640_FMT_MUX_YUV422 = 0, 1228c2ecf20Sopenharmony_ci OV5640_FMT_MUX_RGB, 1238c2ecf20Sopenharmony_ci OV5640_FMT_MUX_DITHER, 1248c2ecf20Sopenharmony_ci OV5640_FMT_MUX_RAW_DPC, 1258c2ecf20Sopenharmony_ci OV5640_FMT_MUX_SNR_RAW, 1268c2ecf20Sopenharmony_ci OV5640_FMT_MUX_RAW_CIP, 1278c2ecf20Sopenharmony_ci}; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistruct ov5640_pixfmt { 1308c2ecf20Sopenharmony_ci u32 code; 1318c2ecf20Sopenharmony_ci u32 colorspace; 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic const struct ov5640_pixfmt ov5640_formats[] = { 1358c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_JPEG_1X8, V4L2_COLORSPACE_JPEG, }, 1368c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_SRGB, }, 1378c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_SRGB, }, 1388c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB, }, 1398c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB, }, 1408c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB, }, 1418c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_COLORSPACE_SRGB, }, 1428c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_COLORSPACE_SRGB, }, 1438c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_COLORSPACE_SRGB, }, 1448c2ecf20Sopenharmony_ci}; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/* 1478c2ecf20Sopenharmony_ci * FIXME: remove this when a subdev API becomes available 1488c2ecf20Sopenharmony_ci * to set the MIPI CSI-2 virtual channel. 1498c2ecf20Sopenharmony_ci */ 1508c2ecf20Sopenharmony_cistatic unsigned int virtual_channel; 1518c2ecf20Sopenharmony_cimodule_param(virtual_channel, uint, 0444); 1528c2ecf20Sopenharmony_ciMODULE_PARM_DESC(virtual_channel, 1538c2ecf20Sopenharmony_ci "MIPI CSI-2 virtual channel (0..3), default 0"); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic const int ov5640_framerates[] = { 1568c2ecf20Sopenharmony_ci [OV5640_15_FPS] = 15, 1578c2ecf20Sopenharmony_ci [OV5640_30_FPS] = 30, 1588c2ecf20Sopenharmony_ci [OV5640_60_FPS] = 60, 1598c2ecf20Sopenharmony_ci}; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci/* regulator supplies */ 1628c2ecf20Sopenharmony_cistatic const char * const ov5640_supply_name[] = { 1638c2ecf20Sopenharmony_ci "DOVDD", /* Digital I/O (1.8V) supply */ 1648c2ecf20Sopenharmony_ci "AVDD", /* Analog (2.8V) supply */ 1658c2ecf20Sopenharmony_ci "DVDD", /* Digital Core (1.5V) supply */ 1668c2ecf20Sopenharmony_ci}; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci#define OV5640_NUM_SUPPLIES ARRAY_SIZE(ov5640_supply_name) 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci/* 1718c2ecf20Sopenharmony_ci * Image size under 1280 * 960 are SUBSAMPLING 1728c2ecf20Sopenharmony_ci * Image size upper 1280 * 960 are SCALING 1738c2ecf20Sopenharmony_ci */ 1748c2ecf20Sopenharmony_cienum ov5640_downsize_mode { 1758c2ecf20Sopenharmony_ci SUBSAMPLING, 1768c2ecf20Sopenharmony_ci SCALING, 1778c2ecf20Sopenharmony_ci}; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistruct reg_value { 1808c2ecf20Sopenharmony_ci u16 reg_addr; 1818c2ecf20Sopenharmony_ci u8 val; 1828c2ecf20Sopenharmony_ci u8 mask; 1838c2ecf20Sopenharmony_ci u32 delay_ms; 1848c2ecf20Sopenharmony_ci}; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistruct ov5640_mode_info { 1878c2ecf20Sopenharmony_ci enum ov5640_mode_id id; 1888c2ecf20Sopenharmony_ci enum ov5640_downsize_mode dn_mode; 1898c2ecf20Sopenharmony_ci u32 hact; 1908c2ecf20Sopenharmony_ci u32 htot; 1918c2ecf20Sopenharmony_ci u32 vact; 1928c2ecf20Sopenharmony_ci u32 vtot; 1938c2ecf20Sopenharmony_ci const struct reg_value *reg_data; 1948c2ecf20Sopenharmony_ci u32 reg_data_size; 1958c2ecf20Sopenharmony_ci u32 max_fps; 1968c2ecf20Sopenharmony_ci}; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistruct ov5640_ctrls { 1998c2ecf20Sopenharmony_ci struct v4l2_ctrl_handler handler; 2008c2ecf20Sopenharmony_ci struct v4l2_ctrl *pixel_rate; 2018c2ecf20Sopenharmony_ci struct { 2028c2ecf20Sopenharmony_ci struct v4l2_ctrl *auto_exp; 2038c2ecf20Sopenharmony_ci struct v4l2_ctrl *exposure; 2048c2ecf20Sopenharmony_ci }; 2058c2ecf20Sopenharmony_ci struct { 2068c2ecf20Sopenharmony_ci struct v4l2_ctrl *auto_wb; 2078c2ecf20Sopenharmony_ci struct v4l2_ctrl *blue_balance; 2088c2ecf20Sopenharmony_ci struct v4l2_ctrl *red_balance; 2098c2ecf20Sopenharmony_ci }; 2108c2ecf20Sopenharmony_ci struct { 2118c2ecf20Sopenharmony_ci struct v4l2_ctrl *auto_gain; 2128c2ecf20Sopenharmony_ci struct v4l2_ctrl *gain; 2138c2ecf20Sopenharmony_ci }; 2148c2ecf20Sopenharmony_ci struct v4l2_ctrl *brightness; 2158c2ecf20Sopenharmony_ci struct v4l2_ctrl *light_freq; 2168c2ecf20Sopenharmony_ci struct v4l2_ctrl *saturation; 2178c2ecf20Sopenharmony_ci struct v4l2_ctrl *contrast; 2188c2ecf20Sopenharmony_ci struct v4l2_ctrl *hue; 2198c2ecf20Sopenharmony_ci struct v4l2_ctrl *test_pattern; 2208c2ecf20Sopenharmony_ci struct v4l2_ctrl *hflip; 2218c2ecf20Sopenharmony_ci struct v4l2_ctrl *vflip; 2228c2ecf20Sopenharmony_ci}; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistruct ov5640_dev { 2258c2ecf20Sopenharmony_ci struct i2c_client *i2c_client; 2268c2ecf20Sopenharmony_ci struct v4l2_subdev sd; 2278c2ecf20Sopenharmony_ci struct media_pad pad; 2288c2ecf20Sopenharmony_ci struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */ 2298c2ecf20Sopenharmony_ci struct clk *xclk; /* system clock to OV5640 */ 2308c2ecf20Sopenharmony_ci u32 xclk_freq; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci struct regulator_bulk_data supplies[OV5640_NUM_SUPPLIES]; 2338c2ecf20Sopenharmony_ci struct gpio_desc *reset_gpio; 2348c2ecf20Sopenharmony_ci struct gpio_desc *pwdn_gpio; 2358c2ecf20Sopenharmony_ci bool upside_down; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci /* lock to protect all members below */ 2388c2ecf20Sopenharmony_ci struct mutex lock; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci int power_count; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt fmt; 2438c2ecf20Sopenharmony_ci bool pending_fmt_change; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci const struct ov5640_mode_info *current_mode; 2468c2ecf20Sopenharmony_ci const struct ov5640_mode_info *last_mode; 2478c2ecf20Sopenharmony_ci enum ov5640_frame_rate current_fr; 2488c2ecf20Sopenharmony_ci struct v4l2_fract frame_interval; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci struct ov5640_ctrls ctrls; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci u32 prev_sysclk, prev_hts; 2538c2ecf20Sopenharmony_ci u32 ae_low, ae_high, ae_target; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci bool pending_mode_change; 2568c2ecf20Sopenharmony_ci bool streaming; 2578c2ecf20Sopenharmony_ci}; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci return container_of(sd, struct ov5640_dev, sd); 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci return &container_of(ctrl->handler, struct ov5640_dev, 2678c2ecf20Sopenharmony_ci ctrls.handler)->sd; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci/* 2718c2ecf20Sopenharmony_ci * FIXME: all of these register tables are likely filled with 2728c2ecf20Sopenharmony_ci * entries that set the register to their power-on default values, 2738c2ecf20Sopenharmony_ci * and which are otherwise not touched by this driver. Those entries 2748c2ecf20Sopenharmony_ci * should be identified and removed to speed register load time 2758c2ecf20Sopenharmony_ci * over i2c. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ci/* YUV422 UYVY VGA@30fps */ 2788c2ecf20Sopenharmony_cistatic const struct reg_value ov5640_init_setting_30fps_VGA[] = { 2798c2ecf20Sopenharmony_ci {0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0}, 2808c2ecf20Sopenharmony_ci {0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0}, 2818c2ecf20Sopenharmony_ci {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0}, 2828c2ecf20Sopenharmony_ci {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0}, 2838c2ecf20Sopenharmony_ci {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0}, 2848c2ecf20Sopenharmony_ci {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0}, 2858c2ecf20Sopenharmony_ci {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0}, 2868c2ecf20Sopenharmony_ci {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0}, 2878c2ecf20Sopenharmony_ci {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0}, 2888c2ecf20Sopenharmony_ci {0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0}, 2898c2ecf20Sopenharmony_ci {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0}, 2908c2ecf20Sopenharmony_ci {0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0}, 2918c2ecf20Sopenharmony_ci {0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0}, 2928c2ecf20Sopenharmony_ci {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 2938c2ecf20Sopenharmony_ci {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, 2948c2ecf20Sopenharmony_ci {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, 2958c2ecf20Sopenharmony_ci {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, 2968c2ecf20Sopenharmony_ci {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, 2978c2ecf20Sopenharmony_ci {0x3810, 0x00, 0, 0}, 2988c2ecf20Sopenharmony_ci {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, 2998c2ecf20Sopenharmony_ci {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 3008c2ecf20Sopenharmony_ci {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 3018c2ecf20Sopenharmony_ci {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 3028c2ecf20Sopenharmony_ci {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 3038c2ecf20Sopenharmony_ci {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 3048c2ecf20Sopenharmony_ci {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0}, 3058c2ecf20Sopenharmony_ci {0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0}, 3068c2ecf20Sopenharmony_ci {0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0}, 3078c2ecf20Sopenharmony_ci {0x501f, 0x00, 0, 0}, {0x4407, 0x04, 0, 0}, 3088c2ecf20Sopenharmony_ci {0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 3098c2ecf20Sopenharmony_ci {0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0}, 3108c2ecf20Sopenharmony_ci {0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0}, 3118c2ecf20Sopenharmony_ci {0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0}, 3128c2ecf20Sopenharmony_ci {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0}, 3138c2ecf20Sopenharmony_ci {0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0}, 3148c2ecf20Sopenharmony_ci {0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0}, 3158c2ecf20Sopenharmony_ci {0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0}, 3168c2ecf20Sopenharmony_ci {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, 3178c2ecf20Sopenharmony_ci {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, 3188c2ecf20Sopenharmony_ci {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, 3198c2ecf20Sopenharmony_ci {0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, 3208c2ecf20Sopenharmony_ci {0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0}, 3218c2ecf20Sopenharmony_ci {0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0}, 3228c2ecf20Sopenharmony_ci {0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0}, 3238c2ecf20Sopenharmony_ci {0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0}, 3248c2ecf20Sopenharmony_ci {0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0}, 3258c2ecf20Sopenharmony_ci {0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0}, 3268c2ecf20Sopenharmony_ci {0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0}, 3278c2ecf20Sopenharmony_ci {0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0}, 3288c2ecf20Sopenharmony_ci {0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0}, 3298c2ecf20Sopenharmony_ci {0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0}, 3308c2ecf20Sopenharmony_ci {0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0}, 3318c2ecf20Sopenharmony_ci {0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0}, 3328c2ecf20Sopenharmony_ci {0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0}, 3338c2ecf20Sopenharmony_ci {0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0}, 3348c2ecf20Sopenharmony_ci {0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0}, 3358c2ecf20Sopenharmony_ci {0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0}, 3368c2ecf20Sopenharmony_ci {0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0}, 3378c2ecf20Sopenharmony_ci {0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0}, 3388c2ecf20Sopenharmony_ci {0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0}, 3398c2ecf20Sopenharmony_ci {0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0}, 3408c2ecf20Sopenharmony_ci {0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0}, 3418c2ecf20Sopenharmony_ci {0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0}, 3428c2ecf20Sopenharmony_ci {0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0}, 3438c2ecf20Sopenharmony_ci {0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0}, 3448c2ecf20Sopenharmony_ci {0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0}, 3458c2ecf20Sopenharmony_ci {0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0}, 3468c2ecf20Sopenharmony_ci {0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0}, 3478c2ecf20Sopenharmony_ci {0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0}, 3488c2ecf20Sopenharmony_ci {0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0}, 3498c2ecf20Sopenharmony_ci {0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0}, 3508c2ecf20Sopenharmony_ci {0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0}, 3518c2ecf20Sopenharmony_ci {0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0}, 3528c2ecf20Sopenharmony_ci {0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0}, 3538c2ecf20Sopenharmony_ci {0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0}, 3548c2ecf20Sopenharmony_ci {0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0}, 3558c2ecf20Sopenharmony_ci {0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0}, 3568c2ecf20Sopenharmony_ci {0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0}, 3578c2ecf20Sopenharmony_ci {0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0}, 3588c2ecf20Sopenharmony_ci {0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0}, 3598c2ecf20Sopenharmony_ci {0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300}, 3608c2ecf20Sopenharmony_ci}; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic const struct reg_value ov5640_setting_VGA_640_480[] = { 3638c2ecf20Sopenharmony_ci {0x3c07, 0x08, 0, 0}, 3648c2ecf20Sopenharmony_ci {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 3658c2ecf20Sopenharmony_ci {0x3814, 0x31, 0, 0}, 3668c2ecf20Sopenharmony_ci {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, 3678c2ecf20Sopenharmony_ci {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, 3688c2ecf20Sopenharmony_ci {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, 3698c2ecf20Sopenharmony_ci {0x3810, 0x00, 0, 0}, 3708c2ecf20Sopenharmony_ci {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, 3718c2ecf20Sopenharmony_ci {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 3728c2ecf20Sopenharmony_ci {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 3738c2ecf20Sopenharmony_ci {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 3748c2ecf20Sopenharmony_ci {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 3758c2ecf20Sopenharmony_ci {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 3768c2ecf20Sopenharmony_ci {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 3778c2ecf20Sopenharmony_ci {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 3788c2ecf20Sopenharmony_ci {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, 3798c2ecf20Sopenharmony_ci}; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic const struct reg_value ov5640_setting_XGA_1024_768[] = { 3828c2ecf20Sopenharmony_ci {0x3c07, 0x08, 0, 0}, 3838c2ecf20Sopenharmony_ci {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 3848c2ecf20Sopenharmony_ci {0x3814, 0x31, 0, 0}, 3858c2ecf20Sopenharmony_ci {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, 3868c2ecf20Sopenharmony_ci {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, 3878c2ecf20Sopenharmony_ci {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, 3888c2ecf20Sopenharmony_ci {0x3810, 0x00, 0, 0}, 3898c2ecf20Sopenharmony_ci {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, 3908c2ecf20Sopenharmony_ci {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 3918c2ecf20Sopenharmony_ci {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 3928c2ecf20Sopenharmony_ci {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 3938c2ecf20Sopenharmony_ci {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 3948c2ecf20Sopenharmony_ci {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 3958c2ecf20Sopenharmony_ci {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 3968c2ecf20Sopenharmony_ci {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 3978c2ecf20Sopenharmony_ci {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, 3988c2ecf20Sopenharmony_ci}; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic const struct reg_value ov5640_setting_QVGA_320_240[] = { 4018c2ecf20Sopenharmony_ci {0x3c07, 0x08, 0, 0}, 4028c2ecf20Sopenharmony_ci {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 4038c2ecf20Sopenharmony_ci {0x3814, 0x31, 0, 0}, 4048c2ecf20Sopenharmony_ci {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, 4058c2ecf20Sopenharmony_ci {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, 4068c2ecf20Sopenharmony_ci {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, 4078c2ecf20Sopenharmony_ci {0x3810, 0x00, 0, 0}, 4088c2ecf20Sopenharmony_ci {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, 4098c2ecf20Sopenharmony_ci {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 4108c2ecf20Sopenharmony_ci {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 4118c2ecf20Sopenharmony_ci {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 4128c2ecf20Sopenharmony_ci {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 4138c2ecf20Sopenharmony_ci {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 4148c2ecf20Sopenharmony_ci {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 4158c2ecf20Sopenharmony_ci {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 4168c2ecf20Sopenharmony_ci {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, 4178c2ecf20Sopenharmony_ci}; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cistatic const struct reg_value ov5640_setting_QCIF_176_144[] = { 4208c2ecf20Sopenharmony_ci {0x3c07, 0x08, 0, 0}, 4218c2ecf20Sopenharmony_ci {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 4228c2ecf20Sopenharmony_ci {0x3814, 0x31, 0, 0}, 4238c2ecf20Sopenharmony_ci {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, 4248c2ecf20Sopenharmony_ci {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, 4258c2ecf20Sopenharmony_ci {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, 4268c2ecf20Sopenharmony_ci {0x3810, 0x00, 0, 0}, 4278c2ecf20Sopenharmony_ci {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, 4288c2ecf20Sopenharmony_ci {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 4298c2ecf20Sopenharmony_ci {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 4308c2ecf20Sopenharmony_ci {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 4318c2ecf20Sopenharmony_ci {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 4328c2ecf20Sopenharmony_ci {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 4338c2ecf20Sopenharmony_ci {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 4348c2ecf20Sopenharmony_ci {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 4358c2ecf20Sopenharmony_ci {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, 4368c2ecf20Sopenharmony_ci}; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic const struct reg_value ov5640_setting_NTSC_720_480[] = { 4398c2ecf20Sopenharmony_ci {0x3c07, 0x08, 0, 0}, 4408c2ecf20Sopenharmony_ci {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 4418c2ecf20Sopenharmony_ci {0x3814, 0x31, 0, 0}, 4428c2ecf20Sopenharmony_ci {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, 4438c2ecf20Sopenharmony_ci {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, 4448c2ecf20Sopenharmony_ci {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, 4458c2ecf20Sopenharmony_ci {0x3810, 0x00, 0, 0}, 4468c2ecf20Sopenharmony_ci {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0}, 4478c2ecf20Sopenharmony_ci {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 4488c2ecf20Sopenharmony_ci {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 4498c2ecf20Sopenharmony_ci {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 4508c2ecf20Sopenharmony_ci {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 4518c2ecf20Sopenharmony_ci {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 4528c2ecf20Sopenharmony_ci {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 4538c2ecf20Sopenharmony_ci {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 4548c2ecf20Sopenharmony_ci {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, 4558c2ecf20Sopenharmony_ci}; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cistatic const struct reg_value ov5640_setting_PAL_720_576[] = { 4588c2ecf20Sopenharmony_ci {0x3c07, 0x08, 0, 0}, 4598c2ecf20Sopenharmony_ci {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 4608c2ecf20Sopenharmony_ci {0x3814, 0x31, 0, 0}, 4618c2ecf20Sopenharmony_ci {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, 4628c2ecf20Sopenharmony_ci {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, 4638c2ecf20Sopenharmony_ci {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, 4648c2ecf20Sopenharmony_ci {0x3810, 0x00, 0, 0}, 4658c2ecf20Sopenharmony_ci {0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, 4668c2ecf20Sopenharmony_ci {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 4678c2ecf20Sopenharmony_ci {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 4688c2ecf20Sopenharmony_ci {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 4698c2ecf20Sopenharmony_ci {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 4708c2ecf20Sopenharmony_ci {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 4718c2ecf20Sopenharmony_ci {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 4728c2ecf20Sopenharmony_ci {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 4738c2ecf20Sopenharmony_ci {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, 4748c2ecf20Sopenharmony_ci}; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic const struct reg_value ov5640_setting_720P_1280_720[] = { 4778c2ecf20Sopenharmony_ci {0x3c07, 0x07, 0, 0}, 4788c2ecf20Sopenharmony_ci {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 4798c2ecf20Sopenharmony_ci {0x3814, 0x31, 0, 0}, 4808c2ecf20Sopenharmony_ci {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, 4818c2ecf20Sopenharmony_ci {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, 4828c2ecf20Sopenharmony_ci {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, 4838c2ecf20Sopenharmony_ci {0x3810, 0x00, 0, 0}, 4848c2ecf20Sopenharmony_ci {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, 4858c2ecf20Sopenharmony_ci {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 4868c2ecf20Sopenharmony_ci {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, 4878c2ecf20Sopenharmony_ci {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0}, 4888c2ecf20Sopenharmony_ci {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0}, 4898c2ecf20Sopenharmony_ci {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0}, 4908c2ecf20Sopenharmony_ci {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 4918c2ecf20Sopenharmony_ci {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, 4928c2ecf20Sopenharmony_ci {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, 4938c2ecf20Sopenharmony_ci}; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_cistatic const struct reg_value ov5640_setting_1080P_1920_1080[] = { 4968c2ecf20Sopenharmony_ci {0x3c07, 0x08, 0, 0}, 4978c2ecf20Sopenharmony_ci {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 4988c2ecf20Sopenharmony_ci {0x3814, 0x11, 0, 0}, 4998c2ecf20Sopenharmony_ci {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, 5008c2ecf20Sopenharmony_ci {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0}, 5018c2ecf20Sopenharmony_ci {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0}, 5028c2ecf20Sopenharmony_ci {0x3810, 0x00, 0, 0}, 5038c2ecf20Sopenharmony_ci {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, 5048c2ecf20Sopenharmony_ci {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, 5058c2ecf20Sopenharmony_ci {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, 5068c2ecf20Sopenharmony_ci {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 5078c2ecf20Sopenharmony_ci {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 5088c2ecf20Sopenharmony_ci {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 5098c2ecf20Sopenharmony_ci {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, 5108c2ecf20Sopenharmony_ci {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 5118c2ecf20Sopenharmony_ci {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, 5128c2ecf20Sopenharmony_ci {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0}, 5138c2ecf20Sopenharmony_ci {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 5148c2ecf20Sopenharmony_ci {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0}, 5158c2ecf20Sopenharmony_ci {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0}, 5168c2ecf20Sopenharmony_ci {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, 5178c2ecf20Sopenharmony_ci {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0}, 5188c2ecf20Sopenharmony_ci {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0}, 5198c2ecf20Sopenharmony_ci {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0}, 5208c2ecf20Sopenharmony_ci {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0}, 5218c2ecf20Sopenharmony_ci {0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0}, 5228c2ecf20Sopenharmony_ci {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0}, 5238c2ecf20Sopenharmony_ci {0x4005, 0x1a, 0, 0}, 5248c2ecf20Sopenharmony_ci}; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic const struct reg_value ov5640_setting_QSXGA_2592_1944[] = { 5278c2ecf20Sopenharmony_ci {0x3c07, 0x08, 0, 0}, 5288c2ecf20Sopenharmony_ci {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 5298c2ecf20Sopenharmony_ci {0x3814, 0x11, 0, 0}, 5308c2ecf20Sopenharmony_ci {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, 5318c2ecf20Sopenharmony_ci {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0}, 5328c2ecf20Sopenharmony_ci {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0}, 5338c2ecf20Sopenharmony_ci {0x3810, 0x00, 0, 0}, 5348c2ecf20Sopenharmony_ci {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, 5358c2ecf20Sopenharmony_ci {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, 5368c2ecf20Sopenharmony_ci {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, 5378c2ecf20Sopenharmony_ci {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 5388c2ecf20Sopenharmony_ci {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 5398c2ecf20Sopenharmony_ci {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 5408c2ecf20Sopenharmony_ci {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, 5418c2ecf20Sopenharmony_ci {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 5428c2ecf20Sopenharmony_ci {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70}, 5438c2ecf20Sopenharmony_ci}; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci/* power-on sensor init reg table */ 5468c2ecf20Sopenharmony_cistatic const struct ov5640_mode_info ov5640_mode_init_data = { 5478c2ecf20Sopenharmony_ci 0, SUBSAMPLING, 640, 1896, 480, 984, 5488c2ecf20Sopenharmony_ci ov5640_init_setting_30fps_VGA, 5498c2ecf20Sopenharmony_ci ARRAY_SIZE(ov5640_init_setting_30fps_VGA), 5508c2ecf20Sopenharmony_ci OV5640_30_FPS, 5518c2ecf20Sopenharmony_ci}; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic const struct ov5640_mode_info 5548c2ecf20Sopenharmony_ciov5640_mode_data[OV5640_NUM_MODES] = { 5558c2ecf20Sopenharmony_ci {OV5640_MODE_QCIF_176_144, SUBSAMPLING, 5568c2ecf20Sopenharmony_ci 176, 1896, 144, 984, 5578c2ecf20Sopenharmony_ci ov5640_setting_QCIF_176_144, 5588c2ecf20Sopenharmony_ci ARRAY_SIZE(ov5640_setting_QCIF_176_144), 5598c2ecf20Sopenharmony_ci OV5640_30_FPS}, 5608c2ecf20Sopenharmony_ci {OV5640_MODE_QVGA_320_240, SUBSAMPLING, 5618c2ecf20Sopenharmony_ci 320, 1896, 240, 984, 5628c2ecf20Sopenharmony_ci ov5640_setting_QVGA_320_240, 5638c2ecf20Sopenharmony_ci ARRAY_SIZE(ov5640_setting_QVGA_320_240), 5648c2ecf20Sopenharmony_ci OV5640_30_FPS}, 5658c2ecf20Sopenharmony_ci {OV5640_MODE_VGA_640_480, SUBSAMPLING, 5668c2ecf20Sopenharmony_ci 640, 1896, 480, 1080, 5678c2ecf20Sopenharmony_ci ov5640_setting_VGA_640_480, 5688c2ecf20Sopenharmony_ci ARRAY_SIZE(ov5640_setting_VGA_640_480), 5698c2ecf20Sopenharmony_ci OV5640_60_FPS}, 5708c2ecf20Sopenharmony_ci {OV5640_MODE_NTSC_720_480, SUBSAMPLING, 5718c2ecf20Sopenharmony_ci 720, 1896, 480, 984, 5728c2ecf20Sopenharmony_ci ov5640_setting_NTSC_720_480, 5738c2ecf20Sopenharmony_ci ARRAY_SIZE(ov5640_setting_NTSC_720_480), 5748c2ecf20Sopenharmony_ci OV5640_30_FPS}, 5758c2ecf20Sopenharmony_ci {OV5640_MODE_PAL_720_576, SUBSAMPLING, 5768c2ecf20Sopenharmony_ci 720, 1896, 576, 984, 5778c2ecf20Sopenharmony_ci ov5640_setting_PAL_720_576, 5788c2ecf20Sopenharmony_ci ARRAY_SIZE(ov5640_setting_PAL_720_576), 5798c2ecf20Sopenharmony_ci OV5640_30_FPS}, 5808c2ecf20Sopenharmony_ci {OV5640_MODE_XGA_1024_768, SUBSAMPLING, 5818c2ecf20Sopenharmony_ci 1024, 1896, 768, 1080, 5828c2ecf20Sopenharmony_ci ov5640_setting_XGA_1024_768, 5838c2ecf20Sopenharmony_ci ARRAY_SIZE(ov5640_setting_XGA_1024_768), 5848c2ecf20Sopenharmony_ci OV5640_30_FPS}, 5858c2ecf20Sopenharmony_ci {OV5640_MODE_720P_1280_720, SUBSAMPLING, 5868c2ecf20Sopenharmony_ci 1280, 1892, 720, 740, 5878c2ecf20Sopenharmony_ci ov5640_setting_720P_1280_720, 5888c2ecf20Sopenharmony_ci ARRAY_SIZE(ov5640_setting_720P_1280_720), 5898c2ecf20Sopenharmony_ci OV5640_30_FPS}, 5908c2ecf20Sopenharmony_ci {OV5640_MODE_1080P_1920_1080, SCALING, 5918c2ecf20Sopenharmony_ci 1920, 2500, 1080, 1120, 5928c2ecf20Sopenharmony_ci ov5640_setting_1080P_1920_1080, 5938c2ecf20Sopenharmony_ci ARRAY_SIZE(ov5640_setting_1080P_1920_1080), 5948c2ecf20Sopenharmony_ci OV5640_30_FPS}, 5958c2ecf20Sopenharmony_ci {OV5640_MODE_QSXGA_2592_1944, SCALING, 5968c2ecf20Sopenharmony_ci 2592, 2844, 1944, 1968, 5978c2ecf20Sopenharmony_ci ov5640_setting_QSXGA_2592_1944, 5988c2ecf20Sopenharmony_ci ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944), 5998c2ecf20Sopenharmony_ci OV5640_15_FPS}, 6008c2ecf20Sopenharmony_ci}; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_cistatic int ov5640_init_slave_id(struct ov5640_dev *sensor) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci struct i2c_client *client = sensor->i2c_client; 6058c2ecf20Sopenharmony_ci struct i2c_msg msg; 6068c2ecf20Sopenharmony_ci u8 buf[3]; 6078c2ecf20Sopenharmony_ci int ret; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (client->addr == OV5640_DEFAULT_SLAVE_ID) 6108c2ecf20Sopenharmony_ci return 0; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci buf[0] = OV5640_REG_SLAVE_ID >> 8; 6138c2ecf20Sopenharmony_ci buf[1] = OV5640_REG_SLAVE_ID & 0xff; 6148c2ecf20Sopenharmony_ci buf[2] = client->addr << 1; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci msg.addr = OV5640_DEFAULT_SLAVE_ID; 6178c2ecf20Sopenharmony_ci msg.flags = 0; 6188c2ecf20Sopenharmony_ci msg.buf = buf; 6198c2ecf20Sopenharmony_ci msg.len = sizeof(buf); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci ret = i2c_transfer(client->adapter, &msg, 1); 6228c2ecf20Sopenharmony_ci if (ret < 0) { 6238c2ecf20Sopenharmony_ci dev_err(&client->dev, "%s: failed with %d\n", __func__, ret); 6248c2ecf20Sopenharmony_ci return ret; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci return 0; 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_cistatic int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci struct i2c_client *client = sensor->i2c_client; 6338c2ecf20Sopenharmony_ci struct i2c_msg msg; 6348c2ecf20Sopenharmony_ci u8 buf[3]; 6358c2ecf20Sopenharmony_ci int ret; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci buf[0] = reg >> 8; 6388c2ecf20Sopenharmony_ci buf[1] = reg & 0xff; 6398c2ecf20Sopenharmony_ci buf[2] = val; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci msg.addr = client->addr; 6428c2ecf20Sopenharmony_ci msg.flags = client->flags; 6438c2ecf20Sopenharmony_ci msg.buf = buf; 6448c2ecf20Sopenharmony_ci msg.len = sizeof(buf); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci ret = i2c_transfer(client->adapter, &msg, 1); 6478c2ecf20Sopenharmony_ci if (ret < 0) { 6488c2ecf20Sopenharmony_ci dev_err(&client->dev, "%s: error: reg=%x, val=%x\n", 6498c2ecf20Sopenharmony_ci __func__, reg, val); 6508c2ecf20Sopenharmony_ci return ret; 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci return 0; 6548c2ecf20Sopenharmony_ci} 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_cistatic int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci struct i2c_client *client = sensor->i2c_client; 6598c2ecf20Sopenharmony_ci struct i2c_msg msg[2]; 6608c2ecf20Sopenharmony_ci u8 buf[2]; 6618c2ecf20Sopenharmony_ci int ret; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci buf[0] = reg >> 8; 6648c2ecf20Sopenharmony_ci buf[1] = reg & 0xff; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci msg[0].addr = client->addr; 6678c2ecf20Sopenharmony_ci msg[0].flags = client->flags; 6688c2ecf20Sopenharmony_ci msg[0].buf = buf; 6698c2ecf20Sopenharmony_ci msg[0].len = sizeof(buf); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci msg[1].addr = client->addr; 6728c2ecf20Sopenharmony_ci msg[1].flags = client->flags | I2C_M_RD; 6738c2ecf20Sopenharmony_ci msg[1].buf = buf; 6748c2ecf20Sopenharmony_ci msg[1].len = 1; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci ret = i2c_transfer(client->adapter, msg, 2); 6778c2ecf20Sopenharmony_ci if (ret < 0) { 6788c2ecf20Sopenharmony_ci dev_err(&client->dev, "%s: error: reg=%x\n", 6798c2ecf20Sopenharmony_ci __func__, reg); 6808c2ecf20Sopenharmony_ci return ret; 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci *val = buf[0]; 6848c2ecf20Sopenharmony_ci return 0; 6858c2ecf20Sopenharmony_ci} 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_cistatic int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val) 6888c2ecf20Sopenharmony_ci{ 6898c2ecf20Sopenharmony_ci u8 hi, lo; 6908c2ecf20Sopenharmony_ci int ret; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci ret = ov5640_read_reg(sensor, reg, &hi); 6938c2ecf20Sopenharmony_ci if (ret) 6948c2ecf20Sopenharmony_ci return ret; 6958c2ecf20Sopenharmony_ci ret = ov5640_read_reg(sensor, reg + 1, &lo); 6968c2ecf20Sopenharmony_ci if (ret) 6978c2ecf20Sopenharmony_ci return ret; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci *val = ((u16)hi << 8) | (u16)lo; 7008c2ecf20Sopenharmony_ci return 0; 7018c2ecf20Sopenharmony_ci} 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_cistatic int ov5640_write_reg16(struct ov5640_dev *sensor, u16 reg, u16 val) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci int ret; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci ret = ov5640_write_reg(sensor, reg, val >> 8); 7088c2ecf20Sopenharmony_ci if (ret) 7098c2ecf20Sopenharmony_ci return ret; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci return ov5640_write_reg(sensor, reg + 1, val & 0xff); 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_cistatic int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg, 7158c2ecf20Sopenharmony_ci u8 mask, u8 val) 7168c2ecf20Sopenharmony_ci{ 7178c2ecf20Sopenharmony_ci u8 readval; 7188c2ecf20Sopenharmony_ci int ret; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci ret = ov5640_read_reg(sensor, reg, &readval); 7218c2ecf20Sopenharmony_ci if (ret) 7228c2ecf20Sopenharmony_ci return ret; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci readval &= ~mask; 7258c2ecf20Sopenharmony_ci val &= mask; 7268c2ecf20Sopenharmony_ci val |= readval; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci return ov5640_write_reg(sensor, reg, val); 7298c2ecf20Sopenharmony_ci} 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci/* 7328c2ecf20Sopenharmony_ci * After trying the various combinations, reading various 7338c2ecf20Sopenharmony_ci * documentations spread around the net, and from the various 7348c2ecf20Sopenharmony_ci * feedback, the clock tree is probably as follows: 7358c2ecf20Sopenharmony_ci * 7368c2ecf20Sopenharmony_ci * +--------------+ 7378c2ecf20Sopenharmony_ci * | Ext. Clock | 7388c2ecf20Sopenharmony_ci * +-+------------+ 7398c2ecf20Sopenharmony_ci * | +----------+ 7408c2ecf20Sopenharmony_ci * +->| PLL1 | - reg 0x3036, for the multiplier 7418c2ecf20Sopenharmony_ci * +-+--------+ - reg 0x3037, bits 0-3 for the pre-divider 7428c2ecf20Sopenharmony_ci * | +--------------+ 7438c2ecf20Sopenharmony_ci * +->| System Clock | - reg 0x3035, bits 4-7 7448c2ecf20Sopenharmony_ci * +-+------------+ 7458c2ecf20Sopenharmony_ci * | +--------------+ 7468c2ecf20Sopenharmony_ci * +->| MIPI Divider | - reg 0x3035, bits 0-3 7478c2ecf20Sopenharmony_ci * | +-+------------+ 7488c2ecf20Sopenharmony_ci * | +----------------> MIPI SCLK 7498c2ecf20Sopenharmony_ci * | + +-----+ 7508c2ecf20Sopenharmony_ci * | +->| / 2 |-------> MIPI BIT CLK 7518c2ecf20Sopenharmony_ci * | +-----+ 7528c2ecf20Sopenharmony_ci * | +--------------+ 7538c2ecf20Sopenharmony_ci * +->| PLL Root Div | - reg 0x3037, bit 4 7548c2ecf20Sopenharmony_ci * +-+------------+ 7558c2ecf20Sopenharmony_ci * | +---------+ 7568c2ecf20Sopenharmony_ci * +->| Bit Div | - reg 0x3034, bits 0-3 7578c2ecf20Sopenharmony_ci * +-+-------+ 7588c2ecf20Sopenharmony_ci * | +-------------+ 7598c2ecf20Sopenharmony_ci * +->| SCLK Div | - reg 0x3108, bits 0-1 7608c2ecf20Sopenharmony_ci * | +-+-----------+ 7618c2ecf20Sopenharmony_ci * | +---------------> SCLK 7628c2ecf20Sopenharmony_ci * | +-------------+ 7638c2ecf20Sopenharmony_ci * +->| SCLK 2X Div | - reg 0x3108, bits 2-3 7648c2ecf20Sopenharmony_ci * | +-+-----------+ 7658c2ecf20Sopenharmony_ci * | +---------------> SCLK 2X 7668c2ecf20Sopenharmony_ci * | +-------------+ 7678c2ecf20Sopenharmony_ci * +->| PCLK Div | - reg 0x3108, bits 4-5 7688c2ecf20Sopenharmony_ci * ++------------+ 7698c2ecf20Sopenharmony_ci * + +-----------+ 7708c2ecf20Sopenharmony_ci * +->| P_DIV | - reg 0x3035, bits 0-3 7718c2ecf20Sopenharmony_ci * +-----+-----+ 7728c2ecf20Sopenharmony_ci * +------------> PCLK 7738c2ecf20Sopenharmony_ci * 7748c2ecf20Sopenharmony_ci * This is deviating from the datasheet at least for the register 7758c2ecf20Sopenharmony_ci * 0x3108, since it's said here that the PCLK would be clocked from 7768c2ecf20Sopenharmony_ci * the PLL. 7778c2ecf20Sopenharmony_ci * 7788c2ecf20Sopenharmony_ci * There seems to be also (unverified) constraints: 7798c2ecf20Sopenharmony_ci * - the PLL pre-divider output rate should be in the 4-27MHz range 7808c2ecf20Sopenharmony_ci * - the PLL multiplier output rate should be in the 500-1000MHz range 7818c2ecf20Sopenharmony_ci * - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG 7828c2ecf20Sopenharmony_ci * 7838c2ecf20Sopenharmony_ci * In the two latter cases, these constraints are met since our 7848c2ecf20Sopenharmony_ci * factors are hardcoded. If we were to change that, we would need to 7858c2ecf20Sopenharmony_ci * take this into account. The only varying parts are the PLL 7868c2ecf20Sopenharmony_ci * multiplier and the system clock divider, which are shared between 7878c2ecf20Sopenharmony_ci * all these clocks so won't cause any issue. 7888c2ecf20Sopenharmony_ci */ 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci/* 7918c2ecf20Sopenharmony_ci * This is supposed to be ranging from 1 to 8, but the value is always 7928c2ecf20Sopenharmony_ci * set to 3 in the vendor kernels. 7938c2ecf20Sopenharmony_ci */ 7948c2ecf20Sopenharmony_ci#define OV5640_PLL_PREDIV 3 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci#define OV5640_PLL_MULT_MIN 4 7978c2ecf20Sopenharmony_ci#define OV5640_PLL_MULT_MAX 252 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci/* 8008c2ecf20Sopenharmony_ci * This is supposed to be ranging from 1 to 16, but the value is 8018c2ecf20Sopenharmony_ci * always set to either 1 or 2 in the vendor kernels. 8028c2ecf20Sopenharmony_ci */ 8038c2ecf20Sopenharmony_ci#define OV5640_SYSDIV_MIN 1 8048c2ecf20Sopenharmony_ci#define OV5640_SYSDIV_MAX 16 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci/* 8078c2ecf20Sopenharmony_ci * Hardcode these values for scaler and non-scaler modes. 8088c2ecf20Sopenharmony_ci * FIXME: to be re-calcualted for 1 data lanes setups 8098c2ecf20Sopenharmony_ci */ 8108c2ecf20Sopenharmony_ci#define OV5640_MIPI_DIV_PCLK 2 8118c2ecf20Sopenharmony_ci#define OV5640_MIPI_DIV_SCLK 1 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci/* 8148c2ecf20Sopenharmony_ci * This is supposed to be ranging from 1 to 2, but the value is always 8158c2ecf20Sopenharmony_ci * set to 2 in the vendor kernels. 8168c2ecf20Sopenharmony_ci */ 8178c2ecf20Sopenharmony_ci#define OV5640_PLL_ROOT_DIV 2 8188c2ecf20Sopenharmony_ci#define OV5640_PLL_CTRL3_PLL_ROOT_DIV_2 BIT(4) 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci/* 8218c2ecf20Sopenharmony_ci * We only supports 8-bit formats at the moment 8228c2ecf20Sopenharmony_ci */ 8238c2ecf20Sopenharmony_ci#define OV5640_BIT_DIV 2 8248c2ecf20Sopenharmony_ci#define OV5640_PLL_CTRL0_MIPI_MODE_8BIT 0x08 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci/* 8278c2ecf20Sopenharmony_ci * This is supposed to be ranging from 1 to 8, but the value is always 8288c2ecf20Sopenharmony_ci * set to 2 in the vendor kernels. 8298c2ecf20Sopenharmony_ci */ 8308c2ecf20Sopenharmony_ci#define OV5640_SCLK_ROOT_DIV 2 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci/* 8338c2ecf20Sopenharmony_ci * This is hardcoded so that the consistency is maintained between SCLK and 8348c2ecf20Sopenharmony_ci * SCLK 2x. 8358c2ecf20Sopenharmony_ci */ 8368c2ecf20Sopenharmony_ci#define OV5640_SCLK2X_ROOT_DIV (OV5640_SCLK_ROOT_DIV / 2) 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci/* 8398c2ecf20Sopenharmony_ci * This is supposed to be ranging from 1 to 8, but the value is always 8408c2ecf20Sopenharmony_ci * set to 1 in the vendor kernels. 8418c2ecf20Sopenharmony_ci */ 8428c2ecf20Sopenharmony_ci#define OV5640_PCLK_ROOT_DIV 1 8438c2ecf20Sopenharmony_ci#define OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS 0x00 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_cistatic unsigned long ov5640_compute_sys_clk(struct ov5640_dev *sensor, 8468c2ecf20Sopenharmony_ci u8 pll_prediv, u8 pll_mult, 8478c2ecf20Sopenharmony_ci u8 sysdiv) 8488c2ecf20Sopenharmony_ci{ 8498c2ecf20Sopenharmony_ci unsigned long sysclk = sensor->xclk_freq / pll_prediv * pll_mult; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci /* PLL1 output cannot exceed 1GHz. */ 8528c2ecf20Sopenharmony_ci if (sysclk / 1000000 > 1000) 8538c2ecf20Sopenharmony_ci return 0; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci return sysclk / sysdiv; 8568c2ecf20Sopenharmony_ci} 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_cistatic unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor, 8598c2ecf20Sopenharmony_ci unsigned long rate, 8608c2ecf20Sopenharmony_ci u8 *pll_prediv, u8 *pll_mult, 8618c2ecf20Sopenharmony_ci u8 *sysdiv) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci unsigned long best = ~0; 8648c2ecf20Sopenharmony_ci u8 best_sysdiv = 1, best_mult = 1; 8658c2ecf20Sopenharmony_ci u8 _sysdiv, _pll_mult; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci for (_sysdiv = OV5640_SYSDIV_MIN; 8688c2ecf20Sopenharmony_ci _sysdiv <= OV5640_SYSDIV_MAX; 8698c2ecf20Sopenharmony_ci _sysdiv++) { 8708c2ecf20Sopenharmony_ci for (_pll_mult = OV5640_PLL_MULT_MIN; 8718c2ecf20Sopenharmony_ci _pll_mult <= OV5640_PLL_MULT_MAX; 8728c2ecf20Sopenharmony_ci _pll_mult++) { 8738c2ecf20Sopenharmony_ci unsigned long _rate; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci /* 8768c2ecf20Sopenharmony_ci * The PLL multiplier cannot be odd if above 8778c2ecf20Sopenharmony_ci * 127. 8788c2ecf20Sopenharmony_ci */ 8798c2ecf20Sopenharmony_ci if (_pll_mult > 127 && (_pll_mult % 2)) 8808c2ecf20Sopenharmony_ci continue; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci _rate = ov5640_compute_sys_clk(sensor, 8838c2ecf20Sopenharmony_ci OV5640_PLL_PREDIV, 8848c2ecf20Sopenharmony_ci _pll_mult, _sysdiv); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci /* 8878c2ecf20Sopenharmony_ci * We have reached the maximum allowed PLL1 output, 8888c2ecf20Sopenharmony_ci * increase sysdiv. 8898c2ecf20Sopenharmony_ci */ 8908c2ecf20Sopenharmony_ci if (!_rate) 8918c2ecf20Sopenharmony_ci break; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci /* 8948c2ecf20Sopenharmony_ci * Prefer rates above the expected clock rate than 8958c2ecf20Sopenharmony_ci * below, even if that means being less precise. 8968c2ecf20Sopenharmony_ci */ 8978c2ecf20Sopenharmony_ci if (_rate < rate) 8988c2ecf20Sopenharmony_ci continue; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci if (abs(rate - _rate) < abs(rate - best)) { 9018c2ecf20Sopenharmony_ci best = _rate; 9028c2ecf20Sopenharmony_ci best_sysdiv = _sysdiv; 9038c2ecf20Sopenharmony_ci best_mult = _pll_mult; 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci if (_rate == rate) 9078c2ecf20Sopenharmony_ci goto out; 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci } 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ciout: 9128c2ecf20Sopenharmony_ci *sysdiv = best_sysdiv; 9138c2ecf20Sopenharmony_ci *pll_prediv = OV5640_PLL_PREDIV; 9148c2ecf20Sopenharmony_ci *pll_mult = best_mult; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci return best; 9178c2ecf20Sopenharmony_ci} 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci/* 9208c2ecf20Sopenharmony_ci * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values 9218c2ecf20Sopenharmony_ci * for the MIPI CSI-2 output. 9228c2ecf20Sopenharmony_ci * 9238c2ecf20Sopenharmony_ci * @rate: The requested bandwidth per lane in bytes per second. 9248c2ecf20Sopenharmony_ci * 'Bandwidth Per Lane' is calculated as: 9258c2ecf20Sopenharmony_ci * bpl = HTOT * VTOT * FPS * bpp / num_lanes; 9268c2ecf20Sopenharmony_ci * 9278c2ecf20Sopenharmony_ci * This function use the requested bandwidth to calculate: 9288c2ecf20Sopenharmony_ci * - sample_rate = bpl / (bpp / num_lanes); 9298c2ecf20Sopenharmony_ci * = bpl / (PLL_RDIV * BIT_DIV * PCLK_DIV * MIPI_DIV / num_lanes); 9308c2ecf20Sopenharmony_ci * 9318c2ecf20Sopenharmony_ci * - mipi_sclk = bpl / MIPI_DIV / 2; ( / 2 is for CSI-2 DDR) 9328c2ecf20Sopenharmony_ci * 9338c2ecf20Sopenharmony_ci * with these fixed parameters: 9348c2ecf20Sopenharmony_ci * PLL_RDIV = 2; 9358c2ecf20Sopenharmony_ci * BIT_DIVIDER = 2; (MIPI_BIT_MODE == 8 ? 2 : 2,5); 9368c2ecf20Sopenharmony_ci * PCLK_DIV = 1; 9378c2ecf20Sopenharmony_ci * 9388c2ecf20Sopenharmony_ci * The MIPI clock generation differs for modes that use the scaler and modes 9398c2ecf20Sopenharmony_ci * that do not. In case the scaler is in use, the MIPI_SCLK generates the MIPI 9408c2ecf20Sopenharmony_ci * BIT CLk, and thus: 9418c2ecf20Sopenharmony_ci * 9428c2ecf20Sopenharmony_ci * - mipi_sclk = bpl / MIPI_DIV / 2; 9438c2ecf20Sopenharmony_ci * MIPI_DIV = 1; 9448c2ecf20Sopenharmony_ci * 9458c2ecf20Sopenharmony_ci * For modes that do not go through the scaler, the MIPI BIT CLOCK is generated 9468c2ecf20Sopenharmony_ci * from the pixel clock, and thus: 9478c2ecf20Sopenharmony_ci * 9488c2ecf20Sopenharmony_ci * - sample_rate = bpl / (bpp / num_lanes); 9498c2ecf20Sopenharmony_ci * = bpl / (2 * 2 * 1 * MIPI_DIV / num_lanes); 9508c2ecf20Sopenharmony_ci * = bpl / (4 * MIPI_DIV / num_lanes); 9518c2ecf20Sopenharmony_ci * - MIPI_DIV = bpp / (4 * num_lanes); 9528c2ecf20Sopenharmony_ci * 9538c2ecf20Sopenharmony_ci * FIXME: this have been tested with 16bpp and 2 lanes setup only. 9548c2ecf20Sopenharmony_ci * MIPI_DIV is fixed to value 2, but it -might- be changed according to the 9558c2ecf20Sopenharmony_ci * above formula for setups with 1 lane or image formats with different bpp. 9568c2ecf20Sopenharmony_ci * 9578c2ecf20Sopenharmony_ci * FIXME: this deviates from the sensor manual documentation which is quite 9588c2ecf20Sopenharmony_ci * thin on the MIPI clock tree generation part. 9598c2ecf20Sopenharmony_ci */ 9608c2ecf20Sopenharmony_cistatic int ov5640_set_mipi_pclk(struct ov5640_dev *sensor, 9618c2ecf20Sopenharmony_ci unsigned long rate) 9628c2ecf20Sopenharmony_ci{ 9638c2ecf20Sopenharmony_ci const struct ov5640_mode_info *mode = sensor->current_mode; 9648c2ecf20Sopenharmony_ci u8 prediv, mult, sysdiv; 9658c2ecf20Sopenharmony_ci u8 mipi_div; 9668c2ecf20Sopenharmony_ci int ret; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci /* 9698c2ecf20Sopenharmony_ci * 1280x720 is reported to use 'SUBSAMPLING' only, 9708c2ecf20Sopenharmony_ci * but according to the sensor manual it goes through the 9718c2ecf20Sopenharmony_ci * scaler before subsampling. 9728c2ecf20Sopenharmony_ci */ 9738c2ecf20Sopenharmony_ci if (mode->dn_mode == SCALING || 9748c2ecf20Sopenharmony_ci (mode->id == OV5640_MODE_720P_1280_720)) 9758c2ecf20Sopenharmony_ci mipi_div = OV5640_MIPI_DIV_SCLK; 9768c2ecf20Sopenharmony_ci else 9778c2ecf20Sopenharmony_ci mipi_div = OV5640_MIPI_DIV_PCLK; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci ov5640_calc_sys_clk(sensor, rate, &prediv, &mult, &sysdiv); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 9828c2ecf20Sopenharmony_ci 0x0f, OV5640_PLL_CTRL0_MIPI_MODE_8BIT); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 9858c2ecf20Sopenharmony_ci 0xff, sysdiv << 4 | mipi_div); 9868c2ecf20Sopenharmony_ci if (ret) 9878c2ecf20Sopenharmony_ci return ret; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 0xff, mult); 9908c2ecf20Sopenharmony_ci if (ret) 9918c2ecf20Sopenharmony_ci return ret; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 9948c2ecf20Sopenharmony_ci 0x1f, OV5640_PLL_CTRL3_PLL_ROOT_DIV_2 | prediv); 9958c2ecf20Sopenharmony_ci if (ret) 9968c2ecf20Sopenharmony_ci return ret; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 9998c2ecf20Sopenharmony_ci 0x30, OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS); 10008c2ecf20Sopenharmony_ci} 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_cistatic unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor, 10038c2ecf20Sopenharmony_ci unsigned long rate, 10048c2ecf20Sopenharmony_ci u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv, 10058c2ecf20Sopenharmony_ci u8 *pll_rdiv, u8 *bit_div, u8 *pclk_div) 10068c2ecf20Sopenharmony_ci{ 10078c2ecf20Sopenharmony_ci unsigned long _rate = rate * OV5640_PLL_ROOT_DIV * OV5640_BIT_DIV * 10088c2ecf20Sopenharmony_ci OV5640_PCLK_ROOT_DIV; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci _rate = ov5640_calc_sys_clk(sensor, _rate, pll_prediv, pll_mult, 10118c2ecf20Sopenharmony_ci sysdiv); 10128c2ecf20Sopenharmony_ci *pll_rdiv = OV5640_PLL_ROOT_DIV; 10138c2ecf20Sopenharmony_ci *bit_div = OV5640_BIT_DIV; 10148c2ecf20Sopenharmony_ci *pclk_div = OV5640_PCLK_ROOT_DIV; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci return _rate / *pll_rdiv / *bit_div / *pclk_div; 10178c2ecf20Sopenharmony_ci} 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_cistatic int ov5640_set_dvp_pclk(struct ov5640_dev *sensor, unsigned long rate) 10208c2ecf20Sopenharmony_ci{ 10218c2ecf20Sopenharmony_ci u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div; 10228c2ecf20Sopenharmony_ci int ret; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv, 10258c2ecf20Sopenharmony_ci &bit_div, &pclk_div); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci if (bit_div == 2) 10288c2ecf20Sopenharmony_ci bit_div = 8; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 10318c2ecf20Sopenharmony_ci 0x0f, bit_div); 10328c2ecf20Sopenharmony_ci if (ret) 10338c2ecf20Sopenharmony_ci return ret; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci /* 10368c2ecf20Sopenharmony_ci * We need to set sysdiv according to the clock, and to clear 10378c2ecf20Sopenharmony_ci * the MIPI divider. 10388c2ecf20Sopenharmony_ci */ 10398c2ecf20Sopenharmony_ci ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 10408c2ecf20Sopenharmony_ci 0xff, sysdiv << 4); 10418c2ecf20Sopenharmony_ci if (ret) 10428c2ecf20Sopenharmony_ci return ret; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 10458c2ecf20Sopenharmony_ci 0xff, mult); 10468c2ecf20Sopenharmony_ci if (ret) 10478c2ecf20Sopenharmony_ci return ret; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 10508c2ecf20Sopenharmony_ci 0x1f, prediv | ((pll_rdiv - 1) << 4)); 10518c2ecf20Sopenharmony_ci if (ret) 10528c2ecf20Sopenharmony_ci return ret; 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x30, 10558c2ecf20Sopenharmony_ci (ilog2(pclk_div) << 4)); 10568c2ecf20Sopenharmony_ci} 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci/* set JPEG framing sizes */ 10598c2ecf20Sopenharmony_cistatic int ov5640_set_jpeg_timings(struct ov5640_dev *sensor, 10608c2ecf20Sopenharmony_ci const struct ov5640_mode_info *mode) 10618c2ecf20Sopenharmony_ci{ 10628c2ecf20Sopenharmony_ci int ret; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci /* 10658c2ecf20Sopenharmony_ci * compression mode 3 timing 10668c2ecf20Sopenharmony_ci * 10678c2ecf20Sopenharmony_ci * Data is transmitted with programmable width (VFIFO_HSIZE). 10688c2ecf20Sopenharmony_ci * No padding done. Last line may have less data. Varying 10698c2ecf20Sopenharmony_ci * number of lines per frame, depending on amount of data. 10708c2ecf20Sopenharmony_ci */ 10718c2ecf20Sopenharmony_ci ret = ov5640_mod_reg(sensor, OV5640_REG_JPG_MODE_SELECT, 0x7, 0x3); 10728c2ecf20Sopenharmony_ci if (ret < 0) 10738c2ecf20Sopenharmony_ci return ret; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->hact); 10768c2ecf20Sopenharmony_ci if (ret < 0) 10778c2ecf20Sopenharmony_ci return ret; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->vact); 10808c2ecf20Sopenharmony_ci} 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci/* download ov5640 settings to sensor through i2c */ 10838c2ecf20Sopenharmony_cistatic int ov5640_set_timings(struct ov5640_dev *sensor, 10848c2ecf20Sopenharmony_ci const struct ov5640_mode_info *mode) 10858c2ecf20Sopenharmony_ci{ 10868c2ecf20Sopenharmony_ci int ret; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) { 10898c2ecf20Sopenharmony_ci ret = ov5640_set_jpeg_timings(sensor, mode); 10908c2ecf20Sopenharmony_ci if (ret < 0) 10918c2ecf20Sopenharmony_ci return ret; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->hact); 10958c2ecf20Sopenharmony_ci if (ret < 0) 10968c2ecf20Sopenharmony_ci return ret; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->vact); 10998c2ecf20Sopenharmony_ci if (ret < 0) 11008c2ecf20Sopenharmony_ci return ret; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, mode->htot); 11038c2ecf20Sopenharmony_ci if (ret < 0) 11048c2ecf20Sopenharmony_ci return ret; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, mode->vtot); 11078c2ecf20Sopenharmony_ci} 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_cistatic int ov5640_load_regs(struct ov5640_dev *sensor, 11108c2ecf20Sopenharmony_ci const struct ov5640_mode_info *mode) 11118c2ecf20Sopenharmony_ci{ 11128c2ecf20Sopenharmony_ci const struct reg_value *regs = mode->reg_data; 11138c2ecf20Sopenharmony_ci unsigned int i; 11148c2ecf20Sopenharmony_ci u32 delay_ms; 11158c2ecf20Sopenharmony_ci u16 reg_addr; 11168c2ecf20Sopenharmony_ci u8 mask, val; 11178c2ecf20Sopenharmony_ci int ret = 0; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci for (i = 0; i < mode->reg_data_size; ++i, ++regs) { 11208c2ecf20Sopenharmony_ci delay_ms = regs->delay_ms; 11218c2ecf20Sopenharmony_ci reg_addr = regs->reg_addr; 11228c2ecf20Sopenharmony_ci val = regs->val; 11238c2ecf20Sopenharmony_ci mask = regs->mask; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci /* remain in power down mode for DVP */ 11268c2ecf20Sopenharmony_ci if (regs->reg_addr == OV5640_REG_SYS_CTRL0 && 11278c2ecf20Sopenharmony_ci val == OV5640_REG_SYS_CTRL0_SW_PWUP && 11288c2ecf20Sopenharmony_ci sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY) 11298c2ecf20Sopenharmony_ci continue; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci if (mask) 11328c2ecf20Sopenharmony_ci ret = ov5640_mod_reg(sensor, reg_addr, mask, val); 11338c2ecf20Sopenharmony_ci else 11348c2ecf20Sopenharmony_ci ret = ov5640_write_reg(sensor, reg_addr, val); 11358c2ecf20Sopenharmony_ci if (ret) 11368c2ecf20Sopenharmony_ci break; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci if (delay_ms) 11398c2ecf20Sopenharmony_ci usleep_range(1000 * delay_ms, 1000 * delay_ms + 100); 11408c2ecf20Sopenharmony_ci } 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci return ov5640_set_timings(sensor, mode); 11438c2ecf20Sopenharmony_ci} 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_cistatic int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on) 11468c2ecf20Sopenharmony_ci{ 11478c2ecf20Sopenharmony_ci return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL, 11488c2ecf20Sopenharmony_ci BIT(0), on ? 0 : BIT(0)); 11498c2ecf20Sopenharmony_ci} 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci/* read exposure, in number of line periods */ 11528c2ecf20Sopenharmony_cistatic int ov5640_get_exposure(struct ov5640_dev *sensor) 11538c2ecf20Sopenharmony_ci{ 11548c2ecf20Sopenharmony_ci int exp, ret; 11558c2ecf20Sopenharmony_ci u8 temp; 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_HI, &temp); 11588c2ecf20Sopenharmony_ci if (ret) 11598c2ecf20Sopenharmony_ci return ret; 11608c2ecf20Sopenharmony_ci exp = ((int)temp & 0x0f) << 16; 11618c2ecf20Sopenharmony_ci ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_MED, &temp); 11628c2ecf20Sopenharmony_ci if (ret) 11638c2ecf20Sopenharmony_ci return ret; 11648c2ecf20Sopenharmony_ci exp |= ((int)temp << 8); 11658c2ecf20Sopenharmony_ci ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_LO, &temp); 11668c2ecf20Sopenharmony_ci if (ret) 11678c2ecf20Sopenharmony_ci return ret; 11688c2ecf20Sopenharmony_ci exp |= (int)temp; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci return exp >> 4; 11718c2ecf20Sopenharmony_ci} 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci/* write exposure, given number of line periods */ 11748c2ecf20Sopenharmony_cistatic int ov5640_set_exposure(struct ov5640_dev *sensor, u32 exposure) 11758c2ecf20Sopenharmony_ci{ 11768c2ecf20Sopenharmony_ci int ret; 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci exposure <<= 4; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci ret = ov5640_write_reg(sensor, 11818c2ecf20Sopenharmony_ci OV5640_REG_AEC_PK_EXPOSURE_LO, 11828c2ecf20Sopenharmony_ci exposure & 0xff); 11838c2ecf20Sopenharmony_ci if (ret) 11848c2ecf20Sopenharmony_ci return ret; 11858c2ecf20Sopenharmony_ci ret = ov5640_write_reg(sensor, 11868c2ecf20Sopenharmony_ci OV5640_REG_AEC_PK_EXPOSURE_MED, 11878c2ecf20Sopenharmony_ci (exposure >> 8) & 0xff); 11888c2ecf20Sopenharmony_ci if (ret) 11898c2ecf20Sopenharmony_ci return ret; 11908c2ecf20Sopenharmony_ci return ov5640_write_reg(sensor, 11918c2ecf20Sopenharmony_ci OV5640_REG_AEC_PK_EXPOSURE_HI, 11928c2ecf20Sopenharmony_ci (exposure >> 16) & 0x0f); 11938c2ecf20Sopenharmony_ci} 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_cistatic int ov5640_get_gain(struct ov5640_dev *sensor) 11968c2ecf20Sopenharmony_ci{ 11978c2ecf20Sopenharmony_ci u16 gain; 11988c2ecf20Sopenharmony_ci int ret; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, &gain); 12018c2ecf20Sopenharmony_ci if (ret) 12028c2ecf20Sopenharmony_ci return ret; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci return gain & 0x3ff; 12058c2ecf20Sopenharmony_ci} 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_cistatic int ov5640_set_gain(struct ov5640_dev *sensor, int gain) 12088c2ecf20Sopenharmony_ci{ 12098c2ecf20Sopenharmony_ci return ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, 12108c2ecf20Sopenharmony_ci (u16)gain & 0x3ff); 12118c2ecf20Sopenharmony_ci} 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_cistatic int ov5640_set_autogain(struct ov5640_dev *sensor, bool on) 12148c2ecf20Sopenharmony_ci{ 12158c2ecf20Sopenharmony_ci return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL, 12168c2ecf20Sopenharmony_ci BIT(1), on ? 0 : BIT(1)); 12178c2ecf20Sopenharmony_ci} 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_cistatic int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on) 12208c2ecf20Sopenharmony_ci{ 12218c2ecf20Sopenharmony_ci return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ? 12228c2ecf20Sopenharmony_ci OV5640_REG_SYS_CTRL0_SW_PWUP : 12238c2ecf20Sopenharmony_ci OV5640_REG_SYS_CTRL0_SW_PWDN); 12248c2ecf20Sopenharmony_ci} 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_cistatic int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on) 12278c2ecf20Sopenharmony_ci{ 12288c2ecf20Sopenharmony_ci int ret; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci /* 12318c2ecf20Sopenharmony_ci * Enable/disable the MIPI interface 12328c2ecf20Sopenharmony_ci * 12338c2ecf20Sopenharmony_ci * 0x300e = on ? 0x45 : 0x40 12348c2ecf20Sopenharmony_ci * 12358c2ecf20Sopenharmony_ci * FIXME: the sensor manual (version 2.03) reports 12368c2ecf20Sopenharmony_ci * [7:5] = 000 : 1 data lane mode 12378c2ecf20Sopenharmony_ci * [7:5] = 001 : 2 data lanes mode 12388c2ecf20Sopenharmony_ci * But this settings do not work, while the following ones 12398c2ecf20Sopenharmony_ci * have been validated for 2 data lanes mode. 12408c2ecf20Sopenharmony_ci * 12418c2ecf20Sopenharmony_ci * [7:5] = 010 : 2 data lanes mode 12428c2ecf20Sopenharmony_ci * [4] = 0 : Power up MIPI HS Tx 12438c2ecf20Sopenharmony_ci * [3] = 0 : Power up MIPI LS Rx 12448c2ecf20Sopenharmony_ci * [2] = 1/0 : MIPI interface enable/disable 12458c2ecf20Sopenharmony_ci * [1:0] = 01/00: FIXME: 'debug' 12468c2ecf20Sopenharmony_ci */ 12478c2ecf20Sopenharmony_ci ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 12488c2ecf20Sopenharmony_ci on ? 0x45 : 0x40); 12498c2ecf20Sopenharmony_ci if (ret) 12508c2ecf20Sopenharmony_ci return ret; 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci return ov5640_write_reg(sensor, OV5640_REG_FRAME_CTRL01, 12538c2ecf20Sopenharmony_ci on ? 0x00 : 0x0f); 12548c2ecf20Sopenharmony_ci} 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_cistatic int ov5640_get_sysclk(struct ov5640_dev *sensor) 12578c2ecf20Sopenharmony_ci{ 12588c2ecf20Sopenharmony_ci /* calculate sysclk */ 12598c2ecf20Sopenharmony_ci u32 xvclk = sensor->xclk_freq / 10000; 12608c2ecf20Sopenharmony_ci u32 multiplier, prediv, VCO, sysdiv, pll_rdiv; 12618c2ecf20Sopenharmony_ci u32 sclk_rdiv_map[] = {1, 2, 4, 8}; 12628c2ecf20Sopenharmony_ci u32 bit_div2x = 1, sclk_rdiv, sysclk; 12638c2ecf20Sopenharmony_ci u8 temp1, temp2; 12648c2ecf20Sopenharmony_ci int ret; 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL0, &temp1); 12678c2ecf20Sopenharmony_ci if (ret) 12688c2ecf20Sopenharmony_ci return ret; 12698c2ecf20Sopenharmony_ci temp2 = temp1 & 0x0f; 12708c2ecf20Sopenharmony_ci if (temp2 == 8 || temp2 == 10) 12718c2ecf20Sopenharmony_ci bit_div2x = temp2 / 2; 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL1, &temp1); 12748c2ecf20Sopenharmony_ci if (ret) 12758c2ecf20Sopenharmony_ci return ret; 12768c2ecf20Sopenharmony_ci sysdiv = temp1 >> 4; 12778c2ecf20Sopenharmony_ci if (sysdiv == 0) 12788c2ecf20Sopenharmony_ci sysdiv = 16; 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL2, &temp1); 12818c2ecf20Sopenharmony_ci if (ret) 12828c2ecf20Sopenharmony_ci return ret; 12838c2ecf20Sopenharmony_ci multiplier = temp1; 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL3, &temp1); 12868c2ecf20Sopenharmony_ci if (ret) 12878c2ecf20Sopenharmony_ci return ret; 12888c2ecf20Sopenharmony_ci prediv = temp1 & 0x0f; 12898c2ecf20Sopenharmony_ci pll_rdiv = ((temp1 >> 4) & 0x01) + 1; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci ret = ov5640_read_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, &temp1); 12928c2ecf20Sopenharmony_ci if (ret) 12938c2ecf20Sopenharmony_ci return ret; 12948c2ecf20Sopenharmony_ci temp2 = temp1 & 0x03; 12958c2ecf20Sopenharmony_ci sclk_rdiv = sclk_rdiv_map[temp2]; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci if (!prediv || !sysdiv || !pll_rdiv || !bit_div2x) 12988c2ecf20Sopenharmony_ci return -EINVAL; 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci VCO = xvclk * multiplier / prediv; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci sysclk = VCO / sysdiv / pll_rdiv * 2 / bit_div2x / sclk_rdiv; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci return sysclk; 13058c2ecf20Sopenharmony_ci} 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_cistatic int ov5640_set_night_mode(struct ov5640_dev *sensor) 13088c2ecf20Sopenharmony_ci{ 13098c2ecf20Sopenharmony_ci /* read HTS from register settings */ 13108c2ecf20Sopenharmony_ci u8 mode; 13118c2ecf20Sopenharmony_ci int ret; 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci ret = ov5640_read_reg(sensor, OV5640_REG_AEC_CTRL00, &mode); 13148c2ecf20Sopenharmony_ci if (ret) 13158c2ecf20Sopenharmony_ci return ret; 13168c2ecf20Sopenharmony_ci mode &= 0xfb; 13178c2ecf20Sopenharmony_ci return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL00, mode); 13188c2ecf20Sopenharmony_ci} 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_cistatic int ov5640_get_hts(struct ov5640_dev *sensor) 13218c2ecf20Sopenharmony_ci{ 13228c2ecf20Sopenharmony_ci /* read HTS from register settings */ 13238c2ecf20Sopenharmony_ci u16 hts; 13248c2ecf20Sopenharmony_ci int ret; 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_HTS, &hts); 13278c2ecf20Sopenharmony_ci if (ret) 13288c2ecf20Sopenharmony_ci return ret; 13298c2ecf20Sopenharmony_ci return hts; 13308c2ecf20Sopenharmony_ci} 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_cistatic int ov5640_get_vts(struct ov5640_dev *sensor) 13338c2ecf20Sopenharmony_ci{ 13348c2ecf20Sopenharmony_ci u16 vts; 13358c2ecf20Sopenharmony_ci int ret; 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_VTS, &vts); 13388c2ecf20Sopenharmony_ci if (ret) 13398c2ecf20Sopenharmony_ci return ret; 13408c2ecf20Sopenharmony_ci return vts; 13418c2ecf20Sopenharmony_ci} 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_cistatic int ov5640_set_vts(struct ov5640_dev *sensor, int vts) 13448c2ecf20Sopenharmony_ci{ 13458c2ecf20Sopenharmony_ci return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, vts); 13468c2ecf20Sopenharmony_ci} 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_cistatic int ov5640_get_light_freq(struct ov5640_dev *sensor) 13498c2ecf20Sopenharmony_ci{ 13508c2ecf20Sopenharmony_ci /* get banding filter value */ 13518c2ecf20Sopenharmony_ci int ret, light_freq = 0; 13528c2ecf20Sopenharmony_ci u8 temp, temp1; 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL01, &temp); 13558c2ecf20Sopenharmony_ci if (ret) 13568c2ecf20Sopenharmony_ci return ret; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci if (temp & 0x80) { 13598c2ecf20Sopenharmony_ci /* manual */ 13608c2ecf20Sopenharmony_ci ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL00, 13618c2ecf20Sopenharmony_ci &temp1); 13628c2ecf20Sopenharmony_ci if (ret) 13638c2ecf20Sopenharmony_ci return ret; 13648c2ecf20Sopenharmony_ci if (temp1 & 0x04) { 13658c2ecf20Sopenharmony_ci /* 50Hz */ 13668c2ecf20Sopenharmony_ci light_freq = 50; 13678c2ecf20Sopenharmony_ci } else { 13688c2ecf20Sopenharmony_ci /* 60Hz */ 13698c2ecf20Sopenharmony_ci light_freq = 60; 13708c2ecf20Sopenharmony_ci } 13718c2ecf20Sopenharmony_ci } else { 13728c2ecf20Sopenharmony_ci /* auto */ 13738c2ecf20Sopenharmony_ci ret = ov5640_read_reg(sensor, OV5640_REG_SIGMADELTA_CTRL0C, 13748c2ecf20Sopenharmony_ci &temp1); 13758c2ecf20Sopenharmony_ci if (ret) 13768c2ecf20Sopenharmony_ci return ret; 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci if (temp1 & 0x01) { 13798c2ecf20Sopenharmony_ci /* 50Hz */ 13808c2ecf20Sopenharmony_ci light_freq = 50; 13818c2ecf20Sopenharmony_ci } else { 13828c2ecf20Sopenharmony_ci /* 60Hz */ 13838c2ecf20Sopenharmony_ci } 13848c2ecf20Sopenharmony_ci } 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci return light_freq; 13878c2ecf20Sopenharmony_ci} 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_cistatic int ov5640_set_bandingfilter(struct ov5640_dev *sensor) 13908c2ecf20Sopenharmony_ci{ 13918c2ecf20Sopenharmony_ci u32 band_step60, max_band60, band_step50, max_band50, prev_vts; 13928c2ecf20Sopenharmony_ci int ret; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci /* read preview PCLK */ 13958c2ecf20Sopenharmony_ci ret = ov5640_get_sysclk(sensor); 13968c2ecf20Sopenharmony_ci if (ret < 0) 13978c2ecf20Sopenharmony_ci return ret; 13988c2ecf20Sopenharmony_ci if (ret == 0) 13998c2ecf20Sopenharmony_ci return -EINVAL; 14008c2ecf20Sopenharmony_ci sensor->prev_sysclk = ret; 14018c2ecf20Sopenharmony_ci /* read preview HTS */ 14028c2ecf20Sopenharmony_ci ret = ov5640_get_hts(sensor); 14038c2ecf20Sopenharmony_ci if (ret < 0) 14048c2ecf20Sopenharmony_ci return ret; 14058c2ecf20Sopenharmony_ci if (ret == 0) 14068c2ecf20Sopenharmony_ci return -EINVAL; 14078c2ecf20Sopenharmony_ci sensor->prev_hts = ret; 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci /* read preview VTS */ 14108c2ecf20Sopenharmony_ci ret = ov5640_get_vts(sensor); 14118c2ecf20Sopenharmony_ci if (ret < 0) 14128c2ecf20Sopenharmony_ci return ret; 14138c2ecf20Sopenharmony_ci prev_vts = ret; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci /* calculate banding filter */ 14168c2ecf20Sopenharmony_ci /* 60Hz */ 14178c2ecf20Sopenharmony_ci band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100 / 120; 14188c2ecf20Sopenharmony_ci ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B60_STEP, band_step60); 14198c2ecf20Sopenharmony_ci if (ret) 14208c2ecf20Sopenharmony_ci return ret; 14218c2ecf20Sopenharmony_ci if (!band_step60) 14228c2ecf20Sopenharmony_ci return -EINVAL; 14238c2ecf20Sopenharmony_ci max_band60 = (int)((prev_vts - 4) / band_step60); 14248c2ecf20Sopenharmony_ci ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0D, max_band60); 14258c2ecf20Sopenharmony_ci if (ret) 14268c2ecf20Sopenharmony_ci return ret; 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci /* 50Hz */ 14298c2ecf20Sopenharmony_ci band_step50 = sensor->prev_sysclk * 100 / sensor->prev_hts; 14308c2ecf20Sopenharmony_ci ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B50_STEP, band_step50); 14318c2ecf20Sopenharmony_ci if (ret) 14328c2ecf20Sopenharmony_ci return ret; 14338c2ecf20Sopenharmony_ci if (!band_step50) 14348c2ecf20Sopenharmony_ci return -EINVAL; 14358c2ecf20Sopenharmony_ci max_band50 = (int)((prev_vts - 4) / band_step50); 14368c2ecf20Sopenharmony_ci return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0E, max_band50); 14378c2ecf20Sopenharmony_ci} 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_cistatic int ov5640_set_ae_target(struct ov5640_dev *sensor, int target) 14408c2ecf20Sopenharmony_ci{ 14418c2ecf20Sopenharmony_ci /* stable in high */ 14428c2ecf20Sopenharmony_ci u32 fast_high, fast_low; 14438c2ecf20Sopenharmony_ci int ret; 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci sensor->ae_low = target * 23 / 25; /* 0.92 */ 14468c2ecf20Sopenharmony_ci sensor->ae_high = target * 27 / 25; /* 1.08 */ 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci fast_high = sensor->ae_high << 1; 14498c2ecf20Sopenharmony_ci if (fast_high > 255) 14508c2ecf20Sopenharmony_ci fast_high = 255; 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci fast_low = sensor->ae_low >> 1; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0F, sensor->ae_high); 14558c2ecf20Sopenharmony_ci if (ret) 14568c2ecf20Sopenharmony_ci return ret; 14578c2ecf20Sopenharmony_ci ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL10, sensor->ae_low); 14588c2ecf20Sopenharmony_ci if (ret) 14598c2ecf20Sopenharmony_ci return ret; 14608c2ecf20Sopenharmony_ci ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1B, sensor->ae_high); 14618c2ecf20Sopenharmony_ci if (ret) 14628c2ecf20Sopenharmony_ci return ret; 14638c2ecf20Sopenharmony_ci ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1E, sensor->ae_low); 14648c2ecf20Sopenharmony_ci if (ret) 14658c2ecf20Sopenharmony_ci return ret; 14668c2ecf20Sopenharmony_ci ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL11, fast_high); 14678c2ecf20Sopenharmony_ci if (ret) 14688c2ecf20Sopenharmony_ci return ret; 14698c2ecf20Sopenharmony_ci return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1F, fast_low); 14708c2ecf20Sopenharmony_ci} 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_cistatic int ov5640_get_binning(struct ov5640_dev *sensor) 14738c2ecf20Sopenharmony_ci{ 14748c2ecf20Sopenharmony_ci u8 temp; 14758c2ecf20Sopenharmony_ci int ret; 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci ret = ov5640_read_reg(sensor, OV5640_REG_TIMING_TC_REG21, &temp); 14788c2ecf20Sopenharmony_ci if (ret) 14798c2ecf20Sopenharmony_ci return ret; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci return temp & BIT(0); 14828c2ecf20Sopenharmony_ci} 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_cistatic int ov5640_set_binning(struct ov5640_dev *sensor, bool enable) 14858c2ecf20Sopenharmony_ci{ 14868c2ecf20Sopenharmony_ci int ret; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci /* 14898c2ecf20Sopenharmony_ci * TIMING TC REG21: 14908c2ecf20Sopenharmony_ci * - [0]: Horizontal binning enable 14918c2ecf20Sopenharmony_ci */ 14928c2ecf20Sopenharmony_ci ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21, 14938c2ecf20Sopenharmony_ci BIT(0), enable ? BIT(0) : 0); 14948c2ecf20Sopenharmony_ci if (ret) 14958c2ecf20Sopenharmony_ci return ret; 14968c2ecf20Sopenharmony_ci /* 14978c2ecf20Sopenharmony_ci * TIMING TC REG20: 14988c2ecf20Sopenharmony_ci * - [0]: Undocumented, but hardcoded init sequences 14998c2ecf20Sopenharmony_ci * are always setting REG21/REG20 bit 0 to same value... 15008c2ecf20Sopenharmony_ci */ 15018c2ecf20Sopenharmony_ci return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20, 15028c2ecf20Sopenharmony_ci BIT(0), enable ? BIT(0) : 0); 15038c2ecf20Sopenharmony_ci} 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_cistatic int ov5640_set_virtual_channel(struct ov5640_dev *sensor) 15068c2ecf20Sopenharmony_ci{ 15078c2ecf20Sopenharmony_ci struct i2c_client *client = sensor->i2c_client; 15088c2ecf20Sopenharmony_ci u8 temp, channel = virtual_channel; 15098c2ecf20Sopenharmony_ci int ret; 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci if (channel > 3) { 15128c2ecf20Sopenharmony_ci dev_err(&client->dev, 15138c2ecf20Sopenharmony_ci "%s: wrong virtual_channel parameter, expected (0..3), got %d\n", 15148c2ecf20Sopenharmony_ci __func__, channel); 15158c2ecf20Sopenharmony_ci return -EINVAL; 15168c2ecf20Sopenharmony_ci } 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci ret = ov5640_read_reg(sensor, OV5640_REG_DEBUG_MODE, &temp); 15198c2ecf20Sopenharmony_ci if (ret) 15208c2ecf20Sopenharmony_ci return ret; 15218c2ecf20Sopenharmony_ci temp &= ~(3 << 6); 15228c2ecf20Sopenharmony_ci temp |= (channel << 6); 15238c2ecf20Sopenharmony_ci return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp); 15248c2ecf20Sopenharmony_ci} 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_cistatic const struct ov5640_mode_info * 15278c2ecf20Sopenharmony_ciov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr, 15288c2ecf20Sopenharmony_ci int width, int height, bool nearest) 15298c2ecf20Sopenharmony_ci{ 15308c2ecf20Sopenharmony_ci const struct ov5640_mode_info *mode; 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci mode = v4l2_find_nearest_size(ov5640_mode_data, 15338c2ecf20Sopenharmony_ci ARRAY_SIZE(ov5640_mode_data), 15348c2ecf20Sopenharmony_ci hact, vact, 15358c2ecf20Sopenharmony_ci width, height); 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci if (!mode || 15388c2ecf20Sopenharmony_ci (!nearest && (mode->hact != width || mode->vact != height))) 15398c2ecf20Sopenharmony_ci return NULL; 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci /* Check to see if the current mode exceeds the max frame rate */ 15428c2ecf20Sopenharmony_ci if (ov5640_framerates[fr] > ov5640_framerates[mode->max_fps]) 15438c2ecf20Sopenharmony_ci return NULL; 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci return mode; 15468c2ecf20Sopenharmony_ci} 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_cistatic u64 ov5640_calc_pixel_rate(struct ov5640_dev *sensor) 15498c2ecf20Sopenharmony_ci{ 15508c2ecf20Sopenharmony_ci u64 rate; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci rate = sensor->current_mode->vtot * sensor->current_mode->htot; 15538c2ecf20Sopenharmony_ci rate *= ov5640_framerates[sensor->current_fr]; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci return rate; 15568c2ecf20Sopenharmony_ci} 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci/* 15598c2ecf20Sopenharmony_ci * sensor changes between scaling and subsampling, go through 15608c2ecf20Sopenharmony_ci * exposure calculation 15618c2ecf20Sopenharmony_ci */ 15628c2ecf20Sopenharmony_cistatic int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor, 15638c2ecf20Sopenharmony_ci const struct ov5640_mode_info *mode) 15648c2ecf20Sopenharmony_ci{ 15658c2ecf20Sopenharmony_ci u32 prev_shutter, prev_gain16; 15668c2ecf20Sopenharmony_ci u32 cap_shutter, cap_gain16; 15678c2ecf20Sopenharmony_ci u32 cap_sysclk, cap_hts, cap_vts; 15688c2ecf20Sopenharmony_ci u32 light_freq, cap_bandfilt, cap_maxband; 15698c2ecf20Sopenharmony_ci u32 cap_gain16_shutter; 15708c2ecf20Sopenharmony_ci u8 average; 15718c2ecf20Sopenharmony_ci int ret; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci if (!mode->reg_data) 15748c2ecf20Sopenharmony_ci return -EINVAL; 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci /* read preview shutter */ 15778c2ecf20Sopenharmony_ci ret = ov5640_get_exposure(sensor); 15788c2ecf20Sopenharmony_ci if (ret < 0) 15798c2ecf20Sopenharmony_ci return ret; 15808c2ecf20Sopenharmony_ci prev_shutter = ret; 15818c2ecf20Sopenharmony_ci ret = ov5640_get_binning(sensor); 15828c2ecf20Sopenharmony_ci if (ret < 0) 15838c2ecf20Sopenharmony_ci return ret; 15848c2ecf20Sopenharmony_ci if (ret && mode->id != OV5640_MODE_720P_1280_720 && 15858c2ecf20Sopenharmony_ci mode->id != OV5640_MODE_1080P_1920_1080) 15868c2ecf20Sopenharmony_ci prev_shutter *= 2; 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci /* read preview gain */ 15898c2ecf20Sopenharmony_ci ret = ov5640_get_gain(sensor); 15908c2ecf20Sopenharmony_ci if (ret < 0) 15918c2ecf20Sopenharmony_ci return ret; 15928c2ecf20Sopenharmony_ci prev_gain16 = ret; 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci /* get average */ 15958c2ecf20Sopenharmony_ci ret = ov5640_read_reg(sensor, OV5640_REG_AVG_READOUT, &average); 15968c2ecf20Sopenharmony_ci if (ret) 15978c2ecf20Sopenharmony_ci return ret; 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci /* turn off night mode for capture */ 16008c2ecf20Sopenharmony_ci ret = ov5640_set_night_mode(sensor); 16018c2ecf20Sopenharmony_ci if (ret < 0) 16028c2ecf20Sopenharmony_ci return ret; 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci /* Write capture setting */ 16058c2ecf20Sopenharmony_ci ret = ov5640_load_regs(sensor, mode); 16068c2ecf20Sopenharmony_ci if (ret < 0) 16078c2ecf20Sopenharmony_ci return ret; 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci /* read capture VTS */ 16108c2ecf20Sopenharmony_ci ret = ov5640_get_vts(sensor); 16118c2ecf20Sopenharmony_ci if (ret < 0) 16128c2ecf20Sopenharmony_ci return ret; 16138c2ecf20Sopenharmony_ci cap_vts = ret; 16148c2ecf20Sopenharmony_ci ret = ov5640_get_hts(sensor); 16158c2ecf20Sopenharmony_ci if (ret < 0) 16168c2ecf20Sopenharmony_ci return ret; 16178c2ecf20Sopenharmony_ci if (ret == 0) 16188c2ecf20Sopenharmony_ci return -EINVAL; 16198c2ecf20Sopenharmony_ci cap_hts = ret; 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci ret = ov5640_get_sysclk(sensor); 16228c2ecf20Sopenharmony_ci if (ret < 0) 16238c2ecf20Sopenharmony_ci return ret; 16248c2ecf20Sopenharmony_ci if (ret == 0) 16258c2ecf20Sopenharmony_ci return -EINVAL; 16268c2ecf20Sopenharmony_ci cap_sysclk = ret; 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci /* calculate capture banding filter */ 16298c2ecf20Sopenharmony_ci ret = ov5640_get_light_freq(sensor); 16308c2ecf20Sopenharmony_ci if (ret < 0) 16318c2ecf20Sopenharmony_ci return ret; 16328c2ecf20Sopenharmony_ci light_freq = ret; 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci if (light_freq == 60) { 16358c2ecf20Sopenharmony_ci /* 60Hz */ 16368c2ecf20Sopenharmony_ci cap_bandfilt = cap_sysclk * 100 / cap_hts * 100 / 120; 16378c2ecf20Sopenharmony_ci } else { 16388c2ecf20Sopenharmony_ci /* 50Hz */ 16398c2ecf20Sopenharmony_ci cap_bandfilt = cap_sysclk * 100 / cap_hts; 16408c2ecf20Sopenharmony_ci } 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci if (!sensor->prev_sysclk) { 16438c2ecf20Sopenharmony_ci ret = ov5640_get_sysclk(sensor); 16448c2ecf20Sopenharmony_ci if (ret < 0) 16458c2ecf20Sopenharmony_ci return ret; 16468c2ecf20Sopenharmony_ci if (ret == 0) 16478c2ecf20Sopenharmony_ci return -EINVAL; 16488c2ecf20Sopenharmony_ci sensor->prev_sysclk = ret; 16498c2ecf20Sopenharmony_ci } 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci if (!cap_bandfilt) 16528c2ecf20Sopenharmony_ci return -EINVAL; 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci cap_maxband = (int)((cap_vts - 4) / cap_bandfilt); 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci /* calculate capture shutter/gain16 */ 16578c2ecf20Sopenharmony_ci if (average > sensor->ae_low && average < sensor->ae_high) { 16588c2ecf20Sopenharmony_ci /* in stable range */ 16598c2ecf20Sopenharmony_ci cap_gain16_shutter = 16608c2ecf20Sopenharmony_ci prev_gain16 * prev_shutter * 16618c2ecf20Sopenharmony_ci cap_sysclk / sensor->prev_sysclk * 16628c2ecf20Sopenharmony_ci sensor->prev_hts / cap_hts * 16638c2ecf20Sopenharmony_ci sensor->ae_target / average; 16648c2ecf20Sopenharmony_ci } else { 16658c2ecf20Sopenharmony_ci cap_gain16_shutter = 16668c2ecf20Sopenharmony_ci prev_gain16 * prev_shutter * 16678c2ecf20Sopenharmony_ci cap_sysclk / sensor->prev_sysclk * 16688c2ecf20Sopenharmony_ci sensor->prev_hts / cap_hts; 16698c2ecf20Sopenharmony_ci } 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci /* gain to shutter */ 16728c2ecf20Sopenharmony_ci if (cap_gain16_shutter < (cap_bandfilt * 16)) { 16738c2ecf20Sopenharmony_ci /* shutter < 1/100 */ 16748c2ecf20Sopenharmony_ci cap_shutter = cap_gain16_shutter / 16; 16758c2ecf20Sopenharmony_ci if (cap_shutter < 1) 16768c2ecf20Sopenharmony_ci cap_shutter = 1; 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci cap_gain16 = cap_gain16_shutter / cap_shutter; 16798c2ecf20Sopenharmony_ci if (cap_gain16 < 16) 16808c2ecf20Sopenharmony_ci cap_gain16 = 16; 16818c2ecf20Sopenharmony_ci } else { 16828c2ecf20Sopenharmony_ci if (cap_gain16_shutter > (cap_bandfilt * cap_maxband * 16)) { 16838c2ecf20Sopenharmony_ci /* exposure reach max */ 16848c2ecf20Sopenharmony_ci cap_shutter = cap_bandfilt * cap_maxband; 16858c2ecf20Sopenharmony_ci if (!cap_shutter) 16868c2ecf20Sopenharmony_ci return -EINVAL; 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci cap_gain16 = cap_gain16_shutter / cap_shutter; 16898c2ecf20Sopenharmony_ci } else { 16908c2ecf20Sopenharmony_ci /* 1/100 < (cap_shutter = n/100) =< max */ 16918c2ecf20Sopenharmony_ci cap_shutter = 16928c2ecf20Sopenharmony_ci ((int)(cap_gain16_shutter / 16 / cap_bandfilt)) 16938c2ecf20Sopenharmony_ci * cap_bandfilt; 16948c2ecf20Sopenharmony_ci if (!cap_shutter) 16958c2ecf20Sopenharmony_ci return -EINVAL; 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci cap_gain16 = cap_gain16_shutter / cap_shutter; 16988c2ecf20Sopenharmony_ci } 16998c2ecf20Sopenharmony_ci } 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci /* set capture gain */ 17028c2ecf20Sopenharmony_ci ret = ov5640_set_gain(sensor, cap_gain16); 17038c2ecf20Sopenharmony_ci if (ret) 17048c2ecf20Sopenharmony_ci return ret; 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci /* write capture shutter */ 17078c2ecf20Sopenharmony_ci if (cap_shutter > (cap_vts - 4)) { 17088c2ecf20Sopenharmony_ci cap_vts = cap_shutter + 4; 17098c2ecf20Sopenharmony_ci ret = ov5640_set_vts(sensor, cap_vts); 17108c2ecf20Sopenharmony_ci if (ret < 0) 17118c2ecf20Sopenharmony_ci return ret; 17128c2ecf20Sopenharmony_ci } 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_ci /* set exposure */ 17158c2ecf20Sopenharmony_ci return ov5640_set_exposure(sensor, cap_shutter); 17168c2ecf20Sopenharmony_ci} 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci/* 17198c2ecf20Sopenharmony_ci * if sensor changes inside scaling or subsampling 17208c2ecf20Sopenharmony_ci * change mode directly 17218c2ecf20Sopenharmony_ci */ 17228c2ecf20Sopenharmony_cistatic int ov5640_set_mode_direct(struct ov5640_dev *sensor, 17238c2ecf20Sopenharmony_ci const struct ov5640_mode_info *mode) 17248c2ecf20Sopenharmony_ci{ 17258c2ecf20Sopenharmony_ci if (!mode->reg_data) 17268c2ecf20Sopenharmony_ci return -EINVAL; 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci /* Write capture setting */ 17298c2ecf20Sopenharmony_ci return ov5640_load_regs(sensor, mode); 17308c2ecf20Sopenharmony_ci} 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_cistatic int ov5640_set_mode(struct ov5640_dev *sensor) 17338c2ecf20Sopenharmony_ci{ 17348c2ecf20Sopenharmony_ci const struct ov5640_mode_info *mode = sensor->current_mode; 17358c2ecf20Sopenharmony_ci const struct ov5640_mode_info *orig_mode = sensor->last_mode; 17368c2ecf20Sopenharmony_ci enum ov5640_downsize_mode dn_mode, orig_dn_mode; 17378c2ecf20Sopenharmony_ci bool auto_gain = sensor->ctrls.auto_gain->val == 1; 17388c2ecf20Sopenharmony_ci bool auto_exp = sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO; 17398c2ecf20Sopenharmony_ci unsigned long rate; 17408c2ecf20Sopenharmony_ci int ret; 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci dn_mode = mode->dn_mode; 17438c2ecf20Sopenharmony_ci orig_dn_mode = orig_mode->dn_mode; 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci /* auto gain and exposure must be turned off when changing modes */ 17468c2ecf20Sopenharmony_ci if (auto_gain) { 17478c2ecf20Sopenharmony_ci ret = ov5640_set_autogain(sensor, false); 17488c2ecf20Sopenharmony_ci if (ret) 17498c2ecf20Sopenharmony_ci return ret; 17508c2ecf20Sopenharmony_ci } 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci if (auto_exp) { 17538c2ecf20Sopenharmony_ci ret = ov5640_set_autoexposure(sensor, false); 17548c2ecf20Sopenharmony_ci if (ret) 17558c2ecf20Sopenharmony_ci goto restore_auto_gain; 17568c2ecf20Sopenharmony_ci } 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci /* 17598c2ecf20Sopenharmony_ci * All the formats we support have 16 bits per pixel, seems to require 17608c2ecf20Sopenharmony_ci * the same rate than YUV, so we can just use 16 bpp all the time. 17618c2ecf20Sopenharmony_ci */ 17628c2ecf20Sopenharmony_ci rate = ov5640_calc_pixel_rate(sensor) * 16; 17638c2ecf20Sopenharmony_ci if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY) { 17648c2ecf20Sopenharmony_ci rate = rate / sensor->ep.bus.mipi_csi2.num_data_lanes; 17658c2ecf20Sopenharmony_ci ret = ov5640_set_mipi_pclk(sensor, rate); 17668c2ecf20Sopenharmony_ci } else { 17678c2ecf20Sopenharmony_ci rate = rate / sensor->ep.bus.parallel.bus_width; 17688c2ecf20Sopenharmony_ci ret = ov5640_set_dvp_pclk(sensor, rate); 17698c2ecf20Sopenharmony_ci } 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci if (ret < 0) 17728c2ecf20Sopenharmony_ci return 0; 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) || 17758c2ecf20Sopenharmony_ci (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) { 17768c2ecf20Sopenharmony_ci /* 17778c2ecf20Sopenharmony_ci * change between subsampling and scaling 17788c2ecf20Sopenharmony_ci * go through exposure calculation 17798c2ecf20Sopenharmony_ci */ 17808c2ecf20Sopenharmony_ci ret = ov5640_set_mode_exposure_calc(sensor, mode); 17818c2ecf20Sopenharmony_ci } else { 17828c2ecf20Sopenharmony_ci /* 17838c2ecf20Sopenharmony_ci * change inside subsampling or scaling 17848c2ecf20Sopenharmony_ci * download firmware directly 17858c2ecf20Sopenharmony_ci */ 17868c2ecf20Sopenharmony_ci ret = ov5640_set_mode_direct(sensor, mode); 17878c2ecf20Sopenharmony_ci } 17888c2ecf20Sopenharmony_ci if (ret < 0) 17898c2ecf20Sopenharmony_ci goto restore_auto_exp_gain; 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci /* restore auto gain and exposure */ 17928c2ecf20Sopenharmony_ci if (auto_gain) 17938c2ecf20Sopenharmony_ci ov5640_set_autogain(sensor, true); 17948c2ecf20Sopenharmony_ci if (auto_exp) 17958c2ecf20Sopenharmony_ci ov5640_set_autoexposure(sensor, true); 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci ret = ov5640_set_binning(sensor, dn_mode != SCALING); 17988c2ecf20Sopenharmony_ci if (ret < 0) 17998c2ecf20Sopenharmony_ci return ret; 18008c2ecf20Sopenharmony_ci ret = ov5640_set_ae_target(sensor, sensor->ae_target); 18018c2ecf20Sopenharmony_ci if (ret < 0) 18028c2ecf20Sopenharmony_ci return ret; 18038c2ecf20Sopenharmony_ci ret = ov5640_get_light_freq(sensor); 18048c2ecf20Sopenharmony_ci if (ret < 0) 18058c2ecf20Sopenharmony_ci return ret; 18068c2ecf20Sopenharmony_ci ret = ov5640_set_bandingfilter(sensor); 18078c2ecf20Sopenharmony_ci if (ret < 0) 18088c2ecf20Sopenharmony_ci return ret; 18098c2ecf20Sopenharmony_ci ret = ov5640_set_virtual_channel(sensor); 18108c2ecf20Sopenharmony_ci if (ret < 0) 18118c2ecf20Sopenharmony_ci return ret; 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci sensor->pending_mode_change = false; 18148c2ecf20Sopenharmony_ci sensor->last_mode = mode; 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci return 0; 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_cirestore_auto_exp_gain: 18198c2ecf20Sopenharmony_ci if (auto_exp) 18208c2ecf20Sopenharmony_ci ov5640_set_autoexposure(sensor, true); 18218c2ecf20Sopenharmony_cirestore_auto_gain: 18228c2ecf20Sopenharmony_ci if (auto_gain) 18238c2ecf20Sopenharmony_ci ov5640_set_autogain(sensor, true); 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci return ret; 18268c2ecf20Sopenharmony_ci} 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_cistatic int ov5640_set_framefmt(struct ov5640_dev *sensor, 18298c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *format); 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ci/* restore the last set video mode after chip power-on */ 18328c2ecf20Sopenharmony_cistatic int ov5640_restore_mode(struct ov5640_dev *sensor) 18338c2ecf20Sopenharmony_ci{ 18348c2ecf20Sopenharmony_ci int ret; 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci /* first load the initial register values */ 18378c2ecf20Sopenharmony_ci ret = ov5640_load_regs(sensor, &ov5640_mode_init_data); 18388c2ecf20Sopenharmony_ci if (ret < 0) 18398c2ecf20Sopenharmony_ci return ret; 18408c2ecf20Sopenharmony_ci sensor->last_mode = &ov5640_mode_init_data; 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f, 18438c2ecf20Sopenharmony_ci (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) | 18448c2ecf20Sopenharmony_ci ilog2(OV5640_SCLK_ROOT_DIV)); 18458c2ecf20Sopenharmony_ci if (ret) 18468c2ecf20Sopenharmony_ci return ret; 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci /* now restore the last capture mode */ 18498c2ecf20Sopenharmony_ci ret = ov5640_set_mode(sensor); 18508c2ecf20Sopenharmony_ci if (ret < 0) 18518c2ecf20Sopenharmony_ci return ret; 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci return ov5640_set_framefmt(sensor, &sensor->fmt); 18548c2ecf20Sopenharmony_ci} 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_cistatic void ov5640_power(struct ov5640_dev *sensor, bool enable) 18578c2ecf20Sopenharmony_ci{ 18588c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1); 18598c2ecf20Sopenharmony_ci} 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_cistatic void ov5640_reset(struct ov5640_dev *sensor) 18628c2ecf20Sopenharmony_ci{ 18638c2ecf20Sopenharmony_ci if (!sensor->reset_gpio) 18648c2ecf20Sopenharmony_ci return; 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(sensor->reset_gpio, 0); 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci /* camera power cycle */ 18698c2ecf20Sopenharmony_ci ov5640_power(sensor, false); 18708c2ecf20Sopenharmony_ci usleep_range(5000, 10000); 18718c2ecf20Sopenharmony_ci ov5640_power(sensor, true); 18728c2ecf20Sopenharmony_ci usleep_range(5000, 10000); 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(sensor->reset_gpio, 1); 18758c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(sensor->reset_gpio, 0); 18788c2ecf20Sopenharmony_ci usleep_range(20000, 25000); 18798c2ecf20Sopenharmony_ci} 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_cistatic int ov5640_set_power_on(struct ov5640_dev *sensor) 18828c2ecf20Sopenharmony_ci{ 18838c2ecf20Sopenharmony_ci struct i2c_client *client = sensor->i2c_client; 18848c2ecf20Sopenharmony_ci int ret; 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci ret = clk_prepare_enable(sensor->xclk); 18878c2ecf20Sopenharmony_ci if (ret) { 18888c2ecf20Sopenharmony_ci dev_err(&client->dev, "%s: failed to enable clock\n", 18898c2ecf20Sopenharmony_ci __func__); 18908c2ecf20Sopenharmony_ci return ret; 18918c2ecf20Sopenharmony_ci } 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci ret = regulator_bulk_enable(OV5640_NUM_SUPPLIES, 18948c2ecf20Sopenharmony_ci sensor->supplies); 18958c2ecf20Sopenharmony_ci if (ret) { 18968c2ecf20Sopenharmony_ci dev_err(&client->dev, "%s: failed to enable regulators\n", 18978c2ecf20Sopenharmony_ci __func__); 18988c2ecf20Sopenharmony_ci goto xclk_off; 18998c2ecf20Sopenharmony_ci } 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci ov5640_reset(sensor); 19028c2ecf20Sopenharmony_ci ov5640_power(sensor, true); 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci ret = ov5640_init_slave_id(sensor); 19058c2ecf20Sopenharmony_ci if (ret) 19068c2ecf20Sopenharmony_ci goto power_off; 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci return 0; 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_cipower_off: 19118c2ecf20Sopenharmony_ci ov5640_power(sensor, false); 19128c2ecf20Sopenharmony_ci regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies); 19138c2ecf20Sopenharmony_cixclk_off: 19148c2ecf20Sopenharmony_ci clk_disable_unprepare(sensor->xclk); 19158c2ecf20Sopenharmony_ci return ret; 19168c2ecf20Sopenharmony_ci} 19178c2ecf20Sopenharmony_ci 19188c2ecf20Sopenharmony_cistatic void ov5640_set_power_off(struct ov5640_dev *sensor) 19198c2ecf20Sopenharmony_ci{ 19208c2ecf20Sopenharmony_ci ov5640_power(sensor, false); 19218c2ecf20Sopenharmony_ci regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies); 19228c2ecf20Sopenharmony_ci clk_disable_unprepare(sensor->xclk); 19238c2ecf20Sopenharmony_ci} 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_cistatic int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on) 19268c2ecf20Sopenharmony_ci{ 19278c2ecf20Sopenharmony_ci int ret; 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci if (!on) { 19308c2ecf20Sopenharmony_ci /* Reset MIPI bus settings to their default values. */ 19318c2ecf20Sopenharmony_ci ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58); 19328c2ecf20Sopenharmony_ci ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x04); 19338c2ecf20Sopenharmony_ci ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x00); 19348c2ecf20Sopenharmony_ci return 0; 19358c2ecf20Sopenharmony_ci } 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci /* 19388c2ecf20Sopenharmony_ci * Power up MIPI HS Tx and LS Rx; 2 data lanes mode 19398c2ecf20Sopenharmony_ci * 19408c2ecf20Sopenharmony_ci * 0x300e = 0x40 19418c2ecf20Sopenharmony_ci * [7:5] = 010 : 2 data lanes mode (see FIXME note in 19428c2ecf20Sopenharmony_ci * "ov5640_set_stream_mipi()") 19438c2ecf20Sopenharmony_ci * [4] = 0 : Power up MIPI HS Tx 19448c2ecf20Sopenharmony_ci * [3] = 0 : Power up MIPI LS Rx 19458c2ecf20Sopenharmony_ci * [2] = 1 : MIPI interface enabled 19468c2ecf20Sopenharmony_ci */ 19478c2ecf20Sopenharmony_ci ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x44); 19488c2ecf20Sopenharmony_ci if (ret) 19498c2ecf20Sopenharmony_ci return ret; 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci /* 19528c2ecf20Sopenharmony_ci * Gate clock and set LP11 in 'no packets mode' (idle) 19538c2ecf20Sopenharmony_ci * 19548c2ecf20Sopenharmony_ci * 0x4800 = 0x24 19558c2ecf20Sopenharmony_ci * [5] = 1 : Gate clock when 'no packets' 19568c2ecf20Sopenharmony_ci * [2] = 1 : MIPI bus in LP11 when 'no packets' 19578c2ecf20Sopenharmony_ci */ 19588c2ecf20Sopenharmony_ci ret = ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x24); 19598c2ecf20Sopenharmony_ci if (ret) 19608c2ecf20Sopenharmony_ci return ret; 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci /* 19638c2ecf20Sopenharmony_ci * Set data lanes and clock in LP11 when 'sleeping' 19648c2ecf20Sopenharmony_ci * 19658c2ecf20Sopenharmony_ci * 0x3019 = 0x70 19668c2ecf20Sopenharmony_ci * [6] = 1 : MIPI data lane 2 in LP11 when 'sleeping' 19678c2ecf20Sopenharmony_ci * [5] = 1 : MIPI data lane 1 in LP11 when 'sleeping' 19688c2ecf20Sopenharmony_ci * [4] = 1 : MIPI clock lane in LP11 when 'sleeping' 19698c2ecf20Sopenharmony_ci */ 19708c2ecf20Sopenharmony_ci ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x70); 19718c2ecf20Sopenharmony_ci if (ret) 19728c2ecf20Sopenharmony_ci return ret; 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci /* Give lanes some time to coax into LP11 state. */ 19758c2ecf20Sopenharmony_ci usleep_range(500, 1000); 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ci return 0; 19788c2ecf20Sopenharmony_ci} 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_cistatic int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on) 19818c2ecf20Sopenharmony_ci{ 19828c2ecf20Sopenharmony_ci unsigned int flags = sensor->ep.bus.parallel.flags; 19838c2ecf20Sopenharmony_ci bool bt656 = sensor->ep.bus_type == V4L2_MBUS_BT656; 19848c2ecf20Sopenharmony_ci u8 polarities = 0; 19858c2ecf20Sopenharmony_ci int ret; 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci if (!on) { 19888c2ecf20Sopenharmony_ci /* Reset settings to their default values. */ 19898c2ecf20Sopenharmony_ci ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 0x00); 19908c2ecf20Sopenharmony_ci ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58); 19918c2ecf20Sopenharmony_ci ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, 0x20); 19928c2ecf20Sopenharmony_ci ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x00); 19938c2ecf20Sopenharmony_ci ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0x00); 19948c2ecf20Sopenharmony_ci return 0; 19958c2ecf20Sopenharmony_ci } 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci /* 19988c2ecf20Sopenharmony_ci * Note about parallel port configuration. 19998c2ecf20Sopenharmony_ci * 20008c2ecf20Sopenharmony_ci * When configured in parallel mode, the OV5640 will 20018c2ecf20Sopenharmony_ci * output 10 bits data on DVP data lines [9:0]. 20028c2ecf20Sopenharmony_ci * If only 8 bits data are wanted, the 8 bits data lines 20038c2ecf20Sopenharmony_ci * of the camera interface must be physically connected 20048c2ecf20Sopenharmony_ci * on the DVP data lines [9:2]. 20058c2ecf20Sopenharmony_ci * 20068c2ecf20Sopenharmony_ci * Control lines polarity can be configured through 20078c2ecf20Sopenharmony_ci * devicetree endpoint control lines properties. 20088c2ecf20Sopenharmony_ci * If no endpoint control lines properties are set, 20098c2ecf20Sopenharmony_ci * polarity will be as below: 20108c2ecf20Sopenharmony_ci * - VSYNC: active high 20118c2ecf20Sopenharmony_ci * - HREF: active low 20128c2ecf20Sopenharmony_ci * - PCLK: active low 20138c2ecf20Sopenharmony_ci * 20148c2ecf20Sopenharmony_ci * VSYNC & HREF are not configured if BT656 bus mode is selected 20158c2ecf20Sopenharmony_ci */ 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci /* 20188c2ecf20Sopenharmony_ci * BT656 embedded synchronization configuration 20198c2ecf20Sopenharmony_ci * 20208c2ecf20Sopenharmony_ci * CCIR656 CTRL00 20218c2ecf20Sopenharmony_ci * - [7]: SYNC code selection (0: auto generate sync code, 20228c2ecf20Sopenharmony_ci * 1: sync code from regs 0x4732-0x4735) 20238c2ecf20Sopenharmony_ci * - [6]: f value in CCIR656 SYNC code when fixed f value 20248c2ecf20Sopenharmony_ci * - [5]: Fixed f value 20258c2ecf20Sopenharmony_ci * - [4:3]: Blank toggle data options (00: data=1'h040/1'h200, 20268c2ecf20Sopenharmony_ci * 01: data from regs 0x4736-0x4738, 10: always keep 0) 20278c2ecf20Sopenharmony_ci * - [1]: Clip data disable 20288c2ecf20Sopenharmony_ci * - [0]: CCIR656 mode enable 20298c2ecf20Sopenharmony_ci * 20308c2ecf20Sopenharmony_ci * Default CCIR656 SAV/EAV mode with default codes 20318c2ecf20Sopenharmony_ci * SAV=0xff000080 & EAV=0xff00009d is enabled here with settings: 20328c2ecf20Sopenharmony_ci * - CCIR656 mode enable 20338c2ecf20Sopenharmony_ci * - auto generation of sync codes 20348c2ecf20Sopenharmony_ci * - blank toggle data 1'h040/1'h200 20358c2ecf20Sopenharmony_ci * - clip reserved data (0x00 & 0xff changed to 0x01 & 0xfe) 20368c2ecf20Sopenharmony_ci */ 20378c2ecf20Sopenharmony_ci ret = ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 20388c2ecf20Sopenharmony_ci bt656 ? 0x01 : 0x00); 20398c2ecf20Sopenharmony_ci if (ret) 20408c2ecf20Sopenharmony_ci return ret; 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci /* 20438c2ecf20Sopenharmony_ci * configure parallel port control lines polarity 20448c2ecf20Sopenharmony_ci * 20458c2ecf20Sopenharmony_ci * POLARITY CTRL0 20468c2ecf20Sopenharmony_ci * - [5]: PCLK polarity (0: active low, 1: active high) 20478c2ecf20Sopenharmony_ci * - [1]: HREF polarity (0: active low, 1: active high) 20488c2ecf20Sopenharmony_ci * - [0]: VSYNC polarity (mismatch here between 20498c2ecf20Sopenharmony_ci * datasheet and hardware, 0 is active high 20508c2ecf20Sopenharmony_ci * and 1 is active low...) 20518c2ecf20Sopenharmony_ci */ 20528c2ecf20Sopenharmony_ci if (!bt656) { 20538c2ecf20Sopenharmony_ci if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) 20548c2ecf20Sopenharmony_ci polarities |= BIT(1); 20558c2ecf20Sopenharmony_ci if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) 20568c2ecf20Sopenharmony_ci polarities |= BIT(0); 20578c2ecf20Sopenharmony_ci } 20588c2ecf20Sopenharmony_ci if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) 20598c2ecf20Sopenharmony_ci polarities |= BIT(5); 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, polarities); 20628c2ecf20Sopenharmony_ci if (ret) 20638c2ecf20Sopenharmony_ci return ret; 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci /* 20668c2ecf20Sopenharmony_ci * powerdown MIPI TX/RX PHY & enable DVP 20678c2ecf20Sopenharmony_ci * 20688c2ecf20Sopenharmony_ci * MIPI CONTROL 00 20698c2ecf20Sopenharmony_ci * [4] = 1 : Power down MIPI HS Tx 20708c2ecf20Sopenharmony_ci * [3] = 1 : Power down MIPI LS Rx 20718c2ecf20Sopenharmony_ci * [2] = 0 : DVP enable (MIPI disable) 20728c2ecf20Sopenharmony_ci */ 20738c2ecf20Sopenharmony_ci ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x18); 20748c2ecf20Sopenharmony_ci if (ret) 20758c2ecf20Sopenharmony_ci return ret; 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci /* 20788c2ecf20Sopenharmony_ci * enable VSYNC/HREF/PCLK DVP control lines 20798c2ecf20Sopenharmony_ci * & D[9:6] DVP data lines 20808c2ecf20Sopenharmony_ci * 20818c2ecf20Sopenharmony_ci * PAD OUTPUT ENABLE 01 20828c2ecf20Sopenharmony_ci * - 6: VSYNC output enable 20838c2ecf20Sopenharmony_ci * - 5: HREF output enable 20848c2ecf20Sopenharmony_ci * - 4: PCLK output enable 20858c2ecf20Sopenharmony_ci * - [3:0]: D[9:6] output enable 20868c2ecf20Sopenharmony_ci */ 20878c2ecf20Sopenharmony_ci ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 20888c2ecf20Sopenharmony_ci bt656 ? 0x1f : 0x7f); 20898c2ecf20Sopenharmony_ci if (ret) 20908c2ecf20Sopenharmony_ci return ret; 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci /* 20938c2ecf20Sopenharmony_ci * enable D[5:0] DVP data lines 20948c2ecf20Sopenharmony_ci * 20958c2ecf20Sopenharmony_ci * PAD OUTPUT ENABLE 02 20968c2ecf20Sopenharmony_ci * - [7:2]: D[5:0] output enable 20978c2ecf20Sopenharmony_ci */ 20988c2ecf20Sopenharmony_ci return ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0xfc); 20998c2ecf20Sopenharmony_ci} 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_cistatic int ov5640_set_power(struct ov5640_dev *sensor, bool on) 21028c2ecf20Sopenharmony_ci{ 21038c2ecf20Sopenharmony_ci int ret = 0; 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci if (on) { 21068c2ecf20Sopenharmony_ci ret = ov5640_set_power_on(sensor); 21078c2ecf20Sopenharmony_ci if (ret) 21088c2ecf20Sopenharmony_ci return ret; 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci ret = ov5640_restore_mode(sensor); 21118c2ecf20Sopenharmony_ci if (ret) 21128c2ecf20Sopenharmony_ci goto power_off; 21138c2ecf20Sopenharmony_ci } 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY) 21168c2ecf20Sopenharmony_ci ret = ov5640_set_power_mipi(sensor, on); 21178c2ecf20Sopenharmony_ci else 21188c2ecf20Sopenharmony_ci ret = ov5640_set_power_dvp(sensor, on); 21198c2ecf20Sopenharmony_ci if (ret) 21208c2ecf20Sopenharmony_ci goto power_off; 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci if (!on) 21238c2ecf20Sopenharmony_ci ov5640_set_power_off(sensor); 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci return 0; 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_cipower_off: 21288c2ecf20Sopenharmony_ci ov5640_set_power_off(sensor); 21298c2ecf20Sopenharmony_ci return ret; 21308c2ecf20Sopenharmony_ci} 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci/* --------------- Subdev Operations --------------- */ 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_cistatic int ov5640_s_power(struct v4l2_subdev *sd, int on) 21358c2ecf20Sopenharmony_ci{ 21368c2ecf20Sopenharmony_ci struct ov5640_dev *sensor = to_ov5640_dev(sd); 21378c2ecf20Sopenharmony_ci int ret = 0; 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci mutex_lock(&sensor->lock); 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci /* 21428c2ecf20Sopenharmony_ci * If the power count is modified from 0 to != 0 or from != 0 to 0, 21438c2ecf20Sopenharmony_ci * update the power state. 21448c2ecf20Sopenharmony_ci */ 21458c2ecf20Sopenharmony_ci if (sensor->power_count == !on) { 21468c2ecf20Sopenharmony_ci ret = ov5640_set_power(sensor, !!on); 21478c2ecf20Sopenharmony_ci if (ret) 21488c2ecf20Sopenharmony_ci goto out; 21498c2ecf20Sopenharmony_ci } 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ci /* Update the power count. */ 21528c2ecf20Sopenharmony_ci sensor->power_count += on ? 1 : -1; 21538c2ecf20Sopenharmony_ci WARN_ON(sensor->power_count < 0); 21548c2ecf20Sopenharmony_ciout: 21558c2ecf20Sopenharmony_ci mutex_unlock(&sensor->lock); 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci if (on && !ret && sensor->power_count == 1) { 21588c2ecf20Sopenharmony_ci /* restore controls */ 21598c2ecf20Sopenharmony_ci ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler); 21608c2ecf20Sopenharmony_ci } 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci return ret; 21638c2ecf20Sopenharmony_ci} 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_cistatic int ov5640_try_frame_interval(struct ov5640_dev *sensor, 21668c2ecf20Sopenharmony_ci struct v4l2_fract *fi, 21678c2ecf20Sopenharmony_ci u32 width, u32 height) 21688c2ecf20Sopenharmony_ci{ 21698c2ecf20Sopenharmony_ci const struct ov5640_mode_info *mode; 21708c2ecf20Sopenharmony_ci enum ov5640_frame_rate rate = OV5640_15_FPS; 21718c2ecf20Sopenharmony_ci int minfps, maxfps, best_fps, fps; 21728c2ecf20Sopenharmony_ci int i; 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci minfps = ov5640_framerates[OV5640_15_FPS]; 21758c2ecf20Sopenharmony_ci maxfps = ov5640_framerates[OV5640_60_FPS]; 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ci if (fi->numerator == 0) { 21788c2ecf20Sopenharmony_ci fi->denominator = maxfps; 21798c2ecf20Sopenharmony_ci fi->numerator = 1; 21808c2ecf20Sopenharmony_ci rate = OV5640_60_FPS; 21818c2ecf20Sopenharmony_ci goto find_mode; 21828c2ecf20Sopenharmony_ci } 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator), 21858c2ecf20Sopenharmony_ci minfps, maxfps); 21868c2ecf20Sopenharmony_ci 21878c2ecf20Sopenharmony_ci best_fps = minfps; 21888c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) { 21898c2ecf20Sopenharmony_ci int curr_fps = ov5640_framerates[i]; 21908c2ecf20Sopenharmony_ci 21918c2ecf20Sopenharmony_ci if (abs(curr_fps - fps) < abs(best_fps - fps)) { 21928c2ecf20Sopenharmony_ci best_fps = curr_fps; 21938c2ecf20Sopenharmony_ci rate = i; 21948c2ecf20Sopenharmony_ci } 21958c2ecf20Sopenharmony_ci } 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_ci fi->numerator = 1; 21988c2ecf20Sopenharmony_ci fi->denominator = best_fps; 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_cifind_mode: 22018c2ecf20Sopenharmony_ci mode = ov5640_find_mode(sensor, rate, width, height, false); 22028c2ecf20Sopenharmony_ci return mode ? rate : -EINVAL; 22038c2ecf20Sopenharmony_ci} 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_cistatic int ov5640_get_fmt(struct v4l2_subdev *sd, 22068c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 22078c2ecf20Sopenharmony_ci struct v4l2_subdev_format *format) 22088c2ecf20Sopenharmony_ci{ 22098c2ecf20Sopenharmony_ci struct ov5640_dev *sensor = to_ov5640_dev(sd); 22108c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *fmt; 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci if (format->pad != 0) 22138c2ecf20Sopenharmony_ci return -EINVAL; 22148c2ecf20Sopenharmony_ci 22158c2ecf20Sopenharmony_ci mutex_lock(&sensor->lock); 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci if (format->which == V4L2_SUBDEV_FORMAT_TRY) 22188c2ecf20Sopenharmony_ci fmt = v4l2_subdev_get_try_format(&sensor->sd, cfg, 22198c2ecf20Sopenharmony_ci format->pad); 22208c2ecf20Sopenharmony_ci else 22218c2ecf20Sopenharmony_ci fmt = &sensor->fmt; 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci format->format = *fmt; 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci mutex_unlock(&sensor->lock); 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci return 0; 22288c2ecf20Sopenharmony_ci} 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_cistatic int ov5640_try_fmt_internal(struct v4l2_subdev *sd, 22318c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *fmt, 22328c2ecf20Sopenharmony_ci enum ov5640_frame_rate fr, 22338c2ecf20Sopenharmony_ci const struct ov5640_mode_info **new_mode) 22348c2ecf20Sopenharmony_ci{ 22358c2ecf20Sopenharmony_ci struct ov5640_dev *sensor = to_ov5640_dev(sd); 22368c2ecf20Sopenharmony_ci const struct ov5640_mode_info *mode; 22378c2ecf20Sopenharmony_ci int i; 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci mode = ov5640_find_mode(sensor, fr, fmt->width, fmt->height, true); 22408c2ecf20Sopenharmony_ci if (!mode) 22418c2ecf20Sopenharmony_ci return -EINVAL; 22428c2ecf20Sopenharmony_ci fmt->width = mode->hact; 22438c2ecf20Sopenharmony_ci fmt->height = mode->vact; 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci if (new_mode) 22468c2ecf20Sopenharmony_ci *new_mode = mode; 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ov5640_formats); i++) 22498c2ecf20Sopenharmony_ci if (ov5640_formats[i].code == fmt->code) 22508c2ecf20Sopenharmony_ci break; 22518c2ecf20Sopenharmony_ci if (i >= ARRAY_SIZE(ov5640_formats)) 22528c2ecf20Sopenharmony_ci i = 0; 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci fmt->code = ov5640_formats[i].code; 22558c2ecf20Sopenharmony_ci fmt->colorspace = ov5640_formats[i].colorspace; 22568c2ecf20Sopenharmony_ci fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); 22578c2ecf20Sopenharmony_ci fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; 22588c2ecf20Sopenharmony_ci fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace); 22598c2ecf20Sopenharmony_ci 22608c2ecf20Sopenharmony_ci return 0; 22618c2ecf20Sopenharmony_ci} 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_cistatic int ov5640_set_fmt(struct v4l2_subdev *sd, 22648c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 22658c2ecf20Sopenharmony_ci struct v4l2_subdev_format *format) 22668c2ecf20Sopenharmony_ci{ 22678c2ecf20Sopenharmony_ci struct ov5640_dev *sensor = to_ov5640_dev(sd); 22688c2ecf20Sopenharmony_ci const struct ov5640_mode_info *new_mode; 22698c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *mbus_fmt = &format->format; 22708c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *fmt; 22718c2ecf20Sopenharmony_ci int ret; 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ci if (format->pad != 0) 22748c2ecf20Sopenharmony_ci return -EINVAL; 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci mutex_lock(&sensor->lock); 22778c2ecf20Sopenharmony_ci 22788c2ecf20Sopenharmony_ci if (sensor->streaming) { 22798c2ecf20Sopenharmony_ci ret = -EBUSY; 22808c2ecf20Sopenharmony_ci goto out; 22818c2ecf20Sopenharmony_ci } 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_ci ret = ov5640_try_fmt_internal(sd, mbus_fmt, 22848c2ecf20Sopenharmony_ci sensor->current_fr, &new_mode); 22858c2ecf20Sopenharmony_ci if (ret) 22868c2ecf20Sopenharmony_ci goto out; 22878c2ecf20Sopenharmony_ci 22888c2ecf20Sopenharmony_ci if (format->which == V4L2_SUBDEV_FORMAT_TRY) 22898c2ecf20Sopenharmony_ci fmt = v4l2_subdev_get_try_format(sd, cfg, 0); 22908c2ecf20Sopenharmony_ci else 22918c2ecf20Sopenharmony_ci fmt = &sensor->fmt; 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_ci *fmt = *mbus_fmt; 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_ci if (new_mode != sensor->current_mode) { 22968c2ecf20Sopenharmony_ci sensor->current_mode = new_mode; 22978c2ecf20Sopenharmony_ci sensor->pending_mode_change = true; 22988c2ecf20Sopenharmony_ci } 22998c2ecf20Sopenharmony_ci if (mbus_fmt->code != sensor->fmt.code) 23008c2ecf20Sopenharmony_ci sensor->pending_fmt_change = true; 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, 23038c2ecf20Sopenharmony_ci ov5640_calc_pixel_rate(sensor)); 23048c2ecf20Sopenharmony_ciout: 23058c2ecf20Sopenharmony_ci mutex_unlock(&sensor->lock); 23068c2ecf20Sopenharmony_ci return ret; 23078c2ecf20Sopenharmony_ci} 23088c2ecf20Sopenharmony_ci 23098c2ecf20Sopenharmony_cistatic int ov5640_set_framefmt(struct ov5640_dev *sensor, 23108c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *format) 23118c2ecf20Sopenharmony_ci{ 23128c2ecf20Sopenharmony_ci int ret = 0; 23138c2ecf20Sopenharmony_ci bool is_jpeg = false; 23148c2ecf20Sopenharmony_ci u8 fmt, mux; 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci switch (format->code) { 23178c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_UYVY8_2X8: 23188c2ecf20Sopenharmony_ci /* YUV422, UYVY */ 23198c2ecf20Sopenharmony_ci fmt = 0x3f; 23208c2ecf20Sopenharmony_ci mux = OV5640_FMT_MUX_YUV422; 23218c2ecf20Sopenharmony_ci break; 23228c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_YUYV8_2X8: 23238c2ecf20Sopenharmony_ci /* YUV422, YUYV */ 23248c2ecf20Sopenharmony_ci fmt = 0x30; 23258c2ecf20Sopenharmony_ci mux = OV5640_FMT_MUX_YUV422; 23268c2ecf20Sopenharmony_ci break; 23278c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_RGB565_2X8_LE: 23288c2ecf20Sopenharmony_ci /* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */ 23298c2ecf20Sopenharmony_ci fmt = 0x6F; 23308c2ecf20Sopenharmony_ci mux = OV5640_FMT_MUX_RGB; 23318c2ecf20Sopenharmony_ci break; 23328c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_RGB565_2X8_BE: 23338c2ecf20Sopenharmony_ci /* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */ 23348c2ecf20Sopenharmony_ci fmt = 0x61; 23358c2ecf20Sopenharmony_ci mux = OV5640_FMT_MUX_RGB; 23368c2ecf20Sopenharmony_ci break; 23378c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_JPEG_1X8: 23388c2ecf20Sopenharmony_ci /* YUV422, YUYV */ 23398c2ecf20Sopenharmony_ci fmt = 0x30; 23408c2ecf20Sopenharmony_ci mux = OV5640_FMT_MUX_YUV422; 23418c2ecf20Sopenharmony_ci is_jpeg = true; 23428c2ecf20Sopenharmony_ci break; 23438c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SBGGR8_1X8: 23448c2ecf20Sopenharmony_ci /* Raw, BGBG... / GRGR... */ 23458c2ecf20Sopenharmony_ci fmt = 0x00; 23468c2ecf20Sopenharmony_ci mux = OV5640_FMT_MUX_RAW_DPC; 23478c2ecf20Sopenharmony_ci break; 23488c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SGBRG8_1X8: 23498c2ecf20Sopenharmony_ci /* Raw bayer, GBGB... / RGRG... */ 23508c2ecf20Sopenharmony_ci fmt = 0x01; 23518c2ecf20Sopenharmony_ci mux = OV5640_FMT_MUX_RAW_DPC; 23528c2ecf20Sopenharmony_ci break; 23538c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SGRBG8_1X8: 23548c2ecf20Sopenharmony_ci /* Raw bayer, GRGR... / BGBG... */ 23558c2ecf20Sopenharmony_ci fmt = 0x02; 23568c2ecf20Sopenharmony_ci mux = OV5640_FMT_MUX_RAW_DPC; 23578c2ecf20Sopenharmony_ci break; 23588c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SRGGB8_1X8: 23598c2ecf20Sopenharmony_ci /* Raw bayer, RGRG... / GBGB... */ 23608c2ecf20Sopenharmony_ci fmt = 0x03; 23618c2ecf20Sopenharmony_ci mux = OV5640_FMT_MUX_RAW_DPC; 23628c2ecf20Sopenharmony_ci break; 23638c2ecf20Sopenharmony_ci default: 23648c2ecf20Sopenharmony_ci return -EINVAL; 23658c2ecf20Sopenharmony_ci } 23668c2ecf20Sopenharmony_ci 23678c2ecf20Sopenharmony_ci /* FORMAT CONTROL00: YUV and RGB formatting */ 23688c2ecf20Sopenharmony_ci ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, fmt); 23698c2ecf20Sopenharmony_ci if (ret) 23708c2ecf20Sopenharmony_ci return ret; 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci /* FORMAT MUX CONTROL: ISP YUV or RGB */ 23738c2ecf20Sopenharmony_ci ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, mux); 23748c2ecf20Sopenharmony_ci if (ret) 23758c2ecf20Sopenharmony_ci return ret; 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_ci /* 23788c2ecf20Sopenharmony_ci * TIMING TC REG21: 23798c2ecf20Sopenharmony_ci * - [5]: JPEG enable 23808c2ecf20Sopenharmony_ci */ 23818c2ecf20Sopenharmony_ci ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21, 23828c2ecf20Sopenharmony_ci BIT(5), is_jpeg ? BIT(5) : 0); 23838c2ecf20Sopenharmony_ci if (ret) 23848c2ecf20Sopenharmony_ci return ret; 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_ci /* 23878c2ecf20Sopenharmony_ci * SYSTEM RESET02: 23888c2ecf20Sopenharmony_ci * - [4]: Reset JFIFO 23898c2ecf20Sopenharmony_ci * - [3]: Reset SFIFO 23908c2ecf20Sopenharmony_ci * - [2]: Reset JPEG 23918c2ecf20Sopenharmony_ci */ 23928c2ecf20Sopenharmony_ci ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_RESET02, 23938c2ecf20Sopenharmony_ci BIT(4) | BIT(3) | BIT(2), 23948c2ecf20Sopenharmony_ci is_jpeg ? 0 : (BIT(4) | BIT(3) | BIT(2))); 23958c2ecf20Sopenharmony_ci if (ret) 23968c2ecf20Sopenharmony_ci return ret; 23978c2ecf20Sopenharmony_ci 23988c2ecf20Sopenharmony_ci /* 23998c2ecf20Sopenharmony_ci * CLOCK ENABLE02: 24008c2ecf20Sopenharmony_ci * - [5]: Enable JPEG 2x clock 24018c2ecf20Sopenharmony_ci * - [3]: Enable JPEG clock 24028c2ecf20Sopenharmony_ci */ 24038c2ecf20Sopenharmony_ci return ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE02, 24048c2ecf20Sopenharmony_ci BIT(5) | BIT(3), 24058c2ecf20Sopenharmony_ci is_jpeg ? (BIT(5) | BIT(3)) : 0); 24068c2ecf20Sopenharmony_ci} 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci/* 24098c2ecf20Sopenharmony_ci * Sensor Controls. 24108c2ecf20Sopenharmony_ci */ 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_cistatic int ov5640_set_ctrl_hue(struct ov5640_dev *sensor, int value) 24138c2ecf20Sopenharmony_ci{ 24148c2ecf20Sopenharmony_ci int ret; 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_ci if (value) { 24178c2ecf20Sopenharmony_ci ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, 24188c2ecf20Sopenharmony_ci BIT(0), BIT(0)); 24198c2ecf20Sopenharmony_ci if (ret) 24208c2ecf20Sopenharmony_ci return ret; 24218c2ecf20Sopenharmony_ci ret = ov5640_write_reg16(sensor, OV5640_REG_SDE_CTRL1, value); 24228c2ecf20Sopenharmony_ci } else { 24238c2ecf20Sopenharmony_ci ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(0), 0); 24248c2ecf20Sopenharmony_ci } 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_ci return ret; 24278c2ecf20Sopenharmony_ci} 24288c2ecf20Sopenharmony_ci 24298c2ecf20Sopenharmony_cistatic int ov5640_set_ctrl_contrast(struct ov5640_dev *sensor, int value) 24308c2ecf20Sopenharmony_ci{ 24318c2ecf20Sopenharmony_ci int ret; 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci if (value) { 24348c2ecf20Sopenharmony_ci ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, 24358c2ecf20Sopenharmony_ci BIT(2), BIT(2)); 24368c2ecf20Sopenharmony_ci if (ret) 24378c2ecf20Sopenharmony_ci return ret; 24388c2ecf20Sopenharmony_ci ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL5, 24398c2ecf20Sopenharmony_ci value & 0xff); 24408c2ecf20Sopenharmony_ci } else { 24418c2ecf20Sopenharmony_ci ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(2), 0); 24428c2ecf20Sopenharmony_ci } 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_ci return ret; 24458c2ecf20Sopenharmony_ci} 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_cistatic int ov5640_set_ctrl_saturation(struct ov5640_dev *sensor, int value) 24488c2ecf20Sopenharmony_ci{ 24498c2ecf20Sopenharmony_ci int ret; 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ci if (value) { 24528c2ecf20Sopenharmony_ci ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, 24538c2ecf20Sopenharmony_ci BIT(1), BIT(1)); 24548c2ecf20Sopenharmony_ci if (ret) 24558c2ecf20Sopenharmony_ci return ret; 24568c2ecf20Sopenharmony_ci ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL3, 24578c2ecf20Sopenharmony_ci value & 0xff); 24588c2ecf20Sopenharmony_ci if (ret) 24598c2ecf20Sopenharmony_ci return ret; 24608c2ecf20Sopenharmony_ci ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL4, 24618c2ecf20Sopenharmony_ci value & 0xff); 24628c2ecf20Sopenharmony_ci } else { 24638c2ecf20Sopenharmony_ci ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(1), 0); 24648c2ecf20Sopenharmony_ci } 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci return ret; 24678c2ecf20Sopenharmony_ci} 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_cistatic int ov5640_set_ctrl_white_balance(struct ov5640_dev *sensor, int awb) 24708c2ecf20Sopenharmony_ci{ 24718c2ecf20Sopenharmony_ci int ret; 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci ret = ov5640_mod_reg(sensor, OV5640_REG_AWB_MANUAL_CTRL, 24748c2ecf20Sopenharmony_ci BIT(0), awb ? 0 : 1); 24758c2ecf20Sopenharmony_ci if (ret) 24768c2ecf20Sopenharmony_ci return ret; 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci if (!awb) { 24798c2ecf20Sopenharmony_ci u16 red = (u16)sensor->ctrls.red_balance->val; 24808c2ecf20Sopenharmony_ci u16 blue = (u16)sensor->ctrls.blue_balance->val; 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_R_GAIN, red); 24838c2ecf20Sopenharmony_ci if (ret) 24848c2ecf20Sopenharmony_ci return ret; 24858c2ecf20Sopenharmony_ci ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_B_GAIN, blue); 24868c2ecf20Sopenharmony_ci } 24878c2ecf20Sopenharmony_ci 24888c2ecf20Sopenharmony_ci return ret; 24898c2ecf20Sopenharmony_ci} 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_cistatic int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor, 24928c2ecf20Sopenharmony_ci enum v4l2_exposure_auto_type auto_exposure) 24938c2ecf20Sopenharmony_ci{ 24948c2ecf20Sopenharmony_ci struct ov5640_ctrls *ctrls = &sensor->ctrls; 24958c2ecf20Sopenharmony_ci bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO); 24968c2ecf20Sopenharmony_ci int ret = 0; 24978c2ecf20Sopenharmony_ci 24988c2ecf20Sopenharmony_ci if (ctrls->auto_exp->is_new) { 24998c2ecf20Sopenharmony_ci ret = ov5640_set_autoexposure(sensor, auto_exp); 25008c2ecf20Sopenharmony_ci if (ret) 25018c2ecf20Sopenharmony_ci return ret; 25028c2ecf20Sopenharmony_ci } 25038c2ecf20Sopenharmony_ci 25048c2ecf20Sopenharmony_ci if (!auto_exp && ctrls->exposure->is_new) { 25058c2ecf20Sopenharmony_ci u16 max_exp; 25068c2ecf20Sopenharmony_ci 25078c2ecf20Sopenharmony_ci ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_VTS, 25088c2ecf20Sopenharmony_ci &max_exp); 25098c2ecf20Sopenharmony_ci if (ret) 25108c2ecf20Sopenharmony_ci return ret; 25118c2ecf20Sopenharmony_ci ret = ov5640_get_vts(sensor); 25128c2ecf20Sopenharmony_ci if (ret < 0) 25138c2ecf20Sopenharmony_ci return ret; 25148c2ecf20Sopenharmony_ci max_exp += ret; 25158c2ecf20Sopenharmony_ci ret = 0; 25168c2ecf20Sopenharmony_ci 25178c2ecf20Sopenharmony_ci if (ctrls->exposure->val < max_exp) 25188c2ecf20Sopenharmony_ci ret = ov5640_set_exposure(sensor, ctrls->exposure->val); 25198c2ecf20Sopenharmony_ci } 25208c2ecf20Sopenharmony_ci 25218c2ecf20Sopenharmony_ci return ret; 25228c2ecf20Sopenharmony_ci} 25238c2ecf20Sopenharmony_ci 25248c2ecf20Sopenharmony_cistatic int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain) 25258c2ecf20Sopenharmony_ci{ 25268c2ecf20Sopenharmony_ci struct ov5640_ctrls *ctrls = &sensor->ctrls; 25278c2ecf20Sopenharmony_ci int ret = 0; 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_ci if (ctrls->auto_gain->is_new) { 25308c2ecf20Sopenharmony_ci ret = ov5640_set_autogain(sensor, auto_gain); 25318c2ecf20Sopenharmony_ci if (ret) 25328c2ecf20Sopenharmony_ci return ret; 25338c2ecf20Sopenharmony_ci } 25348c2ecf20Sopenharmony_ci 25358c2ecf20Sopenharmony_ci if (!auto_gain && ctrls->gain->is_new) 25368c2ecf20Sopenharmony_ci ret = ov5640_set_gain(sensor, ctrls->gain->val); 25378c2ecf20Sopenharmony_ci 25388c2ecf20Sopenharmony_ci return ret; 25398c2ecf20Sopenharmony_ci} 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_cistatic const char * const test_pattern_menu[] = { 25428c2ecf20Sopenharmony_ci "Disabled", 25438c2ecf20Sopenharmony_ci "Color bars", 25448c2ecf20Sopenharmony_ci "Color bars w/ rolling bar", 25458c2ecf20Sopenharmony_ci "Color squares", 25468c2ecf20Sopenharmony_ci "Color squares w/ rolling bar", 25478c2ecf20Sopenharmony_ci}; 25488c2ecf20Sopenharmony_ci 25498c2ecf20Sopenharmony_ci#define OV5640_TEST_ENABLE BIT(7) 25508c2ecf20Sopenharmony_ci#define OV5640_TEST_ROLLING BIT(6) /* rolling horizontal bar */ 25518c2ecf20Sopenharmony_ci#define OV5640_TEST_TRANSPARENT BIT(5) 25528c2ecf20Sopenharmony_ci#define OV5640_TEST_SQUARE_BW BIT(4) /* black & white squares */ 25538c2ecf20Sopenharmony_ci#define OV5640_TEST_BAR_STANDARD (0 << 2) 25548c2ecf20Sopenharmony_ci#define OV5640_TEST_BAR_VERT_CHANGE_1 (1 << 2) 25558c2ecf20Sopenharmony_ci#define OV5640_TEST_BAR_HOR_CHANGE (2 << 2) 25568c2ecf20Sopenharmony_ci#define OV5640_TEST_BAR_VERT_CHANGE_2 (3 << 2) 25578c2ecf20Sopenharmony_ci#define OV5640_TEST_BAR (0 << 0) 25588c2ecf20Sopenharmony_ci#define OV5640_TEST_RANDOM (1 << 0) 25598c2ecf20Sopenharmony_ci#define OV5640_TEST_SQUARE (2 << 0) 25608c2ecf20Sopenharmony_ci#define OV5640_TEST_BLACK (3 << 0) 25618c2ecf20Sopenharmony_ci 25628c2ecf20Sopenharmony_cistatic const u8 test_pattern_val[] = { 25638c2ecf20Sopenharmony_ci 0, 25648c2ecf20Sopenharmony_ci OV5640_TEST_ENABLE | OV5640_TEST_BAR_VERT_CHANGE_1 | 25658c2ecf20Sopenharmony_ci OV5640_TEST_BAR, 25668c2ecf20Sopenharmony_ci OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | 25678c2ecf20Sopenharmony_ci OV5640_TEST_BAR_VERT_CHANGE_1 | OV5640_TEST_BAR, 25688c2ecf20Sopenharmony_ci OV5640_TEST_ENABLE | OV5640_TEST_SQUARE, 25698c2ecf20Sopenharmony_ci OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | OV5640_TEST_SQUARE, 25708c2ecf20Sopenharmony_ci}; 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_cistatic int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value) 25738c2ecf20Sopenharmony_ci{ 25748c2ecf20Sopenharmony_ci return ov5640_write_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1, 25758c2ecf20Sopenharmony_ci test_pattern_val[value]); 25768c2ecf20Sopenharmony_ci} 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_cistatic int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value) 25798c2ecf20Sopenharmony_ci{ 25808c2ecf20Sopenharmony_ci int ret; 25818c2ecf20Sopenharmony_ci 25828c2ecf20Sopenharmony_ci ret = ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL01, BIT(7), 25838c2ecf20Sopenharmony_ci (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) ? 25848c2ecf20Sopenharmony_ci 0 : BIT(7)); 25858c2ecf20Sopenharmony_ci if (ret) 25868c2ecf20Sopenharmony_ci return ret; 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci return ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL00, BIT(2), 25898c2ecf20Sopenharmony_ci (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) ? 25908c2ecf20Sopenharmony_ci BIT(2) : 0); 25918c2ecf20Sopenharmony_ci} 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_cistatic int ov5640_set_ctrl_hflip(struct ov5640_dev *sensor, int value) 25948c2ecf20Sopenharmony_ci{ 25958c2ecf20Sopenharmony_ci /* 25968c2ecf20Sopenharmony_ci * If sensor is mounted upside down, mirror logic is inversed. 25978c2ecf20Sopenharmony_ci * 25988c2ecf20Sopenharmony_ci * Sensor is a BSI (Back Side Illuminated) one, 25998c2ecf20Sopenharmony_ci * so image captured is physically mirrored. 26008c2ecf20Sopenharmony_ci * This is why mirror logic is inversed in 26018c2ecf20Sopenharmony_ci * order to cancel this mirror effect. 26028c2ecf20Sopenharmony_ci */ 26038c2ecf20Sopenharmony_ci 26048c2ecf20Sopenharmony_ci /* 26058c2ecf20Sopenharmony_ci * TIMING TC REG21: 26068c2ecf20Sopenharmony_ci * - [2]: ISP mirror 26078c2ecf20Sopenharmony_ci * - [1]: Sensor mirror 26088c2ecf20Sopenharmony_ci */ 26098c2ecf20Sopenharmony_ci return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21, 26108c2ecf20Sopenharmony_ci BIT(2) | BIT(1), 26118c2ecf20Sopenharmony_ci (!(value ^ sensor->upside_down)) ? 26128c2ecf20Sopenharmony_ci (BIT(2) | BIT(1)) : 0); 26138c2ecf20Sopenharmony_ci} 26148c2ecf20Sopenharmony_ci 26158c2ecf20Sopenharmony_cistatic int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value) 26168c2ecf20Sopenharmony_ci{ 26178c2ecf20Sopenharmony_ci /* If sensor is mounted upside down, flip logic is inversed */ 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci /* 26208c2ecf20Sopenharmony_ci * TIMING TC REG20: 26218c2ecf20Sopenharmony_ci * - [2]: ISP vflip 26228c2ecf20Sopenharmony_ci * - [1]: Sensor vflip 26238c2ecf20Sopenharmony_ci */ 26248c2ecf20Sopenharmony_ci return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20, 26258c2ecf20Sopenharmony_ci BIT(2) | BIT(1), 26268c2ecf20Sopenharmony_ci (value ^ sensor->upside_down) ? 26278c2ecf20Sopenharmony_ci (BIT(2) | BIT(1)) : 0); 26288c2ecf20Sopenharmony_ci} 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_cistatic int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl) 26318c2ecf20Sopenharmony_ci{ 26328c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = ctrl_to_sd(ctrl); 26338c2ecf20Sopenharmony_ci struct ov5640_dev *sensor = to_ov5640_dev(sd); 26348c2ecf20Sopenharmony_ci int val; 26358c2ecf20Sopenharmony_ci 26368c2ecf20Sopenharmony_ci /* v4l2_ctrl_lock() locks our own mutex */ 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci switch (ctrl->id) { 26398c2ecf20Sopenharmony_ci case V4L2_CID_AUTOGAIN: 26408c2ecf20Sopenharmony_ci val = ov5640_get_gain(sensor); 26418c2ecf20Sopenharmony_ci if (val < 0) 26428c2ecf20Sopenharmony_ci return val; 26438c2ecf20Sopenharmony_ci sensor->ctrls.gain->val = val; 26448c2ecf20Sopenharmony_ci break; 26458c2ecf20Sopenharmony_ci case V4L2_CID_EXPOSURE_AUTO: 26468c2ecf20Sopenharmony_ci val = ov5640_get_exposure(sensor); 26478c2ecf20Sopenharmony_ci if (val < 0) 26488c2ecf20Sopenharmony_ci return val; 26498c2ecf20Sopenharmony_ci sensor->ctrls.exposure->val = val; 26508c2ecf20Sopenharmony_ci break; 26518c2ecf20Sopenharmony_ci } 26528c2ecf20Sopenharmony_ci 26538c2ecf20Sopenharmony_ci return 0; 26548c2ecf20Sopenharmony_ci} 26558c2ecf20Sopenharmony_ci 26568c2ecf20Sopenharmony_cistatic int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) 26578c2ecf20Sopenharmony_ci{ 26588c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = ctrl_to_sd(ctrl); 26598c2ecf20Sopenharmony_ci struct ov5640_dev *sensor = to_ov5640_dev(sd); 26608c2ecf20Sopenharmony_ci int ret; 26618c2ecf20Sopenharmony_ci 26628c2ecf20Sopenharmony_ci /* v4l2_ctrl_lock() locks our own mutex */ 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_ci /* 26658c2ecf20Sopenharmony_ci * If the device is not powered up by the host driver do 26668c2ecf20Sopenharmony_ci * not apply any controls to H/W at this time. Instead 26678c2ecf20Sopenharmony_ci * the controls will be restored right after power-up. 26688c2ecf20Sopenharmony_ci */ 26698c2ecf20Sopenharmony_ci if (sensor->power_count == 0) 26708c2ecf20Sopenharmony_ci return 0; 26718c2ecf20Sopenharmony_ci 26728c2ecf20Sopenharmony_ci switch (ctrl->id) { 26738c2ecf20Sopenharmony_ci case V4L2_CID_AUTOGAIN: 26748c2ecf20Sopenharmony_ci ret = ov5640_set_ctrl_gain(sensor, ctrl->val); 26758c2ecf20Sopenharmony_ci break; 26768c2ecf20Sopenharmony_ci case V4L2_CID_EXPOSURE_AUTO: 26778c2ecf20Sopenharmony_ci ret = ov5640_set_ctrl_exposure(sensor, ctrl->val); 26788c2ecf20Sopenharmony_ci break; 26798c2ecf20Sopenharmony_ci case V4L2_CID_AUTO_WHITE_BALANCE: 26808c2ecf20Sopenharmony_ci ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val); 26818c2ecf20Sopenharmony_ci break; 26828c2ecf20Sopenharmony_ci case V4L2_CID_HUE: 26838c2ecf20Sopenharmony_ci ret = ov5640_set_ctrl_hue(sensor, ctrl->val); 26848c2ecf20Sopenharmony_ci break; 26858c2ecf20Sopenharmony_ci case V4L2_CID_CONTRAST: 26868c2ecf20Sopenharmony_ci ret = ov5640_set_ctrl_contrast(sensor, ctrl->val); 26878c2ecf20Sopenharmony_ci break; 26888c2ecf20Sopenharmony_ci case V4L2_CID_SATURATION: 26898c2ecf20Sopenharmony_ci ret = ov5640_set_ctrl_saturation(sensor, ctrl->val); 26908c2ecf20Sopenharmony_ci break; 26918c2ecf20Sopenharmony_ci case V4L2_CID_TEST_PATTERN: 26928c2ecf20Sopenharmony_ci ret = ov5640_set_ctrl_test_pattern(sensor, ctrl->val); 26938c2ecf20Sopenharmony_ci break; 26948c2ecf20Sopenharmony_ci case V4L2_CID_POWER_LINE_FREQUENCY: 26958c2ecf20Sopenharmony_ci ret = ov5640_set_ctrl_light_freq(sensor, ctrl->val); 26968c2ecf20Sopenharmony_ci break; 26978c2ecf20Sopenharmony_ci case V4L2_CID_HFLIP: 26988c2ecf20Sopenharmony_ci ret = ov5640_set_ctrl_hflip(sensor, ctrl->val); 26998c2ecf20Sopenharmony_ci break; 27008c2ecf20Sopenharmony_ci case V4L2_CID_VFLIP: 27018c2ecf20Sopenharmony_ci ret = ov5640_set_ctrl_vflip(sensor, ctrl->val); 27028c2ecf20Sopenharmony_ci break; 27038c2ecf20Sopenharmony_ci default: 27048c2ecf20Sopenharmony_ci ret = -EINVAL; 27058c2ecf20Sopenharmony_ci break; 27068c2ecf20Sopenharmony_ci } 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_ci return ret; 27098c2ecf20Sopenharmony_ci} 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops ov5640_ctrl_ops = { 27128c2ecf20Sopenharmony_ci .g_volatile_ctrl = ov5640_g_volatile_ctrl, 27138c2ecf20Sopenharmony_ci .s_ctrl = ov5640_s_ctrl, 27148c2ecf20Sopenharmony_ci}; 27158c2ecf20Sopenharmony_ci 27168c2ecf20Sopenharmony_cistatic int ov5640_init_controls(struct ov5640_dev *sensor) 27178c2ecf20Sopenharmony_ci{ 27188c2ecf20Sopenharmony_ci const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops; 27198c2ecf20Sopenharmony_ci struct ov5640_ctrls *ctrls = &sensor->ctrls; 27208c2ecf20Sopenharmony_ci struct v4l2_ctrl_handler *hdl = &ctrls->handler; 27218c2ecf20Sopenharmony_ci int ret; 27228c2ecf20Sopenharmony_ci 27238c2ecf20Sopenharmony_ci v4l2_ctrl_handler_init(hdl, 32); 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_ci /* we can use our own mutex for the ctrl lock */ 27268c2ecf20Sopenharmony_ci hdl->lock = &sensor->lock; 27278c2ecf20Sopenharmony_ci 27288c2ecf20Sopenharmony_ci /* Clock related controls */ 27298c2ecf20Sopenharmony_ci ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE, 27308c2ecf20Sopenharmony_ci 0, INT_MAX, 1, 27318c2ecf20Sopenharmony_ci ov5640_calc_pixel_rate(sensor)); 27328c2ecf20Sopenharmony_ci 27338c2ecf20Sopenharmony_ci /* Auto/manual white balance */ 27348c2ecf20Sopenharmony_ci ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops, 27358c2ecf20Sopenharmony_ci V4L2_CID_AUTO_WHITE_BALANCE, 27368c2ecf20Sopenharmony_ci 0, 1, 1, 1); 27378c2ecf20Sopenharmony_ci ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE, 27388c2ecf20Sopenharmony_ci 0, 4095, 1, 0); 27398c2ecf20Sopenharmony_ci ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE, 27408c2ecf20Sopenharmony_ci 0, 4095, 1, 0); 27418c2ecf20Sopenharmony_ci /* Auto/manual exposure */ 27428c2ecf20Sopenharmony_ci ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops, 27438c2ecf20Sopenharmony_ci V4L2_CID_EXPOSURE_AUTO, 27448c2ecf20Sopenharmony_ci V4L2_EXPOSURE_MANUAL, 0, 27458c2ecf20Sopenharmony_ci V4L2_EXPOSURE_AUTO); 27468c2ecf20Sopenharmony_ci ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, 27478c2ecf20Sopenharmony_ci 0, 65535, 1, 0); 27488c2ecf20Sopenharmony_ci /* Auto/manual gain */ 27498c2ecf20Sopenharmony_ci ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN, 27508c2ecf20Sopenharmony_ci 0, 1, 1, 1); 27518c2ecf20Sopenharmony_ci ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN, 27528c2ecf20Sopenharmony_ci 0, 1023, 1, 0); 27538c2ecf20Sopenharmony_ci 27548c2ecf20Sopenharmony_ci ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, 27558c2ecf20Sopenharmony_ci 0, 255, 1, 64); 27568c2ecf20Sopenharmony_ci ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE, 27578c2ecf20Sopenharmony_ci 0, 359, 1, 0); 27588c2ecf20Sopenharmony_ci ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, 27598c2ecf20Sopenharmony_ci 0, 255, 1, 0); 27608c2ecf20Sopenharmony_ci ctrls->test_pattern = 27618c2ecf20Sopenharmony_ci v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN, 27628c2ecf20Sopenharmony_ci ARRAY_SIZE(test_pattern_menu) - 1, 27638c2ecf20Sopenharmony_ci 0, 0, test_pattern_menu); 27648c2ecf20Sopenharmony_ci ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 27658c2ecf20Sopenharmony_ci 0, 1, 1, 0); 27668c2ecf20Sopenharmony_ci ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 27678c2ecf20Sopenharmony_ci 0, 1, 1, 0); 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ci ctrls->light_freq = 27708c2ecf20Sopenharmony_ci v4l2_ctrl_new_std_menu(hdl, ops, 27718c2ecf20Sopenharmony_ci V4L2_CID_POWER_LINE_FREQUENCY, 27728c2ecf20Sopenharmony_ci V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, 27738c2ecf20Sopenharmony_ci V4L2_CID_POWER_LINE_FREQUENCY_50HZ); 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_ci if (hdl->error) { 27768c2ecf20Sopenharmony_ci ret = hdl->error; 27778c2ecf20Sopenharmony_ci goto free_ctrls; 27788c2ecf20Sopenharmony_ci } 27798c2ecf20Sopenharmony_ci 27808c2ecf20Sopenharmony_ci ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY; 27818c2ecf20Sopenharmony_ci ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE; 27828c2ecf20Sopenharmony_ci ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE; 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ci v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false); 27858c2ecf20Sopenharmony_ci v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true); 27868c2ecf20Sopenharmony_ci v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true); 27878c2ecf20Sopenharmony_ci 27888c2ecf20Sopenharmony_ci sensor->sd.ctrl_handler = hdl; 27898c2ecf20Sopenharmony_ci return 0; 27908c2ecf20Sopenharmony_ci 27918c2ecf20Sopenharmony_cifree_ctrls: 27928c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(hdl); 27938c2ecf20Sopenharmony_ci return ret; 27948c2ecf20Sopenharmony_ci} 27958c2ecf20Sopenharmony_ci 27968c2ecf20Sopenharmony_cistatic int ov5640_enum_frame_size(struct v4l2_subdev *sd, 27978c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 27988c2ecf20Sopenharmony_ci struct v4l2_subdev_frame_size_enum *fse) 27998c2ecf20Sopenharmony_ci{ 28008c2ecf20Sopenharmony_ci if (fse->pad != 0) 28018c2ecf20Sopenharmony_ci return -EINVAL; 28028c2ecf20Sopenharmony_ci if (fse->index >= OV5640_NUM_MODES) 28038c2ecf20Sopenharmony_ci return -EINVAL; 28048c2ecf20Sopenharmony_ci 28058c2ecf20Sopenharmony_ci fse->min_width = 28068c2ecf20Sopenharmony_ci ov5640_mode_data[fse->index].hact; 28078c2ecf20Sopenharmony_ci fse->max_width = fse->min_width; 28088c2ecf20Sopenharmony_ci fse->min_height = 28098c2ecf20Sopenharmony_ci ov5640_mode_data[fse->index].vact; 28108c2ecf20Sopenharmony_ci fse->max_height = fse->min_height; 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_ci return 0; 28138c2ecf20Sopenharmony_ci} 28148c2ecf20Sopenharmony_ci 28158c2ecf20Sopenharmony_cistatic int ov5640_enum_frame_interval( 28168c2ecf20Sopenharmony_ci struct v4l2_subdev *sd, 28178c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 28188c2ecf20Sopenharmony_ci struct v4l2_subdev_frame_interval_enum *fie) 28198c2ecf20Sopenharmony_ci{ 28208c2ecf20Sopenharmony_ci struct ov5640_dev *sensor = to_ov5640_dev(sd); 28218c2ecf20Sopenharmony_ci struct v4l2_fract tpf; 28228c2ecf20Sopenharmony_ci int ret; 28238c2ecf20Sopenharmony_ci 28248c2ecf20Sopenharmony_ci if (fie->pad != 0) 28258c2ecf20Sopenharmony_ci return -EINVAL; 28268c2ecf20Sopenharmony_ci if (fie->index >= OV5640_NUM_FRAMERATES) 28278c2ecf20Sopenharmony_ci return -EINVAL; 28288c2ecf20Sopenharmony_ci 28298c2ecf20Sopenharmony_ci tpf.numerator = 1; 28308c2ecf20Sopenharmony_ci tpf.denominator = ov5640_framerates[fie->index]; 28318c2ecf20Sopenharmony_ci 28328c2ecf20Sopenharmony_ci ret = ov5640_try_frame_interval(sensor, &tpf, 28338c2ecf20Sopenharmony_ci fie->width, fie->height); 28348c2ecf20Sopenharmony_ci if (ret < 0) 28358c2ecf20Sopenharmony_ci return -EINVAL; 28368c2ecf20Sopenharmony_ci 28378c2ecf20Sopenharmony_ci fie->interval = tpf; 28388c2ecf20Sopenharmony_ci return 0; 28398c2ecf20Sopenharmony_ci} 28408c2ecf20Sopenharmony_ci 28418c2ecf20Sopenharmony_cistatic int ov5640_g_frame_interval(struct v4l2_subdev *sd, 28428c2ecf20Sopenharmony_ci struct v4l2_subdev_frame_interval *fi) 28438c2ecf20Sopenharmony_ci{ 28448c2ecf20Sopenharmony_ci struct ov5640_dev *sensor = to_ov5640_dev(sd); 28458c2ecf20Sopenharmony_ci 28468c2ecf20Sopenharmony_ci mutex_lock(&sensor->lock); 28478c2ecf20Sopenharmony_ci fi->interval = sensor->frame_interval; 28488c2ecf20Sopenharmony_ci mutex_unlock(&sensor->lock); 28498c2ecf20Sopenharmony_ci 28508c2ecf20Sopenharmony_ci return 0; 28518c2ecf20Sopenharmony_ci} 28528c2ecf20Sopenharmony_ci 28538c2ecf20Sopenharmony_cistatic int ov5640_s_frame_interval(struct v4l2_subdev *sd, 28548c2ecf20Sopenharmony_ci struct v4l2_subdev_frame_interval *fi) 28558c2ecf20Sopenharmony_ci{ 28568c2ecf20Sopenharmony_ci struct ov5640_dev *sensor = to_ov5640_dev(sd); 28578c2ecf20Sopenharmony_ci const struct ov5640_mode_info *mode; 28588c2ecf20Sopenharmony_ci int frame_rate, ret = 0; 28598c2ecf20Sopenharmony_ci 28608c2ecf20Sopenharmony_ci if (fi->pad != 0) 28618c2ecf20Sopenharmony_ci return -EINVAL; 28628c2ecf20Sopenharmony_ci 28638c2ecf20Sopenharmony_ci mutex_lock(&sensor->lock); 28648c2ecf20Sopenharmony_ci 28658c2ecf20Sopenharmony_ci if (sensor->streaming) { 28668c2ecf20Sopenharmony_ci ret = -EBUSY; 28678c2ecf20Sopenharmony_ci goto out; 28688c2ecf20Sopenharmony_ci } 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_ci mode = sensor->current_mode; 28718c2ecf20Sopenharmony_ci 28728c2ecf20Sopenharmony_ci frame_rate = ov5640_try_frame_interval(sensor, &fi->interval, 28738c2ecf20Sopenharmony_ci mode->hact, mode->vact); 28748c2ecf20Sopenharmony_ci if (frame_rate < 0) { 28758c2ecf20Sopenharmony_ci /* Always return a valid frame interval value */ 28768c2ecf20Sopenharmony_ci fi->interval = sensor->frame_interval; 28778c2ecf20Sopenharmony_ci goto out; 28788c2ecf20Sopenharmony_ci } 28798c2ecf20Sopenharmony_ci 28808c2ecf20Sopenharmony_ci mode = ov5640_find_mode(sensor, frame_rate, mode->hact, 28818c2ecf20Sopenharmony_ci mode->vact, true); 28828c2ecf20Sopenharmony_ci if (!mode) { 28838c2ecf20Sopenharmony_ci ret = -EINVAL; 28848c2ecf20Sopenharmony_ci goto out; 28858c2ecf20Sopenharmony_ci } 28868c2ecf20Sopenharmony_ci 28878c2ecf20Sopenharmony_ci if (mode != sensor->current_mode || 28888c2ecf20Sopenharmony_ci frame_rate != sensor->current_fr) { 28898c2ecf20Sopenharmony_ci sensor->current_fr = frame_rate; 28908c2ecf20Sopenharmony_ci sensor->frame_interval = fi->interval; 28918c2ecf20Sopenharmony_ci sensor->current_mode = mode; 28928c2ecf20Sopenharmony_ci sensor->pending_mode_change = true; 28938c2ecf20Sopenharmony_ci 28948c2ecf20Sopenharmony_ci __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, 28958c2ecf20Sopenharmony_ci ov5640_calc_pixel_rate(sensor)); 28968c2ecf20Sopenharmony_ci } 28978c2ecf20Sopenharmony_ciout: 28988c2ecf20Sopenharmony_ci mutex_unlock(&sensor->lock); 28998c2ecf20Sopenharmony_ci return ret; 29008c2ecf20Sopenharmony_ci} 29018c2ecf20Sopenharmony_ci 29028c2ecf20Sopenharmony_cistatic int ov5640_enum_mbus_code(struct v4l2_subdev *sd, 29038c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 29048c2ecf20Sopenharmony_ci struct v4l2_subdev_mbus_code_enum *code) 29058c2ecf20Sopenharmony_ci{ 29068c2ecf20Sopenharmony_ci if (code->pad != 0) 29078c2ecf20Sopenharmony_ci return -EINVAL; 29088c2ecf20Sopenharmony_ci if (code->index >= ARRAY_SIZE(ov5640_formats)) 29098c2ecf20Sopenharmony_ci return -EINVAL; 29108c2ecf20Sopenharmony_ci 29118c2ecf20Sopenharmony_ci code->code = ov5640_formats[code->index].code; 29128c2ecf20Sopenharmony_ci return 0; 29138c2ecf20Sopenharmony_ci} 29148c2ecf20Sopenharmony_ci 29158c2ecf20Sopenharmony_cistatic int ov5640_s_stream(struct v4l2_subdev *sd, int enable) 29168c2ecf20Sopenharmony_ci{ 29178c2ecf20Sopenharmony_ci struct ov5640_dev *sensor = to_ov5640_dev(sd); 29188c2ecf20Sopenharmony_ci int ret = 0; 29198c2ecf20Sopenharmony_ci 29208c2ecf20Sopenharmony_ci mutex_lock(&sensor->lock); 29218c2ecf20Sopenharmony_ci 29228c2ecf20Sopenharmony_ci if (sensor->streaming == !enable) { 29238c2ecf20Sopenharmony_ci if (enable && sensor->pending_mode_change) { 29248c2ecf20Sopenharmony_ci ret = ov5640_set_mode(sensor); 29258c2ecf20Sopenharmony_ci if (ret) 29268c2ecf20Sopenharmony_ci goto out; 29278c2ecf20Sopenharmony_ci } 29288c2ecf20Sopenharmony_ci 29298c2ecf20Sopenharmony_ci if (enable && sensor->pending_fmt_change) { 29308c2ecf20Sopenharmony_ci ret = ov5640_set_framefmt(sensor, &sensor->fmt); 29318c2ecf20Sopenharmony_ci if (ret) 29328c2ecf20Sopenharmony_ci goto out; 29338c2ecf20Sopenharmony_ci sensor->pending_fmt_change = false; 29348c2ecf20Sopenharmony_ci } 29358c2ecf20Sopenharmony_ci 29368c2ecf20Sopenharmony_ci if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY) 29378c2ecf20Sopenharmony_ci ret = ov5640_set_stream_mipi(sensor, enable); 29388c2ecf20Sopenharmony_ci else 29398c2ecf20Sopenharmony_ci ret = ov5640_set_stream_dvp(sensor, enable); 29408c2ecf20Sopenharmony_ci 29418c2ecf20Sopenharmony_ci if (!ret) 29428c2ecf20Sopenharmony_ci sensor->streaming = enable; 29438c2ecf20Sopenharmony_ci } 29448c2ecf20Sopenharmony_ciout: 29458c2ecf20Sopenharmony_ci mutex_unlock(&sensor->lock); 29468c2ecf20Sopenharmony_ci return ret; 29478c2ecf20Sopenharmony_ci} 29488c2ecf20Sopenharmony_ci 29498c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_core_ops ov5640_core_ops = { 29508c2ecf20Sopenharmony_ci .s_power = ov5640_s_power, 29518c2ecf20Sopenharmony_ci .log_status = v4l2_ctrl_subdev_log_status, 29528c2ecf20Sopenharmony_ci .subscribe_event = v4l2_ctrl_subdev_subscribe_event, 29538c2ecf20Sopenharmony_ci .unsubscribe_event = v4l2_event_subdev_unsubscribe, 29548c2ecf20Sopenharmony_ci}; 29558c2ecf20Sopenharmony_ci 29568c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_video_ops ov5640_video_ops = { 29578c2ecf20Sopenharmony_ci .g_frame_interval = ov5640_g_frame_interval, 29588c2ecf20Sopenharmony_ci .s_frame_interval = ov5640_s_frame_interval, 29598c2ecf20Sopenharmony_ci .s_stream = ov5640_s_stream, 29608c2ecf20Sopenharmony_ci}; 29618c2ecf20Sopenharmony_ci 29628c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_pad_ops ov5640_pad_ops = { 29638c2ecf20Sopenharmony_ci .enum_mbus_code = ov5640_enum_mbus_code, 29648c2ecf20Sopenharmony_ci .get_fmt = ov5640_get_fmt, 29658c2ecf20Sopenharmony_ci .set_fmt = ov5640_set_fmt, 29668c2ecf20Sopenharmony_ci .enum_frame_size = ov5640_enum_frame_size, 29678c2ecf20Sopenharmony_ci .enum_frame_interval = ov5640_enum_frame_interval, 29688c2ecf20Sopenharmony_ci}; 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_ops ov5640_subdev_ops = { 29718c2ecf20Sopenharmony_ci .core = &ov5640_core_ops, 29728c2ecf20Sopenharmony_ci .video = &ov5640_video_ops, 29738c2ecf20Sopenharmony_ci .pad = &ov5640_pad_ops, 29748c2ecf20Sopenharmony_ci}; 29758c2ecf20Sopenharmony_ci 29768c2ecf20Sopenharmony_cistatic int ov5640_get_regulators(struct ov5640_dev *sensor) 29778c2ecf20Sopenharmony_ci{ 29788c2ecf20Sopenharmony_ci int i; 29798c2ecf20Sopenharmony_ci 29808c2ecf20Sopenharmony_ci for (i = 0; i < OV5640_NUM_SUPPLIES; i++) 29818c2ecf20Sopenharmony_ci sensor->supplies[i].supply = ov5640_supply_name[i]; 29828c2ecf20Sopenharmony_ci 29838c2ecf20Sopenharmony_ci return devm_regulator_bulk_get(&sensor->i2c_client->dev, 29848c2ecf20Sopenharmony_ci OV5640_NUM_SUPPLIES, 29858c2ecf20Sopenharmony_ci sensor->supplies); 29868c2ecf20Sopenharmony_ci} 29878c2ecf20Sopenharmony_ci 29888c2ecf20Sopenharmony_cistatic int ov5640_check_chip_id(struct ov5640_dev *sensor) 29898c2ecf20Sopenharmony_ci{ 29908c2ecf20Sopenharmony_ci struct i2c_client *client = sensor->i2c_client; 29918c2ecf20Sopenharmony_ci int ret = 0; 29928c2ecf20Sopenharmony_ci u16 chip_id; 29938c2ecf20Sopenharmony_ci 29948c2ecf20Sopenharmony_ci ret = ov5640_set_power_on(sensor); 29958c2ecf20Sopenharmony_ci if (ret) 29968c2ecf20Sopenharmony_ci return ret; 29978c2ecf20Sopenharmony_ci 29988c2ecf20Sopenharmony_ci ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id); 29998c2ecf20Sopenharmony_ci if (ret) { 30008c2ecf20Sopenharmony_ci dev_err(&client->dev, "%s: failed to read chip identifier\n", 30018c2ecf20Sopenharmony_ci __func__); 30028c2ecf20Sopenharmony_ci goto power_off; 30038c2ecf20Sopenharmony_ci } 30048c2ecf20Sopenharmony_ci 30058c2ecf20Sopenharmony_ci if (chip_id != 0x5640) { 30068c2ecf20Sopenharmony_ci dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n", 30078c2ecf20Sopenharmony_ci __func__, chip_id); 30088c2ecf20Sopenharmony_ci ret = -ENXIO; 30098c2ecf20Sopenharmony_ci } 30108c2ecf20Sopenharmony_ci 30118c2ecf20Sopenharmony_cipower_off: 30128c2ecf20Sopenharmony_ci ov5640_set_power_off(sensor); 30138c2ecf20Sopenharmony_ci return ret; 30148c2ecf20Sopenharmony_ci} 30158c2ecf20Sopenharmony_ci 30168c2ecf20Sopenharmony_cistatic int ov5640_probe(struct i2c_client *client) 30178c2ecf20Sopenharmony_ci{ 30188c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 30198c2ecf20Sopenharmony_ci struct fwnode_handle *endpoint; 30208c2ecf20Sopenharmony_ci struct ov5640_dev *sensor; 30218c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *fmt; 30228c2ecf20Sopenharmony_ci u32 rotation; 30238c2ecf20Sopenharmony_ci int ret; 30248c2ecf20Sopenharmony_ci 30258c2ecf20Sopenharmony_ci sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); 30268c2ecf20Sopenharmony_ci if (!sensor) 30278c2ecf20Sopenharmony_ci return -ENOMEM; 30288c2ecf20Sopenharmony_ci 30298c2ecf20Sopenharmony_ci sensor->i2c_client = client; 30308c2ecf20Sopenharmony_ci 30318c2ecf20Sopenharmony_ci /* 30328c2ecf20Sopenharmony_ci * default init sequence initialize sensor to 30338c2ecf20Sopenharmony_ci * YUV422 UYVY VGA@30fps 30348c2ecf20Sopenharmony_ci */ 30358c2ecf20Sopenharmony_ci fmt = &sensor->fmt; 30368c2ecf20Sopenharmony_ci fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; 30378c2ecf20Sopenharmony_ci fmt->colorspace = V4L2_COLORSPACE_SRGB; 30388c2ecf20Sopenharmony_ci fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); 30398c2ecf20Sopenharmony_ci fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; 30408c2ecf20Sopenharmony_ci fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace); 30418c2ecf20Sopenharmony_ci fmt->width = 640; 30428c2ecf20Sopenharmony_ci fmt->height = 480; 30438c2ecf20Sopenharmony_ci fmt->field = V4L2_FIELD_NONE; 30448c2ecf20Sopenharmony_ci sensor->frame_interval.numerator = 1; 30458c2ecf20Sopenharmony_ci sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS]; 30468c2ecf20Sopenharmony_ci sensor->current_fr = OV5640_30_FPS; 30478c2ecf20Sopenharmony_ci sensor->current_mode = 30488c2ecf20Sopenharmony_ci &ov5640_mode_data[OV5640_MODE_VGA_640_480]; 30498c2ecf20Sopenharmony_ci sensor->last_mode = sensor->current_mode; 30508c2ecf20Sopenharmony_ci 30518c2ecf20Sopenharmony_ci sensor->ae_target = 52; 30528c2ecf20Sopenharmony_ci 30538c2ecf20Sopenharmony_ci /* optional indication of physical rotation of sensor */ 30548c2ecf20Sopenharmony_ci ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation", 30558c2ecf20Sopenharmony_ci &rotation); 30568c2ecf20Sopenharmony_ci if (!ret) { 30578c2ecf20Sopenharmony_ci switch (rotation) { 30588c2ecf20Sopenharmony_ci case 180: 30598c2ecf20Sopenharmony_ci sensor->upside_down = true; 30608c2ecf20Sopenharmony_ci fallthrough; 30618c2ecf20Sopenharmony_ci case 0: 30628c2ecf20Sopenharmony_ci break; 30638c2ecf20Sopenharmony_ci default: 30648c2ecf20Sopenharmony_ci dev_warn(dev, "%u degrees rotation is not supported, ignoring...\n", 30658c2ecf20Sopenharmony_ci rotation); 30668c2ecf20Sopenharmony_ci } 30678c2ecf20Sopenharmony_ci } 30688c2ecf20Sopenharmony_ci 30698c2ecf20Sopenharmony_ci endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), 30708c2ecf20Sopenharmony_ci NULL); 30718c2ecf20Sopenharmony_ci if (!endpoint) { 30728c2ecf20Sopenharmony_ci dev_err(dev, "endpoint node not found\n"); 30738c2ecf20Sopenharmony_ci return -EINVAL; 30748c2ecf20Sopenharmony_ci } 30758c2ecf20Sopenharmony_ci 30768c2ecf20Sopenharmony_ci ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep); 30778c2ecf20Sopenharmony_ci fwnode_handle_put(endpoint); 30788c2ecf20Sopenharmony_ci if (ret) { 30798c2ecf20Sopenharmony_ci dev_err(dev, "Could not parse endpoint\n"); 30808c2ecf20Sopenharmony_ci return ret; 30818c2ecf20Sopenharmony_ci } 30828c2ecf20Sopenharmony_ci 30838c2ecf20Sopenharmony_ci if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL && 30848c2ecf20Sopenharmony_ci sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY && 30858c2ecf20Sopenharmony_ci sensor->ep.bus_type != V4L2_MBUS_BT656) { 30868c2ecf20Sopenharmony_ci dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type); 30878c2ecf20Sopenharmony_ci return -EINVAL; 30888c2ecf20Sopenharmony_ci } 30898c2ecf20Sopenharmony_ci 30908c2ecf20Sopenharmony_ci /* get system clock (xclk) */ 30918c2ecf20Sopenharmony_ci sensor->xclk = devm_clk_get(dev, "xclk"); 30928c2ecf20Sopenharmony_ci if (IS_ERR(sensor->xclk)) { 30938c2ecf20Sopenharmony_ci dev_err(dev, "failed to get xclk\n"); 30948c2ecf20Sopenharmony_ci return PTR_ERR(sensor->xclk); 30958c2ecf20Sopenharmony_ci } 30968c2ecf20Sopenharmony_ci 30978c2ecf20Sopenharmony_ci sensor->xclk_freq = clk_get_rate(sensor->xclk); 30988c2ecf20Sopenharmony_ci if (sensor->xclk_freq < OV5640_XCLK_MIN || 30998c2ecf20Sopenharmony_ci sensor->xclk_freq > OV5640_XCLK_MAX) { 31008c2ecf20Sopenharmony_ci dev_err(dev, "xclk frequency out of range: %d Hz\n", 31018c2ecf20Sopenharmony_ci sensor->xclk_freq); 31028c2ecf20Sopenharmony_ci return -EINVAL; 31038c2ecf20Sopenharmony_ci } 31048c2ecf20Sopenharmony_ci 31058c2ecf20Sopenharmony_ci /* request optional power down pin */ 31068c2ecf20Sopenharmony_ci sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown", 31078c2ecf20Sopenharmony_ci GPIOD_OUT_HIGH); 31088c2ecf20Sopenharmony_ci if (IS_ERR(sensor->pwdn_gpio)) 31098c2ecf20Sopenharmony_ci return PTR_ERR(sensor->pwdn_gpio); 31108c2ecf20Sopenharmony_ci 31118c2ecf20Sopenharmony_ci /* request optional reset pin */ 31128c2ecf20Sopenharmony_ci sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset", 31138c2ecf20Sopenharmony_ci GPIOD_OUT_HIGH); 31148c2ecf20Sopenharmony_ci if (IS_ERR(sensor->reset_gpio)) 31158c2ecf20Sopenharmony_ci return PTR_ERR(sensor->reset_gpio); 31168c2ecf20Sopenharmony_ci 31178c2ecf20Sopenharmony_ci v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops); 31188c2ecf20Sopenharmony_ci 31198c2ecf20Sopenharmony_ci sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | 31208c2ecf20Sopenharmony_ci V4L2_SUBDEV_FL_HAS_EVENTS; 31218c2ecf20Sopenharmony_ci sensor->pad.flags = MEDIA_PAD_FL_SOURCE; 31228c2ecf20Sopenharmony_ci sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; 31238c2ecf20Sopenharmony_ci ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); 31248c2ecf20Sopenharmony_ci if (ret) 31258c2ecf20Sopenharmony_ci return ret; 31268c2ecf20Sopenharmony_ci 31278c2ecf20Sopenharmony_ci ret = ov5640_get_regulators(sensor); 31288c2ecf20Sopenharmony_ci if (ret) 31298c2ecf20Sopenharmony_ci return ret; 31308c2ecf20Sopenharmony_ci 31318c2ecf20Sopenharmony_ci mutex_init(&sensor->lock); 31328c2ecf20Sopenharmony_ci 31338c2ecf20Sopenharmony_ci ret = ov5640_check_chip_id(sensor); 31348c2ecf20Sopenharmony_ci if (ret) 31358c2ecf20Sopenharmony_ci goto entity_cleanup; 31368c2ecf20Sopenharmony_ci 31378c2ecf20Sopenharmony_ci ret = ov5640_init_controls(sensor); 31388c2ecf20Sopenharmony_ci if (ret) 31398c2ecf20Sopenharmony_ci goto entity_cleanup; 31408c2ecf20Sopenharmony_ci 31418c2ecf20Sopenharmony_ci ret = v4l2_async_register_subdev_sensor_common(&sensor->sd); 31428c2ecf20Sopenharmony_ci if (ret) 31438c2ecf20Sopenharmony_ci goto free_ctrls; 31448c2ecf20Sopenharmony_ci 31458c2ecf20Sopenharmony_ci return 0; 31468c2ecf20Sopenharmony_ci 31478c2ecf20Sopenharmony_cifree_ctrls: 31488c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&sensor->ctrls.handler); 31498c2ecf20Sopenharmony_cientity_cleanup: 31508c2ecf20Sopenharmony_ci media_entity_cleanup(&sensor->sd.entity); 31518c2ecf20Sopenharmony_ci mutex_destroy(&sensor->lock); 31528c2ecf20Sopenharmony_ci return ret; 31538c2ecf20Sopenharmony_ci} 31548c2ecf20Sopenharmony_ci 31558c2ecf20Sopenharmony_cistatic int ov5640_remove(struct i2c_client *client) 31568c2ecf20Sopenharmony_ci{ 31578c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = i2c_get_clientdata(client); 31588c2ecf20Sopenharmony_ci struct ov5640_dev *sensor = to_ov5640_dev(sd); 31598c2ecf20Sopenharmony_ci 31608c2ecf20Sopenharmony_ci v4l2_async_unregister_subdev(&sensor->sd); 31618c2ecf20Sopenharmony_ci media_entity_cleanup(&sensor->sd.entity); 31628c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&sensor->ctrls.handler); 31638c2ecf20Sopenharmony_ci mutex_destroy(&sensor->lock); 31648c2ecf20Sopenharmony_ci 31658c2ecf20Sopenharmony_ci return 0; 31668c2ecf20Sopenharmony_ci} 31678c2ecf20Sopenharmony_ci 31688c2ecf20Sopenharmony_cistatic const struct i2c_device_id ov5640_id[] = { 31698c2ecf20Sopenharmony_ci {"ov5640", 0}, 31708c2ecf20Sopenharmony_ci {}, 31718c2ecf20Sopenharmony_ci}; 31728c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, ov5640_id); 31738c2ecf20Sopenharmony_ci 31748c2ecf20Sopenharmony_cistatic const struct of_device_id ov5640_dt_ids[] = { 31758c2ecf20Sopenharmony_ci { .compatible = "ovti,ov5640" }, 31768c2ecf20Sopenharmony_ci { /* sentinel */ } 31778c2ecf20Sopenharmony_ci}; 31788c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ov5640_dt_ids); 31798c2ecf20Sopenharmony_ci 31808c2ecf20Sopenharmony_cistatic struct i2c_driver ov5640_i2c_driver = { 31818c2ecf20Sopenharmony_ci .driver = { 31828c2ecf20Sopenharmony_ci .name = "ov5640", 31838c2ecf20Sopenharmony_ci .of_match_table = ov5640_dt_ids, 31848c2ecf20Sopenharmony_ci }, 31858c2ecf20Sopenharmony_ci .id_table = ov5640_id, 31868c2ecf20Sopenharmony_ci .probe_new = ov5640_probe, 31878c2ecf20Sopenharmony_ci .remove = ov5640_remove, 31888c2ecf20Sopenharmony_ci}; 31898c2ecf20Sopenharmony_ci 31908c2ecf20Sopenharmony_cimodule_i2c_driver(ov5640_i2c_driver); 31918c2ecf20Sopenharmony_ci 31928c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("OV5640 MIPI Camera Subdev Driver"); 31938c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 3194