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

Commit 4104c0f4 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "input: touchscreen: focaltech: toggle reset gpio during error"

parents 8b249d7c 88af9a72
Loading
Loading
Loading
Loading
+436 −153
Original line number Diff line number Diff line
@@ -100,6 +100,8 @@ static int fts_ts_probe_delayed(struct fts_ts_data *fts_data);

#ifdef CONFIG_FTS_TRUSTED_TOUCH

static void fts_ts_trusted_touch_abort_handler(struct fts_ts_data *fts_data,
						int error);
static struct hh_acl_desc *fts_ts_vm_get_acl(enum hh_vm_names vm_name)
{
	struct hh_acl_desc *acl_desc;
@@ -241,7 +243,71 @@ static void fts_ts_vm_deinit(struct fts_ts_data *fts_data)

#ifdef CONFIG_ARCH_QTI_VM
static int fts_ts_vm_mem_release(struct fts_ts_data *fts_data);
static void fts_ts_trusted_touch_vm_mode_disable(struct fts_ts_data *fts_data);
static void fts_ts_trusted_touch_tvm_vm_mode_disable(struct fts_ts_data *fts_data);
static void fts_ts_trusted_touch_abort_tvm(struct fts_ts_data *fts_data);
static void fts_ts_trusted_touch_event_notify(struct fts_ts_data *fts_data, int event);

void fts_ts_trusted_touch_tvm_i2c_failure_report(struct fts_ts_data *fts_data)
{
	pr_err("initiating trusted touch abort due to i2c failure\n");
	fts_ts_trusted_touch_abort_handler(fts_data,
			TRUSTED_TOUCH_EVENT_I2C_FAILURE);
}

static void fts_ts_trusted_touch_reset_gpio_toggle(struct fts_ts_data *fts_data)
{
	void __iomem *base;

	base = ioremap(TOUCH_RESET_GPIO_BASE, TOUCH_RESET_GPIO_SIZE);
	writel_relaxed(0x1, base + TOUCH_RESET_GPIO_OFFSET);
	/* wait until toggle to finish*/
	wmb();
	writel_relaxed(0x0, base + TOUCH_RESET_GPIO_OFFSET);
	/* wait until toggle to finish*/
	wmb();
	iounmap(base);
}

static void fts_trusted_touch_intr_gpio_toggle(struct fts_ts_data *fts_data,
		bool enable)
{
	void __iomem *base;
	u32 val;

	base = ioremap(TOUCH_INTR_GPIO_BASE, TOUCH_INTR_GPIO_SIZE);
	val = readl_relaxed(base + TOUCH_RESET_GPIO_OFFSET);
	if (enable) {
		val |= BIT(0);
		writel_relaxed(val, base + TOUCH_INTR_GPIO_OFFSET);
		/* wait until toggle to finish*/
		wmb();
	} else {
		val &= ~BIT(0);
		writel_relaxed(val, base + TOUCH_INTR_GPIO_OFFSET);
		/* wait until toggle to finish*/
		wmb();
	}
	iounmap(base);
}

static int fts_ts_trusted_touch_get_tvm_driver_state(struct fts_ts_data *fts_data)
{
	int state;

	mutex_lock(&fts_data->vm_info->tvm_state_mutex);
	state = atomic_read(&fts_data->vm_info->tvm_state);
	mutex_unlock(&fts_data->vm_info->tvm_state_mutex);

	return state;
}

static void fts_ts_trusted_touch_set_tvm_driver_state(struct fts_ts_data *fts_data,
						int state)
{
	mutex_lock(&fts_data->vm_info->tvm_state_mutex);
	atomic_set(&fts_data->vm_info->tvm_state, state);
	mutex_unlock(&fts_data->vm_info->tvm_state_mutex);
}

static int fts_ts_sgl_cmp(const void *a, const void *b)
{
@@ -293,69 +359,131 @@ static int fts_ts_vm_handle_vm_hardware(struct fts_ts_data *fts_data)
	}

	fts_irq_enable();
	fts_ts_trusted_touch_set_tvm_driver_state(fts_data, TVM_INTERRUPT_ENABLED);
	return rc;
}

static void fts_ts_vm_irq_on_lend_callback(void *data,
					unsigned long notif_type,
					enum hh_irq_label label)
static void fts_ts_trusted_touch_tvm_vm_mode_enable(struct fts_ts_data *fts_data)
{
	struct fts_ts_data *fts_data = data;

	struct hh_sgl_desc *sgl_desc, *expected_sgl_desc;
	struct hh_acl_desc *acl_desc;
	struct irq_data *irq_data;
	int irq = 0;
	int const resource_timeout = msecs_to_jiffies(2000);
	int rc = 0;
	int irq = 0;

	irq = hh_irq_accept(fts_data->vm_info->irq_label, -1,
						IRQ_TYPE_EDGE_RISING);
	if (fts_ts_trusted_touch_get_tvm_driver_state(fts_data) !=
					TVM_ALL_RESOURCES_LENT_NOTIFIED) {
		pr_err("All lend notifications not received\n");
		fts_ts_trusted_touch_event_notify(fts_data,
				TRUSTED_TOUCH_EVENT_NOTIFICATIONS_PENDING);
		return;
	}

	acl_desc = fts_ts_vm_get_acl(HH_TRUSTED_VM);
	if (IS_ERR(acl_desc)) {
		pr_err("failed to populated acl data:rc=%d\n",
				PTR_ERR(acl_desc));
		goto accept_fail;
	}

	sgl_desc = hh_rm_mem_accept(fts_data->vm_info->vm_mem_handle,
			HH_RM_MEM_TYPE_IO,
			HH_RM_TRANS_TYPE_LEND,
			HH_RM_MEM_ACCEPT_VALIDATE_ACL_ATTRS |
			HH_RM_MEM_ACCEPT_VALIDATE_LABEL |
			HH_RM_MEM_ACCEPT_DONE,  TRUSTED_TOUCH_MEM_LABEL,
			acl_desc, NULL, NULL, 0);
	if (IS_ERR_OR_NULL(sgl_desc)) {
		pr_err("failed to do mem accept :rc=%d\n",
				PTR_ERR(sgl_desc));
		goto acl_fail;
	}
	fts_ts_trusted_touch_set_tvm_driver_state(fts_data, TVM_IOMEM_ACCEPTED);

	/* Initiate i2c session on tvm */
	rc = pm_runtime_get_sync(fts_data->client->adapter->dev.parent);
	if (rc < 0) {
		pr_err("failed to get sync rc:%d\n", rc);
		goto acl_fail;
	}
	fts_ts_trusted_touch_set_tvm_driver_state(fts_data, TVM_I2C_SESSION_ACQUIRED);

	expected_sgl_desc = fts_ts_vm_get_sgl(fts_data->vm_info);
	if (fts_ts_vm_compare_sgl_desc(expected_sgl_desc, sgl_desc)) {
		pr_err("IO sg list does not match\n");
		goto sgl_cmp_fail;
	}

	kfree(expected_sgl_desc);
	kfree(acl_desc);

	irq = hh_irq_accept(fts_data->vm_info->irq_label, -1, IRQ_TYPE_EDGE_RISING);
	fts_trusted_touch_intr_gpio_toggle(fts_data, false);
	if (irq < 0) {
		pr_err("failed to accept irq\n");
		goto irq_fail;
		goto accept_fail;
	}
	atomic_set(&fts_data->vm_info->tvm_owns_irq, 1);
	fts_ts_trusted_touch_set_tvm_driver_state(fts_data, TVM_IRQ_ACCEPTED);


	irq_data = irq_get_irq_data(irq);
	if (!irq_data) {
		pr_err("Invalid irq data for trusted touch\n");
		goto irq_fail;
		goto accept_fail;
	}
	if (!irq_data->hwirq) {
		pr_err("Invalid irq in irq data\n");
		goto irq_fail;
		goto accept_fail;
	}
	if (irq_data->hwirq != fts_data->vm_info->hw_irq) {
		pr_err("Invalid irq lent\n");
		goto irq_fail;
		goto accept_fail;
	}

	pr_debug("irq:returned from accept:%d\n", irq);
	fts_data->irq = irq;
	if (!wait_for_completion_timeout(&fts_data->resource_checkpoint,
				resource_timeout)) {
		pr_err("Resources not acquired in TVM\n");
		goto irq_fail;
	}

	rc = fts_ts_vm_handle_vm_hardware(fts_data);
	if (rc) {
		pr_err(" Delayed probe failure on VM!\n");
		goto irq_fail;
		goto accept_fail;
	}

	atomic_set(&fts_data->trusted_touch_enabled, 1);
	pr_info("trusted touch enabled\n");

	return;
irq_fail:
	fts_ts_trusted_touch_vm_mode_disable(fts_data);
sgl_cmp_fail:
	kfree(expected_sgl_desc);
acl_fail:
	kfree(acl_desc);
accept_fail:
	fts_ts_trusted_touch_abort_handler(fts_data,
			TRUSTED_TOUCH_EVENT_ACCEPT_FAILURE);
}
static void fts_ts_vm_irq_on_lend_callback(void *data,
					unsigned long notif_type,
					enum hh_irq_label label)
{
	struct fts_ts_data *fts_data = data;

	pr_debug("received irq lend request for label:%d\n", label);
	if (fts_ts_trusted_touch_get_tvm_driver_state(fts_data) ==
		TVM_IOMEM_LENT_NOTIFIED) {
		fts_ts_trusted_touch_set_tvm_driver_state(fts_data,
		TVM_ALL_RESOURCES_LENT_NOTIFIED);
	} else {
		fts_ts_trusted_touch_set_tvm_driver_state(fts_data,
			TVM_IRQ_LENT_NOTIFIED);
	}
}

static void fts_ts_vm_mem_on_lend_handler(enum hh_mem_notifier_tag tag,
		unsigned long notif_type, void *entry_data, void *notif_msg)
{
	struct hh_rm_notif_mem_shared_payload *payload;
	struct hh_sgl_desc *sgl_desc, *expected_sgl_desc;
	struct hh_acl_desc *acl_desc;
	struct trusted_touch_vm_info *vm_info;
	struct fts_ts_data *fts_data;
	int rc = 0;

	if (notif_type != HH_RM_NOTIF_MEM_SHARED ||
			tag != HH_MEM_NOTIFIER_TAG_TOUCH) {
@@ -379,62 +507,31 @@ static void fts_ts_vm_mem_on_lend_handler(enum hh_mem_notifier_tag tag,
	if (payload->trans_type != HH_RM_TRANS_TYPE_LEND ||
			payload->label != TRUSTED_TOUCH_MEM_LABEL) {
		pr_err("Invalid label or transaction type\n");
		goto onlend_fail;
	}

	acl_desc = fts_ts_vm_get_acl(HH_TRUSTED_VM);
	if (IS_ERR(acl_desc)) {
		pr_err("failed to populated acl data:rc=%d\n",
				PTR_ERR(acl_desc));
		goto onlend_fail;
	}

	sgl_desc = hh_rm_mem_accept(payload->mem_handle, HH_RM_MEM_TYPE_IO,
			HH_RM_TRANS_TYPE_LEND,
			HH_RM_MEM_ACCEPT_VALIDATE_ACL_ATTRS |
			HH_RM_MEM_ACCEPT_VALIDATE_LABEL |
			HH_RM_MEM_ACCEPT_DONE,  payload->label, acl_desc,
			NULL, NULL, 0);
	if (IS_ERR_OR_NULL(sgl_desc)) {
		pr_err("failed to do mem accept :rc=%d\n",
				PTR_ERR(sgl_desc));
		goto acl_fail;
	}
	atomic_set(&vm_info->tvm_owns_iomem, 1);

	/* Initiate i2c session on tvm */
	rc = pm_runtime_get_sync(fts_data->client->adapter->dev.parent);
	if (rc < 0) {
		pr_err("failed to get sync rc:%d\n", rc);
		(void)fts_ts_vm_mem_release(fts_data);
		atomic_set(&fts_data->vm_info->tvm_owns_iomem, 0);
		goto acl_fail;
	}
	complete(&fts_data->resource_checkpoint);

	expected_sgl_desc = fts_ts_vm_get_sgl(vm_info);
	if (fts_ts_vm_compare_sgl_desc(expected_sgl_desc, sgl_desc)) {
		pr_err("IO sg list does not match\n");
		goto sgl_cmp_fail;
		return;
	}

	vm_info->vm_mem_handle = payload->mem_handle;
	kfree(expected_sgl_desc);
	kfree(acl_desc);
	return;

sgl_cmp_fail:
	kfree(expected_sgl_desc);
acl_fail:
	kfree(acl_desc);
onlend_fail:
	fts_ts_trusted_touch_vm_mode_disable(fts_data);
	pr_debug("received mem lend request with handle:%d\n",
		vm_info->vm_mem_handle);
	if (fts_ts_trusted_touch_get_tvm_driver_state(fts_data) ==
		TVM_IRQ_LENT_NOTIFIED) {
		fts_ts_trusted_touch_set_tvm_driver_state(fts_data,
			TVM_ALL_RESOURCES_LENT_NOTIFIED);
	} else {
		fts_ts_trusted_touch_set_tvm_driver_state(fts_data,
		TVM_IOMEM_LENT_NOTIFIED);
	}
}

static int fts_ts_vm_mem_release(struct fts_ts_data *fts_data)
{
	int rc = 0;

	if (!fts_data->vm_info->vm_mem_handle) {
		pr_err("Invalid memory handle\n");
		return -EINVAL;
	}

	rc = hh_rm_mem_release(fts_data->vm_info->vm_mem_handle, 0);
	if (rc)
		pr_err("VM mem release failed: rc=%d\n", rc);
@@ -444,44 +541,58 @@ static int fts_ts_vm_mem_release(struct fts_ts_data *fts_data)
				HH_MEM_NOTIFIER_TAG_TOUCH, 0);
	if (rc)
		pr_err("Failed to notify mem release to PVM: rc=%d\n");
	pr_debug("vm mem release succeded\n");

	fts_data->vm_info->vm_mem_handle = 0;
	return rc;
}

static void fts_ts_trusted_touch_vm_mode_disable(struct fts_ts_data *fts_data)
static void fts_ts_trusted_touch_tvm_vm_mode_disable(struct fts_ts_data *fts_data)
{
	int rc = 0;

	if (atomic_read(&fts_data->trusted_touch_abort_status)) {
		fts_ts_trusted_touch_abort_tvm(fts_data);
		return;
	}

	if (atomic_read(&fts_data->vm_info->tvm_owns_iomem) &&
			atomic_read(&fts_data->vm_info->tvm_owns_irq))
	fts_irq_disable();
	fts_ts_trusted_touch_set_tvm_driver_state(fts_data,
				TVM_INTERRUPT_DISABLED);

	if (atomic_read(&fts_data->vm_info->tvm_owns_iomem)) {
		fts_release_all_finger();
		rc = fts_ts_vm_mem_release(fts_data);
		if (rc)
			pr_err("Failed to release mem rc:%d\n", rc);
		else
			atomic_set(&fts_data->vm_info->tvm_owns_iomem, 0);
		pm_runtime_put_sync(fts_data->client->adapter->dev.parent);
	}

	if (atomic_read(&fts_data->vm_info->tvm_owns_irq)) {
	rc = hh_irq_release(fts_data->vm_info->irq_label);
		if (rc)
	if (rc) {
		pr_err("Failed to release irq rc:%d\n", rc);
		else
			atomic_set(&fts_data->vm_info->tvm_owns_irq, 0);

		goto error;
	} else {
		fts_ts_trusted_touch_set_tvm_driver_state(fts_data,
					TVM_IRQ_RELEASED);
	}
	rc = hh_irq_release_notify(fts_data->vm_info->irq_label);
	if (rc)
		pr_err("Failed to notify release irq rc:%d\n", rc);

	pr_debug("vm irq release succeded\n");

	fts_release_all_finger();
	rc = fts_ts_vm_mem_release(fts_data);
	if (rc) {
		pr_err("Failed to release mem rc:%d\n", rc);
		goto error;
	} else {
		fts_ts_trusted_touch_set_tvm_driver_state(fts_data,
					TVM_IOMEM_RELEASED);
	}
	pm_runtime_put_sync(fts_data->client->adapter->dev.parent);
	fts_ts_trusted_touch_set_tvm_driver_state(fts_data,
					TVM_I2C_SESSION_RELEASED);
	fts_ts_trusted_touch_set_tvm_driver_state(fts_data, TRUSTED_TOUCH_TVM_INIT);
	atomic_set(&fts_data->trusted_touch_enabled, 0);
	reinit_completion(&fts_data->resource_checkpoint);
	pr_debug("trusted touch disabled\n");
	pr_info("trusted touch disabled\n");
	return;
error:
	fts_ts_trusted_touch_abort_handler(fts_data,
			TRUSTED_TOUCH_EVENT_RELEASE_FAILURE);
}

int fts_ts_handle_trusted_touch_tvm(struct fts_ts_data *fts_data, int value)
@@ -490,13 +601,14 @@ int fts_ts_handle_trusted_touch_tvm(struct fts_ts_data *fts_data, int value)

	switch (value) {
	case 0:
		if (atomic_read(&fts_data->trusted_touch_enabled) == 0) {
		if ((atomic_read(&fts_data->trusted_touch_enabled) == 0) &&
			(atomic_read(&fts_data->trusted_touch_abort_status) == 0)) {
			pr_err("Trusted touch is already disabled\n");
			break;
		}
		if (atomic_read(&fts_data->trusted_touch_mode) ==
				TRUSTED_TOUCH_VM_MODE) {
			fts_ts_trusted_touch_vm_mode_disable(fts_data);
			fts_ts_trusted_touch_tvm_vm_mode_disable(fts_data);
		} else {
			pr_err("Unsupported trusted touch mode\n");
		}
@@ -510,7 +622,7 @@ int fts_ts_handle_trusted_touch_tvm(struct fts_ts_data *fts_data, int value)
		}
		if (atomic_read(&fts_data->trusted_touch_mode) ==
				TRUSTED_TOUCH_VM_MODE) {
			pr_err("Cannot turnon trusted touch(vm mode) in VM\n");
			fts_ts_trusted_touch_tvm_vm_mode_enable(fts_data);
		} else {
			pr_err("Unsupported trusted touch mode\n");
		}
@@ -525,8 +637,115 @@ int fts_ts_handle_trusted_touch_tvm(struct fts_ts_data *fts_data, int value)
	return err;
}

static void fts_ts_trusted_touch_abort_tvm(struct fts_ts_data *fts_data)
{
	int rc = 0;
	int tvm_state = fts_ts_trusted_touch_get_tvm_driver_state(fts_data);

	if (tvm_state >= TRUSTED_TOUCH_TVM_STATE_MAX) {
		pr_err("invalid tvm driver state: %d\n", tvm_state);
		return;
	}

	switch (tvm_state) {
	case TVM_INTERRUPT_ENABLED:
		fts_irq_disable();
	case TVM_IRQ_ACCEPTED:
	case TVM_INTERRUPT_DISABLED:
		rc = hh_irq_release(fts_data->vm_info->irq_label);
		if (rc)
			pr_err("Failed to release irq rc:%d\n", rc);
		rc = hh_irq_release_notify(fts_data->vm_info->irq_label);
		if (rc)
			pr_err("Failed to notify irq release rc:%d\n", rc);
	case TVM_I2C_SESSION_ACQUIRED:
	case TVM_IOMEM_ACCEPTED:
	case TVM_IRQ_RELEASED:
		fts_release_all_finger();
		rc = fts_ts_vm_mem_release(fts_data);
		if (rc)
			pr_err("Failed to release mem rc:%d\n", rc);
	case TVM_IOMEM_RELEASED:
		pm_runtime_put_sync(fts_data->client->adapter->dev.parent);
	case TVM_I2C_SESSION_RELEASED:
	case TVM_IOMEM_LENT_NOTIFIED:
	case TVM_IRQ_LENT_NOTIFIED:
	case TVM_ALL_RESOURCES_LENT_NOTIFIED:
	case TRUSTED_TOUCH_TVM_INIT:
		atomic_set(&fts_data->trusted_touch_enabled, 0);
	}

	atomic_set(&fts_data->trusted_touch_abort_status, 0);
	fts_ts_trusted_touch_set_tvm_driver_state(fts_data, TRUSTED_TOUCH_TVM_INIT);
}

#else

static void fts_ts_bus_put(struct fts_ts_data *fts_data);

static int fts_ts_trusted_touch_get_pvm_driver_state(struct fts_ts_data *fts_data)
{
	int state;

	mutex_lock(&fts_data->vm_info->pvm_state_mutex);
	state = atomic_read(&fts_data->vm_info->pvm_state);
	mutex_unlock(&fts_data->vm_info->pvm_state_mutex);

	return state;

}

static void fts_ts_trusted_touch_set_pvm_driver_state(struct fts_ts_data *fts_data,
							int state)
{
	mutex_lock(&fts_data->vm_info->pvm_state_mutex);
	atomic_set(&fts_data->vm_info->pvm_state, state);
	mutex_unlock(&fts_data->vm_info->pvm_state_mutex);
}

static void fts_ts_trusted_touch_abort_pvm(struct fts_ts_data *fts_data)
{
	int rc = 0;
	int pvm_state = fts_ts_trusted_touch_get_pvm_driver_state(fts_data);

	if (pvm_state >= TRUSTED_TOUCH_PVM_STATE_MAX) {
		pr_err("Invalid driver state: %d\n", pvm_state);
		return;
	}

	switch (pvm_state) {
	case PVM_IRQ_RELEASE_NOTIFIED:
	case PVM_ALL_RESOURCES_RELEASE_NOTIFIED:
	case PVM_IRQ_LENT:
	case PVM_IRQ_LENT_NOTIFIED:
		rc = hh_irq_reclaim(fts_data->vm_info->irq_label);
		if (rc)
			pr_err("failed to reclaim irq on pvm rc:%d\n", rc);
	case PVM_IRQ_RECLAIMED:
	case PVM_IOMEM_LENT:
	case PVM_IOMEM_LENT_NOTIFIED:
	case PVM_IOMEM_RELEASE_NOTIFIED:
		rc = hh_rm_mem_reclaim(fts_data->vm_info->vm_mem_handle, 0);
		if (rc)
			pr_err("failed to reclaim iomem on pvm rc:%d\n", rc);
		fts_data->vm_info->vm_mem_handle = 0;
	case PVM_IOMEM_RECLAIMED:
	case PVM_INTERRUPT_DISABLED:
		fts_irq_enable();
	case PVM_I2C_RESOURCE_ACQUIRED:
	case PVM_INTERRUPT_ENABLED:
		fts_ts_bus_put(fts_data);
		complete(&fts_data->trusted_touch_powerdown);
	case TRUSTED_TOUCH_PVM_INIT:
	case PVM_I2C_RESOURCE_RELEASED:
		atomic_set(&fts_data->trusted_touch_enabled, 0);
	}

	atomic_set(&fts_data->trusted_touch_abort_status, 0);

	fts_ts_trusted_touch_set_pvm_driver_state(fts_data, TRUSTED_TOUCH_PVM_INIT);
}

static int fts_ts_clk_prepare_enable(struct fts_ts_data *fts_data)
{
	int ret;
@@ -591,18 +810,48 @@ static struct hh_notify_vmid_desc *fts_ts_vm_get_vmid(hh_vmid_t vmid)
	return vmid_desc;
}

static void fts_ts_trusted_touch_complete(struct fts_ts_data *fts_data)
static void fts_trusted_touch_pvm_vm_mode_disable(struct fts_ts_data *fts_data)
{
	if (atomic_read(&fts_data->vm_info->pvm_owns_iomem) &&
			atomic_read(&fts_data->vm_info->pvm_owns_irq)) {
	int rc = 0;

	if (atomic_read(&fts_data->trusted_touch_abort_status)) {
		fts_ts_trusted_touch_abort_pvm(fts_data);
		return;
	}

	if (fts_ts_trusted_touch_get_pvm_driver_state(fts_data) !=
					PVM_ALL_RESOURCES_RELEASE_NOTIFIED)
		pr_err("all release notifications are not received yet\n");

	rc = hh_irq_reclaim(fts_data->vm_info->irq_label);
	if (rc) {
		pr_err("failed to reclaim irq on pvm rc:%d\n", rc);
		goto error;
	}
	fts_ts_trusted_touch_set_pvm_driver_state(fts_data,
				PVM_IRQ_RECLAIMED);

	rc = hh_rm_mem_reclaim(fts_data->vm_info->vm_mem_handle, 0);
	if (rc) {
		pr_err("Trusted touch VM mem reclaim failed rc:%d\n", rc);
		goto error;
	}
	fts_ts_trusted_touch_set_pvm_driver_state(fts_data, PVM_IOMEM_RECLAIMED);
	fts_data->vm_info->vm_mem_handle = 0;

	fts_irq_enable();
	fts_ts_trusted_touch_set_pvm_driver_state(fts_data, PVM_INTERRUPT_ENABLED);
	fts_ts_bus_put(fts_data);
	fts_ts_trusted_touch_set_pvm_driver_state(fts_data,
						PVM_I2C_RESOURCE_RELEASED);
	complete(&fts_data->trusted_touch_powerdown);
	fts_ts_trusted_touch_set_pvm_driver_state(fts_data,
						TRUSTED_TOUCH_PVM_INIT);
	atomic_set(&fts_data->trusted_touch_enabled, 0);
		pr_debug("reenabled interrupts on PVM\n");
	} else {
		pr_err("PVM does not own irq and IOMEM\n");
	}
	return;
error:
	fts_ts_trusted_touch_abort_handler(fts_data,
			TRUSTED_TOUCH_EVENT_RECLAIM_FAILURE);
}

static void fts_ts_vm_irq_on_release_callback(void *data,
@@ -610,26 +859,36 @@ static void fts_ts_vm_irq_on_release_callback(void *data,
					enum hh_irq_label label)
{
	struct fts_ts_data *fts_data = data;
	int rc = 0;

	rc = hh_irq_reclaim(fts_data->vm_info->irq_label);
	if (rc)
		pr_err("failed to reclaim irq on pvm rc:%d\n", rc);
	else
		atomic_set(&fts_data->vm_info->pvm_owns_irq, 1);
	if (notif_type != HH_RM_NOTIF_VM_IRQ_RELEASED) {
		pr_err("invalid notification type\n");
		return;
	}

	if (fts_ts_trusted_touch_get_pvm_driver_state(fts_data) ==
		PVM_IOMEM_RELEASE_NOTIFIED) {
		fts_ts_trusted_touch_set_pvm_driver_state(fts_data,
			PVM_ALL_RESOURCES_RELEASE_NOTIFIED);
	} else {
		fts_ts_trusted_touch_set_pvm_driver_state(fts_data,
			PVM_IRQ_RELEASE_NOTIFIED);
	}
}

static void fts_ts_vm_mem_on_release_handler(enum hh_mem_notifier_tag tag,
		unsigned long notif_type, void *entry_data, void *notif_msg)
{
	struct hh_rm_notif_mem_released_payload *payload;
	struct hh_rm_notif_mem_released_payload *release_payload;
	struct trusted_touch_vm_info *vm_info;
	struct fts_ts_data *fts_data;
	int rc = 0;

	if (notif_type != HH_RM_NOTIF_MEM_RELEASED ||
			tag != HH_MEM_NOTIFIER_TAG_TOUCH) {
		pr_err(" Invalid tag or command passed\n");
	if (notif_type != HH_RM_NOTIF_MEM_RELEASED) {
		pr_err(" Invalid notification type\n");
		return;
	}

	if (tag != HH_MEM_NOTIFIER_TAG_TOUCH) {
		pr_err(" Invalid tag\n");
		return;
	}

@@ -638,7 +897,6 @@ static void fts_ts_vm_mem_on_release_handler(enum hh_mem_notifier_tag tag,
		return;
	}

	payload = (struct hh_rm_notif_mem_released_payload  *)notif_msg;
	fts_data = (struct fts_ts_data *)entry_data;
	vm_info = fts_data->vm_info;
	if (!vm_info) {
@@ -646,18 +904,20 @@ static void fts_ts_vm_mem_on_release_handler(enum hh_mem_notifier_tag tag,
		return;
	}

	if (payload->mem_handle != vm_info->vm_mem_handle) {
	release_payload = (struct hh_rm_notif_mem_released_payload  *)notif_msg;
	if (release_payload->mem_handle != vm_info->vm_mem_handle) {
		pr_err("Invalid mem handle detected\n");
		return;
	}

	rc = hh_rm_mem_reclaim(payload->mem_handle, 0);
	if (rc) {
		pr_err("Trusted touch VM mem release failed rc:%d\n", rc);
		return;
	if (fts_ts_trusted_touch_get_pvm_driver_state(fts_data) ==
				PVM_IRQ_RELEASE_NOTIFIED) {
		fts_ts_trusted_touch_set_pvm_driver_state(fts_data,
			PVM_ALL_RESOURCES_RELEASE_NOTIFIED);
	} else {
		fts_ts_trusted_touch_set_pvm_driver_state(fts_data,
			PVM_IOMEM_RELEASE_NOTIFIED);
	}
	atomic_set(&vm_info->pvm_owns_iomem, 1);
	vm_info->vm_mem_handle = 0;
}

static int fts_ts_vm_mem_lend(struct fts_ts_data *fts_data)
@@ -692,6 +952,10 @@ static int fts_ts_vm_mem_lend(struct fts_ts_data *fts_data)
		goto error;
	}

	pr_info("vm mem lend succeded\n");

	fts_ts_trusted_touch_set_pvm_driver_state(fts_data, PVM_IOMEM_LENT);

	hh_rm_get_vmid(HH_TRUSTED_VM, &trusted_vmid);

	vmid_desc = fts_ts_vm_get_vmid(trusted_vmid);
@@ -703,6 +967,8 @@ static int fts_ts_vm_mem_lend(struct fts_ts_data *fts_data)
		goto vmid_error;
	}

	fts_ts_trusted_touch_set_pvm_driver_state(fts_data, PVM_IOMEM_LENT_NOTIFIED);

	fts_data->vm_info->vm_mem_handle = mem_handle;
vmid_error:
	kfree(vmid_desc);
@@ -714,7 +980,7 @@ static int fts_ts_vm_mem_lend(struct fts_ts_data *fts_data)
	return rc;
}

static int fts_ts_trusted_touch_vm_mode_enable(struct fts_ts_data *fts_data)
static int fts_ts_trusted_touch_pvm_vm_mode_enable(struct fts_ts_data *fts_data)
{
	int rc = 0;
	struct trusted_touch_vm_info *vm_info = fts_data->vm_info;
@@ -726,35 +992,42 @@ static int fts_ts_trusted_touch_vm_mode_enable(struct fts_ts_data *fts_data)
		return rc;
	}

	fts_ts_trusted_touch_set_pvm_driver_state(fts_data, PVM_I2C_RESOURCE_ACQUIRED);
	/* flush pending interurpts from FIFO */
	fts_irq_disable();
	fts_ts_trusted_touch_set_pvm_driver_state(fts_data, PVM_INTERRUPT_DISABLED);
	fts_release_all_finger();

	rc = fts_ts_vm_mem_lend(fts_data);
	if (rc) {
		pr_err("Failed to lend memory\n");
		return -EINVAL;
		goto error;
	}
	atomic_set(&vm_info->pvm_owns_iomem, 0);

	rc = hh_irq_lend_v2(vm_info->irq_label, vm_info->vm_name,
		fts_data->irq, &fts_ts_vm_irq_on_release_callback, fts_data);
	if (rc) {
		pr_err("Failed to lend irq\n");
		return -EINVAL;
		goto error;
	}
	atomic_set(&vm_info->pvm_owns_irq, 0);

	pr_info("vm irq lend succeded for irq:%d\n", fts_data->irq);
	fts_ts_trusted_touch_set_pvm_driver_state(fts_data, PVM_IRQ_LENT);

	rc = hh_irq_lend_notify(vm_info->irq_label);
	if (rc) {
		pr_err("Failed to notify irq\n");
		return -EINVAL;
		goto error;
	}
	fts_ts_trusted_touch_set_pvm_driver_state(fts_data, PVM_IRQ_LENT_NOTIFIED);

	reinit_completion(&fts_data->trusted_touch_powerdown);
	atomic_set(&fts_data->trusted_touch_enabled, 1);
	pr_debug("trusted touch enabled\n");
	return rc;
error:
	fts_ts_trusted_touch_abort_handler(fts_data, TRUSTED_TOUCH_EVENT_LEND_FAILURE);
	return rc;
}

int fts_ts_handle_trusted_touch_pvm(struct fts_ts_data *fts_data, int value)
@@ -763,13 +1036,14 @@ int fts_ts_handle_trusted_touch_pvm(struct fts_ts_data *fts_data, int value)

	switch (value) {
	case 0:
		if (atomic_read(&fts_data->trusted_touch_enabled) == 0) {
		if (atomic_read(&fts_data->trusted_touch_enabled) == 0 &&
			(atomic_read(&fts_data->trusted_touch_abort_status) == 0)) {
			pr_err("Trusted touch is already disabled\n");
			break;
		}
		if (atomic_read(&fts_data->trusted_touch_mode) ==
				TRUSTED_TOUCH_VM_MODE) {
			fts_ts_trusted_touch_complete(fts_data);
			fts_trusted_touch_pvm_vm_mode_disable(fts_data);
		} else {
			pr_err("Unsupported trusted touch mode\n");
		}
@@ -783,7 +1057,7 @@ int fts_ts_handle_trusted_touch_pvm(struct fts_ts_data *fts_data, int value)
		}
		if (atomic_read(&fts_data->trusted_touch_mode) ==
				TRUSTED_TOUCH_VM_MODE) {
			err = fts_ts_trusted_touch_vm_mode_enable(fts_data);
			err = fts_ts_trusted_touch_pvm_vm_mode_enable(fts_data);
		} else {
			pr_err("Unsupported trusted touch mode\n");
		}
@@ -799,6 +1073,27 @@ int fts_ts_handle_trusted_touch_pvm(struct fts_ts_data *fts_data, int value)

#endif

static void fts_ts_trusted_touch_event_notify(struct fts_ts_data *fts_data, int event)
{
	atomic_set(&fts_data->trusted_touch_event, event);
	sysfs_notify(&fts_data->client->dev.kobj, NULL, "trusted_touch_event");
}

static void fts_ts_trusted_touch_abort_handler(struct fts_ts_data *fts_data, int error)
{
	atomic_set(&fts_data->trusted_touch_abort_status, error);
	pr_err("TUI session aborted with failure:%d\n", error);
	fts_ts_trusted_touch_event_notify(fts_data, error);
#ifdef CONFIG_ARCH_QTI_VM
	pr_err("Resetting touch controller\n");
	if (fts_ts_trusted_touch_get_tvm_driver_state(fts_data) >= TVM_IOMEM_ACCEPTED
			&& error == TRUSTED_TOUCH_EVENT_I2C_FAILURE) {
		pr_err("Resetting touch controller\n");
		fts_ts_trusted_touch_reset_gpio_toggle(fts_data);
	}
#endif
}

static int fts_ts_vm_init(struct fts_ts_data *fts_data)
{
	int rc = 0;
@@ -824,9 +1119,8 @@ static int fts_ts_vm_init(struct fts_ts_data *fts_data)
	vm_info->mem_cookie = mem_cookie;
	rc = hh_irq_wait_for_lend_v2(vm_info->irq_label, HH_PRIMARY_VM,
			&fts_ts_vm_irq_on_lend_callback, fts_data);
	atomic_set(&vm_info->tvm_owns_irq, 0);
	atomic_set(&vm_info->tvm_owns_iomem, 0);
	init_completion(&fts_data->resource_checkpoint);
	mutex_init(&fts_data->vm_info->tvm_state_mutex);
	fts_ts_trusted_touch_set_tvm_driver_state(fts_data, TRUSTED_TOUCH_TVM_INIT);
#else
	mem_cookie = hh_mem_notifier_register(HH_MEM_NOTIFIER_TAG_TOUCH,
			fts_ts_vm_mem_on_release_handler, fts_data);
@@ -836,8 +1130,8 @@ static int fts_ts_vm_init(struct fts_ts_data *fts_data)
		goto init_fail;
	}
	vm_info->mem_cookie = mem_cookie;
	atomic_set(&vm_info->pvm_owns_irq, 1);
	atomic_set(&vm_info->pvm_owns_iomem, 1);
	mutex_init(&fts_data->vm_info->pvm_state_mutex);
	fts_ts_trusted_touch_set_pvm_driver_state(fts_data, TRUSTED_TOUCH_PVM_INIT);
#endif
	return rc;
init_fail:
@@ -1557,17 +1851,6 @@ static irqreturn_t fts_irq_handler(int irq, void *data)
		return IRQ_HANDLED;
	}

#ifdef CONFIG_FTS_TRUSTED_TOUCH
#ifndef CONFIG_ARCH_QTI_VM
	if (atomic_read(&fts_data->trusted_touch_enabled)) {
		if (atomic_read(&fts_data->vm_info->pvm_owns_iomem) &&
			atomic_read(&fts_data->vm_info->pvm_owns_irq)) {
			pr_err("Trusted Touch Enabled: Cannot service irq\n");
			return IRQ_HANDLED;
		}
	}
#endif
#endif
	fts_irq_read_report();
	return IRQ_HANDLED;
}
+61 −5

File changed.

Preview size limit exceeded, changes collapsed.

+54 −0

File changed.

Preview size limit exceeded, changes collapsed.

+43 −1

File changed.

Preview size limit exceeded, changes collapsed.