diff --git a/drivers/input/touchscreen/nt36xxx/Kconfig b/drivers/input/touchscreen/nt36xxx/Kconfig index 04cff5faba62..bb990cf68e38 100644 --- a/drivers/input/touchscreen/nt36xxx/Kconfig +++ b/drivers/input/touchscreen/nt36xxx/Kconfig @@ -9,3 +9,10 @@ config TOUCHSCREEN_NT36XXX to your system. If unsure, say N. + +config NOVATEK_TRUSTED_TOUCH + bool "Novatek Trusted Touch" + depends on TOUCHSCREEN_NT36XXX + help + Say Y here to enable Novatek Trusted Touch. + If unsure, say N. diff --git a/drivers/input/touchscreen/nt36xxx/nt36xxx.c b/drivers/input/touchscreen/nt36xxx/nt36xxx.c index 99e5daf0a510..a2a450070538 100644 --- a/drivers/input/touchscreen/nt36xxx/nt36xxx.c +++ b/drivers/input/touchscreen/nt36xxx/nt36xxx.c @@ -17,6 +17,7 @@ * */ #include +#include #include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #if defined(CONFIG_DRM_PANEL) #include @@ -40,6 +42,22 @@ #include #endif /* #if NVT_TOUCH_ESD_PROTECT */ +#if defined(CONFIG_NOVATEK_TRUSTED_TOUCH) +#include +#include +#include +#include +#include +#include +#include +#include +#include "linux/haven/hh_irq_lend.h" +#include "linux/haven/hh_msgq.h" +#include "linux/haven/hh_mem_notifier.h" +#include "linux/haven/hh_rm_drv.h" +#include +#endif + #if NVT_TOUCH_ESD_PROTECT static struct delayed_work nvt_esd_check_work; static struct workqueue_struct *nvt_esd_check_wq; @@ -78,6 +96,11 @@ static void nvt_ts_early_suspend(struct early_suspend *h); static void nvt_ts_late_resume(struct early_suspend *h); #endif +static void nvt_irq_enable(bool enable); +static irqreturn_t nvt_ts_work_func(int irq, void *data); +static int32_t nvt_ts_late_probe_sub(struct i2c_client *client, + const struct i2c_device_id *id); + #if TOUCH_KEY_NUM > 0 const uint16_t touch_key_array[TOUCH_KEY_NUM] = { KEY_BACK, @@ -106,6 +129,1072 @@ const uint16_t gesture_key_array[] = { static uint8_t bTouchIsAwake = 0; +#ifdef CONFIG_NOVATEK_TRUSTED_TOUCH + +static void nvt_ts_trusted_touch_abort_handler(struct nvt_ts_data *ts, + int error); +static struct hh_acl_desc *nvt_ts_vm_get_acl(enum hh_vm_names vm_name) +{ + struct hh_acl_desc *acl_desc; + hh_vmid_t vmid; + + hh_rm_get_vmid(vm_name, &vmid); + + acl_desc = kzalloc(offsetof(struct hh_acl_desc, acl_entries[1]), + GFP_KERNEL); + if (!acl_desc) + return ERR_PTR(ENOMEM); + + acl_desc->n_acl_entries = 1; + acl_desc->acl_entries[0].vmid = vmid; + acl_desc->acl_entries[0].perms = HH_RM_ACL_R | HH_RM_ACL_W; + + return acl_desc; +} + +static struct hh_sgl_desc *nvt_ts_vm_get_sgl( + struct trusted_touch_vm_info *vm_info) +{ + struct hh_sgl_desc *sgl_desc; + int i; + + sgl_desc = kzalloc(offsetof(struct hh_sgl_desc, + sgl_entries[vm_info->iomem_list_size]), GFP_KERNEL); + if (!sgl_desc) + return ERR_PTR(ENOMEM); + + sgl_desc->n_sgl_entries = vm_info->iomem_list_size; + + for (i = 0; i < vm_info->iomem_list_size; i++) { + sgl_desc->sgl_entries[i].ipa_base = vm_info->iomem_bases[i]; + sgl_desc->sgl_entries[i].size = vm_info->iomem_sizes[i]; + } + + return sgl_desc; +} + +static int nvt_ts_populate_vm_info(struct nvt_ts_data *ts) +{ + int rc = 0; + struct trusted_touch_vm_info *vm_info; + struct device_node *np = ts->client->dev.of_node; + int num_regs, num_sizes = 0; + + vm_info = kzalloc(sizeof(struct trusted_touch_vm_info), GFP_KERNEL); + if (!vm_info) { + rc = -ENOMEM; + goto error; + } + + ts->vm_info = vm_info; + vm_info->irq_label = HH_IRQ_LABEL_TRUSTED_TOUCH; + vm_info->vm_name = HH_TRUSTED_VM; + rc = of_property_read_u32(np, "novatek,trusted-touch-spi-irq", + &vm_info->hw_irq); + if (rc) { + pr_err("Failed to read trusted touch SPI irq:%d\n", rc); + goto vm_error; + } + num_regs = of_property_count_u32_elems(np, + "novatek,trusted-touch-io-bases"); + if (num_regs < 0) { + pr_err("Invalid number of IO regions specified\n"); + rc = -EINVAL; + goto vm_error; + } + + num_sizes = of_property_count_u32_elems(np, + "novatek,trusted-touch-io-sizes"); + if (num_sizes < 0) { + pr_err("Invalid number of IO regions specified\n"); + rc = -EINVAL; + goto vm_error; + } + + if (num_regs != num_sizes) { + pr_err("IO bases and sizes doe not match\n"); + rc = -EINVAL; + goto vm_error; + } + + vm_info->iomem_list_size = num_regs; + + vm_info->iomem_bases = kcalloc(num_regs, sizeof(*vm_info->iomem_bases), + GFP_KERNEL); + if (!vm_info->iomem_bases) { + rc = -ENOMEM; + goto vm_error; + } + + rc = of_property_read_u32_array(np, "novatek,trusted-touch-io-bases", + vm_info->iomem_bases, vm_info->iomem_list_size); + if (rc) { + pr_err("Failed to read trusted touch io bases:%d\n", rc); + goto io_bases_error; + } + + vm_info->iomem_sizes = kzalloc( + sizeof(*vm_info->iomem_sizes) * num_sizes, GFP_KERNEL); + if (!vm_info->iomem_sizes) { + rc = -ENOMEM; + goto io_bases_error; + } + + rc = of_property_read_u32_array(np, "novatek,trusted-touch-io-sizes", + vm_info->iomem_sizes, vm_info->iomem_list_size); + if (rc) { + pr_err("Failed to read trusted touch io sizes:%d\n", rc); + goto io_sizes_error; + } + return rc; + +io_sizes_error: + kfree(vm_info->iomem_sizes); +io_bases_error: + kfree(vm_info->iomem_bases); +vm_error: + kfree(vm_info); +error: + return rc; +} + +static void nvt_ts_destroy_vm_info(struct nvt_ts_data *ts) +{ + kfree(ts->vm_info->iomem_sizes); + kfree(ts->vm_info->iomem_bases); + kfree(ts->vm_info); +} + +static void nvt_ts_vm_deinit(struct nvt_ts_data *ts) +{ + if (ts->vm_info->mem_cookie) + hh_mem_notifier_unregister(ts->vm_info->mem_cookie); + nvt_ts_destroy_vm_info(ts); +} + +#ifdef CONFIG_ARCH_QTI_VM +static int nvt_ts_vm_mem_release(struct nvt_ts_data *ts); +static void nvt_ts_trusted_touch_tvm_vm_mode_disable(struct nvt_ts_data *ts); +static void nvt_ts_trusted_touch_abort_tvm(struct nvt_ts_data *ts); +static void nvt_ts_trusted_touch_event_notify(struct nvt_ts_data *ts, int event); +static int32_t nvt_ts_late_probe_tvm(struct i2c_client *client, + const struct i2c_device_id *id); + +static int nvt_ts_trusted_touch_get_tvm_driver_state(struct nvt_ts_data *ts) +{ + int state; + + mutex_lock(&ts->vm_info->tvm_state_mutex); + state = atomic_read(&ts->vm_info->tvm_state); + mutex_unlock(&ts->vm_info->tvm_state_mutex); + + return state; +} + +static void nvt_ts_trusted_touch_set_tvm_driver_state(struct nvt_ts_data *ts, + int state) +{ + mutex_lock(&ts->vm_info->tvm_state_mutex); + atomic_set(&ts->vm_info->tvm_state, state); + mutex_unlock(&ts->vm_info->tvm_state_mutex); +} + +static int nvt_ts_sgl_cmp(const void *a, const void *b) +{ + struct hh_sgl_entry *left = (struct hh_sgl_entry *)a; + struct hh_sgl_entry *right = (struct hh_sgl_entry *)b; + + return (left->ipa_base - right->ipa_base); +} + +static int nvt_ts_vm_compare_sgl_desc(struct hh_sgl_desc *expected, + struct hh_sgl_desc *received) +{ + int idx; + + if (expected->n_sgl_entries != received->n_sgl_entries) + return -E2BIG; + sort(received->sgl_entries, received->n_sgl_entries, + sizeof(received->sgl_entries[0]), nvt_ts_sgl_cmp, NULL); + sort(expected->sgl_entries, expected->n_sgl_entries, + sizeof(expected->sgl_entries[0]), nvt_ts_sgl_cmp, NULL); + + for (idx = 0; idx < expected->n_sgl_entries; idx++) { + struct hh_sgl_entry *left = &expected->sgl_entries[idx]; + struct hh_sgl_entry *right = &received->sgl_entries[idx]; + + if ((left->ipa_base != right->ipa_base) || + (left->size != right->size)) { + pr_err("sgl mismatch: base l:%d r:%d size l:%d r:%d\n", + left->ipa_base, right->ipa_base, + left->size, right->size); + return -EINVAL; + } + } + return 0; +} + +static int nvt_ts_vm_handle_vm_hardware(struct nvt_ts_data *ts) +{ + int rc = 0; + + if (atomic_read(&ts->delayed_vm_probe_pending)) { + rc = nvt_ts_late_probe_tvm(ts->client, ts->id); + if (rc) { + pr_err("Delayed probe failure on VM!\n"); + return rc; + } + atomic_set(&ts->delayed_vm_probe_pending, 0); + return rc; + } + + nvt_irq_enable(true); + nvt_ts_trusted_touch_set_tvm_driver_state(ts, TVM_INTERRUPT_ENABLED); + return rc; +} + +static void nvt_ts_trusted_touch_tvm_vm_mode_enable(struct nvt_ts_data *ts) +{ + + struct hh_sgl_desc *sgl_desc, *expected_sgl_desc; + struct hh_acl_desc *acl_desc; + struct irq_data *irq_data; + int rc = 0; + int irq = 0; + + if (nvt_ts_trusted_touch_get_tvm_driver_state(ts) != + TVM_ALL_RESOURCES_LENT_NOTIFIED) { + pr_err("All lend notifications not received for touch\n"); + nvt_ts_trusted_touch_event_notify(ts, + TRUSTED_TOUCH_EVENT_NOTIFICATIONS_PENDING); + return; + } + + acl_desc = nvt_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(ts->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; + } + nvt_ts_trusted_touch_set_tvm_driver_state(ts, TVM_IOMEM_ACCEPTED); + + /* Initiate i2c session on tvm */ + rc = pm_runtime_get_sync(ts->client->adapter->dev.parent); + if (rc < 0) { + pr_err("failed to get sync rc:%d\n", rc); + goto acl_fail; + } + nvt_ts_trusted_touch_set_tvm_driver_state(ts, TVM_I2C_SESSION_ACQUIRED); + + expected_sgl_desc = nvt_ts_vm_get_sgl(ts->vm_info); + if (nvt_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(ts->vm_info->irq_label, -1, IRQ_TYPE_EDGE_RISING); + if (irq < 0) { + pr_err("failed to accept irq\n"); + goto accept_fail; + } + nvt_ts_trusted_touch_set_tvm_driver_state(ts, TVM_IRQ_ACCEPTED); + + + irq_data = irq_get_irq_data(irq); + if (!irq_data) { + pr_err("Invalid irq data for trusted touch\n"); + goto accept_fail; + } + if (!irq_data->hwirq) { + pr_err("Invalid irq in irq data\n"); + goto accept_fail; + } + if (irq_data->hwirq != ts->vm_info->hw_irq) { + pr_err("Invalid irq lent\n"); + goto accept_fail; + } + + pr_info("touch irq:returned from accept:%d\n", irq); + ts->client->irq = irq; + + rc = nvt_ts_vm_handle_vm_hardware(ts); + if (rc) { + pr_err("Delayed probe failure on VM!\n"); + goto accept_fail; + } + atomic_set(&ts->trusted_touch_enabled, 1); + pr_info("trusted touch enabled\n"); + + return; +sgl_cmp_fail: + kfree(expected_sgl_desc); +acl_fail: + kfree(acl_desc); +accept_fail: + nvt_ts_trusted_touch_abort_handler(ts, + TRUSTED_TOUCH_EVENT_ACCEPT_FAILURE); +} + +static void nvt_ts_vm_irq_on_lend_callback(void *data, + unsigned long notif_type, + enum hh_irq_label label) +{ + struct nvt_ts_data *ts = data; + + pr_debug("received touch irq lend request for label:%d\n", label); + if (nvt_ts_trusted_touch_get_tvm_driver_state(ts) == + TVM_IOMEM_LENT_NOTIFIED) { + nvt_ts_trusted_touch_set_tvm_driver_state(ts, + TVM_ALL_RESOURCES_LENT_NOTIFIED); + } else { + nvt_ts_trusted_touch_set_tvm_driver_state(ts, + TVM_IRQ_LENT_NOTIFIED); + } +} + +static void nvt_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 trusted_touch_vm_info *vm_info; + struct nvt_ts_data *ts; + + if (notif_type != HH_RM_NOTIF_MEM_SHARED || + tag != HH_MEM_NOTIFIER_TAG_TOUCH) { + pr_err("Invalid command passed from rm\n"); + return; + } + + if (!entry_data || !notif_msg) { + pr_err("Invalid entry data passed from rm\n"); + return; + } + + ts = (struct nvt_ts_data *)entry_data; + vm_info = ts->vm_info; + if (!vm_info) { + pr_err("Invalid vm_info\n"); + return; + } + + payload = (struct hh_rm_notif_mem_shared_payload *)notif_msg; + if (payload->trans_type != HH_RM_TRANS_TYPE_LEND || + payload->label != TRUSTED_TOUCH_MEM_LABEL) { + pr_err("Invalid label or transaction type\n"); + return; + } + + vm_info->vm_mem_handle = payload->mem_handle; + pr_debug("received touch mem lend request with handle:%d\n", + vm_info->vm_mem_handle); + if (nvt_ts_trusted_touch_get_tvm_driver_state(ts) == + TVM_IRQ_LENT_NOTIFIED) { + nvt_ts_trusted_touch_set_tvm_driver_state(ts, + TVM_ALL_RESOURCES_LENT_NOTIFIED); + } else { + nvt_ts_trusted_touch_set_tvm_driver_state(ts, + TVM_IOMEM_LENT_NOTIFIED); + } +} + +static int nvt_ts_vm_mem_release(struct nvt_ts_data *ts) +{ + int rc = 0; + + if (!ts->vm_info->vm_mem_handle) { + pr_err("Invalid memory handle\n"); + return -EINVAL; + } + + rc = hh_rm_mem_release(ts->vm_info->vm_mem_handle, 0); + if (rc) + pr_err("touch VM mem release failed: rc=%d\n", rc); + + rc = hh_rm_mem_notify(ts->vm_info->vm_mem_handle, + HH_RM_MEM_NOTIFY_OWNER_RELEASED, + HH_MEM_NOTIFIER_TAG_TOUCH, NULL); + if (rc) + pr_err("Failed to notify mem release to PVM: rc=%d\n"); + pr_debug("touch vm mem release succeded\n"); + + ts->vm_info->vm_mem_handle = 0; + return rc; +} + +static void nvt_ts_trusted_touch_tvm_vm_mode_disable(struct nvt_ts_data *ts) +{ + int rc = 0; + + if (atomic_read(&ts->trusted_touch_abort_status)) { + nvt_ts_trusted_touch_abort_tvm(ts); + return; + } + + nvt_irq_enable(false); + nvt_ts_trusted_touch_set_tvm_driver_state(ts, + TVM_INTERRUPT_DISABLED); + rc = hh_irq_release(ts->vm_info->irq_label); + if (rc) { + pr_err("Failed to release irq rc:%d\n", rc); + goto error; + } else { + nvt_ts_trusted_touch_set_tvm_driver_state(ts, + TVM_IRQ_RELEASED); + } + rc = hh_irq_release_notify(ts->vm_info->irq_label); + if (rc) + pr_err("Failed to notify release irq rc:%d\n", rc); + + pr_debug("vm irq release succeded\n"); + + rc = nvt_ts_vm_mem_release(ts); + if (rc) { + pr_err("Failed to release mem rc:%d\n", rc); + goto error; + } else { + nvt_ts_trusted_touch_set_tvm_driver_state(ts, + TVM_IOMEM_RELEASED); + } + pm_runtime_put_sync(ts->client->adapter->dev.parent); + nvt_ts_trusted_touch_set_tvm_driver_state(ts, + TVM_I2C_SESSION_RELEASED); + nvt_ts_trusted_touch_set_tvm_driver_state(ts, TRUSTED_TOUCH_TVM_INIT); + atomic_set(&ts->trusted_touch_enabled, 0); + pr_info("trusted touch disabled\n"); + return; +error: + nvt_ts_trusted_touch_abort_handler(ts, + TRUSTED_TOUCH_EVENT_RELEASE_FAILURE); +} + +static int nvt_ts_handle_trusted_touch_tvm(struct nvt_ts_data *ts, int value) +{ + int err = 0; + + switch (value) { + case 0: + if ((atomic_read(&ts->trusted_touch_enabled) == 0) && + (atomic_read(&ts->trusted_touch_abort_status) == 0)) { + pr_err("Trusted touch is already disabled\n"); + break; + } + if (atomic_read(&ts->trusted_touch_mode) == + TRUSTED_TOUCH_VM_MODE) { + nvt_ts_trusted_touch_tvm_vm_mode_disable(ts); + } else { + pr_err("Unsupported trusted touch mode\n"); + } + break; + + case 1: + if (atomic_read(&ts->trusted_touch_enabled)) { + pr_err("Trusted touch usecase underway\n"); + err = -EBUSY; + break; + } + if (atomic_read(&ts->trusted_touch_mode) == + TRUSTED_TOUCH_VM_MODE) { + nvt_ts_trusted_touch_tvm_vm_mode_enable(ts); + } else { + pr_err("Unsupported trusted touch mode\n"); + } + break; + + default: + pr_err("unsupported value: %lu\n", value); + err = -EINVAL; + break; + } + + return err; +} + +static void nvt_ts_trusted_touch_abort_tvm(struct nvt_ts_data *ts) +{ + int rc = 0; + int tvm_state = nvt_ts_trusted_touch_get_tvm_driver_state(ts); + + 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: + nvt_irq_enable(false); + case TVM_IRQ_ACCEPTED: + case TVM_INTERRUPT_DISABLED: + rc = hh_irq_release(ts->vm_info->irq_label); + if (rc) + pr_err("Failed to release irq rc:%d\n", rc); + rc = hh_irq_release_notify(ts->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: + rc = nvt_ts_vm_mem_release(ts); + if (rc) + pr_err("Failed to release mem rc:%d\n", rc); + case TVM_IOMEM_RELEASED: + pm_runtime_put_sync(ts->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(&ts->trusted_touch_enabled, 0); + } + + atomic_set(&ts->trusted_touch_abort_status, 0); + nvt_ts_trusted_touch_set_tvm_driver_state(ts, TRUSTED_TOUCH_TVM_INIT); +} + +#else + +static void nvt_ts_bus_put(struct nvt_ts_data *ts); + +static int nvt_ts_trusted_touch_get_pvm_driver_state(struct nvt_ts_data *ts) +{ + int state; + + mutex_lock(&ts->vm_info->pvm_state_mutex); + state = atomic_read(&ts->vm_info->pvm_state); + mutex_unlock(&ts->vm_info->pvm_state_mutex); + + return state; +} + +static void nvt_ts_trusted_touch_set_pvm_driver_state(struct nvt_ts_data *ts, + int state) +{ + mutex_lock(&ts->vm_info->pvm_state_mutex); + atomic_set(&ts->vm_info->pvm_state, state); + mutex_unlock(&ts->vm_info->pvm_state_mutex); +} + +static void nvt_ts_trusted_touch_abort_pvm(struct nvt_ts_data *ts) +{ + int rc = 0; + int pvm_state = nvt_ts_trusted_touch_get_pvm_driver_state(ts); + + 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(ts->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(ts->vm_info->vm_mem_handle, 0); + if (rc) + pr_err("failed to reclaim iomem on pvm rc:%d\n", rc); + ts->vm_info->vm_mem_handle = 0; + case PVM_IOMEM_RECLAIMED: + case PVM_INTERRUPT_DISABLED: + nvt_irq_enable(true); + case PVM_I2C_RESOURCE_ACQUIRED: + case PVM_INTERRUPT_ENABLED: + nvt_ts_bus_put(ts); + complete(&ts->trusted_touch_powerdown); + case TRUSTED_TOUCH_PVM_INIT: + case PVM_I2C_RESOURCE_RELEASED: + atomic_set(&ts->trusted_touch_enabled, 0); + } + + atomic_set(&ts->trusted_touch_abort_status, 0); + + nvt_ts_trusted_touch_set_pvm_driver_state(ts, TRUSTED_TOUCH_PVM_INIT); +} + +static int nvt_ts_clk_prepare_enable(struct nvt_ts_data *ts) +{ + int ret; + + ret = clk_prepare_enable(ts->iface_clk); + if (ret) { + pr_err("error on clk_prepare_enable(iface_clk):%d\n", ret); + return ret; + } + + ret = clk_prepare_enable(ts->core_clk); + if (ret) { + clk_disable_unprepare(ts->iface_clk); + pr_err("error clk_prepare_enable(core_clk):%d\n", ret); + } + return ret; +} + +static void nvt_ts_clk_disable_unprepare(struct nvt_ts_data *ts) +{ + clk_disable_unprepare(ts->core_clk); + clk_disable_unprepare(ts->iface_clk); +} + +static int nvt_ts_bus_get(struct nvt_ts_data *ts) +{ + int rc = 0; + + mutex_lock(&ts->nvt_clk_io_ctrl_mutex); + rc = pm_runtime_get_sync(ts->client->adapter->dev.parent); + if (rc >= 0 && ts->core_clk != NULL && + ts->iface_clk != NULL) { + rc = nvt_ts_clk_prepare_enable(ts); + if (rc) + pm_runtime_put_sync( + ts->client->adapter->dev.parent); + } + mutex_unlock(&ts->nvt_clk_io_ctrl_mutex); + return rc; +} + +static void nvt_ts_bus_put(struct nvt_ts_data *ts) +{ + mutex_lock(&ts->nvt_clk_io_ctrl_mutex); + if (ts->core_clk != NULL && ts->iface_clk != NULL) + nvt_ts_clk_disable_unprepare(ts); + pm_runtime_put_sync(ts->client->adapter->dev.parent); + mutex_unlock(&ts->nvt_clk_io_ctrl_mutex); +} + +static struct hh_notify_vmid_desc *nvt_ts_vm_get_vmid(hh_vmid_t vmid) +{ + struct hh_notify_vmid_desc *vmid_desc; + + vmid_desc = kzalloc(offsetof(struct hh_notify_vmid_desc, + vmid_entries[1]), GFP_KERNEL); + if (!vmid_desc) + return ERR_PTR(ENOMEM); + + vmid_desc->n_vmid_entries = 1; + vmid_desc->vmid_entries[0].vmid = vmid; + return vmid_desc; +} + +static void nvt_trusted_touch_pvm_vm_mode_disable(struct nvt_ts_data *ts) +{ + int rc = 0; + + if (atomic_read(&ts->trusted_touch_abort_status)) { + nvt_ts_trusted_touch_abort_pvm(ts); + return; + } + + if (nvt_ts_trusted_touch_get_pvm_driver_state(ts) != + PVM_ALL_RESOURCES_RELEASE_NOTIFIED) + pr_err("all release notifications are not received yet\n"); + + rc = hh_irq_reclaim(ts->vm_info->irq_label); + if (rc) { + pr_err("failed to reclaim irq on pvm rc:%d\n", rc); + goto error; + } + nvt_ts_trusted_touch_set_pvm_driver_state(ts, + PVM_IRQ_RECLAIMED); + + rc = hh_rm_mem_reclaim(ts->vm_info->vm_mem_handle, 0); + if (rc) { + pr_err("Trusted touch VM mem reclaim failed rc:%d\n", rc); + goto error; + } + nvt_ts_trusted_touch_set_pvm_driver_state(ts, PVM_IOMEM_RECLAIMED); + ts->vm_info->vm_mem_handle = 0; + + nvt_irq_enable(true); + nvt_ts_trusted_touch_set_pvm_driver_state(ts, PVM_INTERRUPT_ENABLED); + nvt_ts_bus_put(ts); + nvt_ts_trusted_touch_set_pvm_driver_state(ts, + PVM_I2C_RESOURCE_RELEASED); + complete(&ts->trusted_touch_powerdown); + nvt_ts_trusted_touch_set_pvm_driver_state(ts, + TRUSTED_TOUCH_PVM_INIT); + atomic_set(&ts->trusted_touch_enabled, 0); + pr_info("trusted touch disabled\n"); + return; +error: + nvt_ts_trusted_touch_abort_handler(ts, + TRUSTED_TOUCH_EVENT_RECLAIM_FAILURE); +} + +static void nvt_ts_vm_irq_on_release_callback(void *data, + unsigned long notif_type, + enum hh_irq_label label) +{ + struct nvt_ts_data *ts = data; + + if (notif_type != HH_RM_NOTIF_VM_IRQ_RELEASED) { + pr_err("invalid notification type\n"); + return; + } + + if (nvt_ts_trusted_touch_get_pvm_driver_state(ts) == + PVM_IOMEM_RELEASE_NOTIFIED) { + nvt_ts_trusted_touch_set_pvm_driver_state(ts, + PVM_ALL_RESOURCES_RELEASE_NOTIFIED); + } else { + nvt_ts_trusted_touch_set_pvm_driver_state(ts, + PVM_IRQ_RELEASE_NOTIFIED); + } +} + +static void nvt_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 *release_payload; + struct trusted_touch_vm_info *vm_info; + struct nvt_ts_data *ts; + + 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; + } + + if (!entry_data || !notif_msg) { + pr_err(" Invalid data or notification message\n"); + return; + } + + ts = (struct nvt_ts_data *)entry_data; + vm_info = ts->vm_info; + if (!vm_info) { + pr_err(" Invalid vm_info\n"); + return; + } + + 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; + } + + if (nvt_ts_trusted_touch_get_pvm_driver_state(ts) == + PVM_IRQ_RELEASE_NOTIFIED) { + nvt_ts_trusted_touch_set_pvm_driver_state(ts, + PVM_ALL_RESOURCES_RELEASE_NOTIFIED); + } else { + nvt_ts_trusted_touch_set_pvm_driver_state(ts, + PVM_IOMEM_RELEASE_NOTIFIED); + } +} + +static int nvt_ts_vm_mem_lend(struct nvt_ts_data *ts) +{ + struct hh_acl_desc *acl_desc; + struct hh_sgl_desc *sgl_desc; + struct hh_notify_vmid_desc *vmid_desc; + hh_memparcel_handle_t mem_handle; + hh_vmid_t trusted_vmid; + int rc = 0; + + acl_desc = nvt_ts_vm_get_acl(HH_TRUSTED_VM); + if (IS_ERR(acl_desc)) { + pr_err("Failed to get acl of IO memories for Trusted touch\n"); + PTR_ERR(acl_desc); + return -EINVAL; + } + + sgl_desc = nvt_ts_vm_get_sgl(ts->vm_info); + if (IS_ERR(sgl_desc)) { + pr_err("Failed to get sgl of IO memories for Trusted touch\n"); + PTR_ERR(sgl_desc); + rc = -EINVAL; + goto sgl_error; + } + + rc = hh_rm_mem_lend(HH_RM_MEM_TYPE_IO, 0, TRUSTED_TOUCH_MEM_LABEL, + acl_desc, sgl_desc, NULL, &mem_handle); + if (rc) { + pr_err("Failed to lend IO memories for Trusted touch rc:%d\n", + rc); + goto error; + } + + pr_info("vm mem lend succeded\n"); + + nvt_ts_trusted_touch_set_pvm_driver_state(ts, PVM_IOMEM_LENT); + + hh_rm_get_vmid(HH_TRUSTED_VM, &trusted_vmid); + + vmid_desc = nvt_ts_vm_get_vmid(trusted_vmid); + + rc = hh_rm_mem_notify(mem_handle, HH_RM_MEM_NOTIFY_RECIPIENT_SHARED, + HH_MEM_NOTIFIER_TAG_TOUCH, vmid_desc); + if (rc) { + pr_err("Failed to notify mem lend to hypervisor rc:%d\n", rc); + goto vmid_error; + } + + nvt_ts_trusted_touch_set_pvm_driver_state(ts, PVM_IOMEM_LENT_NOTIFIED); + + ts->vm_info->vm_mem_handle = mem_handle; +vmid_error: + kfree(vmid_desc); +error: + kfree(sgl_desc); +sgl_error: + kfree(acl_desc); + + return rc; +} + +static int nvt_ts_trusted_touch_pvm_vm_mode_enable(struct nvt_ts_data *ts) +{ + int rc = 0; + struct trusted_touch_vm_info *vm_info = ts->vm_info; + + /* i2c session start and resource acquire */ + if (nvt_ts_bus_get(ts) < 0) { + pr_err("nvt_ts_bus_get failed\n"); + rc = -EIO; + return rc; + } + + nvt_ts_trusted_touch_set_pvm_driver_state(ts, PVM_I2C_RESOURCE_ACQUIRED); + nvt_irq_enable(false); + nvt_ts_trusted_touch_set_pvm_driver_state(ts, PVM_INTERRUPT_DISABLED); + + rc = nvt_ts_vm_mem_lend(ts); + if (rc) { + pr_err("Failed to lend memory\n"); + goto error; + } + + rc = hh_irq_lend_v2(vm_info->irq_label, vm_info->vm_name, + ts->client->irq, &nvt_ts_vm_irq_on_release_callback, ts); + if (rc) { + pr_err("Failed to lend irq\n"); + goto error; + } + + pr_info("vm irq lend succeded for irq:%d\n", ts->client->irq); + nvt_ts_trusted_touch_set_pvm_driver_state(ts, PVM_IRQ_LENT); + + rc = hh_irq_lend_notify(vm_info->irq_label); + if (rc) { + pr_err("Failed to notify irq\n"); + goto error; + } + nvt_ts_trusted_touch_set_pvm_driver_state(ts, PVM_IRQ_LENT_NOTIFIED); + + reinit_completion(&ts->trusted_touch_powerdown); + atomic_set(&ts->trusted_touch_enabled, 1); + pr_info("trusted touch enabled\n"); + return rc; +error: + nvt_ts_trusted_touch_abort_handler(ts, TRUSTED_TOUCH_EVENT_LEND_FAILURE); + return rc; +} + +static int nvt_ts_handle_trusted_touch_pvm(struct nvt_ts_data *ts, int value) +{ + int err = 0; + + switch (value) { + case 0: + if (atomic_read(&ts->trusted_touch_enabled) == 0 && + (atomic_read(&ts->trusted_touch_abort_status) == 0)) { + pr_err("Trusted touch is already disabled\n"); + break; + } + if (atomic_read(&ts->trusted_touch_mode) == + TRUSTED_TOUCH_VM_MODE) { + nvt_trusted_touch_pvm_vm_mode_disable(ts); + } else { + pr_err("Unsupported trusted touch mode\n"); + } + break; + case 1: + if (atomic_read(&ts->trusted_touch_enabled)) { + pr_err("Trusted touch usecase underway\n"); + err = -EBUSY; + break; + } + if (atomic_read(&ts->trusted_touch_mode) == + TRUSTED_TOUCH_VM_MODE) { + err = nvt_ts_trusted_touch_pvm_vm_mode_enable(ts); + } else { + pr_err("Unsupported trusted touch mode\n"); + } + break; + + default: + pr_err("unsupported value: %lu\n", value); + err = -EINVAL; + break; + } + return err; +} + +#endif + +static void nvt_ts_trusted_touch_event_notify(struct nvt_ts_data *ts, int event) +{ + atomic_set(&ts->trusted_touch_event, event); + sysfs_notify(&ts->client->dev.kobj, NULL, "trusted_touch_event"); +} + +static void nvt_ts_trusted_touch_abort_handler(struct nvt_ts_data *ts, int error) +{ + atomic_set(&ts->trusted_touch_abort_status, error); + pr_err("TUI session aborted with failure:%d\n", error); + nvt_ts_trusted_touch_event_notify(ts, error); +} + +static int nvt_ts_vm_init(struct nvt_ts_data *ts) +{ + int rc = 0; + struct trusted_touch_vm_info *vm_info; + void *mem_cookie; + + rc = nvt_ts_populate_vm_info(ts); + if (rc) { + pr_err("Cannot setup vm pipeline\n"); + rc = -EINVAL; + goto fail; + } + + vm_info = ts->vm_info; +#ifdef CONFIG_ARCH_QTI_VM + mem_cookie = hh_mem_notifier_register(HH_MEM_NOTIFIER_TAG_TOUCH, + nvt_ts_vm_mem_on_lend_handler, ts); + if (!mem_cookie) { + pr_err("Failed to register on lend mem notifier\n"); + rc = -EINVAL; + goto init_fail; + } + vm_info->mem_cookie = mem_cookie; + rc = hh_irq_wait_for_lend_v2(vm_info->irq_label, HH_PRIMARY_VM, + &nvt_ts_vm_irq_on_lend_callback, ts); + mutex_init(&ts->vm_info->tvm_state_mutex); + nvt_ts_trusted_touch_set_tvm_driver_state(ts, TRUSTED_TOUCH_TVM_INIT); +#else + mem_cookie = hh_mem_notifier_register(HH_MEM_NOTIFIER_TAG_TOUCH, + nvt_ts_vm_mem_on_release_handler, ts); + if (!mem_cookie) { + pr_err("Failed to register on release mem notifier\n"); + rc = -EINVAL; + goto init_fail; + } + vm_info->mem_cookie = mem_cookie; + mutex_init(&ts->vm_info->pvm_state_mutex); + nvt_ts_trusted_touch_set_pvm_driver_state(ts, TRUSTED_TOUCH_PVM_INIT); +#endif + return rc; +init_fail: + nvt_ts_vm_deinit(ts); +fail: + return rc; +} + +static void nvt_ts_dt_parse_trusted_touch_info(struct nvt_ts_data *ts) +{ + struct device_node *np = ts->client->dev.of_node; + int rc = 0; + const char *selection; + const char *environment; + + rc = of_property_read_string(np, "novatek,trusted-touch-mode", + &selection); + if (rc) { + dev_warn(&ts->client->dev, + "%s: No trusted touch mode selection made\n", __func__); + atomic_set(&ts->trusted_touch_mode, + TRUSTED_TOUCH_MODE_NONE); + return; + } + + if (!strcmp(selection, "vm_mode")) { + atomic_set(&ts->trusted_touch_mode, + TRUSTED_TOUCH_VM_MODE); + pr_err("Selected trusted touch mode to VM mode\n"); + } else { + atomic_set(&ts->trusted_touch_mode, + TRUSTED_TOUCH_MODE_NONE); + pr_err("Invalid trusted_touch mode\n"); + } + + rc = of_property_read_string(np, "novatek,touch-environment", + &environment); + if (rc) { + dev_warn(&ts->client->dev, + "%s: No trusted touch mode environment\n", __func__); + } + ts->touch_environment = environment; + pr_info("Trusted touch environment:%s\n", + ts->touch_environment); +} + +static void nvt_ts_trusted_touch_init(struct nvt_ts_data *ts) +{ + int rc = 0; + + atomic_set(&ts->trusted_touch_initialized, 0); + nvt_ts_dt_parse_trusted_touch_info(ts); + + if (atomic_read(&ts->trusted_touch_mode) == + TRUSTED_TOUCH_MODE_NONE) + return; + + init_completion(&ts->trusted_touch_powerdown); + + /* Get clocks */ + ts->core_clk = devm_clk_get(ts->client->dev.parent, + "m-ahb"); + if (IS_ERR(ts->core_clk)) { + ts->core_clk = NULL; + dev_warn(&ts->client->dev, + "%s: core_clk is not defined\n", __func__); + } + + ts->iface_clk = devm_clk_get(ts->client->dev.parent, + "se-clk"); + if (IS_ERR(ts->iface_clk)) { + ts->iface_clk = NULL; + dev_warn(&ts->client->dev, + "%s: iface_clk is not defined\n", __func__); + } + + if (atomic_read(&ts->trusted_touch_mode) == + TRUSTED_TOUCH_VM_MODE) { + rc = nvt_ts_vm_init(ts); + if (rc) + pr_err("Failed to init VM\n"); + } + atomic_set(&ts->trusted_touch_initialized, 1); +} + +#endif + /******************************************************* * Description: * Novatek touchscreen irq enable/disable function. @@ -1270,43 +2359,134 @@ out: } #endif -/******************************************************* - * Description: - * Novatek touchscreen driver probe function. - * - * return: - * Executive outcomes. 0---succeed. negative---failed - *******************************************************/ -static int32_t nvt_ts_late_probe(struct i2c_client *client, +#ifdef CONFIG_NOVATEK_TRUSTED_TOUCH +static ssize_t trusted_touch_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct nvt_ts_data *ts; + + if (!client) + return scnprintf(buf, PAGE_SIZE, "client is null\n"); + + ts = i2c_get_clientdata(client); + if (!ts) { + pr_err("info is null\n"); + return scnprintf(buf, PAGE_SIZE, "info is null\n"); + } + + return scnprintf(buf, PAGE_SIZE, "%d", + atomic_read(&ts->trusted_touch_enabled)); +} + +static ssize_t trusted_touch_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct nvt_ts_data *info; + unsigned long value; + int err = 0; + + if (!client) + return -EIO; + info = i2c_get_clientdata(client); + if (!info) { + pr_err("info is null\n"); + return -EIO; + } + if (count > 2) + return -EINVAL; + err = kstrtoul(buf, 10, &value); + if (err != 0) + return err; + + if (!atomic_read(&info->trusted_touch_initialized)) + return -EIO; + +#ifdef CONFIG_ARCH_QTI_VM + err = nvt_ts_handle_trusted_touch_tvm(info, value); + if (err) { + pr_err("Failed to handle trusted touch in tvm\n"); + return -EINVAL; + } +#else + err = nvt_ts_handle_trusted_touch_pvm(info, value); + if (err) { + pr_err("Failed to handle trusted touch in pvm\n"); + return -EINVAL; + } +#endif + err = count; + return err; +} + +static DEVICE_ATTR_RW(trusted_touch_enable); + +static struct attribute *nvt_attributes[] = { + &dev_attr_trusted_touch_enable.attr, + NULL, +}; + +static struct attribute_group nvt_attribute_group = { + .attrs = nvt_attributes +}; + +static int ts_create_sysfs(struct nvt_ts_data *ts) +{ + int ret = 0; + + ret = sysfs_create_group(&ts->client->dev.kobj, &nvt_attribute_group); + if (ret) { + pr_err("[EX]: sysfs_create_group() failed!!\n"); + sysfs_remove_group(&ts->client->dev.kobj, &nvt_attribute_group); + return -ENOMEM; + } + + pr_info("[EX]: sysfs_create_group() succeeded!!\n"); + return ret; +} + +#ifdef CONFIG_ARCH_QTI_VM +static int32_t nvt_ts_late_probe_tvm(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int32_t ret = 0; + + if (!atomic_read(&ts->delayed_vm_probe_pending)) { + ts->fw_ver = 0; + ts->abs_x_max = TOUCH_DEFAULT_MAX_WIDTH; + ts->abs_y_max = TOUCH_DEFAULT_MAX_HEIGHT; + ret = nvt_ts_late_probe_sub(ts->client, ts->id); + if (ret) { + pr_err("Failed to enable resources\n"); + return ret; + } + atomic_set(&ts->delayed_vm_probe_pending, 1); + } + + NVT_ERR("irq:%d\n", ts->client->irq); + ret = request_threaded_irq(ts->client->irq, NULL, nvt_ts_work_func, + IRQ_TYPE_EDGE_RISING | IRQF_ONESHOT, NVT_I2C_NAME, ts); + if (ret != 0) { + NVT_ERR("request_threaded_irq failed\n"); + return ret; + } + + ts->irq_enabled = true; + bTouchIsAwake = 1; + NVT_LOG("end\n"); + return 0; +} +#endif +#endif + +static int32_t nvt_ts_late_probe_sub(struct i2c_client *client, const struct i2c_device_id *id) { int32_t ret = 0; #if ((TOUCH_KEY_NUM > 0) || WAKEUP_GESTURE) int32_t retry = 0; #endif - //---request and config GPIOs--- - ret = nvt_gpio_config(ts); - if (ret) { - NVT_ERR("gpio config error!\n"); - goto err_gpio_config_failed; - } - - //---check chip version trim--- - ret = nvt_ts_check_chip_ver_trim(CHIP_VER_TRIM_ADDR); - if (ret) { - NVT_LOG("try to check from old chip ver trim address\n"); - ret = nvt_ts_check_chip_ver_trim(CHIP_VER_TRIM_OLD_ADDR); - if (ret) { - NVT_ERR("chip is not identified\n"); - ret = -EINVAL; - goto err_chipvertrim_failed; - } - } - - nvt_bootloader_reset(); - nvt_check_fw_reset_state(RESET_STATE_INIT); - nvt_get_fw_info(); - //---allocate input device--- ts->input_dev = input_allocate_device(); if (ts->input_dev == NULL) { @@ -1371,6 +2551,58 @@ static int32_t nvt_ts_late_probe(struct i2c_client *client, goto err_input_register_device_failed; } + return 0; + +err_input_register_device_failed: + if (ts->input_dev) { + input_free_device(ts->input_dev); + ts->input_dev = NULL; + } +err_input_dev_alloc_failed: + NVT_ERR("ret = %d\n", ret); + return ret; +} + +/******************************************************* + * Description: + * Novatek touchscreen driver probe function. + * + * return: + * Executive outcomes. 0---succeed. negative---failed + *******************************************************/ +static int32_t nvt_ts_late_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int32_t ret = 0; + + //---request and config GPIOs--- + ret = nvt_gpio_config(ts); + if (ret) { + NVT_ERR("gpio config error!\n"); + goto err_gpio_config_failed; + } + + //---check chip version trim--- + ret = nvt_ts_check_chip_ver_trim(CHIP_VER_TRIM_ADDR); + if (ret) { + NVT_LOG("try to check from old chip ver trim address\n"); + ret = nvt_ts_check_chip_ver_trim(CHIP_VER_TRIM_OLD_ADDR); + if (ret) { + NVT_ERR("chip is not identified\n"); + ret = -EINVAL; + goto err_chipvertrim_failed; + } + } + + nvt_bootloader_reset(); + nvt_check_fw_reset_state(RESET_STATE_INIT); + nvt_get_fw_info(); + ret = nvt_ts_late_probe_sub(ts->client, ts->id); + if (ret) { + NVT_ERR("Failed to enable resources\n"); + goto err_chipvertrim_failed; + } + //---set int-pin & request irq--- client->irq = gpio_to_irq(ts->irq_gpio); if (client->irq) { @@ -1483,12 +2715,6 @@ err_create_nvt_fwu_wq_failed: err_int_request_failed: input_unregister_device(ts->input_dev); ts->input_dev = NULL; -err_input_register_device_failed: - if (ts->input_dev) { - input_free_device(ts->input_dev); - ts->input_dev = NULL; - } -err_input_dev_alloc_failed: err_chipvertrim_failed: nvt_gpio_deconfig(ts); err_gpio_config_failed: @@ -1568,8 +2794,23 @@ static int32_t nvt_ts_probe(struct i2c_client *client, #endif NVT_LOG("end\n"); - return 0; +#ifdef CONFIG_NOVATEK_TRUSTED_TOUCH + nvt_ts_trusted_touch_init(ts); + mutex_init(&(ts->nvt_clk_io_ctrl_mutex)); + ret = ts_create_sysfs(ts); + if (ret) + NVT_ERR("create sysfs node fail\n"); +#endif +#ifdef CONFIG_NOVATEK_TRUSTED_TOUCH +#ifdef CONFIG_ARCH_QTI_VM + ret = nvt_ts_late_probe_tvm(ts->client, ts->id); + if (ret) + NVT_ERR("Failed to enable resources\n"); + +#endif +#endif + return 0; #if defined(CONFIG_DRM) if (active_panel) drm_panel_notifier_unregister(active_panel, &ts->drm_notif); @@ -1727,6 +2968,12 @@ static int32_t nvt_ts_suspend(struct device *dev) return 0; } +#ifdef CONFIG_NOVATEK_TRUSTED_TOUCH + if (atomic_read(&ts->trusted_touch_enabled)) + wait_for_completion_interruptible( + &ts->trusted_touch_powerdown); +#endif + #if !WAKEUP_GESTURE nvt_irq_enable(false); #endif @@ -1979,7 +3226,11 @@ static void __exit nvt_driver_exit(void) i2c_del_driver(&nvt_i2c_driver); } +#ifdef CONFIG_ARCH_QTI_VM +module_init(nvt_driver_init); +#else late_initcall(nvt_driver_init); +#endif //module_init(nvt_driver_init); module_exit(nvt_driver_exit); diff --git a/drivers/input/touchscreen/nt36xxx/nt36xxx.h b/drivers/input/touchscreen/nt36xxx/nt36xxx.h index d3ae17038eaa..7762b4e1a759 100644 --- a/drivers/input/touchscreen/nt36xxx/nt36xxx.h +++ b/drivers/input/touchscreen/nt36xxx/nt36xxx.h @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef CONFIG_HAS_EARLYSUSPEND #include @@ -89,6 +90,75 @@ extern const uint16_t gesture_key_array[]; #define NVT_TOUCH_ESD_PROTECT 0 #define NVT_TOUCH_ESD_CHECK_PERIOD 1500 /* ms */ +enum trusted_touch_mode_config { + TRUSTED_TOUCH_VM_MODE, + TRUSTED_TOUCH_MODE_NONE +}; + +enum trusted_touch_pvm_states { + TRUSTED_TOUCH_PVM_INIT, + PVM_I2C_RESOURCE_ACQUIRED, + PVM_INTERRUPT_DISABLED, + PVM_IOMEM_LENT, + PVM_IOMEM_LENT_NOTIFIED, + PVM_IRQ_LENT, + PVM_IRQ_LENT_NOTIFIED, + PVM_IOMEM_RELEASE_NOTIFIED, + PVM_IRQ_RELEASE_NOTIFIED, + PVM_ALL_RESOURCES_RELEASE_NOTIFIED, + PVM_IRQ_RECLAIMED, + PVM_IOMEM_RECLAIMED, + PVM_INTERRUPT_ENABLED, + PVM_I2C_RESOURCE_RELEASED, + TRUSTED_TOUCH_PVM_STATE_MAX +}; + +enum trusted_touch_tvm_states { + TRUSTED_TOUCH_TVM_INIT, + TVM_IOMEM_LENT_NOTIFIED, + TVM_IRQ_LENT_NOTIFIED, + TVM_ALL_RESOURCES_LENT_NOTIFIED, + TVM_IOMEM_ACCEPTED, + TVM_I2C_SESSION_ACQUIRED, + TVM_IRQ_ACCEPTED, + TVM_INTERRUPT_ENABLED, + TVM_INTERRUPT_DISABLED, + TVM_IRQ_RELEASED, + TVM_IOMEM_RELEASED, + TVM_I2C_SESSION_RELEASED, + TRUSTED_TOUCH_TVM_STATE_MAX +}; + +#ifdef CONFIG_NOVATEK_TRUSTED_TOUCH +#define TRUSTED_TOUCH_MEM_LABEL 0x7 + +#define TRUSTED_TOUCH_EVENT_LEND_FAILURE -1 +#define TRUSTED_TOUCH_EVENT_LEND_NOTIFICATION_FAILURE -2 +#define TRUSTED_TOUCH_EVENT_ACCEPT_FAILURE -3 +#define TRUSTED_TOUCH_EVENT_FUNCTIONAL_FAILURE -4 +#define TRUSTED_TOUCH_EVENT_RELEASE_FAILURE -5 +#define TRUSTED_TOUCH_EVENT_RECLAIM_FAILURE -6 +#define TRUSTED_TOUCH_EVENT_NOTIFICATIONS_PENDING 5 + +struct trusted_touch_vm_info { + enum hh_irq_label irq_label; + enum hh_vm_names vm_name; + u32 hw_irq; + hh_memparcel_handle_t vm_mem_handle; + u32 *iomem_bases; + u32 *iomem_sizes; + u32 iomem_list_size; + void *mem_cookie; +#ifdef CONFIG_ARCH_QTI_VM + struct mutex tvm_state_mutex; + atomic_t tvm_state; +#else + struct mutex pvm_state_mutex; + atomic_t pvm_state; +#endif +}; +#endif + struct nvt_ts_data { struct i2c_client *client; struct input_dev *input_dev; @@ -122,6 +192,20 @@ struct nvt_ts_data { uint8_t xbuf[1025]; struct mutex xbuf_lock; bool irq_enabled; +#ifdef CONFIG_NOVATEK_TRUSTED_TOUCH + struct trusted_touch_vm_info *vm_info; + struct mutex nvt_clk_io_ctrl_mutex; + const char *touch_environment; + struct completion trusted_touch_powerdown; + struct clk *core_clk; + struct clk *iface_clk; + atomic_t trusted_touch_initialized; + atomic_t trusted_touch_enabled; + atomic_t trusted_touch_event; + atomic_t trusted_touch_abort_status; + atomic_t delayed_vm_probe_pending; + atomic_t trusted_touch_mode; +#endif }; #if NVT_TOUCH_PROC