132a437dbSMikhail Rudenko // SPDX-License-Identifier: GPL-2.0 232a437dbSMikhail Rudenko /* 332a437dbSMikhail Rudenko * ov4689 driver 432a437dbSMikhail Rudenko * 532a437dbSMikhail Rudenko * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd. 6af9874c9SMikhail Rudenko * Copyright (C) 2022, 2024 Mikhail Rudenko 732a437dbSMikhail Rudenko */ 832a437dbSMikhail Rudenko 932a437dbSMikhail Rudenko #include <linux/clk.h> 1032a437dbSMikhail Rudenko #include <linux/delay.h> 1132a437dbSMikhail Rudenko #include <linux/gpio/consumer.h> 1232a437dbSMikhail Rudenko #include <linux/i2c.h> 1332a437dbSMikhail Rudenko #include <linux/module.h> 1432a437dbSMikhail Rudenko #include <linux/pm_runtime.h> 1532a437dbSMikhail Rudenko #include <linux/regulator/consumer.h> 1632a437dbSMikhail Rudenko #include <media/media-entity.h> 1732a437dbSMikhail Rudenko #include <media/v4l2-async.h> 188fe37e59SMikhail Rudenko #include <media/v4l2-cci.h> 1932a437dbSMikhail Rudenko #include <media/v4l2-ctrls.h> 2032a437dbSMikhail Rudenko #include <media/v4l2-subdev.h> 2132a437dbSMikhail Rudenko #include <media/v4l2-fwnode.h> 2232a437dbSMikhail Rudenko 238fe37e59SMikhail Rudenko #define OV4689_REG_CTRL_MODE CCI_REG8(0x0100) 2432a437dbSMikhail Rudenko #define OV4689_MODE_SW_STANDBY 0x0 2532a437dbSMikhail Rudenko #define OV4689_MODE_STREAMING BIT(0) 2632a437dbSMikhail Rudenko 278fe37e59SMikhail Rudenko #define OV4689_REG_CHIP_ID CCI_REG16(0x300a) 28f3adec37SMikhail Rudenko #define CHIP_ID 0x004688 29f3adec37SMikhail Rudenko 308fe37e59SMikhail Rudenko #define OV4689_REG_EXPOSURE CCI_REG24(0x3500) 3132a437dbSMikhail Rudenko #define OV4689_EXPOSURE_MIN 4 3232a437dbSMikhail Rudenko #define OV4689_EXPOSURE_STEP 1 3332a437dbSMikhail Rudenko #define OV4689_VTS_MAX 0x7fff 3432a437dbSMikhail Rudenko 358fe37e59SMikhail Rudenko #define OV4689_REG_GAIN CCI_REG16(0x3508) 3632a437dbSMikhail Rudenko #define OV4689_GAIN_STEP 1 3732a437dbSMikhail Rudenko #define OV4689_GAIN_DEFAULT 0x80 3832a437dbSMikhail Rudenko 398fe37e59SMikhail Rudenko #define OV4689_REG_VTS CCI_REG16(0x380e) 40f3adec37SMikhail Rudenko 418fe37e59SMikhail Rudenko #define OV4689_REG_TEST_PATTERN CCI_REG8(0x5040) 4232a437dbSMikhail Rudenko #define OV4689_TEST_PATTERN_ENABLE 0x80 4332a437dbSMikhail Rudenko #define OV4689_TEST_PATTERN_DISABLE 0x0 4432a437dbSMikhail Rudenko 4532a437dbSMikhail Rudenko #define OV4689_LANES 4 468fe37e59SMikhail Rudenko #define OV4689_XVCLK_FREQ 24000000 4732a437dbSMikhail Rudenko 4832a437dbSMikhail Rudenko static const char *const ov4689_supply_names[] = { 4932a437dbSMikhail Rudenko "avdd", /* Analog power */ 5032a437dbSMikhail Rudenko "dovdd", /* Digital I/O power */ 5132a437dbSMikhail Rudenko "dvdd", /* Digital core power */ 5232a437dbSMikhail Rudenko }; 5332a437dbSMikhail Rudenko 5432a437dbSMikhail Rudenko enum ov4689_mode_id { 5532a437dbSMikhail Rudenko OV4689_MODE_2688_1520 = 0, 5632a437dbSMikhail Rudenko OV4689_NUM_MODES, 5732a437dbSMikhail Rudenko }; 5832a437dbSMikhail Rudenko 5932a437dbSMikhail Rudenko struct ov4689_mode { 6032a437dbSMikhail Rudenko enum ov4689_mode_id id; 6132a437dbSMikhail Rudenko u32 width; 6232a437dbSMikhail Rudenko u32 height; 6332a437dbSMikhail Rudenko u32 max_fps; 6432a437dbSMikhail Rudenko u32 hts_def; 6532a437dbSMikhail Rudenko u32 vts_def; 6632a437dbSMikhail Rudenko u32 exp_def; 6732a437dbSMikhail Rudenko u32 pixel_rate; 6832a437dbSMikhail Rudenko u32 sensor_width; 6932a437dbSMikhail Rudenko u32 sensor_height; 7032a437dbSMikhail Rudenko u32 crop_top; 7132a437dbSMikhail Rudenko u32 crop_left; 728fe37e59SMikhail Rudenko const struct cci_reg_sequence *reg_list; 738fe37e59SMikhail Rudenko unsigned int num_regs; 7432a437dbSMikhail Rudenko }; 7532a437dbSMikhail Rudenko 7632a437dbSMikhail Rudenko struct ov4689 { 77*d015aaafSMikhail Rudenko struct device *dev; 788fe37e59SMikhail Rudenko struct regmap *regmap; 7932a437dbSMikhail Rudenko struct clk *xvclk; 8032a437dbSMikhail Rudenko struct gpio_desc *reset_gpio; 8132a437dbSMikhail Rudenko struct gpio_desc *pwdn_gpio; 8232a437dbSMikhail Rudenko struct regulator_bulk_data supplies[ARRAY_SIZE(ov4689_supply_names)]; 8332a437dbSMikhail Rudenko 8432a437dbSMikhail Rudenko struct v4l2_subdev subdev; 8532a437dbSMikhail Rudenko struct media_pad pad; 8632a437dbSMikhail Rudenko 8732a437dbSMikhail Rudenko u32 clock_rate; 8832a437dbSMikhail Rudenko 89e8d6eb9aSLaurent Pinchart struct mutex mutex; /* lock to protect ctrls and cur_mode */ 9032a437dbSMikhail Rudenko struct v4l2_ctrl_handler ctrl_handler; 9132a437dbSMikhail Rudenko struct v4l2_ctrl *exposure; 9232a437dbSMikhail Rudenko 9332a437dbSMikhail Rudenko const struct ov4689_mode *cur_mode; 9432a437dbSMikhail Rudenko }; 9532a437dbSMikhail Rudenko 9632a437dbSMikhail Rudenko #define to_ov4689(sd) container_of(sd, struct ov4689, subdev) 9732a437dbSMikhail Rudenko 9832a437dbSMikhail Rudenko struct ov4689_gain_range { 9932a437dbSMikhail Rudenko u32 logical_min; 10032a437dbSMikhail Rudenko u32 logical_max; 10132a437dbSMikhail Rudenko u32 offset; 10232a437dbSMikhail Rudenko u32 divider; 10332a437dbSMikhail Rudenko u32 physical_min; 10432a437dbSMikhail Rudenko u32 physical_max; 10532a437dbSMikhail Rudenko }; 10632a437dbSMikhail Rudenko 10732a437dbSMikhail Rudenko /* 10832a437dbSMikhail Rudenko * Xclk 24Mhz 10932a437dbSMikhail Rudenko * max_framerate 30fps 11032a437dbSMikhail Rudenko * mipi_datarate per lane 1008Mbps 11132a437dbSMikhail Rudenko */ 1128fe37e59SMikhail Rudenko static const struct cci_reg_sequence ov4689_2688x1520_regs[] = { 113af9874c9SMikhail Rudenko /* System control*/ 1148fe37e59SMikhail Rudenko { CCI_REG8(0x0103), 0x01 }, /* SC_CTRL0103 software_reset = 1 */ 1158fe37e59SMikhail Rudenko { CCI_REG8(0x3000), 0x20 }, /* SC_CMMN_PAD_OEN0 FSIN_output_enable = 1 */ 1168fe37e59SMikhail Rudenko { CCI_REG8(0x3021), 0x03 }, /* 117af9874c9SMikhail Rudenko * SC_CMMN_MISC_CTRL fst_stby_ctr = 0, 118af9874c9SMikhail Rudenko * sleep_no_latch_enable = 0 119af9874c9SMikhail Rudenko */ 120af9874c9SMikhail Rudenko 121af9874c9SMikhail Rudenko /* AEC PK */ 1228fe37e59SMikhail Rudenko { CCI_REG8(0x3503), 0x04 }, /* AEC_MANUAL gain_input_as_sensor_gain_format = 1 */ 1238fe37e59SMikhail Rudenko { CCI_REG8(0x352a), 0x08 }, /* DIG_GAIN_FRAC_LONG dig_gain_long[14:8] = 0x08 (2x) */ 124af9874c9SMikhail Rudenko 125af9874c9SMikhail Rudenko /* ADC and analog control*/ 1268fe37e59SMikhail Rudenko { CCI_REG8(0x3603), 0x40 }, 1278fe37e59SMikhail Rudenko { CCI_REG8(0x3604), 0x02 }, 1288fe37e59SMikhail Rudenko { CCI_REG8(0x3609), 0x12 }, 1298fe37e59SMikhail Rudenko { CCI_REG8(0x360c), 0x08 }, 1308fe37e59SMikhail Rudenko { CCI_REG8(0x360f), 0xe5 }, 1318fe37e59SMikhail Rudenko { CCI_REG8(0x3608), 0x8f }, 1328fe37e59SMikhail Rudenko { CCI_REG8(0x3611), 0x00 }, 1338fe37e59SMikhail Rudenko { CCI_REG8(0x3613), 0xf7 }, 1348fe37e59SMikhail Rudenko { CCI_REG8(0x3616), 0x58 }, 1358fe37e59SMikhail Rudenko { CCI_REG8(0x3619), 0x99 }, 1368fe37e59SMikhail Rudenko { CCI_REG8(0x361b), 0x60 }, 1378fe37e59SMikhail Rudenko { CCI_REG8(0x361e), 0x79 }, 1388fe37e59SMikhail Rudenko { CCI_REG8(0x3634), 0x10 }, 1398fe37e59SMikhail Rudenko { CCI_REG8(0x3635), 0x10 }, 1408fe37e59SMikhail Rudenko { CCI_REG8(0x3636), 0x15 }, 1418fe37e59SMikhail Rudenko { CCI_REG8(0x3646), 0x86 }, 1428fe37e59SMikhail Rudenko { CCI_REG8(0x364a), 0x0b }, 143af9874c9SMikhail Rudenko 144af9874c9SMikhail Rudenko /* Sensor control */ 1458fe37e59SMikhail Rudenko { CCI_REG8(0x3700), 0x17 }, 1468fe37e59SMikhail Rudenko { CCI_REG8(0x3701), 0x22 }, 1478fe37e59SMikhail Rudenko { CCI_REG8(0x3703), 0x10 }, 1488fe37e59SMikhail Rudenko { CCI_REG8(0x370a), 0x37 }, 1498fe37e59SMikhail Rudenko { CCI_REG8(0x3706), 0x63 }, 1508fe37e59SMikhail Rudenko { CCI_REG8(0x3709), 0x3c }, 1518fe37e59SMikhail Rudenko { CCI_REG8(0x370c), 0x30 }, 1528fe37e59SMikhail Rudenko { CCI_REG8(0x3710), 0x24 }, 1538fe37e59SMikhail Rudenko { CCI_REG8(0x3720), 0x28 }, 1548fe37e59SMikhail Rudenko { CCI_REG8(0x3729), 0x7b }, 1558fe37e59SMikhail Rudenko { CCI_REG8(0x372b), 0xbd }, 1568fe37e59SMikhail Rudenko { CCI_REG8(0x372c), 0xbc }, 1578fe37e59SMikhail Rudenko { CCI_REG8(0x372e), 0x52 }, 1588fe37e59SMikhail Rudenko { CCI_REG8(0x373c), 0x0e }, 1598fe37e59SMikhail Rudenko { CCI_REG8(0x373e), 0x33 }, 1608fe37e59SMikhail Rudenko { CCI_REG8(0x3743), 0x10 }, 1618fe37e59SMikhail Rudenko { CCI_REG8(0x3744), 0x88 }, 1628fe37e59SMikhail Rudenko { CCI_REG8(0x3745), 0xc0 }, 1638fe37e59SMikhail Rudenko { CCI_REG8(0x374c), 0x00 }, 1648fe37e59SMikhail Rudenko { CCI_REG8(0x374e), 0x23 }, 1658fe37e59SMikhail Rudenko { CCI_REG8(0x3751), 0x7b }, 1668fe37e59SMikhail Rudenko { CCI_REG8(0x3753), 0xbd }, 1678fe37e59SMikhail Rudenko { CCI_REG8(0x3754), 0xbc }, 1688fe37e59SMikhail Rudenko { CCI_REG8(0x3756), 0x52 }, 1698fe37e59SMikhail Rudenko { CCI_REG8(0x376b), 0x20 }, 1708fe37e59SMikhail Rudenko { CCI_REG8(0x3774), 0x51 }, 1718fe37e59SMikhail Rudenko { CCI_REG8(0x3776), 0xbd }, 1728fe37e59SMikhail Rudenko { CCI_REG8(0x3777), 0xbd }, 1738fe37e59SMikhail Rudenko { CCI_REG8(0x3781), 0x18 }, 1748fe37e59SMikhail Rudenko { CCI_REG8(0x3783), 0x25 }, 1758fe37e59SMikhail Rudenko { CCI_REG8(0x3798), 0x1b }, 176af9874c9SMikhail Rudenko 177af9874c9SMikhail Rudenko /* Timing control */ 1788fe37e59SMikhail Rudenko { CCI_REG8(0x3801), 0x08 }, /* H_CROP_START_L h_crop_start[7:0] = 0x08 */ 1798fe37e59SMikhail Rudenko { CCI_REG8(0x3805), 0x97 }, /* H_CROP_END_L h_crop_end[7:0] = 0x97 */ 1808fe37e59SMikhail Rudenko { CCI_REG8(0x380c), 0x0a }, /* TIMING_HTS_H hts[14:8] = 0x0a */ 1818fe37e59SMikhail Rudenko { CCI_REG8(0x380d), 0x0e }, /* TIMING_HTS_L hts[7:0] = 0x0e */ 1828fe37e59SMikhail Rudenko { CCI_REG8(0x3811), 0x08 }, /* H_WIN_OFF_L h_win_off[7:0] = 0x08*/ 1838fe37e59SMikhail Rudenko { CCI_REG8(0x3813), 0x04 }, /* V_WIN_OFF_L v_win_off[7:0] = 0x04 */ 1848fe37e59SMikhail Rudenko { CCI_REG8(0x3819), 0x01 }, /* VSYNC_END_L vsync_end_point[7:0] = 0x01 */ 1858fe37e59SMikhail Rudenko { CCI_REG8(0x3821), 0x06 }, /* TIMING_FORMAT2 array_h_mirror = 1, digital_h_mirror = 1 */ 186af9874c9SMikhail Rudenko 187af9874c9SMikhail Rudenko /* OTP control */ 1888fe37e59SMikhail Rudenko { CCI_REG8(0x3d85), 0x36 }, /* OTP_REG85 OTP_power_up_load_setting_enable = 1, 189af9874c9SMikhail Rudenko * OTP_power_up_load_data_enable = 1, 190af9874c9SMikhail Rudenko * OTP_bist_select = 1 (compare with zero) 191af9874c9SMikhail Rudenko */ 1928fe37e59SMikhail Rudenko { CCI_REG8(0x3d8c), 0x71 }, /* OTP_SETTING_STT_ADDRESS_H */ 1938fe37e59SMikhail Rudenko { CCI_REG8(0x3d8d), 0xcb }, /* OTP_SETTING_STT_ADDRESS_L */ 194af9874c9SMikhail Rudenko 195af9874c9SMikhail Rudenko /* BLC registers*/ 1968fe37e59SMikhail Rudenko { CCI_REG8(0x4001), 0x40 }, /* DEBUG_MODE */ 1978fe37e59SMikhail Rudenko { CCI_REG8(0x401b), 0x00 }, /* DEBUG_MODE */ 1988fe37e59SMikhail Rudenko { CCI_REG8(0x401d), 0x00 }, /* DEBUG_MODE */ 1998fe37e59SMikhail Rudenko { CCI_REG8(0x401f), 0x00 }, /* DEBUG_MODE */ 2008fe37e59SMikhail Rudenko { CCI_REG8(0x4020), 0x00 }, /* ANCHOR_LEFT_START_H anchor_left_start[11:8] = 0 */ 2018fe37e59SMikhail Rudenko { CCI_REG8(0x4021), 0x10 }, /* ANCHOR_LEFT_START_L anchor_left_start[7:0] = 0x10 */ 2028fe37e59SMikhail Rudenko { CCI_REG8(0x4022), 0x07 }, /* ANCHOR_LEFT_END_H anchor_left_end[11:8] = 0x07 */ 2038fe37e59SMikhail Rudenko { CCI_REG8(0x4023), 0xcf }, /* ANCHOR_LEFT_END_L anchor_left_end[7:0] = 0xcf */ 2048fe37e59SMikhail Rudenko { CCI_REG8(0x4024), 0x09 }, /* ANCHOR_RIGHT_START_H anchor_right_start[11:8] = 0x09 */ 2058fe37e59SMikhail Rudenko { CCI_REG8(0x4025), 0x60 }, /* ANCHOR_RIGHT_START_L anchor_right_start[7:0] = 0x60 */ 2068fe37e59SMikhail Rudenko { CCI_REG8(0x4026), 0x09 }, /* ANCHOR_RIGHT_END_H anchor_right_end[11:8] = 0x09 */ 2078fe37e59SMikhail Rudenko { CCI_REG8(0x4027), 0x6f }, /* ANCHOR_RIGHT_END_L anchor_right_end[7:0] = 0x6f */ 208af9874c9SMikhail Rudenko 209af9874c9SMikhail Rudenko /* ADC sync control */ 2108fe37e59SMikhail Rudenko { CCI_REG8(0x4500), 0x6c }, /* ADC_SYNC_CTRL */ 2118fe37e59SMikhail Rudenko { CCI_REG8(0x4503), 0x01 }, /* ADC_SYNC_CTRL */ 212af9874c9SMikhail Rudenko 213af9874c9SMikhail Rudenko /* VFIFO */ 2148fe37e59SMikhail Rudenko { CCI_REG8(0x4601), 0xa7 }, /* VFIFO_CTRL_01 r_vfifo_read_start[7:0] = 0xa7 */ 215af9874c9SMikhail Rudenko 216af9874c9SMikhail Rudenko /* Temperature monitor */ 2178fe37e59SMikhail Rudenko { CCI_REG8(0x4d00), 0x04 }, /* TPM_CTRL_00 tmp_slope[15:8] = 0x04 */ 2188fe37e59SMikhail Rudenko { CCI_REG8(0x4d01), 0x42 }, /* TPM_CTRL_01 tmp_slope[7:0] = 0x42 */ 2198fe37e59SMikhail Rudenko { CCI_REG8(0x4d02), 0xd1 }, /* TPM_CTRL_02 tpm_offset[31:24] = 0xd1 */ 2208fe37e59SMikhail Rudenko { CCI_REG8(0x4d03), 0x93 }, /* TPM_CTRL_03 tpm_offset[23:16] = 0x93 */ 2218fe37e59SMikhail Rudenko { CCI_REG8(0x4d04), 0xf5 }, /* TPM_CTRL_04 tpm_offset[15:8] = 0xf5 */ 2228fe37e59SMikhail Rudenko { CCI_REG8(0x4d05), 0xc1 }, /* TPM_CTRL_05 tpm_offset[7:0] = 0xc1 */ 223af9874c9SMikhail Rudenko 224af9874c9SMikhail Rudenko /* pre-ISP control */ 2258fe37e59SMikhail Rudenko { CCI_REG8(0x5050), 0x0c }, /* DEBUG_MODE */ 226af9874c9SMikhail Rudenko 227af9874c9SMikhail Rudenko /* OTP-DPC control */ 2288fe37e59SMikhail Rudenko { CCI_REG8(0x5501), 0x10 }, /* OTP_DPC_START_L otp_start_address[7:0] = 0x10 */ 2298fe37e59SMikhail Rudenko { CCI_REG8(0x5503), 0x0f }, /* OTP_DPC_END_L otp_end_address[7:0] = 0x0f */ 23032a437dbSMikhail Rudenko }; 23132a437dbSMikhail Rudenko 23232a437dbSMikhail Rudenko static const struct ov4689_mode supported_modes[] = { 23332a437dbSMikhail Rudenko { 23432a437dbSMikhail Rudenko .id = OV4689_MODE_2688_1520, 23532a437dbSMikhail Rudenko .width = 2688, 23632a437dbSMikhail Rudenko .height = 1520, 23732a437dbSMikhail Rudenko .sensor_width = 2720, 23832a437dbSMikhail Rudenko .sensor_height = 1536, 23932a437dbSMikhail Rudenko .crop_top = 8, 24032a437dbSMikhail Rudenko .crop_left = 16, 24132a437dbSMikhail Rudenko .max_fps = 30, 24232a437dbSMikhail Rudenko .exp_def = 1536, 24332a437dbSMikhail Rudenko .hts_def = 4 * 2574, 24432a437dbSMikhail Rudenko .vts_def = 1554, 24532a437dbSMikhail Rudenko .pixel_rate = 480000000, 24632a437dbSMikhail Rudenko .reg_list = ov4689_2688x1520_regs, 2478fe37e59SMikhail Rudenko .num_regs = ARRAY_SIZE(ov4689_2688x1520_regs), 24832a437dbSMikhail Rudenko }, 24932a437dbSMikhail Rudenko }; 25032a437dbSMikhail Rudenko 25132a437dbSMikhail Rudenko static const u64 link_freq_menu_items[] = { 504000000 }; 25232a437dbSMikhail Rudenko 25332a437dbSMikhail Rudenko static const char *const ov4689_test_pattern_menu[] = { 25432a437dbSMikhail Rudenko "Disabled", 25532a437dbSMikhail Rudenko "Vertical Color Bar Type 1", 25632a437dbSMikhail Rudenko "Vertical Color Bar Type 2", 25732a437dbSMikhail Rudenko "Vertical Color Bar Type 3", 25832a437dbSMikhail Rudenko "Vertical Color Bar Type 4" 25932a437dbSMikhail Rudenko }; 26032a437dbSMikhail Rudenko 26132a437dbSMikhail Rudenko /* 26232a437dbSMikhail Rudenko * These coefficients are based on those used in Rockchip's camera 26332a437dbSMikhail Rudenko * engine, with minor tweaks for continuity. 26432a437dbSMikhail Rudenko */ 26532a437dbSMikhail Rudenko static const struct ov4689_gain_range ov4689_gain_ranges[] = { 26632a437dbSMikhail Rudenko { 26732a437dbSMikhail Rudenko .logical_min = 0, 26832a437dbSMikhail Rudenko .logical_max = 255, 26932a437dbSMikhail Rudenko .offset = 0, 27032a437dbSMikhail Rudenko .divider = 1, 27132a437dbSMikhail Rudenko .physical_min = 0, 27232a437dbSMikhail Rudenko .physical_max = 255, 27332a437dbSMikhail Rudenko }, 27432a437dbSMikhail Rudenko { 27532a437dbSMikhail Rudenko .logical_min = 256, 27632a437dbSMikhail Rudenko .logical_max = 511, 27732a437dbSMikhail Rudenko .offset = 252, 27832a437dbSMikhail Rudenko .divider = 2, 27932a437dbSMikhail Rudenko .physical_min = 376, 28032a437dbSMikhail Rudenko .physical_max = 504, 28132a437dbSMikhail Rudenko }, 28232a437dbSMikhail Rudenko { 28332a437dbSMikhail Rudenko .logical_min = 512, 28432a437dbSMikhail Rudenko .logical_max = 1023, 28532a437dbSMikhail Rudenko .offset = 758, 28632a437dbSMikhail Rudenko .divider = 4, 28732a437dbSMikhail Rudenko .physical_min = 884, 28832a437dbSMikhail Rudenko .physical_max = 1012, 28932a437dbSMikhail Rudenko }, 29032a437dbSMikhail Rudenko { 29132a437dbSMikhail Rudenko .logical_min = 1024, 29232a437dbSMikhail Rudenko .logical_max = 2047, 29332a437dbSMikhail Rudenko .offset = 1788, 29432a437dbSMikhail Rudenko .divider = 8, 29532a437dbSMikhail Rudenko .physical_min = 1912, 29632a437dbSMikhail Rudenko .physical_max = 2047, 29732a437dbSMikhail Rudenko }, 29832a437dbSMikhail Rudenko }; 29932a437dbSMikhail Rudenko 30032a437dbSMikhail Rudenko static void ov4689_fill_fmt(const struct ov4689_mode *mode, 30132a437dbSMikhail Rudenko struct v4l2_mbus_framefmt *fmt) 30232a437dbSMikhail Rudenko { 30332a437dbSMikhail Rudenko fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; 30432a437dbSMikhail Rudenko fmt->width = mode->width; 30532a437dbSMikhail Rudenko fmt->height = mode->height; 30632a437dbSMikhail Rudenko fmt->field = V4L2_FIELD_NONE; 30732a437dbSMikhail Rudenko } 30832a437dbSMikhail Rudenko 30932a437dbSMikhail Rudenko static int ov4689_set_fmt(struct v4l2_subdev *sd, 31032a437dbSMikhail Rudenko struct v4l2_subdev_state *sd_state, 31132a437dbSMikhail Rudenko struct v4l2_subdev_format *fmt) 31232a437dbSMikhail Rudenko { 31332a437dbSMikhail Rudenko struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format; 31432a437dbSMikhail Rudenko struct ov4689 *ov4689 = to_ov4689(sd); 31532a437dbSMikhail Rudenko 31632a437dbSMikhail Rudenko /* only one mode supported for now */ 31732a437dbSMikhail Rudenko ov4689_fill_fmt(ov4689->cur_mode, mbus_fmt); 31832a437dbSMikhail Rudenko 31932a437dbSMikhail Rudenko return 0; 32032a437dbSMikhail Rudenko } 32132a437dbSMikhail Rudenko 32232a437dbSMikhail Rudenko static int ov4689_get_fmt(struct v4l2_subdev *sd, 32332a437dbSMikhail Rudenko struct v4l2_subdev_state *sd_state, 32432a437dbSMikhail Rudenko struct v4l2_subdev_format *fmt) 32532a437dbSMikhail Rudenko { 32632a437dbSMikhail Rudenko struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format; 32732a437dbSMikhail Rudenko struct ov4689 *ov4689 = to_ov4689(sd); 32832a437dbSMikhail Rudenko 32932a437dbSMikhail Rudenko /* only one mode supported for now */ 33032a437dbSMikhail Rudenko ov4689_fill_fmt(ov4689->cur_mode, mbus_fmt); 33132a437dbSMikhail Rudenko 33232a437dbSMikhail Rudenko return 0; 33332a437dbSMikhail Rudenko } 33432a437dbSMikhail Rudenko 33532a437dbSMikhail Rudenko static int ov4689_enum_mbus_code(struct v4l2_subdev *sd, 33632a437dbSMikhail Rudenko struct v4l2_subdev_state *sd_state, 33732a437dbSMikhail Rudenko struct v4l2_subdev_mbus_code_enum *code) 33832a437dbSMikhail Rudenko { 33932a437dbSMikhail Rudenko if (code->index != 0) 34032a437dbSMikhail Rudenko return -EINVAL; 34132a437dbSMikhail Rudenko code->code = MEDIA_BUS_FMT_SBGGR10_1X10; 34232a437dbSMikhail Rudenko 34332a437dbSMikhail Rudenko return 0; 34432a437dbSMikhail Rudenko } 34532a437dbSMikhail Rudenko 34632a437dbSMikhail Rudenko static int ov4689_enum_frame_sizes(struct v4l2_subdev *sd, 34732a437dbSMikhail Rudenko struct v4l2_subdev_state *sd_state, 34832a437dbSMikhail Rudenko struct v4l2_subdev_frame_size_enum *fse) 34932a437dbSMikhail Rudenko { 35032a437dbSMikhail Rudenko if (fse->index >= ARRAY_SIZE(supported_modes)) 35132a437dbSMikhail Rudenko return -EINVAL; 35232a437dbSMikhail Rudenko 35332a437dbSMikhail Rudenko if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10) 35432a437dbSMikhail Rudenko return -EINVAL; 35532a437dbSMikhail Rudenko 35632a437dbSMikhail Rudenko fse->min_width = supported_modes[fse->index].width; 35732a437dbSMikhail Rudenko fse->max_width = supported_modes[fse->index].width; 35832a437dbSMikhail Rudenko fse->max_height = supported_modes[fse->index].height; 35932a437dbSMikhail Rudenko fse->min_height = supported_modes[fse->index].height; 36032a437dbSMikhail Rudenko 36132a437dbSMikhail Rudenko return 0; 36232a437dbSMikhail Rudenko } 36332a437dbSMikhail Rudenko 36432a437dbSMikhail Rudenko static int ov4689_enable_test_pattern(struct ov4689 *ov4689, u32 pattern) 36532a437dbSMikhail Rudenko { 36632a437dbSMikhail Rudenko u32 val; 36732a437dbSMikhail Rudenko 36832a437dbSMikhail Rudenko if (pattern) 36932a437dbSMikhail Rudenko val = (pattern - 1) | OV4689_TEST_PATTERN_ENABLE; 37032a437dbSMikhail Rudenko else 37132a437dbSMikhail Rudenko val = OV4689_TEST_PATTERN_DISABLE; 37232a437dbSMikhail Rudenko 3738fe37e59SMikhail Rudenko return cci_write(ov4689->regmap, OV4689_REG_TEST_PATTERN, 3748fe37e59SMikhail Rudenko val, NULL); 37532a437dbSMikhail Rudenko } 37632a437dbSMikhail Rudenko 37732a437dbSMikhail Rudenko static int ov4689_get_selection(struct v4l2_subdev *sd, 37832a437dbSMikhail Rudenko struct v4l2_subdev_state *state, 37932a437dbSMikhail Rudenko struct v4l2_subdev_selection *sel) 38032a437dbSMikhail Rudenko { 38132a437dbSMikhail Rudenko const struct ov4689_mode *mode = to_ov4689(sd)->cur_mode; 38232a437dbSMikhail Rudenko 38332a437dbSMikhail Rudenko if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) 38432a437dbSMikhail Rudenko return -EINVAL; 38532a437dbSMikhail Rudenko 38632a437dbSMikhail Rudenko switch (sel->target) { 38732a437dbSMikhail Rudenko case V4L2_SEL_TGT_CROP_BOUNDS: 38832a437dbSMikhail Rudenko sel->r.top = 0; 38932a437dbSMikhail Rudenko sel->r.left = 0; 39032a437dbSMikhail Rudenko sel->r.width = mode->sensor_width; 39132a437dbSMikhail Rudenko sel->r.height = mode->sensor_height; 39232a437dbSMikhail Rudenko return 0; 39332a437dbSMikhail Rudenko case V4L2_SEL_TGT_CROP: 39432a437dbSMikhail Rudenko case V4L2_SEL_TGT_CROP_DEFAULT: 39532a437dbSMikhail Rudenko sel->r.top = mode->crop_top; 39632a437dbSMikhail Rudenko sel->r.left = mode->crop_left; 39732a437dbSMikhail Rudenko sel->r.width = mode->width; 39832a437dbSMikhail Rudenko sel->r.height = mode->height; 39932a437dbSMikhail Rudenko return 0; 40032a437dbSMikhail Rudenko } 40132a437dbSMikhail Rudenko 40232a437dbSMikhail Rudenko return -EINVAL; 40332a437dbSMikhail Rudenko } 40432a437dbSMikhail Rudenko 40532a437dbSMikhail Rudenko static int ov4689_s_stream(struct v4l2_subdev *sd, int on) 40632a437dbSMikhail Rudenko { 40732a437dbSMikhail Rudenko struct ov4689 *ov4689 = to_ov4689(sd); 408*d015aaafSMikhail Rudenko struct device *dev = ov4689->dev; 40932a437dbSMikhail Rudenko int ret = 0; 41032a437dbSMikhail Rudenko 41132a437dbSMikhail Rudenko mutex_lock(&ov4689->mutex); 41232a437dbSMikhail Rudenko 41332a437dbSMikhail Rudenko if (on) { 414*d015aaafSMikhail Rudenko ret = pm_runtime_resume_and_get(dev); 41532a437dbSMikhail Rudenko if (ret < 0) 41632a437dbSMikhail Rudenko goto unlock_and_return; 41732a437dbSMikhail Rudenko 4188fe37e59SMikhail Rudenko ret = cci_multi_reg_write(ov4689->regmap, 4198fe37e59SMikhail Rudenko ov4689->cur_mode->reg_list, 4208fe37e59SMikhail Rudenko ov4689->cur_mode->num_regs, 4218fe37e59SMikhail Rudenko NULL); 42232a437dbSMikhail Rudenko if (ret) { 423*d015aaafSMikhail Rudenko pm_runtime_put(dev); 42432a437dbSMikhail Rudenko goto unlock_and_return; 42532a437dbSMikhail Rudenko } 42632a437dbSMikhail Rudenko 42732a437dbSMikhail Rudenko ret = __v4l2_ctrl_handler_setup(&ov4689->ctrl_handler); 42832a437dbSMikhail Rudenko if (ret) { 429*d015aaafSMikhail Rudenko pm_runtime_put(dev); 43032a437dbSMikhail Rudenko goto unlock_and_return; 43132a437dbSMikhail Rudenko } 43232a437dbSMikhail Rudenko 4338fe37e59SMikhail Rudenko ret = cci_write(ov4689->regmap, OV4689_REG_CTRL_MODE, 4348fe37e59SMikhail Rudenko OV4689_MODE_STREAMING, NULL); 43532a437dbSMikhail Rudenko if (ret) { 436*d015aaafSMikhail Rudenko pm_runtime_put(dev); 43732a437dbSMikhail Rudenko goto unlock_and_return; 43832a437dbSMikhail Rudenko } 43932a437dbSMikhail Rudenko } else { 4408fe37e59SMikhail Rudenko cci_write(ov4689->regmap, OV4689_REG_CTRL_MODE, 4418fe37e59SMikhail Rudenko OV4689_MODE_SW_STANDBY, NULL); 442*d015aaafSMikhail Rudenko pm_runtime_put(dev); 44332a437dbSMikhail Rudenko } 44432a437dbSMikhail Rudenko 44532a437dbSMikhail Rudenko unlock_and_return: 44632a437dbSMikhail Rudenko mutex_unlock(&ov4689->mutex); 44732a437dbSMikhail Rudenko 44832a437dbSMikhail Rudenko return ret; 44932a437dbSMikhail Rudenko } 45032a437dbSMikhail Rudenko 45132a437dbSMikhail Rudenko /* Calculate the delay in us by clock rate and clock cycles */ 45232a437dbSMikhail Rudenko static inline u32 ov4689_cal_delay(struct ov4689 *ov4689, u32 cycles) 45332a437dbSMikhail Rudenko { 45432a437dbSMikhail Rudenko return DIV_ROUND_UP(cycles * 1000, 45532a437dbSMikhail Rudenko DIV_ROUND_UP(ov4689->clock_rate, 1000)); 45632a437dbSMikhail Rudenko } 45732a437dbSMikhail Rudenko 45832a437dbSMikhail Rudenko static int __maybe_unused ov4689_power_on(struct device *dev) 45932a437dbSMikhail Rudenko { 46032a437dbSMikhail Rudenko struct v4l2_subdev *sd = dev_get_drvdata(dev); 46132a437dbSMikhail Rudenko struct ov4689 *ov4689 = to_ov4689(sd); 46232a437dbSMikhail Rudenko u32 delay_us; 46332a437dbSMikhail Rudenko int ret; 46432a437dbSMikhail Rudenko 46532a437dbSMikhail Rudenko ret = clk_prepare_enable(ov4689->xvclk); 46632a437dbSMikhail Rudenko if (ret < 0) { 46732a437dbSMikhail Rudenko dev_err(dev, "Failed to enable xvclk\n"); 46832a437dbSMikhail Rudenko return ret; 46932a437dbSMikhail Rudenko } 47032a437dbSMikhail Rudenko 47132a437dbSMikhail Rudenko gpiod_set_value_cansleep(ov4689->reset_gpio, 1); 47232a437dbSMikhail Rudenko 47332a437dbSMikhail Rudenko ret = regulator_bulk_enable(ARRAY_SIZE(ov4689_supply_names), 47432a437dbSMikhail Rudenko ov4689->supplies); 47532a437dbSMikhail Rudenko if (ret < 0) { 47632a437dbSMikhail Rudenko dev_err(dev, "Failed to enable regulators\n"); 47732a437dbSMikhail Rudenko goto disable_clk; 47832a437dbSMikhail Rudenko } 47932a437dbSMikhail Rudenko 48032a437dbSMikhail Rudenko gpiod_set_value_cansleep(ov4689->reset_gpio, 0); 48132a437dbSMikhail Rudenko usleep_range(500, 1000); 48232a437dbSMikhail Rudenko gpiod_set_value_cansleep(ov4689->pwdn_gpio, 0); 48332a437dbSMikhail Rudenko 48432a437dbSMikhail Rudenko /* 8192 cycles prior to first SCCB transaction */ 48532a437dbSMikhail Rudenko delay_us = ov4689_cal_delay(ov4689, 8192); 48632a437dbSMikhail Rudenko usleep_range(delay_us, delay_us * 2); 48732a437dbSMikhail Rudenko 48832a437dbSMikhail Rudenko return 0; 48932a437dbSMikhail Rudenko 49032a437dbSMikhail Rudenko disable_clk: 49132a437dbSMikhail Rudenko clk_disable_unprepare(ov4689->xvclk); 49232a437dbSMikhail Rudenko 49332a437dbSMikhail Rudenko return ret; 49432a437dbSMikhail Rudenko } 49532a437dbSMikhail Rudenko 49632a437dbSMikhail Rudenko static int __maybe_unused ov4689_power_off(struct device *dev) 49732a437dbSMikhail Rudenko { 49832a437dbSMikhail Rudenko struct v4l2_subdev *sd = dev_get_drvdata(dev); 49932a437dbSMikhail Rudenko struct ov4689 *ov4689 = to_ov4689(sd); 50032a437dbSMikhail Rudenko 50132a437dbSMikhail Rudenko gpiod_set_value_cansleep(ov4689->pwdn_gpio, 1); 50232a437dbSMikhail Rudenko clk_disable_unprepare(ov4689->xvclk); 50332a437dbSMikhail Rudenko gpiod_set_value_cansleep(ov4689->reset_gpio, 1); 50432a437dbSMikhail Rudenko regulator_bulk_disable(ARRAY_SIZE(ov4689_supply_names), 50532a437dbSMikhail Rudenko ov4689->supplies); 50632a437dbSMikhail Rudenko return 0; 50732a437dbSMikhail Rudenko } 50832a437dbSMikhail Rudenko 50932a437dbSMikhail Rudenko static int ov4689_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 51032a437dbSMikhail Rudenko { 51132a437dbSMikhail Rudenko struct ov4689 *ov4689 = to_ov4689(sd); 51232a437dbSMikhail Rudenko struct v4l2_mbus_framefmt *try_fmt; 51332a437dbSMikhail Rudenko 51432a437dbSMikhail Rudenko mutex_lock(&ov4689->mutex); 51532a437dbSMikhail Rudenko 516bc0e8d91SSakari Ailus try_fmt = v4l2_subdev_state_get_format(fh->state, 0); 51732a437dbSMikhail Rudenko /* Initialize try_fmt */ 51832a437dbSMikhail Rudenko ov4689_fill_fmt(&supported_modes[OV4689_MODE_2688_1520], try_fmt); 51932a437dbSMikhail Rudenko 52032a437dbSMikhail Rudenko mutex_unlock(&ov4689->mutex); 52132a437dbSMikhail Rudenko 52232a437dbSMikhail Rudenko return 0; 52332a437dbSMikhail Rudenko } 52432a437dbSMikhail Rudenko 52532a437dbSMikhail Rudenko static const struct dev_pm_ops ov4689_pm_ops = { 52632a437dbSMikhail Rudenko SET_RUNTIME_PM_OPS(ov4689_power_off, ov4689_power_on, NULL) 52732a437dbSMikhail Rudenko }; 52832a437dbSMikhail Rudenko 52932a437dbSMikhail Rudenko static const struct v4l2_subdev_internal_ops ov4689_internal_ops = { 53032a437dbSMikhail Rudenko .open = ov4689_open, 53132a437dbSMikhail Rudenko }; 53232a437dbSMikhail Rudenko 53332a437dbSMikhail Rudenko static const struct v4l2_subdev_video_ops ov4689_video_ops = { 53432a437dbSMikhail Rudenko .s_stream = ov4689_s_stream, 53532a437dbSMikhail Rudenko }; 53632a437dbSMikhail Rudenko 53732a437dbSMikhail Rudenko static const struct v4l2_subdev_pad_ops ov4689_pad_ops = { 53832a437dbSMikhail Rudenko .enum_mbus_code = ov4689_enum_mbus_code, 53932a437dbSMikhail Rudenko .enum_frame_size = ov4689_enum_frame_sizes, 54032a437dbSMikhail Rudenko .get_fmt = ov4689_get_fmt, 54132a437dbSMikhail Rudenko .set_fmt = ov4689_set_fmt, 54232a437dbSMikhail Rudenko .get_selection = ov4689_get_selection, 54332a437dbSMikhail Rudenko }; 54432a437dbSMikhail Rudenko 54532a437dbSMikhail Rudenko static const struct v4l2_subdev_ops ov4689_subdev_ops = { 54632a437dbSMikhail Rudenko .video = &ov4689_video_ops, 54732a437dbSMikhail Rudenko .pad = &ov4689_pad_ops, 54832a437dbSMikhail Rudenko }; 54932a437dbSMikhail Rudenko 55032a437dbSMikhail Rudenko /* 55132a437dbSMikhail Rudenko * Map userspace (logical) gain to sensor (physical) gain using 55232a437dbSMikhail Rudenko * ov4689_gain_ranges table. 55332a437dbSMikhail Rudenko */ 55432a437dbSMikhail Rudenko static int ov4689_map_gain(struct ov4689 *ov4689, int logical_gain, int *result) 55532a437dbSMikhail Rudenko { 55632a437dbSMikhail Rudenko const struct ov4689_gain_range *range; 55732a437dbSMikhail Rudenko unsigned int n; 55832a437dbSMikhail Rudenko 55932a437dbSMikhail Rudenko for (n = 0; n < ARRAY_SIZE(ov4689_gain_ranges); n++) { 56032a437dbSMikhail Rudenko if (logical_gain >= ov4689_gain_ranges[n].logical_min && 5617336c54aSMikhail Rudenko logical_gain <= ov4689_gain_ranges[n].logical_max) 56232a437dbSMikhail Rudenko break; 56332a437dbSMikhail Rudenko } 56432a437dbSMikhail Rudenko 56532a437dbSMikhail Rudenko if (n == ARRAY_SIZE(ov4689_gain_ranges)) { 566*d015aaafSMikhail Rudenko dev_warn_ratelimited(ov4689->dev, 567*d015aaafSMikhail Rudenko "no mapping found for gain %d\n", 56832a437dbSMikhail Rudenko logical_gain); 56932a437dbSMikhail Rudenko return -EINVAL; 57032a437dbSMikhail Rudenko } 57132a437dbSMikhail Rudenko 57232a437dbSMikhail Rudenko range = &ov4689_gain_ranges[n]; 57332a437dbSMikhail Rudenko 57432a437dbSMikhail Rudenko *result = clamp(range->offset + (logical_gain) / range->divider, 57532a437dbSMikhail Rudenko range->physical_min, range->physical_max); 57632a437dbSMikhail Rudenko return 0; 57732a437dbSMikhail Rudenko } 57832a437dbSMikhail Rudenko 57932a437dbSMikhail Rudenko static int ov4689_set_ctrl(struct v4l2_ctrl *ctrl) 58032a437dbSMikhail Rudenko { 58132a437dbSMikhail Rudenko struct ov4689 *ov4689 = 58232a437dbSMikhail Rudenko container_of(ctrl->handler, struct ov4689, ctrl_handler); 583*d015aaafSMikhail Rudenko struct device *dev = ov4689->dev; 5848fe37e59SMikhail Rudenko int sensor_gain = 0; 58532a437dbSMikhail Rudenko s64 max_expo; 58632a437dbSMikhail Rudenko int ret; 58732a437dbSMikhail Rudenko 58832a437dbSMikhail Rudenko /* Propagate change of current control to all related controls */ 58932a437dbSMikhail Rudenko switch (ctrl->id) { 59032a437dbSMikhail Rudenko case V4L2_CID_VBLANK: 59132a437dbSMikhail Rudenko /* Update max exposure while meeting expected vblanking */ 59232a437dbSMikhail Rudenko max_expo = ov4689->cur_mode->height + ctrl->val - 4; 59332a437dbSMikhail Rudenko __v4l2_ctrl_modify_range(ov4689->exposure, 59432a437dbSMikhail Rudenko ov4689->exposure->minimum, max_expo, 59532a437dbSMikhail Rudenko ov4689->exposure->step, 59632a437dbSMikhail Rudenko ov4689->exposure->default_value); 59732a437dbSMikhail Rudenko break; 59832a437dbSMikhail Rudenko } 59932a437dbSMikhail Rudenko 600*d015aaafSMikhail Rudenko if (!pm_runtime_get_if_in_use(dev)) 60132a437dbSMikhail Rudenko return 0; 60232a437dbSMikhail Rudenko 60332a437dbSMikhail Rudenko switch (ctrl->id) { 60432a437dbSMikhail Rudenko case V4L2_CID_EXPOSURE: 60561198ad4SMikhail Rudenko /* 4 least significant bits of exposure are fractional part */ 6068fe37e59SMikhail Rudenko ret = cci_write(ov4689->regmap, OV4689_REG_EXPOSURE, 6078fe37e59SMikhail Rudenko ctrl->val << 4, NULL); 60832a437dbSMikhail Rudenko break; 60932a437dbSMikhail Rudenko case V4L2_CID_ANALOGUE_GAIN: 61032a437dbSMikhail Rudenko ret = ov4689_map_gain(ov4689, ctrl->val, &sensor_gain); 6118fe37e59SMikhail Rudenko cci_write(ov4689->regmap, OV4689_REG_GAIN, sensor_gain, &ret); 61232a437dbSMikhail Rudenko break; 61332a437dbSMikhail Rudenko case V4L2_CID_VBLANK: 6148fe37e59SMikhail Rudenko ret = cci_write(ov4689->regmap, OV4689_REG_VTS, 6158fe37e59SMikhail Rudenko ctrl->val + ov4689->cur_mode->height, NULL); 61632a437dbSMikhail Rudenko break; 61732a437dbSMikhail Rudenko case V4L2_CID_TEST_PATTERN: 61832a437dbSMikhail Rudenko ret = ov4689_enable_test_pattern(ov4689, ctrl->val); 61932a437dbSMikhail Rudenko break; 62032a437dbSMikhail Rudenko default: 621*d015aaafSMikhail Rudenko dev_warn(dev, "%s Unhandled id:0x%x, val:0x%x\n", 62232a437dbSMikhail Rudenko __func__, ctrl->id, ctrl->val); 62332a437dbSMikhail Rudenko ret = -EINVAL; 62432a437dbSMikhail Rudenko break; 62532a437dbSMikhail Rudenko } 62632a437dbSMikhail Rudenko 627*d015aaafSMikhail Rudenko pm_runtime_put(dev); 62832a437dbSMikhail Rudenko 62932a437dbSMikhail Rudenko return ret; 63032a437dbSMikhail Rudenko } 63132a437dbSMikhail Rudenko 63232a437dbSMikhail Rudenko static const struct v4l2_ctrl_ops ov4689_ctrl_ops = { 63332a437dbSMikhail Rudenko .s_ctrl = ov4689_set_ctrl, 63432a437dbSMikhail Rudenko }; 63532a437dbSMikhail Rudenko 63632a437dbSMikhail Rudenko static int ov4689_initialize_controls(struct ov4689 *ov4689) 63732a437dbSMikhail Rudenko { 63832a437dbSMikhail Rudenko struct i2c_client *client = v4l2_get_subdevdata(&ov4689->subdev); 63932a437dbSMikhail Rudenko struct v4l2_fwnode_device_properties props; 64032a437dbSMikhail Rudenko struct v4l2_ctrl_handler *handler; 64132a437dbSMikhail Rudenko const struct ov4689_mode *mode; 64232a437dbSMikhail Rudenko s64 exposure_max, vblank_def; 64332a437dbSMikhail Rudenko struct v4l2_ctrl *ctrl; 64432a437dbSMikhail Rudenko s64 h_blank_def; 64532a437dbSMikhail Rudenko int ret; 64632a437dbSMikhail Rudenko 64732a437dbSMikhail Rudenko handler = &ov4689->ctrl_handler; 64832a437dbSMikhail Rudenko mode = ov4689->cur_mode; 64932a437dbSMikhail Rudenko ret = v4l2_ctrl_handler_init(handler, 10); 65032a437dbSMikhail Rudenko if (ret) 65132a437dbSMikhail Rudenko return ret; 65232a437dbSMikhail Rudenko handler->lock = &ov4689->mutex; 65332a437dbSMikhail Rudenko 65432a437dbSMikhail Rudenko ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, 0, 0, 65532a437dbSMikhail Rudenko link_freq_menu_items); 65632a437dbSMikhail Rudenko if (ctrl) 65732a437dbSMikhail Rudenko ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; 65832a437dbSMikhail Rudenko 65932a437dbSMikhail Rudenko v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, 0, 66032a437dbSMikhail Rudenko mode->pixel_rate, 1, mode->pixel_rate); 66132a437dbSMikhail Rudenko 66232a437dbSMikhail Rudenko h_blank_def = mode->hts_def - mode->width; 66332a437dbSMikhail Rudenko ctrl = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK, h_blank_def, 66432a437dbSMikhail Rudenko h_blank_def, 1, h_blank_def); 66532a437dbSMikhail Rudenko if (ctrl) 66632a437dbSMikhail Rudenko ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; 66732a437dbSMikhail Rudenko 66832a437dbSMikhail Rudenko vblank_def = mode->vts_def - mode->height; 66932a437dbSMikhail Rudenko v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops, V4L2_CID_VBLANK, 67032a437dbSMikhail Rudenko vblank_def, OV4689_VTS_MAX - mode->height, 1, 67132a437dbSMikhail Rudenko vblank_def); 67232a437dbSMikhail Rudenko 67332a437dbSMikhail Rudenko exposure_max = mode->vts_def - 4; 67432a437dbSMikhail Rudenko ov4689->exposure = 67532a437dbSMikhail Rudenko v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops, V4L2_CID_EXPOSURE, 67632a437dbSMikhail Rudenko OV4689_EXPOSURE_MIN, exposure_max, 67732a437dbSMikhail Rudenko OV4689_EXPOSURE_STEP, mode->exp_def); 67832a437dbSMikhail Rudenko 67932a437dbSMikhail Rudenko v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, 68032a437dbSMikhail Rudenko ov4689_gain_ranges[0].logical_min, 68132a437dbSMikhail Rudenko ov4689_gain_ranges[ARRAY_SIZE(ov4689_gain_ranges) - 1] 68232a437dbSMikhail Rudenko .logical_max, 68332a437dbSMikhail Rudenko OV4689_GAIN_STEP, OV4689_GAIN_DEFAULT); 68432a437dbSMikhail Rudenko 68532a437dbSMikhail Rudenko v4l2_ctrl_new_std_menu_items(handler, &ov4689_ctrl_ops, 68632a437dbSMikhail Rudenko V4L2_CID_TEST_PATTERN, 68732a437dbSMikhail Rudenko ARRAY_SIZE(ov4689_test_pattern_menu) - 1, 68832a437dbSMikhail Rudenko 0, 0, ov4689_test_pattern_menu); 68932a437dbSMikhail Rudenko 69032a437dbSMikhail Rudenko if (handler->error) { 69132a437dbSMikhail Rudenko ret = handler->error; 692*d015aaafSMikhail Rudenko dev_err(ov4689->dev, "Failed to init controls(%d)\n", ret); 69332a437dbSMikhail Rudenko goto err_free_handler; 69432a437dbSMikhail Rudenko } 69532a437dbSMikhail Rudenko 69632a437dbSMikhail Rudenko ret = v4l2_fwnode_device_parse(&client->dev, &props); 69732a437dbSMikhail Rudenko if (ret) 69832a437dbSMikhail Rudenko goto err_free_handler; 69932a437dbSMikhail Rudenko 70032a437dbSMikhail Rudenko ret = v4l2_ctrl_new_fwnode_properties(handler, &ov4689_ctrl_ops, 70132a437dbSMikhail Rudenko &props); 70232a437dbSMikhail Rudenko if (ret) 70332a437dbSMikhail Rudenko goto err_free_handler; 70432a437dbSMikhail Rudenko 70532a437dbSMikhail Rudenko ov4689->subdev.ctrl_handler = handler; 70632a437dbSMikhail Rudenko 70732a437dbSMikhail Rudenko return 0; 70832a437dbSMikhail Rudenko 70932a437dbSMikhail Rudenko err_free_handler: 71032a437dbSMikhail Rudenko v4l2_ctrl_handler_free(handler); 71132a437dbSMikhail Rudenko 71232a437dbSMikhail Rudenko return ret; 71332a437dbSMikhail Rudenko } 71432a437dbSMikhail Rudenko 71532a437dbSMikhail Rudenko static int ov4689_check_sensor_id(struct ov4689 *ov4689, 71632a437dbSMikhail Rudenko struct i2c_client *client) 71732a437dbSMikhail Rudenko { 718*d015aaafSMikhail Rudenko struct device *dev = ov4689->dev; 7198fe37e59SMikhail Rudenko u64 id = 0; 72032a437dbSMikhail Rudenko int ret; 72132a437dbSMikhail Rudenko 7228fe37e59SMikhail Rudenko ret = cci_read(ov4689->regmap, OV4689_REG_CHIP_ID, &id, NULL); 72332a437dbSMikhail Rudenko if (ret) { 72432a437dbSMikhail Rudenko dev_err(dev, "Cannot read sensor ID\n"); 72532a437dbSMikhail Rudenko return ret; 72632a437dbSMikhail Rudenko } 72732a437dbSMikhail Rudenko 72832a437dbSMikhail Rudenko if (id != CHIP_ID) { 7298fe37e59SMikhail Rudenko dev_err(dev, "Unexpected sensor ID %06llx, expected %06x\n", 73032a437dbSMikhail Rudenko id, CHIP_ID); 73132a437dbSMikhail Rudenko return -ENODEV; 73232a437dbSMikhail Rudenko } 73332a437dbSMikhail Rudenko 73432a437dbSMikhail Rudenko dev_info(dev, "Detected OV%06x sensor\n", CHIP_ID); 73532a437dbSMikhail Rudenko 73632a437dbSMikhail Rudenko return 0; 73732a437dbSMikhail Rudenko } 73832a437dbSMikhail Rudenko 73932a437dbSMikhail Rudenko static int ov4689_configure_regulators(struct ov4689 *ov4689) 74032a437dbSMikhail Rudenko { 74132a437dbSMikhail Rudenko unsigned int i; 74232a437dbSMikhail Rudenko 7437336c54aSMikhail Rudenko for (i = 0; i < ARRAY_SIZE(ov4689_supply_names); i++) 74432a437dbSMikhail Rudenko ov4689->supplies[i].supply = ov4689_supply_names[i]; 74532a437dbSMikhail Rudenko 746*d015aaafSMikhail Rudenko return devm_regulator_bulk_get(ov4689->dev, 7477336c54aSMikhail Rudenko ARRAY_SIZE(ov4689_supply_names), 74832a437dbSMikhail Rudenko ov4689->supplies); 74932a437dbSMikhail Rudenko } 75032a437dbSMikhail Rudenko 75132a437dbSMikhail Rudenko static u64 ov4689_check_link_frequency(struct v4l2_fwnode_endpoint *ep) 75232a437dbSMikhail Rudenko { 75332a437dbSMikhail Rudenko const u64 *freqs = link_freq_menu_items; 75432a437dbSMikhail Rudenko unsigned int i, j; 75532a437dbSMikhail Rudenko 7567336c54aSMikhail Rudenko for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) { 75732a437dbSMikhail Rudenko for (j = 0; j < ep->nr_of_link_frequencies; j++) 75832a437dbSMikhail Rudenko if (freqs[i] == ep->link_frequencies[j]) 75932a437dbSMikhail Rudenko return freqs[i]; 76032a437dbSMikhail Rudenko } 76132a437dbSMikhail Rudenko 76232a437dbSMikhail Rudenko return 0; 76332a437dbSMikhail Rudenko } 76432a437dbSMikhail Rudenko 76532a437dbSMikhail Rudenko static int ov4689_check_hwcfg(struct device *dev) 76632a437dbSMikhail Rudenko { 76732a437dbSMikhail Rudenko struct fwnode_handle *fwnode = dev_fwnode(dev); 76832a437dbSMikhail Rudenko struct v4l2_fwnode_endpoint bus_cfg = { 76932a437dbSMikhail Rudenko .bus_type = V4L2_MBUS_CSI2_DPHY, 77032a437dbSMikhail Rudenko }; 77132a437dbSMikhail Rudenko struct fwnode_handle *endpoint; 77232a437dbSMikhail Rudenko int ret; 77332a437dbSMikhail Rudenko 77432a437dbSMikhail Rudenko endpoint = fwnode_graph_get_next_endpoint(fwnode, NULL); 77532a437dbSMikhail Rudenko if (!endpoint) 77632a437dbSMikhail Rudenko return -EINVAL; 77732a437dbSMikhail Rudenko 77832a437dbSMikhail Rudenko ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg); 77932a437dbSMikhail Rudenko fwnode_handle_put(endpoint); 78032a437dbSMikhail Rudenko if (ret) 78132a437dbSMikhail Rudenko return ret; 78232a437dbSMikhail Rudenko 78332a437dbSMikhail Rudenko if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV4689_LANES) { 78432a437dbSMikhail Rudenko dev_err(dev, "Only a 4-lane CSI2 config is supported"); 78532a437dbSMikhail Rudenko ret = -EINVAL; 78632a437dbSMikhail Rudenko goto out_free_bus_cfg; 78732a437dbSMikhail Rudenko } 78832a437dbSMikhail Rudenko 78932a437dbSMikhail Rudenko if (!ov4689_check_link_frequency(&bus_cfg)) { 79032a437dbSMikhail Rudenko dev_err(dev, "No supported link frequency found\n"); 79132a437dbSMikhail Rudenko ret = -EINVAL; 79232a437dbSMikhail Rudenko } 79332a437dbSMikhail Rudenko 79432a437dbSMikhail Rudenko out_free_bus_cfg: 79532a437dbSMikhail Rudenko v4l2_fwnode_endpoint_free(&bus_cfg); 79632a437dbSMikhail Rudenko 79732a437dbSMikhail Rudenko return ret; 79832a437dbSMikhail Rudenko } 79932a437dbSMikhail Rudenko 80032a437dbSMikhail Rudenko static int ov4689_probe(struct i2c_client *client) 80132a437dbSMikhail Rudenko { 80232a437dbSMikhail Rudenko struct device *dev = &client->dev; 80332a437dbSMikhail Rudenko struct v4l2_subdev *sd; 80432a437dbSMikhail Rudenko struct ov4689 *ov4689; 80532a437dbSMikhail Rudenko int ret; 80632a437dbSMikhail Rudenko 80732a437dbSMikhail Rudenko ret = ov4689_check_hwcfg(dev); 80832a437dbSMikhail Rudenko if (ret) 80932a437dbSMikhail Rudenko return ret; 81032a437dbSMikhail Rudenko 81132a437dbSMikhail Rudenko ov4689 = devm_kzalloc(dev, sizeof(*ov4689), GFP_KERNEL); 81232a437dbSMikhail Rudenko if (!ov4689) 81332a437dbSMikhail Rudenko return -ENOMEM; 81432a437dbSMikhail Rudenko 815*d015aaafSMikhail Rudenko ov4689->dev = dev; 816*d015aaafSMikhail Rudenko 81732a437dbSMikhail Rudenko ov4689->cur_mode = &supported_modes[OV4689_MODE_2688_1520]; 81832a437dbSMikhail Rudenko 81932a437dbSMikhail Rudenko ov4689->xvclk = devm_clk_get_optional(dev, NULL); 82032a437dbSMikhail Rudenko if (IS_ERR(ov4689->xvclk)) 82132a437dbSMikhail Rudenko return dev_err_probe(dev, PTR_ERR(ov4689->xvclk), 82232a437dbSMikhail Rudenko "Failed to get external clock\n"); 82332a437dbSMikhail Rudenko 82432a437dbSMikhail Rudenko if (!ov4689->xvclk) { 82532a437dbSMikhail Rudenko dev_dbg(dev, 82632a437dbSMikhail Rudenko "No clock provided, using clock-frequency property\n"); 82732a437dbSMikhail Rudenko device_property_read_u32(dev, "clock-frequency", 82832a437dbSMikhail Rudenko &ov4689->clock_rate); 82932a437dbSMikhail Rudenko } else { 83032a437dbSMikhail Rudenko ov4689->clock_rate = clk_get_rate(ov4689->xvclk); 83132a437dbSMikhail Rudenko } 83232a437dbSMikhail Rudenko 83332a437dbSMikhail Rudenko if (ov4689->clock_rate != OV4689_XVCLK_FREQ) { 83432a437dbSMikhail Rudenko dev_err(dev, 83532a437dbSMikhail Rudenko "External clock rate mismatch: got %d Hz, expected %d Hz\n", 83632a437dbSMikhail Rudenko ov4689->clock_rate, OV4689_XVCLK_FREQ); 83732a437dbSMikhail Rudenko return -EINVAL; 83832a437dbSMikhail Rudenko } 83932a437dbSMikhail Rudenko 8408fe37e59SMikhail Rudenko ov4689->regmap = devm_cci_regmap_init_i2c(client, 16); 8418fe37e59SMikhail Rudenko if (IS_ERR(ov4689->regmap)) { 8428fe37e59SMikhail Rudenko ret = PTR_ERR(ov4689->regmap); 8438fe37e59SMikhail Rudenko dev_err(dev, "failed to initialize CCI: %d\n", ret); 8448fe37e59SMikhail Rudenko return ret; 8458fe37e59SMikhail Rudenko } 8468fe37e59SMikhail Rudenko 84732a437dbSMikhail Rudenko ov4689->reset_gpio = devm_gpiod_get_optional(dev, "reset", 84832a437dbSMikhail Rudenko GPIOD_OUT_LOW); 84932a437dbSMikhail Rudenko if (IS_ERR(ov4689->reset_gpio)) { 85032a437dbSMikhail Rudenko dev_err(dev, "Failed to get reset-gpios\n"); 85132a437dbSMikhail Rudenko return PTR_ERR(ov4689->reset_gpio); 85232a437dbSMikhail Rudenko } 85332a437dbSMikhail Rudenko 85432a437dbSMikhail Rudenko ov4689->pwdn_gpio = devm_gpiod_get_optional(dev, "pwdn", GPIOD_OUT_LOW); 85532a437dbSMikhail Rudenko if (IS_ERR(ov4689->pwdn_gpio)) { 85632a437dbSMikhail Rudenko dev_err(dev, "Failed to get pwdn-gpios\n"); 85732a437dbSMikhail Rudenko return PTR_ERR(ov4689->pwdn_gpio); 85832a437dbSMikhail Rudenko } 85932a437dbSMikhail Rudenko 86032a437dbSMikhail Rudenko ret = ov4689_configure_regulators(ov4689); 86132a437dbSMikhail Rudenko if (ret) 86232a437dbSMikhail Rudenko return dev_err_probe(dev, ret, 86332a437dbSMikhail Rudenko "Failed to get power regulators\n"); 86432a437dbSMikhail Rudenko 86532a437dbSMikhail Rudenko mutex_init(&ov4689->mutex); 86632a437dbSMikhail Rudenko 86732a437dbSMikhail Rudenko sd = &ov4689->subdev; 86832a437dbSMikhail Rudenko v4l2_i2c_subdev_init(sd, client, &ov4689_subdev_ops); 86932a437dbSMikhail Rudenko ret = ov4689_initialize_controls(ov4689); 87032a437dbSMikhail Rudenko if (ret) 87132a437dbSMikhail Rudenko goto err_destroy_mutex; 87232a437dbSMikhail Rudenko 87332a437dbSMikhail Rudenko ret = ov4689_power_on(dev); 87432a437dbSMikhail Rudenko if (ret) 87532a437dbSMikhail Rudenko goto err_free_handler; 87632a437dbSMikhail Rudenko 87732a437dbSMikhail Rudenko ret = ov4689_check_sensor_id(ov4689, client); 87832a437dbSMikhail Rudenko if (ret) 87932a437dbSMikhail Rudenko goto err_power_off; 88032a437dbSMikhail Rudenko 88132a437dbSMikhail Rudenko sd->internal_ops = &ov4689_internal_ops; 88232a437dbSMikhail Rudenko sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 88332a437dbSMikhail Rudenko 88432a437dbSMikhail Rudenko ov4689->pad.flags = MEDIA_PAD_FL_SOURCE; 88532a437dbSMikhail Rudenko sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; 88632a437dbSMikhail Rudenko ret = media_entity_pads_init(&sd->entity, 1, &ov4689->pad); 88732a437dbSMikhail Rudenko if (ret < 0) 88832a437dbSMikhail Rudenko goto err_power_off; 88932a437dbSMikhail Rudenko 89032a437dbSMikhail Rudenko ret = v4l2_async_register_subdev_sensor(sd); 89132a437dbSMikhail Rudenko if (ret) { 89232a437dbSMikhail Rudenko dev_err(dev, "v4l2 async register subdev failed\n"); 89332a437dbSMikhail Rudenko goto err_clean_entity; 89432a437dbSMikhail Rudenko } 89532a437dbSMikhail Rudenko 89632a437dbSMikhail Rudenko pm_runtime_set_active(dev); 89732a437dbSMikhail Rudenko pm_runtime_enable(dev); 89832a437dbSMikhail Rudenko pm_runtime_idle(dev); 89932a437dbSMikhail Rudenko 90032a437dbSMikhail Rudenko return 0; 90132a437dbSMikhail Rudenko 90232a437dbSMikhail Rudenko err_clean_entity: 90332a437dbSMikhail Rudenko media_entity_cleanup(&sd->entity); 90432a437dbSMikhail Rudenko err_power_off: 90532a437dbSMikhail Rudenko ov4689_power_off(dev); 90632a437dbSMikhail Rudenko err_free_handler: 90732a437dbSMikhail Rudenko v4l2_ctrl_handler_free(&ov4689->ctrl_handler); 90832a437dbSMikhail Rudenko err_destroy_mutex: 90932a437dbSMikhail Rudenko mutex_destroy(&ov4689->mutex); 91032a437dbSMikhail Rudenko 91132a437dbSMikhail Rudenko return ret; 91232a437dbSMikhail Rudenko } 91332a437dbSMikhail Rudenko 91432a437dbSMikhail Rudenko static void ov4689_remove(struct i2c_client *client) 91532a437dbSMikhail Rudenko { 91632a437dbSMikhail Rudenko struct v4l2_subdev *sd = i2c_get_clientdata(client); 91732a437dbSMikhail Rudenko struct ov4689 *ov4689 = to_ov4689(sd); 91832a437dbSMikhail Rudenko 91932a437dbSMikhail Rudenko v4l2_async_unregister_subdev(sd); 92032a437dbSMikhail Rudenko media_entity_cleanup(&sd->entity); 92132a437dbSMikhail Rudenko 92232a437dbSMikhail Rudenko v4l2_ctrl_handler_free(&ov4689->ctrl_handler); 92332a437dbSMikhail Rudenko mutex_destroy(&ov4689->mutex); 92432a437dbSMikhail Rudenko 92532a437dbSMikhail Rudenko pm_runtime_disable(&client->dev); 92632a437dbSMikhail Rudenko if (!pm_runtime_status_suspended(&client->dev)) 92732a437dbSMikhail Rudenko ov4689_power_off(&client->dev); 92832a437dbSMikhail Rudenko pm_runtime_set_suspended(&client->dev); 92932a437dbSMikhail Rudenko } 93032a437dbSMikhail Rudenko 93132a437dbSMikhail Rudenko static const struct of_device_id ov4689_of_match[] = { 93232a437dbSMikhail Rudenko { .compatible = "ovti,ov4689" }, 93332a437dbSMikhail Rudenko {}, 93432a437dbSMikhail Rudenko }; 93532a437dbSMikhail Rudenko MODULE_DEVICE_TABLE(of, ov4689_of_match); 93632a437dbSMikhail Rudenko 93732a437dbSMikhail Rudenko static struct i2c_driver ov4689_i2c_driver = { 93832a437dbSMikhail Rudenko .driver = { 93932a437dbSMikhail Rudenko .name = "ov4689", 94032a437dbSMikhail Rudenko .pm = &ov4689_pm_ops, 94132a437dbSMikhail Rudenko .of_match_table = ov4689_of_match, 94232a437dbSMikhail Rudenko }, 943aaeb31c0SUwe Kleine-König .probe = ov4689_probe, 94432a437dbSMikhail Rudenko .remove = ov4689_remove, 94532a437dbSMikhail Rudenko }; 94632a437dbSMikhail Rudenko 94732a437dbSMikhail Rudenko module_i2c_driver(ov4689_i2c_driver); 94832a437dbSMikhail Rudenko 94932a437dbSMikhail Rudenko MODULE_DESCRIPTION("OmniVision ov4689 sensor driver"); 95032a437dbSMikhail Rudenko MODULE_LICENSE("GPL"); 951