Re: [PATCH v3 4/4] media: i2c: gc0308: new driver

From: Sakari Ailus
Date: Mon Nov 06 2023 - 03:46:05 EST


Hi Jacopo, Sebastian,

On Mon, Oct 30, 2023 at 09:37:08AM +0100, Jacopo Mondi wrote:
> > +static bool gc0308_is_valid_format(u32 code)
> > +{
> > + unsigned int i;
> > +
> > + for (i = 0; i < ARRAY_SIZE(gc0308_formats); i++) {
> > + if (gc0308_formats[i].code == code)
> > + return true;
> > + }
> > +
> > + return false;
> > +}
> > +
> > +static int gc0308_enum_frame_size(struct v4l2_subdev *subdev,
> > + struct v4l2_subdev_state *sd_state,
> > + struct v4l2_subdev_frame_size_enum *fse)
> > +{
> > + if (fse->index >= ARRAY_SIZE(gc0308_frame_sizes))
> > + return -EINVAL;
> > +
> > + if (!gc0308_is_valid_format(fse->code))
> > + return -EINVAL;
> > +
> > + fse->min_width = gc0308_frame_sizes[fse->index].width;
> > + fse->max_width = gc0308_frame_sizes[fse->index].width;
> > + fse->min_height = gc0308_frame_sizes[fse->index].height;
> > + fse->max_height = gc0308_frame_sizes[fse->index].height;
> > +
> > + return 0;
> > +}
> > +
> > +static void gc0308_update_pad_format(const struct gc0308_frame_size *mode,
> > + struct v4l2_mbus_framefmt *fmt, u32 code)
> > +{
> > + fmt->width = mode->width;
> > + fmt->height = mode->height;
> > + fmt->code = code;
> > + fmt->field = V4L2_FIELD_NONE;
> > + fmt->colorspace = V4L2_COLORSPACE_SRGB;
> > +}
> > +
> > +static int gc0308_set_format(struct v4l2_subdev *sd,
> > + struct v4l2_subdev_state *sd_state,
> > + struct v4l2_subdev_format *fmt)
> > +{
> > + struct gc0308 *gc0308 = to_gc0308(sd);
> > + const struct gc0308_frame_size *mode;
> > + unsigned int i;
> > +
> > + for (i = 0; i < ARRAY_SIZE(gc0308_formats); i++) {
> > + if (fmt->format.code == gc0308_formats[i].code)
> > + break;
> > + }
> > +
> > + if (i >= ARRAY_SIZE(gc0308_formats)) {
> > + dev_warn(gc0308->dev, "unsupported format code: %08x\n",
> > + fmt->format.code);

This isn't supposed to generate a kernel log message. I'd drop it
altogether.

> > + i = 0;
> > + }
>
> This looks very similar to gc0308_is_valid_format()

Could gc0308_is_valid_format() return a pointer to the format array or
NULL? Then you could check for NULL here and use the first entry in that
case.

>
> > +
> > + mode = v4l2_find_nearest_size(gc0308_frame_sizes,
> > + ARRAY_SIZE(gc0308_frame_sizes), width,
> > + height, fmt->format.width,
> > + fmt->format.height);
> > +
> > + gc0308_update_pad_format(mode, &fmt->format, gc0308_formats[i].code);
> > + *v4l2_subdev_get_pad_format(sd, sd_state, fmt->pad) = fmt->format;
> > +
> > + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
> > + return 0;
> > +
> > + gc0308->mode.out_format = gc0308_formats[i].regval;
> > + gc0308->mode.subsample = mode->subsample;
> > + gc0308->mode.width = mode->width;
> > + gc0308->mode.height = mode->height;
> > +
> > + return 0;
> > +}

...

> > + ret = v4l2_async_register_subdev(&gc0308->sd);
> > + if (ret) {
> > + dev_err_probe(dev, ret, "failed to register v4l subdev\n");
> > + goto fail_power_off;
> > + }
> > +
> > + pm_runtime_set_active(dev);
> > + pm_runtime_enable(dev);
> > + pm_runtime_set_autosuspend_delay(&client->dev, 1000);
> > + pm_runtime_use_autosuspend(&client->dev);
> > + pm_runtime_idle(dev);

This will effective power off the device immediately, without a delay. But
I guess that's ok.

Note that enabling runtime PM needs to take place before registering the
sub-device. I'd move all these calls before that.

> > +
> > + return 0;
> > +
> > +fail_power_off:
> > + gc0308_power_off(dev);
> > +fail_subdev_cleanup:
> > + v4l2_subdev_cleanup(&gc0308->sd);
> > +fail_media_entity_cleanup:
> > + media_entity_cleanup(&gc0308->sd.entity);
> > +fail_ctrl_hdl_cleanup:
> > + v4l2_ctrl_handler_free(&gc0308->hdl);
> > + return ret;
> > +}
> > +
> > +static void gc0308_remove(struct i2c_client *client)
> > +{
> > + struct gc0308 *gc0308 = i2c_get_clientdata(client);
> > + struct device *dev = &client->dev;
> > +
> > + pm_runtime_get_sync(dev);
>
> Uh, I've never seen this call in a _remove before. Is it intentional ?

I think disabling runtime PM and marking the device suspended are enough
here runtime PM-wise.

>
> Apart these two nits the rest is good! thanks for addressing the
> comments received on the previous version.
>
> Reviewed-by: Jacopo Mondi <jacopo.mondi@xxxxxxxxxxxxxxxx>
>
> Thanks
> j
>
> > +
> > + v4l2_async_unregister_subdev(&gc0308->sd);
> > + v4l2_ctrl_handler_free(&gc0308->hdl);
> > +
> > + pm_runtime_disable(dev);
> > + pm_runtime_set_suspended(dev);
> > + pm_runtime_put_noidle(dev);
> > + gc0308_power_off(dev);
> > +}

--
Regards,

Sakari Ailus