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

Commit 38be2e8f authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "input: sensor: improve apds993x suspend resume procedure"

parents 8bdc8469 303ae994
Loading
Loading
Loading
Loading
+173 −58
Original line number Diff line number Diff line
@@ -211,10 +211,10 @@ struct apds993x_data {
	struct delayed_work	als_dwork;	/* for ALS polling */
	struct input_dev *input_dev_als;
	struct input_dev *input_dev_ps;
	struct regulator *vdd;
	struct regulator *vio;
	struct sensors_classdev als_cdev;
	struct sensors_classdev ps_cdev;

	/* pinctrl data*/
	struct pinctrl *pinctrl;
	struct pinctrl_state *pin_default;
	struct pinctrl_state *pin_sleep;
@@ -222,6 +222,12 @@ struct apds993x_data {
	struct apds993x_platform_data *platform_data;
	int irq;

	/* regulator data */
	bool power_on;
	struct regulator *vdd;
	struct regulator *vio;

	/* register configuration*/
	unsigned int enable;
	unsigned int atime;
	unsigned int ptime;
@@ -239,6 +245,9 @@ struct apds993x_data {
	unsigned int enable_ps_sensor;
	unsigned int enable_als_sensor;

	/* save sensor enabling state for resume */
	unsigned int als_enable_state;

	/* PS parameters */
	unsigned int ps_threshold;
	unsigned int ps_hysteresis_threshold; 	/* always lower than ps_threshold */
@@ -328,6 +337,7 @@ static int apds993x_set_als_poll_delay(struct i2c_client *client, unsigned int v
#endif

static int sensor_regulator_power_on(struct apds993x_data *data, bool on);
static int apds993x_init_device(struct i2c_client *client);

/*
 * Management functions
@@ -1095,6 +1105,8 @@ static irqreturn_t apds993x_interrupt(int vec, void *info)
static int apds993x_enable_als_sensor(struct i2c_client *client, int val)
{
	struct apds993x_data *data = i2c_get_clientdata(client);
	struct apds993x_platform_data *pdata = data->platform_data;
	int rc;

	pr_debug("%s: val=%d\n", __func__, val);

@@ -1105,6 +1117,19 @@ static int apds993x_enable_als_sensor(struct i2c_client *client, int val)

	if (val == 1) {
		/* turn on light  sensor */
		if ((data->enable_als_sensor == 0) &&
			(data->enable_ps_sensor == 0)) {
			/* Power on and initalize the device */
			if (pdata->power_on)
				pdata->power_on(true);

			rc = apds993x_init_device(client);
			if (rc) {
				dev_err(&client->dev, "Failed to init apds993x\n");
				return rc;
			}
		}

		if (data->enable_als_sensor == 0) {
			data->enable_als_sensor = 1;
			/* Power Off */
@@ -1132,6 +1157,8 @@ static int apds993x_enable_als_sensor(struct i2c_client *client, int val)
			} else {
				/* only enable light sensor with interrupt*/
				apds993x_set_enable(client, 0x13);
				if (data->irq)
					enable_irq(data->irq);
			}
#endif

@@ -1177,6 +1204,13 @@ static int apds993x_enable_als_sensor(struct i2c_client *client, int val)
		flush_delayed_work(&data->als_dwork);
#endif
	}

	/* Vote off  regulators if both light and prox sensor are off */
	if ((data->enable_als_sensor == 0) &&
		(data->enable_ps_sensor == 0) &&
		(pdata->power_on))
		pdata->power_on(false);

	return 0;
}

@@ -1228,6 +1262,8 @@ static int apds993x_set_als_poll_delay(struct i2c_client *client,
static int apds993x_enable_ps_sensor(struct i2c_client *client, int val)
{
	struct apds993x_data *data = i2c_get_clientdata(client);
	struct apds993x_platform_data *pdata = data->platform_data;
	int rc;

	pr_debug("%s: val=%d\n", __func__, val);

@@ -1238,6 +1274,19 @@ static int apds993x_enable_ps_sensor(struct i2c_client *client, int val)

	if (val == 1) {
		/* turn on p sensor */
		if ((data->enable_als_sensor == 0) &&
			(data->enable_ps_sensor == 0)) {
			/* Power on and initalize the device */
			if (pdata->power_on)
				pdata->power_on(true);

			rc = apds993x_init_device(client);
			if (rc) {
				dev_err(&client->dev, "Failed to init apds993x\n");
				return rc;
			}
		}

		if (data->enable_ps_sensor==0) {
			data->enable_ps_sensor= 1;

@@ -1255,13 +1304,22 @@ static int apds993x_enable_ps_sensor(struct i2c_client *client, int val)
			if (data->enable_als_sensor==0) {
				/* only enable PS interrupt */
				apds993x_set_enable(client, 0x27);
				if (data->irq) {
					enable_irq(data->irq);
					irq_set_irq_wake(client->irq, 1);
				}
			} else {
#ifdef ALS_POLLING_ENABLED
				/* enable PS interrupt */
				apds993x_set_enable(client, 0x27);
				if (data->irq) {
					enable_irq(data->irq);
					irq_set_irq_wake(client->irq, 1);
				}
#else
				/* enable ALS and PS interrupt */
				apds993x_set_enable(client, 0x37);
				irq_set_irq_wake(client->irq, 1);
#endif
			}
		}
@@ -1275,6 +1333,11 @@ static int apds993x_enable_ps_sensor(struct i2c_client *client, int val)
		if (data->enable_als_sensor) {
#ifdef ALS_POLLING_ENABLED
			/* no ALS interrupt */
			if (data->irq) {
				irq_set_irq_wake(client->irq, 0);
				disable_irq(data->irq);
			}

			apds993x_set_enable(client, 0x03);

			/*
@@ -1291,6 +1354,9 @@ static int apds993x_enable_ps_sensor(struct i2c_client *client, int val)

#else
			/* reconfigute light sensor setting */
			if (data->irq)
				irq_set_irq_wake(client->irq, 0);

			/* Power Off */
			apds993x_set_enable(client,0);
			/* Force ALS interrupt */
@@ -1301,6 +1367,10 @@ static int apds993x_enable_ps_sensor(struct i2c_client *client, int val)
			apds993x_set_enable(client, 0x13);
#endif
		} else {
			if (data->irq) {
				irq_set_irq_wake(client->irq, 0);
				disable_irq(data->irq);
			}
			apds993x_set_enable(client, 0);
#ifdef ALS_POLLING_ENABLED
			/*
@@ -1313,6 +1383,13 @@ static int apds993x_enable_ps_sensor(struct i2c_client *client, int val)
#endif
		}
	}

	/* Vote off  regulators if both light and prox sensor are off */
	if ((data->enable_als_sensor == 0) &&
		(data->enable_ps_sensor == 0) &&
		(pdata->power_on))
		pdata->power_on(false);

	return 0;
}

@@ -1839,20 +1916,10 @@ static struct miscdevice apds993x_als_device = {
	.fops = &apds993x_als_fops,
};

/*
 * Initialization function
 */

static int apds993x_init_client(struct i2c_client *client)
static int apds993x_check_chip_id(struct i2c_client *client)
{
	struct apds993x_data *data = i2c_get_clientdata(client);
	int err;
	int id;

	err = apds993x_set_enable(client, 0);
	if (err < 0)
		return err;

	id = i2c_smbus_read_byte_data(client, CMD_BYTE|APDS993X_ID_REG);
	switch (id) {
	case APDS9931_ID:
@@ -1874,6 +1941,20 @@ static int apds993x_init_client(struct i2c_client *client)
		dev_err(&client->dev, "Neither APDS993x nor APDS990x\n");
		return -ENODEV;
	}
	return 0;
}

/*
 * Initialization function
 */
static int apds993x_init_device(struct i2c_client *client)
{
	struct apds993x_data *data = i2c_get_clientdata(client);
	int err;

	err = apds993x_set_enable(client, 0);
	if (err < 0)
		return err;

	/* 100.64ms ALS integration time */
	err = apds993x_set_atime(client,
@@ -1943,22 +2024,25 @@ static int apds993x_suspend(struct device *dev)
{
	struct apds993x_data *data;
	struct apds993x_platform_data *pdata;
	int rc;

	data = dev_get_drvdata(dev);
	pdata = data->platform_data;

	if (data->irq) {
		irq_set_irq_wake(data->irq, 0);
		disable_irq(data->irq);
	}

	cancel_delayed_work_sync(&data->dwork);
#ifdef ALS_POLLING_ENABLED
	cancel_delayed_work_sync(&data->als_dwork);
#endif
	/*
	  * Save sensor state and disable them,
	  * this is to ensure internal state flags are set correctly.
	  * device will power off after both sensors are disabled.
	  * P sensor will not be disabled because it  is a wakeup sensor.
	*/
	data->als_enable_state = data->enable_als_sensor;

	if (pdata->power_on)
		pdata->power_on(false);
	if (data->als_enable_state) {
		rc = apds993x_enable_als_sensor(data->client, 0);
		if (rc)
			dev_err(&data->client->dev,
				"Disable light sensor fail! rc=%d\n", rc);
	}

	return 0;
}
@@ -1967,22 +2051,17 @@ static int apds993x_resume(struct device *dev)
{
	struct apds993x_data *data;
	struct apds993x_platform_data *pdata;
	int rc;

	data = dev_get_drvdata(dev);
	pdata = data->platform_data;

	if (pdata->power_on)
		pdata->power_on(true);

	if (data->enable_ps_sensor)
		apds993x_ps_set_enable(&data->ps_cdev, 1);

	if (data->enable_als_sensor)
		apds993x_als_set_enable(&data->als_cdev, 1);

	if (data->irq) {
		enable_irq(data->irq);
		irq_set_irq_wake(data->irq, 1);
	/* Resume L sensor state as P sensor does not disable */
	if (data->als_enable_state) {
		rc = apds993x_enable_als_sensor(data->client, 1);
		if (rc)
			dev_err(&data->client->dev,
				"Disable light sensor fail! rc=%d\n", rc);
	}

	return 0;
@@ -2073,7 +2152,18 @@ static int sensor_regulator_power_on(struct apds993x_data *data, bool on)
			dev_err(&data->client->dev,
				"Regulator vio disable failed rc=%d\n", rc);
			rc = regulator_enable(data->vdd);
			dev_err(&data->client->dev,
					"Regulator vio re-enabled rc=%d\n", rc);
			/*
			 * Successfully re-enable regulator.
			 * Enter poweron delay and returns error.
			 */
			if (!rc) {
				rc = -EBUSY;
				goto enable_delay;
			}
		}
		return rc;
	} else {
		rc = regulator_enable(data->vdd);
		if (rc) {
@@ -2086,36 +2176,49 @@ static int sensor_regulator_power_on(struct apds993x_data *data, bool on)
		if (rc) {
			dev_err(&data->client->dev,
				"Regulator vio enable failed rc=%d\n", rc);
			rc = regulator_disable(data->vdd);
			regulator_disable(data->vdd);
			return rc;
		}
	}

enable_delay:
	msleep(130);

	dev_dbg(&data->client->dev,
		"Sensor regulator power on =%d\n", on);
	return rc;
}

static int sensor_platform_hw_power_on(bool on)
{
	int err;
	struct apds993x_data *data;
	int err = 0;

	if (pdev_data == NULL)
		return -ENODEV;

	if (!IS_ERR_OR_NULL(pdev_data->pinctrl)) {
	data = pdev_data;
	if (data->power_on != on) {
		if (!IS_ERR_OR_NULL(data->pinctrl)) {
			if (on)
			err = pinctrl_select_state(pdev_data->pinctrl,
				pdev_data->pin_default);
				err = pinctrl_select_state(data->pinctrl,
					data->pin_default);
			else
			err = pinctrl_select_state(pdev_data->pinctrl,
				pdev_data->pin_sleep);
				err = pinctrl_select_state(data->pinctrl,
					data->pin_sleep);
			if (err)
			dev_err(&pdev_data->client->dev,
				dev_err(&data->client->dev,
					"Can't select pinctrl state\n");
		}
	sensor_regulator_power_on(pdev_data, on);

	return 0;
		err = sensor_regulator_power_on(data, on);
		if (err)
			dev_err(&data->client->dev,
					"Can't configure regulator!\n");
		else
			data->power_on = on;
	}

	return err;
}

static int sensor_platform_hw_init(void)
@@ -2393,21 +2496,30 @@ static int apds993x_probe(struct i2c_client *client,
	INIT_DELAYED_WORK(&data->als_dwork, apds993x_als_polling_work_handler);
#endif

	err = apds993x_check_chip_id(client);
	if (err) {
		dev_err(&client->dev, "Not a valid chip ID\n");
		err = -ENODEV;
		goto exit_uninit;
	}
	/* Initialize the APDS993X chip */
	err = apds993x_init_client(client);
	err = apds993x_init_device(client);
	if (err) {
		pr_err("%s: Failed to init apds993x\n", __func__);
		goto exit_uninit;
	}

	err = request_irq(data->irq, apds993x_interrupt, IRQF_TRIGGER_FALLING,
	if (data->irq) {
		err = request_irq(data->irq, apds993x_interrupt,
					IRQF_TRIGGER_FALLING,
					APDS993X_DRV_NAME, (void *)client);
		if (err < 0) {
		pr_err("%s: Could not allocate APDS993X_INT !\n", __func__);
			dev_err(&client->dev,
				"Could not allocate APDS993X_INT !\n");
			goto exit_uninit;
		}

	irq_set_irq_wake(client->irq, 1);
		disable_irq(data->irq);
	}

	/* Register to Input Device */
	data->input_dev_als = input_allocate_device();
@@ -2489,6 +2601,9 @@ static int apds993x_probe(struct i2c_client *client,
		goto exit_unregister_als_class;
	}

	if (pdata->power_on)
		err = pdata->power_on(false);

	pr_info("%s: Support ver. %s enabled\n", __func__, DRIVER_VERSION);

	return 0;