From 9370bb92b2d16684ee45cf24e879c93c509162da Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Thu, 19 Dec 2024 01:47:39 +0000 Subject: [PATCH] add wifi6 8852be driver --- kernel/drivers/media/i2c/sc2355.c | 1683 ++++++++++++++++++++++++++++----------------------------- 1 files changed, 822 insertions(+), 861 deletions(-) diff --git a/kernel/drivers/media/i2c/sc2355.c b/kernel/drivers/media/i2c/sc2355.c index a7060f1..680d279 100644 --- a/kernel/drivers/media/i2c/sc2355.c +++ b/kernel/drivers/media/i2c/sc2355.c @@ -1,18 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 /* - * sc2355 driver + * SC2355 driver * - * Copyright (C) 2020 Fuzhou Rockchip Electronics Co., Ltd. - * - * V0.0X01.0X00 first version,adjust sc2355. - * V0.0X01.0X01 add set flip ctrl. - * V0.0X01.0X02 1.fixed time limit error - * 2.fixed gain conversion function - * 3.fixed test pattern error - * 4.add quick stream on/off + * Copyright (C) 2023 Rockchip Electronics Co., Ltd. + * V0.1.0: MIPI is ok. */ -//#define DEBUG #include <linux/clk.h> #include <linux/device.h> #include <linux/delay.h> @@ -30,87 +23,109 @@ #include <media/v4l2-ctrls.h> #include <media/v4l2-subdev.h> #include <linux/pinctrl/consumer.h> -#include <linux/rk-preisp.h> -#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x02) - +#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x00) #ifndef V4L2_CID_DIGITAL_GAIN #define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN #endif -#define MIPI_FREQ_360M 360000000 //720Mbps/lane +#define MIPI_FREQ_180M 180000000 +#define MIPI_FREQ_360M 360000000 -#define SC2355_MAX_PIXEL_RATE (MIPI_FREQ_360M * 2 / 10) -#define OF_CAMERA_HDR_MODE "rockchip,camera-hdr-mode" +#define PIXEL_RATE_WITH_180M (MIPI_FREQ_180M * 2 / 10) +#define PIXEL_RATE_WITH_360M (MIPI_FREQ_360M * 2 / 10) #define SC2355_XVCLK_FREQ 24000000 -#define CHIP_ID 0xeb2c +#define CHIP_ID 0xeb2c #define SC2355_REG_CHIP_ID 0x3107 -#define SC2355_REG_CTRL_MODE 0x0100 -#define SC2355_MODE_SW_STANDBY 0x0 -#define SC2355_MODE_STREAMING BIT(0) +#define SC2355_REG_CTRL_MODE 0x0100 +#define SC2355_MODE_SW_STANDBY 0x0 +#define SC2355_MODE_STREAMING BIT(0) -#define SC2355_EXPOSURE_MIN 1// two lines long exp min +#define SC2355_REG_EXPOSURE 0x3e01 +#define SC2355_EXPOSURE_MIN 6 #define SC2355_EXPOSURE_STEP 1 #define SC2355_VTS_MAX 0xffff -#define SC2355_REG_EXPOSURE 0x3e00 //[3:0] +#define SC2355_REG_COARSE_AGAIN 0x3e09 -//long frame and normal gain reg -#define SC2355_REG_AGAIN 0x3e09 -#define SC2355_REG_AGAIN_FINE 0x3e09 +#define ANALOG_GAIN_MIN 0x01 +#define ANALOG_GAIN_MAX 0xF8 +#define ANALOG_GAIN_STEP 1 +#define ANALOG_GAIN_DEFAULT 0x1f -#define SC2355_REG_DGAIN 0x3e06 -#define SC2355_REG_DGAIN_FINE 0x3e07 - -#define SC2355_GAIN_MIN 0x100 -#define SC2355_GAIN_MAX (128*512) -#define SC2355_GAIN_STEP 1 -#define SC2355_GAIN_DEFAULT 0x100 - -#define SC2355_GROUP_HOLD 0x3812 -#define SC2355_GROUP_UPDATE_DATA_START 0x00 -#define SC2355_GROUP_UPDATE_LAUNCH 0x30 - -#define SC2355_SOFTWARE_RESET_REG 0x0103 -#define SC2355_REG_TEST_PATTERN 0x4501 -#define SC2355_TEST_PATTERN_ENABLE 0x08 +#define SC2355_REG_TEST_PATTERN 0x4501 +#define SC2355_TEST_PATTERN_ENABLE 0xcc +#define SC2355_TEST_PATTERN_DISABLE 0xc4 #define SC2355_REG_VTS 0x320e -#define SC2355_FLIP_REG 0x3221 -#define SC2355_FLIP_MASK 0x60 -#define SC2355_MIRROR_MASK 0x06 + #define REG_NULL 0xFFFF #define SC2355_REG_VALUE_08BIT 1 #define SC2355_REG_VALUE_16BIT 2 #define SC2355_REG_VALUE_24BIT 3 -#define SC2355_LANES 1 -#define LONG_FRAME_MAX_EXP 4297 -#define SHORT_FRAME_MAX_EXP 260 +#define SC2355_NAME "sc2355" #define OF_CAMERA_PINCTRL_STATE_DEFAULT "rockchip,camera_default" #define OF_CAMERA_PINCTRL_STATE_SLEEP "rockchip,camera_sleep" -#define SC2355_NAME "sc2355" +#define SC2355_FETCH_3RD_BYTE_EXP(VAL) (((VAL) >> 16) & 0xF) /* 4 Bits */ +#define SC2355_FETCH_2ND_BYTE_EXP(VAL) (((VAL) >> 8) & 0xFF) /* 8 Bits */ +#define SC2355_FETCH_1ST_BYTE_EXP(VAL) ((VAL) & 0xFF) /* 4 Bits */ -static const char * const sc2355_supply_names[] = { +//fps set +#define SC2355_FPS (20) + +//default exposure +#define EXP_DEFAULT_TIME_US (8000) + +#define SC2355_VTS_30_FPS 0x4e2 + +#define TIME_MS 1000 +#define SC2355_VTS (SC2355_VTS_30_FPS * 30 / SC2355_FPS) + +#define SC2355_TIME_TO_EXP_LINE_US(time_us) \ + (uint16_t)(time_us/1000*30*SC2355_VTS_30_FPS/TIME_MS) + +#define SC2355_DEFAULT_EXP_REG \ + SC2355_TIME_TO_EXP_LINE_US(EXP_DEFAULT_TIME_US) + +#define SC2355_FSYNC_RISING_MARGIN_TIME (600)//us +#define SC2355_FSYNC_RISING_MARGIN \ + SC2355_TIME_TO_EXP_LINE_US(SC2355_FSYNC_RISING_MARGIN_TIME) + +#define SC2355_EXP_REG_TO_FSYNC_RISING(exp_reg) \ + (exp_reg - 15 + SC2355_FSYNC_RISING_MARGIN) + +#define SC2355_DEFAULT_FSYNC_RISING \ + SC2355_EXP_REG_TO_FSYNC_RISING(SC2355_DEFAULT_EXP_REG) + +#define SC2355_DEFAULT_FSYNC_FALLING (0x4c0) +#define SC2355_DEFAULT_FSYNC_FALLING_BINNING (0x4c0/2 + 2) +#define SC2355_FSYNC_RISING_REG (0x3217) + +#define SLAVE_MODE +//slave mode max exp time (RB_ROW) +#define EXP_MAX_TIME_US (13*1000) +#define SC2355_SLAVE_RB_ROW SC2355_TIME_TO_EXP_LINE_US(EXP_MAX_TIME_US) + +#define BINNING_MODE + +static const char *const SC2355_supply_names[] = { "avdd", /* Analog power */ "dovdd", /* Digital I/O power */ "dvdd", /* Digital core power */ }; -#define SC2355_NUM_SUPPLIES ARRAY_SIZE(sc2355_supply_names) +#define SC2355_NUM_SUPPLIES ARRAY_SIZE(SC2355_supply_names) -enum sc2355_max_pad { - PAD0, - PAD1, - PAD2, - PAD3, - PAD_MAX, +enum { + LINK_FREQ_180M_INDEX, + LINK_FREQ_360M_INDEX, }; struct regval { @@ -118,22 +133,21 @@ u8 val; }; -struct sc2355_mode { - u32 bus_fmt; +struct SC2355_mode { u32 width; u32 height; struct v4l2_fract max_fps; u32 hts_def; u32 vts_def; u32 exp_def; + u32 link_freq_index; + u64 pixel_rate; const struct regval *reg_list; - u32 hdr_mode; - u32 mipi_freq_idx; - u32 bpp; - u32 vc[PAD_MAX]; + u32 lanes; + u32 bus_fmt; }; -struct sc2355 { +struct SC2355 { struct i2c_client *client; struct clk *xvclk; struct gpio_desc *reset_gpio; @@ -154,199 +168,366 @@ struct v4l2_ctrl *pixel_rate; struct v4l2_ctrl *link_freq; struct mutex mutex; + struct v4l2_fract cur_fps; + u32 cur_vts; bool streaming; bool power_on; - const struct sc2355_mode *cur_mode; - u32 cfg_num; + const struct SC2355_mode *cur_mode; u32 module_index; const char *module_facing; const char *module_name; const char *len_name; - bool has_init_exp; - u32 cur_vts; - struct preisp_hdrae_exp_s init_hdrae_exp; }; -#define to_sc2355(sd) container_of(sd, struct sc2355, subdev) +#define to_SC2355(sd) container_of(sd, struct SC2355, subdev) /* - * Xclk 24Mhz linear 640*480 30fps 37.125Mbps/lane + * Xclk 24Mhz + * Pclk 72Mhz + * linelength () + * framelength () + * grabwindow_width 800 + * grabwindow_height 600 + * mipi 1 lane + * max_framerate 30fps + * mipi_datarate per lane 360Mbps */ -static const struct regval sc2355_linear10bit_640x480_regs[] = { - {0x0103, 0x01}, - {0x0100, 0x00}, - {0x36e9, 0x80}, - {0x36ea, 0x0f}, - {0x36eb, 0x24}, - {0x36ed, 0x14}, - {0x36e9, 0x01}, - {0x301f, 0x07}, - {0x303f, 0x82}, - {0x3200, 0x00}, - {0x3201, 0x9c}, - {0x3202, 0x00}, - {0x3203, 0x74}, - {0x3204, 0x05}, - {0x3205, 0xab}, - {0x3206, 0x04}, - {0x3207, 0x43}, - {0x3208, 0x02}, - {0x3209, 0x80}, - {0x320a, 0x01}, - {0x320b, 0xe0}, - {0x320e, 0x02}, - {0x320f, 0x71}, - {0x3210, 0x00}, - {0x3211, 0x04}, - {0x3212, 0x00}, - {0x3213, 0x04}, - {0x3215, 0x31}, - {0x3220, 0x01}, - {0x3248, 0x02}, - {0x3253, 0x0a}, - {0x3301, 0xff}, - {0x3302, 0xff}, - {0x3303, 0x10}, - {0x3306, 0x28}, - {0x3307, 0x02}, - {0x330a, 0x00}, - {0x330b, 0xb0}, - {0x3318, 0x02}, - {0x3320, 0x06}, - {0x3321, 0x02}, - {0x3326, 0x12}, - {0x3327, 0x0e}, - {0x3328, 0x03}, - {0x3329, 0x0f}, - {0x3364, 0x4f}, - {0x33b3, 0x40}, - {0x33f9, 0x2c}, - {0x33fb, 0x38}, - {0x33fc, 0x0f}, - {0x33fd, 0x1f}, - {0x349f, 0x03}, - {0x34a6, 0x01}, - {0x34a7, 0x1f}, - {0x34a8, 0x40}, - {0x34a9, 0x30}, - {0x34ab, 0xa6}, - {0x34ad, 0xa6}, - {0x3622, 0x60}, - {0x3625, 0x08}, - {0x3630, 0xa8}, - {0x3631, 0x84}, - {0x3632, 0x90}, - {0x3633, 0x43}, - {0x3634, 0x09}, - {0x3635, 0x82}, - {0x3636, 0x48}, - {0x3637, 0xe4}, - {0x3641, 0x22}, - {0x3670, 0x0f}, - {0x3674, 0xc0}, - {0x3675, 0xc0}, - {0x3676, 0xc0}, - {0x3677, 0x86}, - {0x3678, 0x88}, - {0x3679, 0x8c}, - {0x367c, 0x01}, - {0x367d, 0x0f}, - {0x367e, 0x01}, - {0x367f, 0x0f}, - {0x3690, 0x43}, - {0x3691, 0x43}, - {0x3692, 0x53}, - {0x369c, 0x01}, - {0x369d, 0x1f}, - {0x369e, 0x8a}, - {0x369f, 0x9e}, - {0x36a0, 0xda}, - {0x36a1, 0x01}, - {0x36a2, 0x03}, - {0x3900, 0x0d}, - {0x3904, 0x06}, - {0x3905, 0x98}, - {0x391b, 0x81}, - {0x391c, 0x10}, - {0x391d, 0x19}, - {0x3933, 0x81}, - {0x3934, 0x82}, - {0x3940, 0x91}, - {0x3942, 0x01}, - {0x3943, 0x82}, - {0x3949, 0xc8}, - {0x394b, 0x64}, - {0x3952, 0x02}, - {0x3e00, 0x00}, - {0x3e01, 0x26}, - {0x3e02, 0xb0}, - {0x4502, 0x34}, - {0x4509, 0x30}, - {0x4819, 0x05}, - {0x481b, 0x03}, - {0x481d, 0x0a}, - {0x481f, 0x02}, - {0x4821, 0x08}, - {0x4823, 0x03}, - {0x4825, 0x02}, - {0x4827, 0x03}, - {0x4829, 0x04}, - {0x5000, 0x46}, - {0x5900, 0x01}, - {0x5901, 0x04}, - {REG_NULL, 0x00} +static const struct regval SC2355_1lane_10bit_360Mbps_800x600_30fps_regs[] = { + {0x0103,0x01}, + {0x0100,0x00}, + {0x36e9,0x80}, + {0x36ea,0x0f}, + {0x36eb,0x24}, + {0x36ed,0x14}, + {0x36e9,0x01}, + {0x301f,0x0c}, + {0x303f,0x82}, + {0x3208,0x03}, + {0x3209,0x20}, + {0x320a,0x02}, + {0x320b,0x58}, + {0x3211,0x02}, + {0x3213,0x02}, + {0x3215,0x31}, + {0x3220,0x01}, + {0x3248,0x02}, + {0x3253,0x0a}, + {0x3301,0xff}, + {0x3302,0xff}, + {0x3303,0x10}, + {0x3306,0x28}, + {0x3307,0x02}, + {0x330a,0x00}, + {0x330b,0xb0}, + {0x3318,0x02}, + {0x3320,0x06}, + {0x3321,0x02}, + {0x3326,0x12}, + {0x3327,0x0e}, + {0x3328,0x03}, + {0x3329,0x0f}, + {0x3364,0x4f}, + {0x33b3,0x40}, + {0x33f9,0x2c}, + {0x33fb,0x38}, + {0x33fc,0x0f}, + {0x33fd,0x1f}, + {0x349f,0x03}, + {0x34a6,0x01}, + {0x34a7,0x1f}, + {0x34a8,0x40}, + {0x34a9,0x30}, + {0x34ab,0xa6}, + {0x34ad,0xa6}, + {0x3622,0x60}, + {0x3623,0x40}, + {0x3624,0x61}, + {0x3625,0x08}, + {0x3626,0x03}, + {0x3630,0xa8}, + {0x3631,0x84}, + {0x3632,0x90}, + {0x3633,0x43}, + {0x3634,0x09}, + {0x3635,0x82}, + {0x3636,0x48}, + {0x3637,0xe4}, + {0x3641,0x22}, + {0x3670,0x0f}, + {0x3674,0xc0}, + {0x3675,0xc0}, + {0x3676,0xc0}, + {0x3677,0x86}, + {0x3678,0x88}, + {0x3679,0x8c}, + {0x367c,0x01}, + {0x367d,0x0f}, + {0x367e,0x01}, + {0x367f,0x0f}, + {0x3690,0x63}, + {0x3691,0x63}, + {0x3692,0x73}, + {0x369c,0x01}, + {0x369d,0x1f}, + {0x369e,0x8a}, + {0x369f,0x9e}, + {0x36a0,0xda}, + {0x36a1,0x01}, + {0x36a2,0x03}, + {0x3900,0x0d}, + {0x3904,0x04}, + {0x3905,0x98}, + {0x391b,0x81}, + {0x391c,0x10}, + {0x391d,0x19}, + {0x3933,0x01}, + {0x3934,0x82}, + {0x3940,0x5d}, + {0x3942,0x01}, + {0x3943,0x82}, + {0x3949,0xc8}, + {0x394b,0x64}, + {0x3952,0x02}, + {0x3e00,0x00}, + {0x3e01,0x4d}, + {0x3e02,0xe0}, + {0x4502,0x34}, + {0x4509,0x30}, + {0x450a,0x71}, + {0x4819,0x09}, + {0x481b,0x05}, + {0x481d,0x13}, + {0x481f,0x04}, + {0x4821,0x0a}, + {0x4823,0x05}, + {0x4825,0x04}, + {0x4827,0x05}, + {0x4829,0x08}, + {0x5000,0x46}, + {0x5900,0xf1}, //fix noise + {0x5901,0x04}, + + //vts + {0x320e,(SC2355_VTS>>8)&0xff}, + {0x320f,SC2355_VTS&0xff}, + + //exp + {0x3e00,SC2355_FETCH_3RD_BYTE_EXP(SC2355_DEFAULT_EXP_REG)}, + {0x3e01,SC2355_FETCH_2ND_BYTE_EXP(SC2355_DEFAULT_EXP_REG)}, + {0x3e02,SC2355_FETCH_1ST_BYTE_EXP(SC2355_DEFAULT_EXP_REG)}, + + //[flip] + {0x3221,0x3 << 5}, + + //[gain=1] + {0x3e09,0x00}, + + //fsync +#ifndef SLAVE_MODE + {0x300b,0x44},//FSYNC out + {0x3217,SC2355_DEFAULT_FSYNC_RISING}, + {0x322e,(SC2355_DEFAULT_FSYNC_FALLING_BINNING>>8)&0xff}, + {0x322f,SC2355_DEFAULT_FSYNC_FALLING_BINNING&0xff}, +#else + {0x3222, 0x01 << 1},//slave mode + {0x300a, 0x00 << 2},//input mode + + {0x3230, (SC2355_SLAVE_RB_ROW >> 8)&0xff}, + {0x3231, SC2355_SLAVE_RB_ROW & 0xff}, +#endif + + {REG_NULL, 0x00}, }; + /* - * 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 - * } + * Xclk 24Mhz + * Pclk 72Mhz + * linelength () + * framelength () + * grabwindow_width 1600 + * grabwindow_height 1200 + * mipi 1 lane + * max_framerate 30fps */ -static const struct sc2355_mode supported_modes[] = { +static const struct regval SC2355_1lane_10bit_1600x1200_30fps_regs[] = { + {0x0103,0x01}, + {0x0100,0x00}, + + {0x301f,0x01}, + {0x3248,0x02}, + {0x3253,0x0a}, + {0x3301,0xff}, + {0x3302,0xff}, + {0x3303,0x10}, + {0x3306,0x28}, + {0x3307,0x02}, + {0x330a,0x00}, + {0x330b,0xb0}, + {0x3318,0x02}, + {0x3320,0x06}, + {0x3321,0x02}, + {0x3326,0x12}, + {0x3327,0x0e}, + {0x3328,0x03}, + {0x3329,0x0f}, + {0x3364,0x4f}, + {0x33b3,0x40}, + {0x33f9,0x2c}, + {0x33fb,0x38}, + {0x33fc,0x0f}, + {0x33fd,0x1f}, + {0x349f,0x03}, + {0x34a6,0x01}, + {0x34a7,0x1f}, + {0x34a8,0x40}, + {0x34a9,0x30}, + {0x34ab,0xa6}, + {0x34ad,0xa6}, + {0x3622,0x60}, + {0x3623,0x40}, + {0x3624,0x61}, + {0x3625,0x08}, + {0x3626,0x03}, + {0x3630,0xa8}, + {0x3631,0x84}, + {0x3632,0x90}, + {0x3633,0x43}, + {0x3634,0x09}, + {0x3635,0x82}, + {0x3636,0x48}, + {0x3637,0xe4}, + {0x3641,0x22}, + {0x3670,0x0f}, + {0x3674,0xc0}, + {0x3675,0xc0}, + {0x3676,0xc0}, + {0x3677,0x86}, + {0x3678,0x88}, + {0x3679,0x8c}, + {0x367c,0x01}, + {0x367d,0x0f}, + {0x367e,0x01}, + {0x367f,0x0f}, + {0x3690,0x63}, + {0x3691,0x63}, + {0x3692,0x73}, + {0x369c,0x01}, + {0x369d,0x1f}, + {0x369e,0x8a}, + {0x369f,0x9e}, + {0x36a0,0xda}, + {0x36a1,0x01}, + {0x36a2,0x03}, + {0x36e9,0x01}, + {0x36ea,0x0f}, + {0x36eb,0x25}, + {0x36ed,0x04}, + {0x3900,0x0d}, + {0x3904,0x06}, + {0x3905,0x98}, + {0x391b,0x81}, + {0x391c,0x10}, + {0x391d,0x19}, + {0x3933,0x01}, + {0x3934,0x82}, + {0x3940,0x5d}, + {0x3942,0x01}, + {0x3943,0x82}, + {0x3949,0xc8}, + {0x394b,0x64}, + {0x3952,0x02}, + + //vts + {0x320e,(SC2355_VTS>>8)&0xff}, + {0x320f,SC2355_VTS&0xff}, + + {0x3e00, SC2355_FETCH_3RD_BYTE_EXP(SC2355_DEFAULT_EXP_REG)}, + {0x3e01, SC2355_FETCH_2ND_BYTE_EXP(SC2355_DEFAULT_EXP_REG)}, + {0x3e02, SC2355_FETCH_1ST_BYTE_EXP(SC2355_DEFAULT_EXP_REG)}, + {0x4502,0x34}, + {0x4509,0x30}, + {0x450a,0x71}, + + //[flip] + {0x3221,0x3 << 5}, + //[gain=2] + {0x3e09,0x01}, + +#ifndef SLAVE_MODE + {0x300b,0x44},//FSYNC out + {0x3217,SC2355_DEFAULT_FSYNC_RISING}, + {0x322e,(SC2355_DEFAULT_FSYNC_FALLING>>8)&0xff}, + {0x322f,SC2355_DEFAULT_FSYNC_FALLING&0xff}, +#else + {0x3222, 0x01 << 1},//slave mode + {0x300a, 0x00 << 2},//input mode + + {0x3230, (SC2355_SLAVE_RB_ROW >> 8)&0xff},//input mode + {0x3231, SC2355_SLAVE_RB_ROW & 0xff},//input mode +#endif +}; + +static const struct SC2355_mode supported_modes[] = { +#ifdef BINNING_MODE { - /* linear modes */ - .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, - .width = 640, - .height = 480, + .width = 800, + .height = 600, .max_fps = { .numerator = 10000, - .denominator = 600000, + .denominator = 300000, }, - .exp_def = 0x026b, - .hts_def = 0x0554, - .vts_def = 0x0271, - .reg_list = sc2355_linear10bit_640x480_regs, - .hdr_mode = NO_HDR, - .mipi_freq_idx = 0, - .bpp = 10, - .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, + .exp_def = SC2355_DEFAULT_EXP_REG, + .hts_def = 0x640, + .vts_def = SC2355_VTS, + .link_freq_index = LINK_FREQ_360M_INDEX, + .pixel_rate = PIXEL_RATE_WITH_360M, + .reg_list = SC2355_1lane_10bit_360Mbps_800x600_30fps_regs, + .lanes = 1, + .bus_fmt = MEDIA_BUS_FMT_Y10_1X10, }, +#else + { + .width = 1600, + .height = 1200, + .max_fps = { + .numerator = 10000, + .denominator = 300000, + }, + .exp_def = SC2355_DEFAULT_EXP_REG, + .hts_def = 0x640, + .vts_def = SC2355_VTS, + .link_freq_index = LINK_FREQ_360M_INDEX, + .pixel_rate = PIXEL_RATE_WITH_360M, + .reg_list = SC2355_1lane_10bit_1600x1200_30fps_regs, + .lanes = 1, + .bus_fmt = MEDIA_BUS_FMT_Y10_1X10, + }, +#endif }; -static const s64 link_freq_items[] = { +static const char *const SC2355_test_pattern_menu[] = { + "Disabled", + "Vertical Color Bar Type 1", + "Vertical Color Bar Type 2", + "Vertical Color Bar Type 3", + "Vertical Color Bar Type 4" +}; + +static const s64 link_freq_menu_items[] = { + MIPI_FREQ_180M, MIPI_FREQ_360M, }; -static const char * const sc2355_test_pattern_menu[] = { - "Disabled", - "Vertical Color Bar Type 1" -}; - /* Write registers up to 4 at a time */ -static int sc2355_write_reg(struct i2c_client *client, u16 reg, - u32 len, u32 val) +static int SC2355_write_reg(struct i2c_client *client, + u16 reg, u32 len, u32 val) { u32 buf_i, val_i; u8 buf[6]; u8 *val_p; __be32 val_be; + u32 ret; if (len > 4) return -EINVAL; @@ -362,30 +543,30 @@ while (val_i < 4) buf[buf_i++] = val_p[val_i++]; - if (i2c_master_send(client, buf, len + 2) != len + 2) + ret = i2c_master_send(client, buf, len + 2); + if (ret != len + 2) return -EIO; return 0; } -static int sc2355_write_array(struct i2c_client *client, - const struct regval *regs) +static int SC2355_write_array(struct i2c_client *client, + const struct regval *regs) { u32 i; int ret = 0; for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++) { - ret |= sc2355_write_reg(client, regs[i].addr, - SC2355_REG_VALUE_08BIT, regs[i].val); + ret = SC2355_write_reg(client, regs[i].addr, + SC2355_REG_VALUE_08BIT, regs[i].val); } + return ret; } /* Read registers up to 4 at a time */ -static int sc2355_read_reg(struct i2c_client *client, - u16 reg, - unsigned int len, - u32 *val) +static int SC2355_read_reg(struct i2c_client *client, + u16 reg, unsigned int len, u32 *val) { struct i2c_msg msgs[2]; u8 *data_be_p; @@ -418,15 +599,15 @@ return 0; } -static int sc2355_get_reso_dist(const struct sc2355_mode *mode, - struct v4l2_mbus_framefmt *framefmt) +static int SC2355_get_reso_dist(const struct SC2355_mode *mode, + struct v4l2_mbus_framefmt *framefmt) { return abs(mode->width - framefmt->width) + abs(mode->height - framefmt->height); } -static const struct sc2355_mode * -sc2355_find_best_fit(struct sc2355 *sc2355, struct v4l2_subdev_format *fmt) +static const struct SC2355_mode * +SC2355_find_best_fit(struct v4l2_subdev_format *fmt) { struct v4l2_mbus_framefmt *framefmt = &fmt->format; int dist; @@ -434,10 +615,10 @@ int cur_best_fit_dist = -1; unsigned int i; - for (i = 0; i < sc2355->cfg_num; i++) { - dist = sc2355_get_reso_dist(&supported_modes[i], framefmt); - if ((cur_best_fit_dist == -1 || dist <= cur_best_fit_dist) && - (supported_modes[i].bus_fmt == framefmt->code)) { + for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { + dist = SC2355_get_reso_dist(&supported_modes[i], framefmt); + if ((cur_best_fit_dist == -1 || dist < cur_best_fit_dist) && + (supported_modes[i].bus_fmt == framefmt->code)) { cur_best_fit_dist = dist; cur_best_fit = i; } @@ -445,26 +626,17 @@ return &supported_modes[cur_best_fit]; } -static void sc2355_change_mode(struct sc2355 *sc2355, const struct sc2355_mode *mode) +static int SC2355_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) { - sc2355->cur_mode = mode; - sc2355->cur_vts = sc2355->cur_mode->vts_def; - dev_info(&sc2355->client->dev, "set fmt: cur_mode: %dx%d, hdr: %d\n", - mode->width, mode->height, mode->hdr_mode); -} - -static int sc2355_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct sc2355 *sc2355 = to_sc2355(sd); - const struct sc2355_mode *mode; + struct SC2355 *SC2355 = to_SC2355(sd); + const struct SC2355_mode *mode; s64 h_blank, vblank_def; - u64 pixel_rate = 0; - mutex_lock(&sc2355->mutex); + mutex_lock(&SC2355->mutex); - mode = sc2355_find_best_fit(sc2355, fmt); + mode = SC2355_find_best_fit(fmt); fmt->format.code = mode->bus_fmt; fmt->format.width = mode->width; fmt->format.height = mode->height; @@ -473,40 +645,42 @@ #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format; #else - mutex_unlock(&sc2355->mutex); + mutex_unlock(&SC2355->mutex); return -ENOTTY; #endif } else { - sc2355_change_mode(sc2355, mode); + SC2355->cur_mode = mode; h_blank = mode->hts_def - mode->width; - __v4l2_ctrl_modify_range(sc2355->hblank, h_blank, + __v4l2_ctrl_modify_range(SC2355->hblank, h_blank, h_blank, 1, h_blank); vblank_def = mode->vts_def - mode->height; - __v4l2_ctrl_modify_range(sc2355->vblank, vblank_def, + __v4l2_ctrl_modify_range(SC2355->vblank, vblank_def, SC2355_VTS_MAX - mode->height, 1, vblank_def); - __v4l2_ctrl_s_ctrl(sc2355->link_freq, mode->mipi_freq_idx); - pixel_rate = (u32)link_freq_items[mode->mipi_freq_idx] / - mode->bpp * 2 * SC2355_LANES; - __v4l2_ctrl_s_ctrl_int64(sc2355->pixel_rate, pixel_rate); + __v4l2_ctrl_s_ctrl_int64(SC2355->pixel_rate, mode->pixel_rate); + __v4l2_ctrl_s_ctrl(SC2355->link_freq, mode->link_freq_index); + SC2355->cur_vts = mode->vts_def; + SC2355->cur_fps = mode->max_fps; } - mutex_unlock(&sc2355->mutex); + + mutex_unlock(&SC2355->mutex); + return 0; } -static int sc2355_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) +static int SC2355_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) { - struct sc2355 *sc2355 = to_sc2355(sd); - const struct sc2355_mode *mode = sc2355->cur_mode; + struct SC2355 *SC2355 = to_SC2355(sd); + const struct SC2355_mode *mode = SC2355->cur_mode; - mutex_lock(&sc2355->mutex); + mutex_lock(&SC2355->mutex); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad); #else - mutex_unlock(&sc2355->mutex); + mutex_unlock(&SC2355->mutex); return -ENOTTY; #endif } else { @@ -514,231 +688,86 @@ fmt->format.height = mode->height; fmt->format.code = mode->bus_fmt; fmt->format.field = V4L2_FIELD_NONE; - if (fmt->pad < PAD_MAX && mode->hdr_mode != NO_HDR) - fmt->reserved[0] = mode->vc[fmt->pad]; - else - fmt->reserved[0] = mode->vc[PAD0]; } - mutex_unlock(&sc2355->mutex); + mutex_unlock(&SC2355->mutex); return 0; } -static int sc2355_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) +static int SC2355_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - struct sc2355 *sc2355 = to_sc2355(sd); + struct SC2355 *SC2355 = to_SC2355(sd); if (code->index != 0) return -EINVAL; - code->code = sc2355->cur_mode->bus_fmt; + code->code = SC2355->cur_mode->bus_fmt; return 0; } -static int sc2355_enum_frame_sizes(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) +static int SC2355_enum_frame_sizes(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) { - struct sc2355 *sc2355 = to_sc2355(sd); - - if (fse->index >= sc2355->cfg_num) + if (fse->index >= ARRAY_SIZE(supported_modes)) return -EINVAL; if (fse->code != supported_modes[fse->index].bus_fmt) return -EINVAL; - fse->min_width = supported_modes[fse->index].width; - fse->max_width = supported_modes[fse->index].width; + 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; return 0; } -static int sc2355_enable_test_pattern(struct sc2355 *sc2355, u32 pattern) +static int SC2355_enable_test_pattern(struct SC2355 *SC2355, u32 pattern) { - u32 val = 0; - int ret = 0; + u32 val; - ret = sc2355_read_reg(sc2355->client, SC2355_REG_TEST_PATTERN, - SC2355_REG_VALUE_08BIT, &val); if (pattern) - val |= SC2355_TEST_PATTERN_ENABLE; + val = (pattern - 1) | SC2355_TEST_PATTERN_ENABLE; else - val &= ~SC2355_TEST_PATTERN_ENABLE; - ret |= sc2355_write_reg(sc2355->client, SC2355_REG_TEST_PATTERN, - SC2355_REG_VALUE_08BIT, val); - return ret; + val = SC2355_TEST_PATTERN_DISABLE; + + return SC2355_write_reg(SC2355->client, SC2355_REG_TEST_PATTERN, + SC2355_REG_VALUE_08BIT, val); } -static int sc2355_g_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *fi) -{ - struct sc2355 *sc2355 = to_sc2355(sd); - const struct sc2355_mode *mode = sc2355->cur_mode; - - mutex_lock(&sc2355->mutex); - fi->interval = mode->max_fps; - mutex_unlock(&sc2355->mutex); - - return 0; -} - -static int sc2355_g_mbus_config(struct v4l2_subdev *sd, - struct v4l2_mbus_config *config) -{ - struct sc2355 *sc2355 = to_sc2355(sd); - const struct sc2355_mode *mode = sc2355->cur_mode; - u32 val = 0; - - if (mode->hdr_mode == NO_HDR) - val = 1 << (SC2355_LANES - 1) | - V4L2_MBUS_CSI2_CHANNEL_0 | - V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; - if (mode->hdr_mode == HDR_X2) - val = 1 << (SC2355_LANES - 1) | - V4L2_MBUS_CSI2_CHANNEL_0 | - V4L2_MBUS_CSI2_CONTINUOUS_CLOCK | - V4L2_MBUS_CSI2_CHANNEL_1; - - config->type = V4L2_MBUS_CSI2; - config->flags = val; - - return 0; -} - -static void sc2355_get_module_inf(struct sc2355 *sc2355, - struct rkmodule_inf *inf) +static void SC2355_get_module_inf(struct SC2355 *SC2355, + struct rkmodule_inf *inf) { memset(inf, 0, sizeof(*inf)); strscpy(inf->base.sensor, SC2355_NAME, sizeof(inf->base.sensor)); - strscpy(inf->base.module, sc2355->module_name, + strscpy(inf->base.module, SC2355->module_name, sizeof(inf->base.module)); - strscpy(inf->base.lens, sc2355->len_name, sizeof(inf->base.lens)); + strscpy(inf->base.lens, SC2355->len_name, sizeof(inf->base.lens)); } - -static void sc2355_get_gain(u32 total_gain, u32 *again_reg, u32 *dgain_reg, u32 *dgain_fine_reg) +static long SC2355_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { - u32 again = 0; - u32 dgain = 0, dgain_fine = 0; - - if (total_gain < 0x0100) {/* 1x gain ~ 2x gain */ - again = 0x00; - - dgain = 0x00; - dgain_fine = total_gain; - } else if (total_gain < 0x0200) { /* 2x gain ~ 4x gain */ - again = 0x01; - - dgain = 0x00; - dgain_fine = total_gain >> 1; - } else if (total_gain < 0x0400) { /* 4x gain ~ 8x gain */ - again = 0x03; - - dgain = 0x00; - dgain_fine = total_gain >> 2; - } else if (total_gain < 0x0800) { /* 8x gain ~ 16x gain */ - again = 0x07; - - dgain = 0x00; - dgain_fine = total_gain >> 3; - } else if (total_gain < 0x1000) { /* 16x gain ~ 32x gain */ - again = 0xF; - - dgain = 0x00; - dgain_fine = total_gain >> 4; - } else if (total_gain < 0x2000) { /* 32x gain ~ 64x gain */ - again = 0x1F; - - dgain = 0x00; - dgain_fine = total_gain >> 5; - } else if (total_gain < 0x4000) { /* 64x gain ~ 128x gain */ - again = 0x1F; - - dgain = 0x01; - dgain_fine = total_gain >> 6; - } else if (total_gain < 0x8000) { /* 128x gain ~ 256x gain */ - again = 0x1F; - - dgain = 0x03; - dgain_fine = total_gain >> 7; - } - - *again_reg = again; - *dgain_reg = dgain; - *dgain_fine_reg = dgain_fine; -} -static long sc2355_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - struct sc2355 *sc2355 = to_sc2355(sd); - struct rkmodule_hdr_cfg *hdr_cfg; - const struct sc2355_mode *mode; + struct SC2355 *SC2355 = to_SC2355(sd); long ret = 0; - u64 pixel_rate = 0; - u32 i, h, w, stream; + u32 stream = 0; switch (cmd) { - case RKMODULE_SET_HDR_CFG: - hdr_cfg = (struct rkmodule_hdr_cfg *)arg; - if (sc2355->streaming) { - ret = sc2355_write_array(sc2355->client, sc2355->cur_mode->reg_list); - if (ret) - return ret; - } - w = sc2355->cur_mode->width; - h = sc2355->cur_mode->height; - for (i = 0; i < sc2355->cfg_num; i++) { - if (w == supported_modes[i].width && - h == supported_modes[i].height && - supported_modes[i].hdr_mode == hdr_cfg->hdr_mode) { - sc2355_change_mode(sc2355, &supported_modes[i]); - break; - } - } - - if (i == sc2355->cfg_num) { - dev_err(&sc2355->client->dev, - "not find hdr mode:%d %dx%d config\n", - hdr_cfg->hdr_mode, w, h); - ret = -EINVAL; - } else { - mode = sc2355->cur_mode; - w = mode->hts_def - mode->width; - h = mode->vts_def - mode->height; - __v4l2_ctrl_modify_range(sc2355->hblank, w, w, 1, w); - __v4l2_ctrl_modify_range(sc2355->vblank, h, - SC2355_VTS_MAX - mode->height, - 1, h); - __v4l2_ctrl_s_ctrl(sc2355->link_freq, mode->mipi_freq_idx); - pixel_rate = (u32)link_freq_items[mode->mipi_freq_idx] / - mode->bpp * 2 * SC2355_LANES; - __v4l2_ctrl_s_ctrl_int64(sc2355->pixel_rate, - pixel_rate); - dev_info(&sc2355->client->dev, - "sensor mode: %d\n", mode->hdr_mode); - } - break; case RKMODULE_GET_MODULE_INFO: - sc2355_get_module_inf(sc2355, (struct rkmodule_inf *)arg); - break; - case RKMODULE_GET_HDR_CFG: - hdr_cfg = (struct rkmodule_hdr_cfg *)arg; - hdr_cfg->esp.mode = HDR_NORMAL_VC; - hdr_cfg->hdr_mode = sc2355->cur_mode->hdr_mode; + SC2355_get_module_inf(SC2355, (struct rkmodule_inf *)arg); break; case RKMODULE_SET_QUICK_STREAM: stream = *((u32 *)arg); if (stream) - ret = sc2355_write_reg(sc2355->client, SC2355_REG_CTRL_MODE, - SC2355_REG_VALUE_08BIT, SC2355_MODE_STREAMING); + ret = SC2355_write_reg(SC2355->client, SC2355_REG_CTRL_MODE, + SC2355_REG_VALUE_08BIT, SC2355_MODE_STREAMING); else - ret = sc2355_write_reg(sc2355->client, SC2355_REG_CTRL_MODE, - SC2355_REG_VALUE_08BIT, SC2355_MODE_SW_STANDBY); + ret = SC2355_write_reg(SC2355->client, SC2355_REG_CTRL_MODE, + SC2355_REG_VALUE_08BIT, SC2355_MODE_SW_STANDBY); break; default: ret = -ENOIOCTLCMD; @@ -749,16 +778,12 @@ } #ifdef CONFIG_COMPAT -static long sc2355_compat_ioctl32(struct v4l2_subdev *sd, - unsigned int cmd, unsigned long arg) +static long SC2355_compat_ioctl32(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) { 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 = 0; - u32 cg = 0; u32 stream = 0; switch (cmd) { @@ -769,80 +794,19 @@ return ret; } - ret = sc2355_ioctl(sd, cmd, inf); + ret = SC2355_ioctl(sd, cmd, inf); if (!ret) { ret = copy_to_user(up, inf, sizeof(*inf)); if (ret) - return -EFAULT; + ret = -EFAULT; } kfree(inf); - break; - case RKMODULE_AWB_CFG: - cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); - if (!cfg) { - ret = -ENOMEM; - return ret; - } - - if (copy_from_user(cfg, up, sizeof(*cfg))) { - kfree(cfg); - return -EFAULT; - } - ret = sc2355_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 = sc2355_ioctl(sd, cmd, hdr); - if (!ret) { - ret = copy_to_user(up, hdr, sizeof(*hdr)); - if (ret) - return -EFAULT; - } - kfree(hdr); - break; - case RKMODULE_SET_HDR_CFG: - hdr = kzalloc(sizeof(*hdr), GFP_KERNEL); - if (!hdr) { - ret = -ENOMEM; - return ret; - } - - if (copy_from_user(hdr, up, sizeof(*hdr))) { - kfree(hdr); - return -EFAULT; - } - ret = sc2355_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; - } - - if (copy_from_user(hdrae, up, sizeof(*hdrae))) { - kfree(hdrae); - return -EFAULT; - } - ret = sc2355_ioctl(sd, cmd, hdrae); - kfree(hdrae); - break; - case RKMODULE_SET_CONVERSION_GAIN: - if (copy_from_user(&cg, up, sizeof(cg))) - return -EFAULT; - ret = sc2355_ioctl(sd, cmd, &cg); break; case RKMODULE_SET_QUICK_STREAM: if (copy_from_user(&stream, up, sizeof(u32))) return -EFAULT; - ret = sc2355_ioctl(sd, cmd, &stream); + + ret = SC2355_ioctl(sd, cmd, &stream); break; default: ret = -ENOIOCTLCMD; @@ -853,50 +817,69 @@ } #endif -static int __sc2355_start_stream(struct sc2355 *sc2355) +static int SC2355_set_ctrl_gain(struct SC2355 *SC2355, u32 a_gain) +{ + int ret = 0; + + if (a_gain > 1) + a_gain = ((a_gain + 1) >> 1) << 1; + a_gain -=1; + + ret |= SC2355_write_reg(SC2355->client, + SC2355_REG_COARSE_AGAIN, + SC2355_REG_VALUE_08BIT, + a_gain); + + return ret; +} + + +static int __SC2355_start_stream(struct SC2355 *SC2355) { int ret; - ret = sc2355_write_array(sc2355->client, sc2355->cur_mode->reg_list); - if (ret) - return ret; - - ret = __v4l2_ctrl_handler_setup(&sc2355->ctrl_handler); + ret = SC2355_write_array(SC2355->client, SC2355->cur_mode->reg_list); if (ret) return ret; /* In case these controls are set before streaming */ - if (sc2355->has_init_exp && sc2355->cur_mode->hdr_mode != NO_HDR) { - ret = sc2355_ioctl(&sc2355->subdev, PREISP_CMD_SET_HDRAE_EXP, - &sc2355->init_hdrae_exp); - if (ret) { - dev_err(&sc2355->client->dev, - "init exp fail in hdr mode\n"); - return ret; - } - } + mutex_unlock(&SC2355->mutex); + ret = v4l2_ctrl_handler_setup(&SC2355->ctrl_handler); + mutex_lock(&SC2355->mutex); + if (ret) + return ret; - return sc2355_write_reg(sc2355->client, SC2355_REG_CTRL_MODE, - SC2355_REG_VALUE_08BIT, SC2355_MODE_STREAMING); + ret = SC2355_write_reg(SC2355->client, SC2355_REG_CTRL_MODE, + SC2355_REG_VALUE_08BIT, SC2355_MODE_STREAMING); + + return ret; } -static int __sc2355_stop_stream(struct sc2355 *sc2355) +static int __SC2355_stop_stream(struct SC2355 *SC2355) { - sc2355->has_init_exp = false; - return sc2355_write_reg(sc2355->client, SC2355_REG_CTRL_MODE, - SC2355_REG_VALUE_08BIT, SC2355_MODE_SW_STANDBY); + return SC2355_write_reg(SC2355->client, SC2355_REG_CTRL_MODE, + SC2355_REG_VALUE_08BIT, SC2355_MODE_SW_STANDBY); } -static int sc2355_s_stream(struct v4l2_subdev *sd, int on) +static int SC2355_s_stream(struct v4l2_subdev *sd, int on) { - struct sc2355 *sc2355 = to_sc2355(sd); - struct i2c_client *client = sc2355->client; + struct SC2355 *SC2355 = to_SC2355(sd); + struct i2c_client *client = SC2355->client; + unsigned int fps; int ret = 0; - mutex_lock(&sc2355->mutex); + mutex_lock(&SC2355->mutex); on = !!on; - if (on == sc2355->streaming) + if (on == SC2355->streaming) goto unlock_and_return; + + fps = DIV_ROUND_CLOSEST(SC2355->cur_mode->max_fps.denominator, + SC2355->cur_mode->max_fps.numerator); + + dev_info(&SC2355->client->dev, "%s: on: %d, %dx%d@%d\n", __func__, on, + SC2355->cur_mode->width, + SC2355->cur_mode->height, + fps); if (on) { ret = pm_runtime_get_sync(&client->dev); @@ -905,35 +888,35 @@ goto unlock_and_return; } - ret = __sc2355_start_stream(sc2355); + ret = __SC2355_start_stream(SC2355); if (ret) { v4l2_err(sd, "start stream failed while write regs\n"); pm_runtime_put(&client->dev); goto unlock_and_return; } } else { - __sc2355_stop_stream(sc2355); + __SC2355_stop_stream(SC2355); pm_runtime_put(&client->dev); } - sc2355->streaming = on; + SC2355->streaming = on; unlock_and_return: - mutex_unlock(&sc2355->mutex); + mutex_unlock(&SC2355->mutex); return ret; } -static int sc2355_s_power(struct v4l2_subdev *sd, int on) +static int SC2355_s_power(struct v4l2_subdev *sd, int on) { - struct sc2355 *sc2355 = to_sc2355(sd); - struct i2c_client *client = sc2355->client; + struct SC2355 *SC2355 = to_SC2355(sd); + struct i2c_client *client = SC2355->client; int ret = 0; - mutex_lock(&sc2355->mutex); + mutex_lock(&SC2355->mutex); /* If the power state is not modified - no work to do. */ - if (sc2355->power_on == !!on) + if (SC2355->power_on == !!on) goto unlock_and_return; if (on) { @@ -942,282 +925,290 @@ pm_runtime_put_noidle(&client->dev); goto unlock_and_return; } - - ret |= sc2355_write_reg(sc2355->client, - SC2355_SOFTWARE_RESET_REG, - SC2355_REG_VALUE_08BIT, - 0x01); - usleep_range(100, 200); - - sc2355->power_on = true; + SC2355->power_on = true; } else { pm_runtime_put(&client->dev); - sc2355->power_on = false; + SC2355->power_on = false; } unlock_and_return: - mutex_unlock(&sc2355->mutex); + mutex_unlock(&SC2355->mutex); return ret; } -static int __sc2355_power_on(struct sc2355 *sc2355) +static int SC2355_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + struct SC2355 *SC2355 = to_SC2355(sd); + const struct SC2355_mode *mode = SC2355->cur_mode; + + if (SC2355->streaming) + fi->interval = SC2355->cur_fps; + else + fi->interval = mode->max_fps; + + return 0; +} + +/* Calculate the delay in us by clock rate and clock cycles */ +static inline u32 SC2355_cal_delay(u32 cycles) +{ + return DIV_ROUND_UP(cycles, SC2355_XVCLK_FREQ / 1000 / 1000); +} + +static int __SC2355_power_on(struct SC2355 *SC2355) { int ret; - struct device *dev = &sc2355->client->dev; + u32 delay_us; + struct device *dev = &SC2355->client->dev; - if (!IS_ERR_OR_NULL(sc2355->pins_default)) { - ret = pinctrl_select_state(sc2355->pinctrl, - sc2355->pins_default); + if (!IS_ERR_OR_NULL(SC2355->pins_default)) { + ret = pinctrl_select_state(SC2355->pinctrl, + SC2355->pins_default); if (ret < 0) dev_err(dev, "could not set pins\n"); } - ret = clk_set_rate(sc2355->xvclk, SC2355_XVCLK_FREQ); + + ret = clk_set_rate(SC2355->xvclk, SC2355_XVCLK_FREQ); if (ret < 0) dev_warn(dev, "Failed to set xvclk rate (24MHz)\n"); - if (clk_get_rate(sc2355->xvclk) != SC2355_XVCLK_FREQ) + if (clk_get_rate(SC2355->xvclk) != SC2355_XVCLK_FREQ) dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n"); - ret = clk_prepare_enable(sc2355->xvclk); + ret = clk_prepare_enable(SC2355->xvclk); if (ret < 0) { dev_err(dev, "Failed to enable xvclk\n"); return ret; } - if (!IS_ERR(sc2355->reset_gpio)) - gpiod_set_value_cansleep(sc2355->reset_gpio, 1); - ret = regulator_bulk_enable(SC2355_NUM_SUPPLIES, sc2355->supplies); + ret = regulator_bulk_enable(SC2355_NUM_SUPPLIES, SC2355->supplies); if (ret < 0) { dev_err(dev, "Failed to enable regulators\n"); goto disable_clk; } - if (!IS_ERR(sc2355->reset_gpio)) - gpiod_set_value_cansleep(sc2355->reset_gpio, 0); + if (!IS_ERR(SC2355->reset_gpio)) + gpiod_set_value_cansleep(SC2355->reset_gpio, 1); - usleep_range(500, 1000); - if (!IS_ERR(sc2355->pwdn_gpio)) - gpiod_set_value_cansleep(sc2355->pwdn_gpio, 0); - usleep_range(2000, 4000); + usleep_range(1000, 2000); + + if (!IS_ERR(SC2355->pwdn_gpio)) + gpiod_set_value_cansleep(SC2355->pwdn_gpio, 1); + + if (!IS_ERR(SC2355->reset_gpio)) + gpiod_set_value_cansleep(SC2355->reset_gpio, 0); + + /* 8192 cycles prior to first SCCB transaction */ + delay_us = SC2355_cal_delay(8192); + usleep_range(delay_us, delay_us * 2); return 0; disable_clk: - clk_disable_unprepare(sc2355->xvclk); + clk_disable_unprepare(SC2355->xvclk); return ret; } -static void __sc2355_power_off(struct sc2355 *sc2355) +static void __SC2355_power_off(struct SC2355 *SC2355) { int ret; - struct device *dev = &sc2355->client->dev; - if (!IS_ERR(sc2355->pwdn_gpio)) - gpiod_set_value_cansleep(sc2355->pwdn_gpio, 1); - clk_disable_unprepare(sc2355->xvclk); - if (!IS_ERR(sc2355->reset_gpio)) - gpiod_set_value_cansleep(sc2355->reset_gpio, 1); - if (!IS_ERR_OR_NULL(sc2355->pins_sleep)) { - ret = pinctrl_select_state(sc2355->pinctrl, - sc2355->pins_sleep); + if (!IS_ERR(SC2355->reset_gpio)) + gpiod_set_value_cansleep(SC2355->reset_gpio, 1); + + if (!IS_ERR(SC2355->pwdn_gpio)) + gpiod_set_value_cansleep(SC2355->pwdn_gpio, 0); + clk_disable_unprepare(SC2355->xvclk); + if (!IS_ERR_OR_NULL(SC2355->pins_sleep)) { + ret = pinctrl_select_state(SC2355->pinctrl, + SC2355->pins_sleep); if (ret < 0) - dev_dbg(dev, "could not set pins\n"); + dev_dbg(&SC2355->client->dev, "could not set pins\n"); } - regulator_bulk_disable(SC2355_NUM_SUPPLIES, sc2355->supplies); + regulator_bulk_disable(SC2355_NUM_SUPPLIES, SC2355->supplies); } -static int sc2355_runtime_resume(struct device *dev) +static int SC2355_runtime_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct sc2355 *sc2355 = to_sc2355(sd); + struct SC2355 *SC2355 = to_SC2355(sd); - return __sc2355_power_on(sc2355); + return __SC2355_power_on(SC2355); } -static int sc2355_runtime_suspend(struct device *dev) +static int SC2355_runtime_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct sc2355 *sc2355 = to_sc2355(sd); + struct SC2355 *SC2355 = to_SC2355(sd); - __sc2355_power_off(sc2355); + __SC2355_power_off(SC2355); return 0; } #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API -static int sc2355_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +static int SC2355_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - struct sc2355 *sc2355 = to_sc2355(sd); + struct SC2355 *SC2355 = to_SC2355(sd); struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_get_try_format(sd, fh->pad, 0); - const struct sc2355_mode *def_mode = &supported_modes[0]; + v4l2_subdev_get_try_format(sd, fh->pad, 0); + const struct SC2355_mode *def_mode = &supported_modes[0]; - mutex_lock(&sc2355->mutex); + mutex_lock(&SC2355->mutex); /* Initialize try_fmt */ try_fmt->width = def_mode->width; try_fmt->height = def_mode->height; try_fmt->code = def_mode->bus_fmt; try_fmt->field = V4L2_FIELD_NONE; - mutex_unlock(&sc2355->mutex); + mutex_unlock(&SC2355->mutex); /* No crop or compose */ return 0; } #endif -static int sc2355_enum_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_interval_enum *fie) +static int SC2355_enum_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_interval_enum *fie) { - struct sc2355 *sc2355 = to_sc2355(sd); - - if (fie->index >= sc2355->cfg_num) + if (fie->index >= ARRAY_SIZE(supported_modes)) 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; return 0; } -static const struct dev_pm_ops sc2355_pm_ops = { - SET_RUNTIME_PM_OPS(sc2355_runtime_suspend, - sc2355_runtime_resume, NULL) +static int SC2355_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id, + struct v4l2_mbus_config *config) +{ + u32 val = 0; + struct SC2355 *SC2355 = to_SC2355(sd); + + val = 1 << (SC2355->cur_mode->lanes - 1) | + V4L2_MBUS_CSI2_CHANNEL_0 | + V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; + config->type = V4L2_MBUS_CSI2_DPHY; + config->flags = val; + + return 0; +} + +static const struct dev_pm_ops SC2355_pm_ops = { + SET_RUNTIME_PM_OPS(SC2355_runtime_suspend, + SC2355_runtime_resume, NULL) }; #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API -static const struct v4l2_subdev_internal_ops sc2355_internal_ops = { - .open = sc2355_open, +static const struct v4l2_subdev_internal_ops SC2355_internal_ops = { + .open = SC2355_open, }; #endif -static const struct v4l2_subdev_core_ops sc2355_core_ops = { - .s_power = sc2355_s_power, - .ioctl = sc2355_ioctl, +static const struct v4l2_subdev_core_ops SC2355_core_ops = { + .s_power = SC2355_s_power, + .ioctl = SC2355_ioctl, #ifdef CONFIG_COMPAT - .compat_ioctl32 = sc2355_compat_ioctl32, + .compat_ioctl32 = SC2355_compat_ioctl32, #endif }; -static const struct v4l2_subdev_video_ops sc2355_video_ops = { - .s_stream = sc2355_s_stream, - .g_frame_interval = sc2355_g_frame_interval, - .g_mbus_config = sc2355_g_mbus_config, +static const struct v4l2_subdev_video_ops SC2355_video_ops = { + .s_stream = SC2355_s_stream, + .g_frame_interval = SC2355_g_frame_interval, }; -static const struct v4l2_subdev_pad_ops sc2355_pad_ops = { - .enum_mbus_code = sc2355_enum_mbus_code, - .enum_frame_size = sc2355_enum_frame_sizes, - .enum_frame_interval = sc2355_enum_frame_interval, - .get_fmt = sc2355_get_fmt, - .set_fmt = sc2355_set_fmt, +static const struct v4l2_subdev_pad_ops SC2355_pad_ops = { + .enum_mbus_code = SC2355_enum_mbus_code, + .enum_frame_size = SC2355_enum_frame_sizes, + .enum_frame_interval = SC2355_enum_frame_interval, + .get_fmt = SC2355_get_fmt, + .set_fmt = SC2355_set_fmt, + .get_mbus_config = SC2355_g_mbus_config, }; -static const struct v4l2_subdev_ops sc2355_subdev_ops = { - .core = &sc2355_core_ops, - .video = &sc2355_video_ops, - .pad = &sc2355_pad_ops, +static const struct v4l2_subdev_ops SC2355_subdev_ops = { + .core = &SC2355_core_ops, + .video = &SC2355_video_ops, + .pad = &SC2355_pad_ops, }; -static int sc2355_set_ctrl(struct v4l2_ctrl *ctrl) +static void SC2355_modify_fps_info(struct SC2355 *SC2355) { - struct sc2355 *sc2355 = container_of(ctrl->handler, - struct sc2355, ctrl_handler); - struct i2c_client *client = sc2355->client; + const struct SC2355_mode *mode = SC2355->cur_mode; + + SC2355->cur_fps.denominator = mode->max_fps.denominator * SC2355->cur_vts / + mode->vts_def; +} + +static int SC2355_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct SC2355 *SC2355 = container_of(ctrl->handler, + struct SC2355, ctrl_handler); + struct i2c_client *client = SC2355->client; s64 max; - u32 again, dgain, dgain_fine; int ret = 0; - u32 val; +#ifndef SLAVE_MODE + u16 rising_reg; +#endif /* Propagate change of current control to all related controls */ switch (ctrl->id) { case V4L2_CID_VBLANK: /* Update max exposure while meeting expected vblanking */ - max = sc2355->cur_mode->height + ctrl->val - 4; - __v4l2_ctrl_modify_range(sc2355->exposure, - sc2355->exposure->minimum, max, - sc2355->exposure->step, - sc2355->exposure->default_value); + max = SC2355->cur_mode->height + ctrl->val - 6; + __v4l2_ctrl_modify_range(SC2355->exposure, + SC2355->exposure->minimum, max, + SC2355->exposure->step, + SC2355->exposure->default_value); break; } + if (!pm_runtime_get_if_in_use(&client->dev)) return 0; switch (ctrl->id) { case V4L2_CID_EXPOSURE: - if (sc2355->cur_mode->hdr_mode != NO_HDR) - return ret; - ret = sc2355_write_reg(sc2355->client, SC2355_GROUP_HOLD, - SC2355_REG_VALUE_08BIT, - SC2355_GROUP_UPDATE_DATA_START); - ret |= sc2355_write_reg(sc2355->client, SC2355_REG_EXPOSURE, - SC2355_REG_VALUE_24BIT, ctrl->val << 4); - ret |= sc2355_write_reg(sc2355->client, SC2355_GROUP_HOLD, - SC2355_REG_VALUE_08BIT, - SC2355_GROUP_UPDATE_LAUNCH); + /* 4 least significant bits of expsoure are fractional part */ + ret = SC2355_write_reg(SC2355->client, SC2355_REG_EXPOSURE, + SC2355_REG_VALUE_16BIT, ctrl->val << 4); + +#ifndef SLAVE_MODE + /* set fsync rising */ + rising_reg = SC2355_EXP_REG_TO_FSYNC_RISING(ctrl->val); + if (rising_reg > 0xff) { + rising_reg = 0xff; + dev_warn(&client->dev, + "error: rising reg exceed max val 0xff.\n"); + } + + dev_info(&client->dev, "rising: reg:%d\n", rising_reg); + + ret |= SC2355_write_reg(SC2355->client, SC2355_FSYNC_RISING_REG, + SC2355_REG_VALUE_08BIT, rising_reg); +#endif + break; - case V4L2_CID_ANALOGUE_GAIN: - if (sc2355->cur_mode->hdr_mode != NO_HDR) - return ret; - sc2355_get_gain(ctrl->val, &again, &dgain, &dgain_fine); - - val = ctrl->val << 1; - - dev_dbg(&client->dev, "recv:%d set again 0x%x, set dgain 0x%x, dgain_fine 0x%x\n", - ctrl->val, again, dgain, dgain_fine); - - ret |= sc2355_write_reg(sc2355->client, - SC2355_REG_AGAIN, - SC2355_REG_VALUE_08BIT, - again); - ret |= sc2355_write_reg(sc2355->client, - SC2355_REG_DGAIN, - SC2355_REG_VALUE_08BIT, - dgain); - ret |= sc2355_write_reg(sc2355->client, - SC2355_REG_DGAIN_FINE, - SC2355_REG_VALUE_08BIT, - dgain_fine); + ret = SC2355_set_ctrl_gain(SC2355, ctrl->val); break; case V4L2_CID_VBLANK: - ret = sc2355_write_reg(sc2355->client, SC2355_REG_VTS, + ret = SC2355_write_reg(SC2355->client, SC2355_REG_VTS, SC2355_REG_VALUE_16BIT, - ctrl->val + sc2355->cur_mode->height); - dev_dbg(&client->dev, "set vblank 0x%x\n", - ctrl->val); + ctrl->val + SC2355->cur_mode->height); + if (!ret) + SC2355->cur_vts = ctrl->val + SC2355->cur_mode->height; + if (SC2355->cur_vts != SC2355->cur_mode->vts_def) + SC2355_modify_fps_info(SC2355); break; case V4L2_CID_TEST_PATTERN: - ret = sc2355_enable_test_pattern(sc2355, ctrl->val); - break; - case V4L2_CID_HFLIP: - ret = sc2355_read_reg(sc2355->client, SC2355_FLIP_REG, - SC2355_REG_VALUE_08BIT, &val); - if (ret) - break; - if (ctrl->val) - val |= SC2355_MIRROR_MASK; - else - val &= ~SC2355_MIRROR_MASK; - ret |= sc2355_write_reg(sc2355->client, SC2355_FLIP_REG, - SC2355_REG_VALUE_08BIT, val); - break; - case V4L2_CID_VFLIP: - ret = sc2355_read_reg(sc2355->client, SC2355_FLIP_REG, - SC2355_REG_VALUE_08BIT, &val); - if (ret) - break; - if (ctrl->val) - val |= SC2355_FLIP_MASK; - else - val &= ~SC2355_FLIP_MASK; - ret |= sc2355_write_reg(sc2355->client, SC2355_FLIP_REG, - SC2355_REG_VALUE_08BIT, val); + ret = SC2355_enable_test_pattern(SC2355, ctrl->val); break; default: dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n", @@ -1230,78 +1221,75 @@ return ret; } -static const struct v4l2_ctrl_ops sc2355_ctrl_ops = { - .s_ctrl = sc2355_set_ctrl, +static const struct v4l2_ctrl_ops SC2355_ctrl_ops = { + .s_ctrl = SC2355_set_ctrl, }; -static int sc2355_initialize_controls(struct sc2355 *sc2355) +static int SC2355_initialize_controls(struct SC2355 *SC2355) { - const struct sc2355_mode *mode; + const struct SC2355_mode *mode; struct v4l2_ctrl_handler *handler; s64 exposure_max, vblank_def; u32 h_blank; int ret; - u64 pixel_rate = 0; - handler = &sc2355->ctrl_handler; - mode = sc2355->cur_mode; - ret = v4l2_ctrl_handler_init(handler, 9); + handler = &SC2355->ctrl_handler; + mode = SC2355->cur_mode; + ret = v4l2_ctrl_handler_init(handler, 8); if (ret) return ret; - handler->lock = &sc2355->mutex; + handler->lock = &SC2355->mutex; - sc2355->link_freq = v4l2_ctrl_new_int_menu(handler, NULL, - V4L2_CID_LINK_FREQ, - ARRAY_SIZE(link_freq_items) - 1, 0, - link_freq_items); - __v4l2_ctrl_s_ctrl(sc2355->link_freq, mode->mipi_freq_idx); + SC2355->link_freq = v4l2_ctrl_new_int_menu(handler, + NULL, V4L2_CID_LINK_FREQ, + ARRAY_SIZE(link_freq_menu_items) - 1, 0, + link_freq_menu_items); - /* pixel rate = link frequency * 2 * lanes / BITS_PER_SAMPLE */ - pixel_rate = (u32)link_freq_items[mode->mipi_freq_idx] / mode->bpp * 2 * SC2355_LANES; - sc2355->pixel_rate = v4l2_ctrl_new_std(handler, NULL, - V4L2_CID_PIXEL_RATE, 0, SC2355_MAX_PIXEL_RATE, - 1, pixel_rate); + SC2355->pixel_rate = v4l2_ctrl_new_std(handler, NULL, + V4L2_CID_PIXEL_RATE, + 0, PIXEL_RATE_WITH_360M, + 1, mode->pixel_rate); + + __v4l2_ctrl_s_ctrl(SC2355->link_freq, mode->pixel_rate); h_blank = mode->hts_def - mode->width; - sc2355->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK, - h_blank, h_blank, 1, h_blank); - if (sc2355->hblank) - sc2355->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + SC2355->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK, + h_blank, h_blank, 1, h_blank); + if (SC2355->hblank) + SC2355->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; vblank_def = mode->vts_def - mode->height; - sc2355->vblank = v4l2_ctrl_new_std(handler, &sc2355_ctrl_ops, - V4L2_CID_VBLANK, vblank_def, - SC2355_VTS_MAX - mode->height, - 1, vblank_def); + SC2355->cur_vts = mode->vts_def; + SC2355->cur_fps = mode->max_fps; + SC2355->vblank = v4l2_ctrl_new_std(handler, &SC2355_ctrl_ops, + V4L2_CID_VBLANK, vblank_def, + SC2355_VTS_MAX - mode->height, + 1, vblank_def); - exposure_max = mode->vts_def - 3; - sc2355->exposure = v4l2_ctrl_new_std(handler, &sc2355_ctrl_ops, - V4L2_CID_EXPOSURE, SC2355_EXPOSURE_MIN, - exposure_max, SC2355_EXPOSURE_STEP, - mode->exp_def); + exposure_max = mode->vts_def - 6; + SC2355->exposure = v4l2_ctrl_new_std(handler, &SC2355_ctrl_ops, + V4L2_CID_EXPOSURE, SC2355_EXPOSURE_MIN, + exposure_max, SC2355_EXPOSURE_STEP, + mode->exp_def); - sc2355->anal_gain = v4l2_ctrl_new_std(handler, &sc2355_ctrl_ops, - V4L2_CID_ANALOGUE_GAIN, SC2355_GAIN_MIN, - SC2355_GAIN_MAX, SC2355_GAIN_STEP, - SC2355_GAIN_DEFAULT); + SC2355->anal_gain = v4l2_ctrl_new_std(handler, &SC2355_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, ANALOG_GAIN_MIN, + ANALOG_GAIN_MAX, ANALOG_GAIN_STEP, + ANALOG_GAIN_DEFAULT); - sc2355->test_pattern = v4l2_ctrl_new_std_menu_items(handler, - &sc2355_ctrl_ops, V4L2_CID_TEST_PATTERN, - ARRAY_SIZE(sc2355_test_pattern_menu) - 1, - 0, 0, sc2355_test_pattern_menu); - - v4l2_ctrl_new_std(handler, &sc2355_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(handler, &sc2355_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); + SC2355->test_pattern = v4l2_ctrl_new_std_menu_items(handler, + &SC2355_ctrl_ops, V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(SC2355_test_pattern_menu) - 1, + 0, 0, SC2355_test_pattern_menu); if (handler->error) { ret = handler->error; - dev_err(&sc2355->client->dev, + dev_err(&SC2355->client->dev, "Failed to init controls(%d)\n", ret); goto err_free_handler; } - sc2355->subdev.ctrl_handler = handler; - sc2355->has_init_exp = false; + SC2355->subdev.ctrl_handler = handler; return 0; @@ -1311,162 +1299,141 @@ return ret; } -static int sc2355_check_sensor_id(struct sc2355 *sc2355, - struct i2c_client *client) +static int SC2355_check_sensor_id(struct SC2355 *SC2355, + struct i2c_client *client) { - struct device *dev = &sc2355->client->dev; + struct device *dev = &SC2355->client->dev; u32 id = 0; int ret; - - ret = sc2355_read_reg(client, SC2355_REG_CHIP_ID, - SC2355_REG_VALUE_16BIT, &id); - if (id != CHIP_ID) { + ret = SC2355_read_reg(client, SC2355_REG_CHIP_ID, + SC2355_REG_VALUE_16BIT, &id); + if (ret || id != CHIP_ID) { dev_err(dev, "Unexpected sensor id(%04x), ret(%d)\n", id, ret); return -ENODEV; } - dev_info(dev, "Detected SC%04x sensor\n", CHIP_ID); + dev_info(dev, "Detected SC2355 CHIP ID = 0x%04x sensor\n", CHIP_ID); return 0; } -static int sc2355_configure_regulators(struct sc2355 *sc2355) +static int SC2355_configure_regulators(struct SC2355 *SC2355) { unsigned int i; for (i = 0; i < SC2355_NUM_SUPPLIES; i++) - sc2355->supplies[i].supply = sc2355_supply_names[i]; + SC2355->supplies[i].supply = SC2355_supply_names[i]; - return devm_regulator_bulk_get(&sc2355->client->dev, + return devm_regulator_bulk_get(&SC2355->client->dev, SC2355_NUM_SUPPLIES, - sc2355->supplies); + SC2355->supplies); } -static int sc2355_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int SC2355_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct device *dev = &client->dev; struct device_node *node = dev->of_node; - struct sc2355 *sc2355; + struct SC2355 *SC2355; struct v4l2_subdev *sd; char facing[2]; int ret; - u32 i, hdr_mode = 0; dev_info(dev, "driver version: %02x.%02x.%02x", DRIVER_VERSION >> 16, (DRIVER_VERSION & 0xff00) >> 8, DRIVER_VERSION & 0x00ff); - sc2355 = devm_kzalloc(dev, sizeof(*sc2355), GFP_KERNEL); - if (!sc2355) + SC2355 = devm_kzalloc(dev, sizeof(*SC2355), GFP_KERNEL); + if (!SC2355) return -ENOMEM; ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX, - &sc2355->module_index); + &SC2355->module_index); ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING, - &sc2355->module_facing); + &SC2355->module_facing); ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME, - &sc2355->module_name); + &SC2355->module_name); ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME, - &sc2355->len_name); + &SC2355->len_name); if (ret) { dev_err(dev, "could not get module information!\n"); return -EINVAL; } + SC2355->client = client; + SC2355->cur_mode = &supported_modes[0]; - ret = of_property_read_u32(node, OF_CAMERA_HDR_MODE, - &hdr_mode); - - if (ret) { - hdr_mode = NO_HDR; - dev_warn(dev, " Get hdr mode failed! no hdr default\n"); - } - - sc2355->cfg_num = ARRAY_SIZE(supported_modes); - for (i = 0; i < sc2355->cfg_num; i++) { - if (hdr_mode == supported_modes[i].hdr_mode) { - sc2355->cur_mode = &supported_modes[i]; - break; - } - } - sc2355->client = client; - - sc2355->xvclk = devm_clk_get(dev, "xvclk"); - if (IS_ERR(sc2355->xvclk)) { + SC2355->xvclk = devm_clk_get(dev, "xvclk"); + if (IS_ERR(SC2355->xvclk)) { dev_err(dev, "Failed to get xvclk\n"); return -EINVAL; } - sc2355->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(sc2355->reset_gpio)) + SC2355->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(SC2355->reset_gpio)) dev_warn(dev, "Failed to get reset-gpios\n"); - sc2355->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW); - if (IS_ERR(sc2355->pwdn_gpio)) + SC2355->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW); + if (IS_ERR(SC2355->pwdn_gpio)) dev_warn(dev, "Failed to get pwdn-gpios\n"); - - sc2355->pinctrl = devm_pinctrl_get(dev); - if (!IS_ERR(sc2355->pinctrl)) { - sc2355->pins_default = - pinctrl_lookup_state(sc2355->pinctrl, - OF_CAMERA_PINCTRL_STATE_DEFAULT); - if (IS_ERR(sc2355->pins_default)) - dev_err(dev, "could not get default pinstate\n"); - - sc2355->pins_sleep = - pinctrl_lookup_state(sc2355->pinctrl, - OF_CAMERA_PINCTRL_STATE_SLEEP); - if (IS_ERR(sc2355->pins_sleep)) - dev_err(dev, "could not get sleep pinstate\n"); - } else { - dev_err(dev, "no pinctrl\n"); - } - - ret = sc2355_configure_regulators(sc2355); + ret = SC2355_configure_regulators(SC2355); if (ret) { dev_err(dev, "Failed to get power regulators\n"); return ret; } - mutex_init(&sc2355->mutex); + SC2355->pinctrl = devm_pinctrl_get(dev); + if (!IS_ERR(SC2355->pinctrl)) { + SC2355->pins_default = + pinctrl_lookup_state(SC2355->pinctrl, + OF_CAMERA_PINCTRL_STATE_DEFAULT); + if (IS_ERR(SC2355->pins_default)) + dev_err(dev, "could not get default pinstate\n"); - sd = &sc2355->subdev; - v4l2_i2c_subdev_init(sd, client, &sc2355_subdev_ops); - ret = sc2355_initialize_controls(sc2355); + SC2355->pins_sleep = + pinctrl_lookup_state(SC2355->pinctrl, + OF_CAMERA_PINCTRL_STATE_SLEEP); + if (IS_ERR(SC2355->pins_sleep)) + dev_err(dev, "could not get sleep pinstate\n"); + } + mutex_init(&SC2355->mutex); + + sd = &SC2355->subdev; + v4l2_i2c_subdev_init(sd, client, &SC2355_subdev_ops); + ret = SC2355_initialize_controls(SC2355); if (ret) goto err_destroy_mutex; - ret = __sc2355_power_on(sc2355); + ret = __SC2355_power_on(SC2355); if (ret) goto err_free_handler; - ret = sc2355_check_sensor_id(sc2355, client); + ret = SC2355_check_sensor_id(SC2355, client); if (ret) goto err_power_off; #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API - sd->internal_ops = &sc2355_internal_ops; - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->internal_ops = &SC2355_internal_ops; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_HAS_EVENTS; #endif - #if defined(CONFIG_MEDIA_CONTROLLER) - sc2355->pad.flags = MEDIA_PAD_FL_SOURCE; + SC2355->pad.flags = MEDIA_PAD_FL_SOURCE; sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; - ret = media_entity_pads_init(&sd->entity, 1, &sc2355->pad); + ret = media_entity_pads_init(&sd->entity, 1, &SC2355->pad); if (ret < 0) goto err_power_off; #endif memset(facing, 0, sizeof(facing)); - if (strcmp(sc2355->module_facing, "back") == 0) + if (strcmp(SC2355->module_facing, "back") == 0) facing[0] = 'b'; else facing[0] = 'f'; snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s", - sc2355->module_index, facing, + SC2355->module_index, facing, SC2355_NAME, dev_name(sd->dev)); ret = v4l2_async_register_subdev_sensor_common(sd); if (ret) { @@ -1477,9 +1444,7 @@ pm_runtime_set_active(dev); pm_runtime_enable(dev); pm_runtime_idle(dev); -#ifdef USED_SYS_DEBUG - add_sysfs_interfaces(dev); -#endif + return 0; err_clean_entity: @@ -1487,75 +1452,71 @@ media_entity_cleanup(&sd->entity); #endif err_power_off: - __sc2355_power_off(sc2355); + __SC2355_power_off(SC2355); err_free_handler: - v4l2_ctrl_handler_free(&sc2355->ctrl_handler); + v4l2_ctrl_handler_free(&SC2355->ctrl_handler); err_destroy_mutex: - mutex_destroy(&sc2355->mutex); + mutex_destroy(&SC2355->mutex); return ret; } -static int sc2355_remove(struct i2c_client *client) +static int SC2355_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct sc2355 *sc2355 = to_sc2355(sd); + struct SC2355 *SC2355 = to_SC2355(sd); v4l2_async_unregister_subdev(sd); #if defined(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&sd->entity); #endif - v4l2_ctrl_handler_free(&sc2355->ctrl_handler); - mutex_destroy(&sc2355->mutex); + v4l2_ctrl_handler_free(&SC2355->ctrl_handler); + mutex_destroy(&SC2355->mutex); pm_runtime_disable(&client->dev); if (!pm_runtime_status_suspended(&client->dev)) - __sc2355_power_off(sc2355); + __SC2355_power_off(SC2355); pm_runtime_set_suspended(&client->dev); return 0; } #if IS_ENABLED(CONFIG_OF) -static const struct of_device_id sc2355_of_match[] = { +static const struct of_device_id SC2355_of_match[] = { { .compatible = "smartsens,sc2355" }, - { }, + {}, }; -MODULE_DEVICE_TABLE(of, sc2355_of_match); +MODULE_DEVICE_TABLE(of, SC2355_of_match); #endif -static const struct i2c_device_id sc2355_match_id[] = { +static const struct i2c_device_id SC2355_match_id[] = { { "smartsens,sc2355", 0 }, { }, }; -static struct i2c_driver sc2355_i2c_driver = { +static struct i2c_driver SC2355_i2c_driver = { .driver = { .name = SC2355_NAME, - .pm = &sc2355_pm_ops, - .of_match_table = of_match_ptr(sc2355_of_match), + .pm = &SC2355_pm_ops, + .of_match_table = of_match_ptr(SC2355_of_match), }, - .probe = &sc2355_probe, - .remove = &sc2355_remove, - .id_table = sc2355_match_id, + .probe = &SC2355_probe, + .remove = &SC2355_remove, + .id_table = SC2355_match_id, }; -#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT -module_i2c_driver(sc2355_i2c_driver); -#else static int __init sensor_mod_init(void) { - return i2c_add_driver(&sc2355_i2c_driver); + return i2c_add_driver(&SC2355_i2c_driver); } static void __exit sensor_mod_exit(void) { - i2c_del_driver(&sc2355_i2c_driver); + i2c_del_driver(&SC2355_i2c_driver); } device_initcall_sync(sensor_mod_init); module_exit(sensor_mod_exit); -#endif -MODULE_DESCRIPTION("Smartsens sc2355 sensor driver"); -MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Smartsens SC2355 sensor driver"); +MODULE_LICENSE("GPL"); -- Gitblit v1.6.2