1*fa9e6df6SHardevsinh Palaniya // SPDX-License-Identifier: GPL-2.0 2*fa9e6df6SHardevsinh Palaniya /* 3*fa9e6df6SHardevsinh Palaniya * V4L2 Support for the OV2735 4*fa9e6df6SHardevsinh Palaniya * 5*fa9e6df6SHardevsinh Palaniya * Copyright (C) 2025 Silicon Signals Pvt. Ltd. 6*fa9e6df6SHardevsinh Palaniya * 7*fa9e6df6SHardevsinh Palaniya * Based on Rockchip ov2735 Camera Driver 8*fa9e6df6SHardevsinh Palaniya * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd. 9*fa9e6df6SHardevsinh Palaniya * 10*fa9e6df6SHardevsinh Palaniya * Inspired from ov8858, imx219, imx283 camera drivers. 11*fa9e6df6SHardevsinh Palaniya */ 12*fa9e6df6SHardevsinh Palaniya 13*fa9e6df6SHardevsinh Palaniya #include <linux/array_size.h> 14*fa9e6df6SHardevsinh Palaniya #include <linux/bitops.h> 15*fa9e6df6SHardevsinh Palaniya #include <linux/cleanup.h> 16*fa9e6df6SHardevsinh Palaniya #include <linux/clk.h> 17*fa9e6df6SHardevsinh Palaniya #include <linux/container_of.h> 18*fa9e6df6SHardevsinh Palaniya #include <linux/delay.h> 19*fa9e6df6SHardevsinh Palaniya #include <linux/device/devres.h> 20*fa9e6df6SHardevsinh Palaniya #include <linux/err.h> 21*fa9e6df6SHardevsinh Palaniya #include <linux/gpio/consumer.h> 22*fa9e6df6SHardevsinh Palaniya #include <linux/i2c.h> 23*fa9e6df6SHardevsinh Palaniya #include <linux/module.h> 24*fa9e6df6SHardevsinh Palaniya #include <linux/mutex.h> 25*fa9e6df6SHardevsinh Palaniya #include <linux/pm_runtime.h> 26*fa9e6df6SHardevsinh Palaniya #include <linux/property.h> 27*fa9e6df6SHardevsinh Palaniya #include <linux/regulator/consumer.h> 28*fa9e6df6SHardevsinh Palaniya #include <linux/units.h> 29*fa9e6df6SHardevsinh Palaniya #include <linux/types.h> 30*fa9e6df6SHardevsinh Palaniya #include <linux/time.h> 31*fa9e6df6SHardevsinh Palaniya 32*fa9e6df6SHardevsinh Palaniya #include <media/v4l2-cci.h> 33*fa9e6df6SHardevsinh Palaniya #include <media/v4l2-ctrls.h> 34*fa9e6df6SHardevsinh Palaniya #include <media/v4l2-device.h> 35*fa9e6df6SHardevsinh Palaniya #include <media/v4l2-fwnode.h> 36*fa9e6df6SHardevsinh Palaniya #include <media/v4l2-mediabus.h> 37*fa9e6df6SHardevsinh Palaniya 38*fa9e6df6SHardevsinh Palaniya #define OV2735_XCLK_FREQ (24 * HZ_PER_MHZ) 39*fa9e6df6SHardevsinh Palaniya 40*fa9e6df6SHardevsinh Palaniya /* Add page number in CCI private bits [31:28] of the register address */ 41*fa9e6df6SHardevsinh Palaniya #define OV2735_PAGE_REG8(p, x) (((p) << CCI_REG_PRIVATE_SHIFT) | CCI_REG8(x)) 42*fa9e6df6SHardevsinh Palaniya #define OV2735_PAGE_REG16(p, x) (((p) << CCI_REG_PRIVATE_SHIFT) | CCI_REG16(x)) 43*fa9e6df6SHardevsinh Palaniya 44*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PAGE_SELECT CCI_REG8(0xfd) 45*fa9e6df6SHardevsinh Palaniya 46*fa9e6df6SHardevsinh Palaniya /* Page 0 */ 47*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_CHIPID OV2735_PAGE_REG16(0x00, 0x02) 48*fa9e6df6SHardevsinh Palaniya #define OV2735_CHIPID 0x2735 49*fa9e6df6SHardevsinh Palaniya 50*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_SOFT_RESET OV2735_PAGE_REG8(0x00, 0x20) 51*fa9e6df6SHardevsinh Palaniya 52*fa9e6df6SHardevsinh Palaniya /* Clock Settings */ 53*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PLL_CTRL OV2735_PAGE_REG8(0x00, 0x2f) 54*fa9e6df6SHardevsinh Palaniya #define OV2735_PLL_CTRL_ENABLE 0x7f 55*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PLL_OUTDIV OV2735_PAGE_REG8(0x00, 0x34) 56*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_CLK_MODE OV2735_PAGE_REG8(0x00, 0x30) 57*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_CLOCK_REG1 OV2735_PAGE_REG8(0x00, 0x33) 58*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_CLOCK_REG2 OV2735_PAGE_REG8(0x00, 0x35) 59*fa9e6df6SHardevsinh Palaniya 60*fa9e6df6SHardevsinh Palaniya /* Page 1 */ 61*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_STREAM_CTRL OV2735_PAGE_REG8(0x01, 0xa0) 62*fa9e6df6SHardevsinh Palaniya #define OV2735_STREAM_CTRL_ON 0x01 63*fa9e6df6SHardevsinh Palaniya #define OV2735_STREAM_CTRL_OFF 0x00 64*fa9e6df6SHardevsinh Palaniya 65*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_UPDOWN_MIRROR OV2735_PAGE_REG8(0x01, 0x3f) 66*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_BINNING_DAC_CODE_MODE OV2735_PAGE_REG8(0x01, 0x30) 67*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_FRAME_LENGTH OV2735_PAGE_REG16(0x01, 0x0e) 68*fa9e6df6SHardevsinh Palaniya #define OV2735_FRAME_LENGTH_MAX 0x0fff 69*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_FRAME_EXP_SEPERATE_EN OV2735_PAGE_REG8(0x01, 0x0d) 70*fa9e6df6SHardevsinh Palaniya #define OV2735_FRAME_EXP_SEPERATE_EN 0x10 71*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_FRAME_SYNC OV2735_PAGE_REG8(0x01, 0x01) 72*fa9e6df6SHardevsinh Palaniya 73*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_HBLANK OV2735_PAGE_REG16(0x01, 0x09) 74*fa9e6df6SHardevsinh Palaniya 75*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_HS_MIPI OV2735_PAGE_REG8(0x01, 0xb1) 76*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_MIPI_CTRL1 OV2735_PAGE_REG8(0x01, 0x92) 77*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_MIPI_CTRL2 OV2735_PAGE_REG8(0x01, 0x94) 78*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_MIPI_CTRL3 OV2735_PAGE_REG8(0x01, 0xa1) 79*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_MIPI_CTRL4 OV2735_PAGE_REG8(0x01, 0xb2) 80*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_MIPI_CTRL5 OV2735_PAGE_REG8(0x01, 0xb3) 81*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_MIPI_CTRL6 OV2735_PAGE_REG8(0x01, 0xb4) 82*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_MIPI_CTRL7 OV2735_PAGE_REG8(0x01, 0xb5) 83*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_HIGH_SPEED OV2735_PAGE_REG8(0x01, 0x9d) 84*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PREPARE OV2735_PAGE_REG8(0x01, 0x95) 85*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_R_HS_ZERO OV2735_PAGE_REG8(0x01, 0x96) 86*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_TRAIL OV2735_PAGE_REG8(0x01, 0x98) 87*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_R_CLK_ZERO OV2735_PAGE_REG8(0x01, 0x9c) 88*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_MIPI_COLOMN_NUMBER OV2735_PAGE_REG16(0x01, 0x8e) 89*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_MIPI_LINE_NUMBER OV2735_PAGE_REG16(0x01, 0x90) 90*fa9e6df6SHardevsinh Palaniya 91*fa9e6df6SHardevsinh Palaniya /* Timing control registers */ 92*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_TIMING_CTRL2 OV2735_PAGE_REG8(0x01, 0x1a) 93*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_TIMING_CTRL3 OV2735_PAGE_REG8(0x01, 0x1c) 94*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_TIMING_CTRL1 OV2735_PAGE_REG8(0x01, 0x16) 95*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_RST_NUM OV2735_PAGE_REG16(0x01, 0x10) 96*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_RST_NUM2 OV2735_PAGE_REG16(0x01, 0x32) 97*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_BOOST_EN OV2735_PAGE_REG8(0x01, 0xd0) 98*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_B2_NUM OV2735_PAGE_REG16(0x01, 0xd1) 99*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_B4_NUM OV2735_PAGE_REG16(0x01, 0xd3) 100*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PIXEL_CYCLE_P0 OV2735_PAGE_REG8(0x01, 0x50) 101*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PIXEL_CYCLE_P1 OV2735_PAGE_REG8(0x01, 0x51) 102*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PIXEL_CYCLE_P2 OV2735_PAGE_REG8(0x01, 0x52) 103*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PIXEL_CYCLE_P3 OV2735_PAGE_REG8(0x01, 0x53) 104*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PIXEL_CYCLE_P5 OV2735_PAGE_REG8(0x01, 0x55) 105*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PIXEL_CYCLE_P7 OV2735_PAGE_REG16(0x01, 0x57) 106*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PIXEL_CYCLE_P9 OV2735_PAGE_REG8(0x01, 0x5a) 107*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PIXEL_CYCLE_P10 OV2735_PAGE_REG8(0x01, 0x5b) 108*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PIXEL_CYCLE_P12 OV2735_PAGE_REG8(0x01, 0x5d) 109*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PIXEL_CYCLE_P18 OV2735_PAGE_REG8(0x01, 0x64) 110*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PIXEL_CYCLE_P20 OV2735_PAGE_REG8(0x01, 0x66) 111*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PIXEL_CYCLE_P22 OV2735_PAGE_REG8(0x01, 0x68) 112*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PIXEL_CYCLE_P33 OV2735_PAGE_REG16(0x01, 0x74) 113*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PIXEL_CYCLE_P34 OV2735_PAGE_REG8(0x01, 0x76) 114*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PIXEL_CYCLE_P35_P36 OV2735_PAGE_REG8(0x01, 0x77) 115*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PIXEL_CYCLE_P37_P38 OV2735_PAGE_REG8(0x01, 0x78) 116*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PIXEL_CYCLE_P31 OV2735_PAGE_REG8(0x01, 0x72) 117*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PIXEL_CYCLE_P32 OV2735_PAGE_REG8(0x01, 0x73) 118*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PIXEL_CYCLE_P44 OV2735_PAGE_REG8(0x01, 0x7d) 119*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PIXEL_CYCLE_P45 OV2735_PAGE_REG8(0x01, 0x7e) 120*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PIXEL_BIAS_CTRL_RH_RL OV2735_PAGE_REG8(0x01, 0x8a) 121*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PIXEL_BIAS_CTRL_SH_SL OV2735_PAGE_REG8(0x01, 0x8b) 122*fa9e6df6SHardevsinh Palaniya 123*fa9e6df6SHardevsinh Palaniya /* Analog Control registers */ 124*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_ICOMP OV2735_PAGE_REG8(0x01, 0x19) 125*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_PCP_RST_SEL OV2735_PAGE_REG8(0x01, 0x21) 126*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_VNCP OV2735_PAGE_REG8(0x01, 0x20) 127*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_ANALOG_CTRL3 OV2735_PAGE_REG8(0x01, 0x25) 128*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_ANALOG_CTRL4 OV2735_PAGE_REG8(0x01, 0x26) 129*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_ANALOG_CTRL5 OV2735_PAGE_REG8(0x01, 0x29) 130*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_ANALOG_CTRL6 OV2735_PAGE_REG8(0x01, 0x2a) 131*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_ANALOG_CTRL8 OV2735_PAGE_REG8(0x01, 0x2c) 132*fa9e6df6SHardevsinh Palaniya 133*fa9e6df6SHardevsinh Palaniya /* BLC registers */ 134*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_BLC_GAIN_BLUE OV2735_PAGE_REG8(0x01, 0x86) 135*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_BLC_GAIN_RED OV2735_PAGE_REG8(0x01, 0x87) 136*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_BLC_GAIN_GR OV2735_PAGE_REG8(0x01, 0x88) 137*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_BLC_GAIN_GB OV2735_PAGE_REG8(0x01, 0x89) 138*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_GB_SUBOFFSET OV2735_PAGE_REG8(0x01, 0xf0) 139*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_BLUE_SUBOFFSET OV2735_PAGE_REG8(0x01, 0xf1) 140*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_RED_SUBOFFSET OV2735_PAGE_REG8(0x01, 0xf2) 141*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_GR_SUBOFFSET OV2735_PAGE_REG8(0x01, 0xf3) 142*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_BLC_BPC_TH_P OV2735_PAGE_REG8(0x01, 0xfc) 143*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_BLC_BPC_TH_N OV2735_PAGE_REG8(0x01, 0xfe) 144*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_ABL OV2735_PAGE_REG8(0x01, 0xfb) 145*fa9e6df6SHardevsinh Palaniya 146*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_TEST_PATTERN OV2735_PAGE_REG8(0x01, 0xb2) 147*fa9e6df6SHardevsinh Palaniya #define OV2735_TEST_PATTERN_ENABLE 0x01 148*fa9e6df6SHardevsinh Palaniya #define OV2735_TEST_PATTERN_DISABLE 0xfe 149*fa9e6df6SHardevsinh Palaniya 150*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_LONG_EXPOSURE OV2735_PAGE_REG16(0x01, 0x03) 151*fa9e6df6SHardevsinh Palaniya #define OV2735_EXPOSURE_MIN 4 152*fa9e6df6SHardevsinh Palaniya #define OV2735_EXPOSURE_STEP 1 153*fa9e6df6SHardevsinh Palaniya #define OV2735_EXPOSURE_MARGIN 4 154*fa9e6df6SHardevsinh Palaniya 155*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_ANALOG_GAIN OV2735_PAGE_REG8(0x01, 0x24) 156*fa9e6df6SHardevsinh Palaniya #define OV2735_ANALOG_GAIN_MIN 0x10 157*fa9e6df6SHardevsinh Palaniya #define OV2735_ANALOG_GAIN_MAX 0xff 158*fa9e6df6SHardevsinh Palaniya #define OV2735_ANALOG_GAIN_STEP 1 159*fa9e6df6SHardevsinh Palaniya #define OV2735_ANALOG_GAIN_DEFAULT 0x10 160*fa9e6df6SHardevsinh Palaniya 161*fa9e6df6SHardevsinh Palaniya /* Page 2 */ 162*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_V_START OV2735_PAGE_REG16(0x02, 0xa0) 163*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_V_SIZE OV2735_PAGE_REG16(0x02, 0xa2) 164*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_H_START OV2735_PAGE_REG16(0x02, 0xa4) 165*fa9e6df6SHardevsinh Palaniya #define OV2735_REG_H_SIZE OV2735_PAGE_REG16(0x02, 0xa6) 166*fa9e6df6SHardevsinh Palaniya 167*fa9e6df6SHardevsinh Palaniya #define OV2735_LINK_FREQ_420MHZ (420 * HZ_PER_MHZ) 168*fa9e6df6SHardevsinh Palaniya #define OV2735_PIXEL_RATE (168 * HZ_PER_MHZ) 169*fa9e6df6SHardevsinh Palaniya 170*fa9e6df6SHardevsinh Palaniya /* OV2735 native and active pixel array size */ 171*fa9e6df6SHardevsinh Palaniya static const struct v4l2_rect ov2735_native_area = { 172*fa9e6df6SHardevsinh Palaniya .top = 0, 173*fa9e6df6SHardevsinh Palaniya .left = 0, 174*fa9e6df6SHardevsinh Palaniya .width = 1936, 175*fa9e6df6SHardevsinh Palaniya .height = 1096, 176*fa9e6df6SHardevsinh Palaniya }; 177*fa9e6df6SHardevsinh Palaniya 178*fa9e6df6SHardevsinh Palaniya static const struct v4l2_rect ov2735_active_area = { 179*fa9e6df6SHardevsinh Palaniya .top = 8, 180*fa9e6df6SHardevsinh Palaniya .left = 8, 181*fa9e6df6SHardevsinh Palaniya .width = 1920, 182*fa9e6df6SHardevsinh Palaniya .height = 1080, 183*fa9e6df6SHardevsinh Palaniya }; 184*fa9e6df6SHardevsinh Palaniya 185*fa9e6df6SHardevsinh Palaniya static const char * const ov2735_supply_name[] = { 186*fa9e6df6SHardevsinh Palaniya "avdd", /* Analog power */ 187*fa9e6df6SHardevsinh Palaniya "dovdd", /* Digital I/O power */ 188*fa9e6df6SHardevsinh Palaniya "dvdd", /* Digital core power */ 189*fa9e6df6SHardevsinh Palaniya }; 190*fa9e6df6SHardevsinh Palaniya 191*fa9e6df6SHardevsinh Palaniya /* PLL_OUT = [PLL_IN * (pll_nc +3)] / [(pll_mc + 1) * (pll_outdiv + 1)] */ 192*fa9e6df6SHardevsinh Palaniya struct ov2735_pll_parameters { 193*fa9e6df6SHardevsinh Palaniya u8 pll_nc; 194*fa9e6df6SHardevsinh Palaniya u8 pll_mc; 195*fa9e6df6SHardevsinh Palaniya u8 pll_outdiv; 196*fa9e6df6SHardevsinh Palaniya }; 197*fa9e6df6SHardevsinh Palaniya 198*fa9e6df6SHardevsinh Palaniya struct ov2735 { 199*fa9e6df6SHardevsinh Palaniya struct device *dev; 200*fa9e6df6SHardevsinh Palaniya struct regmap *cci; 201*fa9e6df6SHardevsinh Palaniya struct v4l2_subdev sd; 202*fa9e6df6SHardevsinh Palaniya struct media_pad pad; 203*fa9e6df6SHardevsinh Palaniya struct clk *xclk; 204*fa9e6df6SHardevsinh Palaniya struct gpio_desc *reset_gpio; 205*fa9e6df6SHardevsinh Palaniya struct gpio_desc *enable_gpio; 206*fa9e6df6SHardevsinh Palaniya struct regulator_bulk_data supplies[ARRAY_SIZE(ov2735_supply_name)]; 207*fa9e6df6SHardevsinh Palaniya 208*fa9e6df6SHardevsinh Palaniya /* V4L2 Controls */ 209*fa9e6df6SHardevsinh Palaniya struct v4l2_ctrl_handler handler; 210*fa9e6df6SHardevsinh Palaniya struct v4l2_ctrl *link_freq; 211*fa9e6df6SHardevsinh Palaniya struct v4l2_ctrl *pixel_rate; 212*fa9e6df6SHardevsinh Palaniya struct v4l2_ctrl *hblank; 213*fa9e6df6SHardevsinh Palaniya struct v4l2_ctrl *vblank; 214*fa9e6df6SHardevsinh Palaniya struct v4l2_ctrl *gain; 215*fa9e6df6SHardevsinh Palaniya struct v4l2_ctrl *exposure; 216*fa9e6df6SHardevsinh Palaniya struct v4l2_ctrl *test_pattern; 217*fa9e6df6SHardevsinh Palaniya 218*fa9e6df6SHardevsinh Palaniya u32 link_freq_index; 219*fa9e6df6SHardevsinh Palaniya 220*fa9e6df6SHardevsinh Palaniya u8 current_page; 221*fa9e6df6SHardevsinh Palaniya struct mutex page_lock; 222*fa9e6df6SHardevsinh Palaniya }; 223*fa9e6df6SHardevsinh Palaniya 224*fa9e6df6SHardevsinh Palaniya struct ov2735_mode { 225*fa9e6df6SHardevsinh Palaniya u32 width; 226*fa9e6df6SHardevsinh Palaniya u32 height; 227*fa9e6df6SHardevsinh Palaniya u32 hts_def; 228*fa9e6df6SHardevsinh Palaniya u32 vts_def; 229*fa9e6df6SHardevsinh Palaniya u32 exp_def; 230*fa9e6df6SHardevsinh Palaniya struct v4l2_rect crop; 231*fa9e6df6SHardevsinh Palaniya }; 232*fa9e6df6SHardevsinh Palaniya 233*fa9e6df6SHardevsinh Palaniya static const struct cci_reg_sequence ov2735_common_regs[] = { 234*fa9e6df6SHardevsinh Palaniya { OV2735_REG_CLK_MODE, 0x15 }, 235*fa9e6df6SHardevsinh Palaniya { OV2735_REG_CLOCK_REG1, 0x01 }, 236*fa9e6df6SHardevsinh Palaniya { OV2735_REG_CLOCK_REG2, 0x20 }, 237*fa9e6df6SHardevsinh Palaniya { OV2735_REG_BINNING_DAC_CODE_MODE, 0x00 }, 238*fa9e6df6SHardevsinh Palaniya { OV2735_REG_ABL, 0x73 }, 239*fa9e6df6SHardevsinh Palaniya { OV2735_REG_FRAME_SYNC, 0x01 }, 240*fa9e6df6SHardevsinh Palaniya 241*fa9e6df6SHardevsinh Palaniya /* Timing ctrl */ 242*fa9e6df6SHardevsinh Palaniya { OV2735_REG_TIMING_CTRL2, 0x6b }, 243*fa9e6df6SHardevsinh Palaniya { OV2735_REG_TIMING_CTRL3, 0xea }, 244*fa9e6df6SHardevsinh Palaniya { OV2735_REG_TIMING_CTRL1, 0x0c }, 245*fa9e6df6SHardevsinh Palaniya { OV2735_REG_RST_NUM, 0x0063 }, 246*fa9e6df6SHardevsinh Palaniya { OV2735_REG_RST_NUM2, 0x006f }, 247*fa9e6df6SHardevsinh Palaniya { OV2735_REG_BOOST_EN, 0x02 }, 248*fa9e6df6SHardevsinh Palaniya { OV2735_REG_B2_NUM, 0x0120 }, 249*fa9e6df6SHardevsinh Palaniya { OV2735_REG_B4_NUM, 0x042a }, 250*fa9e6df6SHardevsinh Palaniya { OV2735_REG_PIXEL_CYCLE_P0, 0x00 }, 251*fa9e6df6SHardevsinh Palaniya { OV2735_REG_PIXEL_CYCLE_P1, 0x2c }, 252*fa9e6df6SHardevsinh Palaniya { OV2735_REG_PIXEL_CYCLE_P2, 0x29 }, 253*fa9e6df6SHardevsinh Palaniya { OV2735_REG_PIXEL_CYCLE_P3, 0x00 }, 254*fa9e6df6SHardevsinh Palaniya { OV2735_REG_PIXEL_CYCLE_P5, 0x44 }, 255*fa9e6df6SHardevsinh Palaniya { OV2735_REG_PIXEL_CYCLE_P7, 0x0029 }, 256*fa9e6df6SHardevsinh Palaniya { OV2735_REG_PIXEL_CYCLE_P9, 0x00 }, 257*fa9e6df6SHardevsinh Palaniya { OV2735_REG_PIXEL_CYCLE_P10, 0x00 }, 258*fa9e6df6SHardevsinh Palaniya { OV2735_REG_PIXEL_CYCLE_P12, 0x00 }, 259*fa9e6df6SHardevsinh Palaniya { OV2735_REG_PIXEL_CYCLE_P18, 0x2f }, 260*fa9e6df6SHardevsinh Palaniya { OV2735_REG_PIXEL_CYCLE_P20, 0x62 }, 261*fa9e6df6SHardevsinh Palaniya { OV2735_REG_PIXEL_CYCLE_P22, 0x5b }, 262*fa9e6df6SHardevsinh Palaniya { OV2735_REG_PIXEL_CYCLE_P33, 0x0046 }, 263*fa9e6df6SHardevsinh Palaniya { OV2735_REG_PIXEL_CYCLE_P34, 0x36 }, 264*fa9e6df6SHardevsinh Palaniya { OV2735_REG_PIXEL_CYCLE_P35_P36, 0x4f }, 265*fa9e6df6SHardevsinh Palaniya { OV2735_REG_PIXEL_CYCLE_P37_P38, 0xef }, 266*fa9e6df6SHardevsinh Palaniya { OV2735_REG_PIXEL_CYCLE_P31, 0xcf }, 267*fa9e6df6SHardevsinh Palaniya { OV2735_REG_PIXEL_CYCLE_P32, 0x36 }, 268*fa9e6df6SHardevsinh Palaniya { OV2735_REG_PIXEL_CYCLE_P44, 0x0d }, 269*fa9e6df6SHardevsinh Palaniya { OV2735_REG_PIXEL_CYCLE_P45, 0x0d }, 270*fa9e6df6SHardevsinh Palaniya { OV2735_REG_PIXEL_BIAS_CTRL_RH_RL, 0x77 }, 271*fa9e6df6SHardevsinh Palaniya { OV2735_REG_PIXEL_BIAS_CTRL_SH_SL, 0x77 }, 272*fa9e6df6SHardevsinh Palaniya 273*fa9e6df6SHardevsinh Palaniya /* Analog ctrl */ 274*fa9e6df6SHardevsinh Palaniya { OV2735_REG_ANALOG_CTRL4, 0x5a }, 275*fa9e6df6SHardevsinh Palaniya { OV2735_REG_ANALOG_CTRL5, 0x01 }, 276*fa9e6df6SHardevsinh Palaniya { OV2735_REG_ANALOG_CTRL6, 0xd2 }, 277*fa9e6df6SHardevsinh Palaniya { OV2735_REG_ANALOG_CTRL8, 0x40 }, 278*fa9e6df6SHardevsinh Palaniya { OV2735_REG_PCP_RST_SEL, 0x00 }, 279*fa9e6df6SHardevsinh Palaniya { OV2735_REG_ICOMP, 0xc3 }, 280*fa9e6df6SHardevsinh Palaniya 281*fa9e6df6SHardevsinh Palaniya { OV2735_REG_HS_MIPI, 0x83 }, 282*fa9e6df6SHardevsinh Palaniya { OV2735_REG_MIPI_CTRL5, 0x0b }, 283*fa9e6df6SHardevsinh Palaniya { OV2735_REG_MIPI_CTRL6, 0x14 }, 284*fa9e6df6SHardevsinh Palaniya { OV2735_REG_HIGH_SPEED, 0x40 }, 285*fa9e6df6SHardevsinh Palaniya { OV2735_REG_MIPI_CTRL3, 0x05 }, 286*fa9e6df6SHardevsinh Palaniya { OV2735_REG_MIPI_CTRL2, 0x44 }, 287*fa9e6df6SHardevsinh Palaniya { OV2735_REG_PREPARE, 0x33 }, 288*fa9e6df6SHardevsinh Palaniya { OV2735_REG_R_HS_ZERO, 0x1f }, 289*fa9e6df6SHardevsinh Palaniya { OV2735_REG_TRAIL, 0x45 }, 290*fa9e6df6SHardevsinh Palaniya { OV2735_REG_R_CLK_ZERO, 0x10 }, 291*fa9e6df6SHardevsinh Palaniya { OV2735_REG_MIPI_CTRL7, 0x70 }, 292*fa9e6df6SHardevsinh Palaniya { OV2735_REG_ANALOG_CTRL3, 0xe0 }, 293*fa9e6df6SHardevsinh Palaniya { OV2735_REG_VNCP, 0x7b }, 294*fa9e6df6SHardevsinh Palaniya 295*fa9e6df6SHardevsinh Palaniya /* BLC */ 296*fa9e6df6SHardevsinh Palaniya { OV2735_REG_BLC_GAIN_BLUE, 0x77 }, 297*fa9e6df6SHardevsinh Palaniya { OV2735_REG_BLC_GAIN_GB, 0x77 }, 298*fa9e6df6SHardevsinh Palaniya { OV2735_REG_BLC_GAIN_RED, 0x74 }, 299*fa9e6df6SHardevsinh Palaniya { OV2735_REG_BLC_GAIN_GR, 0x74 }, 300*fa9e6df6SHardevsinh Palaniya { OV2735_REG_BLC_BPC_TH_P, 0xe0 }, 301*fa9e6df6SHardevsinh Palaniya { OV2735_REG_BLC_BPC_TH_N, 0xe0 }, 302*fa9e6df6SHardevsinh Palaniya { OV2735_REG_GB_SUBOFFSET, 0x40 }, 303*fa9e6df6SHardevsinh Palaniya { OV2735_REG_BLUE_SUBOFFSET, 0x40 }, 304*fa9e6df6SHardevsinh Palaniya { OV2735_REG_RED_SUBOFFSET, 0x40 }, 305*fa9e6df6SHardevsinh Palaniya { OV2735_REG_GR_SUBOFFSET, 0x40 }, 306*fa9e6df6SHardevsinh Palaniya }; 307*fa9e6df6SHardevsinh Palaniya 308*fa9e6df6SHardevsinh Palaniya static const struct ov2735_mode supported_modes[] = { 309*fa9e6df6SHardevsinh Palaniya { 310*fa9e6df6SHardevsinh Palaniya .width = 1920, 311*fa9e6df6SHardevsinh Palaniya .height = 1080, 312*fa9e6df6SHardevsinh Palaniya .exp_def = 399, 313*fa9e6df6SHardevsinh Palaniya .hts_def = 2200, 314*fa9e6df6SHardevsinh Palaniya .vts_def = 2545, 315*fa9e6df6SHardevsinh Palaniya .crop = { 316*fa9e6df6SHardevsinh Palaniya .top = 8, 317*fa9e6df6SHardevsinh Palaniya .left = 8, 318*fa9e6df6SHardevsinh Palaniya .width = 1920, 319*fa9e6df6SHardevsinh Palaniya .height = 1080, 320*fa9e6df6SHardevsinh Palaniya }, 321*fa9e6df6SHardevsinh Palaniya }, 322*fa9e6df6SHardevsinh Palaniya }; 323*fa9e6df6SHardevsinh Palaniya 324*fa9e6df6SHardevsinh Palaniya static const s64 link_freq_menu_items[] = { 325*fa9e6df6SHardevsinh Palaniya OV2735_LINK_FREQ_420MHZ, 326*fa9e6df6SHardevsinh Palaniya }; 327*fa9e6df6SHardevsinh Palaniya 328*fa9e6df6SHardevsinh Palaniya static const struct ov2735_pll_parameters pll_configs[] = { 329*fa9e6df6SHardevsinh Palaniya /* For 420MHz pll_configs */ 330*fa9e6df6SHardevsinh Palaniya { 331*fa9e6df6SHardevsinh Palaniya .pll_nc = 4, 332*fa9e6df6SHardevsinh Palaniya .pll_mc = 0, 333*fa9e6df6SHardevsinh Palaniya .pll_outdiv = 1, 334*fa9e6df6SHardevsinh Palaniya }, 335*fa9e6df6SHardevsinh Palaniya }; 336*fa9e6df6SHardevsinh Palaniya 337*fa9e6df6SHardevsinh Palaniya static const char * const ov2735_test_pattern_menu[] = { 338*fa9e6df6SHardevsinh Palaniya "Disabled", 339*fa9e6df6SHardevsinh Palaniya "Vertical Color", 340*fa9e6df6SHardevsinh Palaniya }; 341*fa9e6df6SHardevsinh Palaniya 342*fa9e6df6SHardevsinh Palaniya static int ov2735_page_access(struct ov2735 *ov2735, u32 reg, int *err) 343*fa9e6df6SHardevsinh Palaniya { 344*fa9e6df6SHardevsinh Palaniya u8 page = reg >> CCI_REG_PRIVATE_SHIFT; 345*fa9e6df6SHardevsinh Palaniya int ret = 0; 346*fa9e6df6SHardevsinh Palaniya 347*fa9e6df6SHardevsinh Palaniya if (err && *err) 348*fa9e6df6SHardevsinh Palaniya return *err; 349*fa9e6df6SHardevsinh Palaniya 350*fa9e6df6SHardevsinh Palaniya guard(mutex)(&ov2735->page_lock); 351*fa9e6df6SHardevsinh Palaniya 352*fa9e6df6SHardevsinh Palaniya /* Perform page access before read/write */ 353*fa9e6df6SHardevsinh Palaniya if (ov2735->current_page == page) 354*fa9e6df6SHardevsinh Palaniya return ret; 355*fa9e6df6SHardevsinh Palaniya 356*fa9e6df6SHardevsinh Palaniya ret = cci_write(ov2735->cci, OV2735_REG_PAGE_SELECT, page, err); 357*fa9e6df6SHardevsinh Palaniya if (!ret) 358*fa9e6df6SHardevsinh Palaniya ov2735->current_page = page; 359*fa9e6df6SHardevsinh Palaniya 360*fa9e6df6SHardevsinh Palaniya return ret; 361*fa9e6df6SHardevsinh Palaniya } 362*fa9e6df6SHardevsinh Palaniya 363*fa9e6df6SHardevsinh Palaniya static int ov2735_read(struct ov2735 *ov2735, u32 reg, u64 *val, int *err) 364*fa9e6df6SHardevsinh Palaniya { 365*fa9e6df6SHardevsinh Palaniya u32 addr = reg & ~CCI_REG_PRIVATE_MASK; 366*fa9e6df6SHardevsinh Palaniya int ret; 367*fa9e6df6SHardevsinh Palaniya 368*fa9e6df6SHardevsinh Palaniya ret = ov2735_page_access(ov2735, reg, err); 369*fa9e6df6SHardevsinh Palaniya if (ret) 370*fa9e6df6SHardevsinh Palaniya return ret; 371*fa9e6df6SHardevsinh Palaniya 372*fa9e6df6SHardevsinh Palaniya return cci_read(ov2735->cci, addr, val, err); 373*fa9e6df6SHardevsinh Palaniya } 374*fa9e6df6SHardevsinh Palaniya 375*fa9e6df6SHardevsinh Palaniya static int ov2735_write(struct ov2735 *ov2735, u32 reg, u64 val, int *err) 376*fa9e6df6SHardevsinh Palaniya { 377*fa9e6df6SHardevsinh Palaniya u32 addr = reg & ~CCI_REG_PRIVATE_MASK; 378*fa9e6df6SHardevsinh Palaniya int ret; 379*fa9e6df6SHardevsinh Palaniya 380*fa9e6df6SHardevsinh Palaniya ret = ov2735_page_access(ov2735, reg, err); 381*fa9e6df6SHardevsinh Palaniya if (ret) 382*fa9e6df6SHardevsinh Palaniya return ret; 383*fa9e6df6SHardevsinh Palaniya 384*fa9e6df6SHardevsinh Palaniya return cci_write(ov2735->cci, addr, val, err); 385*fa9e6df6SHardevsinh Palaniya } 386*fa9e6df6SHardevsinh Palaniya 387*fa9e6df6SHardevsinh Palaniya static int ov2735_multi_reg_write(struct ov2735 *ov2735, 388*fa9e6df6SHardevsinh Palaniya const struct cci_reg_sequence *regs, 389*fa9e6df6SHardevsinh Palaniya unsigned int num_regs, int *err) 390*fa9e6df6SHardevsinh Palaniya { 391*fa9e6df6SHardevsinh Palaniya unsigned int i; 392*fa9e6df6SHardevsinh Palaniya int ret; 393*fa9e6df6SHardevsinh Palaniya 394*fa9e6df6SHardevsinh Palaniya for (i = 0; i < num_regs; i++) { 395*fa9e6df6SHardevsinh Palaniya ret = ov2735_write(ov2735, regs[i].reg, regs[i].val, err); 396*fa9e6df6SHardevsinh Palaniya if (ret) 397*fa9e6df6SHardevsinh Palaniya return ret; 398*fa9e6df6SHardevsinh Palaniya } 399*fa9e6df6SHardevsinh Palaniya 400*fa9e6df6SHardevsinh Palaniya return 0; 401*fa9e6df6SHardevsinh Palaniya } 402*fa9e6df6SHardevsinh Palaniya 403*fa9e6df6SHardevsinh Palaniya static inline struct ov2735 *to_ov2735(struct v4l2_subdev *_sd) 404*fa9e6df6SHardevsinh Palaniya { 405*fa9e6df6SHardevsinh Palaniya return container_of_const(_sd, struct ov2735, sd); 406*fa9e6df6SHardevsinh Palaniya } 407*fa9e6df6SHardevsinh Palaniya 408*fa9e6df6SHardevsinh Palaniya static int ov2735_enable_test_pattern(struct ov2735 *ov2735, u32 pattern) 409*fa9e6df6SHardevsinh Palaniya { 410*fa9e6df6SHardevsinh Palaniya int ret; 411*fa9e6df6SHardevsinh Palaniya u64 val; 412*fa9e6df6SHardevsinh Palaniya 413*fa9e6df6SHardevsinh Palaniya ret = ov2735_read(ov2735, OV2735_REG_TEST_PATTERN, &val, NULL); 414*fa9e6df6SHardevsinh Palaniya if (ret) 415*fa9e6df6SHardevsinh Palaniya return ret; 416*fa9e6df6SHardevsinh Palaniya 417*fa9e6df6SHardevsinh Palaniya switch (pattern) { 418*fa9e6df6SHardevsinh Palaniya case 0: 419*fa9e6df6SHardevsinh Palaniya val &= ~OV2735_TEST_PATTERN_ENABLE; 420*fa9e6df6SHardevsinh Palaniya break; 421*fa9e6df6SHardevsinh Palaniya case 1: 422*fa9e6df6SHardevsinh Palaniya val |= OV2735_TEST_PATTERN_ENABLE; 423*fa9e6df6SHardevsinh Palaniya break; 424*fa9e6df6SHardevsinh Palaniya } 425*fa9e6df6SHardevsinh Palaniya 426*fa9e6df6SHardevsinh Palaniya return ov2735_write(ov2735, OV2735_REG_TEST_PATTERN, val, NULL); 427*fa9e6df6SHardevsinh Palaniya } 428*fa9e6df6SHardevsinh Palaniya 429*fa9e6df6SHardevsinh Palaniya static int ov2735_set_ctrl(struct v4l2_ctrl *ctrl) 430*fa9e6df6SHardevsinh Palaniya { 431*fa9e6df6SHardevsinh Palaniya struct ov2735 *ov2735 = 432*fa9e6df6SHardevsinh Palaniya container_of_const(ctrl->handler, struct ov2735, handler); 433*fa9e6df6SHardevsinh Palaniya struct v4l2_mbus_framefmt *fmt; 434*fa9e6df6SHardevsinh Palaniya struct v4l2_subdev_state *state; 435*fa9e6df6SHardevsinh Palaniya u64 vts; 436*fa9e6df6SHardevsinh Palaniya int ret = 0; 437*fa9e6df6SHardevsinh Palaniya 438*fa9e6df6SHardevsinh Palaniya state = v4l2_subdev_get_locked_active_state(&ov2735->sd); 439*fa9e6df6SHardevsinh Palaniya fmt = v4l2_subdev_state_get_format(state, 0); 440*fa9e6df6SHardevsinh Palaniya 441*fa9e6df6SHardevsinh Palaniya if (ctrl->id == V4L2_CID_VBLANK) { 442*fa9e6df6SHardevsinh Palaniya /* Honour the VBLANK limits when setting exposure */ 443*fa9e6df6SHardevsinh Palaniya s64 max = fmt->height + ctrl->val - OV2735_EXPOSURE_MARGIN; 444*fa9e6df6SHardevsinh Palaniya 445*fa9e6df6SHardevsinh Palaniya ret = __v4l2_ctrl_modify_range(ov2735->exposure, 446*fa9e6df6SHardevsinh Palaniya ov2735->exposure->minimum, max, 447*fa9e6df6SHardevsinh Palaniya ov2735->exposure->step, 448*fa9e6df6SHardevsinh Palaniya ov2735->exposure->default_value); 449*fa9e6df6SHardevsinh Palaniya if (ret) 450*fa9e6df6SHardevsinh Palaniya return ret; 451*fa9e6df6SHardevsinh Palaniya } 452*fa9e6df6SHardevsinh Palaniya 453*fa9e6df6SHardevsinh Palaniya if (pm_runtime_get_if_in_use(ov2735->dev) == 0) 454*fa9e6df6SHardevsinh Palaniya return 0; 455*fa9e6df6SHardevsinh Palaniya 456*fa9e6df6SHardevsinh Palaniya switch (ctrl->id) { 457*fa9e6df6SHardevsinh Palaniya case V4L2_CID_EXPOSURE: 458*fa9e6df6SHardevsinh Palaniya ov2735_write(ov2735, OV2735_REG_LONG_EXPOSURE, ctrl->val, &ret); 459*fa9e6df6SHardevsinh Palaniya break; 460*fa9e6df6SHardevsinh Palaniya case V4L2_CID_ANALOGUE_GAIN: 461*fa9e6df6SHardevsinh Palaniya ov2735_write(ov2735, OV2735_REG_ANALOG_GAIN, ctrl->val, &ret); 462*fa9e6df6SHardevsinh Palaniya break; 463*fa9e6df6SHardevsinh Palaniya case V4L2_CID_HBLANK: 464*fa9e6df6SHardevsinh Palaniya ov2735_write(ov2735, OV2735_REG_HBLANK, ctrl->val, &ret); 465*fa9e6df6SHardevsinh Palaniya break; 466*fa9e6df6SHardevsinh Palaniya case V4L2_CID_VBLANK: 467*fa9e6df6SHardevsinh Palaniya vts = ctrl->val + fmt->height; 468*fa9e6df6SHardevsinh Palaniya ov2735_write(ov2735, OV2735_REG_FRAME_EXP_SEPERATE_EN, 469*fa9e6df6SHardevsinh Palaniya OV2735_FRAME_EXP_SEPERATE_EN, &ret); 470*fa9e6df6SHardevsinh Palaniya ov2735_write(ov2735, OV2735_REG_FRAME_LENGTH, vts, &ret); 471*fa9e6df6SHardevsinh Palaniya break; 472*fa9e6df6SHardevsinh Palaniya case V4L2_CID_TEST_PATTERN: 473*fa9e6df6SHardevsinh Palaniya ret = ov2735_enable_test_pattern(ov2735, ctrl->val); 474*fa9e6df6SHardevsinh Palaniya break; 475*fa9e6df6SHardevsinh Palaniya default: 476*fa9e6df6SHardevsinh Palaniya ret = -EINVAL; 477*fa9e6df6SHardevsinh Palaniya break; 478*fa9e6df6SHardevsinh Palaniya } 479*fa9e6df6SHardevsinh Palaniya ov2735_write(ov2735, OV2735_REG_FRAME_SYNC, 0x01, &ret); 480*fa9e6df6SHardevsinh Palaniya 481*fa9e6df6SHardevsinh Palaniya pm_runtime_put(ov2735->dev); 482*fa9e6df6SHardevsinh Palaniya 483*fa9e6df6SHardevsinh Palaniya return ret; 484*fa9e6df6SHardevsinh Palaniya } 485*fa9e6df6SHardevsinh Palaniya 486*fa9e6df6SHardevsinh Palaniya static const struct v4l2_ctrl_ops ov2735_ctrl_ops = { 487*fa9e6df6SHardevsinh Palaniya .s_ctrl = ov2735_set_ctrl, 488*fa9e6df6SHardevsinh Palaniya }; 489*fa9e6df6SHardevsinh Palaniya 490*fa9e6df6SHardevsinh Palaniya static int ov2735_init_controls(struct ov2735 *ov2735) 491*fa9e6df6SHardevsinh Palaniya { 492*fa9e6df6SHardevsinh Palaniya struct v4l2_ctrl_handler *ctrl_hdlr; 493*fa9e6df6SHardevsinh Palaniya struct v4l2_fwnode_device_properties props; 494*fa9e6df6SHardevsinh Palaniya const struct ov2735_mode *mode = &supported_modes[0]; 495*fa9e6df6SHardevsinh Palaniya u64 hblank_def, vblank_def, exp_max; 496*fa9e6df6SHardevsinh Palaniya int ret; 497*fa9e6df6SHardevsinh Palaniya 498*fa9e6df6SHardevsinh Palaniya ctrl_hdlr = &ov2735->handler; 499*fa9e6df6SHardevsinh Palaniya v4l2_ctrl_handler_init(ctrl_hdlr, 9); 500*fa9e6df6SHardevsinh Palaniya 501*fa9e6df6SHardevsinh Palaniya ov2735->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov2735_ctrl_ops, 502*fa9e6df6SHardevsinh Palaniya V4L2_CID_PIXEL_RATE, 0, 503*fa9e6df6SHardevsinh Palaniya OV2735_PIXEL_RATE, 1, 504*fa9e6df6SHardevsinh Palaniya OV2735_PIXEL_RATE); 505*fa9e6df6SHardevsinh Palaniya 506*fa9e6df6SHardevsinh Palaniya ov2735->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov2735_ctrl_ops, 507*fa9e6df6SHardevsinh Palaniya V4L2_CID_LINK_FREQ, 508*fa9e6df6SHardevsinh Palaniya ov2735->link_freq_index, 509*fa9e6df6SHardevsinh Palaniya 0, link_freq_menu_items); 510*fa9e6df6SHardevsinh Palaniya if (ov2735->link_freq) 511*fa9e6df6SHardevsinh Palaniya ov2735->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; 512*fa9e6df6SHardevsinh Palaniya 513*fa9e6df6SHardevsinh Palaniya hblank_def = mode->hts_def - mode->width; 514*fa9e6df6SHardevsinh Palaniya ov2735->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov2735_ctrl_ops, 515*fa9e6df6SHardevsinh Palaniya V4L2_CID_HBLANK, hblank_def, 516*fa9e6df6SHardevsinh Palaniya hblank_def, 1, hblank_def); 517*fa9e6df6SHardevsinh Palaniya 518*fa9e6df6SHardevsinh Palaniya vblank_def = mode->vts_def - mode->height; 519*fa9e6df6SHardevsinh Palaniya ov2735->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov2735_ctrl_ops, 520*fa9e6df6SHardevsinh Palaniya V4L2_CID_VBLANK, vblank_def, 521*fa9e6df6SHardevsinh Palaniya OV2735_FRAME_LENGTH_MAX - mode->height, 522*fa9e6df6SHardevsinh Palaniya 1, vblank_def); 523*fa9e6df6SHardevsinh Palaniya 524*fa9e6df6SHardevsinh Palaniya exp_max = mode->vts_def - OV2735_EXPOSURE_MARGIN; 525*fa9e6df6SHardevsinh Palaniya ov2735->exposure = 526*fa9e6df6SHardevsinh Palaniya v4l2_ctrl_new_std(ctrl_hdlr, &ov2735_ctrl_ops, 527*fa9e6df6SHardevsinh Palaniya V4L2_CID_EXPOSURE, 528*fa9e6df6SHardevsinh Palaniya OV2735_EXPOSURE_MIN, exp_max, 529*fa9e6df6SHardevsinh Palaniya OV2735_EXPOSURE_STEP, mode->exp_def); 530*fa9e6df6SHardevsinh Palaniya 531*fa9e6df6SHardevsinh Palaniya ov2735->gain = 532*fa9e6df6SHardevsinh Palaniya v4l2_ctrl_new_std(ctrl_hdlr, &ov2735_ctrl_ops, 533*fa9e6df6SHardevsinh Palaniya V4L2_CID_ANALOGUE_GAIN, OV2735_ANALOG_GAIN_MIN, 534*fa9e6df6SHardevsinh Palaniya OV2735_ANALOG_GAIN_MAX, OV2735_ANALOG_GAIN_STEP, 535*fa9e6df6SHardevsinh Palaniya OV2735_ANALOG_GAIN_DEFAULT); 536*fa9e6df6SHardevsinh Palaniya 537*fa9e6df6SHardevsinh Palaniya ov2735->test_pattern = 538*fa9e6df6SHardevsinh Palaniya v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &ov2735_ctrl_ops, 539*fa9e6df6SHardevsinh Palaniya V4L2_CID_TEST_PATTERN, 540*fa9e6df6SHardevsinh Palaniya ARRAY_SIZE(ov2735_test_pattern_menu) - 1, 541*fa9e6df6SHardevsinh Palaniya 0, 0, ov2735_test_pattern_menu); 542*fa9e6df6SHardevsinh Palaniya 543*fa9e6df6SHardevsinh Palaniya if (ctrl_hdlr->error) { 544*fa9e6df6SHardevsinh Palaniya ret = ctrl_hdlr->error; 545*fa9e6df6SHardevsinh Palaniya dev_err(ov2735->dev, "control init failed (%d)\n", ret); 546*fa9e6df6SHardevsinh Palaniya goto err_handler_free; 547*fa9e6df6SHardevsinh Palaniya } 548*fa9e6df6SHardevsinh Palaniya 549*fa9e6df6SHardevsinh Palaniya ret = v4l2_fwnode_device_parse(ov2735->dev, &props); 550*fa9e6df6SHardevsinh Palaniya if (ret) 551*fa9e6df6SHardevsinh Palaniya goto err_handler_free; 552*fa9e6df6SHardevsinh Palaniya 553*fa9e6df6SHardevsinh Palaniya ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, 554*fa9e6df6SHardevsinh Palaniya &ov2735_ctrl_ops, &props); 555*fa9e6df6SHardevsinh Palaniya if (ret) 556*fa9e6df6SHardevsinh Palaniya goto err_handler_free; 557*fa9e6df6SHardevsinh Palaniya 558*fa9e6df6SHardevsinh Palaniya ov2735->sd.ctrl_handler = ctrl_hdlr; 559*fa9e6df6SHardevsinh Palaniya 560*fa9e6df6SHardevsinh Palaniya return 0; 561*fa9e6df6SHardevsinh Palaniya 562*fa9e6df6SHardevsinh Palaniya err_handler_free: 563*fa9e6df6SHardevsinh Palaniya v4l2_ctrl_handler_free(ctrl_hdlr); 564*fa9e6df6SHardevsinh Palaniya 565*fa9e6df6SHardevsinh Palaniya return ret; 566*fa9e6df6SHardevsinh Palaniya } 567*fa9e6df6SHardevsinh Palaniya 568*fa9e6df6SHardevsinh Palaniya static int ov2735_set_pll_ctrl(struct ov2735 *ov2735) 569*fa9e6df6SHardevsinh Palaniya { 570*fa9e6df6SHardevsinh Palaniya const struct ov2735_pll_parameters *pll_parameters; 571*fa9e6df6SHardevsinh Palaniya u8 pll_ctrl; 572*fa9e6df6SHardevsinh Palaniya u8 pll_outdiv; 573*fa9e6df6SHardevsinh Palaniya int ret = 0; 574*fa9e6df6SHardevsinh Palaniya 575*fa9e6df6SHardevsinh Palaniya pll_parameters = &pll_configs[ov2735->link_freq_index]; 576*fa9e6df6SHardevsinh Palaniya 577*fa9e6df6SHardevsinh Palaniya /* BIT[7]: pll_clk_sel, BIT[6:2]: pll_nc, BIT[1:0]: pll_mc */ 578*fa9e6df6SHardevsinh Palaniya pll_ctrl = ((pll_parameters->pll_nc << 2) | (pll_parameters->pll_mc << 0)) & 579*fa9e6df6SHardevsinh Palaniya OV2735_PLL_CTRL_ENABLE; 580*fa9e6df6SHardevsinh Palaniya 581*fa9e6df6SHardevsinh Palaniya pll_outdiv = pll_parameters->pll_outdiv; 582*fa9e6df6SHardevsinh Palaniya 583*fa9e6df6SHardevsinh Palaniya ov2735_write(ov2735, OV2735_REG_PLL_CTRL, pll_ctrl, &ret); 584*fa9e6df6SHardevsinh Palaniya ov2735_write(ov2735, OV2735_REG_PLL_OUTDIV, pll_outdiv, &ret); 585*fa9e6df6SHardevsinh Palaniya 586*fa9e6df6SHardevsinh Palaniya return ret; 587*fa9e6df6SHardevsinh Palaniya } 588*fa9e6df6SHardevsinh Palaniya 589*fa9e6df6SHardevsinh Palaniya static int ov2735_set_framefmt(struct ov2735 *ov2735, 590*fa9e6df6SHardevsinh Palaniya struct v4l2_subdev_state *state) 591*fa9e6df6SHardevsinh Palaniya { 592*fa9e6df6SHardevsinh Palaniya const struct v4l2_mbus_framefmt *format; 593*fa9e6df6SHardevsinh Palaniya const struct v4l2_rect *crop; 594*fa9e6df6SHardevsinh Palaniya int ret = 0; 595*fa9e6df6SHardevsinh Palaniya 596*fa9e6df6SHardevsinh Palaniya format = v4l2_subdev_state_get_format(state, 0); 597*fa9e6df6SHardevsinh Palaniya crop = v4l2_subdev_state_get_crop(state, 0); 598*fa9e6df6SHardevsinh Palaniya 599*fa9e6df6SHardevsinh Palaniya ov2735_write(ov2735, OV2735_REG_V_START, crop->top, &ret); 600*fa9e6df6SHardevsinh Palaniya ov2735_write(ov2735, OV2735_REG_V_SIZE, format->height, &ret); 601*fa9e6df6SHardevsinh Palaniya ov2735_write(ov2735, OV2735_REG_MIPI_LINE_NUMBER, format->height, &ret); 602*fa9e6df6SHardevsinh Palaniya ov2735_write(ov2735, OV2735_REG_H_START, crop->left, &ret); 603*fa9e6df6SHardevsinh Palaniya /* OV2735_REG_H_SIZE: Image half horizontal size */ 604*fa9e6df6SHardevsinh Palaniya ov2735_write(ov2735, OV2735_REG_H_SIZE, (format->width / 2), &ret); 605*fa9e6df6SHardevsinh Palaniya ov2735_write(ov2735, OV2735_REG_MIPI_COLOMN_NUMBER, format->width, &ret); 606*fa9e6df6SHardevsinh Palaniya 607*fa9e6df6SHardevsinh Palaniya return ret; 608*fa9e6df6SHardevsinh Palaniya } 609*fa9e6df6SHardevsinh Palaniya 610*fa9e6df6SHardevsinh Palaniya static int ov2735_enable_streams(struct v4l2_subdev *sd, 611*fa9e6df6SHardevsinh Palaniya struct v4l2_subdev_state *state, u32 pad, 612*fa9e6df6SHardevsinh Palaniya u64 streams_mask) 613*fa9e6df6SHardevsinh Palaniya { 614*fa9e6df6SHardevsinh Palaniya struct ov2735 *ov2735 = to_ov2735(sd); 615*fa9e6df6SHardevsinh Palaniya int ret; 616*fa9e6df6SHardevsinh Palaniya 617*fa9e6df6SHardevsinh Palaniya ret = pm_runtime_resume_and_get(ov2735->dev); 618*fa9e6df6SHardevsinh Palaniya if (ret < 0) 619*fa9e6df6SHardevsinh Palaniya return ret; 620*fa9e6df6SHardevsinh Palaniya 621*fa9e6df6SHardevsinh Palaniya /* Apply pll settings */ 622*fa9e6df6SHardevsinh Palaniya ret = ov2735_set_pll_ctrl(ov2735); 623*fa9e6df6SHardevsinh Palaniya if (ret) { 624*fa9e6df6SHardevsinh Palaniya dev_err(ov2735->dev, "failed to set frame format: %d\n", ret); 625*fa9e6df6SHardevsinh Palaniya goto err_rpm_put; 626*fa9e6df6SHardevsinh Palaniya } 627*fa9e6df6SHardevsinh Palaniya 628*fa9e6df6SHardevsinh Palaniya ret = ov2735_multi_reg_write(ov2735, ov2735_common_regs, 629*fa9e6df6SHardevsinh Palaniya ARRAY_SIZE(ov2735_common_regs), NULL); 630*fa9e6df6SHardevsinh Palaniya if (ret) { 631*fa9e6df6SHardevsinh Palaniya dev_err(ov2735->dev, "failed to write common registers\n"); 632*fa9e6df6SHardevsinh Palaniya goto err_rpm_put; 633*fa9e6df6SHardevsinh Palaniya } 634*fa9e6df6SHardevsinh Palaniya 635*fa9e6df6SHardevsinh Palaniya /* Apply format settings */ 636*fa9e6df6SHardevsinh Palaniya ret = ov2735_set_framefmt(ov2735, state); 637*fa9e6df6SHardevsinh Palaniya if (ret) { 638*fa9e6df6SHardevsinh Palaniya dev_err(ov2735->dev, "failed to set frame format: %d\n", ret); 639*fa9e6df6SHardevsinh Palaniya goto err_rpm_put; 640*fa9e6df6SHardevsinh Palaniya } 641*fa9e6df6SHardevsinh Palaniya 642*fa9e6df6SHardevsinh Palaniya /* Apply customized values from user */ 643*fa9e6df6SHardevsinh Palaniya ret = __v4l2_ctrl_handler_setup(ov2735->sd.ctrl_handler); 644*fa9e6df6SHardevsinh Palaniya if (ret) 645*fa9e6df6SHardevsinh Palaniya goto err_rpm_put; 646*fa9e6df6SHardevsinh Palaniya 647*fa9e6df6SHardevsinh Palaniya ret = ov2735_write(ov2735, OV2735_REG_STREAM_CTRL, 648*fa9e6df6SHardevsinh Palaniya OV2735_STREAM_CTRL_ON, NULL); 649*fa9e6df6SHardevsinh Palaniya if (ret) 650*fa9e6df6SHardevsinh Palaniya goto err_rpm_put; 651*fa9e6df6SHardevsinh Palaniya 652*fa9e6df6SHardevsinh Palaniya return 0; 653*fa9e6df6SHardevsinh Palaniya 654*fa9e6df6SHardevsinh Palaniya err_rpm_put: 655*fa9e6df6SHardevsinh Palaniya pm_runtime_put(ov2735->dev); 656*fa9e6df6SHardevsinh Palaniya return ret; 657*fa9e6df6SHardevsinh Palaniya } 658*fa9e6df6SHardevsinh Palaniya 659*fa9e6df6SHardevsinh Palaniya static int ov2735_disable_streams(struct v4l2_subdev *sd, 660*fa9e6df6SHardevsinh Palaniya struct v4l2_subdev_state *state, u32 pad, 661*fa9e6df6SHardevsinh Palaniya u64 streams_mask) 662*fa9e6df6SHardevsinh Palaniya { 663*fa9e6df6SHardevsinh Palaniya struct ov2735 *ov2735 = to_ov2735(sd); 664*fa9e6df6SHardevsinh Palaniya int ret; 665*fa9e6df6SHardevsinh Palaniya 666*fa9e6df6SHardevsinh Palaniya ret = ov2735_write(ov2735, OV2735_REG_STREAM_CTRL, 667*fa9e6df6SHardevsinh Palaniya OV2735_STREAM_CTRL_OFF, NULL); 668*fa9e6df6SHardevsinh Palaniya if (ret) 669*fa9e6df6SHardevsinh Palaniya dev_err(ov2735->dev, "%s failed to set stream\n", __func__); 670*fa9e6df6SHardevsinh Palaniya 671*fa9e6df6SHardevsinh Palaniya pm_runtime_put(ov2735->dev); 672*fa9e6df6SHardevsinh Palaniya 673*fa9e6df6SHardevsinh Palaniya return ret; 674*fa9e6df6SHardevsinh Palaniya } 675*fa9e6df6SHardevsinh Palaniya 676*fa9e6df6SHardevsinh Palaniya static int ov2735_get_selection(struct v4l2_subdev *sd, 677*fa9e6df6SHardevsinh Palaniya struct v4l2_subdev_state *sd_state, 678*fa9e6df6SHardevsinh Palaniya struct v4l2_subdev_selection *sel) 679*fa9e6df6SHardevsinh Palaniya { 680*fa9e6df6SHardevsinh Palaniya switch (sel->target) { 681*fa9e6df6SHardevsinh Palaniya case V4L2_SEL_TGT_CROP: 682*fa9e6df6SHardevsinh Palaniya sel->r = *v4l2_subdev_state_get_crop(sd_state, 0); 683*fa9e6df6SHardevsinh Palaniya return 0; 684*fa9e6df6SHardevsinh Palaniya case V4L2_SEL_TGT_NATIVE_SIZE: 685*fa9e6df6SHardevsinh Palaniya sel->r = ov2735_native_area; 686*fa9e6df6SHardevsinh Palaniya return 0; 687*fa9e6df6SHardevsinh Palaniya case V4L2_SEL_TGT_CROP_DEFAULT: 688*fa9e6df6SHardevsinh Palaniya case V4L2_SEL_TGT_CROP_BOUNDS: 689*fa9e6df6SHardevsinh Palaniya sel->r = ov2735_active_area; 690*fa9e6df6SHardevsinh Palaniya return 0; 691*fa9e6df6SHardevsinh Palaniya default: 692*fa9e6df6SHardevsinh Palaniya return -EINVAL; 693*fa9e6df6SHardevsinh Palaniya } 694*fa9e6df6SHardevsinh Palaniya } 695*fa9e6df6SHardevsinh Palaniya 696*fa9e6df6SHardevsinh Palaniya static int ov2735_enum_mbus_code(struct v4l2_subdev *sd, 697*fa9e6df6SHardevsinh Palaniya struct v4l2_subdev_state *sd_state, 698*fa9e6df6SHardevsinh Palaniya struct v4l2_subdev_mbus_code_enum *code) 699*fa9e6df6SHardevsinh Palaniya { 700*fa9e6df6SHardevsinh Palaniya if (code->index) 701*fa9e6df6SHardevsinh Palaniya return -EINVAL; 702*fa9e6df6SHardevsinh Palaniya 703*fa9e6df6SHardevsinh Palaniya code->code = MEDIA_BUS_FMT_SGRBG10_1X10; 704*fa9e6df6SHardevsinh Palaniya 705*fa9e6df6SHardevsinh Palaniya return 0; 706*fa9e6df6SHardevsinh Palaniya } 707*fa9e6df6SHardevsinh Palaniya 708*fa9e6df6SHardevsinh Palaniya static int ov2735_enum_frame_size(struct v4l2_subdev *sd, 709*fa9e6df6SHardevsinh Palaniya struct v4l2_subdev_state *sd_state, 710*fa9e6df6SHardevsinh Palaniya struct v4l2_subdev_frame_size_enum *fse) 711*fa9e6df6SHardevsinh Palaniya { 712*fa9e6df6SHardevsinh Palaniya if (fse->index >= ARRAY_SIZE(supported_modes)) 713*fa9e6df6SHardevsinh Palaniya return -EINVAL; 714*fa9e6df6SHardevsinh Palaniya 715*fa9e6df6SHardevsinh Palaniya if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) 716*fa9e6df6SHardevsinh Palaniya return -EINVAL; 717*fa9e6df6SHardevsinh Palaniya 718*fa9e6df6SHardevsinh Palaniya fse->min_width = supported_modes[fse->index].width; 719*fa9e6df6SHardevsinh Palaniya fse->max_width = fse->min_width; 720*fa9e6df6SHardevsinh Palaniya fse->min_height = supported_modes[fse->index].height; 721*fa9e6df6SHardevsinh Palaniya fse->max_height = fse->min_height; 722*fa9e6df6SHardevsinh Palaniya 723*fa9e6df6SHardevsinh Palaniya return 0; 724*fa9e6df6SHardevsinh Palaniya } 725*fa9e6df6SHardevsinh Palaniya 726*fa9e6df6SHardevsinh Palaniya static int ov2735_set_framing_limits(struct ov2735 *ov2735, 727*fa9e6df6SHardevsinh Palaniya const struct ov2735_mode *mode) 728*fa9e6df6SHardevsinh Palaniya { 729*fa9e6df6SHardevsinh Palaniya u32 hblank, vblank_def; 730*fa9e6df6SHardevsinh Palaniya int ret; 731*fa9e6df6SHardevsinh Palaniya 732*fa9e6df6SHardevsinh Palaniya hblank = mode->hts_def - mode->width; 733*fa9e6df6SHardevsinh Palaniya ret = __v4l2_ctrl_modify_range(ov2735->hblank, hblank, hblank, 1, 734*fa9e6df6SHardevsinh Palaniya hblank); 735*fa9e6df6SHardevsinh Palaniya if (ret) 736*fa9e6df6SHardevsinh Palaniya return ret; 737*fa9e6df6SHardevsinh Palaniya 738*fa9e6df6SHardevsinh Palaniya vblank_def = mode->vts_def - mode->height; 739*fa9e6df6SHardevsinh Palaniya return __v4l2_ctrl_modify_range(ov2735->vblank, vblank_def, 740*fa9e6df6SHardevsinh Palaniya OV2735_FRAME_LENGTH_MAX - mode->height, 741*fa9e6df6SHardevsinh Palaniya 1, vblank_def); 742*fa9e6df6SHardevsinh Palaniya } 743*fa9e6df6SHardevsinh Palaniya 744*fa9e6df6SHardevsinh Palaniya static int ov2735_set_pad_format(struct v4l2_subdev *sd, 745*fa9e6df6SHardevsinh Palaniya struct v4l2_subdev_state *sd_state, 746*fa9e6df6SHardevsinh Palaniya struct v4l2_subdev_format *fmt) 747*fa9e6df6SHardevsinh Palaniya { 748*fa9e6df6SHardevsinh Palaniya struct v4l2_mbus_framefmt *format; 749*fa9e6df6SHardevsinh Palaniya const struct ov2735_mode *mode; 750*fa9e6df6SHardevsinh Palaniya struct v4l2_rect *crop; 751*fa9e6df6SHardevsinh Palaniya struct ov2735 *ov2735 = to_ov2735(sd); 752*fa9e6df6SHardevsinh Palaniya int ret; 753*fa9e6df6SHardevsinh Palaniya 754*fa9e6df6SHardevsinh Palaniya format = v4l2_subdev_state_get_format(sd_state, 0); 755*fa9e6df6SHardevsinh Palaniya 756*fa9e6df6SHardevsinh Palaniya mode = v4l2_find_nearest_size(supported_modes, 757*fa9e6df6SHardevsinh Palaniya ARRAY_SIZE(supported_modes), 758*fa9e6df6SHardevsinh Palaniya width, height, 759*fa9e6df6SHardevsinh Palaniya fmt->format.width, fmt->format.height); 760*fa9e6df6SHardevsinh Palaniya 761*fa9e6df6SHardevsinh Palaniya fmt->format.width = mode->width; 762*fa9e6df6SHardevsinh Palaniya fmt->format.height = mode->height; 763*fa9e6df6SHardevsinh Palaniya fmt->format.field = V4L2_FIELD_NONE; 764*fa9e6df6SHardevsinh Palaniya fmt->format.colorspace = V4L2_COLORSPACE_RAW; 765*fa9e6df6SHardevsinh Palaniya fmt->format.quantization = V4L2_QUANTIZATION_FULL_RANGE; 766*fa9e6df6SHardevsinh Palaniya fmt->format.xfer_func = V4L2_XFER_FUNC_NONE; 767*fa9e6df6SHardevsinh Palaniya 768*fa9e6df6SHardevsinh Palaniya if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { 769*fa9e6df6SHardevsinh Palaniya ret = ov2735_set_framing_limits(ov2735, mode); 770*fa9e6df6SHardevsinh Palaniya if (ret) 771*fa9e6df6SHardevsinh Palaniya return ret; 772*fa9e6df6SHardevsinh Palaniya } 773*fa9e6df6SHardevsinh Palaniya 774*fa9e6df6SHardevsinh Palaniya *format = fmt->format; 775*fa9e6df6SHardevsinh Palaniya 776*fa9e6df6SHardevsinh Palaniya /* Initialize crop rectangle */ 777*fa9e6df6SHardevsinh Palaniya crop = v4l2_subdev_state_get_crop(sd_state, 0); 778*fa9e6df6SHardevsinh Palaniya *crop = mode->crop; 779*fa9e6df6SHardevsinh Palaniya 780*fa9e6df6SHardevsinh Palaniya return 0; 781*fa9e6df6SHardevsinh Palaniya } 782*fa9e6df6SHardevsinh Palaniya 783*fa9e6df6SHardevsinh Palaniya static int ov2735_init_state(struct v4l2_subdev *sd, 784*fa9e6df6SHardevsinh Palaniya struct v4l2_subdev_state *state) 785*fa9e6df6SHardevsinh Palaniya { 786*fa9e6df6SHardevsinh Palaniya struct v4l2_subdev_format fmt = { 787*fa9e6df6SHardevsinh Palaniya .which = V4L2_SUBDEV_FORMAT_TRY, 788*fa9e6df6SHardevsinh Palaniya .format = { 789*fa9e6df6SHardevsinh Palaniya .code = MEDIA_BUS_FMT_SGRBG10_1X10, 790*fa9e6df6SHardevsinh Palaniya .width = supported_modes[0].width, 791*fa9e6df6SHardevsinh Palaniya .height = supported_modes[0].height, 792*fa9e6df6SHardevsinh Palaniya }, 793*fa9e6df6SHardevsinh Palaniya }; 794*fa9e6df6SHardevsinh Palaniya 795*fa9e6df6SHardevsinh Palaniya ov2735_set_pad_format(sd, state, &fmt); 796*fa9e6df6SHardevsinh Palaniya 797*fa9e6df6SHardevsinh Palaniya return 0; 798*fa9e6df6SHardevsinh Palaniya } 799*fa9e6df6SHardevsinh Palaniya 800*fa9e6df6SHardevsinh Palaniya static const struct v4l2_subdev_video_ops ov2735_video_ops = { 801*fa9e6df6SHardevsinh Palaniya .s_stream = v4l2_subdev_s_stream_helper, 802*fa9e6df6SHardevsinh Palaniya }; 803*fa9e6df6SHardevsinh Palaniya 804*fa9e6df6SHardevsinh Palaniya static const struct v4l2_subdev_pad_ops ov2735_pad_ops = { 805*fa9e6df6SHardevsinh Palaniya .enum_mbus_code = ov2735_enum_mbus_code, 806*fa9e6df6SHardevsinh Palaniya .get_fmt = v4l2_subdev_get_fmt, 807*fa9e6df6SHardevsinh Palaniya .set_fmt = ov2735_set_pad_format, 808*fa9e6df6SHardevsinh Palaniya .get_selection = ov2735_get_selection, 809*fa9e6df6SHardevsinh Palaniya .enum_frame_size = ov2735_enum_frame_size, 810*fa9e6df6SHardevsinh Palaniya .enable_streams = ov2735_enable_streams, 811*fa9e6df6SHardevsinh Palaniya .disable_streams = ov2735_disable_streams, 812*fa9e6df6SHardevsinh Palaniya }; 813*fa9e6df6SHardevsinh Palaniya 814*fa9e6df6SHardevsinh Palaniya static const struct v4l2_subdev_ops ov2735_subdev_ops = { 815*fa9e6df6SHardevsinh Palaniya .video = &ov2735_video_ops, 816*fa9e6df6SHardevsinh Palaniya .pad = &ov2735_pad_ops, 817*fa9e6df6SHardevsinh Palaniya }; 818*fa9e6df6SHardevsinh Palaniya 819*fa9e6df6SHardevsinh Palaniya static const struct v4l2_subdev_internal_ops ov2735_internal_ops = { 820*fa9e6df6SHardevsinh Palaniya .init_state = ov2735_init_state, 821*fa9e6df6SHardevsinh Palaniya }; 822*fa9e6df6SHardevsinh Palaniya 823*fa9e6df6SHardevsinh Palaniya static int ov2735_power_on(struct device *dev) 824*fa9e6df6SHardevsinh Palaniya { 825*fa9e6df6SHardevsinh Palaniya struct v4l2_subdev *sd = dev_get_drvdata(dev); 826*fa9e6df6SHardevsinh Palaniya struct ov2735 *ov2735 = to_ov2735(sd); 827*fa9e6df6SHardevsinh Palaniya int ret; 828*fa9e6df6SHardevsinh Palaniya 829*fa9e6df6SHardevsinh Palaniya ret = regulator_bulk_enable(ARRAY_SIZE(ov2735_supply_name), 830*fa9e6df6SHardevsinh Palaniya ov2735->supplies); 831*fa9e6df6SHardevsinh Palaniya if (ret) { 832*fa9e6df6SHardevsinh Palaniya dev_err(ov2735->dev, "failed to enable regulators\n"); 833*fa9e6df6SHardevsinh Palaniya return ret; 834*fa9e6df6SHardevsinh Palaniya } 835*fa9e6df6SHardevsinh Palaniya 836*fa9e6df6SHardevsinh Palaniya gpiod_set_value_cansleep(ov2735->enable_gpio, 1); 837*fa9e6df6SHardevsinh Palaniya /* T4: delay from PWDN pulling low to RSTB pulling high */ 838*fa9e6df6SHardevsinh Palaniya fsleep(4 * USEC_PER_MSEC); 839*fa9e6df6SHardevsinh Palaniya 840*fa9e6df6SHardevsinh Palaniya ret = clk_prepare_enable(ov2735->xclk); 841*fa9e6df6SHardevsinh Palaniya if (ret) { 842*fa9e6df6SHardevsinh Palaniya dev_err(ov2735->dev, "failed to enable clock\n"); 843*fa9e6df6SHardevsinh Palaniya goto err_regulator_off; 844*fa9e6df6SHardevsinh Palaniya } 845*fa9e6df6SHardevsinh Palaniya 846*fa9e6df6SHardevsinh Palaniya gpiod_set_value_cansleep(ov2735->reset_gpio, 0); 847*fa9e6df6SHardevsinh Palaniya /* T5: delay from RSTB pulling high to first I2C command */ 848*fa9e6df6SHardevsinh Palaniya fsleep(5 * USEC_PER_MSEC); 849*fa9e6df6SHardevsinh Palaniya 850*fa9e6df6SHardevsinh Palaniya return 0; 851*fa9e6df6SHardevsinh Palaniya 852*fa9e6df6SHardevsinh Palaniya err_regulator_off: 853*fa9e6df6SHardevsinh Palaniya regulator_bulk_disable(ARRAY_SIZE(ov2735_supply_name), ov2735->supplies); 854*fa9e6df6SHardevsinh Palaniya return ret; 855*fa9e6df6SHardevsinh Palaniya } 856*fa9e6df6SHardevsinh Palaniya 857*fa9e6df6SHardevsinh Palaniya static int ov2735_power_off(struct device *dev) 858*fa9e6df6SHardevsinh Palaniya { 859*fa9e6df6SHardevsinh Palaniya struct v4l2_subdev *sd = dev_get_drvdata(dev); 860*fa9e6df6SHardevsinh Palaniya struct ov2735 *ov2735 = to_ov2735(sd); 861*fa9e6df6SHardevsinh Palaniya 862*fa9e6df6SHardevsinh Palaniya gpiod_set_value_cansleep(ov2735->enable_gpio, 0); 863*fa9e6df6SHardevsinh Palaniya clk_disable_unprepare(ov2735->xclk); 864*fa9e6df6SHardevsinh Palaniya gpiod_set_value_cansleep(ov2735->reset_gpio, 1); 865*fa9e6df6SHardevsinh Palaniya regulator_bulk_disable(ARRAY_SIZE(ov2735_supply_name), ov2735->supplies); 866*fa9e6df6SHardevsinh Palaniya 867*fa9e6df6SHardevsinh Palaniya return 0; 868*fa9e6df6SHardevsinh Palaniya } 869*fa9e6df6SHardevsinh Palaniya 870*fa9e6df6SHardevsinh Palaniya static int ov2735_get_regulators(struct ov2735 *ov2735) 871*fa9e6df6SHardevsinh Palaniya { 872*fa9e6df6SHardevsinh Palaniya unsigned int i; 873*fa9e6df6SHardevsinh Palaniya 874*fa9e6df6SHardevsinh Palaniya for (i = 0; i < ARRAY_SIZE(ov2735_supply_name); i++) 875*fa9e6df6SHardevsinh Palaniya ov2735->supplies[i].supply = ov2735_supply_name[i]; 876*fa9e6df6SHardevsinh Palaniya 877*fa9e6df6SHardevsinh Palaniya return devm_regulator_bulk_get(ov2735->dev, 878*fa9e6df6SHardevsinh Palaniya ARRAY_SIZE(ov2735_supply_name), 879*fa9e6df6SHardevsinh Palaniya ov2735->supplies); 880*fa9e6df6SHardevsinh Palaniya } 881*fa9e6df6SHardevsinh Palaniya 882*fa9e6df6SHardevsinh Palaniya static int ov2735_identify_module(struct ov2735 *ov2735) 883*fa9e6df6SHardevsinh Palaniya { 884*fa9e6df6SHardevsinh Palaniya u64 chip_id; 885*fa9e6df6SHardevsinh Palaniya int ret; 886*fa9e6df6SHardevsinh Palaniya 887*fa9e6df6SHardevsinh Palaniya ret = ov2735_read(ov2735, OV2735_REG_CHIPID, &chip_id, NULL); 888*fa9e6df6SHardevsinh Palaniya if (ret) 889*fa9e6df6SHardevsinh Palaniya return dev_err_probe(ov2735->dev, ret, 890*fa9e6df6SHardevsinh Palaniya "failed to read chip id %x\n", 891*fa9e6df6SHardevsinh Palaniya OV2735_CHIPID); 892*fa9e6df6SHardevsinh Palaniya 893*fa9e6df6SHardevsinh Palaniya if (chip_id != OV2735_CHIPID) 894*fa9e6df6SHardevsinh Palaniya return dev_err_probe(ov2735->dev, -EIO, 895*fa9e6df6SHardevsinh Palaniya "chip id mismatch: %x!=%llx\n", 896*fa9e6df6SHardevsinh Palaniya OV2735_CHIPID, chip_id); 897*fa9e6df6SHardevsinh Palaniya 898*fa9e6df6SHardevsinh Palaniya return 0; 899*fa9e6df6SHardevsinh Palaniya } 900*fa9e6df6SHardevsinh Palaniya 901*fa9e6df6SHardevsinh Palaniya static int ov2735_parse_endpoint(struct ov2735 *ov2735) 902*fa9e6df6SHardevsinh Palaniya { 903*fa9e6df6SHardevsinh Palaniya struct v4l2_fwnode_endpoint bus_cfg = { 904*fa9e6df6SHardevsinh Palaniya .bus_type = V4L2_MBUS_CSI2_DPHY, 905*fa9e6df6SHardevsinh Palaniya }; 906*fa9e6df6SHardevsinh Palaniya struct fwnode_handle *ep; 907*fa9e6df6SHardevsinh Palaniya unsigned long link_freq_bitmap; 908*fa9e6df6SHardevsinh Palaniya int ret; 909*fa9e6df6SHardevsinh Palaniya 910*fa9e6df6SHardevsinh Palaniya ep = fwnode_graph_get_next_endpoint(dev_fwnode(ov2735->dev), NULL); 911*fa9e6df6SHardevsinh Palaniya if (!ep) 912*fa9e6df6SHardevsinh Palaniya return dev_err_probe(ov2735->dev, -ENXIO, 913*fa9e6df6SHardevsinh Palaniya "Failed to get next endpoint\n"); 914*fa9e6df6SHardevsinh Palaniya 915*fa9e6df6SHardevsinh Palaniya ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); 916*fa9e6df6SHardevsinh Palaniya fwnode_handle_put(ep); 917*fa9e6df6SHardevsinh Palaniya if (ret) 918*fa9e6df6SHardevsinh Palaniya return ret; 919*fa9e6df6SHardevsinh Palaniya 920*fa9e6df6SHardevsinh Palaniya if (bus_cfg.bus.mipi_csi2.num_data_lanes != 2) { 921*fa9e6df6SHardevsinh Palaniya ret = dev_err_probe(ov2735->dev, -EINVAL, 922*fa9e6df6SHardevsinh Palaniya "only 2 data lanes are supported\n"); 923*fa9e6df6SHardevsinh Palaniya goto error_out; 924*fa9e6df6SHardevsinh Palaniya } 925*fa9e6df6SHardevsinh Palaniya 926*fa9e6df6SHardevsinh Palaniya ret = v4l2_link_freq_to_bitmap(ov2735->dev, bus_cfg.link_frequencies, 927*fa9e6df6SHardevsinh Palaniya bus_cfg.nr_of_link_frequencies, 928*fa9e6df6SHardevsinh Palaniya link_freq_menu_items, 929*fa9e6df6SHardevsinh Palaniya ARRAY_SIZE(link_freq_menu_items), 930*fa9e6df6SHardevsinh Palaniya &link_freq_bitmap); 931*fa9e6df6SHardevsinh Palaniya if (ret) { 932*fa9e6df6SHardevsinh Palaniya ret = dev_err_probe(ov2735->dev, -EINVAL, 933*fa9e6df6SHardevsinh Palaniya "only 420MHz frequency is available\n"); 934*fa9e6df6SHardevsinh Palaniya goto error_out; 935*fa9e6df6SHardevsinh Palaniya } 936*fa9e6df6SHardevsinh Palaniya 937*fa9e6df6SHardevsinh Palaniya ov2735->link_freq_index = __ffs(link_freq_bitmap); 938*fa9e6df6SHardevsinh Palaniya 939*fa9e6df6SHardevsinh Palaniya error_out: 940*fa9e6df6SHardevsinh Palaniya v4l2_fwnode_endpoint_free(&bus_cfg); 941*fa9e6df6SHardevsinh Palaniya 942*fa9e6df6SHardevsinh Palaniya return ret; 943*fa9e6df6SHardevsinh Palaniya }; 944*fa9e6df6SHardevsinh Palaniya 945*fa9e6df6SHardevsinh Palaniya static int ov2735_probe(struct i2c_client *client) 946*fa9e6df6SHardevsinh Palaniya { 947*fa9e6df6SHardevsinh Palaniya struct ov2735 *ov2735; 948*fa9e6df6SHardevsinh Palaniya unsigned int xclk_freq; 949*fa9e6df6SHardevsinh Palaniya int ret; 950*fa9e6df6SHardevsinh Palaniya 951*fa9e6df6SHardevsinh Palaniya ov2735 = devm_kzalloc(&client->dev, sizeof(*ov2735), GFP_KERNEL); 952*fa9e6df6SHardevsinh Palaniya if (!ov2735) 953*fa9e6df6SHardevsinh Palaniya return -ENOMEM; 954*fa9e6df6SHardevsinh Palaniya 955*fa9e6df6SHardevsinh Palaniya ov2735->dev = &client->dev; 956*fa9e6df6SHardevsinh Palaniya 957*fa9e6df6SHardevsinh Palaniya v4l2_i2c_subdev_init(&ov2735->sd, client, &ov2735_subdev_ops); 958*fa9e6df6SHardevsinh Palaniya ov2735->sd.internal_ops = &ov2735_internal_ops; 959*fa9e6df6SHardevsinh Palaniya 960*fa9e6df6SHardevsinh Palaniya ov2735->cci = devm_cci_regmap_init_i2c(client, 8); 961*fa9e6df6SHardevsinh Palaniya if (IS_ERR(ov2735->cci)) 962*fa9e6df6SHardevsinh Palaniya return dev_err_probe(ov2735->dev, PTR_ERR(ov2735->cci), 963*fa9e6df6SHardevsinh Palaniya "failed to initialize CCI\n"); 964*fa9e6df6SHardevsinh Palaniya 965*fa9e6df6SHardevsinh Palaniya /* Set Current page to 0 */ 966*fa9e6df6SHardevsinh Palaniya ov2735->current_page = 0; 967*fa9e6df6SHardevsinh Palaniya 968*fa9e6df6SHardevsinh Palaniya ret = devm_mutex_init(ov2735->dev, &ov2735->page_lock); 969*fa9e6df6SHardevsinh Palaniya if (ret) 970*fa9e6df6SHardevsinh Palaniya return dev_err_probe(ov2735->dev, ret, 971*fa9e6df6SHardevsinh Palaniya "Failed to initialize lock\n"); 972*fa9e6df6SHardevsinh Palaniya 973*fa9e6df6SHardevsinh Palaniya /* Get system clock (xvclk) */ 974*fa9e6df6SHardevsinh Palaniya ov2735->xclk = devm_v4l2_sensor_clk_get(ov2735->dev, NULL); 975*fa9e6df6SHardevsinh Palaniya if (IS_ERR(ov2735->xclk)) 976*fa9e6df6SHardevsinh Palaniya return dev_err_probe(ov2735->dev, PTR_ERR(ov2735->xclk), 977*fa9e6df6SHardevsinh Palaniya "failed to get xclk\n"); 978*fa9e6df6SHardevsinh Palaniya 979*fa9e6df6SHardevsinh Palaniya xclk_freq = clk_get_rate(ov2735->xclk); 980*fa9e6df6SHardevsinh Palaniya if (xclk_freq != OV2735_XCLK_FREQ) 981*fa9e6df6SHardevsinh Palaniya return dev_err_probe(ov2735->dev, -EINVAL, 982*fa9e6df6SHardevsinh Palaniya "xclk frequency not supported: %u Hz\n", 983*fa9e6df6SHardevsinh Palaniya xclk_freq); 984*fa9e6df6SHardevsinh Palaniya 985*fa9e6df6SHardevsinh Palaniya ret = ov2735_get_regulators(ov2735); 986*fa9e6df6SHardevsinh Palaniya if (ret) 987*fa9e6df6SHardevsinh Palaniya return dev_err_probe(ov2735->dev, ret, 988*fa9e6df6SHardevsinh Palaniya "failed to get regulators\n"); 989*fa9e6df6SHardevsinh Palaniya 990*fa9e6df6SHardevsinh Palaniya ret = ov2735_parse_endpoint(ov2735); 991*fa9e6df6SHardevsinh Palaniya if (ret) 992*fa9e6df6SHardevsinh Palaniya return dev_err_probe(ov2735->dev, ret, 993*fa9e6df6SHardevsinh Palaniya "failed to parse endpoint configuration\n"); 994*fa9e6df6SHardevsinh Palaniya 995*fa9e6df6SHardevsinh Palaniya ov2735->reset_gpio = devm_gpiod_get_optional(ov2735->dev, 996*fa9e6df6SHardevsinh Palaniya "reset", GPIOD_OUT_LOW); 997*fa9e6df6SHardevsinh Palaniya if (IS_ERR(ov2735->reset_gpio)) 998*fa9e6df6SHardevsinh Palaniya return dev_err_probe(ov2735->dev, PTR_ERR(ov2735->reset_gpio), 999*fa9e6df6SHardevsinh Palaniya "failed to get reset GPIO\n"); 1000*fa9e6df6SHardevsinh Palaniya 1001*fa9e6df6SHardevsinh Palaniya ov2735->enable_gpio = devm_gpiod_get_optional(ov2735->dev, 1002*fa9e6df6SHardevsinh Palaniya "enable", GPIOD_OUT_LOW); 1003*fa9e6df6SHardevsinh Palaniya if (IS_ERR(ov2735->enable_gpio)) 1004*fa9e6df6SHardevsinh Palaniya return dev_err_probe(ov2735->dev, PTR_ERR(ov2735->enable_gpio), 1005*fa9e6df6SHardevsinh Palaniya "failed to get enable GPIO\n"); 1006*fa9e6df6SHardevsinh Palaniya 1007*fa9e6df6SHardevsinh Palaniya ret = ov2735_power_on(ov2735->dev); 1008*fa9e6df6SHardevsinh Palaniya if (ret) 1009*fa9e6df6SHardevsinh Palaniya return ret; 1010*fa9e6df6SHardevsinh Palaniya 1011*fa9e6df6SHardevsinh Palaniya ret = ov2735_identify_module(ov2735); 1012*fa9e6df6SHardevsinh Palaniya if (ret) 1013*fa9e6df6SHardevsinh Palaniya goto error_power_off; 1014*fa9e6df6SHardevsinh Palaniya 1015*fa9e6df6SHardevsinh Palaniya ret = ov2735_init_controls(ov2735); 1016*fa9e6df6SHardevsinh Palaniya if (ret) 1017*fa9e6df6SHardevsinh Palaniya goto error_power_off; 1018*fa9e6df6SHardevsinh Palaniya 1019*fa9e6df6SHardevsinh Palaniya /* Initialize subdev */ 1020*fa9e6df6SHardevsinh Palaniya ov2735->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 1021*fa9e6df6SHardevsinh Palaniya ov2735->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; 1022*fa9e6df6SHardevsinh Palaniya ov2735->pad.flags = MEDIA_PAD_FL_SOURCE; 1023*fa9e6df6SHardevsinh Palaniya 1024*fa9e6df6SHardevsinh Palaniya ret = media_entity_pads_init(&ov2735->sd.entity, 1, &ov2735->pad); 1025*fa9e6df6SHardevsinh Palaniya if (ret) { 1026*fa9e6df6SHardevsinh Palaniya dev_err_probe(ov2735->dev, ret, "failed to init entity pads\n"); 1027*fa9e6df6SHardevsinh Palaniya goto error_handler_free; 1028*fa9e6df6SHardevsinh Palaniya } 1029*fa9e6df6SHardevsinh Palaniya 1030*fa9e6df6SHardevsinh Palaniya ov2735->sd.state_lock = ov2735->handler.lock; 1031*fa9e6df6SHardevsinh Palaniya ret = v4l2_subdev_init_finalize(&ov2735->sd); 1032*fa9e6df6SHardevsinh Palaniya if (ret) { 1033*fa9e6df6SHardevsinh Palaniya dev_err_probe(ov2735->dev, ret, "subdev init error\n"); 1034*fa9e6df6SHardevsinh Palaniya goto error_media_entity; 1035*fa9e6df6SHardevsinh Palaniya } 1036*fa9e6df6SHardevsinh Palaniya 1037*fa9e6df6SHardevsinh Palaniya ret = devm_pm_runtime_get_noresume(ov2735->dev); 1038*fa9e6df6SHardevsinh Palaniya if (ret) { 1039*fa9e6df6SHardevsinh Palaniya dev_err_probe(ov2735->dev, ret, 1040*fa9e6df6SHardevsinh Palaniya "failed to get runtime PM noresume\n"); 1041*fa9e6df6SHardevsinh Palaniya goto error_subdev_cleanup; 1042*fa9e6df6SHardevsinh Palaniya } 1043*fa9e6df6SHardevsinh Palaniya 1044*fa9e6df6SHardevsinh Palaniya ret = devm_pm_runtime_set_active_enabled(ov2735->dev); 1045*fa9e6df6SHardevsinh Palaniya if (ret) { 1046*fa9e6df6SHardevsinh Palaniya dev_err_probe(ov2735->dev, ret, 1047*fa9e6df6SHardevsinh Palaniya "failed to set runtime PM active+enabled\n"); 1048*fa9e6df6SHardevsinh Palaniya goto error_subdev_cleanup; 1049*fa9e6df6SHardevsinh Palaniya } 1050*fa9e6df6SHardevsinh Palaniya 1051*fa9e6df6SHardevsinh Palaniya ret = v4l2_async_register_subdev_sensor(&ov2735->sd); 1052*fa9e6df6SHardevsinh Palaniya if (ret) { 1053*fa9e6df6SHardevsinh Palaniya dev_err_probe(ov2735->dev, ret, 1054*fa9e6df6SHardevsinh Palaniya "failed to register ov2735 sub-device\n"); 1055*fa9e6df6SHardevsinh Palaniya goto error_subdev_cleanup; 1056*fa9e6df6SHardevsinh Palaniya } 1057*fa9e6df6SHardevsinh Palaniya 1058*fa9e6df6SHardevsinh Palaniya return 0; 1059*fa9e6df6SHardevsinh Palaniya 1060*fa9e6df6SHardevsinh Palaniya error_subdev_cleanup: 1061*fa9e6df6SHardevsinh Palaniya v4l2_subdev_cleanup(&ov2735->sd); 1062*fa9e6df6SHardevsinh Palaniya 1063*fa9e6df6SHardevsinh Palaniya error_media_entity: 1064*fa9e6df6SHardevsinh Palaniya media_entity_cleanup(&ov2735->sd.entity); 1065*fa9e6df6SHardevsinh Palaniya 1066*fa9e6df6SHardevsinh Palaniya error_handler_free: 1067*fa9e6df6SHardevsinh Palaniya v4l2_ctrl_handler_free(ov2735->sd.ctrl_handler); 1068*fa9e6df6SHardevsinh Palaniya 1069*fa9e6df6SHardevsinh Palaniya error_power_off: 1070*fa9e6df6SHardevsinh Palaniya ov2735_power_off(ov2735->dev); 1071*fa9e6df6SHardevsinh Palaniya 1072*fa9e6df6SHardevsinh Palaniya return ret; 1073*fa9e6df6SHardevsinh Palaniya } 1074*fa9e6df6SHardevsinh Palaniya 1075*fa9e6df6SHardevsinh Palaniya static void ov2735_remove(struct i2c_client *client) 1076*fa9e6df6SHardevsinh Palaniya { 1077*fa9e6df6SHardevsinh Palaniya struct v4l2_subdev *sd = i2c_get_clientdata(client); 1078*fa9e6df6SHardevsinh Palaniya struct ov2735 *ov2735 = to_ov2735(sd); 1079*fa9e6df6SHardevsinh Palaniya 1080*fa9e6df6SHardevsinh Palaniya v4l2_async_unregister_subdev(sd); 1081*fa9e6df6SHardevsinh Palaniya v4l2_subdev_cleanup(&ov2735->sd); 1082*fa9e6df6SHardevsinh Palaniya media_entity_cleanup(&sd->entity); 1083*fa9e6df6SHardevsinh Palaniya v4l2_ctrl_handler_free(ov2735->sd.ctrl_handler); 1084*fa9e6df6SHardevsinh Palaniya } 1085*fa9e6df6SHardevsinh Palaniya 1086*fa9e6df6SHardevsinh Palaniya static DEFINE_RUNTIME_DEV_PM_OPS(ov2735_pm_ops, 1087*fa9e6df6SHardevsinh Palaniya ov2735_power_off, ov2735_power_on, NULL); 1088*fa9e6df6SHardevsinh Palaniya 1089*fa9e6df6SHardevsinh Palaniya static const struct of_device_id ov2735_id[] = { 1090*fa9e6df6SHardevsinh Palaniya { .compatible = "ovti,ov2735" }, 1091*fa9e6df6SHardevsinh Palaniya { /* sentinel */ } 1092*fa9e6df6SHardevsinh Palaniya }; 1093*fa9e6df6SHardevsinh Palaniya MODULE_DEVICE_TABLE(of, ov2735_id); 1094*fa9e6df6SHardevsinh Palaniya 1095*fa9e6df6SHardevsinh Palaniya static struct i2c_driver ov2735_driver = { 1096*fa9e6df6SHardevsinh Palaniya .driver = { 1097*fa9e6df6SHardevsinh Palaniya .name = "ov2735", 1098*fa9e6df6SHardevsinh Palaniya .pm = pm_ptr(&ov2735_pm_ops), 1099*fa9e6df6SHardevsinh Palaniya .of_match_table = ov2735_id, 1100*fa9e6df6SHardevsinh Palaniya }, 1101*fa9e6df6SHardevsinh Palaniya .probe = ov2735_probe, 1102*fa9e6df6SHardevsinh Palaniya .remove = ov2735_remove, 1103*fa9e6df6SHardevsinh Palaniya }; 1104*fa9e6df6SHardevsinh Palaniya module_i2c_driver(ov2735_driver); 1105*fa9e6df6SHardevsinh Palaniya 1106*fa9e6df6SHardevsinh Palaniya MODULE_DESCRIPTION("OV2735 Camera Sensor Driver"); 1107*fa9e6df6SHardevsinh Palaniya MODULE_AUTHOR("Hardevsinh Palaniya <hardevsinh.palaniya@siliconsignals.io>"); 1108*fa9e6df6SHardevsinh Palaniya MODULE_AUTHOR("Himanshu Bhavani <himanshu.bhavani@siliconsignals.io>"); 1109*fa9e6df6SHardevsinh Palaniya MODULE_LICENSE("GPL"); 1110