Loading Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt +19 −3 Original line number Diff line number Diff line Loading @@ -11,6 +11,8 @@ Required properties: - reg : i2c slave address of the device. - interrupt-parent : parent of interrupt. - synaptics,irq-gpio : irq gpio. - synaptics,reset-gpio : reset gpio. - synaptics,power-gpio : power switch gpio. - synaptics,irq-flags : irq flags. Optional property: Loading @@ -18,13 +20,23 @@ Optional property: - vcc_i2c-supply : analog voltage power supply needed to power device. - synaptics,pwr-reg-name : power reg name of digital voltage. - synaptics,bus-reg-name : bus reg name of analog voltage. - synaptics,irq-on-state : status of irq gpio. - synaptics,irq-on-state : irq gpio active state. - synaptics,reset-on-state : reset gpio active state. - synaptics,power-on-state : power switch active state. - synaptics,ub-i2c-addr : microbootloader mode I2C slave address. - synaptics,cap-button-codes : virtual key code mappings to be used. - synaptics,vir-button-codes : virtual key code and the response region on panel. - synaptics,x-flip : modify orientation of the x axis. - synaptics,y-flip : modify orientation of the y axis. - synaptics,reset-delay-ms : reset delay for controller (ms), default 100. - synaptics,reset-active-ms : reset active duration for controller (ms), default 100. - synaptics,power-delay-ms : power delay for controller (ms), default 100. - synaptics,max-y-for-2d : maximal y value of the panel. - synaptics,swap-axes : specify whether to swap axes. - synaptics,resume-in-workqueue : specify whether to defer the resume to workqueue. - clock-names : Clock names used for secure touch. They are: "iface_clk", "core_clk" - clocks : Defined if 'clock-names' DT property is defined. These clocks are associated with the underlying I2C bus. Example: i2c@78b7000 { Loading @@ -34,8 +46,8 @@ Example: reg = <0x4b>; interrupt-parent = <&tlmm>; interrupts = <65 0x2008>; vdd_ana-supply = <&pmtitanium_l17>; vcc_i2c-supply = <&pmtitanium_l6>; vdd_ana-supply = <&pm8953_l17>; vcc_i2c-supply = <&pm8953_l6>; synaptics,pwr-reg-name = "vdd_ana"; synaptics,bus-reg-name = "vcc_i2c"; synaptics,irq-gpio = <&tlmm 65 0x2008>; Loading @@ -46,5 +58,9 @@ Example: synaptics,max-y-for-2d = <1919>; /* remove if no virtual buttons */ synaptics,cap-button-codes = <139 172 158>; synaptics,vir-button-codes = <139 180 2000 320 160 172 540 2000 320 160 158 900 2000 320 160>; /* Underlying clocks used by secure touch */ clock-names = "iface_clk", "core_clk"; clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>, <&clock_gcc clk_gcc_blsp1_qup3_i2c_apps_clk>; }; }; drivers/input/touchscreen/synaptics_dsx_2.6/Kconfig +10 −0 Original line number Diff line number Diff line Loading @@ -114,4 +114,14 @@ config TOUCHSCREEN_SYNAPTICS_DSX_VIDEO_v26 To compile this driver as a module, choose M here: the module will be called synaptics_dsx_video. config SECURE_TOUCH_SYNAPTICS_DSX_V26 bool "Secure Touch support for Synaptics V2.6 Touchscreen" depends on TOUCHSCREEN_SYNAPTICS_DSX_I2C_v26 help Say Y here -Synaptics DSX V2.6 touch driver is connected -To enable secure touch for Synaptics DSX V2.6 touch driver If unsure, say N. endif drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c +446 −69 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ * * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com> * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com> * Copyright (C) 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by Loading Loading @@ -117,11 +118,11 @@ static int synaptics_rmi4_check_status(struct synaptics_rmi4_data *rmi4_data, bool *was_in_bl_mode); static int synaptics_rmi4_free_fingers(struct synaptics_rmi4_data *rmi4_data); static int synaptics_rmi4_reinit_device(struct synaptics_rmi4_data *rmi4_data); static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data, bool rebuild); #ifdef CONFIG_FB static void synaptics_rmi4_fb_notify_resume_work(struct work_struct *work); static int synaptics_rmi4_fb_notifier_cb(struct notifier_block *self, unsigned long event, void *data); #endif Loading Loading @@ -172,6 +173,19 @@ static ssize_t synaptics_rmi4_wake_gesture_store(struct device *dev, static ssize_t synaptics_rmi4_virtual_key_map_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); #if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26) static ssize_t synaptics_rmi4_secure_touch_enable_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t synaptics_rmi4_secure_touch_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); static ssize_t synaptics_rmi4_secure_touch_show(struct device *dev, struct device_attribute *attr, char *buf); #endif static irqreturn_t synaptics_rmi4_irq(int irq, void *data); struct synaptics_rmi4_f01_device_status { union { struct { Loading Loading @@ -597,26 +611,34 @@ static struct synaptics_dsx_button_map *vir_button_map; static struct device_attribute attrs[] = { __ATTR(reset, 0220, synaptics_rmi4_show_error, NULL, synaptics_rmi4_f01_reset_store), __ATTR(productinfo, 0444, synaptics_rmi4_f01_productinfo_show, synaptics_rmi4_store_error), NULL), __ATTR(buildid, 0444, synaptics_rmi4_f01_buildid_show, synaptics_rmi4_store_error), NULL), __ATTR(flashprog, 0444, synaptics_rmi4_f01_flashprog_show, synaptics_rmi4_store_error), NULL), __ATTR(0dbutton, 0664, synaptics_rmi4_0dbutton_show, synaptics_rmi4_0dbutton_store), __ATTR(suspend, 0220, synaptics_rmi4_show_error, NULL, synaptics_rmi4_suspend_store), __ATTR(wake_gesture, 0664, synaptics_rmi4_wake_gesture_show, synaptics_rmi4_wake_gesture_store), #if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26) __ATTR(secure_touch_enable, 0664, synaptics_rmi4_secure_touch_enable_show, synaptics_rmi4_secure_touch_enable_store), __ATTR(secure_touch, 0444, synaptics_rmi4_secure_touch_show, NULL), #endif }; static struct kobj_attribute virtual_key_map_attr = { Loading @@ -627,6 +649,205 @@ static struct kobj_attribute virtual_key_map_attr = { .show = synaptics_rmi4_virtual_key_map_show, }; #if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26) static void synaptics_secure_touch_init(struct synaptics_rmi4_data *data) { data->st_initialized = 0; init_completion(&data->st_powerdown); init_completion(&data->st_irq_processed); /* Get clocks */ data->core_clk = devm_clk_get(data->pdev->dev.parent, "core_clk"); if (IS_ERR(data->core_clk)) { dev_warn(data->pdev->dev.parent, "%s: error on clk_get(core_clk): %ld\n", __func__, PTR_ERR(data->core_clk)); data->core_clk = NULL; } data->iface_clk = devm_clk_get(data->pdev->dev.parent, "iface_clk"); if (IS_ERR(data->iface_clk)) { dev_warn(data->pdev->dev.parent, "%s: error on clk_get(iface_clk): %ld\n", __func__, PTR_ERR(data->iface_clk)); data->iface_clk = NULL; } data->st_initialized = 1; } static void synaptics_secure_touch_notify(struct synaptics_rmi4_data *rmi4_data) { sysfs_notify(&rmi4_data->input_dev->dev.kobj, NULL, "secure_touch"); } static irqreturn_t synaptics_filter_interrupt( struct synaptics_rmi4_data *rmi4_data) { if (atomic_read(&rmi4_data->st_enabled)) { if (atomic_cmpxchg(&rmi4_data->st_pending_irqs, 0, 1) == 0) { reinit_completion(&rmi4_data->st_irq_processed); synaptics_secure_touch_notify(rmi4_data); wait_for_completion_interruptible( &rmi4_data->st_irq_processed); } return IRQ_HANDLED; } return IRQ_NONE; } /* * 'blocking' variable will have value 'true' when we want to prevent the driver * from accessing the xPU/SMMU protected HW resources while the session is * active. */ static void synaptics_secure_touch_stop(struct synaptics_rmi4_data *rmi4_data, bool blocking) { if (atomic_read(&rmi4_data->st_enabled)) { atomic_set(&rmi4_data->st_pending_irqs, -1); synaptics_secure_touch_notify(rmi4_data); if (blocking) wait_for_completion_interruptible( &rmi4_data->st_powerdown); } } #else static void synaptics_secure_touch_init(struct synaptics_rmi4_data *rmi4_data) { } static irqreturn_t synaptics_filter_interrupt( struct synaptics_rmi4_data *rmi4_data) { return IRQ_NONE; } static void synaptics_secure_touch_stop(struct synaptics_rmi4_data *rmi4_data, bool blocking) { } #endif #if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26) static ssize_t synaptics_rmi4_secure_touch_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); return scnprintf(buf, PAGE_SIZE, "%d", atomic_read(&rmi4_data->st_enabled)); } /* * Accept only "0" and "1" valid values. * "0" will reset the st_enabled flag, then wake up the reading process and * the interrupt handler. * The bus driver is notified via pm_runtime that it is not required to stay * awake anymore. * It will also make sure the queue of events is emptied in the controller, * in case a touch happened in between the secure touch being disabled and * the local ISR being ungated. * "1" will set the st_enabled flag and clear the st_pending_irqs flag. * The bus driver is requested via pm_runtime to stay awake. */ static ssize_t synaptics_rmi4_secure_touch_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); unsigned long value; int err = 0; if (count > 2) return -EINVAL; err = kstrtoul(buf, 10, &value); if (err != 0) return err; if (!rmi4_data->st_initialized) return -EIO; err = count; switch (value) { case 0: if (atomic_read(&rmi4_data->st_enabled) == 0) break; synaptics_rmi4_bus_put(rmi4_data); atomic_set(&rmi4_data->st_enabled, 0); synaptics_secure_touch_notify(rmi4_data); complete(&rmi4_data->st_irq_processed); synaptics_rmi4_irq(rmi4_data->irq, rmi4_data); complete(&rmi4_data->st_powerdown); break; case 1: if (atomic_read(&rmi4_data->st_enabled)) { err = -EBUSY; break; } synchronize_irq(rmi4_data->irq); if (synaptics_rmi4_bus_get(rmi4_data) < 0) { dev_err( rmi4_data->pdev->dev.parent, "synaptics_rmi4_bus_get failed\n"); err = -EIO; break; } reinit_completion(&rmi4_data->st_powerdown); reinit_completion(&rmi4_data->st_irq_processed); atomic_set(&rmi4_data->st_enabled, 1); atomic_set(&rmi4_data->st_pending_irqs, 0); break; default: dev_err( rmi4_data->pdev->dev.parent, "unsupported value: %lu\n", value); err = -EINVAL; break; } return err; } /* * This function returns whether there are pending interrupts, or * other error conditions that need to be signaled to the userspace library, * according tot he following logic: * - st_enabled is 0 if secure touch is not enabled, returning -EBADF * - st_pending_irqs is -1 to signal that secure touch is in being stopped, * returning -EINVAL * - st_pending_irqs is 1 to signal that there is a pending irq, returning * the value "1" to the sysfs read operation * - st_pending_irqs is 0 (only remaining case left) if the pending interrupt * has been processed, so the interrupt handler can be allowed to continue. */ static ssize_t synaptics_rmi4_secure_touch_show(struct device *dev, struct device_attribute *attr, char *buf) { struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); int val = 0; if (atomic_read(&rmi4_data->st_enabled) == 0) return -EBADF; if (atomic_cmpxchg(&rmi4_data->st_pending_irqs, -1, 0) == -1) return -EINVAL; if (atomic_cmpxchg(&rmi4_data->st_pending_irqs, 1, 0) == 1) val = 1; else complete(&rmi4_data->st_irq_processed); return scnprintf(buf, PAGE_SIZE, "%u", val); } #endif static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { Loading Loading @@ -1173,7 +1394,6 @@ static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data, #ifndef TYPE_B_PROTOCOL input_mt_sync(rmi4_data->input_dev); #endif input_sync(rmi4_data->input_dev); dev_dbg(rmi4_data->pdev->dev.parent, "%s: Finger %d: status = 0x%02x, x = %d, y = %d, wx = %d, wy = %d\n", Loading Loading @@ -1245,7 +1465,6 @@ static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data, #ifndef TYPE_B_PROTOCOL input_mt_sync(rmi4_data->input_dev); #endif input_sync(rmi4_data->input_dev); if (rmi4_data->stylus_enable) { stylus_presence = 0; Loading @@ -1261,6 +1480,8 @@ static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data, } } input_sync(rmi4_data->input_dev); mutex_unlock(&(rmi4_data->rmi4_report_mutex)); return touch_count; Loading Loading @@ -1465,12 +1686,6 @@ static void synaptics_rmi4_sensor_report(struct synaptics_rmi4_data *rmi4_data, } if (status.unconfigured && !status.flash_prog) { pr_notice("%s: spontaneous reset detected\n", __func__); retval = synaptics_rmi4_reinit_device(rmi4_data); if (retval < 0) { dev_err(rmi4_data->pdev->dev.parent, "%s: Failed to reinit device\n", __func__); } } if (!report) Loading Loading @@ -1512,6 +1727,9 @@ static irqreturn_t synaptics_rmi4_irq(int irq, void *data) const struct synaptics_dsx_board_data *bdata = rmi4_data->hw_if->board_data; if (synaptics_filter_interrupt(data) == IRQ_HANDLED) return IRQ_HANDLED; if (gpio_get_value(bdata->irq_gpio) != bdata->irq_on_state) goto exit; Loading Loading @@ -2911,7 +3129,9 @@ static int synaptics_rmi4_gpio_setup(int gpio, bool config, int dir, int state) unsigned char buf[16]; if (config) { snprintf(buf, PAGE_SIZE, "dsx_gpio_%u\n", gpio); retval = snprintf(buf, ARRAY_SIZE(buf), "dsx_gpio_%u\n", gpio); if (retval >= 16) return -EINVAL; retval = gpio_request(gpio, buf); if (retval) { Loading Loading @@ -3434,49 +3654,6 @@ static void synaptics_rmi4_rebuild_work(struct work_struct *work) return; } static int synaptics_rmi4_reinit_device(struct synaptics_rmi4_data *rmi4_data) { int retval; struct synaptics_rmi4_fn *fhandler; struct synaptics_rmi4_exp_fhandler *exp_fhandler; struct synaptics_rmi4_device_info *rmi; rmi = &(rmi4_data->rmi4_mod_info); mutex_lock(&(rmi4_data->rmi4_reset_mutex)); synaptics_rmi4_free_fingers(rmi4_data); if (!list_empty(&rmi->support_fn_list)) { list_for_each_entry(fhandler, &rmi->support_fn_list, link) { if (fhandler->fn_number == SYNAPTICS_RMI4_F12) { synaptics_rmi4_f12_set_enables(rmi4_data, 0); break; } } } retval = synaptics_rmi4_int_enable(rmi4_data, true); if (retval < 0) goto exit; mutex_lock(&exp_data.mutex); if (!list_empty(&exp_data.list)) { list_for_each_entry(exp_fhandler, &exp_data.list, link) if (exp_fhandler->exp_fn->reinit != NULL) exp_fhandler->exp_fn->reinit(rmi4_data); } mutex_unlock(&exp_data.mutex); synaptics_rmi4_set_configured(rmi4_data); retval = 0; exit: mutex_unlock(&(rmi4_data->rmi4_reset_mutex)); return retval; } static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data, bool rebuild) { Loading Loading @@ -3688,6 +3865,57 @@ void synaptics_rmi4_new_function(struct synaptics_rmi4_exp_fn *exp_fn, } EXPORT_SYMBOL(synaptics_rmi4_new_function); static int synaptics_dsx_pinctrl_init(struct synaptics_rmi4_data *rmi4_data) { int retval; /* Get pinctrl if target uses pinctrl */ rmi4_data->ts_pinctrl = devm_pinctrl_get((rmi4_data->pdev->dev.parent)); if (IS_ERR_OR_NULL(rmi4_data->ts_pinctrl)) { retval = PTR_ERR(rmi4_data->ts_pinctrl); dev_err(rmi4_data->pdev->dev.parent, "Target does not use pinctrl %d\n", retval); goto err_pinctrl_get; } rmi4_data->pinctrl_state_active = pinctrl_lookup_state(rmi4_data->ts_pinctrl, "pmx_ts_active"); if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_active)) { retval = PTR_ERR(rmi4_data->pinctrl_state_active); dev_err(rmi4_data->pdev->dev.parent, "Can not lookup %s pinstate %d\n", PINCTRL_STATE_ACTIVE, retval); goto err_pinctrl_lookup; } rmi4_data->pinctrl_state_suspend = pinctrl_lookup_state(rmi4_data->ts_pinctrl, "pmx_ts_suspend"); if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_suspend)) { retval = PTR_ERR(rmi4_data->pinctrl_state_suspend); dev_dbg(rmi4_data->pdev->dev.parent, "Can not lookup %s pinstate %d\n", PINCTRL_STATE_SUSPEND, retval); goto err_pinctrl_lookup; } rmi4_data->pinctrl_state_release = pinctrl_lookup_state(rmi4_data->ts_pinctrl, "pmx_ts_release"); if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) { retval = PTR_ERR(rmi4_data->pinctrl_state_release); dev_dbg(rmi4_data->pdev->dev.parent, "Can not lookup %s pinstate %d\n", PINCTRL_STATE_RELEASE, retval); } return 0; err_pinctrl_lookup: devm_pinctrl_put(rmi4_data->ts_pinctrl); err_pinctrl_get: rmi4_data->ts_pinctrl = NULL; return retval; } static int synaptics_rmi4_probe(struct platform_device *pdev) { int retval; Loading Loading @@ -3757,6 +3985,21 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) goto err_enable_reg; } retval = synaptics_dsx_pinctrl_init(rmi4_data); if (!retval && rmi4_data->ts_pinctrl) { /* * Pinctrl handle is optional. If pinctrl handle is found * let pins to be configured in active state. If not * found continue further without error. */ retval = pinctrl_select_state(rmi4_data->ts_pinctrl, rmi4_data->pinctrl_state_active); if (retval < 0) { dev_err(&pdev->dev, "%s: Failed to select %s pinstate %d\n", __func__, PINCTRL_STATE_ACTIVE, retval); } } retval = synaptics_rmi4_set_gpio(rmi4_data); if (retval < 0) { dev_err(&pdev->dev, Loading Loading @@ -3784,6 +4027,8 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) } #ifdef CONFIG_FB INIT_WORK(&rmi4_data->fb_notify_work, synaptics_rmi4_fb_notify_resume_work); rmi4_data->fb_notifier.notifier_call = synaptics_rmi4_fb_notifier_cb; retval = fb_register_client(&rmi4_data->fb_notifier); if (retval < 0) { Loading Loading @@ -3849,25 +4094,52 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) rmi4_data->rb_workqueue = create_singlethread_workqueue("dsx_rebuild_workqueue"); if (!rmi4_data->rb_workqueue) { retval = -ENOMEM; goto err_rb_workqueue; } INIT_DELAYED_WORK(&rmi4_data->rb_work, synaptics_rmi4_rebuild_work); exp_data.workqueue = create_singlethread_workqueue("dsx_exp_workqueue"); if (!exp_data.workqueue) { retval = -ENOMEM; goto err_exp_data_workqueue; } INIT_DELAYED_WORK(&exp_data.work, synaptics_rmi4_exp_fn_work); exp_data.rmi4_data = rmi4_data; exp_data.queue_work = true; queue_delayed_work(exp_data.workqueue, &exp_data.work, 0); queue_delayed_work(exp_data.workqueue, &exp_data.work, 0); #ifdef FB_READY_RESET rmi4_data->reset_workqueue = create_singlethread_workqueue("dsx_reset_workqueue"); if (!rmi4_data->reset_workqueue) { retval = -ENOMEM; goto err_reset_workqueue; } INIT_WORK(&rmi4_data->reset_work, synaptics_rmi4_reset_work); queue_work(rmi4_data->reset_workqueue, &rmi4_data->reset_work); #endif /* Initialize secure touch */ synaptics_secure_touch_init(rmi4_data); synaptics_secure_touch_stop(rmi4_data, true); return retval; #ifdef FB_READY_RESET err_reset_workqueue: #endif cancel_delayed_work_sync(&exp_data.work); flush_workqueue(exp_data.workqueue); destroy_workqueue(exp_data.workqueue); err_exp_data_workqueue: cancel_delayed_work_sync(&rmi4_data->rb_work); flush_workqueue(rmi4_data->rb_workqueue); destroy_workqueue(rmi4_data->rb_workqueue); err_rb_workqueue: err_sysfs: for (attr_count--; attr_count >= 0; attr_count--) { sysfs_remove_file(&rmi4_data->input_dev->dev.kobj, Loading Loading @@ -3913,6 +4185,21 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) err_set_gpio: synaptics_rmi4_enable_reg(rmi4_data, false); if (rmi4_data->ts_pinctrl) { if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) { devm_pinctrl_put(rmi4_data->ts_pinctrl); rmi4_data->ts_pinctrl = NULL; } else { retval = pinctrl_select_state( rmi4_data->ts_pinctrl, rmi4_data->pinctrl_state_release); if (retval) dev_err(&pdev->dev, "%s: Failed to create sysfs attributes\n", __func__); } } err_enable_reg: synaptics_rmi4_get_reg(rmi4_data, false); Loading @@ -3925,6 +4212,7 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) static int synaptics_rmi4_remove(struct platform_device *pdev) { unsigned char attr_count; int err; struct synaptics_rmi4_data *rmi4_data = platform_get_drvdata(pdev); const struct synaptics_dsx_board_data *bdata = rmi4_data->hw_if->board_data; Loading Loading @@ -3980,6 +4268,22 @@ static int synaptics_rmi4_remove(struct platform_device *pdev) if (bdata->power_gpio >= 0) synaptics_rmi4_gpio_setup(bdata->power_gpio, false, 0, 0); if (rmi4_data->ts_pinctrl) { if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) { devm_pinctrl_put(rmi4_data->ts_pinctrl); rmi4_data->ts_pinctrl = NULL; } else { err = pinctrl_select_state( rmi4_data->ts_pinctrl, rmi4_data->pinctrl_state_release); if (err) dev_err(&pdev->dev, "Failed to select release pinctrl state %d\n", err); } } synaptics_rmi4_enable_reg(rmi4_data, false); synaptics_rmi4_get_reg(rmi4_data, false); Loading Loading @@ -4096,6 +4400,14 @@ static void synaptics_rmi4_wakeup_gesture(struct synaptics_rmi4_data *rmi4_data, } #ifdef CONFIG_FB static void synaptics_rmi4_fb_notify_resume_work(struct work_struct *work) { struct synaptics_rmi4_data *rmi4_data = container_of(work, struct synaptics_rmi4_data, fb_notify_work); synaptics_rmi4_resume(&(rmi4_data->input_dev->dev)); rmi4_data->fb_ready = true; } static int synaptics_rmi4_fb_notifier_cb(struct notifier_block *self, unsigned long event, void *data) { Loading @@ -4106,17 +4418,39 @@ static int synaptics_rmi4_fb_notifier_cb(struct notifier_block *self, fb_notifier); if (evdata && evdata->data && rmi4_data) { if (event == FB_EVENT_BLANK) { if (rmi4_data->hw_if->board_data->resume_in_workqueue) { if (event == FB_EARLY_EVENT_BLANK) { synaptics_secure_touch_stop(rmi4_data, false); } else if (event == FB_EVENT_BLANK) { transition = evdata->data; if (*transition == FB_BLANK_POWERDOWN) { flush_work( &(rmi4_data->fb_notify_work)); synaptics_rmi4_suspend( &rmi4_data->pdev->dev); rmi4_data->fb_ready = false; } else if (*transition == FB_BLANK_UNBLANK) { schedule_work( &(rmi4_data->fb_notify_work)); } } } else { if (event == FB_EARLY_EVENT_BLANK) { synaptics_secure_touch_stop(rmi4_data, false); } else if (event == FB_EVENT_BLANK) { transition = evdata->data; if (*transition == FB_BLANK_POWERDOWN) { synaptics_rmi4_suspend(&rmi4_data->pdev->dev); synaptics_rmi4_suspend( &rmi4_data->pdev->dev); rmi4_data->fb_ready = false; } else if (*transition == FB_BLANK_UNBLANK) { synaptics_rmi4_resume(&rmi4_data->pdev->dev); synaptics_rmi4_resume( &rmi4_data->pdev->dev); rmi4_data->fb_ready = true; } } } } return 0; } Loading @@ -4133,6 +4467,14 @@ static void synaptics_rmi4_early_suspend(struct early_suspend *h) if (rmi4_data->stay_awake) return; /* * During early suspend/late resume, the driver doesn't access xPU/SMMU * protected HW resources. So, there is no compelling need to block, * but notifying the userspace that a power event has occurred is * enough. Hence 'blocking' variable can be set to false. */ synaptics_secure_touch_stop(rmi4_data, false); if (rmi4_data->enable_wakeup_gesture) { synaptics_rmi4_wakeup_gesture(rmi4_data, true); enable_irq_wake(rmi4_data->irq); Loading Loading @@ -4170,6 +4512,8 @@ static void synaptics_rmi4_late_resume(struct early_suspend *h) if (rmi4_data->stay_awake) return; synaptics_secure_touch_stop(rmi4_data, false); if (rmi4_data->enable_wakeup_gesture) { synaptics_rmi4_wakeup_gesture(rmi4_data, false); disable_irq_wake(rmi4_data->irq); Loading Loading @@ -4212,10 +4556,13 @@ static int synaptics_rmi4_suspend(struct device *dev) { struct synaptics_rmi4_exp_fhandler *exp_fhandler; struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); int retval; if (rmi4_data->stay_awake) return 0; synaptics_secure_touch_stop(rmi4_data, true); if (rmi4_data->enable_wakeup_gesture) { synaptics_rmi4_wakeup_gesture(rmi4_data, true); enable_irq_wake(rmi4_data->irq); Loading @@ -4228,6 +4575,13 @@ static int synaptics_rmi4_suspend(struct device *dev) synaptics_rmi4_free_fingers(rmi4_data); } if (rmi4_data->ts_pinctrl) { retval = pinctrl_select_state(rmi4_data->ts_pinctrl, rmi4_data->pinctrl_state_suspend); if (retval < 0) dev_err(dev, "Cannot get idle pinctrl state\n"); goto err_pinctrl; } exit: mutex_lock(&exp_data.mutex); if (!list_empty(&exp_data.list)) { Loading @@ -4237,9 +4591,19 @@ static int synaptics_rmi4_suspend(struct device *dev) } mutex_unlock(&exp_data.mutex); if (!rmi4_data->suspend) { synaptics_rmi4_enable_reg(rmi4_data, false); synaptics_rmi4_get_reg(rmi4_data, false); } rmi4_data->suspend = true; return 0; err_pinctrl: synaptics_rmi4_sleep_enable(rmi4_data, false); synaptics_rmi4_irq_enable(rmi4_data, true, false); return retval; } static int synaptics_rmi4_resume(struct device *dev) Loading @@ -4253,6 +4617,8 @@ static int synaptics_rmi4_resume(struct device *dev) if (rmi4_data->stay_awake) return 0; synaptics_secure_touch_stop(rmi4_data, true); if (rmi4_data->enable_wakeup_gesture) { synaptics_rmi4_wakeup_gesture(rmi4_data, false); disable_irq_wake(rmi4_data->irq); Loading @@ -4261,8 +4627,19 @@ static int synaptics_rmi4_resume(struct device *dev) rmi4_data->current_page = MASK_8BIT; if (rmi4_data->suspend) { synaptics_rmi4_get_reg(rmi4_data, true); synaptics_rmi4_enable_reg(rmi4_data, true); } synaptics_rmi4_sleep_enable(rmi4_data, false); synaptics_rmi4_irq_enable(rmi4_data, true, false); if (rmi4_data->ts_pinctrl) { retval = pinctrl_select_state(rmi4_data->ts_pinctrl, rmi4_data->pinctrl_state_active); if (retval < 0) dev_err(dev, "Cannot get default pinctrl state\n"); } exit: #ifdef FB_READY_RESET Loading Loading
Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt +19 −3 Original line number Diff line number Diff line Loading @@ -11,6 +11,8 @@ Required properties: - reg : i2c slave address of the device. - interrupt-parent : parent of interrupt. - synaptics,irq-gpio : irq gpio. - synaptics,reset-gpio : reset gpio. - synaptics,power-gpio : power switch gpio. - synaptics,irq-flags : irq flags. Optional property: Loading @@ -18,13 +20,23 @@ Optional property: - vcc_i2c-supply : analog voltage power supply needed to power device. - synaptics,pwr-reg-name : power reg name of digital voltage. - synaptics,bus-reg-name : bus reg name of analog voltage. - synaptics,irq-on-state : status of irq gpio. - synaptics,irq-on-state : irq gpio active state. - synaptics,reset-on-state : reset gpio active state. - synaptics,power-on-state : power switch active state. - synaptics,ub-i2c-addr : microbootloader mode I2C slave address. - synaptics,cap-button-codes : virtual key code mappings to be used. - synaptics,vir-button-codes : virtual key code and the response region on panel. - synaptics,x-flip : modify orientation of the x axis. - synaptics,y-flip : modify orientation of the y axis. - synaptics,reset-delay-ms : reset delay for controller (ms), default 100. - synaptics,reset-active-ms : reset active duration for controller (ms), default 100. - synaptics,power-delay-ms : power delay for controller (ms), default 100. - synaptics,max-y-for-2d : maximal y value of the panel. - synaptics,swap-axes : specify whether to swap axes. - synaptics,resume-in-workqueue : specify whether to defer the resume to workqueue. - clock-names : Clock names used for secure touch. They are: "iface_clk", "core_clk" - clocks : Defined if 'clock-names' DT property is defined. These clocks are associated with the underlying I2C bus. Example: i2c@78b7000 { Loading @@ -34,8 +46,8 @@ Example: reg = <0x4b>; interrupt-parent = <&tlmm>; interrupts = <65 0x2008>; vdd_ana-supply = <&pmtitanium_l17>; vcc_i2c-supply = <&pmtitanium_l6>; vdd_ana-supply = <&pm8953_l17>; vcc_i2c-supply = <&pm8953_l6>; synaptics,pwr-reg-name = "vdd_ana"; synaptics,bus-reg-name = "vcc_i2c"; synaptics,irq-gpio = <&tlmm 65 0x2008>; Loading @@ -46,5 +58,9 @@ Example: synaptics,max-y-for-2d = <1919>; /* remove if no virtual buttons */ synaptics,cap-button-codes = <139 172 158>; synaptics,vir-button-codes = <139 180 2000 320 160 172 540 2000 320 160 158 900 2000 320 160>; /* Underlying clocks used by secure touch */ clock-names = "iface_clk", "core_clk"; clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>, <&clock_gcc clk_gcc_blsp1_qup3_i2c_apps_clk>; }; };
drivers/input/touchscreen/synaptics_dsx_2.6/Kconfig +10 −0 Original line number Diff line number Diff line Loading @@ -114,4 +114,14 @@ config TOUCHSCREEN_SYNAPTICS_DSX_VIDEO_v26 To compile this driver as a module, choose M here: the module will be called synaptics_dsx_video. config SECURE_TOUCH_SYNAPTICS_DSX_V26 bool "Secure Touch support for Synaptics V2.6 Touchscreen" depends on TOUCHSCREEN_SYNAPTICS_DSX_I2C_v26 help Say Y here -Synaptics DSX V2.6 touch driver is connected -To enable secure touch for Synaptics DSX V2.6 touch driver If unsure, say N. endif
drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c +446 −69 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ * * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com> * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com> * Copyright (C) 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by Loading Loading @@ -117,11 +118,11 @@ static int synaptics_rmi4_check_status(struct synaptics_rmi4_data *rmi4_data, bool *was_in_bl_mode); static int synaptics_rmi4_free_fingers(struct synaptics_rmi4_data *rmi4_data); static int synaptics_rmi4_reinit_device(struct synaptics_rmi4_data *rmi4_data); static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data, bool rebuild); #ifdef CONFIG_FB static void synaptics_rmi4_fb_notify_resume_work(struct work_struct *work); static int synaptics_rmi4_fb_notifier_cb(struct notifier_block *self, unsigned long event, void *data); #endif Loading Loading @@ -172,6 +173,19 @@ static ssize_t synaptics_rmi4_wake_gesture_store(struct device *dev, static ssize_t synaptics_rmi4_virtual_key_map_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); #if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26) static ssize_t synaptics_rmi4_secure_touch_enable_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t synaptics_rmi4_secure_touch_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); static ssize_t synaptics_rmi4_secure_touch_show(struct device *dev, struct device_attribute *attr, char *buf); #endif static irqreturn_t synaptics_rmi4_irq(int irq, void *data); struct synaptics_rmi4_f01_device_status { union { struct { Loading Loading @@ -597,26 +611,34 @@ static struct synaptics_dsx_button_map *vir_button_map; static struct device_attribute attrs[] = { __ATTR(reset, 0220, synaptics_rmi4_show_error, NULL, synaptics_rmi4_f01_reset_store), __ATTR(productinfo, 0444, synaptics_rmi4_f01_productinfo_show, synaptics_rmi4_store_error), NULL), __ATTR(buildid, 0444, synaptics_rmi4_f01_buildid_show, synaptics_rmi4_store_error), NULL), __ATTR(flashprog, 0444, synaptics_rmi4_f01_flashprog_show, synaptics_rmi4_store_error), NULL), __ATTR(0dbutton, 0664, synaptics_rmi4_0dbutton_show, synaptics_rmi4_0dbutton_store), __ATTR(suspend, 0220, synaptics_rmi4_show_error, NULL, synaptics_rmi4_suspend_store), __ATTR(wake_gesture, 0664, synaptics_rmi4_wake_gesture_show, synaptics_rmi4_wake_gesture_store), #if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26) __ATTR(secure_touch_enable, 0664, synaptics_rmi4_secure_touch_enable_show, synaptics_rmi4_secure_touch_enable_store), __ATTR(secure_touch, 0444, synaptics_rmi4_secure_touch_show, NULL), #endif }; static struct kobj_attribute virtual_key_map_attr = { Loading @@ -627,6 +649,205 @@ static struct kobj_attribute virtual_key_map_attr = { .show = synaptics_rmi4_virtual_key_map_show, }; #if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26) static void synaptics_secure_touch_init(struct synaptics_rmi4_data *data) { data->st_initialized = 0; init_completion(&data->st_powerdown); init_completion(&data->st_irq_processed); /* Get clocks */ data->core_clk = devm_clk_get(data->pdev->dev.parent, "core_clk"); if (IS_ERR(data->core_clk)) { dev_warn(data->pdev->dev.parent, "%s: error on clk_get(core_clk): %ld\n", __func__, PTR_ERR(data->core_clk)); data->core_clk = NULL; } data->iface_clk = devm_clk_get(data->pdev->dev.parent, "iface_clk"); if (IS_ERR(data->iface_clk)) { dev_warn(data->pdev->dev.parent, "%s: error on clk_get(iface_clk): %ld\n", __func__, PTR_ERR(data->iface_clk)); data->iface_clk = NULL; } data->st_initialized = 1; } static void synaptics_secure_touch_notify(struct synaptics_rmi4_data *rmi4_data) { sysfs_notify(&rmi4_data->input_dev->dev.kobj, NULL, "secure_touch"); } static irqreturn_t synaptics_filter_interrupt( struct synaptics_rmi4_data *rmi4_data) { if (atomic_read(&rmi4_data->st_enabled)) { if (atomic_cmpxchg(&rmi4_data->st_pending_irqs, 0, 1) == 0) { reinit_completion(&rmi4_data->st_irq_processed); synaptics_secure_touch_notify(rmi4_data); wait_for_completion_interruptible( &rmi4_data->st_irq_processed); } return IRQ_HANDLED; } return IRQ_NONE; } /* * 'blocking' variable will have value 'true' when we want to prevent the driver * from accessing the xPU/SMMU protected HW resources while the session is * active. */ static void synaptics_secure_touch_stop(struct synaptics_rmi4_data *rmi4_data, bool blocking) { if (atomic_read(&rmi4_data->st_enabled)) { atomic_set(&rmi4_data->st_pending_irqs, -1); synaptics_secure_touch_notify(rmi4_data); if (blocking) wait_for_completion_interruptible( &rmi4_data->st_powerdown); } } #else static void synaptics_secure_touch_init(struct synaptics_rmi4_data *rmi4_data) { } static irqreturn_t synaptics_filter_interrupt( struct synaptics_rmi4_data *rmi4_data) { return IRQ_NONE; } static void synaptics_secure_touch_stop(struct synaptics_rmi4_data *rmi4_data, bool blocking) { } #endif #if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26) static ssize_t synaptics_rmi4_secure_touch_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); return scnprintf(buf, PAGE_SIZE, "%d", atomic_read(&rmi4_data->st_enabled)); } /* * Accept only "0" and "1" valid values. * "0" will reset the st_enabled flag, then wake up the reading process and * the interrupt handler. * The bus driver is notified via pm_runtime that it is not required to stay * awake anymore. * It will also make sure the queue of events is emptied in the controller, * in case a touch happened in between the secure touch being disabled and * the local ISR being ungated. * "1" will set the st_enabled flag and clear the st_pending_irqs flag. * The bus driver is requested via pm_runtime to stay awake. */ static ssize_t synaptics_rmi4_secure_touch_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); unsigned long value; int err = 0; if (count > 2) return -EINVAL; err = kstrtoul(buf, 10, &value); if (err != 0) return err; if (!rmi4_data->st_initialized) return -EIO; err = count; switch (value) { case 0: if (atomic_read(&rmi4_data->st_enabled) == 0) break; synaptics_rmi4_bus_put(rmi4_data); atomic_set(&rmi4_data->st_enabled, 0); synaptics_secure_touch_notify(rmi4_data); complete(&rmi4_data->st_irq_processed); synaptics_rmi4_irq(rmi4_data->irq, rmi4_data); complete(&rmi4_data->st_powerdown); break; case 1: if (atomic_read(&rmi4_data->st_enabled)) { err = -EBUSY; break; } synchronize_irq(rmi4_data->irq); if (synaptics_rmi4_bus_get(rmi4_data) < 0) { dev_err( rmi4_data->pdev->dev.parent, "synaptics_rmi4_bus_get failed\n"); err = -EIO; break; } reinit_completion(&rmi4_data->st_powerdown); reinit_completion(&rmi4_data->st_irq_processed); atomic_set(&rmi4_data->st_enabled, 1); atomic_set(&rmi4_data->st_pending_irqs, 0); break; default: dev_err( rmi4_data->pdev->dev.parent, "unsupported value: %lu\n", value); err = -EINVAL; break; } return err; } /* * This function returns whether there are pending interrupts, or * other error conditions that need to be signaled to the userspace library, * according tot he following logic: * - st_enabled is 0 if secure touch is not enabled, returning -EBADF * - st_pending_irqs is -1 to signal that secure touch is in being stopped, * returning -EINVAL * - st_pending_irqs is 1 to signal that there is a pending irq, returning * the value "1" to the sysfs read operation * - st_pending_irqs is 0 (only remaining case left) if the pending interrupt * has been processed, so the interrupt handler can be allowed to continue. */ static ssize_t synaptics_rmi4_secure_touch_show(struct device *dev, struct device_attribute *attr, char *buf) { struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); int val = 0; if (atomic_read(&rmi4_data->st_enabled) == 0) return -EBADF; if (atomic_cmpxchg(&rmi4_data->st_pending_irqs, -1, 0) == -1) return -EINVAL; if (atomic_cmpxchg(&rmi4_data->st_pending_irqs, 1, 0) == 1) val = 1; else complete(&rmi4_data->st_irq_processed); return scnprintf(buf, PAGE_SIZE, "%u", val); } #endif static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { Loading Loading @@ -1173,7 +1394,6 @@ static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data, #ifndef TYPE_B_PROTOCOL input_mt_sync(rmi4_data->input_dev); #endif input_sync(rmi4_data->input_dev); dev_dbg(rmi4_data->pdev->dev.parent, "%s: Finger %d: status = 0x%02x, x = %d, y = %d, wx = %d, wy = %d\n", Loading Loading @@ -1245,7 +1465,6 @@ static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data, #ifndef TYPE_B_PROTOCOL input_mt_sync(rmi4_data->input_dev); #endif input_sync(rmi4_data->input_dev); if (rmi4_data->stylus_enable) { stylus_presence = 0; Loading @@ -1261,6 +1480,8 @@ static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data, } } input_sync(rmi4_data->input_dev); mutex_unlock(&(rmi4_data->rmi4_report_mutex)); return touch_count; Loading Loading @@ -1465,12 +1686,6 @@ static void synaptics_rmi4_sensor_report(struct synaptics_rmi4_data *rmi4_data, } if (status.unconfigured && !status.flash_prog) { pr_notice("%s: spontaneous reset detected\n", __func__); retval = synaptics_rmi4_reinit_device(rmi4_data); if (retval < 0) { dev_err(rmi4_data->pdev->dev.parent, "%s: Failed to reinit device\n", __func__); } } if (!report) Loading Loading @@ -1512,6 +1727,9 @@ static irqreturn_t synaptics_rmi4_irq(int irq, void *data) const struct synaptics_dsx_board_data *bdata = rmi4_data->hw_if->board_data; if (synaptics_filter_interrupt(data) == IRQ_HANDLED) return IRQ_HANDLED; if (gpio_get_value(bdata->irq_gpio) != bdata->irq_on_state) goto exit; Loading Loading @@ -2911,7 +3129,9 @@ static int synaptics_rmi4_gpio_setup(int gpio, bool config, int dir, int state) unsigned char buf[16]; if (config) { snprintf(buf, PAGE_SIZE, "dsx_gpio_%u\n", gpio); retval = snprintf(buf, ARRAY_SIZE(buf), "dsx_gpio_%u\n", gpio); if (retval >= 16) return -EINVAL; retval = gpio_request(gpio, buf); if (retval) { Loading Loading @@ -3434,49 +3654,6 @@ static void synaptics_rmi4_rebuild_work(struct work_struct *work) return; } static int synaptics_rmi4_reinit_device(struct synaptics_rmi4_data *rmi4_data) { int retval; struct synaptics_rmi4_fn *fhandler; struct synaptics_rmi4_exp_fhandler *exp_fhandler; struct synaptics_rmi4_device_info *rmi; rmi = &(rmi4_data->rmi4_mod_info); mutex_lock(&(rmi4_data->rmi4_reset_mutex)); synaptics_rmi4_free_fingers(rmi4_data); if (!list_empty(&rmi->support_fn_list)) { list_for_each_entry(fhandler, &rmi->support_fn_list, link) { if (fhandler->fn_number == SYNAPTICS_RMI4_F12) { synaptics_rmi4_f12_set_enables(rmi4_data, 0); break; } } } retval = synaptics_rmi4_int_enable(rmi4_data, true); if (retval < 0) goto exit; mutex_lock(&exp_data.mutex); if (!list_empty(&exp_data.list)) { list_for_each_entry(exp_fhandler, &exp_data.list, link) if (exp_fhandler->exp_fn->reinit != NULL) exp_fhandler->exp_fn->reinit(rmi4_data); } mutex_unlock(&exp_data.mutex); synaptics_rmi4_set_configured(rmi4_data); retval = 0; exit: mutex_unlock(&(rmi4_data->rmi4_reset_mutex)); return retval; } static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data, bool rebuild) { Loading Loading @@ -3688,6 +3865,57 @@ void synaptics_rmi4_new_function(struct synaptics_rmi4_exp_fn *exp_fn, } EXPORT_SYMBOL(synaptics_rmi4_new_function); static int synaptics_dsx_pinctrl_init(struct synaptics_rmi4_data *rmi4_data) { int retval; /* Get pinctrl if target uses pinctrl */ rmi4_data->ts_pinctrl = devm_pinctrl_get((rmi4_data->pdev->dev.parent)); if (IS_ERR_OR_NULL(rmi4_data->ts_pinctrl)) { retval = PTR_ERR(rmi4_data->ts_pinctrl); dev_err(rmi4_data->pdev->dev.parent, "Target does not use pinctrl %d\n", retval); goto err_pinctrl_get; } rmi4_data->pinctrl_state_active = pinctrl_lookup_state(rmi4_data->ts_pinctrl, "pmx_ts_active"); if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_active)) { retval = PTR_ERR(rmi4_data->pinctrl_state_active); dev_err(rmi4_data->pdev->dev.parent, "Can not lookup %s pinstate %d\n", PINCTRL_STATE_ACTIVE, retval); goto err_pinctrl_lookup; } rmi4_data->pinctrl_state_suspend = pinctrl_lookup_state(rmi4_data->ts_pinctrl, "pmx_ts_suspend"); if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_suspend)) { retval = PTR_ERR(rmi4_data->pinctrl_state_suspend); dev_dbg(rmi4_data->pdev->dev.parent, "Can not lookup %s pinstate %d\n", PINCTRL_STATE_SUSPEND, retval); goto err_pinctrl_lookup; } rmi4_data->pinctrl_state_release = pinctrl_lookup_state(rmi4_data->ts_pinctrl, "pmx_ts_release"); if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) { retval = PTR_ERR(rmi4_data->pinctrl_state_release); dev_dbg(rmi4_data->pdev->dev.parent, "Can not lookup %s pinstate %d\n", PINCTRL_STATE_RELEASE, retval); } return 0; err_pinctrl_lookup: devm_pinctrl_put(rmi4_data->ts_pinctrl); err_pinctrl_get: rmi4_data->ts_pinctrl = NULL; return retval; } static int synaptics_rmi4_probe(struct platform_device *pdev) { int retval; Loading Loading @@ -3757,6 +3985,21 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) goto err_enable_reg; } retval = synaptics_dsx_pinctrl_init(rmi4_data); if (!retval && rmi4_data->ts_pinctrl) { /* * Pinctrl handle is optional. If pinctrl handle is found * let pins to be configured in active state. If not * found continue further without error. */ retval = pinctrl_select_state(rmi4_data->ts_pinctrl, rmi4_data->pinctrl_state_active); if (retval < 0) { dev_err(&pdev->dev, "%s: Failed to select %s pinstate %d\n", __func__, PINCTRL_STATE_ACTIVE, retval); } } retval = synaptics_rmi4_set_gpio(rmi4_data); if (retval < 0) { dev_err(&pdev->dev, Loading Loading @@ -3784,6 +4027,8 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) } #ifdef CONFIG_FB INIT_WORK(&rmi4_data->fb_notify_work, synaptics_rmi4_fb_notify_resume_work); rmi4_data->fb_notifier.notifier_call = synaptics_rmi4_fb_notifier_cb; retval = fb_register_client(&rmi4_data->fb_notifier); if (retval < 0) { Loading Loading @@ -3849,25 +4094,52 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) rmi4_data->rb_workqueue = create_singlethread_workqueue("dsx_rebuild_workqueue"); if (!rmi4_data->rb_workqueue) { retval = -ENOMEM; goto err_rb_workqueue; } INIT_DELAYED_WORK(&rmi4_data->rb_work, synaptics_rmi4_rebuild_work); exp_data.workqueue = create_singlethread_workqueue("dsx_exp_workqueue"); if (!exp_data.workqueue) { retval = -ENOMEM; goto err_exp_data_workqueue; } INIT_DELAYED_WORK(&exp_data.work, synaptics_rmi4_exp_fn_work); exp_data.rmi4_data = rmi4_data; exp_data.queue_work = true; queue_delayed_work(exp_data.workqueue, &exp_data.work, 0); queue_delayed_work(exp_data.workqueue, &exp_data.work, 0); #ifdef FB_READY_RESET rmi4_data->reset_workqueue = create_singlethread_workqueue("dsx_reset_workqueue"); if (!rmi4_data->reset_workqueue) { retval = -ENOMEM; goto err_reset_workqueue; } INIT_WORK(&rmi4_data->reset_work, synaptics_rmi4_reset_work); queue_work(rmi4_data->reset_workqueue, &rmi4_data->reset_work); #endif /* Initialize secure touch */ synaptics_secure_touch_init(rmi4_data); synaptics_secure_touch_stop(rmi4_data, true); return retval; #ifdef FB_READY_RESET err_reset_workqueue: #endif cancel_delayed_work_sync(&exp_data.work); flush_workqueue(exp_data.workqueue); destroy_workqueue(exp_data.workqueue); err_exp_data_workqueue: cancel_delayed_work_sync(&rmi4_data->rb_work); flush_workqueue(rmi4_data->rb_workqueue); destroy_workqueue(rmi4_data->rb_workqueue); err_rb_workqueue: err_sysfs: for (attr_count--; attr_count >= 0; attr_count--) { sysfs_remove_file(&rmi4_data->input_dev->dev.kobj, Loading Loading @@ -3913,6 +4185,21 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) err_set_gpio: synaptics_rmi4_enable_reg(rmi4_data, false); if (rmi4_data->ts_pinctrl) { if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) { devm_pinctrl_put(rmi4_data->ts_pinctrl); rmi4_data->ts_pinctrl = NULL; } else { retval = pinctrl_select_state( rmi4_data->ts_pinctrl, rmi4_data->pinctrl_state_release); if (retval) dev_err(&pdev->dev, "%s: Failed to create sysfs attributes\n", __func__); } } err_enable_reg: synaptics_rmi4_get_reg(rmi4_data, false); Loading @@ -3925,6 +4212,7 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) static int synaptics_rmi4_remove(struct platform_device *pdev) { unsigned char attr_count; int err; struct synaptics_rmi4_data *rmi4_data = platform_get_drvdata(pdev); const struct synaptics_dsx_board_data *bdata = rmi4_data->hw_if->board_data; Loading Loading @@ -3980,6 +4268,22 @@ static int synaptics_rmi4_remove(struct platform_device *pdev) if (bdata->power_gpio >= 0) synaptics_rmi4_gpio_setup(bdata->power_gpio, false, 0, 0); if (rmi4_data->ts_pinctrl) { if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) { devm_pinctrl_put(rmi4_data->ts_pinctrl); rmi4_data->ts_pinctrl = NULL; } else { err = pinctrl_select_state( rmi4_data->ts_pinctrl, rmi4_data->pinctrl_state_release); if (err) dev_err(&pdev->dev, "Failed to select release pinctrl state %d\n", err); } } synaptics_rmi4_enable_reg(rmi4_data, false); synaptics_rmi4_get_reg(rmi4_data, false); Loading Loading @@ -4096,6 +4400,14 @@ static void synaptics_rmi4_wakeup_gesture(struct synaptics_rmi4_data *rmi4_data, } #ifdef CONFIG_FB static void synaptics_rmi4_fb_notify_resume_work(struct work_struct *work) { struct synaptics_rmi4_data *rmi4_data = container_of(work, struct synaptics_rmi4_data, fb_notify_work); synaptics_rmi4_resume(&(rmi4_data->input_dev->dev)); rmi4_data->fb_ready = true; } static int synaptics_rmi4_fb_notifier_cb(struct notifier_block *self, unsigned long event, void *data) { Loading @@ -4106,17 +4418,39 @@ static int synaptics_rmi4_fb_notifier_cb(struct notifier_block *self, fb_notifier); if (evdata && evdata->data && rmi4_data) { if (event == FB_EVENT_BLANK) { if (rmi4_data->hw_if->board_data->resume_in_workqueue) { if (event == FB_EARLY_EVENT_BLANK) { synaptics_secure_touch_stop(rmi4_data, false); } else if (event == FB_EVENT_BLANK) { transition = evdata->data; if (*transition == FB_BLANK_POWERDOWN) { flush_work( &(rmi4_data->fb_notify_work)); synaptics_rmi4_suspend( &rmi4_data->pdev->dev); rmi4_data->fb_ready = false; } else if (*transition == FB_BLANK_UNBLANK) { schedule_work( &(rmi4_data->fb_notify_work)); } } } else { if (event == FB_EARLY_EVENT_BLANK) { synaptics_secure_touch_stop(rmi4_data, false); } else if (event == FB_EVENT_BLANK) { transition = evdata->data; if (*transition == FB_BLANK_POWERDOWN) { synaptics_rmi4_suspend(&rmi4_data->pdev->dev); synaptics_rmi4_suspend( &rmi4_data->pdev->dev); rmi4_data->fb_ready = false; } else if (*transition == FB_BLANK_UNBLANK) { synaptics_rmi4_resume(&rmi4_data->pdev->dev); synaptics_rmi4_resume( &rmi4_data->pdev->dev); rmi4_data->fb_ready = true; } } } } return 0; } Loading @@ -4133,6 +4467,14 @@ static void synaptics_rmi4_early_suspend(struct early_suspend *h) if (rmi4_data->stay_awake) return; /* * During early suspend/late resume, the driver doesn't access xPU/SMMU * protected HW resources. So, there is no compelling need to block, * but notifying the userspace that a power event has occurred is * enough. Hence 'blocking' variable can be set to false. */ synaptics_secure_touch_stop(rmi4_data, false); if (rmi4_data->enable_wakeup_gesture) { synaptics_rmi4_wakeup_gesture(rmi4_data, true); enable_irq_wake(rmi4_data->irq); Loading Loading @@ -4170,6 +4512,8 @@ static void synaptics_rmi4_late_resume(struct early_suspend *h) if (rmi4_data->stay_awake) return; synaptics_secure_touch_stop(rmi4_data, false); if (rmi4_data->enable_wakeup_gesture) { synaptics_rmi4_wakeup_gesture(rmi4_data, false); disable_irq_wake(rmi4_data->irq); Loading Loading @@ -4212,10 +4556,13 @@ static int synaptics_rmi4_suspend(struct device *dev) { struct synaptics_rmi4_exp_fhandler *exp_fhandler; struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); int retval; if (rmi4_data->stay_awake) return 0; synaptics_secure_touch_stop(rmi4_data, true); if (rmi4_data->enable_wakeup_gesture) { synaptics_rmi4_wakeup_gesture(rmi4_data, true); enable_irq_wake(rmi4_data->irq); Loading @@ -4228,6 +4575,13 @@ static int synaptics_rmi4_suspend(struct device *dev) synaptics_rmi4_free_fingers(rmi4_data); } if (rmi4_data->ts_pinctrl) { retval = pinctrl_select_state(rmi4_data->ts_pinctrl, rmi4_data->pinctrl_state_suspend); if (retval < 0) dev_err(dev, "Cannot get idle pinctrl state\n"); goto err_pinctrl; } exit: mutex_lock(&exp_data.mutex); if (!list_empty(&exp_data.list)) { Loading @@ -4237,9 +4591,19 @@ static int synaptics_rmi4_suspend(struct device *dev) } mutex_unlock(&exp_data.mutex); if (!rmi4_data->suspend) { synaptics_rmi4_enable_reg(rmi4_data, false); synaptics_rmi4_get_reg(rmi4_data, false); } rmi4_data->suspend = true; return 0; err_pinctrl: synaptics_rmi4_sleep_enable(rmi4_data, false); synaptics_rmi4_irq_enable(rmi4_data, true, false); return retval; } static int synaptics_rmi4_resume(struct device *dev) Loading @@ -4253,6 +4617,8 @@ static int synaptics_rmi4_resume(struct device *dev) if (rmi4_data->stay_awake) return 0; synaptics_secure_touch_stop(rmi4_data, true); if (rmi4_data->enable_wakeup_gesture) { synaptics_rmi4_wakeup_gesture(rmi4_data, false); disable_irq_wake(rmi4_data->irq); Loading @@ -4261,8 +4627,19 @@ static int synaptics_rmi4_resume(struct device *dev) rmi4_data->current_page = MASK_8BIT; if (rmi4_data->suspend) { synaptics_rmi4_get_reg(rmi4_data, true); synaptics_rmi4_enable_reg(rmi4_data, true); } synaptics_rmi4_sleep_enable(rmi4_data, false); synaptics_rmi4_irq_enable(rmi4_data, true, false); if (rmi4_data->ts_pinctrl) { retval = pinctrl_select_state(rmi4_data->ts_pinctrl, rmi4_data->pinctrl_state_active); if (retval < 0) dev_err(dev, "Cannot get default pinctrl state\n"); } exit: #ifdef FB_READY_RESET Loading