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

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

Merge "input: sensors: add auto report support for akm09911"

parents 49cae9d7 3a5ceb2d
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -22,6 +22,10 @@ Required properties:
	8: 1st pin is right down (from top view)
 - akm,gpio_rstn	: The gpio pin to reset the sensor chip.

Optional properites:

 - akm,auto-report	: Enable auto-report mode.

 Example:
	akm@c {
			compatible = "ak,ak09911";
@@ -33,5 +37,6 @@ Required properties:
			vio-supply = <&pm8110_l14>;
			akm,layout = <0x0>;
			akm,gpio_rstn = <&msmgpio 82 0x0>;
			akm,auto-report;
	};
+120 −4
Original line number Diff line number Diff line
@@ -47,6 +47,8 @@
#define AKM09911_VIO_MIN_UV	1750000
#define AKM09911_VIO_MAX_UV	1950000

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

struct akm_compass_data {
	struct i2c_client	*i2c;
	struct input_dev	*input;
@@ -56,6 +58,7 @@ struct akm_compass_data {
	struct pinctrl_state	*pin_default;
	struct pinctrl_state	*pin_sleep;
	struct sensors_classdev	cdev;
	struct delayed_work	dwork;

	wait_queue_head_t	drdy_wq;
	wait_queue_head_t	open_wq;
@@ -86,6 +89,7 @@ struct akm_compass_data {
	int	irq;
	int	gpio_rstn;
	int	power_enabled;
	int	auto_report;
	struct regulator	*vdd;
	struct regulator	*vio;
};
@@ -844,6 +848,18 @@ static int akm_enable_set(struct sensors_classdev *sensors_cdev,

	akm_compass_sysfs_update_status(akm);

	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 {
			cancel_delayed_work_sync(&akm->dwork);
			AKECS_SetMode(akm, AKM_MODE_POWERDOWN);
		}
	}

	return 0;
}

@@ -1556,6 +1572,11 @@ static int akm_compass_parse_dt(struct device *dev,
		s_akm->layout = temp_val;
	}

	if (of_property_read_bool(np, "akm,auto-report"))
		s_akm->auto_report = 1;
	else
		s_akm->auto_report = 0;

	s_akm->gpio_rstn = of_get_named_gpio_flags(dev->of_node,
			"akm,gpio_rstn", 0, NULL);

@@ -1600,6 +1621,96 @@ static int akm_pinctrl_init(struct akm_compass_data *s_akm)
	return 0;
}

static void akm_dev_poll(struct work_struct *work)
{
	struct akm_compass_data *akm;
	uint8_t dat_buf[AKM_SENSOR_DATA_SIZE];/* for GET_DATA */
	int ret;
	int mag_x, mag_y, mag_z;
	int tmp;

	akm = container_of((struct delayed_work *)work,
			struct akm_compass_data,  dwork);
	ret = AKECS_GetData_Poll(akm, dat_buf, AKM_SENSOR_DATA_SIZE);
	if (ret < 0) {
		dev_warn(&s_akm->i2c->dev, "Get data failed\n");
		goto exit;
	}

	tmp = dat_buf[0] | dat_buf[7];
	if (STATUS_ERROR(tmp)) {
		dev_warn(&s_akm->i2c->dev, "Status error(0x%x). Reset...\n",
			       tmp);
		AKECS_Reset(akm, 0);
		goto exit;
	}

	tmp = (int)((int16_t)(dat_buf[2]<<8)+((int16_t)dat_buf[1]));
	tmp = tmp * akm->sense_conf[0] / 256 + tmp / 2;
	mag_x = tmp;

	tmp = (int)((int16_t)(dat_buf[4]<<8)+((int16_t)dat_buf[3]));
	tmp = tmp * akm->sense_conf[1] / 256 + tmp / 2;
	mag_y = tmp;

	tmp = (int)((int16_t)(dat_buf[6]<<8)+((int16_t)dat_buf[5]));
	tmp = tmp * akm->sense_conf[2] / 256 + tmp / 2;
	mag_z = tmp;

	switch (akm->layout) {
	case 0:
	case 1:
		/* Fall into the default direction */
		break;
	case 2:
		tmp = mag_x;
		mag_x = mag_y;
		mag_y = -tmp;
		break;
	case 3:
		mag_x = -mag_x;
		mag_y = -mag_y;
		break;
	case 4:
		tmp = mag_x;
		mag_x = -mag_y;
		mag_y = tmp;
		break;
	case 5:
		mag_x = -mag_x;
		mag_z = -mag_z;
		break;
	case 6:
		tmp = mag_x;
		mag_x = mag_y;
		mag_y = tmp;
		mag_z = -mag_z;
		break;
	case 7:
		mag_y = -mag_y;
		mag_z = -mag_z;
		break;
	case 8:
		tmp = mag_x;
		mag_x = -mag_y;
		mag_y = -tmp;
		mag_z = -mag_z;
		break;
	}

	input_report_abs(akm->input, ABS_X, mag_x);
	input_report_abs(akm->input, ABS_Y, mag_y);
	input_report_abs(akm->input, ABS_Z, mag_z);
	input_report_abs(akm->input, ABS_MISC, 3);
exit:
	ret = AKECS_SetMode(akm, AKM_MODE_SNG_MEASURE);
	if (ret < 0)
		dev_warn(&s_akm->i2c->dev, "Failed to set mode\n");

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

int akm_compass_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	struct akm09911_platform_data *pdata;
@@ -1722,6 +1833,8 @@ int akm_compass_probe(struct i2c_client *client, const struct i2c_device_id *id)
				"%s: request irq failed.", __func__);
			goto exit4;
		}
	} else if (s_akm->auto_report) {
		INIT_DELAYED_WORK(&s_akm->dwork, akm_dev_poll);
	}

	/***** misc *****/
@@ -1743,6 +1856,9 @@ int akm_compass_probe(struct i2c_client *client, const struct i2c_device_id *id)
	s_akm->cdev = sensors_cdev;
	s_akm->cdev.sensors_enable = akm_enable_set;
	s_akm->cdev.sensors_poll_delay = akm_poll_delay_set;

	s_akm->delay[MAG_DATA_FLAG] = sensors_cdev.delay_msec * 1000000;

	err = sensors_classdev_register(&client->dev, &s_akm->cdev);

	if (err) {