From e3e12f52b214121840b44c91de5b3e5af5d3eb84 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 06 Nov 2023 03:04:41 +0000 Subject: [PATCH] rk3568 rt init --- kernel/drivers/media/i2c/imx464.c | 1042 ++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 878 insertions(+), 164 deletions(-) diff --git a/kernel/drivers/media/i2c/imx464.c b/kernel/drivers/media/i2c/imx464.c index 3458ff9..8d6c04b 100644 --- a/kernel/drivers/media/i2c/imx464.c +++ b/kernel/drivers/media/i2c/imx464.c @@ -10,6 +10,7 @@ * V0.0X01.0X03 support enum sensor fmt */ +//#define DEBUG #include <linux/clk.h> #include <linux/device.h> #include <linux/delay.h> @@ -26,8 +27,11 @@ #include <media/v4l2-async.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-subdev.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-mediabus.h> #include <linux/pinctrl/consumer.h> #include <linux/rk-preisp.h> +#include <linux/of_graph.h> #define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x03) @@ -42,15 +46,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 +134,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 +149,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 */ @@ -165,17 +162,17 @@ #define IMX464_NUM_SUPPLIES ARRAY_SIZE(IMX464_supply_names) +struct regval { + u16 addr; + u8 val; +}; + enum IMX464_max_pad { PAD0, /* link to isp */ PAD1, /* link to csi wr0 | hdr x2:L x3:M */ PAD2, /* link to csi wr1 | hdr x3:L */ PAD3, /* link to csi wr2 | hdr x2:M x3:S */ PAD_MAX, -}; - -struct regval { - u16 addr; - u8 val; }; struct IMX464_mode { @@ -186,6 +183,9 @@ 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]; @@ -213,19 +213,22 @@ 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) @@ -237,16 +240,16 @@ {REG_NULL, 0x00}, }; -static const struct regval IMX464_linear_10bit_2688x1520_regs[] = { +static __maybe_unused const struct regval IMX464_linear_10bit_2688x1520_2lane_37m_regs[] = { {0x3000, 0x01}, {0x3002, 0x01}, {0x300C, 0x5B}, {0x300D, 0x40}, - {0x3030, 0xE4}, - {0x3031, 0x0C}, + {0x3034, 0xDC}, + {0x3035, 0x05}, {0x3050, 0x00}, - {0x3058, 0x06}, - {0x3059, 0x09}, + {0x3058, 0x83}, + {0x3059, 0x04}, {0x30BE, 0x5E}, {0x30E8, 0x14}, {0x3110, 0x02}, @@ -256,6 +259,488 @@ {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}, + {0x300C, 0x5B}, + {0x300D, 0x40}, + {0x3030, 0xE4}, + {0x3031, 0x0C}, + {0x3034, 0xee}, + {0x3035, 0x02}, + {0x3048, 0x00}, + {0x3049, 0x00}, + {0x304A, 0x03}, + {0x304B, 0x02}, + {0x304C, 0x14}, + {0x3050, 0x00}, + {0x3058, 0x06}, + {0x3059, 0x09}, + {0x305C, 0x09}, + {0x3060, 0x21}, + {0x3061, 0x01}, + {0x3068, 0xc9}, + {0x306C, 0x56}, + {0x306D, 0x09}, + {0x30BE, 0x5E}, + {0x30E8, 0x14}, + {0x3110, 0x02}, + {0x314C, 0xC0}, + {0x315A, 0x06}, + {0x316A, 0x7E}, + {0x319D, 0x00}, + {0x319E, 0x02}, + {0x31A1, 0x00}, + {0x31D7, 0x00}, + {0x3200, 0x11}, {0x3288, 0x22}, {0x328A, 0x02}, {0x328C, 0xA2}, @@ -350,6 +835,10 @@ {0x3002, 0x01}, {0x300C, 0x5B}, {0x300D, 0x40}, + {0x3030, 0x72}, + {0x3031, 0x06}, + {0x3034, 0xee}, + {0x3035, 0x02}, {0x3048, 0x01}, {0x3049, 0x01}, {0x304A, 0x04}, @@ -358,7 +847,12 @@ {0x3050, 0x00}, {0x3058, 0x06}, {0x3059, 0x09}, + {0x305C, 0x09}, + {0x3060, 0x21}, + {0x3061, 0x01}, {0x3068, 0x6D}, + {0x306C, 0x56}, + {0x306D, 0x09}, {0x30BE, 0x5E}, {0x30E8, 0x14}, {0x3110, 0x02}, @@ -498,6 +992,7 @@ {0x319E, 0x01}, {0x31A1, 0x00}, {0x31D7, 0x03}, + {0x3200, 0x10}, {0x3288, 0x22}, {0x328A, 0x02}, {0x328C, 0xA2}, @@ -584,7 +1079,6 @@ {0x3A24, 0x4F}, {0x3A26, 0x5F}, {0x3A28, 0x3F}, - {0x3200, 0x10}, {REG_NULL, 0x00}, }; @@ -824,6 +1318,33 @@ {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. @@ -848,6 +1369,9 @@ .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, @@ -863,6 +1387,9 @@ .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, @@ -889,12 +1416,57 @@ #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, .vc[PAD1] = V4L2_MBUS_CSI2_CHANNEL_1,//M->csi wr0 .vc[PAD2] = V4L2_MBUS_CSI2_CHANNEL_0,//L->csi wr1 .vc[PAD3] = V4L2_MBUS_CSI2_CHANNEL_2,//S->csi wr2 + }, +}; + +static const struct IMX464_mode supported_modes_2lane[] = { + { + .bus_fmt = MEDIA_BUS_FMT_SRGGB10_1X10, + .width = 2712, + .height = 1538, + .max_fps = { + .numerator = 10000, + .denominator = 300000, + }, + .exp_def = 0x0600, + .hts_def = 0x05dc * 2, + .vts_def = 0x672, + .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 }, }; @@ -997,15 +1569,15 @@ 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, @@ -1015,8 +1587,7 @@ 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); @@ -1042,42 +1613,12 @@ 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); @@ -1137,13 +1678,13 @@ 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; } @@ -1167,19 +1708,20 @@ 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 | @@ -1241,12 +1783,12 @@ 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, @@ -1428,12 +1970,12 @@ //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, @@ -1670,12 +2212,12 @@ 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, @@ -1743,12 +2285,26 @@ } #endif +static int IMX464_get_channel_info(struct IMX464 *IMX464, struct rkmodule_channel_info *ch_info) +{ + if (ch_info->index >= PAD_MAX) + return -EINVAL; + ch_info->vc = IMX464->cur_mode->vc[ch_info->index]; + ch_info->width = IMX464->cur_mode->width; + ch_info->height = IMX464->cur_mode->height; + ch_info->bus_fmt = IMX464->cur_mode->bus_fmt; + return 0; +} + static long IMX464_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { struct IMX464 *IMX464 = to_IMX464(sd); struct rkmodule_hdr_cfg *hdr; + struct rkmodule_channel_info *ch_info; u32 i, h, w, stream; long ret = 0; + u64 pixel_rate = 0; + u32 *sync_mode = NULL; switch (cmd) { case PREISP_CMD_SET_HDRAE_EXP: @@ -1770,10 +2326,10 @@ 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; } } @@ -1790,16 +2346,13 @@ 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: @@ -1809,16 +2362,25 @@ 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; + ret = IMX464_get_channel_info(IMX464, ch_info); + break; + case RKMODULE_GET_SYNC_MODE: + sync_mode = (u32 *)arg; + *sync_mode = IMX464->sync_mode; + break; + case RKMODULE_SET_SYNC_MODE: + sync_mode = (u32 *)arg; + IMX464->sync_mode = *sync_mode; break; default: ret = -ENOIOCTLCMD; @@ -1837,9 +2399,11 @@ struct rkmodule_awb_cfg *cfg; struct rkmodule_hdr_cfg *hdr; struct preisp_hdrae_exp_s *hdrae; + struct rkmodule_channel_info *ch_info; long ret; u32 cg = 0; u32 stream; + u32 sync_mode; switch (cmd) { case RKMODULE_GET_MODULE_INFO: @@ -1850,8 +2414,11 @@ } ret = IMX464_ioctl(sd, cmd, inf); - if (!ret) + if (!ret) { ret = copy_to_user(up, inf, sizeof(*inf)); + if (ret) + ret = -EFAULT; + } kfree(inf); break; case RKMODULE_AWB_CFG: @@ -1864,6 +2431,8 @@ ret = copy_from_user(cfg, up, sizeof(*cfg)); if (!ret) ret = IMX464_ioctl(sd, cmd, cfg); + else + ret = -EFAULT; kfree(cfg); break; case RKMODULE_GET_HDR_CFG: @@ -1874,8 +2443,11 @@ } ret = IMX464_ioctl(sd, cmd, hdr); - if (!ret) + if (!ret) { ret = copy_to_user(up, hdr, sizeof(*hdr)); + if (ret) + ret = -EFAULT; + } kfree(hdr); break; case RKMODULE_SET_HDR_CFG: @@ -1888,6 +2460,8 @@ ret = copy_from_user(hdr, up, sizeof(*hdr)); if (!ret) ret = IMX464_ioctl(sd, cmd, hdr); + else + ret = -EFAULT; kfree(hdr); break; case PREISP_CMD_SET_HDRAE_EXP: @@ -1900,18 +2474,54 @@ ret = copy_from_user(hdrae, up, sizeof(*hdrae)); if (!ret) ret = IMX464_ioctl(sd, cmd, hdrae); + else + ret = -EFAULT; kfree(hdrae); break; case RKMODULE_SET_CONVERSION_GAIN: ret = copy_from_user(&cg, up, sizeof(cg)); if (!ret) ret = IMX464_ioctl(sd, cmd, &cg); + else + ret = -EFAULT; break; case RKMODULE_SET_QUICK_STREAM: ret = copy_from_user(&stream, up, sizeof(u32)); if (!ret) ret = IMX464_ioctl(sd, cmd, &stream); + else + ret = -EFAULT; + break; + case RKMODULE_GET_CHANNEL_INFO: + ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL); + if (!ch_info) { + ret = -ENOMEM; + return ret; + } + + ret = IMX464_ioctl(sd, cmd, ch_info); + if (!ret) { + ret = copy_to_user(up, ch_info, sizeof(*ch_info)); + if (ret) + ret = -EFAULT; + } + kfree(ch_info); + break; + case RKMODULE_GET_SYNC_MODE: + ret = IMX464_ioctl(sd, cmd, &sync_mode); + if (!ret) { + ret = copy_to_user(up, &sync_mode, sizeof(u32)); + if (ret) + ret = -EFAULT; + } + break; + case RKMODULE_SET_SYNC_MODE: + ret = copy_from_user(&sync_mode, up, sizeof(u32)); + if (!ret) + ret = IMX464_ioctl(sd, cmd, &sync_mode); + else + ret = -EFAULT; break; default: ret = -ENOIOCTLCMD; @@ -1922,17 +2532,20 @@ } #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; } @@ -1943,7 +2556,7 @@ 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 */ @@ -1959,18 +2572,43 @@ 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) @@ -2059,7 +2697,6 @@ 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, @@ -2067,15 +2704,14 @@ 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"); @@ -2089,7 +2725,7 @@ dev_err(dev, "Failed to enable regulators\n"); goto disable_clk; } - + usleep_range(15000, 16000); if (!IS_ERR(IMX464->reset_gpio)) gpiod_set_value_cansleep(IMX464->reset_gpio, 1); @@ -2126,6 +2762,7 @@ dev_err(dev, "could not set pins\n"); } regulator_bulk_disable(IMX464_NUM_SUPPLIES, IMX464->supplies); + usleep_range(15000, 16000); } static int IMX464_runtime_resume(struct device *dev) @@ -2154,7 +2791,7 @@ 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 */ @@ -2179,16 +2816,16 @@ 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; } #define CROP_START(SRC, DST) (((SRC) - (DST)) / 2 / 4 * 4) -#define DST_WIDTH 2688 +#define DST_WIDTH 2560 #define DST_HEIGHT 1520 /* @@ -2266,7 +2903,7 @@ u32 vts = 0; int ret = 0; u32 shr0 = 0; - //u32 flip = 0; + u32 flip = 0; /* Propagate change of current control to all related controls */ switch (ctrl->id) { @@ -2298,7 +2935,7 @@ ret |= imx464_write_reg(IMX464->client, IMX464_LF_EXPO_REG_H, IMX464_REG_VALUE_08BIT, IMX464_FETCH_EXP_H(shr0)); - dev_err(&client->dev, "set exposure 0x%x\n", + dev_dbg(&client->dev, "set exposure 0x%x\n", ctrl->val); } break; @@ -2310,7 +2947,7 @@ ret |= imx464_write_reg(IMX464->client, IMX464_LF_GAIN_REG_L, IMX464_REG_VALUE_08BIT, IMX464_FETCH_GAIN_L(ctrl->val)); - dev_err(&client->dev, "set analog gain 0x%x\n", + dev_dbg(&client->dev, "set analog gain 0x%x\n", ctrl->val); } break; @@ -2338,12 +2975,67 @@ IMX464_REG_VALUE_08BIT, IMX464_FETCH_VTS_H(vts)); - dev_err(&client->dev, "set vts 0x%x\n", - vts); + dev_dbg(&client->dev, "set vts 0x%x\n", vts); break; case V4L2_CID_HFLIP: + ret = imx464_write_reg(client, + IMX464_GROUP_HOLD_REG, + IMX464_REG_VALUE_08BIT, + IMX464_GROUP_HOLD_START); + ret |= imx464_write_reg(IMX464->client, IMX464_HREVERSE_REG, + IMX464_REG_VALUE_08BIT, !!ctrl->val); + ret |= imx464_write_reg(client, + IMX464_GROUP_HOLD_REG, + IMX464_REG_VALUE_08BIT, + IMX464_GROUP_HOLD_END); break; case V4L2_CID_VFLIP: + flip = ctrl->val; + ret = imx464_write_reg(client, + IMX464_GROUP_HOLD_REG, + IMX464_REG_VALUE_08BIT, + IMX464_GROUP_HOLD_START); + ret |= imx464_write_reg(IMX464->client, IMX464_VREVERSE_REG, + IMX464_REG_VALUE_08BIT, !!flip); + if (flip) { + ret |= imx464_write_reg(IMX464->client, 0x3074, + IMX464_REG_VALUE_08BIT, 0x40); + ret |= imx464_write_reg(IMX464->client, 0x3075, + IMX464_REG_VALUE_08BIT, 0x06); + ret |= imx464_write_reg(IMX464->client, 0x3080, + IMX464_REG_VALUE_08BIT, 0xff); + ret |= imx464_write_reg(IMX464->client, 0x30ad, + IMX464_REG_VALUE_08BIT, 0x7e); + ret |= imx464_write_reg(IMX464->client, 0x30b6, + IMX464_REG_VALUE_08BIT, 0xff); + ret |= imx464_write_reg(IMX464->client, 0x30b7, + IMX464_REG_VALUE_08BIT, 0x01); + ret |= imx464_write_reg(IMX464->client, 0x30d8, + IMX464_REG_VALUE_08BIT, 0x45); + ret |= imx464_write_reg(IMX464->client, 0x3114, + IMX464_REG_VALUE_08BIT, 0x01); + } else { + ret |= imx464_write_reg(IMX464->client, 0x3074, + IMX464_REG_VALUE_08BIT, 0x3c); + ret |= imx464_write_reg(IMX464->client, 0x3075, + IMX464_REG_VALUE_08BIT, 0x00); + ret |= imx464_write_reg(IMX464->client, 0x3080, + IMX464_REG_VALUE_08BIT, 0x01); + ret |= imx464_write_reg(IMX464->client, 0x30ad, + IMX464_REG_VALUE_08BIT, 0x02); + ret |= imx464_write_reg(IMX464->client, 0x30b6, + IMX464_REG_VALUE_08BIT, 0x00); + ret |= imx464_write_reg(IMX464->client, 0x30b7, + IMX464_REG_VALUE_08BIT, 0x00); + ret |= imx464_write_reg(IMX464->client, 0x30d8, + IMX464_REG_VALUE_08BIT, 0x44); + ret |= imx464_write_reg(IMX464->client, 0x3114, + IMX464_REG_VALUE_08BIT, 0x02); + } + ret |= imx464_write_reg(client, + IMX464_GROUP_HOLD_REG, + IMX464_REG_VALUE_08BIT, + IMX464_GROUP_HOLD_END); break; default: dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n", @@ -2366,6 +3058,7 @@ struct v4l2_ctrl_handler *handler; s64 exposure_max, vblank_def; u32 h_blank; + u64 pixel_rate = 0; int ret; handler = &IMX464->ctrl_handler; @@ -2378,28 +3071,13 @@ 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, @@ -2436,6 +3114,7 @@ IMX464->subdev.ctrl_handler = handler; IMX464->has_init_exp = false; + IMX464->isHCG = false; return 0; @@ -2483,9 +3162,12 @@ 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, @@ -2509,6 +3191,20 @@ 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) { @@ -2516,15 +3212,32 @@ 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 (ret) { + dev_err(dev, "Failed to get bus cfg\n"); + return ret; + } + 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"); @@ -2610,7 +3323,6 @@ pm_runtime_enable(dev); pm_runtime_idle(dev); - g_isHCG = false; #ifdef USED_SYS_DEBUG add_sysfs_interfaces(dev); #endif @@ -2655,6 +3367,7 @@ #if IS_ENABLED(CONFIG_OF) static const struct of_device_id IMX464_of_match[] = { { .compatible = "sony,IMX464" }, + { .compatible = "sony,imx464" }, {}, }; MODULE_DEVICE_TABLE(of, IMX464_of_match); @@ -2662,6 +3375,7 @@ static const struct i2c_device_id IMX464_match_id[] = { { "sony,IMX464", 0 }, + { "sony,imx464", 0 }, { }, }; -- Gitblit v1.6.2