Re: [PATCH 2/5] gnss: sirf: power on logic for devices without wakeup signal

From: Johan Hovold
Date: Wed Dec 05 2018 - 10:01:20 EST


On Sun, Nov 18, 2018 at 10:57:58PM +0100, Andreas Kemnade wrote:
> Some Wi2Wi devices do not have a wakeup output, so device state can
> only be indirectly detected by looking whether there is communitcation
> over the serial lines.
> Additionally it checks for the initial state of the device during
> probing to ensure it is off.
> Timeout values need to be increased, because the reaction on serial line
> is slower and are in line with previous patches by
> Neil Brown <neilb@xxxxxxx> and H. Nikolaus Schaller <hns@xxxxxxxxxxxxx>.
>
> Signed-off-by: Andreas Kemnade <andreas@xxxxxxxxxxxx>
> ---
> drivers/gnss/sirf.c | 97 +++++++++++++++++++++++++++++++++++------------------
> 1 file changed, 65 insertions(+), 32 deletions(-)
>
> diff --git a/drivers/gnss/sirf.c b/drivers/gnss/sirf.c
> index b5efbb062316..6a0e5c0a2d62 100644
> --- a/drivers/gnss/sirf.c
> +++ b/drivers/gnss/sirf.c
> @@ -22,8 +22,8 @@
>
> #define SIRF_BOOT_DELAY 500
> #define SIRF_ON_OFF_PULSE_TIME 100
> -#define SIRF_ACTIVATE_TIMEOUT 200
> -#define SIRF_HIBERNATE_TIMEOUT 200
> +#define SIRF_ACTIVATE_TIMEOUT 1000
> +#define SIRF_HIBERNATE_TIMEOUT 1000

We shouldn't increase the timeouts for the general case where we have
wakeup connected.

> struct sirf_data {
> struct gnss_device *gdev;
> @@ -45,26 +45,14 @@ static int sirf_open(struct gnss_device *gdev)
> int ret;
>
> data->opened = true;
> - ret = serdev_device_open(serdev);
> - if (ret)
> - return ret;
> -
> - serdev_device_set_baudrate(serdev, data->speed);
> - serdev_device_set_flow_control(serdev, false);

And also here, I think we shouldn't change the general case (wakeup
connected) unnecessarily. Currently user space can request the receiver
to remain powered, while not keeping the port open unnecessarily.

>
> ret = pm_runtime_get_sync(&serdev->dev);
> if (ret < 0) {
> dev_err(&gdev->dev, "failed to runtime resume: %d\n", ret);
> pm_runtime_put_noidle(&serdev->dev);
> data->opened = false;
> - goto err_close;
> }
>
> - return 0;
> -
> -err_close:
> - serdev_device_close(serdev);
> -
> return ret;
> }
>
> @@ -73,8 +61,6 @@ static void sirf_close(struct gnss_device *gdev)
> struct sirf_data *data = gnss_get_drvdata(gdev);
> struct serdev_device *serdev = data->serdev;
>
> - serdev_device_close(serdev);
> -
> pm_runtime_put(&serdev->dev);
> data->opened = false;
> }
> @@ -109,6 +95,11 @@ static int sirf_receive_buf(struct serdev_device *serdev,
> struct sirf_data *data = serdev_device_get_drvdata(serdev);
> struct gnss_device *gdev = data->gdev;
>
> + if ((!data->wakeup) && (!data->active)) {

You have superfluous parenthesis like the above throughout the series.

> + data->active = 1;

active is bool, so use "true".

> + wake_up_interruptible(&data->power_wait);
> + }
> +
> /*
> * we might come here everytime when runtime is resumed
> * and data is received. Two cases are possible
> @@ -149,6 +140,25 @@ static int sirf_wait_for_power_state(struct sirf_data *data, bool active,
> {
> int ret;
>
> + /* no wakeup pin, success condition is that
> + * no byte comes in in the period
> + */

Multiline comment style needs to be fixed throughout. Also use sentence
case and periods where appropriate.

> + if ((!data->wakeup) && (!active) && (data->active)) {
> + /* some bytes might come, so sleep a bit first */
> + msleep(timeout);

This changes the semantics of the functions and effectively doubles the
requested timeout.

> + data->active = false;
> + ret = wait_event_interruptible_timeout(data->power_wait,
> + data->active == true, msecs_to_jiffies(timeout));
> +
> + if (ret < 0)
> + return ret;
> +
> + /* we are still getting woken up -> timeout */
> + if (ret > 0)
> + return -ETIMEDOUT;
> + return 0;
> + }
> +
> ret = wait_event_interruptible_timeout(data->power_wait,
> data->active == active, msecs_to_jiffies(timeout));
> if (ret < 0)
> @@ -203,21 +213,48 @@ static int sirf_set_active(struct sirf_data *data, bool active)
> static int sirf_runtime_suspend(struct device *dev)
> {
> struct sirf_data *data = dev_get_drvdata(dev);
> + int ret;
>
> if (!data->on_off)
> return regulator_disable(data->vcc);

Missing newline.

> + ret = sirf_set_active(data, false);
>

Superfluous newline.

> - return sirf_set_active(data, false);
> + if (ret)
> + dev_err(dev, "failed to deactivate");

Missing '\n'.

> +
> + /* we should close it anyways, so the following receptions
> + * will not run into the empty
> + */

Not sure what you mean here, please rephrase.

> + serdev_device_close(data->serdev);
> + return 0;
> }
>
> static int sirf_runtime_resume(struct device *dev)
> {
> + int ret;

Please, place after the next declaration (reverse xmas style).

> struct sirf_data *data = dev_get_drvdata(dev);

Missing newline.

> + ret = serdev_device_open(data->serdev);
> + if (ret)
> + return ret;
>
> - if (!data->on_off)
> - return regulator_enable(data->vcc);
> + serdev_device_set_baudrate(data->serdev, data->speed);
> + serdev_device_set_flow_control(data->serdev, false);
> +
> + if (!data->on_off) {
> + ret = regulator_enable(data->vcc);
> + if (ret)
> + goto err_close_serdev;
> + }

Newline.

> + ret = sirf_set_active(data, true);
> +
> + if (!ret)
> + return 0;

Add an error label instead, and return 0 unconditionally in the success
path.

>
> - return sirf_set_active(data, true);
> + if (!data->on_off)
> + regulator_disable(data->vcc);
> +err_close_serdev:
> + serdev_device_close(data->serdev);
> + return ret;
> }
>
> static int __maybe_unused sirf_suspend(struct device *dev)
> @@ -311,18 +348,6 @@ static int sirf_probe(struct serdev_device *serdev)
> if (data->on_off) {
> data->wakeup = devm_gpiod_get_optional(dev, "sirf,wakeup",
> GPIOD_IN);
> - if (IS_ERR(data->wakeup))
> - goto err_put_device;

You still want to check for errors here.

> -
> - /*
> - * Configurations where WAKEUP has been left not connected,
> - * are currently not supported.
> - */
> - if (!data->wakeup) {
> - dev_err(dev, "no wakeup gpio specified\n");
> - ret = -ENODEV;
> - goto err_put_device;
> - }
> }
>
> if (data->wakeup) {
> @@ -352,6 +377,13 @@ static int sirf_probe(struct serdev_device *serdev)
> if (IS_ENABLED(CONFIG_PM)) {
> pm_runtime_set_suspended(dev); /* clear runtime_error flag */
> pm_runtime_enable(dev);
> + /* device might be enabled at boot, so lets first enable it,
> + * then disable it to bring it into a clear state
> + */
> + ret = pm_runtime_get_sync(dev);
> + if (ret)
> + goto err_disable_rpm;
> + pm_runtime_put(dev);
> } else {
> ret = sirf_runtime_resume(dev);
> if (ret < 0)
> @@ -401,6 +433,7 @@ static const struct of_device_id sirf_of_match[] = {
> { .compatible = "linx,r4" },
> { .compatible = "wi2wi,w2sg0008i" },
> { .compatible = "wi2wi,w2sg0084i" },
> + { .compatible = "wi2wi,w2sg0004" },

Keep the entries sorted.

> {},
> };
> MODULE_DEVICE_TABLE(of, sirf_of_match);

Johan