diff --git a/drivers/media/i2c/imx327.c b/drivers/media/i2c/imx327.c index f641ee72e7c6..371d5af169f9 100644 --- a/drivers/media/i2c/imx327.c +++ b/drivers/media/i2c/imx327.c @@ -2,8 +2,9 @@ /* * imx327 driver * - * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd. + * Copyright (C) 2020 Rockchip Electronics Co., Ltd. * V0.0X01.0X03 add enum_frame_interval function. + * V0.0X01.0X04 support lvds interface. */ #include @@ -16,89 +17,104 @@ #include #include #include +#include #include +#include #include #include #include #include #include +#include #include -#include -#include -#include -#include -#include -#include #include -#include - -#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x03) +#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x04) #ifndef V4L2_CID_DIGITAL_GAIN #define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN #endif -#define IMX327_LINK_FREQ 222750000 -#define IMX327_HDR_LANES 4 -#define IMX327_LANES 2 -#define IMX327_BITS_PER_SAMPLE 12 +#define IMX327_LINK_FREQ_111M 111370000 +#define IMX327_LINK_FREQ_222M 222750000 +#define IMX327_2LANES 2 +#define IMX327_4LANES 4 +#define IMX327_BITS_PER_SAMPLE 10 /* pixel rate = link frequency * 2 * lanes / BITS_PER_SAMPLE */ -#define IMX327_PIXEL_RATE \ -(IMX327_LINK_FREQ * 2 * IMX327_LANES / IMX327_BITS_PER_SAMPLE) - -#define IMX327_PIXEL_HDR_RATE \ -(IMX327_LINK_FREQ * 2 * IMX327_HDR_LANES / IMX327_BITS_PER_SAMPLE) +#define IMX327_PIXEL_RATE_NORMAL (IMX327_LINK_FREQ_111M * 2 / 10 * IMX327_4LANES) +#define IMX327_PIXEL_RATE_HDR (IMX327_LINK_FREQ_222M * 2 / 10 * IMX327_4LANES) #define IMX327_XVCLK_FREQ 37125000 -#define CHIP_ID 0xa0 -#define IMX327_REG_CHIP_ID 0x3008 +#define CHIP_ID 0xb2 +#define IMX327_REG_CHIP_ID 0x301e #define IMX327_REG_CTRL_MODE 0x3000 #define IMX327_MODE_SW_STANDBY 0x1 #define IMX327_MODE_STREAMING 0x0 -#define IMX327_REG_EXPOSURE_H 0x3022 -#define IMX327_REG_EXPOSURE_M 0x3021 -#define IMX327_REG_EXPOSURE_L 0x3020 +#define IMX327_REG_SHS1_H 0x3022 +#define IMX327_REG_SHS1_M 0x3021 +#define IMX327_REG_SHS1_L 0x3020 -#define IMX327_FETCH_HIGH_BYTE_EXP(VAL) (((VAL) >> 16) & 0x03) -#define IMX327_FETCH_MID_BYTE_EXP(VAL) (((VAL) >> 8) & 0xFF) -#define IMX327_FETCH_LOW_BYTE_EXP(VAL) ((VAL) & 0xFF) +#define IMX327_REG_SHS2_H 0x3026 +#define IMX327_REG_SHS2_M 0x3025 +#define IMX327_REG_SHS2_L 0x3024 + +#define IMX327_REG_RHS1_H 0x3032 +#define IMX327_REG_RHS1_M 0x3031 +#define IMX327_REG_RHS1_L 0x3030 + +#define IMX327_FETCH_HIGH_BYTE_EXP(VAL) (((VAL) >> 16) & 0x0F) +#define IMX327_FETCH_MID_BYTE_EXP(VAL) (((VAL) >> 8) & 0xFF) +#define IMX327_FETCH_LOW_BYTE_EXP(VAL) ((VAL) & 0xFF) #define IMX327_EXPOSURE_MIN 2 #define IMX327_EXPOSURE_STEP 1 #define IMX327_VTS_MAX 0x7fff -#define IMX327_REG_GAIN 0x3014 +#define IMX327_GAIN_SWITCH_REG 0x3009 +#define IMX327_REG_LF_GAIN 0x3014 +#define IMX327_REG_SF_GAIN 0x30f2 #define IMX327_GAIN_MIN 0x00 #define IMX327_GAIN_MAX 0xee #define IMX327_GAIN_STEP 1 #define IMX327_GAIN_DEFAULT 0x00 -#define IMX327_REG_TEST_PATTERN 0x5e00 -#define IMX327_TEST_PATTERN_ENABLE 0x80 -#define IMX327_TEST_PATTERN_DISABLE 0x0 +#define IMX327_GROUP_HOLD_REG 0x3001 +#define IMX327_GROUP_HOLD_START 0x01 +#define IMX327_GROUP_HOLD_END 0x00 + +#define USED_TEST_PATTERN +#ifdef USED_TEST_PATTERN +#define IMX327_REG_TEST_PATTERN 0x308c +#define IMX327_TEST_PATTERN_ENABLE BIT(0) +#endif #define IMX327_REG_VTS_H 0x301a #define IMX327_REG_VTS_M 0x3019 #define IMX327_REG_VTS_L 0x3018 -#define IMX327_FETCH_HIGH_BYTE_VTS(VAL) (((VAL) >> 16) & 0x03) -#define IMX327_FETCH_MID_BYTE_VTS(VAL) (((VAL) >> 8) & 0xFF) -#define IMX327_FETCH_LOW_BYTE_VTS(VAL) ((VAL) & 0xFF) +#define IMX327_FETCH_HIGH_BYTE_VTS(VAL) (((VAL) >> 16) & 0x03) +#define IMX327_FETCH_MID_BYTE_VTS(VAL) (((VAL) >> 8) & 0xFF) +#define IMX327_FETCH_LOW_BYTE_VTS(VAL) ((VAL) & 0xFF) -#define REG_DELAY 0xFFFE #define REG_NULL 0xFFFF +#define REG_DELAY 0xFFFE #define IMX327_REG_VALUE_08BIT 1 #define IMX327_REG_VALUE_16BIT 2 #define IMX327_REG_VALUE_24BIT 3 +static bool g_isHCG; + #define IMX327_NAME "imx327" -#define IMX327_RHS1 0xe1 -static bool g_isHCG; +#define OF_CAMERA_PINCTRL_STATE_DEFAULT "rockchip,camera_default" +#define OF_CAMERA_PINCTRL_STATE_SLEEP "rockchip,camera_sleep" + +#define IMX327_FLIP_REG 0x3007 +#define MIRROR_BIT_MASK BIT(1) +#define FLIP_BIT_MASK BIT(0) static const char * const imx327_supply_names[] = { "avdd", /* Analog power */ @@ -122,6 +138,8 @@ struct imx327_mode { u32 vts_def; u32 exp_def; const struct regval *reg_list; + u32 hdr_mode; + struct rkmodule_lvds_cfg lvds_cfg; }; struct imx327 { @@ -131,6 +149,10 @@ struct imx327 { struct gpio_desc *pwdn_gpio; struct regulator_bulk_data supplies[IMX327_NUM_SUPPLIES]; + struct pinctrl *pinctrl; + struct pinctrl_state *pins_default; + struct pinctrl_state *pins_sleep; + struct v4l2_subdev subdev; struct media_pad pad; struct v4l2_ctrl_handler ctrl_handler; @@ -139,52 +161,110 @@ struct imx327 { struct v4l2_ctrl *digi_gain; struct v4l2_ctrl *hblank; struct v4l2_ctrl *vblank; + struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *h_flip; + struct v4l2_ctrl *v_flip; +#ifdef USED_TEST_PATTERN struct v4l2_ctrl *test_pattern; +#endif struct mutex mutex; bool streaming; bool power_on; - bool has_devnode; - const struct imx327_mode *cur_mode; const struct imx327_mode *support_modes; - u32 support_modes_num; + u32 support_modes_num; + const struct imx327_mode *cur_mode; u32 module_index; const char *module_facing; const char *module_name; const char *len_name; + u32 cur_vts; + bool has_init_exp; + struct preisp_hdrae_exp_s init_hdrae_exp; + struct v4l2_fwnode_endpoint bus_cfg; + u8 flip; }; #define to_imx327(sd) container_of(sd, struct imx327, subdev) /* * Xclk 37.125Mhz - * max_framerate 30fps - * mipi_datarate per lane 445Mbps */ -static const struct regval imx327_1920x1080_regs[] = { +static const struct regval imx327_global_regs[] = { + {REG_NULL, 0x00}, +}; + +/* + * Xclk 37.125Mhz + * max_framerate 30fps + * lvds_datarate per lane 222.75Mbps 4 lane + */ +static const struct regval imx327_linear_1920x1080_lvds_regs[] = { {0x3003, 0x01}, {REG_DELAY, 0x10}, {0x3000, 0x01}, {0x3001, 0x00}, - {0x3002, 0x00}, - {0x3005, 0x01}, + {0x3002, 0x01}, + {0x3005, 0x00}, {0x3007, 0x00}, {0x3009, 0x02}, - {0x300a, 0xf0}, - {0x300b, 0x00}, + {0x300a, 0x3c}, + {0x3010, 0x21}, {0x3011, 0x0a}, - {0x3012, 0x64}, - {0x3014, 0x00}, - {0x3018, 0x65},/* vMAX L */ - {0x3019, 0x04},/* VMAX M */ - {0x301a, 0x00},/* VMAX H */ - {0x301c, 0x30},/* HMAX L */ - {0x301d, 0x11},/* HMAX H */ - {0x3020, 0xfe}, - {0x3021, 0x03}, - {0x3022, 0x00}, - {0x3046, 0x01}, - {0x3048, 0x00}, - {0x3049, 0x08}, + {0x3018, 0x46}, + {0x3019, 0x05}, + {0x301c, 0x30}, + {0x301d, 0x11}, + {0x3046, 0xe0}, + {0x304b, 0x0a}, + {0x305c, 0x18}, + {0x305d, 0x00}, + {0x305e, 0x20}, + {0x305f, 0x01}, + {0x309e, 0x4a}, + {0x309f, 0x4a}, + {0x311c, 0x0e}, + {0x3128, 0x04}, + {0x3129, 0x1d}, + {0x313b, 0x41}, + {0x315e, 0x1a}, + {0x3164, 0x1a}, + {0x317c, 0x12}, + {0x31ec, 0x37}, + {0x3480, 0x49}, + {0x3002, 0x00}, + {REG_NULL, 0x00}, +}; + +/* + * Xclk 37.125Mhz + * max_framerate 30fps + * lvds_datarate per lane 445.5Mbps 4 lane + */ +static const struct regval imx327_hdr2_1920x1080_lvds_regs[] = { + {0x3003, 0x01}, + {REG_DELAY, 0x10}, + {0x3000, 0x01}, + {0x3001, 0x00}, + {0x3002, 0x01}, + {0x3005, 0x00}, + {0x3007, 0x40}, + {0x3009, 0x01}, + {0x300a, 0x3c}, + {0x300c, 0x11}, + {0x3011, 0x02}, + {0x3018, 0xb8},/* VMAX L */ + {0x3019, 0x05},/* VMAX M */ + {0x301c, 0xec},/* HMAX L */ + {0x301d, 0x07},/* HMAX H */ + {0x3020, 0x02},//hdr+ shs1 l short + {0x3021, 0x00},//hdr+ shs1 m + {0x3024, 0xc9},//hdr+ shs2 l + {0x3025, 0x07},//hdr+ shs2 m + {0x3030, 0xe1},//hdr+ IMX327_RHS1 + {0x3031, 0x00},//hdr+IMX327_RHS1 + {0x3045, 0x03},//hdr+ + {0x3046, 0xe0}, {0x304b, 0x0a}, {0x305c, 0x18}, {0x305d, 0x03}, @@ -194,52 +274,112 @@ static const struct regval imx327_1920x1080_regs[] = { {0x309f, 0x4a}, {0x30d2, 0x19}, {0x30d7, 0x03}, - {0x3128, 0x04}, - {0x3129, 0x00}, - {0x313b, 0x41}, + {0x3106, 0x11}, + {0x3129, 0x1d}, + {0x313b, 0x61}, {0x315e, 0x1a}, {0x3164, 0x1a}, - {0x317c, 0x00}, - {0x31ec, 0x0e}, - {0x3405, 0x10}, - {0x3407, 0x01}, - {0x3414, 0x0a}, - {0x3418, 0x38}, - {0x3419, 0x04}, - {0x3441, 0x0c}, - {0x3442, 0x0c}, - {0x3443, 0x01}, - {0x3444, 0x20}, - {0x3445, 0x25}, - {0x3446, 0x57}, - {0x3447, 0x00}, - {0x3448, 0x55}, - {0x3449, 0x00}, - {0x344a, 0x1f}, - {0x344b, 0x00}, - {0x344c, 0x1f}, - {0x344d, 0x00}, - {0x344e, 0x1f}, - {0x344f, 0x00}, - {0x3450, 0x77}, - {0x3451, 0x00}, - {0x3452, 0x1f}, - {0x3453, 0x00}, - {0x3454, 0x17}, - {0x3455, 0x00}, - {0x3472, 0x80}, - {0x3473, 0x07}, + {0x317c, 0x12}, + {0x31ec, 0x37}, + {0x3414, 0x00}, + {0x3415, 0x00}, {0x3480, 0x49}, + {0x31a0, 0xb4}, + {0x31a1, 0x02}, + {0x303c, 0x04},//Y offset + {0x303d, 0x00}, + {0x303e, 0x41}, + {0x303f, 0x04},//height + {0x303A, 0x08},//hdr+ + {0x3010, 0x61},//hdr+ gain 1frame FPGC + {0x3014, 0x00},//hdr+ gain 1frame long + {0x30F0, 0x64},//hdr+ gain 2frame FPGC + {0x30f2, 0x00},//hdr+ gain 2frame short + {0x3002, 0x00}, {REG_NULL, 0x00}, }; -static const struct regval imx327_hdr_1920x1080_regs[] = { - //10bit hdr2 +/* + * Xclk 37.125Mhz + * max_framerate 30fps + * mipi_datarate per lane 222.75Mbps 4 lane + */ +static const struct regval imx327_linear_1920x1080_mipi_regs[] = { {0x3003, 0x01}, {REG_DELAY, 0x10}, {0x3000, 0x01}, {0x3001, 0x00}, + {0x3002, 0x01}, + {0x3005, 0x00}, + {0x3007, 0x00}, + {0x3009, 0x02}, + {0x300A, 0x3c}, + {0x3010, 0x21}, + {0x3011, 0x0a}, + {0x3018, 0x46}, + {0x3019, 0x05}, + {0x301C, 0x30}, + {0x301D, 0x11}, + {0x3046, 0x00}, + {0x304B, 0x0A}, + {0x305C, 0x18}, + {0x305D, 0x03}, + {0x305E, 0x20}, + {0x305F, 0x01}, + {0x309E, 0x4A}, + {0x309F, 0x4A}, + {0x311c, 0x0e}, + {0x3128, 0x04}, + {0x3129, 0x1d}, + {0x313B, 0x41}, + {0x315E, 0x1A}, + {0x3164, 0x1A}, + {0x317C, 0x12}, + {0x31EC, 0x37}, + {0x3405, 0x20}, + {0x3407, 0x03}, + {0x3414, 0x0A}, + {0x3418, 0x49}, + {0x3419, 0x04}, + {0x3441, 0x0a}, + {0x3442, 0x0a}, + {0x3443, 0x03}, + {0x3444, 0x20}, + {0x3445, 0x25}, + {0x3446, 0x47}, + {0x3447, 0x00}, + {0x3448, 0x1f}, + {0x3449, 0x00}, + {0x344A, 0x17}, + {0x344B, 0x00}, + {0x344C, 0x0F}, + {0x344D, 0x00}, + {0x344E, 0x17}, + {0x344F, 0x00}, + {0x3450, 0x47}, + {0x3451, 0x00}, + {0x3452, 0x0F}, + {0x3453, 0x00}, + {0x3454, 0x0f}, + {0x3455, 0x00}, + {0x3472, 0x9c}, + {0x3473, 0x07}, + {0x3480, 0x49}, {0x3002, 0x00}, + {REG_NULL, 0x00}, +}; + +/* + * Xclk 37.125Mhz + * max_framerate 30fps + * mipi_datarate per lane 445.5Mbps 4 lane + */ +static const struct regval imx327_hdr2_1920x1080_mipi_regs[] = { + {0x3003, 0x01}, + {REG_DELAY, 0x10}, + {0x3000, 0x01}, + {0x3001, 0x00}, + {0x3002, 0x01}, {0x3005, 0x00}, {0x3007, 0x40}, {0x3009, 0x01}, @@ -273,7 +413,7 @@ static const struct regval imx327_hdr_1920x1080_regs[] = { {0x3407, 0x03}, {0x3414, 0x00}, {0x3415, 0x00},//hdr+ - {0x3418, 0x7A}, + {0x3418, 0x72}, {0x3419, 0x09}, {0x3441, 0x0a}, {0x3442, 0x0a}, @@ -300,83 +440,195 @@ static const struct regval imx327_hdr_1920x1080_regs[] = { {0x3473, 0x07}, {0x347b, 0x23}, {0x3480, 0x49}, - {0x31a0, 0xb4},//hdr+ {0x31a1, 0x02},//hdr+ - {0x3020, 0x02},//hdr+ shs1 l short {0x3021, 0x00},//hdr+ shs1 m {0x3022, 0x00},//hdr+ shs1 h {0x3030, 0xe1},//hdr+ IMX327_RHS1 {0x3031, 0x00},//hdr+IMX327_RHS1 {0x3032, 0x00},//hdr+ - {0x31A0, 0xe8},//hdr+ HBLANK1 {0x31A1, 0x01},//hdr+ - {0x303C, 0x04},//hdr+ - {0x303D, 0x00},//hdr+ - {0x303E, 0x41},//hdr+ - {0x303F, 0x04},//hdr+ + {0x303c, 0x04}, + {0x303d, 0x00}, + {0x303e, 0x41}, + {0x303f, 0x04}, {0x303A, 0x08},//hdr+ - {0x3024, 0xc9},//hdr+ shs2 l {0x3025, 0x06},//hdr+ shs2 m {0x3026, 0x00},//hdr+ shs2 h - {0x3010, 0x61},//hdr+ gain 1frame FPGC {0x3014, 0x00},//hdr+ gain 1frame long {0x30F0, 0x64},//hdr+ gain 2frame FPGC {0x30f2, 0x00},//hdr+ gain 2frame short + {0x3002, 0x00}, {REG_NULL, 0x00}, }; -static const struct imx327_mode supported_hdr_modes[] = { +/* + * The width and height must be configured to be + * the same as the current output resolution of the sensor. + * The input width of the isp needs to be 16 aligned. + * The input height of the isp needs to be 8 aligned. + * If the width or height does not meet the alignment rules, + * you can configure the cropping parameters with the following function to + * crop out the appropriate resolution. + * struct v4l2_subdev_pad_ops { + * .get_selection + * } + */ +static const struct imx327_mode lvds_supported_modes[] = { { - .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, - .width = 1920, - .height = 1080, + .bus_fmt = MEDIA_BUS_FMT_SRGGB10_1X10, + .width = 1948, + .height = 1110, .max_fps = { .numerator = 10000, - .denominator = 500000, + .denominator = 250000, }, - .exp_def = 0x0002, + .exp_def = 0x03fe, + .hts_def = 0x1130, + .vts_def = 0x0546, + .reg_list = imx327_linear_1920x1080_lvds_regs, + .hdr_mode = NO_HDR, + .lvds_cfg = { + .mode = LS_FIRST, + .frm_sync_code[LVDS_CODE_GRP_LINEAR] = { + .odd_sync_code = { + .act = { + .sav = 0x200, + .eav = 0x274, + }, + .blk = { + .sav = 0x2ac, + .eav = 0x2d8, + }, + }, + }, + }, + }, { + .bus_fmt = MEDIA_BUS_FMT_SRGGB10_1X10, + .width = 1948, + .height = 1098, + .max_fps = { + .numerator = 10000, + .denominator = 250000, + }, + .exp_def = 0x0473, .hts_def = 0x07ec, - .vts_def = 0x05b8, - .reg_list = imx327_hdr_1920x1080_regs, - } + .vts_def = 0x05b8 * 2, + .reg_list = imx327_hdr2_1920x1080_lvds_regs, + .hdr_mode = HDR_X2, + .lvds_cfg = { + .mode = SONY_DOL_HDR_1, + .frm_sync_code[LVDS_CODE_GRP_LONG] = { + .odd_sync_code = { + .act = { + .sav = 0x001, + .eav = 0x075, + }, + .blk = { + .sav = 0x0ac, + .eav = 0x0d8, + }, + }, + .even_sync_code = { + .act = { + .sav = 0x101, + .eav = 0x175, + }, + .blk = { + .sav = 0x1ac, + .eav = 0x1d8, + }, + }, + }, + .frm_sync_code[LVDS_CODE_GRP_SHORT] = { + .odd_sync_code = { + .act = { + .sav = 0x002, + .eav = 0x076, + }, + .blk = { + .sav = 0x0ac, + .eav = 0x0d8, + }, + }, + .even_sync_code = { + .act = { + .sav = 0x102, + .eav = 0x176, + }, + .blk = { + .sav = 0x1ac, + .eav = 0x1d8, + }, + }, + }, + }, + }, }; -static const struct imx327_mode supported_linear_modes[] = { +static const struct imx327_mode mipi_supported_modes[] = { { - .bus_fmt = MEDIA_BUS_FMT_SRGGB12_1X12, - .width = 1920, - .height = 1080, + .bus_fmt = MEDIA_BUS_FMT_SRGGB10_1X10, + .width = 1948, + .height = 1097, .max_fps = { .numerator = 10000, - .denominator = 300000, + .denominator = 250000, }, - .exp_def = 0x0300, + .exp_def = 0x03fe, .hts_def = 0x1130, - .vts_def = 0x0465, - .reg_list = imx327_1920x1080_regs, + .vts_def = 0x0546, + .reg_list = imx327_linear_1920x1080_mipi_regs, + .hdr_mode = NO_HDR, + }, { + .bus_fmt = MEDIA_BUS_FMT_SRGGB10_1X10, + .width = 1952, + .height = 1089, + .max_fps = { + .numerator = 10000, + .denominator = 250000, + }, + .exp_def = 0x0473, + .hts_def = 0x07ec, + .vts_def = 0x05b8 * 2, + .reg_list = imx327_hdr2_1920x1080_mipi_regs, + .hdr_mode = HDR_X2, }, }; static const s64 link_freq_menu_items[] = { - IMX327_LINK_FREQ + IMX327_LINK_FREQ_111M, + IMX327_LINK_FREQ_222M }; +#ifdef USED_TEST_PATTERN static const char * const imx327_test_pattern_menu[] = { "Disabled", - "Vertical Color Bar Type 1", - "Vertical Color Bar Type 2", - "Vertical Color Bar Type 3", - "Vertical Color Bar Type 4" + "Bar Type 1", + "Bar Type 2", + "Bar Type 3", + "Bar Type 4", + "Bar Type 5", + "Bar Type 6", + "Bar Type 7", + "Bar Type 8", + "Bar Type 9", + "Bar Type 10", + "Bar Type 11", + "Bar Type 12", + "Bar Type 13", + "Bar Type 14", + "Bar Type 15" }; +#endif /* Write registers up to 4 at a time */ static int imx327_write_reg(struct i2c_client *client, u16 reg, - int len, u32 val) + u32 len, u32 val) { u32 buf_i, val_i; u8 buf[6]; @@ -411,24 +663,24 @@ static int imx327_write_array(struct i2c_client *client, for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++) if (unlikely(regs[i].addr == REG_DELAY)) - usleep_range(regs[i].val, regs[i].val * 2); + usleep_range(regs[i].val * 1000, regs[i].val * 2000); else ret = imx327_write_reg(client, regs[i].addr, - IMX327_REG_VALUE_08BIT, - regs[i].val); + IMX327_REG_VALUE_08BIT, + regs[i].val); return ret; } /* Read registers up to 4 at a time */ -static int imx327_read_reg(struct i2c_client *client, u16 reg, unsigned int len, - u32 *val) +static int imx327_read_reg(struct i2c_client *client, u16 reg, + unsigned int len, u32 *val) { struct i2c_msg msgs[2]; u8 *data_be_p; __be32 data_be = 0; __be16 reg_addr_be = cpu_to_be16(reg); - int ret, i; + int ret; if (len > 4 || !len) return -EINVAL; @@ -446,49 +698,14 @@ static int imx327_read_reg(struct i2c_client *client, u16 reg, unsigned int len, msgs[1].len = len; msgs[1].buf = &data_be_p[4 - len]; - for (i = 0; i < 3; i++) { - ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (ret == ARRAY_SIZE(msgs)) - break; - } - if (ret != ARRAY_SIZE(msgs) && i == 3) + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) return -EIO; *val = be32_to_cpu(data_be); - return 0; } -static int imx327_get_reso_dist(const struct imx327_mode *mode, - struct v4l2_mbus_framefmt *framefmt) -{ - return abs(mode->width - framefmt->width) + - abs(mode->height - framefmt->height); -} - -static const struct imx327_mode * -imx327_find_best_fit(struct v4l2_subdev *sd, - struct v4l2_subdev_format *fmt) -{ - struct imx327 *imx327 = to_imx327(sd); - struct v4l2_mbus_framefmt *framefmt = &fmt->format; - int dist; - int cur_best_fit = 0; - int cur_best_fit_dist = -1; - unsigned int i; - - for (i = 0; i < imx327->support_modes_num; i++) { - dist = imx327_get_reso_dist(&imx327->support_modes[i], - framefmt); - if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) { - cur_best_fit_dist = dist; - cur_best_fit = i; - } - } - - return &imx327->support_modes[cur_best_fit]; -} - static int imx327_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) @@ -496,10 +713,15 @@ static int imx327_set_fmt(struct v4l2_subdev *sd, struct imx327 *imx327 = to_imx327(sd); const struct imx327_mode *mode; s64 h_blank, vblank_def; + s32 dst_link_freq = 0; + s64 dst_pixel_rate = 0; mutex_lock(&imx327->mutex); - mode = imx327_find_best_fit(sd, fmt); + mode = v4l2_find_nearest_size(imx327->support_modes, + imx327->support_modes_num, + width, height, + fmt->format.width, fmt->format.height); fmt->format.code = mode->bus_fmt; fmt->format.width = mode->width; fmt->format.height = mode->height; @@ -520,6 +742,18 @@ static int imx327_set_fmt(struct v4l2_subdev *sd, __v4l2_ctrl_modify_range(imx327->vblank, vblank_def, IMX327_VTS_MAX - mode->height, 1, vblank_def); + if (imx327->cur_mode->hdr_mode == NO_HDR) { + dst_link_freq = 0; + dst_pixel_rate = IMX327_LINK_FREQ_111M; + } else { + dst_link_freq = 1; + dst_pixel_rate = IMX327_LINK_FREQ_222M; + } + __v4l2_ctrl_s_ctrl_int64(imx327->pixel_rate, + dst_pixel_rate); + __v4l2_ctrl_s_ctrl(imx327->link_freq, + dst_link_freq); + imx327->cur_vts = mode->vts_def; } mutex_unlock(&imx327->mutex); @@ -557,9 +791,11 @@ static int imx327_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_mbus_code_enum *code) { struct imx327 *imx327 = to_imx327(sd); + const struct imx327_mode *mode = imx327->cur_mode; + if (code->index != 0) return -EINVAL; - code->code = imx327->support_modes[0].bus_fmt; + code->code = mode->bus_fmt; return 0; } @@ -573,7 +809,7 @@ static int imx327_enum_frame_sizes(struct v4l2_subdev *sd, if (fse->index >= imx327->support_modes_num) return -EINVAL; - if (fse->code != imx327->support_modes[0].bus_fmt) + if (fse->code != imx327->support_modes[fse->index].bus_fmt) return -EINVAL; fse->min_width = imx327->support_modes[fse->index].width; @@ -584,20 +820,42 @@ static int imx327_enum_frame_sizes(struct v4l2_subdev *sd, return 0; } +#ifdef USED_TEST_PATTERN static int imx327_enable_test_pattern(struct imx327 *imx327, u32 pattern) { - u32 val; + u32 val = 0; - if (pattern) - val = (pattern - 1) | IMX327_TEST_PATTERN_ENABLE; - else - val = IMX327_TEST_PATTERN_DISABLE; - - return imx327_write_reg(imx327->client, - IMX327_REG_TEST_PATTERN, + imx327_read_reg(imx327->client, + IMX327_REG_TEST_PATTERN, + IMX327_REG_VALUE_08BIT, + &val); + if (pattern) { + val = ((pattern - 1) << 4) | IMX327_TEST_PATTERN_ENABLE; + imx327_write_reg(imx327->client, + 0x300a, IMX327_REG_VALUE_08BIT, - val); + 0x00); + imx327_write_reg(imx327->client, + 0x300e, + IMX327_REG_VALUE_08BIT, + 0x00); + } else { + val &= ~IMX327_TEST_PATTERN_ENABLE; + imx327_write_reg(imx327->client, + 0x300a, + IMX327_REG_VALUE_08BIT, + 0x3c); + imx327_write_reg(imx327->client, + 0x300e, + IMX327_REG_VALUE_08BIT, + 0x01); + } + return imx327_write_reg(imx327->client, + IMX327_REG_TEST_PATTERN, + IMX327_REG_VALUE_08BIT, + val); } +#endif static int imx327_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *fi) @@ -612,6 +870,124 @@ static int imx327_g_frame_interval(struct v4l2_subdev *sd, return 0; } +static int imx327_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *config) +{ + struct imx327 *imx327 = to_imx327(sd); + u32 val = 0; + + val = 1 << (IMX327_4LANES - 1) | + V4L2_MBUS_CSI2_CHANNEL_0 | + V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; + if (imx327->bus_cfg.bus_type == 3) + config->type = V4L2_MBUS_CCP2; + else + config->type = V4L2_MBUS_CSI2; + config->flags = val; + + return 0; +} + +static int imx327_set_hdrae(struct imx327 *imx327, + struct preisp_hdrae_exp_s *ae) +{ + u32 l_exp_time, m_exp_time, s_exp_time; + u32 l_gain, m_gain, s_gain; + u32 shs1, shs2, rhs1; + u32 gain_switch = 0; + int ret = 0; + u8 cg_mode = 0; + u32 fsc = imx327->cur_vts;//The HDR mode vts is double by default to workaround T-line + + if (!imx327->has_init_exp && !imx327->streaming) { + imx327->init_hdrae_exp = *ae; + imx327->has_init_exp = true; + dev_dbg(&imx327->client->dev, "imx327 don't stream, record exp for hdr!\n"); + return ret; + } + + l_exp_time = ae->long_exp_reg; + m_exp_time = ae->middle_exp_reg; + s_exp_time = ae->short_exp_reg; + l_gain = ae->long_gain_reg; + m_gain = ae->middle_gain_reg; + s_gain = ae->short_gain_reg; + + if (imx327->cur_mode->hdr_mode == HDR_X2) { + //2 stagger + l_gain = m_gain; + l_exp_time = m_exp_time; + cg_mode = ae->middle_cg_mode; + } + dev_dbg(&imx327->client->dev, + "rev exp req: L_time=%d, gain=%d, S_time=%d, gain=%d\n", + l_exp_time, l_gain, + s_exp_time, s_gain); + ret = imx327_read_reg(imx327->client, IMX327_GAIN_SWITCH_REG, + IMX327_REG_VALUE_08BIT, &gain_switch); + if (!g_isHCG && cg_mode == GAIN_MODE_HCG) { + gain_switch |= 0x0110; + g_isHCG = true; + } else if (g_isHCG && cg_mode == GAIN_MODE_LCG) { + gain_switch &= 0xef; + gain_switch |= 0x100; + g_isHCG = false; + } + + //long exposure and short exposure + rhs1 = 0xe1; + shs1 = rhs1 - s_exp_time - 1; + shs2 = fsc - l_exp_time - 1; + if (shs1 < 2) + shs1 = 2; + if (shs2 < (rhs1 + 2)) + shs2 = rhs1 + 2; + else if (shs2 > (fsc - 2)) + shs2 = fsc - 2; + + ret |= imx327_write_reg(imx327->client, IMX327_REG_SHS1_L, + IMX327_REG_VALUE_08BIT, + IMX327_FETCH_LOW_BYTE_EXP(shs1)); + ret |= imx327_write_reg(imx327->client, IMX327_REG_SHS1_M, + IMX327_REG_VALUE_08BIT, + IMX327_FETCH_MID_BYTE_EXP(shs1)); + ret |= imx327_write_reg(imx327->client, IMX327_REG_SHS1_H, + IMX327_REG_VALUE_08BIT, + IMX327_FETCH_HIGH_BYTE_EXP(shs1)); + ret |= imx327_write_reg(imx327->client, IMX327_REG_SHS2_L, + IMX327_REG_VALUE_08BIT, + IMX327_FETCH_LOW_BYTE_EXP(shs2)); + ret |= imx327_write_reg(imx327->client, IMX327_REG_SHS2_M, + IMX327_REG_VALUE_08BIT, + IMX327_FETCH_MID_BYTE_EXP(shs2)); + ret |= imx327_write_reg(imx327->client, IMX327_REG_SHS2_H, + IMX327_REG_VALUE_08BIT, + IMX327_FETCH_HIGH_BYTE_EXP(shs2)); + + ret |= imx327_write_reg(imx327->client, IMX327_REG_LF_GAIN, + IMX327_REG_VALUE_08BIT, + l_gain); + ret |= imx327_write_reg(imx327->client, IMX327_REG_SF_GAIN, + IMX327_REG_VALUE_08BIT, + s_gain); + if (gain_switch & 0x100) { + ret |= imx327_write_reg(imx327->client, + IMX327_GROUP_HOLD_REG, + IMX327_REG_VALUE_08BIT, + IMX327_GROUP_HOLD_START); + ret |= imx327_write_reg(imx327->client, IMX327_GAIN_SWITCH_REG, + IMX327_REG_VALUE_08BIT, gain_switch); + ret |= imx327_write_reg(imx327->client, + IMX327_GROUP_HOLD_REG, + IMX327_REG_VALUE_08BIT, + IMX327_GROUP_HOLD_END); + } + dev_dbg(&imx327->client->dev, + "set l_gain:0x%x s_gain:0x%x shs2:0x%x shs1:0x%x\n", + l_gain, s_gain, shs2, shs1); + return ret; +} + static void imx327_get_module_inf(struct imx327 *imx327, struct rkmodule_inf *inf) { @@ -622,99 +998,160 @@ static void imx327_get_module_inf(struct imx327 *imx327, strlcpy(inf->base.lens, imx327->len_name, sizeof(inf->base.lens)); } +static int imx327_set_conversion_gain(struct imx327 *imx327, u32 *cg) +{ + int ret = 0; + struct i2c_client *client = imx327->client; + int cur_cg = *cg; + u32 gain_switch = 0; + + ret = imx327_read_reg(client, + IMX327_GAIN_SWITCH_REG, + IMX327_REG_VALUE_08BIT, + &gain_switch); + if (g_isHCG && cur_cg == GAIN_MODE_LCG) { + gain_switch &= 0xef; + gain_switch |= 0x0100; + g_isHCG = false; + } else if (!g_isHCG && cur_cg == GAIN_MODE_HCG) { + gain_switch |= 0x0110; + g_isHCG = true; + } + + if (gain_switch & 0x100) { + ret |= imx327_write_reg(client, + IMX327_GROUP_HOLD_REG, + IMX327_REG_VALUE_08BIT, + IMX327_GROUP_HOLD_START); + ret |= imx327_write_reg(client, + IMX327_GAIN_SWITCH_REG, + IMX327_REG_VALUE_08BIT, + gain_switch & 0xff); + ret |= imx327_write_reg(client, + IMX327_GROUP_HOLD_REG, + IMX327_REG_VALUE_08BIT, + IMX327_GROUP_HOLD_END); + } + + return ret; +} + +#define USED_SYS_DEBUG +#ifdef USED_SYS_DEBUG +//ag: echo 0 > /sys/devices/platform/ff510000.i2c/i2c-1/1-0037/cam_s_cg +static ssize_t set_conversion_gain_status(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx327 *imx327 = to_imx327(sd); + int status = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &status); + if (!ret && status >= 0 && status < 2) + imx327_set_conversion_gain(imx327, &status); + else + dev_err(dev, "input 0 for LCG, 1 for HCG, cur %d\n", status); + return count; +} + +static struct device_attribute attributes[] = { + __ATTR(cam_s_cg, S_IWUSR, NULL, set_conversion_gain_status), +}; + +static int add_sysfs_interfaces(struct device *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(attributes); i++) + if (device_create_file(dev, attributes + i)) + goto undo; + return 0; +undo: + for (i--; i >= 0 ; i--) + device_remove_file(dev, attributes + i); + dev_err(dev, "%s: failed to create sysfs interface\n", __func__); + return -ENODEV; +} +#endif + static long imx327_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { struct imx327 *imx327 = to_imx327(sd); - struct i2c_client *client = imx327->client; - struct preisp_hdrae_exp_s *hdrae_exp; + struct rkmodule_hdr_cfg *hdr; + struct rkmodule_lvds_cfg *lvds_cfg; + u32 i, h, w; long ret = 0; - u32 gain_switch = 0; - s32 l_gain, s_gain, shs1, fsc, shs2; + s64 dst_pixel_rate = 0; + s32 dst_link_freq = 0; switch (cmd) { - case PREISP_CMD_SET_HDRAE_EXP: - hdrae_exp = (struct preisp_hdrae_exp_s *)arg; - dev_info(&client->dev, - "rev exp req: L_time=%d, gain=%d, S_time=%d, gain=%d\n", - hdrae_exp->long_exp_reg, - hdrae_exp->long_gain_reg, - hdrae_exp->short_exp_reg, - hdrae_exp->short_gain_reg); - - //long gain and short gain - l_gain = hdrae_exp->long_gain_reg; - s_gain = hdrae_exp->short_gain_reg; - if (l_gain > 100) { - l_gain -= 27; //8.1db - s_gain = (s_gain < 27) ? 0 : (s_gain - 27); - if (!g_isHCG) { - gain_switch = 0x11; - g_isHCG = true; - } - } else if (l_gain < 44) { - if (g_isHCG) { - gain_switch = 0x1; - g_isHCG = false; - } - } else { - if (g_isHCG) { - l_gain -= 27; - s_gain = (s_gain < 27) ? 0 : (s_gain - 27); - } - } - imx327_write_reg(imx327->client, 0x3014, - IMX327_REG_VALUE_08BIT, l_gain); - imx327_write_reg(imx327->client, 0x30f2, - IMX327_REG_VALUE_08BIT, s_gain); - if (gain_switch) - imx327_write_reg(imx327->client, 0x3009, - IMX327_REG_VALUE_08BIT, gain_switch); - - //long exposure and short exposure - fsc = imx327->cur_mode->vts_def * 2; - shs1 = IMX327_RHS1 - hdrae_exp->short_exp_reg - 1; - shs2 = fsc - hdrae_exp->long_exp_reg - 1; - if (shs1 < 2) - shs1 = 2; - else if (shs1 > (IMX327_RHS1 - 2)) - shs1 = IMX327_RHS1 - 2; - if (shs2 < (IMX327_RHS1 + 2)) - shs2 = IMX327_RHS1 + 2; - else if (shs2 > (fsc - 2)) - shs2 = fsc - 2; - - imx327_write_reg(imx327->client, 0x3020, - IMX327_REG_VALUE_08BIT, - IMX327_FETCH_LOW_BYTE_EXP(shs1)); - imx327_write_reg(imx327->client, 0x3021, - IMX327_REG_VALUE_08BIT, - IMX327_FETCH_MID_BYTE_EXP(shs1)); - imx327_write_reg(imx327->client, 0x3022, - IMX327_REG_VALUE_08BIT, - IMX327_FETCH_HIGH_BYTE_EXP(shs1)); - - imx327_write_reg(imx327->client, 0x3024, - IMX327_REG_VALUE_08BIT, - IMX327_FETCH_LOW_BYTE_EXP(shs2)); - imx327_write_reg(imx327->client, 0x3025, - IMX327_REG_VALUE_08BIT, - IMX327_FETCH_MID_BYTE_EXP(shs2)); - imx327_write_reg(imx327->client, 0x3026, - IMX327_REG_VALUE_08BIT, - IMX327_FETCH_HIGH_BYTE_EXP(shs2)); - - dev_info(&client->dev, - "set l_gain:0x%x s_gain:0x%x shs2:0x%x shs1:0x%x\n", - l_gain, s_gain, shs2, shs1); - break; case RKMODULE_GET_MODULE_INFO: imx327_get_module_inf(imx327, (struct rkmodule_inf *)arg); break; + case PREISP_CMD_SET_HDRAE_EXP: + ret = imx327_set_hdrae(imx327, arg); + break; + case RKMODULE_GET_HDR_CFG: + hdr = (struct rkmodule_hdr_cfg *)arg; + if (imx327->cur_mode->hdr_mode == NO_HDR) + hdr->esp.mode = HDR_NORMAL_VC; + else + hdr->esp.mode = HDR_ID_CODE; + hdr->hdr_mode = imx327->cur_mode->hdr_mode; + break; + case RKMODULE_SET_HDR_CFG: + hdr = (struct rkmodule_hdr_cfg *)arg; + for (i = 0; i < imx327->support_modes_num; i++) { + if (imx327->support_modes[i].hdr_mode == hdr->hdr_mode) { + imx327->cur_mode = &imx327->support_modes[i]; + break; + } + } + if (i == imx327->support_modes_num) { + dev_err(&imx327->client->dev, + "not find hdr mode:%d config\n", + hdr->hdr_mode); + ret = -EINVAL; + } else { + w = imx327->cur_mode->hts_def - imx327->cur_mode->width; + h = imx327->cur_mode->vts_def - imx327->cur_mode->height; + __v4l2_ctrl_modify_range(imx327->hblank, w, w, 1, w); + __v4l2_ctrl_modify_range(imx327->vblank, h, + IMX327_VTS_MAX - imx327->cur_mode->height, + 1, h); + if (imx327->cur_mode->hdr_mode == NO_HDR) { + dst_link_freq = 0; + dst_pixel_rate = IMX327_PIXEL_RATE_NORMAL; + } else { + dst_link_freq = 1; + dst_pixel_rate = IMX327_PIXEL_RATE_HDR; + } + __v4l2_ctrl_s_ctrl_int64(imx327->pixel_rate, + dst_pixel_rate); + __v4l2_ctrl_s_ctrl(imx327->link_freq, + dst_link_freq); + imx327->cur_vts = imx327->cur_mode->vts_def; + } + break; + case RKMODULE_SET_CONVERSION_GAIN: + ret = imx327_set_conversion_gain(imx327, (u32 *)arg); + break; + case RKMODULE_GET_LVDS_CFG: + lvds_cfg = (struct rkmodule_lvds_cfg *)arg; + if (imx327->bus_cfg.bus_type == 3) + memcpy(lvds_cfg, &imx327->cur_mode->lvds_cfg, + sizeof(struct rkmodule_lvds_cfg)); + else + ret = -ENOIOCTLCMD; + break; default: ret = -ENOIOCTLCMD; break; } - return ret; } @@ -725,7 +1162,10 @@ static long imx327_compat_ioctl32(struct v4l2_subdev *sd, void __user *up = compat_ptr(arg); struct rkmodule_inf *inf; struct rkmodule_awb_cfg *cfg; + struct rkmodule_hdr_cfg *hdr; + struct preisp_hdrae_exp_s *hdrae; long ret; + u32 cg = 0; switch (cmd) { case RKMODULE_GET_MODULE_INFO: @@ -746,12 +1186,52 @@ static long imx327_compat_ioctl32(struct v4l2_subdev *sd, ret = -ENOMEM; return ret; } - ret = copy_from_user(cfg, up, sizeof(*cfg)); if (!ret) ret = imx327_ioctl(sd, cmd, cfg); kfree(cfg); break; + case RKMODULE_GET_HDR_CFG: + hdr = kzalloc(sizeof(*hdr), GFP_KERNEL); + if (!hdr) { + ret = -ENOMEM; + return ret; + } + + ret = imx327_ioctl(sd, cmd, hdr); + if (!ret) + ret = copy_to_user(up, hdr, sizeof(*hdr)); + kfree(hdr); + break; + case RKMODULE_SET_HDR_CFG: + hdr = kzalloc(sizeof(*hdr), GFP_KERNEL); + if (!hdr) { + ret = -ENOMEM; + return ret; + } + + ret = copy_from_user(hdr, up, sizeof(*hdr)); + if (!ret) + ret = imx327_ioctl(sd, cmd, hdr); + kfree(hdr); + break; + case PREISP_CMD_SET_HDRAE_EXP: + hdrae = kzalloc(sizeof(*hdrae), GFP_KERNEL); + if (!hdrae) { + ret = -ENOMEM; + return ret; + } + + ret = copy_from_user(hdrae, up, sizeof(*hdrae)); + if (!ret) + ret = imx327_ioctl(sd, cmd, hdrae); + kfree(hdrae); + break; + case RKMODULE_SET_CONVERSION_GAIN: + ret = copy_from_user(&cg, up, sizeof(cg)); + if (!ret) + ret = imx327_ioctl(sd, cmd, &cg); + break; default: ret = -ENOIOCTLCMD; break; @@ -761,6 +1241,26 @@ static long imx327_compat_ioctl32(struct v4l2_subdev *sd, } #endif +static int imx327_init_conversion_gain(struct imx327 *imx327) +{ + int ret = 0; + struct i2c_client *client = imx327->client; + u32 val = 0; + + ret = imx327_read_reg(client, + IMX327_GAIN_SWITCH_REG, + IMX327_REG_VALUE_08BIT, + &val); + val &= 0xef; + ret = imx327_write_reg(client, + IMX327_GAIN_SWITCH_REG, + IMX327_REG_VALUE_08BIT, + val); + if (!ret) + g_isHCG = false; + return ret; +} + static int __imx327_start_stream(struct imx327 *imx327) { int ret; @@ -768,22 +1268,34 @@ static int __imx327_start_stream(struct imx327 *imx327) ret = imx327_write_array(imx327->client, imx327->cur_mode->reg_list); if (ret) return ret; - - /* In case these controls are set before streaming */ - mutex_unlock(&imx327->mutex); - ret = v4l2_ctrl_handler_setup(&imx327->ctrl_handler); - mutex_lock(&imx327->mutex); + ret = imx327_init_conversion_gain(imx327); if (ret) return ret; + /* In case these controls are set before streaming */ + ret = __v4l2_ctrl_handler_setup(&imx327->ctrl_handler); + if (imx327->has_init_exp && imx327->cur_mode->hdr_mode != NO_HDR) { + ret = imx327_ioctl(&imx327->subdev, PREISP_CMD_SET_HDRAE_EXP, + &imx327->init_hdrae_exp); + if (ret) { + dev_err(&imx327->client->dev, + "init exp fail in hdr mode\n"); + return ret; + } + } - return imx327_write_reg(imx327->client, IMX327_REG_CTRL_MODE, - IMX327_REG_VALUE_08BIT, 0); + ret = imx327_write_reg(imx327->client, + IMX327_REG_CTRL_MODE, + IMX327_REG_VALUE_08BIT, + 0); + return ret; } static int __imx327_stop_stream(struct imx327 *imx327) { - return imx327_write_reg(imx327->client, IMX327_REG_CTRL_MODE, - IMX327_REG_VALUE_08BIT, 1); + return imx327_write_reg(imx327->client, + IMX327_REG_CTRL_MODE, + IMX327_REG_VALUE_08BIT, + 1); } static int imx327_s_stream(struct v4l2_subdev *sd, int on) @@ -842,6 +1354,13 @@ static int imx327_s_power(struct v4l2_subdev *sd, int on) goto unlock_and_return; } + ret = imx327_write_array(imx327->client, imx327_global_regs); + if (ret) { + v4l2_err(sd, "could not set init registers\n"); + pm_runtime_put_noidle(&client->dev); + goto unlock_and_return; + } + imx327->power_on = true; } else { pm_runtime_put(&client->dev); @@ -866,21 +1385,26 @@ static int __imx327_power_on(struct imx327 *imx327) u32 delay_us; struct device *dev = &imx327->client->dev; - ret = clk_set_rate(imx327->xvclk, IMX327_XVCLK_FREQ); - if (ret < 0) { - dev_err(dev, "Failed to set xvclk rate (24MHz)\n"); - return ret; + if (!IS_ERR_OR_NULL(imx327->pins_default)) { + ret = pinctrl_select_state(imx327->pinctrl, + imx327->pins_default); + if (ret < 0) + dev_err(dev, "could not set pins\n"); } + + ret = clk_set_rate(imx327->xvclk, IMX327_XVCLK_FREQ); + if (ret < 0) + dev_warn(dev, "Failed to set xvclk rate (37.125M Hz)\n"); + if (clk_get_rate(imx327->xvclk) != IMX327_XVCLK_FREQ) - dev_warn(dev, "xvclk mismatched, modes are based on 37.125MHz\n"); + dev_warn(dev, "xvclk mismatched,based on 24M Hz\n"); + ret = clk_prepare_enable(imx327->xvclk); if (ret < 0) { dev_err(dev, "Failed to enable xvclk\n"); return ret; } - if (!IS_ERR(imx327->reset_gpio)) - gpiod_set_value_cansleep(imx327->reset_gpio, 0); ret = regulator_bulk_enable(IMX327_NUM_SUPPLIES, imx327->supplies); if (ret < 0) { @@ -888,17 +1412,19 @@ static int __imx327_power_on(struct imx327 *imx327) goto disable_clk; } + if (!IS_ERR(imx327->reset_gpio)) + gpiod_set_value_cansleep(imx327->reset_gpio, 0); + usleep_range(500, 1000); if (!IS_ERR(imx327->reset_gpio)) gpiod_set_value_cansleep(imx327->reset_gpio, 1); - usleep_range(500, 1000); if (!IS_ERR(imx327->pwdn_gpio)) gpiod_set_value_cansleep(imx327->pwdn_gpio, 1); /* 8192 cycles prior to first SCCB transaction */ delay_us = imx327_cal_delay(8192); usleep_range(delay_us, delay_us * 2); - + usleep_range(5000, 10000); return 0; disable_clk: @@ -909,11 +1435,20 @@ disable_clk: static void __imx327_power_off(struct imx327 *imx327) { + int ret; + struct device *dev = &imx327->client->dev; + if (!IS_ERR(imx327->pwdn_gpio)) gpiod_set_value_cansleep(imx327->pwdn_gpio, 0); clk_disable_unprepare(imx327->xvclk); if (!IS_ERR(imx327->reset_gpio)) gpiod_set_value_cansleep(imx327->reset_gpio, 0); + if (!IS_ERR_OR_NULL(imx327->pins_sleep)) { + ret = pinctrl_select_state(imx327->pinctrl, + imx327->pins_sleep); + if (ret < 0) + dev_dbg(dev, "could not set pins\n"); + } regulator_bulk_disable(IMX327_NUM_SUPPLIES, imx327->supplies); } @@ -968,15 +1503,51 @@ static int imx327_enum_frame_interval(struct v4l2_subdev *sd, if (fie->index >= imx327->support_modes_num) return -EINVAL; - if (fie->code != imx327->support_modes[fie->index].bus_fmt) - return -EINVAL; - + fie->code = imx327->support_modes[fie->index].bus_fmt; fie->width = imx327->support_modes[fie->index].width; fie->height = imx327->support_modes[fie->index].height; fie->interval = imx327->support_modes[fie->index].max_fps; + fie->reserved[0] = imx327->support_modes[fie->index].hdr_mode; return 0; } +#define CROP_START(SRC, DST) (((SRC) - (DST)) / 2 / 4 * 4) +#define DST_WIDTH 1920 +#define DST_HEIGHT 1080 + +/* + * The resolution of the driver configuration needs to be exactly + * the same as the current output resolution of the sensor, + * the input width of the isp needs to be 16 aligned, + * the input height of the isp needs to be 8 aligned. + * Can be cropped to standard resolution by this function, + * otherwise it will crop out strange resolution according + * to the alignment rules. + */ + +static int imx327_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct imx327 *imx327 = to_imx327(sd); + + if (sel->target == V4L2_SEL_TGT_CROP_BOUNDS) { + sel->r.left = CROP_START(imx327->cur_mode->width, DST_WIDTH); + sel->r.width = DST_WIDTH; + if (imx327->bus_cfg.bus_type == 3) { + if (imx327->cur_mode->hdr_mode == NO_HDR) + sel->r.top = 21; + else + sel->r.top = 13; + } else { + sel->r.top = CROP_START(imx327->cur_mode->height, DST_HEIGHT); + } + sel->r.height = DST_HEIGHT; + return 0; + } + return -EINVAL; +} + static const struct dev_pm_ops imx327_pm_ops = { SET_RUNTIME_PM_OPS(imx327_runtime_suspend, imx327_runtime_resume, NULL) @@ -999,6 +1570,7 @@ static const struct v4l2_subdev_core_ops imx327_core_ops = { static const struct v4l2_subdev_video_ops imx327_video_ops = { .s_stream = imx327_s_stream, .g_frame_interval = imx327_g_frame_interval, + .g_mbus_config = imx327_g_mbus_config, }; static const struct v4l2_subdev_pad_ops imx327_pad_ops = { @@ -1007,6 +1579,7 @@ static const struct v4l2_subdev_pad_ops imx327_pad_ops = { .enum_frame_interval = imx327_enum_frame_interval, .get_fmt = imx327_get_fmt, .set_fmt = imx327_set_fmt, + .get_selection = imx327_get_selection, }; static const struct v4l2_subdev_ops imx327_subdev_ops = { @@ -1022,6 +1595,9 @@ static int imx327_set_ctrl(struct v4l2_ctrl *ctrl) struct i2c_client *client = imx327->client; s64 max; int ret = 0; + u32 shs1 = 0; + u32 vts = 0; + u32 val = 0; /* Propagate change of current control to all related controls */ switch (ctrl->id) { @@ -1040,42 +1616,86 @@ static int imx327_set_ctrl(struct v4l2_ctrl *ctrl) switch (ctrl->id) { case V4L2_CID_EXPOSURE: - /* 4 least significant bits of expsoure are fractional part */ + shs1 = imx327->cur_vts - ctrl->val; ret = imx327_write_reg(imx327->client, - IMX327_REG_EXPOSURE_H, - IMX327_REG_VALUE_08BIT, - IMX327_FETCH_HIGH_BYTE_EXP(ctrl->val)); + IMX327_REG_SHS1_H, + IMX327_REG_VALUE_08BIT, + IMX327_FETCH_HIGH_BYTE_EXP(shs1)); ret |= imx327_write_reg(imx327->client, - IMX327_REG_EXPOSURE_M, - IMX327_REG_VALUE_08BIT, - IMX327_FETCH_MID_BYTE_EXP(ctrl->val)); + IMX327_REG_SHS1_M, + IMX327_REG_VALUE_08BIT, + IMX327_FETCH_MID_BYTE_EXP(shs1)); ret |= imx327_write_reg(imx327->client, - IMX327_REG_EXPOSURE_L, - IMX327_REG_VALUE_08BIT, - IMX327_FETCH_LOW_BYTE_EXP(ctrl->val)); + IMX327_REG_SHS1_L, + IMX327_REG_VALUE_08BIT, + IMX327_FETCH_LOW_BYTE_EXP(shs1)); + dev_dbg(&client->dev, "set exposure 0x%x, cur_vts 0x%x,shs1 0x%x\n", + ctrl->val, imx327->cur_vts, shs1); break; case V4L2_CID_ANALOGUE_GAIN: ret = imx327_write_reg(imx327->client, - IMX327_REG_GAIN, - IMX327_REG_VALUE_08BIT, - ctrl->val); + IMX327_REG_LF_GAIN, + IMX327_REG_VALUE_08BIT, + ctrl->val); + dev_dbg(&client->dev, "set analog gain 0x%x\n", + ctrl->val); break; case V4L2_CID_VBLANK: + vts = ctrl->val + imx327->cur_mode->height; + imx327->cur_vts = vts; + if (imx327->cur_mode->hdr_mode == HDR_X2) + vts /= 2; ret = imx327_write_reg(imx327->client, - IMX327_REG_VTS_H, - IMX327_REG_VALUE_08BIT, - IMX327_FETCH_HIGH_BYTE_VTS(ctrl->val + imx327->cur_mode->height)); + IMX327_REG_VTS_H, + IMX327_REG_VALUE_08BIT, + IMX327_FETCH_HIGH_BYTE_VTS(vts)); ret |= imx327_write_reg(imx327->client, - IMX327_REG_VTS_M, - IMX327_REG_VALUE_08BIT, - IMX327_FETCH_MID_BYTE_VTS(ctrl->val + imx327->cur_mode->height)); + IMX327_REG_VTS_M, + IMX327_REG_VALUE_08BIT, + IMX327_FETCH_MID_BYTE_VTS(vts)); ret |= imx327_write_reg(imx327->client, - IMX327_REG_VTS_L, - IMX327_REG_VALUE_08BIT, - IMX327_FETCH_LOW_BYTE_VTS(ctrl->val + imx327->cur_mode->height)); + IMX327_REG_VTS_L, + IMX327_REG_VALUE_08BIT, + IMX327_FETCH_LOW_BYTE_VTS(vts)); + dev_dbg(&client->dev, "set vts 0x%x\n", + vts); break; case V4L2_CID_TEST_PATTERN: +#ifdef USED_TEST_PATTERN ret = imx327_enable_test_pattern(imx327, ctrl->val); +#endif + break; + case V4L2_CID_HFLIP: + ret = imx327_read_reg(client, + IMX327_FLIP_REG, + IMX327_REG_VALUE_08BIT, + &val); + if (ctrl->val) + val |= MIRROR_BIT_MASK; + else + val &= ~MIRROR_BIT_MASK; + ret |= imx327_write_reg(client, + IMX327_FLIP_REG, + IMX327_REG_VALUE_08BIT, + val); + if (ret == 0) + imx327->flip = val; + break; + case V4L2_CID_VFLIP: + ret = imx327_read_reg(client, + IMX327_FLIP_REG, + IMX327_REG_VALUE_08BIT, + &val); + if (ctrl->val) + val |= FLIP_BIT_MASK; + else + val &= ~FLIP_BIT_MASK; + ret |= imx327_write_reg(client, + IMX327_FLIP_REG, + IMX327_REG_VALUE_08BIT, + val); + if (ret == 0) + imx327->flip = val; break; default: dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n", @@ -1096,45 +1716,50 @@ static int imx327_initialize_controls(struct imx327 *imx327) { const struct imx327_mode *mode; struct v4l2_ctrl_handler *handler; - struct v4l2_ctrl *ctrl; s64 exposure_max, vblank_def; u32 h_blank; int ret; + s32 dst_link_freq = 0; + s64 dst_pixel_rate = 0; handler = &imx327->ctrl_handler; mode = imx327->cur_mode; - ret = v4l2_ctrl_handler_init(handler, 8); + ret = v4l2_ctrl_handler_init(handler, 9); if (ret) return ret; handler->lock = &imx327->mutex; - ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, - 0, 0, link_freq_menu_items); - if (ctrl) - ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + imx327->link_freq = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, + 1, 0, link_freq_menu_items); - if (imx327->has_devnode) { - v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, - 0, IMX327_PIXEL_RATE, 1, IMX327_PIXEL_RATE); + if (imx327->cur_mode->hdr_mode == NO_HDR) { + dst_link_freq = 0; + dst_pixel_rate = IMX327_PIXEL_RATE_NORMAL; } else { - v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, - 0, IMX327_PIXEL_HDR_RATE, - 1, IMX327_PIXEL_HDR_RATE); + dst_link_freq = 1; + dst_pixel_rate = IMX327_PIXEL_RATE_HDR; } + __v4l2_ctrl_s_ctrl(imx327->link_freq, + dst_link_freq); + imx327->pixel_rate = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, + 0, IMX327_PIXEL_RATE_HDR, 1, dst_pixel_rate); h_blank = mode->hts_def - mode->width; + imx327->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK, h_blank, h_blank, 1, h_blank); if (imx327->hblank) imx327->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; vblank_def = mode->vts_def - mode->height; + imx327->cur_vts = mode->vts_def; imx327->vblank = v4l2_ctrl_new_std(handler, &imx327_ctrl_ops, V4L2_CID_VBLANK, vblank_def, IMX327_VTS_MAX - mode->height, 1, vblank_def); exposure_max = mode->vts_def - 4; + imx327->exposure = v4l2_ctrl_new_std(handler, &imx327_ctrl_ops, V4L2_CID_EXPOSURE, IMX327_EXPOSURE_MIN, exposure_max, IMX327_EXPOSURE_STEP, @@ -1145,10 +1770,18 @@ static int imx327_initialize_controls(struct imx327 *imx327) IMX327_GAIN_MAX, IMX327_GAIN_STEP, IMX327_GAIN_DEFAULT); +#ifdef USED_TEST_PATTERN imx327->test_pattern = v4l2_ctrl_new_std_menu_items(handler, &imx327_ctrl_ops, V4L2_CID_TEST_PATTERN, ARRAY_SIZE(imx327_test_pattern_menu) - 1, 0, 0, imx327_test_pattern_menu); +#endif + imx327->h_flip = v4l2_ctrl_new_std(handler, &imx327_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + + imx327->v_flip = v4l2_ctrl_new_std(handler, &imx327_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + imx327->flip = 0; if (handler->error) { ret = handler->error; dev_err(&imx327->client->dev, @@ -1157,6 +1790,7 @@ static int imx327_initialize_controls(struct imx327 *imx327) } imx327->subdev.ctrl_handler = handler; + imx327->has_init_exp = false; return 0; @@ -1167,43 +1801,19 @@ err_free_handler: } static int imx327_check_sensor_id(struct imx327 *imx327, - struct i2c_client *client) + struct i2c_client *client) { struct device *dev = &imx327->client->dev; u32 id = 0; int ret; ret = imx327_read_reg(client, IMX327_REG_CHIP_ID, - IMX327_REG_VALUE_08BIT, &id); + IMX327_REG_VALUE_08BIT, &id); + if (id != CHIP_ID) { dev_err(dev, "Unexpected sensor id(%06x), ret(%d)\n", id, ret); - return -ENODEV; - } - - dev_info(dev, "Detected imx327 id:%06x\n", CHIP_ID); - - return 0; -} - -static int imx327_check_remote_dev(struct imx327 *imx327) -{ - struct device *dev = &imx327->client->dev; - struct device_node *parent = dev->of_node; - struct device_node *remote = NULL; - int ret = 0; - - imx327->has_devnode = true; - remote = of_graph_get_remote_node(parent, 0, 0); - if (!remote) { - dev_err(dev, "Invalid remote device!\n"); return -EINVAL; } - - if (strstr(of_node_full_name(remote), "spi_rk1608")) - imx327->has_devnode = false; - - of_node_put(remote); - return ret; } @@ -1220,7 +1830,7 @@ static int imx327_configure_regulators(struct imx327 *imx327) } static int imx327_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { struct device *dev = &client->dev; struct device_node *node = dev->of_node; @@ -1228,11 +1838,12 @@ static int imx327_probe(struct i2c_client *client, struct v4l2_subdev *sd; char facing[2]; int ret; + struct device_node *endpoint; dev_info(dev, "driver version: %02x.%02x.%02x", - DRIVER_VERSION >> 16, - (DRIVER_VERSION & 0xff00) >> 8, - DRIVER_VERSION & 0x00ff); + DRIVER_VERSION >> 16, + (DRIVER_VERSION & 0xff00) >> 8, + DRIVER_VERSION & 0x00ff); imx327 = devm_kzalloc(dev, sizeof(*imx327), GFP_KERNEL); if (!imx327) @@ -1250,7 +1861,21 @@ static int imx327_probe(struct i2c_client *client, dev_err(dev, "could not get module information!\n"); return -EINVAL; } + 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), + &imx327->bus_cfg); + if (imx327->bus_cfg.bus_type == 3) { + imx327->support_modes = lvds_supported_modes; + imx327->support_modes_num = ARRAY_SIZE(lvds_supported_modes); + } else { + imx327->support_modes = mipi_supported_modes; + imx327->support_modes_num = ARRAY_SIZE(mipi_supported_modes); + } imx327->client = client; imx327->cur_mode = &imx327->support_modes[0]; @@ -1274,22 +1899,25 @@ static int imx327_probe(struct i2c_client *client, return ret; } + imx327->pinctrl = devm_pinctrl_get(dev); + if (!IS_ERR(imx327->pinctrl)) { + imx327->pins_default = + pinctrl_lookup_state(imx327->pinctrl, + OF_CAMERA_PINCTRL_STATE_DEFAULT); + if (IS_ERR(imx327->pins_default)) + dev_err(dev, "could not get default pinstate\n"); + + imx327->pins_sleep = + pinctrl_lookup_state(imx327->pinctrl, + OF_CAMERA_PINCTRL_STATE_SLEEP); + if (IS_ERR(imx327->pins_sleep)) + dev_err(dev, "could not get sleep pinstate\n"); + } + mutex_init(&imx327->mutex); sd = &imx327->subdev; v4l2_i2c_subdev_init(sd, client, &imx327_subdev_ops); - imx327_check_remote_dev(imx327); - if (imx327->has_devnode) { - imx327->support_modes = supported_linear_modes; - imx327->support_modes_num = ARRAY_SIZE(supported_linear_modes); - dev_err(dev, "linear mode"); - } else { - imx327->support_modes = supported_hdr_modes; - imx327->support_modes_num = ARRAY_SIZE(supported_hdr_modes); - dev_err(dev, "hdr mode"); - } - imx327->cur_mode = &imx327->support_modes[0]; - ret = imx327_initialize_controls(imx327); if (ret) goto err_destroy_mutex; @@ -1303,11 +1931,13 @@ static int imx327_probe(struct i2c_client *client, goto err_power_off; #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + dev_err(dev, "set the video v4l2 subdev api\n"); sd->internal_ops = &imx327_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; #endif #if defined(CONFIG_MEDIA_CONTROLLER) + dev_err(dev, "set the media controller\n"); imx327->pad.flags = MEDIA_PAD_FL_SOURCE; sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&sd->entity, 1, &imx327->pad); @@ -1333,7 +1963,11 @@ static int imx327_probe(struct i2c_client *client, pm_runtime_set_active(dev); pm_runtime_enable(dev); pm_runtime_idle(dev); - + g_isHCG = false; +#ifdef USED_SYS_DEBUG + add_sysfs_interfaces(dev); +#endif + dev_err(dev, "v4l2 async register subdev success\n"); return 0; err_clean_entity: