Re: [PATCH v6 2/2] media: Add a driver for the ov5645 camera sensor.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

Adding Mark Brown in --to list.

My reply on comments below.
The question on regulator bulk API to Mark Brown still holds.


On 10/19/2016 11:44 AM, Laurent Pinchart wrote:
> Hi Todor,
> 
> (CC'ing Mark Brown for a question on regulators)
> 
> On Friday 14 Oct 2016 14:57:01 Todor Tomov wrote:
>> Hi Laurent,
>>
>> Thank you for the time spent to do this thorough review of the patch!
>>
>> Below I have removed some of the comments where I agree and I'll fix.
>> I have left the places where I have something relevant to say or ask.
>>
>> On 09/08/2016 03:22 PM, Laurent Pinchart wrote:
>>> On Thursday 08 Sep 2016 12:13:55 Todor Tomov wrote:
>>>> The ov5645 sensor from Omnivision supports up to 2592x1944
>>>> and CSI2 interface.
>>>>
>>>> The driver adds support for the following modes:
>>>> - 1280x960
>>>> - 1920x1080
>>>> - 2592x1944
>>>>
>>>> Output format is packed 8bit UYVY.
>>>>
>>>> Signed-off-by: Todor Tomov <todor.tomov@xxxxxxxxxx>
>>>> ---
>>>>
>>>>  drivers/media/i2c/Kconfig  |   12 +
>>>>  drivers/media/i2c/Makefile |    1 +
>>>>  drivers/media/i2c/ov5645.c | 1372 ++++++++++++++++++++++++++++++++++++++
>>>>  3 files changed, 1385 insertions(+)
>>>>  create mode 100644 drivers/media/i2c/ov5645.c
>>>
>>> [snip]
>>>
>>>> diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c
>>>> new file mode 100644
>>>> index 0000000..5e5c37e
>>>> --- /dev/null
>>>> +++ b/drivers/media/i2c/ov5645.c
>>>> @@ -0,0 +1,1372 @@
> 
> [snip]
> 
>>>> +	{ 0x3103, 0x11 },
>>>> +	{ 0x3008, 0x82 },
>>>> +	{ 0x3008, 0x42 },
>>>> +	{ 0x3103, 0x03 },
>>>> +	{ 0x3503, 0x07 },
>>>
>>> [snip]
>>>
>>>> +	{ 0x3503, 0x00 },
>>>
>>> Can't you get rid of the first write to 0x3503 ?
>>
>> No, this is a startup sequence from the vendor so I'm following it as it is.
> 
> 0x3503 controls the AEC/AGC mode, I wonder if that's really needed. I'm OK 
> keeping it as-is for now.

I agree that there is a reason to wonder if it is really needed, but I'd still
prefer not to touch it.

> 
>> [snip]
>>
>>>> +static int ov5645_regulators_enable(struct ov5645 *ov5645)
>>>> +{
>>>> +	int ret;
>>>> +
>>>> +	ret = regulator_enable(ov5645->io_regulator);
>>>> +	if (ret < 0) {
>>>> +		dev_err(ov5645->dev, "set io voltage failed\n");
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	ret = regulator_enable(ov5645->core_regulator);
>>>> +	if (ret) {
>>>> +		dev_err(ov5645->dev, "set core voltage failed\n");
>>>> +		goto err_disable_io;
>>>> +	}
>>>> +
>>>> +	ret = regulator_enable(ov5645->analog_regulator);
>>>> +	if (ret) {
>>>> +		dev_err(ov5645->dev, "set analog voltage failed\n");
>>>> +		goto err_disable_core;
>>>> +	}
>>>
>>> How about using the regulator bulk API ? This would simplify the enable
>>> and disable functions.
>>
>> The driver must enable the regulators in this order. I can see in the
>> implementation of the bulk api that they are enabled again in order
>> but I don't see stated anywhere that it is guaranteed to follow the
>> same order in future. I'd prefer to keep it explicit as it is now.
> 
> I believe it should be an API guarantee, otherwise many drivers using the bulk 
> API would break. Mark, could you please comment on that ?

Ok, let's wait for a response from Mark.

> 
>> [snip]
>>
>>>> +static int ov5645_set_power_on(struct ov5645 *ov5645)
>>>> +{
>>>> +	int ret;
>>>> +
>>>> +	clk_set_rate(ov5645->xclk, ov5645->xclk_freq);
>>>
>>> Is this needed every time you power the sensor on or could you do it just
>>> once at probe time ?
>>
>> I'll move it at probe time.
>>
>>>> +	ret = clk_prepare_enable(ov5645->xclk);
>>>> +	if (ret < 0) {
>>>> +		dev_err(ov5645->dev, "clk prepare enable failed\n");
>>>> +		return ret;
>>>> +	}
>>>
>>> Is it safe to start the clock before the regulators ? Driving an input of
>>> an unpowered chip can lead to latch-up issues.
>>
>> Correct, power should be enabled first. I'll fix this.
>>
>>>> +	ret = ov5645_regulators_enable(ov5645);
>>>> +	if (ret < 0) {
>>>> +		clk_disable_unprepare(ov5645->xclk);
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	usleep_range(5000, 15000);
>>>> +	gpiod_set_value_cansleep(ov5645->enable_gpio, 1);
>>>> +
>>>> +	usleep_range(1000, 2000);
>>>> +	gpiod_set_value_cansleep(ov5645->rst_gpio, 0);
>>>> +
>>>> +	msleep(20);
>>>> +
>>>> +	return ret;
>>>
>>> You can return 0.
>>
>> Ok.
>>
>> [snip]
>>
>>>> +static int ov5645_set_hflip(struct ov5645 *ov5645, s32 value)
>>>> +{
>>>> +	u8 val;
>>>> +	int ret;
>>>> +
>>>> +	ret = ov5645_read_reg(ov5645, OV5645_TIMING_TC_REG21, &val);
>>>> +	if (ret < 0)
>>>> +		return ret;
>>>> +
>>>> +	if (value == 0)
>>>> +		val &= ~(OV5645_SENSOR_MIRROR);
>>>> +	else
>>>> +		val |= (OV5645_SENSOR_MIRROR);
>>>> +
>>>> +	return ov5645_write_reg(ov5645, OV5645_TIMING_TC_REG21, val);
>>>
>>> You could cache this register too.
>>
>> Ok.
>>
>>>> +}
>>>> +
>>>> +static int ov5645_set_vflip(struct ov5645 *ov5645, s32 value)
>>>> +{
>>>> +	u8 val;
>>>> +	int ret;
>>>> +
>>>> +	ret = ov5645_read_reg(ov5645, OV5645_TIMING_TC_REG20, &val);
>>>> +	if (ret < 0)
>>>> +		return ret;
>>>> +
>>>> +	if (value == 0)
>>>> +		val |= (OV5645_SENSOR_VFLIP | OV5645_ISP_VFLIP);
>>>> +	else
>>>> +		val &= ~(OV5645_SENSOR_VFLIP | OV5645_ISP_VFLIP);
>>>> +
>>>> +	return ov5645_write_reg(ov5645, OV5645_TIMING_TC_REG20, val);
>>>
>>> And this one as well.
>>
>> Yes.
>>
>>> How about using regmap by the way ?
>>
>> I'd prefer to keep it as is for now.
>>
>>>> +}
>>>> +
>>>> +static int ov5645_set_test_pattern(struct ov5645 *ov5645, s32 value)
>>>> +{
>>>> +	u8 val;
>>>> +	int ret;
>>>> +
>>>> +	ret = ov5645_read_reg(ov5645, OV5645_PRE_ISP_TEST_SETTING_1, &val);
>>>> +	if (ret < 0)
>>>> +		return ret;
>>>> +
>>>> +	if (value) {
>>>> +		val &= ~OV5645_SET_TEST_PATTERN(OV5645_TEST_PATTERN_MASK);
>>>> +		val |= OV5645_SET_TEST_PATTERN(value - 1);
>>>> +		val |= OV5645_TEST_PATTERN_ENABLE;
>>>> +	} else {
>>>> +		val &= ~OV5645_TEST_PATTERN_ENABLE;
>>>> +	}
>>>> +
>>>> +	return ov5645_write_reg(ov5645, OV5645_PRE_ISP_TEST_SETTING_1, val);
>>>
>>> Are there other bits that need to be preserved in this register ?
>>
>> This driver is based on the driver for OV5645 from QC and the driver for
>> OV5640 that was sent to linux-media. I cannot add additional functionality
>> so I preserve the rest of the bits. But I'll add caching in a variable here
>> too.
> 
> As far as I know, based on the documentation I've seen, all bits in this 
> register control the test pattern and none need to be preserved. The default 
> reset value of the register is 0x00 and the initialization sequence sets it to 
> 0x00 as well, so it should be safe not caching it.
> 

Ok, then I'll remove any reading or caching for this one.

>>>> +}
>>>> +
>>>> +static const char * const ov5645_test_pattern_menu[] = {
>>>> +	"Disabled",
>>>> +	"Vertical Color Bars",
>>>> +	"Pseudo-Random Data",
>>>> +	"Color Square",
>>>> +	"Black Image",
>>>> +};
>>>> +
>>>> +static int ov5645_set_awb(struct ov5645 *ov5645, s32 enable_auto)
>>>> +{
>>>> +	u8 val;
>>>> +	int ret;
>>>> +
>>>> +	ret = ov5645_read_reg(ov5645, OV5645_AWB_MANUAL_CONTROL, &val);
>>>> +	if (ret < 0)
>>>> +		return ret;
>>>> +
>>>> +	if (enable_auto)
>>>> +		val &= ~OV5645_AWB_MANUAL_ENABLE;
>>>> +	else
>>>> +		val |= OV5645_AWB_MANUAL_ENABLE;
>>>> +
>>>> +	return ov5645_write_reg(ov5645, OV5645_AWB_MANUAL_CONTROL, val);
>>>
>>> Same here, are there other bits that need to be preserved ?
>>
>> Same as above.
> 
> Bits 7:1 are documented as "debug mode" and are set to 0 at reset time. It 
> should be fine not caching this register.
> 

I will remove the reading and caching here too.

>>>> +}
> 
> [snip]
> 
>>>> +static int ov5645_entity_init_cfg(struct v4l2_subdev *subdev,
>>>> +				  struct v4l2_subdev_pad_config *cfg)
>>>> +{
>>>> +	struct v4l2_subdev_format fmt = { 0 };
>>>> +
>>>> +	fmt.which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
>>>
>>> The function will always be called with cfg != NULL.
>>
>> I intend to call this function from probe to init the active format. Will
>> this be ok?
> 
> If you plan to call it with cfg == NULL then yes this has to be handled.
> 
>>>> +	fmt.format.width = 1920;
>>>> +	fmt.format.height = 1080;
>>>> +
>>>> +	v4l2_subdev_call(subdev, pad, set_fmt, cfg, &fmt);
>>>
>>> You can call ov5645_set_format directly.
>>
>> Ok.
>>
>>>> +	return 0;
>>>> +}
> 
> [snip]
> 

-- 
Best regards,
Todor Tomov
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux