From 1b609ecc23d2252210ff1e610294873fa4e21631 Mon Sep 17 00:00:00 2001 From: haojl2 Date: Fri, 27 Sep 2019 12:43:55 +0800 Subject: [PATCH] nova_0flash_mmi: notify firmware when usb connected TP: When USB connected, notify this info to firmware. This will help firmware to handle ghost touch issue. Change-Id: I86ac9a721eb6fdca3cb3a9c38d1b55290f6b8175 Signed-off-by: haojl2 Reviewed-on: https://gerrit.mot.com/1448175 SME-Granted: SME Approvals Granted SLTApproved: Slta Waiver Tested-by: Jira Key Reviewed-by: Jun Weng Reviewed-by: Huosheng Liao Submit-Approved: Jira Key --- .../touchscreen/nova_0flash_mmi/nt36xxx.c | 195 ++++++++++++++++++ .../touchscreen/nova_0flash_mmi/nt36xxx.h | 15 ++ .../nova_0flash_mmi/nt36xxx_fw_update.c | 3 + 3 files changed, 213 insertions(+) diff --git a/drivers/input/touchscreen/nova_0flash_mmi/nt36xxx.c b/drivers/input/touchscreen/nova_0flash_mmi/nt36xxx.c index 667291acd7f3..dad2aa6be2f2 100644 --- a/drivers/input/touchscreen/nova_0flash_mmi/nt36xxx.c +++ b/drivers/input/touchscreen/nova_0flash_mmi/nt36xxx.c @@ -24,6 +24,7 @@ #include #include #include +#include #if defined(CONFIG_FB) #ifdef CONFIG_DRM_MSM @@ -109,6 +110,10 @@ static void nvt_ts_late_resume(struct early_suspend *h); uint32_t ENG_RST_ADDR = 0x7FFF80; uint32_t SWRST_N8_ADDR = 0; //read from dtsi uint32_t SPI_RD_FAST_ADDR = 0; //read from dtsi +static int charger_notifier_callback(struct notifier_block *nb, unsigned long val, void *v); +static int nvt_set_charger(uint8_t charger_on_off); +static void nvt_charger_notify_work(struct work_struct *work); +static int usb_detect_flag = 0; #if TOUCH_KEY_NUM > 0 const uint16_t touch_key_array[TOUCH_KEY_NUM] = { @@ -1110,6 +1115,12 @@ static int32_t nvt_parse_dt(struct device *dev) } else { NVT_LOG("SPI_RD_FAST_ADDR=0x%06X\n", SPI_RD_FAST_ADDR); } + if (of_property_read_bool(np, "novatek,usb_charger")) { + NVT_LOG("novatek,usb_charger set"); + ts->charger_detection_enable = 1; + } else { + ts->charger_detection_enable = 0; + } return ret; } @@ -1940,6 +1951,59 @@ static int32_t nvt_ts_probe(struct spi_device *client) } #endif + if (ts->charger_detection_enable) { + ts->charger_detection = kzalloc(sizeof(struct usb_charger_detection), GFP_KERNEL); + if (ts->charger_detection == NULL) { + NVT_ERR("failed to allocated memory for usb_charger_detection\n"); + goto err_charger_detection_alloc_failed; + } + } + + if (ts->charger_detection) { + struct power_supply *psy = NULL; + union power_supply_propval prop = {0}; + + NVT_LOG("charger_detection on"); + ts->charger_detection->usb_connected = 0; + ts->charger_detection->nvt_charger_notify_wq = create_singlethread_workqueue("nvt_charger_wq"); + if (!ts->charger_detection->nvt_charger_notify_wq) { + NVT_ERR("allocate nvt_charger_notify_wq failed\n"); + goto err_charger_notify_wq_failed; + } + INIT_WORK(&ts->charger_detection->charger_notify_work, nvt_charger_notify_work); + + ts->charger_detection->charger_notif.notifier_call = charger_notifier_callback; + ret = power_supply_reg_notifier(&ts->charger_detection->charger_notif); + if (ret) { + NVT_ERR("Unable to register charger_notifier:%d\n", ret); + goto err_register_charger_notify_failed; + } + + /* if power supply supplier registered brfore TP + * ps_notify_callback will not receive PSY_EVENT_PROP_ADDED + * event, and will cause miss to set TP into charger state. + * So check PS state in probe. + */ + psy = power_supply_get_by_name("usb"); + if (psy) { + ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_PRESENT,&prop); + if (ret < 0) { + NVT_ERR("Couldn't get POWER_SUPPLY_PROP_ONLINE rc=%d\n", ret); + goto err_register_charger_notify_failed; + } else { + usb_detect_flag = prop.intval; + if (usb_detect_flag != ts->charger_detection->usb_connected) { + if (USB_DETECT_IN == usb_detect_flag) { + ts->charger_detection->usb_connected = USB_DETECT_IN; + } else { + ts->charger_detection->usb_connected = USB_DETECT_OUT; + } + nvt_set_charger(ts->charger_detection->usb_connected); + } + } + } + } + #if BOOT_UPDATE_FIRMWARE nvt_fwu_wq = alloc_workqueue("nvt_fwu_wq", WQ_UNBOUND | WQ_MEM_RECLAIM, 1); if (!nvt_fwu_wq) { @@ -2075,6 +2139,16 @@ err_create_nvt_fwu_wq_failed: #if WAKEUP_GESTURE device_init_wakeup(&ts->input_dev->dev, 0); #endif +err_register_charger_notify_failed: + if (ts->charger_detection) { + if (ts->charger_detection->charger_notif.notifier_call) + power_supply_unreg_notifier(&ts->charger_detection->charger_notif); + destroy_workqueue(ts->charger_detection->nvt_charger_notify_wq); + ts->charger_detection->nvt_charger_notify_wq = NULL; + kfree(ts->charger_detection); + } +err_charger_detection_alloc_failed: +err_charger_notify_wq_failed: free_irq(client->irq, ts); err_int_request_failed: input_unregister_device(ts->input_dev); @@ -2132,6 +2206,12 @@ static int32_t nvt_ts_remove(struct spi_device *client) #endif #if NVT_TOUCH_PROC nvt_flash_proc_deinit(); + if (ts->charger_detection) { + if (ts->charger_detection->charger_notif.notifier_call) + power_supply_unreg_notifier(&ts->charger_detection->charger_notif); + destroy_workqueue(ts->charger_detection->nvt_charger_notify_wq); + kfree(ts->charger_detection); + } #endif #if NVT_TOUCH_ESD_PROTECT @@ -2380,6 +2460,10 @@ static int32_t nvt_ts_resume(struct device *dev) msecs_to_jiffies(NVT_TOUCH_ESD_CHECK_PERIOD)); #endif /* #if NVT_TOUCH_ESD_PROTECT */ + if (ts->charger_detection) { + queue_work(ts->charger_detection->nvt_charger_notify_wq, &ts->charger_detection->charger_notify_work); + } + #if WAKEUP_GESTURE #ifdef NVT_SENSOR_EN if (ts->wakeable) { @@ -2495,6 +2579,117 @@ static const struct spi_device_id nvt_ts_id[] = { { } }; +static int nvt_set_charger(uint8_t charger_on_off) +{ + uint8_t buf[8] = {0}; + int32_t ret = 0; + + NVT_LOG("set charger: %d\n", charger_on_off); + + msleep(20); + //---set xdata index to EVENT BUF ADDR--- + ret = nvt_set_page(ts->mmap->EVENT_BUF_ADDR | EVENT_MAP_HOST_CMD); + if (ret < 0) { + NVT_ERR("Set event buffer index fail!\n"); + goto nvt_set_charger_out; + } + + if (charger_on_off == USB_DETECT_IN) { + buf[0] = EVENT_MAP_HOST_CMD; + buf[1] = CMD_CHARGER_ON; + ret = CTP_SPI_WRITE(ts->client, buf, 2); + if (ret < 0) { + NVT_ERR("Write set charger command fail!\n"); + goto nvt_set_charger_out; + } else { + NVT_LOG("set charger on cmd succeeded\n"); + } + } else if (charger_on_off == USB_DETECT_OUT) { + buf[0] = EVENT_MAP_HOST_CMD; + buf[1] = CMD_CHARGER_OFF; + ret = CTP_SPI_WRITE(ts->client, buf, 2); + if (ret < 0) { + NVT_ERR("Write set charger command fail!\n"); + goto nvt_set_charger_out; + } else { + NVT_LOG("set charger off cmd succeeded\n"); + } + } else { + NVT_ERR("Invalid charger parameter!\n"); + ret = -EINVAL; + } + + nvt_set_charger_out: + + return ret; +} + +static void nvt_charger_notify_work(struct work_struct *work) +{ + if (NULL == work) { + NVT_ERR("%s: parameter work are null!\n", __func__); + return; + } + NVT_LOG("enter\n"); + if (USB_DETECT_IN == usb_detect_flag) { + if (mutex_lock_interruptible(&ts->lock)) { + NVT_ERR("Failed to lock in mutex_lock_interruptible(&ts->lock).\n"); + return; + } + nvt_set_charger(USB_DETECT_IN); + mutex_unlock(&ts->lock); + } else if (USB_DETECT_OUT == usb_detect_flag) { + if (mutex_lock_interruptible(&ts->lock)) { + NVT_ERR("Failed to lock in mutex_lock_interruptible(&ts->lock).\n"); + return; + } + nvt_set_charger(USB_DETECT_OUT); + mutex_unlock(&ts->lock); + }else{ + NVT_LOG("Charger flag:%d not currently required!\n",usb_detect_flag); + } +} + +static int charger_notifier_callback(struct notifier_block *nb, + unsigned long val, void *v) +{ + int ret = 0; + struct power_supply *psy = NULL; + struct usb_charger_detection *charger_detection = + container_of(nb, struct usb_charger_detection, charger_notif); + union power_supply_propval prop; + + psy= power_supply_get_by_name("usb"); + if (!psy){ + return -EINVAL; + NVT_ERR("Couldn't get usbpsy\n"); + } + + if (!strcmp(psy->desc->name, "usb")){ + if (psy && charger_detection && val == POWER_SUPPLY_PROP_STATUS) { + ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_PRESENT,&prop); + if (ret < 0) { + NVT_ERR("Couldn't get POWER_SUPPLY_PROP_ONLINE rc=%d\n", ret); + return ret; + }else{ + usb_detect_flag = prop.intval; + if(usb_detect_flag != charger_detection->usb_connected) { + if (USB_DETECT_IN == usb_detect_flag) { + charger_detection->usb_connected = USB_DETECT_IN; + }else{ + charger_detection->usb_connected = USB_DETECT_OUT; + } + if (bTouchIsAwake){ + queue_work(charger_detection->nvt_charger_notify_wq, + &charger_detection->charger_notify_work); + } + } + } + } + } + return 0; +} + #ifdef CONFIG_OF static struct of_device_id nvt_match_table[] = { { .compatible = "novatek,NVT-ts-spi",}, diff --git a/drivers/input/touchscreen/nova_0flash_mmi/nt36xxx.h b/drivers/input/touchscreen/nova_0flash_mmi/nt36xxx.h index e793cdd87333..e109a98b52bb 100644 --- a/drivers/input/touchscreen/nova_0flash_mmi/nt36xxx.h +++ b/drivers/input/touchscreen/nova_0flash_mmi/nt36xxx.h @@ -123,6 +123,19 @@ struct nvt_sensor_platform_data { }; #endif +/* charger detect */ +#define USB_DETECT_IN 1 +#define USB_DETECT_OUT 0 +#define CMD_CHARGER_ON (0x53) +#define CMD_CHARGER_OFF (0x51) + +struct usb_charger_detection { + struct notifier_block charger_notif; + uint8_t usb_connected; + struct workqueue_struct *nvt_charger_notify_wq; + struct work_struct charger_notify_work; +}; + struct nvt_ts_data { struct spi_device *client; struct input_dev *input_dev; @@ -162,6 +175,8 @@ struct nvt_ts_data { #ifdef CONFIG_MTK_SPI struct mt_chip_conf spi_ctrl; #endif + uint32_t charger_detection_enable; + struct usb_charger_detection *charger_detection; #ifdef CONFIG_SPI_MT65XX struct mtk_chip_config spi_ctrl; #endif diff --git a/drivers/input/touchscreen/nova_0flash_mmi/nt36xxx_fw_update.c b/drivers/input/touchscreen/nova_0flash_mmi/nt36xxx_fw_update.c index 6025341dadd8..61c7cc22a0d6 100644 --- a/drivers/input/touchscreen/nova_0flash_mmi/nt36xxx_fw_update.c +++ b/drivers/input/touchscreen/nova_0flash_mmi/nt36xxx_fw_update.c @@ -1008,6 +1008,9 @@ void Boot_Update_Firmware(struct work_struct *work) } else { nvt_check_fw_reset_state(RESET_STATE_REK); } + if (ts->charger_detection) { + queue_work(ts->charger_detection->nvt_charger_notify_wq, &ts->charger_detection->charger_notify_work); + } mutex_unlock(&ts->lock); }