summaryrefslogtreecommitdiff
path: root/drivers/input/mouse
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/mouse')
-rw-r--r--drivers/input/mouse/Kconfig12
-rw-r--r--drivers/input/mouse/Makefile1
-rw-r--r--drivers/input/mouse/alps.c81
-rw-r--r--drivers/input/mouse/alps.h2
-rw-r--r--drivers/input/mouse/appletouch.c59
-rw-r--r--drivers/input/mouse/bcm5974.c24
-rw-r--r--drivers/input/mouse/navpoint.c369
-rw-r--r--drivers/input/mouse/sentelic.c34
-rw-r--r--drivers/input/mouse/sentelic.h8
-rw-r--r--drivers/input/mouse/sermouse.c13
-rw-r--r--drivers/input/mouse/synaptics.c20
-rw-r--r--drivers/input/mouse/vsxxxaa.c14
12 files changed, 552 insertions, 85 deletions
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index 9b8db821d5f0..cd6268cf7cd5 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -339,4 +339,16 @@ config MOUSE_SYNAPTICS_USB
To compile this driver as a module, choose M here: the
module will be called synaptics_usb.
+config MOUSE_NAVPOINT_PXA27x
+ tristate "Synaptics NavPoint (PXA27x SSP/SPI)"
+ depends on PXA27x && PXA_SSP
+ help
+ This driver adds support for the Synaptics NavPoint touchpad connected
+ to a PXA27x SSP port in SPI slave mode. The device emulates a mouse;
+ a tap or tap-and-a-half drag gesture emulates the left mouse button.
+ For example, use the xf86-input-evdev driver for an X pointing device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called navpoint.
+
endif
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index 4718effeb8d9..46ba7556fd4f 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o
obj-$(CONFIG_MOUSE_INPORT) += inport.o
obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o
obj-$(CONFIG_MOUSE_MAPLE) += maplemouse.o
+obj-$(CONFIG_MOUSE_NAVPOINT_PXA27x) += navpoint.o
obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o
obj-$(CONFIG_MOUSE_PS2) += psmouse.o
obj-$(CONFIG_MOUSE_PXA930_TRKBALL) += pxa930_trkball.o
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 4c6a72d3d48c..4a1347e91bdc 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -553,10 +553,7 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
- input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
- input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
- input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
- input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4);
+ input_mt_report_finger_count(dev, fingers);
input_report_key(dev, BTN_LEFT, left);
input_report_key(dev, BTN_RIGHT, right);
@@ -604,10 +601,54 @@ static void alps_process_packet_v3(struct psmouse *psmouse)
static void alps_process_packet_v4(struct psmouse *psmouse)
{
+ struct alps_data *priv = psmouse->private;
unsigned char *packet = psmouse->packet;
struct input_dev *dev = psmouse->dev;
+ int offset;
int x, y, z;
int left, right;
+ int x1, y1, x2, y2;
+ int fingers = 0;
+ unsigned int x_bitmap, y_bitmap;
+
+ /*
+ * v4 has a 6-byte encoding for bitmap data, but this data is
+ * broken up between 3 normal packets. Use priv->multi_packet to
+ * track our position in the bitmap packet.
+ */
+ if (packet[6] & 0x40) {
+ /* sync, reset position */
+ priv->multi_packet = 0;
+ }
+
+ if (WARN_ON_ONCE(priv->multi_packet > 2))
+ return;
+
+ offset = 2 * priv->multi_packet;
+ priv->multi_data[offset] = packet[6];
+ priv->multi_data[offset + 1] = packet[7];
+
+ if (++priv->multi_packet > 2) {
+ priv->multi_packet = 0;
+
+ x_bitmap = ((priv->multi_data[2] & 0x1f) << 10) |
+ ((priv->multi_data[3] & 0x60) << 3) |
+ ((priv->multi_data[0] & 0x3f) << 2) |
+ ((priv->multi_data[1] & 0x60) >> 5);
+ y_bitmap = ((priv->multi_data[5] & 0x01) << 10) |
+ ((priv->multi_data[3] & 0x1f) << 5) |
+ (priv->multi_data[1] & 0x1f);
+
+ fingers = alps_process_bitmap(x_bitmap, y_bitmap,
+ &x1, &y1, &x2, &y2);
+
+ /* Store MT data.*/
+ priv->fingers = fingers;
+ priv->x1 = x1;
+ priv->x2 = x2;
+ priv->y1 = y1;
+ priv->y2 = y2;
+ }
left = packet[4] & 0x01;
right = packet[4] & 0x02;
@@ -617,21 +658,41 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
z = packet[5] & 0x7f;
+ /*
+ * If there were no contacts in the bitmap, use ST
+ * points in MT reports.
+ * If there were two contacts or more, report MT data.
+ */
+ if (priv->fingers < 2) {
+ x1 = x;
+ y1 = y;
+ fingers = z > 0 ? 1 : 0;
+ } else {
+ fingers = priv->fingers;
+ x1 = priv->x1;
+ x2 = priv->x2;
+ y1 = priv->y1;
+ y2 = priv->y2;
+ }
+
if (z >= 64)
input_report_key(dev, BTN_TOUCH, 1);
else
input_report_key(dev, BTN_TOUCH, 0);
+ alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
+
+ input_mt_report_finger_count(dev, fingers);
+
+ input_report_key(dev, BTN_LEFT, left);
+ input_report_key(dev, BTN_RIGHT, right);
+
if (z > 0) {
input_report_abs(dev, ABS_X, x);
input_report_abs(dev, ABS_Y, y);
}
input_report_abs(dev, ABS_PRESSURE, z);
- input_report_key(dev, BTN_TOOL_FINGER, z > 0);
- input_report_key(dev, BTN_LEFT, left);
- input_report_key(dev, BTN_RIGHT, right);
-
input_sync(dev);
}
@@ -1557,6 +1618,7 @@ int alps_init(struct psmouse *psmouse)
input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
break;
case ALPS_PROTO_V3:
+ case ALPS_PROTO_V4:
set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
input_mt_init_slots(dev1, 2);
input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0);
@@ -1565,8 +1627,7 @@ int alps_init(struct psmouse *psmouse)
set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit);
set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
- /* fall through */
- case ALPS_PROTO_V4:
+
input_set_abs_params(dev1, ABS_X, 0, ALPS_V3_X_MAX, 0, 0);
input_set_abs_params(dev1, ABS_Y, 0, ALPS_V3_Y_MAX, 0, 0);
break;
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index a00a4ab92a0f..ae1ac354c778 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -39,6 +39,8 @@ struct alps_data {
int prev_fin; /* Finger bit from previous packet */
int multi_packet; /* Multi-packet data in progress */
unsigned char multi_data[6]; /* Saved multi-packet data */
+ int x1, x2, y1, y2; /* Coordinates from last MT report */
+ int fingers; /* Number of fingers from MT report */
u8 quirks;
struct timer_list timer;
};
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index 0acbc7d50d05..e42f1fa8cdc0 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -195,6 +195,7 @@ enum atp_status_bits {
struct atp {
char phys[64];
struct usb_device *udev; /* usb device */
+ struct usb_interface *intf; /* usb interface */
struct urb *urb; /* usb request block */
u8 *data; /* transferred data */
struct input_dev *input; /* input dev */
@@ -253,8 +254,9 @@ MODULE_PARM_DESC(debug, "Activate debugging output");
* packets (Report ID 2). This code changes device mode, so it
* sends raw sensor reports (Report ID 5).
*/
-static int atp_geyser_init(struct usb_device *udev)
+static int atp_geyser_init(struct atp *dev)
{
+ struct usb_device *udev = dev->udev;
char *data;
int size;
int i;
@@ -262,7 +264,7 @@ static int atp_geyser_init(struct usb_device *udev)
data = kmalloc(8, GFP_KERNEL);
if (!data) {
- err("Out of memory");
+ dev_err(&dev->intf->dev, "Out of memory\n");
return -ENOMEM;
}
@@ -277,7 +279,7 @@ static int atp_geyser_init(struct usb_device *udev)
for (i = 0; i < 8; i++)
dprintk("appletouch[%d]: %d\n", i, data[i]);
- err("Failed to read mode from device.");
+ dev_err(&dev->intf->dev, "Failed to read mode from device.\n");
ret = -EIO;
goto out_free;
}
@@ -296,7 +298,7 @@ static int atp_geyser_init(struct usb_device *udev)
for (i = 0; i < 8; i++)
dprintk("appletouch[%d]: %d\n", i, data[i]);
- err("Failed to request geyser raw mode");
+ dev_err(&dev->intf->dev, "Failed to request geyser raw mode\n");
ret = -EIO;
goto out_free;
}
@@ -313,16 +315,16 @@ out_free:
static void atp_reinit(struct work_struct *work)
{
struct atp *dev = container_of(work, struct atp, work);
- struct usb_device *udev = dev->udev;
int retval;
dprintk("appletouch: putting appletouch to sleep (reinit)\n");
- atp_geyser_init(udev);
+ atp_geyser_init(dev);
retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
if (retval)
- err("atp_reinit: usb_submit_urb failed with error %d",
- retval);
+ dev_err(&dev->intf->dev,
+ "atp_reinit: usb_submit_urb failed with error %d\n",
+ retval);
}
static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
@@ -400,6 +402,7 @@ static inline void atp_report_fingers(struct input_dev *input, int fingers)
static int atp_status_check(struct urb *urb)
{
struct atp *dev = urb->context;
+ struct usb_interface *intf = dev->intf;
switch (urb->status) {
case 0:
@@ -407,8 +410,8 @@ static int atp_status_check(struct urb *urb)
break;
case -EOVERFLOW:
if (!dev->overflow_warned) {
- printk(KERN_WARNING "appletouch: OVERFLOW with data "
- "length %d, actual length is %d\n",
+ dev_warn(&intf->dev,
+ "appletouch: OVERFLOW with data length %d, actual length is %d\n",
dev->info->datalen, dev->urb->actual_length);
dev->overflow_warned = true;
}
@@ -416,13 +419,15 @@ static int atp_status_check(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* This urb is terminated, clean up */
- dbg("atp_complete: urb shutting down with status: %d",
- urb->status);
+ dev_dbg(&intf->dev,
+ "atp_complete: urb shutting down with status: %d\n",
+ urb->status);
return ATP_URB_STATUS_ERROR_FATAL;
default:
- dbg("atp_complete: nonzero urb status received: %d",
- urb->status);
+ dev_dbg(&intf->dev,
+ "atp_complete: nonzero urb status received: %d\n",
+ urb->status);
return ATP_URB_STATUS_ERROR;
}
@@ -445,7 +450,8 @@ static void atp_detect_size(struct atp *dev)
for (i = dev->info->xsensors; i < ATP_XSENSORS; i++) {
if (dev->xy_cur[i]) {
- printk(KERN_INFO "appletouch: 17\" model detected.\n");
+ dev_info(&dev->intf->dev,
+ "appletouch: 17\" model detected.\n");
input_set_abs_params(dev->input, ABS_X, 0,
(dev->info->xsensors_17 - 1) *
@@ -588,8 +594,9 @@ static void atp_complete_geyser_1_2(struct urb *urb)
exit:
retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
if (retval)
- err("atp_complete: usb_submit_urb failed with result %d",
- retval);
+ dev_err(&dev->intf->dev,
+ "atp_complete: usb_submit_urb failed with result %d\n",
+ retval);
}
/* Interrupt function for older touchpads: GEYSER3/GEYSER4 */
@@ -722,8 +729,9 @@ static void atp_complete_geyser_3_4(struct urb *urb)
exit:
retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
if (retval)
- err("atp_complete: usb_submit_urb failed with result %d",
- retval);
+ dev_err(&dev->intf->dev,
+ "atp_complete: usb_submit_urb failed with result %d\n",
+ retval);
}
static int atp_open(struct input_dev *input)
@@ -748,14 +756,12 @@ static void atp_close(struct input_dev *input)
static int atp_handle_geyser(struct atp *dev)
{
- struct usb_device *udev = dev->udev;
-
if (dev->info != &fountain_info) {
/* switch to raw sensor mode */
- if (atp_geyser_init(udev))
+ if (atp_geyser_init(dev))
return -EIO;
- printk(KERN_INFO "appletouch: Geyser mode initialized.\n");
+ dev_info(&dev->intf->dev, "Geyser mode initialized.\n");
}
return 0;
@@ -785,7 +791,7 @@ static int atp_probe(struct usb_interface *iface,
}
}
if (!int_in_endpointAddr) {
- err("Could not find int-in endpoint");
+ dev_err(&iface->dev, "Could not find int-in endpoint\n");
return -EIO;
}
@@ -793,11 +799,12 @@ static int atp_probe(struct usb_interface *iface,
dev = kzalloc(sizeof(struct atp), GFP_KERNEL);
input_dev = input_allocate_device();
if (!dev || !input_dev) {
- err("Out of memory");
+ dev_err(&iface->dev, "Out of memory\n");
goto err_free_devs;
}
dev->udev = udev;
+ dev->intf = iface;
dev->input = input_dev;
dev->info = info;
dev->overflow_warned = false;
@@ -886,7 +893,7 @@ static void atp_disconnect(struct usb_interface *iface)
usb_free_urb(dev->urb);
kfree(dev);
}
- printk(KERN_INFO "input: appletouch disconnected\n");
+ dev_info(&iface->dev, "input: appletouch disconnected\n");
}
static int atp_recover(struct atp *dev)
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index f9e2758b9f46..2cf681d98c0d 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -584,7 +584,7 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
int retval = 0, size;
if (!data) {
- err("bcm5974: out of memory");
+ dev_err(&dev->intf->dev, "out of memory\n");
retval = -ENOMEM;
goto out;
}
@@ -597,7 +597,7 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
if (size != 8) {
- err("bcm5974: could not read from device");
+ dev_err(&dev->intf->dev, "could not read from device\n");
retval = -EIO;
goto out;
}
@@ -615,7 +615,7 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
if (size != 8) {
- err("bcm5974: could not write to device");
+ dev_err(&dev->intf->dev, "could not write to device\n");
retval = -EIO;
goto out;
}
@@ -631,6 +631,7 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
static void bcm5974_irq_button(struct urb *urb)
{
struct bcm5974 *dev = urb->context;
+ struct usb_interface *intf = dev->intf;
int error;
switch (urb->status) {
@@ -640,10 +641,11 @@ static void bcm5974_irq_button(struct urb *urb)
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
- dbg("bcm5974: button urb shutting down: %d", urb->status);
+ dev_dbg(&intf->dev, "button urb shutting down: %d\n",
+ urb->status);
return;
default:
- dbg("bcm5974: button urb status: %d", urb->status);
+ dev_dbg(&intf->dev, "button urb status: %d\n", urb->status);
goto exit;
}
@@ -654,12 +656,13 @@ static void bcm5974_irq_button(struct urb *urb)
exit:
error = usb_submit_urb(dev->bt_urb, GFP_ATOMIC);
if (error)
- err("bcm5974: button urb failed: %d", error);
+ dev_err(&intf->dev, "button urb failed: %d\n", error);
}
static void bcm5974_irq_trackpad(struct urb *urb)
{
struct bcm5974 *dev = urb->context;
+ struct usb_interface *intf = dev->intf;
int error;
switch (urb->status) {
@@ -669,10 +672,11 @@ static void bcm5974_irq_trackpad(struct urb *urb)
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
- dbg("bcm5974: trackpad urb shutting down: %d", urb->status);
+ dev_dbg(&intf->dev, "trackpad urb shutting down: %d\n",
+ urb->status);
return;
default:
- dbg("bcm5974: trackpad urb status: %d", urb->status);
+ dev_dbg(&intf->dev, "trackpad urb status: %d\n", urb->status);
goto exit;
}
@@ -687,7 +691,7 @@ static void bcm5974_irq_trackpad(struct urb *urb)
exit:
error = usb_submit_urb(dev->tp_urb, GFP_ATOMIC);
if (error)
- err("bcm5974: trackpad urb failed: %d", error);
+ dev_err(&intf->dev, "trackpad urb failed: %d\n", error);
}
/*
@@ -833,7 +837,7 @@ static int bcm5974_probe(struct usb_interface *iface,
dev = kzalloc(sizeof(struct bcm5974), GFP_KERNEL);
input_dev = input_allocate_device();
if (!dev || !input_dev) {
- err("bcm5974: out of memory");
+ dev_err(&iface->dev, "out of memory\n");
goto err_free_devs;
}
diff --git a/drivers/input/mouse/navpoint.c b/drivers/input/mouse/navpoint.c
new file mode 100644
index 000000000000..c29ae7654d5e
--- /dev/null
+++ b/drivers/input/mouse/navpoint.c
@@ -0,0 +1,369 @@
+/*
+ * Synaptics NavPoint (PXA27x SSP/SPI) driver.
+ *
+ * Copyright (C) 2012 Paul Parsons <lost.distance@yahoo.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/input/navpoint.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/pxa2xx_ssp.h>
+#include <linux/slab.h>
+
+/*
+ * Synaptics Modular Embedded Protocol: Module Packet Format.
+ * Module header byte 2:0 = Length (# bytes that follow)
+ * Module header byte 4:3 = Control
+ * Module header byte 7:5 = Module Address
+ */
+#define HEADER_LENGTH(byte) ((byte) & 0x07)
+#define HEADER_CONTROL(byte) (((byte) >> 3) & 0x03)
+#define HEADER_ADDRESS(byte) ((byte) >> 5)
+
+struct navpoint {
+ struct ssp_device *ssp;
+ struct input_dev *input;
+ struct device *dev;
+ int gpio;
+ int index;
+ u8 data[1 + HEADER_LENGTH(0xff)];
+};
+
+/*
+ * Initialization values for SSCR0_x, SSCR1_x, SSSR_x.
+ */
+static const u32 sscr0 = 0
+ | SSCR0_TUM /* TIM = 1; No TUR interrupts */
+ | SSCR0_RIM /* RIM = 1; No ROR interrupts */
+ | SSCR0_SSE /* SSE = 1; SSP enabled */
+ | SSCR0_Motorola /* FRF = 0; Motorola SPI */
+ | SSCR0_DataSize(16) /* DSS = 15; Data size = 16-bit */
+ ;
+static const u32 sscr1 = 0
+ | SSCR1_SCFR /* SCFR = 1; SSPSCLK only during transfers */
+ | SSCR1_SCLKDIR /* SCLKDIR = 1; Slave mode */
+ | SSCR1_SFRMDIR /* SFRMDIR = 1; Slave mode */
+ | SSCR1_RWOT /* RWOT = 1; Receive without transmit mode */
+ | SSCR1_RxTresh(1) /* RFT = 0; Receive FIFO threshold = 1 */
+ | SSCR1_SPH /* SPH = 1; SSPSCLK inactive 0.5 + 1 cycles */
+ | SSCR1_RIE /* RIE = 1; Receive FIFO interrupt enabled */
+ ;
+static const u32 sssr = 0
+ | SSSR_BCE /* BCE = 1; Clear BCE */
+ | SSSR_TUR /* TUR = 1; Clear TUR */
+ | SSSR_EOC /* EOC = 1; Clear EOC */
+ | SSSR_TINT /* TINT = 1; Clear TINT */
+ | SSSR_PINT /* PINT = 1; Clear PINT */
+ | SSSR_ROR /* ROR = 1; Clear ROR */
+ ;
+
+/*
+ * MEP Query $22: Touchpad Coordinate Range Query is not supported by
+ * the NavPoint module, so sampled values provide the default limits.
+ */
+#define NAVPOINT_X_MIN 1278
+#define NAVPOINT_X_MAX 5340
+#define NAVPOINT_Y_MIN 1572
+#define NAVPOINT_Y_MAX 4396
+#define NAVPOINT_PRESSURE_MIN 0
+#define NAVPOINT_PRESSURE_MAX 255
+
+static void navpoint_packet(struct navpoint *navpoint)
+{
+ int finger;
+ int gesture;
+ int x, y, z;
+
+ switch (navpoint->data[0]) {
+ case 0xff: /* Garbage (packet?) between reset and Hello packet */
+ case 0x00: /* Module 0, NULL packet */
+ break;
+
+ case 0x0e: /* Module 0, Absolute packet */
+ finger = (navpoint->data[1] & 0x01);
+ gesture = (navpoint->data[1] & 0x02);
+ x = ((navpoint->data[2] & 0x1f) << 8) | navpoint->data[3];
+ y = ((navpoint->data[4] & 0x1f) << 8) | navpoint->data[5];
+ z = navpoint->data[6];
+ input_report_key(navpoint->input, BTN_TOUCH, finger);
+ input_report_abs(navpoint->input, ABS_X, x);
+ input_report_abs(navpoint->input, ABS_Y, y);
+ input_report_abs(navpoint->input, ABS_PRESSURE, z);
+ input_report_key(navpoint->input, BTN_TOOL_FINGER, finger);
+ input_report_key(navpoint->input, BTN_LEFT, gesture);
+ input_sync(navpoint->input);
+ break;
+
+ case 0x19: /* Module 0, Hello packet */
+ if ((navpoint->data[1] & 0xf0) == 0x10)
+ break;
+ /* FALLTHROUGH */
+ default:
+ dev_warn(navpoint->dev,
+ "spurious packet: data=0x%02x,0x%02x,...\n",
+ navpoint->data[0], navpoint->data[1]);
+ break;
+ }
+}
+
+static irqreturn_t navpoint_irq(int irq, void *dev_id)
+{
+ struct navpoint *navpoint = dev_id;
+ struct ssp_device *ssp = navpoint->ssp;
+ irqreturn_t ret = IRQ_NONE;
+ u32 status;
+
+ status = pxa_ssp_read_reg(ssp, SSSR);
+ if (status & sssr) {
+ dev_warn(navpoint->dev,
+ "unexpected interrupt: status=0x%08x\n", status);
+ pxa_ssp_write_reg(ssp, SSSR, (status & sssr));
+ ret = IRQ_HANDLED;
+ }
+
+ while (status & SSSR_RNE) {
+ u32 data;
+
+ data = pxa_ssp_read_reg(ssp, SSDR);
+ navpoint->data[navpoint->index + 0] = (data >> 8);
+ navpoint->data[navpoint->index + 1] = data;
+ navpoint->index += 2;
+ if (HEADER_LENGTH(navpoint->data[0]) < navpoint->index) {
+ navpoint_packet(navpoint);
+ navpoint->index = 0;
+ }
+ status = pxa_ssp_read_reg(ssp, SSSR);
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+static void navpoint_up(struct navpoint *navpoint)
+{
+ struct ssp_device *ssp = navpoint->ssp;
+ int timeout;
+
+ clk_prepare_enable(ssp->clk);
+
+ pxa_ssp_write_reg(ssp, SSCR1, sscr1);
+ pxa_ssp_write_reg(ssp, SSSR, sssr);
+ pxa_ssp_write_reg(ssp, SSTO, 0);
+ pxa_ssp_write_reg(ssp, SSCR0, sscr0); /* SSCR0_SSE written last */
+
+ /* Wait until SSP port is ready for slave clock operations */
+ for (timeout = 100; timeout != 0; --timeout) {
+ if (!(pxa_ssp_read_reg(ssp, SSSR) & SSSR_CSS))
+ break;
+ msleep(1);
+ }
+
+ if (timeout == 0)
+ dev_err(navpoint->dev,
+ "timeout waiting for SSSR[CSS] to clear\n");
+
+ if (gpio_is_valid(navpoint->gpio))
+ gpio_set_value(navpoint->gpio, 1);
+}
+
+static void navpoint_down(struct navpoint *navpoint)
+{
+ struct ssp_device *ssp = navpoint->ssp;
+
+ if (gpio_is_valid(navpoint->gpio))
+ gpio_set_value(navpoint->gpio, 0);
+
+ pxa_ssp_write_reg(ssp, SSCR0, 0);
+
+ clk_disable_unprepare(ssp->clk);
+}
+
+static int navpoint_open(struct input_dev *input)
+{
+ struct navpoint *navpoint = input_get_drvdata(input);
+
+ navpoint_up(navpoint);
+
+ return 0;
+}
+
+static void navpoint_close(struct input_dev *input)
+{
+ struct navpoint *navpoint = input_get_drvdata(input);
+
+ navpoint_down(navpoint);
+}
+
+static int __devinit navpoint_probe(struct platform_device *pdev)
+{
+ const struct navpoint_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
+ struct ssp_device *ssp;
+ struct input_dev *input;
+ struct navpoint *navpoint;
+ int error;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data\n");
+ return -EINVAL;
+ }
+
+ if (gpio_is_valid(pdata->gpio)) {
+ error = gpio_request_one(pdata->gpio, GPIOF_OUT_INIT_LOW,
+ "SYNAPTICS_ON");
+ if (error)
+ return error;
+ }
+
+ ssp = pxa_ssp_request(pdata->port, pdev->name);
+ if (!ssp) {
+ error = -ENODEV;
+ goto err_free_gpio;
+ }
+
+ /* HaRET does not disable devices before jumping into Linux */
+ if (pxa_ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) {
+ pxa_ssp_write_reg(ssp, SSCR0, 0);
+ dev_warn(&pdev->dev, "ssp%d already enabled\n", pdata->port);
+ }
+
+ navpoint = kzalloc(sizeof(*navpoint), GFP_KERNEL);
+ input = input_allocate_device();
+ if (!navpoint || !input) {
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ navpoint->ssp = ssp;
+ navpoint->input = input;
+ navpoint->dev = &pdev->dev;
+ navpoint->gpio = pdata->gpio;
+
+ input->name = pdev->name;
+ input->dev.parent = &pdev->dev;
+
+ __set_bit(EV_KEY, input->evbit);
+ __set_bit(EV_ABS, input->evbit);
+ __set_bit(BTN_LEFT, input->keybit);
+ __set_bit(BTN_TOUCH, input->keybit);
+ __set_bit(BTN_TOOL_FINGER, input->keybit);
+
+ input_set_abs_params(input, ABS_X,
+ NAVPOINT_X_MIN, NAVPOINT_X_MAX, 0, 0);
+ input_set_abs_params(input, ABS_Y,
+ NAVPOINT_Y_MIN, NAVPOINT_Y_MAX, 0, 0);
+ input_set_abs_params(input, ABS_PRESSURE,
+ NAVPOINT_PRESSURE_MIN, NAVPOINT_PRESSURE_MAX,
+ 0, 0);
+
+ input->open = navpoint_open;
+ input->close = navpoint_close;
+
+ input_set_drvdata(input, navpoint);
+
+ error = request_irq(ssp->irq, navpoint_irq, 0, pdev->name, navpoint);
+ if (error)
+ goto err_free_mem;
+
+ error = input_register_device(input);
+ if (error)
+ goto err_free_irq;
+
+ platform_set_drvdata(pdev, navpoint);
+ dev_dbg(&pdev->dev, "ssp%d, irq %d\n", pdata->port, ssp->irq);
+
+ return 0;
+
+err_free_irq:
+ free_irq(ssp->irq, &pdev->dev);
+err_free_mem:
+ input_free_device(input);
+ kfree(navpoint);
+ pxa_ssp_free(ssp);
+err_free_gpio:
+ if (gpio_is_valid(pdata->gpio))
+ gpio_free(pdata->gpio);
+
+ return error;
+}
+
+static int __devexit navpoint_remove(struct platform_device *pdev)
+{
+ const struct navpoint_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
+ struct navpoint *navpoint = platform_get_drvdata(pdev);
+ struct ssp_device *ssp = navpoint->ssp;
+
+ free_irq(ssp->irq, navpoint);
+
+ input_unregister_device(navpoint->input);
+ kfree(navpoint);
+
+ pxa_ssp_free(ssp);
+
+ if (gpio_is_valid(pdata->gpio))
+ gpio_free(pdata->gpio);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int navpoint_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct navpoint *navpoint = platform_get_drvdata(pdev);
+ struct input_dev *input = navpoint->input;
+
+ mutex_lock(&input->mutex);
+ if (input->users)
+ navpoint_down(navpoint);
+ mutex_unlock(&input->mutex);
+
+ return 0;
+}
+
+static int navpoint_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct navpoint *navpoint = platform_get_drvdata(pdev);
+ struct input_dev *input = navpoint->input;
+
+ mutex_lock(&input->mutex);
+ if (input->users)
+ navpoint_up(navpoint);
+ mutex_unlock(&input->mutex);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(navpoint_pm_ops, navpoint_suspend, navpoint_resume);
+
+static struct platform_driver navpoint_driver = {
+ .probe = navpoint_probe,
+ .remove = __devexit_p(navpoint_remove),
+ .driver = {
+ .name = "navpoint",
+ .owner = THIS_MODULE,
+ .pm = &navpoint_pm_ops,
+ },
+};
+
+module_platform_driver(navpoint_driver);
+
+MODULE_AUTHOR("Paul Parsons <lost.distance@yahoo.com>");
+MODULE_DESCRIPTION("Synaptics NavPoint (PXA27x SSP/SPI) driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:navpoint");
diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c
index 661a0ca3b3d6..3f5649f19082 100644
--- a/drivers/input/mouse/sentelic.c
+++ b/drivers/input/mouse/sentelic.c
@@ -41,7 +41,7 @@
#define GET_ABS_Y(packet) ((packet[2] << 2) | (packet[3] & 0x03))
/** Driver version. */
-static const char fsp_drv_ver[] = "1.0.0-K";
+static const char fsp_drv_ver[] = "1.1.0-K";
/*
* Make sure that the value being sent to FSP will not conflict with
@@ -303,6 +303,27 @@ static int fsp_get_revision(struct psmouse *psmouse, int *rev)
return 0;
}
+static int fsp_get_sn(struct psmouse *psmouse, int *sn)
+{
+ int v0, v1, v2;
+ int rc = -EIO;
+
+ /* production number since Cx is available at: 0x0b40 ~ 0x0b42 */
+ if (fsp_page_reg_write(psmouse, FSP_PAGE_0B))
+ goto out;
+ if (fsp_reg_read(psmouse, FSP_REG_SN0, &v0))
+ goto out;
+ if (fsp_reg_read(psmouse, FSP_REG_SN1, &v1))
+ goto out;
+ if (fsp_reg_read(psmouse, FSP_REG_SN2, &v2))
+ goto out;
+ *sn = (v0 << 16) | (v1 << 8) | v2;
+ rc = 0;
+out:
+ fsp_page_reg_write(psmouse, FSP_PAGE_DEFAULT);
+ return rc;
+}
+
static int fsp_get_buttons(struct psmouse *psmouse, int *btn)
{
static const int buttons[] = {
@@ -1000,16 +1021,21 @@ static int fsp_reconnect(struct psmouse *psmouse)
int fsp_init(struct psmouse *psmouse)
{
struct fsp_data *priv;
- int ver, rev;
+ int ver, rev, sn = 0;
int error;
if (fsp_get_version(psmouse, &ver) ||
fsp_get_revision(psmouse, &rev)) {
return -ENODEV;
}
+ if (ver >= FSP_VER_STL3888_C0) {
+ /* firmware information is only available since C0 */
+ fsp_get_sn(psmouse, &sn);
+ }
- psmouse_info(psmouse, "Finger Sensing Pad, hw: %d.%d.%d, sw: %s\n",
- ver >> 4, ver & 0x0F, rev, fsp_drv_ver);
+ psmouse_info(psmouse,
+ "Finger Sensing Pad, hw: %d.%d.%d, sn: %x, sw: %s\n",
+ ver >> 4, ver & 0x0F, rev, sn, fsp_drv_ver);
psmouse->private = priv = kzalloc(sizeof(struct fsp_data), GFP_KERNEL);
if (!priv)
diff --git a/drivers/input/mouse/sentelic.h b/drivers/input/mouse/sentelic.h
index 334de19e5ddb..aa697ece405b 100644
--- a/drivers/input/mouse/sentelic.h
+++ b/drivers/input/mouse/sentelic.h
@@ -65,6 +65,14 @@
#define FSP_BIT_SWC1_GST_GRP1 BIT(6)
#define FSP_BIT_SWC1_BX_COMPAT BIT(7)
+#define FSP_PAGE_0B (0x0b)
+#define FSP_PAGE_82 (0x82)
+#define FSP_PAGE_DEFAULT FSP_PAGE_82
+
+#define FSP_REG_SN0 (0x40)
+#define FSP_REG_SN1 (0x41)
+#define FSP_REG_SN2 (0x42)
+
/* Finger-sensing Pad packet formating related definitions */
/* absolute packet type */
diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c
index 17ff137b9bd5..d5928fd0c914 100644
--- a/drivers/input/mouse/sermouse.c
+++ b/drivers/input/mouse/sermouse.c
@@ -355,15 +355,4 @@ static struct serio_driver sermouse_drv = {
.disconnect = sermouse_disconnect,
};
-static int __init sermouse_init(void)
-{
- return serio_register_driver(&sermouse_drv);
-}
-
-static void __exit sermouse_exit(void)
-{
- serio_unregister_driver(&sermouse_drv);
-}
-
-module_init(sermouse_init);
-module_exit(sermouse_exit);
+module_serio_driver(sermouse_drv);
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index a4b14a41cbf4..c703d53be3a0 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -45,16 +45,6 @@
#define YMIN_NOMINAL 1408
#define YMAX_NOMINAL 4448
-/*
- * Synaptics touchpads report the y coordinate from bottom to top, which is
- * opposite from what userspace expects.
- * This function is used to invert y before reporting.
- */
-static int synaptics_invert_y(int y)
-{
- return YMAX_NOMINAL + YMIN_NOMINAL - y;
-}
-
/*****************************************************************************
* Stuff we need even when we do not want native Synaptics support
@@ -112,6 +102,16 @@ void synaptics_reset(struct psmouse *psmouse)
****************************************************************************/
/*
+ * Synaptics touchpads report the y coordinate from bottom to top, which is
+ * opposite from what userspace expects.
+ * This function is used to invert y before reporting.
+ */
+static int synaptics_invert_y(int y)
+{
+ return YMAX_NOMINAL + YMIN_NOMINAL - y;
+}
+
+/*
* Send a command to the synpatics touchpad by special commands
*/
static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param)
diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c
index eb9a3cfbeefa..e900d465aaf6 100644
--- a/drivers/input/mouse/vsxxxaa.c
+++ b/drivers/input/mouse/vsxxxaa.c
@@ -548,16 +548,4 @@ static struct serio_driver vsxxxaa_drv = {
.disconnect = vsxxxaa_disconnect,
};
-static int __init vsxxxaa_init(void)
-{
- return serio_register_driver(&vsxxxaa_drv);
-}
-
-static void __exit vsxxxaa_exit(void)
-{
- serio_unregister_driver(&vsxxxaa_drv);
-}
-
-module_init(vsxxxaa_init);
-module_exit(vsxxxaa_exit);
-
+module_serio_driver(vsxxxaa_drv);