From: Jonathan Cameron <jic23@kernel.org>
To: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>,
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: Sun, 27 Jul 2014 14:42:44 +0100 [thread overview]
Message-ID: <53D501D4.3000303@kernel.org> (raw)
In-Reply-To: <53CDBCFD.9090702@intel.com>
On 22/07/14 02:23, Rafael J. Wysocki wrote:
> 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.
Thanks anyway,
> Rafael
>
Srinivas, from my initial review I was in the process of applying this and
got:
drivers/iio/accel/kxcjk-1013.c: In function ‘kxcjk1013_set_power_state’:
drivers/iio/accel/kxcjk-1013.c:252:4: error: implicit declaration of function ‘kxcjk1013_get_startup_times’ [-Werror=implicit-function-declaration]
sleep_val = kxcjk1013_get_startup_times(data);
^
drivers/iio/accel/kxcjk-1013.c: At top level:
drivers/iio/accel/kxcjk-1013.c:413:12: error: static declaration of ‘kxcjk1013_get_startup_times’ follows non-static declaration
static int kxcjk1013_get_startup_times(struct kxcjk1013_data *data)
^
drivers/iio/accel/kxcjk-1013.c:252:16: note: previous implicit declaration of ‘kxcjk1013_get_startup_times’ was here
sleep_val = kxcjk1013_get_startup_times(data);
^
drivers/iio/accel/kxcjk-1013.c:413:12: warning: ‘kxcjk1013_get_startup_times’ defined but not used [-Wunused-function]
static int kxcjk1013_get_startup_times(struct kxcjk1013_data *data)
^
Looks like a spot of reordering is needed.
Jonathan
>
>>> ---
>>> 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-27 13:40 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
2014-07-27 13:42 ` Jonathan Cameron [this message]
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=53D501D4.3000303@kernel.org \
--to=jic23@kernel.org \
--cc=linux-iio@vger.kernel.org \
--cc=rafael.j.wysocki@intel.com \
--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).