Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (68 commits) Input: adp5589-keys - add support for the ADP5585 derivatives Input: imx_keypad - add pm suspend and resume support Input: force feedback - potential integer wrap in input_ff_create() Input: tsc2007 - make sure that X plate resistance is specified Input: serio_raw - fix memory leak when closing char device Input: serio_raw - kick clients when disconnecting port Input: serio_raw - explicitly mark disconnected ports as dead Input: serio_raw - fix coding style issues Input: serio_raw - use dev_*() for messages Input: serio_raw - use bool for boolean data Input: serio_raw - perform proper locking when adding clients to list Input: serio_raw - rename serio_raw_list to serio_raw_client Input: serio_raw - use kref instead of rolling out its own refcounting Input: psmouse - switch to using dev_*() for messages Input: wacom - correct max Y value on medium bamboos Input: wacom - add ABS_DISTANCE to Bamboo Pen reports Input: wacom - remove unneeded touch pressure initialization Input: lm8323 - wrap suspend and resume in CONFIG_PM_SLEEP Input: ad7879-i2c - wrap suspend and resume in CONFIG_PM_SLEEP Input: synaptics_i2c - wrap suspend and resume in CONFIG_PM_SLEEP ...
This commit is contained in:
commit
396e6e49c5
70 changed files with 4545 additions and 980 deletions
72
Documentation/ABI/testing/sysfs-driver-wacom
Normal file
72
Documentation/ABI/testing/sysfs-driver-wacom
Normal file
|
@ -0,0 +1,72 @@
|
|||
What: /sys/class/hidraw/hidraw*/device/speed
|
||||
Date: April 2010
|
||||
Kernel Version: 2.6.35
|
||||
Contact: linux-bluetooth@vger.kernel.org
|
||||
Description:
|
||||
The /sys/class/hidraw/hidraw*/device/speed file controls
|
||||
reporting speed of Wacom bluetooth tablet. Reading from
|
||||
this file returns 1 if tablet reports in high speed mode
|
||||
or 0 otherwise. Writing to this file one of these values
|
||||
switches reporting speed.
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/led
|
||||
Date: August 2011
|
||||
Contact: linux-input@vger.kernel.org
|
||||
Description:
|
||||
Attribute group for control of the status LEDs and the OLEDs.
|
||||
This attribute group is only available for Intuos 4 M, L,
|
||||
and XL (with LEDs and OLEDs) and Cintiq 21UX2 (LEDs only).
|
||||
Therefore its presence implicitly signifies the presence of
|
||||
said LEDs and OLEDs on the tablet device.
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/status0_luminance
|
||||
Date: August 2011
|
||||
Contact: linux-input@vger.kernel.org
|
||||
Description:
|
||||
Writing to this file sets the status LED luminance (1..127)
|
||||
when the stylus does not touch the tablet surface, and no
|
||||
button is pressed on the stylus. This luminance level is
|
||||
normally lower than the level when a button is pressed.
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/status1_luminance
|
||||
Date: August 2011
|
||||
Contact: linux-input@vger.kernel.org
|
||||
Description:
|
||||
Writing to this file sets the status LED luminance (1..127)
|
||||
when the stylus touches the tablet surface, or any button is
|
||||
pressed on the stylus.
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/status_led0_select
|
||||
Date: August 2011
|
||||
Contact: linux-input@vger.kernel.org
|
||||
Description:
|
||||
Writing to this file sets which one of the four (for Intuos 4)
|
||||
or of the right four (for Cintiq 21UX2) status LEDs is active (0..3).
|
||||
The other three LEDs on the same side are always inactive.
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/status_led1_select
|
||||
Date: September 2011
|
||||
Contact: linux-input@vger.kernel.org
|
||||
Description:
|
||||
Writing to this file sets which one of the left four (for Cintiq 21UX2)
|
||||
status LEDs is active (0..3). The other three LEDs on the left are always
|
||||
inactive.
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/buttons_luminance
|
||||
Date: August 2011
|
||||
Contact: linux-input@vger.kernel.org
|
||||
Description:
|
||||
Writing to this file sets the overall luminance level (0..15)
|
||||
of all eight button OLED displays.
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/button<n>_rawimg
|
||||
Date: August 2011
|
||||
Contact: linux-input@vger.kernel.org
|
||||
Description:
|
||||
When writing a 1024 byte raw image in Wacom Intuos 4
|
||||
interleaving format to the file, the image shows up on Button N
|
||||
of the device. The image is a 64x32 pixel 4-bit gray image. The
|
||||
1024 byte binary is split up into 16x 64 byte chunks. Each 64
|
||||
byte chunk encodes the image data for two consecutive lines on
|
||||
the display. The low nibble of each byte contains the first
|
||||
line, and the high nibble contains the second line.
|
|
@ -1,10 +0,0 @@
|
|||
What: /sys/class/hidraw/hidraw*/device/speed
|
||||
Date: April 2010
|
||||
Kernel Version: 2.6.35
|
||||
Contact: linux-bluetooth@vger.kernel.org
|
||||
Description:
|
||||
The /sys/class/hidraw/hidraw*/device/speed file controls
|
||||
reporting speed of wacom bluetooth tablet. Reading from
|
||||
this file returns 1 if tablet reports in high speed mode
|
||||
or 0 otherwise. Writing to this file one of these values
|
||||
switches reporting speed.
|
|
@ -16,15 +16,28 @@ Contents
|
|||
|
||||
1. Introduction
|
||||
2. Extra knobs
|
||||
3. Hardware version 1
|
||||
3.1 Registers
|
||||
3.2 Native relative mode 4 byte packet format
|
||||
3.3 Native absolute mode 4 byte packet format
|
||||
4. Hardware version 2
|
||||
3. Differentiating hardware versions
|
||||
4. Hardware version 1
|
||||
4.1 Registers
|
||||
4.2 Native absolute mode 6 byte packet format
|
||||
4.2.1 One finger touch
|
||||
4.2.2 Two finger touch
|
||||
4.2 Native relative mode 4 byte packet format
|
||||
4.3 Native absolute mode 4 byte packet format
|
||||
5. Hardware version 2
|
||||
5.1 Registers
|
||||
5.2 Native absolute mode 6 byte packet format
|
||||
5.2.1 Parity checking and packet re-synchronization
|
||||
5.2.2 One/Three finger touch
|
||||
5.2.3 Two finger touch
|
||||
6. Hardware version 3
|
||||
6.1 Registers
|
||||
6.2 Native absolute mode 6 byte packet format
|
||||
6.2.1 One/Three finger touch
|
||||
6.2.2 Two finger touch
|
||||
7. Hardware version 4
|
||||
7.1 Registers
|
||||
7.2 Native absolute mode 6 byte packet format
|
||||
7.2.1 Status packet
|
||||
7.2.2 Head packet
|
||||
7.2.3 Motion packet
|
||||
|
||||
|
||||
|
||||
|
@ -375,7 +388,7 @@ For all the other ones, there are just a few constant bits:
|
|||
|
||||
In case an error is detected, all the packets are shifted by one (and packet[0] is discarded).
|
||||
|
||||
5.2.1 One/Three finger touch
|
||||
5.2.2 One/Three finger touch
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
byte 0:
|
||||
|
@ -384,19 +397,19 @@ byte 0:
|
|||
n1 n0 w3 w2 . . R L
|
||||
|
||||
L, R = 1 when Left, Right mouse button pressed
|
||||
n1..n0 = numbers of fingers on touchpad
|
||||
n1..n0 = number of fingers on touchpad
|
||||
|
||||
byte 1:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
p7 p6 p5 p4 . x10 x9 x8
|
||||
p7 p6 p5 p4 x11 x10 x9 x8
|
||||
|
||||
byte 2:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
x7 x6 x5 x4 x3 x2 x1 x0
|
||||
|
||||
x10..x0 = absolute x value (horizontal)
|
||||
x11..x0 = absolute x value (horizontal)
|
||||
|
||||
byte 3:
|
||||
|
||||
|
@ -420,7 +433,7 @@ byte 3:
|
|||
byte 4:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
p3 p1 p2 p0 . . y9 y8
|
||||
p3 p1 p2 p0 y11 y10 y9 y8
|
||||
|
||||
p7..p0 = pressure (not EF113)
|
||||
|
||||
|
@ -429,10 +442,10 @@ byte 5:
|
|||
bit 7 6 5 4 3 2 1 0
|
||||
y7 y6 y5 y4 y3 y2 y1 y0
|
||||
|
||||
y9..y0 = absolute y value (vertical)
|
||||
y11..y0 = absolute y value (vertical)
|
||||
|
||||
|
||||
4.2.2 Two finger touch
|
||||
5.2.3 Two finger touch
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Note that the two pairs of coordinates are not exactly the coordinates of the
|
||||
|
@ -446,7 +459,7 @@ byte 0:
|
|||
n1 n0 ay8 ax8 . . R L
|
||||
|
||||
L, R = 1 when Left, Right mouse button pressed
|
||||
n1..n0 = numbers of fingers on touchpad
|
||||
n1..n0 = number of fingers on touchpad
|
||||
|
||||
byte 1:
|
||||
|
||||
|
@ -480,3 +493,253 @@ byte 5:
|
|||
by7 by8 by5 by4 by3 by2 by1 by0
|
||||
|
||||
by8..by0 = upper-right finger absolute y value
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
6. Hardware version 3
|
||||
==================
|
||||
|
||||
6.1 Registers
|
||||
~~~~~~~~~
|
||||
* reg_10
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
0 0 0 0 0 0 0 A
|
||||
|
||||
A: 1 = enable absolute tracking
|
||||
|
||||
6.2 Native absolute mode 6 byte packet format
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
1 and 3 finger touch shares the same 6-byte packet format, except that
|
||||
3 finger touch only reports the position of the center of all three fingers.
|
||||
|
||||
Firmware would send 12 bytes of data for 2 finger touch.
|
||||
|
||||
Note on debounce:
|
||||
In case the box has unstable power supply or other electricity issues, or
|
||||
when number of finger changes, F/W would send "debounce packet" to inform
|
||||
driver that the hardware is in debounce status.
|
||||
The debouce packet has the following signature:
|
||||
byte 0: 0xc4
|
||||
byte 1: 0xff
|
||||
byte 2: 0xff
|
||||
byte 3: 0x02
|
||||
byte 4: 0xff
|
||||
byte 5: 0xff
|
||||
When we encounter this kind of packet, we just ignore it.
|
||||
|
||||
6.2.1 One/Three finger touch
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
byte 0:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
n1 n0 w3 w2 0 1 R L
|
||||
|
||||
L, R = 1 when Left, Right mouse button pressed
|
||||
n1..n0 = number of fingers on touchpad
|
||||
|
||||
byte 1:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
p7 p6 p5 p4 x11 x10 x9 x8
|
||||
|
||||
byte 2:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
x7 x6 x5 x4 x3 x2 x1 x0
|
||||
|
||||
x11..x0 = absolute x value (horizontal)
|
||||
|
||||
byte 3:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
0 0 w1 w0 0 0 1 0
|
||||
|
||||
w3..w0 = width of the finger touch
|
||||
|
||||
byte 4:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
p3 p1 p2 p0 y11 y10 y9 y8
|
||||
|
||||
p7..p0 = pressure
|
||||
|
||||
byte 5:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
y7 y6 y5 y4 y3 y2 y1 y0
|
||||
|
||||
y11..y0 = absolute y value (vertical)
|
||||
|
||||
6.2.2 Two finger touch
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
The packet format is exactly the same for two finger touch, except the hardware
|
||||
sends two 6 byte packets. The first packet contains data for the first finger,
|
||||
the second packet has data for the second finger. So for two finger touch a
|
||||
total of 12 bytes are sent.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
7. Hardware version 4
|
||||
==================
|
||||
|
||||
7.1 Registers
|
||||
~~~~~~~~~
|
||||
* reg_07
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
0 0 0 0 0 0 0 A
|
||||
|
||||
A: 1 = enable absolute tracking
|
||||
|
||||
7.2 Native absolute mode 6 byte packet format
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
v4 hardware is a true multitouch touchpad, capable of tracking up to 5 fingers.
|
||||
Unfortunately, due to PS/2's limited bandwidth, its packet format is rather
|
||||
complex.
|
||||
|
||||
Whenever the numbers or identities of the fingers changes, the hardware sends a
|
||||
status packet to indicate how many and which fingers is on touchpad, followed by
|
||||
head packets or motion packets. A head packet contains data of finger id, finger
|
||||
position (absolute x, y values), width, and pressure. A motion packet contains
|
||||
two fingers' position delta.
|
||||
|
||||
For example, when status packet tells there are 2 fingers on touchpad, then we
|
||||
can expect two following head packets. If the finger status doesn't change,
|
||||
the following packets would be motion packets, only sending delta of finger
|
||||
position, until we receive a status packet.
|
||||
|
||||
One exception is one finger touch. when a status packet tells us there is only
|
||||
one finger, the hardware would just send head packets afterwards.
|
||||
|
||||
7.2.1 Status packet
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
byte 0:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
. . . . 0 1 R L
|
||||
|
||||
L, R = 1 when Left, Right mouse button pressed
|
||||
|
||||
byte 1:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
. . . ft4 ft3 ft2 ft1 ft0
|
||||
|
||||
ft4 ft3 ft2 ft1 ft0 ftn = 1 when finger n is on touchpad
|
||||
|
||||
byte 2: not used
|
||||
|
||||
byte 3:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
. . . 1 0 0 0 0
|
||||
|
||||
constant bits
|
||||
|
||||
byte 4:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
p . . . . . . .
|
||||
|
||||
p = 1 for palm
|
||||
|
||||
byte 5: not used
|
||||
|
||||
7.2.2 Head packet
|
||||
~~~~~~~~~~~
|
||||
|
||||
byte 0:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
w3 w2 w1 w0 0 1 R L
|
||||
|
||||
L, R = 1 when Left, Right mouse button pressed
|
||||
w3..w0 = finger width (spans how many trace lines)
|
||||
|
||||
byte 1:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
p7 p6 p5 p4 x11 x10 x9 x8
|
||||
|
||||
byte 2:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
x7 x6 x5 x4 x3 x2 x1 x0
|
||||
|
||||
x11..x0 = absolute x value (horizontal)
|
||||
|
||||
byte 3:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
id2 id1 id0 1 0 0 0 1
|
||||
|
||||
id2..id0 = finger id
|
||||
|
||||
byte 4:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
p3 p1 p2 p0 y11 y10 y9 y8
|
||||
|
||||
p7..p0 = pressure
|
||||
|
||||
byte 5:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
y7 y6 y5 y4 y3 y2 y1 y0
|
||||
|
||||
y11..y0 = absolute y value (vertical)
|
||||
|
||||
7.2.3 Motion packet
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
byte 0:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
id2 id1 id0 w 0 1 R L
|
||||
|
||||
L, R = 1 when Left, Right mouse button pressed
|
||||
id2..id0 = finger id
|
||||
w = 1 when delta overflows (> 127 or < -128), in this case
|
||||
firmware sends us (delta x / 5) and (delta y / 5)
|
||||
|
||||
byte 1:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
x7 x6 x5 x4 x3 x2 x1 x0
|
||||
|
||||
x7..x0 = delta x (two's complement)
|
||||
|
||||
byte 2:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
y7 y6 y5 y4 y3 y2 y1 y0
|
||||
|
||||
y7..y0 = delta y (two's complement)
|
||||
|
||||
byte 3:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
id2 id1 id0 1 0 0 1 0
|
||||
|
||||
id2..id0 = finger id
|
||||
|
||||
byte 4:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
x7 x6 x5 x4 x3 x2 x1 x0
|
||||
|
||||
x7..x0 = delta x (two's complement)
|
||||
|
||||
byte 5:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
y7 y6 y5 y4 y3 y2 y1 y0
|
||||
|
||||
y7..y0 = delta y (two's complement)
|
||||
|
||||
byte 0 ~ 2 for one finger
|
||||
byte 3 ~ 5 for another
|
||||
|
|
|
@ -65,6 +65,20 @@ the full state of each initiated contact has to reside in the receiving
|
|||
end. Upon receiving an MT event, one simply updates the appropriate
|
||||
attribute of the current slot.
|
||||
|
||||
Some devices identify and/or track more contacts than they can report to the
|
||||
driver. A driver for such a device should associate one type B slot with each
|
||||
contact that is reported by the hardware. Whenever the identity of the
|
||||
contact associated with a slot changes, the driver should invalidate that
|
||||
slot by changing its ABS_MT_TRACKING_ID. If the hardware signals that it is
|
||||
tracking more contacts than it is currently reporting, the driver should use
|
||||
a BTN_TOOL_*TAP event to inform userspace of the total number of contacts
|
||||
being tracked by the hardware at that moment. The driver should do this by
|
||||
explicitly sending the corresponding BTN_TOOL_*TAP event and setting
|
||||
use_count to false when calling input_mt_report_pointer_emulation().
|
||||
The driver should only advertise as many slots as the hardware can report.
|
||||
Userspace can detect that a driver can report more total contacts than slots
|
||||
by noting that the largest supported BTN_TOOL_*TAP event is larger than the
|
||||
total number of type B slots reported in the absinfo for the ABS_MT_SLOT axis.
|
||||
|
||||
Protocol Example A
|
||||
------------------
|
||||
|
|
|
@ -309,9 +309,10 @@ EXPORT_SYMBOL_GPL(input_ff_event);
|
|||
* Once ff device is created you need to setup its upload, erase,
|
||||
* playback and other handlers before registering input device
|
||||
*/
|
||||
int input_ff_create(struct input_dev *dev, int max_effects)
|
||||
int input_ff_create(struct input_dev *dev, unsigned int max_effects)
|
||||
{
|
||||
struct ff_device *ff;
|
||||
size_t ff_dev_size;
|
||||
int i;
|
||||
|
||||
if (!max_effects) {
|
||||
|
@ -319,8 +320,12 @@ int input_ff_create(struct input_dev *dev, int max_effects)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
ff = kzalloc(sizeof(struct ff_device) +
|
||||
max_effects * sizeof(struct file *), GFP_KERNEL);
|
||||
ff_dev_size = sizeof(struct ff_device) +
|
||||
max_effects * sizeof(struct file *);
|
||||
if (ff_dev_size < max_effects) /* overflow */
|
||||
return -EINVAL;
|
||||
|
||||
ff = kzalloc(ff_dev_size, GFP_KERNEL);
|
||||
if (!ff)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
@ -117,6 +117,7 @@ void input_mt_report_finger_count(struct input_dev *dev, int count)
|
|||
input_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, count == 2);
|
||||
input_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, count == 3);
|
||||
input_event(dev, EV_KEY, BTN_TOOL_QUADTAP, count == 4);
|
||||
input_event(dev, EV_KEY, BTN_TOOL_QUINTTAP, count == 5);
|
||||
}
|
||||
EXPORT_SYMBOL(input_mt_report_finger_count);
|
||||
|
||||
|
|
|
@ -49,8 +49,10 @@ static int input_open_polled_device(struct input_dev *input)
|
|||
dev->open(dev);
|
||||
|
||||
/* Only start polling if polling is enabled */
|
||||
if (dev->poll_interval > 0)
|
||||
queue_delayed_work(system_freezable_wq, &dev->work, 0);
|
||||
if (dev->poll_interval > 0) {
|
||||
dev->poll(dev);
|
||||
input_polldev_queue_work(dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -33,10 +33,10 @@ config KEYBOARD_ADP5588
|
|||
module will be called adp5588-keys.
|
||||
|
||||
config KEYBOARD_ADP5589
|
||||
tristate "ADP5589 I2C QWERTY Keypad and IO Expander"
|
||||
tristate "ADP5585/ADP5589 I2C QWERTY Keypad and IO Expander"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you want to use a ADP5589 attached to your
|
||||
Say Y here if you want to use a ADP5585/ADP5589 attached to your
|
||||
system I2C bus.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
|
|
|
@ -550,7 +550,7 @@ static int __devinit adp5588_probe(struct i2c_client *client,
|
|||
}
|
||||
|
||||
error = request_irq(client->irq, adp5588_irq,
|
||||
IRQF_TRIGGER_FALLING | IRQF_DISABLED,
|
||||
IRQF_TRIGGER_FALLING,
|
||||
client->dev.driver->name, kpad);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "irq %d busy?\n", client->irq);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Description: keypad driver for ADP5589
|
||||
* Description: keypad driver for ADP5589, ADP5585
|
||||
* I2C QWERTY Keypad and IO Expander
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
|
@ -22,35 +22,165 @@
|
|||
|
||||
#include <linux/input/adp5589.h>
|
||||
|
||||
/* ADP5589/ADP5585 Common Registers */
|
||||
#define ADP5589_5_ID 0x00
|
||||
#define ADP5589_5_INT_STATUS 0x01
|
||||
#define ADP5589_5_STATUS 0x02
|
||||
#define ADP5589_5_FIFO_1 0x03
|
||||
#define ADP5589_5_FIFO_2 0x04
|
||||
#define ADP5589_5_FIFO_3 0x05
|
||||
#define ADP5589_5_FIFO_4 0x06
|
||||
#define ADP5589_5_FIFO_5 0x07
|
||||
#define ADP5589_5_FIFO_6 0x08
|
||||
#define ADP5589_5_FIFO_7 0x09
|
||||
#define ADP5589_5_FIFO_8 0x0A
|
||||
#define ADP5589_5_FIFO_9 0x0B
|
||||
#define ADP5589_5_FIFO_10 0x0C
|
||||
#define ADP5589_5_FIFO_11 0x0D
|
||||
#define ADP5589_5_FIFO_12 0x0E
|
||||
#define ADP5589_5_FIFO_13 0x0F
|
||||
#define ADP5589_5_FIFO_14 0x10
|
||||
#define ADP5589_5_FIFO_15 0x11
|
||||
#define ADP5589_5_FIFO_16 0x12
|
||||
#define ADP5589_5_GPI_INT_STAT_A 0x13
|
||||
#define ADP5589_5_GPI_INT_STAT_B 0x14
|
||||
|
||||
/* ADP5589 Registers */
|
||||
#define ADP5589_GPI_INT_STAT_C 0x15
|
||||
#define ADP5589_GPI_STATUS_A 0x16
|
||||
#define ADP5589_GPI_STATUS_B 0x17
|
||||
#define ADP5589_GPI_STATUS_C 0x18
|
||||
#define ADP5589_RPULL_CONFIG_A 0x19
|
||||
#define ADP5589_RPULL_CONFIG_B 0x1A
|
||||
#define ADP5589_RPULL_CONFIG_C 0x1B
|
||||
#define ADP5589_RPULL_CONFIG_D 0x1C
|
||||
#define ADP5589_RPULL_CONFIG_E 0x1D
|
||||
#define ADP5589_GPI_INT_LEVEL_A 0x1E
|
||||
#define ADP5589_GPI_INT_LEVEL_B 0x1F
|
||||
#define ADP5589_GPI_INT_LEVEL_C 0x20
|
||||
#define ADP5589_GPI_EVENT_EN_A 0x21
|
||||
#define ADP5589_GPI_EVENT_EN_B 0x22
|
||||
#define ADP5589_GPI_EVENT_EN_C 0x23
|
||||
#define ADP5589_GPI_INTERRUPT_EN_A 0x24
|
||||
#define ADP5589_GPI_INTERRUPT_EN_B 0x25
|
||||
#define ADP5589_GPI_INTERRUPT_EN_C 0x26
|
||||
#define ADP5589_DEBOUNCE_DIS_A 0x27
|
||||
#define ADP5589_DEBOUNCE_DIS_B 0x28
|
||||
#define ADP5589_DEBOUNCE_DIS_C 0x29
|
||||
#define ADP5589_GPO_DATA_OUT_A 0x2A
|
||||
#define ADP5589_GPO_DATA_OUT_B 0x2B
|
||||
#define ADP5589_GPO_DATA_OUT_C 0x2C
|
||||
#define ADP5589_GPO_OUT_MODE_A 0x2D
|
||||
#define ADP5589_GPO_OUT_MODE_B 0x2E
|
||||
#define ADP5589_GPO_OUT_MODE_C 0x2F
|
||||
#define ADP5589_GPIO_DIRECTION_A 0x30
|
||||
#define ADP5589_GPIO_DIRECTION_B 0x31
|
||||
#define ADP5589_GPIO_DIRECTION_C 0x32
|
||||
#define ADP5589_UNLOCK1 0x33
|
||||
#define ADP5589_UNLOCK2 0x34
|
||||
#define ADP5589_EXT_LOCK_EVENT 0x35
|
||||
#define ADP5589_UNLOCK_TIMERS 0x36
|
||||
#define ADP5589_LOCK_CFG 0x37
|
||||
#define ADP5589_RESET1_EVENT_A 0x38
|
||||
#define ADP5589_RESET1_EVENT_B 0x39
|
||||
#define ADP5589_RESET1_EVENT_C 0x3A
|
||||
#define ADP5589_RESET2_EVENT_A 0x3B
|
||||
#define ADP5589_RESET2_EVENT_B 0x3C
|
||||
#define ADP5589_RESET_CFG 0x3D
|
||||
#define ADP5589_PWM_OFFT_LOW 0x3E
|
||||
#define ADP5589_PWM_OFFT_HIGH 0x3F
|
||||
#define ADP5589_PWM_ONT_LOW 0x40
|
||||
#define ADP5589_PWM_ONT_HIGH 0x41
|
||||
#define ADP5589_PWM_CFG 0x42
|
||||
#define ADP5589_CLOCK_DIV_CFG 0x43
|
||||
#define ADP5589_LOGIC_1_CFG 0x44
|
||||
#define ADP5589_LOGIC_2_CFG 0x45
|
||||
#define ADP5589_LOGIC_FF_CFG 0x46
|
||||
#define ADP5589_LOGIC_INT_EVENT_EN 0x47
|
||||
#define ADP5589_POLL_PTIME_CFG 0x48
|
||||
#define ADP5589_PIN_CONFIG_A 0x49
|
||||
#define ADP5589_PIN_CONFIG_B 0x4A
|
||||
#define ADP5589_PIN_CONFIG_C 0x4B
|
||||
#define ADP5589_PIN_CONFIG_D 0x4C
|
||||
#define ADP5589_GENERAL_CFG 0x4D
|
||||
#define ADP5589_INT_EN 0x4E
|
||||
|
||||
/* ADP5585 Registers */
|
||||
#define ADP5585_GPI_STATUS_A 0x15
|
||||
#define ADP5585_GPI_STATUS_B 0x16
|
||||
#define ADP5585_RPULL_CONFIG_A 0x17
|
||||
#define ADP5585_RPULL_CONFIG_B 0x18
|
||||
#define ADP5585_RPULL_CONFIG_C 0x19
|
||||
#define ADP5585_RPULL_CONFIG_D 0x1A
|
||||
#define ADP5585_GPI_INT_LEVEL_A 0x1B
|
||||
#define ADP5585_GPI_INT_LEVEL_B 0x1C
|
||||
#define ADP5585_GPI_EVENT_EN_A 0x1D
|
||||
#define ADP5585_GPI_EVENT_EN_B 0x1E
|
||||
#define ADP5585_GPI_INTERRUPT_EN_A 0x1F
|
||||
#define ADP5585_GPI_INTERRUPT_EN_B 0x20
|
||||
#define ADP5585_DEBOUNCE_DIS_A 0x21
|
||||
#define ADP5585_DEBOUNCE_DIS_B 0x22
|
||||
#define ADP5585_GPO_DATA_OUT_A 0x23
|
||||
#define ADP5585_GPO_DATA_OUT_B 0x24
|
||||
#define ADP5585_GPO_OUT_MODE_A 0x25
|
||||
#define ADP5585_GPO_OUT_MODE_B 0x26
|
||||
#define ADP5585_GPIO_DIRECTION_A 0x27
|
||||
#define ADP5585_GPIO_DIRECTION_B 0x28
|
||||
#define ADP5585_RESET1_EVENT_A 0x29
|
||||
#define ADP5585_RESET1_EVENT_B 0x2A
|
||||
#define ADP5585_RESET1_EVENT_C 0x2B
|
||||
#define ADP5585_RESET2_EVENT_A 0x2C
|
||||
#define ADP5585_RESET2_EVENT_B 0x2D
|
||||
#define ADP5585_RESET_CFG 0x2E
|
||||
#define ADP5585_PWM_OFFT_LOW 0x2F
|
||||
#define ADP5585_PWM_OFFT_HIGH 0x30
|
||||
#define ADP5585_PWM_ONT_LOW 0x31
|
||||
#define ADP5585_PWM_ONT_HIGH 0x32
|
||||
#define ADP5585_PWM_CFG 0x33
|
||||
#define ADP5585_LOGIC_CFG 0x34
|
||||
#define ADP5585_LOGIC_FF_CFG 0x35
|
||||
#define ADP5585_LOGIC_INT_EVENT_EN 0x36
|
||||
#define ADP5585_POLL_PTIME_CFG 0x37
|
||||
#define ADP5585_PIN_CONFIG_A 0x38
|
||||
#define ADP5585_PIN_CONFIG_B 0x39
|
||||
#define ADP5585_PIN_CONFIG_D 0x3A
|
||||
#define ADP5585_GENERAL_CFG 0x3B
|
||||
#define ADP5585_INT_EN 0x3C
|
||||
|
||||
/* ID Register */
|
||||
#define ADP5589_5_DEVICE_ID_MASK 0xF
|
||||
#define ADP5589_5_MAN_ID_MASK 0xF
|
||||
#define ADP5589_5_MAN_ID_SHIFT 4
|
||||
#define ADP5589_5_MAN_ID 0x02
|
||||
|
||||
/* GENERAL_CFG Register */
|
||||
#define OSC_EN (1 << 7)
|
||||
#define CORE_CLK(x) (((x) & 0x3) << 5)
|
||||
#define LCK_TRK_LOGIC (1 << 4)
|
||||
#define LCK_TRK_GPI (1 << 3)
|
||||
#define LCK_TRK_LOGIC (1 << 4) /* ADP5589 only */
|
||||
#define LCK_TRK_GPI (1 << 3) /* ADP5589 only */
|
||||
#define INT_CFG (1 << 1)
|
||||
#define RST_CFG (1 << 0)
|
||||
|
||||
/* INT_EN Register */
|
||||
#define LOGIC2_IEN (1 << 5)
|
||||
#define LOGIC2_IEN (1 << 5) /* ADP5589 only */
|
||||
#define LOGIC1_IEN (1 << 4)
|
||||
#define LOCK_IEN (1 << 3)
|
||||
#define LOCK_IEN (1 << 3) /* ADP5589 only */
|
||||
#define OVRFLOW_IEN (1 << 2)
|
||||
#define GPI_IEN (1 << 1)
|
||||
#define EVENT_IEN (1 << 0)
|
||||
|
||||
/* Interrupt Status Register */
|
||||
#define LOGIC2_INT (1 << 5)
|
||||
#define LOGIC2_INT (1 << 5) /* ADP5589 only */
|
||||
#define LOGIC1_INT (1 << 4)
|
||||
#define LOCK_INT (1 << 3)
|
||||
#define LOCK_INT (1 << 3) /* ADP5589 only */
|
||||
#define OVRFLOW_INT (1 << 2)
|
||||
#define GPI_INT (1 << 1)
|
||||
#define EVENT_INT (1 << 0)
|
||||
|
||||
/* STATUS Register */
|
||||
|
||||
#define LOGIC2_STAT (1 << 7)
|
||||
#define LOGIC2_STAT (1 << 7) /* ADP5589 only */
|
||||
#define LOGIC1_STAT (1 << 6)
|
||||
#define LOCK_STAT (1 << 5)
|
||||
#define LOCK_STAT (1 << 5) /* ADP5589 only */
|
||||
#define KEC 0xF
|
||||
|
||||
/* PIN_CONFIG_D Register */
|
||||
|
@ -61,27 +191,54 @@
|
|||
#define LOCK_EN (1 << 0)
|
||||
|
||||
#define PTIME_MASK 0x3
|
||||
#define LTIME_MASK 0x3
|
||||
#define LTIME_MASK 0x3 /* ADP5589 only */
|
||||
|
||||
/* Key Event Register xy */
|
||||
#define KEY_EV_PRESSED (1 << 7)
|
||||
#define KEY_EV_MASK (0x7F)
|
||||
|
||||
#define KEYP_MAX_EVENT 16
|
||||
#define ADP5589_MAXGPIO 19
|
||||
#define ADP5585_MAXGPIO 11 /* 10 on the ADP5585-01, 11 on ADP5585-02 */
|
||||
|
||||
#define MAXGPIO 19
|
||||
#define ADP_BANK(offs) ((offs) >> 3)
|
||||
#define ADP_BIT(offs) (1u << ((offs) & 0x7))
|
||||
enum {
|
||||
ADP5589,
|
||||
ADP5585_01,
|
||||
ADP5585_02
|
||||
};
|
||||
|
||||
struct adp_constants {
|
||||
u8 maxgpio;
|
||||
u8 keymapsize;
|
||||
u8 gpi_pin_row_base;
|
||||
u8 gpi_pin_row_end;
|
||||
u8 gpi_pin_col_base;
|
||||
u8 gpi_pin_base;
|
||||
u8 gpi_pin_end;
|
||||
u8 gpimapsize_max;
|
||||
u8 max_row_num;
|
||||
u8 max_col_num;
|
||||
u8 row_mask;
|
||||
u8 col_mask;
|
||||
u8 col_shift;
|
||||
u8 c4_extend_cfg;
|
||||
u8 (*bank) (u8 offset);
|
||||
u8 (*bit) (u8 offset);
|
||||
u8 (*reg) (u8 reg);
|
||||
};
|
||||
|
||||
struct adp5589_kpad {
|
||||
struct i2c_client *client;
|
||||
struct input_dev *input;
|
||||
const struct adp_constants *var;
|
||||
unsigned short keycode[ADP5589_KEYMAPSIZE];
|
||||
const struct adp5589_gpi_map *gpimap;
|
||||
unsigned short gpimapsize;
|
||||
unsigned extend_cfg;
|
||||
bool is_adp5585;
|
||||
bool adp5585_support_row5;
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
unsigned char gpiomap[MAXGPIO];
|
||||
unsigned char gpiomap[ADP5589_MAXGPIO];
|
||||
bool export_gpio;
|
||||
struct gpio_chip gc;
|
||||
struct mutex gpio_lock; /* Protect cached dir, dat_out */
|
||||
|
@ -90,6 +247,129 @@ struct adp5589_kpad {
|
|||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* ADP5589 / ADP5585 derivative / variant handling
|
||||
*/
|
||||
|
||||
|
||||
/* ADP5589 */
|
||||
|
||||
static unsigned char adp5589_bank(unsigned char offset)
|
||||
{
|
||||
return offset >> 3;
|
||||
}
|
||||
|
||||
static unsigned char adp5589_bit(unsigned char offset)
|
||||
{
|
||||
return 1u << (offset & 0x7);
|
||||
}
|
||||
|
||||
static unsigned char adp5589_reg(unsigned char reg)
|
||||
{
|
||||
return reg;
|
||||
}
|
||||
|
||||
static const struct adp_constants const_adp5589 = {
|
||||
.maxgpio = ADP5589_MAXGPIO,
|
||||
.keymapsize = ADP5589_KEYMAPSIZE,
|
||||
.gpi_pin_row_base = ADP5589_GPI_PIN_ROW_BASE,
|
||||
.gpi_pin_row_end = ADP5589_GPI_PIN_ROW_END,
|
||||
.gpi_pin_col_base = ADP5589_GPI_PIN_COL_BASE,
|
||||
.gpi_pin_base = ADP5589_GPI_PIN_BASE,
|
||||
.gpi_pin_end = ADP5589_GPI_PIN_END,
|
||||
.gpimapsize_max = ADP5589_GPIMAPSIZE_MAX,
|
||||
.c4_extend_cfg = 12,
|
||||
.max_row_num = ADP5589_MAX_ROW_NUM,
|
||||
.max_col_num = ADP5589_MAX_COL_NUM,
|
||||
.row_mask = ADP5589_ROW_MASK,
|
||||
.col_mask = ADP5589_COL_MASK,
|
||||
.col_shift = ADP5589_COL_SHIFT,
|
||||
.bank = adp5589_bank,
|
||||
.bit = adp5589_bit,
|
||||
.reg = adp5589_reg,
|
||||
};
|
||||
|
||||
/* ADP5585 */
|
||||
|
||||
static unsigned char adp5585_bank(unsigned char offset)
|
||||
{
|
||||
return offset > ADP5585_MAX_ROW_NUM;
|
||||
}
|
||||
|
||||
static unsigned char adp5585_bit(unsigned char offset)
|
||||
{
|
||||
return (offset > ADP5585_MAX_ROW_NUM) ?
|
||||
1u << (offset - ADP5585_COL_SHIFT) : 1u << offset;
|
||||
}
|
||||
|
||||
static const unsigned char adp5585_reg_lut[] = {
|
||||
[ADP5589_GPI_STATUS_A] = ADP5585_GPI_STATUS_A,
|
||||
[ADP5589_GPI_STATUS_B] = ADP5585_GPI_STATUS_B,
|
||||
[ADP5589_RPULL_CONFIG_A] = ADP5585_RPULL_CONFIG_A,
|
||||
[ADP5589_RPULL_CONFIG_B] = ADP5585_RPULL_CONFIG_B,
|
||||
[ADP5589_RPULL_CONFIG_C] = ADP5585_RPULL_CONFIG_C,
|
||||
[ADP5589_RPULL_CONFIG_D] = ADP5585_RPULL_CONFIG_D,
|
||||
[ADP5589_GPI_INT_LEVEL_A] = ADP5585_GPI_INT_LEVEL_A,
|
||||
[ADP5589_GPI_INT_LEVEL_B] = ADP5585_GPI_INT_LEVEL_B,
|
||||
[ADP5589_GPI_EVENT_EN_A] = ADP5585_GPI_EVENT_EN_A,
|
||||
[ADP5589_GPI_EVENT_EN_B] = ADP5585_GPI_EVENT_EN_B,
|
||||
[ADP5589_GPI_INTERRUPT_EN_A] = ADP5585_GPI_INTERRUPT_EN_A,
|
||||
[ADP5589_GPI_INTERRUPT_EN_B] = ADP5585_GPI_INTERRUPT_EN_B,
|
||||
[ADP5589_DEBOUNCE_DIS_A] = ADP5585_DEBOUNCE_DIS_A,
|
||||
[ADP5589_DEBOUNCE_DIS_B] = ADP5585_DEBOUNCE_DIS_B,
|
||||
[ADP5589_GPO_DATA_OUT_A] = ADP5585_GPO_DATA_OUT_A,
|
||||
[ADP5589_GPO_DATA_OUT_B] = ADP5585_GPO_DATA_OUT_B,
|
||||
[ADP5589_GPO_OUT_MODE_A] = ADP5585_GPO_OUT_MODE_A,
|
||||
[ADP5589_GPO_OUT_MODE_B] = ADP5585_GPO_OUT_MODE_B,
|
||||
[ADP5589_GPIO_DIRECTION_A] = ADP5585_GPIO_DIRECTION_A,
|
||||
[ADP5589_GPIO_DIRECTION_B] = ADP5585_GPIO_DIRECTION_B,
|
||||
[ADP5589_RESET1_EVENT_A] = ADP5585_RESET1_EVENT_A,
|
||||
[ADP5589_RESET1_EVENT_B] = ADP5585_RESET1_EVENT_B,
|
||||
[ADP5589_RESET1_EVENT_C] = ADP5585_RESET1_EVENT_C,
|
||||
[ADP5589_RESET2_EVENT_A] = ADP5585_RESET2_EVENT_A,
|
||||
[ADP5589_RESET2_EVENT_B] = ADP5585_RESET2_EVENT_B,
|
||||
[ADP5589_RESET_CFG] = ADP5585_RESET_CFG,
|
||||
[ADP5589_PWM_OFFT_LOW] = ADP5585_PWM_OFFT_LOW,
|
||||
[ADP5589_PWM_OFFT_HIGH] = ADP5585_PWM_OFFT_HIGH,
|
||||
[ADP5589_PWM_ONT_LOW] = ADP5585_PWM_ONT_LOW,
|
||||
[ADP5589_PWM_ONT_HIGH] = ADP5585_PWM_ONT_HIGH,
|
||||
[ADP5589_PWM_CFG] = ADP5585_PWM_CFG,
|
||||
[ADP5589_LOGIC_1_CFG] = ADP5585_LOGIC_CFG,
|
||||
[ADP5589_LOGIC_FF_CFG] = ADP5585_LOGIC_FF_CFG,
|
||||
[ADP5589_LOGIC_INT_EVENT_EN] = ADP5585_LOGIC_INT_EVENT_EN,
|
||||
[ADP5589_POLL_PTIME_CFG] = ADP5585_POLL_PTIME_CFG,
|
||||
[ADP5589_PIN_CONFIG_A] = ADP5585_PIN_CONFIG_A,
|
||||
[ADP5589_PIN_CONFIG_B] = ADP5585_PIN_CONFIG_B,
|
||||
[ADP5589_PIN_CONFIG_D] = ADP5585_PIN_CONFIG_D,
|
||||
[ADP5589_GENERAL_CFG] = ADP5585_GENERAL_CFG,
|
||||
[ADP5589_INT_EN] = ADP5585_INT_EN,
|
||||
};
|
||||
|
||||
static unsigned char adp5585_reg(unsigned char reg)
|
||||
{
|
||||
return adp5585_reg_lut[reg];
|
||||
}
|
||||
|
||||
static const struct adp_constants const_adp5585 = {
|
||||
.maxgpio = ADP5585_MAXGPIO,
|
||||
.keymapsize = ADP5585_KEYMAPSIZE,
|
||||
.gpi_pin_row_base = ADP5585_GPI_PIN_ROW_BASE,
|
||||
.gpi_pin_row_end = ADP5585_GPI_PIN_ROW_END,
|
||||
.gpi_pin_col_base = ADP5585_GPI_PIN_COL_BASE,
|
||||
.gpi_pin_base = ADP5585_GPI_PIN_BASE,
|
||||
.gpi_pin_end = ADP5585_GPI_PIN_END,
|
||||
.gpimapsize_max = ADP5585_GPIMAPSIZE_MAX,
|
||||
.c4_extend_cfg = 10,
|
||||
.max_row_num = ADP5585_MAX_ROW_NUM,
|
||||
.max_col_num = ADP5585_MAX_COL_NUM,
|
||||
.row_mask = ADP5585_ROW_MASK,
|
||||
.col_mask = ADP5585_COL_MASK,
|
||||
.col_shift = ADP5585_COL_SHIFT,
|
||||
.bank = adp5585_bank,
|
||||
.bit = adp5585_bit,
|
||||
.reg = adp5585_reg,
|
||||
};
|
||||
|
||||
static int adp5589_read(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
int ret = i2c_smbus_read_byte_data(client, reg);
|
||||
|
@ -109,10 +389,11 @@ static int adp5589_write(struct i2c_client *client, u8 reg, u8 val)
|
|||
static int adp5589_gpio_get_value(struct gpio_chip *chip, unsigned off)
|
||||
{
|
||||
struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
|
||||
unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
|
||||
unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
|
||||
unsigned int bank = kpad->var->bank(kpad->gpiomap[off]);
|
||||
unsigned int bit = kpad->var->bit(kpad->gpiomap[off]);
|
||||
|
||||
return !!(adp5589_read(kpad->client, ADP5589_GPI_STATUS_A + bank) &
|
||||
return !!(adp5589_read(kpad->client,
|
||||
kpad->var->reg(ADP5589_GPI_STATUS_A) + bank) &
|
||||
bit);
|
||||
}
|
||||
|
||||
|
@ -120,8 +401,8 @@ static void adp5589_gpio_set_value(struct gpio_chip *chip,
|
|||
unsigned off, int val)
|
||||
{
|
||||
struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
|
||||
unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
|
||||
unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
|
||||
unsigned int bank = kpad->var->bank(kpad->gpiomap[off]);
|
||||
unsigned int bit = kpad->var->bit(kpad->gpiomap[off]);
|
||||
|
||||
mutex_lock(&kpad->gpio_lock);
|
||||
|
||||
|
@ -130,8 +411,8 @@ static void adp5589_gpio_set_value(struct gpio_chip *chip,
|
|||
else
|
||||
kpad->dat_out[bank] &= ~bit;
|
||||
|
||||
adp5589_write(kpad->client, ADP5589_GPO_DATA_OUT_A + bank,
|
||||
kpad->dat_out[bank]);
|
||||
adp5589_write(kpad->client, kpad->var->reg(ADP5589_GPO_DATA_OUT_A) +
|
||||
bank, kpad->dat_out[bank]);
|
||||
|
||||
mutex_unlock(&kpad->gpio_lock);
|
||||
}
|
||||
|
@ -139,14 +420,15 @@ static void adp5589_gpio_set_value(struct gpio_chip *chip,
|
|||
static int adp5589_gpio_direction_input(struct gpio_chip *chip, unsigned off)
|
||||
{
|
||||
struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
|
||||
unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
|
||||
unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
|
||||
unsigned int bank = kpad->var->bank(kpad->gpiomap[off]);
|
||||
unsigned int bit = kpad->var->bit(kpad->gpiomap[off]);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&kpad->gpio_lock);
|
||||
|
||||
kpad->dir[bank] &= ~bit;
|
||||
ret = adp5589_write(kpad->client, ADP5589_GPIO_DIRECTION_A + bank,
|
||||
ret = adp5589_write(kpad->client,
|
||||
kpad->var->reg(ADP5589_GPIO_DIRECTION_A) + bank,
|
||||
kpad->dir[bank]);
|
||||
|
||||
mutex_unlock(&kpad->gpio_lock);
|
||||
|
@ -158,8 +440,8 @@ static int adp5589_gpio_direction_output(struct gpio_chip *chip,
|
|||
unsigned off, int val)
|
||||
{
|
||||
struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
|
||||
unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
|
||||
unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
|
||||
unsigned int bank = kpad->var->bank(kpad->gpiomap[off]);
|
||||
unsigned int bit = kpad->var->bit(kpad->gpiomap[off]);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&kpad->gpio_lock);
|
||||
|
@ -171,9 +453,10 @@ static int adp5589_gpio_direction_output(struct gpio_chip *chip,
|
|||
else
|
||||
kpad->dat_out[bank] &= ~bit;
|
||||
|
||||
ret = adp5589_write(kpad->client, ADP5589_GPO_DATA_OUT_A + bank,
|
||||
kpad->dat_out[bank]);
|
||||
ret |= adp5589_write(kpad->client, ADP5589_GPIO_DIRECTION_A + bank,
|
||||
ret = adp5589_write(kpad->client, kpad->var->reg(ADP5589_GPO_DATA_OUT_A)
|
||||
+ bank, kpad->dat_out[bank]);
|
||||
ret |= adp5589_write(kpad->client,
|
||||
kpad->var->reg(ADP5589_GPIO_DIRECTION_A) + bank,
|
||||
kpad->dir[bank]);
|
||||
|
||||
mutex_unlock(&kpad->gpio_lock);
|
||||
|
@ -184,26 +467,29 @@ static int adp5589_gpio_direction_output(struct gpio_chip *chip,
|
|||
static int __devinit adp5589_build_gpiomap(struct adp5589_kpad *kpad,
|
||||
const struct adp5589_kpad_platform_data *pdata)
|
||||
{
|
||||
bool pin_used[MAXGPIO];
|
||||
bool pin_used[ADP5589_MAXGPIO];
|
||||
int n_unused = 0;
|
||||
int i;
|
||||
|
||||
memset(pin_used, false, sizeof(pin_used));
|
||||
|
||||
for (i = 0; i < MAXGPIO; i++)
|
||||
for (i = 0; i < kpad->var->maxgpio; i++)
|
||||
if (pdata->keypad_en_mask & (1 << i))
|
||||
pin_used[i] = true;
|
||||
|
||||
for (i = 0; i < kpad->gpimapsize; i++)
|
||||
pin_used[kpad->gpimap[i].pin - ADP5589_GPI_PIN_BASE] = true;
|
||||
pin_used[kpad->gpimap[i].pin - kpad->var->gpi_pin_base] = true;
|
||||
|
||||
if (kpad->extend_cfg & R4_EXTEND_CFG)
|
||||
pin_used[4] = true;
|
||||
|
||||
if (kpad->extend_cfg & C4_EXTEND_CFG)
|
||||
pin_used[12] = true;
|
||||
pin_used[kpad->var->c4_extend_cfg] = true;
|
||||
|
||||
for (i = 0; i < MAXGPIO; i++)
|
||||
if (!kpad->adp5585_support_row5)
|
||||
pin_used[5] = true;
|
||||
|
||||
for (i = 0; i < kpad->var->maxgpio; i++)
|
||||
if (!pin_used[i])
|
||||
kpad->gpiomap[n_unused++] = i;
|
||||
|
||||
|
@ -246,11 +532,11 @@ static int __devinit adp5589_gpio_add(struct adp5589_kpad *kpad)
|
|||
return error;
|
||||
}
|
||||
|
||||
for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
|
||||
kpad->dat_out[i] = adp5589_read(kpad->client,
|
||||
ADP5589_GPO_DATA_OUT_A + i);
|
||||
kpad->dir[i] = adp5589_read(kpad->client,
|
||||
ADP5589_GPIO_DIRECTION_A + i);
|
||||
for (i = 0; i <= kpad->var->bank(kpad->var->maxgpio); i++) {
|
||||
kpad->dat_out[i] = adp5589_read(kpad->client, kpad->var->reg(
|
||||
ADP5589_GPO_DATA_OUT_A) + i);
|
||||
kpad->dir[i] = adp5589_read(kpad->client, kpad->var->reg(
|
||||
ADP5589_GPIO_DIRECTION_A) + i);
|
||||
}
|
||||
|
||||
if (gpio_data->setup) {
|
||||
|
@ -317,11 +603,11 @@ static void adp5589_report_events(struct adp5589_kpad *kpad, int ev_cnt)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < ev_cnt; i++) {
|
||||
int key = adp5589_read(kpad->client, ADP5589_FIFO_1 + i);
|
||||
int key = adp5589_read(kpad->client, ADP5589_5_FIFO_1 + i);
|
||||
int key_val = key & KEY_EV_MASK;
|
||||
|
||||
if (key_val >= ADP5589_GPI_PIN_BASE &&
|
||||
key_val <= ADP5589_GPI_PIN_END) {
|
||||
if (key_val >= kpad->var->gpi_pin_base &&
|
||||
key_val <= kpad->var->gpi_pin_end) {
|
||||
adp5589_report_switches(kpad, key, key_val);
|
||||
} else {
|
||||
input_report_key(kpad->input,
|
||||
|
@ -337,29 +623,30 @@ static irqreturn_t adp5589_irq(int irq, void *handle)
|
|||
struct i2c_client *client = kpad->client;
|
||||
int status, ev_cnt;
|
||||
|
||||
status = adp5589_read(client, ADP5589_INT_STATUS);
|
||||
status = adp5589_read(client, ADP5589_5_INT_STATUS);
|
||||
|
||||
if (status & OVRFLOW_INT) /* Unlikely and should never happen */
|
||||
dev_err(&client->dev, "Event Overflow Error\n");
|
||||
|
||||
if (status & EVENT_INT) {
|
||||
ev_cnt = adp5589_read(client, ADP5589_STATUS) & KEC;
|
||||
ev_cnt = adp5589_read(client, ADP5589_5_STATUS) & KEC;
|
||||
if (ev_cnt) {
|
||||
adp5589_report_events(kpad, ev_cnt);
|
||||
input_sync(kpad->input);
|
||||
}
|
||||
}
|
||||
|
||||
adp5589_write(client, ADP5589_INT_STATUS, status); /* Status is W1C */
|
||||
adp5589_write(client, ADP5589_5_INT_STATUS, status); /* Status is W1C */
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __devinit adp5589_get_evcode(struct adp5589_kpad *kpad, unsigned short key)
|
||||
static int __devinit adp5589_get_evcode(struct adp5589_kpad *kpad,
|
||||
unsigned short key)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ADP5589_KEYMAPSIZE; i++)
|
||||
for (i = 0; i < kpad->var->keymapsize; i++)
|
||||
if (key == kpad->keycode[i])
|
||||
return (i + 1) | KEY_EV_PRESSED;
|
||||
|
||||
|
@ -373,18 +660,22 @@ static int __devinit adp5589_setup(struct adp5589_kpad *kpad)
|
|||
struct i2c_client *client = kpad->client;
|
||||
const struct adp5589_kpad_platform_data *pdata =
|
||||
client->dev.platform_data;
|
||||
int i, ret;
|
||||
u8 (*reg) (u8) = kpad->var->reg;
|
||||
unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0;
|
||||
unsigned char pull_mask = 0;
|
||||
int i, ret;
|
||||
|
||||
ret = adp5589_write(client, ADP5589_PIN_CONFIG_A,
|
||||
pdata->keypad_en_mask & 0xFF);
|
||||
ret |= adp5589_write(client, ADP5589_PIN_CONFIG_B,
|
||||
(pdata->keypad_en_mask >> 8) & 0xFF);
|
||||
ret = adp5589_write(client, reg(ADP5589_PIN_CONFIG_A),
|
||||
pdata->keypad_en_mask & kpad->var->row_mask);
|
||||
ret |= adp5589_write(client, reg(ADP5589_PIN_CONFIG_B),
|
||||
(pdata->keypad_en_mask >> kpad->var->col_shift) &
|
||||
kpad->var->col_mask);
|
||||
|
||||
if (!kpad->is_adp5585)
|
||||
ret |= adp5589_write(client, ADP5589_PIN_CONFIG_C,
|
||||
(pdata->keypad_en_mask >> 16) & 0xFF);
|
||||
|
||||
if (pdata->en_keylock) {
|
||||
if (!kpad->is_adp5585 && pdata->en_keylock) {
|
||||
ret |= adp5589_write(client, ADP5589_UNLOCK1,
|
||||
pdata->unlock_key1);
|
||||
ret |= adp5589_write(client, ADP5589_UNLOCK2,
|
||||
|
@ -395,96 +686,130 @@ static int __devinit adp5589_setup(struct adp5589_kpad *kpad)
|
|||
}
|
||||
|
||||
for (i = 0; i < KEYP_MAX_EVENT; i++)
|
||||
ret |= adp5589_read(client, ADP5589_FIFO_1 + i);
|
||||
ret |= adp5589_read(client, ADP5589_5_FIFO_1 + i);
|
||||
|
||||
for (i = 0; i < pdata->gpimapsize; i++) {
|
||||
unsigned short pin = pdata->gpimap[i].pin;
|
||||
|
||||
if (pin <= ADP5589_GPI_PIN_ROW_END) {
|
||||
evt_mode1 |= (1 << (pin - ADP5589_GPI_PIN_ROW_BASE));
|
||||
if (pin <= kpad->var->gpi_pin_row_end) {
|
||||
evt_mode1 |= (1 << (pin - kpad->var->gpi_pin_row_base));
|
||||
} else {
|
||||
evt_mode2 |=
|
||||
((1 << (pin - ADP5589_GPI_PIN_COL_BASE)) & 0xFF);
|
||||
evt_mode3 |=
|
||||
((1 << (pin - ADP5589_GPI_PIN_COL_BASE)) >> 8);
|
||||
((1 << (pin - kpad->var->gpi_pin_col_base)) & 0xFF);
|
||||
if (!kpad->is_adp5585)
|
||||
evt_mode3 |= ((1 << (pin -
|
||||
kpad->var->gpi_pin_col_base)) >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
if (pdata->gpimapsize) {
|
||||
ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_A, evt_mode1);
|
||||
ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_B, evt_mode2);
|
||||
ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_C, evt_mode3);
|
||||
ret |= adp5589_write(client, reg(ADP5589_GPI_EVENT_EN_A),
|
||||
evt_mode1);
|
||||
ret |= adp5589_write(client, reg(ADP5589_GPI_EVENT_EN_B),
|
||||
evt_mode2);
|
||||
if (!kpad->is_adp5585)
|
||||
ret |= adp5589_write(client,
|
||||
reg(ADP5589_GPI_EVENT_EN_C),
|
||||
evt_mode3);
|
||||
}
|
||||
|
||||
if (pdata->pull_dis_mask & pdata->pullup_en_100k &
|
||||
pdata->pullup_en_300k & pdata->pulldown_en_300k)
|
||||
dev_warn(&client->dev, "Conflicting pull resistor config\n");
|
||||
|
||||
for (i = 0; i < MAXGPIO; i++) {
|
||||
unsigned val = 0;
|
||||
|
||||
if (pdata->pullup_en_300k & (1 << i))
|
||||
for (i = 0; i <= kpad->var->max_row_num; i++) {
|
||||
unsigned val = 0, bit = (1 << i);
|
||||
if (pdata->pullup_en_300k & bit)
|
||||
val = 0;
|
||||
else if (pdata->pulldown_en_300k & (1 << i))
|
||||
else if (pdata->pulldown_en_300k & bit)
|
||||
val = 1;
|
||||
else if (pdata->pullup_en_100k & (1 << i))
|
||||
else if (pdata->pullup_en_100k & bit)
|
||||
val = 2;
|
||||
else if (pdata->pull_dis_mask & (1 << i))
|
||||
else if (pdata->pull_dis_mask & bit)
|
||||
val = 3;
|
||||
|
||||
pull_mask |= val << (2 * (i & 0x3));
|
||||
|
||||
if ((i & 0x3) == 0x3 || i == MAXGPIO - 1) {
|
||||
if (i == 3 || i == kpad->var->max_row_num) {
|
||||
ret |= adp5589_write(client, reg(ADP5585_RPULL_CONFIG_A)
|
||||
+ (i >> 2), pull_mask);
|
||||
pull_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i <= kpad->var->max_col_num; i++) {
|
||||
unsigned val = 0, bit = 1 << (i + kpad->var->col_shift);
|
||||
if (pdata->pullup_en_300k & bit)
|
||||
val = 0;
|
||||
else if (pdata->pulldown_en_300k & bit)
|
||||
val = 1;
|
||||
else if (pdata->pullup_en_100k & bit)
|
||||
val = 2;
|
||||
else if (pdata->pull_dis_mask & bit)
|
||||
val = 3;
|
||||
|
||||
pull_mask |= val << (2 * (i & 0x3));
|
||||
|
||||
if (i == 3 || i == kpad->var->max_col_num) {
|
||||
ret |= adp5589_write(client,
|
||||
ADP5589_RPULL_CONFIG_A + (i >> 2),
|
||||
pull_mask);
|
||||
reg(ADP5585_RPULL_CONFIG_C) +
|
||||
(i >> 2), pull_mask);
|
||||
pull_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (pdata->reset1_key_1 && pdata->reset1_key_2 && pdata->reset1_key_3) {
|
||||
ret |= adp5589_write(client, ADP5589_RESET1_EVENT_A,
|
||||
ret |= adp5589_write(client, reg(ADP5589_RESET1_EVENT_A),
|
||||
adp5589_get_evcode(kpad,
|
||||
pdata->reset1_key_1));
|
||||
ret |= adp5589_write(client, ADP5589_RESET1_EVENT_B,
|
||||
ret |= adp5589_write(client, reg(ADP5589_RESET1_EVENT_B),
|
||||
adp5589_get_evcode(kpad,
|
||||
pdata->reset1_key_2));
|
||||
ret |= adp5589_write(client, ADP5589_RESET1_EVENT_C,
|
||||
ret |= adp5589_write(client, reg(ADP5589_RESET1_EVENT_C),
|
||||
adp5589_get_evcode(kpad,
|
||||
pdata->reset1_key_3));
|
||||
kpad->extend_cfg |= R4_EXTEND_CFG;
|
||||
}
|
||||
|
||||
if (pdata->reset2_key_1 && pdata->reset2_key_2) {
|
||||
ret |= adp5589_write(client, ADP5589_RESET2_EVENT_A,
|
||||
ret |= adp5589_write(client, reg(ADP5589_RESET2_EVENT_A),
|
||||
adp5589_get_evcode(kpad,
|
||||
pdata->reset2_key_1));
|
||||
ret |= adp5589_write(client, ADP5589_RESET2_EVENT_B,
|
||||
ret |= adp5589_write(client, reg(ADP5589_RESET2_EVENT_B),
|
||||
adp5589_get_evcode(kpad,
|
||||
pdata->reset2_key_2));
|
||||
kpad->extend_cfg |= C4_EXTEND_CFG;
|
||||
}
|
||||
|
||||
if (kpad->extend_cfg) {
|
||||
ret |= adp5589_write(client, ADP5589_RESET_CFG,
|
||||
ret |= adp5589_write(client, reg(ADP5589_RESET_CFG),
|
||||
pdata->reset_cfg);
|
||||
ret |= adp5589_write(client, ADP5589_PIN_CONFIG_D,
|
||||
ret |= adp5589_write(client, reg(ADP5589_PIN_CONFIG_D),
|
||||
kpad->extend_cfg);
|
||||
}
|
||||
|
||||
for (i = 0; i <= ADP_BANK(MAXGPIO); i++)
|
||||
ret |= adp5589_write(client, ADP5589_DEBOUNCE_DIS_A + i,
|
||||
pdata->debounce_dis_mask >> (i * 8));
|
||||
ret |= adp5589_write(client, reg(ADP5589_DEBOUNCE_DIS_A),
|
||||
pdata->debounce_dis_mask & kpad->var->row_mask);
|
||||
|
||||
ret |= adp5589_write(client, ADP5589_POLL_PTIME_CFG,
|
||||
ret |= adp5589_write(client, reg(ADP5589_DEBOUNCE_DIS_B),
|
||||
(pdata->debounce_dis_mask >> kpad->var->col_shift)
|
||||
& kpad->var->col_mask);
|
||||
|
||||
if (!kpad->is_adp5585)
|
||||
ret |= adp5589_write(client, reg(ADP5589_DEBOUNCE_DIS_C),
|
||||
(pdata->debounce_dis_mask >> 16) & 0xFF);
|
||||
|
||||
ret |= adp5589_write(client, reg(ADP5589_POLL_PTIME_CFG),
|
||||
pdata->scan_cycle_time & PTIME_MASK);
|
||||
ret |= adp5589_write(client, ADP5589_INT_STATUS, LOGIC2_INT |
|
||||
LOGIC1_INT | OVRFLOW_INT | LOCK_INT |
|
||||
ret |= adp5589_write(client, ADP5589_5_INT_STATUS,
|
||||
(kpad->is_adp5585 ? 0 : LOGIC2_INT) |
|
||||
LOGIC1_INT | OVRFLOW_INT |
|
||||
(kpad->is_adp5585 ? 0 : LOCK_INT) |
|
||||
GPI_INT | EVENT_INT); /* Status is W1C */
|
||||
|
||||
ret |= adp5589_write(client, ADP5589_GENERAL_CFG,
|
||||
ret |= adp5589_write(client, reg(ADP5589_GENERAL_CFG),
|
||||
INT_CFG | OSC_EN | CORE_CLK(3));
|
||||
ret |= adp5589_write(client, ADP5589_INT_EN,
|
||||
ret |= adp5589_write(client, reg(ADP5589_INT_EN),
|
||||
OVRFLOW_IEN | GPI_IEN | EVENT_IEN);
|
||||
|
||||
if (ret < 0) {
|
||||
|
@ -497,30 +822,33 @@ static int __devinit adp5589_setup(struct adp5589_kpad *kpad)
|
|||
|
||||
static void __devinit adp5589_report_switch_state(struct adp5589_kpad *kpad)
|
||||
{
|
||||
int gpi_stat1 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_A);
|
||||
int gpi_stat2 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_B);
|
||||
int gpi_stat3 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_C);
|
||||
int gpi_stat_tmp, pin_loc;
|
||||
int i;
|
||||
int gpi_stat1 = adp5589_read(kpad->client,
|
||||
kpad->var->reg(ADP5589_GPI_STATUS_A));
|
||||
int gpi_stat2 = adp5589_read(kpad->client,
|
||||
kpad->var->reg(ADP5589_GPI_STATUS_B));
|
||||
int gpi_stat3 = !kpad->is_adp5585 ?
|
||||
adp5589_read(kpad->client, ADP5589_GPI_STATUS_C) : 0;
|
||||
|
||||
for (i = 0; i < kpad->gpimapsize; i++) {
|
||||
unsigned short pin = kpad->gpimap[i].pin;
|
||||
|
||||
if (pin <= ADP5589_GPI_PIN_ROW_END) {
|
||||
if (pin <= kpad->var->gpi_pin_row_end) {
|
||||
gpi_stat_tmp = gpi_stat1;
|
||||
pin_loc = pin - ADP5589_GPI_PIN_ROW_BASE;
|
||||
} else if ((pin - ADP5589_GPI_PIN_COL_BASE) < 8) {
|
||||
pin_loc = pin - kpad->var->gpi_pin_row_base;
|
||||
} else if ((pin - kpad->var->gpi_pin_col_base) < 8) {
|
||||
gpi_stat_tmp = gpi_stat2;
|
||||
pin_loc = pin - ADP5589_GPI_PIN_COL_BASE;
|
||||
pin_loc = pin - kpad->var->gpi_pin_col_base;
|
||||
} else {
|
||||
gpi_stat_tmp = gpi_stat3;
|
||||
pin_loc = pin - ADP5589_GPI_PIN_COL_BASE - 8;
|
||||
pin_loc = pin - kpad->var->gpi_pin_col_base - 8;
|
||||
}
|
||||
|
||||
if (gpi_stat_tmp < 0) {
|
||||
dev_err(&kpad->client->dev,
|
||||
"Can't read GPIO_DAT_STAT switch"
|
||||
" %d default to OFF\n", pin);
|
||||
"Can't read GPIO_DAT_STAT switch %d, default to OFF\n",
|
||||
pin);
|
||||
gpi_stat_tmp = 0;
|
||||
}
|
||||
|
||||
|
@ -536,7 +864,8 @@ static int __devinit adp5589_probe(struct i2c_client *client,
|
|||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct adp5589_kpad *kpad;
|
||||
const struct adp5589_kpad_platform_data *pdata;
|
||||
const struct adp5589_kpad_platform_data *pdata =
|
||||
client->dev.platform_data;
|
||||
struct input_dev *input;
|
||||
unsigned int revid;
|
||||
int ret, i;
|
||||
|
@ -548,56 +877,79 @@ static int __devinit adp5589_probe(struct i2c_client *client,
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
pdata = client->dev.platform_data;
|
||||
if (!pdata) {
|
||||
dev_err(&client->dev, "no platform data?\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!((pdata->keypad_en_mask & 0xFF) &&
|
||||
(pdata->keypad_en_mask >> 8)) || !pdata->keymap) {
|
||||
dev_err(&client->dev, "no rows, cols or keymap from pdata\n");
|
||||
return -EINVAL;
|
||||
kpad = kzalloc(sizeof(*kpad), GFP_KERNEL);
|
||||
if (!kpad)
|
||||
return -ENOMEM;
|
||||
|
||||
switch (id->driver_data) {
|
||||
case ADP5585_02:
|
||||
kpad->adp5585_support_row5 = true;
|
||||
case ADP5585_01:
|
||||
kpad->is_adp5585 = true;
|
||||
kpad->var = &const_adp5585;
|
||||
break;
|
||||
case ADP5589:
|
||||
kpad->var = &const_adp5589;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pdata->keymapsize != ADP5589_KEYMAPSIZE) {
|
||||
if (!((pdata->keypad_en_mask & kpad->var->row_mask) &&
|
||||
(pdata->keypad_en_mask >> kpad->var->col_shift)) ||
|
||||
!pdata->keymap) {
|
||||
dev_err(&client->dev, "no rows, cols or keymap from pdata\n");
|
||||
error = -EINVAL;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
if (pdata->keymapsize != kpad->var->keymapsize) {
|
||||
dev_err(&client->dev, "invalid keymapsize\n");
|
||||
return -EINVAL;
|
||||
error = -EINVAL;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
if (!pdata->gpimap && pdata->gpimapsize) {
|
||||
dev_err(&client->dev, "invalid gpimap from pdata\n");
|
||||
return -EINVAL;
|
||||
error = -EINVAL;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
if (pdata->gpimapsize > ADP5589_GPIMAPSIZE_MAX) {
|
||||
if (pdata->gpimapsize > kpad->var->gpimapsize_max) {
|
||||
dev_err(&client->dev, "invalid gpimapsize\n");
|
||||
return -EINVAL;
|
||||
error = -EINVAL;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
for (i = 0; i < pdata->gpimapsize; i++) {
|
||||
unsigned short pin = pdata->gpimap[i].pin;
|
||||
|
||||
if (pin < ADP5589_GPI_PIN_BASE || pin > ADP5589_GPI_PIN_END) {
|
||||
if (pin < kpad->var->gpi_pin_base ||
|
||||
pin > kpad->var->gpi_pin_end) {
|
||||
dev_err(&client->dev, "invalid gpi pin data\n");
|
||||
return -EINVAL;
|
||||
error = -EINVAL;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
if ((1 << (pin - ADP5589_GPI_PIN_ROW_BASE)) &
|
||||
if ((1 << (pin - kpad->var->gpi_pin_row_base)) &
|
||||
pdata->keypad_en_mask) {
|
||||
dev_err(&client->dev, "invalid gpi row/col data\n");
|
||||
return -EINVAL;
|
||||
error = -EINVAL;
|
||||
goto err_free_mem;
|
||||
}
|
||||
}
|
||||
|
||||
if (!client->irq) {
|
||||
dev_err(&client->dev, "no IRQ?\n");
|
||||
return -EINVAL;
|
||||
error = -EINVAL;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
kpad = kzalloc(sizeof(*kpad), GFP_KERNEL);
|
||||
input = input_allocate_device();
|
||||
if (!kpad || !input) {
|
||||
if (!input) {
|
||||
error = -ENOMEM;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
@ -605,13 +957,13 @@ static int __devinit adp5589_probe(struct i2c_client *client,
|
|||
kpad->client = client;
|
||||
kpad->input = input;
|
||||
|
||||
ret = adp5589_read(client, ADP5589_ID);
|
||||
ret = adp5589_read(client, ADP5589_5_ID);
|
||||
if (ret < 0) {
|
||||
error = ret;
|
||||
goto err_free_mem;
|
||||
goto err_free_input;
|
||||
}
|
||||
|
||||
revid = (u8) ret & ADP5589_DEVICE_ID_MASK;
|
||||
revid = (u8) ret & ADP5589_5_DEVICE_ID_MASK;
|
||||
|
||||
input->name = client->name;
|
||||
input->phys = "adp5589-keys/input0";
|
||||
|
@ -652,7 +1004,7 @@ static int __devinit adp5589_probe(struct i2c_client *client,
|
|||
error = input_register_device(input);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "unable to register input device\n");
|
||||
goto err_free_mem;
|
||||
goto err_free_input;
|
||||
}
|
||||
|
||||
error = request_threaded_irq(client->irq, NULL, adp5589_irq,
|
||||
|
@ -685,8 +1037,9 @@ static int __devinit adp5589_probe(struct i2c_client *client,
|
|||
err_unreg_dev:
|
||||
input_unregister_device(input);
|
||||
input = NULL;
|
||||
err_free_mem:
|
||||
err_free_input:
|
||||
input_free_device(input);
|
||||
err_free_mem:
|
||||
kfree(kpad);
|
||||
|
||||
return error;
|
||||
|
@ -696,7 +1049,7 @@ static int __devexit adp5589_remove(struct i2c_client *client)
|
|||
{
|
||||
struct adp5589_kpad *kpad = i2c_get_clientdata(client);
|
||||
|
||||
adp5589_write(client, ADP5589_GENERAL_CFG, 0);
|
||||
adp5589_write(client, kpad->var->reg(ADP5589_GENERAL_CFG), 0);
|
||||
free_irq(client->irq, kpad);
|
||||
input_unregister_device(kpad->input);
|
||||
adp5589_gpio_remove(kpad);
|
||||
|
@ -736,7 +1089,9 @@ static int adp5589_resume(struct device *dev)
|
|||
static SIMPLE_DEV_PM_OPS(adp5589_dev_pm_ops, adp5589_suspend, adp5589_resume);
|
||||
|
||||
static const struct i2c_device_id adp5589_id[] = {
|
||||
{"adp5589-keys", 0},
|
||||
{"adp5589-keys", ADP5589},
|
||||
{"adp5585-keys", ADP5585_01},
|
||||
{"adp5585-02-keys", ADP5585_02}, /* Adds ROW5 to ADP5585 */
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -767,4 +1122,4 @@ module_exit(adp5589_exit);
|
|||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
|
||||
MODULE_DESCRIPTION("ADP5589 Keypad driver");
|
||||
MODULE_DESCRIPTION("ADP5589/ADP5585 Keypad driver");
|
||||
|
|
|
@ -271,7 +271,7 @@ static int __init davinci_ks_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
error = request_irq(davinci_ks->irq, davinci_ks_interrupt,
|
||||
IRQF_DISABLED, pdev->name, davinci_ks);
|
||||
0, pdev->name, davinci_ks);
|
||||
if (error < 0) {
|
||||
dev_err(dev, "unable to register davinci key scan interrupt\n");
|
||||
goto fail5;
|
||||
|
|
|
@ -323,7 +323,7 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
|
|||
platform_set_drvdata(pdev, keypad);
|
||||
|
||||
err = request_irq(keypad->irq, ep93xx_keypad_irq_handler,
|
||||
IRQF_DISABLED, pdev->name, keypad);
|
||||
0, pdev->name, keypad);
|
||||
if (err)
|
||||
goto failed_free_dev;
|
||||
|
||||
|
|
|
@ -461,8 +461,7 @@ static int gpio_keys_get_devtree_pdata(struct device *dev,
|
|||
struct device_node *node, *pp;
|
||||
int i;
|
||||
struct gpio_keys_button *buttons;
|
||||
const u32 *reg;
|
||||
int len;
|
||||
u32 reg;
|
||||
|
||||
node = dev->of_node;
|
||||
if (node == NULL)
|
||||
|
@ -470,7 +469,7 @@ static int gpio_keys_get_devtree_pdata(struct device *dev,
|
|||
|
||||
memset(pdata, 0, sizeof *pdata);
|
||||
|
||||
pdata->rep = !!of_get_property(node, "autorepeat", &len);
|
||||
pdata->rep = !!of_get_property(node, "autorepeat", NULL);
|
||||
|
||||
/* First count the subnodes */
|
||||
pdata->nbuttons = 0;
|
||||
|
@ -498,22 +497,25 @@ static int gpio_keys_get_devtree_pdata(struct device *dev,
|
|||
buttons[i].gpio = of_get_gpio_flags(pp, 0, &flags);
|
||||
buttons[i].active_low = flags & OF_GPIO_ACTIVE_LOW;
|
||||
|
||||
reg = of_get_property(pp, "linux,code", &len);
|
||||
if (!reg) {
|
||||
if (of_property_read_u32(pp, "linux,code", ®)) {
|
||||
dev_err(dev, "Button without keycode: 0x%x\n", buttons[i].gpio);
|
||||
goto out_fail;
|
||||
}
|
||||
buttons[i].code = be32_to_cpup(reg);
|
||||
buttons[i].code = reg;
|
||||
|
||||
buttons[i].desc = of_get_property(pp, "label", &len);
|
||||
buttons[i].desc = of_get_property(pp, "label", NULL);
|
||||
|
||||
reg = of_get_property(pp, "linux,input-type", &len);
|
||||
buttons[i].type = reg ? be32_to_cpup(reg) : EV_KEY;
|
||||
if (of_property_read_u32(pp, "linux,input-type", ®) == 0)
|
||||
buttons[i].type = reg;
|
||||
else
|
||||
buttons[i].type = EV_KEY;
|
||||
|
||||
buttons[i].wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
|
||||
|
||||
reg = of_get_property(pp, "debounce-interval", &len);
|
||||
buttons[i].debounce_interval = reg ? be32_to_cpup(reg) : 5;
|
||||
if (of_property_read_u32(pp, "debounce-interval", ®) == 0)
|
||||
buttons[i].debounce_interval = reg;
|
||||
else
|
||||
buttons[i].debounce_interval = 5;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
|
|
@ -510,7 +510,7 @@ static int __devinit imx_keypad_probe(struct platform_device *pdev)
|
|||
/* Ensure that the keypad will stay dormant until opened */
|
||||
imx_keypad_inhibit(keypad);
|
||||
|
||||
error = request_irq(irq, imx_keypad_irq_handler, IRQF_DISABLED,
|
||||
error = request_irq(irq, imx_keypad_irq_handler, 0,
|
||||
pdev->name, keypad);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to request IRQ\n");
|
||||
|
@ -567,10 +567,54 @@ static int __devexit imx_keypad_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int imx_kbd_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct imx_keypad *kbd = platform_get_drvdata(pdev);
|
||||
struct input_dev *input_dev = kbd->input_dev;
|
||||
|
||||
/* imx kbd can wake up system even clock is disabled */
|
||||
mutex_lock(&input_dev->mutex);
|
||||
|
||||
if (input_dev->users)
|
||||
clk_disable(kbd->clk);
|
||||
|
||||
mutex_unlock(&input_dev->mutex);
|
||||
|
||||
if (device_may_wakeup(&pdev->dev))
|
||||
enable_irq_wake(kbd->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx_kbd_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct imx_keypad *kbd = platform_get_drvdata(pdev);
|
||||
struct input_dev *input_dev = kbd->input_dev;
|
||||
|
||||
if (device_may_wakeup(&pdev->dev))
|
||||
disable_irq_wake(kbd->irq);
|
||||
|
||||
mutex_lock(&input_dev->mutex);
|
||||
|
||||
if (input_dev->users)
|
||||
clk_enable(kbd->clk);
|
||||
|
||||
mutex_unlock(&input_dev->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(imx_kbd_pm_ops, imx_kbd_suspend, imx_kbd_resume);
|
||||
|
||||
static struct platform_driver imx_keypad_driver = {
|
||||
.driver = {
|
||||
.name = "imx-keypad",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &imx_kbd_pm_ops,
|
||||
},
|
||||
.probe = imx_keypad_probe,
|
||||
.remove = __devexit_p(imx_keypad_remove),
|
||||
|
|
|
@ -129,7 +129,7 @@ static int __devinit jornada720_kbd_probe(struct platform_device *pdev)
|
|||
|
||||
err = request_irq(IRQ_GPIO0,
|
||||
jornada720_kbd_interrupt,
|
||||
IRQF_DISABLED | IRQF_TRIGGER_FALLING,
|
||||
IRQF_TRIGGER_FALLING,
|
||||
"jornadakbd", pdev);
|
||||
if (err) {
|
||||
printk(KERN_INFO "jornadakbd720_kbd: Unable to grab IRQ\n");
|
||||
|
|
|
@ -788,7 +788,7 @@ static int __devexit lm8323_remove(struct i2c_client *client)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/*
|
||||
* We don't need to explicitly suspend the chip, as it already switches off
|
||||
* when there's no activity.
|
||||
|
|
|
@ -343,7 +343,6 @@ static int __devinit init_matrix_gpio(struct platform_device *pdev,
|
|||
for (i = 0; i < pdata->num_row_gpios; i++) {
|
||||
err = request_irq(gpio_to_irq(pdata->row_gpios[i]),
|
||||
matrix_keypad_interrupt,
|
||||
IRQF_DISABLED |
|
||||
IRQF_TRIGGER_RISING |
|
||||
IRQF_TRIGGER_FALLING,
|
||||
"matrix-keypad", keypad);
|
||||
|
|
|
@ -535,7 +535,7 @@ static int __devinit pxa27x_keypad_probe(struct platform_device *pdev)
|
|||
input_dev->evbit[0] |= BIT_MASK(EV_REL);
|
||||
}
|
||||
|
||||
error = request_irq(irq, pxa27x_keypad_irq_handler, IRQF_DISABLED,
|
||||
error = request_irq(irq, pxa27x_keypad_irq_handler, 0,
|
||||
pdev->name, keypad);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to request IRQ\n");
|
||||
|
|
|
@ -148,7 +148,7 @@ static int __devinit pxa930_rotary_probe(struct platform_device *pdev)
|
|||
r->input_dev = input_dev;
|
||||
input_set_drvdata(input_dev, r);
|
||||
|
||||
err = request_irq(irq, rotary_irq, IRQF_DISABLED,
|
||||
err = request_irq(irq, rotary_irq, 0,
|
||||
"enhanced rotary", r);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "failed to request IRQ\n");
|
||||
|
|
|
@ -90,7 +90,7 @@ struct tc_keypad {
|
|||
bool keypad_stopped;
|
||||
};
|
||||
|
||||
static int __devinit tc3589x_keypad_init_key_hardware(struct tc_keypad *keypad)
|
||||
static int tc3589x_keypad_init_key_hardware(struct tc_keypad *keypad)
|
||||
{
|
||||
int ret;
|
||||
struct tc3589x *tc3589x = keypad->tc3589x;
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
|
||||
#define KBC_ROW_CFG0_0 0x8
|
||||
#define KBC_COL_CFG0_0 0x18
|
||||
#define KBC_TO_CNT_0 0x24
|
||||
#define KBC_INIT_DLY_0 0x28
|
||||
#define KBC_RPT_DLY_0 0x2c
|
||||
#define KBC_KP_ENT0_0 0x30
|
||||
|
@ -70,6 +71,7 @@ struct tegra_kbc {
|
|||
spinlock_t lock;
|
||||
unsigned int repoll_dly;
|
||||
unsigned long cp_dly_jiffies;
|
||||
unsigned int cp_to_wkup_dly;
|
||||
bool use_fn_map;
|
||||
bool use_ghost_filter;
|
||||
const struct tegra_kbc_platform_data *pdata;
|
||||
|
@ -258,12 +260,10 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
|
|||
u32 val = 0;
|
||||
unsigned int i;
|
||||
unsigned int num_down = 0;
|
||||
unsigned long flags;
|
||||
bool fn_keypress = false;
|
||||
bool key_in_same_row = false;
|
||||
bool key_in_same_col = false;
|
||||
|
||||
spin_lock_irqsave(&kbc->lock, flags);
|
||||
for (i = 0; i < KBC_MAX_KPENT; i++) {
|
||||
if ((i % 4) == 0)
|
||||
val = readl(kbc->mmio + KBC_KP_ENT0_0 + i);
|
||||
|
@ -292,7 +292,7 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
|
|||
* any 2 of the 3 keys share a row, and any 2 of them share a column.
|
||||
* If so ignore the key presses for this iteration.
|
||||
*/
|
||||
if ((kbc->use_ghost_filter) && (num_down >= 3)) {
|
||||
if (kbc->use_ghost_filter && num_down >= 3) {
|
||||
for (i = 0; i < num_down; i++) {
|
||||
unsigned int j;
|
||||
u8 curr_col = scancodes[i] & 0x07;
|
||||
|
@ -325,8 +325,6 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
|
|||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&kbc->lock, flags);
|
||||
|
||||
/* Ignore the key presses for this iteration? */
|
||||
if (key_in_same_col && key_in_same_row)
|
||||
return;
|
||||
|
@ -341,6 +339,18 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
|
|||
kbc->num_pressed_keys = num_down;
|
||||
}
|
||||
|
||||
static void tegra_kbc_set_fifo_interrupt(struct tegra_kbc *kbc, bool enable)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(kbc->mmio + KBC_CONTROL_0);
|
||||
if (enable)
|
||||
val |= KBC_CONTROL_FIFO_CNT_INT_EN;
|
||||
else
|
||||
val &= ~KBC_CONTROL_FIFO_CNT_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;
|
||||
|
@ -348,6 +358,8 @@ static void tegra_kbc_keypress_timer(unsigned long data)
|
|||
u32 val;
|
||||
unsigned int i;
|
||||
|
||||
spin_lock_irqsave(&kbc->lock, flags);
|
||||
|
||||
val = (readl(kbc->mmio + KBC_INT_0) >> 4) & 0xf;
|
||||
if (val) {
|
||||
unsigned long dly;
|
||||
|
@ -369,26 +381,19 @@ static void tegra_kbc_keypress_timer(unsigned long data)
|
|||
kbc->num_pressed_keys = 0;
|
||||
|
||||
/* All keys are released so enable the keypress interrupt */
|
||||
spin_lock_irqsave(&kbc->lock, flags);
|
||||
val = readl(kbc->mmio + KBC_CONTROL_0);
|
||||
val |= KBC_CONTROL_FIFO_CNT_INT_EN;
|
||||
writel(val, kbc->mmio + KBC_CONTROL_0);
|
||||
spin_unlock_irqrestore(&kbc->lock, flags);
|
||||
tegra_kbc_set_fifo_interrupt(kbc, true);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&kbc->lock, flags);
|
||||
}
|
||||
|
||||
static irqreturn_t tegra_kbc_isr(int irq, void *args)
|
||||
{
|
||||
struct tegra_kbc *kbc = args;
|
||||
u32 val, ctl;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
* Until all keys are released, defer further processing to
|
||||
* the polling loop in tegra_kbc_keypress_timer
|
||||
*/
|
||||
ctl = readl(kbc->mmio + KBC_CONTROL_0);
|
||||
ctl &= ~KBC_CONTROL_FIFO_CNT_INT_EN;
|
||||
writel(ctl, kbc->mmio + KBC_CONTROL_0);
|
||||
spin_lock_irqsave(&kbc->lock, flags);
|
||||
|
||||
/*
|
||||
* Quickly bail out & reenable interrupts if the fifo threshold
|
||||
|
@ -399,15 +404,15 @@ static irqreturn_t tegra_kbc_isr(int irq, void *args)
|
|||
|
||||
if (val & KBC_INT_FIFO_CNT_INT_STATUS) {
|
||||
/*
|
||||
* Schedule timer to run when hardware is in continuous
|
||||
* polling mode.
|
||||
* Until all keys are released, defer further processing to
|
||||
* the polling loop in tegra_kbc_keypress_timer.
|
||||
*/
|
||||
tegra_kbc_set_fifo_interrupt(kbc, false);
|
||||
mod_timer(&kbc->timer, jiffies + kbc->cp_dly_jiffies);
|
||||
} else {
|
||||
ctl |= KBC_CONTROL_FIFO_CNT_INT_EN;
|
||||
writel(ctl, kbc->mmio + KBC_CONTROL_0);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&kbc->lock, flags);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -455,7 +460,6 @@ static void tegra_kbc_config_pins(struct tegra_kbc *kbc)
|
|||
static int tegra_kbc_start(struct tegra_kbc *kbc)
|
||||
{
|
||||
const struct tegra_kbc_platform_data *pdata = kbc->pdata;
|
||||
unsigned long flags;
|
||||
unsigned int debounce_cnt;
|
||||
u32 val = 0;
|
||||
|
||||
|
@ -493,7 +497,6 @@ static int tegra_kbc_start(struct tegra_kbc *kbc)
|
|||
* Atomically clear out any remaining entries in the key FIFO
|
||||
* and enable keyboard interrupts.
|
||||
*/
|
||||
spin_lock_irqsave(&kbc->lock, flags);
|
||||
while (1) {
|
||||
val = readl(kbc->mmio + KBC_INT_0);
|
||||
val >>= 4;
|
||||
|
@ -504,7 +507,6 @@ static int tegra_kbc_start(struct tegra_kbc *kbc)
|
|||
val = readl(kbc->mmio + KBC_KP_ENT1_0);
|
||||
}
|
||||
writel(0x7, kbc->mmio + KBC_INT_0);
|
||||
spin_unlock_irqrestore(&kbc->lock, flags);
|
||||
|
||||
enable_irq(kbc->irq);
|
||||
|
||||
|
@ -734,18 +736,30 @@ static int tegra_kbc_suspend(struct device *dev)
|
|||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct tegra_kbc *kbc = platform_get_drvdata(pdev);
|
||||
|
||||
mutex_lock(&kbc->idev->mutex);
|
||||
if (device_may_wakeup(&pdev->dev)) {
|
||||
tegra_kbc_setup_wakekeys(kbc, true);
|
||||
enable_irq_wake(kbc->irq);
|
||||
disable_irq(kbc->irq);
|
||||
del_timer_sync(&kbc->timer);
|
||||
tegra_kbc_set_fifo_interrupt(kbc, false);
|
||||
|
||||
/* Forcefully clear the interrupt status */
|
||||
writel(0x7, kbc->mmio + KBC_INT_0);
|
||||
/*
|
||||
* Store the previous resident time of continuous polling mode.
|
||||
* Force the keyboard into interrupt mode.
|
||||
*/
|
||||
kbc->cp_to_wkup_dly = readl(kbc->mmio + KBC_TO_CNT_0);
|
||||
writel(0, kbc->mmio + KBC_TO_CNT_0);
|
||||
|
||||
tegra_kbc_setup_wakekeys(kbc, true);
|
||||
msleep(30);
|
||||
|
||||
enable_irq_wake(kbc->irq);
|
||||
} else {
|
||||
mutex_lock(&kbc->idev->mutex);
|
||||
if (kbc->idev->users)
|
||||
tegra_kbc_stop(kbc);
|
||||
mutex_unlock(&kbc->idev->mutex);
|
||||
}
|
||||
mutex_unlock(&kbc->idev->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -756,15 +770,22 @@ static int tegra_kbc_resume(struct device *dev)
|
|||
struct tegra_kbc *kbc = platform_get_drvdata(pdev);
|
||||
int err = 0;
|
||||
|
||||
mutex_lock(&kbc->idev->mutex);
|
||||
if (device_may_wakeup(&pdev->dev)) {
|
||||
disable_irq_wake(kbc->irq);
|
||||
tegra_kbc_setup_wakekeys(kbc, false);
|
||||
|
||||
/* Restore the resident time of continuous polling mode. */
|
||||
writel(kbc->cp_to_wkup_dly, kbc->mmio + KBC_TO_CNT_0);
|
||||
|
||||
tegra_kbc_set_fifo_interrupt(kbc, true);
|
||||
|
||||
enable_irq(kbc->irq);
|
||||
} else {
|
||||
mutex_lock(&kbc->idev->mutex);
|
||||
if (kbc->idev->users)
|
||||
err = tegra_kbc_start(kbc);
|
||||
mutex_unlock(&kbc->idev->mutex);
|
||||
}
|
||||
mutex_unlock(&kbc->idev->mutex);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -203,7 +203,7 @@ static int __devinit w90p910_keypad_probe(struct platform_device *pdev)
|
|||
input_dev->keycode, input_dev->keybit);
|
||||
|
||||
error = request_irq(keypad->irq, w90p910_keypad_irq_handler,
|
||||
IRQF_DISABLED, pdev->name, keypad);
|
||||
0, pdev->name, keypad);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to request IRQ\n");
|
||||
goto failed_put_clk;
|
||||
|
|
|
@ -62,6 +62,17 @@ config INPUT_AD714X_SPI
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called ad714x-spi.
|
||||
|
||||
config INPUT_BMA150
|
||||
tristate "BMA150/SMB380 acceleration sensor support"
|
||||
depends on I2C
|
||||
select INPUT_POLLDEV
|
||||
help
|
||||
Say Y here if you have Bosch Sensortec's BMA150 or SMB380
|
||||
acceleration sensor hooked to an I2C bus.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called bma150.
|
||||
|
||||
config INPUT_PCSPKR
|
||||
tristate "PC Speaker support"
|
||||
depends on PCSPKR_PLATFORM
|
||||
|
@ -74,6 +85,29 @@ config INPUT_PCSPKR
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called pcspkr.
|
||||
|
||||
config INPUT_PM8XXX_VIBRATOR
|
||||
tristate "Qualcomm PM8XXX vibrator support"
|
||||
depends on MFD_PM8XXX
|
||||
select INPUT_FF_MEMLESS
|
||||
help
|
||||
This option enables device driver support for the vibrator
|
||||
on Qualcomm PM8xxx chip. This driver supports ff-memless interface
|
||||
from input framework.
|
||||
|
||||
To compile this driver as module, choose M here: the
|
||||
module will be called pm8xxx-vibrator.
|
||||
|
||||
config INPUT_PMIC8XXX_PWRKEY
|
||||
tristate "PMIC8XXX power key support"
|
||||
depends on MFD_PM8XXX
|
||||
help
|
||||
Say Y here if you want support for the PMIC8XXX power key.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called pmic8xxx-pwrkey.
|
||||
|
||||
config INPUT_SPARCSPKR
|
||||
tristate "SPARC Speaker support"
|
||||
depends on PCI && SPARC64
|
||||
|
@ -379,17 +413,6 @@ config INPUT_PWM_BEEPER
|
|||
To compile this driver as a module, choose M here: the module will be
|
||||
called pwm-beeper.
|
||||
|
||||
config INPUT_PMIC8XXX_PWRKEY
|
||||
tristate "PMIC8XXX power key support"
|
||||
depends on MFD_PM8XXX
|
||||
help
|
||||
Say Y here if you want support for the PMIC8XXX power key.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called pmic8xxx-pwrkey.
|
||||
|
||||
config INPUT_GPIO_ROTARY_ENCODER
|
||||
tristate "Rotary encoders connected to GPIO pins"
|
||||
depends on GPIOLIB && GENERIC_GPIO
|
||||
|
|
|
@ -17,6 +17,7 @@ obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o
|
|||
obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
|
||||
obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o
|
||||
obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o
|
||||
obj-$(CONFIG_INPUT_BMA150) += bma150.o
|
||||
obj-$(CONFIG_INPUT_CM109) += cm109.o
|
||||
obj-$(CONFIG_INPUT_CMA3000) += cma3000_d0x.o
|
||||
obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o
|
||||
|
@ -34,9 +35,10 @@ obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o
|
|||
obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o
|
||||
obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o
|
||||
obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o
|
||||
obj-$(CONFIG_INPUT_PM8XXX_VIBRATOR) += pm8xxx-vibrator.o
|
||||
obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o
|
||||
obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
|
||||
obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o
|
||||
obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o
|
||||
obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
|
||||
obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o
|
||||
obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
|
||||
|
|
|
@ -116,13 +116,13 @@ static struct i2c_driver ad714x_i2c_driver = {
|
|||
.id_table = ad714x_id,
|
||||
};
|
||||
|
||||
static __init int ad714x_i2c_init(void)
|
||||
static int __init ad714x_i2c_init(void)
|
||||
{
|
||||
return i2c_add_driver(&ad714x_i2c_driver);
|
||||
}
|
||||
module_init(ad714x_i2c_init);
|
||||
|
||||
static __exit void ad714x_i2c_exit(void)
|
||||
static void __exit ad714x_i2c_exit(void)
|
||||
{
|
||||
i2c_del_driver(&ad714x_i2c_driver);
|
||||
}
|
||||
|
|
691
drivers/input/misc/bma150.c
Normal file
691
drivers/input/misc/bma150.c
Normal file
|
@ -0,0 +1,691 @@
|
|||
/*
|
||||
* Copyright (c) 2011 Bosch Sensortec GmbH
|
||||
* Copyright (c) 2011 Unixphere
|
||||
*
|
||||
* This driver adds support for Bosch Sensortec's digital acceleration
|
||||
* sensors BMA150 and SMB380.
|
||||
* The SMB380 is fully compatible with BMA150 and only differs in packaging.
|
||||
*
|
||||
* The datasheet for the BMA150 chip can be found here:
|
||||
* http://www.bosch-sensortec.com/content/language1/downloads/BST-BMA150-DS000-07.pdf
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input-polldev.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/bma150.h>
|
||||
|
||||
#define ABSMAX_ACC_VAL 0x01FF
|
||||
#define ABSMIN_ACC_VAL -(ABSMAX_ACC_VAL)
|
||||
|
||||
/* Each axis is represented by a 2-byte data word */
|
||||
#define BMA150_XYZ_DATA_SIZE 6
|
||||
|
||||
/* Input poll interval in milliseconds */
|
||||
#define BMA150_POLL_INTERVAL 10
|
||||
#define BMA150_POLL_MAX 200
|
||||
#define BMA150_POLL_MIN 0
|
||||
|
||||
#define BMA150_BW_25HZ 0
|
||||
#define BMA150_BW_50HZ 1
|
||||
#define BMA150_BW_100HZ 2
|
||||
#define BMA150_BW_190HZ 3
|
||||
#define BMA150_BW_375HZ 4
|
||||
#define BMA150_BW_750HZ 5
|
||||
#define BMA150_BW_1500HZ 6
|
||||
|
||||
#define BMA150_RANGE_2G 0
|
||||
#define BMA150_RANGE_4G 1
|
||||
#define BMA150_RANGE_8G 2
|
||||
|
||||
#define BMA150_MODE_NORMAL 0
|
||||
#define BMA150_MODE_SLEEP 2
|
||||
#define BMA150_MODE_WAKE_UP 3
|
||||
|
||||
/* Data register addresses */
|
||||
#define BMA150_DATA_0_REG 0x00
|
||||
#define BMA150_DATA_1_REG 0x01
|
||||
#define BMA150_DATA_2_REG 0x02
|
||||
|
||||
/* Control register addresses */
|
||||
#define BMA150_CTRL_0_REG 0x0A
|
||||
#define BMA150_CTRL_1_REG 0x0B
|
||||
#define BMA150_CTRL_2_REG 0x14
|
||||
#define BMA150_CTRL_3_REG 0x15
|
||||
|
||||
/* Configuration/Setting register addresses */
|
||||
#define BMA150_CFG_0_REG 0x0C
|
||||
#define BMA150_CFG_1_REG 0x0D
|
||||
#define BMA150_CFG_2_REG 0x0E
|
||||
#define BMA150_CFG_3_REG 0x0F
|
||||
#define BMA150_CFG_4_REG 0x10
|
||||
#define BMA150_CFG_5_REG 0x11
|
||||
|
||||
#define BMA150_CHIP_ID 2
|
||||
#define BMA150_CHIP_ID_REG BMA150_DATA_0_REG
|
||||
|
||||
#define BMA150_ACC_X_LSB_REG BMA150_DATA_2_REG
|
||||
|
||||
#define BMA150_SLEEP_POS 0
|
||||
#define BMA150_SLEEP_MSK 0x01
|
||||
#define BMA150_SLEEP_REG BMA150_CTRL_0_REG
|
||||
|
||||
#define BMA150_BANDWIDTH_POS 0
|
||||
#define BMA150_BANDWIDTH_MSK 0x07
|
||||
#define BMA150_BANDWIDTH_REG BMA150_CTRL_2_REG
|
||||
|
||||
#define BMA150_RANGE_POS 3
|
||||
#define BMA150_RANGE_MSK 0x18
|
||||
#define BMA150_RANGE_REG BMA150_CTRL_2_REG
|
||||
|
||||
#define BMA150_WAKE_UP_POS 0
|
||||
#define BMA150_WAKE_UP_MSK 0x01
|
||||
#define BMA150_WAKE_UP_REG BMA150_CTRL_3_REG
|
||||
|
||||
#define BMA150_SW_RES_POS 1
|
||||
#define BMA150_SW_RES_MSK 0x02
|
||||
#define BMA150_SW_RES_REG BMA150_CTRL_0_REG
|
||||
|
||||
/* Any-motion interrupt register fields */
|
||||
#define BMA150_ANY_MOTION_EN_POS 6
|
||||
#define BMA150_ANY_MOTION_EN_MSK 0x40
|
||||
#define BMA150_ANY_MOTION_EN_REG BMA150_CTRL_1_REG
|
||||
|
||||
#define BMA150_ANY_MOTION_DUR_POS 6
|
||||
#define BMA150_ANY_MOTION_DUR_MSK 0xC0
|
||||
#define BMA150_ANY_MOTION_DUR_REG BMA150_CFG_5_REG
|
||||
|
||||
#define BMA150_ANY_MOTION_THRES_REG BMA150_CFG_4_REG
|
||||
|
||||
/* Advanced interrupt register fields */
|
||||
#define BMA150_ADV_INT_EN_POS 6
|
||||
#define BMA150_ADV_INT_EN_MSK 0x40
|
||||
#define BMA150_ADV_INT_EN_REG BMA150_CTRL_3_REG
|
||||
|
||||
/* High-G interrupt register fields */
|
||||
#define BMA150_HIGH_G_EN_POS 1
|
||||
#define BMA150_HIGH_G_EN_MSK 0x02
|
||||
#define BMA150_HIGH_G_EN_REG BMA150_CTRL_1_REG
|
||||
|
||||
#define BMA150_HIGH_G_HYST_POS 3
|
||||
#define BMA150_HIGH_G_HYST_MSK 0x38
|
||||
#define BMA150_HIGH_G_HYST_REG BMA150_CFG_5_REG
|
||||
|
||||
#define BMA150_HIGH_G_DUR_REG BMA150_CFG_3_REG
|
||||
#define BMA150_HIGH_G_THRES_REG BMA150_CFG_2_REG
|
||||
|
||||
/* Low-G interrupt register fields */
|
||||
#define BMA150_LOW_G_EN_POS 0
|
||||
#define BMA150_LOW_G_EN_MSK 0x01
|
||||
#define BMA150_LOW_G_EN_REG BMA150_CTRL_1_REG
|
||||
|
||||
#define BMA150_LOW_G_HYST_POS 0
|
||||
#define BMA150_LOW_G_HYST_MSK 0x07
|
||||
#define BMA150_LOW_G_HYST_REG BMA150_CFG_5_REG
|
||||
|
||||
#define BMA150_LOW_G_DUR_REG BMA150_CFG_1_REG
|
||||
#define BMA150_LOW_G_THRES_REG BMA150_CFG_0_REG
|
||||
|
||||
struct bma150_data {
|
||||
struct i2c_client *client;
|
||||
struct input_polled_dev *input_polled;
|
||||
struct input_dev *input;
|
||||
u8 mode;
|
||||
};
|
||||
|
||||
/*
|
||||
* The settings for the given range, bandwidth and interrupt features
|
||||
* are stated and verified by Bosch Sensortec where they are configured
|
||||
* to provide a generic sensitivity performance.
|
||||
*/
|
||||
static struct bma150_cfg default_cfg __devinitdata = {
|
||||
.any_motion_int = 1,
|
||||
.hg_int = 1,
|
||||
.lg_int = 1,
|
||||
.any_motion_dur = 0,
|
||||
.any_motion_thres = 0,
|
||||
.hg_hyst = 0,
|
||||
.hg_dur = 150,
|
||||
.hg_thres = 160,
|
||||
.lg_hyst = 0,
|
||||
.lg_dur = 150,
|
||||
.lg_thres = 20,
|
||||
.range = BMA150_RANGE_2G,
|
||||
.bandwidth = BMA150_BW_50HZ
|
||||
};
|
||||
|
||||
static int bma150_write_byte(struct i2c_client *client, u8 reg, u8 val)
|
||||
{
|
||||
s32 ret;
|
||||
|
||||
/* As per specification, disable irq in between register writes */
|
||||
if (client->irq)
|
||||
disable_irq_nosync(client->irq);
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, reg, val);
|
||||
|
||||
if (client->irq)
|
||||
enable_irq(client->irq);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bma150_set_reg_bits(struct i2c_client *client,
|
||||
int val, int shift, u8 mask, u8 reg)
|
||||
{
|
||||
int data;
|
||||
|
||||
data = i2c_smbus_read_byte_data(client, reg);
|
||||
if (data < 0)
|
||||
return data;
|
||||
|
||||
data = (data & ~mask) | ((val << shift) & mask);
|
||||
return bma150_write_byte(client, reg, data);
|
||||
}
|
||||
|
||||
static int bma150_set_mode(struct bma150_data *bma150, u8 mode)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = bma150_set_reg_bits(bma150->client, mode, BMA150_WAKE_UP_POS,
|
||||
BMA150_WAKE_UP_MSK, BMA150_WAKE_UP_REG);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = bma150_set_reg_bits(bma150->client, mode, BMA150_SLEEP_POS,
|
||||
BMA150_SLEEP_MSK, BMA150_SLEEP_REG);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (mode == BMA150_MODE_NORMAL)
|
||||
msleep(2);
|
||||
|
||||
bma150->mode = mode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit bma150_soft_reset(struct bma150_data *bma150)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = bma150_set_reg_bits(bma150->client, 1, BMA150_SW_RES_POS,
|
||||
BMA150_SW_RES_MSK, BMA150_SW_RES_REG);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
msleep(2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit bma150_set_range(struct bma150_data *bma150, u8 range)
|
||||
{
|
||||
return bma150_set_reg_bits(bma150->client, range, BMA150_RANGE_POS,
|
||||
BMA150_RANGE_MSK, BMA150_RANGE_REG);
|
||||
}
|
||||
|
||||
static int __devinit bma150_set_bandwidth(struct bma150_data *bma150, u8 bw)
|
||||
{
|
||||
return bma150_set_reg_bits(bma150->client, bw, BMA150_BANDWIDTH_POS,
|
||||
BMA150_BANDWIDTH_MSK, BMA150_BANDWIDTH_REG);
|
||||
}
|
||||
|
||||
static int __devinit bma150_set_low_g_interrupt(struct bma150_data *bma150,
|
||||
u8 enable, u8 hyst, u8 dur, u8 thres)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = bma150_set_reg_bits(bma150->client, hyst,
|
||||
BMA150_LOW_G_HYST_POS, BMA150_LOW_G_HYST_MSK,
|
||||
BMA150_LOW_G_HYST_REG);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = bma150_write_byte(bma150->client, BMA150_LOW_G_DUR_REG, dur);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = bma150_write_byte(bma150->client, BMA150_LOW_G_THRES_REG, thres);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return bma150_set_reg_bits(bma150->client, !!enable,
|
||||
BMA150_LOW_G_EN_POS, BMA150_LOW_G_EN_MSK,
|
||||
BMA150_LOW_G_EN_REG);
|
||||
}
|
||||
|
||||
static int __devinit bma150_set_high_g_interrupt(struct bma150_data *bma150,
|
||||
u8 enable, u8 hyst, u8 dur, u8 thres)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = bma150_set_reg_bits(bma150->client, hyst,
|
||||
BMA150_HIGH_G_HYST_POS, BMA150_HIGH_G_HYST_MSK,
|
||||
BMA150_HIGH_G_HYST_REG);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = bma150_write_byte(bma150->client,
|
||||
BMA150_HIGH_G_DUR_REG, dur);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = bma150_write_byte(bma150->client,
|
||||
BMA150_HIGH_G_THRES_REG, thres);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return bma150_set_reg_bits(bma150->client, !!enable,
|
||||
BMA150_HIGH_G_EN_POS, BMA150_HIGH_G_EN_MSK,
|
||||
BMA150_HIGH_G_EN_REG);
|
||||
}
|
||||
|
||||
|
||||
static int __devinit bma150_set_any_motion_interrupt(struct bma150_data *bma150,
|
||||
u8 enable, u8 dur, u8 thres)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = bma150_set_reg_bits(bma150->client, dur,
|
||||
BMA150_ANY_MOTION_DUR_POS,
|
||||
BMA150_ANY_MOTION_DUR_MSK,
|
||||
BMA150_ANY_MOTION_DUR_REG);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = bma150_write_byte(bma150->client,
|
||||
BMA150_ANY_MOTION_THRES_REG, thres);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = bma150_set_reg_bits(bma150->client, !!enable,
|
||||
BMA150_ADV_INT_EN_POS, BMA150_ADV_INT_EN_MSK,
|
||||
BMA150_ADV_INT_EN_REG);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return bma150_set_reg_bits(bma150->client, !!enable,
|
||||
BMA150_ANY_MOTION_EN_POS,
|
||||
BMA150_ANY_MOTION_EN_MSK,
|
||||
BMA150_ANY_MOTION_EN_REG);
|
||||
}
|
||||
|
||||
static void bma150_report_xyz(struct bma150_data *bma150)
|
||||
{
|
||||
u8 data[BMA150_XYZ_DATA_SIZE];
|
||||
s16 x, y, z;
|
||||
s32 ret;
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(bma150->client,
|
||||
BMA150_ACC_X_LSB_REG, BMA150_XYZ_DATA_SIZE, data);
|
||||
if (ret != BMA150_XYZ_DATA_SIZE)
|
||||
return;
|
||||
|
||||
x = ((0xc0 & data[0]) >> 6) | (data[1] << 2);
|
||||
y = ((0xc0 & data[2]) >> 6) | (data[3] << 2);
|
||||
z = ((0xc0 & data[4]) >> 6) | (data[5] << 2);
|
||||
|
||||
/* sign extension */
|
||||
x = (s16) (x << 6) >> 6;
|
||||
y = (s16) (y << 6) >> 6;
|
||||
z = (s16) (z << 6) >> 6;
|
||||
|
||||
input_report_abs(bma150->input, ABS_X, x);
|
||||
input_report_abs(bma150->input, ABS_Y, y);
|
||||
input_report_abs(bma150->input, ABS_Z, z);
|
||||
input_sync(bma150->input);
|
||||
}
|
||||
|
||||
static irqreturn_t bma150_irq_thread(int irq, void *dev)
|
||||
{
|
||||
bma150_report_xyz(dev);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void bma150_poll(struct input_polled_dev *dev)
|
||||
{
|
||||
bma150_report_xyz(dev->private);
|
||||
}
|
||||
|
||||
static int bma150_open(struct bma150_data *bma150)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = pm_runtime_get_sync(&bma150->client->dev);
|
||||
if (error && error != -ENOSYS)
|
||||
return error;
|
||||
|
||||
/*
|
||||
* See if runtime PM woke up the device. If runtime PM
|
||||
* is disabled we need to do it ourselves.
|
||||
*/
|
||||
if (bma150->mode != BMA150_MODE_NORMAL) {
|
||||
error = bma150_set_mode(bma150, BMA150_MODE_NORMAL);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bma150_close(struct bma150_data *bma150)
|
||||
{
|
||||
pm_runtime_put_sync(&bma150->client->dev);
|
||||
|
||||
if (bma150->mode != BMA150_MODE_SLEEP)
|
||||
bma150_set_mode(bma150, BMA150_MODE_SLEEP);
|
||||
}
|
||||
|
||||
static int bma150_irq_open(struct input_dev *input)
|
||||
{
|
||||
struct bma150_data *bma150 = input_get_drvdata(input);
|
||||
|
||||
return bma150_open(bma150);
|
||||
}
|
||||
|
||||
static void bma150_irq_close(struct input_dev *input)
|
||||
{
|
||||
struct bma150_data *bma150 = input_get_drvdata(input);
|
||||
|
||||
bma150_close(bma150);
|
||||
}
|
||||
|
||||
static void bma150_poll_open(struct input_polled_dev *ipoll_dev)
|
||||
{
|
||||
struct bma150_data *bma150 = ipoll_dev->private;
|
||||
|
||||
bma150_open(bma150);
|
||||
}
|
||||
|
||||
static void bma150_poll_close(struct input_polled_dev *ipoll_dev)
|
||||
{
|
||||
struct bma150_data *bma150 = ipoll_dev->private;
|
||||
|
||||
bma150_close(bma150);
|
||||
}
|
||||
|
||||
static int __devinit bma150_initialize(struct bma150_data *bma150,
|
||||
const struct bma150_cfg *cfg)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = bma150_soft_reset(bma150);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = bma150_set_bandwidth(bma150, cfg->bandwidth);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = bma150_set_range(bma150, cfg->range);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (bma150->client->irq) {
|
||||
error = bma150_set_any_motion_interrupt(bma150,
|
||||
cfg->any_motion_int,
|
||||
cfg->any_motion_dur,
|
||||
cfg->any_motion_thres);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = bma150_set_high_g_interrupt(bma150,
|
||||
cfg->hg_int, cfg->hg_hyst,
|
||||
cfg->hg_dur, cfg->hg_thres);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = bma150_set_low_g_interrupt(bma150,
|
||||
cfg->lg_int, cfg->lg_hyst,
|
||||
cfg->lg_dur, cfg->lg_thres);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
return bma150_set_mode(bma150, BMA150_MODE_SLEEP);
|
||||
}
|
||||
|
||||
static void __devinit bma150_init_input_device(struct bma150_data *bma150,
|
||||
struct input_dev *idev)
|
||||
{
|
||||
idev->name = BMA150_DRIVER;
|
||||
idev->phys = BMA150_DRIVER "/input0";
|
||||
idev->id.bustype = BUS_I2C;
|
||||
idev->dev.parent = &bma150->client->dev;
|
||||
|
||||
idev->evbit[0] = BIT_MASK(EV_ABS);
|
||||
input_set_abs_params(idev, ABS_X, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);
|
||||
input_set_abs_params(idev, ABS_Y, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);
|
||||
input_set_abs_params(idev, ABS_Z, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);
|
||||
}
|
||||
|
||||
static int __devinit bma150_register_input_device(struct bma150_data *bma150)
|
||||
{
|
||||
struct input_dev *idev;
|
||||
int error;
|
||||
|
||||
idev = input_allocate_device();
|
||||
if (!idev)
|
||||
return -ENOMEM;
|
||||
|
||||
bma150_init_input_device(bma150, idev);
|
||||
|
||||
idev->open = bma150_irq_open;
|
||||
idev->close = bma150_irq_close;
|
||||
input_set_drvdata(idev, bma150);
|
||||
|
||||
error = input_register_device(idev);
|
||||
if (error) {
|
||||
input_free_device(idev);
|
||||
return error;
|
||||
}
|
||||
|
||||
bma150->input = idev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit bma150_register_polled_device(struct bma150_data *bma150)
|
||||
{
|
||||
struct input_polled_dev *ipoll_dev;
|
||||
int error;
|
||||
|
||||
ipoll_dev = input_allocate_polled_device();
|
||||
if (!ipoll_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
ipoll_dev->private = bma150;
|
||||
ipoll_dev->open = bma150_poll_open;
|
||||
ipoll_dev->close = bma150_poll_close;
|
||||
ipoll_dev->poll = bma150_poll;
|
||||
ipoll_dev->poll_interval = BMA150_POLL_INTERVAL;
|
||||
ipoll_dev->poll_interval_min = BMA150_POLL_MIN;
|
||||
ipoll_dev->poll_interval_max = BMA150_POLL_MAX;
|
||||
|
||||
bma150_init_input_device(bma150, ipoll_dev->input);
|
||||
|
||||
error = input_register_polled_device(ipoll_dev);
|
||||
if (error) {
|
||||
input_free_polled_device(ipoll_dev);
|
||||
return error;
|
||||
}
|
||||
|
||||
bma150->input_polled = ipoll_dev;
|
||||
bma150->input = ipoll_dev->input;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit bma150_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
const struct bma150_platform_data *pdata = client->dev.platform_data;
|
||||
const struct bma150_cfg *cfg;
|
||||
struct bma150_data *bma150;
|
||||
int chip_id;
|
||||
int error;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
dev_err(&client->dev, "i2c_check_functionality error\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
chip_id = i2c_smbus_read_byte_data(client, BMA150_CHIP_ID_REG);
|
||||
if (chip_id != BMA150_CHIP_ID) {
|
||||
dev_err(&client->dev, "BMA150 chip id error: %d\n", chip_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bma150 = kzalloc(sizeof(struct bma150_data), GFP_KERNEL);
|
||||
if (!bma150)
|
||||
return -ENOMEM;
|
||||
|
||||
bma150->client = client;
|
||||
|
||||
if (pdata) {
|
||||
if (pdata->irq_gpio_cfg) {
|
||||
error = pdata->irq_gpio_cfg();
|
||||
if (error) {
|
||||
dev_err(&client->dev,
|
||||
"IRQ GPIO conf. error %d, error %d\n",
|
||||
client->irq, error);
|
||||
goto err_free_mem;
|
||||
}
|
||||
}
|
||||
cfg = &pdata->cfg;
|
||||
} else {
|
||||
cfg = &default_cfg;
|
||||
}
|
||||
|
||||
error = bma150_initialize(bma150, cfg);
|
||||
if (error)
|
||||
goto err_free_mem;
|
||||
|
||||
if (client->irq > 0) {
|
||||
error = bma150_register_input_device(bma150);
|
||||
if (error)
|
||||
goto err_free_mem;
|
||||
|
||||
error = request_threaded_irq(client->irq,
|
||||
NULL, bma150_irq_thread,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
BMA150_DRIVER, bma150);
|
||||
if (error) {
|
||||
dev_err(&client->dev,
|
||||
"irq request failed %d, error %d\n",
|
||||
client->irq, error);
|
||||
input_unregister_device(bma150->input);
|
||||
goto err_free_mem;
|
||||
}
|
||||
} else {
|
||||
error = bma150_register_polled_device(bma150);
|
||||
if (error)
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, bma150);
|
||||
|
||||
pm_runtime_enable(&client->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_mem:
|
||||
kfree(bma150);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __devexit bma150_remove(struct i2c_client *client)
|
||||
{
|
||||
struct bma150_data *bma150 = i2c_get_clientdata(client);
|
||||
|
||||
pm_runtime_disable(&client->dev);
|
||||
|
||||
if (client->irq > 0) {
|
||||
free_irq(client->irq, bma150);
|
||||
input_unregister_device(bma150->input);
|
||||
} else {
|
||||
input_unregister_polled_device(bma150->input_polled);
|
||||
input_free_polled_device(bma150->input_polled);
|
||||
}
|
||||
|
||||
kfree(bma150);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int bma150_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct bma150_data *bma150 = i2c_get_clientdata(client);
|
||||
|
||||
return bma150_set_mode(bma150, BMA150_MODE_SLEEP);
|
||||
}
|
||||
|
||||
static int bma150_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct bma150_data *bma150 = i2c_get_clientdata(client);
|
||||
|
||||
return bma150_set_mode(bma150, BMA150_MODE_NORMAL);
|
||||
}
|
||||
#endif
|
||||
|
||||
static UNIVERSAL_DEV_PM_OPS(bma150_pm, bma150_suspend, bma150_resume, NULL);
|
||||
|
||||
static const struct i2c_device_id bma150_id[] = {
|
||||
{ "bma150", 0 },
|
||||
{ "smb380", 0 },
|
||||
{ "bma023", 0 },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, bma150_id);
|
||||
|
||||
static struct i2c_driver bma150_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = BMA150_DRIVER,
|
||||
.pm = &bma150_pm,
|
||||
},
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.id_table = bma150_id,
|
||||
.probe = bma150_probe,
|
||||
.remove = __devexit_p(bma150_remove),
|
||||
};
|
||||
|
||||
static int __init BMA150_init(void)
|
||||
{
|
||||
return i2c_add_driver(&bma150_driver);
|
||||
}
|
||||
|
||||
static void __exit BMA150_exit(void)
|
||||
{
|
||||
i2c_del_driver(&bma150_driver);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Albert Zhang <xu.zhang@bosch-sensortec.com>");
|
||||
MODULE_DESCRIPTION("BMA150 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(BMA150_init);
|
||||
module_exit(BMA150_exit);
|
|
@ -111,7 +111,7 @@ static int __devinit ixp4xx_spkr_probe(struct platform_device *dev)
|
|||
input_dev->event = ixp4xx_spkr_event;
|
||||
|
||||
err = request_irq(IRQ_IXP4XX_TIMER2, &ixp4xx_spkr_interrupt,
|
||||
IRQF_DISABLED | IRQF_NO_SUSPEND, "ixp4xx-beeper",
|
||||
IRQF_NO_SUSPEND, "ixp4xx-beeper",
|
||||
(void *) dev->id);
|
||||
if (err)
|
||||
goto err_free_device;
|
||||
|
|
|
@ -88,13 +88,13 @@ static int mma8450_write(struct mma8450 *m, unsigned off, u8 v)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mma8450_read_xyz(struct mma8450 *m, int *x, int *y, int *z)
|
||||
static int mma8450_read_block(struct mma8450 *m, unsigned off,
|
||||
u8 *buf, size_t size)
|
||||
{
|
||||
struct i2c_client *c = m->client;
|
||||
u8 buff[6];
|
||||
int err;
|
||||
|
||||
err = i2c_smbus_read_i2c_block_data(c, MMA8450_OUT_X_LSB, 6, buff);
|
||||
err = i2c_smbus_read_i2c_block_data(c, off, size, buf);
|
||||
if (err < 0) {
|
||||
dev_err(&c->dev,
|
||||
"failed to read block data at 0x%02x, error %d\n",
|
||||
|
@ -102,10 +102,6 @@ static int mma8450_read_xyz(struct mma8450 *m, int *x, int *y, int *z)
|
|||
return err;
|
||||
}
|
||||
|
||||
*x = ((buff[1] << 4) & 0xff0) | (buff[0] & 0xf);
|
||||
*y = ((buff[3] << 4) & 0xff0) | (buff[2] & 0xf);
|
||||
*z = ((buff[5] << 4) & 0xff0) | (buff[4] & 0xf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -114,7 +110,7 @@ static void mma8450_poll(struct input_polled_dev *dev)
|
|||
struct mma8450 *m = dev->private;
|
||||
int x, y, z;
|
||||
int ret;
|
||||
int err;
|
||||
u8 buf[6];
|
||||
|
||||
ret = mma8450_read(m, MMA8450_STATUS);
|
||||
if (ret < 0)
|
||||
|
@ -123,10 +119,14 @@ static void mma8450_poll(struct input_polled_dev *dev)
|
|||
if (!(ret & MMA8450_STATUS_ZXYDR))
|
||||
return;
|
||||
|
||||
err = mma8450_read_xyz(m, &x, &y, &z);
|
||||
if (err)
|
||||
ret = mma8450_read_block(m, MMA8450_OUT_X_LSB, buf, sizeof(buf));
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
x = ((buf[1] << 4) & 0xff0) | (buf[0] & 0xf);
|
||||
y = ((buf[3] << 4) & 0xff0) | (buf[2] & 0xf);
|
||||
z = ((buf[5] << 4) & 0xff0) | (buf[4] & 0xf);
|
||||
|
||||
input_report_abs(dev->input, ABS_X, x);
|
||||
input_report_abs(dev->input, ABS_Y, y);
|
||||
input_report_abs(dev->input, ABS_Z, z);
|
||||
|
|
296
drivers/input/misc/pm8xxx-vibrator.c
Normal file
296
drivers/input/misc/pm8xxx-vibrator.c
Normal file
|
@ -0,0 +1,296 @@
|
|||
/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mfd/pm8xxx/core.h>
|
||||
|
||||
#define VIB_DRV 0x4A
|
||||
|
||||
#define VIB_DRV_SEL_MASK 0xf8
|
||||
#define VIB_DRV_SEL_SHIFT 0x03
|
||||
#define VIB_DRV_EN_MANUAL_MASK 0xfc
|
||||
|
||||
#define VIB_MAX_LEVEL_mV (3100)
|
||||
#define VIB_MIN_LEVEL_mV (1200)
|
||||
#define VIB_MAX_LEVELS (VIB_MAX_LEVEL_mV - VIB_MIN_LEVEL_mV)
|
||||
|
||||
#define MAX_FF_SPEED 0xff
|
||||
|
||||
/**
|
||||
* struct pm8xxx_vib - structure to hold vibrator data
|
||||
* @vib_input_dev: input device supporting force feedback
|
||||
* @work: work structure to set the vibration parameters
|
||||
* @dev: device supporting force feedback
|
||||
* @speed: speed of vibration set from userland
|
||||
* @active: state of vibrator
|
||||
* @level: level of vibration to set in the chip
|
||||
* @reg_vib_drv: VIB_DRV register value
|
||||
*/
|
||||
struct pm8xxx_vib {
|
||||
struct input_dev *vib_input_dev;
|
||||
struct work_struct work;
|
||||
struct device *dev;
|
||||
int speed;
|
||||
int level;
|
||||
bool active;
|
||||
u8 reg_vib_drv;
|
||||
};
|
||||
|
||||
/**
|
||||
* pm8xxx_vib_read_u8 - helper to read a byte from pmic chip
|
||||
* @vib: pointer to vibrator structure
|
||||
* @data: placeholder for data to be read
|
||||
* @reg: register address
|
||||
*/
|
||||
static int pm8xxx_vib_read_u8(struct pm8xxx_vib *vib,
|
||||
u8 *data, u16 reg)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = pm8xxx_readb(vib->dev->parent, reg, data);
|
||||
if (rc < 0)
|
||||
dev_warn(vib->dev, "Error reading pm8xxx reg 0x%x(0x%x)\n",
|
||||
reg, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* pm8xxx_vib_write_u8 - helper to write a byte to pmic chip
|
||||
* @vib: pointer to vibrator structure
|
||||
* @data: data to write
|
||||
* @reg: register address
|
||||
*/
|
||||
static int pm8xxx_vib_write_u8(struct pm8xxx_vib *vib,
|
||||
u8 data, u16 reg)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = pm8xxx_writeb(vib->dev->parent, reg, data);
|
||||
if (rc < 0)
|
||||
dev_warn(vib->dev, "Error writing pm8xxx reg 0x%x(0x%x)\n",
|
||||
reg, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* pm8xxx_vib_set - handler to start/stop vibration
|
||||
* @vib: pointer to vibrator structure
|
||||
* @on: state to set
|
||||
*/
|
||||
static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on)
|
||||
{
|
||||
int rc;
|
||||
u8 val = vib->reg_vib_drv;
|
||||
|
||||
if (on)
|
||||
val |= ((vib->level << VIB_DRV_SEL_SHIFT) & VIB_DRV_SEL_MASK);
|
||||
else
|
||||
val &= ~VIB_DRV_SEL_MASK;
|
||||
|
||||
rc = pm8xxx_vib_write_u8(vib, val, VIB_DRV);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
vib->reg_vib_drv = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pm8xxx_work_handler - worker to set vibration level
|
||||
* @work: pointer to work_struct
|
||||
*/
|
||||
static void pm8xxx_work_handler(struct work_struct *work)
|
||||
{
|
||||
struct pm8xxx_vib *vib = container_of(work, struct pm8xxx_vib, work);
|
||||
int rc;
|
||||
u8 val;
|
||||
|
||||
rc = pm8xxx_vib_read_u8(vib, &val, VIB_DRV);
|
||||
if (rc < 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* pmic vibrator supports voltage ranges from 1.2 to 3.1V, so
|
||||
* scale the level to fit into these ranges.
|
||||
*/
|
||||
if (vib->speed) {
|
||||
vib->active = true;
|
||||
vib->level = ((VIB_MAX_LEVELS * vib->speed) / MAX_FF_SPEED) +
|
||||
VIB_MIN_LEVEL_mV;
|
||||
vib->level /= 100;
|
||||
} else {
|
||||
vib->active = false;
|
||||
vib->level = VIB_MIN_LEVEL_mV / 100;
|
||||
}
|
||||
|
||||
pm8xxx_vib_set(vib, vib->active);
|
||||
}
|
||||
|
||||
/**
|
||||
* pm8xxx_vib_close - callback of input close callback
|
||||
* @dev: input device pointer
|
||||
*
|
||||
* Turns off the vibrator.
|
||||
*/
|
||||
static void pm8xxx_vib_close(struct input_dev *dev)
|
||||
{
|
||||
struct pm8xxx_vib *vib = input_get_drvdata(dev);
|
||||
|
||||
cancel_work_sync(&vib->work);
|
||||
if (vib->active)
|
||||
pm8xxx_vib_set(vib, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* pm8xxx_vib_play_effect - function to handle vib effects.
|
||||
* @dev: input device pointer
|
||||
* @data: data of effect
|
||||
* @effect: effect to play
|
||||
*
|
||||
* Currently this driver supports only rumble effects.
|
||||
*/
|
||||
static int pm8xxx_vib_play_effect(struct input_dev *dev, void *data,
|
||||
struct ff_effect *effect)
|
||||
{
|
||||
struct pm8xxx_vib *vib = input_get_drvdata(dev);
|
||||
|
||||
vib->speed = effect->u.rumble.strong_magnitude >> 8;
|
||||
if (!vib->speed)
|
||||
vib->speed = effect->u.rumble.weak_magnitude >> 9;
|
||||
|
||||
schedule_work(&vib->work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit pm8xxx_vib_probe(struct platform_device *pdev)
|
||||
|
||||
{
|
||||
struct pm8xxx_vib *vib;
|
||||
struct input_dev *input_dev;
|
||||
int error;
|
||||
u8 val;
|
||||
|
||||
vib = kzalloc(sizeof(*vib), GFP_KERNEL);
|
||||
input_dev = input_allocate_device();
|
||||
if (!vib || !input_dev) {
|
||||
dev_err(&pdev->dev, "couldn't allocate memory\n");
|
||||
error = -ENOMEM;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
INIT_WORK(&vib->work, pm8xxx_work_handler);
|
||||
vib->dev = &pdev->dev;
|
||||
vib->vib_input_dev = input_dev;
|
||||
|
||||
/* operate in manual mode */
|
||||
error = pm8xxx_vib_read_u8(vib, &val, VIB_DRV);
|
||||
if (error < 0)
|
||||
goto err_free_mem;
|
||||
val &= ~VIB_DRV_EN_MANUAL_MASK;
|
||||
error = pm8xxx_vib_write_u8(vib, val, VIB_DRV);
|
||||
if (error < 0)
|
||||
goto err_free_mem;
|
||||
|
||||
vib->reg_vib_drv = val;
|
||||
|
||||
input_dev->name = "pm8xxx_vib_ffmemless";
|
||||
input_dev->id.version = 1;
|
||||
input_dev->dev.parent = &pdev->dev;
|
||||
input_dev->close = pm8xxx_vib_close;
|
||||
input_set_drvdata(input_dev, vib);
|
||||
input_set_capability(vib->vib_input_dev, EV_FF, FF_RUMBLE);
|
||||
|
||||
error = input_ff_create_memless(input_dev, NULL,
|
||||
pm8xxx_vib_play_effect);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev,
|
||||
"couldn't register vibrator as FF device\n");
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
error = input_register_device(input_dev);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "couldn't register input device\n");
|
||||
goto err_destroy_memless;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, vib);
|
||||
return 0;
|
||||
|
||||
err_destroy_memless:
|
||||
input_ff_destroy(input_dev);
|
||||
err_free_mem:
|
||||
input_free_device(input_dev);
|
||||
kfree(vib);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __devexit pm8xxx_vib_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pm8xxx_vib *vib = platform_get_drvdata(pdev);
|
||||
|
||||
input_unregister_device(vib->vib_input_dev);
|
||||
kfree(vib);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int pm8xxx_vib_suspend(struct device *dev)
|
||||
{
|
||||
struct pm8xxx_vib *vib = dev_get_drvdata(dev);
|
||||
|
||||
/* Turn off the vibrator */
|
||||
pm8xxx_vib_set(vib, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL);
|
||||
|
||||
static struct platform_driver pm8xxx_vib_driver = {
|
||||
.probe = pm8xxx_vib_probe,
|
||||
.remove = __devexit_p(pm8xxx_vib_remove),
|
||||
.driver = {
|
||||
.name = "pm8xxx-vib",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &pm8xxx_vib_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init pm8xxx_vib_init(void)
|
||||
{
|
||||
return platform_driver_register(&pm8xxx_vib_driver);
|
||||
}
|
||||
module_init(pm8xxx_vib_init);
|
||||
|
||||
static void __exit pm8xxx_vib_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&pm8xxx_vib_driver);
|
||||
}
|
||||
module_exit(pm8xxx_vib_exit);
|
||||
|
||||
MODULE_ALIAS("platform:pm8xxx_vib");
|
||||
MODULE_DESCRIPTION("PMIC8xxx vibrator driver based on ff-memless framework");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Amy Maloche <amaloche@codeaurora.org>");
|
|
@ -228,7 +228,7 @@ static void twl6040_vibra_close(struct input_dev *input)
|
|||
mutex_unlock(&info->mutex);
|
||||
}
|
||||
|
||||
#if CONFIG_PM_SLEEP
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int twl6040_vibra_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
|
|
|
@ -23,13 +23,6 @@
|
|||
#include "psmouse.h"
|
||||
#include "alps.h"
|
||||
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
#define dbg(format, arg...) printk(KERN_INFO "alps.c: " format "\n", ## arg)
|
||||
#else
|
||||
#define dbg(format, arg...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#define ALPS_OLDPROTO 0x01 /* old style input */
|
||||
#define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */
|
||||
#define ALPS_PASS 0x04 /* device has a pass-through port */
|
||||
|
@ -297,8 +290,8 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse)
|
|||
psmouse->packet[4] |
|
||||
psmouse->packet[5]) & 0x80) ||
|
||||
(!alps_is_valid_first_byte(priv->i, psmouse->packet[6]))) {
|
||||
dbg("refusing packet %x %x %x %x "
|
||||
"(suspected interleaved ps/2)\n",
|
||||
psmouse_dbg(psmouse,
|
||||
"refusing packet %x %x %x %x (suspected interleaved ps/2)\n",
|
||||
psmouse->packet[3], psmouse->packet[4],
|
||||
psmouse->packet[5], psmouse->packet[6]);
|
||||
return PSMOUSE_BAD_DATA;
|
||||
|
@ -319,13 +312,13 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse)
|
|||
* There is also possibility that we got 6-byte ALPS
|
||||
* packet followed by 3-byte packet from trackpoint. We
|
||||
* can not distinguish between these 2 scenarios but
|
||||
* becase the latter is unlikely to happen in course of
|
||||
* because the latter is unlikely to happen in course of
|
||||
* normal operation (user would need to press all
|
||||
* buttons on the pad and start moving trackpoint
|
||||
* without touching the pad surface) we assume former.
|
||||
* Even if we are wrong the wost thing that would happen
|
||||
* the cursor would jump but we should not get protocol
|
||||
* desynchronization.
|
||||
* de-synchronization.
|
||||
*/
|
||||
|
||||
alps_report_bare_ps2_packet(psmouse, &psmouse->packet[3],
|
||||
|
@ -361,8 +354,8 @@ static void alps_flush_packet(unsigned long data)
|
|||
if ((psmouse->packet[3] |
|
||||
psmouse->packet[4] |
|
||||
psmouse->packet[5]) & 0x80) {
|
||||
dbg("refusing packet %x %x %x "
|
||||
"(suspected interleaved ps/2)\n",
|
||||
psmouse_dbg(psmouse,
|
||||
"refusing packet %x %x %x (suspected interleaved ps/2)\n",
|
||||
psmouse->packet[3], psmouse->packet[4],
|
||||
psmouse->packet[5]);
|
||||
} else {
|
||||
|
@ -396,7 +389,8 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
|
|||
}
|
||||
|
||||
if (!alps_is_valid_first_byte(model, psmouse->packet[0])) {
|
||||
dbg("refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n",
|
||||
psmouse_dbg(psmouse,
|
||||
"refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n",
|
||||
psmouse->packet[0], model->mask0, model->byte0);
|
||||
return PSMOUSE_BAD_DATA;
|
||||
}
|
||||
|
@ -404,8 +398,9 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
|
|||
/* Bytes 2 - 6 should have 0 in the highest bit */
|
||||
if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 &&
|
||||
(psmouse->packet[psmouse->pktcnt - 1] & 0x80)) {
|
||||
dbg("refusing packet[%i] = %x\n",
|
||||
psmouse->pktcnt - 1, psmouse->packet[psmouse->pktcnt - 1]);
|
||||
psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
|
||||
psmouse->pktcnt - 1,
|
||||
psmouse->packet[psmouse->pktcnt - 1]);
|
||||
return PSMOUSE_BAD_DATA;
|
||||
}
|
||||
|
||||
|
@ -439,7 +434,8 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int
|
|||
if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
|
||||
return NULL;
|
||||
|
||||
dbg("E6 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
|
||||
psmouse_dbg(psmouse, "E6 report: %2.2x %2.2x %2.2x",
|
||||
param[0], param[1], param[2]);
|
||||
|
||||
if (param[0] != 0 || param[1] != 0 || (param[2] != 10 && param[2] != 100))
|
||||
return NULL;
|
||||
|
@ -459,7 +455,8 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int
|
|||
if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
|
||||
return NULL;
|
||||
|
||||
dbg("E7 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
|
||||
psmouse_dbg(psmouse, "E7 report: %2.2x %2.2x %2.2x",
|
||||
param[0], param[1], param[2]);
|
||||
|
||||
if (version) {
|
||||
for (i = 0; i < ARRAY_SIZE(rates) && param[2] != rates[i]; i++)
|
||||
|
@ -527,7 +524,8 @@ static int alps_get_status(struct psmouse *psmouse, char *param)
|
|||
ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
|
||||
return -1;
|
||||
|
||||
dbg("Status: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
|
||||
psmouse_dbg(psmouse, "Status: %2.2x %2.2x %2.2x",
|
||||
param[0], param[1], param[2]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -605,12 +603,12 @@ static int alps_hw_init(struct psmouse *psmouse)
|
|||
}
|
||||
|
||||
if (alps_tap_mode(psmouse, true)) {
|
||||
printk(KERN_WARNING "alps.c: Failed to enable hardware tapping\n");
|
||||
psmouse_warn(psmouse, "Failed to enable hardware tapping\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (alps_absolute_mode(psmouse)) {
|
||||
printk(KERN_ERR "alps.c: Failed to enable absolute mode\n");
|
||||
psmouse_err(psmouse, "Failed to enable absolute mode\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -621,7 +619,7 @@ static int alps_hw_init(struct psmouse *psmouse)
|
|||
|
||||
/* ALPS needs stream mode, otherwise it won't report any data */
|
||||
if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSTREAM)) {
|
||||
printk(KERN_ERR "alps.c: Failed to enable stream mode\n");
|
||||
psmouse_err(psmouse, "Failed to enable stream mode\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -16,14 +16,17 @@
|
|||
/*
|
||||
* Command values for Synaptics style queries
|
||||
*/
|
||||
#define ETP_FW_ID_QUERY 0x00
|
||||
#define ETP_FW_VERSION_QUERY 0x01
|
||||
#define ETP_CAPABILITIES_QUERY 0x02
|
||||
#define ETP_SAMPLE_QUERY 0x03
|
||||
|
||||
/*
|
||||
* Command values for register reading or writing
|
||||
*/
|
||||
#define ETP_REGISTER_READ 0x10
|
||||
#define ETP_REGISTER_WRITE 0x11
|
||||
#define ETP_REGISTER_READWRITE 0x00
|
||||
|
||||
/*
|
||||
* Hardware version 2 custom PS/2 command value
|
||||
|
@ -66,16 +69,13 @@
|
|||
#define ETP_YMAX_V1 (384 - ETP_EDGE_FUZZ_V1)
|
||||
|
||||
/*
|
||||
* It seems the resolution for hardware version 2 doubled.
|
||||
* Hence the X and Y ranges are doubled too.
|
||||
* The bezel around the pad also appears to be smaller
|
||||
* The resolution for older v2 hardware doubled.
|
||||
* (newer v2's firmware provides command so we can query)
|
||||
*/
|
||||
#define ETP_EDGE_FUZZ_V2 8
|
||||
|
||||
#define ETP_XMIN_V2 ( 0 + ETP_EDGE_FUZZ_V2)
|
||||
#define ETP_XMAX_V2 (1152 - ETP_EDGE_FUZZ_V2)
|
||||
#define ETP_YMIN_V2 ( 0 + ETP_EDGE_FUZZ_V2)
|
||||
#define ETP_YMAX_V2 ( 768 - ETP_EDGE_FUZZ_V2)
|
||||
#define ETP_XMIN_V2 0
|
||||
#define ETP_XMAX_V2 1152
|
||||
#define ETP_YMIN_V2 0
|
||||
#define ETP_YMAX_V2 768
|
||||
|
||||
#define ETP_PMIN_V2 0
|
||||
#define ETP_PMAX_V2 255
|
||||
|
@ -83,17 +83,37 @@
|
|||
#define ETP_WMAX_V2 15
|
||||
|
||||
/*
|
||||
* For two finger touches the coordinate of each finger gets reported
|
||||
* separately but with reduced resolution.
|
||||
* v3 hardware has 2 kinds of packet types,
|
||||
* v4 hardware has 3.
|
||||
*/
|
||||
#define ETP_2FT_FUZZ 4
|
||||
#define PACKET_UNKNOWN 0x01
|
||||
#define PACKET_DEBOUNCE 0x02
|
||||
#define PACKET_V3_HEAD 0x03
|
||||
#define PACKET_V3_TAIL 0x04
|
||||
#define PACKET_V4_HEAD 0x05
|
||||
#define PACKET_V4_MOTION 0x06
|
||||
#define PACKET_V4_STATUS 0x07
|
||||
|
||||
#define ETP_2FT_XMIN ( 0 + ETP_2FT_FUZZ)
|
||||
#define ETP_2FT_XMAX (288 - ETP_2FT_FUZZ)
|
||||
#define ETP_2FT_YMIN ( 0 + ETP_2FT_FUZZ)
|
||||
#define ETP_2FT_YMAX (192 - ETP_2FT_FUZZ)
|
||||
/*
|
||||
* track up to 5 fingers for v4 hardware
|
||||
*/
|
||||
#define ETP_MAX_FINGERS 5
|
||||
|
||||
/*
|
||||
* weight value for v4 hardware
|
||||
*/
|
||||
#define ETP_WEIGHT_VALUE 5
|
||||
|
||||
/*
|
||||
* The base position for one finger, v4 hardware
|
||||
*/
|
||||
struct finger_pos {
|
||||
unsigned int x;
|
||||
unsigned int y;
|
||||
};
|
||||
|
||||
struct elantech_data {
|
||||
unsigned char reg_07;
|
||||
unsigned char reg_10;
|
||||
unsigned char reg_11;
|
||||
unsigned char reg_20;
|
||||
|
@ -104,13 +124,16 @@ struct elantech_data {
|
|||
unsigned char reg_25;
|
||||
unsigned char reg_26;
|
||||
unsigned char debug;
|
||||
unsigned char capabilities;
|
||||
unsigned char capabilities[3];
|
||||
bool paritycheck;
|
||||
bool jumpy_cursor;
|
||||
bool reports_pressure;
|
||||
unsigned char hw_version;
|
||||
unsigned int fw_version;
|
||||
unsigned int single_finger_reports;
|
||||
unsigned int y_max;
|
||||
unsigned int width;
|
||||
struct finger_pos mt[ETP_MAX_FINGERS];
|
||||
unsigned char parity[256];
|
||||
};
|
||||
|
||||
|
|
|
@ -136,10 +136,10 @@ static int hgpk_discard_decay_hack(struct psmouse *psmouse, int x, int y)
|
|||
/* discard if too big, or half that but > 4 times the prev delta */
|
||||
if (avx > recalib_delta ||
|
||||
(avx > recalib_delta / 2 && ((avx / 4) > priv->xlast))) {
|
||||
hgpk_err(psmouse, "detected %dpx jump in x\n", x);
|
||||
psmouse_warn(psmouse, "detected %dpx jump in x\n", x);
|
||||
priv->xbigj = avx;
|
||||
} else if (approx_half(avx, priv->xbigj)) {
|
||||
hgpk_err(psmouse, "detected secondary %dpx jump in x\n", x);
|
||||
psmouse_warn(psmouse, "detected secondary %dpx jump in x\n", x);
|
||||
priv->xbigj = avx;
|
||||
priv->xsaw_secondary++;
|
||||
} else {
|
||||
|
@ -151,10 +151,10 @@ static int hgpk_discard_decay_hack(struct psmouse *psmouse, int x, int y)
|
|||
|
||||
if (avy > recalib_delta ||
|
||||
(avy > recalib_delta / 2 && ((avy / 4) > priv->ylast))) {
|
||||
hgpk_err(psmouse, "detected %dpx jump in y\n", y);
|
||||
psmouse_warn(psmouse, "detected %dpx jump in y\n", y);
|
||||
priv->ybigj = avy;
|
||||
} else if (approx_half(avy, priv->ybigj)) {
|
||||
hgpk_err(psmouse, "detected secondary %dpx jump in y\n", y);
|
||||
psmouse_warn(psmouse, "detected secondary %dpx jump in y\n", y);
|
||||
priv->ybigj = avy;
|
||||
priv->ysaw_secondary++;
|
||||
} else {
|
||||
|
@ -168,7 +168,7 @@ static int hgpk_discard_decay_hack(struct psmouse *psmouse, int x, int y)
|
|||
priv->ylast = avy;
|
||||
|
||||
if (do_recal && jumpy_delay) {
|
||||
hgpk_err(psmouse, "scheduling recalibration\n");
|
||||
psmouse_warn(psmouse, "scheduling recalibration\n");
|
||||
psmouse_queue_work(psmouse, &priv->recalib_wq,
|
||||
msecs_to_jiffies(jumpy_delay));
|
||||
}
|
||||
|
@ -260,7 +260,7 @@ static void hgpk_spewing_hack(struct psmouse *psmouse,
|
|||
* movement, it is probably a case of the user moving the
|
||||
* cursor very slowly across the screen. */
|
||||
if (abs(priv->x_tally) < 3 && abs(priv->y_tally) < 3) {
|
||||
hgpk_err(psmouse, "packet spew detected (%d,%d)\n",
|
||||
psmouse_warn(psmouse, "packet spew detected (%d,%d)\n",
|
||||
priv->x_tally, priv->y_tally);
|
||||
priv->spew_flag = RECALIBRATING;
|
||||
psmouse_queue_work(psmouse, &priv->recalib_wq,
|
||||
|
@ -333,7 +333,7 @@ static bool hgpk_is_byte_valid(struct psmouse *psmouse, unsigned char *packet)
|
|||
}
|
||||
|
||||
if (!valid)
|
||||
hgpk_dbg(psmouse,
|
||||
psmouse_dbg(psmouse,
|
||||
"bad data, mode %d (%d) %02x %02x %02x %02x %02x %02x\n",
|
||||
priv->mode, pktcnt,
|
||||
psmouse->packet[0], psmouse->packet[1],
|
||||
|
@ -361,7 +361,7 @@ static void hgpk_process_advanced_packet(struct psmouse *psmouse)
|
|||
|
||||
input_report_abs(idev, ABS_PRESSURE, z);
|
||||
if (tpdebug)
|
||||
hgpk_dbg(psmouse, "pd=%d fd=%d z=%d",
|
||||
psmouse_dbg(psmouse, "pd=%d fd=%d z=%d",
|
||||
pt_down, finger_down, z);
|
||||
} else {
|
||||
/*
|
||||
|
@ -369,11 +369,12 @@ static void hgpk_process_advanced_packet(struct psmouse *psmouse)
|
|||
* report it here
|
||||
*/
|
||||
if (tpdebug)
|
||||
hgpk_dbg(psmouse, "pd=%d ", down);
|
||||
psmouse_dbg(psmouse, "pd=%d ", down);
|
||||
}
|
||||
|
||||
if (tpdebug)
|
||||
hgpk_dbg(psmouse, "l=%d r=%d x=%d y=%d\n", left, right, x, y);
|
||||
psmouse_dbg(psmouse, "l=%d r=%d x=%d y=%d\n",
|
||||
left, right, x, y);
|
||||
|
||||
input_report_key(idev, BTN_TOUCH, down);
|
||||
input_report_key(idev, BTN_LEFT, left);
|
||||
|
@ -395,7 +396,7 @@ static void hgpk_process_advanced_packet(struct psmouse *psmouse)
|
|||
if (x == priv->abs_x && y == priv->abs_y) {
|
||||
if (++priv->dupe_count > SPEW_WATCH_COUNT) {
|
||||
if (tpdebug)
|
||||
hgpk_dbg(psmouse, "hard spew detected\n");
|
||||
psmouse_dbg(psmouse, "hard spew detected\n");
|
||||
priv->spew_flag = RECALIBRATING;
|
||||
psmouse_queue_work(psmouse, &priv->recalib_wq,
|
||||
msecs_to_jiffies(spew_delay));
|
||||
|
@ -412,7 +413,7 @@ static void hgpk_process_advanced_packet(struct psmouse *psmouse)
|
|||
int y_diff = priv->abs_y - y;
|
||||
if (hgpk_discard_decay_hack(psmouse, x_diff, y_diff)) {
|
||||
if (tpdebug)
|
||||
hgpk_dbg(psmouse, "discarding\n");
|
||||
psmouse_dbg(psmouse, "discarding\n");
|
||||
goto done;
|
||||
}
|
||||
hgpk_spewing_hack(psmouse, left, right, x_diff, y_diff);
|
||||
|
@ -437,20 +438,21 @@ static void hgpk_process_simple_packet(struct psmouse *psmouse)
|
|||
int y = ((packet[0] << 3) & 0x100) - packet[2];
|
||||
|
||||
if (packet[0] & 0xc0)
|
||||
hgpk_dbg(psmouse,
|
||||
psmouse_dbg(psmouse,
|
||||
"overflow -- 0x%02x 0x%02x 0x%02x\n",
|
||||
packet[0], packet[1], packet[2]);
|
||||
|
||||
if (hgpk_discard_decay_hack(psmouse, x, y)) {
|
||||
if (tpdebug)
|
||||
hgpk_dbg(psmouse, "discarding\n");
|
||||
psmouse_dbg(psmouse, "discarding\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hgpk_spewing_hack(psmouse, left, right, x, y);
|
||||
|
||||
if (tpdebug)
|
||||
hgpk_dbg(psmouse, "l=%d r=%d x=%d y=%d\n", left, right, x, y);
|
||||
psmouse_dbg(psmouse, "l=%d r=%d x=%d y=%d\n",
|
||||
left, right, x, y);
|
||||
|
||||
input_report_key(dev, BTN_LEFT, left);
|
||||
input_report_key(dev, BTN_RIGHT, right);
|
||||
|
@ -482,9 +484,8 @@ static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse)
|
|||
* ugh, got a packet inside our recalibration
|
||||
* window, schedule another recalibration.
|
||||
*/
|
||||
hgpk_dbg(psmouse,
|
||||
"packet inside calibration window, "
|
||||
"queueing another recalibration\n");
|
||||
psmouse_dbg(psmouse,
|
||||
"packet inside calibration window, queueing another recalibration\n");
|
||||
psmouse_queue_work(psmouse, &priv->recalib_wq,
|
||||
msecs_to_jiffies(post_interrupt_delay));
|
||||
}
|
||||
|
@ -628,7 +629,7 @@ static int hgpk_reset_device(struct psmouse *psmouse, bool recalibrate)
|
|||
|
||||
err = hgpk_select_mode(psmouse);
|
||||
if (err) {
|
||||
hgpk_err(psmouse, "failed to select mode\n");
|
||||
psmouse_err(psmouse, "failed to select mode\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -648,11 +649,11 @@ static int hgpk_force_recalibrate(struct psmouse *psmouse)
|
|||
return 0;
|
||||
|
||||
if (!autorecal) {
|
||||
hgpk_dbg(psmouse, "recalibrations disabled, ignoring\n");
|
||||
psmouse_dbg(psmouse, "recalibration disabled, ignoring\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
hgpk_dbg(psmouse, "recalibrating touchpad..\n");
|
||||
psmouse_dbg(psmouse, "recalibrating touchpad..\n");
|
||||
|
||||
/* we don't want to race with the irq handler, nor with resyncs */
|
||||
psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
|
||||
|
@ -675,7 +676,7 @@ static int hgpk_force_recalibrate(struct psmouse *psmouse)
|
|||
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
|
||||
|
||||
if (tpdebug)
|
||||
hgpk_dbg(psmouse, "touchpad reactivated\n");
|
||||
psmouse_dbg(psmouse, "touchpad reactivated\n");
|
||||
|
||||
/*
|
||||
* If we get packets right away after recalibrating, it's likely
|
||||
|
@ -727,16 +728,16 @@ static int hgpk_toggle_powersave(struct psmouse *psmouse, int enable)
|
|||
|
||||
err = hgpk_reset_device(psmouse, false);
|
||||
if (err) {
|
||||
hgpk_err(psmouse, "Failed to reset device!\n");
|
||||
psmouse_err(psmouse, "Failed to reset device!\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* should be all set, enable the touchpad */
|
||||
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE);
|
||||
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
|
||||
hgpk_dbg(psmouse, "Touchpad powered up.\n");
|
||||
psmouse_dbg(psmouse, "Touchpad powered up.\n");
|
||||
} else {
|
||||
hgpk_dbg(psmouse, "Powering off touchpad.\n");
|
||||
psmouse_dbg(psmouse, "Powering off touchpad.\n");
|
||||
|
||||
if (ps2_command(ps2dev, NULL, 0xec) ||
|
||||
ps2_command(ps2dev, NULL, 0xec) ||
|
||||
|
@ -923,7 +924,7 @@ static void hgpk_recalib_work(struct work_struct *work)
|
|||
struct psmouse *psmouse = priv->psmouse;
|
||||
|
||||
if (hgpk_force_recalibrate(psmouse))
|
||||
hgpk_err(psmouse, "recalibration failed!\n");
|
||||
psmouse_err(psmouse, "recalibration failed!\n");
|
||||
}
|
||||
|
||||
static int hgpk_register(struct psmouse *psmouse)
|
||||
|
@ -947,14 +948,15 @@ static int hgpk_register(struct psmouse *psmouse)
|
|||
err = device_create_file(&psmouse->ps2dev.serio->dev,
|
||||
&psmouse_attr_powered.dattr);
|
||||
if (err) {
|
||||
hgpk_err(psmouse, "Failed creating 'powered' sysfs node\n");
|
||||
psmouse_err(psmouse, "Failed creating 'powered' sysfs node\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = device_create_file(&psmouse->ps2dev.serio->dev,
|
||||
&psmouse_attr_hgpk_mode.dattr);
|
||||
if (err) {
|
||||
hgpk_err(psmouse, "Failed creating 'hgpk_mode' sysfs node\n");
|
||||
psmouse_err(psmouse,
|
||||
"Failed creating 'hgpk_mode' sysfs node\n");
|
||||
goto err_remove_powered;
|
||||
}
|
||||
|
||||
|
@ -963,7 +965,7 @@ static int hgpk_register(struct psmouse *psmouse)
|
|||
err = device_create_file(&psmouse->ps2dev.serio->dev,
|
||||
&psmouse_attr_recalibrate.dattr);
|
||||
if (err) {
|
||||
hgpk_err(psmouse,
|
||||
psmouse_err(psmouse,
|
||||
"Failed creating 'recalibrate' sysfs node\n");
|
||||
goto err_remove_mode;
|
||||
}
|
||||
|
@ -1027,13 +1029,13 @@ static enum hgpk_model_t hgpk_get_model(struct psmouse *psmouse)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
hgpk_dbg(psmouse, "ID: %02x %02x %02x\n", param[0], param[1], param[2]);
|
||||
psmouse_dbg(psmouse, "ID: %02x %02x %02x\n", param[0], param[1], param[2]);
|
||||
|
||||
/* HGPK signature: 0x67, 0x00, 0x<model> */
|
||||
if (param[0] != 0x67 || param[1] != 0x00)
|
||||
return -ENODEV;
|
||||
|
||||
hgpk_info(psmouse, "OLPC touchpad revision 0x%x\n", param[2]);
|
||||
psmouse_info(psmouse, "OLPC touchpad revision 0x%x\n", param[2]);
|
||||
|
||||
return param[2];
|
||||
}
|
||||
|
|
|
@ -46,17 +46,6 @@ struct hgpk_data {
|
|||
int xsaw_secondary, ysaw_secondary; /* jumpiness detection */
|
||||
};
|
||||
|
||||
#define hgpk_dbg(psmouse, format, arg...) \
|
||||
dev_dbg(&(psmouse)->ps2dev.serio->dev, format, ## arg)
|
||||
#define hgpk_err(psmouse, format, arg...) \
|
||||
dev_err(&(psmouse)->ps2dev.serio->dev, format, ## arg)
|
||||
#define hgpk_info(psmouse, format, arg...) \
|
||||
dev_info(&(psmouse)->ps2dev.serio->dev, format, ## arg)
|
||||
#define hgpk_warn(psmouse, format, arg...) \
|
||||
dev_warn(&(psmouse)->ps2dev.serio->dev, format, ## arg)
|
||||
#define hgpk_notice(psmouse, format, arg...) \
|
||||
dev_notice(&(psmouse)->ps2dev.serio->dev, format, ## arg)
|
||||
|
||||
#ifdef CONFIG_MOUSE_PS2_OLPC
|
||||
void hgpk_module_init(void);
|
||||
int hgpk_detect(struct psmouse *psmouse, bool set_properties);
|
||||
|
|
|
@ -169,8 +169,8 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
|
|||
|
||||
if (relative_packet) {
|
||||
if (!dev2)
|
||||
printk(KERN_WARNING "lifebook.c: got relative packet "
|
||||
"but no relative device set up\n");
|
||||
psmouse_warn(psmouse,
|
||||
"got relative packet but no relative device set up\n");
|
||||
} else {
|
||||
if (lifebook_use_6byte_proto) {
|
||||
input_report_abs(dev1, ABS_X,
|
||||
|
@ -212,7 +212,7 @@ static int lifebook_absolute_mode(struct psmouse *psmouse)
|
|||
|
||||
/*
|
||||
* Enable absolute output -- ps2_command fails always but if
|
||||
* you leave this call out the touchsreen will never send
|
||||
* you leave this call out the touchscreen will never send
|
||||
* absolute coordinates
|
||||
*/
|
||||
param = lifebook_use_6byte_proto ? 0x08 : 0x07;
|
||||
|
|
|
@ -82,11 +82,11 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
|
|||
packet[0] = packet[2] | 0x08;
|
||||
break;
|
||||
|
||||
#ifdef DEBUG
|
||||
default:
|
||||
printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n",
|
||||
psmouse_dbg(psmouse,
|
||||
"Received PS2++ packet #%x, but don't know how to handle.\n",
|
||||
(packet[1] >> 4) | (packet[0] & 0x30));
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Standard PS/2 motion data */
|
||||
|
@ -382,7 +382,7 @@ int ps2pp_init(struct psmouse *psmouse, bool set_properties)
|
|||
}
|
||||
|
||||
} else {
|
||||
printk(KERN_WARNING "logips2pp: Detected unknown logitech mouse model %d\n", model);
|
||||
psmouse_warn(psmouse, "Detected unknown Logitech mouse model %d\n", model);
|
||||
}
|
||||
|
||||
if (set_properties) {
|
||||
|
@ -400,9 +400,9 @@ int ps2pp_init(struct psmouse *psmouse, bool set_properties)
|
|||
error = device_create_file(&psmouse->ps2dev.serio->dev,
|
||||
&psmouse_attr_smartscroll.dattr);
|
||||
if (error) {
|
||||
printk(KERN_ERR
|
||||
"logips2pp.c: failed to create smartscroll "
|
||||
"sysfs attribute, error: %d\n", error);
|
||||
psmouse_err(psmouse,
|
||||
"failed to create smartscroll sysfs attribute, error: %d\n",
|
||||
error);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
#define psmouse_fmt(fmt) fmt
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -251,11 +254,14 @@ static int psmouse_handle_byte(struct psmouse *psmouse)
|
|||
switch (rc) {
|
||||
case PSMOUSE_BAD_DATA:
|
||||
if (psmouse->state == PSMOUSE_ACTIVATED) {
|
||||
printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n",
|
||||
psmouse->name, psmouse->phys, psmouse->pktcnt);
|
||||
psmouse_warn(psmouse,
|
||||
"%s at %s lost sync at byte %d\n",
|
||||
psmouse->name, psmouse->phys,
|
||||
psmouse->pktcnt);
|
||||
if (++psmouse->out_of_sync_cnt == psmouse->resetafter) {
|
||||
__psmouse_set_state(psmouse, PSMOUSE_IGNORE);
|
||||
printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n");
|
||||
psmouse_notice(psmouse,
|
||||
"issuing reconnect request\n");
|
||||
serio_reconnect(psmouse->ps2dev.serio);
|
||||
return -1;
|
||||
}
|
||||
|
@ -267,7 +273,8 @@ static int psmouse_handle_byte(struct psmouse *psmouse)
|
|||
psmouse->pktcnt = 0;
|
||||
if (psmouse->out_of_sync_cnt) {
|
||||
psmouse->out_of_sync_cnt = 0;
|
||||
printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n",
|
||||
psmouse_notice(psmouse,
|
||||
"%s at %s - driver resynced.\n",
|
||||
psmouse->name, psmouse->phys);
|
||||
}
|
||||
break;
|
||||
|
@ -295,7 +302,8 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
|
|||
((flags & SERIO_PARITY) && !psmouse->ignore_parity))) {
|
||||
|
||||
if (psmouse->state == PSMOUSE_ACTIVATED)
|
||||
printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n",
|
||||
psmouse_warn(psmouse,
|
||||
"bad data from KBC -%s%s\n",
|
||||
flags & SERIO_TIMEOUT ? " timeout" : "",
|
||||
flags & SERIO_PARITY ? " bad parity" : "");
|
||||
ps2_cmd_aborted(&psmouse->ps2dev);
|
||||
|
@ -315,7 +323,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
|
|||
|
||||
if (psmouse->state == PSMOUSE_ACTIVATED &&
|
||||
psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) {
|
||||
printk(KERN_INFO "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n",
|
||||
psmouse_info(psmouse, "%s at %s lost synchronization, throwing %d bytes away.\n",
|
||||
psmouse->name, psmouse->phys, psmouse->pktcnt);
|
||||
psmouse->badbyte = psmouse->packet[0];
|
||||
__psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
|
||||
|
@ -943,7 +951,8 @@ static int psmouse_probe(struct psmouse *psmouse)
|
|||
*/
|
||||
|
||||
if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS))
|
||||
printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", ps2dev->serio->phys);
|
||||
psmouse_warn(psmouse, "Failed to reset mouse on %s\n",
|
||||
ps2dev->serio->phys);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1005,7 +1014,7 @@ static void psmouse_initialize(struct psmouse *psmouse)
|
|||
static void psmouse_activate(struct psmouse *psmouse)
|
||||
{
|
||||
if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE))
|
||||
printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n",
|
||||
psmouse_warn(psmouse, "Failed to enable mouse on %s\n",
|
||||
psmouse->ps2dev.serio->phys);
|
||||
|
||||
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
|
||||
|
@ -1020,14 +1029,14 @@ static void psmouse_activate(struct psmouse *psmouse)
|
|||
static void psmouse_deactivate(struct psmouse *psmouse)
|
||||
{
|
||||
if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE))
|
||||
printk(KERN_WARNING "psmouse.c: Failed to deactivate mouse on %s\n",
|
||||
psmouse_warn(psmouse, "Failed to deactivate mouse on %s\n",
|
||||
psmouse->ps2dev.serio->phys);
|
||||
|
||||
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
|
||||
}
|
||||
|
||||
/*
|
||||
* psmouse_poll() - default poll hanlder. Everyone except for ALPS uses it.
|
||||
* psmouse_poll() - default poll handler. Everyone except for ALPS uses it.
|
||||
*/
|
||||
|
||||
static int psmouse_poll(struct psmouse *psmouse)
|
||||
|
@ -1115,14 +1124,15 @@ static void psmouse_resync(struct work_struct *work)
|
|||
}
|
||||
|
||||
if (!enabled) {
|
||||
printk(KERN_WARNING "psmouse.c: failed to re-enable mouse on %s\n",
|
||||
psmouse_warn(psmouse, "failed to re-enable mouse on %s\n",
|
||||
psmouse->ps2dev.serio->phys);
|
||||
failed = true;
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
psmouse_set_state(psmouse, PSMOUSE_IGNORE);
|
||||
printk(KERN_INFO "psmouse.c: resync failed, issuing reconnect request\n");
|
||||
psmouse_info(psmouse,
|
||||
"resync failed, issuing reconnect request\n");
|
||||
serio_reconnect(serio);
|
||||
} else
|
||||
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
|
||||
|
@ -1155,7 +1165,7 @@ static void psmouse_cleanup(struct serio *serio)
|
|||
* Disable stream mode so cleanup routine can proceed undisturbed.
|
||||
*/
|
||||
if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE))
|
||||
printk(KERN_WARNING "psmouse.c: Failed to disable mouse on %s\n",
|
||||
psmouse_warn(psmouse, "Failed to disable mouse on %s\n",
|
||||
psmouse->ps2dev.serio->phys);
|
||||
|
||||
if (psmouse->cleanup)
|
||||
|
@ -1400,7 +1410,8 @@ static int psmouse_reconnect(struct serio *serio)
|
|||
int rc = -1;
|
||||
|
||||
if (!drv || !psmouse) {
|
||||
printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n");
|
||||
psmouse_dbg(psmouse,
|
||||
"reconnect request, but serio is disconnected, ignoring...\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -1427,8 +1438,9 @@ static int psmouse_reconnect(struct serio *serio)
|
|||
goto out;
|
||||
}
|
||||
|
||||
/* ok, the device type (and capabilities) match the old one,
|
||||
* we can continue using it, complete intialization
|
||||
/*
|
||||
* OK, the device type (and capabilities) match the old one,
|
||||
* we can continue using it, complete initialization
|
||||
*/
|
||||
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
|
||||
|
||||
|
@ -1586,9 +1598,8 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co
|
|||
|
||||
while (!list_empty(&serio->children)) {
|
||||
if (++retry > 3) {
|
||||
printk(KERN_WARNING
|
||||
"psmouse: failed to destroy children ports, "
|
||||
"protocol change aborted.\n");
|
||||
psmouse_warn(psmouse,
|
||||
"failed to destroy children ports, protocol change aborted.\n");
|
||||
input_free_device(new_dev);
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -1715,7 +1726,7 @@ static int __init psmouse_init(void)
|
|||
|
||||
kpsmoused_wq = create_singlethread_workqueue("kpsmoused");
|
||||
if (!kpsmoused_wq) {
|
||||
printk(KERN_ERR "psmouse: failed to create kpsmoused workqueue\n");
|
||||
pr_err("failed to create kpsmoused workqueue\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
|
@ -150,4 +150,29 @@ static struct psmouse_attribute psmouse_attr_##_name = { \
|
|||
static ssize_t _set(struct psmouse *, void *, const char *, size_t); \
|
||||
__PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, NULL, _set, true)
|
||||
|
||||
#ifndef psmouse_fmt
|
||||
#define psmouse_fmt(fmt) KBUILD_BASENAME ": " fmt
|
||||
#endif
|
||||
|
||||
#define psmouse_dbg(psmouse, format, ...) \
|
||||
dev_dbg(&(psmouse)->ps2dev.serio->dev, \
|
||||
psmouse_fmt(format), ##__VA_ARGS__)
|
||||
#define psmouse_info(psmouse, format, ...) \
|
||||
dev_info(&(psmouse)->ps2dev.serio->dev, \
|
||||
psmouse_fmt(format), ##__VA_ARGS__)
|
||||
#define psmouse_warn(psmouse, format, ...) \
|
||||
dev_warn(&(psmouse)->ps2dev.serio->dev, \
|
||||
psmouse_fmt(format), ##__VA_ARGS__)
|
||||
#define psmouse_err(psmouse, format, ...) \
|
||||
dev_err(&(psmouse)->ps2dev.serio->dev, \
|
||||
psmouse_fmt(format), ##__VA_ARGS__)
|
||||
#define psmouse_notice(psmouse, format, ...) \
|
||||
dev_notice(&(psmouse)->ps2dev.serio->dev, \
|
||||
psmouse_fmt(format), ##__VA_ARGS__)
|
||||
#define psmouse_printk(level, psmouse, format, ...) \
|
||||
dev_printk(level, \
|
||||
&(psmouse)->ps2dev.serio->dev, \
|
||||
psmouse_fmt(format), ##__VA_ARGS__)
|
||||
|
||||
|
||||
#endif /* _PSMOUSE_H */
|
||||
|
|
|
@ -183,7 +183,7 @@ static int __devinit pxa930_trkball_probe(struct platform_device *pdev)
|
|||
/* held the module in reset, will be enabled in open() */
|
||||
pxa930_trkball_disable(trkball);
|
||||
|
||||
error = request_irq(irq, pxa930_trkball_interrupt, IRQF_DISABLED,
|
||||
error = request_irq(irq, pxa930_trkball_interrupt, 0,
|
||||
pdev->name, trkball);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to request irq: %d\n", error);
|
||||
|
|
|
@ -607,11 +607,12 @@ static void fsp_packet_debug(unsigned char packet[])
|
|||
|
||||
ps2_packet_cnt++;
|
||||
jiffies_msec = jiffies_to_msecs(jiffies);
|
||||
printk(KERN_DEBUG "%08dms PS/2 packets: %02x, %02x, %02x, %02x\n",
|
||||
psmouse_dbg(psmouse,
|
||||
"%08dms PS/2 packets: %02x, %02x, %02x, %02x\n",
|
||||
jiffies_msec, packet[0], packet[1], packet[2], packet[3]);
|
||||
|
||||
if (jiffies_msec - ps2_last_second > 1000) {
|
||||
printk(KERN_DEBUG "PS/2 packets/sec = %d\n", ps2_packet_cnt);
|
||||
psmouse_dbg(psmouse, "PS/2 packets/sec = %d\n", ps2_packet_cnt);
|
||||
ps2_packet_cnt = 0;
|
||||
ps2_last_second = jiffies_msec;
|
||||
}
|
||||
|
@ -820,7 +821,7 @@ int fsp_init(struct psmouse *psmouse)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
printk(KERN_INFO
|
||||
psmouse_info(psmouse,
|
||||
"Finger Sensing Pad, hw: %d.%d.%d, sw: %s, buttons: %d\n",
|
||||
ver >> 4, ver & 0x0F, rev, fsp_drv_ver, buttons & 7);
|
||||
|
||||
|
|
|
@ -44,6 +44,16 @@
|
|||
#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
|
||||
|
@ -157,8 +167,8 @@ static int synaptics_capability(struct psmouse *psmouse)
|
|||
|
||||
if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 1) {
|
||||
if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) {
|
||||
printk(KERN_ERR "Synaptics claims to have extended capabilities,"
|
||||
" but I'm not able to read them.\n");
|
||||
psmouse_warn(psmouse,
|
||||
"device claims to have extended capabilities, but I'm not able to read them.\n");
|
||||
} else {
|
||||
priv->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2];
|
||||
|
||||
|
@ -173,8 +183,8 @@ static int synaptics_capability(struct psmouse *psmouse)
|
|||
|
||||
if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 4) {
|
||||
if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB_0C, cap)) {
|
||||
printk(KERN_ERR "Synaptics claims to have extended capability 0x0c,"
|
||||
" but I'm not able to read it.\n");
|
||||
psmouse_warn(psmouse,
|
||||
"device claims to have extended capability 0x0c, but I'm not able to read it.\n");
|
||||
} else {
|
||||
priv->ext_cap_0c = (cap[0] << 16) | (cap[1] << 8) | cap[2];
|
||||
}
|
||||
|
@ -222,8 +232,8 @@ static int synaptics_resolution(struct psmouse *psmouse)
|
|||
if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 &&
|
||||
SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) {
|
||||
if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MAX_COORDS, resp)) {
|
||||
printk(KERN_ERR "Synaptics claims to have max coordinates"
|
||||
" query, but I'm not able to read it.\n");
|
||||
psmouse_warn(psmouse,
|
||||
"device claims to have max coordinates query, but I'm not able to read it.\n");
|
||||
} else {
|
||||
priv->x_max = (resp[0] << 5) | ((resp[1] & 0x0f) << 1);
|
||||
priv->y_max = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3);
|
||||
|
@ -233,8 +243,8 @@ static int synaptics_resolution(struct psmouse *psmouse)
|
|||
if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 7 &&
|
||||
SYN_CAP_MIN_DIMENSIONS(priv->ext_cap_0c)) {
|
||||
if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MIN_COORDS, resp)) {
|
||||
printk(KERN_ERR "Synaptics claims to have min coordinates"
|
||||
" query, but I'm not able to read it.\n");
|
||||
psmouse_warn(psmouse,
|
||||
"device claims to have min coordinates query, but I'm not able to read it.\n");
|
||||
} else {
|
||||
priv->x_min = (resp[0] << 5) | ((resp[1] & 0x0f) << 1);
|
||||
priv->y_min = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3);
|
||||
|
@ -294,7 +304,8 @@ static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse)
|
|||
static unsigned char param = 0xc8;
|
||||
struct synaptics_data *priv = psmouse->private;
|
||||
|
||||
if (!SYN_CAP_ADV_GESTURE(priv->ext_cap_0c))
|
||||
if (!(SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) ||
|
||||
SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)))
|
||||
return 0;
|
||||
|
||||
if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL))
|
||||
|
@ -377,7 +388,8 @@ static void synaptics_pt_activate(struct psmouse *psmouse)
|
|||
priv->mode &= ~SYN_BIT_FOUR_BYTE_CLIENT;
|
||||
|
||||
if (synaptics_mode_cmd(psmouse, priv->mode))
|
||||
printk(KERN_INFO "synaptics: failed to switch guest protocol\n");
|
||||
psmouse_warn(psmouse,
|
||||
"failed to switch guest protocol\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -387,7 +399,8 @@ static void synaptics_pt_create(struct psmouse *psmouse)
|
|||
|
||||
serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
|
||||
if (!serio) {
|
||||
printk(KERN_ERR "synaptics: not enough memory to allocate pass-through port\n");
|
||||
psmouse_err(psmouse,
|
||||
"not enough memory for pass-through port\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -401,7 +414,8 @@ static void synaptics_pt_create(struct psmouse *psmouse)
|
|||
|
||||
psmouse->pt_activate = synaptics_pt_activate;
|
||||
|
||||
printk(KERN_INFO "serio: %s port at %s\n", serio->name, psmouse->phys);
|
||||
psmouse_info(psmouse, "serio: %s port at %s\n",
|
||||
serio->name, psmouse->phys);
|
||||
serio_register_port(serio);
|
||||
}
|
||||
|
||||
|
@ -409,6 +423,44 @@ static void synaptics_pt_create(struct psmouse *psmouse)
|
|||
* Functions to interpret the absolute mode packets
|
||||
****************************************************************************/
|
||||
|
||||
static void synaptics_mt_state_set(struct synaptics_mt_state *state, int count,
|
||||
int sgm, int agm)
|
||||
{
|
||||
state->count = count;
|
||||
state->sgm = sgm;
|
||||
state->agm = agm;
|
||||
}
|
||||
|
||||
static void synaptics_parse_agm(const unsigned char buf[],
|
||||
struct synaptics_data *priv,
|
||||
struct synaptics_hw_state *hw)
|
||||
{
|
||||
struct synaptics_hw_state *agm = &priv->agm;
|
||||
int agm_packet_type;
|
||||
|
||||
agm_packet_type = (buf[5] & 0x30) >> 4;
|
||||
switch (agm_packet_type) {
|
||||
case 1:
|
||||
/* Gesture packet: (x, y, z) half resolution */
|
||||
agm->w = hw->w;
|
||||
agm->x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1;
|
||||
agm->y = (((buf[4] & 0xf0) << 4) | buf[2]) << 1;
|
||||
agm->z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
/* AGM-CONTACT packet: (count, sgm, agm) */
|
||||
synaptics_mt_state_set(&agm->mt_state, buf[1], buf[2], buf[4]);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Record that at least one AGM has been received since last SGM */
|
||||
priv->agm_pending = true;
|
||||
}
|
||||
|
||||
static int synaptics_parse_hw_state(const unsigned char buf[],
|
||||
struct synaptics_data *priv,
|
||||
struct synaptics_hw_state *hw)
|
||||
|
@ -442,11 +494,10 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
|
|||
hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0;
|
||||
}
|
||||
|
||||
if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) && hw->w == 2) {
|
||||
/* Gesture packet: (x, y, z) at half resolution */
|
||||
priv->mt.x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1;
|
||||
priv->mt.y = (((buf[4] & 0xf0) << 4) | buf[2]) << 1;
|
||||
priv->mt.z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1;
|
||||
if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) ||
|
||||
SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) &&
|
||||
hw->w == 2) {
|
||||
synaptics_parse_agm(buf, priv, hw);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -502,8 +553,7 @@ static void synaptics_report_semi_mt_slot(struct input_dev *dev, int slot,
|
|||
input_mt_report_slot_state(dev, MT_TOOL_FINGER, active);
|
||||
if (active) {
|
||||
input_report_abs(dev, ABS_MT_POSITION_X, x);
|
||||
input_report_abs(dev, ABS_MT_POSITION_Y,
|
||||
YMAX_NOMINAL + YMIN_NOMINAL - y);
|
||||
input_report_abs(dev, ABS_MT_POSITION_Y, synaptics_invert_y(y));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -526,6 +576,388 @@ static void synaptics_report_semi_mt_data(struct input_dev *dev,
|
|||
}
|
||||
}
|
||||
|
||||
static void synaptics_report_buttons(struct psmouse *psmouse,
|
||||
const struct synaptics_hw_state *hw)
|
||||
{
|
||||
struct input_dev *dev = psmouse->dev;
|
||||
struct synaptics_data *priv = psmouse->private;
|
||||
int i;
|
||||
|
||||
input_report_key(dev, BTN_LEFT, hw->left);
|
||||
input_report_key(dev, BTN_RIGHT, hw->right);
|
||||
|
||||
if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
|
||||
input_report_key(dev, BTN_MIDDLE, hw->middle);
|
||||
|
||||
if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
|
||||
input_report_key(dev, BTN_FORWARD, hw->up);
|
||||
input_report_key(dev, BTN_BACK, hw->down);
|
||||
}
|
||||
|
||||
for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
|
||||
input_report_key(dev, BTN_0 + i, hw->ext_buttons & (1 << i));
|
||||
}
|
||||
|
||||
static void synaptics_report_slot(struct input_dev *dev, int slot,
|
||||
const struct synaptics_hw_state *hw)
|
||||
{
|
||||
input_mt_slot(dev, slot);
|
||||
input_mt_report_slot_state(dev, MT_TOOL_FINGER, (hw != NULL));
|
||||
if (!hw)
|
||||
return;
|
||||
|
||||
input_report_abs(dev, ABS_MT_POSITION_X, hw->x);
|
||||
input_report_abs(dev, ABS_MT_POSITION_Y, synaptics_invert_y(hw->y));
|
||||
input_report_abs(dev, ABS_MT_PRESSURE, hw->z);
|
||||
}
|
||||
|
||||
static void synaptics_report_mt_data(struct psmouse *psmouse,
|
||||
struct synaptics_mt_state *mt_state,
|
||||
const struct synaptics_hw_state *sgm)
|
||||
{
|
||||
struct input_dev *dev = psmouse->dev;
|
||||
struct synaptics_data *priv = psmouse->private;
|
||||
struct synaptics_hw_state *agm = &priv->agm;
|
||||
struct synaptics_mt_state *old = &priv->mt_state;
|
||||
|
||||
switch (mt_state->count) {
|
||||
case 0:
|
||||
synaptics_report_slot(dev, 0, NULL);
|
||||
synaptics_report_slot(dev, 1, NULL);
|
||||
break;
|
||||
case 1:
|
||||
if (mt_state->sgm == -1) {
|
||||
synaptics_report_slot(dev, 0, NULL);
|
||||
synaptics_report_slot(dev, 1, NULL);
|
||||
} else if (mt_state->sgm == 0) {
|
||||
synaptics_report_slot(dev, 0, sgm);
|
||||
synaptics_report_slot(dev, 1, NULL);
|
||||
} else {
|
||||
synaptics_report_slot(dev, 0, NULL);
|
||||
synaptics_report_slot(dev, 1, sgm);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* If the finger slot contained in SGM is valid, and either
|
||||
* hasn't changed, or is new, then report SGM in MTB slot 0.
|
||||
* Otherwise, empty MTB slot 0.
|
||||
*/
|
||||
if (mt_state->sgm != -1 &&
|
||||
(mt_state->sgm == old->sgm || old->sgm == -1))
|
||||
synaptics_report_slot(dev, 0, sgm);
|
||||
else
|
||||
synaptics_report_slot(dev, 0, NULL);
|
||||
|
||||
/*
|
||||
* If the finger slot contained in AGM is valid, and either
|
||||
* hasn't changed, or is new, then report AGM in MTB slot 1.
|
||||
* Otherwise, empty MTB slot 1.
|
||||
*/
|
||||
if (mt_state->agm != -1 &&
|
||||
(mt_state->agm == old->agm || old->agm == -1))
|
||||
synaptics_report_slot(dev, 1, agm);
|
||||
else
|
||||
synaptics_report_slot(dev, 1, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Don't use active slot count to generate BTN_TOOL events. */
|
||||
input_mt_report_pointer_emulation(dev, false);
|
||||
|
||||
/* Send the number of fingers reported by touchpad itself. */
|
||||
input_mt_report_finger_count(dev, mt_state->count);
|
||||
|
||||
synaptics_report_buttons(psmouse, sgm);
|
||||
|
||||
input_sync(dev);
|
||||
}
|
||||
|
||||
/* Handle case where mt_state->count = 0 */
|
||||
static void synaptics_image_sensor_0f(struct synaptics_data *priv,
|
||||
struct synaptics_mt_state *mt_state)
|
||||
{
|
||||
synaptics_mt_state_set(mt_state, 0, -1, -1);
|
||||
priv->mt_state_lost = false;
|
||||
}
|
||||
|
||||
/* Handle case where mt_state->count = 1 */
|
||||
static void synaptics_image_sensor_1f(struct synaptics_data *priv,
|
||||
struct synaptics_mt_state *mt_state)
|
||||
{
|
||||
struct synaptics_hw_state *agm = &priv->agm;
|
||||
struct synaptics_mt_state *old = &priv->mt_state;
|
||||
|
||||
/*
|
||||
* If the last AGM was (0,0,0), and there is only one finger left,
|
||||
* then we absolutely know that SGM contains slot 0, and all other
|
||||
* fingers have been removed.
|
||||
*/
|
||||
if (priv->agm_pending && agm->z == 0) {
|
||||
synaptics_mt_state_set(mt_state, 1, 0, -1);
|
||||
priv->mt_state_lost = false;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (old->count) {
|
||||
case 0:
|
||||
synaptics_mt_state_set(mt_state, 1, 0, -1);
|
||||
break;
|
||||
case 1:
|
||||
/*
|
||||
* If mt_state_lost, then the previous transition was 3->1,
|
||||
* and SGM now contains either slot 0 or 1, but we don't know
|
||||
* which. So, we just assume that the SGM now contains slot 1.
|
||||
*
|
||||
* If pending AGM and either:
|
||||
* (a) the previous SGM slot contains slot 0, or
|
||||
* (b) there was no SGM slot
|
||||
* then, the SGM now contains slot 1
|
||||
*
|
||||
* Case (a) happens with very rapid "drum roll" gestures, where
|
||||
* slot 0 finger is lifted and a new slot 1 finger touches
|
||||
* within one reporting interval.
|
||||
*
|
||||
* Case (b) happens if initially two or more fingers tap
|
||||
* briefly, and all but one lift before the end of the first
|
||||
* reporting interval.
|
||||
*
|
||||
* (In both these cases, slot 0 will becomes empty, so SGM
|
||||
* contains slot 1 with the new finger)
|
||||
*
|
||||
* Else, if there was no previous SGM, it now contains slot 0.
|
||||
*
|
||||
* Otherwise, SGM still contains the same slot.
|
||||
*/
|
||||
if (priv->mt_state_lost ||
|
||||
(priv->agm_pending && old->sgm <= 0))
|
||||
synaptics_mt_state_set(mt_state, 1, 1, -1);
|
||||
else if (old->sgm == -1)
|
||||
synaptics_mt_state_set(mt_state, 1, 0, -1);
|
||||
break;
|
||||
case 2:
|
||||
/*
|
||||
* If mt_state_lost, we don't know which finger SGM contains.
|
||||
*
|
||||
* So, report 1 finger, but with both slots empty.
|
||||
* We will use slot 1 on subsequent 1->1
|
||||
*/
|
||||
if (priv->mt_state_lost) {
|
||||
synaptics_mt_state_set(mt_state, 1, -1, -1);
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Since the last AGM was NOT (0,0,0), it was the finger in
|
||||
* slot 0 that has been removed.
|
||||
* So, SGM now contains previous AGM's slot, and AGM is now
|
||||
* empty.
|
||||
*/
|
||||
synaptics_mt_state_set(mt_state, 1, old->agm, -1);
|
||||
break;
|
||||
case 3:
|
||||
/*
|
||||
* Since last AGM was not (0,0,0), we don't know which finger
|
||||
* is left.
|
||||
*
|
||||
* So, report 1 finger, but with both slots empty.
|
||||
* We will use slot 1 on subsequent 1->1
|
||||
*/
|
||||
synaptics_mt_state_set(mt_state, 1, -1, -1);
|
||||
priv->mt_state_lost = true;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
/* mt_state was updated by AGM-CONTACT packet */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle case where mt_state->count = 2 */
|
||||
static void synaptics_image_sensor_2f(struct synaptics_data *priv,
|
||||
struct synaptics_mt_state *mt_state)
|
||||
{
|
||||
struct synaptics_mt_state *old = &priv->mt_state;
|
||||
|
||||
switch (old->count) {
|
||||
case 0:
|
||||
synaptics_mt_state_set(mt_state, 2, 0, 1);
|
||||
break;
|
||||
case 1:
|
||||
/*
|
||||
* If previous SGM contained slot 1 or higher, SGM now contains
|
||||
* slot 0 (the newly touching finger) and AGM contains SGM's
|
||||
* previous slot.
|
||||
*
|
||||
* Otherwise, SGM still contains slot 0 and AGM now contains
|
||||
* slot 1.
|
||||
*/
|
||||
if (old->sgm >= 1)
|
||||
synaptics_mt_state_set(mt_state, 2, 0, old->sgm);
|
||||
else
|
||||
synaptics_mt_state_set(mt_state, 2, 0, 1);
|
||||
break;
|
||||
case 2:
|
||||
/*
|
||||
* If mt_state_lost, SGM now contains either finger 1 or 2, but
|
||||
* we don't know which.
|
||||
* So, we just assume that the SGM contains slot 0 and AGM 1.
|
||||
*/
|
||||
if (priv->mt_state_lost)
|
||||
synaptics_mt_state_set(mt_state, 2, 0, 1);
|
||||
/*
|
||||
* Otherwise, use the same mt_state, since it either hasn't
|
||||
* changed, or was updated by a recently received AGM-CONTACT
|
||||
* packet.
|
||||
*/
|
||||
break;
|
||||
case 3:
|
||||
/*
|
||||
* 3->2 transitions have two unsolvable problems:
|
||||
* 1) no indication is given which finger was removed
|
||||
* 2) no way to tell if agm packet was for finger 3
|
||||
* before 3->2, or finger 2 after 3->2.
|
||||
*
|
||||
* So, report 2 fingers, but empty all slots.
|
||||
* We will guess slots [0,1] on subsequent 2->2.
|
||||
*/
|
||||
synaptics_mt_state_set(mt_state, 2, -1, -1);
|
||||
priv->mt_state_lost = true;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
/* mt_state was updated by AGM-CONTACT packet */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle case where mt_state->count = 3 */
|
||||
static void synaptics_image_sensor_3f(struct synaptics_data *priv,
|
||||
struct synaptics_mt_state *mt_state)
|
||||
{
|
||||
struct synaptics_mt_state *old = &priv->mt_state;
|
||||
|
||||
switch (old->count) {
|
||||
case 0:
|
||||
synaptics_mt_state_set(mt_state, 3, 0, 2);
|
||||
break;
|
||||
case 1:
|
||||
/*
|
||||
* If previous SGM contained slot 2 or higher, SGM now contains
|
||||
* slot 0 (one of the newly touching fingers) and AGM contains
|
||||
* SGM's previous slot.
|
||||
*
|
||||
* Otherwise, SGM now contains slot 0 and AGM contains slot 2.
|
||||
*/
|
||||
if (old->sgm >= 2)
|
||||
synaptics_mt_state_set(mt_state, 3, 0, old->sgm);
|
||||
else
|
||||
synaptics_mt_state_set(mt_state, 3, 0, 2);
|
||||
break;
|
||||
case 2:
|
||||
/*
|
||||
* If the AGM previously contained slot 3 or higher, then the
|
||||
* newly touching finger is in the lowest available slot.
|
||||
*
|
||||
* If SGM was previously 1 or higher, then the new SGM is
|
||||
* now slot 0 (with a new finger), otherwise, the new finger
|
||||
* is now in a hidden slot between 0 and AGM's slot.
|
||||
*
|
||||
* In all such cases, the SGM now contains slot 0, and the AGM
|
||||
* continues to contain the same slot as before.
|
||||
*/
|
||||
if (old->agm >= 3) {
|
||||
synaptics_mt_state_set(mt_state, 3, 0, old->agm);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* After some 3->1 and all 3->2 transitions, we lose track
|
||||
* of which slot is reported by SGM and AGM.
|
||||
*
|
||||
* For 2->3 in this state, report 3 fingers, but empty all
|
||||
* slots, and we will guess (0,2) on a subsequent 0->3.
|
||||
*
|
||||
* To userspace, the resulting transition will look like:
|
||||
* 2:[0,1] -> 3:[-1,-1] -> 3:[0,2]
|
||||
*/
|
||||
if (priv->mt_state_lost) {
|
||||
synaptics_mt_state_set(mt_state, 3, -1, -1);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the (SGM,AGM) really previously contained slots (0, 1),
|
||||
* then we cannot know what slot was just reported by the AGM,
|
||||
* because the 2->3 transition can occur either before or after
|
||||
* the AGM packet. Thus, this most recent AGM could contain
|
||||
* either the same old slot 1 or the new slot 2.
|
||||
* Subsequent AGMs will be reporting slot 2.
|
||||
*
|
||||
* To userspace, the resulting transition will look like:
|
||||
* 2:[0,1] -> 3:[0,-1] -> 3:[0,2]
|
||||
*/
|
||||
synaptics_mt_state_set(mt_state, 3, 0, -1);
|
||||
break;
|
||||
case 3:
|
||||
/*
|
||||
* If, for whatever reason, the previous agm was invalid,
|
||||
* Assume SGM now contains slot 0, AGM now contains slot 2.
|
||||
*/
|
||||
if (old->agm <= 2)
|
||||
synaptics_mt_state_set(mt_state, 3, 0, 2);
|
||||
/*
|
||||
* mt_state either hasn't changed, or was updated by a recently
|
||||
* received AGM-CONTACT packet.
|
||||
*/
|
||||
break;
|
||||
|
||||
case 4:
|
||||
case 5:
|
||||
/* mt_state was updated by AGM-CONTACT packet */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle case where mt_state->count = 4, or = 5 */
|
||||
static void synaptics_image_sensor_45f(struct synaptics_data *priv,
|
||||
struct synaptics_mt_state *mt_state)
|
||||
{
|
||||
/* mt_state was updated correctly by AGM-CONTACT packet */
|
||||
priv->mt_state_lost = false;
|
||||
}
|
||||
|
||||
static void synaptics_image_sensor_process(struct psmouse *psmouse,
|
||||
struct synaptics_hw_state *sgm)
|
||||
{
|
||||
struct synaptics_data *priv = psmouse->private;
|
||||
struct synaptics_hw_state *agm = &priv->agm;
|
||||
struct synaptics_mt_state mt_state;
|
||||
|
||||
/* Initialize using current mt_state (as updated by last agm) */
|
||||
mt_state = agm->mt_state;
|
||||
|
||||
/*
|
||||
* Update mt_state using the new finger count and current mt_state.
|
||||
*/
|
||||
if (sgm->z == 0)
|
||||
synaptics_image_sensor_0f(priv, &mt_state);
|
||||
else if (sgm->w >= 4)
|
||||
synaptics_image_sensor_1f(priv, &mt_state);
|
||||
else if (sgm->w == 0)
|
||||
synaptics_image_sensor_2f(priv, &mt_state);
|
||||
else if (sgm->w == 1 && mt_state.count <= 3)
|
||||
synaptics_image_sensor_3f(priv, &mt_state);
|
||||
else
|
||||
synaptics_image_sensor_45f(priv, &mt_state);
|
||||
|
||||
/* Send resulting input events to user space */
|
||||
synaptics_report_mt_data(psmouse, &mt_state, sgm);
|
||||
|
||||
/* Store updated mt_state */
|
||||
priv->mt_state = agm->mt_state = mt_state;
|
||||
priv->agm_pending = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* called for each full received packet from the touchpad
|
||||
*/
|
||||
|
@ -536,11 +968,15 @@ static void synaptics_process_packet(struct psmouse *psmouse)
|
|||
struct synaptics_hw_state hw;
|
||||
int num_fingers;
|
||||
int finger_width;
|
||||
int i;
|
||||
|
||||
if (synaptics_parse_hw_state(psmouse->packet, priv, &hw))
|
||||
return;
|
||||
|
||||
if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) {
|
||||
synaptics_image_sensor_process(psmouse, &hw);
|
||||
return;
|
||||
}
|
||||
|
||||
if (hw.scroll) {
|
||||
priv->scroll += hw.scroll;
|
||||
|
||||
|
@ -586,7 +1022,8 @@ static void synaptics_process_packet(struct psmouse *psmouse)
|
|||
}
|
||||
|
||||
if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c))
|
||||
synaptics_report_semi_mt_data(dev, &hw, &priv->mt, num_fingers);
|
||||
synaptics_report_semi_mt_data(dev, &hw, &priv->agm,
|
||||
num_fingers);
|
||||
|
||||
/* Post events
|
||||
* BTN_TOUCH has to be first as mousedev relies on it when doing
|
||||
|
@ -597,7 +1034,7 @@ static void synaptics_process_packet(struct psmouse *psmouse)
|
|||
|
||||
if (num_fingers > 0) {
|
||||
input_report_abs(dev, ABS_X, hw.x);
|
||||
input_report_abs(dev, ABS_Y, YMAX_NOMINAL + YMIN_NOMINAL - hw.y);
|
||||
input_report_abs(dev, ABS_Y, synaptics_invert_y(hw.y));
|
||||
}
|
||||
input_report_abs(dev, ABS_PRESSURE, hw.z);
|
||||
|
||||
|
@ -605,35 +1042,25 @@ static void synaptics_process_packet(struct psmouse *psmouse)
|
|||
input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
|
||||
|
||||
input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1);
|
||||
input_report_key(dev, BTN_LEFT, hw.left);
|
||||
input_report_key(dev, BTN_RIGHT, hw.right);
|
||||
|
||||
if (SYN_CAP_MULTIFINGER(priv->capabilities)) {
|
||||
input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2);
|
||||
input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3);
|
||||
}
|
||||
|
||||
if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
|
||||
input_report_key(dev, BTN_MIDDLE, hw.middle);
|
||||
|
||||
if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
|
||||
input_report_key(dev, BTN_FORWARD, hw.up);
|
||||
input_report_key(dev, BTN_BACK, hw.down);
|
||||
}
|
||||
|
||||
for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
|
||||
input_report_key(dev, BTN_0 + i, hw.ext_buttons & (1 << i));
|
||||
synaptics_report_buttons(psmouse, &hw);
|
||||
|
||||
input_sync(dev);
|
||||
}
|
||||
|
||||
static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type)
|
||||
static int synaptics_validate_byte(struct psmouse *psmouse,
|
||||
int idx, unsigned char pkt_type)
|
||||
{
|
||||
static const unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 };
|
||||
static const unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 };
|
||||
static const unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 };
|
||||
static const unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
|
||||
static const unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
|
||||
const char *packet = psmouse->packet;
|
||||
|
||||
if (idx < 0 || idx > 4)
|
||||
return 0;
|
||||
|
@ -651,7 +1078,7 @@ static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned cha
|
|||
return (packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx];
|
||||
|
||||
default:
|
||||
printk(KERN_ERR "synaptics: unknown packet type %d\n", pkt_type);
|
||||
psmouse_err(psmouse, "unknown packet type %d\n", pkt_type);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -661,8 +1088,8 @@ static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
if (!synaptics_validate_byte(psmouse->packet, i, SYN_NEWABS_STRICT)) {
|
||||
printk(KERN_INFO "synaptics: using relaxed packet validation\n");
|
||||
if (!synaptics_validate_byte(psmouse, i, SYN_NEWABS_STRICT)) {
|
||||
psmouse_info(psmouse, "using relaxed packet validation\n");
|
||||
return SYN_NEWABS_RELAXED;
|
||||
}
|
||||
|
||||
|
@ -687,46 +1114,56 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
|
|||
return PSMOUSE_FULL_PACKET;
|
||||
}
|
||||
|
||||
return synaptics_validate_byte(psmouse->packet, psmouse->pktcnt - 1, priv->pkt_type) ?
|
||||
return synaptics_validate_byte(psmouse, psmouse->pktcnt - 1, priv->pkt_type) ?
|
||||
PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Driver initialization/cleanup functions
|
||||
****************************************************************************/
|
||||
static void set_abs_position_params(struct input_dev *dev,
|
||||
struct synaptics_data *priv, int x_code,
|
||||
int y_code)
|
||||
{
|
||||
int x_min = priv->x_min ?: XMIN_NOMINAL;
|
||||
int x_max = priv->x_max ?: XMAX_NOMINAL;
|
||||
int y_min = priv->y_min ?: YMIN_NOMINAL;
|
||||
int y_max = priv->y_max ?: YMAX_NOMINAL;
|
||||
int fuzz = SYN_CAP_REDUCED_FILTERING(priv->ext_cap_0c) ?
|
||||
SYN_REDUCED_FILTER_FUZZ : 0;
|
||||
|
||||
input_set_abs_params(dev, x_code, x_min, x_max, fuzz, 0);
|
||||
input_set_abs_params(dev, y_code, y_min, y_max, fuzz, 0);
|
||||
input_abs_set_res(dev, x_code, priv->x_res);
|
||||
input_abs_set_res(dev, y_code, priv->y_res);
|
||||
}
|
||||
|
||||
static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
|
||||
{
|
||||
int i;
|
||||
int fuzz = SYN_CAP_REDUCED_FILTERING(priv->ext_cap_0c) ?
|
||||
SYN_REDUCED_FILTER_FUZZ : 0;
|
||||
|
||||
__set_bit(INPUT_PROP_POINTER, dev->propbit);
|
||||
|
||||
__set_bit(EV_ABS, dev->evbit);
|
||||
input_set_abs_params(dev, ABS_X,
|
||||
priv->x_min ?: XMIN_NOMINAL,
|
||||
priv->x_max ?: XMAX_NOMINAL,
|
||||
fuzz, 0);
|
||||
input_set_abs_params(dev, ABS_Y,
|
||||
priv->y_min ?: YMIN_NOMINAL,
|
||||
priv->y_max ?: YMAX_NOMINAL,
|
||||
fuzz, 0);
|
||||
set_abs_position_params(dev, priv, ABS_X, ABS_Y);
|
||||
input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
|
||||
|
||||
if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) {
|
||||
if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) {
|
||||
input_mt_init_slots(dev, 2);
|
||||
set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
|
||||
ABS_MT_POSITION_Y);
|
||||
/* Image sensors can report per-contact pressure */
|
||||
input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
|
||||
|
||||
/* Image sensors can signal 4 and 5 finger clicks */
|
||||
__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
|
||||
__set_bit(BTN_TOOL_QUINTTAP, dev->keybit);
|
||||
} else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) {
|
||||
/* Non-image sensors with AGM use semi-mt */
|
||||
__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
|
||||
input_mt_init_slots(dev, 2);
|
||||
input_set_abs_params(dev, ABS_MT_POSITION_X,
|
||||
priv->x_min ?: XMIN_NOMINAL,
|
||||
priv->x_max ?: XMAX_NOMINAL,
|
||||
fuzz, 0);
|
||||
input_set_abs_params(dev, ABS_MT_POSITION_Y,
|
||||
priv->y_min ?: YMIN_NOMINAL,
|
||||
priv->y_max ?: YMAX_NOMINAL,
|
||||
fuzz, 0);
|
||||
|
||||
input_abs_set_res(dev, ABS_MT_POSITION_X, priv->x_res);
|
||||
input_abs_set_res(dev, ABS_MT_POSITION_Y, priv->y_res);
|
||||
set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
|
||||
ABS_MT_POSITION_Y);
|
||||
}
|
||||
|
||||
if (SYN_CAP_PALMDETECT(priv->capabilities))
|
||||
|
@ -759,9 +1196,6 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
|
|||
__clear_bit(REL_X, dev->relbit);
|
||||
__clear_bit(REL_Y, dev->relbit);
|
||||
|
||||
input_abs_set_res(dev, ABS_X, priv->x_res);
|
||||
input_abs_set_res(dev, ABS_Y, priv->y_res);
|
||||
|
||||
if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
|
||||
__set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
|
||||
/* Clickpads report only left button */
|
||||
|
@ -793,21 +1227,21 @@ static int synaptics_reconnect(struct psmouse *psmouse)
|
|||
return -1;
|
||||
|
||||
if (retry > 1)
|
||||
printk(KERN_DEBUG "Synaptics reconnected after %d tries\n",
|
||||
retry);
|
||||
psmouse_dbg(psmouse, "reconnected after %d tries\n", retry);
|
||||
|
||||
if (synaptics_query_hardware(psmouse)) {
|
||||
printk(KERN_ERR "Unable to query Synaptics hardware.\n");
|
||||
psmouse_err(psmouse, "Unable to query device.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (synaptics_set_absolute_mode(psmouse)) {
|
||||
printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
|
||||
psmouse_err(psmouse, "Unable to initialize device.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (synaptics_set_advanced_gesture_mode(psmouse)) {
|
||||
printk(KERN_ERR "Advanced gesture mode reconnect failed.\n");
|
||||
psmouse_err(psmouse,
|
||||
"Advanced gesture mode reconnect failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -815,8 +1249,8 @@ static int synaptics_reconnect(struct psmouse *psmouse)
|
|||
old_priv.model_id != priv->model_id ||
|
||||
old_priv.capabilities != priv->capabilities ||
|
||||
old_priv.ext_cap != priv->ext_cap) {
|
||||
printk(KERN_ERR "Synaptics hardware appears to be different: "
|
||||
"id(%ld-%ld), model(%ld-%ld), caps(%lx-%lx), ext(%lx-%lx).\n",
|
||||
psmouse_err(psmouse,
|
||||
"hardware appears to be different: id(%ld-%ld), model(%ld-%ld), caps(%lx-%lx), ext(%lx-%lx).\n",
|
||||
old_priv.identity, priv->identity,
|
||||
old_priv.model_id, priv->model_id,
|
||||
old_priv.capabilities, priv->capabilities,
|
||||
|
@ -901,7 +1335,8 @@ int synaptics_init(struct psmouse *psmouse)
|
|||
* just fine.
|
||||
*/
|
||||
if (broken_olpc_ec) {
|
||||
printk(KERN_INFO "synaptics: OLPC XO detected, not enabling Synaptics protocol.\n");
|
||||
psmouse_info(psmouse,
|
||||
"OLPC XO detected, not enabling Synaptics protocol.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
@ -912,26 +1347,28 @@ int synaptics_init(struct psmouse *psmouse)
|
|||
psmouse_reset(psmouse);
|
||||
|
||||
if (synaptics_query_hardware(psmouse)) {
|
||||
printk(KERN_ERR "Unable to query Synaptics hardware.\n");
|
||||
psmouse_err(psmouse, "Unable to query device.\n");
|
||||
goto init_fail;
|
||||
}
|
||||
|
||||
if (synaptics_set_absolute_mode(psmouse)) {
|
||||
printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
|
||||
psmouse_err(psmouse, "Unable to initialize device.\n");
|
||||
goto init_fail;
|
||||
}
|
||||
|
||||
if (synaptics_set_advanced_gesture_mode(psmouse)) {
|
||||
printk(KERN_ERR "Advanced gesture mode init failed.\n");
|
||||
psmouse_err(psmouse, "Advanced gesture mode init failed.\n");
|
||||
goto init_fail;
|
||||
}
|
||||
|
||||
priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
|
||||
|
||||
printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx\n",
|
||||
psmouse_info(psmouse,
|
||||
"Touchpad model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx\n",
|
||||
SYN_ID_MODEL(priv->identity),
|
||||
SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity),
|
||||
priv->model_id, priv->capabilities, priv->ext_cap, priv->ext_cap_0c);
|
||||
priv->model_id,
|
||||
priv->capabilities, priv->ext_cap, priv->ext_cap_0c);
|
||||
|
||||
set_input_params(psmouse->dev, priv);
|
||||
|
||||
|
@ -963,7 +1400,8 @@ int synaptics_init(struct psmouse *psmouse)
|
|||
* the same rate as a standard PS/2 mouse).
|
||||
*/
|
||||
if (psmouse->rate >= 80 && impaired_toshiba_kbc) {
|
||||
printk(KERN_INFO "synaptics: Toshiba %s detected, limiting rate to 40pps.\n",
|
||||
psmouse_info(psmouse,
|
||||
"Toshiba %s detected, limiting rate to 40pps.\n",
|
||||
dmi_get_system_info(DMI_PRODUCT_NAME));
|
||||
psmouse->rate = 40;
|
||||
}
|
||||
|
|
|
@ -74,6 +74,8 @@
|
|||
* 2 0x04 reduced filtering firmware does less filtering on
|
||||
* position data, driver should watch
|
||||
* for noise.
|
||||
* 2 0x08 image sensor image sensor tracks 5 fingers, but only
|
||||
* reports 2.
|
||||
* 2 0x20 report min query 0x0f gives min coord reported
|
||||
*/
|
||||
#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */
|
||||
|
@ -82,6 +84,7 @@
|
|||
#define SYN_CAP_MIN_DIMENSIONS(ex0c) ((ex0c) & 0x002000)
|
||||
#define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & 0x080000)
|
||||
#define SYN_CAP_REDUCED_FILTERING(ex0c) ((ex0c) & 0x000400)
|
||||
#define SYN_CAP_IMAGE_SENSOR(ex0c) ((ex0c) & 0x000800)
|
||||
|
||||
/* synaptics modes query bits */
|
||||
#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
|
||||
|
@ -111,10 +114,19 @@
|
|||
/* amount to fuzz position data when touchpad reports reduced filtering */
|
||||
#define SYN_REDUCED_FILTER_FUZZ 8
|
||||
|
||||
/*
|
||||
* A structure to describe which internal touchpad finger slots are being
|
||||
* reported in raw packets.
|
||||
*/
|
||||
struct synaptics_mt_state {
|
||||
int count; /* num fingers being tracked */
|
||||
int sgm; /* which slot is reported by sgm pkt */
|
||||
int agm; /* which slot is reported by agm pkt*/
|
||||
};
|
||||
|
||||
/*
|
||||
* A structure to describe the state of the touchpad hardware (buttons and pad)
|
||||
*/
|
||||
|
||||
struct synaptics_hw_state {
|
||||
int x;
|
||||
int y;
|
||||
|
@ -127,6 +139,9 @@ struct synaptics_hw_state {
|
|||
unsigned int down:1;
|
||||
unsigned char ext_buttons;
|
||||
signed char scroll;
|
||||
|
||||
/* As reported in last AGM-CONTACT packets */
|
||||
struct synaptics_mt_state mt_state;
|
||||
};
|
||||
|
||||
struct synaptics_data {
|
||||
|
@ -146,7 +161,15 @@ struct synaptics_data {
|
|||
|
||||
struct serio *pt_port; /* Pass-through serio port */
|
||||
|
||||
struct synaptics_hw_state mt; /* current gesture packet */
|
||||
struct synaptics_mt_state mt_state; /* Current mt finger state */
|
||||
bool mt_state_lost; /* mt_state may be incorrect */
|
||||
|
||||
/*
|
||||
* Last received Advanced Gesture Mode (AGM) packet. An AGM packet
|
||||
* contains position data for a second contact, at half resolution.
|
||||
*/
|
||||
struct synaptics_hw_state agm;
|
||||
bool agm_pending; /* new AGM packet received */
|
||||
};
|
||||
|
||||
void synaptics_module_init(void);
|
||||
|
|
|
@ -570,7 +570,7 @@ static int __devinit synaptics_i2c_probe(struct i2c_client *client,
|
|||
"Requesting IRQ: %d\n", touch->client->irq);
|
||||
|
||||
ret = request_irq(touch->client->irq, synaptics_i2c_irq,
|
||||
IRQF_DISABLED|IRQ_TYPE_EDGE_FALLING,
|
||||
IRQ_TYPE_EDGE_FALLING,
|
||||
DRIVER_NAME, touch);
|
||||
if (ret) {
|
||||
dev_warn(&touch->client->dev,
|
||||
|
@ -619,7 +619,7 @@ static int __devexit synaptics_i2c_remove(struct i2c_client *client)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int synaptics_i2c_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kref.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/poll.h>
|
||||
|
@ -33,15 +34,16 @@ struct serio_raw {
|
|||
unsigned int tail, head;
|
||||
|
||||
char name[16];
|
||||
unsigned int refcnt;
|
||||
struct kref kref;
|
||||
struct serio *serio;
|
||||
struct miscdevice dev;
|
||||
wait_queue_head_t wait;
|
||||
struct list_head list;
|
||||
struct list_head client_list;
|
||||
struct list_head node;
|
||||
bool dead;
|
||||
};
|
||||
|
||||
struct serio_raw_list {
|
||||
struct serio_raw_client {
|
||||
struct fasync_struct *fasync;
|
||||
struct serio_raw *serio_raw;
|
||||
struct list_head node;
|
||||
|
@ -49,7 +51,6 @@ struct serio_raw_list {
|
|||
|
||||
static DEFINE_MUTEX(serio_raw_mutex);
|
||||
static LIST_HEAD(serio_raw_list);
|
||||
static unsigned int serio_raw_no;
|
||||
|
||||
/*********************************************************************
|
||||
* Interface with userspace (file operations) *
|
||||
|
@ -57,9 +58,9 @@ static unsigned int serio_raw_no;
|
|||
|
||||
static int serio_raw_fasync(int fd, struct file *file, int on)
|
||||
{
|
||||
struct serio_raw_list *list = file->private_data;
|
||||
struct serio_raw_client *client = file->private_data;
|
||||
|
||||
return fasync_helper(fd, file, on, &list->fasync);
|
||||
return fasync_helper(fd, file, on, &client->fasync);
|
||||
}
|
||||
|
||||
static struct serio_raw *serio_raw_locate(int minor)
|
||||
|
@ -77,8 +78,8 @@ static struct serio_raw *serio_raw_locate(int minor)
|
|||
static int serio_raw_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct serio_raw *serio_raw;
|
||||
struct serio_raw_list *list;
|
||||
int retval = 0;
|
||||
struct serio_raw_client *client;
|
||||
int retval;
|
||||
|
||||
retval = mutex_lock_interruptible(&serio_raw_mutex);
|
||||
if (retval)
|
||||
|
@ -90,60 +91,61 @@ static int serio_raw_open(struct inode *inode, struct file *file)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (!serio_raw->serio) {
|
||||
if (serio_raw->dead) {
|
||||
retval = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
list = kzalloc(sizeof(struct serio_raw_list), GFP_KERNEL);
|
||||
if (!list) {
|
||||
client = kzalloc(sizeof(struct serio_raw_client), GFP_KERNEL);
|
||||
if (!client) {
|
||||
retval = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
list->serio_raw = serio_raw;
|
||||
file->private_data = list;
|
||||
client->serio_raw = serio_raw;
|
||||
file->private_data = client;
|
||||
|
||||
serio_raw->refcnt++;
|
||||
list_add_tail(&list->node, &serio_raw->list);
|
||||
kref_get(&serio_raw->kref);
|
||||
|
||||
serio_pause_rx(serio_raw->serio);
|
||||
list_add_tail(&client->node, &serio_raw->client_list);
|
||||
serio_continue_rx(serio_raw->serio);
|
||||
|
||||
out:
|
||||
mutex_unlock(&serio_raw_mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int serio_raw_cleanup(struct serio_raw *serio_raw)
|
||||
static void serio_raw_free(struct kref *kref)
|
||||
{
|
||||
if (--serio_raw->refcnt == 0) {
|
||||
misc_deregister(&serio_raw->dev);
|
||||
list_del_init(&serio_raw->node);
|
||||
struct serio_raw *serio_raw =
|
||||
container_of(kref, struct serio_raw, kref);
|
||||
|
||||
put_device(&serio_raw->serio->dev);
|
||||
kfree(serio_raw);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serio_raw_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct serio_raw_list *list = file->private_data;
|
||||
struct serio_raw *serio_raw = list->serio_raw;
|
||||
struct serio_raw_client *client = file->private_data;
|
||||
struct serio_raw *serio_raw = client->serio_raw;
|
||||
|
||||
mutex_lock(&serio_raw_mutex);
|
||||
serio_pause_rx(serio_raw->serio);
|
||||
list_del(&client->node);
|
||||
serio_continue_rx(serio_raw->serio);
|
||||
|
||||
serio_raw_cleanup(serio_raw);
|
||||
kfree(client);
|
||||
|
||||
kref_put(&serio_raw->kref, serio_raw_free);
|
||||
|
||||
mutex_unlock(&serio_raw_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c)
|
||||
static bool serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c)
|
||||
{
|
||||
unsigned long flags;
|
||||
int empty;
|
||||
bool empty;
|
||||
|
||||
spin_lock_irqsave(&serio_raw->serio->lock, flags);
|
||||
serio_pause_rx(serio_raw->serio);
|
||||
|
||||
empty = serio_raw->head == serio_raw->tail;
|
||||
if (!empty) {
|
||||
|
@ -151,30 +153,31 @@ static int serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c)
|
|||
serio_raw->tail = (serio_raw->tail + 1) % SERIO_RAW_QUEUE_LEN;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&serio_raw->serio->lock, flags);
|
||||
serio_continue_rx(serio_raw->serio);
|
||||
|
||||
return !empty;
|
||||
}
|
||||
|
||||
static ssize_t serio_raw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
|
||||
static ssize_t serio_raw_read(struct file *file, char __user *buffer,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct serio_raw_list *list = file->private_data;
|
||||
struct serio_raw *serio_raw = list->serio_raw;
|
||||
struct serio_raw_client *client = file->private_data;
|
||||
struct serio_raw *serio_raw = client->serio_raw;
|
||||
char uninitialized_var(c);
|
||||
ssize_t retval = 0;
|
||||
|
||||
if (!serio_raw->serio)
|
||||
if (serio_raw->dead)
|
||||
return -ENODEV;
|
||||
|
||||
if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK))
|
||||
return -EAGAIN;
|
||||
|
||||
retval = wait_event_interruptible(list->serio_raw->wait,
|
||||
serio_raw->head != serio_raw->tail || !serio_raw->serio);
|
||||
retval = wait_event_interruptible(serio_raw->wait,
|
||||
serio_raw->head != serio_raw->tail || serio_raw->dead);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (!serio_raw->serio)
|
||||
if (serio_raw->dead)
|
||||
return -ENODEV;
|
||||
|
||||
while (retval < count && serio_raw_fetch_byte(serio_raw, &c)) {
|
||||
|
@ -186,9 +189,11 @@ static ssize_t serio_raw_read(struct file *file, char __user *buffer, size_t cou
|
|||
return retval;
|
||||
}
|
||||
|
||||
static ssize_t serio_raw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
|
||||
static ssize_t serio_raw_write(struct file *file, const char __user *buffer,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct serio_raw_list *list = file->private_data;
|
||||
struct serio_raw_client *client = file->private_data;
|
||||
struct serio_raw *serio_raw = client->serio_raw;
|
||||
ssize_t written = 0;
|
||||
int retval;
|
||||
unsigned char c;
|
||||
|
@ -197,7 +202,7 @@ static ssize_t serio_raw_write(struct file *file, const char __user *buffer, siz
|
|||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (!list->serio_raw->serio) {
|
||||
if (serio_raw->dead) {
|
||||
retval = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
@ -210,7 +215,7 @@ static ssize_t serio_raw_write(struct file *file, const char __user *buffer, siz
|
|||
retval = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
if (serio_write(list->serio_raw->serio, c)) {
|
||||
if (serio_write(serio_raw->serio, c)) {
|
||||
retval = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
@ -224,11 +229,14 @@ static ssize_t serio_raw_write(struct file *file, const char __user *buffer, siz
|
|||
|
||||
static unsigned int serio_raw_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
struct serio_raw_list *list = file->private_data;
|
||||
struct serio_raw_client *client = file->private_data;
|
||||
struct serio_raw *serio_raw = client->serio_raw;
|
||||
unsigned int mask;
|
||||
|
||||
poll_wait(file, &list->serio_raw->wait, wait);
|
||||
poll_wait(file, &serio_raw->wait, wait);
|
||||
|
||||
if (list->serio_raw->head != list->serio_raw->tail)
|
||||
mask = serio_raw->dead ? POLLHUP | POLLERR : POLLOUT | POLLWRNORM;
|
||||
if (serio_raw->head != serio_raw->tail)
|
||||
return POLLIN | POLLRDNORM;
|
||||
|
||||
return 0;
|
||||
|
@ -254,16 +262,16 @@ static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data,
|
|||
unsigned int dfl)
|
||||
{
|
||||
struct serio_raw *serio_raw = serio_get_drvdata(serio);
|
||||
struct serio_raw_list *list;
|
||||
struct serio_raw_client *client;
|
||||
unsigned int head = serio_raw->head;
|
||||
|
||||
/* we are holding serio->lock here so we are prootected */
|
||||
/* we are holding serio->lock here so we are protected */
|
||||
serio_raw->queue[head] = data;
|
||||
head = (head + 1) % SERIO_RAW_QUEUE_LEN;
|
||||
if (likely(head != serio_raw->tail)) {
|
||||
serio_raw->head = head;
|
||||
list_for_each_entry(list, &serio_raw->list, node)
|
||||
kill_fasync(&list->fasync, SIGIO, POLL_IN);
|
||||
list_for_each_entry(client, &serio_raw->client_list, node)
|
||||
kill_fasync(&client->fasync, SIGIO, POLL_IN);
|
||||
wake_up_interruptible(&serio_raw->wait);
|
||||
}
|
||||
|
||||
|
@ -272,29 +280,37 @@ static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data,
|
|||
|
||||
static int serio_raw_connect(struct serio *serio, struct serio_driver *drv)
|
||||
{
|
||||
static atomic_t serio_raw_no = ATOMIC_INIT(0);
|
||||
struct serio_raw *serio_raw;
|
||||
int err;
|
||||
|
||||
if (!(serio_raw = kzalloc(sizeof(struct serio_raw), GFP_KERNEL))) {
|
||||
printk(KERN_ERR "serio_raw.c: can't allocate memory for a device\n");
|
||||
serio_raw = kzalloc(sizeof(struct serio_raw), GFP_KERNEL);
|
||||
if (!serio_raw) {
|
||||
dev_dbg(&serio->dev, "can't allocate memory for a device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mutex_lock(&serio_raw_mutex);
|
||||
|
||||
snprintf(serio_raw->name, sizeof(serio_raw->name), "serio_raw%d", serio_raw_no++);
|
||||
serio_raw->refcnt = 1;
|
||||
serio_raw->serio = serio;
|
||||
INIT_LIST_HEAD(&serio_raw->list);
|
||||
snprintf(serio_raw->name, sizeof(serio_raw->name),
|
||||
"serio_raw%ld", (long)atomic_inc_return(&serio_raw_no) - 1);
|
||||
kref_init(&serio_raw->kref);
|
||||
INIT_LIST_HEAD(&serio_raw->client_list);
|
||||
init_waitqueue_head(&serio_raw->wait);
|
||||
|
||||
serio_raw->serio = serio;
|
||||
get_device(&serio->dev);
|
||||
|
||||
serio_set_drvdata(serio, serio_raw);
|
||||
|
||||
err = serio_open(serio, drv);
|
||||
if (err)
|
||||
goto out_free;
|
||||
goto err_free;
|
||||
|
||||
err = mutex_lock_killable(&serio_raw_mutex);
|
||||
if (err)
|
||||
goto err_close;
|
||||
|
||||
list_add_tail(&serio_raw->node, &serio_raw_list);
|
||||
mutex_unlock(&serio_raw_mutex);
|
||||
|
||||
serio_raw->dev.minor = PSMOUSE_MINOR;
|
||||
serio_raw->dev.name = serio_raw->name;
|
||||
|
@ -308,23 +324,23 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv)
|
|||
}
|
||||
|
||||
if (err) {
|
||||
printk(KERN_INFO "serio_raw: failed to register raw access device for %s\n",
|
||||
dev_err(&serio->dev,
|
||||
"failed to register raw access device for %s\n",
|
||||
serio->phys);
|
||||
goto out_close;
|
||||
goto err_unlink;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "serio_raw: raw access enabled on %s (%s, minor %d)\n",
|
||||
dev_info(&serio->dev, "raw access enabled on %s (%s, minor %d)\n",
|
||||
serio->phys, serio_raw->name, serio_raw->dev.minor);
|
||||
goto out;
|
||||
return 0;
|
||||
|
||||
out_close:
|
||||
serio_close(serio);
|
||||
err_unlink:
|
||||
list_del_init(&serio_raw->node);
|
||||
out_free:
|
||||
err_close:
|
||||
serio_close(serio);
|
||||
err_free:
|
||||
serio_set_drvdata(serio, NULL);
|
||||
kfree(serio_raw);
|
||||
out:
|
||||
mutex_unlock(&serio_raw_mutex);
|
||||
kref_put(&serio_raw->kref, serio_raw_free);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -334,7 +350,8 @@ static int serio_raw_reconnect(struct serio *serio)
|
|||
struct serio_driver *drv = serio->drv;
|
||||
|
||||
if (!drv || !serio_raw) {
|
||||
printk(KERN_DEBUG "serio_raw: reconnect request, but serio is disconnected, ignoring...\n");
|
||||
dev_dbg(&serio->dev,
|
||||
"reconnect request, but serio is disconnected, ignoring...\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -345,22 +362,40 @@ static int serio_raw_reconnect(struct serio *serio)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wake up users waiting for IO so they can disconnect from
|
||||
* dead device.
|
||||
*/
|
||||
static void serio_raw_hangup(struct serio_raw *serio_raw)
|
||||
{
|
||||
struct serio_raw_client *client;
|
||||
|
||||
serio_pause_rx(serio_raw->serio);
|
||||
list_for_each_entry(client, &serio_raw->client_list, node)
|
||||
kill_fasync(&client->fasync, SIGIO, POLL_HUP);
|
||||
serio_continue_rx(serio_raw->serio);
|
||||
|
||||
wake_up_interruptible(&serio_raw->wait);
|
||||
}
|
||||
|
||||
|
||||
static void serio_raw_disconnect(struct serio *serio)
|
||||
{
|
||||
struct serio_raw *serio_raw;
|
||||
struct serio_raw *serio_raw = serio_get_drvdata(serio);
|
||||
|
||||
misc_deregister(&serio_raw->dev);
|
||||
|
||||
mutex_lock(&serio_raw_mutex);
|
||||
serio_raw->dead = true;
|
||||
list_del_init(&serio_raw->node);
|
||||
mutex_unlock(&serio_raw_mutex);
|
||||
|
||||
serio_raw = serio_get_drvdata(serio);
|
||||
serio_raw_hangup(serio_raw);
|
||||
|
||||
serio_close(serio);
|
||||
kref_put(&serio_raw->kref, serio_raw_free);
|
||||
|
||||
serio_set_drvdata(serio, NULL);
|
||||
|
||||
serio_raw->serio = NULL;
|
||||
if (!serio_raw_cleanup(serio_raw))
|
||||
wake_up_interruptible(&serio_raw->wait);
|
||||
|
||||
mutex_unlock(&serio_raw_mutex);
|
||||
}
|
||||
|
||||
static struct serio_device_id serio_raw_serio_ids[] = {
|
||||
|
@ -391,7 +426,7 @@ static struct serio_driver serio_raw_drv = {
|
|||
.connect = serio_raw_connect,
|
||||
.reconnect = serio_raw_reconnect,
|
||||
.disconnect = serio_raw_disconnect,
|
||||
.manual_bind = 1,
|
||||
.manual_bind = true,
|
||||
};
|
||||
|
||||
static int __init serio_raw_init(void)
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
* Copyright (c) 2000 Daniel Egger <egger@suse.de>
|
||||
* Copyright (c) 2001 Frederic Lepied <flepied@mandrakesoft.com>
|
||||
* Copyright (c) 2004 Panagiotis Issaris <panagiotis.issaris@mech.kuleuven.ac.be>
|
||||
* Copyright (c) 2002-2009 Ping Cheng <pingc@wacom.com>
|
||||
* Copyright (c) 2002-2011 Ping Cheng <pingc@wacom.com>
|
||||
*
|
||||
* ChangeLog:
|
||||
* v0.1 (vp) - Initial release
|
||||
|
@ -93,7 +93,7 @@
|
|||
/*
|
||||
* Version Information
|
||||
*/
|
||||
#define DRIVER_VERSION "v1.52"
|
||||
#define DRIVER_VERSION "v1.53"
|
||||
#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
|
||||
#define DRIVER_DESC "USB Wacom tablet driver"
|
||||
#define DRIVER_LICENSE "GPL"
|
||||
|
@ -114,6 +114,12 @@ struct wacom {
|
|||
struct mutex lock;
|
||||
bool open;
|
||||
char phys[32];
|
||||
struct wacom_led {
|
||||
u8 select[2]; /* status led selector (0..3) */
|
||||
u8 llv; /* status led brightness no button (1..127) */
|
||||
u8 hlv; /* status led brightness button pressed (1..127) */
|
||||
u8 img_lum; /* OLED matrix display brightness */
|
||||
} led;
|
||||
};
|
||||
|
||||
extern const struct usb_device_id wacom_ids[];
|
||||
|
|
|
@ -48,27 +48,49 @@ struct hid_descriptor {
|
|||
/* defines to get/set USB message */
|
||||
#define USB_REQ_GET_REPORT 0x01
|
||||
#define USB_REQ_SET_REPORT 0x09
|
||||
|
||||
#define WAC_HID_FEATURE_REPORT 0x03
|
||||
#define WAC_MSG_RETRIES 5
|
||||
|
||||
static int usb_get_report(struct usb_interface *intf, unsigned char type,
|
||||
unsigned char id, void *buf, int size)
|
||||
#define WAC_CMD_LED_CONTROL 0x20
|
||||
#define WAC_CMD_ICON_START 0x21
|
||||
#define WAC_CMD_ICON_XFER 0x23
|
||||
#define WAC_CMD_RETRIES 10
|
||||
|
||||
static int wacom_get_report(struct usb_interface *intf, u8 type, u8 id,
|
||||
void *buf, size_t size, unsigned int retries)
|
||||
{
|
||||
return usb_control_msg(interface_to_usbdev(intf),
|
||||
usb_rcvctrlpipe(interface_to_usbdev(intf), 0),
|
||||
USB_REQ_GET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
|
||||
(type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber,
|
||||
struct usb_device *dev = interface_to_usbdev(intf);
|
||||
int retval;
|
||||
|
||||
do {
|
||||
retval = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
|
||||
USB_REQ_GET_REPORT,
|
||||
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
|
||||
(type << 8) + id,
|
||||
intf->altsetting[0].desc.bInterfaceNumber,
|
||||
buf, size, 100);
|
||||
} while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int usb_set_report(struct usb_interface *intf, unsigned char type,
|
||||
unsigned char id, void *buf, int size)
|
||||
static int wacom_set_report(struct usb_interface *intf, u8 type, u8 id,
|
||||
void *buf, size_t size, unsigned int retries)
|
||||
{
|
||||
return usb_control_msg(interface_to_usbdev(intf),
|
||||
usb_sndctrlpipe(interface_to_usbdev(intf), 0),
|
||||
USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
|
||||
(type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber,
|
||||
struct usb_device *dev = interface_to_usbdev(intf);
|
||||
int retval;
|
||||
|
||||
do {
|
||||
retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
|
||||
USB_REQ_SET_REPORT,
|
||||
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
|
||||
(type << 8) + id,
|
||||
intf->altsetting[0].desc.bInterfaceNumber,
|
||||
buf, size, 1000);
|
||||
} while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void wacom_sys_irq(struct urb *urb)
|
||||
|
@ -319,23 +341,23 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
|
|||
rep_data[2] = 0;
|
||||
rep_data[3] = 0;
|
||||
report_id = 3;
|
||||
error = usb_set_report(intf, WAC_HID_FEATURE_REPORT,
|
||||
report_id, rep_data, 4);
|
||||
error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT,
|
||||
report_id, rep_data, 4, 1);
|
||||
if (error >= 0)
|
||||
error = usb_get_report(intf,
|
||||
WAC_HID_FEATURE_REPORT, report_id,
|
||||
rep_data, 4);
|
||||
error = wacom_get_report(intf,
|
||||
WAC_HID_FEATURE_REPORT,
|
||||
report_id, rep_data, 4, 1);
|
||||
} while ((error < 0 || rep_data[1] != 4) && limit++ < WAC_MSG_RETRIES);
|
||||
} else if (features->type != TABLETPC) {
|
||||
do {
|
||||
rep_data[0] = 2;
|
||||
rep_data[1] = 2;
|
||||
error = usb_set_report(intf, WAC_HID_FEATURE_REPORT,
|
||||
report_id, rep_data, 2);
|
||||
error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT,
|
||||
report_id, rep_data, 2, 1);
|
||||
if (error >= 0)
|
||||
error = usb_get_report(intf,
|
||||
WAC_HID_FEATURE_REPORT, report_id,
|
||||
rep_data, 2);
|
||||
error = wacom_get_report(intf,
|
||||
WAC_HID_FEATURE_REPORT,
|
||||
report_id, rep_data, 2, 1);
|
||||
} while ((error < 0 || rep_data[1] != 2) && limit++ < WAC_MSG_RETRIES);
|
||||
}
|
||||
|
||||
|
@ -454,6 +476,275 @@ static void wacom_remove_shared_data(struct wacom_wac *wacom)
|
|||
}
|
||||
}
|
||||
|
||||
static int wacom_led_control(struct wacom *wacom)
|
||||
{
|
||||
unsigned char *buf;
|
||||
int retval, led = 0;
|
||||
|
||||
buf = kzalloc(9, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
if (wacom->wacom_wac.features.type == WACOM_21UX2)
|
||||
led = (wacom->led.select[1] << 4) | 0x40;
|
||||
|
||||
led |= wacom->led.select[0] | 0x4;
|
||||
|
||||
buf[0] = WAC_CMD_LED_CONTROL;
|
||||
buf[1] = led;
|
||||
buf[2] = wacom->led.llv;
|
||||
buf[3] = wacom->led.hlv;
|
||||
buf[4] = wacom->led.img_lum;
|
||||
|
||||
retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_LED_CONTROL,
|
||||
buf, 9, WAC_CMD_RETRIES);
|
||||
kfree(buf);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int wacom_led_putimage(struct wacom *wacom, int button_id, const void *img)
|
||||
{
|
||||
unsigned char *buf;
|
||||
int i, retval;
|
||||
|
||||
buf = kzalloc(259, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Send 'start' command */
|
||||
buf[0] = WAC_CMD_ICON_START;
|
||||
buf[1] = 1;
|
||||
retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_ICON_START,
|
||||
buf, 2, WAC_CMD_RETRIES);
|
||||
if (retval < 0)
|
||||
goto out;
|
||||
|
||||
buf[0] = WAC_CMD_ICON_XFER;
|
||||
buf[1] = button_id & 0x07;
|
||||
for (i = 0; i < 4; i++) {
|
||||
buf[2] = i;
|
||||
memcpy(buf + 3, img + i * 256, 256);
|
||||
|
||||
retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_ICON_XFER,
|
||||
buf, 259, WAC_CMD_RETRIES);
|
||||
if (retval < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Send 'stop' */
|
||||
buf[0] = WAC_CMD_ICON_START;
|
||||
buf[1] = 0;
|
||||
wacom_set_report(wacom->intf, 0x03, WAC_CMD_ICON_START,
|
||||
buf, 2, WAC_CMD_RETRIES);
|
||||
|
||||
out:
|
||||
kfree(buf);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static ssize_t wacom_led_select_store(struct device *dev, int set_id,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct wacom *wacom = dev_get_drvdata(dev);
|
||||
unsigned int id;
|
||||
int err;
|
||||
|
||||
err = kstrtouint(buf, 10, &id);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&wacom->lock);
|
||||
|
||||
wacom->led.select[set_id] = id & 0x3;
|
||||
err = wacom_led_control(wacom);
|
||||
|
||||
mutex_unlock(&wacom->lock);
|
||||
|
||||
return err < 0 ? err : count;
|
||||
}
|
||||
|
||||
#define DEVICE_LED_SELECT_ATTR(SET_ID) \
|
||||
static ssize_t wacom_led##SET_ID##_select_store(struct device *dev, \
|
||||
struct device_attribute *attr, const char *buf, size_t count) \
|
||||
{ \
|
||||
return wacom_led_select_store(dev, SET_ID, buf, count); \
|
||||
} \
|
||||
static ssize_t wacom_led##SET_ID##_select_show(struct device *dev, \
|
||||
struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct wacom *wacom = dev_get_drvdata(dev); \
|
||||
return snprintf(buf, 2, "%d\n", wacom->led.select[SET_ID]); \
|
||||
} \
|
||||
static DEVICE_ATTR(status_led##SET_ID##_select, S_IWUSR | S_IRUSR, \
|
||||
wacom_led##SET_ID##_select_show, \
|
||||
wacom_led##SET_ID##_select_store)
|
||||
|
||||
DEVICE_LED_SELECT_ATTR(0);
|
||||
DEVICE_LED_SELECT_ATTR(1);
|
||||
|
||||
static ssize_t wacom_luminance_store(struct wacom *wacom, u8 *dest,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int value;
|
||||
int err;
|
||||
|
||||
err = kstrtouint(buf, 10, &value);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&wacom->lock);
|
||||
|
||||
*dest = value & 0x7f;
|
||||
err = wacom_led_control(wacom);
|
||||
|
||||
mutex_unlock(&wacom->lock);
|
||||
|
||||
return err < 0 ? err : count;
|
||||
}
|
||||
|
||||
#define DEVICE_LUMINANCE_ATTR(name, field) \
|
||||
static ssize_t wacom_##name##_luminance_store(struct device *dev, \
|
||||
struct device_attribute *attr, const char *buf, size_t count) \
|
||||
{ \
|
||||
struct wacom *wacom = dev_get_drvdata(dev); \
|
||||
\
|
||||
return wacom_luminance_store(wacom, &wacom->led.field, \
|
||||
buf, count); \
|
||||
} \
|
||||
static DEVICE_ATTR(name##_luminance, S_IWUSR, \
|
||||
NULL, wacom_##name##_luminance_store)
|
||||
|
||||
DEVICE_LUMINANCE_ATTR(status0, llv);
|
||||
DEVICE_LUMINANCE_ATTR(status1, hlv);
|
||||
DEVICE_LUMINANCE_ATTR(buttons, img_lum);
|
||||
|
||||
static ssize_t wacom_button_image_store(struct device *dev, int button_id,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct wacom *wacom = dev_get_drvdata(dev);
|
||||
int err;
|
||||
|
||||
if (count != 1024)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&wacom->lock);
|
||||
|
||||
err = wacom_led_putimage(wacom, button_id, buf);
|
||||
|
||||
mutex_unlock(&wacom->lock);
|
||||
|
||||
return err < 0 ? err : count;
|
||||
}
|
||||
|
||||
#define DEVICE_BTNIMG_ATTR(BUTTON_ID) \
|
||||
static ssize_t wacom_btnimg##BUTTON_ID##_store(struct device *dev, \
|
||||
struct device_attribute *attr, const char *buf, size_t count) \
|
||||
{ \
|
||||
return wacom_button_image_store(dev, BUTTON_ID, buf, count); \
|
||||
} \
|
||||
static DEVICE_ATTR(button##BUTTON_ID##_rawimg, S_IWUSR, \
|
||||
NULL, wacom_btnimg##BUTTON_ID##_store)
|
||||
|
||||
DEVICE_BTNIMG_ATTR(0);
|
||||
DEVICE_BTNIMG_ATTR(1);
|
||||
DEVICE_BTNIMG_ATTR(2);
|
||||
DEVICE_BTNIMG_ATTR(3);
|
||||
DEVICE_BTNIMG_ATTR(4);
|
||||
DEVICE_BTNIMG_ATTR(5);
|
||||
DEVICE_BTNIMG_ATTR(6);
|
||||
DEVICE_BTNIMG_ATTR(7);
|
||||
|
||||
static struct attribute *cintiq_led_attrs[] = {
|
||||
&dev_attr_status_led0_select.attr,
|
||||
&dev_attr_status_led1_select.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group cintiq_led_attr_group = {
|
||||
.name = "wacom_led",
|
||||
.attrs = cintiq_led_attrs,
|
||||
};
|
||||
|
||||
static struct attribute *intuos4_led_attrs[] = {
|
||||
&dev_attr_status0_luminance.attr,
|
||||
&dev_attr_status1_luminance.attr,
|
||||
&dev_attr_status_led0_select.attr,
|
||||
&dev_attr_buttons_luminance.attr,
|
||||
&dev_attr_button0_rawimg.attr,
|
||||
&dev_attr_button1_rawimg.attr,
|
||||
&dev_attr_button2_rawimg.attr,
|
||||
&dev_attr_button3_rawimg.attr,
|
||||
&dev_attr_button4_rawimg.attr,
|
||||
&dev_attr_button5_rawimg.attr,
|
||||
&dev_attr_button6_rawimg.attr,
|
||||
&dev_attr_button7_rawimg.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group intuos4_led_attr_group = {
|
||||
.name = "wacom_led",
|
||||
.attrs = intuos4_led_attrs,
|
||||
};
|
||||
|
||||
static int wacom_initialize_leds(struct wacom *wacom)
|
||||
{
|
||||
int error;
|
||||
|
||||
/* Initialize default values */
|
||||
switch (wacom->wacom_wac.features.type) {
|
||||
case INTUOS4:
|
||||
case INTUOS4L:
|
||||
wacom->led.select[0] = 0;
|
||||
wacom->led.select[1] = 0;
|
||||
wacom->led.llv = 10;
|
||||
wacom->led.hlv = 20;
|
||||
wacom->led.img_lum = 10;
|
||||
error = sysfs_create_group(&wacom->intf->dev.kobj,
|
||||
&intuos4_led_attr_group);
|
||||
break;
|
||||
|
||||
case WACOM_21UX2:
|
||||
wacom->led.select[0] = 0;
|
||||
wacom->led.select[1] = 0;
|
||||
wacom->led.llv = 0;
|
||||
wacom->led.hlv = 0;
|
||||
wacom->led.img_lum = 0;
|
||||
|
||||
error = sysfs_create_group(&wacom->intf->dev.kobj,
|
||||
&cintiq_led_attr_group);
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
dev_err(&wacom->intf->dev,
|
||||
"cannot create sysfs group err: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
wacom_led_control(wacom);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wacom_destroy_leds(struct wacom *wacom)
|
||||
{
|
||||
switch (wacom->wacom_wac.features.type) {
|
||||
case INTUOS4:
|
||||
case INTUOS4L:
|
||||
sysfs_remove_group(&wacom->intf->dev.kobj,
|
||||
&intuos4_led_attr_group);
|
||||
break;
|
||||
|
||||
case WACOM_21UX2:
|
||||
sysfs_remove_group(&wacom->intf->dev.kobj,
|
||||
&cintiq_led_attr_group);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *dev = interface_to_usbdev(intf);
|
||||
|
@ -542,16 +833,21 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
|
|||
wacom->irq->transfer_dma = wacom->data_dma;
|
||||
wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
|
||||
error = input_register_device(input_dev);
|
||||
error = wacom_initialize_leds(wacom);
|
||||
if (error)
|
||||
goto fail4;
|
||||
|
||||
error = input_register_device(input_dev);
|
||||
if (error)
|
||||
goto fail5;
|
||||
|
||||
/* Note that if query fails it is not a hard failure */
|
||||
wacom_query_tablet_data(intf, features);
|
||||
|
||||
usb_set_intfdata(intf, wacom);
|
||||
return 0;
|
||||
|
||||
fail5: wacom_destroy_leds(wacom);
|
||||
fail4: wacom_remove_shared_data(wacom_wac);
|
||||
fail3: usb_free_urb(wacom->irq);
|
||||
fail2: usb_free_coherent(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma);
|
||||
|
@ -568,6 +864,7 @@ static void wacom_disconnect(struct usb_interface *intf)
|
|||
|
||||
usb_kill_urb(wacom->irq);
|
||||
input_unregister_device(wacom->wacom_wac.input);
|
||||
wacom_destroy_leds(wacom);
|
||||
usb_free_urb(wacom->irq);
|
||||
usb_free_coherent(interface_to_usbdev(intf), WACOM_PKGLEN_MAX,
|
||||
wacom->wacom_wac.data, wacom->data_dma);
|
||||
|
@ -590,17 +887,16 @@ static int wacom_resume(struct usb_interface *intf)
|
|||
{
|
||||
struct wacom *wacom = usb_get_intfdata(intf);
|
||||
struct wacom_features *features = &wacom->wacom_wac.features;
|
||||
int rv;
|
||||
int rv = 0;
|
||||
|
||||
mutex_lock(&wacom->lock);
|
||||
|
||||
/* switch to wacom mode first */
|
||||
wacom_query_tablet_data(intf, features);
|
||||
wacom_led_control(wacom);
|
||||
|
||||
if (wacom->open)
|
||||
rv = usb_submit_urb(wacom->irq, GFP_NOIO);
|
||||
else
|
||||
rv = 0;
|
||||
if (wacom->open && usb_submit_urb(wacom->irq, GFP_NOIO) < 0)
|
||||
rv = -EIO;
|
||||
|
||||
mutex_unlock(&wacom->lock);
|
||||
|
||||
|
|
|
@ -874,7 +874,15 @@ static int wacom_bpt_pen(struct wacom_wac *wacom)
|
|||
x = le16_to_cpup((__le16 *)&data[2]);
|
||||
y = le16_to_cpup((__le16 *)&data[4]);
|
||||
p = le16_to_cpup((__le16 *)&data[6]);
|
||||
d = data[8];
|
||||
/*
|
||||
* Convert distance from out prox to distance from tablet.
|
||||
* distance will be greater than distance_max once
|
||||
* touching and applying pressure; do not report negative
|
||||
* distance.
|
||||
*/
|
||||
if (data[8] <= wacom->features.distance_max)
|
||||
d = wacom->features.distance_max - data[8];
|
||||
|
||||
pen = data[1] & 0x01;
|
||||
btn1 = data[1] & 0x02;
|
||||
btn2 = data[1] & 0x04;
|
||||
|
@ -1030,8 +1038,6 @@ void wacom_setup_device_quirks(struct wacom_features *features)
|
|||
features->y_max <<= 5;
|
||||
features->x_fuzz <<= 5;
|
||||
features->y_fuzz <<= 5;
|
||||
features->pressure_max = 256;
|
||||
features->pressure_fuzz = 16;
|
||||
features->quirks |= WACOM_QUIRK_BBTOUCH_LOWRES;
|
||||
}
|
||||
}
|
||||
|
@ -1241,14 +1247,14 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
|
|||
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
|
||||
0, features->y_max,
|
||||
features->y_fuzz, 0);
|
||||
input_set_abs_params(input_dev, ABS_MT_PRESSURE,
|
||||
0, features->pressure_max,
|
||||
features->pressure_fuzz, 0);
|
||||
} else if (features->device_type == BTN_TOOL_PEN) {
|
||||
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
|
||||
__set_bit(BTN_TOOL_PEN, input_dev->keybit);
|
||||
__set_bit(BTN_STYLUS, input_dev->keybit);
|
||||
__set_bit(BTN_STYLUS2, input_dev->keybit);
|
||||
input_set_abs_params(input_dev, ABS_DISTANCE, 0,
|
||||
features->distance_max,
|
||||
0, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1469,37 +1475,37 @@ static const struct wacom_features wacom_features_0x47 =
|
|||
31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0xD0 =
|
||||
{ "Wacom Bamboo 2FG", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
|
||||
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0xD1 =
|
||||
{ "Wacom Bamboo 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
|
||||
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0xD2 =
|
||||
{ "Wacom Bamboo Craft", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
|
||||
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0xD3 =
|
||||
{ "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023,
|
||||
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
{ "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023,
|
||||
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0xD4 =
|
||||
{ "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
|
||||
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0xD5 =
|
||||
{ "Wacom Bamboo Pen 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023,
|
||||
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
{ "Wacom Bamboo Pen 6x8", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023,
|
||||
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0xD6 =
|
||||
{ "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
|
||||
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0xD7 =
|
||||
{ "Wacom BambooPT 2FG Small", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
|
||||
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0xD8 =
|
||||
{ "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023,
|
||||
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
{ "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023,
|
||||
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0xDA =
|
||||
{ "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
|
||||
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static struct wacom_features wacom_features_0xDB =
|
||||
{ "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023,
|
||||
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
{ "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023,
|
||||
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0x6004 =
|
||||
{ "ISD-V4", WACOM_PKGLEN_GRAPHIRE, 12800, 8000, 255,
|
||||
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
|
|
|
@ -651,6 +651,18 @@ config TOUCHSCREEN_TOUCHIT213
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called touchit213.
|
||||
|
||||
config TOUCHSCREEN_TSC_SERIO
|
||||
tristate "TSC-10/25/40 serial touchscreen support"
|
||||
select SERIO
|
||||
help
|
||||
Say Y here if you have a TSC-10, 25 or 40 serial touchscreen connected
|
||||
to your system.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called tsc40.
|
||||
|
||||
config TOUCHSCREEN_TSC2005
|
||||
tristate "TSC2005 based touchscreens"
|
||||
depends on SPI_MASTER && GENERIC_HARDIRQS
|
||||
|
|
|
@ -46,6 +46,7 @@ obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o
|
|||
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TSC_SERIO) += tsc40.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TSC2005) += tsc2005.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
#define AD7879_DEVID 0x79 /* AD7879-1/AD7889-1 */
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int ad7879_i2c_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
@ -36,9 +36,9 @@ static int ad7879_i2c_resume(struct device *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(ad7879_i2c_pm, ad7879_i2c_suspend, ad7879_i2c_resume);
|
||||
#endif
|
||||
|
||||
/* All registers are word-sized.
|
||||
* AD7879 uses a high-byte first convention.
|
||||
|
@ -119,9 +119,7 @@ static struct i2c_driver ad7879_i2c_driver = {
|
|||
.driver = {
|
||||
.name = "ad7879",
|
||||
.owner = THIS_MODULE,
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &ad7879_i2c_pm,
|
||||
#endif
|
||||
},
|
||||
.probe = ad7879_i2c_probe,
|
||||
.remove = __devexit_p(ad7879_i2c_remove),
|
||||
|
|
|
@ -910,12 +910,17 @@ static ssize_t mxt_object_show(struct device *dev,
|
|||
for (i = 0; i < data->info.object_num; i++) {
|
||||
object = data->object_table + i;
|
||||
|
||||
count += sprintf(buf + count,
|
||||
"Object Table Element %d(Type %d)\n",
|
||||
count += snprintf(buf + count, PAGE_SIZE - count,
|
||||
"Object[%d] (Type %d)\n",
|
||||
i + 1, object->type);
|
||||
if (count >= PAGE_SIZE)
|
||||
return PAGE_SIZE - 1;
|
||||
|
||||
if (!mxt_object_readable(object->type)) {
|
||||
count += sprintf(buf + count, "\n");
|
||||
count += snprintf(buf + count, PAGE_SIZE - count,
|
||||
"\n");
|
||||
if (count >= PAGE_SIZE)
|
||||
return PAGE_SIZE - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -925,11 +930,15 @@ static ssize_t mxt_object_show(struct device *dev,
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
count += sprintf(buf + count,
|
||||
" Byte %d: 0x%x (%d)\n", j, val, val);
|
||||
count += snprintf(buf + count, PAGE_SIZE - count,
|
||||
"\t[%2d]: %02x (%d)\n", j, val, val);
|
||||
if (count >= PAGE_SIZE)
|
||||
return PAGE_SIZE - 1;
|
||||
}
|
||||
|
||||
count += sprintf(buf + count, "\n");
|
||||
count += snprintf(buf + count, PAGE_SIZE - count, "\n");
|
||||
if (count >= PAGE_SIZE)
|
||||
return PAGE_SIZE - 1;
|
||||
}
|
||||
|
||||
return count;
|
||||
|
|
|
@ -229,7 +229,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
|
|||
goto err_release_mem;
|
||||
}
|
||||
|
||||
err = request_irq(ts_dev->irq, atmel_tsadcc_interrupt, IRQF_DISABLED,
|
||||
err = request_irq(ts_dev->irq, atmel_tsadcc_interrupt, 0,
|
||||
pdev->dev.driver->name, ts_dev);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "failed to allocate irq.\n");
|
||||
|
|
|
@ -396,14 +396,14 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
|
|||
set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
|
||||
|
||||
if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
|
||||
IRQF_SHARED | IRQF_DISABLED, "h3600_action", ts->dev)) {
|
||||
IRQF_SHARED, "h3600_action", ts->dev)) {
|
||||
printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
|
||||
err = -EBUSY;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
|
||||
IRQF_SHARED | IRQF_DISABLED, "h3600_suspend", ts->dev)) {
|
||||
IRQF_SHARED, "h3600_suspend", ts->dev)) {
|
||||
printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n");
|
||||
err = -EBUSY;
|
||||
goto fail2;
|
||||
|
|
|
@ -93,7 +93,7 @@ static int __init hp680_ts_init(void)
|
|||
hp680_ts_dev->phys = "hp680_ts/input0";
|
||||
|
||||
if (request_irq(HP680_TS_IRQ, hp680_ts_interrupt,
|
||||
IRQF_DISABLED, MODNAME, 0) < 0) {
|
||||
0, MODNAME, 0) < 0) {
|
||||
printk(KERN_ERR "hp680_touchscreen.c: Can't allocate irq %d\n",
|
||||
HP680_TS_IRQ);
|
||||
err = -EBUSY;
|
||||
|
|
|
@ -127,7 +127,7 @@ static int __devinit jornada720_ts_probe(struct platform_device *pdev)
|
|||
|
||||
error = request_irq(IRQ_GPIO9,
|
||||
jornada720_ts_interrupt,
|
||||
IRQF_DISABLED | IRQF_TRIGGER_RISING,
|
||||
IRQF_TRIGGER_RISING,
|
||||
"HP7XX Touchscreen driver", pdev);
|
||||
if (error) {
|
||||
printk(KERN_INFO "HP7XX TS : Unable to acquire irq!\n");
|
||||
|
|
|
@ -276,7 +276,7 @@ static int __devinit lpc32xx_ts_probe(struct platform_device *pdev)
|
|||
input_set_drvdata(input, tsc);
|
||||
|
||||
error = request_irq(tsc->irq, lpc32xx_ts_interrupt,
|
||||
IRQF_DISABLED, pdev->name, tsc);
|
||||
0, pdev->name, tsc);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed requesting interrupt\n");
|
||||
goto err_put_clock;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* Penmount serial touchscreen driver
|
||||
*
|
||||
* Copyright (c) 2006 Rick Koch <n1gp@hotmail.com>
|
||||
* Copyright (c) 2011 John Sung <penmount.touch@gmail.com>
|
||||
*
|
||||
* Based on ELO driver (drivers/input/touchscreen/elo.c)
|
||||
* Copyright (c) 2004 Vojtech Pavlik
|
||||
|
@ -18,12 +19,14 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/serio.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#define DRIVER_DESC "Penmount serial touchscreen driver"
|
||||
#define DRIVER_DESC "PenMount serial touchscreen driver"
|
||||
|
||||
MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>");
|
||||
MODULE_AUTHOR("John Sung <penmount.touch@gmail.com>");
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
@ -31,7 +34,19 @@ MODULE_LICENSE("GPL");
|
|||
* Definitions & global arrays.
|
||||
*/
|
||||
|
||||
#define PM_MAX_LENGTH 5
|
||||
#define PM_MAX_LENGTH 6
|
||||
#define PM_MAX_MTSLOT 16
|
||||
#define PM_3000_MTSLOT 2
|
||||
#define PM_6250_MTSLOT 12
|
||||
|
||||
/*
|
||||
* Multi-touch slot
|
||||
*/
|
||||
|
||||
struct mt_slot {
|
||||
unsigned short x, y;
|
||||
bool active; /* is the touch valid? */
|
||||
};
|
||||
|
||||
/*
|
||||
* Per-touchscreen data.
|
||||
|
@ -43,25 +58,119 @@ struct pm {
|
|||
int idx;
|
||||
unsigned char data[PM_MAX_LENGTH];
|
||||
char phys[32];
|
||||
unsigned char packetsize;
|
||||
unsigned char maxcontacts;
|
||||
struct mt_slot slots[PM_MAX_MTSLOT];
|
||||
void (*parse_packet)(struct pm *);
|
||||
};
|
||||
|
||||
/*
|
||||
* pm_mtevent() sends mt events and also emulates pointer movement
|
||||
*/
|
||||
|
||||
static void pm_mtevent(struct pm *pm, struct input_dev *input)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pm->maxcontacts; ++i) {
|
||||
input_mt_slot(input, i);
|
||||
input_mt_report_slot_state(input, MT_TOOL_FINGER,
|
||||
pm->slots[i].active);
|
||||
if (pm->slots[i].active) {
|
||||
input_event(input, EV_ABS, ABS_MT_POSITION_X, pm->slots[i].x);
|
||||
input_event(input, EV_ABS, ABS_MT_POSITION_Y, pm->slots[i].y);
|
||||
}
|
||||
}
|
||||
|
||||
input_mt_report_pointer_emulation(input, true);
|
||||
input_sync(input);
|
||||
}
|
||||
|
||||
/*
|
||||
* pm_checkpacket() checks if data packet is valid
|
||||
*/
|
||||
|
||||
static bool pm_checkpacket(unsigned char *packet)
|
||||
{
|
||||
int total = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
total += packet[i];
|
||||
|
||||
return packet[5] == (unsigned char)~(total & 0xff);
|
||||
}
|
||||
|
||||
static void pm_parse_9000(struct pm *pm)
|
||||
{
|
||||
struct input_dev *dev = pm->dev;
|
||||
|
||||
if ((pm->data[0] & 0x80) && pm->packetsize == ++pm->idx) {
|
||||
input_report_abs(dev, ABS_X, pm->data[1] * 128 + pm->data[2]);
|
||||
input_report_abs(dev, ABS_Y, pm->data[3] * 128 + pm->data[4]);
|
||||
input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40));
|
||||
input_sync(dev);
|
||||
pm->idx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void pm_parse_6000(struct pm *pm)
|
||||
{
|
||||
struct input_dev *dev = pm->dev;
|
||||
|
||||
if ((pm->data[0] & 0xbf) == 0x30 && pm->packetsize == ++pm->idx) {
|
||||
if (pm_checkpacket(pm->data)) {
|
||||
input_report_abs(dev, ABS_X,
|
||||
pm->data[2] * 256 + pm->data[1]);
|
||||
input_report_abs(dev, ABS_Y,
|
||||
pm->data[4] * 256 + pm->data[3]);
|
||||
input_report_key(dev, BTN_TOUCH, pm->data[0] & 0x40);
|
||||
input_sync(dev);
|
||||
}
|
||||
pm->idx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void pm_parse_3000(struct pm *pm)
|
||||
{
|
||||
struct input_dev *dev = pm->dev;
|
||||
|
||||
if ((pm->data[0] & 0xce) == 0x40 && pm->packetsize == ++pm->idx) {
|
||||
if (pm_checkpacket(pm->data)) {
|
||||
int slotnum = pm->data[0] & 0x0f;
|
||||
pm->slots[slotnum].active = pm->data[0] & 0x30;
|
||||
pm->slots[slotnum].x = pm->data[2] * 256 + pm->data[1];
|
||||
pm->slots[slotnum].y = pm->data[4] * 256 + pm->data[3];
|
||||
pm_mtevent(pm, dev);
|
||||
}
|
||||
pm->idx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void pm_parse_6250(struct pm *pm)
|
||||
{
|
||||
struct input_dev *dev = pm->dev;
|
||||
|
||||
if ((pm->data[0] & 0xb0) == 0x30 && pm->packetsize == ++pm->idx) {
|
||||
if (pm_checkpacket(pm->data)) {
|
||||
int slotnum = pm->data[0] & 0x0f;
|
||||
pm->slots[slotnum].active = pm->data[0] & 0x40;
|
||||
pm->slots[slotnum].x = pm->data[2] * 256 + pm->data[1];
|
||||
pm->slots[slotnum].y = pm->data[4] * 256 + pm->data[3];
|
||||
pm_mtevent(pm, dev);
|
||||
}
|
||||
pm->idx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t pm_interrupt(struct serio *serio,
|
||||
unsigned char data, unsigned int flags)
|
||||
{
|
||||
struct pm *pm = serio_get_drvdata(serio);
|
||||
struct input_dev *dev = pm->dev;
|
||||
|
||||
pm->data[pm->idx] = data;
|
||||
|
||||
if (pm->data[0] & 0x80) {
|
||||
if (PM_MAX_LENGTH == ++pm->idx) {
|
||||
input_report_abs(dev, ABS_X, pm->data[2] * 128 + pm->data[1]);
|
||||
input_report_abs(dev, ABS_Y, pm->data[4] * 128 + pm->data[3]);
|
||||
input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40));
|
||||
input_sync(dev);
|
||||
pm->idx = 0;
|
||||
}
|
||||
}
|
||||
pm->parse_packet(pm);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -74,17 +183,17 @@ static void pm_disconnect(struct serio *serio)
|
|||
{
|
||||
struct pm *pm = serio_get_drvdata(serio);
|
||||
|
||||
input_get_device(pm->dev);
|
||||
input_unregister_device(pm->dev);
|
||||
serio_close(serio);
|
||||
serio_set_drvdata(serio, NULL);
|
||||
input_put_device(pm->dev);
|
||||
|
||||
input_unregister_device(pm->dev);
|
||||
kfree(pm);
|
||||
|
||||
serio_set_drvdata(serio, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* pm_connect() is the routine that is called when someone adds a
|
||||
* new serio device that supports Gunze protocol and registers it as
|
||||
* new serio device that supports PenMount protocol and registers it as
|
||||
* an input device.
|
||||
*/
|
||||
|
||||
|
@ -92,6 +201,7 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv)
|
|||
{
|
||||
struct pm *pm;
|
||||
struct input_dev *input_dev;
|
||||
int max_x, max_y;
|
||||
int err;
|
||||
|
||||
pm = kzalloc(sizeof(struct pm), GFP_KERNEL);
|
||||
|
@ -104,8 +214,9 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv)
|
|||
pm->serio = serio;
|
||||
pm->dev = input_dev;
|
||||
snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys);
|
||||
pm->maxcontacts = 1;
|
||||
|
||||
input_dev->name = "Penmount Serial TouchScreen";
|
||||
input_dev->name = "PenMount Serial TouchScreen";
|
||||
input_dev->phys = pm->phys;
|
||||
input_dev->id.bustype = BUS_RS232;
|
||||
input_dev->id.vendor = SERIO_PENMOUNT;
|
||||
|
@ -115,8 +226,50 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv)
|
|||
|
||||
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(pm->dev, ABS_X, 0, 0x3ff, 0, 0);
|
||||
input_set_abs_params(pm->dev, ABS_Y, 0, 0x3ff, 0, 0);
|
||||
|
||||
switch (serio->id.id) {
|
||||
default:
|
||||
case 0:
|
||||
pm->packetsize = 5;
|
||||
pm->parse_packet = pm_parse_9000;
|
||||
input_dev->id.product = 0x9000;
|
||||
max_x = max_y = 0x3ff;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
pm->packetsize = 6;
|
||||
pm->parse_packet = pm_parse_6000;
|
||||
input_dev->id.product = 0x6000;
|
||||
max_x = max_y = 0x3ff;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
pm->packetsize = 6;
|
||||
pm->parse_packet = pm_parse_3000;
|
||||
input_dev->id.product = 0x3000;
|
||||
max_x = max_y = 0x7ff;
|
||||
pm->maxcontacts = PM_3000_MTSLOT;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
pm->packetsize = 6;
|
||||
pm->parse_packet = pm_parse_6250;
|
||||
input_dev->id.product = 0x6250;
|
||||
max_x = max_y = 0x3ff;
|
||||
pm->maxcontacts = PM_6250_MTSLOT;
|
||||
break;
|
||||
}
|
||||
|
||||
input_set_abs_params(pm->dev, ABS_X, 0, max_x, 0, 0);
|
||||
input_set_abs_params(pm->dev, ABS_Y, 0, max_y, 0, 0);
|
||||
|
||||
if (pm->maxcontacts > 1) {
|
||||
input_mt_init_slots(pm->dev, pm->maxcontacts);
|
||||
input_set_abs_params(pm->dev,
|
||||
ABS_MT_POSITION_X, 0, max_x, 0, 0);
|
||||
input_set_abs_params(pm->dev,
|
||||
ABS_MT_POSITION_Y, 0, max_y, 0, 0);
|
||||
}
|
||||
|
||||
serio_set_drvdata(serio, pm);
|
||||
|
||||
|
@ -155,7 +308,7 @@ MODULE_DEVICE_TABLE(serio, pm_serio_ids);
|
|||
|
||||
static struct serio_driver pm_drv = {
|
||||
.driver = {
|
||||
.name = "penmountlpc",
|
||||
.name = "serio-penmount",
|
||||
},
|
||||
.description = DRIVER_DESC,
|
||||
.id_table = pm_serio_ids,
|
||||
|
|
|
@ -328,7 +328,7 @@ static int __devinit s3c2410ts_probe(struct platform_device *pdev)
|
|||
ts.shift = info->oversampling_shift;
|
||||
ts.features = platform_get_device_id(pdev)->driver_data;
|
||||
|
||||
ret = request_irq(ts.irq_tc, stylus_irq, IRQF_DISABLED,
|
||||
ret = request_irq(ts.irq_tc, stylus_irq, 0,
|
||||
"s3c2410_ts_pen", ts.input);
|
||||
if (ret) {
|
||||
dev_err(dev, "cannot get TC interrupt\n");
|
||||
|
|
|
@ -66,7 +66,6 @@ struct ts_event {
|
|||
struct tsc2007 {
|
||||
struct input_dev *input;
|
||||
char phys[32];
|
||||
struct delayed_work work;
|
||||
|
||||
struct i2c_client *client;
|
||||
|
||||
|
@ -76,9 +75,11 @@ struct tsc2007 {
|
|||
unsigned long poll_delay;
|
||||
unsigned long poll_period;
|
||||
|
||||
bool pendown;
|
||||
int irq;
|
||||
|
||||
wait_queue_head_t wait;
|
||||
bool stopped;
|
||||
|
||||
int (*get_pendown_state)(void);
|
||||
void (*clear_penirq)(void);
|
||||
};
|
||||
|
@ -141,25 +142,8 @@ static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc)
|
|||
return rt;
|
||||
}
|
||||
|
||||
static void tsc2007_send_up_event(struct tsc2007 *tsc)
|
||||
static bool tsc2007_is_pen_down(struct tsc2007 *ts)
|
||||
{
|
||||
struct input_dev *input = tsc->input;
|
||||
|
||||
dev_dbg(&tsc->client->dev, "UP\n");
|
||||
|
||||
input_report_key(input, BTN_TOUCH, 0);
|
||||
input_report_abs(input, ABS_PRESSURE, 0);
|
||||
input_sync(input);
|
||||
}
|
||||
|
||||
static void tsc2007_work(struct work_struct *work)
|
||||
{
|
||||
struct tsc2007 *ts =
|
||||
container_of(to_delayed_work(work), struct tsc2007, work);
|
||||
bool debounced = false;
|
||||
struct ts_event tc;
|
||||
u32 rt;
|
||||
|
||||
/*
|
||||
* NOTE: We can't rely on the pressure to determine the pen down
|
||||
* state, even though this controller has a pressure sensor.
|
||||
|
@ -170,97 +154,123 @@ static void tsc2007_work(struct work_struct *work)
|
|||
* The only safe way to check for the pen up condition is in the
|
||||
* work function by reading the pen signal state (it's a GPIO
|
||||
* and IRQ). Unfortunately such callback is not always available,
|
||||
* in that case we have rely on the pressure anyway.
|
||||
* in that case we assume that the pen is down and expect caller
|
||||
* to fall back on the pressure reading.
|
||||
*/
|
||||
if (ts->get_pendown_state) {
|
||||
if (unlikely(!ts->get_pendown_state())) {
|
||||
tsc2007_send_up_event(ts);
|
||||
ts->pendown = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev_dbg(&ts->client->dev, "pen is still down\n");
|
||||
}
|
||||
if (!ts->get_pendown_state)
|
||||
return true;
|
||||
|
||||
return ts->get_pendown_state();
|
||||
}
|
||||
|
||||
static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
|
||||
{
|
||||
struct tsc2007 *ts = handle;
|
||||
struct input_dev *input = ts->input;
|
||||
struct ts_event tc;
|
||||
u32 rt;
|
||||
|
||||
while (!ts->stopped && tsc2007_is_pen_down(ts)) {
|
||||
|
||||
/* pen is down, continue with the measurement */
|
||||
tsc2007_read_values(ts, &tc);
|
||||
|
||||
rt = tsc2007_calculate_pressure(ts, &tc);
|
||||
if (rt > ts->max_rt) {
|
||||
/*
|
||||
* Sample found inconsistent by debouncing or pressure is
|
||||
* beyond the maximum. Don't report it to user space,
|
||||
* repeat at least once more the measurement.
|
||||
*/
|
||||
dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);
|
||||
debounced = true;
|
||||
goto out;
|
||||
|
||||
if (rt == 0 && !ts->get_pendown_state) {
|
||||
/*
|
||||
* If pressure reported is 0 and we don't have
|
||||
* callback to check pendown state, we have to
|
||||
* assume that pen was lifted up.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
if (rt) {
|
||||
struct input_dev *input = ts->input;
|
||||
|
||||
if (!ts->pendown) {
|
||||
dev_dbg(&ts->client->dev, "DOWN\n");
|
||||
if (rt <= ts->max_rt) {
|
||||
dev_dbg(&ts->client->dev,
|
||||
"DOWN point(%4d,%4d), pressure (%4u)\n",
|
||||
tc.x, tc.y, rt);
|
||||
|
||||
input_report_key(input, BTN_TOUCH, 1);
|
||||
ts->pendown = true;
|
||||
}
|
||||
|
||||
input_report_abs(input, ABS_X, tc.x);
|
||||
input_report_abs(input, ABS_Y, tc.y);
|
||||
input_report_abs(input, ABS_PRESSURE, rt);
|
||||
|
||||
input_sync(input);
|
||||
|
||||
dev_dbg(&ts->client->dev, "point(%4d,%4d), pressure (%4u)\n",
|
||||
tc.x, tc.y, rt);
|
||||
|
||||
} else if (!ts->get_pendown_state && ts->pendown) {
|
||||
} else {
|
||||
/*
|
||||
* We don't have callback to check pendown state, so we
|
||||
* have to assume that since pressure reported is 0 the
|
||||
* pen was lifted up.
|
||||
* Sample found inconsistent by debouncing or pressure is
|
||||
* beyond the maximum. Don't report it to user space,
|
||||
* repeat at least once more the measurement.
|
||||
*/
|
||||
tsc2007_send_up_event(ts);
|
||||
ts->pendown = false;
|
||||
dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);
|
||||
}
|
||||
|
||||
out:
|
||||
if (ts->pendown || debounced)
|
||||
schedule_delayed_work(&ts->work,
|
||||
wait_event_timeout(ts->wait, ts->stopped,
|
||||
msecs_to_jiffies(ts->poll_period));
|
||||
else
|
||||
enable_irq(ts->irq);
|
||||
}
|
||||
|
||||
static irqreturn_t tsc2007_irq(int irq, void *handle)
|
||||
{
|
||||
struct tsc2007 *ts = handle;
|
||||
|
||||
if (!ts->get_pendown_state || likely(ts->get_pendown_state())) {
|
||||
disable_irq_nosync(ts->irq);
|
||||
schedule_delayed_work(&ts->work,
|
||||
msecs_to_jiffies(ts->poll_delay));
|
||||
}
|
||||
|
||||
dev_dbg(&ts->client->dev, "UP\n");
|
||||
|
||||
input_report_key(input, BTN_TOUCH, 0);
|
||||
input_report_abs(input, ABS_PRESSURE, 0);
|
||||
input_sync(input);
|
||||
|
||||
if (ts->clear_penirq)
|
||||
ts->clear_penirq();
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void tsc2007_free_irq(struct tsc2007 *ts)
|
||||
static irqreturn_t tsc2007_hard_irq(int irq, void *handle)
|
||||
{
|
||||
free_irq(ts->irq, ts);
|
||||
if (cancel_delayed_work_sync(&ts->work)) {
|
||||
/*
|
||||
* Work was pending, therefore we need to enable
|
||||
* IRQ here to balance the disable_irq() done in the
|
||||
* interrupt handler.
|
||||
*/
|
||||
struct tsc2007 *ts = handle;
|
||||
|
||||
if (!ts->get_pendown_state || likely(ts->get_pendown_state()))
|
||||
return IRQ_WAKE_THREAD;
|
||||
|
||||
if (ts->clear_penirq)
|
||||
ts->clear_penirq();
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void tsc2007_stop(struct tsc2007 *ts)
|
||||
{
|
||||
ts->stopped = true;
|
||||
mb();
|
||||
wake_up(&ts->wait);
|
||||
|
||||
disable_irq(ts->irq);
|
||||
}
|
||||
|
||||
static int tsc2007_open(struct input_dev *input_dev)
|
||||
{
|
||||
struct tsc2007 *ts = input_get_drvdata(input_dev);
|
||||
int err;
|
||||
|
||||
ts->stopped = false;
|
||||
mb();
|
||||
|
||||
enable_irq(ts->irq);
|
||||
|
||||
/* Prepare for touch readings - power down ADC and enable PENIRQ */
|
||||
err = tsc2007_xfer(ts, PWRDOWN);
|
||||
if (err < 0) {
|
||||
tsc2007_stop(ts);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tsc2007_close(struct input_dev *input_dev)
|
||||
{
|
||||
struct tsc2007 *ts = input_get_drvdata(input_dev);
|
||||
|
||||
tsc2007_stop(ts);
|
||||
}
|
||||
|
||||
static int __devinit tsc2007_probe(struct i2c_client *client,
|
||||
|
@ -290,7 +300,7 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
|
|||
ts->client = client;
|
||||
ts->irq = client->irq;
|
||||
ts->input = input_dev;
|
||||
INIT_DELAYED_WORK(&ts->work, tsc2007_work);
|
||||
init_waitqueue_head(&ts->wait);
|
||||
|
||||
ts->model = pdata->model;
|
||||
ts->x_plate_ohms = pdata->x_plate_ohms;
|
||||
|
@ -300,6 +310,12 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
|
|||
ts->get_pendown_state = pdata->get_pendown_state;
|
||||
ts->clear_penirq = pdata->clear_penirq;
|
||||
|
||||
if (pdata->x_plate_ohms == 0) {
|
||||
dev_err(&client->dev, "x_plate_ohms is not set up in platform data");
|
||||
err = -EINVAL;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
snprintf(ts->phys, sizeof(ts->phys),
|
||||
"%s/input0", dev_name(&client->dev));
|
||||
|
||||
|
@ -307,6 +323,11 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
|
|||
input_dev->phys = ts->phys;
|
||||
input_dev->id.bustype = BUS_I2C;
|
||||
|
||||
input_dev->open = tsc2007_open;
|
||||
input_dev->close = tsc2007_close;
|
||||
|
||||
input_set_drvdata(input_dev, ts);
|
||||
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
|
||||
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
|
||||
|
||||
|
@ -318,17 +339,14 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
|
|||
if (pdata->init_platform_hw)
|
||||
pdata->init_platform_hw();
|
||||
|
||||
err = request_irq(ts->irq, tsc2007_irq, 0,
|
||||
client->dev.driver->name, ts);
|
||||
err = request_threaded_irq(ts->irq, tsc2007_hard_irq, tsc2007_soft_irq,
|
||||
IRQF_ONESHOT, client->dev.driver->name, ts);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "irq %d busy?\n", ts->irq);
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
/* Prepare for touch readings - power down ADC and enable PENIRQ */
|
||||
err = tsc2007_xfer(ts, PWRDOWN);
|
||||
if (err < 0)
|
||||
goto err_free_irq;
|
||||
tsc2007_stop(ts);
|
||||
|
||||
err = input_register_device(input_dev);
|
||||
if (err)
|
||||
|
@ -339,7 +357,7 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
|
|||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
tsc2007_free_irq(ts);
|
||||
free_irq(ts->irq, ts);
|
||||
if (pdata->exit_platform_hw)
|
||||
pdata->exit_platform_hw();
|
||||
err_free_mem:
|
||||
|
@ -353,7 +371,7 @@ static int __devexit tsc2007_remove(struct i2c_client *client)
|
|||
struct tsc2007 *ts = i2c_get_clientdata(client);
|
||||
struct tsc2007_platform_data *pdata = client->dev.platform_data;
|
||||
|
||||
tsc2007_free_irq(ts);
|
||||
free_irq(ts->irq, ts);
|
||||
|
||||
if (pdata->exit_platform_hw)
|
||||
pdata->exit_platform_hw();
|
||||
|
|
184
drivers/input/touchscreen/tsc40.c
Normal file
184
drivers/input/touchscreen/tsc40.c
Normal file
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* TSC-40 serial touchscreen driver. It should be compatible with
|
||||
* TSC-10 and 25.
|
||||
*
|
||||
* Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
||||
* License: GPLv2 as published by the FSF.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/serio.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#define PACKET_LENGTH 5
|
||||
struct tsc_ser {
|
||||
struct input_dev *dev;
|
||||
struct serio *serio;
|
||||
u32 idx;
|
||||
unsigned char data[PACKET_LENGTH];
|
||||
char phys[32];
|
||||
};
|
||||
|
||||
static void tsc_process_data(struct tsc_ser *ptsc)
|
||||
{
|
||||
struct input_dev *dev = ptsc->dev;
|
||||
u8 *data = ptsc->data;
|
||||
u32 x;
|
||||
u32 y;
|
||||
|
||||
x = ((data[1] & 0x03) << 8) | data[2];
|
||||
y = ((data[3] & 0x03) << 8) | data[4];
|
||||
|
||||
input_report_abs(dev, ABS_X, x);
|
||||
input_report_abs(dev, ABS_Y, y);
|
||||
input_report_key(dev, BTN_TOUCH, 1);
|
||||
|
||||
input_sync(dev);
|
||||
}
|
||||
|
||||
static irqreturn_t tsc_interrupt(struct serio *serio,
|
||||
unsigned char data, unsigned int flags)
|
||||
{
|
||||
struct tsc_ser *ptsc = serio_get_drvdata(serio);
|
||||
struct input_dev *dev = ptsc->dev;
|
||||
|
||||
ptsc->data[ptsc->idx] = data;
|
||||
switch (ptsc->idx++) {
|
||||
case 0:
|
||||
if (unlikely((data & 0x3e) != 0x10)) {
|
||||
dev_dbg(&serio->dev,
|
||||
"unsynchronized packet start (0x%02x)\n", data);
|
||||
ptsc->idx = 0;
|
||||
} else if (!(data & 0x01)) {
|
||||
input_report_key(dev, BTN_TOUCH, 0);
|
||||
input_sync(dev);
|
||||
ptsc->idx = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
case 3:
|
||||
if (unlikely(data & 0xfc)) {
|
||||
dev_dbg(&serio->dev,
|
||||
"unsynchronized data 0x%02x at offset %d\n",
|
||||
data, ptsc->idx - 1);
|
||||
ptsc->idx = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
tsc_process_data(ptsc);
|
||||
ptsc->idx = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int tsc_connect(struct serio *serio, struct serio_driver *drv)
|
||||
{
|
||||
struct tsc_ser *ptsc;
|
||||
struct input_dev *input_dev;
|
||||
int error;
|
||||
|
||||
ptsc = kzalloc(sizeof(struct tsc_ser), GFP_KERNEL);
|
||||
input_dev = input_allocate_device();
|
||||
if (!ptsc || !input_dev) {
|
||||
error = -ENOMEM;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
ptsc->serio = serio;
|
||||
ptsc->dev = input_dev;
|
||||
snprintf(ptsc->phys, sizeof(ptsc->phys), "%s/input0", serio->phys);
|
||||
|
||||
input_dev->name = "TSC-10/25/40 Serial TouchScreen";
|
||||
input_dev->phys = ptsc->phys;
|
||||
input_dev->id.bustype = BUS_RS232;
|
||||
input_dev->id.vendor = SERIO_TSC40;
|
||||
input_dev->id.product = 40;
|
||||
input_dev->id.version = 0x0001;
|
||||
input_dev->dev.parent = &serio->dev;
|
||||
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
|
||||
__set_bit(BTN_TOUCH, input_dev->keybit);
|
||||
input_set_abs_params(ptsc->dev, ABS_X, 0, 0x3ff, 0, 0);
|
||||
input_set_abs_params(ptsc->dev, ABS_Y, 0, 0x3ff, 0, 0);
|
||||
input_set_abs_params(ptsc->dev, ABS_PRESSURE, 0, 0, 0, 0);
|
||||
|
||||
serio_set_drvdata(serio, ptsc);
|
||||
|
||||
error = serio_open(serio, drv);
|
||||
if (error)
|
||||
goto fail2;
|
||||
|
||||
error = input_register_device(ptsc->dev);
|
||||
if (error)
|
||||
goto fail3;
|
||||
|
||||
return 0;
|
||||
|
||||
fail3:
|
||||
serio_close(serio);
|
||||
fail2:
|
||||
serio_set_drvdata(serio, NULL);
|
||||
fail1:
|
||||
input_free_device(input_dev);
|
||||
kfree(ptsc);
|
||||
return error;
|
||||
}
|
||||
|
||||
static void tsc_disconnect(struct serio *serio)
|
||||
{
|
||||
struct tsc_ser *ptsc = serio_get_drvdata(serio);
|
||||
|
||||
serio_close(serio);
|
||||
|
||||
input_unregister_device(ptsc->dev);
|
||||
kfree(ptsc);
|
||||
|
||||
serio_set_drvdata(serio, NULL);
|
||||
}
|
||||
|
||||
static struct serio_device_id tsc_serio_ids[] = {
|
||||
{
|
||||
.type = SERIO_RS232,
|
||||
.proto = SERIO_TSC40,
|
||||
.id = SERIO_ANY,
|
||||
.extra = SERIO_ANY,
|
||||
},
|
||||
{ 0 }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(serio, tsc_serio_ids);
|
||||
|
||||
#define DRIVER_DESC "TSC-10/25/40 serial touchscreen driver"
|
||||
|
||||
static struct serio_driver tsc_drv = {
|
||||
.driver = {
|
||||
.name = "tsc40",
|
||||
},
|
||||
.description = DRIVER_DESC,
|
||||
.id_table = tsc_serio_ids,
|
||||
.interrupt = tsc_interrupt,
|
||||
.connect = tsc_connect,
|
||||
.disconnect = tsc_disconnect,
|
||||
};
|
||||
|
||||
static int __init tsc_ser_init(void)
|
||||
{
|
||||
return serio_register_driver(&tsc_drv);
|
||||
}
|
||||
module_init(tsc_ser_init);
|
||||
|
||||
static void __exit tsc_exit(void)
|
||||
{
|
||||
serio_unregister_driver(&tsc_drv);
|
||||
}
|
||||
module_exit(tsc_exit);
|
||||
|
||||
MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -279,7 +279,7 @@ static int __devinit w90x900ts_probe(struct platform_device *pdev)
|
|||
|
||||
w90p910_ts->irq_num = platform_get_irq(pdev, 0);
|
||||
if (request_irq(w90p910_ts->irq_num, w90p910_ts_interrupt,
|
||||
IRQF_DISABLED, "w90p910ts", w90p910_ts)) {
|
||||
0, "w90p910ts", w90p910_ts)) {
|
||||
err = -EBUSY;
|
||||
goto fail4;
|
||||
}
|
||||
|
|
|
@ -367,6 +367,20 @@ static int w8001_command(struct w8001 *w8001, unsigned char command,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int w8001_open(struct input_dev *dev)
|
||||
{
|
||||
struct w8001 *w8001 = input_get_drvdata(dev);
|
||||
|
||||
return w8001_command(w8001, W8001_CMD_START, false);
|
||||
}
|
||||
|
||||
static void w8001_close(struct input_dev *dev)
|
||||
{
|
||||
struct w8001 *w8001 = input_get_drvdata(dev);
|
||||
|
||||
w8001_command(w8001, W8001_CMD_STOP, false);
|
||||
}
|
||||
|
||||
static int w8001_setup(struct w8001 *w8001)
|
||||
{
|
||||
struct input_dev *dev = w8001->dev;
|
||||
|
@ -476,7 +490,7 @@ static int w8001_setup(struct w8001 *w8001)
|
|||
|
||||
strlcat(w8001->name, " Touchscreen", sizeof(w8001->name));
|
||||
|
||||
return w8001_command(w8001, W8001_CMD_START, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -487,12 +501,12 @@ static void w8001_disconnect(struct serio *serio)
|
|||
{
|
||||
struct w8001 *w8001 = serio_get_drvdata(serio);
|
||||
|
||||
input_get_device(w8001->dev);
|
||||
input_unregister_device(w8001->dev);
|
||||
serio_close(serio);
|
||||
serio_set_drvdata(serio, NULL);
|
||||
input_put_device(w8001->dev);
|
||||
|
||||
input_unregister_device(w8001->dev);
|
||||
kfree(w8001);
|
||||
|
||||
serio_set_drvdata(serio, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -536,6 +550,11 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
|
|||
input_dev->id.version = 0x0100;
|
||||
input_dev->dev.parent = &serio->dev;
|
||||
|
||||
input_dev->open = w8001_open;
|
||||
input_dev->close = w8001_close;
|
||||
|
||||
input_set_drvdata(input_dev, w8001);
|
||||
|
||||
err = input_register_device(w8001->dev);
|
||||
if (err)
|
||||
goto fail3;
|
||||
|
|
46
include/linux/bma150.h
Normal file
46
include/linux/bma150.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2011 Bosch Sensortec GmbH
|
||||
* Copyright (c) 2011 Unixphere
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _BMA150_H_
|
||||
#define _BMA150_H_
|
||||
|
||||
#define BMA150_DRIVER "bma150"
|
||||
|
||||
struct bma150_cfg {
|
||||
bool any_motion_int; /* Set to enable any-motion interrupt */
|
||||
bool hg_int; /* Set to enable high-G interrupt */
|
||||
bool lg_int; /* Set to enable low-G interrupt */
|
||||
unsigned char any_motion_dur; /* Any-motion duration */
|
||||
unsigned char any_motion_thres; /* Any-motion threshold */
|
||||
unsigned char hg_hyst; /* High-G hysterisis */
|
||||
unsigned char hg_dur; /* High-G duration */
|
||||
unsigned char hg_thres; /* High-G threshold */
|
||||
unsigned char lg_hyst; /* Low-G hysterisis */
|
||||
unsigned char lg_dur; /* Low-G duration */
|
||||
unsigned char lg_thres; /* Low-G threshold */
|
||||
unsigned char range; /* BMA0150_RANGE_xxx (in G) */
|
||||
unsigned char bandwidth; /* BMA0150_BW_xxx (in Hz) */
|
||||
};
|
||||
|
||||
struct bma150_platform_data {
|
||||
struct bma150_cfg cfg;
|
||||
int (*irq_gpio_cfg)(void);
|
||||
};
|
||||
|
||||
#endif /* _BMA150_H_ */
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
struct tsc2007_platform_data {
|
||||
u16 model; /* 2007. */
|
||||
u16 x_plate_ohms;
|
||||
u16 x_plate_ohms; /* must be non-zero value */
|
||||
u16 max_rt; /* max. resistance above which samples are ignored */
|
||||
unsigned long poll_delay; /* delay (in ms) after pen-down event
|
||||
before polling starts */
|
||||
|
|
|
@ -505,6 +505,7 @@ struct input_keymap_entry {
|
|||
#define BTN_TOOL_FINGER 0x145
|
||||
#define BTN_TOOL_MOUSE 0x146
|
||||
#define BTN_TOOL_LENS 0x147
|
||||
#define BTN_TOOL_QUINTTAP 0x148 /* Five fingers on trackpad */
|
||||
#define BTN_TOUCH 0x14a
|
||||
#define BTN_STYLUS 0x14b
|
||||
#define BTN_STYLUS2 0x14c
|
||||
|
@ -1609,7 +1610,7 @@ struct ff_device {
|
|||
struct file *effect_owners[];
|
||||
};
|
||||
|
||||
int input_ff_create(struct input_dev *dev, int max_effects);
|
||||
int input_ff_create(struct input_dev *dev, unsigned int max_effects);
|
||||
void input_ff_destroy(struct input_dev *dev);
|
||||
|
||||
int input_ff_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Analog Devices ADP5589 I/O Expander and QWERTY Keypad Controller
|
||||
* Analog Devices ADP5589/ADP5585 I/O Expander and QWERTY Keypad Controller
|
||||
*
|
||||
* Copyright 2010-2011 Analog Devices Inc.
|
||||
*
|
||||
|
@ -9,89 +9,9 @@
|
|||
#ifndef _ADP5589_H
|
||||
#define _ADP5589_H
|
||||
|
||||
#define ADP5589_ID 0x00
|
||||
#define ADP5589_INT_STATUS 0x01
|
||||
#define ADP5589_STATUS 0x02
|
||||
#define ADP5589_FIFO_1 0x03
|
||||
#define ADP5589_FIFO_2 0x04
|
||||
#define ADP5589_FIFO_3 0x05
|
||||
#define ADP5589_FIFO_4 0x06
|
||||
#define ADP5589_FIFO_5 0x07
|
||||
#define ADP5589_FIFO_6 0x08
|
||||
#define ADP5589_FIFO_7 0x09
|
||||
#define ADP5589_FIFO_8 0x0A
|
||||
#define ADP5589_FIFO_9 0x0B
|
||||
#define ADP5589_FIFO_10 0x0C
|
||||
#define ADP5589_FIFO_11 0x0D
|
||||
#define ADP5589_FIFO_12 0x0E
|
||||
#define ADP5589_FIFO_13 0x0F
|
||||
#define ADP5589_FIFO_14 0x10
|
||||
#define ADP5589_FIFO_15 0x11
|
||||
#define ADP5589_FIFO_16 0x12
|
||||
#define ADP5589_GPI_INT_STAT_A 0x13
|
||||
#define ADP5589_GPI_INT_STAT_B 0x14
|
||||
#define ADP5589_GPI_INT_STAT_C 0x15
|
||||
#define ADP5589_GPI_STATUS_A 0x16
|
||||
#define ADP5589_GPI_STATUS_B 0x17
|
||||
#define ADP5589_GPI_STATUS_C 0x18
|
||||
#define ADP5589_RPULL_CONFIG_A 0x19
|
||||
#define ADP5589_RPULL_CONFIG_B 0x1A
|
||||
#define ADP5589_RPULL_CONFIG_C 0x1B
|
||||
#define ADP5589_RPULL_CONFIG_D 0x1C
|
||||
#define ADP5589_RPULL_CONFIG_E 0x1D
|
||||
#define ADP5589_GPI_INT_LEVEL_A 0x1E
|
||||
#define ADP5589_GPI_INT_LEVEL_B 0x1F
|
||||
#define ADP5589_GPI_INT_LEVEL_C 0x20
|
||||
#define ADP5589_GPI_EVENT_EN_A 0x21
|
||||
#define ADP5589_GPI_EVENT_EN_B 0x22
|
||||
#define ADP5589_GPI_EVENT_EN_C 0x23
|
||||
#define ADP5589_GPI_INTERRUPT_EN_A 0x24
|
||||
#define ADP5589_GPI_INTERRUPT_EN_B 0x25
|
||||
#define ADP5589_GPI_INTERRUPT_EN_C 0x26
|
||||
#define ADP5589_DEBOUNCE_DIS_A 0x27
|
||||
#define ADP5589_DEBOUNCE_DIS_B 0x28
|
||||
#define ADP5589_DEBOUNCE_DIS_C 0x29
|
||||
#define ADP5589_GPO_DATA_OUT_A 0x2A
|
||||
#define ADP5589_GPO_DATA_OUT_B 0x2B
|
||||
#define ADP5589_GPO_DATA_OUT_C 0x2C
|
||||
#define ADP5589_GPO_OUT_MODE_A 0x2D
|
||||
#define ADP5589_GPO_OUT_MODE_B 0x2E
|
||||
#define ADP5589_GPO_OUT_MODE_C 0x2F
|
||||
#define ADP5589_GPIO_DIRECTION_A 0x30
|
||||
#define ADP5589_GPIO_DIRECTION_B 0x31
|
||||
#define ADP5589_GPIO_DIRECTION_C 0x32
|
||||
#define ADP5589_UNLOCK1 0x33
|
||||
#define ADP5589_UNLOCK2 0x34
|
||||
#define ADP5589_EXT_LOCK_EVENT 0x35
|
||||
#define ADP5589_UNLOCK_TIMERS 0x36
|
||||
#define ADP5589_LOCK_CFG 0x37
|
||||
#define ADP5589_RESET1_EVENT_A 0x38
|
||||
#define ADP5589_RESET1_EVENT_B 0x39
|
||||
#define ADP5589_RESET1_EVENT_C 0x3A
|
||||
#define ADP5589_RESET2_EVENT_A 0x3B
|
||||
#define ADP5589_RESET2_EVENT_B 0x3C
|
||||
#define ADP5589_RESET_CFG 0x3D
|
||||
#define ADP5589_PWM_OFFT_LOW 0x3E
|
||||
#define ADP5589_PWM_OFFT_HIGH 0x3F
|
||||
#define ADP5589_PWM_ONT_LOW 0x40
|
||||
#define ADP5589_PWM_ONT_HIGH 0x41
|
||||
#define ADP5589_PWM_CFG 0x42
|
||||
#define ADP5589_CLOCK_DIV_CFG 0x43
|
||||
#define ADP5589_LOGIC_1_CFG 0x44
|
||||
#define ADP5589_LOGIC_2_CFG 0x45
|
||||
#define ADP5589_LOGIC_FF_CFG 0x46
|
||||
#define ADP5589_LOGIC_INT_EVENT_EN 0x47
|
||||
#define ADP5589_POLL_PTIME_CFG 0x48
|
||||
#define ADP5589_PIN_CONFIG_A 0x49
|
||||
#define ADP5589_PIN_CONFIG_B 0x4A
|
||||
#define ADP5589_PIN_CONFIG_C 0x4B
|
||||
#define ADP5589_PIN_CONFIG_D 0x4C
|
||||
#define ADP5589_GENERAL_CFG 0x4D
|
||||
#define ADP5589_INT_EN 0x4E
|
||||
|
||||
#define ADP5589_DEVICE_ID_MASK 0xF
|
||||
|
||||
/* Put one of these structures in i2c_board_info platform_data */
|
||||
/*
|
||||
* ADP5589 specific GPI and Keymap defines
|
||||
*/
|
||||
|
||||
#define ADP5589_KEYMAPSIZE 88
|
||||
|
||||
|
@ -127,6 +47,35 @@
|
|||
|
||||
#define ADP5589_GPIMAPSIZE_MAX (ADP5589_GPI_PIN_END - ADP5589_GPI_PIN_BASE + 1)
|
||||
|
||||
/*
|
||||
* ADP5585 specific GPI and Keymap defines
|
||||
*/
|
||||
|
||||
#define ADP5585_KEYMAPSIZE 30
|
||||
|
||||
#define ADP5585_GPI_PIN_ROW0 37
|
||||
#define ADP5585_GPI_PIN_ROW1 38
|
||||
#define ADP5585_GPI_PIN_ROW2 39
|
||||
#define ADP5585_GPI_PIN_ROW3 40
|
||||
#define ADP5585_GPI_PIN_ROW4 41
|
||||
#define ADP5585_GPI_PIN_ROW5 42
|
||||
#define ADP5585_GPI_PIN_COL0 43
|
||||
#define ADP5585_GPI_PIN_COL1 44
|
||||
#define ADP5585_GPI_PIN_COL2 45
|
||||
#define ADP5585_GPI_PIN_COL3 46
|
||||
#define ADP5585_GPI_PIN_COL4 47
|
||||
#define GPI_LOGIC 48
|
||||
|
||||
#define ADP5585_GPI_PIN_ROW_BASE ADP5585_GPI_PIN_ROW0
|
||||
#define ADP5585_GPI_PIN_ROW_END ADP5585_GPI_PIN_ROW5
|
||||
#define ADP5585_GPI_PIN_COL_BASE ADP5585_GPI_PIN_COL0
|
||||
#define ADP5585_GPI_PIN_COL_END ADP5585_GPI_PIN_COL4
|
||||
|
||||
#define ADP5585_GPI_PIN_BASE ADP5585_GPI_PIN_ROW_BASE
|
||||
#define ADP5585_GPI_PIN_END ADP5585_GPI_PIN_COL_END
|
||||
|
||||
#define ADP5585_GPIMAPSIZE_MAX (ADP5585_GPI_PIN_END - ADP5585_GPI_PIN_BASE + 1)
|
||||
|
||||
struct adp5589_gpi_map {
|
||||
unsigned short pin;
|
||||
unsigned short sw_evt;
|
||||
|
@ -159,7 +108,7 @@ struct adp5589_gpi_map {
|
|||
#define RESET2_POL_HIGH (1 << 7)
|
||||
#define RESET2_POL_LOW (0 << 7)
|
||||
|
||||
/* Mask Bits:
|
||||
/* ADP5589 Mask Bits:
|
||||
* C C C C C C C C C C C | R R R R R R R R
|
||||
* 1 9 8 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0
|
||||
* 0
|
||||
|
@ -170,16 +119,42 @@ struct adp5589_gpi_map {
|
|||
|
||||
#define ADP_ROW(x) (1 << (x))
|
||||
#define ADP_COL(x) (1 << (x + 8))
|
||||
#define ADP5589_ROW_MASK 0xFF
|
||||
#define ADP5589_COL_MASK 0xFF
|
||||
#define ADP5589_COL_SHIFT 8
|
||||
#define ADP5589_MAX_ROW_NUM 7
|
||||
#define ADP5589_MAX_COL_NUM 10
|
||||
|
||||
/* ADP5585 Mask Bits:
|
||||
* C C C C C | R R R R R R
|
||||
* 4 3 2 1 0 | 5 4 3 2 1 0
|
||||
*
|
||||
* ---- BIT -- -----------
|
||||
* 1 0 0 0 0 | 0 0 0 0 0 0
|
||||
* 0 9 8 7 6 | 5 4 3 2 1 0
|
||||
*/
|
||||
|
||||
#define ADP5585_ROW_MASK 0x3F
|
||||
#define ADP5585_COL_MASK 0x1F
|
||||
#define ADP5585_ROW_SHIFT 0
|
||||
#define ADP5585_COL_SHIFT 6
|
||||
#define ADP5585_MAX_ROW_NUM 5
|
||||
#define ADP5585_MAX_COL_NUM 4
|
||||
|
||||
#define ADP5585_ROW(x) (1 << ((x) & ADP5585_ROW_MASK))
|
||||
#define ADP5585_COL(x) (1 << (((x) & ADP5585_COL_MASK) + ADP5585_COL_SHIFT))
|
||||
|
||||
/* Put one of these structures in i2c_board_info platform_data */
|
||||
|
||||
struct adp5589_kpad_platform_data {
|
||||
unsigned keypad_en_mask; /* Keypad (Rows/Columns) enable mask */
|
||||
const unsigned short *keymap; /* Pointer to keymap */
|
||||
unsigned short keymapsize; /* Keymap size */
|
||||
bool repeat; /* Enable key repeat */
|
||||
bool en_keylock; /* Enable key lock feature */
|
||||
unsigned char unlock_key1; /* Unlock Key 1 */
|
||||
unsigned char unlock_key2; /* Unlock Key 2 */
|
||||
unsigned char unlock_timer; /* Time in seconds [0..7] between the two unlock keys 0=disable */
|
||||
bool en_keylock; /* Enable key lock feature (ADP5589 only)*/
|
||||
unsigned char unlock_key1; /* Unlock Key 1 (ADP5589 only) */
|
||||
unsigned char unlock_key2; /* Unlock Key 2 (ADP5589 only) */
|
||||
unsigned char unlock_timer; /* Time in seconds [0..7] between the two unlock keys 0=disable (ADP5589 only) */
|
||||
unsigned char scan_cycle_time; /* Time between consecutive scan cycles */
|
||||
unsigned char reset_cfg; /* Reset config */
|
||||
unsigned short reset1_key_1; /* Reset Key 1 */
|
||||
|
|
|
@ -30,8 +30,9 @@ struct adxl34x_platform_data {
|
|||
* Y, or Z participation in Tap detection. A '0' excludes the
|
||||
* selected axis from participation in Tap detection.
|
||||
* Setting the SUPPRESS bit suppresses Double Tap detection if
|
||||
* acceleration greater than tap_threshold is present between
|
||||
* taps.
|
||||
* acceleration greater than tap_threshold is present during the
|
||||
* tap_latency period, i.e. after the first tap but before the
|
||||
* opening of the second tap window.
|
||||
*/
|
||||
|
||||
#define ADXL_SUPPRESS (1 << 3)
|
||||
|
@ -226,13 +227,13 @@ struct adxl34x_platform_data {
|
|||
* detection will begin and prevent the detection of activity. This
|
||||
* bit serially links the activity and inactivity functions. When '0'
|
||||
* the inactivity and activity functions are concurrent. Additional
|
||||
* information can be found in the Application section under Link
|
||||
* Mode.
|
||||
* information can be found in the ADXL34x datasheet's Application
|
||||
* section under Link Mode.
|
||||
* AUTO_SLEEP: A '1' sets the ADXL34x to switch to Sleep Mode
|
||||
* when inactivity (acceleration has been below inactivity_threshold
|
||||
* for at least inactivity_time) is detected and the LINK bit is set.
|
||||
* A '0' disables automatic switching to Sleep Mode. See SLEEP
|
||||
* for further description.
|
||||
* A '0' disables automatic switching to Sleep Mode. See the
|
||||
* Sleep Bit section of the ADXL34x datasheet for more information.
|
||||
*/
|
||||
|
||||
#define ADXL_LINK (1 << 5)
|
||||
|
@ -266,6 +267,12 @@ struct adxl34x_platform_data {
|
|||
|
||||
u8 watermark;
|
||||
|
||||
/*
|
||||
* When acceleration measurements are received from the ADXL34x
|
||||
* events are sent to the event subsystem. The following settings
|
||||
* select the event type and event code for new x, y and z axis data
|
||||
* respectively.
|
||||
*/
|
||||
u32 ev_type; /* EV_ABS or EV_REL */
|
||||
|
||||
u32 ev_code_x; /* ABS_X,Y,Z or REL_X,Y,Z */
|
||||
|
@ -289,7 +296,7 @@ struct adxl34x_platform_data {
|
|||
u32 ev_code_act_inactivity; /* EV_KEY */
|
||||
|
||||
/*
|
||||
* Use ADXL34x INT2 instead of INT1
|
||||
* Use ADXL34x INT2 pin instead of INT1 pin for interrupt output
|
||||
*/
|
||||
u8 use_int2;
|
||||
|
||||
|
|
|
@ -199,5 +199,6 @@ static inline void serio_continue_rx(struct serio *serio)
|
|||
#define SERIO_DYNAPRO 0x3a
|
||||
#define SERIO_HAMPSHIRE 0x3b
|
||||
#define SERIO_PS2MULT 0x3c
|
||||
#define SERIO_TSC40 0x3d
|
||||
|
||||
#endif
|
||||
|
|
|
@ -68,7 +68,7 @@ struct uinput_device {
|
|||
unsigned char head;
|
||||
unsigned char tail;
|
||||
struct input_event buff[UINPUT_BUFFER_SIZE];
|
||||
int ff_effects_max;
|
||||
unsigned int ff_effects_max;
|
||||
|
||||
struct uinput_request *requests[UINPUT_NUM_REQUESTS];
|
||||
wait_queue_head_t requests_waitq;
|
||||
|
|
Loading…
Reference in a new issue