On Wed, Jul 11, 2018 at 12:29:33PM +0000, Jean-Baptiste Maneyrol wrote:
> Hello,
> 
> I really don't like the idea to have regulator handled inside the driver. I 
> know this was done like that before for Nexus 5, but I think now this is 
> something that can be done using dts only.
> Does anyone know if there is a way with dts to handle regulator automatically 
> and prevent the use in the driver? That would be a good idea to search how 
> this handled for other drivers.
> 
> Anyway, you are enforcing regulator use in your code. It doesn't seem the 
> code will work when there is no regulator declared in the dts, which is the 
> case for the majority of configurations. We should at least make it optional.
> 
> Thanks for the contribution.

My understanding of devm_regulator_get_optional() is that a stub
regulator will be returned if one is not configured. See the comment
above regulator_get_optional() for where I got this information.

https://elixir.bootlin.com/linux/v4.17/source/drivers/regulator/core.c#L1750

I agree that it would be better if this could be handled exclusively in
dts if possible, although I'm not sure how. I looked at other drivers
and commits from the last year or so and this appears to be the current
recommended approach. I'm open to other approaches to doing this.

Brian


>
> 
> From: Brian Masney <masn...@onstation.org>
> Sent: Wednesday, July 11, 2018 03:09
> To: ji...@kernel.org; robh...@kernel.org; mark.rutl...@arm.com; 
> andy.gr...@linaro.org; david.br...@linaro.org; linux-...@vger.kernel.org; 
> devicet...@vger.kernel.org; linux-kernel@vger.kernel.org; 
> linux-arm-...@vger.kernel.org; linux-...@vger.kernel.org
> Cc: jonat...@marek.ca; Jean-Baptiste Maneyrol; knaac...@gmx.de; 
> l...@metafoo.de; pme...@pmeerw.net; mke...@xevo.com; 
> fischerdougl...@gmail.com; bs...@kde.org; ctatlo...@gmail.com; 
> masn...@onstation.org
> Subject: [PATCH 2/3] iio: imu: mpu6050: add support for regulator framework
>   
> 
> CAUTION: This email originated from outside of the organization. Please make 
> sure the sender is who they say they are and do not click links or open 
> attachments unless you recognize the sender and know the content is safe.
> 
> 
> This patch adds support for the regulator framework to the mpu6050
> driver.
> 
> Signed-off-by: Brian Masney <masn...@onstation.org>
> Signed-off-by: Jonathan Marek <jonat...@marek.ca>
> ---
> This is a variation of Jonathan Marek's patch from postmarketOS
> https://gitlab.com/postmarketOS/linux-postmarketos/commit/b8ad1ec1859c8bbcbce94944b3f4dd68f8f9fc37
> with the following changes:
> 
> - Stripped out 6515 variant code. (See my previous patch in this series)
> - Add the regulator to the mpu core instead of only the i2c variant.
> - Add error handling.
> - Release the regulator on suspend, device remove, etc.
> - Device tree documentation.
> 
>  .../bindings/iio/imu/inv_mpu6050.txt          |  1 +
>  drivers/iio/imu/inv_mpu6050/inv_mpu_core.c    | 57 +++++++++++++++++--
>  drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c     |  2 +-
>  drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h     |  3 +
>  drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c     |  9 +++
>  5 files changed, 66 insertions(+), 6 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt 
> b/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt
> index b7def51c8ad9..d39907b12a46 100644
> --- a/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt
> +++ b/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt
> @@ -21,6 +21,7 @@ Required properties:
>    bindings.
> 
>  Optional properties:
> + - vddio-supply: regulator phandle for VDDIO supply
>   - mount-matrix: an optional 3x3 mounting rotation matrix
>   - i2c-gate node.  These devices also support an auxiliary i2c bus.  This is
>     simple enough to be described using the i2c-gate binding. See
> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c 
> b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
> index 12c1b9507007..ec276b7bcc69 100644
> --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
> @@ -23,6 +23,7 @@
>  #include <linux/iio/iio.h>
>  #include <linux/acpi.h>
>  #include <linux/platform_device.h>
> +#include <linux/regulator/consumer.h>
>  #include "inv_mpu_iio.h"
> 
>  /*
> @@ -926,6 +927,19 @@ static int inv_check_and_setup_chip(struct 
> inv_mpu6050_state *st)
>         return result;
>  }
> 
> +static int inv_mpu_core_enable_regulator(struct inv_mpu6050_state *st)
> +{
> +       int result;
> +
> +       result = regulator_enable(st->vddio_supply);
> +       if (result == 0) {
> +               /* Give the device a little bit of time to start up. */
> +               usleep_range(35000, 70000);
> +       }
> +
> +       return result;
> +}
> +
>  int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
>                 int (*inv_mpu_bus_setup)(struct iio_dev *), int chip_type)
>  {
> @@ -990,15 +1004,28 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, 
> const char *name,
>                 return -EINVAL;
>         }
> 
> +       st->vddio_supply = devm_regulator_get_optional(dev, "vddio");
> +       if (IS_ERR(st->vddio_supply)) {
> +               if (PTR_ERR(st->vddio_supply) != -EPROBE_DEFER)
> +                       dev_err(dev, "Failed to get vddio regulator %d\n",
> +                               (int)PTR_ERR(st->vddio_supply));
> +
> +               return PTR_ERR(st->vddio_supply);
> +       }
> +
> +       result = inv_mpu_core_enable_regulator(st);
> +       if (result)
> +               return result;
> +
>         /* power is turned on inside check chip type*/
>         result = inv_check_and_setup_chip(st);
>         if (result)
> -               return result;
> +               goto out_disable_regulator;
> 
>         result = inv_mpu6050_init_config(indio_dev);
>         if (result) {
>                 dev_err(dev, "Could not initialize device.\n");
> -               return result;
> +               goto out_disable_regulator;
>         }
> 
>         if (inv_mpu_bus_setup)
> @@ -1023,24 +1050,34 @@ int inv_mpu_core_probe(struct regmap *regmap, int 
> irq, const char *name,
>                                                  NULL);
>         if (result) {
>                 dev_err(dev, "configure buffer fail %d\n", result);
> -               return result;
> +               goto out_disable_regulator;
>         }
>         result = inv_mpu6050_probe_trigger(indio_dev, irq_type);
>         if (result) {
>                 dev_err(dev, "trigger probe fail %d\n", result);
> -               return result;
> +               goto out_disable_regulator;
>         }
> 
>         result = devm_iio_device_register(dev, indio_dev);
>         if (result) {
>                 dev_err(dev, "IIO register fail %d\n", result);
> -               return result;
> +               goto out_disable_regulator;
>         }
> 
>         return 0;
> +
> +out_disable_regulator:
> +       regulator_disable(st->vddio_supply);
> +       return result;
> +
>  }
>  EXPORT_SYMBOL_GPL(inv_mpu_core_probe);
> 
> +int inv_mpu_core_remove(struct inv_mpu6050_state *st)
> +{
> +       return regulator_disable(st->vddio_supply);
> +}
> +
>  #ifdef CONFIG_PM_SLEEP
> 
>  static int inv_mpu_resume(struct device *dev)
> @@ -1050,6 +1087,11 @@ static int inv_mpu_resume(struct device *dev)
> 
>         mutex_lock(&st->lock);
>         result = inv_mpu6050_set_power_itg(st, true);
> +       if (result)
> +               goto out_unlock;
> +
> +       result = inv_mpu_core_enable_regulator(st);
> +out_unlock:
>         mutex_unlock(&st->lock);
> 
>         return result;
> @@ -1062,6 +1104,11 @@ static int inv_mpu_suspend(struct device *dev)
> 
>         mutex_lock(&st->lock);
>         result = inv_mpu6050_set_power_itg(st, false);
> +       if (result)
> +               goto out_unlock;
> +
> +       result = regulator_disable(st->vddio_supply);
> +out_unlock:
>         mutex_unlock(&st->lock);
> 
>         return result;
> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c 
> b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
> index dd758e3d403d..ce227038c61c 100644
> --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
> @@ -164,7 +164,7 @@ static int inv_mpu_remove(struct i2c_client *client)
>                 i2c_mux_del_adapters(st->muxc);
>         }
> 
> -       return 0;
> +       return inv_mpu_core_remove(st);
>  }
> 
>  /*
> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h 
> b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
> index e69a59659dbc..0289615a6135 100644
> --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
> @@ -129,6 +129,7 @@ struct inv_mpu6050_hw {
>   *  @chip_period:      chip internal period estimation (~1kHz).
>   *  @it_timestamp:     timestamp from previous interrupt.
>   *  @data_timestamp:   timestamp for next data sample.
> + *  @vddio_supply      voltage regulator for the chip.
>   */
>  struct inv_mpu6050_state {
>         struct mutex lock;
> @@ -149,6 +150,7 @@ struct inv_mpu6050_state {
>         s64 chip_period;
>         s64 it_timestamp;
>         s64 data_timestamp;
> +       struct regulator *vddio_supply;
>  };
> 
>  /*register and associated bit definition*/
> @@ -321,4 +323,5 @@ int inv_mpu_acpi_create_mux_client(struct i2c_client 
> *client);
>  void inv_mpu_acpi_delete_mux_client(struct i2c_client *client);
>  int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
>                 int (*inv_mpu_bus_setup)(struct iio_dev *), int chip_type);
> +int inv_mpu_core_remove(struct inv_mpu6050_state *st);
>  extern const struct dev_pm_ops inv_mpu_pmops;
> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c 
> b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
> index 227f50afff22..fce935f8f1e4 100644
> --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
> @@ -70,6 +70,14 @@ static int inv_mpu_probe(struct spi_device *spi)
>                                   inv_mpu_i2c_disable, chip_type);
>  }
> 
> +static int inv_mpu_remove(struct spi_device *spi)
> +{
> +       struct iio_dev *indio_dev = spi_get_drvdata(spi);
> +       struct inv_mpu6050_state *st = iio_priv(indio_dev);
> +
> +       return inv_mpu_core_remove(st);
> +}
> +
>  /*
>   * device id table is used to identify what device can be
>   * supported by this driver
> @@ -94,6 +102,7 @@ MODULE_DEVICE_TABLE(acpi, inv_acpi_match);
> 
>  static struct spi_driver inv_mpu_driver = {
>         .probe          =       inv_mpu_probe,
> +       .remove         =       inv_mpu_remove,
>         .id_table       =       inv_mpu_id,
>         .driver = {
>                 .acpi_match_table = ACPI_PTR(inv_acpi_match),
> --
> 2.17.1
> 
>     

Reply via email to