diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index c3d0243add02..dff8832f0b5b 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -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 diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 5f2aac477580..9a62448a1119 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -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/ diff --git a/drivers/input/touchscreen/synaptics_tcm/Kconfig b/drivers/input/touchscreen/synaptics_tcm/Kconfig index 88bd4159967b..78c687df4fe6 100644 --- a/drivers/input/touchscreen/synaptics_tcm/Kconfig +++ b/drivers/input/touchscreen/synaptics_tcm/Kconfig @@ -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. diff --git a/drivers/input/touchscreen/synaptics_tcm/synaptics_tcm_core.c b/drivers/input/touchscreen/synaptics_tcm/synaptics_tcm_core.c index 9598e941cb2e..f095624ddfcb 100644 --- a/drivers/input/touchscreen/synaptics_tcm/synaptics_tcm_core.c +++ b/drivers/input/touchscreen/synaptics_tcm/synaptics_tcm_core.c @@ -50,6 +50,16 @@ /* #define FORCE_RUN_APPLICATION_FIRMWARE */ +#define SYNA_VTG_MIN_UV 2800000 + +#define SYNA_VTG_MAX_UV 3300000 + +#define SYNA_LOAD_MAX_UA 30000 + +#define SYNA_VDD_VTG_MIN_UV 1800000 + +#define SYNA_VDD_VTG_MAX_UV 2000000 + #define NOTIFIER_PRIORITY 2 #define RESPONSE_TIMEOUT_MS 3000 @@ -1911,6 +1921,22 @@ static int syna_tcm_enable_regulator(struct syna_tcm_hcd *tcm_hcd, bool en) } if (tcm_hcd->bus_reg) { + retval = regulator_set_voltage(tcm_hcd->bus_reg, + SYNA_VDD_VTG_MIN_UV, SYNA_VDD_VTG_MAX_UV); + if (retval) { + LOGE(tcm_hcd->pdev->dev.parent, + "set bus regulator voltage failed\n"); + goto exit; + } + + retval = regulator_set_load(tcm_hcd->bus_reg, + SYNA_LOAD_MAX_UA); + if (retval) { + LOGE(tcm_hcd->pdev->dev.parent, + "set bus regulator load failed\n"); + goto exit; + } + retval = regulator_enable(tcm_hcd->bus_reg); if (retval < 0) { LOGE(tcm_hcd->pdev->dev.parent, @@ -1920,6 +1946,23 @@ static int syna_tcm_enable_regulator(struct syna_tcm_hcd *tcm_hcd, bool en) } if (tcm_hcd->pwr_reg) { + if (regulator_count_voltages(tcm_hcd->pwr_reg) > 0) { + retval = regulator_set_voltage(tcm_hcd->pwr_reg, + SYNA_VTG_MIN_UV, SYNA_VTG_MAX_UV); + if (retval) { + LOGE(tcm_hcd->pdev->dev.parent, + "set power regulator voltage failed\n"); + goto disable_bus_reg; + } + retval = regulator_set_load(tcm_hcd->pwr_reg, + SYNA_LOAD_MAX_UA); + if (retval) { + LOGE(tcm_hcd->pdev->dev.parent, + "set power regulator load failed\n"); + goto disable_bus_reg; + } + } + retval = regulator_enable(tcm_hcd->pwr_reg); if (retval < 0) { LOGE(tcm_hcd->pdev->dev.parent, @@ -1932,12 +1975,22 @@ static int syna_tcm_enable_regulator(struct syna_tcm_hcd *tcm_hcd, bool en) return 0; disable_pwr_reg: - if (tcm_hcd->pwr_reg) + if (tcm_hcd->pwr_reg) { + if (regulator_count_voltages(tcm_hcd->pwr_reg) > 0) { + regulator_set_load(tcm_hcd->pwr_reg, 0); + regulator_set_voltage(tcm_hcd->pwr_reg, 0, + SYNA_VTG_MAX_UV); + } regulator_disable(tcm_hcd->pwr_reg); + } disable_bus_reg: - if (tcm_hcd->bus_reg) + if (tcm_hcd->bus_reg) { + regulator_set_load(tcm_hcd->bus_reg, 0); + regulator_set_voltage(tcm_hcd->bus_reg, 0, + SYNA_VDD_VTG_MAX_UV); regulator_disable(tcm_hcd->bus_reg); + } exit: return retval; @@ -2840,6 +2893,9 @@ static int syna_tcm_resume(struct device *dev) if (!tcm_hcd->init_okay) syna_tcm_deferred_probe(dev); + + if (!tcm_hcd->in_suspend) + return 0; else { if (tcm_hcd->irq_enabled) { tcm_hcd->watchdog.run = false; @@ -2848,8 +2904,11 @@ static int syna_tcm_resume(struct device *dev) } } - if (!tcm_hcd->in_suspend) - return 0; + retval = syna_tcm_enable_regulator(tcm_hcd, true); + if (retval < 0) { + LOGE(tcm_hcd->pdev->dev.parent, + "Failed to enable regulators\n"); + } retval = pinctrl_select_state( tcm_hcd->ts_pinctrl, @@ -2945,6 +3004,7 @@ static int syna_tcm_suspend(struct device *dev) { struct syna_tcm_module_handler *mod_handler; struct syna_tcm_hcd *tcm_hcd = dev_get_drvdata(dev); + int retval; if (tcm_hcd->in_suspend || !tcm_hcd->init_okay) return 0; @@ -2967,11 +3027,17 @@ static int syna_tcm_suspend(struct device *dev) } } + retval = syna_tcm_enable_regulator(tcm_hcd, false); + if (retval < 0) { + LOGE(tcm_hcd->pdev->dev.parent, + "Failed to disable regulators\n"); + } + mutex_unlock(&mod_pool.mutex); tcm_hcd->in_suspend = true; - return 0; + return retval; } #endif @@ -3040,21 +3106,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 +3129,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 +3312,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) { @@ -3356,10 +3420,30 @@ static int syna_tcm_probe(struct platform_device *pdev) goto err_get_regulator; } - retval = synaptics_tcm_pinctrl_init(tcm_hcd); + retval = syna_tcm_enable_regulator(tcm_hcd, true); if (retval < 0) { - LOGE(tcm_hcd->pdev->dev.parent, "Failed to init pinctrl\n"); - goto err_pinctrl_init; + LOGE(tcm_hcd->pdev->dev.parent, + "Failed to enable regulators\n"); + goto err_enable_regulator; + } + + retval = syna_tcm_config_gpio(tcm_hcd); + if (retval < 0) { + LOGE(tcm_hcd->pdev->dev.parent, + "Failed to configure GPIO's\n"); + goto err_config_gpio; + } + + retval = synaptics_tcm_pinctrl_init(tcm_hcd); + if (!retval && tcm_hcd->ts_pinctrl) { + retval = pinctrl_select_state( + tcm_hcd->ts_pinctrl, + tcm_hcd->pinctrl_state_active); + if (retval < 0) { + LOGE(tcm_hcd->pdev->dev.parent, + "%s: Failed to select %s pinstate %d\n", + __func__, PINCTRL_STATE_ACTIVE, retval); + } } sysfs_dir = kobject_create_and_add(PLATFORM_DRIVER_NAME, @@ -3405,11 +3489,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 +3542,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 @@ -3475,7 +3567,21 @@ err_sysfs_create_file: kobject_put(tcm_hcd->sysfs_dir); err_sysfs_create_dir: -err_pinctrl_init: + if (bdata->irq_gpio >= 0) + syna_tcm_set_gpio(tcm_hcd, bdata->irq_gpio, false, 0, 0); + + if (bdata->power_gpio >= 0) + syna_tcm_set_gpio(tcm_hcd, bdata->power_gpio, false, 0, 0); + + if (bdata->reset_gpio >= 0) + syna_tcm_set_gpio(tcm_hcd, bdata->reset_gpio, false, 0, 0); + +err_config_gpio: + syna_tcm_enable_regulator(tcm_hcd, false); + +err_enable_regulator: + syna_tcm_get_regulator(tcm_hcd, false); + err_get_regulator: device_init_wakeup(&pdev->dev, 0); @@ -3487,6 +3593,7 @@ err_alloc_mem: RELEASE_BUFFER(tcm_hcd->out); RELEASE_BUFFER(tcm_hcd->in); +err_drm_reg: kfree(tcm_hcd); return retval; @@ -3495,33 +3602,8 @@ err_alloc_mem: static int syna_tcm_deferred_probe(struct device *dev) { int retval; - const struct syna_tcm_board_data *bdata; struct syna_tcm_hcd *tcm_hcd = dev_get_drvdata(dev); - retval = pinctrl_select_state( - tcm_hcd->ts_pinctrl, - tcm_hcd->pinctrl_state_active); - - if (retval < 0) { - LOGE(tcm_hcd->pdev->dev.parent, - "Failed to pinctrl_select_state\n"); - goto err_pinctrl_select_state; - } - - retval = syna_tcm_enable_regulator(tcm_hcd, true); - if (retval < 0) { - LOGE(tcm_hcd->pdev->dev.parent, - "Failed to enable regulators\n"); - goto err_enable_regulator; - } - - retval = syna_tcm_config_gpio(tcm_hcd); - if (retval < 0) { - LOGE(tcm_hcd->pdev->dev.parent, - "Failed to configure GPIO's\n"); - goto err_config_gpio; - } - retval = tcm_hcd->enable_irq(tcm_hcd, true, NULL); if (retval < 0) { LOGE(tcm_hcd->pdev->dev.parent, @@ -3552,27 +3634,6 @@ err_reset: #endif err_enable_irq: -err_config_gpio: - syna_tcm_enable_regulator(tcm_hcd, false); - -err_enable_regulator: - syna_tcm_get_regulator(tcm_hcd, false); - -err_pinctrl_select_state: - if (!tcm_hcd->hw_if || !tcm_hcd->hw_if->bdata) - return -EINVAL; - - bdata = tcm_hcd->hw_if->bdata; - - if (bdata->irq_gpio >= 0) - syna_tcm_set_gpio(tcm_hcd, bdata->irq_gpio, false, 0, 0); - - if (bdata->power_gpio >= 0) - syna_tcm_set_gpio(tcm_hcd, bdata->power_gpio, false, 0, 0); - - if (bdata->reset_gpio >= 0) - syna_tcm_set_gpio(tcm_hcd, bdata->reset_gpio, false, 0, 0); - return retval; } @@ -3584,6 +3645,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 +3686,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 @@ -3668,11 +3732,6 @@ static int syna_tcm_remove(struct platform_device *pdev) return 0; } -static void syna_tcm_shutdown(struct platform_device *pdev) -{ - syna_tcm_remove(pdev); -} - #ifdef CONFIG_PM static const struct dev_pm_ops syna_tcm_dev_pm_ops = { #if !defined(CONFIG_DRM) && !defined(CONFIG_FB) @@ -3692,7 +3751,6 @@ static struct platform_driver syna_tcm_driver = { }, .probe = syna_tcm_probe, .remove = syna_tcm_remove, - .shutdown = syna_tcm_shutdown, }; static int __init syna_tcm_module_init(void) @@ -3713,7 +3771,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."); diff --git a/drivers/input/touchscreen/synaptics_tcm/synaptics_tcm_core.h b/drivers/input/touchscreen/synaptics_tcm/synaptics_tcm_core.h index 92a4858127a0..9bbccc7d915c 100644 --- a/drivers/input/touchscreen/synaptics_tcm/synaptics_tcm_core.h +++ b/drivers/input/touchscreen/synaptics_tcm/synaptics_tcm_core.h @@ -42,7 +42,7 @@ #include #include #ifdef CONFIG_DRM -#include +#include #elif CONFIG_FB #include #include @@ -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); diff --git a/drivers/input/touchscreen/synaptics_tcm/synaptics_tcm_diagnostics.c b/drivers/input/touchscreen/synaptics_tcm/synaptics_tcm_diagnostics.c index 0f8570a07565..92472e108656 100644 --- a/drivers/input/touchscreen/synaptics_tcm/synaptics_tcm_diagnostics.c +++ b/drivers/input/touchscreen/synaptics_tcm/synaptics_tcm_diagnostics.c @@ -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) diff --git a/drivers/input/touchscreen/synaptics_tcm/synaptics_tcm_i2c.c b/drivers/input/touchscreen/synaptics_tcm/synaptics_tcm_i2c.c index e573d92c9ad5..cf4ae8cb47bf 100644 --- a/drivers/input/touchscreen/synaptics_tcm/synaptics_tcm_i2c.c +++ b/drivers/input/touchscreen/synaptics_tcm/synaptics_tcm_i2c.c @@ -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; - 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; + 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); - 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; + bdata->power_gpio = of_get_named_gpio_flags(np, + "synaptics,power-gpio", 0, NULL); - 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; - } - - 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 { + retval = of_property_read_u32(np, "synaptics,power-on-state", + &bdata->power_on_state); + if (retval < 0) { + LOGD(dev, "Failed to read synaptics,power-on-state\n"); bdata->power_on_state = 0; } - 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,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,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_get_named_gpio_flags(np, + "synaptics,reset-gpio", 0, NULL); + if (!gpio_is_valid(retval)) { + if (retval != -EPROBE_DEFER) + dev_err(dev, "Error getting reset 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,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; + 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-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; + 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-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; - } + 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,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 @@ exit: 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 @@ exit: 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 @@ exit: 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 diff --git a/drivers/input/touchscreen/synaptics_tcm/synaptics_tcm_recovery.c b/drivers/input/touchscreen/synaptics_tcm/synaptics_tcm_recovery.c index 027facbcad79..3be072faf1e8 100644 --- a/drivers/input/touchscreen/synaptics_tcm/synaptics_tcm_recovery.c +++ b/drivers/input/touchscreen/synaptics_tcm/synaptics_tcm_recovery.c @@ -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); diff --git a/drivers/input/touchscreen/synaptics_tcm/synaptics_tcm_reflash.c b/drivers/input/touchscreen/synaptics_tcm/synaptics_tcm_reflash.c index bb6bef6f1df5..bfb6e6db17ab 100644 --- a/drivers/input/touchscreen/synaptics_tcm/synaptics_tcm_reflash.c +++ b/drivers/input/touchscreen/synaptics_tcm/synaptics_tcm_reflash.c @@ -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); diff --git a/include/linux/input/synaptics_tcm.h b/include/linux/input/synaptics_tcm.h index 58b4d2987d5b..1d650b451f86 100644 --- a/include/linux/input/synaptics_tcm.h +++ b/include/linux/input/synaptics_tcm.h @@ -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; };