input: touchscreen: synaptics_tcm: enable touch driver

Enable touch driver in touch driver.
Support drm_panel callback to be notified when screen on/off.
Add new property "synaptics,firmware-name" when different modules
with same touch IC.

Change-Id: I58159ce531913108e702227c5474fdc2f539d2d3
Signed-off-by: Fei Mao <feim1@codeaurora.org>
Signed-off-by: Ritesh Kumar <riteshk@codeaurora.org>
This commit is contained in:
Fei Mao 2019-11-12 17:14:59 +08:00 committed by Gerrit - the friendly Code Review server
parent 43aa526391
commit da720aef2b
10 changed files with 210 additions and 159 deletions

View File

@ -1314,4 +1314,18 @@ source "drivers/input/touchscreen/st/Kconfig"
source "drivers/input/touchscreen/focaltech_touch/Kconfig"
config TOUCHSCREEN_SYNAPTICS_TCM
bool "Synaptics TCM Touchscreen Driver"
depends on I2C
default y
help
Say Y here if you have a Synaptics Touchscreen.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called synaptics_tcm.
source "drivers/input/touchscreen/synaptics_tcm/Kconfig"
endif

View File

@ -112,3 +112,4 @@ obj-$(CONFIG_TOUCHSCREEN_RASPBERRYPI_FW) += raspberrypi-ts.o
obj-$(CONFIG_TOUCHSCREEN_IQS5XX) += iqs5xx.o
obj-$(CONFIG_TOUCHSCREEN_ST) += st/
obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_touch/
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_TCM) += synaptics_tcm/

View File

@ -3,6 +3,7 @@
#
menuconfig TOUCHSCREEN_SYNAPTICS_TCM
bool "Synaptics TCM touchscreen"
default y
help
Say Y here if you have a Synaptics TCM touchscreen connected
to your system.
@ -41,6 +42,7 @@ endchoice
config TOUCHSCREEN_SYNAPTICS_TCM_CORE
tristate "Synaptics TCM core module"
depends on I2C || SPI_MASTER
default y
help
Say Y here to enable core functionality.
@ -52,6 +54,7 @@ config TOUCHSCREEN_SYNAPTICS_TCM_CORE
config TOUCHSCREEN_SYNAPTICS_TCM_TOUCH
tristate "Synaptics TCM touch module"
depends on TOUCHSCREEN_SYNAPTICS_TCM_CORE
default y
help
Say Y here to enable support for touch reporting.
@ -63,6 +66,7 @@ config TOUCHSCREEN_SYNAPTICS_TCM_TOUCH
config TOUCHSCREEN_SYNAPTICS_TCM_DEVICE
tristate "Synaptics TCM device module"
depends on TOUCHSCREEN_SYNAPTICS_TCM_CORE
default y
help
Say Y here to enable support for TCM device functionality.
@ -85,6 +89,7 @@ config TOUCHSCREEN_SYNAPTICS_TCM_TESTING
config TOUCHSCREEN_SYNAPTICS_TCM_REFLASH
tristate "Synaptics TCM reflash module"
depends on TOUCHSCREEN_SYNAPTICS_TCM_CORE
default y
help
Say Y here to enable support for reflash functionality.
@ -96,6 +101,7 @@ config TOUCHSCREEN_SYNAPTICS_TCM_REFLASH
config TOUCHSCREEN_SYNAPTICS_TCM_RECOVERY
tristate "Synaptics TCM recovery module"
depends on TOUCHSCREEN_SYNAPTICS_TCM_CORE
default y
help
Say Y here to enable support for recovery functionality.
@ -118,6 +124,7 @@ config TOUCHSCREEN_SYNAPTICS_TCM_ZEROFLASH
config TOUCHSCREEN_SYNAPTICS_TCM_DIAGNOSTICS
tristate "Synaptics TCM diagnostics module"
depends on TOUCHSCREEN_SYNAPTICS_TCM_CORE
default y
help
Say Y here to enable support for diagnostics functionality.

View File

@ -3040,21 +3040,18 @@ static int syna_tcm_fb_notifier_cb(struct notifier_block *nb,
unsigned long action, void *data)
{
int retval = 0;
int *transition;
struct msm_drm_notifier *evdata = data;
int transition;
struct drm_panel_notifier *evdata = data;
struct syna_tcm_hcd *tcm_hcd =
container_of(nb, struct syna_tcm_hcd, fb_notifier);
if (!evdata || (evdata->id != 0))
if (!evdata)
return 0;
if (!evdata->data || !tcm_hcd)
return 0;
transition = (int *) evdata->data;
transition = *(int *)evdata->data;
if (atomic_read(&tcm_hcd->firmware_flashing)
&& *transition == MSM_DRM_BLANK_POWERDOWN) {
&& transition == DRM_PANEL_BLANK_POWERDOWN) {
retval = wait_event_interruptible_timeout(tcm_hcd->reflash_wq,
!atomic_read(&tcm_hcd->firmware_flashing),
msecs_to_jiffies(RESPONSE_TIMEOUT_MS));
@ -3066,21 +3063,21 @@ static int syna_tcm_fb_notifier_cb(struct notifier_block *nb,
}
}
if (action == MSM_DRM_EARLY_EVENT_BLANK &&
*transition == MSM_DRM_BLANK_POWERDOWN)
if (action == DRM_PANEL_EARLY_EVENT_BLANK &&
transition == DRM_PANEL_BLANK_POWERDOWN)
retval = syna_tcm_early_suspend(&tcm_hcd->pdev->dev);
else if (action == MSM_DRM_EVENT_BLANK) {
if (*transition == MSM_DRM_BLANK_POWERDOWN) {
else if (action == DRM_PANEL_EVENT_BLANK) {
if (transition == DRM_PANEL_BLANK_POWERDOWN) {
retval = syna_tcm_suspend(&tcm_hcd->pdev->dev);
tcm_hcd->fb_ready = 0;
} else if (*transition == MSM_DRM_BLANK_UNBLANK) {
} else if (transition == DRM_PANEL_BLANK_UNBLANK) {
#ifndef RESUME_EARLY_UNBLANK
retval = syna_tcm_resume(&tcm_hcd->pdev->dev);
tcm_hcd->fb_ready++;
#endif
}
} else if (action == MSM_DRM_EARLY_EVENT_BLANK &&
*transition == MSM_DRM_BLANK_UNBLANK) {
} else if (action == DRM_PANEL_EARLY_EVENT_BLANK &&
transition == DRM_PANEL_BLANK_UNBLANK) {
#ifdef RESUME_EARLY_UNBLANK
retval = syna_tcm_resume(&tcm_hcd->pdev->dev);
tcm_hcd->fb_ready++;
@ -3249,6 +3246,7 @@ static int syna_tcm_probe(struct platform_device *pdev)
struct syna_tcm_hcd *tcm_hcd;
const struct syna_tcm_board_data *bdata;
const struct syna_tcm_hw_interface *hw_if;
struct drm_panel *active_panel = tcm_get_panel();
hw_if = pdev->dev.platform_data;
if (!hw_if) {
@ -3405,11 +3403,17 @@ static int syna_tcm_probe(struct platform_device *pdev)
#ifdef CONFIG_DRM
tcm_hcd->fb_notifier.notifier_call = syna_tcm_fb_notifier_cb;
retval = msm_drm_register_client(&tcm_hcd->fb_notifier);
if (retval < 0) {
LOGE(tcm_hcd->pdev->dev.parent,
"Failed to register DRM notifier client\n");
if (active_panel) {
retval = drm_panel_notifier_register(active_panel,
&tcm_hcd->fb_notifier);
if (retval < 0) {
dev_err(&pdev->dev,
"%s: Failed to register fb notifier client\n",
__func__);
goto err_drm_reg;
}
}
#elif CONFIG_FB
tcm_hcd->fb_notifier.notifier_call = syna_tcm_fb_notifier_cb;
retval = fb_register_client(&tcm_hcd->fb_notifier);
@ -3452,7 +3456,9 @@ static int syna_tcm_probe(struct platform_device *pdev)
err_create_run_kthread:
#ifdef CONFIG_DRM
msm_drm_unregister_client(&tcm_hcd->fb_notifier);
if (active_panel)
drm_panel_notifier_unregister(active_panel,
&tcm_hcd->fb_notifier);
#elif CONFIG_FB
fb_unregister_client(&tcm_hcd->fb_notifier);
#endif
@ -3487,6 +3493,7 @@ static int syna_tcm_probe(struct platform_device *pdev)
RELEASE_BUFFER(tcm_hcd->out);
RELEASE_BUFFER(tcm_hcd->in);
err_drm_reg:
kfree(tcm_hcd);
return retval;
@ -3584,6 +3591,7 @@ static int syna_tcm_remove(struct platform_device *pdev)
struct syna_tcm_module_handler *tmp_handler;
struct syna_tcm_hcd *tcm_hcd = platform_get_drvdata(pdev);
const struct syna_tcm_board_data *bdata = tcm_hcd->hw_if->bdata;
struct drm_panel *active_panel = tcm_get_panel();
mutex_lock(&mod_pool.mutex);
@ -3624,7 +3632,9 @@ static int syna_tcm_remove(struct platform_device *pdev)
kthread_stop(tcm_hcd->notifier_thread);
#ifdef CONFIG_DRM
msm_drm_unregister_client(&tcm_hcd->fb_notifier);
if (active_panel)
drm_panel_notifier_unregister(active_panel,
&tcm_hcd->fb_notifier);
#elif CONFIG_FB
fb_unregister_client(&tcm_hcd->fb_notifier);
#endif
@ -3713,7 +3723,7 @@ static void __exit syna_tcm_module_exit(void)
syna_tcm_bus_exit();
}
module_init(syna_tcm_module_init);
late_initcall(syna_tcm_module_init);
module_exit(syna_tcm_module_exit);
MODULE_AUTHOR("Synaptics, Inc.");

View File

@ -42,7 +42,7 @@
#include <linux/slab.h>
#include <linux/input/synaptics_tcm.h>
#ifdef CONFIG_DRM
#include <linux/msm_drm_notify.h>
#include <drm/drm_panel.h>
#elif CONFIG_FB
#include <linux/fb.h>
#include <linux/notifier.h>
@ -522,6 +522,8 @@ struct syna_tcm_hw_interface {
const struct syna_tcm_bus_io *bus_io;
};
struct drm_panel *tcm_get_panel(void);
int syna_tcm_bus_init(void);
void syna_tcm_bus_exit(void);

View File

@ -411,9 +411,6 @@ static void diag_report(void)
diag_hcd->state = state;
state = PING;
}
if (diag_hcd->pid)
send_sig_info(SIGIO, &diag_hcd->sigio, diag_hcd->task);
}
static int diag_init(struct syna_tcm_hcd *tcm_hcd)

View File

@ -47,145 +47,95 @@ static struct syna_tcm_hw_interface hw_if;
static struct platform_device *syna_tcm_i2c_device;
active_tp_setup(synaptics_tcm);
static struct drm_panel *active_tcm_panel;
struct drm_panel *tcm_get_panel(void)
{
return active_tcm_panel;
}
#ifdef CONFIG_OF
static int parse_dt(struct device *dev, struct syna_tcm_board_data *bdata)
{
int retval;
u32 value;
struct property *prop;
struct device_node *np = dev->of_node;
const char *name;
prop = of_find_property(np, "synaptics,irq-gpio", NULL);
if (prop && prop->length) {
bdata->irq_gpio = of_get_named_gpio_flags(np,
"synaptics,irq-gpio", 0,
(enum of_gpio_flags *)&bdata->irq_flags);
} else {
bdata->irq_gpio = -1;
retval = of_get_named_gpio_flags(np,
"synaptics,irq-gpio", 0,
(enum of_gpio_flags *)&bdata->irq_flags);
if (!gpio_is_valid(retval)) {
if (retval != -EPROBE_DEFER)
dev_err(dev, "Error getting irq_gpio\n");
return retval;
}
bdata->irq_gpio = retval;
of_property_read_u32(np, "synaptics,irq-on-state",
&bdata->irq_on_state);
of_property_read_string(np, "synaptics,pwr-reg-name",
&bdata->pwr_reg_name);
of_property_read_string(np, "synaptics,bus-reg-name",
&bdata->bus_reg_name);
of_property_read_string(np, "synaptics,firmware-name",
&bdata->fw_name);
bdata->power_gpio = of_get_named_gpio_flags(np,
"synaptics,power-gpio", 0, NULL);
retval = of_property_read_u32(np, "synaptics,power-on-state",
&bdata->power_on_state);
if (retval < 0) {
LOGE(dev, "Failed to read synaptics,power-on-state\n");
return retval;
}
retval = of_property_read_u32(np, "synaptics,irq-on-state", &value);
if (retval < 0)
bdata->irq_on_state = 0;
else
bdata->irq_on_state = value;
retval = of_property_read_string(np, "synaptics,pwr-reg-name", &name);
if (retval < 0)
bdata->pwr_reg_name = NULL;
else
bdata->pwr_reg_name = name;
retval = of_property_read_string(np, "synaptics,bus-reg-name", &name);
if (retval < 0)
bdata->bus_reg_name = NULL;
else
bdata->bus_reg_name = name;
prop = of_find_property(np, "synaptics,power-gpio", NULL);
if (prop && prop->length) {
bdata->power_gpio = of_get_named_gpio_flags(np,
"synaptics,power-gpio", 0, NULL);
} else {
bdata->power_gpio = -1;
retval = of_property_read_u32(np, "synaptics,power-delay-ms",
&bdata->power_delay_ms);
if (retval < 0) {
LOGE(dev, "Failed to read synaptics,power-delay-ms\n");
return retval;
}
prop = of_find_property(np, "synaptics,power-on-state", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,power-on-state",
&value);
if (retval < 0) {
LOGE(dev, "Failed to read synaptics,power-on-state\n");
return retval;
}
bdata->power_on_state = value;
} else {
bdata->power_on_state = 0;
retval = of_get_named_gpio_flags(np,
"synaptics,reset-gpio", 0, NULL);
if (!gpio_is_valid(retval)) {
if (retval != -EPROBE_DEFER)
dev_err(dev, "Error getting irq_gpio\n");
return retval;
}
bdata->reset_gpio = retval;
retval = of_property_read_u32(np, "synaptics,reset-on-state",
&bdata->reset_on_state);
if (retval < 0) {
LOGE(dev, "Failed to read synaptics,reset-on-state\n");
return retval;
}
prop = of_find_property(np, "synaptics,power-delay-ms", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,power-delay-ms",
&value);
if (retval < 0) {
LOGE(dev, "Failed to read synaptics,power-delay-ms\n");
return retval;
}
bdata->power_delay_ms = value;
} else {
bdata->power_delay_ms = 0;
retval = of_property_read_u32(np, "synaptics,reset-active-ms",
&bdata->reset_active_ms);
if (retval < 0) {
LOGE(dev, "Failed to read synaptics,reset-active-ms\n");
return retval;
}
prop = of_find_property(np, "synaptics,reset-gpio", NULL);
if (prop && prop->length) {
bdata->reset_gpio = of_get_named_gpio_flags(np,
"synaptics,reset-gpio", 0, NULL);
} else {
bdata->reset_gpio = -1;
retval = of_property_read_u32(np, "synaptics,reset-delay-ms",
&bdata->reset_delay_ms);
if (retval < 0) {
LOGE(dev, "Unable to read synaptics,reset-delay-ms\n");
return retval;
}
prop = of_find_property(np, "synaptics,reset-on-state", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,reset-on-state",
&value);
if (retval < 0) {
LOGE(dev, "Failed to read synaptics,reset-on-state\n");
return retval;
}
bdata->reset_on_state = value;
} else {
bdata->reset_on_state = 0;
}
bdata->x_flip = of_property_read_bool(np, "synaptics,x-flip");
bdata->y_flip = of_property_read_bool(np, "synaptics,y-flip");
bdata->swap_axes = of_property_read_bool(np, "synaptics,swap-axes");
prop = of_find_property(np, "synaptics,reset-active-ms", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,reset-active-ms",
&value);
if (retval < 0) {
LOGE(dev, "Failed to read synaptics,reset-active-ms\n");
return retval;
}
bdata->reset_active_ms = value;
} else {
bdata->reset_active_ms = 0;
}
prop = of_find_property(np, "synaptics,reset-delay-ms", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,reset-delay-ms",
&value);
if (retval < 0) {
LOGE(dev, "Unable to read synaptics,reset-delay-ms\n");
return retval;
}
bdata->reset_delay_ms = value;
} else {
bdata->reset_delay_ms = 0;
}
prop = of_find_property(np, "synaptics,x-flip", NULL);
bdata->x_flip = prop > 0 ? true : false;
prop = of_find_property(np, "synaptics,y-flip", NULL);
bdata->y_flip = prop > 0 ? true : false;
prop = of_find_property(np, "synaptics,swap-axes", NULL);
bdata->swap_axes = prop > 0 ? true : false;
prop = of_find_property(np, "synaptics,ubl-i2c-addr", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,ubl-i2c-addr",
&value);
if (retval < 0) {
LOGE(dev, "Unable to read synaptics,ubl-i2c-addr\n");
return retval;
}
bdata->ubl_i2c_addr = value;
} else {
bdata->ubl_i2c_addr = 0;
retval = of_property_read_u32(np, "synaptics,ubl-i2c-addr",
&bdata->ubl_i2c_addr);
if (retval < 0) {
LOGE(dev, "Unable to read synaptics,ubl-i2c-addr\n");
return retval;
}
bdata->extend_report = of_property_read_bool(np,
@ -219,7 +169,7 @@ static int syna_tcm_i2c_alloc_mem(struct syna_tcm_hcd *tcm_hcd,
static int syna_tcm_i2c_rmi_read(struct syna_tcm_hcd *tcm_hcd,
unsigned short addr, unsigned char *data, unsigned int length)
{
int retval;
int retval = 0;
unsigned char address;
unsigned int attempt;
struct i2c_msg msg[2];
@ -327,7 +277,7 @@ static int syna_tcm_i2c_rmi_write(struct syna_tcm_hcd *tcm_hcd,
static int syna_tcm_i2c_read(struct syna_tcm_hcd *tcm_hcd, unsigned char *data,
unsigned int length)
{
int retval;
int retval = 0;
unsigned int attempt;
struct i2c_msg msg;
struct i2c_client *i2c = to_i2c_client(tcm_hcd->pdev->dev.parent);
@ -365,7 +315,7 @@ static int syna_tcm_i2c_read(struct syna_tcm_hcd *tcm_hcd, unsigned char *data,
static int syna_tcm_i2c_write(struct syna_tcm_hcd *tcm_hcd, unsigned char *data,
unsigned int length)
{
int retval;
int retval = 0;
unsigned int attempt;
struct i2c_msg msg;
struct i2c_client *i2c = to_i2c_client(tcm_hcd->pdev->dev.parent);
@ -400,15 +350,73 @@ static int syna_tcm_i2c_write(struct syna_tcm_hcd *tcm_hcd, unsigned char *data,
return retval;
}
static int syna_tcm_check_dt(struct device_node *np)
{
int i;
int count;
struct device_node *node;
struct drm_panel *panel;
count = of_count_phandle_with_args(np, "panel", NULL);
if (count <= 0)
return 0;
for (i = 0; i < count; i++) {
node = of_parse_phandle(np, "panel", i);
panel = of_drm_find_panel(node);
of_node_put(node);
if (!IS_ERR(panel)) {
active_tcm_panel = panel;
return 0;
}
}
return -ENODEV;
}
static int syna_tcm_check_default_tp(struct device_node *dt, const char *prop)
{
const char *active_tp;
const char *compatible;
char *start;
int ret;
ret = of_property_read_string(dt->parent, prop, &active_tp);
if (ret) {
pr_err(" %s:fail to read %s %d\n", __func__, prop, ret);
return -ENODEV;
}
ret = of_property_read_string(dt, "compatible", &compatible);
if (ret < 0) {
pr_err(" %s:fail to read %s %d\n", __func__, "compatible", ret);
return -ENODEV;
}
start = strnstr(active_tp, compatible, strlen(active_tp));
if (start == NULL) {
pr_err(" %s:no match compatible, %s, %s\n",
__func__, compatible, active_tp);
ret = -ENODEV;
}
return ret;
}
static int syna_tcm_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *dev_id)
{
int retval;
struct device_node *dt = i2c->dev.of_node;
if (synaptics_tcm_check_assigned_tp(dt, "compatible",
"qcom,i2c-touch-active") < 0)
return -ENODEV;
if (syna_tcm_check_dt(dt)) {
if (!syna_tcm_check_default_tp(dt, "qcom,i2c-touch-active"))
retval = -EPROBE_DEFER;
else
retval = -ENODEV;
return retval;
}
syna_tcm_i2c_device = platform_device_alloc(PLATFORM_DRIVER_NAME, 0);
if (!syna_tcm_i2c_device) {
@ -424,7 +432,11 @@ static int syna_tcm_i2c_probe(struct i2c_client *i2c,
"Failed to allocate memory for board data\n");
return -ENOMEM;
}
parse_dt(&i2c->dev, hw_if.bdata);
retval = parse_dt(&i2c->dev, hw_if.bdata);
if (retval < 0) {
LOGE(&i2c->dev, "Failed to parse dt\n");
return retval;
}
#else
hw_if.bdata = i2c->dev.platform_data;
#endif

View File

@ -744,7 +744,7 @@ static int recovery_do_recovery(void)
static int recovery_init(struct syna_tcm_hcd *tcm_hcd)
{
int retval;
int retval = 0;
int idx;
recovery_hcd = kzalloc(sizeof(*recovery_hcd), GFP_KERNEL);

View File

@ -926,15 +926,22 @@ static int reflash_parse_fw_image(void)
static int reflash_get_fw_image(void)
{
int retval;
const char *fw_name;
struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
const struct syna_tcm_board_data *bdata = tcm_hcd->hw_if->bdata;
if (bdata->fw_name)
fw_name = bdata->fw_name;
else
fw_name = FW_IMAGE_NAME;
if (reflash_hcd->image == NULL) {
retval = request_firmware(&reflash_hcd->fw_entry, FW_IMAGE_NAME,
retval = request_firmware(&reflash_hcd->fw_entry, fw_name,
tcm_hcd->pdev->dev.parent);
if (retval < 0) {
LOGD(tcm_hcd->pdev->dev.parent,
"Failed to request %s\n",
FW_IMAGE_NAME);
fw_name);
return retval;
}
@ -1761,7 +1768,7 @@ static int reflash_update_boot_config(bool lock)
int retval;
unsigned char slot_used;
unsigned int idx;
unsigned int addr;
unsigned int addr = 0;
struct boot_config *data;
struct boot_config *last_slot;
struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
@ -1976,7 +1983,7 @@ static void reflash_startup_work(struct work_struct *work)
static int reflash_init(struct syna_tcm_hcd *tcm_hcd)
{
int retval;
int retval = 0;
int idx;
reflash_hcd = kzalloc(sizeof(*reflash_hcd), GFP_KERNEL);

View File

@ -58,6 +58,7 @@ struct syna_tcm_board_data {
unsigned long irq_flags;
const char *pwr_reg_name;
const char *bus_reg_name;
const char *fw_name;
bool extend_report;
};