Re: [PATCH 12/15 v2] iio: accel: kxsd9: Fetch and handle regulators

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 01/09/16 10:44, Linus Walleij wrote:
> This adds supply regulator handling for the VDD and IOVDD inputs
> on the KXSD9 component, makes sure to bring the regulators online
> during probe and disable them on remove or the errorpath.
> 
> Signed-off-by: Linus Walleij <linus.walleij@xxxxxxxxxx>
I'm lazy and tested this without actually checking the regs were
either configured correctly in my board file (unlikely ;) or
actually enabled.  It doesn't break that case :)

Jonathan
> ---
> ChangeLog v1->v2:
> - Rebase on the rest of the series.
> ---
>  drivers/iio/accel/kxsd9.c | 88 +++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 85 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c
> index 8c6a4559256e..dc53f70e616e 100644
> --- a/drivers/iio/accel/kxsd9.c
> +++ b/drivers/iio/accel/kxsd9.c
> @@ -21,6 +21,8 @@
>  #include <linux/module.h>
>  #include <linux/regmap.h>
>  #include <linux/bitops.h>
> +#include <linux/delay.h>
> +#include <linux/regulator/consumer.h>
>  #include <linux/iio/iio.h>
>  #include <linux/iio/sysfs.h>
>  #include <linux/iio/buffer.h>
> @@ -65,10 +67,12 @@
>   * struct kxsd9_state - device related storage
>   * @dev: pointer to the parent device
>   * @map: regmap to the device
> + * @regs: regulators for this device, VDD and IOVDD
>   */
>  struct kxsd9_state {
>  	struct device *dev;
>  	struct regmap *map;
> +	struct regulator_bulk_data regs[2];
>  };
>  
>  #define KXSD9_SCALE_2G "0.011978"
> @@ -81,6 +85,12 @@ static const int kxsd9_micro_scales[4] = { 47853, 35934, 23927, 11978 };
>  
>  #define KXSD9_ZERO_G_OFFSET -2048
>  
> +/*
> + * Regulator names
> + */
> +static const char kxsd9_reg_vdd[] = "vdd";
> +static const char kxsd9_reg_iovdd[] = "iovdd";
> +
>  static int kxsd9_write_scale(struct iio_dev *indio_dev, int micro)
>  {
>  	int ret, i;
> @@ -252,12 +262,69 @@ static int kxsd9_power_up(struct kxsd9_state *st)
>  {
>  	int ret;
>  
> -	ret = regmap_write(st->map, KXSD9_REG_CTRL_B, 0x40);
> +	/* Enable the regulators */
> +	ret = regulator_bulk_enable(ARRAY_SIZE(st->regs), st->regs);
> +	if (ret) {
> +		dev_err(st->dev, "Cannot enable regulators\n");
> +		return ret;
> +	}
> +
> +	/* Power up */
> +	ret = regmap_write(st->map,
> +			   KXSD9_REG_CTRL_B,
> +			   KXSD9_CTRL_B_ENABLE);
>  	if (ret)
>  		return ret;
> -	return regmap_write(st->map, KXSD9_REG_CTRL_C, 0x9b);
> +
> +	/*
> +	 * Set 1000Hz LPF, 2g fullscale, motion wakeup threshold 1g,
> +	 * latched wakeup
> +	 */
> +	ret = regmap_write(st->map,
> +			   KXSD9_REG_CTRL_C,
> +			   KXSD9_CTRL_C_LP_1000HZ |
> +			   KXSD9_CTRL_C_MOT_LEV	|
> +			   KXSD9_CTRL_C_MOT_LAT |
> +			   KXSD9_CTRL_C_FS_2G);
> +	if (ret)
> +		return ret;
> +
> +	/*
> +	 * Power-up time depends on the LPF setting, but typ 15.9 ms, let's
> +	 * set 20 ms to allow for some slack.
> +	 */
> +	msleep(20);
> +
> +	return 0;
>  };
>  
> +static int kxsd9_power_down(struct kxsd9_state *st)
> +{
> +	int ret;
> +
> +	/*
> +	 * Set into low power mode - since there may be more users of the
> +	 * regulators this is the first step of the power saving: it will
> +	 * make sure we conserve power even if there are others users on the
> +	 * regulators.
> +	 */
> +	ret = regmap_update_bits(st->map,
> +				 KXSD9_REG_CTRL_B,
> +				 KXSD9_CTRL_B_ENABLE,
> +				 0);
> +	if (ret)
> +		return ret;
> +
> +	/* Disable the regulators */
> +	ret = regulator_bulk_disable(ARRAY_SIZE(st->regs), st->regs);
> +	if (ret) {
> +		dev_err(st->dev, "Cannot disable regulators\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
>  static const struct iio_info kxsd9_info = {
>  	.read_raw = &kxsd9_read_raw,
>  	.write_raw = &kxsd9_write_raw,
> @@ -292,6 +359,17 @@ int kxsd9_common_probe(struct device *parent,
>  	indio_dev->modes = INDIO_DIRECT_MODE;
>  	indio_dev->available_scan_masks = kxsd9_scan_masks;
>  
> +	/* Fetch and turn on regulators */
> +	st->regs[0].supply = kxsd9_reg_vdd;
> +	st->regs[1].supply = kxsd9_reg_iovdd;
> +	ret = devm_regulator_bulk_get(parent,
> +				      ARRAY_SIZE(st->regs),
> +				      st->regs);
> +	if (ret) {
> +		dev_err(parent, "Cannot get regulators\n");
> +		return ret;
> +	}
> +
>  	kxsd9_power_up(st);
>  
>  	ret = iio_triggered_buffer_setup(indio_dev,
> @@ -300,7 +378,7 @@ int kxsd9_common_probe(struct device *parent,
>  					 NULL);
>  	if (ret) {
>  		dev_err(parent, "triggered buffer setup failed\n");
> -		return ret;
> +		goto err_power_down;
>  	}
>  
>  	ret = iio_device_register(indio_dev);
> @@ -313,6 +391,8 @@ int kxsd9_common_probe(struct device *parent,
>  
>  err_cleanup_buffer:
>  	iio_triggered_buffer_cleanup(indio_dev);
> +err_power_down:
> +	kxsd9_power_down(st);
>  
>  	return ret;
>  }
> @@ -321,9 +401,11 @@ EXPORT_SYMBOL(kxsd9_common_probe);
>  int kxsd9_common_remove(struct device *parent)
>  {
>  	struct iio_dev *indio_dev = dev_get_drvdata(parent);
> +	struct kxsd9_state *st = iio_priv(indio_dev);
>  
>  	iio_triggered_buffer_cleanup(indio_dev);
>  	iio_device_unregister(indio_dev);
> +	kxsd9_power_down(st);
>  
>  	return 0;
>  }
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux