Re: [PATCH v4 3/6] iio: imu: kmx61: Add PM runtime support

2014-12-15 Thread Daniel Baluta
On Mon, Dec 15, 2014 at 12:55 AM, Hartmut Knaack  wrote:
> Daniel Baluta schrieb am 03.12.2014 um 14:31:
>> By default both sensors are ACTIVE, in this way the driver
>> will work even if CONFIG_PM_RUNTIME is not selected.
>>
> Since kmx61_set_power_state() can return error codes, wouldn't it be better to
> handle them (as long as you are not using it in an error handler)?
> Thanks,

That's correct I will send a patch asap.

Daniel.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v4 3/6] iio: imu: kmx61: Add PM runtime support

2014-12-14 Thread Hartmut Knaack
Daniel Baluta schrieb am 03.12.2014 um 14:31:
> By default both sensors are ACTIVE, in this way the driver
> will work even if CONFIG_PM_RUNTIME is not selected.
> 
Since kmx61_set_power_state() can return error codes, wouldn't it be better to
handle them (as long as you are not using it in an error handler)?
Thanks,

Hartmut
> Signed-off-by: Daniel Baluta 
> ---
>  drivers/iio/imu/kmx61.c | 114 
> +++-
>  1 file changed, 112 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c
> index 893f7c8..7536043 100644
> --- a/drivers/iio/imu/kmx61.c
> +++ b/drivers/iio/imu/kmx61.c
> @@ -15,6 +15,8 @@
>  #include 
>  #include 
>  #include 
> +#include 
> +#include 
>  #include 
>  #include 
>  
> @@ -69,6 +71,8 @@
>  #define KMX61_ACC_ODR_MASK   0x0F
>  #define KMX61_MAG_ODR_MASK   0xF0
>  
> +#define KMX61_SLEEP_DELAY_MS 2000
> +
>  #define KMX61_CHIP_ID0x12
>  
>  /* KMX61 devices */
> @@ -85,6 +89,10 @@ struct kmx61_data {
>   bool acc_stby;
>   bool mag_stby;
>  
> + /* power state */
> + bool acc_ps;
> + bool mag_ps;
> +
>   /* config bits */
>   u8 range;
>   u8 odr_bits;
> @@ -457,6 +465,58 @@ static int kmx61_chip_init(struct kmx61_data *data)
>   return 0;
>  }
>  
> +/**
> + * kmx61_set_power_state() - set power state for kmx61 @device
> + * @data - kmx61 device private pointer
> + * @on - power state to be set for @device
> + * @device - bitmask indicating device for which @on state needs to be set
> + *
> + * Notice that when ACC power state needs to be set to ON and MAG is in
> + * OPERATION then we know that kmx61_runtime_resume was already called
> + * so we must set ACC OPERATION mode here. The same happens when MAG power
> + * state needs to be set to ON and ACC is in OPERATION.
> + */
> +static int kmx61_set_power_state(struct kmx61_data *data, bool on, u8 device)
> +{
> +#ifdef CONFIG_PM_RUNTIME
> + int ret;
> +
> + if (device & KMX61_ACC) {
> + if (on && !data->acc_ps && !data->mag_stby) {
> + ret = kmx61_set_mode(data, 0, KMX61_ACC, true);
> + if (ret < 0)
> + return ret;
> + }
> + data->acc_ps = on;
> + }
> + if (device & KMX61_MAG) {
> + if (on && !data->mag_ps && !data->acc_stby) {
> + ret = kmx61_set_mode(data, 0, KMX61_MAG, true);
> + if (ret < 0)
> + return ret;
> + }
> + data->mag_ps = on;
> + }
> +
> + if (on) {
> + ret = pm_runtime_get_sync(&data->client->dev);
> + } else {
> + pm_runtime_mark_last_busy(&data->client->dev);
> + ret = pm_runtime_put_autosuspend(&data->client->dev);
> + }
> + if (ret < 0) {
> + dev_err(&data->client->dev,
> + "Failed: kmx61_set_power_state for %d, ret %d\n",
> + on, ret);
> + if (on)
> + pm_runtime_put_noidle(&data->client->dev);
> +
> + return ret;
> + }
> +#endif
> + return 0;
> +}
> +
>  static int kmx61_read_measurement(struct kmx61_data *data, u8 base, u8 
> offset)
>  {
>   int ret;
> @@ -491,13 +551,16 @@ static int kmx61_read_raw(struct iio_dev *indio_dev,
>   }
>   mutex_lock(&data->lock);
>  
> + kmx61_set_power_state(data, true, chan->address);
>   ret = kmx61_read_measurement(data, base_reg, chan->scan_index);
>   if (ret < 0) {
> + kmx61_set_power_state(data, false, chan->address);
>   mutex_unlock(&data->lock);
>   return ret;
>   }
>   *val = sign_extend32(ret >> chan->scan_type.shift,
>chan->scan_type.realbits - 1);
> + kmx61_set_power_state(data, false, chan->address);
>  
>   mutex_unlock(&data->lock);
>   return IIO_VAL_INT;
> @@ -693,12 +756,22 @@ static int kmx61_probe(struct i2c_client *client,
>   ret = iio_device_register(data->mag_indio_dev);
>   if (ret < 0) {
>   dev_err(&client->dev, "Failed to register mag iio device\n");
> - goto err_iio_unregister;
> + goto err_iio_unregister_acc;
>   }
>  
> + ret = pm_runtime_set_active(&client->dev);
> + if (ret < 0)
> + goto err_iio_unregister_mag;
> +
> + pm_runtime_enable(&client->dev);
> + pm_runtime_set_autosuspend_delay(&client->dev, KMX61_SLEEP_DELAY_MS);
> + pm_runtime_use_autosuspend(&client->dev);
> +
>   return 0;
>  
> -err_iio_unregister:
> +err_iio_unregister_mag:
> + iio_device_unregister(data->mag_indio_dev);
> +err_iio_unregister_acc:
>   iio_device_unregister(data->acc_indio_dev);
>  err_chip_uninit:
>   kmx61_set_mode(data, KMX61_ALL_STBY, KMX61

Re: [PATCH v4 3/6] iio: imu: kmx61: Add PM runtime support

2014-12-12 Thread Jonathan Cameron
On 03/12/14 13:31, Daniel Baluta wrote:
> By default both sensors are ACTIVE, in this way the driver
> will work even if CONFIG_PM_RUNTIME is not selected.
> 
> Signed-off-by: Daniel Baluta 
Applied to the togreg branch of iio.git

Thanks,

Jonathan
> ---
>  drivers/iio/imu/kmx61.c | 114 
> +++-
>  1 file changed, 112 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c
> index 893f7c8..7536043 100644
> --- a/drivers/iio/imu/kmx61.c
> +++ b/drivers/iio/imu/kmx61.c
> @@ -15,6 +15,8 @@
>  #include 
>  #include 
>  #include 
> +#include 
> +#include 
>  #include 
>  #include 
>  
> @@ -69,6 +71,8 @@
>  #define KMX61_ACC_ODR_MASK   0x0F
>  #define KMX61_MAG_ODR_MASK   0xF0
>  
> +#define KMX61_SLEEP_DELAY_MS 2000
> +
>  #define KMX61_CHIP_ID0x12
>  
>  /* KMX61 devices */
> @@ -85,6 +89,10 @@ struct kmx61_data {
>   bool acc_stby;
>   bool mag_stby;
>  
> + /* power state */
> + bool acc_ps;
> + bool mag_ps;
> +
>   /* config bits */
>   u8 range;
>   u8 odr_bits;
> @@ -457,6 +465,58 @@ static int kmx61_chip_init(struct kmx61_data *data)
>   return 0;
>  }
>  
> +/**
> + * kmx61_set_power_state() - set power state for kmx61 @device
> + * @data - kmx61 device private pointer
> + * @on - power state to be set for @device
> + * @device - bitmask indicating device for which @on state needs to be set
> + *
> + * Notice that when ACC power state needs to be set to ON and MAG is in
> + * OPERATION then we know that kmx61_runtime_resume was already called
> + * so we must set ACC OPERATION mode here. The same happens when MAG power
> + * state needs to be set to ON and ACC is in OPERATION.
> + */
> +static int kmx61_set_power_state(struct kmx61_data *data, bool on, u8 device)
> +{
> +#ifdef CONFIG_PM_RUNTIME
> + int ret;
> +
> + if (device & KMX61_ACC) {
> + if (on && !data->acc_ps && !data->mag_stby) {
> + ret = kmx61_set_mode(data, 0, KMX61_ACC, true);
> + if (ret < 0)
> + return ret;
> + }
> + data->acc_ps = on;
> + }
> + if (device & KMX61_MAG) {
> + if (on && !data->mag_ps && !data->acc_stby) {
> + ret = kmx61_set_mode(data, 0, KMX61_MAG, true);
> + if (ret < 0)
> + return ret;
> + }
> + data->mag_ps = on;
> + }
> +
> + if (on) {
> + ret = pm_runtime_get_sync(&data->client->dev);
> + } else {
> + pm_runtime_mark_last_busy(&data->client->dev);
> + ret = pm_runtime_put_autosuspend(&data->client->dev);
> + }
> + if (ret < 0) {
> + dev_err(&data->client->dev,
> + "Failed: kmx61_set_power_state for %d, ret %d\n",
> + on, ret);
> + if (on)
> + pm_runtime_put_noidle(&data->client->dev);
> +
> + return ret;
> + }
> +#endif
> + return 0;
> +}
> +
>  static int kmx61_read_measurement(struct kmx61_data *data, u8 base, u8 
> offset)
>  {
>   int ret;
> @@ -491,13 +551,16 @@ static int kmx61_read_raw(struct iio_dev *indio_dev,
>   }
>   mutex_lock(&data->lock);
>  
> + kmx61_set_power_state(data, true, chan->address);
>   ret = kmx61_read_measurement(data, base_reg, chan->scan_index);
>   if (ret < 0) {
> + kmx61_set_power_state(data, false, chan->address);
>   mutex_unlock(&data->lock);
>   return ret;
>   }
>   *val = sign_extend32(ret >> chan->scan_type.shift,
>chan->scan_type.realbits - 1);
> + kmx61_set_power_state(data, false, chan->address);
>  
>   mutex_unlock(&data->lock);
>   return IIO_VAL_INT;
> @@ -693,12 +756,22 @@ static int kmx61_probe(struct i2c_client *client,
>   ret = iio_device_register(data->mag_indio_dev);
>   if (ret < 0) {
>   dev_err(&client->dev, "Failed to register mag iio device\n");
> - goto err_iio_unregister;
> + goto err_iio_unregister_acc;
>   }
>  
> + ret = pm_runtime_set_active(&client->dev);
> + if (ret < 0)
> + goto err_iio_unregister_mag;
> +
> + pm_runtime_enable(&client->dev);
> + pm_runtime_set_autosuspend_delay(&client->dev, KMX61_SLEEP_DELAY_MS);
> + pm_runtime_use_autosuspend(&client->dev);
> +
>   return 0;
>  
> -err_iio_unregister:
> +err_iio_unregister_mag:
> + iio_device_unregister(data->mag_indio_dev);
> +err_iio_unregister_acc:
>   iio_device_unregister(data->acc_indio_dev);
>  err_chip_uninit:
>   kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true);
> @@ -709,6 +782,10 @@ static int kmx61_remove(struct i2c_client *client)
>  {
> 

[PATCH v4 3/6] iio: imu: kmx61: Add PM runtime support

2014-12-03 Thread Daniel Baluta
By default both sensors are ACTIVE, in this way the driver
will work even if CONFIG_PM_RUNTIME is not selected.

Signed-off-by: Daniel Baluta 
---
 drivers/iio/imu/kmx61.c | 114 +++-
 1 file changed, 112 insertions(+), 2 deletions(-)

diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c
index 893f7c8..7536043 100644
--- a/drivers/iio/imu/kmx61.c
+++ b/drivers/iio/imu/kmx61.c
@@ -15,6 +15,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 
@@ -69,6 +71,8 @@
 #define KMX61_ACC_ODR_MASK 0x0F
 #define KMX61_MAG_ODR_MASK 0xF0
 
+#define KMX61_SLEEP_DELAY_MS   2000
+
 #define KMX61_CHIP_ID  0x12
 
 /* KMX61 devices */
@@ -85,6 +89,10 @@ struct kmx61_data {
bool acc_stby;
bool mag_stby;
 
+   /* power state */
+   bool acc_ps;
+   bool mag_ps;
+
/* config bits */
u8 range;
u8 odr_bits;
@@ -457,6 +465,58 @@ static int kmx61_chip_init(struct kmx61_data *data)
return 0;
 }
 
+/**
+ * kmx61_set_power_state() - set power state for kmx61 @device
+ * @data - kmx61 device private pointer
+ * @on - power state to be set for @device
+ * @device - bitmask indicating device for which @on state needs to be set
+ *
+ * Notice that when ACC power state needs to be set to ON and MAG is in
+ * OPERATION then we know that kmx61_runtime_resume was already called
+ * so we must set ACC OPERATION mode here. The same happens when MAG power
+ * state needs to be set to ON and ACC is in OPERATION.
+ */
+static int kmx61_set_power_state(struct kmx61_data *data, bool on, u8 device)
+{
+#ifdef CONFIG_PM_RUNTIME
+   int ret;
+
+   if (device & KMX61_ACC) {
+   if (on && !data->acc_ps && !data->mag_stby) {
+   ret = kmx61_set_mode(data, 0, KMX61_ACC, true);
+   if (ret < 0)
+   return ret;
+   }
+   data->acc_ps = on;
+   }
+   if (device & KMX61_MAG) {
+   if (on && !data->mag_ps && !data->acc_stby) {
+   ret = kmx61_set_mode(data, 0, KMX61_MAG, true);
+   if (ret < 0)
+   return ret;
+   }
+   data->mag_ps = on;
+   }
+
+   if (on) {
+   ret = pm_runtime_get_sync(&data->client->dev);
+   } else {
+   pm_runtime_mark_last_busy(&data->client->dev);
+   ret = pm_runtime_put_autosuspend(&data->client->dev);
+   }
+   if (ret < 0) {
+   dev_err(&data->client->dev,
+   "Failed: kmx61_set_power_state for %d, ret %d\n",
+   on, ret);
+   if (on)
+   pm_runtime_put_noidle(&data->client->dev);
+
+   return ret;
+   }
+#endif
+   return 0;
+}
+
 static int kmx61_read_measurement(struct kmx61_data *data, u8 base, u8 offset)
 {
int ret;
@@ -491,13 +551,16 @@ static int kmx61_read_raw(struct iio_dev *indio_dev,
}
mutex_lock(&data->lock);
 
+   kmx61_set_power_state(data, true, chan->address);
ret = kmx61_read_measurement(data, base_reg, chan->scan_index);
if (ret < 0) {
+   kmx61_set_power_state(data, false, chan->address);
mutex_unlock(&data->lock);
return ret;
}
*val = sign_extend32(ret >> chan->scan_type.shift,
 chan->scan_type.realbits - 1);
+   kmx61_set_power_state(data, false, chan->address);
 
mutex_unlock(&data->lock);
return IIO_VAL_INT;
@@ -693,12 +756,22 @@ static int kmx61_probe(struct i2c_client *client,
ret = iio_device_register(data->mag_indio_dev);
if (ret < 0) {
dev_err(&client->dev, "Failed to register mag iio device\n");
-   goto err_iio_unregister;
+   goto err_iio_unregister_acc;
}
 
+   ret = pm_runtime_set_active(&client->dev);
+   if (ret < 0)
+   goto err_iio_unregister_mag;
+
+   pm_runtime_enable(&client->dev);
+   pm_runtime_set_autosuspend_delay(&client->dev, KMX61_SLEEP_DELAY_MS);
+   pm_runtime_use_autosuspend(&client->dev);
+
return 0;
 
-err_iio_unregister:
+err_iio_unregister_mag:
+   iio_device_unregister(data->mag_indio_dev);
+err_iio_unregister_acc:
iio_device_unregister(data->acc_indio_dev);
 err_chip_uninit:
kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true);
@@ -709,6 +782,10 @@ static int kmx61_remove(struct i2c_client *client)
 {
struct kmx61_data *data = i2c_get_clientdata(client);
 
+   pm_runtime_disable(&client->dev);
+   pm_runtime_set_suspended(&client->dev);
+   pm_runtime_put_noidle(&client->dev);
+
iio_device_unregister(data->acc_indio_dev);