media: i2c: sc850sl: Synchronize with the driver of kernel 5.10 branch
Signed-off-by: Su Yuefu <yuefu.su@rock-chips.com> Change-Id: Ie91a7f1a643da9ce76e06f331558e58bba546392
This commit is contained in:
@@ -5,9 +5,13 @@
|
||||
* Copyright (C) 2023 Rockchip Electronics Co., Ltd.
|
||||
*
|
||||
* V0.0X01.0X01 first version
|
||||
* V0.0X01.0X02 change power_gpio to pwdn_gpio
|
||||
* V0.0X01.0X03 support thunder boot
|
||||
* V0.0X01.0X04 support sleep/wake up
|
||||
*
|
||||
*/
|
||||
|
||||
//#define DEBUG
|
||||
// #define DEBUG
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
@@ -27,8 +31,9 @@
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/rk-preisp.h>
|
||||
#include "../platform/rockchip/isp/rkisp_tb_helper.h"
|
||||
#include "cam-sleep-wakeup.h"
|
||||
|
||||
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x01)
|
||||
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x04)
|
||||
|
||||
#ifndef V4L2_CID_DIGITAL_GAIN
|
||||
#define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN
|
||||
@@ -64,9 +69,9 @@
|
||||
#define SC850SL_REG_EXP_SF_M 0x3e04 //[7:0]
|
||||
#define SC850SL_REG_EXP_SF_L 0x3e05 //[7:4]
|
||||
|
||||
#define SC850SL_FETCH_EXP_H(VAL) (((VAL) >> 12) & 0xF)
|
||||
#define SC850SL_FETCH_EXP_M(VAL) (((VAL) >> 4) & 0xFF)
|
||||
#define SC850SL_FETCH_EXP_L(VAL) (((VAL) & 0xF) << 4)
|
||||
#define SC850SL_FETCH_EXP_H(VAL) (((VAL) >> 12) & 0xF)
|
||||
#define SC850SL_FETCH_EXP_M(VAL) (((VAL) >> 4) & 0xFF)
|
||||
#define SC850SL_FETCH_EXP_L(VAL) (((VAL) & 0xF) << 4)
|
||||
|
||||
/*gain*/
|
||||
//long frame and normal gain reg
|
||||
@@ -110,15 +115,18 @@
|
||||
|
||||
#define OF_CAMERA_PINCTRL_STATE_DEFAULT "rockchip,camera_default"
|
||||
#define OF_CAMERA_PINCTRL_STATE_SLEEP "rockchip,camera_sleep"
|
||||
|
||||
#define OF_CAMERA_HDR_MODE "rockchip,camera-hdr-mode"
|
||||
#define SC850SL_NAME "sc850sl"
|
||||
|
||||
#define ENABLE_NR 1
|
||||
#define SC850SL_LGAIN 0
|
||||
#define SC850SL_SGAIN 1
|
||||
|
||||
static const char * const sc850sl_supply_names[] = {
|
||||
"dvdd", // Digital core power
|
||||
"dovdd", // Digital I/O power
|
||||
"avdd", // Analog power
|
||||
};
|
||||
|
||||
#define SC850SL_NUM_SUPPLIES ARRAY_SIZE(sc850sl_supply_names)
|
||||
|
||||
struct regval {
|
||||
@@ -145,7 +153,7 @@ struct sc850sl {
|
||||
struct i2c_client *client;
|
||||
struct clk *xvclk;
|
||||
struct gpio_desc *reset_gpio;
|
||||
struct gpio_desc *power_gpio;
|
||||
struct gpio_desc *pwdn_gpio;
|
||||
struct regulator_bulk_data supplies[SC850SL_NUM_SUPPLIES];
|
||||
|
||||
struct pinctrl *pinctrl;
|
||||
@@ -167,7 +175,6 @@ struct sc850sl {
|
||||
struct v4l2_fract cur_fps;
|
||||
bool streaming;
|
||||
bool power_on;
|
||||
bool is_first_streamoff;
|
||||
const struct sc850sl_mode *cur_mode;
|
||||
u32 module_index;
|
||||
u32 cfg_num;
|
||||
@@ -176,10 +183,12 @@ struct sc850sl {
|
||||
const char *len_name;
|
||||
u32 cur_vts;
|
||||
bool has_init_exp;
|
||||
bool is_thunderboot;
|
||||
bool is_first_streamoff;
|
||||
struct preisp_hdrae_exp_s init_hdrae_exp;
|
||||
struct cam_sw_info *cam_sw_info;
|
||||
};
|
||||
|
||||
|
||||
#define to_sc850sl(sd) container_of(sd, struct sc850sl, subdev)
|
||||
|
||||
//cleaned_0x20_SC850SL_MIPI_24Minput_1C4D_1080Mbps_10bit_3840x2160_30fps_one_expo.ini
|
||||
@@ -266,7 +275,7 @@ static __maybe_unused const struct regval sc850sl_linear10bit_3840x2160_regs[] =
|
||||
{0x3637, 0x06},
|
||||
{0x3638, 0x26},
|
||||
{0x363b, 0x06},
|
||||
{0x363c, 0x08},
|
||||
{0x363c, 0x07},
|
||||
{0x363d, 0x05},
|
||||
{0x363e, 0x8f},
|
||||
{0x3648, 0xe0},
|
||||
@@ -285,12 +294,12 @@ static __maybe_unused const struct regval sc850sl_linear10bit_3840x2160_regs[] =
|
||||
{0x3905, 0x91},
|
||||
{0x391e, 0x83},
|
||||
{0x3928, 0x04},
|
||||
{0x3933, 0xa0},
|
||||
{0x3934, 0x0a},
|
||||
{0x3935, 0x68},
|
||||
{0x3933, 0x90},
|
||||
{0x3934, 0x10},
|
||||
{0x3935, 0x70},
|
||||
{0x3936, 0x00},
|
||||
{0x3937, 0x20},
|
||||
{0x3938, 0x0a},
|
||||
{0x3937, 0x10},
|
||||
{0x3938, 0x14},
|
||||
{0x3946, 0x20},
|
||||
{0x3961, 0x40},
|
||||
{0x3962, 0x40},
|
||||
@@ -342,6 +351,9 @@ static __maybe_unused const struct regval sc850sl_linear10bit_3840x2160_regs[] =
|
||||
{0x5795, 0x01},
|
||||
{0x5799, 0x06},
|
||||
{0x57a2, 0x60},
|
||||
{0x57ab, 0x7f},
|
||||
{0x57ac, 0x7f},
|
||||
{0x57ad, 0x7f},
|
||||
{0x59e0, 0xfe},
|
||||
{0x59e1, 0x40},
|
||||
{0x59e2, 0x38},
|
||||
@@ -375,6 +387,7 @@ static __maybe_unused const struct regval sc850sl_linear10bit_3840x2160_regs[] =
|
||||
* [gain >=2x] {0x363c, 0x07},
|
||||
*/
|
||||
{0x363c, 0x07},
|
||||
{0x5799, 0x77},
|
||||
{REG_NULL, 0x00},
|
||||
};
|
||||
|
||||
@@ -411,7 +424,9 @@ static const struct sc850sl_mode supported_modes[] = {
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
static const u32 bus_code[] = {
|
||||
MEDIA_BUS_FMT_SBGGR10_1X10,
|
||||
};
|
||||
|
||||
static const char * const sc850sl_test_pattern_menu[] = {
|
||||
"Disabled",
|
||||
@@ -520,10 +535,13 @@ sc850sl_find_best_fit(struct sc850sl *sc850sl, struct v4l2_subdev_format *fmt)
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
|
||||
dist = sc850sl_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) {
|
||||
if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) {
|
||||
cur_best_fit_dist = dist;
|
||||
cur_best_fit = i;
|
||||
} else if (dist == cur_best_fit_dist &&
|
||||
framefmt->code == supported_modes[i].bus_fmt) {
|
||||
cur_best_fit = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
dev_info(&sc850sl->client->dev, "%s: cur_best_fit(%d)",
|
||||
@@ -619,11 +637,9 @@ static int sc850sl_enum_mbus_code(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_mbus_code_enum *code)
|
||||
{
|
||||
struct sc850sl *sc850sl = to_sc850sl(sd);
|
||||
|
||||
if (code->index != 0)
|
||||
if (code->index >= ARRAY_SIZE(bus_code))
|
||||
return -EINVAL;
|
||||
code->code = sc850sl->cur_mode->bus_fmt;
|
||||
code->code = bus_code[code->index];
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -678,10 +694,78 @@ static int sc850sl_g_frame_interval(struct v4l2_subdev *sd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct sc850sl_mode *sc850sl_find_mode(struct sc850sl *sc850sl, int fps)
|
||||
{
|
||||
const struct sc850sl_mode *mode = NULL;
|
||||
const struct sc850sl_mode *match = NULL;
|
||||
int cur_fps = 0;
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < sc850sl->cfg_num; i++) {
|
||||
mode = &supported_modes[i];
|
||||
if (mode->width == sc850sl->cur_mode->width &&
|
||||
mode->height == sc850sl->cur_mode->height &&
|
||||
mode->hdr_mode == sc850sl->cur_mode->hdr_mode &&
|
||||
mode->bus_fmt == sc850sl->cur_mode->bus_fmt) {
|
||||
cur_fps = DIV_ROUND_CLOSEST(mode->max_fps.denominator, mode->max_fps.numerator);
|
||||
if (cur_fps == fps) {
|
||||
match = mode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
static int sc850sl_s_frame_interval(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_frame_interval *fi)
|
||||
{
|
||||
struct sc850sl *sc850sl = to_sc850sl(sd);
|
||||
const struct sc850sl_mode *mode = NULL;
|
||||
struct v4l2_fract *fract = &fi->interval;
|
||||
s64 h_blank, vblank_def;
|
||||
u64 pixel_rate = 0;
|
||||
int fps;
|
||||
|
||||
if (sc850sl->streaming)
|
||||
return -EBUSY;
|
||||
|
||||
if (fi->pad != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (fract->numerator == 0) {
|
||||
v4l2_err(sd, "error param, check interval param\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
fps = DIV_ROUND_CLOSEST(fract->denominator, fract->numerator);
|
||||
mode = sc850sl_find_mode(sc850sl, fps);
|
||||
if (mode == NULL) {
|
||||
v4l2_err(sd, "couldn't match fi\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sc850sl->cur_mode = mode;
|
||||
|
||||
h_blank = mode->hts_def - mode->width;
|
||||
__v4l2_ctrl_modify_range(sc850sl->hblank, h_blank,
|
||||
h_blank, 1, h_blank);
|
||||
vblank_def = mode->vts_def - mode->height;
|
||||
__v4l2_ctrl_modify_range(sc850sl->vblank, vblank_def,
|
||||
SC850SL_VTS_MAX - mode->height,
|
||||
1, vblank_def);
|
||||
__v4l2_ctrl_s_ctrl(sc850sl->link_freq, mode->mipi_freq_idx);
|
||||
pixel_rate = (u32)link_freq_items[mode->mipi_freq_idx] /
|
||||
mode->bpp * 2 * SC850SL_4LANES;
|
||||
__v4l2_ctrl_s_ctrl_int64(sc850sl->pixel_rate, pixel_rate);
|
||||
sc850sl->cur_fps = mode->max_fps;
|
||||
sc850sl->cur_vts = mode->vts_def;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sc850sl_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id,
|
||||
struct v4l2_mbus_config *config)
|
||||
{
|
||||
|
||||
config->type = V4L2_MBUS_CSI2_DPHY;
|
||||
config->bus.mipi_csi2.num_data_lanes = SC850SL_4LANES;
|
||||
|
||||
@@ -698,68 +782,164 @@ static void sc850sl_get_module_inf(struct sc850sl *sc850sl,
|
||||
strscpy(inf->base.lens, sc850sl->len_name, sizeof(inf->base.lens));
|
||||
}
|
||||
|
||||
static void sc850sl_get_gain_reg(u32 val, u32 *again_reg, u32 *again_fine_reg,
|
||||
u32 *dgain_reg, u32 *dgain_fine_reg)
|
||||
/* mode: 0 = lgain 1 = sgain */
|
||||
static int sc850sl_set_gain_reg(struct sc850sl *sc850sl, u32 gain, int mode)
|
||||
{
|
||||
u8 u8Reg0x3e09 = 0x40, u8Reg0x3e08 = 0x03;
|
||||
u32 aCoarseGain = 0;
|
||||
u32 aFineGain = 0;
|
||||
u32 again = 0;
|
||||
u32 dgain = 0;
|
||||
u32 ANA_Fine_gainx64 = 1, DIG_Fine_gainx1000 = 1;
|
||||
u32 Dcg_gainx1000;
|
||||
u8 Coarse_gain = 1, DIG_gain = 1;
|
||||
u8 ANA_Fine_gain_reg = 0x40, DIG_Fine_gain_reg = 0;
|
||||
u8 Dcg_gain_reg, Coarse_gain_reg, DIG_gain_reg;
|
||||
int ret = 0;
|
||||
u64 val = 0;
|
||||
|
||||
if (val < 64)
|
||||
val = 64;
|
||||
else if (val > SC850SL_GAIN_MAX)
|
||||
val = SC850SL_GAIN_MAX;
|
||||
gain = gain * 16;
|
||||
if (gain <= 1024)
|
||||
gain = 1024;
|
||||
else if (gain > SC850SL_GAIN_MAX * 16)
|
||||
gain = SC850SL_GAIN_MAX * 16;
|
||||
|
||||
if (val <= 3199) {
|
||||
again = val;
|
||||
dgain = 1;
|
||||
if (gain < 2048) { // start again 2 * 1024
|
||||
Dcg_gainx1000 = 1000;
|
||||
Coarse_gain = 1;
|
||||
DIG_gain = 1;
|
||||
DIG_Fine_gainx1000 = 1000;
|
||||
Dcg_gain_reg = 0;
|
||||
Coarse_gain_reg = 0x03;
|
||||
DIG_gain_reg = 0x0;
|
||||
DIG_Fine_gain_reg = 0x80;
|
||||
} else if (gain < 3200) {// 3.125 * 1024
|
||||
Dcg_gainx1000 = 1000;
|
||||
Coarse_gain = 2;
|
||||
DIG_gain = 1;
|
||||
DIG_Fine_gainx1000 = 1000;
|
||||
Dcg_gain_reg = 0;
|
||||
Coarse_gain_reg = 0x07;
|
||||
DIG_gain_reg = 0x0;
|
||||
DIG_Fine_gain_reg = 0x80;
|
||||
} else if (gain < 6400) {// 6.25 * 1024
|
||||
Dcg_gainx1000 = 3125;
|
||||
Coarse_gain = 1;
|
||||
DIG_gain = 1;
|
||||
DIG_Fine_gainx1000 = 1000;
|
||||
Dcg_gain_reg = 1;
|
||||
Coarse_gain_reg = 0x23;
|
||||
DIG_gain_reg = 0x0;
|
||||
DIG_Fine_gain_reg = 0x80;
|
||||
} else if (gain < 12800) {// 12.5 * 1024
|
||||
Dcg_gainx1000 = 3125;
|
||||
Coarse_gain = 2;
|
||||
DIG_gain = 1;
|
||||
DIG_Fine_gainx1000 = 1000;
|
||||
Dcg_gain_reg = 1;
|
||||
Coarse_gain_reg = 0x27;
|
||||
DIG_gain_reg = 0x0;
|
||||
DIG_Fine_gain_reg = 0x80;
|
||||
} else if (gain < 25600) {// 25 * 1024
|
||||
Dcg_gainx1000 = 3125;
|
||||
Coarse_gain = 4;
|
||||
DIG_gain = 1;
|
||||
DIG_Fine_gainx1000 = 1000;
|
||||
Dcg_gain_reg = 1;
|
||||
Coarse_gain_reg = 0x2f;
|
||||
DIG_gain_reg = 0x0;
|
||||
DIG_Fine_gain_reg = 0x80;
|
||||
} else if (gain < 51200) {// 50 * 1024 // end again
|
||||
Dcg_gainx1000 = 3125;
|
||||
Coarse_gain = 8;
|
||||
DIG_gain = 1;
|
||||
DIG_Fine_gainx1000 = 1000;
|
||||
Dcg_gain_reg = 1;
|
||||
Coarse_gain_reg = 0x3f;
|
||||
DIG_gain_reg = 0x0;
|
||||
DIG_Fine_gain_reg = 0x80;
|
||||
} else if (gain < 50800 * 2) {// start dgain
|
||||
Dcg_gainx1000 = 3125;
|
||||
Coarse_gain = 8;
|
||||
DIG_gain = 1;
|
||||
ANA_Fine_gainx64 = 127;
|
||||
Dcg_gain_reg = 1;
|
||||
Coarse_gain_reg = 0x3f;
|
||||
DIG_gain_reg = 0x0;
|
||||
ANA_Fine_gain_reg = 0x7f;
|
||||
} else if (gain < 50800 * 4) {
|
||||
Dcg_gainx1000 = 3125;
|
||||
Coarse_gain = 8;
|
||||
DIG_gain = 2;
|
||||
ANA_Fine_gainx64 = 127;
|
||||
Dcg_gain_reg = 1;
|
||||
Coarse_gain_reg = 0x3f;
|
||||
DIG_gain_reg = 0x1;
|
||||
ANA_Fine_gain_reg = 0x7f;
|
||||
} else if (gain < 50800 * 8) {
|
||||
Dcg_gainx1000 = 3125;
|
||||
Coarse_gain = 8;
|
||||
DIG_gain = 4;
|
||||
ANA_Fine_gainx64 = 127;
|
||||
Dcg_gain_reg = 1;
|
||||
Coarse_gain_reg = 0x3f;
|
||||
DIG_gain_reg = 0x3;
|
||||
ANA_Fine_gain_reg = 0x7f;
|
||||
} else {
|
||||
again = 3199;
|
||||
dgain = val / again;
|
||||
Dcg_gainx1000 = 3125;
|
||||
Coarse_gain = 8;
|
||||
DIG_gain = 8;
|
||||
ANA_Fine_gainx64 = 127;
|
||||
Dcg_gain_reg = 1;
|
||||
Coarse_gain_reg = 0x3f;
|
||||
DIG_gain_reg = 0x7;
|
||||
ANA_Fine_gain_reg = 0x7f;
|
||||
}
|
||||
|
||||
//again
|
||||
if (again <= 200) {
|
||||
//a_gain < 3.125x
|
||||
for (aCoarseGain = 1; aCoarseGain <= 2; aCoarseGain = aCoarseGain * 2) {
|
||||
//1,2,4,8,16
|
||||
if (again < (64 * 2 * aCoarseGain))
|
||||
break;
|
||||
}
|
||||
aFineGain = again / aCoarseGain;
|
||||
if (gain < 2048) {
|
||||
val = div_u64(1000ULL * gain, (Dcg_gainx1000 * Coarse_gain));
|
||||
ANA_Fine_gain_reg = div_u64(val, 16);
|
||||
} else if (gain == 3200) {
|
||||
ANA_Fine_gain_reg = 0x40;
|
||||
} else if (gain < 51200) {
|
||||
val = div_u64(1000ULL * gain, (Dcg_gainx1000 * Coarse_gain));
|
||||
ANA_Fine_gain_reg = div_u64(val, 16);
|
||||
} else if (gain < 50800 * 8) {
|
||||
val = div_u64(8000ULL * gain, (Dcg_gainx1000 * Coarse_gain * DIG_gain));
|
||||
DIG_Fine_gain_reg = div_u64(val, ANA_Fine_gainx64);
|
||||
} else {
|
||||
for (aCoarseGain = 1; aCoarseGain <= 8; aCoarseGain = aCoarseGain * 2) {
|
||||
//1,2,4,8
|
||||
if (again < (64 * 2 * aCoarseGain * 3125 / 1000))
|
||||
break;
|
||||
}
|
||||
aFineGain = 1000 * again / aCoarseGain / 3125;
|
||||
}
|
||||
for ( ; aCoarseGain >= 2; aCoarseGain = aCoarseGain / 2)
|
||||
u8Reg0x3e08 = (u8Reg0x3e08 << 1) | 0x01;
|
||||
|
||||
u8Reg0x3e09 = aFineGain;
|
||||
//dcg = 2.72 --> 2.72*1024=2785.28
|
||||
u8Reg0x3e08 = (again > 200) ? (u8Reg0x3e08 | 0x20) : (u8Reg0x3e08 & 0x1f);
|
||||
*dgain_fine_reg = val * 128 / again / dgain;
|
||||
//dgain
|
||||
if (dgain < 2) { /*1x ~ 2x*/
|
||||
*dgain_reg = 0x00;
|
||||
} else if (dgain < 4) { /*2x ~ 4x*/
|
||||
*dgain_reg = 0x01;
|
||||
*dgain_fine_reg += (dgain - 2) * 64;
|
||||
} else if (dgain < 8) { /*4x ~ 8x*/
|
||||
*dgain_reg = 0x03;
|
||||
*dgain_fine_reg += (dgain - 4) * 32;
|
||||
} else {
|
||||
*dgain_reg = 0x07;
|
||||
*dgain_fine_reg = 0x80;
|
||||
DIG_Fine_gain_reg = 0x80;
|
||||
}
|
||||
|
||||
*again_reg = u8Reg0x3e08;
|
||||
*again_fine_reg = u8Reg0x3e09;
|
||||
if (mode == SC850SL_LGAIN) {
|
||||
ret = sc850sl_write_reg(sc850sl->client,
|
||||
SC850SL_REG_DGAIN,
|
||||
SC850SL_REG_VALUE_08BIT,
|
||||
DIG_gain_reg & 0xF);
|
||||
ret |= sc850sl_write_reg(sc850sl->client,
|
||||
SC850SL_REG_DGAIN_FINE,
|
||||
SC850SL_REG_VALUE_08BIT,
|
||||
DIG_Fine_gain_reg);
|
||||
ret |= sc850sl_write_reg(sc850sl->client,
|
||||
SC850SL_REG_AGAIN,
|
||||
SC850SL_REG_VALUE_08BIT,
|
||||
Coarse_gain_reg);
|
||||
ret |= sc850sl_write_reg(sc850sl->client,
|
||||
SC850SL_REG_AGAIN_FINE,
|
||||
SC850SL_REG_VALUE_08BIT,
|
||||
ANA_Fine_gain_reg);
|
||||
}
|
||||
#if ENABLE_NR
|
||||
if (gain < 2048)
|
||||
ret |= sc850sl_write_reg(sc850sl->client,
|
||||
0x363c,
|
||||
SC850SL_REG_VALUE_08BIT,
|
||||
0x05);
|
||||
else
|
||||
ret |= sc850sl_write_reg(sc850sl->client,
|
||||
0x363c,
|
||||
SC850SL_REG_VALUE_08BIT,
|
||||
0x07);
|
||||
#endif
|
||||
dev_dbg(&sc850sl->client->dev,
|
||||
"recv_gain:%d set again 0x%x, again_fine 0x%x, set dgain 0x%x, dgain_fine 0x%x\n",
|
||||
gain / 16, Coarse_gain_reg, ANA_Fine_gain_reg, DIG_gain_reg, DIG_Fine_gain_reg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sc850sl_get_channel_info(struct sc850sl *sc850sl, struct rkmodule_channel_info *ch_info)
|
||||
@@ -782,37 +962,52 @@ static long sc850sl_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
|
||||
long ret = 0;
|
||||
u64 pixel_rate = 0;
|
||||
u32 i, h, w, stream;
|
||||
int cur_best_fit = -1;
|
||||
int cur_best_fit_dist = -1;
|
||||
int cur_dist, cur_fps, dst_fps;
|
||||
|
||||
switch (cmd) {
|
||||
case PREISP_CMD_SET_HDRAE_EXP:
|
||||
/*
|
||||
* ret = sc850sl_set_hdrae(sc850sl, arg);
|
||||
*/
|
||||
if (sc850sl->cam_sw_info)
|
||||
memcpy(&sc850sl->cam_sw_info->hdr_ae, (struct preisp_hdrae_exp_s *)(arg),
|
||||
sizeof(struct preisp_hdrae_exp_s));
|
||||
break;
|
||||
|
||||
case RKMODULE_SET_HDR_CFG:
|
||||
hdr_cfg = (struct rkmodule_hdr_cfg *)arg;
|
||||
if (sc850sl->streaming) {
|
||||
ret = sc850sl_write_array(sc850sl->client, sc850sl->cur_mode->reg_list);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
if (hdr_cfg->hdr_mode == sc850sl->cur_mode->hdr_mode)
|
||||
return 0;
|
||||
w = sc850sl->cur_mode->width;
|
||||
h = sc850sl->cur_mode->height;
|
||||
dst_fps = DIV_ROUND_CLOSEST(sc850sl->cur_mode->max_fps.denominator,
|
||||
sc850sl->cur_mode->max_fps.numerator);
|
||||
for (i = 0; i < sc850sl->cfg_num; i++) {
|
||||
if (w == supported_modes[i].width &&
|
||||
h == supported_modes[i].height &&
|
||||
supported_modes[i].hdr_mode == hdr_cfg->hdr_mode) {
|
||||
sc850sl_change_mode(sc850sl, &supported_modes[i]);
|
||||
break;
|
||||
h == supported_modes[i].height &&
|
||||
supported_modes[i].hdr_mode == hdr_cfg->hdr_mode &&
|
||||
supported_modes[i].bus_fmt == sc850sl->cur_mode->bus_fmt) {
|
||||
cur_fps = DIV_ROUND_CLOSEST(supported_modes[i].max_fps.denominator,
|
||||
supported_modes[i].max_fps.numerator);
|
||||
cur_dist = abs(cur_fps - dst_fps);
|
||||
if (cur_best_fit_dist == -1 || cur_dist < cur_best_fit_dist) {
|
||||
cur_best_fit_dist = cur_dist;
|
||||
cur_best_fit = i;
|
||||
} else if (cur_dist == cur_best_fit_dist) {
|
||||
cur_best_fit = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i == sc850sl->cfg_num) {
|
||||
if (cur_best_fit == -1) {
|
||||
dev_err(&sc850sl->client->dev,
|
||||
"not find hdr mode:%d %dx%d config\n",
|
||||
hdr_cfg->hdr_mode, w, h);
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
sc850sl_change_mode(sc850sl, &supported_modes[cur_best_fit]);
|
||||
mode = sc850sl->cur_mode;
|
||||
w = mode->hts_def - mode->width;
|
||||
h = mode->vts_def - mode->height;
|
||||
@@ -844,12 +1039,27 @@ static long sc850sl_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
|
||||
case RKMODULE_SET_QUICK_STREAM:
|
||||
stream = *((u32 *)arg);
|
||||
|
||||
if (stream)
|
||||
if (stream) {
|
||||
ret = sc850sl_write_reg(sc850sl->client, 0x3019,
|
||||
SC850SL_REG_VALUE_08BIT,
|
||||
0xf0);
|
||||
ret = sc850sl_write_reg(sc850sl->client, 0x3018,
|
||||
SC850SL_REG_VALUE_08BIT,
|
||||
0x7a);
|
||||
ret = sc850sl_write_reg(sc850sl->client, SC850SL_REG_CTRL_MODE,
|
||||
SC850SL_REG_VALUE_08BIT, SC850SL_MODE_STREAMING);
|
||||
else
|
||||
SC850SL_REG_VALUE_08BIT,
|
||||
SC850SL_MODE_STREAMING);
|
||||
} else {
|
||||
ret = sc850sl_write_reg(sc850sl->client, 0x3018,
|
||||
SC850SL_REG_VALUE_08BIT,
|
||||
0x7f);
|
||||
ret = sc850sl_write_reg(sc850sl->client, 0x3019,
|
||||
SC850SL_REG_VALUE_08BIT,
|
||||
0xff);
|
||||
ret = sc850sl_write_reg(sc850sl->client, SC850SL_REG_CTRL_MODE,
|
||||
SC850SL_REG_VALUE_08BIT, SC850SL_MODE_SW_STANDBY);
|
||||
SC850SL_REG_VALUE_08BIT,
|
||||
SC850SL_MODE_SW_STANDBY);
|
||||
}
|
||||
break;
|
||||
|
||||
case RKMODULE_GET_CHANNEL_INFO:
|
||||
@@ -1012,21 +1222,31 @@ static int __sc850sl_start_stream(struct sc850sl *sc850sl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sc850sl_write_array(sc850sl->client, sc850sl->cur_mode->reg_list);
|
||||
if (ret)
|
||||
return ret;
|
||||
dev_info(&sc850sl->client->dev,
|
||||
"%dx%d@%d, mode %d, vts 0x%x\n",
|
||||
sc850sl->cur_mode->width,
|
||||
sc850sl->cur_mode->height,
|
||||
sc850sl->cur_fps.denominator / sc850sl->cur_fps.numerator,
|
||||
sc850sl->cur_mode->hdr_mode,
|
||||
sc850sl->cur_vts);
|
||||
|
||||
ret = __v4l2_ctrl_handler_setup(&sc850sl->ctrl_handler);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* In case these controls are set before streaming */
|
||||
if (sc850sl->has_init_exp && sc850sl->cur_mode->hdr_mode != NO_HDR) {
|
||||
ret = sc850sl_ioctl(&sc850sl->subdev, PREISP_CMD_SET_HDRAE_EXP,
|
||||
&sc850sl->init_hdrae_exp);
|
||||
if (ret) {
|
||||
dev_err(&sc850sl->client->dev,
|
||||
"init exp fail in hdr mode\n");
|
||||
if (!sc850sl->is_thunderboot) {
|
||||
ret = sc850sl_write_array(sc850sl->client, sc850sl->cur_mode->reg_list);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = __v4l2_ctrl_handler_setup(&sc850sl->ctrl_handler);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* In case these controls are set before streaming */
|
||||
if (sc850sl->has_init_exp && sc850sl->cur_mode->hdr_mode != NO_HDR) {
|
||||
ret = sc850sl_ioctl(&sc850sl->subdev, PREISP_CMD_SET_HDRAE_EXP,
|
||||
&sc850sl->init_hdrae_exp);
|
||||
if (ret) {
|
||||
dev_err(&sc850sl->client->dev,
|
||||
"init exp fail in hdr mode\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sc850sl_write_reg(sc850sl->client, SC850SL_REG_CTRL_MODE,
|
||||
@@ -1036,10 +1256,15 @@ static int __sc850sl_start_stream(struct sc850sl *sc850sl)
|
||||
static int __sc850sl_stop_stream(struct sc850sl *sc850sl)
|
||||
{
|
||||
sc850sl->has_init_exp = false;
|
||||
if (sc850sl->is_thunderboot) {
|
||||
sc850sl->is_first_streamoff = true;
|
||||
pm_runtime_put(&sc850sl->client->dev);
|
||||
}
|
||||
return sc850sl_write_reg(sc850sl->client, SC850SL_REG_CTRL_MODE,
|
||||
SC850SL_REG_VALUE_08BIT, SC850SL_MODE_SW_STANDBY);
|
||||
SC850SL_REG_VALUE_08BIT, SC850SL_MODE_SW_STANDBY);
|
||||
}
|
||||
|
||||
static int __sc850sl_power_on(struct sc850sl *sc850sl);
|
||||
static int sc850sl_s_stream(struct v4l2_subdev *sd, int on)
|
||||
{
|
||||
struct sc850sl *sc850sl = to_sc850sl(sd);
|
||||
@@ -1056,6 +1281,10 @@ static int sc850sl_s_stream(struct v4l2_subdev *sd, int on)
|
||||
goto unlock_and_return;
|
||||
|
||||
if (on) {
|
||||
if (sc850sl->is_thunderboot && rkisp_tb_get_state() == RKISP_TB_NG) {
|
||||
sc850sl->is_thunderboot = false;
|
||||
__sc850sl_power_on(sc850sl);
|
||||
}
|
||||
ret = pm_runtime_get_sync(&client->dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(&client->dev);
|
||||
@@ -1097,18 +1326,19 @@ static int sc850sl_s_power(struct v4l2_subdev *sd, int on)
|
||||
pm_runtime_put_noidle(&client->dev);
|
||||
goto unlock_and_return;
|
||||
}
|
||||
if (!sc850sl->is_thunderboot) {
|
||||
ret |= sc850sl_write_reg(sc850sl->client,
|
||||
SC850SL_SOFTWARE_RESET_REG,
|
||||
SC850SL_REG_VALUE_08BIT,
|
||||
0x01);
|
||||
if (ret) {
|
||||
v4l2_err(sd, "could not set init registers\n");
|
||||
pm_runtime_put_noidle(&client->dev);
|
||||
goto unlock_and_return;
|
||||
}
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
ret |= sc850sl_write_reg(sc850sl->client,
|
||||
SC850SL_SOFTWARE_RESET_REG,
|
||||
SC850SL_REG_VALUE_08BIT,
|
||||
0x01);
|
||||
/*
|
||||
* usleep_range(100, 200);
|
||||
* ret |= sc850sl_write_reg(sc2310->client,
|
||||
* 0x303f,
|
||||
* SC850SL_REG_VALUE_08BIT,
|
||||
* 0x01);
|
||||
*/
|
||||
sc850sl->power_on = true;
|
||||
} else {
|
||||
pm_runtime_put(&client->dev);
|
||||
@@ -1131,15 +1361,6 @@ static int __sc850sl_power_on(struct sc850sl *sc850sl)
|
||||
if (ret < 0)
|
||||
dev_err(dev, "could not set pins\n");
|
||||
}
|
||||
|
||||
if (!IS_ERR(sc850sl->power_gpio))
|
||||
gpiod_direction_output(sc850sl->power_gpio, 1);
|
||||
|
||||
usleep_range(4000, 6000);
|
||||
if (!IS_ERR(sc850sl->reset_gpio))
|
||||
gpiod_direction_output(sc850sl->reset_gpio, 0);
|
||||
|
||||
usleep_range(4000, 6000);
|
||||
ret = clk_set_rate(sc850sl->xvclk, SC850SL_XVCLK_FREQ_24M);
|
||||
if (ret < 0)
|
||||
dev_warn(dev, "Failed to set xvclk rate 24MHz\n");
|
||||
@@ -1151,17 +1372,38 @@ static int __sc850sl_power_on(struct sc850sl *sc850sl)
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
cam_sw_regulator_bulk_init(sc850sl->cam_sw_info,
|
||||
SC850SL_NUM_SUPPLIES, sc850sl->supplies);
|
||||
|
||||
if (sc850sl->is_thunderboot)
|
||||
return 0;
|
||||
|
||||
if (!IS_ERR(sc850sl->pwdn_gpio))
|
||||
gpiod_set_value_cansleep(sc850sl->pwdn_gpio, 1);
|
||||
|
||||
usleep_range(4000, 6000);
|
||||
if (!IS_ERR(sc850sl->reset_gpio))
|
||||
gpiod_set_value_cansleep(sc850sl->reset_gpio, 0);
|
||||
|
||||
usleep_range(4000, 6000);
|
||||
|
||||
ret = regulator_bulk_enable(SC850SL_NUM_SUPPLIES, sc850sl->supplies);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to enable regulators\n");
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
if (!IS_ERR(sc850sl->reset_gpio))
|
||||
gpiod_set_value_cansleep(sc850sl->reset_gpio, 1);
|
||||
|
||||
usleep_range(4000, 6000);
|
||||
|
||||
if (!IS_ERR(sc850sl->pwdn_gpio))
|
||||
gpiod_set_value_cansleep(sc850sl->pwdn_gpio, 1);
|
||||
return 0;
|
||||
err_clk:
|
||||
if (!IS_ERR(sc850sl->reset_gpio))
|
||||
gpiod_direction_output(sc850sl->reset_gpio, 1);
|
||||
gpiod_direction_output(sc850sl->reset_gpio, 0);
|
||||
disable_clk:
|
||||
clk_disable_unprepare(sc850sl->xvclk);
|
||||
|
||||
@@ -1173,20 +1415,74 @@ static void __sc850sl_power_off(struct sc850sl *sc850sl)
|
||||
int ret;
|
||||
struct device *dev = &sc850sl->client->dev;
|
||||
|
||||
if (!IS_ERR(sc850sl->reset_gpio))
|
||||
gpiod_direction_output(sc850sl->reset_gpio, 1);
|
||||
clk_disable_unprepare(sc850sl->xvclk);
|
||||
if (sc850sl->is_thunderboot) {
|
||||
if (sc850sl->is_first_streamoff) {
|
||||
sc850sl->is_thunderboot = false;
|
||||
sc850sl->is_first_streamoff = false;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!IS_ERR(sc850sl->reset_gpio))
|
||||
gpiod_direction_output(sc850sl->reset_gpio, 0);
|
||||
|
||||
if (!IS_ERR_OR_NULL(sc850sl->pins_sleep)) {
|
||||
ret = pinctrl_select_state(sc850sl->pinctrl,
|
||||
sc850sl->pins_sleep);
|
||||
if (ret < 0)
|
||||
dev_dbg(dev, "could not set pins\n");
|
||||
}
|
||||
if (!IS_ERR(sc850sl->power_gpio))
|
||||
gpiod_direction_output(sc850sl->power_gpio, 0);
|
||||
if (!IS_ERR(sc850sl->pwdn_gpio))
|
||||
gpiod_direction_output(sc850sl->pwdn_gpio, 0);
|
||||
regulator_bulk_disable(SC850SL_NUM_SUPPLIES, sc850sl->supplies);
|
||||
}
|
||||
|
||||
#if IS_REACHABLE(CONFIG_VIDEO_CAM_SLEEP_WAKEUP)
|
||||
static int sc850sl_resume(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct sc850sl *sc850sl = to_sc850sl(sd);
|
||||
|
||||
cam_sw_prepare_wakeup(sc850sl->cam_sw_info, dev);
|
||||
|
||||
usleep_range(4000, 5000);
|
||||
cam_sw_write_array(sc850sl->cam_sw_info);
|
||||
|
||||
if (__v4l2_ctrl_handler_setup(&sc850sl->ctrl_handler))
|
||||
dev_err(dev, "__v4l2_ctrl_handler_setup fail!");
|
||||
|
||||
if (sc850sl->has_init_exp && sc850sl->cur_mode != NO_HDR) { // hdr mode
|
||||
ret = sc850sl_ioctl(&sc850sl->subdev, PREISP_CMD_SET_HDRAE_EXP,
|
||||
&sc850sl->cam_sw_info->hdr_ae);
|
||||
if (ret) {
|
||||
dev_err(&sc850sl->client->dev, "set exp fail in hdr mode\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sc850sl_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct sc850sl *sc850sl = to_sc850sl(sd);
|
||||
|
||||
cam_sw_write_array_cb_init(sc850sl->cam_sw_info, client,
|
||||
(void *)sc850sl->cur_mode->reg_list,
|
||||
(sensor_write_array)sc850sl_write_array);
|
||||
cam_sw_prepare_sleep(sc850sl->cam_sw_info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define sc850sl_resume NULL
|
||||
#define sc850sl_suspend NULL
|
||||
#endif
|
||||
|
||||
static int sc850sl_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
@@ -1285,6 +1581,7 @@ static int sc850sl_get_selection(struct v4l2_subdev *sd,
|
||||
static const struct dev_pm_ops sc850sl_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(sc850sl_runtime_suspend,
|
||||
sc850sl_runtime_resume, NULL)
|
||||
SET_LATE_SYSTEM_SLEEP_PM_OPS(sc850sl_suspend, sc850sl_resume)
|
||||
};
|
||||
|
||||
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
|
||||
@@ -1304,6 +1601,7 @@ static const struct v4l2_subdev_core_ops sc850sl_core_ops = {
|
||||
static const struct v4l2_subdev_video_ops sc850sl_video_ops = {
|
||||
.s_stream = sc850sl_s_stream,
|
||||
.g_frame_interval = sc850sl_g_frame_interval,
|
||||
.s_frame_interval = sc850sl_s_frame_interval,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_pad_ops sc850sl_pad_ops = {
|
||||
@@ -1336,7 +1634,6 @@ static int sc850sl_set_ctrl(struct v4l2_ctrl *ctrl)
|
||||
struct sc850sl, ctrl_handler);
|
||||
struct i2c_client *client = sc850sl->client;
|
||||
s64 max;
|
||||
u32 again, again_fine, dgain, dgain_fine;
|
||||
int ret = 0;
|
||||
u32 val;
|
||||
|
||||
@@ -1378,27 +1675,8 @@ static int sc850sl_set_ctrl(struct v4l2_ctrl *ctrl)
|
||||
case V4L2_CID_ANALOGUE_GAIN:
|
||||
if (sc850sl->cur_mode->hdr_mode != NO_HDR)
|
||||
goto out_ctrl;
|
||||
sc850sl_get_gain_reg(ctrl->val, &again, &again_fine, &dgain, &dgain_fine);
|
||||
dev_dbg(&client->dev,
|
||||
"recv_gain:%d set again 0x%x, again_fine 0x%x, set dgain 0x%x, dgain_fine 0x%x\n",
|
||||
ctrl->val, again, again_fine, dgain, dgain_fine);
|
||||
ret = sc850sl_set_gain_reg(sc850sl, ctrl->val, SC850SL_LGAIN);
|
||||
|
||||
ret |= sc850sl_write_reg(sc850sl->client,
|
||||
SC850SL_REG_AGAIN,
|
||||
SC850SL_REG_VALUE_08BIT,
|
||||
again);
|
||||
ret |= sc850sl_write_reg(sc850sl->client,
|
||||
SC850SL_REG_AGAIN_FINE,
|
||||
SC850SL_REG_VALUE_08BIT,
|
||||
again_fine);
|
||||
ret |= sc850sl_write_reg(sc850sl->client,
|
||||
SC850SL_REG_DGAIN,
|
||||
SC850SL_REG_VALUE_08BIT,
|
||||
dgain);
|
||||
ret |= sc850sl_write_reg(sc850sl->client,
|
||||
SC850SL_REG_DGAIN_FINE,
|
||||
SC850SL_REG_VALUE_08BIT,
|
||||
dgain_fine);
|
||||
break;
|
||||
case V4L2_CID_VBLANK:
|
||||
ret = sc850sl_write_reg(sc850sl->client, SC850SL_REG_VTS,
|
||||
@@ -1537,14 +1815,18 @@ static int sc850sl_check_sensor_id(struct sc850sl *sc850sl,
|
||||
u32 id = 0;
|
||||
int ret;
|
||||
|
||||
if (sc850sl->is_thunderboot) {
|
||||
dev_info(dev, "Enable thunderboot mode, skip sensor id check\n");
|
||||
return 0;
|
||||
}
|
||||
ret = sc850sl_read_reg(client, SC850SL_REG_CHIP_ID,
|
||||
SC850SL_REG_VALUE_16BIT, &id);
|
||||
SC850SL_REG_VALUE_16BIT, &id);
|
||||
if (id != CHIP_ID) {
|
||||
dev_err(dev, "Unexpected sensor id(%06x), ret(%d)\n", id, ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev_info(dev, "Detected sc850sl id %06x\n", CHIP_ID);
|
||||
dev_info(dev, "Detected sc850sl id(%06x)\n", CHIP_ID);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1600,6 +1882,7 @@ static int sc850sl_probe(struct i2c_client *client,
|
||||
dev_warn(dev, " Get hdr mode failed! no hdr default\n");
|
||||
}
|
||||
|
||||
sc850sl->is_thunderboot = IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP);
|
||||
sc850sl->client = client;
|
||||
sc850sl->cfg_num = ARRAY_SIZE(supported_modes);
|
||||
for (i = 0; i < sc850sl->cfg_num; i++) {
|
||||
@@ -1615,12 +1898,15 @@ static int sc850sl_probe(struct i2c_client *client,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sc850sl->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS);
|
||||
sc850sl->reset_gpio = devm_gpiod_get(dev, "reset",
|
||||
sc850sl->is_thunderboot ? GPIOD_ASIS : GPIOD_OUT_LOW);
|
||||
if (IS_ERR(sc850sl->reset_gpio))
|
||||
dev_warn(dev, "Failed to get reset-gpios\n");
|
||||
sc850sl->power_gpio = devm_gpiod_get(dev, "power", GPIOD_ASIS);
|
||||
if (IS_ERR(sc850sl->power_gpio))
|
||||
dev_warn(dev, "Failed to get power_gpios\n");
|
||||
|
||||
sc850sl->pwdn_gpio = devm_gpiod_get(dev, "pwdn",
|
||||
sc850sl->is_thunderboot ? GPIOD_ASIS : GPIOD_OUT_LOW);
|
||||
if (IS_ERR(sc850sl->pwdn_gpio))
|
||||
dev_warn(dev, "Failed to get pwdn_gpio\n");
|
||||
|
||||
sc850sl->pinctrl = devm_pinctrl_get(dev);
|
||||
if (!IS_ERR(sc850sl->pinctrl)) {
|
||||
@@ -1672,6 +1958,12 @@ static int sc850sl_probe(struct i2c_client *client,
|
||||
if (ret < 0)
|
||||
goto err_power_off;
|
||||
#endif
|
||||
if (!sc850sl->cam_sw_info) {
|
||||
sc850sl->cam_sw_info = cam_sw_init();
|
||||
cam_sw_clk_init(sc850sl->cam_sw_info, sc850sl->xvclk, SC850SL_XVCLK_FREQ_24M);
|
||||
cam_sw_reset_pin_init(sc850sl->cam_sw_info, sc850sl->reset_gpio, 0);
|
||||
cam_sw_pwdn_pin_init(sc850sl->cam_sw_info, sc850sl->pwdn_gpio, 1);
|
||||
}
|
||||
|
||||
memset(facing, 0, sizeof(facing));
|
||||
if (strcmp(sc850sl->module_facing, "back") == 0)
|
||||
@@ -1690,7 +1982,10 @@ static int sc850sl_probe(struct i2c_client *client,
|
||||
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
pm_runtime_idle(dev);
|
||||
if (sc850sl->is_thunderboot)
|
||||
pm_runtime_get_sync(dev);
|
||||
else
|
||||
pm_runtime_idle(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1720,6 +2015,8 @@ static void sc850sl_remove(struct i2c_client *client)
|
||||
v4l2_ctrl_handler_free(&sc850sl->ctrl_handler);
|
||||
mutex_destroy(&sc850sl->mutex);
|
||||
|
||||
cam_sw_deinit(sc850sl->cam_sw_info);
|
||||
|
||||
pm_runtime_disable(&client->dev);
|
||||
if (!pm_runtime_status_suspended(&client->dev))
|
||||
__sc850sl_power_off(sc850sl);
|
||||
|
||||
Reference in New Issue
Block a user