From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
To: Jonathan Cameron <jic23@kernel.org>,
Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Cc: linux-iio@vger.kernel.org
Subject: Re: [PATCH 3/6] iio: accel: kxcjk-1013: support runtime pm
Date: Tue, 22 Jul 2014 03:23:09 +0200 [thread overview]
Message-ID: <53CDBCFD.9090702@intel.com> (raw)
In-Reply-To: <53CBE22A.3050401@kernel.org>
On 7/20/2014 5:37 PM, Jonathan Cameron wrote:
> On 17/07/14 01:42, Srinivas Pandruvada wrote:
>> In an effort to improve raw read performance and at the same time enter
>> low power state at every possible chance.
>> For raw reads, it will keep the system powered on for a user specified
>> max time, this will help read multiple samples without power on/off
>> sequence.
>> When runtime pm is not enabled, then it fallbacks to current scheme
>> of on/off after each read.
>>
>> Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
> I'm happy with what you have here, but really don't feel confident enough
> on the runtime_pm side of things to take it without someone with more
> experience of that taking a quick look at it.
>
> Hence, I've cc'd Rafael. Rafael, if you don't have time to look at this
> feel free to say so and I'll rely on the docs rather than experience.
Well, quite frankly, that'd take me quite some time to review as I'm not
familiar with the driver, so I'm afraid I can't promise any reasonable
time frame.
Rafael
>> ---
>> drivers/iio/accel/kxcjk-1013.c | 198
>> +++++++++++++++++++++++++++++++++--------
>> 1 file changed, 160 insertions(+), 38 deletions(-)
>>
>> diff --git a/drivers/iio/accel/kxcjk-1013.c
>> b/drivers/iio/accel/kxcjk-1013.c
>> index bff5161..4912143 100644
>> --- a/drivers/iio/accel/kxcjk-1013.c
>> +++ b/drivers/iio/accel/kxcjk-1013.c
>> @@ -21,6 +21,8 @@
>> #include <linux/string.h>
>> #include <linux/acpi.h>
>> #include <linux/gpio/consumer.h>
>> +#include <linux/pm.h>
>> +#include <linux/pm_runtime.h>
>> #include <linux/iio/iio.h>
>> #include <linux/iio/sysfs.h>
>> #include <linux/iio/buffer.h>
>> @@ -71,15 +73,21 @@
>> #define KXCJK1013_DATA_MASK_12_BIT 0x0FFF
>> #define KXCJK1013_MAX_STARTUP_TIME_US 100000
>>
>> +#define KXCJK1013_SLEEP_DELAY_MS 2000
>> +static int kxcjk1013_power_off_delay_ms = KXCJK1013_SLEEP_DELAY_MS;
>> +module_param(kxcjk1013_power_off_delay_ms, int, 0644);
>> +MODULE_PARM_DESC(kxcjk1013_power_off_delay_ms,
>> + "KXCJK1013 accelerometer power of delay in milli seconds.");
>> +
>> struct kxcjk1013_data {
>> struct i2c_client *client;
>> struct iio_trigger *trig;
>> bool trig_mode;
>> struct mutex mutex;
>> s16 buffer[8];
>> - int power_state;
>> u8 odr_bits;
>> bool active_high_intr;
>> + bool trigger_on;
>> };
>>
>> enum kxcjk1013_axis {
>> @@ -138,6 +146,25 @@ static int kxcjk1013_set_mode(struct
>> kxcjk1013_data *data,
>> return 0;
>> }
>>
>> +static int kxcjk1013_get_mode(struct kxcjk1013_data *data,
>> + enum kxcjk1013_mode *mode)
>> +{
>> + int ret;
>> +
>> + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1);
>> + if (ret < 0) {
>> + dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
>> + return ret;
>> + }
>> +
>> + if (ret & KXCJK1013_REG_CTRL1_BIT_PC1)
>> + *mode = OPERATION;
>> + else
>> + *mode = STANDBY;
>> +
>> + return 0;
>> +}
>> +
>> static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
>> {
>> int ret;
>> @@ -204,10 +231,53 @@ static int kxcjk1013_chip_init(struct
>> kxcjk1013_data *data)
>> return 0;
>> }
>>
>> +static int kxcjk1013_set_power_state(struct kxcjk1013_data *data,
>> bool on)
>> +{
>> + int ret;
>> +
>> +#ifdef CONFIG_PM_RUNTIME
>> + if (on)
>> + ret = pm_runtime_get_sync(&data->client->dev);
>> + else {
>> + pm_runtime_put_noidle(&data->client->dev);
>> + ret = pm_schedule_suspend(&data->client->dev,
>> + kxcjk1013_power_off_delay_ms);
>> + }
>> +#else
>> + if (on) {
>> + ret = kxcjk1013_set_mode(data, OPERATION);
>> + if (!ret) {
>> + int sleep_val;
>> +
>> + sleep_val = kxcjk1013_get_startup_times(data);
>> + if (sleep_val < 20000)
>> + usleep_range(sleep_val, 20000);
>> + else
>> + msleep_interruptible(sleep_val/1000);
>> +
>> + }
>> + } else
>> + ret = kxcjk1013_set_mode(data, STANDBY);
>> +#endif
>> +
>> + if (ret < 0) {
>> + dev_err(&data->client->dev,
>> + "Failed: kxcjk1013_set_power_state for %d\n", on);
>> + return ret;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> static int kxcjk1013_chip_setup_interrupt(struct kxcjk1013_data *data,
>> bool status)
>> {
>> int ret;
>> + enum kxcjk1013_mode store_mode;
>> +
>> + ret = kxcjk1013_get_mode(data, &store_mode);
>> + if (ret < 0)
>> + return ret;
>>
>> /* This is requirement by spec to change state to STANDBY */
>> ret = kxcjk1013_set_mode(data, STANDBY);
>> @@ -250,7 +320,13 @@ static int kxcjk1013_chip_setup_interrupt(struct
>> kxcjk1013_data *data,
>> return ret;
>> }
>>
>> - return ret;
>> + if (store_mode == OPERATION) {
>> + ret = kxcjk1013_set_mode(data, OPERATION);
>> + if (ret < 0)
>> + return ret;
>> + }
>> +
>> + return 0;
>> }
>>
>> static int kxcjk1013_convert_freq_to_bit(int val, int val2)
>> @@ -271,6 +347,11 @@ static int kxcjk1013_set_odr(struct
>> kxcjk1013_data *data, int val, int val2)
>> {
>> int ret;
>> int odr_bits;
>> + enum kxcjk1013_mode store_mode;
>> +
>> + ret = kxcjk1013_get_mode(data, &store_mode);
>> + if (ret < 0)
>> + return ret;
>>
>> odr_bits = kxcjk1013_convert_freq_to_bit(val, val2);
>> if (odr_bits < 0)
>> @@ -290,9 +371,7 @@ static int kxcjk1013_set_odr(struct
>> kxcjk1013_data *data, int val, int val2)
>>
>> data->odr_bits = odr_bits;
>>
>> - /* Check, if the ODR is changed after data enable */
>> - if (data->power_state) {
>> - /* Set the state back to operation */
>> + if (store_mode == OPERATION) {
>> ret = kxcjk1013_set_mode(data, OPERATION);
>> if (ret < 0)
>> return ret;
>> @@ -356,29 +435,25 @@ static int kxcjk1013_read_raw(struct iio_dev
>> *indio_dev,
>> if (iio_buffer_enabled(indio_dev))
>> ret = -EBUSY;
>> else {
>> - int sleep_val;
>> -
>> - ret = kxcjk1013_set_mode(data, OPERATION);
>> + ret = kxcjk1013_set_power_state(data, true);
>> if (ret < 0) {
>> mutex_unlock(&data->mutex);
>> return ret;
>> }
>> - ++data->power_state;
>> - sleep_val = kxcjk1013_get_startup_times(data);
>> - if (sleep_val < 20000)
>> - usleep_range(sleep_val, 20000);
>> - else
>> - msleep_interruptible(sleep_val/1000);
>> ret = kxcjk1013_get_acc_reg(data, chan->scan_index);
>> - if (--data->power_state == 0)
>> - kxcjk1013_set_mode(data, STANDBY);
>> + if (ret < 0) {
>> + kxcjk1013_set_power_state(data, false);
>> + mutex_unlock(&data->mutex);
>> + return ret;
>> + }
>> + *val = sign_extend32(ret >> 4, 11);
>> + ret = kxcjk1013_set_power_state(data, false);
>> }
>> mutex_unlock(&data->mutex);
>>
>> if (ret < 0)
>> return ret;
>>
>> - *val = sign_extend32(ret >> 4, 11);
>> return IIO_VAL_INT;
>>
>> case IIO_CHAN_INFO_SCALE:
>> @@ -520,20 +595,21 @@ static int
>> kxcjk1013_data_rdy_trigger_set_state(struct iio_trigger *trig,
>> {
>> struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
>> struct kxcjk1013_data *data = iio_priv(indio_dev);
>> + int ret;
>> +
>> + if (state && data->trigger_on)
>> + return 0;
>>
>> mutex_lock(&data->mutex);
>> - if (state) {
>> - kxcjk1013_chip_setup_interrupt(data, true);
>> - kxcjk1013_set_mode(data, OPERATION);
>> - ++data->power_state;
>> - } else {
>> - if (--data->power_state) {
>> + ret = kxcjk1013_chip_setup_interrupt(data, state);
>> + if (!ret) {
>> + ret = kxcjk1013_set_power_state(data, state);
>> + if (ret < 0) {
>> mutex_unlock(&data->mutex);
>> - return 0;
>> + return ret;
>> }
>> - kxcjk1013_chip_setup_interrupt(data, false);
>> - kxcjk1013_set_mode(data, STANDBY);
>> }
>> + data->trigger_on = state;
>> mutex_unlock(&data->mutex);
>>
>> return 0;
>> @@ -660,14 +736,22 @@ static int kxcjk1013_probe(struct i2c_client
>> *client,
>> }
>> }
>>
>> - ret = devm_iio_device_register(&client->dev, indio_dev);
>> + ret = iio_device_register(indio_dev);
>> if (ret < 0) {
>> dev_err(&client->dev, "unable to register iio device\n");
>> goto err_buffer_cleanup;
>> }
>>
>> + ret = pm_runtime_set_active(&client->dev);
>> + if (ret)
>> + goto err_iio_unregister;
>> +
>> + pm_runtime_enable(&client->dev);
>> +
>> return 0;
>>
>> +err_iio_unregister:
>> + iio_device_unregister(indio_dev);
>> err_buffer_cleanup:
>> if (data->trig_mode)
>> iio_triggered_buffer_cleanup(indio_dev);
>> @@ -686,6 +770,12 @@ static int kxcjk1013_remove(struct i2c_client
>> *client)
>> struct iio_dev *indio_dev = i2c_get_clientdata(client);
>> struct kxcjk1013_data *data = iio_priv(indio_dev);
>>
>> + pm_runtime_disable(&client->dev);
>> + pm_runtime_set_suspended(&client->dev);
>> + pm_runtime_put_noidle(&client->dev);
>> +
>> + iio_device_unregister(indio_dev);
>> +
>> if (data->trig_mode) {
>> iio_triggered_buffer_cleanup(indio_dev);
>> iio_trigger_unregister(data->trig);
>> @@ -704,35 +794,67 @@ static int kxcjk1013_suspend(struct device *dev)
>> {
>> struct iio_dev *indio_dev =
>> i2c_get_clientdata(to_i2c_client(dev));
>> struct kxcjk1013_data *data = iio_priv(indio_dev);
>> + int ret;
>>
>> mutex_lock(&data->mutex);
>> - kxcjk1013_set_mode(data, STANDBY);
>> + ret = kxcjk1013_set_mode(data, STANDBY);
>> mutex_unlock(&data->mutex);
>>
>> - return 0;
>> + return ret;
>> }
>>
>> static int kxcjk1013_resume(struct device *dev)
>> {
>> struct iio_dev *indio_dev =
>> i2c_get_clientdata(to_i2c_client(dev));
>> struct kxcjk1013_data *data = iio_priv(indio_dev);
>> + int ret = 0;
>>
>> mutex_lock(&data->mutex);
>> + /* Check, if the suspend occured while active */
>> + if (data->trigger_on)
>> + ret = kxcjk1013_set_mode(data, OPERATION);
>> + mutex_unlock(&data->mutex);
>>
>> - if (data->power_state)
>> - kxcjk1013_set_mode(data, OPERATION);
>> + return ret;
>> +}
>> +#endif
>>
>> - mutex_unlock(&data->mutex);
>> +#ifdef CONFIG_PM_RUNTIME
>> +static int kxcjk1013_runtime_suspend(struct device *dev)
>> +{
>> + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
>> + struct kxcjk1013_data *data = iio_priv(indio_dev);
>>
>> - return 0;
>> + return kxcjk1013_set_mode(data, STANDBY);
>> }
>>
>> -static SIMPLE_DEV_PM_OPS(kxcjk1013_pm_ops, kxcjk1013_suspend,
>> kxcjk1013_resume);
>> -#define KXCJK1013_PM_OPS (&kxcjk1013_pm_ops)
>> -#else
>> -#define KXCJK1013_PM_OPS NULL
>> +static int kxcjk1013_runtime_resume(struct device *dev)
>> +{
>> + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
>> + struct kxcjk1013_data *data = iio_priv(indio_dev);
>> + int ret;
>> + int sleep_val;
>> +
>> + ret = kxcjk1013_set_mode(data, OPERATION);
>> + if (ret < 0)
>> + return ret;
>> +
>> + sleep_val = kxcjk1013_get_startup_times(data);
>> + if (sleep_val < 20000)
>> + usleep_range(sleep_val, 20000);
>> + else
>> + msleep_interruptible(sleep_val/1000);
>> +
>> + return 0;
>> +}
>> #endif
>>
>> +static const struct dev_pm_ops kxcjk1013_pm_ops = {
>> + SET_SYSTEM_SLEEP_PM_OPS(kxcjk1013_suspend, kxcjk1013_resume)
>> + SET_RUNTIME_PM_OPS(kxcjk1013_runtime_suspend,
>> + kxcjk1013_runtime_resume, NULL)
>> +};
>> +
>> static const struct acpi_device_id kx_acpi_match[] = {
>> {"KXCJ1013", 0},
>> { },
>> @@ -750,7 +872,7 @@ static struct i2c_driver kxcjk1013_driver = {
>> .driver = {
>> .name = KXCJK1013_DRV_NAME,
>> .acpi_match_table = ACPI_PTR(kx_acpi_match),
>> - .pm = KXCJK1013_PM_OPS,
>> + .pm = &kxcjk1013_pm_ops,
>> },
>> .probe = kxcjk1013_probe,
>> .remove = kxcjk1013_remove,
>>
>
next prev parent reply other threads:[~2014-07-22 1:23 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-07-17 0:42 [PATCH 1/6] iio: accel: kxcjk-1013: Fix setting frequency Srinivas Pandruvada
2014-07-17 0:42 ` [PATCH 2/6] iio: accel: kxcjk-1013: Use try_reenable to ack intr Srinivas Pandruvada
2014-07-20 15:20 ` Jonathan Cameron
2014-07-17 0:42 ` [PATCH 3/6] iio: accel: kxcjk-1013: support runtime pm Srinivas Pandruvada
2014-07-20 15:37 ` Jonathan Cameron
2014-07-22 1:23 ` Rafael J. Wysocki [this message]
2014-07-27 13:42 ` Jonathan Cameron
2014-07-27 14:26 ` Srinivas Pandruvada
2014-07-17 0:42 ` [PATCH 4/6] iio: accel: kxcjk-1013: Set adjustable range Srinivas Pandruvada
2014-07-20 15:45 ` Jonathan Cameron
2014-07-24 23:04 ` Srinivas Pandruvada
2014-07-27 13:51 ` Jonathan Cameron
2014-07-17 0:42 ` [PATCH 5/6] iio: accel: kxcjk-1013: Support thresholds Srinivas Pandruvada
2014-07-20 16:04 ` Jonathan Cameron
2014-07-20 16:34 ` Srinivas Pandruvada
2014-07-20 17:01 ` Jonathan Cameron
2014-07-17 0:42 ` [PATCH 6/6] iio: accel: kxcjk-1013: Increment ref counter for indio_dev->trig Srinivas Pandruvada
2014-07-20 11:29 ` Lars-Peter Clausen
2014-07-20 12:24 ` Jonathan Cameron
2014-07-20 15:39 ` Jonathan Cameron
2014-07-20 15:19 ` [PATCH 1/6] iio: accel: kxcjk-1013: Fix setting frequency Jonathan Cameron
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=53CDBCFD.9090702@intel.com \
--to=rafael.j.wysocki@intel.com \
--cc=jic23@kernel.org \
--cc=linux-iio@vger.kernel.org \
--cc=srinivas.pandruvada@linux.intel.com \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).