media: i2c: ov7251 support 640x480@120fps mode

Signed-off-by: Yiqing Zeng <zack.zeng@rock-chips.com>
Change-Id: Ic00cfd746ebc91458452ce91c9ae16c078a9db5b
This commit is contained in:
Yiqing Zeng
2021-08-02 16:31:40 +08:00
committed by Tao Huang
parent 5eb4e05072
commit fa0b8533c1

View File

@@ -9,6 +9,7 @@
* 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 support 640x480@120fps mode
*/
#include <linux/clk.h>
@@ -18,6 +19,7 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/pinctrl/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
@@ -28,7 +30,7 @@
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.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
@@ -51,6 +53,7 @@
#define OV7251_EXPOSURE_MIN 4
#define OV7251_EXPOSURE_STEP 0xf
#define OV7251_VTS_MAX 0xffff
#define OV7251_REG_VTS 0x380e
#define OV7251_REG_ANALOG_GAIN 0x350a
#define ANALOG_GAIN_MASK 0x3ff
@@ -63,8 +66,6 @@
#define OV7251_TEST_PATTERN_ENABLE 0x80
#define OV7251_TEST_PATTERN_DISABLE 0x0
#define OV7251_REG_VTS 0x380e
#define REG_NULL 0xFFFF
#define OV7251_REG_VALUE_08BIT 1
@@ -72,8 +73,11 @@
#define OV7251_REG_VALUE_24BIT 3
#define OV7251_NAME "ov7251"
#define OV7251_LANES 1
#define PIX_FORMAT MEDIA_BUS_FMT_Y10_1X10
#define OF_CAMERA_PINCTRL_STATE_DEFAULT "rockchip,camera_default"
#define OF_CAMERA_PINCTRL_STATE_SLEEP "rockchip,camera_sleep"
static const char * const ov7251_supply_names[] = {
"avdd", /* Analog power */
@@ -96,6 +100,7 @@ struct ov7251_mode {
u32 vts_def;
u32 exp_def;
const struct regval *reg_list;
u32 hdr_mode;
};
struct ov7251 {
@@ -104,7 +109,9 @@ struct ov7251 {
struct gpio_desc *reset_gpio;
struct gpio_desc *pwdn_gpio;
struct regulator_bulk_data supplies[OV7251_NUM_SUPPLIES];
struct pinctrl *pinctrl;
struct pinctrl_state *pins_default;
struct pinctrl_state *pins_sleep;
struct v4l2_subdev subdev;
struct media_pad pad;
struct v4l2_ctrl_handler ctrl_handler;
@@ -126,6 +133,160 @@ struct ov7251 {
#define to_ov7251(sd) container_of(sd, struct ov7251, subdev)
/*
* Xclk 24Mhz
* Pclk 48Mhz
* PCLK = HTS * VTS * FPS
* linelength 775(0x302)
* framelength 516(0x204)
* grabwindow_width 640
* grabwindow_height 480
* max_framerate 120fps
* mipi_datarate per lane 640Mbps
*/
static const struct regval ov7251_640x480_120fps_regs[] = {
{0x0103, 0x01},
{0x0100, 0x00},
{0x3005, 0x00},
{0x3012, 0xc0},
{0x3013, 0xd2},
{0x3014, 0x04},
{0x3016, 0x10},
{0x3017, 0x00},
{0x3018, 0x00},
{0x301a, 0x00},
{0x301b, 0x00},
{0x301c, 0x00},
{0x3023, 0x05},
{0x3037, 0xf0},
{0x3098, 0x04},
{0x3099, 0x32},
{0x309a, 0x05},
{0x309b, 0x04},
{0x30b0, 0x0a},
{0x30b1, 0x01},
{0x30b3, 0x64},
{0x30b4, 0x03},
{0x30b5, 0x05},
{0x3106, 0xda},
{0x3500, 0x00},
{0x3501, 0x1f},
{0x3502, 0x80},
{0x3503, 0x07},
{0x3509, 0x10},
{0x350b, 0x10},
{0x3600, 0x1c},
{0x3602, 0x62},
{0x3620, 0xb7},
{0x3622, 0x04},
{0x3626, 0x21},
{0x3627, 0x30},
{0x3630, 0x44},
{0x3631, 0x35},
{0x3634, 0x60},
{0x3636, 0x00},
{0x3662, 0x01},
{0x3663, 0x70},
{0x3664, 0xf0},
{0x3666, 0x0a},
{0x3669, 0x1a},
{0x366a, 0x00},
{0x366b, 0x50},
{0x3673, 0x01},
{0x3674, 0xef},
{0x3675, 0x03},
{0x3705, 0xc1},
{0x3709, 0x40},
{0x373c, 0x08},
{0x3742, 0x00},
{0x3757, 0xb3},
{0x3788, 0x00},
{0x37a8, 0x01},
{0x37a9, 0xc0},
{0x3800, 0x00},
{0x3801, 0x04},
{0x3802, 0x00},
{0x3803, 0x04},
{0x3804, 0x02},
{0x3805, 0x8b},
{0x3806, 0x01},
{0x3807, 0xeb},
{0x3808, 0x02},
{0x3809, 0x80},
{0x380a, 0x01},
{0x380b, 0xe0},
{0x380c, 0x03},
{0x380d, 0xa1},
{0x380e, 0x02},
{0x380f, 0x1a},
{0x3810, 0x00},
{0x3811, 0x04},
{0x3812, 0x00},
{0x3813, 0x05},
{0x3814, 0x11},
{0x3815, 0x11},
{0x3820, 0x40},
{0x3821, 0x00},
{0x382f, 0x0e},
{0x3832, 0x00},
{0x3833, 0x05},
{0x3834, 0x00},
{0x3835, 0x0c},
{0x3837, 0x00},
{0x3b80, 0x00},
{0x3b81, 0xa5},
{0x3b82, 0x10},
{0x3b83, 0x00},
{0x3b84, 0x08},
{0x3b85, 0x00},
{0x3b86, 0x01},
{0x3b87, 0x00},
{0x3b88, 0x00},
{0x3b89, 0x00},
{0x3b8a, 0x00},
{0x3b8b, 0x05},
{0x3b8c, 0x00},
{0x3b8d, 0x00},
{0x3b8e, 0x00},
{0x3b8f, 0x1a},
{0x3b94, 0x05},
{0x3b95, 0xf2},
{0x3b96, 0x40},
{0x3c00, 0x89},
{0x3c01, 0x63},
{0x3c02, 0x01},
{0x3c03, 0x00},
{0x3c04, 0x00},
{0x3c05, 0x03},
{0x3c06, 0x00},
{0x3c07, 0x06},
{0x3c0c, 0x01},
{0x3c0d, 0xd0},
{0x3c0e, 0x02},
{0x3c0f, 0x0a},
{0x4001, 0x42},
{0x4004, 0x04},
{0x4005, 0x00},
{0x404e, 0x01},
{0x4300, 0xff},
{0x4301, 0x00},
{0x4501, 0x48},
{0x4600, 0x00},
{0x4601, 0x4e},
{0x4801, 0x0f},
{0x4806, 0x0f},
{0x4819, 0xaa},
{0x4823, 0x3e},
{0x4837, 0x19},
{0x4a0d, 0x00},
{0x4a47, 0x7f},
{0x4a49, 0xf0},
{0x4a4b, 0x30},
{0x5000, 0x85},
{0x5001, 0x80},
{REG_NULL, 0x00},
};
/*
* Xclk 24Mhz
* Pclk 48Mhz
@@ -137,10 +298,9 @@ struct ov7251 {
* max_framerate 30fps
* mipi_datarate per lane 640Mbps
*/
static const struct regval ov7251_640x480_regs[] = {
static const struct regval ov7251_640x480_30fps_regs[] = {
{0x0100, 0x00},
{0x0103, 0x01},
{0x3001, 0x62},
{0x3005, 0x00},
{0x3012, 0xc0},
@@ -285,6 +445,19 @@ static const struct regval ov7251_640x480_regs[] = {
};
static const struct ov7251_mode supported_modes[] = {
{
.width = 640,
.height = 480,
.max_fps = {
.numerator = 10000,
.denominator = 1200000,
},
.exp_def = 0x00f8,
.hts_def = 0x03a1,
.vts_def = 0x021a,
.reg_list = ov7251_640x480_120fps_regs,
.hdr_mode = 0,
},
{
.width = 640,
.height = 480,
@@ -295,8 +468,9 @@ static const struct ov7251_mode supported_modes[] = {
.exp_def = 0x061c,
.hts_def = 0x03a0,
.vts_def = 0x06b8,
.reg_list = ov7251_640x480_regs,
},
.reg_list = ov7251_640x480_30fps_regs,
.hdr_mode = 0,
}
};
#define OV7251_LINK_FREQ_320MHZ 320000000
@@ -425,7 +599,7 @@ static int ov7251_set_fmt(struct v4l2_subdev *sd,
mutex_lock(&ov7251->mutex);
mode = ov7251_find_best_fit(fmt);
fmt->format.code = MEDIA_BUS_FMT_Y10_1X10;
fmt->format.code = PIX_FORMAT;
fmt->format.width = mode->width;
fmt->format.height = mode->height;
fmt->format.field = V4L2_FIELD_NONE;
@@ -470,7 +644,7 @@ static int ov7251_get_fmt(struct v4l2_subdev *sd,
} else {
fmt->format.width = mode->width;
fmt->format.height = mode->height;
fmt->format.code = MEDIA_BUS_FMT_Y10_1X10;
fmt->format.code = PIX_FORMAT;
fmt->format.field = V4L2_FIELD_NONE;
}
mutex_unlock(&ov7251->mutex);
@@ -484,7 +658,7 @@ static int ov7251_enum_mbus_code(struct v4l2_subdev *sd,
{
if (code->index != 0)
return -EINVAL;
code->code = MEDIA_BUS_FMT_Y10_1X10;
code->code = PIX_FORMAT;
return 0;
}
@@ -496,7 +670,7 @@ static int ov7251_enum_frame_sizes(struct v4l2_subdev *sd,
if (fse->index >= ARRAY_SIZE(supported_modes))
return -EINVAL;
if (fse->code != MEDIA_BUS_FMT_Y10_1X10)
if (fse->code != PIX_FORMAT)
return -EINVAL;
fse->min_width = supported_modes[fse->index].width;
@@ -537,15 +711,16 @@ static void ov7251_get_module_inf(struct ov7251 *ov7251,
struct rkmodule_inf *inf)
{
memset(inf, 0, sizeof(*inf));
strlcpy(inf->base.sensor, OV7251_NAME, sizeof(inf->base.sensor));
strlcpy(inf->base.module, ov7251->module_name,
strscpy(inf->base.sensor, OV7251_NAME, sizeof(inf->base.sensor));
strscpy(inf->base.module, ov7251->module_name,
sizeof(inf->base.module));
strlcpy(inf->base.lens, ov7251->len_name, sizeof(inf->base.lens));
strscpy(inf->base.lens, ov7251->len_name, sizeof(inf->base.lens));
}
static long ov7251_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct ov7251 *ov7251 = to_ov7251(sd);
struct rkmodule_hdr_cfg *hdr;
long ret = 0;
u32 stream = 0;
@@ -553,10 +728,18 @@ static long ov7251_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
case RKMODULE_GET_MODULE_INFO:
ov7251_get_module_inf(ov7251, (struct rkmodule_inf *)arg);
break;
case RKMODULE_GET_HDR_CFG:
hdr = (struct rkmodule_hdr_cfg *)arg;
hdr->esp.mode = HDR_NORMAL_VC;
hdr->hdr_mode = ov7251->cur_mode->hdr_mode;
break;
case RKMODULE_SET_HDR_CFG:
hdr = (struct rkmodule_hdr_cfg *)arg;
if (hdr->hdr_mode != 0)
ret = -1;
break;
case RKMODULE_SET_QUICK_STREAM:
stream = *((u32 *)arg);
if (stream)
ret = ov7251_write_reg(ov7251->client, OV7251_REG_CTRL_MODE,
OV7251_REG_VALUE_08BIT, OV7251_MODE_STREAMING);
@@ -578,7 +761,7 @@ static long ov7251_compat_ioctl32(struct v4l2_subdev *sd,
{
void __user *up = compat_ptr(arg);
struct rkmodule_inf *inf;
struct rkmodule_awb_cfg *cfg;
struct rkmodule_hdr_cfg *hdr;
long ret;
u32 stream = 0;
@@ -591,26 +774,48 @@ static long ov7251_compat_ioctl32(struct v4l2_subdev *sd,
}
ret = ov7251_ioctl(sd, cmd, inf);
if (!ret)
if (!ret) {
ret = copy_to_user(up, inf, sizeof(*inf));
if (ret)
ret = -EFAULT;
}
kfree(inf);
break;
case RKMODULE_AWB_CFG:
cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
if (!cfg) {
case RKMODULE_GET_HDR_CFG:
hdr = kzalloc(sizeof(*hdr), GFP_KERNEL);
if (!hdr) {
ret = -ENOMEM;
return ret;
}
ret = copy_from_user(cfg, up, sizeof(*cfg));
if (!ret)
ret = ov7251_ioctl(sd, cmd, cfg);
kfree(cfg);
ret = ov7251_ioctl(sd, cmd, hdr);
if (!ret) {
ret = copy_to_user(up, hdr, sizeof(*hdr));
if (ret)
ret = -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 = ov7251_ioctl(sd, cmd, hdr);
kfree(hdr);
break;
case RKMODULE_SET_QUICK_STREAM:
ret = copy_from_user(&stream, up, sizeof(u32));
if (!ret)
ret = ov7251_ioctl(sd, cmd, &stream);
if (copy_from_user(&stream, up, sizeof(u32)))
return -EFAULT;
ret = ov7251_ioctl(sd, cmd, &stream);
break;
default:
ret = -ENOIOCTLCMD;
@@ -726,11 +931,18 @@ static int __ov7251_power_on(struct ov7251 *ov7251)
u32 delay_us;
struct device *dev = &ov7251->client->dev;
if (!IS_ERR_OR_NULL(ov7251->pins_default)) {
ret = pinctrl_select_state(ov7251->pinctrl,
ov7251->pins_default);
if (ret < 0)
dev_err(dev, "could not set pins\n");
}
ret = clk_set_rate(ov7251->xvclk, OV7251_XVCLK_FREQ);
if (ret < 0)
dev_warn(dev, "Failed to set xvclk rate (24MHz)\n");
dev_err(dev, "Failed to set xvclk rate (24MHz)\n");
if (clk_get_rate(ov7251->xvclk) != OV7251_XVCLK_FREQ)
dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
dev_err(dev, "xvclk mismatched, modes are based on 24MHz\n");
ret = clk_prepare_enable(ov7251->xvclk);
if (ret < 0) {
dev_err(dev, "Failed to enable xvclk\n");
@@ -763,11 +975,23 @@ static int __ov7251_power_on(struct ov7251 *ov7251)
disable_clk:
clk_disable_unprepare(ov7251->xvclk);
if (!IS_ERR_OR_NULL(ov7251->pins_sleep))
pinctrl_select_state(ov7251->pinctrl, ov7251->pins_sleep);
return ret;
}
static void __ov7251_power_off(struct ov7251 *ov7251)
{
int ret;
struct device *dev = &ov7251->client->dev;
if (!IS_ERR_OR_NULL(ov7251->pins_sleep)) {
ret = pinctrl_select_state(ov7251->pinctrl,
ov7251->pins_sleep);
if (ret < 0)
dev_dbg(dev, "could not set pins\n");
}
if (!IS_ERR(ov7251->pwdn_gpio))
gpiod_set_value_cansleep(ov7251->pwdn_gpio, 0);
clk_disable_unprepare(ov7251->xvclk);
@@ -808,7 +1032,7 @@ static int ov7251_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_Y10_1X10;
try_fmt->code = PIX_FORMAT;
try_fmt->field = V4L2_FIELD_NONE;
mutex_unlock(&ov7251->mutex);
@@ -825,7 +1049,7 @@ static int ov7251_enum_frame_interval(struct v4l2_subdev *sd,
if (fie->index >= ARRAY_SIZE(supported_modes))
return -EINVAL;
if (fie->code != MEDIA_BUS_FMT_Y10_1X10)
if (fie->code != PIX_FORMAT)
return -EINVAL;
fie->width = supported_modes[fie->index].width;
@@ -848,6 +1072,35 @@ static int ov7251_g_mbus_config(struct v4l2_subdev *sd,
return 0;
}
#define CROP_START(SRC, DST) (((SRC) - (DST)) / 2 / 4 * 4)
#define DST_WIDTH 640
#define DST_HEIGHT 480
/*
* The resolution of the driver configuration needs to be exactly
* 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.
* Can be cropped to standard resolution by this function,
* otherwise it will crop out strange resolution according
* to the alignment rules.
*/
static int ov7251_get_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct ov7251 *ov7251 = to_ov7251(sd);
if (sel->target == V4L2_SEL_TGT_CROP_BOUNDS) {
sel->r.left = CROP_START(ov7251->cur_mode->width, DST_WIDTH);
sel->r.width = DST_WIDTH;
sel->r.top = CROP_START(ov7251->cur_mode->height, DST_HEIGHT);
sel->r.height = DST_HEIGHT;
return 0;
}
return -EINVAL;
}
static const struct dev_pm_ops ov7251_pm_ops = {
SET_RUNTIME_PM_OPS(ov7251_runtime_suspend,
ov7251_runtime_resume, NULL)
@@ -879,6 +1132,7 @@ static const struct v4l2_subdev_pad_ops ov7251_pad_ops = {
.enum_frame_interval = ov7251_enum_frame_interval,
.get_fmt = ov7251_get_fmt,
.set_fmt = ov7251_set_fmt,
.get_selection = ov7251_get_selection,
};
static const struct v4l2_subdev_ops ov7251_subdev_ops = {
@@ -1098,7 +1352,22 @@ static int ov7251_probe(struct i2c_client *client,
dev_err(dev, "Failed to get power regulators\n");
return ret;
}
ov7251->pinctrl = devm_pinctrl_get(dev);
if (!IS_ERR(ov7251->pinctrl)) {
ov7251->pins_default =
pinctrl_lookup_state(ov7251->pinctrl,
OF_CAMERA_PINCTRL_STATE_DEFAULT);
if (IS_ERR(ov7251->pins_default))
dev_info(dev, "could not get default pinstate\n");
ov7251->pins_sleep =
pinctrl_lookup_state(ov7251->pinctrl,
OF_CAMERA_PINCTRL_STATE_SLEEP);
if (IS_ERR(ov7251->pins_sleep))
dev_info(dev, "could not get sleep pinstate\n");
} else {
dev_info(dev, "no pinctrl\n");
}
mutex_init(&ov7251->mutex);
sd = &ov7251->subdev;