diff --git a/drivers/media/i2c/imx464.c b/drivers/media/i2c/imx464.c index 86575b3b7976..7b5620a0d12a 100644 --- a/drivers/media/i2c/imx464.c +++ b/drivers/media/i2c/imx464.c @@ -26,8 +26,11 @@ #include #include #include +#include +#include #include #include +#include #define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x03) @@ -42,15 +45,12 @@ #define OF_CAMERA_HDR_MODE "rockchip,camera-hdr-mode" /* pixel rate = link frequency * 2 * lanes / BITS_PER_SAMPLE */ -#define IMX464_10BIT_LINEAR_PIXEL_RATE (MIPI_FREQ_445M * 2 / 10 * 4) #define IMX464_10BIT_HDR2_PIXEL_RATE (MIPI_FREQ_594M * 2 / 10 * 4) -#define IMX464_10BIT_HDR3_PIXEL_RATE (MIPI_FREQ_594M * 2 / 10 * 4) -#define IMX464_12BIT_PIXEL_RATE (MIPI_FREQ_360M * 2 / 12 * 4) #define IMX464_XVCLK_FREQ_37M 37125000 #define IMX464_XVCLK_FREQ_24M 24000000 -#define CHIP_ID 0x00 -#define IMX464_REG_CHIP_ID 0x0000 +#define CHIP_ID 0x06 +#define IMX464_REG_CHIP_ID 0x3057 #define IMX464_REG_CTRL_MODE 0x3000 #define IMX464_MODE_SW_STANDBY BIT(0) @@ -133,8 +133,6 @@ #define IMX464_REG_VALUE_16BIT 2 #define IMX464_REG_VALUE_24BIT 3 -#define IMX464_2LANES 2 -#define IMX464_4LANES 4 #define IMX464_BITS_PER_SAMPLE 10 #define IMX464_VREVERSE_REG 0x304f @@ -150,12 +148,10 @@ #define USED_SYS_DEBUG -static bool g_isHCG; - #define OF_CAMERA_PINCTRL_STATE_DEFAULT "rockchip,camera_default" #define OF_CAMERA_PINCTRL_STATE_SLEEP "rockchip,camera_sleep" -#define IMX464_NAME "IMX464" +#define IMX464_NAME "imx464" static const char * const IMX464_supply_names[] = { "avdd", /* Analog power */ @@ -178,6 +174,9 @@ struct IMX464_mode { u32 hts_def; u32 vts_def; u32 exp_def; + u32 mipi_freq_idx; + u32 mclk; + u32 bpp; const struct regval *reg_list; u32 hdr_mode; u32 vc[PAD_MAX]; @@ -205,19 +204,22 @@ struct IMX464 { struct v4l2_ctrl *pixel_rate; struct v4l2_ctrl *link_freq; struct mutex mutex; + struct v4l2_fwnode_endpoint bus_cfg; bool streaming; bool power_on; + bool has_init_exp; + const struct IMX464_mode *support_modes; const struct IMX464_mode *cur_mode; u32 module_index; u32 cfg_num; - u32 cur_pixel_rate; - u32 cur_link_freq; + u32 cur_vts; + u32 cur_mclk; const char *module_facing; const char *module_name; const char *len_name; - u32 cur_vts; - bool has_init_exp; + enum rkmodule_sync_mode sync_mode; struct preisp_hdrae_exp_s init_hdrae_exp; + bool isHCG; }; #define to_IMX464(sd) container_of(sd, struct IMX464, subdev) @@ -229,6 +231,473 @@ static const struct regval IMX464_global_regs[] = { {REG_NULL, 0x00}, }; +static __maybe_unused const struct regval IMX464_linear_10bit_2688x1520_2lane_37m_regs[] = { + {0x3000, 0x01}, + {0x3002, 0x01}, + {0x300C, 0x5B}, + {0x300D, 0x40}, + {0x3034, 0xDC}, + {0x3035, 0x05}, + {0x3050, 0x00}, + {0x3058, 0x83}, + {0x3059, 0x04}, + {0x30BE, 0x5E}, + {0x30E8, 0x14}, + {0x3110, 0x02}, + {0x314C, 0xC0}, + {0x315A, 0x06}, + {0x316A, 0x7E}, + {0x319D, 0x00}, + {0x319E, 0x02}, + {0x31A1, 0x00}, + {0x3288, 0x22}, + {0x328A, 0x02}, + {0x328C, 0xA2}, + {0x328E, 0x22}, + {0x3415, 0x27}, + {0x3418, 0x27}, + {0x3428, 0xFE}, + {0x349E, 0x6A}, + {0x34A2, 0x9A}, + {0x34A4, 0x8A}, + {0x34A6, 0x8E}, + {0x34AA, 0xD8}, + {0x35BC, 0x00}, + {0x35BE, 0xFF}, + {0x35CC, 0x1B}, + {0x35CD, 0x00}, + {0x35CE, 0x2A}, + {0x35CF, 0x00}, + {0x35DC, 0x07}, + {0x35DE, 0x1A}, + {0x35DF, 0x00}, + {0x35E4, 0x2B}, + {0x35E5, 0x00}, + {0x35E6, 0x07}, + {0x35E7, 0x01}, + {0x3648, 0x01}, + {0x3678, 0x01}, + {0x367C, 0x69}, + {0x367E, 0x69}, + {0x3680, 0x69}, + {0x3682, 0x69}, + {0x3718, 0x1C}, + {0x371D, 0x05}, + {0x375D, 0x11}, + {0x375E, 0x43}, + {0x375F, 0x76}, + {0x3760, 0x07}, + {0x3768, 0x1B}, + {0x3769, 0x1B}, + {0x376A, 0x1A}, + {0x376B, 0x19}, + {0x376C, 0x17}, + {0x376D, 0x0F}, + {0x376E, 0x0B}, + {0x376F, 0x0B}, + {0x3770, 0x0B}, + {0x3776, 0x89}, + {0x3777, 0x00}, + {0x3778, 0xCA}, + {0x3779, 0x00}, + {0x377A, 0x45}, + {0x377B, 0x01}, + {0x377C, 0x56}, + {0x377D, 0x02}, + {0x377E, 0xFE}, + {0x377F, 0x03}, + {0x3780, 0xFE}, + {0x3781, 0x05}, + {0x3782, 0xFE}, + {0x3783, 0x06}, + {0x3784, 0x7F}, + {0x3788, 0x1F}, + {0x378A, 0xCA}, + {0x378B, 0x00}, + {0x378C, 0x45}, + {0x378D, 0x01}, + {0x378E, 0x56}, + {0x378F, 0x02}, + {0x3790, 0xFE}, + {0x3791, 0x03}, + {0x3792, 0xFE}, + {0x3793, 0x05}, + {0x3794, 0xFE}, + {0x3795, 0x06}, + {0x3796, 0x7F}, + {0x3798, 0xBF}, + {0x3A01, 0x01}, + {0x3A18, 0x7F}, + {0x3A1A, 0x37}, + {0x3A1C, 0x37}, + {0x3A1E, 0xF7}, + {0x3A1F, 0x00}, + {0x3A20, 0x3F}, + {0x3A22, 0x6F}, + {0x3A24, 0x3F}, + {0x3A26, 0x5F}, + {0x3A28, 0x2F}, + {REG_NULL, 0x00}, +}; + +static __maybe_unused const struct regval IMX464_hdr_2x_10bit_2688x1520_2lane_37m_regs[] = { + {0x3000, 0x01}, + {0x3002, 0x01}, + {0x300C, 0x5B}, + {0x300D, 0x40}, + {0x3034, 0xDC}, + {0x3035, 0x05}, + {0x3048, 0x01}, + {0x3049, 0x01}, + {0x304A, 0x01}, + {0x304B, 0x01}, + {0x304C, 0x13}, + {0x304D, 0x00}, + {0x3050, 0x00}, + {0x3058, 0xF4}, + {0x3059, 0x0A}, + {0x3068, 0x3D}, + {0x30BE, 0x5E}, + {0x30E8, 0x0A}, + {0x3110, 0x02}, + {0x314C, 0x80},// + {0x315A, 0x02}, + {0x316A, 0x7E}, + {0x319D, 0x00}, + {0x319E, 0x01},//1188M + {0x31A1, 0x00}, + {0x31D7, 0x01}, + {0x3200, 0x10}, + {0x3288, 0x22}, + {0x328A, 0x02}, + {0x328C, 0xA2}, + {0x328E, 0x22}, + {0x3415, 0x27}, + {0x3418, 0x27}, + {0x3428, 0xFE}, + {0x349E, 0x6A}, + {0x34A2, 0x9A}, + {0x34A4, 0x8A}, + {0x34A6, 0x8E}, + {0x34AA, 0xD8}, + {0x35BC, 0x00}, + {0x35BE, 0xFF}, + {0x35CC, 0x1B}, + {0x35CD, 0x00}, + {0x35CE, 0x2A}, + {0x35CF, 0x00}, + {0x35DC, 0x07}, + {0x35DE, 0x1A}, + {0x35DF, 0x00}, + {0x35E4, 0x2B}, + {0x35E5, 0x00}, + {0x35E6, 0x07}, + {0x35E7, 0x01}, + {0x3648, 0x01}, + {0x3678, 0x01}, + {0x367C, 0x69}, + {0x367E, 0x69}, + {0x3680, 0x69}, + {0x3682, 0x69}, + {0x3718, 0x1C}, + {0x371D, 0x05}, + {0x375D, 0x11}, + {0x375E, 0x43}, + {0x375F, 0x76}, + {0x3760, 0x07}, + {0x3768, 0x1B}, + {0x3769, 0x1B}, + {0x376A, 0x1A}, + {0x376B, 0x19}, + {0x376C, 0x17}, + {0x376D, 0x0F}, + {0x376E, 0x0B}, + {0x376F, 0x0B}, + {0x3770, 0x0B}, + {0x3776, 0x89}, + {0x3777, 0x00}, + {0x3778, 0xCA}, + {0x3779, 0x00}, + {0x377A, 0x45}, + {0x377B, 0x01}, + {0x377C, 0x56}, + {0x377D, 0x02}, + {0x377E, 0xFE}, + {0x377F, 0x03}, + {0x3780, 0xFE}, + {0x3781, 0x05}, + {0x3782, 0xFE}, + {0x3783, 0x06}, + {0x3784, 0x7F}, + {0x3788, 0x1F}, + {0x378A, 0xCA}, + {0x378B, 0x00}, + {0x378C, 0x45}, + {0x378D, 0x01}, + {0x378E, 0x56}, + {0x378F, 0x02}, + {0x3790, 0xFE}, + {0x3791, 0x03}, + {0x3792, 0xFE}, + {0x3793, 0x05}, + {0x3794, 0xFE}, + {0x3795, 0x06}, + {0x3796, 0x7F}, + {0x3798, 0xBF}, + {0x3A01, 0x01}, + {0x3A18, 0x8F}, + {0x3A1A, 0x4F}, + {0x3A1C, 0x47}, + {0x3A1E, 0x37}, + {0x3A1F, 0x01}, + {0x3A20, 0x4F}, + {0x3A22, 0x87}, + {0x3A24, 0x4F}, + {0x3A26, 0x7F}, + {0x3A28, 0x3F}, + {REG_NULL, 0x00}, +}; + +static const struct regval IMX464_linear_10bit_2688x1520_2lane_regs[] = { + {0x3000, 0x01}, + {0x3002, 0x01}, + {0x300C, 0x3b}, + {0x300D, 0x2a}, + {0x3034, 0xDC}, + {0x3035, 0x05}, + {0x3048, 0x00}, + {0x3049, 0x00}, + {0x304A, 0x03}, + {0x304B, 0x02}, + {0x304C, 0x14}, + {0x304D, 0x03}, + {0x3050, 0x00}, + {0x3058, 0x83}, + {0x3059, 0x04}, + {0x3068, 0xc9}, + {0x30BE, 0x5E}, + {0x30E8, 0x14}, + {0x3110, 0x02}, + {0x314C, 0x29}, + {0x314D, 0x01}, + {0x315A, 0x06}, + {0x3168, 0xA0}, + {0x316A, 0x7E}, + {0x319D, 0x00}, + {0x319E, 0x02}, + {0x31A1, 0x00}, + {0x31D7, 0x00}, + {0x3200, 0x11}, + {0x3288, 0x22}, + {0x328A, 0x02}, + {0x328C, 0xA2}, + {0x328E, 0x22}, + {0x3415, 0x27}, + {0x3418, 0x27}, + {0x3428, 0xFE}, + {0x349E, 0x6A}, + {0x34A2, 0x9A}, + {0x34A4, 0x8A}, + {0x34A6, 0x8E}, + {0x34AA, 0xD8}, + {0x35BC, 0x00}, + {0x35BE, 0xFF}, + {0x35CC, 0x1B}, + {0x35CD, 0x00}, + {0x35CE, 0x2A}, + {0x35CF, 0x00}, + {0x35DC, 0x07}, + {0x35DE, 0x1A}, + {0x35DF, 0x00}, + {0x35E4, 0x2B}, + {0x35E5, 0x00}, + {0x35E6, 0x07}, + {0x35E7, 0x01}, + {0x3648, 0x01}, + {0x3678, 0x01}, + {0x367C, 0x69}, + {0x367E, 0x69}, + {0x3680, 0x69}, + {0x3682, 0x69}, + {0x3718, 0x1C}, + {0x371D, 0x05}, + {0x375D, 0x11}, + {0x375E, 0x43}, + {0x375F, 0x76}, + {0x3760, 0x07}, + {0x3768, 0x1B}, + {0x3769, 0x1B}, + {0x376A, 0x1A}, + {0x376B, 0x19}, + {0x376C, 0x17}, + {0x376D, 0x0F}, + {0x376E, 0x0B}, + {0x376F, 0x0B}, + {0x3770, 0x0B}, + {0x3776, 0x89}, + {0x3777, 0x00}, + {0x3778, 0xCA}, + {0x3779, 0x00}, + {0x377A, 0x45}, + {0x377B, 0x01}, + {0x377C, 0x56}, + {0x377D, 0x02}, + {0x377E, 0xFE}, + {0x377F, 0x03}, + {0x3780, 0xFE}, + {0x3781, 0x05}, + {0x3782, 0xFE}, + {0x3783, 0x06}, + {0x3784, 0x7F}, + {0x3788, 0x1F}, + {0x378A, 0xCA}, + {0x378B, 0x00}, + {0x378C, 0x45}, + {0x378D, 0x01}, + {0x378E, 0x56}, + {0x378F, 0x02}, + {0x3790, 0xFE}, + {0x3791, 0x03}, + {0x3792, 0xFE}, + {0x3793, 0x05}, + {0x3794, 0xFE}, + {0x3795, 0x06}, + {0x3796, 0x7F}, + {0x3798, 0xBF}, + {0x3A01, 0x01}, + {0x3A18, 0x7F}, + {0x3A1A, 0x37}, + {0x3A1C, 0x37}, + {0x3A1E, 0xF7}, + {0x3A1F, 0x00}, + {0x3A20, 0x3F}, + {0x3A22, 0x6F}, + {0x3A24, 0x3F}, + {0x3A26, 0x5F}, + {0x3A28, 0x2F}, + {REG_NULL, 0x00}, +}; + +static const struct regval IMX464_hdr_2x_10bit_2688x1520_2lane_regs[] = { + {0x3000, 0x01}, + {0x3002, 0x01}, + {0x300C, 0x3B}, + {0x300D, 0x2A}, + {0x3034, 0xDC}, + {0x3035, 0x05}, + {0x3048, 0x01}, + {0x3049, 0x01}, + {0x304A, 0x04}, + {0x304B, 0x04}, + {0x304C, 0x13}, + {0x304D, 0x00}, + {0x3050, 0x00}, + {0x3058, 0xF4}, + {0x3059, 0x0A}, + {0x3068, 0x3D}, + {0x30BE, 0x5E}, + {0x30E8, 0x14}, + {0x3110, 0x02}, + {0x314C, 0x29},// + {0x314D, 0x01},// + {0x315A, 0x06}, + {0x3168, 0xA0}, + {0x316A, 0x7E}, + {0x319D, 0x00}, + {0x319E, 0x02},//1188M + {0x31A1, 0x00}, + {0x31D7, 0x01}, + {0x3200, 0x10}, + {0x3288, 0x22}, + {0x328A, 0x02}, + {0x328C, 0xA2}, + {0x328E, 0x22}, + {0x3415, 0x27}, + {0x3418, 0x27}, + {0x3428, 0xFE}, + {0x349E, 0x6A}, + {0x34A2, 0x9A}, + {0x34A4, 0x8A}, + {0x34A6, 0x8E}, + {0x34AA, 0xD8}, + {0x35BC, 0x00}, + {0x35BE, 0xFF}, + {0x35CC, 0x1B}, + {0x35CD, 0x00}, + {0x35CE, 0x2A}, + {0x35CF, 0x00}, + {0x35DC, 0x07}, + {0x35DE, 0x1A}, + {0x35DF, 0x00}, + {0x35E4, 0x2B}, + {0x35E5, 0x00}, + {0x35E6, 0x07}, + {0x35E7, 0x01}, + {0x3648, 0x01}, + {0x3678, 0x01}, + {0x367C, 0x69}, + {0x367E, 0x69}, + {0x3680, 0x69}, + {0x3682, 0x69}, + {0x3718, 0x1C}, + {0x371D, 0x05}, + {0x375D, 0x11}, + {0x375E, 0x43}, + {0x375F, 0x76}, + {0x3760, 0x07}, + {0x3768, 0x1B}, + {0x3769, 0x1B}, + {0x376A, 0x1A}, + {0x376B, 0x19}, + {0x376C, 0x17}, + {0x376D, 0x0F}, + {0x376E, 0x0B}, + {0x376F, 0x0B}, + {0x3770, 0x0B}, + {0x3776, 0x89}, + {0x3777, 0x00}, + {0x3778, 0xCA}, + {0x3779, 0x00}, + {0x377A, 0x45}, + {0x377B, 0x01}, + {0x377C, 0x56}, + {0x377D, 0x02}, + {0x377E, 0xFE}, + {0x377F, 0x03}, + {0x3780, 0xFE}, + {0x3781, 0x05}, + {0x3782, 0xFE}, + {0x3783, 0x06}, + {0x3784, 0x7F}, + {0x3788, 0x1F}, + {0x378A, 0xCA}, + {0x378B, 0x00}, + {0x378C, 0x45}, + {0x378D, 0x01}, + {0x378E, 0x56}, + {0x378F, 0x02}, + {0x3790, 0xFE}, + {0x3791, 0x03}, + {0x3792, 0xFE}, + {0x3793, 0x05}, + {0x3794, 0xFE}, + {0x3795, 0x06}, + {0x3796, 0x7F}, + {0x3798, 0xBF}, + {0x3A01, 0x01}, + {0x3A18, 0x7F}, + {0x3A1A, 0x37}, + {0x3A1C, 0x37}, + {0x3A1E, 0xF7}, + {0x3A1F, 0x00}, + {0x3A20, 0x3F}, + {0x3A22, 0x6F}, + {0x3A24, 0x3F}, + {0x3A26, 0x5F}, + {0x3A28, 0x2F}, + {REG_NULL, 0x00}, +}; + static const struct regval IMX464_linear_10bit_2688x1520_regs[] = { {0x3000, 0x01}, {0x3002, 0x01}, @@ -816,6 +1285,33 @@ static __maybe_unused const struct regval IMX464_hdr_2x_12bit_2688x1520_regs[] = {REG_NULL, 0x00}, }; +static __maybe_unused const struct regval IMX464_interal_sync_master_start_regs[] = { + {0x3010, 0x07}, + {0x31a1, 0x00}, + {REG_NULL, 0x00}, +}; +static __maybe_unused const struct regval IMX464_interal_sync_master_stop_regs[] = { + {0x31a1, 0x0f}, + {REG_NULL, 0x00}, +}; + +static __maybe_unused const struct regval IMX464_external_sync_master_start_regs[] = { + {0x3010, 0x05}, + {0x31a1, 0x03}, + {0x31d9, 0x01}, + {REG_NULL, 0x00}, +}; +static __maybe_unused const struct regval IMX464_external_sync_master_stop_regs[] = { + {0x31a1, 0x0f}, + {REG_NULL, 0x00}, +}; + +static __maybe_unused const struct regval IMX464_slave_start_regs[] = { + {0x3010, 0x05}, + {0x31a1, 0x0f}, + {REG_NULL, 0x00}, +}; + /* * The width and height must be configured to be * the same as the current output resolution of the sensor. @@ -840,6 +1336,9 @@ static const struct IMX464_mode supported_modes[] = { .exp_def = 0x0906, .hts_def = 0x05dc * 2, .vts_def = 0x0ce4, + .mipi_freq_idx = 0, + .bpp = 10, + .mclk = 37125000, .reg_list = IMX464_linear_10bit_2688x1520_regs, .hdr_mode = NO_HDR, .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, @@ -855,6 +1354,9 @@ static const struct IMX464_mode supported_modes[] = { .exp_def = 0x03de, .hts_def = 0x02ee * 4, .vts_def = 0x0672 * 2, + .mipi_freq_idx = 1, + .bpp = 10, + .mclk = 37125000, .reg_list = IMX464_hdr_2x_10bit_2688x1520_regs, .hdr_mode = HDR_X2, .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_1, @@ -881,6 +1383,9 @@ static const struct IMX464_mode supported_modes[] = { #else .vts_def = 0x04D1 * 4, #endif + .mipi_freq_idx = 1, + .bpp = 10, + .mclk = 37125000, .reg_list = IMX464_hdr_3x_10bit_2688x1520_regs, .hdr_mode = HDR_X3, .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_2, @@ -890,6 +1395,48 @@ static const struct IMX464_mode supported_modes[] = { }, }; +static const struct IMX464_mode supported_modes_2lane[] = { + { + .bus_fmt = MEDIA_BUS_FMT_SRGGB10_1X10, + .width = 2712, + .height = 1538, + .max_fps = { + .numerator = 10000, + .denominator = 250000, + }, + .exp_def = 0x0600, + .hts_def = 0x05dc * 2, + .vts_def = 0x7bc, + .mipi_freq_idx = 0, + .bpp = 10, + .mclk = 24000000, + .reg_list = IMX464_linear_10bit_2688x1520_2lane_regs, + .hdr_mode = NO_HDR, + .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, + }, + { + .bus_fmt = MEDIA_BUS_FMT_SRGGB10_1X10, + .width = 2712, + .height = 1538, + .max_fps = { + .numerator = 10000, + .denominator = 150000, + }, + .exp_def = 0x0600, + .hts_def = 0x05dc * 4, + .vts_def = 0x0672 * 2, + .mipi_freq_idx = 0, + .bpp = 10, + .mclk = 24000000, + .reg_list = IMX464_hdr_2x_10bit_2688x1520_2lane_regs, + .hdr_mode = HDR_X2, + .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_1, + .vc[PAD1] = V4L2_MBUS_CSI2_CHANNEL_0,//L->csi wr0 + .vc[PAD2] = V4L2_MBUS_CSI2_CHANNEL_1, + .vc[PAD3] = V4L2_MBUS_CSI2_CHANNEL_1,//M->csi wr2 + }, +}; + static const s64 link_freq_menu_items[] = { MIPI_FREQ_445M, MIPI_FREQ_594M, @@ -989,15 +1536,15 @@ IMX464_find_best_fit(struct IMX464 *IMX464, struct v4l2_subdev_format *fmt) unsigned int i; for (i = 0; i < IMX464->cfg_num; i++) { - dist = IMX464_get_reso_dist(&supported_modes[i], framefmt); + dist = IMX464_get_reso_dist(&IMX464->support_modes[i], framefmt); if ((cur_best_fit_dist == -1 || dist <= cur_best_fit_dist) && - supported_modes[i].bus_fmt == framefmt->code) { + IMX464->support_modes[i].bus_fmt == framefmt->code) { cur_best_fit_dist = dist; cur_best_fit = i; } } - return &supported_modes[cur_best_fit]; + return &IMX464->support_modes[cur_best_fit]; } static int IMX464_set_fmt(struct v4l2_subdev *sd, @@ -1007,8 +1554,7 @@ static int IMX464_set_fmt(struct v4l2_subdev *sd, struct IMX464 *IMX464 = to_IMX464(sd); const struct IMX464_mode *mode; s64 h_blank, vblank_def; - struct device *dev = &IMX464->client->dev; - int ret = 0; + u64 pixel_rate = 0; mutex_lock(&IMX464->mutex); @@ -1034,42 +1580,12 @@ static int IMX464_set_fmt(struct v4l2_subdev *sd, IMX464_VTS_MAX - mode->height, 1, vblank_def); IMX464->cur_vts = IMX464->cur_mode->vts_def; - if (mode->bus_fmt == MEDIA_BUS_FMT_SRGGB10_1X10) { - IMX464->cur_link_freq = 1; - if (mode->hdr_mode == NO_HDR) { - IMX464->cur_pixel_rate = IMX464_10BIT_LINEAR_PIXEL_RATE; - IMX464->cur_link_freq = 0; - } else if (mode->hdr_mode == HDR_X2) - IMX464->cur_pixel_rate = IMX464_10BIT_HDR2_PIXEL_RATE; - else if (mode->hdr_mode == HDR_X3) - IMX464->cur_pixel_rate = IMX464_10BIT_HDR3_PIXEL_RATE; - - clk_disable_unprepare(IMX464->xvclk); - ret = clk_set_rate(IMX464->xvclk, IMX464_XVCLK_FREQ_37M); - if (ret < 0) - dev_err(dev, "Failed to set xvclk rate\n"); - if (clk_get_rate(IMX464->xvclk) != IMX464_XVCLK_FREQ_37M) - dev_err(dev, "xvclk mismatched\n"); - ret = clk_prepare_enable(IMX464->xvclk); - if (ret < 0) - dev_err(dev, "Failed to enable xvclk\n"); - } else { - IMX464->cur_pixel_rate = IMX464_12BIT_PIXEL_RATE; - IMX464->cur_link_freq = 0; - clk_disable_unprepare(IMX464->xvclk); - ret = clk_set_rate(IMX464->xvclk, IMX464_XVCLK_FREQ_24M); - if (ret < 0) - dev_err(dev, "Failed to set xvclk rate\n"); - if (clk_get_rate(IMX464->xvclk) != IMX464_XVCLK_FREQ_24M) - dev_err(dev, "xvclk mismatched\n"); - ret = clk_prepare_enable(IMX464->xvclk); - if (ret < 0) - dev_err(dev, "Failed to enable xvclk\n"); - } + pixel_rate = (u32)link_freq_menu_items[mode->mipi_freq_idx] / mode->bpp * 2 * + IMX464->bus_cfg.bus.mipi_csi2.num_data_lanes; __v4l2_ctrl_s_ctrl_int64(IMX464->pixel_rate, - IMX464->cur_pixel_rate); + pixel_rate); __v4l2_ctrl_s_ctrl(IMX464->link_freq, - IMX464->cur_link_freq); + mode->mipi_freq_idx); } mutex_unlock(&IMX464->mutex); @@ -1129,13 +1645,13 @@ static int IMX464_enum_frame_sizes(struct v4l2_subdev *sd, if (fse->index >= IMX464->cfg_num) return -EINVAL; - if (fse->code != supported_modes[fse->index].bus_fmt) + if (fse->code != IMX464->support_modes[fse->index].bus_fmt) return -EINVAL; - fse->min_width = supported_modes[fse->index].width; - fse->max_width = supported_modes[fse->index].width; - fse->max_height = supported_modes[fse->index].height; - fse->min_height = supported_modes[fse->index].height; + fse->min_width = IMX464->support_modes[fse->index].width; + fse->max_width = IMX464->support_modes[fse->index].width; + fse->max_height = IMX464->support_modes[fse->index].height; + fse->min_height = IMX464->support_modes[fse->index].height; return 0; } @@ -1159,19 +1675,20 @@ static int IMX464_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id, struct IMX464 *IMX464 = to_IMX464(sd); const struct IMX464_mode *mode = IMX464->cur_mode; u32 val = 0; + u32 lane_num = IMX464->bus_cfg.bus.mipi_csi2.num_data_lanes; if (mode->hdr_mode == NO_HDR) { - val = 1 << (IMX464_4LANES - 1) | + val = 1 << (lane_num - 1) | V4L2_MBUS_CSI2_CHANNEL_0 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; } if (mode->hdr_mode == HDR_X2) - val = 1 << (IMX464_4LANES - 1) | + val = 1 << (lane_num - 1) | V4L2_MBUS_CSI2_CHANNEL_0 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK | V4L2_MBUS_CSI2_CHANNEL_1; if (mode->hdr_mode == HDR_X3) - val = 1 << (IMX464_4LANES - 1) | + val = 1 << (lane_num - 1) | V4L2_MBUS_CSI2_CHANNEL_0 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK | V4L2_MBUS_CSI2_CHANNEL_1 | @@ -1233,12 +1750,12 @@ static int IMX464_set_hdrae(struct IMX464 *IMX464, l_exp_time = m_exp_time; cg_mode = ae->middle_cg_mode; } - if (!g_isHCG && cg_mode == GAIN_MODE_HCG) { + if (!IMX464->isHCG && cg_mode == GAIN_MODE_HCG) { gain_switch = 0x01 | 0x100; - g_isHCG = true; - } else if (g_isHCG && cg_mode == GAIN_MODE_LCG) { + IMX464->isHCG = true; + } else if (IMX464->isHCG && cg_mode == GAIN_MODE_LCG) { gain_switch = 0x00 | 0x100; - g_isHCG = false; + IMX464->isHCG = false; } ret = imx464_write_reg(client, IMX464_GROUP_HOLD_REG, @@ -1420,12 +1937,12 @@ static int IMX464_set_hdrae_3frame(struct IMX464 *IMX464, //3 stagger cg_mode = ae->long_cg_mode; } - if (!g_isHCG && cg_mode == GAIN_MODE_HCG) { + if (!IMX464->isHCG && cg_mode == GAIN_MODE_HCG) { gain_switch = 0x01 | 0x100; - g_isHCG = true; - } else if (g_isHCG && cg_mode == GAIN_MODE_LCG) { + IMX464->isHCG = true; + } else if (IMX464->isHCG && cg_mode == GAIN_MODE_LCG) { gain_switch = 0x00 | 0x100; - g_isHCG = false; + IMX464->isHCG = false; } dev_dbg(&client->dev, @@ -1662,12 +2179,12 @@ static int IMX464_set_conversion_gain(struct IMX464 *IMX464, u32 *cg) int cur_cg = *cg; u32 gain_switch = 0; - if (g_isHCG && cur_cg == GAIN_MODE_LCG) { + if (IMX464->isHCG && cur_cg == GAIN_MODE_LCG) { gain_switch = 0x00 | 0x100; - g_isHCG = false; - } else if (!g_isHCG && cur_cg == GAIN_MODE_HCG) { + IMX464->isHCG = false; + } else if (!IMX464->isHCG && cur_cg == GAIN_MODE_HCG) { gain_switch = 0x01 | 0x100; - g_isHCG = true; + IMX464->isHCG = true; } ret = imx464_write_reg(client, IMX464_GROUP_HOLD_REG, @@ -1753,6 +2270,7 @@ static long IMX464_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) struct rkmodule_channel_info *ch_info; u32 i, h, w, stream; long ret = 0; + u64 pixel_rate = 0; switch (cmd) { case PREISP_CMD_SET_HDRAE_EXP: @@ -1774,10 +2292,10 @@ static long IMX464_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) w = IMX464->cur_mode->width; h = IMX464->cur_mode->height; for (i = 0; i < IMX464->cfg_num; i++) { - if (w == supported_modes[i].width && - h == supported_modes[i].height && - supported_modes[i].hdr_mode == hdr->hdr_mode) { - IMX464->cur_mode = &supported_modes[i]; + if (w == IMX464->support_modes[i].width && + h == IMX464->support_modes[i].height && + IMX464->support_modes[i].hdr_mode == hdr->hdr_mode) { + IMX464->cur_mode = &IMX464->support_modes[i]; break; } } @@ -1794,16 +2312,12 @@ static long IMX464_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) IMX464_VTS_MAX - IMX464->cur_mode->height, 1, h); IMX464->cur_vts = IMX464->cur_mode->vts_def; - if (IMX464->cur_mode->bus_fmt == MEDIA_BUS_FMT_SRGGB10_1X10) { - if (IMX464->cur_mode->hdr_mode == NO_HDR) - IMX464->cur_pixel_rate = IMX464_10BIT_LINEAR_PIXEL_RATE; - else if (IMX464->cur_mode->hdr_mode == HDR_X2) - IMX464->cur_pixel_rate = IMX464_10BIT_HDR2_PIXEL_RATE; - else if (IMX464->cur_mode->hdr_mode == HDR_X3) - IMX464->cur_pixel_rate = IMX464_10BIT_HDR3_PIXEL_RATE; - __v4l2_ctrl_s_ctrl_int64(IMX464->pixel_rate, - IMX464->cur_pixel_rate); - } + pixel_rate = (u32)link_freq_menu_items[IMX464->cur_mode->mipi_freq_idx] / IMX464->cur_mode->bpp * 2 * + IMX464->bus_cfg.bus.mipi_csi2.num_data_lanes; + __v4l2_ctrl_s_ctrl_int64(IMX464->pixel_rate, + pixel_rate); + __v4l2_ctrl_s_ctrl(IMX464->link_freq, + IMX464->cur_mode->mipi_freq_idx); } break; case RKMODULE_SET_CONVERSION_GAIN: @@ -1813,16 +2327,13 @@ static long IMX464_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) stream = *((u32 *)arg); - if (stream) { + if (stream) ret = imx464_write_reg(IMX464->client, IMX464_REG_CTRL_MODE, IMX464_REG_VALUE_08BIT, IMX464_MODE_STREAMING); - usleep_range(30000, 40000); - imx464_write_reg(IMX464->client, IMX464_REG_MARSTER_MODE, - IMX464_REG_VALUE_08BIT, 0); - } else { + else ret = imx464_write_reg(IMX464->client, IMX464_REG_CTRL_MODE, IMX464_REG_VALUE_08BIT, IMX464_MODE_SW_STANDBY); - } + break; case RKMODULE_GET_CHANNEL_INFO: ch_info = (struct rkmodule_channel_info *)arg; @@ -1962,17 +2473,20 @@ static long IMX464_compat_ioctl32(struct v4l2_subdev *sd, } #endif -static int IMX464_init_conversion_gain(struct IMX464 *IMX464) +static int IMX464_init_conversion_gain(struct IMX464 *IMX464, bool isHCG) { - int ret = 0; struct i2c_client *client = IMX464->client; + int ret = 0; + u32 val = 0; + if (isHCG) + val = 0x01; + else + val = 0; ret = imx464_write_reg(client, IMX464_GAIN_SWITCH_REG, IMX464_REG_VALUE_08BIT, - 0X00); - if (!ret) - g_isHCG = false; + val); return ret; } @@ -1983,7 +2497,7 @@ static int __IMX464_start_stream(struct IMX464 *IMX464) ret = IMX464_write_array(IMX464->client, IMX464->cur_mode->reg_list); if (ret) return ret; - ret = IMX464_init_conversion_gain(IMX464); + ret = IMX464_init_conversion_gain(IMX464, IMX464->isHCG); if (ret) return ret; /* In case these controls are set before streaming */ @@ -1999,18 +2513,44 @@ static int __IMX464_start_stream(struct IMX464 *IMX464) return ret; } } - imx464_write_reg(IMX464->client, IMX464_REG_CTRL_MODE, - IMX464_REG_VALUE_08BIT, IMX464_MODE_STREAMING); - usleep_range(30000, 40000); - return imx464_write_reg(IMX464->client, IMX464_REG_MARSTER_MODE, - IMX464_REG_VALUE_08BIT, 0); + + if (IMX464->sync_mode == EXTERNAL_MASTER_MODE) { + ret |= IMX464_write_array(IMX464->client, IMX464_external_sync_master_start_regs); + v4l2_err(&IMX464->subdev, "cur externam master mode\n"); + } else if (IMX464->sync_mode == INTERNAL_MASTER_MODE) { + ret |= IMX464_write_array(IMX464->client, IMX464_interal_sync_master_start_regs); + v4l2_err(&IMX464->subdev, "cur intertal master\n"); + } else if (IMX464->sync_mode == SLAVE_MODE) { + ret |= IMX464_write_array(IMX464->client, IMX464_slave_start_regs); + v4l2_err(&IMX464->subdev, "cur slave mode\n"); + } + if (IMX464->sync_mode == NO_SYNC_MODE) { + ret = imx464_write_reg(IMX464->client, IMX464_REG_CTRL_MODE, + IMX464_REG_VALUE_08BIT, IMX464_MODE_STREAMING); + usleep_range(30000, 40000); + ret |= imx464_write_reg(IMX464->client, IMX464_REG_MARSTER_MODE, + IMX464_REG_VALUE_08BIT, 0); + } else { + ret |= imx464_write_reg(IMX464->client, IMX464_REG_MARSTER_MODE, + IMX464_REG_VALUE_08BIT, 0); + } + return ret; } static int __IMX464_stop_stream(struct IMX464 *IMX464) { + int ret = 0; + IMX464->has_init_exp = false; - return imx464_write_reg(IMX464->client, IMX464_REG_CTRL_MODE, - IMX464_REG_VALUE_08BIT, IMX464_MODE_SW_STANDBY); + ret = imx464_write_reg(IMX464->client, IMX464_REG_CTRL_MODE, + IMX464_REG_VALUE_08BIT, IMX464_MODE_SW_STANDBY); + + if (IMX464->sync_mode == EXTERNAL_MASTER_MODE) + ret |= IMX464_write_array(IMX464->client, IMX464_external_sync_master_stop_regs); + else if (IMX464->sync_mode == INTERNAL_MASTER_MODE) + ret |= IMX464_write_array(IMX464->client, IMX464_interal_sync_master_stop_regs); + + return ret; } static int IMX464_s_stream(struct v4l2_subdev *sd, int on) @@ -2099,7 +2639,6 @@ static int __IMX464_power_on(struct IMX464 *IMX464) int ret; u32 delay_us; struct device *dev = &IMX464->client->dev; - unsigned long mclk = 0; if (!IS_ERR_OR_NULL(IMX464->pins_default)) { ret = pinctrl_select_state(IMX464->pinctrl, @@ -2107,15 +2646,14 @@ static int __IMX464_power_on(struct IMX464 *IMX464) if (ret < 0) dev_err(dev, "could not set pins\n"); } - if (IMX464->cur_mode->bus_fmt == MEDIA_BUS_FMT_SRGGB10_1X10) - mclk = IMX464_XVCLK_FREQ_37M; - else - mclk = IMX464_XVCLK_FREQ_24M; - ret = clk_set_rate(IMX464->xvclk, mclk); + + ret = clk_set_rate(IMX464->xvclk, IMX464->cur_mode->mclk); if (ret < 0) dev_warn(dev, "Failed to set xvclk rate\n"); - if (clk_get_rate(IMX464->xvclk) != mclk) - dev_warn(dev, "xvclk mismatched\n"); + if (clk_get_rate(IMX464->xvclk) != IMX464->cur_mode->mclk) + dev_warn(dev, "xvclk mismatched, %lu\n", clk_get_rate(IMX464->xvclk)); + else + IMX464->cur_mclk = IMX464->cur_mode->mclk; ret = clk_prepare_enable(IMX464->xvclk); if (ret < 0) { dev_err(dev, "Failed to enable xvclk\n"); @@ -2194,7 +2732,7 @@ static int IMX464_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) struct IMX464 *IMX464 = to_IMX464(sd); struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_get_try_format(sd, fh->pad, 0); - const struct IMX464_mode *def_mode = &supported_modes[0]; + const struct IMX464_mode *def_mode = &IMX464->support_modes[0]; mutex_lock(&IMX464->mutex); /* Initialize try_fmt */ @@ -2219,11 +2757,11 @@ static int IMX464_enum_frame_interval(struct v4l2_subdev *sd, if (fie->index >= IMX464->cfg_num) return -EINVAL; - fie->code = supported_modes[fie->index].bus_fmt; - fie->width = supported_modes[fie->index].width; - fie->height = supported_modes[fie->index].height; - fie->interval = supported_modes[fie->index].max_fps; - fie->reserved[0] = supported_modes[fie->index].hdr_mode; + fie->code = IMX464->support_modes[fie->index].bus_fmt; + fie->width = IMX464->support_modes[fie->index].width; + fie->height = IMX464->support_modes[fie->index].height; + fie->interval = IMX464->support_modes[fie->index].max_fps; + fie->reserved[0] = IMX464->support_modes[fie->index].hdr_mode; return 0; } @@ -2406,6 +2944,7 @@ static int IMX464_initialize_controls(struct IMX464 *IMX464) struct v4l2_ctrl_handler *handler; s64 exposure_max, vblank_def; u32 h_blank; + u64 pixel_rate = 0; int ret; handler = &IMX464->ctrl_handler; @@ -2418,28 +2957,13 @@ static int IMX464_initialize_controls(struct IMX464 *IMX464) IMX464->link_freq = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, 1, 0, link_freq_menu_items); - if (IMX464->cur_mode->bus_fmt == MEDIA_BUS_FMT_SRGGB10_1X10) { - IMX464->cur_link_freq = 1; - if (IMX464->cur_mode->hdr_mode == NO_HDR) { - IMX464->cur_pixel_rate = - IMX464_10BIT_LINEAR_PIXEL_RATE; - IMX464->cur_link_freq = 0; - } else if (IMX464->cur_mode->hdr_mode == HDR_X2) - IMX464->cur_pixel_rate = - IMX464_10BIT_HDR2_PIXEL_RATE; - else if (IMX464->cur_mode->hdr_mode == HDR_X3) - IMX464->cur_pixel_rate = - IMX464_10BIT_HDR3_PIXEL_RATE; - } else { - IMX464->cur_link_freq = 0; - IMX464->cur_pixel_rate = - IMX464_12BIT_PIXEL_RATE; - } __v4l2_ctrl_s_ctrl(IMX464->link_freq, - IMX464->cur_link_freq); + IMX464->cur_mode->mipi_freq_idx); + pixel_rate = (u32)link_freq_menu_items[mode->mipi_freq_idx] / mode->bpp * 2 * + IMX464->bus_cfg.bus.mipi_csi2.num_data_lanes; IMX464->pixel_rate = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, 0, IMX464_10BIT_HDR2_PIXEL_RATE, - 1, IMX464->cur_pixel_rate); + 1, pixel_rate); h_blank = mode->hts_def - mode->width; IMX464->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK, @@ -2476,6 +3000,7 @@ static int IMX464_initialize_controls(struct IMX464 *IMX464) IMX464->subdev.ctrl_handler = handler; IMX464->has_init_exp = false; + IMX464->isHCG = false; return 0; @@ -2523,9 +3048,12 @@ static int IMX464_probe(struct i2c_client *client, struct device_node *node = dev->of_node; struct IMX464 *IMX464; struct v4l2_subdev *sd; + struct device_node *endpoint; char facing[2]; int ret; u32 i, hdr_mode = 0; + const char *sync_mode_name = NULL; + dev_info(dev, "driver version: %02x.%02x.%02x", DRIVER_VERSION >> 16, @@ -2549,6 +3077,20 @@ static int IMX464_probe(struct i2c_client *client, return -EINVAL; } + ret = of_property_read_string(node, RKMODULE_CAMERA_SYNC_MODE, + &sync_mode_name); + if (ret) { + IMX464->sync_mode = NO_SYNC_MODE; + dev_err(dev, "could not get sync mode!\n"); + } else { + if (strcmp(sync_mode_name, RKMODULE_EXTERNAL_MASTER_MODE) == 0) + IMX464->sync_mode = EXTERNAL_MASTER_MODE; + else if (strcmp(sync_mode_name, RKMODULE_INTERNAL_MASTER_MODE) == 0) + IMX464->sync_mode = INTERNAL_MASTER_MODE; + else if (strcmp(sync_mode_name, RKMODULE_SLAVE_MODE) == 0) + IMX464->sync_mode = SLAVE_MODE; + } + ret = of_property_read_u32(node, OF_CAMERA_HDR_MODE, &hdr_mode); if (ret) { @@ -2556,15 +3098,28 @@ static int IMX464_probe(struct i2c_client *client, dev_warn(dev, " Get hdr mode failed! no hdr default\n"); } IMX464->client = client; + endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); + if (!endpoint) { + dev_err(dev, "Failed to get endpoint\n"); + return -EINVAL; + } + ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(endpoint), + &IMX464->bus_cfg); + if (IMX464->bus_cfg.bus.mipi_csi2.num_data_lanes == 4) { + IMX464->support_modes = supported_modes; + IMX464->cfg_num = ARRAY_SIZE(supported_modes); + } else { + IMX464->support_modes = supported_modes_2lane; + IMX464->cfg_num = ARRAY_SIZE(supported_modes_2lane); + } - IMX464->cfg_num = ARRAY_SIZE(supported_modes); for (i = 0; i < IMX464->cfg_num; i++) { - if (hdr_mode == supported_modes[i].hdr_mode) { - IMX464->cur_mode = &supported_modes[i]; + if (hdr_mode == IMX464->support_modes[i].hdr_mode) { + IMX464->cur_mode = &IMX464->support_modes[i]; break; } } - IMX464->cur_mode = &supported_modes[0]; + IMX464->cur_mode = &IMX464->support_modes[0]; IMX464->xvclk = devm_clk_get(dev, "xvclk"); if (IS_ERR(IMX464->xvclk)) { dev_err(dev, "Failed to get xvclk\n"); @@ -2650,7 +3205,6 @@ static int IMX464_probe(struct i2c_client *client, pm_runtime_enable(dev); pm_runtime_idle(dev); - g_isHCG = false; #ifdef USED_SYS_DEBUG add_sysfs_interfaces(dev); #endif