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

Commit 18f4fd88 authored by Bingzhe Cai's avatar Bingzhe Cai
Browse files

input: sensor: power down akm09911 sensor during suspend



To save more power, sensor needs power off during suspend and
sensor GPIOs also need to be properly configured.

CRs-fixed: 655099
Change-Id: Id47160e51a4e14464d66156731d3012eedd184d9
Signed-off-by: default avatarBingzhe Cai <bingzhec@codeaurora.org>
parent dd2d02d4
Loading
Loading
Loading
Loading
+90 −9
Original line number Diff line number Diff line
@@ -41,6 +41,8 @@
#define AKM_DRDY_TIMEOUT_MS		100
#define AKM_BASE_NUM			10

#define AKM_IS_MAG_DATA_ENABLED() (akm->enable_flag & (1 << MAG_DATA_FLAG))

/* POWER SUPPLY VOLTAGE RANGE */
#define AKM09911_VDD_MIN_UV	2000000
#define AKM09911_VDD_MAX_UV	3300000
@@ -49,6 +51,12 @@

#define STATUS_ERROR(st)		(((st)&0x09) != 0x01)

/* Save last device state for power down */
struct akm_sensor_state {
	bool power_on;
	uint8_t mode;
};

struct akm_compass_data {
	struct i2c_client	*i2c;
	struct input_dev	*input;
@@ -59,6 +67,7 @@ struct akm_compass_data {
	struct pinctrl_state	*pin_sleep;
	struct sensors_classdev	cdev;
	struct delayed_work	dwork;
	struct mutex		op_mutex;

	wait_queue_head_t	drdy_wq;
	wait_queue_head_t	open_wq;
@@ -92,6 +101,7 @@ struct akm_compass_data {
	int	auto_report;
	struct regulator	*vdd;
	struct regulator	*vio;
	struct akm_sensor_state state;
};

static struct sensors_classdev sensors_cdev = {
@@ -114,6 +124,7 @@ static struct sensors_classdev sensors_cdev = {

static struct akm_compass_data *s_akm;

static int akm_compass_power_set(struct akm_compass_data *data, bool on);
/***** I2C I/O function ***********************************************/
static int akm_i2c_rxdata(
	struct i2c_client *i2c,
@@ -837,7 +848,7 @@ static void akm_compass_sysfs_update_status(
static int akm_enable_set(struct sensors_classdev *sensors_cdev,
		unsigned int enable)
{

	int ret = 0;
	struct akm_compass_data *akm = container_of(sensors_cdev,
			struct akm_compass_data, cdev);

@@ -847,20 +858,37 @@ static int akm_enable_set(struct sensors_classdev *sensors_cdev,
	mutex_unlock(&akm->val_mutex);

	akm_compass_sysfs_update_status(akm);
	mutex_lock(&akm->op_mutex);
	if (enable) {
		ret = akm_compass_power_set(akm, true);
		if (ret) {
			dev_err(&akm->i2c->dev,
				"Fail to power on the device!\n");
			goto exit;
		}

		if (akm->auto_report) {
		if (enable) {
			AKECS_SetMode(akm, AKM_MODE_SNG_MEASURE);
			schedule_delayed_work(&akm->dwork,
				(unsigned long)nsecs_to_jiffies64(
					akm->delay[MAG_DATA_FLAG]));
		}
	} else {
		if (akm->auto_report) {
			cancel_delayed_work_sync(&akm->dwork);
			AKECS_SetMode(akm, AKM_MODE_POWERDOWN);
		}
		ret = akm_compass_power_set(akm, false);
		if (ret) {
			dev_err(&akm->i2c->dev,
				"Fail to power off the device!\n");
			goto exit;
		}
	}

	return 0;
exit:
	mutex_unlock(&akm->op_mutex);
	return ret;
}

static ssize_t akm_compass_sysfs_enable_show(
@@ -879,6 +907,7 @@ static ssize_t akm_compass_sysfs_enable_store(
	struct akm_compass_data *akm, char const *buf, size_t count, int pos)
{
	long en = 0;
	int ret = 0;

	if (NULL == buf)
		return -EINVAL;
@@ -891,6 +920,13 @@ static ssize_t akm_compass_sysfs_enable_store(

	en = en ? 1 : 0;

	mutex_lock(&akm->op_mutex);
	ret = akm_compass_power_set(akm, en);
	if (ret) {
		dev_err(&akm->i2c->dev,
			"Fail to configure device power!\n");
		goto exit;
	}
	mutex_lock(&akm->val_mutex);
	akm->enable_flag &= ~(1<<pos);
	akm->enable_flag |= ((uint32_t)(en))<<pos;
@@ -898,7 +934,10 @@ static ssize_t akm_compass_sysfs_enable_store(

	akm_compass_sysfs_update_status(akm);

	return count;
exit:
	mutex_unlock(&akm->op_mutex);

	return ret ? ret : count;
}

/***** Acceleration ***/
@@ -1418,17 +1457,56 @@ work_func_none:
static int akm_compass_suspend(struct device *dev)
{
	struct akm_compass_data *akm = dev_get_drvdata(dev);
	int ret = 0;

	if (AKM_IS_MAG_DATA_ENABLED() && akm->auto_report)
		cancel_delayed_work_sync(&akm->dwork);

	akm->state.power_on = akm->power_enabled;
	if (akm->state.power_on)
		akm_compass_power_set(akm, false);

	ret = pinctrl_select_state(akm->pinctrl, akm->pin_sleep);
	if (ret)
		dev_err(dev, "Can't select pinctrl state\n");

	dev_dbg(&akm->i2c->dev, "suspended\n");

	return 0;
	return ret;
}

static int akm_compass_resume(struct device *dev)
{
	struct akm_compass_data *akm = dev_get_drvdata(dev);
	int ret = 0;

	ret = pinctrl_select_state(akm->pinctrl, akm->pin_default);
	if (ret)
		dev_err(dev, "Can't select pinctrl state\n");

	if (akm->state.power_on) {
		ret = akm_compass_power_set(akm, true);
		if (ret) {
			dev_err(dev, "Sensor power resume fail!\n");
			goto exit;
		}

		ret = AKECS_SetMode(akm, akm->state.mode);
		if (ret) {
			dev_err(dev, "Sensor state resume fail!\n");
			goto exit;
		}

		if (AKM_IS_MAG_DATA_ENABLED() && akm->auto_report)
			schedule_delayed_work(&akm->dwork,
				(unsigned long)nsecs_to_jiffies64(
				akm->delay[MAG_DATA_FLAG]));
	}

	dev_dbg(&akm->i2c->dev, "resumed\n");

	return 0;
exit:
	return ret;
}

static int akm09911_i2c_check_device(
@@ -1655,7 +1733,7 @@ static int akm_pinctrl_init(struct akm_compass_data *s_akm)

	s_akm->pin_sleep = pinctrl_lookup_state(s_akm->pinctrl, "sleep");
	if (IS_ERR_OR_NULL(s_akm->pin_sleep)) {
		dev_err(&client->dev, "Failed to look up reset state\n");
		dev_err(&client->dev, "Failed to look up sleep state\n");
		return PTR_ERR(s_akm->pin_sleep);
	}

@@ -1811,6 +1889,7 @@ int akm_compass_probe(struct i2c_client *client, const struct i2c_device_id *id)
	mutex_init(&s_akm->sensor_mutex);
	mutex_init(&s_akm->accel_mutex);
	mutex_init(&s_akm->val_mutex);
	mutex_init(&s_akm->op_mutex);

	atomic_set(&s_akm->active, 0);
	atomic_set(&s_akm->drdy, 0);
@@ -1939,6 +2018,8 @@ int akm_compass_probe(struct i2c_client *client, const struct i2c_device_id *id)
		goto exit8;
	}

	akm_compass_power_set(s_akm, false);

	dev_info(&client->dev, "successfully probed.");
	return 0;