forked from Minki/linux
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
This commit is contained in:
commit
dbe950f201
@ -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
|
||||
|
18
Documentation/devicetree/bindings/input/tegra-kbc.txt
Normal file
18
Documentation/devicetree/bindings/input/tegra-kbc.txt
Normal file
@ -0,0 +1,18 @@
|
||||
* 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;
|
||||
};
|
188
Documentation/input/alps.txt
Normal file
188
Documentation/input/alps.txt
Normal file
@ -0,0 +1,188 @@
|
||||
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.
|
103
Documentation/input/gpio-tilt.txt
Normal file
103
Documentation/input/gpio-tilt.txt
Normal file
@ -0,0 +1,103 @@
|
||||
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,
|
||||
},
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
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");
|
||||
|
430
drivers/input/keyboard/tca8418_keypad.c
Normal file
430
drivers/input/keyboard/tca8418_keypad.c
Normal file
@ -0,0 +1,430 @@
|
||||
/*
|
||||
* 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, ®);
|
||||
|
||||
/* 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, ®);
|
||||
}
|
||||
|
||||
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, ®);
|
||||
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;
|
||||
@ -589,22 +647,29 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
|
||||
unsigned int debounce_cnt;
|
||||
unsigned int scan_time_rows;
|
||||
|
||||
if (!pdata)
|
||||
pdata = tegra_kbc_dt_parse_pdata(pdev);
|
||||
|
||||
if (!pdata)
|
||||
return -EINVAL;
|
||||
|
||||
if (!tegra_kbc_check_pin_cfg(pdata, &pdev->dev, &num_rows))
|
||||
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 @@ err_free_mem_region:
|
||||
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");
|
||||
|
299
drivers/input/misc/gp2ap002a00f.c
Normal file
299
drivers/input/misc/gp2ap002a00f.c
Normal file
@ -0,0 +1,299 @@
|
||||
/*
|
||||
* 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");
|
213
drivers/input/misc/gpio_tilt_polled.c
Normal file
213
drivers/input/misc/gpio_tilt_polled.c
Normal file
@ -0,0 +1,213 @@
|
||||
/*
|
||||
* 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");
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
unsigned int value;
|
||||
int err;
|
||||
|
||||
if (strict_strtoul(buf, 10, &value))
|
||||
return -EINVAL;
|
||||
|
||||
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;
|
||||
|
||||
if (strict_strtoul(buf, 16, ®) || reg > 0xff)
|
||||
err = kstrtoint(buf, 16, ®);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
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;
|
||||
|
||||
if (strict_strtoul(buf, 10, &val) || val > 1)
|
||||
err = kstrtouint(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
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;
|
||||
|
||||
if (strict_strtoul(buf, 10, &val) || val > 1)
|
||||
err = kstrtouint(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
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, ¶m, 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, ¶m, 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;
|
||||
|
||||
if (strict_strtoul(buf, 10, &value) || value > 1)
|
||||
err = kstrtouint(buf, 10, &value);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
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);
|
||||
}
|
||||
EXPORT_SYMBOL(ad7879_suspend);
|
||||
|
||||
void ad7879_resume(struct ad7879 *ts)
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user