From 2f7c68cb55ecb7331f2381deb497c27155f32faf Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Wed, 03 Jan 2024 09:43:39 +0000
Subject: [PATCH] update kernel to 5.10.198
---
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