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

Commit 8e5f0b85 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: power up the apds993x sensor chip"

parents be3b3b79 d01b9d19
Loading
Loading
Loading
Loading
+39 −0
Original line number Diff line number Diff line
Avago apds993x ambient light + proximity combo driver

Required properties:

 - compatible					: Should be "avago,apds9930".
 - reg							: i2c slave address of the device.
 - interrupt-parent				: Parent of interrupt.
 - interupts					: L/P sample interrupt to indicate new data ready.
 - vdd-supply					: Power supply needed to power up the device.
 - vio-supply					: IO power supply needed for IO and I2C.
 - avago,irq-gpio				: The gpio pin for the interrupt.
 - avago,ps_threshold			: The threshold adc value for proximity sensor to trigger away interrupt.
 - avago,ps_hysteresis_threshold: The hysteresis threshold adc value for proximity sensor to trigger  close interrupt.
 - avago,ps_pulse				: The proximity pulse that the LDR will generate.
 - avago,ps_gain				: The proximity gain of the sensor.
 - avago,als_B					: Tunning value of COE_B parameter.
 - avago,als_C					: Tunning value of COE_C parameter.
 - avago,als_D					: Tunning value of COE_D parameter.
 - avago,ga_value				: Tunning value of the gain for light sensor.

 Example:

	 avago@39 {
		 compatible = "avago,apds9930";
		 reg = <0x39>;
		 interrupt-parent = <&msmgpio>;
		 interrupts = <80 0x2>;
		 vdd-supply = <&pm8110_l19>;
		 vio-supply = <&pm8110_l14>;
		 avago,irq-gpio = <&msmgpio 80 0x2>;
		 avago,ps_threshold = <600>;
		 avago,ps_hysteresis_threshold = <500>;
		 avago,ps_pulse = <8>;
		 avago,ps_pgain = <0>;
		 avago,als_B = <223>;
		 avago,als_C = <70>;
		 avago,als_D = <142>;
		 avago,ga_value = <48>;
	 };
+105 −185
Original line number Diff line number Diff line
@@ -41,8 +41,6 @@
#define APDS993X_DRV_NAME	"apds993x"
#define DRIVER_VERSION		"1.0.0"

#define ABS_LIGHT	0x29	/* added to support LIGHT - light sensor */

#define ALS_POLLING_ENABLED

#define APDS993X_PS_DETECTION_THRESHOLD		800
@@ -206,6 +204,8 @@ 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 apds993x_platform_data *platform_data;
	int irq;
@@ -766,7 +766,7 @@ static void apds993x_change_als_threshold(struct i2c_client *client)

	if (lux_is_valid) {
		/* report the lux level */
		input_report_abs(data->input_dev_als, ABS_LIGHT, luxValue);
		input_report_abs(data->input_dev_als, ABS_MISC, luxValue);
		input_sync(data->input_dev_als);
	}

@@ -834,7 +834,7 @@ static void apds993x_reschedule_work(struct apds993x_data *data,
	 * If work is already scheduled then subsequent schedules will not
	 * change the scheduled time that's why we have to cancel it first.
	 */
	__cancel_delayed_work(&data->dwork);
	cancel_delayed_work(&data->dwork);
	queue_delayed_work(apds993x_workqueue, &data->dwork, delay);
}

@@ -914,7 +914,7 @@ static void apds993x_als_polling_work_handler(struct work_struct *work)

	if (lux_is_valid) {
		/* report the lux level */
		input_report_abs(data->input_dev_als, ABS_LIGHT, luxValue);
		input_report_abs(data->input_dev_als, ABS_MISC, luxValue);
		input_sync(data->input_dev_als);
	}

@@ -1093,7 +1093,7 @@ static int apds993x_enable_als_sensor(struct i2c_client *client, int val)
			 * schedules will not change the scheduled time
			 * that's why we have to cancel it first.
			 */
			__cancel_delayed_work(&data->als_dwork);
			cancel_delayed_work(&data->als_dwork);
			flush_delayed_work(&data->als_dwork);
			queue_delayed_work(apds993x_workqueue, &data->als_dwork, msecs_to_jiffies(data->als_poll_delay));
#endif
@@ -1125,7 +1125,7 @@ static int apds993x_enable_als_sensor(struct i2c_client *client, int val)
		 * will not change the scheduled time that's why we have
		 * to cancel it first.
		 */
		__cancel_delayed_work(&data->als_dwork);
		cancel_delayed_work(&data->als_dwork);
		flush_delayed_work(&data->als_dwork);
#endif
	}
@@ -1169,7 +1169,7 @@ static int apds993x_set_als_poll_delay(struct i2c_client *client,
	 * If work is already scheduled then subsequent schedules will not
	 * change the scheduled time that's why we have to cancel it first.
	 */
	__cancel_delayed_work(&data->als_dwork);
	cancel_delayed_work(&data->als_dwork);
	flush_delayed_work(&data->als_dwork);
	queue_delayed_work(apds993x_workqueue,
			&data->als_dwork,
@@ -1235,7 +1235,7 @@ static int apds993x_enable_ps_sensor(struct i2c_client *client, int val)
			 * schedules will not change the scheduled time
			 * that's why we have to cancel it first.
			 */
			__cancel_delayed_work(&data->als_dwork);
			cancel_delayed_work(&data->als_dwork);
			flush_delayed_work(&data->als_dwork);
			/* 100ms */
			queue_delayed_work(apds993x_workqueue,
@@ -1261,7 +1261,7 @@ static int apds993x_enable_ps_sensor(struct i2c_client *client, int val)
			 * schedules will not change the scheduled time
			 * that's why we have to cancel it first.
			 */
			__cancel_delayed_work(&data->als_dwork);
			cancel_delayed_work(&data->als_dwork);
			flush_delayed_work(&data->als_dwork);
#endif
		}
@@ -1863,208 +1863,127 @@ static int apds993x_resume(struct device *dev)
	return 0;
}

static int reg_set_optimum_mode_check(struct regulator *reg, int load_uA)
{
	return (regulator_count_voltages(reg) > 0) ?
			regulator_set_optimum_mode(reg, load_uA) : 0;
}

static int sensor_regulator_configure(struct apds993x_data *data, bool on)
{
	struct i2c_client *client = data->client;
	struct apds993x_platform_data *pdata = data->platform_data;
	int rc;

	if (on == false)
		goto hw_shutdown;
	if (!on) {
		if (regulator_count_voltages(data->vdd) > 0)
			regulator_set_voltage(data->vdd, 0,
				APDS993X_VDD_MAX_UV);

		regulator_put(data->vdd);
		regulator_disable(data->vdd);

	pdata->vcc_ana = regulator_get(&client->dev, "avago,vdd_ana");
	if (IS_ERR(pdata->vcc_ana)) {
		rc = PTR_ERR(pdata->vcc_ana);
		dev_err(&client->dev,
			"Regulator get failed vcc_ana rc=%d\n", rc);
		if (regulator_count_voltages(data->vio) > 0)
			regulator_set_voltage(data->vio, 0,
				APDS993X_VIO_MAX_UV);

		regulator_put(data->vio);
		regulator_disable(data->vio);

	} else {
		data->vdd = regulator_get(&data->client->dev, "vdd");
		if (IS_ERR(data->vdd)) {
			rc = PTR_ERR(data->vdd);
			dev_err(&data->client->dev,
				"Regulator get failed vdd rc=%d\n", rc);
			return rc;
		}

	if (regulator_count_voltages(pdata->vcc_ana) > 0) {
		rc = regulator_set_voltage(pdata->vcc_ana, AVDD_VTG_MIN_UV,
			AVDD_VTG_MAX_UV);
		if (regulator_count_voltages(data->vdd) > 0) {
			rc = regulator_set_voltage(data->vdd,
				APDS993X_VDD_MIN_UV, APDS993X_VDD_MAX_UV);
			if (rc) {
			dev_err(&client->dev,
				"regulator set_vtg failed rc=%d\n", rc);
			goto error_set_vtg_vcc_ana;
		}
				dev_err(&data->client->dev,
					"Regulator set failed vdd rc=%d\n",
					rc);
				goto reg_vdd_put;
			}

	if (pdata->digital_pwr_regulator) {
		pdata->vcc_dig = regulator_get(&client->dev, "avago,vddio_dig");
		if (IS_ERR(pdata->vcc_dig)) {
			rc = PTR_ERR(pdata->vcc_dig);
			dev_err(&client->dev,
				"Regulator get dig failed rc=%d\n", rc);
			goto error_get_vtg_vcc_dig;
		}

		if (regulator_count_voltages(pdata->vcc_dig) > 0) {
			rc = regulator_set_voltage(pdata->vcc_dig,
					VDDIO_VTG_DIG_MIN_UV, VDDIO_VTG_DIG_MAX_UV);
		rc = regulator_enable(data->vdd);
		if (rc) {
				dev_err(&client->dev,
					"regulator set_vtg failed rc=%d\n", rc);
				goto error_set_vtg_vcc_dig;
			}
		}
			dev_err(&data->client->dev,
				"Regulator enable vdd failed. rc=%d\n", rc);
			goto reg_vdd_put;
		}

	if (pdata->i2c_pull_up) {
		pdata->vcc_i2c = regulator_get(&client->dev, "avago,vddio_i2c");
		if (IS_ERR(pdata->vcc_i2c)) {
			rc = PTR_ERR(pdata->vcc_i2c);
			dev_err(&client->dev,
				"Regulator get failed rc=%d\n", rc);
			goto error_get_vtg_i2c;
		data->vio = regulator_get(&data->client->dev, "vio");
		if (IS_ERR(data->vio)) {
			rc = PTR_ERR(data->vio);
			dev_err(&data->client->dev,
				"Regulator get failed vio rc=%d\n", rc);
			goto reg_vdd_set;
		}
		if (regulator_count_voltages(pdata->vcc_i2c) > 0) {
			rc = regulator_set_voltage(pdata->vcc_i2c,
						   VDDIO_I2C_VTG_MIN_UV,
						   VDDIO_I2C_VTG_MAX_UV);

		if (regulator_count_voltages(data->vio) > 0) {
			rc = regulator_set_voltage(data->vio,
				APDS993X_VIO_MIN_UV, APDS993X_VIO_MAX_UV);
			if (rc) {
				dev_err(&client->dev,
					"regulator set_vtg failed rc=%d\n", rc);
				goto error_set_vtg_i2c;
				dev_err(&data->client->dev,
				"Regulator set failed vio rc=%d\n", rc);
				goto reg_vio_put;
			}
		}
		rc = regulator_enable(data->vio);
		if (rc) {
			dev_err(&data->client->dev,
				"Regulator enable vio failed. rc=%d\n", rc);
			goto reg_vio_put;
		}
	}

	return 0;

error_set_vtg_i2c:
	regulator_put(pdata->vcc_i2c);
error_get_vtg_i2c:
	if (pdata->digital_pwr_regulator)
		if (regulator_count_voltages(pdata->vcc_dig) > 0)
			regulator_set_voltage(pdata->vcc_dig, 0,
						  VDDIO_VTG_DIG_MAX_UV);
error_set_vtg_vcc_dig:
	if (pdata->digital_pwr_regulator)
		regulator_put(pdata->vcc_dig);
error_get_vtg_vcc_dig:
	if (regulator_count_voltages(pdata->vcc_ana) > 0)
		regulator_set_voltage(pdata->vcc_ana, 0, AVDD_VTG_MAX_UV);
error_set_vtg_vcc_ana:
	regulator_put(pdata->vcc_ana);
reg_vio_put:
	regulator_put(data->vio);

reg_vdd_set:
	if (regulator_count_voltages(data->vdd) > 0)
		regulator_set_voltage(data->vdd, 0, APDS993X_VDD_MAX_UV);
reg_vdd_put:
	regulator_put(data->vdd);
	return rc;

hw_shutdown:
	if (regulator_count_voltages(pdata->vcc_ana) > 0)
		regulator_set_voltage(pdata->vcc_ana, 0, AVDD_VTG_MAX_UV);
	regulator_put(pdata->vcc_ana);
	if (pdata->digital_pwr_regulator) {
		if (regulator_count_voltages(pdata->vcc_dig) > 0)
			regulator_set_voltage(pdata->vcc_dig, 0,
						  VDDIO_VTG_DIG_MAX_UV);
		regulator_put(pdata->vcc_dig);
	}
	if (pdata->i2c_pull_up) {
		if (regulator_count_voltages(pdata->vcc_i2c) > 0)
			regulator_set_voltage(pdata->vcc_i2c, 0,
						  VDDIO_I2C_VTG_MAX_UV);
		regulator_put(pdata->vcc_i2c);
	}
	return 0;
}


static int sensor_regulator_power_on(struct apds993x_data *data, bool on)
{
	struct i2c_client *client = data->client;
	struct apds993x_platform_data *pdata = data->platform_data;
	int rc;

	if (on == false)
		goto power_off;
	int rc = 0;

	rc = reg_set_optimum_mode_check(pdata->vcc_ana, AVDD_ACTIVE_LOAD_UA);
	if (rc < 0) {
		dev_err(&client->dev,
			"Regulator vcc_ana set_opt failed rc=%d\n", rc);
	if (!on) {
		rc = regulator_disable(data->vdd);
		if (rc) {
			dev_err(&data->client->dev,
				"Regulator vdd disable failed rc=%d\n", rc);
			return rc;
		}

	rc = regulator_enable(pdata->vcc_ana);
		rc = regulator_disable(data->vio);
		if (rc) {
		dev_err(&client->dev,
			"Regulator vcc_ana enable failed rc=%d\n", rc);
		goto error_reg_en_vcc_ana;
			dev_err(&data->client->dev,
				"Regulator vio disable failed rc=%d\n", rc);
			rc = regulator_enable(data->vdd);
		}

	if (pdata->digital_pwr_regulator) {
		rc = reg_set_optimum_mode_check(pdata->vcc_dig,
						VDDIO_ACTIVE_LOAD_DIG_UA);
		if (rc < 0) {
			dev_err(&client->dev,
				"Regulator vcc_dig set_opt failed rc=%d\n",
				rc);
			goto error_reg_opt_vcc_dig;
		}

		rc = regulator_enable(pdata->vcc_dig);
	} else {
		rc = regulator_enable(data->vdd);
		if (rc) {
			dev_err(&client->dev,
				"Regulator vcc_dig enable failed rc=%d\n", rc);
			goto error_reg_en_vcc_dig;
		}
	}

	if (pdata->i2c_pull_up) {
		rc = reg_set_optimum_mode_check(pdata->vcc_i2c,
				VDDIO_I2C_LOAD_UA);
		if (rc < 0) {
			dev_err(&client->dev,
				"Regulator vcc_i2c set_opt failed rc=%d\n", rc);
			goto error_reg_opt_i2c;
			dev_err(&data->client->dev,
				"Regulator vdd enable failed rc=%d\n", rc);
			return rc;
		}

		rc = regulator_enable(pdata->vcc_i2c);
		rc = regulator_enable(data->vio);
		if (rc) {
			dev_err(&client->dev,
				"Regulator vcc_i2c enable failed rc=%d\n", rc);
			goto error_reg_en_vcc_i2c;
			dev_err(&data->client->dev,
				"Regulator vio enable failed rc=%d\n", rc);
			rc = regulator_disable(data->vdd);
		}
	}

	msleep(130);

	return 0;

error_reg_en_vcc_i2c:
	if (pdata->i2c_pull_up)
		reg_set_optimum_mode_check(pdata->vcc_i2c, 0);
error_reg_opt_i2c:
	if (pdata->digital_pwr_regulator)
		regulator_disable(pdata->vcc_dig);
error_reg_en_vcc_dig:
	if (pdata->digital_pwr_regulator)
		reg_set_optimum_mode_check(pdata->vcc_dig, 0);
error_reg_opt_vcc_dig:
	regulator_disable(pdata->vcc_ana);
error_reg_en_vcc_ana:
	reg_set_optimum_mode_check(pdata->vcc_ana, 0);
	return rc;

power_off:
	reg_set_optimum_mode_check(pdata->vcc_ana, 0);
	regulator_disable(pdata->vcc_ana);
	if (pdata->digital_pwr_regulator) {
		reg_set_optimum_mode_check(pdata->vcc_dig, 0);
		regulator_disable(pdata->vcc_dig);
	}
	if (pdata->i2c_pull_up) {
		reg_set_optimum_mode_check(pdata->vcc_i2c, 0);
		regulator_disable(pdata->vcc_i2c);
	}
	msleep(50);
	return 0;
}

static int sensor_platform_hw_power_on(bool on)
@@ -2096,7 +2015,7 @@ static int sensor_platform_hw_init(void)
	}

	if (gpio_is_valid(data->platform_data->irq_gpio)) {
		/* configure touchscreen irq gpio */
		/* configure apds993x irq gpio */
		error = gpio_request_one(data->platform_data->irq_gpio,
				GPIOF_DIR_IN,
				"apds993x_irq_gpio");
@@ -2130,21 +2049,22 @@ static int sensor_parse_dt(struct device *dev,
{
	struct device_node *np = dev->of_node;
	unsigned int tmp;
	int rc;

	/* regulator info */
	pdata->i2c_pull_up = of_property_read_bool(np, "avago,i2c-pull-up");
	pdata->digital_pwr_regulator = NULL;

	/* reset, irq gpio info */
	pdata->irq_gpio = of_get_named_gpio_flags(np, "avago,irq-gpio",
			0, &pdata->irq_gpio_flags);
	int rc = 0;

	/* set functions of platform data */
	pdata->init = sensor_platform_hw_init;
	pdata->exit = sensor_platform_hw_exit;
	pdata->power_on = sensor_platform_hw_power_on;

	/* irq gpio */
	rc = of_get_named_gpio_flags(dev->of_node,
			"avago,irq-gpio", 0, NULL);
	if (rc < 0) {
		dev_err(dev, "Unable to read irq gpio\n");
		return rc;
	}
	pdata->irq_gpio = rc;

	/* ps tuning data*/
	rc = of_property_read_u32(np, "avago,ps_threshold", &tmp);
	if (rc) {
@@ -2345,11 +2265,11 @@ static int apds993x_probe(struct i2c_client *client,
	set_bit(EV_ABS, data->input_dev_als->evbit);
	set_bit(EV_ABS, data->input_dev_ps->evbit);

	input_set_abs_params(data->input_dev_als, ABS_LIGHT, 0, 30000, 0, 0);
	input_set_abs_params(data->input_dev_als, ABS_MISC, 0, 30000, 0, 0);
	input_set_abs_params(data->input_dev_ps, ABS_DISTANCE, 0, 5, 0, 0);

	data->input_dev_als->name = "Avago light sensor";
	data->input_dev_ps->name = "Avago proximity sensor";
	data->input_dev_als->name = "light";
	data->input_dev_ps->name = "proximity";

	err = input_register_device(data->input_dev_als);
	if (err) {
+6 −4
Original line number Diff line number Diff line
@@ -67,6 +67,12 @@ struct apds993x_chip_factors {
 *
 */

/* POWER SUPPLY VOLTAGE RANGE */
#define APDS993X_VDD_MIN_UV  2000000
#define APDS993X_VDD_MAX_UV  3300000
#define APDS993X_VIO_MIN_UV  1750000
#define APDS993X_VIO_MAX_UV  1950000

/* Analog voltage @2.7 V */
#define AVDD_VTG_MIN_UV		3000000
#define AVDD_VTG_MAX_UV		3000000
@@ -113,10 +119,6 @@ struct apds993x_platform_data {

	unsigned int irq_gpio;
	u32 irq_gpio_flags;

	struct regulator *vcc_ana;
	struct regulator *vcc_dig;
	struct regulator *vcc_i2c;
};

#endif