Skip to content

Commit 2db5054

Browse files
masneybjic23
authored andcommitted
staging: iio: isl29028: add runtime power management support
This patch adds runtime power management support to the isl29028 driver. It defaults to powering off the device after two seconds of inactivity. isl29028_chip_init_and_power_on() currently only zeros the CONFIGURE register on the chip, which will cause the chip to turn off. This patch also renames that function to isl29028_clear_configure_reg() since it is now used in several places. Signed-off-by: Brian Masney <[email protected]> Signed-off-by: Jonathan Cameron <[email protected]>
1 parent 0fac96e commit 2db5054

File tree

1 file changed

+110
-8
lines changed

1 file changed

+110
-8
lines changed

drivers/staging/iio/light/isl29028.c

Lines changed: 110 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <linux/regmap.h>
2727
#include <linux/iio/iio.h>
2828
#include <linux/iio/sysfs.h>
29+
#include <linux/pm_runtime.h>
2930

3031
#define ISL29028_CONV_TIME_MS 100
3132

@@ -60,6 +61,8 @@
6061

6162
#define ISL29028_NUM_REGS (ISL29028_REG_TEST2_MODE + 1)
6263

64+
#define ISL29028_POWER_OFF_DELAY_MS 2000
65+
6366
enum isl29028_als_ir_mode {
6467
ISL29028_MODE_NONE = 0,
6568
ISL29028_MODE_ALS,
@@ -297,16 +300,39 @@ static int isl29028_ir_get(struct isl29028_chip *chip, int *ir_data)
297300
return isl29028_read_als_ir(chip, ir_data);
298301
}
299302

303+
static int isl29028_set_pm_runtime_busy(struct isl29028_chip *chip, bool on)
304+
{
305+
struct device *dev = regmap_get_device(chip->regmap);
306+
int ret;
307+
308+
if (on) {
309+
ret = pm_runtime_get_sync(dev);
310+
if (ret < 0)
311+
pm_runtime_put_noidle(dev);
312+
} else {
313+
pm_runtime_mark_last_busy(dev);
314+
ret = pm_runtime_put_autosuspend(dev);
315+
}
316+
317+
return ret;
318+
}
319+
300320
/* Channel IO */
301321
static int isl29028_write_raw(struct iio_dev *indio_dev,
302322
struct iio_chan_spec const *chan,
303323
int val, int val2, long mask)
304324
{
305325
struct isl29028_chip *chip = iio_priv(indio_dev);
306326
struct device *dev = regmap_get_device(chip->regmap);
307-
int ret = -EINVAL;
327+
int ret;
328+
329+
ret = isl29028_set_pm_runtime_busy(chip, true);
330+
if (ret < 0)
331+
return ret;
308332

309333
mutex_lock(&chip->lock);
334+
335+
ret = -EINVAL;
310336
switch (chan->type) {
311337
case IIO_PROXIMITY:
312338
if (mask != IIO_CHAN_INFO_SAMP_FREQ) {
@@ -350,6 +376,13 @@ static int isl29028_write_raw(struct iio_dev *indio_dev,
350376

351377
mutex_unlock(&chip->lock);
352378

379+
if (ret < 0)
380+
return ret;
381+
382+
ret = isl29028_set_pm_runtime_busy(chip, false);
383+
if (ret < 0)
384+
return ret;
385+
353386
return ret;
354387
}
355388

@@ -359,9 +392,15 @@ static int isl29028_read_raw(struct iio_dev *indio_dev,
359392
{
360393
struct isl29028_chip *chip = iio_priv(indio_dev);
361394
struct device *dev = regmap_get_device(chip->regmap);
362-
int ret = -EINVAL;
395+
int ret, pm_ret;
396+
397+
ret = isl29028_set_pm_runtime_busy(chip, true);
398+
if (ret < 0)
399+
return ret;
363400

364401
mutex_lock(&chip->lock);
402+
403+
ret = -EINVAL;
365404
switch (mask) {
366405
case IIO_CHAN_INFO_RAW:
367406
case IIO_CHAN_INFO_PROCESSED:
@@ -405,6 +444,18 @@ static int isl29028_read_raw(struct iio_dev *indio_dev,
405444

406445
mutex_unlock(&chip->lock);
407446

447+
if (ret < 0)
448+
return ret;
449+
450+
/**
451+
* Preserve the ret variable if the call to
452+
* isl29028_set_pm_runtime_busy() is successful so the reading
453+
* (if applicable) is returned to user space.
454+
*/
455+
pm_ret = isl29028_set_pm_runtime_busy(chip, false);
456+
if (pm_ret < 0)
457+
return pm_ret;
458+
408459
return ret;
409460
}
410461

@@ -445,17 +496,18 @@ static const struct iio_info isl29028_info = {
445496
.write_raw = isl29028_write_raw,
446497
};
447498

448-
static int isl29028_chip_init_and_power_on(struct isl29028_chip *chip)
499+
static int isl29028_clear_configure_reg(struct isl29028_chip *chip)
449500
{
450501
struct device *dev = regmap_get_device(chip->regmap);
451502
int ret;
452503

453504
ret = regmap_write(chip->regmap, ISL29028_REG_CONFIGURE, 0x0);
454-
if (ret < 0) {
505+
if (ret < 0)
455506
dev_err(dev, "%s(): Error %d clearing the CONFIGURE register\n",
456507
__func__, ret);
457-
return ret;
458-
}
508+
509+
chip->als_ir_mode = ISL29028_MODE_NONE;
510+
chip->enable_prox = false;
459511

460512
return ret;
461513
}
@@ -509,7 +561,6 @@ static int isl29028_probe(struct i2c_client *client,
509561
chip->enable_prox = false;
510562
chip->prox_sampling = 20;
511563
chip->lux_scale = 2000;
512-
chip->als_ir_mode = ISL29028_MODE_NONE;
513564

514565
ret = regmap_write(chip->regmap, ISL29028_REG_TEST1_MODE, 0x0);
515566
if (ret < 0) {
@@ -527,7 +578,7 @@ static int isl29028_probe(struct i2c_client *client,
527578
return ret;
528579
}
529580

530-
ret = isl29028_chip_init_and_power_on(chip);
581+
ret = isl29028_clear_configure_reg(chip);
531582
if (ret < 0)
532583
return ret;
533584

@@ -538,6 +589,11 @@ static int isl29028_probe(struct i2c_client *client,
538589
indio_dev->dev.parent = &client->dev;
539590
indio_dev->modes = INDIO_DIRECT_MODE;
540591

592+
pm_runtime_enable(&client->dev);
593+
pm_runtime_set_autosuspend_delay(&client->dev,
594+
ISL29028_POWER_OFF_DELAY_MS);
595+
pm_runtime_use_autosuspend(&client->dev);
596+
541597
ret = devm_iio_device_register(indio_dev->dev.parent, indio_dev);
542598
if (ret < 0) {
543599
dev_err(&client->dev,
@@ -549,6 +605,50 @@ static int isl29028_probe(struct i2c_client *client,
549605
return 0;
550606
}
551607

608+
static int isl29028_remove(struct i2c_client *client)
609+
{
610+
struct iio_dev *indio_dev = i2c_get_clientdata(client);
611+
struct isl29028_chip *chip = iio_priv(indio_dev);
612+
613+
iio_device_unregister(indio_dev);
614+
615+
pm_runtime_disable(&client->dev);
616+
pm_runtime_set_suspended(&client->dev);
617+
pm_runtime_put_noidle(&client->dev);
618+
619+
return isl29028_clear_configure_reg(chip);
620+
}
621+
622+
static int __maybe_unused isl29028_suspend(struct device *dev)
623+
{
624+
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
625+
struct isl29028_chip *chip = iio_priv(indio_dev);
626+
int ret;
627+
628+
mutex_lock(&chip->lock);
629+
630+
ret = isl29028_clear_configure_reg(chip);
631+
632+
mutex_unlock(&chip->lock);
633+
634+
return ret;
635+
}
636+
637+
static int __maybe_unused isl29028_resume(struct device *dev)
638+
{
639+
/**
640+
* The specific component (ALS/IR or proximity) will enable itself as
641+
* needed the next time that the user requests a reading. This is done
642+
* above in isl29028_set_als_ir_mode() and isl29028_enable_proximity().
643+
*/
644+
return 0;
645+
}
646+
647+
static const struct dev_pm_ops isl29028_pm_ops = {
648+
SET_SYSTEM_SLEEP_PM_OPS(isl29028_suspend, isl29028_resume)
649+
SET_RUNTIME_PM_OPS(isl29028_suspend, isl29028_resume, NULL)
650+
};
651+
552652
static const struct i2c_device_id isl29028_id[] = {
553653
{"isl29028", 0},
554654
{}
@@ -565,9 +665,11 @@ MODULE_DEVICE_TABLE(of, isl29028_of_match);
565665
static struct i2c_driver isl29028_driver = {
566666
.driver = {
567667
.name = "isl29028",
668+
.pm = &isl29028_pm_ops,
568669
.of_match_table = isl29028_of_match,
569670
},
570671
.probe = isl29028_probe,
672+
.remove = isl29028_remove,
571673
.id_table = isl29028_id,
572674
};
573675

0 commit comments

Comments
 (0)