summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS7
-rw-r--r--arch/arm/mach-tegra/include/mach/kbc.h13
-rw-r--r--arch/arm/plat-spear/include/plat/keyboard.h66
-rw-r--r--arch/m68k/q40/config.c13
-rw-r--r--drivers/hid/hid-core.c10
-rw-r--r--drivers/hid/hid-ids.h11
-rw-r--r--drivers/input/evdev.c25
-rw-r--r--drivers/input/keyboard/nomadik-ske-keypad.c17
-rw-r--r--drivers/input/keyboard/samsung-keypad.c6
-rw-r--r--drivers/input/keyboard/spear-keyboard.c16
-rw-r--r--drivers/input/keyboard/tegra-kbc.c51
-rw-r--r--drivers/input/misc/Kconfig12
-rw-r--r--drivers/input/misc/Makefile1
-rw-r--r--drivers/input/misc/da9052_onkey.c169
-rw-r--r--drivers/input/misc/max8925_onkey.c115
-rw-r--r--drivers/input/mouse/Kconfig17
-rw-r--r--drivers/input/mouse/Makefile1
-rw-r--r--drivers/input/mouse/hgpk.c9
-rw-r--r--drivers/input/mouse/psmouse-base.c15
-rw-r--r--drivers/input/mouse/psmouse.h2
-rw-r--r--drivers/input/mouse/sentelic.c12
-rw-r--r--drivers/input/mouse/synaptics_usb.c568
-rw-r--r--drivers/input/serio/at32psif.c22
-rw-r--r--drivers/input/serio/q40kbd.c139
-rw-r--r--drivers/input/tablet/wacom_sys.c6
-rw-r--r--drivers/input/tablet/wacom_wac.c28
-rw-r--r--drivers/input/tablet/wacom_wac.h2
-rw-r--r--drivers/input/touchscreen/Kconfig53
-rw-r--r--drivers/input/touchscreen/Makefile6
-rw-r--r--drivers/input/touchscreen/atmel-wm97xx.c20
-rw-r--r--drivers/input/touchscreen/cyttsp_core.c625
-rw-r--r--drivers/input/touchscreen/cyttsp_core.h149
-rw-r--r--drivers/input/touchscreen/cyttsp_i2c.c146
-rw-r--r--drivers/input/touchscreen/cyttsp_spi.c210
-rw-r--r--drivers/input/touchscreen/ti_tscadc.c486
-rw-r--r--drivers/input/touchscreen/usbtouchscreen.c63
-rw-r--r--include/linux/input.h2
-rw-r--r--include/linux/input/cyttsp.h58
-rw-r--r--include/linux/input/ti_tscadc.h17
-rw-r--r--kernel/time/timekeeping.c2
40 files changed, 2974 insertions, 216 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 4e41d5255d7..b31d1c95466 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2089,6 +2089,13 @@ W: http://www.cyclades.com/
S: Orphan
F: drivers/net/wan/pc300*
+CYTTSP TOUCHSCREEN DRIVER
+M: Javier Martinez Canillas <javier@dowhile0.org>
+L: linux-input@vger.kernel.org
+S: Maintained
+F: drivers/input/touchscreen/cyttsp*
+F: include/linux/input/cyttsp.h
+
DAMA SLAVE for AX.25
M: Joerg Reuter <jreuter@yaina.de>
W: http://yaina.de/jreuter/
diff --git a/arch/arm/mach-tegra/include/mach/kbc.h b/arch/arm/mach-tegra/include/mach/kbc.h
index 20bb0545f99..a1302561293 100644
--- a/arch/arm/mach-tegra/include/mach/kbc.h
+++ b/arch/arm/mach-tegra/include/mach/kbc.h
@@ -24,20 +24,21 @@
#include <linux/types.h>
#include <linux/input/matrix_keypad.h>
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
#define KBC_MAX_GPIO 24
#define KBC_MAX_KPENT 8
-#else
-#define KBC_MAX_GPIO 20
-#define KBC_MAX_KPENT 7
-#endif
#define KBC_MAX_ROW 16
#define KBC_MAX_COL 8
#define KBC_MAX_KEY (KBC_MAX_ROW * KBC_MAX_COL)
+enum tegra_pin_type {
+ PIN_CFG_IGNORE,
+ PIN_CFG_COL,
+ PIN_CFG_ROW,
+};
+
struct tegra_kbc_pin_cfg {
- bool is_row;
+ enum tegra_pin_type type;
unsigned char num;
};
diff --git a/arch/arm/plat-spear/include/plat/keyboard.h b/arch/arm/plat-spear/include/plat/keyboard.h
index 68b5394fc58..c16cc31ecbe 100644
--- a/arch/arm/plat-spear/include/plat/keyboard.h
+++ b/arch/arm/plat-spear/include/plat/keyboard.h
@@ -15,7 +15,7 @@
#include <linux/input/matrix_keypad.h>
#include <linux/types.h>
-#define DECLARE_KEYMAP(_name) \
+#define DECLARE_9x9_KEYMAP(_name) \
int _name[] = { \
KEY(0, 0, KEY_ESC), \
KEY(0, 1, KEY_1), \
@@ -62,24 +62,6 @@ int _name[] = { \
KEY(4, 6, KEY_Z), \
KEY(4, 7, KEY_X), \
KEY(4, 8, KEY_C), \
- KEY(4, 0, KEY_L), \
- KEY(4, 1, KEY_SEMICOLON), \
- KEY(4, 2, KEY_APOSTROPHE), \
- KEY(4, 3, KEY_GRAVE), \
- KEY(4, 4, KEY_LEFTSHIFT), \
- KEY(4, 5, KEY_BACKSLASH), \
- KEY(4, 6, KEY_Z), \
- KEY(4, 7, KEY_X), \
- KEY(4, 8, KEY_C), \
- KEY(4, 0, KEY_L), \
- KEY(4, 1, KEY_SEMICOLON), \
- KEY(4, 2, KEY_APOSTROPHE), \
- KEY(4, 3, KEY_GRAVE), \
- KEY(4, 4, KEY_LEFTSHIFT), \
- KEY(4, 5, KEY_BACKSLASH), \
- KEY(4, 6, KEY_Z), \
- KEY(4, 7, KEY_X), \
- KEY(4, 8, KEY_C), \
KEY(5, 0, KEY_V), \
KEY(5, 1, KEY_B), \
KEY(5, 2, KEY_N), \
@@ -118,10 +100,55 @@ int _name[] = { \
KEY(8, 8, KEY_KP0), \
}
+#define DECLARE_6x6_KEYMAP(_name) \
+int _name[] = { \
+ KEY(0, 0, KEY_RESERVED), \
+ KEY(0, 1, KEY_1), \
+ KEY(0, 2, KEY_2), \
+ KEY(0, 3, KEY_3), \
+ KEY(0, 4, KEY_4), \
+ KEY(0, 5, KEY_5), \
+ KEY(1, 0, KEY_Q), \
+ KEY(1, 1, KEY_W), \
+ KEY(1, 2, KEY_E), \
+ KEY(1, 3, KEY_R), \
+ KEY(1, 4, KEY_T), \
+ KEY(1, 5, KEY_Y), \
+ KEY(2, 0, KEY_D), \
+ KEY(2, 1, KEY_F), \
+ KEY(2, 2, KEY_G), \
+ KEY(2, 3, KEY_H), \
+ KEY(2, 4, KEY_J), \
+ KEY(2, 5, KEY_K), \
+ KEY(3, 0, KEY_B), \
+ KEY(3, 1, KEY_N), \
+ KEY(3, 2, KEY_M), \
+ KEY(3, 3, KEY_COMMA), \
+ KEY(3, 4, KEY_DOT), \
+ KEY(3, 5, KEY_SLASH), \
+ KEY(4, 0, KEY_F6), \
+ KEY(4, 1, KEY_F7), \
+ KEY(4, 2, KEY_F8), \
+ KEY(4, 3, KEY_F9), \
+ KEY(4, 4, KEY_F10), \
+ KEY(4, 5, KEY_NUMLOCK), \
+ KEY(5, 0, KEY_KP2), \
+ KEY(5, 1, KEY_KP3), \
+ KEY(5, 2, KEY_KP0), \
+ KEY(5, 3, KEY_KPDOT), \
+ KEY(5, 4, KEY_RO), \
+ KEY(5, 5, KEY_ZENKAKUHANKAKU), \
+}
+
+#define KEYPAD_9x9 0
+#define KEYPAD_6x6 1
+#define KEYPAD_2x2 2
+
/**
* struct kbd_platform_data - spear keyboard platform data
* keymap: pointer to keymap data (table and size)
* rep: enables key autorepeat
+ * mode: choose keyboard support(9x9, 6x6, 2x2)
*
* This structure is supposed to be used by platform code to supply
* keymaps to drivers that implement keyboards.
@@ -129,6 +156,7 @@ int _name[] = { \
struct kbd_platform_data {
const struct matrix_keymap_data *keymap;
bool rep;
+ unsigned int mode;
};
/* This function is used to set platform data field of pdev->dev */
diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c
index ad10fecec2f..be936480b96 100644
--- a/arch/m68k/q40/config.c
+++ b/arch/m68k/q40/config.c
@@ -24,6 +24,7 @@
#include <linux/rtc.h>
#include <linux/vt_kern.h>
#include <linux/bcd.h>
+#include <linux/platform_device.h>
#include <asm/io.h>
#include <asm/rtc.h>
@@ -329,3 +330,15 @@ static int q40_set_rtc_pll(struct rtc_pll_info *pll)
} else
return -EINVAL;
}
+
+static __init int q40_add_kbd_device(void)
+{
+ struct platform_device *pdev;
+
+ pdev = platform_device_register_simple("q40kbd", -1, NULL, 0);
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ return 0;
+}
+arch_initcall(q40_add_kbd_device);
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index af08ce7207d..4c861e23999 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1912,6 +1912,16 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) },
+#if defined(CONFIG_MOUSE_SYNAPTICS_USB) || defined(CONFIG_MOUSE_SYNAPTICS_USB_MODULE)
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_INT_TP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_CPAD) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_STICK) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_WP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_COMP_TP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_WTP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_DPAD) },
+#endif
{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index b8574cddd95..8e96f19b62e 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -652,6 +652,17 @@
#define USB_DEVICE_ID_SYMBOL_SCANNER_1 0x0800
#define USB_DEVICE_ID_SYMBOL_SCANNER_2 0x1300
+#define USB_VENDOR_ID_SYNAPTICS 0x06cb
+#define USB_DEVICE_ID_SYNAPTICS_TP 0x0001
+#define USB_DEVICE_ID_SYNAPTICS_INT_TP 0x0002
+#define USB_DEVICE_ID_SYNAPTICS_CPAD 0x0003
+#define USB_DEVICE_ID_SYNAPTICS_TS 0x0006
+#define USB_DEVICE_ID_SYNAPTICS_STICK 0x0007
+#define USB_DEVICE_ID_SYNAPTICS_WP 0x0008
+#define USB_DEVICE_ID_SYNAPTICS_COMP_TP 0x0009
+#define USB_DEVICE_ID_SYNAPTICS_WTP 0x0010
+#define USB_DEVICE_ID_SYNAPTICS_DPAD 0x0013
+
#define USB_VENDOR_ID_THRUSTMASTER 0x044f
#define USB_VENDOR_ID_TOPSEED 0x0766
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index afc166fcc3d..3626b1ce460 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -46,6 +46,7 @@ struct evdev_client {
struct fasync_struct *fasync;
struct evdev *evdev;
struct list_head node;
+ int clkid;
unsigned int bufsize;
struct input_event buffer[];
};
@@ -54,8 +55,12 @@ static struct evdev *evdev_table[EVDEV_MINORS];
static DEFINE_MUTEX(evdev_table_mutex);
static void evdev_pass_event(struct evdev_client *client,
- struct input_event *event)
+ struct input_event *event,
+ ktime_t mono, ktime_t real)
{
+ event->time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
+ mono : real);
+
/* Interrupts are disabled, just acquire the lock. */
spin_lock(&client->buffer_lock);
@@ -94,8 +99,11 @@ static void evdev_event(struct input_handle *handle,
struct evdev *evdev = handle->private;
struct evdev_client *client;
struct input_event event;
+ ktime_t time_mono, time_real;
+
+ time_mono = ktime_get();
+ time_real = ktime_sub(time_mono, ktime_get_monotonic_offset());
- do_gettimeofday(&event.time);
event.type = type;
event.code = code;
event.value = value;
@@ -103,11 +111,12 @@ static void evdev_event(struct input_handle *handle,
rcu_read_lock();
client = rcu_dereference(evdev->grab);
+
if (client)
- evdev_pass_event(client, &event);
+ evdev_pass_event(client, &event, time_mono, time_real);
else
list_for_each_entry_rcu(client, &evdev->client_list, node)
- evdev_pass_event(client, &event);
+ evdev_pass_event(client, &event, time_mono, time_real);
rcu_read_unlock();
@@ -685,6 +694,14 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
else
return evdev_ungrab(evdev, client);
+ case EVIOCSCLOCKID:
+ if (copy_from_user(&i, p, sizeof(unsigned int)))
+ return -EFAULT;
+ if (i != CLOCK_MONOTONIC && i != CLOCK_REALTIME)
+ return -EINVAL;
+ client->clkid = i;
+ return 0;
+
case EVIOCGKEYCODE:
return evdev_handle_get_keycode(dev, p);
diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c
index e35566aa102..101e245944e 100644
--- a/drivers/input/keyboard/nomadik-ske-keypad.c
+++ b/drivers/input/keyboard/nomadik-ske-keypad.c
@@ -88,7 +88,7 @@ static void ske_keypad_set_bits(struct ske_keypad *keypad, u16 addr,
*
* Enable Multi key press detection, auto scan mode
*/
-static int __devinit ske_keypad_chip_init(struct ske_keypad *keypad)
+static int __init ske_keypad_chip_init(struct ske_keypad *keypad)
{
u32 value;
int timeout = 50;
@@ -198,7 +198,7 @@ static irqreturn_t ske_keypad_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int __devinit ske_keypad_probe(struct platform_device *pdev)
+static int __init ske_keypad_probe(struct platform_device *pdev)
{
const struct ske_keypad_platform_data *plat = pdev->dev.platform_data;
struct ske_keypad *keypad;
@@ -344,7 +344,7 @@ static int __devexit ske_keypad_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int ske_keypad_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -372,22 +372,17 @@ static int ske_keypad_resume(struct device *dev)
return 0;
}
-
-static const struct dev_pm_ops ske_keypad_dev_pm_ops = {
- .suspend = ske_keypad_suspend,
- .resume = ske_keypad_resume,
-};
#endif
+static SIMPLE_DEV_PM_OPS(ske_keypad_dev_pm_ops,
+ ske_keypad_suspend, ske_keypad_resume);
+
static struct platform_driver ske_keypad_driver = {
.driver = {
.name = "nmk-ske-keypad",
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
.pm = &ske_keypad_dev_pm_ops,
-#endif
},
- .probe = ske_keypad_probe,
.remove = __devexit_p(ske_keypad_remove),
};
diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c
index 17ba7f9f80f..2391ae884fe 100644
--- a/drivers/input/keyboard/samsung-keypad.c
+++ b/drivers/input/keyboard/samsung-keypad.c
@@ -175,7 +175,7 @@ static irqreturn_t samsung_keypad_irq(int irq, void *dev_id)
} while (key_down && !keypad->stopped);
- pm_runtime_put_sync(&keypad->pdev->dev);
+ pm_runtime_put(&keypad->pdev->dev);
return IRQ_HANDLED;
}
@@ -199,7 +199,7 @@ static void samsung_keypad_start(struct samsung_keypad *keypad)
/* KEYIFCOL reg clear. */
writel(0, keypad->base + SAMSUNG_KEYIFCOL);
- pm_runtime_put_sync(&keypad->pdev->dev);
+ pm_runtime_put(&keypad->pdev->dev);
}
static void samsung_keypad_stop(struct samsung_keypad *keypad)
@@ -229,7 +229,7 @@ static void samsung_keypad_stop(struct samsung_keypad *keypad)
*/
enable_irq(keypad->irq);
- pm_runtime_put_sync(&keypad->pdev->dev);
+ pm_runtime_put(&keypad->pdev->dev);
}
static int samsung_keypad_open(struct input_dev *input_dev)
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c
index c88bd63dc9c..3b6b528f02f 100644
--- a/drivers/input/keyboard/spear-keyboard.c
+++ b/drivers/input/keyboard/spear-keyboard.c
@@ -50,6 +50,7 @@
#define ROW_MASK 0xF0
#define COLUMN_MASK 0x0F
#define ROW_SHIFT 4
+#define KEY_MATRIX_SHIFT 6
struct spear_kbd {
struct input_dev *input;
@@ -57,6 +58,7 @@ struct spear_kbd {
void __iomem *io_base;
struct clk *clk;
unsigned int irq;
+ unsigned int mode;
unsigned short last_key;
unsigned short keycodes[256];
};
@@ -106,7 +108,8 @@ static int spear_kbd_open(struct input_dev *dev)
return error;
/* program keyboard */
- val = SCAN_RATE_80 | MODE_KEYBOARD | PCLK_FREQ_MSK;
+ val = SCAN_RATE_80 | MODE_KEYBOARD | PCLK_FREQ_MSK |
+ (kbd->mode << KEY_MATRIX_SHIFT);
writew(val, kbd->io_base + MODE_REG);
writeb(1, kbd->io_base + STATUS_REG);
@@ -176,6 +179,8 @@ static int __devinit spear_kbd_probe(struct platform_device *pdev)
kbd->input = input_dev;
kbd->irq = irq;
+ kbd->mode = pdata->mode;
+
kbd->res = request_mem_region(res->start, resource_size(res),
pdev->name);
if (!kbd->res) {
@@ -308,22 +313,17 @@ static int spear_kbd_resume(struct device *dev)
return 0;
}
-
-static const struct dev_pm_ops spear_kbd_pm_ops = {
- .suspend = spear_kbd_suspend,
- .resume = spear_kbd_resume,
-};
#endif
+static SIMPLE_DEV_PM_OPS(spear_kbd_pm_ops, spear_kbd_suspend, spear_kbd_resume);
+
static struct platform_driver spear_kbd_driver = {
.probe = spear_kbd_probe,
.remove = __devexit_p(spear_kbd_remove),
.driver = {
.name = "keyboard",
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
.pm = &spear_kbd_pm_ops,
-#endif
},
};
module_platform_driver(spear_kbd_driver);
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c
index a136e2e832b..dc19432c665 100644
--- a/drivers/input/keyboard/tegra-kbc.c
+++ b/drivers/input/keyboard/tegra-kbc.c
@@ -48,6 +48,7 @@
#define KBC_FIFO_TH_CNT_SHIFT(cnt) (cnt << 14)
#define KBC_DEBOUNCE_CNT_SHIFT(cnt) (cnt << 4)
#define KBC_CONTROL_FIFO_CNT_INT_EN (1 << 3)
+#define KBC_CONTROL_KEYPRESS_INT_EN (1 << 1)
#define KBC_CONTROL_KBC_EN (1 << 0)
/* KBC Interrupt Register */
@@ -356,6 +357,18 @@ static void tegra_kbc_set_fifo_interrupt(struct tegra_kbc *kbc, bool enable)
writel(val, kbc->mmio + KBC_CONTROL_0);
}
+static void tegra_kbc_set_keypress_interrupt(struct tegra_kbc *kbc, bool enable)
+{
+ u32 val;
+
+ val = readl(kbc->mmio + KBC_CONTROL_0);
+ if (enable)
+ val |= KBC_CONTROL_KEYPRESS_INT_EN;
+ else
+ val &= ~KBC_CONTROL_KEYPRESS_INT_EN;
+ writel(val, kbc->mmio + KBC_CONTROL_0);
+}
+
static void tegra_kbc_keypress_timer(unsigned long data)
{
struct tegra_kbc *kbc = (struct tegra_kbc *)data;
@@ -455,10 +468,18 @@ static void tegra_kbc_config_pins(struct tegra_kbc *kbc)
row_cfg &= ~r_mask;
col_cfg &= ~c_mask;
- if (pdata->pin_cfg[i].is_row)
+ switch (pdata->pin_cfg[i].type) {
+ case PIN_CFG_ROW:
row_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << r_shft;
- else
+ break;
+
+ case PIN_CFG_COL:
col_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << c_shft;
+ break;
+
+ case PIN_CFG_IGNORE:
+ break;
+ }
writel(row_cfg, kbc->mmio + r_offs);
writel(col_cfg, kbc->mmio + c_offs);
@@ -563,7 +584,8 @@ tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata,
for (i = 0; i < KBC_MAX_GPIO; i++) {
const struct tegra_kbc_pin_cfg *pin_cfg = &pdata->pin_cfg[i];
- if (pin_cfg->is_row) {
+ switch (pin_cfg->type) {
+ case PIN_CFG_ROW:
if (pin_cfg->num >= KBC_MAX_ROW) {
dev_err(dev,
"pin_cfg[%d]: invalid row number %d\n",
@@ -571,13 +593,25 @@ tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata,
return false;
}
(*num_rows)++;
- } else {
+ break;
+
+ case PIN_CFG_COL:
if (pin_cfg->num >= KBC_MAX_COL) {
dev_err(dev,
"pin_cfg[%d]: invalid column number %d\n",
i, pin_cfg->num);
return false;
}
+ break;
+
+ case PIN_CFG_IGNORE:
+ break;
+
+ default:
+ dev_err(dev,
+ "pin_cfg[%d]: invalid entry type %d\n",
+ pin_cfg->type, pin_cfg->num);
+ return false;
}
}
@@ -594,7 +628,6 @@ tegra_kbc_dt_parse_pdata(struct platform_device *pdev)
if (!np)
return NULL;
- pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return NULL;
@@ -616,12 +649,12 @@ tegra_kbc_dt_parse_pdata(struct platform_device *pdev)
*/
for (i = 0; i < KBC_MAX_ROW; i++) {
pdata->pin_cfg[i].num = i;
- pdata->pin_cfg[i].is_row = true;
+ pdata->pin_cfg[i].type = PIN_CFG_ROW;
}
for (i = 0; i < KBC_MAX_COL; i++) {
pdata->pin_cfg[KBC_MAX_ROW + i].num = i;
- pdata->pin_cfg[KBC_MAX_ROW + i].is_row = false;
+ pdata->pin_cfg[KBC_MAX_ROW + i].type = PIN_CFG_COL;
}
return pdata;
@@ -831,6 +864,8 @@ static int tegra_kbc_suspend(struct device *dev)
msleep(30);
kbc->keypress_caused_wake = false;
+ /* Enable keypress interrupt before going into suspend. */
+ tegra_kbc_set_keypress_interrupt(kbc, true);
enable_irq(kbc->irq);
enable_irq_wake(kbc->irq);
} else {
@@ -852,6 +887,8 @@ static int tegra_kbc_resume(struct device *dev)
if (device_may_wakeup(&pdev->dev)) {
disable_irq_wake(kbc->irq);
tegra_kbc_setup_wakekeys(kbc, false);
+ /* We will use fifo interrupts for key detection. */
+ tegra_kbc_set_keypress_interrupt(kbc, false);
/* Restore the resident time of continuous polling mode. */
writel(kbc->cp_to_wkup_dly, kbc->mmio + KBC_TO_CNT_0);
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 7b46781c30c..eb07e88162a 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -415,7 +415,7 @@ config INPUT_PCF8574
tristate "PCF8574 Keypad input device"
depends on I2C && EXPERIMENTAL
help
- Say Y here if you want to support a keypad connetced via I2C
+ Say Y here if you want to support a keypad connected via I2C
with a PCF8574.
To compile this driver as a module, choose M here: the
@@ -455,6 +455,16 @@ config INPUT_RB532_BUTTON
To compile this driver as a module, choose M here: the
module will be called rb532_button.
+config INPUT_DA9052_ONKEY
+ tristate "Dialog DA9052/DA9053 Onkey"
+ depends on PMIC_DA9052
+ help
+ Support the ONKEY of Dialog DA9052 PMICs as an input device
+ reporting power button status.
+
+ To compile this driver as a module, choose M here: the
+ module will be called da9052_onkey.
+
config INPUT_DM355EVM
tristate "TI DaVinci DM355 EVM Keypad and IR Remote"
depends on MFD_DM355EVM_MSP
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 46671a875b9..a6d8de06914 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_INPUT_CM109) += cm109.o
obj-$(CONFIG_INPUT_CMA3000) += cma3000_d0x.o
obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o
obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o
+obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o
obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o
obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o
obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o
diff --git a/drivers/input/misc/da9052_onkey.c b/drivers/input/misc/da9052_onkey.c
new file mode 100644
index 00000000000..34aebb8cd08
--- /dev/null
+++ b/drivers/input/misc/da9052_onkey.c
@@ -0,0 +1,169 @@
+/*
+ * ON pin driver for Dialog DA9052 PMICs
+ *
+ * Copyright(c) 2012 Dialog Semiconductor Ltd.
+ *
+ * Author: David Dajun Chen <dchen@diasemi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/reg.h>
+
+struct da9052_onkey {
+ struct da9052 *da9052;
+ struct input_dev *input;
+ struct delayed_work work;
+ unsigned int irq;
+};
+
+static void da9052_onkey_query(struct da9052_onkey *onkey)
+{
+ int key_stat;
+
+ key_stat = da9052_reg_read(onkey->da9052, DA9052_EVENT_B_REG);
+ if (key_stat < 0) {
+ dev_err(onkey->da9052->dev,
+ "Failed to read onkey event %d\n", key_stat);
+ } else {
+ /*
+ * Since interrupt for deassertion of ONKEY pin is not
+ * generated, onkey event state determines the onkey
+ * button state.
+ */
+ key_stat &= DA9052_EVENTB_ENONKEY;
+ input_report_key(onkey->input, KEY_POWER, key_stat);
+ input_sync(onkey->input);
+ }
+
+ /*
+ * Interrupt is generated only when the ONKEY pin is asserted.
+ * Hence the deassertion of the pin is simulated through work queue.
+ */
+ if (key_stat)
+ schedule_delayed_work(&onkey->work, msecs_to_jiffies(50));
+}
+
+static void da9052_onkey_work(struct work_struct *work)
+{
+ struct da9052_onkey *onkey = container_of(work, struct da9052_onkey,
+ work.work);
+
+ da9052_onkey_query(onkey);
+}
+
+static irqreturn_t da9052_onkey_irq(int irq, void *data)
+{
+ struct da9052_onkey *onkey = data;
+
+ da9052_onkey_query(onkey);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit da9052_onkey_probe(struct platform_device *pdev)
+{
+ struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent);
+ struct da9052_onkey *onkey;
+ struct input_dev *input_dev;
+ int irq;
+ int error;
+
+ if (!da9052) {
+ dev_err(&pdev->dev, "Failed to get the driver's data\n");
+ return -EINVAL;
+ }
+
+ irq = platform_get_irq_byname(pdev, "ONKEY");
+ if (irq < 0) {
+ dev_err(&pdev->dev,
+ "Failed to get an IRQ for input device, %d\n", irq);
+ return -EINVAL;
+ }
+
+ onkey = kzalloc(sizeof(*onkey), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!onkey || !input_dev) {
+ dev_err(&pdev->dev, "Failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ onkey->input = input_dev;
+ onkey->da9052 = da9052;
+ onkey->irq = irq;
+ INIT_DELAYED_WORK(&onkey->work, da9052_onkey_work);
+
+ input_dev->name = "da9052-onkey";
+ input_dev->phys = "da9052-onkey/input0";
+ input_dev->dev.parent = &pdev->dev;
+
+ input_dev->evbit[0] = BIT_MASK(EV_KEY);
+ __set_bit(KEY_POWER, input_dev->keybit);
+
+ error = request_threaded_irq(onkey->irq, NULL, da9052_onkey_irq,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "ONKEY", onkey);
+ if (error < 0) {
+ dev_err(onkey->da9052->dev,
+ "Failed to register ONKEY IRQ %d, error = %d\n",
+ onkey->irq, error);
+ goto err_free_mem;
+ }
+
+ error = input_register_device(onkey->input);
+ if (error) {
+ dev_err(&pdev->dev, "Unable to register input device, %d\n",
+ error);
+ goto err_free_irq;
+ }
+
+ platform_set_drvdata(pdev, onkey);
+ return 0;
+
+err_free_irq:
+ free_irq(onkey->irq, onkey);
+ cancel_delayed_work_sync(&onkey->work);
+err_free_mem:
+ input_free_device(input_dev);
+ kfree(onkey);
+
+ return error;
+}
+
+static int __devexit da9052_onkey_remove(struct platform_device *pdev)
+{
+ struct da9052_onkey *onkey = platform_get_drvdata(pdev);
+
+ free_irq(onkey->irq, onkey);
+ cancel_delayed_work_sync(&onkey->work);
+
+ input_unregister_device(onkey->input);
+ kfree(onkey);
+
+ return 0;
+}
+
+static struct platform_driver da9052_onkey_driver = {
+ .probe = da9052_onkey_probe,
+ .remove = __devexit_p(da9052_onkey_remove),
+ .driver = {
+ .name = "da9052-onkey",
+ .owner = THIS_MODULE,
+ },
+};
+module_platform_driver(da9052_onkey_driver);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_DESCRIPTION("Onkey driver for DA9052");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9052-onkey");
diff --git a/drivers/input/misc/max8925_onkey.c b/drivers/input/misc/max8925_onkey.c
index 23cf0827104..0a12b74140d 100644
--- a/drivers/input/misc/max8925_onkey.c
+++ b/drivers/input/misc/max8925_onkey.c
@@ -1,5 +1,5 @@
/**
- * max8925_onkey.c - MAX8925 ONKEY driver
+ * MAX8925 ONKEY driver
*
* Copyright (C) 2009 Marvell International Ltd.
* Haojian Zhuang <haojian.zhuang@marvell.com>
@@ -35,7 +35,7 @@ struct max8925_onkey_info {
struct input_dev *idev;
struct i2c_client *i2c;
struct device *dev;
- int irq[2];
+ unsigned int irq[2];
};
/*
@@ -46,17 +46,14 @@ struct max8925_onkey_info {
static irqreturn_t max8925_onkey_handler(int irq, void *data)
{
struct max8925_onkey_info *info = data;
- int ret, event;
-
- ret = max8925_reg_read(info->i2c, MAX8925_ON_OFF_STATUS);
- if (ret & SW_INPUT)
- event = 1;
- else
- event = 0;
- input_report_key(info->idev, KEY_POWER, event);
+ int state;
+
+ state = max8925_reg_read(info->i2c, MAX8925_ON_OFF_STATUS);
+
+ input_report_key(info->idev, KEY_POWER, state & SW_INPUT);
input_sync(info->idev);
- dev_dbg(info->dev, "onkey event:%d\n", event);
+ dev_dbg(info->dev, "onkey state:%d\n", state);
/* Enable hardreset to halt if system isn't shutdown on time */
max8925_set_bits(info->i2c, MAX8925_SYSENSEL,
@@ -69,6 +66,7 @@ static int __devinit max8925_onkey_probe(struct platform_device *pdev)
{
struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
struct max8925_onkey_info *info;
+ struct input_dev *input;
int irq[2], error;
irq[0] = platform_get_irq(pdev, 0);
@@ -76,6 +74,7 @@ static int __devinit max8925_onkey_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "No IRQ resource!\n");
return -EINVAL;
}
+
irq[1] = platform_get_irq(pdev, 1);
if (irq[1] < 0) {
dev_err(&pdev->dev, "No IRQ resource!\n");
@@ -83,11 +82,24 @@ static int __devinit max8925_onkey_probe(struct platform_device *pdev)
}
info = kzalloc(sizeof(struct max8925_onkey_info), GFP_KERNEL);
- if (!info)
- return -ENOMEM;
+ input = input_allocate_device();
+ if (!info || !input) {
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+ info->idev = input;
info->i2c = chip->i2c;
info->dev = &pdev->dev;
+ info->irq[0] = irq[0];
+ info->irq[1] = irq[1];
+
+ input->name = "max8925_on";
+ input->phys = "max8925_on/input0";
+ input->id.bustype = BUS_I2C;
+ input->dev.parent = &pdev->dev;
+ input_set_capability(input, EV_KEY, KEY_POWER);
+
irq[0] += chip->irq_base;
irq[1] += chip->irq_base;
@@ -96,60 +108,46 @@ static int __devinit max8925_onkey_probe(struct platform_device *pdev)
if (error < 0) {
dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
irq[0], error);
- goto out;
+ goto err_free_mem;
}
+
error = request_threaded_irq(irq[1], NULL, max8925_onkey_handler,
IRQF_ONESHOT, "onkey-up", info);
if (error < 0) {
dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
irq[1], error);
- goto out_irq;
+ goto err_free_irq0;
}
- info->idev = input_allocate_device();
- if (!info->idev) {
- dev_err(chip->dev, "Failed to allocate input dev\n");
- error = -ENOMEM;
- goto out_input;
- }
-
- info->idev->name = "max8925_on";
- info->idev->phys = "max8925_on/input0";
- info->idev->id.bustype = BUS_I2C;
- info->idev->dev.parent = &pdev->dev;
- info->irq[0] = irq[0];
- info->irq[1] = irq[1];
- info->idev->evbit[0] = BIT_MASK(EV_KEY);
- info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
-
-
error = input_register_device(info->idev);
if (error) {
dev_err(chip->dev, "Can't register input device: %d\n", error);
- goto out_reg;
+ goto err_free_irq1;
}
platform_set_drvdata(pdev, info);
+ device_init_wakeup(&pdev->dev, 1);
return 0;
-out_reg:
- input_free_device(info->idev);
-out_input:
- free_irq(info->irq[1], info);
-out_irq:
- free_irq(info->irq[0], info);
-out:
+err_free_irq1:
+ free_irq(irq[1], info);
+err_free_irq0:
+ free_irq(irq[0], info);
+err_free_mem:
+ input_free_device(input);
kfree(info);
+
return error;
}
static int __devexit max8925_onkey_remove(struct platform_device *pdev)
{
struct max8925_onkey_info *info = platform_get_drvdata(pdev);
+ struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
- free_irq(info->irq[0], info);
- free_irq(info->irq[1], info);
+ free_irq(info->irq[0] + chip->irq_base, info);
+ free_irq(info->irq[1] + chip->irq_base, info);
input_unregister_device(info->idev);
kfree(info);
@@ -158,10 +156,43 @@ static int __devexit max8925_onkey_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int max8925_onkey_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct max8925_onkey_info *info = platform_get_drvdata(pdev);
+ struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+ if (device_may_wakeup(dev)) {
+ chip->wakeup_flag |= 1 << info->irq[0];
+ chip->wakeup_flag |= 1 << info->irq[1];
+ }
+
+ return 0;
+}
+
+static int max8925_onkey_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct max8925_onkey_info *info = platform_get_drvdata(pdev);
+ struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+ if (device_may_wakeup(dev)) {
+ chip->wakeup_flag &= ~(1 << info->irq[0]);
+ chip->wakeup_flag &= ~(1 << info->irq[1]);
+ }
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(max8925_onkey_pm_ops, max8925_onkey_suspend, max8925_onkey_resume);
+
static struct platform_driver max8925_onkey_driver = {
.driver = {
.name = "max8925-onkey",
.owner = THIS_MODULE,
+ .pm = &max8925_onkey_pm_ops,
},
.probe = max8925_onkey_probe,
.remove = __devexit_p(max8925_onkey_remove),
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index 9c1e6ee8353..9b8db821d5f 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -322,4 +322,21 @@ config MOUSE_SYNAPTICS_I2C
To compile this driver as a module, choose M here: the
module will be called synaptics_i2c.
+config MOUSE_SYNAPTICS_USB
+ tristate "Synaptics USB device support"
+ depends on USB_ARCH_HAS_HCD
+ select USB
+ help
+ Say Y here if you want to use a Synaptics USB touchpad or pointing
+ stick.
+
+ While these devices emulate an USB mouse by default and can be used
+ with standard usbhid driver, this driver, together with its X.Org
+ counterpart, allows you to fully utilize capabilities of the device.
+ More information can be found at:
+ <http://jan-steinhoff.de/linux/synaptics-usb.html>
+
+ To compile this driver as a module, choose M here: the
+ module will be called synaptics_usb.
+
endif
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index 570c84a4a65..4718effeb8d 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_MOUSE_PXA930_TRKBALL) += pxa930_trkball.o
obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o
obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o
obj-$(CONFIG_MOUSE_SYNAPTICS_I2C) += synaptics_i2c.o
+obj-$(CONFIG_MOUSE_SYNAPTICS_USB) += synaptics_usb.o
obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o
psmouse-objs := psmouse-base.o synaptics.o
diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c
index 1c5d521de60..575f880727f 100644
--- a/drivers/input/mouse/hgpk.c
+++ b/drivers/input/mouse/hgpk.c
@@ -640,7 +640,6 @@ static int hgpk_reset_device(struct psmouse *psmouse, bool recalibrate)
static int hgpk_force_recalibrate(struct psmouse *psmouse)
{
- struct ps2dev *ps2dev = &psmouse->ps2dev;
struct hgpk_data *priv = psmouse->private;
int err;
@@ -669,12 +668,9 @@ static int hgpk_force_recalibrate(struct psmouse *psmouse)
* we don't have a good way to deal with it. The 2s window stuff
* (below) is our best option for now.
*/
-
- if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE))
+ if (psmouse_activate(psmouse))
return -1;
- psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
-
if (tpdebug)
psmouse_dbg(psmouse, "touchpad reactivated\n");
@@ -733,8 +729,7 @@ static int hgpk_toggle_powersave(struct psmouse *psmouse, int enable)
}
/* should be all set, enable the touchpad */
- ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE);
- psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
+ psmouse_activate(psmouse);
psmouse_dbg(psmouse, "Touchpad powered up.\n");
} else {
psmouse_dbg(psmouse, "Powering off touchpad.\n");
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index e6c9931f02c..22fe2547e16 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -1092,28 +1092,33 @@ static void psmouse_initialize(struct psmouse *psmouse)
* psmouse_activate() enables the mouse so that we get motion reports from it.
*/
-static void psmouse_activate(struct psmouse *psmouse)
+int psmouse_activate(struct psmouse *psmouse)
{
- if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE))
+ if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
psmouse_warn(psmouse, "Failed to enable mouse on %s\n",
psmouse->ps2dev.serio->phys);
+ return -1;
+ }
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
+ return 0;
}
-
/*
* psmouse_deactivate() puts the mouse into poll mode so that we don't get motion
* reports from it unless we explicitly request it.
*/
-static void psmouse_deactivate(struct psmouse *psmouse)
+int psmouse_deactivate(struct psmouse *psmouse)
{
- if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE))
+ if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) {
psmouse_warn(psmouse, "Failed to deactivate mouse on %s\n",
psmouse->ps2dev.serio->phys);
+ return -1;
+ }
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
+ return 0;
}
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index 6a417092d01..fe1df231ba4 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -105,6 +105,8 @@ int psmouse_reset(struct psmouse *psmouse);
void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state);
void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution);
psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse);
+int psmouse_activate(struct psmouse *psmouse);
+int psmouse_deactivate(struct psmouse *psmouse);
struct psmouse_attribute {
struct device_attribute dattr;
diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c
index e36847de761..2a77a52d2e6 100644
--- a/drivers/input/mouse/sentelic.c
+++ b/drivers/input/mouse/sentelic.c
@@ -90,8 +90,7 @@ static int fsp_reg_read(struct psmouse *psmouse, int reg_addr, int *reg_val)
* to do that for writes because sysfs set helper does this for
* us.
*/
- ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE);
- psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
+ psmouse_deactivate(psmouse);
ps2_begin_command(ps2dev);
@@ -128,8 +127,7 @@ static int fsp_reg_read(struct psmouse *psmouse, int reg_addr, int *reg_val)
out:
ps2_end_command(ps2dev);
- ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
- psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
+ psmouse_activate(psmouse);
dev_dbg(&ps2dev->serio->dev, "READ REG: 0x%02x is 0x%02x (rc = %d)\n",
reg_addr, *reg_val, rc);
return rc;
@@ -213,8 +211,7 @@ static int fsp_page_reg_read(struct psmouse *psmouse, int *reg_val)
unsigned char param[3];
int rc = -1;
- ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE);
- psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
+ psmouse_deactivate(psmouse);
ps2_begin_command(ps2dev);
@@ -239,8 +236,7 @@ static int fsp_page_reg_read(struct psmouse *psmouse, int *reg_val)
out:
ps2_end_command(ps2dev);
- ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
- psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
+ psmouse_activate(psmouse);
dev_dbg(&ps2dev->serio->dev, "READ PAGE REG: 0x%02x (rc = %d)\n",
*reg_val, rc);
return rc;
diff --git a/drivers/input/mouse/synaptics_usb.c b/drivers/input/mouse/synaptics_usb.c
new file mode 100644
index 00000000000..e559a947bb5
--- /dev/null
+++ b/drivers/input/mouse/synaptics_usb.c
@@ -0,0 +1,568 @@
+/*
+ * USB Synaptics device driver
+ *
+ * Copyright (c) 2002 Rob Miller (rob@inpharmatica . co . uk)
+ * Copyright (c) 2003 Ron Lee (ron@debian.org)
+ * cPad driver for kernel 2.4
+ *
+ * Copyright (c) 2004 Jan Steinhoff (cpad@jan-steinhoff . de)
+ * Copyright (c) 2004 Ron Lee (ron@debian.org)
+ * rewritten for kernel 2.6
+ *
+ * cPad display character device part is not included. It can be found at
+ * http://jan-steinhoff.de/linux/synaptics-usb.html
+ *
+ * Bases on: usb_skeleton.c v2.2 by Greg Kroah-Hartman
+ * drivers/hid/usbhid/usbmouse.c by Vojtech Pavlik
+ * drivers/input/mouse/synaptics.c by Peter Osterlund
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * Trademarks are the property of their respective owners.
+ */
+
+/*
+ * There are three different types of Synaptics USB devices: Touchpads,
+ * touchsticks (or trackpoints), and touchscreens. Touchpads are well supported
+ * by this driver, touchstick support has not been tested much yet, and
+ * touchscreens have not been tested at all.
+ *
+ * Up to three alternate settings are possible:
+ * setting 0: one int endpoint for relative movement (used by usbhid.ko)
+ * setting 1: one int endpoint for absolute finger position
+ * setting 2 (cPad only): one int endpoint for absolute finger position and
+ * two bulk endpoints for the display (in/out)
+ * This driver uses setting 1.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/usb.h>
+#include <linux/input.h>
+#include <linux/usb/input.h>
+
+#define USB_VENDOR_ID_SYNAPTICS 0x06cb
+#define USB_DEVICE_ID_SYNAPTICS_TP 0x0001 /* Synaptics USB TouchPad */
+#define USB_DEVICE_ID_SYNAPTICS_INT_TP 0x0002 /* Integrated USB TouchPad */
+#define USB_DEVICE_ID_SYNAPTICS_CPAD 0x0003 /* Synaptics cPad */
+#define USB_DEVICE_ID_SYNAPTICS_TS 0x0006 /* Synaptics TouchScreen */
+#define USB_DEVICE_ID_SYNAPTICS_STICK 0x0007 /* Synaptics USB Styk */
+#define USB_DEVICE_ID_SYNAPTICS_WP 0x0008 /* Synaptics USB WheelPad */
+#define USB_DEVICE_ID_SYNAPTICS_COMP_TP 0x0009 /* Composite USB TouchPad */
+#define USB_DEVICE_ID_SYNAPTICS_WTP 0x0010 /* Wireless TouchPad */
+#define USB_DEVICE_ID_SYNAPTICS_DPAD 0x0013 /* DisplayPad */
+
+#define SYNUSB_TOUCHPAD (1 << 0)
+#define SYNUSB_STICK (1 << 1)
+#define SYNUSB_TOUCHSCREEN (1 << 2)
+#define SYNUSB_AUXDISPLAY (1 << 3) /* For cPad */
+#define SYNUSB_COMBO (1 << 4) /* Composite device (TP + stick) */
+#define SYNUSB_IO_ALWAYS (1 << 5)
+
+#define USB_DEVICE_SYNAPTICS(prod, kind) \
+ USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, \
+ USB_DEVICE_ID_SYNAPTICS_##prod), \
+ .driver_info = (kind),
+
+#define SYNUSB_RECV_SIZE 8
+
+#define XMIN_NOMINAL 1472
+#define XMAX_NOMINAL 5472
+#define YMIN_NOMINAL 1408
+#define YMAX_NOMINAL 4448
+
+struct synusb {
+ struct usb_device *udev;
+ struct usb_interface *intf;
+ struct urb *urb;
+ unsigned char *data;
+
+ /* input device related data structures */
+ struct input_dev *input;
+ char name[128];
+ char phys[64];
+
+ /* characteristics of the device */
+ unsigned long flags;
+};
+
+static void synusb_report_buttons(struct synusb *synusb)
+{
+ struct input_dev *input_dev = synusb->input;
+
+ input_report_key(input_dev, BTN_LEFT, synusb->data[1] & 0x04);
+ input_report_key(input_dev, BTN_RIGHT, synusb->data[1] & 0x01);
+ input_report_key(input_dev, BTN_MIDDLE, synusb->data[1] & 0x02);
+}
+
+static void synusb_report_stick(struct synusb *synusb)
+{
+ struct input_dev *input_dev = synusb->input;
+ int x, y;
+ unsigned int pressure;
+
+ pressure = synusb->data[6];
+ x = (s16)(be16_to_cpup((__be16 *)&synusb->data[2]) << 3) >> 7;
+ y = (s16)(be16_to_cpup((__be16 *)&synusb->data[4]) << 3) >> 7;
+
+ if (pressure > 0) {
+ input_report_rel(input_dev, REL_X, x);
+ input_report_rel(input_dev, REL_Y, -y);
+ }
+
+ input_report_abs(input_dev, ABS_PRESSURE, pressure);
+
+ synusb_report_buttons(synusb);
+
+ input_sync(input_dev);
+}
+
+static void synusb_report_touchpad(struct synusb *synusb)
+{
+ struct input_dev *input_dev = synusb->input;
+ unsigned int num_fingers, tool_width;
+ unsigned int x, y;
+ unsigned int pressure, w;
+
+ pressure = synusb->data[6];
+ x = be16_to_cpup((__be16 *)&synusb->data[2]);
+ y = be16_to_cpup((__be16 *)&synusb->data[4]);
+ w = synusb->data[0] & 0x0f;
+
+ if (pressure > 0) {
+ num_fingers = 1;
+ tool_width = 5;
+ switch (w) {
+ case 0 ... 1:
+ num_fingers = 2 + w;
+ break;
+
+ case 2: /* pen, pretend its a finger */
+ break;
+
+ case 4 ... 15:
+ tool_width = w;
+ break;
+ }
+ } else {
+ num_fingers = 0;
+ tool_width = 0;
+ }
+
+ /*
+ * Post events
+ * BTN_TOUCH has to be first as mousedev relies on it when doing
+ * absolute -> relative conversion
+ */
+
+ if (pressure > 30)
+ input_report_key(input_dev, BTN_TOUCH, 1);
+ if (pressure < 25)
+ input_report_key(input_dev, BTN_TOUCH, 0);
+
+ if (num_fingers > 0) {
+ input_report_abs(input_dev, ABS_X, x);
+ input_report_abs(input_dev, ABS_Y,
+ YMAX_NOMINAL + YMIN_NOMINAL - y);
+ }
+
+ input_report_abs(input_dev, ABS_PRESSURE, pressure);
+ input_report_abs(input_dev, ABS_TOOL_WIDTH, tool_width);
+
+ input_report_key(input_dev, BTN_TOOL_FINGER, num_fingers == 1);
+ input_report_key(input_dev, BTN_TOOL_DOUBLETAP, num_fingers == 2);
+ input_report_key(input_dev, BTN_TOOL_TRIPLETAP, num_fingers == 3);
+
+ synusb_report_buttons(synusb);
+ if (synusb->flags & SYNUSB_AUXDISPLAY)
+ input_report_key(input_dev, BTN_MIDDLE, synusb->data[1] & 0x08);
+
+ input_sync(input_dev);
+}
+
+static void synusb_irq(struct urb *urb)
+{
+ struct synusb *synusb = urb->context;
+ int error;
+
+ /* Check our status in case we need to bail out early. */
+ switch (urb->status) {
+ case 0:
+ usb_mark_last_busy(synusb->udev);
+ break;
+
+ /* Device went away so don't keep trying to read from it. */
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+
+ default:
+ goto resubmit;
+ break;
+ }
+
+ if (synusb->flags & SYNUSB_STICK)
+ synusb_report_stick(synusb);
+ else
+ synusb_report_touchpad(synusb);
+
+resubmit:
+ error = usb_submit_urb(urb, GFP_ATOMIC);
+ if (error && error != -EPERM)
+ dev_err(&synusb->intf->dev,
+ "%s - usb_submit_urb failed with result: %d",
+ __func__, error);
+}
+
+static struct usb_endpoint_descriptor *
+synusb_get_in_endpoint(struct usb_host_interface *iface)
+{
+
+ struct usb_endpoint_descriptor *endpoint;
+ int i;
+
+ for (i = 0; i < iface->desc.bNumEndpoints; ++i) {
+ endpoint = &iface->endpoint[i].desc;
+
+ if (usb_endpoint_is_int_in(endpoint)) {
+ /* we found our interrupt in endpoint */
+ return endpoint;
+ }
+ }
+
+ return NULL;
+}
+
+static int synusb_open(struct input_dev *dev)
+{
+ struct synusb *synusb = input_get_drvdata(dev);
+ int retval;
+
+ retval = usb_autopm_get_interface(synusb->intf);
+ if (retval) {
+ dev_err(&synusb->intf->dev,
+ "%s - usb_autopm_get_interface failed, error: %d\n",
+ __func__, retval);
+ return retval;
+ }
+
+ retval = usb_submit_urb(synusb->urb, GFP_KERNEL);
+ if (retval) {
+ dev_err(&synusb->intf->dev,
+ "%s - usb_submit_urb failed, error: %d\n",
+ __func__, retval);
+ retval = -EIO;
+ goto out;
+ }
+
+ synusb->intf->needs_remote_wakeup = 1;
+
+out:
+ usb_autopm_put_interface(synusb->intf);
+ return retval;
+}
+
+static void synusb_close(struct input_dev *dev)
+{
+ struct synusb *synusb = input_get_drvdata(dev);
+ int autopm_error;
+
+ autopm_error = usb_autopm_get_interface(synusb->intf);
+
+ usb_kill_urb(synusb->urb);
+ synusb->intf->needs_remote_wakeup = 0;
+
+ if (!autopm_error)
+ usb_autopm_put_interface(synusb->intf);
+}
+
+static int synusb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct usb_endpoint_descriptor *ep;
+ struct synusb *synusb;
+ struct input_dev *input_dev;
+ unsigned int intf_num = intf->cur_altsetting->desc.bInterfaceNumber;
+ unsigned int altsetting = min(intf->num_altsetting, 1U);
+ int error;
+
+ error = usb_set_interface(udev, intf_num, altsetting);
+ if (error) {
+ dev_err(&udev->dev,
+ "Can not set alternate setting to %i, error: %i",
+ altsetting, error);
+ return error;
+ }
+
+ ep = synusb_get_in_endpoint(intf->cur_altsetting);
+ if (!ep)
+ return -ENODEV;
+
+ synusb = kzalloc(sizeof(*synusb), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!synusb || !input_dev) {
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ synusb->udev = udev;
+ synusb->intf = intf;
+ synusb->input = input_dev;
+
+ synusb->flags = id->driver_info;
+ if (synusb->flags & SYNUSB_COMBO) {
+ /*
+ * This is a combo device, we need to set proper
+ * capability, depending on the interface.
+ */
+ synusb->flags |= intf_num == 1 ?
+ SYNUSB_STICK : SYNUSB_TOUCHPAD;
+ }
+
+ synusb->urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!synusb->urb) {
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ synusb->data = usb_alloc_coherent(udev, SYNUSB_RECV_SIZE, GFP_KERNEL,
+ &synusb->urb->transfer_dma);
+ if (!synusb->data) {
+ error = -ENOMEM;
+ goto err_free_urb;
+ }
+
+ usb_fill_int_urb(synusb->urb, udev,
+ usb_rcvintpipe(udev, ep->bEndpointAddress),
+ synusb->data, SYNUSB_RECV_SIZE,
+ synusb_irq, synusb,
+ ep->bInterval);
+ synusb->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ if (udev->manufacturer)
+ strlcpy(synusb->name, udev->manufacturer,
+ sizeof(synusb->name));
+
+ if (udev->product) {
+ if (udev->manufacturer)
+ strlcat(synusb->name, " ", sizeof(synusb->name));
+ strlcat(synusb->name, udev->product, sizeof(synusb->name));
+ }
+
+ if (!strlen(synusb->name))
+ snprintf(synusb->name, sizeof(synusb->name),
+ "USB Synaptics Device %04x:%04x",
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct));
+
+ if (synusb->flags & SYNUSB_STICK)
+ strlcat(synusb->name, " (Stick) ", sizeof(synusb->name));
+
+ usb_make_path(udev, synusb->phys, sizeof(synusb->phys));
+ strlcat(synusb->phys, "/input0", sizeof(synusb->phys));
+
+ input_dev->name = synusb->name;
+ input_dev->phys = synusb->phys;
+ usb_to_input_id(udev, &input_dev->id);
+ input_dev->dev.parent = &synusb->intf->dev;
+
+ if (!(synusb->flags & SYNUSB_IO_ALWAYS)) {
+ input_dev->open = synusb_open;
+ input_dev->close = synusb_close;
+ }
+
+ input_set_drvdata(input_dev, synusb);
+
+ __set_bit(EV_ABS, input_dev->evbit);
+ __set_bit(EV_KEY, input_dev->evbit);
+
+ if (synusb->flags & SYNUSB_STICK) {
+ __set_bit(EV_REL, input_dev->evbit);
+ __set_bit(REL_X, input_dev->relbit);
+ __set_bit(REL_Y, input_dev->relbit);
+ input_set_abs_params(input_dev, ABS_PRESSURE, 0, 127, 0, 0);
+ } else {
+ input_set_abs_params(input_dev, ABS_X,
+ XMIN_NOMINAL, XMAX_NOMINAL, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y,
+ YMIN_NOMINAL, YMAX_NOMINAL, 0, 0);
+ input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0);
+ input_set_abs_params(input_dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
+ __set_bit(BTN_TOUCH, input_dev->keybit);
+ __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
+ __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
+ __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
+ }
+
+ __set_bit(BTN_LEFT, input_dev->keybit);
+ __set_bit(BTN_RIGHT, input_dev->keybit);
+ __set_bit(BTN_MIDDLE, input_dev->keybit);
+
+ usb_set_intfdata(intf, synusb);
+
+ if (synusb->flags & SYNUSB_IO_ALWAYS) {
+ error = synusb_open(input_dev);
+ if (error)
+ goto err_free_dma;
+ }
+
+ error = input_register_device(input_dev);
+ if (error) {
+ dev_err(&udev->dev,
+ "Failed to register input device, error %d\n",
+ error);
+ goto err_stop_io;
+ }
+
+ return 0;
+
+err_stop_io:
+ if (synusb->flags & SYNUSB_IO_ALWAYS)
+ synusb_close(synusb->input);
+err_free_dma:
+ usb_free_coherent(udev, SYNUSB_RECV_SIZE, synusb->data,
+ synusb->urb->transfer_dma);
+err_free_urb:
+ usb_free_urb(synusb->urb);
+err_free_mem:
+ input_free_device(input_dev);
+ kfree(synusb);
+ usb_set_intfdata(intf, NULL);
+
+ return error;
+}
+
+static void synusb_disconnect(struct usb_interface *intf)
+{
+ struct synusb *synusb = usb_get_intfdata(intf);
+ struct usb_device *udev = interface_to_usbdev(intf);
+
+ if (synusb->flags & SYNUSB_IO_ALWAYS)
+ synusb_close(synusb->input);
+
+ input_unregister_device(synusb->input);
+
+ usb_free_coherent(udev, SYNUSB_RECV_SIZE, synusb->data,
+ synusb->urb->transfer_dma);
+ usb_free_urb(synusb->urb);
+ kfree(synusb);
+
+ usb_set_intfdata(intf, NULL);
+}
+
+static int synusb_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct synusb *synusb = usb_get_intfdata(intf);
+ struct input_dev *input_dev = synusb->input;
+
+ mutex_lock(&input_dev->mutex);
+ usb_kill_urb(synusb->urb);
+ mutex_unlock(&input_dev->mutex);
+
+ return 0;
+}
+
+static int synusb_resume(struct usb_interface *intf)
+{
+ struct synusb *synusb = usb_get_intfdata(intf);
+ struct input_dev *input_dev = synusb->input;
+ int retval = 0;
+
+ mutex_lock(&input_dev->mutex);
+
+ if ((input_dev->users || (synusb->flags & SYNUSB_IO_ALWAYS)) &&
+ usb_submit_urb(synusb->urb, GFP_NOIO) < 0) {
+ retval = -EIO;
+ }
+
+ mutex_unlock(&input_dev->mutex);
+
+ return retval;
+}
+
+static int synusb_pre_reset(struct usb_interface *intf)
+{
+ struct synusb *synusb = usb_get_intfdata(intf);
+ struct input_dev *input_dev = synusb->input;
+
+ mutex_lock(&input_dev->mutex);
+ usb_kill_urb(synusb->urb);
+
+ return 0;
+}
+
+static int synusb_post_reset(struct usb_interface *intf)
+{
+ struct synusb *synusb = usb_get_intfdata(intf);
+ struct input_dev *input_dev = synusb->input;
+ int retval = 0;
+
+ if ((input_dev->users || (synusb->flags & SYNUSB_IO_ALWAYS)) &&
+ usb_submit_urb(synusb->urb, GFP_NOIO) < 0) {
+ retval = -EIO;
+ }
+
+ mutex_unlock(&input_dev->mutex);
+
+ return retval;
+}
+
+static int synusb_reset_resume(struct usb_interface *intf)
+{
+ return synusb_resume(intf);
+}
+
+static struct usb_device_id synusb_idtable[] = {
+ { USB_DEVICE_SYNAPTICS(TP, SYNUSB_TOUCHPAD) },
+ { USB_DEVICE_SYNAPTICS(INT_TP, SYNUSB_TOUCHPAD) },
+ { USB_DEVICE_SYNAPTICS(CPAD,
+ SYNUSB_TOUCHPAD | SYNUSB_AUXDISPLAY | SYNUSB_IO_ALWAYS) },
+ { USB_DEVICE_SYNAPTICS(TS, SYNUSB_TOUCHSCREEN) },
+ { USB_DEVICE_SYNAPTICS(STICK, SYNUSB_STICK) },
+ { USB_DEVICE_SYNAPTICS(WP, SYNUSB_TOUCHPAD) },
+ { USB_DEVICE_SYNAPTICS(COMP_TP, SYNUSB_COMBO) },
+ { USB_DEVICE_SYNAPTICS(WTP, SYNUSB_TOUCHPAD) },
+ { USB_DEVICE_SYNAPTICS(DPAD, SYNUSB_TOUCHPAD) },
+ { }
+};
+MODULE_DEVICE_TABLE(usb, synusb_idtable);
+
+static struct usb_driver synusb_driver = {
+ .name = "synaptics_usb",
+ .probe = synusb_probe,
+ .disconnect = synusb_disconnect,
+ .id_table = synusb_idtable,
+ .suspend = synusb_suspend,
+ .resume = synusb_resume,
+ .pre_reset = synusb_pre_reset,
+ .post_reset = synusb_post_reset,
+ .reset_resume = synusb_reset_resume,
+ .supports_autosuspend = 1,
+};
+
+static int __init synusb_init(void)
+{
+ return usb_register(&synusb_driver);
+}
+
+static void __exit synusb_exit(void)
+{
+ usb_deregister(&synusb_driver);
+}
+
+module_init(synusb_init);
+module_exit(synusb_exit);
+
+MODULE_AUTHOR("Rob Miller <rob@inpharmatica.co.uk>, "
+ "Ron Lee <ron@debian.org>, "
+ "Jan Steinhoff <cpad@jan-steinhoff.de>");
+MODULE_DESCRIPTION("Synaptics USB device driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/serio/at32psif.c b/drivers/input/serio/at32psif.c
index 95280f9207e..36e799c31f5 100644
--- a/drivers/input/serio/at32psif.c
+++ b/drivers/input/serio/at32psif.c
@@ -98,9 +98,9 @@ struct psif {
struct serio *io;
void __iomem *regs;
unsigned int irq;
- unsigned int open;
/* Prevent concurrent writes to PSIF THR. */
spinlock_t lock;
+ bool open;
};
static irqreturn_t psif_interrupt(int irq, void *_ptr)
@@ -164,7 +164,7 @@ static int psif_open(struct serio *io)
psif_writel(psif, CR, PSIF_BIT(CR_TXEN) | PSIF_BIT(CR_RXEN));
psif_writel(psif, IER, PSIF_BIT(RXRDY));
- psif->open = 1;
+ psif->open = true;
out:
return retval;
}
@@ -173,7 +173,7 @@ static void psif_close(struct serio *io)
{
struct psif *psif = io->port_data;
- psif->open = 0;
+ psif->open = false;
psif_writel(psif, IDR, ~0UL);
psif_writel(psif, CR, PSIF_BIT(CR_TXDIS) | PSIF_BIT(CR_RXDIS));
@@ -319,9 +319,10 @@ static int __exit psif_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
-static int psif_suspend(struct platform_device *pdev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int psif_suspend(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct psif *psif = platform_get_drvdata(pdev);
if (psif->open) {
@@ -332,8 +333,9 @@ static int psif_suspend(struct platform_device *pdev, pm_message_t state)
return 0;
}
-static int psif_resume(struct platform_device *pdev)
+static int psif_resume(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct psif *psif = platform_get_drvdata(pdev);
if (psif->open) {
@@ -344,19 +346,17 @@ static int psif_resume(struct platform_device *pdev)
return 0;
}
-#else
-#define psif_suspend NULL
-#define psif_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(psif_pm_ops, psif_suspend, psif_resume);
+
static struct platform_driver psif_driver = {
.remove = __exit_p(psif_remove),
.driver = {
.name = "atmel_psif",
.owner = THIS_MODULE,
+ .pm = &psif_pm_ops,
},
- .suspend = psif_suspend,
- .resume = psif_resume,
};
static int __init psif_init(void)
diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c
index 5eb84b3b67f..0c0df7f7380 100644
--- a/drivers/input/serio/q40kbd.c
+++ b/drivers/input/serio/q40kbd.c
@@ -44,26 +44,31 @@
#include <asm/irq.h>
#include <asm/q40ints.h>
+#define DRV_NAME "q40kbd"
+
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
-static DEFINE_SPINLOCK(q40kbd_lock);
-static struct serio *q40kbd_port;
-static struct platform_device *q40kbd_device;
+struct q40kbd {
+ struct serio *port;
+ spinlock_t lock;
+};
static irqreturn_t q40kbd_interrupt(int irq, void *dev_id)
{
+ struct q40kbd *q40kbd = dev_id;
unsigned long flags;
- spin_lock_irqsave(&q40kbd_lock, flags);
+ spin_lock_irqsave(&q40kbd->lock, flags);
if (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))
- serio_interrupt(q40kbd_port, master_inb(KEYCODE_REG), 0);
+ serio_interrupt(q40kbd->port, master_inb(KEYCODE_REG), 0);
master_outb(-1, KEYBOARD_UNLOCK_REG);
- spin_unlock_irqrestore(&q40kbd_lock, flags);
+ spin_unlock_irqrestore(&q40kbd->lock, flags);
return IRQ_HANDLED;
}
@@ -72,17 +77,23 @@ static irqreturn_t q40kbd_interrupt(int irq, void *dev_id)
* q40kbd_flush() flushes all data that may be in the keyboard buffers
*/
-static void q40kbd_flush(void)
+static void q40kbd_flush(struct q40kbd *q40kbd)
{
int maxread = 100;
unsigned long flags;
- spin_lock_irqsave(&q40kbd_lock, flags);
+ spin_lock_irqsave(&q40kbd->lock, flags);
while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)))
master_inb(KEYCODE_REG);
- spin_unlock_irqrestore(&q40kbd_lock, flags);
+ spin_unlock_irqrestore(&q40kbd->lock, flags);
+}
+
+static void q40kbd_stop(void)
+{
+ master_outb(0, KEY_IRQ_ENABLE_REG);
+ master_outb(-1, KEYBOARD_UNLOCK_REG);
}
/*
@@ -92,12 +103,9 @@ static void q40kbd_flush(void)
static int q40kbd_open(struct serio *port)
{
- q40kbd_flush();
+ struct q40kbd *q40kbd = port->port_data;
- if (request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, "q40kbd", NULL)) {
- printk(KERN_ERR "q40kbd.c: Can't get irq %d.\n", Q40_IRQ_KEYBOARD);
- return -EBUSY;
- }
+ q40kbd_flush(q40kbd);
/* off we go */
master_outb(-1, KEYBOARD_UNLOCK_REG);
@@ -108,36 +116,72 @@ static int q40kbd_open(struct serio *port)
static void q40kbd_close(struct serio *port)
{
- master_outb(0, KEY_IRQ_ENABLE_REG);
- master_outb(-1, KEYBOARD_UNLOCK_REG);
- free_irq(Q40_IRQ_KEYBOARD, NULL);
+ struct q40kbd *q40kbd = port->port_data;
- q40kbd_flush();
+ q40kbd_stop();
+ q40kbd_flush(q40kbd);
}
-static int __devinit q40kbd_probe(struct platform_device *dev)
+static int __devinit q40kbd_probe(struct platform_device *pdev)
{
- q40kbd_port = kzalloc(sizeof(struct serio), GFP_KERNEL);
- if (!q40kbd_port)
- return -ENOMEM;
-
- q40kbd_port->id.type = SERIO_8042;
- q40kbd_port->open = q40kbd_open;
- q40kbd_port->close = q40kbd_close;
- q40kbd_port->dev.parent = &dev->dev;
- strlcpy(q40kbd_port->name, "Q40 Kbd Port", sizeof(q40kbd_port->name));
- strlcpy(q40kbd_port->phys, "Q40", sizeof(q40kbd_port->phys));
-
- serio_register_port(q40kbd_port);
+ struct q40kbd *q40kbd;
+ struct serio *port;
+ int error;
+
+ q40kbd = kzalloc(sizeof(struct q40kbd), GFP_KERNEL);
+ port = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ if (!q40kbd || !port) {
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ q40kbd->port = port;
+ spin_lock_init(&q40kbd->lock);
+
+ port->id.type = SERIO_8042;
+ port->open = q40kbd_open;
+ port->close = q40kbd_close;
+ port->port_data = q40kbd;
+ port->dev.parent = &pdev->dev;
+ strlcpy(port->name, "Q40 Kbd Port", sizeof(port->name));
+ strlcpy(port->phys, "Q40", sizeof(port->phys));
+
+ q40kbd_stop();
+
+ error = request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0,
+ DRV_NAME, q40kbd);
+ if (error) {
+ dev_err(&pdev->dev, "Can't get irq %d.\n", Q40_IRQ_KEYBOARD);
+ goto err_free_mem;
+ }
+
+ serio_register_port(q40kbd->port);
+
+ platform_set_drvdata(pdev, q40kbd);
printk(KERN_INFO "serio: Q40 kbd registered\n");
return 0;
+
+err_free_mem:
+ kfree(port);
+ kfree(q40kbd);
+ return error;
}
-static int __devexit q40kbd_remove(struct platform_device *dev)
+static int __devexit q40kbd_remove(struct platform_device *pdev)
{
- serio_unregister_port(q40kbd_port);
-
+ struct q40kbd *q40kbd = platform_get_drvdata(pdev);
+
+ /*
+ * q40kbd_close() will be called as part of unregistering
+ * and will ensure that IRQ is turned off, so it is safe
+ * to unregister port first and free IRQ later.
+ */
+ serio_unregister_port(q40kbd->port);
+ free_irq(Q40_IRQ_KEYBOARD, q40kbd);
+ kfree(q40kbd);
+
+ platform_set_drvdata(pdev, NULL);
return 0;
}
@@ -146,41 +190,16 @@ static struct platform_driver q40kbd_driver = {
.name = "q40kbd",
.owner = THIS_MODULE,
},
- .probe = q40kbd_probe,
.remove = __devexit_p(q40kbd_remove),
};
static int __init q40kbd_init(void)
{
- int error;
-
- if (!MACH_IS_Q40)
- return -ENODEV;
-
- error = platform_driver_register(&q40kbd_driver);
- if (error)
- return error;
-
- q40kbd_device = platform_device_alloc("q40kbd", -1);
- if (!q40kbd_device)
- goto err_unregister_driver;
-
- error = platform_device_add(q40kbd_device);
- if (error)
- goto err_free_device;
-
- return 0;
-
- err_free_device:
- platform_device_put(q40kbd_device);
- err_unregister_driver:
- platform_driver_unregister(&q40kbd_driver);
- return error;
+ return platform_driver_probe(&q40kbd_driver, q40kbd_probe);
}
static void __exit q40kbd_exit(void)
{
- platform_device_unregister(q40kbd_device);
platform_driver_unregister(&q40kbd_driver);
}
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index 2a97b7e76db..39205eddf71 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -176,7 +176,7 @@ static int wacom_parse_logical_collection(unsigned char *report,
/* Logical collection is only used by 3rd gen Bamboo Touch */
features->pktlen = WACOM_PKGLEN_BBTOUCH3;
- features->device_type = BTN_TOOL_DOUBLETAP;
+ features->device_type = BTN_TOOL_FINGER;
/*
* Stylus and Touch have same active area
@@ -286,12 +286,10 @@ static int wacom_parse_hid(struct usb_interface *intf,
if (features->type == TABLETPC2FG) {
/* need to reset back */
features->pktlen = WACOM_PKGLEN_TPC2FG;
- features->device_type = BTN_TOOL_DOUBLETAP;
}
if (features->type == BAMBOO_PT) {
/* need to reset back */
features->pktlen = WACOM_PKGLEN_BBTOUCH;
- features->device_type = BTN_TOOL_DOUBLETAP;
features->x_phy =
get_unaligned_le16(&report[i + 5]);
features->x_max =
@@ -325,7 +323,6 @@ static int wacom_parse_hid(struct usb_interface *intf,
if (features->type == TABLETPC2FG) {
/* need to reset back */
features->pktlen = WACOM_PKGLEN_TPC2FG;
- features->device_type = BTN_TOOL_DOUBLETAP;
features->y_max =
get_unaligned_le16(&report[i + 3]);
features->y_phy =
@@ -334,7 +331,6 @@ static int wacom_parse_hid(struct usb_interface *intf,
} else if (features->type == BAMBOO_PT) {
/* need to reset back */
features->pktlen = WACOM_PKGLEN_BBTOUCH;
- features->device_type = BTN_TOOL_DOUBLETAP;
features->y_phy =
get_unaligned_le16(&report[i + 3]);
features->y_max =
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 88672ec296c..07a1f218b5c 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -832,12 +832,24 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
dbg("wacom_tpc_irq: received report #%d", data[0]);
- if (len == WACOM_PKGLEN_TPC1FG || data[0] == WACOM_REPORT_TPC1FG)
- return wacom_tpc_single_touch(wacom, len);
- else if (data[0] == WACOM_REPORT_TPC2FG)
- return wacom_tpc_mt_touch(wacom);
- else if (data[0] == WACOM_REPORT_PENABLED)
- return wacom_tpc_pen(wacom);
+ switch (len) {
+ case WACOM_PKGLEN_TPC1FG:
+ return wacom_tpc_single_touch(wacom, len);
+
+ case WACOM_PKGLEN_TPC2FG:
+ return wacom_tpc_mt_touch(wacom);
+
+ default:
+ switch (data[0]) {
+ case WACOM_REPORT_TPC1FG:
+ case WACOM_REPORT_TPCHID:
+ case WACOM_REPORT_TPCST:
+ return wacom_tpc_single_touch(wacom, len);
+
+ case WACOM_REPORT_PENABLED:
+ return wacom_tpc_pen(wacom);
+ }
+ }
return 0;
}
@@ -1317,7 +1329,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
break;
case TABLETPC2FG:
- if (features->device_type == BTN_TOOL_DOUBLETAP) {
+ if (features->device_type == BTN_TOOL_FINGER) {
input_mt_init_slots(input_dev, 2);
input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
@@ -1366,7 +1378,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
- if (features->device_type == BTN_TOOL_DOUBLETAP) {
+ if (features->device_type == BTN_TOOL_FINGER) {
__set_bit(BTN_LEFT, input_dev->keybit);
__set_bit(BTN_FORWARD, input_dev->keybit);
__set_bit(BTN_BACK, input_dev->keybit);
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index 050acaefee7..4f0ba21b019 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -39,6 +39,8 @@
#define WACOM_REPORT_INTUOSPAD 12
#define WACOM_REPORT_TPC1FG 6
#define WACOM_REPORT_TPC2FG 13
+#define WACOM_REPORT_TPCHID 15
+#define WACOM_REPORT_TPCST 16
/* device quirks */
#define WACOM_QUIRK_MULTI_INPUT 0x0001
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 4af2a18eb3b..fc087b3c95c 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -139,7 +139,6 @@ config TOUCHSCREEN_CY8CTMG110
tristate "cy8ctmg110 touchscreen"
depends on I2C
depends on GPIOLIB
-
help
Say Y here if you have a cy8ctmg110 capacitive touchscreen on
an AAVA device.
@@ -149,6 +148,37 @@ config TOUCHSCREEN_CY8CTMG110
To compile this driver as a module, choose M here: the
module will be called cy8ctmg110_ts.
+config TOUCHSCREEN_CYTTSP_CORE
+ tristate "Cypress TTSP touchscreen"
+ help
+ Say Y here if you have a touchscreen using controller from
+ the Cypress TrueTouch(tm) Standard Product family connected
+ to your system. You will also need to select appropriate
+ bus connection below.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cyttsp_core.
+
+config TOUCHSCREEN_CYTTSP_I2C
+ tristate "support I2C bus connection"
+ depends on TOUCHSCREEN_CYTTSP_CORE && I2C
+ help
+ Say Y here if the touchscreen is connected via I2C bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cyttsp_i2c.
+
+config TOUCHSCREEN_CYTTSP_SPI
+ tristate "support SPI bus connection"
+ depends on TOUCHSCREEN_CYTTSP_CORE && SPI_MASTER
+ help
+ Say Y here if the touchscreen is connected via SPI bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cyttsp_spi.
+
config TOUCHSCREEN_DA9034
tristate "Touchscreen support for Dialog Semiconductor DA9034"
depends on PMIC_DA903X
@@ -430,6 +460,18 @@ config TOUCHSCREEN_TOUCHWIN
To compile this driver as a module, choose M here: the
module will be called touchwin.
+config TOUCHSCREEN_TI_TSCADC
+ tristate "TI Touchscreen Interface"
+ depends on ARCH_OMAP2PLUS
+ help
+ Say Y here if you have 4/5/8 wire touchscreen controller
+ to be connected to the ADC controller on your TI AM335x SoC.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ti_tscadc.
+
config TOUCHSCREEN_ATMEL_TSADCC
tristate "Atmel Touchscreen Interface"
depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
@@ -577,6 +619,7 @@ config TOUCHSCREEN_USB_COMPOSITE
- JASTEC USB Touch Controller/DigiTech DTR-02U
- Zytronic controllers
- Elo TouchSystems 2700 IntelliTouch
+ - EasyTouch USB Touch Controller from Data Modul
Have a look at <http://linux.chapter7.ch/touchkit/> for
a usage description and the required user-space stuff.
@@ -681,6 +724,14 @@ config TOUCHSCREEN_USB_NEXIO
bool "NEXIO/iNexio device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
+config TOUCHSCREEN_USB_EASYTOUCH
+ default y
+ bool "EasyTouch USB Touch controller device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+ help
+ Say Y here if you have a EasyTouch USB Touch controller device support.
+ If unsure, say N.
+
config TOUCHSCREEN_TOUCHIT213
tristate "Sahara TouchIT-213 touchscreen"
select SERIO
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 496091e8846..e748fb83775 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -16,8 +16,11 @@ obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o
obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
-obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o
+obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o
obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI) += cyttsp_spi.o
obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o
obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o
obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o
@@ -45,6 +48,7 @@ obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
+obj-$(CONFIG_TOUCHSCREEN_TI_TSCADC) += ti_tscadc.o
obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
diff --git a/drivers/input/touchscreen/atmel-wm97xx.c b/drivers/input/touchscreen/atmel-wm97xx.c
index 8034cbb20f7..c5c2dbb9386 100644
--- a/drivers/input/touchscreen/atmel-wm97xx.c
+++ b/drivers/input/touchscreen/atmel-wm97xx.c
@@ -392,9 +392,10 @@ static int __exit atmel_wm97xx_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
-static int atmel_wm97xx_suspend(struct platform_device *pdev, pm_message_t msg)
+#ifdef CONFIG_PM_SLEEP
+static int atmel_wm97xx_suspend(struct *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev);
ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT);
@@ -404,8 +405,9 @@ static int atmel_wm97xx_suspend(struct platform_device *pdev, pm_message_t msg)
return 0;
}
-static int atmel_wm97xx_resume(struct platform_device *pdev)
+static int atmel_wm97xx_resume(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev);
struct wm97xx *wm = atmel_wm97xx->wm;
@@ -416,18 +418,18 @@ static int atmel_wm97xx_resume(struct platform_device *pdev)
return 0;
}
-#else
-#define atmel_wm97xx_suspend NULL
-#define atmel_wm97xx_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(atmel_wm97xx_pm_ops,
+ atmel_wm97xx_suspend, atmel_wm97xx_resume);
+
static struct platform_driver atmel_wm97xx_driver = {
.remove = __exit_p(atmel_wm97xx_remove),
.driver = {
- .name = "wm97xx-touch",
+ .name = "wm97xx-touch",
+ .owner = THIS_MODULE,
+ .pm = &atmel_wm97xx_pm_ops,
},
- .suspend = atmel_wm97xx_suspend,
- .resume = atmel_wm97xx_resume,
};
static int __init atmel_wm97xx_init(void)
diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c
new file mode 100644
index 00000000000..f030d9ec795
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_core.c
@@ -0,0 +1,625 @@
+/*
+ * Core Source for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
+ * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+#include "cyttsp_core.h"
+
+/* Bootloader number of command keys */
+#define CY_NUM_BL_KEYS 8
+
+/* helpers */
+#define GET_NUM_TOUCHES(x) ((x) & 0x0F)
+#define IS_LARGE_AREA(x) (((x) & 0x10) >> 4)
+#define IS_BAD_PKT(x) ((x) & 0x20)
+#define IS_VALID_APP(x) ((x) & 0x01)
+#define IS_OPERATIONAL_ERR(x) ((x) & 0x3F)
+#define GET_HSTMODE(reg) (((reg) & 0x70) >> 4)
+#define GET_BOOTLOADERMODE(reg) (((reg) & 0x10) >> 4)
+
+#define CY_REG_BASE 0x00
+#define CY_REG_ACT_DIST 0x1E
+#define CY_REG_ACT_INTRVL 0x1D
+#define CY_REG_TCH_TMOUT (CY_REG_ACT_INTRVL + 1)
+#define CY_REG_LP_INTRVL (CY_REG_TCH_TMOUT + 1)
+#define CY_MAXZ 255
+#define CY_DELAY_DFLT 20 /* ms */
+#define CY_DELAY_MAX 500
+#define CY_ACT_DIST_DFLT 0xF8
+#define CY_HNDSHK_BIT 0x80
+/* device mode bits */
+#define CY_OPERATE_MODE 0x00
+#define CY_SYSINFO_MODE 0x10
+/* power mode select bits */
+#define CY_SOFT_RESET_MODE 0x01 /* return to Bootloader mode */
+#define CY_DEEP_SLEEP_MODE 0x02
+#define CY_LOW_POWER_MODE 0x04
+
+/* Slots management */
+#define CY_MAX_FINGER 4
+#define CY_MAX_ID 16
+
+static const u8 bl_command[] = {
+ 0x00, /* file offset */
+ 0xFF, /* command */
+ 0xA5, /* exit bootloader command */
+ 0, 1, 2, 3, 4, 5, 6, 7 /* default keys */
+};
+
+static int ttsp_read_block_data(struct cyttsp *ts, u8 command,
+ u8 length, void *buf)
+{
+ int error;
+ int tries;
+
+ for (tries = 0; tries < CY_NUM_RETRY; tries++) {
+ error = ts->bus_ops->read(ts, command, length, buf);
+ if (!error)
+ return 0;
+
+ msleep(CY_DELAY_DFLT);
+ }
+
+ return -EIO;
+}
+
+static int ttsp_write_block_data(struct cyttsp *ts, u8 command,
+ u8 length, void *buf)
+{
+ int error;
+ int tries;
+
+ for (tries = 0; tries < CY_NUM_RETRY; tries++) {
+ error = ts->bus_ops->write(ts, command, length, buf);
+ if (!error)
+ return 0;
+
+ msleep(CY_DELAY_DFLT);
+ }
+
+ return -EIO;
+}
+
+static int ttsp_send_command(struct cyttsp *ts, u8 cmd)
+{
+ return ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd);
+}
+
+static int cyttsp_load_bl_regs(struct cyttsp *ts)
+{
+ memset(&ts->bl_data, 0, sizeof(ts->bl_data));
+ ts->bl_data.bl_status = 0x10;
+
+ return ttsp_read_block_data(ts, CY_REG_BASE,
+ sizeof(ts->bl_data), &ts->bl_data);
+}
+
+static int cyttsp_exit_bl_mode(struct cyttsp *ts)
+{
+ int error;
+ u8 bl_cmd[sizeof(bl_command)];
+
+ memcpy(bl_cmd, bl_command, sizeof(bl_command));
+ if (ts->pdata->bl_keys)
+ memcpy(&bl_cmd[sizeof(bl_command) - CY_NUM_BL_KEYS],
+ ts->pdata->bl_keys, sizeof(bl_command));
+
+ error = ttsp_write_block_data(ts, CY_REG_BASE,
+ sizeof(bl_cmd), bl_cmd);
+ if (error)
+ return error;
+
+ /* wait for TTSP Device to complete the operation */
+ msleep(CY_DELAY_DFLT);
+
+ error = cyttsp_load_bl_regs(ts);
+ if (error)
+ return error;
+
+ if (GET_BOOTLOADERMODE(ts->bl_data.bl_status))
+ return -EIO;
+
+ return 0;
+}
+
+static int cyttsp_set_operational_mode(struct cyttsp *ts)
+{
+ int error;
+
+ error = ttsp_send_command(ts, CY_OPERATE_MODE);
+ if (error)
+ return error;
+
+ /* wait for TTSP Device to complete switch to Operational mode */
+ error = ttsp_read_block_data(ts, CY_REG_BASE,
+ sizeof(ts->xy_data), &ts->xy_data);
+ if (error)
+ return error;
+
+ return ts->xy_data.act_dist == CY_ACT_DIST_DFLT ? -EIO : 0;
+}
+
+static int cyttsp_set_sysinfo_mode(struct cyttsp *ts)
+{
+ int error;
+
+ memset(&ts->sysinfo_data, 0, sizeof(ts->sysinfo_data));
+
+ /* switch to sysinfo mode */
+ error = ttsp_send_command(ts, CY_SYSINFO_MODE);
+ if (error)
+ return error;
+
+ /* read sysinfo registers */
+ msleep(CY_DELAY_DFLT);
+ error = ttsp_read_block_data(ts, CY_REG_BASE, sizeof(ts->sysinfo_data),
+ &ts->sysinfo_data);
+ if (error)
+ return error;
+
+ if (!ts->sysinfo_data.tts_verh && !ts->sysinfo_data.tts_verl)
+ return -EIO;
+
+ return 0;
+}
+
+static int cyttsp_set_sysinfo_regs(struct cyttsp *ts)
+{
+ int retval = 0;
+
+ if (ts->pdata->act_intrvl != CY_ACT_INTRVL_DFLT ||
+ ts->pdata->tch_tmout != CY_TCH_TMOUT_DFLT ||
+ ts->pdata->lp_intrvl != CY_LP_INTRVL_DFLT) {
+
+ u8 intrvl_ray[] = {
+ ts->pdata->act_intrvl,
+ ts->pdata->tch_tmout,
+ ts->pdata->lp_intrvl
+ };
+
+ /* set intrvl registers */
+ retval = ttsp_write_block_data(ts, CY_REG_ACT_INTRVL,
+ sizeof(intrvl_ray), intrvl_ray);
+ msleep(CY_DELAY_DFLT);
+ }
+
+ return retval;
+}
+
+static int cyttsp_soft_reset(struct cyttsp *ts)
+{
+ unsigned long timeout;
+ int retval;
+
+ /* wait for interrupt to set ready completion */
+ INIT_COMPLETION(ts->bl_ready);
+ ts->state = CY_BL_STATE;
+
+ enable_irq(ts->irq);
+
+ retval = ttsp_send_command(ts, CY_SOFT_RESET_MODE);
+ if (retval)
+ goto out;
+
+ timeout = wait_for_completion_timeout(&ts->bl_ready,
+ msecs_to_jiffies(CY_DELAY_DFLT * CY_DELAY_MAX));
+ retval = timeout ? 0 : -EIO;
+
+out:
+ ts->state = CY_IDLE_STATE;
+ disable_irq(ts->irq);
+ return retval;
+}
+
+static int cyttsp_act_dist_setup(struct cyttsp *ts)
+{
+ u8 act_dist_setup = ts->pdata->act_dist;
+
+ /* Init gesture; active distance setup */
+ return ttsp_write_block_data(ts, CY_REG_ACT_DIST,
+ sizeof(act_dist_setup), &act_dist_setup);
+}
+
+static void cyttsp_extract_track_ids(struct cyttsp_xydata *xy_data, int *ids)
+{
+ ids[0] = xy_data->touch12_id >> 4;
+ ids[1] = xy_data->touch12_id & 0xF;
+ ids[2] = xy_data->touch34_id >> 4;
+ ids[3] = xy_data->touch34_id & 0xF;
+}
+
+static const struct cyttsp_tch *cyttsp_get_tch(struct cyttsp_xydata *xy_data,
+ int idx)
+{
+ switch (idx) {
+ case 0:
+ return &xy_data->tch1;
+ case 1:
+ return &xy_data->tch2;
+ case 2:
+ return &xy_data->tch3;
+ case 3:
+ return &xy_data->tch4;
+ default:
+ return NULL;
+ }
+}
+
+static void cyttsp_report_tchdata(struct cyttsp *ts)
+{
+ struct cyttsp_xydata *xy_data = &ts->xy_data;
+ struct input_dev *input = ts->input;
+ int num_tch = GET_NUM_TOUCHES(xy_data->tt_stat);
+ const struct cyttsp_tch *tch;
+ int ids[CY_MAX_ID];
+ int i;
+ DECLARE_BITMAP(used, CY_MAX_ID);
+
+ if (IS_LARGE_AREA(xy_data->tt_stat) == 1) {
+ /* terminate all active tracks */
+ num_tch = 0;
+ dev_dbg(ts->dev, "%s: Large area detected\n", __func__);
+ } else if (num_tch > CY_MAX_FINGER) {
+ /* terminate all active tracks */
+ num_tch = 0;
+ dev_dbg(ts->dev, "%s: Num touch error detected\n", __func__);
+ } else if (IS_BAD_PKT(xy_data->tt_mode)) {
+ /* terminate all active tracks */
+ num_tch = 0;
+ dev_dbg(ts->dev, "%s: Invalid buffer detected\n", __func__);
+ }
+
+ cyttsp_extract_track_ids(xy_data, ids);
+
+ bitmap_zero(used, CY_MAX_ID);
+
+ for (i = 0; i < num_tch; i++) {
+ tch = cyttsp_get_tch(xy_data, i);
+
+ input_mt_slot(input, ids[i]);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
+ input_report_abs(input, ABS_MT_POSITION_X, be16_to_cpu(tch->x));
+ input_report_abs(input, ABS_MT_POSITION_Y, be16_to_cpu(tch->y));
+ input_report_abs(input, ABS_MT_TOUCH_MAJOR, tch->z);
+
+ __set_bit(ids[i], used);
+ }
+
+ for (i = 0; i < CY_MAX_ID; i++) {
+ if (test_bit(i, used))
+ continue;
+
+ input_mt_slot(input, i);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, false);
+ }
+
+ input_sync(input);
+}
+
+static irqreturn_t cyttsp_irq(int irq, void *handle)
+{
+ struct cyttsp *ts = handle;
+ int error;
+
+ if (unlikely(ts->state == CY_BL_STATE)) {
+ complete(&ts->bl_ready);
+ goto out;
+ }
+
+ /* Get touch data from CYTTSP device */
+ error = ttsp_read_block_data(ts, CY_REG_BASE,
+ sizeof(struct cyttsp_xydata), &ts->xy_data);
+ if (error)
+ goto out;
+
+ /* provide flow control handshake */
+ if (ts->pdata->use_hndshk) {
+ error = ttsp_send_command(ts,
+ ts->xy_data.hst_mode ^ CY_HNDSHK_BIT);
+ if (error)
+ goto out;
+ }
+
+ if (unlikely(ts->state == CY_IDLE_STATE))
+ goto out;
+
+ if (GET_BOOTLOADERMODE(ts->xy_data.tt_mode)) {
+ /*
+ * TTSP device has reset back to bootloader mode.
+ * Restore to operational mode.
+ */
+ error = cyttsp_exit_bl_mode(ts);
+ if (error) {
+ dev_err(ts->dev,
+ "Could not return to operational mode, err: %d\n",
+ error);
+ ts->state = CY_IDLE_STATE;
+ }
+ } else {
+ cyttsp_report_tchdata(ts);
+ }
+
+out:
+ return IRQ_HANDLED;
+}
+
+static int cyttsp_power_on(struct cyttsp *ts)
+{
+ int error;
+
+ error = cyttsp_soft_reset(ts);
+ if (error)
+ return error;
+
+ error = cyttsp_load_bl_regs(ts);
+ if (error)
+ return error;
+
+ if (GET_BOOTLOADERMODE(ts->bl_data.bl_status) &&
+ IS_VALID_APP(ts->bl_data.bl_status)) {
+ error = cyttsp_exit_bl_mode(ts);
+ if (error)
+ return error;
+ }
+
+ if (GET_HSTMODE(ts->bl_data.bl_file) != CY_OPERATE_MODE ||
+ IS_OPERATIONAL_ERR(ts->bl_data.bl_status)) {
+ return -ENODEV;
+ }
+
+ error = cyttsp_set_sysinfo_mode(ts);
+ if (error)
+ return error;
+
+ error = cyttsp_set_sysinfo_regs(ts);
+ if (error)
+ return error;
+
+ error = cyttsp_set_operational_mode(ts);
+ if (error)
+ return error;
+
+ /* init active distance */
+ error = cyttsp_act_dist_setup(ts);
+ if (error)
+ return error;
+
+ ts->state = CY_ACTIVE_STATE;
+
+ return 0;
+}
+
+static int cyttsp_enable(struct cyttsp *ts)
+{
+ int error;
+
+ /*
+ * The device firmware can wake on an I2C or SPI memory slave
+ * address match. So just reading a register is sufficient to
+ * wake up the device. The first read attempt will fail but it
+ * will wake it up making the second read attempt successful.
+ */
+ error = ttsp_read_block_data(ts, CY_REG_BASE,
+ sizeof(ts->xy_data), &ts->xy_data);
+ if (error)
+ return error;
+
+ if (GET_HSTMODE(ts->xy_data.hst_mode))
+ return -EIO;
+
+ enable_irq(ts->irq);
+
+ return 0;
+}
+
+static int cyttsp_disable(struct cyttsp *ts)
+{
+ int error;
+
+ error = ttsp_send_command(ts, CY_LOW_POWER_MODE);
+ if (error)
+ return error;
+
+ disable_irq(ts->irq);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int cyttsp_suspend(struct device *dev)
+{
+ struct cyttsp *ts = dev_get_drvdata(dev);
+ int retval = 0;
+
+ mutex_lock(&ts->input->mutex);
+
+ if (ts->input->users) {
+ retval = cyttsp_disable(ts);
+ if (retval == 0)
+ ts->suspended = true;
+ }
+
+ mutex_unlock(&ts->input->mutex);
+
+ return retval;
+}
+
+static int cyttsp_resume(struct device *dev)
+{
+ struct cyttsp *ts = dev_get_drvdata(dev);
+
+ mutex_lock(&ts->input->mutex);
+
+ if (ts->input->users)
+ cyttsp_enable(ts);
+
+ ts->suspended = false;
+
+ mutex_unlock(&ts->input->mutex);
+
+ return 0;
+}
+
+#endif
+
+SIMPLE_DEV_PM_OPS(cyttsp_pm_ops, cyttsp_suspend, cyttsp_resume);
+EXPORT_SYMBOL_GPL(cyttsp_pm_ops);
+
+static int cyttsp_open(struct input_dev *dev)
+{
+ struct cyttsp *ts = input_get_drvdata(dev);
+ int retval = 0;
+
+ if (!ts->suspended)
+ retval = cyttsp_enable(ts);
+
+ return retval;
+}
+
+static void cyttsp_close(struct input_dev *dev)
+{
+ struct cyttsp *ts = input_get_drvdata(dev);
+
+ if (!ts->suspended)
+ cyttsp_disable(ts);
+}
+
+struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
+ struct device *dev, int irq, size_t xfer_buf_size)
+{
+ const struct cyttsp_platform_data *pdata = dev->platform_data;
+ struct cyttsp *ts;
+ struct input_dev *input_dev;
+ int error;
+
+ if (!pdata || !pdata->name || irq <= 0) {
+ error = -EINVAL;
+ goto err_out;
+ }
+
+ ts = kzalloc(sizeof(*ts) + xfer_buf_size, GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!ts || !input_dev) {
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ ts->dev = dev;
+ ts->input = input_dev;
+ ts->pdata = dev->platform_data;
+ ts->bus_ops = bus_ops;
+ ts->irq = irq;
+
+ init_completion(&ts->bl_ready);
+ snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
+
+ if (pdata->init) {
+ error = pdata->init();
+ if (error) {
+ dev_err(ts->dev, "platform init failed, err: %d\n",
+ error);
+ goto err_free_mem;
+ }
+ }
+
+ input_dev->name = pdata->name;
+ input_dev->phys = ts->phys;
+ input_dev->id.bustype = bus_ops->bustype;
+ input_dev->dev.parent = ts->dev;
+
+ input_dev->open = cyttsp_open;
+ input_dev->close = cyttsp_close;
+
+ input_set_drvdata(input_dev, ts);
+
+ __set_bit(EV_ABS, input_dev->evbit);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+ 0, pdata->maxx, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+ 0, pdata->maxy, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
+ 0, CY_MAXZ, 0, 0);
+
+ input_mt_init_slots(input_dev, CY_MAX_ID);
+
+ error = request_threaded_irq(ts->irq, NULL, cyttsp_irq,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ pdata->name, ts);
+ if (error) {
+ dev_err(ts->dev, "failed to request IRQ %d, err: %d\n",
+ ts->irq, error);
+ goto err_platform_exit;
+ }
+
+ disable_irq(ts->irq);
+
+ error = cyttsp_power_on(ts);
+ if (error)
+ goto err_free_irq;
+
+ error = input_register_device(input_dev);
+ if (error) {
+ dev_err(ts->dev, "failed to register input device: %d\n",
+ error);
+ goto err_free_irq;
+ }
+
+ return ts;
+
+err_free_irq:
+ free_irq(ts->irq, ts);
+err_platform_exit:
+ if (pdata->exit)
+ pdata->exit();
+err_free_mem:
+ input_free_device(input_dev);
+ kfree(ts);
+err_out:
+ return ERR_PTR(error);
+}
+EXPORT_SYMBOL_GPL(cyttsp_probe);
+
+void cyttsp_remove(struct cyttsp *ts)
+{
+ free_irq(ts->irq, ts);
+ input_unregister_device(ts->input);
+ if (ts->pdata->exit)
+ ts->pdata->exit();
+ kfree(ts);
+}
+EXPORT_SYMBOL_GPL(cyttsp_remove);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver core");
+MODULE_AUTHOR("Cypress");
diff --git a/drivers/input/touchscreen/cyttsp_core.h b/drivers/input/touchscreen/cyttsp_core.h
new file mode 100644
index 00000000000..1aa3c6967e7
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_core.h
@@ -0,0 +1,149 @@
+/*
+ * Header file for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
+ * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+
+#ifndef __CYTTSP_CORE_H__
+#define __CYTTSP_CORE_H__
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/input/cyttsp.h>
+
+#define CY_NUM_RETRY 16 /* max number of retries for read ops */
+
+struct cyttsp_tch {
+ __be16 x, y;
+ u8 z;
+} __packed;
+
+/* TrueTouch Standard Product Gen3 interface definition */
+struct cyttsp_xydata {
+ u8 hst_mode;
+ u8 tt_mode;
+ u8 tt_stat;
+ struct cyttsp_tch tch1;
+ u8 touch12_id;
+ struct cyttsp_tch tch2;
+ u8 gest_cnt;
+ u8 gest_id;
+ struct cyttsp_tch tch3;
+ u8 touch34_id;
+ struct cyttsp_tch tch4;
+ u8 tt_undef[3];
+ u8 act_dist;
+ u8 tt_reserved;
+} __packed;
+
+
+/* TTSP System Information interface definition */
+struct cyttsp_sysinfo_data {
+ u8 hst_mode;
+ u8 mfg_cmd;
+ u8 mfg_stat;
+ u8 cid[3];
+ u8 tt_undef1;
+ u8 uid[8];
+ u8 bl_verh;
+ u8 bl_verl;
+ u8 tts_verh;
+ u8 tts_verl;
+ u8 app_idh;
+ u8 app_idl;
+ u8 app_verh;
+ u8 app_verl;
+ u8 tt_undef[5];
+ u8 scn_typ;
+ u8 act_intrvl;
+ u8 tch_tmout;
+ u8 lp_intrvl;
+};
+
+/* TTSP Bootloader Register Map interface definition */
+#define CY_BL_CHKSUM_OK 0x01
+struct cyttsp_bootloader_data {
+ u8 bl_file;
+ u8 bl_status;
+ u8 bl_error;
+ u8 blver_hi;
+ u8 blver_lo;
+ u8 bld_blver_hi;
+ u8 bld_blver_lo;
+ u8 ttspver_hi;
+ u8 ttspver_lo;
+ u8 appid_hi;
+ u8 appid_lo;
+ u8 appver_hi;
+ u8 appver_lo;
+ u8 cid_0;
+ u8 cid_1;
+ u8 cid_2;
+};
+
+struct cyttsp;
+
+struct cyttsp_bus_ops {
+ u16 bustype;
+ int (*write)(struct cyttsp *ts,
+ u8 addr, u8 length, const void *values);
+ int (*read)(struct cyttsp *ts, u8 addr, u8 length, void *values);
+};
+
+enum cyttsp_state {
+ CY_IDLE_STATE,
+ CY_ACTIVE_STATE,
+ CY_BL_STATE,
+};
+
+struct cyttsp {
+ struct device *dev;
+ int irq;
+ struct input_dev *input;
+ char phys[32];
+ const struct cyttsp_platform_data *pdata;
+ const struct cyttsp_bus_ops *bus_ops;
+ struct cyttsp_bootloader_data bl_data;
+ struct cyttsp_sysinfo_data sysinfo_data;
+ struct cyttsp_xydata xy_data;
+ struct completion bl_ready;
+ enum cyttsp_state state;
+ bool suspended;
+
+ u8 xfer_buf[] ____cacheline_aligned;
+};
+
+struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
+ struct device *dev, int irq, size_t xfer_buf_size);
+void cyttsp_remove(struct cyttsp *ts);
+
+extern const struct dev_pm_ops cyttsp_pm_ops;
+
+#endif /* __CYTTSP_CORE_H__ */
diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c
new file mode 100644
index 00000000000..c7110cc06b9
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_i2c.c
@@ -0,0 +1,146 @@
+/*
+ * Source for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
+ * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+#include "cyttsp_core.h"
+
+#include <linux/i2c.h>
+#include <linux/input.h>
+
+#define CY_I2C_DATA_SIZE 128
+
+static int cyttsp_i2c_read_block_data(struct cyttsp *ts,
+ u8 addr, u8 length, void *values)
+{
+ struct i2c_client *client = to_i2c_client(ts->dev);
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = &addr,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = length,
+ .buf = values,
+ },
+ };
+ int retval;
+
+ retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (retval < 0)
+ return retval;
+
+ return retval != ARRAY_SIZE(msgs) ? -EIO : 0;
+}
+
+static int cyttsp_i2c_write_block_data(struct cyttsp *ts,
+ u8 addr, u8 length, const void *values)
+{
+ struct i2c_client *client = to_i2c_client(ts->dev);
+ int retval;
+
+ ts->xfer_buf[0] = addr;
+ memcpy(&ts->xfer_buf[1], values, length);
+
+ retval = i2c_master_send(client, ts->xfer_buf, length + 1);
+
+ return retval < 0 ? retval : 0;
+}
+
+static const struct cyttsp_bus_ops cyttsp_i2c_bus_ops = {
+ .bustype = BUS_I2C,
+ .write = cyttsp_i2c_write_block_data,
+ .read = cyttsp_i2c_read_block_data,
+};
+
+static int __devinit cyttsp_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct cyttsp *ts;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "I2C functionality not Supported\n");
+ return -EIO;
+ }
+
+ ts = cyttsp_probe(&cyttsp_i2c_bus_ops, &client->dev, client->irq,
+ CY_I2C_DATA_SIZE);
+
+ if (IS_ERR(ts))
+ return PTR_ERR(ts);
+
+ i2c_set_clientdata(client, ts);
+
+ return 0;
+}
+
+static int __devexit cyttsp_i2c_remove(struct i2c_client *client)
+{
+ struct cyttsp *ts = i2c_get_clientdata(client);
+
+ cyttsp_remove(ts);
+
+ return 0;
+}
+
+static const struct i2c_device_id cyttsp_i2c_id[] = {
+ { CY_I2C_NAME, 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id);
+
+static struct i2c_driver cyttsp_i2c_driver = {
+ .driver = {
+ .name = CY_I2C_NAME,
+ .owner = THIS_MODULE,
+ .pm = &cyttsp_pm_ops,
+ },
+ .probe = cyttsp_i2c_probe,
+ .remove = __devexit_p(cyttsp_i2c_remove),
+ .id_table = cyttsp_i2c_id,
+};
+
+static int __init cyttsp_i2c_init(void)
+{
+ return i2c_add_driver(&cyttsp_i2c_driver);
+}
+module_init(cyttsp_i2c_init);
+
+static void __exit cyttsp_i2c_exit(void)
+{
+ return i2c_del_driver(&cyttsp_i2c_driver);
+}
+module_exit(cyttsp_i2c_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver");
+MODULE_AUTHOR("Cypress");
+MODULE_ALIAS("i2c:cyttsp");
diff --git a/drivers/input/touchscreen/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp_spi.c
new file mode 100644
index 00000000000..9db5f8754d1
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_spi.c
@@ -0,0 +1,210 @@
+/*
+ * Source for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) SPI touchscreen driver.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
+ * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+#include "cyttsp_core.h"
+
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/spi/spi.h>
+
+#define CY_SPI_WR_OP 0x00 /* r/~w */
+#define CY_SPI_RD_OP 0x01
+#define CY_SPI_CMD_BYTES 4
+#define CY_SPI_SYNC_BYTE 2
+#define CY_SPI_SYNC_ACK1 0x62 /* from protocol v.2 */
+#define CY_SPI_SYNC_ACK2 0x9D /* from protocol v.2 */
+#define CY_SPI_DATA_SIZE 128
+#define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE)
+#define CY_SPI_BITS_PER_WORD 8
+
+static int cyttsp_spi_xfer(struct cyttsp *ts,
+ u8 op, u8 reg, u8 *buf, int length)
+{
+ struct spi_device *spi = to_spi_device(ts->dev);
+ struct spi_message msg;
+ struct spi_transfer xfer[2];
+ u8 *wr_buf = &ts->xfer_buf[0];
+ u8 *rd_buf = &ts->xfer_buf[CY_SPI_DATA_BUF_SIZE];
+ int retval;
+ int i;
+
+ if (length > CY_SPI_DATA_SIZE) {
+ dev_err(ts->dev, "%s: length %d is too big.\n",
+ __func__, length);
+ return -EINVAL;
+ }
+
+ memset(wr_buf, 0, CY_SPI_DATA_BUF_SIZE);
+ memset(rd_buf, 0, CY_SPI_DATA_BUF_SIZE);
+
+ wr_buf[0] = 0x00; /* header byte 0 */
+ wr_buf[1] = 0xFF; /* header byte 1 */
+ wr_buf[2] = reg; /* reg index */
+ wr_buf[3] = op; /* r/~w */
+ if (op == CY_SPI_WR_OP)
+ memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length);
+
+ memset(xfer, 0, sizeof(xfer));
+ spi_message_init(&msg);
+
+ /*
+ We set both TX and RX buffers because Cypress TTSP
+ requires full duplex operation.
+ */
+ xfer[0].tx_buf = wr_buf;
+ xfer[0].rx_buf = rd_buf;
+ switch (op) {
+ case CY_SPI_WR_OP:
+ xfer[0].len = length + CY_SPI_CMD_BYTES;
+ spi_message_add_tail(&xfer[0], &msg);
+ break;
+
+ case CY_SPI_RD_OP:
+ xfer[0].len = CY_SPI_CMD_BYTES;
+ spi_message_add_tail(&xfer[0], &msg);
+
+ xfer[1].rx_buf = buf;
+ xfer[1].len = length;
+ spi_message_add_tail(&xfer[1], &msg);
+ break;
+
+ default:
+ dev_err(ts->dev, "%s: bad operation code=%d\n", __func__, op);
+ return -EINVAL;
+ }
+
+ retval = spi_sync(spi, &msg);
+ if (retval < 0) {
+ dev_dbg(ts->dev, "%s: spi_sync() error %d, len=%d, op=%d\n",
+ __func__, retval, xfer[1].len, op);
+
+ /*
+ * do not return here since was a bad ACK sequence
+ * let the following ACK check handle any errors and
+ * allow silent retries
+ */
+ }
+
+ if (rd_buf[CY_SPI_SYNC_BYTE] != CY_SPI_SYNC_ACK1 ||
+ rd_buf[CY_SPI_SYNC_BYTE + 1] != CY_SPI_SYNC_ACK2) {
+
+ dev_dbg(ts->dev, "%s: operation %d failed\n", __func__, op);
+
+ for (i = 0; i < CY_SPI_CMD_BYTES; i++)
+ dev_dbg(ts->dev, "%s: test rd_buf[%d]:0x%02x\n",
+ __func__, i, rd_buf[i]);
+ for (i = 0; i < length; i++)
+ dev_dbg(ts->dev, "%s: test buf[%d]:0x%02x\n",
+ __func__, i, buf[i]);
+
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int cyttsp_spi_read_block_data(struct cyttsp *ts,
+ u8 addr, u8 length, void *data)
+{
+ return cyttsp_spi_xfer(ts, CY_SPI_RD_OP, addr, data, length);
+}
+
+static int cyttsp_spi_write_block_data(struct cyttsp *ts,
+ u8 addr, u8 length, const void *data)
+{
+ return cyttsp_spi_xfer(ts, CY_SPI_WR_OP, addr, (void *)data, length);
+}
+
+static const struct cyttsp_bus_ops cyttsp_spi_bus_ops = {
+ .bustype = BUS_SPI,
+ .write = cyttsp_spi_write_block_data,
+ .read = cyttsp_spi_read_block_data,
+};
+
+static int __devinit cyttsp_spi_probe(struct spi_device *spi)
+{
+ struct cyttsp *ts;
+ int error;
+
+ /* Set up SPI*/
+ spi->bits_per_word = CY_SPI_BITS_PER_WORD;
+ spi->mode = SPI_MODE_0;
+ error = spi_setup(spi);
+ if (error < 0) {
+ dev_err(&spi->dev, "%s: SPI setup error %d\n",
+ __func__, error);
+ return error;
+ }
+
+ ts = cyttsp_probe(&cyttsp_spi_bus_ops, &spi->dev, spi->irq,
+ CY_SPI_DATA_BUF_SIZE * 2);
+ if (IS_ERR(ts))
+ return PTR_ERR(ts);
+
+ spi_set_drvdata(spi, ts);
+
+ return 0;
+}
+
+static int __devexit cyttsp_spi_remove(struct spi_device *spi)
+{
+ struct cyttsp *ts = spi_get_drvdata(spi);
+
+ cyttsp_remove(ts);
+
+ return 0;
+}
+
+static struct spi_driver cyttsp_spi_driver = {
+ .driver = {
+ .name = CY_SPI_NAME,
+ .owner = THIS_MODULE,
+ .pm = &cyttsp_pm_ops,
+ },
+ .probe = cyttsp_spi_probe,
+ .remove = __devexit_p(cyttsp_spi_remove),
+};
+
+static int __init cyttsp_spi_init(void)
+{
+ return spi_register_driver(&cyttsp_spi_driver);
+}
+module_init(cyttsp_spi_init);
+
+static void __exit cyttsp_spi_exit(void)
+{
+ spi_unregister_driver(&cyttsp_spi_driver);
+}
+module_exit(cyttsp_spi_exit);
+
+MODULE_ALIAS("spi:cyttsp");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver");
+MODULE_AUTHOR("Cypress");
+MODULE_ALIAS("spi:cyttsp");
diff --git a/drivers/input/touchscreen/ti_tscadc.c b/drivers/input/touchscreen/ti_tscadc.c
new file mode 100644
index 00000000000..d229c741d54
--- /dev/null
+++ b/drivers/input/touchscreen/ti_tscadc.c
@@ -0,0 +1,486 @@
+/*
+ * TI Touch Screen driver
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/input/ti_tscadc.h>
+#include <linux/delay.h>
+
+#define REG_IRQEOI 0x020
+#define REG_RAWIRQSTATUS 0x024
+#define REG_IRQSTATUS 0x028
+#define REG_IRQENABLE 0x02C
+#define REG_IRQWAKEUP 0x034
+#define REG_CTRL 0x040
+#define REG_ADCFSM 0x044
+#define REG_CLKDIV 0x04C
+#define REG_SE 0x054
+#define REG_IDLECONFIG 0x058
+#define REG_CHARGECONFIG 0x05C
+#define REG_CHARGEDELAY 0x060
+#define REG_STEPCONFIG(n) (0x64 + ((n - 1) * 8))
+#define REG_STEPDELAY(n) (0x68 + ((n - 1) * 8))
+#define REG_STEPCONFIG13 0x0C4
+#define REG_STEPDELAY13 0x0C8
+#define REG_STEPCONFIG14 0x0CC
+#define REG_STEPDELAY14 0x0D0
+#define REG_FIFO0CNT 0xE4
+#define REG_FIFO1THR 0xF4
+#define REG_FIFO0 0x100
+#define REG_FIFO1 0x200
+
+/* Register Bitfields */
+#define IRQWKUP_ENB BIT(0)
+#define STPENB_STEPENB 0x7FFF
+#define IRQENB_FIFO1THRES BIT(5)
+#define IRQENB_PENUP BIT(9)
+#define STEPCONFIG_MODE_HWSYNC 0x2
+#define STEPCONFIG_SAMPLES_AVG (1 << 4)
+#define STEPCONFIG_XPP (1 << 5)
+#define STEPCONFIG_XNN (1 << 6)
+#define STEPCONFIG_YPP (1 << 7)
+#define STEPCONFIG_YNN (1 << 8)
+#define STEPCONFIG_XNP (1 << 9)
+#define STEPCONFIG_YPN (1 << 10)
+#define STEPCONFIG_INM (1 << 18)
+#define STEPCONFIG_INP (1 << 20)
+#define STEPCONFIG_INP_5 (1 << 21)
+#define STEPCONFIG_FIFO1 (1 << 26)
+#define STEPCONFIG_OPENDLY 0xff
+#define STEPCONFIG_Z1 (3 << 19)
+#define STEPIDLE_INP (1 << 22)
+#define STEPCHARGE_RFP (1 << 12)
+#define STEPCHARGE_INM (1 << 15)
+#define STEPCHARGE_INP (1 << 19)
+#define STEPCHARGE_RFM (1 << 23)
+#define STEPCHARGE_DELAY 0x1
+#define CNTRLREG_TSCSSENB (1 << 0)
+#define CNTRLREG_STEPID (1 << 1)
+#define CNTRLREG_STEPCONFIGWRT (1 << 2)
+#define CNTRLREG_4WIRE (1 << 5)
+#define CNTRLREG_5WIRE (1 << 6)
+#define CNTRLREG_8WIRE (3 << 5)
+#define CNTRLREG_TSCENB (1 << 7)
+#define ADCFSM_STEPID 0x10
+
+#define SEQ_SETTLE 275
+#define ADC_CLK 3000000
+#define MAX_12BIT ((1 << 12) - 1)
+#define TSCADC_DELTA_X 15
+#define TSCADC_DELTA_Y 15
+
+struct tscadc {
+ struct input_dev *input;
+ struct clk *tsc_ick;
+ void __iomem *tsc_base;
+ unsigned int irq;
+ unsigned int wires;
+ unsigned int x_plate_resistance;
+ bool pen_down;
+};
+
+static unsigned int tscadc_readl(struct tscadc *ts, unsigned int reg)
+{
+ return readl(ts->tsc_base + reg);
+}
+
+static void tscadc_writel(struct tscadc *tsc, unsigned int reg,
+ unsigned int val)
+{
+ writel(val, tsc->tsc_base + reg);
+}
+
+static void tscadc_step_config(struct tscadc *ts_dev)
+{
+ unsigned int config;
+ int i;
+
+ /* Configure the Step registers */
+
+ config = STEPCONFIG_MODE_HWSYNC |
+ STEPCONFIG_SAMPLES_AVG | STEPCONFIG_XPP;
+ switch (ts_dev->wires) {
+ case 4:
+ config |= STEPCONFIG_INP | STEPCONFIG_XNN;
+ break;
+ case 5:
+ config |= STEPCONFIG_YNN |
+ STEPCONFIG_INP_5 | STEPCONFIG_XNN |
+ STEPCONFIG_YPP;
+ break;
+ case 8:
+ config |= STEPCONFIG_INP | STEPCONFIG_XNN;
+ break;
+ }
+
+ for (i = 1; i < 7; i++) {
+ tscadc_writel(ts_dev, REG_STEPCONFIG(i), config);
+ tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
+ }
+
+ config = 0;
+ config = STEPCONFIG_MODE_HWSYNC |
+ STEPCONFIG_SAMPLES_AVG | STEPCONFIG_YNN |
+ STEPCONFIG_INM | STEPCONFIG_FIFO1;
+ switch (ts_dev->wires) {
+ case 4:
+ config |= STEPCONFIG_YPP;
+ break;
+ case 5:
+ config |= STEPCONFIG_XPP | STEPCONFIG_INP_5 |
+ STEPCONFIG_XNP | STEPCONFIG_YPN;
+ break;
+ case 8:
+ config |= STEPCONFIG_YPP;
+ break;
+ }
+
+ for (i = 7; i < 13; i++) {
+ tscadc_writel(ts_dev, REG_STEPCONFIG(i), config);
+ tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
+ }
+
+ config = 0;
+ /* Charge step configuration */
+ config = STEPCONFIG_XPP | STEPCONFIG_YNN |
+ STEPCHARGE_RFP | STEPCHARGE_RFM |
+ STEPCHARGE_INM | STEPCHARGE_INP;
+
+ tscadc_writel(ts_dev, REG_CHARGECONFIG, config);
+ tscadc_writel(ts_dev, REG_CHARGEDELAY, STEPCHARGE_DELAY);
+
+ config = 0;
+ /* Configure to calculate pressure */
+ config = STEPCONFIG_MODE_HWSYNC |
+ STEPCONFIG_SAMPLES_AVG | STEPCONFIG_YPP |
+ STEPCONFIG_XNN | STEPCONFIG_INM;
+ tscadc_writel(ts_dev, REG_STEPCONFIG13, config);
+ tscadc_writel(ts_dev, REG_STEPDELAY13, STEPCONFIG_OPENDLY);
+
+ config |= STEPCONFIG_Z1 | STEPCONFIG_FIFO1;
+ tscadc_writel(ts_dev, REG_STEPCONFIG14, config);
+ tscadc_writel(ts_dev, REG_STEPDELAY14, STEPCONFIG_OPENDLY);
+
+ tscadc_writel(ts_dev, REG_SE, STPENB_STEPENB);
+}
+
+static void tscadc_idle_config(struct tscadc *ts_config)
+{
+ unsigned int idleconfig;
+
+ idleconfig = STEPCONFIG_YNN |
+ STEPCONFIG_INM |
+ STEPCONFIG_YPN | STEPIDLE_INP;
+ tscadc_writel(ts_config, REG_IDLECONFIG, idleconfig);
+}
+
+static void tscadc_read_coordinates(struct tscadc *ts_dev,
+ unsigned int *x, unsigned int *y)
+{
+ unsigned int fifocount = tscadc_readl(ts_dev, REG_FIFO0CNT);
+ unsigned int prev_val_x = ~0, prev_val_y = ~0;
+ unsigned int prev_diff_x = ~0, prev_diff_y = ~0;
+ unsigned int read, diff;
+ unsigned int i;
+
+ /*
+ * Delta filter is used to remove large variations in sampled
+ * values from ADC. The filter tries to predict where the next
+ * coordinate could be. This is done by taking a previous
+ * coordinate and subtracting it form current one. Further the
+ * algorithm compares the difference with that of a present value,
+ * if true the value is reported to the sub system.
+ */
+ for (i = 0; i < fifocount - 1; i++) {
+ read = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff;
+ diff = abs(read - prev_val_x);
+ if (diff < prev_diff_x) {
+ prev_diff_x = diff;
+ *x = read;
+ }
+ prev_val_x = read;
+
+ read = tscadc_readl(ts_dev, REG_FIFO1) & 0xfff;
+ diff = abs(read - prev_val_y);
+ if (diff < prev_diff_y) {
+ prev_diff_y = diff;
+ *y = read;
+ }
+ prev_val_y = read;
+ }
+}
+
+static irqreturn_t tscadc_irq(int irq, void *dev)
+{
+ struct tscadc *ts_dev = dev;
+ struct input_dev *input_dev = ts_dev->input;
+ unsigned int status, irqclr = 0;
+ unsigned int x = 0, y = 0;
+ unsigned int z1, z2, z;
+ unsigned int fsm;
+
+ status = tscadc_readl(ts_dev, REG_IRQSTATUS);
+ if (status & IRQENB_FIFO1THRES) {
+ tscadc_read_coordinates(ts_dev, &x, &y);
+
+ z1 = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff;
+ z2 = tscadc_readl(ts_dev, REG_FIFO1) & 0xfff;
+
+ if (ts_dev->pen_down && z1 != 0 && z2 != 0) {
+ /*
+ * Calculate pressure using formula
+ * Resistance(touch) = x plate resistance *
+ * x postion/4096 * ((z2 / z1) - 1)
+ */
+ z = z2 - z1;
+ z *= x;
+ z *= ts_dev->x_plate_resistance;
+ z /= z1;
+ z = (z + 2047) >> 12;
+
+ if (z <= MAX_12BIT) {
+ input_report_abs(input_dev, ABS_X, x);
+ input_report_abs(input_dev, ABS_Y, y);
+ input_report_abs(input_dev, ABS_PRESSURE, z);
+ input_report_key(input_dev, BTN_TOUCH, 1);
+ input_sync(input_dev);
+ }
+ }
+ irqclr |= IRQENB_FIFO1THRES;
+ }
+
+ /*
+ * Time for sequencer to settle, to read
+ * correct state of the sequencer.
+ */
+ udelay(SEQ_SETTLE);
+
+ status = tscadc_readl(ts_dev, REG_RAWIRQSTATUS);
+ if (status & IRQENB_PENUP) {
+ /* Pen up event */
+ fsm = tscadc_readl(ts_dev, REG_ADCFSM);
+ if (fsm == ADCFSM_STEPID) {
+ ts_dev->pen_down = false;
+ input_report_key(input_dev, BTN_TOUCH, 0);
+ input_report_abs(input_dev, ABS_PRESSURE, 0);
+ input_sync(input_dev);
+ } else {
+ ts_dev->pen_down = true;
+ }
+ irqclr |= IRQENB_PENUP;
+ }
+
+ tscadc_writel(ts_dev, REG_IRQSTATUS, irqclr);
+ /* check pending interrupts */
+ tscadc_writel(ts_dev, REG_IRQEOI, 0x0);
+
+ tscadc_writel(ts_dev, REG_SE, STPENB_STEPENB);
+ return IRQ_HANDLED;
+}
+
+/*
+ * The functions for inserting/removing driver as a module.
+ */
+
+static int __devinit tscadc_probe(struct platform_device *pdev)
+{
+ const struct tsc_data *pdata = pdev->dev.platform_data;
+ struct resource *res;
+ struct tscadc *ts_dev;
+ struct input_dev *input_dev;
+ struct clk *clk;
+ int err;
+ int clk_value, ctrl, irq;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "missing platform data.\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no memory resource defined.\n");
+ return -EINVAL;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no irq ID is specified.\n");
+ return -EINVAL;
+ }
+
+ /* Allocate memory for device */
+ ts_dev = kzalloc(sizeof(struct tscadc), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!ts_dev || !input_dev) {
+ dev_err(&pdev->dev, "failed to allocate memory.\n");
+ err = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ ts_dev->input = input_dev;
+ ts_dev->irq = irq;
+ ts_dev->wires = pdata->wires;
+ ts_dev->x_plate_resistance = pdata->x_plate_resistance;
+
+ res = request_mem_region(res->start, resource_size(res), pdev->name);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to reserve registers.\n");
+ err = -EBUSY;
+ goto err_free_mem;
+ }
+
+ ts_dev->tsc_base = ioremap(res->start, resource_size(res));
+ if (!ts_dev->tsc_base) {
+ dev_err(&pdev->dev, "failed to map registers.\n");
+ err = -ENOMEM;
+ goto err_release_mem_region;
+ }
+
+ err = request_irq(ts_dev->irq, tscadc_irq,
+ 0, pdev->dev.driver->name, ts_dev);
+ if (err) {
+ dev_err(&pdev->dev, "failed to allocate irq.\n");
+ goto err_unmap_regs;
+ }
+
+ ts_dev->tsc_ick = clk_get(&pdev->dev, "adc_tsc_ick");
+ if (IS_ERR(ts_dev->tsc_ick)) {
+ dev_err(&pdev->dev, "failed to get TSC ick\n");
+ goto err_free_irq;
+ }
+ clk_enable(ts_dev->tsc_ick);
+
+ clk = clk_get(&pdev->dev, "adc_tsc_fck");
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "failed to get TSC fck\n");
+ err = PTR_ERR(clk);
+ goto err_disable_clk;
+ }
+
+ clk_value = clk_get_rate(clk) / ADC_CLK;
+ clk_put(clk);
+
+ if (clk_value < 7) {
+ dev_err(&pdev->dev, "clock input less than min clock requirement\n");
+ goto err_disable_clk;
+ }
+ /* CLKDIV needs to be configured to the value minus 1 */
+ tscadc_writel(ts_dev, REG_CLKDIV, clk_value - 1);
+
+ /* Enable wake-up of the SoC using touchscreen */
+ tscadc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB);
+
+ ctrl = CNTRLREG_STEPCONFIGWRT |
+ CNTRLREG_TSCENB |
+ CNTRLREG_STEPID;
+ switch (ts_dev->wires) {
+ case 4:
+ ctrl |= CNTRLREG_4WIRE;
+ break;
+ case 5:
+ ctrl |= CNTRLREG_5WIRE;
+ break;
+ case 8:
+ ctrl |= CNTRLREG_8WIRE;
+ break;
+ }
+ tscadc_writel(ts_dev, REG_CTRL, ctrl);
+
+ tscadc_idle_config(ts_dev);
+ tscadc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO1THRES);
+ tscadc_step_config(ts_dev);
+ tscadc_writel(ts_dev, REG_FIFO1THR, 6);
+
+ ctrl |= CNTRLREG_TSCSSENB;
+ tscadc_writel(ts_dev, REG_CTRL, ctrl);
+
+ input_dev->name = "ti-tsc-adc";
+ input_dev->dev.parent = &pdev->dev;
+
+ 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);
+
+ /* register to the input system */
+ err = input_register_device(input_dev);
+ if (err)
+ goto err_disable_clk;
+
+ platform_set_drvdata(pdev, ts_dev);
+ return 0;
+
+err_disable_clk:
+ clk_disable(ts_dev->tsc_ick);
+ clk_put(ts_dev->tsc_ick);
+err_free_irq:
+ free_irq(ts_dev->irq, ts_dev);
+err_unmap_regs:
+ iounmap(ts_dev->tsc_base);
+err_release_mem_region:
+ release_mem_region(res->start, resource_size(res));
+err_free_mem:
+ input_free_device(input_dev);
+ kfree(ts_dev);
+ return err;
+}
+
+static int __devexit tscadc_remove(struct platform_device *pdev)
+{
+ struct tscadc *ts_dev = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ free_irq(ts_dev->irq, ts_dev);
+
+ input_unregister_device(ts_dev->input);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ iounmap(ts_dev->tsc_base);
+ release_mem_region(res->start, resource_size(res));
+
+ clk_disable(ts_dev->tsc_ick);
+ clk_put(ts_dev->tsc_ick);
+
+ kfree(ts_dev);
+
+ platform_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+static struct platform_driver ti_tsc_driver = {
+ .probe = tscadc_probe,
+ .remove = __devexit_p(tscadc_remove),
+ .driver = {
+ .name = "tsc",
+ .owner = THIS_MODULE,
+ },
+};
+module_platform_driver(ti_tsc_driver);
+
+MODULE_DESCRIPTION("TI touchscreen controller driver");
+MODULE_AUTHOR("Rachna Patil <rachna@ti.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index 3a5ebf452e8..22cd96f58c9 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -17,6 +17,7 @@
* - Zytronic capacitive touchscreen
* - NEXIO/iNexio
* - Elo TouchSystems 2700 IntelliTouch
+ * - EasyTouch USB Dual/Multi touch controller from Data Modul
*
* Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
* Copyright (C) by Todd E. Johnson (mtouchusb.c)
@@ -140,6 +141,7 @@ enum {
DEVTYPE_TC45USB,
DEVTYPE_NEXIO,
DEVTYPE_ELO,
+ DEVTYPE_ETOUCH,
};
#define USB_DEVICE_HID_CLASS(vend, prod) \
@@ -245,6 +247,10 @@ static const struct usb_device_id usbtouch_devices[] = {
{USB_DEVICE(0x04e7, 0x0020), .driver_info = DEVTYPE_ELO},
#endif
+#ifdef CONFIG_TOUCHSCREEN_USB_EASYTOUCH
+ {USB_DEVICE(0x7374, 0x0001), .driver_info = DEVTYPE_ETOUCH},
+#endif
+
{}
};
@@ -326,6 +332,51 @@ static int egalax_get_pkt_len(unsigned char *buf, int len)
}
#endif
+/*****************************************************************************
+ * EasyTouch part
+ */
+
+#ifdef CONFIG_TOUCHSCREEN_USB_EASYTOUCH
+
+#ifndef MULTI_PACKET
+#define MULTI_PACKET
+#endif
+
+#define ETOUCH_PKT_TYPE_MASK 0xFE
+#define ETOUCH_PKT_TYPE_REPT 0x80
+#define ETOUCH_PKT_TYPE_REPT2 0xB0
+#define ETOUCH_PKT_TYPE_DIAG 0x0A
+
+static int etouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+ if ((pkt[0] & ETOUCH_PKT_TYPE_MASK) != ETOUCH_PKT_TYPE_REPT &&
+ (pkt[0] & ETOUCH_PKT_TYPE_MASK) != ETOUCH_PKT_TYPE_REPT2)
+ return 0;
+
+ dev->x = ((pkt[1] & 0x1F) << 7) | (pkt[2] & 0x7F);
+ dev->y = ((pkt[3] & 0x1F) << 7) | (pkt[4] & 0x7F);
+ dev->touch = pkt[0] & 0x01;
+
+ return 1;
+}
+
+static int etouch_get_pkt_len(unsigned char *buf, int len)
+{
+ switch (buf[0] & ETOUCH_PKT_TYPE_MASK) {
+ case ETOUCH_PKT_TYPE_REPT:
+ case ETOUCH_PKT_TYPE_REPT2:
+ return 5;
+
+ case ETOUCH_PKT_TYPE_DIAG:
+ if (len < 2)
+ return -1;
+
+ return buf[1] + 2;
+ }
+
+ return 0;
+}
+#endif
/*****************************************************************************
* PanJit Part
@@ -1175,6 +1226,18 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
.exit = nexio_exit,
},
#endif
+#ifdef CONFIG_TOUCHSCREEN_USB_EASYTOUCH
+ [DEVTYPE_ETOUCH] = {
+ .min_xc = 0x0,
+ .max_xc = 0x07ff,
+ .min_yc = 0x0,
+ .max_yc = 0x07ff,
+ .rept_size = 16,
+ .process_pkt = usbtouch_process_multi,
+ .get_pkt_len = etouch_get_pkt_len,
+ .read_data = etouch_read_data,
+ },
+#endif
};
diff --git a/include/linux/input.h b/include/linux/input.h
index 3862e32c4ee..177261ea6f5 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -129,6 +129,8 @@ struct input_keymap_entry {
#define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */
+#define EVIOCSCLOCKID _IOW('E', 0xa0, int) /* Set clockid to be used for timestamps */
+
/*
* Device properties and quirks
*/
diff --git a/include/linux/input/cyttsp.h b/include/linux/input/cyttsp.h
new file mode 100644
index 00000000000..5af7c66f1fc
--- /dev/null
+++ b/include/linux/input/cyttsp.h
@@ -0,0 +1,58 @@
+/*
+ * Header file for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
+ * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com (kev@cypress.com)
+ *
+ */
+#ifndef _CYTTSP_H_
+#define _CYTTSP_H_
+
+#define CY_SPI_NAME "cyttsp-spi"
+#define CY_I2C_NAME "cyttsp-i2c"
+/* Active Power state scanning/processing refresh interval */
+#define CY_ACT_INTRVL_DFLT 0x00 /* ms */
+/* touch timeout for the Active power */
+#define CY_TCH_TMOUT_DFLT 0xFF /* ms */
+/* Low Power state scanning/processing refresh interval */
+#define CY_LP_INTRVL_DFLT 0x0A /* ms */
+/* Active distance in pixels for a gesture to be reported */
+#define CY_ACT_DIST_DFLT 0xF8 /* pixels */
+
+struct cyttsp_platform_data {
+ u32 maxx;
+ u32 maxy;
+ bool use_hndshk;
+ u8 act_dist; /* Active distance */
+ u8 act_intrvl; /* Active refresh interval; ms */
+ u8 tch_tmout; /* Active touch timeout; ms */
+ u8 lp_intrvl; /* Low power refresh interval; ms */
+ int (*init)(void);
+ void (*exit)(void);
+ char *name;
+ s16 irq_gpio;
+ u8 *bl_keys;
+};
+
+#endif /* _CYTTSP_H_ */
diff --git a/include/linux/input/ti_tscadc.h b/include/linux/input/ti_tscadc.h
new file mode 100644
index 00000000000..b10a527a92a
--- /dev/null
+++ b/include/linux/input/ti_tscadc.h
@@ -0,0 +1,17 @@
+#ifndef __LINUX_TI_TSCADC_H
+#define __LINUX_TI_TSCADC_H
+
+/**
+ * struct tsc_data Touchscreen wire configuration
+ * @wires: Wires refer to application modes
+ * i.e. 4/5/8 wire touchscreen support
+ * on the platform.
+ * @x_plate_resistance: X plate resistance.
+ */
+
+struct tsc_data {
+ int wires;
+ int x_plate_resistance;
+};
+
+#endif
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 0c635818640..e6a5a6bc276 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -1230,6 +1230,8 @@ ktime_t ktime_get_monotonic_offset(void)
} while (read_seqretry(&xtime_lock, seq));
return timespec_to_ktime(wtom);
}
+EXPORT_SYMBOL_GPL(ktime_get_monotonic_offset);
+
/**
* xtime_update() - advances the timekeeping infrastructure