Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

iio: light: ltr390: Implement runtime PM support

Implement runtime power management for the LTR390 sensor. The device
autosuspends after 1s of idle time, reducing current consumption from
100 µA in active mode to 1 µA in standby mode as per the datasheet.

Ensure that interrupts continue to be delivered with runtime PM.
Since the LTR390 cannot be used as a wakeup source during runtime
suspend, therefore increment the runtime PM refcount when enabling
events and decrement it when disabling events or powering down.
This prevents event loss while still allowing power savings when IRQs
are unused.

Signed-off-by: Akshay Jindal <akshayaj.lkd@gmail.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Akshay Jindal and committed by
Jonathan Cameron
abe629eb 661facba

+119 -17
+119 -17
drivers/iio/light/ltr390.c
··· 26 26 #include <linux/math.h> 27 27 #include <linux/module.h> 28 28 #include <linux/mutex.h> 29 + #include <linux/pm_runtime.h> 29 30 #include <linux/regmap.h> 30 31 31 32 #include <linux/iio/iio.h> ··· 106 105 enum ltr390_mode mode; 107 106 int gain; 108 107 int int_time_us; 108 + bool irq_enabled; 109 109 }; 110 110 111 111 static const struct regmap_range ltr390_readable_reg_ranges[] = { ··· 217 215 return ltr390_samp_freq_table[value][option]; 218 216 } 219 217 220 - static int ltr390_read_raw(struct iio_dev *iio_device, 221 - struct iio_chan_spec const *chan, int *val, 222 - int *val2, long mask) 218 + 219 + static int ltr390_do_read_raw(struct iio_dev *iio_device, 220 + struct iio_chan_spec const *chan, int *val, 221 + int *val2, long mask) 223 222 { 224 223 int ret; 225 224 struct ltr390_data *data = iio_priv(iio_device); ··· 281 278 default: 282 279 return -EINVAL; 283 280 } 281 + } 282 + 283 + static int ltr390_read_raw(struct iio_dev *iio_device, 284 + struct iio_chan_spec const *chan, 285 + int *val, int *val2, long mask) 286 + { 287 + int ret; 288 + struct ltr390_data *data = iio_priv(iio_device); 289 + struct device *dev = &data->client->dev; 290 + 291 + ret = pm_runtime_resume_and_get(dev); 292 + if (ret < 0) { 293 + dev_err(dev, "runtime PM failed to resume: %d\n", ret); 294 + return ret; 295 + } 296 + 297 + ret = ltr390_do_read_raw(iio_device, chan, val, val2, mask); 298 + 299 + pm_runtime_put_autosuspend(dev); 300 + 301 + return ret; 284 302 } 285 303 286 304 /* integration time in us */ ··· 610 586 return FIELD_GET(LTR390_LS_INT_EN, status); 611 587 } 612 588 613 - static int ltr390_write_event_config(struct iio_dev *indio_dev, 614 - const struct iio_chan_spec *chan, 615 - enum iio_event_type type, 616 - enum iio_event_direction dir, 617 - bool state) 589 + static int ltr390_do_event_config(struct iio_dev *indio_dev, 590 + const struct iio_chan_spec *chan, 591 + enum iio_event_type type, 592 + enum iio_event_direction dir, 593 + bool state) 618 594 { 619 595 struct ltr390_data *data = iio_priv(indio_dev); 620 596 int ret; ··· 622 598 if (!state) 623 599 return regmap_clear_bits(data->regmap, LTR390_INT_CFG, LTR390_LS_INT_EN); 624 600 625 - guard(mutex)(&data->lock); 626 601 ret = regmap_set_bits(data->regmap, LTR390_INT_CFG, LTR390_LS_INT_EN); 627 602 if (ret < 0) 628 603 return ret; ··· 644 621 default: 645 622 return -EINVAL; 646 623 } 624 + } 625 + 626 + static int ltr390_write_event_config(struct iio_dev *indio_dev, 627 + const struct iio_chan_spec *chan, 628 + enum iio_event_type type, 629 + enum iio_event_direction dir, 630 + bool state) 631 + { 632 + int ret; 633 + struct ltr390_data *data = iio_priv(indio_dev); 634 + struct device *dev = &data->client->dev; 635 + 636 + guard(mutex)(&data->lock); 637 + 638 + if (state && !data->irq_enabled) { 639 + ret = pm_runtime_resume_and_get(dev); 640 + if (ret < 0) { 641 + dev_err(dev, "runtime PM failed to resume: %d\n", ret); 642 + return ret; 643 + } 644 + data->irq_enabled = true; 645 + } 646 + 647 + ret = ltr390_do_event_config(indio_dev, chan, type, dir, state); 648 + 649 + if (!state && data->irq_enabled) { 650 + data->irq_enabled = false; 651 + pm_runtime_put_autosuspend(dev); 652 + } 653 + 654 + return ret; 647 655 } 648 656 649 657 static int ltr390_debugfs_reg_access(struct iio_dev *indio_dev, ··· 737 683 static void ltr390_powerdown(void *priv) 738 684 { 739 685 struct ltr390_data *data = priv; 686 + struct device *dev = &data->client->dev; 687 + int ret; 740 688 741 689 guard(mutex)(&data->lock); 742 690 743 691 /* Ensure that power off and interrupts are disabled */ 744 - if (regmap_clear_bits(data->regmap, LTR390_INT_CFG, 745 - LTR390_LS_INT_EN) < 0) 746 - dev_err(&data->client->dev, "failed to disable interrupts\n"); 692 + if (data->irq_enabled) { 693 + ret = regmap_clear_bits(data->regmap, LTR390_INT_CFG, LTR390_LS_INT_EN); 694 + if (ret < 0) 695 + dev_err(dev, "failed to disable interrupts\n"); 747 696 748 - if (regmap_clear_bits(data->regmap, LTR390_MAIN_CTRL, 749 - LTR390_SENSOR_ENABLE) < 0) 750 - dev_err(&data->client->dev, "failed to disable sensor\n"); 697 + data->irq_enabled = false; 698 + pm_runtime_put_autosuspend(dev); 699 + } 700 + 701 + ret = regmap_clear_bits(data->regmap, LTR390_MAIN_CTRL, LTR390_SENSOR_ENABLE); 702 + if (ret < 0) 703 + dev_err(dev, "failed to disable sensor\n"); 704 + } 705 + 706 + static int ltr390_pm_init(struct ltr390_data *data) 707 + { 708 + int ret; 709 + struct device *dev = &data->client->dev; 710 + 711 + ret = devm_pm_runtime_set_active_enabled(dev); 712 + if (ret) 713 + return dev_err_probe(dev, ret, "failed to enable runtime PM\n"); 714 + 715 + pm_runtime_set_autosuspend_delay(dev, 1000); 716 + pm_runtime_use_autosuspend(dev); 717 + return 0; 751 718 } 752 719 753 720 static int ltr390_probe(struct i2c_client *client) ··· 783 708 if (!indio_dev) 784 709 return -ENOMEM; 785 710 711 + i2c_set_clientdata(client, indio_dev); 712 + 786 713 data = iio_priv(indio_dev); 787 714 data->regmap = devm_regmap_init_i2c(client, &ltr390_regmap_config); 788 715 if (IS_ERR(data->regmap)) ··· 798 721 data->gain = 3; 799 722 /* default mode for ltr390 is ALS mode */ 800 723 data->mode = LTR390_SET_ALS_MODE; 724 + /* default value of irq_enabled is false */ 725 + data->irq_enabled = false; 801 726 802 727 mutex_init(&data->lock); 803 728 ··· 842 763 "request irq (%d) failed\n", client->irq); 843 764 } 844 765 766 + ret = ltr390_pm_init(data); 767 + if (ret) 768 + return dev_err_probe(dev, ret, "failed to initialize runtime PM\n"); 769 + 845 770 return devm_iio_device_register(dev, indio_dev); 846 771 } 847 772 ··· 867 784 LTR390_SENSOR_ENABLE); 868 785 } 869 786 870 - static DEFINE_SIMPLE_DEV_PM_OPS(ltr390_pm_ops, ltr390_suspend, ltr390_resume); 787 + static int ltr390_runtime_suspend(struct device *dev) 788 + { 789 + struct iio_dev *indio_dev = dev_get_drvdata(dev); 790 + struct ltr390_data *data = iio_priv(indio_dev); 791 + 792 + return regmap_clear_bits(data->regmap, LTR390_MAIN_CTRL, LTR390_SENSOR_ENABLE); 793 + } 794 + 795 + static int ltr390_runtime_resume(struct device *dev) 796 + { 797 + struct iio_dev *indio_dev = dev_get_drvdata(dev); 798 + struct ltr390_data *data = iio_priv(indio_dev); 799 + 800 + return regmap_set_bits(data->regmap, LTR390_MAIN_CTRL, LTR390_SENSOR_ENABLE); 801 + } 802 + 803 + static const struct dev_pm_ops ltr390_pm_ops = { 804 + SYSTEM_SLEEP_PM_OPS(ltr390_suspend, ltr390_resume) 805 + RUNTIME_PM_OPS(ltr390_runtime_suspend, ltr390_runtime_resume, NULL) 806 + }; 871 807 872 808 static const struct i2c_device_id ltr390_id[] = { 873 809 { "ltr390" }, ··· 904 802 .driver = { 905 803 .name = "ltr390", 906 804 .of_match_table = ltr390_of_table, 907 - .pm = pm_sleep_ptr(&ltr390_pm_ops), 805 + .pm = pm_ptr(&ltr390_pm_ops), 908 806 }, 909 807 .probe = ltr390_probe, 910 808 .id_table = ltr390_id,