summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2011-05-11 11:57:03 +1000
committerStephen Rothwell <sfr@canb.auug.org.au>2011-05-11 11:57:03 +1000
commitb11bdc28ea5f972a5196f2c624f89446e536a5b0 (patch)
treea8662274898fac46c67d4ea7b5786fc3beb6b319
parent636f17522c351c9cdc50bf9f72104cfa7f1475f7 (diff)
parent7388754e0399d341e6d02fc7394b3727cad57371 (diff)
Merge remote-tracking branch 'input/next'
-rw-r--r--arch/arm/mach-tegra/include/mach/kbc.h1
-rw-r--r--drivers/input/evdev.c17
-rw-r--r--drivers/input/input-polldev.c56
-rw-r--r--drivers/input/keyboard/gpio_keys.c11
-rw-r--r--drivers/input/keyboard/omap-keypad.c6
-rw-r--r--drivers/input/keyboard/qt1070.c1
-rw-r--r--drivers/input/keyboard/sh_keysc.c53
-rw-r--r--drivers/input/keyboard/tegra-kbc.c36
-rw-r--r--drivers/input/misc/ati_remote2.c9
-rw-r--r--drivers/input/misc/twl4030-pwrbutton.c2
-rw-r--r--drivers/input/touchscreen/Kconfig12
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c92
-rw-r--r--drivers/input/touchscreen/h3600_ts_input.c8
-rw-r--r--drivers/input/touchscreen/max11801_ts.c272
-rw-r--r--include/linux/gpio_keys.h8
16 files changed, 448 insertions, 137 deletions
diff --git a/arch/arm/mach-tegra/include/mach/kbc.h b/arch/arm/mach-tegra/include/mach/kbc.h
index 04c779832c78..bd99744f27db 100644
--- a/arch/arm/mach-tegra/include/mach/kbc.h
+++ b/arch/arm/mach-tegra/include/mach/kbc.h
@@ -58,5 +58,6 @@ struct tegra_kbc_platform_data {
bool wakeup;
bool use_fn_map;
+ bool use_ghost_filter;
};
#endif
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 88d8e4cb419a..75c4e8683033 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);
}
/*
@@ -387,12 +392,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 +426,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-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 <dtor@mail.ru>");
@@ -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/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/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/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..5fb4b972f205 100644
--- a/drivers/input/keyboard/tegra-kbc.c
+++ b/drivers/input/keyboard/tegra-kbc.c
@@ -72,6 +72,7 @@ struct tegra_kbc {
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 +261,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 +288,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 +328,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);
@@ -652,6 +687,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/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/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/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/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/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 <jiejing.zhang@freescale.com>
+ *
+ * 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 <jiejing.zhang@freescale.com>");
+MODULE_DESCRIPTION("Touchscreen driver for MAXI MAX11801 controller");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h
index dd1a56fbe924..b5ca4b2c08ec 100644
--- a/include/linux/gpio_keys.h
+++ b/include/linux/gpio_keys.h
@@ -3,14 +3,15 @@
struct gpio_keys_button {
/* Configuration parameters */
- int code; /* input event code (KEY_*, SW_*) */
+ unsigned int code; /* input event code (KEY_*, SW_*) */
int gpio;
int active_low;
- char *desc;
- int type; /* input event type (EV_KEY, EV_SW) */
+ const char *desc;
+ unsigned int type; /* input event type (EV_KEY, EV_SW, EV_ABS) */
int wakeup; /* configure the button as a wake-up source */
int debounce_interval; /* debounce ticks interval in msecs */
bool can_disable;
+ int value; /* axis value for EV_ABS */
};
struct gpio_keys_platform_data {
@@ -21,6 +22,7 @@ struct gpio_keys_platform_data {
unsigned int rep:1; /* enable input subsystem auto repeat */
int (*enable)(struct device *dev);
void (*disable)(struct device *dev);
+ const char *name; /* input device name */
};
#endif