diff options
Diffstat (limited to 'drivers/input')
23 files changed, 564 insertions, 138 deletions
| diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c index 1cf5deda06e1..fa8d1a466014 100644 --- a/drivers/input/ff-core.c +++ b/drivers/input/ff-core.c @@ -67,7 +67,7 @@ static int compat_effect(struct ff_device *ff, struct ff_effect *effect)  		effect->type = FF_PERIODIC;  		effect->u.periodic.waveform = FF_SINE;  		effect->u.periodic.period = 50; -		effect->u.periodic.magnitude = max(magnitude, 0x7fff); +		effect->u.periodic.magnitude = magnitude;  		effect->u.periodic.offset = 0;  		effect->u.periodic.phase = 0;  		effect->u.periodic.envelope.attack_length = 0; diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c index 429411c6c0a8..a85a4f33aea8 100644 --- a/drivers/input/joystick/spaceball.c +++ b/drivers/input/joystick/spaceball.c @@ -19,6 +19,7 @@  #include <linux/module.h>  #include <linux/input.h>  #include <linux/serio.h> +#include <asm/unaligned.h>  #define DRIVER_DESC	"SpaceTec SpaceBall 2003/3003/4000 FLX driver" @@ -75,9 +76,15 @@ static void spaceball_process_packet(struct spaceball* spaceball)  		case 'D':					/* Ball data */  			if (spaceball->idx != 15) return; -			for (i = 0; i < 6; i++) +			/* +			 * Skip first three bytes; read six axes worth of data. +			 * Axis values are signed 16-bit big-endian. +			 */ +			data += 3; +			for (i = 0; i < ARRAY_SIZE(spaceball_axes); i++) {  				input_report_abs(dev, spaceball_axes[i], -					(__s16)((data[2 * i + 3] << 8) | data[2 * i + 2])); +					(__s16)get_unaligned_be16(&data[i * 2])); +			}  			break;  		case 'K':					/* Button data */ diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 8dbf1e69c90a..d75a8b179a8a 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -247,7 +247,7 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,  	ssize_t error;  	int i; -	bits = bitmap_zalloc(n_events, GFP_KERNEL); +	bits = bitmap_alloc(n_events, GFP_KERNEL);  	if (!bits)  		return -ENOMEM; diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c index e09b1fae42e1..04da7916eb70 100644 --- a/drivers/input/misc/axp20x-pek.c +++ b/drivers/input/misc/axp20x-pek.c @@ -206,11 +206,8 @@ ATTRIBUTE_GROUPS(axp20x);  static irqreturn_t axp20x_pek_irq(int irq, void *pwr)  { -	struct axp20x_pek *axp20x_pek = pwr; -	struct input_dev *idev = axp20x_pek->input; - -	if (!idev) -		return IRQ_HANDLED; +	struct input_dev *idev = pwr; +	struct axp20x_pek *axp20x_pek = input_get_drvdata(idev);  	/*  	 * The power-button is connected to ground so a falling edge (dbf) @@ -229,9 +226,22 @@ static irqreturn_t axp20x_pek_irq(int irq, void *pwr)  static int axp20x_pek_probe_input_device(struct axp20x_pek *axp20x_pek,  					 struct platform_device *pdev)  { +	struct axp20x_dev *axp20x = axp20x_pek->axp20x;  	struct input_dev *idev;  	int error; +	axp20x_pek->irq_dbr = platform_get_irq_byname(pdev, "PEK_DBR"); +	if (axp20x_pek->irq_dbr < 0) +		return axp20x_pek->irq_dbr; +	axp20x_pek->irq_dbr = regmap_irq_get_virq(axp20x->regmap_irqc, +						  axp20x_pek->irq_dbr); + +	axp20x_pek->irq_dbf = platform_get_irq_byname(pdev, "PEK_DBF"); +	if (axp20x_pek->irq_dbf < 0) +		return axp20x_pek->irq_dbf; +	axp20x_pek->irq_dbf = regmap_irq_get_virq(axp20x->regmap_irqc, +						  axp20x_pek->irq_dbf); +  	axp20x_pek->input = devm_input_allocate_device(&pdev->dev);  	if (!axp20x_pek->input)  		return -ENOMEM; @@ -246,6 +256,24 @@ static int axp20x_pek_probe_input_device(struct axp20x_pek *axp20x_pek,  	input_set_drvdata(idev, axp20x_pek); +	error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbr, +					     axp20x_pek_irq, 0, +					     "axp20x-pek-dbr", idev); +	if (error < 0) { +		dev_err(&pdev->dev, "Failed to request dbr IRQ#%d: %d\n", +			axp20x_pek->irq_dbr, error); +		return error; +	} + +	error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbf, +					  axp20x_pek_irq, 0, +					  "axp20x-pek-dbf", idev); +	if (error < 0) { +		dev_err(&pdev->dev, "Failed to request dbf IRQ#%d: %d\n", +			axp20x_pek->irq_dbf, error); +		return error; +	} +  	error = input_register_device(idev);  	if (error) {  		dev_err(&pdev->dev, "Can't register input device: %d\n", @@ -253,6 +281,8 @@ static int axp20x_pek_probe_input_device(struct axp20x_pek *axp20x_pek,  		return error;  	} +	device_init_wakeup(&pdev->dev, true); +  	return 0;  } @@ -293,18 +323,6 @@ static int axp20x_pek_probe(struct platform_device *pdev)  	axp20x_pek->axp20x = dev_get_drvdata(pdev->dev.parent); -	axp20x_pek->irq_dbr = platform_get_irq_byname(pdev, "PEK_DBR"); -	if (axp20x_pek->irq_dbr < 0) -		return axp20x_pek->irq_dbr; -	axp20x_pek->irq_dbr = regmap_irq_get_virq( -			axp20x_pek->axp20x->regmap_irqc, axp20x_pek->irq_dbr); - -	axp20x_pek->irq_dbf = platform_get_irq_byname(pdev, "PEK_DBF"); -	if (axp20x_pek->irq_dbf < 0) -		return axp20x_pek->irq_dbf; -	axp20x_pek->irq_dbf = regmap_irq_get_virq( -			axp20x_pek->axp20x->regmap_irqc, axp20x_pek->irq_dbf); -  	if (axp20x_pek_should_register_input(axp20x_pek)) {  		error = axp20x_pek_probe_input_device(axp20x_pek, pdev);  		if (error) @@ -313,26 +331,6 @@ static int axp20x_pek_probe(struct platform_device *pdev)  	axp20x_pek->info = (struct axp20x_info *)match->driver_data; -	error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbr, -					     axp20x_pek_irq, 0, -					     "axp20x-pek-dbr", axp20x_pek); -	if (error < 0) { -		dev_err(&pdev->dev, "Failed to request dbr IRQ#%d: %d\n", -			axp20x_pek->irq_dbr, error); -		return error; -	} - -	error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbf, -					  axp20x_pek_irq, 0, -					  "axp20x-pek-dbf", axp20x_pek); -	if (error < 0) { -		dev_err(&pdev->dev, "Failed to request dbf IRQ#%d: %d\n", -			axp20x_pek->irq_dbf, error); -		return error; -	} - -	device_init_wakeup(&pdev->dev, true); -  	platform_set_drvdata(pdev, axp20x_pek);  	return 0; diff --git a/drivers/input/misc/iqs626a.c b/drivers/input/misc/iqs626a.c index d57e996732cf..23b5dd9552dc 100644 --- a/drivers/input/misc/iqs626a.c +++ b/drivers/input/misc/iqs626a.c @@ -456,9 +456,10 @@ struct iqs626_private {  	unsigned int suspend_mode;  }; -static int iqs626_parse_events(struct iqs626_private *iqs626, -			       const struct fwnode_handle *ch_node, -			       enum iqs626_ch_id ch_id) +static noinline_for_stack int +iqs626_parse_events(struct iqs626_private *iqs626, +		    const struct fwnode_handle *ch_node, +		    enum iqs626_ch_id ch_id)  {  	struct iqs626_sys_reg *sys_reg = &iqs626->sys_reg;  	struct i2c_client *client = iqs626->client; @@ -604,9 +605,10 @@ static int iqs626_parse_events(struct iqs626_private *iqs626,  	return 0;  } -static int iqs626_parse_ati_target(struct iqs626_private *iqs626, -				   const struct fwnode_handle *ch_node, -				   enum iqs626_ch_id ch_id) +static noinline_for_stack int +iqs626_parse_ati_target(struct iqs626_private *iqs626, +			const struct fwnode_handle *ch_node, +			enum iqs626_ch_id ch_id)  {  	struct iqs626_sys_reg *sys_reg = &iqs626->sys_reg;  	struct i2c_client *client = iqs626->client; @@ -885,9 +887,10 @@ static int iqs626_parse_trackpad(struct iqs626_private *iqs626,  	return 0;  } -static int iqs626_parse_channel(struct iqs626_private *iqs626, -				const struct fwnode_handle *ch_node, -				enum iqs626_ch_id ch_id) +static noinline_for_stack int +iqs626_parse_channel(struct iqs626_private *iqs626, +		     const struct fwnode_handle *ch_node, +		     enum iqs626_ch_id ch_id)  {  	struct iqs626_sys_reg *sys_reg = &iqs626->sys_reg;  	struct i2c_client *client = iqs626->client; diff --git a/drivers/input/misc/palmas-pwrbutton.c b/drivers/input/misc/palmas-pwrbutton.c index f9b05cf09ff5..2213e06b611d 100644 --- a/drivers/input/misc/palmas-pwrbutton.c +++ b/drivers/input/misc/palmas-pwrbutton.c @@ -15,6 +15,7 @@   * GNU General Public License for more details.   */ +#include <linux/bitfield.h>  #include <linux/init.h>  #include <linux/input.h>  #include <linux/interrupt.h> @@ -115,8 +116,8 @@ static void palmas_pwron_params_ofinit(struct device *dev,  	struct device_node *np;  	u32 val;  	int i, error; -	u8 lpk_times[] = { 6, 8, 10, 12 }; -	int pwr_on_deb_ms[] = { 15, 100, 500, 1000 }; +	static const u8 lpk_times[] = { 6, 8, 10, 12 }; +	static const int pwr_on_deb_ms[] = { 15, 100, 500, 1000 };  	memset(config, 0, sizeof(*config)); @@ -192,8 +193,8 @@ static int palmas_pwron_probe(struct platform_device *pdev)  	 * Setup default hardware shutdown option (long key press)  	 * and debounce.  	 */ -	val = config.long_press_time_val << __ffs(PALMAS_LPK_TIME_MASK); -	val |= config.pwron_debounce_val << __ffs(PALMAS_PWRON_DEBOUNCE_MASK); +	val = FIELD_PREP(PALMAS_LPK_TIME_MASK, config.long_press_time_val) | +	      FIELD_PREP(PALMAS_PWRON_DEBOUNCE_MASK, config.pwron_debounce_val);  	error = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE,  				   PALMAS_LONG_PRESS_KEY,  				   PALMAS_LPK_TIME_MASK | diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c index 4ff5cd2a6d8d..3d17a0b3fe51 100644 --- a/drivers/input/misc/xen-kbdfront.c +++ b/drivers/input/misc/xen-kbdfront.c @@ -542,6 +542,7 @@ static struct xenbus_driver xenkbd_driver = {  	.remove = xenkbd_remove,  	.resume = xenkbd_resume,  	.otherend_changed = xenkbd_backend_changed, +	.not_essential = true,  };  static int __init xenkbd_init(void) diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c index bfa26651c0be..627048bc6a12 100644 --- a/drivers/input/mouse/appletouch.c +++ b/drivers/input/mouse/appletouch.c @@ -916,6 +916,8 @@ static int atp_probe(struct usb_interface *iface,  	set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);  	set_bit(BTN_LEFT, input_dev->keybit); +	INIT_WORK(&dev->work, atp_reinit); +  	error = input_register_device(dev->input);  	if (error)  		goto err_free_buffer; @@ -923,8 +925,6 @@ static int atp_probe(struct usb_interface *iface,  	/* save our data pointer in this interface device */  	usb_set_intfdata(iface, dev); -	INIT_WORK(&dev->work, atp_reinit); -  	return 0;   err_free_buffer: diff --git a/drivers/input/mouse/byd.c b/drivers/input/mouse/byd.c index 6e0c5f5a2713..221a553f45cd 100644 --- a/drivers/input/mouse/byd.c +++ b/drivers/input/mouse/byd.c @@ -191,7 +191,7 @@  /*   * The touchpad generates a mixture of absolute and relative packets, indicated - * by the the last byte of each packet being set to one of the following: + * by the last byte of each packet being set to one of the following:   */  #define BYD_PACKET_ABSOLUTE			0xf8  #define BYD_PACKET_RELATIVE			0x00 diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 956d9cd34796..ece97f8c6a3e 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1588,7 +1588,13 @@ static const struct dmi_system_id no_hw_res_dmi_table[] = {   */  static int elantech_change_report_id(struct psmouse *psmouse)  { -	unsigned char param[2] = { 0x10, 0x03 }; +	/* +	 * NOTE: the code is expecting to receive param[] as an array of 3 +	 * items (see __ps2_command()), even if in this case only 2 are +	 * actually needed. Make sure the array size is 3 to avoid potential +	 * stack out-of-bound accesses. +	 */ +	unsigned char param[3] = { 0x10, 0x03 };  	if (elantech_write_reg_params(psmouse, 0x7, param) ||  	    elantech_read_reg_params(psmouse, 0x7, param) || diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index aedd05541044..148a7c5fd0e2 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -995,6 +995,24 @@ static const struct dmi_system_id __initconst i8042_dmi_kbdreset_table[] = {  	{ }  }; +static const struct dmi_system_id i8042_dmi_probe_defer_table[] __initconst = { +	{ +		/* ASUS ZenBook UX425UA */ +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), +			DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX425UA"), +		}, +	}, +	{ +		/* ASUS ZenBook UM325UA */ +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), +			DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX325UA_UM325UA"), +		}, +	}, +	{ } +}; +  #endif /* CONFIG_X86 */  #ifdef CONFIG_PNP @@ -1315,6 +1333,9 @@ static int __init i8042_platform_init(void)  	if (dmi_check_system(i8042_dmi_kbdreset_table))  		i8042_kbdreset = true; +	if (dmi_check_system(i8042_dmi_probe_defer_table)) +		i8042_probe_defer = true; +  	/*  	 * A20 was already enabled during early kernel init. But some buggy  	 * BIOSes (in MSI Laptops) require A20 to be enabled using 8042 to diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 0b9f1d0a8f8b..3fc0a89cc785 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -45,6 +45,10 @@ static bool i8042_unlock;  module_param_named(unlock, i8042_unlock, bool, 0);  MODULE_PARM_DESC(unlock, "Ignore keyboard lock."); +static bool i8042_probe_defer; +module_param_named(probe_defer, i8042_probe_defer, bool, 0); +MODULE_PARM_DESC(probe_defer, "Allow deferred probing."); +  enum i8042_controller_reset_mode {  	I8042_RESET_NEVER,  	I8042_RESET_ALWAYS, @@ -711,7 +715,7 @@ static int i8042_set_mux_mode(bool multiplex, unsigned char *mux_version)   * LCS/Telegraphics.   */ -static int __init i8042_check_mux(void) +static int i8042_check_mux(void)  {  	unsigned char mux_version; @@ -740,10 +744,10 @@ static int __init i8042_check_mux(void)  /*   * The following is used to test AUX IRQ delivery.   */ -static struct completion i8042_aux_irq_delivered __initdata; -static bool i8042_irq_being_tested __initdata; +static struct completion i8042_aux_irq_delivered; +static bool i8042_irq_being_tested; -static irqreturn_t __init i8042_aux_test_irq(int irq, void *dev_id) +static irqreturn_t i8042_aux_test_irq(int irq, void *dev_id)  {  	unsigned long flags;  	unsigned char str, data; @@ -770,7 +774,7 @@ static irqreturn_t __init i8042_aux_test_irq(int irq, void *dev_id)   * verifies success by readinng CTR. Used when testing for presence of AUX   * port.   */ -static int __init i8042_toggle_aux(bool on) +static int i8042_toggle_aux(bool on)  {  	unsigned char param;  	int i; @@ -798,7 +802,7 @@ static int __init i8042_toggle_aux(bool on)   * the presence of an AUX interface.   */ -static int __init i8042_check_aux(void) +static int i8042_check_aux(void)  {  	int retval = -1;  	bool irq_registered = false; @@ -1005,7 +1009,7 @@ static int i8042_controller_init(void)  		if (i8042_command(&ctr[n++ % 2], I8042_CMD_CTL_RCTR)) {  			pr_err("Can't read CTR while initializing i8042\n"); -			return -EIO; +			return i8042_probe_defer ? -EPROBE_DEFER : -EIO;  		}  	} while (n < 2 || ctr[0] != ctr[1]); @@ -1320,7 +1324,7 @@ static void i8042_shutdown(struct platform_device *dev)  	i8042_controller_reset(false);  } -static int __init i8042_create_kbd_port(void) +static int i8042_create_kbd_port(void)  {  	struct serio *serio;  	struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO]; @@ -1349,7 +1353,7 @@ static int __init i8042_create_kbd_port(void)  	return 0;  } -static int __init i8042_create_aux_port(int idx) +static int i8042_create_aux_port(int idx)  {  	struct serio *serio;  	int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx; @@ -1386,13 +1390,13 @@ static int __init i8042_create_aux_port(int idx)  	return 0;  } -static void __init i8042_free_kbd_port(void) +static void i8042_free_kbd_port(void)  {  	kfree(i8042_ports[I8042_KBD_PORT_NO].serio);  	i8042_ports[I8042_KBD_PORT_NO].serio = NULL;  } -static void __init i8042_free_aux_ports(void) +static void i8042_free_aux_ports(void)  {  	int i; @@ -1402,7 +1406,7 @@ static void __init i8042_free_aux_ports(void)  	}  } -static void __init i8042_register_ports(void) +static void i8042_register_ports(void)  {  	int i; @@ -1443,7 +1447,7 @@ static void i8042_free_irqs(void)  	i8042_aux_irq_registered = i8042_kbd_irq_registered = false;  } -static int __init i8042_setup_aux(void) +static int i8042_setup_aux(void)  {  	int (*aux_enable)(void);  	int error; @@ -1485,7 +1489,7 @@ static int __init i8042_setup_aux(void)  	return error;  } -static int __init i8042_setup_kbd(void) +static int i8042_setup_kbd(void)  {  	int error; @@ -1535,7 +1539,7 @@ static int i8042_kbd_bind_notifier(struct notifier_block *nb,  	return 0;  } -static int __init i8042_probe(struct platform_device *dev) +static int i8042_probe(struct platform_device *dev)  {  	int error; @@ -1600,6 +1604,7 @@ static struct platform_driver i8042_driver = {  		.pm	= &i8042_pm_ops,  #endif  	}, +	.probe		= i8042_probe,  	.remove		= i8042_remove,  	.shutdown	= i8042_shutdown,  }; @@ -1610,7 +1615,6 @@ static struct notifier_block i8042_kbd_bind_notifier_block = {  static int __init i8042_init(void)  { -	struct platform_device *pdev;  	int err;  	dbg_init(); @@ -1626,17 +1630,29 @@ static int __init i8042_init(void)  	/* Set this before creating the dev to allow i8042_command to work right away */  	i8042_present = true; -	pdev = platform_create_bundle(&i8042_driver, i8042_probe, NULL, 0, NULL, 0); -	if (IS_ERR(pdev)) { -		err = PTR_ERR(pdev); +	err = platform_driver_register(&i8042_driver); +	if (err)  		goto err_platform_exit; + +	i8042_platform_device = platform_device_alloc("i8042", -1); +	if (!i8042_platform_device) { +		err = -ENOMEM; +		goto err_unregister_driver;  	} +	err = platform_device_add(i8042_platform_device); +	if (err) +		goto err_free_device; +  	bus_register_notifier(&serio_bus, &i8042_kbd_bind_notifier_block);  	panic_blink = i8042_panic_blink;  	return 0; +err_free_device: +	platform_device_put(i8042_platform_device); +err_unregister_driver: +	platform_driver_unregister(&i8042_driver);   err_platform_exit:  	i8042_platform_exit();  	return err; diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 17eb8f2aa48d..669a728095b8 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -207,8 +207,8 @@ static void serport_set_type(struct tty_struct *tty, unsigned long type)   * serport_ldisc_ioctl() allows to set the port protocol, and device ID   */ -static int serport_ldisc_ioctl(struct tty_struct *tty, struct file *file, -			       unsigned int cmd, unsigned long arg) +static int serport_ldisc_ioctl(struct tty_struct *tty, unsigned int cmd, +			       unsigned long arg)  {  	if (cmd == SPIOCSTYPE) {  		unsigned long type; @@ -226,7 +226,6 @@ static int serport_ldisc_ioctl(struct tty_struct *tty, struct file *file,  #ifdef CONFIG_COMPAT  #define COMPAT_SPIOCSTYPE	_IOW('q', 0x01, compat_ulong_t)  static int serport_ldisc_compat_ioctl(struct tty_struct *tty, -				       struct file *file,  				       unsigned int cmd, unsigned long arg)  {  	if (cmd == COMPAT_SPIOCSTYPE) { diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 05de92c0293b..eb66cd2689b7 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1882,7 +1882,7 @@ static int mxt_read_info_block(struct mxt_data *data)  	if (error) {  		dev_err(&client->dev, "Error %d parsing object table\n", error);  		mxt_free_object_table(data); -		goto err_free_mem; +		return error;  	}  	data->object_table = (struct mxt_object *)(id_buf + MXT_OBJECT_START); diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index 7e13a66a8a95..879a4d984c90 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -117,6 +117,19 @@  #define ELAN_POWERON_DELAY_USEC	500  #define ELAN_RESET_DELAY_MSEC	20 +/* FW boot code version */ +#define BC_VER_H_BYTE_FOR_EKTH3900x1_I2C        0x72 +#define BC_VER_H_BYTE_FOR_EKTH3900x2_I2C        0x82 +#define BC_VER_H_BYTE_FOR_EKTH3900x3_I2C        0x92 +#define BC_VER_H_BYTE_FOR_EKTH5312x1_I2C        0x6D +#define BC_VER_H_BYTE_FOR_EKTH5312x2_I2C        0x6E +#define BC_VER_H_BYTE_FOR_EKTH5312cx1_I2C       0x77 +#define BC_VER_H_BYTE_FOR_EKTH5312cx2_I2C       0x78 +#define BC_VER_H_BYTE_FOR_EKTH5312x1_I2C_USB    0x67 +#define BC_VER_H_BYTE_FOR_EKTH5312x2_I2C_USB    0x68 +#define BC_VER_H_BYTE_FOR_EKTH5312cx1_I2C_USB   0x74 +#define BC_VER_H_BYTE_FOR_EKTH5312cx2_I2C_USB   0x75 +  enum elants_chip_id {  	EKTH3500,  	EKTF3624, @@ -736,6 +749,37 @@ static int elants_i2c_validate_remark_id(struct elants_data *ts,  	return 0;  } +static bool elants_i2c_should_check_remark_id(struct elants_data *ts) +{ +	struct i2c_client *client = ts->client; +	const u8 bootcode_version = ts->iap_version; +	bool check; + +	/* I2C eKTH3900 and eKTH5312 are NOT support Remark ID */ +	if ((bootcode_version == BC_VER_H_BYTE_FOR_EKTH3900x1_I2C) || +	    (bootcode_version == BC_VER_H_BYTE_FOR_EKTH3900x2_I2C) || +	    (bootcode_version == BC_VER_H_BYTE_FOR_EKTH3900x3_I2C) || +	    (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312x1_I2C) || +	    (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312x2_I2C) || +	    (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312cx1_I2C) || +	    (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312cx2_I2C) || +	    (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312x1_I2C_USB) || +	    (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312x2_I2C_USB) || +	    (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312cx1_I2C_USB) || +	    (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312cx2_I2C_USB)) { +		dev_dbg(&client->dev, +			"eKTH3900/eKTH5312(0x%02x) are not support remark id\n", +			bootcode_version); +		check = false; +	} else if (bootcode_version >= 0x60) { +		check = true; +	} else { +		check = false; +	} + +	return check; +} +  static int elants_i2c_do_update_firmware(struct i2c_client *client,  					 const struct firmware *fw,  					 bool force) @@ -749,7 +793,7 @@ static int elants_i2c_do_update_firmware(struct i2c_client *client,  	u16 send_id;  	int page, n_fw_pages;  	int error; -	bool check_remark_id = ts->iap_version >= 0x60; +	bool check_remark_id = elants_i2c_should_check_remark_id(ts);  	/* Recovery mode detection! */  	if (force) { diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index b5cc91788195..a3bfc7a41679 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -102,6 +102,7 @@ static const struct goodix_chip_id goodix_chip_ids[] = {  	{ .id = "911", .data = >911_chip_data },  	{ .id = "9271", .data = >911_chip_data },  	{ .id = "9110", .data = >911_chip_data }, +	{ .id = "9111", .data = >911_chip_data },  	{ .id = "927", .data = >911_chip_data },  	{ .id = "928", .data = >911_chip_data }, @@ -296,6 +297,108 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)  	return -ENOMSG;  } +static struct input_dev *goodix_create_pen_input(struct goodix_ts_data *ts) +{ +	struct device *dev = &ts->client->dev; +	struct input_dev *input; + +	input = devm_input_allocate_device(dev); +	if (!input) +		return NULL; + +	input_alloc_absinfo(input); +	if (!input->absinfo) { +		input_free_device(input); +		return NULL; +	} + +	input->absinfo[ABS_X] = ts->input_dev->absinfo[ABS_MT_POSITION_X]; +	input->absinfo[ABS_Y] = ts->input_dev->absinfo[ABS_MT_POSITION_Y]; +	__set_bit(ABS_X, input->absbit); +	__set_bit(ABS_Y, input->absbit); +	input_set_abs_params(input, ABS_PRESSURE, 0, 255, 0, 0); + +	input_set_capability(input, EV_KEY, BTN_TOUCH); +	input_set_capability(input, EV_KEY, BTN_TOOL_PEN); +	input_set_capability(input, EV_KEY, BTN_STYLUS); +	input_set_capability(input, EV_KEY, BTN_STYLUS2); +	__set_bit(INPUT_PROP_DIRECT, input->propbit); +	/* +	 * The resolution of these touchscreens is about 10 units/mm, the actual +	 * resolution does not matter much since we set INPUT_PROP_DIRECT. +	 * Userspace wants something here though, so just set it to 10 units/mm. +	 */ +	input_abs_set_res(input, ABS_X, 10); +	input_abs_set_res(input, ABS_Y, 10); + +	input->name = "Goodix Active Pen"; +	input->phys = "input/pen"; +	input->id.bustype = BUS_I2C; +	input->id.vendor = 0x0416; +	if (kstrtou16(ts->id, 10, &input->id.product)) +		input->id.product = 0x1001; +	input->id.version = ts->version; + +	if (input_register_device(input) != 0) { +		input_free_device(input); +		return NULL; +	} + +	return input; +} + +static void goodix_ts_report_pen_down(struct goodix_ts_data *ts, u8 *data) +{ +	int input_x, input_y, input_w; +	u8 key_value; + +	if (!ts->input_pen) { +		ts->input_pen = goodix_create_pen_input(ts); +		if (!ts->input_pen) +			return; +	} + +	if (ts->contact_size == 9) { +		input_x = get_unaligned_le16(&data[4]); +		input_y = get_unaligned_le16(&data[6]); +		input_w = get_unaligned_le16(&data[8]); +	} else { +		input_x = get_unaligned_le16(&data[2]); +		input_y = get_unaligned_le16(&data[4]); +		input_w = get_unaligned_le16(&data[6]); +	} + +	touchscreen_report_pos(ts->input_pen, &ts->prop, input_x, input_y, false); +	input_report_abs(ts->input_pen, ABS_PRESSURE, input_w); + +	input_report_key(ts->input_pen, BTN_TOUCH, 1); +	input_report_key(ts->input_pen, BTN_TOOL_PEN, 1); + +	if (data[0] & GOODIX_HAVE_KEY) { +		key_value = data[1 + ts->contact_size]; +		input_report_key(ts->input_pen, BTN_STYLUS, key_value & 0x10); +		input_report_key(ts->input_pen, BTN_STYLUS2, key_value & 0x20); +	} else { +		input_report_key(ts->input_pen, BTN_STYLUS, 0); +		input_report_key(ts->input_pen, BTN_STYLUS2, 0); +	} + +	input_sync(ts->input_pen); +} + +static void goodix_ts_report_pen_up(struct goodix_ts_data *ts) +{ +	if (!ts->input_pen) +		return; + +	input_report_key(ts->input_pen, BTN_TOUCH, 0); +	input_report_key(ts->input_pen, BTN_TOOL_PEN, 0); +	input_report_key(ts->input_pen, BTN_STYLUS, 0); +	input_report_key(ts->input_pen, BTN_STYLUS2, 0); + +	input_sync(ts->input_pen); +} +  static void goodix_ts_report_touch_8b(struct goodix_ts_data *ts, u8 *coor_data)  {  	int id = coor_data[0] & 0x0F; @@ -326,6 +429,14 @@ static void goodix_ts_report_touch_9b(struct goodix_ts_data *ts, u8 *coor_data)  	input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w);  } +static void goodix_ts_release_keys(struct goodix_ts_data *ts) +{ +	int i; + +	for (i = 0; i < GOODIX_MAX_KEYS; i++) +		input_report_key(ts->input_dev, ts->keymap[i], 0); +} +  static void goodix_ts_report_key(struct goodix_ts_data *ts, u8 *data)  {  	int touch_num; @@ -340,8 +451,7 @@ static void goodix_ts_report_key(struct goodix_ts_data *ts, u8 *data)  				input_report_key(ts->input_dev,  						 ts->keymap[i], 1);  	} else { -		for (i = 0; i < GOODIX_MAX_KEYS; i++) -			input_report_key(ts->input_dev, ts->keymap[i], 0); +		goodix_ts_release_keys(ts);  	}  } @@ -363,6 +473,15 @@ static void goodix_process_events(struct goodix_ts_data *ts)  	if (touch_num < 0)  		return; +	/* The pen being down is always reported as a single touch */ +	if (touch_num == 1 && (point_data[1] & 0x80)) { +		goodix_ts_report_pen_down(ts, point_data); +		goodix_ts_release_keys(ts); +		goto sync; /* Release any previously registered touches */ +	} else { +		goodix_ts_report_pen_up(ts); +	} +  	goodix_ts_report_key(ts, point_data);  	for (i = 0; i < touch_num; i++) @@ -373,6 +492,7 @@ static void goodix_process_events(struct goodix_ts_data *ts)  			goodix_ts_report_touch_8b(ts,  				&point_data[1 + ts->contact_size * i]); +sync:  	input_mt_sync_frame(ts->input_dev);  	input_sync(ts->input_dev);  } @@ -650,10 +770,16 @@ int goodix_reset_no_int_sync(struct goodix_ts_data *ts)  	usleep_range(6000, 10000);		/* T4: > 5ms */ -	/* end select I2C slave addr */ -	error = gpiod_direction_input(ts->gpiod_rst); -	if (error) -		goto error; +	/* +	 * Put the reset pin back in to input / high-impedance mode to save +	 * power. Only do this in the non ACPI case since some ACPI boards +	 * don't have a pull-up, so there the reset pin must stay active-high. +	 */ +	if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_GPIO) { +		error = gpiod_direction_input(ts->gpiod_rst); +		if (error) +			goto error; +	}  	return 0; @@ -787,6 +913,14 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)  		return -EINVAL;  	} +	/* +	 * Normally we put the reset pin in input / high-impedance mode to save +	 * power. But some x86/ACPI boards don't have a pull-up, so for the ACPI +	 * case, leave the pin as is. This results in the pin not being touched +	 * at all on x86/ACPI boards, except when needed for error-recover. +	 */ +	ts->gpiod_rst_flags = GPIOD_ASIS; +  	return devm_acpi_dev_add_driver_gpios(dev, gpio_mapping);  }  #else @@ -812,6 +946,12 @@ static int goodix_get_gpio_config(struct goodix_ts_data *ts)  		return -EINVAL;  	dev = &ts->client->dev; +	/* +	 * By default we request the reset pin as input, leaving it in +	 * high-impedance when not resetting the controller to save power. +	 */ +	ts->gpiod_rst_flags = GPIOD_IN; +  	ts->avdd28 = devm_regulator_get(dev, "AVDD28");  	if (IS_ERR(ts->avdd28)) {  		error = PTR_ERR(ts->avdd28); @@ -836,7 +976,7 @@ retry_get_irq_gpio:  	if (IS_ERR(gpiod)) {  		error = PTR_ERR(gpiod);  		if (error != -EPROBE_DEFER) -			dev_dbg(dev, "Failed to get %s GPIO: %d\n", +			dev_err(dev, "Failed to get %s GPIO: %d\n",  				GOODIX_GPIO_INT_NAME, error);  		return error;  	} @@ -849,11 +989,11 @@ retry_get_irq_gpio:  	ts->gpiod_int = gpiod;  	/* Get the reset line GPIO pin number */ -	gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, GPIOD_IN); +	gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, ts->gpiod_rst_flags);  	if (IS_ERR(gpiod)) {  		error = PTR_ERR(gpiod);  		if (error != -EPROBE_DEFER) -			dev_dbg(dev, "Failed to get %s GPIO: %d\n", +			dev_err(dev, "Failed to get %s GPIO: %d\n",  				GOODIX_GPIO_RST_NAME, error);  		return error;  	} diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h index 62138f930d1a..fa8602e78a64 100644 --- a/drivers/input/touchscreen/goodix.h +++ b/drivers/input/touchscreen/goodix.h @@ -76,6 +76,7 @@ struct goodix_chip_data {  struct goodix_ts_data {  	struct i2c_client *client;  	struct input_dev *input_dev; +	struct input_dev *input_pen;  	const struct goodix_chip_data *chip;  	const char *firmware_name;  	struct touchscreen_properties prop; @@ -87,6 +88,7 @@ struct goodix_ts_data {  	struct gpio_desc *gpiod_rst;  	int gpio_count;  	int gpio_int_idx; +	enum gpiod_flags gpiod_rst_flags;  	char id[GOODIX_ID_MAX_LEN + 1];  	char cfg_name[64];  	u16 version; diff --git a/drivers/input/touchscreen/goodix_fwupload.c b/drivers/input/touchscreen/goodix_fwupload.c index c1e7a2413078..191d4f38d991 100644 --- a/drivers/input/touchscreen/goodix_fwupload.c +++ b/drivers/input/touchscreen/goodix_fwupload.c @@ -207,7 +207,7 @@ static int goodix_firmware_upload(struct goodix_ts_data *ts)  	error = goodix_reset_no_int_sync(ts);  	if (error) -		return error; +		goto release;  	error = goodix_enter_upload_mode(ts->client);  	if (error) diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c index 1ee760bac0cf..3eef8c01090f 100644 --- a/drivers/input/touchscreen/silead.c +++ b/drivers/input/touchscreen/silead.c @@ -67,6 +67,7 @@ struct silead_ts_data {  	struct i2c_client *client;  	struct gpio_desc *gpio_power;  	struct input_dev *input; +	struct input_dev *pen_input;  	struct regulator_bulk_data regulators[2];  	char fw_name[64];  	struct touchscreen_properties prop; @@ -75,6 +76,13 @@ struct silead_ts_data {  	struct input_mt_pos pos[SILEAD_MAX_FINGERS];  	int slots[SILEAD_MAX_FINGERS];  	int id[SILEAD_MAX_FINGERS]; +	u32 efi_fw_min_max[4]; +	bool efi_fw_min_max_set; +	bool pen_supported; +	bool pen_down; +	u32 pen_x_res; +	u32 pen_y_res; +	int pen_up_count;  };  struct silead_fw_data { @@ -82,6 +90,35 @@ struct silead_fw_data {  	u32 val;  }; +static void silead_apply_efi_fw_min_max(struct silead_ts_data *data) +{ +	struct input_absinfo *absinfo_x = &data->input->absinfo[ABS_MT_POSITION_X]; +	struct input_absinfo *absinfo_y = &data->input->absinfo[ABS_MT_POSITION_Y]; + +	if (!data->efi_fw_min_max_set) +		return; + +	absinfo_x->minimum = data->efi_fw_min_max[0]; +	absinfo_x->maximum = data->efi_fw_min_max[1]; +	absinfo_y->minimum = data->efi_fw_min_max[2]; +	absinfo_y->maximum = data->efi_fw_min_max[3]; + +	if (data->prop.invert_x) { +		absinfo_x->maximum -= absinfo_x->minimum; +		absinfo_x->minimum = 0; +	} + +	if (data->prop.invert_y) { +		absinfo_y->maximum -= absinfo_y->minimum; +		absinfo_y->minimum = 0; +	} + +	if (data->prop.swap_x_y) { +		swap(absinfo_x->minimum, absinfo_y->minimum); +		swap(absinfo_x->maximum, absinfo_y->maximum); +	} +} +  static int silead_ts_request_input_dev(struct silead_ts_data *data)  {  	struct device *dev = &data->client->dev; @@ -97,6 +134,7 @@ static int silead_ts_request_input_dev(struct silead_ts_data *data)  	input_set_abs_params(data->input, ABS_MT_POSITION_X, 0, 4095, 0, 0);  	input_set_abs_params(data->input, ABS_MT_POSITION_Y, 0, 4095, 0, 0);  	touchscreen_parse_properties(data->input, true, &data->prop); +	silead_apply_efi_fw_min_max(data);  	input_mt_init_slots(data->input, data->max_fingers,  			    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED | @@ -112,6 +150,40 @@ static int silead_ts_request_input_dev(struct silead_ts_data *data)  	error = input_register_device(data->input);  	if (error) {  		dev_err(dev, "Failed to register input device: %d\n", error); +			return error; +	} + +	return 0; +} + +static int silead_ts_request_pen_input_dev(struct silead_ts_data *data) +{ +	struct device *dev = &data->client->dev; +	int error; + +	if (!data->pen_supported) +		return 0; + +	data->pen_input = devm_input_allocate_device(dev); +	if (!data->pen_input) +		return -ENOMEM; + +	input_set_abs_params(data->pen_input, ABS_X, 0, 4095, 0, 0); +	input_set_abs_params(data->pen_input, ABS_Y, 0, 4095, 0, 0); +	input_set_capability(data->pen_input, EV_KEY, BTN_TOUCH); +	input_set_capability(data->pen_input, EV_KEY, BTN_TOOL_PEN); +	set_bit(INPUT_PROP_DIRECT, data->pen_input->propbit); +	touchscreen_parse_properties(data->pen_input, false, &data->prop); +	input_abs_set_res(data->pen_input, ABS_X, data->pen_x_res); +	input_abs_set_res(data->pen_input, ABS_Y, data->pen_y_res); + +	data->pen_input->name = SILEAD_TS_NAME " pen"; +	data->pen_input->phys = "input/pen"; +	data->input->id.bustype = BUS_I2C; + +	error = input_register_device(data->pen_input); +	if (error) { +		dev_err(dev, "Failed to register pen input device: %d\n", error);  		return error;  	} @@ -129,6 +201,45 @@ static void silead_ts_set_power(struct i2c_client *client,  	}  } +static bool silead_ts_handle_pen_data(struct silead_ts_data *data, u8 *buf) +{ +	u8 *coord = buf + SILEAD_POINT_DATA_LEN; +	struct input_mt_pos pos; + +	if (!data->pen_supported || buf[2] != 0x00 || buf[3] != 0x00) +		return false; + +	if (buf[0] == 0x00 && buf[1] == 0x00 && data->pen_down) { +		data->pen_up_count++; +		if (data->pen_up_count == 6) { +			data->pen_down = false; +			goto sync; +		} +		return true; +	} + +	if (buf[0] == 0x01 && buf[1] == 0x08) { +		touchscreen_set_mt_pos(&pos, &data->prop, +			get_unaligned_le16(&coord[SILEAD_POINT_X_OFF]) & 0xfff, +			get_unaligned_le16(&coord[SILEAD_POINT_Y_OFF]) & 0xfff); + +		input_report_abs(data->pen_input, ABS_X, pos.x); +		input_report_abs(data->pen_input, ABS_Y, pos.y); + +		data->pen_up_count = 0; +		data->pen_down = true; +		goto sync; +	} + +	return false; + +sync: +	input_report_key(data->pen_input, BTN_TOOL_PEN, data->pen_down); +	input_report_key(data->pen_input, BTN_TOUCH, data->pen_down); +	input_sync(data->pen_input); +	return true; +} +  static void silead_ts_read_data(struct i2c_client *client)  {  	struct silead_ts_data *data = i2c_get_clientdata(client); @@ -151,6 +262,9 @@ static void silead_ts_read_data(struct i2c_client *client)  		buf[0] = data->max_fingers;  	} +	if (silead_ts_handle_pen_data(data, buf)) +		goto sync; /* Pen is down, release all previous touches */ +  	touch_nr = 0;  	bufp = buf + SILEAD_POINT_DATA_LEN;  	for (i = 0; i < buf[0]; i++, bufp += SILEAD_POINT_DATA_LEN) { @@ -193,6 +307,7 @@ static void silead_ts_read_data(struct i2c_client *client)  			data->pos[i].y, data->id[i], data->slots[i]);  	} +sync:  	input_mt_sync_frame(input);  	input_report_key(input, KEY_LEFTMETA, softbutton_pressed);  	input_sync(input); @@ -282,17 +397,56 @@ static int silead_ts_load_fw(struct i2c_client *client)  {  	struct device *dev = &client->dev;  	struct silead_ts_data *data = i2c_get_clientdata(client); -	unsigned int fw_size, i; -	const struct firmware *fw; +	const struct firmware *fw = NULL;  	struct silead_fw_data *fw_data; +	unsigned int fw_size, i;  	int error;  	dev_dbg(dev, "Firmware file name: %s", data->fw_name); -	error = firmware_request_platform(&fw, data->fw_name, dev); +	/* +	 * Unfortunately, at the time of writing this comment, we have been unable to +	 * get permission from Silead, or from device OEMs, to distribute the necessary +	 * Silead firmware files in linux-firmware. +	 * +	 * On a whole bunch of devices the UEFI BIOS code contains a touchscreen driver, +	 * which contains an embedded copy of the firmware. The fw-loader code has a +	 * "platform" fallback mechanism, which together with info on the firmware +	 * from drivers/platform/x86/touchscreen_dmi.c will use the firmware from the +	 * UEFI driver when the firmware is missing from /lib/firmware. This makes the +	 * touchscreen work OOTB without users needing to manually download the firmware. +	 * +	 * The firmware bundled with the original Windows/Android is usually newer then +	 * the firmware in the UEFI driver and it is better calibrated. This better +	 * calibration can lead to significant differences in the reported min/max +	 * coordinates. +	 * +	 * To deal with this we first try to load the firmware without "platform" +	 * fallback. If that fails we retry with "platform" fallback and if that +	 * succeeds we apply an (optional) set of alternative min/max values from the +	 * "silead,efi-fw-min-max" property. +	 */ +	error = firmware_request_nowarn(&fw, data->fw_name, dev);  	if (error) { -		dev_err(dev, "Firmware request error %d\n", error); -		return error; +		error = firmware_request_platform(&fw, data->fw_name, dev); +		if (error) { +			dev_err(dev, "Firmware request error %d\n", error); +			return error; +		} + +		error = device_property_read_u32_array(dev, "silead,efi-fw-min-max", +						       data->efi_fw_min_max, +						       ARRAY_SIZE(data->efi_fw_min_max)); +		if (!error) +			data->efi_fw_min_max_set = true; + +		/* The EFI (platform) embedded fw does not have pen support */ +		if (data->pen_supported) { +			dev_warn(dev, "Warning loading '%s' from filesystem failed, using EFI embedded copy.\n", +				 data->fw_name); +			dev_warn(dev, "Warning pen support is known to be broken in the EFI embedded fw version\n"); +			data->pen_supported = false; +		}  	}  	fw_size = fw->size / sizeof(*fw_data); @@ -450,6 +604,10 @@ static void silead_ts_read_props(struct i2c_client *client)  			 "silead/%s", str);  	else  		dev_dbg(dev, "Firmware file name read error. Using default."); + +	data->pen_supported = device_property_read_bool(dev, "silead,pen-supported"); +	device_property_read_u32(dev, "silead,pen-resolution-x", &data->pen_x_res); +	device_property_read_u32(dev, "silead,pen-resolution-y", &data->pen_y_res);  }  #ifdef CONFIG_ACPI @@ -562,6 +720,10 @@ static int silead_ts_probe(struct i2c_client *client,  	if (error)  		return error; +	error = silead_ts_request_pen_input_dev(data); +	if (error) +		return error; +  	error = devm_request_threaded_irq(dev, client->irq,  					  NULL, silead_ts_threaded_irq_handler,  					  IRQF_ONESHOT, client->name, data); diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index 83e685557a19..f2fb6a9a1a57 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c @@ -126,12 +126,13 @@ static int titsc_config_wires(struct titsc *ts_dev)  static void titsc_step_config(struct titsc *ts_dev)  {  	unsigned int	config; -	int i; +	int i, n;  	int end_step, first_step, tsc_steps;  	u32 stepenable;  	config = STEPCONFIG_MODE_HWSYNC | -			STEPCONFIG_AVG_16 | ts_dev->bit_xp; +			STEPCONFIG_AVG_16 | ts_dev->bit_xp | +			STEPCONFIG_INM_ADCREFM;  	switch (ts_dev->wires) {  	case 4:  		config |= STEPCONFIG_INP(ts_dev->inp_yp) | ts_dev->bit_xn; @@ -150,9 +151,11 @@ static void titsc_step_config(struct titsc *ts_dev)  	first_step = TOTAL_STEPS - tsc_steps;  	/* Steps 16 to 16-coordinate_readouts is for X */  	end_step = first_step + tsc_steps; +	n = 0;  	for (i = end_step - ts_dev->coordinate_readouts; i < end_step; i++) {  		titsc_writel(ts_dev, REG_STEPCONFIG(i), config); -		titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); +		titsc_writel(ts_dev, REG_STEPDELAY(i), +			     n++ == 0 ? STEPCONFIG_OPENDLY : 0);  	}  	config = 0; @@ -174,9 +177,11 @@ static void titsc_step_config(struct titsc *ts_dev)  	/* 1 ... coordinate_readouts is for Y */  	end_step = first_step + ts_dev->coordinate_readouts; +	n = 0;  	for (i = first_step; i < end_step; i++) {  		titsc_writel(ts_dev, REG_STEPCONFIG(i), config); -		titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); +		titsc_writel(ts_dev, REG_STEPDELAY(i), +			     n++ == 0 ? STEPCONFIG_OPENDLY : 0);  	}  	/* Make CHARGECONFIG same as IDLECONFIG */ @@ -195,7 +200,10 @@ static void titsc_step_config(struct titsc *ts_dev)  			STEPCONFIG_OPENDLY);  	end_step++; -	config |= STEPCONFIG_INP(ts_dev->inp_yn); +	config = STEPCONFIG_MODE_HWSYNC | +			STEPCONFIG_AVG_16 | ts_dev->bit_yp | +			ts_dev->bit_xn | STEPCONFIG_INM_ADCREFM | +			STEPCONFIG_INP(ts_dev->inp_yn);  	titsc_writel(ts_dev, REG_STEPCONFIG(end_step), config);  	titsc_writel(ts_dev, REG_STEPDELAY(end_step),  			STEPCONFIG_OPENDLY); @@ -310,7 +318,7 @@ static irqreturn_t titsc_irq(int irq, void *dev)  			/*  			 * Calculate pressure using formula  			 * Resistance(touch) = x plate resistance * -			 * x postion/4096 * ((z2 / z1) - 1) +			 * x position/4096 * ((z2 / z1) - 1)  			 */  			z = z1 - z2;  			z *= x; diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index e3f2c940ef3d..dfd3b35590c3 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -186,7 +186,6 @@ static irqreturn_t ucb1400_irq(int irqnr, void *devid)  {  	struct ucb1400_ts *ucb = devid;  	unsigned int x, y, p; -	bool penup;  	if (unlikely(irqnr != ucb->irq))  		return IRQ_NONE; @@ -196,8 +195,7 @@ static irqreturn_t ucb1400_irq(int irqnr, void *devid)  	/* Start with a small delay before checking pendown state */  	msleep(UCB1400_TS_POLL_PERIOD); -	while (!ucb->stopped && !(penup = ucb1400_ts_pen_up(ucb))) { - +	while (!ucb->stopped && !ucb1400_ts_pen_up(ucb)) {  		ucb1400_adc_enable(ucb->ac97);  		x = ucb1400_ts_read_xpos(ucb);  		y = ucb1400_ts_read_ypos(ucb); diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c index fe4ea6204a4e..141754b2764c 100644 --- a/drivers/input/touchscreen/wacom_i2c.c +++ b/drivers/input/touchscreen/wacom_i2c.c @@ -24,12 +24,19 @@  #define WACOM_IN_PROXIMITY	BIT(5)  /* Registers */ -#define WACOM_CMD_QUERY0	0x04 -#define WACOM_CMD_QUERY1	0x00 -#define WACOM_CMD_QUERY2	0x33 -#define WACOM_CMD_QUERY3	0x02 -#define WACOM_CMD_THROW0	0x05 -#define WACOM_CMD_THROW1	0x00 +#define WACOM_COMMAND_LSB	0x04 +#define WACOM_COMMAND_MSB	0x00 + +#define WACOM_DATA_LSB		0x05 +#define WACOM_DATA_MSB		0x00 + +/* Report types */ +#define REPORT_FEATURE		0x30 + +/* Requests / operations */ +#define OPCODE_GET_REPORT	0x02 + +#define WACOM_QUERY_REPORT	3  #define WACOM_QUERY_SIZE	19  struct wacom_features { @@ -50,23 +57,24 @@ struct wacom_i2c {  static int wacom_query_device(struct i2c_client *client,  			      struct wacom_features *features)  { -	int ret; -	u8 cmd1[] = { WACOM_CMD_QUERY0, WACOM_CMD_QUERY1, -			WACOM_CMD_QUERY2, WACOM_CMD_QUERY3 }; -	u8 cmd2[] = { WACOM_CMD_THROW0, WACOM_CMD_THROW1 }; +	u8 get_query_data_cmd[] = { +		WACOM_COMMAND_LSB, +		WACOM_COMMAND_MSB, +		REPORT_FEATURE | WACOM_QUERY_REPORT, +		OPCODE_GET_REPORT, +		WACOM_DATA_LSB, +		WACOM_DATA_MSB, +	};  	u8 data[WACOM_QUERY_SIZE]; +	int ret; +  	struct i2c_msg msgs[] = { +		/* Request reading of feature ReportID: 3 (Pen Query Data) */  		{  			.addr = client->addr,  			.flags = 0, -			.len = sizeof(cmd1), -			.buf = cmd1, -		}, -		{ -			.addr = client->addr, -			.flags = 0, -			.len = sizeof(cmd2), -			.buf = cmd2, +			.len = sizeof(get_query_data_cmd), +			.buf = get_query_data_cmd,  		},  		{  			.addr = client->addr, diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c index b8d901099378..7c82c4f5fa6b 100644 --- a/drivers/input/touchscreen/zinitix.c +++ b/drivers/input/touchscreen/zinitix.c @@ -252,16 +252,27 @@ static int zinitix_init_touch(struct bt541_ts_data *bt541)  static int zinitix_init_regulators(struct bt541_ts_data *bt541)  { -	struct i2c_client *client = bt541->client; +	struct device *dev = &bt541->client->dev;  	int error; -	bt541->supplies[0].supply = "vdd"; -	bt541->supplies[1].supply = "vddo"; -	error = devm_regulator_bulk_get(&client->dev, +	/* +	 * Some older device trees have erroneous names for the regulators, +	 * so check if "vddo" is present and in that case use these names. +	 * Else use the proper supply names on the component. +	 */ +	if (of_find_property(dev->of_node, "vddo-supply", NULL)) { +		bt541->supplies[0].supply = "vdd"; +		bt541->supplies[1].supply = "vddo"; +	} else { +		/* Else use the proper supply names */ +		bt541->supplies[0].supply = "vcca"; +		bt541->supplies[1].supply = "vdd"; +	} +	error = devm_regulator_bulk_get(dev,  					ARRAY_SIZE(bt541->supplies),  					bt541->supplies);  	if (error < 0) { -		dev_err(&client->dev, "Failed to get regulators: %d\n", error); +		dev_err(dev, "Failed to get regulators: %d\n", error);  		return error;  	} @@ -488,6 +499,15 @@ static int zinitix_ts_probe(struct i2c_client *client)  		return error;  	} +	error = devm_request_threaded_irq(&client->dev, client->irq, +					  NULL, zinitix_ts_irq_handler, +					  IRQF_ONESHOT | IRQF_NO_AUTOEN, +					  client->name, bt541); +	if (error) { +		dev_err(&client->dev, "Failed to request IRQ: %d\n", error); +		return error; +	} +  	error = zinitix_init_input_dev(bt541);  	if (error) {  		dev_err(&client->dev, @@ -513,15 +533,6 @@ static int zinitix_ts_probe(struct i2c_client *client)  		return -EINVAL;  	} -	error = devm_request_threaded_irq(&client->dev, client->irq, -					  NULL, zinitix_ts_irq_handler, -					  IRQF_ONESHOT | IRQF_NO_AUTOEN, -					  client->name, bt541); -	if (error) { -		dev_err(&client->dev, "Failed to request IRQ: %d\n", error); -		return error; -	} -  	return 0;  } @@ -560,6 +571,7 @@ static SIMPLE_DEV_PM_OPS(zinitix_pm_ops, zinitix_suspend, zinitix_resume);  #ifdef CONFIG_OF  static const struct of_device_id zinitix_of_match[] = { +	{ .compatible = "zinitix,bt532" },  	{ .compatible = "zinitix,bt541" },  	{ }  }; |