Hi Sakari,
On Tue, May 9, 2017 at 4:55 AM, Sakari Ailus <[email protected]> wrote:
> Hi Rajmohan,
>
> A few comments below...
>
> On Sun, May 07, 2017 at 04:33:24AM -0700, [email protected] wrote:
[snip]
>> + rval = v4l2_async_register_subdev(&dw9714_dev->sd);
>> + if (rval < 0)
>> + goto err_cleanup;
>> +
>> + pm_runtime_enable(&client->dev);
>
> Getting PM runtime right doesn't seem to be easy. :-I
>
> pm_runtime_enable() alone doesn't do the trick. I wonder if adding
> pm_runtime_suspend() would do the trick.
Is this something specific for I2C devices? For platform devices,
typically pm_runtime_enable() is the only thing you would need to do.
>
>> +
>> + return 0;
>> +
>> +err_cleanup:
>> + dw9714_subdev_cleanup(dw9714_dev);
>> + dev_err(&client->dev, "Probe failed: %d\n", rval);
>> + return rval;
>> +}
>> +
>> +static int dw9714_remove(struct i2c_client *client)
>> +{
>> + struct v4l2_subdev *sd = i2c_get_clientdata(client);
>> + struct dw9714_device *dw9714_dev = container_of(sd,
>> + struct dw9714_device,
>> + sd);
>> +
>> + pm_runtime_disable(&client->dev);
>> + dw9714_subdev_cleanup(dw9714_dev);
>> +
>> + return 0;
>> +}
>> +
>> +#ifdef CONFIG_PM
>> +
>> +static int dw9714_runtime_suspend(struct device *dev)
>> +{
>> + return 0;
>> +}
>> +
>> +static int dw9714_runtime_resume(struct device *dev)
>> +{
>> + return 0;
>
> I think it'd be fine to remove empty callbacks.
It's actually a bit more complicated (if a PM domain is attached, the
callbacks must be present), however in case of external I2C devices it
should be fine indeed. However, AFAIK, pm_runtime_no_callbacks()
should be called.
>
>> +}
>> +
>> +/* This function sets the vcm position, so it consumes least current */
>> +static int dw9714_suspend(struct device *dev)
>> +{
>> + struct i2c_client *client = to_i2c_client(dev);
>> + struct v4l2_subdev *sd = i2c_get_clientdata(client);
>> + struct dw9714_device *dw9714_dev = container_of(sd,
>> + struct dw9714_device,
>> + sd);
>> + int ret, val;
>> +
>> + dev_dbg(dev, "%s\n", __func__);
>> +
>> + for (val = dw9714_dev->current_val & ~(DW9714_CTRL_STEPS - 1);
>> + val >= 0; val -= DW9714_CTRL_STEPS) {
>> + ret = dw9714_i2c_write(client,
>> + DW9714_VAL((u16) val,
>> DW9714_DEFAULT_S));
>> + if (ret)
>> + dev_err(dev, "%s I2C failure: %d", __func__, ret);
>> + usleep_range(DW9714_CTRL_DELAY_US, DW9714_CTRL_DELAY_US + 10);
>> + }
>> + return 0;
>> +}
>> +
>> +/*
>> + * This function sets the vcm position, so the focus position is set
>> + * closer to the camera
>> + */
>> +static int dw9714_resume(struct device *dev)
>> +{
>> + struct i2c_client *client = to_i2c_client(dev);
>> + struct v4l2_subdev *sd = i2c_get_clientdata(client);
>> + struct dw9714_device *dw9714_dev = container_of(sd,
>> + struct dw9714_device,
>> + sd);
>> + int ret, val;
>> +
>> + dev_dbg(dev, "%s\n", __func__);
>> +
>> + for (val = dw9714_dev->current_val % DW9714_CTRL_STEPS;
>> + val < dw9714_dev->current_val + DW9714_CTRL_STEPS - 1;
>> + val += DW9714_CTRL_STEPS) {
>> + ret = dw9714_i2c_write(client,
>> + DW9714_VAL((u16) val,
>> DW9714_DEFAULT_S));
>> + if (ret)
>> + dev_err(dev, "%s I2C failure: %d", __func__, ret);
>> + usleep_range(DW9714_CTRL_DELAY_US, DW9714_CTRL_DELAY_US + 10);
>> + }
>> +
>> + /* restore v4l2 control values */
>> + ret = v4l2_ctrl_handler_setup(&dw9714_dev->ctrls_vcm);
>
> Doesn't this need to be done for runtime_resume as well?
This driver doesn't seem to be doing any physical power off in its
runtime_suspend and I don't expect an I2C device to be put in a PM
domain, so possibly no need for it.
Best regards,
Tomasz