diff options
author | Adriana Reus <adriana.reus@intel.com> | 2015-11-24 05:59:51 -0500 |
---|---|---|
committer | Jonathan Cameron <jic23@kernel.org> | 2015-12-02 13:42:05 -0500 |
commit | f0e5f57d3ac25aa2afb25dc94d2b42a8defa8a19 (patch) | |
tree | 2ca5d7a0420330e9d02e3042fecdf270299652cb | |
parent | a22a3c5c40deb31f03c2810a46e669bedbf476c5 (diff) |
iio: light: us8152d: Add power management support
Add power management for sleep as well as runtime pm.
Signed-off-by: Adriana Reus <adriana.reus@intel.com>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
-rw-r--r-- | drivers/iio/light/us5182d.c | 95 |
1 files changed, 88 insertions, 7 deletions
diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c index e67956c1f296..256c4bc12d21 100644 --- a/drivers/iio/light/us5182d.c +++ b/drivers/iio/light/us5182d.c | |||
@@ -23,6 +23,8 @@ | |||
23 | #include <linux/iio/iio.h> | 23 | #include <linux/iio/iio.h> |
24 | #include <linux/iio/sysfs.h> | 24 | #include <linux/iio/sysfs.h> |
25 | #include <linux/mutex.h> | 25 | #include <linux/mutex.h> |
26 | #include <linux/pm.h> | ||
27 | #include <linux/pm_runtime.h> | ||
26 | 28 | ||
27 | #define US5182D_REG_CFG0 0x00 | 29 | #define US5182D_REG_CFG0 0x00 |
28 | #define US5182D_CFG0_ONESHOT_EN BIT(6) | 30 | #define US5182D_CFG0_ONESHOT_EN BIT(6) |
@@ -81,6 +83,7 @@ | |||
81 | #define US5182D_READ_BYTE 1 | 83 | #define US5182D_READ_BYTE 1 |
82 | #define US5182D_READ_WORD 2 | 84 | #define US5182D_READ_WORD 2 |
83 | #define US5182D_OPSTORE_SLEEP_TIME 20 /* ms */ | 85 | #define US5182D_OPSTORE_SLEEP_TIME 20 /* ms */ |
86 | #define US5182D_SLEEP_MS 3000 /* ms */ | ||
84 | 87 | ||
85 | /* Available ranges: [12354, 7065, 3998, 2202, 1285, 498, 256, 138] lux */ | 88 | /* Available ranges: [12354, 7065, 3998, 2202, 1285, 498, 256, 138] lux */ |
86 | static const int us5182d_scales[] = {188500, 107800, 61000, 33600, 19600, 7600, | 89 | static const int us5182d_scales[] = {188500, 107800, 61000, 33600, 19600, 7600, |
@@ -300,6 +303,26 @@ static int us5182d_shutdown_en(struct us5182d_data *data, u8 state) | |||
300 | return ret; | 303 | return ret; |
301 | } | 304 | } |
302 | 305 | ||
306 | |||
307 | static int us5182d_set_power_state(struct us5182d_data *data, bool on) | ||
308 | { | ||
309 | int ret; | ||
310 | |||
311 | if (data->power_mode == US5182D_ONESHOT) | ||
312 | return 0; | ||
313 | |||
314 | if (on) { | ||
315 | ret = pm_runtime_get_sync(&data->client->dev); | ||
316 | if (ret < 0) | ||
317 | pm_runtime_put_noidle(&data->client->dev); | ||
318 | } else { | ||
319 | pm_runtime_mark_last_busy(&data->client->dev); | ||
320 | ret = pm_runtime_put_autosuspend(&data->client->dev); | ||
321 | } | ||
322 | |||
323 | return ret; | ||
324 | } | ||
325 | |||
303 | static int us5182d_read_raw(struct iio_dev *indio_dev, | 326 | static int us5182d_read_raw(struct iio_dev *indio_dev, |
304 | struct iio_chan_spec const *chan, int *val, | 327 | struct iio_chan_spec const *chan, int *val, |
305 | int *val2, long mask) | 328 | int *val2, long mask) |
@@ -317,15 +340,20 @@ static int us5182d_read_raw(struct iio_dev *indio_dev, | |||
317 | if (ret < 0) | 340 | if (ret < 0) |
318 | goto out_err; | 341 | goto out_err; |
319 | } | 342 | } |
320 | ret = us5182d_als_enable(data); | 343 | ret = us5182d_set_power_state(data, true); |
321 | if (ret < 0) | 344 | if (ret < 0) |
322 | goto out_err; | 345 | goto out_err; |
323 | 346 | ret = us5182d_als_enable(data); | |
347 | if (ret < 0) | ||
348 | goto out_poweroff; | ||
324 | ret = us5182d_get_als(data); | 349 | ret = us5182d_get_als(data); |
325 | if (ret < 0) | 350 | if (ret < 0) |
351 | goto out_poweroff; | ||
352 | *val = ret; | ||
353 | ret = us5182d_set_power_state(data, false); | ||
354 | if (ret < 0) | ||
326 | goto out_err; | 355 | goto out_err; |
327 | mutex_unlock(&data->lock); | 356 | mutex_unlock(&data->lock); |
328 | *val = ret; | ||
329 | return IIO_VAL_INT; | 357 | return IIO_VAL_INT; |
330 | case IIO_PROXIMITY: | 358 | case IIO_PROXIMITY: |
331 | mutex_lock(&data->lock); | 359 | mutex_lock(&data->lock); |
@@ -334,17 +362,22 @@ static int us5182d_read_raw(struct iio_dev *indio_dev, | |||
334 | if (ret < 0) | 362 | if (ret < 0) |
335 | goto out_err; | 363 | goto out_err; |
336 | } | 364 | } |
337 | ret = us5182d_px_enable(data); | 365 | ret = us5182d_set_power_state(data, true); |
338 | if (ret < 0) | 366 | if (ret < 0) |
339 | goto out_err; | 367 | goto out_err; |
340 | 368 | ret = us5182d_px_enable(data); | |
369 | if (ret < 0) | ||
370 | goto out_poweroff; | ||
341 | ret = i2c_smbus_read_word_data(data->client, | 371 | ret = i2c_smbus_read_word_data(data->client, |
342 | US5182D_REG_PDL); | 372 | US5182D_REG_PDL); |
343 | if (ret < 0) | 373 | if (ret < 0) |
374 | goto out_poweroff; | ||
375 | *val = ret; | ||
376 | ret = us5182d_set_power_state(data, false); | ||
377 | if (ret < 0) | ||
344 | goto out_err; | 378 | goto out_err; |
345 | mutex_unlock(&data->lock); | 379 | mutex_unlock(&data->lock); |
346 | *val = ret; | 380 | return IIO_VAL_INT; |
347 | return IIO_VAL_INT; | ||
348 | default: | 381 | default: |
349 | return -EINVAL; | 382 | return -EINVAL; |
350 | } | 383 | } |
@@ -363,6 +396,9 @@ static int us5182d_read_raw(struct iio_dev *indio_dev, | |||
363 | } | 396 | } |
364 | 397 | ||
365 | return -EINVAL; | 398 | return -EINVAL; |
399 | |||
400 | out_poweroff: | ||
401 | us5182d_set_power_state(data, false); | ||
366 | out_err: | 402 | out_err: |
367 | mutex_unlock(&data->lock); | 403 | mutex_unlock(&data->lock); |
368 | return ret; | 404 | return ret; |
@@ -579,6 +615,17 @@ static int us5182d_probe(struct i2c_client *client, | |||
579 | if (ret < 0) | 615 | if (ret < 0) |
580 | goto out_err; | 616 | goto out_err; |
581 | 617 | ||
618 | if (data->default_continuous) { | ||
619 | pm_runtime_set_active(&client->dev); | ||
620 | if (ret < 0) | ||
621 | goto out_err; | ||
622 | } | ||
623 | |||
624 | pm_runtime_enable(&client->dev); | ||
625 | pm_runtime_set_autosuspend_delay(&client->dev, | ||
626 | US5182D_SLEEP_MS); | ||
627 | pm_runtime_use_autosuspend(&client->dev); | ||
628 | |||
582 | ret = iio_device_register(indio_dev); | 629 | ret = iio_device_register(indio_dev); |
583 | if (ret < 0) | 630 | if (ret < 0) |
584 | goto out_err; | 631 | goto out_err; |
@@ -597,9 +644,42 @@ static int us5182d_remove(struct i2c_client *client) | |||
597 | 644 | ||
598 | iio_device_unregister(i2c_get_clientdata(client)); | 645 | iio_device_unregister(i2c_get_clientdata(client)); |
599 | 646 | ||
647 | pm_runtime_disable(&client->dev); | ||
648 | pm_runtime_set_suspended(&client->dev); | ||
649 | |||
600 | return us5182d_shutdown_en(data, US5182D_CFG0_SHUTDOWN_EN); | 650 | return us5182d_shutdown_en(data, US5182D_CFG0_SHUTDOWN_EN); |
601 | } | 651 | } |
602 | 652 | ||
653 | #if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM) | ||
654 | static int us5182d_suspend(struct device *dev) | ||
655 | { | ||
656 | struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); | ||
657 | struct us5182d_data *data = iio_priv(indio_dev); | ||
658 | |||
659 | if (data->power_mode == US5182D_CONTINUOUS) | ||
660 | return us5182d_shutdown_en(data, US5182D_CFG0_SHUTDOWN_EN); | ||
661 | |||
662 | return 0; | ||
663 | } | ||
664 | |||
665 | static int us5182d_resume(struct device *dev) | ||
666 | { | ||
667 | struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); | ||
668 | struct us5182d_data *data = iio_priv(indio_dev); | ||
669 | |||
670 | if (data->power_mode == US5182D_CONTINUOUS) | ||
671 | return us5182d_shutdown_en(data, | ||
672 | ~US5182D_CFG0_SHUTDOWN_EN & 0xff); | ||
673 | |||
674 | return 0; | ||
675 | } | ||
676 | #endif | ||
677 | |||
678 | static const struct dev_pm_ops us5182d_pm_ops = { | ||
679 | SET_SYSTEM_SLEEP_PM_OPS(us5182d_suspend, us5182d_resume) | ||
680 | SET_RUNTIME_PM_OPS(us5182d_suspend, us5182d_resume, NULL) | ||
681 | }; | ||
682 | |||
603 | static const struct acpi_device_id us5182d_acpi_match[] = { | 683 | static const struct acpi_device_id us5182d_acpi_match[] = { |
604 | { "USD5182", 0}, | 684 | { "USD5182", 0}, |
605 | {} | 685 | {} |
@@ -617,6 +697,7 @@ MODULE_DEVICE_TABLE(i2c, us5182d_id); | |||
617 | static struct i2c_driver us5182d_driver = { | 697 | static struct i2c_driver us5182d_driver = { |
618 | .driver = { | 698 | .driver = { |
619 | .name = US5182D_DRV_NAME, | 699 | .name = US5182D_DRV_NAME, |
700 | .pm = &us5182d_pm_ops, | ||
620 | .acpi_match_table = ACPI_PTR(us5182d_acpi_match), | 701 | .acpi_match_table = ACPI_PTR(us5182d_acpi_match), |
621 | }, | 702 | }, |
622 | .probe = us5182d_probe, | 703 | .probe = us5182d_probe, |