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> 12dc69bc7aSDaniel Scally #include <linux/mod_devicetable.h> 1311c0d8fdSPaul Kocialkowski #include <linux/module.h> 1411c0d8fdSPaul Kocialkowski #include <linux/of_graph.h> 1511c0d8fdSPaul Kocialkowski #include <linux/pm_runtime.h> 1611c0d8fdSPaul Kocialkowski #include <linux/regulator/consumer.h> 1711c0d8fdSPaul Kocialkowski #include <linux/videodev2.h> 1811c0d8fdSPaul Kocialkowski #include <media/v4l2-ctrls.h> 1911c0d8fdSPaul Kocialkowski #include <media/v4l2-device.h> 2011c0d8fdSPaul Kocialkowski #include <media/v4l2-fwnode.h> 2111c0d8fdSPaul Kocialkowski #include <media/v4l2-image-sizes.h> 2211c0d8fdSPaul Kocialkowski #include <media/v4l2-mediabus.h> 2311c0d8fdSPaul Kocialkowski 2411c0d8fdSPaul Kocialkowski /* Register definitions */ 2511c0d8fdSPaul Kocialkowski 2611c0d8fdSPaul Kocialkowski /* System */ 2711c0d8fdSPaul Kocialkowski 2811c0d8fdSPaul Kocialkowski #define OV8865_SW_STANDBY_REG 0x100 2911c0d8fdSPaul Kocialkowski #define OV8865_SW_STANDBY_STREAM_ON BIT(0) 3011c0d8fdSPaul Kocialkowski 3111c0d8fdSPaul Kocialkowski #define OV8865_SW_RESET_REG 0x103 3211c0d8fdSPaul Kocialkowski #define OV8865_SW_RESET_RESET BIT(0) 3311c0d8fdSPaul Kocialkowski 3411c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL0_REG 0x300 3511c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL0_PRE_DIV(v) ((v) & GENMASK(2, 0)) 3611c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL1_REG 0x301 3711c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL1_MUL_H(v) (((v) & GENMASK(9, 8)) >> 8) 3811c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL2_REG 0x302 3911c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL2_MUL_L(v) ((v) & GENMASK(7, 0)) 4011c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL3_REG 0x303 4111c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL3_M_DIV(v) (((v) - 1) & GENMASK(3, 0)) 4211c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL4_REG 0x304 4311c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL4_MIPI_DIV(v) ((v) & GENMASK(1, 0)) 4411c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL5_REG 0x305 4511c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL5_SYS_PRE_DIV(v) ((v) & GENMASK(1, 0)) 4611c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL6_REG 0x306 4711c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL6_SYS_DIV(v) (((v) - 1) & BIT(0)) 4811c0d8fdSPaul Kocialkowski 4911c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL8_REG 0x308 5011c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL9_REG 0x309 5111c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRLA_REG 0x30a 5211c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRLA_PRE_DIV_HALF(v) (((v) - 1) & BIT(0)) 5311c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRLB_REG 0x30b 5411c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRLB_PRE_DIV(v) ((v) & GENMASK(2, 0)) 5511c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRLC_REG 0x30c 5611c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRLC_MUL_H(v) (((v) & GENMASK(9, 8)) >> 8) 5711c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRLD_REG 0x30d 5811c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRLD_MUL_L(v) ((v) & GENMASK(7, 0)) 5911c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRLE_REG 0x30e 6011c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRLE_SYS_DIV(v) ((v) & GENMASK(2, 0)) 6111c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRLF_REG 0x30f 6211c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRLF_SYS_PRE_DIV(v) (((v) - 1) & GENMASK(3, 0)) 6311c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL10_REG 0x310 6411c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL11_REG 0x311 6511c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL12_REG 0x312 6611c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL12_PRE_DIV_HALF(v) ((((v) - 1) << 4) & BIT(4)) 6711c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL12_DAC_DIV(v) (((v) - 1) & GENMASK(3, 0)) 6811c0d8fdSPaul Kocialkowski 6911c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL1B_REG 0x31b 7011c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL1C_REG 0x31c 7111c0d8fdSPaul Kocialkowski 7211c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL1E_REG 0x31e 7311c0d8fdSPaul Kocialkowski #define OV8865_PLL_CTRL1E_PLL1_NO_LAT BIT(3) 7411c0d8fdSPaul Kocialkowski 7511c0d8fdSPaul Kocialkowski #define OV8865_PAD_OEN0_REG 0x3000 7611c0d8fdSPaul Kocialkowski 7711c0d8fdSPaul Kocialkowski #define OV8865_PAD_OEN2_REG 0x3002 7811c0d8fdSPaul Kocialkowski 7911c0d8fdSPaul Kocialkowski #define OV8865_CLK_RST5_REG 0x3005 8011c0d8fdSPaul Kocialkowski 8111c0d8fdSPaul Kocialkowski #define OV8865_CHIP_ID_HH_REG 0x300a 8211c0d8fdSPaul Kocialkowski #define OV8865_CHIP_ID_HH_VALUE 0x00 8311c0d8fdSPaul Kocialkowski #define OV8865_CHIP_ID_H_REG 0x300b 8411c0d8fdSPaul Kocialkowski #define OV8865_CHIP_ID_H_VALUE 0x88 8511c0d8fdSPaul Kocialkowski #define OV8865_CHIP_ID_L_REG 0x300c 8611c0d8fdSPaul Kocialkowski #define OV8865_CHIP_ID_L_VALUE 0x65 8711c0d8fdSPaul Kocialkowski #define OV8865_PAD_OUT2_REG 0x300d 8811c0d8fdSPaul Kocialkowski 8911c0d8fdSPaul Kocialkowski #define OV8865_PAD_SEL2_REG 0x3010 9011c0d8fdSPaul Kocialkowski #define OV8865_PAD_PK_REG 0x3011 9111c0d8fdSPaul Kocialkowski #define OV8865_PAD_PK_DRIVE_STRENGTH_1X (0 << 5) 9211c0d8fdSPaul Kocialkowski #define OV8865_PAD_PK_DRIVE_STRENGTH_2X (1 << 5) 9311c0d8fdSPaul Kocialkowski #define OV8865_PAD_PK_DRIVE_STRENGTH_3X (2 << 5) 9411c0d8fdSPaul Kocialkowski #define OV8865_PAD_PK_DRIVE_STRENGTH_4X (3 << 5) 9511c0d8fdSPaul Kocialkowski 9611c0d8fdSPaul Kocialkowski #define OV8865_PUMP_CLK_DIV_REG 0x3015 9711c0d8fdSPaul Kocialkowski #define OV8865_PUMP_CLK_DIV_PUMP_N(v) (((v) << 4) & GENMASK(6, 4)) 9811c0d8fdSPaul Kocialkowski #define OV8865_PUMP_CLK_DIV_PUMP_P(v) ((v) & GENMASK(2, 0)) 9911c0d8fdSPaul Kocialkowski 10011c0d8fdSPaul Kocialkowski #define OV8865_MIPI_SC_CTRL0_REG 0x3018 10111c0d8fdSPaul Kocialkowski #define OV8865_MIPI_SC_CTRL0_LANES(v) ((((v) - 1) << 5) & \ 10211c0d8fdSPaul Kocialkowski GENMASK(7, 5)) 10311c0d8fdSPaul Kocialkowski #define OV8865_MIPI_SC_CTRL0_MIPI_EN BIT(4) 10411c0d8fdSPaul Kocialkowski #define OV8865_MIPI_SC_CTRL0_UNKNOWN BIT(1) 10511c0d8fdSPaul Kocialkowski #define OV8865_MIPI_SC_CTRL0_LANES_PD_MIPI BIT(0) 10611c0d8fdSPaul Kocialkowski #define OV8865_MIPI_SC_CTRL1_REG 0x3019 10711c0d8fdSPaul Kocialkowski #define OV8865_CLK_RST0_REG 0x301a 10811c0d8fdSPaul Kocialkowski #define OV8865_CLK_RST1_REG 0x301b 10911c0d8fdSPaul Kocialkowski #define OV8865_CLK_RST2_REG 0x301c 11011c0d8fdSPaul Kocialkowski #define OV8865_CLK_RST3_REG 0x301d 11111c0d8fdSPaul Kocialkowski #define OV8865_CLK_RST4_REG 0x301e 11211c0d8fdSPaul Kocialkowski 11311c0d8fdSPaul Kocialkowski #define OV8865_PCLK_SEL_REG 0x3020 11411c0d8fdSPaul Kocialkowski #define OV8865_PCLK_SEL_PCLK_DIV_MASK BIT(3) 11511c0d8fdSPaul Kocialkowski #define OV8865_PCLK_SEL_PCLK_DIV(v) ((((v) - 1) << 3) & BIT(3)) 11611c0d8fdSPaul Kocialkowski 11711c0d8fdSPaul Kocialkowski #define OV8865_MISC_CTRL_REG 0x3021 11811c0d8fdSPaul Kocialkowski #define OV8865_MIPI_SC_CTRL2_REG 0x3022 11911c0d8fdSPaul Kocialkowski #define OV8865_MIPI_SC_CTRL2_CLK_LANES_PD_MIPI BIT(1) 12011c0d8fdSPaul Kocialkowski #define OV8865_MIPI_SC_CTRL2_PD_MIPI_RST_SYNC BIT(0) 12111c0d8fdSPaul Kocialkowski 12211c0d8fdSPaul Kocialkowski #define OV8865_MIPI_BIT_SEL_REG 0x3031 12311c0d8fdSPaul Kocialkowski #define OV8865_MIPI_BIT_SEL(v) (((v) << 0) & GENMASK(4, 0)) 12411c0d8fdSPaul Kocialkowski #define OV8865_CLK_SEL0_REG 0x3032 12511c0d8fdSPaul Kocialkowski #define OV8865_CLK_SEL0_PLL1_SYS_SEL(v) (((v) << 7) & BIT(7)) 12611c0d8fdSPaul Kocialkowski #define OV8865_CLK_SEL1_REG 0x3033 12711c0d8fdSPaul Kocialkowski #define OV8865_CLK_SEL1_MIPI_EOF BIT(5) 12811c0d8fdSPaul Kocialkowski #define OV8865_CLK_SEL1_UNKNOWN BIT(2) 12911c0d8fdSPaul Kocialkowski #define OV8865_CLK_SEL1_PLL_SCLK_SEL_MASK BIT(1) 13011c0d8fdSPaul Kocialkowski #define OV8865_CLK_SEL1_PLL_SCLK_SEL(v) (((v) << 1) & BIT(1)) 13111c0d8fdSPaul Kocialkowski 13211c0d8fdSPaul Kocialkowski #define OV8865_SCLK_CTRL_REG 0x3106 13311c0d8fdSPaul Kocialkowski #define OV8865_SCLK_CTRL_SCLK_DIV(v) (((v) << 4) & GENMASK(7, 4)) 13411c0d8fdSPaul Kocialkowski #define OV8865_SCLK_CTRL_SCLK_PRE_DIV(v) (((v) << 2) & GENMASK(3, 2)) 13511c0d8fdSPaul Kocialkowski #define OV8865_SCLK_CTRL_UNKNOWN BIT(0) 13611c0d8fdSPaul Kocialkowski 13711c0d8fdSPaul Kocialkowski /* Exposure/gain */ 13811c0d8fdSPaul Kocialkowski 13911c0d8fdSPaul Kocialkowski #define OV8865_EXPOSURE_CTRL_HH_REG 0x3500 14011c0d8fdSPaul Kocialkowski #define OV8865_EXPOSURE_CTRL_HH(v) (((v) & GENMASK(19, 16)) >> 16) 14111c0d8fdSPaul Kocialkowski #define OV8865_EXPOSURE_CTRL_H_REG 0x3501 14211c0d8fdSPaul Kocialkowski #define OV8865_EXPOSURE_CTRL_H(v) (((v) & GENMASK(15, 8)) >> 8) 14311c0d8fdSPaul Kocialkowski #define OV8865_EXPOSURE_CTRL_L_REG 0x3502 14411c0d8fdSPaul Kocialkowski #define OV8865_EXPOSURE_CTRL_L(v) ((v) & GENMASK(7, 0)) 14511c0d8fdSPaul Kocialkowski #define OV8865_EXPOSURE_GAIN_MANUAL_REG 0x3503 146ca28690eSDaniel Scally #define OV8865_INTEGRATION_TIME_MARGIN 8 14711c0d8fdSPaul Kocialkowski 14811c0d8fdSPaul Kocialkowski #define OV8865_GAIN_CTRL_H_REG 0x3508 14911c0d8fdSPaul Kocialkowski #define OV8865_GAIN_CTRL_H(v) (((v) & GENMASK(12, 8)) >> 8) 15011c0d8fdSPaul Kocialkowski #define OV8865_GAIN_CTRL_L_REG 0x3509 15111c0d8fdSPaul Kocialkowski #define OV8865_GAIN_CTRL_L(v) ((v) & GENMASK(7, 0)) 15211c0d8fdSPaul Kocialkowski 15311c0d8fdSPaul Kocialkowski /* Timing */ 15411c0d8fdSPaul Kocialkowski 15511c0d8fdSPaul Kocialkowski #define OV8865_CROP_START_X_H_REG 0x3800 15611c0d8fdSPaul Kocialkowski #define OV8865_CROP_START_X_H(v) (((v) & GENMASK(11, 8)) >> 8) 15711c0d8fdSPaul Kocialkowski #define OV8865_CROP_START_X_L_REG 0x3801 15811c0d8fdSPaul Kocialkowski #define OV8865_CROP_START_X_L(v) ((v) & GENMASK(7, 0)) 15911c0d8fdSPaul Kocialkowski #define OV8865_CROP_START_Y_H_REG 0x3802 16011c0d8fdSPaul Kocialkowski #define OV8865_CROP_START_Y_H(v) (((v) & GENMASK(11, 8)) >> 8) 16111c0d8fdSPaul Kocialkowski #define OV8865_CROP_START_Y_L_REG 0x3803 16211c0d8fdSPaul Kocialkowski #define OV8865_CROP_START_Y_L(v) ((v) & GENMASK(7, 0)) 16311c0d8fdSPaul Kocialkowski #define OV8865_CROP_END_X_H_REG 0x3804 16411c0d8fdSPaul Kocialkowski #define OV8865_CROP_END_X_H(v) (((v) & GENMASK(11, 8)) >> 8) 16511c0d8fdSPaul Kocialkowski #define OV8865_CROP_END_X_L_REG 0x3805 16611c0d8fdSPaul Kocialkowski #define OV8865_CROP_END_X_L(v) ((v) & GENMASK(7, 0)) 16711c0d8fdSPaul Kocialkowski #define OV8865_CROP_END_Y_H_REG 0x3806 16811c0d8fdSPaul Kocialkowski #define OV8865_CROP_END_Y_H(v) (((v) & GENMASK(11, 8)) >> 8) 16911c0d8fdSPaul Kocialkowski #define OV8865_CROP_END_Y_L_REG 0x3807 17011c0d8fdSPaul Kocialkowski #define OV8865_CROP_END_Y_L(v) ((v) & GENMASK(7, 0)) 17111c0d8fdSPaul Kocialkowski #define OV8865_OUTPUT_SIZE_X_H_REG 0x3808 17211c0d8fdSPaul Kocialkowski #define OV8865_OUTPUT_SIZE_X_H(v) (((v) & GENMASK(11, 8)) >> 8) 17311c0d8fdSPaul Kocialkowski #define OV8865_OUTPUT_SIZE_X_L_REG 0x3809 17411c0d8fdSPaul Kocialkowski #define OV8865_OUTPUT_SIZE_X_L(v) ((v) & GENMASK(7, 0)) 17511c0d8fdSPaul Kocialkowski #define OV8865_OUTPUT_SIZE_Y_H_REG 0x380a 17611c0d8fdSPaul Kocialkowski #define OV8865_OUTPUT_SIZE_Y_H(v) (((v) & GENMASK(11, 8)) >> 8) 17711c0d8fdSPaul Kocialkowski #define OV8865_OUTPUT_SIZE_Y_L_REG 0x380b 17811c0d8fdSPaul Kocialkowski #define OV8865_OUTPUT_SIZE_Y_L(v) ((v) & GENMASK(7, 0)) 17911c0d8fdSPaul Kocialkowski #define OV8865_HTS_H_REG 0x380c 18011c0d8fdSPaul Kocialkowski #define OV8865_HTS_H(v) (((v) & GENMASK(11, 8)) >> 8) 18111c0d8fdSPaul Kocialkowski #define OV8865_HTS_L_REG 0x380d 18211c0d8fdSPaul Kocialkowski #define OV8865_HTS_L(v) ((v) & GENMASK(7, 0)) 18311c0d8fdSPaul Kocialkowski #define OV8865_VTS_H_REG 0x380e 18411c0d8fdSPaul Kocialkowski #define OV8865_VTS_H(v) (((v) & GENMASK(11, 8)) >> 8) 18511c0d8fdSPaul Kocialkowski #define OV8865_VTS_L_REG 0x380f 18611c0d8fdSPaul Kocialkowski #define OV8865_VTS_L(v) ((v) & GENMASK(7, 0)) 1879293aafeSDaniel Scally #define OV8865_TIMING_MAX_VTS 0xffff 1889293aafeSDaniel Scally #define OV8865_TIMING_MIN_VTS 0x04 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 456acd25e22SDaniel Scally /* Pixel Array */ 457acd25e22SDaniel Scally 458acd25e22SDaniel Scally #define OV8865_NATIVE_WIDTH 3296 459acd25e22SDaniel Scally #define OV8865_NATIVE_HEIGHT 2528 460acd25e22SDaniel Scally #define OV8865_ACTIVE_START_TOP 32 461acd25e22SDaniel Scally #define OV8865_ACTIVE_START_LEFT 80 462acd25e22SDaniel Scally #define OV8865_ACTIVE_WIDTH 3264 463acd25e22SDaniel Scally #define OV8865_ACTIVE_HEIGHT 2448 464acd25e22SDaniel Scally 46511c0d8fdSPaul Kocialkowski /* Macros */ 46611c0d8fdSPaul Kocialkowski 46711c0d8fdSPaul Kocialkowski #define ov8865_subdev_sensor(s) \ 46811c0d8fdSPaul Kocialkowski container_of(s, struct ov8865_sensor, subdev) 46911c0d8fdSPaul Kocialkowski 47011c0d8fdSPaul Kocialkowski #define ov8865_ctrl_subdev(c) \ 47136e4f2b2SPaul Kocialkowski (&container_of((c)->handler, struct ov8865_sensor, \ 47236e4f2b2SPaul Kocialkowski ctrls.handler)->subdev) 47311c0d8fdSPaul Kocialkowski 47411c0d8fdSPaul Kocialkowski /* Data structures */ 47511c0d8fdSPaul Kocialkowski 47611c0d8fdSPaul Kocialkowski struct ov8865_register_value { 47711c0d8fdSPaul Kocialkowski u16 address; 47811c0d8fdSPaul Kocialkowski u8 value; 47911c0d8fdSPaul Kocialkowski unsigned int delay_ms; 48011c0d8fdSPaul Kocialkowski }; 48111c0d8fdSPaul Kocialkowski 48211c0d8fdSPaul Kocialkowski /* 48311c0d8fdSPaul Kocialkowski * PLL1 Clock Tree: 48411c0d8fdSPaul Kocialkowski * 48511c0d8fdSPaul Kocialkowski * +-< EXTCLK 48611c0d8fdSPaul Kocialkowski * | 48711c0d8fdSPaul Kocialkowski * +-+ pll_pre_div_half (0x30a [0]) 48811c0d8fdSPaul Kocialkowski * | 48911c0d8fdSPaul Kocialkowski * +-+ pll_pre_div (0x300 [2:0], special values: 49011c0d8fdSPaul Kocialkowski * | 0: 1, 1: 1.5, 3: 2.5, 4: 3, 5: 4, 7: 8) 49111c0d8fdSPaul Kocialkowski * +-+ pll_mul (0x301 [1:0], 0x302 [7:0]) 49211c0d8fdSPaul Kocialkowski * | 49311c0d8fdSPaul Kocialkowski * +-+ m_div (0x303 [3:0]) 49411c0d8fdSPaul Kocialkowski * | | 49511c0d8fdSPaul Kocialkowski * | +-> PHY_SCLK 49611c0d8fdSPaul Kocialkowski * | | 49711c0d8fdSPaul Kocialkowski * | +-+ mipi_div (0x304 [1:0], special values: 0: 4, 1: 5, 2: 6, 3: 8) 49811c0d8fdSPaul Kocialkowski * | | 49911c0d8fdSPaul Kocialkowski * | +-+ pclk_div (0x3020 [3]) 50011c0d8fdSPaul Kocialkowski * | | 50111c0d8fdSPaul Kocialkowski * | +-> PCLK 50211c0d8fdSPaul Kocialkowski * | 50311c0d8fdSPaul Kocialkowski * +-+ sys_pre_div (0x305 [1:0], special values: 0: 3, 1: 4, 2: 5, 3: 6) 50411c0d8fdSPaul Kocialkowski * | 50511c0d8fdSPaul Kocialkowski * +-+ sys_div (0x306 [0]) 50611c0d8fdSPaul Kocialkowski * | 50711c0d8fdSPaul Kocialkowski * +-+ sys_sel (0x3032 [7], 0: PLL1, 1: PLL2) 50811c0d8fdSPaul Kocialkowski * | 50911c0d8fdSPaul Kocialkowski * +-+ sclk_sel (0x3033 [1], 0: sys_sel, 1: PLL2 DAC_CLK) 51011c0d8fdSPaul Kocialkowski * | 51111c0d8fdSPaul Kocialkowski * +-+ sclk_pre_div (0x3106 [3:2], special values: 51211c0d8fdSPaul Kocialkowski * | 0: 1, 1: 2, 2: 4, 3: 1) 51311c0d8fdSPaul Kocialkowski * | 51411c0d8fdSPaul Kocialkowski * +-+ sclk_div (0x3106 [7:4], special values: 0: 1) 51511c0d8fdSPaul Kocialkowski * | 51611c0d8fdSPaul Kocialkowski * +-> SCLK 51711c0d8fdSPaul Kocialkowski */ 51811c0d8fdSPaul Kocialkowski 51911c0d8fdSPaul Kocialkowski struct ov8865_pll1_config { 52011c0d8fdSPaul Kocialkowski unsigned int pll_pre_div_half; 52111c0d8fdSPaul Kocialkowski unsigned int pll_pre_div; 52211c0d8fdSPaul Kocialkowski unsigned int pll_mul; 52311c0d8fdSPaul Kocialkowski unsigned int m_div; 52411c0d8fdSPaul Kocialkowski unsigned int mipi_div; 52511c0d8fdSPaul Kocialkowski unsigned int pclk_div; 52611c0d8fdSPaul Kocialkowski unsigned int sys_pre_div; 52711c0d8fdSPaul Kocialkowski unsigned int sys_div; 52811c0d8fdSPaul Kocialkowski }; 52911c0d8fdSPaul Kocialkowski 53011c0d8fdSPaul Kocialkowski /* 53111c0d8fdSPaul Kocialkowski * PLL2 Clock Tree: 53211c0d8fdSPaul Kocialkowski * 53311c0d8fdSPaul Kocialkowski * +-< EXTCLK 53411c0d8fdSPaul Kocialkowski * | 53511c0d8fdSPaul Kocialkowski * +-+ pll_pre_div_half (0x312 [4]) 53611c0d8fdSPaul Kocialkowski * | 53711c0d8fdSPaul Kocialkowski * +-+ pll_pre_div (0x30b [2:0], special values: 53811c0d8fdSPaul Kocialkowski * | 0: 1, 1: 1.5, 3: 2.5, 4: 3, 5: 4, 7: 8) 53911c0d8fdSPaul Kocialkowski * +-+ pll_mul (0x30c [1:0], 0x30d [7:0]) 54011c0d8fdSPaul Kocialkowski * | 54111c0d8fdSPaul Kocialkowski * +-+ dac_div (0x312 [3:0]) 54211c0d8fdSPaul Kocialkowski * | | 54311c0d8fdSPaul Kocialkowski * | +-> DAC_CLK 54411c0d8fdSPaul Kocialkowski * | 54511c0d8fdSPaul Kocialkowski * +-+ sys_pre_div (0x30f [3:0]) 54611c0d8fdSPaul Kocialkowski * | 54711c0d8fdSPaul Kocialkowski * +-+ sys_div (0x30e [2:0], special values: 54811c0d8fdSPaul Kocialkowski * | 0: 1, 1: 1.5, 3: 2.5, 4: 3, 5: 3.5, 6: 4, 7:5) 54911c0d8fdSPaul Kocialkowski * | 55011c0d8fdSPaul Kocialkowski * +-+ sys_sel (0x3032 [7], 0: PLL1, 1: PLL2) 55111c0d8fdSPaul Kocialkowski * | 55211c0d8fdSPaul Kocialkowski * +-+ sclk_sel (0x3033 [1], 0: sys_sel, 1: PLL2 DAC_CLK) 55311c0d8fdSPaul Kocialkowski * | 55411c0d8fdSPaul Kocialkowski * +-+ sclk_pre_div (0x3106 [3:2], special values: 55511c0d8fdSPaul Kocialkowski * | 0: 1, 1: 2, 2: 4, 3: 1) 55611c0d8fdSPaul Kocialkowski * | 55711c0d8fdSPaul Kocialkowski * +-+ sclk_div (0x3106 [7:4], special values: 0: 1) 55811c0d8fdSPaul Kocialkowski * | 55911c0d8fdSPaul Kocialkowski * +-> SCLK 56011c0d8fdSPaul Kocialkowski */ 56111c0d8fdSPaul Kocialkowski 56211c0d8fdSPaul Kocialkowski struct ov8865_pll2_config { 56311c0d8fdSPaul Kocialkowski unsigned int pll_pre_div_half; 56411c0d8fdSPaul Kocialkowski unsigned int pll_pre_div; 56511c0d8fdSPaul Kocialkowski unsigned int pll_mul; 56611c0d8fdSPaul Kocialkowski unsigned int dac_div; 56711c0d8fdSPaul Kocialkowski unsigned int sys_pre_div; 56811c0d8fdSPaul Kocialkowski unsigned int sys_div; 56911c0d8fdSPaul Kocialkowski }; 57011c0d8fdSPaul Kocialkowski 57111c0d8fdSPaul Kocialkowski struct ov8865_sclk_config { 57211c0d8fdSPaul Kocialkowski unsigned int sys_sel; 57311c0d8fdSPaul Kocialkowski unsigned int sclk_sel; 57411c0d8fdSPaul Kocialkowski unsigned int sclk_pre_div; 57511c0d8fdSPaul Kocialkowski unsigned int sclk_div; 57611c0d8fdSPaul Kocialkowski }; 57711c0d8fdSPaul Kocialkowski 57873dcffebSDaniel Scally struct ov8865_pll_configs { 57973dcffebSDaniel Scally const struct ov8865_pll1_config *pll1_config; 58073dcffebSDaniel Scally const struct ov8865_pll2_config *pll2_config_native; 58173dcffebSDaniel Scally const struct ov8865_pll2_config *pll2_config_binning; 58273dcffebSDaniel Scally }; 58373dcffebSDaniel Scally 58473dcffebSDaniel Scally /* Clock rate */ 58573dcffebSDaniel Scally 58673dcffebSDaniel Scally enum extclk_rate { 58773dcffebSDaniel Scally OV8865_19_2_MHZ, 58873dcffebSDaniel Scally OV8865_24_MHZ, 58973dcffebSDaniel Scally OV8865_NUM_SUPPORTED_RATES 59073dcffebSDaniel Scally }; 59173dcffebSDaniel Scally 59273dcffebSDaniel Scally static const unsigned long supported_extclk_rates[] = { 59373dcffebSDaniel Scally [OV8865_19_2_MHZ] = 19200000, 59473dcffebSDaniel Scally [OV8865_24_MHZ] = 24000000, 59573dcffebSDaniel Scally }; 59673dcffebSDaniel Scally 59711c0d8fdSPaul Kocialkowski /* 59811c0d8fdSPaul Kocialkowski * General formulas for (array-centered) mode calculation: 59911c0d8fdSPaul Kocialkowski * - photo_array_width = 3296 60011c0d8fdSPaul Kocialkowski * - crop_start_x = (photo_array_width - output_size_x) / 2 60111c0d8fdSPaul Kocialkowski * - crop_end_x = crop_start_x + offset_x + output_size_x - 1 60211c0d8fdSPaul Kocialkowski * 60311c0d8fdSPaul Kocialkowski * - photo_array_height = 2480 60411c0d8fdSPaul Kocialkowski * - crop_start_y = (photo_array_height - output_size_y) / 2 60511c0d8fdSPaul Kocialkowski * - crop_end_y = crop_start_y + offset_y + output_size_y - 1 60611c0d8fdSPaul Kocialkowski */ 60711c0d8fdSPaul Kocialkowski 60811c0d8fdSPaul Kocialkowski struct ov8865_mode { 60911c0d8fdSPaul Kocialkowski unsigned int crop_start_x; 61011c0d8fdSPaul Kocialkowski unsigned int offset_x; 61111c0d8fdSPaul Kocialkowski unsigned int output_size_x; 61211c0d8fdSPaul Kocialkowski unsigned int crop_end_x; 61311c0d8fdSPaul Kocialkowski unsigned int hts; 61411c0d8fdSPaul Kocialkowski 61511c0d8fdSPaul Kocialkowski unsigned int crop_start_y; 61611c0d8fdSPaul Kocialkowski unsigned int offset_y; 61711c0d8fdSPaul Kocialkowski unsigned int output_size_y; 61811c0d8fdSPaul Kocialkowski unsigned int crop_end_y; 61911c0d8fdSPaul Kocialkowski unsigned int vts; 62011c0d8fdSPaul Kocialkowski 62111c0d8fdSPaul Kocialkowski /* With auto size, only output and total sizes need to be set. */ 62211c0d8fdSPaul Kocialkowski bool size_auto; 62311c0d8fdSPaul Kocialkowski unsigned int size_auto_boundary_x; 62411c0d8fdSPaul Kocialkowski unsigned int size_auto_boundary_y; 62511c0d8fdSPaul Kocialkowski 62611c0d8fdSPaul Kocialkowski bool binning_x; 62711c0d8fdSPaul Kocialkowski bool binning_y; 62811c0d8fdSPaul Kocialkowski bool variopixel; 62911c0d8fdSPaul Kocialkowski unsigned int variopixel_hsub_coef; 63011c0d8fdSPaul Kocialkowski unsigned int variopixel_vsub_coef; 63111c0d8fdSPaul Kocialkowski 63211c0d8fdSPaul Kocialkowski /* Bits for the format register, used for binning. */ 63311c0d8fdSPaul Kocialkowski bool sync_hbin; 63411c0d8fdSPaul Kocialkowski bool horz_var2; 63511c0d8fdSPaul Kocialkowski 63611c0d8fdSPaul Kocialkowski unsigned int inc_x_odd; 63711c0d8fdSPaul Kocialkowski unsigned int inc_x_even; 63811c0d8fdSPaul Kocialkowski unsigned int inc_y_odd; 63911c0d8fdSPaul Kocialkowski unsigned int inc_y_even; 64011c0d8fdSPaul Kocialkowski 64111c0d8fdSPaul Kocialkowski unsigned int vfifo_read_start; 64211c0d8fdSPaul Kocialkowski 64311c0d8fdSPaul Kocialkowski unsigned int ablc_num; 64411c0d8fdSPaul Kocialkowski unsigned int zline_num; 64511c0d8fdSPaul Kocialkowski 64611c0d8fdSPaul Kocialkowski unsigned int blc_top_zero_line_start; 64711c0d8fdSPaul Kocialkowski unsigned int blc_top_zero_line_num; 64811c0d8fdSPaul Kocialkowski unsigned int blc_top_black_line_start; 64911c0d8fdSPaul Kocialkowski unsigned int blc_top_black_line_num; 65011c0d8fdSPaul Kocialkowski 65111c0d8fdSPaul Kocialkowski unsigned int blc_bottom_zero_line_start; 65211c0d8fdSPaul Kocialkowski unsigned int blc_bottom_zero_line_num; 65311c0d8fdSPaul Kocialkowski unsigned int blc_bottom_black_line_start; 65411c0d8fdSPaul Kocialkowski unsigned int blc_bottom_black_line_num; 65511c0d8fdSPaul Kocialkowski 65611c0d8fdSPaul Kocialkowski u8 blc_col_shift_mask; 65711c0d8fdSPaul Kocialkowski 65811c0d8fdSPaul Kocialkowski unsigned int blc_anchor_left_start; 65911c0d8fdSPaul Kocialkowski unsigned int blc_anchor_left_end; 66011c0d8fdSPaul Kocialkowski unsigned int blc_anchor_right_start; 66111c0d8fdSPaul Kocialkowski unsigned int blc_anchor_right_end; 66211c0d8fdSPaul Kocialkowski 66373dcffebSDaniel Scally bool pll2_binning; 66411c0d8fdSPaul Kocialkowski 66511c0d8fdSPaul Kocialkowski const struct ov8865_register_value *register_values; 66611c0d8fdSPaul Kocialkowski unsigned int register_values_count; 66711c0d8fdSPaul Kocialkowski }; 66811c0d8fdSPaul Kocialkowski 66911c0d8fdSPaul Kocialkowski struct ov8865_state { 67011c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode; 67111c0d8fdSPaul Kocialkowski u32 mbus_code; 67211c0d8fdSPaul Kocialkowski 67311c0d8fdSPaul Kocialkowski bool streaming; 67411c0d8fdSPaul Kocialkowski }; 67511c0d8fdSPaul Kocialkowski 67611c0d8fdSPaul Kocialkowski struct ov8865_ctrls { 67711c0d8fdSPaul Kocialkowski struct v4l2_ctrl *link_freq; 67811c0d8fdSPaul Kocialkowski struct v4l2_ctrl *pixel_rate; 679d84d4ceeSDaniel Scally struct v4l2_ctrl *hblank; 6809293aafeSDaniel Scally struct v4l2_ctrl *vblank; 681ca28690eSDaniel Scally struct v4l2_ctrl *exposure; 68211c0d8fdSPaul Kocialkowski 68311c0d8fdSPaul Kocialkowski struct v4l2_ctrl_handler handler; 68411c0d8fdSPaul Kocialkowski }; 68511c0d8fdSPaul Kocialkowski 68611c0d8fdSPaul Kocialkowski struct ov8865_sensor { 68711c0d8fdSPaul Kocialkowski struct device *dev; 68811c0d8fdSPaul Kocialkowski struct i2c_client *i2c_client; 68911c0d8fdSPaul Kocialkowski struct gpio_desc *reset; 69011c0d8fdSPaul Kocialkowski struct gpio_desc *powerdown; 69111c0d8fdSPaul Kocialkowski struct regulator *avdd; 69211c0d8fdSPaul Kocialkowski struct regulator *dvdd; 69311c0d8fdSPaul Kocialkowski struct regulator *dovdd; 69473dcffebSDaniel Scally 69573dcffebSDaniel Scally unsigned long extclk_rate; 69673dcffebSDaniel Scally const struct ov8865_pll_configs *pll_configs; 69711c0d8fdSPaul Kocialkowski struct clk *extclk; 69811c0d8fdSPaul Kocialkowski 69911c0d8fdSPaul Kocialkowski struct v4l2_fwnode_endpoint endpoint; 70011c0d8fdSPaul Kocialkowski struct v4l2_subdev subdev; 70111c0d8fdSPaul Kocialkowski struct media_pad pad; 70211c0d8fdSPaul Kocialkowski 70311c0d8fdSPaul Kocialkowski struct mutex mutex; 70411c0d8fdSPaul Kocialkowski 70511c0d8fdSPaul Kocialkowski struct ov8865_state state; 70611c0d8fdSPaul Kocialkowski struct ov8865_ctrls ctrls; 70711c0d8fdSPaul Kocialkowski }; 70811c0d8fdSPaul Kocialkowski 70911c0d8fdSPaul Kocialkowski /* Static definitions */ 71011c0d8fdSPaul Kocialkowski 71111c0d8fdSPaul Kocialkowski /* 71211c0d8fdSPaul Kocialkowski * PHY_SCLK = 720 MHz 71311c0d8fdSPaul Kocialkowski * MIPI_PCLK = 90 MHz 71411c0d8fdSPaul Kocialkowski */ 71573dcffebSDaniel Scally 71673dcffebSDaniel Scally static const struct ov8865_pll1_config ov8865_pll1_config_native_19_2mhz = { 71773dcffebSDaniel Scally .pll_pre_div_half = 1, 71873dcffebSDaniel Scally .pll_pre_div = 2, 71973dcffebSDaniel Scally .pll_mul = 75, 72073dcffebSDaniel Scally .m_div = 1, 72173dcffebSDaniel Scally .mipi_div = 3, 72273dcffebSDaniel Scally .pclk_div = 1, 72373dcffebSDaniel Scally .sys_pre_div = 1, 72473dcffebSDaniel Scally .sys_div = 2, 72573dcffebSDaniel Scally }; 72673dcffebSDaniel Scally 72773dcffebSDaniel Scally static const struct ov8865_pll1_config ov8865_pll1_config_native_24mhz = { 72811c0d8fdSPaul Kocialkowski .pll_pre_div_half = 1, 72911c0d8fdSPaul Kocialkowski .pll_pre_div = 0, 73011c0d8fdSPaul Kocialkowski .pll_mul = 30, 73111c0d8fdSPaul Kocialkowski .m_div = 1, 73211c0d8fdSPaul Kocialkowski .mipi_div = 3, 73311c0d8fdSPaul Kocialkowski .pclk_div = 1, 73411c0d8fdSPaul Kocialkowski .sys_pre_div = 1, 73511c0d8fdSPaul Kocialkowski .sys_div = 2, 73611c0d8fdSPaul Kocialkowski }; 73711c0d8fdSPaul Kocialkowski 73811c0d8fdSPaul Kocialkowski /* 73911c0d8fdSPaul Kocialkowski * DAC_CLK = 360 MHz 74011c0d8fdSPaul Kocialkowski * SCLK = 144 MHz 74111c0d8fdSPaul Kocialkowski */ 74211c0d8fdSPaul Kocialkowski 74373dcffebSDaniel Scally static const struct ov8865_pll2_config ov8865_pll2_config_native_19_2mhz = { 74473dcffebSDaniel Scally .pll_pre_div_half = 1, 74573dcffebSDaniel Scally .pll_pre_div = 5, 74673dcffebSDaniel Scally .pll_mul = 75, 74773dcffebSDaniel Scally .dac_div = 1, 74873dcffebSDaniel Scally .sys_pre_div = 1, 74973dcffebSDaniel Scally .sys_div = 3, 75073dcffebSDaniel Scally }; 75173dcffebSDaniel Scally 75273dcffebSDaniel Scally static const struct ov8865_pll2_config ov8865_pll2_config_native_24mhz = { 75311c0d8fdSPaul Kocialkowski .pll_pre_div_half = 1, 75411c0d8fdSPaul Kocialkowski .pll_pre_div = 0, 75511c0d8fdSPaul Kocialkowski .pll_mul = 30, 75611c0d8fdSPaul Kocialkowski .dac_div = 2, 75711c0d8fdSPaul Kocialkowski .sys_pre_div = 5, 75811c0d8fdSPaul Kocialkowski .sys_div = 0, 75911c0d8fdSPaul Kocialkowski }; 76011c0d8fdSPaul Kocialkowski 76111c0d8fdSPaul Kocialkowski /* 76211c0d8fdSPaul Kocialkowski * DAC_CLK = 360 MHz 763651d1f20SDaniel Scally * SCLK = 72 MHz 76411c0d8fdSPaul Kocialkowski */ 76511c0d8fdSPaul Kocialkowski 76673dcffebSDaniel Scally static const struct ov8865_pll2_config ov8865_pll2_config_binning_19_2mhz = { 76773dcffebSDaniel Scally .pll_pre_div_half = 1, 76873dcffebSDaniel Scally .pll_pre_div = 2, 76973dcffebSDaniel Scally .pll_mul = 75, 77073dcffebSDaniel Scally .dac_div = 2, 77173dcffebSDaniel Scally .sys_pre_div = 10, 77273dcffebSDaniel Scally .sys_div = 0, 77373dcffebSDaniel Scally }; 77473dcffebSDaniel Scally 77573dcffebSDaniel Scally static const struct ov8865_pll2_config ov8865_pll2_config_binning_24mhz = { 77611c0d8fdSPaul Kocialkowski .pll_pre_div_half = 1, 77711c0d8fdSPaul Kocialkowski .pll_pre_div = 0, 77811c0d8fdSPaul Kocialkowski .pll_mul = 30, 77911c0d8fdSPaul Kocialkowski .dac_div = 2, 78011c0d8fdSPaul Kocialkowski .sys_pre_div = 10, 78111c0d8fdSPaul Kocialkowski .sys_div = 0, 78211c0d8fdSPaul Kocialkowski }; 78311c0d8fdSPaul Kocialkowski 78473dcffebSDaniel Scally static const struct ov8865_pll_configs ov8865_pll_configs_19_2mhz = { 78573dcffebSDaniel Scally .pll1_config = &ov8865_pll1_config_native_19_2mhz, 78673dcffebSDaniel Scally .pll2_config_native = &ov8865_pll2_config_native_19_2mhz, 78773dcffebSDaniel Scally .pll2_config_binning = &ov8865_pll2_config_binning_19_2mhz, 78873dcffebSDaniel Scally }; 78973dcffebSDaniel Scally 79073dcffebSDaniel Scally static const struct ov8865_pll_configs ov8865_pll_configs_24mhz = { 79173dcffebSDaniel Scally .pll1_config = &ov8865_pll1_config_native_24mhz, 79273dcffebSDaniel Scally .pll2_config_native = &ov8865_pll2_config_native_24mhz, 79373dcffebSDaniel Scally .pll2_config_binning = &ov8865_pll2_config_binning_24mhz, 79473dcffebSDaniel Scally }; 79573dcffebSDaniel Scally 79673dcffebSDaniel Scally static const struct ov8865_pll_configs *ov8865_pll_configs[] = { 79773dcffebSDaniel Scally &ov8865_pll_configs_19_2mhz, 79873dcffebSDaniel Scally &ov8865_pll_configs_24mhz, 79973dcffebSDaniel Scally }; 80073dcffebSDaniel Scally 80111c0d8fdSPaul Kocialkowski static const struct ov8865_sclk_config ov8865_sclk_config_native = { 80211c0d8fdSPaul Kocialkowski .sys_sel = 1, 80311c0d8fdSPaul Kocialkowski .sclk_sel = 0, 80411c0d8fdSPaul Kocialkowski .sclk_pre_div = 0, 80511c0d8fdSPaul Kocialkowski .sclk_div = 0, 80611c0d8fdSPaul Kocialkowski }; 80711c0d8fdSPaul Kocialkowski 80811c0d8fdSPaul Kocialkowski static const struct ov8865_register_value ov8865_register_values_native[] = { 80911c0d8fdSPaul Kocialkowski /* Sensor */ 81011c0d8fdSPaul Kocialkowski 81111c0d8fdSPaul Kocialkowski { 0x3700, 0x48 }, 81211c0d8fdSPaul Kocialkowski { 0x3701, 0x18 }, 81311c0d8fdSPaul Kocialkowski { 0x3702, 0x50 }, 81411c0d8fdSPaul Kocialkowski { 0x3703, 0x32 }, 81511c0d8fdSPaul Kocialkowski { 0x3704, 0x28 }, 81611c0d8fdSPaul Kocialkowski { 0x3706, 0x70 }, 81711c0d8fdSPaul Kocialkowski { 0x3707, 0x08 }, 81811c0d8fdSPaul Kocialkowski { 0x3708, 0x48 }, 81911c0d8fdSPaul Kocialkowski { 0x3709, 0x80 }, 82011c0d8fdSPaul Kocialkowski { 0x370a, 0x01 }, 82111c0d8fdSPaul Kocialkowski { 0x370b, 0x70 }, 82211c0d8fdSPaul Kocialkowski { 0x370c, 0x07 }, 82311c0d8fdSPaul Kocialkowski { 0x3718, 0x14 }, 82411c0d8fdSPaul Kocialkowski { 0x3712, 0x44 }, 82511c0d8fdSPaul Kocialkowski { 0x371e, 0x31 }, 82611c0d8fdSPaul Kocialkowski { 0x371f, 0x7f }, 82711c0d8fdSPaul Kocialkowski { 0x3720, 0x0a }, 82811c0d8fdSPaul Kocialkowski { 0x3721, 0x0a }, 82911c0d8fdSPaul Kocialkowski { 0x3724, 0x04 }, 83011c0d8fdSPaul Kocialkowski { 0x3725, 0x04 }, 83111c0d8fdSPaul Kocialkowski { 0x3726, 0x0c }, 83211c0d8fdSPaul Kocialkowski { 0x3728, 0x0a }, 83311c0d8fdSPaul Kocialkowski { 0x3729, 0x03 }, 83411c0d8fdSPaul Kocialkowski { 0x372a, 0x06 }, 83511c0d8fdSPaul Kocialkowski { 0x372b, 0xa6 }, 83611c0d8fdSPaul Kocialkowski { 0x372c, 0xa6 }, 83711c0d8fdSPaul Kocialkowski { 0x372d, 0xa6 }, 83811c0d8fdSPaul Kocialkowski { 0x372e, 0x0c }, 83911c0d8fdSPaul Kocialkowski { 0x372f, 0x20 }, 84011c0d8fdSPaul Kocialkowski { 0x3730, 0x02 }, 84111c0d8fdSPaul Kocialkowski { 0x3731, 0x0c }, 84211c0d8fdSPaul Kocialkowski { 0x3732, 0x28 }, 84311c0d8fdSPaul Kocialkowski { 0x3736, 0x30 }, 84411c0d8fdSPaul Kocialkowski { 0x373a, 0x04 }, 84511c0d8fdSPaul Kocialkowski { 0x373b, 0x18 }, 84611c0d8fdSPaul Kocialkowski { 0x373c, 0x14 }, 84711c0d8fdSPaul Kocialkowski { 0x373e, 0x06 }, 84811c0d8fdSPaul Kocialkowski { 0x375a, 0x0c }, 84911c0d8fdSPaul Kocialkowski { 0x375b, 0x26 }, 85011c0d8fdSPaul Kocialkowski { 0x375d, 0x04 }, 85111c0d8fdSPaul Kocialkowski { 0x375f, 0x28 }, 85211c0d8fdSPaul Kocialkowski { 0x3767, 0x1e }, 85311c0d8fdSPaul Kocialkowski { 0x3772, 0x46 }, 85411c0d8fdSPaul Kocialkowski { 0x3773, 0x04 }, 85511c0d8fdSPaul Kocialkowski { 0x3774, 0x2c }, 85611c0d8fdSPaul Kocialkowski { 0x3775, 0x13 }, 85711c0d8fdSPaul Kocialkowski { 0x3776, 0x10 }, 85811c0d8fdSPaul Kocialkowski { 0x37a0, 0x88 }, 85911c0d8fdSPaul Kocialkowski { 0x37a1, 0x7a }, 86011c0d8fdSPaul Kocialkowski { 0x37a2, 0x7a }, 86111c0d8fdSPaul Kocialkowski { 0x37a3, 0x02 }, 86211c0d8fdSPaul Kocialkowski { 0x37a5, 0x09 }, 86311c0d8fdSPaul Kocialkowski { 0x37a7, 0x88 }, 86411c0d8fdSPaul Kocialkowski { 0x37a8, 0xb0 }, 86511c0d8fdSPaul Kocialkowski { 0x37a9, 0xb0 }, 86611c0d8fdSPaul Kocialkowski { 0x37aa, 0x88 }, 86711c0d8fdSPaul Kocialkowski { 0x37ab, 0x5c }, 86811c0d8fdSPaul Kocialkowski { 0x37ac, 0x5c }, 86911c0d8fdSPaul Kocialkowski { 0x37ad, 0x55 }, 87011c0d8fdSPaul Kocialkowski { 0x37ae, 0x19 }, 87111c0d8fdSPaul Kocialkowski { 0x37af, 0x19 }, 87211c0d8fdSPaul Kocialkowski { 0x37b3, 0x84 }, 87311c0d8fdSPaul Kocialkowski { 0x37b4, 0x84 }, 87411c0d8fdSPaul Kocialkowski { 0x37b5, 0x66 }, 87511c0d8fdSPaul Kocialkowski 87611c0d8fdSPaul Kocialkowski /* PSRAM */ 87711c0d8fdSPaul Kocialkowski 87811c0d8fdSPaul Kocialkowski { OV8865_PSRAM_CTRL8_REG, 0x16 }, 87911c0d8fdSPaul Kocialkowski 88011c0d8fdSPaul Kocialkowski /* ADC Sync */ 88111c0d8fdSPaul Kocialkowski 88211c0d8fdSPaul Kocialkowski { 0x4500, 0x68 }, 88311c0d8fdSPaul Kocialkowski }; 88411c0d8fdSPaul Kocialkowski 88511c0d8fdSPaul Kocialkowski static const struct ov8865_register_value ov8865_register_values_binning[] = { 88611c0d8fdSPaul Kocialkowski /* Sensor */ 88711c0d8fdSPaul Kocialkowski 88811c0d8fdSPaul Kocialkowski { 0x3700, 0x24 }, 88911c0d8fdSPaul Kocialkowski { 0x3701, 0x0c }, 89011c0d8fdSPaul Kocialkowski { 0x3702, 0x28 }, 89111c0d8fdSPaul Kocialkowski { 0x3703, 0x19 }, 89211c0d8fdSPaul Kocialkowski { 0x3704, 0x14 }, 89311c0d8fdSPaul Kocialkowski { 0x3706, 0x38 }, 89411c0d8fdSPaul Kocialkowski { 0x3707, 0x04 }, 89511c0d8fdSPaul Kocialkowski { 0x3708, 0x24 }, 89611c0d8fdSPaul Kocialkowski { 0x3709, 0x40 }, 89711c0d8fdSPaul Kocialkowski { 0x370a, 0x00 }, 89811c0d8fdSPaul Kocialkowski { 0x370b, 0xb8 }, 89911c0d8fdSPaul Kocialkowski { 0x370c, 0x04 }, 90011c0d8fdSPaul Kocialkowski { 0x3718, 0x12 }, 90111c0d8fdSPaul Kocialkowski { 0x3712, 0x42 }, 90211c0d8fdSPaul Kocialkowski { 0x371e, 0x19 }, 90311c0d8fdSPaul Kocialkowski { 0x371f, 0x40 }, 90411c0d8fdSPaul Kocialkowski { 0x3720, 0x05 }, 90511c0d8fdSPaul Kocialkowski { 0x3721, 0x05 }, 90611c0d8fdSPaul Kocialkowski { 0x3724, 0x02 }, 90711c0d8fdSPaul Kocialkowski { 0x3725, 0x02 }, 90811c0d8fdSPaul Kocialkowski { 0x3726, 0x06 }, 90911c0d8fdSPaul Kocialkowski { 0x3728, 0x05 }, 91011c0d8fdSPaul Kocialkowski { 0x3729, 0x02 }, 91111c0d8fdSPaul Kocialkowski { 0x372a, 0x03 }, 91211c0d8fdSPaul Kocialkowski { 0x372b, 0x53 }, 91311c0d8fdSPaul Kocialkowski { 0x372c, 0xa3 }, 91411c0d8fdSPaul Kocialkowski { 0x372d, 0x53 }, 91511c0d8fdSPaul Kocialkowski { 0x372e, 0x06 }, 91611c0d8fdSPaul Kocialkowski { 0x372f, 0x10 }, 91711c0d8fdSPaul Kocialkowski { 0x3730, 0x01 }, 91811c0d8fdSPaul Kocialkowski { 0x3731, 0x06 }, 91911c0d8fdSPaul Kocialkowski { 0x3732, 0x14 }, 92011c0d8fdSPaul Kocialkowski { 0x3736, 0x20 }, 92111c0d8fdSPaul Kocialkowski { 0x373a, 0x02 }, 92211c0d8fdSPaul Kocialkowski { 0x373b, 0x0c }, 92311c0d8fdSPaul Kocialkowski { 0x373c, 0x0a }, 92411c0d8fdSPaul Kocialkowski { 0x373e, 0x03 }, 92511c0d8fdSPaul Kocialkowski { 0x375a, 0x06 }, 92611c0d8fdSPaul Kocialkowski { 0x375b, 0x13 }, 92711c0d8fdSPaul Kocialkowski { 0x375d, 0x02 }, 92811c0d8fdSPaul Kocialkowski { 0x375f, 0x14 }, 92911c0d8fdSPaul Kocialkowski { 0x3767, 0x1c }, 93011c0d8fdSPaul Kocialkowski { 0x3772, 0x23 }, 93111c0d8fdSPaul Kocialkowski { 0x3773, 0x02 }, 93211c0d8fdSPaul Kocialkowski { 0x3774, 0x16 }, 93311c0d8fdSPaul Kocialkowski { 0x3775, 0x12 }, 93411c0d8fdSPaul Kocialkowski { 0x3776, 0x08 }, 93511c0d8fdSPaul Kocialkowski { 0x37a0, 0x44 }, 93611c0d8fdSPaul Kocialkowski { 0x37a1, 0x3d }, 93711c0d8fdSPaul Kocialkowski { 0x37a2, 0x3d }, 93811c0d8fdSPaul Kocialkowski { 0x37a3, 0x01 }, 93911c0d8fdSPaul Kocialkowski { 0x37a5, 0x08 }, 94011c0d8fdSPaul Kocialkowski { 0x37a7, 0x44 }, 94111c0d8fdSPaul Kocialkowski { 0x37a8, 0x58 }, 94211c0d8fdSPaul Kocialkowski { 0x37a9, 0x58 }, 94311c0d8fdSPaul Kocialkowski { 0x37aa, 0x44 }, 94411c0d8fdSPaul Kocialkowski { 0x37ab, 0x2e }, 94511c0d8fdSPaul Kocialkowski { 0x37ac, 0x2e }, 94611c0d8fdSPaul Kocialkowski { 0x37ad, 0x33 }, 94711c0d8fdSPaul Kocialkowski { 0x37ae, 0x0d }, 94811c0d8fdSPaul Kocialkowski { 0x37af, 0x0d }, 94911c0d8fdSPaul Kocialkowski { 0x37b3, 0x42 }, 95011c0d8fdSPaul Kocialkowski { 0x37b4, 0x42 }, 95111c0d8fdSPaul Kocialkowski { 0x37b5, 0x33 }, 95211c0d8fdSPaul Kocialkowski 95311c0d8fdSPaul Kocialkowski /* PSRAM */ 95411c0d8fdSPaul Kocialkowski 95511c0d8fdSPaul Kocialkowski { OV8865_PSRAM_CTRL8_REG, 0x0b }, 95611c0d8fdSPaul Kocialkowski 95711c0d8fdSPaul Kocialkowski /* ADC Sync */ 95811c0d8fdSPaul Kocialkowski 95911c0d8fdSPaul Kocialkowski { 0x4500, 0x40 }, 96011c0d8fdSPaul Kocialkowski }; 96111c0d8fdSPaul Kocialkowski 96211c0d8fdSPaul Kocialkowski static const struct ov8865_mode ov8865_modes[] = { 96311c0d8fdSPaul Kocialkowski /* 3264x2448 */ 96411c0d8fdSPaul Kocialkowski { 96511c0d8fdSPaul Kocialkowski /* Horizontal */ 96611c0d8fdSPaul Kocialkowski .output_size_x = 3264, 967295786e5SDaniel Scally .hts = 3888, 96811c0d8fdSPaul Kocialkowski 96911c0d8fdSPaul Kocialkowski /* Vertical */ 97011c0d8fdSPaul Kocialkowski .output_size_y = 2448, 97111c0d8fdSPaul Kocialkowski .vts = 2470, 97211c0d8fdSPaul Kocialkowski 97311c0d8fdSPaul Kocialkowski .size_auto = true, 97411c0d8fdSPaul Kocialkowski .size_auto_boundary_x = 8, 97511c0d8fdSPaul Kocialkowski .size_auto_boundary_y = 4, 97611c0d8fdSPaul Kocialkowski 97711c0d8fdSPaul Kocialkowski /* Subsample increase */ 97811c0d8fdSPaul Kocialkowski .inc_x_odd = 1, 97911c0d8fdSPaul Kocialkowski .inc_x_even = 1, 98011c0d8fdSPaul Kocialkowski .inc_y_odd = 1, 98111c0d8fdSPaul Kocialkowski .inc_y_even = 1, 98211c0d8fdSPaul Kocialkowski 98311c0d8fdSPaul Kocialkowski /* VFIFO */ 98411c0d8fdSPaul Kocialkowski .vfifo_read_start = 16, 98511c0d8fdSPaul Kocialkowski 98611c0d8fdSPaul Kocialkowski .ablc_num = 4, 98711c0d8fdSPaul Kocialkowski .zline_num = 1, 98811c0d8fdSPaul Kocialkowski 98911c0d8fdSPaul Kocialkowski /* Black Level */ 99011c0d8fdSPaul Kocialkowski 99111c0d8fdSPaul Kocialkowski .blc_top_zero_line_start = 0, 99211c0d8fdSPaul Kocialkowski .blc_top_zero_line_num = 2, 99311c0d8fdSPaul Kocialkowski .blc_top_black_line_start = 4, 99411c0d8fdSPaul Kocialkowski .blc_top_black_line_num = 4, 99511c0d8fdSPaul Kocialkowski 99611c0d8fdSPaul Kocialkowski .blc_bottom_zero_line_start = 2, 99711c0d8fdSPaul Kocialkowski .blc_bottom_zero_line_num = 2, 99811c0d8fdSPaul Kocialkowski .blc_bottom_black_line_start = 8, 99911c0d8fdSPaul Kocialkowski .blc_bottom_black_line_num = 2, 100011c0d8fdSPaul Kocialkowski 100111c0d8fdSPaul Kocialkowski .blc_anchor_left_start = 576, 100211c0d8fdSPaul Kocialkowski .blc_anchor_left_end = 831, 100311c0d8fdSPaul Kocialkowski .blc_anchor_right_start = 1984, 100411c0d8fdSPaul Kocialkowski .blc_anchor_right_end = 2239, 100511c0d8fdSPaul Kocialkowski 100611c0d8fdSPaul Kocialkowski /* PLL */ 100773dcffebSDaniel Scally .pll2_binning = false, 100811c0d8fdSPaul Kocialkowski 100911c0d8fdSPaul Kocialkowski /* Registers */ 101011c0d8fdSPaul Kocialkowski .register_values = ov8865_register_values_native, 101111c0d8fdSPaul Kocialkowski .register_values_count = 101211c0d8fdSPaul Kocialkowski ARRAY_SIZE(ov8865_register_values_native), 101311c0d8fdSPaul Kocialkowski }, 101411c0d8fdSPaul Kocialkowski /* 3264x1836 */ 101511c0d8fdSPaul Kocialkowski { 101611c0d8fdSPaul Kocialkowski /* Horizontal */ 101711c0d8fdSPaul Kocialkowski .output_size_x = 3264, 1018295786e5SDaniel Scally .hts = 3888, 101911c0d8fdSPaul Kocialkowski 102011c0d8fdSPaul Kocialkowski /* Vertical */ 102111c0d8fdSPaul Kocialkowski .output_size_y = 1836, 1022295786e5SDaniel Scally .vts = 2470, 102311c0d8fdSPaul Kocialkowski 102411c0d8fdSPaul Kocialkowski .size_auto = true, 102511c0d8fdSPaul Kocialkowski .size_auto_boundary_x = 8, 102611c0d8fdSPaul Kocialkowski .size_auto_boundary_y = 4, 102711c0d8fdSPaul Kocialkowski 102811c0d8fdSPaul Kocialkowski /* Subsample increase */ 102911c0d8fdSPaul Kocialkowski .inc_x_odd = 1, 103011c0d8fdSPaul Kocialkowski .inc_x_even = 1, 103111c0d8fdSPaul Kocialkowski .inc_y_odd = 1, 103211c0d8fdSPaul Kocialkowski .inc_y_even = 1, 103311c0d8fdSPaul Kocialkowski 103411c0d8fdSPaul Kocialkowski /* VFIFO */ 103511c0d8fdSPaul Kocialkowski .vfifo_read_start = 16, 103611c0d8fdSPaul Kocialkowski 103711c0d8fdSPaul Kocialkowski .ablc_num = 4, 103811c0d8fdSPaul Kocialkowski .zline_num = 1, 103911c0d8fdSPaul Kocialkowski 104011c0d8fdSPaul Kocialkowski /* Black Level */ 104111c0d8fdSPaul Kocialkowski 104211c0d8fdSPaul Kocialkowski .blc_top_zero_line_start = 0, 104311c0d8fdSPaul Kocialkowski .blc_top_zero_line_num = 2, 104411c0d8fdSPaul Kocialkowski .blc_top_black_line_start = 4, 104511c0d8fdSPaul Kocialkowski .blc_top_black_line_num = 4, 104611c0d8fdSPaul Kocialkowski 104711c0d8fdSPaul Kocialkowski .blc_bottom_zero_line_start = 2, 104811c0d8fdSPaul Kocialkowski .blc_bottom_zero_line_num = 2, 104911c0d8fdSPaul Kocialkowski .blc_bottom_black_line_start = 8, 105011c0d8fdSPaul Kocialkowski .blc_bottom_black_line_num = 2, 105111c0d8fdSPaul Kocialkowski 105211c0d8fdSPaul Kocialkowski .blc_anchor_left_start = 576, 105311c0d8fdSPaul Kocialkowski .blc_anchor_left_end = 831, 105411c0d8fdSPaul Kocialkowski .blc_anchor_right_start = 1984, 105511c0d8fdSPaul Kocialkowski .blc_anchor_right_end = 2239, 105611c0d8fdSPaul Kocialkowski 105711c0d8fdSPaul Kocialkowski /* PLL */ 105873dcffebSDaniel Scally .pll2_binning = false, 105911c0d8fdSPaul Kocialkowski 106011c0d8fdSPaul Kocialkowski /* Registers */ 106111c0d8fdSPaul Kocialkowski .register_values = ov8865_register_values_native, 106211c0d8fdSPaul Kocialkowski .register_values_count = 106311c0d8fdSPaul Kocialkowski ARRAY_SIZE(ov8865_register_values_native), 106411c0d8fdSPaul Kocialkowski }, 106511c0d8fdSPaul Kocialkowski /* 1632x1224 */ 106611c0d8fdSPaul Kocialkowski { 106711c0d8fdSPaul Kocialkowski /* Horizontal */ 106811c0d8fdSPaul Kocialkowski .output_size_x = 1632, 106911c0d8fdSPaul Kocialkowski .hts = 1923, 107011c0d8fdSPaul Kocialkowski 107111c0d8fdSPaul Kocialkowski /* Vertical */ 107211c0d8fdSPaul Kocialkowski .output_size_y = 1224, 107311c0d8fdSPaul Kocialkowski .vts = 1248, 107411c0d8fdSPaul Kocialkowski 107511c0d8fdSPaul Kocialkowski .size_auto = true, 107611c0d8fdSPaul Kocialkowski .size_auto_boundary_x = 8, 107711c0d8fdSPaul Kocialkowski .size_auto_boundary_y = 8, 107811c0d8fdSPaul Kocialkowski 107911c0d8fdSPaul Kocialkowski /* Subsample increase */ 108011c0d8fdSPaul Kocialkowski .inc_x_odd = 3, 108111c0d8fdSPaul Kocialkowski .inc_x_even = 1, 108211c0d8fdSPaul Kocialkowski .inc_y_odd = 3, 108311c0d8fdSPaul Kocialkowski .inc_y_even = 1, 108411c0d8fdSPaul Kocialkowski 108511c0d8fdSPaul Kocialkowski /* Binning */ 108611c0d8fdSPaul Kocialkowski .binning_y = true, 108711c0d8fdSPaul Kocialkowski .sync_hbin = true, 108811c0d8fdSPaul Kocialkowski 108911c0d8fdSPaul Kocialkowski /* VFIFO */ 109011c0d8fdSPaul Kocialkowski .vfifo_read_start = 116, 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 = 4, 110011c0d8fdSPaul Kocialkowski .blc_top_black_line_num = 4, 110111c0d8fdSPaul Kocialkowski 110211c0d8fdSPaul Kocialkowski .blc_bottom_zero_line_start = 2, 110311c0d8fdSPaul Kocialkowski .blc_bottom_zero_line_num = 2, 110411c0d8fdSPaul Kocialkowski .blc_bottom_black_line_start = 8, 110511c0d8fdSPaul Kocialkowski .blc_bottom_black_line_num = 2, 110611c0d8fdSPaul Kocialkowski 110711c0d8fdSPaul Kocialkowski .blc_anchor_left_start = 288, 110811c0d8fdSPaul Kocialkowski .blc_anchor_left_end = 415, 110911c0d8fdSPaul Kocialkowski .blc_anchor_right_start = 992, 111011c0d8fdSPaul Kocialkowski .blc_anchor_right_end = 1119, 111111c0d8fdSPaul Kocialkowski 111211c0d8fdSPaul Kocialkowski /* PLL */ 111373dcffebSDaniel Scally .pll2_binning = true, 111411c0d8fdSPaul Kocialkowski 111511c0d8fdSPaul Kocialkowski /* Registers */ 111611c0d8fdSPaul Kocialkowski .register_values = ov8865_register_values_binning, 111711c0d8fdSPaul Kocialkowski .register_values_count = 111811c0d8fdSPaul Kocialkowski ARRAY_SIZE(ov8865_register_values_binning), 111911c0d8fdSPaul Kocialkowski }, 112011c0d8fdSPaul Kocialkowski /* 800x600 (SVGA) */ 112111c0d8fdSPaul Kocialkowski { 112211c0d8fdSPaul Kocialkowski /* Horizontal */ 112311c0d8fdSPaul Kocialkowski .output_size_x = 800, 112411c0d8fdSPaul Kocialkowski .hts = 1250, 112511c0d8fdSPaul Kocialkowski 112611c0d8fdSPaul Kocialkowski /* Vertical */ 112711c0d8fdSPaul Kocialkowski .output_size_y = 600, 112811c0d8fdSPaul Kocialkowski .vts = 640, 112911c0d8fdSPaul Kocialkowski 113011c0d8fdSPaul Kocialkowski .size_auto = true, 113111c0d8fdSPaul Kocialkowski .size_auto_boundary_x = 8, 113211c0d8fdSPaul Kocialkowski .size_auto_boundary_y = 8, 113311c0d8fdSPaul Kocialkowski 113411c0d8fdSPaul Kocialkowski /* Subsample increase */ 113511c0d8fdSPaul Kocialkowski .inc_x_odd = 3, 113611c0d8fdSPaul Kocialkowski .inc_x_even = 1, 113711c0d8fdSPaul Kocialkowski .inc_y_odd = 5, 113811c0d8fdSPaul Kocialkowski .inc_y_even = 3, 113911c0d8fdSPaul Kocialkowski 114011c0d8fdSPaul Kocialkowski /* Binning */ 114111c0d8fdSPaul Kocialkowski .binning_y = true, 114211c0d8fdSPaul Kocialkowski .variopixel = true, 114311c0d8fdSPaul Kocialkowski .variopixel_hsub_coef = 2, 114411c0d8fdSPaul Kocialkowski .variopixel_vsub_coef = 1, 114511c0d8fdSPaul Kocialkowski .sync_hbin = true, 114611c0d8fdSPaul Kocialkowski .horz_var2 = true, 114711c0d8fdSPaul Kocialkowski 114811c0d8fdSPaul Kocialkowski /* VFIFO */ 114911c0d8fdSPaul Kocialkowski .vfifo_read_start = 80, 115011c0d8fdSPaul Kocialkowski 115111c0d8fdSPaul Kocialkowski .ablc_num = 8, 115211c0d8fdSPaul Kocialkowski .zline_num = 2, 115311c0d8fdSPaul Kocialkowski 115411c0d8fdSPaul Kocialkowski /* Black Level */ 115511c0d8fdSPaul Kocialkowski 115611c0d8fdSPaul Kocialkowski .blc_top_zero_line_start = 0, 115711c0d8fdSPaul Kocialkowski .blc_top_zero_line_num = 2, 115811c0d8fdSPaul Kocialkowski .blc_top_black_line_start = 2, 115911c0d8fdSPaul Kocialkowski .blc_top_black_line_num = 2, 116011c0d8fdSPaul Kocialkowski 116111c0d8fdSPaul Kocialkowski .blc_bottom_zero_line_start = 0, 116211c0d8fdSPaul Kocialkowski .blc_bottom_zero_line_num = 0, 116311c0d8fdSPaul Kocialkowski .blc_bottom_black_line_start = 4, 116411c0d8fdSPaul Kocialkowski .blc_bottom_black_line_num = 2, 116511c0d8fdSPaul Kocialkowski 116611c0d8fdSPaul Kocialkowski .blc_col_shift_mask = OV8865_BLC_CTRL1_COL_SHIFT_128, 116711c0d8fdSPaul Kocialkowski 116811c0d8fdSPaul Kocialkowski .blc_anchor_left_start = 288, 116911c0d8fdSPaul Kocialkowski .blc_anchor_left_end = 415, 117011c0d8fdSPaul Kocialkowski .blc_anchor_right_start = 992, 117111c0d8fdSPaul Kocialkowski .blc_anchor_right_end = 1119, 117211c0d8fdSPaul Kocialkowski 117311c0d8fdSPaul Kocialkowski /* PLL */ 117473dcffebSDaniel Scally .pll2_binning = true, 117511c0d8fdSPaul Kocialkowski 117611c0d8fdSPaul Kocialkowski /* Registers */ 117711c0d8fdSPaul Kocialkowski .register_values = ov8865_register_values_binning, 117811c0d8fdSPaul Kocialkowski .register_values_count = 117911c0d8fdSPaul Kocialkowski ARRAY_SIZE(ov8865_register_values_binning), 118011c0d8fdSPaul Kocialkowski }, 118111c0d8fdSPaul Kocialkowski }; 118211c0d8fdSPaul Kocialkowski 118311c0d8fdSPaul Kocialkowski static const u32 ov8865_mbus_codes[] = { 118411c0d8fdSPaul Kocialkowski MEDIA_BUS_FMT_SBGGR10_1X10, 118511c0d8fdSPaul Kocialkowski }; 118611c0d8fdSPaul Kocialkowski 118711c0d8fdSPaul Kocialkowski static const struct ov8865_register_value ov8865_init_sequence[] = { 118811c0d8fdSPaul Kocialkowski /* Analog */ 118911c0d8fdSPaul Kocialkowski 119011c0d8fdSPaul Kocialkowski { 0x3604, 0x04 }, 119111c0d8fdSPaul Kocialkowski { 0x3602, 0x30 }, 119211c0d8fdSPaul Kocialkowski { 0x3605, 0x00 }, 119311c0d8fdSPaul Kocialkowski { 0x3607, 0x20 }, 119411c0d8fdSPaul Kocialkowski { 0x3608, 0x11 }, 119511c0d8fdSPaul Kocialkowski { 0x3609, 0x68 }, 119611c0d8fdSPaul Kocialkowski { 0x360a, 0x40 }, 119711c0d8fdSPaul Kocialkowski { 0x360c, 0xdd }, 119811c0d8fdSPaul Kocialkowski { 0x360e, 0x0c }, 119911c0d8fdSPaul Kocialkowski { 0x3610, 0x07 }, 120011c0d8fdSPaul Kocialkowski { 0x3612, 0x86 }, 120111c0d8fdSPaul Kocialkowski { 0x3613, 0x58 }, 120211c0d8fdSPaul Kocialkowski { 0x3614, 0x28 }, 120311c0d8fdSPaul Kocialkowski { 0x3617, 0x40 }, 120411c0d8fdSPaul Kocialkowski { 0x3618, 0x5a }, 120511c0d8fdSPaul Kocialkowski { 0x3619, 0x9b }, 120611c0d8fdSPaul Kocialkowski { 0x361c, 0x00 }, 120711c0d8fdSPaul Kocialkowski { 0x361d, 0x60 }, 120811c0d8fdSPaul Kocialkowski { 0x3631, 0x60 }, 120911c0d8fdSPaul Kocialkowski { 0x3633, 0x10 }, 121011c0d8fdSPaul Kocialkowski { 0x3634, 0x10 }, 121111c0d8fdSPaul Kocialkowski { 0x3635, 0x10 }, 121211c0d8fdSPaul Kocialkowski { 0x3636, 0x10 }, 121311c0d8fdSPaul Kocialkowski { 0x3638, 0xff }, 121411c0d8fdSPaul Kocialkowski { 0x3641, 0x55 }, 121511c0d8fdSPaul Kocialkowski { 0x3646, 0x86 }, 121611c0d8fdSPaul Kocialkowski { 0x3647, 0x27 }, 121711c0d8fdSPaul Kocialkowski { 0x364a, 0x1b }, 121811c0d8fdSPaul Kocialkowski 121911c0d8fdSPaul Kocialkowski /* Sensor */ 122011c0d8fdSPaul Kocialkowski 122111c0d8fdSPaul Kocialkowski { 0x3700, 0x24 }, 122211c0d8fdSPaul Kocialkowski { 0x3701, 0x0c }, 122311c0d8fdSPaul Kocialkowski { 0x3702, 0x28 }, 122411c0d8fdSPaul Kocialkowski { 0x3703, 0x19 }, 122511c0d8fdSPaul Kocialkowski { 0x3704, 0x14 }, 122611c0d8fdSPaul Kocialkowski { 0x3705, 0x00 }, 122711c0d8fdSPaul Kocialkowski { 0x3706, 0x38 }, 122811c0d8fdSPaul Kocialkowski { 0x3707, 0x04 }, 122911c0d8fdSPaul Kocialkowski { 0x3708, 0x24 }, 123011c0d8fdSPaul Kocialkowski { 0x3709, 0x40 }, 123111c0d8fdSPaul Kocialkowski { 0x370a, 0x00 }, 123211c0d8fdSPaul Kocialkowski { 0x370b, 0xb8 }, 123311c0d8fdSPaul Kocialkowski { 0x370c, 0x04 }, 123411c0d8fdSPaul Kocialkowski { 0x3718, 0x12 }, 123511c0d8fdSPaul Kocialkowski { 0x3719, 0x31 }, 123611c0d8fdSPaul Kocialkowski { 0x3712, 0x42 }, 123711c0d8fdSPaul Kocialkowski { 0x3714, 0x12 }, 123811c0d8fdSPaul Kocialkowski { 0x371e, 0x19 }, 123911c0d8fdSPaul Kocialkowski { 0x371f, 0x40 }, 124011c0d8fdSPaul Kocialkowski { 0x3720, 0x05 }, 124111c0d8fdSPaul Kocialkowski { 0x3721, 0x05 }, 124211c0d8fdSPaul Kocialkowski { 0x3724, 0x02 }, 124311c0d8fdSPaul Kocialkowski { 0x3725, 0x02 }, 124411c0d8fdSPaul Kocialkowski { 0x3726, 0x06 }, 124511c0d8fdSPaul Kocialkowski { 0x3728, 0x05 }, 124611c0d8fdSPaul Kocialkowski { 0x3729, 0x02 }, 124711c0d8fdSPaul Kocialkowski { 0x372a, 0x03 }, 124811c0d8fdSPaul Kocialkowski { 0x372b, 0x53 }, 124911c0d8fdSPaul Kocialkowski { 0x372c, 0xa3 }, 125011c0d8fdSPaul Kocialkowski { 0x372d, 0x53 }, 125111c0d8fdSPaul Kocialkowski { 0x372e, 0x06 }, 125211c0d8fdSPaul Kocialkowski { 0x372f, 0x10 }, 125311c0d8fdSPaul Kocialkowski { 0x3730, 0x01 }, 125411c0d8fdSPaul Kocialkowski { 0x3731, 0x06 }, 125511c0d8fdSPaul Kocialkowski { 0x3732, 0x14 }, 125611c0d8fdSPaul Kocialkowski { 0x3733, 0x10 }, 125711c0d8fdSPaul Kocialkowski { 0x3734, 0x40 }, 125811c0d8fdSPaul Kocialkowski { 0x3736, 0x20 }, 125911c0d8fdSPaul Kocialkowski { 0x373a, 0x02 }, 126011c0d8fdSPaul Kocialkowski { 0x373b, 0x0c }, 126111c0d8fdSPaul Kocialkowski { 0x373c, 0x0a }, 126211c0d8fdSPaul Kocialkowski { 0x373e, 0x03 }, 126311c0d8fdSPaul Kocialkowski { 0x3755, 0x40 }, 126411c0d8fdSPaul Kocialkowski { 0x3758, 0x00 }, 126511c0d8fdSPaul Kocialkowski { 0x3759, 0x4c }, 126611c0d8fdSPaul Kocialkowski { 0x375a, 0x06 }, 126711c0d8fdSPaul Kocialkowski { 0x375b, 0x13 }, 126811c0d8fdSPaul Kocialkowski { 0x375c, 0x40 }, 126911c0d8fdSPaul Kocialkowski { 0x375d, 0x02 }, 127011c0d8fdSPaul Kocialkowski { 0x375e, 0x00 }, 127111c0d8fdSPaul Kocialkowski { 0x375f, 0x14 }, 127211c0d8fdSPaul Kocialkowski { 0x3767, 0x1c }, 127311c0d8fdSPaul Kocialkowski { 0x3768, 0x04 }, 127411c0d8fdSPaul Kocialkowski { 0x3769, 0x20 }, 127511c0d8fdSPaul Kocialkowski { 0x376c, 0xc0 }, 127611c0d8fdSPaul Kocialkowski { 0x376d, 0xc0 }, 127711c0d8fdSPaul Kocialkowski { 0x376a, 0x08 }, 127811c0d8fdSPaul Kocialkowski { 0x3761, 0x00 }, 127911c0d8fdSPaul Kocialkowski { 0x3762, 0x00 }, 128011c0d8fdSPaul Kocialkowski { 0x3763, 0x00 }, 128111c0d8fdSPaul Kocialkowski { 0x3766, 0xff }, 128211c0d8fdSPaul Kocialkowski { 0x376b, 0x42 }, 128311c0d8fdSPaul Kocialkowski { 0x3772, 0x23 }, 128411c0d8fdSPaul Kocialkowski { 0x3773, 0x02 }, 128511c0d8fdSPaul Kocialkowski { 0x3774, 0x16 }, 128611c0d8fdSPaul Kocialkowski { 0x3775, 0x12 }, 128711c0d8fdSPaul Kocialkowski { 0x3776, 0x08 }, 128811c0d8fdSPaul Kocialkowski { 0x37a0, 0x44 }, 128911c0d8fdSPaul Kocialkowski { 0x37a1, 0x3d }, 129011c0d8fdSPaul Kocialkowski { 0x37a2, 0x3d }, 129111c0d8fdSPaul Kocialkowski { 0x37a3, 0x01 }, 129211c0d8fdSPaul Kocialkowski { 0x37a4, 0x00 }, 129311c0d8fdSPaul Kocialkowski { 0x37a5, 0x08 }, 129411c0d8fdSPaul Kocialkowski { 0x37a6, 0x00 }, 129511c0d8fdSPaul Kocialkowski { 0x37a7, 0x44 }, 129611c0d8fdSPaul Kocialkowski { 0x37a8, 0x58 }, 129711c0d8fdSPaul Kocialkowski { 0x37a9, 0x58 }, 129811c0d8fdSPaul Kocialkowski { 0x3760, 0x00 }, 129911c0d8fdSPaul Kocialkowski { 0x376f, 0x01 }, 130011c0d8fdSPaul Kocialkowski { 0x37aa, 0x44 }, 130111c0d8fdSPaul Kocialkowski { 0x37ab, 0x2e }, 130211c0d8fdSPaul Kocialkowski { 0x37ac, 0x2e }, 130311c0d8fdSPaul Kocialkowski { 0x37ad, 0x33 }, 130411c0d8fdSPaul Kocialkowski { 0x37ae, 0x0d }, 130511c0d8fdSPaul Kocialkowski { 0x37af, 0x0d }, 130611c0d8fdSPaul Kocialkowski { 0x37b0, 0x00 }, 130711c0d8fdSPaul Kocialkowski { 0x37b1, 0x00 }, 130811c0d8fdSPaul Kocialkowski { 0x37b2, 0x00 }, 130911c0d8fdSPaul Kocialkowski { 0x37b3, 0x42 }, 131011c0d8fdSPaul Kocialkowski { 0x37b4, 0x42 }, 131111c0d8fdSPaul Kocialkowski { 0x37b5, 0x33 }, 131211c0d8fdSPaul Kocialkowski { 0x37b6, 0x00 }, 131311c0d8fdSPaul Kocialkowski { 0x37b7, 0x00 }, 131411c0d8fdSPaul Kocialkowski { 0x37b8, 0x00 }, 131511c0d8fdSPaul Kocialkowski { 0x37b9, 0xff }, 131611c0d8fdSPaul Kocialkowski 131711c0d8fdSPaul Kocialkowski /* ADC Sync */ 131811c0d8fdSPaul Kocialkowski 131911c0d8fdSPaul Kocialkowski { 0x4503, 0x10 }, 132011c0d8fdSPaul Kocialkowski }; 132111c0d8fdSPaul Kocialkowski 132211c0d8fdSPaul Kocialkowski static const s64 ov8865_link_freq_menu[] = { 132311c0d8fdSPaul Kocialkowski 360000000, 132411c0d8fdSPaul Kocialkowski }; 132511c0d8fdSPaul Kocialkowski 132611c0d8fdSPaul Kocialkowski static const char *const ov8865_test_pattern_menu[] = { 132711c0d8fdSPaul Kocialkowski "Disabled", 132811c0d8fdSPaul Kocialkowski "Random data", 132911c0d8fdSPaul Kocialkowski "Color bars", 133011c0d8fdSPaul Kocialkowski "Color bars with rolling bar", 133111c0d8fdSPaul Kocialkowski "Color squares", 133211c0d8fdSPaul Kocialkowski "Color squares with rolling bar" 133311c0d8fdSPaul Kocialkowski }; 133411c0d8fdSPaul Kocialkowski 133511c0d8fdSPaul Kocialkowski static const u8 ov8865_test_pattern_bits[] = { 133611c0d8fdSPaul Kocialkowski 0, 133711c0d8fdSPaul Kocialkowski OV8865_PRE_CTRL0_PATTERN_EN | OV8865_PRE_CTRL0_PATTERN_RANDOM_DATA, 133811c0d8fdSPaul Kocialkowski OV8865_PRE_CTRL0_PATTERN_EN | OV8865_PRE_CTRL0_PATTERN_COLOR_BARS, 133911c0d8fdSPaul Kocialkowski OV8865_PRE_CTRL0_PATTERN_EN | OV8865_PRE_CTRL0_ROLLING_BAR_EN | 134011c0d8fdSPaul Kocialkowski OV8865_PRE_CTRL0_PATTERN_COLOR_BARS, 134111c0d8fdSPaul Kocialkowski OV8865_PRE_CTRL0_PATTERN_EN | OV8865_PRE_CTRL0_PATTERN_COLOR_SQUARES, 134211c0d8fdSPaul Kocialkowski OV8865_PRE_CTRL0_PATTERN_EN | OV8865_PRE_CTRL0_ROLLING_BAR_EN | 134311c0d8fdSPaul Kocialkowski OV8865_PRE_CTRL0_PATTERN_COLOR_SQUARES, 134411c0d8fdSPaul Kocialkowski }; 134511c0d8fdSPaul Kocialkowski 134611c0d8fdSPaul Kocialkowski /* Input/Output */ 134711c0d8fdSPaul Kocialkowski 134811c0d8fdSPaul Kocialkowski static int ov8865_read(struct ov8865_sensor *sensor, u16 address, u8 *value) 134911c0d8fdSPaul Kocialkowski { 135011c0d8fdSPaul Kocialkowski unsigned char data[2] = { address >> 8, address & 0xff }; 135111c0d8fdSPaul Kocialkowski struct i2c_client *client = sensor->i2c_client; 135211c0d8fdSPaul Kocialkowski int ret; 135311c0d8fdSPaul Kocialkowski 135411c0d8fdSPaul Kocialkowski ret = i2c_master_send(client, data, sizeof(data)); 135511c0d8fdSPaul Kocialkowski if (ret < 0) { 135611c0d8fdSPaul Kocialkowski dev_dbg(&client->dev, "i2c send error at address %#04x\n", 135711c0d8fdSPaul Kocialkowski address); 135811c0d8fdSPaul Kocialkowski return ret; 135911c0d8fdSPaul Kocialkowski } 136011c0d8fdSPaul Kocialkowski 136111c0d8fdSPaul Kocialkowski ret = i2c_master_recv(client, value, 1); 136211c0d8fdSPaul Kocialkowski if (ret < 0) { 136311c0d8fdSPaul Kocialkowski dev_dbg(&client->dev, "i2c recv error at address %#04x\n", 136411c0d8fdSPaul Kocialkowski address); 136511c0d8fdSPaul Kocialkowski return ret; 136611c0d8fdSPaul Kocialkowski } 136711c0d8fdSPaul Kocialkowski 136811c0d8fdSPaul Kocialkowski return 0; 136911c0d8fdSPaul Kocialkowski } 137011c0d8fdSPaul Kocialkowski 137111c0d8fdSPaul Kocialkowski static int ov8865_write(struct ov8865_sensor *sensor, u16 address, u8 value) 137211c0d8fdSPaul Kocialkowski { 137311c0d8fdSPaul Kocialkowski unsigned char data[3] = { address >> 8, address & 0xff, value }; 137411c0d8fdSPaul Kocialkowski struct i2c_client *client = sensor->i2c_client; 137511c0d8fdSPaul Kocialkowski int ret; 137611c0d8fdSPaul Kocialkowski 137711c0d8fdSPaul Kocialkowski ret = i2c_master_send(client, data, sizeof(data)); 137811c0d8fdSPaul Kocialkowski if (ret < 0) { 137911c0d8fdSPaul Kocialkowski dev_dbg(&client->dev, "i2c send error at address %#04x\n", 138011c0d8fdSPaul Kocialkowski address); 138111c0d8fdSPaul Kocialkowski return ret; 138211c0d8fdSPaul Kocialkowski } 138311c0d8fdSPaul Kocialkowski 138411c0d8fdSPaul Kocialkowski return 0; 138511c0d8fdSPaul Kocialkowski } 138611c0d8fdSPaul Kocialkowski 138711c0d8fdSPaul Kocialkowski static int ov8865_write_sequence(struct ov8865_sensor *sensor, 138811c0d8fdSPaul Kocialkowski const struct ov8865_register_value *sequence, 138911c0d8fdSPaul Kocialkowski unsigned int sequence_count) 139011c0d8fdSPaul Kocialkowski { 139111c0d8fdSPaul Kocialkowski unsigned int i; 139211c0d8fdSPaul Kocialkowski int ret = 0; 139311c0d8fdSPaul Kocialkowski 139411c0d8fdSPaul Kocialkowski for (i = 0; i < sequence_count; i++) { 139511c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, sequence[i].address, 139611c0d8fdSPaul Kocialkowski sequence[i].value); 139711c0d8fdSPaul Kocialkowski if (ret) 139811c0d8fdSPaul Kocialkowski break; 139911c0d8fdSPaul Kocialkowski 140011c0d8fdSPaul Kocialkowski if (sequence[i].delay_ms) 140111c0d8fdSPaul Kocialkowski msleep(sequence[i].delay_ms); 140211c0d8fdSPaul Kocialkowski } 140311c0d8fdSPaul Kocialkowski 140411c0d8fdSPaul Kocialkowski return ret; 140511c0d8fdSPaul Kocialkowski } 140611c0d8fdSPaul Kocialkowski 140711c0d8fdSPaul Kocialkowski static int ov8865_update_bits(struct ov8865_sensor *sensor, u16 address, 140811c0d8fdSPaul Kocialkowski u8 mask, u8 bits) 140911c0d8fdSPaul Kocialkowski { 141011c0d8fdSPaul Kocialkowski u8 value = 0; 141111c0d8fdSPaul Kocialkowski int ret; 141211c0d8fdSPaul Kocialkowski 141311c0d8fdSPaul Kocialkowski ret = ov8865_read(sensor, address, &value); 141411c0d8fdSPaul Kocialkowski if (ret) 141511c0d8fdSPaul Kocialkowski return ret; 141611c0d8fdSPaul Kocialkowski 141711c0d8fdSPaul Kocialkowski value &= ~mask; 141811c0d8fdSPaul Kocialkowski value |= bits; 141911c0d8fdSPaul Kocialkowski 142011c0d8fdSPaul Kocialkowski return ov8865_write(sensor, address, value); 142111c0d8fdSPaul Kocialkowski } 142211c0d8fdSPaul Kocialkowski 142311c0d8fdSPaul Kocialkowski /* Sensor */ 142411c0d8fdSPaul Kocialkowski 142511c0d8fdSPaul Kocialkowski static int ov8865_sw_reset(struct ov8865_sensor *sensor) 142611c0d8fdSPaul Kocialkowski { 142711c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_SW_RESET_REG, OV8865_SW_RESET_RESET); 142811c0d8fdSPaul Kocialkowski } 142911c0d8fdSPaul Kocialkowski 143011c0d8fdSPaul Kocialkowski static int ov8865_sw_standby(struct ov8865_sensor *sensor, int standby) 143111c0d8fdSPaul Kocialkowski { 143211c0d8fdSPaul Kocialkowski u8 value = 0; 143311c0d8fdSPaul Kocialkowski 143411c0d8fdSPaul Kocialkowski if (!standby) 143511c0d8fdSPaul Kocialkowski value = OV8865_SW_STANDBY_STREAM_ON; 143611c0d8fdSPaul Kocialkowski 143711c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_SW_STANDBY_REG, value); 143811c0d8fdSPaul Kocialkowski } 143911c0d8fdSPaul Kocialkowski 144011c0d8fdSPaul Kocialkowski static int ov8865_chip_id_check(struct ov8865_sensor *sensor) 144111c0d8fdSPaul Kocialkowski { 144211c0d8fdSPaul Kocialkowski u16 regs[] = { OV8865_CHIP_ID_HH_REG, OV8865_CHIP_ID_H_REG, 144311c0d8fdSPaul Kocialkowski OV8865_CHIP_ID_L_REG }; 144411c0d8fdSPaul Kocialkowski u8 values[] = { OV8865_CHIP_ID_HH_VALUE, OV8865_CHIP_ID_H_VALUE, 144511c0d8fdSPaul Kocialkowski OV8865_CHIP_ID_L_VALUE }; 144611c0d8fdSPaul Kocialkowski unsigned int i; 144711c0d8fdSPaul Kocialkowski u8 value; 144811c0d8fdSPaul Kocialkowski int ret; 144911c0d8fdSPaul Kocialkowski 145011c0d8fdSPaul Kocialkowski for (i = 0; i < ARRAY_SIZE(regs); i++) { 145111c0d8fdSPaul Kocialkowski ret = ov8865_read(sensor, regs[i], &value); 145211c0d8fdSPaul Kocialkowski if (ret < 0) 145311c0d8fdSPaul Kocialkowski return ret; 145411c0d8fdSPaul Kocialkowski 145511c0d8fdSPaul Kocialkowski if (value != values[i]) { 145611c0d8fdSPaul Kocialkowski dev_err(sensor->dev, 145711c0d8fdSPaul Kocialkowski "chip id value mismatch: %#x instead of %#x\n", 145811c0d8fdSPaul Kocialkowski value, values[i]); 145911c0d8fdSPaul Kocialkowski return -EINVAL; 146011c0d8fdSPaul Kocialkowski } 146111c0d8fdSPaul Kocialkowski } 146211c0d8fdSPaul Kocialkowski 146311c0d8fdSPaul Kocialkowski return 0; 146411c0d8fdSPaul Kocialkowski } 146511c0d8fdSPaul Kocialkowski 146611c0d8fdSPaul Kocialkowski static int ov8865_charge_pump_configure(struct ov8865_sensor *sensor) 146711c0d8fdSPaul Kocialkowski { 146811c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_PUMP_CLK_DIV_REG, 146911c0d8fdSPaul Kocialkowski OV8865_PUMP_CLK_DIV_PUMP_P(1)); 147011c0d8fdSPaul Kocialkowski } 147111c0d8fdSPaul Kocialkowski 147211c0d8fdSPaul Kocialkowski static int ov8865_mipi_configure(struct ov8865_sensor *sensor) 147311c0d8fdSPaul Kocialkowski { 147411c0d8fdSPaul Kocialkowski struct v4l2_fwnode_bus_mipi_csi2 *bus_mipi_csi2 = 147511c0d8fdSPaul Kocialkowski &sensor->endpoint.bus.mipi_csi2; 147611c0d8fdSPaul Kocialkowski unsigned int lanes_count = bus_mipi_csi2->num_data_lanes; 147711c0d8fdSPaul Kocialkowski int ret; 147811c0d8fdSPaul Kocialkowski 147911c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_MIPI_SC_CTRL0_REG, 148011c0d8fdSPaul Kocialkowski OV8865_MIPI_SC_CTRL0_LANES(lanes_count) | 148111c0d8fdSPaul Kocialkowski OV8865_MIPI_SC_CTRL0_MIPI_EN | 148211c0d8fdSPaul Kocialkowski OV8865_MIPI_SC_CTRL0_UNKNOWN); 148311c0d8fdSPaul Kocialkowski if (ret) 148411c0d8fdSPaul Kocialkowski return ret; 148511c0d8fdSPaul Kocialkowski 148611c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_MIPI_SC_CTRL2_REG, 148711c0d8fdSPaul Kocialkowski OV8865_MIPI_SC_CTRL2_PD_MIPI_RST_SYNC); 148811c0d8fdSPaul Kocialkowski if (ret) 148911c0d8fdSPaul Kocialkowski return ret; 149011c0d8fdSPaul Kocialkowski 149111c0d8fdSPaul Kocialkowski if (lanes_count >= 2) { 149211c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_MIPI_LANE_SEL01_REG, 149311c0d8fdSPaul Kocialkowski OV8865_MIPI_LANE_SEL01_LANE0(0) | 149411c0d8fdSPaul Kocialkowski OV8865_MIPI_LANE_SEL01_LANE1(1)); 149511c0d8fdSPaul Kocialkowski if (ret) 149611c0d8fdSPaul Kocialkowski return ret; 149711c0d8fdSPaul Kocialkowski } 149811c0d8fdSPaul Kocialkowski 149911c0d8fdSPaul Kocialkowski if (lanes_count >= 4) { 150011c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_MIPI_LANE_SEL23_REG, 150111c0d8fdSPaul Kocialkowski OV8865_MIPI_LANE_SEL23_LANE2(2) | 150211c0d8fdSPaul Kocialkowski OV8865_MIPI_LANE_SEL23_LANE3(3)); 150311c0d8fdSPaul Kocialkowski if (ret) 150411c0d8fdSPaul Kocialkowski return ret; 150511c0d8fdSPaul Kocialkowski } 150611c0d8fdSPaul Kocialkowski 150711c0d8fdSPaul Kocialkowski ret = ov8865_update_bits(sensor, OV8865_CLK_SEL1_REG, 150811c0d8fdSPaul Kocialkowski OV8865_CLK_SEL1_MIPI_EOF, 150911c0d8fdSPaul Kocialkowski OV8865_CLK_SEL1_MIPI_EOF); 151011c0d8fdSPaul Kocialkowski if (ret) 151111c0d8fdSPaul Kocialkowski return ret; 151211c0d8fdSPaul Kocialkowski 151311c0d8fdSPaul Kocialkowski /* 151411c0d8fdSPaul Kocialkowski * This value might need to change depending on PCLK rate, 151511c0d8fdSPaul Kocialkowski * but it's unclear how. This value seems to generally work 151611c0d8fdSPaul Kocialkowski * while the default value was found to cause transmission errors. 151711c0d8fdSPaul Kocialkowski */ 151811c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_MIPI_PCLK_PERIOD_REG, 0x16); 151911c0d8fdSPaul Kocialkowski } 152011c0d8fdSPaul Kocialkowski 152111c0d8fdSPaul Kocialkowski static int ov8865_black_level_configure(struct ov8865_sensor *sensor) 152211c0d8fdSPaul Kocialkowski { 152311c0d8fdSPaul Kocialkowski int ret; 152411c0d8fdSPaul Kocialkowski 152511c0d8fdSPaul Kocialkowski /* Trigger BLC on relevant events and enable filter. */ 152611c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_CTRL0_REG, 152711c0d8fdSPaul Kocialkowski OV8865_BLC_CTRL0_TRIG_RANGE_EN | 152811c0d8fdSPaul Kocialkowski OV8865_BLC_CTRL0_TRIG_FORMAT_EN | 152911c0d8fdSPaul Kocialkowski OV8865_BLC_CTRL0_TRIG_GAIN_EN | 153011c0d8fdSPaul Kocialkowski OV8865_BLC_CTRL0_TRIG_EXPOSURE_EN | 153111c0d8fdSPaul Kocialkowski OV8865_BLC_CTRL0_FILTER_EN); 153211c0d8fdSPaul Kocialkowski if (ret) 153311c0d8fdSPaul Kocialkowski return ret; 153411c0d8fdSPaul Kocialkowski 153511c0d8fdSPaul Kocialkowski /* Lower BLC offset trigger threshold. */ 153611c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_CTRLD_REG, 153711c0d8fdSPaul Kocialkowski OV8865_BLC_CTRLD_OFFSET_TRIGGER(16)); 153811c0d8fdSPaul Kocialkowski if (ret) 153911c0d8fdSPaul Kocialkowski return ret; 154011c0d8fdSPaul Kocialkowski 154111c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_CTRL1F_REG, 0); 154211c0d8fdSPaul Kocialkowski if (ret) 154311c0d8fdSPaul Kocialkowski return ret; 154411c0d8fdSPaul Kocialkowski 154511c0d8fdSPaul Kocialkowski /* Increase BLC offset maximum limit. */ 154611c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_BLC_OFFSET_LIMIT_REG, 154711c0d8fdSPaul Kocialkowski OV8865_BLC_OFFSET_LIMIT(63)); 154811c0d8fdSPaul Kocialkowski } 154911c0d8fdSPaul Kocialkowski 155011c0d8fdSPaul Kocialkowski static int ov8865_isp_configure(struct ov8865_sensor *sensor) 155111c0d8fdSPaul Kocialkowski { 155211c0d8fdSPaul Kocialkowski int ret; 155311c0d8fdSPaul Kocialkowski 155411c0d8fdSPaul Kocialkowski /* Disable lens correction. */ 155511c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_ISP_CTRL0_REG, 155611c0d8fdSPaul Kocialkowski OV8865_ISP_CTRL0_WHITE_BALANCE_EN | 155711c0d8fdSPaul Kocialkowski OV8865_ISP_CTRL0_DPC_BLACK_EN | 155811c0d8fdSPaul Kocialkowski OV8865_ISP_CTRL0_DPC_WHITE_EN); 155911c0d8fdSPaul Kocialkowski if (ret) 156011c0d8fdSPaul Kocialkowski return ret; 156111c0d8fdSPaul Kocialkowski 156211c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_ISP_CTRL1_REG, 156311c0d8fdSPaul Kocialkowski OV8865_ISP_CTRL1_BLC_EN); 156411c0d8fdSPaul Kocialkowski } 156511c0d8fdSPaul Kocialkowski 156611c0d8fdSPaul Kocialkowski static unsigned long ov8865_mode_pll1_rate(struct ov8865_sensor *sensor, 156711c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode) 156811c0d8fdSPaul Kocialkowski { 156973dcffebSDaniel Scally const struct ov8865_pll1_config *config; 157011c0d8fdSPaul Kocialkowski unsigned long pll1_rate; 157111c0d8fdSPaul Kocialkowski 157273dcffebSDaniel Scally config = sensor->pll_configs->pll1_config; 157373dcffebSDaniel Scally pll1_rate = sensor->extclk_rate * config->pll_mul / config->pll_pre_div_half; 157411c0d8fdSPaul Kocialkowski 157511c0d8fdSPaul Kocialkowski switch (config->pll_pre_div) { 157611c0d8fdSPaul Kocialkowski case 0: 157711c0d8fdSPaul Kocialkowski break; 157811c0d8fdSPaul Kocialkowski case 1: 157911c0d8fdSPaul Kocialkowski pll1_rate *= 3; 158011c0d8fdSPaul Kocialkowski pll1_rate /= 2; 158111c0d8fdSPaul Kocialkowski break; 158211c0d8fdSPaul Kocialkowski case 3: 158311c0d8fdSPaul Kocialkowski pll1_rate *= 5; 158411c0d8fdSPaul Kocialkowski pll1_rate /= 2; 158511c0d8fdSPaul Kocialkowski break; 158611c0d8fdSPaul Kocialkowski case 4: 158711c0d8fdSPaul Kocialkowski pll1_rate /= 3; 158811c0d8fdSPaul Kocialkowski break; 158911c0d8fdSPaul Kocialkowski case 5: 159011c0d8fdSPaul Kocialkowski pll1_rate /= 4; 159111c0d8fdSPaul Kocialkowski break; 159211c0d8fdSPaul Kocialkowski case 7: 159311c0d8fdSPaul Kocialkowski pll1_rate /= 8; 159411c0d8fdSPaul Kocialkowski break; 159511c0d8fdSPaul Kocialkowski default: 159611c0d8fdSPaul Kocialkowski pll1_rate /= config->pll_pre_div; 159711c0d8fdSPaul Kocialkowski break; 159811c0d8fdSPaul Kocialkowski } 159911c0d8fdSPaul Kocialkowski 160011c0d8fdSPaul Kocialkowski return pll1_rate; 160111c0d8fdSPaul Kocialkowski } 160211c0d8fdSPaul Kocialkowski 160311c0d8fdSPaul Kocialkowski static int ov8865_mode_pll1_configure(struct ov8865_sensor *sensor, 160411c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode, 160511c0d8fdSPaul Kocialkowski u32 mbus_code) 160611c0d8fdSPaul Kocialkowski { 160773dcffebSDaniel Scally const struct ov8865_pll1_config *config; 160811c0d8fdSPaul Kocialkowski u8 value; 160911c0d8fdSPaul Kocialkowski int ret; 161011c0d8fdSPaul Kocialkowski 161173dcffebSDaniel Scally config = sensor->pll_configs->pll1_config; 161273dcffebSDaniel Scally 161311c0d8fdSPaul Kocialkowski switch (mbus_code) { 161411c0d8fdSPaul Kocialkowski case MEDIA_BUS_FMT_SBGGR10_1X10: 161511c0d8fdSPaul Kocialkowski value = OV8865_MIPI_BIT_SEL(10); 161611c0d8fdSPaul Kocialkowski break; 161711c0d8fdSPaul Kocialkowski default: 161811c0d8fdSPaul Kocialkowski return -EINVAL; 161911c0d8fdSPaul Kocialkowski } 162011c0d8fdSPaul Kocialkowski 162111c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_MIPI_BIT_SEL_REG, value); 162211c0d8fdSPaul Kocialkowski if (ret) 162311c0d8fdSPaul Kocialkowski return ret; 162411c0d8fdSPaul Kocialkowski 162511c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRLA_REG, 162611c0d8fdSPaul Kocialkowski OV8865_PLL_CTRLA_PRE_DIV_HALF(config->pll_pre_div_half)); 162711c0d8fdSPaul Kocialkowski if (ret) 162811c0d8fdSPaul Kocialkowski return ret; 162911c0d8fdSPaul Kocialkowski 163011c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRL0_REG, 163111c0d8fdSPaul Kocialkowski OV8865_PLL_CTRL0_PRE_DIV(config->pll_pre_div)); 163211c0d8fdSPaul Kocialkowski if (ret) 163311c0d8fdSPaul Kocialkowski return ret; 163411c0d8fdSPaul Kocialkowski 163511c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRL1_REG, 163611c0d8fdSPaul Kocialkowski OV8865_PLL_CTRL1_MUL_H(config->pll_mul)); 163711c0d8fdSPaul Kocialkowski if (ret) 163811c0d8fdSPaul Kocialkowski return ret; 163911c0d8fdSPaul Kocialkowski 164011c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRL2_REG, 164111c0d8fdSPaul Kocialkowski OV8865_PLL_CTRL2_MUL_L(config->pll_mul)); 164211c0d8fdSPaul Kocialkowski if (ret) 164311c0d8fdSPaul Kocialkowski return ret; 164411c0d8fdSPaul Kocialkowski 164511c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRL3_REG, 164611c0d8fdSPaul Kocialkowski OV8865_PLL_CTRL3_M_DIV(config->m_div)); 164711c0d8fdSPaul Kocialkowski if (ret) 164811c0d8fdSPaul Kocialkowski return ret; 164911c0d8fdSPaul Kocialkowski 165011c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRL4_REG, 165111c0d8fdSPaul Kocialkowski OV8865_PLL_CTRL4_MIPI_DIV(config->mipi_div)); 165211c0d8fdSPaul Kocialkowski if (ret) 165311c0d8fdSPaul Kocialkowski return ret; 165411c0d8fdSPaul Kocialkowski 165511c0d8fdSPaul Kocialkowski ret = ov8865_update_bits(sensor, OV8865_PCLK_SEL_REG, 165611c0d8fdSPaul Kocialkowski OV8865_PCLK_SEL_PCLK_DIV_MASK, 165711c0d8fdSPaul Kocialkowski OV8865_PCLK_SEL_PCLK_DIV(config->pclk_div)); 165811c0d8fdSPaul Kocialkowski if (ret) 165911c0d8fdSPaul Kocialkowski return ret; 166011c0d8fdSPaul Kocialkowski 166111c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRL5_REG, 166211c0d8fdSPaul Kocialkowski OV8865_PLL_CTRL5_SYS_PRE_DIV(config->sys_pre_div)); 166311c0d8fdSPaul Kocialkowski if (ret) 166411c0d8fdSPaul Kocialkowski return ret; 166511c0d8fdSPaul Kocialkowski 166611c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRL6_REG, 166711c0d8fdSPaul Kocialkowski OV8865_PLL_CTRL6_SYS_DIV(config->sys_div)); 166811c0d8fdSPaul Kocialkowski if (ret) 166911c0d8fdSPaul Kocialkowski return ret; 167011c0d8fdSPaul Kocialkowski 167111c0d8fdSPaul Kocialkowski return ov8865_update_bits(sensor, OV8865_PLL_CTRL1E_REG, 167211c0d8fdSPaul Kocialkowski OV8865_PLL_CTRL1E_PLL1_NO_LAT, 167311c0d8fdSPaul Kocialkowski OV8865_PLL_CTRL1E_PLL1_NO_LAT); 167411c0d8fdSPaul Kocialkowski } 167511c0d8fdSPaul Kocialkowski 167611c0d8fdSPaul Kocialkowski static int ov8865_mode_pll2_configure(struct ov8865_sensor *sensor, 167711c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode) 167811c0d8fdSPaul Kocialkowski { 167973dcffebSDaniel Scally const struct ov8865_pll2_config *config; 168011c0d8fdSPaul Kocialkowski int ret; 168111c0d8fdSPaul Kocialkowski 168273dcffebSDaniel Scally config = mode->pll2_binning ? sensor->pll_configs->pll2_config_binning : 168373dcffebSDaniel Scally sensor->pll_configs->pll2_config_native; 168473dcffebSDaniel Scally 168511c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRL12_REG, 168611c0d8fdSPaul Kocialkowski OV8865_PLL_CTRL12_PRE_DIV_HALF(config->pll_pre_div_half) | 168711c0d8fdSPaul Kocialkowski OV8865_PLL_CTRL12_DAC_DIV(config->dac_div)); 168811c0d8fdSPaul Kocialkowski if (ret) 168911c0d8fdSPaul Kocialkowski return ret; 169011c0d8fdSPaul Kocialkowski 169111c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRLB_REG, 169211c0d8fdSPaul Kocialkowski OV8865_PLL_CTRLB_PRE_DIV(config->pll_pre_div)); 169311c0d8fdSPaul Kocialkowski if (ret) 169411c0d8fdSPaul Kocialkowski return ret; 169511c0d8fdSPaul Kocialkowski 169611c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRLC_REG, 169711c0d8fdSPaul Kocialkowski OV8865_PLL_CTRLC_MUL_H(config->pll_mul)); 169811c0d8fdSPaul Kocialkowski if (ret) 169911c0d8fdSPaul Kocialkowski return ret; 170011c0d8fdSPaul Kocialkowski 170111c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRLD_REG, 170211c0d8fdSPaul Kocialkowski OV8865_PLL_CTRLD_MUL_L(config->pll_mul)); 170311c0d8fdSPaul Kocialkowski if (ret) 170411c0d8fdSPaul Kocialkowski return ret; 170511c0d8fdSPaul Kocialkowski 170611c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_PLL_CTRLF_REG, 170711c0d8fdSPaul Kocialkowski OV8865_PLL_CTRLF_SYS_PRE_DIV(config->sys_pre_div)); 170811c0d8fdSPaul Kocialkowski if (ret) 170911c0d8fdSPaul Kocialkowski return ret; 171011c0d8fdSPaul Kocialkowski 171111c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_PLL_CTRLE_REG, 171211c0d8fdSPaul Kocialkowski OV8865_PLL_CTRLE_SYS_DIV(config->sys_div)); 171311c0d8fdSPaul Kocialkowski } 171411c0d8fdSPaul Kocialkowski 171511c0d8fdSPaul Kocialkowski static int ov8865_mode_sclk_configure(struct ov8865_sensor *sensor, 171611c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode) 171711c0d8fdSPaul Kocialkowski { 171873dcffebSDaniel Scally const struct ov8865_sclk_config *config = &ov8865_sclk_config_native; 171911c0d8fdSPaul Kocialkowski int ret; 172011c0d8fdSPaul Kocialkowski 172111c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_CLK_SEL0_REG, 172211c0d8fdSPaul Kocialkowski OV8865_CLK_SEL0_PLL1_SYS_SEL(config->sys_sel)); 172311c0d8fdSPaul Kocialkowski if (ret) 172411c0d8fdSPaul Kocialkowski return ret; 172511c0d8fdSPaul Kocialkowski 172611c0d8fdSPaul Kocialkowski ret = ov8865_update_bits(sensor, OV8865_CLK_SEL1_REG, 172711c0d8fdSPaul Kocialkowski OV8865_CLK_SEL1_PLL_SCLK_SEL_MASK, 172811c0d8fdSPaul Kocialkowski OV8865_CLK_SEL1_PLL_SCLK_SEL(config->sclk_sel)); 172911c0d8fdSPaul Kocialkowski if (ret) 173011c0d8fdSPaul Kocialkowski return ret; 173111c0d8fdSPaul Kocialkowski 173211c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_SCLK_CTRL_REG, 173311c0d8fdSPaul Kocialkowski OV8865_SCLK_CTRL_UNKNOWN | 173411c0d8fdSPaul Kocialkowski OV8865_SCLK_CTRL_SCLK_DIV(config->sclk_div) | 173511c0d8fdSPaul Kocialkowski OV8865_SCLK_CTRL_SCLK_PRE_DIV(config->sclk_pre_div)); 173611c0d8fdSPaul Kocialkowski } 173711c0d8fdSPaul Kocialkowski 173811c0d8fdSPaul Kocialkowski static int ov8865_mode_binning_configure(struct ov8865_sensor *sensor, 173911c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode) 174011c0d8fdSPaul Kocialkowski { 174111c0d8fdSPaul Kocialkowski unsigned int variopixel_hsub_coef, variopixel_vsub_coef; 174211c0d8fdSPaul Kocialkowski u8 value; 174311c0d8fdSPaul Kocialkowski int ret; 174411c0d8fdSPaul Kocialkowski 174511c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_FORMAT1_REG, 0); 174611c0d8fdSPaul Kocialkowski if (ret) 174711c0d8fdSPaul Kocialkowski return ret; 174811c0d8fdSPaul Kocialkowski 174911c0d8fdSPaul Kocialkowski value = OV8865_FORMAT2_HSYNC_EN; 175011c0d8fdSPaul Kocialkowski 175111c0d8fdSPaul Kocialkowski if (mode->binning_x) 175211c0d8fdSPaul Kocialkowski value |= OV8865_FORMAT2_FST_HBIN_EN; 175311c0d8fdSPaul Kocialkowski 175411c0d8fdSPaul Kocialkowski if (mode->binning_y) 175511c0d8fdSPaul Kocialkowski value |= OV8865_FORMAT2_FST_VBIN_EN; 175611c0d8fdSPaul Kocialkowski 175711c0d8fdSPaul Kocialkowski if (mode->sync_hbin) 175811c0d8fdSPaul Kocialkowski value |= OV8865_FORMAT2_SYNC_HBIN_EN; 175911c0d8fdSPaul Kocialkowski 176011c0d8fdSPaul Kocialkowski if (mode->horz_var2) 176111c0d8fdSPaul Kocialkowski value |= OV8865_FORMAT2_ISP_HORZ_VAR2_EN; 176211c0d8fdSPaul Kocialkowski 176311c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_FORMAT2_REG, value); 176411c0d8fdSPaul Kocialkowski if (ret) 176511c0d8fdSPaul Kocialkowski return ret; 176611c0d8fdSPaul Kocialkowski 176711c0d8fdSPaul Kocialkowski ret = ov8865_update_bits(sensor, OV8865_ISP_CTRL2_REG, 176811c0d8fdSPaul Kocialkowski OV8865_ISP_CTRL2_VARIOPIXEL_EN, 176911c0d8fdSPaul Kocialkowski mode->variopixel ? 177011c0d8fdSPaul Kocialkowski OV8865_ISP_CTRL2_VARIOPIXEL_EN : 0); 177111c0d8fdSPaul Kocialkowski if (ret) 177211c0d8fdSPaul Kocialkowski return ret; 177311c0d8fdSPaul Kocialkowski 177411c0d8fdSPaul Kocialkowski if (mode->variopixel) { 177511c0d8fdSPaul Kocialkowski /* VarioPixel coefs needs to be > 1. */ 177611c0d8fdSPaul Kocialkowski variopixel_hsub_coef = mode->variopixel_hsub_coef; 177711c0d8fdSPaul Kocialkowski variopixel_vsub_coef = mode->variopixel_vsub_coef; 177811c0d8fdSPaul Kocialkowski } else { 177911c0d8fdSPaul Kocialkowski variopixel_hsub_coef = 1; 178011c0d8fdSPaul Kocialkowski variopixel_vsub_coef = 1; 178111c0d8fdSPaul Kocialkowski } 178211c0d8fdSPaul Kocialkowski 178311c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_VAP_CTRL1_REG, 178411c0d8fdSPaul Kocialkowski OV8865_VAP_CTRL1_HSUB_COEF(variopixel_hsub_coef) | 178511c0d8fdSPaul Kocialkowski OV8865_VAP_CTRL1_VSUB_COEF(variopixel_vsub_coef)); 178611c0d8fdSPaul Kocialkowski if (ret) 178711c0d8fdSPaul Kocialkowski return ret; 178811c0d8fdSPaul Kocialkowski 178911c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_INC_X_ODD_REG, 179011c0d8fdSPaul Kocialkowski OV8865_INC_X_ODD(mode->inc_x_odd)); 179111c0d8fdSPaul Kocialkowski if (ret) 179211c0d8fdSPaul Kocialkowski return ret; 179311c0d8fdSPaul Kocialkowski 179411c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_INC_X_EVEN_REG, 179511c0d8fdSPaul Kocialkowski OV8865_INC_X_EVEN(mode->inc_x_even)); 179611c0d8fdSPaul Kocialkowski if (ret) 179711c0d8fdSPaul Kocialkowski return ret; 179811c0d8fdSPaul Kocialkowski 179911c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_INC_Y_ODD_REG, 180011c0d8fdSPaul Kocialkowski OV8865_INC_Y_ODD(mode->inc_y_odd)); 180111c0d8fdSPaul Kocialkowski if (ret) 180211c0d8fdSPaul Kocialkowski return ret; 180311c0d8fdSPaul Kocialkowski 180411c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_INC_Y_EVEN_REG, 180511c0d8fdSPaul Kocialkowski OV8865_INC_Y_EVEN(mode->inc_y_even)); 180611c0d8fdSPaul Kocialkowski } 180711c0d8fdSPaul Kocialkowski 180811c0d8fdSPaul Kocialkowski static int ov8865_mode_black_level_configure(struct ov8865_sensor *sensor, 180911c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode) 181011c0d8fdSPaul Kocialkowski { 181111c0d8fdSPaul Kocialkowski int ret; 181211c0d8fdSPaul Kocialkowski 181311c0d8fdSPaul Kocialkowski /* Note that a zero value for blc_col_shift_mask is the default 256. */ 181411c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_CTRL1_REG, 181511c0d8fdSPaul Kocialkowski mode->blc_col_shift_mask | 181611c0d8fdSPaul Kocialkowski OV8865_BLC_CTRL1_OFFSET_LIMIT_EN); 181711c0d8fdSPaul Kocialkowski if (ret) 181811c0d8fdSPaul Kocialkowski return ret; 181911c0d8fdSPaul Kocialkowski 182011c0d8fdSPaul Kocialkowski /* BLC top zero line */ 182111c0d8fdSPaul Kocialkowski 182211c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_TOP_ZLINE_START_REG, 182311c0d8fdSPaul Kocialkowski OV8865_BLC_TOP_ZLINE_START(mode->blc_top_zero_line_start)); 182411c0d8fdSPaul Kocialkowski if (ret) 182511c0d8fdSPaul Kocialkowski return ret; 182611c0d8fdSPaul Kocialkowski 182711c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_TOP_ZLINE_NUM_REG, 182811c0d8fdSPaul Kocialkowski OV8865_BLC_TOP_ZLINE_NUM(mode->blc_top_zero_line_num)); 182911c0d8fdSPaul Kocialkowski if (ret) 183011c0d8fdSPaul Kocialkowski return ret; 183111c0d8fdSPaul Kocialkowski 183211c0d8fdSPaul Kocialkowski /* BLC top black line */ 183311c0d8fdSPaul Kocialkowski 183411c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_TOP_BLKLINE_START_REG, 183511c0d8fdSPaul Kocialkowski OV8865_BLC_TOP_BLKLINE_START(mode->blc_top_black_line_start)); 183611c0d8fdSPaul Kocialkowski if (ret) 183711c0d8fdSPaul Kocialkowski return ret; 183811c0d8fdSPaul Kocialkowski 183911c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_TOP_BLKLINE_NUM_REG, 184011c0d8fdSPaul Kocialkowski OV8865_BLC_TOP_BLKLINE_NUM(mode->blc_top_black_line_num)); 184111c0d8fdSPaul Kocialkowski if (ret) 184211c0d8fdSPaul Kocialkowski return ret; 184311c0d8fdSPaul Kocialkowski 184411c0d8fdSPaul Kocialkowski /* BLC bottom zero line */ 184511c0d8fdSPaul Kocialkowski 184611c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_BOT_ZLINE_START_REG, 184711c0d8fdSPaul Kocialkowski OV8865_BLC_BOT_ZLINE_START(mode->blc_bottom_zero_line_start)); 184811c0d8fdSPaul Kocialkowski if (ret) 184911c0d8fdSPaul Kocialkowski return ret; 185011c0d8fdSPaul Kocialkowski 185111c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_BOT_ZLINE_NUM_REG, 185211c0d8fdSPaul Kocialkowski OV8865_BLC_BOT_ZLINE_NUM(mode->blc_bottom_zero_line_num)); 185311c0d8fdSPaul Kocialkowski if (ret) 185411c0d8fdSPaul Kocialkowski return ret; 185511c0d8fdSPaul Kocialkowski 185611c0d8fdSPaul Kocialkowski /* BLC bottom black line */ 185711c0d8fdSPaul Kocialkowski 185811c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_BOT_BLKLINE_START_REG, 185911c0d8fdSPaul Kocialkowski OV8865_BLC_BOT_BLKLINE_START(mode->blc_bottom_black_line_start)); 186011c0d8fdSPaul Kocialkowski if (ret) 186111c0d8fdSPaul Kocialkowski return ret; 186211c0d8fdSPaul Kocialkowski 186311c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_BOT_BLKLINE_NUM_REG, 186411c0d8fdSPaul Kocialkowski OV8865_BLC_BOT_BLKLINE_NUM(mode->blc_bottom_black_line_num)); 186511c0d8fdSPaul Kocialkowski if (ret) 186611c0d8fdSPaul Kocialkowski return ret; 186711c0d8fdSPaul Kocialkowski 186811c0d8fdSPaul Kocialkowski /* BLC anchor */ 186911c0d8fdSPaul Kocialkowski 187011c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_ANCHOR_LEFT_START_H_REG, 187111c0d8fdSPaul Kocialkowski OV8865_BLC_ANCHOR_LEFT_START_H(mode->blc_anchor_left_start)); 187211c0d8fdSPaul Kocialkowski if (ret) 187311c0d8fdSPaul Kocialkowski return ret; 187411c0d8fdSPaul Kocialkowski 187511c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_ANCHOR_LEFT_START_L_REG, 187611c0d8fdSPaul Kocialkowski OV8865_BLC_ANCHOR_LEFT_START_L(mode->blc_anchor_left_start)); 187711c0d8fdSPaul Kocialkowski if (ret) 187811c0d8fdSPaul Kocialkowski return ret; 187911c0d8fdSPaul Kocialkowski 188011c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_ANCHOR_LEFT_END_H_REG, 188111c0d8fdSPaul Kocialkowski OV8865_BLC_ANCHOR_LEFT_END_H(mode->blc_anchor_left_end)); 188211c0d8fdSPaul Kocialkowski if (ret) 188311c0d8fdSPaul Kocialkowski return ret; 188411c0d8fdSPaul Kocialkowski 188511c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_ANCHOR_LEFT_END_L_REG, 188611c0d8fdSPaul Kocialkowski OV8865_BLC_ANCHOR_LEFT_END_L(mode->blc_anchor_left_end)); 188711c0d8fdSPaul Kocialkowski if (ret) 188811c0d8fdSPaul Kocialkowski return ret; 188911c0d8fdSPaul Kocialkowski 189011c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_ANCHOR_RIGHT_START_H_REG, 189111c0d8fdSPaul Kocialkowski OV8865_BLC_ANCHOR_RIGHT_START_H(mode->blc_anchor_right_start)); 189211c0d8fdSPaul Kocialkowski if (ret) 189311c0d8fdSPaul Kocialkowski return ret; 189411c0d8fdSPaul Kocialkowski 189511c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_ANCHOR_RIGHT_START_L_REG, 189611c0d8fdSPaul Kocialkowski OV8865_BLC_ANCHOR_RIGHT_START_L(mode->blc_anchor_right_start)); 189711c0d8fdSPaul Kocialkowski if (ret) 189811c0d8fdSPaul Kocialkowski return ret; 189911c0d8fdSPaul Kocialkowski 190011c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_BLC_ANCHOR_RIGHT_END_H_REG, 190111c0d8fdSPaul Kocialkowski OV8865_BLC_ANCHOR_RIGHT_END_H(mode->blc_anchor_right_end)); 190211c0d8fdSPaul Kocialkowski if (ret) 190311c0d8fdSPaul Kocialkowski return ret; 190411c0d8fdSPaul Kocialkowski 190511c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_BLC_ANCHOR_RIGHT_END_L_REG, 190611c0d8fdSPaul Kocialkowski OV8865_BLC_ANCHOR_RIGHT_END_L(mode->blc_anchor_right_end)); 190711c0d8fdSPaul Kocialkowski } 190811c0d8fdSPaul Kocialkowski 190911c0d8fdSPaul Kocialkowski static int ov8865_mode_configure(struct ov8865_sensor *sensor, 191011c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode, u32 mbus_code) 191111c0d8fdSPaul Kocialkowski { 191211c0d8fdSPaul Kocialkowski int ret; 191311c0d8fdSPaul Kocialkowski 191411c0d8fdSPaul Kocialkowski /* Output Size X */ 191511c0d8fdSPaul Kocialkowski 191611c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_OUTPUT_SIZE_X_H_REG, 191711c0d8fdSPaul Kocialkowski OV8865_OUTPUT_SIZE_X_H(mode->output_size_x)); 191811c0d8fdSPaul Kocialkowski if (ret) 191911c0d8fdSPaul Kocialkowski return ret; 192011c0d8fdSPaul Kocialkowski 192111c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_OUTPUT_SIZE_X_L_REG, 192211c0d8fdSPaul Kocialkowski OV8865_OUTPUT_SIZE_X_L(mode->output_size_x)); 192311c0d8fdSPaul Kocialkowski if (ret) 192411c0d8fdSPaul Kocialkowski return ret; 192511c0d8fdSPaul Kocialkowski 192611c0d8fdSPaul Kocialkowski /* Horizontal Total Size */ 192711c0d8fdSPaul Kocialkowski 192811c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_HTS_H_REG, OV8865_HTS_H(mode->hts)); 192911c0d8fdSPaul Kocialkowski if (ret) 193011c0d8fdSPaul Kocialkowski return ret; 193111c0d8fdSPaul Kocialkowski 193211c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_HTS_L_REG, OV8865_HTS_L(mode->hts)); 193311c0d8fdSPaul Kocialkowski if (ret) 193411c0d8fdSPaul Kocialkowski return ret; 193511c0d8fdSPaul Kocialkowski 193611c0d8fdSPaul Kocialkowski /* Output Size Y */ 193711c0d8fdSPaul Kocialkowski 193811c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_OUTPUT_SIZE_Y_H_REG, 193911c0d8fdSPaul Kocialkowski OV8865_OUTPUT_SIZE_Y_H(mode->output_size_y)); 194011c0d8fdSPaul Kocialkowski if (ret) 194111c0d8fdSPaul Kocialkowski return ret; 194211c0d8fdSPaul Kocialkowski 194311c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_OUTPUT_SIZE_Y_L_REG, 194411c0d8fdSPaul Kocialkowski OV8865_OUTPUT_SIZE_Y_L(mode->output_size_y)); 194511c0d8fdSPaul Kocialkowski if (ret) 194611c0d8fdSPaul Kocialkowski return ret; 194711c0d8fdSPaul Kocialkowski 194811c0d8fdSPaul Kocialkowski /* Vertical Total Size */ 194911c0d8fdSPaul Kocialkowski 195011c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_VTS_H_REG, OV8865_VTS_H(mode->vts)); 195111c0d8fdSPaul Kocialkowski if (ret) 195211c0d8fdSPaul Kocialkowski return ret; 195311c0d8fdSPaul Kocialkowski 195411c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_VTS_L_REG, OV8865_VTS_L(mode->vts)); 195511c0d8fdSPaul Kocialkowski if (ret) 195611c0d8fdSPaul Kocialkowski return ret; 195711c0d8fdSPaul Kocialkowski 195811c0d8fdSPaul Kocialkowski if (mode->size_auto) { 195911c0d8fdSPaul Kocialkowski /* Auto Size */ 196011c0d8fdSPaul Kocialkowski 196111c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_AUTO_SIZE_CTRL_REG, 196211c0d8fdSPaul Kocialkowski OV8865_AUTO_SIZE_CTRL_OFFSET_Y_REG | 196311c0d8fdSPaul Kocialkowski OV8865_AUTO_SIZE_CTRL_OFFSET_X_REG | 196411c0d8fdSPaul Kocialkowski OV8865_AUTO_SIZE_CTRL_CROP_END_Y_REG | 196511c0d8fdSPaul Kocialkowski OV8865_AUTO_SIZE_CTRL_CROP_END_X_REG | 196611c0d8fdSPaul Kocialkowski OV8865_AUTO_SIZE_CTRL_CROP_START_Y_REG | 196711c0d8fdSPaul Kocialkowski OV8865_AUTO_SIZE_CTRL_CROP_START_X_REG); 196811c0d8fdSPaul Kocialkowski if (ret) 196911c0d8fdSPaul Kocialkowski return ret; 197011c0d8fdSPaul Kocialkowski 197111c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_AUTO_SIZE_BOUNDARIES_REG, 197211c0d8fdSPaul Kocialkowski OV8865_AUTO_SIZE_BOUNDARIES_Y(mode->size_auto_boundary_y) | 197311c0d8fdSPaul Kocialkowski OV8865_AUTO_SIZE_BOUNDARIES_X(mode->size_auto_boundary_x)); 197411c0d8fdSPaul Kocialkowski if (ret) 197511c0d8fdSPaul Kocialkowski return ret; 197611c0d8fdSPaul Kocialkowski } else { 197711c0d8fdSPaul Kocialkowski /* Crop Start X */ 197811c0d8fdSPaul Kocialkowski 197911c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_CROP_START_X_H_REG, 198011c0d8fdSPaul Kocialkowski OV8865_CROP_START_X_H(mode->crop_start_x)); 198111c0d8fdSPaul Kocialkowski if (ret) 198211c0d8fdSPaul Kocialkowski return ret; 198311c0d8fdSPaul Kocialkowski 198411c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_CROP_START_X_L_REG, 198511c0d8fdSPaul Kocialkowski OV8865_CROP_START_X_L(mode->crop_start_x)); 198611c0d8fdSPaul Kocialkowski if (ret) 198711c0d8fdSPaul Kocialkowski return ret; 198811c0d8fdSPaul Kocialkowski 198911c0d8fdSPaul Kocialkowski /* Offset X */ 199011c0d8fdSPaul Kocialkowski 199111c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_OFFSET_X_H_REG, 199211c0d8fdSPaul Kocialkowski OV8865_OFFSET_X_H(mode->offset_x)); 199311c0d8fdSPaul Kocialkowski if (ret) 199411c0d8fdSPaul Kocialkowski return ret; 199511c0d8fdSPaul Kocialkowski 199611c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_OFFSET_X_L_REG, 199711c0d8fdSPaul Kocialkowski OV8865_OFFSET_X_L(mode->offset_x)); 199811c0d8fdSPaul Kocialkowski if (ret) 199911c0d8fdSPaul Kocialkowski return ret; 200011c0d8fdSPaul Kocialkowski 200111c0d8fdSPaul Kocialkowski /* Crop End X */ 200211c0d8fdSPaul Kocialkowski 200311c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_CROP_END_X_H_REG, 200411c0d8fdSPaul Kocialkowski OV8865_CROP_END_X_H(mode->crop_end_x)); 200511c0d8fdSPaul Kocialkowski if (ret) 200611c0d8fdSPaul Kocialkowski return ret; 200711c0d8fdSPaul Kocialkowski 200811c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_CROP_END_X_L_REG, 200911c0d8fdSPaul Kocialkowski OV8865_CROP_END_X_L(mode->crop_end_x)); 201011c0d8fdSPaul Kocialkowski if (ret) 201111c0d8fdSPaul Kocialkowski return ret; 201211c0d8fdSPaul Kocialkowski 201311c0d8fdSPaul Kocialkowski /* Crop Start Y */ 201411c0d8fdSPaul Kocialkowski 201511c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_CROP_START_Y_H_REG, 201611c0d8fdSPaul Kocialkowski OV8865_CROP_START_Y_H(mode->crop_start_y)); 201711c0d8fdSPaul Kocialkowski if (ret) 201811c0d8fdSPaul Kocialkowski return ret; 201911c0d8fdSPaul Kocialkowski 202011c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_CROP_START_Y_L_REG, 202111c0d8fdSPaul Kocialkowski OV8865_CROP_START_Y_L(mode->crop_start_y)); 202211c0d8fdSPaul Kocialkowski if (ret) 202311c0d8fdSPaul Kocialkowski return ret; 202411c0d8fdSPaul Kocialkowski 202511c0d8fdSPaul Kocialkowski /* Offset Y */ 202611c0d8fdSPaul Kocialkowski 202711c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_OFFSET_Y_H_REG, 202811c0d8fdSPaul Kocialkowski OV8865_OFFSET_Y_H(mode->offset_y)); 202911c0d8fdSPaul Kocialkowski if (ret) 203011c0d8fdSPaul Kocialkowski return ret; 203111c0d8fdSPaul Kocialkowski 203211c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_OFFSET_Y_L_REG, 203311c0d8fdSPaul Kocialkowski OV8865_OFFSET_Y_L(mode->offset_y)); 203411c0d8fdSPaul Kocialkowski if (ret) 203511c0d8fdSPaul Kocialkowski return ret; 203611c0d8fdSPaul Kocialkowski 203711c0d8fdSPaul Kocialkowski /* Crop End Y */ 203811c0d8fdSPaul Kocialkowski 203911c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_CROP_END_Y_H_REG, 204011c0d8fdSPaul Kocialkowski OV8865_CROP_END_Y_H(mode->crop_end_y)); 204111c0d8fdSPaul Kocialkowski if (ret) 204211c0d8fdSPaul Kocialkowski return ret; 204311c0d8fdSPaul Kocialkowski 204411c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_CROP_END_Y_L_REG, 204511c0d8fdSPaul Kocialkowski OV8865_CROP_END_Y_L(mode->crop_end_y)); 204611c0d8fdSPaul Kocialkowski if (ret) 204711c0d8fdSPaul Kocialkowski return ret; 204811c0d8fdSPaul Kocialkowski } 204911c0d8fdSPaul Kocialkowski 205011c0d8fdSPaul Kocialkowski /* VFIFO */ 205111c0d8fdSPaul Kocialkowski 205211c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_VFIFO_READ_START_H_REG, 205311c0d8fdSPaul Kocialkowski OV8865_VFIFO_READ_START_H(mode->vfifo_read_start)); 205411c0d8fdSPaul Kocialkowski if (ret) 205511c0d8fdSPaul Kocialkowski return ret; 205611c0d8fdSPaul Kocialkowski 205711c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_VFIFO_READ_START_L_REG, 205811c0d8fdSPaul Kocialkowski OV8865_VFIFO_READ_START_L(mode->vfifo_read_start)); 205911c0d8fdSPaul Kocialkowski if (ret) 206011c0d8fdSPaul Kocialkowski return ret; 206111c0d8fdSPaul Kocialkowski 206211c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_ABLC_NUM_REG, 206311c0d8fdSPaul Kocialkowski OV8865_ABLC_NUM(mode->ablc_num)); 206411c0d8fdSPaul Kocialkowski if (ret) 206511c0d8fdSPaul Kocialkowski return ret; 206611c0d8fdSPaul Kocialkowski 206711c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_ZLINE_NUM_REG, 206811c0d8fdSPaul Kocialkowski OV8865_ZLINE_NUM(mode->zline_num)); 206911c0d8fdSPaul Kocialkowski if (ret) 207011c0d8fdSPaul Kocialkowski return ret; 207111c0d8fdSPaul Kocialkowski 207211c0d8fdSPaul Kocialkowski /* Binning */ 207311c0d8fdSPaul Kocialkowski 207411c0d8fdSPaul Kocialkowski ret = ov8865_mode_binning_configure(sensor, mode); 207511c0d8fdSPaul Kocialkowski if (ret) 207611c0d8fdSPaul Kocialkowski return ret; 207711c0d8fdSPaul Kocialkowski 207811c0d8fdSPaul Kocialkowski /* Black Level */ 207911c0d8fdSPaul Kocialkowski 208011c0d8fdSPaul Kocialkowski ret = ov8865_mode_black_level_configure(sensor, mode); 208111c0d8fdSPaul Kocialkowski if (ret) 208211c0d8fdSPaul Kocialkowski return ret; 208311c0d8fdSPaul Kocialkowski 208411c0d8fdSPaul Kocialkowski /* PLLs */ 208511c0d8fdSPaul Kocialkowski 208611c0d8fdSPaul Kocialkowski ret = ov8865_mode_pll1_configure(sensor, mode, mbus_code); 208711c0d8fdSPaul Kocialkowski if (ret) 208811c0d8fdSPaul Kocialkowski return ret; 208911c0d8fdSPaul Kocialkowski 209011c0d8fdSPaul Kocialkowski ret = ov8865_mode_pll2_configure(sensor, mode); 209111c0d8fdSPaul Kocialkowski if (ret) 209211c0d8fdSPaul Kocialkowski return ret; 209311c0d8fdSPaul Kocialkowski 209411c0d8fdSPaul Kocialkowski ret = ov8865_mode_sclk_configure(sensor, mode); 209511c0d8fdSPaul Kocialkowski if (ret) 209611c0d8fdSPaul Kocialkowski return ret; 209711c0d8fdSPaul Kocialkowski 209811c0d8fdSPaul Kocialkowski /* Extra registers */ 209911c0d8fdSPaul Kocialkowski 210011c0d8fdSPaul Kocialkowski if (mode->register_values) { 210111c0d8fdSPaul Kocialkowski ret = ov8865_write_sequence(sensor, mode->register_values, 210211c0d8fdSPaul Kocialkowski mode->register_values_count); 210311c0d8fdSPaul Kocialkowski if (ret) 210411c0d8fdSPaul Kocialkowski return ret; 210511c0d8fdSPaul Kocialkowski } 210611c0d8fdSPaul Kocialkowski 210711c0d8fdSPaul Kocialkowski return 0; 210811c0d8fdSPaul Kocialkowski } 210911c0d8fdSPaul Kocialkowski 211011c0d8fdSPaul Kocialkowski static unsigned long ov8865_mode_mipi_clk_rate(struct ov8865_sensor *sensor, 211111c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode) 211211c0d8fdSPaul Kocialkowski { 211373dcffebSDaniel Scally const struct ov8865_pll1_config *config; 211411c0d8fdSPaul Kocialkowski unsigned long pll1_rate; 211511c0d8fdSPaul Kocialkowski 211673dcffebSDaniel Scally config = sensor->pll_configs->pll1_config; 211773dcffebSDaniel Scally 211811c0d8fdSPaul Kocialkowski pll1_rate = ov8865_mode_pll1_rate(sensor, mode); 211911c0d8fdSPaul Kocialkowski 212011c0d8fdSPaul Kocialkowski return pll1_rate / config->m_div / 2; 212111c0d8fdSPaul Kocialkowski } 212211c0d8fdSPaul Kocialkowski 212311c0d8fdSPaul Kocialkowski /* Exposure */ 212411c0d8fdSPaul Kocialkowski 212511c0d8fdSPaul Kocialkowski static int ov8865_exposure_configure(struct ov8865_sensor *sensor, u32 exposure) 212611c0d8fdSPaul Kocialkowski { 212711c0d8fdSPaul Kocialkowski int ret; 212811c0d8fdSPaul Kocialkowski 2129e15ddc96SDaniel Scally /* The sensor stores exposure in units of 1/16th of a line */ 2130e15ddc96SDaniel Scally exposure *= 16; 2131e15ddc96SDaniel Scally 213211c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_EXPOSURE_CTRL_HH_REG, 213311c0d8fdSPaul Kocialkowski OV8865_EXPOSURE_CTRL_HH(exposure)); 213411c0d8fdSPaul Kocialkowski if (ret) 213511c0d8fdSPaul Kocialkowski return ret; 213611c0d8fdSPaul Kocialkowski 213711c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_EXPOSURE_CTRL_H_REG, 213811c0d8fdSPaul Kocialkowski OV8865_EXPOSURE_CTRL_H(exposure)); 213911c0d8fdSPaul Kocialkowski if (ret) 214011c0d8fdSPaul Kocialkowski return ret; 214111c0d8fdSPaul Kocialkowski 214211c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_EXPOSURE_CTRL_L_REG, 214311c0d8fdSPaul Kocialkowski OV8865_EXPOSURE_CTRL_L(exposure)); 214411c0d8fdSPaul Kocialkowski } 214511c0d8fdSPaul Kocialkowski 214611c0d8fdSPaul Kocialkowski /* Gain */ 214711c0d8fdSPaul Kocialkowski 2148d938b2f2SDaniel Scally static int ov8865_analog_gain_configure(struct ov8865_sensor *sensor, u32 gain) 214911c0d8fdSPaul Kocialkowski { 215011c0d8fdSPaul Kocialkowski int ret; 215111c0d8fdSPaul Kocialkowski 215211c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_GAIN_CTRL_H_REG, 215311c0d8fdSPaul Kocialkowski OV8865_GAIN_CTRL_H(gain)); 215411c0d8fdSPaul Kocialkowski if (ret) 215511c0d8fdSPaul Kocialkowski return ret; 215611c0d8fdSPaul Kocialkowski 215711c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_GAIN_CTRL_L_REG, 215811c0d8fdSPaul Kocialkowski OV8865_GAIN_CTRL_L(gain)); 215911c0d8fdSPaul Kocialkowski } 216011c0d8fdSPaul Kocialkowski 216111c0d8fdSPaul Kocialkowski /* White Balance */ 216211c0d8fdSPaul Kocialkowski 216311c0d8fdSPaul Kocialkowski static int ov8865_red_balance_configure(struct ov8865_sensor *sensor, 216411c0d8fdSPaul Kocialkowski u32 red_balance) 216511c0d8fdSPaul Kocialkowski { 216611c0d8fdSPaul Kocialkowski int ret; 216711c0d8fdSPaul Kocialkowski 216811c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_ISP_GAIN_RED_H_REG, 216911c0d8fdSPaul Kocialkowski OV8865_ISP_GAIN_RED_H(red_balance)); 217011c0d8fdSPaul Kocialkowski if (ret) 217111c0d8fdSPaul Kocialkowski return ret; 217211c0d8fdSPaul Kocialkowski 217311c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_ISP_GAIN_RED_L_REG, 217411c0d8fdSPaul Kocialkowski OV8865_ISP_GAIN_RED_L(red_balance)); 217511c0d8fdSPaul Kocialkowski } 217611c0d8fdSPaul Kocialkowski 217711c0d8fdSPaul Kocialkowski static int ov8865_blue_balance_configure(struct ov8865_sensor *sensor, 217811c0d8fdSPaul Kocialkowski u32 blue_balance) 217911c0d8fdSPaul Kocialkowski { 218011c0d8fdSPaul Kocialkowski int ret; 218111c0d8fdSPaul Kocialkowski 218211c0d8fdSPaul Kocialkowski ret = ov8865_write(sensor, OV8865_ISP_GAIN_BLUE_H_REG, 218311c0d8fdSPaul Kocialkowski OV8865_ISP_GAIN_BLUE_H(blue_balance)); 218411c0d8fdSPaul Kocialkowski if (ret) 218511c0d8fdSPaul Kocialkowski return ret; 218611c0d8fdSPaul Kocialkowski 218711c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_ISP_GAIN_BLUE_L_REG, 218811c0d8fdSPaul Kocialkowski OV8865_ISP_GAIN_BLUE_L(blue_balance)); 218911c0d8fdSPaul Kocialkowski } 219011c0d8fdSPaul Kocialkowski 219111c0d8fdSPaul Kocialkowski /* Flip */ 219211c0d8fdSPaul Kocialkowski 219311c0d8fdSPaul Kocialkowski static int ov8865_flip_vert_configure(struct ov8865_sensor *sensor, bool enable) 219411c0d8fdSPaul Kocialkowski { 219511c0d8fdSPaul Kocialkowski u8 bits = OV8865_FORMAT1_FLIP_VERT_ISP_EN | 219611c0d8fdSPaul Kocialkowski OV8865_FORMAT1_FLIP_VERT_SENSOR_EN; 219711c0d8fdSPaul Kocialkowski 219811c0d8fdSPaul Kocialkowski return ov8865_update_bits(sensor, OV8865_FORMAT1_REG, bits, 219911c0d8fdSPaul Kocialkowski enable ? bits : 0); 220011c0d8fdSPaul Kocialkowski } 220111c0d8fdSPaul Kocialkowski 220211c0d8fdSPaul Kocialkowski static int ov8865_flip_horz_configure(struct ov8865_sensor *sensor, bool enable) 220311c0d8fdSPaul Kocialkowski { 220411c0d8fdSPaul Kocialkowski u8 bits = OV8865_FORMAT2_FLIP_HORZ_ISP_EN | 220511c0d8fdSPaul Kocialkowski OV8865_FORMAT2_FLIP_HORZ_SENSOR_EN; 220611c0d8fdSPaul Kocialkowski 220711c0d8fdSPaul Kocialkowski return ov8865_update_bits(sensor, OV8865_FORMAT2_REG, bits, 220811c0d8fdSPaul Kocialkowski enable ? bits : 0); 220911c0d8fdSPaul Kocialkowski } 221011c0d8fdSPaul Kocialkowski 221111c0d8fdSPaul Kocialkowski /* Test Pattern */ 221211c0d8fdSPaul Kocialkowski 221311c0d8fdSPaul Kocialkowski static int ov8865_test_pattern_configure(struct ov8865_sensor *sensor, 221411c0d8fdSPaul Kocialkowski unsigned int index) 221511c0d8fdSPaul Kocialkowski { 221611c0d8fdSPaul Kocialkowski if (index >= ARRAY_SIZE(ov8865_test_pattern_bits)) 221711c0d8fdSPaul Kocialkowski return -EINVAL; 221811c0d8fdSPaul Kocialkowski 221911c0d8fdSPaul Kocialkowski return ov8865_write(sensor, OV8865_PRE_CTRL0_REG, 222011c0d8fdSPaul Kocialkowski ov8865_test_pattern_bits[index]); 222111c0d8fdSPaul Kocialkowski } 222211c0d8fdSPaul Kocialkowski 22239293aafeSDaniel Scally /* Blanking */ 22249293aafeSDaniel Scally 22259293aafeSDaniel Scally static int ov8865_vts_configure(struct ov8865_sensor *sensor, u32 vblank) 22269293aafeSDaniel Scally { 22279293aafeSDaniel Scally u16 vts = sensor->state.mode->output_size_y + vblank; 22289293aafeSDaniel Scally int ret; 22299293aafeSDaniel Scally 22309293aafeSDaniel Scally ret = ov8865_write(sensor, OV8865_VTS_H_REG, OV8865_VTS_H(vts)); 22319293aafeSDaniel Scally if (ret) 22329293aafeSDaniel Scally return ret; 22339293aafeSDaniel Scally 22349293aafeSDaniel Scally return ov8865_write(sensor, OV8865_VTS_L_REG, OV8865_VTS_L(vts)); 22359293aafeSDaniel Scally } 22369293aafeSDaniel Scally 223711c0d8fdSPaul Kocialkowski /* State */ 223811c0d8fdSPaul Kocialkowski 223911c0d8fdSPaul Kocialkowski static int ov8865_state_mipi_configure(struct ov8865_sensor *sensor, 224011c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode, 224111c0d8fdSPaul Kocialkowski u32 mbus_code) 224211c0d8fdSPaul Kocialkowski { 224311c0d8fdSPaul Kocialkowski struct ov8865_ctrls *ctrls = &sensor->ctrls; 224411c0d8fdSPaul Kocialkowski struct v4l2_fwnode_bus_mipi_csi2 *bus_mipi_csi2 = 224511c0d8fdSPaul Kocialkowski &sensor->endpoint.bus.mipi_csi2; 224611c0d8fdSPaul Kocialkowski unsigned long mipi_clk_rate; 224711c0d8fdSPaul Kocialkowski unsigned int bits_per_sample; 224811c0d8fdSPaul Kocialkowski unsigned int lanes_count; 224911c0d8fdSPaul Kocialkowski unsigned int i, j; 225011c0d8fdSPaul Kocialkowski s64 mipi_pixel_rate; 225111c0d8fdSPaul Kocialkowski 225211c0d8fdSPaul Kocialkowski mipi_clk_rate = ov8865_mode_mipi_clk_rate(sensor, mode); 225311c0d8fdSPaul Kocialkowski if (!mipi_clk_rate) 225411c0d8fdSPaul Kocialkowski return -EINVAL; 225511c0d8fdSPaul Kocialkowski 225611c0d8fdSPaul Kocialkowski for (i = 0; i < ARRAY_SIZE(ov8865_link_freq_menu); i++) { 225711c0d8fdSPaul Kocialkowski s64 freq = ov8865_link_freq_menu[i]; 225811c0d8fdSPaul Kocialkowski 225911c0d8fdSPaul Kocialkowski if (freq == mipi_clk_rate) 226011c0d8fdSPaul Kocialkowski break; 226111c0d8fdSPaul Kocialkowski } 226211c0d8fdSPaul Kocialkowski 226311c0d8fdSPaul Kocialkowski for (j = 0; j < sensor->endpoint.nr_of_link_frequencies; j++) { 226411c0d8fdSPaul Kocialkowski u64 freq = sensor->endpoint.link_frequencies[j]; 226511c0d8fdSPaul Kocialkowski 226611c0d8fdSPaul Kocialkowski if (freq == mipi_clk_rate) 226711c0d8fdSPaul Kocialkowski break; 226811c0d8fdSPaul Kocialkowski } 226911c0d8fdSPaul Kocialkowski 227011c0d8fdSPaul Kocialkowski if (i == ARRAY_SIZE(ov8865_link_freq_menu)) { 227111c0d8fdSPaul Kocialkowski dev_err(sensor->dev, 227211c0d8fdSPaul Kocialkowski "failed to find %lu clk rate in link freq\n", 227311c0d8fdSPaul Kocialkowski mipi_clk_rate); 227411c0d8fdSPaul Kocialkowski } else if (j == sensor->endpoint.nr_of_link_frequencies) { 227511c0d8fdSPaul Kocialkowski dev_err(sensor->dev, 227611c0d8fdSPaul Kocialkowski "failed to find %lu clk rate in endpoint link-frequencies\n", 227711c0d8fdSPaul Kocialkowski mipi_clk_rate); 227811c0d8fdSPaul Kocialkowski } else { 227911c0d8fdSPaul Kocialkowski __v4l2_ctrl_s_ctrl(ctrls->link_freq, i); 228011c0d8fdSPaul Kocialkowski } 228111c0d8fdSPaul Kocialkowski 228211c0d8fdSPaul Kocialkowski switch (mbus_code) { 228311c0d8fdSPaul Kocialkowski case MEDIA_BUS_FMT_SBGGR10_1X10: 228411c0d8fdSPaul Kocialkowski bits_per_sample = 10; 228511c0d8fdSPaul Kocialkowski break; 228611c0d8fdSPaul Kocialkowski default: 228711c0d8fdSPaul Kocialkowski return -EINVAL; 228811c0d8fdSPaul Kocialkowski } 228911c0d8fdSPaul Kocialkowski 229011c0d8fdSPaul Kocialkowski lanes_count = bus_mipi_csi2->num_data_lanes; 229111c0d8fdSPaul Kocialkowski mipi_pixel_rate = mipi_clk_rate * 2 * lanes_count / bits_per_sample; 229211c0d8fdSPaul Kocialkowski 229311c0d8fdSPaul Kocialkowski __v4l2_ctrl_s_ctrl_int64(ctrls->pixel_rate, mipi_pixel_rate); 229411c0d8fdSPaul Kocialkowski 229511c0d8fdSPaul Kocialkowski return 0; 229611c0d8fdSPaul Kocialkowski } 229711c0d8fdSPaul Kocialkowski 229811c0d8fdSPaul Kocialkowski static int ov8865_state_configure(struct ov8865_sensor *sensor, 229911c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode, 230011c0d8fdSPaul Kocialkowski u32 mbus_code) 230111c0d8fdSPaul Kocialkowski { 230211c0d8fdSPaul Kocialkowski int ret; 230311c0d8fdSPaul Kocialkowski 230411c0d8fdSPaul Kocialkowski if (sensor->state.streaming) 230511c0d8fdSPaul Kocialkowski return -EBUSY; 230611c0d8fdSPaul Kocialkowski 230711c0d8fdSPaul Kocialkowski /* State will be configured at first power on otherwise. */ 230811c0d8fdSPaul Kocialkowski if (pm_runtime_enabled(sensor->dev) && 230911c0d8fdSPaul Kocialkowski !pm_runtime_suspended(sensor->dev)) { 231011c0d8fdSPaul Kocialkowski ret = ov8865_mode_configure(sensor, mode, mbus_code); 231111c0d8fdSPaul Kocialkowski if (ret) 231211c0d8fdSPaul Kocialkowski return ret; 231311c0d8fdSPaul Kocialkowski } 231411c0d8fdSPaul Kocialkowski 231511c0d8fdSPaul Kocialkowski ret = ov8865_state_mipi_configure(sensor, mode, mbus_code); 231611c0d8fdSPaul Kocialkowski if (ret) 231711c0d8fdSPaul Kocialkowski return ret; 231811c0d8fdSPaul Kocialkowski 231911c0d8fdSPaul Kocialkowski sensor->state.mode = mode; 232011c0d8fdSPaul Kocialkowski sensor->state.mbus_code = mbus_code; 232111c0d8fdSPaul Kocialkowski 232211c0d8fdSPaul Kocialkowski return 0; 232311c0d8fdSPaul Kocialkowski } 232411c0d8fdSPaul Kocialkowski 232511c0d8fdSPaul Kocialkowski static int ov8865_state_init(struct ov8865_sensor *sensor) 232611c0d8fdSPaul Kocialkowski { 232711c0d8fdSPaul Kocialkowski return ov8865_state_configure(sensor, &ov8865_modes[0], 232811c0d8fdSPaul Kocialkowski ov8865_mbus_codes[0]); 232911c0d8fdSPaul Kocialkowski } 233011c0d8fdSPaul Kocialkowski 233111c0d8fdSPaul Kocialkowski /* Sensor Base */ 233211c0d8fdSPaul Kocialkowski 233311c0d8fdSPaul Kocialkowski static int ov8865_sensor_init(struct ov8865_sensor *sensor) 233411c0d8fdSPaul Kocialkowski { 233511c0d8fdSPaul Kocialkowski int ret; 233611c0d8fdSPaul Kocialkowski 233711c0d8fdSPaul Kocialkowski ret = ov8865_sw_reset(sensor); 233811c0d8fdSPaul Kocialkowski if (ret) { 233911c0d8fdSPaul Kocialkowski dev_err(sensor->dev, "failed to perform sw reset\n"); 234011c0d8fdSPaul Kocialkowski return ret; 234111c0d8fdSPaul Kocialkowski } 234211c0d8fdSPaul Kocialkowski 234311c0d8fdSPaul Kocialkowski ret = ov8865_sw_standby(sensor, 1); 234411c0d8fdSPaul Kocialkowski if (ret) { 234511c0d8fdSPaul Kocialkowski dev_err(sensor->dev, "failed to set sensor standby\n"); 234611c0d8fdSPaul Kocialkowski return ret; 234711c0d8fdSPaul Kocialkowski } 234811c0d8fdSPaul Kocialkowski 234911c0d8fdSPaul Kocialkowski ret = ov8865_chip_id_check(sensor); 235011c0d8fdSPaul Kocialkowski if (ret) { 235111c0d8fdSPaul Kocialkowski dev_err(sensor->dev, "failed to check sensor chip id\n"); 235211c0d8fdSPaul Kocialkowski return ret; 235311c0d8fdSPaul Kocialkowski } 235411c0d8fdSPaul Kocialkowski 235511c0d8fdSPaul Kocialkowski ret = ov8865_write_sequence(sensor, ov8865_init_sequence, 235611c0d8fdSPaul Kocialkowski ARRAY_SIZE(ov8865_init_sequence)); 235711c0d8fdSPaul Kocialkowski if (ret) { 235811c0d8fdSPaul Kocialkowski dev_err(sensor->dev, "failed to write init sequence\n"); 235911c0d8fdSPaul Kocialkowski return ret; 236011c0d8fdSPaul Kocialkowski } 236111c0d8fdSPaul Kocialkowski 236211c0d8fdSPaul Kocialkowski ret = ov8865_charge_pump_configure(sensor); 236311c0d8fdSPaul Kocialkowski if (ret) { 236411c0d8fdSPaul Kocialkowski dev_err(sensor->dev, "failed to configure pad\n"); 236511c0d8fdSPaul Kocialkowski return ret; 236611c0d8fdSPaul Kocialkowski } 236711c0d8fdSPaul Kocialkowski 236811c0d8fdSPaul Kocialkowski ret = ov8865_mipi_configure(sensor); 236911c0d8fdSPaul Kocialkowski if (ret) { 237011c0d8fdSPaul Kocialkowski dev_err(sensor->dev, "failed to configure MIPI\n"); 237111c0d8fdSPaul Kocialkowski return ret; 237211c0d8fdSPaul Kocialkowski } 237311c0d8fdSPaul Kocialkowski 237411c0d8fdSPaul Kocialkowski ret = ov8865_isp_configure(sensor); 237511c0d8fdSPaul Kocialkowski if (ret) { 237611c0d8fdSPaul Kocialkowski dev_err(sensor->dev, "failed to configure ISP\n"); 237711c0d8fdSPaul Kocialkowski return ret; 237811c0d8fdSPaul Kocialkowski } 237911c0d8fdSPaul Kocialkowski 238011c0d8fdSPaul Kocialkowski ret = ov8865_black_level_configure(sensor); 238111c0d8fdSPaul Kocialkowski if (ret) { 238211c0d8fdSPaul Kocialkowski dev_err(sensor->dev, "failed to configure black level\n"); 238311c0d8fdSPaul Kocialkowski return ret; 238411c0d8fdSPaul Kocialkowski } 238511c0d8fdSPaul Kocialkowski 238611c0d8fdSPaul Kocialkowski /* Configure current mode. */ 238711c0d8fdSPaul Kocialkowski ret = ov8865_state_configure(sensor, sensor->state.mode, 238811c0d8fdSPaul Kocialkowski sensor->state.mbus_code); 238911c0d8fdSPaul Kocialkowski if (ret) { 239011c0d8fdSPaul Kocialkowski dev_err(sensor->dev, "failed to configure state\n"); 239111c0d8fdSPaul Kocialkowski return ret; 239211c0d8fdSPaul Kocialkowski } 239311c0d8fdSPaul Kocialkowski 239411c0d8fdSPaul Kocialkowski return 0; 239511c0d8fdSPaul Kocialkowski } 239611c0d8fdSPaul Kocialkowski 239711c0d8fdSPaul Kocialkowski static int ov8865_sensor_power(struct ov8865_sensor *sensor, bool on) 239811c0d8fdSPaul Kocialkowski { 239911c0d8fdSPaul Kocialkowski /* Keep initialized to zero for disable label. */ 240011c0d8fdSPaul Kocialkowski int ret = 0; 240111c0d8fdSPaul Kocialkowski 240211c0d8fdSPaul Kocialkowski if (on) { 240311c0d8fdSPaul Kocialkowski gpiod_set_value_cansleep(sensor->reset, 1); 240411c0d8fdSPaul Kocialkowski gpiod_set_value_cansleep(sensor->powerdown, 1); 240511c0d8fdSPaul Kocialkowski 240611c0d8fdSPaul Kocialkowski ret = regulator_enable(sensor->dovdd); 240711c0d8fdSPaul Kocialkowski if (ret) { 240811c0d8fdSPaul Kocialkowski dev_err(sensor->dev, 240911c0d8fdSPaul Kocialkowski "failed to enable DOVDD regulator\n"); 241011c0d8fdSPaul Kocialkowski goto disable; 241111c0d8fdSPaul Kocialkowski } 241211c0d8fdSPaul Kocialkowski 241311c0d8fdSPaul Kocialkowski ret = regulator_enable(sensor->avdd); 241411c0d8fdSPaul Kocialkowski if (ret) { 241511c0d8fdSPaul Kocialkowski dev_err(sensor->dev, 241611c0d8fdSPaul Kocialkowski "failed to enable AVDD regulator\n"); 241711c0d8fdSPaul Kocialkowski goto disable; 241811c0d8fdSPaul Kocialkowski } 241911c0d8fdSPaul Kocialkowski 242011c0d8fdSPaul Kocialkowski ret = regulator_enable(sensor->dvdd); 242111c0d8fdSPaul Kocialkowski if (ret) { 242211c0d8fdSPaul Kocialkowski dev_err(sensor->dev, 242311c0d8fdSPaul Kocialkowski "failed to enable DVDD regulator\n"); 242411c0d8fdSPaul Kocialkowski goto disable; 242511c0d8fdSPaul Kocialkowski } 242611c0d8fdSPaul Kocialkowski 242711c0d8fdSPaul Kocialkowski ret = clk_prepare_enable(sensor->extclk); 242811c0d8fdSPaul Kocialkowski if (ret) { 242911c0d8fdSPaul Kocialkowski dev_err(sensor->dev, "failed to enable EXTCLK clock\n"); 243011c0d8fdSPaul Kocialkowski goto disable; 243111c0d8fdSPaul Kocialkowski } 243211c0d8fdSPaul Kocialkowski 243311c0d8fdSPaul Kocialkowski gpiod_set_value_cansleep(sensor->reset, 0); 243411c0d8fdSPaul Kocialkowski gpiod_set_value_cansleep(sensor->powerdown, 0); 243511c0d8fdSPaul Kocialkowski 243611c0d8fdSPaul Kocialkowski /* Time to enter streaming mode according to power timings. */ 243711c0d8fdSPaul Kocialkowski usleep_range(10000, 12000); 243811c0d8fdSPaul Kocialkowski } else { 243911c0d8fdSPaul Kocialkowski disable: 244011c0d8fdSPaul Kocialkowski gpiod_set_value_cansleep(sensor->powerdown, 1); 244111c0d8fdSPaul Kocialkowski gpiod_set_value_cansleep(sensor->reset, 1); 244211c0d8fdSPaul Kocialkowski 244311c0d8fdSPaul Kocialkowski clk_disable_unprepare(sensor->extclk); 244411c0d8fdSPaul Kocialkowski 244511c0d8fdSPaul Kocialkowski regulator_disable(sensor->dvdd); 244611c0d8fdSPaul Kocialkowski regulator_disable(sensor->avdd); 244711c0d8fdSPaul Kocialkowski regulator_disable(sensor->dovdd); 244811c0d8fdSPaul Kocialkowski } 244911c0d8fdSPaul Kocialkowski 245011c0d8fdSPaul Kocialkowski return ret; 245111c0d8fdSPaul Kocialkowski } 245211c0d8fdSPaul Kocialkowski 245311c0d8fdSPaul Kocialkowski /* Controls */ 245411c0d8fdSPaul Kocialkowski 245511c0d8fdSPaul Kocialkowski static int ov8865_s_ctrl(struct v4l2_ctrl *ctrl) 245611c0d8fdSPaul Kocialkowski { 245711c0d8fdSPaul Kocialkowski struct v4l2_subdev *subdev = ov8865_ctrl_subdev(ctrl); 245811c0d8fdSPaul Kocialkowski struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev); 245911c0d8fdSPaul Kocialkowski unsigned int index; 246011c0d8fdSPaul Kocialkowski int ret; 246111c0d8fdSPaul Kocialkowski 2462ca28690eSDaniel Scally /* If VBLANK is altered we need to update exposure to compensate */ 2463ca28690eSDaniel Scally if (ctrl->id == V4L2_CID_VBLANK) { 2464ca28690eSDaniel Scally int exposure_max; 2465ca28690eSDaniel Scally 2466ca28690eSDaniel Scally exposure_max = sensor->state.mode->output_size_y + ctrl->val - 2467ca28690eSDaniel Scally OV8865_INTEGRATION_TIME_MARGIN; 2468ca28690eSDaniel Scally __v4l2_ctrl_modify_range(sensor->ctrls.exposure, 2469ca28690eSDaniel Scally sensor->ctrls.exposure->minimum, 2470ca28690eSDaniel Scally exposure_max, 2471ca28690eSDaniel Scally sensor->ctrls.exposure->step, 2472ca28690eSDaniel Scally min(sensor->ctrls.exposure->val, 2473ca28690eSDaniel Scally exposure_max)); 2474ca28690eSDaniel Scally } 2475ca28690eSDaniel Scally 247611c0d8fdSPaul Kocialkowski /* Wait for the sensor to be on before setting controls. */ 247711c0d8fdSPaul Kocialkowski if (pm_runtime_suspended(sensor->dev)) 247811c0d8fdSPaul Kocialkowski return 0; 247911c0d8fdSPaul Kocialkowski 248011c0d8fdSPaul Kocialkowski switch (ctrl->id) { 248111c0d8fdSPaul Kocialkowski case V4L2_CID_EXPOSURE: 248211c0d8fdSPaul Kocialkowski ret = ov8865_exposure_configure(sensor, ctrl->val); 248311c0d8fdSPaul Kocialkowski if (ret) 248411c0d8fdSPaul Kocialkowski return ret; 248511c0d8fdSPaul Kocialkowski break; 2486d938b2f2SDaniel Scally case V4L2_CID_ANALOGUE_GAIN: 2487d938b2f2SDaniel Scally ret = ov8865_analog_gain_configure(sensor, ctrl->val); 248811c0d8fdSPaul Kocialkowski if (ret) 248911c0d8fdSPaul Kocialkowski return ret; 249011c0d8fdSPaul Kocialkowski break; 249111c0d8fdSPaul Kocialkowski case V4L2_CID_RED_BALANCE: 249211c0d8fdSPaul Kocialkowski return ov8865_red_balance_configure(sensor, ctrl->val); 249311c0d8fdSPaul Kocialkowski case V4L2_CID_BLUE_BALANCE: 249411c0d8fdSPaul Kocialkowski return ov8865_blue_balance_configure(sensor, ctrl->val); 249511c0d8fdSPaul Kocialkowski case V4L2_CID_HFLIP: 249611c0d8fdSPaul Kocialkowski return ov8865_flip_horz_configure(sensor, !!ctrl->val); 249711c0d8fdSPaul Kocialkowski case V4L2_CID_VFLIP: 249811c0d8fdSPaul Kocialkowski return ov8865_flip_vert_configure(sensor, !!ctrl->val); 249911c0d8fdSPaul Kocialkowski case V4L2_CID_TEST_PATTERN: 250011c0d8fdSPaul Kocialkowski index = (unsigned int)ctrl->val; 250111c0d8fdSPaul Kocialkowski return ov8865_test_pattern_configure(sensor, index); 25029293aafeSDaniel Scally case V4L2_CID_VBLANK: 25039293aafeSDaniel Scally return ov8865_vts_configure(sensor, ctrl->val); 250411c0d8fdSPaul Kocialkowski default: 250511c0d8fdSPaul Kocialkowski return -EINVAL; 250611c0d8fdSPaul Kocialkowski } 250711c0d8fdSPaul Kocialkowski 250811c0d8fdSPaul Kocialkowski return 0; 250911c0d8fdSPaul Kocialkowski } 251011c0d8fdSPaul Kocialkowski 251111c0d8fdSPaul Kocialkowski static const struct v4l2_ctrl_ops ov8865_ctrl_ops = { 251211c0d8fdSPaul Kocialkowski .s_ctrl = ov8865_s_ctrl, 251311c0d8fdSPaul Kocialkowski }; 251411c0d8fdSPaul Kocialkowski 251511c0d8fdSPaul Kocialkowski static int ov8865_ctrls_init(struct ov8865_sensor *sensor) 251611c0d8fdSPaul Kocialkowski { 251711c0d8fdSPaul Kocialkowski struct ov8865_ctrls *ctrls = &sensor->ctrls; 251811c0d8fdSPaul Kocialkowski struct v4l2_ctrl_handler *handler = &ctrls->handler; 251911c0d8fdSPaul Kocialkowski const struct v4l2_ctrl_ops *ops = &ov8865_ctrl_ops; 25209293aafeSDaniel Scally const struct ov8865_mode *mode = &ov8865_modes[0]; 25216eecfb34SDaniel Scally struct v4l2_fwnode_device_properties props; 25229293aafeSDaniel Scally unsigned int vblank_max, vblank_def; 2523d84d4ceeSDaniel Scally unsigned int hblank; 252411c0d8fdSPaul Kocialkowski int ret; 252511c0d8fdSPaul Kocialkowski 252611c0d8fdSPaul Kocialkowski v4l2_ctrl_handler_init(handler, 32); 252711c0d8fdSPaul Kocialkowski 252811c0d8fdSPaul Kocialkowski /* Use our mutex for ctrl locking. */ 252911c0d8fdSPaul Kocialkowski handler->lock = &sensor->mutex; 253011c0d8fdSPaul Kocialkowski 253111c0d8fdSPaul Kocialkowski /* Exposure */ 253211c0d8fdSPaul Kocialkowski 2533e15ddc96SDaniel Scally ctrls->exposure = v4l2_ctrl_new_std(handler, ops, V4L2_CID_EXPOSURE, 2, 2534e15ddc96SDaniel Scally 65535, 1, 32); 253511c0d8fdSPaul Kocialkowski 253611c0d8fdSPaul Kocialkowski /* Gain */ 253711c0d8fdSPaul Kocialkowski 2538*3fdd94e2SDaniel Scally v4l2_ctrl_new_std(handler, ops, V4L2_CID_ANALOGUE_GAIN, 128, 2048, 128, 2539d938b2f2SDaniel Scally 128); 254011c0d8fdSPaul Kocialkowski 254111c0d8fdSPaul Kocialkowski /* White Balance */ 254211c0d8fdSPaul Kocialkowski 254311c0d8fdSPaul Kocialkowski v4l2_ctrl_new_std(handler, ops, V4L2_CID_RED_BALANCE, 1, 32767, 1, 254411c0d8fdSPaul Kocialkowski 1024); 254511c0d8fdSPaul Kocialkowski 254611c0d8fdSPaul Kocialkowski v4l2_ctrl_new_std(handler, ops, V4L2_CID_BLUE_BALANCE, 1, 32767, 1, 254711c0d8fdSPaul Kocialkowski 1024); 254811c0d8fdSPaul Kocialkowski 254911c0d8fdSPaul Kocialkowski /* Flip */ 255011c0d8fdSPaul Kocialkowski 255111c0d8fdSPaul Kocialkowski v4l2_ctrl_new_std(handler, ops, V4L2_CID_HFLIP, 0, 1, 1, 0); 255211c0d8fdSPaul Kocialkowski v4l2_ctrl_new_std(handler, ops, V4L2_CID_VFLIP, 0, 1, 1, 0); 255311c0d8fdSPaul Kocialkowski 255411c0d8fdSPaul Kocialkowski /* Test Pattern */ 255511c0d8fdSPaul Kocialkowski 255611c0d8fdSPaul Kocialkowski v4l2_ctrl_new_std_menu_items(handler, ops, V4L2_CID_TEST_PATTERN, 255711c0d8fdSPaul Kocialkowski ARRAY_SIZE(ov8865_test_pattern_menu) - 1, 255811c0d8fdSPaul Kocialkowski 0, 0, ov8865_test_pattern_menu); 255911c0d8fdSPaul Kocialkowski 25609293aafeSDaniel Scally /* Blanking */ 2561d84d4ceeSDaniel Scally hblank = mode->hts - mode->output_size_x; 2562d84d4ceeSDaniel Scally ctrls->hblank = v4l2_ctrl_new_std(handler, ops, V4L2_CID_HBLANK, hblank, 2563d84d4ceeSDaniel Scally hblank, 1, hblank); 2564d84d4ceeSDaniel Scally 2565d84d4ceeSDaniel Scally if (ctrls->hblank) 2566d84d4ceeSDaniel Scally ctrls->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; 2567d84d4ceeSDaniel Scally 25689293aafeSDaniel Scally vblank_max = OV8865_TIMING_MAX_VTS - mode->output_size_y; 25699293aafeSDaniel Scally vblank_def = mode->vts - mode->output_size_y; 25709293aafeSDaniel Scally ctrls->vblank = v4l2_ctrl_new_std(handler, ops, V4L2_CID_VBLANK, 25719293aafeSDaniel Scally OV8865_TIMING_MIN_VTS, vblank_max, 1, 25729293aafeSDaniel Scally vblank_def); 25739293aafeSDaniel Scally 257411c0d8fdSPaul Kocialkowski /* MIPI CSI-2 */ 257511c0d8fdSPaul Kocialkowski 257611c0d8fdSPaul Kocialkowski ctrls->link_freq = 257711c0d8fdSPaul Kocialkowski v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, 257811c0d8fdSPaul Kocialkowski ARRAY_SIZE(ov8865_link_freq_menu) - 1, 257911c0d8fdSPaul Kocialkowski 0, ov8865_link_freq_menu); 258011c0d8fdSPaul Kocialkowski 258111c0d8fdSPaul Kocialkowski ctrls->pixel_rate = 258211c0d8fdSPaul Kocialkowski v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, 1, 258311c0d8fdSPaul Kocialkowski INT_MAX, 1, 1); 258411c0d8fdSPaul Kocialkowski 25856eecfb34SDaniel Scally /* set properties from fwnode (e.g. rotation, orientation) */ 25866eecfb34SDaniel Scally ret = v4l2_fwnode_device_parse(sensor->dev, &props); 25876eecfb34SDaniel Scally if (ret) 25886eecfb34SDaniel Scally goto error_ctrls; 25896eecfb34SDaniel Scally 25906eecfb34SDaniel Scally ret = v4l2_ctrl_new_fwnode_properties(handler, ops, &props); 25916eecfb34SDaniel Scally if (ret) 25926eecfb34SDaniel Scally goto error_ctrls; 25936eecfb34SDaniel Scally 259411c0d8fdSPaul Kocialkowski if (handler->error) { 259511c0d8fdSPaul Kocialkowski ret = handler->error; 259611c0d8fdSPaul Kocialkowski goto error_ctrls; 259711c0d8fdSPaul Kocialkowski } 259811c0d8fdSPaul Kocialkowski 259911c0d8fdSPaul Kocialkowski ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; 260011c0d8fdSPaul Kocialkowski ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY; 260111c0d8fdSPaul Kocialkowski 260211c0d8fdSPaul Kocialkowski sensor->subdev.ctrl_handler = handler; 260311c0d8fdSPaul Kocialkowski 260411c0d8fdSPaul Kocialkowski return 0; 260511c0d8fdSPaul Kocialkowski 260611c0d8fdSPaul Kocialkowski error_ctrls: 260711c0d8fdSPaul Kocialkowski v4l2_ctrl_handler_free(handler); 260811c0d8fdSPaul Kocialkowski 260911c0d8fdSPaul Kocialkowski return ret; 261011c0d8fdSPaul Kocialkowski } 261111c0d8fdSPaul Kocialkowski 261211c0d8fdSPaul Kocialkowski /* Subdev Video Operations */ 261311c0d8fdSPaul Kocialkowski 261411c0d8fdSPaul Kocialkowski static int ov8865_s_stream(struct v4l2_subdev *subdev, int enable) 261511c0d8fdSPaul Kocialkowski { 261611c0d8fdSPaul Kocialkowski struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev); 261711c0d8fdSPaul Kocialkowski struct ov8865_state *state = &sensor->state; 261811c0d8fdSPaul Kocialkowski int ret; 261911c0d8fdSPaul Kocialkowski 262011c0d8fdSPaul Kocialkowski if (enable) { 2621586ee057SMauro Carvalho Chehab ret = pm_runtime_resume_and_get(sensor->dev); 2622586ee057SMauro Carvalho Chehab if (ret < 0) 262311c0d8fdSPaul Kocialkowski return ret; 262411c0d8fdSPaul Kocialkowski } 262511c0d8fdSPaul Kocialkowski 262611c0d8fdSPaul Kocialkowski mutex_lock(&sensor->mutex); 262711c0d8fdSPaul Kocialkowski ret = ov8865_sw_standby(sensor, !enable); 262811c0d8fdSPaul Kocialkowski mutex_unlock(&sensor->mutex); 262911c0d8fdSPaul Kocialkowski 263011c0d8fdSPaul Kocialkowski if (ret) 263111c0d8fdSPaul Kocialkowski return ret; 263211c0d8fdSPaul Kocialkowski 263311c0d8fdSPaul Kocialkowski state->streaming = !!enable; 263411c0d8fdSPaul Kocialkowski 263511c0d8fdSPaul Kocialkowski if (!enable) 263611c0d8fdSPaul Kocialkowski pm_runtime_put(sensor->dev); 263711c0d8fdSPaul Kocialkowski 263811c0d8fdSPaul Kocialkowski return 0; 263911c0d8fdSPaul Kocialkowski } 264011c0d8fdSPaul Kocialkowski 264111c0d8fdSPaul Kocialkowski static int ov8865_g_frame_interval(struct v4l2_subdev *subdev, 264211c0d8fdSPaul Kocialkowski struct v4l2_subdev_frame_interval *interval) 264311c0d8fdSPaul Kocialkowski { 264411c0d8fdSPaul Kocialkowski struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev); 264511c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode; 2646295786e5SDaniel Scally unsigned int framesize; 2647295786e5SDaniel Scally unsigned int fps; 264811c0d8fdSPaul Kocialkowski 264911c0d8fdSPaul Kocialkowski mutex_lock(&sensor->mutex); 265011c0d8fdSPaul Kocialkowski 265111c0d8fdSPaul Kocialkowski mode = sensor->state.mode; 2652295786e5SDaniel Scally framesize = mode->hts * (mode->output_size_y + 2653295786e5SDaniel Scally sensor->ctrls.vblank->val); 2654295786e5SDaniel Scally fps = DIV_ROUND_CLOSEST(sensor->ctrls.pixel_rate->val, framesize); 2655295786e5SDaniel Scally 2656295786e5SDaniel Scally interval->interval.numerator = 1; 2657295786e5SDaniel Scally interval->interval.denominator = fps; 265811c0d8fdSPaul Kocialkowski 265911c0d8fdSPaul Kocialkowski mutex_unlock(&sensor->mutex); 266011c0d8fdSPaul Kocialkowski 2661a1946cafSYang Li return 0; 266211c0d8fdSPaul Kocialkowski } 266311c0d8fdSPaul Kocialkowski 266411c0d8fdSPaul Kocialkowski static const struct v4l2_subdev_video_ops ov8865_subdev_video_ops = { 266511c0d8fdSPaul Kocialkowski .s_stream = ov8865_s_stream, 266611c0d8fdSPaul Kocialkowski .g_frame_interval = ov8865_g_frame_interval, 266711c0d8fdSPaul Kocialkowski .s_frame_interval = ov8865_g_frame_interval, 266811c0d8fdSPaul Kocialkowski }; 266911c0d8fdSPaul Kocialkowski 267011c0d8fdSPaul Kocialkowski /* Subdev Pad Operations */ 267111c0d8fdSPaul Kocialkowski 267211c0d8fdSPaul Kocialkowski static int ov8865_enum_mbus_code(struct v4l2_subdev *subdev, 26730d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 267411c0d8fdSPaul Kocialkowski struct v4l2_subdev_mbus_code_enum *code_enum) 267511c0d8fdSPaul Kocialkowski { 267611c0d8fdSPaul Kocialkowski if (code_enum->index >= ARRAY_SIZE(ov8865_mbus_codes)) 267711c0d8fdSPaul Kocialkowski return -EINVAL; 267811c0d8fdSPaul Kocialkowski 267911c0d8fdSPaul Kocialkowski code_enum->code = ov8865_mbus_codes[code_enum->index]; 268011c0d8fdSPaul Kocialkowski 268111c0d8fdSPaul Kocialkowski return 0; 268211c0d8fdSPaul Kocialkowski } 268311c0d8fdSPaul Kocialkowski 268411c0d8fdSPaul Kocialkowski static void ov8865_mbus_format_fill(struct v4l2_mbus_framefmt *mbus_format, 268511c0d8fdSPaul Kocialkowski u32 mbus_code, 268611c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode) 268711c0d8fdSPaul Kocialkowski { 268811c0d8fdSPaul Kocialkowski mbus_format->width = mode->output_size_x; 268911c0d8fdSPaul Kocialkowski mbus_format->height = mode->output_size_y; 269011c0d8fdSPaul Kocialkowski mbus_format->code = mbus_code; 269111c0d8fdSPaul Kocialkowski 269211c0d8fdSPaul Kocialkowski mbus_format->field = V4L2_FIELD_NONE; 269311c0d8fdSPaul Kocialkowski mbus_format->colorspace = V4L2_COLORSPACE_RAW; 269411c0d8fdSPaul Kocialkowski mbus_format->ycbcr_enc = 269511c0d8fdSPaul Kocialkowski V4L2_MAP_YCBCR_ENC_DEFAULT(mbus_format->colorspace); 269611c0d8fdSPaul Kocialkowski mbus_format->quantization = V4L2_QUANTIZATION_FULL_RANGE; 269711c0d8fdSPaul Kocialkowski mbus_format->xfer_func = 269811c0d8fdSPaul Kocialkowski V4L2_MAP_XFER_FUNC_DEFAULT(mbus_format->colorspace); 269911c0d8fdSPaul Kocialkowski } 270011c0d8fdSPaul Kocialkowski 270111c0d8fdSPaul Kocialkowski static int ov8865_get_fmt(struct v4l2_subdev *subdev, 27020d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 270311c0d8fdSPaul Kocialkowski struct v4l2_subdev_format *format) 270411c0d8fdSPaul Kocialkowski { 270511c0d8fdSPaul Kocialkowski struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev); 270611c0d8fdSPaul Kocialkowski struct v4l2_mbus_framefmt *mbus_format = &format->format; 270711c0d8fdSPaul Kocialkowski 270811c0d8fdSPaul Kocialkowski mutex_lock(&sensor->mutex); 270911c0d8fdSPaul Kocialkowski 271011c0d8fdSPaul Kocialkowski if (format->which == V4L2_SUBDEV_FORMAT_TRY) 27110d346d2aSTomi Valkeinen *mbus_format = *v4l2_subdev_get_try_format(subdev, sd_state, 271211c0d8fdSPaul Kocialkowski format->pad); 271311c0d8fdSPaul Kocialkowski else 271411c0d8fdSPaul Kocialkowski ov8865_mbus_format_fill(mbus_format, sensor->state.mbus_code, 271511c0d8fdSPaul Kocialkowski sensor->state.mode); 271611c0d8fdSPaul Kocialkowski 271711c0d8fdSPaul Kocialkowski mutex_unlock(&sensor->mutex); 271811c0d8fdSPaul Kocialkowski 271911c0d8fdSPaul Kocialkowski return 0; 272011c0d8fdSPaul Kocialkowski } 272111c0d8fdSPaul Kocialkowski 272211c0d8fdSPaul Kocialkowski static int ov8865_set_fmt(struct v4l2_subdev *subdev, 27230d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 272411c0d8fdSPaul Kocialkowski struct v4l2_subdev_format *format) 272511c0d8fdSPaul Kocialkowski { 272611c0d8fdSPaul Kocialkowski struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev); 272711c0d8fdSPaul Kocialkowski struct v4l2_mbus_framefmt *mbus_format = &format->format; 272811c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode; 272911c0d8fdSPaul Kocialkowski u32 mbus_code = 0; 2730d84d4ceeSDaniel Scally unsigned int hblank; 273111c0d8fdSPaul Kocialkowski unsigned int index; 2732ca28690eSDaniel Scally int exposure_max; 273311c0d8fdSPaul Kocialkowski int ret = 0; 273411c0d8fdSPaul Kocialkowski 273511c0d8fdSPaul Kocialkowski mutex_lock(&sensor->mutex); 273611c0d8fdSPaul Kocialkowski 273711c0d8fdSPaul Kocialkowski if (sensor->state.streaming) { 273811c0d8fdSPaul Kocialkowski ret = -EBUSY; 273911c0d8fdSPaul Kocialkowski goto complete; 274011c0d8fdSPaul Kocialkowski } 274111c0d8fdSPaul Kocialkowski 274211c0d8fdSPaul Kocialkowski /* Try to find requested mbus code. */ 274311c0d8fdSPaul Kocialkowski for (index = 0; index < ARRAY_SIZE(ov8865_mbus_codes); index++) { 274411c0d8fdSPaul Kocialkowski if (ov8865_mbus_codes[index] == mbus_format->code) { 274511c0d8fdSPaul Kocialkowski mbus_code = mbus_format->code; 274611c0d8fdSPaul Kocialkowski break; 274711c0d8fdSPaul Kocialkowski } 274811c0d8fdSPaul Kocialkowski } 274911c0d8fdSPaul Kocialkowski 275011c0d8fdSPaul Kocialkowski /* Fallback to default. */ 275111c0d8fdSPaul Kocialkowski if (!mbus_code) 275211c0d8fdSPaul Kocialkowski mbus_code = ov8865_mbus_codes[0]; 275311c0d8fdSPaul Kocialkowski 275411c0d8fdSPaul Kocialkowski /* Find the mode with nearest dimensions. */ 275511c0d8fdSPaul Kocialkowski mode = v4l2_find_nearest_size(ov8865_modes, ARRAY_SIZE(ov8865_modes), 275611c0d8fdSPaul Kocialkowski output_size_x, output_size_y, 275711c0d8fdSPaul Kocialkowski mbus_format->width, mbus_format->height); 275811c0d8fdSPaul Kocialkowski if (!mode) { 275911c0d8fdSPaul Kocialkowski ret = -EINVAL; 276011c0d8fdSPaul Kocialkowski goto complete; 276111c0d8fdSPaul Kocialkowski } 276211c0d8fdSPaul Kocialkowski 276311c0d8fdSPaul Kocialkowski ov8865_mbus_format_fill(mbus_format, mbus_code, mode); 276411c0d8fdSPaul Kocialkowski 276511c0d8fdSPaul Kocialkowski if (format->which == V4L2_SUBDEV_FORMAT_TRY) 27660d346d2aSTomi Valkeinen *v4l2_subdev_get_try_format(subdev, sd_state, format->pad) = 276711c0d8fdSPaul Kocialkowski *mbus_format; 276811c0d8fdSPaul Kocialkowski else if (sensor->state.mode != mode || 276911c0d8fdSPaul Kocialkowski sensor->state.mbus_code != mbus_code) 277011c0d8fdSPaul Kocialkowski ret = ov8865_state_configure(sensor, mode, mbus_code); 277111c0d8fdSPaul Kocialkowski 27729293aafeSDaniel Scally __v4l2_ctrl_modify_range(sensor->ctrls.vblank, OV8865_TIMING_MIN_VTS, 27739293aafeSDaniel Scally OV8865_TIMING_MAX_VTS - mode->output_size_y, 27749293aafeSDaniel Scally 1, mode->vts - mode->output_size_y); 27759293aafeSDaniel Scally 2776d84d4ceeSDaniel Scally hblank = mode->hts - mode->output_size_x; 2777d84d4ceeSDaniel Scally __v4l2_ctrl_modify_range(sensor->ctrls.hblank, hblank, hblank, 1, 2778d84d4ceeSDaniel Scally hblank); 2779d84d4ceeSDaniel Scally 2780ca28690eSDaniel Scally exposure_max = mode->vts - OV8865_INTEGRATION_TIME_MARGIN; 2781ca28690eSDaniel Scally __v4l2_ctrl_modify_range(sensor->ctrls.exposure, 2782ca28690eSDaniel Scally sensor->ctrls.exposure->minimum, exposure_max, 2783ca28690eSDaniel Scally sensor->ctrls.exposure->step, 2784ca28690eSDaniel Scally min(sensor->ctrls.exposure->val, 2785ca28690eSDaniel Scally exposure_max)); 2786ca28690eSDaniel Scally 278711c0d8fdSPaul Kocialkowski complete: 278811c0d8fdSPaul Kocialkowski mutex_unlock(&sensor->mutex); 278911c0d8fdSPaul Kocialkowski 279011c0d8fdSPaul Kocialkowski return ret; 279111c0d8fdSPaul Kocialkowski } 279211c0d8fdSPaul Kocialkowski 279311c0d8fdSPaul Kocialkowski static int ov8865_enum_frame_size(struct v4l2_subdev *subdev, 27940d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 279511c0d8fdSPaul Kocialkowski struct v4l2_subdev_frame_size_enum *size_enum) 279611c0d8fdSPaul Kocialkowski { 279711c0d8fdSPaul Kocialkowski const struct ov8865_mode *mode; 279811c0d8fdSPaul Kocialkowski 279911c0d8fdSPaul Kocialkowski if (size_enum->index >= ARRAY_SIZE(ov8865_modes)) 280011c0d8fdSPaul Kocialkowski return -EINVAL; 280111c0d8fdSPaul Kocialkowski 280211c0d8fdSPaul Kocialkowski mode = &ov8865_modes[size_enum->index]; 280311c0d8fdSPaul Kocialkowski 280411c0d8fdSPaul Kocialkowski size_enum->min_width = size_enum->max_width = mode->output_size_x; 280511c0d8fdSPaul Kocialkowski size_enum->min_height = size_enum->max_height = mode->output_size_y; 280611c0d8fdSPaul Kocialkowski 280711c0d8fdSPaul Kocialkowski return 0; 280811c0d8fdSPaul Kocialkowski } 280911c0d8fdSPaul Kocialkowski 2810acd25e22SDaniel Scally static void 2811acd25e22SDaniel Scally __ov8865_get_pad_crop(struct ov8865_sensor *sensor, 2812acd25e22SDaniel Scally struct v4l2_subdev_state *state, unsigned int pad, 2813acd25e22SDaniel Scally enum v4l2_subdev_format_whence which, struct v4l2_rect *r) 2814acd25e22SDaniel Scally { 2815acd25e22SDaniel Scally const struct ov8865_mode *mode = sensor->state.mode; 2816acd25e22SDaniel Scally 2817acd25e22SDaniel Scally switch (which) { 2818acd25e22SDaniel Scally case V4L2_SUBDEV_FORMAT_TRY: 2819acd25e22SDaniel Scally *r = *v4l2_subdev_get_try_crop(&sensor->subdev, state, pad); 2820acd25e22SDaniel Scally break; 2821acd25e22SDaniel Scally case V4L2_SUBDEV_FORMAT_ACTIVE: 2822acd25e22SDaniel Scally r->height = mode->output_size_y; 2823acd25e22SDaniel Scally r->width = mode->output_size_x; 2824acd25e22SDaniel Scally r->top = (OV8865_NATIVE_HEIGHT - mode->output_size_y) / 2; 2825acd25e22SDaniel Scally r->left = (OV8865_NATIVE_WIDTH - mode->output_size_x) / 2; 2826acd25e22SDaniel Scally break; 2827acd25e22SDaniel Scally } 2828acd25e22SDaniel Scally } 2829acd25e22SDaniel Scally 2830acd25e22SDaniel Scally static int ov8865_get_selection(struct v4l2_subdev *subdev, 2831acd25e22SDaniel Scally struct v4l2_subdev_state *state, 2832acd25e22SDaniel Scally struct v4l2_subdev_selection *sel) 2833acd25e22SDaniel Scally { 2834acd25e22SDaniel Scally struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev); 2835acd25e22SDaniel Scally 2836acd25e22SDaniel Scally switch (sel->target) { 2837acd25e22SDaniel Scally case V4L2_SEL_TGT_CROP: 2838acd25e22SDaniel Scally mutex_lock(&sensor->mutex); 2839acd25e22SDaniel Scally __ov8865_get_pad_crop(sensor, state, sel->pad, 2840acd25e22SDaniel Scally sel->which, &sel->r); 2841acd25e22SDaniel Scally mutex_unlock(&sensor->mutex); 2842acd25e22SDaniel Scally break; 2843acd25e22SDaniel Scally case V4L2_SEL_TGT_NATIVE_SIZE: 2844acd25e22SDaniel Scally sel->r.top = 0; 2845acd25e22SDaniel Scally sel->r.left = 0; 2846acd25e22SDaniel Scally sel->r.width = OV8865_NATIVE_WIDTH; 2847acd25e22SDaniel Scally sel->r.height = OV8865_NATIVE_HEIGHT; 2848acd25e22SDaniel Scally break; 2849acd25e22SDaniel Scally case V4L2_SEL_TGT_CROP_BOUNDS: 2850acd25e22SDaniel Scally case V4L2_SEL_TGT_CROP_DEFAULT: 2851acd25e22SDaniel Scally sel->r.top = OV8865_ACTIVE_START_TOP; 2852acd25e22SDaniel Scally sel->r.left = OV8865_ACTIVE_START_LEFT; 2853acd25e22SDaniel Scally sel->r.width = OV8865_ACTIVE_WIDTH; 2854acd25e22SDaniel Scally sel->r.height = OV8865_ACTIVE_HEIGHT; 2855acd25e22SDaniel Scally break; 2856acd25e22SDaniel Scally default: 2857acd25e22SDaniel Scally return -EINVAL; 2858acd25e22SDaniel Scally } 2859acd25e22SDaniel Scally 2860acd25e22SDaniel Scally return 0; 2861acd25e22SDaniel Scally } 2862acd25e22SDaniel Scally 286311c0d8fdSPaul Kocialkowski static const struct v4l2_subdev_pad_ops ov8865_subdev_pad_ops = { 286411c0d8fdSPaul Kocialkowski .enum_mbus_code = ov8865_enum_mbus_code, 286511c0d8fdSPaul Kocialkowski .get_fmt = ov8865_get_fmt, 286611c0d8fdSPaul Kocialkowski .set_fmt = ov8865_set_fmt, 286711c0d8fdSPaul Kocialkowski .enum_frame_size = ov8865_enum_frame_size, 2868acd25e22SDaniel Scally .get_selection = ov8865_get_selection, 2869acd25e22SDaniel Scally .set_selection = ov8865_get_selection, 287011c0d8fdSPaul Kocialkowski }; 287111c0d8fdSPaul Kocialkowski 287211c0d8fdSPaul Kocialkowski static const struct v4l2_subdev_ops ov8865_subdev_ops = { 287311c0d8fdSPaul Kocialkowski .video = &ov8865_subdev_video_ops, 287411c0d8fdSPaul Kocialkowski .pad = &ov8865_subdev_pad_ops, 287511c0d8fdSPaul Kocialkowski }; 287611c0d8fdSPaul Kocialkowski 287711c0d8fdSPaul Kocialkowski static int ov8865_suspend(struct device *dev) 287811c0d8fdSPaul Kocialkowski { 287911c0d8fdSPaul Kocialkowski struct i2c_client *client = to_i2c_client(dev); 288011c0d8fdSPaul Kocialkowski struct v4l2_subdev *subdev = i2c_get_clientdata(client); 288111c0d8fdSPaul Kocialkowski struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev); 288211c0d8fdSPaul Kocialkowski struct ov8865_state *state = &sensor->state; 288311c0d8fdSPaul Kocialkowski int ret = 0; 288411c0d8fdSPaul Kocialkowski 288511c0d8fdSPaul Kocialkowski mutex_lock(&sensor->mutex); 288611c0d8fdSPaul Kocialkowski 288711c0d8fdSPaul Kocialkowski if (state->streaming) { 288811c0d8fdSPaul Kocialkowski ret = ov8865_sw_standby(sensor, true); 288911c0d8fdSPaul Kocialkowski if (ret) 289011c0d8fdSPaul Kocialkowski goto complete; 289111c0d8fdSPaul Kocialkowski } 289211c0d8fdSPaul Kocialkowski 289311c0d8fdSPaul Kocialkowski ret = ov8865_sensor_power(sensor, false); 289411c0d8fdSPaul Kocialkowski if (ret) 289511c0d8fdSPaul Kocialkowski ov8865_sw_standby(sensor, false); 289611c0d8fdSPaul Kocialkowski 289711c0d8fdSPaul Kocialkowski complete: 289811c0d8fdSPaul Kocialkowski mutex_unlock(&sensor->mutex); 289911c0d8fdSPaul Kocialkowski 290011c0d8fdSPaul Kocialkowski return ret; 290111c0d8fdSPaul Kocialkowski } 290211c0d8fdSPaul Kocialkowski 290311c0d8fdSPaul Kocialkowski static int ov8865_resume(struct device *dev) 290411c0d8fdSPaul Kocialkowski { 290511c0d8fdSPaul Kocialkowski struct i2c_client *client = to_i2c_client(dev); 290611c0d8fdSPaul Kocialkowski struct v4l2_subdev *subdev = i2c_get_clientdata(client); 290711c0d8fdSPaul Kocialkowski struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev); 290811c0d8fdSPaul Kocialkowski struct ov8865_state *state = &sensor->state; 290911c0d8fdSPaul Kocialkowski int ret = 0; 291011c0d8fdSPaul Kocialkowski 291111c0d8fdSPaul Kocialkowski mutex_lock(&sensor->mutex); 291211c0d8fdSPaul Kocialkowski 291311c0d8fdSPaul Kocialkowski ret = ov8865_sensor_power(sensor, true); 291411c0d8fdSPaul Kocialkowski if (ret) 291511c0d8fdSPaul Kocialkowski goto complete; 291611c0d8fdSPaul Kocialkowski 291711c0d8fdSPaul Kocialkowski ret = ov8865_sensor_init(sensor); 291811c0d8fdSPaul Kocialkowski if (ret) 291911c0d8fdSPaul Kocialkowski goto error_power; 292011c0d8fdSPaul Kocialkowski 292111c0d8fdSPaul Kocialkowski ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler); 292211c0d8fdSPaul Kocialkowski if (ret) 292311c0d8fdSPaul Kocialkowski goto error_power; 292411c0d8fdSPaul Kocialkowski 292511c0d8fdSPaul Kocialkowski if (state->streaming) { 292611c0d8fdSPaul Kocialkowski ret = ov8865_sw_standby(sensor, false); 292711c0d8fdSPaul Kocialkowski if (ret) 292811c0d8fdSPaul Kocialkowski goto error_power; 292911c0d8fdSPaul Kocialkowski } 293011c0d8fdSPaul Kocialkowski 293111c0d8fdSPaul Kocialkowski goto complete; 293211c0d8fdSPaul Kocialkowski 293311c0d8fdSPaul Kocialkowski error_power: 293411c0d8fdSPaul Kocialkowski ov8865_sensor_power(sensor, false); 293511c0d8fdSPaul Kocialkowski 293611c0d8fdSPaul Kocialkowski complete: 293711c0d8fdSPaul Kocialkowski mutex_unlock(&sensor->mutex); 293811c0d8fdSPaul Kocialkowski 293911c0d8fdSPaul Kocialkowski return ret; 294011c0d8fdSPaul Kocialkowski } 294111c0d8fdSPaul Kocialkowski 294211c0d8fdSPaul Kocialkowski static int ov8865_probe(struct i2c_client *client) 294311c0d8fdSPaul Kocialkowski { 294411c0d8fdSPaul Kocialkowski struct device *dev = &client->dev; 294511c0d8fdSPaul Kocialkowski struct fwnode_handle *handle; 294611c0d8fdSPaul Kocialkowski struct ov8865_sensor *sensor; 294711c0d8fdSPaul Kocialkowski struct v4l2_subdev *subdev; 294811c0d8fdSPaul Kocialkowski struct media_pad *pad; 294973dcffebSDaniel Scally unsigned int rate = 0; 295073dcffebSDaniel Scally unsigned int i; 295111c0d8fdSPaul Kocialkowski int ret; 295211c0d8fdSPaul Kocialkowski 295311c0d8fdSPaul Kocialkowski sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); 295411c0d8fdSPaul Kocialkowski if (!sensor) 295511c0d8fdSPaul Kocialkowski return -ENOMEM; 295611c0d8fdSPaul Kocialkowski 295711c0d8fdSPaul Kocialkowski sensor->dev = dev; 295811c0d8fdSPaul Kocialkowski sensor->i2c_client = client; 295911c0d8fdSPaul Kocialkowski 296091f08141SDaniel Scally /* Regulators */ 296191f08141SDaniel Scally 296291f08141SDaniel Scally /* DVDD: digital core */ 296391f08141SDaniel Scally sensor->dvdd = devm_regulator_get(dev, "dvdd"); 296491f08141SDaniel Scally if (IS_ERR(sensor->dvdd)) 296591f08141SDaniel Scally return dev_err_probe(dev, PTR_ERR(sensor->dvdd), 296691f08141SDaniel Scally "cannot get DVDD regulator\n"); 296791f08141SDaniel Scally 296891f08141SDaniel Scally /* DOVDD: digital I/O */ 296991f08141SDaniel Scally sensor->dovdd = devm_regulator_get(dev, "dovdd"); 297091f08141SDaniel Scally if (IS_ERR(sensor->dovdd)) 297191f08141SDaniel Scally return dev_err_probe(dev, PTR_ERR(sensor->dovdd), 297291f08141SDaniel Scally "cannot get DOVDD regulator\n"); 297391f08141SDaniel Scally 297491f08141SDaniel Scally /* AVDD: analog */ 297591f08141SDaniel Scally sensor->avdd = devm_regulator_get(dev, "avdd"); 297691f08141SDaniel Scally if (IS_ERR(sensor->avdd)) 297791f08141SDaniel Scally return dev_err_probe(dev, PTR_ERR(sensor->avdd), 297891f08141SDaniel Scally "cannot get AVDD (analog) regulator\n"); 297991f08141SDaniel Scally 298011c0d8fdSPaul Kocialkowski /* Graph Endpoint */ 298111c0d8fdSPaul Kocialkowski 298211c0d8fdSPaul Kocialkowski handle = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); 2983ba0c8045SDaniel Scally if (!handle) 2984ba0c8045SDaniel Scally return -EPROBE_DEFER; 298511c0d8fdSPaul Kocialkowski 298611c0d8fdSPaul Kocialkowski sensor->endpoint.bus_type = V4L2_MBUS_CSI2_DPHY; 298711c0d8fdSPaul Kocialkowski 298811c0d8fdSPaul Kocialkowski ret = v4l2_fwnode_endpoint_alloc_parse(handle, &sensor->endpoint); 298911c0d8fdSPaul Kocialkowski fwnode_handle_put(handle); 299011c0d8fdSPaul Kocialkowski if (ret) { 299111c0d8fdSPaul Kocialkowski dev_err(dev, "failed to parse endpoint node\n"); 299211c0d8fdSPaul Kocialkowski return ret; 299311c0d8fdSPaul Kocialkowski } 299411c0d8fdSPaul Kocialkowski 299511c0d8fdSPaul Kocialkowski /* GPIOs */ 299611c0d8fdSPaul Kocialkowski 299711c0d8fdSPaul Kocialkowski sensor->powerdown = devm_gpiod_get_optional(dev, "powerdown", 299811c0d8fdSPaul Kocialkowski GPIOD_OUT_HIGH); 299911c0d8fdSPaul Kocialkowski if (IS_ERR(sensor->powerdown)) { 300011c0d8fdSPaul Kocialkowski ret = PTR_ERR(sensor->powerdown); 300111c0d8fdSPaul Kocialkowski goto error_endpoint; 300211c0d8fdSPaul Kocialkowski } 300311c0d8fdSPaul Kocialkowski 300411c0d8fdSPaul Kocialkowski sensor->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); 300511c0d8fdSPaul Kocialkowski if (IS_ERR(sensor->reset)) { 300611c0d8fdSPaul Kocialkowski ret = PTR_ERR(sensor->reset); 300711c0d8fdSPaul Kocialkowski goto error_endpoint; 300811c0d8fdSPaul Kocialkowski } 300911c0d8fdSPaul Kocialkowski 301011c0d8fdSPaul Kocialkowski /* External Clock */ 301111c0d8fdSPaul Kocialkowski 301211c0d8fdSPaul Kocialkowski sensor->extclk = devm_clk_get(dev, NULL); 301373dcffebSDaniel Scally if (PTR_ERR(sensor->extclk) == -ENOENT) { 301473dcffebSDaniel Scally dev_info(dev, "no external clock found, continuing...\n"); 301573dcffebSDaniel Scally sensor->extclk = NULL; 301673dcffebSDaniel Scally } else if (IS_ERR(sensor->extclk)) { 301711c0d8fdSPaul Kocialkowski dev_err(dev, "failed to get external clock\n"); 301811c0d8fdSPaul Kocialkowski ret = PTR_ERR(sensor->extclk); 301911c0d8fdSPaul Kocialkowski goto error_endpoint; 302011c0d8fdSPaul Kocialkowski } 302111c0d8fdSPaul Kocialkowski 302273dcffebSDaniel Scally /* 302373dcffebSDaniel Scally * We could have either a 24MHz or 19.2MHz clock rate from either dt or 302473dcffebSDaniel Scally * ACPI...but we also need to support the weird IPU3 case which will 302573dcffebSDaniel Scally * have an external clock AND a clock-frequency property. Check for the 302673dcffebSDaniel Scally * clock-frequency property and if found, set that rate if we managed 302773dcffebSDaniel Scally * to acquire a clock. This should cover the ACPI case. If the system 302873dcffebSDaniel Scally * uses devicetree then the configured rate should already be set, so 302973dcffebSDaniel Scally * we can just read it. 303073dcffebSDaniel Scally */ 303173dcffebSDaniel Scally ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", 303273dcffebSDaniel Scally &rate); 303373dcffebSDaniel Scally if (!ret && sensor->extclk) { 303473dcffebSDaniel Scally ret = clk_set_rate(sensor->extclk, rate); 303573dcffebSDaniel Scally if (ret) 303673dcffebSDaniel Scally return dev_err_probe(dev, ret, 303773dcffebSDaniel Scally "failed to set clock rate\n"); 303873dcffebSDaniel Scally } else if (ret && !sensor->extclk) { 303973dcffebSDaniel Scally return dev_err_probe(dev, ret, "invalid clock config\n"); 304073dcffebSDaniel Scally } 304173dcffebSDaniel Scally 304273dcffebSDaniel Scally sensor->extclk_rate = rate ? rate : clk_get_rate(sensor->extclk); 304373dcffebSDaniel Scally 304473dcffebSDaniel Scally for (i = 0; i < ARRAY_SIZE(supported_extclk_rates); i++) { 304573dcffebSDaniel Scally if (sensor->extclk_rate == supported_extclk_rates[i]) 304673dcffebSDaniel Scally break; 304773dcffebSDaniel Scally } 304873dcffebSDaniel Scally 304973dcffebSDaniel Scally if (i == ARRAY_SIZE(supported_extclk_rates)) { 305073dcffebSDaniel Scally dev_err(dev, "clock rate %lu Hz is unsupported\n", 305173dcffebSDaniel Scally sensor->extclk_rate); 305211c0d8fdSPaul Kocialkowski ret = -EINVAL; 305311c0d8fdSPaul Kocialkowski goto error_endpoint; 305411c0d8fdSPaul Kocialkowski } 305511c0d8fdSPaul Kocialkowski 305673dcffebSDaniel Scally sensor->pll_configs = ov8865_pll_configs[i]; 305773dcffebSDaniel Scally 305811c0d8fdSPaul Kocialkowski /* Subdev, entity and pad */ 305911c0d8fdSPaul Kocialkowski 306011c0d8fdSPaul Kocialkowski subdev = &sensor->subdev; 306111c0d8fdSPaul Kocialkowski v4l2_i2c_subdev_init(subdev, client, &ov8865_subdev_ops); 306211c0d8fdSPaul Kocialkowski 306311c0d8fdSPaul Kocialkowski subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 306411c0d8fdSPaul Kocialkowski subdev->entity.function = MEDIA_ENT_F_CAM_SENSOR; 306511c0d8fdSPaul Kocialkowski 306611c0d8fdSPaul Kocialkowski pad = &sensor->pad; 306711c0d8fdSPaul Kocialkowski pad->flags = MEDIA_PAD_FL_SOURCE; 306811c0d8fdSPaul Kocialkowski 306911c0d8fdSPaul Kocialkowski ret = media_entity_pads_init(&subdev->entity, 1, pad); 307011c0d8fdSPaul Kocialkowski if (ret) 307111c0d8fdSPaul Kocialkowski goto error_entity; 307211c0d8fdSPaul Kocialkowski 307311c0d8fdSPaul Kocialkowski /* Mutex */ 307411c0d8fdSPaul Kocialkowski 307511c0d8fdSPaul Kocialkowski mutex_init(&sensor->mutex); 307611c0d8fdSPaul Kocialkowski 307711c0d8fdSPaul Kocialkowski /* Sensor */ 307811c0d8fdSPaul Kocialkowski 307911c0d8fdSPaul Kocialkowski ret = ov8865_ctrls_init(sensor); 308011c0d8fdSPaul Kocialkowski if (ret) 308111c0d8fdSPaul Kocialkowski goto error_mutex; 308211c0d8fdSPaul Kocialkowski 30836e1c9bc9SHans de Goede mutex_lock(&sensor->mutex); 308411c0d8fdSPaul Kocialkowski ret = ov8865_state_init(sensor); 30856e1c9bc9SHans de Goede mutex_unlock(&sensor->mutex); 308611c0d8fdSPaul Kocialkowski if (ret) 308711c0d8fdSPaul Kocialkowski goto error_ctrls; 308811c0d8fdSPaul Kocialkowski 308911c0d8fdSPaul Kocialkowski /* Runtime PM */ 309011c0d8fdSPaul Kocialkowski 309111c0d8fdSPaul Kocialkowski pm_runtime_set_suspended(sensor->dev); 3092d2484fbfSDaniel Scally pm_runtime_enable(sensor->dev); 309311c0d8fdSPaul Kocialkowski 309411c0d8fdSPaul Kocialkowski /* V4L2 subdev register */ 309511c0d8fdSPaul Kocialkowski 309615786f7bSSakari Ailus ret = v4l2_async_register_subdev_sensor(subdev); 309711c0d8fdSPaul Kocialkowski if (ret) 309811c0d8fdSPaul Kocialkowski goto error_pm; 309911c0d8fdSPaul Kocialkowski 310011c0d8fdSPaul Kocialkowski return 0; 310111c0d8fdSPaul Kocialkowski 310211c0d8fdSPaul Kocialkowski error_pm: 310311c0d8fdSPaul Kocialkowski pm_runtime_disable(sensor->dev); 310411c0d8fdSPaul Kocialkowski 310511c0d8fdSPaul Kocialkowski error_ctrls: 310611c0d8fdSPaul Kocialkowski v4l2_ctrl_handler_free(&sensor->ctrls.handler); 310711c0d8fdSPaul Kocialkowski 310811c0d8fdSPaul Kocialkowski error_mutex: 310911c0d8fdSPaul Kocialkowski mutex_destroy(&sensor->mutex); 311011c0d8fdSPaul Kocialkowski 311111c0d8fdSPaul Kocialkowski error_entity: 311211c0d8fdSPaul Kocialkowski media_entity_cleanup(&sensor->subdev.entity); 311311c0d8fdSPaul Kocialkowski 311411c0d8fdSPaul Kocialkowski error_endpoint: 311511c0d8fdSPaul Kocialkowski v4l2_fwnode_endpoint_free(&sensor->endpoint); 311611c0d8fdSPaul Kocialkowski 311711c0d8fdSPaul Kocialkowski return ret; 311811c0d8fdSPaul Kocialkowski } 311911c0d8fdSPaul Kocialkowski 312011c0d8fdSPaul Kocialkowski static int ov8865_remove(struct i2c_client *client) 312111c0d8fdSPaul Kocialkowski { 312211c0d8fdSPaul Kocialkowski struct v4l2_subdev *subdev = i2c_get_clientdata(client); 312311c0d8fdSPaul Kocialkowski struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev); 312411c0d8fdSPaul Kocialkowski 312511c0d8fdSPaul Kocialkowski v4l2_async_unregister_subdev(subdev); 312611c0d8fdSPaul Kocialkowski pm_runtime_disable(sensor->dev); 312711c0d8fdSPaul Kocialkowski v4l2_ctrl_handler_free(&sensor->ctrls.handler); 312811c0d8fdSPaul Kocialkowski mutex_destroy(&sensor->mutex); 312911c0d8fdSPaul Kocialkowski media_entity_cleanup(&subdev->entity); 313011c0d8fdSPaul Kocialkowski 313111c0d8fdSPaul Kocialkowski v4l2_fwnode_endpoint_free(&sensor->endpoint); 313211c0d8fdSPaul Kocialkowski 313311c0d8fdSPaul Kocialkowski return 0; 313411c0d8fdSPaul Kocialkowski } 313511c0d8fdSPaul Kocialkowski 313611c0d8fdSPaul Kocialkowski static const struct dev_pm_ops ov8865_pm_ops = { 313711c0d8fdSPaul Kocialkowski SET_RUNTIME_PM_OPS(ov8865_suspend, ov8865_resume, NULL) 313811c0d8fdSPaul Kocialkowski }; 313911c0d8fdSPaul Kocialkowski 3140dc69bc7aSDaniel Scally static const struct acpi_device_id ov8865_acpi_match[] = { 3141dc69bc7aSDaniel Scally {"INT347A"}, 3142dc69bc7aSDaniel Scally { } 3143dc69bc7aSDaniel Scally }; 3144dc69bc7aSDaniel Scally MODULE_DEVICE_TABLE(acpi, ov8865_acpi_match); 3145dc69bc7aSDaniel Scally 314611c0d8fdSPaul Kocialkowski static const struct of_device_id ov8865_of_match[] = { 314711c0d8fdSPaul Kocialkowski { .compatible = "ovti,ov8865" }, 314811c0d8fdSPaul Kocialkowski { } 314911c0d8fdSPaul Kocialkowski }; 315011c0d8fdSPaul Kocialkowski MODULE_DEVICE_TABLE(of, ov8865_of_match); 315111c0d8fdSPaul Kocialkowski 315211c0d8fdSPaul Kocialkowski static struct i2c_driver ov8865_driver = { 315311c0d8fdSPaul Kocialkowski .driver = { 315411c0d8fdSPaul Kocialkowski .name = "ov8865", 315511c0d8fdSPaul Kocialkowski .of_match_table = ov8865_of_match, 3156dc69bc7aSDaniel Scally .acpi_match_table = ov8865_acpi_match, 315711c0d8fdSPaul Kocialkowski .pm = &ov8865_pm_ops, 315811c0d8fdSPaul Kocialkowski }, 315911c0d8fdSPaul Kocialkowski .probe_new = ov8865_probe, 316011c0d8fdSPaul Kocialkowski .remove = ov8865_remove, 316111c0d8fdSPaul Kocialkowski }; 316211c0d8fdSPaul Kocialkowski 316311c0d8fdSPaul Kocialkowski module_i2c_driver(ov8865_driver); 316411c0d8fdSPaul Kocialkowski 316511c0d8fdSPaul Kocialkowski MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>"); 316611c0d8fdSPaul Kocialkowski MODULE_DESCRIPTION("V4L2 driver for the OmniVision OV8865 image sensor"); 316711c0d8fdSPaul Kocialkowski MODULE_LICENSE("GPL v2"); 3168