提交 dbe950f2 编写于 作者: L Linus Torvalds

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: (64 commits)
  Input: tc3589x-keypad - add missing kerneldoc
  Input: ucb1400-ts - switch to using dev_xxx() for diagnostic messages
  Input: ucb1400_ts - convert to threaded IRQ
  Input: ucb1400_ts - drop inline annotations
  Input: usb1400_ts - add __devinit/__devexit section annotations
  Input: ucb1400_ts - set driver owner
  Input: ucb1400_ts - convert to use dev_pm_ops
  Input: psmouse - make sure we do not use stale methods
  Input: evdev - do not block waiting for an event if fd is nonblock
  Input: evdev - if no events and non-block, return EAGAIN not 0
  Input: evdev - only allow reading events if a full packet is present
  Input: add driver for pixcir i2c touchscreens
  Input: samsung-keypad - implement runtime power management support
  Input: tegra-kbc - report wakeup key for some platforms
  Input: tegra-kbc - add device tree bindings
  Input: add driver for AUO In-Cell touchscreens using pixcir ICs
  Input: mpu3050 - configure the sampling method
  Input: mpu3050 - ensure we enable interrupts
  Input: mpu3050 - add of_match table for device-tree probing
  Input: sentelic - document the latest hardware
  ...

Fix up fairly trivial conflicts (device tree matching conflicting with
some independent cleanups) in drivers/input/keyboard/samsung-keypad.c
......@@ -15,9 +15,9 @@ 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.
and XL (with LEDs and OLEDs) and Cintiq 21UX2 and Cintiq 24HD
(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
......@@ -41,16 +41,17 @@ 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.
or of the right four (for Cintiq 21UX2 and Cintiq 24HD) 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.
Writing to this file sets which one of the left four (for Cintiq 21UX2
and Cintiq 24HD) 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
......
* Tegra keyboard controller
Required properties:
- compatible: "nvidia,tegra20-kbc"
Optional properties:
- debounce-delay: delay in milliseconds per row scan for debouncing
- repeat-delay: delay in milliseconds before repeat starts
- ghost-filter: enable ghost filtering for this device
- wakeup-source: configure keyboard as a wakeup source for suspend/resume
Example:
keyboard: keyboard {
compatible = "nvidia,tegra20-kbc";
reg = <0x7000e200 0x100>;
ghost-filter;
};
ALPS Touchpad Protocol
----------------------
Introduction
------------
Currently the ALPS touchpad driver supports four protocol versions in use by
ALPS touchpads, called versions 1, 2, 3, and 4. Information about the various
protocol versions is contained in the following sections.
Detection
---------
All ALPS touchpads should respond to the "E6 report" command sequence:
E8-E6-E6-E6-E9. An ALPS touchpad should respond with either 00-00-0A or
00-00-64.
If the E6 report is successful, the touchpad model is identified using the "E7
report" sequence: E8-E7-E7-E7-E9. The response is the model signature and is
matched against known models in the alps_model_data_array.
With protocol versions 3 and 4, the E7 report model signature is always
73-02-64. To differentiate between these versions, the response from the
"Enter Command Mode" sequence must be inspected as described below.
Command Mode
------------
Protocol versions 3 and 4 have a command mode that is used to read and write
one-byte device registers in a 16-bit address space. The command sequence
EC-EC-EC-E9 places the device in command mode, and the device will respond
with 88-07 followed by a third byte. This third byte can be used to determine
whether the devices uses the version 3 or 4 protocol.
To exit command mode, PSMOUSE_CMD_SETSTREAM (EA) is sent to the touchpad.
While in command mode, register addresses can be set by first sending a
specific command, either EC for v3 devices or F5 for v4 devices. Then the
address is sent one nibble at a time, where each nibble is encoded as a
command with optional data. This enoding differs slightly between the v3 and
v4 protocols.
Once an address has been set, the addressed register can be read by sending
PSMOUSE_CMD_GETINFO (E9). The first two bytes of the response contains the
address of the register being read, and the third contains the value of the
register. Registers are written by writing the value one nibble at a time
using the same encoding used for addresses.
Packet Format
-------------
In the following tables, the following notation is used.
CAPITALS = stick, miniscules = touchpad
?'s can have different meanings on different models, such as wheel rotation,
extra buttons, stick buttons on a dualpoint, etc.
PS/2 packet format
------------------
byte 0: 0 0 YSGN XSGN 1 M R L
byte 1: X7 X6 X5 X4 X3 X2 X1 X0
byte 2: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
Note that the device never signals overflow condition.
ALPS Absolute Mode - Protocol Verion 1
--------------------------------------
byte 0: 1 0 0 0 1 x9 x8 x7
byte 1: 0 x6 x5 x4 x3 x2 x1 x0
byte 2: 0 ? ? l r ? fin ges
byte 3: 0 ? ? ? ? y9 y8 y7
byte 4: 0 y6 y5 y4 y3 y2 y1 y0
byte 5: 0 z6 z5 z4 z3 z2 z1 z0
ALPS Absolute Mode - Protocol Version 2
---------------------------------------
byte 0: 1 ? ? ? 1 ? ? ?
byte 1: 0 x6 x5 x4 x3 x2 x1 x0
byte 2: 0 x10 x9 x8 x7 ? fin ges
byte 3: 0 y9 y8 y7 1 M R L
byte 4: 0 y6 y5 y4 y3 y2 y1 y0
byte 5: 0 z6 z5 z4 z3 z2 z1 z0
Dualpoint device -- interleaved packet format
---------------------------------------------
byte 0: 1 1 0 0 1 1 1 1
byte 1: 0 x6 x5 x4 x3 x2 x1 x0
byte 2: 0 x10 x9 x8 x7 0 fin ges
byte 3: 0 0 YSGN XSGN 1 1 1 1
byte 4: X7 X6 X5 X4 X3 X2 X1 X0
byte 5: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
byte 6: 0 y9 y8 y7 1 m r l
byte 7: 0 y6 y5 y4 y3 y2 y1 y0
byte 8: 0 z6 z5 z4 z3 z2 z1 z0
ALPS Absolute Mode - Protocol Version 3
---------------------------------------
ALPS protocol version 3 has three different packet formats. The first two are
associated with touchpad events, and the third is associatd with trackstick
events.
The first type is the touchpad position packet.
byte 0: 1 ? x1 x0 1 1 1 1
byte 1: 0 x10 x9 x8 x7 x6 x5 x4
byte 2: 0 y10 y9 y8 y7 y6 y5 y4
byte 3: 0 M R L 1 m r l
byte 4: 0 mt x3 x2 y3 y2 y1 y0
byte 5: 0 z6 z5 z4 z3 z2 z1 z0
Note that for some devices the trackstick buttons are reported in this packet,
and on others it is reported in the trackstick packets.
The second packet type contains bitmaps representing the x and y axes. In the
bitmaps a given bit is set if there is a finger covering that position on the
given axis. Thus the bitmap packet can be used for low-resolution multi-touch
data, although finger tracking is not possible. This packet also encodes the
number of contacts (f1 and f0 in the table below).
byte 0: 1 1 x1 x0 1 1 1 1
byte 1: 0 x8 x7 x6 x5 x4 x3 x2
byte 2: 0 y7 y6 y5 y4 y3 y2 y1
byte 3: 0 y10 y9 y8 1 1 1 1
byte 4: 0 x14 x13 x12 x11 x10 x9 y0
byte 5: 0 1 ? ? ? ? f1 f0
This packet only appears after a position packet with the mt bit set, and
ususally only appears when there are two or more contacts (although
ocassionally it's seen with only a single contact).
The final v3 packet type is the trackstick packet.
byte 0: 1 1 x7 y7 1 1 1 1
byte 1: 0 x6 x5 x4 x3 x2 x1 x0
byte 2: 0 y6 y5 y4 y3 y2 y1 y0
byte 3: 0 1 0 0 1 0 0 0
byte 4: 0 z4 z3 z2 z1 z0 ? ?
byte 5: 0 0 1 1 1 1 1 1
ALPS Absolute Mode - Protocol Version 4
---------------------------------------
Protocol version 4 has an 8-byte packet format.
byte 0: 1 ? x1 x0 1 1 1 1
byte 1: 0 x10 x9 x8 x7 x6 x5 x4
byte 2: 0 y10 y9 y8 y7 y6 y5 y4
byte 3: 0 1 x3 x2 y3 y2 y1 y0
byte 4: 0 ? ? ? 1 ? r l
byte 5: 0 z6 z5 z4 z3 z2 z1 z0
byte 6: bitmap data (described below)
byte 7: bitmap data (described below)
The last two bytes represent a partial bitmap packet, with 3 full packets
required to construct a complete bitmap packet. Once assembled, the 6-byte
bitmap packet has the following format:
byte 0: 0 1 x7 x6 x5 x4 x3 x2
byte 1: 0 x1 x0 y4 y3 y2 y1 y0
byte 2: 0 0 ? x14 x13 x12 x11 x10
byte 3: 0 x9 x8 y9 y8 y7 y6 y5
byte 4: 0 0 0 0 0 0 0 0
byte 5: 0 0 0 0 0 0 0 y10
There are several things worth noting here.
1) In the bitmap data, bit 6 of byte 0 serves as a sync byte to
identify the first fragment of a bitmap packet.
2) The bitmaps represent the same data as in the v3 bitmap packets, although
the packet layout is different.
3) There doesn't seem to be a count of the contact points anywhere in the v4
protocol packets. Deriving a count of contact points must be done by
analyzing the bitmaps.
4) There is a 3 to 1 ratio of position packets to bitmap packets. Therefore
MT position can only be updated for every third ST position update, and
the count of contact points can only be updated every third packet as
well.
So far no v4 devices with tracksticks have been encountered.
Driver for tilt-switches connected via GPIOs
============================================
Generic driver to read data from tilt switches connected via gpios.
Orientation can be provided by one or more than one tilt switches,
i.e. each tilt switch providing one axis, and the number of axes
is also not limited.
Data structures:
----------------
The array of struct gpio in the gpios field is used to list the gpios
that represent the current tilt state.
The array of struct gpio_tilt_axis describes the axes that are reported
to the input system. The values set therein are used for the
input_set_abs_params calls needed to init the axes.
The array of struct gpio_tilt_state maps gpio states to the corresponding
values to report. The gpio state is represented as a bitfield where the
bit-index corresponds to the index of the gpio in the struct gpio array.
In the same manner the values stored in the axes array correspond to
the elements of the gpio_tilt_axis-array.
Example:
--------
Example configuration for a single TS1003 tilt switch that rotates around
one axis in 4 steps and emitts the current tilt via two GPIOs.
static int sg060_tilt_enable(struct device *dev) {
/* code to enable the sensors */
};
static void sg060_tilt_disable(struct device *dev) {
/* code to disable the sensors */
};
static struct gpio sg060_tilt_gpios[] = {
{ SG060_TILT_GPIO_SENSOR1, GPIOF_IN, "tilt_sensor1" },
{ SG060_TILT_GPIO_SENSOR2, GPIOF_IN, "tilt_sensor2" },
};
static struct gpio_tilt_state sg060_tilt_states[] = {
{
.gpios = (0 << 1) | (0 << 0),
.axes = (int[]) {
0,
},
}, {
.gpios = (0 << 1) | (1 << 0),
.axes = (int[]) {
1, /* 90 degrees */
},
}, {
.gpios = (1 << 1) | (1 << 0),
.axes = (int[]) {
2, /* 180 degrees */
},
}, {
.gpios = (1 << 1) | (0 << 0),
.axes = (int[]) {
3, /* 270 degrees */
},
},
};
static struct gpio_tilt_axis sg060_tilt_axes[] = {
{
.axis = ABS_RY,
.min = 0,
.max = 3,
.fuzz = 0,
.flat = 0,
},
};
static struct gpio_tilt_platform_data sg060_tilt_pdata= {
.gpios = sg060_tilt_gpios,
.nr_gpios = ARRAY_SIZE(sg060_tilt_gpios),
.axes = sg060_tilt_axes,
.nr_axes = ARRAY_SIZE(sg060_tilt_axes),
.states = sg060_tilt_states,
.nr_states = ARRAY_SIZE(sg060_tilt_states),
.debounce_interval = 100,
.poll_interval = 1000,
.enable = sg060_tilt_enable,
.disable = sg060_tilt_disable,
};
static struct platform_device sg060_device_tilt = {
.name = "gpio-tilt-polled",
.id = -1,
.dev = {
.platform_data = &sg060_tilt_pdata,
},
};
Copyright (C) 2002-2010 Sentelic Corporation.
Last update: Jan-13-2010
Copyright (C) 2002-2011 Sentelic Corporation.
Last update: Dec-07-2011
==============================================================================
* Finger Sensing Pad Intellimouse Mode(scrolling wheel, 4th and 5th buttons)
......@@ -140,6 +140,7 @@ BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------
Byte 1: Bit7~Bit6 => 00, Normal data packet
=> 01, Absolute coordination packet
=> 10, Notify packet
=> 11, Normal data packet with on-pad click
Bit5 => Valid bit, 0 means that the coordinate is invalid or finger up.
When both fingers are up, the last two reports have zero valid
bit.
......@@ -164,6 +165,7 @@ BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------
Byte 1: Bit7~Bit6 => 00, Normal data packet
=> 01, Absolute coordinates packet
=> 10, Notify packet
=> 11, Normal data packet with on-pad click
Bit5 => Valid bit, 0 means that the coordinate is invalid or finger up.
When both fingers are up, the last two reports have zero valid
bit.
......@@ -188,6 +190,7 @@ BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------
Byte 1: Bit7~Bit6 => 00, Normal data packet
=> 01, Absolute coordinates packet
=> 10, Notify packet
=> 11, Normal data packet with on-pad click
Bit5 => 1
Bit4 => when in absolute coordinates mode (valid when EN_PKT_GO is 1):
0: left button is generated by the on-pad command
......@@ -205,7 +208,7 @@ Byte 4: Bit7 => scroll right button
Bit6 => scroll left button
Bit5 => scroll down button
Bit4 => scroll up button
* Note that if gesture and additional buttoni (Bit4~Bit7)
* Note that if gesture and additional button (Bit4~Bit7)
happen at the same time, the button information will not
be sent.
Bit3~Bit0 => Reserved
......@@ -227,6 +230,7 @@ BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------
Byte 1: Bit7~Bit6 => 00, Normal data packet
=> 01, Absolute coordinates packet
=> 10, Notify packet
=> 11, Normal data packet with on-pad click
Bit5 => Valid bit, 0 means that the coordinate is invalid or finger up.
When both fingers are up, the last two reports have zero valid
bit.
......@@ -253,6 +257,7 @@ BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------
Byte 1: Bit7~Bit6 => 00, Normal data packet
=> 01, Absolute coordination packet
=> 10, Notify packet
=> 11, Normal data packet with on-pad click
Bit5 => Valid bit, 0 means that the coordinate is invalid or finger up.
When both fingers are up, the last two reports have zero valid
bit.
......@@ -279,8 +284,9 @@ BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------
Byte 1: Bit7~Bit6 => 00, Normal data packet
=> 01, Absolute coordination packet
=> 10, Notify packet
=> 11, Normal data packet with on-pad click
Bit5 => 1
Bit4 => when in absolute coordinate mode (valid when EN_PKT_GO is 1):
Bit4 => when in absolute coordinates mode (valid when EN_PKT_GO is 1):
0: left button is generated by the on-pad command
1: left button is generated by the external button
Bit3 => 1
......@@ -306,6 +312,110 @@ Sample sequence of Multi-finger, Multi-coordinate mode:
notify packet (valid bit == 1), abs pkt 1, abs pkt 2, abs pkt 1,
abs pkt 2, ..., notify packet (valid bit == 0)
==============================================================================
* Absolute position for STL3888-Cx and STL3888-Dx.
==============================================================================
Single Finger, Absolute Coordinate Mode (SFAC)
Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
1 |0|1|0|P|1|M|R|L| 2 |X|X|X|X|X|X|X|X| 3 |Y|Y|Y|Y|Y|Y|Y|Y| 4 |r|l|B|F|X|X|Y|Y|
|---------------| |---------------| |---------------| |---------------|
Byte 1: Bit7~Bit6 => 00, Normal data packet
=> 01, Absolute coordinates packet
=> 10, Notify packet
Bit5 => Coordinate mode(always 0 in SFAC mode):
0: single-finger absolute coordinates (SFAC) mode
1: multi-finger, multiple coordinates (MFMC) mode
Bit4 => 0: The LEFT button is generated by on-pad command (OPC)
1: The LEFT button is generated by external button
Default is 1 even if the LEFT button is not pressed.
Bit3 => Always 1, as specified by PS/2 protocol.
Bit2 => Middle Button, 1 is pressed, 0 is not pressed.
Bit1 => Right Button, 1 is pressed, 0 is not pressed.
Bit0 => Left Button, 1 is pressed, 0 is not pressed.
Byte 2: X coordinate (xpos[9:2])
Byte 3: Y coordinate (ypos[9:2])
Byte 4: Bit1~Bit0 => Y coordinate (xpos[1:0])
Bit3~Bit2 => X coordinate (ypos[1:0])
Bit4 => 4th mouse button(forward one page)
Bit5 => 5th mouse button(backward one page)
Bit6 => scroll left button
Bit7 => scroll right button
Multi Finger, Multiple Coordinates Mode (MFMC):
Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
1 |0|1|1|P|1|F|R|L| 2 |X|X|X|X|X|X|X|X| 3 |Y|Y|Y|Y|Y|Y|Y|Y| 4 |r|l|B|F|X|X|Y|Y|
|---------------| |---------------| |---------------| |---------------|
Byte 1: Bit7~Bit6 => 00, Normal data packet
=> 01, Absolute coordination packet
=> 10, Notify packet
Bit5 => Coordinate mode (always 1 in MFMC mode):
0: single-finger absolute coordinates (SFAC) mode
1: multi-finger, multiple coordinates (MFMC) mode
Bit4 => 0: The LEFT button is generated by on-pad command (OPC)
1: The LEFT button is generated by external button
Default is 1 even if the LEFT button is not pressed.
Bit3 => Always 1, as specified by PS/2 protocol.
Bit2 => Finger index, 0 is the first finger, 1 is the second finger.
If bit 1 and 0 are all 1 and bit 4 is 0, the middle external
button is pressed.
Bit1 => Right Button, 1 is pressed, 0 is not pressed.
Bit0 => Left Button, 1 is pressed, 0 is not pressed.
Byte 2: X coordinate (xpos[9:2])
Byte 3: Y coordinate (ypos[9:2])
Byte 4: Bit1~Bit0 => Y coordinate (xpos[1:0])
Bit3~Bit2 => X coordinate (ypos[1:0])
Bit4 => 4th mouse button(forward one page)
Bit5 => 5th mouse button(backward one page)
Bit6 => scroll left button
Bit7 => scroll right button
When one of the two fingers is up, the device will output four consecutive
MFMC#0 report packets with zero X and Y to represent 1st finger is up or
four consecutive MFMC#1 report packets with zero X and Y to represent that
the 2nd finger is up. On the other hand, if both fingers are up, the device
will output four consecutive single-finger, absolute coordinate(SFAC) packets
with zero X and Y.
Notify Packet for STL3888-Cx/Dx
Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
1 |1|0|0|P|1|M|R|L| 2 |C|C|C|C|C|C|C|C| 3 |0|0|F|F|0|0|0|i| 4 |r|l|u|d|0|0|0|0|
|---------------| |---------------| |---------------| |---------------|
Byte 1: Bit7~Bit6 => 00, Normal data packet
=> 01, Absolute coordinates packet
=> 10, Notify packet
Bit5 => Always 0
Bit4 => 0: The LEFT button is generated by on-pad command(OPC)
1: The LEFT button is generated by external button
Default is 1 even if the LEFT button is not pressed.
Bit3 => 1
Bit2 => Middle Button, 1 is pressed, 0 is not pressed.
Bit1 => Right Button, 1 is pressed, 0 is not pressed.
Bit0 => Left Button, 1 is pressed, 0 is not pressed.
Byte 2: Message type:
0xba => gesture information
0xc0 => one finger hold-rotating gesture
Byte 3: The first parameter for the received message:
0xba => gesture ID (refer to the 'Gesture ID' section)
0xc0 => region ID
Byte 4: The second parameter for the received message:
0xba => N/A
0xc0 => finger up/down information
Sample sequence of Multi-finger, Multi-coordinates mode:
notify packet (valid bit == 1), MFMC packet 1 (byte 1, bit 2 == 0),
MFMC packet 2 (byte 1, bit 2 == 1), MFMC packet 1, MFMC packet 2,
..., notify packet (valid bit == 0)
That is, when the device is in MFMC mode, the host will receive
interleaved absolute coordinate packets for each finger.
==============================================================================
* FSP Enable/Disable packet
==============================================================================
......@@ -348,9 +458,10 @@ http://www.computer-engineering.org/ps2mouse/
==============================================================================
1. Identify FSP by reading device ID(0x00) and version(0x01) register
2. Determine number of buttons by reading status2 (0x0b) register
2a. For FSP version < STL3888 Cx, determine number of buttons by reading
the 'test mode status' (0x20) register:
buttons = reg[0x0b] & 0x30
buttons = reg[0x20] & 0x30
if buttons == 0x30 or buttons == 0x20:
# two/four buttons
......@@ -365,6 +476,10 @@ http://www.computer-engineering.org/ps2mouse/
Refer to 'Finger Sensing Pad PS/2 Mouse Intellimouse'
section A for packet parsing detail
2b. For FSP version >= STL3888 Cx:
Refer to 'Finger Sensing Pad PS/2 Mouse Intellimouse'
section A for packet parsing detail (ignore byte 4, bit ~ 7)
==============================================================================
* Programming Sequence for Register Reading/Writing
==============================================================================
......@@ -374,7 +489,7 @@ Register inversion requirement:
Following values needed to be inverted(the '~' operator in C) before being
sent to FSP:
0xe9, 0xee, 0xf2 and 0xff.
0xe8, 0xe9, 0xee, 0xf2, 0xf3 and 0xff.
Register swapping requirement:
......@@ -415,7 +530,18 @@ Register reading sequence:
8. send 0xe9(status request) PS/2 command to FSP;
9. the response read from FSP should be the requested register value.
9. the 4th byte of the response read from FSP should be the
requested register value(?? indicates don't care byte):
host: 0xe9
3888: 0xfa (??) (??) (val)
* Note that since the Cx release, the hardware will return 1's
complement of the register value at the 3rd byte of status request
result:
host: 0xe9
3888: 0xfa (??) (~val) (val)
Register writing sequence:
......@@ -465,71 +591,194 @@ Register writing sequence:
9. the register writing sequence is completed.
* Note that since the Cx release, the hardware will return 1's
complement of the register value at the 3rd byte of status request
result. Host can optionally send another 0xe9 (status request) PS/2
command to FSP at the end of register writing to verify that the
register writing operation is successful (?? indicates don't care
byte):
host: 0xe9
3888: 0xfa (??) (~val) (val)
==============================================================================
* Programming Sequence for Page Register Reading/Writing
==============================================================================
In order to overcome the limitation of maximum number of registers
supported, the hardware separates register into different groups called
'pages.' Each page is able to include up to 255 registers.
The default page after power up is 0x82; therefore, if one has to get
access to register 0x8301, one has to use following sequence to switch
to page 0x83, then start reading/writing from/to offset 0x01 by using
the register read/write sequence described in previous section.
Page register reading sequence:
1. send 0xf3 PS/2 command to FSP;
2. send 0x66 PS/2 command to FSP;
3. send 0x88 PS/2 command to FSP;
4. send 0xf3 PS/2 command to FSP;
5. send 0x83 PS/2 command to FSP;
6. send 0x88 PS/2 command to FSP;
7. send 0xe9(status request) PS/2 command to FSP;
8. the response read from FSP should be the requested page value.
Page register writing sequence:
1. send 0xf3 PS/2 command to FSP;
2. send 0x38 PS/2 command to FSP;
3. send 0x88 PS/2 command to FSP;
4. send 0xf3 PS/2 command to FSP;
5. if the page address being written is not required to be
inverted(refer to the 'Register inversion requirement' section),
goto step 6
5a. send 0x47 PS/2 command to FSP;
5b. send the inverted page address to FSP and goto step 9;
6. if the page address being written is not required to be
swapped(refer to the 'Register swapping requirement' section),
goto step 7
6a. send 0x44 PS/2 command to FSP;
6b. send the swapped page address to FSP and goto step 9;
7. send 0x33 PS/2 command to FSP;
8. send the page address to FSP;
9. the page register writing sequence is completed.
==============================================================================
* Gesture ID
==============================================================================
Unlike other devices which sends multiple fingers' coordinates to host,
FSP processes multiple fingers' coordinates internally and convert them
into a 8 bits integer, namely 'Gesture ID.' Following is a list of
supported gesture IDs:
ID Description
0x86 2 finger straight up
0x82 2 finger straight down
0x80 2 finger straight right
0x84 2 finger straight left
0x8f 2 finger zoom in
0x8b 2 finger zoom out
0xc0 2 finger curve, counter clockwise
0xc4 2 finger curve, clockwise
0x2e 3 finger straight up
0x2a 3 finger straight down
0x28 3 finger straight right
0x2c 3 finger straight left
0x38 palm
==============================================================================
* Register Listing
==============================================================================
Registers are represented in 16 bits values. The higher 8 bits represent
the page address and the lower 8 bits represent the relative offset within
that particular page. Refer to the 'Programming Sequence for Page Register
Reading/Writing' section for instructions on how to change current page
address.
offset width default r/w name
0x00 bit7~bit0 0x01 RO device ID
0x8200 bit7~bit0 0x01 RO device ID
0x01 bit7~bit0 0xc0 RW version ID
0x8201 bit7~bit0 RW version ID
0xc1: STL3888 Ax
0xd0 ~ 0xd2: STL3888 Bx
0xe0 ~ 0xe1: STL3888 Cx
0xe2 ~ 0xe3: STL3888 Dx
0x02 bit7~bit0 0x01 RO vendor ID
0x8202 bit7~bit0 0x01 RO vendor ID
0x03 bit7~bit0 0x01 RO product ID
0x8203 bit7~bit0 0x01 RO product ID
0x04 bit3~bit0 0x01 RW revision ID
0x8204 bit3~bit0 0x01 RW revision ID
0x0b RO test mode status 1
bit3 1 RO 0: rotate 180 degree, 1: no rotation
0x820b test mode status 1
bit3 1 RO 0: rotate 180 degree
1: no rotation
*only supported by H/W prior to Cx
bit5~bit4 RO number of buttons
11 => 2, lbtn/rbtn
10 => 4, lbtn/rbtn/scru/scrd
01 => 6, lbtn/rbtn/scru/scrd/scrl/scrr
00 => 6, lbtn/rbtn/scru/scrd/fbtn/bbtn
0x820f register file page control
bit2 0 RW 1: rotate 180 degree
0: no rotation
*supported since Cx
0x0f RW register file page control
bit0 0 RW 1 to enable page 1 register files
*only supported by H/W prior to Cx
0x10 RW system control 1
0x8210 RW system control 1
bit0 1 RW Reserved, must be 1
bit1 0 RW Reserved, must be 0
bit4 1 RW Reserved, must be 0
bit5 0 RW register clock gating enable
bit4 0 RW Reserved, must be 0
bit5 1 RW register clock gating enable
0: read only, 1: read/write enable
(Note that following registers does not require clock gating being
enabled prior to write: 05 06 07 08 09 0c 0f 10 11 12 16 17 18 23 2e
40 41 42 43. In addition to that, this bit must be 1 when gesture
mode is enabled)
0x31 RW on-pad command detection
0x8220 test mode status
bit5~bit4 RO number of buttons
11 => 2, lbtn/rbtn
10 => 4, lbtn/rbtn/scru/scrd
01 => 6, lbtn/rbtn/scru/scrd/scrl/scrr
00 => 6, lbtn/rbtn/scru/scrd/fbtn/bbtn
*only supported by H/W prior to Cx
0x8231 RW on-pad command detection
bit7 0 RW on-pad command left button down tag
enable
0: disable, 1: enable
*only supported by H/W prior to Cx
0x34 RW on-pad command control 5
0x8234 RW on-pad command control 5
bit4~bit0 0x05 RW XLO in 0s/4/1, so 03h = 0010.1b = 2.5
(Note that position unit is in 0.5 scanline)
*only supported by H/W prior to Cx
bit7 0 RW on-pad tap zone enable
0: disable, 1: enable
*only supported by H/W prior to Cx
0x35 RW on-pad command control 6
0x8235 RW on-pad command control 6
bit4~bit0 0x1d RW XHI in 0s/4/1, so 19h = 1100.1b = 12.5
(Note that position unit is in 0.5 scanline)
*only supported by H/W prior to Cx
0x36 RW on-pad command control 7
0x8236 RW on-pad command control 7
bit4~bit0 0x04 RW YLO in 0s/4/1, so 03h = 0010.1b = 2.5
(Note that position unit is in 0.5 scanline)
*only supported by H/W prior to Cx
0x37 RW on-pad command control 8
0x8237 RW on-pad command control 8
bit4~bit0 0x13 RW YHI in 0s/4/1, so 11h = 1000.1b = 8.5
(Note that position unit is in 0.5 scanline)
*only supported by H/W prior to Cx
0x40 RW system control 5
0x8240 RW system control 5
bit1 0 RW FSP Intellimouse mode enable
0: disable, 1: enable
*only supported by H/W prior to Cx
bit2 0 RW movement + abs. coordinate mode enable
0: disable, 1: enable
......@@ -537,6 +786,7 @@ offset width default r/w name
bit 1 is not set. However, the format is different from that of bit 1.
In addition, when bit 1 and bit 2 are set at the same time, bit 2 will
override bit 1.)
*only supported by H/W prior to Cx
bit3 0 RW abs. coordinate only mode enable
0: disable, 1: enable
......@@ -544,9 +794,11 @@ offset width default r/w name
bit 1 is not set. However, the format is different from that of bit 1.
In addition, when bit 1, bit 2 and bit 3 are set at the same time,
bit 3 will override bit 1 and 2.)
*only supported by H/W prior to Cx
bit5 0 RW auto switch enable
0: disable, 1: enable
*only supported by H/W prior to Cx
bit6 0 RW G0 abs. + notify packet format enable
0: disable, 1: enable
......@@ -554,18 +806,68 @@ offset width default r/w name
bit 2 and 3. That is, if any of those bit is 1, host will receive
absolute coordinates; otherwise, host only receives packets with
relative coordinate.)
*only supported by H/W prior to Cx
bit7 0 RW EN_PS2_F2: PS/2 gesture mode 2nd
finger packet enable
0: disable, 1: enable
*only supported by H/W prior to Cx
0x43 RW on-pad control
0x8243 RW on-pad control
bit0 0 RW on-pad control enable
0: disable, 1: enable
(Note that if this bit is cleared, bit 3/5 will be ineffective)
*only supported by H/W prior to Cx
bit3 0 RW on-pad fix vertical scrolling enable
0: disable, 1: enable
*only supported by H/W prior to Cx
bit5 0 RW on-pad fix horizontal scrolling enable
0: disable, 1: enable
*only supported by H/W prior to Cx
0x8290 RW software control register 1
bit0 0 RW absolute coordination mode
0: disable, 1: enable
*supported since Cx
bit1 0 RW gesture ID output
0: disable, 1: enable
*supported since Cx
bit2 0 RW two fingers' coordinates output
0: disable, 1: enable
*supported since Cx
bit3 0 RW finger up one packet output
0: disable, 1: enable
*supported since Cx
bit4 0 RW absolute coordination continuous mode
0: disable, 1: enable
*supported since Cx
bit6~bit5 00 RW gesture group selection
00: basic
01: suite
10: suite pro
11: advanced
*supported since Cx
bit7 0 RW Bx packet output compatible mode
0: disable, 1: enable *supported since Cx
*supported since Cx
0x833d RW on-pad command control 1
bit7 1 RW on-pad command detection enable
0: disable, 1: enable
*supported since Cx
0x833e RW on-pad command detection
bit7 0 RW on-pad command left button down tag
enable. Works only in H/W based PS/2
data packet mode.
0: disable, 1: enable
*supported since Cx
......@@ -53,6 +53,7 @@ struct tegra_kbc_platform_data {
struct tegra_kbc_pin_cfg pin_cfg[KBC_MAX_GPIO];
const struct matrix_keymap_data *keymap_data;
u32 wakeup_key;
bool wakeup;
bool use_fn_map;
bool use_ghost_filter;
......
......@@ -13,32 +13,7 @@
#ifndef __PLAT_SAMSUNG_KEYPAD_H
#define __PLAT_SAMSUNG_KEYPAD_H
#include <linux/input/matrix_keypad.h>
#define SAMSUNG_MAX_ROWS 8
#define SAMSUNG_MAX_COLS 8
/**
* struct samsung_keypad_platdata - Platform device data for Samsung Keypad.
* @keymap_data: pointer to &matrix_keymap_data.
* @rows: number of keypad row supported.
* @cols: number of keypad col supported.
* @no_autorepeat: disable key autorepeat.
* @wakeup: controls whether the device should be set up as wakeup source.
* @cfg_gpio: configure the GPIO.
*
* Initialisation data specific to either the machine or the platform
* for the device driver to use or call-back when configuring gpio.
*/
struct samsung_keypad_platdata {
const struct matrix_keymap_data *keymap_data;
unsigned int rows;
unsigned int cols;
bool no_autorepeat;
bool wakeup;
void (*cfg_gpio)(unsigned int rows, unsigned int cols);
};
#include <linux/input/samsung-keypad.h>
/**
* samsung_keypad_set_platdata - Set platform data for Samsung Keypad device.
......
......@@ -369,7 +369,7 @@ static int evdev_fetch_next_event(struct evdev_client *client,
spin_lock_irq(&client->buffer_lock);
have_event = client->head != client->tail;
have_event = client->packet_head != client->tail;
if (have_event) {
*event = client->buffer[client->tail++];
client->tail &= client->bufsize - 1;
......@@ -391,14 +391,13 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,
if (count < input_event_size())
return -EINVAL;
if (client->packet_head == client->tail && evdev->exist &&
(file->f_flags & O_NONBLOCK))
return -EAGAIN;
retval = wait_event_interruptible(evdev->wait,
client->packet_head != client->tail || !evdev->exist);
if (retval)
return retval;
if (!(file->f_flags & O_NONBLOCK)) {
retval = wait_event_interruptible(evdev->wait,
client->packet_head != client->tail ||
!evdev->exist);
if (retval)
return retval;
}
if (!evdev->exist)
return -ENODEV;
......@@ -412,6 +411,9 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,
retval += input_event_size();
}
if (retval == 0 && (file->f_flags & O_NONBLOCK))
return -EAGAIN;
return retval;
}
......
......@@ -84,10 +84,12 @@ static ssize_t input_polldev_set_poll(struct device *dev,
{
struct input_polled_dev *polldev = dev_get_drvdata(dev);
struct input_dev *input = polldev->input;
unsigned long interval;
unsigned int interval;
int err;
if (strict_strtoul(buf, 0, &interval))
return -EINVAL;
err = kstrtouint(buf, 0, &interval);
if (err)
return err;
if (interval < polldev->poll_interval_min)
return -EINVAL;
......
......@@ -221,6 +221,22 @@ config KEYBOARD_TCA6416
To compile this driver as a module, choose M here: the
module will be called tca6416_keypad.
config KEYBOARD_TCA8418
tristate "TCA8418 Keypad Support"
depends on I2C
help
This driver implements basic keypad functionality
for keys connected through TCA8418 keypad decoder.
Say Y here if your device has keys connected to
TCA8418 keypad decoder.
If enabled the complete TCA8418 device will be managed through
this driver.
To compile this driver as a module, choose M here: the
module will be called tca8418_keypad.
config KEYBOARD_MATRIX
tristate "GPIO driven matrix keypad support"
depends on GENERIC_GPIO
......@@ -425,9 +441,10 @@ config KEYBOARD_PMIC8XXX
config KEYBOARD_SAMSUNG
tristate "Samsung keypad support"
depends on SAMSUNG_DEV_KEYPAD
depends on HAVE_CLK
help
Say Y here if you want to use the Samsung keypad.
Say Y here if you want to use the keypad on your Samsung mobile
device.
To compile this driver as a module, choose M here: the
module will be called samsung-keypad.
......
......@@ -16,6 +16,7 @@ obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
obj-$(CONFIG_KEYBOARD_GPIO_POLLED) += gpio_keys_polled.o
obj-$(CONFIG_KEYBOARD_TCA6416) += tca6416-keypad.o
obj-$(CONFIG_KEYBOARD_TCA8418) += tca8418_keypad.o
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o
......
......@@ -202,18 +202,7 @@ static struct platform_driver adp5520_keys_driver = {
.probe = adp5520_keys_probe,
.remove = __devexit_p(adp5520_keys_remove),
};
static int __init adp5520_keys_init(void)
{
return platform_driver_register(&adp5520_keys_driver);
}
module_init(adp5520_keys_init);
static void __exit adp5520_keys_exit(void)
{
platform_driver_unregister(&adp5520_keys_driver);
}
module_exit(adp5520_keys_exit);
module_platform_driver(adp5520_keys_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Keys ADP5520 Driver");
......
......@@ -259,19 +259,6 @@ static struct platform_driver amikbd_driver = {
.owner = THIS_MODULE,
},
};
static int __init amikbd_init(void)
{
return platform_driver_probe(&amikbd_driver, amikbd_probe);
}
module_init(amikbd_init);
static void __exit amikbd_exit(void)
{
platform_driver_unregister(&amikbd_driver);
}
module_exit(amikbd_exit);
module_platform_driver(amikbd_driver);
MODULE_ALIAS("platform:amiga-keyboard");
......@@ -1305,7 +1305,7 @@ static ssize_t atkbd_show_extra(struct atkbd *atkbd, char *buf)
static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t count)
{
struct input_dev *old_dev, *new_dev;
unsigned long value;
unsigned int value;
int err;
bool old_extra;
unsigned char old_set;
......@@ -1313,7 +1313,11 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun
if (!atkbd->write)
return -EIO;
if (strict_strtoul(buf, 10, &value) || value > 1)
err = kstrtouint(buf, 10, &value);
if (err)
return err;
if (value > 1)
return -EINVAL;
if (atkbd->extra != value) {
......@@ -1389,11 +1393,15 @@ static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf)
static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t count)
{
struct input_dev *old_dev, *new_dev;
unsigned long value;
unsigned int value;
int err;
bool old_scroll;
if (strict_strtoul(buf, 10, &value) || value > 1)
err = kstrtouint(buf, 10, &value);
if (err)
return err;
if (value > 1)
return -EINVAL;
if (atkbd->scroll != value) {
......@@ -1433,7 +1441,7 @@ static ssize_t atkbd_show_set(struct atkbd *atkbd, char *buf)
static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count)
{
struct input_dev *old_dev, *new_dev;
unsigned long value;
unsigned int value;
int err;
unsigned char old_set;
bool old_extra;
......@@ -1441,7 +1449,11 @@ static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count)
if (!atkbd->write)
return -EIO;
if (strict_strtoul(buf, 10, &value) || (value != 2 && value != 3))
err = kstrtouint(buf, 10, &value);
if (err)
return err;
if (value != 2 && value != 3)
return -EINVAL;
if (atkbd->set != value) {
......@@ -1484,14 +1496,18 @@ static ssize_t atkbd_show_softrepeat(struct atkbd *atkbd, char *buf)
static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t count)
{
struct input_dev *old_dev, *new_dev;
unsigned long value;
unsigned int value;
int err;
bool old_softrepeat, old_softraw;
if (!atkbd->write)
return -EIO;
if (strict_strtoul(buf, 10, &value) || value > 1)
err = kstrtouint(buf, 10, &value);
if (err)
return err;
if (value > 1)
return -EINVAL;
if (atkbd->softrepeat != value) {
......@@ -1534,11 +1550,15 @@ static ssize_t atkbd_show_softraw(struct atkbd *atkbd, char *buf)
static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t count)
{
struct input_dev *old_dev, *new_dev;
unsigned long value;
unsigned int value;
int err;
bool old_softraw;
if (strict_strtoul(buf, 10, &value) || value > 1)
err = kstrtouint(buf, 10, &value);
if (err)
return err;
if (value > 1)
return -EINVAL;
if (atkbd->softraw != value) {
......
......@@ -384,7 +384,7 @@ static int bfin_kpad_resume(struct platform_device *pdev)
# define bfin_kpad_resume NULL
#endif
struct platform_driver bfin_kpad_device_driver = {
static struct platform_driver bfin_kpad_device_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
......@@ -394,19 +394,7 @@ struct platform_driver bfin_kpad_device_driver = {
.suspend = bfin_kpad_suspend,
.resume = bfin_kpad_resume,
};
static int __init bfin_kpad_init(void)
{
return platform_driver_register(&bfin_kpad_device_driver);
}
static void __exit bfin_kpad_exit(void)
{
platform_driver_unregister(&bfin_kpad_device_driver);
}
module_init(bfin_kpad_init);
module_exit(bfin_kpad_exit);
module_platform_driver(bfin_kpad_device_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
......
......@@ -328,18 +328,7 @@ static struct platform_driver davinci_ks_driver = {
},
.remove = __devexit_p(davinci_ks_remove),
};
static int __init davinci_ks_init(void)
{
return platform_driver_probe(&davinci_ks_driver, davinci_ks_probe);
}
module_init(davinci_ks_init);
static void __exit davinci_ks_exit(void)
{
platform_driver_unregister(&davinci_ks_driver);
}
module_exit(davinci_ks_exit);
module_platform_driver(davinci_ks_driver);
MODULE_AUTHOR("Miguel Aguilar");
MODULE_DESCRIPTION("Texas Instruments DaVinci Key Scan Driver");
......
......@@ -390,19 +390,7 @@ static struct platform_driver ep93xx_keypad_driver = {
.suspend = ep93xx_keypad_suspend,
.resume = ep93xx_keypad_resume,
};
static int __init ep93xx_keypad_init(void)
{
return platform_driver_register(&ep93xx_keypad_driver);
}
static void __exit ep93xx_keypad_exit(void)
{
platform_driver_unregister(&ep93xx_keypad_driver);
}
module_init(ep93xx_keypad_init);
module_exit(ep93xx_keypad_exit);
module_platform_driver(ep93xx_keypad_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
......
......@@ -241,19 +241,7 @@ static struct platform_driver gpio_keys_polled_driver = {
.owner = THIS_MODULE,
},
};
static int __init gpio_keys_polled_init(void)
{
return platform_driver_register(&gpio_keys_polled_driver);
}
static void __exit gpio_keys_polled_exit(void)
{
platform_driver_unregister(&gpio_keys_polled_driver);
}
module_init(gpio_keys_polled_init);
module_exit(gpio_keys_polled_exit);
module_platform_driver(gpio_keys_polled_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
......
......@@ -619,19 +619,7 @@ static struct platform_driver imx_keypad_driver = {
.probe = imx_keypad_probe,
.remove = __devexit_p(imx_keypad_remove),
};
static int __init imx_keypad_init(void)
{
return platform_driver_register(&imx_keypad_driver);
}
static void __exit imx_keypad_exit(void)
{
platform_driver_unregister(&imx_keypad_driver);
}
module_init(imx_keypad_init);
module_exit(imx_keypad_exit);
module_platform_driver(imx_keypad_driver);
MODULE_AUTHOR("Alberto Panizzo <maramaopercheseimorto@gmail.com>");
MODULE_DESCRIPTION("IMX Keypad Port Driver");
......
......@@ -260,19 +260,7 @@ static struct platform_driver jornada680kbd_driver = {
.probe = jornada680kbd_probe,
.remove = __devexit_p(jornada680kbd_remove),
};
static int __init jornada680kbd_init(void)
{
return platform_driver_register(&jornada680kbd_driver);
}
static void __exit jornada680kbd_exit(void)
{
platform_driver_unregister(&jornada680kbd_driver);
}
module_init(jornada680kbd_init);
module_exit(jornada680kbd_exit);
module_platform_driver(jornada680kbd_driver);
MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
MODULE_DESCRIPTION("HP Jornada 620/660/680/690 Keyboard Driver");
......
......@@ -174,16 +174,4 @@ static struct platform_driver jornada720_kbd_driver = {
.probe = jornada720_kbd_probe,
.remove = __devexit_p(jornada720_kbd_remove),
};
static int __init jornada720_kbd_init(void)
{
return platform_driver_register(&jornada720_kbd_driver);
}
static void __exit jornada720_kbd_exit(void)
{
platform_driver_unregister(&jornada720_kbd_driver);
}
module_init(jornada720_kbd_init);
module_exit(jornada720_kbd_exit);
module_platform_driver(jornada720_kbd_driver);
......@@ -545,13 +545,12 @@ static ssize_t lm8323_pwm_store_time(struct device *dev,
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct lm8323_pwm *pwm = cdev_to_pwm(led_cdev);
int ret;
unsigned long time;
int ret, time;
ret = strict_strtoul(buf, 10, &time);
ret = kstrtoint(buf, 10, &time);
/* Numbers only, please. */
if (ret)
return -EINVAL;
return ret;
pwm->fade_time = time;
......@@ -613,9 +612,9 @@ static ssize_t lm8323_set_disable(struct device *dev,
{
struct lm8323_chip *lm = dev_get_drvdata(dev);
int ret;
unsigned long i;
unsigned int i;
ret = strict_strtoul(buf, 10, &i);
ret = kstrtouint(buf, 10, &i);
mutex_lock(&lm->lock);
lm->kp_enabled = !i;
......
......@@ -496,19 +496,7 @@ static struct platform_driver matrix_keypad_driver = {
#endif
},
};
static int __init matrix_keypad_init(void)
{
return platform_driver_register(&matrix_keypad_driver);
}
static void __exit matrix_keypad_exit(void)
{
platform_driver_unregister(&matrix_keypad_driver);
}
module_init(matrix_keypad_init);
module_exit(matrix_keypad_exit);
module_platform_driver(matrix_keypad_driver);
MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
MODULE_DESCRIPTION("GPIO Driven Matrix Keypad Driver");
......
......@@ -379,7 +379,7 @@ static const struct dev_pm_ops ske_keypad_dev_pm_ops = {
};
#endif
struct platform_driver ske_keypad_driver = {
static struct platform_driver ske_keypad_driver = {
.driver = {
.name = "nmk-ske-keypad",
.owner = THIS_MODULE,
......@@ -390,18 +390,7 @@ struct platform_driver ske_keypad_driver = {
.probe = ske_keypad_probe,
.remove = __devexit_p(ske_keypad_remove),
};
static int __init ske_keypad_init(void)
{
return platform_driver_probe(&ske_keypad_driver, ske_keypad_probe);
}
module_init(ske_keypad_init);
static void __exit ske_keypad_exit(void)
{
platform_driver_unregister(&ske_keypad_driver);
}
module_exit(ske_keypad_exit);
module_platform_driver(ske_keypad_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Naveen Kumar <naveen.gaddipati@stericsson.com> / Sundar Iyer <sundar.iyer@stericsson.com>");
......
......@@ -473,20 +473,7 @@ static struct platform_driver omap_kp_driver = {
.owner = THIS_MODULE,
},
};
static int __init omap_kp_init(void)
{
printk(KERN_INFO "OMAP Keypad Driver\n");
return platform_driver_register(&omap_kp_driver);
}
static void __exit omap_kp_exit(void)
{
platform_driver_unregister(&omap_kp_driver);
}
module_init(omap_kp_init);
module_exit(omap_kp_exit);
module_platform_driver(omap_kp_driver);
MODULE_AUTHOR("Timo Teräs");
MODULE_DESCRIPTION("OMAP Keypad Driver");
......
......@@ -335,18 +335,7 @@ static struct platform_driver omap4_keypad_driver = {
.owner = THIS_MODULE,
},
};
static int __init omap4_keypad_init(void)
{
return platform_driver_register(&omap4_keypad_driver);
}
module_init(omap4_keypad_init);
static void __exit omap4_keypad_exit(void)
{
platform_driver_unregister(&omap4_keypad_driver);
}
module_exit(omap4_keypad_exit);
module_platform_driver(omap4_keypad_driver);
MODULE_AUTHOR("Texas Instruments");
MODULE_DESCRIPTION("OMAP4 Keypad Driver");
......
......@@ -163,18 +163,7 @@ static struct platform_driver opencores_kbd_device_driver = {
.name = "opencores-kbd",
},
};
static int __init opencores_kbd_init(void)
{
return platform_driver_register(&opencores_kbd_device_driver);
}
module_init(opencores_kbd_init);
static void __exit opencores_kbd_exit(void)
{
platform_driver_unregister(&opencores_kbd_device_driver);
}
module_exit(opencores_kbd_exit);
module_platform_driver(opencores_kbd_device_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Javier Herrero <jherrero@hvsistemas.es>");
......
......@@ -780,18 +780,7 @@ static struct platform_driver pmic8xxx_kp_driver = {
.pm = &pm8xxx_kp_pm_ops,
},
};
static int __init pmic8xxx_kp_init(void)
{
return platform_driver_register(&pmic8xxx_kp_driver);
}
module_init(pmic8xxx_kp_init);
static void __exit pmic8xxx_kp_exit(void)
{
platform_driver_unregister(&pmic8xxx_kp_driver);
}
module_exit(pmic8xxx_kp_exit);
module_platform_driver(pmic8xxx_kp_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("PMIC8XXX keypad driver");
......
......@@ -602,19 +602,7 @@ static struct platform_driver pxa27x_keypad_driver = {
#endif
},
};
static int __init pxa27x_keypad_init(void)
{
return platform_driver_register(&pxa27x_keypad_driver);
}
static void __exit pxa27x_keypad_exit(void)
{
platform_driver_unregister(&pxa27x_keypad_driver);
}
module_init(pxa27x_keypad_init);
module_exit(pxa27x_keypad_exit);
module_platform_driver(pxa27x_keypad_driver);
MODULE_DESCRIPTION("PXA27x Keypad Controller Driver");
MODULE_LICENSE("GPL");
......@@ -195,18 +195,7 @@ static struct platform_driver pxa930_rotary_driver = {
.probe = pxa930_rotary_probe,
.remove = __devexit_p(pxa930_rotary_remove),
};
static int __init pxa930_rotary_init(void)
{
return platform_driver_register(&pxa930_rotary_driver);
}
module_init(pxa930_rotary_init);
static void __exit pxa930_rotary_exit(void)
{
platform_driver_unregister(&pxa930_rotary_driver);
}
module_exit(pxa930_rotary_exit);
module_platform_driver(pxa930_rotary_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Driver for PXA93x Enhanced Rotary Controller");
......
......@@ -20,11 +20,13 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/sched.h>
#include <plat/keypad.h>
#include <linux/input/samsung-keypad.h>
#define SAMSUNG_KEYIFCON 0x00
#define SAMSUNG_KEYIFSTSCLR 0x04
......@@ -65,10 +67,12 @@ enum samsung_keypad_type {
struct samsung_keypad {
struct input_dev *input_dev;
struct platform_device *pdev;
struct clk *clk;
void __iomem *base;
wait_queue_head_t wait;
bool stopped;
bool wake_enabled;
int irq;
enum samsung_keypad_type type;
unsigned int row_shift;
......@@ -155,6 +159,8 @@ static irqreturn_t samsung_keypad_irq(int irq, void *dev_id)
unsigned int val;
bool key_down;
pm_runtime_get_sync(&keypad->pdev->dev);
do {
val = readl(keypad->base + SAMSUNG_KEYIFSTSCLR);
/* Clear interrupt. */
......@@ -169,6 +175,8 @@ static irqreturn_t samsung_keypad_irq(int irq, void *dev_id)
} while (key_down && !keypad->stopped);
pm_runtime_put_sync(&keypad->pdev->dev);
return IRQ_HANDLED;
}
......@@ -176,6 +184,8 @@ static void samsung_keypad_start(struct samsung_keypad *keypad)
{
unsigned int val;
pm_runtime_get_sync(&keypad->pdev->dev);
/* Tell IRQ thread that it may poll the device. */
keypad->stopped = false;
......@@ -188,12 +198,16 @@ static void samsung_keypad_start(struct samsung_keypad *keypad)
/* KEYIFCOL reg clear. */
writel(0, keypad->base + SAMSUNG_KEYIFCOL);
pm_runtime_put_sync(&keypad->pdev->dev);
}
static void samsung_keypad_stop(struct samsung_keypad *keypad)
{
unsigned int val;
pm_runtime_get_sync(&keypad->pdev->dev);
/* Signal IRQ thread to stop polling and disable the handler. */
keypad->stopped = true;
wake_up(&keypad->wait);
......@@ -214,6 +228,8 @@ static void samsung_keypad_stop(struct samsung_keypad *keypad)
* re-enable the handler.
*/
enable_irq(keypad->irq);
pm_runtime_put_sync(&keypad->pdev->dev);
}
static int samsung_keypad_open(struct input_dev *input_dev)
......@@ -418,9 +434,11 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev)
}
keypad->input_dev = input_dev;
keypad->pdev = pdev;
keypad->row_shift = row_shift;
keypad->rows = pdata->rows;
keypad->cols = pdata->cols;
keypad->stopped = true;
init_waitqueue_head(&keypad->wait);
if (pdev->dev.of_node) {
......@@ -467,13 +485,14 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev)
goto err_put_clk;
}
device_init_wakeup(&pdev->dev, pdata->wakeup);
platform_set_drvdata(pdev, keypad);
pm_runtime_enable(&pdev->dev);
error = input_register_device(keypad->input_dev);
if (error)
goto err_free_irq;
device_init_wakeup(&pdev->dev, pdata->wakeup);
platform_set_drvdata(pdev, keypad);
if (pdev->dev.of_node) {
devm_kfree(&pdev->dev, (void *)pdata->keymap_data->keymap);
devm_kfree(&pdev->dev, (void *)pdata->keymap_data);
......@@ -483,6 +502,9 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev)
err_free_irq:
free_irq(keypad->irq, keypad);
pm_runtime_disable(&pdev->dev);
device_init_wakeup(&pdev->dev, 0);
platform_set_drvdata(pdev, NULL);
err_put_clk:
clk_put(keypad->clk);
samsung_keypad_dt_gpio_free(keypad);
......@@ -499,6 +521,7 @@ static int __devexit samsung_keypad_remove(struct platform_device *pdev)
{
struct samsung_keypad *keypad = platform_get_drvdata(pdev);
pm_runtime_disable(&pdev->dev);
device_init_wakeup(&pdev->dev, 0);
platform_set_drvdata(pdev, NULL);
......@@ -519,11 +542,57 @@ static int __devexit samsung_keypad_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
#ifdef CONFIG_PM_RUNTIME
static int samsung_keypad_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct samsung_keypad *keypad = platform_get_drvdata(pdev);
unsigned int val;
int error;
if (keypad->stopped)
return 0;
/* This may fail on some SoCs due to lack of controller support */
error = enable_irq_wake(keypad->irq);
if (!error)
keypad->wake_enabled = true;
val = readl(keypad->base + SAMSUNG_KEYIFCON);
val |= SAMSUNG_KEYIFCON_WAKEUPEN;
writel(val, keypad->base + SAMSUNG_KEYIFCON);
clk_disable(keypad->clk);
return 0;
}
static int samsung_keypad_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct samsung_keypad *keypad = platform_get_drvdata(pdev);
unsigned int val;
if (keypad->stopped)
return 0;
clk_enable(keypad->clk);
val = readl(keypad->base + SAMSUNG_KEYIFCON);
val &= ~SAMSUNG_KEYIFCON_WAKEUPEN;
writel(val, keypad->base + SAMSUNG_KEYIFCON);
if (keypad->wake_enabled)
disable_irq_wake(keypad->irq);
return 0;
}
#endif
#ifdef CONFIG_PM_SLEEP
static void samsung_keypad_toggle_wakeup(struct samsung_keypad *keypad,
bool enable)
{
struct device *dev = keypad->input_dev->dev.parent;
unsigned int val;
clk_enable(keypad->clk);
......@@ -531,11 +600,11 @@ static void samsung_keypad_toggle_wakeup(struct samsung_keypad *keypad,
val = readl(keypad->base + SAMSUNG_KEYIFCON);
if (enable) {
val |= SAMSUNG_KEYIFCON_WAKEUPEN;
if (device_may_wakeup(dev))
if (device_may_wakeup(&keypad->pdev->dev))
enable_irq_wake(keypad->irq);
} else {
val &= ~SAMSUNG_KEYIFCON_WAKEUPEN;
if (device_may_wakeup(dev))
if (device_may_wakeup(&keypad->pdev->dev))
disable_irq_wake(keypad->irq);
}
writel(val, keypad->base + SAMSUNG_KEYIFCON);
......@@ -578,12 +647,13 @@ static int samsung_keypad_resume(struct device *dev)
return 0;
}
#endif
static const struct dev_pm_ops samsung_keypad_pm_ops = {
.suspend = samsung_keypad_suspend,
.resume = samsung_keypad_resume,
SET_SYSTEM_SLEEP_PM_OPS(samsung_keypad_suspend, samsung_keypad_resume)
SET_RUNTIME_PM_OPS(samsung_keypad_runtime_suspend,
samsung_keypad_runtime_resume, NULL)
};
#endif
#ifdef CONFIG_OF
static const struct of_device_id samsung_keypad_dt_match[] = {
......@@ -615,27 +685,13 @@ static struct platform_driver samsung_keypad_driver = {
.name = "samsung-keypad",
.owner = THIS_MODULE,
.of_match_table = samsung_keypad_dt_match,
#ifdef CONFIG_PM
.pm = &samsung_keypad_pm_ops,
#endif
},
.id_table = samsung_keypad_driver_ids,
};
static int __init samsung_keypad_init(void)
{
return platform_driver_register(&samsung_keypad_driver);
}
module_init(samsung_keypad_init);
static void __exit samsung_keypad_exit(void)
{
platform_driver_unregister(&samsung_keypad_driver);
}
module_exit(samsung_keypad_exit);
module_platform_driver(samsung_keypad_driver);
MODULE_DESCRIPTION("Samsung keypad driver");
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:samsung-keypad");
......@@ -337,19 +337,7 @@ static struct platform_driver sh_keysc_device_driver = {
.pm = &sh_keysc_dev_pm_ops,
}
};
static int __init sh_keysc_init(void)
{
return platform_driver_register(&sh_keysc_device_driver);
}
static void __exit sh_keysc_exit(void)
{
platform_driver_unregister(&sh_keysc_device_driver);
}
module_init(sh_keysc_init);
module_exit(sh_keysc_exit);
module_platform_driver(sh_keysc_device_driver);
MODULE_AUTHOR("Magnus Damm");
MODULE_DESCRIPTION("SuperH KEYSC Keypad Driver");
......
......@@ -326,18 +326,7 @@ static struct platform_driver spear_kbd_driver = {
#endif
},
};
static int __init spear_kbd_init(void)
{
return platform_driver_register(&spear_kbd_driver);
}
module_init(spear_kbd_init);
static void __exit spear_kbd_exit(void)
{
platform_driver_unregister(&spear_kbd_driver);
}
module_exit(spear_kbd_exit);
module_platform_driver(spear_kbd_driver);
MODULE_AUTHOR("Rajeev Kumar");
MODULE_DESCRIPTION("SPEAr Keyboard Driver");
......
......@@ -368,18 +368,7 @@ static struct platform_driver stmpe_keypad_driver = {
.probe = stmpe_keypad_probe,
.remove = __devexit_p(stmpe_keypad_remove),
};
static int __init stmpe_keypad_init(void)
{
return platform_driver_register(&stmpe_keypad_driver);
}
module_init(stmpe_keypad_init);
static void __exit stmpe_keypad_exit(void)
{
platform_driver_unregister(&stmpe_keypad_driver);
}
module_exit(stmpe_keypad_exit);
module_platform_driver(stmpe_keypad_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("STMPExxxx keypad driver");
......
......@@ -74,11 +74,13 @@
/**
* struct tc_keypad - data structure used by keypad driver
* @tc3589x: pointer to tc35893
* @input: pointer to input device object
* @board: keypad platform device
* @krow: number of rows
* @kcol: number of coloumns
* @keymap: matrix scan code table for keycodes
* @keypad_stopped: holds keypad status
*/
struct tc_keypad {
struct tc3589x *tc3589x;
......@@ -453,18 +455,7 @@ static struct platform_driver tc3589x_keypad_driver = {
.probe = tc3589x_keypad_probe,
.remove = __devexit_p(tc3589x_keypad_remove),
};
static int __init tc3589x_keypad_init(void)
{
return platform_driver_register(&tc3589x_keypad_driver);
}
module_init(tc3589x_keypad_init);
static void __exit tc3589x_keypad_exit(void)
{
return platform_driver_unregister(&tc3589x_keypad_driver);
}
module_exit(tc3589x_keypad_exit);
module_platform_driver(tc3589x_keypad_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Jayeeta Banerjee/Sundar Iyer");
......
/*
* Driver for TCA8418 I2C keyboard
*
* Copyright (C) 2011 Fuel7, Inc. All rights reserved.
*
* Author: Kyle Manna <kyle.manna@fuel7.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License v2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 021110-1307, USA.
*
* If you can't comply with GPLv2, alternative licensing terms may be
* arranged. Please contact Fuel7, Inc. (http://fuel7.com/) for proprietary
* alternative licensing inquiries.
*/
#include <linux/types.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/tca8418_keypad.h>
/* TCA8418 hardware limits */
#define TCA8418_MAX_ROWS 8
#define TCA8418_MAX_COLS 10
/* TCA8418 register offsets */
#define REG_CFG 0x01
#define REG_INT_STAT 0x02
#define REG_KEY_LCK_EC 0x03
#define REG_KEY_EVENT_A 0x04
#define REG_KEY_EVENT_B 0x05
#define REG_KEY_EVENT_C 0x06
#define REG_KEY_EVENT_D 0x07
#define REG_KEY_EVENT_E 0x08
#define REG_KEY_EVENT_F 0x09
#define REG_KEY_EVENT_G 0x0A
#define REG_KEY_EVENT_H 0x0B
#define REG_KEY_EVENT_I 0x0C
#define REG_KEY_EVENT_J 0x0D
#define REG_KP_LCK_TIMER 0x0E
#define REG_UNLOCK1 0x0F
#define REG_UNLOCK2 0x10
#define REG_GPIO_INT_STAT1 0x11
#define REG_GPIO_INT_STAT2 0x12
#define REG_GPIO_INT_STAT3 0x13
#define REG_GPIO_DAT_STAT1 0x14
#define REG_GPIO_DAT_STAT2 0x15
#define REG_GPIO_DAT_STAT3 0x16
#define REG_GPIO_DAT_OUT1 0x17
#define REG_GPIO_DAT_OUT2 0x18
#define REG_GPIO_DAT_OUT3 0x19
#define REG_GPIO_INT_EN1 0x1A
#define REG_GPIO_INT_EN2 0x1B
#define REG_GPIO_INT_EN3 0x1C
#define REG_KP_GPIO1 0x1D
#define REG_KP_GPIO2 0x1E
#define REG_KP_GPIO3 0x1F
#define REG_GPI_EM1 0x20
#define REG_GPI_EM2 0x21
#define REG_GPI_EM3 0x22
#define REG_GPIO_DIR1 0x23
#define REG_GPIO_DIR2 0x24
#define REG_GPIO_DIR3 0x25
#define REG_GPIO_INT_LVL1 0x26
#define REG_GPIO_INT_LVL2 0x27
#define REG_GPIO_INT_LVL3 0x28
#define REG_DEBOUNCE_DIS1 0x29
#define REG_DEBOUNCE_DIS2 0x2A
#define REG_DEBOUNCE_DIS3 0x2B
#define REG_GPIO_PULL1 0x2C
#define REG_GPIO_PULL2 0x2D
#define REG_GPIO_PULL3 0x2E
/* TCA8418 bit definitions */
#define CFG_AI BIT(7)
#define CFG_GPI_E_CFG BIT(6)
#define CFG_OVR_FLOW_M BIT(5)
#define CFG_INT_CFG BIT(4)
#define CFG_OVR_FLOW_IEN BIT(3)
#define CFG_K_LCK_IEN BIT(2)
#define CFG_GPI_IEN BIT(1)
#define CFG_KE_IEN BIT(0)
#define INT_STAT_CAD_INT BIT(4)
#define INT_STAT_OVR_FLOW_INT BIT(3)
#define INT_STAT_K_LCK_INT BIT(2)
#define INT_STAT_GPI_INT BIT(1)
#define INT_STAT_K_INT BIT(0)
/* TCA8418 register masks */
#define KEY_LCK_EC_KEC 0x7
#define KEY_EVENT_CODE 0x7f
#define KEY_EVENT_VALUE 0x80
static const struct i2c_device_id tca8418_id[] = {
{ TCA8418_NAME, 8418, },
{ }
};
MODULE_DEVICE_TABLE(i2c, tca8418_id);
struct tca8418_keypad {
unsigned int rows;
unsigned int cols;
unsigned int keypad_mask; /* Mask for keypad col/rol regs */
unsigned int irq;
unsigned int row_shift;
struct i2c_client *client;
struct input_dev *input;
/* Flexible array member, must be at end of struct */
unsigned short keymap[];
};
/*
* Write a byte to the TCA8418
*/
static int tca8418_write_byte(struct tca8418_keypad *keypad_data,
int reg, u8 val)
{
int error;
error = i2c_smbus_write_byte_data(keypad_data->client, reg, val);
if (error < 0) {
dev_err(&keypad_data->client->dev,
"%s failed, reg: %d, val: %d, error: %d\n",
__func__, reg, val, error);
return error;
}
return 0;
}
/*
* Read a byte from the TCA8418
*/
static int tca8418_read_byte(struct tca8418_keypad *keypad_data,
int reg, u8 *val)
{
int error;
error = i2c_smbus_read_byte_data(keypad_data->client, reg);
if (error < 0) {
dev_err(&keypad_data->client->dev,
"%s failed, reg: %d, error: %d\n",
__func__, reg, error);
return error;
}
*val = (u8)error;
return 0;
}
static void tca8418_read_keypad(struct tca8418_keypad *keypad_data)
{
int error, col, row;
u8 reg, state, code;
/* Initial read of the key event FIFO */
error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, &reg);
/* Assume that key code 0 signifies empty FIFO */
while (error >= 0 && reg > 0) {
state = reg & KEY_EVENT_VALUE;
code = reg & KEY_EVENT_CODE;
row = code / TCA8418_MAX_COLS;
col = code % TCA8418_MAX_COLS;
row = (col) ? row : row - 1;
col = (col) ? col - 1 : TCA8418_MAX_COLS - 1;
code = MATRIX_SCAN_CODE(row, col, keypad_data->row_shift);
input_event(keypad_data->input, EV_MSC, MSC_SCAN, code);
input_report_key(keypad_data->input,
keypad_data->keymap[code], state);
/* Read for next loop */
error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, &reg);
}
if (error < 0)
dev_err(&keypad_data->client->dev,
"unable to read REG_KEY_EVENT_A\n");
input_sync(keypad_data->input);
}
/*
* Threaded IRQ handler and this can (and will) sleep.
*/
static irqreturn_t tca8418_irq_handler(int irq, void *dev_id)
{
struct tca8418_keypad *keypad_data = dev_id;
u8 reg;
int error;
error = tca8418_read_byte(keypad_data, REG_INT_STAT, &reg);
if (error) {
dev_err(&keypad_data->client->dev,
"unable to read REG_INT_STAT\n");
goto exit;
}
if (reg & INT_STAT_OVR_FLOW_INT)
dev_warn(&keypad_data->client->dev, "overflow occurred\n");
if (reg & INT_STAT_K_INT)
tca8418_read_keypad(keypad_data);
exit:
/* Clear all interrupts, even IRQs we didn't check (GPI, CAD, LCK) */
reg = 0xff;
error = tca8418_write_byte(keypad_data, REG_INT_STAT, reg);
if (error)
dev_err(&keypad_data->client->dev,
"unable to clear REG_INT_STAT\n");
return IRQ_HANDLED;
}
/*
* Configure the TCA8418 for keypad operation
*/
static int __devinit tca8418_configure(struct tca8418_keypad *keypad_data)
{
int reg, error;
/* Write config register, if this fails assume device not present */
error = tca8418_write_byte(keypad_data, REG_CFG,
CFG_INT_CFG | CFG_OVR_FLOW_IEN | CFG_KE_IEN);
if (error < 0)
return -ENODEV;
/* Assemble a mask for row and column registers */
reg = ~(~0 << keypad_data->rows);
reg += (~(~0 << keypad_data->cols)) << 8;
keypad_data->keypad_mask = reg;
/* Set registers to keypad mode */
error |= tca8418_write_byte(keypad_data, REG_KP_GPIO1, reg);
error |= tca8418_write_byte(keypad_data, REG_KP_GPIO2, reg >> 8);
error |= tca8418_write_byte(keypad_data, REG_KP_GPIO3, reg >> 16);
/* Enable column debouncing */
error |= tca8418_write_byte(keypad_data, REG_DEBOUNCE_DIS1, reg);
error |= tca8418_write_byte(keypad_data, REG_DEBOUNCE_DIS2, reg >> 8);
error |= tca8418_write_byte(keypad_data, REG_DEBOUNCE_DIS3, reg >> 16);
return error;
}
static int __devinit tca8418_keypad_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct tca8418_keypad_platform_data *pdata =
client->dev.platform_data;
struct tca8418_keypad *keypad_data;
struct input_dev *input;
int error, row_shift, max_keys;
/* Copy the platform data */
if (!pdata) {
dev_dbg(&client->dev, "no platform data\n");
return -EINVAL;
}
if (!pdata->keymap_data) {
dev_err(&client->dev, "no keymap data defined\n");
return -EINVAL;
}
if (!pdata->rows || pdata->rows > TCA8418_MAX_ROWS) {
dev_err(&client->dev, "invalid rows\n");
return -EINVAL;
}
if (!pdata->cols || pdata->cols > TCA8418_MAX_COLS) {
dev_err(&client->dev, "invalid columns\n");
return -EINVAL;
}
/* Check i2c driver capabilities */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) {
dev_err(&client->dev, "%s adapter not supported\n",
dev_driver_string(&client->adapter->dev));
return -ENODEV;
}
row_shift = get_count_order(pdata->cols);
max_keys = pdata->rows << row_shift;
/* Allocate memory for keypad_data, keymap and input device */
keypad_data = kzalloc(sizeof(*keypad_data) +
max_keys * sizeof(keypad_data->keymap[0]), GFP_KERNEL);
if (!keypad_data)
return -ENOMEM;
keypad_data->rows = pdata->rows;
keypad_data->cols = pdata->cols;
keypad_data->client = client;
keypad_data->row_shift = row_shift;
/* Initialize the chip or fail if chip isn't present */
error = tca8418_configure(keypad_data);
if (error < 0)
goto fail1;
/* Configure input device */
input = input_allocate_device();
if (!input) {
error = -ENOMEM;
goto fail1;
}
keypad_data->input = input;
input->name = client->name;
input->dev.parent = &client->dev;
input->id.bustype = BUS_I2C;
input->id.vendor = 0x0001;
input->id.product = 0x001;
input->id.version = 0x0001;
input->keycode = keypad_data->keymap;
input->keycodesize = sizeof(keypad_data->keymap[0]);
input->keycodemax = max_keys;
__set_bit(EV_KEY, input->evbit);
if (pdata->rep)
__set_bit(EV_REP, input->evbit);
input_set_capability(input, EV_MSC, MSC_SCAN);
input_set_drvdata(input, keypad_data);
matrix_keypad_build_keymap(pdata->keymap_data, row_shift,
input->keycode, input->keybit);
if (pdata->irq_is_gpio)
client->irq = gpio_to_irq(client->irq);
error = request_threaded_irq(client->irq, NULL, tca8418_irq_handler,
IRQF_TRIGGER_FALLING,
client->name, keypad_data);
if (error) {
dev_dbg(&client->dev,
"Unable to claim irq %d; error %d\n",
client->irq, error);
goto fail2;
}
error = input_register_device(input);
if (error) {
dev_dbg(&client->dev,
"Unable to register input device, error: %d\n", error);
goto fail3;
}
i2c_set_clientdata(client, keypad_data);
return 0;
fail3:
free_irq(client->irq, keypad_data);
fail2:
input_free_device(input);
fail1:
kfree(keypad_data);
return error;
}
static int __devexit tca8418_keypad_remove(struct i2c_client *client)
{
struct tca8418_keypad *keypad_data = i2c_get_clientdata(client);
free_irq(keypad_data->client->irq, keypad_data);
input_unregister_device(keypad_data->input);
kfree(keypad_data);
return 0;
}
static struct i2c_driver tca8418_keypad_driver = {
.driver = {
.name = TCA8418_NAME,
.owner = THIS_MODULE,
},
.probe = tca8418_keypad_probe,
.remove = __devexit_p(tca8418_keypad_remove),
.id_table = tca8418_id,
};
static int __init tca8418_keypad_init(void)
{
return i2c_add_driver(&tca8418_keypad_driver);
}
subsys_initcall(tca8418_keypad_init);
static void __exit tca8418_keypad_exit(void)
{
i2c_del_driver(&tca8418_keypad_driver);
}
module_exit(tca8418_keypad_exit);
MODULE_AUTHOR("Kyle Manna <kyle.manna@fuel7.com>");
MODULE_DESCRIPTION("Keypad driver for TCA8418");
MODULE_LICENSE("GPL");
......@@ -26,6 +26,7 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <mach/clk.h>
......@@ -52,6 +53,7 @@
/* KBC Interrupt Register */
#define KBC_INT_0 0x4
#define KBC_INT_FIFO_CNT_INT_STATUS (1 << 2)
#define KBC_INT_KEYPRESS_INT_STATUS (1 << 0)
#define KBC_ROW_CFG0_0 0x8
#define KBC_COL_CFG0_0 0x18
......@@ -74,15 +76,17 @@ struct tegra_kbc {
unsigned int cp_to_wkup_dly;
bool use_fn_map;
bool use_ghost_filter;
bool keypress_caused_wake;
const struct tegra_kbc_platform_data *pdata;
unsigned short keycode[KBC_MAX_KEY * 2];
unsigned short current_keys[KBC_MAX_KPENT];
unsigned int num_pressed_keys;
u32 wakeup_key;
struct timer_list timer;
struct clk *clk;
};
static const u32 tegra_kbc_default_keymap[] = {
static const u32 tegra_kbc_default_keymap[] __devinitdata = {
KEY(0, 2, KEY_W),
KEY(0, 3, KEY_S),
KEY(0, 4, KEY_A),
......@@ -217,7 +221,8 @@ static const u32 tegra_kbc_default_keymap[] = {
KEY(31, 4, KEY_HELP),
};
static const struct matrix_keymap_data tegra_kbc_default_keymap_data = {
static const
struct matrix_keymap_data tegra_kbc_default_keymap_data __devinitdata = {
.keymap = tegra_kbc_default_keymap,
.keymap_size = ARRAY_SIZE(tegra_kbc_default_keymap),
};
......@@ -409,6 +414,9 @@ static irqreturn_t tegra_kbc_isr(int irq, void *args)
*/
tegra_kbc_set_fifo_interrupt(kbc, false);
mod_timer(&kbc->timer, jiffies + kbc->cp_dly_jiffies);
} else if (val & KBC_INT_KEYPRESS_INT_STATUS) {
/* We can be here only through system resume path */
kbc->keypress_caused_wake = true;
}
spin_unlock_irqrestore(&kbc->lock, flags);
......@@ -576,6 +584,56 @@ tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata,
return true;
}
#ifdef CONFIG_OF
static struct tegra_kbc_platform_data * __devinit
tegra_kbc_dt_parse_pdata(struct platform_device *pdev)
{
struct tegra_kbc_platform_data *pdata;
struct device_node *np = pdev->dev.of_node;
if (!np)
return NULL;
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return NULL;
if (!of_property_read_u32(np, "debounce-delay", &prop))
pdata->debounce_cnt = prop;
if (!of_property_read_u32(np, "repeat-delay", &prop))
pdata->repeat_cnt = prop;
if (of_find_property(np, "needs-ghost-filter", NULL))
pdata->use_ghost_filter = true;
if (of_find_property(np, "wakeup-source", NULL))
pdata->wakeup = true;
/*
* All currently known keymaps with device tree support use the same
* pin_cfg, so set it up here.
*/
for (i = 0; i < KBC_MAX_ROW; i++) {
pdata->pin_cfg[i].num = i;
pdata->pin_cfg[i].is_row = true;
}
for (i = 0; i < KBC_MAX_COL; i++) {
pdata->pin_cfg[KBC_MAX_ROW + i].num = i;
pdata->pin_cfg[KBC_MAX_ROW + i].is_row = false;
}
return pdata;
}
#else
static inline struct tegra_kbc_platform_data *tegra_kbc_dt_parse_pdata(
struct platform_device *pdev)
{
return NULL;
}
#endif
static int __devinit tegra_kbc_probe(struct platform_device *pdev)
{
const struct tegra_kbc_platform_data *pdata = pdev->dev.platform_data;
......@@ -590,21 +648,28 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
unsigned int scan_time_rows;
if (!pdata)
return -EINVAL;
pdata = tegra_kbc_dt_parse_pdata(pdev);
if (!tegra_kbc_check_pin_cfg(pdata, &pdev->dev, &num_rows))
if (!pdata)
return -EINVAL;
if (!tegra_kbc_check_pin_cfg(pdata, &pdev->dev, &num_rows)) {
err = -EINVAL;
goto err_free_pdata;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "failed to get I/O memory\n");
return -ENXIO;
err = -ENXIO;
goto err_free_pdata;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "failed to get keyboard IRQ\n");
return -ENXIO;
err = -ENXIO;
goto err_free_pdata;
}
kbc = kzalloc(sizeof(*kbc), GFP_KERNEL);
......@@ -674,9 +739,10 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
keymap_data = pdata->keymap_data ?: &tegra_kbc_default_keymap_data;
matrix_keypad_build_keymap(keymap_data, KBC_ROW_SHIFT,
input_dev->keycode, input_dev->keybit);
kbc->wakeup_key = pdata->wakeup_key;
err = request_irq(kbc->irq, tegra_kbc_isr, IRQF_TRIGGER_HIGH,
pdev->name, kbc);
err = request_irq(kbc->irq, tegra_kbc_isr,
IRQF_NO_SUSPEND | IRQF_TRIGGER_HIGH, pdev->name, kbc);
if (err) {
dev_err(&pdev->dev, "failed to request keyboard IRQ\n");
goto err_put_clk;
......@@ -706,6 +772,9 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
err_free_mem:
input_free_device(input_dev);
kfree(kbc);
err_free_pdata:
if (!pdev->dev.platform_data)
kfree(pdata);
return err;
}
......@@ -715,6 +784,8 @@ static int __devexit tegra_kbc_remove(struct platform_device *pdev)
struct tegra_kbc *kbc = platform_get_drvdata(pdev);
struct resource *res;
platform_set_drvdata(pdev, NULL);
free_irq(kbc->irq, pdev);
clk_put(kbc->clk);
......@@ -723,9 +794,14 @@ static int __devexit tegra_kbc_remove(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
kfree(kbc);
/*
* If we do not have platform data attached to the device we
* allocated it ourselves and thus need to free it.
*/
if (!pdev->dev.platform_data)
kfree(kbc->pdata);
platform_set_drvdata(pdev, NULL);
kfree(kbc);
return 0;
}
......@@ -754,6 +830,8 @@ static int tegra_kbc_suspend(struct device *dev)
tegra_kbc_setup_wakekeys(kbc, true);
msleep(30);
kbc->keypress_caused_wake = false;
enable_irq(kbc->irq);
enable_irq_wake(kbc->irq);
} else {
if (kbc->idev->users)
......@@ -780,7 +858,19 @@ static int tegra_kbc_resume(struct device *dev)
tegra_kbc_set_fifo_interrupt(kbc, true);
enable_irq(kbc->irq);
if (kbc->keypress_caused_wake && kbc->wakeup_key) {
/*
* We can't report events directly from the ISR
* because timekeeping is stopped when processing
* wakeup request and we get a nasty warning when
* we try to call do_gettimeofday() in evdev
* handler.
*/
input_report_key(kbc->idev, kbc->wakeup_key, 1);
input_sync(kbc->idev);
input_report_key(kbc->idev, kbc->wakeup_key, 0);
input_sync(kbc->idev);
}
} else {
if (kbc->idev->users)
err = tegra_kbc_start(kbc);
......@@ -793,6 +883,12 @@ static int tegra_kbc_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(tegra_kbc_pm_ops, tegra_kbc_suspend, tegra_kbc_resume);
static const struct of_device_id tegra_kbc_of_match[] = {
{ .compatible = "nvidia,tegra20-kbc", },
{ },
};
MODULE_DEVICE_TABLE(of, tegra_kbc_of_match);
static struct platform_driver tegra_kbc_driver = {
.probe = tegra_kbc_probe,
.remove = __devexit_p(tegra_kbc_remove),
......@@ -800,20 +896,10 @@ static struct platform_driver tegra_kbc_driver = {
.name = "tegra-kbc",
.owner = THIS_MODULE,
.pm = &tegra_kbc_pm_ops,
.of_match_table = tegra_kbc_of_match,
},
};
static void __exit tegra_kbc_exit(void)
{
platform_driver_unregister(&tegra_kbc_driver);
}
module_exit(tegra_kbc_exit);
static int __init tegra_kbc_init(void)
{
return platform_driver_register(&tegra_kbc_driver);
}
module_init(tegra_kbc_init);
module_platform_driver(tegra_kbc_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Rakesh Iyer <riyer@nvidia.com>");
......
......@@ -322,19 +322,7 @@ static struct platform_driver keypad_driver = {
.driver.name = "tnetv107x-keypad",
.driver.owner = THIS_MODULE,
};
static int __init keypad_init(void)
{
return platform_driver_register(&keypad_driver);
}
static void __exit keypad_exit(void)
{
platform_driver_unregister(&keypad_driver);
}
module_init(keypad_init);
module_exit(keypad_exit);
module_platform_driver(keypad_driver);
MODULE_AUTHOR("Cyril Chemparathy");
MODULE_DESCRIPTION("TNETV107X Keypad Driver");
......
......@@ -460,18 +460,7 @@ static struct platform_driver twl4030_kp_driver = {
.owner = THIS_MODULE,
},
};
static int __init twl4030_kp_init(void)
{
return platform_driver_register(&twl4030_kp_driver);
}
module_init(twl4030_kp_init);
static void __exit twl4030_kp_exit(void)
{
platform_driver_unregister(&twl4030_kp_driver);
}
module_exit(twl4030_kp_exit);
module_platform_driver(twl4030_kp_driver);
MODULE_AUTHOR("Texas Instruments");
MODULE_DESCRIPTION("TWL4030 Keypad Driver");
......
......@@ -262,19 +262,7 @@ static struct platform_driver w90p910_keypad_driver = {
.owner = THIS_MODULE,
},
};
static int __init w90p910_keypad_init(void)
{
return platform_driver_register(&w90p910_keypad_driver);
}
static void __exit w90p910_keypad_exit(void)
{
platform_driver_unregister(&w90p910_keypad_driver);
}
module_init(w90p910_keypad_init);
module_exit(w90p910_keypad_exit);
module_platform_driver(w90p910_keypad_driver);
MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
MODULE_DESCRIPTION("w90p910 keypad driver");
......
......@@ -137,18 +137,7 @@ static struct platform_driver pm860x_onkey_driver = {
.probe = pm860x_onkey_probe,
.remove = __devexit_p(pm860x_onkey_remove),
};
static int __init pm860x_onkey_init(void)
{
return platform_driver_register(&pm860x_onkey_driver);
}
module_init(pm860x_onkey_init);
static void __exit pm860x_onkey_exit(void)
{
platform_driver_unregister(&pm860x_onkey_driver);
}
module_exit(pm860x_onkey_exit);
module_platform_driver(pm860x_onkey_driver);
MODULE_DESCRIPTION("Marvell 88PM860x ONKEY driver");
MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
......
......@@ -179,6 +179,31 @@ config INPUT_APANEL
To compile this driver as a module, choose M here: the module will
be called apanel.
config INPUT_GP2A
tristate "Sharp GP2AP002A00F I2C Proximity/Opto sensor driver"
depends on I2C
depends on GENERIC_GPIO
help
Say Y here if you have a Sharp GP2AP002A00F proximity/als combo-chip
hooked to an I2C bus.
To compile this driver as a module, choose M here: the
module will be called gp2ap002a00f.
config INPUT_GPIO_TILT_POLLED
tristate "Polled GPIO tilt switch"
depends on GENERIC_GPIO
select INPUT_POLLDEV
help
This driver implements support for tilt switches connected
to GPIO pins that are not capable of generating interrupts.
The list of gpios to use and the mapping of their states
to specific angles is done via platform data.
To compile this driver as a module, choose M here: the
module will be called gpio_tilt_polled.
config INPUT_IXP4XX_BEEPER
tristate "IXP4XX Beeper support"
depends on ARCH_IXP4XX
......
......@@ -22,6 +22,8 @@ obj-$(CONFIG_INPUT_CMA3000) += cma3000_d0x.o
obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o
obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o
obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o
obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o
obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o
obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
......
......@@ -139,18 +139,7 @@ static struct platform_driver ab8500_ponkey_driver = {
.probe = ab8500_ponkey_probe,
.remove = __devexit_p(ab8500_ponkey_remove),
};
static int __init ab8500_ponkey_init(void)
{
return platform_driver_register(&ab8500_ponkey_driver);
}
module_init(ab8500_ponkey_init);
static void __exit ab8500_ponkey_exit(void)
{
platform_driver_unregister(&ab8500_ponkey_driver);
}
module_exit(ab8500_ponkey_exit);
module_platform_driver(ab8500_ponkey_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Sundar Iyer <sundar.iyer@stericsson.com>");
......
......@@ -122,7 +122,6 @@ static SIMPLE_DEV_PM_OPS(adxl34x_spi_pm, adxl34x_spi_suspend,
static struct spi_driver adxl34x_driver = {
.driver = {
.name = "adxl34x",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
.pm = &adxl34x_spi_pm,
},
......
......@@ -452,10 +452,10 @@ static ssize_t adxl34x_disable_store(struct device *dev,
const char *buf, size_t count)
{
struct adxl34x *ac = dev_get_drvdata(dev);
unsigned long val;
unsigned int val;
int error;
error = strict_strtoul(buf, 10, &val);
error = kstrtouint(buf, 10, &val);
if (error)
return error;
......@@ -541,10 +541,10 @@ static ssize_t adxl34x_rate_store(struct device *dev,
const char *buf, size_t count)
{
struct adxl34x *ac = dev_get_drvdata(dev);
unsigned long val;
unsigned char val;
int error;
error = strict_strtoul(buf, 10, &val);
error = kstrtou8(buf, 10, &val);
if (error)
return error;
......@@ -576,10 +576,10 @@ static ssize_t adxl34x_autosleep_store(struct device *dev,
const char *buf, size_t count)
{
struct adxl34x *ac = dev_get_drvdata(dev);
unsigned long val;
unsigned int val;
int error;
error = strict_strtoul(buf, 10, &val);
error = kstrtouint(buf, 10, &val);
if (error)
return error;
......@@ -623,13 +623,13 @@ static ssize_t adxl34x_write_store(struct device *dev,
const char *buf, size_t count)
{
struct adxl34x *ac = dev_get_drvdata(dev);
unsigned long val;
unsigned int val;
int error;
/*
* This allows basic ADXL register write access for debug purposes.
*/
error = strict_strtoul(buf, 16, &val);
error = kstrtouint(buf, 16, &val);
if (error)
return error;
......
......@@ -42,13 +42,13 @@ static int ati_remote2_set_mask(const char *val,
const struct kernel_param *kp,
unsigned int max)
{
unsigned long mask;
unsigned int mask;
int ret;
if (!val)
return -EINVAL;
ret = strict_strtoul(val, 0, &mask);
ret = kstrtouint(val, 0, &mask);
if (ret)
return ret;
......@@ -720,11 +720,12 @@ static ssize_t ati_remote2_store_channel_mask(struct device *dev,
struct usb_device *udev = to_usb_device(dev);
struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
struct ati_remote2 *ar2 = usb_get_intfdata(intf);
unsigned long mask;
unsigned int mask;
int r;
if (strict_strtoul(buf, 0, &mask))
return -EINVAL;
r = kstrtouint(buf, 0, &mask);
if (r)
return r;
if (mask & ~ATI_REMOTE2_MAX_CHANNEL_MASK)
return -EINVAL;
......@@ -769,10 +770,12 @@ static ssize_t ati_remote2_store_mode_mask(struct device *dev,
struct usb_device *udev = to_usb_device(dev);
struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
struct ati_remote2 *ar2 = usb_get_intfdata(intf);
unsigned long mask;
unsigned int mask;
int err;
if (strict_strtoul(buf, 0, &mask))
return -EINVAL;
err = kstrtouint(buf, 0, &mask);
if (err)
return err;
if (mask & ~ATI_REMOTE2_MAX_MODE_MASK)
return -EINVAL;
......
......@@ -264,18 +264,7 @@ static struct platform_driver bfin_rotary_device_driver = {
#endif
},
};
static int __init bfin_rotary_init(void)
{
return platform_driver_register(&bfin_rotary_device_driver);
}
module_init(bfin_rotary_init);
static void __exit bfin_rotary_exit(void)
{
platform_driver_unregister(&bfin_rotary_device_driver);
}
module_exit(bfin_rotary_exit);
module_platform_driver(bfin_rotary_device_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
......
......@@ -163,16 +163,4 @@ static struct platform_driver cobalt_buttons_driver = {
.owner = THIS_MODULE,
},
};
static int __init cobalt_buttons_init(void)
{
return platform_driver_register(&cobalt_buttons_driver);
}
static void __exit cobalt_buttons_exit(void)
{
platform_driver_unregister(&cobalt_buttons_driver);
}
module_init(cobalt_buttons_init);
module_exit(cobalt_buttons_exit);
module_platform_driver(cobalt_buttons_driver);
......@@ -267,17 +267,6 @@ static struct platform_driver dm355evm_keys_driver = {
.name = "dm355evm_keys",
},
};
static int __init dm355evm_keys_init(void)
{
return platform_driver_register(&dm355evm_keys_driver);
}
module_init(dm355evm_keys_init);
static void __exit dm355evm_keys_exit(void)
{
platform_driver_unregister(&dm355evm_keys_driver);
}
module_exit(dm355evm_keys_exit);
module_platform_driver(dm355evm_keys_driver);
MODULE_LICENSE("GPL");
/*
* Copyright (C) 2011 Sony Ericsson Mobile Communications Inc.
*
* Author: Courtney Cavin <courtney.cavin@sonyericsson.com>
* Prepared for up-stream by: Oskar Andero <oskar.andero@sonyericsson.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*/
#include <linux/i2c.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/input/gp2ap002a00f.h>
struct gp2a_data {
struct input_dev *input;
const struct gp2a_platform_data *pdata;
struct i2c_client *i2c_client;
};
enum gp2a_addr {
GP2A_ADDR_PROX = 0x0,
GP2A_ADDR_GAIN = 0x1,
GP2A_ADDR_HYS = 0x2,
GP2A_ADDR_CYCLE = 0x3,
GP2A_ADDR_OPMOD = 0x4,
GP2A_ADDR_CON = 0x6
};
enum gp2a_controls {
/* Software Shutdown control: 0 = shutdown, 1 = normal operation */
GP2A_CTRL_SSD = 0x01
};
static int gp2a_report(struct gp2a_data *dt)
{
int vo = gpio_get_value(dt->pdata->vout_gpio);
input_report_switch(dt->input, SW_FRONT_PROXIMITY, !vo);
input_sync(dt->input);
return 0;
}
static irqreturn_t gp2a_irq(int irq, void *handle)
{
struct gp2a_data *dt = handle;
gp2a_report(dt);
return IRQ_HANDLED;
}
static int gp2a_enable(struct gp2a_data *dt)
{
return i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_OPMOD,
GP2A_CTRL_SSD);
}
static int gp2a_disable(struct gp2a_data *dt)
{
return i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_OPMOD,
0x00);
}
static int gp2a_device_open(struct input_dev *dev)
{
struct gp2a_data *dt = input_get_drvdata(dev);
int error;
error = gp2a_enable(dt);
if (error < 0) {
dev_err(&dt->i2c_client->dev,
"unable to activate, err %d\n", error);
return error;
}
gp2a_report(dt);
return 0;
}
static void gp2a_device_close(struct input_dev *dev)
{
struct gp2a_data *dt = input_get_drvdata(dev);
int error;
error = gp2a_disable(dt);
if (error < 0)
dev_err(&dt->i2c_client->dev,
"unable to deactivate, err %d\n", error);
}
static int __devinit gp2a_initialize(struct gp2a_data *dt)
{
int error;
error = i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_GAIN,
0x08);
if (error < 0)
return error;
error = i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_HYS,
0xc2);
if (error < 0)
return error;
error = i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_CYCLE,
0x04);
if (error < 0)
return error;
error = gp2a_disable(dt);
return error;
}
static int __devinit gp2a_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct gp2a_platform_data *pdata = client->dev.platform_data;
struct gp2a_data *dt;
int error;
if (!pdata)
return -EINVAL;
if (pdata->hw_setup) {
error = pdata->hw_setup(client);
if (error < 0)
return error;
}
error = gpio_request_one(pdata->vout_gpio, GPIOF_IN, GP2A_I2C_NAME);
if (error)
goto err_hw_shutdown;
dt = kzalloc(sizeof(struct gp2a_data), GFP_KERNEL);
if (!dt) {
error = -ENOMEM;
goto err_free_gpio;
}
dt->pdata = pdata;
dt->i2c_client = client;
error = gp2a_initialize(dt);
if (error < 0)
goto err_free_mem;
dt->input = input_allocate_device();
if (!dt->input) {
error = -ENOMEM;
goto err_free_mem;
}
input_set_drvdata(dt->input, dt);
dt->input->open = gp2a_device_open;
dt->input->close = gp2a_device_close;
dt->input->name = GP2A_I2C_NAME;
dt->input->id.bustype = BUS_I2C;
dt->input->dev.parent = &client->dev;
input_set_capability(dt->input, EV_SW, SW_FRONT_PROXIMITY);
error = request_threaded_irq(client->irq, NULL, gp2a_irq,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
GP2A_I2C_NAME, dt);
if (error) {
dev_err(&client->dev, "irq request failed\n");
goto err_free_input_dev;
}
error = input_register_device(dt->input);
if (error) {
dev_err(&client->dev, "device registration failed\n");
goto err_free_irq;
}
device_init_wakeup(&client->dev, pdata->wakeup);
i2c_set_clientdata(client, dt);
return 0;
err_free_irq:
free_irq(client->irq, dt);
err_free_input_dev:
input_free_device(dt->input);
err_free_mem:
kfree(dt);
err_free_gpio:
gpio_free(pdata->vout_gpio);
err_hw_shutdown:
if (pdata->hw_shutdown)
pdata->hw_shutdown(client);
return error;
}
static int __devexit gp2a_remove(struct i2c_client *client)
{
struct gp2a_data *dt = i2c_get_clientdata(client);
const struct gp2a_platform_data *pdata = dt->pdata;
device_init_wakeup(&client->dev, false);
free_irq(client->irq, dt);
input_unregister_device(dt->input);
kfree(dt);
gpio_free(pdata->vout_gpio);
if (pdata->hw_shutdown)
pdata->hw_shutdown(client);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int gp2a_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct gp2a_data *dt = i2c_get_clientdata(client);
int retval = 0;
if (device_may_wakeup(&client->dev)) {
enable_irq_wake(client->irq);
} else {
mutex_lock(&dt->input->mutex);
if (dt->input->users)
retval = gp2a_disable(dt);
mutex_unlock(&dt->input->mutex);
}
return retval;
}
static int gp2a_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct gp2a_data *dt = i2c_get_clientdata(client);
int retval = 0;
if (device_may_wakeup(&client->dev)) {
disable_irq_wake(client->irq);
} else {
mutex_lock(&dt->input->mutex);
if (dt->input->users)
retval = gp2a_enable(dt);
mutex_unlock(&dt->input->mutex);
}
return retval;
}
#endif
static SIMPLE_DEV_PM_OPS(gp2a_pm, gp2a_suspend, gp2a_resume);
static const struct i2c_device_id gp2a_i2c_id[] = {
{ GP2A_I2C_NAME, 0 },
{ }
};
static struct i2c_driver gp2a_i2c_driver = {
.driver = {
.name = GP2A_I2C_NAME,
.owner = THIS_MODULE,
.pm = &gp2a_pm,
},
.probe = gp2a_probe,
.remove = __devexit_p(gp2a_remove),
.id_table = gp2a_i2c_id,
};
static int __init gp2a_init(void)
{
return i2c_add_driver(&gp2a_i2c_driver);
}
static void __exit gp2a_exit(void)
{
i2c_del_driver(&gp2a_i2c_driver);
}
module_init(gp2a_init);
module_exit(gp2a_exit);
MODULE_AUTHOR("Courtney Cavin <courtney.cavin@sonyericsson.com>");
MODULE_DESCRIPTION("Sharp GP2AP002A00F I2C Proximity/Opto sensor driver");
MODULE_LICENSE("GPL v2");
/*
* Driver for tilt switches connected via GPIO lines
* not capable of generating interrupts
*
* Copyright (C) 2011 Heiko Stuebner <heiko@sntech.de>
*
* based on: drivers/input/keyboard/gpio_keys_polled.c
*
* Copyright (C) 2007-2010 Gabor Juhos <juhosg@openwrt.org>
* Copyright (C) 2010 Nuno Goncalves <nunojpg@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/input-polldev.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/input/gpio_tilt.h>
#define DRV_NAME "gpio-tilt-polled"
struct gpio_tilt_polled_dev {
struct input_polled_dev *poll_dev;
struct device *dev;
const struct gpio_tilt_platform_data *pdata;
int last_state;
int threshold;
int count;
};
static void gpio_tilt_polled_poll(struct input_polled_dev *dev)
{
struct gpio_tilt_polled_dev *tdev = dev->private;
const struct gpio_tilt_platform_data *pdata = tdev->pdata;
struct input_dev *input = dev->input;
struct gpio_tilt_state *tilt_state = NULL;
int state, i;
if (tdev->count < tdev->threshold) {
tdev->count++;
} else {
state = 0;
for (i = 0; i < pdata->nr_gpios; i++)
state |= (!!gpio_get_value(pdata->gpios[i].gpio) << i);
if (state != tdev->last_state) {
for (i = 0; i < pdata->nr_states; i++)
if (pdata->states[i].gpios == state)
tilt_state = &pdata->states[i];
if (tilt_state) {
for (i = 0; i < pdata->nr_axes; i++)
input_report_abs(input,
pdata->axes[i].axis,
tilt_state->axes[i]);
input_sync(input);
}
tdev->count = 0;
tdev->last_state = state;
}
}
}
static void gpio_tilt_polled_open(struct input_polled_dev *dev)
{
struct gpio_tilt_polled_dev *tdev = dev->private;
const struct gpio_tilt_platform_data *pdata = tdev->pdata;
if (pdata->enable)
pdata->enable(tdev->dev);
/* report initial state of the axes */
tdev->last_state = -1;
tdev->count = tdev->threshold;
gpio_tilt_polled_poll(tdev->poll_dev);
}
static void gpio_tilt_polled_close(struct input_polled_dev *dev)
{
struct gpio_tilt_polled_dev *tdev = dev->private;
const struct gpio_tilt_platform_data *pdata = tdev->pdata;
if (pdata->disable)
pdata->disable(tdev->dev);
}
static int __devinit gpio_tilt_polled_probe(struct platform_device *pdev)
{
const struct gpio_tilt_platform_data *pdata = pdev->dev.platform_data;
struct device *dev = &pdev->dev;
struct gpio_tilt_polled_dev *tdev;
struct input_polled_dev *poll_dev;
struct input_dev *input;
int error, i;
if (!pdata || !pdata->poll_interval)
return -EINVAL;
tdev = kzalloc(sizeof(struct gpio_tilt_polled_dev), GFP_KERNEL);
if (!tdev) {
dev_err(dev, "no memory for private data\n");
return -ENOMEM;
}
error = gpio_request_array(pdata->gpios, pdata->nr_gpios);
if (error) {
dev_err(dev,
"Could not request tilt GPIOs: %d\n", error);
goto err_free_tdev;
}
poll_dev = input_allocate_polled_device();
if (!poll_dev) {
dev_err(dev, "no memory for polled device\n");
error = -ENOMEM;
goto err_free_gpios;
}
poll_dev->private = tdev;
poll_dev->poll = gpio_tilt_polled_poll;
poll_dev->poll_interval = pdata->poll_interval;
poll_dev->open = gpio_tilt_polled_open;
poll_dev->close = gpio_tilt_polled_close;
input = poll_dev->input;
input->name = pdev->name;
input->phys = DRV_NAME"/input0";
input->dev.parent = &pdev->dev;
input->id.bustype = BUS_HOST;
input->id.vendor = 0x0001;
input->id.product = 0x0001;
input->id.version = 0x0100;
__set_bit(EV_ABS, input->evbit);
for (i = 0; i < pdata->nr_axes; i++)
input_set_abs_params(input, pdata->axes[i].axis,
pdata->axes[i].min, pdata->axes[i].max,
pdata->axes[i].fuzz, pdata->axes[i].flat);
tdev->threshold = DIV_ROUND_UP(pdata->debounce_interval,
pdata->poll_interval);
tdev->poll_dev = poll_dev;
tdev->dev = dev;
tdev->pdata = pdata;
error = input_register_polled_device(poll_dev);
if (error) {
dev_err(dev, "unable to register polled device, err=%d\n",
error);
goto err_free_polldev;
}
platform_set_drvdata(pdev, tdev);
return 0;
err_free_polldev:
input_free_polled_device(poll_dev);
err_free_gpios:
gpio_free_array(pdata->gpios, pdata->nr_gpios);
err_free_tdev:
kfree(tdev);
return error;
}
static int __devexit gpio_tilt_polled_remove(struct platform_device *pdev)
{
struct gpio_tilt_polled_dev *tdev = platform_get_drvdata(pdev);
const struct gpio_tilt_platform_data *pdata = tdev->pdata;
platform_set_drvdata(pdev, NULL);
input_unregister_polled_device(tdev->poll_dev);
input_free_polled_device(tdev->poll_dev);
gpio_free_array(pdata->gpios, pdata->nr_gpios);
kfree(tdev);
return 0;
}
static struct platform_driver gpio_tilt_polled_driver = {
.probe = gpio_tilt_polled_probe,
.remove = __devexit_p(gpio_tilt_polled_remove),
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
};
module_platform_driver(gpio_tilt_polled_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
MODULE_DESCRIPTION("Polled GPIO tilt driver");
MODULE_ALIAS("platform:" DRV_NAME);
......@@ -168,16 +168,5 @@ static struct platform_driver ixp4xx_spkr_platform_driver = {
.remove = __devexit_p(ixp4xx_spkr_remove),
.shutdown = ixp4xx_spkr_shutdown,
};
module_platform_driver(ixp4xx_spkr_platform_driver);
static int __init ixp4xx_spkr_init(void)
{
return platform_driver_register(&ixp4xx_spkr_platform_driver);
}
static void __exit ixp4xx_spkr_exit(void)
{
platform_driver_unregister(&ixp4xx_spkr_platform_driver);
}
module_init(ixp4xx_spkr_init);
module_exit(ixp4xx_spkr_exit);
......@@ -166,18 +166,7 @@ static struct platform_driver max8925_onkey_driver = {
.probe = max8925_onkey_probe,
.remove = __devexit_p(max8925_onkey_remove),
};
static int __init max8925_onkey_init(void)
{
return platform_driver_register(&max8925_onkey_driver);
}
module_init(max8925_onkey_init);
static void __exit max8925_onkey_exit(void)
{
platform_driver_unregister(&max8925_onkey_driver);
}
module_exit(max8925_onkey_exit);
module_platform_driver(max8925_onkey_driver);
MODULE_DESCRIPTION("Maxim MAX8925 ONKEY driver");
MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
......
......@@ -255,7 +255,7 @@ static int __devexit mc13783_pwrbutton_remove(struct platform_device *pdev)
return 0;
}
struct platform_driver mc13783_pwrbutton_driver = {
static struct platform_driver mc13783_pwrbutton_driver = {
.probe = mc13783_pwrbutton_probe,
.remove = __devexit_p(mc13783_pwrbutton_remove),
.driver = {
......@@ -264,17 +264,7 @@ struct platform_driver mc13783_pwrbutton_driver = {
},
};
static int __init mc13783_pwrbutton_init(void)
{
return platform_driver_register(&mc13783_pwrbutton_driver);
}
module_init(mc13783_pwrbutton_init);
static void __exit mc13783_pwrbutton_exit(void)
{
platform_driver_unregister(&mc13783_pwrbutton_driver);
}
module_exit(mc13783_pwrbutton_exit);
module_platform_driver(mc13783_pwrbutton_driver);
MODULE_ALIAS("platform:mc13783-pwrbutton");
MODULE_DESCRIPTION("MC13783 Power Button");
......
......@@ -41,18 +41,67 @@
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#define MPU3050_CHIP_ID_REG 0x00
#define MPU3050_CHIP_ID 0x69
#define MPU3050_XOUT_H 0x1D
#define MPU3050_PWR_MGM 0x3E
#define MPU3050_PWR_MGM_POS 6
#define MPU3050_PWR_MGM_MASK 0x40
#define MPU3050_AUTO_DELAY 1000
#define MPU3050_MIN_VALUE -32768
#define MPU3050_MAX_VALUE 32767
#define MPU3050_DEFAULT_POLL_INTERVAL 200
#define MPU3050_DEFAULT_FS_RANGE 3
/* Register map */
#define MPU3050_CHIP_ID_REG 0x00
#define MPU3050_SMPLRT_DIV 0x15
#define MPU3050_DLPF_FS_SYNC 0x16
#define MPU3050_INT_CFG 0x17
#define MPU3050_XOUT_H 0x1D
#define MPU3050_PWR_MGM 0x3E
#define MPU3050_PWR_MGM_POS 6
/* Register bits */
/* DLPF_FS_SYNC */
#define MPU3050_EXT_SYNC_NONE 0x00
#define MPU3050_EXT_SYNC_TEMP 0x20
#define MPU3050_EXT_SYNC_GYROX 0x40
#define MPU3050_EXT_SYNC_GYROY 0x60
#define MPU3050_EXT_SYNC_GYROZ 0x80
#define MPU3050_EXT_SYNC_ACCELX 0xA0
#define MPU3050_EXT_SYNC_ACCELY 0xC0
#define MPU3050_EXT_SYNC_ACCELZ 0xE0
#define MPU3050_EXT_SYNC_MASK 0xE0
#define MPU3050_FS_250DPS 0x00
#define MPU3050_FS_500DPS 0x08
#define MPU3050_FS_1000DPS 0x10
#define MPU3050_FS_2000DPS 0x18
#define MPU3050_FS_MASK 0x18
#define MPU3050_DLPF_CFG_256HZ_NOLPF2 0x00
#define MPU3050_DLPF_CFG_188HZ 0x01
#define MPU3050_DLPF_CFG_98HZ 0x02
#define MPU3050_DLPF_CFG_42HZ 0x03
#define MPU3050_DLPF_CFG_20HZ 0x04
#define MPU3050_DLPF_CFG_10HZ 0x05
#define MPU3050_DLPF_CFG_5HZ 0x06
#define MPU3050_DLPF_CFG_2100HZ_NOLPF 0x07
#define MPU3050_DLPF_CFG_MASK 0x07
/* INT_CFG */
#define MPU3050_RAW_RDY_EN 0x01
#define MPU3050_MPU_RDY_EN 0x02
#define MPU3050_LATCH_INT_EN 0x04
/* PWR_MGM */
#define MPU3050_PWR_MGM_PLL_X 0x01
#define MPU3050_PWR_MGM_PLL_Y 0x02
#define MPU3050_PWR_MGM_PLL_Z 0x03
#define MPU3050_PWR_MGM_CLKSEL 0x07
#define MPU3050_PWR_MGM_STBY_ZG 0x08
#define MPU3050_PWR_MGM_STBY_YG 0x10
#define MPU3050_PWR_MGM_STBY_XG 0x20
#define MPU3050_PWR_MGM_SLEEP 0x40
#define MPU3050_PWR_MGM_RESET 0x80
#define MPU3050_PWR_MGM_MASK 0x40
struct axis_data {
s16 x;
s16 y;
......@@ -148,9 +197,20 @@ static void mpu3050_set_power_mode(struct i2c_client *client, u8 val)
static int mpu3050_input_open(struct input_dev *input)
{
struct mpu3050_sensor *sensor = input_get_drvdata(input);
int error;
pm_runtime_get(sensor->dev);
/* Enable interrupts */
error = i2c_smbus_write_byte_data(sensor->client, MPU3050_INT_CFG,
MPU3050_LATCH_INT_EN |
MPU3050_RAW_RDY_EN |
MPU3050_MPU_RDY_EN);
if (error < 0) {
pm_runtime_put(sensor->dev);
return error;
}
return 0;
}
......@@ -191,6 +251,51 @@ static irqreturn_t mpu3050_interrupt_thread(int irq, void *data)
return IRQ_HANDLED;
}
/**
* mpu3050_hw_init - initialize hardware
* @sensor: the sensor
*
* Called during device probe; configures the sampling method.
*/
static int __devinit mpu3050_hw_init(struct mpu3050_sensor *sensor)
{
struct i2c_client *client = sensor->client;
int ret;
u8 reg;
/* Reset */
ret = i2c_smbus_write_byte_data(client, MPU3050_PWR_MGM,
MPU3050_PWR_MGM_RESET);
if (ret < 0)
return ret;
ret = i2c_smbus_read_byte_data(client, MPU3050_PWR_MGM);
if (ret < 0)
return ret;
ret &= ~MPU3050_PWR_MGM_CLKSEL;
ret |= MPU3050_PWR_MGM_PLL_Z;
ret = i2c_smbus_write_byte_data(client, MPU3050_PWR_MGM, ret);
if (ret < 0)
return ret;
/* Output frequency divider. The poll interval */
ret = i2c_smbus_write_byte_data(client, MPU3050_SMPLRT_DIV,
MPU3050_DEFAULT_POLL_INTERVAL - 1);
if (ret < 0)
return ret;
/* Set low pass filter and full scale */
reg = MPU3050_DEFAULT_FS_RANGE;
reg |= MPU3050_DLPF_CFG_42HZ << 3;
reg |= MPU3050_EXT_SYNC_NONE << 5;
ret = i2c_smbus_write_byte_data(client, MPU3050_DLPF_FS_SYNC, reg);
if (ret < 0)
return ret;
return 0;
}
/**
* mpu3050_probe - device detection callback
* @client: i2c client of found device
......@@ -256,10 +361,14 @@ static int __devinit mpu3050_probe(struct i2c_client *client,
pm_runtime_set_active(&client->dev);
error = mpu3050_hw_init(sensor);
if (error)
goto err_pm_set_suspended;
error = request_threaded_irq(client->irq,
NULL, mpu3050_interrupt_thread,
IRQF_TRIGGER_RISING,
"mpu_int", sensor);
"mpu3050", sensor);
if (error) {
dev_err(&client->dev,
"can't get IRQ %d, error %d\n", client->irq, error);
......@@ -348,11 +457,18 @@ static const struct i2c_device_id mpu3050_ids[] = {
};
MODULE_DEVICE_TABLE(i2c, mpu3050_ids);
static const struct of_device_id mpu3050_of_match[] = {
{ .compatible = "invn,mpu3050", },
{ },
};
MODULE_DEVICE_TABLE(of, mpu3050_of_match);
static struct i2c_driver mpu3050_i2c_driver = {
.driver = {
.name = "mpu3050",
.owner = THIS_MODULE,
.pm = &mpu3050_pm,
.of_match_table = mpu3050_of_match,
},
.probe = mpu3050_probe,
.remove = __devexit_p(mpu3050_remove),
......
......@@ -125,19 +125,7 @@ static struct platform_driver pcap_keys_device_driver = {
.owner = THIS_MODULE,
}
};
static int __init pcap_keys_init(void)
{
return platform_driver_register(&pcap_keys_device_driver);
};
static void __exit pcap_keys_exit(void)
{
platform_driver_unregister(&pcap_keys_device_driver);
};
module_init(pcap_keys_init);
module_exit(pcap_keys_exit);
module_platform_driver(pcap_keys_device_driver);
MODULE_DESCRIPTION("Motorola PCAP2 input events driver");
MODULE_AUTHOR("Ilya Petrov <ilya.muromec@gmail.com>");
......
......@@ -113,18 +113,7 @@ static struct platform_driver pcf50633_input_driver = {
.probe = pcf50633_input_probe,
.remove = __devexit_p(pcf50633_input_remove),
};
static int __init pcf50633_input_init(void)
{
return platform_driver_register(&pcf50633_input_driver);
}
module_init(pcf50633_input_init);
static void __exit pcf50633_input_exit(void)
{
platform_driver_unregister(&pcf50633_input_driver);
}
module_exit(pcf50633_input_exit);
module_platform_driver(pcf50633_input_driver);
MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
MODULE_DESCRIPTION("PCF50633 input driver");
......
......@@ -134,17 +134,5 @@ static struct platform_driver pcspkr_platform_driver = {
.remove = __devexit_p(pcspkr_remove),
.shutdown = pcspkr_shutdown,
};
module_platform_driver(pcspkr_platform_driver);
static int __init pcspkr_init(void)
{
return platform_driver_register(&pcspkr_platform_driver);
}
static void __exit pcspkr_exit(void)
{
platform_driver_unregister(&pcspkr_platform_driver);
}
module_init(pcspkr_init);
module_exit(pcspkr_exit);
......@@ -277,18 +277,7 @@ static struct platform_driver pm8xxx_vib_driver = {
.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_platform_driver(pm8xxx_vib_driver);
MODULE_ALIAS("platform:pm8xxx_vib");
MODULE_DESCRIPTION("PMIC8xxx vibrator driver based on ff-memless framework");
......
......@@ -213,18 +213,7 @@ static struct platform_driver pmic8xxx_pwrkey_driver = {
.pm = &pm8xxx_pwr_key_pm_ops,
},
};
static int __init pmic8xxx_pwrkey_init(void)
{
return platform_driver_register(&pmic8xxx_pwrkey_driver);
}
module_init(pmic8xxx_pwrkey_init);
static void __exit pmic8xxx_pwrkey_exit(void)
{
platform_driver_unregister(&pmic8xxx_pwrkey_driver);
}
module_exit(pmic8xxx_pwrkey_exit);
module_platform_driver(pmic8xxx_pwrkey_driver);
MODULE_ALIAS("platform:pmic8xxx_pwrkey");
MODULE_DESCRIPTION("PMIC8XXX Power Key driver");
......
......@@ -180,18 +180,7 @@ static struct platform_driver pwm_beeper_driver = {
.pm = PWM_BEEPER_PM_OPS,
},
};
static int __init pwm_beeper_init(void)
{
return platform_driver_register(&pwm_beeper_driver);
}
module_init(pwm_beeper_init);
static void __exit pwm_beeper_exit(void)
{
platform_driver_unregister(&pwm_beeper_driver);
}
module_exit(pwm_beeper_exit);
module_platform_driver(pwm_beeper_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("PWM beeper driver");
......
......@@ -100,19 +100,7 @@ static struct platform_driver rb532_button_driver = {
.owner = THIS_MODULE,
},
};
static int __init rb532_button_init(void)
{
return platform_driver_register(&rb532_button_driver);
}
static void __exit rb532_button_exit(void)
{
platform_driver_unregister(&rb532_button_driver);
}
module_init(rb532_button_init);
module_exit(rb532_button_exit);
module_platform_driver(rb532_button_driver);
MODULE_AUTHOR("Phil Sutter <n0-1@freewrt.org>");
MODULE_LICENSE("GPL");
......
......@@ -284,19 +284,7 @@ static struct platform_driver rotary_encoder_driver = {
.owner = THIS_MODULE,
}
};
static int __init rotary_encoder_init(void)
{
return platform_driver_register(&rotary_encoder_driver);
}
static void __exit rotary_encoder_exit(void)
{
platform_driver_unregister(&rotary_encoder_driver);
}
module_init(rotary_encoder_init);
module_exit(rotary_encoder_exit);
module_platform_driver(rotary_encoder_driver);
MODULE_ALIAS("platform:" DRV_NAME);
MODULE_DESCRIPTION("GPIO rotary encoder driver");
......
......@@ -164,17 +164,6 @@ static struct platform_driver sgi_buttons_driver = {
.owner = THIS_MODULE,
},
};
static int __init sgi_buttons_init(void)
{
return platform_driver_register(&sgi_buttons_driver);
}
static void __exit sgi_buttons_exit(void)
{
platform_driver_unregister(&sgi_buttons_driver);
}
module_platform_driver(sgi_buttons_driver);
MODULE_LICENSE("GPL");
module_init(sgi_buttons_init);
module_exit(sgi_buttons_exit);
......@@ -107,25 +107,14 @@ static int __exit twl4030_pwrbutton_remove(struct platform_device *pdev)
}
static struct platform_driver twl4030_pwrbutton_driver = {
.probe = twl4030_pwrbutton_probe,
.remove = __exit_p(twl4030_pwrbutton_remove),
.driver = {
.name = "twl4030_pwrbutton",
.owner = THIS_MODULE,
},
};
static int __init twl4030_pwrbutton_init(void)
{
return platform_driver_probe(&twl4030_pwrbutton_driver,
twl4030_pwrbutton_probe);
}
module_init(twl4030_pwrbutton_init);
static void __exit twl4030_pwrbutton_exit(void)
{
platform_driver_unregister(&twl4030_pwrbutton_driver);
}
module_exit(twl4030_pwrbutton_exit);
module_platform_driver(twl4030_pwrbutton_driver);
MODULE_ALIAS("platform:twl4030_pwrbutton");
MODULE_DESCRIPTION("Triton2 Power Button");
......
......@@ -278,21 +278,9 @@ static struct platform_driver twl4030_vibra_driver = {
#endif
},
};
static int __init twl4030_vibra_init(void)
{
return platform_driver_register(&twl4030_vibra_driver);
}
module_init(twl4030_vibra_init);
static void __exit twl4030_vibra_exit(void)
{
platform_driver_unregister(&twl4030_vibra_driver);
}
module_exit(twl4030_vibra_exit);
module_platform_driver(twl4030_vibra_driver);
MODULE_ALIAS("platform:twl4030-vibra");
MODULE_DESCRIPTION("TWL4030 Vibra driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Nokia Corporation");
......@@ -410,18 +410,7 @@ static struct platform_driver twl6040_vibra_driver = {
.pm = &twl6040_vibra_pm_ops,
},
};
static int __init twl6040_vibra_init(void)
{
return platform_driver_register(&twl6040_vibra_driver);
}
module_init(twl6040_vibra_init);
static void __exit twl6040_vibra_exit(void)
{
platform_driver_unregister(&twl6040_vibra_driver);
}
module_exit(twl6040_vibra_exit);
module_platform_driver(twl6040_vibra_driver);
MODULE_ALIAS("platform:twl6040-vibra");
MODULE_DESCRIPTION("TWL6040 Vibra driver");
......
......@@ -145,18 +145,7 @@ static struct platform_driver wm831x_on_driver = {
.owner = THIS_MODULE,
},
};
static int __init wm831x_on_init(void)
{
return platform_driver_register(&wm831x_on_driver);
}
module_init(wm831x_on_init);
static void __exit wm831x_on_exit(void)
{
platform_driver_unregister(&wm831x_on_driver);
}
module_exit(wm831x_on_exit);
module_platform_driver(wm831x_on_driver);
MODULE_ALIAS("platform:wm831x-on");
MODULE_DESCRIPTION("WM831x ON pin");
......
......@@ -17,13 +17,63 @@
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/serio.h>
#include <linux/libps2.h>
#include "psmouse.h"
#include "alps.h"
#define ALPS_OLDPROTO 0x01 /* old style input */
/*
* Definitions for ALPS version 3 and 4 command mode protocol
*/
#define ALPS_V3_X_MAX 2000
#define ALPS_V3_Y_MAX 1400
#define ALPS_BITMAP_X_BITS 15
#define ALPS_BITMAP_Y_BITS 11
#define ALPS_CMD_NIBBLE_10 0x01f2
static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
{ PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */
{ PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */
{ PSMOUSE_CMD_SETSCALE21, 0x00 }, /* 2 */
{ PSMOUSE_CMD_SETRATE, 0x0a }, /* 3 */
{ PSMOUSE_CMD_SETRATE, 0x14 }, /* 4 */
{ PSMOUSE_CMD_SETRATE, 0x28 }, /* 5 */
{ PSMOUSE_CMD_SETRATE, 0x3c }, /* 6 */
{ PSMOUSE_CMD_SETRATE, 0x50 }, /* 7 */
{ PSMOUSE_CMD_SETRATE, 0x64 }, /* 8 */
{ PSMOUSE_CMD_SETRATE, 0xc8 }, /* 9 */
{ ALPS_CMD_NIBBLE_10, 0x00 }, /* a */
{ PSMOUSE_CMD_SETRES, 0x00 }, /* b */
{ PSMOUSE_CMD_SETRES, 0x01 }, /* c */
{ PSMOUSE_CMD_SETRES, 0x02 }, /* d */
{ PSMOUSE_CMD_SETRES, 0x03 }, /* e */
{ PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */
};
static const struct alps_nibble_commands alps_v4_nibble_commands[] = {
{ PSMOUSE_CMD_ENABLE, 0x00 }, /* 0 */
{ PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */
{ PSMOUSE_CMD_SETSCALE21, 0x00 }, /* 2 */
{ PSMOUSE_CMD_SETRATE, 0x0a }, /* 3 */
{ PSMOUSE_CMD_SETRATE, 0x14 }, /* 4 */
{ PSMOUSE_CMD_SETRATE, 0x28 }, /* 5 */
{ PSMOUSE_CMD_SETRATE, 0x3c }, /* 6 */
{ PSMOUSE_CMD_SETRATE, 0x50 }, /* 7 */
{ PSMOUSE_CMD_SETRATE, 0x64 }, /* 8 */
{ PSMOUSE_CMD_SETRATE, 0xc8 }, /* 9 */
{ ALPS_CMD_NIBBLE_10, 0x00 }, /* a */
{ PSMOUSE_CMD_SETRES, 0x00 }, /* b */
{ PSMOUSE_CMD_SETRES, 0x01 }, /* c */
{ PSMOUSE_CMD_SETRES, 0x02 }, /* d */
{ PSMOUSE_CMD_SETRES, 0x03 }, /* e */
{ PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */
};
#define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */
#define ALPS_PASS 0x04 /* device has a pass-through port */
......@@ -35,30 +85,33 @@
6-byte ALPS packet */
static const struct alps_model_info alps_model_data[] = {
{ { 0x32, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
{ { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */
{ { 0x53, 0x02, 0x0a }, 0xf8, 0xf8, 0 },
{ { 0x53, 0x02, 0x14 }, 0xf8, 0xf8, 0 },
{ { 0x60, 0x03, 0xc8 }, 0xf8, 0xf8, 0 }, /* HP ze1115 */
{ { 0x63, 0x02, 0x0a }, 0xf8, 0xf8, 0 },
{ { 0x63, 0x02, 0x14 }, 0xf8, 0xf8, 0 },
{ { 0x63, 0x02, 0x28 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Fujitsu Siemens S6010 */
{ { 0x63, 0x02, 0x3c }, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */
{ { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */
{ { 0x63, 0x02, 0x64 }, 0xf8, 0xf8, 0 },
{ { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D800 */
{ { 0x73, 0x00, 0x0a }, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */
{ { 0x73, 0x02, 0x0a }, 0xf8, 0xf8, 0 },
{ { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */
{ { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
{ { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
{ { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
{ { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
{ { 0x33, 0x02, 0x0a }, 0x00, ALPS_PROTO_V1, 0x88, 0xf8, 0 }, /* UMAX-530T */
{ { 0x53, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
{ { 0x53, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
{ { 0x60, 0x03, 0xc8 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, /* HP ze1115 */
{ { 0x63, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
{ { 0x63, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
{ { 0x63, 0x02, 0x28 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Fujitsu Siemens S6010 */
{ { 0x63, 0x02, 0x3c }, 0x00, ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */
{ { 0x63, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */
{ { 0x63, 0x02, 0x64 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
{ { 0x63, 0x03, 0xc8 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D800 */
{ { 0x73, 0x00, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */
{ { 0x73, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
{ { 0x73, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */
{ { 0x20, 0x02, 0x0e }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
{ { 0x22, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
{ { 0x22, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
/* Dell Latitude E5500, E6400, E6500, Precision M4400 */
{ { 0x62, 0x02, 0x14 }, 0xcf, 0xcf,
{ { 0x62, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf,
ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED },
{ { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */
{ { 0x52, 0x01, 0x14 }, 0xff, 0xff,
ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */
{ { 0x73, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */
{ { 0x52, 0x01, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff,
ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */
{ { 0x73, 0x02, 0x64 }, 0x9b, ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT },
{ { 0x73, 0x02, 0x64 }, 0x9d, ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT },
{ { 0x73, 0x02, 0x64 }, 0x8a, ALPS_PROTO_V4, 0x8f, 0x8f, 0 },
};
/*
......@@ -67,42 +120,7 @@ static const struct alps_model_info alps_model_data[] = {
* isn't valid per PS/2 spec.
*/
/*
* PS/2 packet format
*
* byte 0: 0 0 YSGN XSGN 1 M R L
* byte 1: X7 X6 X5 X4 X3 X2 X1 X0
* byte 2: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
*
* Note that the device never signals overflow condition.
*
* ALPS absolute Mode - new format
*
* byte 0: 1 ? ? ? 1 ? ? ?
* byte 1: 0 x6 x5 x4 x3 x2 x1 x0
* byte 2: 0 x10 x9 x8 x7 ? fin ges
* byte 3: 0 y9 y8 y7 1 M R L
* byte 4: 0 y6 y5 y4 y3 y2 y1 y0
* byte 5: 0 z6 z5 z4 z3 z2 z1 z0
*
* Dualpoint device -- interleaved packet format
*
* byte 0: 1 1 0 0 1 1 1 1
* byte 1: 0 x6 x5 x4 x3 x2 x1 x0
* byte 2: 0 x10 x9 x8 x7 0 fin ges
* byte 3: 0 0 YSGN XSGN 1 1 1 1
* byte 4: X7 X6 X5 X4 X3 X2 X1 X0
* byte 5: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
* byte 6: 0 y9 y8 y7 1 m r l
* byte 7: 0 y6 y5 y4 y3 y2 y1 y0
* byte 8: 0 z6 z5 z4 z3 z2 z1 z0
*
* CAPITALS = stick, miniscules = touchpad
*
* ?'s can have different meanings on different models,
* such as wheel rotation, extra buttons, stick buttons
* on a dualpoint, etc.
*/
/* Packet formats are described in Documentation/input/alps.txt */
static bool alps_is_valid_first_byte(const struct alps_model_info *model,
unsigned char data)
......@@ -137,7 +155,7 @@ static void alps_report_buttons(struct psmouse *psmouse,
input_sync(dev2);
}
static void alps_process_packet(struct psmouse *psmouse)
static void alps_process_packet_v1_v2(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
const struct alps_model_info *model = priv->i;
......@@ -147,7 +165,7 @@ static void alps_process_packet(struct psmouse *psmouse)
int x, y, z, ges, fin, left, right, middle;
int back = 0, forward = 0;
if (model->flags & ALPS_OLDPROTO) {
if (model->proto_version == ALPS_PROTO_V1) {
left = packet[2] & 0x10;
right = packet[2] & 0x08;
middle = 0;
......@@ -239,6 +257,403 @@ static void alps_process_packet(struct psmouse *psmouse)
input_sync(dev);
}
/*
* Process bitmap data from v3 and v4 protocols. Returns the number of
* fingers detected. A return value of 0 means at least one of the
* bitmaps was empty.
*
* The bitmaps don't have enough data to track fingers, so this function
* only generates points representing a bounding box of all contacts.
* These points are returned in x1, y1, x2, and y2 when the return value
* is greater than 0.
*/
static int alps_process_bitmap(unsigned int x_map, unsigned int y_map,
int *x1, int *y1, int *x2, int *y2)
{
struct alps_bitmap_point {
int start_bit;
int num_bits;
};
int fingers_x = 0, fingers_y = 0, fingers;
int i, bit, prev_bit;
struct alps_bitmap_point x_low = {0,}, x_high = {0,};
struct alps_bitmap_point y_low = {0,}, y_high = {0,};
struct alps_bitmap_point *point;
if (!x_map || !y_map)
return 0;
*x1 = *y1 = *x2 = *y2 = 0;
prev_bit = 0;
point = &x_low;
for (i = 0; x_map != 0; i++, x_map >>= 1) {
bit = x_map & 1;
if (bit) {
if (!prev_bit) {
point->start_bit = i;
fingers_x++;
}
point->num_bits++;
} else {
if (prev_bit)
point = &x_high;
else
point->num_bits = 0;
}
prev_bit = bit;
}
/*
* y bitmap is reversed for what we need (lower positions are in
* higher bits), so we process from the top end.
*/
y_map = y_map << (sizeof(y_map) * BITS_PER_BYTE - ALPS_BITMAP_Y_BITS);
prev_bit = 0;
point = &y_low;
for (i = 0; y_map != 0; i++, y_map <<= 1) {
bit = y_map & (1 << (sizeof(y_map) * BITS_PER_BYTE - 1));
if (bit) {
if (!prev_bit) {
point->start_bit = i;
fingers_y++;
}
point->num_bits++;
} else {
if (prev_bit)
point = &y_high;
else
point->num_bits = 0;
}
prev_bit = bit;
}
/*
* Fingers can overlap, so we use the maximum count of fingers
* on either axis as the finger count.
*/
fingers = max(fingers_x, fingers_y);
/*
* If total fingers is > 1 but either axis reports only a single
* contact, we have overlapping or adjacent fingers. For the
* purposes of creating a bounding box, divide the single contact
* (roughly) equally between the two points.
*/
if (fingers > 1) {
if (fingers_x == 1) {
i = x_low.num_bits / 2;
x_low.num_bits = x_low.num_bits - i;
x_high.start_bit = x_low.start_bit + i;
x_high.num_bits = max(i, 1);
} else if (fingers_y == 1) {
i = y_low.num_bits / 2;
y_low.num_bits = y_low.num_bits - i;
y_high.start_bit = y_low.start_bit + i;
y_high.num_bits = max(i, 1);
}
}
*x1 = (ALPS_V3_X_MAX * (2 * x_low.start_bit + x_low.num_bits - 1)) /
(2 * (ALPS_BITMAP_X_BITS - 1));
*y1 = (ALPS_V3_Y_MAX * (2 * y_low.start_bit + y_low.num_bits - 1)) /
(2 * (ALPS_BITMAP_Y_BITS - 1));
if (fingers > 1) {
*x2 = (ALPS_V3_X_MAX * (2 * x_high.start_bit + x_high.num_bits - 1)) /
(2 * (ALPS_BITMAP_X_BITS - 1));
*y2 = (ALPS_V3_Y_MAX * (2 * y_high.start_bit + y_high.num_bits - 1)) /
(2 * (ALPS_BITMAP_Y_BITS - 1));
}
return fingers;
}
static void alps_set_slot(struct input_dev *dev, int slot, bool active,
int x, int y)
{
input_mt_slot(dev, 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, y);
}
}
static void alps_report_semi_mt_data(struct input_dev *dev, int num_fingers,
int x1, int y1, int x2, int y2)
{
alps_set_slot(dev, 0, num_fingers != 0, x1, y1);
alps_set_slot(dev, 1, num_fingers == 2, x2, y2);
}
static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
unsigned char *packet = psmouse->packet;
struct input_dev *dev = priv->dev2;
int x, y, z, left, right, middle;
/* Sanity check packet */
if (!(packet[0] & 0x40)) {
psmouse_dbg(psmouse, "Bad trackstick packet, discarding\n");
return;
}
/*
* There's a special packet that seems to indicate the end
* of a stream of trackstick data. Filter these out.
*/
if (packet[1] == 0x7f && packet[2] == 0x7f && packet[4] == 0x7f)
return;
x = (s8)(((packet[0] & 0x20) << 2) | (packet[1] & 0x7f));
y = (s8)(((packet[0] & 0x10) << 3) | (packet[2] & 0x7f));
z = (packet[4] & 0x7c) >> 2;
/*
* The x and y values tend to be quite large, and when used
* alone the trackstick is difficult to use. Scale them down
* to compensate.
*/
x /= 8;
y /= 8;
input_report_rel(dev, REL_X, x);
input_report_rel(dev, REL_Y, -y);
/*
* Most ALPS models report the trackstick buttons in the touchpad
* packets, but a few report them here. No reliable way has been
* found to differentiate between the models upfront, so we enable
* the quirk in response to seeing a button press in the trackstick
* packet.
*/
left = packet[3] & 0x01;
right = packet[3] & 0x02;
middle = packet[3] & 0x04;
if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS) &&
(left || right || middle))
priv->quirks |= ALPS_QUIRK_TRACKSTICK_BUTTONS;
if (priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS) {
input_report_key(dev, BTN_LEFT, left);
input_report_key(dev, BTN_RIGHT, right);
input_report_key(dev, BTN_MIDDLE, middle);
}
input_sync(dev);
return;
}
static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
unsigned char *packet = psmouse->packet;
struct input_dev *dev = psmouse->dev;
struct input_dev *dev2 = priv->dev2;
int x, y, z;
int left, right, middle;
int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
int fingers = 0, bmap_fingers;
unsigned int x_bitmap, y_bitmap;
/*
* There's no single feature of touchpad position and bitmap packets
* that can be used to distinguish between them. We rely on the fact
* that a bitmap packet should always follow a position packet with
* bit 6 of packet[4] set.
*/
if (priv->multi_packet) {
/*
* Sometimes a position packet will indicate a multi-packet
* sequence, but then what follows is another position
* packet. Check for this, and when it happens process the
* position packet as usual.
*/
if (packet[0] & 0x40) {
fingers = (packet[5] & 0x3) + 1;
x_bitmap = ((packet[4] & 0x7e) << 8) |
((packet[1] & 0x7f) << 2) |
((packet[0] & 0x30) >> 4);
y_bitmap = ((packet[3] & 0x70) << 4) |
((packet[2] & 0x7f) << 1) |
(packet[4] & 0x01);
bmap_fingers = alps_process_bitmap(x_bitmap, y_bitmap,
&x1, &y1, &x2, &y2);
/*
* We shouldn't report more than one finger if
* we don't have two coordinates.
*/
if (fingers > 1 && bmap_fingers < 2)
fingers = bmap_fingers;
/* Now process position packet */
packet = priv->multi_data;
} else {
priv->multi_packet = 0;
}
}
/*
* Bit 6 of byte 0 is not usually set in position packets. The only
* times it seems to be set is in situations where the data is
* suspect anyway, e.g. a palm resting flat on the touchpad. Given
* this combined with the fact that this bit is useful for filtering
* out misidentified bitmap packets, we reject anything with this
* bit set.
*/
if (packet[0] & 0x40)
return;
if (!priv->multi_packet && (packet[4] & 0x40)) {
priv->multi_packet = 1;
memcpy(priv->multi_data, packet, sizeof(priv->multi_data));
return;
}
priv->multi_packet = 0;
left = packet[3] & 0x01;
right = packet[3] & 0x02;
middle = packet[3] & 0x04;
x = ((packet[1] & 0x7f) << 4) | ((packet[4] & 0x30) >> 2) |
((packet[0] & 0x30) >> 4);
y = ((packet[2] & 0x7f) << 4) | (packet[4] & 0x0f);
z = packet[5] & 0x7f;
/*
* Sometimes the hardware sends a single packet with z = 0
* in the middle of a stream. Real releases generate packets
* with x, y, and z all zero, so these seem to be flukes.
* Ignore them.
*/
if (x && y && !z)
return;
/*
* If we don't have MT data or the bitmaps were empty, we have
* to rely on ST data.
*/
if (!fingers) {
x1 = x;
y1 = y;
fingers = z > 0 ? 1 : 0;
}
if (z >= 64)
input_report_key(dev, BTN_TOUCH, 1);
else
input_report_key(dev, BTN_TOUCH, 0);
alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4);
input_report_key(dev, BTN_LEFT, left);
input_report_key(dev, BTN_RIGHT, right);
input_report_key(dev, BTN_MIDDLE, middle);
if (z > 0) {
input_report_abs(dev, ABS_X, x);
input_report_abs(dev, ABS_Y, y);
}
input_report_abs(dev, ABS_PRESSURE, z);
input_sync(dev);
if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
left = packet[3] & 0x10;
right = packet[3] & 0x20;
middle = packet[3] & 0x40;
input_report_key(dev2, BTN_LEFT, left);
input_report_key(dev2, BTN_RIGHT, right);
input_report_key(dev2, BTN_MIDDLE, middle);
input_sync(dev2);
}
}
static void alps_process_packet_v3(struct psmouse *psmouse)
{
unsigned char *packet = psmouse->packet;
/*
* v3 protocol packets come in three types, two representing
* touchpad data and one representing trackstick data.
* Trackstick packets seem to be distinguished by always
* having 0x3f in the last byte. This value has never been
* observed in the last byte of either of the other types
* of packets.
*/
if (packet[5] == 0x3f) {
alps_process_trackstick_packet_v3(psmouse);
return;
}
alps_process_touchpad_packet_v3(psmouse);
}
static void alps_process_packet_v4(struct psmouse *psmouse)
{
unsigned char *packet = psmouse->packet;
struct input_dev *dev = psmouse->dev;
int x, y, z;
int left, right;
left = packet[4] & 0x01;
right = packet[4] & 0x02;
x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) |
((packet[0] & 0x30) >> 4);
y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
z = packet[5] & 0x7f;
if (z >= 64)
input_report_key(dev, BTN_TOUCH, 1);
else
input_report_key(dev, BTN_TOUCH, 0);
if (z > 0) {
input_report_abs(dev, ABS_X, x);
input_report_abs(dev, ABS_Y, y);
}
input_report_abs(dev, ABS_PRESSURE, z);
input_report_key(dev, BTN_TOOL_FINGER, z > 0);
input_report_key(dev, BTN_LEFT, left);
input_report_key(dev, BTN_RIGHT, right);
input_sync(dev);
}
static void alps_process_packet(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
const struct alps_model_info *model = priv->i;
switch (model->proto_version) {
case ALPS_PROTO_V1:
case ALPS_PROTO_V2:
alps_process_packet_v1_v2(psmouse);
break;
case ALPS_PROTO_V3:
alps_process_packet_v3(psmouse);
break;
case ALPS_PROTO_V4:
alps_process_packet_v4(psmouse);
break;
}
}
static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
unsigned char packet[],
bool report_buttons)
......@@ -344,7 +759,7 @@ static void alps_flush_packet(unsigned long data)
serio_pause_rx(psmouse->ps2dev.serio);
if (psmouse->pktcnt == 6) {
if (psmouse->pktcnt == psmouse->pktsize) {
/*
* We did not any more data in reasonable amount of time.
......@@ -395,8 +810,8 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
return PSMOUSE_BAD_DATA;
}
/* Bytes 2 - 6 should have 0 in the highest bit */
if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 &&
/* Bytes 2 - pktsize should have 0 in the highest bit */
if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= psmouse->pktsize &&
(psmouse->packet[psmouse->pktcnt - 1] & 0x80)) {
psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
psmouse->pktcnt - 1,
......@@ -404,7 +819,7 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
return PSMOUSE_BAD_DATA;
}
if (psmouse->pktcnt == 6) {
if (psmouse->pktcnt == psmouse->pktsize) {
alps_process_packet(psmouse);
return PSMOUSE_FULL_PACKET;
}
......@@ -412,11 +827,127 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
return PSMOUSE_GOOD_DATA;
}
static int alps_command_mode_send_nibble(struct psmouse *psmouse, int nibble)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
struct alps_data *priv = psmouse->private;
int command;
unsigned char *param;
unsigned char dummy[4];
BUG_ON(nibble > 0xf);
command = priv->nibble_commands[nibble].command;
param = (command & 0x0f00) ?
dummy : (unsigned char *)&priv->nibble_commands[nibble].data;
if (ps2_command(ps2dev, param, command))
return -1;
return 0;
}
static int alps_command_mode_set_addr(struct psmouse *psmouse, int addr)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
struct alps_data *priv = psmouse->private;
int i, nibble;
if (ps2_command(ps2dev, NULL, priv->addr_command))
return -1;
for (i = 12; i >= 0; i -= 4) {
nibble = (addr >> i) & 0xf;
if (alps_command_mode_send_nibble(psmouse, nibble))
return -1;
}
return 0;
}
static int __alps_command_mode_read_reg(struct psmouse *psmouse, int addr)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4];
if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
return -1;
/*
* The address being read is returned in the first two bytes
* of the result. Check that this address matches the expected
* address.
*/
if (addr != ((param[0] << 8) | param[1]))
return -1;
return param[2];
}
static int alps_command_mode_read_reg(struct psmouse *psmouse, int addr)
{
if (alps_command_mode_set_addr(psmouse, addr))
return -1;
return __alps_command_mode_read_reg(psmouse, addr);
}
static int __alps_command_mode_write_reg(struct psmouse *psmouse, u8 value)
{
if (alps_command_mode_send_nibble(psmouse, (value >> 4) & 0xf))
return -1;
if (alps_command_mode_send_nibble(psmouse, value & 0xf))
return -1;
return 0;
}
static int alps_command_mode_write_reg(struct psmouse *psmouse, int addr,
u8 value)
{
if (alps_command_mode_set_addr(psmouse, addr))
return -1;
return __alps_command_mode_write_reg(psmouse, value);
}
static int alps_enter_command_mode(struct psmouse *psmouse,
unsigned char *resp)
{
unsigned char param[4];
struct ps2dev *ps2dev = &psmouse->ps2dev;
if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) {
psmouse_err(psmouse, "failed to enter command mode\n");
return -1;
}
if (param[0] != 0x88 && param[1] != 0x07) {
psmouse_dbg(psmouse,
"unknown response while entering command mode: %2.2x %2.2x %2.2x\n",
param[0], param[1], param[2]);
return -1;
}
if (resp)
*resp = param[2];
return 0;
}
static inline int alps_exit_command_mode(struct psmouse *psmouse)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM))
return -1;
return 0;
}
static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
static const unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 };
unsigned char param[4];
const struct alps_model_info *model = NULL;
int i;
/*
......@@ -464,12 +995,41 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int
*version = (param[0] << 8) | (param[1] << 4) | i;
}
for (i = 0; i < ARRAY_SIZE(alps_model_data); i++)
for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) {
if (!memcmp(param, alps_model_data[i].signature,
sizeof(alps_model_data[i].signature)))
return alps_model_data + i;
sizeof(alps_model_data[i].signature))) {
model = alps_model_data + i;
break;
}
}
return NULL;
if (model && model->proto_version > ALPS_PROTO_V2) {
/*
* Need to check command mode response to identify
* model
*/
model = NULL;
if (alps_enter_command_mode(psmouse, param)) {
psmouse_warn(psmouse,
"touchpad failed to enter command mode\n");
} else {
for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) {
if (alps_model_data[i].proto_version > ALPS_PROTO_V2 &&
alps_model_data[i].command_mode_resp == param[0]) {
model = alps_model_data + i;
break;
}
}
alps_exit_command_mode(psmouse);
if (!model)
psmouse_dbg(psmouse,
"Unknown command mode response %2.2x\n",
param[0]);
}
}
return model;
}
/*
......@@ -477,7 +1037,7 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int
* subsequent commands. It looks like glidepad is behind stickpointer,
* I'd thought it would be other way around...
*/
static int alps_passthrough_mode(struct psmouse *psmouse, bool enable)
static int alps_passthrough_mode_v2(struct psmouse *psmouse, bool enable)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11;
......@@ -494,7 +1054,7 @@ static int alps_passthrough_mode(struct psmouse *psmouse, bool enable)
return 0;
}
static int alps_absolute_mode(struct psmouse *psmouse)
static int alps_absolute_mode_v1_v2(struct psmouse *psmouse)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
......@@ -565,17 +1125,17 @@ static int alps_tap_mode(struct psmouse *psmouse, int enable)
static int alps_poll(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
unsigned char buf[6];
unsigned char buf[sizeof(psmouse->packet)];
bool poll_failed;
if (priv->i->flags & ALPS_PASS)
alps_passthrough_mode(psmouse, true);
alps_passthrough_mode_v2(psmouse, true);
poll_failed = ps2_command(&psmouse->ps2dev, buf,
PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)) < 0;
if (priv->i->flags & ALPS_PASS)
alps_passthrough_mode(psmouse, false);
alps_passthrough_mode_v2(psmouse, false);
if (poll_failed || (buf[0] & priv->i->mask0) != priv->i->byte0)
return -1;
......@@ -592,13 +1152,13 @@ static int alps_poll(struct psmouse *psmouse)
return 0;
}
static int alps_hw_init(struct psmouse *psmouse)
static int alps_hw_init_v1_v2(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
const struct alps_model_info *model = priv->i;
if ((model->flags & ALPS_PASS) &&
alps_passthrough_mode(psmouse, true)) {
alps_passthrough_mode_v2(psmouse, true)) {
return -1;
}
......@@ -607,13 +1167,13 @@ static int alps_hw_init(struct psmouse *psmouse)
return -1;
}
if (alps_absolute_mode(psmouse)) {
if (alps_absolute_mode_v1_v2(psmouse)) {
psmouse_err(psmouse, "Failed to enable absolute mode\n");
return -1;
}
if ((model->flags & ALPS_PASS) &&
alps_passthrough_mode(psmouse, false)) {
alps_passthrough_mode_v2(psmouse, false)) {
return -1;
}
......@@ -626,6 +1186,297 @@ static int alps_hw_init(struct psmouse *psmouse)
return 0;
}
/*
* Enable or disable passthrough mode to the trackstick. Must be in
* command mode when calling this function.
*/
static int alps_passthrough_mode_v3(struct psmouse *psmouse, bool enable)
{
int reg_val;
reg_val = alps_command_mode_read_reg(psmouse, 0x0008);
if (reg_val == -1)
return -1;
if (enable)
reg_val |= 0x01;
else
reg_val &= ~0x01;
if (__alps_command_mode_write_reg(psmouse, reg_val))
return -1;
return 0;
}
/* Must be in command mode when calling this function */
static int alps_absolute_mode_v3(struct psmouse *psmouse)
{
int reg_val;
reg_val = alps_command_mode_read_reg(psmouse, 0x0004);
if (reg_val == -1)
return -1;
reg_val |= 0x06;
if (__alps_command_mode_write_reg(psmouse, reg_val))
return -1;
return 0;
}
static int alps_hw_init_v3(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
struct ps2dev *ps2dev = &psmouse->ps2dev;
int reg_val;
unsigned char param[4];
priv->nibble_commands = alps_v3_nibble_commands;
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
if (alps_enter_command_mode(psmouse, NULL))
goto error;
/* Check for trackstick */
reg_val = alps_command_mode_read_reg(psmouse, 0x0008);
if (reg_val == -1)
goto error;
if (reg_val & 0x80) {
if (alps_passthrough_mode_v3(psmouse, true))
goto error;
if (alps_exit_command_mode(psmouse))
goto error;
/*
* E7 report for the trackstick
*
* There have been reports of failures to seem to trace back
* to the above trackstick check failing. When these occur
* this E7 report fails, so when that happens we continue
* with the assumption that there isn't a trackstick after
* all.
*/
param[0] = 0x64;
if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) {
psmouse_warn(psmouse, "trackstick E7 report failed\n");
} else {
psmouse_dbg(psmouse,
"trackstick E7 report: %2.2x %2.2x %2.2x\n",
param[0], param[1], param[2]);
/*
* Not sure what this does, but it is absolutely
* essential. Without it, the touchpad does not
* work at all and the trackstick just emits normal
* PS/2 packets.
*/
if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
alps_command_mode_send_nibble(psmouse, 0x9) ||
alps_command_mode_send_nibble(psmouse, 0x4)) {
psmouse_err(psmouse,
"Error sending magic E6 sequence\n");
goto error_passthrough;
}
}
if (alps_enter_command_mode(psmouse, NULL))
goto error_passthrough;
if (alps_passthrough_mode_v3(psmouse, false))
goto error;
}
if (alps_absolute_mode_v3(psmouse)) {
psmouse_err(psmouse, "Failed to enter absolute mode\n");
goto error;
}
reg_val = alps_command_mode_read_reg(psmouse, 0x0006);
if (reg_val == -1)
goto error;
if (__alps_command_mode_write_reg(psmouse, reg_val | 0x01))
goto error;
reg_val = alps_command_mode_read_reg(psmouse, 0x0007);
if (reg_val == -1)
goto error;
if (__alps_command_mode_write_reg(psmouse, reg_val | 0x01))
goto error;
if (alps_command_mode_read_reg(psmouse, 0x0144) == -1)
goto error;
if (__alps_command_mode_write_reg(psmouse, 0x04))
goto error;
if (alps_command_mode_read_reg(psmouse, 0x0159) == -1)
goto error;
if (__alps_command_mode_write_reg(psmouse, 0x03))
goto error;
if (alps_command_mode_read_reg(psmouse, 0x0163) == -1)
goto error;
if (alps_command_mode_write_reg(psmouse, 0x0163, 0x03))
goto error;
if (alps_command_mode_read_reg(psmouse, 0x0162) == -1)
goto error;
if (alps_command_mode_write_reg(psmouse, 0x0162, 0x04))
goto error;
/*
* This ensures the trackstick packets are in the format
* supported by this driver. If bit 1 isn't set the packet
* format is different.
*/
if (alps_command_mode_write_reg(psmouse, 0x0008, 0x82))
goto error;
alps_exit_command_mode(psmouse);
/* Set rate and enable data reporting */
param[0] = 0x64;
if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE) ||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
psmouse_err(psmouse, "Failed to enable data reporting\n");
return -1;
}
return 0;
error_passthrough:
/* Something failed while in passthrough mode, so try to get out */
if (!alps_enter_command_mode(psmouse, NULL))
alps_passthrough_mode_v3(psmouse, false);
error:
/*
* Leaving the touchpad in command mode will essentially render
* it unusable until the machine reboots, so exit it here just
* to be safe
*/
alps_exit_command_mode(psmouse);
return -1;
}
/* Must be in command mode when calling this function */
static int alps_absolute_mode_v4(struct psmouse *psmouse)
{
int reg_val;
reg_val = alps_command_mode_read_reg(psmouse, 0x0004);
if (reg_val == -1)
return -1;
reg_val |= 0x02;
if (__alps_command_mode_write_reg(psmouse, reg_val))
return -1;
return 0;
}
static int alps_hw_init_v4(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4];
priv->nibble_commands = alps_v4_nibble_commands;
priv->addr_command = PSMOUSE_CMD_DISABLE;
if (alps_enter_command_mode(psmouse, NULL))
goto error;
if (alps_absolute_mode_v4(psmouse)) {
psmouse_err(psmouse, "Failed to enter absolute mode\n");
goto error;
}
if (alps_command_mode_write_reg(psmouse, 0x0007, 0x8c))
goto error;
if (alps_command_mode_write_reg(psmouse, 0x0149, 0x03))
goto error;
if (alps_command_mode_write_reg(psmouse, 0x0160, 0x03))
goto error;
if (alps_command_mode_write_reg(psmouse, 0x017f, 0x15))
goto error;
if (alps_command_mode_write_reg(psmouse, 0x0151, 0x01))
goto error;
if (alps_command_mode_write_reg(psmouse, 0x0168, 0x03))
goto error;
if (alps_command_mode_write_reg(psmouse, 0x014a, 0x03))
goto error;
if (alps_command_mode_write_reg(psmouse, 0x0161, 0x03))
goto error;
alps_exit_command_mode(psmouse);
/*
* This sequence changes the output from a 9-byte to an
* 8-byte format. All the same data seems to be present,
* just in a more compact format.
*/
param[0] = 0xc8;
param[1] = 0x64;
param[2] = 0x50;
if (ps2_command(ps2dev, &param[0], PSMOUSE_CMD_SETRATE) ||
ps2_command(ps2dev, &param[1], PSMOUSE_CMD_SETRATE) ||
ps2_command(ps2dev, &param[2], PSMOUSE_CMD_SETRATE) ||
ps2_command(ps2dev, param, PSMOUSE_CMD_GETID))
return -1;
/* Set rate and enable data reporting */
param[0] = 0x64;
if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE) ||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
psmouse_err(psmouse, "Failed to enable data reporting\n");
return -1;
}
return 0;
error:
/*
* Leaving the touchpad in command mode will essentially render
* it unusable until the machine reboots, so exit it here just
* to be safe
*/
alps_exit_command_mode(psmouse);
return -1;
}
static int alps_hw_init(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
const struct alps_model_info *model = priv->i;
int ret = -1;
switch (model->proto_version) {
case ALPS_PROTO_V1:
case ALPS_PROTO_V2:
ret = alps_hw_init_v1_v2(psmouse);
break;
case ALPS_PROTO_V3:
ret = alps_hw_init_v3(psmouse);
break;
case ALPS_PROTO_V4:
ret = alps_hw_init_v4(psmouse);
break;
}
return ret;
}
static int alps_reconnect(struct psmouse *psmouse)
{
const struct alps_model_info *model;
......@@ -666,6 +1517,8 @@ int alps_init(struct psmouse *psmouse)
psmouse->private = priv;
psmouse_reset(psmouse);
model = alps_get_model(psmouse, &version);
if (!model)
goto init_fail;
......@@ -693,8 +1546,29 @@ int alps_init(struct psmouse *psmouse)
BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0);
input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
switch (model->proto_version) {
case ALPS_PROTO_V1:
case ALPS_PROTO_V2:
input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0);
input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
break;
case ALPS_PROTO_V3:
set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
input_mt_init_slots(dev1, 2);
input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0);
input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, ALPS_V3_Y_MAX, 0, 0);
set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit);
set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
/* fall through */
case ALPS_PROTO_V4:
input_set_abs_params(dev1, ABS_X, 0, ALPS_V3_X_MAX, 0, 0);
input_set_abs_params(dev1, ABS_Y, 0, ALPS_V3_Y_MAX, 0, 0);
break;
}
input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
if (model->flags & ALPS_WHEEL) {
......@@ -737,7 +1611,7 @@ int alps_init(struct psmouse *psmouse)
psmouse->poll = alps_poll;
psmouse->disconnect = alps_disconnect;
psmouse->reconnect = alps_reconnect;
psmouse->pktsize = 6;
psmouse->pktsize = model->proto_version == ALPS_PROTO_V4 ? 8 : 6;
/* We are having trouble resyncing ALPS touchpads so disable it for now */
psmouse->resync_time = 0;
......
......@@ -12,20 +12,39 @@
#ifndef _ALPS_H
#define _ALPS_H
#define ALPS_PROTO_V1 0
#define ALPS_PROTO_V2 1
#define ALPS_PROTO_V3 2
#define ALPS_PROTO_V4 3
struct alps_model_info {
unsigned char signature[3];
unsigned char command_mode_resp; /* v3/v4 only */
unsigned char proto_version;
unsigned char byte0, mask0;
unsigned char flags;
};
struct alps_nibble_commands {
int command;
unsigned char data;
};
struct alps_data {
struct input_dev *dev2; /* Relative device */
char phys[32]; /* Phys */
const struct alps_model_info *i;/* Info */
const struct alps_nibble_commands *nibble_commands;
int addr_command; /* Command to set register address */
int prev_fin; /* Finger bit from previous packet */
int multi_packet; /* Multi-packet data in progress */
unsigned char multi_data[6]; /* Saved multi-packet data */
u8 quirks;
struct timer_list timer;
};
#define ALPS_QUIRK_TRACKSTICK_BUTTONS 1 /* trakcstick buttons in trackstick packet */
#ifdef CONFIG_MOUSE_PS2_ALPS
int alps_detect(struct psmouse *psmouse, bool set_properties);
int alps_init(struct psmouse *psmouse);
......
......@@ -140,25 +140,13 @@ static int __exit amimouse_remove(struct platform_device *pdev)
}
static struct platform_driver amimouse_driver = {
.probe = amimouse_probe,
.remove = __exit_p(amimouse_remove),
.driver = {
.name = "amiga-mouse",
.owner = THIS_MODULE,
},
};
static int __init amimouse_init(void)
{
return platform_driver_probe(&amimouse_driver, amimouse_probe);
}
module_init(amimouse_init);
static void __exit amimouse_exit(void)
{
platform_driver_unregister(&amimouse_driver);
}
module_exit(amimouse_exit);
module_platform_driver(amimouse_driver);
MODULE_ALIAS("platform:amiga-mouse");
......@@ -42,6 +42,24 @@ static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c,
return 0;
}
/*
* V3 and later support this fast command
*/
static int elantech_send_cmd(struct psmouse *psmouse, unsigned char c,
unsigned char *param)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
if (ps2_command(ps2dev, NULL, ETP_PS2_CUSTOM_COMMAND) ||
ps2_command(ps2dev, NULL, c) ||
ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) {
psmouse_err(psmouse, "%s query 0x%02x failed.\n", __func__, c);
return -1;
}
return 0;
}
/*
* A retrying version of ps2_command
*/
......@@ -863,13 +881,13 @@ static int elantech_set_range(struct psmouse *psmouse,
i = (etd->fw_version > 0x020800 &&
etd->fw_version < 0x020900) ? 1 : 2;
if (synaptics_send_cmd(psmouse, ETP_FW_ID_QUERY, param))
if (etd->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
return -1;
fixed_dpi = param[1] & 0x10;
if (((etd->fw_version >> 16) == 0x14) && fixed_dpi) {
if (synaptics_send_cmd(psmouse, ETP_SAMPLE_QUERY, param))
if (etd->send_cmd(psmouse, ETP_SAMPLE_QUERY, param))
return -1;
*x_max = (etd->capabilities[1] - i) * param[1] / 2;
......@@ -888,7 +906,7 @@ static int elantech_set_range(struct psmouse *psmouse,
break;
case 3:
if (synaptics_send_cmd(psmouse, ETP_FW_ID_QUERY, param))
if (etd->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
return -1;
*x_max = (0x0f & param[0]) << 8 | param[1];
......@@ -896,7 +914,7 @@ static int elantech_set_range(struct psmouse *psmouse,
break;
case 4:
if (synaptics_send_cmd(psmouse, ETP_FW_ID_QUERY, param))
if (etd->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
return -1;
*x_max = (0x0f & param[0]) << 8 | param[1];
......@@ -912,6 +930,30 @@ static int elantech_set_range(struct psmouse *psmouse,
return 0;
}
/*
* (value from firmware) * 10 + 790 = dpi
* we also have to convert dpi to dots/mm (*10/254 to avoid floating point)
*/
static unsigned int elantech_convert_res(unsigned int val)
{
return (val * 10 + 790) * 10 / 254;
}
static int elantech_get_resolution_v4(struct psmouse *psmouse,
unsigned int *x_res,
unsigned int *y_res)
{
unsigned char param[3];
if (elantech_send_cmd(psmouse, ETP_RESOLUTION_QUERY, param))
return -1;
*x_res = elantech_convert_res(param[1] & 0x0f);
*y_res = elantech_convert_res((param[1] & 0xf0) >> 4);
return 0;
}
/*
* Set the appropriate event bits for the input subsystem
*/
......@@ -920,6 +962,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
struct input_dev *dev = psmouse->dev;
struct elantech_data *etd = psmouse->private;
unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, width = 0;
unsigned int x_res = 0, y_res = 0;
if (elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max, &width))
return -1;
......@@ -967,10 +1010,20 @@ static int elantech_set_input_params(struct psmouse *psmouse)
break;
case 4:
if (elantech_get_resolution_v4(psmouse, &x_res, &y_res)) {
/*
* if query failed, print a warning and leave the values
* zero to resemble synaptics.c behavior.
*/
psmouse_warn(psmouse, "couldn't query resolution data.\n");
}
__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
/* For X to recognize me as touchpad. */
input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
input_abs_set_res(dev, ABS_X, x_res);
input_abs_set_res(dev, ABS_Y, y_res);
/*
* range of pressure and width is the same as v2,
* report ABS_PRESSURE, ABS_TOOL_WIDTH for compatibility.
......@@ -983,6 +1036,8 @@ static int elantech_set_input_params(struct psmouse *psmouse)
input_mt_init_slots(dev, ETP_MAX_FINGERS);
input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
input_abs_set_res(dev, ABS_MT_POSITION_X, x_res);
input_abs_set_res(dev, ABS_MT_POSITION_Y, y_res);
input_set_abs_params(dev, ABS_MT_PRESSURE, ETP_PMIN_V2,
ETP_PMAX_V2, 0, 0);
/*
......@@ -1031,16 +1086,13 @@ static ssize_t elantech_set_int_attr(struct psmouse *psmouse,
struct elantech_data *etd = psmouse->private;
struct elantech_attr_data *attr = data;
unsigned char *reg = (unsigned char *) etd + attr->field_offset;
unsigned long value;
unsigned char value;
int err;
err = strict_strtoul(buf, 16, &value);
err = kstrtou8(buf, 16, &value);
if (err)
return err;
if (value > 0xff)
return -EINVAL;
/* Do we need to preserve some bits for version 2 hardware too? */
if (etd->hw_version == 1) {
if (attr->reg == 0x10)
......@@ -1233,9 +1285,11 @@ static int elantech_set_properties(struct elantech_data *etd)
}
}
/*
* Turn on packet checking by default.
*/
/* decide which send_cmd we're gonna use early */
etd->send_cmd = etd->hw_version >= 3 ? elantech_send_cmd :
synaptics_send_cmd;
/* Turn on packet checking by default */
etd->paritycheck = 1;
/*
......@@ -1291,7 +1345,7 @@ int elantech_init(struct psmouse *psmouse)
"assuming hardware version %d (with firmware version 0x%02x%02x%02x)\n",
etd->hw_version, param[0], param[1], param[2]);
if (synaptics_send_cmd(psmouse, ETP_CAPABILITIES_QUERY,
if (etd->send_cmd(psmouse, ETP_CAPABILITIES_QUERY,
etd->capabilities)) {
psmouse_err(psmouse, "failed to query capabilities.\n");
goto init_fail;
......
......@@ -20,6 +20,7 @@
#define ETP_FW_VERSION_QUERY 0x01
#define ETP_CAPABILITIES_QUERY 0x02
#define ETP_SAMPLE_QUERY 0x03
#define ETP_RESOLUTION_QUERY 0x04
/*
* Command values for register reading or writing
......@@ -135,6 +136,7 @@ struct elantech_data {
unsigned int width;
struct finger_pos mt[ETP_MAX_FINGERS];
unsigned char parity[256];
int (*send_cmd)(struct psmouse *psmouse, unsigned char c, unsigned char *param);
};
#ifdef CONFIG_MOUSE_PS2_ELANTECH
......
......@@ -178,18 +178,7 @@ static struct platform_driver gpio_mouse_device_driver = {
.owner = THIS_MODULE,
}
};
static int __init gpio_mouse_init(void)
{
return platform_driver_register(&gpio_mouse_device_driver);
}
module_init(gpio_mouse_init);
static void __exit gpio_mouse_exit(void)
{
platform_driver_unregister(&gpio_mouse_device_driver);
}
module_exit(gpio_mouse_exit);
module_platform_driver(gpio_mouse_device_driver);
MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
MODULE_DESCRIPTION("GPIO mouse driver");
......
......@@ -789,11 +789,14 @@ static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data,
const char *buf, size_t count)
{
struct hgpk_data *priv = psmouse->private;
unsigned long value;
unsigned int value;
int err;
err = strict_strtoul(buf, 10, &value);
if (err || value > 1)
err = kstrtouint(buf, 10, &value);
if (err)
return err;
if (value > 1)
return -EINVAL;
if (value != priv->powered) {
......@@ -881,11 +884,14 @@ static ssize_t hgpk_trigger_recal(struct psmouse *psmouse, void *data,
const char *buf, size_t count)
{
struct hgpk_data *priv = psmouse->private;
unsigned long value;
unsigned int value;
int err;
err = strict_strtoul(buf, 10, &value);
if (err || value != 1)
err = kstrtouint(buf, 10, &value);
if (err)
return err;
if (value != 1)
return -EINVAL;
/*
......
......@@ -155,9 +155,14 @@ static ssize_t ps2pp_attr_show_smartscroll(struct psmouse *psmouse,
static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data,
const char *buf, size_t count)
{
unsigned long value;
unsigned int value;
int err;
if (strict_strtoul(buf, 10, &value) || value > 1)
err = kstrtouint(buf, 10, &value);
if (err)
return err;
if (value > 1)
return -EINVAL;
ps2pp_set_smartscroll(psmouse, value);
......
......@@ -127,7 +127,7 @@ struct psmouse_protocol {
* relevant events to the input module once full packet has arrived.
*/
static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
{
struct input_dev *dev = psmouse->dev;
unsigned char *packet = psmouse->packet;
......@@ -418,6 +418,49 @@ int psmouse_reset(struct psmouse *psmouse)
return 0;
}
/*
* Here we set the mouse resolution.
*/
void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution)
{
static const unsigned char params[] = { 0, 1, 2, 2, 3 };
unsigned char p;
if (resolution == 0 || resolution > 200)
resolution = 200;
p = params[resolution / 50];
ps2_command(&psmouse->ps2dev, &p, PSMOUSE_CMD_SETRES);
psmouse->resolution = 25 << p;
}
/*
* Here we set the mouse report rate.
*/
static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate)
{
static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 };
unsigned char r;
int i = 0;
while (rates[i] > rate) i++;
r = rates[i];
ps2_command(&psmouse->ps2dev, &r, PSMOUSE_CMD_SETRATE);
psmouse->rate = r;
}
/*
* psmouse_poll() - default poll handler. Everyone except for ALPS uses it.
*/
static int psmouse_poll(struct psmouse *psmouse)
{
return ps2_command(&psmouse->ps2dev, psmouse->packet,
PSMOUSE_CMD_POLL | (psmouse->pktsize << 8));
}
/*
* Genius NetMouse magic init.
......@@ -602,6 +645,56 @@ static int cortron_detect(struct psmouse *psmouse, bool set_properties)
return 0;
}
/*
* Apply default settings to the psmouse structure. Most of them will
* be overridden by individual protocol initialization routines.
*/
static void psmouse_apply_defaults(struct psmouse *psmouse)
{
struct input_dev *input_dev = psmouse->dev;
memset(input_dev->evbit, 0, sizeof(input_dev->evbit));
memset(input_dev->keybit, 0, sizeof(input_dev->keybit));
memset(input_dev->relbit, 0, sizeof(input_dev->relbit));
memset(input_dev->absbit, 0, sizeof(input_dev->absbit));
memset(input_dev->mscbit, 0, sizeof(input_dev->mscbit));
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(EV_REL, input_dev->evbit);
__set_bit(BTN_LEFT, input_dev->keybit);
__set_bit(BTN_RIGHT, input_dev->keybit);
__set_bit(REL_X, input_dev->relbit);
__set_bit(REL_Y, input_dev->relbit);
psmouse->set_rate = psmouse_set_rate;
psmouse->set_resolution = psmouse_set_resolution;
psmouse->poll = psmouse_poll;
psmouse->protocol_handler = psmouse_process_byte;
psmouse->pktsize = 3;
psmouse->reconnect = NULL;
psmouse->disconnect = NULL;
psmouse->cleanup = NULL;
psmouse->pt_activate = NULL;
psmouse->pt_deactivate = NULL;
}
/*
* Apply default settings to the psmouse structure and call specified
* protocol detection or initialization routine.
*/
static int psmouse_do_detect(int (*detect)(struct psmouse *psmouse,
bool set_properties),
struct psmouse *psmouse, bool set_properties)
{
if (set_properties)
psmouse_apply_defaults(psmouse);
return detect(psmouse, set_properties);
}
/*
* psmouse_extensions() probes for any extensions to the basic PS/2 protocol
* the mouse may have.
......@@ -616,7 +709,7 @@ static int psmouse_extensions(struct psmouse *psmouse,
* We always check for lifebook because it does not disturb mouse
* (it only checks DMI information).
*/
if (lifebook_detect(psmouse, set_properties) == 0) {
if (psmouse_do_detect(lifebook_detect, psmouse, set_properties) == 0) {
if (max_proto > PSMOUSE_IMEX) {
if (!set_properties || lifebook_init(psmouse) == 0)
return PSMOUSE_LIFEBOOK;
......@@ -628,15 +721,18 @@ static int psmouse_extensions(struct psmouse *psmouse,
* upsets the thinkingmouse).
*/
if (max_proto > PSMOUSE_IMEX && thinking_detect(psmouse, set_properties) == 0)
if (max_proto > PSMOUSE_IMEX &&
psmouse_do_detect(thinking_detect, psmouse, set_properties) == 0) {
return PSMOUSE_THINKPS;
}
/*
* Try Synaptics TouchPad. Note that probing is done even if Synaptics protocol
* support is disabled in config - we need to know if it is synaptics so we
* can reset it properly after probing for intellimouse.
*/
if (max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse, set_properties) == 0) {
if (max_proto > PSMOUSE_PS2 &&
psmouse_do_detect(synaptics_detect, psmouse, set_properties) == 0) {
synaptics_hardware = true;
if (max_proto > PSMOUSE_IMEX) {
......@@ -667,7 +763,8 @@ static int psmouse_extensions(struct psmouse *psmouse,
*/
if (max_proto > PSMOUSE_IMEX) {
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
if (alps_detect(psmouse, set_properties) == 0) {
if (psmouse_do_detect(alps_detect,
psmouse, set_properties) == 0) {
if (!set_properties || alps_init(psmouse) == 0)
return PSMOUSE_ALPS;
/*
......@@ -681,7 +778,7 @@ static int psmouse_extensions(struct psmouse *psmouse,
* Try OLPC HGPK touchpad.
*/
if (max_proto > PSMOUSE_IMEX &&
hgpk_detect(psmouse, set_properties) == 0) {
psmouse_do_detect(hgpk_detect, psmouse, set_properties) == 0) {
if (!set_properties || hgpk_init(psmouse) == 0)
return PSMOUSE_HGPK;
/*
......@@ -694,7 +791,7 @@ static int psmouse_extensions(struct psmouse *psmouse,
* Try Elantech touchpad.
*/
if (max_proto > PSMOUSE_IMEX &&
elantech_detect(psmouse, set_properties) == 0) {
psmouse_do_detect(elantech_detect, psmouse, set_properties) == 0) {
if (!set_properties || elantech_init(psmouse) == 0)
return PSMOUSE_ELANTECH;
/*
......@@ -703,18 +800,21 @@ static int psmouse_extensions(struct psmouse *psmouse,
max_proto = PSMOUSE_IMEX;
}
if (max_proto > PSMOUSE_IMEX) {
if (genius_detect(psmouse, set_properties) == 0)
if (psmouse_do_detect(genius_detect,
psmouse, set_properties) == 0)
return PSMOUSE_GENPS;
if (ps2pp_init(psmouse, set_properties) == 0)
if (psmouse_do_detect(ps2pp_init,
psmouse, set_properties) == 0)
return PSMOUSE_PS2PP;
if (trackpoint_detect(psmouse, set_properties) == 0)
if (psmouse_do_detect(trackpoint_detect,
psmouse, set_properties) == 0)
return PSMOUSE_TRACKPOINT;
if (touchkit_ps2_detect(psmouse, set_properties) == 0)
if (psmouse_do_detect(touchkit_ps2_detect,
psmouse, set_properties) == 0)
return PSMOUSE_TOUCHKIT_PS2;
}
......@@ -723,7 +823,8 @@ static int psmouse_extensions(struct psmouse *psmouse,
* Trackpoint devices (causing TP_READ_ID command to time out).
*/
if (max_proto > PSMOUSE_IMEX) {
if (fsp_detect(psmouse, set_properties) == 0) {
if (psmouse_do_detect(fsp_detect,
psmouse, set_properties) == 0) {
if (!set_properties || fsp_init(psmouse) == 0)
return PSMOUSE_FSP;
/*
......@@ -741,17 +842,23 @@ static int psmouse_extensions(struct psmouse *psmouse,
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
psmouse_reset(psmouse);
if (max_proto >= PSMOUSE_IMEX && im_explorer_detect(psmouse, set_properties) == 0)
if (max_proto >= PSMOUSE_IMEX &&
psmouse_do_detect(im_explorer_detect,
psmouse, set_properties) == 0) {
return PSMOUSE_IMEX;
}
if (max_proto >= PSMOUSE_IMPS && intellimouse_detect(psmouse, set_properties) == 0)
if (max_proto >= PSMOUSE_IMPS &&
psmouse_do_detect(intellimouse_detect,
psmouse, set_properties) == 0) {
return PSMOUSE_IMPS;
}
/*
* Okay, all failed, we have a standard mouse here. The number of the buttons
* is still a question, though. We assume 3.
*/
ps2bare_detect(psmouse, set_properties);
psmouse_do_detect(ps2bare_detect, psmouse, set_properties);
if (synaptics_hardware) {
/*
......@@ -819,6 +926,13 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.detect = synaptics_detect,
.init = synaptics_init,
},
{
.type = PSMOUSE_SYNAPTICS_RELATIVE,
.name = "SynRelPS/2",
.alias = "synaptics-relative",
.detect = synaptics_detect,
.init = synaptics_init_relative,
},
#endif
#ifdef CONFIG_MOUSE_PS2_ALPS
{
......@@ -957,39 +1071,6 @@ static int psmouse_probe(struct psmouse *psmouse)
return 0;
}
/*
* Here we set the mouse resolution.
*/
void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution)
{
static const unsigned char params[] = { 0, 1, 2, 2, 3 };
unsigned char p;
if (resolution == 0 || resolution > 200)
resolution = 200;
p = params[resolution / 50];
ps2_command(&psmouse->ps2dev, &p, PSMOUSE_CMD_SETRES);
psmouse->resolution = 25 << p;
}
/*
* Here we set the mouse report rate.
*/
static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate)
{
static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 };
unsigned char r;
int i = 0;
while (rates[i] > rate) i++;
r = rates[i];
ps2_command(&psmouse->ps2dev, &r, PSMOUSE_CMD_SETRATE);
psmouse->rate = r;
}
/*
* psmouse_initialize() initializes the mouse to a sane state.
*/
......@@ -1035,16 +1116,6 @@ static void psmouse_deactivate(struct psmouse *psmouse)
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
}
/*
* psmouse_poll() - default poll handler. Everyone except for ALPS uses it.
*/
static int psmouse_poll(struct psmouse *psmouse)
{
return ps2_command(&psmouse->ps2dev, psmouse->packet,
PSMOUSE_CMD_POLL | (psmouse->pktsize << 8));
}
/*
* psmouse_resync() attempts to re-validate current protocol.
......@@ -1245,18 +1316,9 @@ static int psmouse_switch_protocol(struct psmouse *psmouse,
input_dev->dev.parent = &psmouse->ps2dev.serio->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
input_dev->keybit[BIT_WORD(BTN_MOUSE)] =
BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
psmouse->set_rate = psmouse_set_rate;
psmouse->set_resolution = psmouse_set_resolution;
psmouse->poll = psmouse_poll;
psmouse->protocol_handler = psmouse_process_byte;
psmouse->pktsize = 3;
if (proto && (proto->detect || proto->init)) {
psmouse_apply_defaults(psmouse);
if (proto->detect && proto->detect(psmouse, true) < 0)
return -1;
......@@ -1558,13 +1620,12 @@ static ssize_t psmouse_show_int_attr(struct psmouse *psmouse, void *offset, char
static ssize_t psmouse_set_int_attr(struct psmouse *psmouse, void *offset, const char *buf, size_t count)
{
unsigned int *field = (unsigned int *)((char *)psmouse + (size_t)offset);
unsigned long value;
if (strict_strtoul(buf, 10, &value))
return -EINVAL;
unsigned int value;
int err;
if ((unsigned int)value != value)
return -EINVAL;
err = kstrtouint(buf, 10, &value);
if (err)
return err;
*field = value;
......@@ -1671,10 +1732,12 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co
static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, void *data, const char *buf, size_t count)
{
unsigned long value;
unsigned int value;
int err;
if (strict_strtoul(buf, 10, &value))
return -EINVAL;
err = kstrtouint(buf, 10, &value);
if (err)
return err;
psmouse->set_rate(psmouse, value);
return count;
......@@ -1682,10 +1745,12 @@ static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, void *data, const
static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, void *data, const char *buf, size_t count)
{
unsigned long value;
unsigned int value;
int err;
if (strict_strtoul(buf, 10, &value))
return -EINVAL;
err = kstrtouint(buf, 10, &value);
if (err)
return err;
psmouse->set_resolution(psmouse, value);
return count;
......
......@@ -8,6 +8,7 @@
#define PSMOUSE_CMD_SETSTREAM 0x00ea
#define PSMOUSE_CMD_SETPOLL 0x00f0
#define PSMOUSE_CMD_POLL 0x00eb /* caller sets number of bytes to receive */
#define PSMOUSE_CMD_RESET_WRAP 0x00ec
#define PSMOUSE_CMD_GETID 0x02f2
#define PSMOUSE_CMD_SETRATE 0x10f3
#define PSMOUSE_CMD_ENABLE 0x00f4
......@@ -93,6 +94,7 @@ enum psmouse_type {
PSMOUSE_HGPK,
PSMOUSE_ELANTECH,
PSMOUSE_FSP,
PSMOUSE_SYNAPTICS_RELATIVE,
PSMOUSE_AUTO /* This one should always be last */
};
......@@ -102,6 +104,7 @@ int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
int psmouse_reset(struct psmouse *psmouse);
void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state);
void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution);
psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse);
struct psmouse_attribute {
struct device_attribute dattr;
......
......@@ -250,19 +250,7 @@ static struct platform_driver pxa930_trkball_driver = {
.probe = pxa930_trkball_probe,
.remove = __devexit_p(pxa930_trkball_remove),
};
static int __init pxa930_trkball_init(void)
{
return platform_driver_register(&pxa930_trkball_driver);
}
static void __exit pxa930_trkball_exit(void)
{
platform_driver_unregister(&pxa930_trkball_driver);
}
module_init(pxa930_trkball_init);
module_exit(pxa930_trkball_exit);
module_platform_driver(pxa930_trkball_driver);
MODULE_AUTHOR("Yong Yao <yaoyong@marvell.com>");
MODULE_DESCRIPTION("PXA930 Trackball Mouse Driver");
......
......@@ -408,7 +408,7 @@ static int fsp_onpad_hscr(struct psmouse *psmouse, bool enable)
static ssize_t fsp_attr_set_setreg(struct psmouse *psmouse, void *data,
const char *buf, size_t count)
{
unsigned long reg, val;
int reg, val;
char *rest;
ssize_t retval;
......@@ -416,7 +416,11 @@ static ssize_t fsp_attr_set_setreg(struct psmouse *psmouse, void *data,
if (rest == buf || *rest != ' ' || reg > 0xff)
return -EINVAL;
if (strict_strtoul(rest + 1, 16, &val) || val > 0xff)
retval = kstrtoint(rest + 1, 16, &val);
if (retval)
return retval;
if (val > 0xff)
return -EINVAL;
if (fsp_reg_write_enable(psmouse, true))
......@@ -448,10 +452,13 @@ static ssize_t fsp_attr_set_getreg(struct psmouse *psmouse, void *data,
const char *buf, size_t count)
{
struct fsp_data *pad = psmouse->private;
unsigned long reg;
int val;
int reg, val, err;
err = kstrtoint(buf, 16, &reg);
if (err)
return err;
if (strict_strtoul(buf, 16, &reg) || reg > 0xff)
if (reg > 0xff)
return -EINVAL;
if (fsp_reg_read(psmouse, reg, &val))
......@@ -480,9 +487,13 @@ static ssize_t fsp_attr_show_pagereg(struct psmouse *psmouse,
static ssize_t fsp_attr_set_pagereg(struct psmouse *psmouse, void *data,
const char *buf, size_t count)
{
unsigned long val;
int val, err;
if (strict_strtoul(buf, 16, &val) || val > 0xff)
err = kstrtoint(buf, 16, &val);
if (err)
return err;
if (val > 0xff)
return -EINVAL;
if (fsp_page_reg_write(psmouse, val))
......@@ -505,9 +516,14 @@ static ssize_t fsp_attr_show_vscroll(struct psmouse *psmouse,
static ssize_t fsp_attr_set_vscroll(struct psmouse *psmouse, void *data,
const char *buf, size_t count)
{
unsigned long val;
unsigned int val;
int err;
err = kstrtouint(buf, 10, &val);
if (err)
return err;
if (strict_strtoul(buf, 10, &val) || val > 1)
if (val > 1)
return -EINVAL;
fsp_onpad_vscr(psmouse, val);
......@@ -529,9 +545,14 @@ static ssize_t fsp_attr_show_hscroll(struct psmouse *psmouse,
static ssize_t fsp_attr_set_hscroll(struct psmouse *psmouse, void *data,
const char *buf, size_t count)
{
unsigned long val;
unsigned int val;
int err;
err = kstrtouint(buf, 10, &val);
if (err)
return err;
if (strict_strtoul(buf, 10, &val) || val > 1)
if (val > 1)
return -EINVAL;
fsp_onpad_hscr(psmouse, val);
......
......@@ -269,19 +269,49 @@ static int synaptics_query_hardware(struct psmouse *psmouse)
return 0;
}
static int synaptics_set_absolute_mode(struct psmouse *psmouse)
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))
return 0;
if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL))
return -1;
if (ps2_command(&psmouse->ps2dev, &param, PSMOUSE_CMD_SETRATE))
return -1;
/* Advanced gesture mode also sends multi finger data */
priv->capabilities |= BIT(1);
return 0;
}
static int synaptics_set_mode(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;
priv->mode = SYN_BIT_ABSOLUTE_MODE;
if (SYN_ID_MAJOR(priv->identity) >= 4)
priv->mode = 0;
if (priv->absolute_mode)
priv->mode |= SYN_BIT_ABSOLUTE_MODE;
if (priv->disable_gesture)
priv->mode |= SYN_BIT_DISABLE_GESTURE;
if (psmouse->rate >= 80)
priv->mode |= SYN_BIT_HIGH_RATE;
if (SYN_CAP_EXTENDED(priv->capabilities))
priv->mode |= SYN_BIT_W_MODE;
if (synaptics_mode_cmd(psmouse, priv->mode))
return -1;
if (priv->absolute_mode &&
synaptics_set_advanced_gesture_mode(psmouse)) {
psmouse_err(psmouse, "Advanced gesture mode init failed.\n");
return -1;
}
return 0;
}
......@@ -300,26 +330,6 @@ static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate)
synaptics_mode_cmd(psmouse, priv->mode);
}
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) ||
SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)))
return 0;
if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL))
return -1;
if (ps2_command(&psmouse->ps2dev, &param, PSMOUSE_CMD_SETRATE))
return -1;
/* Advanced gesture mode also sends multi finger data */
priv->capabilities |= BIT(1);
return 0;
}
/*****************************************************************************
* Synaptics pass-through PS/2 port support
****************************************************************************/
......@@ -1143,8 +1153,24 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
{
int i;
/* Things that apply to both modes */
__set_bit(INPUT_PROP_POINTER, dev->propbit);
__set_bit(EV_KEY, dev->evbit);
__set_bit(BTN_LEFT, dev->keybit);
__set_bit(BTN_RIGHT, dev->keybit);
if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
__set_bit(BTN_MIDDLE, dev->keybit);
if (!priv->absolute_mode) {
/* Relative mode */
__set_bit(EV_REL, dev->evbit);
__set_bit(REL_X, dev->relbit);
__set_bit(REL_Y, dev->relbit);
return;
}
/* Absolute mode */
__set_bit(EV_ABS, dev->evbit);
set_abs_position_params(dev, priv, ABS_X, ABS_Y);
input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
......@@ -1170,20 +1196,14 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
if (SYN_CAP_PALMDETECT(priv->capabilities))
input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
__set_bit(EV_KEY, dev->evbit);
__set_bit(BTN_TOUCH, dev->keybit);
__set_bit(BTN_TOOL_FINGER, dev->keybit);
__set_bit(BTN_LEFT, dev->keybit);
__set_bit(BTN_RIGHT, dev->keybit);
if (SYN_CAP_MULTIFINGER(priv->capabilities)) {
__set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
__set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
}
if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
__set_bit(BTN_MIDDLE, dev->keybit);
if (SYN_CAP_FOUR_BUTTON(priv->capabilities) ||
SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
__set_bit(BTN_FORWARD, dev->keybit);
......@@ -1205,10 +1225,58 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
}
}
static ssize_t synaptics_show_disable_gesture(struct psmouse *psmouse,
void *data, char *buf)
{
struct synaptics_data *priv = psmouse->private;
return sprintf(buf, "%c\n", priv->disable_gesture ? '1' : '0');
}
static ssize_t synaptics_set_disable_gesture(struct psmouse *psmouse,
void *data, const char *buf,
size_t len)
{
struct synaptics_data *priv = psmouse->private;
unsigned int value;
int err;
err = kstrtouint(buf, 10, &value);
if (err)
return err;
if (value > 1)
return -EINVAL;
if (value == priv->disable_gesture)
return len;
priv->disable_gesture = value;
if (value)
priv->mode |= SYN_BIT_DISABLE_GESTURE;
else
priv->mode &= ~SYN_BIT_DISABLE_GESTURE;
if (synaptics_mode_cmd(psmouse, priv->mode))
return -EIO;
return len;
}
PSMOUSE_DEFINE_ATTR(disable_gesture, S_IWUSR | S_IRUGO, NULL,
synaptics_show_disable_gesture,
synaptics_set_disable_gesture);
static void synaptics_disconnect(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;
if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(priv->identity))
device_remove_file(&psmouse->ps2dev.serio->dev,
&psmouse_attr_disable_gesture.dattr);
synaptics_reset(psmouse);
kfree(psmouse->private);
kfree(priv);
psmouse->private = NULL;
}
......@@ -1245,17 +1313,11 @@ static int synaptics_reconnect(struct psmouse *psmouse)
return -1;
}
if (synaptics_set_absolute_mode(psmouse)) {
if (synaptics_set_mode(psmouse)) {
psmouse_err(psmouse, "Unable to initialize device.\n");
return -1;
}
if (synaptics_set_advanced_gesture_mode(psmouse)) {
psmouse_err(psmouse,
"Advanced gesture mode reconnect failed.\n");
return -1;
}
if (old_priv.identity != priv->identity ||
old_priv.model_id != priv->model_id ||
old_priv.capabilities != priv->capabilities ||
......@@ -1332,20 +1394,18 @@ void __init synaptics_module_init(void)
broken_olpc_ec = dmi_check_system(olpc_dmi_table);
}
int synaptics_init(struct psmouse *psmouse)
static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)
{
struct synaptics_data *priv;
int err = -1;
/*
* The OLPC XO has issues with Synaptics' absolute mode; similarly to
* the HGPK, it quickly degrades and the hardware becomes jumpy and
* overly sensitive. Not only that, but the constant packet spew
* (even at a lowered 40pps rate) overloads the EC such that key
* presses on the keyboard are missed. Given all of that, don't
* even attempt to use Synaptics mode. Relative mode seems to work
* just fine.
* The OLPC XO has issues with Synaptics' absolute mode; the constant
* packet spew overloads the EC such that key presses on the keyboard
* are missed. Given that, don't even attempt to use Absolute mode.
* Relative mode seems to work just fine.
*/
if (broken_olpc_ec) {
if (absolute_mode && broken_olpc_ec) {
psmouse_info(psmouse,
"OLPC XO detected, not enabling Synaptics protocol.\n");
return -ENODEV;
......@@ -1362,13 +1422,12 @@ int synaptics_init(struct psmouse *psmouse)
goto init_fail;
}
if (synaptics_set_absolute_mode(psmouse)) {
psmouse_err(psmouse, "Unable to initialize device.\n");
goto init_fail;
}
priv->absolute_mode = absolute_mode;
if (SYN_ID_DISGEST_SUPPORTED(priv->identity))
priv->disable_gesture = true;
if (synaptics_set_advanced_gesture_mode(psmouse)) {
psmouse_err(psmouse, "Advanced gesture mode init failed.\n");
if (synaptics_set_mode(psmouse)) {
psmouse_err(psmouse, "Unable to initialize device.\n");
goto init_fail;
}
......@@ -1393,12 +1452,19 @@ int synaptics_init(struct psmouse *psmouse)
psmouse->model = ((priv->model_id & 0x00ff0000) >> 8) |
(priv->model_id & 0x000000ff);
psmouse->protocol_handler = synaptics_process_byte;
if (absolute_mode) {
psmouse->protocol_handler = synaptics_process_byte;
psmouse->pktsize = 6;
} else {
/* Relative mode follows standard PS/2 mouse protocol */
psmouse->protocol_handler = psmouse_process_byte;
psmouse->pktsize = 3;
}
psmouse->set_rate = synaptics_set_rate;
psmouse->disconnect = synaptics_disconnect;
psmouse->reconnect = synaptics_reconnect;
psmouse->cleanup = synaptics_reset;
psmouse->pktsize = 6;
/* Synaptics can usually stay in sync without extra help */
psmouse->resync_time = 0;
......@@ -1417,11 +1483,32 @@ int synaptics_init(struct psmouse *psmouse)
psmouse->rate = 40;
}
if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(priv->identity)) {
err = device_create_file(&psmouse->ps2dev.serio->dev,
&psmouse_attr_disable_gesture.dattr);
if (err) {
psmouse_err(psmouse,
"Failed to create disable_gesture attribute (%d)",
err);
goto init_fail;
}
}
return 0;
init_fail:
kfree(priv);
return -1;
return err;
}
int synaptics_init(struct psmouse *psmouse)
{
return __synaptics_init(psmouse, true);
}
int synaptics_init_relative(struct psmouse *psmouse)
{
return __synaptics_init(psmouse, false);
}
bool synaptics_supported(void)
......
......@@ -100,6 +100,7 @@
#define SYN_ID_MINOR(i) (((i) >> 16) & 0xff)
#define SYN_ID_FULL(i) ((SYN_ID_MAJOR(i) << 8) | SYN_ID_MINOR(i))
#define SYN_ID_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47)
#define SYN_ID_DISGEST_SUPPORTED(i) (SYN_ID_MAJOR(i) >= 4)
/* synaptics special commands */
#define SYN_PS_SET_MODE2 0x14
......@@ -159,6 +160,9 @@ struct synaptics_data {
unsigned char mode; /* current mode byte */
int scroll;
bool absolute_mode; /* run in Absolute mode */
bool disable_gesture; /* disable gestures */
struct serio *pt_port; /* Pass-through serio port */
struct synaptics_mt_state mt_state; /* Current mt finger state */
......@@ -175,6 +179,7 @@ struct synaptics_data {
void synaptics_module_init(void);
int synaptics_detect(struct psmouse *psmouse, bool set_properties);
int synaptics_init(struct psmouse *psmouse);
int synaptics_init_relative(struct psmouse *psmouse);
void synaptics_reset(struct psmouse *psmouse);
bool synaptics_supported(void);
......
......@@ -89,10 +89,12 @@ static ssize_t trackpoint_set_int_attr(struct psmouse *psmouse, void *data,
struct trackpoint_data *tp = psmouse->private;
struct trackpoint_attr_data *attr = data;
unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset);
unsigned long value;
unsigned char value;
int err;
if (strict_strtoul(buf, 10, &value) || value > 255)
return -EINVAL;
err = kstrtou8(buf, 10, &value);
if (err)
return err;
*field = value;
trackpoint_write(&psmouse->ps2dev, attr->command, value);
......@@ -115,9 +117,14 @@ static ssize_t trackpoint_set_bit_attr(struct psmouse *psmouse, void *data,
struct trackpoint_data *tp = psmouse->private;
struct trackpoint_attr_data *attr = data;
unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset);
unsigned long value;
unsigned int value;
int err;
err = kstrtouint(buf, 10, &value);
if (err)
return err;
if (strict_strtoul(buf, 10, &value) || value > 1)
if (value > 1)
return -EINVAL;
if (attr->inverted)
......
......@@ -196,18 +196,7 @@ static struct platform_driver altera_ps2_driver = {
.of_match_table = altera_ps2_match,
},
};
static int __init altera_ps2_init(void)
{
return platform_driver_register(&altera_ps2_driver);
}
module_init(altera_ps2_init);
static void __exit altera_ps2_exit(void)
{
platform_driver_unregister(&altera_ps2_driver);
}
module_exit(altera_ps2_exit);
module_platform_driver(altera_ps2_driver);
MODULE_DESCRIPTION("Altera University Program PS2 controller driver");
MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
......
......@@ -358,19 +358,7 @@ static struct platform_driver psif_driver = {
.suspend = psif_suspend,
.resume = psif_resume,
};
static int __init psif_init(void)
{
return platform_driver_probe(&psif_driver, psif_probe);
}
static void __exit psif_exit(void)
{
platform_driver_unregister(&psif_driver);
}
module_init(psif_init);
module_exit(psif_exit);
module_platform_driver(psif_driver);
MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
MODULE_DESCRIPTION("Atmel AVR32 PSIF PS/2 driver");
......
......@@ -991,7 +991,7 @@ static int i8042_controller_init(void)
* Reset the controller and reset CRT to the original value set by BIOS.
*/
static void i8042_controller_reset(void)
static void i8042_controller_reset(bool force_reset)
{
i8042_flush();
......@@ -1016,7 +1016,7 @@ static void i8042_controller_reset(void)
* Reset the controller if requested.
*/
if (i8042_reset)
if (i8042_reset || force_reset)
i8042_controller_selftest();
/*
......@@ -1139,9 +1139,9 @@ static int i8042_controller_resume(bool force_reset)
* upsetting it.
*/
static int i8042_pm_reset(struct device *dev)
static int i8042_pm_suspend(struct device *dev)
{
i8042_controller_reset();
i8042_controller_reset(true);
return 0;
}
......@@ -1163,13 +1163,20 @@ static int i8042_pm_thaw(struct device *dev)
return 0;
}
static int i8042_pm_reset(struct device *dev)
{
i8042_controller_reset(false);
return 0;
}
static int i8042_pm_restore(struct device *dev)
{
return i8042_controller_resume(false);
}
static const struct dev_pm_ops i8042_pm_ops = {
.suspend = i8042_pm_reset,
.suspend = i8042_pm_suspend,
.resume = i8042_pm_resume,
.thaw = i8042_pm_thaw,
.poweroff = i8042_pm_reset,
......@@ -1185,7 +1192,7 @@ static const struct dev_pm_ops i8042_pm_ops = {
static void i8042_shutdown(struct platform_device *dev)
{
i8042_controller_reset();
i8042_controller_reset(false);
}
static int __init i8042_create_kbd_port(void)
......@@ -1424,7 +1431,7 @@ static int __init i8042_probe(struct platform_device *dev)
out_fail:
i8042_free_aux_ports(); /* in case KBD failed but AUX not */
i8042_free_irqs();
i8042_controller_reset();
i8042_controller_reset(false);
i8042_platform_device = NULL;
return error;
......@@ -1434,7 +1441,7 @@ static int __devexit i8042_remove(struct platform_device *dev)
{
i8042_unregister_ports();
i8042_free_irqs();
i8042_controller_reset();
i8042_controller_reset(false);
i8042_platform_device = NULL;
return 0;
......
......@@ -143,16 +143,4 @@ static struct platform_driver rpckbd_driver = {
.owner = THIS_MODULE,
},
};
static int __init rpckbd_init(void)
{
return platform_driver_register(&rpckbd_driver);
}
static void __exit rpckbd_exit(void)
{
platform_driver_unregister(&rpckbd_driver);
}
module_init(rpckbd_init);
module_exit(rpckbd_exit);
module_platform_driver(rpckbd_driver);
......@@ -369,19 +369,7 @@ static struct platform_driver xps2_of_driver = {
.probe = xps2_of_probe,
.remove = __devexit_p(xps2_of_remove),
};
static int __init xps2_init(void)
{
return platform_driver_register(&xps2_of_driver);
}
static void __exit xps2_cleanup(void)
{
platform_driver_unregister(&xps2_of_driver);
}
module_init(xps2_init);
module_exit(xps2_cleanup);
module_platform_driver(xps2_of_driver);
MODULE_AUTHOR("Xilinx, Inc.");
MODULE_DESCRIPTION("Xilinx XPS PS/2 driver");
......
......@@ -1198,9 +1198,9 @@ static ssize_t
store_tabletXtilt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct aiptek *aiptek = dev_get_drvdata(dev);
long x;
int x;
if (strict_strtol(buf, 10, &x)) {
if (kstrtoint(buf, 10, &x)) {
size_t len = buf[count - 1] == '\n' ? count - 1 : count;
if (strncmp(buf, "disable", len))
......@@ -1240,9 +1240,9 @@ static ssize_t
store_tabletYtilt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct aiptek *aiptek = dev_get_drvdata(dev);
long y;
int y;
if (strict_strtol(buf, 10, &y)) {
if (kstrtoint(buf, 10, &y)) {
size_t len = buf[count - 1] == '\n' ? count - 1 : count;
if (strncmp(buf, "disable", len))
......@@ -1277,12 +1277,13 @@ static ssize_t
store_tabletJitterDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct aiptek *aiptek = dev_get_drvdata(dev);
long j;
int err, j;
if (strict_strtol(buf, 10, &j))
return -EINVAL;
err = kstrtoint(buf, 10, &j);
if (err)
return err;
aiptek->newSetting.jitterDelay = (int)j;
aiptek->newSetting.jitterDelay = j;
return count;
}
......@@ -1306,12 +1307,13 @@ static ssize_t
store_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct aiptek *aiptek = dev_get_drvdata(dev);
long d;
int err, d;
if (strict_strtol(buf, 10, &d))
return -EINVAL;
err = kstrtoint(buf, 10, &d);
if (err)
return err;
aiptek->newSetting.programmableDelay = (int)d;
aiptek->newSetting.programmableDelay = d;
return count;
}
......@@ -1557,11 +1559,13 @@ static ssize_t
store_tabletWheel(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct aiptek *aiptek = dev_get_drvdata(dev);
long w;
int err, w;
if (strict_strtol(buf, 10, &w)) return -EINVAL;
err = kstrtoint(buf, 10, &w);
if (err)
return err;
aiptek->newSetting.wheel = (int)w;
aiptek->newSetting.wheel = w;
return count;
}
......
......@@ -28,7 +28,9 @@
#define HID_USAGE_Y_TILT 0x3e
#define HID_USAGE_FINGER 0x22
#define HID_USAGE_STYLUS 0x20
#define HID_COLLECTION 0xc0
#define HID_COLLECTION 0xa1
#define HID_COLLECTION_LOGICAL 0x02
#define HID_COLLECTION_END 0xc0
enum {
WCM_UNDEFINED = 0,
......@@ -66,7 +68,8 @@ static int wacom_get_report(struct usb_interface *intf, u8 type, u8 id,
do {
retval = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_REPORT,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
USB_DIR_IN | USB_TYPE_CLASS |
USB_RECIP_INTERFACE,
(type << 8) + id,
intf->altsetting[0].desc.bInterfaceNumber,
buf, size, 100);
......@@ -164,7 +167,70 @@ static void wacom_close(struct input_dev *dev)
usb_autopm_put_interface(wacom->intf);
}
static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hid_desc,
static int wacom_parse_logical_collection(unsigned char *report,
struct wacom_features *features)
{
int length = 0;
if (features->type == BAMBOO_PT) {
/* Logical collection is only used by 3rd gen Bamboo Touch */
features->pktlen = WACOM_PKGLEN_BBTOUCH3;
features->device_type = BTN_TOOL_DOUBLETAP;
/*
* Stylus and Touch have same active area
* so compute physical size based on stylus
* data before its overwritten.
*/
features->x_phy =
(features->x_max * features->x_resolution) / 100;
features->y_phy =
(features->y_max * features->y_resolution) / 100;
features->x_max = features->y_max =
get_unaligned_le16(&report[10]);
length = 11;
}
return length;
}
/*
* Interface Descriptor of wacom devices can be incomplete and
* inconsistent so wacom_features table is used to store stylus
* device's packet lengths, various maximum values, and tablet
* resolution based on product ID's.
*
* For devices that contain 2 interfaces, wacom_features table is
* inaccurate for the touch interface. Since the Interface Descriptor
* for touch interfaces has pretty complete data, this function exists
* to query tablet for this missing information instead of hard coding in
* an additional table.
*
* A typical Interface Descriptor for a stylus will contain a
* boot mouse application collection that is not of interest and this
* function will ignore it.
*
* It also contains a digitizer application collection that also is not
* of interest since any information it contains would be duplicate
* of what is in wacom_features. Usually it defines a report of an array
* of bytes that could be used as max length of the stylus packet returned.
* If it happens to define a Digitizer-Stylus Physical Collection then
* the X and Y logical values contain valid data but it is ignored.
*
* A typical Interface Descriptor for a touch interface will contain a
* Digitizer-Finger Physical Collection which will define both logical
* X/Y maximum as well as the physical size of tablet. Since touch
* interfaces haven't supported pressure or distance, this is enough
* information to override invalid values in the wacom_features table.
*
* 3rd gen Bamboo Touch no longer define a Digitizer-Finger Pysical
* Collection. Instead they define a Logical Collection with a single
* Logical Maximum for both X and Y.
*/
static int wacom_parse_hid(struct usb_interface *intf,
struct hid_descriptor *hid_desc,
struct wacom_features *features)
{
struct usb_device *dev = interface_to_usbdev(intf);
......@@ -244,8 +310,6 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
/* penabled only accepts exact bytes of data */
if (features->type == TABLETPC2FG)
features->pktlen = WACOM_PKGLEN_GRAPHIRE;
if (features->type == BAMBOO_PT)
features->pktlen = WACOM_PKGLEN_BBFUN;
features->device_type = BTN_TOOL_PEN;
features->x_max =
get_unaligned_le16(&report[i + 3]);
......@@ -287,8 +351,6 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
/* penabled only accepts exact bytes of data */
if (features->type == TABLETPC2FG)
features->pktlen = WACOM_PKGLEN_GRAPHIRE;
if (features->type == BAMBOO_PT)
features->pktlen = WACOM_PKGLEN_BBFUN;
features->device_type = BTN_TOOL_PEN;
features->y_max =
get_unaligned_le16(&report[i + 3]);
......@@ -302,6 +364,11 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
i++;
break;
/*
* Requiring Stylus Usage will ignore boot mouse
* X/Y values and some cases of invalid Digitizer X/Y
* values commonly reported.
*/
case HID_USAGE_STYLUS:
pen = 1;
i++;
......@@ -309,10 +376,20 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
}
break;
case HID_COLLECTION:
case HID_COLLECTION_END:
/* reset UsagePage and Finger */
finger = usage = 0;
break;
case HID_COLLECTION:
i++;
switch (report[i]) {
case HID_COLLECTION_LOGICAL:
i += wacom_parse_logical_collection(&report[i],
features);
break;
}
break;
}
}
......@@ -348,7 +425,8 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
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) {
} else if (features->type != TABLETPC &&
features->device_type == BTN_TOOL_PEN) {
do {
rep_data[0] = 2;
rep_data[1] = 2;
......@@ -485,7 +563,8 @@ static int wacom_led_control(struct wacom *wacom)
if (!buf)
return -ENOMEM;
if (wacom->wacom_wac.features.type == WACOM_21UX2)
if (wacom->wacom_wac.features.type == WACOM_21UX2 ||
wacom->wacom_wac.features.type == WACOM_24HD)
led = (wacom->led.select[1] << 4) | 0x40;
led |= wacom->led.select[0] | 0x4;
......@@ -704,6 +783,7 @@ static int wacom_initialize_leds(struct wacom *wacom)
&intuos4_led_attr_group);
break;
case WACOM_24HD:
case WACOM_21UX2:
wacom->led.select[0] = 0;
wacom->led.select[1] = 0;
......@@ -738,6 +818,7 @@ static void wacom_destroy_leds(struct wacom *wacom)
&intuos4_led_attr_group);
break;
case WACOM_24HD:
case WACOM_21UX2:
sysfs_remove_group(&wacom->intf->dev.kobj,
&cintiq_led_attr_group);
......
......@@ -452,7 +452,7 @@ static void wacom_intuos_general(struct wacom_wac *wacom)
if ((data[1] & 0xb8) == 0xa0) {
t = (data[6] << 2) | ((data[7] >> 6) & 3);
if ((features->type >= INTUOS4S && features->type <= INTUOS4L) ||
features->type == WACOM_21UX2) {
features->type == WACOM_21UX2 || features->type == WACOM_24HD) {
t = (t << 1) | (data[1] & 1);
}
input_report_abs(input, ABS_PRESSURE, t);
......@@ -519,6 +519,56 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
input_report_key(input, wacom->tool[1], 0);
input_report_abs(input, ABS_MISC, 0);
}
} else if (features->type == WACOM_24HD) {
input_report_key(input, BTN_0, (data[6] & 0x01));
input_report_key(input, BTN_1, (data[6] & 0x02));
input_report_key(input, BTN_2, (data[6] & 0x04));
input_report_key(input, BTN_3, (data[6] & 0x08));
input_report_key(input, BTN_4, (data[6] & 0x10));
input_report_key(input, BTN_5, (data[6] & 0x20));
input_report_key(input, BTN_6, (data[6] & 0x40));
input_report_key(input, BTN_7, (data[6] & 0x80));
input_report_key(input, BTN_8, (data[8] & 0x01));
input_report_key(input, BTN_9, (data[8] & 0x02));
input_report_key(input, BTN_A, (data[8] & 0x04));
input_report_key(input, BTN_B, (data[8] & 0x08));
input_report_key(input, BTN_C, (data[8] & 0x10));
input_report_key(input, BTN_X, (data[8] & 0x20));
input_report_key(input, BTN_Y, (data[8] & 0x40));
input_report_key(input, BTN_Z, (data[8] & 0x80));
/*
* Three "buttons" are available on the 24HD which are
* physically implemented as a touchstrip. Each button
* is approximately 3 bits wide with a 2 bit spacing.
* The raw touchstrip bits are stored at:
* ((data[3] & 0x1f) << 8) | data[4])
*/
input_report_key(input, KEY_PROG1, data[4] & 0x07);
input_report_key(input, KEY_PROG2, data[4] & 0xE0);
input_report_key(input, KEY_PROG3, data[3] & 0x1C);
if (data[1] & 0x80) {
input_report_abs(input, ABS_WHEEL, (data[1] & 0x7f));
} else {
/* Out of proximity, clear wheel value. */
input_report_abs(input, ABS_WHEEL, 0);
}
if (data[2] & 0x80) {
input_report_abs(input, ABS_THROTTLE, (data[2] & 0x7f));
} else {
/* Out of proximity, clear second wheel value. */
input_report_abs(input, ABS_THROTTLE, 0);
}
if (data[1] | data[2] | (data[3] & 0x1f) | data[4] | data[6] | data[8]) {
input_report_key(input, wacom->tool[1], 1);
input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
} else {
input_report_key(input, wacom->tool[1], 0);
input_report_abs(input, ABS_MISC, 0);
}
} else {
if (features->type == WACOM_21UX2) {
input_report_key(input, BTN_0, (data[5] & 0x01));
......@@ -799,6 +849,9 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
unsigned char *data = wacom->data;
int i;
if (data[0] != 0x02)
return 0;
for (i = 0; i < 2; i++) {
int offset = (data[1] & 0x80) ? (8 * i) : (9 * i);
bool touch = data[offset + 3] & 0x80;
......@@ -837,18 +890,77 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
return 0;
}
static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
{
struct input_dev *input = wacom->input;
int slot_id = data[0] - 2; /* data[0] is between 2 and 17 */
bool touch = data[1] & 0x80;
touch = touch && !wacom->shared->stylus_in_proximity;
input_mt_slot(input, slot_id);
input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
if (touch) {
int x = (data[2] << 4) | (data[4] >> 4);
int y = (data[3] << 4) | (data[4] & 0x0f);
int w = data[6];
input_report_abs(input, ABS_MT_POSITION_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y);
input_report_abs(input, ABS_MT_TOUCH_MAJOR, w);
}
}
static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data)
{
struct input_dev *input = wacom->input;
input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0);
input_report_key(input, BTN_FORWARD, (data[1] & 0x04) != 0);
input_report_key(input, BTN_BACK, (data[1] & 0x02) != 0);
input_report_key(input, BTN_RIGHT, (data[1] & 0x01) != 0);
}
static int wacom_bpt3_touch(struct wacom_wac *wacom)
{
struct input_dev *input = wacom->input;
unsigned char *data = wacom->data;
int count = data[1] & 0x03;
int i;
if (data[0] != 0x02)
return 0;
/* data has up to 7 fixed sized 8-byte messages starting at data[2] */
for (i = 0; i < count; i++) {
int offset = (8 * i) + 2;
int msg_id = data[offset];
if (msg_id >= 2 && msg_id <= 17)
wacom_bpt3_touch_msg(wacom, data + offset);
else if (msg_id == 128)
wacom_bpt3_button_msg(wacom, data + offset);
}
input_mt_report_pointer_emulation(input, true);
input_sync(input);
return 0;
}
static int wacom_bpt_pen(struct wacom_wac *wacom)
{
struct input_dev *input = wacom->input;
unsigned char *data = wacom->data;
int prox = 0, x = 0, y = 0, p = 0, d = 0, pen = 0, btn1 = 0, btn2 = 0;
/*
* Similar to Graphire protocol, data[1] & 0x20 is proximity and
* data[1] & 0x18 is tool ID. 0x30 is safety check to ignore
* 2 unused tool ID's.
*/
prox = (data[1] & 0x30) == 0x30;
if (data[0] != 0x02)
return 0;
prox = (data[1] & 0x20) == 0x20;
/*
* All reports shared between PEN and RUBBER tool must be
......@@ -912,7 +1024,9 @@ static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len)
{
if (len == WACOM_PKGLEN_BBTOUCH)
return wacom_bpt_touch(wacom);
else if (len == WACOM_PKGLEN_BBFUN)
else if (len == WACOM_PKGLEN_BBTOUCH3)
return wacom_bpt3_touch(wacom);
else if (len == WACOM_PKGLEN_BBFUN || len == WACOM_PKGLEN_BBPEN)
return wacom_bpt_pen(wacom);
return 0;
......@@ -955,6 +1069,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
case CINTIQ:
case WACOM_BEE:
case WACOM_21UX2:
case WACOM_24HD:
sync = wacom_intuos_irq(wacom_wac);
break;
......@@ -1031,9 +1146,9 @@ void wacom_setup_device_quirks(struct wacom_features *features)
features->type == BAMBOO_PT)
features->quirks |= WACOM_QUIRK_MULTI_INPUT;
/* quirks for bamboo touch */
/* quirk for bamboo touch with 2 low res touches */
if (features->type == BAMBOO_PT &&
features->device_type == BTN_TOOL_DOUBLETAP) {
features->pktlen == WACOM_PKGLEN_BBTOUCH) {
features->x_max <<= 5;
features->y_max <<= 5;
features->x_fuzz <<= 5;
......@@ -1110,6 +1225,26 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
break;
case WACOM_24HD:
__set_bit(BTN_A, input_dev->keybit);
__set_bit(BTN_B, input_dev->keybit);
__set_bit(BTN_C, input_dev->keybit);
__set_bit(BTN_X, input_dev->keybit);
__set_bit(BTN_Y, input_dev->keybit);
__set_bit(BTN_Z, input_dev->keybit);
for (i = 0; i < 10; i++)
__set_bit(BTN_0 + i, input_dev->keybit);
__set_bit(KEY_PROG1, input_dev->keybit);
__set_bit(KEY_PROG2, input_dev->keybit);
__set_bit(KEY_PROG3, input_dev->keybit);
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0);
wacom_setup_cintiq(wacom_wac);
break;
case WACOM_21UX2:
__set_bit(BTN_A, input_dev->keybit);
__set_bit(BTN_B, input_dev->keybit);
......@@ -1240,7 +1375,21 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
input_mt_init_slots(input_dev, 2);
if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
__set_bit(BTN_TOOL_TRIPLETAP,
input_dev->keybit);
__set_bit(BTN_TOOL_QUADTAP,
input_dev->keybit);
input_mt_init_slots(input_dev, 16);
input_set_abs_params(input_dev,
ABS_MT_TOUCH_MAJOR,
0, 255, 0, 0);
} else {
input_mt_init_slots(input_dev, 2);
}
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
0, features->x_max,
features->x_fuzz, 0);
......@@ -1425,6 +1574,9 @@ static const struct wacom_features wacom_features_0xBB =
static const struct wacom_features wacom_features_0xBC =
{ "Wacom Intuos4 WL", WACOM_PKGLEN_INTUOS, 40840, 25400, 2047,
63, INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0xF4 =
{ "Wacom Cintiq 24HD", WACOM_PKGLEN_INTUOS, 104480, 65600, 2047,
63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0x3F =
{ "Wacom Cintiq 21UX", WACOM_PKGLEN_INTUOS, 87200, 65600, 1023,
63, CINTIQ, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
......@@ -1509,6 +1661,15 @@ static const struct wacom_features wacom_features_0xDA =
static struct wacom_features wacom_features_0xDB =
{ "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_0xDD =
{ "Wacom Bamboo Connect", WACOM_PKGLEN_BBPEN, 14720, 9200, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xDE =
{ "Wacom Bamboo 16FG 4x5", WACOM_PKGLEN_BBPEN, 14720, 9200, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xDF =
{ "Wacom Bamboo 16FG 6x8", WACOM_PKGLEN_BBPEN, 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 };
......@@ -1604,6 +1765,9 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0xD8) },
{ USB_DEVICE_WACOM(0xDA) },
{ USB_DEVICE_WACOM(0xDB) },
{ USB_DEVICE_WACOM(0xDD) },
{ USB_DEVICE_WACOM(0xDE) },
{ USB_DEVICE_WACOM(0xDF) },
{ USB_DEVICE_WACOM(0xF0) },
{ USB_DEVICE_WACOM(0xCC) },
{ USB_DEVICE_WACOM(0x90) },
......@@ -1616,6 +1780,7 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0xE6) },
{ USB_DEVICE_WACOM(0xEC) },
{ USB_DEVICE_WACOM(0x47) },
{ USB_DEVICE_WACOM(0xF4) },
{ USB_DEVICE_LENOVO(0x6004) },
{ }
};
......
......@@ -12,7 +12,7 @@
#include <linux/types.h>
/* maximum packet length for USB devices */
#define WACOM_PKGLEN_MAX 32
#define WACOM_PKGLEN_MAX 64
/* packet length for individual models */
#define WACOM_PKGLEN_PENPRTN 7
......@@ -22,6 +22,8 @@
#define WACOM_PKGLEN_TPC1FG 5
#define WACOM_PKGLEN_TPC2FG 14
#define WACOM_PKGLEN_BBTOUCH 20
#define WACOM_PKGLEN_BBTOUCH3 64
#define WACOM_PKGLEN_BBPEN 10
/* device IDs */
#define STYLUS_DEVICE_ID 0x02
......@@ -57,6 +59,7 @@ enum {
INTUOS4S,
INTUOS4,
INTUOS4L,
WACOM_24HD,
WACOM_21UX2,
CINTIQ,
WACOM_BEE,
......
......@@ -217,18 +217,7 @@ static struct platform_driver pm860x_touch_driver = {
.probe = pm860x_touch_probe,
.remove = __devexit_p(pm860x_touch_remove),
};
static int __init pm860x_touch_init(void)
{
return platform_driver_register(&pm860x_touch_driver);
}
module_init(pm860x_touch_init);
static void __exit pm860x_touch_exit(void)
{
platform_driver_unregister(&pm860x_touch_driver);
}
module_exit(pm860x_touch_exit);
module_platform_driver(pm860x_touch_driver);
MODULE_DESCRIPTION("Touchscreen driver for Marvell Semiconductor 88PM860x");
MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
......
......@@ -98,6 +98,19 @@ config TOUCHSCREEN_ATMEL_MXT
To compile this driver as a module, choose M here: the
module will be called atmel_mxt_ts.
config TOUCHSCREEN_AUO_PIXCIR
tristate "AUO in-cell touchscreen using Pixcir ICs"
depends on I2C
depends on GPIOLIB
help
Say Y here if you have a AUO display with in-cell touchscreen
using Pixcir ICs.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called auo-pixcir-ts.
config TOUCHSCREEN_BITSY
tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
depends on SA1100_BITSY
......@@ -177,6 +190,16 @@ config TOUCHSCREEN_EETI
To compile this driver as a module, choose M here: the
module will be called eeti_ts.
config TOUCHSCREEN_EGALAX
tristate "EETI eGalax multi-touch panel support"
depends on I2C
help
Say Y here to enable support for I2C connected EETI
eGalax multi-touch panels.
To compile this driver as a module, choose M here: the
module will be called egalax_ts.
config TOUCHSCREEN_FUJITSU
tristate "Fujitsu serial touchscreen"
select SERIO
......@@ -435,6 +458,18 @@ config TOUCHSCREEN_UCB1400
To compile this driver as a module, choose M here: the
module will be called ucb1400_ts.
config TOUCHSCREEN_PIXCIR
tristate "PIXCIR I2C touchscreens"
depends on I2C
help
Say Y here if you have a pixcir i2c touchscreen
controller.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called pixcir_i2c_ts.
config TOUCHSCREEN_WM831X
tristate "Support for WM831x touchscreen controllers"
depends on MFD_WM831X
......@@ -541,6 +576,7 @@ config TOUCHSCREEN_USB_COMPOSITE
- GoTop Super_Q2/GogoPen/PenPower tablets
- JASTEC USB Touch Controller/DigiTech DTR-02U
- Zytronic controllers
- Elo TouchSystems 2700 IntelliTouch
Have a look at <http://linux.chapter7.ch/touchkit/> for
a usage description and the required user-space stuff.
......@@ -620,6 +656,11 @@ config TOUCHSCREEN_USB_JASTEC
bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_ELO
default y
bool "Elo TouchSystems 2700 IntelliTouch controller device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_E2I
default y
bool "e2i Touchscreen controller (e.g. from Mimo 740)"
......
......@@ -14,6 +14,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o
obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o
obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o
obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o
......@@ -23,6 +24,7 @@ obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o
obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o
......@@ -39,6 +41,7 @@ obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o
obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o
obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
......
......@@ -488,10 +488,10 @@ static ssize_t ad7877_disable_store(struct device *dev,
const char *buf, size_t count)
{
struct ad7877 *ts = dev_get_drvdata(dev);
unsigned long val;
unsigned int val;
int error;
error = strict_strtoul(buf, 10, &val);
error = kstrtouint(buf, 10, &val);
if (error)
return error;
......@@ -518,10 +518,10 @@ static ssize_t ad7877_dac_store(struct device *dev,
const char *buf, size_t count)
{
struct ad7877 *ts = dev_get_drvdata(dev);
unsigned long val;
unsigned int val;
int error;
error = strict_strtoul(buf, 10, &val);
error = kstrtouint(buf, 10, &val);
if (error)
return error;
......@@ -548,10 +548,10 @@ static ssize_t ad7877_gpio3_store(struct device *dev,
const char *buf, size_t count)
{
struct ad7877 *ts = dev_get_drvdata(dev);
unsigned long val;
unsigned int val;
int error;
error = strict_strtoul(buf, 10, &val);
error = kstrtouint(buf, 10, &val);
if (error)
return error;
......@@ -579,10 +579,10 @@ static ssize_t ad7877_gpio4_store(struct device *dev,
const char *buf, size_t count)
{
struct ad7877 *ts = dev_get_drvdata(dev);
unsigned long val;
unsigned int val;
int error;
error = strict_strtoul(buf, 10, &val);
error = kstrtouint(buf, 10, &val);
if (error)
return error;
......@@ -853,7 +853,6 @@ static SIMPLE_DEV_PM_OPS(ad7877_pm, ad7877_suspend, ad7877_resume);
static struct spi_driver ad7877_driver = {
.driver = {
.name = "ad7877",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
.pm = &ad7877_pm,
},
......
......@@ -16,30 +16,6 @@
#define AD7879_DEVID 0x79 /* AD7879-1/AD7889-1 */
#ifdef CONFIG_PM_SLEEP
static int ad7879_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ad7879 *ts = i2c_get_clientdata(client);
ad7879_suspend(ts);
return 0;
}
static int ad7879_i2c_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ad7879 *ts = i2c_get_clientdata(client);
ad7879_resume(ts);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(ad7879_i2c_pm, ad7879_i2c_suspend, ad7879_i2c_resume);
/* All registers are word-sized.
* AD7879 uses a high-byte first convention.
*/
......@@ -47,7 +23,7 @@ static int ad7879_i2c_read(struct device *dev, u8 reg)
{
struct i2c_client *client = to_i2c_client(dev);
return swab16(i2c_smbus_read_word_data(client, reg));
return i2c_smbus_read_word_swapped(client, reg);
}
static int ad7879_i2c_multi_read(struct device *dev,
......@@ -68,7 +44,7 @@ static int ad7879_i2c_write(struct device *dev, u8 reg, u16 val)
{
struct i2c_client *client = to_i2c_client(dev);
return i2c_smbus_write_word_data(client, reg, swab16(val));
return i2c_smbus_write_word_swapped(client, reg, val);
}
static const struct ad7879_bus_ops ad7879_i2c_bus_ops = {
......@@ -119,7 +95,7 @@ static struct i2c_driver ad7879_i2c_driver = {
.driver = {
.name = "ad7879",
.owner = THIS_MODULE,
.pm = &ad7879_i2c_pm,
.pm = &ad7879_pm_ops,
},
.probe = ad7879_i2c_probe,
.remove = __devexit_p(ad7879_i2c_remove),
......@@ -141,4 +117,3 @@ module_exit(ad7879_i2c_exit);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("AD7879(-1) touchscreen I2C bus driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("i2c:ad7879");
......@@ -22,30 +22,6 @@
#define AD7879_WRITECMD(reg) (AD7879_CMD(reg))
#define AD7879_READCMD(reg) (AD7879_CMD(reg) | AD7879_CMD_READ)
#ifdef CONFIG_PM_SLEEP
static int ad7879_spi_suspend(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct ad7879 *ts = spi_get_drvdata(spi);
ad7879_suspend(ts);
return 0;
}
static int ad7879_spi_resume(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct ad7879 *ts = spi_get_drvdata(spi);
ad7879_resume(ts);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(ad7879_spi_pm, ad7879_spi_suspend, ad7879_spi_resume);
/*
* ad7879_read/write are only used for initial setup and for sysfs controls.
* The main traffic is done in ad7879_collect().
......@@ -174,9 +150,8 @@ static int __devexit ad7879_spi_remove(struct spi_device *spi)
static struct spi_driver ad7879_spi_driver = {
.driver = {
.name = "ad7879",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
.pm = &ad7879_spi_pm,
.pm = &ad7879_pm_ops,
},
.probe = ad7879_spi_probe,
.remove = __devexit_p(ad7879_spi_remove),
......
......@@ -281,8 +281,11 @@ static void ad7879_close(struct input_dev* input)
__ad7879_disable(ts);
}
void ad7879_suspend(struct ad7879 *ts)
#ifdef CONFIG_PM_SLEEP
static int ad7879_suspend(struct device *dev)
{
struct ad7879 *ts = dev_get_drvdata(dev);
mutex_lock(&ts->input->mutex);
if (!ts->suspended && !ts->disabled && ts->input->users)
......@@ -291,11 +294,14 @@ void ad7879_suspend(struct ad7879 *ts)
ts->suspended = true;
mutex_unlock(&ts->input->mutex);
return 0;
}
EXPORT_SYMBOL(ad7879_suspend);
void ad7879_resume(struct ad7879 *ts)
static int ad7879_resume(struct device *dev)
{
struct ad7879 *ts = dev_get_drvdata(dev);
mutex_lock(&ts->input->mutex);
if (ts->suspended && !ts->disabled && ts->input->users)
......@@ -304,8 +310,13 @@ void ad7879_resume(struct ad7879 *ts)
ts->suspended = false;
mutex_unlock(&ts->input->mutex);
return 0;
}
EXPORT_SYMBOL(ad7879_resume);
#endif
SIMPLE_DEV_PM_OPS(ad7879_pm_ops, ad7879_suspend, ad7879_resume);
EXPORT_SYMBOL(ad7879_pm_ops);
static void ad7879_toggle(struct ad7879 *ts, bool disable)
{
......@@ -340,10 +351,10 @@ static ssize_t ad7879_disable_store(struct device *dev,
const char *buf, size_t count)
{
struct ad7879 *ts = dev_get_drvdata(dev);
unsigned long val;
unsigned int val;
int error;
error = strict_strtoul(buf, 10, &val);
error = kstrtouint(buf, 10, &val);
if (error)
return error;
......
......@@ -21,8 +21,8 @@ struct ad7879_bus_ops {
int (*write)(struct device *dev, u8 reg, u16 val);
};
void ad7879_suspend(struct ad7879 *);
void ad7879_resume(struct ad7879 *);
extern const struct dev_pm_ops ad7879_pm_ops;
struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned irq,
const struct ad7879_bus_ops *bops);
void ad7879_remove(struct ad7879 *);
......
......@@ -602,10 +602,12 @@ static ssize_t ads7846_disable_store(struct device *dev,
const char *buf, size_t count)
{
struct ads7846 *ts = dev_get_drvdata(dev);
unsigned long i;
unsigned int i;
int err;
if (strict_strtoul(buf, 10, &i))
return -EINVAL;
err = kstrtouint(buf, 10, &i);
if (err)
return err;
if (i)
ads7846_disable(ts);
......@@ -1424,7 +1426,6 @@ static int __devexit ads7846_remove(struct spi_device *spi)
static struct spi_driver ads7846_driver = {
.driver = {
.name = "ads7846",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
.pm = &ads7846_pm,
},
......
......@@ -429,18 +429,7 @@ static struct platform_driver atmel_wm97xx_driver = {
.suspend = atmel_wm97xx_suspend,
.resume = atmel_wm97xx_resume,
};
static int __init atmel_wm97xx_init(void)
{
return platform_driver_probe(&atmel_wm97xx_driver, atmel_wm97xx_probe);
}
module_init(atmel_wm97xx_init);
static void __exit atmel_wm97xx_exit(void)
{
platform_driver_unregister(&atmel_wm97xx_driver);
}
module_exit(atmel_wm97xx_exit);
module_platform_driver(atmel_wm97xx_driver);
MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
MODULE_DESCRIPTION("wm97xx continuous touch driver for Atmel AT91 and AVR32");
......
......@@ -351,20 +351,7 @@ static struct platform_driver atmel_tsadcc_driver = {
.name = "atmel_tsadcc",
},
};
static int __init atmel_tsadcc_init(void)
{
return platform_driver_register(&atmel_tsadcc_driver);
}
static void __exit atmel_tsadcc_exit(void)
{
platform_driver_unregister(&atmel_tsadcc_driver);
}
module_init(atmel_tsadcc_init);
module_exit(atmel_tsadcc_exit);
module_platform_driver(atmel_tsadcc_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Atmel TouchScreen Driver");
......
/*
* Driver for AUO in-cell touchscreens
*
* Copyright (c) 2011 Heiko Stuebner <heiko@sntech.de>
*
* loosely based on auo_touch.c from Dell Streak vendor-kernel
*
* Copyright (c) 2008 QUALCOMM Incorporated.
* Copyright (c) 2008 QUALCOMM USA, INC.
*
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/input/auo-pixcir-ts.h>
/*
* Coordinate calculation:
* X1 = X1_LSB + X1_MSB*256
* Y1 = Y1_LSB + Y1_MSB*256
* X2 = X2_LSB + X2_MSB*256
* Y2 = Y2_LSB + Y2_MSB*256
*/
#define AUO_PIXCIR_REG_X1_LSB 0x00
#define AUO_PIXCIR_REG_X1_MSB 0x01
#define AUO_PIXCIR_REG_Y1_LSB 0x02
#define AUO_PIXCIR_REG_Y1_MSB 0x03
#define AUO_PIXCIR_REG_X2_LSB 0x04
#define AUO_PIXCIR_REG_X2_MSB 0x05
#define AUO_PIXCIR_REG_Y2_LSB 0x06
#define AUO_PIXCIR_REG_Y2_MSB 0x07
#define AUO_PIXCIR_REG_STRENGTH 0x0d
#define AUO_PIXCIR_REG_STRENGTH_X1_LSB 0x0e
#define AUO_PIXCIR_REG_STRENGTH_X1_MSB 0x0f
#define AUO_PIXCIR_REG_RAW_DATA_X 0x2b
#define AUO_PIXCIR_REG_RAW_DATA_Y 0x4f
#define AUO_PIXCIR_REG_X_SENSITIVITY 0x6f
#define AUO_PIXCIR_REG_Y_SENSITIVITY 0x70
#define AUO_PIXCIR_REG_INT_SETTING 0x71
#define AUO_PIXCIR_REG_INT_WIDTH 0x72
#define AUO_PIXCIR_REG_POWER_MODE 0x73
#define AUO_PIXCIR_REG_VERSION 0x77
#define AUO_PIXCIR_REG_CALIBRATE 0x78
#define AUO_PIXCIR_REG_TOUCHAREA_X1 0x1e
#define AUO_PIXCIR_REG_TOUCHAREA_Y1 0x1f
#define AUO_PIXCIR_REG_TOUCHAREA_X2 0x20
#define AUO_PIXCIR_REG_TOUCHAREA_Y2 0x21
#define AUO_PIXCIR_REG_EEPROM_CALIB_X 0x42
#define AUO_PIXCIR_REG_EEPROM_CALIB_Y 0xad
#define AUO_PIXCIR_INT_TPNUM_MASK 0xe0
#define AUO_PIXCIR_INT_TPNUM_SHIFT 5
#define AUO_PIXCIR_INT_RELEASE (1 << 4)
#define AUO_PIXCIR_INT_ENABLE (1 << 3)
#define AUO_PIXCIR_INT_POL_HIGH (1 << 2)
#define AUO_PIXCIR_INT_MODE_MASK 0x03
/*
* Power modes:
* active: scan speed 60Hz
* sleep: scan speed 10Hz can be auto-activated, wakeup on 1st touch
* deep sleep: scan speed 1Hz can only be entered or left manually.
*/
#define AUO_PIXCIR_POWER_ACTIVE 0x00
#define AUO_PIXCIR_POWER_SLEEP 0x01
#define AUO_PIXCIR_POWER_DEEP_SLEEP 0x02
#define AUO_PIXCIR_POWER_MASK 0x03
#define AUO_PIXCIR_POWER_ALLOW_SLEEP (1 << 2)
#define AUO_PIXCIR_POWER_IDLE_TIME(ms) ((ms & 0xf) << 4)
#define AUO_PIXCIR_CALIBRATE 0x03
#define AUO_PIXCIR_EEPROM_CALIB_X_LEN 62
#define AUO_PIXCIR_EEPROM_CALIB_Y_LEN 36
#define AUO_PIXCIR_RAW_DATA_X_LEN 18
#define AUO_PIXCIR_RAW_DATA_Y_LEN 11
#define AUO_PIXCIR_STRENGTH_ENABLE (1 << 0)
/* Touchscreen absolute values */
#define AUO_PIXCIR_REPORT_POINTS 2
#define AUO_PIXCIR_MAX_AREA 0xff
#define AUO_PIXCIR_PENUP_TIMEOUT_MS 10
struct auo_pixcir_ts {
struct i2c_client *client;
struct input_dev *input;
char phys[32];
/* special handling for touch_indicate interupt mode */
bool touch_ind_mode;
wait_queue_head_t wait;
bool stopped;
};
struct auo_point_t {
int coord_x;
int coord_y;
int area_major;
int area_minor;
int orientation;
};
static int auo_pixcir_collect_data(struct auo_pixcir_ts *ts,
struct auo_point_t *point)
{
struct i2c_client *client = ts->client;
const struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
uint8_t raw_coord[8];
uint8_t raw_area[4];
int i, ret;
/* touch coordinates */
ret = i2c_smbus_read_i2c_block_data(client, AUO_PIXCIR_REG_X1_LSB,
8, raw_coord);
if (ret < 0) {
dev_err(&client->dev, "failed to read coordinate, %d\n", ret);
return ret;
}
/* touch area */
ret = i2c_smbus_read_i2c_block_data(client, AUO_PIXCIR_REG_TOUCHAREA_X1,
4, raw_area);
if (ret < 0) {
dev_err(&client->dev, "could not read touch area, %d\n", ret);
return ret;
}
for (i = 0; i < AUO_PIXCIR_REPORT_POINTS; i++) {
point[i].coord_x =
raw_coord[4 * i + 1] << 8 | raw_coord[4 * i];
point[i].coord_y =
raw_coord[4 * i + 3] << 8 | raw_coord[4 * i + 2];
if (point[i].coord_x > pdata->x_max ||
point[i].coord_y > pdata->y_max) {
dev_warn(&client->dev, "coordinates (%d,%d) invalid\n",
point[i].coord_x, point[i].coord_y);
point[i].coord_x = point[i].coord_y = 0;
}
/* determine touch major, minor and orientation */
point[i].area_major = max(raw_area[2 * i], raw_area[2 * i + 1]);
point[i].area_minor = min(raw_area[2 * i], raw_area[2 * i + 1]);
point[i].orientation = raw_area[2 * i] > raw_area[2 * i + 1];
}
return 0;
}
static irqreturn_t auo_pixcir_interrupt(int irq, void *dev_id)
{
struct auo_pixcir_ts *ts = dev_id;
struct i2c_client *client = ts->client;
const struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
struct auo_point_t point[AUO_PIXCIR_REPORT_POINTS];
int i;
int ret;
int fingers = 0;
int abs = -1;
while (!ts->stopped) {
/* check for up event in touch touch_ind_mode */
if (ts->touch_ind_mode) {
if (gpio_get_value(pdata->gpio_int) == 0) {
input_mt_sync(ts->input);
input_report_key(ts->input, BTN_TOUCH, 0);
input_sync(ts->input);
break;
}
}
ret = auo_pixcir_collect_data(ts, point);
if (ret < 0) {
/* we want to loop only in touch_ind_mode */
if (!ts->touch_ind_mode)
break;
wait_event_timeout(ts->wait, ts->stopped,
msecs_to_jiffies(AUO_PIXCIR_PENUP_TIMEOUT_MS));
continue;
}
for (i = 0; i < AUO_PIXCIR_REPORT_POINTS; i++) {
if (point[i].coord_x > 0 || point[i].coord_y > 0) {
input_report_abs(ts->input, ABS_MT_POSITION_X,
point[i].coord_x);
input_report_abs(ts->input, ABS_MT_POSITION_Y,
point[i].coord_y);
input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR,
point[i].area_major);
input_report_abs(ts->input, ABS_MT_TOUCH_MINOR,
point[i].area_minor);
input_report_abs(ts->input, ABS_MT_ORIENTATION,
point[i].orientation);
input_mt_sync(ts->input);
/* use first finger as source for singletouch */
if (fingers == 0)
abs = i;
/* number of touch points could also be queried
* via i2c but would require an additional call
*/
fingers++;
}
}
input_report_key(ts->input, BTN_TOUCH, fingers > 0);
if (abs > -1) {
input_report_abs(ts->input, ABS_X, point[abs].coord_x);
input_report_abs(ts->input, ABS_Y, point[abs].coord_y);
}
input_sync(ts->input);
/* we want to loop only in touch_ind_mode */
if (!ts->touch_ind_mode)
break;
wait_event_timeout(ts->wait, ts->stopped,
msecs_to_jiffies(AUO_PIXCIR_PENUP_TIMEOUT_MS));
}
return IRQ_HANDLED;
}
/*
* Set the power mode of the device.
* Valid modes are
* - AUO_PIXCIR_POWER_ACTIVE
* - AUO_PIXCIR_POWER_SLEEP - automatically left on first touch
* - AUO_PIXCIR_POWER_DEEP_SLEEP
*/
static int auo_pixcir_power_mode(struct auo_pixcir_ts *ts, int mode)
{
struct i2c_client *client = ts->client;
int ret;
ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_POWER_MODE);
if (ret < 0) {
dev_err(&client->dev, "unable to read reg %Xh, %d\n",
AUO_PIXCIR_REG_POWER_MODE, ret);
return ret;
}
ret &= ~AUO_PIXCIR_POWER_MASK;
ret |= mode;
ret = i2c_smbus_write_byte_data(client, AUO_PIXCIR_REG_POWER_MODE, ret);
if (ret) {
dev_err(&client->dev, "unable to write reg %Xh, %d\n",
AUO_PIXCIR_REG_POWER_MODE, ret);
return ret;
}
return 0;
}
static __devinit int auo_pixcir_int_config(struct auo_pixcir_ts *ts,
int int_setting)
{
struct i2c_client *client = ts->client;
struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
int ret;
ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_INT_SETTING);
if (ret < 0) {
dev_err(&client->dev, "unable to read reg %Xh, %d\n",
AUO_PIXCIR_REG_INT_SETTING, ret);
return ret;
}
ret &= ~AUO_PIXCIR_INT_MODE_MASK;
ret |= int_setting;
ret |= AUO_PIXCIR_INT_POL_HIGH; /* always use high for interrupts */
ret = i2c_smbus_write_byte_data(client, AUO_PIXCIR_REG_INT_SETTING,
ret);
if (ret < 0) {
dev_err(&client->dev, "unable to write reg %Xh, %d\n",
AUO_PIXCIR_REG_INT_SETTING, ret);
return ret;
}
ts->touch_ind_mode = pdata->int_setting == AUO_PIXCIR_INT_TOUCH_IND;
return 0;
}
/* control the generation of interrupts on the device side */
static int auo_pixcir_int_toggle(struct auo_pixcir_ts *ts, bool enable)
{
struct i2c_client *client = ts->client;
int ret;
ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_INT_SETTING);
if (ret < 0) {
dev_err(&client->dev, "unable to read reg %Xh, %d\n",
AUO_PIXCIR_REG_INT_SETTING, ret);
return ret;
}
if (enable)
ret |= AUO_PIXCIR_INT_ENABLE;
else
ret &= ~AUO_PIXCIR_INT_ENABLE;
ret = i2c_smbus_write_byte_data(client, AUO_PIXCIR_REG_INT_SETTING,
ret);
if (ret < 0) {
dev_err(&client->dev, "unable to write reg %Xh, %d\n",
AUO_PIXCIR_REG_INT_SETTING, ret);
return ret;
}
return 0;
}
static int auo_pixcir_start(struct auo_pixcir_ts *ts)
{
struct i2c_client *client = ts->client;
int ret;
ret = auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_ACTIVE);
if (ret < 0) {
dev_err(&client->dev, "could not set power mode, %d\n",
ret);
return ret;
}
ts->stopped = false;
mb();
enable_irq(client->irq);
ret = auo_pixcir_int_toggle(ts, 1);
if (ret < 0) {
dev_err(&client->dev, "could not enable interrupt, %d\n",
ret);
disable_irq(client->irq);
return ret;
}
return 0;
}
static int auo_pixcir_stop(struct auo_pixcir_ts *ts)
{
struct i2c_client *client = ts->client;
int ret;
ret = auo_pixcir_int_toggle(ts, 0);
if (ret < 0) {
dev_err(&client->dev, "could not disable interrupt, %d\n",
ret);
return ret;
}
/* disable receiving of interrupts */
disable_irq(client->irq);
ts->stopped = true;
mb();
wake_up(&ts->wait);
return auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_DEEP_SLEEP);
}
static int auo_pixcir_input_open(struct input_dev *dev)
{
struct auo_pixcir_ts *ts = input_get_drvdata(dev);
int ret;
ret = auo_pixcir_start(ts);
if (ret)
return ret;
return 0;
}
static void auo_pixcir_input_close(struct input_dev *dev)
{
struct auo_pixcir_ts *ts = input_get_drvdata(dev);
auo_pixcir_stop(ts);
return;
}
#ifdef CONFIG_PM_SLEEP
static int auo_pixcir_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct auo_pixcir_ts *ts = i2c_get_clientdata(client);
struct input_dev *input = ts->input;
int ret = 0;
mutex_lock(&input->mutex);
/* when configured as wakeup source, device should always wake system
* therefore start device if necessary
*/
if (device_may_wakeup(&client->dev)) {
/* need to start device if not open, to be wakeup source */
if (!input->users) {
ret = auo_pixcir_start(ts);
if (ret)
goto unlock;
}
enable_irq_wake(client->irq);
ret = auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_SLEEP);
} else if (input->users) {
ret = auo_pixcir_stop(ts);
}
unlock:
mutex_unlock(&input->mutex);
return ret;
}
static int auo_pixcir_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct auo_pixcir_ts *ts = i2c_get_clientdata(client);
struct input_dev *input = ts->input;
int ret = 0;
mutex_lock(&input->mutex);
if (device_may_wakeup(&client->dev)) {
disable_irq_wake(client->irq);
/* need to stop device if it was not open on suspend */
if (!input->users) {
ret = auo_pixcir_stop(ts);
if (ret)
goto unlock;
}
/* device wakes automatically from SLEEP */
} else if (input->users) {
ret = auo_pixcir_start(ts);
}
unlock:
mutex_unlock(&input->mutex);
return ret;
}
#endif
static SIMPLE_DEV_PM_OPS(auo_pixcir_pm_ops, auo_pixcir_suspend,
auo_pixcir_resume);
static int __devinit auo_pixcir_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
struct auo_pixcir_ts *ts;
struct input_dev *input_dev;
int ret;
if (!pdata)
return -EINVAL;
ts = kzalloc(sizeof(struct auo_pixcir_ts), GFP_KERNEL);
if (!ts)
return -ENOMEM;
ret = gpio_request(pdata->gpio_int, "auo_pixcir_ts_int");
if (ret) {
dev_err(&client->dev, "request of gpio %d failed, %d\n",
pdata->gpio_int, ret);
goto err_gpio_int;
}
if (pdata->init_hw)
pdata->init_hw(client);
ts->client = client;
ts->touch_ind_mode = 0;
init_waitqueue_head(&ts->wait);
snprintf(ts->phys, sizeof(ts->phys),
"%s/input0", dev_name(&client->dev));
input_dev = input_allocate_device();
if (!input_dev) {
dev_err(&client->dev, "could not allocate input device\n");
goto err_input_alloc;
}
ts->input = input_dev;
input_dev->name = "AUO-Pixcir touchscreen";
input_dev->phys = ts->phys;
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
input_dev->open = auo_pixcir_input_open;
input_dev->close = auo_pixcir_input_close;
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
/* For single touch */
input_set_abs_params(input_dev, ABS_X, 0, pdata->x_max, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, pdata->y_max, 0, 0);
/* For multi touch */
input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
pdata->x_max, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
pdata->y_max, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0,
AUO_PIXCIR_MAX_AREA, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0,
AUO_PIXCIR_MAX_AREA, 0, 0);
input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0);
ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_VERSION);
if (ret < 0)
goto err_fw_vers;
dev_info(&client->dev, "firmware version 0x%X\n", ret);
ret = auo_pixcir_int_config(ts, pdata->int_setting);
if (ret)
goto err_fw_vers;
input_set_drvdata(ts->input, ts);
ts->stopped = true;
ret = request_threaded_irq(client->irq, NULL, auo_pixcir_interrupt,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
input_dev->name, ts);
if (ret) {
dev_err(&client->dev, "irq %d requested failed\n", client->irq);
goto err_fw_vers;
}
/* stop device and put it into deep sleep until it is opened */
ret = auo_pixcir_stop(ts);
if (ret < 0)
goto err_input_register;
ret = input_register_device(input_dev);
if (ret) {
dev_err(&client->dev, "could not register input device\n");
goto err_input_register;
}
i2c_set_clientdata(client, ts);
return 0;
err_input_register:
free_irq(client->irq, ts);
err_fw_vers:
input_free_device(input_dev);
err_input_alloc:
if (pdata->exit_hw)
pdata->exit_hw(client);
gpio_free(pdata->gpio_int);
err_gpio_int:
kfree(ts);
return ret;
}
static int __devexit auo_pixcir_remove(struct i2c_client *client)
{
struct auo_pixcir_ts *ts = i2c_get_clientdata(client);
const struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
free_irq(client->irq, ts);
input_unregister_device(ts->input);
if (pdata->exit_hw)
pdata->exit_hw(client);
gpio_free(pdata->gpio_int);
kfree(ts);
return 0;
}
static const struct i2c_device_id auo_pixcir_idtable[] = {
{ "auo_pixcir_ts", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, auo_pixcir_idtable);
static struct i2c_driver auo_pixcir_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "auo_pixcir_ts",
.pm = &auo_pixcir_pm_ops,
},
.probe = auo_pixcir_probe,
.remove = __devexit_p(auo_pixcir_remove),
.id_table = auo_pixcir_idtable,
};
static int __init auo_pixcir_init(void)
{
return i2c_add_driver(&auo_pixcir_driver);
}
module_init(auo_pixcir_init);
static void __exit auo_pixcir_exit(void)
{
i2c_del_driver(&auo_pixcir_driver);
}
module_exit(auo_pixcir_exit);
MODULE_DESCRIPTION("AUO-PIXCIR touchscreen driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
......@@ -379,18 +379,7 @@ static struct platform_driver da9034_touch_driver = {
.probe = da9034_touch_probe,
.remove = __devexit_p(da9034_touch_remove),
};
static int __init da9034_touch_init(void)
{
return platform_driver_register(&da9034_touch_driver);
}
module_init(da9034_touch_init);
static void __exit da9034_touch_exit(void)
{
platform_driver_unregister(&da9034_touch_driver);
}
module_exit(da9034_touch_exit);
module_platform_driver(da9034_touch_driver);
MODULE_DESCRIPTION("Touchscreen driver for Dialog Semiconductor DA9034");
MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>, Bin Yang <bin.yang@marvell.com>");
......
/*
* Driver for EETI eGalax Multiple Touch Controller
*
* Copyright (C) 2011 Freescale Semiconductor, Inc.
*
* based on max11801_ts.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/* EETI eGalax serial touch screen controller is a I2C based multiple
* touch screen controller, it supports 5 point multiple touch. */
/* TODO:
- auto idle mode support
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/bitops.h>
#include <linux/input/mt.h>
/*
* Mouse Mode: some panel may configure the controller to mouse mode,
* which can only report one point at a given time.
* This driver will ignore events in this mode.
*/
#define REPORT_MODE_MOUSE 0x1
/*
* Vendor Mode: this mode is used to transfer some vendor specific
* messages.
* This driver will ignore events in this mode.
*/
#define REPORT_MODE_VENDOR 0x3
/* Multiple Touch Mode */
#define REPORT_MODE_MTTOUCH 0x4
#define MAX_SUPPORT_POINTS 5
#define EVENT_VALID_OFFSET 7
#define EVENT_VALID_MASK (0x1 << EVENT_VALID_OFFSET)
#define EVENT_ID_OFFSET 2
#define EVENT_ID_MASK (0xf << EVENT_ID_OFFSET)
#define EVENT_IN_RANGE (0x1 << 1)
#define EVENT_DOWN_UP (0X1 << 0)
#define MAX_I2C_DATA_LEN 10
#define EGALAX_MAX_X 32760
#define EGALAX_MAX_Y 32760
#define EGALAX_MAX_TRIES 100
struct egalax_ts {
struct i2c_client *client;
struct input_dev *input_dev;
};
static irqreturn_t egalax_ts_interrupt(int irq, void *dev_id)
{
struct egalax_ts *ts = dev_id;
struct input_dev *input_dev = ts->input_dev;
struct i2c_client *client = ts->client;
u8 buf[MAX_I2C_DATA_LEN];
int id, ret, x, y, z;
int tries = 0;
bool down, valid;
u8 state;
do {
ret = i2c_master_recv(client, buf, MAX_I2C_DATA_LEN);
} while (ret == -EAGAIN && tries++ < EGALAX_MAX_TRIES);
if (ret < 0)
return IRQ_HANDLED;
if (buf[0] != REPORT_MODE_MTTOUCH) {
/* ignore mouse events and vendor events */
return IRQ_HANDLED;
}
state = buf[1];
x = (buf[3] << 8) | buf[2];
y = (buf[5] << 8) | buf[4];
z = (buf[7] << 8) | buf[6];
valid = state & EVENT_VALID_MASK;
id = (state & EVENT_ID_MASK) >> EVENT_ID_OFFSET;
down = state & EVENT_DOWN_UP;
if (!valid || id > MAX_SUPPORT_POINTS) {
dev_dbg(&client->dev, "point invalid\n");
return IRQ_HANDLED;
}
input_mt_slot(input_dev, id);
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, down);
dev_dbg(&client->dev, "%s id:%d x:%d y:%d z:%d",
down ? "down" : "up", id, x, y, z);
if (down) {
input_report_abs(input_dev, ABS_MT_POSITION_X, x);
input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
input_report_abs(input_dev, ABS_MT_PRESSURE, z);
}
input_mt_report_pointer_emulation(input_dev, true);
input_sync(input_dev);
return IRQ_HANDLED;
}
/* wake up controller by an falling edge of interrupt gpio. */
static int egalax_wake_up_device(struct i2c_client *client)
{
int gpio = irq_to_gpio(client->irq);
int ret;
ret = gpio_request(gpio, "egalax_irq");
if (ret < 0) {
dev_err(&client->dev,
"request gpio failed, cannot wake up controller: %d\n",
ret);
return ret;
}
/* wake up controller via an falling edge on IRQ gpio. */
gpio_direction_output(gpio, 0);
gpio_set_value(gpio, 1);
/* controller should be waken up, return irq. */
gpio_direction_input(gpio);
gpio_free(gpio);
return 0;
}
static int __devinit egalax_firmware_version(struct i2c_client *client)
{
static const u8 cmd[MAX_I2C_DATA_LEN] = { 0x03, 0x03, 0xa, 0x01, 0x41 };
int ret;
ret = i2c_master_send(client, cmd, MAX_I2C_DATA_LEN);
if (ret < 0)
return ret;
return 0;
}
static int __devinit egalax_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct egalax_ts *ts;
struct input_dev *input_dev;
int ret;
int error;
ts = kzalloc(sizeof(struct egalax_ts), GFP_KERNEL);
if (!ts) {
dev_err(&client->dev, "Failed to allocate memory\n");
return -ENOMEM;
}
input_dev = input_allocate_device();
if (!input_dev) {
dev_err(&client->dev, "Failed to allocate memory\n");
error = -ENOMEM;
goto err_free_ts;
}
ts->client = client;
ts->input_dev = input_dev;
/* controller may be in sleep, wake it up. */
egalax_wake_up_device(client);
ret = egalax_firmware_version(client);
if (ret < 0) {
dev_err(&client->dev, "Failed to read firmware version\n");
error = -EIO;
goto err_free_dev;
}
input_dev->name = "EETI eGalax Touch Screen";
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
input_set_abs_params(input_dev, ABS_X, 0, EGALAX_MAX_X, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, EGALAX_MAX_Y, 0, 0);
input_set_abs_params(input_dev,
ABS_MT_POSITION_X, 0, EGALAX_MAX_X, 0, 0);
input_set_abs_params(input_dev,
ABS_MT_POSITION_X, 0, EGALAX_MAX_Y, 0, 0);
input_mt_init_slots(input_dev, MAX_SUPPORT_POINTS);
input_set_drvdata(input_dev, ts);
error = request_threaded_irq(client->irq, NULL, egalax_ts_interrupt,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"egalax_ts", ts);
if (error < 0) {
dev_err(&client->dev, "Failed to register interrupt\n");
goto err_free_dev;
}
error = input_register_device(ts->input_dev);
if (error)
goto err_free_irq;
i2c_set_clientdata(client, ts);
return 0;
err_free_irq:
free_irq(client->irq, ts);
err_free_dev:
input_free_device(input_dev);
err_free_ts:
kfree(ts);
return error;
}
static __devexit int egalax_ts_remove(struct i2c_client *client)
{
struct egalax_ts *ts = i2c_get_clientdata(client);
free_irq(client->irq, ts);
input_unregister_device(ts->input_dev);
kfree(ts);
return 0;
}
static const struct i2c_device_id egalax_ts_id[] = {
{ "egalax_ts", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, egalax_ts_id);
#ifdef CONFIG_PM_SLEEP
static int egalax_ts_suspend(struct device *dev)
{
static const u8 suspend_cmd[MAX_I2C_DATA_LEN] = {
0x3, 0x6, 0xa, 0x3, 0x36, 0x3f, 0x2, 0, 0, 0
};
struct i2c_client *client = to_i2c_client(dev);
int ret;
ret = i2c_master_send(client, suspend_cmd, MAX_I2C_DATA_LEN);
return ret > 0 ? 0 : ret;
}
static int egalax_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
return egalax_wake_up_device(client);
}
#endif
static SIMPLE_DEV_PM_OPS(egalax_ts_pm_ops, egalax_ts_suspend, egalax_ts_resume);
static struct i2c_driver egalax_ts_driver = {
.driver = {
.name = "egalax_ts",
.owner = THIS_MODULE,
.pm = &egalax_ts_pm_ops,
},
.id_table = egalax_ts_id,
.probe = egalax_ts_probe,
.remove = __devexit_p(egalax_ts_remove),
};
static int __init egalax_ts_init(void)
{
return i2c_add_driver(&egalax_ts_driver);
}
static void __exit egalax_ts_exit(void)
{
i2c_del_driver(&egalax_ts_driver);
}
module_init(egalax_ts_init);
module_exit(egalax_ts_exit);
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
MODULE_DESCRIPTION("Touchscreen driver for EETI eGalax touch controller");
MODULE_LICENSE("GPL");
......@@ -47,12 +47,6 @@ static int invert_y;
module_param(invert_y, bool, 0644);
MODULE_PARM_DESC(invert_y, "If set, Y axis is inverted");
static struct pnp_device_id pnp_ids[] = {
{ .id = "PNP0cc0" },
{ .id = "" }
};
MODULE_DEVICE_TABLE(pnp, pnp_ids);
static irqreturn_t htcpen_interrupt(int irq, void *handle)
{
struct input_dev *htcpen_dev = handle;
......@@ -237,6 +231,7 @@ static struct dmi_system_id __initdata htcshift_dmi_table[] = {
},
{ }
};
MODULE_DEVICE_TABLE(dmi, htcshift_dmi_table);
static int __init htcpen_isa_init(void)
{
......
......@@ -664,18 +664,7 @@ static struct platform_driver mrstouch_driver = {
.probe = mrstouch_probe,
.remove = __devexit_p(mrstouch_remove),
};
static int __init mrstouch_init(void)
{
return platform_driver_register(&mrstouch_driver);
}
module_init(mrstouch_init);
static void __exit mrstouch_exit(void)
{
platform_driver_unregister(&mrstouch_driver);
}
module_exit(mrstouch_exit);
module_platform_driver(mrstouch_driver);
MODULE_AUTHOR("Sreedhara Murthy. D.S, sreedhara.ds@intel.com");
MODULE_DESCRIPTION("Intel Moorestown Resistive Touch Screen Driver");
......
......@@ -172,16 +172,4 @@ static struct platform_driver jornada720_ts_driver = {
.owner = THIS_MODULE,
},
};
static int __init jornada720_ts_init(void)
{
return platform_driver_register(&jornada720_ts_driver);
}
static void __exit jornada720_ts_exit(void)
{
platform_driver_unregister(&jornada720_ts_driver);
}
module_init(jornada720_ts_init);
module_exit(jornada720_ts_exit);
module_platform_driver(jornada720_ts_driver);
......@@ -392,18 +392,7 @@ static struct platform_driver lpc32xx_ts_driver = {
.pm = LPC32XX_TS_PM_OPS,
},
};
static int __init lpc32xx_ts_init(void)
{
return platform_driver_register(&lpc32xx_ts_driver);
}
module_init(lpc32xx_ts_init);
static void __exit lpc32xx_ts_exit(void)
{
platform_driver_unregister(&lpc32xx_ts_driver);
}
module_exit(lpc32xx_ts_exit);
module_platform_driver(lpc32xx_ts_driver);
MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com");
MODULE_DESCRIPTION("LPC32XX TSC Driver");
......
......@@ -302,19 +302,7 @@ static struct platform_driver mainstone_wm97xx_driver = {
.name = "wm97xx-touch",
},
};
static int __init mainstone_wm97xx_init(void)
{
return platform_driver_register(&mainstone_wm97xx_driver);
}
static void __exit mainstone_wm97xx_exit(void)
{
platform_driver_unregister(&mainstone_wm97xx_driver);
}
module_init(mainstone_wm97xx_init);
module_exit(mainstone_wm97xx_exit);
module_platform_driver(mainstone_wm97xx_driver);
/* Module information */
MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
......
......@@ -240,18 +240,7 @@ static struct platform_driver mc13783_ts_driver = {
.name = MC13783_TS_NAME,
},
};
static int __init mc13783_ts_init(void)
{
return platform_driver_probe(&mc13783_ts_driver, &mc13783_ts_probe);
}
module_init(mc13783_ts_init);
static void __exit mc13783_ts_exit(void)
{
platform_driver_unregister(&mc13783_ts_driver);
}
module_exit(mc13783_ts_exit);
module_platform_driver(mc13783_ts_driver);
MODULE_DESCRIPTION("MC13783 input touchscreen driver");
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
......
......@@ -36,7 +36,6 @@
struct migor_ts_priv {
struct i2c_client *client;
struct input_dev *input;
struct delayed_work work;
int irq;
};
......@@ -44,15 +43,24 @@ static const u_int8_t migor_ts_ena_seq[17] = { 0x33, 0x22, 0x11,
0x01, 0x06, 0x07, };
static const u_int8_t migor_ts_dis_seq[17] = { };
static void migor_ts_poscheck(struct work_struct *work)
static irqreturn_t migor_ts_isr(int irq, void *dev_id)
{
struct migor_ts_priv *priv = container_of(work,
struct migor_ts_priv,
work.work);
struct migor_ts_priv *priv = dev_id;
unsigned short xpos, ypos;
unsigned char event;
u_int8_t buf[16];
/*
* The touch screen controller chip is hooked up to the CPU
* using I2C and a single interrupt line. The interrupt line
* is pulled low whenever someone taps the screen. To deassert
* the interrupt line we need to acknowledge the interrupt by
* communicating with the controller over the slow i2c bus.
*
* Since I2C bus controller may sleep we are using threaded
* IRQ here.
*/
memset(buf, 0, sizeof(buf));
/* Set Index 0 */
......@@ -72,41 +80,25 @@ static void migor_ts_poscheck(struct work_struct *work)
xpos = ((buf[11] & 0x03) << 8 | buf[10]);
event = buf[12];
if (event == EVENT_PENDOWN || event == EVENT_REPEAT) {
switch (event) {
case EVENT_PENDOWN:
case EVENT_REPEAT:
input_report_key(priv->input, BTN_TOUCH, 1);
input_report_abs(priv->input, ABS_X, ypos); /*X-Y swap*/
input_report_abs(priv->input, ABS_Y, xpos);
input_sync(priv->input);
} else if (event == EVENT_PENUP) {
break;
case EVENT_PENUP:
input_report_key(priv->input, BTN_TOUCH, 0);
input_sync(priv->input);
break;
}
out:
enable_irq(priv->irq);
}
static irqreturn_t migor_ts_isr(int irq, void *dev_id)
{
struct migor_ts_priv *priv = dev_id;
/* the touch screen controller chip is hooked up to the cpu
* using i2c and a single interrupt line. the interrupt line
* is pulled low whenever someone taps the screen. to deassert
* the interrupt line we need to acknowledge the interrupt by
* communicating with the controller over the slow i2c bus.
*
* we can't acknowledge from interrupt context since the i2c
* bus controller may sleep, so we just disable the interrupt
* here and handle the acknowledge using delayed work.
*/
disable_irq_nosync(irq);
schedule_delayed_work(&priv->work, HZ / 20);
out:
return IRQ_HANDLED;
}
static int migor_ts_open(struct input_dev *dev)
{
struct migor_ts_priv *priv = input_get_drvdata(dev);
......@@ -131,15 +123,6 @@ static void migor_ts_close(struct input_dev *dev)
disable_irq(priv->irq);
/* cancel pending work and wait for migor_ts_poscheck() to finish */
if (cancel_delayed_work_sync(&priv->work)) {
/*
* if migor_ts_poscheck was canceled we need to enable IRQ
* here to balance disable done in migor_ts_isr.
*/
enable_irq(priv->irq);
}
/* disable controller */
i2c_master_send(client, migor_ts_dis_seq, sizeof(migor_ts_dis_seq));
......@@ -154,23 +137,20 @@ static int migor_ts_probe(struct i2c_client *client,
int error;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
dev_err(&client->dev, "failed to allocate driver data\n");
error = -ENOMEM;
goto err0;
}
dev_set_drvdata(&client->dev, priv);
input = input_allocate_device();
if (!input) {
dev_err(&client->dev, "Failed to allocate input device.\n");
if (!priv || !input) {
dev_err(&client->dev, "failed to allocate memory\n");
error = -ENOMEM;
goto err1;
goto err_free_mem;
}
priv->client = client;
priv->input = input;
priv->irq = client->irq;
input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
__set_bit(BTN_TOUCH, input->keybit);
input_set_abs_params(input, ABS_X, 95, 955, 0, 0);
input_set_abs_params(input, ABS_Y, 85, 935, 0, 0);
......@@ -184,39 +164,34 @@ static int migor_ts_probe(struct i2c_client *client,
input_set_drvdata(input, priv);
priv->client = client;
priv->input = input;
INIT_DELAYED_WORK(&priv->work, migor_ts_poscheck);
priv->irq = client->irq;
error = input_register_device(input);
if (error)
goto err1;
error = request_irq(priv->irq, migor_ts_isr, IRQF_TRIGGER_LOW,
client->name, priv);
error = request_threaded_irq(priv->irq, NULL, migor_ts_isr,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
client->name, priv);
if (error) {
dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
goto err2;
goto err_free_mem;
}
error = input_register_device(input);
if (error)
goto err_free_irq;
i2c_set_clientdata(client, priv);
device_init_wakeup(&client->dev, 1);
return 0;
err2:
input_unregister_device(input);
input = NULL; /* so we dont try to free it below */
err1:
err_free_irq:
free_irq(priv->irq, priv);
err_free_mem:
input_free_device(input);
kfree(priv);
err0:
dev_set_drvdata(&client->dev, NULL);
return error;
}
static int migor_ts_remove(struct i2c_client *client)
{
struct migor_ts_priv *priv = dev_get_drvdata(&client->dev);
struct migor_ts_priv *priv = i2c_get_clientdata(client);
free_irq(priv->irq, priv);
input_unregister_device(priv->input);
......@@ -230,7 +205,7 @@ static int migor_ts_remove(struct i2c_client *client)
static int migor_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct migor_ts_priv *priv = dev_get_drvdata(&client->dev);
struct migor_ts_priv *priv = i2c_get_clientdata(client);
if (device_may_wakeup(&client->dev))
enable_irq_wake(priv->irq);
......@@ -241,7 +216,7 @@ static int migor_ts_suspend(struct device *dev)
static int migor_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct migor_ts_priv *priv = dev_get_drvdata(&client->dev);
struct migor_ts_priv *priv = i2c_get_clientdata(client);
if (device_may_wakeup(&client->dev))
disable_irq_wake(priv->irq);
......
......@@ -252,19 +252,7 @@ static struct platform_driver pcap_ts_driver = {
.pm = PCAP_TS_PM_OPS,
},
};
static int __init pcap_ts_init(void)
{
return platform_driver_register(&pcap_ts_driver);
}
static void __exit pcap_ts_exit(void)
{
platform_driver_unregister(&pcap_ts_driver);
}
module_init(pcap_ts_init);
module_exit(pcap_ts_exit);
module_platform_driver(pcap_ts_driver);
MODULE_DESCRIPTION("Motorola PCAP2 touchscreen driver");
MODULE_AUTHOR("Daniel Ribeiro / Harald Welte");
......
/*
* Driver for Pixcir I2C touchscreen controllers.
*
* Copyright (C) 2010-2011 Pixcir, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/pixcir_ts.h>
struct pixcir_i2c_ts_data {
struct i2c_client *client;
struct input_dev *input;
const struct pixcir_ts_platform_data *chip;
bool exiting;
};
static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
{
struct pixcir_i2c_ts_data *tsdata = data;
u8 rdbuf[10], wrbuf[1] = { 0 };
u8 touch;
int ret;
ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
if (ret != sizeof(wrbuf)) {
dev_err(&tsdata->client->dev,
"%s: i2c_master_send failed(), ret=%d\n",
__func__, ret);
return;
}
ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf));
if (ret != sizeof(rdbuf)) {
dev_err(&tsdata->client->dev,
"%s: i2c_master_recv failed(), ret=%d\n",
__func__, ret);
return;
}
touch = rdbuf[0];
if (touch) {
u16 posx1 = (rdbuf[3] << 8) | rdbuf[2];
u16 posy1 = (rdbuf[5] << 8) | rdbuf[4];
u16 posx2 = (rdbuf[7] << 8) | rdbuf[6];
u16 posy2 = (rdbuf[9] << 8) | rdbuf[8];
input_report_key(tsdata->input, BTN_TOUCH, 1);
input_report_abs(tsdata->input, ABS_X, posx1);
input_report_abs(tsdata->input, ABS_Y, posy1);
input_report_abs(tsdata->input, ABS_MT_POSITION_X, posx1);
input_report_abs(tsdata->input, ABS_MT_POSITION_Y, posy1);
input_mt_sync(tsdata->input);
if (touch == 2) {
input_report_abs(tsdata->input,
ABS_MT_POSITION_X, posx2);
input_report_abs(tsdata->input,
ABS_MT_POSITION_Y, posy2);
input_mt_sync(tsdata->input);
}
} else {
input_report_key(tsdata->input, BTN_TOUCH, 0);
}
input_sync(tsdata->input);
}
static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
{
struct pixcir_i2c_ts_data *tsdata = dev_id;
while (!tsdata->exiting) {
pixcir_ts_poscheck(tsdata);
if (tsdata->chip->attb_read_val())
break;
msleep(20);
}
return IRQ_HANDLED;
}
#ifdef CONFIG_PM_SLEEP
static int pixcir_i2c_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
if (device_may_wakeup(&client->dev))
enable_irq_wake(client->irq);
return 0;
}
static int pixcir_i2c_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
if (device_may_wakeup(&client->dev))
disable_irq_wake(client->irq);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,
pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume);
static int __devinit pixcir_i2c_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct pixcir_ts_platform_data *pdata = client->dev.platform_data;
struct pixcir_i2c_ts_data *tsdata;
struct input_dev *input;
int error;
if (!pdata) {
dev_err(&client->dev, "platform data not defined\n");
return -EINVAL;
}
tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL);
input = input_allocate_device();
if (!tsdata || !input) {
dev_err(&client->dev, "Failed to allocate driver data!\n");
error = -ENOMEM;
goto err_free_mem;
}
tsdata->client = client;
tsdata->input = input;
tsdata->chip = pdata;
input->name = client->name;
input->id.bustype = BUS_I2C;
input->dev.parent = &client->dev;
__set_bit(EV_KEY, input->evbit);
__set_bit(EV_ABS, input->evbit);
__set_bit(BTN_TOUCH, input->keybit);
input_set_abs_params(input, ABS_X, 0, pdata->x_max, 0, 0);
input_set_abs_params(input, ABS_Y, 0, pdata->y_max, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0);
input_set_drvdata(input, tsdata);
error = request_threaded_irq(client->irq, NULL, pixcir_ts_isr,
IRQF_TRIGGER_FALLING,
client->name, tsdata);
if (error) {
dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
goto err_free_mem;
}
error = input_register_device(input);
if (error)
goto err_free_irq;
i2c_set_clientdata(client, tsdata);
device_init_wakeup(&client->dev, 1);
return 0;
err_free_irq:
free_irq(client->irq, tsdata);
err_free_mem:
input_free_device(input);
kfree(tsdata);
return error;
}
static int __devexit pixcir_i2c_ts_remove(struct i2c_client *client)
{
struct pixcir_i2c_ts_data *tsdata = i2c_get_clientdata(client);
device_init_wakeup(&client->dev, 0);
tsdata->exiting = true;
mb();
free_irq(client->irq, tsdata);
input_unregister_device(tsdata->input);
kfree(tsdata);
return 0;
}
static const struct i2c_device_id pixcir_i2c_ts_id[] = {
{ "pixcir_ts", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id);
static struct i2c_driver pixcir_i2c_ts_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "pixcir_ts",
.pm = &pixcir_dev_pm_ops,
},
.probe = pixcir_i2c_ts_probe,
.remove = __devexit_p(pixcir_i2c_ts_remove),
.id_table = pixcir_i2c_ts_id,
};
static int __init pixcir_i2c_ts_init(void)
{
return i2c_add_driver(&pixcir_i2c_ts_driver);
}
module_init(pixcir_i2c_ts_init);
static void __exit pixcir_i2c_ts_exit(void)
{
i2c_del_driver(&pixcir_i2c_ts_driver);
}
module_exit(pixcir_i2c_ts_exit);
MODULE_AUTHOR("Jianchun Bian <jcbian@pixcir.com.cn>, Dequan Meng <dqmeng@pixcir.com.cn>");
MODULE_DESCRIPTION("Pixcir I2C Touchscreen Driver");
MODULE_LICENSE("GPL");
......@@ -432,19 +432,7 @@ static struct platform_driver s3c_ts_driver = {
.probe = s3c2410ts_probe,
.remove = __devexit_p(s3c2410ts_remove),
};
static int __init s3c2410ts_init(void)
{
return platform_driver_register(&s3c_ts_driver);
}
static void __exit s3c2410ts_exit(void)
{
platform_driver_unregister(&s3c_ts_driver);
}
module_init(s3c2410ts_init);
module_exit(s3c2410ts_exit);
module_platform_driver(s3c_ts_driver);
MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, "
"Ben Dooks <ben@simtec.co.uk>, "
......
......@@ -379,20 +379,7 @@ static struct platform_driver stmpe_ts_driver = {
.probe = stmpe_input_probe,
.remove = __devexit_p(stmpe_ts_remove),
};
static int __init stmpe_ts_init(void)
{
return platform_driver_register(&stmpe_ts_driver);
}
module_init(stmpe_ts_init);
static void __exit stmpe_ts_exit(void)
{
platform_driver_unregister(&stmpe_ts_driver);
}
module_exit(stmpe_ts_exit);
module_platform_driver(stmpe_ts_driver);
MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
MODULE_DESCRIPTION("STMPEXXX touchscreen driver");
......
......@@ -378,19 +378,7 @@ static struct platform_driver tsc_driver = {
.driver.name = "tnetv107x-ts",
.driver.owner = THIS_MODULE,
};
static int __init tsc_init(void)
{
return platform_driver_register(&tsc_driver);
}
static void __exit tsc_exit(void)
{
platform_driver_unregister(&tsc_driver);
}
module_init(tsc_init);
module_exit(tsc_exit);
module_platform_driver(tsc_driver);
MODULE_AUTHOR("Cyril Chemparathy");
MODULE_DESCRIPTION("TNETV107X Touchscreen Driver");
......
......@@ -371,18 +371,7 @@ static struct platform_driver tps6507x_ts_driver = {
.probe = tps6507x_ts_probe,
.remove = __devexit_p(tps6507x_ts_remove),
};
static int __init tps6507x_ts_init(void)
{
return platform_driver_register(&tps6507x_ts_driver);
}
module_init(tps6507x_ts_init);
static void __exit tps6507x_ts_exit(void)
{
platform_driver_unregister(&tps6507x_ts_driver);
}
module_exit(tps6507x_ts_exit);
module_platform_driver(tps6507x_ts_driver);
MODULE_AUTHOR("Todd Fischer <todd.fischer@ridgerun.com>");
MODULE_DESCRIPTION("TPS6507x - TouchScreen driver");
......
......@@ -20,24 +20,24 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/input.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/suspend.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <linux/ucb1400.h>
#define UCB1400_TS_POLL_PERIOD 10 /* ms */
static int adcsync;
static int ts_delay = 55; /* us */
static int ts_delay_pressure; /* us */
/* Switch to interrupt mode. */
static inline void ucb1400_ts_mode_int(struct snd_ac97 *ac97)
static void ucb1400_ts_mode_int(struct ucb1400_ts *ucb)
{
ucb1400_reg_write(ac97, UCB_TS_CR,
ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
UCB_TS_CR_MODE_INT);
......@@ -47,13 +47,15 @@ static inline void ucb1400_ts_mode_int(struct snd_ac97 *ac97)
* Switch to pressure mode, and read pressure. We don't need to wait
* here, since both plates are being driven.
*/
static inline unsigned int ucb1400_ts_read_pressure(struct ucb1400_ts *ucb)
static unsigned int ucb1400_ts_read_pressure(struct ucb1400_ts *ucb)
{
ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
udelay(ts_delay_pressure);
return ucb1400_adc_read(ucb->ac97, UCB_ADC_INP_TSPY, adcsync);
}
......@@ -63,7 +65,7 @@ static inline unsigned int ucb1400_ts_read_pressure(struct ucb1400_ts *ucb)
* gives a faster response time. Even so, we need to wait about 55us
* for things to stabilise.
*/
static inline unsigned int ucb1400_ts_read_xpos(struct ucb1400_ts *ucb)
static unsigned int ucb1400_ts_read_xpos(struct ucb1400_ts *ucb)
{
ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
......@@ -86,7 +88,7 @@ static inline unsigned int ucb1400_ts_read_xpos(struct ucb1400_ts *ucb)
* gives a faster response time. Even so, we need to wait about 55us
* for things to stabilise.
*/
static inline unsigned int ucb1400_ts_read_ypos(struct ucb1400_ts *ucb)
static int ucb1400_ts_read_ypos(struct ucb1400_ts *ucb)
{
ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
......@@ -107,7 +109,7 @@ static inline unsigned int ucb1400_ts_read_ypos(struct ucb1400_ts *ucb)
* Switch to X plate resistance mode. Set MX to ground, PX to
* supply. Measure current.
*/
static inline unsigned int ucb1400_ts_read_xres(struct ucb1400_ts *ucb)
static unsigned int ucb1400_ts_read_xres(struct ucb1400_ts *ucb)
{
ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
......@@ -119,7 +121,7 @@ static inline unsigned int ucb1400_ts_read_xres(struct ucb1400_ts *ucb)
* Switch to Y plate resistance mode. Set MY to ground, PY to
* supply. Measure current.
*/
static inline unsigned int ucb1400_ts_read_yres(struct ucb1400_ts *ucb)
static unsigned int ucb1400_ts_read_yres(struct ucb1400_ts *ucb)
{
ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
......@@ -127,26 +129,26 @@ static inline unsigned int ucb1400_ts_read_yres(struct ucb1400_ts *ucb)
return ucb1400_adc_read(ucb->ac97, 0, adcsync);
}
static inline int ucb1400_ts_pen_up(struct snd_ac97 *ac97)
static int ucb1400_ts_pen_up(struct ucb1400_ts *ucb)
{
unsigned short val = ucb1400_reg_read(ac97, UCB_TS_CR);
unsigned short val = ucb1400_reg_read(ucb->ac97, UCB_TS_CR);
return val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW);
}
static inline void ucb1400_ts_irq_enable(struct snd_ac97 *ac97)
static void ucb1400_ts_irq_enable(struct ucb1400_ts *ucb)
{
ucb1400_reg_write(ac97, UCB_IE_CLEAR, UCB_IE_TSPX);
ucb1400_reg_write(ac97, UCB_IE_CLEAR, 0);
ucb1400_reg_write(ac97, UCB_IE_FAL, UCB_IE_TSPX);
ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, UCB_IE_TSPX);
ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0);
ucb1400_reg_write(ucb->ac97, UCB_IE_FAL, UCB_IE_TSPX);
}
static inline void ucb1400_ts_irq_disable(struct snd_ac97 *ac97)
static void ucb1400_ts_irq_disable(struct ucb1400_ts *ucb)
{
ucb1400_reg_write(ac97, UCB_IE_FAL, 0);
ucb1400_reg_write(ucb->ac97, UCB_IE_FAL, 0);
}
static void ucb1400_ts_evt_add(struct input_dev *idev, u16 pressure, u16 x, u16 y)
static void ucb1400_ts_report_event(struct input_dev *idev, u16 pressure, u16 x, u16 y)
{
input_report_abs(idev, ABS_X, x);
input_report_abs(idev, ABS_Y, y);
......@@ -162,7 +164,7 @@ static void ucb1400_ts_event_release(struct input_dev *idev)
input_sync(idev);
}
static void ucb1400_handle_pending_irq(struct ucb1400_ts *ucb)
static void ucb1400_clear_pending_irq(struct ucb1400_ts *ucb)
{
unsigned int isr;
......@@ -171,32 +173,34 @@ static void ucb1400_handle_pending_irq(struct ucb1400_ts *ucb)
ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0);
if (isr & UCB_IE_TSPX)
ucb1400_ts_irq_disable(ucb->ac97);
ucb1400_ts_irq_disable(ucb);
else
dev_dbg(&ucb->ts_idev->dev, "ucb1400: unexpected IE_STATUS = %#x\n", isr);
enable_irq(ucb->irq);
dev_dbg(&ucb->ts_idev->dev,
"ucb1400: unexpected IE_STATUS = %#x\n", isr);
}
static int ucb1400_ts_thread(void *_ucb)
/*
* A restriction with interrupts exists when using the ucb1400, as
* the codec read/write routines may sleep while waiting for codec
* access completion and uses semaphores for access control to the
* AC97 bus. Therefore the driver is forced to use threaded interrupt
* handler.
*/
static irqreturn_t ucb1400_irq(int irqnr, void *devid)
{
struct ucb1400_ts *ucb = _ucb;
struct task_struct *tsk = current;
int valid = 0;
struct sched_param param = { .sched_priority = 1 };
struct ucb1400_ts *ucb = devid;
unsigned int x, y, p;
bool penup;
sched_setscheduler(tsk, SCHED_FIFO, &param);
if (unlikely(irqnr != ucb->irq))
return IRQ_NONE;
set_freezable();
while (!kthread_should_stop()) {
unsigned int x, y, p;
long timeout;
ucb1400_clear_pending_irq(ucb);
ucb->ts_restart = 0;
/* Start with a small delay before checking pendown state */
msleep(UCB1400_TS_POLL_PERIOD);
if (ucb->irq_pending) {
ucb->irq_pending = 0;
ucb1400_handle_pending_irq(ucb);
}
while (!ucb->stopped && !(penup = ucb1400_ts_pen_up(ucb))) {
ucb1400_adc_enable(ucb->ac97);
x = ucb1400_ts_read_xpos(ucb);
......@@ -204,91 +208,62 @@ static int ucb1400_ts_thread(void *_ucb)
p = ucb1400_ts_read_pressure(ucb);
ucb1400_adc_disable(ucb->ac97);
/* Switch back to interrupt mode. */
ucb1400_ts_mode_int(ucb->ac97);
msleep(10);
if (ucb1400_ts_pen_up(ucb->ac97)) {
ucb1400_ts_irq_enable(ucb->ac97);
/*
* If we spat out a valid sample set last time,
* spit out a "pen off" sample here.
*/
if (valid) {
ucb1400_ts_event_release(ucb->ts_idev);
valid = 0;
}
timeout = MAX_SCHEDULE_TIMEOUT;
} else {
valid = 1;
ucb1400_ts_evt_add(ucb->ts_idev, p, x, y);
timeout = msecs_to_jiffies(10);
}
ucb1400_ts_report_event(ucb->ts_idev, p, x, y);
wait_event_freezable_timeout(ucb->ts_wait,
ucb->irq_pending || ucb->ts_restart ||
kthread_should_stop(), timeout);
wait_event_timeout(ucb->ts_wait, ucb->stopped,
msecs_to_jiffies(UCB1400_TS_POLL_PERIOD));
}
/* Send the "pen off" if we are stopping with the pen still active */
if (valid)
ucb1400_ts_event_release(ucb->ts_idev);
ucb1400_ts_event_release(ucb->ts_idev);
ucb->ts_task = NULL;
return 0;
if (!ucb->stopped) {
/* Switch back to interrupt mode. */
ucb1400_ts_mode_int(ucb);
ucb1400_ts_irq_enable(ucb);
}
return IRQ_HANDLED;
}
/*
* A restriction with interrupts exists when using the ucb1400, as
* the codec read/write routines may sleep while waiting for codec
* access completion and uses semaphores for access control to the
* AC97 bus. A complete codec read cycle could take anywhere from
* 60 to 100uSec so we *definitely* don't want to spin inside the
* interrupt handler waiting for codec access. So, we handle the
* interrupt by scheduling a RT kernel thread to run in process
* context instead of interrupt context.
*/
static irqreturn_t ucb1400_hard_irq(int irqnr, void *devid)
static void ucb1400_ts_stop(struct ucb1400_ts *ucb)
{
struct ucb1400_ts *ucb = devid;
/* Signal IRQ thread to stop polling and disable the handler. */
ucb->stopped = true;
mb();
wake_up(&ucb->ts_wait);
disable_irq(ucb->irq);
if (irqnr == ucb->irq) {
disable_irq_nosync(ucb->irq);
ucb->irq_pending = 1;
wake_up(&ucb->ts_wait);
return IRQ_HANDLED;
}
return IRQ_NONE;
ucb1400_ts_irq_disable(ucb);
ucb1400_reg_write(ucb->ac97, UCB_TS_CR, 0);
}
/* Must be called with ts->lock held */
static void ucb1400_ts_start(struct ucb1400_ts *ucb)
{
/* Tell IRQ thread that it may poll the device. */
ucb->stopped = false;
mb();
ucb1400_ts_mode_int(ucb);
ucb1400_ts_irq_enable(ucb);
enable_irq(ucb->irq);
}
static int ucb1400_ts_open(struct input_dev *idev)
{
struct ucb1400_ts *ucb = input_get_drvdata(idev);
int ret = 0;
BUG_ON(ucb->ts_task);
ucb1400_ts_start(ucb);
ucb->ts_task = kthread_run(ucb1400_ts_thread, ucb, "UCB1400_ts");
if (IS_ERR(ucb->ts_task)) {
ret = PTR_ERR(ucb->ts_task);
ucb->ts_task = NULL;
}
return ret;
return 0;
}
static void ucb1400_ts_close(struct input_dev *idev)
{
struct ucb1400_ts *ucb = input_get_drvdata(idev);
if (ucb->ts_task)
kthread_stop(ucb->ts_task);
ucb1400_ts_irq_disable(ucb->ac97);
ucb1400_reg_write(ucb->ac97, UCB_TS_CR, 0);
ucb1400_ts_stop(ucb);
}
#ifndef NO_IRQ
......@@ -299,7 +274,8 @@ static void ucb1400_ts_close(struct input_dev *idev)
* Try to probe our interrupt, rather than relying on lots of
* hard-coded machine dependencies.
*/
static int ucb1400_ts_detect_irq(struct ucb1400_ts *ucb)
static int __devinit ucb1400_ts_detect_irq(struct ucb1400_ts *ucb,
struct platform_device *pdev)
{
unsigned long mask, timeout;
......@@ -321,7 +297,7 @@ static int ucb1400_ts_detect_irq(struct ucb1400_ts *ucb)
UCB_ADC_DAT_VALID)) {
cpu_relax();
if (time_after(jiffies, timeout)) {
printk(KERN_ERR "ucb1400: timed out in IRQ probe\n");
dev_err(&pdev->dev, "timed out in IRQ probe\n");
probe_irq_off(mask);
return -ENODEV;
}
......@@ -342,11 +318,11 @@ static int ucb1400_ts_detect_irq(struct ucb1400_ts *ucb)
return 0;
}
static int ucb1400_ts_probe(struct platform_device *dev)
static int __devinit ucb1400_ts_probe(struct platform_device *pdev)
{
struct ucb1400_ts *ucb = pdev->dev.platform_data;
int error, x_res, y_res;
u16 fcsr;
struct ucb1400_ts *ucb = dev->dev.platform_data;
ucb->ts_idev = input_allocate_device();
if (!ucb->ts_idev) {
......@@ -356,27 +332,19 @@ static int ucb1400_ts_probe(struct platform_device *dev)
/* Only in case the IRQ line wasn't supplied, try detecting it */
if (ucb->irq < 0) {
error = ucb1400_ts_detect_irq(ucb);
error = ucb1400_ts_detect_irq(ucb, pdev);
if (error) {
printk(KERN_ERR "UCB1400: IRQ probe failed\n");
dev_err(&pdev->dev, "IRQ probe failed\n");
goto err_free_devs;
}
}
dev_dbg(&pdev->dev, "found IRQ %d\n", ucb->irq);
init_waitqueue_head(&ucb->ts_wait);
error = request_irq(ucb->irq, ucb1400_hard_irq, IRQF_TRIGGER_RISING,
"UCB1400", ucb);
if (error) {
printk(KERN_ERR "ucb1400: unable to grab irq%d: %d\n",
ucb->irq, error);
goto err_free_devs;
}
printk(KERN_DEBUG "UCB1400: found IRQ %d\n", ucb->irq);
input_set_drvdata(ucb->ts_idev, ucb);
ucb->ts_idev->dev.parent = &dev->dev;
ucb->ts_idev->dev.parent = &pdev->dev;
ucb->ts_idev->name = "UCB1400 touchscreen interface";
ucb->ts_idev->id.vendor = ucb1400_reg_read(ucb->ac97,
AC97_VENDOR_ID1);
......@@ -398,12 +366,23 @@ static int ucb1400_ts_probe(struct platform_device *dev)
x_res = ucb1400_ts_read_xres(ucb);
y_res = ucb1400_ts_read_yres(ucb);
ucb1400_adc_disable(ucb->ac97);
printk(KERN_DEBUG "UCB1400: x/y = %d/%d\n", x_res, y_res);
dev_dbg(&pdev->dev, "x/y = %d/%d\n", x_res, y_res);
input_set_abs_params(ucb->ts_idev, ABS_X, 0, x_res, 0, 0);
input_set_abs_params(ucb->ts_idev, ABS_Y, 0, y_res, 0, 0);
input_set_abs_params(ucb->ts_idev, ABS_PRESSURE, 0, 0, 0, 0);
ucb1400_ts_stop(ucb);
error = request_threaded_irq(ucb->irq, NULL, ucb1400_irq,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"UCB1400", ucb);
if (error) {
dev_err(&pdev->dev,
"unable to grab irq%d: %d\n", ucb->irq, error);
goto err_free_devs;
}
error = input_register_device(ucb->ts_idev);
if (error)
goto err_free_irq;
......@@ -416,56 +395,61 @@ static int ucb1400_ts_probe(struct platform_device *dev)
input_free_device(ucb->ts_idev);
err:
return error;
}
static int ucb1400_ts_remove(struct platform_device *dev)
static int __devexit ucb1400_ts_remove(struct platform_device *pdev)
{
struct ucb1400_ts *ucb = dev->dev.platform_data;
struct ucb1400_ts *ucb = pdev->dev.platform_data;
free_irq(ucb->irq, ucb);
input_unregister_device(ucb->ts_idev);
return 0;
}
#ifdef CONFIG_PM
static int ucb1400_ts_resume(struct platform_device *dev)
#ifdef CONFIG_PM_SLEEP
static int ucb1400_ts_suspend(struct device *dev)
{
struct ucb1400_ts *ucb = dev->dev.platform_data;
if (ucb->ts_task) {
/*
* Restart the TS thread to ensure the
* TS interrupt mode is set up again
* after sleep.
*/
ucb->ts_restart = 1;
wake_up(&ucb->ts_wait);
}
struct ucb1400_ts *ucb = dev->platform_data;
struct input_dev *idev = ucb->ts_idev;
mutex_lock(&idev->mutex);
if (idev->users)
ucb1400_ts_start(ucb);
mutex_unlock(&idev->mutex);
return 0;
}
static int ucb1400_ts_resume(struct device *dev)
{
struct ucb1400_ts *ucb = dev->platform_data;
struct input_dev *idev = ucb->ts_idev;
mutex_lock(&idev->mutex);
if (idev->users)
ucb1400_ts_stop(ucb);
mutex_unlock(&idev->mutex);
return 0;
}
#else
#define ucb1400_ts_resume NULL
#endif
static SIMPLE_DEV_PM_OPS(ucb1400_ts_pm_ops,
ucb1400_ts_suspend, ucb1400_ts_resume);
static struct platform_driver ucb1400_ts_driver = {
.probe = ucb1400_ts_probe,
.remove = ucb1400_ts_remove,
.resume = ucb1400_ts_resume,
.remove = __devexit_p(ucb1400_ts_remove),
.driver = {
.name = "ucb1400_ts",
.owner = THIS_MODULE,
.pm = &ucb1400_ts_pm_ops,
},
};
static int __init ucb1400_ts_init(void)
{
return platform_driver_register(&ucb1400_ts_driver);
}
static void __exit ucb1400_ts_exit(void)
{
platform_driver_unregister(&ucb1400_ts_driver);
}
module_platform_driver(ucb1400_ts_driver);
module_param(adcsync, bool, 0444);
MODULE_PARM_DESC(adcsync, "Synchronize touch readings with ADCSYNC pin.");
......@@ -479,8 +463,5 @@ MODULE_PARM_DESC(ts_delay_pressure,
"delay between panel setup and pressure read."
" Default = 0us.");
module_init(ucb1400_ts_init);
module_exit(ucb1400_ts_exit);
MODULE_DESCRIPTION("Philips UCB1400 touchscreen driver");
MODULE_LICENSE("GPL");
......@@ -16,6 +16,7 @@
* - JASTEC USB touch controller/DigiTech DTR-02U
* - Zytronic capacitive touchscreen
* - NEXIO/iNexio
* - Elo TouchSystems 2700 IntelliTouch
*
* Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
* Copyright (C) by Todd E. Johnson (mtouchusb.c)
......@@ -138,6 +139,7 @@ enum {
DEVTYPE_ZYTRONIC,
DEVTYPE_TC45USB,
DEVTYPE_NEXIO,
DEVTYPE_ELO,
};
#define USB_DEVICE_HID_CLASS(vend, prod) \
......@@ -239,6 +241,10 @@ static const struct usb_device_id usbtouch_devices[] = {
.driver_info = DEVTYPE_NEXIO},
#endif
#ifdef CONFIG_TOUCHSCREEN_USB_ELO
{USB_DEVICE(0x04e7, 0x0020), .driver_info = DEVTYPE_ELO},
#endif
{}
};
......@@ -944,6 +950,24 @@ static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
#endif
/*****************************************************************************
* ELO part
*/
#ifdef CONFIG_TOUCHSCREEN_USB_ELO
static int elo_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
{
dev->x = (pkt[3] << 8) | pkt[2];
dev->y = (pkt[5] << 8) | pkt[4];
dev->touch = pkt[6] > 0;
dev->press = pkt[6];
return 1;
}
#endif
/*****************************************************************************
* the different device descriptors
*/
......@@ -953,6 +977,18 @@ static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
#endif
static struct usbtouch_device_info usbtouch_dev_info[] = {
#ifdef CONFIG_TOUCHSCREEN_USB_ELO
[DEVTYPE_ELO] = {
.min_xc = 0x0,
.max_xc = 0x0fff,
.min_yc = 0x0,
.max_yc = 0x0fff,
.max_press = 0xff,
.rept_size = 8,
.read_data = elo_read_data,
},
#endif
#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
[DEVTYPE_EGALAX] = {
.min_xc = 0x0,
......
......@@ -331,19 +331,7 @@ static struct platform_driver w90x900ts_driver = {
.owner = THIS_MODULE,
},
};
static int __init w90x900ts_init(void)
{
return platform_driver_register(&w90x900ts_driver);
}
static void __exit w90x900ts_exit(void)
{
platform_driver_unregister(&w90x900ts_driver);
}
module_init(w90x900ts_init);
module_exit(w90x900ts_exit);
module_platform_driver(w90x900ts_driver);
MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
MODULE_DESCRIPTION("w90p910 touch screen driver!");
......
......@@ -401,18 +401,7 @@ static struct platform_driver wm831x_ts_driver = {
.probe = wm831x_ts_probe,
.remove = __devexit_p(wm831x_ts_remove),
};
static int __init wm831x_ts_init(void)
{
return platform_driver_register(&wm831x_ts_driver);
}
module_init(wm831x_ts_init);
static void __exit wm831x_ts_exit(void)
{
platform_driver_unregister(&wm831x_ts_driver);
}
module_exit(wm831x_ts_exit);
module_platform_driver(wm831x_ts_driver);
/* Module information */
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
......
......@@ -224,19 +224,7 @@ static struct platform_driver zylonite_wm97xx_driver = {
.name = "wm97xx-touch",
},
};
static int __init zylonite_wm97xx_init(void)
{
return platform_driver_register(&zylonite_wm97xx_driver);
}
static void __exit zylonite_wm97xx_exit(void)
{
platform_driver_unregister(&zylonite_wm97xx_driver);
}
module_init(zylonite_wm97xx_init);
module_exit(zylonite_wm97xx_exit);
module_platform_driver(zylonite_wm97xx_driver);
/* Module information */
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
......
/*
* Driver for AUO in-cell touchscreens
*
* Copyright (c) 2011 Heiko Stuebner <heiko@sntech.de>
*
* based on auo_touch.h from Dell Streak kernel
*
* Copyright (c) 2008 QUALCOMM Incorporated.
* Copyright (c) 2008 QUALCOMM USA, INC.
*
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#ifndef __AUO_PIXCIR_TS_H__
#define __AUO_PIXCIR_TS_H__
/*
* Interrupt modes:
* periodical: interrupt is asserted periodicaly
* compare coordinates: interrupt is asserted when coordinates change
* indicate touch: interrupt is asserted during touch
*/
#define AUO_PIXCIR_INT_PERIODICAL 0x00
#define AUO_PIXCIR_INT_COMP_COORD 0x01
#define AUO_PIXCIR_INT_TOUCH_IND 0x02
/*
* @gpio_int interrupt gpio
* @int_setting one of AUO_PIXCIR_INT_*
* @init_hw hardwarespecific init
* @exit_hw hardwarespecific shutdown
* @x_max x-resolution
* @y_max y-resolution
*/
struct auo_pixcir_ts_platdata {
int gpio_int;
int int_setting;
void (*init_hw)(struct i2c_client *);
void (*exit_hw)(struct i2c_client *);
unsigned int x_max;
unsigned int y_max;
};
#endif
#ifndef _GP2AP002A00F_H_
#define _GP2AP002A00F_H_
#include <linux/i2c.h>
#define GP2A_I2C_NAME "gp2ap002a00f"
/**
* struct gp2a_platform_data - Sharp gp2ap002a00f proximity platform data
* @vout_gpio: The gpio connected to the object detected pin (VOUT)
* @wakeup: Set to true if the proximity can wake the device from suspend
* @hw_setup: Callback for setting up hardware such as gpios and vregs
* @hw_shutdown: Callback for properly shutting down hardware
*/
struct gp2a_platform_data {
int vout_gpio;
bool wakeup;
int (*hw_setup)(struct i2c_client *client);
int (*hw_shutdown)(struct i2c_client *client);
};
#endif
#ifndef _INPUT_GPIO_TILT_H
#define _INPUT_GPIO_TILT_H
/**
* struct gpio_tilt_axis - Axis used by the tilt switch
* @axis: Constant describing the axis, e.g. ABS_X
* @min: minimum value for abs_param
* @max: maximum value for abs_param
* @fuzz: fuzz value for abs_param
* @flat: flat value for abs_param
*/
struct gpio_tilt_axis {
int axis;
int min;
int max;
int fuzz;
int flat;
};
/**
* struct gpio_tilt_state - state description
* @gpios: bitfield of gpio target-states for the value
* @axes: array containing the axes settings for the gpio state
* The array indizes must correspond to the axes defined
* in platform_data
*
* This structure describes a supported axis settings
* and the necessary gpio-state which represent it.
*
* The n-th bit in the bitfield describes the state of the n-th GPIO
* from the gpios-array defined in gpio_regulator_config below.
*/
struct gpio_tilt_state {
int gpios;
int *axes;
};
/**
* struct gpio_tilt_platform_data
* @gpios: Array containing the gpios determining the tilt state
* @nr_gpios: Number of gpios
* @axes: Array of gpio_tilt_axis descriptions
* @nr_axes: Number of axes
* @states: Array of gpio_tilt_state entries describing
* the gpio state for specific tilts
* @nr_states: Number of states available
* @debounce_interval: debounce ticks interval in msecs
* @poll_interval: polling interval in msecs - for polling driver only
* @enable: callback to enable the tilt switch
* @disable: callback to disable the tilt switch
*
* This structure contains gpio-tilt-switch configuration
* information that must be passed by platform code to the
* gpio-tilt input driver.
*/
struct gpio_tilt_platform_data {
struct gpio *gpios;
int nr_gpios;
struct gpio_tilt_axis *axes;
int nr_axes;
struct gpio_tilt_state *states;
int nr_states;
int debounce_interval;
unsigned int poll_interval;
int (*enable)(struct device *dev);
void (*disable)(struct device *dev);
};
#endif
#ifndef _PIXCIR_I2C_TS_H
#define _PIXCIR_I2C_TS_H
struct pixcir_ts_platform_data {
int (*attb_read_val)(void);
int x_max;
int y_max;
};
#endif
/*
* Samsung Keypad platform data definitions
*
* Copyright (C) 2010 Samsung Electronics Co.Ltd
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef __SAMSUNG_KEYPAD_H
#define __SAMSUNG_KEYPAD_H
#include <linux/input/matrix_keypad.h>
#define SAMSUNG_MAX_ROWS 8
#define SAMSUNG_MAX_COLS 8
/**
* struct samsung_keypad_platdata - Platform device data for Samsung Keypad.
* @keymap_data: pointer to &matrix_keymap_data.
* @rows: number of keypad row supported.
* @cols: number of keypad col supported.
* @no_autorepeat: disable key autorepeat.
* @wakeup: controls whether the device should be set up as wakeup source.
* @cfg_gpio: configure the GPIO.
*
* Initialisation data specific to either the machine or the platform
* for the device driver to use or call-back when configuring gpio.
*/
struct samsung_keypad_platdata {
const struct matrix_keymap_data *keymap_data;
unsigned int rows;
unsigned int cols;
bool no_autorepeat;
bool wakeup;
void (*cfg_gpio)(unsigned int rows, unsigned int cols);
};
#endif /* __SAMSUNG_KEYPAD_H */
/*
* TCA8418 keypad platform support
*
* Copyright (C) 2011 Fuel7, Inc. All rights reserved.
*
* Author: Kyle Manna <kyle.manna@fuel7.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License v2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 021110-1307, USA.
*
* If you can't comply with GPLv2, alternative licensing terms may be
* arranged. Please contact Fuel7, Inc. (http://fuel7.com/) for proprietary
* alternative licensing inquiries.
*/
#ifndef _TCA8418_KEYPAD_H
#define _TCA8418_KEYPAD_H
#include <linux/types.h>
#include <linux/input/matrix_keypad.h>
#define TCA8418_I2C_ADDR 0x34
#define TCA8418_NAME "tca8418_keypad"
struct tca8418_keypad_platform_data {
const struct matrix_keymap_data *keymap_data;
unsigned rows;
unsigned cols;
bool rep;
bool irq_is_gpio;
};
#endif
......@@ -96,13 +96,11 @@ struct ucb1400_gpio {
struct ucb1400_ts {
struct input_dev *ts_idev;
struct task_struct *ts_task;
int id;
wait_queue_head_t ts_wait;
unsigned int ts_restart:1;
int irq;
unsigned int irq_pending; /* not bit field shared */
struct snd_ac97 *ac97;
wait_queue_head_t ts_wait;
bool stopped;
};
struct ucb1400 {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册