Hi Laurent,

On Sat, Mar 20, 2021 at 06:14:43PM +0200, Laurent Pinchart wrote:
> Hi Jacopo,
>
> Thank you for the patch.
>
> On Fri, Mar 19, 2021 at 05:41:42PM +0100, Jacopo Mondi wrote:
> > The current RDACM21 initialization routine powers up the
> > OV10640 image sensor after the OV490 ISP. The ISP is programmed with
> > a firmware loaded from an embedded EEPROM that (most probably) tries
>
> It's actually a serial flash, not an EEPROM.
>
> > to interact and program also the image sensor connected to the ISP.
> >
> > As described in commit ccb26c5742f5 ("media: i2c: rdacm21: Fix OV10640
>
> That commit ID won't be valid anymore once the patches get merged,
> unless they are pulled instead of cherry-picked, which is currently not
> done in the Linux media subsystem. I'd drop it an only mention the
> commit's subject.
>
> > powerup") the image sensor powerdown signal is kept high by an internal
> > pull up resistor and occasionally fails to startup correctly if the
> > powerdown line is not asserted explicitly. Failures in the OV10640
> > startup causes the OV490 firmware to fail to boot correctly resulting in
> > the camera module initialization to fail consequentially.
> >
> > Fix this by powering up the OV10640 image sensor before testing the
> > OV490 firmware boot completion, by splitting the ov10640_initialize()
> > function in an ov10640_power_up() one and an ov10640_check_id() one.
> >
> > Also make sure the OV10640 identification procedure gives enough time to
> > the image sensor to resume after the programming phase performed by the
> > OV490 firmware by repeating the ID read procedure,
>
> s/,/./
>

I'll rework

> >
> > This commit fixes a sporadic start-up error triggered by a failure to
> > detect the OV490 firmware boot completion:
> > rdacm21 8-0054: Timeout waiting for firmware boot
> >
> > Fixes: a59f853b3b4b ("media: i2c: Add driver for RDACM21 camera module")
> > Signed-off-by: Jacopo Mondi <jacopo+rene...@jmondi.org>
> > ---
> >  drivers/media/i2c/rdacm21.c | 46 ++++++++++++++++++++++++++-----------
> >  1 file changed, 32 insertions(+), 14 deletions(-)
> >
> > diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c
> > index 3f38c465b348..3763eb690d74 100644
> > --- a/drivers/media/i2c/rdacm21.c
> > +++ b/drivers/media/i2c/rdacm21.c
> > @@ -69,6 +69,7 @@
> >  #define OV490_ISP_VSIZE_LOW                0x80820062
> >  #define OV490_ISP_VSIZE_HIGH               0x80820063
> >
> > +#define OV10640_PID_TIMEOUT                20
> >  #define OV10640_ID_HIGH                    0xa6
> >  #define OV10640_CHIP_ID                    0x300a
> >  #define OV10640_PIXEL_RATE         55000000
> > @@ -314,10 +315,8 @@ static int rdacm21_get_fmt(struct v4l2_subdev *sd,
> >     return 0;
> >  }
> >
> > -static int ov10640_initialize(struct rdacm21_device *dev)
> > +static void ov10640_power_up(struct rdacm21_device *dev)
> >  {
> > -   u8 val;
> > -
> >     /* Enable GPIO0#0 (reset) and GPIO1#0 (pwdn) as output lines. */
> >     ov490_write_reg(dev, OV490_GPIO_SEL0, OV490_GPIO0);
> >     ov490_write_reg(dev, OV490_GPIO_SEL1, OV490_SPWDN0);
> > @@ -332,18 +331,35 @@ static int ov10640_initialize(struct rdacm21_device 
> > *dev)
> >     usleep_range(1500, 3000);
> >     ov490_write_reg(dev, OV490_GPIO_OUTPUT_VALUE0, OV490_GPIO0);
> >     usleep_range(3000, 5000);
> > +}
> >
> > -   /* Read OV10640 ID to test communications. */
> > -   ov490_write_reg(dev, OV490_SCCB_SLAVE0_DIR, OV490_SCCB_SLAVE_READ);
> > -   ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_HIGH, OV10640_CHIP_ID >> 8);
> > -   ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_LOW, OV10640_CHIP_ID & 
> > 0xff);
> > -
> > -   /* Trigger SCCB slave transaction and give it some time to complete. */
> > -   ov490_write_reg(dev, OV490_HOST_CMD, OV490_HOST_CMD_TRIGGER);
> > -   usleep_range(1000, 1500);
> > +static int ov10640_check_id(struct rdacm21_device *dev)
> > +{
> > +   unsigned int i;
> > +   u8 val;
> >
> > -   ov490_read_reg(dev, OV490_SCCB_SLAVE0_DIR, &val);
> > -   if (val != OV10640_ID_HIGH) {
> > +   /* Read OV10640 ID to test communications. */
> > +   for (i = 0; i < OV10640_PID_TIMEOUT; ++i) {
>
> OV10640_PID_TIMEOUT is used in this function only, I would have made it
> local.
>

I don't think a local variable is better. The timeout is a read-only
constant which is better defined as a macro than a variable.

> > +           ov490_write_reg(dev, OV490_SCCB_SLAVE0_DIR,
> > +                           OV490_SCCB_SLAVE_READ);
> > +           ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_HIGH,
> > +                           OV10640_CHIP_ID >> 8);
> > +           ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_LOW,
> > +                           OV10640_CHIP_ID & 0xff);
> > +
> > +           /*
> > +            * Trigger SCCB slave transaction and give it some time
> > +            * to complete.
> > +            */
> > +           ov490_write_reg(dev, OV490_HOST_CMD, OV490_HOST_CMD_TRIGGER);
> > +           usleep_range(1000, 1500);
>
> It would make sense to create an ov490_sensor_read() function to
> encapsulate all this.
>

Maybe on top when we'll have more users

> It would also be nicer to poll an OV490 register instead of sleeping
> blindly. That likely requires the OV490 application note (referenced in
> the datasheet), which we don't have. It may be useful to try and get
> hold of that. I still feel there may be something a bit fishy, but way
> less than before.
>
> > +
> > +           ov490_read_reg(dev, OV490_SCCB_SLAVE0_DIR, &val);
> > +           if (val == OV10640_ID_HIGH)
> > +                   break;
> > +           usleep_range(1000, 1500);
> > +   }
>
> Blank line ?
>

There isn't one intentionally as the two blocks are tightly coupled.

> > +   if (i == OV10640_PID_TIMEOUT) {
> >             dev_err(dev->dev, "OV10640 ID mismatch: (0x%02x)\n", val);
> >             return -ENODEV;
> >     }
> > @@ -359,6 +375,8 @@ static int ov490_initialize(struct rdacm21_device *dev)
> >     unsigned int i;
> >     int ret;
> >
> > +   ov10640_power_up(dev);
>
> On top of this series, error handling of OV490 writes would make sense.
>

Maybe on top, yes

Is there anything major I should do to get a tag here ?

Thanks
  j


> > +
> >     /*
> >      * Read OV490 Id to test communications. Give it up to 40msec to
> >      * exit from reset.
> > @@ -396,7 +414,7 @@ static int ov490_initialize(struct rdacm21_device *dev)
> >             return -ENODEV;
> >     }
> >
> > -   ret = ov10640_initialize(dev);
> > +   ret = ov10640_check_id(dev);
> >     if (ret)
> >             return ret;
> >
>
> --
> Regards,
>
> Laurent Pinchart

Reply via email to