From: Dongchun Zhu <dongchun.zhu@mediatek.com>
To: Tomasz Figa <tfiga@chromium.org>
Cc: <linus.walleij@linaro.org>, <bgolaszewski@baylibre.com>,
<mchehab@kernel.org>, <andriy.shevchenko@linux.intel.com>,
<robh+dt@kernel.org>, <mark.rutland@arm.com>,
<sakari.ailus@linux.intel.com>, <drinkcat@chromium.org>,
<matthias.bgg@gmail.com>, <bingbu.cao@intel.com>,
<srv_heupstream@mediatek.com>,
<linux-mediatek@lists.infradead.org>,
<linux-arm-kernel@lists.infradead.org>, <sj.huang@mediatek.com>,
<linux-media@vger.kernel.org>, <devicetree@vger.kernel.org>,
<louis.kuo@mediatek.com>, <shengnan.wang@mediatek.com>,
<dongchun.zhu@mediatek.com>
Subject: Re: [V6, 2/2] media: i2c: dw9768: Add DW9768 VCM driver
Date: Fri, 22 May 2020 17:26:01 +0800 [thread overview]
Message-ID: <1590139561.8804.390.camel@mhfsdcap03> (raw)
In-Reply-To: <20200521195113.GC14214@chromium.org>
Hi Tomasz,
Thanks for the review. My replies are as below.
On Thu, 2020-05-21 at 19:51 +0000, Tomasz Figa wrote:
> Hi Dongchun, Sakari,
>
> On Mon, May 18, 2020 at 09:27:31PM +0800, Dongchun Zhu wrote:
> > Add a V4L2 sub-device driver for DW9768 voice coil motor, providing
> > control to set the desired focus via IIC serial interface.
> >
> > Signed-off-by: Dongchun Zhu <dongchun.zhu@mediatek.com>
> > ---
> > MAINTAINERS | 1 +
> > drivers/media/i2c/Kconfig | 13 ++
> > drivers/media/i2c/Makefile | 1 +
> > drivers/media/i2c/dw9768.c | 515 +++++++++++++++++++++++++++++++++++++++++++++
> > 4 files changed, 530 insertions(+)
> > create mode 100644 drivers/media/i2c/dw9768.c
> [snip]
> > +/*
> > + * DW9768_AAC_PRESC_REG & DW9768_AAC_TIME_REG determine VCM operation time.
> > + * If DW9768_AAC_PRESC_REG is 0x41, and DW9768_AAC_TIME_REG is 0x39, VCM mode
> > + * would be AAC3, Operation Time would be 0.70xTvib, that is 8.40ms.
> > + */
> > +#define DW9768_MOVE_DELAY_US 8400
> > +#define DW9768_STABLE_TIME_US 20000
>
> These times are only valid with the specific settings mentioned in the
> comment. If one sets different settings in DT, the driver would apply
> incorrect delays. Rather than hardcoded, they should be computed based
> on the configured values.
>
> That said, I wonder if we're not digging too deep now. Sakari, do you
> think we could take a step back, remove the optional DT properties and
> just support the fixed values for now, so that we can get a basic driver
> upstream first without doubling the effort?
>
Thanks for the reminder.
Yes, here DW9768_MOVE_DELAY_US actually represents Operation Time,
which is dependent upon board-specific settings that defined in DT.
For instance, for one given board, if aac-mode is 2, aac-timing is 0x39,
clock-presc is 1, then Operation Time would be 0.70*(6.3ms+57*0.1ms)*1 =
8.4ms.
> > +
> > +static const char * const dw9768_supply_names[] = {
> > + "vin", /* I2C I/O interface power */
> > + "vdd", /* VCM power */
> > +};
> > +
> > +/* dw9768 device structure */
> > +struct dw9768 {
> > + struct regulator_bulk_data supplies[ARRAY_SIZE(dw9768_supply_names)];
> > + struct v4l2_ctrl_handler ctrls;
> > + struct v4l2_ctrl *focus;
> > + struct v4l2_subdev sd;
> > +
> > + u32 aac_mode;
> > + u32 aac_timing;
> > + u32 clock_dividing_rate;
> > + bool aac_mode_control_enable;
> > + bool aact_cnt_select_enable;
> > + bool clock_dividing_rate_select_enable;
>
> nit: Separate types from names with just 1 space.
>
Fixed in next release.
> > +};
> > +
> > +static inline struct dw9768 *sd_to_dw9768(struct v4l2_subdev *subdev)
> > +{
> > + return container_of(subdev, struct dw9768, sd);
> > +}
> > +
> > +struct regval_list {
> > + u8 reg_num;
> > + u8 value;
> > +};
> > +
> > +static int dw9768_read_smbus(struct dw9768 *dw9768, unsigned char reg,
> > + unsigned char *val)
> > +{
> > + struct i2c_client *client = v4l2_get_subdevdata(&dw9768->sd);
> > + int ret;
> > +
> > + ret = i2c_smbus_read_byte_data(client, reg);
> > +
> > + if (ret < 0)
> > + return ret;
> > +
> > + *val = (unsigned char)ret;
> > +
> > + return 0;
> > +}
>
> Why do we need this function? Couldn't we just call
> i2c_smbus_read_byte_data() directly?
>
Fixed in next release.
> [snip]
> > +static int dw9768_probe(struct i2c_client *client)
> > +{
> > + struct device *dev = &client->dev;
> > + struct dw9768 *dw9768;
> > + unsigned int aac_mode_select;
> > + unsigned int aac_timing_select;
> > + unsigned int clock_dividing_rate_select;
> > + unsigned int i;
> > + int ret;
> > +
> > + dw9768 = devm_kzalloc(dev, sizeof(*dw9768), GFP_KERNEL);
> > + if (!dw9768)
> > + return -ENOMEM;
> > +
> > + v4l2_i2c_subdev_init(&dw9768->sd, client, &dw9768_ops);
> > + dw9768->aac_mode_control_enable = false;
> > + dw9768->aact_cnt_select_enable = false;
> > + dw9768->clock_dividing_rate_select_enable = false;
>
> devm_kzalloc() initializes the memory to zero, so no need to set anything
> to false explicitly.
>
Thanks for the reminder.
Yes, these parameters shall not be needed to initialized as zeros.
> > +
> > + /* Optional indication of AAC mode select */
> > + ret = fwnode_property_read_u32(dev_fwnode(dev), "dongwoon,aac-mode",
> > + &aac_mode_select);
> > +
> > + if (!ret) {
> > + dw9768->aac_mode_control_enable = true;
> > + dw9768->aac_mode = aac_mode_select;
>
> How about making aac_mode a signed int and assigning -1 by
> default? Then we don't need two separate fields in the struct.
>
Good idea.
> > + }
> > +
> > + /* Optional indication of VCM internal clock dividing rate select */
> > + ret = fwnode_property_read_u32(dev_fwnode(dev),
> > + "dongwoon,clock-dividing-rate",
> > + &clock_dividing_rate_select);
> > +
> > + if (!ret) {
> > + dw9768->clock_dividing_rate_select_enable = true;
> > + dw9768->clock_dividing_rate = clock_dividing_rate_select;
>
> Ditto.
>
Got it.
> > + }
> > +
> > + /* Optional indication of AAC Timing */
> > + ret = fwnode_property_read_u32(dev_fwnode(dev), "dongwoon,aac-timing",
> > + &aac_timing_select);
> > +
> > + if (!ret) {
> > + dw9768->aact_cnt_select_enable = true;
> > + dw9768->aac_timing = aac_timing_select;
>
> Ditto.
>
Got it.
> > + }
> > +
> > + for (i = 0; i < ARRAY_SIZE(dw9768_supply_names); i++)
> > + dw9768->supplies[i].supply = dw9768_supply_names[i];
> > +
> > + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(dw9768_supply_names),
> > + dw9768->supplies);
> > + if (ret) {
> > + dev_err(dev, "failed to get regulators\n");
> > + return ret;
> > + }
> > +
> > + ret = dw9768_init_controls(dw9768);
> > + if (ret)
> > + goto entity_cleanup;
> > +
> > + dw9768->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> > + dw9768->sd.internal_ops = &dw9768_int_ops;
> > +
> > + ret = media_entity_pads_init(&dw9768->sd.entity, 0, NULL);
> > + if (ret < 0)
> > + goto entity_cleanup;
> > +
> > + dw9768->sd.entity.function = MEDIA_ENT_F_LENS;
> > +
> > + pm_runtime_enable(dev);
> > + if (!pm_runtime_enabled(dev)) {
> > + ret = dw9768_runtime_resume(dev);
> > + if (ret < 0) {
> > + dev_err(dev, "failed to power on: %d\n", ret);
> > + goto entity_cleanup;
> > + }
> > + }
> > +
> > + ret = v4l2_async_register_subdev(&dw9768->sd);
> > + if (ret < 0)
> > + goto entity_cleanup;
> > +
> > + return 0;
> > +
> > +entity_cleanup:
>
> Need to power off if the code above powered on.
>
Thanks for the reminder.
If there is something wrong with runtime PM, actuator is to be powered
on via dw9768_runtime_resume() API.
When actuator sub-device is powered on completely and async registered
successfully, we shall power off it afterwards.
> > + v4l2_ctrl_handler_free(&dw9768->ctrls);
> > + media_entity_cleanup(&dw9768->sd.entity);
> > + return ret;
> > +}
> > +
> > +static int dw9768_remove(struct i2c_client *client)
> > +{
> > + struct v4l2_subdev *sd = i2c_get_clientdata(client);
> > + struct dw9768 *dw9768 = sd_to_dw9768(sd);
> > +
> > + pm_runtime_disable(&client->dev);
>
> First the device must be unregistered from the userspace. Otherwise there
> is a race condition that risks the userspace accessing the device while the
> deinitialization is happening.
>
Fixed in next release by adjusting the sequence of unregistering and
runtime PM disable.
> Best regards,
> Tomasz
WARNING: multiple messages have this Message-ID (diff)
From: Dongchun Zhu <dongchun.zhu@mediatek.com>
To: Tomasz Figa <tfiga@chromium.org>
Cc: mark.rutland@arm.com, drinkcat@chromium.org,
andriy.shevchenko@linux.intel.com, srv_heupstream@mediatek.com,
devicetree@vger.kernel.org, linus.walleij@linaro.org,
shengnan.wang@mediatek.com, louis.kuo@mediatek.com,
bgolaszewski@baylibre.com, sj.huang@mediatek.com,
robh+dt@kernel.org, linux-mediatek@lists.infradead.org,
dongchun.zhu@mediatek.com, sakari.ailus@linux.intel.com,
matthias.bgg@gmail.com, bingbu.cao@intel.com, mchehab@kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-media@vger.kernel.org
Subject: Re: [V6, 2/2] media: i2c: dw9768: Add DW9768 VCM driver
Date: Fri, 22 May 2020 17:26:01 +0800 [thread overview]
Message-ID: <1590139561.8804.390.camel@mhfsdcap03> (raw)
In-Reply-To: <20200521195113.GC14214@chromium.org>
Hi Tomasz,
Thanks for the review. My replies are as below.
On Thu, 2020-05-21 at 19:51 +0000, Tomasz Figa wrote:
> Hi Dongchun, Sakari,
>
> On Mon, May 18, 2020 at 09:27:31PM +0800, Dongchun Zhu wrote:
> > Add a V4L2 sub-device driver for DW9768 voice coil motor, providing
> > control to set the desired focus via IIC serial interface.
> >
> > Signed-off-by: Dongchun Zhu <dongchun.zhu@mediatek.com>
> > ---
> > MAINTAINERS | 1 +
> > drivers/media/i2c/Kconfig | 13 ++
> > drivers/media/i2c/Makefile | 1 +
> > drivers/media/i2c/dw9768.c | 515 +++++++++++++++++++++++++++++++++++++++++++++
> > 4 files changed, 530 insertions(+)
> > create mode 100644 drivers/media/i2c/dw9768.c
> [snip]
> > +/*
> > + * DW9768_AAC_PRESC_REG & DW9768_AAC_TIME_REG determine VCM operation time.
> > + * If DW9768_AAC_PRESC_REG is 0x41, and DW9768_AAC_TIME_REG is 0x39, VCM mode
> > + * would be AAC3, Operation Time would be 0.70xTvib, that is 8.40ms.
> > + */
> > +#define DW9768_MOVE_DELAY_US 8400
> > +#define DW9768_STABLE_TIME_US 20000
>
> These times are only valid with the specific settings mentioned in the
> comment. If one sets different settings in DT, the driver would apply
> incorrect delays. Rather than hardcoded, they should be computed based
> on the configured values.
>
> That said, I wonder if we're not digging too deep now. Sakari, do you
> think we could take a step back, remove the optional DT properties and
> just support the fixed values for now, so that we can get a basic driver
> upstream first without doubling the effort?
>
Thanks for the reminder.
Yes, here DW9768_MOVE_DELAY_US actually represents Operation Time,
which is dependent upon board-specific settings that defined in DT.
For instance, for one given board, if aac-mode is 2, aac-timing is 0x39,
clock-presc is 1, then Operation Time would be 0.70*(6.3ms+57*0.1ms)*1 =
8.4ms.
> > +
> > +static const char * const dw9768_supply_names[] = {
> > + "vin", /* I2C I/O interface power */
> > + "vdd", /* VCM power */
> > +};
> > +
> > +/* dw9768 device structure */
> > +struct dw9768 {
> > + struct regulator_bulk_data supplies[ARRAY_SIZE(dw9768_supply_names)];
> > + struct v4l2_ctrl_handler ctrls;
> > + struct v4l2_ctrl *focus;
> > + struct v4l2_subdev sd;
> > +
> > + u32 aac_mode;
> > + u32 aac_timing;
> > + u32 clock_dividing_rate;
> > + bool aac_mode_control_enable;
> > + bool aact_cnt_select_enable;
> > + bool clock_dividing_rate_select_enable;
>
> nit: Separate types from names with just 1 space.
>
Fixed in next release.
> > +};
> > +
> > +static inline struct dw9768 *sd_to_dw9768(struct v4l2_subdev *subdev)
> > +{
> > + return container_of(subdev, struct dw9768, sd);
> > +}
> > +
> > +struct regval_list {
> > + u8 reg_num;
> > + u8 value;
> > +};
> > +
> > +static int dw9768_read_smbus(struct dw9768 *dw9768, unsigned char reg,
> > + unsigned char *val)
> > +{
> > + struct i2c_client *client = v4l2_get_subdevdata(&dw9768->sd);
> > + int ret;
> > +
> > + ret = i2c_smbus_read_byte_data(client, reg);
> > +
> > + if (ret < 0)
> > + return ret;
> > +
> > + *val = (unsigned char)ret;
> > +
> > + return 0;
> > +}
>
> Why do we need this function? Couldn't we just call
> i2c_smbus_read_byte_data() directly?
>
Fixed in next release.
> [snip]
> > +static int dw9768_probe(struct i2c_client *client)
> > +{
> > + struct device *dev = &client->dev;
> > + struct dw9768 *dw9768;
> > + unsigned int aac_mode_select;
> > + unsigned int aac_timing_select;
> > + unsigned int clock_dividing_rate_select;
> > + unsigned int i;
> > + int ret;
> > +
> > + dw9768 = devm_kzalloc(dev, sizeof(*dw9768), GFP_KERNEL);
> > + if (!dw9768)
> > + return -ENOMEM;
> > +
> > + v4l2_i2c_subdev_init(&dw9768->sd, client, &dw9768_ops);
> > + dw9768->aac_mode_control_enable = false;
> > + dw9768->aact_cnt_select_enable = false;
> > + dw9768->clock_dividing_rate_select_enable = false;
>
> devm_kzalloc() initializes the memory to zero, so no need to set anything
> to false explicitly.
>
Thanks for the reminder.
Yes, these parameters shall not be needed to initialized as zeros.
> > +
> > + /* Optional indication of AAC mode select */
> > + ret = fwnode_property_read_u32(dev_fwnode(dev), "dongwoon,aac-mode",
> > + &aac_mode_select);
> > +
> > + if (!ret) {
> > + dw9768->aac_mode_control_enable = true;
> > + dw9768->aac_mode = aac_mode_select;
>
> How about making aac_mode a signed int and assigning -1 by
> default? Then we don't need two separate fields in the struct.
>
Good idea.
> > + }
> > +
> > + /* Optional indication of VCM internal clock dividing rate select */
> > + ret = fwnode_property_read_u32(dev_fwnode(dev),
> > + "dongwoon,clock-dividing-rate",
> > + &clock_dividing_rate_select);
> > +
> > + if (!ret) {
> > + dw9768->clock_dividing_rate_select_enable = true;
> > + dw9768->clock_dividing_rate = clock_dividing_rate_select;
>
> Ditto.
>
Got it.
> > + }
> > +
> > + /* Optional indication of AAC Timing */
> > + ret = fwnode_property_read_u32(dev_fwnode(dev), "dongwoon,aac-timing",
> > + &aac_timing_select);
> > +
> > + if (!ret) {
> > + dw9768->aact_cnt_select_enable = true;
> > + dw9768->aac_timing = aac_timing_select;
>
> Ditto.
>
Got it.
> > + }
> > +
> > + for (i = 0; i < ARRAY_SIZE(dw9768_supply_names); i++)
> > + dw9768->supplies[i].supply = dw9768_supply_names[i];
> > +
> > + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(dw9768_supply_names),
> > + dw9768->supplies);
> > + if (ret) {
> > + dev_err(dev, "failed to get regulators\n");
> > + return ret;
> > + }
> > +
> > + ret = dw9768_init_controls(dw9768);
> > + if (ret)
> > + goto entity_cleanup;
> > +
> > + dw9768->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> > + dw9768->sd.internal_ops = &dw9768_int_ops;
> > +
> > + ret = media_entity_pads_init(&dw9768->sd.entity, 0, NULL);
> > + if (ret < 0)
> > + goto entity_cleanup;
> > +
> > + dw9768->sd.entity.function = MEDIA_ENT_F_LENS;
> > +
> > + pm_runtime_enable(dev);
> > + if (!pm_runtime_enabled(dev)) {
> > + ret = dw9768_runtime_resume(dev);
> > + if (ret < 0) {
> > + dev_err(dev, "failed to power on: %d\n", ret);
> > + goto entity_cleanup;
> > + }
> > + }
> > +
> > + ret = v4l2_async_register_subdev(&dw9768->sd);
> > + if (ret < 0)
> > + goto entity_cleanup;
> > +
> > + return 0;
> > +
> > +entity_cleanup:
>
> Need to power off if the code above powered on.
>
Thanks for the reminder.
If there is something wrong with runtime PM, actuator is to be powered
on via dw9768_runtime_resume() API.
When actuator sub-device is powered on completely and async registered
successfully, we shall power off it afterwards.
> > + v4l2_ctrl_handler_free(&dw9768->ctrls);
> > + media_entity_cleanup(&dw9768->sd.entity);
> > + return ret;
> > +}
> > +
> > +static int dw9768_remove(struct i2c_client *client)
> > +{
> > + struct v4l2_subdev *sd = i2c_get_clientdata(client);
> > + struct dw9768 *dw9768 = sd_to_dw9768(sd);
> > +
> > + pm_runtime_disable(&client->dev);
>
> First the device must be unregistered from the userspace. Otherwise there
> is a race condition that risks the userspace accessing the device while the
> deinitialization is happening.
>
Fixed in next release by adjusting the sequence of unregistering and
runtime PM disable.
> Best regards,
> Tomasz
_______________________________________________
Linux-mediatek mailing list
Linux-mediatek@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-mediatek
WARNING: multiple messages have this Message-ID (diff)
From: Dongchun Zhu <dongchun.zhu@mediatek.com>
To: Tomasz Figa <tfiga@chromium.org>
Cc: mark.rutland@arm.com, drinkcat@chromium.org,
andriy.shevchenko@linux.intel.com, srv_heupstream@mediatek.com,
devicetree@vger.kernel.org, linus.walleij@linaro.org,
shengnan.wang@mediatek.com, louis.kuo@mediatek.com,
bgolaszewski@baylibre.com, sj.huang@mediatek.com,
robh+dt@kernel.org, linux-mediatek@lists.infradead.org,
dongchun.zhu@mediatek.com, sakari.ailus@linux.intel.com,
matthias.bgg@gmail.com, bingbu.cao@intel.com, mchehab@kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-media@vger.kernel.org
Subject: Re: [V6, 2/2] media: i2c: dw9768: Add DW9768 VCM driver
Date: Fri, 22 May 2020 17:26:01 +0800 [thread overview]
Message-ID: <1590139561.8804.390.camel@mhfsdcap03> (raw)
In-Reply-To: <20200521195113.GC14214@chromium.org>
Hi Tomasz,
Thanks for the review. My replies are as below.
On Thu, 2020-05-21 at 19:51 +0000, Tomasz Figa wrote:
> Hi Dongchun, Sakari,
>
> On Mon, May 18, 2020 at 09:27:31PM +0800, Dongchun Zhu wrote:
> > Add a V4L2 sub-device driver for DW9768 voice coil motor, providing
> > control to set the desired focus via IIC serial interface.
> >
> > Signed-off-by: Dongchun Zhu <dongchun.zhu@mediatek.com>
> > ---
> > MAINTAINERS | 1 +
> > drivers/media/i2c/Kconfig | 13 ++
> > drivers/media/i2c/Makefile | 1 +
> > drivers/media/i2c/dw9768.c | 515 +++++++++++++++++++++++++++++++++++++++++++++
> > 4 files changed, 530 insertions(+)
> > create mode 100644 drivers/media/i2c/dw9768.c
> [snip]
> > +/*
> > + * DW9768_AAC_PRESC_REG & DW9768_AAC_TIME_REG determine VCM operation time.
> > + * If DW9768_AAC_PRESC_REG is 0x41, and DW9768_AAC_TIME_REG is 0x39, VCM mode
> > + * would be AAC3, Operation Time would be 0.70xTvib, that is 8.40ms.
> > + */
> > +#define DW9768_MOVE_DELAY_US 8400
> > +#define DW9768_STABLE_TIME_US 20000
>
> These times are only valid with the specific settings mentioned in the
> comment. If one sets different settings in DT, the driver would apply
> incorrect delays. Rather than hardcoded, they should be computed based
> on the configured values.
>
> That said, I wonder if we're not digging too deep now. Sakari, do you
> think we could take a step back, remove the optional DT properties and
> just support the fixed values for now, so that we can get a basic driver
> upstream first without doubling the effort?
>
Thanks for the reminder.
Yes, here DW9768_MOVE_DELAY_US actually represents Operation Time,
which is dependent upon board-specific settings that defined in DT.
For instance, for one given board, if aac-mode is 2, aac-timing is 0x39,
clock-presc is 1, then Operation Time would be 0.70*(6.3ms+57*0.1ms)*1 =
8.4ms.
> > +
> > +static const char * const dw9768_supply_names[] = {
> > + "vin", /* I2C I/O interface power */
> > + "vdd", /* VCM power */
> > +};
> > +
> > +/* dw9768 device structure */
> > +struct dw9768 {
> > + struct regulator_bulk_data supplies[ARRAY_SIZE(dw9768_supply_names)];
> > + struct v4l2_ctrl_handler ctrls;
> > + struct v4l2_ctrl *focus;
> > + struct v4l2_subdev sd;
> > +
> > + u32 aac_mode;
> > + u32 aac_timing;
> > + u32 clock_dividing_rate;
> > + bool aac_mode_control_enable;
> > + bool aact_cnt_select_enable;
> > + bool clock_dividing_rate_select_enable;
>
> nit: Separate types from names with just 1 space.
>
Fixed in next release.
> > +};
> > +
> > +static inline struct dw9768 *sd_to_dw9768(struct v4l2_subdev *subdev)
> > +{
> > + return container_of(subdev, struct dw9768, sd);
> > +}
> > +
> > +struct regval_list {
> > + u8 reg_num;
> > + u8 value;
> > +};
> > +
> > +static int dw9768_read_smbus(struct dw9768 *dw9768, unsigned char reg,
> > + unsigned char *val)
> > +{
> > + struct i2c_client *client = v4l2_get_subdevdata(&dw9768->sd);
> > + int ret;
> > +
> > + ret = i2c_smbus_read_byte_data(client, reg);
> > +
> > + if (ret < 0)
> > + return ret;
> > +
> > + *val = (unsigned char)ret;
> > +
> > + return 0;
> > +}
>
> Why do we need this function? Couldn't we just call
> i2c_smbus_read_byte_data() directly?
>
Fixed in next release.
> [snip]
> > +static int dw9768_probe(struct i2c_client *client)
> > +{
> > + struct device *dev = &client->dev;
> > + struct dw9768 *dw9768;
> > + unsigned int aac_mode_select;
> > + unsigned int aac_timing_select;
> > + unsigned int clock_dividing_rate_select;
> > + unsigned int i;
> > + int ret;
> > +
> > + dw9768 = devm_kzalloc(dev, sizeof(*dw9768), GFP_KERNEL);
> > + if (!dw9768)
> > + return -ENOMEM;
> > +
> > + v4l2_i2c_subdev_init(&dw9768->sd, client, &dw9768_ops);
> > + dw9768->aac_mode_control_enable = false;
> > + dw9768->aact_cnt_select_enable = false;
> > + dw9768->clock_dividing_rate_select_enable = false;
>
> devm_kzalloc() initializes the memory to zero, so no need to set anything
> to false explicitly.
>
Thanks for the reminder.
Yes, these parameters shall not be needed to initialized as zeros.
> > +
> > + /* Optional indication of AAC mode select */
> > + ret = fwnode_property_read_u32(dev_fwnode(dev), "dongwoon,aac-mode",
> > + &aac_mode_select);
> > +
> > + if (!ret) {
> > + dw9768->aac_mode_control_enable = true;
> > + dw9768->aac_mode = aac_mode_select;
>
> How about making aac_mode a signed int and assigning -1 by
> default? Then we don't need two separate fields in the struct.
>
Good idea.
> > + }
> > +
> > + /* Optional indication of VCM internal clock dividing rate select */
> > + ret = fwnode_property_read_u32(dev_fwnode(dev),
> > + "dongwoon,clock-dividing-rate",
> > + &clock_dividing_rate_select);
> > +
> > + if (!ret) {
> > + dw9768->clock_dividing_rate_select_enable = true;
> > + dw9768->clock_dividing_rate = clock_dividing_rate_select;
>
> Ditto.
>
Got it.
> > + }
> > +
> > + /* Optional indication of AAC Timing */
> > + ret = fwnode_property_read_u32(dev_fwnode(dev), "dongwoon,aac-timing",
> > + &aac_timing_select);
> > +
> > + if (!ret) {
> > + dw9768->aact_cnt_select_enable = true;
> > + dw9768->aac_timing = aac_timing_select;
>
> Ditto.
>
Got it.
> > + }
> > +
> > + for (i = 0; i < ARRAY_SIZE(dw9768_supply_names); i++)
> > + dw9768->supplies[i].supply = dw9768_supply_names[i];
> > +
> > + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(dw9768_supply_names),
> > + dw9768->supplies);
> > + if (ret) {
> > + dev_err(dev, "failed to get regulators\n");
> > + return ret;
> > + }
> > +
> > + ret = dw9768_init_controls(dw9768);
> > + if (ret)
> > + goto entity_cleanup;
> > +
> > + dw9768->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> > + dw9768->sd.internal_ops = &dw9768_int_ops;
> > +
> > + ret = media_entity_pads_init(&dw9768->sd.entity, 0, NULL);
> > + if (ret < 0)
> > + goto entity_cleanup;
> > +
> > + dw9768->sd.entity.function = MEDIA_ENT_F_LENS;
> > +
> > + pm_runtime_enable(dev);
> > + if (!pm_runtime_enabled(dev)) {
> > + ret = dw9768_runtime_resume(dev);
> > + if (ret < 0) {
> > + dev_err(dev, "failed to power on: %d\n", ret);
> > + goto entity_cleanup;
> > + }
> > + }
> > +
> > + ret = v4l2_async_register_subdev(&dw9768->sd);
> > + if (ret < 0)
> > + goto entity_cleanup;
> > +
> > + return 0;
> > +
> > +entity_cleanup:
>
> Need to power off if the code above powered on.
>
Thanks for the reminder.
If there is something wrong with runtime PM, actuator is to be powered
on via dw9768_runtime_resume() API.
When actuator sub-device is powered on completely and async registered
successfully, we shall power off it afterwards.
> > + v4l2_ctrl_handler_free(&dw9768->ctrls);
> > + media_entity_cleanup(&dw9768->sd.entity);
> > + return ret;
> > +}
> > +
> > +static int dw9768_remove(struct i2c_client *client)
> > +{
> > + struct v4l2_subdev *sd = i2c_get_clientdata(client);
> > + struct dw9768 *dw9768 = sd_to_dw9768(sd);
> > +
> > + pm_runtime_disable(&client->dev);
>
> First the device must be unregistered from the userspace. Otherwise there
> is a race condition that risks the userspace accessing the device while the
> deinitialization is happening.
>
Fixed in next release by adjusting the sequence of unregistering and
runtime PM disable.
> Best regards,
> Tomasz
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
next prev parent reply other threads:[~2020-05-22 9:27 UTC|newest]
Thread overview: 45+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-05-18 13:27 [V6, 0/2] media: i2c: Add support for DW9768 VCM driver Dongchun Zhu
2020-05-18 13:27 ` Dongchun Zhu
2020-05-18 13:27 ` Dongchun Zhu
2020-05-18 13:27 ` [V6, 1/2] media: dt-bindings: media: i2c: Document DW9768 bindings Dongchun Zhu
2020-05-18 13:27 ` Dongchun Zhu
2020-05-18 13:27 ` Dongchun Zhu
2020-05-18 14:12 ` Tomasz Figa
2020-05-18 14:12 ` Tomasz Figa
2020-05-18 14:12 ` Tomasz Figa
2020-05-18 14:31 ` Rob Herring
2020-05-18 14:31 ` Rob Herring
2020-05-18 14:31 ` Rob Herring
2020-05-19 3:10 ` Dongchun Zhu
2020-05-19 3:10 ` Dongchun Zhu
2020-05-19 3:10 ` Dongchun Zhu
2020-05-18 13:27 ` [V6, 2/2] media: i2c: dw9768: Add DW9768 VCM driver Dongchun Zhu
2020-05-18 13:27 ` Dongchun Zhu
2020-05-18 13:27 ` Dongchun Zhu
2020-05-21 19:51 ` Tomasz Figa
2020-05-21 19:51 ` Tomasz Figa
2020-05-21 19:51 ` Tomasz Figa
2020-05-22 9:26 ` Dongchun Zhu [this message]
2020-05-22 9:26 ` Dongchun Zhu
2020-05-22 9:26 ` Dongchun Zhu
2020-05-25 11:45 ` Tomasz Figa
2020-05-25 11:45 ` Tomasz Figa
2020-05-25 11:45 ` Tomasz Figa
2020-05-27 9:01 ` Dongchun Zhu
2020-05-27 9:01 ` Dongchun Zhu
2020-05-27 9:01 ` Dongchun Zhu
2020-06-01 18:47 ` Tomasz Figa
2020-06-01 18:47 ` Tomasz Figa
2020-06-01 18:47 ` Tomasz Figa
2020-06-04 2:33 ` Dongchun Zhu
2020-06-04 2:33 ` Dongchun Zhu
2020-06-04 2:33 ` Dongchun Zhu
2020-06-04 8:10 ` Sakari Ailus
2020-06-04 8:10 ` Sakari Ailus
2020-06-04 8:10 ` Sakari Ailus
2020-06-05 3:28 ` Dongchun Zhu
2020-06-05 3:28 ` Dongchun Zhu
2020-06-05 3:28 ` Dongchun Zhu
2020-05-27 21:11 ` Sakari Ailus
2020-05-27 21:11 ` Sakari Ailus
2020-05-27 21:11 ` Sakari Ailus
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1590139561.8804.390.camel@mhfsdcap03 \
--to=dongchun.zhu@mediatek.com \
--cc=andriy.shevchenko@linux.intel.com \
--cc=bgolaszewski@baylibre.com \
--cc=bingbu.cao@intel.com \
--cc=devicetree@vger.kernel.org \
--cc=drinkcat@chromium.org \
--cc=linus.walleij@linaro.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-media@vger.kernel.org \
--cc=linux-mediatek@lists.infradead.org \
--cc=louis.kuo@mediatek.com \
--cc=mark.rutland@arm.com \
--cc=matthias.bgg@gmail.com \
--cc=mchehab@kernel.org \
--cc=robh+dt@kernel.org \
--cc=sakari.ailus@linux.intel.com \
--cc=shengnan.wang@mediatek.com \
--cc=sj.huang@mediatek.com \
--cc=srv_heupstream@mediatek.com \
--cc=tfiga@chromium.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.