Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f0e5f57d authored by Adriana Reus's avatar Adriana Reus Committed by Jonathan Cameron
Browse files

iio: light: us8152d: Add power management support



Add power management for sleep as well as runtime pm.

Signed-off-by: default avatarAdriana Reus <adriana.reus@intel.com>
Signed-off-by: default avatarJonathan Cameron <jic23@kernel.org>
parent a22a3c5c
Loading
Loading
Loading
Loading
+88 −7
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/mutex.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>

#define US5182D_REG_CFG0				0x00
#define US5182D_CFG0_ONESHOT_EN				BIT(6)
@@ -81,6 +83,7 @@
#define US5182D_READ_BYTE			1
#define US5182D_READ_WORD			2
#define US5182D_OPSTORE_SLEEP_TIME		20 /* ms */
#define US5182D_SLEEP_MS			3000 /* ms */

/* Available ranges: [12354, 7065, 3998, 2202, 1285, 498, 256, 138] lux */
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)
	return ret;
}


static int us5182d_set_power_state(struct us5182d_data *data, bool on)
{
	int ret;

	if (data->power_mode == US5182D_ONESHOT)
		return 0;

	if (on) {
		ret = pm_runtime_get_sync(&data->client->dev);
		if (ret < 0)
			pm_runtime_put_noidle(&data->client->dev);
	} else {
		pm_runtime_mark_last_busy(&data->client->dev);
		ret = pm_runtime_put_autosuspend(&data->client->dev);
	}

	return ret;
}

static int us5182d_read_raw(struct iio_dev *indio_dev,
			    struct iio_chan_spec const *chan, int *val,
			    int *val2, long mask)
@@ -317,15 +340,20 @@ static int us5182d_read_raw(struct iio_dev *indio_dev,
				if (ret < 0)
					goto out_err;
			}
			ret = us5182d_als_enable(data);
			ret = us5182d_set_power_state(data, true);
			if (ret < 0)
				goto out_err;

			ret = us5182d_als_enable(data);
			if (ret < 0)
				goto out_poweroff;
			ret = us5182d_get_als(data);
			if (ret < 0)
				goto out_poweroff;
			*val = ret;
			ret = us5182d_set_power_state(data, false);
			if (ret < 0)
				goto out_err;
			mutex_unlock(&data->lock);
			*val = ret;
			return IIO_VAL_INT;
		case IIO_PROXIMITY:
			mutex_lock(&data->lock);
@@ -334,16 +362,21 @@ static int us5182d_read_raw(struct iio_dev *indio_dev,
				if (ret < 0)
					goto out_err;
			}
			ret = us5182d_px_enable(data);
			ret = us5182d_set_power_state(data, true);
			if (ret < 0)
				goto out_err;

			ret = us5182d_px_enable(data);
			if (ret < 0)
				goto out_poweroff;
			ret = i2c_smbus_read_word_data(data->client,
						       US5182D_REG_PDL);
			if (ret < 0)
				goto out_poweroff;
			*val = ret;
			ret = us5182d_set_power_state(data, false);
			if (ret < 0)
				goto out_err;
			mutex_unlock(&data->lock);
			*val = ret;
			return IIO_VAL_INT;
		default:
			return -EINVAL;
@@ -363,6 +396,9 @@ static int us5182d_read_raw(struct iio_dev *indio_dev,
	}

	return -EINVAL;

out_poweroff:
	us5182d_set_power_state(data, false);
out_err:
	mutex_unlock(&data->lock);
	return ret;
@@ -579,6 +615,17 @@ static int us5182d_probe(struct i2c_client *client,
	if (ret < 0)
		goto out_err;

	if (data->default_continuous) {
		pm_runtime_set_active(&client->dev);
		if (ret < 0)
			goto out_err;
	}

	pm_runtime_enable(&client->dev);
	pm_runtime_set_autosuspend_delay(&client->dev,
					 US5182D_SLEEP_MS);
	pm_runtime_use_autosuspend(&client->dev);

	ret = iio_device_register(indio_dev);
	if (ret < 0)
		goto out_err;
@@ -597,9 +644,42 @@ static int us5182d_remove(struct i2c_client *client)

	iio_device_unregister(i2c_get_clientdata(client));

	pm_runtime_disable(&client->dev);
	pm_runtime_set_suspended(&client->dev);

	return us5182d_shutdown_en(data, US5182D_CFG0_SHUTDOWN_EN);
}

#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM)
static int us5182d_suspend(struct device *dev)
{
	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
	struct us5182d_data *data = iio_priv(indio_dev);

	if (data->power_mode == US5182D_CONTINUOUS)
		return us5182d_shutdown_en(data, US5182D_CFG0_SHUTDOWN_EN);

	return 0;
}

static int us5182d_resume(struct device *dev)
{
	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
	struct us5182d_data *data = iio_priv(indio_dev);

	if (data->power_mode == US5182D_CONTINUOUS)
		return us5182d_shutdown_en(data,
					   ~US5182D_CFG0_SHUTDOWN_EN & 0xff);

	return 0;
}
#endif

static const struct dev_pm_ops us5182d_pm_ops = {
	SET_SYSTEM_SLEEP_PM_OPS(us5182d_suspend, us5182d_resume)
	SET_RUNTIME_PM_OPS(us5182d_suspend, us5182d_resume, NULL)
};

static const struct acpi_device_id us5182d_acpi_match[] = {
	{ "USD5182", 0},
	{}
@@ -617,6 +697,7 @@ MODULE_DEVICE_TABLE(i2c, us5182d_id);
static struct i2c_driver us5182d_driver = {
	.driver = {
		.name = US5182D_DRV_NAME,
		.pm = &us5182d_pm_ops,
		.acpi_match_table = ACPI_PTR(us5182d_acpi_match),
	},
	.probe = us5182d_probe,