diff options
Diffstat (limited to 'drivers/input')
235 files changed, 7718 insertions, 3706 deletions
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 38b523a1ece..a11ff74a512 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -80,7 +80,7 @@ config INPUT_MATRIXKMAP  comment "Userland interfaces"  config INPUT_MOUSEDEV -	tristate "Mouse interface" if EXPERT +	tristate "Mouse interface"  	default y  	help  	  Say Y here if you want your mouse to be accessible as char devices diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index b6ded17b3be..fd325ec9f06 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -18,6 +18,8 @@  #include <linux/poll.h>  #include <linux/sched.h>  #include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/mm.h>  #include <linux/module.h>  #include <linux/init.h>  #include <linux/input/mt.h> @@ -369,7 +371,11 @@ static int evdev_release(struct inode *inode, struct file *file)  	mutex_unlock(&evdev->mutex);  	evdev_detach_client(evdev, client); -	kfree(client); + +	if (is_vmalloc_addr(client)) +		vfree(client); +	else +		kfree(client);  	evdev_close_device(evdev); @@ -389,12 +395,14 @@ static int evdev_open(struct inode *inode, struct file *file)  {  	struct evdev *evdev = container_of(inode->i_cdev, struct evdev, cdev);  	unsigned int bufsize = evdev_compute_buffer_size(evdev->handle.dev); +	unsigned int size = sizeof(struct evdev_client) + +					bufsize * sizeof(struct input_event);  	struct evdev_client *client;  	int error; -	client = kzalloc(sizeof(struct evdev_client) + -				bufsize * sizeof(struct input_event), -			 GFP_KERNEL); +	client = kzalloc(size, GFP_KERNEL | __GFP_NOWARN); +	if (!client) +		client = vzalloc(size);  	if (!client)  		return -ENOMEM; @@ -621,12 +629,10 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p)  	return copy_to_user(p, str, len) ? -EFAULT : len;  } -#define OLD_KEY_MAX	0x1ff  static int handle_eviocgbit(struct input_dev *dev,  			    unsigned int type, unsigned int size,  			    void __user *p, int compat_mode)  { -	static unsigned long keymax_warn_time;  	unsigned long *bits;  	int len; @@ -644,24 +650,8 @@ static int handle_eviocgbit(struct input_dev *dev,  	default: return -EINVAL;  	} -	/* -	 * Work around bugs in userspace programs that like to do -	 * EVIOCGBIT(EV_KEY, KEY_MAX) and not realize that 'len' -	 * should be in bytes, not in bits. -	 */ -	if (type == EV_KEY && size == OLD_KEY_MAX) { -		len = OLD_KEY_MAX; -		if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000)) -			pr_warning("(EVIOCGBIT): Suspicious buffer size %u, " -				   "limiting output to %zu bytes. See " -				   "http://userweb.kernel.org/~dtor/eviocgbit-bug.html\n", -				   OLD_KEY_MAX, -				   BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long)); -	} -  	return bits_to_user(bits, len, size, p, compat_mode);  } -#undef OLD_KEY_MAX  static int evdev_handle_get_keycode(struct input_dev *dev, void __user *p)  { @@ -946,11 +936,13 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,  			return -EFAULT;  		error = input_ff_upload(dev, &effect, file); +		if (error) +			return error;  		if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))  			return -EFAULT; -		return error; +		return 0;  	}  	/* Multi-number variable-length handlers */ diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c index fa7a95c1da0..2909e9561cf 100644 --- a/drivers/input/gameport/emu10k1-gp.c +++ b/drivers/input/gameport/emu10k1-gp.c @@ -30,7 +30,6 @@  #include <linux/module.h>  #include <linux/ioport.h> -#include <linux/init.h>  #include <linux/gameport.h>  #include <linux/slab.h>  #include <linux/pci.h> diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c index ae912d3aee4..7c03114158e 100644 --- a/drivers/input/gameport/fm801-gp.c +++ b/drivers/input/gameport/fm801-gp.c @@ -27,7 +27,6 @@  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/pci.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/gameport.h> diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 922a7fea2ce..24c41ba7d4e 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -422,14 +422,15 @@ static struct gameport *gameport_get_pending_child(struct gameport *parent)   * Gameport port operations   */ -static ssize_t gameport_show_description(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t gameport_description_show(struct device *dev, struct device_attribute *attr, char *buf)  {  	struct gameport *gameport = to_gameport_port(dev);  	return sprintf(buf, "%s\n", gameport->name);  } +static DEVICE_ATTR(description, S_IRUGO, gameport_description_show, NULL); -static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t drvctl_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)  {  	struct gameport *gameport = to_gameport_port(dev);  	struct device_driver *drv; @@ -457,12 +458,14 @@ static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribut  	return error ? error : count;  } +static DEVICE_ATTR_WO(drvctl); -static struct device_attribute gameport_device_attrs[] = { -	__ATTR(description, S_IRUGO, gameport_show_description, NULL), -	__ATTR(drvctl, S_IWUSR, NULL, gameport_rebind_driver), -	__ATTR_NULL +static struct attribute *gameport_device_attrs[] = { +	&dev_attr_description.attr, +	&dev_attr_drvctl.attr, +	NULL,  }; +ATTRIBUTE_GROUPS(gameport_device);  static void gameport_release_port(struct device *dev)  { @@ -750,7 +753,7 @@ static int gameport_bus_match(struct device *dev, struct device_driver *drv)  static struct bus_type gameport_bus = {  	.name		= "gameport", -	.dev_attrs	= gameport_device_attrs, +	.dev_groups	= gameport_device_groups,  	.drv_groups	= gameport_driver_groups,  	.match		= gameport_bus_match,  	.probe		= gameport_driver_probe, diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c index 7f161d93203..3664f81655c 100644 --- a/drivers/input/input-polldev.c +++ b/drivers/input/input-polldev.c @@ -147,6 +147,11 @@ static struct attribute_group input_polldev_attribute_group = {  	.attrs = sysfs_attrs  }; +static const struct attribute_group *input_polldev_attribute_groups[] = { +	&input_polldev_attribute_group, +	NULL +}; +  /**   * input_allocate_polled_device - allocate memory for polled device   * @@ -171,6 +176,91 @@ struct input_polled_dev *input_allocate_polled_device(void)  }  EXPORT_SYMBOL(input_allocate_polled_device); +struct input_polled_devres { +	struct input_polled_dev *polldev; +}; + +static int devm_input_polldev_match(struct device *dev, void *res, void *data) +{ +	struct input_polled_devres *devres = res; + +	return devres->polldev == data; +} + +static void devm_input_polldev_release(struct device *dev, void *res) +{ +	struct input_polled_devres *devres = res; +	struct input_polled_dev *polldev = devres->polldev; + +	dev_dbg(dev, "%s: dropping reference/freeing %s\n", +		__func__, dev_name(&polldev->input->dev)); + +	input_put_device(polldev->input); +	kfree(polldev); +} + +static void devm_input_polldev_unregister(struct device *dev, void *res) +{ +	struct input_polled_devres *devres = res; +	struct input_polled_dev *polldev = devres->polldev; + +	dev_dbg(dev, "%s: unregistering device %s\n", +		__func__, dev_name(&polldev->input->dev)); +	input_unregister_device(polldev->input); + +	/* +	 * Note that we are still holding extra reference to the input +	 * device so it will stick around until devm_input_polldev_release() +	 * is called. +	 */ +} + +/** + * devm_input_allocate_polled_device - allocate managed polled device + * @dev: device owning the polled device being created + * + * Returns prepared &struct input_polled_dev or %NULL. + * + * Managed polled input devices do not need to be explicitly unregistered + * or freed as it will be done automatically when owner device unbinds + * from * its driver (or binding fails). Once such managed polled device + * is allocated, it is ready to be set up and registered in the same + * fashion as regular polled input devices (using + * input_register_polled_device() function). + * + * If you want to manually unregister and free such managed polled devices, + * it can be still done by calling input_unregister_polled_device() and + * input_free_polled_device(), although it is rarely needed. + * + * NOTE: the owner device is set up as parent of input device and users + * should not override it. + */ +struct input_polled_dev *devm_input_allocate_polled_device(struct device *dev) +{ +	struct input_polled_dev *polldev; +	struct input_polled_devres *devres; + +	devres = devres_alloc(devm_input_polldev_release, sizeof(*devres), +			      GFP_KERNEL); +	if (!devres) +		return NULL; + +	polldev = input_allocate_polled_device(); +	if (!polldev) { +		devres_free(devres); +		return NULL; +	} + +	polldev->input->dev.parent = dev; +	polldev->devres_managed = true; + +	devres->polldev = polldev; +	devres_add(dev, devres); + +	return polldev; +} +EXPORT_SYMBOL(devm_input_allocate_polled_device); +  /**   * input_free_polled_device - free memory allocated for polled device   * @dev: device to free @@ -181,7 +271,12 @@ EXPORT_SYMBOL(input_allocate_polled_device);  void input_free_polled_device(struct input_polled_dev *dev)  {  	if (dev) { -		input_free_device(dev->input); +		if (dev->devres_managed) +			WARN_ON(devres_destroy(dev->input->dev.parent, +						devm_input_polldev_release, +						devm_input_polldev_match, +						dev)); +		input_put_device(dev->input);  		kfree(dev);  	}  } @@ -199,26 +294,35 @@ EXPORT_SYMBOL(input_free_polled_device);   */  int input_register_polled_device(struct input_polled_dev *dev)  { +	struct input_polled_devres *devres = NULL;  	struct input_dev *input = dev->input;  	int error; +	if (dev->devres_managed) { +		devres = devres_alloc(devm_input_polldev_unregister, +				      sizeof(*devres), GFP_KERNEL); +		if (!devres) +			return -ENOMEM; + +		devres->polldev = dev; +	} +  	input_set_drvdata(input, dev);  	INIT_DELAYED_WORK(&dev->work, input_polled_device_work); +  	if (!dev->poll_interval)  		dev->poll_interval = 500;  	if (!dev->poll_interval_max)  		dev->poll_interval_max = dev->poll_interval; +  	input->open = input_open_polled_device;  	input->close = input_close_polled_device; -	error = input_register_device(input); -	if (error) -		return error; +	input->dev.groups = input_polldev_attribute_groups; -	error = sysfs_create_group(&input->dev.kobj, -				   &input_polldev_attribute_group); +	error = input_register_device(input);  	if (error) { -		input_unregister_device(input); +		devres_free(devres);  		return error;  	} @@ -231,6 +335,12 @@ int input_register_polled_device(struct input_polled_dev *dev)  	 */  	input_get_device(input); +	if (dev->devres_managed) { +		dev_dbg(input->dev.parent, "%s: registering %s with devres.\n", +			__func__, dev_name(&input->dev)); +		devres_add(input->dev.parent, devres); +	} +  	return 0;  }  EXPORT_SYMBOL(input_register_polled_device); @@ -245,8 +355,11 @@ EXPORT_SYMBOL(input_register_polled_device);   */  void input_unregister_polled_device(struct input_polled_dev *dev)  { -	sysfs_remove_group(&dev->input->dev.kobj, -			   &input_polldev_attribute_group); +	if (dev->devres_managed) +		WARN_ON(devres_destroy(dev->input->dev.parent, +					devm_input_polldev_unregister, +					devm_input_polldev_match, +					dev));  	input_unregister_device(dev->input);  } diff --git a/drivers/input/input.c b/drivers/input/input.c index c0446992892..29ca0bb4f56 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -257,9 +257,10 @@ static int input_handle_abs_event(struct input_dev *dev,  }  static int input_get_disposition(struct input_dev *dev, -			  unsigned int type, unsigned int code, int value) +			  unsigned int type, unsigned int code, int *pval)  {  	int disposition = INPUT_IGNORE_EVENT; +	int value = *pval;  	switch (type) { @@ -357,6 +358,7 @@ static int input_get_disposition(struct input_dev *dev,  		break;  	} +	*pval = value;  	return disposition;  } @@ -365,7 +367,7 @@ static void input_handle_event(struct input_dev *dev,  {  	int disposition; -	disposition = input_get_disposition(dev, type, code, value); +	disposition = input_get_disposition(dev, type, code, &value);  	if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)  		dev->event(dev, type, code, value); @@ -1653,35 +1655,36 @@ static void input_dev_toggle(struct input_dev *dev, bool activate)   */  void input_reset_device(struct input_dev *dev)  { -	mutex_lock(&dev->mutex); +	unsigned long flags; -	if (dev->users) { -		input_dev_toggle(dev, true); +	mutex_lock(&dev->mutex); +	spin_lock_irqsave(&dev->event_lock, flags); -		/* -		 * Keys that have been pressed at suspend time are unlikely -		 * to be still pressed when we resume. -		 */ -		spin_lock_irq(&dev->event_lock); -		input_dev_release_keys(dev); -		spin_unlock_irq(&dev->event_lock); -	} +	input_dev_toggle(dev, true); +	input_dev_release_keys(dev); +	spin_unlock_irqrestore(&dev->event_lock, flags);  	mutex_unlock(&dev->mutex);  }  EXPORT_SYMBOL(input_reset_device); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int input_dev_suspend(struct device *dev)  {  	struct input_dev *input_dev = to_input_dev(dev); -	mutex_lock(&input_dev->mutex); +	spin_lock_irq(&input_dev->event_lock); + +	/* +	 * Keys that are pressed now are unlikely to be +	 * still pressed when we resume. +	 */ +	input_dev_release_keys(input_dev); -	if (input_dev->users) -		input_dev_toggle(input_dev, false); +	/* Turn off LEDs and sounds, if any are active. */ +	input_dev_toggle(input_dev, false); -	mutex_unlock(&input_dev->mutex); +	spin_unlock_irq(&input_dev->event_lock);  	return 0;  } @@ -1690,7 +1693,43 @@ static int input_dev_resume(struct device *dev)  {  	struct input_dev *input_dev = to_input_dev(dev); -	input_reset_device(input_dev); +	spin_lock_irq(&input_dev->event_lock); + +	/* Restore state of LEDs and sounds, if any were active. */ +	input_dev_toggle(input_dev, true); + +	spin_unlock_irq(&input_dev->event_lock); + +	return 0; +} + +static int input_dev_freeze(struct device *dev) +{ +	struct input_dev *input_dev = to_input_dev(dev); + +	spin_lock_irq(&input_dev->event_lock); + +	/* +	 * Keys that are pressed now are unlikely to be +	 * still pressed when we resume. +	 */ +	input_dev_release_keys(input_dev); + +	spin_unlock_irq(&input_dev->event_lock); + +	return 0; +} + +static int input_dev_poweroff(struct device *dev) +{ +	struct input_dev *input_dev = to_input_dev(dev); + +	spin_lock_irq(&input_dev->event_lock); + +	/* Turn off LEDs and sounds, if any are active. */ +	input_dev_toggle(input_dev, false); + +	spin_unlock_irq(&input_dev->event_lock);  	return 0;  } @@ -1698,7 +1737,8 @@ static int input_dev_resume(struct device *dev)  static const struct dev_pm_ops input_dev_pm_ops = {  	.suspend	= input_dev_suspend,  	.resume		= input_dev_resume, -	.poweroff	= input_dev_suspend, +	.freeze		= input_dev_freeze, +	.poweroff	= input_dev_poweroff,  	.restore	= input_dev_resume,  };  #endif /* CONFIG_PM */ @@ -1707,7 +1747,7 @@ static struct device_type input_dev_type = {  	.groups		= input_dev_attr_groups,  	.release	= input_dev_release,  	.uevent		= input_dev_uevent, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.pm		= &input_dev_pm_ops,  #endif  }; @@ -1734,6 +1774,7 @@ EXPORT_SYMBOL_GPL(input_class);   */  struct input_dev *input_allocate_device(void)  { +	static atomic_t input_no = ATOMIC_INIT(0);  	struct input_dev *dev;  	dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL); @@ -1743,9 +1784,13 @@ struct input_dev *input_allocate_device(void)  		device_initialize(&dev->dev);  		mutex_init(&dev->mutex);  		spin_lock_init(&dev->event_lock); +		init_timer(&dev->timer);  		INIT_LIST_HEAD(&dev->h_list);  		INIT_LIST_HEAD(&dev->node); +		dev_set_name(&dev->dev, "input%ld", +			     (unsigned long) atomic_inc_return(&input_no) - 1); +  		__module_get(THIS_MODULE);  	} @@ -1866,6 +1911,10 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int  		break;  	case EV_ABS: +		input_alloc_absinfo(dev); +		if (!dev->absinfo) +			return; +  		__set_bit(code, dev->absbit);  		break; @@ -2019,7 +2068,6 @@ static void devm_input_device_unregister(struct device *dev, void *res)   */  int input_register_device(struct input_dev *dev)  { -	static atomic_t input_no = ATOMIC_INIT(0);  	struct input_devres *devres = NULL;  	struct input_handler *handler;  	unsigned int packet_size; @@ -2048,7 +2096,7 @@ int input_register_device(struct input_dev *dev)  	if (dev->hint_events_per_packet < packet_size)  		dev->hint_events_per_packet = packet_size; -	dev->max_vals = max(dev->hint_events_per_packet, packet_size) + 2; +	dev->max_vals = dev->hint_events_per_packet + 2;  	dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);  	if (!dev->vals) {  		error = -ENOMEM; @@ -2059,7 +2107,6 @@ int input_register_device(struct input_dev *dev)  	 * If delay and period are pre-set by the driver, then autorepeating  	 * is handled by the driver itself and we don't do it in input.c.  	 */ -	init_timer(&dev->timer);  	if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {  		dev->timer.data = (long) dev;  		dev->timer.function = input_repeat_key; @@ -2073,9 +2120,6 @@ int input_register_device(struct input_dev *dev)  	if (!dev->setkeycode)  		dev->setkeycode = input_default_setkeycode; -	dev_set_name(&dev->dev, "input%ld", -		     (unsigned long) atomic_inc_return(&input_no) - 1); -  	error = device_add(&dev->dev);  	if (error)  		goto err_free_vals; diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c index 85bc8dc07cf..55efdfc7eb6 100644 --- a/drivers/input/joystick/a3d.c +++ b/drivers/input/joystick/a3d.c @@ -29,7 +29,6 @@  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/slab.h> -#include <linux/init.h>  #include <linux/gameport.h>  #include <linux/input.h>  #include <linux/jiffies.h> diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c index 0cbfd2dfabf..b78425765d3 100644 --- a/drivers/input/joystick/adi.c +++ b/drivers/input/joystick/adi.c @@ -33,7 +33,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/gameport.h> -#include <linux/init.h>  #include <linux/jiffies.h>  #define DRIVER_DESC	"Logitech ADI joystick family driver" diff --git a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c index 65367e44d71..ae3ee24a236 100644 --- a/drivers/input/joystick/cobra.c +++ b/drivers/input/joystick/cobra.c @@ -29,7 +29,6 @@  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/slab.h> -#include <linux/init.h>  #include <linux/gameport.h>  #include <linux/input.h>  #include <linux/jiffies.h> diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c index ab1cf288200..0f519db6474 100644 --- a/drivers/input/joystick/gf2k.c +++ b/drivers/input/joystick/gf2k.c @@ -30,7 +30,6 @@  #include <linux/kernel.h>  #include <linux/slab.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/input.h>  #include <linux/gameport.h>  #include <linux/jiffies.h> diff --git a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c index 9e1beff57c3..eac9c5b8d73 100644 --- a/drivers/input/joystick/grip.c +++ b/drivers/input/joystick/grip.c @@ -28,7 +28,6 @@  #include <linux/kernel.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/gameport.h>  #include <linux/input.h> diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c index c0f9c7b7eb4..573191dd78e 100644 --- a/drivers/input/joystick/grip_mp.c +++ b/drivers/input/joystick/grip_mp.c @@ -11,7 +11,6 @@  #include <linux/kernel.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/gameport.h>  #include <linux/input.h> diff --git a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c index 55196f730af..a9ac2f9cfce 100644 --- a/drivers/input/joystick/guillemot.c +++ b/drivers/input/joystick/guillemot.c @@ -30,7 +30,6 @@  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/delay.h> -#include <linux/init.h>  #include <linux/gameport.h>  #include <linux/input.h>  #include <linux/jiffies.h> diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h index b1d7d9b0eb8..96ae4f5bd0e 100644 --- a/drivers/input/joystick/iforce/iforce.h +++ b/drivers/input/joystick/iforce/iforce.h @@ -29,7 +29,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/spinlock.h>  #include <linux/usb.h>  #include <linux/serio.h> diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c index 88c22623a2e..17c2c800743 100644 --- a/drivers/input/joystick/interact.c +++ b/drivers/input/joystick/interact.c @@ -33,7 +33,6 @@  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/delay.h> -#include <linux/init.h>  #include <linux/gameport.h>  #include <linux/input.h>  #include <linux/jiffies.h> diff --git a/drivers/input/joystick/joydump.c b/drivers/input/joystick/joydump.c index 7eb878bab96..d1c6e4846a4 100644 --- a/drivers/input/joystick/joydump.c +++ b/drivers/input/joystick/joydump.c @@ -31,7 +31,6 @@  #include <linux/gameport.h>  #include <linux/kernel.h>  #include <linux/delay.h> -#include <linux/init.h>  #include <linux/slab.h>  #define DRIVER_DESC	"Gameport data dumper module" diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c index 9fb153eef2f..c5358ba1f57 100644 --- a/drivers/input/joystick/magellan.c +++ b/drivers/input/joystick/magellan.c @@ -31,7 +31,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"Magellan and SpaceMouse 6dof controller driver" diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c index 04c69af3714..4a95b224169 100644 --- a/drivers/input/joystick/sidewinder.c +++ b/drivers/input/joystick/sidewinder.c @@ -30,7 +30,6 @@  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/slab.h> -#include <linux/init.h>  #include <linux/input.h>  #include <linux/gameport.h>  #include <linux/jiffies.h> diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c index 80a7b27a457..f4445a4e8d6 100644 --- a/drivers/input/joystick/spaceball.c +++ b/drivers/input/joystick/spaceball.c @@ -33,7 +33,6 @@  #include <linux/kernel.h>  #include <linux/slab.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/input.h>  #include <linux/serio.h> diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c index a41f291652e..f2667820e8c 100644 --- a/drivers/input/joystick/spaceorb.c +++ b/drivers/input/joystick/spaceorb.c @@ -32,7 +32,6 @@  #include <linux/kernel.h>  #include <linux/slab.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/input.h>  #include <linux/serio.h> diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c index 0f51a60e14a..099c6d7b5e0 100644 --- a/drivers/input/joystick/stinger.c +++ b/drivers/input/joystick/stinger.c @@ -32,7 +32,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"Gravis Stinger gamepad driver" diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c index 5ef9bcdb034..7e17cde464f 100644 --- a/drivers/input/joystick/tmdc.c +++ b/drivers/input/joystick/tmdc.c @@ -33,7 +33,6 @@  #include <linux/kernel.h>  #include <linux/slab.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/gameport.h>  #include <linux/input.h>  #include <linux/jiffies.h> diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c index 2556a819357..7f7e5ab3f9e 100644 --- a/drivers/input/joystick/twidjoy.c +++ b/drivers/input/joystick/twidjoy.c @@ -52,7 +52,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"Handykey Twiddler keyboard as a joystick driver" diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c index 23b3071abb6..e13a9144a25 100644 --- a/drivers/input/joystick/warrior.c +++ b/drivers/input/joystick/warrior.c @@ -31,7 +31,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"Logitech WingMan Warrior joystick driver" diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 75e3b102ce4..603fe0dd368 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -74,7 +74,6 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/stat.h>  #include <linux/module.h> @@ -125,6 +124,8 @@ static const struct xpad_device {  	{ 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },  	{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },  	{ 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX }, +	{ 0x046d, 0xc21d, "Logitech Gamepad F310", 0, XTYPE_XBOX360 }, +	{ 0x046d, 0xc21f, "Logitech Gamepad F710", 0, XTYPE_XBOX360 },  	{ 0x046d, 0xc242, "Logitech Chillstream Controller", 0, XTYPE_XBOX360 },  	{ 0x046d, 0xca84, "Logitech Xbox Cordless Controller", 0, XTYPE_XBOX },  	{ 0x046d, 0xca88, "Logitech Compact Controller for Xbox", 0, XTYPE_XBOX }, @@ -166,8 +167,8 @@ static const struct xpad_device {  	{ 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", 0, XTYPE_XBOX360 },  	{ 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },  	{ 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 }, -	{ 0x1689, 0xfd00, "Razer Onza Tournament Edition", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, -	{ 0x1689, 0xfd01, "Razer Onza Classic Edition", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, +	{ 0x1689, 0xfd00, "Razer Onza Tournament Edition", 0, XTYPE_XBOX360 }, +	{ 0x1689, 0xfd01, "Razer Onza Classic Edition", 0, XTYPE_XBOX360 },  	{ 0x1bad, 0x0002, "Harmonix Rock Band Guitar", 0, XTYPE_XBOX360 },  	{ 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },  	{ 0x1bad, 0xf016, "Mad Catz Xbox 360 Controller", 0, XTYPE_XBOX360 }, diff --git a/drivers/input/joystick/zhenhua.c b/drivers/input/joystick/zhenhua.c index c4de4388fd7..30af2e8c670 100644 --- a/drivers/input/joystick/zhenhua.c +++ b/drivers/input/joystick/zhenhua.c @@ -49,7 +49,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"RC transmitter with 5-byte Zhen Hua protocol joystick driver" diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index c1edd39bc5b..f7e79b48134 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -2,7 +2,7 @@  # Input core configuration  #  menuconfig INPUT_KEYBOARD -	bool "Keyboards" if EXPERT || !X86 +	bool "Keyboards"  	default y  	help  	  Say Y here, and a list of supported keyboards will be displayed. @@ -67,11 +67,11 @@ config KEYBOARD_ATARI  	  module will be called atakbd.  config KEYBOARD_ATKBD -	tristate "AT keyboard" if EXPERT || !X86 +	tristate "AT keyboard"  	default y  	select SERIO  	select SERIO_LIBPS2 -	select SERIO_I8042 if X86 +	select SERIO_I8042 if ARCH_MIGHT_HAVE_PC_SERIO  	select SERIO_GSCPS2 if GSC  	help  	  Say Y here if you want to use a standard AT or PS/2 keyboard. Usually @@ -151,6 +151,18 @@ config KEYBOARD_BFIN  	  To compile this driver as a module, choose M here: the  	  module will be called bf54x-keys. +config KEYBOARD_CLPS711X +	tristate "CLPS711X Keypad support" +	depends on OF_GPIO && (ARCH_CLPS711X || COMPILE_TEST) +	select INPUT_MATRIXKMAP +	select INPUT_POLLDEV +	help +	  Say Y here to enable the matrix keypad on the Cirrus Logic +	  CLPS711X CPUs. + +	  To compile this driver as a module, choose M here: the +	  module will be called clps711x-keypad. +  config KEYBOARD_LKKBD  	tristate "DECstation/VAXstation LK201/LK401 keyboard"  	select SERIO @@ -512,6 +524,17 @@ config KEYBOARD_STOWAWAY  	  To compile this driver as a module, choose M here: the  	  module will be called stowaway. +config KEYBOARD_ST_KEYSCAN +	tristate "STMicroelectronics keyscan support" +	depends on ARCH_STI || COMPILE_TEST +	select INPUT_MATRIXKMAP +	help +	  Say Y here if you want to use a keypad attached to the keyscan block +	  on some STMicroelectronics SoC devices. + +	  To compile this driver as a module, choose M here: the +	  module will be called st-keyscan. +  config KEYBOARD_SUNKBD  	tristate "Sun Type 4 and Type 5 keyboard"  	select SERIO @@ -525,7 +548,7 @@ config KEYBOARD_SUNKBD  config KEYBOARD_SH_KEYSC  	tristate "SuperH KEYSC keypad support" -	depends on SUPERH || ARCH_SHMOBILE +	depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST  	help  	  Say Y here if you want to use a keypad attached to the KEYSC block  	  on SuperH processors such as sh7722 and sh7343. @@ -566,7 +589,7 @@ config KEYBOARD_OMAP  config KEYBOARD_OMAP4  	tristate "TI OMAP4+ keypad support" -	depends on ARCH_OMAP2PLUS +	depends on OF || ARCH_OMAP2PLUS  	select INPUT_MATRIXKMAP  	help  	  Say Y here if you want to use the OMAP4+ keypad. @@ -595,16 +618,6 @@ config KEYBOARD_TC3589X  	  To compile this driver as a module, choose M here: the  	  module will be called tc3589x-keypad. -config KEYBOARD_TNETV107X -	tristate "TI TNETV107X keypad support" -	depends on ARCH_DAVINCI_TNETV107X -	select INPUT_MATRIXKMAP -	help -	  Say Y here if you want to use the TNETV107X keypad. - -	  To compile this driver as a module, choose M here: the -	  module will be called tnetv107x-keypad. -  config KEYBOARD_TWL4030  	tristate "TI TWL4030/TWL5030/TPS659x0 keypad support"  	depends on TWL4030_CORE diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index a699b617230..7504ae19049 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_KEYBOARD_AMIGA)		+= amikbd.o  obj-$(CONFIG_KEYBOARD_ATARI)		+= atakbd.o  obj-$(CONFIG_KEYBOARD_ATKBD)		+= atkbd.o  obj-$(CONFIG_KEYBOARD_BFIN)		+= bf54x-keys.o +obj-$(CONFIG_KEYBOARD_CLPS711X)		+= clps711x-keypad.o  obj-$(CONFIG_KEYBOARD_CROS_EC)		+= cros_ec_keyb.o  obj-$(CONFIG_KEYBOARD_DAVINCI)		+= davinci_keyscan.o  obj-$(CONFIG_KEYBOARD_EP93XX)		+= ep93xx_keypad.o @@ -50,10 +51,10 @@ obj-$(CONFIG_KEYBOARD_SH_KEYSC)		+= sh_keysc.o  obj-$(CONFIG_KEYBOARD_SPEAR)		+= spear-keyboard.o  obj-$(CONFIG_KEYBOARD_STMPE)		+= stmpe-keypad.o  obj-$(CONFIG_KEYBOARD_STOWAWAY)		+= stowaway.o +obj-$(CONFIG_KEYBOARD_ST_KEYSCAN)	+= st-keyscan.o  obj-$(CONFIG_KEYBOARD_SUNKBD)		+= sunkbd.o  obj-$(CONFIG_KEYBOARD_TC3589X)		+= tc3589x-keypad.o  obj-$(CONFIG_KEYBOARD_TEGRA)		+= tegra-kbc.o -obj-$(CONFIG_KEYBOARD_TNETV107X)	+= tnetv107x-keypad.o  obj-$(CONFIG_KEYBOARD_TWL4030)		+= twl4030_keypad.o  obj-$(CONFIG_KEYBOARD_XTKBD)		+= xtkbd.o  obj-$(CONFIG_KEYBOARD_W90P910)		+= w90p910_keypad.o diff --git a/drivers/input/keyboard/adp5520-keys.c b/drivers/input/keyboard/adp5520-keys.c index ef26b17fb15..7f4a8b58efc 100644 --- a/drivers/input/keyboard/adp5520-keys.c +++ b/drivers/input/keyboard/adp5520-keys.c @@ -8,11 +8,11 @@  #include <linux/module.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/input.h>  #include <linux/mfd/adp5520.h>  #include <linux/slab.h> +#include <linux/device.h>  struct adp5520_keys {  	struct input_dev *input; @@ -71,7 +71,7 @@ static int adp5520_keys_notifier(struct notifier_block *nb,  static int adp5520_keys_probe(struct platform_device *pdev)  { -	struct adp5520_keys_platform_data *pdata = pdev->dev.platform_data; +	struct adp5520_keys_platform_data *pdata = dev_get_platdata(&pdev->dev);  	struct input_dev *input;  	struct adp5520_keys *dev;  	int ret, i; @@ -82,7 +82,7 @@ static int adp5520_keys_probe(struct platform_device *pdev)  		return -EINVAL;  	} -	if (pdata == NULL) { +	if (!pdata) {  		dev_err(&pdev->dev, "missing platform data\n");  		return -EINVAL;  	} @@ -90,17 +90,15 @@ static int adp5520_keys_probe(struct platform_device *pdev)  	if (!(pdata->rows_en_mask && pdata->cols_en_mask))  		return -EINVAL; -	dev = kzalloc(sizeof(*dev), GFP_KERNEL); -	if (dev == NULL) { +	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); +	if (!dev) {  		dev_err(&pdev->dev, "failed to alloc memory\n");  		return -ENOMEM;  	} -	input = input_allocate_device(); -	if (!input) { -		ret = -ENOMEM; -		goto err; -	} +	input = devm_input_allocate_device(&pdev->dev); +	if (!input) +		return -ENOMEM;  	dev->master = pdev->dev.parent;  	dev->input = input; @@ -136,7 +134,7 @@ static int adp5520_keys_probe(struct platform_device *pdev)  	ret = input_register_device(input);  	if (ret) {  		dev_err(&pdev->dev, "unable to register input device\n"); -		goto err; +		return ret;  	}  	en_mask = pdata->rows_en_mask | pdata->cols_en_mask; @@ -158,8 +156,7 @@ static int adp5520_keys_probe(struct platform_device *pdev)  	if (ret) {  		dev_err(&pdev->dev, "failed to write\n"); -		ret = -EIO; -		goto err1; +		return -EIO;  	}  	dev->notifier.notifier_call = adp5520_keys_notifier; @@ -167,19 +164,11 @@ static int adp5520_keys_probe(struct platform_device *pdev)  			ADP5520_KP_IEN | ADP5520_KR_IEN);  	if (ret) {  		dev_err(&pdev->dev, "failed to register notifier\n"); -		goto err1; +		return ret;  	}  	platform_set_drvdata(pdev, dev);  	return 0; - -err1: -	input_unregister_device(input); -	input = NULL; -err: -	input_free_device(input); -	kfree(dev); -	return ret;  }  static int adp5520_keys_remove(struct platform_device *pdev) @@ -189,8 +178,6 @@ static int adp5520_keys_remove(struct platform_device *pdev)  	adp5520_unregister_notifier(dev->master, &dev->notifier,  				ADP5520_KP_IEN | ADP5520_KR_IEN); -	input_unregister_device(dev->input); -	kfree(dev);  	return 0;  } diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index dbd2047f164..5ef7fcf0e25 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -9,7 +9,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/irq.h>  #include <linux/workqueue.h> @@ -77,8 +76,18 @@ static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)  	struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);  	unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);  	unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]); +	int val; -	return !!(adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank) & bit); +	mutex_lock(&kpad->gpio_lock); + +	if (kpad->dir[bank] & bit) +		val = kpad->dat_out[bank]; +	else +		val = adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank); + +	mutex_unlock(&kpad->gpio_lock); + +	return !!(val & bit);  }  static void adp5588_gpio_set_value(struct gpio_chip *chip, @@ -173,7 +182,7 @@ static int adp5588_build_gpiomap(struct adp5588_kpad *kpad,  static int adp5588_gpio_add(struct adp5588_kpad *kpad)  {  	struct device *dev = &kpad->client->dev; -	const struct adp5588_kpad_platform_data *pdata = dev->platform_data; +	const struct adp5588_kpad_platform_data *pdata = dev_get_platdata(dev);  	const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;  	int i, error; @@ -227,7 +236,7 @@ static int adp5588_gpio_add(struct adp5588_kpad *kpad)  static void adp5588_gpio_remove(struct adp5588_kpad *kpad)  {  	struct device *dev = &kpad->client->dev; -	const struct adp5588_kpad_platform_data *pdata = dev->platform_data; +	const struct adp5588_kpad_platform_data *pdata = dev_get_platdata(dev);  	const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;  	int error; @@ -321,7 +330,8 @@ static irqreturn_t adp5588_irq(int irq, void *handle)  static int adp5588_setup(struct i2c_client *client)  { -	const struct adp5588_kpad_platform_data *pdata = client->dev.platform_data; +	const struct adp5588_kpad_platform_data *pdata = +			dev_get_platdata(&client->dev);  	const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;  	int i, ret;  	unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0; @@ -424,7 +434,8 @@ static int adp5588_probe(struct i2c_client *client,  			 const struct i2c_device_id *id)  {  	struct adp5588_kpad *kpad; -	const struct adp5588_kpad_platform_data *pdata = client->dev.platform_data; +	const struct adp5588_kpad_platform_data *pdata = +			dev_get_platdata(&client->dev);  	struct input_dev *input;  	unsigned int revid;  	int ret, i; @@ -536,7 +547,8 @@ static int adp5588_probe(struct i2c_client *client,  		__set_bit(EV_REP, input->evbit);  	for (i = 0; i < input->keycodemax; i++) -		__set_bit(kpad->keycode[i] & KEY_MAX, input->keybit); +		if (kpad->keycode[i] <= KEY_MAX) +			__set_bit(kpad->keycode[i], input->keybit);  	__clear_bit(KEY_RESERVED, input->keybit);  	if (kpad->gpimapsize) diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c index 67d12b3427c..6329549bf6a 100644 --- a/drivers/input/keyboard/adp5589-keys.c +++ b/drivers/input/keyboard/adp5589-keys.c @@ -8,7 +8,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/irq.h>  #include <linux/workqueue.h> @@ -499,7 +498,7 @@ static int adp5589_build_gpiomap(struct adp5589_kpad *kpad,  static int adp5589_gpio_add(struct adp5589_kpad *kpad)  {  	struct device *dev = &kpad->client->dev; -	const struct adp5589_kpad_platform_data *pdata = dev->platform_data; +	const struct adp5589_kpad_platform_data *pdata = dev_get_platdata(dev);  	const struct adp5589_gpio_platform_data *gpio_data = pdata->gpio_data;  	int i, error; @@ -553,7 +552,7 @@ static int adp5589_gpio_add(struct adp5589_kpad *kpad)  static void adp5589_gpio_remove(struct adp5589_kpad *kpad)  {  	struct device *dev = &kpad->client->dev; -	const struct adp5589_kpad_platform_data *pdata = dev->platform_data; +	const struct adp5589_kpad_platform_data *pdata = dev_get_platdata(dev);  	const struct adp5589_gpio_platform_data *gpio_data = pdata->gpio_data;  	int error; @@ -658,7 +657,7 @@ static int adp5589_setup(struct adp5589_kpad *kpad)  {  	struct i2c_client *client = kpad->client;  	const struct adp5589_kpad_platform_data *pdata = -		client->dev.platform_data; +		dev_get_platdata(&client->dev);  	u8 (*reg) (u8) = kpad->var->reg;  	unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0;  	unsigned char pull_mask = 0; @@ -864,7 +863,7 @@ static int adp5589_probe(struct i2c_client *client,  {  	struct adp5589_kpad *kpad;  	const struct adp5589_kpad_platform_data *pdata = -		client->dev.platform_data; +		dev_get_platdata(&client->dev);  	struct input_dev *input;  	unsigned int revid;  	int ret, i; @@ -992,7 +991,8 @@ static int adp5589_probe(struct i2c_client *client,  		__set_bit(EV_REP, input->evbit);  	for (i = 0; i < input->keycodemax; i++) -		__set_bit(kpad->keycode[i] & KEY_MAX, input->keybit); +		if (kpad->keycode[i] <= KEY_MAX) +			__set_bit(kpad->keycode[i], input->keybit);  	__clear_bit(KEY_RESERVED, input->keybit);  	if (kpad->gpimapsize) diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 2626773ff29..2dd1d0dd4f7 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -243,6 +243,12 @@ static void (*atkbd_platform_fixup)(struct atkbd *, const void *data);  static void *atkbd_platform_fixup_data;  static unsigned int (*atkbd_platform_scancode_fixup)(struct atkbd *, unsigned int); +/* + * Certain keyboards to not like ATKBD_CMD_RESET_DIS and stop responding + * to many commands until full reset (ATKBD_CMD_RESET_BAT) is performed. + */ +static bool atkbd_skip_deactivate; +  static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,  				ssize_t (*handler)(struct atkbd *, char *));  static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count, @@ -768,7 +774,8 @@ static int atkbd_probe(struct atkbd *atkbd)   * Make sure nothing is coming from the keyboard and disturbs our   * internal state.   */ -	atkbd_deactivate(atkbd); +	if (!atkbd_skip_deactivate) +		atkbd_deactivate(atkbd);  	return 0;  } @@ -1638,6 +1645,12 @@ static int __init atkbd_setup_scancode_fixup(const struct dmi_system_id *id)  	return 1;  } +static int __init atkbd_deactivate_fixup(const struct dmi_system_id *id) +{ +	atkbd_skip_deactivate = true; +	return 1; +} +  static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = {  	{  		.matches = { @@ -1775,6 +1788,20 @@ static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = {  		.callback = atkbd_setup_scancode_fixup,  		.driver_data = atkbd_oqo_01plus_scancode_fixup,  	}, +	{ +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"), +			DMI_MATCH(DMI_PRODUCT_NAME, "LW25-B7HV"), +		}, +		.callback = atkbd_deactivate_fixup, +	}, +	{ +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"), +			DMI_MATCH(DMI_PRODUCT_NAME, "P1-J273B"), +		}, +		.callback = atkbd_deactivate_fixup, +	},  	{ }  }; diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c index fc88fb48d70..e6d46c5994d 100644 --- a/drivers/input/keyboard/bf54x-keys.c +++ b/drivers/input/keyboard/bf54x-keys.c @@ -30,7 +30,6 @@  #include <linux/module.h> -#include <linux/init.h>  #include <linux/fs.h>  #include <linux/interrupt.h>  #include <linux/irq.h> @@ -180,7 +179,7 @@ static irqreturn_t bfin_kpad_isr(int irq, void *dev_id)  static int bfin_kpad_probe(struct platform_device *pdev)  {  	struct bf54x_kpad *bf54x_kpad; -	struct bfin_kpad_platform_data *pdata = pdev->dev.platform_data; +	struct bfin_kpad_platform_data *pdata = dev_get_platdata(&pdev->dev);  	struct input_dev *input;  	int i, error; @@ -289,7 +288,8 @@ static int bfin_kpad_probe(struct platform_device *pdev)  		__set_bit(EV_REP, input->evbit);  	for (i = 0; i < input->keycodemax; i++) -		__set_bit(bf54x_kpad->keycode[i] & KEY_MAX, input->keybit); +		if (bf54x_kpad->keycode[i] <= KEY_MAX) +			__set_bit(bf54x_kpad->keycode[i], input->keybit);  	__clear_bit(KEY_RESERVED, input->keybit);  	error = input_register_device(input); @@ -332,7 +332,7 @@ out:  static int bfin_kpad_remove(struct platform_device *pdev)  { -	struct bfin_kpad_platform_data *pdata = pdev->dev.platform_data; +	struct bfin_kpad_platform_data *pdata = dev_get_platdata(&pdev->dev);  	struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev);  	del_timer_sync(&bf54x_kpad->timer); diff --git a/drivers/input/keyboard/clps711x-keypad.c b/drivers/input/keyboard/clps711x-keypad.c new file mode 100644 index 00000000000..552b65c6e6b --- /dev/null +++ b/drivers/input/keyboard/clps711x-keypad.c @@ -0,0 +1,207 @@ +/* + * Cirrus Logic CLPS711X Keypad driver + * + * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru> + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/input.h> +#include <linux/input-polldev.h> +#include <linux/module.h> +#include <linux/of_gpio.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/sched.h> +#include <linux/input/matrix_keypad.h> +#include <linux/mfd/syscon.h> +#include <linux/mfd/syscon/clps711x.h> + +#define CLPS711X_KEYPAD_COL_COUNT	8 + +struct clps711x_gpio_data { +	struct gpio_desc *desc; +	DECLARE_BITMAP(last_state, CLPS711X_KEYPAD_COL_COUNT); +}; + +struct clps711x_keypad_data { +	struct regmap			*syscon; +	int				row_count; +	unsigned int			row_shift; +	struct clps711x_gpio_data	*gpio_data; +}; + +static void clps711x_keypad_poll(struct input_polled_dev *dev) +{ +	const unsigned short *keycodes = dev->input->keycode; +	struct clps711x_keypad_data *priv = dev->private; +	bool sync = false; +	int col, row; + +	for (col = 0; col < CLPS711X_KEYPAD_COL_COUNT; col++) { +		/* Assert column */ +		regmap_update_bits(priv->syscon, SYSCON_OFFSET, +				   SYSCON1_KBDSCAN_MASK, +				   SYSCON1_KBDSCAN(8 + col)); + +		/* Scan rows */ +		for (row = 0; row < priv->row_count; row++) { +			struct clps711x_gpio_data *data = &priv->gpio_data[row]; +			bool state, state1; + +			/* Read twice for protection against fluctuations */ +			do { +				state = gpiod_get_value_cansleep(data->desc); +				cond_resched(); +				state1 = gpiod_get_value_cansleep(data->desc); +			} while (state != state1); + +			if (test_bit(col, data->last_state) != state) { +				int code = MATRIX_SCAN_CODE(row, col, +							    priv->row_shift); + +				if (state) { +					set_bit(col, data->last_state); +					input_event(dev->input, EV_MSC, +						    MSC_SCAN, code); +				} else { +					clear_bit(col, data->last_state); +				} + +				if (keycodes[code]) +					input_report_key(dev->input, +							 keycodes[code], state); +				sync = true; +			} +		} + +		/* Set all columns to low */ +		regmap_update_bits(priv->syscon, SYSCON_OFFSET, +				   SYSCON1_KBDSCAN_MASK, SYSCON1_KBDSCAN(1)); +	} + +	if (sync) +		input_sync(dev->input); +} + +static int clps711x_keypad_probe(struct platform_device *pdev) +{ +	struct clps711x_keypad_data *priv; +	struct device *dev = &pdev->dev; +	struct device_node *np = dev->of_node; +	struct input_polled_dev *poll_dev; +	u32 poll_interval; +	int i, err; + +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); +	if (!priv) +		return -ENOMEM; + +	priv->syscon = +		syscon_regmap_lookup_by_compatible("cirrus,clps711x-syscon1"); +	if (IS_ERR(priv->syscon)) +		return PTR_ERR(priv->syscon); + +	priv->row_count = of_gpio_named_count(np, "row-gpios"); +	if (priv->row_count < 1) +		return -EINVAL; + +	priv->gpio_data = devm_kzalloc(dev, +				sizeof(*priv->gpio_data) * priv->row_count, +				GFP_KERNEL); +	if (!priv->gpio_data) +		return -ENOMEM; + +	priv->row_shift = get_count_order(CLPS711X_KEYPAD_COL_COUNT); + +	for (i = 0; i < priv->row_count; i++) { +		struct clps711x_gpio_data *data = &priv->gpio_data[i]; + +		data->desc = devm_gpiod_get_index(dev, "row", i); +		if (!data->desc) +			return -EINVAL; + +		if (IS_ERR(data->desc)) +			return PTR_ERR(data->desc); + +		gpiod_direction_input(data->desc); +	} + +	err = of_property_read_u32(np, "poll-interval", &poll_interval); +	if (err) +		return err; + +	poll_dev = input_allocate_polled_device(); +	if (!poll_dev) +		return -ENOMEM; + +	poll_dev->private		= priv; +	poll_dev->poll			= clps711x_keypad_poll; +	poll_dev->poll_interval		= poll_interval; +	poll_dev->input->name		= pdev->name; +	poll_dev->input->dev.parent	= dev; +	poll_dev->input->id.bustype	= BUS_HOST; +	poll_dev->input->id.vendor	= 0x0001; +	poll_dev->input->id.product	= 0x0001; +	poll_dev->input->id.version	= 0x0100; + +	err = matrix_keypad_build_keymap(NULL, NULL, priv->row_count, +					 CLPS711X_KEYPAD_COL_COUNT, +					 NULL, poll_dev->input); +	if (err) +		goto out_err; + +	input_set_capability(poll_dev->input, EV_MSC, MSC_SCAN); +	if (of_property_read_bool(np, "autorepeat")) +		__set_bit(EV_REP, poll_dev->input->evbit); + +	platform_set_drvdata(pdev, poll_dev); + +	/* Set all columns to low */ +	regmap_update_bits(priv->syscon, SYSCON_OFFSET, SYSCON1_KBDSCAN_MASK, +			   SYSCON1_KBDSCAN(1)); + +	err = input_register_polled_device(poll_dev); +	if (err) +		goto out_err; + +	return 0; + +out_err: +	input_free_polled_device(poll_dev); +	return err; +} + +static int clps711x_keypad_remove(struct platform_device *pdev) +{ +	struct input_polled_dev *poll_dev = platform_get_drvdata(pdev); + +	input_unregister_polled_device(poll_dev); +	input_free_polled_device(poll_dev); + +	return 0; +} + +static const struct of_device_id clps711x_keypad_of_match[] = { +	{ .compatible = "cirrus,clps711x-keypad", }, +	{ } +}; +MODULE_DEVICE_TABLE(of, clps711x_keypad_of_match); + +static struct platform_driver clps711x_keypad_driver = { +	.driver	= { +		.name		= "clps711x-keypad", +		.owner		= THIS_MODULE, +		.of_match_table	= clps711x_keypad_of_match, +	}, +	.probe	= clps711x_keypad_probe, +	.remove	= clps711x_keypad_remove, +}; +module_platform_driver(clps711x_keypad_driver); + +MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); +MODULE_DESCRIPTION("Cirrus Logic CLPS711X Keypad driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c index 7e8b0a52af2..408379669d3 100644 --- a/drivers/input/keyboard/cros_ec_keyb.c +++ b/drivers/input/keyboard/cros_ec_keyb.c @@ -38,6 +38,7 @@   * @row_shift: log2 or number of rows, rounded up   * @keymap_data: Matrix keymap data used to convert to keyscan values   * @ghost_filter: true to enable the matrix key-ghosting filter + * @old_kb_state: bitmap of keys pressed last scan   * @dev: Device pointer   * @idev: Input device   * @ec: Top level ChromeOS device to use to talk to EC @@ -49,6 +50,7 @@ struct cros_ec_keyb {  	int row_shift;  	const struct matrix_keymap_data *keymap_data;  	bool ghost_filter; +	uint8_t *old_kb_state;  	struct device *dev;  	struct input_dev *idev; @@ -135,6 +137,7 @@ static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev,  	struct input_dev *idev = ckdev->idev;  	int col, row;  	int new_state; +	int old_state;  	int num_cols;  	num_cols = len; @@ -153,18 +156,19 @@ static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev,  		for (row = 0; row < ckdev->rows; row++) {  			int pos = MATRIX_SCAN_CODE(row, col, ckdev->row_shift);  			const unsigned short *keycodes = idev->keycode; -			int code; -			code = keycodes[pos];  			new_state = kb_state[col] & (1 << row); -			if (!!new_state != test_bit(code, idev->key)) { +			old_state = ckdev->old_kb_state[col] & (1 << row); +			if (new_state != old_state) {  				dev_dbg(ckdev->dev,  					"changed: [r%d c%d]: byte %02x\n",  					row, col, new_state); -				input_report_key(idev, code, new_state); +				input_report_key(idev, keycodes[pos], +						 new_state);  			}  		} +		ckdev->old_kb_state[col] = kb_state[col];  	}  	input_sync(ckdev->idev);  } @@ -226,6 +230,9 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)  					    &ckdev->cols);  	if (err)  		return err; +	ckdev->old_kb_state = devm_kzalloc(&pdev->dev, ckdev->cols, GFP_KERNEL); +	if (!ckdev->old_kb_state) +		return -ENOMEM;  	idev = devm_input_allocate_device(&pdev->dev);  	if (!idev) diff --git a/drivers/input/keyboard/davinci_keyscan.c b/drivers/input/keyboard/davinci_keyscan.c index d15977a8361..1559dc1cf95 100644 --- a/drivers/input/keyboard/davinci_keyscan.c +++ b/drivers/input/keyboard/davinci_keyscan.c @@ -172,7 +172,7 @@ static int __init davinci_ks_probe(struct platform_device *pdev)  	struct input_dev *key_dev;  	struct resource *res, *mem;  	struct device *dev = &pdev->dev; -	struct davinci_ks_platform_data *pdata = pdev->dev.platform_data; +	struct davinci_ks_platform_data *pdata = dev_get_platdata(&pdev->dev);  	int error, i;  	if (pdata->device_enable) { diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c index 47206bdba41..e59876212b8 100644 --- a/drivers/input/keyboard/ep93xx_keypad.c +++ b/drivers/input/keyboard/ep93xx_keypad.c @@ -244,7 +244,7 @@ static int ep93xx_keypad_probe(struct platform_device *pdev)  	if (!keypad)  		return -ENOMEM; -	keypad->pdata = pdev->dev.platform_data; +	keypad->pdata = dev_get_platdata(&pdev->dev);  	if (!keypad->pdata) {  		err = -EINVAL;  		goto failed_free; diff --git a/drivers/input/keyboard/goldfish_events.c b/drivers/input/keyboard/goldfish_events.c index 9f60a2ec88d..69e85476337 100644 --- a/drivers/input/keyboard/goldfish_events.c +++ b/drivers/input/keyboard/goldfish_events.c @@ -14,7 +14,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/types.h>  #include <linux/input.h> diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 440ce32462b..8c98e97f8e4 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -26,6 +26,7 @@  #include <linux/gpio_keys.h>  #include <linux/workqueue.h>  #include <linux/gpio.h> +#include <linux/of.h>  #include <linux/of_platform.h>  #include <linux/of_gpio.h>  #include <linux/spinlock.h> @@ -423,6 +424,16 @@ out:  	return IRQ_HANDLED;  } +static void gpio_keys_quiesce_key(void *data) +{ +	struct gpio_button_data *bdata = data; + +	if (bdata->timer_debounce) +		del_timer_sync(&bdata->timer); + +	cancel_work_sync(&bdata->work); +} +  static int gpio_keys_setup_key(struct platform_device *pdev,  				struct input_dev *input,  				struct gpio_button_data *bdata, @@ -432,7 +443,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev,  	struct device *dev = &pdev->dev;  	irq_handler_t isr;  	unsigned long irqflags; -	int irq, error; +	int irq; +	int error;  	bdata->input = input;  	bdata->button = button; @@ -440,7 +452,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev,  	if (gpio_is_valid(button->gpio)) { -		error = gpio_request_one(button->gpio, GPIOF_IN, desc); +		error = devm_gpio_request_one(&pdev->dev, button->gpio, +					      GPIOF_IN, desc);  		if (error < 0) {  			dev_err(dev, "Failed to request GPIO %d, error %d\n",  				button->gpio, error); @@ -462,7 +475,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev,  			dev_err(dev,  				"Unable to get irq number for GPIO %d, error %d\n",  				button->gpio, error); -			goto fail; +			return error;  		}  		bdata->irq = irq; @@ -496,26 +509,33 @@ static int gpio_keys_setup_key(struct platform_device *pdev,  	input_set_capability(input, button->type ?: EV_KEY, button->code);  	/* +	 * Install custom action to cancel debounce timer and +	 * workqueue item. +	 */ +	error = devm_add_action(&pdev->dev, gpio_keys_quiesce_key, bdata); +	if (error) { +		dev_err(&pdev->dev, +			"failed to register quiesce action, error: %d\n", +			error); +		return error; +	} + +	/*  	 * If platform has specified that the button can be disabled,  	 * we don't want it to share the interrupt line.  	 */  	if (!button->can_disable)  		irqflags |= IRQF_SHARED; -	error = request_any_context_irq(bdata->irq, isr, irqflags, desc, bdata); +	error = devm_request_any_context_irq(&pdev->dev, bdata->irq, +					     isr, irqflags, desc, bdata);  	if (error < 0) {  		dev_err(dev, "Unable to claim irq %d; error %d\n",  			bdata->irq, error); -		goto fail; +		return error;  	}  	return 0; - -fail: -	if (gpio_is_valid(button->gpio)) -		gpio_free(button->gpio); - -	return error;  }  static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata) @@ -577,23 +597,18 @@ gpio_keys_get_devtree_pdata(struct device *dev)  	int i;  	node = dev->of_node; -	if (!node) { -		error = -ENODEV; -		goto err_out; -	} +	if (!node) +		return ERR_PTR(-ENODEV);  	nbuttons = of_get_child_count(node); -	if (nbuttons == 0) { -		error = -ENODEV; -		goto err_out; -	} +	if (nbuttons == 0) +		return ERR_PTR(-ENODEV); -	pdata = kzalloc(sizeof(*pdata) + nbuttons * (sizeof *button), -			GFP_KERNEL); -	if (!pdata) { -		error = -ENOMEM; -		goto err_out; -	} +	pdata = devm_kzalloc(dev, +			     sizeof(*pdata) + nbuttons * sizeof(*button), +			     GFP_KERNEL); +	if (!pdata) +		return ERR_PTR(-ENOMEM);  	pdata->buttons = (struct gpio_keys_button *)(pdata + 1);  	pdata->nbuttons = nbuttons; @@ -618,7 +633,7 @@ gpio_keys_get_devtree_pdata(struct device *dev)  				dev_err(dev,  					"Failed to get gpio flags, error: %d\n",  					error); -			goto err_free_pdata; +			return ERR_PTR(error);  		}  		button = &pdata->buttons[i++]; @@ -629,8 +644,7 @@ gpio_keys_get_devtree_pdata(struct device *dev)  		if (of_property_read_u32(pp, "linux,code", &button->code)) {  			dev_err(dev, "Button without keycode: 0x%x\n",  				button->gpio); -			error = -EINVAL; -			goto err_free_pdata; +			return ERR_PTR(-EINVAL);  		}  		button->desc = of_get_property(pp, "label", NULL); @@ -645,20 +659,13 @@ gpio_keys_get_devtree_pdata(struct device *dev)  			button->debounce_interval = 5;  	} -	if (pdata->nbuttons == 0) { -		error = -EINVAL; -		goto err_free_pdata; -	} +	if (pdata->nbuttons == 0) +		return ERR_PTR(-EINVAL);  	return pdata; - -err_free_pdata: -	kfree(pdata); -err_out: -	return ERR_PTR(error);  } -static struct of_device_id gpio_keys_of_match[] = { +static const struct of_device_id gpio_keys_of_match[] = {  	{ .compatible = "gpio-keys", },  	{ },  }; @@ -674,22 +681,13 @@ gpio_keys_get_devtree_pdata(struct device *dev)  #endif -static void gpio_remove_key(struct gpio_button_data *bdata) -{ -	free_irq(bdata->irq, bdata); -	if (bdata->timer_debounce) -		del_timer_sync(&bdata->timer); -	cancel_work_sync(&bdata->work); -	if (gpio_is_valid(bdata->button->gpio)) -		gpio_free(bdata->button->gpio); -} -  static int gpio_keys_probe(struct platform_device *pdev)  {  	struct device *dev = &pdev->dev;  	const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);  	struct gpio_keys_drvdata *ddata;  	struct input_dev *input; +	size_t size;  	int i, error;  	int wakeup = 0; @@ -699,14 +697,18 @@ static int gpio_keys_probe(struct platform_device *pdev)  			return PTR_ERR(pdata);  	} -	ddata = kzalloc(sizeof(struct gpio_keys_drvdata) + -			pdata->nbuttons * sizeof(struct gpio_button_data), -			GFP_KERNEL); -	input = input_allocate_device(); -	if (!ddata || !input) { +	size = sizeof(struct gpio_keys_drvdata) + +			pdata->nbuttons * sizeof(struct gpio_button_data); +	ddata = devm_kzalloc(dev, size, GFP_KERNEL); +	if (!ddata) {  		dev_err(dev, "failed to allocate state\n"); -		error = -ENOMEM; -		goto fail1; +		return -ENOMEM; +	} + +	input = devm_input_allocate_device(dev); +	if (!input) { +		dev_err(dev, "failed to allocate input device\n"); +		return -ENOMEM;  	}  	ddata->pdata = pdata; @@ -737,7 +739,7 @@ static int gpio_keys_probe(struct platform_device *pdev)  		error = gpio_keys_setup_key(pdev, input, bdata, button);  		if (error) -			goto fail2; +			return error;  		if (button->wakeup)  			wakeup = 1; @@ -747,57 +749,31 @@ static int gpio_keys_probe(struct platform_device *pdev)  	if (error) {  		dev_err(dev, "Unable to export keys/switches, error: %d\n",  			error); -		goto fail2; +		return error;  	}  	error = input_register_device(input);  	if (error) {  		dev_err(dev, "Unable to register input device, error: %d\n",  			error); -		goto fail3; +		goto err_remove_group;  	}  	device_init_wakeup(&pdev->dev, wakeup);  	return 0; - fail3: +err_remove_group:  	sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group); - fail2: -	while (--i >= 0) -		gpio_remove_key(&ddata->data[i]); - - fail1: -	input_free_device(input); -	kfree(ddata); -	/* If we have no platform data, we allocated pdata dynamically. */ -	if (!dev_get_platdata(&pdev->dev)) -		kfree(pdata); -  	return error;  }  static int gpio_keys_remove(struct platform_device *pdev)  { -	struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); -	struct input_dev *input = ddata->input; -	int i; -  	sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);  	device_init_wakeup(&pdev->dev, 0); -	for (i = 0; i < ddata->pdata->nbuttons; i++) -		gpio_remove_key(&ddata->data[i]); - -	input_unregister_device(input); - -	/* If we have no platform data, we allocated pdata dynamically. */ -	if (!dev_get_platdata(&pdev->dev)) -		kfree(ddata->pdata); - -	kfree(ddata); -  	return 0;  } diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index cd5ed9e2216..432d36395f3 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -17,7 +17,6 @@  #include <linux/kernel.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/input-polldev.h> @@ -25,6 +24,7 @@  #include <linux/platform_device.h>  #include <linux/gpio.h>  #include <linux/gpio_keys.h> +#include <linux/of.h>  #include <linux/of_platform.h>  #include <linux/of_gpio.h> @@ -120,12 +120,10 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct  	if (nbuttons == 0)  		return NULL; -	pdata = kzalloc(sizeof(*pdata) + nbuttons * (sizeof *button), -			GFP_KERNEL); -	if (!pdata) { -		error = -ENOMEM; -		goto err_out; -	} +	pdata = devm_kzalloc(dev, sizeof(*pdata) + nbuttons * sizeof(*button), +			     GFP_KERNEL); +	if (!pdata) +		return ERR_PTR(-ENOMEM);  	pdata->buttons = (struct gpio_keys_button *)(pdata + 1);  	pdata->nbuttons = nbuttons; @@ -151,7 +149,7 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct  				dev_err(dev,  					"Failed to get gpio flags, error: %d\n",  					error); -			goto err_free_pdata; +			return ERR_PTR(error);  		}  		button = &pdata->buttons[i++]; @@ -162,8 +160,7 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct  		if (of_property_read_u32(pp, "linux,code", &button->code)) {  			dev_err(dev, "Button without keycode: 0x%x\n",  				button->gpio); -			error = -EINVAL; -			goto err_free_pdata; +			return ERR_PTR(-EINVAL);  		}  		button->desc = of_get_property(pp, "label", NULL); @@ -178,20 +175,13 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct  			button->debounce_interval = 5;  	} -	if (pdata->nbuttons == 0) { -		error = -EINVAL; -		goto err_free_pdata; -	} +	if (pdata->nbuttons == 0) +		return ERR_PTR(-EINVAL);  	return pdata; - -err_free_pdata: -	kfree(pdata); -err_out: -	return ERR_PTR(error);  } -static struct of_device_id gpio_keys_polled_of_match[] = { +static const struct of_device_id gpio_keys_polled_of_match[] = {  	{ .compatible = "gpio-keys-polled", },  	{ },  }; @@ -213,6 +203,7 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)  	struct gpio_keys_polled_dev *bdev;  	struct input_polled_dev *poll_dev;  	struct input_dev *input; +	size_t size;  	int error;  	int i; @@ -228,24 +219,21 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)  	if (!pdata->poll_interval) {  		dev_err(dev, "missing poll_interval value\n"); -		error = -EINVAL; -		goto err_free_pdata; +		return -EINVAL;  	} -	bdev = kzalloc(sizeof(struct gpio_keys_polled_dev) + -		       pdata->nbuttons * sizeof(struct gpio_keys_button_data), -		       GFP_KERNEL); +	size = sizeof(struct gpio_keys_polled_dev) + +			pdata->nbuttons * sizeof(struct gpio_keys_button_data); +	bdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);  	if (!bdev) {  		dev_err(dev, "no memory for private data\n"); -		error = -ENOMEM; -		goto err_free_pdata; +		return -ENOMEM;  	} -	poll_dev = input_allocate_polled_device(); +	poll_dev = devm_input_allocate_polled_device(&pdev->dev);  	if (!poll_dev) {  		dev_err(dev, "no memory for polled device\n"); -		error = -ENOMEM; -		goto err_free_bdev; +		return -ENOMEM;  	}  	poll_dev->private = bdev; @@ -258,7 +246,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)  	input->name = pdev->name;  	input->phys = DRV_NAME"/input0"; -	input->dev.parent = &pdev->dev;  	input->id.bustype = BUS_HOST;  	input->id.vendor = 0x0001; @@ -277,16 +264,15 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)  		if (button->wakeup) {  			dev_err(dev, DRV_NAME " does not support wakeup\n"); -			error = -EINVAL; -			goto err_free_gpio; +			return -EINVAL;  		} -		error = gpio_request_one(gpio, GPIOF_IN, -					 button->desc ?: DRV_NAME); +		error = devm_gpio_request_one(&pdev->dev, gpio, GPIOF_IN, +					      button->desc ? : DRV_NAME);  		if (error) {  			dev_err(dev, "unable to claim gpio %u, err=%d\n",  				gpio, error); -			goto err_free_gpio; +			return error;  		}  		bdata->can_sleep = gpio_cansleep(gpio); @@ -306,7 +292,7 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)  	if (error) {  		dev_err(dev, "unable to register polled device, err=%d\n",  			error); -		goto err_free_gpio; +		return error;  	}  	/* report initial state of the buttons */ @@ -315,52 +301,10 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)  					     &bdev->data[i]);  	return 0; - -err_free_gpio: -	while (--i >= 0) -		gpio_free(pdata->buttons[i].gpio); - -	input_free_polled_device(poll_dev); - -err_free_bdev: -	kfree(bdev); - -err_free_pdata: -	/* If we have no platform_data, we allocated pdata dynamically.  */ -	if (!dev_get_platdata(&pdev->dev)) -		kfree(pdata); - -	return error; -} - -static int gpio_keys_polled_remove(struct platform_device *pdev) -{ -	struct gpio_keys_polled_dev *bdev = platform_get_drvdata(pdev); -	const struct gpio_keys_platform_data *pdata = bdev->pdata; -	int i; - -	input_unregister_polled_device(bdev->poll_dev); - -	for (i = 0; i < pdata->nbuttons; i++) -		gpio_free(pdata->buttons[i].gpio); - -	input_free_polled_device(bdev->poll_dev); - -	/* -	 * If we had no platform_data, we allocated pdata dynamically and -	 * must free it here. -	 */ -	if (!dev_get_platdata(&pdev->dev)) -		kfree(pdata); - -	kfree(bdev); - -	return 0;  }  static struct platform_driver gpio_keys_polled_driver = {  	.probe	= gpio_keys_polled_probe, -	.remove	= gpio_keys_polled_remove,  	.driver	= {  		.name	= DRV_NAME,  		.owner	= THIS_MODULE, diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c index 589e3c258f3..610a8af795a 100644 --- a/drivers/input/keyboard/hil_kbd.c +++ b/drivers/input/keyboard/hil_kbd.c @@ -36,7 +36,6 @@  #include <linux/serio.h>  #include <linux/kernel.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/completion.h>  #include <linux/slab.h>  #include <linux/pci_ids.h> diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index 328cfc1eed9..8280cb16260 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -13,7 +13,6 @@  #include <linux/delay.h>  #include <linux/device.h>  #include <linux/err.h> -#include <linux/init.h>  #include <linux/input/matrix_keypad.h>  #include <linux/interrupt.h>  #include <linux/io.h> @@ -416,7 +415,7 @@ open_err:  }  #ifdef CONFIG_OF -static struct of_device_id imx_keypad_of_match[] = { +static const struct of_device_id imx_keypad_of_match[] = {  	{ .compatible = "fsl,imx21-kpp", },  	{ /* sentinel */ }  }; @@ -425,7 +424,8 @@ MODULE_DEVICE_TABLE(of, imx_keypad_of_match);  static int imx_keypad_probe(struct platform_device *pdev)  { -	const struct matrix_keymap_data *keymap_data = pdev->dev.platform_data; +	const struct matrix_keymap_data *keymap_data = +			dev_get_platdata(&pdev->dev);  	struct imx_keypad *keypad;  	struct input_dev *input_dev;  	struct resource *res; @@ -439,7 +439,7 @@ static int imx_keypad_probe(struct platform_device *pdev)  	irq = platform_get_irq(pdev, 0);  	if (irq < 0) {  		dev_err(&pdev->dev, "no irq defined in platform data\n"); -		return -EINVAL; +		return irq;  	}  	input_dev = devm_input_allocate_device(&pdev->dev); @@ -449,7 +449,7 @@ static int imx_keypad_probe(struct platform_device *pdev)  	}  	keypad = devm_kzalloc(&pdev->dev, sizeof(struct imx_keypad), -			     GFP_KERNEL); +			      GFP_KERNEL);  	if (!keypad) {  		dev_err(&pdev->dev, "not enough memory for driver data\n");  		return -ENOMEM; diff --git a/drivers/input/keyboard/jornada680_kbd.c b/drivers/input/keyboard/jornada680_kbd.c index a2a034c25f0..0ba4428da24 100644 --- a/drivers/input/keyboard/jornada680_kbd.c +++ b/drivers/input/keyboard/jornada680_kbd.c @@ -16,7 +16,7 @@   * published by the Free Software Foundation.   */ -#include <linux/init.h> +#include <linux/device.h>  #include <linux/input.h>  #include <linux/input-polldev.h>  #include <linux/interrupt.h> @@ -186,14 +186,15 @@ static int jornada680kbd_probe(struct platform_device *pdev)  	struct input_dev *input_dev;  	int i, error; -	jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL); +	jornadakbd = devm_kzalloc(&pdev->dev, sizeof(struct jornadakbd), +				  GFP_KERNEL);  	if (!jornadakbd)  		return -ENOMEM; -	poll_dev = input_allocate_polled_device(); +	poll_dev = devm_input_allocate_polled_device(&pdev->dev);  	if (!poll_dev) { -		error = -ENOMEM; -		goto failed; +		dev_err(&pdev->dev, "failed to allocate polled input device\n"); +		return -ENOMEM;  	}  	platform_set_drvdata(pdev, jornadakbd); @@ -225,27 +226,10 @@ static int jornada680kbd_probe(struct platform_device *pdev)  	input_set_capability(input_dev, EV_MSC, MSC_SCAN);  	error = input_register_polled_device(jornadakbd->poll_dev); -	if (error) -		goto failed; - -	return 0; - - failed: -	printk(KERN_ERR "Jornadakbd: failed to register driver, error: %d\n", -		error); -	input_free_polled_device(poll_dev); -	kfree(jornadakbd); -	return error; - -} - -static int jornada680kbd_remove(struct platform_device *pdev) -{ -	struct jornadakbd *jornadakbd = platform_get_drvdata(pdev); - -	input_unregister_polled_device(jornadakbd->poll_dev); -	input_free_polled_device(jornadakbd->poll_dev); -	kfree(jornadakbd); +	if (error) { +		dev_err(&pdev->dev, "failed to register polled input device\n"); +		return error; +	}  	return 0;  } @@ -256,7 +240,6 @@ static struct platform_driver jornada680kbd_driver = {  		.owner	= THIS_MODULE,  	},  	.probe	= jornada680kbd_probe, -	.remove	= jornada680kbd_remove,  };  module_platform_driver(jornada680kbd_driver); diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c index b0ad457ca9d..cd729d485e9 100644 --- a/drivers/input/keyboard/jornada720_kbd.c +++ b/drivers/input/keyboard/jornada720_kbd.c @@ -18,7 +18,6 @@  #include <linux/device.h>  #include <linux/errno.h>  #include <linux/interrupt.h> -#include <linux/init.h>  #include <linux/input.h>  #include <linux/kernel.h>  #include <linux/module.h> diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c index fc0a63c2f27..9fcd9f1d5dc 100644 --- a/drivers/input/keyboard/lkkbd.c +++ b/drivers/input/keyboard/lkkbd.c @@ -65,7 +65,6 @@  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/interrupt.h> -#include <linux/init.h>  #include <linux/input.h>  #include <linux/serio.h>  #include <linux/workqueue.h> diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index 0de23f41b2d..0b42118cbf8 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -627,7 +627,7 @@ static DEVICE_ATTR(disable_kp, 0644, lm8323_show_disable, lm8323_set_disable);  static int lm8323_probe(struct i2c_client *client,  				  const struct i2c_device_id *id)  { -	struct lm8323_platform_data *pdata = client->dev.platform_data; +	struct lm8323_platform_data *pdata = dev_get_platdata(&client->dev);  	struct input_dev *idev;  	struct lm8323_chip *lm;  	int pwm; diff --git a/drivers/input/keyboard/lm8333.c b/drivers/input/keyboard/lm8333.c index 5a8ca35dc9a..9081cbef11e 100644 --- a/drivers/input/keyboard/lm8333.c +++ b/drivers/input/keyboard/lm8333.c @@ -131,7 +131,8 @@ static irqreturn_t lm8333_irq_thread(int irq, void *data)  static int lm8333_probe(struct i2c_client *client,  				  const struct i2c_device_id *id)  { -	const struct lm8333_platform_data *pdata = client->dev.platform_data; +	const struct lm8333_platform_data *pdata = +			dev_get_platdata(&client->dev);  	struct lm8333 *lm8333;  	struct input_dev *input;  	int err, active_time; diff --git a/drivers/input/keyboard/lpc32xx-keys.c b/drivers/input/keyboard/lpc32xx-keys.c index 42181435fe6..8b1b01361ec 100644 --- a/drivers/input/keyboard/lpc32xx-keys.c +++ b/drivers/input/keyboard/lpc32xx-keys.c @@ -383,7 +383,7 @@ static struct platform_driver lpc32xx_kscan_driver = {  		.name	= DRV_NAME,  		.owner	= THIS_MODULE,  		.pm	= &lpc32xx_kscan_pm_ops, -		.of_match_table = of_match_ptr(lpc32xx_kscan_match), +		.of_match_table = lpc32xx_kscan_match,  	}  }; diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index 90ff73ace42..8d2e19e81e1 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -14,7 +14,6 @@  #include <linux/types.h>  #include <linux/delay.h>  #include <linux/platform_device.h> -#include <linux/init.h>  #include <linux/input.h>  #include <linux/irq.h>  #include <linux/interrupt.h> diff --git a/drivers/input/keyboard/max7359_keypad.c b/drivers/input/keyboard/max7359_keypad.c index bc2cdaf563f..430b5453972 100644 --- a/drivers/input/keyboard/max7359_keypad.c +++ b/drivers/input/keyboard/max7359_keypad.c @@ -182,7 +182,8 @@ static void max7359_initialize(struct i2c_client *client)  static int max7359_probe(struct i2c_client *client,  					const struct i2c_device_id *id)  { -	const struct matrix_keymap_data *keymap_data = client->dev.platform_data; +	const struct matrix_keymap_data *keymap_data = +			dev_get_platdata(&client->dev);  	struct max7359_keypad *keypad;  	struct input_dev *input_dev;  	int ret; diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c index 7c236f9c6a5..375b05ca8e2 100644 --- a/drivers/input/keyboard/mcs_touchkey.c +++ b/drivers/input/keyboard/mcs_touchkey.c @@ -12,7 +12,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/i2c.h>  #include <linux/i2c/mcs.h>  #include <linux/interrupt.h> @@ -108,7 +107,7 @@ static int mcs_touchkey_probe(struct i2c_client *client,  	int error;  	int i; -	pdata = client->dev.platform_data; +	pdata = dev_get_platdata(&client->dev);  	if (!pdata) {  		dev_err(&client->dev, "no platform data defined\n");  		return -EINVAL; @@ -148,7 +147,7 @@ static int mcs_touchkey_probe(struct i2c_client *client,  	}  	dev_info(&client->dev, "Firmware version: %d\n", fw_ver); -	input_dev->name = "MELPAS MCS Touchkey"; +	input_dev->name = "MELFAS MCS Touchkey";  	input_dev->id.bustype = BUS_I2C;  	input_dev->dev.parent = &client->dev;  	input_dev->evbit[0] = BIT_MASK(EV_KEY); diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c index f7f3e9a9fd3..009c82256e8 100644 --- a/drivers/input/keyboard/mpr121_touchkey.c +++ b/drivers/input/keyboard/mpr121_touchkey.c @@ -13,7 +13,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/input.h>  #include <linux/i2c.h>  #include <linux/slab.h> @@ -188,7 +187,8 @@ err_i2c_write:  static int mpr_touchkey_probe(struct i2c_client *client,  			      const struct i2c_device_id *id)  { -	const struct mpr121_platform_data *pdata = client->dev.platform_data; +	const struct mpr121_platform_data *pdata = +			dev_get_platdata(&client->dev);  	struct mpr121_touchkey *mpr121;  	struct input_dev *input_dev;  	int error; diff --git a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c index f971898ad59..20f04437799 100644 --- a/drivers/input/keyboard/newtonkbd.c +++ b/drivers/input/keyboard/newtonkbd.c @@ -29,7 +29,6 @@  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/input.h> -#include <linux/init.h>  #include <linux/serio.h>  #define DRIVER_DESC	"Newton keyboard driver" diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c index c7d505cce72..63332e2f862 100644 --- a/drivers/input/keyboard/nomadik-ske-keypad.c +++ b/drivers/input/keyboard/nomadik-ske-keypad.c @@ -222,7 +222,8 @@ static irqreturn_t ske_keypad_irq(int irq, void *dev_id)  static int __init ske_keypad_probe(struct platform_device *pdev)  { -	const struct ske_keypad_platform_data *plat = pdev->dev.platform_data; +	const struct ske_keypad_platform_data *plat = +			dev_get_platdata(&pdev->dev);  	struct ske_keypad *keypad;  	struct input_dev *input;  	struct resource *res; diff --git a/drivers/input/keyboard/nspire-keypad.c b/drivers/input/keyboard/nspire-keypad.c index b3e3edab6d9..b31064981e9 100644 --- a/drivers/input/keyboard/nspire-keypad.c +++ b/drivers/input/keyboard/nspire-keypad.c @@ -143,8 +143,10 @@ static int nspire_keypad_open(struct input_dev *input)  		return error;  	error = nspire_keypad_chip_init(keypad); -	if (error) +	if (error) { +		clk_disable_unprepare(keypad->clk);  		return error; +	}  	return 0;  } @@ -267,7 +269,7 @@ static struct platform_driver nspire_keypad_driver = {  	.driver = {  		.name = "nspire-keypad",  		.owner = THIS_MODULE, -		.of_match_table = of_match_ptr(nspire_keypad_dt_match), +		.of_match_table = nspire_keypad_dt_match,  	},  	.probe = nspire_keypad_probe,  }; diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c index d0d5226d9cd..b1acc9852eb 100644 --- a/drivers/input/keyboard/omap-keypad.c +++ b/drivers/input/keyboard/omap-keypad.c @@ -25,7 +25,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/types.h>  #include <linux/input.h> @@ -248,7 +247,7 @@ static int omap_kp_probe(struct platform_device *pdev)  {  	struct omap_kp *omap_kp;  	struct input_dev *input_dev; -	struct omap_kp_platform_data *pdata =  pdev->dev.platform_data; +	struct omap_kp_platform_data *pdata = dev_get_platdata(&pdev->dev);  	int i, col_idx, row_idx, ret;  	unsigned int row_shift, keycodemax; diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index 30acfd49fa6..024b7bdffe5 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -22,18 +22,16 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/platform_device.h>  #include <linux/errno.h>  #include <linux/io.h>  #include <linux/of.h>  #include <linux/input.h> +#include <linux/input/matrix_keypad.h>  #include <linux/slab.h>  #include <linux/pm_runtime.h> -#include <linux/platform_data/omap4-keypad.h> -  /* OMAP4 registers */  #define OMAP4_KBD_REVISION		0x00  #define OMAP4_KBD_SYSCONFIG		0x10 @@ -219,7 +217,6 @@ static void omap4_keypad_close(struct input_dev *input)  	pm_runtime_put_sync(input->dev.parent);  } -#ifdef CONFIG_OF  static int omap4_keypad_parse_dt(struct device *dev,  				 struct omap4_keypad *keypad_data)  { @@ -236,20 +233,9 @@ static int omap4_keypad_parse_dt(struct device *dev,  	return 0;  } -#else -static inline int omap4_keypad_parse_dt(struct device *dev, -					struct omap4_keypad *keypad_data) -{ -	return -ENOSYS; -} -#endif  static int omap4_keypad_probe(struct platform_device *pdev)  { -	const struct omap4_keypad_platform_data *pdata = -				dev_get_platdata(&pdev->dev); -	const struct matrix_keymap_data *keymap_data = -				pdata ? pdata->keymap_data : NULL;  	struct omap4_keypad *keypad_data;  	struct input_dev *input_dev;  	struct resource *res; @@ -278,14 +264,9 @@ static int omap4_keypad_probe(struct platform_device *pdev)  	keypad_data->irq = irq; -	if (pdata) { -		keypad_data->rows = pdata->rows; -		keypad_data->cols = pdata->cols; -	} else { -		error = omap4_keypad_parse_dt(&pdev->dev, keypad_data); -		if (error) -			return error; -	} +	error = omap4_keypad_parse_dt(&pdev->dev, keypad_data); +	if (error) +		return error;  	res = request_mem_region(res->start, resource_size(res), pdev->name);  	if (!res) { @@ -364,7 +345,7 @@ static int omap4_keypad_probe(struct platform_device *pdev)  		goto err_free_input;  	} -	error = matrix_keypad_build_keymap(keymap_data, NULL, +	error = matrix_keypad_build_keymap(NULL, NULL,  					   keypad_data->rows, keypad_data->cols,  					   keypad_data->keymap, input_dev);  	if (error) { @@ -435,13 +416,11 @@ static int omap4_keypad_remove(struct platform_device *pdev)  	return 0;  } -#ifdef CONFIG_OF  static const struct of_device_id omap_keypad_dt_match[] = {  	{ .compatible = "ti,omap4-keypad" },  	{},  };  MODULE_DEVICE_TABLE(of, omap_keypad_dt_match); -#endif  #ifdef CONFIG_PM_SLEEP  static int omap4_keypad_suspend(struct device *dev) @@ -483,7 +462,7 @@ static struct platform_driver omap4_keypad_driver = {  		.name	= "omap4-keypad",  		.owner	= THIS_MODULE,  		.pm	= &omap4_keypad_pm_ops, -		.of_match_table = of_match_ptr(omap_keypad_dt_match), +		.of_match_table = omap_keypad_dt_match,  	},  };  module_platform_driver(omap4_keypad_driver); diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c index 2c9f19ac35e..80c6b0ef3fc 100644 --- a/drivers/input/keyboard/pmic8xxx-keypad.c +++ b/drivers/input/keyboard/pmic8xxx-keypad.c @@ -19,10 +19,9 @@  #include <linux/bitops.h>  #include <linux/delay.h>  #include <linux/mutex.h> - -#include <linux/mfd/pm8xxx/core.h> -#include <linux/mfd/pm8xxx/gpio.h> -#include <linux/input/pmic8xxx-keypad.h> +#include <linux/regmap.h> +#include <linux/of.h> +#include <linux/input/matrix_keypad.h>  #define PM8XXX_MAX_ROWS		18  #define PM8XXX_MAX_COLS		8 @@ -85,8 +84,10 @@  /**   * struct pmic8xxx_kp - internal keypad data structure - * @pdata - keypad platform data pointer + * @num_cols - number of columns of keypad + * @num_rows - number of row of keypad   * @input - input device pointer for keypad + * @regmap - regmap handle   * @key_sense_irq - key press/release irq number   * @key_stuck_irq - key stuck notification irq number   * @keycodes - array to hold the key codes @@ -96,8 +97,10 @@   * @ctrl_reg - control register value   */  struct pmic8xxx_kp { -	const struct pm8xxx_keypad_platform_data *pdata; +	unsigned int num_rows; +	unsigned int num_cols;  	struct input_dev *input; +	struct regmap *regmap;  	int key_sense_irq;  	int key_stuck_irq; @@ -110,40 +113,13 @@ struct pmic8xxx_kp {  	u8 ctrl_reg;  }; -static int pmic8xxx_kp_write_u8(struct pmic8xxx_kp *kp, -				 u8 data, u16 reg) -{ -	int rc; - -	rc = pm8xxx_writeb(kp->dev->parent, reg, data); -	return rc; -} - -static int pmic8xxx_kp_read(struct pmic8xxx_kp *kp, -				 u8 *data, u16 reg, unsigned num_bytes) -{ -	int rc; - -	rc = pm8xxx_read_buf(kp->dev->parent, reg, data, num_bytes); -	return rc; -} - -static int pmic8xxx_kp_read_u8(struct pmic8xxx_kp *kp, -				 u8 *data, u16 reg) -{ -	int rc; - -	rc = pmic8xxx_kp_read(kp, data, reg, 1); -	return rc; -} -  static u8 pmic8xxx_col_state(struct pmic8xxx_kp *kp, u8 col)  {  	/* all keys pressed on that particular row? */  	if (col == 0x00) -		return 1 << kp->pdata->num_cols; +		return 1 << kp->num_cols;  	else -		return col & ((1 << kp->pdata->num_cols) - 1); +		return col & ((1 << kp->num_cols) - 1);  }  /* @@ -161,9 +137,9 @@ static u8 pmic8xxx_col_state(struct pmic8xxx_kp *kp, u8 col)  static int pmic8xxx_chk_sync_read(struct pmic8xxx_kp *kp)  {  	int rc; -	u8 scan_val; +	unsigned int scan_val; -	rc = pmic8xxx_kp_read_u8(kp, &scan_val, KEYP_SCAN); +	rc = regmap_read(kp->regmap, KEYP_SCAN, &scan_val);  	if (rc < 0) {  		dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc);  		return rc; @@ -171,7 +147,7 @@ static int pmic8xxx_chk_sync_read(struct pmic8xxx_kp *kp)  	scan_val |= 0x1; -	rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN); +	rc = regmap_write(kp->regmap, KEYP_SCAN, scan_val);  	if (rc < 0) {  		dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc);  		return rc; @@ -187,31 +163,29 @@ static int pmic8xxx_kp_read_data(struct pmic8xxx_kp *kp, u16 *state,  					u16 data_reg, int read_rows)  {  	int rc, row; -	u8 new_data[PM8XXX_MAX_ROWS]; - -	rc = pmic8xxx_kp_read(kp, new_data, data_reg, read_rows); -	if (rc) -		return rc; +	unsigned int val; -	for (row = 0; row < kp->pdata->num_rows; row++) { -		dev_dbg(kp->dev, "new_data[%d] = %d\n", row, -					new_data[row]); -		state[row] = pmic8xxx_col_state(kp, new_data[row]); +	for (row = 0; row < read_rows; row++) { +		rc = regmap_read(kp->regmap, data_reg, &val); +		if (rc) +			return rc; +		dev_dbg(kp->dev, "%d = %d\n", row, val); +		state[row] = pmic8xxx_col_state(kp, val);  	} -	return rc; +	return 0;  }  static int pmic8xxx_kp_read_matrix(struct pmic8xxx_kp *kp, u16 *new_state,  					 u16 *old_state)  {  	int rc, read_rows; -	u8 scan_val; +	unsigned int scan_val; -	if (kp->pdata->num_rows < PM8XXX_MIN_ROWS) +	if (kp->num_rows < PM8XXX_MIN_ROWS)  		read_rows = PM8XXX_MIN_ROWS;  	else -		read_rows = kp->pdata->num_rows; +		read_rows = kp->num_rows;  	pmic8xxx_chk_sync_read(kp); @@ -236,14 +210,14 @@ static int pmic8xxx_kp_read_matrix(struct pmic8xxx_kp *kp, u16 *new_state,  	/* 4 * 32KHz clocks */  	udelay((4 * DIV_ROUND_UP(USEC_PER_SEC, KEYP_CLOCK_FREQ)) + 1); -	rc = pmic8xxx_kp_read_u8(kp, &scan_val, KEYP_SCAN); +	rc = regmap_read(kp->regmap, KEYP_SCAN, &scan_val);  	if (rc < 0) {  		dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc);  		return rc;  	}  	scan_val &= 0xFE; -	rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN); +	rc = regmap_write(kp->regmap, KEYP_SCAN, scan_val);  	if (rc < 0)  		dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc); @@ -255,13 +229,13 @@ static void __pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, u16 *new_state,  {  	int row, col, code; -	for (row = 0; row < kp->pdata->num_rows; row++) { +	for (row = 0; row < kp->num_rows; row++) {  		int bits_changed = new_state[row] ^ old_state[row];  		if (!bits_changed)  			continue; -		for (col = 0; col < kp->pdata->num_cols; col++) { +		for (col = 0; col < kp->num_cols; col++) {  			if (!(bits_changed & (1 << col)))  				continue; @@ -287,9 +261,9 @@ static bool pmic8xxx_detect_ghost_keys(struct pmic8xxx_kp *kp, u16 *new_state)  	u16 check, row_state;  	check = 0; -	for (row = 0; row < kp->pdata->num_rows; row++) { +	for (row = 0; row < kp->num_rows; row++) {  		row_state = (~new_state[row]) & -				 ((1 << kp->pdata->num_cols) - 1); +				 ((1 << kp->num_cols) - 1);  		if (hweight16(row_state) > 1) {  			if (found_first == -1) @@ -379,10 +353,10 @@ static irqreturn_t pmic8xxx_kp_stuck_irq(int irq, void *data)  static irqreturn_t pmic8xxx_kp_irq(int irq, void *data)  {  	struct pmic8xxx_kp *kp = data; -	u8 ctrl_val, events; +	unsigned int ctrl_val, events;  	int rc; -	rc = pmic8xxx_kp_read(kp, &ctrl_val, KEYP_CTRL, 1); +	rc = regmap_read(kp->regmap, KEYP_CTRL, &ctrl_val);  	if (rc < 0) {  		dev_err(kp->dev, "failed to read keyp_ctrl register\n");  		return IRQ_HANDLED; @@ -397,8 +371,13 @@ static irqreturn_t pmic8xxx_kp_irq(int irq, void *data)  	return IRQ_HANDLED;  } -static int pmic8xxx_kpd_init(struct pmic8xxx_kp *kp) +static int pmic8xxx_kpd_init(struct pmic8xxx_kp *kp, +			     struct platform_device *pdev)  { +	const struct device_node *of_node = pdev->dev.of_node; +	unsigned int scan_delay_ms; +	unsigned int row_hold_ns; +	unsigned int debounce_ms;  	int bits, rc, cycles;  	u8 scan_val = 0, ctrl_val = 0;  	static const u8 row_bits[] = { @@ -406,40 +385,69 @@ static int pmic8xxx_kpd_init(struct pmic8xxx_kp *kp)  	};  	/* Find column bits */ -	if (kp->pdata->num_cols < KEYP_CTRL_SCAN_COLS_MIN) +	if (kp->num_cols < KEYP_CTRL_SCAN_COLS_MIN)  		bits = 0;  	else -		bits = kp->pdata->num_cols - KEYP_CTRL_SCAN_COLS_MIN; +		bits = kp->num_cols - KEYP_CTRL_SCAN_COLS_MIN;  	ctrl_val = (bits & KEYP_CTRL_SCAN_COLS_BITS) <<  		KEYP_CTRL_SCAN_COLS_SHIFT;  	/* Find row bits */ -	if (kp->pdata->num_rows < KEYP_CTRL_SCAN_ROWS_MIN) +	if (kp->num_rows < KEYP_CTRL_SCAN_ROWS_MIN)  		bits = 0;  	else -		bits = row_bits[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN]; +		bits = row_bits[kp->num_rows - KEYP_CTRL_SCAN_ROWS_MIN];  	ctrl_val |= (bits << KEYP_CTRL_SCAN_ROWS_SHIFT); -	rc = pmic8xxx_kp_write_u8(kp, ctrl_val, KEYP_CTRL); +	rc = regmap_write(kp->regmap, KEYP_CTRL, ctrl_val);  	if (rc < 0) {  		dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc);  		return rc;  	} -	bits = (kp->pdata->debounce_ms / 5) - 1; +	if (of_property_read_u32(of_node, "scan-delay", &scan_delay_ms)) +		scan_delay_ms = MIN_SCAN_DELAY; + +	if (scan_delay_ms > MAX_SCAN_DELAY || scan_delay_ms < MIN_SCAN_DELAY || +	    !is_power_of_2(scan_delay_ms)) { +		dev_err(&pdev->dev, "invalid keypad scan time supplied\n"); +		return -EINVAL; +	} + +	if (of_property_read_u32(of_node, "row-hold", &row_hold_ns)) +		row_hold_ns = MIN_ROW_HOLD_DELAY; + +	if (row_hold_ns > MAX_ROW_HOLD_DELAY || +	    row_hold_ns < MIN_ROW_HOLD_DELAY || +	    ((row_hold_ns % MIN_ROW_HOLD_DELAY) != 0)) { +		dev_err(&pdev->dev, "invalid keypad row hold time supplied\n"); +		return -EINVAL; +	} + +	if (of_property_read_u32(of_node, "debounce", &debounce_ms)) +		debounce_ms = MIN_DEBOUNCE_TIME; + +	if (((debounce_ms % 5) != 0) || +	    debounce_ms > MAX_DEBOUNCE_TIME || +	    debounce_ms < MIN_DEBOUNCE_TIME) { +		dev_err(&pdev->dev, "invalid debounce time supplied\n"); +		return -EINVAL; +	} + +	bits = (debounce_ms / 5) - 1;  	scan_val |= (bits << KEYP_SCAN_DBOUNCE_SHIFT); -	bits = fls(kp->pdata->scan_delay_ms) - 1; +	bits = fls(scan_delay_ms) - 1;  	scan_val |= (bits << KEYP_SCAN_PAUSE_SHIFT);  	/* Row hold time is a multiple of 32KHz cycles. */ -	cycles = (kp->pdata->row_hold_ns * KEYP_CLOCK_FREQ) / NSEC_PER_SEC; +	cycles = (row_hold_ns * KEYP_CLOCK_FREQ) / NSEC_PER_SEC;  	scan_val |= (cycles << KEYP_SCAN_ROW_HOLD_SHIFT); -	rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN); +	rc = regmap_write(kp->regmap, KEYP_SCAN, scan_val);  	if (rc)  		dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc); @@ -447,34 +455,13 @@ static int pmic8xxx_kpd_init(struct pmic8xxx_kp *kp)  } -static int  pmic8xxx_kp_config_gpio(int gpio_start, int num_gpios, -			struct pmic8xxx_kp *kp, struct pm_gpio *gpio_config) -{ -	int	rc, i; - -	if (gpio_start < 0 || num_gpios < 0) -		return -EINVAL; - -	for (i = 0; i < num_gpios; i++) { -		rc = pm8xxx_gpio_config(gpio_start + i, gpio_config); -		if (rc) { -			dev_err(kp->dev, "%s: FAIL pm8xxx_gpio_config():" -					"for PM GPIO [%d] rc=%d.\n", -					__func__, gpio_start + i, rc); -			return rc; -		} -	 } - -	return 0; -} -  static int pmic8xxx_kp_enable(struct pmic8xxx_kp *kp)  {  	int rc;  	kp->ctrl_reg |= KEYP_CTRL_KEYP_EN; -	rc = pmic8xxx_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL); +	rc = regmap_write(kp->regmap, KEYP_CTRL, kp->ctrl_reg);  	if (rc < 0)  		dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc); @@ -487,7 +474,7 @@ static int pmic8xxx_kp_disable(struct pmic8xxx_kp *kp)  	kp->ctrl_reg &= ~KEYP_CTRL_KEYP_EN; -	rc = pmic8xxx_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL); +	rc = regmap_write(kp->regmap, KEYP_CTRL, kp->ctrl_reg);  	if (rc < 0)  		return rc; @@ -520,106 +507,62 @@ static void pmic8xxx_kp_close(struct input_dev *dev)   */  static int pmic8xxx_kp_probe(struct platform_device *pdev)  { -	const struct pm8xxx_keypad_platform_data *pdata = -					dev_get_platdata(&pdev->dev); -	const struct matrix_keymap_data *keymap_data; +	unsigned int rows, cols; +	bool repeat; +	bool wakeup;  	struct pmic8xxx_kp *kp;  	int rc; -	u8 ctrl_val; - -	struct pm_gpio kypd_drv = { -		.direction	= PM_GPIO_DIR_OUT, -		.output_buffer	= PM_GPIO_OUT_BUF_OPEN_DRAIN, -		.output_value	= 0, -		.pull		= PM_GPIO_PULL_NO, -		.vin_sel	= PM_GPIO_VIN_S3, -		.out_strength	= PM_GPIO_STRENGTH_LOW, -		.function	= PM_GPIO_FUNC_1, -		.inv_int_pol	= 1, -	}; - -	struct pm_gpio kypd_sns = { -		.direction	= PM_GPIO_DIR_IN, -		.pull		= PM_GPIO_PULL_UP_31P5, -		.vin_sel	= PM_GPIO_VIN_S3, -		.out_strength	= PM_GPIO_STRENGTH_NO, -		.function	= PM_GPIO_FUNC_NORMAL, -		.inv_int_pol	= 1, -	}; +	unsigned int ctrl_val; +	rc = matrix_keypad_parse_of_params(&pdev->dev, &rows, &cols); +	if (rc) +		return rc; -	if (!pdata || !pdata->num_cols || !pdata->num_rows || -		pdata->num_cols > PM8XXX_MAX_COLS || -		pdata->num_rows > PM8XXX_MAX_ROWS || -		pdata->num_cols < PM8XXX_MIN_COLS) { +	if (cols > PM8XXX_MAX_COLS || rows > PM8XXX_MAX_ROWS || +	    cols < PM8XXX_MIN_COLS) {  		dev_err(&pdev->dev, "invalid platform data\n");  		return -EINVAL;  	} -	if (!pdata->scan_delay_ms || -		pdata->scan_delay_ms > MAX_SCAN_DELAY || -		pdata->scan_delay_ms < MIN_SCAN_DELAY || -		!is_power_of_2(pdata->scan_delay_ms)) { -		dev_err(&pdev->dev, "invalid keypad scan time supplied\n"); -		return -EINVAL; -	} - -	if (!pdata->row_hold_ns || -		pdata->row_hold_ns > MAX_ROW_HOLD_DELAY || -		pdata->row_hold_ns < MIN_ROW_HOLD_DELAY || -		((pdata->row_hold_ns % MIN_ROW_HOLD_DELAY) != 0)) { -		dev_err(&pdev->dev, "invalid keypad row hold time supplied\n"); -		return -EINVAL; -	} - -	if (!pdata->debounce_ms || -		((pdata->debounce_ms % 5) != 0) || -		pdata->debounce_ms > MAX_DEBOUNCE_TIME || -		pdata->debounce_ms < MIN_DEBOUNCE_TIME) { -		dev_err(&pdev->dev, "invalid debounce time supplied\n"); -		return -EINVAL; -	} - -	keymap_data = pdata->keymap_data; -	if (!keymap_data) { -		dev_err(&pdev->dev, "no keymap data supplied\n"); -		return -EINVAL; -	} +	repeat = !of_property_read_bool(pdev->dev.of_node, +					"linux,input-no-autorepeat"); +	wakeup = of_property_read_bool(pdev->dev.of_node, +					"linux,keypad-wakeup"); -	kp = kzalloc(sizeof(*kp), GFP_KERNEL); +	kp = devm_kzalloc(&pdev->dev, sizeof(*kp), GFP_KERNEL);  	if (!kp)  		return -ENOMEM; +	kp->regmap = dev_get_regmap(pdev->dev.parent, NULL); +	if (!kp->regmap) +		return -ENODEV; +  	platform_set_drvdata(pdev, kp); -	kp->pdata	= pdata; +	kp->num_rows	= rows; +	kp->num_cols	= cols;  	kp->dev		= &pdev->dev; -	kp->input = input_allocate_device(); +	kp->input = devm_input_allocate_device(&pdev->dev);  	if (!kp->input) {  		dev_err(&pdev->dev, "unable to allocate input device\n"); -		rc = -ENOMEM; -		goto err_alloc_device; +		return -ENOMEM;  	}  	kp->key_sense_irq = platform_get_irq(pdev, 0);  	if (kp->key_sense_irq < 0) {  		dev_err(&pdev->dev, "unable to get keypad sense irq\n"); -		rc = -ENXIO; -		goto err_get_irq; +		return kp->key_sense_irq;  	}  	kp->key_stuck_irq = platform_get_irq(pdev, 1);  	if (kp->key_stuck_irq < 0) {  		dev_err(&pdev->dev, "unable to get keypad stuck irq\n"); -		rc = -ENXIO; -		goto err_get_irq; +		return kp->key_stuck_irq;  	} -	kp->input->name = pdata->input_name ? : "PMIC8XXX keypad"; -	kp->input->phys = pdata->input_phys_device ? : "pmic8xxx_keypad/input0"; - -	kp->input->dev.parent	= &pdev->dev; +	kp->input->name = "PMIC8XXX keypad"; +	kp->input->phys = "pmic8xxx_keypad/input0";  	kp->input->id.bustype	= BUS_I2C;  	kp->input->id.version	= 0x0001; @@ -629,15 +572,15 @@ static int pmic8xxx_kp_probe(struct platform_device *pdev)  	kp->input->open		= pmic8xxx_kp_open;  	kp->input->close	= pmic8xxx_kp_close; -	rc = matrix_keypad_build_keymap(keymap_data, NULL, +	rc = matrix_keypad_build_keymap(NULL, NULL,  					PM8XXX_MAX_ROWS, PM8XXX_MAX_COLS,  					kp->keycodes, kp->input);  	if (rc) {  		dev_err(&pdev->dev, "failed to build keymap\n"); -		goto err_get_irq; +		return rc;  	} -	if (pdata->rep) +	if (repeat)  		__set_bit(EV_REP, kp->input->evbit);  	input_set_capability(kp->input, EV_MSC, MSC_SCAN); @@ -647,44 +590,32 @@ static int pmic8xxx_kp_probe(struct platform_device *pdev)  	memset(kp->keystate, 0xff, sizeof(kp->keystate));  	memset(kp->stuckstate, 0xff, sizeof(kp->stuckstate)); -	rc = pmic8xxx_kpd_init(kp); +	rc = pmic8xxx_kpd_init(kp, pdev);  	if (rc < 0) {  		dev_err(&pdev->dev, "unable to initialize keypad controller\n"); -		goto err_get_irq; -	} - -	rc = pmic8xxx_kp_config_gpio(pdata->cols_gpio_start, -					pdata->num_cols, kp, &kypd_sns); -	if (rc < 0) { -		dev_err(&pdev->dev, "unable to configure keypad sense lines\n"); -		goto err_gpio_config; -	} - -	rc = pmic8xxx_kp_config_gpio(pdata->rows_gpio_start, -					pdata->num_rows, kp, &kypd_drv); -	if (rc < 0) { -		dev_err(&pdev->dev, "unable to configure keypad drive lines\n"); -		goto err_gpio_config; +		return rc;  	} -	rc = request_any_context_irq(kp->key_sense_irq, pmic8xxx_kp_irq, -				 IRQF_TRIGGER_RISING, "pmic-keypad", kp); +	rc = devm_request_any_context_irq(&pdev->dev, kp->key_sense_irq, +			pmic8xxx_kp_irq, IRQF_TRIGGER_RISING, "pmic-keypad", +			kp);  	if (rc < 0) {  		dev_err(&pdev->dev, "failed to request keypad sense irq\n"); -		goto err_get_irq; +		return rc;  	} -	rc = request_any_context_irq(kp->key_stuck_irq, pmic8xxx_kp_stuck_irq, -				 IRQF_TRIGGER_RISING, "pmic-keypad-stuck", kp); +	rc = devm_request_any_context_irq(&pdev->dev, kp->key_stuck_irq, +			pmic8xxx_kp_stuck_irq, IRQF_TRIGGER_RISING, +			"pmic-keypad-stuck", kp);  	if (rc < 0) {  		dev_err(&pdev->dev, "failed to request keypad stuck irq\n"); -		goto err_req_stuck_irq; +		return rc;  	} -	rc = pmic8xxx_kp_read_u8(kp, &ctrl_val, KEYP_CTRL); +	rc = regmap_read(kp->regmap, KEYP_CTRL, &ctrl_val);  	if (rc < 0) {  		dev_err(&pdev->dev, "failed to read KEYP_CTRL register\n"); -		goto err_pmic_reg_read; +		return rc;  	}  	kp->ctrl_reg = ctrl_val; @@ -692,34 +623,10 @@ static int pmic8xxx_kp_probe(struct platform_device *pdev)  	rc = input_register_device(kp->input);  	if (rc < 0) {  		dev_err(&pdev->dev, "unable to register keypad input device\n"); -		goto err_pmic_reg_read; +		return rc;  	} -	device_init_wakeup(&pdev->dev, pdata->wakeup); - -	return 0; - -err_pmic_reg_read: -	free_irq(kp->key_stuck_irq, kp); -err_req_stuck_irq: -	free_irq(kp->key_sense_irq, kp); -err_gpio_config: -err_get_irq: -	input_free_device(kp->input); -err_alloc_device: -	kfree(kp); -	return rc; -} - -static int pmic8xxx_kp_remove(struct platform_device *pdev) -{ -	struct pmic8xxx_kp *kp = platform_get_drvdata(pdev); - -	device_init_wakeup(&pdev->dev, 0); -	free_irq(kp->key_stuck_irq, kp); -	free_irq(kp->key_sense_irq, kp); -	input_unregister_device(kp->input); -	kfree(kp); +	device_init_wakeup(&pdev->dev, wakeup);  	return 0;  } @@ -769,13 +676,20 @@ static int pmic8xxx_kp_resume(struct device *dev)  static SIMPLE_DEV_PM_OPS(pm8xxx_kp_pm_ops,  			 pmic8xxx_kp_suspend, pmic8xxx_kp_resume); +static const struct of_device_id pm8xxx_match_table[] = { +	{ .compatible = "qcom,pm8058-keypad" }, +	{ .compatible = "qcom,pm8921-keypad" }, +	{ } +}; +MODULE_DEVICE_TABLE(of, pm8xxx_match_table); +  static struct platform_driver pmic8xxx_kp_driver = {  	.probe		= pmic8xxx_kp_probe, -	.remove		= pmic8xxx_kp_remove,  	.driver		= { -		.name = PM8XXX_KEYPAD_DEV_NAME, +		.name = "pm8xxx-keypad",  		.owner = THIS_MODULE,  		.pm = &pm8xxx_kp_pm_ops, +		.of_match_table = pm8xxx_match_table,  	},  };  module_platform_driver(pmic8xxx_kp_driver); diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index 134c3b404a5..a15063bea70 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -18,7 +18,6 @@  #include <linux/kernel.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/input.h>  #include <linux/device.h> @@ -27,6 +26,7 @@  #include <linux/err.h>  #include <linux/input/matrix_keypad.h>  #include <linux/slab.h> +#include <linux/of.h>  #include <asm/mach/arch.h>  #include <asm/mach/map.h> @@ -111,6 +111,8 @@ struct pxa27x_keypad {  	unsigned short keycodes[MAX_KEYPAD_KEYS];  	int rotary_rel_code[2]; +	unsigned int row_shift; +  	/* state row bits of each column scan */  	uint32_t matrix_key_state[MAX_MATRIX_KEY_COLS];  	uint32_t direct_key_state; @@ -467,7 +469,8 @@ scan:  			if ((bits_changed & (1 << row)) == 0)  				continue; -			code = MATRIX_SCAN_CODE(row, col, MATRIX_ROW_SHIFT); +			code = MATRIX_SCAN_CODE(row, col, keypad->row_shift); +  			input_event(input_dev, EV_MSC, MSC_SCAN, code);  			input_report_key(input_dev, keypad->keycodes[code],  					 new_state[col] & (1 << row)); @@ -786,15 +789,24 @@ static int pxa27x_keypad_probe(struct platform_device *pdev)  	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);  	input_set_capability(input_dev, EV_MSC, MSC_SCAN); -	if (pdata) +	if (pdata) {  		error = pxa27x_keypad_build_keycode(keypad); -	else +	} else {  		error = pxa27x_keypad_build_keycode_from_dt(keypad); +		/* +		 * Data that we get from DT resides in dynamically +		 * allocated memory so we need to update our pdata +		 * pointer. +		 */ +		pdata = keypad->pdata; +	}  	if (error) {  		dev_err(&pdev->dev, "failed to build keycode\n");  		goto failed_put_clk;  	} +	keypad->row_shift = get_count_order(pdata->matrix_key_cols); +  	if ((pdata->enable_rotary0 && keypad->rotary_rel_code[0] != -1) ||  	    (pdata->enable_rotary1 && keypad->rotary_rel_code[1] != -1)) {  		input_dev->evbit[0] |= BIT_MASK(EV_REL); diff --git a/drivers/input/keyboard/pxa930_rotary.c b/drivers/input/keyboard/pxa930_rotary.c index 248cdcf9529..374ca0246c8 100644 --- a/drivers/input/keyboard/pxa930_rotary.c +++ b/drivers/input/keyboard/pxa930_rotary.c @@ -8,7 +8,6 @@  #include <linux/kernel.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/input.h>  #include <linux/platform_device.h> @@ -84,7 +83,8 @@ static void pxa930_rotary_close(struct input_dev *dev)  static int pxa930_rotary_probe(struct platform_device *pdev)  { -	struct pxa930_rotary_platform_data *pdata = pdev->dev.platform_data; +	struct pxa930_rotary_platform_data *pdata = +			dev_get_platdata(&pdev->dev);  	struct pxa930_rotary *r;  	struct input_dev *input_dev;  	struct resource *res; diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c index 6c561ec3cc0..52cd6e88acd 100644 --- a/drivers/input/keyboard/qt1070.c +++ b/drivers/input/keyboard/qt1070.c @@ -25,7 +25,6 @@   */  #include <linux/kernel.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/i2c.h>  #include <linux/input.h>  #include <linux/slab.h> diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c index 1c0ddad0a1c..819b22897c1 100644 --- a/drivers/input/keyboard/qt2160.c +++ b/drivers/input/keyboard/qt2160.c @@ -19,7 +19,6 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/leds.h>  #include <linux/module.h>  #include <linux/slab.h> diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c index ac43a486c77..5e80fbf7b5e 100644 --- a/drivers/input/keyboard/samsung-keypad.c +++ b/drivers/input/keyboard/samsung-keypad.c @@ -14,7 +14,6 @@  #include <linux/clk.h>  #include <linux/delay.h>  #include <linux/err.h> -#include <linux/init.h>  #include <linux/input.h>  #include <linux/interrupt.h>  #include <linux/io.h> @@ -244,8 +243,8 @@ static void samsung_keypad_close(struct input_dev *input_dev)  }  #ifdef CONFIG_OF -static struct samsung_keypad_platdata *samsung_keypad_parse_dt( -				struct device *dev) +static struct samsung_keypad_platdata * +samsung_keypad_parse_dt(struct device *dev)  {  	struct samsung_keypad_platdata *pdata;  	struct matrix_keymap_data *keymap_data; @@ -253,17 +252,22 @@ static struct samsung_keypad_platdata *samsung_keypad_parse_dt(  	struct device_node *np = dev->of_node, *key_np;  	unsigned int key_count; +	if (!np) { +		dev_err(dev, "missing device tree data\n"); +		return ERR_PTR(-EINVAL); +	} +  	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);  	if (!pdata) {  		dev_err(dev, "could not allocate memory for platform data\n"); -		return NULL; +		return ERR_PTR(-ENOMEM);  	}  	of_property_read_u32(np, "samsung,keypad-num-rows", &num_rows);  	of_property_read_u32(np, "samsung,keypad-num-columns", &num_cols);  	if (!num_rows || !num_cols) {  		dev_err(dev, "number of keypad rows/columns not specified\n"); -		return NULL; +		return ERR_PTR(-EINVAL);  	}  	pdata->rows = num_rows;  	pdata->cols = num_cols; @@ -271,7 +275,7 @@ static struct samsung_keypad_platdata *samsung_keypad_parse_dt(  	keymap_data = devm_kzalloc(dev, sizeof(*keymap_data), GFP_KERNEL);  	if (!keymap_data) {  		dev_err(dev, "could not allocate memory for keymap data\n"); -		return NULL; +		return ERR_PTR(-ENOMEM);  	}  	pdata->keymap_data = keymap_data; @@ -280,7 +284,7 @@ static struct samsung_keypad_platdata *samsung_keypad_parse_dt(  	keymap = devm_kzalloc(dev, sizeof(uint32_t) * key_count, GFP_KERNEL);  	if (!keymap) {  		dev_err(dev, "could not allocate memory for keymap\n"); -		return NULL; +		return ERR_PTR(-ENOMEM);  	}  	keymap_data->keymap = keymap; @@ -294,16 +298,19 @@ static struct samsung_keypad_platdata *samsung_keypad_parse_dt(  	if (of_get_property(np, "linux,input-no-autorepeat", NULL))  		pdata->no_autorepeat = true; +  	if (of_get_property(np, "linux,input-wakeup", NULL))  		pdata->wakeup = true;  	return pdata;  }  #else -static -struct samsung_keypad_platdata *samsung_keypad_parse_dt(struct device *dev) +static struct samsung_keypad_platdata * +samsung_keypad_parse_dt(struct device *dev)  { -	return NULL; +	dev_err(dev, "no platform data defined\n"); + +	return ERR_PTR(-EINVAL);  }  #endif @@ -318,13 +325,11 @@ static int samsung_keypad_probe(struct platform_device *pdev)  	unsigned int keymap_size;  	int error; -	if (pdev->dev.of_node) -		pdata = samsung_keypad_parse_dt(&pdev->dev); -	else -		pdata = pdev->dev.platform_data; +	pdata = dev_get_platdata(&pdev->dev);  	if (!pdata) { -		dev_err(&pdev->dev, "no platform data defined\n"); -		return -EINVAL; +		pdata = samsung_keypad_parse_dt(&pdev->dev); +		if (IS_ERR(pdata)) +			return PTR_ERR(pdata);  	}  	keymap_data = pdata->keymap_data; diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c index fe0e498d247..7abf03b4cc9 100644 --- a/drivers/input/keyboard/sh_keysc.c +++ b/drivers/input/keyboard/sh_keysc.c @@ -12,7 +12,6 @@  #include <linux/kernel.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/irq.h>  #include <linux/delay.h> @@ -171,7 +170,7 @@ static int sh_keysc_probe(struct platform_device *pdev)  	int i;  	int irq, error; -	if (!pdev->dev.platform_data) { +	if (!dev_get_platdata(&pdev->dev)) {  		dev_err(&pdev->dev, "no platform data defined\n");  		error = -EINVAL;  		goto err0; @@ -198,7 +197,7 @@ static int sh_keysc_probe(struct platform_device *pdev)  	}  	platform_set_drvdata(pdev, priv); -	memcpy(&priv->pdata, pdev->dev.platform_data, sizeof(priv->pdata)); +	memcpy(&priv->pdata, dev_get_platdata(&pdev->dev), sizeof(priv->pdata));  	pdata = &priv->pdata;  	priv->iomem_base = ioremap_nocache(res->start, resource_size(res)); diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c index 85ff530d9a9..258af10e581 100644 --- a/drivers/input/keyboard/spear-keyboard.c +++ b/drivers/input/keyboard/spear-keyboard.c @@ -12,7 +12,6 @@  #include <linux/clk.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/input.h>  #include <linux/io.h> diff --git a/drivers/input/keyboard/st-keyscan.c b/drivers/input/keyboard/st-keyscan.c new file mode 100644 index 00000000000..de7be4f03d9 --- /dev/null +++ b/drivers/input/keyboard/st-keyscan.c @@ -0,0 +1,276 @@ +/* + * STMicroelectronics Key Scanning driver + * + * Copyright (c) 2014 STMicroelectonics Ltd. + * Author: Stuart Menefy <stuart.menefy@st.com> + * + * Based on sh_keysc.c, copyright 2008 Magnus Damm + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/input/matrix_keypad.h> + +#define ST_KEYSCAN_MAXKEYS 16 + +#define KEYSCAN_CONFIG_OFF		0x0 +#define KEYSCAN_CONFIG_ENABLE		0x1 +#define KEYSCAN_DEBOUNCE_TIME_OFF	0x4 +#define KEYSCAN_MATRIX_STATE_OFF	0x8 +#define KEYSCAN_MATRIX_DIM_OFF		0xc +#define KEYSCAN_MATRIX_DIM_X_SHIFT	0x0 +#define KEYSCAN_MATRIX_DIM_Y_SHIFT	0x2 + +struct st_keyscan { +	void __iomem *base; +	int irq; +	struct clk *clk; +	struct input_dev *input_dev; +	unsigned long last_state; +	unsigned int n_rows; +	unsigned int n_cols; +	unsigned int debounce_us; +}; + +static irqreturn_t keyscan_isr(int irq, void *dev_id) +{ +	struct st_keyscan *keypad = dev_id; +	unsigned short *keycode = keypad->input_dev->keycode; +	unsigned long state, change; +	int bit_nr; + +	state = readl(keypad->base + KEYSCAN_MATRIX_STATE_OFF) & 0xffff; +	change = keypad->last_state ^ state; +	keypad->last_state = state; + +	for_each_set_bit(bit_nr, &change, BITS_PER_LONG) +		input_report_key(keypad->input_dev, +				 keycode[bit_nr], state & BIT(bit_nr)); + +	input_sync(keypad->input_dev); + +	return IRQ_HANDLED; +} + +static int keyscan_start(struct st_keyscan *keypad) +{ +	int error; + +	error = clk_enable(keypad->clk); +	if (error) +		return error; + +	writel(keypad->debounce_us * (clk_get_rate(keypad->clk) / 1000000), +	       keypad->base + KEYSCAN_DEBOUNCE_TIME_OFF); + +	writel(((keypad->n_cols - 1) << KEYSCAN_MATRIX_DIM_X_SHIFT) | +	       ((keypad->n_rows - 1) << KEYSCAN_MATRIX_DIM_Y_SHIFT), +	       keypad->base + KEYSCAN_MATRIX_DIM_OFF); + +	writel(KEYSCAN_CONFIG_ENABLE, keypad->base + KEYSCAN_CONFIG_OFF); + +	return 0; +} + +static void keyscan_stop(struct st_keyscan *keypad) +{ +	writel(0, keypad->base + KEYSCAN_CONFIG_OFF); + +	clk_disable(keypad->clk); +} + +static int keyscan_open(struct input_dev *dev) +{ +	struct st_keyscan *keypad = input_get_drvdata(dev); + +	return keyscan_start(keypad); +} + +static void keyscan_close(struct input_dev *dev) +{ +	struct st_keyscan *keypad = input_get_drvdata(dev); + +	keyscan_stop(keypad); +} + +static int keypad_matrix_key_parse_dt(struct st_keyscan *keypad_data) +{ +	struct device *dev = keypad_data->input_dev->dev.parent; +	struct device_node *np = dev->of_node; +	int error; + +	error = matrix_keypad_parse_of_params(dev, &keypad_data->n_rows, +					      &keypad_data->n_cols); +	if (error) { +		dev_err(dev, "failed to parse keypad params\n"); +		return error; +	} + +	of_property_read_u32(np, "st,debounce-us", &keypad_data->debounce_us); + +	dev_dbg(dev, "n_rows=%d n_col=%d debounce=%d\n", +		keypad_data->n_rows, keypad_data->n_cols, +		keypad_data->debounce_us); + +	return 0; +} + +static int keyscan_probe(struct platform_device *pdev) +{ +	struct st_keyscan *keypad_data; +	struct input_dev *input_dev; +	struct resource *res; +	int error; + +	if (!pdev->dev.of_node) { +		dev_err(&pdev->dev, "no DT data present\n"); +		return -EINVAL; +	} + +	keypad_data = devm_kzalloc(&pdev->dev, sizeof(*keypad_data), +				   GFP_KERNEL); +	if (!keypad_data) +		return -ENOMEM; + +	input_dev = devm_input_allocate_device(&pdev->dev); +	if (!input_dev) { +		dev_err(&pdev->dev, "failed to allocate the input device\n"); +		return -ENOMEM; +	} + +	input_dev->name = pdev->name; +	input_dev->phys = "keyscan-keys/input0"; +	input_dev->dev.parent = &pdev->dev; +	input_dev->open = keyscan_open; +	input_dev->close = keyscan_close; + +	input_dev->id.bustype = BUS_HOST; + +	error = keypad_matrix_key_parse_dt(keypad_data); +	if (error) +		return error; + +	error = matrix_keypad_build_keymap(NULL, NULL, +					   keypad_data->n_rows, +					   keypad_data->n_cols, +					   NULL, input_dev); +	if (error) { +		dev_err(&pdev->dev, "failed to build keymap\n"); +		return error; +	} + +	input_set_drvdata(input_dev, keypad_data); + +	keypad_data->input_dev = input_dev; + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	keypad_data->base = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(keypad_data->base)) +		return PTR_ERR(keypad_data->base); + +	keypad_data->clk = devm_clk_get(&pdev->dev, NULL); +	if (IS_ERR(keypad_data->clk)) { +		dev_err(&pdev->dev, "cannot get clock\n"); +		return PTR_ERR(keypad_data->clk); +	} + +	error = clk_enable(keypad_data->clk); +	if (error) { +		dev_err(&pdev->dev, "failed to enable clock\n"); +		return error; +	} + +	keyscan_stop(keypad_data); + +	keypad_data->irq = platform_get_irq(pdev, 0); +	if (keypad_data->irq < 0) { +		dev_err(&pdev->dev, "no IRQ specified\n"); +		return -EINVAL; +	} + +	error = devm_request_irq(&pdev->dev, keypad_data->irq, keyscan_isr, 0, +				 pdev->name, keypad_data); +	if (error) { +		dev_err(&pdev->dev, "failed to request IRQ\n"); +		return error; +	} + +	error = input_register_device(input_dev); +	if (error) { +		dev_err(&pdev->dev, "failed to register input device\n"); +		return error; +	} + +	platform_set_drvdata(pdev, keypad_data); + +	device_set_wakeup_capable(&pdev->dev, 1); + +	return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int keyscan_suspend(struct device *dev) +{ +	struct platform_device *pdev = to_platform_device(dev); +	struct st_keyscan *keypad = platform_get_drvdata(pdev); +	struct input_dev *input = keypad->input_dev; + +	mutex_lock(&input->mutex); + +	if (device_may_wakeup(dev)) +		enable_irq_wake(keypad->irq); +	else if (input->users) +		keyscan_stop(keypad); + +	mutex_unlock(&input->mutex); +	return 0; +} + +static int keyscan_resume(struct device *dev) +{ +	struct platform_device *pdev = to_platform_device(dev); +	struct st_keyscan *keypad = platform_get_drvdata(pdev); +	struct input_dev *input = keypad->input_dev; +	int retval = 0; + +	mutex_lock(&input->mutex); + +	if (device_may_wakeup(dev)) +		disable_irq_wake(keypad->irq); +	else if (input->users) +		retval = keyscan_start(keypad); + +	mutex_unlock(&input->mutex); +	return retval; +} +#endif + +static SIMPLE_DEV_PM_OPS(keyscan_dev_pm_ops, keyscan_suspend, keyscan_resume); + +static const struct of_device_id keyscan_of_match[] = { +	{ .compatible = "st,sti-keyscan" }, +	{ }, +}; +MODULE_DEVICE_TABLE(of, keyscan_of_match); + +static struct platform_driver keyscan_device_driver = { +	.probe		= keyscan_probe, +	.driver		= { +		.name	= "st-keyscan", +		.pm	= &keyscan_dev_pm_ops, +		.of_match_table = of_match_ptr(keyscan_of_match), +	} +}; + +module_platform_driver(keyscan_device_driver); + +MODULE_AUTHOR("Stuart Menefy <stuart.menefy@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics keyscan device driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/keyboard/stmpe-keypad.c b/drivers/input/keyboard/stmpe-keypad.c index 5cbec56f772..c6727dda68f 100644 --- a/drivers/input/keyboard/stmpe-keypad.c +++ b/drivers/input/keyboard/stmpe-keypad.c @@ -6,7 +6,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/interrupt.h> diff --git a/drivers/input/keyboard/stowaway.c b/drivers/input/keyboard/stowaway.c index cc612c5d542..a6e0d565e30 100644 --- a/drivers/input/keyboard/stowaway.c +++ b/drivers/input/keyboard/stowaway.c @@ -32,7 +32,6 @@  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/input.h> -#include <linux/init.h>  #include <linux/serio.h>  #define DRIVER_DESC	"Stowaway keyboard driver" diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c index 5f836b1638c..dc6bb9d5b4f 100644 --- a/drivers/input/keyboard/sunkbd.c +++ b/drivers/input/keyboard/sunkbd.c @@ -31,7 +31,6 @@  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/interrupt.h> -#include <linux/init.h>  #include <linux/input.h>  #include <linux/serio.h>  #include <linux/workqueue.h> diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c index 208de7cbb7f..ad7abae6907 100644 --- a/drivers/input/keyboard/tc3589x-keypad.c +++ b/drivers/input/keyboard/tc3589x-keypad.c @@ -10,7 +10,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/input.h>  #include <linux/platform_device.h> @@ -297,6 +296,65 @@ static void tc3589x_keypad_close(struct input_dev *input)  	tc3589x_keypad_disable(keypad);  } +#ifdef CONFIG_OF +static const struct tc3589x_keypad_platform_data * +tc3589x_keypad_of_probe(struct device *dev) +{ +	struct device_node *np = dev->of_node; +	struct tc3589x_keypad_platform_data *plat; +	u32 cols, rows; +	u32 debounce_ms; +	int proplen; + +	if (!np) +		return ERR_PTR(-ENODEV); + +	plat = devm_kzalloc(dev, sizeof(*plat), GFP_KERNEL); +	if (!plat) +		return ERR_PTR(-ENOMEM); + +	of_property_read_u32(np, "keypad,num-columns", &cols); +	of_property_read_u32(np, "keypad,num-rows", &rows); +	plat->kcol = (u8) cols; +	plat->krow = (u8) rows; +	if (!plat->krow || !plat->kcol || +	     plat->krow > TC_KPD_ROWS || plat->kcol > TC_KPD_COLUMNS) { +		dev_err(dev, +			"keypad columns/rows not properly specified (%ux%u)\n", +			plat->kcol, plat->krow); +		return ERR_PTR(-EINVAL); +	} + +	if (!of_get_property(np, "linux,keymap", &proplen)) { +		dev_err(dev, "property linux,keymap not found\n"); +		return ERR_PTR(-ENOENT); +	} + +	plat->no_autorepeat = of_property_read_bool(np, "linux,no-autorepeat"); +	plat->enable_wakeup = of_property_read_bool(np, "linux,wakeup"); + +	/* The custom delay format is ms/16 */ +	of_property_read_u32(np, "debounce-delay-ms", &debounce_ms); +	if (debounce_ms) +		plat->debounce_period = debounce_ms * 16; +	else +		plat->debounce_period = TC_KPD_DEBOUNCE_PERIOD; + +	plat->settle_time = TC_KPD_SETTLE_TIME; +	/* FIXME: should be property of the IRQ resource? */ +	plat->irqtype = IRQF_TRIGGER_FALLING; + +	return plat; +} +#else +static inline const struct tc3589x_keypad_platform_data * +tc3589x_keypad_of_probe(struct device *dev) +{ +	return ERR_PTR(-ENODEV); +} +#endif + +  static int tc3589x_keypad_probe(struct platform_device *pdev)  {  	struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent); @@ -307,8 +365,11 @@ static int tc3589x_keypad_probe(struct platform_device *pdev)  	plat = tc3589x->pdata->keypad;  	if (!plat) { -		dev_err(&pdev->dev, "invalid keypad platform data\n"); -		return -EINVAL; +		plat = tc3589x_keypad_of_probe(&pdev->dev); +		if (IS_ERR(plat)) { +			dev_err(&pdev->dev, "invalid keypad platform data\n"); +			return PTR_ERR(plat); +		}  	}  	irq = platform_get_irq(pdev, 0); diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c index bfc832c35a7..dc983ab6c0a 100644 --- a/drivers/input/keyboard/tca6416-keypad.c +++ b/drivers/input/keyboard/tca6416-keypad.c @@ -213,7 +213,7 @@ static int tca6416_keypad_probe(struct i2c_client *client,  		return -ENODEV;  	} -	pdata = client->dev.platform_data; +	pdata = dev_get_platdata(&client->dev);  	if (!pdata) {  		dev_dbg(&client->dev, "no platform data\n");  		return -EINVAL; diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index 55c15304ddb..4e491c1762c 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -392,6 +392,13 @@ static const struct of_device_id tca8418_dt_ids[] = {  	{ }  };  MODULE_DEVICE_TABLE(of, tca8418_dt_ids); + +/* + * The device tree based i2c loader looks for + * "i2c:" + second_component_of(property("compatible")) + * and therefore we need an alias to be found. + */ +MODULE_ALIAS("i2c:tca8418");  #endif  static struct i2c_driver tca8418_keypad_driver = { diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index 9cd20e6905a..9757a58bc89 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -31,7 +31,7 @@  #include <linux/clk.h>  #include <linux/slab.h>  #include <linux/input/matrix_keypad.h> -#include <linux/clk/tegra.h> +#include <linux/reset.h>  #include <linux/err.h>  #define KBC_MAX_KPENT	8 @@ -116,6 +116,7 @@ struct tegra_kbc {  	u32 wakeup_key;  	struct timer_list timer;  	struct clk *clk; +	struct reset_control *rst;  	const struct tegra_kbc_hw_support *hw_support;  	int max_keys;  	int num_rows_and_columns; @@ -373,9 +374,9 @@ static int tegra_kbc_start(struct tegra_kbc *kbc)  	clk_prepare_enable(kbc->clk);  	/* Reset the KBC controller to clear all previous status.*/ -	tegra_periph_reset_assert(kbc->clk); +	reset_control_assert(kbc->rst);  	udelay(100); -	tegra_periph_reset_deassert(kbc->clk); +	reset_control_assert(kbc->rst);  	udelay(100);  	tegra_kbc_config_pins(kbc); @@ -614,7 +615,7 @@ static int tegra_kbc_probe(struct platform_device *pdev)  	unsigned int keymap_rows;  	const struct of_device_id *match; -	match = of_match_device(of_match_ptr(tegra_kbc_of_match), &pdev->dev); +	match = of_match_device(tegra_kbc_of_match, &pdev->dev);  	kbc = devm_kzalloc(&pdev->dev, sizeof(*kbc), GFP_KERNEL);  	if (!kbc) { @@ -663,6 +664,12 @@ static int tegra_kbc_probe(struct platform_device *pdev)  		return PTR_ERR(kbc->clk);  	} +	kbc->rst = devm_reset_control_get(&pdev->dev, "kbc"); +	if (IS_ERR(kbc->rst)) { +		dev_err(&pdev->dev, "failed to get keyboard reset\n"); +		return PTR_ERR(kbc->rst); +	} +  	/*  	 * The time delay between two consecutive reads of the FIFO is  	 * the sum of the repeat time and the time taken for scanning diff --git a/drivers/input/keyboard/tnetv107x-keypad.c b/drivers/input/keyboard/tnetv107x-keypad.c deleted file mode 100644 index 5f7b427dd7e..00000000000 --- a/drivers/input/keyboard/tnetv107x-keypad.c +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Texas Instruments TNETV107X Keypad Driver - * - * Copyright (C) 2010 Texas Instruments - * - * 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 the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - */ - -#include <linux/kernel.h> -#include <linux/err.h> -#include <linux/errno.h> -#include <linux/input.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/clk.h> -#include <linux/input/matrix_keypad.h> -#include <linux/module.h> - -#define BITS(x)			(BIT(x) - 1) - -#define KEYPAD_ROWS		9 -#define KEYPAD_COLS		9 - -#define DEBOUNCE_MIN		0x400ul -#define DEBOUNCE_MAX		0x3ffffffful - -struct keypad_regs { -	u32	rev; -	u32	mode; -	u32	mask; -	u32	pol; -	u32	dclock; -	u32	rclock; -	u32	stable_cnt; -	u32	in_en; -	u32	out; -	u32	out_en; -	u32	in; -	u32	lock; -	u32	pres[3]; -}; - -#define keypad_read(kp, reg)		__raw_readl(&(kp)->regs->reg) -#define keypad_write(kp, reg, val)	__raw_writel(val, &(kp)->regs->reg) - -struct keypad_data { -	struct input_dev		*input_dev; -	struct resource			*res; -	struct keypad_regs __iomem	*regs; -	struct clk			*clk; -	struct device			*dev; -	spinlock_t			lock; -	u32				irq_press; -	u32				irq_release; -	int				rows, cols, row_shift; -	int				debounce_ms, active_low; -	u32				prev_keys[3]; -	unsigned short			keycodes[]; -}; - -static irqreturn_t keypad_irq(int irq, void *data) -{ -	struct keypad_data *kp = data; -	int i, bit, val, row, col, code; -	unsigned long flags; -	u32 curr_keys[3]; -	u32 change; - -	spin_lock_irqsave(&kp->lock, flags); - -	memset(curr_keys, 0, sizeof(curr_keys)); -	if (irq == kp->irq_press) -		for (i = 0; i < 3; i++) -			curr_keys[i] = keypad_read(kp, pres[i]); - -	for (i = 0; i < 3; i++) { -		change = curr_keys[i] ^ kp->prev_keys[i]; - -		while (change) { -			bit     = fls(change) - 1; -			change ^= BIT(bit); -			val     = curr_keys[i] & BIT(bit); -			bit    += i * 32; -			row     = bit / KEYPAD_COLS; -			col     = bit % KEYPAD_COLS; - -			code = MATRIX_SCAN_CODE(row, col, kp->row_shift); -			input_event(kp->input_dev, EV_MSC, MSC_SCAN, code); -			input_report_key(kp->input_dev, kp->keycodes[code], -					 val); -		} -	} -	input_sync(kp->input_dev); -	memcpy(kp->prev_keys, curr_keys, sizeof(curr_keys)); - -	if (irq == kp->irq_press) -		keypad_write(kp, lock, 0); /* Allow hardware updates */ - -	spin_unlock_irqrestore(&kp->lock, flags); - -	return IRQ_HANDLED; -} - -static int keypad_start(struct input_dev *dev) -{ -	struct keypad_data *kp = input_get_drvdata(dev); -	unsigned long mask, debounce, clk_rate_khz; -	unsigned long flags; - -	clk_enable(kp->clk); -	clk_rate_khz = clk_get_rate(kp->clk) / 1000; - -	spin_lock_irqsave(&kp->lock, flags); - -	/* Initialize device registers */ -	keypad_write(kp, mode, 0); - -	mask  = BITS(kp->rows) << KEYPAD_COLS; -	mask |= BITS(kp->cols); -	keypad_write(kp, mask, ~mask); - -	keypad_write(kp, pol, kp->active_low ? 0 : 0x3ffff); -	keypad_write(kp, stable_cnt, 3); - -	debounce = kp->debounce_ms * clk_rate_khz; -	debounce = clamp(debounce, DEBOUNCE_MIN, DEBOUNCE_MAX); -	keypad_write(kp, dclock, debounce); -	keypad_write(kp, rclock, 4 * debounce); - -	keypad_write(kp, in_en, 1); - -	spin_unlock_irqrestore(&kp->lock, flags); - -	return 0; -} - -static void keypad_stop(struct input_dev *dev) -{ -	struct keypad_data *kp = input_get_drvdata(dev); - -	synchronize_irq(kp->irq_press); -	synchronize_irq(kp->irq_release); -	clk_disable(kp->clk); -} - -static int keypad_probe(struct platform_device *pdev) -{ -	const struct matrix_keypad_platform_data *pdata; -	const struct matrix_keymap_data *keymap_data; -	struct device *dev = &pdev->dev; -	struct keypad_data *kp; -	int error = 0, sz, row_shift; -	u32 rev = 0; - -	pdata = pdev->dev.platform_data; -	if (!pdata) { -		dev_err(dev, "cannot find device data\n"); -		return -EINVAL; -	} - -	keymap_data = pdata->keymap_data; -	if (!keymap_data) { -		dev_err(dev, "cannot find keymap data\n"); -		return -EINVAL; -	} - -	row_shift = get_count_order(pdata->num_col_gpios); -	sz  = offsetof(struct keypad_data, keycodes); -	sz += (pdata->num_row_gpios << row_shift) * sizeof(kp->keycodes[0]); -	kp = kzalloc(sz, GFP_KERNEL); -	if (!kp) { -		dev_err(dev, "cannot allocate device info\n"); -		return -ENOMEM; -	} - -	kp->dev  = dev; -	kp->rows = pdata->num_row_gpios; -	kp->cols = pdata->num_col_gpios; -	kp->row_shift = row_shift; -	platform_set_drvdata(pdev, kp); -	spin_lock_init(&kp->lock); - -	kp->irq_press   = platform_get_irq_byname(pdev, "press"); -	kp->irq_release = platform_get_irq_byname(pdev, "release"); -	if (kp->irq_press < 0 || kp->irq_release < 0) { -		dev_err(dev, "cannot determine device interrupts\n"); -		error = -ENODEV; -		goto error_res; -	} - -	kp->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!kp->res) { -		dev_err(dev, "cannot determine register area\n"); -		error = -ENODEV; -		goto error_res; -	} - -	if (!request_mem_region(kp->res->start, resource_size(kp->res), -				pdev->name)) { -		dev_err(dev, "cannot claim register memory\n"); -		kp->res = NULL; -		error = -EINVAL; -		goto error_res; -	} - -	kp->regs = ioremap(kp->res->start, resource_size(kp->res)); -	if (!kp->regs) { -		dev_err(dev, "cannot map register memory\n"); -		error = -ENOMEM; -		goto error_map; -	} - -	kp->clk = clk_get(dev, NULL); -	if (IS_ERR(kp->clk)) { -		dev_err(dev, "cannot claim device clock\n"); -		error = PTR_ERR(kp->clk); -		goto error_clk; -	} - -	error = request_threaded_irq(kp->irq_press, NULL, keypad_irq, -				     IRQF_ONESHOT, dev_name(dev), kp); -	if (error < 0) { -		dev_err(kp->dev, "Could not allocate keypad press key irq\n"); -		goto error_irq_press; -	} - -	error = request_threaded_irq(kp->irq_release, NULL, keypad_irq, -				     IRQF_ONESHOT, dev_name(dev), kp); -	if (error < 0) { -		dev_err(kp->dev, "Could not allocate keypad release key irq\n"); -		goto error_irq_release; -	} - -	kp->input_dev = input_allocate_device(); -	if (!kp->input_dev) { -		dev_err(dev, "cannot allocate input device\n"); -		error = -ENOMEM; -		goto error_input; -	} - -	kp->input_dev->name	  = pdev->name; -	kp->input_dev->dev.parent = &pdev->dev; -	kp->input_dev->open	  = keypad_start; -	kp->input_dev->close	  = keypad_stop; - -	clk_enable(kp->clk); -	rev = keypad_read(kp, rev); -	kp->input_dev->id.bustype = BUS_HOST; -	kp->input_dev->id.product = ((rev >>  8) & 0x07); -	kp->input_dev->id.version = ((rev >> 16) & 0xfff); -	clk_disable(kp->clk); - -	error = matrix_keypad_build_keymap(keymap_data, NULL, -					   kp->rows, kp->cols, -					   kp->keycodes, kp->input_dev); -	if (error) { -		dev_err(dev, "Failed to build keymap\n"); -		goto error_reg; -	} - -	if (!pdata->no_autorepeat) -		kp->input_dev->evbit[0] |= BIT_MASK(EV_REP); -	input_set_capability(kp->input_dev, EV_MSC, MSC_SCAN); - -	input_set_drvdata(kp->input_dev, kp); - -	error = input_register_device(kp->input_dev); -	if (error < 0) { -		dev_err(dev, "Could not register input device\n"); -		goto error_reg; -	} - -	return 0; - - -error_reg: -	input_free_device(kp->input_dev); -error_input: -	free_irq(kp->irq_release, kp); -error_irq_release: -	free_irq(kp->irq_press, kp); -error_irq_press: -	clk_put(kp->clk); -error_clk: -	iounmap(kp->regs); -error_map: -	release_mem_region(kp->res->start, resource_size(kp->res)); -error_res: -	kfree(kp); -	return error; -} - -static int keypad_remove(struct platform_device *pdev) -{ -	struct keypad_data *kp = platform_get_drvdata(pdev); - -	free_irq(kp->irq_press, kp); -	free_irq(kp->irq_release, kp); -	input_unregister_device(kp->input_dev); -	clk_put(kp->clk); -	iounmap(kp->regs); -	release_mem_region(kp->res->start, resource_size(kp->res)); -	kfree(kp); - -	return 0; -} - -static struct platform_driver keypad_driver = { -	.probe		= keypad_probe, -	.remove		= keypad_remove, -	.driver.name	= "tnetv107x-keypad", -	.driver.owner	= THIS_MODULE, -}; -module_platform_driver(keypad_driver); - -MODULE_AUTHOR("Cyril Chemparathy"); -MODULE_DESCRIPTION("TNETV107X Keypad Driver"); -MODULE_ALIAS("platform:tnetv107x-keypad"); -MODULE_LICENSE("GPL"); diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c index d2d178c84ea..c5a11700a1b 100644 --- a/drivers/input/keyboard/twl4030_keypad.c +++ b/drivers/input/keyboard/twl4030_keypad.c @@ -27,12 +27,12 @@  #include <linux/kernel.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/input.h>  #include <linux/platform_device.h>  #include <linux/i2c/twl.h>  #include <linux/slab.h> +#include <linux/of.h>  /*   * The TWL4030 family chips include a keypad controller that supports @@ -60,6 +60,7 @@  struct twl4030_keypad {  	unsigned short	keymap[TWL4030_KEYMAP_SIZE];  	u16		kp_state[TWL4030_MAX_ROWS]; +	bool		autorepeat;  	unsigned	n_rows;  	unsigned	n_cols;  	unsigned	irq; @@ -330,70 +331,89 @@ static int twl4030_kp_program(struct twl4030_keypad *kp)   */  static int twl4030_kp_probe(struct platform_device *pdev)  { -	struct twl4030_keypad_data *pdata = pdev->dev.platform_data; -	const struct matrix_keymap_data *keymap_data; +	struct twl4030_keypad_data *pdata = dev_get_platdata(&pdev->dev); +	const struct matrix_keymap_data *keymap_data = NULL;  	struct twl4030_keypad *kp;  	struct input_dev *input;  	u8 reg;  	int error; -	if (!pdata || !pdata->rows || !pdata->cols || !pdata->keymap_data || -	    pdata->rows > TWL4030_MAX_ROWS || pdata->cols > TWL4030_MAX_COLS) { -		dev_err(&pdev->dev, "Invalid platform_data\n"); -		return -EINVAL; -	} +	kp = devm_kzalloc(&pdev->dev, sizeof(*kp), GFP_KERNEL); +	if (!kp) +		return -ENOMEM; -	keymap_data = pdata->keymap_data; - -	kp = kzalloc(sizeof(*kp), GFP_KERNEL); -	input = input_allocate_device(); -	if (!kp || !input) { -		error = -ENOMEM; -		goto err1; -	} +	input = devm_input_allocate_device(&pdev->dev); +	if (!input) +		return -ENOMEM; -	/* Get the debug Device */ -	kp->dbg_dev = &pdev->dev; -	kp->input = input; - -	kp->n_rows = pdata->rows; -	kp->n_cols = pdata->cols; -	kp->irq = platform_get_irq(pdev, 0); +	/* get the debug device */ +	kp->dbg_dev		= &pdev->dev; +	kp->input		= input;  	/* setup input device */  	input->name		= "TWL4030 Keypad";  	input->phys		= "twl4030_keypad/input0"; -	input->dev.parent	= &pdev->dev;  	input->id.bustype	= BUS_HOST;  	input->id.vendor	= 0x0001;  	input->id.product	= 0x0001;  	input->id.version	= 0x0003; +	if (pdata) { +		if (!pdata->rows || !pdata->cols || !pdata->keymap_data) { +			dev_err(&pdev->dev, "Missing platform_data\n"); +			return -EINVAL; +		} + +		kp->n_rows = pdata->rows; +		kp->n_cols = pdata->cols; +		kp->autorepeat = pdata->rep; +		keymap_data = pdata->keymap_data; +	} else { +		error = matrix_keypad_parse_of_params(&pdev->dev, &kp->n_rows, +						      &kp->n_cols); +		if (error) +			return error; + +		kp->autorepeat = true; +	} + +	if (kp->n_rows > TWL4030_MAX_ROWS || kp->n_cols > TWL4030_MAX_COLS) { +		dev_err(&pdev->dev, +			"Invalid rows/cols amount specified in platform/devicetree data\n"); +		return -EINVAL; +	} + +	kp->irq = platform_get_irq(pdev, 0); +	if (!kp->irq) { +		dev_err(&pdev->dev, "no keyboard irq assigned\n"); +		return -EINVAL; +	} +  	error = matrix_keypad_build_keymap(keymap_data, NULL,  					   TWL4030_MAX_ROWS,  					   1 << TWL4030_ROW_SHIFT,  					   kp->keymap, input);  	if (error) {  		dev_err(kp->dbg_dev, "Failed to build keymap\n"); -		goto err1; +		return error;  	}  	input_set_capability(input, EV_MSC, MSC_SCAN);  	/* Enable auto repeat feature of Linux input subsystem */ -	if (pdata->rep) +	if (kp->autorepeat)  		__set_bit(EV_REP, input->evbit);  	error = input_register_device(input);  	if (error) {  		dev_err(kp->dbg_dev,  			"Unable to register twl4030 keypad device\n"); -		goto err1; +		return error;  	}  	error = twl4030_kp_program(kp);  	if (error) -		goto err2; +		return error;  	/*  	 * This ISR will always execute in kernel thread context because of @@ -401,47 +421,33 @@ static int twl4030_kp_probe(struct platform_device *pdev)  	 *  	 * NOTE:  we assume this host is wired to TWL4040 INT1, not INT2 ...  	 */ -	error = request_threaded_irq(kp->irq, NULL, do_kp_irq, -			0, pdev->name, kp); +	error = devm_request_threaded_irq(&pdev->dev, kp->irq, NULL, do_kp_irq, +					  0, pdev->name, kp);  	if (error) { -		dev_info(kp->dbg_dev, "request_irq failed for irq no=%d\n", -			kp->irq); -		goto err2; +		dev_info(kp->dbg_dev, "request_irq failed for irq no=%d: %d\n", +			kp->irq, error); +		return error;  	}  	/* Enable KP and TO interrupts now. */  	reg = (u8) ~(KEYP_IMR1_KP | KEYP_IMR1_TO);  	if (twl4030_kpwrite_u8(kp, reg, KEYP_IMR1)) { -		error = -EIO; -		goto err3; +		/* mask all events - we don't care about the result */ +		(void) twl4030_kpwrite_u8(kp, 0xff, KEYP_IMR1); +		return -EIO;  	}  	platform_set_drvdata(pdev, kp);  	return 0; - -err3: -	/* mask all events - we don't care about the result */ -	(void) twl4030_kpwrite_u8(kp, 0xff, KEYP_IMR1); -	free_irq(kp->irq, kp); -err2: -	input_unregister_device(input); -	input = NULL; -err1: -	input_free_device(input); -	kfree(kp); -	return error;  } -static int twl4030_kp_remove(struct platform_device *pdev) -{ -	struct twl4030_keypad *kp = platform_get_drvdata(pdev); - -	free_irq(kp->irq, kp); -	input_unregister_device(kp->input); -	kfree(kp); - -	return 0; -} +#ifdef CONFIG_OF +static const struct of_device_id twl4030_keypad_dt_match_table[] = { +	{ .compatible = "ti,twl4030-keypad" }, +	{}, +}; +MODULE_DEVICE_TABLE(of, twl4030_keypad_dt_match_table); +#endif  /*   * NOTE: twl4030 are multi-function devices connected via I2C. @@ -451,10 +457,10 @@ static int twl4030_kp_remove(struct platform_device *pdev)  static struct platform_driver twl4030_kp_driver = {  	.probe		= twl4030_kp_probe, -	.remove		= twl4030_kp_remove,  	.driver		= {  		.name	= "twl4030_keypad",  		.owner	= THIS_MODULE, +		.of_match_table = of_match_ptr(twl4030_keypad_dt_match_table),  	},  };  module_platform_driver(twl4030_kp_driver); diff --git a/drivers/input/keyboard/w90p910_keypad.c b/drivers/input/keyboard/w90p910_keypad.c index 7b039162a3f..e8b9d94daae 100644 --- a/drivers/input/keyboard/w90p910_keypad.c +++ b/drivers/input/keyboard/w90p910_keypad.c @@ -11,7 +11,6 @@  #include <linux/kernel.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/input.h>  #include <linux/device.h> @@ -121,7 +120,7 @@ static void w90p910_keypad_close(struct input_dev *dev)  static int w90p910_keypad_probe(struct platform_device *pdev)  {  	const struct w90p910_keypad_platform_data *pdata = -						pdev->dev.platform_data; +						dev_get_platdata(&pdev->dev);  	const struct matrix_keymap_data *keymap_data;  	struct w90p910_keypad *keypad;  	struct input_dev *input_dev; diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c index d050d9d0011..7c2325bd740 100644 --- a/drivers/input/keyboard/xtkbd.c +++ b/drivers/input/keyboard/xtkbd.c @@ -29,7 +29,6 @@  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/input.h> -#include <linux/init.h>  #include <linux/serio.h>  #define DRIVER_DESC	"XT keyboard driver" diff --git a/drivers/input/misc/88pm860x_onkey.c b/drivers/input/misc/88pm860x_onkey.c index abd8453e521..220ce0fa15d 100644 --- a/drivers/input/misc/88pm860x_onkey.c +++ b/drivers/input/misc/88pm860x_onkey.c @@ -26,6 +26,7 @@  #include <linux/interrupt.h>  #include <linux/mfd/88pm860x.h>  #include <linux/slab.h> +#include <linux/device.h>  #define PM8607_WAKEUP		0x0b @@ -68,7 +69,8 @@ static int pm860x_onkey_probe(struct platform_device *pdev)  		return -EINVAL;  	} -	info = kzalloc(sizeof(struct pm860x_onkey_info), GFP_KERNEL); +	info = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_onkey_info), +			    GFP_KERNEL);  	if (!info)  		return -ENOMEM;  	info->chip = chip; @@ -76,11 +78,10 @@ static int pm860x_onkey_probe(struct platform_device *pdev)  	info->dev = &pdev->dev;  	info->irq = irq; -	info->idev = input_allocate_device(); +	info->idev = devm_input_allocate_device(&pdev->dev);  	if (!info->idev) {  		dev_err(chip->dev, "Failed to allocate input dev\n"); -		ret = -ENOMEM; -		goto out; +		return -ENOMEM;  	}  	info->idev->name = "88pm860x_on"; @@ -93,42 +94,22 @@ static int pm860x_onkey_probe(struct platform_device *pdev)  	ret = input_register_device(info->idev);  	if (ret) {  		dev_err(chip->dev, "Can't register input device: %d\n", ret); -		goto out_reg; +		return ret;  	} -	ret = request_threaded_irq(info->irq, NULL, pm860x_onkey_handler, -				   IRQF_ONESHOT, "onkey", info); +	ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL, +					pm860x_onkey_handler, IRQF_ONESHOT, +					"onkey", info);  	if (ret < 0) {  		dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",  			info->irq, ret); -		goto out_irq; +		return ret;  	}  	platform_set_drvdata(pdev, info);  	device_init_wakeup(&pdev->dev, 1);  	return 0; - -out_irq: -	input_unregister_device(info->idev); -	kfree(info); -	return ret; - -out_reg: -	input_free_device(info->idev); -out: -	kfree(info); -	return ret; -} - -static int pm860x_onkey_remove(struct platform_device *pdev) -{ -	struct pm860x_onkey_info *info = platform_get_drvdata(pdev); - -	free_irq(info->irq, info); -	input_unregister_device(info->idev); -	kfree(info); -	return 0;  }  #ifdef CONFIG_PM_SLEEP @@ -161,7 +142,6 @@ static struct platform_driver pm860x_onkey_driver = {  		.pm	= &pm860x_onkey_pm_ops,  	},  	.probe		= pm860x_onkey_probe, -	.remove		= pm860x_onkey_remove,  };  module_platform_driver(pm860x_onkey_driver); diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index aa51baaa9b1..2ff4425a893 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -156,7 +156,7 @@ config INPUT_MAX8925_ONKEY  config INPUT_MAX8997_HAPTIC  	tristate "MAXIM MAX8997 haptic controller support" -	depends on HAVE_PWM && MFD_MAX8997 +	depends on PWM && MFD_MAX8997  	select INPUT_FF_MEMLESS  	help  	  This option enables device driver support for the haptic controller @@ -168,7 +168,7 @@ config INPUT_MAX8997_HAPTIC  config INPUT_MC13783_PWRBUTTON  	tristate "MC13783 ON buttons" -	depends on MFD_MC13783 +	depends on MFD_MC13XXX  	help  	  Support the ON buttons of MC13783 PMIC as an input device  	  reporting power button status. @@ -222,6 +222,15 @@ config INPUT_GP2A  	  To compile this driver as a module, choose M here: the  	  module will be called gp2ap002a00f. +config INPUT_GPIO_BEEPER +	tristate "Generic GPIO Beeper support" +	depends on GPIOLIB +	help +	  Say Y here if you have a beeper connected to a GPIO pin. + +	  To compile this driver as a module, choose M here: the +	  module will be called gpio-beeper. +  config INPUT_GPIO_TILT_POLLED  	tristate "Polled GPIO tilt switch"  	depends on GPIOLIB @@ -260,7 +269,7 @@ config INPUT_COBALT_BTNS  config INPUT_WISTRON_BTNS  	tristate "x86 Wistron laptop button interface" -	depends on X86 && !X86_64 +	depends on X86_32  	select INPUT_POLLDEV  	select INPUT_SPARSEKMAP  	select NEW_LEDS @@ -461,7 +470,7 @@ config INPUT_PCF8574  config INPUT_PWM_BEEPER  	tristate "PWM beeper support" -	depends on HAVE_PWM || PWM +	depends on PWM  	help  	  Say Y here to get support for PWM based beeper devices. @@ -657,4 +666,14 @@ config INPUT_IDEAPAD_SLIDEBAR  	  To compile this driver as a module, choose M here: the  	  module will be called ideapad_slidebar. +config INPUT_SOC_BUTTON_ARRAY +	tristate "Windows-compatible SoC Button Array" +	depends on KEYBOARD_GPIO +	help +	  Say Y here if you have a SoC-based tablet that originally +	  runs Windows 8. + +	  To compile this driver as a module, choose M here: the +	  module will be called soc_button_array. +  endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 0ebfb6dbf0f..4955ad322a0 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_INPUT_DA9052_ONKEY)	+= da9052_onkey.o  obj-$(CONFIG_INPUT_DA9055_ONKEY)	+= da9055_onkey.o  obj-$(CONFIG_INPUT_DM355EVM)		+= dm355evm_keys.o  obj-$(CONFIG_INPUT_GP2A)		+= gp2ap002a00f.o +obj-$(CONFIG_INPUT_GPIO_BEEPER)		+= gpio-beeper.o  obj-$(CONFIG_INPUT_GPIO_TILT_POLLED)	+= gpio_tilt_polled.o  obj-$(CONFIG_HP_SDC_RTC)		+= hp_sdc_rtc.o  obj-$(CONFIG_INPUT_IMS_PCU)		+= ims-pcu.o @@ -52,6 +53,7 @@ obj-$(CONFIG_INPUT_RETU_PWRBUTTON)	+= retu-pwrbutton.o  obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER)	+= rotary_encoder.o  obj-$(CONFIG_INPUT_SGI_BTNS)		+= sgi_btns.o  obj-$(CONFIG_INPUT_SIRFSOC_ONKEY)	+= sirfsoc-onkey.o +obj-$(CONFIG_INPUT_SOC_BUTTON_ARRAY)	+= soc_button_array.o  obj-$(CONFIG_INPUT_SPARCSPKR)		+= sparcspkr.o  obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON)	+= twl4030-pwrbutton.o  obj-$(CONFIG_INPUT_TWL4030_VIBRA)	+= twl4030-vibra.o diff --git a/drivers/input/misc/ab8500-ponkey.c b/drivers/input/misc/ab8500-ponkey.c index f2fbdd88ed2..95ef7dd6442 100644 --- a/drivers/input/misc/ab8500-ponkey.c +++ b/drivers/input/misc/ab8500-ponkey.c @@ -7,6 +7,7 @@   * AB8500 Power-On Key handler   */ +#include <linux/device.h>  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/platform_device.h> @@ -65,12 +66,14 @@ static int ab8500_ponkey_probe(struct platform_device *pdev)  		return irq_dbr;  	} -	ponkey = kzalloc(sizeof(struct ab8500_ponkey), GFP_KERNEL); -	input = input_allocate_device(); -	if (!ponkey || !input) { -		error = -ENOMEM; -		goto err_free_mem; -	} +	ponkey = devm_kzalloc(&pdev->dev, sizeof(struct ab8500_ponkey), +			      GFP_KERNEL); +	if (!ponkey) +		return -ENOMEM; + +	input = devm_input_allocate_device(&pdev->dev); +	if (!input) +		return -ENOMEM;  	ponkey->idev = input;  	ponkey->ab8500 = ab8500; @@ -82,52 +85,32 @@ static int ab8500_ponkey_probe(struct platform_device *pdev)  	input_set_capability(input, EV_KEY, KEY_POWER); -	error = request_any_context_irq(ponkey->irq_dbf, ab8500_ponkey_handler, -					0, "ab8500-ponkey-dbf", ponkey); +	error = devm_request_any_context_irq(&pdev->dev, ponkey->irq_dbf, +					     ab8500_ponkey_handler, 0, +					     "ab8500-ponkey-dbf", ponkey);  	if (error < 0) {  		dev_err(ab8500->dev, "Failed to request dbf IRQ#%d: %d\n",  			ponkey->irq_dbf, error); -		goto err_free_mem; +		return error;  	} -	error = request_any_context_irq(ponkey->irq_dbr, ab8500_ponkey_handler, -					0, "ab8500-ponkey-dbr", ponkey); +	error = devm_request_any_context_irq(&pdev->dev, ponkey->irq_dbr, +					     ab8500_ponkey_handler, 0, +					     "ab8500-ponkey-dbr", ponkey);  	if (error < 0) {  		dev_err(ab8500->dev, "Failed to request dbr IRQ#%d: %d\n",  			ponkey->irq_dbr, error); -		goto err_free_dbf_irq; +		return error;  	}  	error = input_register_device(ponkey->idev);  	if (error) {  		dev_err(ab8500->dev, "Can't register input device: %d\n", error); -		goto err_free_dbr_irq; +		return error;  	}  	platform_set_drvdata(pdev, ponkey);  	return 0; - -err_free_dbr_irq: -	free_irq(ponkey->irq_dbr, ponkey); -err_free_dbf_irq: -	free_irq(ponkey->irq_dbf, ponkey); -err_free_mem: -	input_free_device(input); -	kfree(ponkey); - -	return error; -} - -static int ab8500_ponkey_remove(struct platform_device *pdev) -{ -	struct ab8500_ponkey *ponkey = platform_get_drvdata(pdev); - -	free_irq(ponkey->irq_dbf, ponkey); -	free_irq(ponkey->irq_dbr, ponkey); -	input_unregister_device(ponkey->idev); -	kfree(ponkey); - -	return 0;  }  #ifdef CONFIG_OF @@ -144,7 +127,6 @@ static struct platform_driver ab8500_ponkey_driver = {  		.of_match_table = of_match_ptr(ab8500_ponkey_match),  	},  	.probe		= ab8500_ponkey_probe, -	.remove		= ab8500_ponkey_remove,  };  module_platform_driver(ab8500_ponkey_driver); diff --git a/drivers/input/misc/ad714x-spi.c b/drivers/input/misc/ad714x-spi.c index 61891486067..3a90b710e30 100644 --- a/drivers/input/misc/ad714x-spi.c +++ b/drivers/input/misc/ad714x-spi.c @@ -108,7 +108,6 @@ static int ad714x_spi_remove(struct spi_device *spi)  	struct ad714x_chip *chip = spi_get_drvdata(spi);  	ad714x_remove(chip); -	spi_set_drvdata(spi, NULL);  	return 0;  } diff --git a/drivers/input/misc/ad714x.c b/drivers/input/misc/ad714x.c index 2e5d5e1de64..7a61e9ee682 100644 --- a/drivers/input/misc/ad714x.c +++ b/drivers/input/misc/ad714x.c @@ -7,7 +7,6 @@   */  #include <linux/device.h> -#include <linux/init.h>  #include <linux/input.h>  #include <linux/interrupt.h>  #include <linux/slab.h> @@ -969,7 +968,7 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,  	int error;  	struct input_dev *input[MAX_DEVICE_NUM]; -	struct ad714x_platform_data *plat_data = dev->platform_data; +	struct ad714x_platform_data *plat_data = dev_get_platdata(dev);  	struct ad714x_chip *ad714x;  	void *drv_mem;  	unsigned long irqflags; @@ -986,7 +985,7 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,  		goto err_out;  	} -	if (dev->platform_data == NULL) { +	if (dev_get_platdata(dev) == NULL) {  		dev_err(dev, "platform data for ad714x doesn't exist\n");  		error = -EINVAL;  		goto err_out; diff --git a/drivers/input/misc/adxl34x.c b/drivers/input/misc/adxl34x.c index 0735de3a646..2b2d02f408b 100644 --- a/drivers/input/misc/adxl34x.c +++ b/drivers/input/misc/adxl34x.c @@ -8,7 +8,6 @@   */  #include <linux/device.h> -#include <linux/init.h>  #include <linux/delay.h>  #include <linux/input.h>  #include <linux/interrupt.h> @@ -158,7 +157,7 @@  /* ORIENT ADXL346 only */  #define ADXL346_2D_VALID		(1 << 6) -#define ADXL346_2D_ORIENT(x)		(((x) & 0x3) >> 4) +#define ADXL346_2D_ORIENT(x)		(((x) & 0x30) >> 4)  #define ADXL346_3D_VALID		(1 << 3)  #define ADXL346_3D_ORIENT(x)		((x) & 0x7)  #define ADXL346_2D_PORTRAIT_POS		0	/* +X */ @@ -714,7 +713,7 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,  	ac->fifo_delay = fifo_delay_default; -	pdata = dev->platform_data; +	pdata = dev_get_platdata(dev);  	if (!pdata) {  		dev_dbg(dev,  			"No platform data: Using default initialization\n"); diff --git a/drivers/input/misc/arizona-haptics.c b/drivers/input/misc/arizona-haptics.c index 7a04f54ef96..ef2e281b0a4 100644 --- a/drivers/input/misc/arizona-haptics.c +++ b/drivers/input/misc/arizona-haptics.c @@ -37,7 +37,6 @@ static void arizona_haptics_work(struct work_struct *work)  						       struct arizona_haptics,  						       work);  	struct arizona *arizona = haptics->arizona; -	struct mutex *dapm_mutex = &arizona->dapm->card->dapm_mutex;  	int ret;  	if (!haptics->arizona->dapm) { @@ -67,13 +66,10 @@ static void arizona_haptics_work(struct work_struct *work)  			return;  		} -		mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); -  		ret = snd_soc_dapm_enable_pin(arizona->dapm, "HAPTICS");  		if (ret != 0) {  			dev_err(arizona->dev, "Failed to start HAPTICS: %d\n",  				ret); -			mutex_unlock(dapm_mutex);  			return;  		} @@ -81,21 +77,14 @@ static void arizona_haptics_work(struct work_struct *work)  		if (ret != 0) {  			dev_err(arizona->dev, "Failed to sync DAPM: %d\n",  				ret); -			mutex_unlock(dapm_mutex);  			return;  		} - -		mutex_unlock(dapm_mutex); -  	} else {  		/* This disable sequence will be a noop if already enabled */ -		mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); -  		ret = snd_soc_dapm_disable_pin(arizona->dapm, "HAPTICS");  		if (ret != 0) {  			dev_err(arizona->dev, "Failed to disable HAPTICS: %d\n",  				ret); -			mutex_unlock(dapm_mutex);  			return;  		} @@ -103,12 +92,9 @@ static void arizona_haptics_work(struct work_struct *work)  		if (ret != 0) {  			dev_err(arizona->dev, "Failed to sync DAPM: %d\n",  				ret); -			mutex_unlock(dapm_mutex);  			return;  		} -		mutex_unlock(dapm_mutex); -  		ret = regmap_update_bits(arizona->regmap,  					 ARIZONA_HAPTICS_CONTROL_1,  					 ARIZONA_HAP_CTRL_MASK, @@ -155,16 +141,11 @@ static int arizona_haptics_play(struct input_dev *input, void *data,  static void arizona_haptics_close(struct input_dev *input)  {  	struct arizona_haptics *haptics = input_get_drvdata(input); -	struct mutex *dapm_mutex = &haptics->arizona->dapm->card->dapm_mutex;  	cancel_work_sync(&haptics->work); -	mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); -  	if (haptics->arizona->dapm)  		snd_soc_dapm_disable_pin(haptics->arizona->dapm, "HAPTICS"); - -	mutex_unlock(dapm_mutex);  }  static int arizona_haptics_probe(struct platform_device *pdev) diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c index 5d4402365a5..638165c78e7 100644 --- a/drivers/input/misc/atlas_btns.c +++ b/drivers/input/misc/atlas_btns.c @@ -25,11 +25,10 @@  #include <linux/kernel.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/input.h>  #include <linux/types.h> +#include <linux/acpi.h>  #include <asm/uaccess.h> -#include <acpi/acpi_drivers.h>  #define ACPI_ATLAS_NAME		"Atlas ACPI"  #define ACPI_ATLAS_CLASS	"Atlas" diff --git a/drivers/input/misc/bfin_rotary.c b/drivers/input/misc/bfin_rotary.c index cd139cb17e3..e69d9bcb37e 100644 --- a/drivers/input/misc/bfin_rotary.c +++ b/drivers/input/misc/bfin_rotary.c @@ -6,7 +6,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/irq.h>  #include <linux/pm.h> @@ -92,7 +91,7 @@ static irqreturn_t bfin_rotary_isr(int irq, void *dev_id)  static int bfin_rotary_probe(struct platform_device *pdev)  { -	struct bfin_rotary_platform_data *pdata = pdev->dev.platform_data; +	struct bfin_rotary_platform_data *pdata = dev_get_platdata(&pdev->dev);  	struct bfin_rot *rotary;  	struct input_dev *input;  	int error; diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c index 865c2f9d25b..b36831c828d 100644 --- a/drivers/input/misc/bma150.c +++ b/drivers/input/misc/bma150.c @@ -70,6 +70,7 @@  #define BMA150_CFG_5_REG	0x11  #define BMA150_CHIP_ID		2 +#define BMA180_CHIP_ID		3  #define BMA150_CHIP_ID_REG	BMA150_DATA_0_REG  #define BMA150_ACC_X_LSB_REG	BMA150_DATA_2_REG @@ -526,7 +527,8 @@ static int bma150_register_polled_device(struct bma150_data *bma150)  static int bma150_probe(struct i2c_client *client,  				  const struct i2c_device_id *id)  { -	const struct bma150_platform_data *pdata = client->dev.platform_data; +	const struct bma150_platform_data *pdata = +			dev_get_platdata(&client->dev);  	const struct bma150_cfg *cfg;  	struct bma150_data *bma150;  	int chip_id; @@ -538,7 +540,7 @@ static int bma150_probe(struct i2c_client *client,  	}  	chip_id = i2c_smbus_read_byte_data(client, BMA150_CHIP_ID_REG); -	if (chip_id != BMA150_CHIP_ID) { +	if (chip_id != BMA150_CHIP_ID && chip_id != BMA180_CHIP_ID) {  		dev_err(&client->dev, "BMA150 chip id error: %d\n", chip_id);  		return -EINVAL;  	} @@ -642,6 +644,7 @@ static UNIVERSAL_DEV_PM_OPS(bma150_pm, bma150_suspend, bma150_resume, NULL);  static const struct i2c_device_id bma150_id[] = {  	{ "bma150", 0 }, +	{ "bma180", 0 },  	{ "smb380", 0 },  	{ "bma023", 0 },  	{ } diff --git a/drivers/input/misc/cm109.c b/drivers/input/misc/cm109.c index 082684e7f39..9365535ba7f 100644 --- a/drivers/input/misc/cm109.c +++ b/drivers/input/misc/cm109.c @@ -351,7 +351,9 @@ static void cm109_urb_irq_callback(struct urb *urb)  	if (status) {  		if (status == -ESHUTDOWN)  			return; -		dev_err(&dev->intf->dev, "%s: urb status %d\n", __func__, status); +		dev_err_ratelimited(&dev->intf->dev, "%s: urb status %d\n", +				    __func__, status); +		goto out;  	}  	/* Special keys */ @@ -418,8 +420,12 @@ static void cm109_urb_ctl_callback(struct urb *urb)  	     dev->ctl_data->byte[2],  	     dev->ctl_data->byte[3]); -	if (status) -		dev_err(&dev->intf->dev, "%s: urb status %d\n", __func__, status); +	if (status) { +		if (status == -ESHUTDOWN) +			return; +		dev_err_ratelimited(&dev->intf->dev, "%s: urb status %d\n", +				    __func__, status); +	}  	spin_lock(&dev->ctl_submit_lock); @@ -427,7 +433,7 @@ static void cm109_urb_ctl_callback(struct urb *urb)  	if (likely(!dev->shutdown)) { -		if (dev->buzzer_pending) { +		if (dev->buzzer_pending || status) {  			dev->buzzer_pending = 0;  			dev->ctl_urb_pending = 1;  			cm109_submit_buzz_toggle(dev); diff --git a/drivers/input/misc/cma3000_d0x.c b/drivers/input/misc/cma3000_d0x.c index df9b756594f..c7d00748277 100644 --- a/drivers/input/misc/cma3000_d0x.c +++ b/drivers/input/misc/cma3000_d0x.c @@ -284,7 +284,7 @@ EXPORT_SYMBOL(cma3000_resume);  struct cma3000_accl_data *cma3000_init(struct device *dev, int irq,  				       const struct cma3000_bus_ops *bops)  { -	const struct cma3000_platform_data *pdata = dev->platform_data; +	const struct cma3000_platform_data *pdata = dev_get_platdata(dev);  	struct cma3000_accl_data *data;  	struct input_dev *input_dev;  	int rev; diff --git a/drivers/input/misc/cobalt_btns.c b/drivers/input/misc/cobalt_btns.c index 4f77f87847e..3e11510ff82 100644 --- a/drivers/input/misc/cobalt_btns.c +++ b/drivers/input/misc/cobalt_btns.c @@ -17,7 +17,6 @@   *  along with this program; if not, write to the Free Software   *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA   */ -#include <linux/init.h>  #include <linux/input-polldev.h>  #include <linux/ioport.h>  #include <linux/module.h> @@ -131,7 +130,6 @@ static int cobalt_buttons_probe(struct platform_device *pdev)   err_free_mem:  	input_free_polled_device(poll_dev);  	kfree(bdev); -	dev_set_drvdata(&pdev->dev, NULL);  	return error;  } @@ -144,7 +142,6 @@ static int cobalt_buttons_remove(struct platform_device *pdev)  	input_free_polled_device(bdev->poll_dev);  	iounmap(bdev->reg);  	kfree(bdev); -	dev_set_drvdata(dev, NULL);  	return 0;  } diff --git a/drivers/input/misc/da9052_onkey.c b/drivers/input/misc/da9052_onkey.c index 020569a499f..184c8f21ab5 100644 --- a/drivers/input/misc/da9052_onkey.c +++ b/drivers/input/misc/da9052_onkey.c @@ -11,7 +11,6 @@   * option) any later version.   */ -#include <linux/init.h>  #include <linux/input.h>  #include <linux/module.h>  #include <linux/platform_device.h> @@ -28,29 +27,32 @@ struct da9052_onkey {  static void da9052_onkey_query(struct da9052_onkey *onkey)  { -	int key_stat; +	int ret; -	key_stat = da9052_reg_read(onkey->da9052, DA9052_EVENT_B_REG); -	if (key_stat < 0) { +	ret = da9052_reg_read(onkey->da9052, DA9052_STATUS_A_REG); +	if (ret < 0) {  		dev_err(onkey->da9052->dev, -			"Failed to read onkey event %d\n", key_stat); +			"Failed to read onkey event err=%d\n", ret);  	} else {  		/*  		 * Since interrupt for deassertion of ONKEY pin is not  		 * generated, onkey event state determines the onkey  		 * button state.  		 */ -		key_stat &= DA9052_EVENTB_ENONKEY; -		input_report_key(onkey->input, KEY_POWER, key_stat); +		bool pressed = !(ret & DA9052_STATUSA_NONKEY); + +		input_report_key(onkey->input, KEY_POWER, pressed);  		input_sync(onkey->input); -	} -	/* -	 * Interrupt is generated only when the ONKEY pin is asserted. -	 * Hence the deassertion of the pin is simulated through work queue. -	 */ -	if (key_stat) -		schedule_delayed_work(&onkey->work, msecs_to_jiffies(50)); +		/* +		 * Interrupt is generated only when the ONKEY pin +		 * is asserted.  Hence the deassertion of the pin +		 * is simulated through work queue. +		 */ +		if (pressed) +			schedule_delayed_work(&onkey->work, +						msecs_to_jiffies(50)); +	}  }  static void da9052_onkey_work(struct work_struct *work) diff --git a/drivers/input/misc/da9055_onkey.c b/drivers/input/misc/da9055_onkey.c index a0af8b2506c..4765799fef7 100644 --- a/drivers/input/misc/da9055_onkey.c +++ b/drivers/input/misc/da9055_onkey.c @@ -11,7 +11,6 @@   * option) any later version.   */ -#include <linux/init.h>  #include <linux/input.h>  #include <linux/module.h>  #include <linux/platform_device.h> @@ -110,7 +109,6 @@ static int da9055_onkey_probe(struct platform_device *pdev)  	INIT_DELAYED_WORK(&onkey->work, da9055_onkey_work); -	irq = regmap_irq_get_virq(da9055->irq_data, irq);  	err = request_threaded_irq(irq, NULL, da9055_onkey_irq,  				   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,  				   "ONKEY", onkey); diff --git a/drivers/input/misc/dm355evm_keys.c b/drivers/input/misc/dm355evm_keys.c index a309a5c0899..0eba94f581d 100644 --- a/drivers/input/misc/dm355evm_keys.c +++ b/drivers/input/misc/dm355evm_keys.c @@ -9,7 +9,6 @@   * 2 of the License, or (at your option) any later version.   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/input/sparse-keymap.h> diff --git a/drivers/input/misc/gp2ap002a00f.c b/drivers/input/misc/gp2ap002a00f.c index fe30bd0fe4b..de21e317da3 100644 --- a/drivers/input/misc/gp2ap002a00f.c +++ b/drivers/input/misc/gp2ap002a00f.c @@ -125,7 +125,7 @@ static int gp2a_initialize(struct gp2a_data *dt)  static int gp2a_probe(struct i2c_client *client,  				const struct i2c_device_id *id)  { -	const struct gp2a_platform_data *pdata = client->dev.platform_data; +	const struct gp2a_platform_data *pdata = dev_get_platdata(&client->dev);  	struct gp2a_data *dt;  	int error; diff --git a/drivers/input/misc/gpio-beeper.c b/drivers/input/misc/gpio-beeper.c new file mode 100644 index 00000000000..8886af63eae --- /dev/null +++ b/drivers/input/misc/gpio-beeper.c @@ -0,0 +1,124 @@ +/* + * Generic GPIO beeper driver + * + * Copyright (C) 2013-2014 Alexander Shiyan <shc_work@mail.ru> + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/input.h> +#include <linux/module.h> +#include <linux/gpio/consumer.h> +#include <linux/of.h> +#include <linux/workqueue.h> +#include <linux/platform_device.h> + +#define BEEPER_MODNAME		"gpio-beeper" + +struct gpio_beeper { +	struct work_struct	work; +	struct gpio_desc	*desc; +	bool			beeping; +}; + +static void gpio_beeper_toggle(struct gpio_beeper *beep, bool on) +{ +	gpiod_set_value_cansleep(beep->desc, on); +} + +static void gpio_beeper_work(struct work_struct *work) +{ +	struct gpio_beeper *beep = container_of(work, struct gpio_beeper, work); + +	gpio_beeper_toggle(beep, beep->beeping); +} + +static int gpio_beeper_event(struct input_dev *dev, unsigned int type, +			     unsigned int code, int value) +{ +	struct gpio_beeper *beep = input_get_drvdata(dev); + +	if (type != EV_SND || code != SND_BELL) +		return -ENOTSUPP; + +	if (value < 0) +		return -EINVAL; + +	beep->beeping = value; +	/* Schedule work to actually turn the beeper on or off */ +	schedule_work(&beep->work); + +	return 0; +} + +static void gpio_beeper_close(struct input_dev *input) +{ +	struct gpio_beeper *beep = input_get_drvdata(input); + +	cancel_work_sync(&beep->work); +	gpio_beeper_toggle(beep, false); +} + +static int gpio_beeper_probe(struct platform_device *pdev) +{ +	struct gpio_beeper *beep; +	struct input_dev *input; +	int err; + +	beep = devm_kzalloc(&pdev->dev, sizeof(*beep), GFP_KERNEL); +	if (!beep) +		return -ENOMEM; + +	beep->desc = devm_gpiod_get(&pdev->dev, NULL); +	if (IS_ERR(beep->desc)) +		return PTR_ERR(beep->desc); + +	input = devm_input_allocate_device(&pdev->dev); +	if (!input) +		return -ENOMEM; + +	INIT_WORK(&beep->work, gpio_beeper_work); + +	input->name		= pdev->name; +	input->id.bustype	= BUS_HOST; +	input->id.vendor	= 0x0001; +	input->id.product	= 0x0001; +	input->id.version	= 0x0100; +	input->close		= gpio_beeper_close; +	input->event		= gpio_beeper_event; + +	input_set_capability(input, EV_SND, SND_BELL); + +	err = gpiod_direction_output(beep->desc, 0); +	if (err) +		return err; + +	input_set_drvdata(input, beep); + +	return input_register_device(input); +} + +#ifdef CONFIG_OF +static const struct of_device_id gpio_beeper_of_match[] = { +	{ .compatible = BEEPER_MODNAME, }, +	{ } +}; +MODULE_DEVICE_TABLE(of, gpio_beeper_of_match); +#endif + +static struct platform_driver gpio_beeper_platform_driver = { +	.driver	= { +		.name		= BEEPER_MODNAME, +		.owner		= THIS_MODULE, +		.of_match_table	= of_match_ptr(gpio_beeper_of_match), +	}, +	.probe	= gpio_beeper_probe, +}; +module_platform_driver(gpio_beeper_platform_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); +MODULE_DESCRIPTION("Generic GPIO beeper driver"); diff --git a/drivers/input/misc/gpio_tilt_polled.c b/drivers/input/misc/gpio_tilt_polled.c index 714c6836913..1a81d911522 100644 --- a/drivers/input/misc/gpio_tilt_polled.c +++ b/drivers/input/misc/gpio_tilt_polled.c @@ -16,7 +16,6 @@  #include <linux/kernel.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/input-polldev.h> @@ -98,7 +97,8 @@ static void gpio_tilt_polled_close(struct input_polled_dev *dev)  static int gpio_tilt_polled_probe(struct platform_device *pdev)  { -	const struct gpio_tilt_platform_data *pdata = pdev->dev.platform_data; +	const struct gpio_tilt_platform_data *pdata = +			dev_get_platdata(&pdev->dev);  	struct device *dev = &pdev->dev;  	struct gpio_tilt_polled_dev *tdev;  	struct input_polled_dev *poll_dev; diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c index 86b822806e9..45e0e3e55de 100644 --- a/drivers/input/misc/hp_sdc_rtc.c +++ b/drivers/input/misc/hp_sdc_rtc.c @@ -180,7 +180,10 @@ static int64_t hp_sdc_rtc_read_i8042timer (uint8_t loadcmd, int numreg)  	if (WARN_ON(down_interruptible(&i8042tregs)))  		return -1; -	if (hp_sdc_enqueue_transaction(&t)) return -1; +	if (hp_sdc_enqueue_transaction(&t)) { +		up(&i8042tregs); +		return -1; +	}  	/* Sleep until results come back. */  	if (WARN_ON(down_interruptible(&i8042tregs))) diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c index e204f26b001..719410feb84 100644 --- a/drivers/input/misc/ims-pcu.c +++ b/drivers/input/misc/ims-pcu.c @@ -51,6 +51,8 @@ struct ims_pcu_backlight {  #define IMS_PCU_BL_VERSION_LEN		(9 + 1)  #define IMS_PCU_BL_RESET_REASON_LEN	(2 + 1) +#define IMS_PCU_PCU_B_DEVICE_ID		5 +  #define IMS_PCU_BUF_SIZE		128  struct ims_pcu { @@ -68,6 +70,9 @@ struct ims_pcu {  	char bl_version[IMS_PCU_BL_VERSION_LEN];  	char reset_reason[IMS_PCU_BL_RESET_REASON_LEN];  	int update_firmware_status; +	u8 device_id; + +	u8 ofn_reg_addr;  	struct usb_interface *ctrl_intf; @@ -371,6 +376,8 @@ static void ims_pcu_destroy_gamepad(struct ims_pcu *pcu)  #define IMS_PCU_CMD_GET_DEVICE_ID	0xae  #define IMS_PCU_CMD_SPECIAL_INFO	0xb0  #define IMS_PCU_CMD_BOOTLOADER		0xb1	/* Pass data to bootloader */ +#define IMS_PCU_CMD_OFN_SET_CONFIG	0xb3 +#define IMS_PCU_CMD_OFN_GET_CONFIG	0xb4  /* PCU responses */  #define IMS_PCU_RSP_STATUS		0xc0 @@ -389,6 +396,9 @@ static void ims_pcu_destroy_gamepad(struct ims_pcu *pcu)  #define IMS_PCU_RSP_GET_DEVICE_ID	0xce  #define IMS_PCU_RSP_SPECIAL_INFO	0xd0  #define IMS_PCU_RSP_BOOTLOADER		0xd1	/* Bootloader response */ +#define IMS_PCU_RSP_OFN_SET_CONFIG	0xd2 +#define IMS_PCU_RSP_OFN_GET_CONFIG	0xd3 +  #define IMS_PCU_RSP_EVNT_BUTTONS	0xe0	/* Unsolicited, button state */  #define IMS_PCU_GAMEPAD_MASK		0x0001ff80UL	/* Bits 7 through 16 */ @@ -1256,6 +1266,225 @@ static struct attribute_group ims_pcu_attr_group = {  	.attrs		= ims_pcu_attrs,  }; +/* Support for a separate OFN attribute group */ + +#define OFN_REG_RESULT_OFFSET	2 + +static int ims_pcu_read_ofn_config(struct ims_pcu *pcu, u8 addr, u8 *data) +{ +	int error; +	s16 result; + +	error = ims_pcu_execute_command(pcu, OFN_GET_CONFIG, +					&addr, sizeof(addr)); +	if (error) +		return error; + +	result = (s16)get_unaligned_le16(pcu->cmd_buf + OFN_REG_RESULT_OFFSET); +	if (result < 0) +		return -EIO; + +	/* We only need LSB */ +	*data = pcu->cmd_buf[OFN_REG_RESULT_OFFSET]; +	return 0; +} + +static int ims_pcu_write_ofn_config(struct ims_pcu *pcu, u8 addr, u8 data) +{ +	u8 buffer[] = { addr, data }; +	int error; +	s16 result; + +	error = ims_pcu_execute_command(pcu, OFN_SET_CONFIG, +					&buffer, sizeof(buffer)); +	if (error) +		return error; + +	result = (s16)get_unaligned_le16(pcu->cmd_buf + OFN_REG_RESULT_OFFSET); +	if (result < 0) +		return -EIO; + +	return 0; +} + +static ssize_t ims_pcu_ofn_reg_data_show(struct device *dev, +					 struct device_attribute *dattr, +					 char *buf) +{ +	struct usb_interface *intf = to_usb_interface(dev); +	struct ims_pcu *pcu = usb_get_intfdata(intf); +	int error; +	u8 data; + +	mutex_lock(&pcu->cmd_mutex); +	error = ims_pcu_read_ofn_config(pcu, pcu->ofn_reg_addr, &data); +	mutex_unlock(&pcu->cmd_mutex); + +	if (error) +		return error; + +	return scnprintf(buf, PAGE_SIZE, "%x\n", data); +} + +static ssize_t ims_pcu_ofn_reg_data_store(struct device *dev, +					  struct device_attribute *dattr, +					  const char *buf, size_t count) +{ +	struct usb_interface *intf = to_usb_interface(dev); +	struct ims_pcu *pcu = usb_get_intfdata(intf); +	int error; +	u8 value; + +	error = kstrtou8(buf, 0, &value); +	if (error) +		return error; + +	mutex_lock(&pcu->cmd_mutex); +	error = ims_pcu_write_ofn_config(pcu, pcu->ofn_reg_addr, value); +	mutex_unlock(&pcu->cmd_mutex); + +	return error ?: count; +} + +static DEVICE_ATTR(reg_data, S_IRUGO | S_IWUSR, +		   ims_pcu_ofn_reg_data_show, ims_pcu_ofn_reg_data_store); + +static ssize_t ims_pcu_ofn_reg_addr_show(struct device *dev, +					 struct device_attribute *dattr, +					 char *buf) +{ +	struct usb_interface *intf = to_usb_interface(dev); +	struct ims_pcu *pcu = usb_get_intfdata(intf); +	int error; + +	mutex_lock(&pcu->cmd_mutex); +	error = scnprintf(buf, PAGE_SIZE, "%x\n", pcu->ofn_reg_addr); +	mutex_unlock(&pcu->cmd_mutex); + +	return error; +} + +static ssize_t ims_pcu_ofn_reg_addr_store(struct device *dev, +					  struct device_attribute *dattr, +					  const char *buf, size_t count) +{ +	struct usb_interface *intf = to_usb_interface(dev); +	struct ims_pcu *pcu = usb_get_intfdata(intf); +	int error; +	u8 value; + +	error = kstrtou8(buf, 0, &value); +	if (error) +		return error; + +	mutex_lock(&pcu->cmd_mutex); +	pcu->ofn_reg_addr = value; +	mutex_unlock(&pcu->cmd_mutex); + +	return error ?: count; +} + +static DEVICE_ATTR(reg_addr, S_IRUGO | S_IWUSR, +		   ims_pcu_ofn_reg_addr_show, ims_pcu_ofn_reg_addr_store); + +struct ims_pcu_ofn_bit_attribute { +	struct device_attribute dattr; +	u8 addr; +	u8 nr; +}; + +static ssize_t ims_pcu_ofn_bit_show(struct device *dev, +				    struct device_attribute *dattr, +				    char *buf) +{ +	struct usb_interface *intf = to_usb_interface(dev); +	struct ims_pcu *pcu = usb_get_intfdata(intf); +	struct ims_pcu_ofn_bit_attribute *attr = +		container_of(dattr, struct ims_pcu_ofn_bit_attribute, dattr); +	int error; +	u8 data; + +	mutex_lock(&pcu->cmd_mutex); +	error = ims_pcu_read_ofn_config(pcu, attr->addr, &data); +	mutex_unlock(&pcu->cmd_mutex); + +	if (error) +		return error; + +	return scnprintf(buf, PAGE_SIZE, "%d\n", !!(data & (1 << attr->nr))); +} + +static ssize_t ims_pcu_ofn_bit_store(struct device *dev, +				     struct device_attribute *dattr, +				     const char *buf, size_t count) +{ +	struct usb_interface *intf = to_usb_interface(dev); +	struct ims_pcu *pcu = usb_get_intfdata(intf); +	struct ims_pcu_ofn_bit_attribute *attr = +		container_of(dattr, struct ims_pcu_ofn_bit_attribute, dattr); +	int error; +	int value; +	u8 data; + +	error = kstrtoint(buf, 0, &value); +	if (error) +		return error; + +	if (value > 1) +		return -EINVAL; + +	mutex_lock(&pcu->cmd_mutex); + +	error = ims_pcu_read_ofn_config(pcu, attr->addr, &data); +	if (!error) { +		if (value) +			data |= 1U << attr->nr; +		else +			data &= ~(1U << attr->nr); + +		error = ims_pcu_write_ofn_config(pcu, attr->addr, data); +	} + +	mutex_unlock(&pcu->cmd_mutex); + +	return error ?: count; +} + +#define IMS_PCU_OFN_BIT_ATTR(_field, _addr, _nr)			\ +struct ims_pcu_ofn_bit_attribute ims_pcu_ofn_attr_##_field = {		\ +	.dattr = __ATTR(_field, S_IWUSR | S_IRUGO,			\ +			ims_pcu_ofn_bit_show, ims_pcu_ofn_bit_store),	\ +	.addr = _addr,							\ +	.nr = _nr,							\ +} + +static IMS_PCU_OFN_BIT_ATTR(engine_enable,   0x60, 7); +static IMS_PCU_OFN_BIT_ATTR(speed_enable,    0x60, 6); +static IMS_PCU_OFN_BIT_ATTR(assert_enable,   0x60, 5); +static IMS_PCU_OFN_BIT_ATTR(xyquant_enable,  0x60, 4); +static IMS_PCU_OFN_BIT_ATTR(xyscale_enable,  0x60, 1); + +static IMS_PCU_OFN_BIT_ATTR(scale_x2,        0x63, 6); +static IMS_PCU_OFN_BIT_ATTR(scale_y2,        0x63, 7); + +static struct attribute *ims_pcu_ofn_attrs[] = { +	&dev_attr_reg_data.attr, +	&dev_attr_reg_addr.attr, +	&ims_pcu_ofn_attr_engine_enable.dattr.attr, +	&ims_pcu_ofn_attr_speed_enable.dattr.attr, +	&ims_pcu_ofn_attr_assert_enable.dattr.attr, +	&ims_pcu_ofn_attr_xyquant_enable.dattr.attr, +	&ims_pcu_ofn_attr_xyscale_enable.dattr.attr, +	&ims_pcu_ofn_attr_scale_x2.dattr.attr, +	&ims_pcu_ofn_attr_scale_y2.dattr.attr, +	NULL +}; + +static struct attribute_group ims_pcu_ofn_attr_group = { +	.name	= "ofn", +	.attrs	= ims_pcu_ofn_attrs, +}; +  static void ims_pcu_irq(struct urb *urb)  {  	struct ims_pcu *pcu = urb->context; @@ -1337,6 +1566,7 @@ static int ims_pcu_buffers_alloc(struct ims_pcu *pcu)  	if (!pcu->urb_ctrl_buf) {  		dev_err(pcu->dev,  			"Failed to allocate memory for read buffer\n"); +		error = -ENOMEM;  		goto err_free_urb_out_buf;  	} @@ -1624,7 +1854,6 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)  	static atomic_t device_no = ATOMIC_INIT(0);  	const struct ims_pcu_device_info *info; -	u8 device_id;  	int error;  	error = ims_pcu_get_device_info(pcu); @@ -1633,7 +1862,7 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)  		return error;  	} -	error = ims_pcu_identify_type(pcu, &device_id); +	error = ims_pcu_identify_type(pcu, &pcu->device_id);  	if (error) {  		dev_err(pcu->dev,  			"Failed to identify device, error: %d\n", error); @@ -1645,9 +1874,9 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)  		return 0;  	} -	if (device_id >= ARRAY_SIZE(ims_pcu_device_info) || -	    !ims_pcu_device_info[device_id].keymap) { -		dev_err(pcu->dev, "Device ID %d is not valid\n", device_id); +	if (pcu->device_id >= ARRAY_SIZE(ims_pcu_device_info) || +	    !ims_pcu_device_info[pcu->device_id].keymap) { +		dev_err(pcu->dev, "Device ID %d is not valid\n", pcu->device_id);  		/* Same as above, punt to userspace */  		return 0;  	} @@ -1655,11 +1884,21 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)  	/* Device appears to be operable, complete initialization */  	pcu->device_no = atomic_inc_return(&device_no) - 1; +	/* +	 * PCU-B devices, both GEN_1 and GEN_2 do not have OFN sensor +	 */ +	if (pcu->device_id != IMS_PCU_PCU_B_DEVICE_ID) { +		error = sysfs_create_group(&pcu->dev->kobj, +					   &ims_pcu_ofn_attr_group); +		if (error) +			return error; +	} +  	error = ims_pcu_setup_backlight(pcu);  	if (error)  		return error; -	info = &ims_pcu_device_info[device_id]; +	info = &ims_pcu_device_info[pcu->device_id];  	error = ims_pcu_setup_buttons(pcu, info->keymap, info->keymap_len);  	if (error)  		goto err_destroy_backlight; @@ -1674,10 +1913,10 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)  	return 0; -err_destroy_backlight: -	ims_pcu_destroy_backlight(pcu);  err_destroy_buttons:  	ims_pcu_destroy_buttons(pcu); +err_destroy_backlight: +	ims_pcu_destroy_backlight(pcu);  	return error;  } @@ -1691,6 +1930,10 @@ static void ims_pcu_destroy_application_mode(struct ims_pcu *pcu)  			ims_pcu_destroy_gamepad(pcu);  		ims_pcu_destroy_buttons(pcu);  		ims_pcu_destroy_backlight(pcu); + +		if (pcu->device_id != IMS_PCU_PCU_B_DEVICE_ID) +			sysfs_remove_group(&pcu->dev->kobj, +					   &ims_pcu_ofn_attr_group);  	}  } diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c index f34beb228d3..ed8e5e8449d 100644 --- a/drivers/input/misc/ixp4xx-beeper.c +++ b/drivers/input/misc/ixp4xx-beeper.c @@ -20,6 +20,7 @@  #include <linux/delay.h>  #include <linux/platform_device.h>  #include <linux/interrupt.h> +#include <linux/gpio.h>  #include <mach/hardware.h>  MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); @@ -35,15 +36,12 @@ static void ixp4xx_spkr_control(unsigned int pin, unsigned int count)  	spin_lock_irqsave(&beep_lock, flags); -	 if (count) { -		gpio_line_config(pin, IXP4XX_GPIO_OUT); -		gpio_line_set(pin, IXP4XX_GPIO_LOW); - +	if (count) { +		gpio_direction_output(pin, 0);  		*IXP4XX_OSRT2 = (count & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE;  	} else { -		gpio_line_config(pin, IXP4XX_GPIO_IN); -		gpio_line_set(pin, IXP4XX_GPIO_HIGH); - +		gpio_direction_output(pin, 1); +		gpio_direction_input(pin);  		*IXP4XX_OSRT2 = 0;  	} @@ -69,7 +67,7 @@ static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned  	}  	if (value > 20 && value < 32767) -		count = (IXP4XX_TIMER_FREQ / (value * 4)) - 1; +		count = (ixp4xx_timer_freq / (value * 4)) - 1;  	ixp4xx_spkr_control(pin, count); @@ -78,11 +76,13 @@ static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned  static irqreturn_t ixp4xx_spkr_interrupt(int irq, void *dev_id)  { +	unsigned int pin = (unsigned int) dev_id; +  	/* clear interrupt */  	*IXP4XX_OSST = IXP4XX_OSST_TIMER_2_PEND;  	/* flip the beeper output */ -	*IXP4XX_GPIO_GPOUTR ^= (1 << (unsigned int) dev_id); +	gpio_set_value(pin, !gpio_get_value(pin));  	return IRQ_HANDLED;  } @@ -110,11 +110,15 @@ static int ixp4xx_spkr_probe(struct platform_device *dev)  	input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);  	input_dev->event = ixp4xx_spkr_event; +	err = gpio_request(dev->id, "ixp4-beeper"); +	if (err) +		goto err_free_device; +  	err = request_irq(IRQ_IXP4XX_TIMER2, &ixp4xx_spkr_interrupt,  			  IRQF_NO_SUSPEND, "ixp4xx-beeper",  			  (void *) dev->id);  	if (err) -		goto err_free_device; +		goto err_free_gpio;  	err = input_register_device(input_dev);  	if (err) @@ -126,6 +130,8 @@ static int ixp4xx_spkr_probe(struct platform_device *dev)   err_free_irq:  	free_irq(IRQ_IXP4XX_TIMER2, (void *)dev->id); + err_free_gpio: +	gpio_free(dev->id);   err_free_device:  	input_free_device(input_dev); @@ -144,6 +150,7 @@ static int ixp4xx_spkr_remove(struct platform_device *dev)  	ixp4xx_spkr_control(pin, 0);  	free_irq(IRQ_IXP4XX_TIMER2, (void *)dev->id); +	gpio_free(dev->id);  	return 0;  } diff --git a/drivers/input/misc/keyspan_remote.c b/drivers/input/misc/keyspan_remote.c index 290fa5f97de..01f3b5b300f 100644 --- a/drivers/input/misc/keyspan_remote.c +++ b/drivers/input/misc/keyspan_remote.c @@ -13,7 +13,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/usb/input.h> diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c index a993b67a8a5..d708478bc5b 100644 --- a/drivers/input/misc/kxtj9.c +++ b/drivers/input/misc/kxtj9.c @@ -509,7 +509,8 @@ out:  static int kxtj9_probe(struct i2c_client *client,  				 const struct i2c_device_id *id)  { -	const struct kxtj9_platform_data *pdata = client->dev.platform_data; +	const struct kxtj9_platform_data *pdata = +			dev_get_platdata(&client->dev);  	struct kxtj9_data *tj9;  	int err; diff --git a/drivers/input/misc/max8925_onkey.c b/drivers/input/misc/max8925_onkey.c index eef41cfc054..3809618e6a5 100644 --- a/drivers/input/misc/max8925_onkey.c +++ b/drivers/input/misc/max8925_onkey.c @@ -26,6 +26,7 @@  #include <linux/interrupt.h>  #include <linux/mfd/max8925.h>  #include <linux/slab.h> +#include <linux/device.h>  #define SW_INPUT		(1 << 7)	/* 0/1 -- up/down */  #define HARDRESET_EN		(1 << 7) @@ -81,12 +82,14 @@ static int max8925_onkey_probe(struct platform_device *pdev)  		return -EINVAL;  	} -	info = kzalloc(sizeof(struct max8925_onkey_info), GFP_KERNEL); -	input = input_allocate_device(); -	if (!info || !input) { -		error = -ENOMEM; -		goto err_free_mem; -	} +	info = devm_kzalloc(&pdev->dev, sizeof(struct max8925_onkey_info), +			    GFP_KERNEL); +	if (!info) +		return -ENOMEM; + +	input = devm_input_allocate_device(&pdev->dev); +	if (!input) +		return -ENOMEM;  	info->idev = input;  	info->i2c = chip->i2c; @@ -100,55 +103,34 @@ static int max8925_onkey_probe(struct platform_device *pdev)  	input->dev.parent = &pdev->dev;  	input_set_capability(input, EV_KEY, KEY_POWER); -	error = request_threaded_irq(irq[0], NULL, max8925_onkey_handler, -				     IRQF_ONESHOT, "onkey-down", info); +	error = devm_request_threaded_irq(&pdev->dev, irq[0], NULL, +					  max8925_onkey_handler, IRQF_ONESHOT, +					  "onkey-down", info);  	if (error < 0) {  		dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",  			irq[0], error); -		goto err_free_mem; +		return error;  	} -	error = request_threaded_irq(irq[1], NULL, max8925_onkey_handler, -				     IRQF_ONESHOT, "onkey-up", info); +	error = devm_request_threaded_irq(&pdev->dev, irq[1], NULL, +					  max8925_onkey_handler, IRQF_ONESHOT, +					  "onkey-up", info);  	if (error < 0) {  		dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",  			irq[1], error); -		goto err_free_irq0; +		return error;  	}  	error = input_register_device(info->idev);  	if (error) {  		dev_err(chip->dev, "Can't register input device: %d\n", error); -		goto err_free_irq1; +		return error;  	}  	platform_set_drvdata(pdev, info);  	device_init_wakeup(&pdev->dev, 1);  	return 0; - -err_free_irq1: -	free_irq(irq[1], info); -err_free_irq0: -	free_irq(irq[0], info); -err_free_mem: -	input_free_device(input); -	kfree(info); - -	return error; -} - -static int max8925_onkey_remove(struct platform_device *pdev) -{ -	struct max8925_onkey_info *info = platform_get_drvdata(pdev); -	struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); - -	free_irq(info->irq[0] + chip->irq_base, info); -	free_irq(info->irq[1] + chip->irq_base, info); -	input_unregister_device(info->idev); -	kfree(info); - -	return 0;  }  #ifdef CONFIG_PM_SLEEP @@ -190,7 +172,6 @@ static struct platform_driver max8925_onkey_driver = {  		.pm	= &max8925_onkey_pm_ops,  	},  	.probe		= max8925_onkey_probe, -	.remove		= max8925_onkey_remove,  };  module_platform_driver(max8925_onkey_driver); diff --git a/drivers/input/misc/max8997_haptic.c b/drivers/input/misc/max8997_haptic.c index e973133212a..a363ebbd9cc 100644 --- a/drivers/input/misc/max8997_haptic.c +++ b/drivers/input/misc/max8997_haptic.c @@ -23,7 +23,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/platform_device.h>  #include <linux/err.h> @@ -182,11 +181,21 @@ static void max8997_haptic_enable(struct max8997_haptic *chip)  	}  	if (!chip->enabled) { -		chip->enabled = true; -		regulator_enable(chip->regulator); +		error = regulator_enable(chip->regulator); +		if (error) { +			dev_err(chip->dev, "Failed to enable regulator\n"); +			goto out; +		}  		max8997_haptic_configure(chip); -		if (chip->mode == MAX8997_EXTERNAL_MODE) -			pwm_enable(chip->pwm); +		if (chip->mode == MAX8997_EXTERNAL_MODE) { +			error = pwm_enable(chip->pwm); +			if (error) { +				dev_err(chip->dev, "Failed to enable PWM\n"); +				regulator_disable(chip->regulator); +				goto out; +			} +		} +		chip->enabled = true;  	}  out: diff --git a/drivers/input/misc/mc13783-pwrbutton.c b/drivers/input/misc/mc13783-pwrbutton.c index d0277a7b157..0df6e8d8bd0 100644 --- a/drivers/input/misc/mc13783-pwrbutton.c +++ b/drivers/input/misc/mc13783-pwrbutton.c @@ -20,7 +20,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/kernel.h>  #include <linux/errno.h>  #include <linux/input.h> diff --git a/drivers/input/misc/mma8450.c b/drivers/input/misc/mma8450.c index f3309696d05..59d4dcddf6d 100644 --- a/drivers/input/misc/mma8450.c +++ b/drivers/input/misc/mma8450.c @@ -168,7 +168,7 @@ static void mma8450_close(struct input_polled_dev *dev)   * I2C init/probing/exit functions   */  static int mma8450_probe(struct i2c_client *c, -				   const struct i2c_device_id *id) +			 const struct i2c_device_id *id)  {  	struct input_polled_dev *idev;  	struct mma8450 *m; @@ -204,6 +204,8 @@ static int mma8450_probe(struct i2c_client *c,  		goto err_free_mem;  	} +	i2c_set_clientdata(c, m); +  	return 0;  err_free_mem: diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c index dce0d95943c..5e5051351c3 100644 --- a/drivers/input/misc/mpu3050.c +++ b/drivers/input/misc/mpu3050.c @@ -30,7 +30,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/platform_device.h>  #include <linux/mutex.h> @@ -383,6 +382,7 @@ static int mpu3050_probe(struct i2c_client *client,  	pm_runtime_enable(&client->dev);  	pm_runtime_set_autosuspend_delay(&client->dev, MPU3050_AUTO_DELAY); +	i2c_set_clientdata(client, sensor);  	return 0; diff --git a/drivers/input/misc/pcap_keys.c b/drivers/input/misc/pcap_keys.c index 40ac9a5adf8..cd230365166 100644 --- a/drivers/input/misc/pcap_keys.c +++ b/drivers/input/misc/pcap_keys.c @@ -12,7 +12,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/platform_device.h>  #include <linux/input.h> diff --git a/drivers/input/misc/pcf50633-input.c b/drivers/input/misc/pcf50633-input.c index 73b13ebabe5..db92f4f3c99 100644 --- a/drivers/input/misc/pcf50633-input.c +++ b/drivers/input/misc/pcf50633-input.c @@ -16,7 +16,6 @@  #include <linux/kernel.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/device.h>  #include <linux/platform_device.h>  #include <linux/input.h> diff --git a/drivers/input/misc/pcf8574_keypad.c b/drivers/input/misc/pcf8574_keypad.c index e37392976fd..97f711a7bd2 100644 --- a/drivers/input/misc/pcf8574_keypad.c +++ b/drivers/input/misc/pcf8574_keypad.c @@ -7,7 +7,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/input.h>  #include <linux/interrupt.h>  #include <linux/i2c.h> @@ -113,9 +112,12 @@ static int pcf8574_kp_probe(struct i2c_client *client, const struct i2c_device_i  	idev->keycodemax = ARRAY_SIZE(lp->btncode);  	for (i = 0; i < ARRAY_SIZE(pcf8574_kp_btncode); i++) { -		lp->btncode[i] = pcf8574_kp_btncode[i]; -		__set_bit(lp->btncode[i] & KEY_MAX, idev->keybit); +		if (lp->btncode[i] <= KEY_MAX) { +			lp->btncode[i] = pcf8574_kp_btncode[i]; +			__set_bit(lp->btncode[i], idev->keybit); +		}  	} +	__clear_bit(KEY_RESERVED, idev->keybit);  	sprintf(lp->name, DRV_NAME);  	sprintf(lp->phys, "kp_data/input0"); diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 7288b267613..674a2cfc3c0 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -15,7 +15,6 @@  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/i8253.h> -#include <linux/init.h>  #include <linux/input.h>  #include <linux/platform_device.h>  #include <linux/timex.h> diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c index ec086f6f3cc..6a915ba31bb 100644 --- a/drivers/input/misc/pm8xxx-vibrator.c +++ b/drivers/input/misc/pm8xxx-vibrator.c @@ -11,13 +11,12 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/kernel.h>  #include <linux/errno.h>  #include <linux/platform_device.h>  #include <linux/input.h>  #include <linux/slab.h> -#include <linux/mfd/pm8xxx/core.h> +#include <linux/regmap.h>  #define VIB_DRV			0x4A @@ -35,7 +34,7 @@   * struct pm8xxx_vib - structure to hold vibrator data   * @vib_input_dev: input device supporting force feedback   * @work: work structure to set the vibration parameters - * @dev: device supporting force feedback + * @regmap: regmap for register read/write   * @speed: speed of vibration set from userland   * @active: state of vibrator   * @level: level of vibration to set in the chip @@ -44,7 +43,7 @@  struct pm8xxx_vib {  	struct input_dev *vib_input_dev;  	struct work_struct work; -	struct device *dev; +	struct regmap *regmap;  	int speed;  	int level;  	bool active; @@ -52,42 +51,6 @@ struct pm8xxx_vib {  };  /** - * pm8xxx_vib_read_u8 - helper to read a byte from pmic chip - * @vib: pointer to vibrator structure - * @data: placeholder for data to be read - * @reg: register address - */ -static int pm8xxx_vib_read_u8(struct pm8xxx_vib *vib, -				 u8 *data, u16 reg) -{ -	int rc; - -	rc = pm8xxx_readb(vib->dev->parent, reg, data); -	if (rc < 0) -		dev_warn(vib->dev, "Error reading pm8xxx reg 0x%x(0x%x)\n", -				reg, rc); -	return rc; -} - -/** - * pm8xxx_vib_write_u8 - helper to write a byte to pmic chip - * @vib: pointer to vibrator structure - * @data: data to write - * @reg: register address - */ -static int pm8xxx_vib_write_u8(struct pm8xxx_vib *vib, -				 u8 data, u16 reg) -{ -	int rc; - -	rc = pm8xxx_writeb(vib->dev->parent, reg, data); -	if (rc < 0) -		dev_warn(vib->dev, "Error writing pm8xxx reg 0x%x(0x%x)\n", -				reg, rc); -	return rc; -} - -/**   * pm8xxx_vib_set - handler to start/stop vibration   * @vib: pointer to vibrator structure   * @on: state to set @@ -95,14 +58,14 @@ static int pm8xxx_vib_write_u8(struct pm8xxx_vib *vib,  static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on)  {  	int rc; -	u8 val = vib->reg_vib_drv; +	unsigned int val = vib->reg_vib_drv;  	if (on)  		val |= ((vib->level << VIB_DRV_SEL_SHIFT) & VIB_DRV_SEL_MASK);  	else  		val &= ~VIB_DRV_SEL_MASK; -	rc = pm8xxx_vib_write_u8(vib, val, VIB_DRV); +	rc = regmap_write(vib->regmap, VIB_DRV, val);  	if (rc < 0)  		return rc; @@ -118,9 +81,9 @@ static void pm8xxx_work_handler(struct work_struct *work)  {  	struct pm8xxx_vib *vib = container_of(work, struct pm8xxx_vib, work);  	int rc; -	u8 val; +	unsigned int val; -	rc = pm8xxx_vib_read_u8(vib, &val, VIB_DRV); +	rc = regmap_read(vib->regmap, VIB_DRV, &val);  	if (rc < 0)  		return; @@ -179,39 +142,41 @@ static int pm8xxx_vib_play_effect(struct input_dev *dev, void *data,  }  static int pm8xxx_vib_probe(struct platform_device *pdev) -  {  	struct pm8xxx_vib *vib;  	struct input_dev *input_dev;  	int error; -	u8 val; - -	vib = kzalloc(sizeof(*vib), GFP_KERNEL); -	input_dev = input_allocate_device(); -	if (!vib || !input_dev) { -		dev_err(&pdev->dev, "couldn't allocate memory\n"); -		error = -ENOMEM; -		goto err_free_mem; -	} +	unsigned int val; + +	vib = devm_kzalloc(&pdev->dev, sizeof(*vib), GFP_KERNEL); +	if (!vib) +		return -ENOMEM; + +	vib->regmap = dev_get_regmap(pdev->dev.parent, NULL); +	if (!vib->regmap) +		return -ENODEV; + +	input_dev = devm_input_allocate_device(&pdev->dev); +	if (!input_dev) +		return -ENOMEM;  	INIT_WORK(&vib->work, pm8xxx_work_handler); -	vib->dev = &pdev->dev;  	vib->vib_input_dev = input_dev;  	/* operate in manual mode */ -	error = pm8xxx_vib_read_u8(vib, &val, VIB_DRV); +	error = regmap_read(vib->regmap, VIB_DRV, &val);  	if (error < 0) -		goto err_free_mem; +		return error; +  	val &= ~VIB_DRV_EN_MANUAL_MASK; -	error = pm8xxx_vib_write_u8(vib, val, VIB_DRV); +	error = regmap_write(vib->regmap, VIB_DRV, val);  	if (error < 0) -		goto err_free_mem; +		return error;  	vib->reg_vib_drv = val;  	input_dev->name = "pm8xxx_vib_ffmemless";  	input_dev->id.version = 1; -	input_dev->dev.parent = &pdev->dev;  	input_dev->close = pm8xxx_vib_close;  	input_set_drvdata(input_dev, vib);  	input_set_capability(vib->vib_input_dev, EV_FF, FF_RUMBLE); @@ -221,35 +186,17 @@ static int pm8xxx_vib_probe(struct platform_device *pdev)  	if (error) {  		dev_err(&pdev->dev,  			"couldn't register vibrator as FF device\n"); -		goto err_free_mem; +		return error;  	}  	error = input_register_device(input_dev);  	if (error) {  		dev_err(&pdev->dev, "couldn't register input device\n"); -		goto err_destroy_memless; +		return error;  	}  	platform_set_drvdata(pdev, vib);  	return 0; - -err_destroy_memless: -	input_ff_destroy(input_dev); -err_free_mem: -	input_free_device(input_dev); -	kfree(vib); - -	return error; -} - -static int pm8xxx_vib_remove(struct platform_device *pdev) -{ -	struct pm8xxx_vib *vib = platform_get_drvdata(pdev); - -	input_unregister_device(vib->vib_input_dev); -	kfree(vib); - -	return 0;  }  #ifdef CONFIG_PM_SLEEP @@ -266,13 +213,20 @@ static int pm8xxx_vib_suspend(struct device *dev)  static SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL); +static const struct of_device_id pm8xxx_vib_id_table[] = { +	{ .compatible = "qcom,pm8058-vib" }, +	{ .compatible = "qcom,pm8921-vib" }, +	{ } +}; +MODULE_DEVICE_TABLE(of, pm8xxx_vib_id_table); +  static struct platform_driver pm8xxx_vib_driver = {  	.probe		= pm8xxx_vib_probe, -	.remove		= pm8xxx_vib_remove,  	.driver		= {  		.name	= "pm8xxx-vib",  		.owner	= THIS_MODULE,  		.pm	= &pm8xxx_vib_pm_ops, +		.of_match_table = pm8xxx_vib_id_table,  	},  };  module_platform_driver(pm8xxx_vib_driver); diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c index b49b738aa9c..c91e3d33aea 100644 --- a/drivers/input/misc/pmic8xxx-pwrkey.c +++ b/drivers/input/misc/pmic8xxx-pwrkey.c @@ -11,17 +11,15 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/kernel.h>  #include <linux/errno.h>  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/interrupt.h>  #include <linux/platform_device.h> +#include <linux/regmap.h>  #include <linux/log2.h> - -#include <linux/mfd/pm8xxx/core.h> -#include <linux/input/pmic8xxx-pwrkey.h> +#include <linux/of.h>  #define PON_CNTL_1 0x1C  #define PON_CNTL_PULL_UP BIT(7) @@ -32,26 +30,25 @@   * @key_press_irq: key press irq number   */  struct pmic8xxx_pwrkey { -	struct input_dev *pwr;  	int key_press_irq;  }; -static irqreturn_t pwrkey_press_irq(int irq, void *_pwrkey) +static irqreturn_t pwrkey_press_irq(int irq, void *_pwr)  { -	struct pmic8xxx_pwrkey *pwrkey = _pwrkey; +	struct input_dev *pwr = _pwr; -	input_report_key(pwrkey->pwr, KEY_POWER, 1); -	input_sync(pwrkey->pwr); +	input_report_key(pwr, KEY_POWER, 1); +	input_sync(pwr);  	return IRQ_HANDLED;  } -static irqreturn_t pwrkey_release_irq(int irq, void *_pwrkey) +static irqreturn_t pwrkey_release_irq(int irq, void *_pwr)  { -	struct pmic8xxx_pwrkey *pwrkey = _pwrkey; +	struct input_dev *pwr = _pwr; -	input_report_key(pwrkey->pwr, KEY_POWER, 0); -	input_sync(pwrkey->pwr); +	input_report_key(pwr, KEY_POWER, 0); +	input_sync(pwr);  	return IRQ_HANDLED;  } @@ -88,127 +85,119 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)  	int key_press_irq = platform_get_irq(pdev, 1);  	int err;  	unsigned int delay; -	u8 pon_cntl; +	unsigned int pon_cntl; +	struct regmap *regmap;  	struct pmic8xxx_pwrkey *pwrkey; -	const struct pm8xxx_pwrkey_platform_data *pdata = -					dev_get_platdata(&pdev->dev); +	u32 kpd_delay; +	bool pull_up; -	if (!pdata) { -		dev_err(&pdev->dev, "power key platform data not supplied\n"); -		return -EINVAL; -	} +	if (of_property_read_u32(pdev->dev.of_node, "debounce", &kpd_delay)) +		kpd_delay = 15625; -	if (pdata->kpd_trigger_delay_us > 62500) { +	if (kpd_delay > 62500 || kpd_delay == 0) {  		dev_err(&pdev->dev, "invalid power key trigger delay\n");  		return -EINVAL;  	} -	pwrkey = kzalloc(sizeof(*pwrkey), GFP_KERNEL); +	pull_up = of_property_read_bool(pdev->dev.of_node, "pull-up"); + +	regmap = dev_get_regmap(pdev->dev.parent, NULL); +	if (!regmap) { +		dev_err(&pdev->dev, "failed to locate regmap for the device\n"); +		return -ENODEV; +	} + +	pwrkey = devm_kzalloc(&pdev->dev, sizeof(*pwrkey), GFP_KERNEL);  	if (!pwrkey)  		return -ENOMEM; -	pwr = input_allocate_device(); +	pwrkey->key_press_irq = key_press_irq; + +	pwr = devm_input_allocate_device(&pdev->dev);  	if (!pwr) {  		dev_dbg(&pdev->dev, "Can't allocate power button\n"); -		err = -ENOMEM; -		goto free_pwrkey; +		return -ENOMEM;  	}  	input_set_capability(pwr, EV_KEY, KEY_POWER);  	pwr->name = "pmic8xxx_pwrkey";  	pwr->phys = "pmic8xxx_pwrkey/input0"; -	pwr->dev.parent = &pdev->dev; -	delay = (pdata->kpd_trigger_delay_us << 10) / USEC_PER_SEC; +	delay = (kpd_delay << 10) / USEC_PER_SEC;  	delay = 1 + ilog2(delay); -	err = pm8xxx_readb(pdev->dev.parent, PON_CNTL_1, &pon_cntl); +	err = regmap_read(regmap, PON_CNTL_1, &pon_cntl);  	if (err < 0) {  		dev_err(&pdev->dev, "failed reading PON_CNTL_1 err=%d\n", err); -		goto free_input_dev; +		return err;  	}  	pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;  	pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK); -	if (pdata->pull_up) +	if (pull_up)  		pon_cntl |= PON_CNTL_PULL_UP;  	else  		pon_cntl &= ~PON_CNTL_PULL_UP; -	err = pm8xxx_writeb(pdev->dev.parent, PON_CNTL_1, pon_cntl); +	err = regmap_write(regmap, PON_CNTL_1, pon_cntl);  	if (err < 0) {  		dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err); -		goto free_input_dev; +		return err;  	} -	err = input_register_device(pwr); +	err = devm_request_irq(&pdev->dev, key_press_irq, pwrkey_press_irq, +			       IRQF_TRIGGER_RISING, +			       "pmic8xxx_pwrkey_press", pwr);  	if (err) { -		dev_dbg(&pdev->dev, "Can't register power key: %d\n", err); -		goto free_input_dev; +		dev_err(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n", +			key_press_irq, err); +		return err;  	} -	pwrkey->key_press_irq = key_press_irq; -	pwrkey->pwr = pwr; - -	platform_set_drvdata(pdev, pwrkey); - -	err = request_irq(key_press_irq, pwrkey_press_irq, -		IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_press", pwrkey); -	if (err < 0) { -		dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n", -				 key_press_irq, err); -		goto unreg_input_dev; +	err = devm_request_irq(&pdev->dev, key_release_irq, pwrkey_release_irq, +			       IRQF_TRIGGER_RISING, +			       "pmic8xxx_pwrkey_release", pwr); +	if (err) { +		dev_err(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n", +			key_release_irq, err); +		return err;  	} -	err = request_irq(key_release_irq, pwrkey_release_irq, -		 IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_release", pwrkey); -	if (err < 0) { -		dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n", -				 key_release_irq, err); - -		goto free_press_irq; +	err = input_register_device(pwr); +	if (err) { +		dev_err(&pdev->dev, "Can't register power key: %d\n", err); +		return err;  	} -	device_init_wakeup(&pdev->dev, pdata->wakeup); +	platform_set_drvdata(pdev, pwrkey); +	device_init_wakeup(&pdev->dev, 1);  	return 0; - -free_press_irq: -	free_irq(key_press_irq, pwrkey); -unreg_input_dev: -	input_unregister_device(pwr); -	pwr = NULL; -free_input_dev: -	input_free_device(pwr); -free_pwrkey: -	kfree(pwrkey); -	return err;  }  static int pmic8xxx_pwrkey_remove(struct platform_device *pdev)  { -	struct pmic8xxx_pwrkey *pwrkey = platform_get_drvdata(pdev); -	int key_release_irq = platform_get_irq(pdev, 0); -	int key_press_irq = platform_get_irq(pdev, 1); -  	device_init_wakeup(&pdev->dev, 0); -	free_irq(key_press_irq, pwrkey); -	free_irq(key_release_irq, pwrkey); -	input_unregister_device(pwrkey->pwr); -	kfree(pwrkey); -  	return 0;  } +static const struct of_device_id pm8xxx_pwr_key_id_table[] = { +	{ .compatible = "qcom,pm8058-pwrkey" }, +	{ .compatible = "qcom,pm8921-pwrkey" }, +	{ } +}; +MODULE_DEVICE_TABLE(of, pm8xxx_pwr_key_id_table); +  static struct platform_driver pmic8xxx_pwrkey_driver = {  	.probe		= pmic8xxx_pwrkey_probe,  	.remove		= pmic8xxx_pwrkey_remove,  	.driver		= { -		.name	= PM8XXX_PWRKEY_DEV_NAME, +		.name	= "pm8xxx-pwrkey",  		.owner	= THIS_MODULE,  		.pm	= &pm8xxx_pwr_key_pm_ops, +		.of_match_table = pm8xxx_pwr_key_id_table,  	},  };  module_platform_driver(pmic8xxx_pwrkey_driver); diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c index 49c0c3ebd32..63b539d3dab 100644 --- a/drivers/input/misc/powermate.c +++ b/drivers/input/misc/powermate.c @@ -31,7 +31,6 @@  #include <linux/kernel.h>  #include <linux/slab.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/spinlock.h>  #include <linux/usb/input.h> diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c index 2ff4d1c78ab..8ef288e7c97 100644 --- a/drivers/input/misc/pwm-beeper.c +++ b/drivers/input/misc/pwm-beeper.c @@ -16,6 +16,7 @@  #include <linux/input.h>  #include <linux/module.h>  #include <linux/kernel.h> +#include <linux/of.h>  #include <linux/platform_device.h>  #include <linux/pwm.h>  #include <linux/slab.h> @@ -67,7 +68,7 @@ static int pwm_beeper_event(struct input_dev *input,  static int pwm_beeper_probe(struct platform_device *pdev)  { -	unsigned long pwm_id = (unsigned long)pdev->dev.platform_data; +	unsigned long pwm_id = (unsigned long)dev_get_platdata(&pdev->dev);  	struct pwm_beeper *beeper;  	int error; diff --git a/drivers/input/misc/rb532_button.c b/drivers/input/misc/rb532_button.c index fb4f8ac3343..83fff38b86b 100644 --- a/drivers/input/misc/rb532_button.c +++ b/drivers/input/misc/rb532_button.c @@ -87,7 +87,6 @@ static int rb532_button_remove(struct platform_device *pdev)  	input_unregister_polled_device(poll_dev);  	input_free_polled_device(poll_dev); -	dev_set_drvdata(&pdev->dev, NULL);  	return 0;  } diff --git a/drivers/input/misc/retu-pwrbutton.c b/drivers/input/misc/retu-pwrbutton.c index 7ca09baa001..4bff1aa9b0d 100644 --- a/drivers/input/misc/retu-pwrbutton.c +++ b/drivers/input/misc/retu-pwrbutton.c @@ -17,7 +17,6 @@   */  #include <linux/irq.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/errno.h>  #include <linux/input.h> diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index 5b1aff82513..93558a1c7f7 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -16,7 +16,6 @@  #include <linux/kernel.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/input.h>  #include <linux/device.h> @@ -24,6 +23,7 @@  #include <linux/gpio.h>  #include <linux/rotary_encoder.h>  #include <linux/slab.h> +#include <linux/of.h>  #include <linux/of_platform.h>  #include <linux/of_gpio.h> @@ -143,7 +143,7 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)  }  #ifdef CONFIG_OF -static struct of_device_id rotary_encoder_of_match[] = { +static const struct of_device_id rotary_encoder_of_match[] = {  	{ .compatible = "rotary-encoder", },  	{ },  }; diff --git a/drivers/input/misc/sgi_btns.c b/drivers/input/misc/sgi_btns.c index 95cf299ef9a..f10474937a6 100644 --- a/drivers/input/misc/sgi_btns.c +++ b/drivers/input/misc/sgi_btns.c @@ -17,7 +17,6 @@   *  along with this program; if not, write to the Free Software   *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA   */ -#include <linux/init.h>  #include <linux/input-polldev.h>  #include <linux/ioport.h>  #include <linux/module.h> diff --git a/drivers/input/misc/sirfsoc-onkey.c b/drivers/input/misc/sirfsoc-onkey.c index 0621c367049..fed5102e180 100644 --- a/drivers/input/misc/sirfsoc-onkey.c +++ b/drivers/input/misc/sirfsoc-onkey.c @@ -1,29 +1,54 @@  /*   * Power key driver for SiRF PrimaII   * - * Copyright (c) 2013 Cambridge Silicon Radio Limited, a CSR plc group company. + * Copyright (c) 2013 - 2014 Cambridge Silicon Radio Limited, a CSR plc group + * company.   *   * Licensed under GPLv2 or later.   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/delay.h>  #include <linux/platform_device.h>  #include <linux/input.h>  #include <linux/rtc/sirfsoc_rtciobrg.h>  #include <linux/of.h> +#include <linux/workqueue.h>  struct sirfsoc_pwrc_drvdata {  	u32			pwrc_base;  	struct input_dev	*input; +	struct delayed_work	work;  };  #define PWRC_ON_KEY_BIT			(1 << 0)  #define PWRC_INT_STATUS			0xc  #define PWRC_INT_MASK			0x10 +#define PWRC_PIN_STATUS			0x14 +#define PWRC_KEY_DETECT_UP_TIME		20	/* ms*/ + +static int sirfsoc_pwrc_is_on_key_down(struct sirfsoc_pwrc_drvdata *pwrcdrv) +{ +	u32 state = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base + +							PWRC_PIN_STATUS); +	return !(state & PWRC_ON_KEY_BIT); /* ON_KEY is active low */ +} + +static void sirfsoc_pwrc_report_event(struct work_struct *work) +{ +	struct sirfsoc_pwrc_drvdata *pwrcdrv = +		container_of(work, struct sirfsoc_pwrc_drvdata, work.work); + +	if (sirfsoc_pwrc_is_on_key_down(pwrcdrv)) { +		schedule_delayed_work(&pwrcdrv->work, +			msecs_to_jiffies(PWRC_KEY_DETECT_UP_TIME)); +	} else { +		input_event(pwrcdrv->input, EV_KEY, KEY_POWER, 0); +		input_sync(pwrcdrv->input); +	} +}  static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id)  { @@ -35,21 +60,44 @@ static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id)  	sirfsoc_rtc_iobrg_writel(int_status & ~PWRC_ON_KEY_BIT,  				 pwrcdrv->pwrc_base + PWRC_INT_STATUS); -	/* -	 * For a typical Linux system, we report KEY_SUSPEND to trigger apm-power.c -	 * to queue a SUSPEND APM event -	 */ -	input_event(pwrcdrv->input, EV_PWR, KEY_SUSPEND, 1); +	input_event(pwrcdrv->input, EV_KEY, KEY_POWER, 1);  	input_sync(pwrcdrv->input); - -	/* -	 * Todo: report KEY_POWER event for Android platforms, Android PowerManager -	 * will handle the suspend and powerdown/hibernation -	 */ +	schedule_delayed_work(&pwrcdrv->work, +			      msecs_to_jiffies(PWRC_KEY_DETECT_UP_TIME));  	return IRQ_HANDLED;  } +static void sirfsoc_pwrc_toggle_interrupts(struct sirfsoc_pwrc_drvdata *pwrcdrv, +					   bool enable) +{ +	u32 int_mask; + +	int_mask = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base + PWRC_INT_MASK); +	if (enable) +		int_mask |= PWRC_ON_KEY_BIT; +	else +		int_mask &= ~PWRC_ON_KEY_BIT; +	sirfsoc_rtc_iobrg_writel(int_mask, pwrcdrv->pwrc_base + PWRC_INT_MASK); +} + +static int sirfsoc_pwrc_open(struct input_dev *input) +{ +	struct sirfsoc_pwrc_drvdata *pwrcdrv = input_get_drvdata(input); + +	sirfsoc_pwrc_toggle_interrupts(pwrcdrv, true); + +	return 0; +} + +static void sirfsoc_pwrc_close(struct input_dev *input) +{ +	struct sirfsoc_pwrc_drvdata *pwrcdrv = input_get_drvdata(input); + +	sirfsoc_pwrc_toggle_interrupts(pwrcdrv, false); +	cancel_delayed_work_sync(&pwrcdrv->work); +} +  static const struct of_device_id sirfsoc_pwrc_of_match[] = {  	{ .compatible = "sirf,prima2-pwrc" },  	{}, @@ -71,7 +119,7 @@ static int sirfsoc_pwrc_probe(struct platform_device *pdev)  	}  	/* -	 * we can't use of_iomap because pwrc is not mapped in memory, +	 * We can't use of_iomap because pwrc is not mapped in memory,  	 * the so-called base address is only offset in rtciobrg  	 */  	error = of_property_read_u32(np, "reg", &pwrcdrv->pwrc_base); @@ -87,11 +135,22 @@ static int sirfsoc_pwrc_probe(struct platform_device *pdev)  	pwrcdrv->input->name = "sirfsoc pwrckey";  	pwrcdrv->input->phys = "pwrc/input0"; -	pwrcdrv->input->evbit[0] = BIT_MASK(EV_PWR); +	pwrcdrv->input->evbit[0] = BIT_MASK(EV_KEY); +	input_set_capability(pwrcdrv->input, EV_KEY, KEY_POWER); + +	INIT_DELAYED_WORK(&pwrcdrv->work, sirfsoc_pwrc_report_event); + +	pwrcdrv->input->open = sirfsoc_pwrc_open; +	pwrcdrv->input->close = sirfsoc_pwrc_close; + +	input_set_drvdata(pwrcdrv->input, pwrcdrv); + +	/* Make sure the device is quiesced */ +	sirfsoc_pwrc_toggle_interrupts(pwrcdrv, false);  	irq = platform_get_irq(pdev, 0);  	error = devm_request_irq(&pdev->dev, irq, -				 sirfsoc_pwrc_isr, IRQF_SHARED, +				 sirfsoc_pwrc_isr, 0,  				 "sirfsoc_pwrc_int", pwrcdrv);  	if (error) {  		dev_err(&pdev->dev, "unable to claim irq %d, error: %d\n", @@ -99,11 +158,6 @@ static int sirfsoc_pwrc_probe(struct platform_device *pdev)  		return error;  	} -	sirfsoc_rtc_iobrg_writel( -		sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base + PWRC_INT_MASK) | -			PWRC_ON_KEY_BIT, -		pwrcdrv->pwrc_base + PWRC_INT_MASK); -  	error = input_register_device(pwrcdrv->input);  	if (error) {  		dev_err(&pdev->dev, @@ -112,7 +166,7 @@ static int sirfsoc_pwrc_probe(struct platform_device *pdev)  		return error;  	} -	platform_set_drvdata(pdev, pwrcdrv); +	dev_set_drvdata(&pdev->dev, pwrcdrv);  	device_init_wakeup(&pdev->dev, 1);  	return 0; @@ -126,25 +180,25 @@ static int sirfsoc_pwrc_remove(struct platform_device *pdev)  }  #ifdef CONFIG_PM_SLEEP -static int pwrc_resume(struct device *dev) +static int sirfsoc_pwrc_resume(struct device *dev)  { -	struct platform_device *pdev = to_platform_device(dev); -	struct sirfsoc_pwrc_drvdata *pwrcdrv = platform_get_drvdata(pdev); +	struct sirfsoc_pwrc_drvdata *pwrcdrv = dev_get_drvdata(dev); +	struct input_dev *input = pwrcdrv->input;  	/*  	 * Do not mask pwrc interrupt as we want pwrc work as a wakeup source  	 * if users touch X_ONKEY_B, see arch/arm/mach-prima2/pm.c  	 */ -	sirfsoc_rtc_iobrg_writel( -		sirfsoc_rtc_iobrg_readl( -		pwrcdrv->pwrc_base + PWRC_INT_MASK) | PWRC_ON_KEY_BIT, -		pwrcdrv->pwrc_base + PWRC_INT_MASK); +	mutex_lock(&input->mutex); +	if (input->users) +		sirfsoc_pwrc_toggle_interrupts(pwrcdrv, true); +	mutex_unlock(&input->mutex);  	return 0;  }  #endif -static SIMPLE_DEV_PM_OPS(sirfsoc_pwrc_pm_ops, NULL, pwrc_resume); +static SIMPLE_DEV_PM_OPS(sirfsoc_pwrc_pm_ops, NULL, sirfsoc_pwrc_resume);  static struct platform_driver sirfsoc_pwrc_driver = {  	.probe		= sirfsoc_pwrc_probe, @@ -153,13 +207,13 @@ static struct platform_driver sirfsoc_pwrc_driver = {  		.name	= "sirfsoc-pwrc",  		.owner	= THIS_MODULE,  		.pm	= &sirfsoc_pwrc_pm_ops, -		.of_match_table = of_match_ptr(sirfsoc_pwrc_of_match), +		.of_match_table = sirfsoc_pwrc_of_match,  	}  };  module_platform_driver(sirfsoc_pwrc_driver); -MODULE_LICENSE("GPLv2"); +MODULE_LICENSE("GPL v2");  MODULE_AUTHOR("Binghua Duan <Binghua.Duan@csr.com>, Xianglong Du <Xianglong.Du@csr.com>");  MODULE_DESCRIPTION("CSR Prima2 PWRC Driver");  MODULE_ALIAS("platform:sirfsoc-pwrc"); diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c new file mode 100644 index 00000000000..5a6334be30b --- /dev/null +++ b/drivers/input/misc/soc_button_array.c @@ -0,0 +1,218 @@ +/* + * Supports for the button array on SoC tablets originally running + * Windows 8. + * + * (C) Copyright 2014 Intel Corporation + * + * 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 the Free Software Foundation; version 2 + * of the License. + */ + +#include <linux/module.h> +#include <linux/input.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/acpi.h> +#include <linux/gpio/consumer.h> +#include <linux/gpio_keys.h> +#include <linux/platform_device.h> +#include <linux/pnp.h> + +/* + * Definition of buttons on the tablet. The ACPI index of each button + * is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC + * Platforms" + */ +#define MAX_NBUTTONS	5 + +struct soc_button_info { +	const char *name; +	int acpi_index; +	unsigned int event_type; +	unsigned int event_code; +	bool autorepeat; +	bool wakeup; +}; + +/* + * Some of the buttons like volume up/down are auto repeat, while others + * are not. To support both, we register two platform devices, and put + * buttons into them based on whether the key should be auto repeat. + */ +#define BUTTON_TYPES	2 + +struct soc_button_data { +	struct platform_device *children[BUTTON_TYPES]; +}; + +/* + * Get the Nth GPIO number from the ACPI object. + */ +static int soc_button_lookup_gpio(struct device *dev, int acpi_index) +{ +	struct gpio_desc *desc; +	int gpio; + +	desc = gpiod_get_index(dev, KBUILD_MODNAME, acpi_index); +	if (IS_ERR(desc)) +		return PTR_ERR(desc); + +	gpio = desc_to_gpio(desc); + +	gpiod_put(desc); + +	return gpio; +} + +static struct platform_device * +soc_button_device_create(struct pnp_dev *pdev, +			 const struct soc_button_info *button_info, +			 bool autorepeat) +{ +	const struct soc_button_info *info; +	struct platform_device *pd; +	struct gpio_keys_button *gpio_keys; +	struct gpio_keys_platform_data *gpio_keys_pdata; +	int n_buttons = 0; +	int gpio; +	int error; + +	gpio_keys_pdata = devm_kzalloc(&pdev->dev, +				       sizeof(*gpio_keys_pdata) + +					sizeof(*gpio_keys) * MAX_NBUTTONS, +				       GFP_KERNEL); +	gpio_keys = (void *)(gpio_keys_pdata + 1); + +	for (info = button_info; info->name; info++) { +		if (info->autorepeat != autorepeat) +			continue; + +		gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index); +		if (gpio < 0) +			continue; + +		gpio_keys[n_buttons].type = info->event_type; +		gpio_keys[n_buttons].code = info->event_code; +		gpio_keys[n_buttons].gpio = gpio; +		gpio_keys[n_buttons].active_low = 1; +		gpio_keys[n_buttons].desc = info->name; +		gpio_keys[n_buttons].wakeup = info->wakeup; +		n_buttons++; +	} + +	if (n_buttons == 0) { +		error = -ENODEV; +		goto err_free_mem; +	} + +	gpio_keys_pdata->buttons = gpio_keys; +	gpio_keys_pdata->nbuttons = n_buttons; +	gpio_keys_pdata->rep = autorepeat; + +	pd = platform_device_alloc("gpio-keys", PLATFORM_DEVID_AUTO); +	if (!pd) { +		error = -ENOMEM; +		goto err_free_mem; +	} + +	error = platform_device_add_data(pd, gpio_keys_pdata, +					 sizeof(*gpio_keys_pdata)); +	if (error) +		goto err_free_pdev; + +	error = platform_device_add(pd); +	if (error) +		goto err_free_pdev; + +	return pd; + +err_free_pdev: +	platform_device_put(pd); +err_free_mem: +	devm_kfree(&pdev->dev, gpio_keys_pdata); +	return ERR_PTR(error); +} + +static void soc_button_remove(struct pnp_dev *pdev) +{ +	struct soc_button_data *priv = pnp_get_drvdata(pdev); +	int i; + +	for (i = 0; i < BUTTON_TYPES; i++) +		if (priv->children[i]) +			platform_device_unregister(priv->children[i]); +} + +static int soc_button_pnp_probe(struct pnp_dev *pdev, +				const struct pnp_device_id *id) +{ +	const struct soc_button_info *button_info = (void *)id->driver_data; +	struct soc_button_data *priv; +	struct platform_device *pd; +	int i; +	int error; + +	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); +	if (!priv) +		return -ENOMEM; + +	pnp_set_drvdata(pdev, priv); + +	for (i = 0; i < BUTTON_TYPES; i++) { +		pd = soc_button_device_create(pdev, button_info, i == 0); +		if (IS_ERR(pd)) { +			error = PTR_ERR(pd); +			if (error != -ENODEV) { +				soc_button_remove(pdev); +				return error; +			} +			continue; +		} + +		priv->children[i] = pd; +	} + +	if (!priv->children[0] && !priv->children[1]) +		return -ENODEV; + +	return 0; +} + +static struct soc_button_info soc_button_PNP0C40[] = { +	{ "power", 0, EV_KEY, KEY_POWER, false, true }, +	{ "home", 1, EV_KEY, KEY_HOME, false, true }, +	{ "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false }, +	{ "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false }, +	{ "rotation_lock", 4, EV_SW, SW_ROTATE_LOCK, false, false }, +	{ } +}; + +static const struct pnp_device_id soc_button_pnp_match[] = { +	{ .id = "PNP0C40", .driver_data = (long)soc_button_PNP0C40 }, +	{ .id = "" } +}; +MODULE_DEVICE_TABLE(pnp, soc_button_pnp_match); + +static struct pnp_driver soc_button_pnp_driver = { +	.name		= KBUILD_MODNAME, +	.id_table	= soc_button_pnp_match, +	.probe          = soc_button_pnp_probe, +	.remove		= soc_button_remove, +}; + +static int __init soc_button_init(void) +{ +	return pnp_register_driver(&soc_button_pnp_driver); +} + +static void __exit soc_button_exit(void) +{ +	pnp_unregister_driver(&soc_button_pnp_driver); +} + +module_init(soc_button_init); +module_exit(soc_button_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c index b9a05fda03e..fb3b63b2f85 100644 --- a/drivers/input/misc/twl4030-pwrbutton.c +++ b/drivers/input/misc/twl4030-pwrbutton.c @@ -52,15 +52,15 @@ static irqreturn_t powerbutton_irq(int irq, void *_pwr)  	return IRQ_HANDLED;  } -static int __init twl4030_pwrbutton_probe(struct platform_device *pdev) +static int twl4030_pwrbutton_probe(struct platform_device *pdev)  {  	struct input_dev *pwr;  	int irq = platform_get_irq(pdev, 0);  	int err; -	pwr = input_allocate_device(); +	pwr = devm_input_allocate_device(&pdev->dev);  	if (!pwr) { -		dev_dbg(&pdev->dev, "Can't allocate power button\n"); +		dev_err(&pdev->dev, "Can't allocate power button\n");  		return -ENOMEM;  	} @@ -70,52 +70,42 @@ static int __init twl4030_pwrbutton_probe(struct platform_device *pdev)  	pwr->phys = "twl4030_pwrbutton/input0";  	pwr->dev.parent = &pdev->dev; -	err = request_threaded_irq(irq, NULL, powerbutton_irq, +	err = devm_request_threaded_irq(&pwr->dev, irq, NULL, powerbutton_irq,  			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,  			"twl4030_pwrbutton", pwr);  	if (err < 0) { -		dev_dbg(&pdev->dev, "Can't get IRQ for pwrbutton: %d\n", err); -		goto free_input_dev; +		dev_err(&pdev->dev, "Can't get IRQ for pwrbutton: %d\n", err); +		return err;  	}  	err = input_register_device(pwr);  	if (err) { -		dev_dbg(&pdev->dev, "Can't register power button: %d\n", err); -		goto free_irq; +		dev_err(&pdev->dev, "Can't register power button: %d\n", err); +		return err;  	}  	platform_set_drvdata(pdev, pwr);  	return 0; - -free_irq: -	free_irq(irq, pwr); -free_input_dev: -	input_free_device(pwr); -	return err;  } -static int __exit twl4030_pwrbutton_remove(struct platform_device *pdev) -{ -	struct input_dev *pwr = platform_get_drvdata(pdev); -	int irq = platform_get_irq(pdev, 0); - -	free_irq(irq, pwr); -	input_unregister_device(pwr); - -	return 0; -} +#ifdef CONFIG_OF +static const struct of_device_id twl4030_pwrbutton_dt_match_table[] = { +       { .compatible = "ti,twl4030-pwrbutton" }, +       {}, +}; +MODULE_DEVICE_TABLE(of, twl4030_pwrbutton_dt_match_table); +#endif  static struct platform_driver twl4030_pwrbutton_driver = { -	.remove		= __exit_p(twl4030_pwrbutton_remove), +	.probe		= twl4030_pwrbutton_probe,  	.driver		= {  		.name	= "twl4030_pwrbutton",  		.owner	= THIS_MODULE, +		.of_match_table = of_match_ptr(twl4030_pwrbutton_dt_match_table),  	},  }; - -module_platform_driver_probe(twl4030_pwrbutton_driver, -			twl4030_pwrbutton_probe); +module_platform_driver(twl4030_pwrbutton_driver);  MODULE_ALIAS("platform:twl4030_pwrbutton");  MODULE_DESCRIPTION("Triton2 Power Button"); diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c index 68a5f33152a..960ef2a7091 100644 --- a/drivers/input/misc/twl4030-vibra.c +++ b/drivers/input/misc/twl4030-vibra.c @@ -185,15 +185,17 @@ static bool twl4030_vibra_check_coexist(struct twl4030_vibra_data *pdata,  	if (pdata && pdata->coexist)  		return true; -	if (of_find_node_by_name(node, "codec")) +	if (of_find_node_by_name(node, "codec")) { +		of_node_put(node);  		return true; +	}  	return false;  }  static int twl4030_vibra_probe(struct platform_device *pdev)  { -	struct twl4030_vibra_data *pdata = pdev->dev.platform_data; +	struct twl4030_vibra_data *pdata = dev_get_platdata(&pdev->dev);  	struct device_node *twl4030_core_node = pdev->dev.parent->of_node;  	struct vibra_info *info;  	int ret; diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c index 7864b0c3ebb..6d26eecc278 100644 --- a/drivers/input/misc/twl6040-vibra.c +++ b/drivers/input/misc/twl6040-vibra.c @@ -258,17 +258,14 @@ static SIMPLE_DEV_PM_OPS(twl6040_vibra_pm_ops, twl6040_vibra_suspend, NULL);  static int twl6040_vibra_probe(struct platform_device *pdev)  {  	struct device *twl6040_core_dev = pdev->dev.parent; -	struct device_node *twl6040_core_node = NULL; +	struct device_node *twl6040_core_node;  	struct vibra_info *info;  	int vddvibl_uV = 0;  	int vddvibr_uV = 0; -	int ret; +	int error; -#ifdef CONFIG_OF  	twl6040_core_node = of_find_node_by_name(twl6040_core_dev->of_node,  						 "vibra"); -#endif -  	if (!twl6040_core_node) {  		dev_err(&pdev->dev, "parent of node is missing?\n");  		return -EINVAL; @@ -276,6 +273,7 @@ static int twl6040_vibra_probe(struct platform_device *pdev)  	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);  	if (!info) { +		of_node_put(twl6040_core_node);  		dev_err(&pdev->dev, "couldn't allocate memory\n");  		return -ENOMEM;  	} @@ -295,6 +293,8 @@ static int twl6040_vibra_probe(struct platform_device *pdev)  	of_property_read_u32(twl6040_core_node, "ti,vddvibl-uV", &vddvibl_uV);  	of_property_read_u32(twl6040_core_node, "ti,vddvibr-uV", &vddvibr_uV); +	of_node_put(twl6040_core_node); +  	if ((!info->vibldrv_res && !info->viblmotor_res) ||  	    (!info->vibrdrv_res && !info->vibrmotor_res)) {  		dev_err(info->dev, "invalid vibra driver/motor resistance\n"); @@ -309,12 +309,12 @@ static int twl6040_vibra_probe(struct platform_device *pdev)  	mutex_init(&info->mutex); -	ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL, -					twl6040_vib_irq_handler, 0, -					"twl6040_irq_vib", info); -	if (ret) { -		dev_err(info->dev, "VIB IRQ request failed: %d\n", ret); -		return ret; +	error = devm_request_threaded_irq(&pdev->dev, info->irq, NULL, +					  twl6040_vib_irq_handler, 0, +					  "twl6040_irq_vib", info); +	if (error) { +		dev_err(info->dev, "VIB IRQ request failed: %d\n", error); +		return error;  	}  	info->supplies[0].supply = "vddvibl"; @@ -323,40 +323,40 @@ static int twl6040_vibra_probe(struct platform_device *pdev)  	 * When booted with Device tree the regulators are attached to the  	 * parent device (twl6040 MFD core)  	 */ -	ret = regulator_bulk_get(twl6040_core_dev, ARRAY_SIZE(info->supplies), -				 info->supplies); -	if (ret) { -		dev_err(info->dev, "couldn't get regulators %d\n", ret); -		return ret; +	error = devm_regulator_bulk_get(twl6040_core_dev, +					ARRAY_SIZE(info->supplies), +					info->supplies); +	if (error) { +		dev_err(info->dev, "couldn't get regulators %d\n", error); +		return error;  	}  	if (vddvibl_uV) { -		ret = regulator_set_voltage(info->supplies[0].consumer, -					    vddvibl_uV, vddvibl_uV); -		if (ret) { +		error = regulator_set_voltage(info->supplies[0].consumer, +					      vddvibl_uV, vddvibl_uV); +		if (error) {  			dev_err(info->dev, "failed to set VDDVIBL volt %d\n", -				ret); -			goto err_regulator; +				error); +			return error;  		}  	}  	if (vddvibr_uV) { -		ret = regulator_set_voltage(info->supplies[1].consumer, -					    vddvibr_uV, vddvibr_uV); -		if (ret) { +		error = regulator_set_voltage(info->supplies[1].consumer, +					      vddvibr_uV, vddvibr_uV); +		if (error) {  			dev_err(info->dev, "failed to set VDDVIBR volt %d\n", -				ret); -			goto err_regulator; +				error); +			return error;  		}  	}  	INIT_WORK(&info->play_work, vibra_play_work); -	info->input_dev = input_allocate_device(); -	if (info->input_dev == NULL) { +	info->input_dev = devm_input_allocate_device(&pdev->dev); +	if (!info->input_dev) {  		dev_err(info->dev, "couldn't allocate input device\n"); -		ret = -ENOMEM; -		goto err_regulator; +		return -ENOMEM;  	}  	input_set_drvdata(info->input_dev, info); @@ -367,44 +367,25 @@ static int twl6040_vibra_probe(struct platform_device *pdev)  	info->input_dev->close = twl6040_vibra_close;  	__set_bit(FF_RUMBLE, info->input_dev->ffbit); -	ret = input_ff_create_memless(info->input_dev, NULL, vibra_play); -	if (ret < 0) { +	error = input_ff_create_memless(info->input_dev, NULL, vibra_play); +	if (error) {  		dev_err(info->dev, "couldn't register vibrator to FF\n"); -		goto err_ialloc; +		return error;  	} -	ret = input_register_device(info->input_dev); -	if (ret < 0) { +	error = input_register_device(info->input_dev); +	if (error) {  		dev_err(info->dev, "couldn't register input device\n"); -		goto err_iff; +		return error;  	}  	platform_set_drvdata(pdev, info);  	return 0; - -err_iff: -	input_ff_destroy(info->input_dev); -err_ialloc: -	input_free_device(info->input_dev); -err_regulator: -	regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies); -	return ret; -} - -static int twl6040_vibra_remove(struct platform_device *pdev) -{ -	struct vibra_info *info = platform_get_drvdata(pdev); - -	input_unregister_device(info->input_dev); -	regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies); - -	return 0;  }  static struct platform_driver twl6040_vibra_driver = {  	.probe		= twl6040_vibra_probe, -	.remove		= twl6040_vibra_remove,  	.driver		= {  		.name	= "twl6040-vibra",  		.owner	= THIS_MODULE, diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index a0a4bbaef02..85693624750 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -20,6 +20,8 @@   * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>   *   * Changes/Revisions: + *	0.4	01/09/2014 (Benjamin Tissoires <benjamin.tissoires@redhat.com>) + *		- add UI_GET_SYSNAME ioctl   *	0.3	09/04/2006 (Anssi Hannula <anssi.hannula@gmail.com>)   *		- updated ff support for the changes in kernel interface   *		- added MODULE_VERSION @@ -430,20 +432,30 @@ static int uinput_setup_device(struct uinput_device *udev,  	return retval;  } -static ssize_t uinput_inject_event(struct uinput_device *udev, -				   const char __user *buffer, size_t count) +static ssize_t uinput_inject_events(struct uinput_device *udev, +				    const char __user *buffer, size_t count)  {  	struct input_event ev; +	size_t bytes = 0; -	if (count < input_event_size()) +	if (count != 0 && count < input_event_size())  		return -EINVAL; -	if (input_event_from_user(buffer, &ev)) -		return -EFAULT; +	while (bytes + input_event_size() <= count) { +		/* +		 * Note that even if some events were fetched successfully +		 * we are still going to return EFAULT instead of partial +		 * count to let userspace know that it got it's buffers +		 * all wrong. +		 */ +		if (input_event_from_user(buffer + bytes, &ev)) +			return -EFAULT; -	input_event(udev->dev, ev.type, ev.code, ev.value); +		input_event(udev->dev, ev.type, ev.code, ev.value); +		bytes += input_event_size(); +	} -	return input_event_size(); +	return bytes;  }  static ssize_t uinput_write(struct file *file, const char __user *buffer, @@ -460,7 +472,7 @@ static ssize_t uinput_write(struct file *file, const char __user *buffer,  		return retval;  	retval = udev->state == UIST_CREATED ? -			uinput_inject_event(udev, buffer, count) : +			uinput_inject_events(udev, buffer, count) :  			uinput_setup_device(udev, buffer, count);  	mutex_unlock(&udev->mutex); @@ -660,6 +672,31 @@ static int uinput_ff_upload_from_user(const char __user *buffer,  	__ret;						\  }) +static int uinput_str_to_user(void __user *dest, const char *str, +			      unsigned int maxlen) +{ +	char __user *p = dest; +	int len, ret; + +	if (!str) +		return -ENOENT; + +	if (maxlen == 0) +		return -EINVAL; + +	len = strlen(str) + 1; +	if (len > maxlen) +		len = maxlen; + +	ret = copy_to_user(p, str, len); +	if (ret) +		return -EFAULT; + +	/* force terminating '\0' */ +	ret = put_user(0, p + len - 1); +	return ret ? -EFAULT : len; +} +  static long uinput_ioctl_handler(struct file *file, unsigned int cmd,  				 unsigned long arg, void __user *p)  { @@ -669,6 +706,8 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,  	struct uinput_ff_erase  ff_erase;  	struct uinput_request   *req;  	char			*phys; +	const char		*name; +	unsigned int		size;  	retval = mutex_lock_interruptible(&udev->mutex);  	if (retval) @@ -683,51 +722,51 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,  	switch (cmd) {  		case UI_DEV_CREATE:  			retval = uinput_create_device(udev); -			break; +			goto out;  		case UI_DEV_DESTROY:  			uinput_destroy_device(udev); -			break; +			goto out;  		case UI_SET_EVBIT:  			retval = uinput_set_bit(arg, evbit, EV_MAX); -			break; +			goto out;  		case UI_SET_KEYBIT:  			retval = uinput_set_bit(arg, keybit, KEY_MAX); -			break; +			goto out;  		case UI_SET_RELBIT:  			retval = uinput_set_bit(arg, relbit, REL_MAX); -			break; +			goto out;  		case UI_SET_ABSBIT:  			retval = uinput_set_bit(arg, absbit, ABS_MAX); -			break; +			goto out;  		case UI_SET_MSCBIT:  			retval = uinput_set_bit(arg, mscbit, MSC_MAX); -			break; +			goto out;  		case UI_SET_LEDBIT:  			retval = uinput_set_bit(arg, ledbit, LED_MAX); -			break; +			goto out;  		case UI_SET_SNDBIT:  			retval = uinput_set_bit(arg, sndbit, SND_MAX); -			break; +			goto out;  		case UI_SET_FFBIT:  			retval = uinput_set_bit(arg, ffbit, FF_MAX); -			break; +			goto out;  		case UI_SET_SWBIT:  			retval = uinput_set_bit(arg, swbit, SW_MAX); -			break; +			goto out;  		case UI_SET_PROPBIT:  			retval = uinput_set_bit(arg, propbit, INPUT_PROP_MAX); -			break; +			goto out;  		case UI_SET_PHYS:  			if (udev->state == UIST_CREATED) { @@ -743,18 +782,18 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,  			kfree(udev->dev->phys);  			udev->dev->phys = phys; -			break; +			goto out;  		case UI_BEGIN_FF_UPLOAD:  			retval = uinput_ff_upload_from_user(p, &ff_up);  			if (retval) -				break; +				goto out;  			req = uinput_request_find(udev, ff_up.request_id);  			if (!req || req->code != UI_FF_UPLOAD ||  			    !req->u.upload.effect) {  				retval = -EINVAL; -				break; +				goto out;  			}  			ff_up.retval = 0; @@ -765,65 +804,77 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,  				memset(&ff_up.old, 0, sizeof(struct ff_effect));  			retval = uinput_ff_upload_to_user(p, &ff_up); -			break; +			goto out;  		case UI_BEGIN_FF_ERASE:  			if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {  				retval = -EFAULT; -				break; +				goto out;  			}  			req = uinput_request_find(udev, ff_erase.request_id);  			if (!req || req->code != UI_FF_ERASE) {  				retval = -EINVAL; -				break; +				goto out;  			}  			ff_erase.retval = 0;  			ff_erase.effect_id = req->u.effect_id;  			if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) {  				retval = -EFAULT; -				break; +				goto out;  			} -			break; +			goto out;  		case UI_END_FF_UPLOAD:  			retval = uinput_ff_upload_from_user(p, &ff_up);  			if (retval) -				break; +				goto out;  			req = uinput_request_find(udev, ff_up.request_id);  			if (!req || req->code != UI_FF_UPLOAD ||  			    !req->u.upload.effect) {  				retval = -EINVAL; -				break; +				goto out;  			}  			req->retval = ff_up.retval;  			uinput_request_done(udev, req); -			break; +			goto out;  		case UI_END_FF_ERASE:  			if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {  				retval = -EFAULT; -				break; +				goto out;  			}  			req = uinput_request_find(udev, ff_erase.request_id);  			if (!req || req->code != UI_FF_ERASE) {  				retval = -EINVAL; -				break; +				goto out;  			}  			req->retval = ff_erase.retval;  			uinput_request_done(udev, req); -			break; +			goto out; +	} -		default: -			retval = -EINVAL; +	size = _IOC_SIZE(cmd); + +	/* Now check variable-length commands */ +	switch (cmd & ~IOCSIZE_MASK) { +	case UI_GET_SYSNAME(0): +		if (udev->state != UIST_CREATED) { +			retval = -ENOENT; +			goto out; +		} +		name = dev_name(&udev->dev->dev); +		retval = uinput_str_to_user(p, name, size); +		goto out;  	} +	retval = -EINVAL;   out:  	mutex_unlock(&udev->mutex);  	return retval; diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index b6505454bcc..7b7add5061a 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -277,6 +277,16 @@ static struct key_entry keymap_fs_amilo_pro_v3505[] __initdata = {  	{ KE_END,       0 }  }; +static struct key_entry keymap_fs_amilo_pro_v8210[] __initdata = { +	{ KE_KEY,       0x01, {KEY_HELP} },          /* Fn+F1 */ +	{ KE_KEY,       0x06, {KEY_DISPLAYTOGGLE} }, /* Fn+F4 */ +	{ KE_BLUETOOTH, 0x30 },                      /* Fn+F10 */ +	{ KE_KEY,       0x31, {KEY_MAIL} },          /* mail button */ +	{ KE_KEY,       0x36, {KEY_WWW} },           /* www button */ +	{ KE_WIFI,      0x78 },                      /* satelite dish button */ +	{ KE_END,       FE_WIFI_LED } +}; +  static struct key_entry keymap_fujitsu_n3510[] __initdata = {  	{ KE_KEY, 0x11, {KEY_PROG1} },  	{ KE_KEY, 0x12, {KEY_PROG2} }, @@ -654,6 +664,15 @@ static const struct dmi_system_id dmi_ids[] __initconst = {  		.driver_data = keymap_fs_amilo_pro_v3505  	},  	{ +		/* Fujitsu-Siemens Amilo Pro Edition V8210 */ +		.callback = dmi_matched, +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), +			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro Series V8210"), +		}, +		.driver_data = keymap_fs_amilo_pro_v8210 +	}, +	{  		/* Fujitsu-Siemens Amilo M7400 */  		.callback = dmi_matched,  		.matches = { diff --git a/drivers/input/misc/wm831x-on.c b/drivers/input/misc/wm831x-on.c index caa2c4068f0..173b6dcca0d 100644 --- a/drivers/input/misc/wm831x-on.c +++ b/drivers/input/misc/wm831x-on.c @@ -18,7 +18,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/kernel.h>  #include <linux/errno.h> diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c index e21c1816a8f..fbfdc10573b 100644 --- a/drivers/input/misc/xen-kbdfront.c +++ b/drivers/input/misc/xen-kbdfront.c @@ -29,6 +29,7 @@  #include <xen/interface/io/fbif.h>  #include <xen/interface/io/kbdif.h>  #include <xen/xenbus.h> +#include <xen/platform_pci.h>  struct xenkbd_info {  	struct input_dev *kbd; @@ -380,6 +381,9 @@ static int __init xenkbd_init(void)  	if (xen_initial_domain())  		return -ENODEV; +	if (!xen_has_pv_devices()) +		return -ENODEV; +  	return xenbus_register_frontend(&xenkbd_driver);  } diff --git a/drivers/input/misc/yealink.c b/drivers/input/misc/yealink.c index 285a5bd6cbc..79c964c075f 100644 --- a/drivers/input/misc/yealink.c +++ b/drivers/input/misc/yealink.c @@ -47,7 +47,6 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/rwsem.h> diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index effa9c5f2c5..366fc7ad5eb 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -17,7 +17,7 @@ config MOUSE_PS2  	default y  	select SERIO  	select SERIO_LIBPS2 -	select SERIO_I8042 if X86 +	select SERIO_I8042 if ARCH_MIGHT_HAVE_PC_SERIO  	select SERIO_GSCPS2 if GSC  	help  	  Say Y here if you have a PS/2 mouse connected to your system. This @@ -53,7 +53,7 @@ config MOUSE_PS2_LOGIPS2PP  	default y  	depends on MOUSE_PS2  	help -	  Say Y here if you have a Logictech PS/2++ mouse connected to +	  Say Y here if you have a Logitech PS/2++ mouse connected to  	  your system.  	  If unsure, say Y. diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 7c5d72a6a26..fb15c64ffb9 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -70,6 +70,25 @@ static const struct alps_nibble_commands alps_v4_nibble_commands[] = {  	{ PSMOUSE_CMD_SETSCALE11,	0x00 }, /* f */  }; +static const struct alps_nibble_commands alps_v6_nibble_commands[] = { +	{ PSMOUSE_CMD_ENABLE,		0x00 }, /* 0 */ +	{ PSMOUSE_CMD_SETRATE,		0x0a }, /* 1 */ +	{ PSMOUSE_CMD_SETRATE,		0x14 }, /* 2 */ +	{ PSMOUSE_CMD_SETRATE,		0x28 }, /* 3 */ +	{ PSMOUSE_CMD_SETRATE,		0x3c }, /* 4 */ +	{ PSMOUSE_CMD_SETRATE,		0x50 }, /* 5 */ +	{ PSMOUSE_CMD_SETRATE,		0x64 }, /* 6 */ +	{ PSMOUSE_CMD_SETRATE,		0xc8 }, /* 7 */ +	{ PSMOUSE_CMD_GETID,		0x00 }, /* 8 */ +	{ PSMOUSE_CMD_GETINFO,		0x00 }, /* 9 */ +	{ PSMOUSE_CMD_SETRES,		0x00 }, /* a */ +	{ PSMOUSE_CMD_SETRES,		0x01 }, /* b */ +	{ PSMOUSE_CMD_SETRES,		0x02 }, /* c */ +	{ PSMOUSE_CMD_SETRES,		0x03 }, /* d */ +	{ PSMOUSE_CMD_SETSCALE21,	0x00 }, /* e */ +	{ PSMOUSE_CMD_SETSCALE11,	0x00 }, /* f */ +}; +  #define ALPS_DUALPOINT		0x02	/* touchpad has trackstick */  #define ALPS_PASS		0x04	/* device has a pass-through port */ @@ -103,6 +122,7 @@ static const struct alps_model_info alps_model_data[] = {  	/* Dell Latitude E5500, E6400, E6500, Precision M4400 */  	{ { 0x62, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf,  		ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, +	{ { 0x73, 0x00, 0x14 }, 0x00, ALPS_PROTO_V6, 0xff, 0xff, ALPS_DUALPOINT },		/* Dell XT2 */  	{ { 0x73, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS },		/* Dell Vostro 1400 */  	{ { 0x52, 0x01, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff,  		ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED },				/* Toshiba Tecra A11-11L */ @@ -257,6 +277,57 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)  }  /* + * Process bitmap data for V5 protocols. Return value is null. + * + * The bitmaps don't have enough data to track fingers, so this function + * only generates points representing a bounding box of at most two contacts. + * These two points are returned in x1, y1, x2, and y2. + */ +static void alps_process_bitmap_dolphin(struct alps_data *priv, +					struct alps_fields *fields, +					int *x1, int *y1, int *x2, int *y2) +{ +	int box_middle_x, box_middle_y; +	unsigned int x_map, y_map; +	unsigned char start_bit, end_bit; +	unsigned char x_msb, x_lsb, y_msb, y_lsb; + +	x_map = fields->x_map; +	y_map = fields->y_map; + +	if (!x_map || !y_map) +		return; + +	/* Get Most-significant and Least-significant bit */ +	x_msb = fls(x_map); +	x_lsb = ffs(x_map); +	y_msb = fls(y_map); +	y_lsb = ffs(y_map); + +	/* Most-significant bit should never exceed max sensor line number */ +	if (x_msb > priv->x_bits || y_msb > priv->y_bits) +		return; + +	*x1 = *y1 = *x2 = *y2 = 0; + +	if (fields->fingers > 1) { +		start_bit = priv->x_bits - x_msb; +		end_bit = priv->x_bits - x_lsb; +		box_middle_x = (priv->x_max * (start_bit + end_bit)) / +				(2 * (priv->x_bits - 1)); + +		start_bit = y_lsb - 1; +		end_bit = y_msb - 1; +		box_middle_y = (priv->y_max * (start_bit + end_bit)) / +				(2 * (priv->y_bits - 1)); +		*x1 = fields->x; +		*y1 = fields->y; +		*x2 = 2 * box_middle_x - *x1; +		*y2 = 2 * box_middle_y - *y1; +	} +} + +/*   * Process bitmap data from v3 and v4 protocols. Returns the number of   * fingers detected. A return value of 0 means at least one of the   * bitmaps was empty. @@ -461,7 +532,8 @@ static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)  	f->ts_middle = !!(p[3] & 0x40);  } -static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p) +static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p, +				 struct psmouse *psmouse)  {  	f->first_mp = !!(p[4] & 0x40);  	f->is_mp = !!(p[0] & 0x40); @@ -482,48 +554,61 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p)  	alps_decode_buttons_v3(f, p);  } -static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p) +static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p, +				 struct psmouse *psmouse)  { -	alps_decode_pinnacle(f, p); +	alps_decode_pinnacle(f, p, psmouse);  	f->x_map |= (p[5] & 0x10) << 11;  	f->y_map |= (p[5] & 0x20) << 6;  } -static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p) +static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p, +				struct psmouse *psmouse)  { +	u64 palm_data = 0; +	struct alps_data *priv = psmouse->private; +  	f->first_mp = !!(p[0] & 0x02);  	f->is_mp = !!(p[0] & 0x20); -	f->fingers = ((p[0] & 0x6) >> 1 | +	if (!f->is_mp) { +		f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7)); +		f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3)); +		f->z = (p[0] & 4) ? 0 : p[5] & 0x7f; +		alps_decode_buttons_v3(f, p); +	} else { +		f->fingers = ((p[0] & 0x6) >> 1 |  		     (p[0] & 0x10) >> 2); -	f->x_map = ((p[2] & 0x60) >> 5) | -		   ((p[4] & 0x7f) << 2) | -		   ((p[5] & 0x7f) << 9) | -		   ((p[3] & 0x07) << 16) | -		   ((p[3] & 0x70) << 15) | -		   ((p[0] & 0x01) << 22); -	f->y_map = (p[1] & 0x7f) | -		   ((p[2] & 0x1f) << 7); - -	f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7)); -	f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3)); -	f->z = (p[0] & 4) ? 0 : p[5] & 0x7f; -	alps_decode_buttons_v3(f, p); +		palm_data = (p[1] & 0x7f) | +			    ((p[2] & 0x7f) << 7) | +			    ((p[4] & 0x7f) << 14) | +			    ((p[5] & 0x7f) << 21) | +			    ((p[3] & 0x07) << 28) | +			    (((u64)p[3] & 0x70) << 27) | +			    (((u64)p[0] & 0x01) << 34); + +		/* Y-profile is stored in P(0) to p(n-1), n = y_bits; */ +		f->y_map = palm_data & (BIT(priv->y_bits) - 1); + +		/* X-profile is stored in p(n) to p(n+m-1), m = x_bits; */ +		f->x_map = (palm_data >> priv->y_bits) & +			   (BIT(priv->x_bits) - 1); +	}  } -static void alps_process_touchpad_packet_v3(struct psmouse *psmouse) +static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)  {  	struct alps_data *priv = psmouse->private;  	unsigned char *packet = psmouse->packet;  	struct input_dev *dev = psmouse->dev;  	struct input_dev *dev2 = priv->dev2;  	int x1 = 0, y1 = 0, x2 = 0, y2 = 0; -	int fingers = 0, bmap_fingers; -	struct alps_fields f; +	int fingers = 0, bmap_fn; +	struct alps_fields f = {0}; -	priv->decode_fields(&f, packet); +	priv->decode_fields(&f, packet, psmouse);  	/*  	 * There's no single feature of touchpad position and bitmap packets @@ -540,19 +625,38 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)  		 */  		if (f.is_mp) {  			fingers = f.fingers; -			bmap_fingers = alps_process_bitmap(priv, -							   f.x_map, f.y_map, -							   &x1, &y1, &x2, &y2); - -			/* -			 * We shouldn't report more than one finger if -			 * we don't have two coordinates. -			 */ -			if (fingers > 1 && bmap_fingers < 2) -				fingers = bmap_fingers; - -			/* Now process position packet */ -			priv->decode_fields(&f, priv->multi_data); +			if (priv->proto_version == ALPS_PROTO_V3) { +				bmap_fn = alps_process_bitmap(priv, f.x_map, +							      f.y_map, &x1, &y1, +							      &x2, &y2); + +				/* +				 * We shouldn't report more than one finger if +				 * we don't have two coordinates. +				 */ +				if (fingers > 1 && bmap_fn < 2) +					fingers = bmap_fn; + +				/* Now process position packet */ +				priv->decode_fields(&f, priv->multi_data, +						    psmouse); +			} else { +				/* +				 * Because Dolphin uses position packet's +				 * coordinate data as Pt1 and uses it to +				 * calculate Pt2, so we need to do position +				 * packet decode first. +				 */ +				priv->decode_fields(&f, priv->multi_data, +						    psmouse); + +				/* +				 * Since Dolphin's finger number is reliable, +				 * there is no need to compare with bmap_fn. +				 */ +				alps_process_bitmap_dolphin(priv, &f, &x1, &y1, +							    &x2, &y2); +			}  		} else {  			priv->multi_packet = 0;  		} @@ -642,7 +746,77 @@ static void alps_process_packet_v3(struct psmouse *psmouse)  		return;  	} -	alps_process_touchpad_packet_v3(psmouse); +	alps_process_touchpad_packet_v3_v5(psmouse); +} + +static void alps_process_packet_v6(struct psmouse *psmouse) +{ +	struct alps_data *priv = psmouse->private; +	unsigned char *packet = psmouse->packet; +	struct input_dev *dev = psmouse->dev; +	struct input_dev *dev2 = priv->dev2; +	int x, y, z, left, right, middle; + +	/* +	 * We can use Byte5 to distinguish if the packet is from Touchpad +	 * or Trackpoint. +	 * Touchpad:	0 - 0x7E +	 * Trackpoint:	0x7F +	 */ +	if (packet[5] == 0x7F) { +		/* It should be a DualPoint when received Trackpoint packet */ +		if (!(priv->flags & ALPS_DUALPOINT)) +			return; + +		/* Trackpoint packet */ +		x = packet[1] | ((packet[3] & 0x20) << 2); +		y = packet[2] | ((packet[3] & 0x40) << 1); +		z = packet[4]; +		left = packet[3] & 0x01; +		right = packet[3] & 0x02; +		middle = packet[3] & 0x04; + +		/* To prevent the cursor jump when finger lifted */ +		if (x == 0x7F && y == 0x7F && z == 0x7F) +			x = y = z = 0; + +		/* Divide 4 since trackpoint's speed is too fast */ +		input_report_rel(dev2, REL_X, (char)x / 4); +		input_report_rel(dev2, REL_Y, -((char)y / 4)); + +		input_report_key(dev2, BTN_LEFT, left); +		input_report_key(dev2, BTN_RIGHT, right); +		input_report_key(dev2, BTN_MIDDLE, middle); + +		input_sync(dev2); +		return; +	} + +	/* Touchpad packet */ +	x = packet[1] | ((packet[3] & 0x78) << 4); +	y = packet[2] | ((packet[4] & 0x78) << 4); +	z = packet[5]; +	left = packet[3] & 0x01; +	right = packet[3] & 0x02; + +	if (z > 30) +		input_report_key(dev, BTN_TOUCH, 1); +	if (z < 25) +		input_report_key(dev, BTN_TOUCH, 0); + +	if (z > 0) { +		input_report_abs(dev, ABS_X, x); +		input_report_abs(dev, ABS_Y, y); +	} + +	input_report_abs(dev, ABS_PRESSURE, z); +	input_report_key(dev, BTN_TOOL_FINGER, z > 0); + +	/* v6 touchpad does not have middle button */ +	input_report_key(dev, BTN_LEFT, left); +	input_report_key(dev, BTN_RIGHT, right); + +	input_sync(dev);  }  static void alps_process_packet_v4(struct psmouse *psmouse) @@ -897,7 +1071,7 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)  	}  	/* Bytes 2 - pktsize should have 0 in the highest bit */ -	if (priv->proto_version != ALPS_PROTO_V5 && +	if ((priv->proto_version < ALPS_PROTO_V5) &&  	    psmouse->pktcnt >= 2 && psmouse->pktcnt <= psmouse->pktsize &&  	    (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) {  		psmouse_dbg(psmouse, "refusing packet[%i] = %x\n", @@ -1085,6 +1259,80 @@ static int alps_absolute_mode_v1_v2(struct psmouse *psmouse)  	return ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETPOLL);  } +static int alps_monitor_mode_send_word(struct psmouse *psmouse, u16 word) +{ +	int i, nibble; + +	/* +	 * b0-b11 are valid bits, send sequence is inverse. +	 * e.g. when word = 0x0123, nibble send sequence is 3, 2, 1 +	 */ +	for (i = 0; i <= 8; i += 4) { +		nibble = (word >> i) & 0xf; +		if (alps_command_mode_send_nibble(psmouse, nibble)) +			return -1; +	} + +	return 0; +} + +static int alps_monitor_mode_write_reg(struct psmouse *psmouse, +				       u16 addr, u16 value) +{ +	struct ps2dev *ps2dev = &psmouse->ps2dev; + +	/* 0x0A0 is the command to write the word */ +	if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE) || +	    alps_monitor_mode_send_word(psmouse, 0x0A0) || +	    alps_monitor_mode_send_word(psmouse, addr) || +	    alps_monitor_mode_send_word(psmouse, value) || +	    ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE)) +		return -1; + +	return 0; +} + +static int alps_monitor_mode(struct psmouse *psmouse, bool enable) +{ +	struct ps2dev *ps2dev = &psmouse->ps2dev; + +	if (enable) { +		/* EC E9 F5 F5 E7 E6 E7 E9 to enter monitor mode */ +		if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) || +		    ps2_command(ps2dev, NULL, PSMOUSE_CMD_GETINFO) || +		    ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || +		    ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || +		    ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || +		    ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || +		    ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || +		    ps2_command(ps2dev, NULL, PSMOUSE_CMD_GETINFO)) +			return -1; +	} else { +		/* EC to exit monitor mode */ +		if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP)) +			return -1; +	} + +	return 0; +} + +static int alps_absolute_mode_v6(struct psmouse *psmouse) +{ +	u16 reg_val = 0x181; +	int ret = -1; + +	/* enter monitor mode, to write the register */ +	if (alps_monitor_mode(psmouse, true)) +		return -1; + +	ret = alps_monitor_mode_write_reg(psmouse, 0x000, reg_val); + +	if (alps_monitor_mode(psmouse, false)) +		ret = -1; + +	return ret; +} +  static int alps_get_status(struct psmouse *psmouse, char *param)  {  	/* Get status: 0xF5 0xF5 0xF5 0xE9 */ @@ -1189,6 +1437,32 @@ static int alps_hw_init_v1_v2(struct psmouse *psmouse)  	return 0;  } +static int alps_hw_init_v6(struct psmouse *psmouse) +{ +	unsigned char param[2] = {0xC8, 0x14}; + +	/* Enter passthrough mode to let trackpoint enter 6byte raw mode */ +	if (alps_passthrough_mode_v2(psmouse, true)) +		return -1; + +	if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || +	    ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || +	    ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || +	    ps2_command(&psmouse->ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) || +	    ps2_command(&psmouse->ps2dev, ¶m[1], PSMOUSE_CMD_SETRATE)) +		return -1; + +	if (alps_passthrough_mode_v2(psmouse, false)) +		return -1; + +	if (alps_absolute_mode_v6(psmouse)) { +		psmouse_err(psmouse, "Failed to enable absolute mode\n"); +		return -1; +	} + +	return 0; +} +  /*   * Enable or disable passthrough mode to the trackstick.   */ @@ -1519,6 +1793,52 @@ error:  	return -1;  } +static int alps_dolphin_get_device_area(struct psmouse *psmouse, +					struct alps_data *priv) +{ +	struct ps2dev *ps2dev = &psmouse->ps2dev; +	unsigned char param[4] = {0}; +	int num_x_electrode, num_y_electrode; + +	if (alps_enter_command_mode(psmouse)) +		return -1; + +	param[0] = 0x0a; +	if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) || +	    ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) || +	    ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) || +	    ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) || +	    ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE)) +		return -1; + +	if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) +		return -1; + +	/* +	 * Dolphin's sensor line number is not fixed. It can be calculated +	 * by adding the device's register value with DOLPHIN_PROFILE_X/YOFFSET. +	 * Further more, we can get device's x_max and y_max by multiplying +	 * sensor line number with DOLPHIN_COUNT_PER_ELECTRODE. +	 * +	 * e.g. When we get register's sensor_x = 11 & sensor_y = 8, +	 *	real sensor line number X = 11 + 8 = 19, and +	 *	real sensor line number Y = 8 + 1 = 9. +	 *	So, x_max = (19 - 1) * 64 = 1152, and +	 *	    y_max = (9 - 1) * 64 = 512. +	 */ +	num_x_electrode = DOLPHIN_PROFILE_XOFFSET + (param[2] & 0x0F); +	num_y_electrode = DOLPHIN_PROFILE_YOFFSET + ((param[2] >> 4) & 0x0F); +	priv->x_bits = num_x_electrode; +	priv->y_bits = num_y_electrode; +	priv->x_max = (num_x_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE; +	priv->y_max = (num_y_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE; + +	if (alps_exit_command_mode(psmouse)) +		return -1; + +	return 0; +} +  static int alps_hw_init_dolphin_v1(struct psmouse *psmouse)  {  	struct ps2dev *ps2dev = &psmouse->ps2dev; @@ -1553,6 +1873,8 @@ static void alps_set_defaults(struct alps_data *priv)  		priv->hw_init = alps_hw_init_v1_v2;  		priv->process_packet = alps_process_packet_v1_v2;  		priv->set_abs_params = alps_set_abs_params_st; +		priv->x_max = 1023; +		priv->y_max = 767;  		break;  	case ALPS_PROTO_V3:  		priv->hw_init = alps_hw_init_v3; @@ -1571,19 +1893,27 @@ static void alps_set_defaults(struct alps_data *priv)  		break;  	case ALPS_PROTO_V5:  		priv->hw_init = alps_hw_init_dolphin_v1; -		priv->process_packet = alps_process_packet_v3; +		priv->process_packet = alps_process_touchpad_packet_v3_v5;  		priv->decode_fields = alps_decode_dolphin;  		priv->set_abs_params = alps_set_abs_params_mt;  		priv->nibble_commands = alps_v3_nibble_commands;  		priv->addr_command = PSMOUSE_CMD_RESET_WRAP;  		priv->byte0 = 0xc8; -		priv->mask0 = 0xc8; +		priv->mask0 = 0xd8;  		priv->flags = 0;  		priv->x_max = 1360;  		priv->y_max = 660;  		priv->x_bits = 23;  		priv->y_bits = 12;  		break; +	case ALPS_PROTO_V6: +		priv->hw_init = alps_hw_init_v6; +		priv->process_packet = alps_process_packet_v6; +		priv->set_abs_params = alps_set_abs_params_st; +		priv->nibble_commands = alps_v6_nibble_commands; +		priv->x_max = 2047; +		priv->y_max = 1535; +		break;  	}  } @@ -1645,11 +1975,13 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)  	if (alps_match_table(psmouse, priv, e7, ec) == 0) {  		return 0;  	} else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 && -		   ec[0] == 0x73 && ec[1] == 0x01) { +		   ec[0] == 0x73 && (ec[1] == 0x01 || ec[1] == 0x02)) {  		priv->proto_version = ALPS_PROTO_V5;  		alps_set_defaults(priv); - -		return 0; +		if (alps_dolphin_get_device_area(psmouse, priv)) +			return -EIO; +		else +			return 0;  	} else if (ec[0] == 0x88 && ec[1] == 0x08) {  		priv->proto_version = ALPS_PROTO_V3;  		alps_set_defaults(priv); @@ -1705,8 +2037,8 @@ static void alps_disconnect(struct psmouse *psmouse)  static void alps_set_abs_params_st(struct alps_data *priv,  				   struct input_dev *dev1)  { -	input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0); -	input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0); +	input_set_abs_params(dev1, ABS_X, 0, priv->x_max, 0, 0); +	input_set_abs_params(dev1, ABS_Y, 0, priv->y_max, 0, 0);  }  static void alps_set_abs_params_mt(struct alps_data *priv, @@ -1792,7 +2124,7 @@ int alps_init(struct psmouse *psmouse)  	snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys);  	dev2->phys = priv->phys;  	dev2->name = (priv->flags & ALPS_DUALPOINT) ? -		     "DualPoint Stick" : "PS/2 Mouse"; +		     "DualPoint Stick" : "ALPS PS/2 Device";  	dev2->id.bustype = BUS_I8042;  	dev2->id.vendor  = 0x0002;  	dev2->id.product = PSMOUSE_ALPS; diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index eee59853b9c..03f88b6940c 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -17,6 +17,11 @@  #define ALPS_PROTO_V3	3  #define ALPS_PROTO_V4	4  #define ALPS_PROTO_V5	5 +#define ALPS_PROTO_V6	6 + +#define DOLPHIN_COUNT_PER_ELECTRODE	64 +#define DOLPHIN_PROFILE_XOFFSET		8	/* x-electrode offset */ +#define DOLPHIN_PROFILE_YOFFSET		1	/* y-electrode offset */  /**   * struct alps_model_info - touchpad ID table @@ -145,7 +150,8 @@ struct alps_data {  	int (*hw_init)(struct psmouse *psmouse);  	void (*process_packet)(struct psmouse *psmouse); -	void (*decode_fields)(struct alps_fields *f, unsigned char *p); +	void (*decode_fields)(struct alps_fields *f, unsigned char *p, +			      struct psmouse *psmouse);  	void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1);  	int prev_fin; diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c index e42f1fa8cdc..ef234c9b2f2 100644 --- a/drivers/input/mouse/appletouch.c +++ b/drivers/input/mouse/appletouch.c @@ -30,7 +30,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/usb/input.h> @@ -49,6 +48,7 @@ struct atp_info {  	int yfact;				/* Y multiplication factor */  	int datalen;				/* size of USB transfers */  	void (*callback)(struct urb *);		/* callback function */ +	int fuzz;				/* fuzz touchpad generates */  };  static void atp_complete_geyser_1_2(struct urb *urb); @@ -62,6 +62,7 @@ static const struct atp_info fountain_info = {  	.yfact		= 43,  	.datalen	= 81,  	.callback	= atp_complete_geyser_1_2, +	.fuzz		= 16,  };  static const struct atp_info geyser1_info = { @@ -72,6 +73,7 @@ static const struct atp_info geyser1_info = {  	.yfact		= 43,  	.datalen	= 81,  	.callback	= atp_complete_geyser_1_2, +	.fuzz		= 16,  };  static const struct atp_info geyser2_info = { @@ -82,6 +84,7 @@ static const struct atp_info geyser2_info = {  	.yfact		= 43,  	.datalen	= 64,  	.callback	= atp_complete_geyser_1_2, +	.fuzz		= 0,  };  static const struct atp_info geyser3_info = { @@ -91,6 +94,7 @@ static const struct atp_info geyser3_info = {  	.yfact		= 64,  	.datalen	= 64,  	.callback	= atp_complete_geyser_3_4, +	.fuzz		= 0,  };  static const struct atp_info geyser4_info = { @@ -100,6 +104,7 @@ static const struct atp_info geyser4_info = {  	.yfact		= 64,  	.datalen	= 64,  	.callback	= atp_complete_geyser_3_4, +	.fuzz		= 0,  };  #define ATP_DEVICE(prod, info)					\ @@ -156,8 +161,11 @@ MODULE_DEVICE_TABLE(usb, atp_table);  #define ATP_XSENSORS	26  #define ATP_YSENSORS	16 -/* amount of fuzz this touchpad generates */ -#define ATP_FUZZ	16 +/* + * The largest possible bank of sensors with additional buffer of 4 extra values + * on either side, for an array of smoothed sensor values. + */ +#define ATP_SMOOTHSIZE	34  /* maximum pressure this driver will report */  #define ATP_PRESSURE	300 @@ -166,7 +174,13 @@ MODULE_DEVICE_TABLE(usb, atp_table);   * Threshold for the touchpad sensors. Any change less than ATP_THRESHOLD is   * ignored.   */ -#define ATP_THRESHOLD	 5 +#define ATP_THRESHOLD	5 + +/* + * How far we'll bitshift our sensor values before averaging them. Mitigates + * rounding errors. + */ +#define ATP_SCALE	12  /* Geyser initialization constants */  #define ATP_GEYSER_MODE_READ_REQUEST_ID		1 @@ -204,11 +218,14 @@ struct atp {  	bool			valid;		/* are the samples valid? */  	bool			size_detect_done;  	bool			overflow_warned; +	int			fingers_old;	/* last reported finger count */  	int			x_old;		/* last reported x/y, */  	int			y_old;		/* used for smoothing */  	signed char		xy_cur[ATP_XSENSORS + ATP_YSENSORS];  	signed char		xy_old[ATP_XSENSORS + ATP_YSENSORS];  	int			xy_acc[ATP_XSENSORS + ATP_YSENSORS]; +	int			smooth[ATP_SMOOTHSIZE]; +	int			smooth_tmp[ATP_SMOOTHSIZE];  	int			idlecount;	/* number of empty packets */  	struct work_struct	work;  }; @@ -327,10 +344,17 @@ static void atp_reinit(struct work_struct *work)  			retval);  } -static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact, -			     int *z, int *fingers) +static int atp_calculate_abs(struct atp *dev, int offset, int nb_sensors, +			     int fact, int *z, int *fingers)  { -	int i; +	int i, pass; + +	/* +	 * Use offset to point xy_sensors at the first value in dev->xy_acc +	 * for whichever dimension we're looking at this particular go-round. +	 */ +	int *xy_sensors = dev->xy_acc + offset; +  	/* values to calculate mean */  	int pcum = 0, psum = 0;  	int is_increasing = 0; @@ -342,9 +366,6 @@ static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,  			if (is_increasing)  				is_increasing = 0; -			continue; -		} -  		/*  		 * Makes the finger detection more versatile.  For example,  		 * two fingers with no gap will be detected.  Also, my @@ -359,27 +380,63 @@ static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,  		 *  		 * - Jason Parekh <jasonparekh@gmail.com>  		 */ -		if (i < 1 || + +		} else if (i < 1 ||  		    (!is_increasing && xy_sensors[i - 1] < xy_sensors[i])) {  			(*fingers)++;  			is_increasing = 1;  		} else if (i > 0 && (xy_sensors[i - 1] - xy_sensors[i] > threshold)) {  			is_increasing = 0;  		} +	} + +	if (*fingers < 1)     /* No need to continue if no fingers are found. */ +		return 0; +	/* +	 * Use a smoothed version of sensor data for movement calculations, to +	 * combat noise without needing to rely so heavily on a threshold. +	 * This improves tracking. +	 * +	 * The smoothed array is bigger than the original so that the smoothing +	 * doesn't result in edge values being truncated. +	 */ + +	memset(dev->smooth, 0, 4 * sizeof(dev->smooth[0])); +	/* Pull base values, scaled up to help avoid truncation errors. */ +	for (i = 0; i < nb_sensors; i++) +		dev->smooth[i + 4] = xy_sensors[i] << ATP_SCALE; +	memset(&dev->smooth[nb_sensors + 4], 0, 4 * sizeof(dev->smooth[0])); + +	for (pass = 0; pass < 4; pass++) { +		/* Handle edge. */ +		dev->smooth_tmp[0] = (dev->smooth[0] + dev->smooth[1]) / 2; + +		/* Average values with neighbors. */ +		for (i = 1; i < nb_sensors + 7; i++) +			dev->smooth_tmp[i] = (dev->smooth[i - 1] + +					      dev->smooth[i] * 2 + +					      dev->smooth[i + 1]) / 4; + +		/* Handle other edge. */ +		dev->smooth_tmp[i] = (dev->smooth[i - 1] + dev->smooth[i]) / 2; + +		memcpy(dev->smooth, dev->smooth_tmp, sizeof(dev->smooth)); +	} + +	for (i = 0; i < nb_sensors + 8; i++) {  		/* -		 * Subtracts threshold so a high sensor that just passes the -		 * threshold won't skew the calculated absolute coordinate. -		 * Fixes an issue where slowly moving the mouse would -		 * occasionally jump a number of pixels (slowly moving the -		 * finger makes this issue most apparent.) +		 * Skip values if they're small enough to be truncated to 0 +		 * by scale. Mostly noise.  		 */ -		pcum += (xy_sensors[i] - threshold) * i; -		psum += (xy_sensors[i] - threshold); +		if ((dev->smooth[i] >> ATP_SCALE) > 0) { +			pcum += dev->smooth[i] * i; +			psum += dev->smooth[i]; +		}  	}  	if (psum > 0) { -		*z = psum; +		*z = psum >> ATP_SCALE;        /* Scale down pressure output. */  		return pcum * fact / psum;  	} @@ -456,7 +513,7 @@ static void atp_detect_size(struct atp *dev)  			input_set_abs_params(dev->input, ABS_X, 0,  					     (dev->info->xsensors_17 - 1) *  							dev->info->xfact - 1, -					     ATP_FUZZ, 0); +					     dev->info->fuzz, 0);  			break;  		}  	} @@ -472,7 +529,7 @@ static void atp_complete_geyser_1_2(struct urb *urb)  {  	int x, y, x_z, y_z, x_f, y_f;  	int retval, i, j; -	int key; +	int key, fingers;  	struct atp *dev = urb->context;  	int status = atp_status_check(urb); @@ -549,16 +606,18 @@ static void atp_complete_geyser_1_2(struct urb *urb)  	dbg_dump("accumulator", dev->xy_acc); -	x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS, +	x = atp_calculate_abs(dev, 0, ATP_XSENSORS,  			      dev->info->xfact, &x_z, &x_f); -	y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS, +	y = atp_calculate_abs(dev, ATP_XSENSORS, ATP_YSENSORS,  			      dev->info->yfact, &y_z, &y_f);  	key = dev->data[dev->info->datalen - 1] & ATP_STATUS_BUTTON; -	if (x && y) { +	fingers = max(x_f, y_f); + +	if (x && y && fingers == dev->fingers_old) {  		if (dev->x_old != -1) { -			x = (dev->x_old * 3 + x) >> 2; -			y = (dev->y_old * 3 + y) >> 2; +			x = (dev->x_old * 7 + x) >> 3; +			y = (dev->y_old * 7 + y) >> 3;  			dev->x_old = x;  			dev->y_old = y; @@ -572,7 +631,7 @@ static void atp_complete_geyser_1_2(struct urb *urb)  			input_report_abs(dev->input, ABS_Y, y);  			input_report_abs(dev->input, ABS_PRESSURE,  					 min(ATP_PRESSURE, x_z + y_z)); -			atp_report_fingers(dev->input, max(x_f, y_f)); +			atp_report_fingers(dev->input, fingers);  		}  		dev->x_old = x;  		dev->y_old = y; @@ -580,6 +639,7 @@ static void atp_complete_geyser_1_2(struct urb *urb)  	} else if (!x && !y) {  		dev->x_old = dev->y_old = -1; +		dev->fingers_old = 0;  		input_report_key(dev->input, BTN_TOUCH, 0);  		input_report_abs(dev->input, ABS_PRESSURE, 0);  		atp_report_fingers(dev->input, 0); @@ -588,6 +648,10 @@ static void atp_complete_geyser_1_2(struct urb *urb)  		memset(dev->xy_acc, 0, sizeof(dev->xy_acc));  	} +	if (fingers != dev->fingers_old) +		dev->x_old = dev->y_old = -1; +	dev->fingers_old = fingers; +  	input_report_key(dev->input, BTN_LEFT, key);  	input_sync(dev->input); @@ -605,7 +669,7 @@ static void atp_complete_geyser_3_4(struct urb *urb)  {  	int x, y, x_z, y_z, x_f, y_f;  	int retval, i, j; -	int key; +	int key, fingers;  	struct atp *dev = urb->context;  	int status = atp_status_check(urb); @@ -661,16 +725,19 @@ static void atp_complete_geyser_3_4(struct urb *urb)  	dbg_dump("accumulator", dev->xy_acc); -	x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS, +	x = atp_calculate_abs(dev, 0, ATP_XSENSORS,  			      dev->info->xfact, &x_z, &x_f); -	y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS, +	y = atp_calculate_abs(dev, ATP_XSENSORS, ATP_YSENSORS,  			      dev->info->yfact, &y_z, &y_f); +  	key = dev->data[dev->info->datalen - 1] & ATP_STATUS_BUTTON; -	if (x && y) { +	fingers = max(x_f, y_f); + +	if (x && y && fingers == dev->fingers_old) {  		if (dev->x_old != -1) { -			x = (dev->x_old * 3 + x) >> 2; -			y = (dev->y_old * 3 + y) >> 2; +			x = (dev->x_old * 7 + x) >> 3; +			y = (dev->y_old * 7 + y) >> 3;  			dev->x_old = x;  			dev->y_old = y; @@ -684,7 +751,7 @@ static void atp_complete_geyser_3_4(struct urb *urb)  			input_report_abs(dev->input, ABS_Y, y);  			input_report_abs(dev->input, ABS_PRESSURE,  					 min(ATP_PRESSURE, x_z + y_z)); -			atp_report_fingers(dev->input, max(x_f, y_f)); +			atp_report_fingers(dev->input, fingers);  		}  		dev->x_old = x;  		dev->y_old = y; @@ -692,6 +759,7 @@ static void atp_complete_geyser_3_4(struct urb *urb)  	} else if (!x && !y) {  		dev->x_old = dev->y_old = -1; +		dev->fingers_old = 0;  		input_report_key(dev->input, BTN_TOUCH, 0);  		input_report_abs(dev->input, ABS_PRESSURE, 0);  		atp_report_fingers(dev->input, 0); @@ -700,6 +768,10 @@ static void atp_complete_geyser_3_4(struct urb *urb)  		memset(dev->xy_acc, 0, sizeof(dev->xy_acc));  	} +	if (fingers != dev->fingers_old) +		dev->x_old = dev->y_old = -1; +	dev->fingers_old = fingers; +  	input_report_key(dev->input, BTN_LEFT, key);  	input_sync(dev->input); @@ -844,10 +916,10 @@ static int atp_probe(struct usb_interface *iface,  	input_set_abs_params(input_dev, ABS_X, 0,  			     (dev->info->xsensors - 1) * dev->info->xfact - 1, -			     ATP_FUZZ, 0); +			     dev->info->fuzz, 0);  	input_set_abs_params(input_dev, ABS_Y, 0,  			     (dev->info->ysensors - 1) * dev->info->yfact - 1, -			     ATP_FUZZ, 0); +			     dev->info->fuzz, 0);  	input_set_abs_params(input_dev, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0);  	set_bit(EV_KEY, input_dev->evbit); diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index a73f9618b0a..c329cdb0b91 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -34,7 +34,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/usb/input.h> diff --git a/drivers/input/mouse/cypress_ps2.c b/drivers/input/mouse/cypress_ps2.c index f51765fff05..8af34ffe208 100644 --- a/drivers/input/mouse/cypress_ps2.c +++ b/drivers/input/mouse/cypress_ps2.c @@ -15,7 +15,6 @@   * the Free Software Foundation.   */ -#include <linux/init.h>  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/slab.h> @@ -410,7 +409,6 @@ static int cypress_set_input_params(struct input_dev *input,  	__clear_bit(REL_X, input->relbit);  	__clear_bit(REL_Y, input->relbit); -	__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);  	__set_bit(EV_KEY, input->evbit);  	__set_bit(BTN_LEFT, input->keybit);  	__set_bit(BTN_RIGHT, input->keybit); @@ -439,7 +437,7 @@ static int cypress_get_finger_count(unsigned char header_byte)  			case 2: return 5;  			default:  				/* Invalid contact (e.g. palm). Ignore it. */ -				return -1; +				return 0;  		}  	} @@ -452,17 +450,10 @@ static int cypress_parse_packet(struct psmouse *psmouse,  {  	unsigned char *packet = psmouse->packet;  	unsigned char header_byte = packet[0]; -	int contact_cnt;  	memset(report_data, 0, sizeof(struct cytp_report_data)); -	contact_cnt = cypress_get_finger_count(header_byte); - -	if (contact_cnt < 0) /* e.g. palm detect */ -		return -EINVAL; - -	report_data->contact_cnt = contact_cnt; - +	report_data->contact_cnt = cypress_get_finger_count(header_byte);  	report_data->tap = (header_byte & ABS_MULTIFINGER_TAP) ? 1 : 0;  	if (report_data->contact_cnt == 1) { @@ -535,11 +526,9 @@ static void cypress_process_packet(struct psmouse *psmouse, bool zero_pkt)  	int slots[CYTP_MAX_MT_SLOTS];  	int n; -	if (cypress_parse_packet(psmouse, cytp, &report_data)) -		return; +	cypress_parse_packet(psmouse, cytp, &report_data);  	n = report_data.contact_cnt; -  	if (n > CYTP_MAX_MT_SLOTS)  		n = CYTP_MAX_MT_SLOTS; @@ -605,10 +594,6 @@ static psmouse_ret_t cypress_validate_byte(struct psmouse *psmouse)  		return PSMOUSE_BAD_DATA;  	contact_cnt = cypress_get_finger_count(packet[0]); - -	if (contact_cnt < 0) -		return PSMOUSE_BAD_DATA; -  	if (cytp->mode & CYTP_BIT_ABS_NO_PRESSURE)  		cypress_set_packet_size(psmouse, contact_cnt == 2 ? 7 : 4);  	else @@ -679,15 +664,15 @@ int cypress_init(struct psmouse *psmouse)  {  	struct cytp_data *cytp; -	cytp = (struct cytp_data *)kzalloc(sizeof(struct cytp_data), GFP_KERNEL); -	psmouse->private = (void *)cytp; -	if (cytp == NULL) +	cytp = kzalloc(sizeof(struct cytp_data), GFP_KERNEL); +	if (!cytp)  		return -ENOMEM; -	cypress_reset(psmouse); - +	psmouse->private = cytp;  	psmouse->pktsize = 8; +	cypress_reset(psmouse); +  	if (cypress_query_hardware(psmouse)) {  		psmouse_err(psmouse, "Unable to query Trackpad hardware.\n");  		goto err_exit; diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 8551dcaf24d..ee2a04d90d2 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -11,6 +11,7 @@   */  #include <linux/delay.h> +#include <linux/dmi.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/input.h> @@ -472,8 +473,15 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,  	input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);  	input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);  	input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); -	input_report_key(dev, BTN_LEFT, packet[0] & 0x01); -	input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); + +	/* For clickpads map both buttons to BTN_LEFT */ +	if (etd->fw_version & 0x001000) { +		input_report_key(dev, BTN_LEFT, packet[0] & 0x03); +	} else { +		input_report_key(dev, BTN_LEFT, packet[0] & 0x01); +		input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); +	} +  	input_report_abs(dev, ABS_PRESSURE, pres);  	input_report_abs(dev, ABS_TOOL_WIDTH, width); @@ -483,9 +491,17 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,  static void elantech_input_sync_v4(struct psmouse *psmouse)  {  	struct input_dev *dev = psmouse->dev; +	struct elantech_data *etd = psmouse->private;  	unsigned char *packet = psmouse->packet; -	input_report_key(dev, BTN_LEFT, packet[0] & 0x01); +	/* For clickpads map both buttons to BTN_LEFT */ +	if (etd->fw_version & 0x001000) { +		input_report_key(dev, BTN_LEFT, packet[0] & 0x03); +	} else { +		input_report_key(dev, BTN_LEFT, packet[0] & 0x01); +		input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); +	} +  	input_mt_report_pointer_emulation(dev, true);  	input_sync(dev);  } @@ -830,7 +846,11 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)  		break;  	case 3: -		etd->reg_10 = 0x0b; +		if (etd->set_hw_resolution) +			etd->reg_10 = 0x0b; +		else +			etd->reg_10 = 0x01; +  		if (elantech_write_reg(psmouse, 0x10, etd->reg_10))  			rc = -1; @@ -984,6 +1004,44 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,  }  /* + * Advertise INPUT_PROP_BUTTONPAD for clickpads. The testing of bit 12 in + * fw_version for this is based on the following fw_version & caps table: + * + * Laptop-model:           fw_version:     caps:           buttons: + * Acer S3                 0x461f00        10, 13, 0e      clickpad + * Acer S7-392             0x581f01        50, 17, 0d      clickpad + * Acer V5-131             0x461f02        01, 16, 0c      clickpad + * Acer V5-551             0x461f00        ?               clickpad + * Asus K53SV              0x450f01        78, 15, 0c      2 hw buttons + * Asus G46VW              0x460f02        00, 18, 0c      2 hw buttons + * Asus G750JX             0x360f00        00, 16, 0c      2 hw buttons + * Asus UX31               0x361f00        20, 15, 0e      clickpad + * Asus UX32VD             0x361f02        00, 15, 0e      clickpad + * Avatar AVIU-145A2       0x361f00        ?               clickpad + * Gigabyte U2442          0x450f01        58, 17, 0c      2 hw buttons + * Lenovo L430             0x350f02        b9, 15, 0c      2 hw buttons (*) + * Samsung NF210           0x150b00        78, 14, 0a      2 hw buttons + * Samsung NP770Z5E        0x575f01        10, 15, 0f      clickpad + * Samsung NP700Z5B        0x361f06        21, 15, 0f      clickpad + * Samsung NP900X3E-A02    0x575f03        ?               clickpad + * Samsung NP-QX410        0x851b00        19, 14, 0c      clickpad + * Samsung RC512           0x450f00        08, 15, 0c      2 hw buttons + * Samsung RF710           0x450f00        ?               2 hw buttons + * System76 Pangolin       0x250f01        ?               2 hw buttons + * (*) + 3 trackpoint buttons + */ +static void elantech_set_buttonpad_prop(struct psmouse *psmouse) +{ +	struct input_dev *dev = psmouse->dev; +	struct elantech_data *etd = psmouse->private; + +	if (etd->fw_version & 0x001000) { +		__set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); +		__clear_bit(BTN_RIGHT, dev->keybit); +	} +} + +/*   * Set the appropriate event bits for the input subsystem   */  static int elantech_set_input_params(struct psmouse *psmouse) @@ -1026,6 +1084,8 @@ static int elantech_set_input_params(struct psmouse *psmouse)  		__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);  		/* fall through */  	case 3: +		if (etd->hw_version == 3) +			elantech_set_buttonpad_prop(psmouse);  		input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);  		input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);  		if (etd->reports_pressure) { @@ -1047,9 +1107,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)  			 */  			psmouse_warn(psmouse, "couldn't query resolution data.\n");  		} -		/* v4 is clickpad, with only one button. */ -		__set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); -		__clear_bit(BTN_RIGHT, dev->keybit); +		elantech_set_buttonpad_prop(psmouse);  		__set_bit(BTN_TOOL_QUADTAP, dev->keybit);  		/* For X to recognize me as touchpad. */  		input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0); @@ -1292,6 +1350,23 @@ static int elantech_reconnect(struct psmouse *psmouse)  }  /* + * Some hw_version 3 models go into error state when we try to set + * bit 3 and/or bit 1 of r10. + */ +static const struct dmi_system_id no_hw_res_dmi_table[] = { +#if defined(CONFIG_DMI) && defined(CONFIG_X86) +	{ +		/* Gigabyte U2442 */ +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), +			DMI_MATCH(DMI_PRODUCT_NAME, "U2442"), +		}, +	}, +#endif +	{ } +}; + +/*   * determine hardware version and set some properties according to it.   */  static int elantech_set_properties(struct elantech_data *etd) @@ -1313,6 +1388,8 @@ static int elantech_set_properties(struct elantech_data *etd)  			break;  		case 6:  		case 7: +		case 8: +		case 9:  			etd->hw_version = 4;  			break;  		default: @@ -1349,6 +1426,9 @@ static int elantech_set_properties(struct elantech_data *etd)  	 */  	etd->crc_enabled = ((etd->fw_version & 0x4000) == 0x4000); +	/* Enable real hardware resolution on hw_version 3 ? */ +	etd->set_hw_resolution = !dmi_check_system(no_hw_res_dmi_table); +  	return 0;  } diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h index 036a04abaef..9e0e2a1f340 100644 --- a/drivers/input/mouse/elantech.h +++ b/drivers/input/mouse/elantech.h @@ -130,6 +130,7 @@ struct elantech_data {  	bool jumpy_cursor;  	bool reports_pressure;  	bool crc_enabled; +	bool set_hw_resolution;  	unsigned char hw_version;  	unsigned int fw_version;  	unsigned int single_finger_reports; diff --git a/drivers/input/mouse/gpio_mouse.c b/drivers/input/mouse/gpio_mouse.c index 6b44413f54e..8c7d94200bd 100644 --- a/drivers/input/mouse/gpio_mouse.c +++ b/drivers/input/mouse/gpio_mouse.c @@ -8,7 +8,6 @@   * published by the Free Software Foundation.   */ -#include <linux/init.h>  #include <linux/module.h>  #include <linux/platform_device.h>  #include <linux/input-polldev.h> @@ -48,7 +47,7 @@ static void gpio_mouse_scan(struct input_polled_dev *dev)  static int gpio_mouse_probe(struct platform_device *pdev)  { -	struct gpio_mouse_platform_data *pdata = pdev->dev.platform_data; +	struct gpio_mouse_platform_data *pdata = dev_get_platdata(&pdev->dev);  	struct input_polled_dev *input_poll;  	struct input_dev *input;  	int pin, i; diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index 84de2fc6acc..136e222e2a1 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -220,7 +220,7 @@ static const struct ps2pp_info *get_model_info(unsigned char model)  		{ 61,	PS2PP_KIND_MX,					/* MX700 */  				PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |  				PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, -		{ 66,	PS2PP_KIND_MX,					/* MX3100 reciver */ +		{ 66,	PS2PP_KIND_MX,					/* MX3100 receiver */  				PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |  				PS2PP_EXTRA_BTN | PS2PP_NAV_BTN | PS2PP_HWHEEL },  		{ 72,	PS2PP_KIND_TRACKMAN,	0 },			/* T-CH11: TrackMan Marble */ diff --git a/drivers/input/mouse/navpoint.c b/drivers/input/mouse/navpoint.c index 0b8d33591de..1ccc88af1f0 100644 --- a/drivers/input/mouse/navpoint.c +++ b/drivers/input/mouse/navpoint.c @@ -9,7 +9,6 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/module.h>  #include <linux/platform_device.h>  #include <linux/clk.h> diff --git a/drivers/input/mouse/pxa930_trkball.c b/drivers/input/mouse/pxa930_trkball.c index 0ecb9e7945e..9b4d9a59e22 100644 --- a/drivers/input/mouse/pxa930_trkball.c +++ b/drivers/input/mouse/pxa930_trkball.c @@ -10,7 +10,6 @@   *  published by the Free Software Foundation.   */ -#include <linux/init.h>  #include <linux/input.h>  #include <linux/interrupt.h>  #include <linux/module.h> @@ -166,7 +165,7 @@ static int pxa930_trkball_probe(struct platform_device *pdev)  	if (!trkball)  		return -ENOMEM; -	trkball->pdata = pdev->dev.platform_data; +	trkball->pdata = dev_get_platdata(&pdev->dev);  	if (!trkball->pdata) {  		dev_err(&pdev->dev, "no platform data defined\n");  		error = -EINVAL; diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c index d5928fd0c91..8df526620eb 100644 --- a/drivers/input/mouse/sermouse.c +++ b/drivers/input/mouse/sermouse.c @@ -32,7 +32,6 @@  #include <linux/interrupt.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"Serial mouse driver" diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 26386f9d256..ef9e0b8a9aa 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -117,6 +117,82 @@ void synaptics_reset(struct psmouse *psmouse)  }  #ifdef CONFIG_MOUSE_PS2_SYNAPTICS +struct min_max_quirk { +	const char * const *pnp_ids; +	int x_min, x_max, y_min, y_max; +}; + +static const struct min_max_quirk min_max_pnpid_table[] = { +	{ +		(const char * const []){"LEN0033", NULL}, +		1024, 5052, 2258, 4832 +	}, +	{ +		(const char * const []){"LEN0035", "LEN0042", NULL}, +		1232, 5710, 1156, 4696 +	}, +	{ +		(const char * const []){"LEN0034", "LEN0036", "LEN2002", +					"LEN2004", NULL}, +		1024, 5112, 2024, 4832 +	}, +	{ +		(const char * const []){"LEN2001", NULL}, +		1024, 5022, 2508, 4832 +	}, +	{ } +}; + +/* This list has been kindly provided by Synaptics. */ +static const char * const topbuttonpad_pnp_ids[] = { +	"LEN0017", +	"LEN0018", +	"LEN0019", +	"LEN0023", +	"LEN002A", +	"LEN002B", +	"LEN002C", +	"LEN002D", +	"LEN002E", +	"LEN0033", /* Helix */ +	"LEN0034", /* T431s, L440, L540, T540, W540, X1 Carbon 2nd */ +	"LEN0035", /* X240 */ +	"LEN0036", /* T440 */ +	"LEN0037", +	"LEN0038", +	"LEN0041", +	"LEN0042", /* Yoga */ +	"LEN0045", +	"LEN0046", +	"LEN0047", +	"LEN0048", +	"LEN0049", +	"LEN2000", +	"LEN2001", /* Edge E431 */ +	"LEN2002", /* Edge E531 */ +	"LEN2003", +	"LEN2004", /* L440 */ +	"LEN2005", +	"LEN2006", +	"LEN2007", +	"LEN2008", +	"LEN2009", +	"LEN200A", +	"LEN200B", +	NULL +}; + +static bool matches_pnp_id(struct psmouse *psmouse, const char * const ids[]) +{ +	int i; + +	if (!strncmp(psmouse->ps2dev.serio->firmware_id, "PNP:", 4)) +		for (i = 0; ids[i]; i++) +			if (strstr(psmouse->ps2dev.serio->firmware_id, ids[i])) +				return true; + +	return false; +}  /*****************************************************************************   *	Synaptics communications functions @@ -265,10 +341,12 @@ static int synaptics_identify(struct psmouse *psmouse)   * Read touchpad resolution and maximum reported coordinates   * Resolution is left zero if touchpad does not support the query   */ +  static int synaptics_resolution(struct psmouse *psmouse)  {  	struct synaptics_data *priv = psmouse->private;  	unsigned char resp[3]; +	int i;  	if (SYN_ID_MAJOR(priv->identity) < 4)  		return 0; @@ -280,6 +358,16 @@ static int synaptics_resolution(struct psmouse *psmouse)  		}  	} +	for (i = 0; min_max_pnpid_table[i].pnp_ids; i++) { +		if (matches_pnp_id(psmouse, min_max_pnpid_table[i].pnp_ids)) { +			priv->x_min = min_max_pnpid_table[i].x_min; +			priv->x_max = min_max_pnpid_table[i].x_max; +			priv->y_min = min_max_pnpid_table[i].y_min; +			priv->y_max = min_max_pnpid_table[i].y_max; +			return 0; +		} +	} +  	if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 &&  	    SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) {  		if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MAX_COORDS, resp)) { @@ -1244,8 +1332,10 @@ static void set_abs_position_params(struct input_dev *dev,  	input_abs_set_res(dev, y_code, priv->y_res);  } -static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) +static void set_input_params(struct psmouse *psmouse, +			     struct synaptics_data *priv)  { +	struct input_dev *dev = psmouse->dev;  	int i;  	/* Things that apply to both modes */ @@ -1314,6 +1404,8 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)  	if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {  		__set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); +		if (matches_pnp_id(psmouse, topbuttonpad_pnp_ids)) +			__set_bit(INPUT_PROP_TOPBUTTONPAD, dev->propbit);  		/* Clickpads report only left button */  		__clear_bit(BTN_RIGHT, dev->keybit);  		__clear_bit(BTN_MIDDLE, dev->keybit); @@ -1538,7 +1630,7 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)  		     priv->capabilities, priv->ext_cap, priv->ext_cap_0c,  		     priv->board_id, priv->firmware_id); -	set_input_params(psmouse->dev, priv); +	set_input_params(psmouse, priv);  	/*  	 * Encode touchpad model so that it can be used to set diff --git a/drivers/input/mouse/synaptics_usb.c b/drivers/input/mouse/synaptics_usb.c index 64cf34ea760..e122bda16aa 100644 --- a/drivers/input/mouse/synaptics_usb.c +++ b/drivers/input/mouse/synaptics_usb.c @@ -39,7 +39,6 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/moduleparam.h> diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c index e900d465aaf..38298232124 100644 --- a/drivers/input/mouse/vsxxxaa.c +++ b/drivers/input/mouse/vsxxxaa.c @@ -82,7 +82,6 @@  #include <linux/interrupt.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC "Driver for DEC VSXXX-AA and -GA mice and VSXXX-AB tablet" diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 4c842c320c2..b604564dec5 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -67,7 +67,6 @@ struct mousedev {  	struct device dev;  	struct cdev cdev;  	bool exist; -	bool is_mixdev;  	struct list_head mixdev_node;  	bool opened_by_mixdev; @@ -77,6 +76,9 @@ struct mousedev {  	int old_x[4], old_y[4];  	int frac_dx, frac_dy;  	unsigned long touch; + +	int (*open_device)(struct mousedev *mousedev); +	void (*close_device)(struct mousedev *mousedev);  };  enum mousedev_emul { @@ -116,9 +118,6 @@ static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 };  static struct mousedev *mousedev_mix;  static LIST_HEAD(mousedev_mix_list); -static void mixdev_open_devices(void); -static void mixdev_close_devices(void); -  #define fx(i)  (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])  #define fy(i)  (mousedev->old_y[(mousedev->pkt_count - (i)) & 03]) @@ -428,9 +427,7 @@ static int mousedev_open_device(struct mousedev *mousedev)  	if (retval)  		return retval; -	if (mousedev->is_mixdev) -		mixdev_open_devices(); -	else if (!mousedev->exist) +	if (!mousedev->exist)  		retval = -ENODEV;  	else if (!mousedev->open++) {  		retval = input_open_device(&mousedev->handle); @@ -446,9 +443,7 @@ static void mousedev_close_device(struct mousedev *mousedev)  {  	mutex_lock(&mousedev->mutex); -	if (mousedev->is_mixdev) -		mixdev_close_devices(); -	else if (mousedev->exist && !--mousedev->open) +	if (mousedev->exist && !--mousedev->open)  		input_close_device(&mousedev->handle);  	mutex_unlock(&mousedev->mutex); @@ -459,21 +454,29 @@ static void mousedev_close_device(struct mousedev *mousedev)   * stream. Note that this function is called with mousedev_mix->mutex   * held.   */ -static void mixdev_open_devices(void) +static int mixdev_open_devices(struct mousedev *mixdev)  { -	struct mousedev *mousedev; +	int error; + +	error = mutex_lock_interruptible(&mixdev->mutex); +	if (error) +		return error; -	if (mousedev_mix->open++) -		return; +	if (!mixdev->open++) { +		struct mousedev *mousedev; -	list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { -		if (!mousedev->opened_by_mixdev) { -			if (mousedev_open_device(mousedev)) -				continue; +		list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { +			if (!mousedev->opened_by_mixdev) { +				if (mousedev_open_device(mousedev)) +					continue; -			mousedev->opened_by_mixdev = true; +				mousedev->opened_by_mixdev = true; +			}  		}  	} + +	mutex_unlock(&mixdev->mutex); +	return 0;  }  /* @@ -481,19 +484,22 @@ static void mixdev_open_devices(void)   * device. Note that this function is called with mousedev_mix->mutex   * held.   */ -static void mixdev_close_devices(void) +static void mixdev_close_devices(struct mousedev *mixdev)  { -	struct mousedev *mousedev; +	mutex_lock(&mixdev->mutex); -	if (--mousedev_mix->open) -		return; +	if (!--mixdev->open) { +		struct mousedev *mousedev; -	list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { -		if (mousedev->opened_by_mixdev) { -			mousedev->opened_by_mixdev = false; -			mousedev_close_device(mousedev); +		list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { +			if (mousedev->opened_by_mixdev) { +				mousedev->opened_by_mixdev = false; +				mousedev_close_device(mousedev); +			}  		}  	} + +	mutex_unlock(&mixdev->mutex);  } @@ -522,7 +528,7 @@ static int mousedev_release(struct inode *inode, struct file *file)  	mousedev_detach_client(mousedev, client);  	kfree(client); -	mousedev_close_device(mousedev); +	mousedev->close_device(mousedev);  	return 0;  } @@ -550,7 +556,7 @@ static int mousedev_open(struct inode *inode, struct file *file)  	client->mousedev = mousedev;  	mousedev_attach_client(mousedev, client); -	error = mousedev_open_device(mousedev); +	error = mousedev->open_device(mousedev);  	if (error)  		goto err_free_client; @@ -861,16 +867,21 @@ static struct mousedev *mousedev_create(struct input_dev *dev,  	if (mixdev) {  		dev_set_name(&mousedev->dev, "mice"); + +		mousedev->open_device = mixdev_open_devices; +		mousedev->close_device = mixdev_close_devices;  	} else {  		int dev_no = minor;  		/* Normalize device number if it falls into legacy range */  		if (dev_no < MOUSEDEV_MINOR_BASE + MOUSEDEV_MINORS)  			dev_no -= MOUSEDEV_MINOR_BASE;  		dev_set_name(&mousedev->dev, "mouse%d", dev_no); + +		mousedev->open_device = mousedev_open_device; +		mousedev->close_device = mousedev_close_device;  	}  	mousedev->exist = true; -	mousedev->is_mixdev = mixdev;  	mousedev->handle.dev = input_get_device(dev);  	mousedev->handle.name = dev_name(&mousedev->dev);  	mousedev->handle.handler = handler; @@ -919,7 +930,7 @@ static void mousedev_destroy(struct mousedev *mousedev)  	device_del(&mousedev->dev);  	mousedev_cleanup(mousedev);  	input_free_minor(MINOR(mousedev->dev.devt)); -	if (!mousedev->is_mixdev) +	if (mousedev != mousedev_mix)  		input_unregister_handle(&mousedev->handle);  	put_device(&mousedev->dev);  } diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index 33b3e88fe4a..bc2d47431bd 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -2,7 +2,7 @@  # Input core configuration  #  config SERIO -	tristate "Serial I/O support" if EXPERT || !X86 +	tristate "Serial I/O support"  	default y  	help  	  Say Yes here if you have any input device that uses serial I/O to @@ -16,14 +16,19 @@ config SERIO  	  To compile this driver as a module, choose M here: the  	  module will be called serio. +config ARCH_MIGHT_HAVE_PC_SERIO +	bool +	help +	  Select this config option from the architecture Kconfig if +	  the architecture might use a PC serio device (i8042) to +	  communicate with keyboard, mouse, etc. +  if SERIO  config SERIO_I8042 -	tristate "i8042 PC Keyboard controller" if EXPERT || !X86 +	tristate "i8042 PC Keyboard controller"  	default y -	depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && \ -		   (!SUPERH || SH_CAYMAN) && !M68K && !BLACKFIN && !S390 && \ -		   !ARC +	depends on ARCH_MIGHT_HAVE_PC_SERIO  	help  	  i8042 is the chip over which the standard AT keyboard and PS/2  	  mouse are connected to the computer. If you use these devices, @@ -170,7 +175,7 @@ config SERIO_MACEPS2  	  module will be called maceps2.  config SERIO_LIBPS2 -	tristate "PS/2 driver library" if EXPERT +	tristate "PS/2 driver library"  	depends on SERIO_I8042 || SERIO_I8042=n  	help  	  Say Y here if you are using a driver for device connected @@ -258,7 +263,7 @@ config SERIO_APBPS2  config SERIO_OLPC_APSP  	tristate "OLPC AP-SP input support" -	depends on OF +	depends on OLPC || COMPILE_TEST  	help  	  Say Y here if you want support for the keyboard and touchpad included  	  in the OLPC XO-1.75 and XO-4 laptops. @@ -266,4 +271,14 @@ config SERIO_OLPC_APSP  	  To compile this driver as a module, choose M here: the module will  	  be called olpc_apsp. +config HYPERV_KEYBOARD +	tristate "Microsoft Synthetic Keyboard driver" +	depends on HYPERV +	default HYPERV +	help +	  Select this option to enable the Hyper-V Keyboard driver. + +	  To compile this driver as a module, choose M here: the module will +	  be called hyperv_keyboard. +  endif diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile index 12298b1c0e7..815d874fe72 100644 --- a/drivers/input/serio/Makefile +++ b/drivers/input/serio/Makefile @@ -28,3 +28,4 @@ obj-$(CONFIG_SERIO_ALTERA_PS2)	+= altera_ps2.o  obj-$(CONFIG_SERIO_ARC_PS2)	+= arc_ps2.o  obj-$(CONFIG_SERIO_APBPS2)	+= apbps2.o  obj-$(CONFIG_SERIO_OLPC_APSP)	+= olpc_apsp.o +obj-$(CONFIG_HYPERV_KEYBOARD)	+= hyperv-keyboard.o diff --git a/drivers/input/serio/altera_ps2.c b/drivers/input/serio/altera_ps2.c index 4777a73cd39..cce69d6b958 100644 --- a/drivers/input/serio/altera_ps2.c +++ b/drivers/input/serio/altera_ps2.c @@ -12,7 +12,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/input.h>  #include <linux/serio.h>  #include <linux/interrupt.h> diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c index 4e2fd44865e..8b748d99b93 100644 --- a/drivers/input/serio/ambakmi.c +++ b/drivers/input/serio/ambakmi.c @@ -10,7 +10,6 @@   * (at your option) any later version.   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/serio.h>  #include <linux/errno.h>  #include <linux/interrupt.h> @@ -80,7 +79,8 @@ static int amba_kmi_open(struct serio *io)  	writeb(divisor, KMICLKDIV);  	writeb(KMICR_EN, KMICR); -	ret = request_irq(kmi->irq, amba_kmi_int, 0, "kmi-pl050", kmi); +	ret = request_irq(kmi->irq, amba_kmi_int, IRQF_SHARED, "kmi-pl050", +			  kmi);  	if (ret) {  		printk(KERN_ERR "kmi: failed to claim IRQ%d\n", kmi->irq);  		writeb(0, KMICR); @@ -167,8 +167,6 @@ static int amba_kmi_remove(struct amba_device *dev)  {  	struct amba_kmi_port *kmi = amba_get_drvdata(dev); -	amba_set_drvdata(dev, NULL); -  	serio_unregister_port(kmi->io);  	clk_put(kmi->clk);  	iounmap(kmi->base); diff --git a/drivers/input/serio/apbps2.c b/drivers/input/serio/apbps2.c index 17e01a807dd..98be824544a 100644 --- a/drivers/input/serio/apbps2.c +++ b/drivers/input/serio/apbps2.c @@ -203,7 +203,7 @@ static int apbps2_of_remove(struct platform_device *of_dev)  	return 0;  } -static struct of_device_id apbps2_of_match[] = { +static const struct of_device_id apbps2_of_match[] = {  	{ .name = "GAISLER_APBPS2", },  	{ .name = "01_060", },  	{} diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index d7a7e54f646..852858e5d8d 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -984,7 +984,7 @@ static void hp_sdc_exit(void)  	free_irq(hp_sdc.irq, &hp_sdc);  	write_unlock_irq(&hp_sdc.lock); -	del_timer(&hp_sdc.kicker); +	del_timer_sync(&hp_sdc.kicker);  	tasklet_kill(&hp_sdc.task); diff --git a/drivers/input/serio/hyperv-keyboard.c b/drivers/input/serio/hyperv-keyboard.c new file mode 100644 index 00000000000..61326199462 --- /dev/null +++ b/drivers/input/serio/hyperv-keyboard.c @@ -0,0 +1,439 @@ +/* + *  Copyright (c) 2013, Microsoft Corporation. + * + *  This program is free software; you can redistribute it and/or modify it + *  under the terms and conditions of the GNU General Public License, + *  version 2, as published by the Free Software Foundation. + * + *  This program is distributed in the hope it will be useful, but WITHOUT + *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + *  more details. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/completion.h> +#include <linux/hyperv.h> +#include <linux/serio.h> +#include <linux/slab.h> + +/* + * Current version 1.0 + * + */ +#define SYNTH_KBD_VERSION_MAJOR 1 +#define SYNTH_KBD_VERSION_MINOR	0 +#define SYNTH_KBD_VERSION		(SYNTH_KBD_VERSION_MINOR | \ +					 (SYNTH_KBD_VERSION_MAJOR << 16)) + + +/* + * Message types in the synthetic input protocol + */ +enum synth_kbd_msg_type { +	SYNTH_KBD_PROTOCOL_REQUEST = 1, +	SYNTH_KBD_PROTOCOL_RESPONSE = 2, +	SYNTH_KBD_EVENT = 3, +	SYNTH_KBD_LED_INDICATORS = 4, +}; + +/* + * Basic message structures. + */ +struct synth_kbd_msg_hdr { +	__le32 type; +}; + +struct synth_kbd_msg { +	struct synth_kbd_msg_hdr header; +	char data[]; /* Enclosed message */ +}; + +union synth_kbd_version { +	__le32 version; +}; + +/* + * Protocol messages + */ +struct synth_kbd_protocol_request { +	struct synth_kbd_msg_hdr header; +	union synth_kbd_version version_requested; +}; + +#define PROTOCOL_ACCEPTED	BIT(0) +struct synth_kbd_protocol_response { +	struct synth_kbd_msg_hdr header; +	__le32 proto_status; +}; + +#define IS_UNICODE	BIT(0) +#define IS_BREAK	BIT(1) +#define IS_E0		BIT(2) +#define IS_E1		BIT(3) +struct synth_kbd_keystroke { +	struct synth_kbd_msg_hdr header; +	__le16 make_code; +	__le16 reserved0; +	__le32 info; /* Additional information */ +}; + + +#define HK_MAXIMUM_MESSAGE_SIZE 256 + +#define KBD_VSC_SEND_RING_BUFFER_SIZE		(10 * PAGE_SIZE) +#define KBD_VSC_RECV_RING_BUFFER_SIZE		(10 * PAGE_SIZE) + +#define XTKBD_EMUL0     0xe0 +#define XTKBD_EMUL1     0xe1 +#define XTKBD_RELEASE   0x80 + + +/* + * Represents a keyboard device + */ +struct hv_kbd_dev { +	struct hv_device *hv_dev; +	struct serio *hv_serio; +	struct synth_kbd_protocol_request protocol_req; +	struct synth_kbd_protocol_response protocol_resp; +	/* Synchronize the request/response if needed */ +	struct completion wait_event; +	spinlock_t lock; /* protects 'started' field */ +	bool started; +}; + +static void hv_kbd_on_receive(struct hv_device *hv_dev, +			      struct synth_kbd_msg *msg, u32 msg_length) +{ +	struct hv_kbd_dev *kbd_dev = hv_get_drvdata(hv_dev); +	struct synth_kbd_keystroke *ks_msg; +	unsigned long flags; +	u32 msg_type = __le32_to_cpu(msg->header.type); +	u32 info; +	u16 scan_code; + +	switch (msg_type) { +	case SYNTH_KBD_PROTOCOL_RESPONSE: +		/* +		 * Validate the information provided by the host. +		 * If the host is giving us a bogus packet, +		 * drop the packet (hoping the problem +		 * goes away). +		 */ +		if (msg_length < sizeof(struct synth_kbd_protocol_response)) { +			dev_err(&hv_dev->device, +				"Illegal protocol response packet (len: %d)\n", +				msg_length); +			break; +		} + +		memcpy(&kbd_dev->protocol_resp, msg, +			sizeof(struct synth_kbd_protocol_response)); +		complete(&kbd_dev->wait_event); +		break; + +	case SYNTH_KBD_EVENT: +		/* +		 * Validate the information provided by the host. +		 * If the host is giving us a bogus packet, +		 * drop the packet (hoping the problem +		 * goes away). +		 */ +		if (msg_length < sizeof(struct  synth_kbd_keystroke)) { +			dev_err(&hv_dev->device, +				"Illegal keyboard event packet (len: %d)\n", +				msg_length); +			break; +		} + +		ks_msg = (struct synth_kbd_keystroke *)msg; +		info = __le32_to_cpu(ks_msg->info); + +		/* +		 * Inject the information through the serio interrupt. +		 */ +		spin_lock_irqsave(&kbd_dev->lock, flags); +		if (kbd_dev->started) { +			if (info & IS_E0) +				serio_interrupt(kbd_dev->hv_serio, +						XTKBD_EMUL0, 0); +			if (info & IS_E1) +				serio_interrupt(kbd_dev->hv_serio, +						XTKBD_EMUL1, 0); +			scan_code = __le16_to_cpu(ks_msg->make_code); +			if (info & IS_BREAK) +				scan_code |= XTKBD_RELEASE; + +			serio_interrupt(kbd_dev->hv_serio, scan_code, 0); +		} +		spin_unlock_irqrestore(&kbd_dev->lock, flags); +		break; + +	default: +		dev_err(&hv_dev->device, +			"unhandled message type %d\n", msg_type); +	} +} + +static void hv_kbd_handle_received_packet(struct hv_device *hv_dev, +					  struct vmpacket_descriptor *desc, +					  u32 bytes_recvd, +					  u64 req_id) +{ +	struct synth_kbd_msg *msg; +	u32 msg_sz; + +	switch (desc->type) { +	case VM_PKT_COMP: +		break; + +	case VM_PKT_DATA_INBAND: +		/* +		 * We have a packet that has "inband" data. The API used +		 * for retrieving the packet guarantees that the complete +		 * packet is read. So, minimally, we should be able to +		 * parse the payload header safely (assuming that the host +		 * can be trusted.  Trusting the host seems to be a +		 * reasonable assumption because in a virtualized +		 * environment there is not whole lot you can do if you +		 * don't trust the host. +		 * +		 * Nonetheless, let us validate if the host can be trusted +		 * (in a trivial way).  The interesting aspect of this +		 * validation is how do you recover if we discover that the +		 * host is not to be trusted? Simply dropping the packet, I +		 * don't think is an appropriate recovery.  In the interest +		 * of failing fast, it may be better to crash the guest. +		 * For now, I will just drop the packet! +		 */ + +		msg_sz = bytes_recvd - (desc->offset8 << 3); +		if (msg_sz <= sizeof(struct synth_kbd_msg_hdr)) { +			/* +			 * Drop the packet and hope +			 * the problem magically goes away. +			 */ +			dev_err(&hv_dev->device, +				"Illegal packet (type: %d, tid: %llx, size: %d)\n", +				desc->type, req_id, msg_sz); +			break; +		} + +		msg = (void *)desc + (desc->offset8 << 3); +		hv_kbd_on_receive(hv_dev, msg, msg_sz); +		break; + +	default: +		dev_err(&hv_dev->device, +			"unhandled packet type %d, tid %llx len %d\n", +			desc->type, req_id, bytes_recvd); +		break; +	} +} + +static void hv_kbd_on_channel_callback(void *context) +{ +	struct hv_device *hv_dev = context; +	void *buffer; +	int bufferlen = 0x100; /* Start with sensible size */ +	u32 bytes_recvd; +	u64 req_id; +	int error; + +	buffer = kmalloc(bufferlen, GFP_ATOMIC); +	if (!buffer) +		return; + +	while (1) { +		error = vmbus_recvpacket_raw(hv_dev->channel, buffer, bufferlen, +					     &bytes_recvd, &req_id); +		switch (error) { +		case 0: +			if (bytes_recvd == 0) { +				kfree(buffer); +				return; +			} + +			hv_kbd_handle_received_packet(hv_dev, buffer, +						      bytes_recvd, req_id); +			break; + +		case -ENOBUFS: +			kfree(buffer); +			/* Handle large packet */ +			bufferlen = bytes_recvd; +			buffer = kmalloc(bytes_recvd, GFP_ATOMIC); +			if (!buffer) +				return; +			break; +		} +	} +} + +static int hv_kbd_connect_to_vsp(struct hv_device *hv_dev) +{ +	struct hv_kbd_dev *kbd_dev = hv_get_drvdata(hv_dev); +	struct synth_kbd_protocol_request *request; +	struct synth_kbd_protocol_response *response; +	u32 proto_status; +	int error; + +	request = &kbd_dev->protocol_req; +	memset(request, 0, sizeof(struct synth_kbd_protocol_request)); +	request->header.type = __cpu_to_le32(SYNTH_KBD_PROTOCOL_REQUEST); +	request->version_requested.version = __cpu_to_le32(SYNTH_KBD_VERSION); + +	error = vmbus_sendpacket(hv_dev->channel, request, +				 sizeof(struct synth_kbd_protocol_request), +				 (unsigned long)request, +				 VM_PKT_DATA_INBAND, +				 VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); +	if (error) +		return error; + +	if (!wait_for_completion_timeout(&kbd_dev->wait_event, 10 * HZ)) +		return -ETIMEDOUT; + +	response = &kbd_dev->protocol_resp; +	proto_status = __le32_to_cpu(response->proto_status); +	if (!(proto_status & PROTOCOL_ACCEPTED)) { +		dev_err(&hv_dev->device, +			"synth_kbd protocol request failed (version %d)\n", +		        SYNTH_KBD_VERSION); +		return -ENODEV; +	} + +	return 0; +} + +static int hv_kbd_start(struct serio *serio) +{ +	struct hv_kbd_dev *kbd_dev = serio->port_data; +	unsigned long flags; + +	spin_lock_irqsave(&kbd_dev->lock, flags); +	kbd_dev->started = true; +	spin_unlock_irqrestore(&kbd_dev->lock, flags); + +	return 0; +} + +static void hv_kbd_stop(struct serio *serio) +{ +	struct hv_kbd_dev *kbd_dev = serio->port_data; +	unsigned long flags; + +	spin_lock_irqsave(&kbd_dev->lock, flags); +	kbd_dev->started = false; +	spin_unlock_irqrestore(&kbd_dev->lock, flags); +} + +static int hv_kbd_probe(struct hv_device *hv_dev, +			const struct hv_vmbus_device_id *dev_id) +{ +	struct hv_kbd_dev *kbd_dev; +	struct serio *hv_serio; +	int error; + +	kbd_dev = kzalloc(sizeof(struct hv_kbd_dev), GFP_KERNEL); +	hv_serio = kzalloc(sizeof(struct serio), GFP_KERNEL); +	if (!kbd_dev || !hv_serio) { +		error = -ENOMEM; +		goto err_free_mem; +	} + +	kbd_dev->hv_dev = hv_dev; +	kbd_dev->hv_serio = hv_serio; +	spin_lock_init(&kbd_dev->lock); +	init_completion(&kbd_dev->wait_event); +	hv_set_drvdata(hv_dev, kbd_dev); + +	hv_serio->dev.parent  = &hv_dev->device; +	hv_serio->id.type = SERIO_8042_XL; +	hv_serio->port_data = kbd_dev; +	strlcpy(hv_serio->name, dev_name(&hv_dev->device), +		sizeof(hv_serio->name)); +	strlcpy(hv_serio->phys, dev_name(&hv_dev->device), +		sizeof(hv_serio->phys)); + +	hv_serio->start = hv_kbd_start; +	hv_serio->stop = hv_kbd_stop; + +	error = vmbus_open(hv_dev->channel, +			   KBD_VSC_SEND_RING_BUFFER_SIZE, +			   KBD_VSC_RECV_RING_BUFFER_SIZE, +			   NULL, 0, +			   hv_kbd_on_channel_callback, +			   hv_dev); +	if (error) +		goto err_free_mem; + +	error = hv_kbd_connect_to_vsp(hv_dev); +	if (error) +		goto err_close_vmbus; + +	serio_register_port(kbd_dev->hv_serio); +	return 0; + +err_close_vmbus: +	vmbus_close(hv_dev->channel); +err_free_mem: +	kfree(hv_serio); +	kfree(kbd_dev); +	return error; +} + +static int hv_kbd_remove(struct hv_device *hv_dev) +{ +	struct hv_kbd_dev *kbd_dev = hv_get_drvdata(hv_dev); + +	serio_unregister_port(kbd_dev->hv_serio); +	vmbus_close(hv_dev->channel); +	kfree(kbd_dev); + +	hv_set_drvdata(hv_dev, NULL); + +	return 0; +} + +/* + * Keyboard GUID + * {f912ad6d-2b17-48ea-bd65-f927a61c7684} + */ +#define HV_KBD_GUID \ +	.guid = { \ +			0x6d, 0xad, 0x12, 0xf9, 0x17, 0x2b, 0xea, 0x48, \ +			0xbd, 0x65, 0xf9, 0x27, 0xa6, 0x1c, 0x76, 0x84 \ +	} + +static const struct hv_vmbus_device_id id_table[] = { +	/* Keyboard guid */ +	{ HV_KBD_GUID, }, +	{ }, +}; + +MODULE_DEVICE_TABLE(vmbus, id_table); + +static struct  hv_driver hv_kbd_drv = { +	.name = KBUILD_MODNAME, +	.id_table = id_table, +	.probe = hv_kbd_probe, +	.remove = hv_kbd_remove, +}; + +static int __init hv_kbd_init(void) +{ +	return vmbus_driver_register(&hv_kbd_drv); +} + +static void __exit hv_kbd_exit(void) +{ +	vmbus_driver_unregister(&hv_kbd_drv); +} + +MODULE_LICENSE("GPL"); +module_init(hv_kbd_init); +module_exit(hv_kbd_exit); diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 5f306f79da0..136b7b204f5 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -402,6 +402,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {  		},  	},  	{ +		/* Acer Aspire 5710 */ +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5710"), +		}, +	}, +	{  		/* Gericom Bellagio */  		.matches = {  			DMI_MATCH(DMI_SYS_VENDOR, "Gericom"), @@ -702,6 +709,17 @@ static int i8042_pnp_aux_irq;  static char i8042_pnp_kbd_name[32];  static char i8042_pnp_aux_name[32]; +static void i8042_pnp_id_to_string(struct pnp_id *id, char *dst, int dst_size) +{ +	strlcpy(dst, "PNP:", dst_size); + +	while (id) { +		strlcat(dst, " ", dst_size); +		strlcat(dst, id->id, dst_size); +		id = id->next; +	} +} +  static int i8042_pnp_kbd_probe(struct pnp_dev *dev, const struct pnp_device_id *did)  {  	if (pnp_port_valid(dev, 0) && pnp_port_len(dev, 0) == 1) @@ -718,6 +736,8 @@ static int i8042_pnp_kbd_probe(struct pnp_dev *dev, const struct pnp_device_id *  		strlcat(i8042_pnp_kbd_name, ":", sizeof(i8042_pnp_kbd_name));  		strlcat(i8042_pnp_kbd_name, pnp_dev_name(dev), sizeof(i8042_pnp_kbd_name));  	} +	i8042_pnp_id_to_string(dev->id, i8042_kbd_firmware_id, +			       sizeof(i8042_kbd_firmware_id));  	/* Keyboard ports are always supposed to be wakeup-enabled */  	device_set_wakeup_enable(&dev->dev, true); @@ -742,6 +762,8 @@ static int i8042_pnp_aux_probe(struct pnp_dev *dev, const struct pnp_device_id *  		strlcat(i8042_pnp_aux_name, ":", sizeof(i8042_pnp_aux_name));  		strlcat(i8042_pnp_aux_name, pnp_dev_name(dev), sizeof(i8042_pnp_aux_name));  	} +	i8042_pnp_id_to_string(dev->id, i8042_aux_firmware_id, +			       sizeof(i8042_aux_firmware_id));  	i8042_pnp_aux_devices++;  	return 0; @@ -765,6 +787,7 @@ static struct pnp_device_id pnp_kbd_devids[] = {  	{ .id = "CPQA0D7", .driver_data = 0 },  	{ .id = "", },  }; +MODULE_DEVICE_TABLE(pnp, pnp_kbd_devids);  static struct pnp_driver i8042_pnp_kbd_driver = {  	.name           = "i8042 kbd", @@ -786,6 +809,7 @@ static struct pnp_device_id pnp_aux_devids[] = {  	{ .id = "SYN0801", .driver_data = 0 },  	{ .id = "", },  }; +MODULE_DEVICE_TABLE(pnp, pnp_aux_devids);  static struct pnp_driver i8042_pnp_aux_driver = {  	.name           = "i8042 aux", diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 78e4de42efa..3807c3e971c 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -87,6 +87,8 @@ MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off");  #endif  static bool i8042_bypass_aux_irq_test; +static char i8042_kbd_firmware_id[128]; +static char i8042_aux_firmware_id[128];  #include "i8042.h" @@ -223,21 +225,26 @@ static int i8042_flush(void)  {  	unsigned long flags;  	unsigned char data, str; -	int i = 0; +	int count = 0; +	int retval = 0;  	spin_lock_irqsave(&i8042_lock, flags); -	while (((str = i8042_read_status()) & I8042_STR_OBF) && (i < I8042_BUFFER_SIZE)) { -		udelay(50); -		data = i8042_read_data(); -		i++; -		dbg("%02x <- i8042 (flush, %s)\n", -		    data, str & I8042_STR_AUXDATA ? "aux" : "kbd"); +	while ((str = i8042_read_status()) & I8042_STR_OBF) { +		if (count++ < I8042_BUFFER_SIZE) { +			udelay(50); +			data = i8042_read_data(); +			dbg("%02x <- i8042 (flush, %s)\n", +			    data, str & I8042_STR_AUXDATA ? "aux" : "kbd"); +		} else { +			retval = -EIO; +			break; +		}  	}  	spin_unlock_irqrestore(&i8042_lock, flags); -	return i; +	return retval;  }  /* @@ -849,7 +856,7 @@ static int __init i8042_check_aux(void)  static int i8042_controller_check(void)  { -	if (i8042_flush() == I8042_BUFFER_SIZE) { +	if (i8042_flush()) {  		pr_err("No controller found\n");  		return -ENODEV;  	} @@ -1031,7 +1038,7 @@ static void i8042_controller_reset(bool force_reset)  /*   * i8042_panic_blink() will turn the keyboard LEDs on or off and is called   * when kernel panics. Flashing LEDs is useful for users running X who may - * not see the console and will help distingushing panics from "real" + * not see the console and will help distinguishing panics from "real"   * lockups.   *   * Note that DELAY has a limit of 10ms so we will not get stuck here @@ -1213,6 +1220,8 @@ static int __init i8042_create_kbd_port(void)  	serio->dev.parent	= &i8042_platform_device->dev;  	strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name));  	strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys)); +	strlcpy(serio->firmware_id, i8042_kbd_firmware_id, +		sizeof(serio->firmware_id));  	port->serio = serio;  	port->irq = I8042_KBD_IRQ; @@ -1239,6 +1248,8 @@ static int __init i8042_create_aux_port(int idx)  	if (idx < 0) {  		strlcpy(serio->name, "i8042 AUX port", sizeof(serio->name));  		strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); +		strlcpy(serio->firmware_id, i8042_aux_firmware_id, +			sizeof(serio->firmware_id));  		serio->close = i8042_port_close;  	} else {  		snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx); diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index 07a8363f3c5..75516996db2 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -18,7 +18,6 @@  #include <linux/input.h>  #include <linux/serio.h>  #include <linux/i8042.h> -#include <linux/init.h>  #include <linux/libps2.h>  #define DRIVER_DESC	"PS/2 driver library" diff --git a/drivers/input/serio/olpc_apsp.c b/drivers/input/serio/olpc_apsp.c index 51b1d40cc28..d906f3ebc8c 100644 --- a/drivers/input/serio/olpc_apsp.c +++ b/drivers/input/serio/olpc_apsp.c @@ -16,7 +16,6 @@  #include <linux/module.h>  #include <linux/interrupt.h> -#include <linux/init.h>  #include <linux/serio.h>  #include <linux/err.h>  #include <linux/platform_device.h> @@ -263,7 +262,7 @@ static int olpc_apsp_remove(struct platform_device *pdev)  	return 0;  } -static struct of_device_id olpc_apsp_dt_ids[] = { +static const struct of_device_id olpc_apsp_dt_ids[] = {  	{ .compatible = "olpc,ap-sp", },  	{}  }; diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c index 76f83836fd5..e862c6ea9d9 100644 --- a/drivers/input/serio/pcips2.c +++ b/drivers/input/serio/pcips2.c @@ -16,7 +16,6 @@  #include <linux/input.h>  #include <linux/pci.h>  #include <linux/slab.h> -#include <linux/init.h>  #include <linux/serio.h>  #include <linux/delay.h>  #include <asm/io.h> @@ -181,7 +180,6 @@ static void pcips2_remove(struct pci_dev *dev)  	struct pcips2_data *ps2if = pci_get_drvdata(dev);  	serio_unregister_port(ps2if->io); -	pci_set_drvdata(dev, NULL);  	kfree(ps2if);  	pci_release_regions(dev);  	pci_disable_device(dev); diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c index 7a65a1bc522..594256c3855 100644 --- a/drivers/input/serio/q40kbd.c +++ b/drivers/input/serio/q40kbd.c @@ -30,7 +30,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/serio.h>  #include <linux/interrupt.h>  #include <linux/err.h> diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c index 567566ae0da..e462e7791bb 100644 --- a/drivers/input/serio/rpckbd.c +++ b/drivers/input/serio/rpckbd.c @@ -29,7 +29,6 @@  #include <linux/module.h>  #include <linux/interrupt.h> -#include <linux/init.h>  #include <linux/serio.h>  #include <linux/err.h>  #include <linux/platform_device.h> diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 2b56855c2c7..b29134de983 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -365,7 +365,7 @@ static ssize_t serio_show_description(struct device *dev, struct device_attribut  	return sprintf(buf, "%s\n", serio->name);  } -static ssize_t serio_show_modalias(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)  {  	struct serio *serio = to_serio_port(dev); @@ -373,54 +373,31 @@ static ssize_t serio_show_modalias(struct device *dev, struct device_attribute *  			serio->id.type, serio->id.proto, serio->id.id, serio->id.extra);  } -static ssize_t serio_show_id_type(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t type_show(struct device *dev, struct device_attribute *attr, char *buf)  {  	struct serio *serio = to_serio_port(dev);  	return sprintf(buf, "%02x\n", serio->id.type);  } -static ssize_t serio_show_id_proto(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t proto_show(struct device *dev, struct device_attribute *attr, char *buf)  {  	struct serio *serio = to_serio_port(dev);  	return sprintf(buf, "%02x\n", serio->id.proto);  } -static ssize_t serio_show_id_id(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf)  {  	struct serio *serio = to_serio_port(dev);  	return sprintf(buf, "%02x\n", serio->id.id);  } -static ssize_t serio_show_id_extra(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t extra_show(struct device *dev, struct device_attribute *attr, char *buf)  {  	struct serio *serio = to_serio_port(dev);  	return sprintf(buf, "%02x\n", serio->id.extra);  } -static DEVICE_ATTR(type, S_IRUGO, serio_show_id_type, NULL); -static DEVICE_ATTR(proto, S_IRUGO, serio_show_id_proto, NULL); -static DEVICE_ATTR(id, S_IRUGO, serio_show_id_id, NULL); -static DEVICE_ATTR(extra, S_IRUGO, serio_show_id_extra, NULL); - -static struct attribute *serio_device_id_attrs[] = { -	&dev_attr_type.attr, -	&dev_attr_proto.attr, -	&dev_attr_id.attr, -	&dev_attr_extra.attr, -	NULL -}; - -static struct attribute_group serio_id_attr_group = { -	.name	= "id", -	.attrs	= serio_device_id_attrs, -}; - -static const struct attribute_group *serio_device_attr_groups[] = { -	&serio_id_attr_group, -	NULL -}; - -static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t drvctl_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)  {  	struct serio *serio = to_serio_port(dev);  	struct device_driver *drv; @@ -474,14 +451,55 @@ static ssize_t serio_set_bind_mode(struct device *dev, struct device_attribute *  	return retval;  } -static struct device_attribute serio_device_attrs[] = { -	__ATTR(description, S_IRUGO, serio_show_description, NULL), -	__ATTR(modalias, S_IRUGO, serio_show_modalias, NULL), -	__ATTR(drvctl, S_IWUSR, NULL, serio_rebind_driver), -	__ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode), -	__ATTR_NULL +static ssize_t firmware_id_show(struct device *dev, struct device_attribute *attr, char *buf) +{ +	struct serio *serio = to_serio_port(dev); + +	return sprintf(buf, "%s\n", serio->firmware_id); +} + +static DEVICE_ATTR_RO(type); +static DEVICE_ATTR_RO(proto); +static DEVICE_ATTR_RO(id); +static DEVICE_ATTR_RO(extra); + +static struct attribute *serio_device_id_attrs[] = { +	&dev_attr_type.attr, +	&dev_attr_proto.attr, +	&dev_attr_id.attr, +	&dev_attr_extra.attr, +	NULL  }; +static struct attribute_group serio_id_attr_group = { +	.name	= "id", +	.attrs	= serio_device_id_attrs, +}; + +static DEVICE_ATTR_RO(modalias); +static DEVICE_ATTR_WO(drvctl); +static DEVICE_ATTR(description, S_IRUGO, serio_show_description, NULL); +static DEVICE_ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode); +static DEVICE_ATTR_RO(firmware_id); + +static struct attribute *serio_device_attrs[] = { +	&dev_attr_modalias.attr, +	&dev_attr_description.attr, +	&dev_attr_drvctl.attr, +	&dev_attr_bind_mode.attr, +	&dev_attr_firmware_id.attr, +	NULL +}; + +static struct attribute_group serio_device_attr_group = { +	.attrs	= serio_device_attrs, +}; + +static const struct attribute_group *serio_device_attr_groups[] = { +	&serio_id_attr_group, +	&serio_device_attr_group, +	NULL +};  static void serio_release_port(struct device *dev)  { @@ -912,9 +930,14 @@ static int serio_uevent(struct device *dev, struct kobj_uevent_env *env)  	SERIO_ADD_UEVENT_VAR("SERIO_PROTO=%02x", serio->id.proto);  	SERIO_ADD_UEVENT_VAR("SERIO_ID=%02x", serio->id.id);  	SERIO_ADD_UEVENT_VAR("SERIO_EXTRA=%02x", serio->id.extra); +  	SERIO_ADD_UEVENT_VAR("MODALIAS=serio:ty%02Xpr%02Xid%02Xex%02X",  				serio->id.type, serio->id.proto, serio->id.id, serio->id.extra); +	if (serio->firmware_id[0]) +		SERIO_ADD_UEVENT_VAR("SERIO_FIRMWARE_ID=%s", +				     serio->firmware_id); +  	return 0;  }  #undef SERIO_ADD_UEVENT_VAR @@ -996,7 +1019,6 @@ EXPORT_SYMBOL(serio_interrupt);  static struct bus_type serio_bus = {  	.name		= "serio", -	.dev_attrs	= serio_device_attrs,  	.drv_groups	= serio_driver_groups,  	.match		= serio_bus_match,  	.uevent		= serio_uevent, diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index 59df2e7317a..c9a02fe5757 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -15,7 +15,6 @@  #include <linux/poll.h>  #include <linux/module.h>  #include <linux/serio.h> -#include <linux/init.h>  #include <linux/major.h>  #include <linux/device.h>  #include <linux/miscdevice.h> diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 8755f5f3ad3..0cb7ef59071 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -124,7 +124,7 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c  {  	struct serport *serport = (struct serport*) tty->disc_data;  	unsigned long flags; -	unsigned int ch_flags; +	unsigned int ch_flags = 0;  	int i;  	spin_lock_irqsave(&serport->lock, flags); @@ -133,18 +133,20 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c  		goto out;  	for (i = 0; i < count; i++) { -		switch (fp[i]) { -		case TTY_FRAME: -			ch_flags = SERIO_FRAME; -			break; - -		case TTY_PARITY: -			ch_flags = SERIO_PARITY; -			break; - -		default: -			ch_flags = 0; -			break; +		if (fp) { +			switch (fp[i]) { +			case TTY_FRAME: +				ch_flags = SERIO_FRAME; +				break; + +			case TTY_PARITY: +				ch_flags = SERIO_PARITY; +				break; + +			default: +				ch_flags = 0; +				break; +			}  		}  		serio_interrupt(serport->serio, cp[i], ch_flags); diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c index 4b7662a17ae..e6cf52ebad8 100644 --- a/drivers/input/serio/xilinx_ps2.c +++ b/drivers/input/serio/xilinx_ps2.c @@ -20,11 +20,11 @@  #include <linux/interrupt.h>  #include <linux/errno.h>  #include <linux/slab.h> -#include <linux/init.h>  #include <linux/list.h>  #include <linux/io.h>  #include <linux/of_address.h>  #include <linux/of_device.h> +#include <linux/of_irq.h>  #include <linux/of_platform.h>  #define DRIVER_NAME		"xilinx_ps2" @@ -235,12 +235,12 @@ static void sxps2_close(struct serio *pserio)   */  static int xps2_of_probe(struct platform_device *ofdev)  { -	struct resource r_irq; /* Interrupt resources */  	struct resource r_mem; /* IO mem resources */  	struct xps2data *drvdata;  	struct serio *serio;  	struct device *dev = &ofdev->dev;  	resource_size_t remap_size, phys_addr; +	unsigned int irq;  	int error;  	dev_info(dev, "Device Tree Probing \'%s\'\n", @@ -254,7 +254,8 @@ static int xps2_of_probe(struct platform_device *ofdev)  	}  	/* Get IRQ for the device */ -	if (!of_irq_to_resource(ofdev->dev.of_node, 0, &r_irq)) { +	irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); +	if (!irq) {  		dev_err(dev, "no IRQ found\n");  		return -ENODEV;  	} @@ -267,7 +268,7 @@ static int xps2_of_probe(struct platform_device *ofdev)  	}  	spin_lock_init(&drvdata->lock); -	drvdata->irq = r_irq.start; +	drvdata->irq = irq;  	drvdata->serio = serio;  	drvdata->dev = dev; diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c index a70aa555bbf..e7409c45bdd 100644 --- a/drivers/input/sparse-keymap.c +++ b/drivers/input/sparse-keymap.c @@ -236,7 +236,7 @@ EXPORT_SYMBOL(sparse_keymap_setup);   * in an input device that was set up by sparse_keymap_setup().   * NOTE: It is safe to cal this function while input device is   * still registered (however the drivers should care not to try to - * use freed keymap and thus have to shut off interrups/polling + * use freed keymap and thus have to shut off interrupts/polling   * before freeing the keymap).   */  void sparse_keymap_free(struct input_dev *dev) diff --git a/drivers/input/tablet/acecad.c b/drivers/input/tablet/acecad.c index e062ec899ca..889f6b77e8c 100644 --- a/drivers/input/tablet/acecad.c +++ b/drivers/input/tablet/acecad.c @@ -28,7 +28,6 @@  #include <linux/kernel.h>  #include <linux/slab.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/usb/input.h>  /* diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c index ee83c3904ee..e7f966da6ef 100644 --- a/drivers/input/tablet/aiptek.c +++ b/drivers/input/tablet/aiptek.c @@ -74,7 +74,6 @@  #include <linux/kernel.h>  #include <linux/slab.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/usb/input.h>  #include <asm/uaccess.h>  #include <asm/unaligned.h> diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c index 29e01ab6859..858045694e9 100644 --- a/drivers/input/tablet/gtco.c +++ b/drivers/input/tablet/gtco.c @@ -53,7 +53,6 @@ Scott Hill shill@gtcocalcomp.com  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/usb.h> @@ -849,7 +848,7 @@ static int gtco_probe(struct usb_interface *usbinterface,  	gtco->inputdevice = input_dev;  	/* Save interface information */ -	gtco->usbdev = usb_get_dev(interface_to_usbdev(usbinterface)); +	gtco->usbdev = interface_to_usbdev(usbinterface);  	gtco->intf = usbinterface;  	/* Allocate some data for incoming reports */ diff --git a/drivers/input/tablet/hanwang.c b/drivers/input/tablet/hanwang.c index 5cc04124995..cd852059b99 100644 --- a/drivers/input/tablet/hanwang.c +++ b/drivers/input/tablet/hanwang.c @@ -26,7 +26,6 @@  #include <linux/kernel.h>  #include <linux/slab.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/usb/input.h>  #define DRIVER_AUTHOR   "Xing Wei <weixing@hanwang.com.cn>" diff --git a/drivers/input/tablet/kbtab.c b/drivers/input/tablet/kbtab.c index 3fba74b9b60..d2ac7c2b5b8 100644 --- a/drivers/input/tablet/kbtab.c +++ b/drivers/input/tablet/kbtab.c @@ -1,7 +1,6 @@  #include <linux/kernel.h>  #include <linux/slab.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/usb/input.h>  #include <asm/unaligned.h> diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h index b79d45198d8..9ebf0ed3b3b 100644 --- a/drivers/input/tablet/wacom.h +++ b/drivers/input/tablet/wacom.h @@ -86,7 +86,6 @@  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/mod_devicetable.h> -#include <linux/init.h>  #include <linux/usb/input.h>  #include <linux/power_supply.h>  #include <asm/unaligned.h> diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index 79b69ea47f7..2c613cd41dd 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c @@ -22,23 +22,18 @@  #define HID_USAGE_PAGE_DIGITIZER	0x0d  #define HID_USAGE_PAGE_DESKTOP		0x01  #define HID_USAGE			0x09 -#define HID_USAGE_X			0x30 -#define HID_USAGE_Y			0x31 -#define HID_USAGE_X_TILT		0x3d -#define HID_USAGE_Y_TILT		0x3e -#define HID_USAGE_FINGER		0x22 -#define HID_USAGE_STYLUS		0x20 -#define HID_USAGE_CONTACTMAX		0x55 +#define HID_USAGE_X			((HID_USAGE_PAGE_DESKTOP << 16) | 0x30) +#define HID_USAGE_Y			((HID_USAGE_PAGE_DESKTOP << 16) | 0x31) +#define HID_USAGE_PRESSURE		((HID_USAGE_PAGE_DIGITIZER << 16) | 0x30) +#define HID_USAGE_X_TILT		((HID_USAGE_PAGE_DIGITIZER << 16) | 0x3d) +#define HID_USAGE_Y_TILT		((HID_USAGE_PAGE_DIGITIZER << 16) | 0x3e) +#define HID_USAGE_FINGER		((HID_USAGE_PAGE_DIGITIZER << 16) | 0x22) +#define HID_USAGE_STYLUS		((HID_USAGE_PAGE_DIGITIZER << 16) | 0x20) +#define HID_USAGE_CONTACTMAX		((HID_USAGE_PAGE_DIGITIZER << 16) | 0x55)  #define HID_COLLECTION			0xa1  #define HID_COLLECTION_LOGICAL		0x02  #define HID_COLLECTION_END		0xc0 -enum { -	WCM_UNDEFINED = 0, -	WCM_DESKTOP, -	WCM_DIGITIZER, -}; -  struct hid_descriptor {  	struct usb_descriptor_header header;  	__le16   bcdHID; @@ -304,8 +299,8 @@ static int wacom_parse_hid(struct usb_interface *intf,  	struct usb_device *dev = interface_to_usbdev(intf);  	char limit = 0;  	/* result has to be defined as int for some devices */ -	int result = 0; -	int i = 0, usage = WCM_UNDEFINED, finger = 0, pen = 0; +	int result = 0, touch_max = 0; +	int i = 0, page = 0, finger = 0, pen = 0;  	unsigned char *report;  	report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL); @@ -332,133 +327,140 @@ static int wacom_parse_hid(struct usb_interface *intf,  		switch (report[i]) {  		case HID_USAGE_PAGE: -			switch (report[i + 1]) { -			case HID_USAGE_PAGE_DIGITIZER: -				usage = WCM_DIGITIZER; -				i++; -				break; - -			case HID_USAGE_PAGE_DESKTOP: -				usage = WCM_DESKTOP; -				i++; -				break; -			} +			page = report[i + 1]; +			i++;  			break;  		case HID_USAGE: -			switch (report[i + 1]) { +			switch (page << 16 | report[i + 1]) {  			case HID_USAGE_X: -				if (usage == WCM_DESKTOP) { -					if (finger) { -						features->device_type = BTN_TOOL_FINGER; - -						switch (features->type) { -						case TABLETPC2FG: -							features->pktlen = WACOM_PKGLEN_TPC2FG; -							break; - -						case MTSCREEN: -						case WACOM_24HDT: -							features->pktlen = WACOM_PKGLEN_MTOUCH; -							break; - -						case MTTPC: -							features->pktlen = WACOM_PKGLEN_MTTPC; -							break; - -						case BAMBOO_PT: -							features->pktlen = WACOM_PKGLEN_BBTOUCH; -							break; - -						default: -							features->pktlen = WACOM_PKGLEN_GRAPHIRE; -							break; -						} - -						switch (features->type) { -						case BAMBOO_PT: -							features->x_phy = -								get_unaligned_le16(&report[i + 5]); -							features->x_max = -								get_unaligned_le16(&report[i + 8]); -							i += 15; -							break; - -						case WACOM_24HDT: -							features->x_max = -								get_unaligned_le16(&report[i + 3]); -							features->x_phy = -								get_unaligned_le16(&report[i + 8]); -							features->unit = report[i - 1]; -							features->unitExpo = report[i - 3]; -							i += 12; -							break; - -						default: -							features->x_max = -								get_unaligned_le16(&report[i + 3]); -							features->x_phy = -								get_unaligned_le16(&report[i + 6]); -							features->unit = report[i + 9]; -							features->unitExpo = report[i + 11]; -							i += 12; -							break; -						} -					} else if (pen) { -						/* penabled only accepts exact bytes of data */ -						if (features->type >= TABLETPC) -							features->pktlen = WACOM_PKGLEN_GRAPHIRE; -						features->device_type = BTN_TOOL_PEN; +				if (finger) { +					features->device_type = BTN_TOOL_FINGER; +					/* touch device at least supports one touch point */ +					touch_max = 1; +					switch (features->type) { +					case TABLETPC2FG: +						features->pktlen = WACOM_PKGLEN_TPC2FG; +						break; + +					case MTSCREEN: +					case WACOM_24HDT: +						features->pktlen = WACOM_PKGLEN_MTOUCH; +						break; + +					case MTTPC: +					case MTTPC_B: +						features->pktlen = WACOM_PKGLEN_MTTPC; +						break; + +					case BAMBOO_PT: +						features->pktlen = WACOM_PKGLEN_BBTOUCH; +						break; + +					default: +						features->pktlen = WACOM_PKGLEN_GRAPHIRE; +						break; +					} + +					switch (features->type) { +					case BAMBOO_PT: +						features->x_phy = +							get_unaligned_le16(&report[i + 5]); +						features->x_max = +							get_unaligned_le16(&report[i + 8]); +						i += 15; +						break; + +					case WACOM_24HDT:  						features->x_max =  							get_unaligned_le16(&report[i + 3]); -						i += 4; +						features->x_phy = +							get_unaligned_le16(&report[i + 8]); +						features->unit = report[i - 1]; +						features->unitExpo = report[i - 3]; +						i += 12; +						break; + +					case MTTPC_B: +						features->x_max = +							get_unaligned_le16(&report[i + 3]); +						features->x_phy = +							get_unaligned_le16(&report[i + 6]); +						features->unit = report[i - 5]; +						features->unitExpo = report[i - 3]; +						i += 9; +						break; + +					default: +						features->x_max = +							get_unaligned_le16(&report[i + 3]); +						features->x_phy = +							get_unaligned_le16(&report[i + 6]); +						features->unit = report[i + 9]; +						features->unitExpo = report[i + 11]; +						i += 12; +						break;  					} +				} else if (pen) { +					/* penabled only accepts exact bytes of data */ +					if (features->type >= TABLETPC) +						features->pktlen = WACOM_PKGLEN_GRAPHIRE; +					features->device_type = BTN_TOOL_PEN; +					features->x_max = +						get_unaligned_le16(&report[i + 3]); +					i += 4;  				}  				break;  			case HID_USAGE_Y: -				if (usage == WCM_DESKTOP) { -					if (finger) { -						switch (features->type) { -						case TABLETPC2FG: -						case MTSCREEN: -						case MTTPC: -							features->y_max = -								get_unaligned_le16(&report[i + 3]); -							features->y_phy = -								get_unaligned_le16(&report[i + 6]); -							i += 7; -							break; - -						case WACOM_24HDT: -							features->y_max = -								get_unaligned_le16(&report[i + 3]); -							features->y_phy = -								get_unaligned_le16(&report[i - 2]); -							i += 7; -							break; - -						case BAMBOO_PT: -							features->y_phy = -								get_unaligned_le16(&report[i + 3]); -							features->y_max = -								get_unaligned_le16(&report[i + 6]); -							i += 12; -							break; - -						default: -							features->y_max = -								features->x_max; -							features->y_phy = -								get_unaligned_le16(&report[i + 3]); -							i += 4; -							break; -						} -					} else if (pen) { +				if (finger) { +					switch (features->type) { +					case TABLETPC2FG: +					case MTSCREEN: +					case MTTPC: +						features->y_max = +							get_unaligned_le16(&report[i + 3]); +						features->y_phy = +							get_unaligned_le16(&report[i + 6]); +						i += 7; +						break; + +					case WACOM_24HDT: +						features->y_max = +							get_unaligned_le16(&report[i + 3]); +						features->y_phy = +							get_unaligned_le16(&report[i - 2]); +						i += 7; +						break; + +					case BAMBOO_PT: +						features->y_phy = +							get_unaligned_le16(&report[i + 3]); +						features->y_max = +							get_unaligned_le16(&report[i + 6]); +						i += 12; +						break; + +					case MTTPC_B: +						features->y_max = +							get_unaligned_le16(&report[i + 3]); +						features->y_phy = +							get_unaligned_le16(&report[i + 6]); +						i += 9; +						break; + +					default:  						features->y_max = +							features->x_max; +						features->y_phy =  							get_unaligned_le16(&report[i + 3]);  						i += 4; +						break;  					} +				} else if (pen) { +					features->y_max = +						get_unaligned_le16(&report[i + 3]); +					i += 4;  				}  				break; @@ -483,12 +485,20 @@ static int wacom_parse_hid(struct usb_interface *intf,  					wacom_retrieve_report_data(intf, features);  				i++;  				break; + +			case HID_USAGE_PRESSURE: +				if (pen) { +					features->pressure_max = +						get_unaligned_le16(&report[i + 3]); +					i += 4; +				} +				break;  			}  			break;  		case HID_COLLECTION_END:  			/* reset UsagePage and Finger */ -			finger = usage = 0; +			finger = page = 0;  			break;  		case HID_COLLECTION: @@ -504,6 +514,8 @@ static int wacom_parse_hid(struct usb_interface *intf,  	}   out: +	if (!features->touch_max && touch_max) +		features->touch_max = touch_max;  	result = 0;  	kfree(report);  	return result; @@ -524,9 +536,6 @@ static int wacom_set_device_mode(struct usb_interface *intf, int report_id, int  		error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT,  		                         report_id, rep_data, length, 1); -		if (error >= 0) -			error = wacom_get_report(intf, WAC_HID_FEATURE_REPORT, -			                         report_id, rep_data, length, 1);  	} while ((error < 0 || rep_data[1] != mode) && limit++ < WAC_MSG_RETRIES);  	kfree(rep_data); @@ -548,7 +557,7 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat  			/* MT Tablet PC touch */  			return wacom_set_device_mode(intf, 3, 4, 4);  		} -		else if (features->type == WACOM_24HDT) { +		else if (features->type == WACOM_24HDT || features->type == CINTIQ_HYBRID) {  			return wacom_set_device_mode(intf, 18, 3, 2);  		}  	} else if (features->device_type == BTN_TOOL_PEN) { @@ -719,7 +728,7 @@ static int wacom_led_control(struct wacom *wacom)  		return -ENOMEM;  	if (wacom->wacom_wac.features.type >= INTUOS5S && -	    wacom->wacom_wac.features.type <= INTUOS5L)	{ +	    wacom->wacom_wac.features.type <= INTUOSPL) {  		/*  		 * Touch Ring and crop mark LED luminance may take on  		 * one of four values: @@ -981,14 +990,20 @@ static int wacom_initialize_leds(struct wacom *wacom)  	case INTUOS5S:  	case INTUOS5:  	case INTUOS5L: -		wacom->led.select[0] = 0; -		wacom->led.select[1] = 0; -		wacom->led.llv = 32; -		wacom->led.hlv = 0; -		wacom->led.img_lum = 0; - -		error = sysfs_create_group(&wacom->intf->dev.kobj, -					   &intuos5_led_attr_group); +	case INTUOSPS: +	case INTUOSPM: +	case INTUOSPL: +		if (wacom->wacom_wac.features.device_type == BTN_TOOL_PEN) { +			wacom->led.select[0] = 0; +			wacom->led.select[1] = 0; +			wacom->led.llv = 32; +			wacom->led.hlv = 0; +			wacom->led.img_lum = 0; + +			error = sysfs_create_group(&wacom->intf->dev.kobj, +						  &intuos5_led_attr_group); +		} else +			return 0;  		break;  	default: @@ -1024,13 +1039,18 @@ static void wacom_destroy_leds(struct wacom *wacom)  	case INTUOS5S:  	case INTUOS5:  	case INTUOS5L: -		sysfs_remove_group(&wacom->intf->dev.kobj, -				   &intuos5_led_attr_group); +	case INTUOSPS: +	case INTUOSPM: +	case INTUOSPL: +		if (wacom->wacom_wac.features.device_type == BTN_TOOL_PEN) +			sysfs_remove_group(&wacom->intf->dev.kobj, +					   &intuos5_led_attr_group);  		break;  	}  }  static enum power_supply_property wacom_battery_props[] = { +	POWER_SUPPLY_PROP_SCOPE,  	POWER_SUPPLY_PROP_CAPACITY  }; @@ -1042,6 +1062,9 @@ static int wacom_battery_get_property(struct power_supply *psy,  	int ret = 0;  	switch (psp) { +		case POWER_SUPPLY_PROP_SCOPE: +			val->intval = POWER_SUPPLY_SCOPE_DEVICE; +			break;  		case POWER_SUPPLY_PROP_CAPACITY:  			val->intval =  				wacom->wacom_wac.battery_capacity * 100 / 31; @@ -1181,34 +1204,54 @@ static void wacom_wireless_work(struct work_struct *work)  		wacom_wac1->features =  			*((struct wacom_features *)id->driver_info);  		wacom_wac1->features.device_type = BTN_TOOL_PEN; +		snprintf(wacom_wac1->name, WACOM_NAME_MAX, "%s (WL) Pen", +			 wacom_wac1->features.name); +		wacom_wac1->shared->touch_max = wacom_wac1->features.touch_max; +		wacom_wac1->shared->type = wacom_wac1->features.type;  		error = wacom_register_input(wacom1);  		if (error) -			goto fail1; +			goto fail;  		/* Touch interface */ -		wacom_wac2->features = -			*((struct wacom_features *)id->driver_info); -		wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3; -		wacom_wac2->features.device_type = BTN_TOOL_FINGER; -		wacom_wac2->features.x_max = wacom_wac2->features.y_max = 4096; -		error = wacom_register_input(wacom2); -		if (error) -			goto fail2; +		if (wacom_wac1->features.touch_max || +		    wacom_wac1->features.type == INTUOSHT) { +			wacom_wac2->features = +				*((struct wacom_features *)id->driver_info); +			wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3; +			wacom_wac2->features.device_type = BTN_TOOL_FINGER; +			wacom_wac2->features.x_max = wacom_wac2->features.y_max = 4096; +			if (wacom_wac2->features.touch_max) +				snprintf(wacom_wac2->name, WACOM_NAME_MAX, +					 "%s (WL) Finger",wacom_wac2->features.name); +			else +				snprintf(wacom_wac2->name, WACOM_NAME_MAX, +					 "%s (WL) Pad",wacom_wac2->features.name); +			error = wacom_register_input(wacom2); +			if (error) +				goto fail; + +			if (wacom_wac1->features.type == INTUOSHT && +			    wacom_wac1->features.touch_max) +				wacom_wac->shared->touch_input = wacom_wac2->input; +		}  		error = wacom_initialize_battery(wacom);  		if (error) -			goto fail3; +			goto fail;  	}  	return; -fail3: -	input_unregister_device(wacom_wac2->input); -	wacom_wac2->input = NULL; -fail2: -	input_unregister_device(wacom_wac1->input); -	wacom_wac1->input = NULL; -fail1: +fail: +	if (wacom_wac2->input) { +		input_unregister_device(wacom_wac2->input); +		wacom_wac2->input = NULL; +	} + +	if (wacom_wac1->input) { +		input_unregister_device(wacom_wac1->input); +		wacom_wac1->input = NULL; +	}  	return;  } @@ -1298,7 +1341,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i  	 * HID descriptor. If this is the touch interface (wMaxPacketSize  	 * of WACOM_PKGLEN_BBTOUCH3), override the table values.  	 */ -	if (features->type >= INTUOS5S && features->type <= INTUOS5L) { +	if (features->type >= INTUOS5S && features->type <= INTUOSHT) {  		if (endpoint->wMaxPacketSize == WACOM_PKGLEN_BBTOUCH3) {  			features->device_type = BTN_TOOL_FINGER;  			features->pktlen = WACOM_PKGLEN_BBTOUCH3; @@ -1325,10 +1368,12 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i  		struct usb_device *other_dev;  		/* Append the device type to the name */ -		strlcat(wacom_wac->name, -			features->device_type == BTN_TOOL_PEN ? -				" Pen" : " Finger", -			sizeof(wacom_wac->name)); +		if (features->device_type != BTN_TOOL_FINGER) +			strlcat(wacom_wac->name, " Pen", WACOM_NAME_MAX); +		else if (features->touch_max) +			strlcat(wacom_wac->name, " Finger", WACOM_NAME_MAX); +		else +			strlcat(wacom_wac->name, " Pad", WACOM_NAME_MAX);  		other_dev = wacom_get_sibling(dev, features->oVid, features->oPid);  		if (other_dev == NULL || wacom_get_usbdev_data(other_dev) == NULL) @@ -1367,6 +1412,11 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i  		}  	} +	if (wacom_wac->features.type == INTUOSHT && wacom_wac->features.touch_max) { +		if (wacom_wac->features.device_type == BTN_TOOL_FINGER) +			wacom_wac->shared->touch_input = wacom_wac->input; +	} +  	return 0;   fail5: wacom_destroy_leds(wacom); diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index b2aa503c16b..e73cf2c71f3 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -178,10 +178,9 @@ static int wacom_ptu_irq(struct wacom_wac *wacom)  static int wacom_dtu_irq(struct wacom_wac *wacom)  { -	struct wacom_features *features = &wacom->features; -	char *data = wacom->data; +	unsigned char *data = wacom->data;  	struct input_dev *input = wacom->input; -	int prox = data[1] & 0x20, pressure; +	int prox = data[1] & 0x20;  	dev_dbg(input->dev.parent,  		"%s: received report #%d", __func__, data[0]); @@ -198,10 +197,7 @@ static int wacom_dtu_irq(struct wacom_wac *wacom)  	input_report_key(input, BTN_STYLUS2, data[1] & 0x10);  	input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));  	input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4])); -	pressure = ((data[7] & 0x01) << 8) | data[6]; -	if (pressure < 0) -		pressure = features->pressure_max + pressure + 1; -	input_report_abs(input, ABS_PRESSURE, pressure); +	input_report_abs(input, ABS_PRESSURE, ((data[7] & 0x01) << 8) | data[6]);  	input_report_key(input, BTN_TOUCH, data[1] & 0x05);  	if (!prox) /* out-prox */  		wacom->id[0] = 0; @@ -210,6 +206,62 @@ static int wacom_dtu_irq(struct wacom_wac *wacom)  	return 1;  } +static int wacom_dtus_irq(struct wacom_wac *wacom) +{ +	char *data = wacom->data; +	struct input_dev *input = wacom->input; +	unsigned short prox, pressure = 0; + +	if (data[0] != WACOM_REPORT_DTUS && data[0] != WACOM_REPORT_DTUSPAD) { +		dev_dbg(input->dev.parent, +			"%s: received unknown report #%d", __func__, data[0]); +		return 0; +	} else if (data[0] == WACOM_REPORT_DTUSPAD) { +		input_report_key(input, BTN_0, (data[1] & 0x01)); +		input_report_key(input, BTN_1, (data[1] & 0x02)); +		input_report_key(input, BTN_2, (data[1] & 0x04)); +		input_report_key(input, BTN_3, (data[1] & 0x08)); +		input_report_abs(input, ABS_MISC, +				 data[1] & 0x0f ? PAD_DEVICE_ID : 0); +		/* +		 * Serial number is required when expresskeys are +		 * reported through pen interface. +		 */ +		input_event(input, EV_MSC, MSC_SERIAL, 0xf0); +		return 1; +	} else { +		prox = data[1] & 0x80; +		if (prox) { +			switch ((data[1] >> 3) & 3) { +			case 1: /* Rubber */ +				wacom->tool[0] = BTN_TOOL_RUBBER; +				wacom->id[0] = ERASER_DEVICE_ID; +				break; + +			case 2: /* Pen */ +				wacom->tool[0] = BTN_TOOL_PEN; +				wacom->id[0] = STYLUS_DEVICE_ID; +				break; +			} +		} + +		input_report_key(input, BTN_STYLUS, data[1] & 0x20); +		input_report_key(input, BTN_STYLUS2, data[1] & 0x40); +		input_report_abs(input, ABS_X, get_unaligned_be16(&data[3])); +		input_report_abs(input, ABS_Y, get_unaligned_be16(&data[5])); +		pressure = ((data[1] & 0x03) << 8) | (data[2] & 0xff); +		input_report_abs(input, ABS_PRESSURE, pressure); +		input_report_key(input, BTN_TOUCH, pressure > 10); + +		if (!prox) /* out-prox */ +			wacom->id[0] = 0; +		input_report_key(input, wacom->tool[0], prox); +		input_report_abs(input, ABS_MISC, wacom->id[0]); +		input_event(input, EV_MSC, MSC_SERIAL, 1); +		return 1; +	} +} +  static int wacom_graphire_irq(struct wacom_wac *wacom)  {  	struct wacom_features *features = &wacom->features; @@ -331,7 +383,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)  	/* Enter report */  	if ((data[1] & 0xfc) == 0xc0) { -		if (features->quirks == WACOM_QUIRK_MULTI_INPUT) +		if (features->quirks & WACOM_QUIRK_MULTI_INPUT)  			wacom->shared->stylus_in_proximity = true;  		/* serial number of the tool */ @@ -427,9 +479,18 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)  			(features->type == WACOM_21UX2))  		return 1; +	/* Range Report */ +	if ((data[1] & 0xfe) == 0x20) { +		input_report_key(input, BTN_TOUCH, 0); +		input_report_abs(input, ABS_PRESSURE, 0); +		input_report_abs(input, ABS_DISTANCE, wacom->features.distance_max); +		if (features->quirks & WACOM_QUIRK_MULTI_INPUT) +			wacom->shared->stylus_in_proximity = true; +	} +  	/* Exit report */  	if ((data[1] & 0xfe) == 0x80) { -		if (features->quirks == WACOM_QUIRK_MULTI_INPUT) +		if (features->quirks & WACOM_QUIRK_MULTI_INPUT)  			wacom->shared->stylus_in_proximity = false;  		/* @@ -477,7 +538,7 @@ static void wacom_intuos_general(struct wacom_wac *wacom)  	/* general pen packet */  	if ((data[1] & 0xb8) == 0xa0) {  		t = (data[6] << 2) | ((data[7] >> 6) & 3); -		if (features->type >= INTUOS4S && features->type <= WACOM_24HD) { +		if (features->type >= INTUOS4S && features->type <= CINTIQ_HYBRID) {  			t = (t << 1) | (data[1] & 1);  		}  		input_report_abs(input, ABS_PRESSURE, t); @@ -621,14 +682,30 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)  			} else {  				input_report_abs(input, ABS_MISC, 0);  			} -		} else if (features->type >= INTUOS5S && features->type <= INTUOS5L) { +		} else if (features->type == CINTIQ_HYBRID) { +			/* +			 * Do not send hardware buttons under Android. They +			 * are already sent to the system through GPIO (and +			 * have different meaning). +			 */ +			input_report_key(input, BTN_1, (data[4] & 0x01)); +			input_report_key(input, BTN_2, (data[4] & 0x02)); +			input_report_key(input, BTN_3, (data[4] & 0x04)); +			input_report_key(input, BTN_4, (data[4] & 0x08)); + +			input_report_key(input, BTN_5, (data[4] & 0x10));  /* Right  */ +			input_report_key(input, BTN_6, (data[4] & 0x20));  /* Up     */ +			input_report_key(input, BTN_7, (data[4] & 0x40));  /* Left   */ +			input_report_key(input, BTN_8, (data[4] & 0x80));  /* Down   */ +			input_report_key(input, BTN_0, (data[3] & 0x01));  /* Center */ +		} else if (features->type >= INTUOS5S && features->type <= INTUOSPL) {  			int i;  			/* Touch ring mode switch has no capacitive sensor */  			input_report_key(input, BTN_0, (data[3] & 0x01));  			/* -			 * ExpressKeys on Intuos5 have a capacitive sensor in +			 * ExpressKeys on Intuos5/Intuos Pro have a capacitive sensor in  			 * addition to the mechanical switch. Switch data is  			 * stored in data[4], capacitive data in data[5].  			 */ @@ -716,7 +793,9 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)  	     features->type == INTUOS4 ||  	     features->type == INTUOS4S ||  	     features->type == INTUOS5 || -	     features->type == INTUOS5S)) { +	     features->type == INTUOS5S || +	     features->type == INTUOSPM || +	     features->type == INTUOSPS)) {  		return 0;  	} @@ -769,8 +848,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)  		} else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {  			/* I4 mouse */ -			if ((features->type >= INTUOS4S && features->type <= INTUOS4L) || -			    (features->type >= INTUOS5S && features->type <= INTUOS5L)) { +			if (features->type >= INTUOS4S && features->type <= INTUOSPL) {  				input_report_key(input, BTN_LEFT,   data[6] & 0x01);  				input_report_key(input, BTN_MIDDLE, data[6] & 0x02);  				input_report_key(input, BTN_RIGHT,  data[6] & 0x04); @@ -797,7 +875,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)  				}  			}  		} else if ((features->type < INTUOS3S || features->type == INTUOS3L || -				features->type == INTUOS4L || features->type == INTUOS5L) && +				features->type == INTUOS4L || features->type == INTUOS5L || +				features->type == INTUOSPL) &&  			   wacom->tool[idx] == BTN_TOOL_LENS) {  			/* Lens cursor packets */  			input_report_key(input, BTN_LEFT,   data[8] & 0x01); @@ -825,7 +904,7 @@ static int int_dist(int x1, int y1, int x2, int y2)  static int wacom_24hdt_irq(struct wacom_wac *wacom)  {  	struct input_dev *input = wacom->input; -	char *data = wacom->data; +	unsigned char *data = wacom->data;  	int i;  	int current_num_contacts = data[61];  	int contacts_to_send = 0; @@ -851,12 +930,12 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)  		input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);  		if (touch) { -			int t_x = le16_to_cpup((__le16 *)&data[offset + 2]); -			int c_x = le16_to_cpup((__le16 *)&data[offset + 4]); -			int t_y = le16_to_cpup((__le16 *)&data[offset + 6]); -			int c_y = le16_to_cpup((__le16 *)&data[offset + 8]); -			int w = le16_to_cpup((__le16 *)&data[offset + 10]); -			int h = le16_to_cpup((__le16 *)&data[offset + 12]); +			int t_x = get_unaligned_le16(&data[offset + 2]); +			int c_x = get_unaligned_le16(&data[offset + 4]); +			int t_y = get_unaligned_le16(&data[offset + 6]); +			int c_y = get_unaligned_le16(&data[offset + 8]); +			int w = get_unaligned_le16(&data[offset + 10]); +			int h = get_unaligned_le16(&data[offset + 12]);  			input_report_abs(input, ABS_MT_POSITION_X, t_x);  			input_report_abs(input, ABS_MT_POSITION_Y, t_y); @@ -878,14 +957,14 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)  static int wacom_mt_touch(struct wacom_wac *wacom)  {  	struct input_dev *input = wacom->input; -	char *data = wacom->data; +	unsigned char *data = wacom->data;  	int i;  	int current_num_contacts = data[2];  	int contacts_to_send = 0;  	int x_offset = 0;  	/* MTTPC does not support Height and Width */ -	if (wacom->features.type == MTTPC) +	if (wacom->features.type == MTTPC || wacom->features.type == MTTPC_B)  		x_offset = -4;  	/* @@ -901,7 +980,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom)  	for (i = 0; i < contacts_to_send; i++) {  		int offset = (WACOM_BYTES_PER_MT_PACKET + x_offset) * i + 3;  		bool touch = data[offset] & 0x1; -		int id = le16_to_cpup((__le16 *)&data[offset + 1]); +		int id = get_unaligned_le16(&data[offset + 1]);  		int slot = input_mt_get_slot_by_key(input, id);  		if (slot < 0) @@ -910,8 +989,8 @@ static int wacom_mt_touch(struct wacom_wac *wacom)  		input_mt_slot(input, slot);  		input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);  		if (touch) { -			int x = le16_to_cpup((__le16 *)&data[offset + x_offset + 7]); -			int y = le16_to_cpup((__le16 *)&data[offset + x_offset + 9]); +			int x = get_unaligned_le16(&data[offset + x_offset + 7]); +			int y = get_unaligned_le16(&data[offset + x_offset + 9]);  			input_report_abs(input, ABS_MT_POSITION_X, x);  			input_report_abs(input, ABS_MT_POSITION_Y, y);  		} @@ -957,7 +1036,7 @@ static int wacom_tpc_mt_touch(struct wacom_wac *wacom)  static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len)  { -	char *data = wacom->data; +	unsigned char *data = wacom->data;  	struct input_dev *input = wacom->input;  	bool prox;  	int x = 0, y = 0; @@ -970,6 +1049,10 @@ static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len)  			prox = data[0] & 0x01;  			x = get_unaligned_le16(&data[1]);  			y = get_unaligned_le16(&data[3]); +		} else if (len == WACOM_PKGLEN_TPC1FG_B) { +			prox = data[2] & 0x01; +			x = get_unaligned_le16(&data[3]); +			y = get_unaligned_le16(&data[5]);  		} else {  			prox = data[1] & 0x01;  			x = le16_to_cpup((__le16 *)&data[2]); @@ -993,10 +1076,8 @@ static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len)  static int wacom_tpc_pen(struct wacom_wac *wacom)  { -	struct wacom_features *features = &wacom->features; -	char *data = wacom->data; +	unsigned char *data = wacom->data;  	struct input_dev *input = wacom->input; -	int pressure;  	bool prox = data[1] & 0x20;  	if (!wacom->shared->stylus_in_proximity) /* first in prox */ @@ -1012,10 +1093,7 @@ static int wacom_tpc_pen(struct wacom_wac *wacom)  		input_report_key(input, BTN_STYLUS2, data[1] & 0x10);  		input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));  		input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4])); -		pressure = ((data[7] & 0x01) << 8) | data[6]; -		if (pressure < 0) -			pressure = features->pressure_max + pressure + 1; -		input_report_abs(input, ABS_PRESSURE, pressure); +		input_report_abs(input, ABS_PRESSURE, ((data[7] & 0x03) << 8) | data[6]);  		input_report_key(input, BTN_TOUCH, data[1] & 0x05);  		input_report_key(input, wacom->tool[0], prox);  		return 1; @@ -1026,7 +1104,7 @@ static int wacom_tpc_pen(struct wacom_wac *wacom)  static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)  { -	char *data = wacom->data; +	unsigned char *data = wacom->data;  	dev_dbg(wacom->input->dev.parent,  		"%s: received report #%d\n", __func__, data[0]); @@ -1038,6 +1116,9 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)  	case WACOM_PKGLEN_TPC2FG:  		return wacom_tpc_mt_touch(wacom); +	case WACOM_PKGLEN_PENABLED: +		return wacom_tpc_pen(wacom); +  	default:  		switch (data[0]) {  		case WACOM_REPORT_TPC1FG: @@ -1047,6 +1128,7 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)  			return wacom_tpc_single_touch(wacom, len);  		case WACOM_REPORT_TPCMT: +		case WACOM_REPORT_TPCMT2:  			return wacom_mt_touch(wacom);  		case WACOM_REPORT_PENABLED: @@ -1107,6 +1189,7 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)  static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)  { +	struct wacom_features *features = &wacom->features;  	struct input_dev *input = wacom->input;  	bool touch = data[1] & 0x80;  	int slot = input_mt_get_slot_by_key(input, data[0]); @@ -1122,14 +1205,23 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)  	if (touch) {  		int x = (data[2] << 4) | (data[4] >> 4);  		int y = (data[3] << 4) | (data[4] & 0x0f); -		int a = data[5]; +		int width, height; -		// "a" is a scaled-down area which we assume is roughly -		// circular and which can be described as: a=(pi*r^2)/C. -		int x_res  = input_abs_get_res(input, ABS_X); -		int y_res  = input_abs_get_res(input, ABS_Y); -		int width  = 2 * int_sqrt(a * WACOM_CONTACT_AREA_SCALE); -		int height = width * y_res / x_res; +		if (features->type >= INTUOSPS && features->type <= INTUOSPL) { +			width  = data[5] * 100; +			height = data[6] * 100; +		} else { +			/* +			 * "a" is a scaled-down area which we assume is +			 * roughly circular and which can be described as: +			 * a=(pi*r^2)/C. +			 */ +			int a = data[5]; +			int x_res = input_abs_get_res(input, ABS_MT_POSITION_X); +			int y_res = input_abs_get_res(input, ABS_MT_POSITION_Y); +			width = 2 * int_sqrt(a * WACOM_CONTACT_AREA_SCALE); +			height = width * y_res / x_res; +		}  		input_report_abs(input, ABS_MT_POSITION_X, x);  		input_report_abs(input, ABS_MT_POSITION_Y, y); @@ -1141,10 +1233,16 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)  static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data)  {  	struct input_dev *input = wacom->input; +	struct wacom_features *features = &wacom->features; -	input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0); +	if (features->type == INTUOSHT) { +		input_report_key(input, BTN_LEFT, (data[1] & 0x02) != 0); +		input_report_key(input, BTN_BACK, (data[1] & 0x08) != 0); +	} else { +		input_report_key(input, BTN_BACK, (data[1] & 0x02) != 0); +		input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0); +	}  	input_report_key(input, BTN_FORWARD, (data[1] & 0x04) != 0); -	input_report_key(input, BTN_BACK, (data[1] & 0x02) != 0);  	input_report_key(input, BTN_RIGHT, (data[1] & 0x01) != 0);  } @@ -1178,13 +1276,23 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)  static int wacom_bpt_pen(struct wacom_wac *wacom)  { +	struct wacom_features *features = &wacom->features;  	struct input_dev *input = wacom->input;  	unsigned char *data = wacom->data;  	int prox = 0, x = 0, y = 0, p = 0, d = 0, pen = 0, btn1 = 0, btn2 = 0; -	if (data[0] != 0x02) +	if (data[0] != WACOM_REPORT_PENABLED && data[0] != WACOM_REPORT_USB)  	    return 0; +	if (data[0] == WACOM_REPORT_USB) { +		if (features->type == INTUOSHT && features->touch_max) { +			input_report_switch(wacom->shared->touch_input, +					    SW_MUTE_DEVICE, data[8] & 0x40); +			input_sync(wacom->shared->touch_input); +		} +		return 0; +	} +  	prox = (data[1] & 0x20) == 0x20;  	/* @@ -1217,8 +1325,8 @@ static int wacom_bpt_pen(struct wacom_wac *wacom)  		 * touching and applying pressure; do not report negative  		 * distance.  		 */ -		if (data[8] <= wacom->features.distance_max) -			d = wacom->features.distance_max - data[8]; +		if (data[8] <= features->distance_max) +			d = features->distance_max - data[8];  		pen = data[1] & 0x01;  		btn1 = data[1] & 0x02; @@ -1262,13 +1370,20 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)  	unsigned char *data = wacom->data;  	int connected; -	if (len != WACOM_PKGLEN_WIRELESS || data[0] != 0x80) +	if (len != WACOM_PKGLEN_WIRELESS || data[0] != WACOM_REPORT_WL)  		return 0;  	connected = data[1] & 0x01;  	if (connected) {  		int pid, battery; +		if ((wacom->shared->type == INTUOSHT) && +				wacom->shared->touch_max) { +			input_report_switch(wacom->shared->touch_input, +					SW_MUTE_DEVICE, data[5] & 0x40); +			input_sync(wacom->shared->touch_input); +		} +  		pid = get_unaligned_be16(&data[6]);  		battery = data[5] & 0x3f;  		if (wacom->pid != pid) { @@ -1313,6 +1428,10 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)  		sync = wacom_dtu_irq(wacom_wac);  		break; +	case DTUS: +		sync = wacom_dtus_irq(wacom_wac); +		break; +  	case INTUOS:  	case INTUOS3S:  	case INTUOS3: @@ -1327,6 +1446,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)  	case WACOM_22HD:  	case WACOM_24HD:  	case DTK: +	case CINTIQ_HYBRID:  		sync = wacom_intuos_irq(wacom_wac);  		break; @@ -1337,6 +1457,9 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)  	case INTUOS5S:  	case INTUOS5:  	case INTUOS5L: +	case INTUOSPS: +	case INTUOSPM: +	case INTUOSPL:  		if (len == WACOM_PKGLEN_BBTOUCH3)  			sync = wacom_bpt3_touch(wacom_wac);  		else @@ -1348,10 +1471,12 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)  	case TABLETPC2FG:  	case MTSCREEN:  	case MTTPC: +	case MTTPC_B:  		sync = wacom_tpc_irq(wacom_wac, len);  		break;  	case BAMBOO_PT: +	case INTUOSHT:  		sync = wacom_bpt_irq(wacom_wac, len);  		break; @@ -1420,7 +1545,7 @@ void wacom_setup_device_quirks(struct wacom_features *features)  	/* these device have multiple inputs */  	if (features->type >= WIRELESS || -	    (features->type >= INTUOS5S && features->type <= INTUOS5L) || +	    (features->type >= INTUOS5S && features->type <= INTUOSHT) ||  	    (features->oVid && features->oPid))  		features->quirks |= WACOM_QUIRK_MULTI_INPUT; @@ -1451,10 +1576,10 @@ static void wacom_abs_set_axis(struct input_dev *input_dev,  	struct wacom_features *features = &wacom_wac->features;  	if (features->device_type == BTN_TOOL_PEN) { -		input_set_abs_params(input_dev, ABS_X, 0, features->x_max, -				     features->x_fuzz, 0); -		input_set_abs_params(input_dev, ABS_Y, 0, features->y_max, -				     features->y_fuzz, 0); +		input_set_abs_params(input_dev, ABS_X, features->x_min, +				     features->x_max, features->x_fuzz, 0); +		input_set_abs_params(input_dev, ABS_Y, features->y_min, +				     features->y_max, features->y_fuzz, 0);  		input_set_abs_params(input_dev, ABS_PRESSURE, 0,  			features->pressure_max, features->pressure_fuzz, 0); @@ -1462,7 +1587,7 @@ static void wacom_abs_set_axis(struct input_dev *input_dev,  		input_abs_set_res(input_dev, ABS_X, features->x_resolution);  		input_abs_set_res(input_dev, ABS_Y, features->y_resolution);  	} else { -		if (features->touch_max <= 2) { +		if (features->touch_max == 1) {  			input_set_abs_params(input_dev, ABS_X, 0,  				features->x_max, features->x_fuzz, 0);  			input_set_abs_params(input_dev, ABS_Y, 0, @@ -1499,7 +1624,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,  	wacom_abs_set_axis(input_dev, wacom_wac); -	switch (wacom_wac->features.type) { +	switch (features->type) {  	case WACOM_MO:  		input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);  		/* fall through */ @@ -1627,6 +1752,8 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,  	case INTUOS5:  	case INTUOS5L: +	case INTUOSPM: +	case INTUOSPL:  		if (features->device_type == BTN_TOOL_PEN) {  			__set_bit(BTN_7, input_dev->keybit);  			__set_bit(BTN_8, input_dev->keybit); @@ -1634,6 +1761,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,  		/* fall through */  	case INTUOS5S: +	case INTUOSPS:  		__set_bit(INPUT_PROP_POINTER, input_dev->propbit);  		if (features->device_type == BTN_TOOL_PEN) { @@ -1685,15 +1813,10 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,  	case MTSCREEN:  	case MTTPC: +	case MTTPC_B:  	case TABLETPC2FG: -		if (features->device_type == BTN_TOOL_FINGER) { -			unsigned int flags = INPUT_MT_DIRECT; - -			if (wacom_wac->features.type == TABLETPC2FG) -				flags = 0; - -			input_mt_init_slots(input_dev, features->touch_max, flags); -		} +		if (features->device_type == BTN_TOOL_FINGER && features->touch_max > 1) +			input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_DIRECT);  		/* fall through */  	case TABLETPC: @@ -1707,8 +1830,14 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,  		/* fall through */ +	case DTUS:  	case PL:  	case DTU: +		if (features->type == DTUS) { +			input_set_capability(input_dev, EV_MSC, MSC_SERIAL); +			for (i = 0; i < 4; i++) +				__set_bit(BTN_0 + i, input_dev->keybit); +		}  		__set_bit(BTN_TOOL_PEN, input_dev->keybit);  		__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);  		__set_bit(BTN_STYLUS, input_dev->keybit); @@ -1729,33 +1858,42 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,  		__set_bit(INPUT_PROP_POINTER, input_dev->propbit);  		break; +	case INTUOSHT: +		if (features->touch_max && +		    features->device_type == BTN_TOOL_FINGER) { +			input_dev->evbit[0] |= BIT_MASK(EV_SW); +			__set_bit(SW_MUTE_DEVICE, input_dev->swbit); +		} +		/* fall through */ +  	case BAMBOO_PT:  		__clear_bit(ABS_MISC, input_dev->absbit); -		__set_bit(INPUT_PROP_POINTER, input_dev->propbit); -  		if (features->device_type == BTN_TOOL_FINGER) { -			unsigned int flags = INPUT_MT_POINTER;  			__set_bit(BTN_LEFT, input_dev->keybit);  			__set_bit(BTN_FORWARD, input_dev->keybit);  			__set_bit(BTN_BACK, input_dev->keybit);  			__set_bit(BTN_RIGHT, input_dev->keybit); -			if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) { -				input_set_abs_params(input_dev, +			if (features->touch_max) { +				if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) { +					input_set_abs_params(input_dev,  						     ABS_MT_TOUCH_MAJOR,  						     0, features->x_max, 0, 0); -				input_set_abs_params(input_dev, +					input_set_abs_params(input_dev,  						     ABS_MT_TOUCH_MINOR,  						     0, features->y_max, 0, 0); +				} +				input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_POINTER);  			} else { -				__set_bit(BTN_TOOL_FINGER, input_dev->keybit); -				__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); -				flags = 0; +				/* buttons/keys only interface */ +				__clear_bit(ABS_X, input_dev->absbit); +				__clear_bit(ABS_Y, input_dev->absbit); +				__clear_bit(BTN_TOUCH, input_dev->keybit);  			} -			input_mt_init_slots(input_dev, features->touch_max, flags);  		} else if (features->device_type == BTN_TOOL_PEN) { +			__set_bit(INPUT_PROP_POINTER, input_dev->propbit);  			__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);  			__set_bit(BTN_TOOL_PEN, input_dev->keybit);  			__set_bit(BTN_STYLUS, input_dev->keybit); @@ -1765,6 +1903,24 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,  					      0, 0);  		}  		break; + +	case CINTIQ_HYBRID: +		__set_bit(BTN_1, input_dev->keybit); +		__set_bit(BTN_2, input_dev->keybit); +		__set_bit(BTN_3, input_dev->keybit); +		__set_bit(BTN_4, input_dev->keybit); + +		__set_bit(BTN_5, input_dev->keybit); +		__set_bit(BTN_6, input_dev->keybit); +		__set_bit(BTN_7, input_dev->keybit); +		__set_bit(BTN_8, input_dev->keybit); +		__set_bit(BTN_0, input_dev->keybit); + +		input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); +		__set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + +		wacom_setup_cintiq(wacom_wac); +		break;  	}  	return 0;  } @@ -1952,12 +2108,24 @@ static const struct wacom_features wacom_features_0x29 =  static const struct wacom_features wacom_features_0x2A =  	{ "Wacom Intuos5 M", WACOM_PKGLEN_INTUOS,  44704, 27940, 2047,  	  63, INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; +static const struct wacom_features wacom_features_0x314 = +	{ "Wacom Intuos Pro S", WACOM_PKGLEN_INTUOS,  31496, 19685, 2047, +	  63, INTUOSPS, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, +	  .touch_max = 16 }; +static const struct wacom_features wacom_features_0x315 = +	{ "Wacom Intuos Pro M", WACOM_PKGLEN_INTUOS,  44704, 27940, 2047, +	  63, INTUOSPM, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, +	  .touch_max = 16 }; +static const struct wacom_features wacom_features_0x317 = +	{ "Wacom Intuos Pro L", WACOM_PKGLEN_INTUOS,  65024, 40640, 2047, +	  63, INTUOSPL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, +	  .touch_max = 16 };  static const struct wacom_features wacom_features_0xF4 = -	{ "Wacom Cintiq 24HD",       WACOM_PKGLEN_INTUOS,   104480, 65600, 2047, -	  63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; +	{ "Wacom Cintiq 24HD",       WACOM_PKGLEN_INTUOS,   104280, 65400, 2047, +	  63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };  static const struct wacom_features wacom_features_0xF8 = -	{ "Wacom Cintiq 24HD touch", WACOM_PKGLEN_INTUOS,   104480, 65600, 2047, /* Pen */ -	  63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, +	{ "Wacom Cintiq 24HD touch", WACOM_PKGLEN_INTUOS,   104280, 65400, 2047, /* Pen */ +	  63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,  	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf6 };  static const struct wacom_features wacom_features_0xF6 =  	{ "Wacom Cintiq 24HD touch", .type = WACOM_24HDT, /* Touch */ @@ -1972,8 +2140,8 @@ static const struct wacom_features wacom_features_0xC6 =  	{ "Wacom Cintiq 12WX",    WACOM_PKGLEN_INTUOS,    53020, 33440, 1023,  	  63, WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };  static const struct wacom_features wacom_features_0x304 = -	{ "Wacom Cintiq 13HD",    WACOM_PKGLEN_INTUOS,    59552, 33848, 1023, -	  63, WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; +	{ "Wacom Cintiq 13HD",    WACOM_PKGLEN_INTUOS,    59352, 33648, 1023, +	  63, WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };  static const struct wacom_features wacom_features_0xC7 =  	{ "Wacom DTU1931",        WACOM_PKGLEN_GRAPHIRE,  37832, 30305,  511,  	  0, PL, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; @@ -1983,25 +2151,28 @@ static const struct wacom_features wacom_features_0xCE =  static const struct wacom_features wacom_features_0xF0 =  	{ "Wacom DTU1631",        WACOM_PKGLEN_GRAPHIRE,  34623, 19553,  511,  	  0, DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; +static const struct wacom_features wacom_features_0xFB = +	{ "Wacom DTU1031",        WACOM_PKGLEN_DTUS,      22096, 13960,  511, +	  0, DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };  static const struct wacom_features wacom_features_0x57 = -	{ "Wacom DTK2241",        WACOM_PKGLEN_INTUOS,    95840, 54260, 2047, -	  63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES}; +	{ "Wacom DTK2241",        WACOM_PKGLEN_INTUOS,    95640, 54060, 2047, +	  63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };  static const struct wacom_features wacom_features_0x59 = /* Pen */ -	{ "Wacom DTH2242",        WACOM_PKGLEN_INTUOS,    95840, 54260, 2047, -	  63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, +	{ "Wacom DTH2242",        WACOM_PKGLEN_INTUOS,    95640, 54060, 2047, +	  63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,  	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5D };  static const struct wacom_features wacom_features_0x5D = /* Touch */  	{ "Wacom DTH2242",       .type = WACOM_24HDT,  	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x59, .touch_max = 10 };  static const struct wacom_features wacom_features_0xCC = -	{ "Wacom Cintiq 21UX2",   WACOM_PKGLEN_INTUOS,    87200, 65600, 2047, -	  63, WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; +	{ "Wacom Cintiq 21UX2",   WACOM_PKGLEN_INTUOS,    87000, 65400, 2047, +	  63, WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };  static const struct wacom_features wacom_features_0xFA = -	{ "Wacom Cintiq 22HD",    WACOM_PKGLEN_INTUOS,    95840, 54260, 2047, -	  63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; +	{ "Wacom Cintiq 22HD",    WACOM_PKGLEN_INTUOS,    95640, 54060, 2047, +	  63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };  static const struct wacom_features wacom_features_0x5B = -	{ "Wacom Cintiq 22HDT", WACOM_PKGLEN_INTUOS,      95840, 54260, 2047, -	  63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, +	{ "Wacom Cintiq 22HDT", WACOM_PKGLEN_INTUOS,      95640, 54060, 2047, +	  63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,  	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5e };  static const struct wacom_features wacom_features_0x5E =  	{ "Wacom Cintiq 22HDT", .type = WACOM_24HDT, @@ -2054,9 +2225,27 @@ static const struct wacom_features wacom_features_0x101 =  static const struct wacom_features wacom_features_0x10D =  	{ "Wacom ISDv4 10D",      WACOM_PKGLEN_MTTPC,     26202, 16325,  255,  	  0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; +static const struct wacom_features wacom_features_0x10E = +	{ "Wacom ISDv4 10E",      WACOM_PKGLEN_MTTPC,     27760, 15694,  255, +	  0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; +static const struct wacom_features wacom_features_0x10F = +	{ "Wacom ISDv4 10F",      WACOM_PKGLEN_MTTPC,     27760, 15694,  255, +	  0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; +static const struct wacom_features wacom_features_0x116 = +	{ "Wacom ISDv4 116",      WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255, +	  0, TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };  static const struct wacom_features wacom_features_0x4001 =  	{ "Wacom ISDv4 4001",      WACOM_PKGLEN_MTTPC,     26202, 16325,  255,  	  0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; +static const struct wacom_features wacom_features_0x4004 = +	{ "Wacom ISDv4 4004",      WACOM_PKGLEN_MTTPC,     11060, 6220,  255, +	  0, MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; +static const struct wacom_features wacom_features_0x5000 = +	{ "Wacom ISDv4 5000",      WACOM_PKGLEN_MTTPC,     27848, 15752,  1023, +	  0, MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; +static const struct wacom_features wacom_features_0x5002 = +	{ "Wacom ISDv4 5002",      WACOM_PKGLEN_MTTPC,     29576, 16724,  1023, +	  0, MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };  static const struct wacom_features wacom_features_0x47 =  	{ "Wacom Intuos2 6x8",    WACOM_PKGLEN_INTUOS,    20320, 16240, 1023,  	  31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; @@ -2122,9 +2311,27 @@ static const struct wacom_features wacom_features_0x300 =  static const struct wacom_features wacom_features_0x301 =  	{ "Wacom Bamboo One M",    WACOM_PKGLEN_BBPEN,    21648, 13530, 1023,  	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; +static const struct wacom_features wacom_features_0x302 = +	{ "Wacom Intuos PT S",     WACOM_PKGLEN_BBPEN,    15200,  9500, 1023, +	  31, INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, +	  .touch_max = 16 }; +static const struct wacom_features wacom_features_0x303 = +	{ "Wacom Intuos PT M",     WACOM_PKGLEN_BBPEN,    21600, 13500, 1023, +	  31, INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, +	  .touch_max = 16 }; +static const struct wacom_features wacom_features_0x30E = +	{ "Wacom Intuos S",        WACOM_PKGLEN_BBPEN,    15200,  9500, 1023, +	  31, INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };  static const struct wacom_features wacom_features_0x6004 =  	{ "ISD-V4",               WACOM_PKGLEN_GRAPHIRE,  12800,  8000,  255,  	  0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; +static const struct wacom_features wacom_features_0x0307 = +	{ "Wacom ISDv5 307", WACOM_PKGLEN_INTUOS,  59352,  33648, 2047, +	  63, CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200, +	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x309 }; +static const struct wacom_features wacom_features_0x0309 = +	{ "Wacom ISDv5 309", .type = WACOM_24HDT, /* Touch */ +	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x0307, .touch_max = 10 };  #define USB_DEVICE_WACOM(prod)					\  	USB_DEVICE(USB_VENDOR_ID_WACOM, prod),			\ @@ -2248,15 +2455,30 @@ const struct usb_device_id wacom_ids[] = {  	{ USB_DEVICE_WACOM(0x100) },  	{ USB_DEVICE_WACOM(0x101) },  	{ USB_DEVICE_WACOM(0x10D) }, +	{ USB_DEVICE_WACOM(0x10E) }, +	{ USB_DEVICE_WACOM(0x10F) }, +	{ USB_DEVICE_WACOM(0x116) },  	{ USB_DEVICE_WACOM(0x300) },  	{ USB_DEVICE_WACOM(0x301) }, +	{ USB_DEVICE_DETAILED(0x302, USB_CLASS_HID, 0, 0) }, +	{ USB_DEVICE_DETAILED(0x303, USB_CLASS_HID, 0, 0) }, +	{ USB_DEVICE_DETAILED(0x30E, USB_CLASS_HID, 0, 0) },  	{ USB_DEVICE_WACOM(0x304) }, +	{ USB_DEVICE_DETAILED(0x314, USB_CLASS_HID, 0, 0) }, +	{ USB_DEVICE_DETAILED(0x315, USB_CLASS_HID, 0, 0) }, +	{ USB_DEVICE_DETAILED(0x317, USB_CLASS_HID, 0, 0) },  	{ USB_DEVICE_WACOM(0x4001) }, +	{ USB_DEVICE_WACOM(0x4004) }, +	{ USB_DEVICE_WACOM(0x5000) }, +	{ USB_DEVICE_WACOM(0x5002) },  	{ USB_DEVICE_WACOM(0x47) },  	{ USB_DEVICE_WACOM(0xF4) },  	{ USB_DEVICE_WACOM(0xF8) },  	{ USB_DEVICE_DETAILED(0xF6, USB_CLASS_HID, 0, 0) },  	{ USB_DEVICE_WACOM(0xFA) }, +	{ USB_DEVICE_WACOM(0xFB) }, +	{ USB_DEVICE_WACOM(0x0307) }, +	{ USB_DEVICE_DETAILED(0x0309, USB_CLASS_HID, 0, 0) },  	{ USB_DEVICE_LENOVO(0x6004) },  	{ }  }; diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h index dfc9e08e7f7..b2c9a9c1b55 100644 --- a/drivers/input/tablet/wacom_wac.h +++ b/drivers/input/tablet/wacom_wac.h @@ -12,7 +12,9 @@  #include <linux/types.h>  /* maximum packet length for USB devices */ -#define WACOM_PKGLEN_MAX	64 +#define WACOM_PKGLEN_MAX	68 + +#define WACOM_NAME_MAX		64  /* packet length for individual models */  #define WACOM_PKGLEN_PENPRTN	 7 @@ -20,6 +22,7 @@  #define WACOM_PKGLEN_BBFUN	 9  #define WACOM_PKGLEN_INTUOS	10  #define WACOM_PKGLEN_TPC1FG	 5 +#define WACOM_PKGLEN_TPC1FG_B	10  #define WACOM_PKGLEN_TPC2FG	14  #define WACOM_PKGLEN_BBTOUCH	20  #define WACOM_PKGLEN_BBTOUCH3	64 @@ -27,6 +30,8 @@  #define WACOM_PKGLEN_WIRELESS	32  #define WACOM_PKGLEN_MTOUCH	62  #define WACOM_PKGLEN_MTTPC	40 +#define WACOM_PKGLEN_DTUS	68 +#define WACOM_PKGLEN_PENABLED	 8  /* wacom data size per MT contact */  #define WACOM_BYTES_PER_MT_PACKET	11 @@ -45,13 +50,18 @@  #define WACOM_REPORT_INTUOSWRITE	6  #define WACOM_REPORT_INTUOSPAD		12  #define WACOM_REPORT_INTUOS5PAD		3 +#define WACOM_REPORT_DTUSPAD		21  #define WACOM_REPORT_TPC1FG		6  #define WACOM_REPORT_TPC2FG		13  #define WACOM_REPORT_TPCMT		13 +#define WACOM_REPORT_TPCMT2		3  #define WACOM_REPORT_TPCHID		15  #define WACOM_REPORT_TPCST		16 +#define WACOM_REPORT_DTUS		17  #define WACOM_REPORT_TPC1FGE		18  #define WACOM_REPORT_24HDT		1 +#define WACOM_REPORT_WL			128 +#define WACOM_REPORT_USB		192  /* device quirks */  #define WACOM_QUIRK_MULTI_INPUT		0x0001 @@ -66,6 +76,7 @@ enum {  	PTU,  	PL,  	DTU, +	DTUS,  	INTUOS,  	INTUOS3S,  	INTUOS3, @@ -76,10 +87,15 @@ enum {  	INTUOS5S,  	INTUOS5,  	INTUOS5L, +	INTUOSPS, +	INTUOSPM, +	INTUOSPL, +	INTUOSHT,  	WACOM_21UX2,  	WACOM_22HD,  	DTK,  	WACOM_24HD, +	CINTIQ_HYBRID,  	CINTIQ,  	WACOM_BEE,  	WACOM_13HD, @@ -92,6 +108,7 @@ enum {  	TABLETPC2FG,  	MTSCREEN,  	MTTPC, +	MTTPC_B,  	MAX_TYPE  }; @@ -105,6 +122,8 @@ struct wacom_features {  	int type;  	int x_resolution;  	int y_resolution; +	int x_min; +	int y_min;  	int device_type;  	int x_phy;  	int y_phy; @@ -123,10 +142,14 @@ struct wacom_features {  struct wacom_shared {  	bool stylus_in_proximity;  	bool touch_down; +	/* for wireless device to access USB interfaces */ +	unsigned touch_max; +	int type; +	struct input_dev *touch_input;  };  struct wacom_wac { -	char name[64]; +	char name[WACOM_NAME_MAX];  	unsigned char *data;  	int tool[2];  	int id[2]; diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c index f7de14a268b..0d4a9fad4a7 100644 --- a/drivers/input/touchscreen/88pm860x-ts.c +++ b/drivers/input/touchscreen/88pm860x-ts.c @@ -16,6 +16,7 @@  #include <linux/input.h>  #include <linux/mfd/88pm860x.h>  #include <linux/slab.h> +#include <linux/device.h>  #define MEAS_LEN		(8)  #define ACCURATE_BIT		(12) @@ -172,7 +173,7 @@ static int pm860x_touch_dt_init(struct platform_device *pdev,  static int pm860x_touch_probe(struct platform_device *pdev)  {  	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); -	struct pm860x_touch_pdata *pdata = pdev->dev.platform_data; +	struct pm860x_touch_pdata *pdata = dev_get_platdata(&pdev->dev);  	struct pm860x_touch *touch;  	struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \  				 : chip->companion; @@ -234,16 +235,17 @@ static int pm860x_touch_probe(struct platform_device *pdev)  	if (ret)  		return ret; -	touch = kzalloc(sizeof(struct pm860x_touch), GFP_KERNEL); -	if (touch == NULL) +	touch = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_touch), +			     GFP_KERNEL); +	if (!touch)  		return -ENOMEM; +  	platform_set_drvdata(pdev, touch); -	touch->idev = input_allocate_device(); -	if (touch->idev == NULL) { +	touch->idev = devm_input_allocate_device(&pdev->dev); +	if (!touch->idev) {  		dev_err(&pdev->dev, "Failed to allocate input device!\n"); -		ret = -ENOMEM; -		goto out; +		return -ENOMEM;  	}  	touch->idev->name = "88pm860x-touch"; @@ -258,10 +260,11 @@ static int pm860x_touch_probe(struct platform_device *pdev)  	touch->res_x = res_x;  	input_set_drvdata(touch->idev, touch); -	ret = request_threaded_irq(touch->irq, NULL, pm860x_touch_handler, -				   IRQF_ONESHOT, "touch", touch); +	ret = devm_request_threaded_irq(&pdev->dev, touch->irq, NULL, +					pm860x_touch_handler, IRQF_ONESHOT, +					"touch", touch);  	if (ret < 0) -		goto out_irq; +		return ret;  	__set_bit(EV_ABS, touch->idev->evbit);  	__set_bit(ABS_X, touch->idev->absbit); @@ -279,28 +282,11 @@ static int pm860x_touch_probe(struct platform_device *pdev)  	ret = input_register_device(touch->idev);  	if (ret < 0) {  		dev_err(chip->dev, "Failed to register touch!\n"); -		goto out_rg; +		return ret;  	}  	platform_set_drvdata(pdev, touch);  	return 0; -out_rg: -	free_irq(touch->irq, touch); -out_irq: -	input_free_device(touch->idev); -out: -	kfree(touch); -	return ret; -} - -static int pm860x_touch_remove(struct platform_device *pdev) -{ -	struct pm860x_touch *touch = platform_get_drvdata(pdev); - -	input_unregister_device(touch->idev); -	free_irq(touch->irq, touch); -	kfree(touch); -	return 0;  }  static struct platform_driver pm860x_touch_driver = { @@ -309,7 +295,6 @@ static struct platform_driver pm860x_touch_driver = {  		.owner	= THIS_MODULE,  	},  	.probe	= pm860x_touch_probe, -	.remove	= pm860x_touch_remove,  };  module_platform_driver(pm860x_touch_driver); diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index e09ec67957a..a23a94bb4bc 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -11,6 +11,10 @@ menuconfig INPUT_TOUCHSCREEN  if INPUT_TOUCHSCREEN +config OF_TOUCHSCREEN +	def_tristate INPUT +	depends on INPUT && OF +  config TOUCHSCREEN_88PM860X  	tristate "Marvell 88PM860x touchscreen"  	depends on MFD_88PM860X @@ -89,6 +93,7 @@ config TOUCHSCREEN_AD7879_SPI  config TOUCHSCREEN_ATMEL_MXT  	tristate "Atmel mXT I2C Touchscreen"  	depends on I2C +	select FW_LOADER  	help  	  Say Y here if you have Atmel mXT series I2C touchscreen,  	  such as AT42QT602240/ATMXT224, connected to your system. @@ -514,15 +519,6 @@ config TOUCHSCREEN_MIGOR  	  To compile this driver as a module, choose M here: the  	  module will be called migor_ts. -config TOUCHSCREEN_TNETV107X -	tristate "TI TNETV107X touchscreen support" -	depends on ARCH_DAVINCI_TNETV107X -	help -	  Say Y here if you want to use the TNETV107X touchscreen. - -	  To compile this driver as a module, choose M here: the -	  module will be called tnetv107x-ts. -  config TOUCHSCREEN_TOUCHRIGHT  	tristate "Touchright serial touchscreen"  	select SERIO @@ -559,18 +555,6 @@ config TOUCHSCREEN_TI_AM335X_TSC  	  To compile this driver as a module, choose M here: the  	  module will be called ti_am335x_tsc. -config TOUCHSCREEN_ATMEL_TSADCC -	tristate "Atmel Touchscreen Interface" -	depends on ARCH_AT91 -	help -	  Say Y here if you have a 4-wire touchscreen connected to the -          ADC Controller on your Atmel SoC. - -	  If unsure, say N. - -	  To compile this driver as a module, choose M here: the -	  module will be called atmel_tsadcc. -  config TOUCHSCREEN_UCB1400  	tristate "Philips UCB1400 touchscreen"  	depends on AC97_BUS @@ -649,7 +633,7 @@ config TOUCHSCREEN_WM9713  config TOUCHSCREEN_WM97XX_ATMEL  	tristate "WM97xx Atmel accelerated touch" -	depends on TOUCHSCREEN_WM97XX && (AVR32 || ARCH_AT91) +	depends on TOUCHSCREEN_WM97XX && AVR32  	help  	  Say Y here for support for streaming mode with WM97xx touchscreens  	  on Atmel AT91 or AVR32 systems with an AC97C module. @@ -717,7 +701,7 @@ config TOUCHSCREEN_USB_COMPOSITE  config TOUCHSCREEN_MC13783  	tristate "Freescale MC13783 touchscreen input driver" -	depends on MFD_MC13783 +	depends on MFD_MC13XXX  	help  	  Say Y here if you have an Freescale MC13783 PMIC on your  	  board and want to use its touchscreen @@ -867,7 +851,7 @@ config TOUCHSCREEN_TSC2007  config TOUCHSCREEN_W90X900  	tristate "W90P910 touchscreen driver" -	depends on HAVE_CLK +	depends on ARCH_W90X900  	help  	  Say Y here if you have a W90P910 based touchscreen. @@ -906,6 +890,28 @@ config TOUCHSCREEN_STMPE  	  To compile this driver as a module, choose M here: the  	  module will be called stmpe-ts. +config TOUCHSCREEN_SUN4I +	tristate "Allwinner sun4i resistive touchscreen controller support" +	depends on ARCH_SUNXI || COMPILE_TEST +	depends on HWMON +	help +	  This selects support for the resistive touchscreen controller +	  found on Allwinner sunxi SoCs. + +	  To compile this driver as a module, choose M here: the +	  module will be called sun4i-ts. + +config TOUCHSCREEN_SUR40 +	tristate "Samsung SUR40 (Surface 2.0/PixelSense) touchscreen" +	depends on USB +	select INPUT_POLLDEV +	help +	  Say Y here if you want support for the Samsung SUR40 touchscreen +	  (also known as Microsoft Surface 2.0 or Microsoft PixelSense). + +	  To compile this driver as a module, choose M here: the +	  module will be called sur40. +  config TOUCHSCREEN_TPS6507X  	tristate "TPS6507x based touchscreens"  	depends on I2C @@ -919,4 +925,17 @@ config TOUCHSCREEN_TPS6507X  	  To compile this driver as a module, choose M here: the  	  module will be called tps6507x_ts. +config TOUCHSCREEN_ZFORCE +	tristate "Neonode zForce infrared touchscreens" +	depends on I2C +	depends on GPIOLIB +	help +	  Say Y here if you have a touchscreen using the zforce +	  infraread technology from Neonode. + +	  If unsure, say N. + +	  To compile this driver as a module, choose M here: the +	  module will be called zforce_ts. +  endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index f5216c1bf53..126479d8c29 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -6,6 +6,7 @@  wm97xx-ts-y := wm97xx-core.o +obj-$(CONFIG_OF_TOUCHSCREEN)		+= of_touchscreen.o  obj-$(CONFIG_TOUCHSCREEN_88PM860X)	+= 88pm860x-ts.o  obj-$(CONFIG_TOUCHSCREEN_AD7877)	+= ad7877.o  obj-$(CONFIG_TOUCHSCREEN_AD7879)	+= ad7879.o @@ -13,7 +14,6 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C)	+= ad7879-i2c.o  obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI)	+= ad7879-spi.o  obj-$(CONFIG_TOUCHSCREEN_ADS7846)	+= ads7846.o  obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT)	+= atmel_mxt_ts.o -obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC)	+= atmel_tsadcc.o  obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR)	+= auo-pixcir-ts.o  obj-$(CONFIG_TOUCHSCREEN_BU21013)	+= bu21013_ts.o  obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)	+= cy8ctmg110_ts.o @@ -54,8 +54,9 @@ obj-$(CONFIG_TOUCHSCREEN_PIXCIR)	+= pixcir_i2c_ts.o  obj-$(CONFIG_TOUCHSCREEN_S3C2410)	+= s3c2410_ts.o  obj-$(CONFIG_TOUCHSCREEN_ST1232)	+= st1232.o  obj-$(CONFIG_TOUCHSCREEN_STMPE)		+= stmpe-ts.o +obj-$(CONFIG_TOUCHSCREEN_SUN4I)		+= sun4i-ts.o +obj-$(CONFIG_TOUCHSCREEN_SUR40)		+= sur40.o  obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC)	+= ti_am335x_tsc.o -obj-$(CONFIG_TOUCHSCREEN_TNETV107X)	+= tnetv107x-ts.o  obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213)	+= touchit213.o  obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)	+= touchright.o  obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN)	+= touchwin.o @@ -75,3 +76,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE)	+= mainstone-wm97xx.o  obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)	+= zylonite-wm97xx.o  obj-$(CONFIG_TOUCHSCREEN_W90X900)	+= w90p910_ts.o  obj-$(CONFIG_TOUCHSCREEN_TPS6507X)	+= tps6507x-ts.o +obj-$(CONFIG_TOUCHSCREEN_ZFORCE)	+= zforce_ts.o diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c index f3a174a83c8..523865daa1d 100644 --- a/drivers/input/touchscreen/ad7877.c +++ b/drivers/input/touchscreen/ad7877.c @@ -37,7 +37,6 @@  #include <linux/device.h> -#include <linux/init.h>  #include <linux/delay.h>  #include <linux/input.h>  #include <linux/interrupt.h> @@ -211,11 +210,6 @@ static bool gpio3;  module_param(gpio3, bool, 0);  MODULE_PARM_DESC(gpio3, "If gpio3 is set to 1 AUX3 acts as GPIO3"); -/* - * ad7877_read/write are only used for initial setup and for sysfs controls. - * The main traffic is done using spi_async() in the interrupt handler. - */ -  static int ad7877_read(struct spi_device *spi, u16 reg)  {  	struct ser_req *req; @@ -686,7 +680,7 @@ static int ad7877_probe(struct spi_device *spi)  {  	struct ad7877			*ts;  	struct input_dev		*input_dev; -	struct ad7877_platform_data	*pdata = spi->dev.platform_data; +	struct ad7877_platform_data	*pdata = dev_get_platdata(&spi->dev);  	int				err;  	u16				verify; @@ -806,7 +800,6 @@ err_free_irq:  err_free_mem:  	input_free_device(input_dev);  	kfree(ts); -	spi_set_drvdata(spi, NULL);  	return err;  } @@ -823,7 +816,6 @@ static int ad7877_remove(struct spi_device *spi)  	kfree(ts);  	dev_dbg(&spi->dev, "unregistered touchscreen\n"); -	spi_set_drvdata(spi, NULL);  	return 0;  } diff --git a/drivers/input/touchscreen/ad7879-spi.c b/drivers/input/touchscreen/ad7879-spi.c index 606da5bd611..1a7b1143536 100644 --- a/drivers/input/touchscreen/ad7879-spi.c +++ b/drivers/input/touchscreen/ad7879-spi.c @@ -142,7 +142,6 @@ static int ad7879_spi_remove(struct spi_device *spi)  	struct ad7879 *ts = spi_get_drvdata(spi);  	ad7879_remove(ts); -	spi_set_drvdata(spi, NULL);  	return 0;  } diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index facd3057b62..fce590677b7 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -22,7 +22,6 @@   */  #include <linux/device.h> -#include <linux/init.h>  #include <linux/delay.h>  #include <linux/input.h>  #include <linux/interrupt.h> @@ -470,7 +469,7 @@ static int ad7879_gpio_add(struct ad7879 *ts,  static void ad7879_gpio_remove(struct ad7879 *ts)  { -	const struct ad7879_platform_data *pdata = ts->dev->platform_data; +	const struct ad7879_platform_data *pdata = dev_get_platdata(ts->dev);  	int ret;  	if (pdata->gpio_export) { @@ -495,7 +494,7 @@ static inline void ad7879_gpio_remove(struct ad7879 *ts)  struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq,  			    const struct ad7879_bus_ops *bops)  { -	struct ad7879_platform_data *pdata = dev->platform_data; +	struct ad7879_platform_data *pdata = dev_get_platdata(dev);  	struct ad7879 *ts;  	struct input_dev *input_dev;  	int err; diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index ea195360747..da201b8e37d 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -19,7 +19,6 @@   */  #include <linux/types.h>  #include <linux/hwmon.h> -#include <linux/init.h>  #include <linux/err.h>  #include <linux/sched.h>  #include <linux/delay.h> @@ -101,8 +100,7 @@ struct ads7846 {  	struct spi_device	*spi;  	struct regulator	*reg; -#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE) -	struct attribute_group	*attr_group; +#if IS_ENABLED(CONFIG_HWMON)  	struct device		*hwmon;  #endif @@ -421,13 +419,13 @@ static int ads7845_read12_ser(struct device *dev, unsigned command)  	return status;  } -#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE) +#if IS_ENABLED(CONFIG_HWMON)  #define SHOW(name, var, adjust) static ssize_t \  name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \  { \  	struct ads7846 *ts = dev_get_drvdata(dev); \ -	ssize_t v = ads7846_read12_ser(dev, \ +	ssize_t v = ads7846_read12_ser(&ts->spi->dev, \  			READ_12BIT_SER(var)); \  	if (v < 0) \  		return v; \ @@ -479,42 +477,36 @@ static inline unsigned vbatt_adjust(struct ads7846 *ts, ssize_t v)  SHOW(in0_input, vaux, vaux_adjust)  SHOW(in1_input, vbatt, vbatt_adjust) -static struct attribute *ads7846_attributes[] = { -	&dev_attr_temp0.attr, -	&dev_attr_temp1.attr, -	&dev_attr_in0_input.attr, -	&dev_attr_in1_input.attr, -	NULL, -}; - -static struct attribute_group ads7846_attr_group = { -	.attrs = ads7846_attributes, -}; +static umode_t ads7846_is_visible(struct kobject *kobj, struct attribute *attr, +				  int index) +{ +	struct device *dev = container_of(kobj, struct device, kobj); +	struct ads7846 *ts = dev_get_drvdata(dev); -static struct attribute *ads7843_attributes[] = { -	&dev_attr_in0_input.attr, -	&dev_attr_in1_input.attr, -	NULL, -}; +	if (ts->model == 7843 && index < 2)	/* in0, in1 */ +		return 0; +	if (ts->model == 7845 && index != 2)	/* in0 */ +		return 0; -static struct attribute_group ads7843_attr_group = { -	.attrs = ads7843_attributes, -}; +	return attr->mode; +} -static struct attribute *ads7845_attributes[] = { -	&dev_attr_in0_input.attr, +static struct attribute *ads7846_attributes[] = { +	&dev_attr_temp0.attr,		/* 0 */ +	&dev_attr_temp1.attr,		/* 1 */ +	&dev_attr_in0_input.attr,	/* 2 */ +	&dev_attr_in1_input.attr,	/* 3 */  	NULL,  }; -static struct attribute_group ads7845_attr_group = { -	.attrs = ads7845_attributes, +static struct attribute_group ads7846_attr_group = { +	.attrs = ads7846_attributes, +	.is_visible = ads7846_is_visible,  }; +__ATTRIBUTE_GROUPS(ads7846_attr);  static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)  { -	struct device *hwmon; -	int err; -  	/* hwmon sensors need a reference voltage */  	switch (ts->model) {  	case 7846: @@ -535,43 +527,19 @@ static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)  		break;  	} -	/* different chips have different sensor groups */ -	switch (ts->model) { -	case 7846: -		ts->attr_group = &ads7846_attr_group; -		break; -	case 7845: -		ts->attr_group = &ads7845_attr_group; -		break; -	case 7843: -		ts->attr_group = &ads7843_attr_group; -		break; -	default: -		dev_dbg(&spi->dev, "ADS%d not recognized\n", ts->model); -		return 0; -	} - -	err = sysfs_create_group(&spi->dev.kobj, ts->attr_group); -	if (err) -		return err; - -	hwmon = hwmon_device_register(&spi->dev); -	if (IS_ERR(hwmon)) { -		sysfs_remove_group(&spi->dev.kobj, ts->attr_group); -		return PTR_ERR(hwmon); -	} +	ts->hwmon = hwmon_device_register_with_groups(&spi->dev, spi->modalias, +						      ts, ads7846_attr_groups); +	if (IS_ERR(ts->hwmon)) +		return PTR_ERR(ts->hwmon); -	ts->hwmon = hwmon;  	return 0;  }  static void ads784x_hwmon_unregister(struct spi_device *spi,  				     struct ads7846 *ts)  { -	if (ts->hwmon) { -		sysfs_remove_group(&spi->dev.kobj, ts->attr_group); +	if (ts->hwmon)  		hwmon_device_unregister(ts->hwmon); -	}  }  #else @@ -738,7 +706,7 @@ static void ads7846_read_state(struct ads7846 *ts)  		m = &ts->msg[msg_idx];  		error = spi_sync(ts->spi, m);  		if (error) { -			dev_err(&ts->spi->dev, "spi_async --> %d\n", error); +			dev_err(&ts->spi->dev, "spi_sync --> %d\n", error);  			packet->tc.ignore = true;  			return;  		} diff --git a/drivers/input/touchscreen/atmel-wm97xx.c b/drivers/input/touchscreen/atmel-wm97xx.c index 268a35e55d7..279c0e42b8a 100644 --- a/drivers/input/touchscreen/atmel-wm97xx.c +++ b/drivers/input/touchscreen/atmel-wm97xx.c @@ -391,7 +391,7 @@ static int __exit atmel_wm97xx_remove(struct platform_device *pdev)  }  #ifdef CONFIG_PM_SLEEP -static int atmel_wm97xx_suspend(struct *dev) +static int atmel_wm97xx_suspend(struct device *dev)  {  	struct platform_device *pdev = to_platform_device(dev);  	struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev); diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 59aa24002c7..6e0b4a2120d 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -2,6 +2,8 @@   * Atmel maXTouch Touchscreen driver   *   * Copyright (C) 2010 Samsung Electronics Co.Ltd + * Copyright (C) 2012 Google, Inc. + *   * Author: Joonyoung Shim <jy0922.shim@samsung.com>   *   * This program is free software; you can redistribute  it and/or modify it @@ -13,6 +15,7 @@  #include <linux/module.h>  #include <linux/init.h> +#include <linux/completion.h>  #include <linux/delay.h>  #include <linux/firmware.h>  #include <linux/i2c.h> @@ -26,12 +29,6 @@  #define MXT_VER_21		21  #define MXT_VER_22		22 -/* Slave addresses */ -#define MXT_APP_LOW		0x4a -#define MXT_APP_HIGH		0x4b -#define MXT_BOOT_LOW		0x24 -#define MXT_BOOT_HIGH		0x25 -  /* Firmware */  #define MXT_FW_NAME		"maxtouch.fw" @@ -84,6 +81,9 @@  #define MXT_COMMAND_REPORTALL	3  #define MXT_COMMAND_DIAGNOSTIC	5 +/* Define for T6 status byte */ +#define MXT_T6_STATUS_RESET	(1 << 7) +  /* MXT_GEN_POWER_T7 field */  #define MXT_POWER_IDLEACQINT	0  #define MXT_POWER_ACTVACQINT	1 @@ -100,33 +100,26 @@  /* MXT_TOUCH_MULTI_T9 field */  #define MXT_TOUCH_CTRL		0 -#define MXT_TOUCH_XORIGIN	1 -#define MXT_TOUCH_YORIGIN	2 -#define MXT_TOUCH_XSIZE		3 -#define MXT_TOUCH_YSIZE		4 -#define MXT_TOUCH_BLEN		6 -#define MXT_TOUCH_TCHTHR	7 -#define MXT_TOUCH_TCHDI		8 -#define MXT_TOUCH_ORIENT	9 -#define MXT_TOUCH_MOVHYSTI	11 -#define MXT_TOUCH_MOVHYSTN	12 -#define MXT_TOUCH_NUMTOUCH	14 -#define MXT_TOUCH_MRGHYST	15 -#define MXT_TOUCH_MRGTHR	16 -#define MXT_TOUCH_AMPHYST	17 -#define MXT_TOUCH_XRANGE_LSB	18 -#define MXT_TOUCH_XRANGE_MSB	19 -#define MXT_TOUCH_YRANGE_LSB	20 -#define MXT_TOUCH_YRANGE_MSB	21 -#define MXT_TOUCH_XLOCLIP	22 -#define MXT_TOUCH_XHICLIP	23 -#define MXT_TOUCH_YLOCLIP	24 -#define MXT_TOUCH_YHICLIP	25 -#define MXT_TOUCH_XEDGECTRL	26 -#define MXT_TOUCH_XEDGEDIST	27 -#define MXT_TOUCH_YEDGECTRL	28 -#define MXT_TOUCH_YEDGEDIST	29 -#define MXT_TOUCH_JUMPLIMIT	30 +#define MXT_T9_ORIENT		9 +#define MXT_T9_RANGE		18 + +/* MXT_TOUCH_MULTI_T9 status */ +#define MXT_T9_UNGRIP		(1 << 0) +#define MXT_T9_SUPPRESS		(1 << 1) +#define MXT_T9_AMP		(1 << 2) +#define MXT_T9_VECTOR		(1 << 3) +#define MXT_T9_MOVE		(1 << 4) +#define MXT_T9_RELEASE		(1 << 5) +#define MXT_T9_PRESS		(1 << 6) +#define MXT_T9_DETECT		(1 << 7) + +struct t9_range { +	u16 x; +	u16 y; +} __packed; + +/* MXT_TOUCH_MULTI_T9 orient */ +#define MXT_T9_ORIENT_SWITCH	(1 << 0)  /* MXT_PROCI_GRIPFACE_T20 field */  #define MXT_GRIPFACE_CTRL	0 @@ -175,17 +168,16 @@  /* Define for MXT_GEN_COMMAND_T6 */  #define MXT_BOOT_VALUE		0xa5 +#define MXT_RESET_VALUE		0x01  #define MXT_BACKUP_VALUE	0x55 + +/* Delay times */  #define MXT_BACKUP_TIME		50	/* msec */  #define MXT_RESET_TIME		200	/* msec */ - -#define MXT_FWRESET_TIME	175	/* msec */ - -/* MXT_SPT_GPIOPWM_T19 field */ -#define MXT_GPIO0_MASK		0x04 -#define MXT_GPIO1_MASK		0x08 -#define MXT_GPIO2_MASK		0x10 -#define MXT_GPIO3_MASK		0x20 +#define MXT_RESET_TIMEOUT	3000	/* msec */ +#define MXT_CRC_TIMEOUT		1000	/* msec */ +#define MXT_FW_RESET_TIME	3000	/* msec */ +#define MXT_FW_CHG_TIMEOUT	300	/* msec */  /* Command to unlock bootloader */  #define MXT_UNLOCK_CMD_MSB	0xaa @@ -199,21 +191,8 @@  #define MXT_FRAME_CRC_PASS	0x04  #define MXT_APP_CRC_FAIL	0x40	/* valid 7 8 bit only */  #define MXT_BOOT_STATUS_MASK	0x3f - -/* Touch status */ -#define MXT_UNGRIP		(1 << 0) -#define MXT_SUPPRESS		(1 << 1) -#define MXT_AMP			(1 << 2) -#define MXT_VECTOR		(1 << 3) -#define MXT_MOVE		(1 << 4) -#define MXT_RELEASE		(1 << 5) -#define MXT_PRESS		(1 << 6) -#define MXT_DETECT		(1 << 7) - -/* Touch orient bits */ -#define MXT_XY_SWITCH		(1 << 0) -#define MXT_X_INVERT		(1 << 1) -#define MXT_Y_INVERT		(1 << 2) +#define MXT_BOOT_EXTENDED_ID	(1 << 5) +#define MXT_BOOT_ID_MASK	0x1f  /* Touchscreen absolute values */  #define MXT_MAX_AREA		0xff @@ -233,8 +212,8 @@ struct mxt_info {  struct mxt_object {  	u8 type;  	u16 start_address; -	u8 size;		/* Size of each instance - 1 */ -	u8 instances;		/* Number of instances - 1 */ +	u8 size_minus_one; +	u8 instances_minus_one;  	u8 num_report_ids;  } __packed; @@ -251,19 +230,40 @@ struct mxt_data {  	const struct mxt_platform_data *pdata;  	struct mxt_object *object_table;  	struct mxt_info info; -	bool is_tp; -  	unsigned int irq;  	unsigned int max_x;  	unsigned int max_y; +	bool in_bootloader; +	u32 config_crc; +	u8 bootloader_addr;  	/* Cached parameters from object table */  	u8 T6_reportid; +	u16 T6_address;  	u8 T9_reportid_min;  	u8 T9_reportid_max;  	u8 T19_reportid; + +	/* for fw update in bootloader */ +	struct completion bl_completion; + +	/* for reset handling */ +	struct completion reset_completion; + +	/* for config update handling */ +	struct completion crc_completion;  }; +static size_t mxt_obj_size(const struct mxt_object *obj) +{ +	return obj->size_minus_one + 1; +} + +static size_t mxt_obj_instances(const struct mxt_object *obj) +{ +	return obj->instances_minus_one + 1; +} +  static bool mxt_object_readable(unsigned int type)  {  	switch (type) { @@ -335,60 +335,190 @@ static void mxt_dump_message(struct device *dev,  		message->reportid, 7, message->message);  } -static int mxt_check_bootloader(struct i2c_client *client, -				     unsigned int state) +static int mxt_wait_for_completion(struct mxt_data *data, +				   struct completion *comp, +				   unsigned int timeout_ms) +{ +	struct device *dev = &data->client->dev; +	unsigned long timeout = msecs_to_jiffies(timeout_ms); +	long ret; + +	ret = wait_for_completion_interruptible_timeout(comp, timeout); +	if (ret < 0) { +		return ret; +	} else if (ret == 0) { +		dev_err(dev, "Wait for completion timed out.\n"); +		return -ETIMEDOUT; +	} +	return 0; +} + +static int mxt_bootloader_read(struct mxt_data *data, +			       u8 *val, unsigned int count) +{ +	int ret; +	struct i2c_msg msg; + +	msg.addr = data->bootloader_addr; +	msg.flags = data->client->flags & I2C_M_TEN; +	msg.flags |= I2C_M_RD; +	msg.len = count; +	msg.buf = val; + +	ret = i2c_transfer(data->client->adapter, &msg, 1); + +	if (ret == 1) { +		ret = 0; +	} else { +		ret = ret < 0 ? ret : -EIO; +		dev_err(&data->client->dev, "%s: i2c recv failed (%d)\n", +			__func__, ret); +	} + +	return ret; +} + +static int mxt_bootloader_write(struct mxt_data *data, +				const u8 * const val, unsigned int count) +{ +	int ret; +	struct i2c_msg msg; + +	msg.addr = data->bootloader_addr; +	msg.flags = data->client->flags & I2C_M_TEN; +	msg.len = count; +	msg.buf = (u8 *)val; + +	ret = i2c_transfer(data->client->adapter, &msg, 1); +	if (ret == 1) { +		ret = 0; +	} else { +		ret = ret < 0 ? ret : -EIO; +		dev_err(&data->client->dev, "%s: i2c send failed (%d)\n", +			__func__, ret); +	} + +	return ret; +} + +static int mxt_lookup_bootloader_address(struct mxt_data *data) +{ +	u8 appmode = data->client->addr; +	u8 bootloader; + +	switch (appmode) { +	case 0x4a: +	case 0x4b: +	case 0x4c: +	case 0x4d: +	case 0x5a: +	case 0x5b: +		bootloader = appmode - 0x26; +		break; +	default: +		dev_err(&data->client->dev, +			"Appmode i2c address 0x%02x not found\n", +			appmode); +		return -EINVAL; +	} + +	data->bootloader_addr = bootloader; +	return 0; +} + +static u8 mxt_get_bootloader_version(struct mxt_data *data, u8 val) +{ +	struct device *dev = &data->client->dev; +	u8 buf[3]; + +	if (val & MXT_BOOT_EXTENDED_ID) { +		if (mxt_bootloader_read(data, &buf[0], 3) != 0) { +			dev_err(dev, "%s: i2c failure\n", __func__); +			return val; +		} + +		dev_dbg(dev, "Bootloader ID:%d Version:%d\n", buf[1], buf[2]); + +		return buf[0]; +	} else { +		dev_dbg(dev, "Bootloader ID:%d\n", val & MXT_BOOT_ID_MASK); + +		return val; +	} +} + +static int mxt_check_bootloader(struct mxt_data *data, unsigned int state)  { +	struct device *dev = &data->client->dev;  	u8 val; +	int ret;  recheck: -	if (i2c_master_recv(client, &val, 1) != 1) { -		dev_err(&client->dev, "%s: i2c recv failed\n", __func__); -		return -EIO; +	if (state != MXT_WAITING_BOOTLOAD_CMD) { +		/* +		 * In application update mode, the interrupt +		 * line signals state transitions. We must wait for the +		 * CHG assertion before reading the status byte. +		 * Once the status byte has been read, the line is deasserted. +		 */ +		ret = mxt_wait_for_completion(data, &data->bl_completion, +					      MXT_FW_CHG_TIMEOUT); +		if (ret) { +			/* +			 * TODO: handle -ERESTARTSYS better by terminating +			 * fw update process before returning to userspace +			 * by writing length 0x000 to device (iff we are in +			 * WAITING_FRAME_DATA state). +			 */ +			dev_err(dev, "Update wait error %d\n", ret); +			return ret; +		}  	} +	ret = mxt_bootloader_read(data, &val, 1); +	if (ret) +		return ret; + +	if (state == MXT_WAITING_BOOTLOAD_CMD) +		val = mxt_get_bootloader_version(data, val); +  	switch (state) {  	case MXT_WAITING_BOOTLOAD_CMD:  	case MXT_WAITING_FRAME_DATA:  		val &= ~MXT_BOOT_STATUS_MASK;  		break;  	case MXT_FRAME_CRC_PASS: -		if (val == MXT_FRAME_CRC_CHECK) +		if (val == MXT_FRAME_CRC_CHECK) {  			goto recheck; +		} else if (val == MXT_FRAME_CRC_FAIL) { +			dev_err(dev, "Bootloader CRC fail\n"); +			return -EINVAL; +		}  		break;  	default:  		return -EINVAL;  	}  	if (val != state) { -		dev_err(&client->dev, "Unvalid bootloader mode state\n"); +		dev_err(dev, "Invalid bootloader state %02X != %02X\n", +			val, state);  		return -EINVAL;  	}  	return 0;  } -static int mxt_unlock_bootloader(struct i2c_client *client) +static int mxt_unlock_bootloader(struct mxt_data *data)  { +	int ret;  	u8 buf[2];  	buf[0] = MXT_UNLOCK_CMD_LSB;  	buf[1] = MXT_UNLOCK_CMD_MSB; -	if (i2c_master_send(client, buf, 2) != 2) { -		dev_err(&client->dev, "%s: i2c send failed\n", __func__); -		return -EIO; -	} - -	return 0; -} - -static int mxt_fw_write(struct i2c_client *client, -			     const u8 *data, unsigned int frame_size) -{ -	if (i2c_master_send(client, data, frame_size) != frame_size) { -		dev_err(&client->dev, "%s: i2c send failed\n", __func__); -		return -EIO; -	} +	ret = mxt_bootloader_write(data, buf, 2); +	if (ret) +		return ret;  	return 0;  } @@ -428,11 +558,6 @@ static int __mxt_read_reg(struct i2c_client *client,  	return ret;  } -static int mxt_read_reg(struct i2c_client *client, u16 reg, u8 *val) -{ -	return __mxt_read_reg(client, reg, 1, val); -} -  static int __mxt_write_reg(struct i2c_client *client, u16 reg, u16 len,  			   const void *val)  { @@ -480,7 +605,7 @@ mxt_get_object(struct mxt_data *data, u8 type)  			return object;  	} -	dev_err(&data->client->dev, "Invalid object type\n"); +	dev_err(&data->client->dev, "Invalid object type T%u\n", type);  	return NULL;  } @@ -506,7 +631,7 @@ static int mxt_write_object(struct mxt_data *data,  	u16 reg;  	object = mxt_get_object(data, type); -	if (!object || offset >= object->size + 1) +	if (!object || offset >= mxt_obj_size(object))  		return -EINVAL;  	reg = object->start_address; @@ -516,18 +641,25 @@ static int mxt_write_object(struct mxt_data *data,  static void mxt_input_button(struct mxt_data *data, struct mxt_message *message)  {  	struct input_dev *input = data->input_dev; +	const struct mxt_platform_data *pdata = data->pdata;  	bool button;  	int i;  	/* Active-low switch */ -	for (i = 0; i < MXT_NUM_GPIO; i++) { -		if (data->pdata->key_map[i] == KEY_RESERVED) +	for (i = 0; i < pdata->t19_num_keys; i++) { +		if (pdata->t19_keymap[i] == KEY_RESERVED)  			continue; -		button = !(message->message[0] & MXT_GPIO0_MASK << i); -		input_report_key(input, data->pdata->key_map[i], button); +		button = !(message->message[0] & (1 << i)); +		input_report_key(input, pdata->t19_keymap[i], button);  	}  } +static void mxt_input_sync(struct input_dev *input_dev) +{ +	input_mt_report_pointer_emulation(input_dev, false); +	input_sync(input_dev); +} +  static void mxt_input_touchevent(struct mxt_data *data,  				      struct mxt_message *message, int id)  { @@ -537,44 +669,60 @@ static void mxt_input_touchevent(struct mxt_data *data,  	int x;  	int y;  	int area; -	int pressure; +	int amplitude;  	x = (message->message[1] << 4) | ((message->message[3] >> 4) & 0xf);  	y = (message->message[2] << 4) | ((message->message[3] & 0xf)); + +	/* Handle 10/12 bit switching */  	if (data->max_x < 1024) -		x = x >> 2; +		x >>= 2;  	if (data->max_y < 1024) -		y = y >> 2; +		y >>= 2;  	area = message->message[4]; -	pressure = message->message[5]; +	amplitude = message->message[5];  	dev_dbg(dev,  		"[%u] %c%c%c%c%c%c%c%c x: %5u y: %5u area: %3u amp: %3u\n",  		id, -		(status & MXT_DETECT) ? 'D' : '.', -		(status & MXT_PRESS) ? 'P' : '.', -		(status & MXT_RELEASE) ? 'R' : '.', -		(status & MXT_MOVE) ? 'M' : '.', -		(status & MXT_VECTOR) ? 'V' : '.', -		(status & MXT_AMP) ? 'A' : '.', -		(status & MXT_SUPPRESS) ? 'S' : '.', -		(status & MXT_UNGRIP) ? 'U' : '.', -		x, y, area, pressure); +		(status & MXT_T9_DETECT) ? 'D' : '.', +		(status & MXT_T9_PRESS) ? 'P' : '.', +		(status & MXT_T9_RELEASE) ? 'R' : '.', +		(status & MXT_T9_MOVE) ? 'M' : '.', +		(status & MXT_T9_VECTOR) ? 'V' : '.', +		(status & MXT_T9_AMP) ? 'A' : '.', +		(status & MXT_T9_SUPPRESS) ? 'S' : '.', +		(status & MXT_T9_UNGRIP) ? 'U' : '.', +		x, y, area, amplitude);  	input_mt_slot(input_dev, id); -	input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, -				   status & MXT_DETECT); -	if (status & MXT_DETECT) { +	if (status & MXT_T9_DETECT) { +		/* +		 * Multiple bits may be set if the host is slow to read +		 * the status messages, indicating all the events that +		 * have happened. +		 */ +		if (status & MXT_T9_RELEASE) { +			input_mt_report_slot_state(input_dev, +						   MT_TOOL_FINGER, 0); +			mxt_input_sync(input_dev); +		} + +		/* Touch active */ +		input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 1);  		input_report_abs(input_dev, ABS_MT_POSITION_X, x);  		input_report_abs(input_dev, ABS_MT_POSITION_Y, y); -		input_report_abs(input_dev, ABS_MT_PRESSURE, pressure); +		input_report_abs(input_dev, ABS_MT_PRESSURE, amplitude);  		input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, area); +	} else { +		/* Touch no longer active, close out slot */ +		input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0);  	}  } -static unsigned mxt_extract_T6_csum(const u8 *csum) +static u16 mxt_extract_T6_csum(const u8 *csum)  {  	return csum[0] | (csum[1] << 8) | (csum[2] << 16);  } @@ -585,28 +733,37 @@ static bool mxt_is_T9_message(struct mxt_data *data, struct mxt_message *msg)  	return (id >= data->T9_reportid_min && id <= data->T9_reportid_max);  } -static irqreturn_t mxt_interrupt(int irq, void *dev_id) +static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)  { -	struct mxt_data *data = dev_id;  	struct mxt_message message;  	const u8 *payload = &message.message[0];  	struct device *dev = &data->client->dev;  	u8 reportid;  	bool update_input = false; +	u32 crc;  	do {  		if (mxt_read_message(data, &message)) {  			dev_err(dev, "Failed to read message\n"); -			goto end; +			return IRQ_NONE;  		}  		reportid = message.reportid;  		if (reportid == data->T6_reportid) {  			u8 status = payload[0]; -			unsigned csum = mxt_extract_T6_csum(&payload[1]); + +			crc = mxt_extract_T6_csum(&payload[1]); +			if (crc != data->config_crc) { +				data->config_crc = crc; +				complete(&data->crc_completion); +			} +  			dev_dbg(dev, "Status: %02x Config Checksum: %06x\n", -				status, csum); +				status, data->config_crc); + +			if (status & MXT_T6_STATUS_RESET) +				complete(&data->reset_completion);  		} else if (mxt_is_T9_message(data, &message)) {  			int id = reportid - data->T9_reportid_min;  			mxt_input_touchevent(data, &message, id); @@ -619,15 +776,96 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)  		}  	} while (reportid != 0xff); -	if (update_input) { -		input_mt_report_pointer_emulation(data->input_dev, false); -		input_sync(data->input_dev); -	} +	if (update_input) +		mxt_input_sync(data->input_dev); -end:  	return IRQ_HANDLED;  } +static irqreturn_t mxt_interrupt(int irq, void *dev_id) +{ +	struct mxt_data *data = dev_id; + +	if (data->in_bootloader) { +		/* bootloader state transition completion */ +		complete(&data->bl_completion); +		return IRQ_HANDLED; +	} + +	return mxt_process_messages_until_invalid(data); +} + +static int mxt_t6_command(struct mxt_data *data, u16 cmd_offset, +			  u8 value, bool wait) +{ +	u16 reg; +	u8 command_register; +	int timeout_counter = 0; +	int ret; + +	reg = data->T6_address + cmd_offset; + +	ret = mxt_write_reg(data->client, reg, value); +	if (ret) +		return ret; + +	if (!wait) +		return 0; + +	do { +		msleep(20); +		ret = __mxt_read_reg(data->client, reg, 1, &command_register); +		if (ret) +			return ret; +	} while (command_register != 0 && timeout_counter++ <= 100); + +	if (timeout_counter > 100) { +		dev_err(&data->client->dev, "Command failed!\n"); +		return -EIO; +	} + +	return 0; +} + +static int mxt_soft_reset(struct mxt_data *data) +{ +	struct device *dev = &data->client->dev; +	int ret = 0; + +	dev_info(dev, "Resetting chip\n"); + +	reinit_completion(&data->reset_completion); + +	ret = mxt_t6_command(data, MXT_COMMAND_RESET, MXT_RESET_VALUE, false); +	if (ret) +		return ret; + +	ret = mxt_wait_for_completion(data, &data->reset_completion, +				      MXT_RESET_TIMEOUT); +	if (ret) +		return ret; + +	return 0; +} + +static void mxt_update_crc(struct mxt_data *data, u8 cmd, u8 value) +{ +	/* +	 * On failure, CRC is set to 0 and config will always be +	 * downloaded. +	 */ +	data->config_crc = 0; +	reinit_completion(&data->crc_completion); + +	mxt_t6_command(data, cmd, value, true); + +	/* +	 * Wait for crc message. On failure, CRC is set to 0 and config will +	 * always be downloaded. +	 */ +	mxt_wait_for_completion(data, &data->crc_completion, MXT_CRC_TIMEOUT); +} +  static int mxt_check_reg_init(struct mxt_data *data)  {  	const struct mxt_platform_data *pdata = data->pdata; @@ -642,13 +880,23 @@ static int mxt_check_reg_init(struct mxt_data *data)  		return 0;  	} +	mxt_update_crc(data, MXT_COMMAND_REPORTALL, 1); + +	if (data->config_crc == pdata->config_crc) { +		dev_info(dev, "Config CRC 0x%06X: OK\n", data->config_crc); +		return 0; +	} + +	dev_info(dev, "Config CRC 0x%06X: does not match 0x%06X\n", +		 data->config_crc, pdata->config_crc); +  	for (i = 0; i < data->info.object_num; i++) {  		object = data->object_table + i;  		if (!mxt_object_writable(object->type))  			continue; -		size = (object->size + 1) * (object->instances + 1); +		size = mxt_obj_size(object) * mxt_obj_instances(object);  		if (index + size > pdata->config_length) {  			dev_err(dev, "Not enough config data!\n");  			return -EINVAL; @@ -661,6 +909,14 @@ static int mxt_check_reg_init(struct mxt_data *data)  		index += size;  	} +	mxt_update_crc(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE); + +	ret = mxt_soft_reset(data); +	if (ret) +		return ret; + +	dev_info(dev, "Config successfully updated\n"); +  	return 0;  } @@ -686,54 +942,6 @@ static int mxt_make_highchg(struct mxt_data *data)  	return 0;  } -static void mxt_handle_pdata(struct mxt_data *data) -{ -	const struct mxt_platform_data *pdata = data->pdata; -	u8 voltage; - -	/* Set touchscreen lines */ -	mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_XSIZE, -			pdata->x_line); -	mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_YSIZE, -			pdata->y_line); - -	/* Set touchscreen orient */ -	mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_ORIENT, -			pdata->orient); - -	/* Set touchscreen burst length */ -	mxt_write_object(data, MXT_TOUCH_MULTI_T9, -			MXT_TOUCH_BLEN, pdata->blen); - -	/* Set touchscreen threshold */ -	mxt_write_object(data, MXT_TOUCH_MULTI_T9, -			MXT_TOUCH_TCHTHR, pdata->threshold); - -	/* Set touchscreen resolution */ -	mxt_write_object(data, MXT_TOUCH_MULTI_T9, -			MXT_TOUCH_XRANGE_LSB, (pdata->x_size - 1) & 0xff); -	mxt_write_object(data, MXT_TOUCH_MULTI_T9, -			MXT_TOUCH_XRANGE_MSB, (pdata->x_size - 1) >> 8); -	mxt_write_object(data, MXT_TOUCH_MULTI_T9, -			MXT_TOUCH_YRANGE_LSB, (pdata->y_size - 1) & 0xff); -	mxt_write_object(data, MXT_TOUCH_MULTI_T9, -			MXT_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8); - -	/* Set touchscreen voltage */ -	if (pdata->voltage) { -		if (pdata->voltage < MXT_VOLTAGE_DEFAULT) { -			voltage = (MXT_VOLTAGE_DEFAULT - pdata->voltage) / -				MXT_VOLTAGE_STEP; -			voltage = 0xff - voltage + 1; -		} else -			voltage = (pdata->voltage - MXT_VOLTAGE_DEFAULT) / -				MXT_VOLTAGE_STEP; - -		mxt_write_object(data, MXT_SPT_CTECONFIG_T28, -				MXT_CTE_VOLTAGE, voltage); -	} -} -  static int mxt_get_info(struct mxt_data *data)  {  	struct i2c_client *client = data->client; @@ -773,7 +981,7 @@ static int mxt_get_object_table(struct mxt_data *data)  		if (object->num_report_ids) {  			min_id = reportid;  			reportid += object->num_report_ids * -					(object->instances + 1); +					mxt_obj_instances(object);  			max_id = reportid - 1;  		} else {  			min_id = 0; @@ -781,13 +989,15 @@ static int mxt_get_object_table(struct mxt_data *data)  		}  		dev_dbg(&data->client->dev, -			"Type %2d Start %3d Size %3d Instances %2d ReportIDs %3u : %3u\n", -			object->type, object->start_address, object->size + 1, -			object->instances + 1, min_id, max_id); +			"T%u Start:%u Size:%zu Instances:%zu Report IDs:%u-%u\n", +			object->type, object->start_address, +			mxt_obj_size(object), mxt_obj_instances(object), +			min_id, max_id);  		switch (object->type) {  		case MXT_GEN_COMMAND_T6:  			data->T6_reportid = min_id; +			data->T6_address = object->start_address;  			break;  		case MXT_TOUCH_MULTI_T9:  			data->T9_reportid_min = min_id; @@ -812,12 +1022,59 @@ static void mxt_free_object_table(struct mxt_data *data)  	data->T19_reportid = 0;  } +static int mxt_read_t9_resolution(struct mxt_data *data) +{ +	struct i2c_client *client = data->client; +	int error; +	struct t9_range range; +	unsigned char orient; +	struct mxt_object *object; + +	object = mxt_get_object(data, MXT_TOUCH_MULTI_T9); +	if (!object) +		return -EINVAL; + +	error = __mxt_read_reg(client, +			       object->start_address + MXT_T9_RANGE, +			       sizeof(range), &range); +	if (error) +		return error; + +	le16_to_cpus(&range.x); +	le16_to_cpus(&range.y); + +	error =  __mxt_read_reg(client, +				object->start_address + MXT_T9_ORIENT, +				1, &orient); +	if (error) +		return error; + +	/* Handle default values */ +	if (range.x == 0) +		range.x = 1023; + +	if (range.y == 0) +		range.y = 1023; + +	if (orient & MXT_T9_ORIENT_SWITCH) { +		data->max_x = range.y; +		data->max_y = range.x; +	} else { +		data->max_x = range.x; +		data->max_y = range.y; +	} + +	dev_dbg(&client->dev, +		"Touchscreen size X%uY%u\n", data->max_x, data->max_y); + +	return 0; +} +  static int mxt_initialize(struct mxt_data *data)  {  	struct i2c_client *client = data->client;  	struct mxt_info *info = &data->info;  	int error; -	u8 val;  	error = mxt_get_info(data);  	if (error) @@ -833,47 +1090,29 @@ static int mxt_initialize(struct mxt_data *data)  	/* Get object table information */  	error = mxt_get_object_table(data); -	if (error) +	if (error) { +		dev_err(&client->dev, "Error %d reading object table\n", error);  		goto err_free_object_table; +	}  	/* Check register init values */  	error = mxt_check_reg_init(data); -	if (error) -		goto err_free_object_table; - -	mxt_handle_pdata(data); - -	/* Backup to memory */ -	mxt_write_object(data, MXT_GEN_COMMAND_T6, -			MXT_COMMAND_BACKUPNV, -			MXT_BACKUP_VALUE); -	msleep(MXT_BACKUP_TIME); - -	/* Soft reset */ -	mxt_write_object(data, MXT_GEN_COMMAND_T6, -			MXT_COMMAND_RESET, 1); -	msleep(MXT_RESET_TIME); - -	/* Update matrix size at info struct */ -	error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val); -	if (error) +	if (error) { +		dev_err(&client->dev, "Error %d initializing configuration\n", +			error);  		goto err_free_object_table; -	info->matrix_xsize = val; +	} -	error = mxt_read_reg(client, MXT_MATRIX_Y_SIZE, &val); -	if (error) +	error = mxt_read_t9_resolution(data); +	if (error) { +		dev_err(&client->dev, "Failed to initialize T9 resolution\n");  		goto err_free_object_table; -	info->matrix_ysize = val; - -	dev_info(&client->dev, -			"Family ID: %u Variant ID: %u Major.Minor.Build: %u.%u.%02X\n", -			info->family_id, info->variant_id, info->version >> 4, -			info->version & 0xf, info->build); +	}  	dev_info(&client->dev, -			"Matrix X Size: %u Matrix Y Size: %u Object Num: %u\n", -			info->matrix_xsize, info->matrix_ysize, -			info->object_num); +		 "Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n", +		 info->family_id, info->variant_id, info->version >> 4, +		 info->version & 0xf, info->build, info->object_num);  	return 0; @@ -882,20 +1121,6 @@ err_free_object_table:  	return error;  } -static void mxt_calc_resolution(struct mxt_data *data) -{ -	unsigned int max_x = data->pdata->x_size - 1; -	unsigned int max_y = data->pdata->y_size - 1; - -	if (data->pdata->orient & MXT_XY_SWITCH) { -		data->max_x = max_y; -		data->max_y = max_x; -	} else { -		data->max_x = max_x; -		data->max_y = max_y; -	} -} -  /* Firmware Version is returned as Major.Minor.Build */  static ssize_t mxt_fw_version_show(struct device *dev,  				   struct device_attribute *attr, char *buf) @@ -922,11 +1147,11 @@ static ssize_t mxt_show_instance(char *buf, int count,  {  	int i; -	if (object->instances > 0) +	if (mxt_obj_instances(object) > 1)  		count += scnprintf(buf + count, PAGE_SIZE - count,  				   "Instance %u\n", instance); -	for (i = 0; i < object->size + 1; i++) +	for (i = 0; i < mxt_obj_size(object); i++)  		count += scnprintf(buf + count, PAGE_SIZE - count,  				"\t[%2u]: %02x (%d)\n", i, val[i], val[i]);  	count += scnprintf(buf + count, PAGE_SIZE - count, "\n"); @@ -959,8 +1184,8 @@ static ssize_t mxt_object_show(struct device *dev,  		count += scnprintf(buf + count, PAGE_SIZE - count,  				"T%u:\n", object->type); -		for (j = 0; j < object->instances + 1; j++) { -			u16 size = object->size + 1; +		for (j = 0; j < mxt_obj_instances(object); j++) { +			u16 size = mxt_obj_size(object);  			u16 addr = object->start_address + j * size;  			error = __mxt_read_reg(data->client, addr, size, obuf); @@ -976,13 +1201,38 @@ done:  	return error ?: count;  } +static int mxt_check_firmware_format(struct device *dev, +				     const struct firmware *fw) +{ +	unsigned int pos = 0; +	char c; + +	while (pos < fw->size) { +		c = *(fw->data + pos); + +		if (c < '0' || (c > '9' && c < 'A') || c > 'F') +			return 0; + +		pos++; +	} + +	/* +	 * To convert file try: +	 * xxd -r -p mXTXXX__APP_VX-X-XX.enc > maxtouch.fw +	 */ +	dev_err(dev, "Aborting: firmware file must be in binary format\n"); + +	return -EINVAL; +} +  static int mxt_load_fw(struct device *dev, const char *fn)  {  	struct mxt_data *data = dev_get_drvdata(dev); -	struct i2c_client *client = data->client;  	const struct firmware *fw = NULL;  	unsigned int frame_size;  	unsigned int pos = 0; +	unsigned int retry = 0; +	unsigned int frame = 0;  	int ret;  	ret = request_firmware(&fw, fn, dev); @@ -991,59 +1241,91 @@ static int mxt_load_fw(struct device *dev, const char *fn)  		return ret;  	} +	/* Check for incorrect enc file */ +	ret = mxt_check_firmware_format(dev, fw); +	if (ret) +		goto release_firmware; + +	ret = mxt_lookup_bootloader_address(data); +	if (ret) +		goto release_firmware; +  	/* Change to the bootloader mode */ -	mxt_write_object(data, MXT_GEN_COMMAND_T6, -			MXT_COMMAND_RESET, MXT_BOOT_VALUE); +	data->in_bootloader = true; + +	ret = mxt_t6_command(data, MXT_COMMAND_RESET, MXT_BOOT_VALUE, false); +	if (ret) +		goto release_firmware; +  	msleep(MXT_RESET_TIME); -	/* Change to slave address of bootloader */ -	if (client->addr == MXT_APP_LOW) -		client->addr = MXT_BOOT_LOW; -	else -		client->addr = MXT_BOOT_HIGH; +	reinit_completion(&data->bl_completion); -	ret = mxt_check_bootloader(client, MXT_WAITING_BOOTLOAD_CMD); +	ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD);  	if (ret) -		goto out; +		goto disable_irq;  	/* Unlock bootloader */ -	mxt_unlock_bootloader(client); +	mxt_unlock_bootloader(data);  	while (pos < fw->size) { -		ret = mxt_check_bootloader(client, -						MXT_WAITING_FRAME_DATA); +		ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA);  		if (ret) -			goto out; +			goto disable_irq;  		frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1)); -		/* We should add 2 at frame size as the the firmware data is not -		 * included the CRC bytes. -		 */ +		/* Take account of CRC bytes */  		frame_size += 2;  		/* Write one frame to device */ -		mxt_fw_write(client, fw->data + pos, frame_size); - -		ret = mxt_check_bootloader(client, -						MXT_FRAME_CRC_PASS); +		ret = mxt_bootloader_write(data, fw->data + pos, frame_size);  		if (ret) -			goto out; +			goto disable_irq; -		pos += frame_size; +		ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS); +		if (ret) { +			retry++; -		dev_dbg(dev, "Updated %d bytes / %zd bytes\n", pos, fw->size); +			/* Back off by 20ms per retry */ +			msleep(retry * 20); + +			if (retry > 20) { +				dev_err(dev, "Retry count exceeded\n"); +				goto disable_irq; +			} +		} else { +			retry = 0; +			pos += frame_size; +			frame++; +		} + +		if (frame % 50 == 0) +			dev_dbg(dev, "Sent %d frames, %d/%zd bytes\n", +				frame, pos, fw->size);  	} -out: -	release_firmware(fw); +	/* Wait for flash. */ +	ret = mxt_wait_for_completion(data, &data->bl_completion, +				      MXT_FW_RESET_TIME); +	if (ret) +		goto disable_irq; -	/* Change to slave address of application */ -	if (client->addr == MXT_BOOT_LOW) -		client->addr = MXT_APP_LOW; -	else -		client->addr = MXT_APP_HIGH; +	dev_dbg(dev, "Sent %d frames, %d bytes\n", frame, pos); +	/* +	 * Wait for device to reset. Some bootloader versions do not assert +	 * the CHG line after bootloading has finished, so ignore potential +	 * errors. +	 */ +	mxt_wait_for_completion(data, &data->bl_completion, MXT_FW_RESET_TIME); + +	data->in_bootloader = false; + +disable_irq: +	disable_irq(data->irq); +release_firmware: +	release_firmware(fw);  	return ret;  } @@ -1054,28 +1336,23 @@ static ssize_t mxt_update_fw_store(struct device *dev,  	struct mxt_data *data = dev_get_drvdata(dev);  	int error; -	disable_irq(data->irq); -  	error = mxt_load_fw(dev, MXT_FW_NAME);  	if (error) {  		dev_err(dev, "The firmware update failed(%d)\n", error);  		count = error;  	} else { -		dev_dbg(dev, "The firmware update succeeded\n"); - -		/* Wait for reset */ -		msleep(MXT_FWRESET_TIME); +		dev_info(dev, "The firmware update succeeded\n");  		mxt_free_object_table(data);  		mxt_initialize(data); -	} -	enable_irq(data->irq); +		enable_irq(data->irq); -	error = mxt_make_highchg(data); -	if (error) -		return error; +		error = mxt_make_highchg(data); +		if (error) +			return error; +	}  	return count;  } @@ -1130,11 +1407,13 @@ static void mxt_input_close(struct input_dev *dev)  static int mxt_probe(struct i2c_client *client,  		const struct i2c_device_id *id)  { -	const struct mxt_platform_data *pdata = client->dev.platform_data; +	const struct mxt_platform_data *pdata = dev_get_platdata(&client->dev);  	struct mxt_data *data;  	struct input_dev *input_dev;  	int error;  	unsigned int num_mt_slots; +	unsigned int mt_flags = 0; +	int i;  	if (!pdata)  		return -EINVAL; @@ -1147,10 +1426,7 @@ static int mxt_probe(struct i2c_client *client,  		goto err_free_mem;  	} -	data->is_tp = pdata && pdata->is_tp; - -	input_dev->name = (data->is_tp) ? "Atmel maXTouch Touchpad" : -					  "Atmel maXTouch Touchscreen"; +	input_dev->name = "Atmel maXTouch Touchscreen";  	snprintf(data->phys, sizeof(data->phys), "i2c-%u-%04x/input0",  		 client->adapter->nr, client->addr); @@ -1166,7 +1442,9 @@ static int mxt_probe(struct i2c_client *client,  	data->pdata = pdata;  	data->irq = client->irq; -	mxt_calc_resolution(data); +	init_completion(&data->bl_completion); +	init_completion(&data->reset_completion); +	init_completion(&data->crc_completion);  	error = mxt_initialize(data);  	if (error) @@ -1176,20 +1454,15 @@ static int mxt_probe(struct i2c_client *client,  	__set_bit(EV_KEY, input_dev->evbit);  	__set_bit(BTN_TOUCH, input_dev->keybit); -	if (data->is_tp) { -		int i; -		__set_bit(INPUT_PROP_POINTER, input_dev->propbit); +	if (pdata->t19_num_keys) {  		__set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit); -		for (i = 0; i < MXT_NUM_GPIO; i++) -			if (pdata->key_map[i] != KEY_RESERVED) -				__set_bit(pdata->key_map[i], input_dev->keybit); +		for (i = 0; i < pdata->t19_num_keys; i++) +			if (pdata->t19_keymap[i] != KEY_RESERVED) +				input_set_capability(input_dev, EV_KEY, +						     pdata->t19_keymap[i]); -		__set_bit(BTN_TOOL_FINGER, input_dev->keybit); -		__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); -		__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); -		__set_bit(BTN_TOOL_QUADTAP, input_dev->keybit); -		__set_bit(BTN_TOOL_QUINTTAP, input_dev->keybit); +		mt_flags |= INPUT_MT_POINTER;  		input_abs_set_res(input_dev, ABS_X, MXT_PIXELS_PER_MM);  		input_abs_set_res(input_dev, ABS_Y, MXT_PIXELS_PER_MM); @@ -1197,6 +1470,8 @@ static int mxt_probe(struct i2c_client *client,  				  MXT_PIXELS_PER_MM);  		input_abs_set_res(input_dev, ABS_MT_POSITION_Y,  				  MXT_PIXELS_PER_MM); + +		input_dev->name = "Atmel maXTouch Touchpad";  	}  	/* For single touch */ @@ -1209,7 +1484,7 @@ static int mxt_probe(struct i2c_client *client,  	/* For multi touch */  	num_mt_slots = data->T9_reportid_max - data->T9_reportid_min + 1; -	error = input_mt_init_slots(input_dev, num_mt_slots, 0); +	error = input_mt_init_slots(input_dev, num_mt_slots, mt_flags);  	if (error)  		goto err_free_object;  	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, @@ -1237,12 +1512,18 @@ static int mxt_probe(struct i2c_client *client,  		goto err_free_irq;  	error = input_register_device(input_dev); -	if (error) +	if (error) { +		dev_err(&client->dev, "Error %d registering input device\n", +			error);  		goto err_free_irq; +	}  	error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group); -	if (error) +	if (error) { +		dev_err(&client->dev, "Failure %d creating sysfs group\n", +			error);  		goto err_unregister_device; +	}  	return 0; @@ -1295,11 +1576,7 @@ static int mxt_resume(struct device *dev)  	struct mxt_data *data = i2c_get_clientdata(client);  	struct input_dev *input_dev = data->input_dev; -	/* Soft reset */ -	mxt_write_object(data, MXT_GEN_COMMAND_T6, -			MXT_COMMAND_RESET, 1); - -	msleep(MXT_RESET_TIME); +	mxt_soft_reset(data);  	mutex_lock(&input_dev->mutex); diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c deleted file mode 100644 index bddabc59507..00000000000 --- a/drivers/input/touchscreen/atmel_tsadcc.c +++ /dev/null @@ -1,359 +0,0 @@ -/* - *  Atmel Touch Screen Driver - * - *  Copyright (c) 2008 ATMEL - *  Copyright (c) 2008 Dan Liang - *  Copyright (c) 2008 TimeSys Corporation - *  Copyright (c) 2008 Justin Waters - * - *  Based on touchscreen code from Atmel Corporation. - * - *  This program is free software; you can redistribute it and/or modify - *  it under the terms of the GNU General Public License version 2 as - *  published by the Free Software Foundation. - */ -#include <linux/init.h> -#include <linux/err.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/input.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/clk.h> -#include <linux/platform_device.h> -#include <linux/io.h> -#include <linux/platform_data/atmel.h> -#include <mach/cpu.h> - -/* Register definitions based on AT91SAM9RL64 preliminary draft datasheet */ - -#define ATMEL_TSADCC_CR		0x00	/* Control register */ -#define   ATMEL_TSADCC_SWRST	(1 << 0)	/* Software Reset*/ -#define	  ATMEL_TSADCC_START	(1 << 1)	/* Start conversion */ - -#define ATMEL_TSADCC_MR		0x04	/* Mode register */ -#define	  ATMEL_TSADCC_TSAMOD	(3    <<  0)	/* ADC mode */ -#define	    ATMEL_TSADCC_TSAMOD_ADC_ONLY_MODE	(0x0)	/* ADC Mode */ -#define	    ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE	(0x1)	/* Touch Screen Only Mode */ -#define	  ATMEL_TSADCC_LOWRES	(1    <<  4)	/* Resolution selection */ -#define	  ATMEL_TSADCC_SLEEP	(1    <<  5)	/* Sleep mode */ -#define	  ATMEL_TSADCC_PENDET	(1    <<  6)	/* Pen Detect selection */ -#define	  ATMEL_TSADCC_PRES	(1    <<  7)	/* Pressure Measurement Selection */ -#define	  ATMEL_TSADCC_PRESCAL	(0x3f <<  8)	/* Prescalar Rate Selection */ -#define	  ATMEL_TSADCC_EPRESCAL	(0xff <<  8)	/* Prescalar Rate Selection (Extended) */ -#define	  ATMEL_TSADCC_STARTUP	(0x7f << 16)	/* Start Up time */ -#define	  ATMEL_TSADCC_SHTIM	(0xf  << 24)	/* Sample & Hold time */ -#define	  ATMEL_TSADCC_PENDBC	(0xf  << 28)	/* Pen Detect debouncing time */ - -#define ATMEL_TSADCC_TRGR	0x08	/* Trigger register */ -#define	  ATMEL_TSADCC_TRGMOD	(7      <<  0)	/* Trigger mode */ -#define	    ATMEL_TSADCC_TRGMOD_NONE		(0 << 0) -#define     ATMEL_TSADCC_TRGMOD_EXT_RISING	(1 << 0) -#define     ATMEL_TSADCC_TRGMOD_EXT_FALLING	(2 << 0) -#define     ATMEL_TSADCC_TRGMOD_EXT_ANY		(3 << 0) -#define     ATMEL_TSADCC_TRGMOD_PENDET		(4 << 0) -#define     ATMEL_TSADCC_TRGMOD_PERIOD		(5 << 0) -#define     ATMEL_TSADCC_TRGMOD_CONTINUOUS	(6 << 0) -#define   ATMEL_TSADCC_TRGPER	(0xffff << 16)	/* Trigger period */ - -#define ATMEL_TSADCC_TSR	0x0C	/* Touch Screen register */ -#define	  ATMEL_TSADCC_TSFREQ	(0xf <<  0)	/* TS Frequency in Interleaved mode */ -#define	  ATMEL_TSADCC_TSSHTIM	(0xf << 24)	/* Sample & Hold time */ - -#define ATMEL_TSADCC_CHER	0x10	/* Channel Enable register */ -#define ATMEL_TSADCC_CHDR	0x14	/* Channel Disable register */ -#define ATMEL_TSADCC_CHSR	0x18	/* Channel Status register */ -#define	  ATMEL_TSADCC_CH(n)	(1 << (n))	/* Channel number */ - -#define ATMEL_TSADCC_SR		0x1C	/* Status register */ -#define	  ATMEL_TSADCC_EOC(n)	(1 << ((n)+0))	/* End of conversion for channel N */ -#define	  ATMEL_TSADCC_OVRE(n)	(1 << ((n)+8))	/* Overrun error for channel N */ -#define	  ATMEL_TSADCC_DRDY	(1 << 16)	/* Data Ready */ -#define	  ATMEL_TSADCC_GOVRE	(1 << 17)	/* General Overrun Error */ -#define	  ATMEL_TSADCC_ENDRX	(1 << 18)	/* End of RX Buffer */ -#define	  ATMEL_TSADCC_RXBUFF	(1 << 19)	/* TX Buffer full */ -#define	  ATMEL_TSADCC_PENCNT	(1 << 20)	/* Pen contact */ -#define	  ATMEL_TSADCC_NOCNT	(1 << 21)	/* No contact */ - -#define ATMEL_TSADCC_LCDR	0x20	/* Last Converted Data register */ -#define	  ATMEL_TSADCC_DATA	(0x3ff << 0)	/* Channel data */ - -#define ATMEL_TSADCC_IER	0x24	/* Interrupt Enable register */ -#define ATMEL_TSADCC_IDR	0x28	/* Interrupt Disable register */ -#define ATMEL_TSADCC_IMR	0x2C	/* Interrupt Mask register */ -#define ATMEL_TSADCC_CDR0	0x30	/* Channel Data 0 */ -#define ATMEL_TSADCC_CDR1	0x34	/* Channel Data 1 */ -#define ATMEL_TSADCC_CDR2	0x38	/* Channel Data 2 */ -#define ATMEL_TSADCC_CDR3	0x3C	/* Channel Data 3 */ -#define ATMEL_TSADCC_CDR4	0x40	/* Channel Data 4 */ -#define ATMEL_TSADCC_CDR5	0x44	/* Channel Data 5 */ - -#define ATMEL_TSADCC_XPOS	0x50 -#define ATMEL_TSADCC_Z1DAT	0x54 -#define ATMEL_TSADCC_Z2DAT	0x58 - -#define PRESCALER_VAL(x)	((x) >> 8) - -#define ADC_DEFAULT_CLOCK	100000 - -struct atmel_tsadcc { -	struct input_dev	*input; -	char			phys[32]; -	struct clk		*clk; -	int			irq; -	unsigned int		prev_absx; -	unsigned int		prev_absy; -	unsigned char		bufferedmeasure; -}; - -static void __iomem		*tsc_base; - -#define atmel_tsadcc_read(reg)		__raw_readl(tsc_base + (reg)) -#define atmel_tsadcc_write(reg, val)	__raw_writel((val), tsc_base + (reg)) - -static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev) -{ -	struct atmel_tsadcc	*ts_dev = (struct atmel_tsadcc *)dev; -	struct input_dev	*input_dev = ts_dev->input; - -	unsigned int status; -	unsigned int reg; - -	status = atmel_tsadcc_read(ATMEL_TSADCC_SR); -	status &= atmel_tsadcc_read(ATMEL_TSADCC_IMR); - -	if (status & ATMEL_TSADCC_NOCNT) { -		/* Contact lost */ -		reg = atmel_tsadcc_read(ATMEL_TSADCC_MR) | ATMEL_TSADCC_PENDBC; - -		atmel_tsadcc_write(ATMEL_TSADCC_MR, reg); -		atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE); -		atmel_tsadcc_write(ATMEL_TSADCC_IDR, -				   ATMEL_TSADCC_EOC(3) | ATMEL_TSADCC_NOCNT); -		atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT); - -		input_report_key(input_dev, BTN_TOUCH, 0); -		ts_dev->bufferedmeasure = 0; -		input_sync(input_dev); - -	} else if (status & ATMEL_TSADCC_PENCNT) { -		/* Pen detected */ -		reg = atmel_tsadcc_read(ATMEL_TSADCC_MR); -		reg &= ~ATMEL_TSADCC_PENDBC; - -		atmel_tsadcc_write(ATMEL_TSADCC_IDR, ATMEL_TSADCC_PENCNT); -		atmel_tsadcc_write(ATMEL_TSADCC_MR, reg); -		atmel_tsadcc_write(ATMEL_TSADCC_IER, -				   ATMEL_TSADCC_EOC(3) | ATMEL_TSADCC_NOCNT); -		atmel_tsadcc_write(ATMEL_TSADCC_TRGR, -				   ATMEL_TSADCC_TRGMOD_PERIOD | (0x0FFF << 16)); - -	} else if (status & ATMEL_TSADCC_EOC(3)) { -		/* Conversion finished */ - -		if (ts_dev->bufferedmeasure) { -			/* Last measurement is always discarded, since it can -			 * be erroneous. -			 * Always report previous measurement */ -			input_report_abs(input_dev, ABS_X, ts_dev->prev_absx); -			input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy); -			input_report_key(input_dev, BTN_TOUCH, 1); -			input_sync(input_dev); -		} else -			ts_dev->bufferedmeasure = 1; - -		/* Now make new measurement */ -		ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10; -		ts_dev->prev_absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2); - -		ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10; -		ts_dev->prev_absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0); -	} - -	return IRQ_HANDLED; -} - -/* - * The functions for inserting/removing us as a module. - */ - -static int atmel_tsadcc_probe(struct platform_device *pdev) -{ -	struct atmel_tsadcc	*ts_dev; -	struct input_dev	*input_dev; -	struct resource		*res; -	struct at91_tsadcc_data *pdata = pdev->dev.platform_data; -	int		err; -	unsigned int	prsc; -	unsigned int	reg; - -	if (!pdata) -		return -EINVAL; - -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!res) { -		dev_err(&pdev->dev, "no mmio resource defined.\n"); -		return -ENXIO; -	} - -	/* Allocate memory for device */ -	ts_dev = kzalloc(sizeof(struct atmel_tsadcc), GFP_KERNEL); -	if (!ts_dev) { -		dev_err(&pdev->dev, "failed to allocate memory.\n"); -		return -ENOMEM; -	} -	platform_set_drvdata(pdev, ts_dev); - -	input_dev = input_allocate_device(); -	if (!input_dev) { -		dev_err(&pdev->dev, "failed to allocate input device.\n"); -		err = -EBUSY; -		goto err_free_mem; -	} - -	ts_dev->irq = platform_get_irq(pdev, 0); -	if (ts_dev->irq < 0) { -		dev_err(&pdev->dev, "no irq ID is designated.\n"); -		err = -ENODEV; -		goto err_free_dev; -	} - -	if (!request_mem_region(res->start, resource_size(res), -				"atmel tsadcc regs")) { -		dev_err(&pdev->dev, "resources is unavailable.\n"); -		err = -EBUSY; -		goto err_free_dev; -	} - -	tsc_base = ioremap(res->start, resource_size(res)); -	if (!tsc_base) { -		dev_err(&pdev->dev, "failed to map registers.\n"); -		err = -ENOMEM; -		goto err_release_mem; -	} - -	err = request_irq(ts_dev->irq, atmel_tsadcc_interrupt, 0, -			pdev->dev.driver->name, ts_dev); -	if (err) { -		dev_err(&pdev->dev, "failed to allocate irq.\n"); -		goto err_unmap_regs; -	} - -	ts_dev->clk = clk_get(&pdev->dev, "tsc_clk"); -	if (IS_ERR(ts_dev->clk)) { -		dev_err(&pdev->dev, "failed to get ts_clk\n"); -		err = PTR_ERR(ts_dev->clk); -		goto err_free_irq; -	} - -	ts_dev->input = input_dev; -	ts_dev->bufferedmeasure = 0; - -	snprintf(ts_dev->phys, sizeof(ts_dev->phys), -		 "%s/input0", dev_name(&pdev->dev)); - -	input_dev->name = "atmel touch screen controller"; -	input_dev->phys = ts_dev->phys; -	input_dev->dev.parent = &pdev->dev; - -	__set_bit(EV_ABS, input_dev->evbit); -	input_set_abs_params(input_dev, ABS_X, 0, 0x3FF, 0, 0); -	input_set_abs_params(input_dev, ABS_Y, 0, 0x3FF, 0, 0); - -	input_set_capability(input_dev, EV_KEY, BTN_TOUCH); - -	/* clk_enable() always returns 0, no need to check it */ -	clk_enable(ts_dev->clk); - -	prsc = clk_get_rate(ts_dev->clk); -	dev_info(&pdev->dev, "Master clock is set at: %d Hz\n", prsc); - -	if (!pdata->adc_clock) -		pdata->adc_clock = ADC_DEFAULT_CLOCK; - -	prsc = (prsc / (2 * pdata->adc_clock)) - 1; - -	/* saturate if this value is too high */ -	if (cpu_is_at91sam9rl()) { -		if (prsc > PRESCALER_VAL(ATMEL_TSADCC_PRESCAL)) -			prsc = PRESCALER_VAL(ATMEL_TSADCC_PRESCAL); -	} else { -		if (prsc > PRESCALER_VAL(ATMEL_TSADCC_EPRESCAL)) -			prsc = PRESCALER_VAL(ATMEL_TSADCC_EPRESCAL); -	} - -	dev_info(&pdev->dev, "Prescaler is set at: %d\n", prsc); - -	reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE		| -		((0x00 << 5) & ATMEL_TSADCC_SLEEP)	|	/* Normal Mode */ -		((0x01 << 6) & ATMEL_TSADCC_PENDET)	|	/* Enable Pen Detect */ -		(prsc << 8)				| -		((0x26 << 16) & ATMEL_TSADCC_STARTUP)	| -		((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC); - -	atmel_tsadcc_write(ATMEL_TSADCC_CR, ATMEL_TSADCC_SWRST); -	atmel_tsadcc_write(ATMEL_TSADCC_MR, reg); -	atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE); -	atmel_tsadcc_write(ATMEL_TSADCC_TSR, -		(pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM); - -	atmel_tsadcc_read(ATMEL_TSADCC_SR); -	atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT); - -	/* All went ok, so register to the input system */ -	err = input_register_device(input_dev); -	if (err) -		goto err_fail; - -	return 0; - -err_fail: -	clk_disable(ts_dev->clk); -	clk_put(ts_dev->clk); -err_free_irq: -	free_irq(ts_dev->irq, ts_dev); -err_unmap_regs: -	iounmap(tsc_base); -err_release_mem: -	release_mem_region(res->start, resource_size(res)); -err_free_dev: -	input_free_device(input_dev); -err_free_mem: -	kfree(ts_dev); -	return err; -} - -static int atmel_tsadcc_remove(struct platform_device *pdev) -{ -	struct atmel_tsadcc *ts_dev = platform_get_drvdata(pdev); -	struct resource *res; - -	free_irq(ts_dev->irq, ts_dev); - -	input_unregister_device(ts_dev->input); - -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	iounmap(tsc_base); -	release_mem_region(res->start, resource_size(res)); - -	clk_disable(ts_dev->clk); -	clk_put(ts_dev->clk); - -	kfree(ts_dev); - -	return 0; -} - -static struct platform_driver atmel_tsadcc_driver = { -	.probe		= atmel_tsadcc_probe, -	.remove		= atmel_tsadcc_remove, -	.driver		= { -		.name	= "atmel_tsadcc", -	}, -}; -module_platform_driver(atmel_tsadcc_driver); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Atmel TouchScreen Driver"); -MODULE_AUTHOR("Dan Liang <dan.liang@atmel.com>"); - diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c index d3f9f6b0f9b..7f3c9478778 100644 --- a/drivers/input/touchscreen/auo-pixcir-ts.c +++ b/drivers/input/touchscreen/auo-pixcir-ts.c @@ -679,7 +679,7 @@ static const struct i2c_device_id auo_pixcir_idtable[] = {  MODULE_DEVICE_TABLE(i2c, auo_pixcir_idtable);  #ifdef CONFIG_OF -static struct of_device_id auo_pixcir_ts_dt_idtable[] = { +static const struct of_device_id auo_pixcir_ts_dt_idtable[] = {  	{ .compatible = "auo,auo_pixcir_ts" },  	{},  }; diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c index 8c651985a5c..5bf1aeeea82 100644 --- a/drivers/input/touchscreen/cy8ctmg110_ts.c +++ b/drivers/input/touchscreen/cy8ctmg110_ts.c @@ -178,7 +178,7 @@ static irqreturn_t cy8ctmg110_irq_thread(int irq, void *dev_id)  static int cy8ctmg110_probe(struct i2c_client *client,  					const struct i2c_device_id *id)  { -	const struct cy8ctmg110_pdata *pdata = client->dev.platform_data; +	const struct cy8ctmg110_pdata *pdata = dev_get_platdata(&client->dev);  	struct cy8ctmg110 *ts;  	struct input_dev *input_dev;  	int err; diff --git a/drivers/input/touchscreen/cyttsp4_core.c b/drivers/input/touchscreen/cyttsp4_core.c index d038575f49d..a035a390f8e 100644 --- a/drivers/input/touchscreen/cyttsp4_core.c +++ b/drivers/input/touchscreen/cyttsp4_core.c @@ -1246,8 +1246,7 @@ static void cyttsp4_watchdog_timer(unsigned long handle)  	dev_vdbg(cd->dev, "%s: Watchdog timer triggered\n", __func__); -	if (!work_pending(&cd->watchdog_work)) -		schedule_work(&cd->watchdog_work); +	schedule_work(&cd->watchdog_work);  	return;  } @@ -2113,7 +2112,6 @@ error_startup:  error_request_irq:  	if (cd->cpdata->init)  		cd->cpdata->init(cd->cpdata, 0, dev); -	dev_set_drvdata(dev, NULL);  error_free_xfer:  	kfree(cd->xfer_buf);  error_free_cd: @@ -2151,7 +2149,6 @@ int cyttsp4_remove(struct cyttsp4 *cd)  	free_irq(cd->irq, cd);  	if (cd->cpdata->init)  		cd->cpdata->init(cd->cpdata, 0, dev); -	dev_set_drvdata(dev, NULL);  	cyttsp4_free_si_ptrs(cd);  	kfree(cd);  	return 0; diff --git a/drivers/input/touchscreen/cyttsp4_spi.c b/drivers/input/touchscreen/cyttsp4_spi.c index a71e1141d63..b19434cebbf 100644 --- a/drivers/input/touchscreen/cyttsp4_spi.c +++ b/drivers/input/touchscreen/cyttsp4_spi.c @@ -171,10 +171,7 @@ static int cyttsp4_spi_probe(struct spi_device *spi)  	ts = cyttsp4_probe(&cyttsp_spi_bus_ops, &spi->dev, spi->irq,  			  CY_SPI_DATA_BUF_SIZE); -	if (IS_ERR(ts)) -		return PTR_ERR(ts); - -	return 0; +	return PTR_ERR_OR_ZERO(ts);  }  static int cyttsp4_spi_remove(struct spi_device *spi) diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c index d53e0b72a40..eee656f77a2 100644 --- a/drivers/input/touchscreen/cyttsp_core.c +++ b/drivers/input/touchscreen/cyttsp_core.c @@ -242,7 +242,7 @@ static int cyttsp_soft_reset(struct cyttsp *ts)  	int retval;  	/* wait for interrupt to set ready completion */ -	INIT_COMPLETION(ts->bl_ready); +	reinit_completion(&ts->bl_ready);  	ts->state = CY_BL_STATE;  	enable_irq(ts->irq); @@ -534,7 +534,7 @@ static void cyttsp_close(struct input_dev *dev)  struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,  			    struct device *dev, int irq, size_t xfer_buf_size)  { -	const struct cyttsp_platform_data *pdata = dev->platform_data; +	const struct cyttsp_platform_data *pdata = dev_get_platdata(dev);  	struct cyttsp *ts;  	struct input_dev *input_dev;  	int error; @@ -553,7 +553,7 @@ struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,  	ts->dev = dev;  	ts->input = input_dev; -	ts->pdata = dev->platform_data; +	ts->pdata = dev_get_platdata(dev);  	ts->bus_ops = bus_ops;  	ts->irq = irq; diff --git a/drivers/input/touchscreen/cyttsp_i2c_common.c b/drivers/input/touchscreen/cyttsp_i2c_common.c index 1d7b6f15416..ccefa56ca21 100644 --- a/drivers/input/touchscreen/cyttsp_i2c_common.c +++ b/drivers/input/touchscreen/cyttsp_i2c_common.c @@ -31,6 +31,8 @@  #include <linux/module.h>  #include <linux/types.h> +#include "cyttsp4_core.h" +  int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf,  				      u16 addr, u8 length, void *values)  { diff --git a/drivers/input/touchscreen/da9034-ts.c b/drivers/input/touchscreen/da9034-ts.c index 34ad84105e6..cf6f4b31db4 100644 --- a/drivers/input/touchscreen/da9034-ts.c +++ b/drivers/input/touchscreen/da9034-ts.c @@ -13,7 +13,6 @@  #include <linux/module.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/delay.h>  #include <linux/platform_device.h>  #include <linux/input.h> @@ -299,13 +298,14 @@ static void da9034_touch_close(struct input_dev *dev)  static int da9034_touch_probe(struct platform_device *pdev)  { -	struct da9034_touch_pdata *pdata = pdev->dev.platform_data; +	struct da9034_touch_pdata *pdata = dev_get_platdata(&pdev->dev);  	struct da9034_touch *touch;  	struct input_dev *input_dev; -	int ret; +	int error; -	touch = kzalloc(sizeof(struct da9034_touch), GFP_KERNEL); -	if (touch == NULL) { +	touch = devm_kzalloc(&pdev->dev, sizeof(struct da9034_touch), +			     GFP_KERNEL); +	if (!touch) {  		dev_err(&pdev->dev, "failed to allocate driver data\n");  		return -ENOMEM;  	} @@ -316,18 +316,18 @@ static int da9034_touch_probe(struct platform_device *pdev)  		touch->interval_ms	= pdata->interval_ms;  		touch->x_inverted	= pdata->x_inverted;  		touch->y_inverted	= pdata->y_inverted; -	} else +	} else {  		/* fallback into default */  		touch->interval_ms	= 10; +	}  	INIT_DELAYED_WORK(&touch->tsi_work, da9034_tsi_work);  	touch->notifier.notifier_call = da9034_touch_notifier; -	input_dev = input_allocate_device(); +	input_dev = devm_input_allocate_device(&pdev->dev);  	if (!input_dev) {  		dev_err(&pdev->dev, "failed to allocate input device\n"); -		ret = -ENOMEM; -		goto err_free_touch; +		return -ENOMEM;  	}  	input_dev->name		= pdev->name; @@ -347,26 +347,9 @@ static int da9034_touch_probe(struct platform_device *pdev)  	touch->input_dev = input_dev;  	input_set_drvdata(input_dev, touch); -	ret = input_register_device(input_dev); -	if (ret) -		goto err_free_input; - -	platform_set_drvdata(pdev, touch); -	return 0; - -err_free_input: -	input_free_device(input_dev); -err_free_touch: -	kfree(touch); -	return ret; -} - -static int da9034_touch_remove(struct platform_device *pdev) -{ -	struct da9034_touch *touch = platform_get_drvdata(pdev); - -	input_unregister_device(touch->input_dev); -	kfree(touch); +	error = input_register_device(input_dev); +	if (error) +		return error;  	return 0;  } @@ -377,7 +360,6 @@ static struct platform_driver da9034_touch_driver = {  		.owner	= THIS_MODULE,  	},  	.probe		= da9034_touch_probe, -	.remove		= da9034_touch_remove,  };  module_platform_driver(da9034_touch_driver); diff --git a/drivers/input/touchscreen/dynapro.c b/drivers/input/touchscreen/dynapro.c index 1809677a651..86237a91087 100644 --- a/drivers/input/touchscreen/dynapro.c +++ b/drivers/input/touchscreen/dynapro.c @@ -24,7 +24,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"Dynapro serial touchscreen driver" diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 83fa1b15a97..d4f33992ad8 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -1,5 +1,7 @@  /*   * Copyright (C) 2012 Simon Budig, <simon.budig@kernelconcepts.de> + * Daniel Wagener <daniel.wagener@kernelconcepts.de> (M09 firmware support) + * Lothar Waßmann <LW@KARO-electronics.de> (DT support)   *   * This software is licensed under the terms of the GNU General Public   * License version 2, as published by the Free Software Foundation, and @@ -33,6 +35,7 @@  #include <linux/debugfs.h>  #include <linux/slab.h>  #include <linux/gpio.h> +#include <linux/of_gpio.h>  #include <linux/input/mt.h>  #include <linux/input/edt-ft5x06.h> @@ -45,6 +48,14 @@  #define WORK_REGISTER_NUM_X		0x33  #define WORK_REGISTER_NUM_Y		0x34 +#define M09_REGISTER_THRESHOLD		0x80 +#define M09_REGISTER_GAIN		0x92 +#define M09_REGISTER_OFFSET		0x93 +#define M09_REGISTER_NUM_X		0x94 +#define M09_REGISTER_NUM_Y		0x95 + +#define NO_REGISTER			0xff +  #define WORK_REGISTER_OPMODE		0x3c  #define FACTORY_REGISTER_OPMODE		0x01 @@ -59,12 +70,30 @@  #define EDT_RAW_DATA_RETRIES		100  #define EDT_RAW_DATA_DELAY		1 /* msec */ +enum edt_ver { +	M06, +	M09, +}; + +struct edt_reg_addr { +	int reg_threshold; +	int reg_report_rate; +	int reg_gain; +	int reg_offset; +	int reg_num_x; +	int reg_num_y; +}; +  struct edt_ft5x06_ts_data {  	struct i2c_client *client;  	struct input_dev *input;  	u16 num_x;  	u16 num_y; +	int reset_pin; +	int irq_pin; +	int wake_pin; +  #if defined(CONFIG_DEBUG_FS)  	struct dentry *debug_dir;  	u8 *raw_buffer; @@ -79,6 +108,9 @@ struct edt_ft5x06_ts_data {  	int report_rate;  	char name[EDT_NAME_LEN]; + +	struct edt_reg_addr reg_addr; +	enum edt_ver version;  };  static int edt_ft5x06_ts_readwrite(struct i2c_client *client, @@ -136,33 +168,58 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)  {  	struct edt_ft5x06_ts_data *tsdata = dev_id;  	struct device *dev = &tsdata->client->dev; -	u8 cmd = 0xf9; -	u8 rdbuf[26]; +	u8 cmd; +	u8 rdbuf[29];  	int i, type, x, y, id; +	int offset, tplen, datalen;  	int error; +	switch (tsdata->version) { +	case M06: +		cmd = 0xf9; /* tell the controller to send touch data */ +		offset = 5; /* where the actual touch data starts */ +		tplen = 4;  /* data comes in so called frames */ +		datalen = 26; /* how much bytes to listen for */ +		break; + +	case M09: +		cmd = 0x02; +		offset = 1; +		tplen = 6; +		datalen = 29; +		break; + +	default: +		goto out; +	} +  	memset(rdbuf, 0, sizeof(rdbuf));  	error = edt_ft5x06_ts_readwrite(tsdata->client,  					sizeof(cmd), &cmd, -					sizeof(rdbuf), rdbuf); +					datalen, rdbuf);  	if (error) {  		dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n",  				    error);  		goto out;  	} -	if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || rdbuf[2] != 26) { -		dev_err_ratelimited(dev, "Unexpected header: %02x%02x%02x!\n", -				    rdbuf[0], rdbuf[1], rdbuf[2]); -		goto out; -	} +	/* M09 does not send header or CRC */ +	if (tsdata->version == M06) { +		if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || +			rdbuf[2] != datalen) { +			dev_err_ratelimited(dev, +					"Unexpected header: %02x%02x%02x!\n", +					rdbuf[0], rdbuf[1], rdbuf[2]); +			goto out; +		} -	if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, 26)) -		goto out; +		if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, datalen)) +			goto out; +	}  	for (i = 0; i < MAX_SUPPORT_POINTS; i++) { -		u8 *buf = &rdbuf[i * 4 + 5]; +		u8 *buf = &rdbuf[i * tplen + offset];  		bool down;  		type = buf[0] >> 6; @@ -170,10 +227,14 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)  		if (type == TOUCH_EVENT_RESERVED)  			continue; +		/* M06 sometimes sends bogus coordinates in TOUCH_DOWN */ +		if (tsdata->version == M06 && type == TOUCH_EVENT_DOWN) +			continue; +  		x = ((buf[0] << 8) | buf[1]) & 0x0fff;  		y = ((buf[2] << 8) | buf[3]) & 0x0fff;  		id = (buf[2] >> 4) & 0x0f; -		down = (type != TOUCH_EVENT_UP); +		down = type != TOUCH_EVENT_UP;  		input_mt_slot(tsdata->input, id);  		input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, down); @@ -197,12 +258,25 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata,  {  	u8 wrbuf[4]; -	wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; -	wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; -	wrbuf[2] = value; -	wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2]; - -	return edt_ft5x06_ts_readwrite(tsdata->client, 4, wrbuf, 0, NULL); +	switch (tsdata->version) { +	case M06: +		wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; +		wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; +		wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; +		wrbuf[2] = value; +		wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2]; +		return edt_ft5x06_ts_readwrite(tsdata->client, 4, +					wrbuf, 0, NULL); +	case M09: +		wrbuf[0] = addr; +		wrbuf[1] = value; + +		return edt_ft5x06_ts_readwrite(tsdata->client, 2, +					wrbuf, 0, NULL); + +	default: +		return -EINVAL; +	}  }  static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata, @@ -211,19 +285,36 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata,  	u8 wrbuf[2], rdbuf[2];  	int error; -	wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; -	wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; -	wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40; +	switch (tsdata->version) { +	case M06: +		wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; +		wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; +		wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40; -	error = edt_ft5x06_ts_readwrite(tsdata->client, 2, wrbuf, 2, rdbuf); -	if (error) -		return error; +		error = edt_ft5x06_ts_readwrite(tsdata->client, 2, wrbuf, 2, +						rdbuf); +		if (error) +			return error; -	if ((wrbuf[0] ^ wrbuf[1] ^ rdbuf[0]) != rdbuf[1]) { -		dev_err(&tsdata->client->dev, -			"crc error: 0x%02x expected, got 0x%02x\n", -			wrbuf[0] ^ wrbuf[1] ^ rdbuf[0], rdbuf[1]); -		return -EIO; +		if ((wrbuf[0] ^ wrbuf[1] ^ rdbuf[0]) != rdbuf[1]) { +			dev_err(&tsdata->client->dev, +				"crc error: 0x%02x expected, got 0x%02x\n", +				wrbuf[0] ^ wrbuf[1] ^ rdbuf[0], +				rdbuf[1]); +			return -EIO; +		} +		break; + +	case M09: +		wrbuf[0] = addr; +		error = edt_ft5x06_ts_readwrite(tsdata->client, 1, +						wrbuf, 1, rdbuf); +		if (error) +			return error; +		break; + +	default: +		return -EINVAL;  	}  	return rdbuf[0]; @@ -234,19 +325,21 @@ struct edt_ft5x06_attribute {  	size_t field_offset;  	u8 limit_low;  	u8 limit_high; -	u8 addr; +	u8 addr_m06; +	u8 addr_m09;  }; -#define EDT_ATTR(_field, _mode, _addr, _limit_low, _limit_high)		\ +#define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09,			\ +		_limit_low, _limit_high)				\  	struct edt_ft5x06_attribute edt_ft5x06_attr_##_field = {	\  		.dattr = __ATTR(_field, _mode,				\  				edt_ft5x06_setting_show,		\  				edt_ft5x06_setting_store),		\ -		.field_offset =						\ -			offsetof(struct edt_ft5x06_ts_data, _field),	\ +		.field_offset = offsetof(struct edt_ft5x06_ts_data, _field), \ +		.addr_m06 = _addr_m06,					\ +		.addr_m09 = _addr_m09,					\  		.limit_low = _limit_low,				\  		.limit_high = _limit_high,				\ -		.addr = _addr,						\  	}  static ssize_t edt_ft5x06_setting_show(struct device *dev, @@ -257,10 +350,11 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,  	struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);  	struct edt_ft5x06_attribute *attr =  			container_of(dattr, struct edt_ft5x06_attribute, dattr); -	u8 *field = (u8 *)((char *)tsdata + attr->field_offset); +	u8 *field = (u8 *)tsdata + attr->field_offset;  	int val;  	size_t count = 0;  	int error = 0; +	u8 addr;  	mutex_lock(&tsdata->mutex); @@ -269,15 +363,33 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,  		goto out;  	} -	val = edt_ft5x06_register_read(tsdata, attr->addr); -	if (val < 0) { -		error = val; -		dev_err(&tsdata->client->dev, -			"Failed to fetch attribute %s, error %d\n", -			dattr->attr.name, error); +	switch (tsdata->version) { +	case M06: +		addr = attr->addr_m06; +		break; + +	case M09: +		addr = attr->addr_m09; +		break; + +	default: +		error = -ENODEV;  		goto out;  	} +	if (addr != NO_REGISTER) { +		val = edt_ft5x06_register_read(tsdata, addr); +		if (val < 0) { +			error = val; +			dev_err(&tsdata->client->dev, +				"Failed to fetch attribute %s, error %d\n", +				dattr->attr.name, error); +			goto out; +		} +	} else { +		val = *field; +	} +  	if (val != *field) {  		dev_warn(&tsdata->client->dev,  			 "%s: read (%d) and stored value (%d) differ\n", @@ -299,9 +411,10 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev,  	struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);  	struct edt_ft5x06_attribute *attr =  			container_of(dattr, struct edt_ft5x06_attribute, dattr); -	u8 *field = (u8 *)((char *)tsdata + attr->field_offset); +	u8 *field = (u8 *)tsdata + attr->field_offset;  	unsigned int val;  	int error; +	u8 addr;  	mutex_lock(&tsdata->mutex); @@ -319,14 +432,29 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev,  		goto out;  	} -	error = edt_ft5x06_register_write(tsdata, attr->addr, val); -	if (error) { -		dev_err(&tsdata->client->dev, -			"Failed to update attribute %s, error: %d\n", -			dattr->attr.name, error); +	switch (tsdata->version) { +	case M06: +		addr = attr->addr_m06; +		break; + +	case M09: +		addr = attr->addr_m09; +		break; + +	default: +		error = -ENODEV;  		goto out;  	} +	if (addr != NO_REGISTER) { +		error = edt_ft5x06_register_write(tsdata, addr, val); +		if (error) { +			dev_err(&tsdata->client->dev, +				"Failed to update attribute %s, error: %d\n", +				dattr->attr.name, error); +			goto out; +		} +	}  	*field = val;  out: @@ -334,12 +462,14 @@ out:  	return error ?: count;  } -static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN, 0, 31); -static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET, 0, 31); -static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, -		WORK_REGISTER_THRESHOLD, 20, 80); -static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, -		WORK_REGISTER_REPORT_RATE, 3, 14); +static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN, +		M09_REGISTER_GAIN, 0, 31); +static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET, +		M09_REGISTER_OFFSET, 0, 31); +static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD, +		M09_REGISTER_THRESHOLD, 20, 80); +static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE, +		NO_REGISTER, 3, 14);  static struct attribute *edt_ft5x06_attrs[] = {  	&edt_ft5x06_attr_gain.dattr.attr, @@ -374,6 +504,9 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)  	}  	/* mode register is 0x3c when in the work mode */ +	if (tsdata->version == M09) +		goto m09_out; +  	error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03);  	if (error) {  		dev_err(&client->dev, @@ -406,12 +539,18 @@ err_out:  	enable_irq(client->irq);  	return error; + +m09_out: +	dev_err(&client->dev, "No factory mode support for M09\n"); +	return -EINVAL; +  }  static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata)  {  	struct i2c_client *client = tsdata->client;  	int retries = EDT_SWITCH_MODE_RETRIES; +	struct edt_reg_addr *reg_addr = &tsdata->reg_addr;  	int ret;  	int error; @@ -444,13 +583,14 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata)  	tsdata->raw_buffer = NULL;  	/* restore parameters */ -	edt_ft5x06_register_write(tsdata, WORK_REGISTER_THRESHOLD, +	edt_ft5x06_register_write(tsdata, reg_addr->reg_threshold,  				  tsdata->threshold); -	edt_ft5x06_register_write(tsdata, WORK_REGISTER_GAIN, +	edt_ft5x06_register_write(tsdata, reg_addr->reg_gain,  				  tsdata->gain); -	edt_ft5x06_register_write(tsdata, WORK_REGISTER_OFFSET, +	edt_ft5x06_register_write(tsdata, reg_addr->reg_offset,  				  tsdata->offset); -	edt_ft5x06_register_write(tsdata, WORK_REGISTER_REPORT_RATE, +	if (reg_addr->reg_report_rate) +		edt_ft5x06_register_write(tsdata, reg_addr->reg_report_rate,  				  tsdata->report_rate);  	enable_irq(client->irq); @@ -479,7 +619,7 @@ static int edt_ft5x06_debugfs_mode_set(void *data, u64 mode)  	if (mode != tsdata->factory_mode) {  		retval = mode ? edt_ft5x06_factory_mode(tsdata) : -			        edt_ft5x06_work_mode(tsdata); +				edt_ft5x06_work_mode(tsdata);  	}  	mutex_unlock(&tsdata->mutex); @@ -568,7 +708,6 @@ out:  	return error ?: read;  }; -  static const struct file_operations debugfs_raw_data_fops = {  	.open = simple_open,  	.read = edt_ft5x06_debugfs_raw_data_read, @@ -614,57 +753,100 @@ edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)  #endif /* CONFIG_DEBUGFS */ - -  static int edt_ft5x06_ts_reset(struct i2c_client *client, -					 int reset_pin) +			struct edt_ft5x06_ts_data *tsdata)  {  	int error; -	if (gpio_is_valid(reset_pin)) { +	if (gpio_is_valid(tsdata->wake_pin)) { +		error = devm_gpio_request_one(&client->dev, +					tsdata->wake_pin, GPIOF_OUT_INIT_LOW, +					"edt-ft5x06 wake"); +		if (error) { +			dev_err(&client->dev, +				"Failed to request GPIO %d as wake pin, error %d\n", +				tsdata->wake_pin, error); +			return error; +		} + +		msleep(5); +		gpio_set_value(tsdata->wake_pin, 1); +	} +	if (gpio_is_valid(tsdata->reset_pin)) {  		/* this pulls reset down, enabling the low active reset */ -		error = gpio_request_one(reset_pin, GPIOF_OUT_INIT_LOW, -					 "edt-ft5x06 reset"); +		error = devm_gpio_request_one(&client->dev, +					tsdata->reset_pin, GPIOF_OUT_INIT_LOW, +					"edt-ft5x06 reset");  		if (error) {  			dev_err(&client->dev,  				"Failed to request GPIO %d as reset pin, error %d\n", -				reset_pin, error); +				tsdata->reset_pin, error);  			return error;  		} -		mdelay(50); -		gpio_set_value(reset_pin, 1); -		mdelay(100); +		msleep(5); +		gpio_set_value(tsdata->reset_pin, 1); +		msleep(300);  	}  	return 0;  }  static int edt_ft5x06_ts_identify(struct i2c_client *client, -					    char *model_name, -					    char *fw_version) +					struct edt_ft5x06_ts_data *tsdata, +					char *fw_version)  {  	u8 rdbuf[EDT_NAME_LEN];  	char *p;  	int error; +	char *model_name = tsdata->name; +	/* see what we find if we assume it is a M06 * +	 * if we get less than EDT_NAME_LEN, we don't want +	 * to have garbage in there +	 */ +	memset(rdbuf, 0, sizeof(rdbuf));  	error = edt_ft5x06_ts_readwrite(client, 1, "\xbb",  					EDT_NAME_LEN - 1, rdbuf);  	if (error)  		return error; -	/* remove last '$' end marker */ -	rdbuf[EDT_NAME_LEN - 1] = '\0'; -	if (rdbuf[EDT_NAME_LEN - 2] == '$') -		rdbuf[EDT_NAME_LEN - 2] = '\0'; +	/* if we find something consistent, stay with that assumption +	 * at least M09 won't send 3 bytes here +	 */ +	if (!(strnicmp(rdbuf + 1, "EP0", 3))) { +		tsdata->version = M06; + +		/* remove last '$' end marker */ +		rdbuf[EDT_NAME_LEN - 1] = '\0'; +		if (rdbuf[EDT_NAME_LEN - 2] == '$') +			rdbuf[EDT_NAME_LEN - 2] = '\0'; + +		/* look for Model/Version separator */ +		p = strchr(rdbuf, '*'); +		if (p) +			*p++ = '\0'; +		strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN); +		strlcpy(fw_version, p ? p : "", EDT_NAME_LEN); +	} else { +		/* since there are only two versions around (M06, M09) */ +		tsdata->version = M09; + +		error = edt_ft5x06_ts_readwrite(client, 1, "\xA6", +						2, rdbuf); +		if (error) +			return error; -	/* look for Model/Version separator */ -	p = strchr(rdbuf, '*'); -	if (p) -		*p++ = '\0'; +		strlcpy(fw_version, rdbuf, 2); -	strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN); -	strlcpy(fw_version, p ? p : "", EDT_NAME_LEN); +		error = edt_ft5x06_ts_readwrite(client, 1, "\xA8", +						1, rdbuf); +		if (error) +			return error; + +		snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09", +			rdbuf[0] >> 4, rdbuf[0] & 0x0F); +	}  	return 0;  } @@ -674,38 +856,109 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,  	    pdata->name <= edt_ft5x06_attr_##name.limit_high)		\  		edt_ft5x06_register_write(tsdata, reg, pdata->name) +#define EDT_GET_PROP(name, reg) {				\ +	u32 val;						\ +	if (of_property_read_u32(np, #name, &val) == 0)		\ +		edt_ft5x06_register_write(tsdata, reg, val);	\ +} + +static void edt_ft5x06_ts_get_dt_defaults(struct device_node *np, +					struct edt_ft5x06_ts_data *tsdata) +{ +	struct edt_reg_addr *reg_addr = &tsdata->reg_addr; + +	EDT_GET_PROP(threshold, reg_addr->reg_threshold); +	EDT_GET_PROP(gain, reg_addr->reg_gain); +	EDT_GET_PROP(offset, reg_addr->reg_offset); +} +  static void  edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata,  			   const struct edt_ft5x06_platform_data *pdata)  { +	struct edt_reg_addr *reg_addr = &tsdata->reg_addr; +  	if (!pdata->use_parameters)  		return;  	/* pick up defaults from the platform data */ -	EDT_ATTR_CHECKSET(threshold, WORK_REGISTER_THRESHOLD); -	EDT_ATTR_CHECKSET(gain, WORK_REGISTER_GAIN); -	EDT_ATTR_CHECKSET(offset, WORK_REGISTER_OFFSET); -	EDT_ATTR_CHECKSET(report_rate, WORK_REGISTER_REPORT_RATE); +	EDT_ATTR_CHECKSET(threshold, reg_addr->reg_threshold); +	EDT_ATTR_CHECKSET(gain, reg_addr->reg_gain); +	EDT_ATTR_CHECKSET(offset, reg_addr->reg_offset); +	if (reg_addr->reg_report_rate != NO_REGISTER) +		EDT_ATTR_CHECKSET(report_rate, reg_addr->reg_report_rate);  }  static void  edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)  { +	struct edt_reg_addr *reg_addr = &tsdata->reg_addr; +  	tsdata->threshold = edt_ft5x06_register_read(tsdata, -						     WORK_REGISTER_THRESHOLD); -	tsdata->gain = edt_ft5x06_register_read(tsdata, WORK_REGISTER_GAIN); -	tsdata->offset = edt_ft5x06_register_read(tsdata, WORK_REGISTER_OFFSET); -	tsdata->report_rate = edt_ft5x06_register_read(tsdata, -						WORK_REGISTER_REPORT_RATE); -	tsdata->num_x = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_X); -	tsdata->num_y = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_Y); +						     reg_addr->reg_threshold); +	tsdata->gain = edt_ft5x06_register_read(tsdata, reg_addr->reg_gain); +	tsdata->offset = edt_ft5x06_register_read(tsdata, reg_addr->reg_offset); +	if (reg_addr->reg_report_rate != NO_REGISTER) +		tsdata->report_rate = edt_ft5x06_register_read(tsdata, +						reg_addr->reg_report_rate); +	tsdata->num_x = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_x); +	tsdata->num_y = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_y); +} + +static void +edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) +{ +	struct edt_reg_addr *reg_addr = &tsdata->reg_addr; + +	switch (tsdata->version) { +	case M06: +		reg_addr->reg_threshold = WORK_REGISTER_THRESHOLD; +		reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE; +		reg_addr->reg_gain = WORK_REGISTER_GAIN; +		reg_addr->reg_offset = WORK_REGISTER_OFFSET; +		reg_addr->reg_num_x = WORK_REGISTER_NUM_X; +		reg_addr->reg_num_y = WORK_REGISTER_NUM_Y; +		break; + +	case M09: +		reg_addr->reg_threshold = M09_REGISTER_THRESHOLD; +		reg_addr->reg_gain = M09_REGISTER_GAIN; +		reg_addr->reg_offset = M09_REGISTER_OFFSET; +		reg_addr->reg_num_x = M09_REGISTER_NUM_X; +		reg_addr->reg_num_y = M09_REGISTER_NUM_Y; +		break; +	} +} + +#ifdef CONFIG_OF +static int edt_ft5x06_i2c_ts_probe_dt(struct device *dev, +				struct edt_ft5x06_ts_data *tsdata) +{ +	struct device_node *np = dev->of_node; + +	/* +	 * irq_pin is not needed for DT setup. +	 * irq is associated via 'interrupts' property in DT +	 */ +	tsdata->irq_pin = -EINVAL; +	tsdata->reset_pin = of_get_named_gpio(np, "reset-gpios", 0); +	tsdata->wake_pin = of_get_named_gpio(np, "wake-gpios", 0); + +	return 0;  } +#else +static inline int edt_ft5x06_i2c_ts_probe_dt(struct device *dev, +					struct edt_ft5x06_ts_data *tsdata) +{ +	return -ENODEV; +} +#endif  static int edt_ft5x06_ts_probe(struct i2c_client *client,  					 const struct i2c_device_id *id)  {  	const struct edt_ft5x06_platform_data *pdata = -						client->dev.platform_data; +						dev_get_platdata(&client->dev);  	struct edt_ft5x06_ts_data *tsdata;  	struct input_dev *input;  	int error; @@ -713,32 +966,44 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,  	dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n"); +	tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL); +	if (!tsdata) { +		dev_err(&client->dev, "failed to allocate driver data.\n"); +		return -ENOMEM; +	} +  	if (!pdata) { -		dev_err(&client->dev, "no platform data?\n"); -		return -EINVAL; +		error = edt_ft5x06_i2c_ts_probe_dt(&client->dev, tsdata); +		if (error) { +			dev_err(&client->dev, +				"DT probe failed and no platform data present\n"); +			return error; +		} +	} else { +		tsdata->reset_pin = pdata->reset_pin; +		tsdata->irq_pin = pdata->irq_pin; +		tsdata->wake_pin = -EINVAL;  	} -	error = edt_ft5x06_ts_reset(client, pdata->reset_pin); +	error = edt_ft5x06_ts_reset(client, tsdata);  	if (error)  		return error; -	if (gpio_is_valid(pdata->irq_pin)) { -		error = gpio_request_one(pdata->irq_pin, -					 GPIOF_IN, "edt-ft5x06 irq"); +	if (gpio_is_valid(tsdata->irq_pin)) { +		error = devm_gpio_request_one(&client->dev, tsdata->irq_pin, +					GPIOF_IN, "edt-ft5x06 irq");  		if (error) {  			dev_err(&client->dev,  				"Failed to request GPIO %d, error %d\n", -				pdata->irq_pin, error); +				tsdata->irq_pin, error);  			return error;  		}  	} -	tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL); -	input = input_allocate_device(); -	if (!tsdata || !input) { -		dev_err(&client->dev, "failed to allocate driver data.\n"); -		error = -ENOMEM; -		goto err_free_mem; +	input = devm_input_allocate_device(&client->dev); +	if (!input) { +		dev_err(&client->dev, "failed to allocate input device.\n"); +		return -ENOMEM;  	}  	mutex_init(&tsdata->mutex); @@ -746,13 +1011,19 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,  	tsdata->input = input;  	tsdata->factory_mode = false; -	error = edt_ft5x06_ts_identify(client, tsdata->name, fw_version); +	error = edt_ft5x06_ts_identify(client, tsdata, fw_version);  	if (error) {  		dev_err(&client->dev, "touchscreen probe failed\n"); -		goto err_free_mem; +		return error;  	} -	edt_ft5x06_ts_get_defaults(tsdata, pdata); +	edt_ft5x06_ts_set_regs(tsdata); + +	if (!pdata) +		edt_ft5x06_ts_get_dt_defaults(client->dev.of_node, tsdata); +	else +		edt_ft5x06_ts_get_defaults(tsdata, pdata); +  	edt_ft5x06_ts_get_parameters(tsdata);  	dev_dbg(&client->dev, @@ -776,23 +1047,24 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,  	error = input_mt_init_slots(input, MAX_SUPPORT_POINTS, 0);  	if (error) {  		dev_err(&client->dev, "Unable to init MT slots.\n"); -		goto err_free_mem; +		return error;  	}  	input_set_drvdata(input, tsdata);  	i2c_set_clientdata(client, tsdata); -	error = request_threaded_irq(client->irq, NULL, edt_ft5x06_ts_isr, -				     IRQF_TRIGGER_FALLING | IRQF_ONESHOT, -				     client->name, tsdata); +	error = devm_request_threaded_irq(&client->dev, client->irq, NULL, +					edt_ft5x06_ts_isr, +					IRQF_TRIGGER_FALLING | IRQF_ONESHOT, +					client->name, tsdata);  	if (error) {  		dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); -		goto err_free_mem; +		return error;  	}  	error = sysfs_create_group(&client->dev.kobj, &edt_ft5x06_attr_group);  	if (error) -		goto err_free_irq; +		return error;  	error = input_register_device(input);  	if (error) @@ -802,44 +1074,23 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,  	device_init_wakeup(&client->dev, 1);  	dev_dbg(&client->dev, -		"EDT FT5x06 initialized: IRQ pin %d, Reset pin %d.\n", -		pdata->irq_pin, pdata->reset_pin); +		"EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n", +		client->irq, tsdata->wake_pin, tsdata->reset_pin);  	return 0;  err_remove_attrs:  	sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group); -err_free_irq: -	free_irq(client->irq, tsdata); -err_free_mem: -	input_free_device(input); -	kfree(tsdata); - -	if (gpio_is_valid(pdata->irq_pin)) -		gpio_free(pdata->irq_pin); -  	return error;  }  static int edt_ft5x06_ts_remove(struct i2c_client *client)  { -	const struct edt_ft5x06_platform_data *pdata = -						dev_get_platdata(&client->dev);  	struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);  	edt_ft5x06_ts_teardown_debugfs(tsdata);  	sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group); -	free_irq(client->irq, tsdata); -	input_unregister_device(tsdata->input); - -	if (gpio_is_valid(pdata->irq_pin)) -		gpio_free(pdata->irq_pin); -	if (gpio_is_valid(pdata->reset_pin)) -		gpio_free(pdata->reset_pin); - -	kfree(tsdata); -  	return 0;  } @@ -869,15 +1120,26 @@ static SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops,  			 edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume);  static const struct i2c_device_id edt_ft5x06_ts_id[] = { -	{ "edt-ft5x06", 0 }, -	{ } +	{ "edt-ft5x06", 0, }, +	{ /* sentinel */ }  };  MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id); +#ifdef CONFIG_OF +static const struct of_device_id edt_ft5x06_of_match[] = { +	{ .compatible = "edt,edt-ft5206", }, +	{ .compatible = "edt,edt-ft5306", }, +	{ .compatible = "edt,edt-ft5406", }, +	{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match); +#endif +  static struct i2c_driver edt_ft5x06_ts_driver = {  	.driver = {  		.owner = THIS_MODULE,  		.name = "edt_ft5x06", +		.of_match_table = of_match_ptr(edt_ft5x06_of_match),  		.pm = &edt_ft5x06_ts_pm_ops,  	},  	.id_table = edt_ft5x06_ts_id, diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 1ce3d29ffca..b1884ddd7a8 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -157,7 +157,7 @@ static void eeti_ts_close(struct input_dev *dev)  static int eeti_ts_probe(struct i2c_client *client,  				   const struct i2c_device_id *idp)  { -	struct eeti_ts_platform_data *pdata = client->dev.platform_data; +	struct eeti_ts_platform_data *pdata = dev_get_platdata(&client->dev);  	struct eeti_ts_priv *priv;  	struct input_dev *input;  	unsigned int irq_flags; diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c index ef5fcb0945e..c8057847d71 100644 --- a/drivers/input/touchscreen/egalax_ts.c +++ b/drivers/input/touchscreen/egalax_ts.c @@ -18,7 +18,6 @@  */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/i2c.h>  #include <linux/interrupt.h>  #include <linux/input.h> @@ -263,7 +262,7 @@ static int egalax_ts_resume(struct device *dev)  static SIMPLE_DEV_PM_OPS(egalax_ts_pm_ops, egalax_ts_suspend, egalax_ts_resume); -static struct of_device_id egalax_ts_dt_ids[] = { +static const struct of_device_id egalax_ts_dt_ids[] = {  	{ .compatible = "eeti,egalax_ts" },  	{ /* sentinel */ }  }; @@ -273,7 +272,7 @@ static struct i2c_driver egalax_ts_driver = {  		.name	= "egalax_ts",  		.owner	= THIS_MODULE,  		.pm	= &egalax_ts_pm_ops, -		.of_match_table	= of_match_ptr(egalax_ts_dt_ids), +		.of_match_table	= egalax_ts_dt_ids,  	},  	.id_table	= egalax_ts_id,  	.probe		= egalax_ts_probe, diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c index 957423d1471..8051a4b704e 100644 --- a/drivers/input/touchscreen/elo.c +++ b/drivers/input/touchscreen/elo.c @@ -22,7 +22,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #include <linux/ctype.h>  #define DRIVER_DESC	"Elo serial touchscreen driver" diff --git a/drivers/input/touchscreen/fujitsu_ts.c b/drivers/input/touchscreen/fujitsu_ts.c index 10794ddbdf5..d0e46a7e183 100644 --- a/drivers/input/touchscreen/fujitsu_ts.c +++ b/drivers/input/touchscreen/fujitsu_ts.c @@ -16,7 +16,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"Fujitsu serial touchscreen driver" diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c index 41c71766bf1..e2ee6261527 100644 --- a/drivers/input/touchscreen/gunze.c +++ b/drivers/input/touchscreen/gunze.c @@ -32,7 +32,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"Gunze AHL-51S touchscreen driver" diff --git a/drivers/input/touchscreen/hampshire.c b/drivers/input/touchscreen/hampshire.c index 0cc47ea98ac..ecb1e0e0132 100644 --- a/drivers/input/touchscreen/hampshire.c +++ b/drivers/input/touchscreen/hampshire.c @@ -23,7 +23,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"Hampshire serial touchscreen driver" diff --git a/drivers/input/touchscreen/htcpen.c b/drivers/input/touchscreen/htcpen.c index 66500852341..92e2243fb77 100644 --- a/drivers/input/touchscreen/htcpen.c +++ b/drivers/input/touchscreen/htcpen.c @@ -186,8 +186,6 @@ static int htcpen_isa_remove(struct device *dev, unsigned int id)  	release_region(HTCPEN_PORT_INIT, 1);  	release_region(HTCPEN_PORT_IRQ_CLEAR, 1); -	dev_set_drvdata(dev, NULL); -  	return 0;  } diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index 1418bdda61b..2a508913981 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -184,7 +184,7 @@ static int ili210x_i2c_probe(struct i2c_client *client,  				       const struct i2c_device_id *id)  {  	struct device *dev = &client->dev; -	const struct ili210x_platform_data *pdata = dev->platform_data; +	const struct ili210x_platform_data *pdata = dev_get_platdata(dev);  	struct ili210x *priv;  	struct input_dev *input;  	struct panel_info panel; diff --git a/drivers/input/touchscreen/inexio.c b/drivers/input/touchscreen/inexio.c index a29c99c3224..adb80b65a25 100644 --- a/drivers/input/touchscreen/inexio.c +++ b/drivers/input/touchscreen/inexio.c @@ -23,7 +23,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"iNexio serial touchscreen driver" diff --git a/drivers/input/touchscreen/intel-mid-touch.c b/drivers/input/touchscreen/intel-mid-touch.c index e30d837dae2..c38ca4a7e38 100644 --- a/drivers/input/touchscreen/intel-mid-touch.c +++ b/drivers/input/touchscreen/intel-mid-touch.c @@ -27,7 +27,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/input.h>  #include <linux/interrupt.h>  #include <linux/err.h> @@ -37,6 +36,7 @@  #include <linux/irq.h>  #include <linux/delay.h>  #include <asm/intel_scu_ipc.h> +#include <linux/device.h>  /* PMIC Interrupt registers */  #define PMIC_REG_ID1		0x00 /* PMIC ID1 register */ @@ -581,12 +581,17 @@ static int mrstouch_probe(struct platform_device *pdev)  		return -EINVAL;  	} -	tsdev = kzalloc(sizeof(struct mrstouch_dev), GFP_KERNEL); -	input = input_allocate_device(); -	if (!tsdev || !input) { +	tsdev = devm_kzalloc(&pdev->dev, sizeof(struct mrstouch_dev), +			     GFP_KERNEL); +	if (!tsdev) {  		dev_err(&pdev->dev, "unable to allocate memory\n"); -		err = -ENOMEM; -		goto err_free_mem; +		return -ENOMEM; +	} + +	input = devm_input_allocate_device(&pdev->dev); +	if (!input) { +		dev_err(&pdev->dev, "unable to allocate input device\n"); +		return -ENOMEM;  	}  	tsdev->dev = &pdev->dev; @@ -599,7 +604,7 @@ static int mrstouch_probe(struct platform_device *pdev)  	err = mrstouch_adc_init(tsdev);  	if (err) {  		dev_err(&pdev->dev, "ADC initialization failed\n"); -		goto err_free_mem; +		return err;  	}  	input->name = "mrst_touchscreen"; @@ -619,38 +624,20 @@ static int mrstouch_probe(struct platform_device *pdev)  	input_set_abs_params(tsdev->input, ABS_PRESSURE,  			     MRST_PRESSURE_MIN, MRST_PRESSURE_MAX, 0, 0); -	err = request_threaded_irq(tsdev->irq, NULL, mrstouch_pendet_irq, -				   IRQF_ONESHOT, "mrstouch", tsdev); +	err = devm_request_threaded_irq(&pdev->dev, tsdev->irq, NULL, +					mrstouch_pendet_irq, IRQF_ONESHOT, +					"mrstouch", tsdev);  	if (err) {  		dev_err(tsdev->dev, "unable to allocate irq\n"); -		goto err_free_mem; +		return err;  	}  	err = input_register_device(tsdev->input);  	if (err) {  		dev_err(tsdev->dev, "unable to register input device\n"); -		goto err_free_irq; +		return err;  	} -	platform_set_drvdata(pdev, tsdev); -	return 0; - -err_free_irq: -	free_irq(tsdev->irq, tsdev); -err_free_mem: -	input_free_device(input); -	kfree(tsdev); -	return err; -} - -static int mrstouch_remove(struct platform_device *pdev) -{ -	struct mrstouch_dev *tsdev = platform_get_drvdata(pdev); - -	free_irq(tsdev->irq, tsdev); -	input_unregister_device(tsdev->input); -	kfree(tsdev); -  	return 0;  } @@ -660,7 +647,6 @@ static struct platform_driver mrstouch_driver = {  		.owner	= THIS_MODULE,  	},  	.probe		= mrstouch_probe, -	.remove		= mrstouch_remove,  };  module_platform_driver(mrstouch_driver); diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c index e463a79ffec..7324c5c0fb8 100644 --- a/drivers/input/touchscreen/jornada720_ts.c +++ b/drivers/input/touchscreen/jornada720_ts.c @@ -14,7 +14,6 @@   */  #include <linux/platform_device.h> -#include <linux/init.h>  #include <linux/input.h>  #include <linux/interrupt.h>  #include <linux/module.h> diff --git a/drivers/input/touchscreen/lpc32xx_ts.c b/drivers/input/touchscreen/lpc32xx_ts.c index 9101ee529c9..bb47d3442a3 100644 --- a/drivers/input/touchscreen/lpc32xx_ts.c +++ b/drivers/input/touchscreen/lpc32xx_ts.c @@ -15,7 +15,6 @@   */  #include <linux/platform_device.h> -#include <linux/init.h>  #include <linux/input.h>  #include <linux/interrupt.h>  #include <linux/module.h> @@ -385,7 +384,7 @@ static const struct dev_pm_ops lpc32xx_ts_pm_ops = {  #endif  #ifdef CONFIG_OF -static struct of_device_id lpc32xx_tsc_of_match[] = { +static const struct of_device_id lpc32xx_tsc_of_match[] = {  	{ .compatible = "nxp,lpc3220-tsc", },  	{ },  }; diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c index 7d2b2136e5a..0786010d7ed 100644 --- a/drivers/input/touchscreen/mainstone-wm97xx.c +++ b/drivers/input/touchscreen/mainstone-wm97xx.c @@ -25,7 +25,6 @@  #include <linux/module.h>  #include <linux/moduleparam.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/delay.h>  #include <linux/irq.h>  #include <linux/interrupt.h> diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c index 9f84fcd0873..a68ec142ee9 100644 --- a/drivers/input/touchscreen/max11801_ts.c +++ b/drivers/input/touchscreen/max11801_ts.c @@ -33,7 +33,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/i2c.h>  #include <linux/interrupt.h>  #include <linux/input.h> diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c index f9f4e0c56ed..00510a9836b 100644 --- a/drivers/input/touchscreen/mcs5000_ts.c +++ b/drivers/input/touchscreen/mcs5000_ts.c @@ -14,7 +14,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/i2c.h>  #include <linux/i2c/mcs.h>  #include <linux/interrupt.h> @@ -162,10 +161,9 @@ static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)  	return IRQ_HANDLED;  } -static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data) +static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data, +				 const struct mcs_platform_data *platform_data)  { -	const struct mcs_platform_data *platform_data = -		data->platform_data;  	struct i2c_client *client = data->client;  	/* Touch reset & sleep mode */ @@ -188,28 +186,32 @@ static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data)  }  static int mcs5000_ts_probe(struct i2c_client *client, -		const struct i2c_device_id *id) +			    const struct i2c_device_id *id)  { +	const struct mcs_platform_data *pdata;  	struct mcs5000_ts_data *data;  	struct input_dev *input_dev; -	int ret; +	int error; -	if (!client->dev.platform_data) +	pdata = dev_get_platdata(&client->dev); +	if (!pdata)  		return -EINVAL; -	data = kzalloc(sizeof(struct mcs5000_ts_data), GFP_KERNEL); -	input_dev = input_allocate_device(); -	if (!data || !input_dev) { +	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); +	if (!data) {  		dev_err(&client->dev, "Failed to allocate memory\n"); -		ret = -ENOMEM; -		goto err_free_mem; +		return -ENOMEM;  	}  	data->client = client; -	data->input_dev = input_dev; -	data->platform_data = client->dev.platform_data; -	input_dev->name = "MELPAS MCS-5000 Touchscreen"; +	input_dev = devm_input_allocate_device(&client->dev); +	if (!input_dev) { +		dev_err(&client->dev, "Failed to allocate input device\n"); +		return -ENOMEM; +	} + +	input_dev->name = "MELFAS MCS-5000 Touchscreen";  	input_dev->id.bustype = BUS_I2C;  	input_dev->dev.parent = &client->dev; @@ -220,44 +222,30 @@ static int mcs5000_ts_probe(struct i2c_client *client,  	input_set_abs_params(input_dev, ABS_Y, 0, MCS5000_MAX_YC, 0, 0);  	input_set_drvdata(input_dev, data); +	data->input_dev = input_dev; -	if (data->platform_data->cfg_pin) -		data->platform_data->cfg_pin(); - -	ret = request_threaded_irq(client->irq, NULL, mcs5000_ts_interrupt, -			IRQF_TRIGGER_LOW | IRQF_ONESHOT, "mcs5000_ts", data); +	if (pdata->cfg_pin) +		pdata->cfg_pin(); -	if (ret < 0) { +	error = devm_request_threaded_irq(&client->dev, client->irq, +					  NULL, mcs5000_ts_interrupt, +					  IRQF_TRIGGER_LOW | IRQF_ONESHOT, +					  "mcs5000_ts", data); +	if (error) {  		dev_err(&client->dev, "Failed to register interrupt\n"); -		goto err_free_mem; +		return error;  	} -	ret = input_register_device(data->input_dev); -	if (ret < 0) -		goto err_free_irq; +	error = input_register_device(data->input_dev); +	if (error) { +		dev_err(&client->dev, "Failed to register input device\n"); +		return error; +	} -	mcs5000_ts_phys_init(data); +	mcs5000_ts_phys_init(data, pdata);  	i2c_set_clientdata(client, data);  	return 0; - -err_free_irq: -	free_irq(client->irq, data); -err_free_mem: -	input_free_device(input_dev); -	kfree(data); -	return ret; -} - -static int mcs5000_ts_remove(struct i2c_client *client) -{ -	struct mcs5000_ts_data *data = i2c_get_clientdata(client); - -	free_irq(client->irq, data); -	input_unregister_device(data->input_dev); -	kfree(data); - -	return 0;  }  #ifdef CONFIG_PM @@ -275,14 +263,15 @@ static int mcs5000_ts_resume(struct device *dev)  {  	struct i2c_client *client = to_i2c_client(dev);  	struct mcs5000_ts_data *data = i2c_get_clientdata(client); +	const struct mcs_platform_data *pdata = dev_get_platdata(dev); -	mcs5000_ts_phys_init(data); +	mcs5000_ts_phys_init(data, pdata);  	return 0;  } +#endif  static SIMPLE_DEV_PM_OPS(mcs5000_ts_pm, mcs5000_ts_suspend, mcs5000_ts_resume); -#endif  static const struct i2c_device_id mcs5000_ts_id[] = {  	{ "mcs5000_ts", 0 }, @@ -292,12 +281,9 @@ MODULE_DEVICE_TABLE(i2c, mcs5000_ts_id);  static struct i2c_driver mcs5000_ts_driver = {  	.probe		= mcs5000_ts_probe, -	.remove		= mcs5000_ts_remove,  	.driver = {  		.name = "mcs5000_ts", -#ifdef CONFIG_PM  		.pm   = &mcs5000_ts_pm, -#endif  	},  	.id_table	= mcs5000_ts_id,  }; diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index 1443532fe6c..372bbf7658f 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -8,7 +8,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/delay.h>  #include <linux/of.h>  #include <linux/i2c.h> @@ -457,7 +456,7 @@ static int mms114_probe(struct i2c_client *client,  	data->input_dev = input_dev;  	data->pdata = pdata; -	input_dev->name = "MELPAS MMS114 Touchscreen"; +	input_dev->name = "MELFAS MMS114 Touchscreen";  	input_dev->id.bustype = BUS_I2C;  	input_dev->dev.parent = &client->dev;  	input_dev->open = mms114_input_open; @@ -571,7 +570,7 @@ static const struct i2c_device_id mms114_id[] = {  MODULE_DEVICE_TABLE(i2c, mms114_id);  #ifdef CONFIG_OF -static struct of_device_id mms114_dt_match[] = { +static const struct of_device_id mms114_dt_match[] = {  	{ .compatible = "melfas,mms114" },  	{ }  }; diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c index eb66b7c37c2..9b5552a2616 100644 --- a/drivers/input/touchscreen/mtouch.c +++ b/drivers/input/touchscreen/mtouch.c @@ -21,7 +21,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"MicroTouch serial touchscreen driver" diff --git a/drivers/input/touchscreen/of_touchscreen.c b/drivers/input/touchscreen/of_touchscreen.c new file mode 100644 index 00000000000..f8f9b84230b --- /dev/null +++ b/drivers/input/touchscreen/of_touchscreen.c @@ -0,0 +1,45 @@ +/* + *  Generic DT helper functions for touchscreen devices + * + *  Copyright (c) 2014 Sebastian Reichel <sre@kernel.org> + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License version 2 as + *  published by the Free Software Foundation. + * + */ + +#include <linux/of.h> +#include <linux/input.h> +#include <linux/input/touchscreen.h> + +/** + * touchscreen_parse_of_params - parse common touchscreen DT properties + * @dev: device that should be parsed + * + * This function parses common DT properties for touchscreens and setups the + * input device accordingly. The function keeps previously setuped default + * values if no value is specified via DT. + */ +void touchscreen_parse_of_params(struct input_dev *dev) +{ +	struct device_node *np = dev->dev.parent->of_node; +	struct input_absinfo *absinfo; + +	input_alloc_absinfo(dev); +	if (!dev->absinfo) +		return; + +	absinfo = &dev->absinfo[ABS_X]; +	of_property_read_u32(np, "touchscreen-size-x", &absinfo->maximum); +	of_property_read_u32(np, "touchscreen-fuzz-x", &absinfo->fuzz); + +	absinfo = &dev->absinfo[ABS_Y]; +	of_property_read_u32(np, "touchscreen-size-y", &absinfo->maximum); +	of_property_read_u32(np, "touchscreen-fuzz-y", &absinfo->fuzz); + +	absinfo = &dev->absinfo[ABS_PRESSURE]; +	of_property_read_u32(np, "touchscreen-max-pressure", &absinfo->maximum); +	of_property_read_u32(np, "touchscreen-fuzz-pressure", &absinfo->fuzz); +} +EXPORT_SYMBOL(touchscreen_parse_of_params); diff --git a/drivers/input/touchscreen/pcap_ts.c b/drivers/input/touchscreen/pcap_ts.c index f22e04dd4e1..cff2376817e 100644 --- a/drivers/input/touchscreen/pcap_ts.c +++ b/drivers/input/touchscreen/pcap_ts.c @@ -11,7 +11,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/fs.h>  #include <linux/string.h>  #include <linux/slab.h> diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c index b49f0b83692..417d8737926 100644 --- a/drivers/input/touchscreen/penmount.c +++ b/drivers/input/touchscreen/penmount.c @@ -21,7 +21,6 @@  #include <linux/input.h>  #include <linux/input/mt.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"PenMount serial touchscreen driver" diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 6cc6b36663f..19c6c0fdc94 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -24,12 +24,13 @@  #include <linux/i2c.h>  #include <linux/input.h>  #include <linux/input/pixcir_ts.h> +#include <linux/gpio.h>  struct pixcir_i2c_ts_data {  	struct i2c_client *client;  	struct input_dev *input;  	const struct pixcir_ts_platform_data *chip; -	bool exiting; +	bool running;  };  static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data) @@ -87,11 +88,12 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)  static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)  {  	struct pixcir_i2c_ts_data *tsdata = dev_id; +	const struct pixcir_ts_platform_data *pdata = tsdata->chip; -	while (!tsdata->exiting) { +	while (tsdata->running) {  		pixcir_ts_poscheck(tsdata); -		if (tsdata->chip->attb_read_val()) +		if (gpio_get_value(pdata->gpio_attb))  			break;  		msleep(20); @@ -100,25 +102,221 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)  	return IRQ_HANDLED;  } +static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts, +				 enum pixcir_power_mode mode) +{ +	struct device *dev = &ts->client->dev; +	int ret; + +	ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_POWER_MODE); +	if (ret < 0) { +		dev_err(dev, "%s: can't read reg 0x%x : %d\n", +			__func__, PIXCIR_REG_POWER_MODE, ret); +		return ret; +	} + +	ret &= ~PIXCIR_POWER_MODE_MASK; +	ret |= mode; + +	/* Always AUTO_IDLE */ +	ret |= PIXCIR_POWER_ALLOW_IDLE; + +	ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_POWER_MODE, ret); +	if (ret < 0) { +		dev_err(dev, "%s: can't write reg 0x%x : %d\n", +			__func__, PIXCIR_REG_POWER_MODE, ret); +		return ret; +	} + +	return 0; +} + +/* + * Set the interrupt mode for the device i.e. ATTB line behaviour + * + * @polarity : 1 for active high, 0 for active low. + */ +static int pixcir_set_int_mode(struct pixcir_i2c_ts_data *ts, +			       enum pixcir_int_mode mode, bool polarity) +{ +	struct device *dev = &ts->client->dev; +	int ret; + +	ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE); +	if (ret < 0) { +		dev_err(dev, "%s: can't read reg 0x%x : %d\n", +			__func__, PIXCIR_REG_INT_MODE, ret); +		return ret; +	} + +	ret &= ~PIXCIR_INT_MODE_MASK; +	ret |= mode; + +	if (polarity) +		ret |= PIXCIR_INT_POL_HIGH; +	else +		ret &= ~PIXCIR_INT_POL_HIGH; + +	ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret); +	if (ret < 0) { +		dev_err(dev, "%s: can't write reg 0x%x : %d\n", +			__func__, PIXCIR_REG_INT_MODE, ret); +		return ret; +	} + +	return 0; +} + +/* + * Enable/disable interrupt generation + */ +static int pixcir_int_enable(struct pixcir_i2c_ts_data *ts, bool enable) +{ +	struct device *dev = &ts->client->dev; +	int ret; + +	ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE); +	if (ret < 0) { +		dev_err(dev, "%s: can't read reg 0x%x : %d\n", +			__func__, PIXCIR_REG_INT_MODE, ret); +		return ret; +	} + +	if (enable) +		ret |= PIXCIR_INT_ENABLE; +	else +		ret &= ~PIXCIR_INT_ENABLE; + +	ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret); +	if (ret < 0) { +		dev_err(dev, "%s: can't write reg 0x%x : %d\n", +			__func__, PIXCIR_REG_INT_MODE, ret); +		return ret; +	} + +	return 0; +} + +static int pixcir_start(struct pixcir_i2c_ts_data *ts) +{ +	struct device *dev = &ts->client->dev; +	int error; + +	/* LEVEL_TOUCH interrupt with active low polarity */ +	error = pixcir_set_int_mode(ts, PIXCIR_INT_LEVEL_TOUCH, 0); +	if (error) { +		dev_err(dev, "Failed to set interrupt mode: %d\n", error); +		return error; +	} + +	ts->running = true; +	mb();	/* Update status before IRQ can fire */ + +	/* enable interrupt generation */ +	error = pixcir_int_enable(ts, true); +	if (error) { +		dev_err(dev, "Failed to enable interrupt generation: %d\n", +			error); +		return error; +	} + +	return 0; +} + +static int pixcir_stop(struct pixcir_i2c_ts_data *ts) +{ +	int error; + +	/* Disable interrupt generation */ +	error = pixcir_int_enable(ts, false); +	if (error) { +		dev_err(&ts->client->dev, +			"Failed to disable interrupt generation: %d\n", +			error); +		return error; +	} + +	/* Exit ISR if running, no more report parsing */ +	ts->running = false; +	mb();	/* update status before we synchronize irq */ + +	/* Wait till running ISR is complete */ +	synchronize_irq(ts->client->irq); + +	return 0; +} + +static int pixcir_input_open(struct input_dev *dev) +{ +	struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev); + +	return pixcir_start(ts); +} + +static void pixcir_input_close(struct input_dev *dev) +{ +	struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev); + +	pixcir_stop(ts); +} +  #ifdef CONFIG_PM_SLEEP  static int pixcir_i2c_ts_suspend(struct device *dev)  {  	struct i2c_client *client = to_i2c_client(dev); +	struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client); +	struct input_dev *input = ts->input; +	int ret = 0; + +	mutex_lock(&input->mutex); + +	if (device_may_wakeup(&client->dev)) { +		if (!input->users) { +			ret = pixcir_start(ts); +			if (ret) { +				dev_err(dev, "Failed to start\n"); +				goto unlock; +			} +		} -	if (device_may_wakeup(&client->dev))  		enable_irq_wake(client->irq); +	} else if (input->users) { +		ret = pixcir_stop(ts); +	} -	return 0; +unlock: +	mutex_unlock(&input->mutex); + +	return ret;  }  static int pixcir_i2c_ts_resume(struct device *dev)  {  	struct i2c_client *client = to_i2c_client(dev); +	struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client); +	struct input_dev *input = ts->input; +	int ret = 0; + +	mutex_lock(&input->mutex); -	if (device_may_wakeup(&client->dev)) +	if (device_may_wakeup(&client->dev)) {  		disable_irq_wake(client->irq); -	return 0; +		if (!input->users) { +			ret = pixcir_stop(ts); +			if (ret) { +				dev_err(dev, "Failed to stop\n"); +				goto unlock; +			} +		} +	} else if (input->users) { +		ret = pixcir_start(ts); +	} + +unlock: +	mutex_unlock(&input->mutex); + +	return ret;  }  #endif @@ -128,7 +326,9 @@ static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,  static int pixcir_i2c_ts_probe(struct i2c_client *client,  					 const struct i2c_device_id *id)  { -	const struct pixcir_ts_platform_data *pdata = client->dev.platform_data; +	const struct pixcir_ts_platform_data *pdata = +			dev_get_platdata(&client->dev); +	struct device *dev = &client->dev;  	struct pixcir_i2c_ts_data *tsdata;  	struct input_dev *input;  	int error; @@ -138,12 +338,19 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,  		return -EINVAL;  	} -	tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL); -	input = input_allocate_device(); -	if (!tsdata || !input) { -		dev_err(&client->dev, "Failed to allocate driver data!\n"); -		error = -ENOMEM; -		goto err_free_mem; +	if (!gpio_is_valid(pdata->gpio_attb)) { +		dev_err(dev, "Invalid gpio_attb in pdata\n"); +		return -EINVAL; +	} + +	tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL); +	if (!tsdata) +		return -ENOMEM; + +	input = devm_input_allocate_device(dev); +	if (!input) { +		dev_err(dev, "Failed to allocate input device\n"); +		return -ENOMEM;  	}  	tsdata->client = client; @@ -152,6 +359,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,  	input->name = client->name;  	input->id.bustype = BUS_I2C; +	input->open = pixcir_input_open; +	input->close = pixcir_input_close;  	input->dev.parent = &client->dev;  	__set_bit(EV_KEY, input->evbit); @@ -164,44 +373,47 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,  	input_set_drvdata(input, tsdata); -	error = request_threaded_irq(client->irq, NULL, pixcir_ts_isr, -				     IRQF_TRIGGER_FALLING | IRQF_ONESHOT, -				     client->name, tsdata); +	error = devm_gpio_request_one(dev, pdata->gpio_attb, +				      GPIOF_DIR_IN, "pixcir_i2c_attb");  	if (error) { -		dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); -		goto err_free_mem; +		dev_err(dev, "Failed to request ATTB gpio\n"); +		return error;  	} +	error = devm_request_threaded_irq(dev, client->irq, NULL, pixcir_ts_isr, +					  IRQF_TRIGGER_FALLING | IRQF_ONESHOT, +					  client->name, tsdata); +	if (error) { +		dev_err(dev, "failed to request irq %d\n", client->irq); +		return error; +	} + +	/* Always be in IDLE mode to save power, device supports auto wake */ +	error = pixcir_set_power_mode(tsdata, PIXCIR_POWER_IDLE); +	if (error) { +		dev_err(dev, "Failed to set IDLE mode\n"); +		return error; +	} + +	/* Stop device till opened */ +	error = pixcir_stop(tsdata); +	if (error) +		return error; +  	error = input_register_device(input);  	if (error) -		goto err_free_irq; +		return error;  	i2c_set_clientdata(client, tsdata);  	device_init_wakeup(&client->dev, 1);  	return 0; - -err_free_irq: -	free_irq(client->irq, tsdata); -err_free_mem: -	input_free_device(input); -	kfree(tsdata); -	return error;  }  static int pixcir_i2c_ts_remove(struct i2c_client *client)  { -	struct pixcir_i2c_ts_data *tsdata = i2c_get_clientdata(client); -  	device_init_wakeup(&client->dev, 0); -	tsdata->exiting = true; -	mb(); -	free_irq(client->irq, tsdata); - -	input_unregister_device(tsdata->input); -	kfree(tsdata); -  	return 0;  } diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c index b061af2c837..19cb247dbb8 100644 --- a/drivers/input/touchscreen/s3c2410_ts.c +++ b/drivers/input/touchscreen/s3c2410_ts.c @@ -28,7 +28,6 @@  #include <linux/module.h>  #include <linux/gpio.h>  #include <linux/input.h> -#include <linux/init.h>  #include <linux/delay.h>  #include <linux/interrupt.h>  #include <linux/platform_device.h> @@ -251,7 +250,7 @@ static int s3c2410ts_probe(struct platform_device *pdev)  	ts.dev = dev; -	info = pdev->dev.platform_data; +	info = dev_get_platdata(&pdev->dev);  	if (!info) {  		dev_err(dev, "no platform data, cannot attach\n");  		return -EINVAL; @@ -392,7 +391,7 @@ static int s3c2410ts_suspend(struct device *dev)  static int s3c2410ts_resume(struct device *dev)  {  	struct platform_device *pdev = to_platform_device(dev); -	struct s3c2410_ts_mach_info *info = pdev->dev.platform_data; +	struct s3c2410_ts_mach_info *info = dev_get_platdata(&pdev->dev);  	clk_enable(ts.clock);  	enable_irq(ts.irq_tc); diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index 1740a249637..3c0f57efe7b 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c @@ -24,6 +24,7 @@  #include <linux/input.h>  #include <linux/interrupt.h>  #include <linux/module.h> +#include <linux/of.h>  #include <linux/of_gpio.h>  #include <linux/pm_qos.h>  #include <linux/slab.h> @@ -133,7 +134,8 @@ static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id)  	} else if (!ts->low_latency_req.dev) {  		/* First contact, request 100 us latency. */  		dev_pm_qos_add_ancestor_request(&ts->client->dev, -						&ts->low_latency_req, 100); +						&ts->low_latency_req, +						DEV_PM_QOS_RESUME_LATENCY, 100);  	}  	/* SYN_REPORT */ @@ -153,7 +155,7 @@ static int st1232_ts_probe(struct i2c_client *client,  					const struct i2c_device_id *id)  {  	struct st1232_ts_data *ts; -	struct st1232_pdata *pdata = client->dev.platform_data; +	struct st1232_pdata *pdata = dev_get_platdata(&client->dev);  	struct input_dev *input_dev;  	int error; diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c index 59e81b00f24..42ce31afa25 100644 --- a/drivers/input/touchscreen/stmpe-ts.c +++ b/drivers/input/touchscreen/stmpe-ts.c @@ -15,7 +15,6 @@  #include <linux/module.h>  #include <linux/sched.h>  #include <linux/interrupt.h> -#include <linux/init.h>  #include <linux/device.h>  #include <linux/of.h>  #include <linux/platform_device.h> diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c new file mode 100644 index 00000000000..2ba82602495 --- /dev/null +++ b/drivers/input/touchscreen/sun4i-ts.c @@ -0,0 +1,339 @@ +/* + * Allwinner sunxi resistive touchscreen controller driver + * + * Copyright (C) 2013 - 2014 Hans de Goede <hdegoede@redhat.com> + * + * The hwmon parts are based on work by Corentin LABBE which is: + * Copyright (C) 2013 Corentin LABBE <clabbe.montjoie@gmail.com> + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ + +/* + * The sun4i-ts controller is capable of detecting a second touch, but when a + * second touch is present then the accuracy becomes so bad the reported touch + * location is not useable. + * + * The original android driver contains some complicated heuristics using the + * aprox. distance between the 2 touches to see if the user is making a pinch + * open / close movement, and then reports emulated multi-touch events around + * the last touch coordinate (as the dual-touch coordinates are worthless). + * + * These kinds of heuristics are just asking for trouble (and don't belong + * in the kernel). So this driver offers straight forward, reliable single + * touch functionality only. + */ + +#include <linux/err.h> +#include <linux/hwmon.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#define TP_CTRL0		0x00 +#define TP_CTRL1		0x04 +#define TP_CTRL2		0x08 +#define TP_CTRL3		0x0c +#define TP_INT_FIFOC		0x10 +#define TP_INT_FIFOS		0x14 +#define TP_TPR			0x18 +#define TP_CDAT			0x1c +#define TEMP_DATA		0x20 +#define TP_DATA			0x24 + +/* TP_CTRL0 bits */ +#define ADC_FIRST_DLY(x)	((x) << 24) /* 8 bits */ +#define ADC_FIRST_DLY_MODE(x)	((x) << 23) +#define ADC_CLK_SEL(x)		((x) << 22) +#define ADC_CLK_DIV(x)		((x) << 20) /* 3 bits */ +#define FS_DIV(x)		((x) << 16) /* 4 bits */ +#define T_ACQ(x)		((x) << 0) /* 16 bits */ + +/* TP_CTRL1 bits */ +#define STYLUS_UP_DEBOUN(x)	((x) << 12) /* 8 bits */ +#define STYLUS_UP_DEBOUN_EN(x)	((x) << 9) +#define TOUCH_PAN_CALI_EN(x)	((x) << 6) +#define TP_DUAL_EN(x)		((x) << 5) +#define TP_MODE_EN(x)		((x) << 4) +#define TP_ADC_SELECT(x)	((x) << 3) +#define ADC_CHAN_SELECT(x)	((x) << 0)  /* 3 bits */ + +/* TP_CTRL2 bits */ +#define TP_SENSITIVE_ADJUST(x)	((x) << 28) /* 4 bits */ +#define TP_MODE_SELECT(x)	((x) << 26) /* 2 bits */ +#define PRE_MEA_EN(x)		((x) << 24) +#define PRE_MEA_THRE_CNT(x)	((x) << 0) /* 24 bits */ + +/* TP_CTRL3 bits */ +#define FILTER_EN(x)		((x) << 2) +#define FILTER_TYPE(x)		((x) << 0)  /* 2 bits */ + +/* TP_INT_FIFOC irq and fifo mask / control bits */ +#define TEMP_IRQ_EN(x)		((x) << 18) +#define OVERRUN_IRQ_EN(x)	((x) << 17) +#define DATA_IRQ_EN(x)		((x) << 16) +#define TP_DATA_XY_CHANGE(x)	((x) << 13) +#define FIFO_TRIG(x)		((x) << 8)  /* 5 bits */ +#define DATA_DRQ_EN(x)		((x) << 7) +#define FIFO_FLUSH(x)		((x) << 4) +#define TP_UP_IRQ_EN(x)		((x) << 1) +#define TP_DOWN_IRQ_EN(x)	((x) << 0) + +/* TP_INT_FIFOS irq and fifo status bits */ +#define TEMP_DATA_PENDING	BIT(18) +#define FIFO_OVERRUN_PENDING	BIT(17) +#define FIFO_DATA_PENDING	BIT(16) +#define TP_IDLE_FLG		BIT(2) +#define TP_UP_PENDING		BIT(1) +#define TP_DOWN_PENDING		BIT(0) + +/* TP_TPR bits */ +#define TEMP_ENABLE(x)		((x) << 16) +#define TEMP_PERIOD(x)		((x) << 0)  /* t = x * 256 * 16 / clkin */ + +struct sun4i_ts_data { +	struct device *dev; +	struct input_dev *input; +	void __iomem *base; +	unsigned int irq; +	bool ignore_fifo_data; +	int temp_data; +}; + +static void sun4i_ts_irq_handle_input(struct sun4i_ts_data *ts, u32 reg_val) +{ +	u32 x, y; + +	if (reg_val & FIFO_DATA_PENDING) { +		x = readl(ts->base + TP_DATA); +		y = readl(ts->base + TP_DATA); +		/* The 1st location reported after an up event is unreliable */ +		if (!ts->ignore_fifo_data) { +			input_report_abs(ts->input, ABS_X, x); +			input_report_abs(ts->input, ABS_Y, y); +			/* +			 * The hardware has a separate down status bit, but +			 * that gets set before we get the first location, +			 * resulting in reporting a click on the old location. +			 */ +			input_report_key(ts->input, BTN_TOUCH, 1); +			input_sync(ts->input); +		} else { +			ts->ignore_fifo_data = false; +		} +	} + +	if (reg_val & TP_UP_PENDING) { +		ts->ignore_fifo_data = true; +		input_report_key(ts->input, BTN_TOUCH, 0); +		input_sync(ts->input); +	} +} + +static irqreturn_t sun4i_ts_irq(int irq, void *dev_id) +{ +	struct sun4i_ts_data *ts = dev_id; +	u32 reg_val; + +	reg_val  = readl(ts->base + TP_INT_FIFOS); + +	if (reg_val & TEMP_DATA_PENDING) +		ts->temp_data = readl(ts->base + TEMP_DATA); + +	if (ts->input) +		sun4i_ts_irq_handle_input(ts, reg_val); + +	writel(reg_val, ts->base + TP_INT_FIFOS); + +	return IRQ_HANDLED; +} + +static int sun4i_ts_open(struct input_dev *dev) +{ +	struct sun4i_ts_data *ts = input_get_drvdata(dev); + +	/* Flush, set trig level to 1, enable temp, data and up irqs */ +	writel(TEMP_IRQ_EN(1) | DATA_IRQ_EN(1) | FIFO_TRIG(1) | FIFO_FLUSH(1) | +		TP_UP_IRQ_EN(1), ts->base + TP_INT_FIFOC); + +	return 0; +} + +static void sun4i_ts_close(struct input_dev *dev) +{ +	struct sun4i_ts_data *ts = input_get_drvdata(dev); + +	/* Deactivate all input IRQs */ +	writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC); +} + +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, +			 char *buf) +{ +	struct sun4i_ts_data *ts = dev_get_drvdata(dev); + +	/* No temp_data until the first irq */ +	if (ts->temp_data == -1) +		return -EAGAIN; + +	return sprintf(buf, "%d\n", (ts->temp_data - 1447) * 100); +} + +static ssize_t show_temp_label(struct device *dev, +			      struct device_attribute *devattr, char *buf) +{ +	return sprintf(buf, "SoC temperature\n"); +} + +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); +static DEVICE_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL); + +static struct attribute *sun4i_ts_attrs[] = { +	&dev_attr_temp1_input.attr, +	&dev_attr_temp1_label.attr, +	NULL +}; +ATTRIBUTE_GROUPS(sun4i_ts); + +static int sun4i_ts_probe(struct platform_device *pdev) +{ +	struct sun4i_ts_data *ts; +	struct device *dev = &pdev->dev; +	struct device_node *np = dev->of_node; +	struct device *hwmon; +	int error; +	bool ts_attached; + +	ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL); +	if (!ts) +		return -ENOMEM; + +	ts->dev = dev; +	ts->ignore_fifo_data = true; +	ts->temp_data = -1; + +	ts_attached = of_property_read_bool(np, "allwinner,ts-attached"); +	if (ts_attached) { +		ts->input = devm_input_allocate_device(dev); +		if (!ts->input) +			return -ENOMEM; + +		ts->input->name = pdev->name; +		ts->input->phys = "sun4i_ts/input0"; +		ts->input->open = sun4i_ts_open; +		ts->input->close = sun4i_ts_close; +		ts->input->id.bustype = BUS_HOST; +		ts->input->id.vendor = 0x0001; +		ts->input->id.product = 0x0001; +		ts->input->id.version = 0x0100; +		ts->input->evbit[0] =  BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS); +		__set_bit(BTN_TOUCH, ts->input->keybit); +		input_set_abs_params(ts->input, ABS_X, 0, 4095, 0, 0); +		input_set_abs_params(ts->input, ABS_Y, 0, 4095, 0, 0); +		input_set_drvdata(ts->input, ts); +	} + +	ts->base = devm_ioremap_resource(dev, +			      platform_get_resource(pdev, IORESOURCE_MEM, 0)); +	if (IS_ERR(ts->base)) +		return PTR_ERR(ts->base); + +	ts->irq = platform_get_irq(pdev, 0); +	error = devm_request_irq(dev, ts->irq, sun4i_ts_irq, 0, "sun4i-ts", ts); +	if (error) +		return error; + +	/* +	 * Select HOSC clk, clkin = clk / 6, adc samplefreq = clkin / 8192, +	 * t_acq = clkin / (16 * 64) +	 */ +	writel(ADC_CLK_SEL(0) | ADC_CLK_DIV(2) | FS_DIV(7) | T_ACQ(63), +	       ts->base + TP_CTRL0); + +	/* +	 * sensitive_adjust = 15 : max, which is not all that sensitive, +	 * tp_mode = 0 : only x and y coordinates, as we don't use dual touch +	 */ +	writel(TP_SENSITIVE_ADJUST(15) | TP_MODE_SELECT(0), +	       ts->base + TP_CTRL2); + +	/* Enable median filter, type 1 : 5/3 */ +	writel(FILTER_EN(1) | FILTER_TYPE(1), ts->base + TP_CTRL3); + +	/* Enable temperature measurement, period 1953 (2 seconds) */ +	writel(TEMP_ENABLE(1) | TEMP_PERIOD(1953), ts->base + TP_TPR); + +	/* +	 * Set stylus up debounce to aprox 10 ms, enable debounce, and +	 * finally enable tp mode. +	 */ +	writel(STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1) | TP_MODE_EN(1), +	       ts->base + TP_CTRL1); + +	hwmon = devm_hwmon_device_register_with_groups(ts->dev, "sun4i_ts", +						       ts, sun4i_ts_groups); +	if (IS_ERR(hwmon)) +		return PTR_ERR(hwmon); + +	writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC); + +	if (ts_attached) { +		error = input_register_device(ts->input); +		if (error) { +			writel(0, ts->base + TP_INT_FIFOC); +			return error; +		} +	} + +	platform_set_drvdata(pdev, ts); +	return 0; +} + +static int sun4i_ts_remove(struct platform_device *pdev) +{ +	struct sun4i_ts_data *ts = platform_get_drvdata(pdev); + +	/* Explicit unregister to avoid open/close changing the imask later */ +	if (ts->input) +		input_unregister_device(ts->input); + +	/* Deactivate all IRQs */ +	writel(0, ts->base + TP_INT_FIFOC); + +	return 0; +} + +static const struct of_device_id sun4i_ts_of_match[] = { +	{ .compatible = "allwinner,sun4i-a10-ts", }, +	{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, sun4i_ts_of_match); + +static struct platform_driver sun4i_ts_driver = { +	.driver = { +		.owner	= THIS_MODULE, +		.name	= "sun4i-ts", +		.of_match_table = of_match_ptr(sun4i_ts_of_match), +	}, +	.probe	= sun4i_ts_probe, +	.remove	= sun4i_ts_remove, +}; + +module_platform_driver(sun4i_ts_driver); + +MODULE_DESCRIPTION("Allwinner sun4i resistive touchscreen controller driver"); +MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c new file mode 100644 index 00000000000..f1cb05148b4 --- /dev/null +++ b/drivers/input/touchscreen/sur40.c @@ -0,0 +1,466 @@ +/* + * Surface2.0/SUR40/PixelSense input driver + * + * Copyright (c) 2013 by Florian 'floe' Echtler <floe@butterbrot.org> + * + * Derived from the USB Skeleton driver 1.1, + * Copyright (c) 2003 Greg Kroah-Hartman (greg@kroah.com) + * + * and from the Apple USB BCM5974 multitouch driver, + * Copyright (c) 2008 Henrik Rydberg (rydberg@euromail.se) + * + * and from the generic hid-multitouch driver, + * Copyright (c) 2010-2012 Stephane Chatty <chatty@enac.fr> + * + * 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 the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/completion.h> +#include <linux/uaccess.h> +#include <linux/usb.h> +#include <linux/printk.h> +#include <linux/input-polldev.h> +#include <linux/input/mt.h> +#include <linux/usb/input.h> + +/* read 512 bytes from endpoint 0x86 -> get header + blobs */ +struct sur40_header { + +	__le16 type;       /* always 0x0001 */ +	__le16 count;      /* count of blobs (if 0: continue prev. packet) */ + +	__le32 packet_id;  /* unique ID for all packets in one frame */ + +	__le32 timestamp;  /* milliseconds (inc. by 16 or 17 each frame) */ +	__le32 unknown;    /* "epoch?" always 02/03 00 00 00 */ + +} __packed; + +struct sur40_blob { + +	__le16 blob_id; + +	u8 action;         /* 0x02 = enter/exit, 0x03 = update (?) */ +	u8 unknown;        /* always 0x01 or 0x02 (no idea what this is?) */ + +	__le16 bb_pos_x;   /* upper left corner of bounding box */ +	__le16 bb_pos_y; + +	__le16 bb_size_x;  /* size of bounding box */ +	__le16 bb_size_y; + +	__le16 pos_x;      /* finger tip position */ +	__le16 pos_y; + +	__le16 ctr_x;      /* centroid position */ +	__le16 ctr_y; + +	__le16 axis_x;     /* somehow related to major/minor axis, mostly: */ +	__le16 axis_y;     /* axis_x == bb_size_y && axis_y == bb_size_x */ + +	__le32 angle;      /* orientation in radians relative to x axis - +	                      actually an IEEE754 float, don't use in kernel */ + +	__le32 area;       /* size in pixels/pressure (?) */ + +	u8 padding[32]; + +} __packed; + +/* combined header/blob data */ +struct sur40_data { +	struct sur40_header header; +	struct sur40_blob   blobs[]; +} __packed; + + +/* version information */ +#define DRIVER_SHORT   "sur40" +#define DRIVER_AUTHOR  "Florian 'floe' Echtler <floe@butterbrot.org>" +#define DRIVER_DESC    "Surface2.0/SUR40/PixelSense input driver" + +/* vendor and device IDs */ +#define ID_MICROSOFT 0x045e +#define ID_SUR40     0x0775 + +/* sensor resolution */ +#define SENSOR_RES_X 1920 +#define SENSOR_RES_Y 1080 + +/* touch data endpoint */ +#define TOUCH_ENDPOINT 0x86 + +/* polling interval (ms) */ +#define POLL_INTERVAL 10 + +/* maximum number of contacts FIXME: this is a guess? */ +#define MAX_CONTACTS 64 + +/* control commands */ +#define SUR40_GET_VERSION 0xb0 /* 12 bytes string    */ +#define SUR40_UNKNOWN1    0xb3 /*  5 bytes           */ +#define SUR40_UNKNOWN2    0xc1 /* 24 bytes           */ + +#define SUR40_GET_STATE   0xc5 /*  4 bytes state (?) */ +#define SUR40_GET_SENSORS 0xb1 /*  8 bytes sensors   */ + +/* + * Note: an earlier, non-public version of this driver used USB_RECIP_ENDPOINT + * here by mistake which is very likely to have corrupted the firmware EEPROM + * on two separate SUR40 devices. Thanks to Alan Stern who spotted this bug. + * Should you ever run into a similar problem, the background story to this + * incident and instructions on how to fix the corrupted EEPROM are available + * at https://floe.butterbrot.org/matrix/hacking/surface/brick.html +*/ + +struct sur40_state { + +	struct usb_device *usbdev; +	struct device *dev; +	struct input_polled_dev *input; + +	struct sur40_data *bulk_in_buffer; +	size_t bulk_in_size; +	u8 bulk_in_epaddr; + +	char phys[64]; +}; + +static int sur40_command(struct sur40_state *dev, +			 u8 command, u16 index, void *buffer, u16 size) +{ +	return usb_control_msg(dev->usbdev, usb_rcvctrlpipe(dev->usbdev, 0), +			       command, +			       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, +			       0x00, index, buffer, size, 1000); +} + +/* Initialization routine, called from sur40_open */ +static int sur40_init(struct sur40_state *dev) +{ +	int result; +	u8 buffer[24]; + +	/* stupidly replay the original MS driver init sequence */ +	result = sur40_command(dev, SUR40_GET_VERSION, 0x00, buffer, 12); +	if (result < 0) +		return result; + +	result = sur40_command(dev, SUR40_GET_VERSION, 0x01, buffer, 12); +	if (result < 0) +		return result; + +	result = sur40_command(dev, SUR40_GET_VERSION, 0x02, buffer, 12); +	if (result < 0) +		return result; + +	result = sur40_command(dev, SUR40_UNKNOWN2,    0x00, buffer, 24); +	if (result < 0) +		return result; + +	result = sur40_command(dev, SUR40_UNKNOWN1,    0x00, buffer,  5); +	if (result < 0) +		return result; + +	result = sur40_command(dev, SUR40_GET_VERSION, 0x03, buffer, 12); + +	/* +	 * Discard the result buffer - no known data inside except +	 * some version strings, maybe extract these sometime... +	 */ + +	return result; +} + +/* + * Callback routines from input_polled_dev + */ + +/* Enable the device, polling will now start. */ +static void sur40_open(struct input_polled_dev *polldev) +{ +	struct sur40_state *sur40 = polldev->private; + +	dev_dbg(sur40->dev, "open\n"); +	sur40_init(sur40); +} + +/* Disable device, polling has stopped. */ +static void sur40_close(struct input_polled_dev *polldev) +{ +	struct sur40_state *sur40 = polldev->private; + +	dev_dbg(sur40->dev, "close\n"); +	/* +	 * There is no known way to stop the device, so we simply +	 * stop polling. +	 */ +} + +/* + * This function is called when a whole contact has been processed, + * so that it can assign it to a slot and store the data there. + */ +static void sur40_report_blob(struct sur40_blob *blob, struct input_dev *input) +{ +	int wide, major, minor; + +	int bb_size_x = le16_to_cpu(blob->bb_size_x); +	int bb_size_y = le16_to_cpu(blob->bb_size_y); + +	int pos_x = le16_to_cpu(blob->pos_x); +	int pos_y = le16_to_cpu(blob->pos_y); + +	int ctr_x = le16_to_cpu(blob->ctr_x); +	int ctr_y = le16_to_cpu(blob->ctr_y); + +	int slotnum = input_mt_get_slot_by_key(input, blob->blob_id); +	if (slotnum < 0 || slotnum >= MAX_CONTACTS) +		return; + +	input_mt_slot(input, slotnum); +	input_mt_report_slot_state(input, MT_TOOL_FINGER, 1); +	wide = (bb_size_x > bb_size_y); +	major = max(bb_size_x, bb_size_y); +	minor = min(bb_size_x, bb_size_y); + +	input_report_abs(input, ABS_MT_POSITION_X, pos_x); +	input_report_abs(input, ABS_MT_POSITION_Y, pos_y); +	input_report_abs(input, ABS_MT_TOOL_X, ctr_x); +	input_report_abs(input, ABS_MT_TOOL_Y, ctr_y); + +	/* TODO: use a better orientation measure */ +	input_report_abs(input, ABS_MT_ORIENTATION, wide); +	input_report_abs(input, ABS_MT_TOUCH_MAJOR, major); +	input_report_abs(input, ABS_MT_TOUCH_MINOR, minor); +} + +/* core function: poll for new input data */ +static void sur40_poll(struct input_polled_dev *polldev) +{ + +	struct sur40_state *sur40 = polldev->private; +	struct input_dev *input = polldev->input; +	int result, bulk_read, need_blobs, packet_blobs, i; +	u32 uninitialized_var(packet_id); + +	struct sur40_header *header = &sur40->bulk_in_buffer->header; +	struct sur40_blob *inblob = &sur40->bulk_in_buffer->blobs[0]; + +	dev_dbg(sur40->dev, "poll\n"); + +	need_blobs = -1; + +	do { + +		/* perform a blocking bulk read to get data from the device */ +		result = usb_bulk_msg(sur40->usbdev, +			usb_rcvbulkpipe(sur40->usbdev, sur40->bulk_in_epaddr), +			sur40->bulk_in_buffer, sur40->bulk_in_size, +			&bulk_read, 1000); + +		dev_dbg(sur40->dev, "received %d bytes\n", bulk_read); + +		if (result < 0) { +			dev_err(sur40->dev, "error in usb_bulk_read\n"); +			return; +		} + +		result = bulk_read - sizeof(struct sur40_header); + +		if (result % sizeof(struct sur40_blob) != 0) { +			dev_err(sur40->dev, "transfer size mismatch\n"); +			return; +		} + +		/* first packet? */ +		if (need_blobs == -1) { +			need_blobs = le16_to_cpu(header->count); +			dev_dbg(sur40->dev, "need %d blobs\n", need_blobs); +			packet_id = le32_to_cpu(header->packet_id); +		} + +		/* +		 * Sanity check. when video data is also being retrieved, the +		 * packet ID will usually increase in the middle of a series +		 * instead of at the end. +		 */ +		if (packet_id != header->packet_id) +			dev_warn(sur40->dev, "packet ID mismatch\n"); + +		packet_blobs = result / sizeof(struct sur40_blob); +		dev_dbg(sur40->dev, "received %d blobs\n", packet_blobs); + +		/* packets always contain at least 4 blobs, even if empty */ +		if (packet_blobs > need_blobs) +			packet_blobs = need_blobs; + +		for (i = 0; i < packet_blobs; i++) { +			need_blobs--; +			dev_dbg(sur40->dev, "processing blob\n"); +			sur40_report_blob(&(inblob[i]), input); +		} + +	} while (need_blobs > 0); + +	input_mt_sync_frame(input); +	input_sync(input); +} + +/* Initialize input device parameters. */ +static void sur40_input_setup(struct input_dev *input_dev) +{ +	__set_bit(EV_KEY, input_dev->evbit); +	__set_bit(EV_ABS, input_dev->evbit); + +	input_set_abs_params(input_dev, ABS_MT_POSITION_X, +			     0, SENSOR_RES_X, 0, 0); +	input_set_abs_params(input_dev, ABS_MT_POSITION_Y, +			     0, SENSOR_RES_Y, 0, 0); + +	input_set_abs_params(input_dev, ABS_MT_TOOL_X, +			     0, SENSOR_RES_X, 0, 0); +	input_set_abs_params(input_dev, ABS_MT_TOOL_Y, +			     0, SENSOR_RES_Y, 0, 0); + +	/* max value unknown, but major/minor axis +	 * can never be larger than screen */ +	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, +			     0, SENSOR_RES_X, 0, 0); +	input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, +			     0, SENSOR_RES_Y, 0, 0); + +	input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0); + +	input_mt_init_slots(input_dev, MAX_CONTACTS, +			    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); +} + +/* Check candidate USB interface. */ +static int sur40_probe(struct usb_interface *interface, +		       const struct usb_device_id *id) +{ +	struct usb_device *usbdev = interface_to_usbdev(interface); +	struct sur40_state *sur40; +	struct usb_host_interface *iface_desc; +	struct usb_endpoint_descriptor *endpoint; +	struct input_polled_dev *poll_dev; +	int error; + +	/* Check if we really have the right interface. */ +	iface_desc = &interface->altsetting[0]; +	if (iface_desc->desc.bInterfaceClass != 0xFF) +		return -ENODEV; + +	/* Use endpoint #4 (0x86). */ +	endpoint = &iface_desc->endpoint[4].desc; +	if (endpoint->bEndpointAddress != TOUCH_ENDPOINT) +		return -ENODEV; + +	/* Allocate memory for our device state and initialize it. */ +	sur40 = kzalloc(sizeof(struct sur40_state), GFP_KERNEL); +	if (!sur40) +		return -ENOMEM; + +	poll_dev = input_allocate_polled_device(); +	if (!poll_dev) { +		error = -ENOMEM; +		goto err_free_dev; +	} + +	/* Set up polled input device control structure */ +	poll_dev->private = sur40; +	poll_dev->poll_interval = POLL_INTERVAL; +	poll_dev->open = sur40_open; +	poll_dev->poll = sur40_poll; +	poll_dev->close = sur40_close; + +	/* Set up regular input device structure */ +	sur40_input_setup(poll_dev->input); + +	poll_dev->input->name = "Samsung SUR40"; +	usb_to_input_id(usbdev, &poll_dev->input->id); +	usb_make_path(usbdev, sur40->phys, sizeof(sur40->phys)); +	strlcat(sur40->phys, "/input0", sizeof(sur40->phys)); +	poll_dev->input->phys = sur40->phys; +	poll_dev->input->dev.parent = &interface->dev; + +	sur40->usbdev = usbdev; +	sur40->dev = &interface->dev; +	sur40->input = poll_dev; + +	/* use the bulk-in endpoint tested above */ +	sur40->bulk_in_size = usb_endpoint_maxp(endpoint); +	sur40->bulk_in_epaddr = endpoint->bEndpointAddress; +	sur40->bulk_in_buffer = kmalloc(sur40->bulk_in_size, GFP_KERNEL); +	if (!sur40->bulk_in_buffer) { +		dev_err(&interface->dev, "Unable to allocate input buffer."); +		error = -ENOMEM; +		goto err_free_polldev; +	} + +	error = input_register_polled_device(poll_dev); +	if (error) { +		dev_err(&interface->dev, +			"Unable to register polled input device."); +		goto err_free_buffer; +	} + +	/* we can register the device now, as it is ready */ +	usb_set_intfdata(interface, sur40); +	dev_dbg(&interface->dev, "%s is now attached\n", DRIVER_DESC); + +	return 0; + +err_free_buffer: +	kfree(sur40->bulk_in_buffer); +err_free_polldev: +	input_free_polled_device(sur40->input); +err_free_dev: +	kfree(sur40); + +	return error; +} + +/* Unregister device & clean up. */ +static void sur40_disconnect(struct usb_interface *interface) +{ +	struct sur40_state *sur40 = usb_get_intfdata(interface); + +	input_unregister_polled_device(sur40->input); +	input_free_polled_device(sur40->input); +	kfree(sur40->bulk_in_buffer); +	kfree(sur40); + +	usb_set_intfdata(interface, NULL); +	dev_dbg(&interface->dev, "%s is now disconnected\n", DRIVER_DESC); +} + +static const struct usb_device_id sur40_table[] = { +	{ USB_DEVICE(ID_MICROSOFT, ID_SUR40) },  /* Samsung SUR40 */ +	{ }                                      /* terminating null entry */ +}; +MODULE_DEVICE_TABLE(usb, sur40_table); + +/* USB-specific object needed to register this driver with the USB subsystem. */ +static struct usb_driver sur40_driver = { +	.name = DRIVER_SHORT, +	.probe = sur40_probe, +	.disconnect = sur40_disconnect, +	.id_table = sur40_table, +}; + +module_usb_driver(sur40_driver); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index e1c5300cacf..2ce649520fe 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c @@ -14,7 +14,6 @@   */ -#include <linux/init.h>  #include <linux/kernel.h>  #include <linux/err.h>  #include <linux/module.h> @@ -52,6 +51,7 @@ struct titsc {  	u32			config_inp[4];  	u32			bit_xp, bit_xn, bit_yp, bit_yn;  	u32			inp_xp, inp_xn, inp_yp, inp_yn; +	u32			step_mask;  };  static unsigned int titsc_readl(struct titsc *ts, unsigned int reg) @@ -196,7 +196,8 @@ static void titsc_step_config(struct titsc *ts_dev)  	/* The steps1 … end and bit 0 for TS_Charge */  	stepenable = (1 << (end_step + 2)) - 1; -	am335x_tsc_se_set(ts_dev->mfd_tscadc, stepenable); +	ts_dev->step_mask = stepenable; +	am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask);  }  static void titsc_read_coordinates(struct titsc *ts_dev, @@ -260,6 +261,10 @@ static irqreturn_t titsc_irq(int irq, void *dev)  	unsigned int fsm;  	status = titsc_readl(ts_dev, REG_IRQSTATUS); +	/* +	 * ADC and touchscreen share the IRQ line. +	 * FIFO1 interrupts are used by ADC. Handle FIFO0 IRQs here only +	 */  	if (status & IRQENB_FIFO0THRES) {  		titsc_read_coordinates(ts_dev, &x, &y, &z1, &z2); @@ -316,7 +321,7 @@ static irqreturn_t titsc_irq(int irq, void *dev)  	if (irqclr) {  		titsc_writel(ts_dev, REG_IRQSTATUS, irqclr); -		am335x_tsc_se_update(ts_dev->mfd_tscadc); +		am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask);  		return IRQ_HANDLED;  	}  	return IRQ_NONE; @@ -348,8 +353,18 @@ static int titsc_parse_dt(struct platform_device *pdev,  	if (err < 0)  		return err; -	err = of_property_read_u32(node, "ti,coordiante-readouts", +	/* +	 * Try with the new binding first. If it fails, try again with +	 * bogus, miss-spelled version. +	 */ +	err = of_property_read_u32(node, "ti,coordinate-readouts",  			&ts_dev->coordinate_readouts); +	if (err < 0) { +		dev_warn(&pdev->dev, "please use 'ti,coordinate-readouts' instead\n"); +		err = of_property_read_u32(node, "ti,coordiante-readouts", +				&ts_dev->coordinate_readouts); +	} +  	if (err < 0)  		return err; @@ -389,7 +404,7 @@ static int titsc_probe(struct platform_device *pdev)  	}  	err = request_irq(ts_dev->irq, titsc_irq, -			  0, pdev->dev.driver->name, ts_dev); +			  IRQF_SHARED, pdev->dev.driver->name, ts_dev);  	if (err) {  		dev_err(&pdev->dev, "failed to allocate irq.\n");  		goto err_free_mem; @@ -505,7 +520,7 @@ static struct platform_driver ti_tsc_driver = {  		.name   = "TI-am335x-tsc",  		.owner	= THIS_MODULE,  		.pm	= TITSC_PM_OPS, -		.of_match_table = of_match_ptr(ti_tsc_dt_ids), +		.of_match_table = ti_tsc_dt_ids,  	},  };  module_platform_driver(ti_tsc_driver); diff --git a/drivers/input/touchscreen/tnetv107x-ts.c b/drivers/input/touchscreen/tnetv107x-ts.c deleted file mode 100644 index c47827a26e3..00000000000 --- a/drivers/input/touchscreen/tnetv107x-ts.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Texas Instruments TNETV107X Touchscreen Driver - * - * Copyright (C) 2010 Texas Instruments - * - * 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 the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/err.h> -#include <linux/errno.h> -#include <linux/input.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/ctype.h> -#include <linux/io.h> -#include <linux/clk.h> - -#include <mach/tnetv107x.h> - -#define TSC_PENUP_POLL		(HZ / 5) -#define IDLE_TIMEOUT		100 /* msec */ - -/* - * The first and last samples of a touch interval are usually garbage and need - * to be filtered out with these devices.  The following definitions control - * the number of samples skipped. - */ -#define TSC_HEAD_SKIP		1 -#define TSC_TAIL_SKIP		1 -#define TSC_SKIP		(TSC_HEAD_SKIP + TSC_TAIL_SKIP + 1) -#define TSC_SAMPLES		(TSC_SKIP + 1) - -/* Register Offsets */ -struct tsc_regs { -	u32	rev; -	u32	tscm; -	u32	bwcm; -	u32	swc; -	u32	adcchnl; -	u32	adcdata; -	u32	chval[4]; -}; - -/* TSC Mode Configuration Register (tscm) bits */ -#define WMODE		BIT(0) -#define TSKIND		BIT(1) -#define ZMEASURE_EN	BIT(2) -#define IDLE		BIT(3) -#define TSC_EN		BIT(4) -#define STOP		BIT(5) -#define ONE_SHOT	BIT(6) -#define SINGLE		BIT(7) -#define AVG		BIT(8) -#define AVGNUM(x)	(((x) & 0x03) <<  9) -#define PVSTC(x)	(((x) & 0x07) << 11) -#define PON		BIT(14) -#define PONBG		BIT(15) -#define AFERST		BIT(16) - -/* ADC DATA Capture Register bits */ -#define DATA_VALID	BIT(16) - -/* Register Access Macros */ -#define tsc_read(ts, reg)		__raw_readl(&(ts)->regs->reg) -#define tsc_write(ts, reg, val)		__raw_writel(val, &(ts)->regs->reg); -#define tsc_set_bits(ts, reg, val)	\ -	tsc_write(ts, reg, tsc_read(ts, reg) | (val)) -#define tsc_clr_bits(ts, reg, val)	\ -	tsc_write(ts, reg, tsc_read(ts, reg) & ~(val)) - -struct sample { -	int x, y, p; -}; - -struct tsc_data { -	struct input_dev		*input_dev; -	struct resource			*res; -	struct tsc_regs __iomem		*regs; -	struct timer_list		timer; -	spinlock_t			lock; -	struct clk			*clk; -	struct device			*dev; -	int				sample_count; -	struct sample			samples[TSC_SAMPLES]; -	int				tsc_irq; -}; - -static int tsc_read_sample(struct tsc_data *ts, struct sample* sample) -{ -	int	x, y, z1, z2, t, p = 0; -	u32	val; - -	val = tsc_read(ts, chval[0]); -	if (val & DATA_VALID) -		x = val & 0xffff; -	else -		return -EINVAL; - -	y  = tsc_read(ts, chval[1]) & 0xffff; -	z1 = tsc_read(ts, chval[2]) & 0xffff; -	z2 = tsc_read(ts, chval[3]) & 0xffff; - -	if (z1) { -		t = ((600 * x) * (z2 - z1)); -		p = t / (u32) (z1 << 12); -		if (p < 0) -			p = 0; -	} - -	sample->x  = x; -	sample->y  = y; -	sample->p  = p; - -	return 0; -} - -static void tsc_poll(unsigned long data) -{ -	struct tsc_data *ts = (struct tsc_data *)data; -	unsigned long flags; -	int i, val, x, y, p; - -	spin_lock_irqsave(&ts->lock, flags); - -	if (ts->sample_count >= TSC_SKIP) { -		input_report_abs(ts->input_dev, ABS_PRESSURE, 0); -		input_report_key(ts->input_dev, BTN_TOUCH, 0); -		input_sync(ts->input_dev); -	} else if (ts->sample_count > 0) { -		/* -		 * A touch event lasted less than our skip count.  Salvage and -		 * report anyway. -		 */ -		for (i = 0, val = 0; i < ts->sample_count; i++) -			val += ts->samples[i].x; -		x = val / ts->sample_count; - -		for (i = 0, val = 0; i < ts->sample_count; i++) -			val += ts->samples[i].y; -		y = val / ts->sample_count; - -		for (i = 0, val = 0; i < ts->sample_count; i++) -			val += ts->samples[i].p; -		p = val / ts->sample_count; - -		input_report_abs(ts->input_dev, ABS_X, x); -		input_report_abs(ts->input_dev, ABS_Y, y); -		input_report_abs(ts->input_dev, ABS_PRESSURE, p); -		input_report_key(ts->input_dev, BTN_TOUCH, 1); -		input_sync(ts->input_dev); -	} - -	ts->sample_count = 0; - -	spin_unlock_irqrestore(&ts->lock, flags); -} - -static irqreturn_t tsc_irq(int irq, void *dev_id) -{ -	struct tsc_data *ts = (struct tsc_data *)dev_id; -	struct sample *sample; -	int index; - -	spin_lock(&ts->lock); - -	index = ts->sample_count % TSC_SAMPLES; -	sample = &ts->samples[index]; -	if (tsc_read_sample(ts, sample) < 0) -		goto out; - -	if (++ts->sample_count >= TSC_SKIP) { -		index = (ts->sample_count - TSC_TAIL_SKIP - 1) % TSC_SAMPLES; -		sample = &ts->samples[index]; - -		input_report_abs(ts->input_dev, ABS_X, sample->x); -		input_report_abs(ts->input_dev, ABS_Y, sample->y); -		input_report_abs(ts->input_dev, ABS_PRESSURE, sample->p); -		if (ts->sample_count == TSC_SKIP) -			input_report_key(ts->input_dev, BTN_TOUCH, 1); -		input_sync(ts->input_dev); -	} -	mod_timer(&ts->timer, jiffies + TSC_PENUP_POLL); -out: -	spin_unlock(&ts->lock); -	return IRQ_HANDLED; -} - -static int tsc_start(struct input_dev *dev) -{ -	struct tsc_data *ts = input_get_drvdata(dev); -	unsigned long timeout = jiffies + msecs_to_jiffies(IDLE_TIMEOUT); -	u32 val; - -	clk_enable(ts->clk); - -	/* Go to idle mode, before any initialization */ -	while (time_after(timeout, jiffies)) { -		if (tsc_read(ts, tscm) & IDLE) -			break; -	} - -	if (time_before(timeout, jiffies)) { -		dev_warn(ts->dev, "timeout waiting for idle\n"); -		clk_disable(ts->clk); -		return -EIO; -	} - -	/* Configure TSC Control register*/ -	val = (PONBG | PON | PVSTC(4) | ONE_SHOT | ZMEASURE_EN); -	tsc_write(ts, tscm, val); - -	/* Bring TSC out of reset: Clear AFE reset bit */ -	val &= ~(AFERST); -	tsc_write(ts, tscm, val); - -	/* Configure all pins for hardware control*/ -	tsc_write(ts, bwcm, 0); - -	/* Finally enable the TSC */ -	tsc_set_bits(ts, tscm, TSC_EN); - -	return 0; -} - -static void tsc_stop(struct input_dev *dev) -{ -	struct tsc_data *ts = input_get_drvdata(dev); - -	tsc_clr_bits(ts, tscm, TSC_EN); -	synchronize_irq(ts->tsc_irq); -	del_timer_sync(&ts->timer); -	clk_disable(ts->clk); -} - -static int tsc_probe(struct platform_device *pdev) -{ -	struct device *dev = &pdev->dev; -	struct tsc_data *ts; -	int error = 0; -	u32 rev = 0; - -	ts = kzalloc(sizeof(struct tsc_data), GFP_KERNEL); -	if (!ts) { -		dev_err(dev, "cannot allocate device info\n"); -		return -ENOMEM; -	} - -	ts->dev = dev; -	spin_lock_init(&ts->lock); -	setup_timer(&ts->timer, tsc_poll, (unsigned long)ts); -	platform_set_drvdata(pdev, ts); - -	ts->tsc_irq = platform_get_irq(pdev, 0); -	if (ts->tsc_irq < 0) { -		dev_err(dev, "cannot determine device interrupt\n"); -		error = -ENODEV; -		goto error_res; -	} - -	ts->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!ts->res) { -		dev_err(dev, "cannot determine register area\n"); -		error = -ENODEV; -		goto error_res; -	} - -	if (!request_mem_region(ts->res->start, resource_size(ts->res), -				pdev->name)) { -		dev_err(dev, "cannot claim register memory\n"); -		ts->res = NULL; -		error = -EINVAL; -		goto error_res; -	} - -	ts->regs = ioremap(ts->res->start, resource_size(ts->res)); -	if (!ts->regs) { -		dev_err(dev, "cannot map register memory\n"); -		error = -ENOMEM; -		goto error_map; -	} - -	ts->clk = clk_get(dev, NULL); -	if (IS_ERR(ts->clk)) { -		dev_err(dev, "cannot claim device clock\n"); -		error = PTR_ERR(ts->clk); -		goto error_clk; -	} - -	error = request_threaded_irq(ts->tsc_irq, NULL, tsc_irq, IRQF_ONESHOT, -				     dev_name(dev), ts); -	if (error < 0) { -		dev_err(ts->dev, "Could not allocate ts irq\n"); -		goto error_irq; -	} - -	ts->input_dev = input_allocate_device(); -	if (!ts->input_dev) { -		dev_err(dev, "cannot allocate input device\n"); -		error = -ENOMEM; -		goto error_input; -	} -	input_set_drvdata(ts->input_dev, ts); - -	ts->input_dev->name       = pdev->name; -	ts->input_dev->id.bustype = BUS_HOST; -	ts->input_dev->dev.parent = &pdev->dev; -	ts->input_dev->open	  = tsc_start; -	ts->input_dev->close	  = tsc_stop; - -	clk_enable(ts->clk); -	rev = tsc_read(ts, rev); -	ts->input_dev->id.product = ((rev >>  8) & 0x07); -	ts->input_dev->id.version = ((rev >> 16) & 0xfff); -	clk_disable(ts->clk); - -	__set_bit(EV_KEY,    ts->input_dev->evbit); -	__set_bit(EV_ABS,    ts->input_dev->evbit); -	__set_bit(BTN_TOUCH, ts->input_dev->keybit); - -	input_set_abs_params(ts->input_dev, ABS_X, 0, 0xffff, 5, 0); -	input_set_abs_params(ts->input_dev, ABS_Y, 0, 0xffff, 5, 0); -	input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 4095, 128, 0); - -	error = input_register_device(ts->input_dev); -	if (error < 0) { -		dev_err(dev, "failed input device registration\n"); -		goto error_reg; -	} - -	return 0; - -error_reg: -	input_free_device(ts->input_dev); -error_input: -	free_irq(ts->tsc_irq, ts); -error_irq: -	clk_put(ts->clk); -error_clk: -	iounmap(ts->regs); -error_map: -	release_mem_region(ts->res->start, resource_size(ts->res)); -error_res: -	kfree(ts); - -	return error; -} - -static int tsc_remove(struct platform_device *pdev) -{ -	struct tsc_data *ts = platform_get_drvdata(pdev); - -	input_unregister_device(ts->input_dev); -	free_irq(ts->tsc_irq, ts); -	clk_put(ts->clk); -	iounmap(ts->regs); -	release_mem_region(ts->res->start, resource_size(ts->res)); -	kfree(ts); - -	return 0; -} - -static struct platform_driver tsc_driver = { -	.probe		= tsc_probe, -	.remove		= tsc_remove, -	.driver.name	= "tnetv107x-ts", -	.driver.owner	= THIS_MODULE, -}; -module_platform_driver(tsc_driver); - -MODULE_AUTHOR("Cyril Chemparathy"); -MODULE_DESCRIPTION("TNETV107X Touchscreen Driver"); -MODULE_ALIAS("platform:tnetv107x-ts"); -MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/touchit213.c b/drivers/input/touchscreen/touchit213.c index 5f29e5b8e1c..c27cf8f3d1c 100644 --- a/drivers/input/touchscreen/touchit213.c +++ b/drivers/input/touchscreen/touchit213.c @@ -21,7 +21,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"Sahara TouchIT-213 serial touchscreen driver" diff --git a/drivers/input/touchscreen/touchright.c b/drivers/input/touchscreen/touchright.c index 8a2887daf19..4000e520540 100644 --- a/drivers/input/touchscreen/touchright.c +++ b/drivers/input/touchscreen/touchright.c @@ -20,7 +20,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"Touchright serial touchscreen driver" diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c index 588cdcb839d..ba90f447df7 100644 --- a/drivers/input/touchscreen/touchwin.c +++ b/drivers/input/touchscreen/touchwin.c @@ -27,7 +27,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"Touchwindow serial touchscreen driver" diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 7213e8b07e7..52380b68ebd 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -25,11 +25,15 @@  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/input.h> +#include <linux/input/touchscreen.h>  #include <linux/interrupt.h>  #include <linux/delay.h>  #include <linux/pm.h> +#include <linux/of.h> +#include <linux/of_gpio.h>  #include <linux/spi/spi.h>  #include <linux/spi/tsc2005.h> +#include <linux/regulator/consumer.h>  /*   * The touchscreen interface operates as follows: @@ -100,6 +104,11 @@  					 TSC2005_CFR2_AVG_7)  #define MAX_12BIT			0xfff +#define TSC2005_DEF_X_FUZZ		4 +#define TSC2005_DEF_Y_FUZZ		8 +#define TSC2005_DEF_P_FUZZ		2 +#define TSC2005_DEF_RESISTOR		280 +  #define TSC2005_SPI_MAX_SPEED_HZ	10000000  #define TSC2005_PENUP_TIME_MS		40 @@ -143,6 +152,9 @@ struct tsc2005 {  	bool			pen_down; +	struct regulator	*vio; + +	int			reset_gpio;  	void			(*set_reset)(bool enable);  }; @@ -337,6 +349,14 @@ static void tsc2005_stop_scan(struct tsc2005 *ts)  	tsc2005_cmd(ts, TSC2005_CMD_STOP);  } +static void tsc2005_set_reset(struct tsc2005 *ts, bool enable) +{ +	if (ts->reset_gpio >= 0) +		gpio_set_value(ts->reset_gpio, enable); +	else if (ts->set_reset) +		ts->set_reset(enable); +} +  /* must be called with ts->mutex held */  static void __tsc2005_disable(struct tsc2005 *ts)  { @@ -355,7 +375,7 @@ static void __tsc2005_enable(struct tsc2005 *ts)  {  	tsc2005_start_scan(ts); -	if (ts->esd_timeout && ts->set_reset) { +	if (ts->esd_timeout && (ts->set_reset || ts->reset_gpio)) {  		ts->last_valid_interrupt = jiffies;  		schedule_delayed_work(&ts->esd_work,  				round_jiffies_relative( @@ -414,9 +434,9 @@ static ssize_t tsc2005_selftest_show(struct device *dev,  	}  	/* hardware reset */ -	ts->set_reset(false); +	tsc2005_set_reset(ts, false);  	usleep_range(100, 500); /* only 10us required */ -	ts->set_reset(true); +	tsc2005_set_reset(ts, true);  	if (!success)  		goto out; @@ -459,7 +479,7 @@ static umode_t tsc2005_attr_is_visible(struct kobject *kobj,  	umode_t mode = attr->mode;  	if (attr == &dev_attr_selftest.attr) { -		if (!ts->set_reset) +		if (!ts->set_reset && !ts->reset_gpio)  			mode = 0;  	} @@ -509,9 +529,9 @@ static void tsc2005_esd_work(struct work_struct *work)  	tsc2005_update_pen_state(ts, 0, 0, 0); -	ts->set_reset(false); +	tsc2005_set_reset(ts, false);  	usleep_range(100, 500); /* only 10us required */ -	ts->set_reset(true); +	tsc2005_set_reset(ts, true);  	enable_irq(ts->spi->irq);  	tsc2005_start_scan(ts); @@ -571,30 +591,48 @@ static void tsc2005_setup_spi_xfer(struct tsc2005 *ts)  static int tsc2005_probe(struct spi_device *spi)  { -	const struct tsc2005_platform_data *pdata = spi->dev.platform_data; +	const struct tsc2005_platform_data *pdata = dev_get_platdata(&spi->dev); +	struct device_node *np = spi->dev.of_node; +  	struct tsc2005 *ts;  	struct input_dev *input_dev; -	unsigned int max_x, max_y, max_p; -	unsigned int fudge_x, fudge_y, fudge_p; +	unsigned int max_x = MAX_12BIT; +	unsigned int max_y = MAX_12BIT; +	unsigned int max_p = MAX_12BIT; +	unsigned int fudge_x = TSC2005_DEF_X_FUZZ; +	unsigned int fudge_y = TSC2005_DEF_Y_FUZZ; +	unsigned int fudge_p = TSC2005_DEF_P_FUZZ; +	unsigned int x_plate_ohm = TSC2005_DEF_RESISTOR; +	unsigned int esd_timeout;  	int error; -	if (!pdata) { -		dev_dbg(&spi->dev, "no platform data\n"); +	if (!np && !pdata) { +		dev_err(&spi->dev, "no platform data\n");  		return -ENODEV;  	} -	fudge_x	= pdata->ts_x_fudge	   ? : 4; -	fudge_y	= pdata->ts_y_fudge	   ? : 8; -	fudge_p	= pdata->ts_pressure_fudge ? : 2; -	max_x	= pdata->ts_x_max	   ? : MAX_12BIT; -	max_y	= pdata->ts_y_max	   ? : MAX_12BIT; -	max_p	= pdata->ts_pressure_max   ? : MAX_12BIT; -  	if (spi->irq <= 0) { -		dev_dbg(&spi->dev, "no irq\n"); +		dev_err(&spi->dev, "no irq\n");  		return -ENODEV;  	} +	if (pdata) { +		fudge_x	= pdata->ts_x_fudge; +		fudge_y	= pdata->ts_y_fudge; +		fudge_p	= pdata->ts_pressure_fudge; +		max_x	= pdata->ts_x_max; +		max_y	= pdata->ts_y_max; +		max_p	= pdata->ts_pressure_max; +		x_plate_ohm = pdata->ts_x_plate_ohm; +		esd_timeout = pdata->esd_timeout_ms; +	} else { +		x_plate_ohm = TSC2005_DEF_RESISTOR; +		of_property_read_u32(np, "ti,x-plate-ohms", &x_plate_ohm); +		esd_timeout = 0; +		of_property_read_u32(np, "ti,esd-recovery-timeout-ms", +								&esd_timeout); +	} +  	spi->mode = SPI_MODE_0;  	spi->bits_per_word = 8;  	if (!spi->max_speed_hz) @@ -604,19 +642,48 @@ static int tsc2005_probe(struct spi_device *spi)  	if (error)  		return error; -	ts = kzalloc(sizeof(*ts), GFP_KERNEL); -	input_dev = input_allocate_device(); -	if (!ts || !input_dev) { -		error = -ENOMEM; -		goto err_free_mem; -	} +	ts = devm_kzalloc(&spi->dev, sizeof(*ts), GFP_KERNEL); +	if (!ts) +		return -ENOMEM; + +	input_dev = devm_input_allocate_device(&spi->dev); +	if (!input_dev) +		return -ENOMEM;  	ts->spi = spi;  	ts->idev = input_dev; -	ts->x_plate_ohm	= pdata->ts_x_plate_ohm	? : 280; -	ts->esd_timeout	= pdata->esd_timeout_ms; -	ts->set_reset	= pdata->set_reset; +	ts->x_plate_ohm = x_plate_ohm; +	ts->esd_timeout = esd_timeout; + +	if (np) { +		ts->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0); +		if (ts->reset_gpio == -EPROBE_DEFER) +			return ts->reset_gpio; +		if (ts->reset_gpio < 0) { +			dev_err(&spi->dev, "error acquiring reset gpio: %d\n", +				ts->reset_gpio); +			return ts->reset_gpio; +		} + +		error = devm_gpio_request_one(&spi->dev, ts->reset_gpio, 0, +					      "reset-gpios"); +		if (error) { +			dev_err(&spi->dev, "error requesting reset gpio: %d\n", +				error); +			return error; +		} + +		ts->vio = devm_regulator_get(&spi->dev, "vio"); +		if (IS_ERR(ts->vio)) { +			error = PTR_ERR(ts->vio); +			dev_err(&spi->dev, "vio regulator missing (%d)", error); +			return error; +		} +	} else { +		ts->reset_gpio = -1; +		ts->set_reset = pdata->set_reset; +	}  	mutex_init(&ts->mutex); @@ -641,6 +708,9 @@ static int tsc2005_probe(struct spi_device *spi)  	input_set_abs_params(input_dev, ABS_Y, 0, max_y, fudge_y, 0);  	input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0); +	if (np) +		touchscreen_parse_of_params(input_dev); +  	input_dev->open = tsc2005_open;  	input_dev->close = tsc2005_close; @@ -649,12 +719,20 @@ static int tsc2005_probe(struct spi_device *spi)  	/* Ensure the touchscreen is off */  	tsc2005_stop_scan(ts); -	error = request_threaded_irq(spi->irq, NULL, tsc2005_irq_thread, -				     IRQF_TRIGGER_RISING | IRQF_ONESHOT, -				     "tsc2005", ts); +	error = devm_request_threaded_irq(&spi->dev, spi->irq, NULL, +					  tsc2005_irq_thread, +					  IRQF_TRIGGER_RISING | IRQF_ONESHOT, +					  "tsc2005", ts);  	if (error) {  		dev_err(&spi->dev, "Failed to request irq, err: %d\n", error); -		goto err_free_mem; +		return error; +	} + +	/* enable regulator for DT */ +	if (ts->vio) { +		error = regulator_enable(ts->vio); +		if (error) +			return error;  	}  	spi_set_drvdata(spi, ts); @@ -662,7 +740,7 @@ static int tsc2005_probe(struct spi_device *spi)  	if (error) {  		dev_err(&spi->dev,  			"Failed to create sysfs attributes, err: %d\n", error); -		goto err_clear_drvdata; +		goto disable_regulator;  	}  	error = input_register_device(ts->idev); @@ -677,12 +755,9 @@ static int tsc2005_probe(struct spi_device *spi)  err_remove_sysfs:  	sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group); -err_clear_drvdata: -	spi_set_drvdata(spi, NULL); -	free_irq(spi->irq, ts); -err_free_mem: -	input_free_device(input_dev); -	kfree(ts); +disable_regulator: +	if (ts->vio) +		regulator_disable(ts->vio);  	return error;  } @@ -690,13 +765,11 @@ static int tsc2005_remove(struct spi_device *spi)  {  	struct tsc2005 *ts = spi_get_drvdata(spi); -	sysfs_remove_group(&ts->spi->dev.kobj, &tsc2005_attr_group); +	sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group); -	free_irq(ts->spi->irq, ts); -	input_unregister_device(ts->idev); -	kfree(ts); +	if (ts->vio) +		regulator_disable(ts->vio); -	spi_set_drvdata(spi, NULL);  	return 0;  } diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 0b67ba476b4..1bf9906b5a3 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -26,6 +26,9 @@  #include <linux/interrupt.h>  #include <linux/i2c.h>  #include <linux/i2c/tsc2007.h> +#include <linux/of_device.h> +#include <linux/of.h> +#include <linux/of_gpio.h>  #define TSC2007_MEASURE_TEMP0		(0x0 << 4)  #define TSC2007_MEASURE_AUX		(0x2 << 4) @@ -72,15 +75,18 @@ struct tsc2007 {  	u16			model;  	u16			x_plate_ohms;  	u16			max_rt; -	unsigned long		poll_delay;  	unsigned long		poll_period; +	int			fuzzx; +	int			fuzzy; +	int			fuzzz; +	unsigned		gpio;  	int			irq;  	wait_queue_head_t	wait;  	bool			stopped; -	int			(*get_pendown_state)(void); +	int			(*get_pendown_state)(struct device *);  	void			(*clear_penirq)(void);  }; @@ -161,7 +167,7 @@ static bool tsc2007_is_pen_down(struct tsc2007 *ts)  	if (!ts->get_pendown_state)  		return true; -	return ts->get_pendown_state(); +	return ts->get_pendown_state(&ts->client->dev);  }  static irqreturn_t tsc2007_soft_irq(int irq, void *handle) @@ -178,7 +184,7 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle)  		rt = tsc2007_calculate_pressure(ts, &tc); -		if (rt == 0 && !ts->get_pendown_state) { +		if (!rt && !ts->get_pendown_state) {  			/*  			 * If pressure reported is 0 and we don't have  			 * callback to check pendown state, we have to @@ -228,7 +234,7 @@ static irqreturn_t tsc2007_hard_irq(int irq, void *handle)  {  	struct tsc2007 *ts = handle; -	if (!ts->get_pendown_state || likely(ts->get_pendown_state())) +	if (tsc2007_is_pen_down(ts))  		return IRQ_WAKE_THREAD;  	if (ts->clear_penirq) @@ -273,49 +279,134 @@ static void tsc2007_close(struct input_dev *input_dev)  	tsc2007_stop(ts);  } -static int tsc2007_probe(struct i2c_client *client, -				   const struct i2c_device_id *id) +#ifdef CONFIG_OF +static int tsc2007_get_pendown_state_gpio(struct device *dev)  { -	struct tsc2007 *ts; -	struct tsc2007_platform_data *pdata = client->dev.platform_data; -	struct input_dev *input_dev; -	int err; +	struct i2c_client *client = to_i2c_client(dev); +	struct tsc2007 *ts = i2c_get_clientdata(client); + +	return !gpio_get_value(ts->gpio); +} + +static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts) +{ +	struct device_node *np = client->dev.of_node; +	u32 val32; +	u64 val64; -	if (!pdata) { -		dev_err(&client->dev, "platform data is required!\n"); +	if (!np) { +		dev_err(&client->dev, "missing device tree data\n");  		return -EINVAL;  	} -	if (!i2c_check_functionality(client->adapter, -				     I2C_FUNC_SMBUS_READ_WORD_DATA)) -		return -EIO; +	if (!of_property_read_u32(np, "ti,max-rt", &val32)) +		ts->max_rt = val32; +	else +		ts->max_rt = MAX_12BIT; + +	if (!of_property_read_u32(np, "ti,fuzzx", &val32)) +		ts->fuzzx = val32; + +	if (!of_property_read_u32(np, "ti,fuzzy", &val32)) +		ts->fuzzy = val32; + +	if (!of_property_read_u32(np, "ti,fuzzz", &val32)) +		ts->fuzzz = val32; + +	if (!of_property_read_u64(np, "ti,poll-period", &val64)) +		ts->poll_period = val64; +	else +		ts->poll_period = 1; -	ts = kzalloc(sizeof(struct tsc2007), GFP_KERNEL); -	input_dev = input_allocate_device(); -	if (!ts || !input_dev) { -		err = -ENOMEM; -		goto err_free_mem; +	if (!of_property_read_u32(np, "ti,x-plate-ohms", &val32)) { +		ts->x_plate_ohms = val32; +	} else { +		dev_err(&client->dev, "missing ti,x-plate-ohms devicetree property."); +		return -EINVAL;  	} -	ts->client = client; -	ts->irq = client->irq; -	ts->input = input_dev; -	init_waitqueue_head(&ts->wait); +	ts->gpio = of_get_gpio(np, 0); +	if (gpio_is_valid(ts->gpio)) +		ts->get_pendown_state = tsc2007_get_pendown_state_gpio; +	else +		dev_warn(&client->dev, +			 "GPIO not specified in DT (of_get_gpio returned %d)\n", +			 ts->gpio); + +	return 0; +} +#else +static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts) +{ +	dev_err(&client->dev, "platform data is required!\n"); +	return -EINVAL; +} +#endif +static int tsc2007_probe_pdev(struct i2c_client *client, struct tsc2007 *ts, +			      const struct tsc2007_platform_data *pdata, +			      const struct i2c_device_id *id) +{  	ts->model             = pdata->model;  	ts->x_plate_ohms      = pdata->x_plate_ohms;  	ts->max_rt            = pdata->max_rt ? : MAX_12BIT; -	ts->poll_delay        = pdata->poll_delay ? : 1;  	ts->poll_period       = pdata->poll_period ? : 1;  	ts->get_pendown_state = pdata->get_pendown_state;  	ts->clear_penirq      = pdata->clear_penirq; +	ts->fuzzx             = pdata->fuzzx; +	ts->fuzzy             = pdata->fuzzy; +	ts->fuzzz             = pdata->fuzzz;  	if (pdata->x_plate_ohms == 0) {  		dev_err(&client->dev, "x_plate_ohms is not set up in platform data"); -		err = -EINVAL; -		goto err_free_mem; +		return -EINVAL;  	} +	return 0; +} + +static void tsc2007_call_exit_platform_hw(void *data) +{ +	struct device *dev = data; +	const struct tsc2007_platform_data *pdata = dev_get_platdata(dev); + +	pdata->exit_platform_hw(); +} + +static int tsc2007_probe(struct i2c_client *client, +			 const struct i2c_device_id *id) +{ +	const struct tsc2007_platform_data *pdata = dev_get_platdata(&client->dev); +	struct tsc2007 *ts; +	struct input_dev *input_dev; +	int err; + +	if (!i2c_check_functionality(client->adapter, +				     I2C_FUNC_SMBUS_READ_WORD_DATA)) +		return -EIO; + +	ts = devm_kzalloc(&client->dev, sizeof(struct tsc2007), GFP_KERNEL); +	if (!ts) +		return -ENOMEM; + +	if (pdata) +		err = tsc2007_probe_pdev(client, ts, pdata, id); +	else +		err = tsc2007_probe_dt(client, ts); +	if (err) +		return err; + +	input_dev = devm_input_allocate_device(&client->dev); +	if (!input_dev) +		return -ENOMEM; + +	i2c_set_clientdata(client, ts); + +	ts->client = client; +	ts->irq = client->irq; +	ts->input = input_dev; +	init_waitqueue_head(&ts->wait); +  	snprintf(ts->phys, sizeof(ts->phys),  		 "%s/input0", dev_name(&client->dev)); @@ -331,53 +422,46 @@ static int tsc2007_probe(struct i2c_client *client,  	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);  	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); -	input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, pdata->fuzzx, 0); -	input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, pdata->fuzzy, 0); +	input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, ts->fuzzx, 0); +	input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, ts->fuzzy, 0);  	input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, -			pdata->fuzzz, 0); +			     ts->fuzzz, 0); + +	if (pdata) { +		if (pdata->exit_platform_hw) { +			err = devm_add_action(&client->dev, +					      tsc2007_call_exit_platform_hw, +					      &client->dev); +			if (err) { +				dev_err(&client->dev, +					"Failed to register exit_platform_hw action, %d\n", +					err); +				return err; +			} +		} -	if (pdata->init_platform_hw) -		pdata->init_platform_hw(); +		if (pdata->init_platform_hw) +			pdata->init_platform_hw(); +	} -	err = request_threaded_irq(ts->irq, tsc2007_hard_irq, tsc2007_soft_irq, -				   IRQF_ONESHOT, client->dev.driver->name, ts); -	if (err < 0) { -		dev_err(&client->dev, "irq %d busy?\n", ts->irq); -		goto err_free_mem; +	err = devm_request_threaded_irq(&client->dev, ts->irq, +					tsc2007_hard_irq, tsc2007_soft_irq, +					IRQF_ONESHOT, +					client->dev.driver->name, ts); +	if (err) { +		dev_err(&client->dev, "Failed to request irq %d: %d\n", +			ts->irq, err); +		return err;  	}  	tsc2007_stop(ts);  	err = input_register_device(input_dev); -	if (err) -		goto err_free_irq; - -	i2c_set_clientdata(client, ts); - -	return 0; - - err_free_irq: -	free_irq(ts->irq, ts); -	if (pdata->exit_platform_hw) -		pdata->exit_platform_hw(); - err_free_mem: -	input_free_device(input_dev); -	kfree(ts); -	return err; -} - -static int tsc2007_remove(struct i2c_client *client) -{ -	struct tsc2007	*ts = i2c_get_clientdata(client); -	struct tsc2007_platform_data *pdata = client->dev.platform_data; - -	free_irq(ts->irq, ts); - -	if (pdata->exit_platform_hw) -		pdata->exit_platform_hw(); - -	input_unregister_device(ts->input); -	kfree(ts); +	if (err) { +		dev_err(&client->dev, +			"Failed to register input device: %d\n", err); +		return err; +	}  	return 0;  } @@ -389,14 +473,22 @@ static const struct i2c_device_id tsc2007_idtable[] = {  MODULE_DEVICE_TABLE(i2c, tsc2007_idtable); +#ifdef CONFIG_OF +static const struct of_device_id tsc2007_of_match[] = { +	{ .compatible = "ti,tsc2007" }, +	{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, tsc2007_of_match); +#endif +  static struct i2c_driver tsc2007_driver = {  	.driver = {  		.owner	= THIS_MODULE, -		.name	= "tsc2007" +		.name	= "tsc2007", +		.of_match_table = of_match_ptr(tsc2007_of_match),  	},  	.id_table	= tsc2007_idtable,  	.probe		= tsc2007_probe, -	.remove		= tsc2007_remove,  };  module_i2c_driver(tsc2007_driver); diff --git a/drivers/input/touchscreen/tsc40.c b/drivers/input/touchscreen/tsc40.c index eb96f168fb9..29687872cb9 100644 --- a/drivers/input/touchscreen/tsc40.c +++ b/drivers/input/touchscreen/tsc40.c @@ -11,7 +11,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define PACKET_LENGTH  5  struct tsc_ser { diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index 1271f97b407..b46c55cd1bb 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -19,7 +19,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/delay.h>  #include <linux/sched.h>  #include <linux/wait.h> @@ -320,7 +319,7 @@ static int ucb1400_ts_detect_irq(struct ucb1400_ts *ucb,  static int ucb1400_ts_probe(struct platform_device *pdev)  { -	struct ucb1400_ts *ucb = pdev->dev.platform_data; +	struct ucb1400_ts *ucb = dev_get_platdata(&pdev->dev);  	int error, x_res, y_res;  	u16 fcsr; @@ -399,7 +398,7 @@ err:  static int ucb1400_ts_remove(struct platform_device *pdev)  { -	struct ucb1400_ts *ucb = pdev->dev.platform_data; +	struct ucb1400_ts *ucb = dev_get_platdata(&pdev->dev);  	free_irq(ucb->irq, ucb);  	input_unregister_device(ucb->ts_idev); @@ -410,7 +409,7 @@ static int ucb1400_ts_remove(struct platform_device *pdev)  #ifdef CONFIG_PM_SLEEP  static int ucb1400_ts_suspend(struct device *dev)  { -	struct ucb1400_ts *ucb = dev->platform_data; +	struct ucb1400_ts *ucb = dev_get_platdata(dev);  	struct input_dev *idev = ucb->ts_idev;  	mutex_lock(&idev->mutex); @@ -424,7 +423,7 @@ static int ucb1400_ts_suspend(struct device *dev)  static int ucb1400_ts_resume(struct device *dev)  { -	struct ucb1400_ts *ucb = dev->platform_data; +	struct ucb1400_ts *ucb = dev_get_platdata(dev);  	struct input_dev *idev = ucb->ts_idev;  	mutex_lock(&idev->mutex); diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index 721fdb3597c..a0966331a89 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -51,7 +51,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/usb.h>  #include <linux/usb/input.h>  #include <linux/hid.h> @@ -106,6 +105,7 @@ struct usbtouch_device_info {  struct usbtouch_usb {  	unsigned char *data;  	dma_addr_t data_dma; +	int data_size;  	unsigned char *buffer;  	int buf_len;  	struct urb *irq; @@ -146,12 +146,10 @@ enum {  #define USB_DEVICE_HID_CLASS(vend, prod) \  	.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS \ -		| USB_DEVICE_ID_MATCH_INT_PROTOCOL \  		| USB_DEVICE_ID_MATCH_DEVICE, \  	.idVendor = (vend), \  	.idProduct = (prod), \ -	.bInterfaceClass = USB_INTERFACE_CLASS_HID, \ -	.bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE +	.bInterfaceClass = USB_INTERFACE_CLASS_HID  static const struct usb_device_id usbtouch_devices[] = {  #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX @@ -1523,7 +1521,7 @@ static int usbtouch_reset_resume(struct usb_interface *intf)  static void usbtouch_free_buffers(struct usb_device *udev,  				  struct usbtouch_usb *usbtouch)  { -	usb_free_coherent(udev, usbtouch->type->rept_size, +	usb_free_coherent(udev, usbtouch->data_size,  			  usbtouch->data, usbtouch->data_dma);  	kfree(usbtouch->buffer);  } @@ -1568,7 +1566,20 @@ static int usbtouch_probe(struct usb_interface *intf,  	if (!type->process_pkt)  		type->process_pkt = usbtouch_process_pkt; -	usbtouch->data = usb_alloc_coherent(udev, type->rept_size, +	usbtouch->data_size = type->rept_size; +	if (type->get_pkt_len) { +		/* +		 * When dealing with variable-length packets we should +		 * not request more than wMaxPacketSize bytes at once +		 * as we do not know if there is more data coming or +		 * we filled exactly wMaxPacketSize bytes and there is +		 * nothing else. +		 */ +		usbtouch->data_size = min(usbtouch->data_size, +					  usb_endpoint_maxp(endpoint)); +	} + +	usbtouch->data = usb_alloc_coherent(udev, usbtouch->data_size,  					    GFP_KERNEL, &usbtouch->data_dma);  	if (!usbtouch->data)  		goto out_free; @@ -1628,12 +1639,12 @@ static int usbtouch_probe(struct usb_interface *intf,  	if (usb_endpoint_type(endpoint) == USB_ENDPOINT_XFER_INT)  		usb_fill_int_urb(usbtouch->irq, udev,  			 usb_rcvintpipe(udev, endpoint->bEndpointAddress), -			 usbtouch->data, type->rept_size, +			 usbtouch->data, usbtouch->data_size,  			 usbtouch_irq, usbtouch, endpoint->bInterval);  	else  		usb_fill_bulk_urb(usbtouch->irq, udev,  			 usb_rcvbulkpipe(udev, endpoint->bEndpointAddress), -			 usbtouch->data, type->rept_size, +			 usbtouch->data, usbtouch->data_size,  			 usbtouch_irq, usbtouch);  	usbtouch->irq->dev = udev; diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c index 9a83be6b658..2792ca397dd 100644 --- a/drivers/input/touchscreen/wacom_w8001.c +++ b/drivers/input/touchscreen/wacom_w8001.c @@ -18,7 +18,6 @@  #include <linux/slab.h>  #include <linux/input/mt.h>  #include <linux/serio.h> -#include <linux/init.h>  #include <linux/ctype.h>  #include <linux/delay.h> diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index 6be2eb6a153..1b953a066b2 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -13,7 +13,6 @@  #include <linux/module.h>  #include <linux/moduleparam.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/string.h>  #include <linux/pm.h>  #include <linux/input.h> diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index 7e45c9f6e6b..d0ef91fc87d 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c @@ -584,7 +584,7 @@ static void wm97xx_ts_input_close(struct input_dev *idev)  static int wm97xx_probe(struct device *dev)  {  	struct wm97xx *wm; -	struct wm97xx_pdata *pdata = dev->platform_data; +	struct wm97xx_pdata *pdata = dev_get_platdata(dev);  	int ret = 0, id = 0;  	wm = kzalloc(sizeof(struct wm97xx), GFP_KERNEL); diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c new file mode 100644 index 00000000000..feea85b52fa --- /dev/null +++ b/drivers/input/touchscreen/zforce_ts.c @@ -0,0 +1,905 @@ +/* + * Copyright (C) 2012-2013 MundoReader S.L. + * Author: Heiko Stuebner <heiko@sntech.de> + * + * based in parts on Nook zforce driver + * + * Copyright (C) 2010 Barnes & Noble, Inc. + * Author: Pieter Truter<ptruter@intrinsyc.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/hrtimer.h> +#include <linux/slab.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/device.h> +#include <linux/sysfs.h> +#include <linux/input/mt.h> +#include <linux/platform_data/zforce_ts.h> +#include <linux/of.h> +#include <linux/of_gpio.h> + +#define WAIT_TIMEOUT		msecs_to_jiffies(1000) + +#define FRAME_START		0xee +#define FRAME_MAXSIZE		257 + +/* Offsets of the different parts of the payload the controller sends */ +#define PAYLOAD_HEADER		0 +#define PAYLOAD_LENGTH		1 +#define PAYLOAD_BODY		2 + +/* Response offsets */ +#define RESPONSE_ID		0 +#define RESPONSE_DATA		1 + +/* Commands */ +#define COMMAND_DEACTIVATE	0x00 +#define COMMAND_INITIALIZE	0x01 +#define COMMAND_RESOLUTION	0x02 +#define COMMAND_SETCONFIG	0x03 +#define COMMAND_DATAREQUEST	0x04 +#define COMMAND_SCANFREQ	0x08 +#define COMMAND_STATUS		0X1e + +/* + * Responses the controller sends as a result of + * command requests + */ +#define RESPONSE_DEACTIVATE	0x00 +#define RESPONSE_INITIALIZE	0x01 +#define RESPONSE_RESOLUTION	0x02 +#define RESPONSE_SETCONFIG	0x03 +#define RESPONSE_SCANFREQ	0x08 +#define RESPONSE_STATUS		0X1e + +/* + * Notifications are sent by the touch controller without + * being requested by the driver and include for example + * touch indications + */ +#define NOTIFICATION_TOUCH		0x04 +#define NOTIFICATION_BOOTCOMPLETE	0x07 +#define NOTIFICATION_OVERRUN		0x25 +#define NOTIFICATION_PROXIMITY		0x26 +#define NOTIFICATION_INVALID_COMMAND	0xfe + +#define ZFORCE_REPORT_POINTS		2 +#define ZFORCE_MAX_AREA			0xff + +#define STATE_DOWN			0 +#define STATE_MOVE			1 +#define STATE_UP			2 + +#define SETCONFIG_DUALTOUCH		(1 << 0) + +struct zforce_point { +	int coord_x; +	int coord_y; +	int state; +	int id; +	int area_major; +	int area_minor; +	int orientation; +	int pressure; +	int prblty; +}; + +/* + * @client		the i2c_client + * @input		the input device + * @suspending		in the process of going to suspend (don't emit wakeup + *			events for commands executed to suspend the device) + * @suspended		device suspended + * @access_mutex	serialize i2c-access, to keep multipart reads together + * @command_done	completion to wait for the command result + * @command_mutex	serialize commands sent to the ic + * @command_waiting	the id of the command that is currently waiting + *			for a result + * @command_result	returned result of the command + */ +struct zforce_ts { +	struct i2c_client	*client; +	struct input_dev	*input; +	const struct zforce_ts_platdata *pdata; +	char			phys[32]; + +	bool			suspending; +	bool			suspended; +	bool			boot_complete; + +	/* Firmware version information */ +	u16			version_major; +	u16			version_minor; +	u16			version_build; +	u16			version_rev; + +	struct mutex		access_mutex; + +	struct completion	command_done; +	struct mutex		command_mutex; +	int			command_waiting; +	int			command_result; +}; + +static int zforce_command(struct zforce_ts *ts, u8 cmd) +{ +	struct i2c_client *client = ts->client; +	char buf[3]; +	int ret; + +	dev_dbg(&client->dev, "%s: 0x%x\n", __func__, cmd); + +	buf[0] = FRAME_START; +	buf[1] = 1; /* data size, command only */ +	buf[2] = cmd; + +	mutex_lock(&ts->access_mutex); +	ret = i2c_master_send(client, &buf[0], ARRAY_SIZE(buf)); +	mutex_unlock(&ts->access_mutex); +	if (ret < 0) { +		dev_err(&client->dev, "i2c send data request error: %d\n", ret); +		return ret; +	} + +	return 0; +} + +static int zforce_send_wait(struct zforce_ts *ts, const char *buf, int len) +{ +	struct i2c_client *client = ts->client; +	int ret; + +	ret = mutex_trylock(&ts->command_mutex); +	if (!ret) { +		dev_err(&client->dev, "already waiting for a command\n"); +		return -EBUSY; +	} + +	dev_dbg(&client->dev, "sending %d bytes for command 0x%x\n", +		buf[1], buf[2]); + +	ts->command_waiting = buf[2]; + +	mutex_lock(&ts->access_mutex); +	ret = i2c_master_send(client, buf, len); +	mutex_unlock(&ts->access_mutex); +	if (ret < 0) { +		dev_err(&client->dev, "i2c send data request error: %d\n", ret); +		goto unlock; +	} + +	dev_dbg(&client->dev, "waiting for result for command 0x%x\n", buf[2]); + +	if (wait_for_completion_timeout(&ts->command_done, WAIT_TIMEOUT) == 0) { +		ret = -ETIME; +		goto unlock; +	} + +	ret = ts->command_result; + +unlock: +	mutex_unlock(&ts->command_mutex); +	return ret; +} + +static int zforce_command_wait(struct zforce_ts *ts, u8 cmd) +{ +	struct i2c_client *client = ts->client; +	char buf[3]; +	int ret; + +	dev_dbg(&client->dev, "%s: 0x%x\n", __func__, cmd); + +	buf[0] = FRAME_START; +	buf[1] = 1; /* data size, command only */ +	buf[2] = cmd; + +	ret = zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf)); +	if (ret < 0) { +		dev_err(&client->dev, "i2c send data request error: %d\n", ret); +		return ret; +	} + +	return 0; +} + +static int zforce_resolution(struct zforce_ts *ts, u16 x, u16 y) +{ +	struct i2c_client *client = ts->client; +	char buf[7] = { FRAME_START, 5, COMMAND_RESOLUTION, +			(x & 0xff), ((x >> 8) & 0xff), +			(y & 0xff), ((y >> 8) & 0xff) }; + +	dev_dbg(&client->dev, "set resolution to (%d,%d)\n", x, y); + +	return zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf)); +} + +static int zforce_scan_frequency(struct zforce_ts *ts, u16 idle, u16 finger, +				 u16 stylus) +{ +	struct i2c_client *client = ts->client; +	char buf[9] = { FRAME_START, 7, COMMAND_SCANFREQ, +			(idle & 0xff), ((idle >> 8) & 0xff), +			(finger & 0xff), ((finger >> 8) & 0xff), +			(stylus & 0xff), ((stylus >> 8) & 0xff) }; + +	dev_dbg(&client->dev, +		"set scan frequency to (idle: %d, finger: %d, stylus: %d)\n", +		idle, finger, stylus); + +	return zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf)); +} + +static int zforce_setconfig(struct zforce_ts *ts, char b1) +{ +	struct i2c_client *client = ts->client; +	char buf[7] = { FRAME_START, 5, COMMAND_SETCONFIG, +			b1, 0, 0, 0 }; + +	dev_dbg(&client->dev, "set config to (%d)\n", b1); + +	return zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf)); +} + +static int zforce_start(struct zforce_ts *ts) +{ +	struct i2c_client *client = ts->client; +	const struct zforce_ts_platdata *pdata = ts->pdata; +	int ret; + +	dev_dbg(&client->dev, "starting device\n"); + +	ret = zforce_command_wait(ts, COMMAND_INITIALIZE); +	if (ret) { +		dev_err(&client->dev, "Unable to initialize, %d\n", ret); +		return ret; +	} + +	ret = zforce_resolution(ts, pdata->x_max, pdata->y_max); +	if (ret) { +		dev_err(&client->dev, "Unable to set resolution, %d\n", ret); +		goto error; +	} + +	ret = zforce_scan_frequency(ts, 10, 50, 50); +	if (ret) { +		dev_err(&client->dev, "Unable to set scan frequency, %d\n", +			ret); +		goto error; +	} + +	ret = zforce_setconfig(ts, SETCONFIG_DUALTOUCH); +	if (ret) { +		dev_err(&client->dev, "Unable to set config\n"); +		goto error; +	} + +	/* start sending touch events */ +	ret = zforce_command(ts, COMMAND_DATAREQUEST); +	if (ret) { +		dev_err(&client->dev, "Unable to request data\n"); +		goto error; +	} + +	/* +	 * Per NN, initial cal. take max. of 200msec. +	 * Allow time to complete this calibration +	 */ +	msleep(200); + +	return 0; + +error: +	zforce_command_wait(ts, COMMAND_DEACTIVATE); +	return ret; +} + +static int zforce_stop(struct zforce_ts *ts) +{ +	struct i2c_client *client = ts->client; +	int ret; + +	dev_dbg(&client->dev, "stopping device\n"); + +	/* Deactivates touch sensing and puts the device into sleep. */ +	ret = zforce_command_wait(ts, COMMAND_DEACTIVATE); +	if (ret != 0) { +		dev_err(&client->dev, "could not deactivate device, %d\n", +			ret); +		return ret; +	} + +	return 0; +} + +static int zforce_touch_event(struct zforce_ts *ts, u8 *payload) +{ +	struct i2c_client *client = ts->client; +	const struct zforce_ts_platdata *pdata = ts->pdata; +	struct zforce_point point; +	int count, i, num = 0; + +	count = payload[0]; +	if (count > ZFORCE_REPORT_POINTS) { +		dev_warn(&client->dev, +			 "too many coordinates %d, expected max %d\n", +			 count, ZFORCE_REPORT_POINTS); +		count = ZFORCE_REPORT_POINTS; +	} + +	for (i = 0; i < count; i++) { +		point.coord_x = +			payload[9 * i + 2] << 8 | payload[9 * i + 1]; +		point.coord_y = +			payload[9 * i + 4] << 8 | payload[9 * i + 3]; + +		if (point.coord_x > pdata->x_max || +		    point.coord_y > pdata->y_max) { +			dev_warn(&client->dev, "coordinates (%d,%d) invalid\n", +				point.coord_x, point.coord_y); +			point.coord_x = point.coord_y = 0; +		} + +		point.state = payload[9 * i + 5] & 0x03; +		point.id = (payload[9 * i + 5] & 0xfc) >> 2; + +		/* determine touch major, minor and orientation */ +		point.area_major = max(payload[9 * i + 6], +					  payload[9 * i + 7]); +		point.area_minor = min(payload[9 * i + 6], +					  payload[9 * i + 7]); +		point.orientation = payload[9 * i + 6] > payload[9 * i + 7]; + +		point.pressure = payload[9 * i + 8]; +		point.prblty = payload[9 * i + 9]; + +		dev_dbg(&client->dev, +			"point %d/%d: state %d, id %d, pressure %d, prblty %d, x %d, y %d, amajor %d, aminor %d, ori %d\n", +			i, count, point.state, point.id, +			point.pressure, point.prblty, +			point.coord_x, point.coord_y, +			point.area_major, point.area_minor, +			point.orientation); + +		/* the zforce id starts with "1", so needs to be decreased */ +		input_mt_slot(ts->input, point.id - 1); + +		input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, +						point.state != STATE_UP); + +		if (point.state != STATE_UP) { +			input_report_abs(ts->input, ABS_MT_POSITION_X, +					 point.coord_x); +			input_report_abs(ts->input, ABS_MT_POSITION_Y, +					 point.coord_y); +			input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, +					 point.area_major); +			input_report_abs(ts->input, ABS_MT_TOUCH_MINOR, +					 point.area_minor); +			input_report_abs(ts->input, ABS_MT_ORIENTATION, +					 point.orientation); +			num++; +		} +	} + +	input_mt_sync_frame(ts->input); + +	input_mt_report_finger_count(ts->input, num); + +	input_sync(ts->input); + +	return 0; +} + +static int zforce_read_packet(struct zforce_ts *ts, u8 *buf) +{ +	struct i2c_client *client = ts->client; +	int ret; + +	mutex_lock(&ts->access_mutex); + +	/* read 2 byte message header */ +	ret = i2c_master_recv(client, buf, 2); +	if (ret < 0) { +		dev_err(&client->dev, "error reading header: %d\n", ret); +		goto unlock; +	} + +	if (buf[PAYLOAD_HEADER] != FRAME_START) { +		dev_err(&client->dev, "invalid frame start: %d\n", buf[0]); +		ret = -EIO; +		goto unlock; +	} + +	if (buf[PAYLOAD_LENGTH] == 0) { +		dev_err(&client->dev, "invalid payload length: %d\n", +			buf[PAYLOAD_LENGTH]); +		ret = -EIO; +		goto unlock; +	} + +	/* read the message */ +	ret = i2c_master_recv(client, &buf[PAYLOAD_BODY], buf[PAYLOAD_LENGTH]); +	if (ret < 0) { +		dev_err(&client->dev, "error reading payload: %d\n", ret); +		goto unlock; +	} + +	dev_dbg(&client->dev, "read %d bytes for response command 0x%x\n", +		buf[PAYLOAD_LENGTH], buf[PAYLOAD_BODY]); + +unlock: +	mutex_unlock(&ts->access_mutex); +	return ret; +} + +static void zforce_complete(struct zforce_ts *ts, int cmd, int result) +{ +	struct i2c_client *client = ts->client; + +	if (ts->command_waiting == cmd) { +		dev_dbg(&client->dev, "completing command 0x%x\n", cmd); +		ts->command_result = result; +		complete(&ts->command_done); +	} else { +		dev_dbg(&client->dev, "command %d not for us\n", cmd); +	} +} + +static irqreturn_t zforce_irq(int irq, void *dev_id) +{ +	struct zforce_ts *ts = dev_id; +	struct i2c_client *client = ts->client; + +	if (ts->suspended && device_may_wakeup(&client->dev)) +		pm_wakeup_event(&client->dev, 500); + +	return IRQ_WAKE_THREAD; +} + +static irqreturn_t zforce_irq_thread(int irq, void *dev_id) +{ +	struct zforce_ts *ts = dev_id; +	struct i2c_client *client = ts->client; +	const struct zforce_ts_platdata *pdata = ts->pdata; +	int ret; +	u8 payload_buffer[FRAME_MAXSIZE]; +	u8 *payload; + +	/* +	 * When still suspended, return. +	 * Due to the level-interrupt we will get re-triggered later. +	 */ +	if (ts->suspended) { +		msleep(20); +		return IRQ_HANDLED; +	} + +	dev_dbg(&client->dev, "handling interrupt\n"); + +	/* Don't emit wakeup events from commands run by zforce_suspend */ +	if (!ts->suspending && device_may_wakeup(&client->dev)) +		pm_stay_awake(&client->dev); + +	while (!gpio_get_value(pdata->gpio_int)) { +		ret = zforce_read_packet(ts, payload_buffer); +		if (ret < 0) { +			dev_err(&client->dev, +				"could not read packet, ret: %d\n", ret); +			break; +		} + +		payload =  &payload_buffer[PAYLOAD_BODY]; + +		switch (payload[RESPONSE_ID]) { +		case NOTIFICATION_TOUCH: +			/* +			 * Always report touch-events received while +			 * suspending, when being a wakeup source +			 */ +			if (ts->suspending && device_may_wakeup(&client->dev)) +				pm_wakeup_event(&client->dev, 500); +			zforce_touch_event(ts, &payload[RESPONSE_DATA]); +			break; + +		case NOTIFICATION_BOOTCOMPLETE: +			ts->boot_complete = payload[RESPONSE_DATA]; +			zforce_complete(ts, payload[RESPONSE_ID], 0); +			break; + +		case RESPONSE_INITIALIZE: +		case RESPONSE_DEACTIVATE: +		case RESPONSE_SETCONFIG: +		case RESPONSE_RESOLUTION: +		case RESPONSE_SCANFREQ: +			zforce_complete(ts, payload[RESPONSE_ID], +					payload[RESPONSE_DATA]); +			break; + +		case RESPONSE_STATUS: +			/* +			 * Version Payload Results +			 * [2:major] [2:minor] [2:build] [2:rev] +			 */ +			ts->version_major = (payload[RESPONSE_DATA + 1] << 8) | +						payload[RESPONSE_DATA]; +			ts->version_minor = (payload[RESPONSE_DATA + 3] << 8) | +						payload[RESPONSE_DATA + 2]; +			ts->version_build = (payload[RESPONSE_DATA + 5] << 8) | +						payload[RESPONSE_DATA + 4]; +			ts->version_rev   = (payload[RESPONSE_DATA + 7] << 8) | +						payload[RESPONSE_DATA + 6]; +			dev_dbg(&ts->client->dev, +				"Firmware Version %04x:%04x %04x:%04x\n", +				ts->version_major, ts->version_minor, +				ts->version_build, ts->version_rev); + +			zforce_complete(ts, payload[RESPONSE_ID], 0); +			break; + +		case NOTIFICATION_INVALID_COMMAND: +			dev_err(&ts->client->dev, "invalid command: 0x%x\n", +				payload[RESPONSE_DATA]); +			break; + +		default: +			dev_err(&ts->client->dev, +				"unrecognized response id: 0x%x\n", +				payload[RESPONSE_ID]); +			break; +		} +	} + +	if (!ts->suspending && device_may_wakeup(&client->dev)) +		pm_relax(&client->dev); + +	dev_dbg(&client->dev, "finished interrupt\n"); + +	return IRQ_HANDLED; +} + +static int zforce_input_open(struct input_dev *dev) +{ +	struct zforce_ts *ts = input_get_drvdata(dev); +	int ret; + +	ret = zforce_start(ts); +	if (ret) +		return ret; + +	return 0; +} + +static void zforce_input_close(struct input_dev *dev) +{ +	struct zforce_ts *ts = input_get_drvdata(dev); +	struct i2c_client *client = ts->client; +	int ret; + +	ret = zforce_stop(ts); +	if (ret) +		dev_warn(&client->dev, "stopping zforce failed\n"); + +	return; +} + +#ifdef CONFIG_PM_SLEEP +static int zforce_suspend(struct device *dev) +{ +	struct i2c_client *client = to_i2c_client(dev); +	struct zforce_ts *ts = i2c_get_clientdata(client); +	struct input_dev *input = ts->input; +	int ret = 0; + +	mutex_lock(&input->mutex); +	ts->suspending = true; + +	/* +	 * When configured as a wakeup source device should always wake +	 * the system, therefore start device if necessary. +	 */ +	if (device_may_wakeup(&client->dev)) { +		dev_dbg(&client->dev, "suspend while being a wakeup source\n"); + +		/* Need to start device, if not open, to be a wakeup source. */ +		if (!input->users) { +			ret = zforce_start(ts); +			if (ret) +				goto unlock; +		} + +		enable_irq_wake(client->irq); +	} else if (input->users) { +		dev_dbg(&client->dev, +			"suspend without being a wakeup source\n"); + +		ret = zforce_stop(ts); +		if (ret) +			goto unlock; + +		disable_irq(client->irq); +	} + +	ts->suspended = true; + +unlock: +	ts->suspending = false; +	mutex_unlock(&input->mutex); + +	return ret; +} + +static int zforce_resume(struct device *dev) +{ +	struct i2c_client *client = to_i2c_client(dev); +	struct zforce_ts *ts = i2c_get_clientdata(client); +	struct input_dev *input = ts->input; +	int ret = 0; + +	mutex_lock(&input->mutex); + +	ts->suspended = false; + +	if (device_may_wakeup(&client->dev)) { +		dev_dbg(&client->dev, "resume from being a wakeup source\n"); + +		disable_irq_wake(client->irq); + +		/* need to stop device if it was not open on suspend */ +		if (!input->users) { +			ret = zforce_stop(ts); +			if (ret) +				goto unlock; +		} +	} else if (input->users) { +		dev_dbg(&client->dev, "resume without being a wakeup source\n"); + +		enable_irq(client->irq); + +		ret = zforce_start(ts); +		if (ret < 0) +			goto unlock; +	} + +unlock: +	mutex_unlock(&input->mutex); + +	return ret; +} +#endif + +static SIMPLE_DEV_PM_OPS(zforce_pm_ops, zforce_suspend, zforce_resume); + +static void zforce_reset(void *data) +{ +	struct zforce_ts *ts = data; + +	gpio_set_value(ts->pdata->gpio_rst, 0); +} + +static struct zforce_ts_platdata *zforce_parse_dt(struct device *dev) +{ +	struct zforce_ts_platdata *pdata; +	struct device_node *np = dev->of_node; + +	if (!np) +		return ERR_PTR(-ENOENT); + +	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); +	if (!pdata) { +		dev_err(dev, "failed to allocate platform data\n"); +		return ERR_PTR(-ENOMEM); +	} + +	pdata->gpio_int = of_get_gpio(np, 0); +	if (!gpio_is_valid(pdata->gpio_int)) { +		dev_err(dev, "failed to get interrupt gpio\n"); +		return ERR_PTR(-EINVAL); +	} + +	pdata->gpio_rst = of_get_gpio(np, 1); +	if (!gpio_is_valid(pdata->gpio_rst)) { +		dev_err(dev, "failed to get reset gpio\n"); +		return ERR_PTR(-EINVAL); +	} + +	if (of_property_read_u32(np, "x-size", &pdata->x_max)) { +		dev_err(dev, "failed to get x-size property\n"); +		return ERR_PTR(-EINVAL); +	} + +	if (of_property_read_u32(np, "y-size", &pdata->y_max)) { +		dev_err(dev, "failed to get y-size property\n"); +		return ERR_PTR(-EINVAL); +	} + +	return pdata; +} + +static int zforce_probe(struct i2c_client *client, +			const struct i2c_device_id *id) +{ +	const struct zforce_ts_platdata *pdata = dev_get_platdata(&client->dev); +	struct zforce_ts *ts; +	struct input_dev *input_dev; +	int ret; + +	if (!pdata) { +		pdata = zforce_parse_dt(&client->dev); +		if (IS_ERR(pdata)) +			return PTR_ERR(pdata); +	} + +	ts = devm_kzalloc(&client->dev, sizeof(struct zforce_ts), GFP_KERNEL); +	if (!ts) +		return -ENOMEM; + +	ret = devm_gpio_request_one(&client->dev, pdata->gpio_int, GPIOF_IN, +				    "zforce_ts_int"); +	if (ret) { +		dev_err(&client->dev, "request of gpio %d failed, %d\n", +			pdata->gpio_int, ret); +		return ret; +	} + +	ret = devm_gpio_request_one(&client->dev, pdata->gpio_rst, +				    GPIOF_OUT_INIT_LOW, "zforce_ts_rst"); +	if (ret) { +		dev_err(&client->dev, "request of gpio %d failed, %d\n", +			pdata->gpio_rst, ret); +		return ret; +	} + +	ret = devm_add_action(&client->dev, zforce_reset, ts); +	if (ret) { +		dev_err(&client->dev, "failed to register reset action, %d\n", +			ret); +		return ret; +	} + +	snprintf(ts->phys, sizeof(ts->phys), +		 "%s/input0", dev_name(&client->dev)); + +	input_dev = devm_input_allocate_device(&client->dev); +	if (!input_dev) { +		dev_err(&client->dev, "could not allocate input device\n"); +		return -ENOMEM; +	} + +	mutex_init(&ts->access_mutex); +	mutex_init(&ts->command_mutex); + +	ts->pdata = pdata; +	ts->client = client; +	ts->input = input_dev; + +	input_dev->name = "Neonode zForce touchscreen"; +	input_dev->phys = ts->phys; +	input_dev->id.bustype = BUS_I2C; + +	input_dev->open = zforce_input_open; +	input_dev->close = zforce_input_close; + +	__set_bit(EV_KEY, input_dev->evbit); +	__set_bit(EV_SYN, input_dev->evbit); +	__set_bit(EV_ABS, input_dev->evbit); + +	/* For multi touch */ +	input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, +			     pdata->x_max, 0, 0); +	input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, +			     pdata->y_max, 0, 0); + +	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, +			     ZFORCE_MAX_AREA, 0, 0); +	input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0, +			     ZFORCE_MAX_AREA, 0, 0); +	input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0); +	input_mt_init_slots(input_dev, ZFORCE_REPORT_POINTS, INPUT_MT_DIRECT); + +	input_set_drvdata(ts->input, ts); + +	init_completion(&ts->command_done); + +	/* +	 * The zforce pulls the interrupt low when it has data ready. +	 * After it is triggered the isr thread runs until all the available +	 * packets have been read and the interrupt is high again. +	 * Therefore we can trigger the interrupt anytime it is low and do +	 * not need to limit it to the interrupt edge. +	 */ +	ret = devm_request_threaded_irq(&client->dev, client->irq, +					zforce_irq, zforce_irq_thread, +					IRQF_TRIGGER_LOW | IRQF_ONESHOT, +					input_dev->name, ts); +	if (ret) { +		dev_err(&client->dev, "irq %d request failed\n", client->irq); +		return ret; +	} + +	i2c_set_clientdata(client, ts); + +	/* let the controller boot */ +	gpio_set_value(pdata->gpio_rst, 1); + +	ts->command_waiting = NOTIFICATION_BOOTCOMPLETE; +	if (wait_for_completion_timeout(&ts->command_done, WAIT_TIMEOUT) == 0) +		dev_warn(&client->dev, "bootcomplete timed out\n"); + +	/* need to start device to get version information */ +	ret = zforce_command_wait(ts, COMMAND_INITIALIZE); +	if (ret) { +		dev_err(&client->dev, "unable to initialize, %d\n", ret); +		return ret; +	} + +	/* this gets the firmware version among other information */ +	ret = zforce_command_wait(ts, COMMAND_STATUS); +	if (ret < 0) { +		dev_err(&client->dev, "couldn't get status, %d\n", ret); +		zforce_stop(ts); +		return ret; +	} + +	/* stop device and put it into sleep until it is opened */ +	ret = zforce_stop(ts); +	if (ret < 0) +		return ret; + +	device_set_wakeup_capable(&client->dev, true); + +	ret = input_register_device(input_dev); +	if (ret) { +		dev_err(&client->dev, "could not register input device, %d\n", +			ret); +		return ret; +	} + +	return 0; +} + +static struct i2c_device_id zforce_idtable[] = { +	{ "zforce-ts", 0 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, zforce_idtable); + +#ifdef CONFIG_OF +static const struct of_device_id zforce_dt_idtable[] = { +	{ .compatible = "neonode,zforce" }, +	{}, +}; +MODULE_DEVICE_TABLE(of, zforce_dt_idtable); +#endif + +static struct i2c_driver zforce_driver = { +	.driver = { +		.owner	= THIS_MODULE, +		.name	= "zforce-ts", +		.pm	= &zforce_pm_ops, +		.of_match_table	= of_match_ptr(zforce_dt_idtable), +	}, +	.probe		= zforce_probe, +	.id_table	= zforce_idtable, +}; + +module_i2c_driver(zforce_driver); + +MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); +MODULE_DESCRIPTION("zForce TouchScreen Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/zylonite-wm97xx.c b/drivers/input/touchscreen/zylonite-wm97xx.c index bf0869a7a78..e2ccd683de6 100644 --- a/drivers/input/touchscreen/zylonite-wm97xx.c +++ b/drivers/input/touchscreen/zylonite-wm97xx.c @@ -20,7 +20,6 @@  #include <linux/module.h>  #include <linux/moduleparam.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/delay.h>  #include <linux/gpio.h>  #include <linux/irq.h>  | 
