mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 03:40:35 +09:00
media: i2c: gc8034: add 2lane support
1. add 2lane support 2. add some debug info 3. adjust gc8034_g_mbus_config function Signed-off-by: Wang Panzhenzhuan <randy.wang@rock-chips.com> Change-Id: I7f40c2c9ce0aea543ea629efb46585ebee387515 Signed-off-by: Zefa Chen <zefa.chen@rock-chips.com>
This commit is contained in:
committed by
Zefa Chen
parent
3b595992f2
commit
2052425b68
@@ -9,6 +9,10 @@
|
||||
* V0.0X01.0X03 add enum_frame_interval function.
|
||||
* V0.0X01.0X04 add quick stream on/off
|
||||
* V0.0X01.0X05 add function g_mbus_config
|
||||
* V0.0X01.0X06
|
||||
* 1. add 2lane support.
|
||||
* 2. add some debug info.
|
||||
* 3. adjust gc8034_g_mbus_config function.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
@@ -18,6 +22,8 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/version.h>
|
||||
@@ -25,11 +31,16 @@
|
||||
#include <media/media-entity.h>
|
||||
#include <media/v4l2-async.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-event.h>
|
||||
#include <media/v4l2-fwnode.h>
|
||||
#include <media/v4l2-image-sizes.h>
|
||||
#include <media/v4l2-mediabus.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x05)
|
||||
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x06)
|
||||
|
||||
#ifndef V4L2_CID_DIGITAL_GAIN
|
||||
#define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN
|
||||
@@ -37,9 +48,10 @@
|
||||
|
||||
#define GC8034_LANES 4
|
||||
#define GC8034_BITS_PER_SAMPLE 10
|
||||
#define GC8034_LINK_FREQ_MHZ 336000000
|
||||
#define GC8034_MIPI_FREQ_336MHZ 336000000U
|
||||
|
||||
/* pixel rate = link frequency * 2 * lanes / BITS_PER_SAMPLE */
|
||||
#define GC8034_PIXEL_RATE 80000000
|
||||
#define GC8034_PIXEL_RATE 288000000
|
||||
#define GC8034_XVCLK_FREQ 24000000
|
||||
|
||||
#define CHIP_ID 0x8044
|
||||
@@ -78,6 +90,7 @@
|
||||
#define OF_CAMERA_PINCTRL_STATE_SLEEP "rockchip,camera_sleep"
|
||||
|
||||
#define GC8034_NAME "gc8034"
|
||||
#define GC8034_MEDIA_BUS_FMT MEDIA_BUS_FMT_SRGGB10_1X10
|
||||
|
||||
static const char * const gc8034_supply_names[] = {
|
||||
"avdd", /* Analog power */
|
||||
@@ -85,6 +98,7 @@ static const char * const gc8034_supply_names[] = {
|
||||
"dvdd", /* Digital core power */
|
||||
};
|
||||
|
||||
static const struct regval *gc8034_global_regs;
|
||||
#define GC8034_NUM_SUPPLIES ARRAY_SIZE(gc8034_supply_names)
|
||||
|
||||
struct gc8034_dd {
|
||||
@@ -150,6 +164,7 @@ struct gc8034_mode {
|
||||
struct gc8034 {
|
||||
struct i2c_client *client;
|
||||
struct clk *xvclk;
|
||||
struct gpio_desc *power_gpio;
|
||||
struct gpio_desc *reset_gpio;
|
||||
struct gpio_desc *pwdn_gpio;
|
||||
struct regulator_bulk_data supplies[GC8034_NUM_SUPPLIES];
|
||||
@@ -164,8 +179,12 @@ struct gc8034 {
|
||||
struct v4l2_ctrl *digi_gain;
|
||||
struct v4l2_ctrl *hblank;
|
||||
struct v4l2_ctrl *vblank;
|
||||
struct v4l2_ctrl *link_freq;
|
||||
struct mutex mutex;
|
||||
bool streaming;
|
||||
unsigned int lane_num;
|
||||
unsigned int cfg_num;
|
||||
unsigned int pixel_rate;
|
||||
bool power_on;
|
||||
const struct gc8034_mode *cur_mode;
|
||||
u32 module_index;
|
||||
@@ -180,10 +199,384 @@ struct gc8034 {
|
||||
|
||||
#define to_gc8034(sd) container_of(sd, struct gc8034, subdev)
|
||||
|
||||
#undef GC8034_MIRROR_NORMAL
|
||||
#undef GC8034_MIRROR_H
|
||||
#undef GC8034_MIRROR_V
|
||||
#undef GC8034_MIRROR_HV
|
||||
/* If you use the otp function, keep the otp_drv ->
|
||||
* gc8034_common_otp_drv.h consistent.
|
||||
*/
|
||||
#define GC8034_MIRROR_NORMAL
|
||||
|
||||
#if defined(GC8034_MIRROR_NORMAL)
|
||||
#define GC8034_MIRROR 0xc0
|
||||
#define BINNING_STARTY 0x04
|
||||
#define BINNING_STARTX 0x05
|
||||
#define FULL_STARTY 0x08
|
||||
#define FULL_STARTX 0x09
|
||||
#elif defined(GC8034_MIRROR_H)
|
||||
#define GC8034_MIRROR 0xc1
|
||||
#define BINNING_STARTY 0x04
|
||||
#define BINNING_STARTX 0x04
|
||||
#define FULL_STARTY 0x08
|
||||
#define FULL_STARTX 0x08
|
||||
#elif defined(GC8034_MIRROR_V)
|
||||
#define GC8034_MIRROR 0xc2
|
||||
#define BINNING_STARTY 0x05
|
||||
#define BINNING_STARTX 0x05
|
||||
#define FULL_STARTY 0x09
|
||||
#define FULL_STARTX 0x09
|
||||
#elif defined(GC8034_MIRROR_HV)
|
||||
#define GC8034_MIRROR 0xc3
|
||||
#define BINNING_STARTY 0x05
|
||||
#define BINNING_STARTX 0x04
|
||||
#define FULL_STARTY 0x09
|
||||
#define FULL_STARTX 0x08
|
||||
#else
|
||||
#define GC8034_MIRROR 0xc0
|
||||
#define BINNING_STARTY 0x04
|
||||
#define BINNING_STARTX 0x05
|
||||
#define FULL_STARTY 0x08
|
||||
#define FULL_STARTX 0x09
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Xclk 24Mhz
|
||||
*/
|
||||
static const struct regval gc8034_global_regs[] = {
|
||||
static const struct regval gc8034_global_regs_2lane[] = {
|
||||
/*SYS*/
|
||||
{0xf2, 0x00},
|
||||
{0xf4, 0x80},
|
||||
{0xf5, 0x19},
|
||||
{0xf6, 0x44},
|
||||
{0xf7, 0x95}, //pll enable
|
||||
{0xf8, 0x63}, //pll mode
|
||||
{0xf9, 0x00},
|
||||
{0xfa, 0x45},
|
||||
{0xfc, 0xfe},
|
||||
|
||||
/*Cisctl&Analog*/
|
||||
{0xfe, 0x00},
|
||||
{0x03, 0x08},
|
||||
{0x04, 0xc6},
|
||||
{0x05, 0x02},
|
||||
{0x06, 0x16},
|
||||
{0x07, 0x00},
|
||||
{0x08, 0x10},
|
||||
{0x0a, 0x3a}, //row start
|
||||
{0x0b, 0x00},
|
||||
{0x0c, 0x04}, //col start
|
||||
{0x0d, 0x09},
|
||||
{0x0e, 0xa0}, //win_height 2464
|
||||
{0x0f, 0x0c},
|
||||
{0x10, 0xd4}, //win_width 3284
|
||||
{0x17, GC8034_MIRROR},
|
||||
{0x18, 0x02},
|
||||
{0x19, 0x17},
|
||||
{0x1e, 0x50},
|
||||
{0x1f, 0x80},
|
||||
{0x21, 0x4c},
|
||||
{0x25, 0x00},
|
||||
{0x28, 0x4a},
|
||||
{0x2d, 0x89},
|
||||
{0xca, 0x02},
|
||||
{0xcb, 0x00},
|
||||
{0xcc, 0x39},
|
||||
{0xce, 0xd0},
|
||||
{0xcf, 0x93},
|
||||
{0xd0, 0x1b},
|
||||
{0xd1, 0xaa},
|
||||
{0xd2, 0xcb},
|
||||
{0xd8, 0x40},
|
||||
{0xd9, 0xff},
|
||||
{0xda, 0x0e},
|
||||
{0xdb, 0xb0},
|
||||
{0xdc, 0x0e},
|
||||
{0xde, 0x08},
|
||||
{0xe4, 0xc6},
|
||||
{0xe5, 0x08},
|
||||
{0xe6, 0x10},
|
||||
{0xed, 0x2a},
|
||||
{0xfe, 0x02},
|
||||
{0x59, 0x02},
|
||||
{0x5a, 0x04},
|
||||
{0x5b, 0x08},
|
||||
{0x5c, 0x20},
|
||||
{0xfe, 0x00},
|
||||
{0x1a, 0x09},
|
||||
{0x1d, 0x13},
|
||||
{0xfe, 0x10},
|
||||
{0xfe, 0x00},
|
||||
{0xfe, 0x10},
|
||||
{0xfe, 0x00},
|
||||
|
||||
/* Gamma */
|
||||
{0xfe, 0x00},
|
||||
{0x20, 0x54},
|
||||
{0x33, 0x82},
|
||||
{0xfe, 0x01},
|
||||
{0xdf, 0x06},
|
||||
{0xe7, 0x18},
|
||||
{0xe8, 0x20},
|
||||
{0xe9, 0x16},
|
||||
{0xea, 0x17},
|
||||
{0xeb, 0x50},
|
||||
{0xec, 0x6c},
|
||||
{0xed, 0x9b},
|
||||
{0xee, 0xd8},
|
||||
|
||||
/*ISP*/
|
||||
{0xfe, 0x00},
|
||||
{0x80, 0x13},
|
||||
{0x84, 0x01},
|
||||
{0x89, 0x03},
|
||||
{0x8d, 0x03},
|
||||
{0x8f, 0x14},
|
||||
{0xad, 0x00},
|
||||
|
||||
/*Crop window*/
|
||||
{0x90, 0x01},
|
||||
{0x92, FULL_STARTY},
|
||||
{0x94, FULL_STARTX},
|
||||
{0x95, 0x09},
|
||||
{0x96, 0x90},
|
||||
{0x97, 0x0c},
|
||||
{0x98, 0xc0},
|
||||
|
||||
/*Gain*/
|
||||
{0xb0, 0x90},
|
||||
{0xb1, 0x01},
|
||||
{0xb2, 0x00},
|
||||
{0xb6, 0x00},
|
||||
|
||||
/*BLK*/
|
||||
{0xfe, 0x00},
|
||||
{0x40, 0x22},
|
||||
{0x43, 0x03}, //add_offset
|
||||
{0x4e, 0x00}, //row_bits[15:8]
|
||||
{0x4f, 0x3c}, //row_bits[7:0]
|
||||
{0x58, 0x80}, //dark current ratio
|
||||
{0x59, 0x80},
|
||||
{0x5a, 0x80},
|
||||
{0x5b, 0x80},
|
||||
{0x5c, 0x00},
|
||||
{0x5d, 0x00},
|
||||
{0x5e, 0x00},
|
||||
{0x5f, 0x00},
|
||||
|
||||
/*WB offset*/
|
||||
{0xfe, 0x01},
|
||||
{0xbf, 0x40},
|
||||
|
||||
/*Dark Sun*/
|
||||
{0xfe, 0x01},
|
||||
{0x68, 0x77},
|
||||
|
||||
/*DPC*/
|
||||
{0xfe, 0x01},
|
||||
{0x60, 0x15},
|
||||
{0x61, 0x10},
|
||||
{0x62, 0x60},
|
||||
{0x63, 0x48},
|
||||
{0x64, 0x02},
|
||||
|
||||
/*LSC*/
|
||||
{0xfe, 0x01},
|
||||
{0xa0, 0x10}, //[6]segment_width[8], 0x[5:4]segment_height[9:8]
|
||||
{0xa8, 0x60}, //segment_height[7:0]
|
||||
{0xa2, 0xd1}, //height_ratio[7:0]
|
||||
{0xc8, 0x5b}, //[7:4]height_ratio[11:8]
|
||||
{0xa1, 0xb8}, //segment_width[7:0]
|
||||
{0xa3, 0x91}, //width_ratio[7:0]
|
||||
{0xc0, 0x50}, //[7:4]width_ratio[11:8]
|
||||
{0xd0, 0x05}, //segment_width_end[11:8]
|
||||
{0xd1, 0xb2}, //segment_width_end[7:0]
|
||||
{0xd2, 0x1f}, //col_segment
|
||||
{0xd3, 0x00}, //row_num_start[7:0]
|
||||
{0xd4, 0x00}, //[5:4]row_num_start[9:8] [3:0]col_seg_start
|
||||
{0xd5, 0x00}, //[7:2]col_num_start[7:2]
|
||||
{0xd6, 0x00}, //[2:0]col_num_start[10:8]
|
||||
{0xd7, 0x00}, //row_seg_start
|
||||
{0xd8, 0x00}, //col_cal_start[7:0]
|
||||
{0xd9, 0x00}, //[2:0]col_cal_start[10:8]
|
||||
|
||||
/*ABB*/
|
||||
{0xfe, 0x01},
|
||||
{0x20, 0x02},
|
||||
{0x21, 0x02},
|
||||
{0x23, 0x43},
|
||||
|
||||
/*MIPI*/
|
||||
{0xfe, 0x03},
|
||||
{0x01, 0x07},
|
||||
{0x02, 0x07},
|
||||
{0x03, 0x92},
|
||||
{0x04, 0x80},
|
||||
{0x11, 0x2b},
|
||||
{0x12, 0xf0}, //lwc 3264*5/4
|
||||
{0x13, 0x0f},
|
||||
{0x15, 0x10}, //LP
|
||||
{0x16, 0x29},
|
||||
{0x17, 0xff},
|
||||
{0x18, 0x01},
|
||||
{0x19, 0xaa},
|
||||
{0x1a, 0x02},
|
||||
{0x21, 0x05},
|
||||
{0x22, 0x05},
|
||||
{0x23, 0x16},
|
||||
{0x24, 0x00},
|
||||
{0x25, 0x12},
|
||||
{0x26, 0x07},
|
||||
{0x29, 0x07},
|
||||
{0x2a, 0x08},
|
||||
{0x2b, 0x07},
|
||||
{0xfe, 0x00},
|
||||
//{0x3f, 0x91},
|
||||
{0x3f, 0x00},
|
||||
|
||||
{REG_NULL, 0x00},
|
||||
};
|
||||
|
||||
/*
|
||||
* Xclk 24Mhz
|
||||
* max_framerate 30fps
|
||||
* mipi_datarate per lane 672Mbps
|
||||
*/
|
||||
static const struct regval gc8034_1632x1224_regs_2lane[] = {
|
||||
/*SYS*/
|
||||
{0xf2, 0x00},
|
||||
{0xf4, 0x80},
|
||||
{0xf5, 0x19},
|
||||
{0xf6, 0x44},
|
||||
{0xf8, 0x63},
|
||||
{0xfa, 0x45},
|
||||
{0xf9, 0x00},
|
||||
{0xf7, 0x95},
|
||||
{0xfc, 0x00},
|
||||
{0xfc, 0x00},
|
||||
{0xfc, 0xea},
|
||||
{0xfe, 0x03},
|
||||
{0x03, 0x9a},
|
||||
{0xfc, 0xee},
|
||||
{0xfe, 0x10},
|
||||
{0xfe, 0x00},
|
||||
{0xfe, 0x10},
|
||||
{0xfe, 0x00},
|
||||
|
||||
/*ISP*/
|
||||
{0xfe, 0x00},
|
||||
{0x80, 0x10},
|
||||
{0xad, 0x30},
|
||||
{0x66, 0x2c},
|
||||
{0xbc, 0x49},
|
||||
|
||||
/*Crop window*/
|
||||
{0x90, 0x01},
|
||||
{0x92, BINNING_STARTY}, //crop y
|
||||
{0x94, BINNING_STARTX}, //crop x
|
||||
{0x95, 0x04},
|
||||
{0x96, 0xc8},
|
||||
{0x97, 0x06},
|
||||
{0x98, 0x60},
|
||||
|
||||
/*MIPI*/
|
||||
{0xfe, 0x03},
|
||||
{0x01, 0x07},
|
||||
{0x02, 0x03},
|
||||
{0x04, 0x80},
|
||||
{0x11, 0x2b},
|
||||
{0x12, 0xf8},
|
||||
{0x13, 0x07},
|
||||
{0x15, 0x10}, //LP mode
|
||||
{0x16, 0x29},
|
||||
{0x17, 0xff},
|
||||
{0x18, 0x01},
|
||||
{0x19, 0xaa},
|
||||
{0x1a, 0x02},
|
||||
{0x21, 0x05},
|
||||
{0x22, 0x06},
|
||||
{0x23, 0x16},
|
||||
{0x24, 0x00},
|
||||
{0x25, 0x12},
|
||||
{0x26, 0x07},
|
||||
{0x29, 0x07},
|
||||
{0x2a, 0x08},
|
||||
{0x2b, 0x07},
|
||||
{0xfe, 0x00},
|
||||
{0x3f, 0x00},
|
||||
|
||||
{REG_NULL, 0x00},
|
||||
};
|
||||
|
||||
/*
|
||||
* Xclk 24Mhz
|
||||
* max_framerate 15fps
|
||||
* mipi_datarate per lane 672Mbps
|
||||
*/
|
||||
static const struct regval gc8034_3264x2448_regs_2lane[] = {
|
||||
/*SYS*/
|
||||
{0xf2, 0x00},
|
||||
{0xf4, 0x80},
|
||||
{0xf5, 0x19},
|
||||
{0xf6, 0x44},
|
||||
{0xf7, 0x95}, //pll enable
|
||||
{0xf8, 0x63}, //pll mode
|
||||
{0xf9, 0x00},
|
||||
{0xfa, 0x45},
|
||||
{0xfc, 0x00},
|
||||
{0xfc, 0x00},
|
||||
{0xfc, 0xfe},
|
||||
|
||||
/* ISP */
|
||||
{0xfe, 0x00},
|
||||
{0x80, 0x13},
|
||||
{0xad, 0x00},
|
||||
{0x66, 0x0c},
|
||||
{0xbc, 0x09},
|
||||
|
||||
/* Crop window */
|
||||
{0x90, 0x01},
|
||||
{0x92, FULL_STARTY},
|
||||
{0x94, FULL_STARTX},
|
||||
{0x95, 0x09},
|
||||
{0x96, 0x90},
|
||||
{0x97, 0x0c},
|
||||
{0x98, 0xc0},
|
||||
|
||||
/* MIPI */
|
||||
{0xfe, 0x03},
|
||||
{0x01, 0x07},
|
||||
{0x02, 0x03},
|
||||
{0x03, 0x92},
|
||||
{0x04, 0x80},
|
||||
{0x11, 0x2b},
|
||||
{0x12, 0xf0}, //lwc 3264*5/4
|
||||
{0x13, 0x0f},
|
||||
{0x15, 0x10}, //LP
|
||||
{0x16, 0x29},
|
||||
{0x17, 0xff},
|
||||
{0x18, 0x01},
|
||||
{0x19, 0xaa},
|
||||
{0x1a, 0x02},
|
||||
{0x21, 0x05},
|
||||
{0x22, 0x05},
|
||||
{0x23, 0x16},
|
||||
{0x24, 0x00},
|
||||
{0x25, 0x12},
|
||||
{0x26, 0x07},
|
||||
{0x29, 0x07},
|
||||
{0x2a, 0x08},
|
||||
{0x2b, 0x07},
|
||||
{0xfe, 0x00},
|
||||
//{0x3f, 0x91},
|
||||
{0x3f, 0x00},
|
||||
{REG_NULL, 0x00},
|
||||
};
|
||||
|
||||
/*
|
||||
* Xclk 24Mhz
|
||||
*/
|
||||
static const struct regval gc8034_global_regs_4lane[] = {
|
||||
/*SYS*/
|
||||
{0xf2, 0x00},
|
||||
{0xf4, 0x80},
|
||||
@@ -445,11 +838,38 @@ static const struct regval gc8034_global_regs[] = {
|
||||
* max_framerate 30fps
|
||||
* mipi_datarate per lane 656Mbps
|
||||
*/
|
||||
static const struct regval gc8034_3264x2448_regs[] = {
|
||||
static const struct regval gc8034_3264x2448_regs_4lane[] = {
|
||||
{REG_NULL, 0x00},
|
||||
};
|
||||
|
||||
static const struct gc8034_mode supported_modes[] = {
|
||||
static const struct gc8034_mode supported_modes_2lane[] = {
|
||||
{
|
||||
.width = 3264,
|
||||
.height = 2448,
|
||||
.max_fps = {
|
||||
.numerator = 10000,
|
||||
.denominator = 150000,
|
||||
},
|
||||
.exp_def = 0x09a0,
|
||||
.hts_def = 0x0858 * 2,
|
||||
.vts_def = 0x09c4,
|
||||
.reg_list = gc8034_3264x2448_regs_2lane,
|
||||
},
|
||||
{
|
||||
.width = 1632,
|
||||
.height = 1224,
|
||||
.max_fps = {
|
||||
.numerator = 10000,
|
||||
.denominator = 300000,
|
||||
},
|
||||
.exp_def = 0x09a0,
|
||||
.hts_def = 0x0858 * 2,
|
||||
.vts_def = 0x09c4,
|
||||
.reg_list = gc8034_1632x1224_regs_2lane,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct gc8034_mode supported_modes_4lane[] = {
|
||||
{
|
||||
.width = 3264,
|
||||
.height = 2448,
|
||||
@@ -460,12 +880,14 @@ static const struct gc8034_mode supported_modes[] = {
|
||||
.exp_def = 0x08c6,
|
||||
.hts_def = 0x10b0,
|
||||
.vts_def = 0x09c0,
|
||||
.reg_list = gc8034_3264x2448_regs,
|
||||
.reg_list = gc8034_3264x2448_regs_4lane,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct gc8034_mode *supported_modes;
|
||||
|
||||
static const s64 link_freq_menu_items[] = {
|
||||
GC8034_LINK_FREQ_MHZ
|
||||
GC8034_MIPI_FREQ_336MHZ,
|
||||
};
|
||||
|
||||
/* Write registers up to 4 at a time */
|
||||
@@ -544,7 +966,8 @@ static int gc8034_get_reso_dist(const struct gc8034_mode *mode,
|
||||
}
|
||||
|
||||
static const struct gc8034_mode *
|
||||
gc8034_find_best_fit(struct v4l2_subdev_format *fmt)
|
||||
gc8034_find_best_fit(struct gc8034 *gc8034,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
struct v4l2_mbus_framefmt *framefmt = &fmt->format;
|
||||
int dist;
|
||||
@@ -552,7 +975,7 @@ gc8034_find_best_fit(struct v4l2_subdev_format *fmt)
|
||||
int cur_best_fit_dist = -1;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
|
||||
for (i = 0; i < gc8034->cfg_num; i++) {
|
||||
dist = gc8034_get_reso_dist(&supported_modes[i], framefmt);
|
||||
if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) {
|
||||
cur_best_fit_dist = dist;
|
||||
@@ -573,8 +996,8 @@ static int gc8034_set_fmt(struct v4l2_subdev *sd,
|
||||
|
||||
mutex_lock(&gc8034->mutex);
|
||||
|
||||
mode = gc8034_find_best_fit(fmt);
|
||||
fmt->format.code = MEDIA_BUS_FMT_SRGGB10_1X10;
|
||||
mode = gc8034_find_best_fit(gc8034, fmt);
|
||||
fmt->format.code = GC8034_MEDIA_BUS_FMT;
|
||||
fmt->format.width = mode->width;
|
||||
fmt->format.height = mode->height;
|
||||
fmt->format.field = V4L2_FIELD_NONE;
|
||||
@@ -594,6 +1017,8 @@ static int gc8034_set_fmt(struct v4l2_subdev *sd,
|
||||
__v4l2_ctrl_modify_range(gc8034->vblank, vblank_def,
|
||||
GC8034_VTS_MAX - mode->height,
|
||||
1, vblank_def);
|
||||
__v4l2_ctrl_s_ctrl(gc8034->link_freq,
|
||||
link_freq_menu_items[0]);
|
||||
}
|
||||
|
||||
mutex_unlock(&gc8034->mutex);
|
||||
@@ -619,7 +1044,7 @@ static int gc8034_get_fmt(struct v4l2_subdev *sd,
|
||||
} else {
|
||||
fmt->format.width = mode->width;
|
||||
fmt->format.height = mode->height;
|
||||
fmt->format.code = MEDIA_BUS_FMT_SRGGB10_1X10;
|
||||
fmt->format.code = GC8034_MEDIA_BUS_FMT;
|
||||
fmt->format.field = V4L2_FIELD_NONE;
|
||||
}
|
||||
mutex_unlock(&gc8034->mutex);
|
||||
@@ -633,7 +1058,7 @@ static int gc8034_enum_mbus_code(struct v4l2_subdev *sd,
|
||||
{
|
||||
if (code->index != 0)
|
||||
return -EINVAL;
|
||||
code->code = MEDIA_BUS_FMT_SRGGB10_1X10;
|
||||
code->code = GC8034_MEDIA_BUS_FMT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -642,10 +1067,12 @@ static int gc8034_enum_frame_sizes(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
struct v4l2_subdev_frame_size_enum *fse)
|
||||
{
|
||||
if (fse->index >= ARRAY_SIZE(supported_modes))
|
||||
struct gc8034 *gc8034 = to_gc8034(sd);
|
||||
|
||||
if (fse->index >= gc8034->cfg_num)
|
||||
return -EINVAL;
|
||||
|
||||
if (fse->code != MEDIA_BUS_FMT_SRGGB10_1X10)
|
||||
if (fse->code != GC8034_MEDIA_BUS_FMT)
|
||||
return -EINVAL;
|
||||
|
||||
fse->min_width = supported_modes[fse->index].width;
|
||||
@@ -669,7 +1096,6 @@ static int gc8034_g_frame_interval(struct v4l2_subdev *sd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define GC8034_MIRROR_NORMAL
|
||||
#define DD_WIDTH 3284
|
||||
#define DD_HEIGHT 2464
|
||||
|
||||
@@ -1226,9 +1652,15 @@ static long gc8034_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
|
||||
ret = gc8034_write_reg(gc8034->client,
|
||||
GC8034_REG_SET_PAGE,
|
||||
GC8034_SET_PAGE_ZERO);
|
||||
ret |= gc8034_write_reg(gc8034->client,
|
||||
GC8034_REG_CTRL_MODE,
|
||||
GC8034_MODE_STREAMING);
|
||||
if (2 == gc8034->lane_num) {
|
||||
ret |= gc8034_write_reg(gc8034->client,
|
||||
GC8034_REG_CTRL_MODE,
|
||||
0x91);
|
||||
} else {
|
||||
ret |= gc8034_write_reg(gc8034->client,
|
||||
GC8034_REG_CTRL_MODE,
|
||||
GC8034_MODE_STREAMING);
|
||||
}
|
||||
} else {
|
||||
ret = gc8034_write_reg(gc8034->client,
|
||||
GC8034_REG_SET_PAGE,
|
||||
@@ -1497,13 +1929,18 @@ static int __gc8034_start_stream(struct gc8034 *gc8034)
|
||||
mutex_unlock(&gc8034->mutex);
|
||||
ret = v4l2_ctrl_handler_setup(&gc8034->ctrl_handler);
|
||||
mutex_lock(&gc8034->mutex);
|
||||
ret = gc8034_write_reg(gc8034->client,
|
||||
ret |= gc8034_write_reg(gc8034->client,
|
||||
GC8034_REG_SET_PAGE,
|
||||
GC8034_SET_PAGE_ZERO);
|
||||
ret |= gc8034_write_reg(gc8034->client,
|
||||
GC8034_REG_CTRL_MODE,
|
||||
GC8034_MODE_STREAMING);
|
||||
|
||||
if (2 == gc8034->lane_num) {
|
||||
ret |= gc8034_write_reg(gc8034->client,
|
||||
GC8034_REG_CTRL_MODE,
|
||||
0x91);
|
||||
} else {
|
||||
ret |= gc8034_write_reg(gc8034->client,
|
||||
GC8034_REG_CTRL_MODE,
|
||||
GC8034_MODE_STREAMING);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1518,7 +1955,7 @@ static int __gc8034_stop_stream(struct gc8034 *gc8034)
|
||||
GC8034_REG_CTRL_MODE,
|
||||
GC8034_MODE_SW_STANDBY);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gc8034_s_stream(struct v4l2_subdev *sd, int on)
|
||||
@@ -1527,6 +1964,12 @@ static int gc8034_s_stream(struct v4l2_subdev *sd, int on)
|
||||
struct i2c_client *client = gc8034->client;
|
||||
int ret = 0;
|
||||
|
||||
dev_info(&client->dev, "%s: on: %d, %dx%d@%d\n", __func__, on,
|
||||
gc8034->cur_mode->width,
|
||||
gc8034->cur_mode->height,
|
||||
DIV_ROUND_CLOSEST(gc8034->cur_mode->max_fps.denominator,
|
||||
gc8034->cur_mode->max_fps.numerator));
|
||||
|
||||
mutex_lock(&gc8034->mutex);
|
||||
on = !!on;
|
||||
if (on == gc8034->streaming)
|
||||
@@ -1564,6 +2007,7 @@ static int gc8034_s_power(struct v4l2_subdev *sd, int on)
|
||||
struct i2c_client *client = gc8034->client;
|
||||
int ret = 0;
|
||||
|
||||
dev_info(&client->dev, "%s(%d) on(%d)\n", __func__, __LINE__, on);
|
||||
mutex_lock(&gc8034->mutex);
|
||||
|
||||
/* If the power state is not modified - no work to do. */
|
||||
@@ -1608,6 +2052,11 @@ static int __gc8034_power_on(struct gc8034 *gc8034)
|
||||
u32 delay_us;
|
||||
struct device *dev = &gc8034->client->dev;
|
||||
|
||||
if (!IS_ERR(gc8034->power_gpio))
|
||||
gpiod_set_value_cansleep(gc8034->power_gpio, 1);
|
||||
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
if (!IS_ERR_OR_NULL(gc8034->pins_default)) {
|
||||
ret = pinctrl_select_state(gc8034->pinctrl,
|
||||
gc8034->pins_default);
|
||||
@@ -1668,6 +2117,9 @@ static void __gc8034_power_off(struct gc8034 *gc8034)
|
||||
if (ret < 0)
|
||||
dev_dbg(&gc8034->client->dev, "could not set pins\n");
|
||||
}
|
||||
if (!IS_ERR(gc8034->power_gpio))
|
||||
gpiod_set_value_cansleep(gc8034->power_gpio, 0);
|
||||
|
||||
regulator_bulk_disable(GC8034_NUM_SUPPLIES, gc8034->supplies);
|
||||
}
|
||||
|
||||
@@ -1703,7 +2155,7 @@ static int gc8034_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
||||
/* Initialize try_fmt */
|
||||
try_fmt->width = def_mode->width;
|
||||
try_fmt->height = def_mode->height;
|
||||
try_fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10;
|
||||
try_fmt->code = GC8034_MEDIA_BUS_FMT;
|
||||
try_fmt->field = V4L2_FIELD_NONE;
|
||||
|
||||
mutex_unlock(&gc8034->mutex);
|
||||
@@ -1717,10 +2169,12 @@ static int gc8034_enum_frame_interval(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
struct v4l2_subdev_frame_interval_enum *fie)
|
||||
{
|
||||
if (fie->index >= ARRAY_SIZE(supported_modes))
|
||||
struct gc8034 *gc8034 = to_gc8034(sd);
|
||||
|
||||
if (fie->index >= gc8034->cfg_num)
|
||||
return -EINVAL;
|
||||
|
||||
if (fie->code != MEDIA_BUS_FMT_SRGGB10_1X10)
|
||||
if (fie->code != GC8034_MEDIA_BUS_FMT)
|
||||
return -EINVAL;
|
||||
|
||||
fie->width = supported_modes[fie->index].width;
|
||||
@@ -1732,14 +2186,25 @@ static int gc8034_enum_frame_interval(struct v4l2_subdev *sd,
|
||||
static int gc8034_g_mbus_config(struct v4l2_subdev *sd,
|
||||
struct v4l2_mbus_config *config)
|
||||
{
|
||||
u32 val = 0;
|
||||
struct gc8034 *sensor = to_gc8034(sd);
|
||||
struct device *dev = &sensor->client->dev;
|
||||
|
||||
val = 1 << (GC8034_LANES - 1) |
|
||||
V4L2_MBUS_CSI2_CHANNEL_0 |
|
||||
V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
|
||||
config->type = V4L2_MBUS_CSI2;
|
||||
config->flags = val;
|
||||
dev_info(dev, "%s(%d) enter!\n", __func__, __LINE__);
|
||||
|
||||
if (2 == sensor->lane_num) {
|
||||
config->type = V4L2_MBUS_CSI2;
|
||||
config->flags = V4L2_MBUS_CSI2_2_LANE |
|
||||
V4L2_MBUS_CSI2_CHANNEL_0 |
|
||||
V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
|
||||
} else if (4 == sensor->lane_num) {
|
||||
config->type = V4L2_MBUS_CSI2;
|
||||
config->flags = V4L2_MBUS_CSI2_4_LANE |
|
||||
V4L2_MBUS_CSI2_CHANNEL_0 |
|
||||
V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
|
||||
} else {
|
||||
dev_err(&sensor->client->dev,
|
||||
"unsupported lane_num(%d)\n", sensor->lane_num);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1902,6 +2367,7 @@ static int gc8034_set_ctrl(struct v4l2_ctrl *ctrl)
|
||||
struct i2c_client *client = gc8034->client;
|
||||
s64 max;
|
||||
int ret = 0;
|
||||
s32 temp;
|
||||
|
||||
/* Propagate change of current control to all related controls */
|
||||
switch (ctrl->id) {
|
||||
@@ -1921,21 +2387,26 @@ static int gc8034_set_ctrl(struct v4l2_ctrl *ctrl)
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_EXPOSURE:
|
||||
/* 4 least significant bits of expsoure are fractional part */
|
||||
dev_info(&client->dev, "set exposure value 0x%x\n", ctrl->val);
|
||||
ret = gc8034_set_exposure_reg(gc8034, ctrl->val);
|
||||
break;
|
||||
case V4L2_CID_ANALOGUE_GAIN:
|
||||
dev_info(&client->dev, "set analog gain value 0x%x\n", ctrl->val);
|
||||
ret = gc8034_set_gain_reg(gc8034, ctrl->val);
|
||||
break;
|
||||
case V4L2_CID_VBLANK:
|
||||
dev_info(&client->dev, "set vb value 0x%x\n", ctrl->val);
|
||||
/* VB = VTS - 2448 -36, according android8.1 driver */
|
||||
temp = ctrl->val + gc8034->cur_mode->height - 2448 - 36;
|
||||
ret = gc8034_write_reg(gc8034->client,
|
||||
GC8034_REG_SET_PAGE,
|
||||
GC8034_SET_PAGE_ZERO);
|
||||
ret |= gc8034_write_reg(gc8034->client,
|
||||
GC8034_REG_VTS_H,
|
||||
((ctrl->val - 36) >> 8) & 0xff);
|
||||
(temp >> 8) & 0xff);
|
||||
ret |= gc8034_write_reg(gc8034->client,
|
||||
GC8034_REG_VTS_L,
|
||||
(ctrl->val - 36) & 0xff);
|
||||
temp & 0xff);
|
||||
break;
|
||||
default:
|
||||
dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n",
|
||||
@@ -1956,7 +2427,6 @@ static int gc8034_initialize_controls(struct gc8034 *gc8034)
|
||||
{
|
||||
const struct gc8034_mode *mode;
|
||||
struct v4l2_ctrl_handler *handler;
|
||||
struct v4l2_ctrl *ctrl;
|
||||
s64 exposure_max, vblank_def;
|
||||
u32 h_blank;
|
||||
int ret;
|
||||
@@ -1968,13 +2438,12 @@ static int gc8034_initialize_controls(struct gc8034 *gc8034)
|
||||
return ret;
|
||||
handler->lock = &gc8034->mutex;
|
||||
|
||||
ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ,
|
||||
0, 0, link_freq_menu_items);
|
||||
if (ctrl)
|
||||
ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
|
||||
gc8034->link_freq = v4l2_ctrl_new_int_menu(handler, NULL,
|
||||
V4L2_CID_LINK_FREQ, 0, 0,
|
||||
link_freq_menu_items);
|
||||
|
||||
v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE,
|
||||
0, GC8034_PIXEL_RATE, 1, GC8034_PIXEL_RATE);
|
||||
0, gc8034->pixel_rate, 1, gc8034->pixel_rate);
|
||||
|
||||
h_blank = mode->hts_def - mode->width;
|
||||
gc8034->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK,
|
||||
@@ -2031,7 +2500,7 @@ static int gc8034_check_sensor_id(struct gc8034 *gc8034,
|
||||
dev_err(dev, "Unexpected sensor id(%06x), ret(%d)\n", id, ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev_info(dev, "detected gc%04x sensor\n", id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2047,6 +2516,60 @@ static int gc8034_configure_regulators(struct gc8034 *gc8034)
|
||||
gc8034->supplies);
|
||||
}
|
||||
|
||||
static int gc8034_parse_of(struct gc8034 *gc8034)
|
||||
{
|
||||
struct device *dev = &gc8034->client->dev;
|
||||
struct device_node *endpoint;
|
||||
struct fwnode_handle *fwnode;
|
||||
int rval;
|
||||
unsigned int fps;
|
||||
|
||||
endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
|
||||
if (!endpoint) {
|
||||
dev_err(dev, "Failed to get endpoint\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
fwnode = of_fwnode_handle(endpoint);
|
||||
rval = fwnode_property_read_u32_array(fwnode, "data-lanes", NULL, 0);
|
||||
if (rval <= 0) {
|
||||
dev_warn(dev, " Get mipi lane num failed!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
gc8034->lane_num = rval;
|
||||
if (4 == gc8034->lane_num) {
|
||||
gc8034->cur_mode = &supported_modes_4lane[0];
|
||||
supported_modes = supported_modes_4lane;
|
||||
gc8034->cfg_num = ARRAY_SIZE(supported_modes_4lane);
|
||||
gc8034_global_regs = gc8034_global_regs_4lane;
|
||||
/* pixel rate = link frequency * 2 * lanes / BITS_PER_SAMPLE */
|
||||
fps = DIV_ROUND_CLOSEST(gc8034->cur_mode->max_fps.denominator,
|
||||
gc8034->cur_mode->max_fps.numerator);
|
||||
gc8034->pixel_rate = gc8034->cur_mode->vts_def *
|
||||
gc8034->cur_mode->hts_def * fps;
|
||||
|
||||
dev_info(dev, "lane_num(%d) pixel_rate(%u)\n",
|
||||
gc8034->lane_num, gc8034->pixel_rate);
|
||||
} else if (2 == gc8034->lane_num) {
|
||||
gc8034->cur_mode = &supported_modes_2lane[0];
|
||||
supported_modes = supported_modes_2lane;
|
||||
gc8034->cfg_num = ARRAY_SIZE(supported_modes_2lane);
|
||||
gc8034_global_regs = gc8034_global_regs_2lane;
|
||||
/*pixel rate = link frequency * 2 * lanes / BITS_PER_SAMPLE */
|
||||
fps = DIV_ROUND_CLOSEST(gc8034->cur_mode->max_fps.denominator,
|
||||
gc8034->cur_mode->max_fps.numerator);
|
||||
gc8034->pixel_rate = gc8034->cur_mode->vts_def *
|
||||
gc8034->cur_mode->hts_def * fps;
|
||||
dev_info(dev, "lane_num(%d) pixel_rate(%u)\n",
|
||||
gc8034->lane_num, gc8034->pixel_rate);
|
||||
} else {
|
||||
dev_err(dev, "unsupported lane_num(%d)\n", gc8034->lane_num);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gc8034_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
@@ -2079,7 +2602,6 @@ static int gc8034_probe(struct i2c_client *client,
|
||||
return -EINVAL;
|
||||
}
|
||||
gc8034->client = client;
|
||||
gc8034->cur_mode = &supported_modes[0];
|
||||
|
||||
gc8034->xvclk = devm_clk_get(dev, "xvclk");
|
||||
if (IS_ERR(gc8034->xvclk)) {
|
||||
@@ -2087,6 +2609,9 @@ static int gc8034_probe(struct i2c_client *client,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gc8034->power_gpio = devm_gpiod_get(dev, "power", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(gc8034->power_gpio))
|
||||
dev_warn(dev, "Failed to get power-gpios, maybe no use\n");
|
||||
gc8034->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(gc8034->reset_gpio))
|
||||
dev_warn(dev, "Failed to get reset-gpios\n");
|
||||
@@ -2101,6 +2626,10 @@ static int gc8034_probe(struct i2c_client *client,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = gc8034_parse_of(gc8034);
|
||||
if (ret != 0)
|
||||
return -EINVAL;
|
||||
|
||||
gc8034->pinctrl = devm_pinctrl_get(dev);
|
||||
if (!IS_ERR(gc8034->pinctrl)) {
|
||||
gc8034->pins_default =
|
||||
|
||||
Reference in New Issue
Block a user