]> Pileus Git - ~andy/linux/commitdiff
Merge commit 'v3.3-rc6' into next
authorDmitry Torokhov <dmitry.torokhov@gmail.com>
Fri, 9 Mar 2012 18:55:17 +0000 (10:55 -0800)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Fri, 9 Mar 2012 18:55:17 +0000 (10:55 -0800)
40 files changed:
MAINTAINERS
arch/arm/mach-tegra/include/mach/kbc.h
arch/arm/plat-spear/include/plat/keyboard.h
arch/m68k/q40/config.c
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/input/evdev.c
drivers/input/keyboard/nomadik-ske-keypad.c
drivers/input/keyboard/samsung-keypad.c
drivers/input/keyboard/spear-keyboard.c
drivers/input/keyboard/tegra-kbc.c
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/da9052_onkey.c [new file with mode: 0644]
drivers/input/misc/max8925_onkey.c
drivers/input/mouse/Kconfig
drivers/input/mouse/Makefile
drivers/input/mouse/hgpk.c
drivers/input/mouse/psmouse-base.c
drivers/input/mouse/psmouse.h
drivers/input/mouse/sentelic.c
drivers/input/mouse/synaptics_usb.c [new file with mode: 0644]
drivers/input/serio/at32psif.c
drivers/input/serio/q40kbd.c
drivers/input/tablet/wacom_sys.c
drivers/input/tablet/wacom_wac.c
drivers/input/tablet/wacom_wac.h
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/atmel-wm97xx.c
drivers/input/touchscreen/cyttsp_core.c [new file with mode: 0644]
drivers/input/touchscreen/cyttsp_core.h [new file with mode: 0644]
drivers/input/touchscreen/cyttsp_i2c.c [new file with mode: 0644]
drivers/input/touchscreen/cyttsp_spi.c [new file with mode: 0644]
drivers/input/touchscreen/ti_tscadc.c [new file with mode: 0644]
drivers/input/touchscreen/usbtouchscreen.c
include/linux/input.h
include/linux/input/cyttsp.h [new file with mode: 0644]
include/linux/input/ti_tscadc.h [new file with mode: 0644]
kernel/time/timekeeping.c

index 4e41d5255d7235662633f1e16af2b82a744dc85c..b31d1c9546610f31131b68578fa1f8965b3bb002 100644 (file)
@@ -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/
index 20bb0545f99208f4126d61afcf53671ba261afb2..a13025612939101fb14f89aecb7043c69adc6464 100644 (file)
 #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;
 };
 
index 68b5394fc583431094395e6ce25c09e40f803a95..c16cc31ecbed6fcb1c28e3a1b2e6f51e16df9bca 100644 (file)
@@ -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 */
index ad10fecec2fe665d7dcf86936da97eae6bd25d0c..be936480b964811a83af2ae293d79a244442a6a0 100644 (file)
@@ -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);
index af08ce7207d972f797d6c2f6d2dbee3c038e0898..4c861e239993543e44f899e8332cc7176a255a6d 100644 (file)
@@ -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) },
index b8574cddd95352a360ef7ff67200527185b3c1fb..8e96f19b62ea994cca874aca4c8f9fee5a467240 100644 (file)
 #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
index afc166fcc3d9c41ad6654bae17d5c893382c3705..3626b1ce46095d367d0d34c800367ef60b637820 100644 (file)
@@ -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);
 
index e35566aa102fa2b4dde8c1f193d705b13fbbd1f3..101e245944e79312b7ce191708ff566271c9f9b4 100644 (file)
@@ -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),
 };
 
index 17ba7f9f80f37364d8024754971ad6631322b04b..2391ae884feea05eb26ad4618b0ee49c7e541729 100644 (file)
@@ -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)
index c88bd63dc9ccc0f582fde988ce129609b7477556..3b6b528f02fde542a5b1b79c7e7e9df936b3be21 100644 (file)
@@ -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);
index a136e2e832beff1e740c8c9a79ad850b01fe14c2..dc19432c665be24d07e22c9a909376f43a75509a 100644 (file)
@@ -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);
index 7b46781c30c9cdf10ad3b392e6b730d6c5907566..eb07e88162ad67cc5404b37f0c973fb545f3bac2 100644 (file)
@@ -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
index 46671a875b91ba7d932de842e0b55d97862be83c..a6d8de069148fcdcb1c483af2008a4f74479b3a4 100644 (file)
@@ -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 (file)
index 0000000..34aebb8
--- /dev/null
@@ -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");
index 23cf08271049d9225a43147c7a3a500817321760..0a12b74140d30dd97d3f9fc1fe56fcd5bb5b1c3b 100644 (file)
@@ -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),
index 9c1e6ee8353187fe3d84a5fe0fb7b0f25260f601..9b8db821d5f0b00f498161b4879a87a19dbe065c 100644 (file)
@@ -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
index 570c84a4a6543ce5aa8d94e3c5df0bb015243312..4718effeb8d959b922342cd02c8d33e5b49d3a27 100644 (file)
@@ -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
index 1c5d521de600b23c0d44008f057f77ad40e3bc44..575f880727fe3fc0e8501c3658e5ab3e6671e439 100644 (file)
@@ -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");
index e6c9931f02c73176483105b494feab56b19ddacd..22fe2547e16991cc45987d33f7c5bfb4436c5265 100644 (file)
@@ -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;
 }
 
 
index 6a417092d010f7afd62f0a95565ad008fb57f6b6..fe1df231ba4c8dfc07488fd6d4fe1031344e0f76 100644 (file)
@@ -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;
index e36847de7617cfdd7cc75af410afad11c46e56f8..2a77a52d2e62a53e53f71c4a46c9db3726c1f484 100644 (file)
@@ -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 (file)
index 0000000..e559a94
--- /dev/null
@@ -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");
index 95280f9207e14cf4d552aaa7cf8b7b3704fc123f..36e799c31f5e2a7424116a201a8d1c7302a55401 100644 (file)
@@ -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)
index 5eb84b3b67fbb7b69776fa33b15db6a690818a1f..0c0df7f73802ea71d44e3cf1cc762280a5f780be 100644 (file)
 #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);
 }
 
index 2a97b7e76db1d33310820502f8e51ae01576af64..39205eddf71301466e993419180d159c88af7307 100644 (file)
@@ -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 =
index 88672ec296c116e10d7340c7f07397e10e09afe1..07a1f218b5c1b6943512e0e7ea1148f61ed1fac2 100644 (file)
@@ -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);
index 050acaefee7d3763f543f70ac5f551f41d5bde30..4f0ba21b01962c4b2556535468c96f7355e17d1c 100644 (file)
@@ -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
index 4af2a18eb3ba9013332de2c961a3076fe28e1d22..fc087b3c95cf423289a3c43e6ce99377c2a6fdfc 100644 (file)
@@ -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
index 496091e884603428da438e7d0cd9d72b27c6f497..e748fb8377591dcf5b551d89b05c531d688124b0 100644 (file)
@@ -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
index 8034cbb20f74c8d8bcd426aa27b998e8bd8fcf20..c5c2dbb938692f418ba603e649b7fc062462268a 100644 (file)
@@ -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 (file)
index 0000000..f030d9e
--- /dev/null
@@ -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 (file)
index 0000000..1aa3c69
--- /dev/null
@@ -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 (file)
index 0000000..c7110cc
--- /dev/null
@@ -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 (file)
index 0000000..9db5f87
--- /dev/null
@@ -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 (file)
index 0000000..d229c74
--- /dev/null
@@ -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");
index 3a5ebf452e810bde7b032650f3e942b3fd6d085e..22cd96f58c99b33451f2cc99757fb561ab738232 100644 (file)
@@ -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
 };
 
 
index 3862e32c4eeb38076d4768c70a958a7b58dd6cf8..177261ea6f5216b3c228c804e18f5e1101df5e4e 100644 (file)
@@ -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 (file)
index 0000000..5af7c66
--- /dev/null
@@ -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 (file)
index 0000000..b10a527
--- /dev/null
@@ -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
index 0c6358186401b8bd40d169fd42f82b6260802dca..e6a5a6bc2769149e8815ff76276256ed073e9e98 100644 (file)
@@ -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