111c0d8fdSPaul Kocialkowski // SPDX-License-Identifier: GPL-2.0-or-later 211c0d8fdSPaul Kocialkowski /* 311c0d8fdSPaul Kocialkowski * Copyright 2020 Kévin L'hôpital <kevin.lhopital@bootlin.com> 411c0d8fdSPaul Kocialkowski * Copyright 2020 Bootlin 511c0d8fdSPaul Kocialkowski * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com> 611c0d8fdSPaul Kocialkowski */ 711c0d8fdSPaul Kocialkowski 811c0d8fdSPaul Kocialkowski #include <linux/clk.h> 911c0d8fdSPaul Kocialkowski #include <linux/delay.h> 1011c0d8fdSPaul Kocialkowski #include <linux/device.h> 1111c0d8fdSPaul Kocialkowski #include <linux/i2c.h> 1211c0d8fdSPaul Kocialkowski #include <linux/module.h> 1311c0d8fdSPaul Kocialkowski #include <linux/of_graph.h> 1411c0d8fdSPaul Kocialkowski #include <linux/pm_runtime.h> 1511c0d8fdSPaul Kocialkowski #include <linux/regulator/consumer.h> 1611c0d8fdSPaul Kocialkowski #include <linux/videodev2.h> 1711c0d8fdSPaul Kocialkowski #include <media/v4l2-ctrls.h> 1811c0d8fdSPaul Kocialkowski #include <media/v4l2-device.h> 1911c0d8fdSPaul Kocialkowski #include <media/v4l2-fwnode.h> 2011c0d8fdSPaul Kocialkowski #include <media/v4l2-image-sizes.h> 2111c0d8fdSPaul Kocialkowski #include <media/v4l2-mediabus.h> 2211c0d8fdSPaul Kocialkowski 2311c0d8fdSPaul Kocialkowski /* Clock rate */ 2411c0d8fdSPaul Kocialkowski 2511c0d8fdSPaul Kocialkowski #define OV8865_EXTCLK_RATE 24000000 2611c0d8fdSPaul Kocialkowski 2711c0d8fdSPaul Kocialkowski /* Register definitions */ 2811c0d8fdSPaul Kocialkowski 2911c0d8fdSPaul Kocialkowski /* System */ 3011c0d8fdSPaul Kocialkowski 3111c0d8fdSPaul Kocialkowski #define OV8865_SW_STANDBY_REG 0x100 3211c0d8fdSPaul Kocialkowski #define OV8865_SW_STANDBY_STREAM_ON BIT(0) 3311c0d8fdSPaul Kocialkowski 3411c0d8fdSPaul Kocialkowski #define OV8865_SW_RESET_REG 0x103 3511c0d8fdSPaul Kocialkowski #define OV8865_SW_RESET_RESET BIT(0) 3611c0d8fdSPaul Kocialkowski 3711c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL0_REG 0x300 3811c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL0_PRE_DIV(v) ((v) & GENMASK(2, 0)) 3911c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL1_REG 0x301 4011c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL1_MUL_H(v) (((v) & GENMASK(9, 8)) >> 8) 4111c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL2_REG 0x302 4211c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL2_MUL_L(v) ((v) & GENMASK(7, 0)) 4311c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL3_REG 0x303 4411c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL3_M_DIV(v) (((v) - 1) & GENMASK(3, 0)) 4511c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL4_REG 0x304 4611c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL4_MIPI_DIV(v) ((v) & GENMASK(1, 0)) 4711c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL5_REG 0x305 4811c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL5_SYS_PRE_DIV(v) ((v) & GENMASK(1, 0)) 4911c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL6_REG 0x306 5011c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL6_SYS_DIV(v) (((v) - 1) & BIT(0)) 5111c0d8fdSPaul Kocialkowski 5211c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL8_REG 0x308 5311c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL9_REG 0x309 5411c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRLA_REG 0x30a 5511c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRLA_PRE_DIV_HALF(v) (((v) - 1) & BIT(0)) 5611c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRLB_REG 0x30b 5711c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRLB_PRE_DIV(v) ((v) & GENMASK(2, 0)) 5811c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRLC_REG 0x30c 5911c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRLC_MUL_H(v) (((v) & GENMASK(9, 8)) >> 8) 6011c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRLD_REG 0x30d 6111c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRLD_MUL_L(v) ((v) & GENMASK(7, 0)) 6211c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRLE_REG 0x30e 6311c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRLE_SYS_DIV(v) ((v) & GENMASK(2, 0)) 6411c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRLF_REG 0x30f 6511c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRLF_SYS_PRE_DIV(v) (((v) - 1) & GENMASK(3, 0)) 6611c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL10_REG 0x310 6711c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL11_REG 0x311 6811c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL12_REG 0x312 6911c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL12_PRE_DIV_HALF(v) ((((v) - 1) << 4) & BIT(4)) 7011c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL12_DAC_DIV(v) (((v) - 1) & GENMASK(3, 0)) 7111c0d8fdSPaul Kocialkowski 7211c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL1B_REG 0x31b 7311c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL1C_REG 0x31c 7411c0d8fdSPaul Kocialkowski 7511c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL1E_REG 0x31e 7611c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL1E_PLL1_NO_LAT BIT(3) 7711c0d8fdSPaul Kocialkowski 7811c0d8fdSPaul Kocialkowski #define OV8865_PAD_OEN0_REG 0x3000 7911c0d8fdSPaul Kocialkowski 8011c0d8fdSPaul Kocialkowski #define OV8865_PAD_OEN2_REG 0x3002 8111c0d8fdSPaul Kocialkowski 8211c0d8fdSPaul Kocialkowski #define OV8865_CLK_RST5_REG 0x3005 8311c0d8fdSPaul Kocialkowski 8411c0d8fdSPaul Kocialkowski #define OV8865_CHIP_ID_HH_REG 0x300a 8511c0d8fdSPaul Kocialkowski #define OV8865_CHIP_ID_HH_VALUE 0x00 8611c0d8fdSPaul Kocialkowski #define OV8865_CHIP_ID_H_REG 0x300b 8711c0d8fdSPaul Kocialkowski #define OV8865_CHIP_ID_H_VALUE 0x88 8811c0d8fdSPaul Kocialkowski #define OV8865_CHIP_ID_L_REG 0x300c 8911c0d8fdSPaul Kocialkowski #define OV8865_CHIP_ID_L_VALUE 0x65 9011c0d8fdSPaul Kocialkowski #define OV8865_PAD_OUT2_REG 0x300d 9111c0d8fdSPaul Kocialkowski 9211c0d8fdSPaul Kocialkowski #define OV8865_PAD_SEL2_REG 0x3010 9311c0d8fdSPaul Kocialkowski #define OV8865_PAD_PK_REG 0x3011 9411c0d8fdSPaul Kocialkowski #define OV8865_PAD_PK_DRIVE_STRENGTH_1X (0 << 5) 9511c0d8fdSPaul Kocialkowski #define OV8865_PAD_PK_DRIVE_STRENGTH_2X (1 << 5) 9611c0d8fdSPaul Kocialkowski #define OV8865_PAD_PK_DRIVE_STRENGTH_3X (2 << 5) 9711c0d8fdSPaul Kocialkowski #define OV8865_PAD_PK_DRIVE_STRENGTH_4X (3 << 5) 9811c0d8fdSPaul Kocialkowski 9911c0d8fdSPaul Kocialkowski #define OV8865_PUMP_CLK_DIV_REG 0x3015 10011c0d8fdSPaul Kocialkowski #define OV8865_PUMP_CLK_DIV_PUMP_N(v) (((v) << 4) & GENMASK(6, 4)) 10111c0d8fdSPaul Kocialkowski #define OV8865_PUMP_CLK_DIV_PUMP_P(v) ((v) & GENMASK(2, 0)) 10211c0d8fdSPaul Kocialkowski 10311c0d8fdSPaul Kocialkowski #define OV8865_MIPI_SC_CTRL0_REG 0x3018 10411c0d8fdSPaul Kocialkowski #define OV8865_MIPI_SC_CTRL0_LANES(v) ((((v) - 1) << 5) & \ 10511c0d8fdSPaul Kocialkowski GENMASK(7, 5)) 10611c0d8fdSPaul Kocialkowski #define OV8865_MIPI_SC_CTRL0_MIPI_EN BIT(4) 10711c0d8fdSPaul Kocialkowski #define OV8865_MIPI_SC_CTRL0_UNKNOWN BIT(1) 10811c0d8fdSPaul Kocialkowski #define OV8865_MIPI_SC_CTRL0_LANES_PD_MIPI BIT(0) 10911c0d8fdSPaul Kocialkowski #define OV8865_MIPI_SC_CTRL1_REG 0x3019 11011c0d8fdSPaul Kocialkowski #define OV8865_CLK_RST0_REG 0x301a 11111c0d8fdSPaul Kocialkowski #define OV8865_CLK_RST1_REG 0x301b 11211c0d8fdSPaul Kocialkowski #define OV8865_CLK_RST2_REG 0x301c 11311c0d8fdSPaul Kocialkowski #define OV8865_CLK_RST3_REG 0x301d 11411c0d8fdSPaul Kocialkowski #define OV8865_CLK_RST4_REG 0x301e 11511c0d8fdSPaul Kocialkowski 11611c0d8fdSPaul Kocialkowski #define OV8865_PCLK_SEL_REG 0x3020 11711c0d8fdSPaul Kocialkowski #define OV8865_PCLK_SEL_PCLK_DIV_MASK BIT(3) 11811c0d8fdSPaul Kocialkowski #define OV8865_PCLK_SEL_PCLK_DIV(v) ((((v) - 1) << 3) & BIT(3)) 11911c0d8fdSPaul Kocialkowski 12011c0d8fdSPaul Kocialkowski #define OV8865_MISC_CTRL_REG 0x3021 12111c0d8fdSPaul Kocialkowski #define OV8865_MIPI_SC_CTRL2_REG 0x3022 12211c0d8fdSPaul Kocialkowski #define OV8865_MIPI_SC_CTRL2_CLK_LANES_PD_MIPI BIT(1) 12311c0d8fdSPaul Kocialkowski #define OV8865_MIPI_SC_CTRL2_PD_MIPI_RST_SYNC BIT(0) 12411c0d8fdSPaul Kocialkowski 12511c0d8fdSPaul Kocialkowski #define OV8865_MIPI_BIT_SEL_REG 0x3031 12611c0d8fdSPaul Kocialkowski #define OV8865_MIPI_BIT_SEL(v) (((v) << 0) & GENMASK(4, 0)) 12711c0d8fdSPaul Kocialkowski #define OV8865_CLK_SEL0_REG 0x3032 12811c0d8fdSPaul Kocialkowski #define OV8865_CLK_SEL0_PLL1_SYS_SEL(v) (((v) << 7) & BIT(7)) 12911c0d8fdSPaul Kocialkowski #define OV8865_CLK_SEL1_REG 0x3033 13011c0d8fdSPaul Kocialkowski #define OV8865_CLK_SEL1_MIPI_EOF BIT(5) 13111c0d8fdSPaul Kocialkowski #define OV8865_CLK_SEL1_UNKNOWN BIT(2) 13211c0d8fdSPaul Kocialkowski #define OV8865_CLK_SEL1_PLL_SCLK_SEL_MASK BIT(1) 13311c0d8fdSPaul Kocialkowski #define OV8865_CLK_SEL1_PLL_SCLK_SEL(v) (((v) << 1) & BIT(1)) 13411c0d8fdSPaul Kocialkowski 13511c0d8fdSPaul Kocialkowski #define OV8865_SCLK_CTRL_REG 0x3106 13611c0d8fdSPaul Kocialkowski #define OV8865_SCLK_CTRL_SCLK_DIV(v) (((v) << 4) & GENMASK(7, 4)) 13711c0d8fdSPaul Kocialkowski #define OV8865_SCLK_CTRL_SCLK_PRE_DIV(v) (((v) << 2) & GENMASK(3, 2)) 13811c0d8fdSPaul Kocialkowski #define OV8865_SCLK_CTRL_UNKNOWN BIT(0) 13911c0d8fdSPaul Kocialkowski 14011c0d8fdSPaul Kocialkowski /* Exposure/gain */ 14111c0d8fdSPaul Kocialkowski 14211c0d8fdSPaul Kocialkowski #define OV8865_EXPOSURE_CTRL_HH_REG 0x3500 14311c0d8fdSPaul Kocialkowski #define OV8865_EXPOSURE_CTRL_HH(v) (((v) & GENMASK(19, 16)) >> 16) 14411c0d8fdSPaul Kocialkowski #define OV8865_EXPOSURE_CTRL_H_REG 0x3501 14511c0d8fdSPaul Kocialkowski #define OV8865_EXPOSURE_CTRL_H(v) (((v) & GENMASK(15, 8)) >> 8) 14611c0d8fdSPaul Kocialkowski #define OV8865_EXPOSURE_CTRL_L_REG 0x3502 14711c0d8fdSPaul Kocialkowski #define OV8865_EXPOSURE_CTRL_L(v) ((v) & GENMASK(7, 0)) 14811c0d8fdSPaul Kocialkowski #define OV8865_EXPOSURE_GAIN_MANUAL_REG 0x3503 14911c0d8fdSPaul Kocialkowski 15011c0d8fdSPaul Kocialkowski #define OV8865_GAIN_CTRL_H_REG 0x3508 15111c0d8fdSPaul Kocialkowski #define OV8865_GAIN_CTRL_H(v) (((v) & GENMASK(12, 8)) >> 8) 15211c0d8fdSPaul Kocialkowski #define OV8865_GAIN_CTRL_L_REG 0x3509 15311c0d8fdSPaul Kocialkowski #define OV8865_GAIN_CTRL_L(v) ((v) & GENMASK(7, 0)) 15411c0d8fdSPaul Kocialkowski 15511c0d8fdSPaul Kocialkowski /* Timing */ 15611c0d8fdSPaul Kocialkowski 15711c0d8fdSPaul Kocialkowski #define OV8865_CROP_START_X_H_REG 0x3800 15811c0d8fdSPaul Kocialkowski #define OV8865_CROP_START_X_H(v) (((v) & GENMASK(11, 8)) >> 8) 15911c0d8fdSPaul Kocialkowski #define OV8865_CROP_START_X_L_REG 0x3801 16011c0d8fdSPaul Kocialkowski #define OV8865_CROP_START_X_L(v) ((v) & GENMASK(7, 0)) 16111c0d8fdSPaul Kocialkowski #define OV8865_CROP_START_Y_H_REG 0x3802 16211c0d8fdSPaul Kocialkowski #define OV8865_CROP_START_Y_H(v) (((v) & GENMASK(11, 8)) >> 8) 16311c0d8fdSPaul Kocialkowski #define OV8865_CROP_START_Y_L_REG 0x3803 16411c0d8fdSPaul Kocialkowski #define OV8865_CROP_START_Y_L(v) ((v) & GENMASK(7, 0)) 16511c0d8fdSPaul Kocialkowski #define OV8865_CROP_END_X_H_REG 0x3804 16611c0d8fdSPaul Kocialkowski #define OV8865_CROP_END_X_H(v) (((v) & GENMASK(11, 8)) >> 8) 16711c0d8fdSPaul Kocialkowski #define OV8865_CROP_END_X_L_REG 0x3805 16811c0d8fdSPaul Kocialkowski #define OV8865_CROP_END_X_L(v) ((v) & GENMASK(7, 0)) 16911c0d8fdSPaul Kocialkowski #define OV8865_CROP_END_Y_H_REG 0x3806 17011c0d8fdSPaul Kocialkowski #define OV8865_CROP_END_Y_H(v) (((v) & GENMASK(11, 8)) >> 8) 17111c0d8fdSPaul Kocialkowski #define OV8865_CROP_END_Y_L_REG 0x3807 17211c0d8fdSPaul Kocialkowski #define OV8865_CROP_END_Y_L(v) ((v) & GENMASK(7, 0)) 17311c0d8fdSPaul Kocialkowski #define OV8865_OUTPUT_SIZE_X_H_REG 0x3808 17411c0d8fdSPaul Kocialkowski #define OV8865_OUTPUT_SIZE_X_H(v) (((v) & GENMASK(11, 8)) >> 8) 17511c0d8fdSPaul Kocialkowski #define OV8865_OUTPUT_SIZE_X_L_REG 0x3809 17611c0d8fdSPaul Kocialkowski #define OV8865_OUTPUT_SIZE_X_L(v) ((v) & GENMASK(7, 0)) 17711c0d8fdSPaul Kocialkowski #define OV8865_OUTPUT_SIZE_Y_H_REG 0x380a 17811c0d8fdSPaul Kocialkowski #define OV8865_OUTPUT_SIZE_Y_H(v) (((v) & GENMASK(11, 8)) >> 8) 17911c0d8fdSPaul Kocialkowski #define OV8865_OUTPUT_SIZE_Y_L_REG 0x380b 18011c0d8fdSPaul Kocialkowski #define OV8865_OUTPUT_SIZE_Y_L(v) ((v) & GENMASK(7, 0)) 18111c0d8fdSPaul Kocialkowski #define OV8865_HTS_H_REG 0x380c 18211c0d8fdSPaul Kocialkowski #define OV8865_HTS_H(v) (((v) & GENMASK(11, 8)) >> 8) 18311c0d8fdSPaul Kocialkowski #define OV8865_HTS_L_REG 0x380d 18411c0d8fdSPaul Kocialkowski #define OV8865_HTS_L(v) ((v) & GENMASK(7, 0)) 18511c0d8fdSPaul Kocialkowski #define OV8865_VTS_H_REG 0x380e 18611c0d8fdSPaul Kocialkowski #define OV8865_VTS_H(v) (((v) & GENMASK(11, 8)) >> 8) 18711c0d8fdSPaul Kocialkowski #define OV8865_VTS_L_REG 0x380f 18811c0d8fdSPaul Kocialkowski #define OV8865_VTS_L(v) ((v) & GENMASK(7, 0)) 18911c0d8fdSPaul Kocialkowski #define OV8865_OFFSET_X_H_REG 0x3810 19011c0d8fdSPaul Kocialkowski #define OV8865_OFFSET_X_H(v) (((v) & GENMASK(15, 8)) >> 8) 19111c0d8fdSPaul Kocialkowski #define OV8865_OFFSET_X_L_REG 0x3811 19211c0d8fdSPaul Kocialkowski #define OV8865_OFFSET_X_L(v) ((v) & GENMASK(7, 0)) 19311c0d8fdSPaul Kocialkowski #define OV8865_OFFSET_Y_H_REG 0x3812 19411c0d8fdSPaul Kocialkowski #define OV8865_OFFSET_Y_H(v) (((v) & GENMASK(14, 8)) >> 8) 19511c0d8fdSPaul Kocialkowski #define OV8865_OFFSET_Y_L_REG 0x3813 19611c0d8fdSPaul Kocialkowski #define OV8865_OFFSET_Y_L(v) ((v) & GENMASK(7, 0)) 19711c0d8fdSPaul Kocialkowski #define OV8865_INC_X_ODD_REG 0x3814 19811c0d8fdSPaul Kocialkowski #define OV8865_INC_X_ODD(v) ((v) & GENMASK(4, 0)) 19911c0d8fdSPaul Kocialkowski #define OV8865_INC_X_EVEN_REG 0x3815 20011c0d8fdSPaul Kocialkowski #define OV8865_INC_X_EVEN(v) ((v) & GENMASK(4, 0)) 20111c0d8fdSPaul Kocialkowski #define OV8865_VSYNC_START_H_REG 0x3816 20211c0d8fdSPaul Kocialkowski #define OV8865_VSYNC_START_H(v) (((v) & GENMASK(15, 8)) >> 8) 20311c0d8fdSPaul Kocialkowski #define OV8865_VSYNC_START_L_REG 0x3817 20411c0d8fdSPaul Kocialkowski #define OV8865_VSYNC_START_L(v) ((v) & GENMASK(7, 0)) 20511c0d8fdSPaul Kocialkowski #define OV8865_VSYNC_END_H_REG 0x3818 20611c0d8fdSPaul Kocialkowski #define OV8865_VSYNC_END_H(v) (((v) & GENMASK(15, 8)) >> 8) 20711c0d8fdSPaul Kocialkowski #define OV8865_VSYNC_END_L_REG 0x3819 20811c0d8fdSPaul Kocialkowski #define OV8865_VSYNC_END_L(v) ((v) & GENMASK(7, 0)) 20911c0d8fdSPaul Kocialkowski #define OV8865_HSYNC_FIRST_H_REG 0x381a 21011c0d8fdSPaul Kocialkowski #define OV8865_HSYNC_FIRST_H(v) (((v) & GENMASK(15, 8)) >> 8) 21111c0d8fdSPaul Kocialkowski #define OV8865_HSYNC_FIRST_L_REG 0x381b 21211c0d8fdSPaul Kocialkowski #define OV8865_HSYNC_FIRST_L(v) ((v) & GENMASK(7, 0)) 21311c0d8fdSPaul Kocialkowski 21411c0d8fdSPaul Kocialkowski #define OV8865_FORMAT1_REG 0x3820 21511c0d8fdSPaul Kocialkowski #define OV8865_FORMAT1_FLIP_VERT_ISP_EN BIT(2) 21611c0d8fdSPaul Kocialkowski #define OV8865_FORMAT1_FLIP_VERT_SENSOR_EN BIT(1) 21711c0d8fdSPaul Kocialkowski #define OV8865_FORMAT2_REG 0x3821 21811c0d8fdSPaul Kocialkowski #define OV8865_FORMAT2_HSYNC_EN BIT(6) 21911c0d8fdSPaul Kocialkowski #define OV8865_FORMAT2_FST_VBIN_EN BIT(5) 22011c0d8fdSPaul Kocialkowski #define OV8865_FORMAT2_FST_HBIN_EN BIT(4) 22111c0d8fdSPaul Kocialkowski #define OV8865_FORMAT2_ISP_HORZ_VAR2_EN BIT(3) 22211c0d8fdSPaul Kocialkowski #define OV8865_FORMAT2_FLIP_HORZ_ISP_EN BIT(2) 22311c0d8fdSPaul Kocialkowski #define OV8865_FORMAT2_FLIP_HORZ_SENSOR_EN BIT(1) 22411c0d8fdSPaul Kocialkowski #define OV8865_FORMAT2_SYNC_HBIN_EN BIT(0) 22511c0d8fdSPaul Kocialkowski 22611c0d8fdSPaul Kocialkowski #define OV8865_INC_Y_ODD_REG 0x382a 22711c0d8fdSPaul Kocialkowski #define OV8865_INC_Y_ODD(v) ((v) & GENMASK(4, 0)) 22811c0d8fdSPaul Kocialkowski #define OV8865_INC_Y_EVEN_REG 0x382b 22911c0d8fdSPaul Kocialkowski #define OV8865_INC_Y_EVEN(v) ((v) & GENMASK(4, 0)) 23011c0d8fdSPaul Kocialkowski 23111c0d8fdSPaul Kocialkowski #define OV8865_ABLC_NUM_REG 0x3830 23211c0d8fdSPaul Kocialkowski #define OV8865_ABLC_NUM(v) ((v) & GENMASK(4, 0)) 23311c0d8fdSPaul Kocialkowski 23411c0d8fdSPaul Kocialkowski #define OV8865_ZLINE_NUM_REG 0x3836 23511c0d8fdSPaul Kocialkowski #define OV8865_ZLINE_NUM(v) ((v) & GENMASK(4, 0)) 23611c0d8fdSPaul Kocialkowski 23711c0d8fdSPaul Kocialkowski #define OV8865_AUTO_SIZE_CTRL_REG 0x3841 23811c0d8fdSPaul Kocialkowski #define OV8865_AUTO_SIZE_CTRL_OFFSET_Y_REG BIT(5) 23911c0d8fdSPaul Kocialkowski #define OV8865_AUTO_SIZE_CTRL_OFFSET_X_REG BIT(4) 24011c0d8fdSPaul Kocialkowski #define OV8865_AUTO_SIZE_CTRL_CROP_END_Y_REG BIT(3) 24111c0d8fdSPaul Kocialkowski #define OV8865_AUTO_SIZE_CTRL_CROP_END_X_REG BIT(2) 24211c0d8fdSPaul Kocialkowski #define OV8865_AUTO_SIZE_CTRL_CROP_START_Y_REG BIT(1) 24311c0d8fdSPaul Kocialkowski #define OV8865_AUTO_SIZE_CTRL_CROP_START_X_REG BIT(0) 24411c0d8fdSPaul Kocialkowski #define OV8865_AUTO_SIZE_X_OFFSET_H_REG 0x3842 24511c0d8fdSPaul Kocialkowski #define OV8865_AUTO_SIZE_X_OFFSET_L_REG 0x3843 24611c0d8fdSPaul Kocialkowski #define OV8865_AUTO_SIZE_Y_OFFSET_H_REG 0x3844 24711c0d8fdSPaul Kocialkowski #define OV8865_AUTO_SIZE_Y_OFFSET_L_REG 0x3845 24811c0d8fdSPaul Kocialkowski #define OV8865_AUTO_SIZE_BOUNDARIES_REG 0x3846 24911c0d8fdSPaul Kocialkowski #define OV8865_AUTO_SIZE_BOUNDARIES_Y(v) (((v) << 4) & GENMASK(7, 4)) 25011c0d8fdSPaul Kocialkowski #define OV8865_AUTO_SIZE_BOUNDARIES_X(v) ((v) & GENMASK(3, 0)) 25111c0d8fdSPaul Kocialkowski 25211c0d8fdSPaul Kocialkowski /* PSRAM */ 25311c0d8fdSPaul Kocialkowski 25411c0d8fdSPaul Kocialkowski #define OV8865_PSRAM_CTRL8_REG 0x3f08 25511c0d8fdSPaul Kocialkowski 25611c0d8fdSPaul Kocialkowski /* Black Level */ 25711c0d8fdSPaul Kocialkowski 25811c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL0_REG 0x4000 25911c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL0_TRIG_RANGE_EN BIT(7) 26011c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL0_TRIG_FORMAT_EN BIT(6) 26111c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL0_TRIG_GAIN_EN BIT(5) 26211c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL0_TRIG_EXPOSURE_EN BIT(4) 26311c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL0_TRIG_MANUAL_EN BIT(3) 26411c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL0_FREEZE_EN BIT(2) 26511c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL0_ALWAYS_EN BIT(1) 26611c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL0_FILTER_EN BIT(0) 26711c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL1_REG 0x4001 26811c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL1_DITHER_EN BIT(7) 26911c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL1_ZERO_LINE_DIFF_EN BIT(6) 27011c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL1_COL_SHIFT_256 (0 << 4) 27111c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL1_COL_SHIFT_128 (1 << 4) 27211c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL1_COL_SHIFT_64 (2 << 4) 27311c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL1_COL_SHIFT_32 (3 << 4) 27411c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL1_OFFSET_LIMIT_EN BIT(2) 27511c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL1_COLUMN_CANCEL_EN BIT(1) 27611c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL2_REG 0x4002 27711c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL3_REG 0x4003 27811c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL4_REG 0x4004 27911c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL5_REG 0x4005 28011c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL6_REG 0x4006 28111c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL7_REG 0x4007 28211c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL8_REG 0x4008 28311c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL9_REG 0x4009 28411c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRLA_REG 0x400a 28511c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRLB_REG 0x400b 28611c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRLC_REG 0x400c 28711c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRLD_REG 0x400d 28811c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRLD_OFFSET_TRIGGER(v) ((v) & GENMASK(7, 0)) 28911c0d8fdSPaul Kocialkowski 29011c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL1F_REG 0x401f 29111c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL1F_RB_REVERSE BIT(3) 29211c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL1F_INTERPOL_X_EN BIT(2) 29311c0d8fdSPaul Kocialkowski #define OV8865_BLC_CTRL1F_INTERPOL_Y_EN BIT(1) 29411c0d8fdSPaul Kocialkowski 29511c0d8fdSPaul Kocialkowski #define OV8865_BLC_ANCHOR_LEFT_START_H_REG 0x4020 29611c0d8fdSPaul Kocialkowski #define OV8865_BLC_ANCHOR_LEFT_START_H(v) (((v) & GENMASK(11, 8)) >> 8) 29711c0d8fdSPaul Kocialkowski #define OV8865_BLC_ANCHOR_LEFT_START_L_REG 0x4021 29811c0d8fdSPaul Kocialkowski #define OV8865_BLC_ANCHOR_LEFT_START_L(v) ((v) & GENMASK(7, 0)) 29911c0d8fdSPaul Kocialkowski #define OV8865_BLC_ANCHOR_LEFT_END_H_REG 0x4022 30011c0d8fdSPaul Kocialkowski #define OV8865_BLC_ANCHOR_LEFT_END_H(v) (((v) & GENMASK(11, 8)) >> 8) 30111c0d8fdSPaul Kocialkowski #define OV8865_BLC_ANCHOR_LEFT_END_L_REG 0x4023 30211c0d8fdSPaul Kocialkowski #define OV8865_BLC_ANCHOR_LEFT_END_L(v) ((v) & GENMASK(7, 0)) 30311c0d8fdSPaul Kocialkowski #define OV8865_BLC_ANCHOR_RIGHT_START_H_REG 0x4024 30411c0d8fdSPaul Kocialkowski #define OV8865_BLC_ANCHOR_RIGHT_START_H(v) (((v) & GENMASK(11, 8)) >> 8) 30511c0d8fdSPaul Kocialkowski #define OV8865_BLC_ANCHOR_RIGHT_START_L_REG 0x4025 30611c0d8fdSPaul Kocialkowski #define OV8865_BLC_ANCHOR_RIGHT_START_L(v) ((v) & GENMASK(7, 0)) 30711c0d8fdSPaul Kocialkowski #define OV8865_BLC_ANCHOR_RIGHT_END_H_REG 0x4026 30811c0d8fdSPaul Kocialkowski #define OV8865_BLC_ANCHOR_RIGHT_END_H(v) (((v) & GENMASK(11, 8)) >> 8) 30911c0d8fdSPaul Kocialkowski #define OV8865_BLC_ANCHOR_RIGHT_END_L_REG 0x4027 31011c0d8fdSPaul Kocialkowski #define OV8865_BLC_ANCHOR_RIGHT_END_L(v) ((v) & GENMASK(7, 0)) 31111c0d8fdSPaul Kocialkowski 31211c0d8fdSPaul Kocialkowski #define OV8865_BLC_TOP_ZLINE_START_REG 0x4028 31311c0d8fdSPaul Kocialkowski #define OV8865_BLC_TOP_ZLINE_START(v) ((v) & GENMASK(5, 0)) 31411c0d8fdSPaul Kocialkowski #define OV8865_BLC_TOP_ZLINE_NUM_REG 0x4029 31511c0d8fdSPaul Kocialkowski #define OV8865_BLC_TOP_ZLINE_NUM(v) ((v) & GENMASK(4, 0)) 31611c0d8fdSPaul Kocialkowski #define OV8865_BLC_TOP_BLKLINE_START_REG 0x402a 31711c0d8fdSPaul Kocialkowski #define OV8865_BLC_TOP_BLKLINE_START(v) ((v) & GENMASK(5, 0)) 31811c0d8fdSPaul Kocialkowski #define OV8865_BLC_TOP_BLKLINE_NUM_REG 0x402b 31911c0d8fdSPaul Kocialkowski #define OV8865_BLC_TOP_BLKLINE_NUM(v) ((v) & GENMASK(4, 0)) 32011c0d8fdSPaul Kocialkowski #define OV8865_BLC_BOT_ZLINE_START_REG 0x402c 32111c0d8fdSPaul Kocialkowski #define OV8865_BLC_BOT_ZLINE_START(v) ((v) & GENMASK(5, 0)) 32211c0d8fdSPaul Kocialkowski #define OV8865_BLC_BOT_ZLINE_NUM_REG 0x402d 32311c0d8fdSPaul Kocialkowski #define OV8865_BLC_BOT_ZLINE_NUM(v) ((v) & GENMASK(4, 0)) 32411c0d8fdSPaul Kocialkowski #define OV8865_BLC_BOT_BLKLINE_START_REG 0x402e 32511c0d8fdSPaul Kocialkowski #define OV8865_BLC_BOT_BLKLINE_START(v) ((v) & GENMASK(5, 0)) 32611c0d8fdSPaul Kocialkowski #define OV8865_BLC_BOT_BLKLINE_NUM_REG 0x402f 32711c0d8fdSPaul Kocialkowski #define OV8865_BLC_BOT_BLKLINE_NUM(v) ((v) & GENMASK(4, 0)) 32811c0d8fdSPaul Kocialkowski 32911c0d8fdSPaul Kocialkowski #define OV8865_BLC_OFFSET_LIMIT_REG 0x4034 33011c0d8fdSPaul Kocialkowski #define OV8865_BLC_OFFSET_LIMIT(v) ((v) & GENMASK(7, 0)) 33111c0d8fdSPaul Kocialkowski 33211c0d8fdSPaul Kocialkowski /* VFIFO */ 33311c0d8fdSPaul Kocialkowski 33411c0d8fdSPaul Kocialkowski #define OV8865_VFIFO_READ_START_H_REG 0x4600 33511c0d8fdSPaul Kocialkowski #define OV8865_VFIFO_READ_START_H(v) (((v) & GENMASK(15, 8)) >> 8) 33611c0d8fdSPaul Kocialkowski #define OV8865_VFIFO_READ_START_L_REG 0x4601 33711c0d8fdSPaul Kocialkowski #define OV8865_VFIFO_READ_START_L(v) ((v) & GENMASK(7, 0)) 33811c0d8fdSPaul Kocialkowski 33911c0d8fdSPaul Kocialkowski /* MIPI */ 34011c0d8fdSPaul Kocialkowski 34111c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CTRL0_REG 0x4800 34211c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CTRL1_REG 0x4801 34311c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CTRL2_REG 0x4802 34411c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CTRL3_REG 0x4803 34511c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CTRL4_REG 0x4804 34611c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CTRL5_REG 0x4805 34711c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CTRL6_REG 0x4806 34811c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CTRL7_REG 0x4807 34911c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CTRL8_REG 0x4808 35011c0d8fdSPaul Kocialkowski 35111c0d8fdSPaul Kocialkowski #define OV8865_MIPI_FCNT_MAX_H_REG 0x4810 35211c0d8fdSPaul Kocialkowski #define OV8865_MIPI_FCNT_MAX_L_REG 0x4811 35311c0d8fdSPaul Kocialkowski 35411c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CTRL13_REG 0x4813 35511c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CTRL14_REG 0x4814 35611c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CTRL15_REG 0x4815 35711c0d8fdSPaul Kocialkowski #define OV8865_MIPI_EMBEDDED_DT_REG 0x4816 35811c0d8fdSPaul Kocialkowski 35911c0d8fdSPaul Kocialkowski #define OV8865_MIPI_HS_ZERO_MIN_H_REG 0x4818 36011c0d8fdSPaul Kocialkowski #define OV8865_MIPI_HS_ZERO_MIN_L_REG 0x4819 36111c0d8fdSPaul Kocialkowski #define OV8865_MIPI_HS_TRAIL_MIN_H_REG 0x481a 36211c0d8fdSPaul Kocialkowski #define OV8865_MIPI_HS_TRAIL_MIN_L_REG 0x481b 36311c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CLK_ZERO_MIN_H_REG 0x481c 36411c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CLK_ZERO_MIN_L_REG 0x481d 36511c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CLK_PREPARE_MAX_REG 0x481e 36611c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CLK_PREPARE_MIN_REG 0x481f 36711c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CLK_POST_MIN_H_REG 0x4820 36811c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CLK_POST_MIN_L_REG 0x4821 36911c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CLK_TRAIL_MIN_H_REG 0x4822 37011c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CLK_TRAIL_MIN_L_REG 0x4823 37111c0d8fdSPaul Kocialkowski #define OV8865_MIPI_LPX_P_MIN_H_REG 0x4824 37211c0d8fdSPaul Kocialkowski #define OV8865_MIPI_LPX_P_MIN_L_REG 0x4825 37311c0d8fdSPaul Kocialkowski #define OV8865_MIPI_HS_PREPARE_MIN_REG 0x4826 37411c0d8fdSPaul Kocialkowski #define OV8865_MIPI_HS_PREPARE_MAX_REG 0x4827 37511c0d8fdSPaul Kocialkowski #define OV8865_MIPI_HS_EXIT_MIN_H_REG 0x4828 37611c0d8fdSPaul Kocialkowski #define OV8865_MIPI_HS_EXIT_MIN_L_REG 0x4829 37711c0d8fdSPaul Kocialkowski #define OV8865_MIPI_UI_HS_ZERO_MIN_REG 0x482a 37811c0d8fdSPaul Kocialkowski #define OV8865_MIPI_UI_HS_TRAIL_MIN_REG 0x482b 37911c0d8fdSPaul Kocialkowski #define OV8865_MIPI_UI_CLK_ZERO_MIN_REG 0x482c 38011c0d8fdSPaul Kocialkowski #define OV8865_MIPI_UI_CLK_PREPARE_REG 0x482d 38111c0d8fdSPaul Kocialkowski #define OV8865_MIPI_UI_CLK_POST_MIN_REG 0x482e 38211c0d8fdSPaul Kocialkowski #define OV8865_MIPI_UI_CLK_TRAIL_MIN_REG 0x482f 38311c0d8fdSPaul Kocialkowski #define OV8865_MIPI_UI_LPX_P_MIN_REG 0x4830 38411c0d8fdSPaul Kocialkowski #define OV8865_MIPI_UI_HS_PREPARE_REG 0x4831 38511c0d8fdSPaul Kocialkowski #define OV8865_MIPI_UI_HS_EXIT_MIN_REG 0x4832 38611c0d8fdSPaul Kocialkowski #define OV8865_MIPI_PKT_START_SIZE_REG 0x4833 38711c0d8fdSPaul Kocialkowski 38811c0d8fdSPaul Kocialkowski #define OV8865_MIPI_PCLK_PERIOD_REG 0x4837 38911c0d8fdSPaul Kocialkowski #define OV8865_MIPI_LP_GPIO0_REG 0x4838 39011c0d8fdSPaul Kocialkowski #define OV8865_MIPI_LP_GPIO1_REG 0x4839 39111c0d8fdSPaul Kocialkowski 39211c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CTRL3C_REG 0x483c 39311c0d8fdSPaul Kocialkowski #define OV8865_MIPI_LP_GPIO4_REG 0x483d 39411c0d8fdSPaul Kocialkowski 39511c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CTRL4A_REG 0x484a 39611c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CTRL4B_REG 0x484b 39711c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CTRL4C_REG 0x484c 39811c0d8fdSPaul Kocialkowski #define OV8865_MIPI_LANE_TEST_PATTERN_REG 0x484d 39911c0d8fdSPaul Kocialkowski #define OV8865_MIPI_FRAME_END_DELAY_REG 0x484e 40011c0d8fdSPaul Kocialkowski #define OV8865_MIPI_CLOCK_TEST_PATTERN_REG 0x484f 40111c0d8fdSPaul Kocialkowski #define OV8865_MIPI_LANE_SEL01_REG 0x4850 40211c0d8fdSPaul Kocialkowski #define OV8865_MIPI_LANE_SEL01_LANE0(v) (((v) << 0) & GENMASK(2, 0)) 40311c0d8fdSPaul Kocialkowski #define OV8865_MIPI_LANE_SEL01_LANE1(v) (((v) << 4) & GENMASK(6, 4)) 40411c0d8fdSPaul Kocialkowski #define OV8865_MIPI_LANE_SEL23_REG 0x4851 40511c0d8fdSPaul Kocialkowski #define OV8865_MIPI_LANE_SEL23_LANE2(v) (((v) << 0) & GENMASK(2, 0)) 40611c0d8fdSPaul Kocialkowski #define OV8865_MIPI_LANE_SEL23_LANE3(v) (((v) << 4) & GENMASK(6, 4)) 40711c0d8fdSPaul Kocialkowski 40811c0d8fdSPaul Kocialkowski /* ISP */ 40911c0d8fdSPaul Kocialkowski 41011c0d8fdSPaul Kocialkowski #define OV8865_ISP_CTRL0_REG 0x5000 41111c0d8fdSPaul Kocialkowski #define OV8865_ISP_CTRL0_LENC_EN BIT(7) 41211c0d8fdSPaul Kocialkowski #define OV8865_ISP_CTRL0_WHITE_BALANCE_EN BIT(4) 41311c0d8fdSPaul Kocialkowski #define OV8865_ISP_CTRL0_DPC_BLACK_EN BIT(2) 41411c0d8fdSPaul Kocialkowski #define OV8865_ISP_CTRL0_DPC_WHITE_EN BIT(1) 41511c0d8fdSPaul Kocialkowski #define OV8865_ISP_CTRL1_REG 0x5001 41611c0d8fdSPaul Kocialkowski #define OV8865_ISP_CTRL1_BLC_EN BIT(0) 41711c0d8fdSPaul Kocialkowski #define OV8865_ISP_CTRL2_REG 0x5002 41811c0d8fdSPaul Kocialkowski #define OV8865_ISP_CTRL2_DEBUG BIT(3) 41911c0d8fdSPaul Kocialkowski #define OV8865_ISP_CTRL2_VARIOPIXEL_EN BIT(2) 42011c0d8fdSPaul Kocialkowski #define OV8865_ISP_CTRL2_VSYNC_LATCH_EN BIT(0) 42111c0d8fdSPaul Kocialkowski #define OV8865_ISP_CTRL3_REG 0x5003 42211c0d8fdSPaul Kocialkowski 42311c0d8fdSPaul Kocialkowski #define OV8865_ISP_GAIN_RED_H_REG 0x5018 42411c0d8fdSPaul Kocialkowski #define OV8865_ISP_GAIN_RED_H(v) (((v) & GENMASK(13, 6)) >> 6) 42511c0d8fdSPaul Kocialkowski #define OV8865_ISP_GAIN_RED_L_REG 0x5019 42611c0d8fdSPaul Kocialkowski #define OV8865_ISP_GAIN_RED_L(v) ((v) & GENMASK(5, 0)) 42711c0d8fdSPaul Kocialkowski #define OV8865_ISP_GAIN_GREEN_H_REG 0x501a 42811c0d8fdSPaul Kocialkowski #define OV8865_ISP_GAIN_GREEN_H(v) (((v) & GENMASK(13, 6)) >> 6) 42911c0d8fdSPaul Kocialkowski #define OV8865_ISP_GAIN_GREEN_L_REG 0x501b 43011c0d8fdSPaul Kocialkowski #define OV8865_ISP_GAIN_GREEN_L(v) ((v) & GENMASK(5, 0)) 43111c0d8fdSPaul Kocialkowski #define OV8865_ISP_GAIN_BLUE_H_REG 0x501c 43211c0d8fdSPaul Kocialkowski #define OV8865_ISP_GAIN_BLUE_H(v) (((v) & GENMASK(13, 6)) >> 6) 43311c0d8fdSPaul Kocialkowski #define OV8865_ISP_GAIN_BLUE_L_REG 0x501d 43411c0d8fdSPaul Kocialkowski #define OV8865_ISP_GAIN_BLUE_L(v) ((v) & GENMASK(5, 0)) 43511c0d8fdSPaul Kocialkowski 43611c0d8fdSPaul Kocialkowski /* VarioPixel */ 43711c0d8fdSPaul Kocialkowski 43811c0d8fdSPaul Kocialkowski #define OV8865_VAP_CTRL0_REG 0x5900 43911c0d8fdSPaul Kocialkowski #define OV8865_VAP_CTRL1_REG 0x5901 44011c0d8fdSPaul Kocialkowski #define OV8865_VAP_CTRL1_HSUB_COEF(v) ((((v) - 1) << 2) & \ 44111c0d8fdSPaul Kocialkowski GENMASK(3, 2)) 44211c0d8fdSPaul Kocialkowski #define OV8865_VAP_CTRL1_VSUB_COEF(v) (((v) - 1) & GENMASK(1, 0)) 44311c0d8fdSPaul Kocialkowski 44411c0d8fdSPaul Kocialkowski /* Pre-DSP */ 44511c0d8fdSPaul Kocialkowski 44611c0d8fdSPaul Kocialkowski #define OV8865_PRE_CTRL0_REG 0x5e00 44711c0d8fdSPaul Kocialkowski #define OV8865_PRE_CTRL0_PATTERN_EN BIT(7) 44811c0d8fdSPaul Kocialkowski #define OV8865_PRE_CTRL0_ROLLING_BAR_EN BIT(6) 44911c0d8fdSPaul Kocialkowski #define OV8865_PRE_CTRL0_TRANSPARENT_MODE BIT(5) 45011c0d8fdSPaul Kocialkowski #define OV8865_PRE_CTRL0_SQUARES_BW_MODE BIT(4) 45111c0d8fdSPaul Kocialkowski #define OV8865_PRE_CTRL0_PATTERN_COLOR_BARS 0 45211c0d8fdSPaul Kocialkowski #define OV8865_PRE_CTRL0_PATTERN_RANDOM_DATA 1 45311c0d8fdSPaul Kocialkowski #define OV8865_PRE_CTRL0_PATTERN_COLOR_SQUARES 2 45411c0d8fdSPaul Kocialkowski #define OV8865_PRE_CTRL0_PATTERN_BLACK 3 45511c0d8fdSPaul Kocialkowski 45611c0d8fdSPaul Kocialkowski /* Macros */ 45711c0d8fdSPaul Kocialkowski 45811c0d8fdSPaul Kocialkowski #define ov8865_subdev_sensor(s) \ 45911c0d8fdSPaul Kocialkowski container_of(s, struct ov8865_sensor, subdev) 46011c0d8fdSPaul Kocialkowski 46111c0d8fdSPaul Kocialkowski #define ov8865_ctrl_subdev(c) \ 46236e4f2b2SPaul Kocialkowski (&container_of((c)->handler, struct ov8865_sensor, \ 46336e4f2b2SPaul Kocialkowski ctrls.handler)->subdev) 46411c0d8fdSPaul Kocialkowski 46511c0d8fdSPaul Kocialkowski /* Data structures */ 46611c0d8fdSPaul Kocialkowski 46711c0d8fdSPaul Kocialkowski struct ov8865_register_value { 46811c0d8fdSPaul Kocialkowski u16 address; 46911c0d8fdSPaul Kocialkowski u8 value; 47011c0d8fdSPaul Kocialkowski unsigned int delay_ms; 47111c0d8fdSPaul Kocialkowski }; 47211c0d8fdSPaul Kocialkowski 47311c0d8fdSPaul Kocialkowski /* 47411c0d8fdSPaul Kocialkowski * PLL1 Clock Tree: 47511c0d8fdSPaul Kocialkowski * 47611c0d8fdSPaul Kocialkowski * +-< EXTCLK 47711c0d8fdSPaul Kocialkowski * | 47811c0d8fdSPaul Kocialkowski * +-+ pll_pre_div_half (0x30a [0]) 47911c0d8fdSPaul Kocialkowski * | 48011c0d8fdSPaul Kocialkowski * +-+ pll_pre_div (0x300 [2:0], special values: 48111c0d8fdSPaul Kocialkowski * | 0: 1, 1: 1.5, 3: 2.5, 4: 3, 5: 4, 7: 8) 48211c0d8fdSPaul Kocialkowski * +-+ pll_mul (0x301 [1:0], 0x302 [7:0]) 48311c0d8fdSPaul Kocialkowski * | 48411c0d8fdSPaul Kocialkowski * +-+ m_div (0x303 [3:0]) 48511c0d8fdSPaul Kocialkowski * | | 48611c0d8fdSPaul Kocialkowski * | +-> PHY_SCLK 48711c0d8fdSPaul Kocialkowski * | | 48811c0d8fdSPaul Kocialkowski * | +-+ mipi_div (0x304 [1:0], special values: 0: 4, 1: 5, 2: 6, 3: 8) 48911c0d8fdSPaul Kocialkowski * | | 49011c0d8fdSPaul Kocialkowski * | +-+ pclk_div (0x3020 [3]) 49111c0d8fdSPaul Kocialkowski * | | 49211c0d8fdSPaul Kocialkowski * | +-> PCLK 49311c0d8fdSPaul Kocialkowski * | 49411c0d8fdSPaul Kocialkowski * +-+ sys_pre_div (0x305 [1:0], special values: 0: 3, 1: 4, 2: 5, 3: 6) 49511c0d8fdSPaul Kocialkowski * | 49611c0d8fdSPaul Kocialkowski * +-+ sys_div (0x306 [0]) 49711c0d8fdSPaul Kocialkowski * | 49811c0d8fdSPaul Kocialkowski * +-+ sys_sel (0x3032 [7], 0: PLL1, 1: PLL2) 49911c0d8fdSPaul Kocialkowski * | 50011c0d8fdSPaul Kocialkowski * +-+ sclk_sel (0x3033 [1], 0: sys_sel, 1: PLL2 DAC_CLK) 50111c0d8fdSPaul Kocialkowski * | 50211c0d8fdSPaul Kocialkowski * +-+ sclk_pre_div (0x3106 [3:2], special values: 50311c0d8fdSPaul Kocialkowski * | 0: 1, 1: 2, 2: 4, 3: 1) 50411c0d8fdSPaul Kocialkowski * | 50511c0d8fdSPaul Kocialkowski * +-+ sclk_div (0x3106 [7:4], special values: 0: 1) 50611c0d8fdSPaul Kocialkowski * | 50711c0d8fdSPaul Kocialkowski * +-> SCLK 50811c0d8fdSPaul Kocialkowski */ 50911c0d8fdSPaul Kocialkowski 51011c0d8fdSPaul Kocialkowski struct ov8865_pll1_config { 51111c0d8fdSPaul Kocialkowski unsigned int pll_pre_div_half; 51211c0d8fdSPaul Kocialkowski unsigned int pll_pre_div; 51311c0d8fdSPaul Kocialkowski unsigned int pll_mul; 51411c0d8fdSPaul Kocialkowski unsigned int m_div; 51511c0d8fdSPaul Kocialkowski unsigned int mipi_div; 51611c0d8fdSPaul Kocialkowski unsigned int pclk_div; 51711c0d8fdSPaul Kocialkowski unsigned int sys_pre_div; 51811c0d8fdSPaul Kocialkowski unsigned int sys_div; 51911c0d8fdSPaul Kocialkowski }; 52011c0d8fdSPaul Kocialkowski 52111c0d8fdSPaul Kocialkowski /* 52211c0d8fdSPaul Kocialkowski * PLL2 Clock Tree: 52311c0d8fdSPaul Kocialkowski * 52411c0d8fdSPaul Kocialkowski * +-< EXTCLK 52511c0d8fdSPaul Kocialkowski * | 52611c0d8fdSPaul Kocialkowski * +-+ pll_pre_div_half (0x312 [4]) 52711c0d8fdSPaul Kocialkowski * | 52811c0d8fdSPaul Kocialkowski * +-+ pll_pre_div (0x30b [2:0], special values: 52911c0d8fdSPaul Kocialkowski * | 0: 1, 1: 1.5, 3: 2.5, 4: 3, 5: 4, 7: 8) 53011c0d8fdSPaul Kocialkowski * +-+ pll_mul (0x30c [1:0], 0x30d [7:0]) 53111c0d8fdSPaul Kocialkowski * | 53211c0d8fdSPaul Kocialkowski * +-+ dac_div (0x312 [3:0]) 53311c0d8fdSPaul Kocialkowski * | | 53411c0d8fdSPaul Kocialkowski * | +-> DAC_CLK 53511c0d8fdSPaul Kocialkowski * | 53611c0d8fdSPaul Kocialkowski * +-+ sys_pre_div (0x30f [3:0]) 53711c0d8fdSPaul Kocialkowski * | 53811c0d8fdSPaul Kocialkowski * +-+ sys_div (0x30e [2:0], special values: 53911c0d8fdSPaul Kocialkowski * | 0: 1, 1: 1.5, 3: 2.5, 4: 3, 5: 3.5, 6: 4, 7:5) 54011c0d8fdSPaul Kocialkowski * | 54111c0d8fdSPaul Kocialkowski * +-+ sys_sel (0x3032 [7], 0: PLL1, 1: PLL2) 54211c0d8fdSPaul Kocialkowski * | 54311c0d8fdSPaul Kocialkowski * +-+ sclk_sel (0x3033 [1], 0: sys_sel, 1: PLL2 DAC_CLK) 54411c0d8fdSPaul Kocialkowski * | 54511c0d8fdSPaul Kocialkowski * +-+ sclk_pre_div (0x3106 [3:2], special values: 54611c0d8fdSPaul Kocialkowski * | 0: 1, 1: 2, 2: 4, 3: 1) 54711c0d8fdSPaul Kocialkowski * | 54811c0d8fdSPaul Kocialkowski * +-+ sclk_div (0x3106 [7:4], special values: 0: 1) 54911c0d8fdSPaul Kocialkowski * | 55011c0d8fdSPaul Kocialkowski * +-> SCLK 55111c0d8fdSPaul Kocialkowski */ 55211c0d8fdSPaul Kocialkowski 55311c0d8fdSPaul Kocialkowski struct ov8865_pll2_config { 55411c0d8fdSPaul Kocialkowski unsigned int pll_pre_div_half; 55511c0d8fdSPaul Kocialkowski unsigned int pll_pre_div; 55611c0d8fdSPaul Kocialkowski unsigned int pll_mul; 55711c0d8fdSPaul Kocialkowski unsigned int dac_div; 55811c0d8fdSPaul Kocialkowski unsigned int sys_pre_div; 55911c0d8fdSPaul Kocialkowski unsigned int sys_div; 56011c0d8fdSPaul Kocialkowski }; 56111c0d8fdSPaul Kocialkowski 56211c0d8fdSPaul Kocialkowski struct ov8865_sclk_config { 56311c0d8fdSPaul Kocialkowski unsigned int sys_sel; 56411c0d8fdSPaul Kocialkowski unsigned int sclk_sel; 56511c0d8fdSPaul Kocialkowski unsigned int sclk_pre_div; 56611c0d8fdSPaul Kocialkowski unsigned int sclk_div; 56711c0d8fdSPaul Kocialkowski }; 56811c0d8fdSPaul Kocialkowski 56911c0d8fdSPaul Kocialkowski /* 57011c0d8fdSPaul Kocialkowski * General formulas for (array-centered) mode calculation: 57111c0d8fdSPaul Kocialkowski * - photo_array_width = 3296 57211c0d8fdSPaul Kocialkowski * - crop_start_x = (photo_array_width - output_size_x) / 2 57311c0d8fdSPaul Kocialkowski * - crop_end_x = crop_start_x + offset_x + output_size_x - 1 57411c0d8fdSPaul Kocialkowski * 57511c0d8fdSPaul Kocialkowski * - photo_array_height = 2480 57611c0d8fdSPaul Kocialkowski * - crop_start_y = (photo_array_height - output_size_y) / 2 57711c0d8fdSPaul Kocialkowski * - crop_end_y = crop_start_y + offset_y + output_size_y - 1 57811c0d8fdSPaul Kocialkowski */ 57911c0d8fdSPaul Kocialkowski 58011c0d8fdSPaul Kocialkowski struct ov8865_mode { 58111c0d8fdSPaul Kocialkowski unsigned int crop_start_x; 58211c0d8fdSPaul Kocialkowski unsigned int offset_x; 58311c0d8fdSPaul Kocialkowski unsigned int output_size_x; 58411c0d8fdSPaul Kocialkowski unsigned int crop_end_x; 58511c0d8fdSPaul Kocialkowski unsigned int hts; 58611c0d8fdSPaul Kocialkowski 58711c0d8fdSPaul Kocialkowski unsigned int crop_start_y; 58811c0d8fdSPaul Kocialkowski unsigned int offset_y; 58911c0d8fdSPaul Kocialkowski unsigned int output_size_y; 59011c0d8fdSPaul Kocialkowski unsigned int crop_end_y; 59111c0d8fdSPaul Kocialkowski unsigned int vts; 59211c0d8fdSPaul Kocialkowski 59311c0d8fdSPaul Kocialkowski /* With auto size, only output and total sizes need to be set. */ 59411c0d8fdSPaul Kocialkowski bool size_auto; 59511c0d8fdSPaul Kocialkowski unsigned int size_auto_boundary_x; 59611c0d8fdSPaul Kocialkowski unsigned int size_auto_boundary_y; 59711c0d8fdSPaul Kocialkowski 59811c0d8fdSPaul Kocialkowski bool binning_x; 59911c0d8fdSPaul Kocialkowski bool binning_y; 60011c0d8fdSPaul Kocialkowski bool variopixel; 60111c0d8fdSPaul Kocialkowski unsigned int variopixel_hsub_coef; 60211c0d8fdSPaul Kocialkowski unsigned int variopixel_vsub_coef; 60311c0d8fdSPaul Kocialkowski 60411c0d8fdSPaul Kocialkowski /* Bits for the format register, used for binning. */ 60511c0d8fdSPaul Kocialkowski bool sync_hbin; 60611c0d8fdSPaul Kocialkowski bool horz_var2; 60711c0d8fdSPaul Kocialkowski 60811c0d8fdSPaul Kocialkowski unsigned int inc_x_odd; 60911c0d8fdSPaul Kocialkowski unsigned int inc_x_even; 61011c0d8fdSPaul Kocialkowski unsigned int inc_y_odd; 61111c0d8fdSPaul Kocialkowski unsigned int inc_y_even; 61211c0d8fdSPaul Kocialkowski 61311c0d8fdSPaul Kocialkowski unsigned int vfifo_read_start; 61411c0d8fdSPaul Kocialkowski 61511c0d8fdSPaul Kocialkowski unsigned int ablc_num; 61611c0d8fdSPaul Kocialkowski unsigned int zline_num; 61711c0d8fdSPaul Kocialkowski 61811c0d8fdSPaul Kocialkowski unsigned int blc_top_zero_line_start; 61911c0d8fdSPaul Kocialkowski unsigned int blc_top_zero_line_num; 62011c0d8fdSPaul Kocialkowski unsigned int blc_top_black_line_start; 62111c0d8fdSPaul Kocialkowski unsigned int blc_top_black_line_num; 62211c0d8fdSPaul Kocialkowski 62311c0d8fdSPaul Kocialkowski unsigned int blc_bottom_zero_line_start; 62411c0d8fdSPaul Kocialkowski unsigned int blc_bottom_zero_line_num; 62511c0d8fdSPaul Kocialkowski unsigned int blc_bottom_black_line_start; 62611c0d8fdSPaul Kocialkowski unsigned int blc_bottom_black_line_num; 62711c0d8fdSPaul Kocialkowski 62811c0d8fdSPaul Kocialkowski u8 blc_col_shift_mask; 62911c0d8fdSPaul Kocialkowski 63011c0d8fdSPaul Kocialkowski unsigned int blc_anchor_left_start; 63111c0d8fdSPaul Kocialkowski unsigned int blc_anchor_left_end; 63211c0d8fdSPaul Kocialkowski unsigned int blc_anchor_right_start; 63311c0d8fdSPaul Kocialkowski unsigned int blc_anchor_right_end; 63411c0d8fdSPaul Kocialkowski 63511c0d8fdSPaul Kocialkowski struct v4l2_fract frame_interval; 63611c0d8fdSPaul Kocialkowski 63711c0d8fdSPaul Kocialkowski const struct ov8865_pll1_config *pll1_config; 63811c0d8fdSPaul Kocialkowski const struct ov8865_pll2_config *pll2_config; 63911c0d8fdSPaul Kocialkowski const struct ov8865_sclk_config *sclk_config; 64011c0d8fdSPaul Kocialkowski 64111c0d8fdSPaul Kocialkowski const struct ov8865_register_value *register_values; 64211c0d8fdSPaul Kocialkowski unsigned int register_values_count; 64311c0d8fdSPaul Kocialkowski }; 64411c0d8fdSPaul Kocialkowski 64511c0d8fdSPaul Kocialkowski struct ov8865_state { 64611c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode; 64711c0d8fdSPaul Kocialkowski u32 mbus_code; 64811c0d8fdSPaul Kocialkowski 64911c0d8fdSPaul Kocialkowski bool streaming; 65011c0d8fdSPaul Kocialkowski }; 65111c0d8fdSPaul Kocialkowski 65211c0d8fdSPaul Kocialkowski struct ov8865_ctrls { 65311c0d8fdSPaul Kocialkowski struct v4l2_ctrl *link_freq; 65411c0d8fdSPaul Kocialkowski struct v4l2_ctrl *pixel_rate; 65511c0d8fdSPaul Kocialkowski 65611c0d8fdSPaul Kocialkowski struct v4l2_ctrl_handler handler; 65711c0d8fdSPaul Kocialkowski }; 65811c0d8fdSPaul Kocialkowski 65911c0d8fdSPaul Kocialkowski struct ov8865_sensor { 66011c0d8fdSPaul Kocialkowski struct device *dev; 66111c0d8fdSPaul Kocialkowski struct i2c_client *i2c_client; 66211c0d8fdSPaul Kocialkowski struct gpio_desc *reset; 66311c0d8fdSPaul Kocialkowski struct gpio_desc *powerdown; 66411c0d8fdSPaul Kocialkowski struct regulator *avdd; 66511c0d8fdSPaul Kocialkowski struct regulator *dvdd; 66611c0d8fdSPaul Kocialkowski struct regulator *dovdd; 66711c0d8fdSPaul Kocialkowski struct clk *extclk; 66811c0d8fdSPaul Kocialkowski 66911c0d8fdSPaul Kocialkowski struct v4l2_fwnode_endpoint endpoint; 67011c0d8fdSPaul Kocialkowski struct v4l2_subdev subdev; 67111c0d8fdSPaul Kocialkowski struct media_pad pad; 67211c0d8fdSPaul Kocialkowski 67311c0d8fdSPaul Kocialkowski struct mutex mutex; 67411c0d8fdSPaul Kocialkowski 67511c0d8fdSPaul Kocialkowski struct ov8865_state state; 67611c0d8fdSPaul Kocialkowski struct ov8865_ctrls ctrls; 67711c0d8fdSPaul Kocialkowski }; 67811c0d8fdSPaul Kocialkowski 67911c0d8fdSPaul Kocialkowski /* Static definitions */ 68011c0d8fdSPaul Kocialkowski 68111c0d8fdSPaul Kocialkowski /* 68211c0d8fdSPaul Kocialkowski * EXTCLK = 24 MHz 68311c0d8fdSPaul Kocialkowski * PHY_SCLK = 720 MHz 68411c0d8fdSPaul Kocialkowski * MIPI_PCLK = 90 MHz 68511c0d8fdSPaul Kocialkowski */ 68611c0d8fdSPaul Kocialkowski static const struct ov8865_pll1_config ov8865_pll1_config_native = { 68711c0d8fdSPaul Kocialkowski .pll_pre_div_half = 1, 68811c0d8fdSPaul Kocialkowski .pll_pre_div = 0, 68911c0d8fdSPaul Kocialkowski .pll_mul = 30, 69011c0d8fdSPaul Kocialkowski .m_div = 1, 69111c0d8fdSPaul Kocialkowski .mipi_div = 3, 69211c0d8fdSPaul Kocialkowski .pclk_div = 1, 69311c0d8fdSPaul Kocialkowski .sys_pre_div = 1, 69411c0d8fdSPaul Kocialkowski .sys_div = 2, 69511c0d8fdSPaul Kocialkowski }; 69611c0d8fdSPaul Kocialkowski 69711c0d8fdSPaul Kocialkowski /* 69811c0d8fdSPaul Kocialkowski * EXTCLK = 24 MHz 69911c0d8fdSPaul Kocialkowski * DAC_CLK = 360 MHz 70011c0d8fdSPaul Kocialkowski * SCLK = 144 MHz 70111c0d8fdSPaul Kocialkowski */ 70211c0d8fdSPaul Kocialkowski 70311c0d8fdSPaul Kocialkowski static const struct ov8865_pll2_config ov8865_pll2_config_native = { 70411c0d8fdSPaul Kocialkowski .pll_pre_div_half = 1, 70511c0d8fdSPaul Kocialkowski .pll_pre_div = 0, 70611c0d8fdSPaul Kocialkowski .pll_mul = 30, 70711c0d8fdSPaul Kocialkowski .dac_div = 2, 70811c0d8fdSPaul Kocialkowski .sys_pre_div = 5, 70911c0d8fdSPaul Kocialkowski .sys_div = 0, 71011c0d8fdSPaul Kocialkowski }; 71111c0d8fdSPaul Kocialkowski 71211c0d8fdSPaul Kocialkowski /* 71311c0d8fdSPaul Kocialkowski * EXTCLK = 24 MHz 71411c0d8fdSPaul Kocialkowski * DAC_CLK = 360 MHz 71511c0d8fdSPaul Kocialkowski * SCLK = 80 MHz 71611c0d8fdSPaul Kocialkowski */ 71711c0d8fdSPaul Kocialkowski 71811c0d8fdSPaul Kocialkowski static const struct ov8865_pll2_config ov8865_pll2_config_binning = { 71911c0d8fdSPaul Kocialkowski .pll_pre_div_half = 1, 72011c0d8fdSPaul Kocialkowski .pll_pre_div = 0, 72111c0d8fdSPaul Kocialkowski .pll_mul = 30, 72211c0d8fdSPaul Kocialkowski .dac_div = 2, 72311c0d8fdSPaul Kocialkowski .sys_pre_div = 10, 72411c0d8fdSPaul Kocialkowski .sys_div = 0, 72511c0d8fdSPaul Kocialkowski }; 72611c0d8fdSPaul Kocialkowski 72711c0d8fdSPaul Kocialkowski static const struct ov8865_sclk_config ov8865_sclk_config_native = { 72811c0d8fdSPaul Kocialkowski .sys_sel = 1, 72911c0d8fdSPaul Kocialkowski .sclk_sel = 0, 73011c0d8fdSPaul Kocialkowski .sclk_pre_div = 0, 73111c0d8fdSPaul Kocialkowski .sclk_div = 0, 73211c0d8fdSPaul Kocialkowski }; 73311c0d8fdSPaul Kocialkowski 73411c0d8fdSPaul Kocialkowski static const struct ov8865_register_value ov8865_register_values_native[] = { 73511c0d8fdSPaul Kocialkowski /* Sensor */ 73611c0d8fdSPaul Kocialkowski 73711c0d8fdSPaul Kocialkowski { 0x3700, 0x48 }, 73811c0d8fdSPaul Kocialkowski { 0x3701, 0x18 }, 73911c0d8fdSPaul Kocialkowski { 0x3702, 0x50 }, 74011c0d8fdSPaul Kocialkowski { 0x3703, 0x32 }, 74111c0d8fdSPaul Kocialkowski { 0x3704, 0x28 }, 74211c0d8fdSPaul Kocialkowski { 0x3706, 0x70 }, 74311c0d8fdSPaul Kocialkowski { 0x3707, 0x08 }, 74411c0d8fdSPaul Kocialkowski { 0x3708, 0x48 }, 74511c0d8fdSPaul Kocialkowski { 0x3709, 0x80 }, 74611c0d8fdSPaul Kocialkowski { 0x370a, 0x01 }, 74711c0d8fdSPaul Kocialkowski { 0x370b, 0x70 }, 74811c0d8fdSPaul Kocialkowski { 0x370c, 0x07 }, 74911c0d8fdSPaul Kocialkowski { 0x3718, 0x14 }, 75011c0d8fdSPaul Kocialkowski { 0x3712, 0x44 }, 75111c0d8fdSPaul Kocialkowski { 0x371e, 0x31 }, 75211c0d8fdSPaul Kocialkowski { 0x371f, 0x7f }, 75311c0d8fdSPaul Kocialkowski { 0x3720, 0x0a }, 75411c0d8fdSPaul Kocialkowski { 0x3721, 0x0a }, 75511c0d8fdSPaul Kocialkowski { 0x3724, 0x04 }, 75611c0d8fdSPaul Kocialkowski { 0x3725, 0x04 }, 75711c0d8fdSPaul Kocialkowski { 0x3726, 0x0c }, 75811c0d8fdSPaul Kocialkowski { 0x3728, 0x0a }, 75911c0d8fdSPaul Kocialkowski { 0x3729, 0x03 }, 76011c0d8fdSPaul Kocialkowski { 0x372a, 0x06 }, 76111c0d8fdSPaul Kocialkowski { 0x372b, 0xa6 }, 76211c0d8fdSPaul Kocialkowski { 0x372c, 0xa6 }, 76311c0d8fdSPaul Kocialkowski { 0x372d, 0xa6 }, 76411c0d8fdSPaul Kocialkowski { 0x372e, 0x0c }, 76511c0d8fdSPaul Kocialkowski { 0x372f, 0x20 }, 76611c0d8fdSPaul Kocialkowski { 0x3730, 0x02 }, 76711c0d8fdSPaul Kocialkowski { 0x3731, 0x0c }, 76811c0d8fdSPaul Kocialkowski { 0x3732, 0x28 }, 76911c0d8fdSPaul Kocialkowski { 0x3736, 0x30 }, 77011c0d8fdSPaul Kocialkowski { 0x373a, 0x04 }, 77111c0d8fdSPaul Kocialkowski { 0x373b, 0x18 }, 77211c0d8fdSPaul Kocialkowski { 0x373c, 0x14 }, 77311c0d8fdSPaul Kocialkowski { 0x373e, 0x06 }, 77411c0d8fdSPaul Kocialkowski { 0x375a, 0x0c }, 77511c0d8fdSPaul Kocialkowski { 0x375b, 0x26 }, 77611c0d8fdSPaul Kocialkowski { 0x375d, 0x04 }, 77711c0d8fdSPaul Kocialkowski { 0x375f, 0x28 }, 77811c0d8fdSPaul Kocialkowski { 0x3767, 0x1e }, 77911c0d8fdSPaul Kocialkowski { 0x3772, 0x46 }, 78011c0d8fdSPaul Kocialkowski { 0x3773, 0x04 }, 78111c0d8fdSPaul Kocialkowski { 0x3774, 0x2c }, 78211c0d8fdSPaul Kocialkowski { 0x3775, 0x13 }, 78311c0d8fdSPaul Kocialkowski { 0x3776, 0x10 }, 78411c0d8fdSPaul Kocialkowski { 0x37a0, 0x88 }, 78511c0d8fdSPaul Kocialkowski { 0x37a1, 0x7a }, 78611c0d8fdSPaul Kocialkowski { 0x37a2, 0x7a }, 78711c0d8fdSPaul Kocialkowski { 0x37a3, 0x02 }, 78811c0d8fdSPaul Kocialkowski { 0x37a5, 0x09 }, 78911c0d8fdSPaul Kocialkowski { 0x37a7, 0x88 }, 79011c0d8fdSPaul Kocialkowski { 0x37a8, 0xb0 }, 79111c0d8fdSPaul Kocialkowski { 0x37a9, 0xb0 }, 79211c0d8fdSPaul Kocialkowski { 0x37aa, 0x88 }, 79311c0d8fdSPaul Kocialkowski { 0x37ab, 0x5c }, 79411c0d8fdSPaul Kocialkowski { 0x37ac, 0x5c }, 79511c0d8fdSPaul Kocialkowski { 0x37ad, 0x55 }, 79611c0d8fdSPaul Kocialkowski { 0x37ae, 0x19 }, 79711c0d8fdSPaul Kocialkowski { 0x37af, 0x19 }, 79811c0d8fdSPaul Kocialkowski { 0x37b3, 0x84 }, 79911c0d8fdSPaul Kocialkowski { 0x37b4, 0x84 }, 80011c0d8fdSPaul Kocialkowski { 0x37b5, 0x66 }, 80111c0d8fdSPaul Kocialkowski 80211c0d8fdSPaul Kocialkowski /* PSRAM */ 80311c0d8fdSPaul Kocialkowski 80411c0d8fdSPaul Kocialkowski { OV8865_PSRAM_CTRL8_REG, 0x16 }, 80511c0d8fdSPaul Kocialkowski 80611c0d8fdSPaul Kocialkowski /* ADC Sync */ 80711c0d8fdSPaul Kocialkowski 80811c0d8fdSPaul Kocialkowski { 0x4500, 0x68 }, 80911c0d8fdSPaul Kocialkowski }; 81011c0d8fdSPaul Kocialkowski 81111c0d8fdSPaul Kocialkowski static const struct ov8865_register_value ov8865_register_values_binning[] = { 81211c0d8fdSPaul Kocialkowski /* Sensor */ 81311c0d8fdSPaul Kocialkowski 81411c0d8fdSPaul Kocialkowski { 0x3700, 0x24 }, 81511c0d8fdSPaul Kocialkowski { 0x3701, 0x0c }, 81611c0d8fdSPaul Kocialkowski { 0x3702, 0x28 }, 81711c0d8fdSPaul Kocialkowski { 0x3703, 0x19 }, 81811c0d8fdSPaul Kocialkowski { 0x3704, 0x14 }, 81911c0d8fdSPaul Kocialkowski { 0x3706, 0x38 }, 82011c0d8fdSPaul Kocialkowski { 0x3707, 0x04 }, 82111c0d8fdSPaul Kocialkowski { 0x3708, 0x24 }, 82211c0d8fdSPaul Kocialkowski { 0x3709, 0x40 }, 82311c0d8fdSPaul Kocialkowski { 0x370a, 0x00 }, 82411c0d8fdSPaul Kocialkowski { 0x370b, 0xb8 }, 82511c0d8fdSPaul Kocialkowski { 0x370c, 0x04 }, 82611c0d8fdSPaul Kocialkowski { 0x3718, 0x12 }, 82711c0d8fdSPaul Kocialkowski { 0x3712, 0x42 }, 82811c0d8fdSPaul Kocialkowski { 0x371e, 0x19 }, 82911c0d8fdSPaul Kocialkowski { 0x371f, 0x40 }, 83011c0d8fdSPaul Kocialkowski { 0x3720, 0x05 }, 83111c0d8fdSPaul Kocialkowski { 0x3721, 0x05 }, 83211c0d8fdSPaul Kocialkowski { 0x3724, 0x02 }, 83311c0d8fdSPaul Kocialkowski { 0x3725, 0x02 }, 83411c0d8fdSPaul Kocialkowski { 0x3726, 0x06 }, 83511c0d8fdSPaul Kocialkowski { 0x3728, 0x05 }, 83611c0d8fdSPaul Kocialkowski { 0x3729, 0x02 }, 83711c0d8fdSPaul Kocialkowski { 0x372a, 0x03 }, 83811c0d8fdSPaul Kocialkowski { 0x372b, 0x53 }, 83911c0d8fdSPaul Kocialkowski { 0x372c, 0xa3 }, 84011c0d8fdSPaul Kocialkowski { 0x372d, 0x53 }, 84111c0d8fdSPaul Kocialkowski { 0x372e, 0x06 }, 84211c0d8fdSPaul Kocialkowski { 0x372f, 0x10 }, 84311c0d8fdSPaul Kocialkowski { 0x3730, 0x01 }, 84411c0d8fdSPaul Kocialkowski { 0x3731, 0x06 }, 84511c0d8fdSPaul Kocialkowski { 0x3732, 0x14 }, 84611c0d8fdSPaul Kocialkowski { 0x3736, 0x20 }, 84711c0d8fdSPaul Kocialkowski { 0x373a, 0x02 }, 84811c0d8fdSPaul Kocialkowski { 0x373b, 0x0c }, 84911c0d8fdSPaul Kocialkowski { 0x373c, 0x0a }, 85011c0d8fdSPaul Kocialkowski { 0x373e, 0x03 }, 85111c0d8fdSPaul Kocialkowski { 0x375a, 0x06 }, 85211c0d8fdSPaul Kocialkowski { 0x375b, 0x13 }, 85311c0d8fdSPaul Kocialkowski { 0x375d, 0x02 }, 85411c0d8fdSPaul Kocialkowski { 0x375f, 0x14 }, 85511c0d8fdSPaul Kocialkowski { 0x3767, 0x1c }, 85611c0d8fdSPaul Kocialkowski { 0x3772, 0x23 }, 85711c0d8fdSPaul Kocialkowski { 0x3773, 0x02 }, 85811c0d8fdSPaul Kocialkowski { 0x3774, 0x16 }, 85911c0d8fdSPaul Kocialkowski { 0x3775, 0x12 }, 86011c0d8fdSPaul Kocialkowski { 0x3776, 0x08 }, 86111c0d8fdSPaul Kocialkowski { 0x37a0, 0x44 }, 86211c0d8fdSPaul Kocialkowski { 0x37a1, 0x3d }, 86311c0d8fdSPaul Kocialkowski { 0x37a2, 0x3d }, 86411c0d8fdSPaul Kocialkowski { 0x37a3, 0x01 }, 86511c0d8fdSPaul Kocialkowski { 0x37a5, 0x08 }, 86611c0d8fdSPaul Kocialkowski { 0x37a7, 0x44 }, 86711c0d8fdSPaul Kocialkowski { 0x37a8, 0x58 }, 86811c0d8fdSPaul Kocialkowski { 0x37a9, 0x58 }, 86911c0d8fdSPaul Kocialkowski { 0x37aa, 0x44 }, 87011c0d8fdSPaul Kocialkowski { 0x37ab, 0x2e }, 87111c0d8fdSPaul Kocialkowski { 0x37ac, 0x2e }, 87211c0d8fdSPaul Kocialkowski { 0x37ad, 0x33 }, 87311c0d8fdSPaul Kocialkowski { 0x37ae, 0x0d }, 87411c0d8fdSPaul Kocialkowski { 0x37af, 0x0d }, 87511c0d8fdSPaul Kocialkowski { 0x37b3, 0x42 }, 87611c0d8fdSPaul Kocialkowski { 0x37b4, 0x42 }, 87711c0d8fdSPaul Kocialkowski { 0x37b5, 0x33 }, 87811c0d8fdSPaul Kocialkowski 87911c0d8fdSPaul Kocialkowski /* PSRAM */ 88011c0d8fdSPaul Kocialkowski 88111c0d8fdSPaul Kocialkowski { OV8865_PSRAM_CTRL8_REG, 0x0b }, 88211c0d8fdSPaul Kocialkowski 88311c0d8fdSPaul Kocialkowski /* ADC Sync */ 88411c0d8fdSPaul Kocialkowski 88511c0d8fdSPaul Kocialkowski { 0x4500, 0x40 }, 88611c0d8fdSPaul Kocialkowski }; 88711c0d8fdSPaul Kocialkowski 88811c0d8fdSPaul Kocialkowski static const struct ov8865_mode ov8865_modes[] = { 88911c0d8fdSPaul Kocialkowski /* 3264x2448 */ 89011c0d8fdSPaul Kocialkowski { 89111c0d8fdSPaul Kocialkowski /* Horizontal */ 89211c0d8fdSPaul Kocialkowski .output_size_x = 3264, 89311c0d8fdSPaul Kocialkowski .hts = 1944, 89411c0d8fdSPaul Kocialkowski 89511c0d8fdSPaul Kocialkowski /* Vertical */ 89611c0d8fdSPaul Kocialkowski .output_size_y = 2448, 89711c0d8fdSPaul Kocialkowski .vts = 2470, 89811c0d8fdSPaul Kocialkowski 89911c0d8fdSPaul Kocialkowski .size_auto = true, 90011c0d8fdSPaul Kocialkowski .size_auto_boundary_x = 8, 90111c0d8fdSPaul Kocialkowski .size_auto_boundary_y = 4, 90211c0d8fdSPaul Kocialkowski 90311c0d8fdSPaul Kocialkowski /* Subsample increase */ 90411c0d8fdSPaul Kocialkowski .inc_x_odd = 1, 90511c0d8fdSPaul Kocialkowski .inc_x_even = 1, 90611c0d8fdSPaul Kocialkowski .inc_y_odd = 1, 90711c0d8fdSPaul Kocialkowski .inc_y_even = 1, 90811c0d8fdSPaul Kocialkowski 90911c0d8fdSPaul Kocialkowski /* VFIFO */ 91011c0d8fdSPaul Kocialkowski .vfifo_read_start = 16, 91111c0d8fdSPaul Kocialkowski 91211c0d8fdSPaul Kocialkowski .ablc_num = 4, 91311c0d8fdSPaul Kocialkowski .zline_num = 1, 91411c0d8fdSPaul Kocialkowski 91511c0d8fdSPaul Kocialkowski /* Black Level */ 91611c0d8fdSPaul Kocialkowski 91711c0d8fdSPaul Kocialkowski .blc_top_zero_line_start = 0, 91811c0d8fdSPaul Kocialkowski .blc_top_zero_line_num = 2, 91911c0d8fdSPaul Kocialkowski .blc_top_black_line_start = 4, 92011c0d8fdSPaul Kocialkowski .blc_top_black_line_num = 4, 92111c0d8fdSPaul Kocialkowski 92211c0d8fdSPaul Kocialkowski .blc_bottom_zero_line_start = 2, 92311c0d8fdSPaul Kocialkowski .blc_bottom_zero_line_num = 2, 92411c0d8fdSPaul Kocialkowski .blc_bottom_black_line_start = 8, 92511c0d8fdSPaul Kocialkowski .blc_bottom_black_line_num = 2, 92611c0d8fdSPaul Kocialkowski 92711c0d8fdSPaul Kocialkowski .blc_anchor_left_start = 576, 92811c0d8fdSPaul Kocialkowski .blc_anchor_left_end = 831, 92911c0d8fdSPaul Kocialkowski .blc_anchor_right_start = 1984, 93011c0d8fdSPaul Kocialkowski .blc_anchor_right_end = 2239, 93111c0d8fdSPaul Kocialkowski 93211c0d8fdSPaul Kocialkowski /* Frame Interval */ 93311c0d8fdSPaul Kocialkowski .frame_interval = { 1, 30 }, 93411c0d8fdSPaul Kocialkowski 93511c0d8fdSPaul Kocialkowski /* PLL */ 93611c0d8fdSPaul Kocialkowski .pll1_config = &ov8865_pll1_config_native, 93711c0d8fdSPaul Kocialkowski .pll2_config = &ov8865_pll2_config_native, 93811c0d8fdSPaul Kocialkowski .sclk_config = &ov8865_sclk_config_native, 93911c0d8fdSPaul Kocialkowski 94011c0d8fdSPaul Kocialkowski /* Registers */ 94111c0d8fdSPaul Kocialkowski .register_values = ov8865_register_values_native, 94211c0d8fdSPaul Kocialkowski .register_values_count = 94311c0d8fdSPaul Kocialkowski ARRAY_SIZE(ov8865_register_values_native), 94411c0d8fdSPaul Kocialkowski }, 94511c0d8fdSPaul Kocialkowski /* 3264x1836 */ 94611c0d8fdSPaul Kocialkowski { 94711c0d8fdSPaul Kocialkowski /* Horizontal */ 94811c0d8fdSPaul Kocialkowski .output_size_x = 3264, 94911c0d8fdSPaul Kocialkowski .hts = 2582, 95011c0d8fdSPaul Kocialkowski 95111c0d8fdSPaul Kocialkowski /* Vertical */ 95211c0d8fdSPaul Kocialkowski .output_size_y = 1836, 95311c0d8fdSPaul Kocialkowski .vts = 2002, 95411c0d8fdSPaul Kocialkowski 95511c0d8fdSPaul Kocialkowski .size_auto = true, 95611c0d8fdSPaul Kocialkowski .size_auto_boundary_x = 8, 95711c0d8fdSPaul Kocialkowski .size_auto_boundary_y = 4, 95811c0d8fdSPaul Kocialkowski 95911c0d8fdSPaul Kocialkowski /* Subsample increase */ 96011c0d8fdSPaul Kocialkowski .inc_x_odd = 1, 96111c0d8fdSPaul Kocialkowski .inc_x_even = 1, 96211c0d8fdSPaul Kocialkowski .inc_y_odd = 1, 96311c0d8fdSPaul Kocialkowski .inc_y_even = 1, 96411c0d8fdSPaul Kocialkowski 96511c0d8fdSPaul Kocialkowski /* VFIFO */ 96611c0d8fdSPaul Kocialkowski .vfifo_read_start = 16, 96711c0d8fdSPaul Kocialkowski 96811c0d8fdSPaul Kocialkowski .ablc_num = 4, 96911c0d8fdSPaul Kocialkowski .zline_num = 1, 97011c0d8fdSPaul Kocialkowski 97111c0d8fdSPaul Kocialkowski /* Black Level */ 97211c0d8fdSPaul Kocialkowski 97311c0d8fdSPaul Kocialkowski .blc_top_zero_line_start = 0, 97411c0d8fdSPaul Kocialkowski .blc_top_zero_line_num = 2, 97511c0d8fdSPaul Kocialkowski .blc_top_black_line_start = 4, 97611c0d8fdSPaul Kocialkowski .blc_top_black_line_num = 4, 97711c0d8fdSPaul Kocialkowski 97811c0d8fdSPaul Kocialkowski .blc_bottom_zero_line_start = 2, 97911c0d8fdSPaul Kocialkowski .blc_bottom_zero_line_num = 2, 98011c0d8fdSPaul Kocialkowski .blc_bottom_black_line_start = 8, 98111c0d8fdSPaul Kocialkowski .blc_bottom_black_line_num = 2, 98211c0d8fdSPaul Kocialkowski 98311c0d8fdSPaul Kocialkowski .blc_anchor_left_start = 576, 98411c0d8fdSPaul Kocialkowski .blc_anchor_left_end = 831, 98511c0d8fdSPaul Kocialkowski .blc_anchor_right_start = 1984, 98611c0d8fdSPaul Kocialkowski .blc_anchor_right_end = 2239, 98711c0d8fdSPaul Kocialkowski 98811c0d8fdSPaul Kocialkowski /* Frame Interval */ 98911c0d8fdSPaul Kocialkowski .frame_interval = { 1, 30 }, 99011c0d8fdSPaul Kocialkowski 99111c0d8fdSPaul Kocialkowski /* PLL */ 99211c0d8fdSPaul Kocialkowski .pll1_config = &ov8865_pll1_config_native, 99311c0d8fdSPaul Kocialkowski .pll2_config = &ov8865_pll2_config_native, 99411c0d8fdSPaul Kocialkowski .sclk_config = &ov8865_sclk_config_native, 99511c0d8fdSPaul Kocialkowski 99611c0d8fdSPaul Kocialkowski /* Registers */ 99711c0d8fdSPaul Kocialkowski .register_values = ov8865_register_values_native, 99811c0d8fdSPaul Kocialkowski .register_values_count = 99911c0d8fdSPaul Kocialkowski ARRAY_SIZE(ov8865_register_values_native), 100011c0d8fdSPaul Kocialkowski }, 100111c0d8fdSPaul Kocialkowski /* 1632x1224 */ 100211c0d8fdSPaul Kocialkowski { 100311c0d8fdSPaul Kocialkowski /* Horizontal */ 100411c0d8fdSPaul Kocialkowski .output_size_x = 1632, 100511c0d8fdSPaul Kocialkowski .hts = 1923, 100611c0d8fdSPaul Kocialkowski 100711c0d8fdSPaul Kocialkowski /* Vertical */ 100811c0d8fdSPaul Kocialkowski .output_size_y = 1224, 100911c0d8fdSPaul Kocialkowski .vts = 1248, 101011c0d8fdSPaul Kocialkowski 101111c0d8fdSPaul Kocialkowski .size_auto = true, 101211c0d8fdSPaul Kocialkowski .size_auto_boundary_x = 8, 101311c0d8fdSPaul Kocialkowski .size_auto_boundary_y = 8, 101411c0d8fdSPaul Kocialkowski 101511c0d8fdSPaul Kocialkowski /* Subsample increase */ 101611c0d8fdSPaul Kocialkowski .inc_x_odd = 3, 101711c0d8fdSPaul Kocialkowski .inc_x_even = 1, 101811c0d8fdSPaul Kocialkowski .inc_y_odd = 3, 101911c0d8fdSPaul Kocialkowski .inc_y_even = 1, 102011c0d8fdSPaul Kocialkowski 102111c0d8fdSPaul Kocialkowski /* Binning */ 102211c0d8fdSPaul Kocialkowski .binning_y = true, 102311c0d8fdSPaul Kocialkowski .sync_hbin = true, 102411c0d8fdSPaul Kocialkowski 102511c0d8fdSPaul Kocialkowski /* VFIFO */ 102611c0d8fdSPaul Kocialkowski .vfifo_read_start = 116, 102711c0d8fdSPaul Kocialkowski 102811c0d8fdSPaul Kocialkowski .ablc_num = 8, 102911c0d8fdSPaul Kocialkowski .zline_num = 2, 103011c0d8fdSPaul Kocialkowski 103111c0d8fdSPaul Kocialkowski /* Black Level */ 103211c0d8fdSPaul Kocialkowski 103311c0d8fdSPaul Kocialkowski .blc_top_zero_line_start = 0, 103411c0d8fdSPaul Kocialkowski .blc_top_zero_line_num = 2, 103511c0d8fdSPaul Kocialkowski .blc_top_black_line_start = 4, 103611c0d8fdSPaul Kocialkowski .blc_top_black_line_num = 4, 103711c0d8fdSPaul Kocialkowski 103811c0d8fdSPaul Kocialkowski .blc_bottom_zero_line_start = 2, 103911c0d8fdSPaul Kocialkowski .blc_bottom_zero_line_num = 2, 104011c0d8fdSPaul Kocialkowski .blc_bottom_black_line_start = 8, 104111c0d8fdSPaul Kocialkowski .blc_bottom_black_line_num = 2, 104211c0d8fdSPaul Kocialkowski 104311c0d8fdSPaul Kocialkowski .blc_anchor_left_start = 288, 104411c0d8fdSPaul Kocialkowski .blc_anchor_left_end = 415, 104511c0d8fdSPaul Kocialkowski .blc_anchor_right_start = 992, 104611c0d8fdSPaul Kocialkowski .blc_anchor_right_end = 1119, 104711c0d8fdSPaul Kocialkowski 104811c0d8fdSPaul Kocialkowski /* Frame Interval */ 104911c0d8fdSPaul Kocialkowski .frame_interval = { 1, 30 }, 105011c0d8fdSPaul Kocialkowski 105111c0d8fdSPaul Kocialkowski /* PLL */ 105211c0d8fdSPaul Kocialkowski .pll1_config = &ov8865_pll1_config_native, 105311c0d8fdSPaul Kocialkowski .pll2_config = &ov8865_pll2_config_binning, 105411c0d8fdSPaul Kocialkowski .sclk_config = &ov8865_sclk_config_native, 105511c0d8fdSPaul Kocialkowski 105611c0d8fdSPaul Kocialkowski /* Registers */ 105711c0d8fdSPaul Kocialkowski .register_values = ov8865_register_values_binning, 105811c0d8fdSPaul Kocialkowski .register_values_count = 105911c0d8fdSPaul Kocialkowski ARRAY_SIZE(ov8865_register_values_binning), 106011c0d8fdSPaul Kocialkowski }, 106111c0d8fdSPaul Kocialkowski /* 800x600 (SVGA) */ 106211c0d8fdSPaul Kocialkowski { 106311c0d8fdSPaul Kocialkowski /* Horizontal */ 106411c0d8fdSPaul Kocialkowski .output_size_x = 800, 106511c0d8fdSPaul Kocialkowski .hts = 1250, 106611c0d8fdSPaul Kocialkowski 106711c0d8fdSPaul Kocialkowski /* Vertical */ 106811c0d8fdSPaul Kocialkowski .output_size_y = 600, 106911c0d8fdSPaul Kocialkowski .vts = 640, 107011c0d8fdSPaul Kocialkowski 107111c0d8fdSPaul Kocialkowski .size_auto = true, 107211c0d8fdSPaul Kocialkowski .size_auto_boundary_x = 8, 107311c0d8fdSPaul Kocialkowski .size_auto_boundary_y = 8, 107411c0d8fdSPaul Kocialkowski 107511c0d8fdSPaul Kocialkowski /* Subsample increase */ 107611c0d8fdSPaul Kocialkowski .inc_x_odd = 3, 107711c0d8fdSPaul Kocialkowski .inc_x_even = 1, 107811c0d8fdSPaul Kocialkowski .inc_y_odd = 5, 107911c0d8fdSPaul Kocialkowski .inc_y_even = 3, 108011c0d8fdSPaul Kocialkowski 108111c0d8fdSPaul Kocialkowski /* Binning */ 108211c0d8fdSPaul Kocialkowski .binning_y = true, 108311c0d8fdSPaul Kocialkowski .variopixel = true, 108411c0d8fdSPaul Kocialkowski .variopixel_hsub_coef = 2, 108511c0d8fdSPaul Kocialkowski .variopixel_vsub_coef = 1, 108611c0d8fdSPaul Kocialkowski .sync_hbin = true, 108711c0d8fdSPaul Kocialkowski .horz_var2 = true, 108811c0d8fdSPaul Kocialkowski 108911c0d8fdSPaul Kocialkowski /* VFIFO */ 109011c0d8fdSPaul Kocialkowski .vfifo_read_start = 80, 109111c0d8fdSPaul Kocialkowski 109211c0d8fdSPaul Kocialkowski .ablc_num = 8, 109311c0d8fdSPaul Kocialkowski .zline_num = 2, 109411c0d8fdSPaul Kocialkowski 109511c0d8fdSPaul Kocialkowski /* Black Level */ 109611c0d8fdSPaul Kocialkowski 109711c0d8fdSPaul Kocialkowski .blc_top_zero_line_start = 0, 109811c0d8fdSPaul Kocialkowski .blc_top_zero_line_num = 2, 109911c0d8fdSPaul Kocialkowski .blc_top_black_line_start = 2, 110011c0d8fdSPaul Kocialkowski .blc_top_black_line_num = 2, 110111c0d8fdSPaul Kocialkowski 110211c0d8fdSPaul Kocialkowski .blc_bottom_zero_line_start = 0, 110311c0d8fdSPaul Kocialkowski .blc_bottom_zero_line_num = 0, 110411c0d8fdSPaul Kocialkowski .blc_bottom_black_line_start = 4, 110511c0d8fdSPaul Kocialkowski .blc_bottom_black_line_num = 2, 110611c0d8fdSPaul Kocialkowski 110711c0d8fdSPaul Kocialkowski .blc_col_shift_mask = OV8865_BLC_CTRL1_COL_SHIFT_128, 110811c0d8fdSPaul Kocialkowski 110911c0d8fdSPaul Kocialkowski .blc_anchor_left_start = 288, 111011c0d8fdSPaul Kocialkowski .blc_anchor_left_end = 415, 111111c0d8fdSPaul Kocialkowski .blc_anchor_right_start = 992, 111211c0d8fdSPaul Kocialkowski .blc_anchor_right_end = 1119, 111311c0d8fdSPaul Kocialkowski 111411c0d8fdSPaul Kocialkowski /* Frame Interval */ 111511c0d8fdSPaul Kocialkowski .frame_interval = { 1, 90 }, 111611c0d8fdSPaul Kocialkowski 111711c0d8fdSPaul Kocialkowski /* PLL */ 111811c0d8fdSPaul Kocialkowski .pll1_config = &ov8865_pll1_config_native, 111911c0d8fdSPaul Kocialkowski .pll2_config = &ov8865_pll2_config_binning, 112011c0d8fdSPaul Kocialkowski .sclk_config = &ov8865_sclk_config_native, 112111c0d8fdSPaul Kocialkowski 112211c0d8fdSPaul Kocialkowski /* Registers */ 112311c0d8fdSPaul Kocialkowski .register_values = ov8865_register_values_binning, 112411c0d8fdSPaul Kocialkowski .register_values_count = 112511c0d8fdSPaul Kocialkowski ARRAY_SIZE(ov8865_register_values_binning), 112611c0d8fdSPaul Kocialkowski }, 112711c0d8fdSPaul Kocialkowski }; 112811c0d8fdSPaul Kocialkowski 112911c0d8fdSPaul Kocialkowski static const u32 ov8865_mbus_codes[] = { 113011c0d8fdSPaul Kocialkowski MEDIA_BUS_FMT_SBGGR10_1X10, 113111c0d8fdSPaul Kocialkowski }; 113211c0d8fdSPaul Kocialkowski 113311c0d8fdSPaul Kocialkowski static const struct ov8865_register_value ov8865_init_sequence[] = { 113411c0d8fdSPaul Kocialkowski /* Analog */ 113511c0d8fdSPaul Kocialkowski 113611c0d8fdSPaul Kocialkowski { 0x3604, 0x04 }, 113711c0d8fdSPaul Kocialkowski { 0x3602, 0x30 }, 113811c0d8fdSPaul Kocialkowski { 0x3605, 0x00 }, 113911c0d8fdSPaul Kocialkowski { 0x3607, 0x20 }, 114011c0d8fdSPaul Kocialkowski { 0x3608, 0x11 }, 114111c0d8fdSPaul Kocialkowski { 0x3609, 0x68 }, 114211c0d8fdSPaul Kocialkowski { 0x360a, 0x40 }, 114311c0d8fdSPaul Kocialkowski { 0x360c, 0xdd }, 114411c0d8fdSPaul Kocialkowski { 0x360e, 0x0c }, 114511c0d8fdSPaul Kocialkowski { 0x3610, 0x07 }, 114611c0d8fdSPaul Kocialkowski { 0x3612, 0x86 }, 114711c0d8fdSPaul Kocialkowski { 0x3613, 0x58 }, 114811c0d8fdSPaul Kocialkowski { 0x3614, 0x28 }, 114911c0d8fdSPaul Kocialkowski { 0x3617, 0x40 }, 115011c0d8fdSPaul Kocialkowski { 0x3618, 0x5a }, 115111c0d8fdSPaul Kocialkowski { 0x3619, 0x9b }, 115211c0d8fdSPaul Kocialkowski { 0x361c, 0x00 }, 115311c0d8fdSPaul Kocialkowski { 0x361d, 0x60 }, 115411c0d8fdSPaul Kocialkowski { 0x3631, 0x60 }, 115511c0d8fdSPaul Kocialkowski { 0x3633, 0x10 }, 115611c0d8fdSPaul Kocialkowski { 0x3634, 0x10 }, 115711c0d8fdSPaul Kocialkowski { 0x3635, 0x10 }, 115811c0d8fdSPaul Kocialkowski { 0x3636, 0x10 }, 115911c0d8fdSPaul Kocialkowski { 0x3638, 0xff }, 116011c0d8fdSPaul Kocialkowski { 0x3641, 0x55 }, 116111c0d8fdSPaul Kocialkowski { 0x3646, 0x86 }, 116211c0d8fdSPaul Kocialkowski { 0x3647, 0x27 }, 116311c0d8fdSPaul Kocialkowski { 0x364a, 0x1b }, 116411c0d8fdSPaul Kocialkowski 116511c0d8fdSPaul Kocialkowski /* Sensor */ 116611c0d8fdSPaul Kocialkowski 116711c0d8fdSPaul Kocialkowski { 0x3700, 0x24 }, 116811c0d8fdSPaul Kocialkowski { 0x3701, 0x0c }, 116911c0d8fdSPaul Kocialkowski { 0x3702, 0x28 }, 117011c0d8fdSPaul Kocialkowski { 0x3703, 0x19 }, 117111c0d8fdSPaul Kocialkowski { 0x3704, 0x14 }, 117211c0d8fdSPaul Kocialkowski { 0x3705, 0x00 }, 117311c0d8fdSPaul Kocialkowski { 0x3706, 0x38 }, 117411c0d8fdSPaul Kocialkowski { 0x3707, 0x04 }, 117511c0d8fdSPaul Kocialkowski { 0x3708, 0x24 }, 117611c0d8fdSPaul Kocialkowski { 0x3709, 0x40 }, 117711c0d8fdSPaul Kocialkowski { 0x370a, 0x00 }, 117811c0d8fdSPaul Kocialkowski { 0x370b, 0xb8 }, 117911c0d8fdSPaul Kocialkowski { 0x370c, 0x04 }, 118011c0d8fdSPaul Kocialkowski { 0x3718, 0x12 }, 118111c0d8fdSPaul Kocialkowski { 0x3719, 0x31 }, 118211c0d8fdSPaul Kocialkowski { 0x3712, 0x42 }, 118311c0d8fdSPaul Kocialkowski { 0x3714, 0x12 }, 118411c0d8fdSPaul Kocialkowski { 0x371e, 0x19 }, 118511c0d8fdSPaul Kocialkowski { 0x371f, 0x40 }, 118611c0d8fdSPaul Kocialkowski { 0x3720, 0x05 }, 118711c0d8fdSPaul Kocialkowski { 0x3721, 0x05 }, 118811c0d8fdSPaul Kocialkowski { 0x3724, 0x02 }, 118911c0d8fdSPaul Kocialkowski { 0x3725, 0x02 }, 119011c0d8fdSPaul Kocialkowski { 0x3726, 0x06 }, 119111c0d8fdSPaul Kocialkowski { 0x3728, 0x05 }, 119211c0d8fdSPaul Kocialkowski { 0x3729, 0x02 }, 119311c0d8fdSPaul Kocialkowski { 0x372a, 0x03 }, 119411c0d8fdSPaul Kocialkowski { 0x372b, 0x53 }, 119511c0d8fdSPaul Kocialkowski { 0x372c, 0xa3 }, 119611c0d8fdSPaul Kocialkowski { 0x372d, 0x53 }, 119711c0d8fdSPaul Kocialkowski { 0x372e, 0x06 }, 119811c0d8fdSPaul Kocialkowski { 0x372f, 0x10 }, 119911c0d8fdSPaul Kocialkowski { 0x3730, 0x01 }, 120011c0d8fdSPaul Kocialkowski { 0x3731, 0x06 }, 120111c0d8fdSPaul Kocialkowski { 0x3732, 0x14 }, 120211c0d8fdSPaul Kocialkowski { 0x3733, 0x10 }, 120311c0d8fdSPaul Kocialkowski { 0x3734, 0x40 }, 120411c0d8fdSPaul Kocialkowski { 0x3736, 0x20 }, 120511c0d8fdSPaul Kocialkowski { 0x373a, 0x02 }, 120611c0d8fdSPaul Kocialkowski { 0x373b, 0x0c }, 120711c0d8fdSPaul Kocialkowski { 0x373c, 0x0a }, 120811c0d8fdSPaul Kocialkowski { 0x373e, 0x03 }, 120911c0d8fdSPaul Kocialkowski { 0x3755, 0x40 }, 121011c0d8fdSPaul Kocialkowski { 0x3758, 0x00 }, 121111c0d8fdSPaul Kocialkowski { 0x3759, 0x4c }, 121211c0d8fdSPaul Kocialkowski { 0x375a, 0x06 }, 121311c0d8fdSPaul Kocialkowski { 0x375b, 0x13 }, 121411c0d8fdSPaul Kocialkowski { 0x375c, 0x40 }, 121511c0d8fdSPaul Kocialkowski { 0x375d, 0x02 }, 121611c0d8fdSPaul Kocialkowski { 0x375e, 0x00 }, 121711c0d8fdSPaul Kocialkowski { 0x375f, 0x14 }, 121811c0d8fdSPaul Kocialkowski { 0x3767, 0x1c }, 121911c0d8fdSPaul Kocialkowski { 0x3768, 0x04 }, 122011c0d8fdSPaul Kocialkowski { 0x3769, 0x20 }, 122111c0d8fdSPaul Kocialkowski { 0x376c, 0xc0 }, 122211c0d8fdSPaul Kocialkowski { 0x376d, 0xc0 }, 122311c0d8fdSPaul Kocialkowski { 0x376a, 0x08 }, 122411c0d8fdSPaul Kocialkowski { 0x3761, 0x00 }, 122511c0d8fdSPaul Kocialkowski { 0x3762, 0x00 }, 122611c0d8fdSPaul Kocialkowski { 0x3763, 0x00 }, 122711c0d8fdSPaul Kocialkowski { 0x3766, 0xff }, 122811c0d8fdSPaul Kocialkowski { 0x376b, 0x42 }, 122911c0d8fdSPaul Kocialkowski { 0x3772, 0x23 }, 123011c0d8fdSPaul Kocialkowski { 0x3773, 0x02 }, 123111c0d8fdSPaul Kocialkowski { 0x3774, 0x16 }, 123211c0d8fdSPaul Kocialkowski { 0x3775, 0x12 }, 123311c0d8fdSPaul Kocialkowski { 0x3776, 0x08 }, 123411c0d8fdSPaul Kocialkowski { 0x37a0, 0x44 }, 123511c0d8fdSPaul Kocialkowski { 0x37a1, 0x3d }, 123611c0d8fdSPaul Kocialkowski { 0x37a2, 0x3d }, 123711c0d8fdSPaul Kocialkowski { 0x37a3, 0x01 }, 123811c0d8fdSPaul Kocialkowski { 0x37a4, 0x00 }, 123911c0d8fdSPaul Kocialkowski { 0x37a5, 0x08 }, 124011c0d8fdSPaul Kocialkowski { 0x37a6, 0x00 }, 124111c0d8fdSPaul Kocialkowski { 0x37a7, 0x44 }, 124211c0d8fdSPaul Kocialkowski { 0x37a8, 0x58 }, 124311c0d8fdSPaul Kocialkowski { 0x37a9, 0x58 }, 124411c0d8fdSPaul Kocialkowski { 0x3760, 0x00 }, 124511c0d8fdSPaul Kocialkowski { 0x376f, 0x01 }, 124611c0d8fdSPaul Kocialkowski { 0x37aa, 0x44 }, 124711c0d8fdSPaul Kocialkowski { 0x37ab, 0x2e }, 124811c0d8fdSPaul Kocialkowski { 0x37ac, 0x2e }, 124911c0d8fdSPaul Kocialkowski { 0x37ad, 0x33 }, 125011c0d8fdSPaul Kocialkowski { 0x37ae, 0x0d }, 125111c0d8fdSPaul Kocialkowski { 0x37af, 0x0d }, 125211c0d8fdSPaul Kocialkowski { 0x37b0, 0x00 }, 125311c0d8fdSPaul Kocialkowski { 0x37b1, 0x00 }, 125411c0d8fdSPaul Kocialkowski { 0x37b2, 0x00 }, 125511c0d8fdSPaul Kocialkowski { 0x37b3, 0x42 }, 125611c0d8fdSPaul Kocialkowski { 0x37b4, 0x42 }, 125711c0d8fdSPaul Kocialkowski { 0x37b5, 0x33 }, 125811c0d8fdSPaul Kocialkowski { 0x37b6, 0x00 }, 125911c0d8fdSPaul Kocialkowski { 0x37b7, 0x00 }, 126011c0d8fdSPaul Kocialkowski { 0x37b8, 0x00 }, 126111c0d8fdSPaul Kocialkowski { 0x37b9, 0xff }, 126211c0d8fdSPaul Kocialkowski 126311c0d8fdSPaul Kocialkowski /* ADC Sync */ 126411c0d8fdSPaul Kocialkowski 126511c0d8fdSPaul Kocialkowski { 0x4503, 0x10 }, 126611c0d8fdSPaul Kocialkowski }; 126711c0d8fdSPaul Kocialkowski 126811c0d8fdSPaul Kocialkowski static const s64 ov8865_link_freq_menu[] = { 126911c0d8fdSPaul Kocialkowski 360000000, 127011c0d8fdSPaul Kocialkowski }; 127111c0d8fdSPaul Kocialkowski 127211c0d8fdSPaul Kocialkowski static const char *const ov8865_test_pattern_menu[] = { 127311c0d8fdSPaul Kocialkowski "Disabled", 127411c0d8fdSPaul Kocialkowski "Random data", 127511c0d8fdSPaul Kocialkowski "Color bars", 127611c0d8fdSPaul Kocialkowski "Color bars with rolling bar", 127711c0d8fdSPaul Kocialkowski "Color squares", 127811c0d8fdSPaul Kocialkowski "Color squares with rolling bar" 127911c0d8fdSPaul Kocialkowski }; 128011c0d8fdSPaul Kocialkowski 128111c0d8fdSPaul Kocialkowski static const u8 ov8865_test_pattern_bits[] = { 128211c0d8fdSPaul Kocialkowski 0, 128311c0d8fdSPaul Kocialkowski OV8865_PRE_CTRL0_PATTERN_EN | OV8865_PRE_CTRL0_PATTERN_RANDOM_DATA, 128411c0d8fdSPaul Kocialkowski OV8865_PRE_CTRL0_PATTERN_EN | OV8865_PRE_CTRL0_PATTERN_COLOR_BARS, 128511c0d8fdSPaul Kocialkowski OV8865_PRE_CTRL0_PATTERN_EN | OV8865_PRE_CTRL0_ROLLING_BAR_EN | 128611c0d8fdSPaul Kocialkowski OV8865_PRE_CTRL0_PATTERN_COLOR_BARS, 128711c0d8fdSPaul Kocialkowski OV8865_PRE_CTRL0_PATTERN_EN | OV8865_PRE_CTRL0_PATTERN_COLOR_SQUARES, 128811c0d8fdSPaul Kocialkowski OV8865_PRE_CTRL0_PATTERN_EN | OV8865_PRE_CTRL0_ROLLING_BAR_EN | 128911c0d8fdSPaul Kocialkowski OV8865_PRE_CTRL0_PATTERN_COLOR_SQUARES, 129011c0d8fdSPaul Kocialkowski }; 129111c0d8fdSPaul Kocialkowski 129211c0d8fdSPaul Kocialkowski /* Input/Output */ 129311c0d8fdSPaul Kocialkowski 129411c0d8fdSPaul Kocialkowski static int ov8865_read(struct ov8865_sensor *sensor, u16 address, u8 *value) 129511c0d8fdSPaul Kocialkowski { 129611c0d8fdSPaul Kocialkowski unsigned char data[2] = { address >> 8, address & 0xff }; 129711c0d8fdSPaul Kocialkowski struct i2c_client *client = sensor->i2c_client; 129811c0d8fdSPaul Kocialkowski int ret; 129911c0d8fdSPaul Kocialkowski 130011c0d8fdSPaul Kocialkowski ret = i2c_master_send(client, data, sizeof(data)); 130111c0d8fdSPaul Kocialkowski if (ret < 0) { 130211c0d8fdSPaul Kocialkowski dev_dbg(&client->dev, "i2c send error at address %#04x\n", 130311c0d8fdSPaul Kocialkowski address); 130411c0d8fdSPaul Kocialkowski return ret; 130511c0d8fdSPaul Kocialkowski } 130611c0d8fdSPaul Kocialkowski 130711c0d8fdSPaul Kocialkowski ret = i2c_master_recv(client, value, 1); 130811c0d8fdSPaul Kocialkowski if (ret < 0) { 130911c0d8fdSPaul Kocialkowski dev_dbg(&client->dev, "i2c recv error at address %#04x\n", 131011c0d8fdSPaul Kocialkowski address); 131111c0d8fdSPaul Kocialkowski return ret; 131211c0d8fdSPaul Kocialkowski } 131311c0d8fdSPaul Kocialkowski 131411c0d8fdSPaul Kocialkowski return 0; 131511c0d8fdSPaul Kocialkowski } 131611c0d8fdSPaul Kocialkowski 131711c0d8fdSPaul Kocialkowski static int ov8865_write(struct ov8865_sensor *sensor, u16 address, u8 value) 131811c0d8fdSPaul Kocialkowski { 131911c0d8fdSPaul Kocialkowski unsigned char data[3] = { address >> 8, address & 0xff, value }; 132011c0d8fdSPaul Kocialkowski struct i2c_client *client = sensor->i2c_client; 132111c0d8fdSPaul Kocialkowski int ret; 132211c0d8fdSPaul Kocialkowski 132311c0d8fdSPaul Kocialkowski ret = i2c_master_send(client, data, sizeof(data)); 132411c0d8fdSPaul Kocialkowski if (ret < 0) { 132511c0d8fdSPaul Kocialkowski dev_dbg(&client->dev, "i2c send error at address %#04x\n", 132611c0d8fdSPaul Kocialkowski address); 132711c0d8fdSPaul Kocialkowski return ret; 132811c0d8fdSPaul Kocialkowski } 132911c0d8fdSPaul Kocialkowski 133011c0d8fdSPaul Kocialkowski return 0; 133111c0d8fdSPaul Kocialkowski } 133211c0d8fdSPaul Kocialkowski 133311c0d8fdSPaul Kocialkowski static int ov8865_write_sequence(struct ov8865_sensor *sensor, 133411c0d8fdSPaul Kocialkowski const struct ov8865_register_value *sequence, 133511c0d8fdSPaul Kocialkowski unsigned int sequence_count) 133611c0d8fdSPaul Kocialkowski { 133711c0d8fdSPaul Kocialkowski unsigned int i; 133811c0d8fdSPaul Kocialkowski int ret = 0; 133911c0d8fdSPaul Kocialkowski 134011c0d8fdSPaul Kocialkowski for (i = 0; i < sequence_count; i++) { 134111c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, sequence[i].address, 134211c0d8fdSPaul Kocialkowski sequence[i].value); 134311c0d8fdSPaul Kocialkowski if (ret) 134411c0d8fdSPaul Kocialkowski break; 134511c0d8fdSPaul Kocialkowski 134611c0d8fdSPaul Kocialkowski if (sequence[i].delay_ms) 134711c0d8fdSPaul Kocialkowski msleep(sequence[i].delay_ms); 134811c0d8fdSPaul Kocialkowski } 134911c0d8fdSPaul Kocialkowski 135011c0d8fdSPaul Kocialkowski return ret; 135111c0d8fdSPaul Kocialkowski } 135211c0d8fdSPaul Kocialkowski 135311c0d8fdSPaul Kocialkowski static int ov8865_update_bits(struct ov8865_sensor *sensor, u16 address, 135411c0d8fdSPaul Kocialkowski u8 mask, u8 bits) 135511c0d8fdSPaul Kocialkowski { 135611c0d8fdSPaul Kocialkowski u8 value = 0; 135711c0d8fdSPaul Kocialkowski int ret; 135811c0d8fdSPaul Kocialkowski 135911c0d8fdSPaul Kocialkowski ret = ov8865_read(sensor, address, &value); 136011c0d8fdSPaul Kocialkowski if (ret) 136111c0d8fdSPaul Kocialkowski return ret; 136211c0d8fdSPaul Kocialkowski 136311c0d8fdSPaul Kocialkowski value &= ~mask; 136411c0d8fdSPaul Kocialkowski value |= bits; 136511c0d8fdSPaul Kocialkowski 136611c0d8fdSPaul Kocialkowski return ov8865_write(sensor, address, value); 136711c0d8fdSPaul Kocialkowski } 136811c0d8fdSPaul Kocialkowski 136911c0d8fdSPaul Kocialkowski /* Sensor */ 137011c0d8fdSPaul Kocialkowski 137111c0d8fdSPaul Kocialkowski static int ov8865_sw_reset(struct ov8865_sensor *sensor) 137211c0d8fdSPaul Kocialkowski { 137311c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_SW_RESET_REG, OV8865_SW_RESET_RESET); 137411c0d8fdSPaul Kocialkowski } 137511c0d8fdSPaul Kocialkowski 137611c0d8fdSPaul Kocialkowski static int ov8865_sw_standby(struct ov8865_sensor *sensor, int standby) 137711c0d8fdSPaul Kocialkowski { 137811c0d8fdSPaul Kocialkowski u8 value = 0; 137911c0d8fdSPaul Kocialkowski 138011c0d8fdSPaul Kocialkowski if (!standby) 138111c0d8fdSPaul Kocialkowski value = OV8865_SW_STANDBY_STREAM_ON; 138211c0d8fdSPaul Kocialkowski 138311c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_SW_STANDBY_REG, value); 138411c0d8fdSPaul Kocialkowski } 138511c0d8fdSPaul Kocialkowski 138611c0d8fdSPaul Kocialkowski static int ov8865_chip_id_check(struct ov8865_sensor *sensor) 138711c0d8fdSPaul Kocialkowski { 138811c0d8fdSPaul Kocialkowski u16 regs[] = { OV8865_CHIP_ID_HH_REG, OV8865_CHIP_ID_H_REG, 138911c0d8fdSPaul Kocialkowski OV8865_CHIP_ID_L_REG }; 139011c0d8fdSPaul Kocialkowski u8 values[] = { OV8865_CHIP_ID_HH_VALUE, OV8865_CHIP_ID_H_VALUE, 139111c0d8fdSPaul Kocialkowski OV8865_CHIP_ID_L_VALUE }; 139211c0d8fdSPaul Kocialkowski unsigned int i; 139311c0d8fdSPaul Kocialkowski u8 value; 139411c0d8fdSPaul Kocialkowski int ret; 139511c0d8fdSPaul Kocialkowski 139611c0d8fdSPaul Kocialkowski for (i = 0; i < ARRAY_SIZE(regs); i++) { 139711c0d8fdSPaul Kocialkowski ret = ov8865_read(sensor, regs[i], &value); 139811c0d8fdSPaul Kocialkowski if (ret < 0) 139911c0d8fdSPaul Kocialkowski return ret; 140011c0d8fdSPaul Kocialkowski 140111c0d8fdSPaul Kocialkowski if (value != values[i]) { 140211c0d8fdSPaul Kocialkowski dev_err(sensor->dev, 140311c0d8fdSPaul Kocialkowski "chip id value mismatch: %#x instead of %#x\n", 140411c0d8fdSPaul Kocialkowski value, values[i]); 140511c0d8fdSPaul Kocialkowski return -EINVAL; 140611c0d8fdSPaul Kocialkowski } 140711c0d8fdSPaul Kocialkowski } 140811c0d8fdSPaul Kocialkowski 140911c0d8fdSPaul Kocialkowski return 0; 141011c0d8fdSPaul Kocialkowski } 141111c0d8fdSPaul Kocialkowski 141211c0d8fdSPaul Kocialkowski static int ov8865_charge_pump_configure(struct ov8865_sensor *sensor) 141311c0d8fdSPaul Kocialkowski { 141411c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_PUMP_CLK_DIV_REG, 141511c0d8fdSPaul Kocialkowski OV8865_PUMP_CLK_DIV_PUMP_P(1)); 141611c0d8fdSPaul Kocialkowski } 141711c0d8fdSPaul Kocialkowski 141811c0d8fdSPaul Kocialkowski static int ov8865_mipi_configure(struct ov8865_sensor *sensor) 141911c0d8fdSPaul Kocialkowski { 142011c0d8fdSPaul Kocialkowski struct v4l2_fwnode_bus_mipi_csi2 *bus_mipi_csi2 = 142111c0d8fdSPaul Kocialkowski &sensor->endpoint.bus.mipi_csi2; 142211c0d8fdSPaul Kocialkowski unsigned int lanes_count = bus_mipi_csi2->num_data_lanes; 142311c0d8fdSPaul Kocialkowski int ret; 142411c0d8fdSPaul Kocialkowski 142511c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_MIPI_SC_CTRL0_REG, 142611c0d8fdSPaul Kocialkowski OV8865_MIPI_SC_CTRL0_LANES(lanes_count) | 142711c0d8fdSPaul Kocialkowski OV8865_MIPI_SC_CTRL0_MIPI_EN | 142811c0d8fdSPaul Kocialkowski OV8865_MIPI_SC_CTRL0_UNKNOWN); 142911c0d8fdSPaul Kocialkowski if (ret) 143011c0d8fdSPaul Kocialkowski return ret; 143111c0d8fdSPaul Kocialkowski 143211c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_MIPI_SC_CTRL2_REG, 143311c0d8fdSPaul Kocialkowski OV8865_MIPI_SC_CTRL2_PD_MIPI_RST_SYNC); 143411c0d8fdSPaul Kocialkowski if (ret) 143511c0d8fdSPaul Kocialkowski return ret; 143611c0d8fdSPaul Kocialkowski 143711c0d8fdSPaul Kocialkowski if (lanes_count >= 2) { 143811c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_MIPI_LANE_SEL01_REG, 143911c0d8fdSPaul Kocialkowski OV8865_MIPI_LANE_SEL01_LANE0(0) | 144011c0d8fdSPaul Kocialkowski OV8865_MIPI_LANE_SEL01_LANE1(1)); 144111c0d8fdSPaul Kocialkowski if (ret) 144211c0d8fdSPaul Kocialkowski return ret; 144311c0d8fdSPaul Kocialkowski } 144411c0d8fdSPaul Kocialkowski 144511c0d8fdSPaul Kocialkowski if (lanes_count >= 4) { 144611c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_MIPI_LANE_SEL23_REG, 144711c0d8fdSPaul Kocialkowski OV8865_MIPI_LANE_SEL23_LANE2(2) | 144811c0d8fdSPaul Kocialkowski OV8865_MIPI_LANE_SEL23_LANE3(3)); 144911c0d8fdSPaul Kocialkowski if (ret) 145011c0d8fdSPaul Kocialkowski return ret; 145111c0d8fdSPaul Kocialkowski } 145211c0d8fdSPaul Kocialkowski 145311c0d8fdSPaul Kocialkowski ret = ov8865_update_bits(sensor, OV8865_CLK_SEL1_REG, 145411c0d8fdSPaul Kocialkowski OV8865_CLK_SEL1_MIPI_EOF, 145511c0d8fdSPaul Kocialkowski OV8865_CLK_SEL1_MIPI_EOF); 145611c0d8fdSPaul Kocialkowski if (ret) 145711c0d8fdSPaul Kocialkowski return ret; 145811c0d8fdSPaul Kocialkowski 145911c0d8fdSPaul Kocialkowski /* 146011c0d8fdSPaul Kocialkowski * This value might need to change depending on PCLK rate, 146111c0d8fdSPaul Kocialkowski * but it's unclear how. This value seems to generally work 146211c0d8fdSPaul Kocialkowski * while the default value was found to cause transmission errors. 146311c0d8fdSPaul Kocialkowski */ 146411c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_MIPI_PCLK_PERIOD_REG, 0x16); 146511c0d8fdSPaul Kocialkowski } 146611c0d8fdSPaul Kocialkowski 146711c0d8fdSPaul Kocialkowski static int ov8865_black_level_configure(struct ov8865_sensor *sensor) 146811c0d8fdSPaul Kocialkowski { 146911c0d8fdSPaul Kocialkowski int ret; 147011c0d8fdSPaul Kocialkowski 147111c0d8fdSPaul Kocialkowski /* Trigger BLC on relevant events and enable filter. */ 147211c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_CTRL0_REG, 147311c0d8fdSPaul Kocialkowski OV8865_BLC_CTRL0_TRIG_RANGE_EN | 147411c0d8fdSPaul Kocialkowski OV8865_BLC_CTRL0_TRIG_FORMAT_EN | 147511c0d8fdSPaul Kocialkowski OV8865_BLC_CTRL0_TRIG_GAIN_EN | 147611c0d8fdSPaul Kocialkowski OV8865_BLC_CTRL0_TRIG_EXPOSURE_EN | 147711c0d8fdSPaul Kocialkowski OV8865_BLC_CTRL0_FILTER_EN); 147811c0d8fdSPaul Kocialkowski if (ret) 147911c0d8fdSPaul Kocialkowski return ret; 148011c0d8fdSPaul Kocialkowski 148111c0d8fdSPaul Kocialkowski /* Lower BLC offset trigger threshold. */ 148211c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_CTRLD_REG, 148311c0d8fdSPaul Kocialkowski OV8865_BLC_CTRLD_OFFSET_TRIGGER(16)); 148411c0d8fdSPaul Kocialkowski if (ret) 148511c0d8fdSPaul Kocialkowski return ret; 148611c0d8fdSPaul Kocialkowski 148711c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_CTRL1F_REG, 0); 148811c0d8fdSPaul Kocialkowski if (ret) 148911c0d8fdSPaul Kocialkowski return ret; 149011c0d8fdSPaul Kocialkowski 149111c0d8fdSPaul Kocialkowski /* Increase BLC offset maximum limit. */ 149211c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_BLC_OFFSET_LIMIT_REG, 149311c0d8fdSPaul Kocialkowski OV8865_BLC_OFFSET_LIMIT(63)); 149411c0d8fdSPaul Kocialkowski } 149511c0d8fdSPaul Kocialkowski 149611c0d8fdSPaul Kocialkowski static int ov8865_isp_configure(struct ov8865_sensor *sensor) 149711c0d8fdSPaul Kocialkowski { 149811c0d8fdSPaul Kocialkowski int ret; 149911c0d8fdSPaul Kocialkowski 150011c0d8fdSPaul Kocialkowski /* Disable lens correction. */ 150111c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_ISP_CTRL0_REG, 150211c0d8fdSPaul Kocialkowski OV8865_ISP_CTRL0_WHITE_BALANCE_EN | 150311c0d8fdSPaul Kocialkowski OV8865_ISP_CTRL0_DPC_BLACK_EN | 150411c0d8fdSPaul Kocialkowski OV8865_ISP_CTRL0_DPC_WHITE_EN); 150511c0d8fdSPaul Kocialkowski if (ret) 150611c0d8fdSPaul Kocialkowski return ret; 150711c0d8fdSPaul Kocialkowski 150811c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_ISP_CTRL1_REG, 150911c0d8fdSPaul Kocialkowski OV8865_ISP_CTRL1_BLC_EN); 151011c0d8fdSPaul Kocialkowski } 151111c0d8fdSPaul Kocialkowski 151211c0d8fdSPaul Kocialkowski static unsigned long ov8865_mode_pll1_rate(struct ov8865_sensor *sensor, 151311c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode) 151411c0d8fdSPaul Kocialkowski { 151511c0d8fdSPaul Kocialkowski const struct ov8865_pll1_config *config = mode->pll1_config; 151611c0d8fdSPaul Kocialkowski unsigned long extclk_rate; 151711c0d8fdSPaul Kocialkowski unsigned long pll1_rate; 151811c0d8fdSPaul Kocialkowski 151911c0d8fdSPaul Kocialkowski extclk_rate = clk_get_rate(sensor->extclk); 152011c0d8fdSPaul Kocialkowski pll1_rate = extclk_rate * config->pll_mul / config->pll_pre_div_half; 152111c0d8fdSPaul Kocialkowski 152211c0d8fdSPaul Kocialkowski switch (config->pll_pre_div) { 152311c0d8fdSPaul Kocialkowski case 0: 152411c0d8fdSPaul Kocialkowski break; 152511c0d8fdSPaul Kocialkowski case 1: 152611c0d8fdSPaul Kocialkowski pll1_rate *= 3; 152711c0d8fdSPaul Kocialkowski pll1_rate /= 2; 152811c0d8fdSPaul Kocialkowski break; 152911c0d8fdSPaul Kocialkowski case 3: 153011c0d8fdSPaul Kocialkowski pll1_rate *= 5; 153111c0d8fdSPaul Kocialkowski pll1_rate /= 2; 153211c0d8fdSPaul Kocialkowski break; 153311c0d8fdSPaul Kocialkowski case 4: 153411c0d8fdSPaul Kocialkowski pll1_rate /= 3; 153511c0d8fdSPaul Kocialkowski break; 153611c0d8fdSPaul Kocialkowski case 5: 153711c0d8fdSPaul Kocialkowski pll1_rate /= 4; 153811c0d8fdSPaul Kocialkowski break; 153911c0d8fdSPaul Kocialkowski case 7: 154011c0d8fdSPaul Kocialkowski pll1_rate /= 8; 154111c0d8fdSPaul Kocialkowski break; 154211c0d8fdSPaul Kocialkowski default: 154311c0d8fdSPaul Kocialkowski pll1_rate /= config->pll_pre_div; 154411c0d8fdSPaul Kocialkowski break; 154511c0d8fdSPaul Kocialkowski } 154611c0d8fdSPaul Kocialkowski 154711c0d8fdSPaul Kocialkowski return pll1_rate; 154811c0d8fdSPaul Kocialkowski } 154911c0d8fdSPaul Kocialkowski 155011c0d8fdSPaul Kocialkowski static int ov8865_mode_pll1_configure(struct ov8865_sensor *sensor, 155111c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode, 155211c0d8fdSPaul Kocialkowski u32 mbus_code) 155311c0d8fdSPaul Kocialkowski { 155411c0d8fdSPaul Kocialkowski const struct ov8865_pll1_config *config = mode->pll1_config; 155511c0d8fdSPaul Kocialkowski u8 value; 155611c0d8fdSPaul Kocialkowski int ret; 155711c0d8fdSPaul Kocialkowski 155811c0d8fdSPaul Kocialkowski switch (mbus_code) { 155911c0d8fdSPaul Kocialkowski case MEDIA_BUS_FMT_SBGGR10_1X10: 156011c0d8fdSPaul Kocialkowski value = OV8865_MIPI_BIT_SEL(10); 156111c0d8fdSPaul Kocialkowski break; 156211c0d8fdSPaul Kocialkowski default: 156311c0d8fdSPaul Kocialkowski return -EINVAL; 156411c0d8fdSPaul Kocialkowski } 156511c0d8fdSPaul Kocialkowski 156611c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_MIPI_BIT_SEL_REG, value); 156711c0d8fdSPaul Kocialkowski if (ret) 156811c0d8fdSPaul Kocialkowski return ret; 156911c0d8fdSPaul Kocialkowski 157011c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRLA_REG, 157111c0d8fdSPaul Kocialkowski OV8865_PLL_CTRLA_PRE_DIV_HALF(config->pll_pre_div_half)); 157211c0d8fdSPaul Kocialkowski if (ret) 157311c0d8fdSPaul Kocialkowski return ret; 157411c0d8fdSPaul Kocialkowski 157511c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRL0_REG, 157611c0d8fdSPaul Kocialkowski OV8865_PLL_CTRL0_PRE_DIV(config->pll_pre_div)); 157711c0d8fdSPaul Kocialkowski if (ret) 157811c0d8fdSPaul Kocialkowski return ret; 157911c0d8fdSPaul Kocialkowski 158011c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRL1_REG, 158111c0d8fdSPaul Kocialkowski OV8865_PLL_CTRL1_MUL_H(config->pll_mul)); 158211c0d8fdSPaul Kocialkowski if (ret) 158311c0d8fdSPaul Kocialkowski return ret; 158411c0d8fdSPaul Kocialkowski 158511c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRL2_REG, 158611c0d8fdSPaul Kocialkowski OV8865_PLL_CTRL2_MUL_L(config->pll_mul)); 158711c0d8fdSPaul Kocialkowski if (ret) 158811c0d8fdSPaul Kocialkowski return ret; 158911c0d8fdSPaul Kocialkowski 159011c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRL3_REG, 159111c0d8fdSPaul Kocialkowski OV8865_PLL_CTRL3_M_DIV(config->m_div)); 159211c0d8fdSPaul Kocialkowski if (ret) 159311c0d8fdSPaul Kocialkowski return ret; 159411c0d8fdSPaul Kocialkowski 159511c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRL4_REG, 159611c0d8fdSPaul Kocialkowski OV8865_PLL_CTRL4_MIPI_DIV(config->mipi_div)); 159711c0d8fdSPaul Kocialkowski if (ret) 159811c0d8fdSPaul Kocialkowski return ret; 159911c0d8fdSPaul Kocialkowski 160011c0d8fdSPaul Kocialkowski ret = ov8865_update_bits(sensor, OV8865_PCLK_SEL_REG, 160111c0d8fdSPaul Kocialkowski OV8865_PCLK_SEL_PCLK_DIV_MASK, 160211c0d8fdSPaul Kocialkowski OV8865_PCLK_SEL_PCLK_DIV(config->pclk_div)); 160311c0d8fdSPaul Kocialkowski if (ret) 160411c0d8fdSPaul Kocialkowski return ret; 160511c0d8fdSPaul Kocialkowski 160611c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRL5_REG, 160711c0d8fdSPaul Kocialkowski OV8865_PLL_CTRL5_SYS_PRE_DIV(config->sys_pre_div)); 160811c0d8fdSPaul Kocialkowski if (ret) 160911c0d8fdSPaul Kocialkowski return ret; 161011c0d8fdSPaul Kocialkowski 161111c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRL6_REG, 161211c0d8fdSPaul Kocialkowski OV8865_PLL_CTRL6_SYS_DIV(config->sys_div)); 161311c0d8fdSPaul Kocialkowski if (ret) 161411c0d8fdSPaul Kocialkowski return ret; 161511c0d8fdSPaul Kocialkowski 161611c0d8fdSPaul Kocialkowski return ov8865_update_bits(sensor, OV8865_PLL_CTRL1E_REG, 161711c0d8fdSPaul Kocialkowski OV8865_PLL_CTRL1E_PLL1_NO_LAT, 161811c0d8fdSPaul Kocialkowski OV8865_PLL_CTRL1E_PLL1_NO_LAT); 161911c0d8fdSPaul Kocialkowski } 162011c0d8fdSPaul Kocialkowski 162111c0d8fdSPaul Kocialkowski static int ov8865_mode_pll2_configure(struct ov8865_sensor *sensor, 162211c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode) 162311c0d8fdSPaul Kocialkowski { 162411c0d8fdSPaul Kocialkowski const struct ov8865_pll2_config *config = mode->pll2_config; 162511c0d8fdSPaul Kocialkowski int ret; 162611c0d8fdSPaul Kocialkowski 162711c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRL12_REG, 162811c0d8fdSPaul Kocialkowski OV8865_PLL_CTRL12_PRE_DIV_HALF(config->pll_pre_div_half) | 162911c0d8fdSPaul Kocialkowski OV8865_PLL_CTRL12_DAC_DIV(config->dac_div)); 163011c0d8fdSPaul Kocialkowski if (ret) 163111c0d8fdSPaul Kocialkowski return ret; 163211c0d8fdSPaul Kocialkowski 163311c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRLB_REG, 163411c0d8fdSPaul Kocialkowski OV8865_PLL_CTRLB_PRE_DIV(config->pll_pre_div)); 163511c0d8fdSPaul Kocialkowski if (ret) 163611c0d8fdSPaul Kocialkowski return ret; 163711c0d8fdSPaul Kocialkowski 163811c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRLC_REG, 163911c0d8fdSPaul Kocialkowski OV8865_PLL_CTRLC_MUL_H(config->pll_mul)); 164011c0d8fdSPaul Kocialkowski if (ret) 164111c0d8fdSPaul Kocialkowski return ret; 164211c0d8fdSPaul Kocialkowski 164311c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRLD_REG, 164411c0d8fdSPaul Kocialkowski OV8865_PLL_CTRLD_MUL_L(config->pll_mul)); 164511c0d8fdSPaul Kocialkowski if (ret) 164611c0d8fdSPaul Kocialkowski return ret; 164711c0d8fdSPaul Kocialkowski 164811c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRLF_REG, 164911c0d8fdSPaul Kocialkowski OV8865_PLL_CTRLF_SYS_PRE_DIV(config->sys_pre_div)); 165011c0d8fdSPaul Kocialkowski if (ret) 165111c0d8fdSPaul Kocialkowski return ret; 165211c0d8fdSPaul Kocialkowski 165311c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_PLL_CTRLE_REG, 165411c0d8fdSPaul Kocialkowski OV8865_PLL_CTRLE_SYS_DIV(config->sys_div)); 165511c0d8fdSPaul Kocialkowski } 165611c0d8fdSPaul Kocialkowski 165711c0d8fdSPaul Kocialkowski static int ov8865_mode_sclk_configure(struct ov8865_sensor *sensor, 165811c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode) 165911c0d8fdSPaul Kocialkowski { 166011c0d8fdSPaul Kocialkowski const struct ov8865_sclk_config *config = mode->sclk_config; 166111c0d8fdSPaul Kocialkowski int ret; 166211c0d8fdSPaul Kocialkowski 166311c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_CLK_SEL0_REG, 166411c0d8fdSPaul Kocialkowski OV8865_CLK_SEL0_PLL1_SYS_SEL(config->sys_sel)); 166511c0d8fdSPaul Kocialkowski if (ret) 166611c0d8fdSPaul Kocialkowski return ret; 166711c0d8fdSPaul Kocialkowski 166811c0d8fdSPaul Kocialkowski ret = ov8865_update_bits(sensor, OV8865_CLK_SEL1_REG, 166911c0d8fdSPaul Kocialkowski OV8865_CLK_SEL1_PLL_SCLK_SEL_MASK, 167011c0d8fdSPaul Kocialkowski OV8865_CLK_SEL1_PLL_SCLK_SEL(config->sclk_sel)); 167111c0d8fdSPaul Kocialkowski if (ret) 167211c0d8fdSPaul Kocialkowski return ret; 167311c0d8fdSPaul Kocialkowski 167411c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_SCLK_CTRL_REG, 167511c0d8fdSPaul Kocialkowski OV8865_SCLK_CTRL_UNKNOWN | 167611c0d8fdSPaul Kocialkowski OV8865_SCLK_CTRL_SCLK_DIV(config->sclk_div) | 167711c0d8fdSPaul Kocialkowski OV8865_SCLK_CTRL_SCLK_PRE_DIV(config->sclk_pre_div)); 167811c0d8fdSPaul Kocialkowski } 167911c0d8fdSPaul Kocialkowski 168011c0d8fdSPaul Kocialkowski static int ov8865_mode_binning_configure(struct ov8865_sensor *sensor, 168111c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode) 168211c0d8fdSPaul Kocialkowski { 168311c0d8fdSPaul Kocialkowski unsigned int variopixel_hsub_coef, variopixel_vsub_coef; 168411c0d8fdSPaul Kocialkowski u8 value; 168511c0d8fdSPaul Kocialkowski int ret; 168611c0d8fdSPaul Kocialkowski 168711c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_FORMAT1_REG, 0); 168811c0d8fdSPaul Kocialkowski if (ret) 168911c0d8fdSPaul Kocialkowski return ret; 169011c0d8fdSPaul Kocialkowski 169111c0d8fdSPaul Kocialkowski value = OV8865_FORMAT2_HSYNC_EN; 169211c0d8fdSPaul Kocialkowski 169311c0d8fdSPaul Kocialkowski if (mode->binning_x) 169411c0d8fdSPaul Kocialkowski value |= OV8865_FORMAT2_FST_HBIN_EN; 169511c0d8fdSPaul Kocialkowski 169611c0d8fdSPaul Kocialkowski if (mode->binning_y) 169711c0d8fdSPaul Kocialkowski value |= OV8865_FORMAT2_FST_VBIN_EN; 169811c0d8fdSPaul Kocialkowski 169911c0d8fdSPaul Kocialkowski if (mode->sync_hbin) 170011c0d8fdSPaul Kocialkowski value |= OV8865_FORMAT2_SYNC_HBIN_EN; 170111c0d8fdSPaul Kocialkowski 170211c0d8fdSPaul Kocialkowski if (mode->horz_var2) 170311c0d8fdSPaul Kocialkowski value |= OV8865_FORMAT2_ISP_HORZ_VAR2_EN; 170411c0d8fdSPaul Kocialkowski 170511c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_FORMAT2_REG, value); 170611c0d8fdSPaul Kocialkowski if (ret) 170711c0d8fdSPaul Kocialkowski return ret; 170811c0d8fdSPaul Kocialkowski 170911c0d8fdSPaul Kocialkowski ret = ov8865_update_bits(sensor, OV8865_ISP_CTRL2_REG, 171011c0d8fdSPaul Kocialkowski OV8865_ISP_CTRL2_VARIOPIXEL_EN, 171111c0d8fdSPaul Kocialkowski mode->variopixel ? 171211c0d8fdSPaul Kocialkowski OV8865_ISP_CTRL2_VARIOPIXEL_EN : 0); 171311c0d8fdSPaul Kocialkowski if (ret) 171411c0d8fdSPaul Kocialkowski return ret; 171511c0d8fdSPaul Kocialkowski 171611c0d8fdSPaul Kocialkowski if (mode->variopixel) { 171711c0d8fdSPaul Kocialkowski /* VarioPixel coefs needs to be > 1. */ 171811c0d8fdSPaul Kocialkowski variopixel_hsub_coef = mode->variopixel_hsub_coef; 171911c0d8fdSPaul Kocialkowski variopixel_vsub_coef = mode->variopixel_vsub_coef; 172011c0d8fdSPaul Kocialkowski } else { 172111c0d8fdSPaul Kocialkowski variopixel_hsub_coef = 1; 172211c0d8fdSPaul Kocialkowski variopixel_vsub_coef = 1; 172311c0d8fdSPaul Kocialkowski } 172411c0d8fdSPaul Kocialkowski 172511c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_VAP_CTRL1_REG, 172611c0d8fdSPaul Kocialkowski OV8865_VAP_CTRL1_HSUB_COEF(variopixel_hsub_coef) | 172711c0d8fdSPaul Kocialkowski OV8865_VAP_CTRL1_VSUB_COEF(variopixel_vsub_coef)); 172811c0d8fdSPaul Kocialkowski if (ret) 172911c0d8fdSPaul Kocialkowski return ret; 173011c0d8fdSPaul Kocialkowski 173111c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_INC_X_ODD_REG, 173211c0d8fdSPaul Kocialkowski OV8865_INC_X_ODD(mode->inc_x_odd)); 173311c0d8fdSPaul Kocialkowski if (ret) 173411c0d8fdSPaul Kocialkowski return ret; 173511c0d8fdSPaul Kocialkowski 173611c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_INC_X_EVEN_REG, 173711c0d8fdSPaul Kocialkowski OV8865_INC_X_EVEN(mode->inc_x_even)); 173811c0d8fdSPaul Kocialkowski if (ret) 173911c0d8fdSPaul Kocialkowski return ret; 174011c0d8fdSPaul Kocialkowski 174111c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_INC_Y_ODD_REG, 174211c0d8fdSPaul Kocialkowski OV8865_INC_Y_ODD(mode->inc_y_odd)); 174311c0d8fdSPaul Kocialkowski if (ret) 174411c0d8fdSPaul Kocialkowski return ret; 174511c0d8fdSPaul Kocialkowski 174611c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_INC_Y_EVEN_REG, 174711c0d8fdSPaul Kocialkowski OV8865_INC_Y_EVEN(mode->inc_y_even)); 174811c0d8fdSPaul Kocialkowski } 174911c0d8fdSPaul Kocialkowski 175011c0d8fdSPaul Kocialkowski static int ov8865_mode_black_level_configure(struct ov8865_sensor *sensor, 175111c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode) 175211c0d8fdSPaul Kocialkowski { 175311c0d8fdSPaul Kocialkowski int ret; 175411c0d8fdSPaul Kocialkowski 175511c0d8fdSPaul Kocialkowski /* Note that a zero value for blc_col_shift_mask is the default 256. */ 175611c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_CTRL1_REG, 175711c0d8fdSPaul Kocialkowski mode->blc_col_shift_mask | 175811c0d8fdSPaul Kocialkowski OV8865_BLC_CTRL1_OFFSET_LIMIT_EN); 175911c0d8fdSPaul Kocialkowski if (ret) 176011c0d8fdSPaul Kocialkowski return ret; 176111c0d8fdSPaul Kocialkowski 176211c0d8fdSPaul Kocialkowski /* BLC top zero line */ 176311c0d8fdSPaul Kocialkowski 176411c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_TOP_ZLINE_START_REG, 176511c0d8fdSPaul Kocialkowski OV8865_BLC_TOP_ZLINE_START(mode->blc_top_zero_line_start)); 176611c0d8fdSPaul Kocialkowski if (ret) 176711c0d8fdSPaul Kocialkowski return ret; 176811c0d8fdSPaul Kocialkowski 176911c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_TOP_ZLINE_NUM_REG, 177011c0d8fdSPaul Kocialkowski OV8865_BLC_TOP_ZLINE_NUM(mode->blc_top_zero_line_num)); 177111c0d8fdSPaul Kocialkowski if (ret) 177211c0d8fdSPaul Kocialkowski return ret; 177311c0d8fdSPaul Kocialkowski 177411c0d8fdSPaul Kocialkowski /* BLC top black line */ 177511c0d8fdSPaul Kocialkowski 177611c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_TOP_BLKLINE_START_REG, 177711c0d8fdSPaul Kocialkowski OV8865_BLC_TOP_BLKLINE_START(mode->blc_top_black_line_start)); 177811c0d8fdSPaul Kocialkowski if (ret) 177911c0d8fdSPaul Kocialkowski return ret; 178011c0d8fdSPaul Kocialkowski 178111c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_TOP_BLKLINE_NUM_REG, 178211c0d8fdSPaul Kocialkowski OV8865_BLC_TOP_BLKLINE_NUM(mode->blc_top_black_line_num)); 178311c0d8fdSPaul Kocialkowski if (ret) 178411c0d8fdSPaul Kocialkowski return ret; 178511c0d8fdSPaul Kocialkowski 178611c0d8fdSPaul Kocialkowski /* BLC bottom zero line */ 178711c0d8fdSPaul Kocialkowski 178811c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_BOT_ZLINE_START_REG, 178911c0d8fdSPaul Kocialkowski OV8865_BLC_BOT_ZLINE_START(mode->blc_bottom_zero_line_start)); 179011c0d8fdSPaul Kocialkowski if (ret) 179111c0d8fdSPaul Kocialkowski return ret; 179211c0d8fdSPaul Kocialkowski 179311c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_BOT_ZLINE_NUM_REG, 179411c0d8fdSPaul Kocialkowski OV8865_BLC_BOT_ZLINE_NUM(mode->blc_bottom_zero_line_num)); 179511c0d8fdSPaul Kocialkowski if (ret) 179611c0d8fdSPaul Kocialkowski return ret; 179711c0d8fdSPaul Kocialkowski 179811c0d8fdSPaul Kocialkowski /* BLC bottom black line */ 179911c0d8fdSPaul Kocialkowski 180011c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_BOT_BLKLINE_START_REG, 180111c0d8fdSPaul Kocialkowski OV8865_BLC_BOT_BLKLINE_START(mode->blc_bottom_black_line_start)); 180211c0d8fdSPaul Kocialkowski if (ret) 180311c0d8fdSPaul Kocialkowski return ret; 180411c0d8fdSPaul Kocialkowski 180511c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_BOT_BLKLINE_NUM_REG, 180611c0d8fdSPaul Kocialkowski OV8865_BLC_BOT_BLKLINE_NUM(mode->blc_bottom_black_line_num)); 180711c0d8fdSPaul Kocialkowski if (ret) 180811c0d8fdSPaul Kocialkowski return ret; 180911c0d8fdSPaul Kocialkowski 181011c0d8fdSPaul Kocialkowski /* BLC anchor */ 181111c0d8fdSPaul Kocialkowski 181211c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_ANCHOR_LEFT_START_H_REG, 181311c0d8fdSPaul Kocialkowski OV8865_BLC_ANCHOR_LEFT_START_H(mode->blc_anchor_left_start)); 181411c0d8fdSPaul Kocialkowski if (ret) 181511c0d8fdSPaul Kocialkowski return ret; 181611c0d8fdSPaul Kocialkowski 181711c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_ANCHOR_LEFT_START_L_REG, 181811c0d8fdSPaul Kocialkowski OV8865_BLC_ANCHOR_LEFT_START_L(mode->blc_anchor_left_start)); 181911c0d8fdSPaul Kocialkowski if (ret) 182011c0d8fdSPaul Kocialkowski return ret; 182111c0d8fdSPaul Kocialkowski 182211c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_ANCHOR_LEFT_END_H_REG, 182311c0d8fdSPaul Kocialkowski OV8865_BLC_ANCHOR_LEFT_END_H(mode->blc_anchor_left_end)); 182411c0d8fdSPaul Kocialkowski if (ret) 182511c0d8fdSPaul Kocialkowski return ret; 182611c0d8fdSPaul Kocialkowski 182711c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_ANCHOR_LEFT_END_L_REG, 182811c0d8fdSPaul Kocialkowski OV8865_BLC_ANCHOR_LEFT_END_L(mode->blc_anchor_left_end)); 182911c0d8fdSPaul Kocialkowski if (ret) 183011c0d8fdSPaul Kocialkowski return ret; 183111c0d8fdSPaul Kocialkowski 183211c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_ANCHOR_RIGHT_START_H_REG, 183311c0d8fdSPaul Kocialkowski OV8865_BLC_ANCHOR_RIGHT_START_H(mode->blc_anchor_right_start)); 183411c0d8fdSPaul Kocialkowski if (ret) 183511c0d8fdSPaul Kocialkowski return ret; 183611c0d8fdSPaul Kocialkowski 183711c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_ANCHOR_RIGHT_START_L_REG, 183811c0d8fdSPaul Kocialkowski OV8865_BLC_ANCHOR_RIGHT_START_L(mode->blc_anchor_right_start)); 183911c0d8fdSPaul Kocialkowski if (ret) 184011c0d8fdSPaul Kocialkowski return ret; 184111c0d8fdSPaul Kocialkowski 184211c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_ANCHOR_RIGHT_END_H_REG, 184311c0d8fdSPaul Kocialkowski OV8865_BLC_ANCHOR_RIGHT_END_H(mode->blc_anchor_right_end)); 184411c0d8fdSPaul Kocialkowski if (ret) 184511c0d8fdSPaul Kocialkowski return ret; 184611c0d8fdSPaul Kocialkowski 184711c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_BLC_ANCHOR_RIGHT_END_L_REG, 184811c0d8fdSPaul Kocialkowski OV8865_BLC_ANCHOR_RIGHT_END_L(mode->blc_anchor_right_end)); 184911c0d8fdSPaul Kocialkowski } 185011c0d8fdSPaul Kocialkowski 185111c0d8fdSPaul Kocialkowski static int ov8865_mode_configure(struct ov8865_sensor *sensor, 185211c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode, u32 mbus_code) 185311c0d8fdSPaul Kocialkowski { 185411c0d8fdSPaul Kocialkowski int ret; 185511c0d8fdSPaul Kocialkowski 185611c0d8fdSPaul Kocialkowski /* Output Size X */ 185711c0d8fdSPaul Kocialkowski 185811c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_OUTPUT_SIZE_X_H_REG, 185911c0d8fdSPaul Kocialkowski OV8865_OUTPUT_SIZE_X_H(mode->output_size_x)); 186011c0d8fdSPaul Kocialkowski if (ret) 186111c0d8fdSPaul Kocialkowski return ret; 186211c0d8fdSPaul Kocialkowski 186311c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_OUTPUT_SIZE_X_L_REG, 186411c0d8fdSPaul Kocialkowski OV8865_OUTPUT_SIZE_X_L(mode->output_size_x)); 186511c0d8fdSPaul Kocialkowski if (ret) 186611c0d8fdSPaul Kocialkowski return ret; 186711c0d8fdSPaul Kocialkowski 186811c0d8fdSPaul Kocialkowski /* Horizontal Total Size */ 186911c0d8fdSPaul Kocialkowski 187011c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_HTS_H_REG, OV8865_HTS_H(mode->hts)); 187111c0d8fdSPaul Kocialkowski if (ret) 187211c0d8fdSPaul Kocialkowski return ret; 187311c0d8fdSPaul Kocialkowski 187411c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_HTS_L_REG, OV8865_HTS_L(mode->hts)); 187511c0d8fdSPaul Kocialkowski if (ret) 187611c0d8fdSPaul Kocialkowski return ret; 187711c0d8fdSPaul Kocialkowski 187811c0d8fdSPaul Kocialkowski /* Output Size Y */ 187911c0d8fdSPaul Kocialkowski 188011c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_OUTPUT_SIZE_Y_H_REG, 188111c0d8fdSPaul Kocialkowski OV8865_OUTPUT_SIZE_Y_H(mode->output_size_y)); 188211c0d8fdSPaul Kocialkowski if (ret) 188311c0d8fdSPaul Kocialkowski return ret; 188411c0d8fdSPaul Kocialkowski 188511c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_OUTPUT_SIZE_Y_L_REG, 188611c0d8fdSPaul Kocialkowski OV8865_OUTPUT_SIZE_Y_L(mode->output_size_y)); 188711c0d8fdSPaul Kocialkowski if (ret) 188811c0d8fdSPaul Kocialkowski return ret; 188911c0d8fdSPaul Kocialkowski 189011c0d8fdSPaul Kocialkowski /* Vertical Total Size */ 189111c0d8fdSPaul Kocialkowski 189211c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_VTS_H_REG, OV8865_VTS_H(mode->vts)); 189311c0d8fdSPaul Kocialkowski if (ret) 189411c0d8fdSPaul Kocialkowski return ret; 189511c0d8fdSPaul Kocialkowski 189611c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_VTS_L_REG, OV8865_VTS_L(mode->vts)); 189711c0d8fdSPaul Kocialkowski if (ret) 189811c0d8fdSPaul Kocialkowski return ret; 189911c0d8fdSPaul Kocialkowski 190011c0d8fdSPaul Kocialkowski if (mode->size_auto) { 190111c0d8fdSPaul Kocialkowski /* Auto Size */ 190211c0d8fdSPaul Kocialkowski 190311c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_AUTO_SIZE_CTRL_REG, 190411c0d8fdSPaul Kocialkowski OV8865_AUTO_SIZE_CTRL_OFFSET_Y_REG | 190511c0d8fdSPaul Kocialkowski OV8865_AUTO_SIZE_CTRL_OFFSET_X_REG | 190611c0d8fdSPaul Kocialkowski OV8865_AUTO_SIZE_CTRL_CROP_END_Y_REG | 190711c0d8fdSPaul Kocialkowski OV8865_AUTO_SIZE_CTRL_CROP_END_X_REG | 190811c0d8fdSPaul Kocialkowski OV8865_AUTO_SIZE_CTRL_CROP_START_Y_REG | 190911c0d8fdSPaul Kocialkowski OV8865_AUTO_SIZE_CTRL_CROP_START_X_REG); 191011c0d8fdSPaul Kocialkowski if (ret) 191111c0d8fdSPaul Kocialkowski return ret; 191211c0d8fdSPaul Kocialkowski 191311c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_AUTO_SIZE_BOUNDARIES_REG, 191411c0d8fdSPaul Kocialkowski OV8865_AUTO_SIZE_BOUNDARIES_Y(mode->size_auto_boundary_y) | 191511c0d8fdSPaul Kocialkowski OV8865_AUTO_SIZE_BOUNDARIES_X(mode->size_auto_boundary_x)); 191611c0d8fdSPaul Kocialkowski if (ret) 191711c0d8fdSPaul Kocialkowski return ret; 191811c0d8fdSPaul Kocialkowski } else { 191911c0d8fdSPaul Kocialkowski /* Crop Start X */ 192011c0d8fdSPaul Kocialkowski 192111c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_CROP_START_X_H_REG, 192211c0d8fdSPaul Kocialkowski OV8865_CROP_START_X_H(mode->crop_start_x)); 192311c0d8fdSPaul Kocialkowski if (ret) 192411c0d8fdSPaul Kocialkowski return ret; 192511c0d8fdSPaul Kocialkowski 192611c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_CROP_START_X_L_REG, 192711c0d8fdSPaul Kocialkowski OV8865_CROP_START_X_L(mode->crop_start_x)); 192811c0d8fdSPaul Kocialkowski if (ret) 192911c0d8fdSPaul Kocialkowski return ret; 193011c0d8fdSPaul Kocialkowski 193111c0d8fdSPaul Kocialkowski /* Offset X */ 193211c0d8fdSPaul Kocialkowski 193311c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_OFFSET_X_H_REG, 193411c0d8fdSPaul Kocialkowski OV8865_OFFSET_X_H(mode->offset_x)); 193511c0d8fdSPaul Kocialkowski if (ret) 193611c0d8fdSPaul Kocialkowski return ret; 193711c0d8fdSPaul Kocialkowski 193811c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_OFFSET_X_L_REG, 193911c0d8fdSPaul Kocialkowski OV8865_OFFSET_X_L(mode->offset_x)); 194011c0d8fdSPaul Kocialkowski if (ret) 194111c0d8fdSPaul Kocialkowski return ret; 194211c0d8fdSPaul Kocialkowski 194311c0d8fdSPaul Kocialkowski /* Crop End X */ 194411c0d8fdSPaul Kocialkowski 194511c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_CROP_END_X_H_REG, 194611c0d8fdSPaul Kocialkowski OV8865_CROP_END_X_H(mode->crop_end_x)); 194711c0d8fdSPaul Kocialkowski if (ret) 194811c0d8fdSPaul Kocialkowski return ret; 194911c0d8fdSPaul Kocialkowski 195011c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_CROP_END_X_L_REG, 195111c0d8fdSPaul Kocialkowski OV8865_CROP_END_X_L(mode->crop_end_x)); 195211c0d8fdSPaul Kocialkowski if (ret) 195311c0d8fdSPaul Kocialkowski return ret; 195411c0d8fdSPaul Kocialkowski 195511c0d8fdSPaul Kocialkowski /* Crop Start Y */ 195611c0d8fdSPaul Kocialkowski 195711c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_CROP_START_Y_H_REG, 195811c0d8fdSPaul Kocialkowski OV8865_CROP_START_Y_H(mode->crop_start_y)); 195911c0d8fdSPaul Kocialkowski if (ret) 196011c0d8fdSPaul Kocialkowski return ret; 196111c0d8fdSPaul Kocialkowski 196211c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_CROP_START_Y_L_REG, 196311c0d8fdSPaul Kocialkowski OV8865_CROP_START_Y_L(mode->crop_start_y)); 196411c0d8fdSPaul Kocialkowski if (ret) 196511c0d8fdSPaul Kocialkowski return ret; 196611c0d8fdSPaul Kocialkowski 196711c0d8fdSPaul Kocialkowski /* Offset Y */ 196811c0d8fdSPaul Kocialkowski 196911c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_OFFSET_Y_H_REG, 197011c0d8fdSPaul Kocialkowski OV8865_OFFSET_Y_H(mode->offset_y)); 197111c0d8fdSPaul Kocialkowski if (ret) 197211c0d8fdSPaul Kocialkowski return ret; 197311c0d8fdSPaul Kocialkowski 197411c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_OFFSET_Y_L_REG, 197511c0d8fdSPaul Kocialkowski OV8865_OFFSET_Y_L(mode->offset_y)); 197611c0d8fdSPaul Kocialkowski if (ret) 197711c0d8fdSPaul Kocialkowski return ret; 197811c0d8fdSPaul Kocialkowski 197911c0d8fdSPaul Kocialkowski /* Crop End Y */ 198011c0d8fdSPaul Kocialkowski 198111c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_CROP_END_Y_H_REG, 198211c0d8fdSPaul Kocialkowski OV8865_CROP_END_Y_H(mode->crop_end_y)); 198311c0d8fdSPaul Kocialkowski if (ret) 198411c0d8fdSPaul Kocialkowski return ret; 198511c0d8fdSPaul Kocialkowski 198611c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_CROP_END_Y_L_REG, 198711c0d8fdSPaul Kocialkowski OV8865_CROP_END_Y_L(mode->crop_end_y)); 198811c0d8fdSPaul Kocialkowski if (ret) 198911c0d8fdSPaul Kocialkowski return ret; 199011c0d8fdSPaul Kocialkowski } 199111c0d8fdSPaul Kocialkowski 199211c0d8fdSPaul Kocialkowski /* VFIFO */ 199311c0d8fdSPaul Kocialkowski 199411c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_VFIFO_READ_START_H_REG, 199511c0d8fdSPaul Kocialkowski OV8865_VFIFO_READ_START_H(mode->vfifo_read_start)); 199611c0d8fdSPaul Kocialkowski if (ret) 199711c0d8fdSPaul Kocialkowski return ret; 199811c0d8fdSPaul Kocialkowski 199911c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_VFIFO_READ_START_L_REG, 200011c0d8fdSPaul Kocialkowski OV8865_VFIFO_READ_START_L(mode->vfifo_read_start)); 200111c0d8fdSPaul Kocialkowski if (ret) 200211c0d8fdSPaul Kocialkowski return ret; 200311c0d8fdSPaul Kocialkowski 200411c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_ABLC_NUM_REG, 200511c0d8fdSPaul Kocialkowski OV8865_ABLC_NUM(mode->ablc_num)); 200611c0d8fdSPaul Kocialkowski if (ret) 200711c0d8fdSPaul Kocialkowski return ret; 200811c0d8fdSPaul Kocialkowski 200911c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_ZLINE_NUM_REG, 201011c0d8fdSPaul Kocialkowski OV8865_ZLINE_NUM(mode->zline_num)); 201111c0d8fdSPaul Kocialkowski if (ret) 201211c0d8fdSPaul Kocialkowski return ret; 201311c0d8fdSPaul Kocialkowski 201411c0d8fdSPaul Kocialkowski /* Binning */ 201511c0d8fdSPaul Kocialkowski 201611c0d8fdSPaul Kocialkowski ret = ov8865_mode_binning_configure(sensor, mode); 201711c0d8fdSPaul Kocialkowski if (ret) 201811c0d8fdSPaul Kocialkowski return ret; 201911c0d8fdSPaul Kocialkowski 202011c0d8fdSPaul Kocialkowski /* Black Level */ 202111c0d8fdSPaul Kocialkowski 202211c0d8fdSPaul Kocialkowski ret = ov8865_mode_black_level_configure(sensor, mode); 202311c0d8fdSPaul Kocialkowski if (ret) 202411c0d8fdSPaul Kocialkowski return ret; 202511c0d8fdSPaul Kocialkowski 202611c0d8fdSPaul Kocialkowski /* PLLs */ 202711c0d8fdSPaul Kocialkowski 202811c0d8fdSPaul Kocialkowski ret = ov8865_mode_pll1_configure(sensor, mode, mbus_code); 202911c0d8fdSPaul Kocialkowski if (ret) 203011c0d8fdSPaul Kocialkowski return ret; 203111c0d8fdSPaul Kocialkowski 203211c0d8fdSPaul Kocialkowski ret = ov8865_mode_pll2_configure(sensor, mode); 203311c0d8fdSPaul Kocialkowski if (ret) 203411c0d8fdSPaul Kocialkowski return ret; 203511c0d8fdSPaul Kocialkowski 203611c0d8fdSPaul Kocialkowski ret = ov8865_mode_sclk_configure(sensor, mode); 203711c0d8fdSPaul Kocialkowski if (ret) 203811c0d8fdSPaul Kocialkowski return ret; 203911c0d8fdSPaul Kocialkowski 204011c0d8fdSPaul Kocialkowski /* Extra registers */ 204111c0d8fdSPaul Kocialkowski 204211c0d8fdSPaul Kocialkowski if (mode->register_values) { 204311c0d8fdSPaul Kocialkowski ret = ov8865_write_sequence(sensor, mode->register_values, 204411c0d8fdSPaul Kocialkowski mode->register_values_count); 204511c0d8fdSPaul Kocialkowski if (ret) 204611c0d8fdSPaul Kocialkowski return ret; 204711c0d8fdSPaul Kocialkowski } 204811c0d8fdSPaul Kocialkowski 204911c0d8fdSPaul Kocialkowski return 0; 205011c0d8fdSPaul Kocialkowski } 205111c0d8fdSPaul Kocialkowski 205211c0d8fdSPaul Kocialkowski static unsigned long ov8865_mode_mipi_clk_rate(struct ov8865_sensor *sensor, 205311c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode) 205411c0d8fdSPaul Kocialkowski { 205511c0d8fdSPaul Kocialkowski const struct ov8865_pll1_config *config = mode->pll1_config; 205611c0d8fdSPaul Kocialkowski unsigned long pll1_rate; 205711c0d8fdSPaul Kocialkowski 205811c0d8fdSPaul Kocialkowski pll1_rate = ov8865_mode_pll1_rate(sensor, mode); 205911c0d8fdSPaul Kocialkowski 206011c0d8fdSPaul Kocialkowski return pll1_rate / config->m_div / 2; 206111c0d8fdSPaul Kocialkowski } 206211c0d8fdSPaul Kocialkowski 206311c0d8fdSPaul Kocialkowski /* Exposure */ 206411c0d8fdSPaul Kocialkowski 206511c0d8fdSPaul Kocialkowski static int ov8865_exposure_configure(struct ov8865_sensor *sensor, u32 exposure) 206611c0d8fdSPaul Kocialkowski { 206711c0d8fdSPaul Kocialkowski int ret; 206811c0d8fdSPaul Kocialkowski 206911c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_EXPOSURE_CTRL_HH_REG, 207011c0d8fdSPaul Kocialkowski OV8865_EXPOSURE_CTRL_HH(exposure)); 207111c0d8fdSPaul Kocialkowski if (ret) 207211c0d8fdSPaul Kocialkowski return ret; 207311c0d8fdSPaul Kocialkowski 207411c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_EXPOSURE_CTRL_H_REG, 207511c0d8fdSPaul Kocialkowski OV8865_EXPOSURE_CTRL_H(exposure)); 207611c0d8fdSPaul Kocialkowski if (ret) 207711c0d8fdSPaul Kocialkowski return ret; 207811c0d8fdSPaul Kocialkowski 207911c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_EXPOSURE_CTRL_L_REG, 208011c0d8fdSPaul Kocialkowski OV8865_EXPOSURE_CTRL_L(exposure)); 208111c0d8fdSPaul Kocialkowski } 208211c0d8fdSPaul Kocialkowski 208311c0d8fdSPaul Kocialkowski /* Gain */ 208411c0d8fdSPaul Kocialkowski 208511c0d8fdSPaul Kocialkowski static int ov8865_gain_configure(struct ov8865_sensor *sensor, u32 gain) 208611c0d8fdSPaul Kocialkowski { 208711c0d8fdSPaul Kocialkowski int ret; 208811c0d8fdSPaul Kocialkowski 208911c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_GAIN_CTRL_H_REG, 209011c0d8fdSPaul Kocialkowski OV8865_GAIN_CTRL_H(gain)); 209111c0d8fdSPaul Kocialkowski if (ret) 209211c0d8fdSPaul Kocialkowski return ret; 209311c0d8fdSPaul Kocialkowski 209411c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_GAIN_CTRL_L_REG, 209511c0d8fdSPaul Kocialkowski OV8865_GAIN_CTRL_L(gain)); 209611c0d8fdSPaul Kocialkowski } 209711c0d8fdSPaul Kocialkowski 209811c0d8fdSPaul Kocialkowski /* White Balance */ 209911c0d8fdSPaul Kocialkowski 210011c0d8fdSPaul Kocialkowski static int ov8865_red_balance_configure(struct ov8865_sensor *sensor, 210111c0d8fdSPaul Kocialkowski u32 red_balance) 210211c0d8fdSPaul Kocialkowski { 210311c0d8fdSPaul Kocialkowski int ret; 210411c0d8fdSPaul Kocialkowski 210511c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_ISP_GAIN_RED_H_REG, 210611c0d8fdSPaul Kocialkowski OV8865_ISP_GAIN_RED_H(red_balance)); 210711c0d8fdSPaul Kocialkowski if (ret) 210811c0d8fdSPaul Kocialkowski return ret; 210911c0d8fdSPaul Kocialkowski 211011c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_ISP_GAIN_RED_L_REG, 211111c0d8fdSPaul Kocialkowski OV8865_ISP_GAIN_RED_L(red_balance)); 211211c0d8fdSPaul Kocialkowski } 211311c0d8fdSPaul Kocialkowski 211411c0d8fdSPaul Kocialkowski static int ov8865_blue_balance_configure(struct ov8865_sensor *sensor, 211511c0d8fdSPaul Kocialkowski u32 blue_balance) 211611c0d8fdSPaul Kocialkowski { 211711c0d8fdSPaul Kocialkowski int ret; 211811c0d8fdSPaul Kocialkowski 211911c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_ISP_GAIN_BLUE_H_REG, 212011c0d8fdSPaul Kocialkowski OV8865_ISP_GAIN_BLUE_H(blue_balance)); 212111c0d8fdSPaul Kocialkowski if (ret) 212211c0d8fdSPaul Kocialkowski return ret; 212311c0d8fdSPaul Kocialkowski 212411c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_ISP_GAIN_BLUE_L_REG, 212511c0d8fdSPaul Kocialkowski OV8865_ISP_GAIN_BLUE_L(blue_balance)); 212611c0d8fdSPaul Kocialkowski } 212711c0d8fdSPaul Kocialkowski 212811c0d8fdSPaul Kocialkowski /* Flip */ 212911c0d8fdSPaul Kocialkowski 213011c0d8fdSPaul Kocialkowski static int ov8865_flip_vert_configure(struct ov8865_sensor *sensor, bool enable) 213111c0d8fdSPaul Kocialkowski { 213211c0d8fdSPaul Kocialkowski u8 bits = OV8865_FORMAT1_FLIP_VERT_ISP_EN | 213311c0d8fdSPaul Kocialkowski OV8865_FORMAT1_FLIP_VERT_SENSOR_EN; 213411c0d8fdSPaul Kocialkowski 213511c0d8fdSPaul Kocialkowski return ov8865_update_bits(sensor, OV8865_FORMAT1_REG, bits, 213611c0d8fdSPaul Kocialkowski enable ? bits : 0); 213711c0d8fdSPaul Kocialkowski } 213811c0d8fdSPaul Kocialkowski 213911c0d8fdSPaul Kocialkowski static int ov8865_flip_horz_configure(struct ov8865_sensor *sensor, bool enable) 214011c0d8fdSPaul Kocialkowski { 214111c0d8fdSPaul Kocialkowski u8 bits = OV8865_FORMAT2_FLIP_HORZ_ISP_EN | 214211c0d8fdSPaul Kocialkowski OV8865_FORMAT2_FLIP_HORZ_SENSOR_EN; 214311c0d8fdSPaul Kocialkowski 214411c0d8fdSPaul Kocialkowski return ov8865_update_bits(sensor, OV8865_FORMAT2_REG, bits, 214511c0d8fdSPaul Kocialkowski enable ? bits : 0); 214611c0d8fdSPaul Kocialkowski } 214711c0d8fdSPaul Kocialkowski 214811c0d8fdSPaul Kocialkowski /* Test Pattern */ 214911c0d8fdSPaul Kocialkowski 215011c0d8fdSPaul Kocialkowski static int ov8865_test_pattern_configure(struct ov8865_sensor *sensor, 215111c0d8fdSPaul Kocialkowski unsigned int index) 215211c0d8fdSPaul Kocialkowski { 215311c0d8fdSPaul Kocialkowski if (index >= ARRAY_SIZE(ov8865_test_pattern_bits)) 215411c0d8fdSPaul Kocialkowski return -EINVAL; 215511c0d8fdSPaul Kocialkowski 215611c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_PRE_CTRL0_REG, 215711c0d8fdSPaul Kocialkowski ov8865_test_pattern_bits[index]); 215811c0d8fdSPaul Kocialkowski } 215911c0d8fdSPaul Kocialkowski 216011c0d8fdSPaul Kocialkowski /* State */ 216111c0d8fdSPaul Kocialkowski 216211c0d8fdSPaul Kocialkowski static int ov8865_state_mipi_configure(struct ov8865_sensor *sensor, 216311c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode, 216411c0d8fdSPaul Kocialkowski u32 mbus_code) 216511c0d8fdSPaul Kocialkowski { 216611c0d8fdSPaul Kocialkowski struct ov8865_ctrls *ctrls = &sensor->ctrls; 216711c0d8fdSPaul Kocialkowski struct v4l2_fwnode_bus_mipi_csi2 *bus_mipi_csi2 = 216811c0d8fdSPaul Kocialkowski &sensor->endpoint.bus.mipi_csi2; 216911c0d8fdSPaul Kocialkowski unsigned long mipi_clk_rate; 217011c0d8fdSPaul Kocialkowski unsigned int bits_per_sample; 217111c0d8fdSPaul Kocialkowski unsigned int lanes_count; 217211c0d8fdSPaul Kocialkowski unsigned int i, j; 217311c0d8fdSPaul Kocialkowski s64 mipi_pixel_rate; 217411c0d8fdSPaul Kocialkowski 217511c0d8fdSPaul Kocialkowski mipi_clk_rate = ov8865_mode_mipi_clk_rate(sensor, mode); 217611c0d8fdSPaul Kocialkowski if (!mipi_clk_rate) 217711c0d8fdSPaul Kocialkowski return -EINVAL; 217811c0d8fdSPaul Kocialkowski 217911c0d8fdSPaul Kocialkowski for (i = 0; i < ARRAY_SIZE(ov8865_link_freq_menu); i++) { 218011c0d8fdSPaul Kocialkowski s64 freq = ov8865_link_freq_menu[i]; 218111c0d8fdSPaul Kocialkowski 218211c0d8fdSPaul Kocialkowski if (freq == mipi_clk_rate) 218311c0d8fdSPaul Kocialkowski break; 218411c0d8fdSPaul Kocialkowski } 218511c0d8fdSPaul Kocialkowski 218611c0d8fdSPaul Kocialkowski for (j = 0; j < sensor->endpoint.nr_of_link_frequencies; j++) { 218711c0d8fdSPaul Kocialkowski u64 freq = sensor->endpoint.link_frequencies[j]; 218811c0d8fdSPaul Kocialkowski 218911c0d8fdSPaul Kocialkowski if (freq == mipi_clk_rate) 219011c0d8fdSPaul Kocialkowski break; 219111c0d8fdSPaul Kocialkowski } 219211c0d8fdSPaul Kocialkowski 219311c0d8fdSPaul Kocialkowski if (i == ARRAY_SIZE(ov8865_link_freq_menu)) { 219411c0d8fdSPaul Kocialkowski dev_err(sensor->dev, 219511c0d8fdSPaul Kocialkowski "failed to find %lu clk rate in link freq\n", 219611c0d8fdSPaul Kocialkowski mipi_clk_rate); 219711c0d8fdSPaul Kocialkowski } else if (j == sensor->endpoint.nr_of_link_frequencies) { 219811c0d8fdSPaul Kocialkowski dev_err(sensor->dev, 219911c0d8fdSPaul Kocialkowski "failed to find %lu clk rate in endpoint link-frequencies\n", 220011c0d8fdSPaul Kocialkowski mipi_clk_rate); 220111c0d8fdSPaul Kocialkowski } else { 220211c0d8fdSPaul Kocialkowski __v4l2_ctrl_s_ctrl(ctrls->link_freq, i); 220311c0d8fdSPaul Kocialkowski } 220411c0d8fdSPaul Kocialkowski 220511c0d8fdSPaul Kocialkowski switch (mbus_code) { 220611c0d8fdSPaul Kocialkowski case MEDIA_BUS_FMT_SBGGR10_1X10: 220711c0d8fdSPaul Kocialkowski bits_per_sample = 10; 220811c0d8fdSPaul Kocialkowski break; 220911c0d8fdSPaul Kocialkowski default: 221011c0d8fdSPaul Kocialkowski return -EINVAL; 221111c0d8fdSPaul Kocialkowski } 221211c0d8fdSPaul Kocialkowski 221311c0d8fdSPaul Kocialkowski lanes_count = bus_mipi_csi2->num_data_lanes; 221411c0d8fdSPaul Kocialkowski mipi_pixel_rate = mipi_clk_rate * 2 * lanes_count / bits_per_sample; 221511c0d8fdSPaul Kocialkowski 221611c0d8fdSPaul Kocialkowski __v4l2_ctrl_s_ctrl_int64(ctrls->pixel_rate, mipi_pixel_rate); 221711c0d8fdSPaul Kocialkowski 221811c0d8fdSPaul Kocialkowski return 0; 221911c0d8fdSPaul Kocialkowski } 222011c0d8fdSPaul Kocialkowski 222111c0d8fdSPaul Kocialkowski static int ov8865_state_configure(struct ov8865_sensor *sensor, 222211c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode, 222311c0d8fdSPaul Kocialkowski u32 mbus_code) 222411c0d8fdSPaul Kocialkowski { 222511c0d8fdSPaul Kocialkowski int ret; 222611c0d8fdSPaul Kocialkowski 222711c0d8fdSPaul Kocialkowski if (sensor->state.streaming) 222811c0d8fdSPaul Kocialkowski return -EBUSY; 222911c0d8fdSPaul Kocialkowski 223011c0d8fdSPaul Kocialkowski /* State will be configured at first power on otherwise. */ 223111c0d8fdSPaul Kocialkowski if (pm_runtime_enabled(sensor->dev) && 223211c0d8fdSPaul Kocialkowski !pm_runtime_suspended(sensor->dev)) { 223311c0d8fdSPaul Kocialkowski ret = ov8865_mode_configure(sensor, mode, mbus_code); 223411c0d8fdSPaul Kocialkowski if (ret) 223511c0d8fdSPaul Kocialkowski return ret; 223611c0d8fdSPaul Kocialkowski } 223711c0d8fdSPaul Kocialkowski 223811c0d8fdSPaul Kocialkowski ret = ov8865_state_mipi_configure(sensor, mode, mbus_code); 223911c0d8fdSPaul Kocialkowski if (ret) 224011c0d8fdSPaul Kocialkowski return ret; 224111c0d8fdSPaul Kocialkowski 224211c0d8fdSPaul Kocialkowski sensor->state.mode = mode; 224311c0d8fdSPaul Kocialkowski sensor->state.mbus_code = mbus_code; 224411c0d8fdSPaul Kocialkowski 224511c0d8fdSPaul Kocialkowski return 0; 224611c0d8fdSPaul Kocialkowski } 224711c0d8fdSPaul Kocialkowski 224811c0d8fdSPaul Kocialkowski static int ov8865_state_init(struct ov8865_sensor *sensor) 224911c0d8fdSPaul Kocialkowski { 225011c0d8fdSPaul Kocialkowski return ov8865_state_configure(sensor, &ov8865_modes[0], 225111c0d8fdSPaul Kocialkowski ov8865_mbus_codes[0]); 225211c0d8fdSPaul Kocialkowski } 225311c0d8fdSPaul Kocialkowski 225411c0d8fdSPaul Kocialkowski /* Sensor Base */ 225511c0d8fdSPaul Kocialkowski 225611c0d8fdSPaul Kocialkowski static int ov8865_sensor_init(struct ov8865_sensor *sensor) 225711c0d8fdSPaul Kocialkowski { 225811c0d8fdSPaul Kocialkowski int ret; 225911c0d8fdSPaul Kocialkowski 226011c0d8fdSPaul Kocialkowski ret = ov8865_sw_reset(sensor); 226111c0d8fdSPaul Kocialkowski if (ret) { 226211c0d8fdSPaul Kocialkowski dev_err(sensor->dev, "failed to perform sw reset\n"); 226311c0d8fdSPaul Kocialkowski return ret; 226411c0d8fdSPaul Kocialkowski } 226511c0d8fdSPaul Kocialkowski 226611c0d8fdSPaul Kocialkowski ret = ov8865_sw_standby(sensor, 1); 226711c0d8fdSPaul Kocialkowski if (ret) { 226811c0d8fdSPaul Kocialkowski dev_err(sensor->dev, "failed to set sensor standby\n"); 226911c0d8fdSPaul Kocialkowski return ret; 227011c0d8fdSPaul Kocialkowski } 227111c0d8fdSPaul Kocialkowski 227211c0d8fdSPaul Kocialkowski ret = ov8865_chip_id_check(sensor); 227311c0d8fdSPaul Kocialkowski if (ret) { 227411c0d8fdSPaul Kocialkowski dev_err(sensor->dev, "failed to check sensor chip id\n"); 227511c0d8fdSPaul Kocialkowski return ret; 227611c0d8fdSPaul Kocialkowski } 227711c0d8fdSPaul Kocialkowski 227811c0d8fdSPaul Kocialkowski ret = ov8865_write_sequence(sensor, ov8865_init_sequence, 227911c0d8fdSPaul Kocialkowski ARRAY_SIZE(ov8865_init_sequence)); 228011c0d8fdSPaul Kocialkowski if (ret) { 228111c0d8fdSPaul Kocialkowski dev_err(sensor->dev, "failed to write init sequence\n"); 228211c0d8fdSPaul Kocialkowski return ret; 228311c0d8fdSPaul Kocialkowski } 228411c0d8fdSPaul Kocialkowski 228511c0d8fdSPaul Kocialkowski ret = ov8865_charge_pump_configure(sensor); 228611c0d8fdSPaul Kocialkowski if (ret) { 228711c0d8fdSPaul Kocialkowski dev_err(sensor->dev, "failed to configure pad\n"); 228811c0d8fdSPaul Kocialkowski return ret; 228911c0d8fdSPaul Kocialkowski } 229011c0d8fdSPaul Kocialkowski 229111c0d8fdSPaul Kocialkowski ret = ov8865_mipi_configure(sensor); 229211c0d8fdSPaul Kocialkowski if (ret) { 229311c0d8fdSPaul Kocialkowski dev_err(sensor->dev, "failed to configure MIPI\n"); 229411c0d8fdSPaul Kocialkowski return ret; 229511c0d8fdSPaul Kocialkowski } 229611c0d8fdSPaul Kocialkowski 229711c0d8fdSPaul Kocialkowski ret = ov8865_isp_configure(sensor); 229811c0d8fdSPaul Kocialkowski if (ret) { 229911c0d8fdSPaul Kocialkowski dev_err(sensor->dev, "failed to configure ISP\n"); 230011c0d8fdSPaul Kocialkowski return ret; 230111c0d8fdSPaul Kocialkowski } 230211c0d8fdSPaul Kocialkowski 230311c0d8fdSPaul Kocialkowski ret = ov8865_black_level_configure(sensor); 230411c0d8fdSPaul Kocialkowski if (ret) { 230511c0d8fdSPaul Kocialkowski dev_err(sensor->dev, "failed to configure black level\n"); 230611c0d8fdSPaul Kocialkowski return ret; 230711c0d8fdSPaul Kocialkowski } 230811c0d8fdSPaul Kocialkowski 230911c0d8fdSPaul Kocialkowski /* Configure current mode. */ 231011c0d8fdSPaul Kocialkowski ret = ov8865_state_configure(sensor, sensor->state.mode, 231111c0d8fdSPaul Kocialkowski sensor->state.mbus_code); 231211c0d8fdSPaul Kocialkowski if (ret) { 231311c0d8fdSPaul Kocialkowski dev_err(sensor->dev, "failed to configure state\n"); 231411c0d8fdSPaul Kocialkowski return ret; 231511c0d8fdSPaul Kocialkowski } 231611c0d8fdSPaul Kocialkowski 231711c0d8fdSPaul Kocialkowski return 0; 231811c0d8fdSPaul Kocialkowski } 231911c0d8fdSPaul Kocialkowski 232011c0d8fdSPaul Kocialkowski static int ov8865_sensor_power(struct ov8865_sensor *sensor, bool on) 232111c0d8fdSPaul Kocialkowski { 232211c0d8fdSPaul Kocialkowski /* Keep initialized to zero for disable label. */ 232311c0d8fdSPaul Kocialkowski int ret = 0; 232411c0d8fdSPaul Kocialkowski 232511c0d8fdSPaul Kocialkowski if (on) { 232611c0d8fdSPaul Kocialkowski gpiod_set_value_cansleep(sensor->reset, 1); 232711c0d8fdSPaul Kocialkowski gpiod_set_value_cansleep(sensor->powerdown, 1); 232811c0d8fdSPaul Kocialkowski 232911c0d8fdSPaul Kocialkowski ret = regulator_enable(sensor->dovdd); 233011c0d8fdSPaul Kocialkowski if (ret) { 233111c0d8fdSPaul Kocialkowski dev_err(sensor->dev, 233211c0d8fdSPaul Kocialkowski "failed to enable DOVDD regulator\n"); 233311c0d8fdSPaul Kocialkowski goto disable; 233411c0d8fdSPaul Kocialkowski } 233511c0d8fdSPaul Kocialkowski 233611c0d8fdSPaul Kocialkowski ret = regulator_enable(sensor->avdd); 233711c0d8fdSPaul Kocialkowski if (ret) { 233811c0d8fdSPaul Kocialkowski dev_err(sensor->dev, 233911c0d8fdSPaul Kocialkowski "failed to enable AVDD regulator\n"); 234011c0d8fdSPaul Kocialkowski goto disable; 234111c0d8fdSPaul Kocialkowski } 234211c0d8fdSPaul Kocialkowski 234311c0d8fdSPaul Kocialkowski ret = regulator_enable(sensor->dvdd); 234411c0d8fdSPaul Kocialkowski if (ret) { 234511c0d8fdSPaul Kocialkowski dev_err(sensor->dev, 234611c0d8fdSPaul Kocialkowski "failed to enable DVDD regulator\n"); 234711c0d8fdSPaul Kocialkowski goto disable; 234811c0d8fdSPaul Kocialkowski } 234911c0d8fdSPaul Kocialkowski 235011c0d8fdSPaul Kocialkowski ret = clk_prepare_enable(sensor->extclk); 235111c0d8fdSPaul Kocialkowski if (ret) { 235211c0d8fdSPaul Kocialkowski dev_err(sensor->dev, "failed to enable EXTCLK clock\n"); 235311c0d8fdSPaul Kocialkowski goto disable; 235411c0d8fdSPaul Kocialkowski } 235511c0d8fdSPaul Kocialkowski 235611c0d8fdSPaul Kocialkowski gpiod_set_value_cansleep(sensor->reset, 0); 235711c0d8fdSPaul Kocialkowski gpiod_set_value_cansleep(sensor->powerdown, 0); 235811c0d8fdSPaul Kocialkowski 235911c0d8fdSPaul Kocialkowski /* Time to enter streaming mode according to power timings. */ 236011c0d8fdSPaul Kocialkowski usleep_range(10000, 12000); 236111c0d8fdSPaul Kocialkowski } else { 236211c0d8fdSPaul Kocialkowski disable: 236311c0d8fdSPaul Kocialkowski gpiod_set_value_cansleep(sensor->powerdown, 1); 236411c0d8fdSPaul Kocialkowski gpiod_set_value_cansleep(sensor->reset, 1); 236511c0d8fdSPaul Kocialkowski 236611c0d8fdSPaul Kocialkowski clk_disable_unprepare(sensor->extclk); 236711c0d8fdSPaul Kocialkowski 236811c0d8fdSPaul Kocialkowski regulator_disable(sensor->dvdd); 236911c0d8fdSPaul Kocialkowski regulator_disable(sensor->avdd); 237011c0d8fdSPaul Kocialkowski regulator_disable(sensor->dovdd); 237111c0d8fdSPaul Kocialkowski } 237211c0d8fdSPaul Kocialkowski 237311c0d8fdSPaul Kocialkowski return ret; 237411c0d8fdSPaul Kocialkowski } 237511c0d8fdSPaul Kocialkowski 237611c0d8fdSPaul Kocialkowski /* Controls */ 237711c0d8fdSPaul Kocialkowski 237811c0d8fdSPaul Kocialkowski static int ov8865_s_ctrl(struct v4l2_ctrl *ctrl) 237911c0d8fdSPaul Kocialkowski { 238011c0d8fdSPaul Kocialkowski struct v4l2_subdev *subdev = ov8865_ctrl_subdev(ctrl); 238111c0d8fdSPaul Kocialkowski struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev); 238211c0d8fdSPaul Kocialkowski unsigned int index; 238311c0d8fdSPaul Kocialkowski int ret; 238411c0d8fdSPaul Kocialkowski 238511c0d8fdSPaul Kocialkowski /* Wait for the sensor to be on before setting controls. */ 238611c0d8fdSPaul Kocialkowski if (pm_runtime_suspended(sensor->dev)) 238711c0d8fdSPaul Kocialkowski return 0; 238811c0d8fdSPaul Kocialkowski 238911c0d8fdSPaul Kocialkowski switch (ctrl->id) { 239011c0d8fdSPaul Kocialkowski case V4L2_CID_EXPOSURE: 239111c0d8fdSPaul Kocialkowski ret = ov8865_exposure_configure(sensor, ctrl->val); 239211c0d8fdSPaul Kocialkowski if (ret) 239311c0d8fdSPaul Kocialkowski return ret; 239411c0d8fdSPaul Kocialkowski break; 239511c0d8fdSPaul Kocialkowski case V4L2_CID_GAIN: 239611c0d8fdSPaul Kocialkowski ret = ov8865_gain_configure(sensor, ctrl->val); 239711c0d8fdSPaul Kocialkowski if (ret) 239811c0d8fdSPaul Kocialkowski return ret; 239911c0d8fdSPaul Kocialkowski break; 240011c0d8fdSPaul Kocialkowski case V4L2_CID_RED_BALANCE: 240111c0d8fdSPaul Kocialkowski return ov8865_red_balance_configure(sensor, ctrl->val); 240211c0d8fdSPaul Kocialkowski case V4L2_CID_BLUE_BALANCE: 240311c0d8fdSPaul Kocialkowski return ov8865_blue_balance_configure(sensor, ctrl->val); 240411c0d8fdSPaul Kocialkowski case V4L2_CID_HFLIP: 240511c0d8fdSPaul Kocialkowski return ov8865_flip_horz_configure(sensor, !!ctrl->val); 240611c0d8fdSPaul Kocialkowski case V4L2_CID_VFLIP: 240711c0d8fdSPaul Kocialkowski return ov8865_flip_vert_configure(sensor, !!ctrl->val); 240811c0d8fdSPaul Kocialkowski case V4L2_CID_TEST_PATTERN: 240911c0d8fdSPaul Kocialkowski index = (unsigned int)ctrl->val; 241011c0d8fdSPaul Kocialkowski return ov8865_test_pattern_configure(sensor, index); 241111c0d8fdSPaul Kocialkowski default: 241211c0d8fdSPaul Kocialkowski return -EINVAL; 241311c0d8fdSPaul Kocialkowski } 241411c0d8fdSPaul Kocialkowski 241511c0d8fdSPaul Kocialkowski return 0; 241611c0d8fdSPaul Kocialkowski } 241711c0d8fdSPaul Kocialkowski 241811c0d8fdSPaul Kocialkowski static const struct v4l2_ctrl_ops ov8865_ctrl_ops = { 241911c0d8fdSPaul Kocialkowski .s_ctrl = ov8865_s_ctrl, 242011c0d8fdSPaul Kocialkowski }; 242111c0d8fdSPaul Kocialkowski 242211c0d8fdSPaul Kocialkowski static int ov8865_ctrls_init(struct ov8865_sensor *sensor) 242311c0d8fdSPaul Kocialkowski { 242411c0d8fdSPaul Kocialkowski struct ov8865_ctrls *ctrls = &sensor->ctrls; 242511c0d8fdSPaul Kocialkowski struct v4l2_ctrl_handler *handler = &ctrls->handler; 242611c0d8fdSPaul Kocialkowski const struct v4l2_ctrl_ops *ops = &ov8865_ctrl_ops; 242711c0d8fdSPaul Kocialkowski int ret; 242811c0d8fdSPaul Kocialkowski 242911c0d8fdSPaul Kocialkowski v4l2_ctrl_handler_init(handler, 32); 243011c0d8fdSPaul Kocialkowski 243111c0d8fdSPaul Kocialkowski /* Use our mutex for ctrl locking. */ 243211c0d8fdSPaul Kocialkowski handler->lock = &sensor->mutex; 243311c0d8fdSPaul Kocialkowski 243411c0d8fdSPaul Kocialkowski /* Exposure */ 243511c0d8fdSPaul Kocialkowski 243611c0d8fdSPaul Kocialkowski v4l2_ctrl_new_std(handler, ops, V4L2_CID_EXPOSURE, 16, 1048575, 16, 243711c0d8fdSPaul Kocialkowski 512); 243811c0d8fdSPaul Kocialkowski 243911c0d8fdSPaul Kocialkowski /* Gain */ 244011c0d8fdSPaul Kocialkowski 244111c0d8fdSPaul Kocialkowski v4l2_ctrl_new_std(handler, ops, V4L2_CID_GAIN, 128, 8191, 128, 128); 244211c0d8fdSPaul Kocialkowski 244311c0d8fdSPaul Kocialkowski /* White Balance */ 244411c0d8fdSPaul Kocialkowski 244511c0d8fdSPaul Kocialkowski v4l2_ctrl_new_std(handler, ops, V4L2_CID_RED_BALANCE, 1, 32767, 1, 244611c0d8fdSPaul Kocialkowski 1024); 244711c0d8fdSPaul Kocialkowski 244811c0d8fdSPaul Kocialkowski v4l2_ctrl_new_std(handler, ops, V4L2_CID_BLUE_BALANCE, 1, 32767, 1, 244911c0d8fdSPaul Kocialkowski 1024); 245011c0d8fdSPaul Kocialkowski 245111c0d8fdSPaul Kocialkowski /* Flip */ 245211c0d8fdSPaul Kocialkowski 245311c0d8fdSPaul Kocialkowski v4l2_ctrl_new_std(handler, ops, V4L2_CID_HFLIP, 0, 1, 1, 0); 245411c0d8fdSPaul Kocialkowski v4l2_ctrl_new_std(handler, ops, V4L2_CID_VFLIP, 0, 1, 1, 0); 245511c0d8fdSPaul Kocialkowski 245611c0d8fdSPaul Kocialkowski /* Test Pattern */ 245711c0d8fdSPaul Kocialkowski 245811c0d8fdSPaul Kocialkowski v4l2_ctrl_new_std_menu_items(handler, ops, V4L2_CID_TEST_PATTERN, 245911c0d8fdSPaul Kocialkowski ARRAY_SIZE(ov8865_test_pattern_menu) - 1, 246011c0d8fdSPaul Kocialkowski 0, 0, ov8865_test_pattern_menu); 246111c0d8fdSPaul Kocialkowski 246211c0d8fdSPaul Kocialkowski /* MIPI CSI-2 */ 246311c0d8fdSPaul Kocialkowski 246411c0d8fdSPaul Kocialkowski ctrls->link_freq = 246511c0d8fdSPaul Kocialkowski v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, 246611c0d8fdSPaul Kocialkowski ARRAY_SIZE(ov8865_link_freq_menu) - 1, 246711c0d8fdSPaul Kocialkowski 0, ov8865_link_freq_menu); 246811c0d8fdSPaul Kocialkowski 246911c0d8fdSPaul Kocialkowski ctrls->pixel_rate = 247011c0d8fdSPaul Kocialkowski v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, 1, 247111c0d8fdSPaul Kocialkowski INT_MAX, 1, 1); 247211c0d8fdSPaul Kocialkowski 247311c0d8fdSPaul Kocialkowski if (handler->error) { 247411c0d8fdSPaul Kocialkowski ret = handler->error; 247511c0d8fdSPaul Kocialkowski goto error_ctrls; 247611c0d8fdSPaul Kocialkowski } 247711c0d8fdSPaul Kocialkowski 247811c0d8fdSPaul Kocialkowski ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; 247911c0d8fdSPaul Kocialkowski ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY; 248011c0d8fdSPaul Kocialkowski 248111c0d8fdSPaul Kocialkowski sensor->subdev.ctrl_handler = handler; 248211c0d8fdSPaul Kocialkowski 248311c0d8fdSPaul Kocialkowski return 0; 248411c0d8fdSPaul Kocialkowski 248511c0d8fdSPaul Kocialkowski error_ctrls: 248611c0d8fdSPaul Kocialkowski v4l2_ctrl_handler_free(handler); 248711c0d8fdSPaul Kocialkowski 248811c0d8fdSPaul Kocialkowski return ret; 248911c0d8fdSPaul Kocialkowski } 249011c0d8fdSPaul Kocialkowski 249111c0d8fdSPaul Kocialkowski /* Subdev Video Operations */ 249211c0d8fdSPaul Kocialkowski 249311c0d8fdSPaul Kocialkowski static int ov8865_s_stream(struct v4l2_subdev *subdev, int enable) 249411c0d8fdSPaul Kocialkowski { 249511c0d8fdSPaul Kocialkowski struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev); 249611c0d8fdSPaul Kocialkowski struct ov8865_state *state = &sensor->state; 249711c0d8fdSPaul Kocialkowski int ret; 249811c0d8fdSPaul Kocialkowski 249911c0d8fdSPaul Kocialkowski if (enable) { 2500586ee057SMauro Carvalho Chehab ret = pm_runtime_resume_and_get(sensor->dev); 2501586ee057SMauro Carvalho Chehab if (ret < 0) 250211c0d8fdSPaul Kocialkowski return ret; 250311c0d8fdSPaul Kocialkowski } 250411c0d8fdSPaul Kocialkowski 250511c0d8fdSPaul Kocialkowski mutex_lock(&sensor->mutex); 250611c0d8fdSPaul Kocialkowski ret = ov8865_sw_standby(sensor, !enable); 250711c0d8fdSPaul Kocialkowski mutex_unlock(&sensor->mutex); 250811c0d8fdSPaul Kocialkowski 250911c0d8fdSPaul Kocialkowski if (ret) 251011c0d8fdSPaul Kocialkowski return ret; 251111c0d8fdSPaul Kocialkowski 251211c0d8fdSPaul Kocialkowski state->streaming = !!enable; 251311c0d8fdSPaul Kocialkowski 251411c0d8fdSPaul Kocialkowski if (!enable) 251511c0d8fdSPaul Kocialkowski pm_runtime_put(sensor->dev); 251611c0d8fdSPaul Kocialkowski 251711c0d8fdSPaul Kocialkowski return 0; 251811c0d8fdSPaul Kocialkowski } 251911c0d8fdSPaul Kocialkowski 252011c0d8fdSPaul Kocialkowski static int ov8865_g_frame_interval(struct v4l2_subdev *subdev, 252111c0d8fdSPaul Kocialkowski struct v4l2_subdev_frame_interval *interval) 252211c0d8fdSPaul Kocialkowski { 252311c0d8fdSPaul Kocialkowski struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev); 252411c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode; 252511c0d8fdSPaul Kocialkowski 252611c0d8fdSPaul Kocialkowski mutex_lock(&sensor->mutex); 252711c0d8fdSPaul Kocialkowski 252811c0d8fdSPaul Kocialkowski mode = sensor->state.mode; 252911c0d8fdSPaul Kocialkowski interval->interval = mode->frame_interval; 253011c0d8fdSPaul Kocialkowski 253111c0d8fdSPaul Kocialkowski mutex_unlock(&sensor->mutex); 253211c0d8fdSPaul Kocialkowski 2533a1946cafSYang Li return 0; 253411c0d8fdSPaul Kocialkowski } 253511c0d8fdSPaul Kocialkowski 253611c0d8fdSPaul Kocialkowski static const struct v4l2_subdev_video_ops ov8865_subdev_video_ops = { 253711c0d8fdSPaul Kocialkowski .s_stream = ov8865_s_stream, 253811c0d8fdSPaul Kocialkowski .g_frame_interval = ov8865_g_frame_interval, 253911c0d8fdSPaul Kocialkowski .s_frame_interval = ov8865_g_frame_interval, 254011c0d8fdSPaul Kocialkowski }; 254111c0d8fdSPaul Kocialkowski 254211c0d8fdSPaul Kocialkowski /* Subdev Pad Operations */ 254311c0d8fdSPaul Kocialkowski 254411c0d8fdSPaul Kocialkowski static int ov8865_enum_mbus_code(struct v4l2_subdev *subdev, 25450d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 254611c0d8fdSPaul Kocialkowski struct v4l2_subdev_mbus_code_enum *code_enum) 254711c0d8fdSPaul Kocialkowski { 254811c0d8fdSPaul Kocialkowski if (code_enum->index >= ARRAY_SIZE(ov8865_mbus_codes)) 254911c0d8fdSPaul Kocialkowski return -EINVAL; 255011c0d8fdSPaul Kocialkowski 255111c0d8fdSPaul Kocialkowski code_enum->code = ov8865_mbus_codes[code_enum->index]; 255211c0d8fdSPaul Kocialkowski 255311c0d8fdSPaul Kocialkowski return 0; 255411c0d8fdSPaul Kocialkowski } 255511c0d8fdSPaul Kocialkowski 255611c0d8fdSPaul Kocialkowski static void ov8865_mbus_format_fill(struct v4l2_mbus_framefmt *mbus_format, 255711c0d8fdSPaul Kocialkowski u32 mbus_code, 255811c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode) 255911c0d8fdSPaul Kocialkowski { 256011c0d8fdSPaul Kocialkowski mbus_format->width = mode->output_size_x; 256111c0d8fdSPaul Kocialkowski mbus_format->height = mode->output_size_y; 256211c0d8fdSPaul Kocialkowski mbus_format->code = mbus_code; 256311c0d8fdSPaul Kocialkowski 256411c0d8fdSPaul Kocialkowski mbus_format->field = V4L2_FIELD_NONE; 256511c0d8fdSPaul Kocialkowski mbus_format->colorspace = V4L2_COLORSPACE_RAW; 256611c0d8fdSPaul Kocialkowski mbus_format->ycbcr_enc = 256711c0d8fdSPaul Kocialkowski V4L2_MAP_YCBCR_ENC_DEFAULT(mbus_format->colorspace); 256811c0d8fdSPaul Kocialkowski mbus_format->quantization = V4L2_QUANTIZATION_FULL_RANGE; 256911c0d8fdSPaul Kocialkowski mbus_format->xfer_func = 257011c0d8fdSPaul Kocialkowski V4L2_MAP_XFER_FUNC_DEFAULT(mbus_format->colorspace); 257111c0d8fdSPaul Kocialkowski } 257211c0d8fdSPaul Kocialkowski 257311c0d8fdSPaul Kocialkowski static int ov8865_get_fmt(struct v4l2_subdev *subdev, 25740d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 257511c0d8fdSPaul Kocialkowski struct v4l2_subdev_format *format) 257611c0d8fdSPaul Kocialkowski { 257711c0d8fdSPaul Kocialkowski struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev); 257811c0d8fdSPaul Kocialkowski struct v4l2_mbus_framefmt *mbus_format = &format->format; 257911c0d8fdSPaul Kocialkowski 258011c0d8fdSPaul Kocialkowski mutex_lock(&sensor->mutex); 258111c0d8fdSPaul Kocialkowski 258211c0d8fdSPaul Kocialkowski if (format->which == V4L2_SUBDEV_FORMAT_TRY) 25830d346d2aSTomi Valkeinen *mbus_format = *v4l2_subdev_get_try_format(subdev, sd_state, 258411c0d8fdSPaul Kocialkowski format->pad); 258511c0d8fdSPaul Kocialkowski else 258611c0d8fdSPaul Kocialkowski ov8865_mbus_format_fill(mbus_format, sensor->state.mbus_code, 258711c0d8fdSPaul Kocialkowski sensor->state.mode); 258811c0d8fdSPaul Kocialkowski 258911c0d8fdSPaul Kocialkowski mutex_unlock(&sensor->mutex); 259011c0d8fdSPaul Kocialkowski 259111c0d8fdSPaul Kocialkowski return 0; 259211c0d8fdSPaul Kocialkowski } 259311c0d8fdSPaul Kocialkowski 259411c0d8fdSPaul Kocialkowski static int ov8865_set_fmt(struct v4l2_subdev *subdev, 25950d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 259611c0d8fdSPaul Kocialkowski struct v4l2_subdev_format *format) 259711c0d8fdSPaul Kocialkowski { 259811c0d8fdSPaul Kocialkowski struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev); 259911c0d8fdSPaul Kocialkowski struct v4l2_mbus_framefmt *mbus_format = &format->format; 260011c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode; 260111c0d8fdSPaul Kocialkowski u32 mbus_code = 0; 260211c0d8fdSPaul Kocialkowski unsigned int index; 260311c0d8fdSPaul Kocialkowski int ret = 0; 260411c0d8fdSPaul Kocialkowski 260511c0d8fdSPaul Kocialkowski mutex_lock(&sensor->mutex); 260611c0d8fdSPaul Kocialkowski 260711c0d8fdSPaul Kocialkowski if (sensor->state.streaming) { 260811c0d8fdSPaul Kocialkowski ret = -EBUSY; 260911c0d8fdSPaul Kocialkowski goto complete; 261011c0d8fdSPaul Kocialkowski } 261111c0d8fdSPaul Kocialkowski 261211c0d8fdSPaul Kocialkowski /* Try to find requested mbus code. */ 261311c0d8fdSPaul Kocialkowski for (index = 0; index < ARRAY_SIZE(ov8865_mbus_codes); index++) { 261411c0d8fdSPaul Kocialkowski if (ov8865_mbus_codes[index] == mbus_format->code) { 261511c0d8fdSPaul Kocialkowski mbus_code = mbus_format->code; 261611c0d8fdSPaul Kocialkowski break; 261711c0d8fdSPaul Kocialkowski } 261811c0d8fdSPaul Kocialkowski } 261911c0d8fdSPaul Kocialkowski 262011c0d8fdSPaul Kocialkowski /* Fallback to default. */ 262111c0d8fdSPaul Kocialkowski if (!mbus_code) 262211c0d8fdSPaul Kocialkowski mbus_code = ov8865_mbus_codes[0]; 262311c0d8fdSPaul Kocialkowski 262411c0d8fdSPaul Kocialkowski /* Find the mode with nearest dimensions. */ 262511c0d8fdSPaul Kocialkowski mode = v4l2_find_nearest_size(ov8865_modes, ARRAY_SIZE(ov8865_modes), 262611c0d8fdSPaul Kocialkowski output_size_x, output_size_y, 262711c0d8fdSPaul Kocialkowski mbus_format->width, mbus_format->height); 262811c0d8fdSPaul Kocialkowski if (!mode) { 262911c0d8fdSPaul Kocialkowski ret = -EINVAL; 263011c0d8fdSPaul Kocialkowski goto complete; 263111c0d8fdSPaul Kocialkowski } 263211c0d8fdSPaul Kocialkowski 263311c0d8fdSPaul Kocialkowski ov8865_mbus_format_fill(mbus_format, mbus_code, mode); 263411c0d8fdSPaul Kocialkowski 263511c0d8fdSPaul Kocialkowski if (format->which == V4L2_SUBDEV_FORMAT_TRY) 26360d346d2aSTomi Valkeinen *v4l2_subdev_get_try_format(subdev, sd_state, format->pad) = 263711c0d8fdSPaul Kocialkowski *mbus_format; 263811c0d8fdSPaul Kocialkowski else if (sensor->state.mode != mode || 263911c0d8fdSPaul Kocialkowski sensor->state.mbus_code != mbus_code) 264011c0d8fdSPaul Kocialkowski ret = ov8865_state_configure(sensor, mode, mbus_code); 264111c0d8fdSPaul Kocialkowski 264211c0d8fdSPaul Kocialkowski complete: 264311c0d8fdSPaul Kocialkowski mutex_unlock(&sensor->mutex); 264411c0d8fdSPaul Kocialkowski 264511c0d8fdSPaul Kocialkowski return ret; 264611c0d8fdSPaul Kocialkowski } 264711c0d8fdSPaul Kocialkowski 264811c0d8fdSPaul Kocialkowski static int ov8865_enum_frame_size(struct v4l2_subdev *subdev, 26490d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 265011c0d8fdSPaul Kocialkowski struct v4l2_subdev_frame_size_enum *size_enum) 265111c0d8fdSPaul Kocialkowski { 265211c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode; 265311c0d8fdSPaul Kocialkowski 265411c0d8fdSPaul Kocialkowski if (size_enum->index >= ARRAY_SIZE(ov8865_modes)) 265511c0d8fdSPaul Kocialkowski return -EINVAL; 265611c0d8fdSPaul Kocialkowski 265711c0d8fdSPaul Kocialkowski mode = &ov8865_modes[size_enum->index]; 265811c0d8fdSPaul Kocialkowski 265911c0d8fdSPaul Kocialkowski size_enum->min_width = size_enum->max_width = mode->output_size_x; 266011c0d8fdSPaul Kocialkowski size_enum->min_height = size_enum->max_height = mode->output_size_y; 266111c0d8fdSPaul Kocialkowski 266211c0d8fdSPaul Kocialkowski return 0; 266311c0d8fdSPaul Kocialkowski } 266411c0d8fdSPaul Kocialkowski 266511c0d8fdSPaul Kocialkowski static int ov8865_enum_frame_interval(struct v4l2_subdev *subdev, 26660d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 266711c0d8fdSPaul Kocialkowski struct v4l2_subdev_frame_interval_enum *interval_enum) 266811c0d8fdSPaul Kocialkowski { 266911c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode = NULL; 267011c0d8fdSPaul Kocialkowski unsigned int mode_index; 267111c0d8fdSPaul Kocialkowski unsigned int interval_index; 267211c0d8fdSPaul Kocialkowski 267311c0d8fdSPaul Kocialkowski if (interval_enum->index > 0) 267411c0d8fdSPaul Kocialkowski return -EINVAL; 267511c0d8fdSPaul Kocialkowski /* 267611c0d8fdSPaul Kocialkowski * Multiple modes with the same dimensions may have different frame 267711c0d8fdSPaul Kocialkowski * intervals, so look up each relevant mode. 267811c0d8fdSPaul Kocialkowski */ 267911c0d8fdSPaul Kocialkowski for (mode_index = 0, interval_index = 0; 268011c0d8fdSPaul Kocialkowski mode_index < ARRAY_SIZE(ov8865_modes); mode_index++) { 268111c0d8fdSPaul Kocialkowski mode = &ov8865_modes[mode_index]; 268211c0d8fdSPaul Kocialkowski 268311c0d8fdSPaul Kocialkowski if (mode->output_size_x == interval_enum->width && 268411c0d8fdSPaul Kocialkowski mode->output_size_y == interval_enum->height) { 268511c0d8fdSPaul Kocialkowski if (interval_index == interval_enum->index) 268611c0d8fdSPaul Kocialkowski break; 268711c0d8fdSPaul Kocialkowski 268811c0d8fdSPaul Kocialkowski interval_index++; 268911c0d8fdSPaul Kocialkowski } 269011c0d8fdSPaul Kocialkowski } 269111c0d8fdSPaul Kocialkowski 269245dbd70cSPaul Kocialkowski if (mode_index == ARRAY_SIZE(ov8865_modes)) 269311c0d8fdSPaul Kocialkowski return -EINVAL; 269411c0d8fdSPaul Kocialkowski 269511c0d8fdSPaul Kocialkowski interval_enum->interval = mode->frame_interval; 269611c0d8fdSPaul Kocialkowski 269711c0d8fdSPaul Kocialkowski return 0; 269811c0d8fdSPaul Kocialkowski } 269911c0d8fdSPaul Kocialkowski 270011c0d8fdSPaul Kocialkowski static const struct v4l2_subdev_pad_ops ov8865_subdev_pad_ops = { 270111c0d8fdSPaul Kocialkowski .enum_mbus_code = ov8865_enum_mbus_code, 270211c0d8fdSPaul Kocialkowski .get_fmt = ov8865_get_fmt, 270311c0d8fdSPaul Kocialkowski .set_fmt = ov8865_set_fmt, 270411c0d8fdSPaul Kocialkowski .enum_frame_size = ov8865_enum_frame_size, 270511c0d8fdSPaul Kocialkowski .enum_frame_interval = ov8865_enum_frame_interval, 270611c0d8fdSPaul Kocialkowski }; 270711c0d8fdSPaul Kocialkowski 270811c0d8fdSPaul Kocialkowski static const struct v4l2_subdev_ops ov8865_subdev_ops = { 270911c0d8fdSPaul Kocialkowski .video = &ov8865_subdev_video_ops, 271011c0d8fdSPaul Kocialkowski .pad = &ov8865_subdev_pad_ops, 271111c0d8fdSPaul Kocialkowski }; 271211c0d8fdSPaul Kocialkowski 271311c0d8fdSPaul Kocialkowski static int ov8865_suspend(struct device *dev) 271411c0d8fdSPaul Kocialkowski { 271511c0d8fdSPaul Kocialkowski struct i2c_client *client = to_i2c_client(dev); 271611c0d8fdSPaul Kocialkowski struct v4l2_subdev *subdev = i2c_get_clientdata(client); 271711c0d8fdSPaul Kocialkowski struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev); 271811c0d8fdSPaul Kocialkowski struct ov8865_state *state = &sensor->state; 271911c0d8fdSPaul Kocialkowski int ret = 0; 272011c0d8fdSPaul Kocialkowski 272111c0d8fdSPaul Kocialkowski mutex_lock(&sensor->mutex); 272211c0d8fdSPaul Kocialkowski 272311c0d8fdSPaul Kocialkowski if (state->streaming) { 272411c0d8fdSPaul Kocialkowski ret = ov8865_sw_standby(sensor, true); 272511c0d8fdSPaul Kocialkowski if (ret) 272611c0d8fdSPaul Kocialkowski goto complete; 272711c0d8fdSPaul Kocialkowski } 272811c0d8fdSPaul Kocialkowski 272911c0d8fdSPaul Kocialkowski ret = ov8865_sensor_power(sensor, false); 273011c0d8fdSPaul Kocialkowski if (ret) 273111c0d8fdSPaul Kocialkowski ov8865_sw_standby(sensor, false); 273211c0d8fdSPaul Kocialkowski 273311c0d8fdSPaul Kocialkowski complete: 273411c0d8fdSPaul Kocialkowski mutex_unlock(&sensor->mutex); 273511c0d8fdSPaul Kocialkowski 273611c0d8fdSPaul Kocialkowski return ret; 273711c0d8fdSPaul Kocialkowski } 273811c0d8fdSPaul Kocialkowski 273911c0d8fdSPaul Kocialkowski static int ov8865_resume(struct device *dev) 274011c0d8fdSPaul Kocialkowski { 274111c0d8fdSPaul Kocialkowski struct i2c_client *client = to_i2c_client(dev); 274211c0d8fdSPaul Kocialkowski struct v4l2_subdev *subdev = i2c_get_clientdata(client); 274311c0d8fdSPaul Kocialkowski struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev); 274411c0d8fdSPaul Kocialkowski struct ov8865_state *state = &sensor->state; 274511c0d8fdSPaul Kocialkowski int ret = 0; 274611c0d8fdSPaul Kocialkowski 274711c0d8fdSPaul Kocialkowski mutex_lock(&sensor->mutex); 274811c0d8fdSPaul Kocialkowski 274911c0d8fdSPaul Kocialkowski ret = ov8865_sensor_power(sensor, true); 275011c0d8fdSPaul Kocialkowski if (ret) 275111c0d8fdSPaul Kocialkowski goto complete; 275211c0d8fdSPaul Kocialkowski 275311c0d8fdSPaul Kocialkowski ret = ov8865_sensor_init(sensor); 275411c0d8fdSPaul Kocialkowski if (ret) 275511c0d8fdSPaul Kocialkowski goto error_power; 275611c0d8fdSPaul Kocialkowski 275711c0d8fdSPaul Kocialkowski ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler); 275811c0d8fdSPaul Kocialkowski if (ret) 275911c0d8fdSPaul Kocialkowski goto error_power; 276011c0d8fdSPaul Kocialkowski 276111c0d8fdSPaul Kocialkowski if (state->streaming) { 276211c0d8fdSPaul Kocialkowski ret = ov8865_sw_standby(sensor, false); 276311c0d8fdSPaul Kocialkowski if (ret) 276411c0d8fdSPaul Kocialkowski goto error_power; 276511c0d8fdSPaul Kocialkowski } 276611c0d8fdSPaul Kocialkowski 276711c0d8fdSPaul Kocialkowski goto complete; 276811c0d8fdSPaul Kocialkowski 276911c0d8fdSPaul Kocialkowski error_power: 277011c0d8fdSPaul Kocialkowski ov8865_sensor_power(sensor, false); 277111c0d8fdSPaul Kocialkowski 277211c0d8fdSPaul Kocialkowski complete: 277311c0d8fdSPaul Kocialkowski mutex_unlock(&sensor->mutex); 277411c0d8fdSPaul Kocialkowski 277511c0d8fdSPaul Kocialkowski return ret; 277611c0d8fdSPaul Kocialkowski } 277711c0d8fdSPaul Kocialkowski 277811c0d8fdSPaul Kocialkowski static int ov8865_probe(struct i2c_client *client) 277911c0d8fdSPaul Kocialkowski { 278011c0d8fdSPaul Kocialkowski struct device *dev = &client->dev; 278111c0d8fdSPaul Kocialkowski struct fwnode_handle *handle; 278211c0d8fdSPaul Kocialkowski struct ov8865_sensor *sensor; 278311c0d8fdSPaul Kocialkowski struct v4l2_subdev *subdev; 278411c0d8fdSPaul Kocialkowski struct media_pad *pad; 278511c0d8fdSPaul Kocialkowski unsigned long rate; 278611c0d8fdSPaul Kocialkowski int ret; 278711c0d8fdSPaul Kocialkowski 278811c0d8fdSPaul Kocialkowski sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); 278911c0d8fdSPaul Kocialkowski if (!sensor) 279011c0d8fdSPaul Kocialkowski return -ENOMEM; 279111c0d8fdSPaul Kocialkowski 279211c0d8fdSPaul Kocialkowski sensor->dev = dev; 279311c0d8fdSPaul Kocialkowski sensor->i2c_client = client; 279411c0d8fdSPaul Kocialkowski 279511c0d8fdSPaul Kocialkowski /* Graph Endpoint */ 279611c0d8fdSPaul Kocialkowski 279711c0d8fdSPaul Kocialkowski handle = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); 279811c0d8fdSPaul Kocialkowski if (!handle) { 2799ea12d248SColin Ian King dev_err(dev, "unable to find endpoint node\n"); 280011c0d8fdSPaul Kocialkowski return -EINVAL; 280111c0d8fdSPaul Kocialkowski } 280211c0d8fdSPaul Kocialkowski 280311c0d8fdSPaul Kocialkowski sensor->endpoint.bus_type = V4L2_MBUS_CSI2_DPHY; 280411c0d8fdSPaul Kocialkowski 280511c0d8fdSPaul Kocialkowski ret = v4l2_fwnode_endpoint_alloc_parse(handle, &sensor->endpoint); 280611c0d8fdSPaul Kocialkowski fwnode_handle_put(handle); 280711c0d8fdSPaul Kocialkowski if (ret) { 280811c0d8fdSPaul Kocialkowski dev_err(dev, "failed to parse endpoint node\n"); 280911c0d8fdSPaul Kocialkowski return ret; 281011c0d8fdSPaul Kocialkowski } 281111c0d8fdSPaul Kocialkowski 281211c0d8fdSPaul Kocialkowski /* GPIOs */ 281311c0d8fdSPaul Kocialkowski 281411c0d8fdSPaul Kocialkowski sensor->powerdown = devm_gpiod_get_optional(dev, "powerdown", 281511c0d8fdSPaul Kocialkowski GPIOD_OUT_HIGH); 281611c0d8fdSPaul Kocialkowski if (IS_ERR(sensor->powerdown)) { 281711c0d8fdSPaul Kocialkowski ret = PTR_ERR(sensor->powerdown); 281811c0d8fdSPaul Kocialkowski goto error_endpoint; 281911c0d8fdSPaul Kocialkowski } 282011c0d8fdSPaul Kocialkowski 282111c0d8fdSPaul Kocialkowski sensor->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); 282211c0d8fdSPaul Kocialkowski if (IS_ERR(sensor->reset)) { 282311c0d8fdSPaul Kocialkowski ret = PTR_ERR(sensor->reset); 282411c0d8fdSPaul Kocialkowski goto error_endpoint; 282511c0d8fdSPaul Kocialkowski } 282611c0d8fdSPaul Kocialkowski 282711c0d8fdSPaul Kocialkowski /* Regulators */ 282811c0d8fdSPaul Kocialkowski 282911c0d8fdSPaul Kocialkowski /* DVDD: digital core */ 283011c0d8fdSPaul Kocialkowski sensor->dvdd = devm_regulator_get(dev, "dvdd"); 283111c0d8fdSPaul Kocialkowski if (IS_ERR(sensor->dvdd)) { 283211c0d8fdSPaul Kocialkowski dev_err(dev, "cannot get DVDD (digital core) regulator\n"); 283311c0d8fdSPaul Kocialkowski ret = PTR_ERR(sensor->dvdd); 283411c0d8fdSPaul Kocialkowski goto error_endpoint; 283511c0d8fdSPaul Kocialkowski } 283611c0d8fdSPaul Kocialkowski 283711c0d8fdSPaul Kocialkowski /* DOVDD: digital I/O */ 283811c0d8fdSPaul Kocialkowski sensor->dovdd = devm_regulator_get(dev, "dovdd"); 28396e7cca27SHans Verkuil if (IS_ERR(sensor->dovdd)) { 284011c0d8fdSPaul Kocialkowski dev_err(dev, "cannot get DOVDD (digital I/O) regulator\n"); 28416e7cca27SHans Verkuil ret = PTR_ERR(sensor->dovdd); 284211c0d8fdSPaul Kocialkowski goto error_endpoint; 284311c0d8fdSPaul Kocialkowski } 284411c0d8fdSPaul Kocialkowski 284511c0d8fdSPaul Kocialkowski /* AVDD: analog */ 284611c0d8fdSPaul Kocialkowski sensor->avdd = devm_regulator_get(dev, "avdd"); 284711c0d8fdSPaul Kocialkowski if (IS_ERR(sensor->avdd)) { 284811c0d8fdSPaul Kocialkowski dev_err(dev, "cannot get AVDD (analog) regulator\n"); 28496e7cca27SHans Verkuil ret = PTR_ERR(sensor->avdd); 285011c0d8fdSPaul Kocialkowski goto error_endpoint; 285111c0d8fdSPaul Kocialkowski } 285211c0d8fdSPaul Kocialkowski 285311c0d8fdSPaul Kocialkowski /* External Clock */ 285411c0d8fdSPaul Kocialkowski 285511c0d8fdSPaul Kocialkowski sensor->extclk = devm_clk_get(dev, NULL); 285611c0d8fdSPaul Kocialkowski if (IS_ERR(sensor->extclk)) { 285711c0d8fdSPaul Kocialkowski dev_err(dev, "failed to get external clock\n"); 285811c0d8fdSPaul Kocialkowski ret = PTR_ERR(sensor->extclk); 285911c0d8fdSPaul Kocialkowski goto error_endpoint; 286011c0d8fdSPaul Kocialkowski } 286111c0d8fdSPaul Kocialkowski 286211c0d8fdSPaul Kocialkowski rate = clk_get_rate(sensor->extclk); 286311c0d8fdSPaul Kocialkowski if (rate != OV8865_EXTCLK_RATE) { 286411c0d8fdSPaul Kocialkowski dev_err(dev, "clock rate %lu Hz is unsupported\n", rate); 286511c0d8fdSPaul Kocialkowski ret = -EINVAL; 286611c0d8fdSPaul Kocialkowski goto error_endpoint; 286711c0d8fdSPaul Kocialkowski } 286811c0d8fdSPaul Kocialkowski 286911c0d8fdSPaul Kocialkowski /* Subdev, entity and pad */ 287011c0d8fdSPaul Kocialkowski 287111c0d8fdSPaul Kocialkowski subdev = &sensor->subdev; 287211c0d8fdSPaul Kocialkowski v4l2_i2c_subdev_init(subdev, client, &ov8865_subdev_ops); 287311c0d8fdSPaul Kocialkowski 287411c0d8fdSPaul Kocialkowski subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 287511c0d8fdSPaul Kocialkowski subdev->entity.function = MEDIA_ENT_F_CAM_SENSOR; 287611c0d8fdSPaul Kocialkowski 287711c0d8fdSPaul Kocialkowski pad = &sensor->pad; 287811c0d8fdSPaul Kocialkowski pad->flags = MEDIA_PAD_FL_SOURCE; 287911c0d8fdSPaul Kocialkowski 288011c0d8fdSPaul Kocialkowski ret = media_entity_pads_init(&subdev->entity, 1, pad); 288111c0d8fdSPaul Kocialkowski if (ret) 288211c0d8fdSPaul Kocialkowski goto error_entity; 288311c0d8fdSPaul Kocialkowski 288411c0d8fdSPaul Kocialkowski /* Mutex */ 288511c0d8fdSPaul Kocialkowski 288611c0d8fdSPaul Kocialkowski mutex_init(&sensor->mutex); 288711c0d8fdSPaul Kocialkowski 288811c0d8fdSPaul Kocialkowski /* Sensor */ 288911c0d8fdSPaul Kocialkowski 289011c0d8fdSPaul Kocialkowski ret = ov8865_ctrls_init(sensor); 289111c0d8fdSPaul Kocialkowski if (ret) 289211c0d8fdSPaul Kocialkowski goto error_mutex; 289311c0d8fdSPaul Kocialkowski 2894*6e1c9bc9SHans de Goede mutex_lock(&sensor->mutex); 289511c0d8fdSPaul Kocialkowski ret = ov8865_state_init(sensor); 2896*6e1c9bc9SHans de Goede mutex_unlock(&sensor->mutex); 289711c0d8fdSPaul Kocialkowski if (ret) 289811c0d8fdSPaul Kocialkowski goto error_ctrls; 289911c0d8fdSPaul Kocialkowski 290011c0d8fdSPaul Kocialkowski /* Runtime PM */ 290111c0d8fdSPaul Kocialkowski 290211c0d8fdSPaul Kocialkowski pm_runtime_set_suspended(sensor->dev); 2903d2484fbfSDaniel Scally pm_runtime_enable(sensor->dev); 290411c0d8fdSPaul Kocialkowski 290511c0d8fdSPaul Kocialkowski /* V4L2 subdev register */ 290611c0d8fdSPaul Kocialkowski 290715786f7bSSakari Ailus ret = v4l2_async_register_subdev_sensor(subdev); 290811c0d8fdSPaul Kocialkowski if (ret) 290911c0d8fdSPaul Kocialkowski goto error_pm; 291011c0d8fdSPaul Kocialkowski 291111c0d8fdSPaul Kocialkowski return 0; 291211c0d8fdSPaul Kocialkowski 291311c0d8fdSPaul Kocialkowski error_pm: 291411c0d8fdSPaul Kocialkowski pm_runtime_disable(sensor->dev); 291511c0d8fdSPaul Kocialkowski 291611c0d8fdSPaul Kocialkowski error_ctrls: 291711c0d8fdSPaul Kocialkowski v4l2_ctrl_handler_free(&sensor->ctrls.handler); 291811c0d8fdSPaul Kocialkowski 291911c0d8fdSPaul Kocialkowski error_mutex: 292011c0d8fdSPaul Kocialkowski mutex_destroy(&sensor->mutex); 292111c0d8fdSPaul Kocialkowski 292211c0d8fdSPaul Kocialkowski error_entity: 292311c0d8fdSPaul Kocialkowski media_entity_cleanup(&sensor->subdev.entity); 292411c0d8fdSPaul Kocialkowski 292511c0d8fdSPaul Kocialkowski error_endpoint: 292611c0d8fdSPaul Kocialkowski v4l2_fwnode_endpoint_free(&sensor->endpoint); 292711c0d8fdSPaul Kocialkowski 292811c0d8fdSPaul Kocialkowski return ret; 292911c0d8fdSPaul Kocialkowski } 293011c0d8fdSPaul Kocialkowski 293111c0d8fdSPaul Kocialkowski static int ov8865_remove(struct i2c_client *client) 293211c0d8fdSPaul Kocialkowski { 293311c0d8fdSPaul Kocialkowski struct v4l2_subdev *subdev = i2c_get_clientdata(client); 293411c0d8fdSPaul Kocialkowski struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev); 293511c0d8fdSPaul Kocialkowski 293611c0d8fdSPaul Kocialkowski v4l2_async_unregister_subdev(subdev); 293711c0d8fdSPaul Kocialkowski pm_runtime_disable(sensor->dev); 293811c0d8fdSPaul Kocialkowski v4l2_ctrl_handler_free(&sensor->ctrls.handler); 293911c0d8fdSPaul Kocialkowski mutex_destroy(&sensor->mutex); 294011c0d8fdSPaul Kocialkowski media_entity_cleanup(&subdev->entity); 294111c0d8fdSPaul Kocialkowski 294211c0d8fdSPaul Kocialkowski v4l2_fwnode_endpoint_free(&sensor->endpoint); 294311c0d8fdSPaul Kocialkowski 294411c0d8fdSPaul Kocialkowski return 0; 294511c0d8fdSPaul Kocialkowski } 294611c0d8fdSPaul Kocialkowski 294711c0d8fdSPaul Kocialkowski static const struct dev_pm_ops ov8865_pm_ops = { 294811c0d8fdSPaul Kocialkowski SET_RUNTIME_PM_OPS(ov8865_suspend, ov8865_resume, NULL) 294911c0d8fdSPaul Kocialkowski }; 295011c0d8fdSPaul Kocialkowski 295111c0d8fdSPaul Kocialkowski static const struct of_device_id ov8865_of_match[] = { 295211c0d8fdSPaul Kocialkowski { .compatible = "ovti,ov8865" }, 295311c0d8fdSPaul Kocialkowski { } 295411c0d8fdSPaul Kocialkowski }; 295511c0d8fdSPaul Kocialkowski MODULE_DEVICE_TABLE(of, ov8865_of_match); 295611c0d8fdSPaul Kocialkowski 295711c0d8fdSPaul Kocialkowski static struct i2c_driver ov8865_driver = { 295811c0d8fdSPaul Kocialkowski .driver = { 295911c0d8fdSPaul Kocialkowski .name = "ov8865", 296011c0d8fdSPaul Kocialkowski .of_match_table = ov8865_of_match, 296111c0d8fdSPaul Kocialkowski .pm = &ov8865_pm_ops, 296211c0d8fdSPaul Kocialkowski }, 296311c0d8fdSPaul Kocialkowski .probe_new = ov8865_probe, 296411c0d8fdSPaul Kocialkowski .remove = ov8865_remove, 296511c0d8fdSPaul Kocialkowski }; 296611c0d8fdSPaul Kocialkowski 296711c0d8fdSPaul Kocialkowski module_i2c_driver(ov8865_driver); 296811c0d8fdSPaul Kocialkowski 296911c0d8fdSPaul Kocialkowski MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>"); 297011c0d8fdSPaul Kocialkowski MODULE_DESCRIPTION("V4L2 driver for the OmniVision OV8865 image sensor"); 297111c0d8fdSPaul Kocialkowski MODULE_LICENSE("GPL v2"); 2972