From 600b2430391e405cc28c710ae25a47517783c702 Mon Sep 17 00:00:00 2001 From: Hu Kejun Date: Mon, 17 Jun 2019 10:23:56 +0800 Subject: [PATCH] media: i2c: ov13850: synchronize with kernel4.4 and update to v01.01.01 Change-Id: I50716a51c39570e68b179fd1adceb5ebb0669520 Signed-off-by: Hu Kejun --- drivers/media/i2c/ov13850.c | 170 ++++++++++++++++++++++++++++++++++-- 1 file changed, 163 insertions(+), 7 deletions(-) diff --git a/drivers/media/i2c/ov13850.c b/drivers/media/i2c/ov13850.c index 6ad238704f41..776bc74c597a 100644 --- a/drivers/media/i2c/ov13850.c +++ b/drivers/media/i2c/ov13850.c @@ -3,6 +3,8 @@ * ov13850 driver * * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd. + * + * V0.0X01.0X01 add poweron function. */ #include @@ -14,12 +16,17 @@ #include #include #include +#include +#include +#include #include #include #include #include #include +#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x01) + #ifndef V4L2_CID_DIGITAL_GAIN #define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN #endif @@ -73,6 +80,8 @@ #define OF_CAMERA_PINCTRL_STATE_DEFAULT "rockchip,camera_default" #define OF_CAMERA_PINCTRL_STATE_SLEEP "rockchip,camera_sleep" +#define OV13850_NAME "ov13850" + static const struct regval *ov13850_global_regs; static const char * const ov13850_supply_names[] = { @@ -120,7 +129,12 @@ struct ov13850 { struct v4l2_ctrl *test_pattern; struct mutex mutex; bool streaming; + bool power_on; const struct ov13850_mode *cur_mode; + u32 module_index; + const char *module_facing; + const char *module_name; + const char *len_name; }; #define to_ov13850(sd) container_of(sd, struct ov13850, subdev) @@ -884,14 +898,80 @@ static int ov13850_g_frame_interval(struct v4l2_subdev *sd, return 0; } +static void ov13850_get_module_inf(struct ov13850 *ov13850, + struct rkmodule_inf *inf) +{ + memset(inf, 0, sizeof(*inf)); + strlcpy(inf->base.sensor, OV13850_NAME, sizeof(inf->base.sensor)); + strlcpy(inf->base.module, ov13850->module_name, + sizeof(inf->base.module)); + strlcpy(inf->base.lens, ov13850->len_name, sizeof(inf->base.lens)); +} + +static long ov13850_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct ov13850 *ov13850 = to_ov13850(sd); + long ret = 0; + + switch (cmd) { + case RKMODULE_GET_MODULE_INFO: + ov13850_get_module_inf(ov13850, (struct rkmodule_inf *)arg); + break; + default: + ret = -ENOIOCTLCMD; + break; + } + + return ret; +} + +#ifdef CONFIG_COMPAT +static long ov13850_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; + long ret; + + switch (cmd) { + case RKMODULE_GET_MODULE_INFO: + inf = kzalloc(sizeof(*inf), GFP_KERNEL); + if (!inf) { + ret = -ENOMEM; + return ret; + } + + ret = ov13850_ioctl(sd, cmd, inf); + if (!ret) + ret = copy_to_user(up, inf, sizeof(*inf)); + kfree(inf); + break; + case RKMODULE_AWB_CFG: + cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); + if (!cfg) { + ret = -ENOMEM; + return ret; + } + + ret = copy_from_user(cfg, up, sizeof(*cfg)); + if (!ret) + ret = ov13850_ioctl(sd, cmd, cfg); + kfree(cfg); + break; + default: + ret = -ENOIOCTLCMD; + break; + } + + return ret; +} +#endif + static int __ov13850_start_stream(struct ov13850 *ov13850) { int ret; - ret = ov13850_write_array(ov13850->client, ov13850_global_regs); - if (ret) - return ret; - ret = ov13850_write_array(ov13850->client, ov13850->cur_mode->reg_list); if (ret) return ret; @@ -954,6 +1034,44 @@ static int ov13850_s_stream(struct v4l2_subdev *sd, int on) return ret; } +static int ov13850_s_power(struct v4l2_subdev *sd, int on) +{ + struct ov13850 *ov13850 = to_ov13850(sd); + struct i2c_client *client = ov13850->client; + int ret = 0; + + mutex_lock(&ov13850->mutex); + + /* If the power state is not modified - no work to do. */ + if (ov13850->power_on == !!on) + goto unlock_and_return; + + if (on) { + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&client->dev); + goto unlock_and_return; + } + + ret = ov13850_write_array(ov13850->client, ov13850_global_regs); + if (ret) { + v4l2_err(sd, "could not set init registers\n"); + pm_runtime_put_noidle(&client->dev); + goto unlock_and_return; + } + + ov13850->power_on = true; + } else { + pm_runtime_put(&client->dev); + ov13850->power_on = false; + } + +unlock_and_return: + mutex_unlock(&ov13850->mutex); + + return ret; +} + /* Calculate the delay in us by clock rate and clock cycles */ static inline u32 ov13850_cal_delay(u32 cycles) { @@ -1079,6 +1197,14 @@ static const struct v4l2_subdev_internal_ops ov13850_internal_ops = { }; #endif +static const struct v4l2_subdev_core_ops ov13850_core_ops = { + .s_power = ov13850_s_power, + .ioctl = ov13850_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = ov13850_compat_ioctl32, +#endif +}; + static const struct v4l2_subdev_video_ops ov13850_video_ops = { .s_stream = ov13850_s_stream, .g_frame_interval = ov13850_g_frame_interval, @@ -1092,6 +1218,7 @@ static const struct v4l2_subdev_pad_ops ov13850_pad_ops = { }; static const struct v4l2_subdev_ops ov13850_subdev_ops = { + .core = &ov13850_core_ops, .video = &ov13850_video_ops, .pad = &ov13850_pad_ops, }; @@ -1242,7 +1369,7 @@ static int ov13850_check_sensor_id(struct ov13850 *ov13850, OV13850_REG_VALUE_16BIT, &id); if (id != CHIP_ID) { dev_err(dev, "Unexpected sensor id(%06x), ret(%d)\n", id, ret); - return ret; + return -ENODEV; } ret = ov13850_read_reg(client, OV13850_CHIP_REVISION_REG, @@ -1277,14 +1404,34 @@ static int ov13850_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; + struct device_node *node = dev->of_node; struct ov13850 *ov13850; struct v4l2_subdev *sd; + char facing[2]; int ret; + dev_info(dev, "driver version: %02x.%02x.%02x", + DRIVER_VERSION >> 16, + (DRIVER_VERSION & 0xff00) >> 8, + DRIVER_VERSION & 0x00ff); + ov13850 = devm_kzalloc(dev, sizeof(*ov13850), GFP_KERNEL); if (!ov13850) return -ENOMEM; + ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX, + &ov13850->module_index); + ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING, + &ov13850->module_facing); + ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME, + &ov13850->module_name); + ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME, + &ov13850->len_name); + if (ret) { + dev_err(dev, "could not get module information!\n"); + return -EINVAL; + } + ov13850->client = client; ov13850->cur_mode = &supported_modes[0]; @@ -1358,7 +1505,16 @@ static int ov13850_probe(struct i2c_client *client, goto err_power_off; #endif - ret = v4l2_async_register_subdev(sd); + memset(facing, 0, sizeof(facing)); + if (strcmp(ov13850->module_facing, "back") == 0) + facing[0] = 'b'; + else + facing[0] = 'f'; + + snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s", + ov13850->module_index, facing, + OV13850_NAME, dev_name(sd->dev)); + ret = v4l2_async_register_subdev_sensor_common(sd); if (ret) { dev_err(dev, "v4l2 async register subdev failed\n"); goto err_clean_entity; @@ -1419,7 +1575,7 @@ static const struct i2c_device_id ov13850_match_id[] = { static struct i2c_driver ov13850_i2c_driver = { .driver = { - .name = "ov13850", + .name = OV13850_NAME, .pm = &ov13850_pm_ops, .of_match_table = of_match_ptr(ov13850_of_match), },