diff options
Diffstat (limited to 'drivers/input')
37 files changed, 2866 insertions, 342 deletions
| diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 88d8e4cb419a..be0921ef6b52 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -41,6 +41,7 @@ struct evdev {  struct evdev_client {  	unsigned int head;  	unsigned int tail; +	unsigned int packet_head; /* [future] position of the first element of next packet */  	spinlock_t buffer_lock; /* protects access to buffer, head and tail */  	struct fasync_struct *fasync;  	struct evdev *evdev; @@ -72,12 +73,16 @@ static void evdev_pass_event(struct evdev_client *client,  		client->buffer[client->tail].type = EV_SYN;  		client->buffer[client->tail].code = SYN_DROPPED;  		client->buffer[client->tail].value = 0; -	} -	spin_unlock(&client->buffer_lock); +		client->packet_head = client->tail; +	} -	if (event->type == EV_SYN) +	if (event->type == EV_SYN && event->code == SYN_REPORT) { +		client->packet_head = client->head;  		kill_fasync(&client->fasync, SIGIO, POLL_IN); +	} + +	spin_unlock(&client->buffer_lock);  }  /* @@ -159,7 +164,6 @@ static int evdev_grab(struct evdev *evdev, struct evdev_client *client)  		return error;  	rcu_assign_pointer(evdev->grab, client); -	synchronize_rcu();  	return 0;  } @@ -182,7 +186,6 @@ static void evdev_attach_client(struct evdev *evdev,  	spin_lock(&evdev->client_lock);  	list_add_tail_rcu(&client->node, &evdev->client_list);  	spin_unlock(&evdev->client_lock); -	synchronize_rcu();  }  static void evdev_detach_client(struct evdev *evdev, @@ -387,12 +390,12 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,  	if (count < input_event_size())  		return -EINVAL; -	if (client->head == client->tail && evdev->exist && +	if (client->packet_head == client->tail && evdev->exist &&  	    (file->f_flags & O_NONBLOCK))  		return -EAGAIN;  	retval = wait_event_interruptible(evdev->wait, -		client->head != client->tail || !evdev->exist); +		client->packet_head != client->tail || !evdev->exist);  	if (retval)  		return retval; @@ -421,7 +424,7 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)  	poll_wait(file, &evdev->wait, wait);  	mask = evdev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR; -	if (client->head != client->tail) +	if (client->packet_head != client->tail)  		mask |= POLLIN | POLLRDNORM;  	return mask; diff --git a/drivers/input/input-compat.h b/drivers/input/input-compat.h index 4d8ea32e8a00..22be27b424de 100644 --- a/drivers/input/input-compat.h +++ b/drivers/input/input-compat.h @@ -19,7 +19,7 @@  /* Note to the author of this code: did it ever occur to     you why the ifdefs are needed? Think about it again. -AK */ -#ifdef CONFIG_X86_64 +#if defined(CONFIG_X86_64) || defined(CONFIG_TILE)  #  define INPUT_COMPAT_TEST is_compat_task()  #elif defined(CONFIG_S390)  #  define INPUT_COMPAT_TEST test_thread_flag(TIF_31BIT) diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c index 3037842a60d8..b1aabde87523 100644 --- a/drivers/input/input-polldev.c +++ b/drivers/input/input-polldev.c @@ -13,6 +13,7 @@  #include <linux/jiffies.h>  #include <linux/slab.h>  #include <linux/mutex.h> +#include <linux/workqueue.h>  #include <linux/input-polldev.h>  MODULE_AUTHOR("Dmitry Torokhov <[email protected]>"); @@ -20,44 +21,6 @@ MODULE_DESCRIPTION("Generic implementation of a polled input device");  MODULE_LICENSE("GPL v2");  MODULE_VERSION("0.1"); -static DEFINE_MUTEX(polldev_mutex); -static int polldev_users; -static struct workqueue_struct *polldev_wq; - -static int input_polldev_start_workqueue(void) -{ -	int retval; - -	retval = mutex_lock_interruptible(&polldev_mutex); -	if (retval) -		return retval; - -	if (!polldev_users) { -		polldev_wq = create_singlethread_workqueue("ipolldevd"); -		if (!polldev_wq) { -			pr_err("failed to create ipolldevd workqueue\n"); -			retval = -ENOMEM; -			goto out; -		} -	} - -	polldev_users++; - - out: -	mutex_unlock(&polldev_mutex); -	return retval; -} - -static void input_polldev_stop_workqueue(void) -{ -	mutex_lock(&polldev_mutex); - -	if (!--polldev_users) -		destroy_workqueue(polldev_wq); - -	mutex_unlock(&polldev_mutex); -} -  static void input_polldev_queue_work(struct input_polled_dev *dev)  {  	unsigned long delay; @@ -66,7 +29,7 @@ static void input_polldev_queue_work(struct input_polled_dev *dev)  	if (delay >= HZ)  		delay = round_jiffies_relative(delay); -	queue_delayed_work(polldev_wq, &dev->work, delay); +	queue_delayed_work(system_freezable_wq, &dev->work, delay);  }  static void input_polled_device_work(struct work_struct *work) @@ -81,18 +44,13 @@ static void input_polled_device_work(struct work_struct *work)  static int input_open_polled_device(struct input_dev *input)  {  	struct input_polled_dev *dev = input_get_drvdata(input); -	int error; - -	error = input_polldev_start_workqueue(); -	if (error) -		return error;  	if (dev->open)  		dev->open(dev);  	/* Only start polling if polling is enabled */  	if (dev->poll_interval > 0) -		queue_delayed_work(polldev_wq, &dev->work, 0); +		queue_delayed_work(system_freezable_wq, &dev->work, 0);  	return 0;  } @@ -102,13 +60,6 @@ static void input_close_polled_device(struct input_dev *input)  	struct input_polled_dev *dev = input_get_drvdata(input);  	cancel_delayed_work_sync(&dev->work); -	/* -	 * Clean up work struct to remove references to the workqueue. -	 * It may be destroyed by the next call. This causes problems -	 * at next device open-close in case of poll_interval == 0. -	 */ -	INIT_DELAYED_WORK(&dev->work, dev->work.work.func); -	input_polldev_stop_workqueue();  	if (dev->close)  		dev->close(dev); @@ -295,4 +246,3 @@ void input_unregister_polled_device(struct input_polled_dev *dev)  	input_unregister_device(dev->input);  }  EXPORT_SYMBOL(input_unregister_polled_device); - diff --git a/drivers/input/input.c b/drivers/input/input.c index ebbceedc92f4..75e11c7b70fd 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -451,7 +451,6 @@ int input_grab_device(struct input_handle *handle)  	}  	rcu_assign_pointer(dev->grab, handle); -	synchronize_rcu();   out:  	mutex_unlock(&dev->mutex); diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 5688b5c88f24..c24ec2d5f926 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -180,7 +180,6 @@ static void joydev_attach_client(struct joydev *joydev,  	spin_lock(&joydev->client_lock);  	list_add_tail_rcu(&client->node, &joydev->client_list);  	spin_unlock(&joydev->client_lock); -	synchronize_rcu();  }  static void joydev_detach_client(struct joydev *joydev, diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index b16bed038f72..b4dee9d5a055 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -32,6 +32,16 @@ config KEYBOARD_ADP5588  	  To compile this driver as a module, choose M here: the  	  module will be called adp5588-keys. +config KEYBOARD_ADP5589 +	tristate "ADP5589 I2C QWERTY Keypad and IO Expander" +	depends on I2C +	help +	  Say Y here if you want to use a ADP5589 attached to your +	  system I2C bus. + +	  To compile this driver as a module, choose M here: the +	  module will be called adp5589-keys. +  config KEYBOARD_AMIGA  	tristate "Amiga keyboard"  	depends on AMIGA @@ -325,6 +335,18 @@ config KEYBOARD_MCS  	  To compile this driver as a module, choose M here: the  	  module will be called mcs_touchkey. +config KEYBOARD_MPR121 +	tristate "Freescale MPR121 Touchkey" +	depends on I2C +	help +	  Say Y here if you have Freescale MPR121 touchkey controller +	  chip in your system. + +	  If unsure, say N. + +	  To compile this driver as a module, choose M here: the +	  module will be called mpr121_touchkey. +  config KEYBOARD_IMX  	tristate "IMX keypad support"  	depends on ARCH_MXC @@ -390,6 +412,17 @@ config KEYBOARD_PXA930_ROTARY  	  To compile this driver as a module, choose M here: the  	  module will be called pxa930_rotary. +config KEYBOARD_PMIC8XXX +	tristate "Qualcomm PMIC8XXX keypad support" +	depends on MFD_PM8XXX +	help +	  Say Y here if you want to enable the driver for the PMIC8XXX +	  keypad provided as a reference design from Qualcomm. This is intended +	  to support upto 18x8 matrix based keypad design. + +	  To compile this driver as a module, choose M here: the module will +	  be called pmic8xxx-keypad. +  config KEYBOARD_SAMSUNG  	tristate "Samsung keypad support"  	depends on SAMSUNG_DEV_KEYPAD diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 878e6c20deb0..ddde0fd476f7 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -6,6 +6,7 @@  obj-$(CONFIG_KEYBOARD_ADP5520)		+= adp5520-keys.o  obj-$(CONFIG_KEYBOARD_ADP5588)		+= adp5588-keys.o +obj-$(CONFIG_KEYBOARD_ADP5589)		+= adp5589-keys.o  obj-$(CONFIG_KEYBOARD_AMIGA)		+= amikbd.o  obj-$(CONFIG_KEYBOARD_ATARI)		+= atakbd.o  obj-$(CONFIG_KEYBOARD_ATKBD)		+= atkbd.o @@ -27,11 +28,13 @@ obj-$(CONFIG_KEYBOARD_MAPLE)		+= maple_keyb.o  obj-$(CONFIG_KEYBOARD_MATRIX)		+= matrix_keypad.o  obj-$(CONFIG_KEYBOARD_MAX7359)		+= max7359_keypad.o  obj-$(CONFIG_KEYBOARD_MCS)		+= mcs_touchkey.o +obj-$(CONFIG_KEYBOARD_MPR121)		+= mpr121_touchkey.o  obj-$(CONFIG_KEYBOARD_NEWTON)		+= newtonkbd.o  obj-$(CONFIG_KEYBOARD_NOMADIK)		+= nomadik-ske-keypad.o  obj-$(CONFIG_KEYBOARD_OMAP)		+= omap-keypad.o  obj-$(CONFIG_KEYBOARD_OMAP4)		+= omap4-keypad.o  obj-$(CONFIG_KEYBOARD_OPENCORES)	+= opencores-kbd.o +obj-$(CONFIG_KEYBOARD_PMIC8XXX)		+= pmic8xxx-keypad.o  obj-$(CONFIG_KEYBOARD_PXA27x)		+= pxa27x_keypad.o  obj-$(CONFIG_KEYBOARD_PXA930_ROTARY)	+= pxa930_rotary.o  obj-$(CONFIG_KEYBOARD_QT1070)           += qt1070.o diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c new file mode 100644 index 000000000000..631598663aab --- /dev/null +++ b/drivers/input/keyboard/adp5589-keys.c @@ -0,0 +1,771 @@ +/* + * Description:  keypad driver for ADP5589 + *		 I2C QWERTY Keypad and IO Expander + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * Copyright (C) 2010-2011 Analog Devices Inc. + * Licensed under the GPL-2. + */ + +#include <linux/module.h> +#include <linux/version.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/workqueue.h> +#include <linux/errno.h> +#include <linux/pm.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/slab.h> + +#include <linux/input/adp5589.h> + +/* GENERAL_CFG Register */ +#define OSC_EN		(1 << 7) +#define CORE_CLK(x)	(((x) & 0x3) << 5) +#define LCK_TRK_LOGIC	(1 << 4) +#define LCK_TRK_GPI	(1 << 3) +#define INT_CFG		(1 << 1) +#define RST_CFG		(1 << 0) + +/* INT_EN Register */ +#define LOGIC2_IEN	(1 << 5) +#define LOGIC1_IEN	(1 << 4) +#define LOCK_IEN	(1 << 3) +#define OVRFLOW_IEN	(1 << 2) +#define GPI_IEN		(1 << 1) +#define EVENT_IEN	(1 << 0) + +/* Interrupt Status Register */ +#define LOGIC2_INT	(1 << 5) +#define LOGIC1_INT	(1 << 4) +#define LOCK_INT	(1 << 3) +#define OVRFLOW_INT	(1 << 2) +#define GPI_INT		(1 << 1) +#define EVENT_INT	(1 << 0) + +/* STATUS Register */ + +#define LOGIC2_STAT	(1 << 7) +#define LOGIC1_STAT	(1 << 6) +#define LOCK_STAT	(1 << 5) +#define KEC		0xF + +/* PIN_CONFIG_D Register */ +#define C4_EXTEND_CFG	(1 << 6)	/* RESET2 */ +#define R4_EXTEND_CFG	(1 << 5)	/* RESET1 */ + +/* LOCK_CFG */ +#define LOCK_EN		(1 << 0) + +#define PTIME_MASK	0x3 +#define LTIME_MASK	0x3 + +/* Key Event Register xy */ +#define KEY_EV_PRESSED		(1 << 7) +#define KEY_EV_MASK		(0x7F) + +#define KEYP_MAX_EVENT		16 + +#define MAXGPIO			19 +#define ADP_BANK(offs)		((offs) >> 3) +#define ADP_BIT(offs)		(1u << ((offs) & 0x7)) + +struct adp5589_kpad { +	struct i2c_client *client; +	struct input_dev *input; +	unsigned short keycode[ADP5589_KEYMAPSIZE]; +	const struct adp5589_gpi_map *gpimap; +	unsigned short gpimapsize; +	unsigned extend_cfg; +#ifdef CONFIG_GPIOLIB +	unsigned char gpiomap[MAXGPIO]; +	bool export_gpio; +	struct gpio_chip gc; +	struct mutex gpio_lock;	/* Protect cached dir, dat_out */ +	u8 dat_out[3]; +	u8 dir[3]; +#endif +}; + +static int adp5589_read(struct i2c_client *client, u8 reg) +{ +	int ret = i2c_smbus_read_byte_data(client, reg); + +	if (ret < 0) +		dev_err(&client->dev, "Read Error\n"); + +	return ret; +} + +static int adp5589_write(struct i2c_client *client, u8 reg, u8 val) +{ +	return i2c_smbus_write_byte_data(client, reg, val); +} + +#ifdef CONFIG_GPIOLIB +static int adp5589_gpio_get_value(struct gpio_chip *chip, unsigned off) +{ +	struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc); +	unsigned int bank = ADP_BANK(kpad->gpiomap[off]); +	unsigned int bit = ADP_BIT(kpad->gpiomap[off]); + +	return !!(adp5589_read(kpad->client, ADP5589_GPI_STATUS_A + bank) & +		  bit); +} + +static void adp5589_gpio_set_value(struct gpio_chip *chip, +				   unsigned off, int val) +{ +	struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc); +	unsigned int bank = ADP_BANK(kpad->gpiomap[off]); +	unsigned int bit = ADP_BIT(kpad->gpiomap[off]); + +	mutex_lock(&kpad->gpio_lock); + +	if (val) +		kpad->dat_out[bank] |= bit; +	else +		kpad->dat_out[bank] &= ~bit; + +	adp5589_write(kpad->client, ADP5589_GPO_DATA_OUT_A + bank, +		      kpad->dat_out[bank]); + +	mutex_unlock(&kpad->gpio_lock); +} + +static int adp5589_gpio_direction_input(struct gpio_chip *chip, unsigned off) +{ +	struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc); +	unsigned int bank = ADP_BANK(kpad->gpiomap[off]); +	unsigned int bit = ADP_BIT(kpad->gpiomap[off]); +	int ret; + +	mutex_lock(&kpad->gpio_lock); + +	kpad->dir[bank] &= ~bit; +	ret = adp5589_write(kpad->client, ADP5589_GPIO_DIRECTION_A + bank, +			    kpad->dir[bank]); + +	mutex_unlock(&kpad->gpio_lock); + +	return ret; +} + +static int adp5589_gpio_direction_output(struct gpio_chip *chip, +					 unsigned off, int val) +{ +	struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc); +	unsigned int bank = ADP_BANK(kpad->gpiomap[off]); +	unsigned int bit = ADP_BIT(kpad->gpiomap[off]); +	int ret; + +	mutex_lock(&kpad->gpio_lock); + +	kpad->dir[bank] |= bit; + +	if (val) +		kpad->dat_out[bank] |= bit; +	else +		kpad->dat_out[bank] &= ~bit; + +	ret = adp5589_write(kpad->client, ADP5589_GPO_DATA_OUT_A + bank, +			    kpad->dat_out[bank]); +	ret |= adp5589_write(kpad->client, ADP5589_GPIO_DIRECTION_A + bank, +			     kpad->dir[bank]); + +	mutex_unlock(&kpad->gpio_lock); + +	return ret; +} + +static int __devinit adp5589_build_gpiomap(struct adp5589_kpad *kpad, +				const struct adp5589_kpad_platform_data *pdata) +{ +	bool pin_used[MAXGPIO]; +	int n_unused = 0; +	int i; + +	memset(pin_used, false, sizeof(pin_used)); + +	for (i = 0; i < MAXGPIO; i++) +		if (pdata->keypad_en_mask & (1 << i)) +			pin_used[i] = true; + +	for (i = 0; i < kpad->gpimapsize; i++) +		pin_used[kpad->gpimap[i].pin - ADP5589_GPI_PIN_BASE] = true; + +	if (kpad->extend_cfg & R4_EXTEND_CFG) +		pin_used[4] = true; + +	if (kpad->extend_cfg & C4_EXTEND_CFG) +		pin_used[12] = true; + +	for (i = 0; i < MAXGPIO; i++) +		if (!pin_used[i]) +			kpad->gpiomap[n_unused++] = i; + +	return n_unused; +} + +static int __devinit 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_gpio_platform_data *gpio_data = pdata->gpio_data; +	int i, error; + +	if (!gpio_data) +		return 0; + +	kpad->gc.ngpio = adp5589_build_gpiomap(kpad, pdata); +	if (kpad->gc.ngpio == 0) { +		dev_info(dev, "No unused gpios left to export\n"); +		return 0; +	} + +	kpad->export_gpio = true; + +	kpad->gc.direction_input = adp5589_gpio_direction_input; +	kpad->gc.direction_output = adp5589_gpio_direction_output; +	kpad->gc.get = adp5589_gpio_get_value; +	kpad->gc.set = adp5589_gpio_set_value; +	kpad->gc.can_sleep = 1; + +	kpad->gc.base = gpio_data->gpio_start; +	kpad->gc.label = kpad->client->name; +	kpad->gc.owner = THIS_MODULE; + +	mutex_init(&kpad->gpio_lock); + +	error = gpiochip_add(&kpad->gc); +	if (error) { +		dev_err(dev, "gpiochip_add failed, err: %d\n", error); +		return error; +	} + +	for (i = 0; i <= ADP_BANK(MAXGPIO); i++) { +		kpad->dat_out[i] = adp5589_read(kpad->client, +						ADP5589_GPO_DATA_OUT_A + i); +		kpad->dir[i] = adp5589_read(kpad->client, +					    ADP5589_GPIO_DIRECTION_A + i); +	} + +	if (gpio_data->setup) { +		error = gpio_data->setup(kpad->client, +					 kpad->gc.base, kpad->gc.ngpio, +					 gpio_data->context); +		if (error) +			dev_warn(dev, "setup failed, %d\n", error); +	} + +	return 0; +} + +static void __devexit 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_gpio_platform_data *gpio_data = pdata->gpio_data; +	int error; + +	if (!kpad->export_gpio) +		return; + +	if (gpio_data->teardown) { +		error = gpio_data->teardown(kpad->client, +					    kpad->gc.base, kpad->gc.ngpio, +					    gpio_data->context); +		if (error) +			dev_warn(dev, "teardown failed %d\n", error); +	} + +	error = gpiochip_remove(&kpad->gc); +	if (error) +		dev_warn(dev, "gpiochip_remove failed %d\n", error); +} +#else +static inline int adp5589_gpio_add(struct adp5589_kpad *kpad) +{ +	return 0; +} + +static inline void adp5589_gpio_remove(struct adp5589_kpad *kpad) +{ +} +#endif + +static void adp5589_report_switches(struct adp5589_kpad *kpad, +				    int key, int key_val) +{ +	int i; + +	for (i = 0; i < kpad->gpimapsize; i++) { +		if (key_val == kpad->gpimap[i].pin) { +			input_report_switch(kpad->input, +					    kpad->gpimap[i].sw_evt, +					    key & KEY_EV_PRESSED); +			break; +		} +	} +} + +static void adp5589_report_events(struct adp5589_kpad *kpad, int ev_cnt) +{ +	int i; + +	for (i = 0; i < ev_cnt; i++) { +		int key = adp5589_read(kpad->client, ADP5589_FIFO_1 + i); +		int key_val = key & KEY_EV_MASK; + +		if (key_val >= ADP5589_GPI_PIN_BASE && +		    key_val <= ADP5589_GPI_PIN_END) { +			adp5589_report_switches(kpad, key, key_val); +		} else { +			input_report_key(kpad->input, +					 kpad->keycode[key_val - 1], +					 key & KEY_EV_PRESSED); +		} +	} +} + +static irqreturn_t adp5589_irq(int irq, void *handle) +{ +	struct adp5589_kpad *kpad = handle; +	struct i2c_client *client = kpad->client; +	int status, ev_cnt; + +	status = adp5589_read(client, ADP5589_INT_STATUS); + +	if (status & OVRFLOW_INT)	/* Unlikely and should never happen */ +		dev_err(&client->dev, "Event Overflow Error\n"); + +	if (status & EVENT_INT) { +		ev_cnt = adp5589_read(client, ADP5589_STATUS) & KEC; +		if (ev_cnt) { +			adp5589_report_events(kpad, ev_cnt); +			input_sync(kpad->input); +		} +	} + +	adp5589_write(client, ADP5589_INT_STATUS, status);	/* Status is W1C */ + +	return IRQ_HANDLED; +} + +static int __devinit adp5589_get_evcode(struct adp5589_kpad *kpad, unsigned short key) +{ +	int i; + +	for (i = 0; i < ADP5589_KEYMAPSIZE; i++) +		if (key == kpad->keycode[i]) +			return (i + 1) | KEY_EV_PRESSED; + +	dev_err(&kpad->client->dev, "RESET/UNLOCK key not in keycode map\n"); + +	return -EINVAL; +} + +static int __devinit adp5589_setup(struct adp5589_kpad *kpad) +{ +	struct i2c_client *client = kpad->client; +	const struct adp5589_kpad_platform_data *pdata = +	    client->dev.platform_data; +	int i, ret; +	unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0; +	unsigned char pull_mask = 0; + +	ret = adp5589_write(client, ADP5589_PIN_CONFIG_A, +			    pdata->keypad_en_mask & 0xFF); +	ret |= adp5589_write(client, ADP5589_PIN_CONFIG_B, +			     (pdata->keypad_en_mask >> 8) & 0xFF); +	ret |= adp5589_write(client, ADP5589_PIN_CONFIG_C, +			     (pdata->keypad_en_mask >> 16) & 0xFF); + +	if (pdata->en_keylock) { +		ret |= adp5589_write(client, ADP5589_UNLOCK1, +				     pdata->unlock_key1); +		ret |= adp5589_write(client, ADP5589_UNLOCK2, +				     pdata->unlock_key2); +		ret |= adp5589_write(client, ADP5589_UNLOCK_TIMERS, +				     pdata->unlock_timer & LTIME_MASK); +		ret |= adp5589_write(client, ADP5589_LOCK_CFG, LOCK_EN); +	} + +	for (i = 0; i < KEYP_MAX_EVENT; i++) +		ret |= adp5589_read(client, ADP5589_FIFO_1 + i); + +	for (i = 0; i < pdata->gpimapsize; i++) { +		unsigned short pin = pdata->gpimap[i].pin; + +		if (pin <= ADP5589_GPI_PIN_ROW_END) { +			evt_mode1 |= (1 << (pin - ADP5589_GPI_PIN_ROW_BASE)); +		} else { +			evt_mode2 |= +			    ((1 << (pin - ADP5589_GPI_PIN_COL_BASE)) & 0xFF); +			evt_mode3 |= +			    ((1 << (pin - ADP5589_GPI_PIN_COL_BASE)) >> 8); +		} +	} + +	if (pdata->gpimapsize) { +		ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_A, evt_mode1); +		ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_B, evt_mode2); +		ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_C, evt_mode3); +	} + +	if (pdata->pull_dis_mask & pdata->pullup_en_100k & +	    pdata->pullup_en_300k & pdata->pulldown_en_300k) +		dev_warn(&client->dev, "Conflicting pull resistor config\n"); + +	for (i = 0; i < MAXGPIO; i++) { +		unsigned val = 0; + +		if (pdata->pullup_en_300k & (1 << i)) +			val = 0; +		else if (pdata->pulldown_en_300k & (1 << i)) +			val = 1; +		else if (pdata->pullup_en_100k & (1 << i)) +			val = 2; +		else if (pdata->pull_dis_mask & (1 << i)) +			val = 3; + +		pull_mask |= val << (2 * (i & 0x3)); + +		if ((i & 0x3) == 0x3 || i == MAXGPIO - 1) { +			ret |= adp5589_write(client, +					     ADP5589_RPULL_CONFIG_A + (i >> 2), +					     pull_mask); +			pull_mask = 0; +		} +	} + +	if (pdata->reset1_key_1 && pdata->reset1_key_2 && pdata->reset1_key_3) { +		ret |= adp5589_write(client, ADP5589_RESET1_EVENT_A, +				     adp5589_get_evcode(kpad, +							pdata->reset1_key_1)); +		ret |= adp5589_write(client, ADP5589_RESET1_EVENT_B, +				     adp5589_get_evcode(kpad, +							pdata->reset1_key_2)); +		ret |= adp5589_write(client, ADP5589_RESET1_EVENT_C, +				     adp5589_get_evcode(kpad, +							pdata->reset1_key_3)); +		kpad->extend_cfg |= R4_EXTEND_CFG; +	} + +	if (pdata->reset2_key_1 && pdata->reset2_key_2) { +		ret |= adp5589_write(client, ADP5589_RESET2_EVENT_A, +				     adp5589_get_evcode(kpad, +							pdata->reset2_key_1)); +		ret |= adp5589_write(client, ADP5589_RESET2_EVENT_B, +				     adp5589_get_evcode(kpad, +							pdata->reset2_key_2)); +		kpad->extend_cfg |= C4_EXTEND_CFG; +	} + +	if (kpad->extend_cfg) { +		ret |= adp5589_write(client, ADP5589_RESET_CFG, +				     pdata->reset_cfg); +		ret |= adp5589_write(client, ADP5589_PIN_CONFIG_D, +				     kpad->extend_cfg); +	} + +	for (i = 0; i <= ADP_BANK(MAXGPIO); i++) +		ret |= adp5589_write(client, ADP5589_DEBOUNCE_DIS_A + i, +				     pdata->debounce_dis_mask >> (i * 8)); + +	ret |= adp5589_write(client, ADP5589_POLL_PTIME_CFG, +			     pdata->scan_cycle_time & PTIME_MASK); +	ret |= adp5589_write(client, ADP5589_INT_STATUS, LOGIC2_INT | +			     LOGIC1_INT | OVRFLOW_INT | LOCK_INT | +			     GPI_INT | EVENT_INT);	/* Status is W1C */ + +	ret |= adp5589_write(client, ADP5589_GENERAL_CFG, +			     INT_CFG | OSC_EN | CORE_CLK(3)); +	ret |= adp5589_write(client, ADP5589_INT_EN, +			     OVRFLOW_IEN | GPI_IEN | EVENT_IEN); + +	if (ret < 0) { +		dev_err(&client->dev, "Write Error\n"); +		return ret; +	} + +	return 0; +} + +static void __devinit adp5589_report_switch_state(struct adp5589_kpad *kpad) +{ +	int gpi_stat1 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_A); +	int gpi_stat2 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_B); +	int gpi_stat3 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_C); +	int gpi_stat_tmp, pin_loc; +	int i; + +	for (i = 0; i < kpad->gpimapsize; i++) { +		unsigned short pin = kpad->gpimap[i].pin; + +		if (pin <= ADP5589_GPI_PIN_ROW_END) { +			gpi_stat_tmp = gpi_stat1; +			pin_loc = pin - ADP5589_GPI_PIN_ROW_BASE; +		} else if ((pin - ADP5589_GPI_PIN_COL_BASE) < 8) { +			gpi_stat_tmp = gpi_stat2; +			pin_loc = pin - ADP5589_GPI_PIN_COL_BASE; +		} else { +			gpi_stat_tmp = gpi_stat3; +			pin_loc = pin - ADP5589_GPI_PIN_COL_BASE - 8; +		} + +		if (gpi_stat_tmp < 0) { +			dev_err(&kpad->client->dev, +				"Can't read GPIO_DAT_STAT switch" +				" %d default to OFF\n", pin); +			gpi_stat_tmp = 0; +		} + +		input_report_switch(kpad->input, +				    kpad->gpimap[i].sw_evt, +				    !(gpi_stat_tmp & (1 << pin_loc))); +	} + +	input_sync(kpad->input); +} + +static int __devinit adp5589_probe(struct i2c_client *client, +				   const struct i2c_device_id *id) +{ +	struct adp5589_kpad *kpad; +	const struct adp5589_kpad_platform_data *pdata; +	struct input_dev *input; +	unsigned int revid; +	int ret, i; +	int error; + +	if (!i2c_check_functionality(client->adapter, +				     I2C_FUNC_SMBUS_BYTE_DATA)) { +		dev_err(&client->dev, "SMBUS Byte Data not Supported\n"); +		return -EIO; +	} + +	pdata = client->dev.platform_data; +	if (!pdata) { +		dev_err(&client->dev, "no platform data?\n"); +		return -EINVAL; +	} + +	if (!((pdata->keypad_en_mask & 0xFF) && +			(pdata->keypad_en_mask >> 8)) || !pdata->keymap) { +		dev_err(&client->dev, "no rows, cols or keymap from pdata\n"); +		return -EINVAL; +	} + +	if (pdata->keymapsize != ADP5589_KEYMAPSIZE) { +		dev_err(&client->dev, "invalid keymapsize\n"); +		return -EINVAL; +	} + +	if (!pdata->gpimap && pdata->gpimapsize) { +		dev_err(&client->dev, "invalid gpimap from pdata\n"); +		return -EINVAL; +	} + +	if (pdata->gpimapsize > ADP5589_GPIMAPSIZE_MAX) { +		dev_err(&client->dev, "invalid gpimapsize\n"); +		return -EINVAL; +	} + +	for (i = 0; i < pdata->gpimapsize; i++) { +		unsigned short pin = pdata->gpimap[i].pin; + +		if (pin < ADP5589_GPI_PIN_BASE || pin > ADP5589_GPI_PIN_END) { +			dev_err(&client->dev, "invalid gpi pin data\n"); +			return -EINVAL; +		} + +		if ((1 << (pin - ADP5589_GPI_PIN_ROW_BASE)) & +				pdata->keypad_en_mask) { +			dev_err(&client->dev, "invalid gpi row/col data\n"); +			return -EINVAL; +		} +	} + +	if (!client->irq) { +		dev_err(&client->dev, "no IRQ?\n"); +		return -EINVAL; +	} + +	kpad = kzalloc(sizeof(*kpad), GFP_KERNEL); +	input = input_allocate_device(); +	if (!kpad || !input) { +		error = -ENOMEM; +		goto err_free_mem; +	} + +	kpad->client = client; +	kpad->input = input; + +	ret = adp5589_read(client, ADP5589_ID); +	if (ret < 0) { +		error = ret; +		goto err_free_mem; +	} + +	revid = (u8) ret & ADP5589_DEVICE_ID_MASK; + +	input->name = client->name; +	input->phys = "adp5589-keys/input0"; +	input->dev.parent = &client->dev; + +	input_set_drvdata(input, kpad); + +	input->id.bustype = BUS_I2C; +	input->id.vendor = 0x0001; +	input->id.product = 0x0001; +	input->id.version = revid; + +	input->keycodesize = sizeof(kpad->keycode[0]); +	input->keycodemax = pdata->keymapsize; +	input->keycode = kpad->keycode; + +	memcpy(kpad->keycode, pdata->keymap, +	       pdata->keymapsize * input->keycodesize); + +	kpad->gpimap = pdata->gpimap; +	kpad->gpimapsize = pdata->gpimapsize; + +	/* setup input device */ +	__set_bit(EV_KEY, input->evbit); + +	if (pdata->repeat) +		__set_bit(EV_REP, input->evbit); + +	for (i = 0; i < input->keycodemax; i++) +		__set_bit(kpad->keycode[i] & KEY_MAX, input->keybit); +	__clear_bit(KEY_RESERVED, input->keybit); + +	if (kpad->gpimapsize) +		__set_bit(EV_SW, input->evbit); +	for (i = 0; i < kpad->gpimapsize; i++) +		__set_bit(kpad->gpimap[i].sw_evt, input->swbit); + +	error = input_register_device(input); +	if (error) { +		dev_err(&client->dev, "unable to register input device\n"); +		goto err_free_mem; +	} + +	error = request_threaded_irq(client->irq, NULL, adp5589_irq, +				     IRQF_TRIGGER_FALLING | IRQF_ONESHOT, +				     client->dev.driver->name, kpad); +	if (error) { +		dev_err(&client->dev, "irq %d busy?\n", client->irq); +		goto err_unreg_dev; +	} + +	error = adp5589_setup(kpad); +	if (error) +		goto err_free_irq; + +	if (kpad->gpimapsize) +		adp5589_report_switch_state(kpad); + +	error = adp5589_gpio_add(kpad); +	if (error) +		goto err_free_irq; + +	device_init_wakeup(&client->dev, 1); +	i2c_set_clientdata(client, kpad); + +	dev_info(&client->dev, "Rev.%d keypad, irq %d\n", revid, client->irq); +	return 0; + +err_free_irq: +	free_irq(client->irq, kpad); +err_unreg_dev: +	input_unregister_device(input); +	input = NULL; +err_free_mem: +	input_free_device(input); +	kfree(kpad); + +	return error; +} + +static int __devexit adp5589_remove(struct i2c_client *client) +{ +	struct adp5589_kpad *kpad = i2c_get_clientdata(client); + +	adp5589_write(client, ADP5589_GENERAL_CFG, 0); +	free_irq(client->irq, kpad); +	input_unregister_device(kpad->input); +	adp5589_gpio_remove(kpad); +	kfree(kpad); + +	return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int adp5589_suspend(struct device *dev) +{ +	struct adp5589_kpad *kpad = dev_get_drvdata(dev); +	struct i2c_client *client = kpad->client; + +	disable_irq(client->irq); + +	if (device_may_wakeup(&client->dev)) +		enable_irq_wake(client->irq); + +	return 0; +} + +static int adp5589_resume(struct device *dev) +{ +	struct adp5589_kpad *kpad = dev_get_drvdata(dev); +	struct i2c_client *client = kpad->client; + +	if (device_may_wakeup(&client->dev)) +		disable_irq_wake(client->irq); + +	enable_irq(client->irq); + +	return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(adp5589_dev_pm_ops, adp5589_suspend, adp5589_resume); + +static const struct i2c_device_id adp5589_id[] = { +	{"adp5589-keys", 0}, +	{} +}; + +MODULE_DEVICE_TABLE(i2c, adp5589_id); + +static struct i2c_driver adp5589_driver = { +	.driver = { +		.name = KBUILD_MODNAME, +		.owner = THIS_MODULE, +		.pm = &adp5589_dev_pm_ops, +	}, +	.probe = adp5589_probe, +	.remove = __devexit_p(adp5589_remove), +	.id_table = adp5589_id, +}; + +static int __init adp5589_init(void) +{ +	return i2c_add_driver(&adp5589_driver); +} +module_init(adp5589_init); + +static void __exit adp5589_exit(void) +{ +	i2c_del_driver(&adp5589_driver); +} +module_exit(adp5589_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Michael Hennerich <[email protected]>"); +MODULE_DESCRIPTION("ADP5589 Keypad driver"); diff --git a/drivers/input/keyboard/atakbd.c b/drivers/input/keyboard/atakbd.c index 1839194ea987..10bcd4ae5402 100644 --- a/drivers/input/keyboard/atakbd.c +++ b/drivers/input/keyboard/atakbd.c @@ -223,8 +223,9 @@ static int __init atakbd_init(void)  		return -ENODEV;  	// need to init core driver if not already done so -	if (atari_keyb_init()) -		return -ENODEV; +	error = atari_keyb_init(); +	if (error) +		return error;  	atakbd_dev = input_allocate_device();  	if (!atakbd_dev) diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index eb3006361ee4..6e6145b9a4c1 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -324,7 +324,12 @@ static void gpio_keys_report_event(struct gpio_button_data *bdata)  	unsigned int type = button->type ?: EV_KEY;  	int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low; -	input_event(input, type, button->code, !!state); +	if (type == EV_ABS) { +		if (state) +			input_event(input, type, button->code, button->value); +	} else { +		input_event(input, type, button->code, !!state); +	}  	input_sync(input);  } @@ -363,7 +368,7 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev,  					 struct gpio_button_data *bdata,  					 struct gpio_keys_button *button)  { -	char *desc = button->desc ? button->desc : "gpio_keys"; +	const char *desc = button->desc ? button->desc : "gpio_keys";  	struct device *dev = &pdev->dev;  	unsigned long irqflags;  	int irq, error; @@ -468,7 +473,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)  	platform_set_drvdata(pdev, ddata);  	input_set_drvdata(input, ddata); -	input->name = pdev->name; +	input->name = pdata->name ? : pdev->name;  	input->phys = "gpio-keys/input0";  	input->dev.parent = &pdev->dev;  	input->open = gpio_keys_open; diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c new file mode 100644 index 000000000000..0a9e81194888 --- /dev/null +++ b/drivers/input/keyboard/mpr121_touchkey.c @@ -0,0 +1,339 @@ +/* + * Touchkey driver for Freescale MPR121 Controllor + * + * Copyright (C) 2011 Freescale Semiconductor, Inc. + * Author: Zhang Jiejing <[email protected]> + * + * Based on mcs_touchkey.c + * + * 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/init.h> +#include <linux/input.h> +#include <linux/i2c.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/bitops.h> +#include <linux/interrupt.h> +#include <linux/i2c/mpr121_touchkey.h> + +/* Register definitions */ +#define ELE_TOUCH_STATUS_0_ADDR	0x0 +#define ELE_TOUCH_STATUS_1_ADDR	0X1 +#define MHD_RISING_ADDR		0x2b +#define NHD_RISING_ADDR		0x2c +#define NCL_RISING_ADDR		0x2d +#define FDL_RISING_ADDR		0x2e +#define MHD_FALLING_ADDR	0x2f +#define NHD_FALLING_ADDR	0x30 +#define NCL_FALLING_ADDR	0x31 +#define FDL_FALLING_ADDR	0x32 +#define ELE0_TOUCH_THRESHOLD_ADDR	0x41 +#define ELE0_RELEASE_THRESHOLD_ADDR	0x42 +#define AFE_CONF_ADDR			0x5c +#define FILTER_CONF_ADDR		0x5d + +/* + * ELECTRODE_CONF_ADDR: This register configures the number of + * enabled capacitance sensing inputs and its run/suspend mode. + */ +#define ELECTRODE_CONF_ADDR		0x5e +#define AUTO_CONFIG_CTRL_ADDR		0x7b +#define AUTO_CONFIG_USL_ADDR		0x7d +#define AUTO_CONFIG_LSL_ADDR		0x7e +#define AUTO_CONFIG_TL_ADDR		0x7f + +/* Threshold of touch/release trigger */ +#define TOUCH_THRESHOLD			0x0f +#define RELEASE_THRESHOLD		0x0a +/* Masks for touch and release triggers */ +#define TOUCH_STATUS_MASK		0xfff +/* MPR121 has 12 keys */ +#define MPR121_MAX_KEY_COUNT		12 + +struct mpr121_touchkey { +	struct i2c_client	*client; +	struct input_dev	*input_dev; +	unsigned int		key_val; +	unsigned int		statusbits; +	unsigned int		keycount; +	u16			keycodes[MPR121_MAX_KEY_COUNT]; +}; + +struct mpr121_init_register { +	int addr; +	u8 val; +}; + +static const struct mpr121_init_register init_reg_table[] __devinitconst = { +	{ MHD_RISING_ADDR,	0x1 }, +	{ NHD_RISING_ADDR,	0x1 }, +	{ MHD_FALLING_ADDR,	0x1 }, +	{ NHD_FALLING_ADDR,	0x1 }, +	{ NCL_FALLING_ADDR,	0xff }, +	{ FDL_FALLING_ADDR,	0x02 }, +	{ FILTER_CONF_ADDR,	0x04 }, +	{ AFE_CONF_ADDR,	0x0b }, +	{ AUTO_CONFIG_CTRL_ADDR, 0x0b }, +}; + +static irqreturn_t mpr_touchkey_interrupt(int irq, void *dev_id) +{ +	struct mpr121_touchkey *mpr121 = dev_id; +	struct i2c_client *client = mpr121->client; +	struct input_dev *input = mpr121->input_dev; +	unsigned int key_num, key_val, pressed; +	int reg; + +	reg = i2c_smbus_read_byte_data(client, ELE_TOUCH_STATUS_1_ADDR); +	if (reg < 0) { +		dev_err(&client->dev, "i2c read error [%d]\n", reg); +		goto out; +	} + +	reg <<= 8; +	reg |= i2c_smbus_read_byte_data(client, ELE_TOUCH_STATUS_0_ADDR); +	if (reg < 0) { +		dev_err(&client->dev, "i2c read error [%d]\n", reg); +		goto out; +	} + +	reg &= TOUCH_STATUS_MASK; +	/* use old press bit to figure out which bit changed */ +	key_num = ffs(reg ^ mpr121->statusbits) - 1; +	pressed = reg & (1 << key_num); +	mpr121->statusbits = reg; + +	key_val = mpr121->keycodes[key_num]; + +	input_event(input, EV_MSC, MSC_SCAN, key_num); +	input_report_key(input, key_val, pressed); +	input_sync(input); + +	dev_dbg(&client->dev, "key %d %d %s\n", key_num, key_val, +		pressed ? "pressed" : "released"); + +out: +	return IRQ_HANDLED; +} + +static int __devinit mpr121_phys_init(const struct mpr121_platform_data *pdata, +				      struct mpr121_touchkey *mpr121, +				      struct i2c_client *client) +{ +	const struct mpr121_init_register *reg; +	unsigned char usl, lsl, tl; +	int i, t, vdd, ret; + +	/* Set up touch/release threshold for ele0-ele11 */ +	for (i = 0; i <= MPR121_MAX_KEY_COUNT; i++) { +		t = ELE0_TOUCH_THRESHOLD_ADDR + (i * 2); +		ret = i2c_smbus_write_byte_data(client, t, TOUCH_THRESHOLD); +		if (ret < 0) +			goto err_i2c_write; +		ret = i2c_smbus_write_byte_data(client, t + 1, +						RELEASE_THRESHOLD); +		if (ret < 0) +			goto err_i2c_write; +	} + +	/* Set up init register */ +	for (i = 0; i < ARRAY_SIZE(init_reg_table); i++) { +		reg = &init_reg_table[i]; +		ret = i2c_smbus_write_byte_data(client, reg->addr, reg->val); +		if (ret < 0) +			goto err_i2c_write; +	} + + +	/* +	 * Capacitance on sensing input varies and needs to be compensated. +	 * The internal MPR121-auto-configuration can do this if it's +	 * registers are set properly (based on pdata->vdd_uv). +	 */ +	vdd = pdata->vdd_uv / 1000; +	usl = ((vdd - 700) * 256) / vdd; +	lsl = (usl * 65) / 100; +	tl = (usl * 90) / 100; +	ret = i2c_smbus_write_byte_data(client, AUTO_CONFIG_USL_ADDR, usl); +	ret |= i2c_smbus_write_byte_data(client, AUTO_CONFIG_LSL_ADDR, lsl); +	ret |= i2c_smbus_write_byte_data(client, AUTO_CONFIG_TL_ADDR, tl); +	ret |= i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR, +					 mpr121->keycount); +	if (ret != 0) +		goto err_i2c_write; + +	dev_dbg(&client->dev, "set up with %x keys.\n", mpr121->keycount); + +	return 0; + +err_i2c_write: +	dev_err(&client->dev, "i2c write error: %d\n", ret); +	return ret; +} + +static int __devinit mpr_touchkey_probe(struct i2c_client *client, +					const struct i2c_device_id *id) +{ +	const struct mpr121_platform_data *pdata = client->dev.platform_data; +	struct mpr121_touchkey *mpr121; +	struct input_dev *input_dev; +	int error; +	int i; + +	if (!pdata) { +		dev_err(&client->dev, "no platform data defined\n"); +		return -EINVAL; +	} + +	if (!pdata->keymap || !pdata->keymap_size) { +		dev_err(&client->dev, "missing keymap data\n"); +		return -EINVAL; +	} + +	if (pdata->keymap_size > MPR121_MAX_KEY_COUNT) { +		dev_err(&client->dev, "too many keys defined\n"); +		return -EINVAL; +	} + +	if (!client->irq) { +		dev_err(&client->dev, "irq number should not be zero\n"); +		return -EINVAL; +	} + +	mpr121 = kzalloc(sizeof(struct mpr121_touchkey), GFP_KERNEL); +	input_dev = input_allocate_device(); +	if (!mpr121 || !input_dev) { +		dev_err(&client->dev, "Failed to allocate memory\n"); +		error = -ENOMEM; +		goto err_free_mem; +	} + +	mpr121->client = client; +	mpr121->input_dev = input_dev; +	mpr121->keycount = pdata->keymap_size; + +	input_dev->name = "Freescale MPR121 Touchkey"; +	input_dev->id.bustype = BUS_I2C; +	input_dev->dev.parent = &client->dev; +	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); + +	input_dev->keycode = mpr121->keycodes; +	input_dev->keycodesize = sizeof(mpr121->keycodes[0]); +	input_dev->keycodemax = mpr121->keycount; + +	for (i = 0; i < pdata->keymap_size; i++) { +		input_set_capability(input_dev, EV_KEY, pdata->keymap[i]); +		mpr121->keycodes[i] = pdata->keymap[i]; +	} + +	error = mpr121_phys_init(pdata, mpr121, client); +	if (error) { +		dev_err(&client->dev, "Failed to init register\n"); +		goto err_free_mem; +	} + +	error = request_threaded_irq(client->irq, NULL, +				     mpr_touchkey_interrupt, +				     IRQF_TRIGGER_FALLING, +				     client->dev.driver->name, mpr121); +	if (error) { +		dev_err(&client->dev, "Failed to register interrupt\n"); +		goto err_free_mem; +	} + +	error = input_register_device(input_dev); +	if (error) +		goto err_free_irq; + +	i2c_set_clientdata(client, mpr121); +	device_init_wakeup(&client->dev, pdata->wakeup); + +	return 0; + +err_free_irq: +	free_irq(client->irq, mpr121); +err_free_mem: +	input_free_device(input_dev); +	kfree(mpr121); +	return error; +} + +static int __devexit mpr_touchkey_remove(struct i2c_client *client) +{ +	struct mpr121_touchkey *mpr121 = i2c_get_clientdata(client); + +	free_irq(client->irq, mpr121); +	input_unregister_device(mpr121->input_dev); +	kfree(mpr121); + +	return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int mpr_suspend(struct device *dev) +{ +	struct i2c_client *client = to_i2c_client(dev); + +	if (device_may_wakeup(&client->dev)) +		enable_irq_wake(client->irq); + +	i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR, 0x00); + +	return 0; +} + +static int mpr_resume(struct device *dev) +{ +	struct i2c_client *client = to_i2c_client(dev); +	struct mpr121_touchkey *mpr121 = i2c_get_clientdata(client); + +	if (device_may_wakeup(&client->dev)) +		disable_irq_wake(client->irq); + +	i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR, +				  mpr121->keycount); + +	return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(mpr121_touchkey_pm_ops, mpr_suspend, mpr_resume); + +static const struct i2c_device_id mpr121_id[] = { +	{ "mpr121_touchkey", 0 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, mpr121_id); + +static struct i2c_driver mpr_touchkey_driver = { +	.driver = { +		.name	= "mpr121", +		.owner	= THIS_MODULE, +		.pm	= &mpr121_touchkey_pm_ops, +	}, +	.id_table	= mpr121_id, +	.probe		= mpr_touchkey_probe, +	.remove		= __devexit_p(mpr_touchkey_remove), +}; + +static int __init mpr_touchkey_init(void) +{ +	return i2c_add_driver(&mpr_touchkey_driver); +} +module_init(mpr_touchkey_init); + +static void __exit mpr_touchkey_exit(void) +{ +	i2c_del_driver(&mpr_touchkey_driver); +} +module_exit(mpr_touchkey_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Zhang Jiejing <[email protected]>"); +MODULE_DESCRIPTION("Touch Key driver for Freescale MPR121 Chip"); diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c index 0e2a19cb43d8..f23a743817db 100644 --- a/drivers/input/keyboard/omap-keypad.c +++ b/drivers/input/keyboard/omap-keypad.c @@ -413,7 +413,7 @@ static int __devinit omap_kp_probe(struct platform_device *pdev)  	return 0;  err5:  	for (i = irq_idx - 1; i >=0; i--) -		free_irq(row_gpios[i], NULL); +		free_irq(row_gpios[i], omap_kp);  err4:  	input_unregister_device(omap_kp->input);  	input_dev = NULL; @@ -444,11 +444,11 @@ static int __devexit omap_kp_remove(struct platform_device *pdev)  			gpio_free(col_gpios[i]);  		for (i = 0; i < omap_kp->rows; i++) {  			gpio_free(row_gpios[i]); -			free_irq(gpio_to_irq(row_gpios[i]), NULL); +			free_irq(gpio_to_irq(row_gpios[i]), omap_kp);  		}  	} else {  		omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); -		free_irq(omap_kp->irq, NULL); +		free_irq(omap_kp->irq, omap_kp);  	}  	del_timer_sync(&omap_kp->timer); diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c new file mode 100644 index 000000000000..40b02ae96f86 --- /dev/null +++ b/drivers/input/keyboard/pmic8xxx-keypad.c @@ -0,0 +1,799 @@ +/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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/platform_device.h> +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/input.h> +#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> + +#define PM8XXX_MAX_ROWS		18 +#define PM8XXX_MAX_COLS		8 +#define PM8XXX_ROW_SHIFT	3 +#define PM8XXX_MATRIX_MAX_SIZE	(PM8XXX_MAX_ROWS * PM8XXX_MAX_COLS) + +#define PM8XXX_MIN_ROWS		5 +#define PM8XXX_MIN_COLS		5 + +#define MAX_SCAN_DELAY		128 +#define MIN_SCAN_DELAY		1 + +/* in nanoseconds */ +#define MAX_ROW_HOLD_DELAY	122000 +#define MIN_ROW_HOLD_DELAY	30500 + +#define MAX_DEBOUNCE_TIME	20 +#define MIN_DEBOUNCE_TIME	5 + +#define KEYP_CTRL			0x148 + +#define KEYP_CTRL_EVNTS			BIT(0) +#define KEYP_CTRL_EVNTS_MASK		0x3 + +#define KEYP_CTRL_SCAN_COLS_SHIFT	5 +#define KEYP_CTRL_SCAN_COLS_MIN		5 +#define KEYP_CTRL_SCAN_COLS_BITS	0x3 + +#define KEYP_CTRL_SCAN_ROWS_SHIFT	2 +#define KEYP_CTRL_SCAN_ROWS_MIN		5 +#define KEYP_CTRL_SCAN_ROWS_BITS	0x7 + +#define KEYP_CTRL_KEYP_EN		BIT(7) + +#define KEYP_SCAN			0x149 + +#define KEYP_SCAN_READ_STATE		BIT(0) +#define KEYP_SCAN_DBOUNCE_SHIFT		1 +#define KEYP_SCAN_PAUSE_SHIFT		3 +#define KEYP_SCAN_ROW_HOLD_SHIFT	6 + +#define KEYP_TEST			0x14A + +#define KEYP_TEST_CLEAR_RECENT_SCAN	BIT(6) +#define KEYP_TEST_CLEAR_OLD_SCAN	BIT(5) +#define KEYP_TEST_READ_RESET		BIT(4) +#define KEYP_TEST_DTEST_EN		BIT(3) +#define KEYP_TEST_ABORT_READ		BIT(0) + +#define KEYP_TEST_DBG_SELECT_SHIFT	1 + +/* bits of these registers represent + * '0' for key press + * '1' for key release + */ +#define KEYP_RECENT_DATA		0x14B +#define KEYP_OLD_DATA			0x14C + +#define KEYP_CLOCK_FREQ			32768 + +/** + * struct pmic8xxx_kp - internal keypad data structure + * @pdata - keypad platform data pointer + * @input - input device pointer for keypad + * @key_sense_irq - key press/release irq number + * @key_stuck_irq - key stuck notification irq number + * @keycodes - array to hold the key codes + * @dev - parent device pointer + * @keystate - present key press/release state + * @stuckstate - present state when key stuck irq + * @ctrl_reg - control register value + */ +struct pmic8xxx_kp { +	const struct pm8xxx_keypad_platform_data *pdata; +	struct input_dev *input; +	int key_sense_irq; +	int key_stuck_irq; + +	unsigned short keycodes[PM8XXX_MATRIX_MAX_SIZE]; + +	struct device *dev; +	u16 keystate[PM8XXX_MAX_ROWS]; +	u16 stuckstate[PM8XXX_MAX_ROWS]; + +	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; +	else +		return col & ((1 << kp->pdata->num_cols) - 1); +} + +/* + * Synchronous read protocol for RevB0 onwards: + * + * 1. Write '1' to ReadState bit in KEYP_SCAN register + * 2. Wait 2*32KHz clocks, so that HW can successfully enter read mode + *    synchronously + * 3. Read rows in old array first if events are more than one + * 4. Read rows in recent array + * 5. Wait 4*32KHz clocks + * 6. Write '0' to ReadState bit of KEYP_SCAN register so that hw can + *    synchronously exit read mode. + */ +static int pmic8xxx_chk_sync_read(struct pmic8xxx_kp *kp) +{ +	int rc; +	u8 scan_val; + +	rc = pmic8xxx_kp_read_u8(kp, &scan_val, KEYP_SCAN); +	if (rc < 0) { +		dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc); +		return rc; +	} + +	scan_val |= 0x1; + +	rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN); +	if (rc < 0) { +		dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc); +		return rc; +	} + +	/* 2 * 32KHz clocks */ +	udelay((2 * DIV_ROUND_UP(USEC_PER_SEC, KEYP_CLOCK_FREQ)) + 1); + +	return rc; +} + +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; + +	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]); +	} + +	return rc; +} + +static int pmic8xxx_kp_read_matrix(struct pmic8xxx_kp *kp, u16 *new_state, +					 u16 *old_state) +{ +	int rc, read_rows; +	u8 scan_val; + +	if (kp->pdata->num_rows < PM8XXX_MIN_ROWS) +		read_rows = PM8XXX_MIN_ROWS; +	else +		read_rows = kp->pdata->num_rows; + +	pmic8xxx_chk_sync_read(kp); + +	if (old_state) { +		rc = pmic8xxx_kp_read_data(kp, old_state, KEYP_OLD_DATA, +						read_rows); +		if (rc < 0) { +			dev_err(kp->dev, +				"Error reading KEYP_OLD_DATA, rc=%d\n", rc); +			return rc; +		} +	} + +	rc = pmic8xxx_kp_read_data(kp, new_state, KEYP_RECENT_DATA, +					 read_rows); +	if (rc < 0) { +		dev_err(kp->dev, +			"Error reading KEYP_RECENT_DATA, rc=%d\n", rc); +		return rc; +	} + +	/* 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); +	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); +	if (rc < 0) +		dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc); + +	return rc; +} + +static void __pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, u16 *new_state, +					 u16 *old_state) +{ +	int row, col, code; + +	for (row = 0; row < kp->pdata->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++) { +			if (!(bits_changed & (1 << col))) +				continue; + +			dev_dbg(kp->dev, "key [%d:%d] %s\n", row, col, +					!(new_state[row] & (1 << col)) ? +					"pressed" : "released"); + +			code = MATRIX_SCAN_CODE(row, col, PM8XXX_ROW_SHIFT); + +			input_event(kp->input, EV_MSC, MSC_SCAN, code); +			input_report_key(kp->input, +					kp->keycodes[code], +					!(new_state[row] & (1 << col))); + +			input_sync(kp->input); +		} +	} +} + +static bool pmic8xxx_detect_ghost_keys(struct pmic8xxx_kp *kp, u16 *new_state) +{ +	int row, found_first = -1; +	u16 check, row_state; + +	check = 0; +	for (row = 0; row < kp->pdata->num_rows; row++) { +		row_state = (~new_state[row]) & +				 ((1 << kp->pdata->num_cols) - 1); + +		if (hweight16(row_state) > 1) { +			if (found_first == -1) +				found_first = row; +			if (check & row_state) { +				dev_dbg(kp->dev, "detected ghost key on row[%d]" +					 " and row[%d]\n", found_first, row); +				return true; +			} +		} +		check |= row_state; +	} +	return false; +} + +static int pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, unsigned int events) +{ +	u16 new_state[PM8XXX_MAX_ROWS]; +	u16 old_state[PM8XXX_MAX_ROWS]; +	int rc; + +	switch (events) { +	case 0x1: +		rc = pmic8xxx_kp_read_matrix(kp, new_state, NULL); +		if (rc < 0) +			return rc; + +		/* detecting ghost key is not an error */ +		if (pmic8xxx_detect_ghost_keys(kp, new_state)) +			return 0; +		__pmic8xxx_kp_scan_matrix(kp, new_state, kp->keystate); +		memcpy(kp->keystate, new_state, sizeof(new_state)); +	break; +	case 0x3: /* two events - eventcounter is gray-coded */ +		rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state); +		if (rc < 0) +			return rc; + +		__pmic8xxx_kp_scan_matrix(kp, old_state, kp->keystate); +		__pmic8xxx_kp_scan_matrix(kp, new_state, old_state); +		memcpy(kp->keystate, new_state, sizeof(new_state)); +	break; +	case 0x2: +		dev_dbg(kp->dev, "Some key events were lost\n"); +		rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state); +		if (rc < 0) +			return rc; +		__pmic8xxx_kp_scan_matrix(kp, old_state, kp->keystate); +		__pmic8xxx_kp_scan_matrix(kp, new_state, old_state); +		memcpy(kp->keystate, new_state, sizeof(new_state)); +	break; +	default: +		rc = -EINVAL; +	} +	return rc; +} + +/* + * NOTE: We are reading recent and old data registers blindly + * whenever key-stuck interrupt happens, because events counter doesn't + * get updated when this interrupt happens due to key stuck doesn't get + * considered as key state change. + * + * We are not using old data register contents after they are being read + * because it might report the key which was pressed before the key being stuck + * as stuck key because it's pressed status is stored in the old data + * register. + */ +static irqreturn_t pmic8xxx_kp_stuck_irq(int irq, void *data) +{ +	u16 new_state[PM8XXX_MAX_ROWS]; +	u16 old_state[PM8XXX_MAX_ROWS]; +	int rc; +	struct pmic8xxx_kp *kp = data; + +	rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state); +	if (rc < 0) { +		dev_err(kp->dev, "failed to read keypad matrix\n"); +		return IRQ_HANDLED; +	} + +	__pmic8xxx_kp_scan_matrix(kp, new_state, kp->stuckstate); + +	return IRQ_HANDLED; +} + +static irqreturn_t pmic8xxx_kp_irq(int irq, void *data) +{ +	struct pmic8xxx_kp *kp = data; +	u8 ctrl_val, events; +	int rc; + +	rc = pmic8xxx_kp_read(kp, &ctrl_val, KEYP_CTRL, 1); +	if (rc < 0) { +		dev_err(kp->dev, "failed to read keyp_ctrl register\n"); +		return IRQ_HANDLED; +	} + +	events = ctrl_val & KEYP_CTRL_EVNTS_MASK; + +	rc = pmic8xxx_kp_scan_matrix(kp, events); +	if (rc < 0) +		dev_err(kp->dev, "failed to scan matrix\n"); + +	return IRQ_HANDLED; +} + +static int __devinit pmic8xxx_kpd_init(struct pmic8xxx_kp *kp) +{ +	int bits, rc, cycles; +	u8 scan_val = 0, ctrl_val = 0; +	static const u8 row_bits[] = { +		0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, +	}; + +	/* Find column bits */ +	if (kp->pdata->num_cols < KEYP_CTRL_SCAN_COLS_MIN) +		bits = 0; +	else +		bits = kp->pdata->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) +		bits = 0; +	else +		bits = row_bits[kp->pdata->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); +	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; + +	scan_val |= (bits << KEYP_SCAN_DBOUNCE_SHIFT); + +	bits = fls(kp->pdata->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; + +	scan_val |= (cycles << KEYP_SCAN_ROW_HOLD_SHIFT); + +	rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN); +	if (rc) +		dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc); + +	return rc; + +} + +static int  __devinit 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); +	if (rc < 0) +		dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc); + +	return rc; +} + +static int pmic8xxx_kp_disable(struct pmic8xxx_kp *kp) +{ +	int rc; + +	kp->ctrl_reg &= ~KEYP_CTRL_KEYP_EN; + +	rc = pmic8xxx_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL); +	if (rc < 0) +		return rc; + +	return rc; +} + +static int pmic8xxx_kp_open(struct input_dev *dev) +{ +	struct pmic8xxx_kp *kp = input_get_drvdata(dev); + +	return pmic8xxx_kp_enable(kp); +} + +static void pmic8xxx_kp_close(struct input_dev *dev) +{ +	struct pmic8xxx_kp *kp = input_get_drvdata(dev); + +	pmic8xxx_kp_disable(kp); +} + +/* + * keypad controller should be initialized in the following sequence + * only, otherwise it might get into FSM stuck state. + * + * - Initialize keypad control parameters, like no. of rows, columns, + *   timing values etc., + * - configure rows and column gpios pull up/down. + * - set irq edge type. + * - enable the keypad controller. + */ +static int __devinit pmic8xxx_kp_probe(struct platform_device *pdev) +{ +	const struct pm8xxx_keypad_platform_data *pdata = mfd_get_data(pdev); +	const struct matrix_keymap_data *keymap_data; +	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, +	}; + + +	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) { +		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; +	} + +	kp = kzalloc(sizeof(*kp), GFP_KERNEL); +	if (!kp) +		return -ENOMEM; + +	platform_set_drvdata(pdev, kp); + +	kp->pdata	= pdata; +	kp->dev		= &pdev->dev; + +	kp->input = input_allocate_device(); +	if (!kp->input) { +		dev_err(&pdev->dev, "unable to allocate input device\n"); +		rc = -ENOMEM; +		goto err_alloc_device; +	} + +	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; +	} + +	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; +	} + +	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->id.bustype	= BUS_I2C; +	kp->input->id.version	= 0x0001; +	kp->input->id.product	= 0x0001; +	kp->input->id.vendor	= 0x0001; + +	kp->input->evbit[0]	= BIT_MASK(EV_KEY); + +	if (pdata->rep) +		__set_bit(EV_REP, kp->input->evbit); + +	kp->input->keycode	= kp->keycodes; +	kp->input->keycodemax	= PM8XXX_MATRIX_MAX_SIZE; +	kp->input->keycodesize	= sizeof(kp->keycodes); +	kp->input->open		= pmic8xxx_kp_open; +	kp->input->close	= pmic8xxx_kp_close; + +	matrix_keypad_build_keymap(keymap_data, PM8XXX_ROW_SHIFT, +					kp->input->keycode, kp->input->keybit); + +	input_set_capability(kp->input, EV_MSC, MSC_SCAN); +	input_set_drvdata(kp->input, kp); + +	/* initialize keypad state */ +	memset(kp->keystate, 0xff, sizeof(kp->keystate)); +	memset(kp->stuckstate, 0xff, sizeof(kp->stuckstate)); + +	rc = pmic8xxx_kpd_init(kp); +	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; +	} + +	rc = request_any_context_irq(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; +	} + +	rc = request_any_context_irq(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; +	} + +	rc = pmic8xxx_kp_read_u8(kp, &ctrl_val, KEYP_CTRL); +	if (rc < 0) { +		dev_err(&pdev->dev, "failed to read KEYP_CTRL register\n"); +		goto err_pmic_reg_read; +	} + +	kp->ctrl_reg = ctrl_val; + +	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; +	} + +	device_init_wakeup(&pdev->dev, pdata->wakeup); + +	return 0; + +err_pmic_reg_read: +	free_irq(kp->key_stuck_irq, NULL); +err_req_stuck_irq: +	free_irq(kp->key_sense_irq, NULL); +err_gpio_config: +err_get_irq: +	input_free_device(kp->input); +err_alloc_device: +	platform_set_drvdata(pdev, NULL); +	kfree(kp); +	return rc; +} + +static int __devexit 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, NULL); +	free_irq(kp->key_sense_irq, NULL); +	input_unregister_device(kp->input); +	kfree(kp); + +	platform_set_drvdata(pdev, NULL); +	return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int pmic8xxx_kp_suspend(struct device *dev) +{ +	struct platform_device *pdev = to_platform_device(dev); +	struct pmic8xxx_kp *kp = platform_get_drvdata(pdev); +	struct input_dev *input_dev = kp->input; + +	if (device_may_wakeup(dev)) { +		enable_irq_wake(kp->key_sense_irq); +	} else { +		mutex_lock(&input_dev->mutex); + +		if (input_dev->users) +			pmic8xxx_kp_disable(kp); + +		mutex_unlock(&input_dev->mutex); +	} + +	return 0; +} + +static int pmic8xxx_kp_resume(struct device *dev) +{ +	struct platform_device *pdev = to_platform_device(dev); +	struct pmic8xxx_kp *kp = platform_get_drvdata(pdev); +	struct input_dev *input_dev = kp->input; + +	if (device_may_wakeup(dev)) { +		disable_irq_wake(kp->key_sense_irq); +	} else { +		mutex_lock(&input_dev->mutex); + +		if (input_dev->users) +			pmic8xxx_kp_enable(kp); + +		mutex_unlock(&input_dev->mutex); +	} + +	return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(pm8xxx_kp_pm_ops, +			 pmic8xxx_kp_suspend, pmic8xxx_kp_resume); + +static struct platform_driver pmic8xxx_kp_driver = { +	.probe		= pmic8xxx_kp_probe, +	.remove		= __devexit_p(pmic8xxx_kp_remove), +	.driver		= { +		.name = PM8XXX_KEYPAD_DEV_NAME, +		.owner = THIS_MODULE, +		.pm = &pm8xxx_kp_pm_ops, +	}, +}; + +static int __init pmic8xxx_kp_init(void) +{ +	return platform_driver_register(&pmic8xxx_kp_driver); +} +module_init(pmic8xxx_kp_init); + +static void __exit pmic8xxx_kp_exit(void) +{ +	platform_driver_unregister(&pmic8xxx_kp_driver); +} +module_exit(pmic8xxx_kp_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("PMIC8XXX keypad driver"); +MODULE_VERSION("1.0"); +MODULE_ALIAS("platform:pmic8xxx_keypad"); +MODULE_AUTHOR("Trilok Soni <[email protected]>"); diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c index fba8404c7297..ca7b89196ab7 100644 --- a/drivers/input/keyboard/qt1070.c +++ b/drivers/input/keyboard/qt1070.c @@ -248,6 +248,7 @@ static const struct i2c_device_id qt1070_id[] = {  	{ "qt1070", 0 },  	{ },  }; +MODULE_DEVICE_TABLE(i2c, qt1070_id);  static struct i2c_driver qt1070_driver = {  	.driver	= { diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c index d7dafd9425b6..834cf98e7efb 100644 --- a/drivers/input/keyboard/sh_keysc.c +++ b/drivers/input/keyboard/sh_keysc.c @@ -20,7 +20,7 @@  #include <linux/input.h>  #include <linux/input/sh_keysc.h>  #include <linux/bitmap.h> -#include <linux/clk.h> +#include <linux/pm_runtime.h>  #include <linux/io.h>  #include <linux/slab.h> @@ -37,7 +37,6 @@ static const struct {  struct sh_keysc_priv {  	void __iomem *iomem_base; -	struct clk *clk;  	DECLARE_BITMAP(last_keys, SH_KEYSC_MAXKEYS);  	struct input_dev *input;  	struct sh_keysc_info pdata; @@ -169,7 +168,6 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)  	struct sh_keysc_info *pdata;  	struct resource *res;  	struct input_dev *input; -	char clk_name[8];  	int i;  	int irq, error; @@ -210,19 +208,11 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)  		goto err1;  	} -	snprintf(clk_name, sizeof(clk_name), "keysc%d", pdev->id); -	priv->clk = clk_get(&pdev->dev, clk_name); -	if (IS_ERR(priv->clk)) { -		dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); -		error = PTR_ERR(priv->clk); -		goto err2; -	} -  	priv->input = input_allocate_device();  	if (!priv->input) {  		dev_err(&pdev->dev, "failed to allocate input device\n");  		error = -ENOMEM; -		goto err3; +		goto err2;  	}  	input = priv->input; @@ -241,10 +231,11 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)  	input->keycodesize = sizeof(pdata->keycodes[0]);  	input->keycodemax = ARRAY_SIZE(pdata->keycodes); -	error = request_irq(irq, sh_keysc_isr, 0, pdev->name, pdev); +	error = request_threaded_irq(irq, NULL, sh_keysc_isr, IRQF_ONESHOT, +				     dev_name(&pdev->dev), pdev);  	if (error) {  		dev_err(&pdev->dev, "failed to request IRQ\n"); -		goto err4; +		goto err3;  	}  	for (i = 0; i < SH_KEYSC_MAXKEYS; i++) @@ -254,10 +245,11 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)  	error = input_register_device(input);  	if (error) {  		dev_err(&pdev->dev, "failed to register input device\n"); -		goto err5; +		goto err4;  	} -	clk_enable(priv->clk); +	pm_runtime_enable(&pdev->dev); +	pm_runtime_get_sync(&pdev->dev);  	sh_keysc_write(priv, KYCR1, (sh_keysc_mode[pdata->mode].kymd << 8) |  		       pdata->scan_timing); @@ -267,12 +259,10 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)  	return 0; - err5: -	free_irq(irq, pdev);   err4: -	input_free_device(input); +	free_irq(irq, pdev);   err3: -	clk_put(priv->clk); +	input_free_device(input);   err2:  	iounmap(priv->iomem_base);   err1: @@ -292,8 +282,8 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev)  	free_irq(platform_get_irq(pdev, 0), pdev);  	iounmap(priv->iomem_base); -	clk_disable(priv->clk); -	clk_put(priv->clk); +	pm_runtime_put_sync(&pdev->dev); +	pm_runtime_disable(&pdev->dev);  	platform_set_drvdata(pdev, NULL);  	kfree(priv); @@ -301,6 +291,7 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev)  	return 0;  } +#if CONFIG_PM_SLEEP  static int sh_keysc_suspend(struct device *dev)  {  	struct platform_device *pdev = to_platform_device(dev); @@ -311,14 +302,13 @@ static int sh_keysc_suspend(struct device *dev)  	value = sh_keysc_read(priv, KYCR1);  	if (device_may_wakeup(dev)) { -		value |= 0x80; +		sh_keysc_write(priv, KYCR1, value | 0x80);  		enable_irq_wake(irq);  	} else { -		value &= ~0x80; +		sh_keysc_write(priv, KYCR1, value & ~0x80); +		pm_runtime_put_sync(dev);  	} -	sh_keysc_write(priv, KYCR1, value); -  	return 0;  } @@ -329,16 +319,17 @@ static int sh_keysc_resume(struct device *dev)  	if (device_may_wakeup(dev))  		disable_irq_wake(irq); +	else +		pm_runtime_get_sync(dev);  	return 0;  } +#endif -static const struct dev_pm_ops sh_keysc_dev_pm_ops = { -	.suspend = sh_keysc_suspend, -	.resume = sh_keysc_resume, -}; +static SIMPLE_DEV_PM_OPS(sh_keysc_dev_pm_ops, +			 sh_keysc_suspend, sh_keysc_resume); -struct platform_driver sh_keysc_device_driver = { +static struct platform_driver sh_keysc_device_driver = {  	.probe		= sh_keysc_probe,  	.remove		= __devexit_p(sh_keysc_remove),  	.driver		= { diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index 99ce9032d08c..2b3b73ec6689 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -66,12 +66,11 @@ struct tegra_kbc {  	void __iomem *mmio;  	struct input_dev *idev;  	unsigned int irq; -	unsigned int wake_enable_rows; -	unsigned int wake_enable_cols;  	spinlock_t lock;  	unsigned int repoll_dly;  	unsigned long cp_dly_jiffies;  	bool use_fn_map; +	bool use_ghost_filter;  	const struct tegra_kbc_platform_data *pdata;  	unsigned short keycode[KBC_MAX_KEY * 2];  	unsigned short current_keys[KBC_MAX_KPENT]; @@ -260,6 +259,8 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)  	unsigned int num_down = 0;  	unsigned long flags;  	bool fn_keypress = false; +	bool key_in_same_row = false; +	bool key_in_same_col = false;  	spin_lock_irqsave(&kbc->lock, flags);  	for (i = 0; i < KBC_MAX_KPENT; i++) { @@ -285,6 +286,34 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)  	}  	/* +	 * Matrix keyboard designs are prone to keyboard ghosting. +	 * Ghosting occurs if there are 3 keys such that - +	 * any 2 of the 3 keys share a row, and any 2 of them share a column. +	 * If so ignore the key presses for this iteration. +	 */ +	if ((kbc->use_ghost_filter) && (num_down >= 3)) { +		for (i = 0; i < num_down; i++) { +			unsigned int j; +			u8 curr_col = scancodes[i] & 0x07; +			u8 curr_row = scancodes[i] >> KBC_ROW_SHIFT; + +			/* +			 * Find 2 keys such that one key is in the same row +			 * and the other is in the same column as the i-th key. +			 */ +			for (j = i + 1; j < num_down; j++) { +				u8 col = scancodes[j] & 0x07; +				u8 row = scancodes[j] >> KBC_ROW_SHIFT; + +				if (col == curr_col) +					key_in_same_col = true; +				if (row == curr_row) +					key_in_same_row = true; +			} +		} +	} + +	/*  	 * If the platform uses Fn keymaps, translate keys on a Fn keypress.  	 * Function keycodes are KBC_MAX_KEY apart from the plain keycodes.  	 */ @@ -297,6 +326,10 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)  	spin_unlock_irqrestore(&kbc->lock, flags); +	/* Ignore the key presses for this iteration? */ +	if (key_in_same_col && key_in_same_row) +		return; +  	tegra_kbc_report_released_keys(kbc->idev,  				       kbc->current_keys, kbc->num_pressed_keys,  				       keycodes, num_down); @@ -383,21 +416,11 @@ static void tegra_kbc_setup_wakekeys(struct tegra_kbc *kbc, bool filter)  	int i;  	unsigned int rst_val; -	BUG_ON(pdata->wake_cnt > KBC_MAX_KEY); -	rst_val = (filter && pdata->wake_cnt) ? ~0 : 0; +	/* Either mask all keys or none. */ +	rst_val = (filter && !pdata->wakeup) ? ~0 : 0;  	for (i = 0; i < KBC_MAX_ROW; i++)  		writel(rst_val, kbc->mmio + KBC_ROW0_MASK_0 + i * 4); - -	if (filter) { -		for (i = 0; i < pdata->wake_cnt; i++) { -			u32 val, addr; -			addr = pdata->wake_cfg[i].row * 4 + KBC_ROW0_MASK_0; -			val = readl(kbc->mmio + addr); -			val &= ~(1 << pdata->wake_cfg[i].col); -			writel(val, kbc->mmio + addr); -		} -	}  }  static void tegra_kbc_config_pins(struct tegra_kbc *kbc) @@ -559,7 +582,6 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)  	struct resource *res;  	int irq;  	int err; -	int i;  	int num_rows = 0;  	unsigned int debounce_cnt;  	unsigned int scan_time_rows; @@ -616,13 +638,6 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)  		goto err_iounmap;  	} -	kbc->wake_enable_rows = 0; -	kbc->wake_enable_cols = 0; -	for (i = 0; i < pdata->wake_cnt; i++) { -		kbc->wake_enable_rows |= (1 << pdata->wake_cfg[i].row); -		kbc->wake_enable_cols |= (1 << pdata->wake_cfg[i].col); -	} -  	/*  	 * The time delay between two consecutive reads of the FIFO is  	 * the sum of the repeat time and the time taken for scanning @@ -652,6 +667,7 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)  		input_dev->keycodemax *= 2;  	kbc->use_fn_map = pdata->use_fn_map; +	kbc->use_ghost_filter = pdata->use_ghost_filter;  	keymap_data = pdata->keymap_data ?: &tegra_kbc_default_keymap_data;  	matrix_keypad_build_keymap(keymap_data, KBC_ROW_SHIFT,  				   input_dev->keycode, input_dev->keybit); diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index f9cf0881b0e3..45dc6aa62ba4 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -330,6 +330,17 @@ config INPUT_PWM_BEEPER  	  To compile this driver as a module, choose M here: the module will be  	  called pwm-beeper. +config INPUT_PMIC8XXX_PWRKEY +	tristate "PMIC8XXX power key support" +	depends on MFD_PM8XXX +	help +	  Say Y here if you want support for the PMIC8XXX power key. + +	  If unsure, say N. + +	  To compile this driver as a module, choose M here: the +	  module will be called pmic8xxx-pwrkey. +  config INPUT_GPIO_ROTARY_ENCODER  	tristate "Rotary encoders connected to GPIO pins"  	depends on GPIOLIB && GENERIC_GPIO diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index e3f7984e6274..38efb2cb182b 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_INPUT_PCF8574)		+= pcf8574_keypad.o  obj-$(CONFIG_INPUT_PCSPKR)		+= pcspkr.o  obj-$(CONFIG_INPUT_POWERMATE)		+= powermate.o  obj-$(CONFIG_INPUT_PWM_BEEPER)		+= pwm-beeper.o +obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY)	+= pmic8xxx-pwrkey.o  obj-$(CONFIG_INPUT_RB532_BUTTON)	+= rb532_button.o  obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER)	+= rotary_encoder.o  obj-$(CONFIG_INPUT_SGI_BTNS)		+= sgi_btns.o diff --git a/drivers/input/misc/ad714x.c b/drivers/input/misc/ad714x.c index c431d09e401a..c3a62c42cd28 100644 --- a/drivers/input/misc/ad714x.c +++ b/drivers/input/misc/ad714x.c @@ -79,13 +79,7 @@ struct ad714x_slider_drv {  struct ad714x_wheel_drv {  	int abs_pos;  	int flt_pos; -	int pre_mean_value;  	int pre_highest_stage; -	int pre_mean_value_no_offset; -	int mean_value; -	int mean_value_no_offset; -	int pos_offset; -	int pos_ratio;  	int highest_stage;  	enum ad714x_device_state state;  	struct input_dev *input; @@ -158,10 +152,10 @@ static void ad714x_use_com_int(struct ad714x_chip *ad714x,  	unsigned short data;  	unsigned short mask; -	mask = ((1 << (end_stage + 1)) - 1) - (1 << start_stage); +	mask = ((1 << (end_stage + 1)) - 1) - ((1 << start_stage) - 1);  	ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data); -	data |= 1 << start_stage; +	data |= 1 << end_stage;  	ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data);  	ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data); @@ -175,10 +169,10 @@ static void ad714x_use_thr_int(struct ad714x_chip *ad714x,  	unsigned short data;  	unsigned short mask; -	mask = ((1 << (end_stage + 1)) - 1) - (1 << start_stage); +	mask = ((1 << (end_stage + 1)) - 1) - ((1 << start_stage) - 1);  	ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data); -	data &= ~(1 << start_stage); +	data &= ~(1 << end_stage);  	ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data);  	ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data); @@ -404,7 +398,6 @@ static void ad714x_slider_state_machine(struct ad714x_chip *ad714x, int idx)  				ad714x_slider_cal_highest_stage(ad714x, idx);  				ad714x_slider_cal_abs_pos(ad714x, idx);  				ad714x_slider_cal_flt_pos(ad714x, idx); -  				input_report_abs(sw->input, ABS_X, sw->flt_pos);  				input_report_key(sw->input, BTN_TOUCH, 1);  			} else { @@ -468,104 +461,41 @@ static void ad714x_wheel_cal_sensor_val(struct ad714x_chip *ad714x, int idx)  /*   * When the scroll wheel is activated, we compute the absolute position based   * on the sensor values. To calculate the position, we first determine the - * sensor that has the greatest response among the 8 sensors that constitutes - * the scrollwheel. Then we determined the 2 sensors on either sides of the + * sensor that has the greatest response among the sensors that constitutes + * the scrollwheel. Then we determined the sensors on either sides of the   * sensor with the highest response and we apply weights to these sensors. The - * result of this computation gives us the mean value which defined by the - * following formula: - * For i= second_before_highest_stage to i= second_after_highest_stage - *         v += Sensor response(i)*WEIGHT*(i+3) - *         w += Sensor response(i) - * Mean_Value=v/w - * pos_on_scrollwheel = (Mean_Value - position_offset) / position_ratio + * result of this computation gives us the mean value.   */ -#define WEIGHT_FACTOR 30 -/* This constant prevents the "PositionOffset" from reaching a big value */ -#define OFFSET_POSITION_CLAMP	120  static void ad714x_wheel_cal_abs_pos(struct ad714x_chip *ad714x, int idx)  {  	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];  	struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];  	int stage_num = hw->end_stage - hw->start_stage + 1; -	int second_before, first_before, highest, first_after, second_after; +	int first_before, highest, first_after;  	int a_param, b_param; -	/* Calculate Mean value */ - -	second_before = (sw->highest_stage + stage_num - 2) % stage_num;  	first_before = (sw->highest_stage + stage_num - 1) % stage_num;  	highest = sw->highest_stage;  	first_after = (sw->highest_stage + stage_num + 1) % stage_num; -	second_after = (sw->highest_stage + stage_num + 2) % stage_num; - -	if (((sw->highest_stage - hw->start_stage) > 1) && -	    ((hw->end_stage - sw->highest_stage) > 1)) { -		a_param = ad714x->sensor_val[second_before] * -			(second_before - hw->start_stage + 3) + -			ad714x->sensor_val[first_before] * -			(second_before - hw->start_stage + 3) + -			ad714x->sensor_val[highest] * -			(second_before - hw->start_stage + 3) + -			ad714x->sensor_val[first_after] * -			(first_after - hw->start_stage + 3) + -			ad714x->sensor_val[second_after] * -			(second_after - hw->start_stage + 3); -	} else { -		a_param = ad714x->sensor_val[second_before] * -			(second_before - hw->start_stage + 1) + -			ad714x->sensor_val[first_before] * -			(second_before - hw->start_stage + 2) + -			ad714x->sensor_val[highest] * -			(second_before - hw->start_stage + 3) + -			ad714x->sensor_val[first_after] * -			(first_after - hw->start_stage + 4) + -			ad714x->sensor_val[second_after] * -			(second_after - hw->start_stage + 5); -	} -	a_param *= WEIGHT_FACTOR; -	b_param = ad714x->sensor_val[second_before] + +	a_param = ad714x->sensor_val[highest] * +		(highest - hw->start_stage) + +		ad714x->sensor_val[first_before] * +		(highest - hw->start_stage - 1) + +		ad714x->sensor_val[first_after] * +		(highest - hw->start_stage + 1); +	b_param = ad714x->sensor_val[highest] +  		ad714x->sensor_val[first_before] + -		ad714x->sensor_val[highest] + -		ad714x->sensor_val[first_after] + -		ad714x->sensor_val[second_after]; - -	sw->pre_mean_value = sw->mean_value; -	sw->mean_value = a_param / b_param; - -	/* Calculate the offset */ - -	if ((sw->pre_highest_stage == hw->end_stage) && -			(sw->highest_stage == hw->start_stage)) -		sw->pos_offset = sw->mean_value; -	else if ((sw->pre_highest_stage == hw->start_stage) && -			(sw->highest_stage == hw->end_stage)) -		sw->pos_offset = sw->pre_mean_value; - -	if (sw->pos_offset > OFFSET_POSITION_CLAMP) -		sw->pos_offset = OFFSET_POSITION_CLAMP; - -	/* Calculate the mean value without the offset */ - -	sw->pre_mean_value_no_offset = sw->mean_value_no_offset; -	sw->mean_value_no_offset = sw->mean_value - sw->pos_offset; -	if (sw->mean_value_no_offset < 0) -		sw->mean_value_no_offset = 0; - -	/* Calculate ratio to scale down to NUMBER_OF_WANTED_POSITIONS */ - -	if ((sw->pre_highest_stage == hw->end_stage) && -			(sw->highest_stage == hw->start_stage)) -		sw->pos_ratio = (sw->pre_mean_value_no_offset * 100) / -			hw->max_coord; -	else if ((sw->pre_highest_stage == hw->start_stage) && -			(sw->highest_stage == hw->end_stage)) -		sw->pos_ratio = (sw->mean_value_no_offset * 100) / -			hw->max_coord; -	sw->abs_pos = (sw->mean_value_no_offset * 100) / sw->pos_ratio; +		ad714x->sensor_val[first_after]; + +	sw->abs_pos = ((hw->max_coord / (hw->end_stage - hw->start_stage)) * +			a_param) / b_param; +  	if (sw->abs_pos > hw->max_coord)  		sw->abs_pos = hw->max_coord; +	else if (sw->abs_pos < 0) +		sw->abs_pos = 0;  }  static void ad714x_wheel_cal_flt_pos(struct ad714x_chip *ad714x, int idx) @@ -639,9 +569,8 @@ static void ad714x_wheel_state_machine(struct ad714x_chip *ad714x, int idx)  				ad714x_wheel_cal_highest_stage(ad714x, idx);  				ad714x_wheel_cal_abs_pos(ad714x, idx);  				ad714x_wheel_cal_flt_pos(ad714x, idx); -  				input_report_abs(sw->input, ABS_WHEEL, -					sw->abs_pos); +					sw->flt_pos);  				input_report_key(sw->input, BTN_TOUCH, 1);  			} else {  				/* When the user lifts off the sensor, configure @@ -1149,6 +1078,8 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,  			input[alloc_idx]->id.bustype = bus_type;  			input[alloc_idx]->id.product = ad714x->product;  			input[alloc_idx]->id.version = ad714x->version; +			input[alloc_idx]->name = "ad714x_captouch_slider"; +			input[alloc_idx]->dev.parent = dev;  			error = input_register_device(input[alloc_idx]);  			if (error) @@ -1179,6 +1110,8 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,  			input[alloc_idx]->id.bustype = bus_type;  			input[alloc_idx]->id.product = ad714x->product;  			input[alloc_idx]->id.version = ad714x->version; +			input[alloc_idx]->name = "ad714x_captouch_wheel"; +			input[alloc_idx]->dev.parent = dev;  			error = input_register_device(input[alloc_idx]);  			if (error) @@ -1212,6 +1145,8 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,  			input[alloc_idx]->id.bustype = bus_type;  			input[alloc_idx]->id.product = ad714x->product;  			input[alloc_idx]->id.version = ad714x->version; +			input[alloc_idx]->name = "ad714x_captouch_pad"; +			input[alloc_idx]->dev.parent = dev;  			error = input_register_device(input[alloc_idx]);  			if (error) @@ -1240,6 +1175,8 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,  		input[alloc_idx]->id.bustype = bus_type;  		input[alloc_idx]->id.product = ad714x->product;  		input[alloc_idx]->id.version = ad714x->version; +		input[alloc_idx]->name = "ad714x_captouch_button"; +		input[alloc_idx]->dev.parent = dev;  		error = input_register_device(input[alloc_idx]);  		if (error) @@ -1249,7 +1186,9 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,  	}  	error = request_threaded_irq(ad714x->irq, NULL, ad714x_interrupt_thread, -			IRQF_TRIGGER_FALLING, "ad714x_captouch", ad714x); +				plat_data->irqflags ? +					plat_data->irqflags : IRQF_TRIGGER_FALLING, +				"ad714x_captouch", ad714x);  	if (error) {  		dev_err(dev, "can't allocate irq %d\n", ad714x->irq);  		goto err_unreg_dev; diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c index 9ccdb82d869a..1de58e8a1b71 100644 --- a/drivers/input/misc/ati_remote2.c +++ b/drivers/input/misc/ati_remote2.c @@ -737,14 +737,17 @@ static ssize_t ati_remote2_store_channel_mask(struct device *dev,  	mutex_lock(&ati_remote2_mutex); -	if (mask != ar2->channel_mask && !ati_remote2_setup(ar2, mask)) -		ar2->channel_mask = mask; +	if (mask != ar2->channel_mask) { +		r = ati_remote2_setup(ar2, mask); +		if (!r) +			ar2->channel_mask = mask; +	}  	mutex_unlock(&ati_remote2_mutex);  	usb_autopm_put_interface(ar2->intf[0]); -	return count; +	return r ? r : count;  }  static ssize_t ati_remote2_show_mode_mask(struct device *dev, diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c new file mode 100644 index 000000000000..97e07e786e41 --- /dev/null +++ b/drivers/input/misc/pmic8xxx-pwrkey.c @@ -0,0 +1,231 @@ +/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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/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/log2.h> + +#include <linux/mfd/pm8xxx/core.h> +#include <linux/input/pmic8xxx-pwrkey.h> + +#define PON_CNTL_1 0x1C +#define PON_CNTL_PULL_UP BIT(7) +#define PON_CNTL_TRIG_DELAY_MASK (0x7) + +/** + * struct pmic8xxx_pwrkey - pmic8xxx pwrkey information + * @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) +{ +	struct pmic8xxx_pwrkey *pwrkey = _pwrkey; + +	input_report_key(pwrkey->pwr, KEY_POWER, 1); +	input_sync(pwrkey->pwr); + +	return IRQ_HANDLED; +} + +static irqreturn_t pwrkey_release_irq(int irq, void *_pwrkey) +{ +	struct pmic8xxx_pwrkey *pwrkey = _pwrkey; + +	input_report_key(pwrkey->pwr, KEY_POWER, 0); +	input_sync(pwrkey->pwr); + +	return IRQ_HANDLED; +} + +#ifdef CONFIG_PM_SLEEP +static int pmic8xxx_pwrkey_suspend(struct device *dev) +{ +	struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev); + +	if (device_may_wakeup(dev)) +		enable_irq_wake(pwrkey->key_press_irq); + +	return 0; +} + +static int pmic8xxx_pwrkey_resume(struct device *dev) +{ +	struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev); + +	if (device_may_wakeup(dev)) +		disable_irq_wake(pwrkey->key_press_irq); + +	return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(pm8xxx_pwr_key_pm_ops, +		pmic8xxx_pwrkey_suspend, pmic8xxx_pwrkey_resume); + +static int __devinit pmic8xxx_pwrkey_probe(struct platform_device *pdev) +{ +	struct input_dev *pwr; +	int key_release_irq = platform_get_irq(pdev, 0); +	int key_press_irq = platform_get_irq(pdev, 1); +	int err; +	unsigned int delay; +	u8 pon_cntl; +	struct pmic8xxx_pwrkey *pwrkey; +	const struct pm8xxx_pwrkey_platform_data *pdata = mfd_get_data(pdev); + +	if (!pdata) { +		dev_err(&pdev->dev, "power key platform data not supplied\n"); +		return -EINVAL; +	} + +	if (pdata->kpd_trigger_delay_us > 62500) { +		dev_err(&pdev->dev, "invalid power key trigger delay\n"); +		return -EINVAL; +	} + +	pwrkey = kzalloc(sizeof(*pwrkey), GFP_KERNEL); +	if (!pwrkey) +		return -ENOMEM; + +	pwr = input_allocate_device(); +	if (!pwr) { +		dev_dbg(&pdev->dev, "Can't allocate power button\n"); +		err = -ENOMEM; +		goto free_pwrkey; +	} + +	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 = 1 + ilog2(delay); + +	err = pm8xxx_readb(pdev->dev.parent, 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; +	} + +	pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK; +	pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK); +	if (pdata->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); +	if (err < 0) { +		dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err); +		goto free_input_dev; +	} + +	err = input_register_device(pwr); +	if (err) { +		dev_dbg(&pdev->dev, "Can't register power key: %d\n", err); +		goto free_input_dev; +	} + +	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 = 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; +	} + +	device_init_wakeup(&pdev->dev, pdata->wakeup); + +	return 0; + +free_press_irq: +	free_irq(key_press_irq, NULL); +unreg_input_dev: +	platform_set_drvdata(pdev, NULL); +	input_unregister_device(pwr); +	pwr = NULL; +free_input_dev: +	input_free_device(pwr); +free_pwrkey: +	kfree(pwrkey); +	return err; +} + +static int __devexit 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); +	platform_set_drvdata(pdev, NULL); +	kfree(pwrkey); + +	return 0; +} + +static struct platform_driver pmic8xxx_pwrkey_driver = { +	.probe		= pmic8xxx_pwrkey_probe, +	.remove		= __devexit_p(pmic8xxx_pwrkey_remove), +	.driver		= { +		.name	= PM8XXX_PWRKEY_DEV_NAME, +		.owner	= THIS_MODULE, +		.pm	= &pm8xxx_pwr_key_pm_ops, +	}, +}; + +static int __init pmic8xxx_pwrkey_init(void) +{ +	return platform_driver_register(&pmic8xxx_pwrkey_driver); +} +module_init(pmic8xxx_pwrkey_init); + +static void __exit pmic8xxx_pwrkey_exit(void) +{ +	platform_driver_unregister(&pmic8xxx_pwrkey_driver); +} +module_exit(pmic8xxx_pwrkey_exit); + +MODULE_ALIAS("platform:pmic8xxx_pwrkey"); +MODULE_DESCRIPTION("PMIC8XXX Power Key driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Trilok Soni <[email protected]>"); diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index 7e64d01da2be..2c8b84dd9dac 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -2,6 +2,7 @@   * rotary_encoder.c   *   * (c) 2009 Daniel Mack <[email protected]> + * Copyright (C) 2011 Johan Hovold <[email protected]>   *   * state machine code inspired by code from Tim Ruetz   * @@ -38,52 +39,66 @@ struct rotary_encoder {  	bool armed;  	unsigned char dir;	/* 0 - clockwise, 1 - CCW */ + +	char last_stable;  }; -static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) +static int rotary_encoder_get_state(struct rotary_encoder_platform_data *pdata)  { -	struct rotary_encoder *encoder = dev_id; -	struct rotary_encoder_platform_data *pdata = encoder->pdata;  	int a = !!gpio_get_value(pdata->gpio_a);  	int b = !!gpio_get_value(pdata->gpio_b); -	int state;  	a ^= pdata->inverted_a;  	b ^= pdata->inverted_b; -	state = (a << 1) | b; -	switch (state) { +	return ((a << 1) | b); +} -	case 0x0: -		if (!encoder->armed) -			break; +static void rotary_encoder_report_event(struct rotary_encoder *encoder) +{ +	struct rotary_encoder_platform_data *pdata = encoder->pdata; -		if (pdata->relative_axis) { -			input_report_rel(encoder->input, pdata->axis, -					 encoder->dir ? -1 : 1); -		} else { -			unsigned int pos = encoder->pos; - -			if (encoder->dir) { -				/* turning counter-clockwise */ -				if (pdata->rollover) -					pos += pdata->steps; -				if (pos) -					pos--; -			} else { -				/* turning clockwise */ -				if (pdata->rollover || pos < pdata->steps) -					pos++; -			} +	if (pdata->relative_axis) { +		input_report_rel(encoder->input, +				 pdata->axis, encoder->dir ? -1 : 1); +	} else { +		unsigned int pos = encoder->pos; + +		if (encoder->dir) { +			/* turning counter-clockwise */  			if (pdata->rollover) -				pos %= pdata->steps; -			encoder->pos = pos; -			input_report_abs(encoder->input, pdata->axis, -					 encoder->pos); +				pos += pdata->steps; +			if (pos) +				pos--; +		} else { +			/* turning clockwise */ +			if (pdata->rollover || pos < pdata->steps) +				pos++;  		} -		input_sync(encoder->input); -		encoder->armed = false; +		if (pdata->rollover) +			pos %= pdata->steps; + +		encoder->pos = pos; +		input_report_abs(encoder->input, pdata->axis, encoder->pos); +	} + +	input_sync(encoder->input); +} + +static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) +{ +	struct rotary_encoder *encoder = dev_id; +	int state; + +	state = rotary_encoder_get_state(encoder->pdata); + +	switch (state) { +	case 0x0: +		if (encoder->armed) { +			rotary_encoder_report_event(encoder); +			encoder->armed = false; +		}  		break;  	case 0x1: @@ -100,11 +115,37 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)  	return IRQ_HANDLED;  } +static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id) +{ +	struct rotary_encoder *encoder = dev_id; +	int state; + +	state = rotary_encoder_get_state(encoder->pdata); + +	switch (state) { +	case 0x00: +	case 0x03: +		if (state != encoder->last_stable) { +			rotary_encoder_report_event(encoder); +			encoder->last_stable = state; +		} +		break; + +	case 0x01: +	case 0x02: +		encoder->dir = (encoder->last_stable + state) & 0x01; +		break; +	} + +	return IRQ_HANDLED; +} +  static int __devinit rotary_encoder_probe(struct platform_device *pdev)  {  	struct rotary_encoder_platform_data *pdata = pdev->dev.platform_data;  	struct rotary_encoder *encoder;  	struct input_dev *input; +	irq_handler_t handler;  	int err;  	if (!pdata) { @@ -175,7 +216,14 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)  	}  	/* request the IRQs */ -	err = request_irq(encoder->irq_a, &rotary_encoder_irq, +	if (pdata->half_period) { +		handler = &rotary_encoder_half_period_irq; +		encoder->last_stable = rotary_encoder_get_state(pdata); +	} else { +		handler = &rotary_encoder_irq; +	} + +	err = request_irq(encoder->irq_a, handler,  			  IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,  			  DRV_NAME, encoder);  	if (err) { @@ -184,7 +232,7 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)  		goto exit_free_gpio_b;  	} -	err = request_irq(encoder->irq_b, &rotary_encoder_irq, +	err = request_irq(encoder->irq_b, handler,  			  IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,  			  DRV_NAME, encoder);  	if (err) { @@ -252,6 +300,5 @@ module_exit(rotary_encoder_exit);  MODULE_ALIAS("platform:" DRV_NAME);  MODULE_DESCRIPTION("GPIO rotary encoder driver"); -MODULE_AUTHOR("Daniel Mack <[email protected]>"); +MODULE_AUTHOR("Daniel Mack <[email protected]>, Johan Hovold");  MODULE_LICENSE("GPL v2"); - diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c index f16972bddca4..38e4b507b94c 100644 --- a/drivers/input/misc/twl4030-pwrbutton.c +++ b/drivers/input/misc/twl4030-pwrbutton.c @@ -89,7 +89,7 @@ static int __init twl4030_pwrbutton_probe(struct platform_device *pdev)  	return 0;  free_irq: -	free_irq(irq, NULL); +	free_irq(irq, pwr);  free_input_dev:  	input_free_device(pwr);  	return err; diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c index 6a11694e3fc7..014dd4ad0d4f 100644 --- a/drivers/input/misc/twl4030-vibra.c +++ b/drivers/input/misc/twl4030-vibra.c @@ -29,7 +29,6 @@  #include <linux/workqueue.h>  #include <linux/i2c/twl.h>  #include <linux/mfd/twl4030-codec.h> -#include <linux/mfd/core.h>  #include <linux/input.h>  #include <linux/slab.h> @@ -197,7 +196,7 @@ static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops,  static int __devinit twl4030_vibra_probe(struct platform_device *pdev)  { -	struct twl4030_codec_vibra_data *pdata = mfd_get_data(pdev); +	struct twl4030_codec_vibra_data *pdata = pdev->dev.platform_data;  	struct vibra_info *info;  	int ret; diff --git a/drivers/input/mouse/atarimouse.c b/drivers/input/mouse/atarimouse.c index adf45b3040e9..5c4a692bf73a 100644 --- a/drivers/input/mouse/atarimouse.c +++ b/drivers/input/mouse/atarimouse.c @@ -77,15 +77,15 @@ static void atamouse_interrupt(char *buf)  #endif  	/* only relative events get here */ -	dx =  buf[1]; -	dy = -buf[2]; +	dx = buf[1]; +	dy = buf[2];  	input_report_rel(atamouse_dev, REL_X, dx);  	input_report_rel(atamouse_dev, REL_Y, dy); -	input_report_key(atamouse_dev, BTN_LEFT,   buttons & 0x1); +	input_report_key(atamouse_dev, BTN_LEFT,   buttons & 0x4);  	input_report_key(atamouse_dev, BTN_MIDDLE, buttons & 0x2); -	input_report_key(atamouse_dev, BTN_RIGHT,  buttons & 0x4); +	input_report_key(atamouse_dev, BTN_RIGHT,  buttons & 0x1);  	input_sync(atamouse_dev); @@ -108,7 +108,7 @@ static int atamouse_open(struct input_dev *dev)  static void atamouse_close(struct input_dev *dev)  {  	ikbd_mouse_disable(); -	atari_mouse_interrupt_hook = NULL; +	atari_input_mouse_interrupt_hook = NULL;  }  static int __init atamouse_init(void) @@ -118,8 +118,9 @@ static int __init atamouse_init(void)  	if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP))  		return -ENODEV; -	if (!atari_keyb_init()) -		return -ENODEV; +	error = atari_keyb_init(); +	if (error) +		return error;  	atamouse_dev = input_allocate_device();  	if (!atamouse_dev) diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 04d9bf320a4f..32503565faf9 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -16,6 +16,7 @@  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/input.h> +#include <linux/input/mt.h>  #include <linux/serio.h>  #include <linux/libps2.h>  #include "psmouse.h" @@ -242,15 +243,37 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse)  	input_sync(dev);  } +static void elantech_set_slot(struct input_dev *dev, int slot, bool active, +			      unsigned int x, unsigned int y) +{ +	input_mt_slot(dev, slot); +	input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); +	if (active) { +		input_report_abs(dev, ABS_MT_POSITION_X, x); +		input_report_abs(dev, ABS_MT_POSITION_Y, y); +	} +} + +/* x1 < x2 and y1 < y2 when two fingers, x = y = 0 when not pressed */ +static void elantech_report_semi_mt_data(struct input_dev *dev, +					 unsigned int num_fingers, +					 unsigned int x1, unsigned int y1, +					 unsigned int x2, unsigned int y2) +{ +	elantech_set_slot(dev, 0, num_fingers != 0, x1, y1); +	elantech_set_slot(dev, 1, num_fingers == 2, x2, y2); +} +  /*   * Interpret complete data packets and report absolute mode input events for   * hardware version 2. (6 byte packets)   */  static void elantech_report_absolute_v2(struct psmouse *psmouse)  { +	struct elantech_data *etd = psmouse->private;  	struct input_dev *dev = psmouse->dev;  	unsigned char *packet = psmouse->packet; -	int fingers, x1, y1, x2, y2; +	unsigned int fingers, x1 = 0, y1 = 0, x2 = 0, y2 = 0, width = 0, pres = 0;  	/* byte 0: n1  n0   .   .   .   .   R   L */  	fingers = (packet[0] & 0xc0) >> 6; @@ -270,14 +293,18 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)  		 * byte 1:  .   .   .   .   .  x10 x9  x8  		 * byte 2: x7  x6  x5  x4  x4  x2  x1  x0  		 */ -		input_report_abs(dev, ABS_X, -			((packet[1] & 0x07) << 8) | packet[2]); +		x1 = ((packet[1] & 0x07) << 8) | packet[2];  		/*  		 * byte 4:  .   .   .   .   .   .  y9  y8  		 * byte 5: y7  y6  y5  y4  y3  y2  y1  y0  		 */ -		input_report_abs(dev, ABS_Y, -			ETP_YMAX_V2 - (((packet[4] & 0x03) << 8) | packet[5])); +		y1 = ETP_YMAX_V2 - (((packet[4] & 0x03) << 8) | packet[5]); + +		input_report_abs(dev, ABS_X, x1); +		input_report_abs(dev, ABS_Y, y1); + +		pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4); +		width = ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4);  		break;  	case 2: @@ -303,23 +330,24 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)  		 */  		input_report_abs(dev, ABS_X, x1 << 2);  		input_report_abs(dev, ABS_Y, y1 << 2); -		/* -		 * For compatibility with the proprietary X Elantech driver -		 * report both coordinates as hat coordinates -		 */ -		input_report_abs(dev, ABS_HAT0X, x1); -		input_report_abs(dev, ABS_HAT0Y, y1); -		input_report_abs(dev, ABS_HAT1X, x2); -		input_report_abs(dev, ABS_HAT1Y, y2); + +		/* Unknown so just report sensible values */ +		pres = 127; +		width = 7;  		break;  	} +	elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);  	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_TOOL_QUADTAP, fingers == 4);  	input_report_key(dev, BTN_LEFT, packet[0] & 0x01);  	input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); +	if (etd->reports_pressure) { +		input_report_abs(dev, ABS_PRESSURE, pres); +		input_report_abs(dev, ABS_TOOL_WIDTH, width); +	}  	input_sync(dev);  } @@ -478,10 +506,16 @@ static void elantech_set_input_params(struct psmouse *psmouse)  		__set_bit(BTN_TOOL_QUADTAP, dev->keybit);  		input_set_abs_params(dev, ABS_X, ETP_XMIN_V2, ETP_XMAX_V2, 0, 0);  		input_set_abs_params(dev, ABS_Y, ETP_YMIN_V2, ETP_YMAX_V2, 0, 0); -		input_set_abs_params(dev, ABS_HAT0X, ETP_2FT_XMIN, ETP_2FT_XMAX, 0, 0); -		input_set_abs_params(dev, ABS_HAT0Y, ETP_2FT_YMIN, ETP_2FT_YMAX, 0, 0); -		input_set_abs_params(dev, ABS_HAT1X, ETP_2FT_XMIN, ETP_2FT_XMAX, 0, 0); -		input_set_abs_params(dev, ABS_HAT1Y, ETP_2FT_YMIN, ETP_2FT_YMAX, 0, 0); +		if (etd->reports_pressure) { +			input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2, +					     ETP_PMAX_V2, 0, 0); +			input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, +					     ETP_WMAX_V2, 0, 0); +		} +		__set_bit(INPUT_PROP_SEMI_MT, dev->propbit); +		input_mt_init_slots(dev, 2); +		input_set_abs_params(dev, ABS_MT_POSITION_X, ETP_XMIN_V2, ETP_XMAX_V2, 0, 0); +		input_set_abs_params(dev, ABS_MT_POSITION_Y, ETP_YMIN_V2, ETP_YMAX_V2, 0, 0);  		break;  	}  } @@ -725,6 +759,10 @@ int elantech_init(struct psmouse *psmouse)  		etd->debug = 1;  		/* Don't know how to do parity checking for version 2 */  		etd->paritycheck = 0; + +		if (etd->fw_version >= 0x020800) +			etd->reports_pressure = true; +  	} else {  		etd->hw_version = 1;  		etd->paritycheck = 1; diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h index aa4aac5d2198..fabb2b99615c 100644 --- a/drivers/input/mouse/elantech.h +++ b/drivers/input/mouse/elantech.h @@ -77,6 +77,11 @@  #define ETP_YMIN_V2			(   0 + ETP_EDGE_FUZZ_V2)  #define ETP_YMAX_V2			( 768 - ETP_EDGE_FUZZ_V2) +#define ETP_PMIN_V2			0 +#define ETP_PMAX_V2			255 +#define ETP_WMIN_V2			0 +#define ETP_WMAX_V2			15 +  /*   * For two finger touches the coordinate of each finger gets reported   * separately but with reduced resolution. @@ -102,6 +107,7 @@ struct elantech_data {  	unsigned char capabilities;  	bool paritycheck;  	bool jumpy_cursor; +	bool reports_pressure;  	unsigned char hw_version;  	unsigned int fw_version;  	unsigned int single_finger_reports; diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 7630273e9474..257e033986e4 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -508,7 +508,6 @@ static void mousedev_attach_client(struct mousedev *mousedev,  	spin_lock(&mousedev->client_lock);  	list_add_tail_rcu(&client->node, &mousedev->client_list);  	spin_unlock(&mousedev->client_lock); -	synchronize_rcu();  }  static void mousedev_detach_client(struct mousedev *mousedev, diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 8755f5f3ad37..f3698967edf6 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -120,17 +120,21 @@ static void serport_ldisc_close(struct tty_struct *tty)   * 'interrupt' routine.   */ -static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) +static unsigned int serport_ldisc_receive(struct tty_struct *tty, +		const unsigned char *cp, char *fp, int count)  {  	struct serport *serport = (struct serport*) tty->disc_data;  	unsigned long flags;  	unsigned int ch_flags; +	int ret = 0;  	int i;  	spin_lock_irqsave(&serport->lock, flags); -	if (!test_bit(SERPORT_ACTIVE, &serport->flags)) +	if (!test_bit(SERPORT_ACTIVE, &serport->flags)) { +		ret = -EINVAL;  		goto out; +	}  	for (i = 0; i < count; i++) {  		switch (fp[i]) { @@ -152,6 +156,8 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c  out:  	spin_unlock_irqrestore(&serport->lock, flags); + +	return ret == 0 ? count : ret;  }  /* diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 434fd800cd24..cabd9e54863f 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -248,6 +248,18 @@ config TOUCHSCREEN_LPC32XX  	  To compile this driver as a module, choose M here: the  	  module will be called lpc32xx_ts. +config TOUCHSCREEN_MAX11801 +	tristate "MAX11801 based touchscreens" +	depends on I2C +	help +	  Say Y here if you have a MAX11801 based touchscreen +	  controller. + +	  If unsure, say N. + +	  To compile this driver as a module, choose M here: the +	  module will be called max11801_ts. +  config TOUCHSCREEN_MCS5000  	tristate "MELFAS MCS-5000 touchscreen"  	depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index ca94098d4c92..282d6f76ae26 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_TOUCHSCREEN_FUJITSU)	+= fujitsu_ts.o  obj-$(CONFIG_TOUCHSCREEN_INEXIO)	+= inexio.o  obj-$(CONFIG_TOUCHSCREEN_INTEL_MID)	+= intel-mid-touch.o  obj-$(CONFIG_TOUCHSCREEN_LPC32XX)	+= lpc32xx_ts.o +obj-$(CONFIG_TOUCHSCREEN_MAX11801)	+= max11801_ts.o  obj-$(CONFIG_TOUCHSCREEN_MC13783)	+= mc13783_ts.o  obj-$(CONFIG_TOUCHSCREEN_MCS5000)	+= mcs5000_ts.o  obj-$(CONFIG_TOUCHSCREEN_MIGOR)		+= migor_ts.o diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 1de1c19dad30..5196861b86ef 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -109,6 +109,7 @@ struct ads7846 {  	u16			pressure_max;  	bool			swap_xy; +	bool			use_internal;  	struct ads7846_packet	*packet; @@ -307,7 +308,6 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)  	struct ads7846 *ts = dev_get_drvdata(dev);  	struct ser_req *req;  	int status; -	int use_internal;  	req = kzalloc(sizeof *req, GFP_KERNEL);  	if (!req) @@ -315,11 +315,8 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)  	spi_message_init(&req->msg); -	/* FIXME boards with ads7846 might use external vref instead ... */ -	use_internal = (ts->model == 7846); -  	/* maybe turn on internal vREF, and let it settle */ -	if (use_internal) { +	if (ts->use_internal) {  		req->ref_on = REF_ON;  		req->xfer[0].tx_buf = &req->ref_on;  		req->xfer[0].len = 1; @@ -331,8 +328,14 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)  		/* for 1uF, settle for 800 usec; no cap, 100 usec.  */  		req->xfer[1].delay_usecs = ts->vref_delay_usecs;  		spi_message_add_tail(&req->xfer[1], &req->msg); + +		/* Enable reference voltage */ +		command |= ADS_PD10_REF_ON;  	} +	/* Enable ADC in every case */ +	command |= ADS_PD10_ADC_ON; +  	/* take sample */  	req->command = (u8) command;  	req->xfer[2].tx_buf = &req->command; @@ -416,7 +419,7 @@ 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, \ -			READ_12BIT_SER(var) | ADS_PD10_ALL_ON); \ +			READ_12BIT_SER(var)); \  	if (v < 0) \  		return v; \  	return sprintf(buf, "%u\n", adjust(ts, v)); \ @@ -509,6 +512,7 @@ static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)  		if (!ts->vref_mv) {  			dev_dbg(&spi->dev, "assuming 2.5V internal vREF\n");  			ts->vref_mv = 2500; +			ts->use_internal = true;  		}  		break;  	case 7845: @@ -969,6 +973,13 @@ static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads784  				pdata->gpio_pendown);  			return err;  		} +		err = gpio_direction_input(pdata->gpio_pendown); +		if (err) { +			dev_err(&spi->dev, "failed to setup pendown GPIO%d\n", +				pdata->gpio_pendown); +			gpio_free(pdata->gpio_pendown); +			return err; +		}  		ts->gpio_pendown = pdata->gpio_pendown; @@ -1340,8 +1351,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)  	if (ts->model == 7845)  		ads7845_read12_ser(&spi->dev, PWRDOWN);  	else -		(void) ads7846_read12_ser(&spi->dev, -				READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON); +		(void) ads7846_read12_ser(&spi->dev, READ_12BIT_SER(vaux));  	err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group);  	if (err) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 4012436633b1..1e61387c73ca 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -17,7 +17,7 @@  #include <linux/firmware.h>  #include <linux/i2c.h>  #include <linux/i2c/atmel_mxt_ts.h> -#include <linux/input.h> +#include <linux/input/mt.h>  #include <linux/interrupt.h>  #include <linux/slab.h> @@ -196,9 +196,12 @@  #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) +  /* Touchscreen absolute values */ -#define MXT_MAX_XC		0x3ff -#define MXT_MAX_YC		0x3ff  #define MXT_MAX_AREA		0xff  #define MXT_MAX_FINGER		10 @@ -246,6 +249,8 @@ struct mxt_data {  	struct mxt_info info;  	struct mxt_finger finger[MXT_MAX_FINGER];  	unsigned int irq; +	unsigned int max_x; +	unsigned int max_y;  };  static bool mxt_object_readable(unsigned int type) @@ -499,19 +504,21 @@ static void mxt_input_report(struct mxt_data *data, int single_id)  		if (!finger[id].status)  			continue; -		input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, -				finger[id].status != MXT_RELEASE ? -				finger[id].area : 0); -		input_report_abs(input_dev, ABS_MT_POSITION_X, -				finger[id].x); -		input_report_abs(input_dev, ABS_MT_POSITION_Y, -				finger[id].y); -		input_mt_sync(input_dev); +		input_mt_slot(input_dev, id); +		input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, +				finger[id].status != MXT_RELEASE); -		if (finger[id].status == MXT_RELEASE) -			finger[id].status = 0; -		else +		if (finger[id].status != MXT_RELEASE) {  			finger_num++; +			input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, +					finger[id].area); +			input_report_abs(input_dev, ABS_MT_POSITION_X, +					finger[id].x); +			input_report_abs(input_dev, ABS_MT_POSITION_Y, +					finger[id].y); +		} else { +			finger[id].status = 0; +		}  	}  	input_report_key(input_dev, BTN_TOUCH, finger_num > 0); @@ -549,8 +556,13 @@ static void mxt_input_touchevent(struct mxt_data *data,  	if (!(status & (MXT_PRESS | MXT_MOVE)))  		return; -	x = (message->message[1] << 2) | ((message->message[3] & ~0x3f) >> 6); -	y = (message->message[2] << 2) | ((message->message[3] & ~0xf3) >> 2); +	x = (message->message[1] << 4) | ((message->message[3] >> 4) & 0xf); +	y = (message->message[2] << 4) | ((message->message[3] & 0xf)); +	if (data->max_x < 1024) +		x = x >> 2; +	if (data->max_y < 1024) +		y = y >> 2; +  	area = message->message[4];  	dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id, @@ -804,10 +816,6 @@ static int mxt_initialize(struct mxt_data *data)  	if (error)  		return error; -	error = mxt_make_highchg(data); -	if (error) -		return error; -  	mxt_handle_pdata(data);  	/* Backup to memory */ @@ -845,6 +853,20 @@ static int mxt_initialize(struct mxt_data *data)  	return 0;  } +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; +	} +} +  static ssize_t mxt_object_show(struct device *dev,  				    struct device_attribute *attr, char *buf)  { @@ -981,6 +1003,10 @@ static ssize_t mxt_update_fw_store(struct device *dev,  	enable_irq(data->irq); +	error = mxt_make_highchg(data); +	if (error) +		return error; +  	return count;  } @@ -1052,31 +1078,33 @@ static int __devinit mxt_probe(struct i2c_client *client,  	input_dev->open = mxt_input_open;  	input_dev->close = mxt_input_close; +	data->client = client; +	data->input_dev = input_dev; +	data->pdata = pdata; +	data->irq = client->irq; + +	mxt_calc_resolution(data); +  	__set_bit(EV_ABS, input_dev->evbit);  	__set_bit(EV_KEY, input_dev->evbit);  	__set_bit(BTN_TOUCH, input_dev->keybit);  	/* For single touch */  	input_set_abs_params(input_dev, ABS_X, -			     0, MXT_MAX_XC, 0, 0); +			     0, data->max_x, 0, 0);  	input_set_abs_params(input_dev, ABS_Y, -			     0, MXT_MAX_YC, 0, 0); +			     0, data->max_y, 0, 0);  	/* For multi touch */ +	input_mt_init_slots(input_dev, MXT_MAX_FINGER);  	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,  			     0, MXT_MAX_AREA, 0, 0);  	input_set_abs_params(input_dev, ABS_MT_POSITION_X, -			     0, MXT_MAX_XC, 0, 0); +			     0, data->max_x, 0, 0);  	input_set_abs_params(input_dev, ABS_MT_POSITION_Y, -			     0, MXT_MAX_YC, 0, 0); +			     0, data->max_y, 0, 0);  	input_set_drvdata(input_dev, data); - -	data->client = client; -	data->input_dev = input_dev; -	data->pdata = pdata; -	data->irq = client->irq; -  	i2c_set_clientdata(client, data);  	error = mxt_initialize(data); @@ -1090,6 +1118,10 @@ static int __devinit mxt_probe(struct i2c_client *client,  		goto err_free_object;  	} +	error = mxt_make_highchg(data); +	if (error) +		goto err_free_irq; +  	error = input_register_device(input_dev);  	if (error)  		goto err_free_irq; diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c index 3d9b5166ebe9..432c69be6ac6 100644 --- a/drivers/input/touchscreen/atmel_tsadcc.c +++ b/drivers/input/touchscreen/atmel_tsadcc.c @@ -317,7 +317,7 @@ err_unmap_regs:  err_release_mem:  	release_mem_region(res->start, resource_size(res));  err_free_dev: -	input_free_device(ts_dev->input); +	input_free_device(input_dev);  err_free_mem:  	kfree(ts_dev);  	return err; diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c index 45f93d0f5592..211811ae5525 100644 --- a/drivers/input/touchscreen/h3600_ts_input.c +++ b/drivers/input/touchscreen/h3600_ts_input.c @@ -396,14 +396,14 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)  	set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);  	if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler, -			IRQF_SHARED | IRQF_DISABLED, "h3600_action", &ts->dev)) { +			IRQF_SHARED | IRQF_DISABLED, "h3600_action", ts->dev)) {  		printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");  		err = -EBUSY;  		goto fail1;  	}  	if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler, -			IRQF_SHARED | IRQF_DISABLED, "h3600_suspend", &ts->dev)) { +			IRQF_SHARED | IRQF_DISABLED, "h3600_suspend", ts->dev)) {  		printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n");  		err = -EBUSY;  		goto fail2; @@ -439,8 +439,8 @@ static void h3600ts_disconnect(struct serio *serio)  {  	struct h3600_dev *ts = serio_get_drvdata(serio); -	free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev); -	free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, &ts->dev); +	free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts->dev); +	free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts->dev);  	input_get_device(ts->dev);  	input_unregister_device(ts->dev);  	serio_close(serio); diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c new file mode 100644 index 000000000000..4f2713d92791 --- /dev/null +++ b/drivers/input/touchscreen/max11801_ts.c @@ -0,0 +1,272 @@ +/* + * Driver for MAXI MAX11801 - A Resistive touch screen controller with + * i2c interface + * + * Copyright (C) 2011 Freescale Semiconductor, Inc. + * Author: Zhang Jiejing <[email protected]> + * + * Based on mcs5000_ts.c + * + * 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. + */ + +/* + * This driver aims to support the series of MAXI touch chips max11801 + * through max11803. The main difference between these 4 chips can be + * found in the table below: + * ----------------------------------------------------- + * | CHIP     |  AUTO MODE SUPPORT(FIFO) | INTERFACE    | + * |----------------------------------------------------| + * | max11800 |  YES                     |   SPI        | + * | max11801 |  YES                     |   I2C        | + * | max11802 |  NO                      |   SPI        | + * | max11803 |  NO                      |   I2C        | + * ------------------------------------------------------ + * + * Currently, this driver only supports max11801. + * + * Data Sheet: + * http://www.maxim-ic.com/datasheet/index.mvp/id/5943 + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/input.h> +#include <linux/slab.h> +#include <linux/bitops.h> + +/* Register Address define */ +#define GENERNAL_STATUS_REG		0x00 +#define GENERNAL_CONF_REG		0x01 +#define MESURE_RES_CONF_REG		0x02 +#define MESURE_AVER_CONF_REG		0x03 +#define ADC_SAMPLE_TIME_CONF_REG	0x04 +#define PANEL_SETUPTIME_CONF_REG	0x05 +#define DELAY_CONVERSION_CONF_REG	0x06 +#define TOUCH_DETECT_PULLUP_CONF_REG	0x07 +#define AUTO_MODE_TIME_CONF_REG		0x08 /* only for max11800/max11801 */ +#define APERTURE_CONF_REG		0x09 /* only for max11800/max11801 */ +#define AUX_MESURE_CONF_REG		0x0a +#define OP_MODE_CONF_REG		0x0b + +/* FIFO is found only in max11800 and max11801 */ +#define FIFO_RD_CMD			(0x50 << 1) +#define MAX11801_FIFO_INT		(1 << 2) +#define MAX11801_FIFO_OVERFLOW		(1 << 3) + +#define XY_BUFSIZE			4 +#define XY_BUF_OFFSET			4 + +#define MAX11801_MAX_X			0xfff +#define MAX11801_MAX_Y			0xfff + +#define MEASURE_TAG_OFFSET		2 +#define MEASURE_TAG_MASK		(3 << MEASURE_TAG_OFFSET) +#define EVENT_TAG_OFFSET		0 +#define EVENT_TAG_MASK			(3 << EVENT_TAG_OFFSET) +#define MEASURE_X_TAG			(0 << MEASURE_TAG_OFFSET) +#define MEASURE_Y_TAG			(1 << MEASURE_TAG_OFFSET) + +/* These are the state of touch event state machine */ +enum { +	EVENT_INIT, +	EVENT_MIDDLE, +	EVENT_RELEASE, +	EVENT_FIFO_END +}; + +struct max11801_data { +	struct i2c_client		*client; +	struct input_dev		*input_dev; +}; + +static u8 read_register(struct i2c_client *client, int addr) +{ +	/* XXX: The chip ignores LSB of register address */ +	return i2c_smbus_read_byte_data(client, addr << 1); +} + +static int max11801_write_reg(struct i2c_client *client, int addr, int data) +{ +	/* XXX: The chip ignores LSB of register address */ +	return i2c_smbus_write_byte_data(client, addr << 1, data); +} + +static irqreturn_t max11801_ts_interrupt(int irq, void *dev_id) +{ +	struct max11801_data *data = dev_id; +	struct i2c_client *client = data->client; +	int status, i, ret; +	u8 buf[XY_BUFSIZE]; +	int x = -1; +	int y = -1; + +	status = read_register(data->client, GENERNAL_STATUS_REG); + +	if (status & (MAX11801_FIFO_INT | MAX11801_FIFO_OVERFLOW)) { +		status = read_register(data->client, GENERNAL_STATUS_REG); + +		ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_CMD, +						    XY_BUFSIZE, buf); + +		/* +		 * We should get 4 bytes buffer that contains X,Y +		 * and event tag +		 */ +		if (ret < XY_BUFSIZE) +			goto out; + +		for (i = 0; i < XY_BUFSIZE; i += XY_BUFSIZE / 2) { +			if ((buf[i + 1] & MEASURE_TAG_MASK) == MEASURE_X_TAG) +				x = (buf[i] << XY_BUF_OFFSET) + +				    (buf[i + 1] >> XY_BUF_OFFSET); +			else if ((buf[i + 1] & MEASURE_TAG_MASK) == MEASURE_Y_TAG) +				y = (buf[i] << XY_BUF_OFFSET) + +				    (buf[i + 1] >> XY_BUF_OFFSET); +		} + +		if ((buf[1] & EVENT_TAG_MASK) != (buf[3] & EVENT_TAG_MASK)) +			goto out; + +		switch (buf[1] & EVENT_TAG_MASK) { +		case EVENT_INIT: +			/* fall through */ +		case EVENT_MIDDLE: +			input_report_abs(data->input_dev, ABS_X, x); +			input_report_abs(data->input_dev, ABS_Y, y); +			input_event(data->input_dev, EV_KEY, BTN_TOUCH, 1); +			input_sync(data->input_dev); +			break; + +		case EVENT_RELEASE: +			input_event(data->input_dev, EV_KEY, BTN_TOUCH, 0); +			input_sync(data->input_dev); +			break; + +		case EVENT_FIFO_END: +			break; +		} +	} +out: +	return IRQ_HANDLED; +} + +static void __devinit max11801_ts_phy_init(struct max11801_data *data) +{ +	struct i2c_client *client = data->client; + +	/* Average X,Y, take 16 samples, average eight media sample */ +	max11801_write_reg(client, MESURE_AVER_CONF_REG, 0xff); +	/* X,Y panel setup time set to 20us */ +	max11801_write_reg(client, PANEL_SETUPTIME_CONF_REG, 0x11); +	/* Rough pullup time (2uS), Fine pullup time (10us)  */ +	max11801_write_reg(client, TOUCH_DETECT_PULLUP_CONF_REG, 0x10); +	/* Auto mode init period = 5ms , scan period = 5ms*/ +	max11801_write_reg(client, AUTO_MODE_TIME_CONF_REG, 0xaa); +	/* Aperture X,Y set to +- 4LSB */ +	max11801_write_reg(client, APERTURE_CONF_REG, 0x33); +	/* Enable Power, enable Automode, enable Aperture, enable Average X,Y */ +	max11801_write_reg(client, OP_MODE_CONF_REG, 0x36); +} + +static int __devinit max11801_ts_probe(struct i2c_client *client, +				       const struct i2c_device_id *id) +{ +	struct max11801_data *data; +	struct input_dev *input_dev; +	int error; + +	data = kzalloc(sizeof(struct max11801_data), GFP_KERNEL); +	input_dev = input_allocate_device(); +	if (!data || !input_dev) { +		dev_err(&client->dev, "Failed to allocate memory\n"); +		error = -ENOMEM; +		goto err_free_mem; +	} + +	data->client = client; +	data->input_dev = input_dev; + +	input_dev->name = "max11801_ts"; +	input_dev->id.bustype = BUS_I2C; +	input_dev->dev.parent = &client->dev; + +	__set_bit(EV_ABS, input_dev->evbit); +	__set_bit(EV_KEY, input_dev->evbit); +	__set_bit(BTN_TOUCH, input_dev->keybit); +	input_set_abs_params(input_dev, ABS_X, 0, MAX11801_MAX_X, 0, 0); +	input_set_abs_params(input_dev, ABS_Y, 0, MAX11801_MAX_Y, 0, 0); +	input_set_drvdata(input_dev, data); + +	max11801_ts_phy_init(data); + +	error = request_threaded_irq(client->irq, NULL, max11801_ts_interrupt, +				     IRQF_TRIGGER_LOW | IRQF_ONESHOT, +				     "max11801_ts", data); +	if (error) { +		dev_err(&client->dev, "Failed to register interrupt\n"); +		goto err_free_mem; +	} + +	error = input_register_device(data->input_dev); +	if (error) +		goto err_free_irq; + +	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 error; +} + +static __devexit int max11801_ts_remove(struct i2c_client *client) +{ +	struct max11801_data *data = i2c_get_clientdata(client); + +	free_irq(client->irq, data); +	input_unregister_device(data->input_dev); +	kfree(data); + +	return 0; +} + +static const struct i2c_device_id max11801_ts_id[] = { +	{"max11801", 0}, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, max11801_ts_id); + +static struct i2c_driver max11801_ts_driver = { +	.driver = { +		.name	= "max11801_ts", +		.owner	= THIS_MODULE, +	}, +	.id_table	= max11801_ts_id, +	.probe		= max11801_ts_probe, +	.remove		= __devexit_p(max11801_ts_remove), +}; + +static int __init max11801_ts_init(void) +{ +	return i2c_add_driver(&max11801_ts_driver); +} + +static void __exit max11801_ts_exit(void) +{ +	i2c_del_driver(&max11801_ts_driver); +} + +module_init(max11801_ts_init); +module_exit(max11801_ts_exit); + +MODULE_AUTHOR("Zhang Jiejing <[email protected]>"); +MODULE_DESCRIPTION("Touchscreen driver for MAXI MAX11801 controller"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 80467f262331..fadc11545b1e 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -27,9 +27,6 @@  #include <linux/i2c.h>  #include <linux/i2c/tsc2007.h> -#define TS_POLL_DELAY			1 /* ms delay between samples */ -#define TS_POLL_PERIOD			1 /* ms delay between samples */ -  #define TSC2007_MEASURE_TEMP0		(0x0 << 4)  #define TSC2007_MEASURE_AUX		(0x2 << 4)  #define TSC2007_MEASURE_TEMP1		(0x4 << 4) @@ -75,6 +72,9 @@ struct tsc2007 {  	u16			model;  	u16			x_plate_ohms; +	u16			max_rt; +	unsigned long		poll_delay; +	unsigned long		poll_period;  	bool			pendown;  	int			irq; @@ -156,6 +156,7 @@ static void tsc2007_work(struct work_struct *work)  {  	struct tsc2007 *ts =  		container_of(to_delayed_work(work), struct tsc2007, work); +	bool debounced = false;  	struct ts_event tc;  	u32 rt; @@ -184,13 +185,14 @@ static void tsc2007_work(struct work_struct *work)  	tsc2007_read_values(ts, &tc);  	rt = tsc2007_calculate_pressure(ts, &tc); -	if (rt > MAX_12BIT) { +	if (rt > ts->max_rt) {  		/*  		 * Sample found inconsistent by debouncing or pressure is  		 * beyond the maximum. Don't report it to user space,  		 * repeat at least once more the measurement.  		 */  		dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt); +		debounced = true;  		goto out;  	} @@ -225,9 +227,9 @@ static void tsc2007_work(struct work_struct *work)  	}   out: -	if (ts->pendown) +	if (ts->pendown || debounced)  		schedule_delayed_work(&ts->work, -				      msecs_to_jiffies(TS_POLL_PERIOD)); +				      msecs_to_jiffies(ts->poll_period));  	else  		enable_irq(ts->irq);  } @@ -239,7 +241,7 @@ static irqreturn_t tsc2007_irq(int irq, void *handle)  	if (!ts->get_pendown_state || likely(ts->get_pendown_state())) {  		disable_irq_nosync(ts->irq);  		schedule_delayed_work(&ts->work, -				      msecs_to_jiffies(TS_POLL_DELAY)); +				      msecs_to_jiffies(ts->poll_delay));  	}  	if (ts->clear_penirq) @@ -292,6 +294,9 @@ static int __devinit tsc2007_probe(struct i2c_client *client,  	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; @@ -305,9 +310,10 @@ static int __devinit 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, 0, 0); -	input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); -	input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0); +	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_PRESSURE, 0, MAX_12BIT, +			pdata->fuzzz, 0);  	if (pdata->init_platform_hw)  		pdata->init_platform_hw(); |