From 0e15664e4eda6e09c799d1d0fb7c791fb59b257c Mon Sep 17 00:00:00 2001 From: Bhanu Murthy V Date: Wed, 29 Aug 2018 15:21:55 -0700 Subject: drivers: camera: Move v4l2 subdev ops to tegracam Move all v4l2 initialization to common framework, ensures most of the duplicated code in sensor drivers reduced. Now sensor drivers will have control and core ops for all operations. New ops - set_mode, start_streaming and stop_streaming are added to modularize sensor drivers. Update current sensor drivers with the new modifications. Bug 2101376 Change-Id: Ic4070bde28f3dce61430af9ecded0541cda2f6fe Signed-off-by: Bhanu Murthy V Reviewed-on: https://git-master.nvidia.com/r/1810324 (cherry picked from commit e5801b45ee0ca88a4d3ea6e98ac24800f1971806) Reviewed-on: https://git-master.nvidia.com/r/1961293 Tested-by: Vincent Chung GVS: Gerrit_Virtual_Submit Tested-by: Frank Chen Reviewed-by: Frank Chen Reviewed-by: David Bang Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/media/i2c/imx185.c | 186 +++++--------------- drivers/media/i2c/imx268.c | 179 +++++-------------- drivers/media/i2c/imx318.c | 181 +++++--------------- drivers/media/platform/tegra/camera/Makefile | 2 +- .../media/platform/tegra/camera/tegracam_core.c | 88 +--------- .../media/platform/tegra/camera/tegracam_ctrls.c | 69 ++++++++ .../media/platform/tegra/camera/tegracam_v4l2.c | 189 +++++++++++++++++++++ include/media/camera_common.h | 4 + include/media/tegracam_core.h | 4 +- 9 files changed, 398 insertions(+), 504 deletions(-) create mode 100644 drivers/media/platform/tegra/camera/tegracam_v4l2.c diff --git a/drivers/media/i2c/imx185.c b/drivers/media/i2c/imx185.c index 5c9536cd7..9fef03a53 100644 --- a/drivers/media/i2c/imx185.c +++ b/drivers/media/i2c/imx185.c @@ -591,165 +591,77 @@ error: return ret; } -static struct camera_common_sensor_ops imx185_common_ops = { - .numfrmfmts = ARRAY_SIZE(imx185_frmfmt), - .frmfmt_table = imx185_frmfmt, - .power_on = imx185_power_on, - .power_off = imx185_power_off, - .write_reg = imx185_write_reg, - .read_reg = imx185_read_reg, - .parse_dt = imx185_parse_dt, - .power_get = imx185_power_get, - .power_put = imx185_power_put, -}; - -static int imx185_s_stream(struct v4l2_subdev *sd, int enable) +static int imx185_set_mode(struct tegracam_device *tc_dev) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct device *dev = &client->dev; - struct camera_common_data *s_data = to_camera_common_data(dev); - struct imx185 *priv = (struct imx185 *)s_data->priv; - struct v4l2_ext_controls ctrls; - struct v4l2_ext_control control[3]; + struct imx185 *priv = (struct imx185 *)tegracam_get_privdata(tc_dev); + struct camera_common_data *s_data = tc_dev->s_data; int err; - dev_dbg(dev, "%s++ enable %d\n", __func__, enable); - - trace_imx185_s_stream(sd->name, enable, s_data->mode); - if (!enable) { - err = imx185_write_table(priv, - mode_table[IMX185_MODE_STOP_STREAM]); - - if (err) - return err; - - /* SW_RESET will have no ACK */ - regmap_write(s_data->regmap, IMX185_SW_RESET_ADDR, 0x01); - - /* Wait for one frame to make sure sensor is set to - * software standby in V-blank - * - * delay = frame length rows * Tline (10 us) - */ - usleep_range(priv->frame_length * 10, - priv->frame_length * 10 + 1000); - return 0; - } err = imx185_write_table(priv, mode_table[s_data->mode_prop_idx]); if (err) - goto exit; - - if (s_data->override_enable) { - /* write list of override regs for the asking gain, */ - /* frame rate and exposure time */ - memset(&ctrls, 0, sizeof(ctrls)); -#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 9, 0) - ctrls.which = V4L2_CTRL_ID2WHICH(TEGRA_CAMERA_CID_GAIN); -#else - ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(TEGRA_CAMERA_CID_GAIN); -#endif - ctrls.count = 3; - ctrls.controls = control; - - control[0].id = TEGRA_CAMERA_CID_GAIN; - control[1].id = TEGRA_CAMERA_CID_FRAME_RATE; - control[2].id = TEGRA_CAMERA_CID_EXPOSURE; - - err = v4l2_g_ext_ctrls(s_data->ctrl_handler, &ctrls); - if (err == 0) { - err |= imx185_set_gain(priv->tc_dev, control[0].value64); - if (err) - dev_err(dev, "%s: error gain override\n", - __func__); - - err |= imx185_set_frame_rate(priv->tc_dev, - control[1].value64); - if (err) - dev_err(dev, - "%s: error frame length override\n", - __func__); - - err |= imx185_set_exposure(priv->tc_dev, control[2].value64); - if (err) - dev_err(dev, "%s: error exposure override\n", - __func__); - - } else { - dev_err(dev, "%s: faile to get overrides\n", __func__); - } - } + return err; + + return 0; +} + +static int imx185_start_streaming(struct tegracam_device *tc_dev) +{ + struct imx185 *priv = (struct imx185 *)tegracam_get_privdata(tc_dev); + int err; if (test_mode) { err = imx185_write_table(priv, mode_table[IMX185_MODE_TEST_PATTERN]); if (err) - goto exit; + return err; } - err = imx185_write_table(priv, mode_table[IMX185_MODE_START_STREAM]); + err = imx185_write_table(priv, + mode_table[IMX185_MODE_START_STREAM]); if (err) - goto exit; + return err; return 0; -exit: - dev_err(dev, "%s: error setting stream\n", __func__); - return err; } -static int imx185_g_input_status(struct v4l2_subdev *sd, u32 *status) +static int imx185_stop_streaming(struct tegracam_device *tc_dev) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct camera_common_data *s_data = to_camera_common_data(&client->dev); - struct camera_common_power_rail *pw = s_data->power; - - *status = pw->state == SWITCH_ON; - return 0; -} - -static struct v4l2_subdev_video_ops imx185_subdev_video_ops = { - .s_stream = imx185_s_stream, - .g_mbus_config = camera_common_g_mbus_config, - .g_input_status = imx185_g_input_status, -}; - -static struct v4l2_subdev_core_ops imx185_subdev_core_ops = { - .s_power = camera_common_s_power, -}; + struct camera_common_data *s_data = tc_dev->s_data; + struct imx185 *priv = (struct imx185 *)tegracam_get_privdata(tc_dev); + int err; -static int imx185_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - return camera_common_g_fmt(sd, &format->format); -} + err = imx185_write_table(priv, mode_table[IMX185_MODE_STOP_STREAM]); + if (err) + return err; -static int imx185_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - int ret; + /* SW_RESET will have no ACK */ + imx185_write_reg(s_data, IMX185_SW_RESET_ADDR, 0x01); - if (format->which == V4L2_SUBDEV_FORMAT_TRY) - ret = camera_common_try_fmt(sd, &format->format); - else - ret = camera_common_s_fmt(sd, &format->format); + /* + * Wait for one frame to make sure sensor is set to + * software standby in V-blank + * + * delay = frame length rows * Tline (10 us) + */ + usleep_range(priv->frame_length * 10, priv->frame_length * 10 + 1000); - return ret; + return 0; } -static struct v4l2_subdev_pad_ops imx185_subdev_pad_ops = { - .set_fmt = imx185_set_fmt, - .get_fmt = imx185_get_fmt, - .enum_mbus_code = camera_common_enum_mbus_code, - .enum_frame_size = camera_common_enum_framesizes, - .enum_frame_interval = camera_common_enum_frameintervals, -}; - -static struct v4l2_subdev_ops imx185_subdev_ops = { - .core = &imx185_subdev_core_ops, - .video = &imx185_subdev_video_ops, - .pad = &imx185_subdev_pad_ops, +static struct camera_common_sensor_ops imx185_common_ops = { + .numfrmfmts = ARRAY_SIZE(imx185_frmfmt), + .frmfmt_table = imx185_frmfmt, + .power_on = imx185_power_on, + .power_off = imx185_power_off, + .write_reg = imx185_write_reg, + .read_reg = imx185_read_reg, + .parse_dt = imx185_parse_dt, + .power_get = imx185_power_get, + .power_put = imx185_power_put, + .set_mode = imx185_set_mode, + .start_streaming = imx185_start_streaming, + .stop_streaming = imx185_stop_streaming, }; static int imx185_fuse_id_setup(struct imx185 *priv) @@ -822,10 +734,6 @@ static const struct v4l2_subdev_internal_ops imx185_subdev_internal_ops = { .open = imx185_open, }; -static const struct media_entity_operations imx185_media_ops = { - .link_validate = v4l2_subdev_link_validate, -}; - static int imx185_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -854,9 +762,7 @@ static int imx185_probe(struct i2c_client *client, strncpy(tc_dev->name, "imx185", sizeof(tc_dev->name)); tc_dev->dev_regmap_config = &sensor_regmap_config; tc_dev->sensor_ops = &imx185_common_ops; - tc_dev->v4l2sd_ops = &imx185_subdev_ops; tc_dev->v4l2sd_internal_ops = &imx185_subdev_internal_ops; - tc_dev->media_ops = &imx185_media_ops; tc_dev->tcctrl_ops = &imx185_ctrl_ops; err = tegracam_device_register(tc_dev); diff --git a/drivers/media/i2c/imx268.c b/drivers/media/i2c/imx268.c index 341184437..59d69fe81 100644 --- a/drivers/media/i2c/imx268.c +++ b/drivers/media/i2c/imx268.c @@ -524,164 +524,67 @@ error: return ret; } -static struct camera_common_sensor_ops imx268_common_ops = { - .numfrmfmts = ARRAY_SIZE(imx268_frmfmt), - .frmfmt_table = imx268_frmfmt, - .power_on = imx268_power_on, - .power_off = imx268_power_off, - .write_reg = imx268_write_reg, - .read_reg = imx268_read_reg, - .parse_dt = imx268_parse_dt, - .power_get = imx268_power_get, - .power_put = imx268_power_put, -}; - -static int imx268_s_stream(struct v4l2_subdev *sd, int enable) +static int imx268_set_mode(struct tegracam_device *tc_dev) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct camera_common_data *s_data = to_camera_common_data(&client->dev); - struct imx268 *priv = (struct imx268 *)s_data->priv; - struct v4l2_ext_controls ctrls; - struct v4l2_ext_control control[3]; + struct imx268 *priv = (struct imx268 *)tegracam_get_privdata(tc_dev); + struct camera_common_data *s_data = tc_dev->s_data; int err; - dev_dbg(&client->dev, "%s++ enable %d\n", __func__, enable); - - if (!enable) { - err = imx268_write_table(priv, - mode_table[IMX268_MODE_STREAM_STOP]); - if (err) - return err; - - /* - * Wait for one frame to make sure sensor is set to - * software standby in V-blank - * - * delay = frame length rows * Tline (10 us) - */ - usleep_range(priv->frame_length * 10, - priv->frame_length * 10 + 1000); - - return 0; - } - err = imx268_write_table(priv, mode_table[IMX268_MODE_COMMON]); if (err) - goto exit; + return err; err = imx268_write_table(priv, mode_table[s_data->mode]); if (err) - goto exit; - - if (s_data->override_enable) { - /* - * write list of override regs for the asking frame length, - * coarse integration time, and gain. Failures to write - * overrides are non-fatal - */ - memset(&ctrls, 0, sizeof(ctrls)); -#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 9, 0) - ctrls.which = V4L2_CTRL_ID2WHICH(TEGRA_CAMERA_CID_GAIN); -#else - ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(TEGRA_CAMERA_CID_GAIN); -#endif - ctrls.count = 3; - ctrls.controls = control; - - control[0].id = TEGRA_CAMERA_CID_GAIN; - control[1].id = TEGRA_CAMERA_CID_FRAME_RATE; - control[2].id = TEGRA_CAMERA_CID_EXPOSURE; - - err = v4l2_g_ext_ctrls(s_data->ctrl_handler, &ctrls); - if (err == 0) { - err |= imx268_set_gain(priv->tc_dev, control[0].value64); - if (err) - dev_err(&client->dev, - "%s: error gain override\n", __func__); - - err |= imx268_set_frame_rate(priv->tc_dev, - control[1].value64); - if (err) - dev_err(&client->dev, - "%s: error frame length override\n", - __func__); - - err |= imx268_set_exposure(priv->tc_dev, control[2].value64); - if (err) - dev_err(&client->dev, - "%s: error exposure override\n", - __func__); - - } else { - dev_err(&client->dev, "%s: failed to get overrides\n", - __func__); - } - } - - err = imx268_write_table(priv, mode_table[IMX268_MODE_STREAM_START]); - if (err) - goto exit; + return err; return 0; -exit: - dev_err(&client->dev, "%s: error setting stream\n", __func__); - return err; } -static int imx268_g_input_status(struct v4l2_subdev *sd, u32 *status) +static int imx268_start_streaming(struct tegracam_device *tc_dev) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct camera_common_data *s_data = to_camera_common_data(&client->dev); - struct camera_common_power_rail *pw = s_data->power; + struct imx268 *priv = (struct imx268 *)tegracam_get_privdata(tc_dev); + int err; - *status = pw->state == SWITCH_ON; + err = imx268_write_table(priv, mode_table[IMX268_MODE_STREAM_START]); + if (err) + return err; return 0; } -static struct v4l2_subdev_video_ops imx268_subdev_video_ops = { - .s_stream = imx268_s_stream, - .g_mbus_config = camera_common_g_mbus_config, - .g_input_status = imx268_g_input_status, -}; - -static struct v4l2_subdev_core_ops imx268_subdev_core_ops = { - .s_power = camera_common_s_power, -}; - -static int imx268_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - return camera_common_g_fmt(sd, &format->format); -} - -static int imx268_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) +static int imx268_stop_streaming(struct tegracam_device *tc_dev) { - int ret; + struct imx268 *priv = (struct imx268 *)tegracam_get_privdata(tc_dev); + int err; - if (format->which == V4L2_SUBDEV_FORMAT_TRY) - ret = camera_common_try_fmt(sd, &format->format); - else - ret = camera_common_s_fmt(sd, &format->format); + err = imx268_write_table(priv, mode_table[IMX268_MODE_STREAM_STOP]); + if (err) + return err; + /* + * Wait for one frame to make sure sensor is set to + * software standby in V-blank + * + * delay = frame length rows * Tline (10 us) + */ + usleep_range(priv->frame_length * 10, priv->frame_length * 10 + 1000); - return ret; + return 0; } -static struct v4l2_subdev_pad_ops imx268_subdev_pad_ops = { - .set_fmt = imx268_set_fmt, - .get_fmt = imx268_get_fmt, - .enum_mbus_code = camera_common_enum_mbus_code, - .enum_frame_size = camera_common_enum_framesizes, - .enum_frame_interval = camera_common_enum_frameintervals, -}; - -static struct v4l2_subdev_ops imx268_subdev_ops = { - .core = &imx268_subdev_core_ops, - .video = &imx268_subdev_video_ops, - .pad = &imx268_subdev_pad_ops, +static struct camera_common_sensor_ops imx268_common_ops = { + .numfrmfmts = ARRAY_SIZE(imx268_frmfmt), + .frmfmt_table = imx268_frmfmt, + .power_on = imx268_power_on, + .power_off = imx268_power_off, + .write_reg = imx268_write_reg, + .read_reg = imx268_read_reg, + .parse_dt = imx268_parse_dt, + .power_get = imx268_power_get, + .power_put = imx268_power_put, + .set_mode = imx268_set_mode, + .start_streaming = imx268_start_streaming, + .stop_streaming = imx268_stop_streaming, }; static int imx268_board_setup(struct imx268 *priv) @@ -731,10 +634,6 @@ static const struct v4l2_subdev_internal_ops imx268_subdev_internal_ops = { .open = imx268_open, }; -static const struct media_entity_operations imx268_media_ops = { - .link_validate = v4l2_subdev_link_validate, -}; - static int imx268_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -762,9 +661,7 @@ static int imx268_probe(struct i2c_client *client, strncpy(tc_dev->name, "imx268", sizeof(tc_dev->name)); tc_dev->dev_regmap_config = &sensor_regmap_config; tc_dev->sensor_ops = &imx268_common_ops; - tc_dev->v4l2sd_ops = &imx268_subdev_ops; tc_dev->v4l2sd_internal_ops = &imx268_subdev_internal_ops; - tc_dev->media_ops = &imx268_media_ops; tc_dev->tcctrl_ops = &imx268_ctrl_ops; err = tegracam_device_register(tc_dev); diff --git a/drivers/media/i2c/imx318.c b/drivers/media/i2c/imx318.c index abfedec0a..1d69ed70a 100644 --- a/drivers/media/i2c/imx318.c +++ b/drivers/media/i2c/imx318.c @@ -552,162 +552,69 @@ error: } -static struct camera_common_sensor_ops imx318_common_ops = { - .numfrmfmts = ARRAY_SIZE(imx318_frmfmt), - .frmfmt_table = imx318_frmfmt, - .power_on = imx318_power_on, - .power_off = imx318_power_off, - .write_reg = imx318_write_reg, - .read_reg = imx318_read_reg, - .parse_dt = imx318_parse_dt, - .power_get = imx318_power_get, - .power_put = imx318_power_put, -}; - - -static int imx318_s_stream(struct v4l2_subdev *sd, int enable) +static int imx318_set_mode(struct tegracam_device *tc_dev) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct camera_common_data *s_data = to_camera_common_data(&client->dev); - struct imx318 *priv = (struct imx318 *)s_data->priv; - struct v4l2_ext_controls ctrls; - struct v4l2_ext_control control[3]; + struct imx318 *priv = (struct imx318 *)tegracam_get_privdata(tc_dev); + struct camera_common_data *s_data = tc_dev->s_data; int err; - dev_dbg(&client->dev, "%s++ enable %d\n", __func__, enable); - - if (!enable) { - err = imx318_write_table(priv, - mode_table[IMX318_MODE_STOP_STREAM]); - if (err) - return err; - - /* - * Wait for one frame to make sure sensor is set to - * software standby in V-blank - * - * delay = frame length rows * Tline (10 us) - */ - usleep_range(priv->frame_length * 10, - priv->frame_length * 10 + 1000); - return 0; - } - err = imx318_write_table(priv, mode_table[IMX318_MODE_COMMON]); if (err) - goto exit; - err = imx318_write_table(priv, mode_table[s_data->mode]); - if (err) - goto exit; - - if (s_data->override_enable) { - /* - * write list of override regs for the asking frame length, - * coarse integration time, and gain. Failures to write - * overrides are non-fatal - */ - memset(&ctrls, 0, sizeof(ctrls)); -#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 9, 0) - ctrls.which = V4L2_CTRL_ID2WHICH(TEGRA_CAMERA_CID_GAIN); -#else - ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(TEGRA_CAMERA_CID_GAIN); -#endif - ctrls.count = 3; - ctrls.controls = control; - - control[0].id = TEGRA_CAMERA_CID_GAIN; - control[1].id = TEGRA_CAMERA_CID_FRAME_RATE; - control[2].id = TEGRA_CAMERA_CID_EXPOSURE; - - err = v4l2_g_ext_ctrls(s_data->ctrl_handler, &ctrls); - if (err == 0) { - err |= imx318_set_gain(priv->tc_dev, control[0].value64); - if (err) - dev_err(&client->dev, - "%s: error gain override\n", __func__); - - err |= imx318_set_frame_rate(priv->tc_dev, - control[1].value64); - if (err) - dev_err(&client->dev, - "%s: error frame length override\n", - __func__); - - err |= imx318_set_exposure(priv->tc_dev, control[2].value64); - if (err) - dev_err(&client->dev, - "%s: error exposure override\n", - __func__); - } else { - dev_err(&client->dev, "%s: faile to get overrides\n", - __func__); - } - } + return err; - err = imx318_write_table(priv, mode_table[IMX318_MODE_START_STREAM]); + err = imx318_write_table(priv, mode_table[s_data->mode]); if (err) - goto exit; + return err; - usleep_range(10000, 10010); /* from tegrashell */ return 0; -exit: - dev_err(&client->dev, "%s: error setting stream\n", __func__); - return err; } -static int imx318_g_input_status(struct v4l2_subdev *sd, u32 *status) +static int imx318_start_streaming(struct tegracam_device *tc_dev) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct camera_common_data *s_data = to_camera_common_data(&client->dev); - struct camera_common_power_rail *pw = s_data->power; - - *status = pw->state == SWITCH_ON; - return 0; -} + struct imx318 *priv = (struct imx318 *)tegracam_get_privdata(tc_dev); + int err; -static struct v4l2_subdev_video_ops imx318_subdev_video_ops = { - .s_stream = imx318_s_stream, - .g_mbus_config = camera_common_g_mbus_config, - .g_input_status = imx318_g_input_status, -}; + err = imx318_write_table(priv, mode_table[IMX318_MODE_START_STREAM]); + if (err) + return err; -static struct v4l2_subdev_core_ops imx318_subdev_core_ops = { - .s_power = camera_common_s_power, -}; + usleep_range(10000, 10010); /* from tegrashell */ -static int imx318_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - return camera_common_g_fmt(sd, &format->format); + return 0; } -static int imx318_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) +static int imx318_stop_streaming(struct tegracam_device *tc_dev) { - int ret; + struct imx318 *priv = (struct imx318 *)tegracam_get_privdata(tc_dev); + int err; - if (format->which == V4L2_SUBDEV_FORMAT_TRY) - ret = camera_common_try_fmt(sd, &format->format); - else - ret = camera_common_s_fmt(sd, &format->format); + err = imx318_write_table(priv, mode_table[IMX318_MODE_STOP_STREAM]); + if (err) + return err; + /* + * Wait for one frame to make sure sensor is set to + * software standby in V-blank + * + * delay = frame length rows * Tline (10 us) + */ + usleep_range(priv->frame_length * 10, priv->frame_length * 10 + 1000); - return ret; + return 0; } -static struct v4l2_subdev_pad_ops imx318_subdev_pad_ops = { - .set_fmt = imx318_set_fmt, - .get_fmt = imx318_get_fmt, - .enum_mbus_code = camera_common_enum_mbus_code, - .enum_frame_size = camera_common_enum_framesizes, - .enum_frame_interval = camera_common_enum_frameintervals, -}; - -static struct v4l2_subdev_ops imx318_subdev_ops = { - .core = &imx318_subdev_core_ops, - .video = &imx318_subdev_video_ops, - .pad = &imx318_subdev_pad_ops, +static struct camera_common_sensor_ops imx318_common_ops = { + .numfrmfmts = ARRAY_SIZE(imx318_frmfmt), + .frmfmt_table = imx318_frmfmt, + .power_on = imx318_power_on, + .power_off = imx318_power_off, + .write_reg = imx318_write_reg, + .read_reg = imx318_read_reg, + .parse_dt = imx318_parse_dt, + .power_get = imx318_power_get, + .power_put = imx318_power_put, + .set_mode = imx318_set_mode, + .start_streaming = imx318_start_streaming, + .stop_streaming = imx318_stop_streaming, }; static int imx318_eeprom_device_release(struct imx318 *priv) @@ -849,10 +756,6 @@ static const struct v4l2_subdev_internal_ops imx318_subdev_internal_ops = { .open = imx318_open, }; -static const struct media_entity_operations imx318_media_ops = { - .link_validate = v4l2_subdev_link_validate, -}; - static int imx318_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -882,9 +785,7 @@ static int imx318_probe(struct i2c_client *client, strncpy(tc_dev->name, "imx318", sizeof(tc_dev->name)); tc_dev->dev_regmap_config = &sensor_regmap_config; tc_dev->sensor_ops = &imx318_common_ops; - tc_dev->v4l2sd_ops = &imx318_subdev_ops; tc_dev->v4l2sd_internal_ops = &imx318_subdev_internal_ops; - tc_dev->media_ops = &imx318_media_ops; tc_dev->tcctrl_ops = &imx318_ctrl_ops; err = tegracam_device_register(tc_dev); diff --git a/drivers/media/platform/tegra/camera/Makefile b/drivers/media/platform/tegra/camera/Makefile index e89cffc4e..8072676a8 100644 --- a/drivers/media/platform/tegra/camera/Makefile +++ b/drivers/media/platform/tegra/camera/Makefile @@ -8,7 +8,7 @@ ccflags-y += -Werror obj-y += vi/ obj-y += csi/ obj-y += camera_common.o camera_gpio.o sensor_common.o camera_version_utils.o \ - tegracam_ctrls.o tegracam_core.o + tegracam_ctrls.o tegracam_core.o tegracam_v4l2.o obj-$(CONFIG_TEGRA_CAMERA_RTCPU) += capture_common.o obj-$(CONFIG_TEGRA_CAMERA_RTCPU) += isp/isp_channel.o obj-$(CONFIG_TEGRA_CAMERA_RTCPU) += isp/capture_isp.o diff --git a/drivers/media/platform/tegra/camera/tegracam_core.c b/drivers/media/platform/tegra/camera/tegracam_core.c index 37ec6574b..5bb3c6ca7 100644 --- a/drivers/media/platform/tegra/camera/tegracam_core.c +++ b/drivers/media/platform/tegra/camera/tegracam_core.c @@ -19,13 +19,18 @@ #include #include - +struct tegracam_device *to_tegracam_device(struct camera_common_data *data) +{ + /* fix this by moving subdev to base struct */ + return (struct tegracam_device *)data->tegracam_ctrl_hdl->tc_dev; +} +EXPORT_SYMBOL_GPL(to_tegracam_device); void tegracam_set_privdata(struct tegracam_device * tc_dev, void *priv) { tc_dev->priv = priv; - /* TODO: cleanup needed for priv once all the sensors adapt new framework */ + /* TODO: cleanup needed for priv once sensors adapt this driver */ tc_dev->s_data->priv = priv; } EXPORT_SYMBOL_GPL(tegracam_set_privdata); @@ -116,72 +121,6 @@ int tegracam_device_register(struct tegracam_device *tc_dev) } EXPORT_SYMBOL_GPL(tegracam_device_register); -int tegracam_v4l2subdev_register(struct tegracam_device *tc_dev, - bool is_sensor) -{ - struct camera_common_data *s_data = tc_dev->s_data; - struct tegracam_ctrl_handler *ctrl_hdl = s_data->tegracam_ctrl_hdl; - struct v4l2_subdev *sd = NULL; - struct device *dev = tc_dev->dev; - int err = 0; - - /* init v4l2 subdevice for registration */ - sd = &s_data->subdev; - if (!sd || !tc_dev->client) { - dev_err(dev, "Invalid subdev context\n"); - return -ENODEV; - } - - if (!tc_dev->v4l2sd_ops || !tc_dev->v4l2sd_internal_ops) { - dev_err(dev, "uninitialized v4l2 subdev ops\n"); - return -EINVAL; - } - - if (!tc_dev->media_ops) { - dev_err(dev, "uninitialized media entiry ops\n"); - return -EINVAL; - } - - if (!tc_dev->tcctrl_ops) { - dev_err(dev, "uninitialized control ops\n"); - return -EINVAL; - } - - v4l2_i2c_subdev_init(sd, tc_dev->client, tc_dev->v4l2sd_ops); - - ctrl_hdl->ctrl_ops = tc_dev->tcctrl_ops; - err = tegracam_ctrl_handler_init(ctrl_hdl); - if (err) { - dev_err(dev, "Failed to init ctrls %s\n", tc_dev->name); - return err; - } - tc_dev->numctrls = ctrl_hdl->ctrl_ops->numctrls; - s_data->numctrls = tc_dev->numctrls; - sd->ctrl_handler = s_data->ctrl_handler = &ctrl_hdl->ctrl_handler; - s_data->ctrls = ctrl_hdl->ctrls; - sd->internal_ops = tc_dev->v4l2sd_internal_ops; - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | - V4L2_SUBDEV_FL_HAS_EVENTS; - -#if defined(CONFIG_MEDIA_CONTROLLER) - tc_dev->pad.flags = MEDIA_PAD_FL_SOURCE; - sd->entity.ops = tc_dev->media_ops; - err = tegra_media_entity_init(&sd->entity, - 1, &tc_dev->pad, true, is_sensor); - if (err < 0) { - dev_err(dev, "unable to init media entity\n"); - return err; - } -#endif - - err = v4l2_async_register_subdev(sd); - if (err) - return err; - - return 0; -} -EXPORT_SYMBOL_GPL(tegracam_v4l2subdev_register); - void tegracam_device_unregister(struct tegracam_device *tc_dev) { struct camera_common_data *s_data = tc_dev->s_data; @@ -190,16 +129,3 @@ void tegracam_device_unregister(struct tegracam_device *tc_dev) camera_common_cleanup(s_data); } EXPORT_SYMBOL_GPL(tegracam_device_unregister); - -void tegracam_v4l2subdev_unregister(struct tegracam_device *tc_dev) -{ - struct camera_common_data *s_data = tc_dev->s_data; - struct v4l2_subdev *sd = &s_data->subdev; - - v4l2_ctrl_handler_free(s_data->ctrl_handler); - v4l2_async_unregister_subdev(sd); -#if defined(CONFIG_MEDIA_CONTROLLER) - media_entity_cleanup(&sd->entity); -#endif -} -EXPORT_SYMBOL_GPL(tegracam_v4l2subdev_unregister); diff --git a/drivers/media/platform/tegra/camera/tegracam_ctrls.c b/drivers/media/platform/tegra/camera/tegracam_ctrls.c index d13222925..6fe79665c 100644 --- a/drivers/media/platform/tegra/camera/tegracam_ctrls.c +++ b/drivers/media/platform/tegra/camera/tegracam_ctrls.c @@ -40,6 +40,18 @@ static const u32 tegracam_def_cids[] = { TEGRA_CAMERA_CID_GROUP_HOLD, }; +/* + * For auto control, the states of the previous controls must + * be applied to get optimal quality faster. List all the controls + * which must be overriden + */ +static const u32 tegracam_override_cids[] = { + TEGRA_CAMERA_CID_GAIN, + TEGRA_CAMERA_CID_EXPOSURE, + TEGRA_CAMERA_CID_FRAME_RATE, +}; +#define NUM_OVERRIDE_CTRLS ARRAY_SIZE(tegracam_override_cids) + static struct v4l2_ctrl_config ctrl_cfg_list[] = { /* Do not change the name field for the controls! */ { @@ -230,6 +242,63 @@ static int tegracam_s_ctrl(struct v4l2_ctrl *ctrl) return err; } +int tegracam_ctrl_set_overrides(struct tegracam_ctrl_handler *hdl) +{ + struct v4l2_ext_controls ctrls; + struct v4l2_ext_control control; + struct tegracam_device *tc_dev = hdl->tc_dev; + struct device *dev = tc_dev->dev; + const struct tegracam_ctrl_ops *ops = hdl->ctrl_ops; + int err, result = 0; + int i; + + /* + * write list of override regs for the asking frame length, + * coarse integration time, and gain. Failures to write + * overrides are non-fatal + */ + memset(&ctrls, 0, sizeof(ctrls)); +#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 9, 0) + ctrls.which = V4L2_CTRL_ID2WHICH(TEGRA_CAMERA_CID_BASE); +#else + ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(TEGRA_CAMERA_CID_BASE); +#endif + ctrls.count = 1; + ctrls.controls = &control; + + for (i = 0; i < NUM_OVERRIDE_CTRLS; i++) { + control.id = tegracam_override_cids[i]; + result = v4l2_g_ext_ctrls(&hdl->ctrl_handler, &ctrls); + if (result == 0) { + switch (control.id) { + case TEGRA_CAMERA_CID_GAIN: + err = ops->set_gain(tc_dev, control.value64); + break; + case TEGRA_CAMERA_CID_EXPOSURE: + err = ops->set_exposure(tc_dev, + control.value64); + break; + case TEGRA_CAMERA_CID_FRAME_RATE: + err = ops->set_frame_rate(tc_dev, + control.value64); + break; + default: + dev_err(dev, "%s: unsupported override %x\n", + __func__, control.id); + return -EINVAL; + } + + if (err) { + dev_err(dev, "%s: error to set %d override\n", + __func__, control.id); + return err; + } + } + } + + return 0; +} + int tegracam_init_ctrl_ranges_by_mode( struct tegracam_ctrl_handler *handler, u32 modeidx) diff --git a/drivers/media/platform/tegra/camera/tegracam_v4l2.c b/drivers/media/platform/tegra/camera/tegracam_v4l2.c new file mode 100644 index 000000000..1c40746e6 --- /dev/null +++ b/drivers/media/platform/tegra/camera/tegracam_v4l2.c @@ -0,0 +1,189 @@ +/* + * tegracam_core - tegra camera framework initialization + * + * Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include +#include + +static int v4l2sd_stream(struct v4l2_subdev *sd, int enable) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct camera_common_data *s_data = to_camera_common_data(&client->dev); + struct camera_common_sensor_ops *sensor_ops = s_data->ops; + struct tegracam_device *tc_dev = to_tegracam_device(s_data); + int err; + + dev_dbg(&client->dev, "%s++ enable %d\n", __func__, enable); + + if (enable) { + err = sensor_ops->set_mode(tc_dev); + if (err) { + dev_err(&client->dev, "Error writing mode\n"); + return err; + } + + if (s_data->override_enable) { + err = tegracam_ctrl_set_overrides( + s_data->tegracam_ctrl_hdl); + if (err) { + dev_err(&client->dev, + "overrides cannot be set\n"); + return err; + } + } + + err = sensor_ops->start_streaming(tc_dev); + if (err) { + dev_err(&client->dev, "Error turning on streaming\n"); + return err; + } + } else { + err = sensor_ops->stop_streaming(tc_dev); + if (err) { + dev_err(&client->dev, "Error turning off streaming\n"); + return err; + } + } + + return 0; +} + +static int v4l2sd_g_input_status(struct v4l2_subdev *sd, u32 *status) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct camera_common_data *s_data = to_camera_common_data(&client->dev); + struct camera_common_power_rail *pw = s_data->power; + + *status = pw->state == SWITCH_ON; + return 0; +} + +static struct v4l2_subdev_video_ops v4l2sd_video_ops = { + .s_stream = v4l2sd_stream, + .g_mbus_config = camera_common_g_mbus_config, + .g_input_status = v4l2sd_g_input_status, +}; + +static struct v4l2_subdev_core_ops v4l2sd_core_ops = { + .s_power = camera_common_s_power, +}; + +static int v4l2sd_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + return camera_common_g_fmt(sd, &format->format); +} + +static int v4l2sd_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + int ret; + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + ret = camera_common_try_fmt(sd, &format->format); + else + ret = camera_common_s_fmt(sd, &format->format); + + /* TODO: Add set mode for blob collection */ + + return ret; +} + +static struct v4l2_subdev_pad_ops v4l2sd_pad_ops = { + .set_fmt = v4l2sd_set_fmt, + .get_fmt = v4l2sd_get_fmt, + .enum_mbus_code = camera_common_enum_mbus_code, + .enum_frame_size = camera_common_enum_framesizes, + .enum_frame_interval = camera_common_enum_frameintervals, +}; + +static struct v4l2_subdev_ops v4l2sd_ops = { + .core = &v4l2sd_core_ops, + .video = &v4l2sd_video_ops, + .pad = &v4l2sd_pad_ops, +}; + +static const struct media_entity_operations media_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +int tegracam_v4l2subdev_register(struct tegracam_device *tc_dev, + bool is_sensor) +{ + struct camera_common_data *s_data = tc_dev->s_data; + struct tegracam_ctrl_handler *ctrl_hdl = s_data->tegracam_ctrl_hdl; + struct v4l2_subdev *sd = NULL; + struct device *dev = tc_dev->dev; + int err = 0; + + /* init v4l2 subdevice for registration */ + sd = &s_data->subdev; + if (!sd || !tc_dev->client) { + dev_err(dev, "Invalid subdev context\n"); + return -ENODEV; + } + + if (!tc_dev->tcctrl_ops) { + dev_err(dev, "uninitialized control ops\n"); + return -EINVAL; + } + + v4l2_i2c_subdev_init(sd, tc_dev->client, &v4l2sd_ops); + + ctrl_hdl->ctrl_ops = tc_dev->tcctrl_ops; + err = tegracam_ctrl_handler_init(ctrl_hdl); + if (err) { + dev_err(dev, "Failed to init ctrls %s\n", tc_dev->name); + return err; + } + tc_dev->numctrls = ctrl_hdl->ctrl_ops->numctrls; + s_data->numctrls = tc_dev->numctrls; + sd->ctrl_handler = s_data->ctrl_handler = &ctrl_hdl->ctrl_handler; + s_data->ctrls = ctrl_hdl->ctrls; + sd->internal_ops = tc_dev->v4l2sd_internal_ops; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_HAS_EVENTS; + +#if defined(CONFIG_MEDIA_CONTROLLER) + tc_dev->pad.flags = MEDIA_PAD_FL_SOURCE; + sd->entity.ops = &media_ops; + err = tegra_media_entity_init(&sd->entity, + 1, &tc_dev->pad, true, is_sensor); + if (err < 0) { + dev_err(dev, "unable to init media entity\n"); + return err; + } +#endif + + return v4l2_async_register_subdev(sd); +} +EXPORT_SYMBOL_GPL(tegracam_v4l2subdev_register); + +void tegracam_v4l2subdev_unregister(struct tegracam_device *tc_dev) +{ + struct camera_common_data *s_data = tc_dev->s_data; + struct v4l2_subdev *sd = &s_data->subdev; + + v4l2_ctrl_handler_free(s_data->ctrl_handler); + v4l2_async_unregister_subdev(sd); +#if defined(CONFIG_MEDIA_CONTROLLER) + media_entity_cleanup(&sd->entity); +#endif +} +EXPORT_SYMBOL_GPL(tegracam_v4l2subdev_unregister); diff --git a/include/media/camera_common.h b/include/media/camera_common.h index cad44c220..ec1503e7b 100644 --- a/include/media/camera_common.h +++ b/include/media/camera_common.h @@ -173,6 +173,9 @@ struct camera_common_sensor_ops { int (*power_put)(struct tegracam_device *tc_dev); int (*get_framesync)(struct camera_common_data *s_data, struct camera_common_framesync *vshs); + int (*set_mode)(struct tegracam_device *tc_dev); + int (*start_streaming)(struct tegracam_device *tc_dev); + int (*stop_streaming)(struct tegracam_device *tc_dev); }; @@ -336,6 +339,7 @@ const struct camera_common_colorfmt *camera_common_find_pixelfmt( unsigned int pix_fmt); /* common control layer init */ +int tegracam_ctrl_set_overrides(struct tegracam_ctrl_handler *handler); int tegracam_ctrl_handler_init(struct tegracam_ctrl_handler *handler); int tegracam_init_ctrl_ranges_by_mode( struct tegracam_ctrl_handler *handler, diff --git a/include/media/tegracam_core.h b/include/media/tegracam_core.h index 3ad2869e7..5725cb437 100644 --- a/include/media/tegracam_core.h +++ b/include/media/tegracam_core.h @@ -1,7 +1,7 @@ /** * tegracam_core.h - tegra camera framework core utilities * - * Copyright (c) 2017, NVIDIA Corporation. All rights reserved. + * Copyright (c) 2017-2018, NVIDIA Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -39,6 +39,8 @@ struct tegracam_device { void *priv; }; +struct tegracam_device *to_tegracam_device(struct camera_common_data *data); + void tegracam_set_privdata(struct tegracam_device *tc_dev, void *priv); void *tegracam_get_privdata(struct tegracam_device *tc_dev); -- cgit v1.2.2