Skip to content

Commit abe629e

Browse files
Akshay Jindaljic23
authored andcommitted
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>
1 parent 661facb commit abe629e

1 file changed

Lines changed: 119 additions & 17 deletions

File tree

drivers/iio/light/ltr390.c

Lines changed: 119 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <linux/math.h>
2727
#include <linux/module.h>
2828
#include <linux/mutex.h>
29+
#include <linux/pm_runtime.h>
2930
#include <linux/regmap.h>
3031

3132
#include <linux/iio/iio.h>
@@ -105,6 +106,7 @@ struct ltr390_data {
105106
enum ltr390_mode mode;
106107
int gain;
107108
int int_time_us;
109+
bool irq_enabled;
108110
};
109111

110112
static const struct regmap_range ltr390_readable_reg_ranges[] = {
@@ -215,9 +217,10 @@ static int ltr390_get_samp_freq_or_period(struct ltr390_data *data,
215217
return ltr390_samp_freq_table[value][option];
216218
}
217219

218-
static int ltr390_read_raw(struct iio_dev *iio_device,
219-
struct iio_chan_spec const *chan, int *val,
220-
int *val2, long mask)
220+
221+
static int ltr390_do_read_raw(struct iio_dev *iio_device,
222+
struct iio_chan_spec const *chan, int *val,
223+
int *val2, long mask)
221224
{
222225
int ret;
223226
struct ltr390_data *data = iio_priv(iio_device);
@@ -280,6 +283,27 @@ static int ltr390_read_raw(struct iio_dev *iio_device,
280283
}
281284
}
282285

286+
static int ltr390_read_raw(struct iio_dev *iio_device,
287+
struct iio_chan_spec const *chan,
288+
int *val, int *val2, long mask)
289+
{
290+
int ret;
291+
struct ltr390_data *data = iio_priv(iio_device);
292+
struct device *dev = &data->client->dev;
293+
294+
ret = pm_runtime_resume_and_get(dev);
295+
if (ret < 0) {
296+
dev_err(dev, "runtime PM failed to resume: %d\n", ret);
297+
return ret;
298+
}
299+
300+
ret = ltr390_do_read_raw(iio_device, chan, val, val2, mask);
301+
302+
pm_runtime_put_autosuspend(dev);
303+
304+
return ret;
305+
}
306+
283307
/* integration time in us */
284308
static const int ltr390_int_time_map_us[] = { 400000, 200000, 100000, 50000, 25000, 12500 };
285309
static const int ltr390_gain_map[] = { 1, 3, 6, 9, 18 };
@@ -586,19 +610,18 @@ static int ltr390_read_event_config(struct iio_dev *indio_dev,
586610
return FIELD_GET(LTR390_LS_INT_EN, status);
587611
}
588612

589-
static int ltr390_write_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)
613+
static int ltr390_do_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)
594618
{
595619
struct ltr390_data *data = iio_priv(indio_dev);
596620
int ret;
597621

598622
if (!state)
599623
return regmap_clear_bits(data->regmap, LTR390_INT_CFG, LTR390_LS_INT_EN);
600624

601-
guard(mutex)(&data->lock);
602625
ret = regmap_set_bits(data->regmap, LTR390_INT_CFG, LTR390_LS_INT_EN);
603626
if (ret < 0)
604627
return ret;
@@ -623,6 +646,37 @@ static int ltr390_write_event_config(struct iio_dev *indio_dev,
623646
}
624647
}
625648

649+
static int ltr390_write_event_config(struct iio_dev *indio_dev,
650+
const struct iio_chan_spec *chan,
651+
enum iio_event_type type,
652+
enum iio_event_direction dir,
653+
bool state)
654+
{
655+
int ret;
656+
struct ltr390_data *data = iio_priv(indio_dev);
657+
struct device *dev = &data->client->dev;
658+
659+
guard(mutex)(&data->lock);
660+
661+
if (state && !data->irq_enabled) {
662+
ret = pm_runtime_resume_and_get(dev);
663+
if (ret < 0) {
664+
dev_err(dev, "runtime PM failed to resume: %d\n", ret);
665+
return ret;
666+
}
667+
data->irq_enabled = true;
668+
}
669+
670+
ret = ltr390_do_event_config(indio_dev, chan, type, dir, state);
671+
672+
if (!state && data->irq_enabled) {
673+
data->irq_enabled = false;
674+
pm_runtime_put_autosuspend(dev);
675+
}
676+
677+
return ret;
678+
}
679+
626680
static int ltr390_debugfs_reg_access(struct iio_dev *indio_dev,
627681
unsigned int reg, unsigned int writeval,
628682
unsigned int *readval)
@@ -683,17 +737,38 @@ static irqreturn_t ltr390_interrupt_handler(int irq, void *private)
683737
static void ltr390_powerdown(void *priv)
684738
{
685739
struct ltr390_data *data = priv;
740+
struct device *dev = &data->client->dev;
741+
int ret;
686742

687743
guard(mutex)(&data->lock);
688744

689745
/* Ensure that power off and interrupts are disabled */
690-
if (regmap_clear_bits(data->regmap, LTR390_INT_CFG,
691-
LTR390_LS_INT_EN) < 0)
692-
dev_err(&data->client->dev, "failed to disable interrupts\n");
746+
if (data->irq_enabled) {
747+
ret = regmap_clear_bits(data->regmap, LTR390_INT_CFG, LTR390_LS_INT_EN);
748+
if (ret < 0)
749+
dev_err(dev, "failed to disable interrupts\n");
750+
751+
data->irq_enabled = false;
752+
pm_runtime_put_autosuspend(dev);
753+
}
754+
755+
ret = regmap_clear_bits(data->regmap, LTR390_MAIN_CTRL, LTR390_SENSOR_ENABLE);
756+
if (ret < 0)
757+
dev_err(dev, "failed to disable sensor\n");
758+
}
759+
760+
static int ltr390_pm_init(struct ltr390_data *data)
761+
{
762+
int ret;
763+
struct device *dev = &data->client->dev;
764+
765+
ret = devm_pm_runtime_set_active_enabled(dev);
766+
if (ret)
767+
return dev_err_probe(dev, ret, "failed to enable runtime PM\n");
693768

694-
if (regmap_clear_bits(data->regmap, LTR390_MAIN_CTRL,
695-
LTR390_SENSOR_ENABLE) < 0)
696-
dev_err(&data->client->dev, "failed to disable sensor\n");
769+
pm_runtime_set_autosuspend_delay(dev, 1000);
770+
pm_runtime_use_autosuspend(dev);
771+
return 0;
697772
}
698773

699774
static int ltr390_probe(struct i2c_client *client)
@@ -708,6 +783,8 @@ static int ltr390_probe(struct i2c_client *client)
708783
if (!indio_dev)
709784
return -ENOMEM;
710785

786+
i2c_set_clientdata(client, indio_dev);
787+
711788
data = iio_priv(indio_dev);
712789
data->regmap = devm_regmap_init_i2c(client, &ltr390_regmap_config);
713790
if (IS_ERR(data->regmap))
@@ -721,6 +798,8 @@ static int ltr390_probe(struct i2c_client *client)
721798
data->gain = 3;
722799
/* default mode for ltr390 is ALS mode */
723800
data->mode = LTR390_SET_ALS_MODE;
801+
/* default value of irq_enabled is false */
802+
data->irq_enabled = false;
724803

725804
mutex_init(&data->lock);
726805

@@ -763,6 +842,10 @@ static int ltr390_probe(struct i2c_client *client)
763842
"request irq (%d) failed\n", client->irq);
764843
}
765844

845+
ret = ltr390_pm_init(data);
846+
if (ret)
847+
return dev_err_probe(dev, ret, "failed to initialize runtime PM\n");
848+
766849
return devm_iio_device_register(dev, indio_dev);
767850
}
768851

@@ -784,7 +867,26 @@ static int ltr390_resume(struct device *dev)
784867
LTR390_SENSOR_ENABLE);
785868
}
786869

787-
static DEFINE_SIMPLE_DEV_PM_OPS(ltr390_pm_ops, ltr390_suspend, ltr390_resume);
870+
static int ltr390_runtime_suspend(struct device *dev)
871+
{
872+
struct iio_dev *indio_dev = dev_get_drvdata(dev);
873+
struct ltr390_data *data = iio_priv(indio_dev);
874+
875+
return regmap_clear_bits(data->regmap, LTR390_MAIN_CTRL, LTR390_SENSOR_ENABLE);
876+
}
877+
878+
static int ltr390_runtime_resume(struct device *dev)
879+
{
880+
struct iio_dev *indio_dev = dev_get_drvdata(dev);
881+
struct ltr390_data *data = iio_priv(indio_dev);
882+
883+
return regmap_set_bits(data->regmap, LTR390_MAIN_CTRL, LTR390_SENSOR_ENABLE);
884+
}
885+
886+
static const struct dev_pm_ops ltr390_pm_ops = {
887+
SYSTEM_SLEEP_PM_OPS(ltr390_suspend, ltr390_resume)
888+
RUNTIME_PM_OPS(ltr390_runtime_suspend, ltr390_runtime_resume, NULL)
889+
};
788890

789891
static const struct i2c_device_id ltr390_id[] = {
790892
{ "ltr390" },
@@ -802,7 +904,7 @@ static struct i2c_driver ltr390_driver = {
802904
.driver = {
803905
.name = "ltr390",
804906
.of_match_table = ltr390_of_table,
805-
.pm = pm_sleep_ptr(&ltr390_pm_ops),
907+
.pm = pm_ptr(&ltr390_pm_ops),
806908
},
807909
.probe = ltr390_probe,
808910
.id_table = ltr390_id,

0 commit comments

Comments
 (0)