linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Bing Bu Cao <bingbu.cao@linux.intel.com>
To: jacopo mondi <jacopo@jmondi.org>, bingbu.cao@intel.com
Cc: linux-media@vger.kernel.org, sakari.ailus@linux.intel.com,
	tian.shu.qiu@linux.intel.com, rajmohan.mani@intel.com,
	mchehab@kernel.org
Subject: Re: [PATCH v3] media: imx319: Add imx319 camera sensor driver
Date: Wed, 23 May 2018 15:19:24 +0800	[thread overview]
Message-ID: <a933b516-1ea5-9fd9-4da8-ff5f85a68672@linux.intel.com> (raw)
In-Reply-To: <20180522200848.GB15035@w540>



On 2018年05月23日 04:08, jacopo mondi wrote:
> Hello Bingbu,
>     thanks for the patch
>
> On Tue, May 22, 2018 at 12:33:01PM +0800, bingbu.cao@intel.com wrote:
>> From: Bingbu Cao <bingbu.cao@intel.com>
>>
>> Add a V4L2 sub-device driver for the Sony IMX319 image sensor.
>> This is a camera sensor using the I2C bus for control and the
>> CSI-2 bus for data.
> Could you please provide a changelog between versions? Also, I know
> using the --in-reply-to option is tempting to keep all patch version
> in a single thread, but most people finds it confusing and I rarely
> see that.
Thanks, I will send the standalone v4 patch with change log .
>
>> Signed-off-by: Bingbu Cao <bingbu.cao@intel.com>
>> Signed-off-by: Tianshu Qiu <tian.shu.qiu@intel.com>
>> ---
>>   MAINTAINERS                |    7 +
>>   drivers/media/i2c/Kconfig  |   11 +
>>   drivers/media/i2c/Makefile |    1 +
>>   drivers/media/i2c/imx319.c | 2434 ++++++++++++++++++++++++++++++++++++++++++++
>>   4 files changed, 2453 insertions(+)
>>   create mode 100644 drivers/media/i2c/imx319.c
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index e73a55a6a855..87b6c338d827 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -13084,6 +13084,13 @@ S:	Maintained
>>   F:	drivers/media/i2c/imx274.c
>>   F:	Documentation/devicetree/bindings/media/i2c/imx274.txt
>>
>> +SONY IMX319 SENSOR DRIVER
>> +M:	Bingbu Cao <bingbu.cao@intel.com>
>> +L:	linux-media@vger.kernel.org
>> +T:	git git://linuxtv.org/media_tree.git
>> +S:	Maintained
>> +F:	drivers/media/i2c/imx319.c
>> +
>>   SONY MEMORYSTICK CARD SUPPORT
>>   M:	Alex Dubov <oakad@yahoo.com>
>>   W:	http://tifmxx.berlios.de/
>> diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
>> index 1f9d7c6aa31a..c3d279cc293e 100644
>> --- a/drivers/media/i2c/Kconfig
>> +++ b/drivers/media/i2c/Kconfig
>> @@ -604,6 +604,17 @@ config VIDEO_IMX274
>>   	  This is a V4L2 sensor-level driver for the Sony IMX274
>>   	  CMOS image sensor.
>>
>> +config VIDEO_IMX319
>> +	tristate "Sony IMX319 sensor support"
>> +	depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
>> +	depends on MEDIA_CAMERA_SUPPORT
>> +	help
>> +	  This is a Video4Linux2 sensor driver for the Sony
>> +	  IMX319 camera.
>> +
>> +	  To compile this driver as a module, choose M here: the
>> +	  module will be called imx319.
>> +
>>   config VIDEO_OV2640
>>   	tristate "OmniVision OV2640 sensor support"
>>   	depends on VIDEO_V4L2 && I2C
>> diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
>> index 16fc34eda5cc..3adb3be4a486 100644
>> --- a/drivers/media/i2c/Makefile
>> +++ b/drivers/media/i2c/Makefile
>> @@ -104,5 +104,6 @@ obj-$(CONFIG_VIDEO_OV2659)	+= ov2659.o
>>   obj-$(CONFIG_VIDEO_TC358743)	+= tc358743.o
>>   obj-$(CONFIG_VIDEO_IMX258)	+= imx258.o
>>   obj-$(CONFIG_VIDEO_IMX274)	+= imx274.o
>> +obj-$(CONFIG_VIDEO_IMX319)	+= imx319.o
>>
>>   obj-$(CONFIG_SDR_MAX2175) += max2175.o
> This hunk does not apply nor on media tree master nor on Linus'
> master. Could you please mention on which branch the patch is meant to
> be applied in the cover letter? Maybe it's obvious for most people here,
> but I failed to find it.
It is based on sakari media_tree branch.
<URL:https://git.linuxtv.org/sailus/media_tree.git/log/?h=for-4.18-3.1>
I will rebase that in follow patches.
>
>> diff --git a/drivers/media/i2c/imx319.c b/drivers/media/i2c/imx319.c
>> new file mode 100644
>> index 000000000000..706bbafc75ec
>> --- /dev/null
>> +++ b/drivers/media/i2c/imx319.c
>> @@ -0,0 +1,2434 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +// Copyright (C) 2018 Intel Corporation
>> +
>> +#include <asm/unaligned.h>
>> +#include <linux/acpi.h>
>> +#include <linux/i2c.h>
>> +#include <linux/module.h>
>> +#include <linux/pm_runtime.h>
>> +#include <media/v4l2-ctrls.h>
>> +#include <media/v4l2-device.h>
>> +
>> +#define IMX319_REG_MODE_SELECT		0x0100
>> +#define IMX319_MODE_STANDBY		0x00
>> +#define IMX319_MODE_STREAMING		0x01
>> +
>> +/* Chip ID */
>> +#define IMX319_REG_CHIP_ID		0x0016
>> +#define IMX319_CHIP_ID			0x0319
>> +
>> +/* V_TIMING internal */
>> +#define IMX319_REG_FLL			0x0340
>> +#define IMX319_FLL_MAX			0xffff
>> +
>> +/* Exposure control */
>> +#define IMX319_REG_EXPOSURE		0x0202
>> +#define IMX319_EXPOSURE_MIN		1
>> +#define IMX319_EXPOSURE_STEP		1
>> +#define IMX319_EXPOSURE_DEFAULT		0x04ee
>> +
>> +/* Analog gain control */
>> +#define IMX319_REG_ANALOG_GAIN		0x0204
>> +#define IMX319_ANA_GAIN_MIN		0
>> +#define IMX319_ANA_GAIN_MAX		960
>> +#define IMX319_ANA_GAIN_STEP		1
>> +#define IMX319_ANA_GAIN_DEFAULT		0
>> +
>> +/* Digital gain control */
>> +#define IMX319_REG_DPGA_USE_GLOBAL_GAIN	0x3ff9
>> +#define IMX319_REG_DIG_GAIN_GLOBAL	0x020e
>> +#define IMX319_DGTL_GAIN_MIN		256
>> +#define IMX319_DGTL_GAIN_MAX		4095
>> +#define IMX319_DGTL_GAIN_STEP		1
>> +#define IMX319_DGTL_GAIN_DEFAULT	256
>> +
>> +/* Test Pattern Control */
>> +#define IMX319_REG_TEST_PATTERN		0x0600
>> +#define IMX319_TEST_PATTERN_DISABLED		0
>> +#define IMX319_TEST_PATTERN_SOLID_COLOR		1
>> +#define IMX319_TEST_PATTERN_COLOR_BARS		2
>> +#define IMX319_TEST_PATTERN_GRAY_COLOR_BARS	3
>> +#define IMX319_TEST_PATTERN_PN9			4
>> +
>> +/* Flip Control */
>> +#define IMX319_REG_ORIENTATION		0x0101
>> +
>> +struct imx319_reg {
>> +	u16 address;
>> +	u8 val;
>> +};
>> +
>> +struct imx319_reg_list {
>> +	u32 num_of_regs;
>> +	const struct imx319_reg *regs;
>> +};
>> +
>> +/* Mode : resolution and related config&values */
>> +struct imx319_mode {
>> +	/* Frame width */
>> +	u32 width;
>> +	/* Frame height */
>> +	u32 height;
>> +
>> +	/* V-timing */
>> +	u32 fll_def;
>> +	u32 fll_min;
>> +
>> +	/* H-timing */
>> +	u32 llp;
>> +
>> +	/* Default register values */
>> +	struct imx319_reg_list reg_list;
>> +};
>> +
>> +struct imx319 {
>> +	struct v4l2_subdev sd;
>> +	struct media_pad pad;
>> +
>> +	struct v4l2_ctrl_handler ctrl_handler;
>> +	/* V4L2 Controls */
>> +	struct v4l2_ctrl *link_freq;
>> +	struct v4l2_ctrl *pixel_rate;
>> +	struct v4l2_ctrl *vblank;
>> +	struct v4l2_ctrl *hblank;
>> +	struct v4l2_ctrl *exposure;
>> +	struct v4l2_ctrl *vflip;
>> +	struct v4l2_ctrl *hflip;
>> +
>> +	/* Current mode */
>> +	const struct imx319_mode *cur_mode;
>> +
>> +	/*
>> +	 * Mutex for serialized access:
>> +	 * Protect sensor set pad format and start/stop streaming safely.
>> +	 * Protect access to sensor v4l2 controls.
>> +	 */
>> +	struct mutex mutex;
>> +
>> +	/* Streaming on/off */
>> +	bool streaming;
>> +};
>> +
> [snip] Long tables of registers
>
>> +/* Configurations for supported link frequencies */
>> +/* Menu items for LINK_FREQ V4L2 control */
>> +static const s64 link_freq_menu_items[] = {
>> +	360000000,
>> +};
>> +
>> +/* Mode configs */
> [snip] Long list of modes
Sorry, is this '[snip]' line a comment or just make message clean? ;)
>
>> +
>> +static inline struct imx319 *to_imx319(struct v4l2_subdev *_sd)
>> +{
>> +	return container_of(_sd, struct imx319, sd);
>> +}
>> +
>> +/* Get bayer order based on flip setting. */
>> +static __u32 imx319_get_format_code(struct imx319 *imx319)
>> +{
>> +	/*
>> +	 * Only one bayer order is supported.
>> +	 * It depends on the flip settings.
>> +	 */
>> +	static const __u32 codes[2][2] = {
>> +		{ MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, },
>> +		{ MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, },
>> +	};
>> +
>> +	return codes[imx319->vflip->val][imx319->hflip->val];
>> +}
> I don't have any major comment actually, this is pretty good for a
> first submission.
>
> This worries me a bit though. The media bus format depends on the
> V/HFLIP value, I assume this is an hardware limitation.But if
> changing the flip changes the reported media bus format, you could
> trigger a -EPIPE error during pipeline format validation between two
> streaming sessions with different flip settings. Isn't this a bit
> dangerous?
Yes, it is a hardware limitation. Make the sensor support different
bayer order by changing the flip.

Thanks for your point, I will have a deep look for this.
>
> Below some minor comments.
>
>> +
>> +/* Read registers up to 4 at a time */
>> +static int imx319_read_reg(struct imx319 *imx319, u16 reg, u32 len, u32 *val)
>> +{
>> +	struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd);
>> +	struct i2c_msg msgs[2];
>> +	u8 addr_buf[2];
>> +	u8 data_buf[4] = { 0 };
>> +	int ret;
>> +
>> +	if (len > 4)
>> +		return -EINVAL;
>> +
>> +	put_unaligned_be16(reg, addr_buf);
>> +	/* Write register address */
>> +	msgs[0].addr = client->addr;
>> +	msgs[0].flags = 0;
>> +	msgs[0].len = ARRAY_SIZE(addr_buf);
>> +	msgs[0].buf = addr_buf;
>> +
>> +	/* Read data from register */
>> +	msgs[1].addr = client->addr;
>> +	msgs[1].flags = I2C_M_RD;
>> +	msgs[1].len = len;
>> +	msgs[1].buf = &data_buf[4 - len];
>> +
>> +	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
>> +	if (ret != ARRAY_SIZE(msgs))
>> +		return -EIO;
>> +
>> +	*val = get_unaligned_be32(data_buf);
>> +
>> +	return 0;
>> +}
>> +
>> +/* Write registers up to 4 at a time */
>> +static int imx319_write_reg(struct imx319 *imx319, u16 reg, u32 len, u32 val)
>> +{
>> +	struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd);
>> +	u8 buf[6];
>> +
>> +	if (len > 4)
>> +		return -EINVAL;
>> +
>> +	put_unaligned_be16(reg, buf);
>> +	put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
>> +	if (i2c_master_send(client, buf, len + 2) != len + 2)
>> +		return -EIO;
>> +
>> +	return 0;
>> +}
>> +
>> +/* Write a list of registers */
>> +static int imx319_write_regs(struct imx319 *imx319,
>> +			      const struct imx319_reg *regs, u32 len)
>> +{
>> +	struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd);
>> +	int ret;
>> +	u32 i;
>> +
>> +	for (i = 0; i < len; i++) {
>> +		ret = imx319_write_reg(imx319, regs[i].address, 1,
>> +					regs[i].val);
> Unaligned to open parenthesis
Ack.
>
>> +		if (ret) {
>> +			dev_err_ratelimited(
>> +				&client->dev,
>> +				"Failed to write reg 0x%4.4x. error = %d\n",
>> +				regs[i].address, ret);
> No need to break line, align to open parenthesis, please.
Ack.
>
>> +
>> +			return ret;
>> +		}
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +/* Open sub-device */
>> +static int imx319_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
>> +{
>> +	struct imx319 *imx319 = to_imx319(sd);
>> +	struct v4l2_mbus_framefmt *try_fmt =
>> +		v4l2_subdev_get_try_format(sd, fh->pad, 0);
>> +
>> +	mutex_lock(&imx319->mutex);
>> +
>> +	/* Initialize try_fmt */
>> +	try_fmt->width = imx319->cur_mode->width;
>> +	try_fmt->height = imx319->cur_mode->height;
>> +	try_fmt->code = imx319_get_format_code(imx319);
>> +	try_fmt->field = V4L2_FIELD_NONE;
>> +
>> +	mutex_unlock(&imx319->mutex);
>> +
>> +	return 0;
>> +}
>> +
>> +static int imx319_update_digital_gain(struct imx319 *imx319, u32 d_gain)
>> +{
>> +	int ret;
>> +
>> +	ret = imx319_write_reg(imx319, IMX319_REG_DPGA_USE_GLOBAL_GAIN, 1, 1);
>> +	if (ret)
>> +		return ret;
>> +
>> +	/* Digital gain = (d_gain & 0xFF00) + (d_gain & 0xFF)/256 times */
>> +	return imx319_write_reg(imx319, IMX319_REG_DIG_GAIN_GLOBAL, 2, d_gain);
>> +}
>> +
>> +static int imx319_set_ctrl(struct v4l2_ctrl *ctrl)
>> +{
>> +	struct imx319 *imx319 = container_of(ctrl->handler,
>> +					     struct imx319, ctrl_handler);
>> +	struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd);
>> +	s64 max;
>> +	int ret;
>> +
>> +	/* Propagate change of current control to all related controls */
>> +	switch (ctrl->id) {
>> +	case V4L2_CID_VBLANK:
>> +		/* Update max exposure while meeting expected vblanking */
>> +		max = imx319->cur_mode->height + ctrl->val - 18;
>> +		__v4l2_ctrl_modify_range(imx319->exposure,
>> +					 imx319->exposure->minimum,
>> +					 max, imx319->exposure->step, max);
>> +		break;
>> +	}
>> +
>> +	/*
>> +	 * Applying V4L2 control value only happens
>> +	 * when power is up for streaming
>> +	 */
>> +	if (pm_runtime_get_if_in_use(&client->dev) == 0)
>> +		return 0;
> I assume powering is handled through ACPI somehow, I know nothing
> about that, but I wonder why setting controls should be enabled only
> when streaming. I would have expected runtime_pm_get/put in subdevices
> node open/close functions not only when streaming. Am I missing something?
>
IMO, the device is turned on by i2c-core with binding pm domain, the 
logic is runtime power up the subdev
iff enable streaming, thus the v4l2 control only apply and take effect 
when the subdev is power-on.
>> +
>> +	switch (ctrl->id) {
>> +	case V4L2_CID_ANALOGUE_GAIN:
>> +		/* Analog gain = 1024/(1024 - ctrl->val) times */
>> +		ret = imx319_write_reg(imx319, IMX319_REG_ANALOG_GAIN,
>> +				       2, ctrl->val);
>> +		break;
>> +	case V4L2_CID_DIGITAL_GAIN:
>> +		ret = imx319_update_digital_gain(imx319, ctrl->val);
>> +		break;
>> +	case V4L2_CID_EXPOSURE:
>> +		ret = imx319_write_reg(imx319, IMX319_REG_EXPOSURE,
>> +				       2, ctrl->val);
>> +		break;
>> +	case V4L2_CID_VBLANK:
>> +		/* Update FLL that meets expected vertical blanking */
>> +		ret = imx319_write_reg(imx319, IMX319_REG_FLL, 2,
>> +				       imx319->cur_mode->height + ctrl->val);
>> +		break;
>> +	case V4L2_CID_TEST_PATTERN:
>> +		ret = imx319_write_reg(imx319, IMX319_REG_TEST_PATTERN,
>> +				       2, imx319_test_pattern_val[ctrl->val]);
>> +		break;
>> +	case V4L2_CID_HFLIP:
>> +	case V4L2_CID_VFLIP:
>> +		ret = imx319_write_reg(imx319, IMX319_REG_ORIENTATION, 1,
>> +				       imx319->hflip->val |
>> +				       imx319->vflip->val << 1);
>> +		break;
>> +	default:
>> +		ret = -EINVAL;
>> +		dev_info(&client->dev,
>> +			 "ctrl(id:0x%x,val:0x%x) is not handled\n",
>> +			 ctrl->id, ctrl->val);
>> +		break;
>> +	}
>> +
>> +	pm_runtime_put(&client->dev);
>> +
>> +	return ret;
>> +}
>> +
>> +static const struct v4l2_ctrl_ops imx319_ctrl_ops = {
>> +	.s_ctrl = imx319_set_ctrl,
>> +};
>> +
>> +static int imx319_enum_mbus_code(struct v4l2_subdev *sd,
>> +				  struct v4l2_subdev_pad_config *cfg,
>> +				  struct v4l2_subdev_mbus_code_enum *code)
>> +{
>> +	struct imx319 *imx319 = to_imx319(sd);
>> +
>> +	if (code->index > 0)
>> +		return -EINVAL;
>> +
>> +	code->code = imx319_get_format_code(imx319);
>> +
>> +	return 0;
>> +}
>> +
>> +static int imx319_enum_frame_size(struct v4l2_subdev *sd,
>> +				   struct v4l2_subdev_pad_config *cfg,
>> +				   struct v4l2_subdev_frame_size_enum *fse)
>> +{
>> +	struct imx319 *imx319 = to_imx319(sd);
>> +
>> +	if (fse->index >= ARRAY_SIZE(supported_modes))
>> +		return -EINVAL;
>> +
>> +	if (fse->code != imx319_get_format_code(imx319))
>> +		return -EINVAL;
>> +
>> +	fse->min_width = supported_modes[fse->index].width;
>> +	fse->max_width = fse->min_width;
>> +	fse->min_height = supported_modes[fse->index].height;
>> +	fse->max_height = fse->min_height;
>> +
>> +	return 0;
>> +}
>> +
>> +static void imx319_update_pad_format(struct imx319 *imx319,
>> +				     const struct imx319_mode *mode,
>> +				     struct v4l2_subdev_format *fmt)
>> +{
>> +	fmt->format.width = mode->width;
>> +	fmt->format.height = mode->height;
>> +	fmt->format.code = imx319_get_format_code(imx319);
>> +	fmt->format.field = V4L2_FIELD_NONE;
>> +}
>> +
>> +static int imx319_do_get_pad_format(struct imx319 *imx319,
>> +				     struct v4l2_subdev_pad_config *cfg,
>> +				     struct v4l2_subdev_format *fmt)
>> +{
>> +	struct v4l2_mbus_framefmt *framefmt;
>> +	struct v4l2_subdev *sd = &imx319->sd;
>> +
>> +	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
>> +		framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
>> +		fmt->format = *framefmt;
>> +	} else {
>> +		imx319_update_pad_format(imx319, imx319->cur_mode, fmt);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int imx319_get_pad_format(struct v4l2_subdev *sd,
>> +				  struct v4l2_subdev_pad_config *cfg,
>> +				  struct v4l2_subdev_format *fmt)
>> +{
>> +	struct imx319 *imx319 = to_imx319(sd);
>> +	int ret;
>> +
>> +	mutex_lock(&imx319->mutex);
>> +	ret = imx319_do_get_pad_format(imx319, cfg, fmt);
>> +	mutex_unlock(&imx319->mutex);
>> +
>> +	return ret;
>> +}
>> +
>> +static int
>> +imx319_set_pad_format(struct v4l2_subdev *sd,
>> +		       struct v4l2_subdev_pad_config *cfg,
>> +		       struct v4l2_subdev_format *fmt)
>> +{
>> +	struct imx319 *imx319 = to_imx319(sd);
>> +	const struct imx319_mode *mode;
>> +	struct v4l2_mbus_framefmt *framefmt;
>> +	s32 vblank_def;
>> +	s32 vblank_min;
>> +	s64 h_blank;
>> +	s64 pixel_rate;
>> +
>> +	mutex_lock(&imx319->mutex);
>> +
>> +	/*
>> +	 * Only one bayer order is supported.
>> +	 * It depends on the flip settings.
>> +	 */
>> +	fmt->format.code = imx319_get_format_code(imx319);
>> +
>> +	mode = v4l2_find_nearest_size(supported_modes,
>> +		ARRAY_SIZE(supported_modes), width, height,
>> +		fmt->format.width, fmt->format.height);
>> +	imx319_update_pad_format(imx319, mode, fmt);
>> +	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
>> +		framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
>> +		*framefmt = fmt->format;
>> +	} else {
>> +		imx319->cur_mode = mode;
>> +		pixel_rate =
>> +		(link_freq_menu_items[0] * 2 * 4) / 10;
> This assumes a fixed link frequency and a fixed number of data lanes,
> and a fixed bpp value (but this is ok, as all the formats you have are
> 10bpp). In OF world those parameters come from DT, what about ACPI?
I have no clear details for this, but I think these parameters are from 
fwnode acpi graph parse.
>
> (also, no need to break line here)
>
>> +		__v4l2_ctrl_s_ctrl_int64(imx319->pixel_rate, pixel_rate);
>> +		/* Update limits and set FPS to default */
>> +		vblank_def = imx319->cur_mode->fll_def -
>> +			     imx319->cur_mode->height;
>> +		vblank_min = imx319->cur_mode->fll_min -
>> +			     imx319->cur_mode->height;
>> +		__v4l2_ctrl_modify_range(
>> +			imx319->vblank, vblank_min,
>> +			IMX319_FLL_MAX - imx319->cur_mode->height, 1,
>> +			vblank_def);
> No need to line break, align to open parenthesis please, here and in
> other places below here.
Ack.
>
>> +		__v4l2_ctrl_s_ctrl(imx319->vblank, vblank_def);
>> +		h_blank = mode->llp - imx319->cur_mode->width;
>> +		/*
>> +		 * Currently hblank is not changeable.
>> +		 * So FPS control is done only by vblank.
>> +		 */
>> +		__v4l2_ctrl_modify_range(imx319->hblank, h_blank,
>> +					 h_blank, 1, h_blank);
>> +	}
>> +
>> +	mutex_unlock(&imx319->mutex);
>> +
>> +	return 0;
>> +}
>> +
>> +/* Start streaming */
>> +static int imx319_start_streaming(struct imx319 *imx319)
>> +{
>> +	struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd);
>> +	const struct imx319_reg_list *reg_list;
>> +	int ret;
>> +
>> +	/* Global Setting */
>> +	reg_list = &imx319_global_setting;
>> +	ret = imx319_write_regs(imx319, reg_list->regs, reg_list->num_of_regs);
>> +	if (ret) {
>> +		dev_err(&client->dev, "%s failed to set global settings\n",
>> +			__func__);
>> +		return ret;
>> +	}
>> +
>> +	/* Apply default values of current mode */
>> +	reg_list = &imx319->cur_mode->reg_list;
>> +	ret = imx319_write_regs(imx319, reg_list->regs, reg_list->num_of_regs);
>> +	if (ret) {
>> +		dev_err(&client->dev, "%s failed to set mode\n", __func__);
>> +		return ret;
>> +	}
>> +
>> +	/* Apply customized values from user */
>> +	ret =  __v4l2_ctrl_handler_setup(imx319->sd.ctrl_handler);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return imx319_write_reg(imx319, IMX319_REG_MODE_SELECT,
>> +				1, IMX319_MODE_STREAMING);
>> +}
>> +
>> +/* Stop streaming */
>> +static int imx319_stop_streaming(struct imx319 *imx319)
>> +{
>> +	return imx319_write_reg(imx319, IMX319_REG_MODE_SELECT,
>> +				1, IMX319_MODE_STANDBY);
>> +}
>> +
>> +static int imx319_set_stream(struct v4l2_subdev *sd, int enable)
>> +{
>> +	struct imx319 *imx319 = to_imx319(sd);
>> +	struct i2c_client *client = v4l2_get_subdevdata(sd);
>> +	int ret = 0;
>> +
>> +	mutex_lock(&imx319->mutex);
>> +	if (imx319->streaming == enable) {
>> +		mutex_unlock(&imx319->mutex);
>> +		return 0;
>> +	}
>> +
>> +	if (enable) {
>> +		ret = pm_runtime_get_sync(&client->dev);
>> +		if (ret < 0) {
>> +			pm_runtime_put_noidle(&client->dev);
>> +			goto err_unlock;
>> +		}
>> +
>> +		/*
>> +		 * Apply default & customized values
>> +		 * and then start streaming.
>> +		 */
>> +		ret = imx319_start_streaming(imx319);
>> +		if (ret)
>> +			goto err_rpm_put;
>> +	} else {
>> +		imx319_stop_streaming(imx319);
>> +		pm_runtime_put(&client->dev);
>> +	}
>> +
>> +	imx319->streaming = enable;
>> +	mutex_unlock(&imx319->mutex);
>> +
>> +	return ret;
>> +
>> +err_rpm_put:
>> +	pm_runtime_put(&client->dev);
>> +err_unlock:
>> +	mutex_unlock(&imx319->mutex);
>> +
>> +	return ret;
>> +}
>> +
>> +static int __maybe_unused imx319_suspend(struct device *dev)
>> +{
>> +	struct i2c_client *client = to_i2c_client(dev);
>> +	struct v4l2_subdev *sd = i2c_get_clientdata(client);
>> +	struct imx319 *imx319 = to_imx319(sd);
>> +
>> +	if (imx319->streaming)
>> +		imx319_stop_streaming(imx319);
>> +
>> +	return 0;
>> +}
>> +
>> +static int __maybe_unused imx319_resume(struct device *dev)
>> +{
>> +	struct i2c_client *client = to_i2c_client(dev);
>> +	struct v4l2_subdev *sd = i2c_get_clientdata(client);
>> +	struct imx319 *imx319 = to_imx319(sd);
>> +	int ret;
>> +
>> +	if (imx319->streaming) {
>> +		ret = imx319_start_streaming(imx319);
>> +		if (ret)
>> +			goto error;
>> +	}
>> +
>> +	return 0;
>> +
>> +error:
>> +	imx319_stop_streaming(imx319);
>> +	imx319->streaming = 0;
>> +	return ret;
>> +}
>> +
>> +/* Verify chip ID */
>> +static int imx319_identify_module(struct imx319 *imx319)
>> +{
>> +	struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd);
>> +	int ret;
>> +	u32 val;
>> +
>> +	ret = imx319_read_reg(imx319, IMX319_REG_CHIP_ID, 2, &val);
>> +	if (ret)
>> +		return ret;
>> +
>> +	if (val != IMX319_CHIP_ID) {
>> +		dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
>> +			IMX319_CHIP_ID, val);
>> +		return -EIO;
>> +	}
>> +	return 0;
>> +}
>> +
>> +static const struct v4l2_subdev_video_ops imx319_video_ops = {
>> +	.s_stream = imx319_set_stream,
>> +};
>> +
>> +static const struct v4l2_subdev_pad_ops imx319_pad_ops = {
>> +	.enum_mbus_code = imx319_enum_mbus_code,
>> +	.get_fmt = imx319_get_pad_format,
>> +	.set_fmt = imx319_set_pad_format,
>> +	.enum_frame_size = imx319_enum_frame_size,
>> +};
>> +
>> +static const struct v4l2_subdev_ops imx319_subdev_ops = {
>> +	.video = &imx319_video_ops,
>> +	.pad = &imx319_pad_ops,
>> +};
>> +
>> +static const struct media_entity_operations imx319_subdev_entity_ops = {
>> +	.link_validate = v4l2_subdev_link_validate,
>> +};
>> +
>> +static const struct v4l2_subdev_internal_ops imx319_internal_ops = {
>> +	.open = imx319_open,
>> +};
>> +
>> +/* Initialize control handlers */
>> +static int imx319_init_controls(struct imx319 *imx319)
>> +{
>> +	struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd);
>> +	struct v4l2_ctrl_handler *ctrl_hdlr;
>> +	s64 exposure_max;
>> +	s64 vblank_def;
>> +	s64 vblank_min;
>> +	s64 hblank;
>> +	s64 pixel_rate;
>> +	const struct imx319_mode *mode;
>> +	int ret;
>> +
>> +	ctrl_hdlr = &imx319->ctrl_handler;
>> +	ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ctrl_hdlr->lock = &imx319->mutex;
>> +	imx319->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr,
>> +				&imx319_ctrl_ops,
>> +				V4L2_CID_LINK_FREQ,
>> +				0,
>> +				0,
>> +				link_freq_menu_items);
> In this function seems like you lost alignment and are breaking lines
> when not necessary. Could you please have a look?
Ack.
>
> Seems like apart a few questions, I only have minor comments then...
Thank you for your review.
>
> Thanks
>     j
>

  reply	other threads:[~2018-05-23  7:16 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-05-17  4:02 [PATCH] media: imx319: Add imx319 camera sensor driver bingbu.cao
2018-05-19 16:53 ` kbuild test robot
2018-05-19 16:53 ` [RFC PATCH] media: imx319: imx319_global_setting can be static kbuild test robot
2018-05-21  7:10 ` [PATCH v2 1/3] media: dw9807: Add dw9807 vcm driver bingbu.cao
2018-05-21  7:10   ` [PATCH v2 2/3] media: imx258: Add imx258 camera sensor driver bingbu.cao
2018-05-21  7:11     ` Bing Bu Cao
2018-05-21  7:11   ` [PATCH v2 1/3] media: dw9807: Add dw9807 vcm driver Bing Bu Cao
2018-05-21  7:10 ` [PATCH v2] media: imx319: Add imx319 camera sensor driver bingbu.cao
2018-05-21 21:27   ` kbuild test robot
2018-05-21 21:27   ` [PATCH] media: imx319: fix semicolon.cocci warnings kbuild test robot
2018-05-22  4:33   ` [PATCH v3] media: imx319: Add imx319 camera sensor driver bingbu.cao
2018-05-22 20:08     ` jacopo mondi
2018-05-23  7:19       ` Bing Bu Cao [this message]
2018-05-23  7:38       ` Sakari Ailus
2018-05-24 20:07         ` jacopo mondi
2018-05-24 20:47           ` Sakari Ailus
2018-05-25  6:18             ` Tomasz Figa
2018-05-25  7:12               ` jacopo mondi
2018-05-25  7:31                 ` Tomasz Figa
2018-05-25 10:56                   ` jacopo mondi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=a933b516-1ea5-9fd9-4da8-ff5f85a68672@linux.intel.com \
    --to=bingbu.cao@linux.intel.com \
    --cc=bingbu.cao@intel.com \
    --cc=jacopo@jmondi.org \
    --cc=linux-media@vger.kernel.org \
    --cc=mchehab@kernel.org \
    --cc=rajmohan.mani@intel.com \
    --cc=sakari.ailus@linux.intel.com \
    --cc=tian.shu.qiu@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).