You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
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: (40 commits) Input: ADP5589 - new driver for I2C Keypad Decoder and I/O Expander Input: tsc2007 - add X, Y and Z fuzz factors to platform data Input: tsc2007 - add poll_period parameter to platform data Input: tsc2007 - add poll_delay parameter to platform data Input: tsc2007 - add max_rt parameter to platform data Input: tsc2007 - debounce pressure measurement Input: ad714x - fix captouch wheel option algorithm Input: ad714x - allow platform code to specify irqflags Input: ad714x - fix threshold and completion interrupt masks Input: ad714x - fix up input configuration Input: elantech - remove support for proprietary X driver Input: elantech - report multitouch with proper ABS_MT messages Input: elantech - export pressure and width when supported Input: elantech - describe further the protocol Input: atmel_tsadcc - correct call to input_free_device Input: add driver FSL MPR121 capacitive touch sensor Input: remove useless synchronize_rcu() calls Input: ads7846 - fix gpio_pendown configuration Input: ads7846 - add possibility to use external vref on ads7846 Input: rotary-encoder - add support for half-period encoders ...
This commit is contained in:
@@ -34,7 +34,8 @@ Contents
|
||||
Currently the Linux Elantech touchpad driver is aware of two different
|
||||
hardware versions unimaginatively called version 1 and version 2. Version 1
|
||||
is found in "older" laptops and uses 4 bytes per packet. Version 2 seems to
|
||||
be introduced with the EeePC and uses 6 bytes per packet.
|
||||
be introduced with the EeePC and uses 6 bytes per packet, and provides
|
||||
additional features such as position of two fingers, and width of the touch.
|
||||
|
||||
The driver tries to support both hardware versions and should be compatible
|
||||
with the Xorg Synaptics touchpad driver and its graphical configuration
|
||||
@@ -94,18 +95,44 @@ Currently the Linux Elantech touchpad driver provides two extra knobs under
|
||||
can check these bits and reject any packet that appears corrupted. Using
|
||||
this knob you can bypass that check.
|
||||
|
||||
It is not known yet whether hardware version 2 provides the same parity
|
||||
bits. Hence checking is disabled by default. Currently even turning it on
|
||||
will do nothing.
|
||||
|
||||
Hardware version 2 does not provide the same parity bits. Only some basic
|
||||
data consistency checking can be done. For now checking is disabled by
|
||||
default. Currently even turning it on will do nothing.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
3. Differentiating hardware versions
|
||||
=================================
|
||||
|
||||
3. Hardware version 1
|
||||
To detect the hardware version, read the version number as param[0].param[1].param[2]
|
||||
|
||||
4 bytes version: (after the arrow is the name given in the Dell-provided driver)
|
||||
02.00.22 => EF013
|
||||
02.06.00 => EF019
|
||||
In the wild, there appear to be more versions, such as 00.01.64, 01.00.21,
|
||||
02.00.00, 02.00.04, 02.00.06.
|
||||
|
||||
6 bytes:
|
||||
02.00.30 => EF113
|
||||
02.08.00 => EF023
|
||||
02.08.XX => EF123
|
||||
02.0B.00 => EF215
|
||||
04.01.XX => Scroll_EF051
|
||||
04.02.XX => EF051
|
||||
In the wild, there appear to be more versions, such as 04.03.01, 04.04.11. There
|
||||
appears to be almost no difference, except for EF113, which does not report
|
||||
pressure/width and has different data consistency checks.
|
||||
|
||||
Probably all the versions with param[0] <= 01 can be considered as
|
||||
4 bytes/firmware 1. The versions < 02.08.00, with the exception of 02.00.30, as
|
||||
4 bytes/firmware 2. Everything >= 02.08.00 can be considered as 6 bytes.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
4. Hardware version 1
|
||||
==================
|
||||
|
||||
3.1 Registers
|
||||
4.1 Registers
|
||||
~~~~~~~~~
|
||||
|
||||
By echoing a hexadecimal value to a register it contents can be altered.
|
||||
@@ -168,7 +195,7 @@ For example:
|
||||
smart edge activation area width?
|
||||
|
||||
|
||||
3.2 Native relative mode 4 byte packet format
|
||||
4.2 Native relative mode 4 byte packet format
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
byte 0:
|
||||
@@ -226,9 +253,13 @@ byte 3:
|
||||
positive = down
|
||||
|
||||
|
||||
3.3 Native absolute mode 4 byte packet format
|
||||
4.3 Native absolute mode 4 byte packet format
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
EF013 and EF019 have a special behaviour (due to a bug in the firmware?), and
|
||||
when 1 finger is touching, the first 2 position reports must be discarded.
|
||||
This counting is reset whenever a different number of fingers is reported.
|
||||
|
||||
byte 0:
|
||||
firmware version 1.x:
|
||||
|
||||
@@ -279,11 +310,11 @@ byte 3:
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
4. Hardware version 2
|
||||
5. Hardware version 2
|
||||
==================
|
||||
|
||||
|
||||
4.1 Registers
|
||||
5.1 Registers
|
||||
~~~~~~~~~
|
||||
|
||||
By echoing a hexadecimal value to a register it contents can be altered.
|
||||
@@ -316,16 +347,41 @@ For example:
|
||||
0x7f = never i.e. tap again to release)
|
||||
|
||||
|
||||
4.2 Native absolute mode 6 byte packet format
|
||||
5.2 Native absolute mode 6 byte packet format
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
5.2.1 Parity checking and packet re-synchronization
|
||||
There is no parity checking, however some consistency checks can be performed.
|
||||
|
||||
4.2.1 One finger touch
|
||||
For instance for EF113:
|
||||
SA1= packet[0];
|
||||
A1 = packet[1];
|
||||
B1 = packet[2];
|
||||
SB1= packet[3];
|
||||
C1 = packet[4];
|
||||
D1 = packet[5];
|
||||
if( (((SA1 & 0x3C) != 0x3C) && ((SA1 & 0xC0) != 0x80)) || // check Byte 1
|
||||
(((SA1 & 0x0C) != 0x0C) && ((SA1 & 0xC0) == 0x80)) || // check Byte 1 (one finger pressed)
|
||||
(((SA1 & 0xC0) != 0x80) && (( A1 & 0xF0) != 0x00)) || // check Byte 2
|
||||
(((SB1 & 0x3E) != 0x38) && ((SA1 & 0xC0) != 0x80)) || // check Byte 4
|
||||
(((SB1 & 0x0E) != 0x08) && ((SA1 & 0xC0) == 0x80)) || // check Byte 4 (one finger pressed)
|
||||
(((SA1 & 0xC0) != 0x80) && (( C1 & 0xF0) != 0x00)) ) // check Byte 5
|
||||
// error detected
|
||||
|
||||
For all the other ones, there are just a few constant bits:
|
||||
if( ((packet[0] & 0x0C) != 0x04) ||
|
||||
((packet[3] & 0x0f) != 0x02) )
|
||||
// error detected
|
||||
|
||||
|
||||
In case an error is detected, all the packets are shifted by one (and packet[0] is discarded).
|
||||
|
||||
5.2.1 One/Three finger touch
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
byte 0:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
n1 n0 . . . . R L
|
||||
n1 n0 w3 w2 . . R L
|
||||
|
||||
L, R = 1 when Left, Right mouse button pressed
|
||||
n1..n0 = numbers of fingers on touchpad
|
||||
@@ -333,24 +389,40 @@ byte 0:
|
||||
byte 1:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
. . . . . x10 x9 x8
|
||||
p7 p6 p5 p4 . x10 x9 x8
|
||||
|
||||
byte 2:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
x7 x6 x5 x4 x4 x2 x1 x0
|
||||
x7 x6 x5 x4 x3 x2 x1 x0
|
||||
|
||||
x10..x0 = absolute x value (horizontal)
|
||||
|
||||
byte 3:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
. . . . . . . .
|
||||
n4 vf w1 w0 . . . b2
|
||||
|
||||
n4 = set if more than 3 fingers (only in 3 fingers mode)
|
||||
vf = a kind of flag ? (only on EF123, 0 when finger is over one
|
||||
of the buttons, 1 otherwise)
|
||||
w3..w0 = width of the finger touch (not EF113)
|
||||
b2 (on EF113 only, 0 otherwise), b2.R.L indicates one button pressed:
|
||||
0 = none
|
||||
1 = Left
|
||||
2 = Right
|
||||
3 = Middle (Left and Right)
|
||||
4 = Forward
|
||||
5 = Back
|
||||
6 = Another one
|
||||
7 = Another one
|
||||
|
||||
byte 4:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
. . . . . . y9 y8
|
||||
p3 p1 p2 p0 . . y9 y8
|
||||
|
||||
p7..p0 = pressure (not EF113)
|
||||
|
||||
byte 5:
|
||||
|
||||
@@ -363,6 +435,11 @@ byte 5:
|
||||
4.2.2 Two finger touch
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Note that the two pairs of coordinates are not exactly the coordinates of the
|
||||
two fingers, but only the pair of the lower-left and upper-right coordinates.
|
||||
So the actual fingers might be situated on the other diagonal of the square
|
||||
defined by these two points.
|
||||
|
||||
byte 0:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
@@ -376,14 +453,14 @@ byte 1:
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0
|
||||
|
||||
ax8..ax0 = first finger absolute x value
|
||||
ax8..ax0 = lower-left finger absolute x value
|
||||
|
||||
byte 2:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0
|
||||
|
||||
ay8..ay0 = first finger absolute y value
|
||||
ay8..ay0 = lower-left finger absolute y value
|
||||
|
||||
byte 3:
|
||||
|
||||
@@ -395,11 +472,11 @@ byte 4:
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
bx7 bx6 bx5 bx4 bx3 bx2 bx1 bx0
|
||||
|
||||
bx8..bx0 = second finger absolute x value
|
||||
bx8..bx0 = upper-right finger absolute x value
|
||||
|
||||
byte 5:
|
||||
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
by7 by8 by5 by4 by3 by2 by1 by0
|
||||
|
||||
by8..by0 = second finger absolute y value
|
||||
by8..by0 = upper-right finger absolute y value
|
||||
|
||||
@@ -9,6 +9,9 @@ peripherals with two wires. The outputs are phase-shifted by 90 degrees
|
||||
and by triggering on falling and rising edges, the turn direction can
|
||||
be determined.
|
||||
|
||||
Some encoders have both outputs low in stable states, whereas others also have
|
||||
a stable state with both outputs high (half-period mode).
|
||||
|
||||
The phase diagram of these two outputs look like this:
|
||||
|
||||
_____ _____ _____
|
||||
@@ -26,6 +29,8 @@ The phase diagram of these two outputs look like this:
|
||||
|<-------->|
|
||||
one step
|
||||
|
||||
|<-->|
|
||||
one step (half-period mode)
|
||||
|
||||
For more information, please see
|
||||
http://en.wikipedia.org/wiki/Rotary_encoder
|
||||
@@ -34,6 +39,13 @@ For more information, please see
|
||||
1. Events / state machine
|
||||
-------------------------
|
||||
|
||||
In half-period mode, state a) and c) above are used to determine the
|
||||
rotational direction based on the last stable state. Events are reported in
|
||||
states b) and d) given that the new stable state is different from the last
|
||||
(i.e. the rotation was not reversed half-way).
|
||||
|
||||
Otherwise, the following apply:
|
||||
|
||||
a) Rising edge on channel A, channel B in low state
|
||||
This state is used to recognize a clockwise turn
|
||||
|
||||
@@ -96,6 +108,7 @@ static struct rotary_encoder_platform_data my_rotary_encoder_info = {
|
||||
.gpio_b = GPIO_ROTARY_B,
|
||||
.inverted_a = 0,
|
||||
.inverted_b = 0,
|
||||
.half_period = false,
|
||||
};
|
||||
|
||||
static struct platform_device rotary_encoder_device = {
|
||||
|
||||
@@ -50,13 +50,11 @@ struct tegra_kbc_platform_data {
|
||||
unsigned int debounce_cnt;
|
||||
unsigned int repeat_cnt;
|
||||
|
||||
unsigned int wake_cnt; /* 0:wake on any key >1:wake on wake_cfg */
|
||||
const struct tegra_kbc_wake_key *wake_cfg;
|
||||
|
||||
struct tegra_kbc_pin_cfg pin_cfg[KBC_MAX_GPIO];
|
||||
const struct matrix_keymap_data *keymap_data;
|
||||
|
||||
bool wakeup;
|
||||
bool use_fn_map;
|
||||
bool use_ghost_filter;
|
||||
};
|
||||
#endif
|
||||
|
||||
+11
-8
@@ -41,6 +41,7 @@ struct evdev {
|
||||
struct evdev_client {
|
||||
unsigned int head;
|
||||
unsigned int tail;
|
||||
unsigned int packet_head; /* [future] position of the first element of next packet */
|
||||
spinlock_t buffer_lock; /* protects access to buffer, head and tail */
|
||||
struct fasync_struct *fasync;
|
||||
struct evdev *evdev;
|
||||
@@ -72,12 +73,16 @@ static void evdev_pass_event(struct evdev_client *client,
|
||||
client->buffer[client->tail].type = EV_SYN;
|
||||
client->buffer[client->tail].code = SYN_DROPPED;
|
||||
client->buffer[client->tail].value = 0;
|
||||
|
||||
client->packet_head = client->tail;
|
||||
}
|
||||
|
||||
if (event->type == EV_SYN && event->code == SYN_REPORT) {
|
||||
client->packet_head = client->head;
|
||||
kill_fasync(&client->fasync, SIGIO, POLL_IN);
|
||||
}
|
||||
|
||||
spin_unlock(&client->buffer_lock);
|
||||
|
||||
if (event->type == EV_SYN)
|
||||
kill_fasync(&client->fasync, SIGIO, POLL_IN);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -159,7 +164,6 @@ static int evdev_grab(struct evdev *evdev, struct evdev_client *client)
|
||||
return error;
|
||||
|
||||
rcu_assign_pointer(evdev->grab, client);
|
||||
synchronize_rcu();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -182,7 +186,6 @@ static void evdev_attach_client(struct evdev *evdev,
|
||||
spin_lock(&evdev->client_lock);
|
||||
list_add_tail_rcu(&client->node, &evdev->client_list);
|
||||
spin_unlock(&evdev->client_lock);
|
||||
synchronize_rcu();
|
||||
}
|
||||
|
||||
static void evdev_detach_client(struct evdev *evdev,
|
||||
@@ -387,12 +390,12 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,
|
||||
if (count < input_event_size())
|
||||
return -EINVAL;
|
||||
|
||||
if (client->head == client->tail && evdev->exist &&
|
||||
if (client->packet_head == client->tail && evdev->exist &&
|
||||
(file->f_flags & O_NONBLOCK))
|
||||
return -EAGAIN;
|
||||
|
||||
retval = wait_event_interruptible(evdev->wait,
|
||||
client->head != client->tail || !evdev->exist);
|
||||
client->packet_head != client->tail || !evdev->exist);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
@@ -421,7 +424,7 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
|
||||
poll_wait(file, &evdev->wait, wait);
|
||||
|
||||
mask = evdev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR;
|
||||
if (client->head != client->tail)
|
||||
if (client->packet_head != client->tail)
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
|
||||
return mask;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/input-polldev.h>
|
||||
|
||||
MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
|
||||
@@ -20,44 +21,6 @@ MODULE_DESCRIPTION("Generic implementation of a polled input device");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_VERSION("0.1");
|
||||
|
||||
static DEFINE_MUTEX(polldev_mutex);
|
||||
static int polldev_users;
|
||||
static struct workqueue_struct *polldev_wq;
|
||||
|
||||
static int input_polldev_start_workqueue(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = mutex_lock_interruptible(&polldev_mutex);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (!polldev_users) {
|
||||
polldev_wq = create_singlethread_workqueue("ipolldevd");
|
||||
if (!polldev_wq) {
|
||||
pr_err("failed to create ipolldevd workqueue\n");
|
||||
retval = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
polldev_users++;
|
||||
|
||||
out:
|
||||
mutex_unlock(&polldev_mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void input_polldev_stop_workqueue(void)
|
||||
{
|
||||
mutex_lock(&polldev_mutex);
|
||||
|
||||
if (!--polldev_users)
|
||||
destroy_workqueue(polldev_wq);
|
||||
|
||||
mutex_unlock(&polldev_mutex);
|
||||
}
|
||||
|
||||
static void input_polldev_queue_work(struct input_polled_dev *dev)
|
||||
{
|
||||
unsigned long delay;
|
||||
@@ -66,7 +29,7 @@ static void input_polldev_queue_work(struct input_polled_dev *dev)
|
||||
if (delay >= HZ)
|
||||
delay = round_jiffies_relative(delay);
|
||||
|
||||
queue_delayed_work(polldev_wq, &dev->work, delay);
|
||||
queue_delayed_work(system_freezable_wq, &dev->work, delay);
|
||||
}
|
||||
|
||||
static void input_polled_device_work(struct work_struct *work)
|
||||
@@ -81,18 +44,13 @@ static void input_polled_device_work(struct work_struct *work)
|
||||
static int input_open_polled_device(struct input_dev *input)
|
||||
{
|
||||
struct input_polled_dev *dev = input_get_drvdata(input);
|
||||
int error;
|
||||
|
||||
error = input_polldev_start_workqueue();
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (dev->open)
|
||||
dev->open(dev);
|
||||
|
||||
/* Only start polling if polling is enabled */
|
||||
if (dev->poll_interval > 0)
|
||||
queue_delayed_work(polldev_wq, &dev->work, 0);
|
||||
queue_delayed_work(system_freezable_wq, &dev->work, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -102,13 +60,6 @@ static void input_close_polled_device(struct input_dev *input)
|
||||
struct input_polled_dev *dev = input_get_drvdata(input);
|
||||
|
||||
cancel_delayed_work_sync(&dev->work);
|
||||
/*
|
||||
* Clean up work struct to remove references to the workqueue.
|
||||
* It may be destroyed by the next call. This causes problems
|
||||
* at next device open-close in case of poll_interval == 0.
|
||||
*/
|
||||
INIT_DELAYED_WORK(&dev->work, dev->work.work.func);
|
||||
input_polldev_stop_workqueue();
|
||||
|
||||
if (dev->close)
|
||||
dev->close(dev);
|
||||
@@ -295,4 +246,3 @@ void input_unregister_polled_device(struct input_polled_dev *dev)
|
||||
input_unregister_device(dev->input);
|
||||
}
|
||||
EXPORT_SYMBOL(input_unregister_polled_device);
|
||||
|
||||
|
||||
@@ -451,7 +451,6 @@ int input_grab_device(struct input_handle *handle)
|
||||
}
|
||||
|
||||
rcu_assign_pointer(dev->grab, handle);
|
||||
synchronize_rcu();
|
||||
|
||||
out:
|
||||
mutex_unlock(&dev->mutex);
|
||||
|
||||
@@ -180,7 +180,6 @@ static void joydev_attach_client(struct joydev *joydev,
|
||||
spin_lock(&joydev->client_lock);
|
||||
list_add_tail_rcu(&client->node, &joydev->client_list);
|
||||
spin_unlock(&joydev->client_lock);
|
||||
synchronize_rcu();
|
||||
}
|
||||
|
||||
static void joydev_detach_client(struct joydev *joydev,
|
||||
|
||||
@@ -32,6 +32,16 @@ config KEYBOARD_ADP5588
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called adp5588-keys.
|
||||
|
||||
config KEYBOARD_ADP5589
|
||||
tristate "ADP5589 I2C QWERTY Keypad and IO Expander"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you want to use a ADP5589 attached to your
|
||||
system I2C bus.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called adp5589-keys.
|
||||
|
||||
config KEYBOARD_AMIGA
|
||||
tristate "Amiga keyboard"
|
||||
depends on AMIGA
|
||||
@@ -325,6 +335,18 @@ config KEYBOARD_MCS
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called mcs_touchkey.
|
||||
|
||||
config KEYBOARD_MPR121
|
||||
tristate "Freescale MPR121 Touchkey"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you have Freescale MPR121 touchkey controller
|
||||
chip in your system.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called mpr121_touchkey.
|
||||
|
||||
config KEYBOARD_IMX
|
||||
tristate "IMX keypad support"
|
||||
depends on ARCH_MXC
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
obj-$(CONFIG_KEYBOARD_ADP5520) += adp5520-keys.o
|
||||
obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o
|
||||
obj-$(CONFIG_KEYBOARD_ADP5589) += adp5589-keys.o
|
||||
obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
|
||||
obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
|
||||
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
|
||||
@@ -27,6 +28,7 @@ obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o
|
||||
obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_MAX7359) += max7359_keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_MCS) += mcs_touchkey.o
|
||||
obj-$(CONFIG_KEYBOARD_MPR121) += mpr121_touchkey.o
|
||||
obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
|
||||
obj-$(CONFIG_KEYBOARD_NOMADIK) += nomadik-ske-keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -324,7 +324,12 @@ static void gpio_keys_report_event(struct gpio_button_data *bdata)
|
||||
unsigned int type = button->type ?: EV_KEY;
|
||||
int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low;
|
||||
|
||||
input_event(input, type, button->code, !!state);
|
||||
if (type == EV_ABS) {
|
||||
if (state)
|
||||
input_event(input, type, button->code, button->value);
|
||||
} else {
|
||||
input_event(input, type, button->code, !!state);
|
||||
}
|
||||
input_sync(input);
|
||||
}
|
||||
|
||||
@@ -363,7 +368,7 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
|
||||
struct gpio_button_data *bdata,
|
||||
struct gpio_keys_button *button)
|
||||
{
|
||||
char *desc = button->desc ? button->desc : "gpio_keys";
|
||||
const char *desc = button->desc ? button->desc : "gpio_keys";
|
||||
struct device *dev = &pdev->dev;
|
||||
unsigned long irqflags;
|
||||
int irq, error;
|
||||
@@ -468,7 +473,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
input_set_drvdata(input, ddata);
|
||||
|
||||
input->name = pdev->name;
|
||||
input->name = pdata->name ? : pdev->name;
|
||||
input->phys = "gpio-keys/input0";
|
||||
input->dev.parent = &pdev->dev;
|
||||
input->open = gpio_keys_open;
|
||||
|
||||
@@ -0,0 +1,339 @@
|
||||
/*
|
||||
* Touchkey driver for Freescale MPR121 Controllor
|
||||
*
|
||||
* Copyright (C) 2011 Freescale Semiconductor, Inc.
|
||||
* Author: Zhang Jiejing <jiejing.zhang@freescale.com>
|
||||
*
|
||||
* Based on mcs_touchkey.c
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c/mpr121_touchkey.h>
|
||||
|
||||
/* Register definitions */
|
||||
#define ELE_TOUCH_STATUS_0_ADDR 0x0
|
||||
#define ELE_TOUCH_STATUS_1_ADDR 0X1
|
||||
#define MHD_RISING_ADDR 0x2b
|
||||
#define NHD_RISING_ADDR 0x2c
|
||||
#define NCL_RISING_ADDR 0x2d
|
||||
#define FDL_RISING_ADDR 0x2e
|
||||
#define MHD_FALLING_ADDR 0x2f
|
||||
#define NHD_FALLING_ADDR 0x30
|
||||
#define NCL_FALLING_ADDR 0x31
|
||||
#define FDL_FALLING_ADDR 0x32
|
||||
#define ELE0_TOUCH_THRESHOLD_ADDR 0x41
|
||||
#define ELE0_RELEASE_THRESHOLD_ADDR 0x42
|
||||
#define AFE_CONF_ADDR 0x5c
|
||||
#define FILTER_CONF_ADDR 0x5d
|
||||
|
||||
/*
|
||||
* ELECTRODE_CONF_ADDR: This register configures the number of
|
||||
* enabled capacitance sensing inputs and its run/suspend mode.
|
||||
*/
|
||||
#define ELECTRODE_CONF_ADDR 0x5e
|
||||
#define AUTO_CONFIG_CTRL_ADDR 0x7b
|
||||
#define AUTO_CONFIG_USL_ADDR 0x7d
|
||||
#define AUTO_CONFIG_LSL_ADDR 0x7e
|
||||
#define AUTO_CONFIG_TL_ADDR 0x7f
|
||||
|
||||
/* Threshold of touch/release trigger */
|
||||
#define TOUCH_THRESHOLD 0x0f
|
||||
#define RELEASE_THRESHOLD 0x0a
|
||||
/* Masks for touch and release triggers */
|
||||
#define TOUCH_STATUS_MASK 0xfff
|
||||
/* MPR121 has 12 keys */
|
||||
#define MPR121_MAX_KEY_COUNT 12
|
||||
|
||||
struct mpr121_touchkey {
|
||||
struct i2c_client *client;
|
||||
struct input_dev *input_dev;
|
||||
unsigned int key_val;
|
||||
unsigned int statusbits;
|
||||
unsigned int keycount;
|
||||
u16 keycodes[MPR121_MAX_KEY_COUNT];
|
||||
};
|
||||
|
||||
struct mpr121_init_register {
|
||||
int addr;
|
||||
u8 val;
|
||||
};
|
||||
|
||||
static const struct mpr121_init_register init_reg_table[] __devinitconst = {
|
||||
{ MHD_RISING_ADDR, 0x1 },
|
||||
{ NHD_RISING_ADDR, 0x1 },
|
||||
{ MHD_FALLING_ADDR, 0x1 },
|
||||
{ NHD_FALLING_ADDR, 0x1 },
|
||||
{ NCL_FALLING_ADDR, 0xff },
|
||||
{ FDL_FALLING_ADDR, 0x02 },
|
||||
{ FILTER_CONF_ADDR, 0x04 },
|
||||
{ AFE_CONF_ADDR, 0x0b },
|
||||
{ AUTO_CONFIG_CTRL_ADDR, 0x0b },
|
||||
};
|
||||
|
||||
static irqreturn_t mpr_touchkey_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct mpr121_touchkey *mpr121 = dev_id;
|
||||
struct i2c_client *client = mpr121->client;
|
||||
struct input_dev *input = mpr121->input_dev;
|
||||
unsigned int key_num, key_val, pressed;
|
||||
int reg;
|
||||
|
||||
reg = i2c_smbus_read_byte_data(client, ELE_TOUCH_STATUS_1_ADDR);
|
||||
if (reg < 0) {
|
||||
dev_err(&client->dev, "i2c read error [%d]\n", reg);
|
||||
goto out;
|
||||
}
|
||||
|
||||
reg <<= 8;
|
||||
reg |= i2c_smbus_read_byte_data(client, ELE_TOUCH_STATUS_0_ADDR);
|
||||
if (reg < 0) {
|
||||
dev_err(&client->dev, "i2c read error [%d]\n", reg);
|
||||
goto out;
|
||||
}
|
||||
|
||||
reg &= TOUCH_STATUS_MASK;
|
||||
/* use old press bit to figure out which bit changed */
|
||||
key_num = ffs(reg ^ mpr121->statusbits) - 1;
|
||||
pressed = reg & (1 << key_num);
|
||||
mpr121->statusbits = reg;
|
||||
|
||||
key_val = mpr121->keycodes[key_num];
|
||||
|
||||
input_event(input, EV_MSC, MSC_SCAN, key_num);
|
||||
input_report_key(input, key_val, pressed);
|
||||
input_sync(input);
|
||||
|
||||
dev_dbg(&client->dev, "key %d %d %s\n", key_num, key_val,
|
||||
pressed ? "pressed" : "released");
|
||||
|
||||
out:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __devinit mpr121_phys_init(const struct mpr121_platform_data *pdata,
|
||||
struct mpr121_touchkey *mpr121,
|
||||
struct i2c_client *client)
|
||||
{
|
||||
const struct mpr121_init_register *reg;
|
||||
unsigned char usl, lsl, tl;
|
||||
int i, t, vdd, ret;
|
||||
|
||||
/* Set up touch/release threshold for ele0-ele11 */
|
||||
for (i = 0; i <= MPR121_MAX_KEY_COUNT; i++) {
|
||||
t = ELE0_TOUCH_THRESHOLD_ADDR + (i * 2);
|
||||
ret = i2c_smbus_write_byte_data(client, t, TOUCH_THRESHOLD);
|
||||
if (ret < 0)
|
||||
goto err_i2c_write;
|
||||
ret = i2c_smbus_write_byte_data(client, t + 1,
|
||||
RELEASE_THRESHOLD);
|
||||
if (ret < 0)
|
||||
goto err_i2c_write;
|
||||
}
|
||||
|
||||
/* Set up init register */
|
||||
for (i = 0; i < ARRAY_SIZE(init_reg_table); i++) {
|
||||
reg = &init_reg_table[i];
|
||||
ret = i2c_smbus_write_byte_data(client, reg->addr, reg->val);
|
||||
if (ret < 0)
|
||||
goto err_i2c_write;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Capacitance on sensing input varies and needs to be compensated.
|
||||
* The internal MPR121-auto-configuration can do this if it's
|
||||
* registers are set properly (based on pdata->vdd_uv).
|
||||
*/
|
||||
vdd = pdata->vdd_uv / 1000;
|
||||
usl = ((vdd - 700) * 256) / vdd;
|
||||
lsl = (usl * 65) / 100;
|
||||
tl = (usl * 90) / 100;
|
||||
ret = i2c_smbus_write_byte_data(client, AUTO_CONFIG_USL_ADDR, usl);
|
||||
ret |= i2c_smbus_write_byte_data(client, AUTO_CONFIG_LSL_ADDR, lsl);
|
||||
ret |= i2c_smbus_write_byte_data(client, AUTO_CONFIG_TL_ADDR, tl);
|
||||
ret |= i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR,
|
||||
mpr121->keycount);
|
||||
if (ret != 0)
|
||||
goto err_i2c_write;
|
||||
|
||||
dev_dbg(&client->dev, "set up with %x keys.\n", mpr121->keycount);
|
||||
|
||||
return 0;
|
||||
|
||||
err_i2c_write:
|
||||
dev_err(&client->dev, "i2c write error: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devinit mpr_touchkey_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
const struct mpr121_platform_data *pdata = client->dev.platform_data;
|
||||
struct mpr121_touchkey *mpr121;
|
||||
struct input_dev *input_dev;
|
||||
int error;
|
||||
int i;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&client->dev, "no platform data defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!pdata->keymap || !pdata->keymap_size) {
|
||||
dev_err(&client->dev, "missing keymap data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pdata->keymap_size > MPR121_MAX_KEY_COUNT) {
|
||||
dev_err(&client->dev, "too many keys defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!client->irq) {
|
||||
dev_err(&client->dev, "irq number should not be zero\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mpr121 = kzalloc(sizeof(struct mpr121_touchkey), GFP_KERNEL);
|
||||
input_dev = input_allocate_device();
|
||||
if (!mpr121 || !input_dev) {
|
||||
dev_err(&client->dev, "Failed to allocate memory\n");
|
||||
error = -ENOMEM;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
mpr121->client = client;
|
||||
mpr121->input_dev = input_dev;
|
||||
mpr121->keycount = pdata->keymap_size;
|
||||
|
||||
input_dev->name = "Freescale MPR121 Touchkey";
|
||||
input_dev->id.bustype = BUS_I2C;
|
||||
input_dev->dev.parent = &client->dev;
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
|
||||
|
||||
input_dev->keycode = mpr121->keycodes;
|
||||
input_dev->keycodesize = sizeof(mpr121->keycodes[0]);
|
||||
input_dev->keycodemax = mpr121->keycount;
|
||||
|
||||
for (i = 0; i < pdata->keymap_size; i++) {
|
||||
input_set_capability(input_dev, EV_KEY, pdata->keymap[i]);
|
||||
mpr121->keycodes[i] = pdata->keymap[i];
|
||||
}
|
||||
|
||||
error = mpr121_phys_init(pdata, mpr121, client);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "Failed to init register\n");
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
error = request_threaded_irq(client->irq, NULL,
|
||||
mpr_touchkey_interrupt,
|
||||
IRQF_TRIGGER_FALLING,
|
||||
client->dev.driver->name, mpr121);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "Failed to register interrupt\n");
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
error = input_register_device(input_dev);
|
||||
if (error)
|
||||
goto err_free_irq;
|
||||
|
||||
i2c_set_clientdata(client, mpr121);
|
||||
device_init_wakeup(&client->dev, pdata->wakeup);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
free_irq(client->irq, mpr121);
|
||||
err_free_mem:
|
||||
input_free_device(input_dev);
|
||||
kfree(mpr121);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __devexit mpr_touchkey_remove(struct i2c_client *client)
|
||||
{
|
||||
struct mpr121_touchkey *mpr121 = i2c_get_clientdata(client);
|
||||
|
||||
free_irq(client->irq, mpr121);
|
||||
input_unregister_device(mpr121->input_dev);
|
||||
kfree(mpr121);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int mpr_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
||||
if (device_may_wakeup(&client->dev))
|
||||
enable_irq_wake(client->irq);
|
||||
|
||||
i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR, 0x00);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpr_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct mpr121_touchkey *mpr121 = i2c_get_clientdata(client);
|
||||
|
||||
if (device_may_wakeup(&client->dev))
|
||||
disable_irq_wake(client->irq);
|
||||
|
||||
i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR,
|
||||
mpr121->keycount);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(mpr121_touchkey_pm_ops, mpr_suspend, mpr_resume);
|
||||
|
||||
static const struct i2c_device_id mpr121_id[] = {
|
||||
{ "mpr121_touchkey", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mpr121_id);
|
||||
|
||||
static struct i2c_driver mpr_touchkey_driver = {
|
||||
.driver = {
|
||||
.name = "mpr121",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &mpr121_touchkey_pm_ops,
|
||||
},
|
||||
.id_table = mpr121_id,
|
||||
.probe = mpr_touchkey_probe,
|
||||
.remove = __devexit_p(mpr_touchkey_remove),
|
||||
};
|
||||
|
||||
static int __init mpr_touchkey_init(void)
|
||||
{
|
||||
return i2c_add_driver(&mpr_touchkey_driver);
|
||||
}
|
||||
module_init(mpr_touchkey_init);
|
||||
|
||||
static void __exit mpr_touchkey_exit(void)
|
||||
{
|
||||
i2c_del_driver(&mpr_touchkey_driver);
|
||||
}
|
||||
module_exit(mpr_touchkey_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Zhang Jiejing <jiejing.zhang@freescale.com>");
|
||||
MODULE_DESCRIPTION("Touch Key driver for Freescale MPR121 Chip");
|
||||
@@ -413,7 +413,7 @@ static int __devinit omap_kp_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
err5:
|
||||
for (i = irq_idx - 1; i >=0; i--)
|
||||
free_irq(row_gpios[i], NULL);
|
||||
free_irq(row_gpios[i], omap_kp);
|
||||
err4:
|
||||
input_unregister_device(omap_kp->input);
|
||||
input_dev = NULL;
|
||||
@@ -444,11 +444,11 @@ static int __devexit omap_kp_remove(struct platform_device *pdev)
|
||||
gpio_free(col_gpios[i]);
|
||||
for (i = 0; i < omap_kp->rows; i++) {
|
||||
gpio_free(row_gpios[i]);
|
||||
free_irq(gpio_to_irq(row_gpios[i]), NULL);
|
||||
free_irq(gpio_to_irq(row_gpios[i]), omap_kp);
|
||||
}
|
||||
} else {
|
||||
omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
|
||||
free_irq(omap_kp->irq, NULL);
|
||||
free_irq(omap_kp->irq, omap_kp);
|
||||
}
|
||||
|
||||
del_timer_sync(&omap_kp->timer);
|
||||
|
||||
@@ -248,6 +248,7 @@ static const struct i2c_device_id qt1070_id[] = {
|
||||
{ "qt1070", 0 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, qt1070_id);
|
||||
|
||||
static struct i2c_driver qt1070_driver = {
|
||||
.driver = {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/sh_keysc.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@@ -37,7 +37,6 @@ static const struct {
|
||||
|
||||
struct sh_keysc_priv {
|
||||
void __iomem *iomem_base;
|
||||
struct clk *clk;
|
||||
DECLARE_BITMAP(last_keys, SH_KEYSC_MAXKEYS);
|
||||
struct input_dev *input;
|
||||
struct sh_keysc_info pdata;
|
||||
@@ -169,7 +168,6 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
|
||||
struct sh_keysc_info *pdata;
|
||||
struct resource *res;
|
||||
struct input_dev *input;
|
||||
char clk_name[8];
|
||||
int i;
|
||||
int irq, error;
|
||||
|
||||
@@ -210,19 +208,11 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
|
||||
goto err1;
|
||||
}
|
||||
|
||||
snprintf(clk_name, sizeof(clk_name), "keysc%d", pdev->id);
|
||||
priv->clk = clk_get(&pdev->dev, clk_name);
|
||||
if (IS_ERR(priv->clk)) {
|
||||
dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
|
||||
error = PTR_ERR(priv->clk);
|
||||
goto err2;
|
||||
}
|
||||
|
||||
priv->input = input_allocate_device();
|
||||
if (!priv->input) {
|
||||
dev_err(&pdev->dev, "failed to allocate input device\n");
|
||||
error = -ENOMEM;
|
||||
goto err3;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
input = priv->input;
|
||||
@@ -241,10 +231,11 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
|
||||
input->keycodesize = sizeof(pdata->keycodes[0]);
|
||||
input->keycodemax = ARRAY_SIZE(pdata->keycodes);
|
||||
|
||||
error = request_irq(irq, sh_keysc_isr, 0, pdev->name, pdev);
|
||||
error = request_threaded_irq(irq, NULL, sh_keysc_isr, IRQF_ONESHOT,
|
||||
dev_name(&pdev->dev), pdev);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to request IRQ\n");
|
||||
goto err4;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
for (i = 0; i < SH_KEYSC_MAXKEYS; i++)
|
||||
@@ -254,10 +245,11 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
|
||||
error = input_register_device(input);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to register input device\n");
|
||||
goto err5;
|
||||
goto err4;
|
||||
}
|
||||
|
||||
clk_enable(priv->clk);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
|
||||
sh_keysc_write(priv, KYCR1, (sh_keysc_mode[pdata->mode].kymd << 8) |
|
||||
pdata->scan_timing);
|
||||
@@ -267,12 +259,10 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
|
||||
err5:
|
||||
free_irq(irq, pdev);
|
||||
err4:
|
||||
input_free_device(input);
|
||||
free_irq(irq, pdev);
|
||||
err3:
|
||||
clk_put(priv->clk);
|
||||
input_free_device(input);
|
||||
err2:
|
||||
iounmap(priv->iomem_base);
|
||||
err1:
|
||||
@@ -292,8 +282,8 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev)
|
||||
free_irq(platform_get_irq(pdev, 0), pdev);
|
||||
iounmap(priv->iomem_base);
|
||||
|
||||
clk_disable(priv->clk);
|
||||
clk_put(priv->clk);
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(priv);
|
||||
@@ -301,6 +291,7 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if CONFIG_PM_SLEEP
|
||||
static int sh_keysc_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
@@ -311,14 +302,13 @@ static int sh_keysc_suspend(struct device *dev)
|
||||
value = sh_keysc_read(priv, KYCR1);
|
||||
|
||||
if (device_may_wakeup(dev)) {
|
||||
value |= 0x80;
|
||||
sh_keysc_write(priv, KYCR1, value | 0x80);
|
||||
enable_irq_wake(irq);
|
||||
} else {
|
||||
value &= ~0x80;
|
||||
sh_keysc_write(priv, KYCR1, value & ~0x80);
|
||||
pm_runtime_put_sync(dev);
|
||||
}
|
||||
|
||||
sh_keysc_write(priv, KYCR1, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -329,16 +319,17 @@ static int sh_keysc_resume(struct device *dev)
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
disable_irq_wake(irq);
|
||||
else
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops sh_keysc_dev_pm_ops = {
|
||||
.suspend = sh_keysc_suspend,
|
||||
.resume = sh_keysc_resume,
|
||||
};
|
||||
static SIMPLE_DEV_PM_OPS(sh_keysc_dev_pm_ops,
|
||||
sh_keysc_suspend, sh_keysc_resume);
|
||||
|
||||
struct platform_driver sh_keysc_device_driver = {
|
||||
static struct platform_driver sh_keysc_device_driver = {
|
||||
.probe = sh_keysc_probe,
|
||||
.remove = __devexit_p(sh_keysc_remove),
|
||||
.driver = {
|
||||
|
||||
@@ -66,12 +66,11 @@ struct tegra_kbc {
|
||||
void __iomem *mmio;
|
||||
struct input_dev *idev;
|
||||
unsigned int irq;
|
||||
unsigned int wake_enable_rows;
|
||||
unsigned int wake_enable_cols;
|
||||
spinlock_t lock;
|
||||
unsigned int repoll_dly;
|
||||
unsigned long cp_dly_jiffies;
|
||||
bool use_fn_map;
|
||||
bool use_ghost_filter;
|
||||
const struct tegra_kbc_platform_data *pdata;
|
||||
unsigned short keycode[KBC_MAX_KEY * 2];
|
||||
unsigned short current_keys[KBC_MAX_KPENT];
|
||||
@@ -260,6 +259,8 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
|
||||
unsigned int num_down = 0;
|
||||
unsigned long flags;
|
||||
bool fn_keypress = false;
|
||||
bool key_in_same_row = false;
|
||||
bool key_in_same_col = false;
|
||||
|
||||
spin_lock_irqsave(&kbc->lock, flags);
|
||||
for (i = 0; i < KBC_MAX_KPENT; i++) {
|
||||
@@ -284,6 +285,34 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
|
||||
val >>= 8;
|
||||
}
|
||||
|
||||
/*
|
||||
* Matrix keyboard designs are prone to keyboard ghosting.
|
||||
* Ghosting occurs if there are 3 keys such that -
|
||||
* any 2 of the 3 keys share a row, and any 2 of them share a column.
|
||||
* If so ignore the key presses for this iteration.
|
||||
*/
|
||||
if ((kbc->use_ghost_filter) && (num_down >= 3)) {
|
||||
for (i = 0; i < num_down; i++) {
|
||||
unsigned int j;
|
||||
u8 curr_col = scancodes[i] & 0x07;
|
||||
u8 curr_row = scancodes[i] >> KBC_ROW_SHIFT;
|
||||
|
||||
/*
|
||||
* Find 2 keys such that one key is in the same row
|
||||
* and the other is in the same column as the i-th key.
|
||||
*/
|
||||
for (j = i + 1; j < num_down; j++) {
|
||||
u8 col = scancodes[j] & 0x07;
|
||||
u8 row = scancodes[j] >> KBC_ROW_SHIFT;
|
||||
|
||||
if (col == curr_col)
|
||||
key_in_same_col = true;
|
||||
if (row == curr_row)
|
||||
key_in_same_row = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the platform uses Fn keymaps, translate keys on a Fn keypress.
|
||||
* Function keycodes are KBC_MAX_KEY apart from the plain keycodes.
|
||||
@@ -297,6 +326,10 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
|
||||
|
||||
spin_unlock_irqrestore(&kbc->lock, flags);
|
||||
|
||||
/* Ignore the key presses for this iteration? */
|
||||
if (key_in_same_col && key_in_same_row)
|
||||
return;
|
||||
|
||||
tegra_kbc_report_released_keys(kbc->idev,
|
||||
kbc->current_keys, kbc->num_pressed_keys,
|
||||
keycodes, num_down);
|
||||
@@ -383,21 +416,11 @@ static void tegra_kbc_setup_wakekeys(struct tegra_kbc *kbc, bool filter)
|
||||
int i;
|
||||
unsigned int rst_val;
|
||||
|
||||
BUG_ON(pdata->wake_cnt > KBC_MAX_KEY);
|
||||
rst_val = (filter && pdata->wake_cnt) ? ~0 : 0;
|
||||
/* Either mask all keys or none. */
|
||||
rst_val = (filter && !pdata->wakeup) ? ~0 : 0;
|
||||
|
||||
for (i = 0; i < KBC_MAX_ROW; i++)
|
||||
writel(rst_val, kbc->mmio + KBC_ROW0_MASK_0 + i * 4);
|
||||
|
||||
if (filter) {
|
||||
for (i = 0; i < pdata->wake_cnt; i++) {
|
||||
u32 val, addr;
|
||||
addr = pdata->wake_cfg[i].row * 4 + KBC_ROW0_MASK_0;
|
||||
val = readl(kbc->mmio + addr);
|
||||
val &= ~(1 << pdata->wake_cfg[i].col);
|
||||
writel(val, kbc->mmio + addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void tegra_kbc_config_pins(struct tegra_kbc *kbc)
|
||||
@@ -559,7 +582,6 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
int irq;
|
||||
int err;
|
||||
int i;
|
||||
int num_rows = 0;
|
||||
unsigned int debounce_cnt;
|
||||
unsigned int scan_time_rows;
|
||||
@@ -616,13 +638,6 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
|
||||
goto err_iounmap;
|
||||
}
|
||||
|
||||
kbc->wake_enable_rows = 0;
|
||||
kbc->wake_enable_cols = 0;
|
||||
for (i = 0; i < pdata->wake_cnt; i++) {
|
||||
kbc->wake_enable_rows |= (1 << pdata->wake_cfg[i].row);
|
||||
kbc->wake_enable_cols |= (1 << pdata->wake_cfg[i].col);
|
||||
}
|
||||
|
||||
/*
|
||||
* The time delay between two consecutive reads of the FIFO is
|
||||
* the sum of the repeat time and the time taken for scanning
|
||||
@@ -652,6 +667,7 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
|
||||
input_dev->keycodemax *= 2;
|
||||
|
||||
kbc->use_fn_map = pdata->use_fn_map;
|
||||
kbc->use_ghost_filter = pdata->use_ghost_filter;
|
||||
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);
|
||||
|
||||
+32
-93
@@ -79,13 +79,7 @@ struct ad714x_slider_drv {
|
||||
struct ad714x_wheel_drv {
|
||||
int abs_pos;
|
||||
int flt_pos;
|
||||
int pre_mean_value;
|
||||
int pre_highest_stage;
|
||||
int pre_mean_value_no_offset;
|
||||
int mean_value;
|
||||
int mean_value_no_offset;
|
||||
int pos_offset;
|
||||
int pos_ratio;
|
||||
int highest_stage;
|
||||
enum ad714x_device_state state;
|
||||
struct input_dev *input;
|
||||
@@ -158,10 +152,10 @@ static void ad714x_use_com_int(struct ad714x_chip *ad714x,
|
||||
unsigned short data;
|
||||
unsigned short mask;
|
||||
|
||||
mask = ((1 << (end_stage + 1)) - 1) - (1 << start_stage);
|
||||
mask = ((1 << (end_stage + 1)) - 1) - ((1 << start_stage) - 1);
|
||||
|
||||
ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data);
|
||||
data |= 1 << start_stage;
|
||||
data |= 1 << end_stage;
|
||||
ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data);
|
||||
|
||||
ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data);
|
||||
@@ -175,10 +169,10 @@ static void ad714x_use_thr_int(struct ad714x_chip *ad714x,
|
||||
unsigned short data;
|
||||
unsigned short mask;
|
||||
|
||||
mask = ((1 << (end_stage + 1)) - 1) - (1 << start_stage);
|
||||
mask = ((1 << (end_stage + 1)) - 1) - ((1 << start_stage) - 1);
|
||||
|
||||
ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data);
|
||||
data &= ~(1 << start_stage);
|
||||
data &= ~(1 << end_stage);
|
||||
ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data);
|
||||
|
||||
ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data);
|
||||
@@ -404,7 +398,6 @@ static void ad714x_slider_state_machine(struct ad714x_chip *ad714x, int idx)
|
||||
ad714x_slider_cal_highest_stage(ad714x, idx);
|
||||
ad714x_slider_cal_abs_pos(ad714x, idx);
|
||||
ad714x_slider_cal_flt_pos(ad714x, idx);
|
||||
|
||||
input_report_abs(sw->input, ABS_X, sw->flt_pos);
|
||||
input_report_key(sw->input, BTN_TOUCH, 1);
|
||||
} else {
|
||||
@@ -468,104 +461,41 @@ static void ad714x_wheel_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
|
||||
/*
|
||||
* When the scroll wheel is activated, we compute the absolute position based
|
||||
* on the sensor values. To calculate the position, we first determine the
|
||||
* sensor that has the greatest response among the 8 sensors that constitutes
|
||||
* the scrollwheel. Then we determined the 2 sensors on either sides of the
|
||||
* sensor that has the greatest response among the sensors that constitutes
|
||||
* the scrollwheel. Then we determined the sensors on either sides of the
|
||||
* sensor with the highest response and we apply weights to these sensors. The
|
||||
* result of this computation gives us the mean value which defined by the
|
||||
* following formula:
|
||||
* For i= second_before_highest_stage to i= second_after_highest_stage
|
||||
* v += Sensor response(i)*WEIGHT*(i+3)
|
||||
* w += Sensor response(i)
|
||||
* Mean_Value=v/w
|
||||
* pos_on_scrollwheel = (Mean_Value - position_offset) / position_ratio
|
||||
* result of this computation gives us the mean value.
|
||||
*/
|
||||
|
||||
#define WEIGHT_FACTOR 30
|
||||
/* This constant prevents the "PositionOffset" from reaching a big value */
|
||||
#define OFFSET_POSITION_CLAMP 120
|
||||
static void ad714x_wheel_cal_abs_pos(struct ad714x_chip *ad714x, int idx)
|
||||
{
|
||||
struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
|
||||
struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
|
||||
int stage_num = hw->end_stage - hw->start_stage + 1;
|
||||
int second_before, first_before, highest, first_after, second_after;
|
||||
int first_before, highest, first_after;
|
||||
int a_param, b_param;
|
||||
|
||||
/* Calculate Mean value */
|
||||
|
||||
second_before = (sw->highest_stage + stage_num - 2) % stage_num;
|
||||
first_before = (sw->highest_stage + stage_num - 1) % stage_num;
|
||||
highest = sw->highest_stage;
|
||||
first_after = (sw->highest_stage + stage_num + 1) % stage_num;
|
||||
second_after = (sw->highest_stage + stage_num + 2) % stage_num;
|
||||
|
||||
if (((sw->highest_stage - hw->start_stage) > 1) &&
|
||||
((hw->end_stage - sw->highest_stage) > 1)) {
|
||||
a_param = ad714x->sensor_val[second_before] *
|
||||
(second_before - hw->start_stage + 3) +
|
||||
ad714x->sensor_val[first_before] *
|
||||
(second_before - hw->start_stage + 3) +
|
||||
ad714x->sensor_val[highest] *
|
||||
(second_before - hw->start_stage + 3) +
|
||||
ad714x->sensor_val[first_after] *
|
||||
(first_after - hw->start_stage + 3) +
|
||||
ad714x->sensor_val[second_after] *
|
||||
(second_after - hw->start_stage + 3);
|
||||
} else {
|
||||
a_param = ad714x->sensor_val[second_before] *
|
||||
(second_before - hw->start_stage + 1) +
|
||||
ad714x->sensor_val[first_before] *
|
||||
(second_before - hw->start_stage + 2) +
|
||||
ad714x->sensor_val[highest] *
|
||||
(second_before - hw->start_stage + 3) +
|
||||
ad714x->sensor_val[first_after] *
|
||||
(first_after - hw->start_stage + 4) +
|
||||
ad714x->sensor_val[second_after] *
|
||||
(second_after - hw->start_stage + 5);
|
||||
}
|
||||
a_param *= WEIGHT_FACTOR;
|
||||
|
||||
b_param = ad714x->sensor_val[second_before] +
|
||||
a_param = ad714x->sensor_val[highest] *
|
||||
(highest - hw->start_stage) +
|
||||
ad714x->sensor_val[first_before] *
|
||||
(highest - hw->start_stage - 1) +
|
||||
ad714x->sensor_val[first_after] *
|
||||
(highest - hw->start_stage + 1);
|
||||
b_param = ad714x->sensor_val[highest] +
|
||||
ad714x->sensor_val[first_before] +
|
||||
ad714x->sensor_val[highest] +
|
||||
ad714x->sensor_val[first_after] +
|
||||
ad714x->sensor_val[second_after];
|
||||
ad714x->sensor_val[first_after];
|
||||
|
||||
sw->pre_mean_value = sw->mean_value;
|
||||
sw->mean_value = a_param / b_param;
|
||||
sw->abs_pos = ((hw->max_coord / (hw->end_stage - hw->start_stage)) *
|
||||
a_param) / b_param;
|
||||
|
||||
/* Calculate the offset */
|
||||
|
||||
if ((sw->pre_highest_stage == hw->end_stage) &&
|
||||
(sw->highest_stage == hw->start_stage))
|
||||
sw->pos_offset = sw->mean_value;
|
||||
else if ((sw->pre_highest_stage == hw->start_stage) &&
|
||||
(sw->highest_stage == hw->end_stage))
|
||||
sw->pos_offset = sw->pre_mean_value;
|
||||
|
||||
if (sw->pos_offset > OFFSET_POSITION_CLAMP)
|
||||
sw->pos_offset = OFFSET_POSITION_CLAMP;
|
||||
|
||||
/* Calculate the mean value without the offset */
|
||||
|
||||
sw->pre_mean_value_no_offset = sw->mean_value_no_offset;
|
||||
sw->mean_value_no_offset = sw->mean_value - sw->pos_offset;
|
||||
if (sw->mean_value_no_offset < 0)
|
||||
sw->mean_value_no_offset = 0;
|
||||
|
||||
/* Calculate ratio to scale down to NUMBER_OF_WANTED_POSITIONS */
|
||||
|
||||
if ((sw->pre_highest_stage == hw->end_stage) &&
|
||||
(sw->highest_stage == hw->start_stage))
|
||||
sw->pos_ratio = (sw->pre_mean_value_no_offset * 100) /
|
||||
hw->max_coord;
|
||||
else if ((sw->pre_highest_stage == hw->start_stage) &&
|
||||
(sw->highest_stage == hw->end_stage))
|
||||
sw->pos_ratio = (sw->mean_value_no_offset * 100) /
|
||||
hw->max_coord;
|
||||
sw->abs_pos = (sw->mean_value_no_offset * 100) / sw->pos_ratio;
|
||||
if (sw->abs_pos > hw->max_coord)
|
||||
sw->abs_pos = hw->max_coord;
|
||||
else if (sw->abs_pos < 0)
|
||||
sw->abs_pos = 0;
|
||||
}
|
||||
|
||||
static void ad714x_wheel_cal_flt_pos(struct ad714x_chip *ad714x, int idx)
|
||||
@@ -639,9 +569,8 @@ static void ad714x_wheel_state_machine(struct ad714x_chip *ad714x, int idx)
|
||||
ad714x_wheel_cal_highest_stage(ad714x, idx);
|
||||
ad714x_wheel_cal_abs_pos(ad714x, idx);
|
||||
ad714x_wheel_cal_flt_pos(ad714x, idx);
|
||||
|
||||
input_report_abs(sw->input, ABS_WHEEL,
|
||||
sw->abs_pos);
|
||||
sw->flt_pos);
|
||||
input_report_key(sw->input, BTN_TOUCH, 1);
|
||||
} else {
|
||||
/* When the user lifts off the sensor, configure
|
||||
@@ -1149,6 +1078,8 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
|
||||
input[alloc_idx]->id.bustype = bus_type;
|
||||
input[alloc_idx]->id.product = ad714x->product;
|
||||
input[alloc_idx]->id.version = ad714x->version;
|
||||
input[alloc_idx]->name = "ad714x_captouch_slider";
|
||||
input[alloc_idx]->dev.parent = dev;
|
||||
|
||||
error = input_register_device(input[alloc_idx]);
|
||||
if (error)
|
||||
@@ -1179,6 +1110,8 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
|
||||
input[alloc_idx]->id.bustype = bus_type;
|
||||
input[alloc_idx]->id.product = ad714x->product;
|
||||
input[alloc_idx]->id.version = ad714x->version;
|
||||
input[alloc_idx]->name = "ad714x_captouch_wheel";
|
||||
input[alloc_idx]->dev.parent = dev;
|
||||
|
||||
error = input_register_device(input[alloc_idx]);
|
||||
if (error)
|
||||
@@ -1212,6 +1145,8 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
|
||||
input[alloc_idx]->id.bustype = bus_type;
|
||||
input[alloc_idx]->id.product = ad714x->product;
|
||||
input[alloc_idx]->id.version = ad714x->version;
|
||||
input[alloc_idx]->name = "ad714x_captouch_pad";
|
||||
input[alloc_idx]->dev.parent = dev;
|
||||
|
||||
error = input_register_device(input[alloc_idx]);
|
||||
if (error)
|
||||
@@ -1240,6 +1175,8 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
|
||||
input[alloc_idx]->id.bustype = bus_type;
|
||||
input[alloc_idx]->id.product = ad714x->product;
|
||||
input[alloc_idx]->id.version = ad714x->version;
|
||||
input[alloc_idx]->name = "ad714x_captouch_button";
|
||||
input[alloc_idx]->dev.parent = dev;
|
||||
|
||||
error = input_register_device(input[alloc_idx]);
|
||||
if (error)
|
||||
@@ -1249,7 +1186,9 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
|
||||
}
|
||||
|
||||
error = request_threaded_irq(ad714x->irq, NULL, ad714x_interrupt_thread,
|
||||
IRQF_TRIGGER_FALLING, "ad714x_captouch", ad714x);
|
||||
plat_data->irqflags ?
|
||||
plat_data->irqflags : IRQF_TRIGGER_FALLING,
|
||||
"ad714x_captouch", ad714x);
|
||||
if (error) {
|
||||
dev_err(dev, "can't allocate irq %d\n", ad714x->irq);
|
||||
goto err_unreg_dev;
|
||||
|
||||
@@ -737,14 +737,17 @@ static ssize_t ati_remote2_store_channel_mask(struct device *dev,
|
||||
|
||||
mutex_lock(&ati_remote2_mutex);
|
||||
|
||||
if (mask != ar2->channel_mask && !ati_remote2_setup(ar2, mask))
|
||||
ar2->channel_mask = mask;
|
||||
if (mask != ar2->channel_mask) {
|
||||
r = ati_remote2_setup(ar2, mask);
|
||||
if (!r)
|
||||
ar2->channel_mask = mask;
|
||||
}
|
||||
|
||||
mutex_unlock(&ati_remote2_mutex);
|
||||
|
||||
usb_autopm_put_interface(ar2->intf[0]);
|
||||
|
||||
return count;
|
||||
return r ? r : count;
|
||||
}
|
||||
|
||||
static ssize_t ati_remote2_show_mode_mask(struct device *dev,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* rotary_encoder.c
|
||||
*
|
||||
* (c) 2009 Daniel Mack <daniel@caiaq.de>
|
||||
* Copyright (C) 2011 Johan Hovold <jhovold@gmail.com>
|
||||
*
|
||||
* state machine code inspired by code from Tim Ruetz
|
||||
*
|
||||
@@ -38,52 +39,66 @@ struct rotary_encoder {
|
||||
|
||||
bool armed;
|
||||
unsigned char dir; /* 0 - clockwise, 1 - CCW */
|
||||
|
||||
char last_stable;
|
||||
};
|
||||
|
||||
static int rotary_encoder_get_state(struct rotary_encoder_platform_data *pdata)
|
||||
{
|
||||
int a = !!gpio_get_value(pdata->gpio_a);
|
||||
int b = !!gpio_get_value(pdata->gpio_b);
|
||||
|
||||
a ^= pdata->inverted_a;
|
||||
b ^= pdata->inverted_b;
|
||||
|
||||
return ((a << 1) | b);
|
||||
}
|
||||
|
||||
static void rotary_encoder_report_event(struct rotary_encoder *encoder)
|
||||
{
|
||||
struct rotary_encoder_platform_data *pdata = encoder->pdata;
|
||||
|
||||
if (pdata->relative_axis) {
|
||||
input_report_rel(encoder->input,
|
||||
pdata->axis, encoder->dir ? -1 : 1);
|
||||
} else {
|
||||
unsigned int pos = encoder->pos;
|
||||
|
||||
if (encoder->dir) {
|
||||
/* turning counter-clockwise */
|
||||
if (pdata->rollover)
|
||||
pos += pdata->steps;
|
||||
if (pos)
|
||||
pos--;
|
||||
} else {
|
||||
/* turning clockwise */
|
||||
if (pdata->rollover || pos < pdata->steps)
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (pdata->rollover)
|
||||
pos %= pdata->steps;
|
||||
|
||||
encoder->pos = pos;
|
||||
input_report_abs(encoder->input, pdata->axis, encoder->pos);
|
||||
}
|
||||
|
||||
input_sync(encoder->input);
|
||||
}
|
||||
|
||||
static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct rotary_encoder *encoder = dev_id;
|
||||
struct rotary_encoder_platform_data *pdata = encoder->pdata;
|
||||
int a = !!gpio_get_value(pdata->gpio_a);
|
||||
int b = !!gpio_get_value(pdata->gpio_b);
|
||||
int state;
|
||||
|
||||
a ^= pdata->inverted_a;
|
||||
b ^= pdata->inverted_b;
|
||||
state = (a << 1) | b;
|
||||
state = rotary_encoder_get_state(encoder->pdata);
|
||||
|
||||
switch (state) {
|
||||
|
||||
case 0x0:
|
||||
if (!encoder->armed)
|
||||
break;
|
||||
|
||||
if (pdata->relative_axis) {
|
||||
input_report_rel(encoder->input, pdata->axis,
|
||||
encoder->dir ? -1 : 1);
|
||||
} else {
|
||||
unsigned int pos = encoder->pos;
|
||||
|
||||
if (encoder->dir) {
|
||||
/* turning counter-clockwise */
|
||||
if (pdata->rollover)
|
||||
pos += pdata->steps;
|
||||
if (pos)
|
||||
pos--;
|
||||
} else {
|
||||
/* turning clockwise */
|
||||
if (pdata->rollover || pos < pdata->steps)
|
||||
pos++;
|
||||
}
|
||||
if (pdata->rollover)
|
||||
pos %= pdata->steps;
|
||||
encoder->pos = pos;
|
||||
input_report_abs(encoder->input, pdata->axis,
|
||||
encoder->pos);
|
||||
if (encoder->armed) {
|
||||
rotary_encoder_report_event(encoder);
|
||||
encoder->armed = false;
|
||||
}
|
||||
input_sync(encoder->input);
|
||||
|
||||
encoder->armed = false;
|
||||
break;
|
||||
|
||||
case 0x1:
|
||||
@@ -100,11 +115,37 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct rotary_encoder *encoder = dev_id;
|
||||
int state;
|
||||
|
||||
state = rotary_encoder_get_state(encoder->pdata);
|
||||
|
||||
switch (state) {
|
||||
case 0x00:
|
||||
case 0x03:
|
||||
if (state != encoder->last_stable) {
|
||||
rotary_encoder_report_event(encoder);
|
||||
encoder->last_stable = state;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
encoder->dir = (encoder->last_stable + state) & 0x01;
|
||||
break;
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __devinit rotary_encoder_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rotary_encoder_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct rotary_encoder *encoder;
|
||||
struct input_dev *input;
|
||||
irq_handler_t handler;
|
||||
int err;
|
||||
|
||||
if (!pdata) {
|
||||
@@ -175,7 +216,14 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* request the IRQs */
|
||||
err = request_irq(encoder->irq_a, &rotary_encoder_irq,
|
||||
if (pdata->half_period) {
|
||||
handler = &rotary_encoder_half_period_irq;
|
||||
encoder->last_stable = rotary_encoder_get_state(pdata);
|
||||
} else {
|
||||
handler = &rotary_encoder_irq;
|
||||
}
|
||||
|
||||
err = request_irq(encoder->irq_a, handler,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
|
||||
DRV_NAME, encoder);
|
||||
if (err) {
|
||||
@@ -184,7 +232,7 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
|
||||
goto exit_free_gpio_b;
|
||||
}
|
||||
|
||||
err = request_irq(encoder->irq_b, &rotary_encoder_irq,
|
||||
err = request_irq(encoder->irq_b, handler,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
|
||||
DRV_NAME, encoder);
|
||||
if (err) {
|
||||
@@ -252,6 +300,5 @@ module_exit(rotary_encoder_exit);
|
||||
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
||||
MODULE_DESCRIPTION("GPIO rotary encoder driver");
|
||||
MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
|
||||
MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>, Johan Hovold");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ static int __init twl4030_pwrbutton_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
free_irq:
|
||||
free_irq(irq, NULL);
|
||||
free_irq(irq, pwr);
|
||||
free_input_dev:
|
||||
input_free_device(pwr);
|
||||
return err;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user