Re: [PATCH 2/2] media: i2c: Add driver for OmniVision OV64A40

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

 



Hi Sakari

On Mon, Nov 13, 2023 at 04:16:18PM +0000, Sakari Ailus wrote:
> Hi Jacopo,
>
> On Mon, Nov 13, 2023 at 10:19:32AM +0100, Jacopo Mondi wrote:
>
> ...
>
> > > > +	bool vbin;
> > > > +	bool hbin;
> > >
> > > I recall bool is 32 bits on arm. Is it 64 bits on arm64? Just a note, I
> > > don't have a great suggestion here. :-)
> > >
> > > So only binning up to 2x2 is supported?
> > >
> >
> > yes, further downscaling is obtained by skipping.
> >
> > The 0x3820 register has BIT(1) "vbin_vc" than enables binning, so the
> > binning factor doesn't seem to be configurable. Of course there might
> > be other bits/registers to control this, but I'm not aware of those
>
> Ack.
>
> > > > +static int ov64a40_start_streaming(struct ov64a40 *ov64a40,
> > > > +				   struct v4l2_subdev_state *state)
> > > > +{
> > > > +	const struct ov64a40_reglist *reglist = &ov64a40->mode->reglist;
> > > > +	unsigned long delay;
> > > > +	int ret;
> > > > +
> > > > +	ret = pm_runtime_resume_and_get(ov64a40->dev);
> > >
> > > You seem to be using autosuspend, but you still do not try to avoid writes
> > > of presumably the same register values if the sensor was powered on. The
> > > register writes usually take the most of the time there.
> >
> > I'm not sure I get this comment. Are you afraid of multiple calls to
> > "start_streaming" being made ? Isn't it responsibility of the bridge
> > driver to handle this correctly ?
>
> It is.
>
> What I'm saying is that you're re-writing a lot of unchanged sensor
> configuration below even if the sensor has not been powered off in the
> meantime.
>

Indeed! I can move programming the long table of registers to
power_on() so that it gets written only when the device actually
resumes, and close calls to start_stream() won't need to do so.

> >
> > One thing for sure, I should grab a few controls (flips, link_freq)
> > avoid them being written to HW while the sensor is streaming.
> >
> > >
> > > pm_runtime_get_sync() returns 1 if the sensor was already in active state.
> > >
> > > I'm about to send a patchset related to this actually, I can cc you...
> > >

Please, I'm not sure I get the issue still

> > > > +	if (ret < 0)
> > > > +		return ret;
> > > > +
> > > > +	ret = cci_multi_reg_write(ov64a40->cci, ov64a40_init,
> > > > +				  ARRAY_SIZE(ov64a40_init), NULL);
> > > > +	if (ret)
> > > > +		goto error_power_off;
> > > > +
> > > > +	ret = cci_multi_reg_write(ov64a40->cci, reglist->regvals,
> > > > +				  reglist->num_regs, NULL);
> > > > +	if (ret)
> > > > +		goto error_power_off;
> > > > +
> > > > +	ret = ov64a40_program_geometry(ov64a40);
> > > > +	if (ret)
> > > > +		goto error_power_off;
> > > > +
> > > > +	ret = ov64a40_program_subsampling(ov64a40);
> > > > +	if (ret)
> > > > +		goto error_power_off;
> > > > +
> > > > +	ret =  __v4l2_ctrl_handler_setup(&ov64a40->ctrl_handler);
> > > > +	if (ret)
> > > > +		goto error_power_off;
> > > > +
> > > > +	ret = cci_write(ov64a40->cci, OV64A40_REG_SMIA,
> > > > +			OV64A40_REG_SMIA_STREAMING, NULL);
> > > > +	if (ret)
> > > > +		goto error_power_off;
> > > > +
> > > > +	/* delay: max(4096 xclk pulses, 150usec) + exposure time */
> > > > +	delay = DIV_ROUND_UP(4096, OV64A40_XCLK_FREQ / 1000 / 1000);
> > > > +	delay = max(delay, 150ul);
> > > > +	delay += DIV_ROUND_UP(ov64a40->mode->ppl * ov64a40->exposure->cur.val,
> > > > +			      OV64A40_PIXEL_RATE / 1000 / 1000);
> > > > +	fsleep(delay);
> > > > +
> > > > +	return 0;
> > > > +
> > > > +error_power_off:
> > > > +	pm_runtime_mark_last_busy(ov64a40->dev);
> > > > +	pm_runtime_put_autosuspend(ov64a40->dev);
> > > > +
> > > > +	return ret;
> > > > +}
>
> ...
>
> > > > +static int ov64a40_set_ctrl(struct v4l2_ctrl *ctrl)
> > > > +{
> > > > +	struct ov64a40 *ov64a40 = container_of(ctrl->handler, struct ov64a40,
> > > > +					       ctrl_handler);
> > > > +	int ret;
> > > > +
> > > > +	if (ctrl->id == V4L2_CID_VBLANK) {
> > > > +		int exp_max = ov64a40->mode->height + ctrl->val
> > > > +			    - OV64A40_EXPOSURE_MARGIN;
> > > > +		int exp_val = min(ov64a40->exposure->cur.val, exp_max);
> > > > +
> > > > +		__v4l2_ctrl_modify_range(ov64a40->exposure,
> > > > +					 ov64a40->exposure->minimum,
> > > > +					 exp_max, 1, exp_val);
> > > > +	}
> > > > +
> > > > +	if (pm_runtime_get_if_in_use(ov64a40->dev) == 0)
> > >
> > > The function you should use here is actually called
> > > pm_runtime_get_if_active(), but this change would better be postponed after
> > > my patchset.
> >
> >   `int pm_runtime_get_if_in_use(struct device *dev);`
> >     - return -EINVAL if 'power.disable_depth' is nonzero; otherwise, if the
> >       runtime PM status is RPM_ACTIVE and the runtime PM usage counter is
> >       nonzero, increment the counter and return 1; otherwise return 0 without
> >       changing the counter
> >
> >   `int pm_runtime_get_if_active(struct device *dev, bool ign_usage_count);`
> >     - return -EINVAL if 'power.disable_depth' is nonzero; otherwise, if the
> >       runtime PM status is RPM_ACTIVE, and either ign_usage_count is true
> >       or the device's usage_count is non-zero, increment the counter and
> >       return 1; otherwise return 0 without changing the counter
> >
> >
> > The only difference I see here is the additional 'ign_usage_count'
> > which allows to forcefully resume the device by ignoring the usage
> > counter ? Why would you forcefully resume the device here ? Don't we
> > actually want the opposite and use this check to only access the HW if
> > the device is powered already ?
> >
>
> It ignores the usage_count before the call while incrementing it if the
> device was in active state. Although this change isn't useful if you
> continue to re-write the configuration to sensor's registers in streamon
> nevertheless.
>

I didn't get why the two things are related :)

> > >
> > > > +		return 0;
> > > > +
> > > > +	switch (ctrl->id) {
> > > > +	case V4L2_CID_EXPOSURE:
> > > > +		ret = cci_write(ov64a40->cci, OV64A40_REG_MEC_LONG_EXPO,
> > > > +				ctrl->val, NULL);
> > > > +		break;
> > > > +	case V4L2_CID_ANALOGUE_GAIN:
> > > > +		ret = ov64a40_set_anagain(ctrl);
> > > > +		break;
> > > > +	case V4L2_CID_VBLANK:
> > > > +		ret = cci_write(ov64a40->cci, OV64A40_REG_TIMINGS_VTS,
> > > > +				ctrl->val + ov64a40->mode->height, NULL);
> > > > +		break;
> > > > +	case V4L2_CID_VFLIP:
> > > > +		ret = cci_update_bits(ov64a40->cci, OV64A40_REG_TIMING_CTRL_20,
> > > > +				      OV64A40_TIMING_CTRL_20_VFLIP,
> > > > +				      ctrl->val << 2,
> > > > +				      NULL);
> > > > +		break;
> > > > +	case V4L2_CID_HFLIP:
> > > > +		ret = cci_update_bits(ov64a40->cci, OV64A40_REG_TIMING_CTRL_21,
> > > > +				      OV64A40_TIMING_CTRL_21_HFLIP,
> > > > +				      ctrl->val << 2,
> > > > +				      NULL);
> > > > +		break;
> > > > +	default:
> > > > +		dev_err(ov64a40->dev, "Unhandled control: %#x\n", ctrl->id);
> > > > +		ret = -EINVAL;
> > > > +		break;
> > > > +	}
> > > > +
> > > > +	pm_runtime_put(ov64a40->dev);
> > > > +
> > > > +	return ret;
> > > > +}
>
> ...
>
> > > > +	xclk_freq = clk_get_rate(ov64a40->xclk);
> > > > +	if (xclk_freq != OV64A40_XCLK_FREQ) {
> > > > +		dev_err(&client->dev, "Unsupported xclk frequency %u\n",
> > > > +			xclk_freq);
> > > > +		return -EINVAL;
> > >
> > > Feel free to handle this not as an error. Up to you.
> > >
> >
> > Well, the driver won't work correctly if the clock is not running
> > at the expected frequency..
>
> There is some number of systems where you can't get this exact frequency
> but typically something fairly close. The above check prevents the driver
> from working in that case.
>
> As I wrote, this is up to you.
>

You know, if we allow close-enough frequencies which I cannot test,
someone could later try and find out that something is wrong and then
rightfully complain. I would prefer to change the driver -after- testing.

> --
> Regards,
>
> Sakari Ailus




[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