Support touch mmi class for GT9615

TP:
Support touch mmi class for GT9615.

Change-Id: I9cf4d0f811ff48d7480778266a41b3bcd6ad4296
Signed-off-by: Wenge Zhu <zhuwg1@motorola.com>
Reviewed-on: https://gerrit.mot.com/2790500
SLTApproved: Slta Waiver
SME-Granted: SME Approvals Granted
Tested-by: Jira Key
Reviewed-by: Jun Weng <wengjun1@motorola.com>
Reviewed-by: Jichao Zou <zoujc@motorola.com>
Submit-Approved: Jira Key
This commit is contained in:
Wenge Zhu 2023-11-09 14:45:33 +08:00 • committed by zhuwg1
commit efe1db2739
7 changed files with 499 additions and 2 deletions

View file

@ -9,6 +9,9 @@ else
endif
endif
ifeq ($(DRM_PANEL_EVENT_NOTIFICATIONS),true)
KBUILD_OPTIONS += CONFIG_DRM_PANEL_EVENT_NOTIFICATIONS=y
endif
include $(CLEAR_VARS)
LOCAL_MODULE := goodix_gt96x_mmi.ko

View file

@ -20,4 +20,13 @@ ifneq ($(filter m y,$(CONFIG_TOUCHSCREEN_GOODIX_BRL_SPI)),)
EXTRA_CFLAGS += -DCONFIG_TOUCHSCREEN_GOODIX_BRL_SPI
endif
ifneq ($(filter m y,$(CONFIG_INPUT_TOUCHSCREEN_MMI)),)
EXTRA_CFLAGS += -DCONFIG_INPUT_TOUCHSCREEN_MMI
goodix_gt96x_mmi-objs += goodix_ts_mmi.o
endif
ifneq ($(filter m y, $(CONFIG_DRM_PANEL_EVENT_NOTIFICATIONS)),)
EXTRA_CFLAGS += -DCONFIG_DRM_PANEL_EVENT_NOTIFICATIONS
endif
KBUILD_EXTRA_SYMBOLS += $(CURDIR)/$(KBUILD_EXTMOD)/../touchscreen_mmi/$(GKI_OBJ_MODULE_DIR)/Module.symvers

View file

@ -222,6 +222,8 @@ static int goodix_spi_probe(struct spi_device *spi)
dev_res->pdev.id = dev_res->id;
dev_res->pdev.num_resources = 0;
spi_set_drvdata(spi, &dev_res->pdev);
/* register platform device, then the goodix_ts_core
* module will probe the touch deivce.
*/

View file

@ -23,12 +23,15 @@
#include <linux/input/mt.h>
#define INPUT_TYPE_B_PROTOCOL
#endif
#include "goodix_ts_mmi.h"
/* goodix fb test */
// #include "../../../video/fbdev/core/fb_firefly.h"
#define GOODIX_DEFAULT_CFG_NAME "goodix_cfg_group.cfg"
struct goodix_device_manager goodix_devices;
#define PINCTRL_STATE_ACTIVE "cli_pmx_ts_active"
#define PINCTRL_STATE_SUSPEND "cli_pmx_ts_suspend"
static void goodix_device_manager_init(void)
{
@ -886,6 +889,16 @@ static int goodix_parse_dt(struct device_node *node,
board_data->pen_enable = of_property_read_bool(node,
"goodix,pen-enable");
/* get ic compatible */
r = of_property_read_string(node, "compatible", &name_tmp);
if (r) {
ts_err("get compatible failed");
return r;
} else {
ts_info("ic_name form dt: %s", name_tmp);
strncpy(board_data->ic_name, name_tmp, sizeof(board_data->ic_name));
}
ts_info("[DT]x:%d, y:%d, w:%d, p:%d sleep_enable:%d pen_enable:%d",
board_data->panel_max_x, board_data->panel_max_y,
board_data->panel_max_w, board_data->panel_max_p,
@ -1156,6 +1169,54 @@ int goodix_ts_power_off(struct goodix_ts_core *cd)
return ret;
}
/**
* goodix_ts_pinctrl_init - Get pinctrl handler and pinctrl_state
* @core_data: pointer to touch core data
* return: 0 ok, <0 failed
*/
static int goodix_ts_pinctrl_init(struct goodix_ts_core *core_data)
{
int r = 0;
/* get pinctrl handler from of node */
core_data->pinctrl = devm_pinctrl_get(core_data->bus->dev);
if (IS_ERR_OR_NULL(core_data->pinctrl)) {
ts_info("Failed to get pinctrl handler[need confirm]");
core_data->pinctrl = NULL;
return -EINVAL;
}
ts_debug("success get pinctrl");
/* active state */
core_data->pin_sta_active = pinctrl_lookup_state(core_data->pinctrl,
PINCTRL_STATE_ACTIVE);
if (IS_ERR_OR_NULL(core_data->pin_sta_active)) {
r = PTR_ERR(core_data->pin_sta_active);
ts_err("Failed to get pinctrl state:%s, r:%d",
PINCTRL_STATE_ACTIVE, r);
core_data->pin_sta_active = NULL;
goto exit_pinctrl_put;
}
ts_info("success get avtive pinctrl state");
/* suspend state */
core_data->pin_sta_suspend = pinctrl_lookup_state(core_data->pinctrl,
PINCTRL_STATE_SUSPEND);
if (IS_ERR_OR_NULL(core_data->pin_sta_suspend)) {
r = PTR_ERR(core_data->pin_sta_suspend);
ts_err("Failed to get pinctrl state:%s, r:%d",
PINCTRL_STATE_SUSPEND, r);
core_data->pin_sta_suspend = NULL;
goto exit_pinctrl_put;
}
ts_info("success get suspend pinctrl state");
return 0;
exit_pinctrl_put:
devm_pinctrl_put(core_data->pinctrl);
core_data->pinctrl = NULL;
return r;
}
/**
* goodix_ts_gpio_setup - Request gpio resources from GPIO subsysten
* @core_data: pointer to touch core data
@ -1443,7 +1504,7 @@ int goodix_ts_esd_init(struct goodix_ts_core *cd)
return 0;
}
static void goodix_ts_release_connects(struct goodix_ts_core *core_data)
void goodix_ts_release_connects(struct goodix_ts_core *core_data)
{
struct input_dev *input_dev = core_data->input_dev;
struct input_dev *pen_dev = core_data->pen_dev;
@ -1473,6 +1534,7 @@ static void goodix_ts_release_connects(struct goodix_ts_core *core_data)
core_data->hw_ops->after_event_handler(core_data);
}
#ifndef CONFIG_INPUT_TOUCHSCREEN_MMI
/**
* goodix_ts_suspend - Touchscreen suspend function
* Called by PM/FB/EARLYSUSPEN module to put the device to sleep
@ -1552,6 +1614,7 @@ static void goodix_ts_resume_work(struct work_struct *work)
container_of(work, struct goodix_ts_core, resume_work);
goodix_ts_resume(cd);
}
#endif
#if IS_ENABLED(CONFIG_FB)
/**
@ -1580,7 +1643,7 @@ int goodix_ts_fb_notifier_callback(struct notifier_block *self,
return 0;
}
#elif IS_ENABLED(CONFIG_PM)
#elif IS_ENABLED(CONFIG_PM) && !defined(CONFIG_INPUT_TOUCHSCREEN_MMI)
/**
* goodix_ts_pm_suspend - PM suspend function
* Called by kernel during system suspend phrase
@ -1607,6 +1670,29 @@ static const struct dev_pm_ops dev_pm_ops = {
.suspend = goodix_ts_pm_suspend,
.resume = goodix_ts_pm_resume,
};
#else
/**
* goodix_ts_pm_suspend - PM suspend function
* Called by kernel during system suspend phrase
*/
static int goodix_ts_pm_suspend(struct device *dev)
{
ts_info("system enters into pm_suspend");
return 0;
}
/**
* goodix_ts_pm_resume - PM resume function
* Called by kernel during system wakeup
*/
static int goodix_ts_pm_resume(struct device *dev)
{
ts_info("system resumes from pm_suspend");
return 0;
}
static const struct dev_pm_ops dev_pm_ops = {
.suspend = goodix_ts_pm_suspend,
.resume = goodix_ts_pm_resume,
};
#endif
static void goodix_self_check(struct work_struct *work)
@ -1679,7 +1765,9 @@ int goodix_ts_stage2_init(struct goodix_ts_core *cd)
/* inspect init */
inspect_module_init(cd);
#ifndef CONFIG_INPUT_TOUCHSCREEN_MMI
INIT_WORK(&cd->resume_work, goodix_ts_resume_work);
#endif
/* Do self check on first boot */
INIT_WORK(&cd->self_check_work, goodix_self_check);
@ -1867,6 +1955,24 @@ static int goodix_ts_probe(struct platform_device *pdev)
goto err_out;
}
/* Pinctrl handle is optional. */
ret = goodix_ts_pinctrl_init(core_data);
if (!ret && core_data->pinctrl) {
ret = pinctrl_select_state(core_data->pinctrl,
core_data->pin_sta_active);
if (ret < 0)
ts_err("Failed to select active pinstate, r:%d", ret);
}
#ifdef CONFIG_INPUT_TOUCHSCREEN_MMI
ts_info("%s:goodix_ts_mmi_dev_register",__func__);
ret = goodix_ts_mmi_dev_register(pdev);
if (ret) {
ts_info("Failed register touchscreen mmi.");
goto err_out;
}
#endif
/* debug node init */
ret = goodix_tools_init(core_data);
if (ret) {
@ -1900,6 +2006,11 @@ static int goodix_ts_remove(struct platform_device *pdev)
struct goodix_ts_hw_ops *hw_ops = core_data->hw_ops;
struct goodix_ts_esd *ts_esd = &core_data->ts_esd;
#ifdef CONFIG_INPUT_TOUCHSCREEN_MMI
ts_info("%s:goodix_ts_mmi_dev_unregister",__func__);
goodix_ts_mmi_dev_unregister(pdev);
#endif
goodix_tools_exit(core_data);
goodix_fw_update_uninit(core_data);

View file

@ -440,6 +440,7 @@ struct goodix_module {
* @fw_name: name of the firmware image
*/
struct goodix_ts_board_data {
char ic_name[GOODIX_MAX_STR_LABLE_LEN];
char avdd_name[GOODIX_MAX_STR_LABLE_LEN];
char iovdd_name[GOODIX_MAX_STR_LABLE_LEN];
int reset_gpio;
@ -736,6 +737,9 @@ struct goodix_ts_core {
struct goodix_ic_config ic_configs[GOODIX_MAX_CONFIG_GROUP];
struct regulator *avdd;
struct regulator *iovdd;
struct pinctrl *pinctrl;
struct pinctrl_state *pin_sta_active;
struct pinctrl_state *pin_sta_suspend;
u32 gesture_type;
char input_name[32];
@ -785,6 +789,17 @@ extern bool debug_log_flag;
{if (debug_log_flag) \
pr_info("[GDX-CLI-DBG][%s] "fmt"\n", __func__, ##arg);}
/*
* get board data pointer
*/
static inline struct goodix_ts_board_data *board_data(
struct goodix_ts_core *core)
{
if (!core)
return NULL;
return &(core->board_data);
}
struct goodix_ts_hw_ops *goodix_get_hw_ops(void);
int goodix_get_config_proc(struct goodix_ts_core *cd);
@ -815,4 +830,8 @@ void goodix_ts_esd_off(struct goodix_ts_core *cd);
int goodix_ts_report_gesture(struct goodix_ts_core *cd, struct goodix_ts_event *event);
int goodix_ts_power_on(struct goodix_ts_core *cd);
int goodix_ts_power_off(struct goodix_ts_core *cd);
void goodix_ts_release_connects(struct goodix_ts_core *core_data);
#endif

View file

@ -0,0 +1,320 @@
/*
* Copyright (C) 2023 Motorola Mobility LLC
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "goodix_ts_mmi.h"
#include <linux/delay.h>
#include <linux/input/mt.h>
#define GET_GOODIX_DATA(dev) { \
pdev = dev_get_drvdata(dev); \
if (!pdev) { \
ts_err("Failed to get platform device"); \
return -ENODEV; \
} \
core_data = platform_get_drvdata(pdev); \
if (!core_data) { \
ts_err("Failed to get driver data"); \
return -ENODEV; \
} \
}
static int goodix_ts_mmi_methods_get_vendor(struct device *dev, void *cdata) {
return scnprintf(TO_CHARP(cdata), TS_MMI_MAX_VENDOR_LEN, "%s", "goodix");
}
static int goodix_ts_mmi_methods_get_productinfo(struct device *dev, void *cdata) {
struct platform_device *pdev;
struct goodix_ts_core *core_data;
struct goodix_ts_board_data *ts_bdata;
char* ic_info;
GET_GOODIX_DATA(dev);
ts_bdata = board_data(core_data);
if (!ts_bdata) {
ts_err("Failed to get ts board data");
return -ENODEV;
}
ic_info = strstr(ts_bdata->ic_name, ",");
ic_info++;
return scnprintf(TO_CHARP(cdata), TS_MMI_MAX_VENDOR_LEN, "%s", ic_info);
}
#define TOUCH_CFG_VERSION_ADDR 0x10076
static int goodix_ts_mmi_methods_get_build_id(struct device *dev, void *cdata) {
int ret;
struct platform_device *pdev;
struct goodix_ts_core *core_data;
u32 cfg_id;
GET_GOODIX_DATA(dev);
ret = core_data->hw_ops->read(core_data, TOUCH_CFG_VERSION_ADDR,
(u8*)&cfg_id, sizeof(cfg_id));
if (ret) {
ts_info("failed get fw version data, %d", ret);
return -EINVAL;
}
return snprintf(TO_CHARP(cdata), TS_MMI_MAX_ID_LEN, "%04x", le32_to_cpu(cfg_id));
}
#define TOUCH_FW_VERSION_ADDR 0x1007E
/*return firmware version*/
static int goodix_ts_mmi_methods_get_config_id(struct device *dev, void *cdata) {
int ret;
struct platform_device *pdev;
struct goodix_ts_core *core_data;
u8 fw_id[4] = {0};
GET_GOODIX_DATA(dev);
ret = core_data->hw_ops->read(core_data, TOUCH_FW_VERSION_ADDR,
fw_id, sizeof(fw_id));
if (ret) {
ts_info("failed get fw version data, %d", ret);
return -EINVAL;
}
return snprintf(TO_CHARP(cdata), TS_MMI_MAX_ID_LEN, "%02x%02x%02x%02x",
fw_id[0], fw_id[1], fw_id[2], fw_id[3]);
}
static int goodix_ts_mmi_methods_get_bus_type(struct device *dev, void *idata) {
struct platform_device *pdev;
struct goodix_ts_core *core_data;
GET_GOODIX_DATA(dev);
TO_INT(idata) = core_data->bus->bus_type == GOODIX_BUS_TYPE_I2C ?
TOUCHSCREEN_MMI_BUS_TYPE_I2C : TOUCHSCREEN_MMI_BUS_TYPE_SPI;
return 0;
}
static int goodix_ts_mmi_methods_get_irq_status(struct device *dev, void *idata) {
struct platform_device *pdev;
struct goodix_ts_core *core_data;
struct goodix_ts_board_data *ts_bdata;
GET_GOODIX_DATA(dev);
ts_bdata = board_data(core_data);
if (!ts_bdata) {
ts_err("Failed to get ts board data");
return -ENODEV;
}
TO_INT(idata) = gpio_get_value(ts_bdata->irq_gpio);
return 0;
}
static int goodix_ts_mmi_methods_get_drv_irq(struct device *dev, void *idata) {
struct platform_device *pdev;
struct goodix_ts_core *core_data;
GET_GOODIX_DATA(dev);
TO_INT(idata) = atomic_read(&core_data->irq_enabled);
return 0;
}
static int goodix_ts_mmi_methods_get_poweron(struct device *dev, void *idata) {
struct platform_device *pdev;
struct goodix_ts_core *core_data;
GET_GOODIX_DATA(dev);
TO_INT(idata) = core_data->power_on;
return 0;
}
static int goodix_ts_mmi_methods_get_flashprog(struct device *dev, void *idata) {
struct platform_device *pdev;
struct goodix_ts_core *core_data;
GET_GOODIX_DATA(dev);
TO_INT(idata) = core_data->update_ctrl.status;
return 0;
}
/* reset chip
* type:can control software reset and hardware reset,
* but GOODIX has no software reset,
* so the type parameter is not used here.
*/
static int goodix_ts_mmi_methods_reset(struct device *dev, int type) {
int ret = -ENODEV;
struct platform_device *pdev;
struct goodix_ts_core *core_data;
GET_GOODIX_DATA(dev);
if (core_data->hw_ops->reset)
ret = core_data->hw_ops->reset(core_data, GOODIX_NORMAL_RESET_DELAY_MS);
return ret;
}
static int goodix_ts_mmi_methods_drv_irq(struct device *dev, int state) {
int ret = -ENODEV;
struct platform_device *pdev;
struct goodix_ts_core *core_data;
GET_GOODIX_DATA(dev);
if (core_data->hw_ops->irq_enable)
ret = core_data->hw_ops->irq_enable(core_data, !(!state));
return ret;
}
static int goodix_ts_mmi_methods_power(struct device *dev, int on) {
struct platform_device *pdev;
struct goodix_ts_core *core_data;
GET_GOODIX_DATA(dev);
if (on == TS_MMI_POWER_ON)
return goodix_ts_power_on(core_data);
else if(on == TS_MMI_POWER_OFF)
return goodix_ts_power_off(core_data);
else {
ts_err("Invalid power parameter %d.\n", on);
return -EINVAL;
}
}
static int goodix_ts_mmi_pre_suspend(struct device *dev) {
struct platform_device *pdev;
struct goodix_ts_core *core_data;
GET_GOODIX_DATA(dev);
ts_info("Suspend start");
atomic_set(&core_data->suspended, 1);
/*
* notify suspend event, inform the esd protector
* and charger detector to turn off the work
*/
goodix_ts_esd_off(core_data);
return 0;
}
static int goodix_ts_mmi_panel_state(struct device *dev,
enum ts_mmi_pm_mode from, enum ts_mmi_pm_mode to)
{
struct platform_device *pdev;
struct goodix_ts_core *core_data;
GET_GOODIX_DATA(dev);
switch (to) {
case TS_MMI_PM_GESTURE:
break;
case TS_MMI_PM_DEEPSLEEP:
break;
case TS_MMI_PM_ACTIVE:
break;
default:
ts_err("Invalid power state parameter %d.\n", to);
return -EINVAL;
}
return 0;
}
static int goodix_ts_mmi_post_suspend(struct device *dev) {
struct goodix_ts_core *core_data;
struct platform_device *pdev;
GET_GOODIX_DATA(dev);
goodix_ts_release_connects(core_data);
ts_info("Suspend end");
return 0;
}
static int goodix_ts_mmi_pre_resume(struct device *dev) {
struct platform_device *pdev;
struct goodix_ts_core *core_data;
ts_info("Resume start");
GET_GOODIX_DATA(dev);
atomic_set(&core_data->suspended, 0);
return 0;
}
static int goodix_ts_mmi_post_resume(struct device *dev) {
struct platform_device *pdev;
struct goodix_ts_core *core_data;
GET_GOODIX_DATA(dev);
/* open esd */
goodix_ts_esd_on(core_data);
ts_info("Resume end");
return 0;
}
static struct ts_mmi_methods goodix_ts_mmi_methods = {
.get_vendor = goodix_ts_mmi_methods_get_vendor,
.get_productinfo = goodix_ts_mmi_methods_get_productinfo,
.get_build_id = goodix_ts_mmi_methods_get_build_id,
.get_config_id = goodix_ts_mmi_methods_get_config_id,
.get_bus_type = goodix_ts_mmi_methods_get_bus_type,
.get_irq_status = goodix_ts_mmi_methods_get_irq_status,
.get_drv_irq = goodix_ts_mmi_methods_get_drv_irq,
.get_poweron = goodix_ts_mmi_methods_get_poweron,
.get_flashprog = goodix_ts_mmi_methods_get_flashprog,
/* SET methods */
.reset = goodix_ts_mmi_methods_reset,
.drv_irq = goodix_ts_mmi_methods_drv_irq,
.power = goodix_ts_mmi_methods_power,
/* PM callback */
.pre_suspend = goodix_ts_mmi_pre_suspend,
.panel_state = goodix_ts_mmi_panel_state,
.post_suspend = goodix_ts_mmi_post_suspend,
.pre_resume = goodix_ts_mmi_pre_resume,
.post_resume = goodix_ts_mmi_post_resume,
};
int goodix_ts_mmi_dev_register(struct platform_device *pdev) {
int ret;
struct goodix_ts_core *core_data;
core_data = platform_get_drvdata(pdev);
if (!core_data) {
ts_err("Failed to get driver data");
return -ENODEV;
}
ret = ts_mmi_dev_register(core_data->bus->dev, &goodix_ts_mmi_methods);
if (ret) {
dev_err(&pdev->dev, "Failed to register ts mmi\n");
return ret;
}
return 0;
}
void goodix_ts_mmi_dev_unregister(struct platform_device *pdev) {
struct goodix_ts_core *core_data;
core_data = platform_get_drvdata(pdev);
if (!core_data)
ts_err("Failed to get driver data");
ts_mmi_dev_unregister(core_data->bus->dev);
}

View file

@ -0,0 +1,33 @@
/*
* Copyright (C) 2023 Motorola Mobility LLC
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __GOODIX_TS_MMI_H__
#define __GOODIX_TS_MMI_H__
#include <linux/platform_device.h>
#include <linux/touchscreen_mmi.h>
#include <linux/mmi_wake_lock.h>
#include "goodix_ts_core.h"
#ifdef CONFIG_INPUT_TOUCHSCREEN_MMI
int goodix_ts_mmi_dev_register(struct platform_device *ts_device);
void goodix_ts_mmi_dev_unregister(struct platform_device *ts_device);
#else
static int inline goodix_ts_mmi_dev_register(struct platform_device *ts_device) {
return -ENOSYS;
}
static int inline goodix_ts_mmi_dev_unregister(struct platform_device *ts_device) {
return -ENOSYS;
}
#endif
#endif