diff options
Diffstat (limited to 'drivers/media/i2c/imx415.c')
-rw-r--r-- | drivers/media/i2c/imx415.c | 852 |
1 files changed, 521 insertions, 331 deletions
diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c index 1e5f20c3ed82..9f37779bd611 100644 --- a/drivers/media/i2c/imx415.c +++ b/drivers/media/i2c/imx415.c @@ -16,6 +16,7 @@ #include <linux/slab.h> #include <linux/videodev2.h> +#include <media/v4l2-cci.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-fwnode.h> #include <media/v4l2-subdev.h> @@ -25,79 +26,75 @@ #define IMX415_PIXEL_ARRAY_WIDTH 3864 #define IMX415_PIXEL_ARRAY_HEIGHT 2192 #define IMX415_PIXEL_ARRAY_VBLANK 58 +#define IMX415_EXPOSURE_OFFSET 8 -#define IMX415_NUM_CLK_PARAM_REGS 11 +#define IMX415_PIXEL_RATE_74_25MHZ 891000000 +#define IMX415_PIXEL_RATE_72MHZ 864000000 -#define IMX415_REG_8BIT(n) ((1 << 16) | (n)) -#define IMX415_REG_16BIT(n) ((2 << 16) | (n)) -#define IMX415_REG_24BIT(n) ((3 << 16) | (n)) -#define IMX415_REG_SIZE_SHIFT 16 -#define IMX415_REG_ADDR_MASK 0xffff +#define IMX415_NUM_CLK_PARAM_REGS 11 -#define IMX415_MODE IMX415_REG_8BIT(0x3000) +#define IMX415_MODE CCI_REG8(0x3000) #define IMX415_MODE_OPERATING (0) #define IMX415_MODE_STANDBY BIT(0) -#define IMX415_REGHOLD IMX415_REG_8BIT(0x3001) +#define IMX415_REGHOLD CCI_REG8(0x3001) #define IMX415_REGHOLD_INVALID (0) #define IMX415_REGHOLD_VALID BIT(0) -#define IMX415_XMSTA IMX415_REG_8BIT(0x3002) +#define IMX415_XMSTA CCI_REG8(0x3002) #define IMX415_XMSTA_START (0) #define IMX415_XMSTA_STOP BIT(0) -#define IMX415_BCWAIT_TIME IMX415_REG_16BIT(0x3008) -#define IMX415_CPWAIT_TIME IMX415_REG_16BIT(0x300A) -#define IMX415_WINMODE IMX415_REG_8BIT(0x301C) -#define IMX415_ADDMODE IMX415_REG_8BIT(0x3022) -#define IMX415_REVERSE IMX415_REG_8BIT(0x3030) +#define IMX415_BCWAIT_TIME CCI_REG16_LE(0x3008) +#define IMX415_CPWAIT_TIME CCI_REG16_LE(0x300a) +#define IMX415_WINMODE CCI_REG8(0x301c) +#define IMX415_ADDMODE CCI_REG8(0x3022) +#define IMX415_REVERSE CCI_REG8(0x3030) #define IMX415_HREVERSE_SHIFT (0) #define IMX415_VREVERSE_SHIFT BIT(0) -#define IMX415_ADBIT IMX415_REG_8BIT(0x3031) -#define IMX415_MDBIT IMX415_REG_8BIT(0x3032) -#define IMX415_SYS_MODE IMX415_REG_8BIT(0x3033) -#define IMX415_OUTSEL IMX415_REG_8BIT(0x30C0) -#define IMX415_DRV IMX415_REG_8BIT(0x30C1) -#define IMX415_VMAX IMX415_REG_24BIT(0x3024) -#define IMX415_HMAX IMX415_REG_16BIT(0x3028) -#define IMX415_SHR0 IMX415_REG_24BIT(0x3050) -#define IMX415_GAIN_PCG_0 IMX415_REG_16BIT(0x3090) +#define IMX415_ADBIT CCI_REG8(0x3031) +#define IMX415_MDBIT CCI_REG8(0x3032) +#define IMX415_SYS_MODE CCI_REG8(0x3033) +#define IMX415_OUTSEL CCI_REG8(0x30c0) +#define IMX415_DRV CCI_REG8(0x30c1) +#define IMX415_VMAX CCI_REG24_LE(0x3024) +#define IMX415_VMAX_MAX 0xfffff +#define IMX415_HMAX CCI_REG16_LE(0x3028) +#define IMX415_HMAX_MAX 0xffff +#define IMX415_HMAX_MULTIPLIER 12 +#define IMX415_SHR0 CCI_REG24_LE(0x3050) +#define IMX415_GAIN_PCG_0 CCI_REG16_LE(0x3090) #define IMX415_AGAIN_MIN 0 #define IMX415_AGAIN_MAX 100 #define IMX415_AGAIN_STEP 1 -#define IMX415_BLKLEVEL IMX415_REG_16BIT(0x30E2) +#define IMX415_BLKLEVEL CCI_REG16_LE(0x30e2) #define IMX415_BLKLEVEL_DEFAULT 50 -#define IMX415_TPG_EN_DUOUT IMX415_REG_8BIT(0x30E4) -#define IMX415_TPG_PATSEL_DUOUT IMX415_REG_8BIT(0x30E6) -#define IMX415_TPG_COLORWIDTH IMX415_REG_8BIT(0x30E8) -#define IMX415_TESTCLKEN_MIPI IMX415_REG_8BIT(0x3110) -#define IMX415_INCKSEL1 IMX415_REG_8BIT(0x3115) -#define IMX415_INCKSEL2 IMX415_REG_8BIT(0x3116) -#define IMX415_INCKSEL3 IMX415_REG_16BIT(0x3118) -#define IMX415_INCKSEL4 IMX415_REG_16BIT(0x311A) -#define IMX415_INCKSEL5 IMX415_REG_8BIT(0x311E) -#define IMX415_DIG_CLP_MODE IMX415_REG_8BIT(0x32C8) -#define IMX415_WRJ_OPEN IMX415_REG_8BIT(0x3390) -#define IMX415_SENSOR_INFO IMX415_REG_16BIT(0x3F12) -#define IMX415_SENSOR_INFO_MASK 0xFFF +#define IMX415_TPG_EN_DUOUT CCI_REG8(0x30e4) +#define IMX415_TPG_PATSEL_DUOUT CCI_REG8(0x30e6) +#define IMX415_TPG_COLORWIDTH CCI_REG8(0x30e8) +#define IMX415_TESTCLKEN_MIPI CCI_REG8(0x3110) +#define IMX415_INCKSEL1 CCI_REG8(0x3115) +#define IMX415_INCKSEL2 CCI_REG8(0x3116) +#define IMX415_INCKSEL3 CCI_REG16_LE(0x3118) +#define IMX415_INCKSEL4 CCI_REG16_LE(0x311a) +#define IMX415_INCKSEL5 CCI_REG8(0x311e) +#define IMX415_DIG_CLP_MODE CCI_REG8(0x32c8) +#define IMX415_WRJ_OPEN CCI_REG8(0x3390) +#define IMX415_SENSOR_INFO CCI_REG16_LE(0x3f12) +#define IMX415_SENSOR_INFO_MASK 0xfff #define IMX415_CHIP_ID 0x514 -#define IMX415_LANEMODE IMX415_REG_16BIT(0x4001) +#define IMX415_LANEMODE CCI_REG16_LE(0x4001) #define IMX415_LANEMODE_2 1 #define IMX415_LANEMODE_4 3 -#define IMX415_TXCLKESC_FREQ IMX415_REG_16BIT(0x4004) -#define IMX415_INCKSEL6 IMX415_REG_8BIT(0x400C) -#define IMX415_TCLKPOST IMX415_REG_16BIT(0x4018) -#define IMX415_TCLKPREPARE IMX415_REG_16BIT(0x401A) -#define IMX415_TCLKTRAIL IMX415_REG_16BIT(0x401C) -#define IMX415_TCLKZERO IMX415_REG_16BIT(0x401E) -#define IMX415_THSPREPARE IMX415_REG_16BIT(0x4020) -#define IMX415_THSZERO IMX415_REG_16BIT(0x4022) -#define IMX415_THSTRAIL IMX415_REG_16BIT(0x4024) -#define IMX415_THSEXIT IMX415_REG_16BIT(0x4026) -#define IMX415_TLPX IMX415_REG_16BIT(0x4028) -#define IMX415_INCKSEL7 IMX415_REG_8BIT(0x4074) - -struct imx415_reg { - u32 address; - u32 val; -}; +#define IMX415_TXCLKESC_FREQ CCI_REG16_LE(0x4004) +#define IMX415_INCKSEL6 CCI_REG8(0x400c) +#define IMX415_TCLKPOST CCI_REG16_LE(0x4018) +#define IMX415_TCLKPREPARE CCI_REG16_LE(0x401a) +#define IMX415_TCLKTRAIL CCI_REG16_LE(0x401c) +#define IMX415_TCLKZERO CCI_REG16_LE(0x401e) +#define IMX415_THSPREPARE CCI_REG16_LE(0x4020) +#define IMX415_THSZERO CCI_REG16_LE(0x4022) +#define IMX415_THSTRAIL CCI_REG16_LE(0x4024) +#define IMX415_THSEXIT CCI_REG16_LE(0x4026) +#define IMX415_TLPX CCI_REG16_LE(0x4028) +#define IMX415_INCKSEL7 CCI_REG8(0x4074) static const char *const imx415_supply_names[] = { "dvdd", @@ -118,13 +115,13 @@ static const s64 link_freq_menu_items[] = { struct imx415_clk_params { u64 lane_rate; u64 inck; - struct imx415_reg regs[IMX415_NUM_CLK_PARAM_REGS]; + struct cci_reg_sequence regs[IMX415_NUM_CLK_PARAM_REGS]; }; /* INCK Settings - includes all lane rate and INCK dependent registers */ static const struct imx415_clk_params imx415_clk_params[] = { { - .lane_rate = 594000000, + .lane_rate = 594000000UL, .inck = 27000000, .regs[0] = { IMX415_BCWAIT_TIME, 0x05D }, .regs[1] = { IMX415_CPWAIT_TIME, 0x042 }, @@ -139,7 +136,37 @@ static const struct imx415_clk_params imx415_clk_params[] = { .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 }, }, { - .lane_rate = 720000000, + .lane_rate = 594000000UL, + .inck = 37125000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x07F }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x05B }, + .regs[2] = { IMX415_SYS_MODE, 0x7 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x24 }, + .regs[5] = { IMX415_INCKSEL3, 0x080 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x24 }, + .regs[8] = { IMX415_INCKSEL6, 0x0 }, + .regs[9] = { IMX415_INCKSEL7, 0x1 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0984 }, + }, + { + .lane_rate = 594000000UL, + .inck = 74250000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x0FF }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x0B6 }, + .regs[2] = { IMX415_SYS_MODE, 0x7 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x28 }, + .regs[5] = { IMX415_INCKSEL3, 0x080 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x28 }, + .regs[8] = { IMX415_INCKSEL6, 0x0 }, + .regs[9] = { IMX415_INCKSEL7, 0x1 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1290 }, + }, + { + .lane_rate = 720000000UL, .inck = 24000000, .regs[0] = { IMX415_BCWAIT_TIME, 0x054 }, .regs[1] = { IMX415_CPWAIT_TIME, 0x03B }, @@ -154,7 +181,22 @@ static const struct imx415_clk_params imx415_clk_params[] = { .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0600 }, }, { - .lane_rate = 891000000, + .lane_rate = 720000000UL, + .inck = 72000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x0F8 }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x0B0 }, + .regs[2] = { IMX415_SYS_MODE, 0x9 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x28 }, + .regs[5] = { IMX415_INCKSEL3, 0x0A0 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x28 }, + .regs[8] = { IMX415_INCKSEL6, 0x0 }, + .regs[9] = { IMX415_INCKSEL7, 0x1 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1200 }, + }, + { + .lane_rate = 891000000UL, .inck = 27000000, .regs[0] = { IMX415_BCWAIT_TIME, 0x05D }, .regs[1] = { IMX415_CPWAIT_TIME, 0x042 }, @@ -169,7 +211,37 @@ static const struct imx415_clk_params imx415_clk_params[] = { .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 }, }, { - .lane_rate = 1440000000, + .lane_rate = 891000000UL, + .inck = 37125000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x07F }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x05B }, + .regs[2] = { IMX415_SYS_MODE, 0x5 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x24 }, + .regs[5] = { IMX415_INCKSEL3, 0x0C0 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x24 }, + .regs[8] = { IMX415_INCKSEL6, 0x0 }, + .regs[9] = { IMX415_INCKSEL7, 0x1 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0948 }, + }, + { + .lane_rate = 891000000UL, + .inck = 74250000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x0FF }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x0B6 }, + .regs[2] = { IMX415_SYS_MODE, 0x5 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x28 }, + .regs[5] = { IMX415_INCKSEL3, 0x0C0 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x28 }, + .regs[8] = { IMX415_INCKSEL6, 0x0 }, + .regs[9] = { IMX415_INCKSEL7, 0x1 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1290 }, + }, + { + .lane_rate = 1440000000UL, .inck = 24000000, .regs[0] = { IMX415_BCWAIT_TIME, 0x054 }, .regs[1] = { IMX415_CPWAIT_TIME, 0x03B }, @@ -184,7 +256,22 @@ static const struct imx415_clk_params imx415_clk_params[] = { .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0600 }, }, { - .lane_rate = 1485000000, + .lane_rate = 1440000000UL, + .inck = 72000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x0F8 }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x0B0 }, + .regs[2] = { IMX415_SYS_MODE, 0x8 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x28 }, + .regs[5] = { IMX415_INCKSEL3, 0x0A0 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x28 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1200 }, + }, + { + .lane_rate = 1485000000UL, .inck = 27000000, .regs[0] = { IMX415_BCWAIT_TIME, 0x05D }, .regs[1] = { IMX415_CPWAIT_TIME, 0x042 }, @@ -198,13 +285,175 @@ static const struct imx415_clk_params imx415_clk_params[] = { .regs[9] = { IMX415_INCKSEL7, 0x0 }, .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 }, }, + { + .lane_rate = 1485000000UL, + .inck = 37125000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x07F }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x05B }, + .regs[2] = { IMX415_SYS_MODE, 0x8 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x24 }, + .regs[5] = { IMX415_INCKSEL3, 0x0A0 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x24 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0948 }, + }, + { + .lane_rate = 1485000000UL, + .inck = 74250000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x0FF }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x0B6 }, + .regs[2] = { IMX415_SYS_MODE, 0x8 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x28 }, + .regs[5] = { IMX415_INCKSEL3, 0x0A0 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x28 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1290 }, + }, + { + .lane_rate = 1782000000UL, + .inck = 27000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x05D }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x042 }, + .regs[2] = { IMX415_SYS_MODE, 0x4 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x23 }, + .regs[5] = { IMX415_INCKSEL3, 0x0C6 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E7 }, + .regs[7] = { IMX415_INCKSEL5, 0x23 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 }, + }, + { + .lane_rate = 1782000000UL, + .inck = 37125000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x07F }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x05B }, + .regs[2] = { IMX415_SYS_MODE, 0x4 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x24 }, + .regs[5] = { IMX415_INCKSEL3, 0x0C0 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x24 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0948 }, + }, + { + .lane_rate = 1782000000UL, + .inck = 74250000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x0FF }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x0B6 }, + .regs[2] = { IMX415_SYS_MODE, 0x4 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x28 }, + .regs[5] = { IMX415_INCKSEL3, 0x0C0 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x28 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1290 }, + }, + { + .lane_rate = 2079000000UL, + .inck = 27000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x05D }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x042 }, + .regs[2] = { IMX415_SYS_MODE, 0x2 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x23 }, + .regs[5] = { IMX415_INCKSEL3, 0x0E7 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E7 }, + .regs[7] = { IMX415_INCKSEL5, 0x23 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 }, + }, + { + .lane_rate = 2079000000UL, + .inck = 37125000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x07F }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x05B }, + .regs[2] = { IMX415_SYS_MODE, 0x2 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x24 }, + .regs[5] = { IMX415_INCKSEL3, 0x0E0 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x24 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0948 }, + }, + { + .lane_rate = 2079000000UL, + .inck = 74250000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x0FF }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x0B6 }, + .regs[2] = { IMX415_SYS_MODE, 0x2 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x28 }, + .regs[5] = { IMX415_INCKSEL3, 0x0E0 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x28 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1290 }, + }, + { + .lane_rate = 2376000000UL, + .inck = 27000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x05D }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x042 }, + .regs[2] = { IMX415_SYS_MODE, 0x0 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x23 }, + .regs[5] = { IMX415_INCKSEL3, 0x108 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E7 }, + .regs[7] = { IMX415_INCKSEL5, 0x23 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 }, + }, + { + .lane_rate = 2376000000UL, + .inck = 37125000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x07F }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x05B }, + .regs[2] = { IMX415_SYS_MODE, 0x0 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x24 }, + .regs[5] = { IMX415_INCKSEL3, 0x100 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x24 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0948 }, + }, + { + .lane_rate = 2376000000UL, + .inck = 74250000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x0FF }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x0B6 }, + .regs[2] = { IMX415_SYS_MODE, 0x0 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x28 }, + .regs[5] = { IMX415_INCKSEL3, 0x100 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x28 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1290 }, + }, }; -/* all-pixel 2-lane 720 Mbps 15.74 Hz mode */ -static const struct imx415_reg imx415_mode_2_720[] = { - { IMX415_VMAX, 0x08CA }, - { IMX415_HMAX, 0x07F0 }, - { IMX415_LANEMODE, IMX415_LANEMODE_2 }, +/* 720 Mbps CSI configuration */ +static const struct cci_reg_sequence imx415_linkrate_720mbps[] = { { IMX415_TCLKPOST, 0x006F }, { IMX415_TCLKPREPARE, 0x002F }, { IMX415_TCLKTRAIL, 0x002F }, @@ -216,11 +465,8 @@ static const struct imx415_reg imx415_mode_2_720[] = { { IMX415_TLPX, 0x0027 }, }; -/* all-pixel 2-lane 1440 Mbps 30.01 Hz mode */ -static const struct imx415_reg imx415_mode_2_1440[] = { - { IMX415_VMAX, 0x08CA }, - { IMX415_HMAX, 0x042A }, - { IMX415_LANEMODE, IMX415_LANEMODE_2 }, +/* 1440 Mbps CSI configuration */ +static const struct cci_reg_sequence imx415_linkrate_1440mbps[] = { { IMX415_TCLKPOST, 0x009F }, { IMX415_TCLKPREPARE, 0x0057 }, { IMX415_TCLKTRAIL, 0x0057 }, @@ -232,11 +478,8 @@ static const struct imx415_reg imx415_mode_2_1440[] = { { IMX415_TLPX, 0x004F }, }; -/* all-pixel 4-lane 891 Mbps 30 Hz mode */ -static const struct imx415_reg imx415_mode_4_891[] = { - { IMX415_VMAX, 0x08CA }, - { IMX415_HMAX, 0x044C }, - { IMX415_LANEMODE, IMX415_LANEMODE_4 }, +/* 891 Mbps CSI configuration */ +static const struct cci_reg_sequence imx415_linkrate_891mbps[] = { { IMX415_TCLKPOST, 0x007F }, { IMX415_TCLKPREPARE, 0x0037 }, { IMX415_TCLKTRAIL, 0x0037 }, @@ -250,42 +493,12 @@ static const struct imx415_reg imx415_mode_4_891[] = { struct imx415_mode_reg_list { u32 num_of_regs; - const struct imx415_reg *regs; + const struct cci_reg_sequence *regs; }; -/* - * Mode : number of lanes, lane rate and frame rate dependent settings - * - * pixel_rate and hmax_pix are needed to calculate hblank for the v4l2 ctrl - * interface. These values can not be found in the data sheet and should be - * treated as virtual values. Use following table when adding new modes. - * - * lane_rate lanes fps hmax_pix pixel_rate - * - * 594 2 10.000 4400 99000000 - * 891 2 15.000 4400 148500000 - * 720 2 15.748 4064 144000000 - * 1782 2 30.000 4400 297000000 - * 2079 2 30.000 4400 297000000 - * 1440 2 30.019 4510 304615385 - * - * 594 4 20.000 5500 247500000 - * 594 4 25.000 4400 247500000 - * 720 4 25.000 4400 247500000 - * 720 4 30.019 4510 304615385 - * 891 4 30.000 4400 297000000 - * 1440 4 30.019 4510 304615385 - * 1440 4 60.038 4510 609230769 - * 1485 4 60.000 4400 594000000 - * 1782 4 60.000 4400 594000000 - * 2079 4 60.000 4400 594000000 - * 2376 4 90.164 4392 891000000 - */ struct imx415_mode { u64 lane_rate; - u32 lanes; - u32 hmax_pix; - u64 pixel_rate; + u32 hmax_min[2]; struct imx415_mode_reg_list reg_list; }; @@ -293,41 +506,30 @@ struct imx415_mode { static const struct imx415_mode supported_modes[] = { { .lane_rate = 720000000, - .lanes = 2, - .hmax_pix = 4064, - .pixel_rate = 144000000, + .hmax_min = { 2032, 1066 }, .reg_list = { - .num_of_regs = ARRAY_SIZE(imx415_mode_2_720), - .regs = imx415_mode_2_720, + .num_of_regs = ARRAY_SIZE(imx415_linkrate_720mbps), + .regs = imx415_linkrate_720mbps, }, }, { .lane_rate = 1440000000, - .lanes = 2, - .hmax_pix = 4510, - .pixel_rate = 304615385, + .hmax_min = { 1066, 533 }, .reg_list = { - .num_of_regs = ARRAY_SIZE(imx415_mode_2_1440), - .regs = imx415_mode_2_1440, + .num_of_regs = ARRAY_SIZE(imx415_linkrate_1440mbps), + .regs = imx415_linkrate_1440mbps, }, }, { .lane_rate = 891000000, - .lanes = 4, - .hmax_pix = 4400, - .pixel_rate = 297000000, + .hmax_min = { 2200, 1100 }, .reg_list = { - .num_of_regs = ARRAY_SIZE(imx415_mode_4_891), - .regs = imx415_mode_4_891, + .num_of_regs = ARRAY_SIZE(imx415_linkrate_891mbps), + .regs = imx415_linkrate_891mbps, }, }, }; -static const struct regmap_config imx415_regmap_config = { - .reg_bits = 16, - .val_bits = 8, -}; - static const char *const imx415_test_pattern_menu[] = { "disabled", "solid black", @@ -347,6 +549,7 @@ static const char *const imx415_test_pattern_menu[] = { struct imx415 { struct device *dev; struct clk *clk; + unsigned long pixel_rate; struct regulator_bulk_data supplies[ARRAY_SIZE(imx415_supply_names)]; struct gpio_desc *reset; struct regmap *regmap; @@ -358,8 +561,10 @@ struct imx415 { struct v4l2_ctrl_handler ctrls; struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hblank; struct v4l2_ctrl *hflip; struct v4l2_ctrl *vflip; + struct v4l2_ctrl *exposure; unsigned int cur_mode; unsigned int num_data_lanes; @@ -369,7 +574,7 @@ struct imx415 { * This table includes fixed register settings and a bunch of undocumented * registers that have to be set to another value than default. */ -static const struct imx415_reg imx415_init_table[] = { +static const struct cci_reg_sequence imx415_init_table[] = { /* use all-pixel readout mode, no flip */ { IMX415_WINMODE, 0x00 }, { IMX415_ADDMODE, 0x00 }, @@ -382,77 +587,77 @@ static const struct imx415_reg imx415_init_table[] = { { IMX415_DRV, 0x00 }, /* SONY magic registers */ - { IMX415_REG_8BIT(0x32D4), 0x21 }, - { IMX415_REG_8BIT(0x32EC), 0xA1 }, - { IMX415_REG_8BIT(0x3452), 0x7F }, - { IMX415_REG_8BIT(0x3453), 0x03 }, - { IMX415_REG_8BIT(0x358A), 0x04 }, - { IMX415_REG_8BIT(0x35A1), 0x02 }, - { IMX415_REG_8BIT(0x36BC), 0x0C }, - { IMX415_REG_8BIT(0x36CC), 0x53 }, - { IMX415_REG_8BIT(0x36CD), 0x00 }, - { IMX415_REG_8BIT(0x36CE), 0x3C }, - { IMX415_REG_8BIT(0x36D0), 0x8C }, - { IMX415_REG_8BIT(0x36D1), 0x00 }, - { IMX415_REG_8BIT(0x36D2), 0x71 }, - { IMX415_REG_8BIT(0x36D4), 0x3C }, - { IMX415_REG_8BIT(0x36D6), 0x53 }, - { IMX415_REG_8BIT(0x36D7), 0x00 }, - { IMX415_REG_8BIT(0x36D8), 0x71 }, - { IMX415_REG_8BIT(0x36DA), 0x8C }, - { IMX415_REG_8BIT(0x36DB), 0x00 }, - { IMX415_REG_8BIT(0x3724), 0x02 }, - { IMX415_REG_8BIT(0x3726), 0x02 }, - { IMX415_REG_8BIT(0x3732), 0x02 }, - { IMX415_REG_8BIT(0x3734), 0x03 }, - { IMX415_REG_8BIT(0x3736), 0x03 }, - { IMX415_REG_8BIT(0x3742), 0x03 }, - { IMX415_REG_8BIT(0x3862), 0xE0 }, - { IMX415_REG_8BIT(0x38CC), 0x30 }, - { IMX415_REG_8BIT(0x38CD), 0x2F }, - { IMX415_REG_8BIT(0x395C), 0x0C }, - { IMX415_REG_8BIT(0x3A42), 0xD1 }, - { IMX415_REG_8BIT(0x3A4C), 0x77 }, - { IMX415_REG_8BIT(0x3AE0), 0x02 }, - { IMX415_REG_8BIT(0x3AEC), 0x0C }, - { IMX415_REG_8BIT(0x3B00), 0x2E }, - { IMX415_REG_8BIT(0x3B06), 0x29 }, - { IMX415_REG_8BIT(0x3B98), 0x25 }, - { IMX415_REG_8BIT(0x3B99), 0x21 }, - { IMX415_REG_8BIT(0x3B9B), 0x13 }, - { IMX415_REG_8BIT(0x3B9C), 0x13 }, - { IMX415_REG_8BIT(0x3B9D), 0x13 }, - { IMX415_REG_8BIT(0x3B9E), 0x13 }, - { IMX415_REG_8BIT(0x3BA1), 0x00 }, - { IMX415_REG_8BIT(0x3BA2), 0x06 }, - { IMX415_REG_8BIT(0x3BA3), 0x0B }, - { IMX415_REG_8BIT(0x3BA4), 0x10 }, - { IMX415_REG_8BIT(0x3BA5), 0x14 }, - { IMX415_REG_8BIT(0x3BA6), 0x18 }, - { IMX415_REG_8BIT(0x3BA7), 0x1A }, - { IMX415_REG_8BIT(0x3BA8), 0x1A }, - { IMX415_REG_8BIT(0x3BA9), 0x1A }, - { IMX415_REG_8BIT(0x3BAC), 0xED }, - { IMX415_REG_8BIT(0x3BAD), 0x01 }, - { IMX415_REG_8BIT(0x3BAE), 0xF6 }, - { IMX415_REG_8BIT(0x3BAF), 0x02 }, - { IMX415_REG_8BIT(0x3BB0), 0xA2 }, - { IMX415_REG_8BIT(0x3BB1), 0x03 }, - { IMX415_REG_8BIT(0x3BB2), 0xE0 }, - { IMX415_REG_8BIT(0x3BB3), 0x03 }, - { IMX415_REG_8BIT(0x3BB4), 0xE0 }, - { IMX415_REG_8BIT(0x3BB5), 0x03 }, - { IMX415_REG_8BIT(0x3BB6), 0xE0 }, - { IMX415_REG_8BIT(0x3BB7), 0x03 }, - { IMX415_REG_8BIT(0x3BB8), 0xE0 }, - { IMX415_REG_8BIT(0x3BBA), 0xE0 }, - { IMX415_REG_8BIT(0x3BBC), 0xDA }, - { IMX415_REG_8BIT(0x3BBE), 0x88 }, - { IMX415_REG_8BIT(0x3BC0), 0x44 }, - { IMX415_REG_8BIT(0x3BC2), 0x7B }, - { IMX415_REG_8BIT(0x3BC4), 0xA2 }, - { IMX415_REG_8BIT(0x3BC8), 0xBD }, - { IMX415_REG_8BIT(0x3BCA), 0xBD }, + { CCI_REG8(0x32D4), 0x21 }, + { CCI_REG8(0x32EC), 0xA1 }, + { CCI_REG8(0x3452), 0x7F }, + { CCI_REG8(0x3453), 0x03 }, + { CCI_REG8(0x358A), 0x04 }, + { CCI_REG8(0x35A1), 0x02 }, + { CCI_REG8(0x36BC), 0x0C }, + { CCI_REG8(0x36CC), 0x53 }, + { CCI_REG8(0x36CD), 0x00 }, + { CCI_REG8(0x36CE), 0x3C }, + { CCI_REG8(0x36D0), 0x8C }, + { CCI_REG8(0x36D1), 0x00 }, + { CCI_REG8(0x36D2), 0x71 }, + { CCI_REG8(0x36D4), 0x3C }, + { CCI_REG8(0x36D6), 0x53 }, + { CCI_REG8(0x36D7), 0x00 }, + { CCI_REG8(0x36D8), 0x71 }, + { CCI_REG8(0x36DA), 0x8C }, + { CCI_REG8(0x36DB), 0x00 }, + { CCI_REG8(0x3724), 0x02 }, + { CCI_REG8(0x3726), 0x02 }, + { CCI_REG8(0x3732), 0x02 }, + { CCI_REG8(0x3734), 0x03 }, + { CCI_REG8(0x3736), 0x03 }, + { CCI_REG8(0x3742), 0x03 }, + { CCI_REG8(0x3862), 0xE0 }, + { CCI_REG8(0x38CC), 0x30 }, + { CCI_REG8(0x38CD), 0x2F }, + { CCI_REG8(0x395C), 0x0C }, + { CCI_REG8(0x3A42), 0xD1 }, + { CCI_REG8(0x3A4C), 0x77 }, + { CCI_REG8(0x3AE0), 0x02 }, + { CCI_REG8(0x3AEC), 0x0C }, + { CCI_REG8(0x3B00), 0x2E }, + { CCI_REG8(0x3B06), 0x29 }, + { CCI_REG8(0x3B98), 0x25 }, + { CCI_REG8(0x3B99), 0x21 }, + { CCI_REG8(0x3B9B), 0x13 }, + { CCI_REG8(0x3B9C), 0x13 }, + { CCI_REG8(0x3B9D), 0x13 }, + { CCI_REG8(0x3B9E), 0x13 }, + { CCI_REG8(0x3BA1), 0x00 }, + { CCI_REG8(0x3BA2), 0x06 }, + { CCI_REG8(0x3BA3), 0x0B }, + { CCI_REG8(0x3BA4), 0x10 }, + { CCI_REG8(0x3BA5), 0x14 }, + { CCI_REG8(0x3BA6), 0x18 }, + { CCI_REG8(0x3BA7), 0x1A }, + { CCI_REG8(0x3BA8), 0x1A }, + { CCI_REG8(0x3BA9), 0x1A }, + { CCI_REG8(0x3BAC), 0xED }, + { CCI_REG8(0x3BAD), 0x01 }, + { CCI_REG8(0x3BAE), 0xF6 }, + { CCI_REG8(0x3BAF), 0x02 }, + { CCI_REG8(0x3BB0), 0xA2 }, + { CCI_REG8(0x3BB1), 0x03 }, + { CCI_REG8(0x3BB2), 0xE0 }, + { CCI_REG8(0x3BB3), 0x03 }, + { CCI_REG8(0x3BB4), 0xE0 }, + { CCI_REG8(0x3BB5), 0x03 }, + { CCI_REG8(0x3BB6), 0xE0 }, + { CCI_REG8(0x3BB7), 0x03 }, + { CCI_REG8(0x3BB8), 0xE0 }, + { CCI_REG8(0x3BBA), 0xE0 }, + { CCI_REG8(0x3BBC), 0xDA }, + { CCI_REG8(0x3BBE), 0x88 }, + { CCI_REG8(0x3BC0), 0x44 }, + { CCI_REG8(0x3BC2), 0x7B }, + { CCI_REG8(0x3BC4), 0xA2 }, + { CCI_REG8(0x3BC8), 0xBD }, + { CCI_REG8(0x3BCA), 0xBD }, }; static inline struct imx415 *to_imx415(struct v4l2_subdev *sd) @@ -460,74 +665,26 @@ static inline struct imx415 *to_imx415(struct v4l2_subdev *sd) return container_of(sd, struct imx415, subdev); } -static int imx415_read(struct imx415 *sensor, u32 addr) -{ - u8 data[3] = { 0 }; - int ret; - - ret = regmap_raw_read(sensor->regmap, addr & IMX415_REG_ADDR_MASK, data, - (addr >> IMX415_REG_SIZE_SHIFT) & 3); - if (ret < 0) - return ret; - - return (data[2] << 16) | (data[1] << 8) | data[0]; -} - -static int imx415_write(struct imx415 *sensor, u32 addr, u32 value) -{ - u8 data[3] = { value & 0xff, (value >> 8) & 0xff, value >> 16 }; - int ret; - - ret = regmap_raw_write(sensor->regmap, addr & IMX415_REG_ADDR_MASK, - data, (addr >> IMX415_REG_SIZE_SHIFT) & 3); - if (ret < 0) - dev_err_ratelimited(sensor->dev, - "%u-bit write to 0x%04x failed: %d\n", - ((addr >> IMX415_REG_SIZE_SHIFT) & 3) * 8, - addr & IMX415_REG_ADDR_MASK, ret); - - return 0; -} - static int imx415_set_testpattern(struct imx415 *sensor, int val) { - int ret; + int ret = 0; if (val) { - ret = imx415_write(sensor, IMX415_BLKLEVEL, 0x00); - if (ret) - return ret; - ret = imx415_write(sensor, IMX415_TPG_EN_DUOUT, 0x01); - if (ret) - return ret; - ret = imx415_write(sensor, IMX415_TPG_PATSEL_DUOUT, val - 1); - if (ret) - return ret; - ret = imx415_write(sensor, IMX415_TPG_COLORWIDTH, 0x01); - if (ret) - return ret; - ret = imx415_write(sensor, IMX415_TESTCLKEN_MIPI, 0x20); - if (ret) - return ret; - ret = imx415_write(sensor, IMX415_DIG_CLP_MODE, 0x00); - if (ret) - return ret; - ret = imx415_write(sensor, IMX415_WRJ_OPEN, 0x00); + cci_write(sensor->regmap, IMX415_BLKLEVEL, 0x00, &ret); + cci_write(sensor->regmap, IMX415_TPG_EN_DUOUT, 0x01, &ret); + cci_write(sensor->regmap, IMX415_TPG_PATSEL_DUOUT, + val - 1, &ret); + cci_write(sensor->regmap, IMX415_TPG_COLORWIDTH, 0x01, &ret); + cci_write(sensor->regmap, IMX415_TESTCLKEN_MIPI, 0x20, &ret); + cci_write(sensor->regmap, IMX415_DIG_CLP_MODE, 0x00, &ret); + cci_write(sensor->regmap, IMX415_WRJ_OPEN, 0x00, &ret); } else { - ret = imx415_write(sensor, IMX415_BLKLEVEL, - IMX415_BLKLEVEL_DEFAULT); - if (ret) - return ret; - ret = imx415_write(sensor, IMX415_TPG_EN_DUOUT, 0x00); - if (ret) - return ret; - ret = imx415_write(sensor, IMX415_TESTCLKEN_MIPI, 0x00); - if (ret) - return ret; - ret = imx415_write(sensor, IMX415_DIG_CLP_MODE, 0x01); - if (ret) - return ret; - ret = imx415_write(sensor, IMX415_WRJ_OPEN, 0x01); + cci_write(sensor->regmap, IMX415_BLKLEVEL, + IMX415_BLKLEVEL_DEFAULT, &ret); + cci_write(sensor->regmap, IMX415_TPG_EN_DUOUT, 0x00, &ret); + cci_write(sensor->regmap, IMX415_TESTCLKEN_MIPI, 0x00, &ret); + cci_write(sensor->regmap, IMX415_DIG_CLP_MODE, 0x01, &ret); + cci_write(sensor->regmap, IMX415_WRJ_OPEN, 0x01, &ret); } return 0; } @@ -538,40 +695,70 @@ static int imx415_s_ctrl(struct v4l2_ctrl *ctrl) ctrls); const struct v4l2_mbus_framefmt *format; struct v4l2_subdev_state *state; + u32 exposure_max; unsigned int vmax; unsigned int flip; int ret; - if (!pm_runtime_get_if_in_use(sensor->dev)) - return 0; - state = v4l2_subdev_get_locked_active_state(&sensor->subdev); format = v4l2_subdev_state_get_format(state, 0); + if (ctrl->id == V4L2_CID_VBLANK) { + exposure_max = format->height + ctrl->val - + IMX415_EXPOSURE_OFFSET; + __v4l2_ctrl_modify_range(sensor->exposure, + sensor->exposure->minimum, + exposure_max, sensor->exposure->step, + sensor->exposure->default_value); + } + + if (!pm_runtime_get_if_in_use(sensor->dev)) + return 0; + switch (ctrl->id) { + case V4L2_CID_VBLANK: + ret = cci_write(sensor->regmap, IMX415_VMAX, + format->height + ctrl->val, NULL); + if (ret) + return ret; + /* + * Exposure is set based on VMAX which has just changed, so + * program exposure register as well + */ + ctrl = sensor->exposure; + fallthrough; case V4L2_CID_EXPOSURE: /* clamp the exposure value to VMAX. */ vmax = format->height + sensor->vblank->cur.val; ctrl->val = min_t(int, ctrl->val, vmax); - ret = imx415_write(sensor, IMX415_SHR0, vmax - ctrl->val); + ret = cci_write(sensor->regmap, IMX415_SHR0, + vmax - ctrl->val, NULL); break; case V4L2_CID_ANALOGUE_GAIN: /* analogue gain in 0.3 dB step size */ - ret = imx415_write(sensor, IMX415_GAIN_PCG_0, ctrl->val); + ret = cci_write(sensor->regmap, IMX415_GAIN_PCG_0, + ctrl->val, NULL); break; case V4L2_CID_HFLIP: case V4L2_CID_VFLIP: flip = (sensor->hflip->val << IMX415_HREVERSE_SHIFT) | (sensor->vflip->val << IMX415_VREVERSE_SHIFT); - ret = imx415_write(sensor, IMX415_REVERSE, flip); + ret = cci_write(sensor->regmap, IMX415_REVERSE, flip, NULL); break; case V4L2_CID_TEST_PATTERN: ret = imx415_set_testpattern(sensor, ctrl->val); break; + case V4L2_CID_HBLANK: + ret = cci_write(sensor->regmap, IMX415_HMAX, + (format->width + ctrl->val) / + IMX415_HMAX_MULTIPLIER, + NULL); + break; + default: ret = -EINVAL; break; @@ -590,11 +777,12 @@ static int imx415_ctrls_init(struct imx415 *sensor) { struct v4l2_fwnode_device_properties props; struct v4l2_ctrl *ctrl; - u64 pixel_rate = supported_modes[sensor->cur_mode].pixel_rate; - u64 lane_rate = supported_modes[sensor->cur_mode].lane_rate; + const struct imx415_mode *cur_mode = &supported_modes[sensor->cur_mode]; + u64 lane_rate = cur_mode->lane_rate; u32 exposure_max = IMX415_PIXEL_ARRAY_HEIGHT + - IMX415_PIXEL_ARRAY_VBLANK - 8; - u32 hblank; + IMX415_PIXEL_ARRAY_VBLANK - + IMX415_EXPOSURE_OFFSET; + u32 hblank_min, hblank_max; unsigned int i; int ret; @@ -622,36 +810,33 @@ static int imx415_ctrls_init(struct imx415 *sensor) if (ctrl) ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; - v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, V4L2_CID_EXPOSURE, - 4, exposure_max, 1, exposure_max); + sensor->exposure = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, + V4L2_CID_EXPOSURE, 4, + exposure_max, 1, exposure_max); v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, IMX415_AGAIN_MIN, IMX415_AGAIN_MAX, IMX415_AGAIN_STEP, IMX415_AGAIN_MIN); - hblank = supported_modes[sensor->cur_mode].hmax_pix - - IMX415_PIXEL_ARRAY_WIDTH; + hblank_min = (cur_mode->hmax_min[sensor->num_data_lanes == 2 ? 0 : 1] * + IMX415_HMAX_MULTIPLIER) - IMX415_PIXEL_ARRAY_WIDTH; + hblank_max = (IMX415_HMAX_MAX * IMX415_HMAX_MULTIPLIER) - + IMX415_PIXEL_ARRAY_WIDTH; ctrl = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, - V4L2_CID_HBLANK, hblank, hblank, 1, hblank); - if (ctrl) - ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + V4L2_CID_HBLANK, hblank_min, + hblank_max, IMX415_HMAX_MULTIPLIER, + hblank_min); sensor->vblank = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, V4L2_CID_VBLANK, IMX415_PIXEL_ARRAY_VBLANK, - IMX415_PIXEL_ARRAY_VBLANK, 1, - IMX415_PIXEL_ARRAY_VBLANK); - if (sensor->vblank) - sensor->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + IMX415_VMAX_MAX - IMX415_PIXEL_ARRAY_HEIGHT, + 1, IMX415_PIXEL_ARRAY_VBLANK); - /* - * The pixel rate used here is a virtual value and can be used for - * calculating the frame rate together with hblank. It may not - * necessarily be the physically correct pixel clock. - */ - v4l2_ctrl_new_std(&sensor->ctrls, NULL, V4L2_CID_PIXEL_RATE, pixel_rate, - pixel_rate, 1, pixel_rate); + v4l2_ctrl_new_std(&sensor->ctrls, NULL, V4L2_CID_PIXEL_RATE, + sensor->pixel_rate, sensor->pixel_rate, 1, + sensor->pixel_rate); sensor->hflip = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0); @@ -679,8 +864,6 @@ static int imx415_ctrls_init(struct imx415 *sensor) static int imx415_set_mode(struct imx415 *sensor, int mode) { - const struct imx415_reg *reg; - unsigned int i; int ret = 0; if (mode >= ARRAY_SIZE(supported_modes)) { @@ -688,34 +871,34 @@ static int imx415_set_mode(struct imx415 *sensor, int mode) return -EINVAL; } - for (i = 0; i < supported_modes[mode].reg_list.num_of_regs; ++i) { - reg = &supported_modes[mode].reg_list.regs[i]; - ret = imx415_write(sensor, reg->address, reg->val); - if (ret) - return ret; - } + cci_multi_reg_write(sensor->regmap, + supported_modes[mode].reg_list.regs, + supported_modes[mode].reg_list.num_of_regs, + &ret); - for (i = 0; i < IMX415_NUM_CLK_PARAM_REGS; ++i) { - reg = &sensor->clk_params->regs[i]; - ret = imx415_write(sensor, reg->address, reg->val); - if (ret) - return ret; - } + cci_multi_reg_write(sensor->regmap, + sensor->clk_params->regs, + IMX415_NUM_CLK_PARAM_REGS, + &ret); - return 0; + ret = cci_write(sensor->regmap, IMX415_LANEMODE, + sensor->num_data_lanes == 2 ? IMX415_LANEMODE_2 : + IMX415_LANEMODE_4, + NULL); + + return ret; } static int imx415_setup(struct imx415 *sensor, struct v4l2_subdev_state *state) { - unsigned int i; int ret; - for (i = 0; i < ARRAY_SIZE(imx415_init_table); ++i) { - ret = imx415_write(sensor, imx415_init_table[i].address, - imx415_init_table[i].val); - if (ret) - return ret; - } + ret = cci_multi_reg_write(sensor->regmap, + imx415_init_table, + ARRAY_SIZE(imx415_init_table), + NULL); + if (ret) + return ret; return imx415_set_mode(sensor, sensor->cur_mode); } @@ -724,7 +907,8 @@ static int imx415_wakeup(struct imx415 *sensor) { int ret; - ret = imx415_write(sensor, IMX415_MODE, IMX415_MODE_OPERATING); + ret = cci_write(sensor->regmap, IMX415_MODE, + IMX415_MODE_OPERATING, NULL); if (ret) return ret; @@ -743,21 +927,18 @@ static int imx415_stream_on(struct imx415 *sensor) int ret; ret = imx415_wakeup(sensor); - if (ret) - return ret; - - return imx415_write(sensor, IMX415_XMSTA, IMX415_XMSTA_START); + return cci_write(sensor->regmap, IMX415_XMSTA, + IMX415_XMSTA_START, &ret); } static int imx415_stream_off(struct imx415 *sensor) { int ret; - ret = imx415_write(sensor, IMX415_XMSTA, IMX415_XMSTA_STOP); - if (ret) - return ret; - - return imx415_write(sensor, IMX415_MODE, IMX415_MODE_STANDBY); + ret = cci_write(sensor->regmap, IMX415_XMSTA, + IMX415_XMSTA_STOP, NULL); + return cci_write(sensor->regmap, IMX415_MODE, + IMX415_MODE_STANDBY, &ret); } static int imx415_s_stream(struct v4l2_subdev *sd, int enable) @@ -928,8 +1109,7 @@ static int imx415_subdev_init(struct imx415 *sensor) if (ret) return ret; - sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | - V4L2_SUBDEV_FL_HAS_EVENTS; + sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; sensor->pad.flags = MEDIA_PAD_FL_SOURCE; sensor->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&sensor->subdev.entity, 1, &sensor->pad); @@ -992,6 +1172,7 @@ static void imx415_power_off(struct imx415 *sensor) static int imx415_identify_model(struct imx415 *sensor) { int model, ret; + u64 chip_id; /* * While most registers can be read when the sensor is in standby, this @@ -1002,14 +1183,14 @@ static int imx415_identify_model(struct imx415 *sensor) return dev_err_probe(sensor->dev, ret, "failed to get sensor out of standby\n"); - ret = imx415_read(sensor, IMX415_SENSOR_INFO); + ret = cci_read(sensor->regmap, IMX415_SENSOR_INFO, &chip_id, NULL); if (ret < 0) { dev_err_probe(sensor->dev, ret, "failed to read sensor information\n"); goto done; } - model = ret & IMX415_SENSOR_INFO_MASK; + model = chip_id & IMX415_SENSOR_INFO_MASK; switch (model) { case IMX415_CHIP_ID: @@ -1024,7 +1205,7 @@ static int imx415_identify_model(struct imx415 *sensor) ret = 0; done: - imx415_write(sensor, IMX415_MODE, IMX415_MODE_STANDBY); + cci_write(sensor->regmap, IMX415_MODE, IMX415_MODE_STANDBY, &ret); return ret; } @@ -1116,8 +1297,6 @@ static int imx415_parse_hw_config(struct imx415 *sensor) } for (j = 0; j < ARRAY_SIZE(supported_modes); ++j) { - if (sensor->num_data_lanes != supported_modes[j].lanes) - continue; if (bus_cfg.link_frequencies[i] * 2 != supported_modes[j].lane_rate) continue; @@ -1132,6 +1311,17 @@ static int imx415_parse_hw_config(struct imx415 *sensor) "no valid sensor mode defined\n"); goto done_endpoint_free; } + switch (inck) { + case 27000000: + case 37125000: + case 74250000: + sensor->pixel_rate = IMX415_PIXEL_RATE_74_25MHZ; + break; + case 24000000: + case 72000000: + sensor->pixel_rate = IMX415_PIXEL_RATE_72MHZ; + break; + } lane_rate = supported_modes[sensor->cur_mode].lane_rate; for (i = 0; i < ARRAY_SIZE(imx415_clk_params); ++i) { @@ -1173,7 +1363,7 @@ static int imx415_probe(struct i2c_client *client) if (ret) return ret; - sensor->regmap = devm_regmap_init_i2c(client, &imx415_regmap_config); + sensor->regmap = devm_cci_regmap_init_i2c(client, 16); if (IS_ERR(sensor->regmap)) return PTR_ERR(sensor->regmap); |