Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
929343ef
Commit
929343ef
authored
Aug 06, 2010
by
Kukjin Kim
Browse files
Options
Browse Files
Download
Plain Diff
Merge commit '
d01d0756
' into next-samsung
parents
d8653d9f
d01d0756
Changes
55
Hide whitespace changes
Inline
Side-by-side
Showing
55 changed files
with
6496 additions
and
959 deletions
+6496
-959
Documentation/input/multi-touch-protocol.txt
Documentation/input/multi-touch-protocol.txt
+149
-69
arch/arm/plat-samsung/include/plat/keypad.h
arch/arm/plat-samsung/include/plat/keypad.h
+43
-0
drivers/char/keyboard.c
drivers/char/keyboard.c
+5
-1
drivers/hid/hid-core.c
drivers/hid/hid-core.c
+1
-0
drivers/hid/hid-ids.h
drivers/hid/hid-ids.h
+1
-0
drivers/hid/hid-input.c
drivers/hid/hid-input.c
+3
-0
drivers/input/evdev.c
drivers/input/evdev.c
+42
-12
drivers/input/input.c
drivers/input/input.c
+125
-57
drivers/input/joydev.c
drivers/input/joydev.c
+3
-4
drivers/input/joystick/xpad.c
drivers/input/joystick/xpad.c
+64
-44
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Kconfig
+21
-0
drivers/input/keyboard/Makefile
drivers/input/keyboard/Makefile
+2
-0
drivers/input/keyboard/adp5588-keys.c
drivers/input/keyboard/adp5588-keys.c
+342
-9
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/gpio_keys.c
+14
-5
drivers/input/keyboard/lm8323.c
drivers/input/keyboard/lm8323.c
+7
-5
drivers/input/keyboard/matrix_keypad.c
drivers/input/keyboard/matrix_keypad.c
+80
-28
drivers/input/keyboard/mcs_touchkey.c
drivers/input/keyboard/mcs_touchkey.c
+239
-0
drivers/input/keyboard/samsung-keypad.c
drivers/input/keyboard/samsung-keypad.c
+491
-0
drivers/input/misc/Kconfig
drivers/input/misc/Kconfig
+48
-0
drivers/input/misc/Makefile
drivers/input/misc/Makefile
+4
-0
drivers/input/misc/adxl34x-i2c.c
drivers/input/misc/adxl34x-i2c.c
+163
-0
drivers/input/misc/adxl34x-spi.c
drivers/input/misc/adxl34x-spi.c
+145
-0
drivers/input/misc/adxl34x.c
drivers/input/misc/adxl34x.c
+915
-0
drivers/input/misc/adxl34x.h
drivers/input/misc/adxl34x.h
+30
-0
drivers/input/misc/atlas_btns.c
drivers/input/misc/atlas_btns.c
+15
-23
drivers/input/misc/pwm-beeper.c
drivers/input/misc/pwm-beeper.c
+199
-0
drivers/input/misc/twl4030-pwrbutton.c
drivers/input/misc/twl4030-pwrbutton.c
+6
-6
drivers/input/misc/wistron_btns.c
drivers/input/misc/wistron_btns.c
+3
-1
drivers/input/mouse/bcm5974.c
drivers/input/mouse/bcm5974.c
+16
-7
drivers/input/mouse/synaptics.c
drivers/input/mouse/synaptics.c
+6
-2
drivers/input/mousedev.c
drivers/input/mousedev.c
+10
-5
drivers/input/serio/i8042-ppcio.h
drivers/input/serio/i8042-ppcio.h
+0
-75
drivers/input/serio/i8042.c
drivers/input/serio/i8042.c
+41
-24
drivers/input/tablet/wacom_wac.c
drivers/input/tablet/wacom_wac.c
+44
-0
drivers/input/tablet/wacom_wac.h
drivers/input/tablet/wacom_wac.h
+1
-0
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Kconfig
+46
-21
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/Makefile
+5
-1
drivers/input/touchscreen/ad7879-i2c.c
drivers/input/touchscreen/ad7879-i2c.c
+143
-0
drivers/input/touchscreen/ad7879-spi.c
drivers/input/touchscreen/ad7879-spi.c
+198
-0
drivers/input/touchscreen/ad7879.c
drivers/input/touchscreen/ad7879.c
+186
-439
drivers/input/touchscreen/ad7879.h
drivers/input/touchscreen/ad7879.h
+30
-0
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/ads7846.c
+155
-51
drivers/input/touchscreen/cy8ctmg110_ts.c
drivers/input/touchscreen/cy8ctmg110_ts.c
+363
-0
drivers/input/touchscreen/mcs5000_ts.c
drivers/input/touchscreen/mcs5000_ts.c
+3
-3
drivers/input/touchscreen/qt602240_ts.c
drivers/input/touchscreen/qt602240_ts.c
+1401
-0
drivers/input/touchscreen/tps6507x-ts.c
drivers/input/touchscreen/tps6507x-ts.c
+0
-3
drivers/input/touchscreen/usbtouchscreen.c
drivers/input/touchscreen/usbtouchscreen.c
+155
-60
include/linux/i2c/adp5588.h
include/linux/i2c/adp5588.h
+37
-0
include/linux/i2c/mcs.h
include/linux/i2c/mcs.h
+34
-0
include/linux/i2c/qt602240_ts.h
include/linux/i2c/qt602240_ts.h
+38
-0
include/linux/input.h
include/linux/input.h
+57
-3
include/linux/input/adxl34x.h
include/linux/input/adxl34x.h
+349
-0
include/linux/input/cy8ctmg110_pdata.h
include/linux/input/cy8ctmg110_pdata.h
+10
-0
include/linux/input/matrix_keypad.h
include/linux/input/matrix_keypad.h
+6
-0
include/linux/spi/ads7846.h
include/linux/spi/ads7846.h
+2
-1
No files found.
Documentation/input/multi-touch-protocol.txt
View file @
929343ef
...
...
@@ -6,31 +6,149 @@ Multi-touch (MT) Protocol
Introduction
------------
In order to utilize the full power of the new multi-touch devices, a way to
report detailed finger data to user space is needed. This document
describes the multi-touch (MT) protocol which allows kernel drivers to
report details for an arbitrary number of fingers.
In order to utilize the full power of the new multi-touch and multi-user
devices, a way to report detailed data from multiple contacts, i.e.,
objects in direct contact with the device surface, is needed. This
document describes the multi-touch (MT) protocol which allows kernel
drivers to report details for an arbitrary number of contacts.
The protocol is divided into two types, depending on the capabilities of the
hardware. For devices handling anonymous contacts (type A), the protocol
describes how to send the raw data for all contacts to the receiver. For
devices capable of tracking identifiable contacts (type B), the protocol
describes how to send updates for individual contacts via event slots.
Protocol Usage
--------------
Contact details are sent sequentially as separate packets of ABS_MT
events. Only the ABS_MT events are recognized as part of a contact
packet. Since these events are ignored by current single-touch (ST)
applications, the MT protocol can be implemented on top of the ST protocol
in an existing driver.
Drivers for type A devices separate contact packets by calling
input_mt_sync() at the end of each packet. This generates a SYN_MT_REPORT
event, which instructs the receiver to accept the data for the current
contact and prepare to receive another.
Drivers for type B devices separate contact packets by calling
input_mt_slot(), with a slot as argument, at the beginning of each packet.
This generates an ABS_MT_SLOT event, which instructs the receiver to
prepare for updates of the given slot.
All drivers mark the end of a multi-touch transfer by calling the usual
input_sync() function. This instructs the receiver to act upon events
accumulated since last EV_SYN/SYN_REPORT and prepare to receive a new set
of events/packets.
The main difference between the stateless type A protocol and the stateful
type B slot protocol lies in the usage of identifiable contacts to reduce
the amount of data sent to userspace. The slot protocol requires the use of
the ABS_MT_TRACKING_ID, either provided by the hardware or computed from
the raw data [5].
For type A devices, the kernel driver should generate an arbitrary
enumeration of the full set of anonymous contacts currently on the
surface. The order in which the packets appear in the event stream is not
important. Event filtering and finger tracking is left to user space [3].
For type B devices, the kernel driver should associate a slot with each
identified contact, and use that slot to propagate changes for the contact.
Creation, replacement and destruction of contacts is achieved by modifying
the ABS_MT_TRACKING_ID of the associated slot. A non-negative tracking id
is interpreted as a contact, and the value -1 denotes an unused slot. A
tracking id not previously present is considered new, and a tracking id no
longer present is considered removed. Since only changes are propagated,
the full state of each initiated contact has to reside in the receiving
end. Upon receiving an MT event, one simply updates the appropriate
attribute of the current slot.
Protocol Example A
------------------
Here is what a minimal event sequence for a two-contact touch would look
like for a type A device:
ABS_MT_POSITION_X x[0]
ABS_MT_POSITION_Y y[0]
SYN_MT_REPORT
ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_MT_REPORT
SYN_REPORT
The sequence after moving one of the contacts looks exactly the same; the
raw data for all present contacts are sent between every synchronization
with SYN_REPORT.
Usage
-----
Here is the sequence after lifting the first contact:
ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_MT_REPORT
SYN_REPORT
And here is the sequence after lifting the second contact:
SYN_MT_REPORT
SYN_REPORT
If the driver reports one of BTN_TOUCH or ABS_PRESSURE in addition to the
ABS_MT events, the last SYN_MT_REPORT event may be omitted. Otherwise, the
last SYN_REPORT will be dropped by the input core, resulting in no
zero-contact event reaching userland.
Anonymous finger details are sent sequentially as separate packets of ABS
events. Only the ABS_MT events are recognized as part of a finger
packet. The end of a packet is marked by calling the input_mt_sync()
function, which generates a SYN_MT_REPORT event. This instructs the
receiver to accept the data for the current finger and prepare to receive
another. The end of a multi-touch transfer is marked by calling the usual
input_sync() function. This instructs the receiver to act upon events
accumulated since last EV_SYN/SYN_REPORT and prepare to receive a new
set of events/packets.
Protocol Example B
------------------
Here is what a minimal event sequence for a two-contact touch would look
like for a type B device:
ABS_MT_SLOT 0
ABS_MT_TRACKING_ID 45
ABS_MT_POSITION_X x[0]
ABS_MT_POSITION_Y y[0]
ABS_MT_SLOT 1
ABS_MT_TRACKING_ID 46
ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_REPORT
Here is the sequence after moving contact 45 in the x direction:
ABS_MT_SLOT 0
ABS_MT_POSITION_X x[0]
SYN_REPORT
Here is the sequence after lifting the contact in slot 0:
ABS_MT_TRACKING_ID -1
SYN_REPORT
The slot being modified is already 0, so the ABS_MT_SLOT is omitted. The
message removes the association of slot 0 with contact 45, thereby
destroying contact 45 and freeing slot 0 to be reused for another contact.
Finally, here is the sequence after lifting the second contact:
ABS_MT_SLOT 1
ABS_MT_TRACKING_ID -1
SYN_REPORT
Event Usage
-----------
A set of ABS_MT events with the desired properties is defined. The events
are divided into categories, to allow for partial implementation. The
minimum set consists of ABS_MT_POSITION_X and ABS_MT_POSITION_Y, which
allows for multiple
finger
s to be tracked. If the device supports it, the
allows for multiple
contact
s to be tracked. If the device supports it, the
ABS_MT_TOUCH_MAJOR and ABS_MT_WIDTH_MAJOR may be used to provide the size
of the contact area and approaching
finger
, respectively.
of the contact area and approaching
contact
, respectively.
The TOUCH and WIDTH parameters have a geometrical interpretation; imagine
looking through a window at someone gently holding a finger against the
...
...
@@ -41,56 +159,26 @@ ABS_MT_TOUCH_MAJOR, the diameter of the outer region is
ABS_MT_WIDTH_MAJOR. Now imagine the person pressing the finger harder
against the glass. The inner region will increase, and in general, the
ratio ABS_MT_TOUCH_MAJOR / ABS_MT_WIDTH_MAJOR, which is always smaller than
unity, is related to the
finger
pressure. For pressure-based devices,
unity, is related to the
contact
pressure. For pressure-based devices,
ABS_MT_PRESSURE may be used to provide the pressure on the contact area
instead.
In addition to the MAJOR parameters, the oval shape of the
finger
can be
In addition to the MAJOR parameters, the oval shape of the
contact
can be
described by adding the MINOR parameters, such that MAJOR and MINOR are the
major and minor axis of an ellipse. Finally, the orientation of the oval
shape can be describe with the ORIENTATION parameter.
The ABS_MT_TOOL_TYPE may be used to specify whether the touching tool is a
finger
or a pen or something else. Devices with more granular information
contact
or a pen or something else. Devices with more granular information
may specify general shapes as blobs, i.e., as a sequence of rectangular
shapes grouped together by an ABS_MT_BLOB_ID. Finally, for the few devices
that currently support it, the ABS_MT_TRACKING_ID event may be used to
report
finger
tracking from hardware [5].
report
contact
tracking from hardware [5].
Here is what a minimal event sequence for a two-finger touch would look
like:
ABS_MT_POSITION_X
ABS_MT_POSITION_Y
SYN_MT_REPORT
ABS_MT_POSITION_X
ABS_MT_POSITION_Y
SYN_MT_REPORT
SYN_REPORT
Here is the sequence after lifting one of the fingers:
ABS_MT_POSITION_X
ABS_MT_POSITION_Y
SYN_MT_REPORT
SYN_REPORT
And here is the sequence after lifting the remaining finger:
SYN_MT_REPORT
SYN_REPORT
If the driver reports one of BTN_TOUCH or ABS_PRESSURE in addition to the
ABS_MT events, the last SYN_MT_REPORT event may be omitted. Otherwise, the
last SYN_REPORT will be dropped by the input core, resulting in no
zero-finger event reaching userland.
Event Semantics
---------------
The word "contact" is used to describe a tool which is in direct contact
with the surface. A finger, a pen or a rubber all classify as contacts.
ABS_MT_TOUCH_MAJOR
The length of the major axis of the contact. The length should be given in
...
...
@@ -157,15 +245,16 @@ MT_TOOL_PEN [2].
ABS_MT_BLOB_ID
The BLOB_ID groups several packets together into one arbitrarily shaped
contact. This is a low-level anonymous grouping
, and should not be confuse
d
with the high-level trackingID [5]. Most kernel drivers will not have blob
capability, and can safely omit the
event.
contact. This is a low-level anonymous grouping
for type A devices, an
d
should not be confused with the high-level trackingID [5]. Most type A
devices do not have blob capability, so drivers can safely omit this
event.
ABS_MT_TRACKING_ID
The TRACKING_ID identifies an initiated contact throughout its life cycle
[5]. There are currently only a few devices that support it, so this event
should normally be omitted.
[5]. This event is mandatory for type B devices. The value range of the
TRACKING_ID should be large enough to ensure unique identification of a
contact maintained over an extended period of time.
Event Computation
...
...
@@ -192,20 +281,11 @@ finger along the X axis (1).
Finger Tracking
---------------
The kernel driver should generate an arbitrary enumeration of the set of
anonymous contacts currently on the surface. The order in which the packets
appear in the event stream is not important.
The process of finger tracking, i.e., to assign a unique trackingID to each
initiated contact on the surface, is left to user space; preferably the
multi-touch X driver [3]. In that driver, the trackingID stays the same and
unique until the contact vanishes (when the finger leaves the surface). The
problem of assigning a set of anonymous fingers to a set of identified
fingers is a euclidian bipartite matching problem at each event update, and
relies on a sufficiently rapid update rate.
There are a few devices that support trackingID in hardware. User space can
make use of these native identifiers to reduce bandwidth and cpu usage.
initiated contact on the surface, is a Euclidian Bipartite Matching
problem. At each event synchronization, the set of actual contacts is
matched to the set of contacts from the previous synchronization. A full
implementation can be found in [3].
Gestures
...
...
arch/arm/plat-samsung/include/plat/keypad.h
0 → 100644
View file @
929343ef
/*
* Samsung Platform - Keypad platform data definitions
*
* Copyright (C) 2010 Samsung Electronics Co.Ltd
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef __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
);
};
#endif
/* __PLAT_SAMSUNG_KEYPAD_H */
drivers/char/keyboard.c
View file @
929343ef
...
...
@@ -1315,10 +1315,14 @@ static bool kbd_match(struct input_handler *handler, struct input_dev *dev)
if
(
test_bit
(
EV_SND
,
dev
->
evbit
))
return
true
;
if
(
test_bit
(
EV_KEY
,
dev
->
evbit
))
if
(
test_bit
(
EV_KEY
,
dev
->
evbit
))
{
for
(
i
=
KEY_RESERVED
;
i
<
BTN_MISC
;
i
++
)
if
(
test_bit
(
i
,
dev
->
keybit
))
return
true
;
for
(
i
=
KEY_BRL_DOT1
;
i
<=
KEY_BRL_DOT10
;
i
++
)
if
(
test_bit
(
i
,
dev
->
keybit
))
return
true
;
}
return
false
;
}
...
...
drivers/hid/hid-core.c
View file @
929343ef
...
...
@@ -1586,6 +1586,7 @@ static const struct hid_device_id hid_ignore_list[] = {
{
HID_USB_DEVICE
(
USB_VENDOR_ID_DELORME
,
USB_DEVICE_ID_DELORME_EM_LT20
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_ESSENTIAL_REALITY
,
USB_DEVICE_ID_ESSENTIAL_REALITY_P5
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_ETT
,
USB_DEVICE_ID_TC5UH
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_ETT
,
USB_DEVICE_ID_TC4UM
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_GENERAL_TOUCH
,
0x0001
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_GENERAL_TOUCH
,
0x0002
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_GENERAL_TOUCH
,
0x0003
)
},
...
...
drivers/hid/hid-ids.h
View file @
929343ef
...
...
@@ -198,6 +198,7 @@
#define USB_VENDOR_ID_ETT 0x0664
#define USB_DEVICE_ID_TC5UH 0x0309
#define USB_DEVICE_ID_TC4UM 0x0306
#define USB_VENDOR_ID_EZKEY 0x0518
#define USB_DEVICE_ID_BTC_8193 0x0002
...
...
drivers/hid/hid-input.c
View file @
929343ef
...
...
@@ -534,6 +534,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
input_set_abs_params
(
input
,
usage
->
code
,
a
,
b
,
(
b
-
a
)
>>
8
,
(
b
-
a
)
>>
4
);
else
input_set_abs_params
(
input
,
usage
->
code
,
a
,
b
,
0
,
0
);
/* use a larger default input buffer for MT devices */
if
(
usage
->
code
==
ABS_MT_POSITION_X
&&
input
->
hint_events_per_packet
==
0
)
input_set_events_per_packet
(
input
,
60
);
}
if
(
usage
->
type
==
EV_ABS
&&
...
...
drivers/input/evdev.c
View file @
929343ef
...
...
@@ -10,7 +10,8 @@
#define EVDEV_MINOR_BASE 64
#define EVDEV_MINORS 32
#define EVDEV_BUFFER_SIZE 64
#define EVDEV_MIN_BUFFER_SIZE 64U
#define EVDEV_BUF_PACKETS 8
#include <linux/poll.h>
#include <linux/sched.h>
...
...
@@ -23,7 +24,6 @@
#include "input-compat.h"
struct
evdev
{
int
exist
;
int
open
;
int
minor
;
struct
input_handle
handle
;
...
...
@@ -33,16 +33,18 @@ struct evdev {
spinlock_t
client_lock
;
/* protects client_list */
struct
mutex
mutex
;
struct
device
dev
;
bool
exist
;
};
struct
evdev_client
{
struct
input_event
buffer
[
EVDEV_BUFFER_SIZE
];
int
head
;
int
tail
;
spinlock_t
buffer_lock
;
/* protects access to buffer, head and tail */
struct
fasync_struct
*
fasync
;
struct
evdev
*
evdev
;
struct
list_head
node
;
int
bufsize
;
struct
input_event
buffer
[];
};
static
struct
evdev
*
evdev_table
[
EVDEV_MINORS
];
...
...
@@ -52,11 +54,15 @@ static void evdev_pass_event(struct evdev_client *client,
struct
input_event
*
event
)
{
/*
* Interrupts are disabled, just acquire the lock
* Interrupts are disabled, just acquire the lock.
* Make sure we don't leave with the client buffer
* "empty" by having client->head == client->tail.
*/
spin_lock
(
&
client
->
buffer_lock
);
client
->
buffer
[
client
->
head
++
]
=
*
event
;
client
->
head
&=
EVDEV_BUFFER_SIZE
-
1
;
do
{
client
->
buffer
[
client
->
head
++
]
=
*
event
;
client
->
head
&=
client
->
bufsize
-
1
;
}
while
(
client
->
head
==
client
->
tail
);
spin_unlock
(
&
client
->
buffer_lock
);
if
(
event
->
type
==
EV_SYN
)
...
...
@@ -242,11 +248,21 @@ static int evdev_release(struct inode *inode, struct file *file)
return
0
;
}
static
unsigned
int
evdev_compute_buffer_size
(
struct
input_dev
*
dev
)
{
unsigned
int
n_events
=
max
(
dev
->
hint_events_per_packet
*
EVDEV_BUF_PACKETS
,
EVDEV_MIN_BUFFER_SIZE
);
return
roundup_pow_of_two
(
n_events
);
}
static
int
evdev_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
struct
evdev
*
evdev
;
struct
evdev_client
*
client
;
int
i
=
iminor
(
inode
)
-
EVDEV_MINOR_BASE
;
unsigned
int
bufsize
;
int
error
;
if
(
i
>=
EVDEV_MINORS
)
...
...
@@ -263,12 +279,17 @@ static int evdev_open(struct inode *inode, struct file *file)
if
(
!
evdev
)
return
-
ENODEV
;
client
=
kzalloc
(
sizeof
(
struct
evdev_client
),
GFP_KERNEL
);
bufsize
=
evdev_compute_buffer_size
(
evdev
->
handle
.
dev
);
client
=
kzalloc
(
sizeof
(
struct
evdev_client
)
+
bufsize
*
sizeof
(
struct
input_event
),
GFP_KERNEL
);
if
(
!
client
)
{
error
=
-
ENOMEM
;
goto
err_put_evdev
;
}
client
->
bufsize
=
bufsize
;
spin_lock_init
(
&
client
->
buffer_lock
);
client
->
evdev
=
evdev
;
evdev_attach_client
(
evdev
,
client
);
...
...
@@ -334,7 +355,7 @@ static int evdev_fetch_next_event(struct evdev_client *client,
have_event
=
client
->
head
!=
client
->
tail
;
if
(
have_event
)
{
*
event
=
client
->
buffer
[
client
->
tail
++
];
client
->
tail
&=
EVDEV_BUFFER_SIZE
-
1
;
client
->
tail
&=
client
->
bufsize
-
1
;
}
spin_unlock_irq
(
&
client
->
buffer_lock
);
...
...
@@ -382,10 +403,15 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
{
struct
evdev_client
*
client
=
file
->
private_data
;
struct
evdev
*
evdev
=
client
->
evdev
;
unsigned
int
mask
;
poll_wait
(
file
,
&
evdev
->
wait
,
wait
);
return
((
client
->
head
==
client
->
tail
)
?
0
:
(
POLLIN
|
POLLRDNORM
))
|
(
evdev
->
exist
?
0
:
(
POLLHUP
|
POLLERR
));
mask
=
evdev
->
exist
?
POLLOUT
|
POLLWRNORM
:
POLLHUP
|
POLLERR
;
if
(
client
->
head
!=
client
->
tail
)
mask
|=
POLLIN
|
POLLRDNORM
;
return
mask
;
}
#ifdef CONFIG_COMPAT
...
...
@@ -665,6 +691,10 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
sizeof
(
struct
input_absinfo
))))
return
-
EFAULT
;
/* We can't change number of reserved MT slots */
if
(
t
==
ABS_MT_SLOT
)
return
-
EINVAL
;
/*
* Take event lock to ensure that we are not
* changing device parameters in the middle
...
...
@@ -768,7 +798,7 @@ static void evdev_remove_chrdev(struct evdev *evdev)
static
void
evdev_mark_dead
(
struct
evdev
*
evdev
)
{
mutex_lock
(
&
evdev
->
mutex
);
evdev
->
exist
=
0
;
evdev
->
exist
=
false
;
mutex_unlock
(
&
evdev
->
mutex
);
}
...
...
@@ -817,7 +847,7 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
init_waitqueue_head
(
&
evdev
->
wait
);
dev_set_name
(
&
evdev
->
dev
,
"event%d"
,
minor
);
evdev
->
exist
=
1
;
evdev
->
exist
=
true
;
evdev
->
minor
=
minor
;
evdev
->
handle
.
dev
=
input_get_device
(
dev
);
...
...
drivers/input/input.c
View file @
929343ef
...
...
@@ -33,25 +33,6 @@ MODULE_LICENSE("GPL");
#define INPUT_DEVICES 256
/*
* EV_ABS events which should not be cached are listed here.
*/
static
unsigned
int
input_abs_bypass_init_data
[]
__initdata
=
{
ABS_MT_TOUCH_MAJOR
,
ABS_MT_TOUCH_MINOR
,
ABS_MT_WIDTH_MAJOR
,
ABS_MT_WIDTH_MINOR
,
ABS_MT_ORIENTATION
,
ABS_MT_POSITION_X
,
ABS_MT_POSITION_Y
,
ABS_MT_TOOL_TYPE
,
ABS_MT_BLOB_ID
,
ABS_MT_TRACKING_ID
,
ABS_MT_PRESSURE
,
0
};
static
unsigned
long
input_abs_bypass
[
BITS_TO_LONGS
(
ABS_CNT
)];
static
LIST_HEAD
(
input_dev_list
);
static
LIST_HEAD
(
input_handler_list
);
...
...
@@ -181,6 +162,56 @@ static void input_stop_autorepeat(struct input_dev *dev)
#define INPUT_PASS_TO_DEVICE 2
#define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
static
int
input_handle_abs_event
(
struct
input_dev
*
dev
,
unsigned
int
code
,
int
*
pval
)
{
bool
is_mt_event
;
int
*
pold
;
if
(
code
==
ABS_MT_SLOT
)
{
/*
* "Stage" the event; we'll flush it later, when we
* get actiual touch data.
*/
if
(
*
pval
>=
0
&&
*
pval
<
dev
->
mtsize
)
dev
->
slot
=
*
pval
;
return
INPUT_IGNORE_EVENT
;
}
is_mt_event
=
code
>=
ABS_MT_FIRST
&&
code
<=
ABS_MT_LAST
;
if
(
!
is_mt_event
)
{
pold
=
&
dev
->
abs
[
code
];
}
else
if
(
dev
->
mt
)
{
struct
input_mt_slot
*
mtslot
=
&
dev
->
mt
[
dev
->
slot
];
pold
=
&
mtslot
->
abs
[
code
-
ABS_MT_FIRST
];
}
else
{
/*
* Bypass filtering for multitouch events when
* not employing slots.
*/
pold
=
NULL
;
}
if
(
pold
)
{
*
pval
=
input_defuzz_abs_event
(
*
pval
,
*
pold
,
dev
->
absfuzz
[
code
]);
if
(
*
pold
==
*
pval
)
return
INPUT_IGNORE_EVENT
;
*
pold
=
*
pval
;
}
/* Flush pending "slot" event */
if
(
is_mt_event
&&
dev
->
slot
!=
dev
->
abs
[
ABS_MT_SLOT
])
{
dev
->
abs
[
ABS_MT_SLOT
]
=
dev
->
slot
;
input_pass_event
(
dev
,
EV_ABS
,
ABS_MT_SLOT
,
dev
->
slot
);
}
return
INPUT_PASS_TO_HANDLERS
;
}
static
void
input_handle_event
(
struct
input_dev
*
dev
,
unsigned
int
type
,
unsigned
int
code
,
int
value
)
{
...
...
@@ -196,12 +227,12 @@ static void input_handle_event(struct input_dev *dev,
case
SYN_REPORT
:
if
(
!
dev
->
sync
)
{
dev
->
sync
=
1
;
dev
->
sync
=
true
;
disposition
=
INPUT_PASS_TO_HANDLERS
;
}
break
;
case
SYN_MT_REPORT
:
dev
->
sync
=
0
;
dev
->
sync
=
false
;
disposition
=
INPUT_PASS_TO_HANDLERS
;
break
;
}
...
...
@@ -233,21 +264,9 @@ static void input_handle_event(struct input_dev *dev,
break
;
case
EV_ABS
:
if
(
is_event_supported
(
code
,
dev
->
absbit
,
ABS_MAX
))
{
if
(
test_bit
(
code
,
input_abs_bypass
))
{
disposition
=
INPUT_PASS_TO_HANDLERS
;
break
;
}
if
(
is_event_supported
(
code
,
dev
->
absbit
,
ABS_MAX
))
disposition
=
input_handle_abs_event
(
dev
,
code
,
&
value
);
value
=
input_defuzz_abs_event
(
value
,
dev
->
abs
[
code
],
dev
->
absfuzz
[
code
]);
if
(
dev
->
abs
[
code
]
!=
value
)
{
dev
->
abs
[
code
]
=
value
;
disposition
=
INPUT_PASS_TO_HANDLERS
;
}
}
break
;
case
EV_REL
:
...
...
@@ -298,7 +317,7 @@ static void input_handle_event(struct input_dev *dev,
}
if
(
disposition
!=
INPUT_IGNORE_EVENT
&&
type
!=
EV_SYN
)
dev
->
sync
=
0
;
dev
->
sync
=
false
;
if
((
disposition
&
INPUT_PASS_TO_DEVICE
)
&&
dev
->
event
)
dev
->
event
(
dev
,
type
,
code
,
value
);
...
...
@@ -527,13 +546,31 @@ void input_close_device(struct input_handle *handle)
}
EXPORT_SYMBOL
(
input_close_device
);
/*
* Simulate keyup events for all keys that are marked as pressed.
* The function must be called with dev->event_lock held.
*/
static
void
input_dev_release_keys
(
struct
input_dev
*
dev
)
{
int
code
;
if
(
is_event_supported
(
EV_KEY
,
dev
->
evbit
,
EV_MAX
))
{
for
(
code
=
0
;
code
<=
KEY_MAX
;
code
++
)
{
if
(
is_event_supported
(
code
,
dev
->
keybit
,
KEY_MAX
)
&&
__test_and_clear_bit
(
code
,
dev
->
key
))
{
input_pass_event
(
dev
,
EV_KEY
,
code
,
0
);
}
}
input_pass_event
(
dev
,
EV_SYN
,
SYN_REPORT
,
1
);
}
}
/*
* Prepare device for unregistering
*/
static
void
input_disconnect_device
(
struct
input_dev
*
dev
)
{
struct
input_handle
*
handle
;
int
code
;
/*
* Mark device as going away. Note that we take dev->mutex here
...
...
@@ -552,15 +589,7 @@ static void input_disconnect_device(struct input_dev *dev)
* generate events even after we done here but they will not
* reach any handlers.
*/
if
(
is_event_supported
(
EV_KEY
,
dev
->
evbit
,
EV_MAX
))
{
for
(
code
=
0
;
code
<=
KEY_MAX
;
code
++
)
{
if
(
is_event_supported
(
code
,
dev
->
keybit
,
KEY_MAX
)
&&
__test_and_clear_bit
(
code
,
dev
->
key
))
{
input_pass_event
(
dev
,
EV_KEY
,
code
,
0
);
}
}
input_pass_event
(
dev
,
EV_SYN
,
SYN_REPORT
,
1
);
}
input_dev_release_keys
(
dev
);
list_for_each_entry
(
handle
,
&
dev
->
h_list
,
d_node
)
handle
->
open
=
0
;
...
...
@@ -684,7 +713,7 @@ int input_set_keycode(struct input_dev *dev,
unsigned
int
scancode
,
unsigned
int
keycode
)
{
unsigned
long
flags
;
int
old_keycode
;
unsigned
int
old_keycode
;
int
retval
;
if
(
keycode
>
KEY_MAX
)
...
...
@@ -1278,6 +1307,7 @@ static void input_dev_release(struct device *device)
struct
input_dev
*
dev
=
to_input_dev
(
device
);
input_ff_destroy
(
dev
);
input_mt_destroy_slots
(
dev
);
kfree
(
dev
);
module_put
(
THIS_MODULE
);
...
...
@@ -1433,6 +1463,15 @@ static int input_dev_resume(struct device *dev)
mutex_lock
(
&
input_dev
->
mutex
);
input_dev_reset
(
input_dev
,
true
);
/*
* Keys that have been pressed at suspend time are unlikely
* to be still pressed when we resume.
*/
spin_lock_irq
(
&
input_dev
->
event_lock
);
input_dev_release_keys
(
input_dev
);
spin_unlock_irq
(
&
input_dev
->
event_lock
);
mutex_unlock
(
&
input_dev
->
mutex
);
return
0
;
...
...
@@ -1517,6 +1556,45 @@ void input_free_device(struct input_dev *dev)
}
EXPORT_SYMBOL
(
input_free_device
);
/**
* input_mt_create_slots() - create MT input slots
* @dev: input device supporting MT events and finger tracking
* @num_slots: number of slots used by the device
*
* This function allocates all necessary memory for MT slot handling
* in the input device, and adds ABS_MT_SLOT to the device capabilities.
*/
int
input_mt_create_slots
(
struct
input_dev
*
dev
,
unsigned
int
num_slots
)
{
if
(
!
num_slots
)
return
0
;
dev
->
mt
=
kcalloc
(
num_slots
,
sizeof
(
struct
input_mt_slot
),
GFP_KERNEL
);
if
(
!
dev
->
mt
)
return
-
ENOMEM
;
dev
->
mtsize
=
num_slots
;
input_set_abs_params
(
dev
,
ABS_MT_SLOT
,
0
,
num_slots
-
1
,
0
,
0
);
return
0
;
}
EXPORT_SYMBOL
(
input_mt_create_slots
);
/**
* input_mt_destroy_slots() - frees the MT slots of the input device
* @dev: input device with allocated MT slots
*
* This function is only needed in error path as the input core will
* automatically free the MT slots when the device is destroyed.
*/
void
input_mt_destroy_slots
(
struct
input_dev
*
dev
)
{
kfree
(
dev
->
mt
);
dev
->
mt
=
NULL
;
dev
->
mtsize
=
0
;
}
EXPORT_SYMBOL
(
input_mt_destroy_slots
);
/**
* input_set_capability - mark device as capable of a certain event
* @dev: device that is capable of emitting or accepting event
...
...
@@ -1926,20 +2004,10 @@ static const struct file_operations input_fops = {
.
open
=
input_open_file
,
};
static
void
__init
input_init_abs_bypass
(
void
)
{
const
unsigned
int
*
p
;
for
(
p
=
input_abs_bypass_init_data
;
*
p
;
p
++
)
input_abs_bypass
[
BIT_WORD
(
*
p
)]
|=
BIT_MASK
(
*
p
);
}
static
int
__init
input_init
(
void
)
{
int
err
;
input_init_abs_bypass
();
err
=
class_register
(
&
input_class
);
if
(
err
)
{
printk
(
KERN_ERR
"input: unable to register input_dev class
\n
"
);
...
...
drivers/input/joydev.c
View file @
929343ef
...
...
@@ -37,7 +37,6 @@ MODULE_LICENSE("GPL");
#define JOYDEV_BUFFER_SIZE 64
struct
joydev
{
int
exist
;
int
open
;
int
minor
;
struct
input_handle
handle
;
...
...
@@ -46,6 +45,7 @@ struct joydev {
spinlock_t
client_lock
;
/* protects client_list */
struct
mutex
mutex
;
struct
device
dev
;
bool
exist
;
struct
js_corr
corr
[
ABS_CNT
];
struct
JS_DATA_SAVE_TYPE
glue
;
...
...
@@ -760,7 +760,7 @@ static void joydev_remove_chrdev(struct joydev *joydev)
static
void
joydev_mark_dead
(
struct
joydev
*
joydev
)
{
mutex_lock
(
&
joydev
->
mutex
);
joydev
->
exist
=
0
;
joydev
->
exist
=
false
;
mutex_unlock
(
&
joydev
->
mutex
);
}
...
...
@@ -817,10 +817,9 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
init_waitqueue_head
(
&
joydev
->
wait
);
dev_set_name
(
&
joydev
->
dev
,
"js%d"
,
minor
);
joydev
->
exist
=
1
;
joydev
->
exist
=
true
;
joydev
->
minor
=
minor
;
joydev
->
exist
=
1
;
joydev
->
handle
.
dev
=
input_get_device
(
dev
);
joydev
->
handle
.
name
=
dev_name
(
&
joydev
->
dev
);
joydev
->
handle
.
handler
=
handler
;
...
...
drivers/input/joystick/xpad.c
View file @
929343ef
...
...
@@ -9,6 +9,7 @@
* 2005 Dominic Cerquetti <binary1230@yahoo.com>
* 2006 Adam Buchbinder <adam.buchbinder@gmail.com>
* 2007 Jan Kratochvil <honza@jikos.cz>
* 2010 Christoph Fritz <chf.fritz@googlemail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
...
...
@@ -88,6 +89,9 @@
but we map them to axes when possible to simplify things */
#define MAP_DPAD_TO_BUTTONS (1 << 0)
#define MAP_TRIGGERS_TO_BUTTONS (1 << 1)
#define MAP_STICKS_TO_NULL (1 << 2)
#define DANCEPAD_MAP_CONFIG (MAP_DPAD_TO_BUTTONS | \
MAP_TRIGGERS_TO_BUTTONS | MAP_STICKS_TO_NULL)
#define XTYPE_XBOX 0
#define XTYPE_XBOX360 1
...
...
@@ -102,6 +106,10 @@ static int triggers_to_buttons;
module_param
(
triggers_to_buttons
,
bool
,
S_IRUGO
);
MODULE_PARM_DESC
(
triggers_to_buttons
,
"Map triggers to buttons rather than axes for unknown pads"
);
static
int
sticks_to_null
;
module_param
(
sticks_to_null
,
bool
,
S_IRUGO
);
MODULE_PARM_DESC
(
sticks_to_null
,
"Do not map sticks at all for unknown pads"
);
static
const
struct
xpad_device
{
u16
idVendor
;
u16
idProduct
;
...
...
@@ -114,7 +122,7 @@ static const struct xpad_device {
{
0x045e
,
0x0285
,
"Microsoft X-Box pad (Japan)"
,
0
,
XTYPE_XBOX
},
{
0x045e
,
0x0287
,
"Microsoft Xbox Controller S"
,
0
,
XTYPE_XBOX
},
{
0x045e
,
0x0719
,
"Xbox 360 Wireless Receiver"
,
MAP_DPAD_TO_BUTTONS
,
XTYPE_XBOX360W
},
{
0x0c12
,
0x8809
,
"RedOctane Xbox Dance Pad"
,
MAP_DPAD_TO_BUTTONS
,
XTYPE_XBOX
},
{
0x0c12
,
0x8809
,
"RedOctane Xbox Dance Pad"
,
DANCEPAD_MAP_CONFIG
,
XTYPE_XBOX
},
{
0x044f
,
0x0f07
,
"Thrustmaster, Inc. Controller"
,
0
,
XTYPE_XBOX
},
{
0x046d
,
0xc242
,
"Logitech Chillstream Controller"
,
0
,
XTYPE_XBOX360
},
{
0x046d
,
0xca84
,
"Logitech Xbox Cordless Controller"
,
0
,
XTYPE_XBOX
},
...
...
@@ -151,6 +159,7 @@ static const struct xpad_device {
{
0x045e
,
0x028e
,
"Microsoft X-Box 360 pad"
,
0
,
XTYPE_XBOX360
},
{
0x1bad
,
0x0003
,
"Harmonix Rock Band Drumkit"
,
MAP_DPAD_TO_BUTTONS
,
XTYPE_XBOX360
},
{
0x0f0d
,
0x0016
,
"Hori Real Arcade Pro.EX"
,
MAP_TRIGGERS_TO_BUTTONS
,
XTYPE_XBOX360
},
{
0x0f0d
,
0x000d
,
"Hori Fighting Stick EX2"
,
MAP_TRIGGERS_TO_BUTTONS
,
XTYPE_XBOX360
},
{
0xffff
,
0xffff
,
"Chinese-made Xbox Controller"
,
0
,
XTYPE_XBOX
},
{
0x0000
,
0x0000
,
"Generic X-Box pad"
,
0
,
XTYPE_UNKNOWN
}
};
...
...
@@ -158,7 +167,7 @@ static const struct xpad_device {
/* buttons shared with xbox and xbox360 */
static
const
signed
short
xpad_common_btn
[]
=
{
BTN_A
,
BTN_B
,
BTN_X
,
BTN_Y
,
/* "analog" buttons */
BTN_START
,
BTN_
BACK
,
BTN_THUMBL
,
BTN_THUMBR
,
/* start/back/sticks */
BTN_START
,
BTN_
SELECT
,
BTN_THUMBL
,
BTN_THUMBR
,
/* start/back/sticks */
-
1
/* terminating entry */
};
...
...
@@ -168,10 +177,10 @@ static const signed short xpad_btn[] = {
-
1
/* terminating entry */
};
/* used when dpad is mapped to
n
uttons */
/* used when dpad is mapped to
b
uttons */
static
const
signed
short
xpad_btn_pad
[]
=
{
BTN_
LEFT
,
BTN_RIGHT
,
/* d-pad left, right */
BTN_
0
,
BTN_1
,
/* d-pad up, down (XXX names??)
*/
BTN_
TRIGGER_HAPPY1
,
BTN_TRIGGER_HAPPY2
,
/* d-pad left, right */
BTN_
TRIGGER_HAPPY3
,
BTN_TRIGGER_HAPPY4
,
/* d-pad up, down
*/
-
1
/* terminating entry */
};
...
...
@@ -279,17 +288,19 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
{
struct
input_dev
*
dev
=
xpad
->
dev
;
/* left stick */
input_report_abs
(
dev
,
ABS_X
,
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
12
)));
input_report_abs
(
dev
,
ABS_Y
,
~
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
14
)));
/* right stick */
input_report_abs
(
dev
,
ABS_RX
,
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
16
)));
input_report_abs
(
dev
,
ABS_RY
,
~
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
18
)));
if
(
!
(
xpad
->
mapping
&
MAP_STICKS_TO_NULL
))
{
/* left stick */
input_report_abs
(
dev
,
ABS_X
,
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
12
)));
input_report_abs
(
dev
,
ABS_Y
,
~
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
14
)));
/* right stick */
input_report_abs
(
dev
,
ABS_RX
,
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
16
)));
input_report_abs
(
dev
,
ABS_RY
,
~
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
18
)));
}
/* triggers left/right */
if
(
xpad
->
mapping
&
MAP_TRIGGERS_TO_BUTTONS
)
{
...
...
@@ -302,10 +313,11 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
/* digital pad */
if
(
xpad
->
mapping
&
MAP_DPAD_TO_BUTTONS
)
{
input_report_key
(
dev
,
BTN_LEFT
,
data
[
2
]
&
0x04
);
input_report_key
(
dev
,
BTN_RIGHT
,
data
[
2
]
&
0x08
);
input_report_key
(
dev
,
BTN_0
,
data
[
2
]
&
0x01
);
/* up */
input_report_key
(
dev
,
BTN_1
,
data
[
2
]
&
0x02
);
/* down */
/* dpad as buttons (left, right, up, down) */
input_report_key
(
dev
,
BTN_TRIGGER_HAPPY1
,
data
[
2
]
&
0x04
);
input_report_key
(
dev
,
BTN_TRIGGER_HAPPY2
,
data
[
2
]
&
0x08
);
input_report_key
(
dev
,
BTN_TRIGGER_HAPPY3
,
data
[
2
]
&
0x01
);
input_report_key
(
dev
,
BTN_TRIGGER_HAPPY4
,
data
[
2
]
&
0x02
);
}
else
{
input_report_abs
(
dev
,
ABS_HAT0X
,
!!
(
data
[
2
]
&
0x08
)
-
!!
(
data
[
2
]
&
0x04
));
...
...
@@ -315,7 +327,7 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
/* start/back buttons and stick press left/right */
input_report_key
(
dev
,
BTN_START
,
data
[
2
]
&
0x10
);
input_report_key
(
dev
,
BTN_
BACK
,
data
[
2
]
&
0x20
);
input_report_key
(
dev
,
BTN_
SELECT
,
data
[
2
]
&
0x20
);
input_report_key
(
dev
,
BTN_THUMBL
,
data
[
2
]
&
0x40
);
input_report_key
(
dev
,
BTN_THUMBR
,
data
[
2
]
&
0x80
);
...
...
@@ -349,11 +361,11 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
/* digital pad */
if
(
xpad
->
mapping
&
MAP_DPAD_TO_BUTTONS
)
{
/* dpad as buttons (
right, left, down, up
) */
input_report_key
(
dev
,
BTN_
LEFT
,
data
[
2
]
&
0x04
);
input_report_key
(
dev
,
BTN_
RIGHT
,
data
[
2
]
&
0x08
);
input_report_key
(
dev
,
BTN_
0
,
data
[
2
]
&
0x01
);
/* up */
input_report_key
(
dev
,
BTN_
1
,
data
[
2
]
&
0x02
);
/* down */
/* dpad as buttons (
left, right, up, down
) */
input_report_key
(
dev
,
BTN_
TRIGGER_HAPPY1
,
data
[
2
]
&
0x04
);
input_report_key
(
dev
,
BTN_
TRIGGER_HAPPY2
,
data
[
2
]
&
0x08
);
input_report_key
(
dev
,
BTN_
TRIGGER_HAPPY3
,
data
[
2
]
&
0x01
);
input_report_key
(
dev
,
BTN_
TRIGGER_HAPPY4
,
data
[
2
]
&
0x02
);
}
else
{
input_report_abs
(
dev
,
ABS_HAT0X
,
!!
(
data
[
2
]
&
0x08
)
-
!!
(
data
[
2
]
&
0x04
));
...
...
@@ -363,7 +375,7 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
/* start/back buttons */
input_report_key
(
dev
,
BTN_START
,
data
[
2
]
&
0x10
);
input_report_key
(
dev
,
BTN_
BACK
,
data
[
2
]
&
0x20
);
input_report_key
(
dev
,
BTN_
SELECT
,
data
[
2
]
&
0x20
);
/* stick press left/right */
input_report_key
(
dev
,
BTN_THUMBL
,
data
[
2
]
&
0x40
);
...
...
@@ -378,17 +390,19 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
input_report_key
(
dev
,
BTN_TR
,
data
[
3
]
&
0x02
);
input_report_key
(
dev
,
BTN_MODE
,
data
[
3
]
&
0x04
);
/* left stick */
input_report_abs
(
dev
,
ABS_X
,
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
6
)));
input_report_abs
(
dev
,
ABS_Y
,
~
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
8
)));
/* right stick */
input_report_abs
(
dev
,
ABS_RX
,
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
10
)));
input_report_abs
(
dev
,
ABS_RY
,
~
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
12
)));
if
(
!
(
xpad
->
mapping
&
MAP_STICKS_TO_NULL
))
{
/* left stick */
input_report_abs
(
dev
,
ABS_X
,
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
6
)));
input_report_abs
(
dev
,
ABS_Y
,
~
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
8
)));
/* right stick */
input_report_abs
(
dev
,
ABS_RX
,
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
10
)));
input_report_abs
(
dev
,
ABS_RY
,
~
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
12
)));
}
/* triggers left/right */
if
(
xpad
->
mapping
&
MAP_TRIGGERS_TO_BUTTONS
)
{
...
...
@@ -814,6 +828,8 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
xpad
->
mapping
|=
MAP_DPAD_TO_BUTTONS
;
if
(
triggers_to_buttons
)
xpad
->
mapping
|=
MAP_TRIGGERS_TO_BUTTONS
;
if
(
sticks_to_null
)
xpad
->
mapping
|=
MAP_STICKS_TO_NULL
;
}
xpad
->
dev
=
input_dev
;
...
...
@@ -830,16 +846,20 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
input_dev
->
open
=
xpad_open
;
input_dev
->
close
=
xpad_close
;
input_dev
->
evbit
[
0
]
=
BIT_MASK
(
EV_KEY
)
|
BIT_MASK
(
EV_ABS
);
input_dev
->
evbit
[
0
]
=
BIT_MASK
(
EV_KEY
);
if
(
!
(
xpad
->
mapping
&
MAP_STICKS_TO_NULL
))
{
input_dev
->
evbit
[
0
]
|=
BIT_MASK
(
EV_ABS
);
/* set up axes */
for
(
i
=
0
;
xpad_abs
[
i
]
>=
0
;
i
++
)
xpad_set_up_abs
(
input_dev
,
xpad_abs
[
i
]);
}
/* set up standard buttons
and axes
*/
/* set up standard buttons */
for
(
i
=
0
;
xpad_common_btn
[
i
]
>=
0
;
i
++
)
__set_bit
(
xpad_common_btn
[
i
],
input_dev
->
keybit
);
for
(
i
=
0
;
xpad_abs
[
i
]
>=
0
;
i
++
)
xpad_set_up_abs
(
input_dev
,
xpad_abs
[
i
]);
/* Now set up model-specific ones */
/* set up model-specific ones */
if
(
xpad
->
xtype
==
XTYPE_XBOX360
||
xpad
->
xtype
==
XTYPE_XBOX360W
)
{
for
(
i
=
0
;
xpad360_btn
[
i
]
>=
0
;
i
++
)
__set_bit
(
xpad360_btn
[
i
],
input_dev
->
keybit
);
...
...
drivers/input/keyboard/Kconfig
View file @
929343ef
...
...
@@ -297,6 +297,18 @@ config KEYBOARD_MAX7359
To compile this driver as a module, choose M here: the
module will be called max7359_keypad.
config KEYBOARD_MCS
tristate "MELFAS MCS Touchkey"
depends on I2C
help
Say Y here if you have the MELFAS MCS5000/5080 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 mcs_touchkey.
config KEYBOARD_IMX
tristate "IMX keypad support"
depends on ARCH_MXC
...
...
@@ -342,6 +354,15 @@ config KEYBOARD_PXA930_ROTARY
To compile this driver as a module, choose M here: the
module will be called pxa930_rotary.
config KEYBOARD_SAMSUNG
tristate "Samsung keypad support"
depends on SAMSUNG_DEV_KEYPAD
help
Say Y here if you want to use the Samsung keypad.
To compile this driver as a module, choose M here: the
module will be called samsung-keypad.
config KEYBOARD_STOWAWAY
tristate "Stowaway keyboard"
select SERIO
...
...
drivers/input/keyboard/Makefile
View file @
929343ef
...
...
@@ -26,12 +26,14 @@ obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o
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_NEWTON)
+=
newtonkbd.o
obj-$(CONFIG_KEYBOARD_OMAP)
+=
omap-keypad.o
obj-$(CONFIG_KEYBOARD_OPENCORES)
+=
opencores-kbd.o
obj-$(CONFIG_KEYBOARD_PXA27x)
+=
pxa27x_keypad.o
obj-$(CONFIG_KEYBOARD_PXA930_ROTARY)
+=
pxa930_rotary.o
obj-$(CONFIG_KEYBOARD_QT2160)
+=
qt2160.o
obj-$(CONFIG_KEYBOARD_SAMSUNG)
+=
samsung-keypad.o
obj-$(CONFIG_KEYBOARD_SH_KEYSC)
+=
sh_keysc.o
obj-$(CONFIG_KEYBOARD_STOWAWAY)
+=
stowaway.o
obj-$(CONFIG_KEYBOARD_SUNKBD)
+=
sunkbd.o
...
...
drivers/input/keyboard/adp5588-keys.c
View file @
929343ef
...
...
@@ -19,6 +19,7 @@
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/i2c/adp5588.h>
...
...
@@ -54,6 +55,10 @@
#define KEYP_MAX_EVENT 10
#define MAXGPIO 18
#define ADP_BANK(offs) ((offs) >> 3)
#define ADP_BIT(offs) (1u << ((offs) & 0x7))
/*
* Early pre 4.0 Silicon required to delay readout by at least 25ms,
* since the Event Counter Register updated 25ms after the interrupt
...
...
@@ -67,6 +72,16 @@ struct adp5588_kpad {
struct
delayed_work
work
;
unsigned
long
delay
;
unsigned
short
keycode
[
ADP5588_KEYMAPSIZE
];
const
struct
adp5588_gpi_map
*
gpimap
;
unsigned
short
gpimapsize
;
#ifdef CONFIG_GPIOLIB
unsigned
char
gpiomap
[
MAXGPIO
];
bool
export_gpio
;
struct
gpio_chip
gc
;
struct
mutex
gpio_lock
;
/* Protect cached dir, dat_out */
u8
dat_out
[
3
];
u8
dir
[
3
];
#endif
};
static
int
adp5588_read
(
struct
i2c_client
*
client
,
u8
reg
)
...
...
@@ -84,12 +99,222 @@ static int adp5588_write(struct i2c_client *client, u8 reg, u8 val)
return
i2c_smbus_write_byte_data
(
client
,
reg
,
val
);
}
#ifdef CONFIG_GPIOLIB
static
int
adp5588_gpio_get_value
(
struct
gpio_chip
*
chip
,
unsigned
off
)
{
struct
adp5588_kpad
*
kpad
=
container_of
(
chip
,
struct
adp5588_kpad
,
gc
);
unsigned
int
bank
=
ADP_BANK
(
kpad
->
gpiomap
[
off
]);
unsigned
int
bit
=
ADP_BIT
(
kpad
->
gpiomap
[
off
]);
return
!!
(
adp5588_read
(
kpad
->
client
,
GPIO_DAT_STAT1
+
bank
)
&
bit
);
}
static
void
adp5588_gpio_set_value
(
struct
gpio_chip
*
chip
,
unsigned
off
,
int
val
)
{
struct
adp5588_kpad
*
kpad
=
container_of
(
chip
,
struct
adp5588_kpad
,
gc
);
unsigned
int
bank
=
ADP_BANK
(
kpad
->
gpiomap
[
off
]);
unsigned
int
bit
=
ADP_BIT
(
kpad
->
gpiomap
[
off
]);
mutex_lock
(
&
kpad
->
gpio_lock
);
if
(
val
)
kpad
->
dat_out
[
bank
]
|=
bit
;
else
kpad
->
dat_out
[
bank
]
&=
~
bit
;
adp5588_write
(
kpad
->
client
,
GPIO_DAT_OUT1
+
bank
,
kpad
->
dat_out
[
bank
]);
mutex_unlock
(
&
kpad
->
gpio_lock
);
}
static
int
adp5588_gpio_direction_input
(
struct
gpio_chip
*
chip
,
unsigned
off
)
{
struct
adp5588_kpad
*
kpad
=
container_of
(
chip
,
struct
adp5588_kpad
,
gc
);
unsigned
int
bank
=
ADP_BANK
(
kpad
->
gpiomap
[
off
]);
unsigned
int
bit
=
ADP_BIT
(
kpad
->
gpiomap
[
off
]);
int
ret
;
mutex_lock
(
&
kpad
->
gpio_lock
);
kpad
->
dir
[
bank
]
&=
~
bit
;
ret
=
adp5588_write
(
kpad
->
client
,
GPIO_DIR1
+
bank
,
kpad
->
dir
[
bank
]);
mutex_unlock
(
&
kpad
->
gpio_lock
);
return
ret
;
}
static
int
adp5588_gpio_direction_output
(
struct
gpio_chip
*
chip
,
unsigned
off
,
int
val
)
{
struct
adp5588_kpad
*
kpad
=
container_of
(
chip
,
struct
adp5588_kpad
,
gc
);
unsigned
int
bank
=
ADP_BANK
(
kpad
->
gpiomap
[
off
]);
unsigned
int
bit
=
ADP_BIT
(
kpad
->
gpiomap
[
off
]);
int
ret
;
mutex_lock
(
&
kpad
->
gpio_lock
);
kpad
->
dir
[
bank
]
|=
bit
;
if
(
val
)
kpad
->
dat_out
[
bank
]
|=
bit
;
else
kpad
->
dat_out
[
bank
]
&=
~
bit
;
ret
=
adp5588_write
(
kpad
->
client
,
GPIO_DAT_OUT1
+
bank
,
kpad
->
dat_out
[
bank
]);
ret
|=
adp5588_write
(
kpad
->
client
,
GPIO_DIR1
+
bank
,
kpad
->
dir
[
bank
]);
mutex_unlock
(
&
kpad
->
gpio_lock
);
return
ret
;
}
static
int
__devinit
adp5588_build_gpiomap
(
struct
adp5588_kpad
*
kpad
,
const
struct
adp5588_kpad_platform_data
*
pdata
)
{
bool
pin_used
[
MAXGPIO
];
int
n_unused
=
0
;
int
i
;
memset
(
pin_used
,
0
,
sizeof
(
pin_used
));
for
(
i
=
0
;
i
<
pdata
->
rows
;
i
++
)
pin_used
[
i
]
=
true
;
for
(
i
=
0
;
i
<
pdata
->
cols
;
i
++
)
pin_used
[
i
+
GPI_PIN_COL_BASE
-
GPI_PIN_BASE
]
=
true
;
for
(
i
=
0
;
i
<
kpad
->
gpimapsize
;
i
++
)
pin_used
[
kpad
->
gpimap
[
i
].
pin
-
GPI_PIN_BASE
]
=
true
;
for
(
i
=
0
;
i
<
MAXGPIO
;
i
++
)
if
(
!
pin_used
[
i
])
kpad
->
gpiomap
[
n_unused
++
]
=
i
;
return
n_unused
;
}
static
int
__devinit
adp5588_gpio_add
(
struct
adp5588_kpad
*
kpad
)
{
struct
device
*
dev
=
&
kpad
->
client
->
dev
;
const
struct
adp5588_kpad_platform_data
*
pdata
=
dev
->
platform_data
;
const
struct
adp5588_gpio_platform_data
*
gpio_data
=
pdata
->
gpio_data
;
int
i
,
error
;
if
(
!
gpio_data
)
return
0
;
kpad
->
gc
.
ngpio
=
adp5588_build_gpiomap
(
kpad
,
pdata
);
if
(
kpad
->
gc
.
ngpio
==
0
)
{
dev_info
(
dev
,
"No unused gpios left to export
\n
"
);
return
0
;
}
kpad
->
export_gpio
=
true
;
kpad
->
gc
.
direction_input
=
adp5588_gpio_direction_input
;
kpad
->
gc
.
direction_output
=
adp5588_gpio_direction_output
;
kpad
->
gc
.
get
=
adp5588_gpio_get_value
;
kpad
->
gc
.
set
=
adp5588_gpio_set_value
;
kpad
->
gc
.
can_sleep
=
1
;
kpad
->
gc
.
base
=
gpio_data
->
gpio_start
;
kpad
->
gc
.
label
=
kpad
->
client
->
name
;
kpad
->
gc
.
owner
=
THIS_MODULE
;
mutex_init
(
&
kpad
->
gpio_lock
);
error
=
gpiochip_add
(
&
kpad
->
gc
);
if
(
error
)
{
dev_err
(
dev
,
"gpiochip_add failed, err: %d
\n
"
,
error
);
return
error
;
}
for
(
i
=
0
;
i
<=
ADP_BANK
(
MAXGPIO
);
i
++
)
{
kpad
->
dat_out
[
i
]
=
adp5588_read
(
kpad
->
client
,
GPIO_DAT_OUT1
+
i
);
kpad
->
dir
[
i
]
=
adp5588_read
(
kpad
->
client
,
GPIO_DIR1
+
i
);
}
if
(
gpio_data
->
setup
)
{
error
=
gpio_data
->
setup
(
kpad
->
client
,
kpad
->
gc
.
base
,
kpad
->
gc
.
ngpio
,
gpio_data
->
context
);
if
(
error
)
dev_warn
(
dev
,
"setup failed, %d
\n
"
,
error
);
}
return
0
;
}
static
void
__devexit
adp5588_gpio_remove
(
struct
adp5588_kpad
*
kpad
)
{
struct
device
*
dev
=
&
kpad
->
client
->
dev
;
const
struct
adp5588_kpad_platform_data
*
pdata
=
dev
->
platform_data
;
const
struct
adp5588_gpio_platform_data
*
gpio_data
=
pdata
->
gpio_data
;
int
error
;
if
(
!
kpad
->
export_gpio
)
return
;
if
(
gpio_data
->
teardown
)
{
error
=
gpio_data
->
teardown
(
kpad
->
client
,
kpad
->
gc
.
base
,
kpad
->
gc
.
ngpio
,
gpio_data
->
context
);
if
(
error
)
dev_warn
(
dev
,
"teardown failed %d
\n
"
,
error
);
}
error
=
gpiochip_remove
(
&
kpad
->
gc
);
if
(
error
)
dev_warn
(
dev
,
"gpiochip_remove failed %d
\n
"
,
error
);
}
#else
static
inline
int
adp5588_gpio_add
(
struct
adp5588_kpad
*
kpad
)
{
return
0
;
}
static
inline
void
adp5588_gpio_remove
(
struct
adp5588_kpad
*
kpad
)
{
}
#endif
static
void
adp5588_report_events
(
struct
adp5588_kpad
*
kpad
,
int
ev_cnt
)
{
int
i
,
j
;
for
(
i
=
0
;
i
<
ev_cnt
;
i
++
)
{
int
key
=
adp5588_read
(
kpad
->
client
,
Key_EVENTA
+
i
);
int
key_val
=
key
&
KEY_EV_MASK
;
if
(
key_val
>=
GPI_PIN_BASE
&&
key_val
<=
GPI_PIN_END
)
{
for
(
j
=
0
;
j
<
kpad
->
gpimapsize
;
j
++
)
{
if
(
key_val
==
kpad
->
gpimap
[
j
].
pin
)
{
input_report_switch
(
kpad
->
input
,
kpad
->
gpimap
[
j
].
sw_evt
,
key
&
KEY_EV_PRESSED
);
break
;
}
}
}
else
{
input_report_key
(
kpad
->
input
,
kpad
->
keycode
[
key_val
-
1
],
key
&
KEY_EV_PRESSED
);
}
}
}
static
void
adp5588_work
(
struct
work_struct
*
work
)
{
struct
adp5588_kpad
*
kpad
=
container_of
(
work
,
struct
adp5588_kpad
,
work
.
work
);
struct
i2c_client
*
client
=
kpad
->
client
;
int
i
,
key
,
status
,
ev_cnt
;
int
status
,
ev_cnt
;
status
=
adp5588_read
(
client
,
INT_STAT
);
...
...
@@ -99,12 +324,7 @@ static void adp5588_work(struct work_struct *work)
if
(
status
&
KE_INT
)
{
ev_cnt
=
adp5588_read
(
client
,
KEY_LCK_EC_STAT
)
&
KEC
;
if
(
ev_cnt
)
{
for
(
i
=
0
;
i
<
ev_cnt
;
i
++
)
{
key
=
adp5588_read
(
client
,
Key_EVENTA
+
i
);
input_report_key
(
kpad
->
input
,
kpad
->
keycode
[(
key
&
KEY_EV_MASK
)
-
1
],
key
&
KEY_EV_PRESSED
);
}
adp5588_report_events
(
kpad
,
ev_cnt
);
input_sync
(
kpad
->
input
);
}
}
...
...
@@ -128,8 +348,10 @@ static irqreturn_t adp5588_irq(int irq, void *handle)
static
int
__devinit
adp5588_setup
(
struct
i2c_client
*
client
)
{
struct
adp5588_kpad_platform_data
*
pdata
=
client
->
dev
.
platform_data
;
const
struct
adp5588_kpad_platform_data
*
pdata
=
client
->
dev
.
platform_data
;
const
struct
adp5588_gpio_platform_data
*
gpio_data
=
pdata
->
gpio_data
;
int
i
,
ret
;
unsigned
char
evt_mode1
=
0
,
evt_mode2
=
0
,
evt_mode3
=
0
;
ret
=
adp5588_write
(
client
,
KP_GPIO1
,
KP_SEL
(
pdata
->
rows
));
ret
|=
adp5588_write
(
client
,
KP_GPIO2
,
KP_SEL
(
pdata
->
cols
)
&
0xFF
);
...
...
@@ -144,6 +366,32 @@ static int __devinit adp5588_setup(struct i2c_client *client)
for
(
i
=
0
;
i
<
KEYP_MAX_EVENT
;
i
++
)
ret
|=
adp5588_read
(
client
,
Key_EVENTA
);
for
(
i
=
0
;
i
<
pdata
->
gpimapsize
;
i
++
)
{
unsigned
short
pin
=
pdata
->
gpimap
[
i
].
pin
;
if
(
pin
<=
GPI_PIN_ROW_END
)
{
evt_mode1
|=
(
1
<<
(
pin
-
GPI_PIN_ROW_BASE
));
}
else
{
evt_mode2
|=
((
1
<<
(
pin
-
GPI_PIN_COL_BASE
))
&
0xFF
);
evt_mode3
|=
((
1
<<
(
pin
-
GPI_PIN_COL_BASE
))
>>
8
);
}
}
if
(
pdata
->
gpimapsize
)
{
ret
|=
adp5588_write
(
client
,
GPI_EM1
,
evt_mode1
);
ret
|=
adp5588_write
(
client
,
GPI_EM2
,
evt_mode2
);
ret
|=
adp5588_write
(
client
,
GPI_EM3
,
evt_mode3
);
}
if
(
gpio_data
)
{
for
(
i
=
0
;
i
<=
ADP_BANK
(
MAXGPIO
);
i
++
)
{
int
pull_mask
=
gpio_data
->
pullup_dis_mask
;
ret
|=
adp5588_write
(
client
,
GPIO_PULL1
+
i
,
(
pull_mask
>>
(
8
*
i
))
&
0xFF
);
}
}
ret
|=
adp5588_write
(
client
,
INT_STAT
,
CMP2_INT
|
CMP1_INT
|
OVR_FLOW_INT
|
K_LCK_INT
|
GPI_INT
|
KE_INT
);
/* Status is W1C */
...
...
@@ -158,11 +406,49 @@ static int __devinit adp5588_setup(struct i2c_client *client)
return
0
;
}
static
void
__devinit
adp5588_report_switch_state
(
struct
adp5588_kpad
*
kpad
)
{
int
gpi_stat1
=
adp5588_read
(
kpad
->
client
,
GPIO_DAT_STAT1
);
int
gpi_stat2
=
adp5588_read
(
kpad
->
client
,
GPIO_DAT_STAT2
);
int
gpi_stat3
=
adp5588_read
(
kpad
->
client
,
GPIO_DAT_STAT3
);
int
gpi_stat_tmp
,
pin_loc
;
int
i
;
for
(
i
=
0
;
i
<
kpad
->
gpimapsize
;
i
++
)
{
unsigned
short
pin
=
kpad
->
gpimap
[
i
].
pin
;
if
(
pin
<=
GPI_PIN_ROW_END
)
{
gpi_stat_tmp
=
gpi_stat1
;
pin_loc
=
pin
-
GPI_PIN_ROW_BASE
;
}
else
if
((
pin
-
GPI_PIN_COL_BASE
)
<
8
)
{
gpi_stat_tmp
=
gpi_stat2
;
pin_loc
=
pin
-
GPI_PIN_COL_BASE
;
}
else
{
gpi_stat_tmp
=
gpi_stat3
;
pin_loc
=
pin
-
GPI_PIN_COL_BASE
-
8
;
}
if
(
gpi_stat_tmp
<
0
)
{
dev_err
(
&
kpad
->
client
->
dev
,
"Can't read GPIO_DAT_STAT switch %d default to OFF
\n
"
,
pin
);
gpi_stat_tmp
=
0
;
}
input_report_switch
(
kpad
->
input
,
kpad
->
gpimap
[
i
].
sw_evt
,
!
(
gpi_stat_tmp
&
(
1
<<
pin_loc
)));
}
input_sync
(
kpad
->
input
);
}
static
int
__devinit
adp5588_probe
(
struct
i2c_client
*
client
,
const
struct
i2c_device_id
*
id
)
{
struct
adp5588_kpad
*
kpad
;
struct
adp5588_kpad_platform_data
*
pdata
=
client
->
dev
.
platform_data
;
const
struct
adp5588_kpad_platform_data
*
pdata
=
client
->
dev
.
platform_data
;
struct
input_dev
*
input
;
unsigned
int
revid
;
int
ret
,
i
;
...
...
@@ -189,6 +475,37 @@ static int __devinit adp5588_probe(struct i2c_client *client,
return
-
EINVAL
;
}
if
(
!
pdata
->
gpimap
&&
pdata
->
gpimapsize
)
{
dev_err
(
&
client
->
dev
,
"invalid gpimap from pdata
\n
"
);
return
-
EINVAL
;
}
if
(
pdata
->
gpimapsize
>
ADP5588_GPIMAPSIZE_MAX
)
{
dev_err
(
&
client
->
dev
,
"invalid gpimapsize
\n
"
);
return
-
EINVAL
;
}
for
(
i
=
0
;
i
<
pdata
->
gpimapsize
;
i
++
)
{
unsigned
short
pin
=
pdata
->
gpimap
[
i
].
pin
;
if
(
pin
<
GPI_PIN_BASE
||
pin
>
GPI_PIN_END
)
{
dev_err
(
&
client
->
dev
,
"invalid gpi pin data
\n
"
);
return
-
EINVAL
;
}
if
(
pin
<=
GPI_PIN_ROW_END
)
{
if
(
pin
-
GPI_PIN_ROW_BASE
+
1
<=
pdata
->
rows
)
{
dev_err
(
&
client
->
dev
,
"invalid gpi row data
\n
"
);
return
-
EINVAL
;
}
}
else
{
if
(
pin
-
GPI_PIN_COL_BASE
+
1
<=
pdata
->
cols
)
{
dev_err
(
&
client
->
dev
,
"invalid gpi col data
\n
"
);
return
-
EINVAL
;
}
}
}
if
(
!
client
->
irq
)
{
dev_err
(
&
client
->
dev
,
"no IRQ?
\n
"
);
return
-
EINVAL
;
...
...
@@ -233,6 +550,9 @@ static int __devinit adp5588_probe(struct i2c_client *client,
memcpy
(
kpad
->
keycode
,
pdata
->
keymap
,
pdata
->
keymapsize
*
input
->
keycodesize
);
kpad
->
gpimap
=
pdata
->
gpimap
;
kpad
->
gpimapsize
=
pdata
->
gpimapsize
;
/* setup input device */
__set_bit
(
EV_KEY
,
input
->
evbit
);
...
...
@@ -243,6 +563,11 @@ static int __devinit adp5588_probe(struct i2c_client *client,
__set_bit
(
kpad
->
keycode
[
i
]
&
KEY_MAX
,
input
->
keybit
);
__clear_bit
(
KEY_RESERVED
,
input
->
keybit
);
if
(
kpad
->
gpimapsize
)
__set_bit
(
EV_SW
,
input
->
evbit
);
for
(
i
=
0
;
i
<
kpad
->
gpimapsize
;
i
++
)
__set_bit
(
kpad
->
gpimap
[
i
].
sw_evt
,
input
->
swbit
);
error
=
input_register_device
(
input
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"unable to register input device
\n
"
);
...
...
@@ -261,6 +586,13 @@ static int __devinit adp5588_probe(struct i2c_client *client,
if
(
error
)
goto
err_free_irq
;
if
(
kpad
->
gpimapsize
)
adp5588_report_switch_state
(
kpad
);
error
=
adp5588_gpio_add
(
kpad
);
if
(
error
)
goto
err_free_irq
;
device_init_wakeup
(
&
client
->
dev
,
1
);
i2c_set_clientdata
(
client
,
kpad
);
...
...
@@ -287,6 +619,7 @@ static int __devexit adp5588_remove(struct i2c_client *client)
free_irq
(
client
->
irq
,
kpad
);
cancel_delayed_work_sync
(
&
kpad
->
work
);
input_unregister_device
(
kpad
->
input
);
adp5588_gpio_remove
(
kpad
);
kfree
(
kpad
);
return
0
;
...
...
drivers/input/keyboard/gpio_keys.c
View file @
929343ef
...
...
@@ -31,6 +31,7 @@ struct gpio_button_data {
struct
input_dev
*
input
;
struct
timer_list
timer
;
struct
work_struct
work
;
int
timer_debounce
;
/* in msecs */
bool
disabled
;
};
...
...
@@ -109,7 +110,7 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata)
* Disable IRQ and possible debouncing timer.
*/
disable_irq
(
gpio_to_irq
(
bdata
->
button
->
gpio
));
if
(
bdata
->
button
->
debounce_interval
)
if
(
bdata
->
timer_debounce
)
del_timer_sync
(
&
bdata
->
timer
);
bdata
->
disabled
=
true
;
...
...
@@ -347,9 +348,9 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
BUG_ON
(
irq
!=
gpio_to_irq
(
button
->
gpio
));
if
(
b
utton
->
debounce_interval
)
if
(
b
data
->
timer_debounce
)
mod_timer
(
&
bdata
->
timer
,
jiffies
+
msecs_to_jiffies
(
b
utton
->
debounce_interval
));
jiffies
+
msecs_to_jiffies
(
b
data
->
timer_debounce
));
else
schedule_work
(
&
bdata
->
work
);
...
...
@@ -383,6 +384,14 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
goto
fail3
;
}
if
(
button
->
debounce_interval
)
{
error
=
gpio_set_debounce
(
button
->
gpio
,
button
->
debounce_interval
*
1000
);
/* use timer if gpiolib doesn't provide debounce */
if
(
error
<
0
)
bdata
->
timer_debounce
=
button
->
debounce_interval
;
}
irq
=
gpio_to_irq
(
button
->
gpio
);
if
(
irq
<
0
)
{
error
=
irq
;
...
...
@@ -498,7 +507,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
fail2:
while
(
--
i
>=
0
)
{
free_irq
(
gpio_to_irq
(
pdata
->
buttons
[
i
].
gpio
),
&
ddata
->
data
[
i
]);
if
(
pdata
->
buttons
[
i
].
debounce_interval
)
if
(
ddata
->
data
[
i
].
timer_debounce
)
del_timer_sync
(
&
ddata
->
data
[
i
].
timer
);
cancel_work_sync
(
&
ddata
->
data
[
i
].
work
);
gpio_free
(
pdata
->
buttons
[
i
].
gpio
);
...
...
@@ -526,7 +535,7 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
for
(
i
=
0
;
i
<
pdata
->
nbuttons
;
i
++
)
{
int
irq
=
gpio_to_irq
(
pdata
->
buttons
[
i
].
gpio
);
free_irq
(
irq
,
&
ddata
->
data
[
i
]);
if
(
pdata
->
buttons
[
i
].
debounce_interval
)
if
(
ddata
->
data
[
i
].
timer_debounce
)
del_timer_sync
(
&
ddata
->
data
[
i
].
timer
);
cancel_work_sync
(
&
ddata
->
data
[
i
].
work
);
gpio_free
(
pdata
->
buttons
[
i
].
gpio
);
...
...
drivers/input/keyboard/lm8323.c
View file @
929343ef
...
...
@@ -642,6 +642,7 @@ static int __devinit lm8323_probe(struct i2c_client *client,
struct
lm8323_platform_data
*
pdata
=
client
->
dev
.
platform_data
;
struct
input_dev
*
idev
;
struct
lm8323_chip
*
lm
;
int
pwm
;
int
i
,
err
;
unsigned
long
tmo
;
u8
data
[
2
];
...
...
@@ -710,8 +711,9 @@ static int __devinit lm8323_probe(struct i2c_client *client,
goto
fail1
;
}
for
(
i
=
0
;
i
<
LM8323_NUM_PWMS
;
i
++
)
{
err
=
init_pwm
(
lm
,
i
+
1
,
&
client
->
dev
,
pdata
->
pwm_names
[
i
]);
for
(
pwm
=
0
;
pwm
<
LM8323_NUM_PWMS
;
pwm
++
)
{
err
=
init_pwm
(
lm
,
pwm
+
1
,
&
client
->
dev
,
pdata
->
pwm_names
[
pwm
]);
if
(
err
<
0
)
goto
fail2
;
}
...
...
@@ -764,9 +766,9 @@ static int __devinit lm8323_probe(struct i2c_client *client,
fail3:
device_remove_file
(
&
client
->
dev
,
&
dev_attr_disable_kp
);
fail2:
while
(
--
i
>=
0
)
if
(
lm
->
pwm
[
i
].
enabled
)
led_classdev_unregister
(
&
lm
->
pwm
[
i
].
cdev
);
while
(
--
pwm
>=
0
)
if
(
lm
->
pwm
[
pwm
].
enabled
)
led_classdev_unregister
(
&
lm
->
pwm
[
pwm
].
cdev
);
fail1:
input_free_device
(
idev
);
kfree
(
lm
);
...
...
drivers/input/keyboard/matrix_keypad.c
View file @
929343ef
...
...
@@ -37,6 +37,7 @@ struct matrix_keypad {
spinlock_t
lock
;
bool
scan_pending
;
bool
stopped
;
bool
gpio_all_disabled
;
};
/*
...
...
@@ -87,8 +88,12 @@ static void enable_row_irqs(struct matrix_keypad *keypad)
const
struct
matrix_keypad_platform_data
*
pdata
=
keypad
->
pdata
;
int
i
;
for
(
i
=
0
;
i
<
pdata
->
num_row_gpios
;
i
++
)
enable_irq
(
gpio_to_irq
(
pdata
->
row_gpios
[
i
]));
if
(
pdata
->
clustered_irq
>
0
)
enable_irq
(
pdata
->
clustered_irq
);
else
{
for
(
i
=
0
;
i
<
pdata
->
num_row_gpios
;
i
++
)
enable_irq
(
gpio_to_irq
(
pdata
->
row_gpios
[
i
]));
}
}
static
void
disable_row_irqs
(
struct
matrix_keypad
*
keypad
)
...
...
@@ -96,8 +101,12 @@ static void disable_row_irqs(struct matrix_keypad *keypad)
const
struct
matrix_keypad_platform_data
*
pdata
=
keypad
->
pdata
;
int
i
;
for
(
i
=
0
;
i
<
pdata
->
num_row_gpios
;
i
++
)
disable_irq_nosync
(
gpio_to_irq
(
pdata
->
row_gpios
[
i
]));
if
(
pdata
->
clustered_irq
>
0
)
disable_irq_nosync
(
pdata
->
clustered_irq
);
else
{
for
(
i
=
0
;
i
<
pdata
->
num_row_gpios
;
i
++
)
disable_irq_nosync
(
gpio_to_irq
(
pdata
->
row_gpios
[
i
]));
}
}
/*
...
...
@@ -216,45 +225,69 @@ static void matrix_keypad_stop(struct input_dev *dev)
}
#ifdef CONFIG_PM
static
int
matrix_keypad_suspend
(
struct
device
*
dev
)
static
void
matrix_keypad_enable_wakeup
(
struct
matrix_keypad
*
keypad
)
{
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
struct
matrix_keypad
*
keypad
=
platform_get_drvdata
(
pdev
);
const
struct
matrix_keypad_platform_data
*
pdata
=
keypad
->
pdata
;
unsigned
int
gpio
;
int
i
;
matrix_keypad_stop
(
keypad
->
input_dev
);
if
(
pdata
->
clustered_irq
>
0
)
{
if
(
enable_irq_wake
(
pdata
->
clustered_irq
)
==
0
)
keypad
->
gpio_all_disabled
=
true
;
}
else
{
if
(
device_may_wakeup
(
&
pdev
->
dev
))
{
for
(
i
=
0
;
i
<
pdata
->
num_row_gpios
;
i
++
)
{
if
(
!
test_bit
(
i
,
keypad
->
disabled_gpios
))
{
unsigned
int
gpio
=
pdata
->
row_gpios
[
i
];
gpio
=
pdata
->
row_gpios
[
i
];
if
(
enable_irq_wake
(
gpio_to_irq
(
gpio
))
==
0
)
__set_bit
(
i
,
keypad
->
disabled_gpios
);
}
}
}
return
0
;
}
static
int
matrix_keypad_resume
(
struct
device
*
dev
)
static
void
matrix_keypad_disable_wakeup
(
struct
matrix_keypad
*
keypad
)
{
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
struct
matrix_keypad
*
keypad
=
platform_get_drvdata
(
pdev
);
const
struct
matrix_keypad_platform_data
*
pdata
=
keypad
->
pdata
;
unsigned
int
gpio
;
int
i
;
if
(
device_may_wakeup
(
&
pdev
->
dev
))
{
if
(
pdata
->
clustered_irq
>
0
)
{
if
(
keypad
->
gpio_all_disabled
)
{
disable_irq_wake
(
pdata
->
clustered_irq
);
keypad
->
gpio_all_disabled
=
false
;
}
}
else
{
for
(
i
=
0
;
i
<
pdata
->
num_row_gpios
;
i
++
)
{
if
(
test_and_clear_bit
(
i
,
keypad
->
disabled_gpios
))
{
unsigned
int
gpio
=
pdata
->
row_gpios
[
i
];
gpio
=
pdata
->
row_gpios
[
i
];
disable_irq_wake
(
gpio_to_irq
(
gpio
));
}
}
}
}
static
int
matrix_keypad_suspend
(
struct
device
*
dev
)
{
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
struct
matrix_keypad
*
keypad
=
platform_get_drvdata
(
pdev
);
matrix_keypad_stop
(
keypad
->
input_dev
);
if
(
device_may_wakeup
(
&
pdev
->
dev
))
matrix_keypad_enable_wakeup
(
keypad
);
return
0
;
}
static
int
matrix_keypad_resume
(
struct
device
*
dev
)
{
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
struct
matrix_keypad
*
keypad
=
platform_get_drvdata
(
pdev
);
if
(
device_may_wakeup
(
&
pdev
->
dev
))
matrix_keypad_disable_wakeup
(
keypad
);
matrix_keypad_start
(
keypad
->
input_dev
);
...
...
@@ -296,17 +329,31 @@ static int __devinit init_matrix_gpio(struct platform_device *pdev,
gpio_direction_input
(
pdata
->
row_gpios
[
i
]);
}
for
(
i
=
0
;
i
<
pdata
->
num_row_gpios
;
i
++
)
{
err
=
request_irq
(
gpio_to_irq
(
pdata
->
row_gpios
[
i
])
,
if
(
pdata
->
clustered_irq
>
0
)
{
err
=
request_irq
(
pdata
->
clustered_irq
,
matrix_keypad_interrupt
,
IRQF_DISABLED
|
IRQF_TRIGGER_RISING
|
IRQF_TRIGGER_FALLING
,
pdata
->
clustered_irq_flags
,
"matrix-keypad"
,
keypad
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"Unable to acquire interrupt for GPIO line %i
\n
"
,
pdata
->
row_gpios
[
i
]);
goto
err_free_irqs
;
"Unable to acquire clustered interrupt
\n
"
);
goto
err_free_rows
;
}
}
else
{
for
(
i
=
0
;
i
<
pdata
->
num_row_gpios
;
i
++
)
{
err
=
request_irq
(
gpio_to_irq
(
pdata
->
row_gpios
[
i
]),
matrix_keypad_interrupt
,
IRQF_DISABLED
|
IRQF_TRIGGER_RISING
|
IRQF_TRIGGER_FALLING
,
"matrix-keypad"
,
keypad
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"Unable to acquire interrupt "
"for GPIO line %i
\n
"
,
pdata
->
row_gpios
[
i
]);
goto
err_free_irqs
;
}
}
}
...
...
@@ -418,11 +465,16 @@ static int __devexit matrix_keypad_remove(struct platform_device *pdev)
device_init_wakeup
(
&
pdev
->
dev
,
0
);
for
(
i
=
0
;
i
<
pdata
->
num_row_gpios
;
i
++
)
{
free_irq
(
gpio_to_irq
(
pdata
->
row_gpios
[
i
]),
keypad
);
gpio_free
(
pdata
->
row_gpios
[
i
]);
if
(
pdata
->
clustered_irq
>
0
)
{
free_irq
(
pdata
->
clustered_irq
,
keypad
);
}
else
{
for
(
i
=
0
;
i
<
pdata
->
num_row_gpios
;
i
++
)
free_irq
(
gpio_to_irq
(
pdata
->
row_gpios
[
i
]),
keypad
);
}
for
(
i
=
0
;
i
<
pdata
->
num_row_gpios
;
i
++
)
gpio_free
(
pdata
->
row_gpios
[
i
]);
for
(
i
=
0
;
i
<
pdata
->
num_col_gpios
;
i
++
)
gpio_free
(
pdata
->
col_gpios
[
i
]);
...
...
drivers/input/keyboard/mcs_touchkey.c
0 → 100644
View file @
929343ef
/*
* mcs_touchkey.c - Touchkey driver for MELFAS MCS5000/5080 controller
*
* Copyright (C) 2010 Samsung Electronics Co.Ltd
* Author: HeungJun Kim <riverful.kim@samsung.com>
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/i2c/mcs.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/irq.h>
#include <linux/slab.h>
/* MCS5000 Touchkey */
#define MCS5000_TOUCHKEY_STATUS 0x04
#define MCS5000_TOUCHKEY_STATUS_PRESS 7
#define MCS5000_TOUCHKEY_FW 0x0a
#define MCS5000_TOUCHKEY_BASE_VAL 0x61
/* MCS5080 Touchkey */
#define MCS5080_TOUCHKEY_STATUS 0x00
#define MCS5080_TOUCHKEY_STATUS_PRESS 3
#define MCS5080_TOUCHKEY_FW 0x01
#define MCS5080_TOUCHKEY_BASE_VAL 0x1
enum
mcs_touchkey_type
{
MCS5000_TOUCHKEY
,
MCS5080_TOUCHKEY
,
};
struct
mcs_touchkey_chip
{
unsigned
int
status_reg
;
unsigned
int
pressbit
;
unsigned
int
press_invert
;
unsigned
int
baseval
;
};
struct
mcs_touchkey_data
{
struct
i2c_client
*
client
;
struct
input_dev
*
input_dev
;
struct
mcs_touchkey_chip
chip
;
unsigned
int
key_code
;
unsigned
int
key_val
;
unsigned
short
keycodes
[];
};
static
irqreturn_t
mcs_touchkey_interrupt
(
int
irq
,
void
*
dev_id
)
{
struct
mcs_touchkey_data
*
data
=
dev_id
;
struct
mcs_touchkey_chip
*
chip
=
&
data
->
chip
;
struct
i2c_client
*
client
=
data
->
client
;
struct
input_dev
*
input
=
data
->
input_dev
;
unsigned
int
key_val
;
unsigned
int
pressed
;
int
val
;
val
=
i2c_smbus_read_byte_data
(
client
,
chip
->
status_reg
);
if
(
val
<
0
)
{
dev_err
(
&
client
->
dev
,
"i2c read error [%d]
\n
"
,
val
);
goto
out
;
}
pressed
=
(
val
&
(
1
<<
chip
->
pressbit
))
>>
chip
->
pressbit
;
if
(
chip
->
press_invert
)
pressed
^=
chip
->
press_invert
;
/* key_val is 0 when released, so we should use key_val of press. */
if
(
pressed
)
{
key_val
=
val
&
(
0xff
>>
(
8
-
chip
->
pressbit
));
if
(
!
key_val
)
goto
out
;
key_val
-=
chip
->
baseval
;
data
->
key_code
=
data
->
keycodes
[
key_val
];
data
->
key_val
=
key_val
;
}
input_event
(
input
,
EV_MSC
,
MSC_SCAN
,
data
->
key_val
);
input_report_key
(
input
,
data
->
key_code
,
pressed
);
input_sync
(
input
);
dev_dbg
(
&
client
->
dev
,
"key %d %d %s
\n
"
,
data
->
key_val
,
data
->
key_code
,
pressed
?
"pressed"
:
"released"
);
out:
return
IRQ_HANDLED
;
}
static
int
__devinit
mcs_touchkey_probe
(
struct
i2c_client
*
client
,
const
struct
i2c_device_id
*
id
)
{
const
struct
mcs_platform_data
*
pdata
;
struct
mcs_touchkey_data
*
data
;
struct
input_dev
*
input_dev
;
unsigned
int
fw_reg
;
int
fw_ver
;
int
error
;
int
i
;
pdata
=
client
->
dev
.
platform_data
;
if
(
!
pdata
)
{
dev_err
(
&
client
->
dev
,
"no platform data defined
\n
"
);
return
-
EINVAL
;
}
data
=
kzalloc
(
sizeof
(
struct
mcs_touchkey_data
)
+
sizeof
(
data
->
keycodes
[
0
])
*
(
pdata
->
key_maxval
+
1
),
GFP_KERNEL
);
input_dev
=
input_allocate_device
();
if
(
!
data
||
!
input_dev
)
{
dev_err
(
&
client
->
dev
,
"Failed to allocate memory
\n
"
);
error
=
-
ENOMEM
;
goto
err_free_mem
;
}
data
->
client
=
client
;
data
->
input_dev
=
input_dev
;
if
(
id
->
driver_data
==
MCS5000_TOUCHKEY
)
{
data
->
chip
.
status_reg
=
MCS5000_TOUCHKEY_STATUS
;
data
->
chip
.
pressbit
=
MCS5000_TOUCHKEY_STATUS_PRESS
;
data
->
chip
.
baseval
=
MCS5000_TOUCHKEY_BASE_VAL
;
fw_reg
=
MCS5000_TOUCHKEY_FW
;
}
else
{
data
->
chip
.
status_reg
=
MCS5080_TOUCHKEY_STATUS
;
data
->
chip
.
pressbit
=
MCS5080_TOUCHKEY_STATUS_PRESS
;
data
->
chip
.
press_invert
=
1
;
data
->
chip
.
baseval
=
MCS5080_TOUCHKEY_BASE_VAL
;
fw_reg
=
MCS5080_TOUCHKEY_FW
;
}
fw_ver
=
i2c_smbus_read_byte_data
(
client
,
fw_reg
);
if
(
fw_ver
<
0
)
{
error
=
fw_ver
;
dev_err
(
&
client
->
dev
,
"i2c read error[%d]
\n
"
,
error
);
goto
err_free_mem
;
}
dev_info
(
&
client
->
dev
,
"Firmware version: %d
\n
"
,
fw_ver
);
input_dev
->
name
=
"MELPAS MCS Touchkey"
;
input_dev
->
id
.
bustype
=
BUS_I2C
;
input_dev
->
dev
.
parent
=
&
client
->
dev
;
input_dev
->
evbit
[
0
]
=
BIT_MASK
(
EV_KEY
);
if
(
!
pdata
->
no_autorepeat
)
input_dev
->
evbit
[
0
]
|=
BIT_MASK
(
EV_REP
);
input_dev
->
keycode
=
data
->
keycodes
;
input_dev
->
keycodesize
=
sizeof
(
data
->
keycodes
[
0
]);
input_dev
->
keycodemax
=
pdata
->
key_maxval
+
1
;
for
(
i
=
0
;
i
<
pdata
->
keymap_size
;
i
++
)
{
unsigned
int
val
=
MCS_KEY_VAL
(
pdata
->
keymap
[
i
]);
unsigned
int
code
=
MCS_KEY_CODE
(
pdata
->
keymap
[
i
]);
data
->
keycodes
[
val
]
=
code
;
__set_bit
(
code
,
input_dev
->
keybit
);
}
input_set_capability
(
input_dev
,
EV_MSC
,
MSC_SCAN
);
input_set_drvdata
(
input_dev
,
data
);
if
(
pdata
->
cfg_pin
)
pdata
->
cfg_pin
();
error
=
request_threaded_irq
(
client
->
irq
,
NULL
,
mcs_touchkey_interrupt
,
IRQF_TRIGGER_FALLING
,
client
->
dev
.
driver
->
name
,
data
);
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
,
data
);
return
0
;
err_free_irq:
free_irq
(
client
->
irq
,
data
);
err_free_mem:
input_free_device
(
input_dev
);
kfree
(
data
);
return
error
;
}
static
int
__devexit
mcs_touchkey_remove
(
struct
i2c_client
*
client
)
{
struct
mcs_touchkey_data
*
data
=
i2c_get_clientdata
(
client
);
free_irq
(
client
->
irq
,
data
);
input_unregister_device
(
data
->
input_dev
);
kfree
(
data
);
return
0
;
}
static
const
struct
i2c_device_id
mcs_touchkey_id
[]
=
{
{
"mcs5000_touchkey"
,
MCS5000_TOUCHKEY
},
{
"mcs5080_touchkey"
,
MCS5080_TOUCHKEY
},
{
}
};
MODULE_DEVICE_TABLE
(
i2c
,
mcs_touchkey_id
);
static
struct
i2c_driver
mcs_touchkey_driver
=
{
.
driver
=
{
.
name
=
"mcs_touchkey"
,
.
owner
=
THIS_MODULE
,
},
.
probe
=
mcs_touchkey_probe
,
.
remove
=
__devexit_p
(
mcs_touchkey_remove
),
.
id_table
=
mcs_touchkey_id
,
};
static
int
__init
mcs_touchkey_init
(
void
)
{
return
i2c_add_driver
(
&
mcs_touchkey_driver
);
}
static
void
__exit
mcs_touchkey_exit
(
void
)
{
i2c_del_driver
(
&
mcs_touchkey_driver
);
}
module_init
(
mcs_touchkey_init
);
module_exit
(
mcs_touchkey_exit
);
/* Module information */
MODULE_AUTHOR
(
"Joonyoung Shim <jy0922.shim@samsung.com>"
);
MODULE_AUTHOR
(
"HeungJun Kim <riverful.kim@samsung.com>"
);
MODULE_DESCRIPTION
(
"Touchkey driver for MELFAS MCS5000/5080 controller"
);
MODULE_LICENSE
(
"GPL"
);
drivers/input/keyboard/samsung-keypad.c
0 → 100644
View file @
929343ef
/*
* Samsung keypad driver
*
* Copyright (C) 2010 Samsung Electronics Co.Ltd
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
* Author: Donghwa Lee <dh09.lee@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <plat/keypad.h>
#define SAMSUNG_KEYIFCON 0x00
#define SAMSUNG_KEYIFSTSCLR 0x04
#define SAMSUNG_KEYIFCOL 0x08
#define SAMSUNG_KEYIFROW 0x0c
#define SAMSUNG_KEYIFFC 0x10
/* SAMSUNG_KEYIFCON */
#define SAMSUNG_KEYIFCON_INT_F_EN (1 << 0)
#define SAMSUNG_KEYIFCON_INT_R_EN (1 << 1)
#define SAMSUNG_KEYIFCON_DF_EN (1 << 2)
#define SAMSUNG_KEYIFCON_FC_EN (1 << 3)
#define SAMSUNG_KEYIFCON_WAKEUPEN (1 << 4)
/* SAMSUNG_KEYIFSTSCLR */
#define SAMSUNG_KEYIFSTSCLR_P_INT_MASK (0xff << 0)
#define SAMSUNG_KEYIFSTSCLR_R_INT_MASK (0xff << 8)
#define SAMSUNG_KEYIFSTSCLR_R_INT_OFFSET 8
#define S5PV210_KEYIFSTSCLR_P_INT_MASK (0x3fff << 0)
#define S5PV210_KEYIFSTSCLR_R_INT_MASK (0x3fff << 16)
#define S5PV210_KEYIFSTSCLR_R_INT_OFFSET 16
/* SAMSUNG_KEYIFCOL */
#define SAMSUNG_KEYIFCOL_MASK (0xff << 0)
#define S5PV210_KEYIFCOLEN_MASK (0xff << 8)
/* SAMSUNG_KEYIFROW */
#define SAMSUNG_KEYIFROW_MASK (0xff << 0)
#define S5PV210_KEYIFROW_MASK (0x3fff << 0)
/* SAMSUNG_KEYIFFC */
#define SAMSUNG_KEYIFFC_MASK (0x3ff << 0)
enum
samsung_keypad_type
{
KEYPAD_TYPE_SAMSUNG
,
KEYPAD_TYPE_S5PV210
,
};
struct
samsung_keypad
{
struct
input_dev
*
input_dev
;
struct
clk
*
clk
;
void
__iomem
*
base
;
wait_queue_head_t
wait
;
bool
stopped
;
int
irq
;
unsigned
int
row_shift
;
unsigned
int
rows
;
unsigned
int
cols
;
unsigned
int
row_state
[
SAMSUNG_MAX_COLS
];
unsigned
short
keycodes
[];
};
static
int
samsung_keypad_is_s5pv210
(
struct
device
*
dev
)
{
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
enum
samsung_keypad_type
type
=
platform_get_device_id
(
pdev
)
->
driver_data
;
return
type
==
KEYPAD_TYPE_S5PV210
;
}
static
void
samsung_keypad_scan
(
struct
samsung_keypad
*
keypad
,
unsigned
int
*
row_state
)
{
struct
device
*
dev
=
keypad
->
input_dev
->
dev
.
parent
;
unsigned
int
col
;
unsigned
int
val
;
for
(
col
=
0
;
col
<
keypad
->
cols
;
col
++
)
{
if
(
samsung_keypad_is_s5pv210
(
dev
))
{
val
=
S5PV210_KEYIFCOLEN_MASK
;
val
&=
~
(
1
<<
col
)
<<
8
;
}
else
{
val
=
SAMSUNG_KEYIFCOL_MASK
;
val
&=
~
(
1
<<
col
);
}
writel
(
val
,
keypad
->
base
+
SAMSUNG_KEYIFCOL
);
mdelay
(
1
);
val
=
readl
(
keypad
->
base
+
SAMSUNG_KEYIFROW
);
row_state
[
col
]
=
~
val
&
((
1
<<
keypad
->
rows
)
-
1
);
}
/* KEYIFCOL reg clear */
writel
(
0
,
keypad
->
base
+
SAMSUNG_KEYIFCOL
);
}
static
bool
samsung_keypad_report
(
struct
samsung_keypad
*
keypad
,
unsigned
int
*
row_state
)
{
struct
input_dev
*
input_dev
=
keypad
->
input_dev
;
unsigned
int
changed
;
unsigned
int
pressed
;
unsigned
int
key_down
=
0
;
unsigned
int
val
;
unsigned
int
col
,
row
;
for
(
col
=
0
;
col
<
keypad
->
cols
;
col
++
)
{
changed
=
row_state
[
col
]
^
keypad
->
row_state
[
col
];
key_down
|=
row_state
[
col
];
if
(
!
changed
)
continue
;
for
(
row
=
0
;
row
<
keypad
->
rows
;
row
++
)
{
if
(
!
(
changed
&
(
1
<<
row
)))
continue
;
pressed
=
row_state
[
col
]
&
(
1
<<
row
);
dev_dbg
(
&
keypad
->
input_dev
->
dev
,
"key %s, row: %d, col: %d
\n
"
,
pressed
?
"pressed"
:
"released"
,
row
,
col
);
val
=
MATRIX_SCAN_CODE
(
row
,
col
,
keypad
->
row_shift
);
input_event
(
input_dev
,
EV_MSC
,
MSC_SCAN
,
val
);
input_report_key
(
input_dev
,
keypad
->
keycodes
[
val
],
pressed
);
}
input_sync
(
keypad
->
input_dev
);
}
memcpy
(
keypad
->
row_state
,
row_state
,
sizeof
(
keypad
->
row_state
));
return
key_down
;
}
static
irqreturn_t
samsung_keypad_irq
(
int
irq
,
void
*
dev_id
)
{
struct
samsung_keypad
*
keypad
=
dev_id
;
unsigned
int
row_state
[
SAMSUNG_MAX_COLS
];
unsigned
int
val
;
bool
key_down
;
do
{
val
=
readl
(
keypad
->
base
+
SAMSUNG_KEYIFSTSCLR
);
/* Clear interrupt. */
writel
(
~
0x0
,
keypad
->
base
+
SAMSUNG_KEYIFSTSCLR
);
samsung_keypad_scan
(
keypad
,
row_state
);
key_down
=
samsung_keypad_report
(
keypad
,
row_state
);
if
(
key_down
)
wait_event_timeout
(
keypad
->
wait
,
keypad
->
stopped
,
msecs_to_jiffies
(
50
));
}
while
(
key_down
&&
!
keypad
->
stopped
);
return
IRQ_HANDLED
;
}
static
void
samsung_keypad_start
(
struct
samsung_keypad
*
keypad
)
{
unsigned
int
val
;
/* Tell IRQ thread that it may poll the device. */
keypad
->
stopped
=
false
;
clk_enable
(
keypad
->
clk
);
/* Enable interrupt bits. */
val
=
readl
(
keypad
->
base
+
SAMSUNG_KEYIFCON
);
val
|=
SAMSUNG_KEYIFCON_INT_F_EN
|
SAMSUNG_KEYIFCON_INT_R_EN
;
writel
(
val
,
keypad
->
base
+
SAMSUNG_KEYIFCON
);
/* KEYIFCOL reg clear. */
writel
(
0
,
keypad
->
base
+
SAMSUNG_KEYIFCOL
);
}
static
void
samsung_keypad_stop
(
struct
samsung_keypad
*
keypad
)
{
unsigned
int
val
;
/* Signal IRQ thread to stop polling and disable the handler. */
keypad
->
stopped
=
true
;
wake_up
(
&
keypad
->
wait
);
disable_irq
(
keypad
->
irq
);
/* Clear interrupt. */
writel
(
~
0x0
,
keypad
->
base
+
SAMSUNG_KEYIFSTSCLR
);
/* Disable interrupt bits. */
val
=
readl
(
keypad
->
base
+
SAMSUNG_KEYIFCON
);
val
&=
~
(
SAMSUNG_KEYIFCON_INT_F_EN
|
SAMSUNG_KEYIFCON_INT_R_EN
);
writel
(
val
,
keypad
->
base
+
SAMSUNG_KEYIFCON
);
clk_disable
(
keypad
->
clk
);
/*
* Now that chip should not generate interrupts we can safely
* re-enable the handler.
*/
enable_irq
(
keypad
->
irq
);
}
static
int
samsung_keypad_open
(
struct
input_dev
*
input_dev
)
{
struct
samsung_keypad
*
keypad
=
input_get_drvdata
(
input_dev
);
samsung_keypad_start
(
keypad
);
return
0
;
}
static
void
samsung_keypad_close
(
struct
input_dev
*
input_dev
)
{
struct
samsung_keypad
*
keypad
=
input_get_drvdata
(
input_dev
);
samsung_keypad_stop
(
keypad
);
}
static
int
__devinit
samsung_keypad_probe
(
struct
platform_device
*
pdev
)
{
const
struct
samsung_keypad_platdata
*
pdata
;
const
struct
matrix_keymap_data
*
keymap_data
;
struct
samsung_keypad
*
keypad
;
struct
resource
*
res
;
struct
input_dev
*
input_dev
;
unsigned
int
row_shift
;
unsigned
int
keymap_size
;
int
error
;
pdata
=
pdev
->
dev
.
platform_data
;
if
(
!
pdata
)
{
dev_err
(
&
pdev
->
dev
,
"no platform data defined
\n
"
);
return
-
EINVAL
;
}
keymap_data
=
pdata
->
keymap_data
;
if
(
!
keymap_data
)
{
dev_err
(
&
pdev
->
dev
,
"no keymap data defined
\n
"
);
return
-
EINVAL
;
}
if
(
!
pdata
->
rows
||
pdata
->
rows
>
SAMSUNG_MAX_ROWS
)
return
-
EINVAL
;
if
(
!
pdata
->
cols
||
pdata
->
cols
>
SAMSUNG_MAX_COLS
)
return
-
EINVAL
;
/* initialize the gpio */
if
(
pdata
->
cfg_gpio
)
pdata
->
cfg_gpio
(
pdata
->
rows
,
pdata
->
cols
);
row_shift
=
get_count_order
(
pdata
->
cols
);
keymap_size
=
(
pdata
->
rows
<<
row_shift
)
*
sizeof
(
keypad
->
keycodes
[
0
]);
keypad
=
kzalloc
(
sizeof
(
*
keypad
)
+
keymap_size
,
GFP_KERNEL
);
input_dev
=
input_allocate_device
();
if
(
!
keypad
||
!
input_dev
)
{
error
=
-
ENOMEM
;
goto
err_free_mem
;
}
res
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
if
(
!
res
)
{
error
=
-
ENODEV
;
goto
err_free_mem
;
}
keypad
->
base
=
ioremap
(
res
->
start
,
resource_size
(
res
));
if
(
!
keypad
->
base
)
{
error
=
-
EBUSY
;
goto
err_free_mem
;
}
keypad
->
clk
=
clk_get
(
&
pdev
->
dev
,
"keypad"
);
if
(
IS_ERR
(
keypad
->
clk
))
{
dev_err
(
&
pdev
->
dev
,
"failed to get keypad clk
\n
"
);
error
=
PTR_ERR
(
keypad
->
clk
);
goto
err_unmap_base
;
}
keypad
->
input_dev
=
input_dev
;
keypad
->
row_shift
=
row_shift
;
keypad
->
rows
=
pdata
->
rows
;
keypad
->
cols
=
pdata
->
cols
;
init_waitqueue_head
(
&
keypad
->
wait
);
input_dev
->
name
=
pdev
->
name
;
input_dev
->
id
.
bustype
=
BUS_HOST
;
input_dev
->
dev
.
parent
=
&
pdev
->
dev
;
input_set_drvdata
(
input_dev
,
keypad
);
input_dev
->
open
=
samsung_keypad_open
;
input_dev
->
close
=
samsung_keypad_close
;
input_dev
->
evbit
[
0
]
=
BIT_MASK
(
EV_KEY
);
if
(
!
pdata
->
no_autorepeat
)
input_dev
->
evbit
[
0
]
|=
BIT_MASK
(
EV_REP
);
input_set_capability
(
input_dev
,
EV_MSC
,
MSC_SCAN
);
input_dev
->
keycode
=
keypad
->
keycodes
;
input_dev
->
keycodesize
=
sizeof
(
keypad
->
keycodes
[
0
]);
input_dev
->
keycodemax
=
pdata
->
rows
<<
row_shift
;
matrix_keypad_build_keymap
(
keymap_data
,
row_shift
,
input_dev
->
keycode
,
input_dev
->
keybit
);
keypad
->
irq
=
platform_get_irq
(
pdev
,
0
);
if
(
keypad
->
irq
<
0
)
{
error
=
keypad
->
irq
;
goto
err_put_clk
;
}
error
=
request_threaded_irq
(
keypad
->
irq
,
NULL
,
samsung_keypad_irq
,
IRQF_ONESHOT
,
dev_name
(
&
pdev
->
dev
),
keypad
);
if
(
error
)
{
dev_err
(
&
pdev
->
dev
,
"failed to register keypad interrupt
\n
"
);
goto
err_put_clk
;
}
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
);
return
0
;
err_free_irq:
free_irq
(
keypad
->
irq
,
keypad
);
err_put_clk:
clk_put
(
keypad
->
clk
);
err_unmap_base:
iounmap
(
keypad
->
base
);
err_free_mem:
input_free_device
(
input_dev
);
kfree
(
keypad
);
return
error
;
}
static
int
__devexit
samsung_keypad_remove
(
struct
platform_device
*
pdev
)
{
struct
samsung_keypad
*
keypad
=
platform_get_drvdata
(
pdev
);
device_init_wakeup
(
&
pdev
->
dev
,
0
);
platform_set_drvdata
(
pdev
,
NULL
);
input_unregister_device
(
keypad
->
input_dev
);
/*
* It is safe to free IRQ after unregistering device because
* samsung_keypad_close will shut off interrupts.
*/
free_irq
(
keypad
->
irq
,
keypad
);
clk_put
(
keypad
->
clk
);
iounmap
(
keypad
->
base
);
kfree
(
keypad
);
return
0
;
}
#ifdef CONFIG_PM
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
);
val
=
readl
(
keypad
->
base
+
SAMSUNG_KEYIFCON
);
if
(
enable
)
{
val
|=
SAMSUNG_KEYIFCON_WAKEUPEN
;
if
(
device_may_wakeup
(
dev
))
enable_irq_wake
(
keypad
->
irq
);
}
else
{
val
&=
~
SAMSUNG_KEYIFCON_WAKEUPEN
;
if
(
device_may_wakeup
(
dev
))
disable_irq_wake
(
keypad
->
irq
);
}
writel
(
val
,
keypad
->
base
+
SAMSUNG_KEYIFCON
);
clk_disable
(
keypad
->
clk
);
}
static
int
samsung_keypad_suspend
(
struct
device
*
dev
)
{
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
struct
samsung_keypad
*
keypad
=
platform_get_drvdata
(
pdev
);
struct
input_dev
*
input_dev
=
keypad
->
input_dev
;
mutex_lock
(
&
input_dev
->
mutex
);
if
(
input_dev
->
users
)
samsung_keypad_stop
(
keypad
);
samsung_keypad_toggle_wakeup
(
keypad
,
true
);
mutex_unlock
(
&
input_dev
->
mutex
);
return
0
;
}
static
int
samsung_keypad_resume
(
struct
device
*
dev
)
{
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
struct
samsung_keypad
*
keypad
=
platform_get_drvdata
(
pdev
);
struct
input_dev
*
input_dev
=
keypad
->
input_dev
;
mutex_lock
(
&
input_dev
->
mutex
);
samsung_keypad_toggle_wakeup
(
keypad
,
false
);
if
(
input_dev
->
users
)
samsung_keypad_start
(
keypad
);
mutex_unlock
(
&
input_dev
->
mutex
);
return
0
;
}
static
const
struct
dev_pm_ops
samsung_keypad_pm_ops
=
{
.
suspend
=
samsung_keypad_suspend
,
.
resume
=
samsung_keypad_resume
,
};
#endif
static
struct
platform_device_id
samsung_keypad_driver_ids
[]
=
{
{
.
name
=
"samsung-keypad"
,
.
driver_data
=
KEYPAD_TYPE_SAMSUNG
,
},
{
.
name
=
"s5pv210-keypad"
,
.
driver_data
=
KEYPAD_TYPE_S5PV210
,
},
{
},
};
MODULE_DEVICE_TABLE
(
platform
,
samsung_keypad_driver_ids
);
static
struct
platform_driver
samsung_keypad_driver
=
{
.
probe
=
samsung_keypad_probe
,
.
remove
=
__devexit_p
(
samsung_keypad_remove
),
.
driver
=
{
.
name
=
"samsung-keypad"
,
.
owner
=
THIS_MODULE
,
#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_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"
);
drivers/input/misc/Kconfig
View file @
929343ef
...
...
@@ -327,6 +327,17 @@ config INPUT_PCF8574
To compile this driver as a module, choose M here: the
module will be called pcf8574_keypad.
config INPUT_PWM_BEEPER
tristate "PWM beeper support"
depends on HAVE_PWM
help
Say Y here to get support for PWM based beeper devices.
If unsure, say N.
To compile this driver as a module, choose M here: the module will be
called pwm-beeper.
config INPUT_GPIO_ROTARY_ENCODER
tristate "Rotary encoders connected to GPIO pins"
depends on GPIOLIB && GENERIC_GPIO
...
...
@@ -390,4 +401,41 @@ config INPUT_PCAP
To compile this driver as a module, choose M here: the
module will be called pcap_keys.
config INPUT_ADXL34X
tristate "Analog Devices ADXL34x Three-Axis Digital Accelerometer"
default n
help
Say Y here if you have a Accelerometer interface using the
ADXL345/6 controller, and your board-specific initialization
code includes that in its table of devices.
This driver can use either I2C or SPI communication to the
ADXL345/6 controller. Select the appropriate method for
your system.
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
module will be called adxl34x.
config INPUT_ADXL34X_I2C
tristate "support I2C bus connection"
depends on INPUT_ADXL34X && I2C
default y
help
Say Y here if you have ADXL345/6 hooked to an I2C bus.
To compile this driver as a module, choose M here: the
module will be called adxl34x-i2c.
config INPUT_ADXL34X_SPI
tristate "support SPI bus connection"
depends on INPUT_ADXL34X && SPI
default y
help
Say Y here if you have ADXL345/6 hooked to a SPI bus.
To compile this driver as a module, choose M here: the
module will be called adxl34x-spi.
endif
drivers/input/misc/Makefile
View file @
929343ef
...
...
@@ -8,6 +8,9 @@ obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o
obj-$(CONFIG_INPUT_AD714X)
+=
ad714x.o
obj-$(CONFIG_INPUT_AD714X_I2C)
+=
ad714x-i2c.o
obj-$(CONFIG_INPUT_AD714X_SPI)
+=
ad714x-spi.o
obj-$(CONFIG_INPUT_ADXL34X)
+=
adxl34x.o
obj-$(CONFIG_INPUT_ADXL34X_I2C)
+=
adxl34x-i2c.o
obj-$(CONFIG_INPUT_ADXL34X_SPI)
+=
adxl34x-spi.o
obj-$(CONFIG_INPUT_APANEL)
+=
apanel.o
obj-$(CONFIG_INPUT_ATI_REMOTE)
+=
ati_remote.o
obj-$(CONFIG_INPUT_ATI_REMOTE2)
+=
ati_remote2.o
...
...
@@ -26,6 +29,7 @@ obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o
obj-$(CONFIG_INPUT_PCF8574)
+=
pcf8574_keypad.o
obj-$(CONFIG_INPUT_PCSPKR)
+=
pcspkr.o
obj-$(CONFIG_INPUT_POWERMATE)
+=
powermate.o
obj-$(CONFIG_INPUT_PWM_BEEPER)
+=
pwm-beeper.o
obj-$(CONFIG_INPUT_RB532_BUTTON)
+=
rb532_button.o
obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER)
+=
rotary_encoder.o
obj-$(CONFIG_INPUT_SGI_BTNS)
+=
sgi_btns.o
...
...
drivers/input/misc/adxl34x-i2c.c
0 → 100644
View file @
929343ef
/*
* ADLX345/346 Three-Axis Digital Accelerometers (I2C Interface)
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
* Licensed under the GPL-2 or later.
*/
#include <linux/input.h>
/* BUS_I2C */
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/types.h>
#include "adxl34x.h"
static
int
adxl34x_smbus_read
(
struct
device
*
dev
,
unsigned
char
reg
)
{
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
return
i2c_smbus_read_byte_data
(
client
,
reg
);
}
static
int
adxl34x_smbus_write
(
struct
device
*
dev
,
unsigned
char
reg
,
unsigned
char
val
)
{
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
return
i2c_smbus_write_byte_data
(
client
,
reg
,
val
);
}
static
int
adxl34x_smbus_read_block
(
struct
device
*
dev
,
unsigned
char
reg
,
int
count
,
void
*
buf
)
{
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
return
i2c_smbus_read_i2c_block_data
(
client
,
reg
,
count
,
buf
);
}
static
int
adxl34x_i2c_read_block
(
struct
device
*
dev
,
unsigned
char
reg
,
int
count
,
void
*
buf
)
{
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
int
ret
;
ret
=
i2c_master_send
(
client
,
&
reg
,
1
);
if
(
ret
<
0
)
return
ret
;
ret
=
i2c_master_recv
(
client
,
buf
,
count
);
if
(
ret
<
0
)
return
ret
;
if
(
ret
!=
count
)
return
-
EIO
;
return
0
;
}
static
const
struct
adxl34x_bus_ops
adxl34x_smbus_bops
=
{
.
bustype
=
BUS_I2C
,
.
write
=
adxl34x_smbus_write
,
.
read
=
adxl34x_smbus_read
,
.
read_block
=
adxl34x_smbus_read_block
,
};
static
const
struct
adxl34x_bus_ops
adxl34x_i2c_bops
=
{
.
bustype
=
BUS_I2C
,
.
write
=
adxl34x_smbus_write
,
.
read
=
adxl34x_smbus_read
,
.
read_block
=
adxl34x_i2c_read_block
,
};
static
int
__devinit
adxl34x_i2c_probe
(
struct
i2c_client
*
client
,
const
struct
i2c_device_id
*
id
)
{
struct
adxl34x
*
ac
;
int
error
;
error
=
i2c_check_functionality
(
client
->
adapter
,
I2C_FUNC_SMBUS_BYTE_DATA
);
if
(
!
error
)
{
dev_err
(
&
client
->
dev
,
"SMBUS Byte Data not Supported
\n
"
);
return
-
EIO
;
}
ac
=
adxl34x_probe
(
&
client
->
dev
,
client
->
irq
,
false
,
i2c_check_functionality
(
client
->
adapter
,
I2C_FUNC_SMBUS_READ_I2C_BLOCK
)
?
&
adxl34x_smbus_bops
:
&
adxl34x_i2c_bops
);
if
(
IS_ERR
(
ac
))
return
PTR_ERR
(
ac
);
i2c_set_clientdata
(
client
,
ac
);
return
0
;
}
static
int
__devexit
adxl34x_i2c_remove
(
struct
i2c_client
*
client
)
{
struct
adxl34x
*
ac
=
i2c_get_clientdata
(
client
);
return
adxl34x_remove
(
ac
);
}
#ifdef CONFIG_PM
static
int
adxl34x_i2c_suspend
(
struct
i2c_client
*
client
,
pm_message_t
message
)
{
struct
adxl34x
*
ac
=
i2c_get_clientdata
(
client
);
adxl34x_suspend
(
ac
);
return
0
;
}
static
int
adxl34x_i2c_resume
(
struct
i2c_client
*
client
)
{
struct
adxl34x
*
ac
=
i2c_get_clientdata
(
client
);
adxl34x_resume
(
ac
);
return
0
;
}
#else
# define adxl34x_i2c_suspend NULL
# define adxl34x_i2c_resume NULL
#endif
static
const
struct
i2c_device_id
adxl34x_id
[]
=
{
{
"adxl34x"
,
0
},
{
}
};
MODULE_DEVICE_TABLE
(
i2c
,
adxl34x_id
);
static
struct
i2c_driver
adxl34x_driver
=
{
.
driver
=
{
.
name
=
"adxl34x"
,
.
owner
=
THIS_MODULE
,
},
.
probe
=
adxl34x_i2c_probe
,
.
remove
=
__devexit_p
(
adxl34x_i2c_remove
),
.
suspend
=
adxl34x_i2c_suspend
,
.
resume
=
adxl34x_i2c_resume
,
.
id_table
=
adxl34x_id
,
};
static
int
__init
adxl34x_i2c_init
(
void
)
{
return
i2c_add_driver
(
&
adxl34x_driver
);
}
module_init
(
adxl34x_i2c_init
);
static
void
__exit
adxl34x_i2c_exit
(
void
)
{
i2c_del_driver
(
&
adxl34x_driver
);
}
module_exit
(
adxl34x_i2c_exit
);
MODULE_AUTHOR
(
"Michael Hennerich <hennerich@blackfin.uclinux.org>"
);
MODULE_DESCRIPTION
(
"ADXL345/346 Three-Axis Digital Accelerometer I2C Bus Driver"
);
MODULE_LICENSE
(
"GPL"
);
drivers/input/misc/adxl34x-spi.c
0 → 100644
View file @
929343ef
/*
* ADLX345/346 Three-Axis Digital Accelerometers (SPI Interface)
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
* Licensed under the GPL-2 or later.
*/
#include <linux/input.h>
/* BUS_SPI */
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/types.h>
#include "adxl34x.h"
#define MAX_SPI_FREQ_HZ 5000000
#define MAX_FREQ_NO_FIFODELAY 1500000
#define ADXL34X_CMD_MULTB (1 << 6)
#define ADXL34X_CMD_READ (1 << 7)
#define ADXL34X_WRITECMD(reg) (reg & 0x3F)
#define ADXL34X_READCMD(reg) (ADXL34X_CMD_READ | (reg & 0x3F))
#define ADXL34X_READMB_CMD(reg) (ADXL34X_CMD_READ | ADXL34X_CMD_MULTB \
| (reg & 0x3F))
static
int
adxl34x_spi_read
(
struct
device
*
dev
,
unsigned
char
reg
)
{
struct
spi_device
*
spi
=
to_spi_device
(
dev
);
unsigned
char
cmd
;
cmd
=
ADXL34X_READCMD
(
reg
);
return
spi_w8r8
(
spi
,
cmd
);
}
static
int
adxl34x_spi_write
(
struct
device
*
dev
,
unsigned
char
reg
,
unsigned
char
val
)
{
struct
spi_device
*
spi
=
to_spi_device
(
dev
);
unsigned
char
buf
[
2
];
buf
[
0
]
=
ADXL34X_WRITECMD
(
reg
);
buf
[
1
]
=
val
;
return
spi_write
(
spi
,
buf
,
sizeof
(
buf
));
}
static
int
adxl34x_spi_read_block
(
struct
device
*
dev
,
unsigned
char
reg
,
int
count
,
void
*
buf
)
{
struct
spi_device
*
spi
=
to_spi_device
(
dev
);
ssize_t
status
;
reg
=
ADXL34X_READMB_CMD
(
reg
);
status
=
spi_write_then_read
(
spi
,
&
reg
,
1
,
buf
,
count
);
return
(
status
<
0
)
?
status
:
0
;
}
static
const
struct
adxl34x_bus_ops
adx134x_spi_bops
=
{
.
bustype
=
BUS_SPI
,
.
write
=
adxl34x_spi_write
,
.
read
=
adxl34x_spi_read
,
.
read_block
=
adxl34x_spi_read_block
,
};
static
int
__devinit
adxl34x_spi_probe
(
struct
spi_device
*
spi
)
{
struct
adxl34x
*
ac
;
/* don't exceed max specified SPI CLK frequency */
if
(
spi
->
max_speed_hz
>
MAX_SPI_FREQ_HZ
)
{
dev_err
(
&
spi
->
dev
,
"SPI CLK %d Hz too fast
\n
"
,
spi
->
max_speed_hz
);
return
-
EINVAL
;
}
ac
=
adxl34x_probe
(
&
spi
->
dev
,
spi
->
irq
,
spi
->
max_speed_hz
>
MAX_FREQ_NO_FIFODELAY
,
&
adx134x_spi_bops
);
if
(
IS_ERR
(
ac
))
return
PTR_ERR
(
ac
);
spi_set_drvdata
(
spi
,
ac
);
return
0
;
}
static
int
__devexit
adxl34x_spi_remove
(
struct
spi_device
*
spi
)
{
struct
adxl34x
*
ac
=
dev_get_drvdata
(
&
spi
->
dev
);
return
adxl34x_remove
(
ac
);
}
#ifdef CONFIG_PM
static
int
adxl34x_spi_suspend
(
struct
spi_device
*
spi
,
pm_message_t
message
)
{
struct
adxl34x
*
ac
=
dev_get_drvdata
(
&
spi
->
dev
);
adxl34x_suspend
(
ac
);
return
0
;
}
static
int
adxl34x_spi_resume
(
struct
spi_device
*
spi
)
{
struct
adxl34x
*
ac
=
dev_get_drvdata
(
&
spi
->
dev
);
adxl34x_resume
(
ac
);
return
0
;
}
#else
# define adxl34x_spi_suspend NULL
# define adxl34x_spi_resume NULL
#endif
static
struct
spi_driver
adxl34x_driver
=
{
.
driver
=
{
.
name
=
"adxl34x"
,
.
bus
=
&
spi_bus_type
,
.
owner
=
THIS_MODULE
,
},
.
probe
=
adxl34x_spi_probe
,
.
remove
=
__devexit_p
(
adxl34x_spi_remove
),
.
suspend
=
adxl34x_spi_suspend
,
.
resume
=
adxl34x_spi_resume
,
};
static
int
__init
adxl34x_spi_init
(
void
)
{
return
spi_register_driver
(
&
adxl34x_driver
);
}
module_init
(
adxl34x_spi_init
);
static
void
__exit
adxl34x_spi_exit
(
void
)
{
spi_unregister_driver
(
&
adxl34x_driver
);
}
module_exit
(
adxl34x_spi_exit
);
MODULE_AUTHOR
(
"Michael Hennerich <hennerich@blackfin.uclinux.org>"
);
MODULE_DESCRIPTION
(
"ADXL345/346 Three-Axis Digital Accelerometer SPI Bus Driver"
);
MODULE_LICENSE
(
"GPL"
);
drivers/input/misc/adxl34x.c
0 → 100644
View file @
929343ef
/*
* ADXL345/346 Three-Axis Digital Accelerometers
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
* Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/input/adxl34x.h>
#include "adxl34x.h"
/* ADXL345/6 Register Map */
#define DEVID 0x00
/* R Device ID */
#define THRESH_TAP 0x1D
/* R/W Tap threshold */
#define OFSX 0x1E
/* R/W X-axis offset */
#define OFSY 0x1F
/* R/W Y-axis offset */
#define OFSZ 0x20
/* R/W Z-axis offset */
#define DUR 0x21
/* R/W Tap duration */
#define LATENT 0x22
/* R/W Tap latency */
#define WINDOW 0x23
/* R/W Tap window */
#define THRESH_ACT 0x24
/* R/W Activity threshold */
#define THRESH_INACT 0x25
/* R/W Inactivity threshold */
#define TIME_INACT 0x26
/* R/W Inactivity time */
#define ACT_INACT_CTL 0x27
/* R/W Axis enable control for activity and */
/* inactivity detection */
#define THRESH_FF 0x28
/* R/W Free-fall threshold */
#define TIME_FF 0x29
/* R/W Free-fall time */
#define TAP_AXES 0x2A
/* R/W Axis control for tap/double tap */
#define ACT_TAP_STATUS 0x2B
/* R Source of tap/double tap */
#define BW_RATE 0x2C
/* R/W Data rate and power mode control */
#define POWER_CTL 0x2D
/* R/W Power saving features control */
#define INT_ENABLE 0x2E
/* R/W Interrupt enable control */
#define INT_MAP 0x2F
/* R/W Interrupt mapping control */
#define INT_SOURCE 0x30
/* R Source of interrupts */
#define DATA_FORMAT 0x31
/* R/W Data format control */
#define DATAX0 0x32
/* R X-Axis Data 0 */
#define DATAX1 0x33
/* R X-Axis Data 1 */
#define DATAY0 0x34
/* R Y-Axis Data 0 */
#define DATAY1 0x35
/* R Y-Axis Data 1 */
#define DATAZ0 0x36
/* R Z-Axis Data 0 */
#define DATAZ1 0x37
/* R Z-Axis Data 1 */
#define FIFO_CTL 0x38
/* R/W FIFO control */
#define FIFO_STATUS 0x39
/* R FIFO status */
#define TAP_SIGN 0x3A
/* R Sign and source for tap/double tap */
/* Orientation ADXL346 only */
#define ORIENT_CONF 0x3B
/* R/W Orientation configuration */
#define ORIENT 0x3C
/* R Orientation status */
/* DEVIDs */
#define ID_ADXL345 0xE5
#define ID_ADXL346 0xE6
/* INT_ENABLE/INT_MAP/INT_SOURCE Bits */
#define DATA_READY (1 << 7)
#define SINGLE_TAP (1 << 6)
#define DOUBLE_TAP (1 << 5)
#define ACTIVITY (1 << 4)
#define INACTIVITY (1 << 3)
#define FREE_FALL (1 << 2)
#define WATERMARK (1 << 1)
#define OVERRUN (1 << 0)
/* ACT_INACT_CONTROL Bits */
#define ACT_ACDC (1 << 7)
#define ACT_X_EN (1 << 6)
#define ACT_Y_EN (1 << 5)
#define ACT_Z_EN (1 << 4)
#define INACT_ACDC (1 << 3)
#define INACT_X_EN (1 << 2)
#define INACT_Y_EN (1 << 1)
#define INACT_Z_EN (1 << 0)
/* TAP_AXES Bits */
#define SUPPRESS (1 << 3)
#define TAP_X_EN (1 << 2)
#define TAP_Y_EN (1 << 1)
#define TAP_Z_EN (1 << 0)
/* ACT_TAP_STATUS Bits */
#define ACT_X_SRC (1 << 6)
#define ACT_Y_SRC (1 << 5)
#define ACT_Z_SRC (1 << 4)
#define ASLEEP (1 << 3)
#define TAP_X_SRC (1 << 2)
#define TAP_Y_SRC (1 << 1)
#define TAP_Z_SRC (1 << 0)
/* BW_RATE Bits */
#define LOW_POWER (1 << 4)
#define RATE(x) ((x) & 0xF)
/* POWER_CTL Bits */
#define PCTL_LINK (1 << 5)
#define PCTL_AUTO_SLEEP (1 << 4)
#define PCTL_MEASURE (1 << 3)
#define PCTL_SLEEP (1 << 2)
#define PCTL_WAKEUP(x) ((x) & 0x3)
/* DATA_FORMAT Bits */
#define SELF_TEST (1 << 7)
#define SPI (1 << 6)
#define INT_INVERT (1 << 5)
#define FULL_RES (1 << 3)
#define JUSTIFY (1 << 2)
#define RANGE(x) ((x) & 0x3)
#define RANGE_PM_2g 0
#define RANGE_PM_4g 1
#define RANGE_PM_8g 2
#define RANGE_PM_16g 3
/*
* Maximum value our axis may get in full res mode for the input device
* (signed 13 bits)
*/
#define ADXL_FULLRES_MAX_VAL 4096
/*
* Maximum value our axis may get in fixed res mode for the input device
* (signed 10 bits)
*/
#define ADXL_FIXEDRES_MAX_VAL 512
/* FIFO_CTL Bits */
#define FIFO_MODE(x) (((x) & 0x3) << 6)
#define FIFO_BYPASS 0
#define FIFO_FIFO 1
#define FIFO_STREAM 2
#define FIFO_TRIGGER 3
#define TRIGGER (1 << 5)
#define SAMPLES(x) ((x) & 0x1F)
/* FIFO_STATUS Bits */
#define FIFO_TRIG (1 << 7)
#define ENTRIES(x) ((x) & 0x3F)
/* TAP_SIGN Bits ADXL346 only */
#define XSIGN (1 << 6)
#define YSIGN (1 << 5)
#define ZSIGN (1 << 4)
#define XTAP (1 << 3)
#define YTAP (1 << 2)
#define ZTAP (1 << 1)
/* ORIENT_CONF ADXL346 only */
#define ORIENT_DEADZONE(x) (((x) & 0x7) << 4)
#define ORIENT_DIVISOR(x) ((x) & 0x7)
/* ORIENT ADXL346 only */
#define ADXL346_2D_VALID (1 << 6)
#define ADXL346_2D_ORIENT(x) (((x) & 0x3) >> 4)
#define ADXL346_3D_VALID (1 << 3)
#define ADXL346_3D_ORIENT(x) ((x) & 0x7)
#define ADXL346_2D_PORTRAIT_POS 0
/* +X */
#define ADXL346_2D_PORTRAIT_NEG 1
/* -X */
#define ADXL346_2D_LANDSCAPE_POS 2
/* +Y */
#define ADXL346_2D_LANDSCAPE_NEG 3
/* -Y */
#define ADXL346_3D_FRONT 3
/* +X */
#define ADXL346_3D_BACK 4
/* -X */
#define ADXL346_3D_RIGHT 2
/* +Y */
#define ADXL346_3D_LEFT 5
/* -Y */
#define ADXL346_3D_TOP 1
/* +Z */
#define ADXL346_3D_BOTTOM 6
/* -Z */
#undef ADXL_DEBUG
#define ADXL_X_AXIS 0
#define ADXL_Y_AXIS 1
#define ADXL_Z_AXIS 2
#define AC_READ(ac, reg) ((ac)->bops->read((ac)->dev, reg))
#define AC_WRITE(ac, reg, val) ((ac)->bops->write((ac)->dev, reg, val))
struct
axis_triple
{
int
x
;
int
y
;
int
z
;
};
struct
adxl34x
{
struct
device
*
dev
;
struct
input_dev
*
input
;
struct
mutex
mutex
;
/* reentrant protection for struct */
struct
adxl34x_platform_data
pdata
;
struct
axis_triple
swcal
;
struct
axis_triple
hwcal
;
struct
axis_triple
saved
;
char
phys
[
32
];
unsigned
orient2d_saved
;
unsigned
orient3d_saved
;
bool
disabled
;
/* P: mutex */
bool
opened
;
/* P: mutex */
bool
suspended
;
/* P: mutex */
bool
fifo_delay
;
int
irq
;
unsigned
model
;
unsigned
int_mask
;
const
struct
adxl34x_bus_ops
*
bops
;
};
static
const
struct
adxl34x_platform_data
adxl34x_default_init
=
{
.
tap_threshold
=
35
,
.
tap_duration
=
3
,
.
tap_latency
=
20
,
.
tap_window
=
20
,
.
tap_axis_control
=
ADXL_TAP_X_EN
|
ADXL_TAP_Y_EN
|
ADXL_TAP_Z_EN
,
.
act_axis_control
=
0xFF
,
.
activity_threshold
=
6
,
.
inactivity_threshold
=
4
,
.
inactivity_time
=
3
,
.
free_fall_threshold
=
8
,
.
free_fall_time
=
0x20
,
.
data_rate
=
8
,
.
data_range
=
ADXL_FULL_RES
,
.
ev_type
=
EV_ABS
,
.
ev_code_x
=
ABS_X
,
/* EV_REL */
.
ev_code_y
=
ABS_Y
,
/* EV_REL */
.
ev_code_z
=
ABS_Z
,
/* EV_REL */
.
ev_code_tap
=
{
BTN_TOUCH
,
BTN_TOUCH
,
BTN_TOUCH
},
/* EV_KEY {x,y,z} */
.
power_mode
=
ADXL_AUTO_SLEEP
|
ADXL_LINK
,
.
fifo_mode
=
FIFO_STREAM
,
.
watermark
=
0
,
};
static
void
adxl34x_get_triple
(
struct
adxl34x
*
ac
,
struct
axis_triple
*
axis
)
{
short
buf
[
3
];
ac
->
bops
->
read_block
(
ac
->
dev
,
DATAX0
,
DATAZ1
-
DATAX0
+
1
,
buf
);
mutex_lock
(
&
ac
->
mutex
);
ac
->
saved
.
x
=
(
s16
)
le16_to_cpu
(
buf
[
0
]);
axis
->
x
=
ac
->
saved
.
x
;
ac
->
saved
.
y
=
(
s16
)
le16_to_cpu
(
buf
[
1
]);
axis
->
y
=
ac
->
saved
.
y
;
ac
->
saved
.
z
=
(
s16
)
le16_to_cpu
(
buf
[
2
]);
axis
->
z
=
ac
->
saved
.
z
;
mutex_unlock
(
&
ac
->
mutex
);
}
static
void
adxl34x_service_ev_fifo
(
struct
adxl34x
*
ac
)
{
struct
adxl34x_platform_data
*
pdata
=
&
ac
->
pdata
;
struct
axis_triple
axis
;
adxl34x_get_triple
(
ac
,
&
axis
);
input_event
(
ac
->
input
,
pdata
->
ev_type
,
pdata
->
ev_code_x
,
axis
.
x
-
ac
->
swcal
.
x
);
input_event
(
ac
->
input
,
pdata
->
ev_type
,
pdata
->
ev_code_y
,
axis
.
y
-
ac
->
swcal
.
y
);
input_event
(
ac
->
input
,
pdata
->
ev_type
,
pdata
->
ev_code_z
,
axis
.
z
-
ac
->
swcal
.
z
);
}
static
void
adxl34x_report_key_single
(
struct
input_dev
*
input
,
int
key
)
{
input_report_key
(
input
,
key
,
true
);
input_sync
(
input
);
input_report_key
(
input
,
key
,
false
);
}
static
void
adxl34x_send_key_events
(
struct
adxl34x
*
ac
,
struct
adxl34x_platform_data
*
pdata
,
int
status
,
int
press
)
{
int
i
;
for
(
i
=
ADXL_X_AXIS
;
i
<=
ADXL_Z_AXIS
;
i
++
)
{
if
(
status
&
(
1
<<
(
ADXL_Z_AXIS
-
i
)))
input_report_key
(
ac
->
input
,
pdata
->
ev_code_tap
[
i
],
press
);
}
}
static
void
adxl34x_do_tap
(
struct
adxl34x
*
ac
,
struct
adxl34x_platform_data
*
pdata
,
int
status
)
{
adxl34x_send_key_events
(
ac
,
pdata
,
status
,
true
);
input_sync
(
ac
->
input
);
adxl34x_send_key_events
(
ac
,
pdata
,
status
,
false
);
}
static
irqreturn_t
adxl34x_irq
(
int
irq
,
void
*
handle
)
{
struct
adxl34x
*
ac
=
handle
;
struct
adxl34x_platform_data
*
pdata
=
&
ac
->
pdata
;
int
int_stat
,
tap_stat
,
samples
,
orient
,
orient_code
;
/*
* ACT_TAP_STATUS should be read before clearing the interrupt
* Avoid reading ACT_TAP_STATUS in case TAP detection is disabled
*/
if
(
pdata
->
tap_axis_control
&
(
TAP_X_EN
|
TAP_Y_EN
|
TAP_Z_EN
))
tap_stat
=
AC_READ
(
ac
,
ACT_TAP_STATUS
);
else
tap_stat
=
0
;
int_stat
=
AC_READ
(
ac
,
INT_SOURCE
);
if
(
int_stat
&
FREE_FALL
)
adxl34x_report_key_single
(
ac
->
input
,
pdata
->
ev_code_ff
);
if
(
int_stat
&
OVERRUN
)
dev_dbg
(
ac
->
dev
,
"OVERRUN
\n
"
);
if
(
int_stat
&
(
SINGLE_TAP
|
DOUBLE_TAP
))
{
adxl34x_do_tap
(
ac
,
pdata
,
tap_stat
);
if
(
int_stat
&
DOUBLE_TAP
)
adxl34x_do_tap
(
ac
,
pdata
,
tap_stat
);
}
if
(
pdata
->
ev_code_act_inactivity
)
{
if
(
int_stat
&
ACTIVITY
)
input_report_key
(
ac
->
input
,
pdata
->
ev_code_act_inactivity
,
1
);
if
(
int_stat
&
INACTIVITY
)
input_report_key
(
ac
->
input
,
pdata
->
ev_code_act_inactivity
,
0
);
}
/*
* ORIENTATION SENSING ADXL346 only
*/
if
(
pdata
->
orientation_enable
)
{
orient
=
AC_READ
(
ac
,
ORIENT
);
if
((
pdata
->
orientation_enable
&
ADXL_EN_ORIENTATION_2D
)
&&
(
orient
&
ADXL346_2D_VALID
))
{
orient_code
=
ADXL346_2D_ORIENT
(
orient
);
/* Report orientation only when it changes */
if
(
ac
->
orient2d_saved
!=
orient_code
)
{
ac
->
orient2d_saved
=
orient_code
;
adxl34x_report_key_single
(
ac
->
input
,
pdata
->
ev_codes_orient_2d
[
orient_code
]);
}
}
if
((
pdata
->
orientation_enable
&
ADXL_EN_ORIENTATION_3D
)
&&
(
orient
&
ADXL346_3D_VALID
))
{
orient_code
=
ADXL346_3D_ORIENT
(
orient
)
-
1
;
/* Report orientation only when it changes */
if
(
ac
->
orient3d_saved
!=
orient_code
)
{
ac
->
orient3d_saved
=
orient_code
;
adxl34x_report_key_single
(
ac
->
input
,
pdata
->
ev_codes_orient_3d
[
orient_code
]);
}
}
}
if
(
int_stat
&
(
DATA_READY
|
WATERMARK
))
{
if
(
pdata
->
fifo_mode
)
samples
=
ENTRIES
(
AC_READ
(
ac
,
FIFO_STATUS
))
+
1
;
else
samples
=
1
;
for
(;
samples
>
0
;
samples
--
)
{
adxl34x_service_ev_fifo
(
ac
);
/*
* To ensure that the FIFO has
* completely popped, there must be at least 5 us between
* the end of reading the data registers, signified by the
* transition to register 0x38 from 0x37 or the CS pin
* going high, and the start of new reads of the FIFO or
* reading the FIFO_STATUS register. For SPI operation at
* 1.5 MHz or lower, the register addressing portion of the
* transmission is sufficient delay to ensure the FIFO has
* completely popped. It is necessary for SPI operation
* greater than 1.5 MHz to de-assert the CS pin to ensure a
* total of 5 us, which is at most 3.4 us at 5 MHz
* operation.
*/
if
(
ac
->
fifo_delay
&&
(
samples
>
1
))
udelay
(
3
);
}
}
input_sync
(
ac
->
input
);
return
IRQ_HANDLED
;
}
static
void
__adxl34x_disable
(
struct
adxl34x
*
ac
)
{
/*
* A '0' places the ADXL34x into standby mode
* with minimum power consumption.
*/
AC_WRITE
(
ac
,
POWER_CTL
,
0
);
}
static
void
__adxl34x_enable
(
struct
adxl34x
*
ac
)
{
AC_WRITE
(
ac
,
POWER_CTL
,
ac
->
pdata
.
power_mode
|
PCTL_MEASURE
);
}
void
adxl34x_suspend
(
struct
adxl34x
*
ac
)
{
mutex_lock
(
&
ac
->
mutex
);
if
(
!
ac
->
suspended
&&
!
ac
->
disabled
&&
ac
->
opened
)
__adxl34x_disable
(
ac
);
ac
->
suspended
=
true
;
mutex_unlock
(
&
ac
->
mutex
);
}
EXPORT_SYMBOL_GPL
(
adxl34x_suspend
);
void
adxl34x_resume
(
struct
adxl34x
*
ac
)
{
mutex_lock
(
&
ac
->
mutex
);
if
(
ac
->
suspended
&&
!
ac
->
disabled
&&
ac
->
opened
)
__adxl34x_enable
(
ac
);
ac
->
suspended
=
false
;
mutex_unlock
(
&
ac
->
mutex
);
}
EXPORT_SYMBOL_GPL
(
adxl34x_resume
);
static
ssize_t
adxl34x_disable_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
adxl34x
*
ac
=
dev_get_drvdata
(
dev
);
return
sprintf
(
buf
,
"%u
\n
"
,
ac
->
disabled
);
}
static
ssize_t
adxl34x_disable_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
struct
adxl34x
*
ac
=
dev_get_drvdata
(
dev
);
unsigned
long
val
;
int
error
;
error
=
strict_strtoul
(
buf
,
10
,
&
val
);
if
(
error
)
return
error
;
mutex_lock
(
&
ac
->
mutex
);
if
(
!
ac
->
suspended
&&
ac
->
opened
)
{
if
(
val
)
{
if
(
!
ac
->
disabled
)
__adxl34x_disable
(
ac
);
}
else
{
if
(
ac
->
disabled
)
__adxl34x_enable
(
ac
);
}
}
ac
->
disabled
=
!!
val
;
mutex_unlock
(
&
ac
->
mutex
);
return
count
;
}
static
DEVICE_ATTR
(
disable
,
0664
,
adxl34x_disable_show
,
adxl34x_disable_store
);
static
ssize_t
adxl34x_calibrate_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
adxl34x
*
ac
=
dev_get_drvdata
(
dev
);
ssize_t
count
;
mutex_lock
(
&
ac
->
mutex
);
count
=
sprintf
(
buf
,
"%d,%d,%d
\n
"
,
ac
->
hwcal
.
x
*
4
+
ac
->
swcal
.
x
,
ac
->
hwcal
.
y
*
4
+
ac
->
swcal
.
y
,
ac
->
hwcal
.
z
*
4
+
ac
->
swcal
.
z
);
mutex_unlock
(
&
ac
->
mutex
);
return
count
;
}
static
ssize_t
adxl34x_calibrate_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
struct
adxl34x
*
ac
=
dev_get_drvdata
(
dev
);
/*
* Hardware offset calibration has a resolution of 15.6 mg/LSB.
* We use HW calibration and handle the remaining bits in SW. (4mg/LSB)
*/
mutex_lock
(
&
ac
->
mutex
);
ac
->
hwcal
.
x
-=
(
ac
->
saved
.
x
/
4
);
ac
->
swcal
.
x
=
ac
->
saved
.
x
%
4
;
ac
->
hwcal
.
y
-=
(
ac
->
saved
.
y
/
4
);
ac
->
swcal
.
y
=
ac
->
saved
.
y
%
4
;
ac
->
hwcal
.
z
-=
(
ac
->
saved
.
z
/
4
);
ac
->
swcal
.
z
=
ac
->
saved
.
z
%
4
;
AC_WRITE
(
ac
,
OFSX
,
(
s8
)
ac
->
hwcal
.
x
);
AC_WRITE
(
ac
,
OFSY
,
(
s8
)
ac
->
hwcal
.
y
);
AC_WRITE
(
ac
,
OFSZ
,
(
s8
)
ac
->
hwcal
.
z
);
mutex_unlock
(
&
ac
->
mutex
);
return
count
;
}
static
DEVICE_ATTR
(
calibrate
,
0664
,
adxl34x_calibrate_show
,
adxl34x_calibrate_store
);
static
ssize_t
adxl34x_rate_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
adxl34x
*
ac
=
dev_get_drvdata
(
dev
);
return
sprintf
(
buf
,
"%u
\n
"
,
RATE
(
ac
->
pdata
.
data_rate
));
}
static
ssize_t
adxl34x_rate_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
struct
adxl34x
*
ac
=
dev_get_drvdata
(
dev
);
unsigned
long
val
;
int
error
;
error
=
strict_strtoul
(
buf
,
10
,
&
val
);
if
(
error
)
return
error
;
mutex_lock
(
&
ac
->
mutex
);
ac
->
pdata
.
data_rate
=
RATE
(
val
);
AC_WRITE
(
ac
,
BW_RATE
,
ac
->
pdata
.
data_rate
|
(
ac
->
pdata
.
low_power_mode
?
LOW_POWER
:
0
));
mutex_unlock
(
&
ac
->
mutex
);
return
count
;
}
static
DEVICE_ATTR
(
rate
,
0664
,
adxl34x_rate_show
,
adxl34x_rate_store
);
static
ssize_t
adxl34x_autosleep_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
adxl34x
*
ac
=
dev_get_drvdata
(
dev
);
return
sprintf
(
buf
,
"%u
\n
"
,
ac
->
pdata
.
power_mode
&
(
PCTL_AUTO_SLEEP
|
PCTL_LINK
)
?
1
:
0
);
}
static
ssize_t
adxl34x_autosleep_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
struct
adxl34x
*
ac
=
dev_get_drvdata
(
dev
);
unsigned
long
val
;
int
error
;
error
=
strict_strtoul
(
buf
,
10
,
&
val
);
if
(
error
)
return
error
;
mutex_lock
(
&
ac
->
mutex
);
if
(
val
)
ac
->
pdata
.
power_mode
|=
(
PCTL_AUTO_SLEEP
|
PCTL_LINK
);
else
ac
->
pdata
.
power_mode
&=
~
(
PCTL_AUTO_SLEEP
|
PCTL_LINK
);
if
(
!
ac
->
disabled
&&
!
ac
->
suspended
&&
ac
->
opened
)
AC_WRITE
(
ac
,
POWER_CTL
,
ac
->
pdata
.
power_mode
|
PCTL_MEASURE
);
mutex_unlock
(
&
ac
->
mutex
);
return
count
;
}
static
DEVICE_ATTR
(
autosleep
,
0664
,
adxl34x_autosleep_show
,
adxl34x_autosleep_store
);
static
ssize_t
adxl34x_position_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
adxl34x
*
ac
=
dev_get_drvdata
(
dev
);
ssize_t
count
;
mutex_lock
(
&
ac
->
mutex
);
count
=
sprintf
(
buf
,
"(%d, %d, %d)
\n
"
,
ac
->
saved
.
x
,
ac
->
saved
.
y
,
ac
->
saved
.
z
);
mutex_unlock
(
&
ac
->
mutex
);
return
count
;
}
static
DEVICE_ATTR
(
position
,
S_IRUGO
,
adxl34x_position_show
,
NULL
);
#ifdef ADXL_DEBUG
static
ssize_t
adxl34x_write_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
struct
adxl34x
*
ac
=
dev_get_drvdata
(
dev
);
unsigned
long
val
;
int
error
;
/*
* This allows basic ADXL register write access for debug purposes.
*/
error
=
strict_strtoul
(
buf
,
16
,
&
val
);
if
(
error
)
return
error
;
mutex_lock
(
&
ac
->
mutex
);
AC_WRITE
(
ac
,
val
>>
8
,
val
&
0xFF
);
mutex_unlock
(
&
ac
->
mutex
);
return
count
;
}
static
DEVICE_ATTR
(
write
,
0664
,
NULL
,
adxl34x_write_store
);
#endif
static
struct
attribute
*
adxl34x_attributes
[]
=
{
&
dev_attr_disable
.
attr
,
&
dev_attr_calibrate
.
attr
,
&
dev_attr_rate
.
attr
,
&
dev_attr_autosleep
.
attr
,
&
dev_attr_position
.
attr
,
#ifdef ADXL_DEBUG
&
dev_attr_write
.
attr
,
#endif
NULL
};
static
const
struct
attribute_group
adxl34x_attr_group
=
{
.
attrs
=
adxl34x_attributes
,
};
static
int
adxl34x_input_open
(
struct
input_dev
*
input
)
{
struct
adxl34x
*
ac
=
input_get_drvdata
(
input
);
mutex_lock
(
&
ac
->
mutex
);
if
(
!
ac
->
suspended
&&
!
ac
->
disabled
)
__adxl34x_enable
(
ac
);
ac
->
opened
=
true
;
mutex_unlock
(
&
ac
->
mutex
);
return
0
;
}
static
void
adxl34x_input_close
(
struct
input_dev
*
input
)
{
struct
adxl34x
*
ac
=
input_get_drvdata
(
input
);
mutex_lock
(
&
ac
->
mutex
);
if
(
!
ac
->
suspended
&&
!
ac
->
disabled
)
__adxl34x_disable
(
ac
);
ac
->
opened
=
false
;
mutex_unlock
(
&
ac
->
mutex
);
}
struct
adxl34x
*
adxl34x_probe
(
struct
device
*
dev
,
int
irq
,
bool
fifo_delay_default
,
const
struct
adxl34x_bus_ops
*
bops
)
{
struct
adxl34x
*
ac
;
struct
input_dev
*
input_dev
;
const
struct
adxl34x_platform_data
*
pdata
;
int
err
,
range
,
i
;
unsigned
char
revid
;
if
(
!
irq
)
{
dev_err
(
dev
,
"no IRQ?
\n
"
);
err
=
-
ENODEV
;
goto
err_out
;
}
ac
=
kzalloc
(
sizeof
(
*
ac
),
GFP_KERNEL
);
input_dev
=
input_allocate_device
();
if
(
!
ac
||
!
input_dev
)
{
err
=
-
ENOMEM
;
goto
err_free_mem
;
}
ac
->
fifo_delay
=
fifo_delay_default
;
pdata
=
dev
->
platform_data
;
if
(
!
pdata
)
{
dev_dbg
(
dev
,
"No platfrom data: Using default initialization
\n
"
);
pdata
=
&
adxl34x_default_init
;
}
ac
->
pdata
=
*
pdata
;
pdata
=
&
ac
->
pdata
;
ac
->
input
=
input_dev
;
ac
->
disabled
=
true
;
ac
->
dev
=
dev
;
ac
->
irq
=
irq
;
ac
->
bops
=
bops
;
mutex_init
(
&
ac
->
mutex
);
input_dev
->
name
=
"ADXL34x accelerometer"
;
revid
=
ac
->
bops
->
read
(
dev
,
DEVID
);
switch
(
revid
)
{
case
ID_ADXL345
:
ac
->
model
=
345
;
break
;
case
ID_ADXL346
:
ac
->
model
=
346
;
break
;
default:
dev_err
(
dev
,
"Failed to probe %s
\n
"
,
input_dev
->
name
);
err
=
-
ENODEV
;
goto
err_free_mem
;
}
snprintf
(
ac
->
phys
,
sizeof
(
ac
->
phys
),
"%s/input0"
,
dev_name
(
dev
));
input_dev
->
phys
=
ac
->
phys
;
input_dev
->
dev
.
parent
=
dev
;
input_dev
->
id
.
product
=
ac
->
model
;
input_dev
->
id
.
bustype
=
bops
->
bustype
;
input_dev
->
open
=
adxl34x_input_open
;
input_dev
->
close
=
adxl34x_input_close
;
input_set_drvdata
(
input_dev
,
ac
);
__set_bit
(
ac
->
pdata
.
ev_type
,
input_dev
->
evbit
);
if
(
ac
->
pdata
.
ev_type
==
EV_REL
)
{
__set_bit
(
REL_X
,
input_dev
->
relbit
);
__set_bit
(
REL_Y
,
input_dev
->
relbit
);
__set_bit
(
REL_Z
,
input_dev
->
relbit
);
}
else
{
/* EV_ABS */
__set_bit
(
ABS_X
,
input_dev
->
absbit
);
__set_bit
(
ABS_Y
,
input_dev
->
absbit
);
__set_bit
(
ABS_Z
,
input_dev
->
absbit
);
if
(
pdata
->
data_range
&
FULL_RES
)
range
=
ADXL_FULLRES_MAX_VAL
;
/* Signed 13-bit */
else
range
=
ADXL_FIXEDRES_MAX_VAL
;
/* Signed 10-bit */
input_set_abs_params
(
input_dev
,
ABS_X
,
-
range
,
range
,
3
,
3
);
input_set_abs_params
(
input_dev
,
ABS_Y
,
-
range
,
range
,
3
,
3
);
input_set_abs_params
(
input_dev
,
ABS_Z
,
-
range
,
range
,
3
,
3
);
}
__set_bit
(
EV_KEY
,
input_dev
->
evbit
);
__set_bit
(
pdata
->
ev_code_tap
[
ADXL_X_AXIS
],
input_dev
->
keybit
);
__set_bit
(
pdata
->
ev_code_tap
[
ADXL_Y_AXIS
],
input_dev
->
keybit
);
__set_bit
(
pdata
->
ev_code_tap
[
ADXL_Z_AXIS
],
input_dev
->
keybit
);
if
(
pdata
->
ev_code_ff
)
{
ac
->
int_mask
=
FREE_FALL
;
__set_bit
(
pdata
->
ev_code_ff
,
input_dev
->
keybit
);
}
if
(
pdata
->
ev_code_act_inactivity
)
__set_bit
(
pdata
->
ev_code_act_inactivity
,
input_dev
->
keybit
);
ac
->
int_mask
|=
ACTIVITY
|
INACTIVITY
;
if
(
pdata
->
watermark
)
{
ac
->
int_mask
|=
WATERMARK
;
if
(
!
FIFO_MODE
(
pdata
->
fifo_mode
))
ac
->
pdata
.
fifo_mode
|=
FIFO_STREAM
;
}
else
{
ac
->
int_mask
|=
DATA_READY
;
}
if
(
pdata
->
tap_axis_control
&
(
TAP_X_EN
|
TAP_Y_EN
|
TAP_Z_EN
))
ac
->
int_mask
|=
SINGLE_TAP
|
DOUBLE_TAP
;
if
(
FIFO_MODE
(
pdata
->
fifo_mode
)
==
FIFO_BYPASS
)
ac
->
fifo_delay
=
false
;
ac
->
bops
->
write
(
dev
,
POWER_CTL
,
0
);
err
=
request_threaded_irq
(
ac
->
irq
,
NULL
,
adxl34x_irq
,
IRQF_TRIGGER_HIGH
|
IRQF_ONESHOT
,
dev_name
(
dev
),
ac
);
if
(
err
)
{
dev_err
(
dev
,
"irq %d busy?
\n
"
,
ac
->
irq
);
goto
err_free_mem
;
}
err
=
sysfs_create_group
(
&
dev
->
kobj
,
&
adxl34x_attr_group
);
if
(
err
)
goto
err_free_irq
;
err
=
input_register_device
(
input_dev
);
if
(
err
)
goto
err_remove_attr
;
AC_WRITE
(
ac
,
THRESH_TAP
,
pdata
->
tap_threshold
);
AC_WRITE
(
ac
,
OFSX
,
pdata
->
x_axis_offset
);
ac
->
hwcal
.
x
=
pdata
->
x_axis_offset
;
AC_WRITE
(
ac
,
OFSY
,
pdata
->
y_axis_offset
);
ac
->
hwcal
.
y
=
pdata
->
y_axis_offset
;
AC_WRITE
(
ac
,
OFSZ
,
pdata
->
z_axis_offset
);
ac
->
hwcal
.
z
=
pdata
->
z_axis_offset
;
AC_WRITE
(
ac
,
THRESH_TAP
,
pdata
->
tap_threshold
);
AC_WRITE
(
ac
,
DUR
,
pdata
->
tap_duration
);
AC_WRITE
(
ac
,
LATENT
,
pdata
->
tap_latency
);
AC_WRITE
(
ac
,
WINDOW
,
pdata
->
tap_window
);
AC_WRITE
(
ac
,
THRESH_ACT
,
pdata
->
activity_threshold
);
AC_WRITE
(
ac
,
THRESH_INACT
,
pdata
->
inactivity_threshold
);
AC_WRITE
(
ac
,
TIME_INACT
,
pdata
->
inactivity_time
);
AC_WRITE
(
ac
,
THRESH_FF
,
pdata
->
free_fall_threshold
);
AC_WRITE
(
ac
,
TIME_FF
,
pdata
->
free_fall_time
);
AC_WRITE
(
ac
,
TAP_AXES
,
pdata
->
tap_axis_control
);
AC_WRITE
(
ac
,
ACT_INACT_CTL
,
pdata
->
act_axis_control
);
AC_WRITE
(
ac
,
BW_RATE
,
RATE
(
ac
->
pdata
.
data_rate
)
|
(
pdata
->
low_power_mode
?
LOW_POWER
:
0
));
AC_WRITE
(
ac
,
DATA_FORMAT
,
pdata
->
data_range
);
AC_WRITE
(
ac
,
FIFO_CTL
,
FIFO_MODE
(
pdata
->
fifo_mode
)
|
SAMPLES
(
pdata
->
watermark
));
if
(
pdata
->
use_int2
)
{
/* Map all INTs to INT2 */
AC_WRITE
(
ac
,
INT_MAP
,
ac
->
int_mask
|
OVERRUN
);
}
else
{
/* Map all INTs to INT1 */
AC_WRITE
(
ac
,
INT_MAP
,
0
);
}
if
(
ac
->
model
==
346
&&
ac
->
pdata
.
orientation_enable
)
{
AC_WRITE
(
ac
,
ORIENT_CONF
,
ORIENT_DEADZONE
(
ac
->
pdata
.
deadzone_angle
)
|
ORIENT_DIVISOR
(
ac
->
pdata
.
divisor_length
));
ac
->
orient2d_saved
=
1234
;
ac
->
orient3d_saved
=
1234
;
if
(
pdata
->
orientation_enable
&
ADXL_EN_ORIENTATION_3D
)
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
pdata
->
ev_codes_orient_3d
);
i
++
)
__set_bit
(
pdata
->
ev_codes_orient_3d
[
i
],
input_dev
->
keybit
);
if
(
pdata
->
orientation_enable
&
ADXL_EN_ORIENTATION_2D
)
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
pdata
->
ev_codes_orient_2d
);
i
++
)
__set_bit
(
pdata
->
ev_codes_orient_2d
[
i
],
input_dev
->
keybit
);
}
else
{
ac
->
pdata
.
orientation_enable
=
0
;
}
AC_WRITE
(
ac
,
INT_ENABLE
,
ac
->
int_mask
|
OVERRUN
);
ac
->
pdata
.
power_mode
&=
(
PCTL_AUTO_SLEEP
|
PCTL_LINK
);
return
ac
;
err_remove_attr:
sysfs_remove_group
(
&
dev
->
kobj
,
&
adxl34x_attr_group
);
err_free_irq:
free_irq
(
ac
->
irq
,
ac
);
err_free_mem:
input_free_device
(
input_dev
);
kfree
(
ac
);
err_out:
return
ERR_PTR
(
err
);
}
EXPORT_SYMBOL_GPL
(
adxl34x_probe
);
int
adxl34x_remove
(
struct
adxl34x
*
ac
)
{
sysfs_remove_group
(
&
ac
->
dev
->
kobj
,
&
adxl34x_attr_group
);
free_irq
(
ac
->
irq
,
ac
);
input_unregister_device
(
ac
->
input
);
dev_dbg
(
ac
->
dev
,
"unregistered accelerometer
\n
"
);
kfree
(
ac
);
return
0
;
}
EXPORT_SYMBOL_GPL
(
adxl34x_remove
);
MODULE_AUTHOR
(
"Michael Hennerich <hennerich@blackfin.uclinux.org>"
);
MODULE_DESCRIPTION
(
"ADXL345/346 Three-Axis Digital Accelerometer Driver"
);
MODULE_LICENSE
(
"GPL"
);
drivers/input/misc/adxl34x.h
0 → 100644
View file @
929343ef
/*
* ADXL345/346 Three-Axis Digital Accelerometers (I2C/SPI Interface)
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
* Licensed under the GPL-2 or later.
*/
#ifndef _ADXL34X_H_
#define _ADXL34X_H_
struct
device
;
struct
adxl34x
;
struct
adxl34x_bus_ops
{
u16
bustype
;
int
(
*
read
)(
struct
device
*
,
unsigned
char
);
int
(
*
read_block
)(
struct
device
*
,
unsigned
char
,
int
,
void
*
);
int
(
*
write
)(
struct
device
*
,
unsigned
char
,
unsigned
char
);
};
void
adxl34x_suspend
(
struct
adxl34x
*
ac
);
void
adxl34x_resume
(
struct
adxl34x
*
ac
);
struct
adxl34x
*
adxl34x_probe
(
struct
device
*
dev
,
int
irq
,
bool
fifo_delay_default
,
const
struct
adxl34x_bus_ops
*
bops
);
int
adxl34x_remove
(
struct
adxl34x
*
ac
);
#endif
drivers/input/misc/atlas_btns.c
View file @
929343ef
...
...
@@ -21,6 +21,8 @@
*
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
...
...
@@ -60,12 +62,11 @@ static acpi_status acpi_atlas_button_handler(u32 function,
input_report_key
(
input_dev
,
atlas_keymap
[
code
],
key_down
);
input_sync
(
input_dev
);
status
=
0
;
status
=
AE_OK
;
}
else
{
printk
(
KERN_WARNING
"atlas: shrugged on unexpected function"
":function=%x,address=%lx,value=%x
\n
"
,
pr_warn
(
"shrugged on unexpected function: function=%x,address=%lx,value=%x
\n
"
,
function
,
(
unsigned
long
)
address
,
(
u32
)
*
value
);
status
=
-
EINVAL
;
status
=
AE_BAD_PARAMETER
;
}
return
status
;
...
...
@@ -79,7 +80,7 @@ static int atlas_acpi_button_add(struct acpi_device *device)
input_dev
=
input_allocate_device
();
if
(
!
input_dev
)
{
pr
intk
(
KERN_ERR
"atlas:
unable to allocate input device
\n
"
);
pr
_err
(
"
unable to allocate input device
\n
"
);
return
-
ENOMEM
;
}
...
...
@@ -102,7 +103,7 @@ static int atlas_acpi_button_add(struct acpi_device *device)
err
=
input_register_device
(
input_dev
);
if
(
err
)
{
pr
intk
(
KERN_ERR
"atlas:
couldn't register input device
\n
"
);
pr
_err
(
"
couldn't register input device
\n
"
);
input_free_device
(
input_dev
);
return
err
;
}
...
...
@@ -112,12 +113,12 @@ static int atlas_acpi_button_add(struct acpi_device *device)
0x81
,
&
acpi_atlas_button_handler
,
&
acpi_atlas_button_setup
,
device
);
if
(
ACPI_FAILURE
(
status
))
{
pr
intk
(
KERN_ERR
"Atlas: E
rror installing addr spc handler
\n
"
);
pr
_err
(
"e
rror installing addr spc handler
\n
"
);
input_unregister_device
(
input_dev
);
status
=
-
EINVAL
;
err
=
-
EINVAL
;
}
return
status
;
return
err
;
}
static
int
atlas_acpi_button_remove
(
struct
acpi_device
*
device
,
int
type
)
...
...
@@ -126,14 +127,12 @@ static int atlas_acpi_button_remove(struct acpi_device *device, int type)
status
=
acpi_remove_address_space_handler
(
device
->
handle
,
0x81
,
&
acpi_atlas_button_handler
);
if
(
ACPI_FAILURE
(
status
))
{
printk
(
KERN_ERR
"Atlas: Error removing addr spc handler
\n
"
);
status
=
-
EINVAL
;
}
if
(
ACPI_FAILURE
(
status
))
pr_err
(
"error removing addr spc handler
\n
"
);
input_unregister_device
(
input_dev
);
return
status
;
return
0
;
}
static
const
struct
acpi_device_id
atlas_device_ids
[]
=
{
...
...
@@ -145,6 +144,7 @@ MODULE_DEVICE_TABLE(acpi, atlas_device_ids);
static
struct
acpi_driver
atlas_acpi_driver
=
{
.
name
=
ACPI_ATLAS_NAME
,
.
class
=
ACPI_ATLAS_CLASS
,
.
owner
=
THIS_MODULE
,
.
ids
=
atlas_device_ids
,
.
ops
=
{
.
add
=
atlas_acpi_button_add
,
...
...
@@ -154,18 +154,10 @@ static struct acpi_driver atlas_acpi_driver = {
static
int
__init
atlas_acpi_init
(
void
)
{
int
result
;
if
(
acpi_disabled
)
return
-
ENODEV
;
result
=
acpi_bus_register_driver
(
&
atlas_acpi_driver
);
if
(
result
<
0
)
{
printk
(
KERN_ERR
"Atlas ACPI: Unable to register driver
\n
"
);
return
-
ENODEV
;
}
return
0
;
return
acpi_bus_register_driver
(
&
atlas_acpi_driver
);
}
static
void
__exit
atlas_acpi_exit
(
void
)
...
...
drivers/input/misc/pwm-beeper.c
0 → 100644
View file @
929343ef
/*
* Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
* PWM beeper driver
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <linux/input.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/pwm.h>
#include <linux/slab.h>
struct
pwm_beeper
{
struct
input_dev
*
input
;
struct
pwm_device
*
pwm
;
unsigned
long
period
;
};
#define HZ_TO_NANOSECONDS(x) (1000000000UL/(x))
static
int
pwm_beeper_event
(
struct
input_dev
*
input
,
unsigned
int
type
,
unsigned
int
code
,
int
value
)
{
int
ret
=
0
;
struct
pwm_beeper
*
beeper
=
input_get_drvdata
(
input
);
unsigned
long
period
;
if
(
type
!=
EV_SND
||
value
<
0
)
return
-
EINVAL
;
switch
(
code
)
{
case
SND_BELL
:
value
=
value
?
1000
:
0
;
break
;
case
SND_TONE
:
break
;
default:
return
-
EINVAL
;
}
if
(
value
==
0
)
{
pwm_config
(
beeper
->
pwm
,
0
,
0
);
pwm_disable
(
beeper
->
pwm
);
}
else
{
period
=
HZ_TO_NANOSECONDS
(
value
);
ret
=
pwm_config
(
beeper
->
pwm
,
period
/
2
,
period
);
if
(
ret
)
return
ret
;
ret
=
pwm_enable
(
beeper
->
pwm
);
if
(
ret
)
return
ret
;
beeper
->
period
=
period
;
}
return
0
;
}
static
int
__devinit
pwm_beeper_probe
(
struct
platform_device
*
pdev
)
{
unsigned
long
pwm_id
=
(
unsigned
long
)
pdev
->
dev
.
platform_data
;
struct
pwm_beeper
*
beeper
;
int
error
;
beeper
=
kzalloc
(
sizeof
(
*
beeper
),
GFP_KERNEL
);
if
(
!
beeper
)
return
-
ENOMEM
;
beeper
->
pwm
=
pwm_request
(
pwm_id
,
"pwm beeper"
);
if
(
IS_ERR
(
beeper
->
pwm
))
{
error
=
PTR_ERR
(
beeper
->
pwm
);
dev_err
(
&
pdev
->
dev
,
"Failed to request pwm device: %d
\n
"
,
error
);
goto
err_free
;
}
beeper
->
input
=
input_allocate_device
();
if
(
!
beeper
->
input
)
{
dev_err
(
&
pdev
->
dev
,
"Failed to allocate input device
\n
"
);
error
=
-
ENOMEM
;
goto
err_pwm_free
;
}
beeper
->
input
->
dev
.
parent
=
&
pdev
->
dev
;
beeper
->
input
->
name
=
"pwm-beeper"
;
beeper
->
input
->
phys
=
"pwm/input0"
;
beeper
->
input
->
id
.
bustype
=
BUS_HOST
;
beeper
->
input
->
id
.
vendor
=
0x001f
;
beeper
->
input
->
id
.
product
=
0x0001
;
beeper
->
input
->
id
.
version
=
0x0100
;
beeper
->
input
->
evbit
[
0
]
=
BIT
(
EV_SND
);
beeper
->
input
->
sndbit
[
0
]
=
BIT
(
SND_TONE
)
|
BIT
(
SND_BELL
);
beeper
->
input
->
event
=
pwm_beeper_event
;
input_set_drvdata
(
beeper
->
input
,
beeper
);
error
=
input_register_device
(
beeper
->
input
);
if
(
error
)
{
dev_err
(
&
pdev
->
dev
,
"Failed to register input device: %d
\n
"
,
error
);
goto
err_input_free
;
}
platform_set_drvdata
(
pdev
,
beeper
);
return
0
;
err_input_free:
input_free_device
(
beeper
->
input
);
err_pwm_free:
pwm_free
(
beeper
->
pwm
);
err_free:
kfree
(
beeper
);
return
error
;
}
static
int
__devexit
pwm_beeper_remove
(
struct
platform_device
*
pdev
)
{
struct
pwm_beeper
*
beeper
=
platform_get_drvdata
(
pdev
);
platform_set_drvdata
(
pdev
,
NULL
);
input_unregister_device
(
beeper
->
input
);
pwm_disable
(
beeper
->
pwm
);
pwm_free
(
beeper
->
pwm
);
kfree
(
beeper
);
return
0
;
}
#ifdef CONFIG_PM
static
int
pwm_beeper_suspend
(
struct
device
*
dev
)
{
struct
pwm_beeper
*
beeper
=
dev_get_drvdata
(
dev
);
if
(
beeper
->
period
)
pwm_disable
(
beeper
->
pwm
);
return
0
;
}
static
int
pwm_beeper_resume
(
struct
device
*
dev
)
{
struct
pwm_beeper
*
beeper
=
dev_get_drvdata
(
dev
);
if
(
beeper
->
period
)
{
pwm_config
(
beeper
->
pwm
,
beeper
->
period
/
2
,
beeper
->
period
);
pwm_enable
(
beeper
->
pwm
);
}
return
0
;
}
static
SIMPLE_DEV_PM_OPS
(
pwm_beeper_pm_ops
,
pwm_beeper_suspend
,
pwm_beeper_resume
);
#define PWM_BEEPER_PM_OPS (&pwm_beeper_pm_ops)
#else
#define PWM_BEEPER_PM_OPS NULL
#endif
static
struct
platform_driver
pwm_beeper_driver
=
{
.
probe
=
pwm_beeper_probe
,
.
remove
=
__devexit_p
(
pwm_beeper_remove
),
.
driver
=
{
.
name
=
"pwm-beeper"
,
.
owner
=
THIS_MODULE
,
.
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_AUTHOR
(
"Lars-Peter Clausen <lars@metafoo.de>"
);
MODULE_DESCRIPTION
(
"PWM beeper driver"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_ALIAS
(
"platform:pwm-beeper"
);
drivers/input/misc/twl4030-pwrbutton.c
View file @
929343ef
...
...
@@ -52,7 +52,7 @@ static irqreturn_t powerbutton_irq(int irq, void *_pwr)
return
IRQ_HANDLED
;
}
static
int
__
dev
init
twl4030_pwrbutton_probe
(
struct
platform_device
*
pdev
)
static
int
__init
twl4030_pwrbutton_probe
(
struct
platform_device
*
pdev
)
{
struct
input_dev
*
pwr
;
int
irq
=
platform_get_irq
(
pdev
,
0
);
...
...
@@ -95,7 +95,7 @@ static int __devinit twl4030_pwrbutton_probe(struct platform_device *pdev)
return
err
;
}
static
int
__
dev
exit
twl4030_pwrbutton_remove
(
struct
platform_device
*
pdev
)
static
int
__exit
twl4030_pwrbutton_remove
(
struct
platform_device
*
pdev
)
{
struct
input_dev
*
pwr
=
platform_get_drvdata
(
pdev
);
int
irq
=
platform_get_irq
(
pdev
,
0
);
...
...
@@ -106,9 +106,8 @@ static int __devexit twl4030_pwrbutton_remove(struct platform_device *pdev)
return
0
;
}
struct
platform_driver
twl4030_pwrbutton_driver
=
{
.
probe
=
twl4030_pwrbutton_probe
,
.
remove
=
__devexit_p
(
twl4030_pwrbutton_remove
),
static
struct
platform_driver
twl4030_pwrbutton_driver
=
{
.
remove
=
__exit_p
(
twl4030_pwrbutton_remove
),
.
driver
=
{
.
name
=
"twl4030_pwrbutton"
,
.
owner
=
THIS_MODULE
,
...
...
@@ -117,7 +116,8 @@ struct platform_driver twl4030_pwrbutton_driver = {
static
int
__init
twl4030_pwrbutton_init
(
void
)
{
return
platform_driver_register
(
&
twl4030_pwrbutton_driver
);
return
platform_driver_probe
(
&
twl4030_pwrbutton_driver
,
twl4030_pwrbutton_probe
);
}
module_init
(
twl4030_pwrbutton_init
);
...
...
drivers/input/misc/wistron_btns.c
View file @
929343ef
...
...
@@ -1347,7 +1347,7 @@ static int __init wb_module_init(void)
err
=
map_bios
();
if
(
err
)
return
err
;
goto
err_free_keymap
;
err
=
platform_driver_register
(
&
wistron_driver
);
if
(
err
)
...
...
@@ -1371,6 +1371,8 @@ static int __init wb_module_init(void)
platform_driver_unregister
(
&
wistron_driver
);
err_unmap_bios:
unmap_bios
();
err_free_keymap:
kfree
(
keymap
);
return
err
;
}
...
...
drivers/input/mouse/bcm5974.c
View file @
929343ef
...
...
@@ -312,6 +312,8 @@ static void setup_events_to_report(struct input_dev *input_dev,
__set_bit
(
BTN_TOOL_TRIPLETAP
,
input_dev
->
keybit
);
__set_bit
(
BTN_TOOL_QUADTAP
,
input_dev
->
keybit
);
__set_bit
(
BTN_LEFT
,
input_dev
->
keybit
);
input_set_events_per_packet
(
input_dev
,
60
);
}
/* report button data as logical button state */
...
...
@@ -580,23 +582,30 @@ static void bcm5974_irq_trackpad(struct urb *urb)
*/
static
int
bcm5974_start_traffic
(
struct
bcm5974
*
dev
)
{
if
(
bcm5974_wellspring_mode
(
dev
,
true
))
{
int
error
;
error
=
bcm5974_wellspring_mode
(
dev
,
true
);
if
(
error
)
{
dprintk
(
1
,
"bcm5974: mode switch failed
\n
"
);
goto
err
or
;
goto
err
_out
;
}
if
(
usb_submit_urb
(
dev
->
bt_urb
,
GFP_KERNEL
))
goto
error
;
error
=
usb_submit_urb
(
dev
->
bt_urb
,
GFP_KERNEL
);
if
(
error
)
goto
err_reset_mode
;
if
(
usb_submit_urb
(
dev
->
tp_urb
,
GFP_KERNEL
))
error
=
usb_submit_urb
(
dev
->
tp_urb
,
GFP_KERNEL
);
if
(
error
)
goto
err_kill_bt
;
return
0
;
err_kill_bt:
usb_kill_urb
(
dev
->
bt_urb
);
error:
return
-
EIO
;
err_reset_mode:
bcm5974_wellspring_mode
(
dev
,
false
);
err_out:
return
error
;
}
static
void
bcm5974_pause_traffic
(
struct
bcm5974
*
dev
)
...
...
drivers/input/mouse/synaptics.c
View file @
929343ef
...
...
@@ -502,7 +502,9 @@ static void synaptics_process_packet(struct psmouse *psmouse)
}
input_report_abs
(
dev
,
ABS_PRESSURE
,
hw
.
z
);
input_report_abs
(
dev
,
ABS_TOOL_WIDTH
,
finger_width
);
if
(
SYN_CAP_PALMDETECT
(
priv
->
capabilities
))
input_report_abs
(
dev
,
ABS_TOOL_WIDTH
,
finger_width
);
input_report_key
(
dev
,
BTN_TOOL_FINGER
,
num_fingers
==
1
);
input_report_key
(
dev
,
BTN_LEFT
,
hw
.
left
);
input_report_key
(
dev
,
BTN_RIGHT
,
hw
.
right
);
...
...
@@ -602,7 +604,9 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
input_set_abs_params
(
dev
,
ABS_Y
,
YMIN_NOMINAL
,
priv
->
y_max
?:
YMAX_NOMINAL
,
0
,
0
);
input_set_abs_params
(
dev
,
ABS_PRESSURE
,
0
,
255
,
0
,
0
);
__set_bit
(
ABS_TOOL_WIDTH
,
dev
->
absbit
);
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
);
...
...
drivers/input/mousedev.c
View file @
929343ef
...
...
@@ -57,7 +57,6 @@ struct mousedev_hw_data {
};
struct
mousedev
{
int
exist
;
int
open
;
int
minor
;
struct
input_handle
handle
;
...
...
@@ -66,6 +65,7 @@ struct mousedev {
spinlock_t
client_lock
;
/* protects client_list */
struct
mutex
mutex
;
struct
device
dev
;
bool
exist
;
struct
list_head
mixdev_node
;
int
mixdev_open
;
...
...
@@ -765,10 +765,15 @@ static unsigned int mousedev_poll(struct file *file, poll_table *wait)
{
struct
mousedev_client
*
client
=
file
->
private_data
;
struct
mousedev
*
mousedev
=
client
->
mousedev
;
unsigned
int
mask
;
poll_wait
(
file
,
&
mousedev
->
wait
,
wait
);
return
((
client
->
ready
||
client
->
buffer
)
?
(
POLLIN
|
POLLRDNORM
)
:
0
)
|
(
mousedev
->
exist
?
0
:
(
POLLHUP
|
POLLERR
));
mask
=
mousedev
->
exist
?
POLLOUT
|
POLLWRNORM
:
POLLHUP
|
POLLERR
;
if
(
client
->
ready
||
client
->
buffer
)
mask
|=
POLLIN
|
POLLRDNORM
;
return
mask
;
}
static
const
struct
file_operations
mousedev_fops
=
{
...
...
@@ -802,7 +807,7 @@ static void mousedev_remove_chrdev(struct mousedev *mousedev)
static
void
mousedev_mark_dead
(
struct
mousedev
*
mousedev
)
{
mutex_lock
(
&
mousedev
->
mutex
);
mousedev
->
exist
=
0
;
mousedev
->
exist
=
false
;
mutex_unlock
(
&
mousedev
->
mutex
);
}
...
...
@@ -862,7 +867,7 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
dev_set_name
(
&
mousedev
->
dev
,
"mouse%d"
,
minor
);
mousedev
->
minor
=
minor
;
mousedev
->
exist
=
1
;
mousedev
->
exist
=
true
;
mousedev
->
handle
.
dev
=
input_get_device
(
dev
);
mousedev
->
handle
.
name
=
dev_name
(
&
mousedev
->
dev
);
mousedev
->
handle
.
handler
=
handler
;
...
...
drivers/input/serio/i8042-ppcio.h
View file @
929343ef
...
...
@@ -52,81 +52,6 @@ static inline void i8042_platform_exit(void)
{
}
#elif defined(CONFIG_SPRUCE)
#define I8042_KBD_IRQ 22
#define I8042_AUX_IRQ 21
#define I8042_KBD_PHYS_DESC "spruceps2/serio0"
#define I8042_AUX_PHYS_DESC "spruceps2/serio1"
#define I8042_MUX_PHYS_DESC "spruceps2/serio%d"
#define I8042_COMMAND_REG 0xff810000
#define I8042_DATA_REG 0xff810001
static
inline
int
i8042_read_data
(
void
)
{
unsigned
long
kbd_data
;
__raw_writel
(
0x00000088
,
0xff500008
);
eieio
();
__raw_writel
(
0x03000000
,
0xff50000c
);
eieio
();
asm
volatile
(
"lis 7,0xff88
\n
\
lswi 6,7,0x8
\n
\
mr %0,6"
:
"=r"
(
kbd_data
)
::
"6"
,
"7"
);
__raw_writel
(
0x00000000
,
0xff50000c
);
eieio
();
return
(
unsigned
char
)(
kbd_data
>>
24
);
}
static
inline
int
i8042_read_status
(
void
)
{
unsigned
long
kbd_status
;
__raw_writel
(
0x00000088
,
0xff500008
);
eieio
();
__raw_writel
(
0x03000000
,
0xff50000c
);
eieio
();
asm
volatile
(
"lis 7,0xff88
\n
\
ori 7,7,0x8
\n
\
lswi 6,7,0x8
\n
\
mr %0,6"
:
"=r"
(
kbd_status
)
::
"6"
,
"7"
);
__raw_writel
(
0x00000000
,
0xff50000c
);
eieio
();
return
(
unsigned
char
)(
kbd_status
>>
24
);
}
static
inline
void
i8042_write_data
(
int
val
)
{
*
((
unsigned
char
*
)
0xff810000
)
=
(
char
)
val
;
}
static
inline
void
i8042_write_command
(
int
val
)
{
*
((
unsigned
char
*
)
0xff810001
)
=
(
char
)
val
;
}
static
inline
int
i8042_platform_init
(
void
)
{
i8042_reset
=
1
;
return
0
;
}
static
inline
void
i8042_platform_exit
(
void
)
{
}
#else
#include "i8042-io.h"
...
...
drivers/input/serio/i8042.c
View file @
929343ef
...
...
@@ -861,9 +861,6 @@ static int i8042_controller_selftest(void)
unsigned
char
param
;
int
i
=
0
;
if
(
!
i8042_reset
)
return
0
;
/*
* We try this 5 times; on some really fragile systems this does not
* take the first time...
...
...
@@ -1020,7 +1017,8 @@ static void i8042_controller_reset(void)
* Reset the controller if requested.
*/
i8042_controller_selftest
();
if
(
i8042_reset
)
i8042_controller_selftest
();
/*
* Restore the original control register setting.
...
...
@@ -1093,24 +1091,12 @@ static void i8042_dritek_enable(void)
#ifdef CONFIG_PM
/*
* Here we try to restore the original BIOS settings to avoid
* upsetting it.
*/
static
int
i8042_pm_reset
(
struct
device
*
dev
)
{
i8042_controller_reset
();
return
0
;
}
/*
* Here we try to reset everything back to a state we had
* before suspending.
*/
static
int
i8042_
pm_restore
(
struct
device
*
dev
)
static
int
i8042_
controller_resume
(
bool
force_reset
)
{
int
error
;
...
...
@@ -1118,9 +1104,11 @@ static int i8042_pm_restore(struct device *dev)
if
(
error
)
return
error
;
error
=
i8042_controller_selftest
();
if
(
error
)
return
error
;
if
(
i8042_reset
||
force_reset
)
{
error
=
i8042_controller_selftest
();
if
(
error
)
return
error
;
}
/*
* Restore original CTR value and disable all ports
...
...
@@ -1162,6 +1150,28 @@ static int i8042_pm_restore(struct device *dev)
return
0
;
}
/*
* Here we try to restore the original BIOS settings to avoid
* upsetting it.
*/
static
int
i8042_pm_reset
(
struct
device
*
dev
)
{
i8042_controller_reset
();
return
0
;
}
static
int
i8042_pm_resume
(
struct
device
*
dev
)
{
/*
* On resume from S2R we always try to reset the controller
* to bring it in a sane state. (In case of S2D we expect
* BIOS to reset the controller for us.)
*/
return
i8042_controller_resume
(
true
);
}
static
int
i8042_pm_thaw
(
struct
device
*
dev
)
{
i8042_interrupt
(
0
,
NULL
);
...
...
@@ -1169,9 +1179,14 @@ static int i8042_pm_thaw(struct device *dev)
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
,
.
resume
=
i8042_pm_res
tor
e
,
.
resume
=
i8042_pm_res
um
e
,
.
thaw
=
i8042_pm_thaw
,
.
poweroff
=
i8042_pm_reset
,
.
restore
=
i8042_pm_restore
,
...
...
@@ -1389,9 +1404,11 @@ static int __init i8042_probe(struct platform_device *dev)
i8042_platform_device
=
dev
;
error
=
i8042_controller_selftest
();
if
(
error
)
return
error
;
if
(
i8042_reset
)
{
error
=
i8042_controller_selftest
();
if
(
error
)
return
error
;
}
error
=
i8042_controller_init
();
if
(
error
)
...
...
drivers/input/tablet/wacom_wac.c
View file @
929343ef
...
...
@@ -158,6 +158,39 @@ static int wacom_ptu_irq(struct wacom_wac *wacom)
return
1
;
}
static
int
wacom_dtu_irq
(
struct
wacom_wac
*
wacom
)
{
struct
wacom_features
*
features
=
&
wacom
->
features
;
char
*
data
=
wacom
->
data
;
struct
input_dev
*
input
=
wacom
->
input
;
int
prox
=
data
[
1
]
&
0x20
,
pressure
;
dbg
(
"wacom_dtu_irq: received report #%d"
,
data
[
0
]);
if
(
prox
)
{
/* Going into proximity select tool */
wacom
->
tool
[
0
]
=
(
data
[
1
]
&
0x0c
)
?
BTN_TOOL_RUBBER
:
BTN_TOOL_PEN
;
if
(
wacom
->
tool
[
0
]
==
BTN_TOOL_PEN
)
wacom
->
id
[
0
]
=
STYLUS_DEVICE_ID
;
else
wacom
->
id
[
0
]
=
ERASER_DEVICE_ID
;
}
input_report_key
(
input
,
BTN_STYLUS
,
data
[
1
]
&
0x02
);
input_report_key
(
input
,
BTN_STYLUS2
,
data
[
1
]
&
0x10
);
input_report_abs
(
input
,
ABS_X
,
le16_to_cpup
((
__le16
*
)
&
data
[
2
]));
input_report_abs
(
input
,
ABS_Y
,
le16_to_cpup
((
__le16
*
)
&
data
[
4
]));
pressure
=
((
data
[
7
]
&
0x01
)
<<
8
)
|
data
[
6
];
if
(
pressure
<
0
)
pressure
=
features
->
pressure_max
+
pressure
+
1
;
input_report_abs
(
input
,
ABS_PRESSURE
,
pressure
);
input_report_key
(
input
,
BTN_TOUCH
,
data
[
1
]
&
0x05
);
if
(
!
prox
)
/* out-prox */
wacom
->
id
[
0
]
=
0
;
input_report_key
(
input
,
wacom
->
tool
[
0
],
prox
);
input_report_abs
(
input
,
ABS_MISC
,
wacom
->
id
[
0
]);
return
1
;
}
static
int
wacom_graphire_irq
(
struct
wacom_wac
*
wacom
)
{
struct
wacom_features
*
features
=
&
wacom
->
features
;
...
...
@@ -845,6 +878,10 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
sync
=
wacom_ptu_irq
(
wacom_wac
);
break
;
case
DTU
:
sync
=
wacom_dtu_irq
(
wacom_wac
);
break
;
case
INTUOS
:
case
INTUOS3S
:
case
INTUOS3
:
...
...
@@ -1030,6 +1067,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
case
PL
:
case
PTU
:
case
DTU
:
__set_bit
(
BTN_TOOL_PEN
,
input_dev
->
keybit
);
__set_bit
(
BTN_STYLUS
,
input_dev
->
keybit
);
__set_bit
(
BTN_STYLUS2
,
input_dev
->
keybit
);
...
...
@@ -1155,6 +1193,10 @@ static const struct wacom_features wacom_features_0xC6 =
{
"Wacom Cintiq 12WX"
,
WACOM_PKGLEN_INTUOS
,
53020
,
33440
,
1023
,
63
,
WACOM_BEE
};
static
const
struct
wacom_features
wacom_features_0xC7
=
{
"Wacom DTU1931"
,
WACOM_PKGLEN_GRAPHIRE
,
37832
,
30305
,
511
,
0
,
PL
};
static
const
struct
wacom_features
wacom_features_0xCE
=
{
"Wacom DTU2231"
,
WACOM_PKGLEN_GRAPHIRE
,
47864
,
27011
,
511
,
0
,
DTU
};
static
const
struct
wacom_features
wacom_features_0xF0
=
{
"Wacom DTU1631"
,
WACOM_PKGLEN_GRAPHIRE
,
34623
,
19553
,
511
,
0
,
DTU
};
static
const
struct
wacom_features
wacom_features_0xCC
=
{
"Wacom Cintiq 21UX2"
,
WACOM_PKGLEN_INTUOS
,
87200
,
65600
,
2047
,
63
,
WACOM_21UX2
};
static
const
struct
wacom_features
wacom_features_0x90
=
...
...
@@ -1234,6 +1276,8 @@ const struct usb_device_id wacom_ids[] = {
{
USB_DEVICE_WACOM
(
0xC5
)
},
{
USB_DEVICE_WACOM
(
0xC6
)
},
{
USB_DEVICE_WACOM
(
0xC7
)
},
{
USB_DEVICE_WACOM
(
0xCE
)
},
{
USB_DEVICE_WACOM
(
0xF0
)
},
{
USB_DEVICE_WACOM
(
0xCC
)
},
{
USB_DEVICE_WACOM
(
0x90
)
},
{
USB_DEVICE_WACOM
(
0x93
)
},
...
...
drivers/input/tablet/wacom_wac.h
View file @
929343ef
...
...
@@ -43,6 +43,7 @@ enum {
WACOM_G4
,
PTU
,
PL
,
DTU
,
INTUOS
,
INTUOS3S
,
INTUOS3
,
...
...
drivers/input/touchscreen/Kconfig
View file @
929343ef
...
...
@@ -55,37 +55,36 @@ config TOUCHSCREEN_AD7877
To compile this driver as a module, choose M here: the
module will be called ad7877.
config TOUCHSCREEN_AD7879_I2C
tristate "AD7879 based touchscreens: AD7879-1 I2C Interface"
depends on I2C
select TOUCHSCREEN_AD7879
config TOUCHSCREEN_AD7879
tristate "Analog Devices AD7879-1/AD7889-1 touchscreen interface"
help
Say Y here if you have a touchscreen interface using the
AD7879-1/AD7889-1 controller, and your board-specific
initialization code includes that in its table of I2C devices.
Say Y here if you want to support a touchscreen interface using
the AD7879-1/AD7889-1 controller.
If unsure, say N (but it's safe to say "Y")
.
You should select a bus connection too
.
To compile this driver as a module, choose M here: the
module will be called ad7879.
config TOUCHSCREEN_AD7879_I2C
tristate "support I2C bus connection"
depends on TOUCHSCREEN_AD7879 && I2C
help
Say Y here if you have AD7879-1/AD7889-1 hooked to an I2C bus.
To compile this driver as a module, choose M here: the
module will be called ad7879-i2c.
config TOUCHSCREEN_AD7879_SPI
tristate "AD7879 based touchscreens: AD7879 SPI Interface"
depends on SPI_MASTER && TOUCHSCREEN_AD7879_I2C = n
select TOUCHSCREEN_AD7879
tristate "support SPI bus connection"
depends on TOUCHSCREEN_AD7879 && SPI_MASTER
help
Say Y here if you have a touchscreen interface using the
AD7879/AD7889 controller, and your board-specific initialization
code includes that in its table of SPI devices.
Say Y here if you have AD7879-1/AD7889-1 hooked to a SPI bus.
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
module will be called ad7879.
config TOUCHSCREEN_AD7879
tristate
default n
module will be called ad7879-spi.
config TOUCHSCREEN_BITSY
tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
...
...
@@ -99,6 +98,20 @@ config TOUCHSCREEN_BITSY
To compile this driver as a module, choose M here: the
module will be called h3600_ts_input.
config TOUCHSCREEN_CY8CTMG110
tristate "cy8ctmg110 touchscreen"
depends on I2C
depends on GPIOLIB
help
Say Y here if you have a cy8ctmg110 capacitive touchscreen on
an AAVA device.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called cy8ctmg110_ts.
config TOUCHSCREEN_DA9034
tristate "Touchscreen support for Dialog Semiconductor DA9034"
depends on PMIC_DA903X
...
...
@@ -292,6 +305,18 @@ config TOUCHSCREEN_PENMOUNT
To compile this driver as a module, choose M here: the
module will be called penmount.
config TOUCHSCREEN_QT602240
tristate "QT602240 I2C Touchscreen"
depends on I2C
help
Say Y here if you have the AT42QT602240/ATMXT224 I2C touchscreen
connected to your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called qt602240_ts.
config TOUCHSCREEN_MIGOR
tristate "Renesas MIGO-R touchscreen"
depends on SH_MIGOR && I2C
...
...
@@ -540,9 +565,9 @@ config TOUCHSCREEN_USB_ZYTRONIC
bool "Zytronic controller" if EMBEDDED
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_ETT_TC
5UH
config TOUCHSCREEN_USB_ETT_TC
45USB
default y
bool "ET&T TC5UH touchscreen controler support" if EMBEDDED
bool "ET&T
USB series TC4UM/
TC5UH touchscreen controler support" if EMBEDDED
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_NEXIO
...
...
drivers/input/touchscreen/Makefile
View file @
929343ef
...
...
@@ -9,9 +9,13 @@ wm97xx-ts-y := wm97xx-core.o
obj-$(CONFIG_TOUCHSCREEN_88PM860X)
+=
88pm860x-ts.o
obj-$(CONFIG_TOUCHSCREEN_AD7877)
+=
ad7877.o
obj-$(CONFIG_TOUCHSCREEN_AD7879)
+=
ad7879.o
obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C)
+=
ad7879-i2c.o
obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI)
+=
ad7879-spi.o
obj-$(CONFIG_TOUCHSCREEN_ADS7846)
+=
ads7846.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC)
+=
atmel_tsadcc.o
obj-$(CONFIG_TOUCHSCREEN_BITSY)
+=
h3600_ts_input.o
obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)
+=
cy8ctmg110_ts.o
obj-$(CONFIG_TOUCHSCREEN_DA9034)
+=
da9034-ts.o
obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)
+=
dynapro.o
obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)
+=
hampshire.o
obj-$(CONFIG_TOUCHSCREEN_GUNZE)
+=
gunze.o
...
...
@@ -30,6 +34,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_QT602240)
+=
qt602240_ts.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410)
+=
s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213)
+=
touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)
+=
touchright.o
...
...
@@ -38,7 +43,6 @@ obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o
obj-$(CONFIG_TOUCHSCREEN_UCB1400)
+=
ucb1400_ts.o
obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001)
+=
wacom_w8001.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX)
+=
wm97xx-ts.o
obj-$(CONFIG_TOUCHSCREEN_DA9034)
+=
da9034-ts.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705)
+=
wm9705.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712)
+=
wm9712.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713)
+=
wm9713.o
...
...
drivers/input/touchscreen/ad7879-i2c.c
0 → 100644
View file @
929343ef
/*
* AD7879-1/AD7889-1 touchscreen (I2C bus)
*
* Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/input.h>
/* BUS_I2C */
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/types.h>
#include "ad7879.h"
#define AD7879_DEVID 0x79
/* AD7879-1/AD7889-1 */
#ifdef CONFIG_PM
static
int
ad7879_i2c_suspend
(
struct
i2c_client
*
client
,
pm_message_t
message
)
{
struct
ad7879
*
ts
=
i2c_get_clientdata
(
client
);
ad7879_suspend
(
ts
);
return
0
;
}
static
int
ad7879_i2c_resume
(
struct
i2c_client
*
client
)
{
struct
ad7879
*
ts
=
i2c_get_clientdata
(
client
);
ad7879_resume
(
ts
);
return
0
;
}
#else
# define ad7879_i2c_suspend NULL
# define ad7879_i2c_resume NULL
#endif
/* All registers are word-sized.
* AD7879 uses a high-byte first convention.
*/
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
));
}
static
int
ad7879_i2c_multi_read
(
struct
device
*
dev
,
u8
first_reg
,
u8
count
,
u16
*
buf
)
{
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
u8
idx
;
i2c_smbus_read_i2c_block_data
(
client
,
first_reg
,
count
*
2
,
(
u8
*
)
buf
);
for
(
idx
=
0
;
idx
<
count
;
++
idx
)
buf
[
idx
]
=
swab16
(
buf
[
idx
]);
return
0
;
}
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
));
}
static
const
struct
ad7879_bus_ops
ad7879_i2c_bus_ops
=
{
.
bustype
=
BUS_I2C
,
.
read
=
ad7879_i2c_read
,
.
multi_read
=
ad7879_i2c_multi_read
,
.
write
=
ad7879_i2c_write
,
};
static
int
__devinit
ad7879_i2c_probe
(
struct
i2c_client
*
client
,
const
struct
i2c_device_id
*
id
)
{
struct
ad7879
*
ts
;
if
(
!
i2c_check_functionality
(
client
->
adapter
,
I2C_FUNC_SMBUS_WORD_DATA
))
{
dev_err
(
&
client
->
dev
,
"SMBUS Word Data not Supported
\n
"
);
return
-
EIO
;
}
ts
=
ad7879_probe
(
&
client
->
dev
,
AD7879_DEVID
,
client
->
irq
,
&
ad7879_i2c_bus_ops
);
if
(
IS_ERR
(
ts
))
return
PTR_ERR
(
ts
);
i2c_set_clientdata
(
client
,
ts
);
return
0
;
}
static
int
__devexit
ad7879_i2c_remove
(
struct
i2c_client
*
client
)
{
struct
ad7879
*
ts
=
i2c_get_clientdata
(
client
);
ad7879_remove
(
ts
);
return
0
;
}
static
const
struct
i2c_device_id
ad7879_id
[]
=
{
{
"ad7879"
,
0
},
{
"ad7889"
,
0
},
{
}
};
MODULE_DEVICE_TABLE
(
i2c
,
ad7879_id
);
static
struct
i2c_driver
ad7879_i2c_driver
=
{
.
driver
=
{
.
name
=
"ad7879"
,
.
owner
=
THIS_MODULE
,
},
.
probe
=
ad7879_i2c_probe
,
.
remove
=
__devexit_p
(
ad7879_i2c_remove
),
.
suspend
=
ad7879_i2c_suspend
,
.
resume
=
ad7879_i2c_resume
,
.
id_table
=
ad7879_id
,
};
static
int
__init
ad7879_i2c_init
(
void
)
{
return
i2c_add_driver
(
&
ad7879_i2c_driver
);
}
module_init
(
ad7879_i2c_init
);
static
void
__exit
ad7879_i2c_exit
(
void
)
{
i2c_del_driver
(
&
ad7879_i2c_driver
);
}
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"
);
drivers/input/touchscreen/ad7879-spi.c
0 → 100644
View file @
929343ef
/*
* AD7879/AD7889 touchscreen (SPI bus)
*
* Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/input.h>
/* BUS_SPI */
#include <linux/spi/spi.h>
#include "ad7879.h"
#define AD7879_DEVID 0x7A
/* AD7879/AD7889 */
#define MAX_SPI_FREQ_HZ 5000000
#define AD7879_CMD_MAGIC 0xE000
#define AD7879_CMD_READ (1 << 10)
#define AD7879_CMD(reg) (AD7879_CMD_MAGIC | ((reg) & 0xF))
#define AD7879_WRITECMD(reg) (AD7879_CMD(reg))
#define AD7879_READCMD(reg) (AD7879_CMD(reg) | AD7879_CMD_READ)
#ifdef CONFIG_PM
static
int
ad7879_spi_suspend
(
struct
spi_device
*
spi
,
pm_message_t
message
)
{
struct
ad7879
*
ts
=
spi_get_drvdata
(
spi
);
ad7879_suspend
(
ts
);
return
0
;
}
static
int
ad7879_spi_resume
(
struct
spi_device
*
spi
)
{
struct
ad7879
*
ts
=
spi_get_drvdata
(
spi
);
ad7879_resume
(
ts
);
return
0
;
}
#else
# define ad7879_spi_suspend NULL
# define ad7879_spi_resume NULL
#endif
/*
* ad7879_read/write are only used for initial setup and for sysfs controls.
* The main traffic is done in ad7879_collect().
*/
static
int
ad7879_spi_xfer
(
struct
spi_device
*
spi
,
u16
cmd
,
u8
count
,
u16
*
tx_buf
,
u16
*
rx_buf
)
{
struct
spi_message
msg
;
struct
spi_transfer
*
xfers
;
void
*
spi_data
;
u16
*
command
;
u16
*
_rx_buf
=
_rx_buf
;
/* shut gcc up */
u8
idx
;
int
ret
;
xfers
=
spi_data
=
kzalloc
(
sizeof
(
*
xfers
)
*
(
count
+
2
),
GFP_KERNEL
);
if
(
!
spi_data
)
return
-
ENOMEM
;
spi_message_init
(
&
msg
);
command
=
spi_data
;
command
[
0
]
=
cmd
;
if
(
count
==
1
)
{
/* ad7879_spi_{read,write} gave us buf on stack */
command
[
1
]
=
*
tx_buf
;
tx_buf
=
&
command
[
1
];
_rx_buf
=
rx_buf
;
rx_buf
=
&
command
[
2
];
}
++
xfers
;
xfers
[
0
].
tx_buf
=
command
;
xfers
[
0
].
len
=
2
;
spi_message_add_tail
(
&
xfers
[
0
],
&
msg
);
++
xfers
;
for
(
idx
=
0
;
idx
<
count
;
++
idx
)
{
if
(
rx_buf
)
xfers
[
idx
].
rx_buf
=
&
rx_buf
[
idx
];
if
(
tx_buf
)
xfers
[
idx
].
tx_buf
=
&
tx_buf
[
idx
];
xfers
[
idx
].
len
=
2
;
spi_message_add_tail
(
&
xfers
[
idx
],
&
msg
);
}
ret
=
spi_sync
(
spi
,
&
msg
);
if
(
count
==
1
)
_rx_buf
[
0
]
=
command
[
2
];
kfree
(
spi_data
);
return
ret
;
}
static
int
ad7879_spi_multi_read
(
struct
device
*
dev
,
u8
first_reg
,
u8
count
,
u16
*
buf
)
{
struct
spi_device
*
spi
=
to_spi_device
(
dev
);
return
ad7879_spi_xfer
(
spi
,
AD7879_READCMD
(
first_reg
),
count
,
NULL
,
buf
);
}
static
int
ad7879_spi_read
(
struct
device
*
dev
,
u8
reg
)
{
struct
spi_device
*
spi
=
to_spi_device
(
dev
);
u16
ret
,
dummy
;
return
ad7879_spi_xfer
(
spi
,
AD7879_READCMD
(
reg
),
1
,
&
dummy
,
&
ret
)
?
:
ret
;
}
static
int
ad7879_spi_write
(
struct
device
*
dev
,
u8
reg
,
u16
val
)
{
struct
spi_device
*
spi
=
to_spi_device
(
dev
);
u16
dummy
;
return
ad7879_spi_xfer
(
spi
,
AD7879_WRITECMD
(
reg
),
1
,
&
val
,
&
dummy
);
}
static
const
struct
ad7879_bus_ops
ad7879_spi_bus_ops
=
{
.
bustype
=
BUS_SPI
,
.
read
=
ad7879_spi_read
,
.
multi_read
=
ad7879_spi_multi_read
,
.
write
=
ad7879_spi_write
,
};
static
int
__devinit
ad7879_spi_probe
(
struct
spi_device
*
spi
)
{
struct
ad7879
*
ts
;
int
err
;
/* don't exceed max specified SPI CLK frequency */
if
(
spi
->
max_speed_hz
>
MAX_SPI_FREQ_HZ
)
{
dev_err
(
&
spi
->
dev
,
"SPI CLK %d Hz?
\n
"
,
spi
->
max_speed_hz
);
return
-
EINVAL
;
}
spi
->
bits_per_word
=
16
;
err
=
spi_setup
(
spi
);
if
(
err
)
{
dev_dbg
(
&
spi
->
dev
,
"spi master doesn't support 16 bits/word
\n
"
);
return
err
;
}
ts
=
ad7879_probe
(
&
spi
->
dev
,
AD7879_DEVID
,
spi
->
irq
,
&
ad7879_spi_bus_ops
);
if
(
IS_ERR
(
ts
))
return
PTR_ERR
(
ts
);
spi_set_drvdata
(
spi
,
ts
);
return
0
;
}
static
int
__devexit
ad7879_spi_remove
(
struct
spi_device
*
spi
)
{
struct
ad7879
*
ts
=
spi_get_drvdata
(
spi
);
ad7879_remove
(
ts
);
spi_set_drvdata
(
spi
,
NULL
);
return
0
;
}
static
struct
spi_driver
ad7879_spi_driver
=
{
.
driver
=
{
.
name
=
"ad7879"
,
.
bus
=
&
spi_bus_type
,
.
owner
=
THIS_MODULE
,
},
.
probe
=
ad7879_spi_probe
,
.
remove
=
__devexit_p
(
ad7879_spi_remove
),
.
suspend
=
ad7879_spi_suspend
,
.
resume
=
ad7879_spi_resume
,
};
static
int
__init
ad7879_spi_init
(
void
)
{
return
spi_register_driver
(
&
ad7879_spi_driver
);
}
module_init
(
ad7879_spi_init
);
static
void
__exit
ad7879_spi_exit
(
void
)
{
spi_unregister_driver
(
&
ad7879_spi_driver
);
}
module_exit
(
ad7879_spi_exit
);
MODULE_AUTHOR
(
"Michael Hennerich <hennerich@blackfin.uclinux.org>"
);
MODULE_DESCRIPTION
(
"AD7879(-1) touchscreen SPI bus driver"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_ALIAS
(
"spi:ad7879"
);
drivers/input/touchscreen/ad7879.c
View file @
929343ef
/*
*
Copyright (C) 2008-2009 Michael Hennerich, Analog Devices Inc.
*
AD7879/AD7889 based touchscreen and GPIO driver
*
* Description: AD7879/AD7889 based touchscreen, and GPIO driver
* (I2C/SPI Interface)
* Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
*
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see the file COPYING, or write
* to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* Licensed under the GPL-2 or later.
*
* History:
* Copyright (c) 2005 David Brownell
...
...
@@ -44,12 +28,12 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/spi/spi.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/spi/ad7879.h>
#include "ad7879.h"
#define AD7879_REG_ZEROS 0
#define AD7879_REG_CTRL1 1
...
...
@@ -120,30 +104,19 @@ enum {
#define MAX_12BIT ((1<<12)-1)
#define TS_PEN_UP_TIMEOUT msecs_to_jiffies(50)
#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
#define AD7879_DEVID 0x7A
typedef
struct
spi_device
bus_device
;
#elif defined(CONFIG_TOUCHSCREEN_AD7879_I2C) || defined(CONFIG_TOUCHSCREEN_AD7879_I2C_MODULE)
#define AD7879_DEVID 0x79
typedef
struct
i2c_client
bus_device
;
#endif
struct
ad7879
{
bus_device
*
bus
;
const
struct
ad7879_bus_ops
*
bops
;
struct
device
*
dev
;
struct
input_dev
*
input
;
struct
work_struct
work
;
struct
timer_list
timer
;
#ifdef CONFIG_GPIOLIB
struct
gpio_chip
gc
;
#endif
struct
mutex
mutex
;
unsigned
disabled
:
1
;
/* P: mutex */
#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
struct
spi_message
msg
;
struct
spi_transfer
xfer
[
AD7879_NR_SENSE
+
1
];
u16
cmd
;
#endif
unsigned
int
irq
;
bool
disabled
;
/* P: input->mutex */
bool
suspended
;
/* P: input->mutex */
u16
conversion_data
[
AD7879_NR_SENSE
];
char
phys
[
32
];
u8
first_conversion_delay
;
...
...
@@ -158,11 +131,22 @@ struct ad7879 {
u16
cmd_crtl3
;
};
static
int
ad7879_read
(
bus_device
*
,
u8
);
static
int
ad7879_write
(
bus_device
*
,
u8
,
u16
);
static
void
ad7879_collect
(
struct
ad7879
*
);
static
int
ad7879_read
(
struct
ad7879
*
ts
,
u8
reg
)
{
return
ts
->
bops
->
read
(
ts
->
dev
,
reg
);
}
static
int
ad7879_multi_read
(
struct
ad7879
*
ts
,
u8
first_reg
,
u8
count
,
u16
*
buf
)
{
return
ts
->
bops
->
multi_read
(
ts
->
dev
,
first_reg
,
count
,
buf
);
}
static
void
ad7879_report
(
struct
ad7879
*
ts
)
static
int
ad7879_write
(
struct
ad7879
*
ts
,
u8
reg
,
u16
val
)
{
return
ts
->
bops
->
write
(
ts
->
dev
,
reg
,
val
);
}
static
int
ad7879_report
(
struct
ad7879
*
ts
)
{
struct
input_dev
*
input_dev
=
ts
->
input
;
unsigned
Rt
;
...
...
@@ -175,12 +159,14 @@ static void ad7879_report(struct ad7879 *ts)
/*
* The samples processed here are already preprocessed by the AD7879.
* The preprocessing function consists of a median and an averaging filter.
* The combination of these two techniques provides a robust solution,
* discarding the spurious noise in the signal and keeping only the data of interest.
* The size of both filters is programmable. (dev.platform_data, see linux/spi/ad7879.h)
* Other user-programmable conversion controls include variable acquisition time,
* and first conversion delay. Up to 16 averages can be taken per conversion.
* The preprocessing function consists of a median and an averaging
* filter. The combination of these two techniques provides a robust
* solution, discarding the spurious noise in the signal and keeping
* only the data of interest. The size of both filters is
* programmable. (dev.platform_data, see linux/spi/ad7879.h) Other
* user-programmable conversion controls include variable acquisition
* time, and first conversion delay. Up to 16 averages can be taken
* per conversion.
*/
if
(
likely
(
x
&&
z1
))
{
...
...
@@ -189,21 +175,17 @@ static void ad7879_report(struct ad7879 *ts)
Rt
/=
z1
;
Rt
=
(
Rt
+
2047
)
>>
12
;
if
(
!
timer_pending
(
&
ts
->
timer
))
input_report_key
(
input_dev
,
BTN_TOUCH
,
1
);
input_report_abs
(
input_dev
,
ABS_X
,
x
);
input_report_abs
(
input_dev
,
ABS_Y
,
y
);
input_report_abs
(
input_dev
,
ABS_PRESSURE
,
Rt
);
input_sync
(
input_dev
);
return
0
;
}
}
static
void
ad7879_work
(
struct
work_struct
*
work
)
{
struct
ad7879
*
ts
=
container_of
(
work
,
struct
ad7879
,
work
);
/* use keventd context to read the result registers */
ad7879_collect
(
ts
);
ad7879_report
(
ts
);
mod_timer
(
&
ts
->
timer
,
jiffies
+
TS_PEN_UP_TIMEOUT
);
return
-
EINVAL
;
}
static
void
ad7879_ts_event_release
(
struct
ad7879
*
ts
)
...
...
@@ -211,6 +193,7 @@ static void ad7879_ts_event_release(struct ad7879 *ts)
struct
input_dev
*
input_dev
=
ts
->
input
;
input_report_abs
(
input_dev
,
ABS_PRESSURE
,
0
);
input_report_key
(
input_dev
,
BTN_TOUCH
,
0
);
input_sync
(
input_dev
);
}
...
...
@@ -225,56 +208,98 @@ static irqreturn_t ad7879_irq(int irq, void *handle)
{
struct
ad7879
*
ts
=
handle
;
/* The repeated conversion sequencer controlled by TMR kicked off too fast.
* We ignore the last and process the sample sequence currently in the queue.
* It can't be older than 9.4ms
*/
ad7879_multi_read
(
ts
,
AD7879_REG_XPLUS
,
AD7879_NR_SENSE
,
ts
->
conversion_data
);
if
(
!
work_pending
(
&
ts
->
work
))
schedule_work
(
&
ts
->
work
);
if
(
!
ad7879_report
(
ts
))
mod_timer
(
&
ts
->
timer
,
jiffies
+
TS_PEN_UP_TIMEOUT
);
return
IRQ_HANDLED
;
}
static
void
ad7879_setup
(
struct
ad7879
*
ts
)
static
void
__ad7879_enable
(
struct
ad7879
*
ts
)
{
ad7879_write
(
ts
->
bus
,
AD7879_REG_CTRL2
,
ts
->
cmd_crtl2
);
ad7879_write
(
ts
->
bus
,
AD7879_REG_CTRL3
,
ts
->
cmd_crtl3
);
ad7879_write
(
ts
->
bus
,
AD7879_REG_CTRL1
,
ts
->
cmd_crtl1
);
ad7879_write
(
ts
,
AD7879_REG_CTRL2
,
ts
->
cmd_crtl2
);
ad7879_write
(
ts
,
AD7879_REG_CTRL3
,
ts
->
cmd_crtl3
);
ad7879_write
(
ts
,
AD7879_REG_CTRL1
,
ts
->
cmd_crtl1
);
enable_irq
(
ts
->
irq
);
}
static
void
ad7879_disable
(
struct
ad7879
*
ts
)
static
void
__
ad7879_disable
(
struct
ad7879
*
ts
)
{
mutex_lock
(
&
ts
->
mutex
);
disable_irq
(
ts
->
irq
);
if
(
del_timer_sync
(
&
ts
->
timer
))
ad7879_ts_event_release
(
ts
);
ad7879_write
(
ts
,
AD7879_REG_CTRL2
,
AD7879_PM
(
AD7879_PM_SHUTDOWN
));
}
if
(
!
ts
->
disabled
)
{
ts
->
disabled
=
1
;
disable_irq
(
ts
->
bus
->
irq
);
static
int
ad7879_open
(
struct
input_dev
*
input
)
{
struct
ad7879
*
ts
=
input_get_drvdata
(
input
);
cancel_work_sync
(
&
ts
->
work
);
/* protected by input->mutex */
if
(
!
ts
->
disabled
&&
!
ts
->
suspended
)
__ad7879_enable
(
ts
);
if
(
del_timer_sync
(
&
ts
->
timer
))
ad7879_ts_event_release
(
ts
);
return
0
;
}
ad7879_write
(
ts
->
bus
,
AD7879_REG_CTRL2
,
AD7879_PM
(
AD7879_PM_SHUTDOWN
));
}
static
void
ad7879_close
(
struct
input_dev
*
input
)
{
struct
ad7879
*
ts
=
input_get_drvdata
(
input
);
mutex_unlock
(
&
ts
->
mutex
);
/* protected by input->mutex */
if
(
!
ts
->
disabled
&&
!
ts
->
suspended
)
__ad7879_disable
(
ts
);
}
static
void
ad7879_enable
(
struct
ad7879
*
ts
)
void
ad7879_suspend
(
struct
ad7879
*
ts
)
{
mutex_lock
(
&
ts
->
mutex
);
mutex_lock
(
&
ts
->
input
->
mutex
);
if
(
!
ts
->
suspended
&&
!
ts
->
disabled
&&
ts
->
input
->
users
)
__ad7879_disable
(
ts
);
ts
->
suspended
=
true
;
if
(
ts
->
disabled
)
{
ad7879_setup
(
ts
);
ts
->
disabled
=
0
;
enable_irq
(
ts
->
bus
->
irq
);
mutex_unlock
(
&
ts
->
input
->
mutex
);
}
EXPORT_SYMBOL
(
ad7879_suspend
);
void
ad7879_resume
(
struct
ad7879
*
ts
)
{
mutex_lock
(
&
ts
->
input
->
mutex
);
if
(
ts
->
suspended
&&
!
ts
->
disabled
&&
ts
->
input
->
users
)
__ad7879_enable
(
ts
);
ts
->
suspended
=
false
;
mutex_unlock
(
&
ts
->
input
->
mutex
);
}
EXPORT_SYMBOL
(
ad7879_resume
);
static
void
ad7879_toggle
(
struct
ad7879
*
ts
,
bool
disable
)
{
mutex_lock
(
&
ts
->
input
->
mutex
);
if
(
!
ts
->
suspended
&&
ts
->
input
->
users
!=
0
)
{
if
(
disable
)
{
if
(
ts
->
disabled
)
__ad7879_enable
(
ts
);
}
else
{
if
(
!
ts
->
disabled
)
__ad7879_disable
(
ts
);
}
}
mutex_unlock
(
&
ts
->
mutex
);
ts
->
disabled
=
disable
;
mutex_unlock
(
&
ts
->
input
->
mutex
);
}
static
ssize_t
ad7879_disable_show
(
struct
device
*
dev
,
...
...
@@ -297,10 +322,7 @@ static ssize_t ad7879_disable_store(struct device *dev,
if
(
error
)
return
error
;
if
(
val
)
ad7879_disable
(
ts
);
else
ad7879_enable
(
ts
);
ad7879_toggle
(
ts
,
val
);
return
count
;
}
...
...
@@ -325,7 +347,7 @@ static int ad7879_gpio_direction_input(struct gpio_chip *chip,
mutex_lock
(
&
ts
->
mutex
);
ts
->
cmd_crtl2
|=
AD7879_GPIO_EN
|
AD7879_GPIODIR
|
AD7879_GPIOPOL
;
err
=
ad7879_write
(
ts
->
bus
,
AD7879_REG_CTRL2
,
ts
->
cmd_crtl2
);
err
=
ad7879_write
(
ts
,
AD7879_REG_CTRL2
,
ts
->
cmd_crtl2
);
mutex_unlock
(
&
ts
->
mutex
);
return
err
;
...
...
@@ -345,7 +367,7 @@ static int ad7879_gpio_direction_output(struct gpio_chip *chip,
else
ts
->
cmd_crtl2
&=
~
AD7879_GPIO_DATA
;
err
=
ad7879_write
(
ts
->
bus
,
AD7879_REG_CTRL2
,
ts
->
cmd_crtl2
);
err
=
ad7879_write
(
ts
,
AD7879_REG_CTRL2
,
ts
->
cmd_crtl2
);
mutex_unlock
(
&
ts
->
mutex
);
return
err
;
...
...
@@ -357,7 +379,7 @@ static int ad7879_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
u16
val
;
mutex_lock
(
&
ts
->
mutex
);
val
=
ad7879_read
(
ts
->
bus
,
AD7879_REG_CTRL2
);
val
=
ad7879_read
(
ts
,
AD7879_REG_CTRL2
);
mutex_unlock
(
&
ts
->
mutex
);
return
!!
(
val
&
AD7879_GPIO_DATA
);
...
...
@@ -374,16 +396,17 @@ static void ad7879_gpio_set_value(struct gpio_chip *chip,
else
ts
->
cmd_crtl2
&=
~
AD7879_GPIO_DATA
;
ad7879_write
(
ts
->
bus
,
AD7879_REG_CTRL2
,
ts
->
cmd_crtl2
);
ad7879_write
(
ts
,
AD7879_REG_CTRL2
,
ts
->
cmd_crtl2
);
mutex_unlock
(
&
ts
->
mutex
);
}
static
int
__devinit
ad7879_gpio_add
(
struct
device
*
dev
)
static
int
ad7879_gpio_add
(
struct
ad7879
*
ts
,
const
struct
ad7879_platform_data
*
pdata
)
{
struct
ad7879
*
ts
=
dev_get_drvdata
(
dev
);
struct
ad7879_platform_data
*
pdata
=
dev
->
platform_data
;
int
ret
=
0
;
mutex_init
(
&
ts
->
mutex
);
if
(
pdata
->
gpio_export
)
{
ts
->
gc
.
direction_input
=
ad7879_gpio_direction_input
;
ts
->
gc
.
direction_output
=
ad7879_gpio_direction_output
;
...
...
@@ -394,72 +417,75 @@ static int __devinit ad7879_gpio_add(struct device *dev)
ts
->
gc
.
ngpio
=
1
;
ts
->
gc
.
label
=
"AD7879-GPIO"
;
ts
->
gc
.
owner
=
THIS_MODULE
;
ts
->
gc
.
dev
=
dev
;
ts
->
gc
.
dev
=
ts
->
dev
;
ret
=
gpiochip_add
(
&
ts
->
gc
);
if
(
ret
)
dev_err
(
dev
,
"failed to register gpio %d
\n
"
,
dev_err
(
ts
->
dev
,
"failed to register gpio %d
\n
"
,
ts
->
gc
.
base
);
}
return
ret
;
}
/*
* We mark ad7879_gpio_remove inline so there is a chance the code
* gets discarded when not needed. We can't do __devinit/__devexit
* markup since it is used in both probe and remove methods.
*/
static
inline
void
ad7879_gpio_remove
(
struct
device
*
dev
)
static
void
ad7879_gpio_remove
(
struct
ad7879
*
ts
)
{
struct
ad7879
*
ts
=
dev_get_drvdata
(
dev
);
struct
ad7879_platform_data
*
pdata
=
dev
->
platform_data
;
const
struct
ad7879_platform_data
*
pdata
=
ts
->
dev
->
platform_data
;
int
ret
;
if
(
pdata
->
gpio_export
)
{
ret
=
gpiochip_remove
(
&
ts
->
gc
);
if
(
ret
)
dev_err
(
dev
,
"failed to remove gpio %d
\n
"
,
dev_err
(
ts
->
dev
,
"failed to remove gpio %d
\n
"
,
ts
->
gc
.
base
);
}
}
#else
static
inline
int
ad7879_gpio_add
(
struct
device
*
dev
)
static
inline
int
ad7879_gpio_add
(
struct
ad7879
*
ts
,
const
struct
ad7879_platform_data
*
pdata
)
{
return
0
;
}
static
inline
void
ad7879_gpio_remove
(
struct
device
*
dev
)
static
inline
void
ad7879_gpio_remove
(
struct
ad7879
*
ts
)
{
}
#endif
static
int
__devinit
ad7879_construct
(
bus_device
*
bus
,
struct
ad7879
*
ts
)
struct
ad7879
*
ad7879_probe
(
struct
device
*
dev
,
u8
devid
,
unsigned
int
irq
,
const
struct
ad7879_bus_ops
*
bops
)
{
struct
ad7879_platform_data
*
pdata
=
dev
->
platform_data
;
struct
ad7879
*
ts
;
struct
input_dev
*
input_dev
;
struct
ad7879_platform_data
*
pdata
=
bus
->
dev
.
platform_data
;
int
err
;
u16
revid
;
if
(
!
bus
->
irq
)
{
dev_err
(
&
bus
->
dev
,
"no IRQ?
\n
"
);
return
-
ENODEV
;
if
(
!
irq
)
{
dev_err
(
dev
,
"no IRQ?
\n
"
);
err
=
-
EINVAL
;
goto
err_out
;
}
if
(
!
pdata
)
{
dev_err
(
&
bus
->
dev
,
"no platform data?
\n
"
);
return
-
ENODEV
;
dev_err
(
dev
,
"no platform data?
\n
"
);
err
=
-
EINVAL
;
goto
err_out
;
}
ts
=
kzalloc
(
sizeof
(
*
ts
),
GFP_KERNEL
);
input_dev
=
input_allocate_device
();
if
(
!
input_dev
)
return
-
ENOMEM
;
if
(
!
ts
||
!
input_dev
)
{
err
=
-
ENOMEM
;
goto
err_free_mem
;
}
ts
->
bops
=
bops
;
ts
->
dev
=
dev
;
ts
->
input
=
input_dev
;
ts
->
irq
=
irq
;
setup_timer
(
&
ts
->
timer
,
ad7879_timer
,
(
unsigned
long
)
ts
);
INIT_WORK
(
&
ts
->
work
,
ad7879_work
);
mutex_init
(
&
ts
->
mutex
);
ts
->
x_plate_ohms
=
pdata
->
x_plate_ohms
?
:
400
;
ts
->
pressure_max
=
pdata
->
pressure_max
?
:
~
0
;
...
...
@@ -470,17 +496,26 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
ts
->
pen_down_acc_interval
=
pdata
->
pen_down_acc_interval
;
ts
->
median
=
pdata
->
median
;
snprintf
(
ts
->
phys
,
sizeof
(
ts
->
phys
),
"%s/input0"
,
dev_name
(
&
bus
->
dev
));
snprintf
(
ts
->
phys
,
sizeof
(
ts
->
phys
),
"%s/input0"
,
dev_name
(
dev
));
input_dev
->
name
=
"AD7879 Touchscreen"
;
input_dev
->
phys
=
ts
->
phys
;
input_dev
->
dev
.
parent
=
&
bus
->
dev
;
input_dev
->
dev
.
parent
=
dev
;
input_dev
->
id
.
bustype
=
bops
->
bustype
;
input_dev
->
open
=
ad7879_open
;
input_dev
->
close
=
ad7879_close
;
input_set_drvdata
(
input_dev
,
ts
);
__set_bit
(
EV_ABS
,
input_dev
->
evbit
);
__set_bit
(
ABS_X
,
input_dev
->
absbit
);
__set_bit
(
ABS_Y
,
input_dev
->
absbit
);
__set_bit
(
ABS_PRESSURE
,
input_dev
->
absbit
);
__set_bit
(
EV_KEY
,
input_dev
->
evbit
);
__set_bit
(
BTN_TOUCH
,
input_dev
->
keybit
);
input_set_abs_params
(
input_dev
,
ABS_X
,
pdata
->
x_min
?
:
0
,
pdata
->
x_max
?
:
MAX_12BIT
,
...
...
@@ -492,17 +527,18 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
input_set_abs_params
(
input_dev
,
ABS_PRESSURE
,
pdata
->
pressure_min
,
pdata
->
pressure_max
,
0
,
0
);
err
=
ad7879_write
(
bus
,
AD7879_REG_CTRL2
,
AD7879_RESET
);
err
=
ad7879_write
(
ts
,
AD7879_REG_CTRL2
,
AD7879_RESET
);
if
(
err
<
0
)
{
dev_err
(
&
bus
->
dev
,
"Failed to write %s
\n
"
,
input_dev
->
name
);
dev_err
(
dev
,
"Failed to write %s
\n
"
,
input_dev
->
name
);
goto
err_free_mem
;
}
revid
=
ad7879_read
(
bus
,
AD7879_REG_REVID
);
if
((
revid
&
0xFF
)
!=
AD7879_DEVID
)
{
dev_err
(
&
bus
->
dev
,
"Failed to probe %s
\n
"
,
input_dev
->
name
);
revid
=
ad7879_read
(
ts
,
AD7879_REG_REVID
);
input_dev
->
id
.
product
=
(
revid
&
0xff
);
input_dev
->
id
.
version
=
revid
>>
8
;
if
(
input_dev
->
id
.
product
!=
devid
)
{
dev_err
(
dev
,
"Failed to probe %s (%x vs %x)
\n
"
,
input_dev
->
name
,
devid
,
revid
);
err
=
-
ENODEV
;
goto
err_free_mem
;
}
...
...
@@ -524,21 +560,21 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
AD7879_ACQ
(
ts
->
acquisition_time
)
|
AD7879_TMR
(
ts
->
pen_down_acc_interval
);
ad7879_setup
(
ts
);
err
=
request_irq
(
bus
->
irq
,
ad7879_irq
,
IRQF_TRIGGER_FALLING
,
bus
->
dev
.
driver
->
name
,
ts
);
err
=
request_threaded_irq
(
ts
->
irq
,
NULL
,
ad7879_irq
,
IRQF_TRIGGER_FALLING
,
dev_name
(
dev
),
ts
);
if
(
err
)
{
dev_err
(
&
bus
->
dev
,
"irq %d busy?
\n
"
,
bu
s
->
irq
);
dev_err
(
dev
,
"irq %d busy?
\n
"
,
t
s
->
irq
);
goto
err_free_mem
;
}
err
=
sysfs_create_group
(
&
bus
->
dev
.
kobj
,
&
ad7879_attr_group
);
__ad7879_disable
(
ts
);
err
=
sysfs_create_group
(
&
dev
->
kobj
,
&
ad7879_attr_group
);
if
(
err
)
goto
err_free_irq
;
err
=
ad7879_gpio_add
(
&
bus
->
dev
);
err
=
ad7879_gpio_add
(
ts
,
pdata
);
if
(
err
)
goto
err_remove_attr
;
...
...
@@ -546,321 +582,32 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
if
(
err
)
goto
err_remove_gpio
;
dev_info
(
&
bus
->
dev
,
"Rev.%d touchscreen, irq %d
\n
"
,
revid
>>
8
,
bus
->
irq
);
return
0
;
return
ts
;
err_remove_gpio:
ad7879_gpio_remove
(
&
bus
->
dev
);
ad7879_gpio_remove
(
ts
);
err_remove_attr:
sysfs_remove_group
(
&
bus
->
dev
.
kobj
,
&
ad7879_attr_group
);
sysfs_remove_group
(
&
dev
->
kobj
,
&
ad7879_attr_group
);
err_free_irq:
free_irq
(
bu
s
->
irq
,
ts
);
free_irq
(
t
s
->
irq
,
ts
);
err_free_mem:
input_free_device
(
input_dev
);
return
err
;
}
static
int
__devexit
ad7879_destroy
(
bus_device
*
bus
,
struct
ad7879
*
ts
)
{
ad7879_gpio_remove
(
&
bus
->
dev
);
ad7879_disable
(
ts
);
sysfs_remove_group
(
&
ts
->
bus
->
dev
.
kobj
,
&
ad7879_attr_group
);
free_irq
(
ts
->
bus
->
irq
,
ts
);
input_unregister_device
(
ts
->
input
);
dev_dbg
(
&
bus
->
dev
,
"unregistered touchscreen
\n
"
);
return
0
;
}
#ifdef CONFIG_PM
static
int
ad7879_suspend
(
bus_device
*
bus
,
pm_message_t
message
)
{
struct
ad7879
*
ts
=
dev_get_drvdata
(
&
bus
->
dev
);
ad7879_disable
(
ts
);
return
0
;
}
static
int
ad7879_resume
(
bus_device
*
bus
)
{
struct
ad7879
*
ts
=
dev_get_drvdata
(
&
bus
->
dev
);
ad7879_enable
(
ts
);
return
0
;
}
#else
#define ad7879_suspend NULL
#define ad7879_resume NULL
#endif
#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
#define MAX_SPI_FREQ_HZ 5000000
#define AD7879_CMD_MAGIC 0xE000
#define AD7879_CMD_READ (1 << 10)
#define AD7879_WRITECMD(reg) (AD7879_CMD_MAGIC | (reg & 0xF))
#define AD7879_READCMD(reg) (AD7879_CMD_MAGIC | AD7879_CMD_READ | (reg & 0xF))
struct
ser_req
{
u16
command
;
u16
data
;
struct
spi_message
msg
;
struct
spi_transfer
xfer
[
2
];
};
/*
* ad7879_read/write are only used for initial setup and for sysfs controls.
* The main traffic is done in ad7879_collect().
*/
static
int
ad7879_read
(
struct
spi_device
*
spi
,
u8
reg
)
{
struct
ser_req
*
req
;
int
status
,
ret
;
req
=
kzalloc
(
sizeof
*
req
,
GFP_KERNEL
);
if
(
!
req
)
return
-
ENOMEM
;
spi_message_init
(
&
req
->
msg
);
req
->
command
=
(
u16
)
AD7879_READCMD
(
reg
);
req
->
xfer
[
0
].
tx_buf
=
&
req
->
command
;
req
->
xfer
[
0
].
len
=
2
;
req
->
xfer
[
1
].
rx_buf
=
&
req
->
data
;
req
->
xfer
[
1
].
len
=
2
;
spi_message_add_tail
(
&
req
->
xfer
[
0
],
&
req
->
msg
);
spi_message_add_tail
(
&
req
->
xfer
[
1
],
&
req
->
msg
);
status
=
spi_sync
(
spi
,
&
req
->
msg
);
ret
=
status
?
:
req
->
data
;
kfree
(
req
);
return
ret
;
}
static
int
ad7879_write
(
struct
spi_device
*
spi
,
u8
reg
,
u16
val
)
{
struct
ser_req
*
req
;
int
status
;
req
=
kzalloc
(
sizeof
*
req
,
GFP_KERNEL
);
if
(
!
req
)
return
-
ENOMEM
;
spi_message_init
(
&
req
->
msg
);
req
->
command
=
(
u16
)
AD7879_WRITECMD
(
reg
);
req
->
xfer
[
0
].
tx_buf
=
&
req
->
command
;
req
->
xfer
[
0
].
len
=
2
;
req
->
data
=
val
;
req
->
xfer
[
1
].
tx_buf
=
&
req
->
data
;
req
->
xfer
[
1
].
len
=
2
;
spi_message_add_tail
(
&
req
->
xfer
[
0
],
&
req
->
msg
);
spi_message_add_tail
(
&
req
->
xfer
[
1
],
&
req
->
msg
);
status
=
spi_sync
(
spi
,
&
req
->
msg
);
kfree
(
req
);
return
status
;
}
static
void
ad7879_collect
(
struct
ad7879
*
ts
)
{
int
status
=
spi_sync
(
ts
->
bus
,
&
ts
->
msg
);
if
(
status
)
dev_err
(
&
ts
->
bus
->
dev
,
"spi_sync --> %d
\n
"
,
status
);
}
static
void
ad7879_setup_ts_def_msg
(
struct
ad7879
*
ts
)
{
struct
spi_message
*
m
;
int
i
;
ts
->
cmd
=
(
u16
)
AD7879_READCMD
(
AD7879_REG_XPLUS
);
m
=
&
ts
->
msg
;
spi_message_init
(
m
);
ts
->
xfer
[
0
].
tx_buf
=
&
ts
->
cmd
;
ts
->
xfer
[
0
].
len
=
2
;
spi_message_add_tail
(
&
ts
->
xfer
[
0
],
m
);
for
(
i
=
0
;
i
<
AD7879_NR_SENSE
;
i
++
)
{
ts
->
xfer
[
i
+
1
].
rx_buf
=
&
ts
->
conversion_data
[
i
];
ts
->
xfer
[
i
+
1
].
len
=
2
;
spi_message_add_tail
(
&
ts
->
xfer
[
i
+
1
],
m
);
}
}
static
int
__devinit
ad7879_probe
(
struct
spi_device
*
spi
)
{
struct
ad7879
*
ts
;
int
error
;
/* don't exceed max specified SPI CLK frequency */
if
(
spi
->
max_speed_hz
>
MAX_SPI_FREQ_HZ
)
{
dev_err
(
&
spi
->
dev
,
"SPI CLK %d Hz?
\n
"
,
spi
->
max_speed_hz
);
return
-
EINVAL
;
}
ts
=
kzalloc
(
sizeof
(
struct
ad7879
),
GFP_KERNEL
);
if
(
!
ts
)
return
-
ENOMEM
;
dev_set_drvdata
(
&
spi
->
dev
,
ts
);
ts
->
bus
=
spi
;
ad7879_setup_ts_def_msg
(
ts
);
error
=
ad7879_construct
(
spi
,
ts
);
if
(
error
)
{
dev_set_drvdata
(
&
spi
->
dev
,
NULL
);
kfree
(
ts
);
}
return
error
;
}
static
int
__devexit
ad7879_remove
(
struct
spi_device
*
spi
)
{
struct
ad7879
*
ts
=
dev_get_drvdata
(
&
spi
->
dev
);
ad7879_destroy
(
spi
,
ts
);
dev_set_drvdata
(
&
spi
->
dev
,
NULL
);
kfree
(
ts
);
return
0
;
err_out:
return
ERR_PTR
(
err
)
;
}
EXPORT_SYMBOL
(
ad7879_probe
);
static
struct
spi_driver
ad7879_driver
=
{
.
driver
=
{
.
name
=
"ad7879"
,
.
bus
=
&
spi_bus_type
,
.
owner
=
THIS_MODULE
,
},
.
probe
=
ad7879_probe
,
.
remove
=
__devexit_p
(
ad7879_remove
),
.
suspend
=
ad7879_suspend
,
.
resume
=
ad7879_resume
,
};
static
int
__init
ad7879_init
(
void
)
{
return
spi_register_driver
(
&
ad7879_driver
);
}
module_init
(
ad7879_init
);
static
void
__exit
ad7879_exit
(
void
)
{
spi_unregister_driver
(
&
ad7879_driver
);
}
module_exit
(
ad7879_exit
);
#elif defined(CONFIG_TOUCHSCREEN_AD7879_I2C) || defined(CONFIG_TOUCHSCREEN_AD7879_I2C_MODULE)
/* All registers are word-sized.
* AD7879 uses a high-byte first convention.
*/
static
int
ad7879_read
(
struct
i2c_client
*
client
,
u8
reg
)
void
ad7879_remove
(
struct
ad7879
*
ts
)
{
return
swab16
(
i2c_smbus_read_word_data
(
client
,
reg
));
}
static
int
ad7879_write
(
struct
i2c_client
*
client
,
u8
reg
,
u16
val
)
{
return
i2c_smbus_write_word_data
(
client
,
reg
,
swab16
(
val
));
}
static
void
ad7879_collect
(
struct
ad7879
*
ts
)
{
int
i
;
for
(
i
=
0
;
i
<
AD7879_NR_SENSE
;
i
++
)
ts
->
conversion_data
[
i
]
=
ad7879_read
(
ts
->
bus
,
AD7879_REG_XPLUS
+
i
);
}
static
int
__devinit
ad7879_probe
(
struct
i2c_client
*
client
,
const
struct
i2c_device_id
*
id
)
{
struct
ad7879
*
ts
;
int
error
;
if
(
!
i2c_check_functionality
(
client
->
adapter
,
I2C_FUNC_SMBUS_WORD_DATA
))
{
dev_err
(
&
client
->
dev
,
"SMBUS Word Data not Supported
\n
"
);
return
-
EIO
;
}
ts
=
kzalloc
(
sizeof
(
struct
ad7879
),
GFP_KERNEL
);
if
(
!
ts
)
return
-
ENOMEM
;
i2c_set_clientdata
(
client
,
ts
);
ts
->
bus
=
client
;
error
=
ad7879_construct
(
client
,
ts
);
if
(
error
)
kfree
(
ts
);
return
error
;
}
static
int
__devexit
ad7879_remove
(
struct
i2c_client
*
client
)
{
struct
ad7879
*
ts
=
dev_get_drvdata
(
&
client
->
dev
);
ad7879_destroy
(
client
,
ts
);
ad7879_gpio_remove
(
ts
);
sysfs_remove_group
(
&
ts
->
dev
->
kobj
,
&
ad7879_attr_group
);
free_irq
(
ts
->
irq
,
ts
);
input_unregister_device
(
ts
->
input
);
kfree
(
ts
);
return
0
;
}
static
const
struct
i2c_device_id
ad7879_id
[]
=
{
{
"ad7879"
,
0
},
{
"ad7889"
,
0
},
{
}
};
MODULE_DEVICE_TABLE
(
i2c
,
ad7879_id
);
static
struct
i2c_driver
ad7879_driver
=
{
.
driver
=
{
.
name
=
"ad7879"
,
.
owner
=
THIS_MODULE
,
},
.
probe
=
ad7879_probe
,
.
remove
=
__devexit_p
(
ad7879_remove
),
.
suspend
=
ad7879_suspend
,
.
resume
=
ad7879_resume
,
.
id_table
=
ad7879_id
,
};
static
int
__init
ad7879_init
(
void
)
{
return
i2c_add_driver
(
&
ad7879_driver
);
}
module_init
(
ad7879_init
);
static
void
__exit
ad7879_exit
(
void
)
{
i2c_del_driver
(
&
ad7879_driver
);
}
module_exit
(
ad7879_exit
);
#endif
EXPORT_SYMBOL
(
ad7879_remove
);
MODULE_AUTHOR
(
"Michael Hennerich <hennerich@blackfin.uclinux.org>"
);
MODULE_DESCRIPTION
(
"AD7879(-1) touchscreen Driver"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_ALIAS
(
"spi:ad7879"
);
drivers/input/touchscreen/ad7879.h
0 → 100644
View file @
929343ef
/*
* AD7879/AD7889 touchscreen (bus interfaces)
*
* Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#ifndef _AD7879_H_
#define _AD7879_H_
#include <linux/types.h>
struct
ad7879
;
struct
device
;
struct
ad7879_bus_ops
{
u16
bustype
;
int
(
*
read
)(
struct
device
*
dev
,
u8
reg
);
int
(
*
multi_read
)(
struct
device
*
dev
,
u8
first_reg
,
u8
count
,
u16
*
buf
);
int
(
*
write
)(
struct
device
*
dev
,
u8
reg
,
u16
val
);
};
void
ad7879_suspend
(
struct
ad7879
*
);
void
ad7879_resume
(
struct
ad7879
*
);
struct
ad7879
*
ad7879_probe
(
struct
device
*
dev
,
u8
devid
,
unsigned
irq
,
const
struct
ad7879_bus_ops
*
bops
);
void
ad7879_remove
(
struct
ad7879
*
);
#endif
drivers/input/touchscreen/ads7846.c
View file @
929343ef
...
...
@@ -68,6 +68,8 @@ struct ts_event {
u16
y
;
u16
z1
,
z2
;
int
ignore
;
u8
x_buf
[
3
];
u8
y_buf
[
3
];
};
/*
...
...
@@ -79,6 +81,8 @@ struct ads7846_packet {
u8
read_x
,
read_y
,
read_z1
,
read_z2
,
pwrdown
;
u16
dummy
;
/* for the pwrdown read */
struct
ts_event
tc
;
/* for ads7845 with mpc5121 psc spi we use 3-byte buffers */
u8
read_x_cmd
[
3
],
read_y_cmd
[
3
],
pwrdown_cmd
[
3
];
};
struct
ads7846
{
...
...
@@ -207,6 +211,14 @@ struct ser_req {
struct
spi_transfer
xfer
[
6
];
};
struct
ads7845_ser_req
{
u8
command
[
3
];
u8
pwrdown
[
3
];
u8
sample
[
3
];
struct
spi_message
msg
;
struct
spi_transfer
xfer
[
2
];
};
static
void
ads7846_enable
(
struct
ads7846
*
ts
);
static
void
ads7846_disable
(
struct
ads7846
*
ts
);
...
...
@@ -287,6 +299,41 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
return
status
;
}
static
int
ads7845_read12_ser
(
struct
device
*
dev
,
unsigned
command
)
{
struct
spi_device
*
spi
=
to_spi_device
(
dev
);
struct
ads7846
*
ts
=
dev_get_drvdata
(
dev
);
struct
ads7845_ser_req
*
req
=
kzalloc
(
sizeof
*
req
,
GFP_KERNEL
);
int
status
;
if
(
!
req
)
return
-
ENOMEM
;
spi_message_init
(
&
req
->
msg
);
req
->
command
[
0
]
=
(
u8
)
command
;
req
->
xfer
[
0
].
tx_buf
=
req
->
command
;
req
->
xfer
[
0
].
rx_buf
=
req
->
sample
;
req
->
xfer
[
0
].
len
=
3
;
spi_message_add_tail
(
&
req
->
xfer
[
0
],
&
req
->
msg
);
ts
->
irq_disabled
=
1
;
disable_irq
(
spi
->
irq
);
status
=
spi_sync
(
spi
,
&
req
->
msg
);
ts
->
irq_disabled
=
0
;
enable_irq
(
spi
->
irq
);
if
(
status
==
0
)
{
/* BE12 value, then padding */
status
=
be16_to_cpu
(
*
((
u16
*
)
&
req
->
sample
[
1
]));
status
=
status
>>
3
;
status
&=
0x0fff
;
}
kfree
(
req
);
return
status
;
}
#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
#define SHOW(name, var, adjust) static ssize_t \
...
...
@@ -540,10 +587,17 @@ static void ads7846_rx(void *ads)
/* ads7846_rx_val() did in-place conversion (including byteswap) from
* on-the-wire format as part of debouncing to get stable readings.
*/
x
=
packet
->
tc
.
x
;
y
=
packet
->
tc
.
y
;
z1
=
packet
->
tc
.
z1
;
z2
=
packet
->
tc
.
z2
;
if
(
ts
->
model
==
7845
)
{
x
=
*
(
u16
*
)
packet
->
tc
.
x_buf
;
y
=
*
(
u16
*
)
packet
->
tc
.
y_buf
;
z1
=
0
;
z2
=
0
;
}
else
{
x
=
packet
->
tc
.
x
;
y
=
packet
->
tc
.
y
;
z1
=
packet
->
tc
.
z1
;
z2
=
packet
->
tc
.
z2
;
}
/* range filtering */
if
(
x
==
MAX_12BIT
)
...
...
@@ -551,6 +605,12 @@ static void ads7846_rx(void *ads)
if
(
ts
->
model
==
7843
)
{
Rt
=
ts
->
pressure_max
/
2
;
}
else
if
(
ts
->
model
==
7845
)
{
if
(
get_pendown_state
(
ts
))
Rt
=
ts
->
pressure_max
/
2
;
else
Rt
=
0
;
dev_vdbg
(
&
ts
->
spi
->
dev
,
"x/y: %d/%d, PD %d
\n
"
,
x
,
y
,
Rt
);
}
else
if
(
likely
(
x
&&
z1
))
{
/* compute touch pressure resistance using equation #2 */
Rt
=
z2
;
...
...
@@ -671,10 +731,14 @@ static void ads7846_rx_val(void *ads)
m
=
&
ts
->
msg
[
ts
->
msg_idx
];
t
=
list_entry
(
m
->
transfers
.
prev
,
struct
spi_transfer
,
transfer_list
);
/* adjust: on-wire is a must-ignore bit, a BE12 value, then padding;
* built from two 8 bit values written msb-first.
*/
val
=
be16_to_cpup
((
__be16
*
)
t
->
rx_buf
)
>>
3
;
if
(
ts
->
model
==
7845
)
{
val
=
be16_to_cpup
((
__be16
*
)
&
(((
char
*
)
t
->
rx_buf
)[
1
]))
>>
3
;
}
else
{
/* adjust: on-wire is a must-ignore bit, a BE12 value, then
* padding; built from two 8 bit values written msb-first.
*/
val
=
be16_to_cpup
((
__be16
*
)
t
->
rx_buf
)
>>
3
;
}
action
=
ts
->
filter
(
ts
->
filter_data
,
ts
->
msg_idx
,
&
val
);
switch
(
action
)
{
...
...
@@ -878,14 +942,15 @@ static int __devinit setup_pendown(struct spi_device *spi, struct ads7846 *ts)
static
int
__devinit
ads7846_probe
(
struct
spi_device
*
spi
)
{
struct
ads7846
*
ts
;
struct
ads7846_packet
*
packet
;
struct
input_dev
*
input_dev
;
struct
ads7846_platform_data
*
pdata
=
spi
->
dev
.
platform_data
;
struct
spi_message
*
m
;
struct
spi_transfer
*
x
;
int
vref
;
int
err
;
struct
ads7846
*
ts
;
struct
ads7846_packet
*
packet
;
struct
input_dev
*
input_dev
;
const
struct
ads7846_platform_data
*
pdata
=
spi
->
dev
.
platform_data
;
struct
spi_message
*
m
;
struct
spi_transfer
*
x
;
unsigned
long
irq_flags
;
int
vref
;
int
err
;
if
(
!
spi
->
irq
)
{
dev_dbg
(
&
spi
->
dev
,
"no IRQ?
\n
"
);
...
...
@@ -1008,16 +1073,26 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi_message_init
(
m
);
/* y- still on; turn on only y+ (and ADC) */
packet
->
read_y
=
READ_Y
(
vref
);
x
->
tx_buf
=
&
packet
->
read_y
;
x
->
len
=
1
;
spi_message_add_tail
(
x
,
m
);
if
(
ts
->
model
==
7845
)
{
packet
->
read_y_cmd
[
0
]
=
READ_Y
(
vref
);
packet
->
read_y_cmd
[
1
]
=
0
;
packet
->
read_y_cmd
[
2
]
=
0
;
x
->
tx_buf
=
&
packet
->
read_y_cmd
[
0
];
x
->
rx_buf
=
&
packet
->
tc
.
y_buf
[
0
];
x
->
len
=
3
;
spi_message_add_tail
(
x
,
m
);
}
else
{
/* y- still on; turn on only y+ (and ADC) */
packet
->
read_y
=
READ_Y
(
vref
);
x
->
tx_buf
=
&
packet
->
read_y
;
x
->
len
=
1
;
spi_message_add_tail
(
x
,
m
);
x
++
;
x
->
rx_buf
=
&
packet
->
tc
.
y
;
x
->
len
=
2
;
spi_message_add_tail
(
x
,
m
);
x
++
;
x
->
rx_buf
=
&
packet
->
tc
.
y
;
x
->
len
=
2
;
spi_message_add_tail
(
x
,
m
);
}
/* the first sample after switching drivers can be low quality;
* optionally discard it, using a second one after the signals
...
...
@@ -1043,17 +1118,28 @@ static int __devinit ads7846_probe(struct spi_device *spi)
m
++
;
spi_message_init
(
m
);
/* turn y- off, x+ on, then leave in lowpower */
x
++
;
packet
->
read_x
=
READ_X
(
vref
);
x
->
tx_buf
=
&
packet
->
read_x
;
x
->
len
=
1
;
spi_message_add_tail
(
x
,
m
);
if
(
ts
->
model
==
7845
)
{
x
++
;
packet
->
read_x_cmd
[
0
]
=
READ_X
(
vref
);
packet
->
read_x_cmd
[
1
]
=
0
;
packet
->
read_x_cmd
[
2
]
=
0
;
x
->
tx_buf
=
&
packet
->
read_x_cmd
[
0
];
x
->
rx_buf
=
&
packet
->
tc
.
x_buf
[
0
];
x
->
len
=
3
;
spi_message_add_tail
(
x
,
m
);
}
else
{
/* turn y- off, x+ on, then leave in lowpower */
x
++
;
packet
->
read_x
=
READ_X
(
vref
);
x
->
tx_buf
=
&
packet
->
read_x
;
x
->
len
=
1
;
spi_message_add_tail
(
x
,
m
);
x
++
;
x
->
rx_buf
=
&
packet
->
tc
.
x
;
x
->
len
=
2
;
spi_message_add_tail
(
x
,
m
);
x
++
;
x
->
rx_buf
=
&
packet
->
tc
.
x
;
x
->
len
=
2
;
spi_message_add_tail
(
x
,
m
);
}
/* ... maybe discard first sample ... */
if
(
pdata
->
settle_delay_usecs
)
{
...
...
@@ -1144,15 +1230,25 @@ static int __devinit ads7846_probe(struct spi_device *spi)
m
++
;
spi_message_init
(
m
);
x
++
;
packet
->
pwrdown
=
PWRDOWN
;
x
->
tx_buf
=
&
packet
->
pwrdown
;
x
->
len
=
1
;
spi_message_add_tail
(
x
,
m
);
if
(
ts
->
model
==
7845
)
{
x
++
;
packet
->
pwrdown_cmd
[
0
]
=
PWRDOWN
;
packet
->
pwrdown_cmd
[
1
]
=
0
;
packet
->
pwrdown_cmd
[
2
]
=
0
;
x
->
tx_buf
=
&
packet
->
pwrdown_cmd
[
0
];
x
->
len
=
3
;
}
else
{
x
++
;
packet
->
pwrdown
=
PWRDOWN
;
x
->
tx_buf
=
&
packet
->
pwrdown
;
x
->
len
=
1
;
spi_message_add_tail
(
x
,
m
);
x
++
;
x
->
rx_buf
=
&
packet
->
dummy
;
x
->
len
=
2
;
}
x
++
;
x
->
rx_buf
=
&
packet
->
dummy
;
x
->
len
=
2
;
CS_CHANGE
(
*
x
);
spi_message_add_tail
(
x
,
m
);
...
...
@@ -1174,17 +1270,22 @@ static int __devinit ads7846_probe(struct spi_device *spi)
goto
err_put_regulator
;
}
if
(
request_irq
(
spi
->
irq
,
ads7846_irq
,
IRQF_TRIGGER_FALLING
,
spi
->
dev
.
driver
->
name
,
ts
))
{
irq_flags
=
pdata
->
irq_flags
?
:
IRQF_TRIGGER_FALLING
;
err
=
request_irq
(
spi
->
irq
,
ads7846_irq
,
irq_flags
,
spi
->
dev
.
driver
->
name
,
ts
);
if
(
err
&&
!
pdata
->
irq_flags
)
{
dev_info
(
&
spi
->
dev
,
"trying pin change workaround on irq %d
\n
"
,
spi
->
irq
);
err
=
request_irq
(
spi
->
irq
,
ads7846_irq
,
IRQF_TRIGGER_FALLING
|
IRQF_TRIGGER_RISING
,
spi
->
dev
.
driver
->
name
,
ts
);
if
(
err
)
{
dev_dbg
(
&
spi
->
dev
,
"irq %d busy?
\n
"
,
spi
->
irq
);
goto
err_disable_regulator
;
}
}
if
(
err
)
{
dev_dbg
(
&
spi
->
dev
,
"irq %d busy?
\n
"
,
spi
->
irq
);
goto
err_disable_regulator
;
}
err
=
ads784x_hwmon_register
(
spi
,
ts
);
...
...
@@ -1196,8 +1297,11 @@ static int __devinit ads7846_probe(struct spi_device *spi)
/* take a first sample, leaving nPENIRQ active and vREF off; avoid
* the touchscreen, in case it's not connected.
*/
(
void
)
ads7846_read12_ser
(
&
spi
->
dev
,
READ_12BIT_SER
(
vaux
)
|
ADS_PD10_ALL_ON
);
if
(
ts
->
model
==
7845
)
ads7845_read12_ser
(
&
spi
->
dev
,
PWRDOWN
);
else
(
void
)
ads7846_read12_ser
(
&
spi
->
dev
,
READ_12BIT_SER
(
vaux
)
|
ADS_PD10_ALL_ON
);
err
=
sysfs_create_group
(
&
spi
->
dev
.
kobj
,
&
ads784x_attr_group
);
if
(
err
)
...
...
drivers/input/touchscreen/cy8ctmg110_ts.c
0 → 100644
View file @
929343ef
/*
* Driver for cypress touch screen controller
*
* Copyright (c) 2009 Aava Mobile
*
* Some cleanups by Alan Cox <alan@linux.intel.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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/input/cy8ctmg110_pdata.h>
#define CY8CTMG110_DRIVER_NAME "cy8ctmg110"
/* Touch coordinates */
#define CY8CTMG110_X_MIN 0
#define CY8CTMG110_Y_MIN 0
#define CY8CTMG110_X_MAX 759
#define CY8CTMG110_Y_MAX 465
/* cy8ctmg110 register definitions */
#define CY8CTMG110_TOUCH_WAKEUP_TIME 0
#define CY8CTMG110_TOUCH_SLEEP_TIME 2
#define CY8CTMG110_TOUCH_X1 3
#define CY8CTMG110_TOUCH_Y1 5
#define CY8CTMG110_TOUCH_X2 7
#define CY8CTMG110_TOUCH_Y2 9
#define CY8CTMG110_FINGERS 11
#define CY8CTMG110_GESTURE 12
#define CY8CTMG110_REG_MAX 13
/*
* The touch driver structure.
*/
struct
cy8ctmg110
{
struct
input_dev
*
input
;
char
phys
[
32
];
struct
i2c_client
*
client
;
int
reset_pin
;
int
irq_pin
;
};
/*
* cy8ctmg110_power is the routine that is called when touch hardware
* will powered off or on.
*/
static
void
cy8ctmg110_power
(
struct
cy8ctmg110
*
ts
,
bool
poweron
)
{
if
(
ts
->
reset_pin
)
gpio_direction_output
(
ts
->
reset_pin
,
1
-
poweron
);
}
static
int
cy8ctmg110_write_regs
(
struct
cy8ctmg110
*
tsc
,
unsigned
char
reg
,
unsigned
char
len
,
unsigned
char
*
value
)
{
struct
i2c_client
*
client
=
tsc
->
client
;
unsigned
int
ret
;
unsigned
char
i2c_data
[
6
];
BUG_ON
(
len
>
5
);
i2c_data
[
0
]
=
reg
;
memcpy
(
i2c_data
+
1
,
value
,
len
);
ret
=
i2c_master_send
(
client
,
i2c_data
,
len
+
1
);
if
(
ret
!=
1
)
{
dev_err
(
&
client
->
dev
,
"i2c write data cmd failed
\n
"
);
return
ret
;
}
return
0
;
}
static
int
cy8ctmg110_read_regs
(
struct
cy8ctmg110
*
tsc
,
unsigned
char
*
data
,
unsigned
char
len
,
unsigned
char
cmd
)
{
struct
i2c_client
*
client
=
tsc
->
client
;
unsigned
int
ret
;
struct
i2c_msg
msg
[
2
]
=
{
/* first write slave position to i2c devices */
{
client
->
addr
,
0
,
1
,
&
cmd
},
/* Second read data from position */
{
client
->
addr
,
I2C_M_RD
,
len
,
data
}
};
ret
=
i2c_transfer
(
client
->
adapter
,
msg
,
2
);
if
(
ret
<
0
)
return
ret
;
return
0
;
}
static
int
cy8ctmg110_touch_pos
(
struct
cy8ctmg110
*
tsc
)
{
struct
input_dev
*
input
=
tsc
->
input
;
unsigned
char
reg_p
[
CY8CTMG110_REG_MAX
];
int
x
,
y
;
memset
(
reg_p
,
0
,
CY8CTMG110_REG_MAX
);
/* Reading coordinates */
if
(
cy8ctmg110_read_regs
(
tsc
,
reg_p
,
9
,
CY8CTMG110_TOUCH_X1
)
!=
0
)
return
-
EIO
;
y
=
reg_p
[
2
]
<<
8
|
reg_p
[
3
];
x
=
reg_p
[
0
]
<<
8
|
reg_p
[
1
];
/* Number of touch */
if
(
reg_p
[
8
]
==
0
)
{
input_report_key
(
input
,
BTN_TOUCH
,
0
);
}
else
{
input_report_key
(
input
,
BTN_TOUCH
,
1
);
input_report_abs
(
input
,
ABS_X
,
x
);
input_report_abs
(
input
,
ABS_Y
,
y
);
}
input_sync
(
input
);
return
0
;
}
static
int
cy8ctmg110_set_sleepmode
(
struct
cy8ctmg110
*
ts
,
bool
sleep
)
{
unsigned
char
reg_p
[
3
];
if
(
sleep
)
{
reg_p
[
0
]
=
0x00
;
reg_p
[
1
]
=
0xff
;
reg_p
[
2
]
=
5
;
}
else
{
reg_p
[
0
]
=
0x10
;
reg_p
[
1
]
=
0xff
;
reg_p
[
2
]
=
0
;
}
return
cy8ctmg110_write_regs
(
ts
,
CY8CTMG110_TOUCH_WAKEUP_TIME
,
3
,
reg_p
);
}
static
irqreturn_t
cy8ctmg110_irq_thread
(
int
irq
,
void
*
dev_id
)
{
struct
cy8ctmg110
*
tsc
=
dev_id
;
cy8ctmg110_touch_pos
(
tsc
);
return
IRQ_HANDLED
;
}
static
int
__devinit
cy8ctmg110_probe
(
struct
i2c_client
*
client
,
const
struct
i2c_device_id
*
id
)
{
const
struct
cy8ctmg110_pdata
*
pdata
=
client
->
dev
.
platform_data
;
struct
cy8ctmg110
*
ts
;
struct
input_dev
*
input_dev
;
int
err
;
/* No pdata no way forward */
if
(
pdata
==
NULL
)
{
dev_err
(
&
client
->
dev
,
"no pdata
\n
"
);
return
-
ENODEV
;
}
if
(
!
i2c_check_functionality
(
client
->
adapter
,
I2C_FUNC_SMBUS_READ_WORD_DATA
))
return
-
EIO
;
ts
=
kzalloc
(
sizeof
(
struct
cy8ctmg110
),
GFP_KERNEL
);
input_dev
=
input_allocate_device
();
if
(
!
ts
||
!
input_dev
)
{
err
=
-
ENOMEM
;
goto
err_free_mem
;
}
ts
->
client
=
client
;
ts
->
input
=
input_dev
;
snprintf
(
ts
->
phys
,
sizeof
(
ts
->
phys
),
"%s/input0"
,
dev_name
(
&
client
->
dev
));
input_dev
->
name
=
CY8CTMG110_DRIVER_NAME
" Touchscreen"
;
input_dev
->
phys
=
ts
->
phys
;
input_dev
->
id
.
bustype
=
BUS_I2C
;
input_dev
->
dev
.
parent
=
&
client
->
dev
;
input_dev
->
evbit
[
0
]
=
BIT_MASK
(
EV_KEY
)
|
BIT_MASK
(
EV_ABS
);
input_dev
->
keybit
[
BIT_WORD
(
BTN_TOUCH
)]
=
BIT_MASK
(
BTN_TOUCH
);
input_set_abs_params
(
input_dev
,
ABS_X
,
CY8CTMG110_X_MIN
,
CY8CTMG110_X_MAX
,
0
,
0
);
input_set_abs_params
(
input_dev
,
ABS_Y
,
CY8CTMG110_Y_MIN
,
CY8CTMG110_Y_MAX
,
0
,
0
);
if
(
ts
->
reset_pin
)
{
err
=
gpio_request
(
ts
->
reset_pin
,
NULL
);
if
(
err
)
{
dev_err
(
&
client
->
dev
,
"Unable to request GPIO pin %d.
\n
"
,
ts
->
reset_pin
);
goto
err_free_mem
;
}
}
cy8ctmg110_power
(
ts
,
true
);
cy8ctmg110_set_sleepmode
(
ts
,
false
);
err
=
gpio_request
(
ts
->
irq_pin
,
"touch_irq_key"
);
if
(
err
<
0
)
{
dev_err
(
&
client
->
dev
,
"Failed to request GPIO %d, error %d
\n
"
,
ts
->
irq_pin
,
err
);
goto
err_shutoff_device
;
}
err
=
gpio_direction_input
(
ts
->
irq_pin
);
if
(
err
<
0
)
{
dev_err
(
&
client
->
dev
,
"Failed to configure input direction for GPIO %d, error %d
\n
"
,
ts
->
irq_pin
,
err
);
goto
err_free_irq_gpio
;
}
client
->
irq
=
gpio_to_irq
(
ts
->
irq_pin
);
if
(
client
->
irq
<
0
)
{
err
=
client
->
irq
;
dev_err
(
&
client
->
dev
,
"Unable to get irq number for GPIO %d, error %d
\n
"
,
ts
->
irq_pin
,
err
);
goto
err_free_irq_gpio
;
}
err
=
request_threaded_irq
(
client
->
irq
,
NULL
,
cy8ctmg110_irq_thread
,
IRQF_TRIGGER_RISING
,
"touch_reset_key"
,
ts
);
if
(
err
<
0
)
{
dev_err
(
&
client
->
dev
,
"irq %d busy? error %d
\n
"
,
client
->
irq
,
err
);
goto
err_free_irq_gpio
;
}
err
=
input_register_device
(
input_dev
);
if
(
err
)
goto
err_free_irq
;
i2c_set_clientdata
(
client
,
ts
);
device_init_wakeup
(
&
client
->
dev
,
1
);
return
0
;
err_free_irq:
free_irq
(
client
->
irq
,
ts
);
err_free_irq_gpio:
gpio_free
(
ts
->
irq_pin
);
err_shutoff_device:
cy8ctmg110_set_sleepmode
(
ts
,
true
);
cy8ctmg110_power
(
ts
,
false
);
if
(
ts
->
reset_pin
)
gpio_free
(
ts
->
reset_pin
);
err_free_mem:
input_free_device
(
input_dev
);
kfree
(
ts
);
return
err
;
}
#ifdef CONFIG_PM
static
int
cy8ctmg110_suspend
(
struct
i2c_client
*
client
,
pm_message_t
mesg
)
{
struct
cy8ctmg110
*
ts
=
i2c_get_clientdata
(
client
);
if
(
device_may_wakeup
(
&
client
->
dev
))
enable_irq_wake
(
client
->
irq
);
else
{
cy8ctmg110_set_sleepmode
(
ts
,
true
);
cy8ctmg110_power
(
ts
,
false
);
}
return
0
;
}
static
int
cy8ctmg110_resume
(
struct
i2c_client
*
client
)
{
struct
cy8ctmg110
*
ts
=
i2c_get_clientdata
(
client
);
if
(
device_may_wakeup
(
&
client
->
dev
))
disable_irq_wake
(
client
->
irq
);
else
{
cy8ctmg110_power
(
ts
,
true
);
cy8ctmg110_set_sleepmode
(
ts
,
false
);
}
return
0
;
}
#endif
static
int
__devexit
cy8ctmg110_remove
(
struct
i2c_client
*
client
)
{
struct
cy8ctmg110
*
ts
=
i2c_get_clientdata
(
client
);
cy8ctmg110_set_sleepmode
(
ts
,
true
);
cy8ctmg110_power
(
ts
,
false
);
free_irq
(
client
->
irq
,
ts
);
input_unregister_device
(
ts
->
input
);
gpio_free
(
ts
->
irq_pin
);
if
(
ts
->
reset_pin
)
gpio_free
(
ts
->
reset_pin
);
kfree
(
ts
);
return
0
;
}
static
struct
i2c_device_id
cy8ctmg110_idtable
[]
=
{
{
CY8CTMG110_DRIVER_NAME
,
1
},
{
}
};
MODULE_DEVICE_TABLE
(
i2c
,
cy8ctmg110_idtable
);
static
struct
i2c_driver
cy8ctmg110_driver
=
{
.
driver
=
{
.
owner
=
THIS_MODULE
,
.
name
=
CY8CTMG110_DRIVER_NAME
,
},
.
id_table
=
cy8ctmg110_idtable
,
.
probe
=
cy8ctmg110_probe
,
.
remove
=
__devexit_p
(
cy8ctmg110_remove
),
#ifdef CONFIG_PM
.
suspend
=
cy8ctmg110_suspend
,
.
resume
=
cy8ctmg110_resume
,
#endif
};
static
int
__init
cy8ctmg110_init
(
void
)
{
return
i2c_add_driver
(
&
cy8ctmg110_driver
);
}
static
void
__exit
cy8ctmg110_exit
(
void
)
{
i2c_del_driver
(
&
cy8ctmg110_driver
);
}
module_init
(
cy8ctmg110_init
);
module_exit
(
cy8ctmg110_exit
);
MODULE_AUTHOR
(
"Samuli Konttila <samuli.konttila@aavamobile.com>"
);
MODULE_DESCRIPTION
(
"cy8ctmg110 TouchScreen Driver"
);
MODULE_LICENSE
(
"GPL v2"
);
drivers/input/touchscreen/mcs5000_ts.c
View file @
929343ef
...
...
@@ -16,7 +16,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/i2c/mcs
5000_ts
.h>
#include <linux/i2c/mcs.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/irq.h>
...
...
@@ -105,7 +105,7 @@ enum mcs5000_ts_read_offset {
struct
mcs5000_ts_data
{
struct
i2c_client
*
client
;
struct
input_dev
*
input_dev
;
const
struct
mcs
5000_ts
_platform_data
*
platform_data
;
const
struct
mcs_platform_data
*
platform_data
;
};
static
irqreturn_t
mcs5000_ts_interrupt
(
int
irq
,
void
*
dev_id
)
...
...
@@ -164,7 +164,7 @@ static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)
static
void
mcs5000_ts_phys_init
(
struct
mcs5000_ts_data
*
data
)
{
const
struct
mcs
5000_ts
_platform_data
*
platform_data
=
const
struct
mcs_platform_data
*
platform_data
=
data
->
platform_data
;
struct
i2c_client
*
client
=
data
->
client
;
...
...
drivers/input/touchscreen/qt602240_ts.c
0 → 100644
View file @
929343ef
/*
* AT42QT602240/ATMXT224 Touchscreen driver
*
* Copyright (C) 2010 Samsung Electronics Co.Ltd
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/i2c.h>
#include <linux/i2c/qt602240_ts.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
/* Version */
#define QT602240_VER_20 20
#define QT602240_VER_21 21
#define QT602240_VER_22 22
/* Slave addresses */
#define QT602240_APP_LOW 0x4a
#define QT602240_APP_HIGH 0x4b
#define QT602240_BOOT_LOW 0x24
#define QT602240_BOOT_HIGH 0x25
/* Firmware */
#define QT602240_FW_NAME "qt602240.fw"
/* Registers */
#define QT602240_FAMILY_ID 0x00
#define QT602240_VARIANT_ID 0x01
#define QT602240_VERSION 0x02
#define QT602240_BUILD 0x03
#define QT602240_MATRIX_X_SIZE 0x04
#define QT602240_MATRIX_Y_SIZE 0x05
#define QT602240_OBJECT_NUM 0x06
#define QT602240_OBJECT_START 0x07
#define QT602240_OBJECT_SIZE 6
/* Object types */
#define QT602240_DEBUG_DIAGNOSTIC 37
#define QT602240_GEN_MESSAGE 5
#define QT602240_GEN_COMMAND 6
#define QT602240_GEN_POWER 7
#define QT602240_GEN_ACQUIRE 8
#define QT602240_TOUCH_MULTI 9
#define QT602240_TOUCH_KEYARRAY 15
#define QT602240_TOUCH_PROXIMITY 23
#define QT602240_PROCI_GRIPFACE 20
#define QT602240_PROCG_NOISE 22
#define QT602240_PROCI_ONETOUCH 24
#define QT602240_PROCI_TWOTOUCH 27
#define QT602240_SPT_COMMSCONFIG 18
/* firmware ver 21 over */
#define QT602240_SPT_GPIOPWM 19
#define QT602240_SPT_SELFTEST 25
#define QT602240_SPT_CTECONFIG 28
#define QT602240_SPT_USERDATA 38
/* firmware ver 21 over */
/* QT602240_GEN_COMMAND field */
#define QT602240_COMMAND_RESET 0
#define QT602240_COMMAND_BACKUPNV 1
#define QT602240_COMMAND_CALIBRATE 2
#define QT602240_COMMAND_REPORTALL 3
#define QT602240_COMMAND_DIAGNOSTIC 5
/* QT602240_GEN_POWER field */
#define QT602240_POWER_IDLEACQINT 0
#define QT602240_POWER_ACTVACQINT 1
#define QT602240_POWER_ACTV2IDLETO 2
/* QT602240_GEN_ACQUIRE field */
#define QT602240_ACQUIRE_CHRGTIME 0
#define QT602240_ACQUIRE_TCHDRIFT 2
#define QT602240_ACQUIRE_DRIFTST 3
#define QT602240_ACQUIRE_TCHAUTOCAL 4
#define QT602240_ACQUIRE_SYNC 5
#define QT602240_ACQUIRE_ATCHCALST 6
#define QT602240_ACQUIRE_ATCHCALSTHR 7
/* QT602240_TOUCH_MULTI field */
#define QT602240_TOUCH_CTRL 0
#define QT602240_TOUCH_XORIGIN 1
#define QT602240_TOUCH_YORIGIN 2
#define QT602240_TOUCH_XSIZE 3
#define QT602240_TOUCH_YSIZE 4
#define QT602240_TOUCH_BLEN 6
#define QT602240_TOUCH_TCHTHR 7
#define QT602240_TOUCH_TCHDI 8
#define QT602240_TOUCH_ORIENT 9
#define QT602240_TOUCH_MOVHYSTI 11
#define QT602240_TOUCH_MOVHYSTN 12
#define QT602240_TOUCH_NUMTOUCH 14
#define QT602240_TOUCH_MRGHYST 15
#define QT602240_TOUCH_MRGTHR 16
#define QT602240_TOUCH_AMPHYST 17
#define QT602240_TOUCH_XRANGE_LSB 18
#define QT602240_TOUCH_XRANGE_MSB 19
#define QT602240_TOUCH_YRANGE_LSB 20
#define QT602240_TOUCH_YRANGE_MSB 21
#define QT602240_TOUCH_XLOCLIP 22
#define QT602240_TOUCH_XHICLIP 23
#define QT602240_TOUCH_YLOCLIP 24
#define QT602240_TOUCH_YHICLIP 25
#define QT602240_TOUCH_XEDGECTRL 26
#define QT602240_TOUCH_XEDGEDIST 27
#define QT602240_TOUCH_YEDGECTRL 28
#define QT602240_TOUCH_YEDGEDIST 29
#define QT602240_TOUCH_JUMPLIMIT 30
/* firmware ver 22 over */
/* QT602240_PROCI_GRIPFACE field */
#define QT602240_GRIPFACE_CTRL 0
#define QT602240_GRIPFACE_XLOGRIP 1
#define QT602240_GRIPFACE_XHIGRIP 2
#define QT602240_GRIPFACE_YLOGRIP 3
#define QT602240_GRIPFACE_YHIGRIP 4
#define QT602240_GRIPFACE_MAXTCHS 5
#define QT602240_GRIPFACE_SZTHR1 7
#define QT602240_GRIPFACE_SZTHR2 8
#define QT602240_GRIPFACE_SHPTHR1 9
#define QT602240_GRIPFACE_SHPTHR2 10
#define QT602240_GRIPFACE_SUPEXTTO 11
/* QT602240_PROCI_NOISE field */
#define QT602240_NOISE_CTRL 0
#define QT602240_NOISE_OUTFLEN 1
#define QT602240_NOISE_GCAFUL_LSB 3
#define QT602240_NOISE_GCAFUL_MSB 4
#define QT602240_NOISE_GCAFLL_LSB 5
#define QT602240_NOISE_GCAFLL_MSB 6
#define QT602240_NOISE_ACTVGCAFVALID 7
#define QT602240_NOISE_NOISETHR 8
#define QT602240_NOISE_FREQHOPSCALE 10
#define QT602240_NOISE_FREQ0 11
#define QT602240_NOISE_FREQ1 12
#define QT602240_NOISE_FREQ2 13
#define QT602240_NOISE_FREQ3 14
#define QT602240_NOISE_FREQ4 15
#define QT602240_NOISE_IDLEGCAFVALID 16
/* QT602240_SPT_COMMSCONFIG */
#define QT602240_COMMS_CTRL 0
#define QT602240_COMMS_CMD 1
/* QT602240_SPT_CTECONFIG field */
#define QT602240_CTE_CTRL 0
#define QT602240_CTE_CMD 1
#define QT602240_CTE_MODE 2
#define QT602240_CTE_IDLEGCAFDEPTH 3
#define QT602240_CTE_ACTVGCAFDEPTH 4
#define QT602240_CTE_VOLTAGE 5
/* firmware ver 21 over */
#define QT602240_VOLTAGE_DEFAULT 2700000
#define QT602240_VOLTAGE_STEP 10000
/* Define for QT602240_GEN_COMMAND */
#define QT602240_BOOT_VALUE 0xa5
#define QT602240_BACKUP_VALUE 0x55
#define QT602240_BACKUP_TIME 25
/* msec */
#define QT602240_RESET_TIME 65
/* msec */
#define QT602240_FWRESET_TIME 175
/* msec */
/* Command to unlock bootloader */
#define QT602240_UNLOCK_CMD_MSB 0xaa
#define QT602240_UNLOCK_CMD_LSB 0xdc
/* Bootloader mode status */
#define QT602240_WAITING_BOOTLOAD_CMD 0xc0
/* valid 7 6 bit only */
#define QT602240_WAITING_FRAME_DATA 0x80
/* valid 7 6 bit only */
#define QT602240_FRAME_CRC_CHECK 0x02
#define QT602240_FRAME_CRC_FAIL 0x03
#define QT602240_FRAME_CRC_PASS 0x04
#define QT602240_APP_CRC_FAIL 0x40
/* valid 7 8 bit only */
#define QT602240_BOOT_STATUS_MASK 0x3f
/* Touch status */
#define QT602240_SUPPRESS (1 << 1)
#define QT602240_AMP (1 << 2)
#define QT602240_VECTOR (1 << 3)
#define QT602240_MOVE (1 << 4)
#define QT602240_RELEASE (1 << 5)
#define QT602240_PRESS (1 << 6)
#define QT602240_DETECT (1 << 7)
/* Touchscreen absolute values */
#define QT602240_MAX_XC 0x3ff
#define QT602240_MAX_YC 0x3ff
#define QT602240_MAX_AREA 0xff
#define QT602240_MAX_FINGER 10
/* Initial register values recommended from chip vendor */
static
const
u8
init_vals_ver_20
[]
=
{
/* QT602240_GEN_COMMAND(6) */
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
/* QT602240_GEN_POWER(7) */
0x20
,
0xff
,
0x32
,
/* QT602240_GEN_ACQUIRE(8) */
0x08
,
0x05
,
0x05
,
0x00
,
0x00
,
0x00
,
0x05
,
0x14
,
/* QT602240_TOUCH_MULTI(9) */
0x00
,
0x00
,
0x00
,
0x11
,
0x0a
,
0x00
,
0x00
,
0x00
,
0x02
,
0x00
,
0x00
,
0x01
,
0x01
,
0x0e
,
0x0a
,
0x0a
,
0x0a
,
0x0a
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x88
,
0x64
,
/* QT602240_TOUCH_KEYARRAY(15) */
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
/* QT602240_SPT_GPIOPWM(19) */
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
/* QT602240_PROCI_GRIPFACE(20) */
0x00
,
0x64
,
0x64
,
0x64
,
0x64
,
0x00
,
0x00
,
0x1e
,
0x14
,
0x04
,
0x1e
,
0x00
,
/* QT602240_PROCG_NOISE(22) */
0x05
,
0x00
,
0x00
,
0x19
,
0x00
,
0xe7
,
0xff
,
0x04
,
0x32
,
0x00
,
0x01
,
0x0a
,
0x0f
,
0x14
,
0x00
,
0x00
,
0xe8
,
/* QT602240_TOUCH_PROXIMITY(23) */
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
/* QT602240_PROCI_ONETOUCH(24) */
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
/* QT602240_SPT_SELFTEST(25) */
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
/* QT602240_PROCI_TWOTOUCH(27) */
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
/* QT602240_SPT_CTECONFIG(28) */
0x00
,
0x00
,
0x00
,
0x04
,
0x08
,
};
static
const
u8
init_vals_ver_21
[]
=
{
/* QT602240_GEN_COMMAND(6) */
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
/* QT602240_GEN_POWER(7) */
0x20
,
0xff
,
0x32
,
/* QT602240_GEN_ACQUIRE(8) */
0x0a
,
0x00
,
0x05
,
0x00
,
0x00
,
0x00
,
0x09
,
0x23
,
/* QT602240_TOUCH_MULTI(9) */
0x00
,
0x00
,
0x00
,
0x13
,
0x0b
,
0x00
,
0x00
,
0x00
,
0x02
,
0x00
,
0x00
,
0x01
,
0x01
,
0x0e
,
0x0a
,
0x0a
,
0x0a
,
0x0a
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
/* QT602240_TOUCH_KEYARRAY(15) */
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
/* QT602240_SPT_GPIOPWM(19) */
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
/* QT602240_PROCI_GRIPFACE(20) */
0x07
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x50
,
0x28
,
0x04
,
0x0f
,
0x0a
,
/* QT602240_PROCG_NOISE(22) */
0x05
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x03
,
0x23
,
0x00
,
0x00
,
0x05
,
0x0f
,
0x19
,
0x23
,
0x2d
,
0x03
,
/* QT602240_TOUCH_PROXIMITY(23) */
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
/* QT602240_PROCI_ONETOUCH(24) */
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
/* QT602240_SPT_SELFTEST(25) */
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
/* QT602240_PROCI_TWOTOUCH(27) */
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
/* QT602240_SPT_CTECONFIG(28) */
0x00
,
0x00
,
0x00
,
0x08
,
0x10
,
0x00
,
};
static
const
u8
init_vals_ver_22
[]
=
{
/* QT602240_GEN_COMMAND(6) */
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
/* QT602240_GEN_POWER(7) */
0x20
,
0xff
,
0x32
,
/* QT602240_GEN_ACQUIRE(8) */
0x0a
,
0x00
,
0x05
,
0x00
,
0x00
,
0x00
,
0x09
,
0x23
,
/* QT602240_TOUCH_MULTI(9) */
0x00
,
0x00
,
0x00
,
0x13
,
0x0b
,
0x00
,
0x00
,
0x00
,
0x02
,
0x00
,
0x00
,
0x01
,
0x01
,
0x0e
,
0x0a
,
0x0a
,
0x0a
,
0x0a
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
/* QT602240_TOUCH_KEYARRAY(15) */
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
/* QT602240_SPT_GPIOPWM(19) */
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
/* QT602240_PROCI_GRIPFACE(20) */
0x07
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x50
,
0x28
,
0x04
,
0x0f
,
0x0a
,
/* QT602240_PROCG_NOISE(22) */
0x05
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x03
,
0x23
,
0x00
,
0x00
,
0x05
,
0x0f
,
0x19
,
0x23
,
0x2d
,
0x03
,
/* QT602240_TOUCH_PROXIMITY(23) */
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
/* QT602240_PROCI_ONETOUCH(24) */
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
/* QT602240_SPT_SELFTEST(25) */
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
/* QT602240_PROCI_TWOTOUCH(27) */
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
/* QT602240_SPT_CTECONFIG(28) */
0x00
,
0x00
,
0x00
,
0x08
,
0x10
,
0x00
,
};
struct
qt602240_info
{
u8
family_id
;
u8
variant_id
;
u8
version
;
u8
build
;
u8
matrix_xsize
;
u8
matrix_ysize
;
u8
object_num
;
};
struct
qt602240_object
{
u8
type
;
u16
start_address
;
u8
size
;
u8
instances
;
u8
num_report_ids
;
/* to map object and message */
u8
max_reportid
;
};
struct
qt602240_message
{
u8
reportid
;
u8
message
[
7
];
u8
checksum
;
};
struct
qt602240_finger
{
int
status
;
int
x
;
int
y
;
int
area
;
};
/* Each client has this additional data */
struct
qt602240_data
{
struct
i2c_client
*
client
;
struct
input_dev
*
input_dev
;
const
struct
qt602240_platform_data
*
pdata
;
struct
qt602240_object
*
object_table
;
struct
qt602240_info
info
;
struct
qt602240_finger
finger
[
QT602240_MAX_FINGER
];
unsigned
int
irq
;
};
static
bool
qt602240_object_readable
(
unsigned
int
type
)
{
switch
(
type
)
{
case
QT602240_GEN_MESSAGE
:
case
QT602240_GEN_COMMAND
:
case
QT602240_GEN_POWER
:
case
QT602240_GEN_ACQUIRE
:
case
QT602240_TOUCH_MULTI
:
case
QT602240_TOUCH_KEYARRAY
:
case
QT602240_TOUCH_PROXIMITY
:
case
QT602240_PROCI_GRIPFACE
:
case
QT602240_PROCG_NOISE
:
case
QT602240_PROCI_ONETOUCH
:
case
QT602240_PROCI_TWOTOUCH
:
case
QT602240_SPT_COMMSCONFIG
:
case
QT602240_SPT_GPIOPWM
:
case
QT602240_SPT_SELFTEST
:
case
QT602240_SPT_CTECONFIG
:
case
QT602240_SPT_USERDATA
:
return
true
;
default:
return
false
;
}
}
static
bool
qt602240_object_writable
(
unsigned
int
type
)
{
switch
(
type
)
{
case
QT602240_GEN_COMMAND
:
case
QT602240_GEN_POWER
:
case
QT602240_GEN_ACQUIRE
:
case
QT602240_TOUCH_MULTI
:
case
QT602240_TOUCH_KEYARRAY
:
case
QT602240_TOUCH_PROXIMITY
:
case
QT602240_PROCI_GRIPFACE
:
case
QT602240_PROCG_NOISE
:
case
QT602240_PROCI_ONETOUCH
:
case
QT602240_PROCI_TWOTOUCH
:
case
QT602240_SPT_GPIOPWM
:
case
QT602240_SPT_SELFTEST
:
case
QT602240_SPT_CTECONFIG
:
return
true
;
default:
return
false
;
}
}
static
void
qt602240_dump_message
(
struct
device
*
dev
,
struct
qt602240_message
*
message
)
{
dev_dbg
(
dev
,
"reportid:
\t
0x%x
\n
"
,
message
->
reportid
);
dev_dbg
(
dev
,
"message1:
\t
0x%x
\n
"
,
message
->
message
[
0
]);
dev_dbg
(
dev
,
"message2:
\t
0x%x
\n
"
,
message
->
message
[
1
]);
dev_dbg
(
dev
,
"message3:
\t
0x%x
\n
"
,
message
->
message
[
2
]);
dev_dbg
(
dev
,
"message4:
\t
0x%x
\n
"
,
message
->
message
[
3
]);
dev_dbg
(
dev
,
"message5:
\t
0x%x
\n
"
,
message
->
message
[
4
]);
dev_dbg
(
dev
,
"message6:
\t
0x%x
\n
"
,
message
->
message
[
5
]);
dev_dbg
(
dev
,
"message7:
\t
0x%x
\n
"
,
message
->
message
[
6
]);
dev_dbg
(
dev
,
"checksum:
\t
0x%x
\n
"
,
message
->
checksum
);
}
static
int
qt602240_check_bootloader
(
struct
i2c_client
*
client
,
unsigned
int
state
)
{
u8
val
;
recheck:
if
(
i2c_master_recv
(
client
,
&
val
,
1
)
!=
1
)
{
dev_err
(
&
client
->
dev
,
"%s: i2c recv failed
\n
"
,
__func__
);
return
-
EIO
;
}
switch
(
state
)
{
case
QT602240_WAITING_BOOTLOAD_CMD
:
case
QT602240_WAITING_FRAME_DATA
:
val
&=
~
QT602240_BOOT_STATUS_MASK
;
break
;
case
QT602240_FRAME_CRC_PASS
:
if
(
val
==
QT602240_FRAME_CRC_CHECK
)
goto
recheck
;
break
;
default:
return
-
EINVAL
;
}
if
(
val
!=
state
)
{
dev_err
(
&
client
->
dev
,
"Unvalid bootloader mode state
\n
"
);
return
-
EINVAL
;
}
return
0
;
}
static
int
qt602240_unlock_bootloader
(
struct
i2c_client
*
client
)
{
u8
buf
[
2
];
buf
[
0
]
=
QT602240_UNLOCK_CMD_LSB
;
buf
[
1
]
=
QT602240_UNLOCK_CMD_MSB
;
if
(
i2c_master_send
(
client
,
buf
,
2
)
!=
2
)
{
dev_err
(
&
client
->
dev
,
"%s: i2c send failed
\n
"
,
__func__
);
return
-
EIO
;
}
return
0
;
}
static
int
qt602240_fw_write
(
struct
i2c_client
*
client
,
const
u8
*
data
,
unsigned
int
frame_size
)
{
if
(
i2c_master_send
(
client
,
data
,
frame_size
)
!=
frame_size
)
{
dev_err
(
&
client
->
dev
,
"%s: i2c send failed
\n
"
,
__func__
);
return
-
EIO
;
}
return
0
;
}
static
int
__qt602240_read_reg
(
struct
i2c_client
*
client
,
u16
reg
,
u16
len
,
void
*
val
)
{
struct
i2c_msg
xfer
[
2
];
u8
buf
[
2
];
buf
[
0
]
=
reg
&
0xff
;
buf
[
1
]
=
(
reg
>>
8
)
&
0xff
;
/* Write register */
xfer
[
0
].
addr
=
client
->
addr
;
xfer
[
0
].
flags
=
0
;
xfer
[
0
].
len
=
2
;
xfer
[
0
].
buf
=
buf
;
/* Read data */
xfer
[
1
].
addr
=
client
->
addr
;
xfer
[
1
].
flags
=
I2C_M_RD
;
xfer
[
1
].
len
=
len
;
xfer
[
1
].
buf
=
val
;
if
(
i2c_transfer
(
client
->
adapter
,
xfer
,
2
)
!=
2
)
{
dev_err
(
&
client
->
dev
,
"%s: i2c transfer failed
\n
"
,
__func__
);
return
-
EIO
;
}
return
0
;
}
static
int
qt602240_read_reg
(
struct
i2c_client
*
client
,
u16
reg
,
u8
*
val
)
{
return
__qt602240_read_reg
(
client
,
reg
,
1
,
val
);
}
static
int
qt602240_write_reg
(
struct
i2c_client
*
client
,
u16
reg
,
u8
val
)
{
u8
buf
[
3
];
buf
[
0
]
=
reg
&
0xff
;
buf
[
1
]
=
(
reg
>>
8
)
&
0xff
;
buf
[
2
]
=
val
;
if
(
i2c_master_send
(
client
,
buf
,
3
)
!=
3
)
{
dev_err
(
&
client
->
dev
,
"%s: i2c send failed
\n
"
,
__func__
);
return
-
EIO
;
}
return
0
;
}
static
int
qt602240_read_object_table
(
struct
i2c_client
*
client
,
u16
reg
,
u8
*
object_buf
)
{
return
__qt602240_read_reg
(
client
,
reg
,
QT602240_OBJECT_SIZE
,
object_buf
);
}
static
struct
qt602240_object
*
qt602240_get_object
(
struct
qt602240_data
*
data
,
u8
type
)
{
struct
qt602240_object
*
object
;
int
i
;
for
(
i
=
0
;
i
<
data
->
info
.
object_num
;
i
++
)
{
object
=
data
->
object_table
+
i
;
if
(
object
->
type
==
type
)
return
object
;
}
dev_err
(
&
data
->
client
->
dev
,
"Invalid object type
\n
"
);
return
NULL
;
}
static
int
qt602240_read_message
(
struct
qt602240_data
*
data
,
struct
qt602240_message
*
message
)
{
struct
qt602240_object
*
object
;
u16
reg
;
object
=
qt602240_get_object
(
data
,
QT602240_GEN_MESSAGE
);
if
(
!
object
)
return
-
EINVAL
;
reg
=
object
->
start_address
;
return
__qt602240_read_reg
(
data
->
client
,
reg
,
sizeof
(
struct
qt602240_message
),
message
);
}
static
int
qt602240_read_object
(
struct
qt602240_data
*
data
,
u8
type
,
u8
offset
,
u8
*
val
)
{
struct
qt602240_object
*
object
;
u16
reg
;
object
=
qt602240_get_object
(
data
,
type
);
if
(
!
object
)
return
-
EINVAL
;
reg
=
object
->
start_address
;
return
__qt602240_read_reg
(
data
->
client
,
reg
+
offset
,
1
,
val
);
}
static
int
qt602240_write_object
(
struct
qt602240_data
*
data
,
u8
type
,
u8
offset
,
u8
val
)
{
struct
qt602240_object
*
object
;
u16
reg
;
object
=
qt602240_get_object
(
data
,
type
);
if
(
!
object
)
return
-
EINVAL
;
reg
=
object
->
start_address
;
return
qt602240_write_reg
(
data
->
client
,
reg
+
offset
,
val
);
}
static
void
qt602240_input_report
(
struct
qt602240_data
*
data
,
int
single_id
)
{
struct
qt602240_finger
*
finger
=
data
->
finger
;
struct
input_dev
*
input_dev
=
data
->
input_dev
;
int
status
=
finger
[
single_id
].
status
;
int
finger_num
=
0
;
int
id
;
for
(
id
=
0
;
id
<
QT602240_MAX_FINGER
;
id
++
)
{
if
(
!
finger
[
id
].
status
)
continue
;
input_report_abs
(
input_dev
,
ABS_MT_TOUCH_MAJOR
,
finger
[
id
].
status
!=
QT602240_RELEASE
?
finger
[
id
].
area
:
0
);
input_report_abs
(
input_dev
,
ABS_MT_POSITION_X
,
finger
[
id
].
x
);
input_report_abs
(
input_dev
,
ABS_MT_POSITION_Y
,
finger
[
id
].
y
);
input_mt_sync
(
input_dev
);
if
(
finger
[
id
].
status
==
QT602240_RELEASE
)
finger
[
id
].
status
=
0
;
else
finger_num
++
;
}
input_report_key
(
input_dev
,
BTN_TOUCH
,
finger_num
>
0
);
if
(
status
!=
QT602240_RELEASE
)
{
input_report_abs
(
input_dev
,
ABS_X
,
finger
[
single_id
].
x
);
input_report_abs
(
input_dev
,
ABS_Y
,
finger
[
single_id
].
y
);
}
input_sync
(
input_dev
);
}
static
void
qt602240_input_touchevent
(
struct
qt602240_data
*
data
,
struct
qt602240_message
*
message
,
int
id
)
{
struct
qt602240_finger
*
finger
=
data
->
finger
;
struct
device
*
dev
=
&
data
->
client
->
dev
;
u8
status
=
message
->
message
[
0
];
int
x
;
int
y
;
int
area
;
/* Check the touch is present on the screen */
if
(
!
(
status
&
QT602240_DETECT
))
{
if
(
status
&
QT602240_RELEASE
)
{
dev_dbg
(
dev
,
"[%d] released
\n
"
,
id
);
finger
[
id
].
status
=
QT602240_RELEASE
;
qt602240_input_report
(
data
,
id
);
}
return
;
}
/* Check only AMP detection */
if
(
!
(
status
&
(
QT602240_PRESS
|
QT602240_MOVE
)))
return
;
x
=
(
message
->
message
[
1
]
<<
2
)
|
((
message
->
message
[
3
]
&
~
0x3f
)
>>
6
);
y
=
(
message
->
message
[
2
]
<<
2
)
|
((
message
->
message
[
3
]
&
~
0xf3
)
>>
2
);
area
=
message
->
message
[
4
];
dev_dbg
(
dev
,
"[%d] %s x: %d, y: %d, area: %d
\n
"
,
id
,
status
&
QT602240_MOVE
?
"moved"
:
"pressed"
,
x
,
y
,
area
);
finger
[
id
].
status
=
status
&
QT602240_MOVE
?
QT602240_MOVE
:
QT602240_PRESS
;
finger
[
id
].
x
=
x
;
finger
[
id
].
y
=
y
;
finger
[
id
].
area
=
area
;
qt602240_input_report
(
data
,
id
);
}
static
irqreturn_t
qt602240_interrupt
(
int
irq
,
void
*
dev_id
)
{
struct
qt602240_data
*
data
=
dev_id
;
struct
qt602240_message
message
;
struct
qt602240_object
*
object
;
struct
device
*
dev
=
&
data
->
client
->
dev
;
int
id
;
u8
reportid
;
u8
max_reportid
;
u8
min_reportid
;
do
{
if
(
qt602240_read_message
(
data
,
&
message
))
{
dev_err
(
dev
,
"Failed to read message
\n
"
);
goto
end
;
}
reportid
=
message
.
reportid
;
/* whether reportid is thing of QT602240_TOUCH_MULTI */
object
=
qt602240_get_object
(
data
,
QT602240_TOUCH_MULTI
);
if
(
!
object
)
goto
end
;
max_reportid
=
object
->
max_reportid
;
min_reportid
=
max_reportid
-
object
->
num_report_ids
+
1
;
id
=
reportid
-
min_reportid
;
if
(
reportid
>=
min_reportid
&&
reportid
<=
max_reportid
)
qt602240_input_touchevent
(
data
,
&
message
,
id
);
else
qt602240_dump_message
(
dev
,
&
message
);
}
while
(
reportid
!=
0xff
);
end:
return
IRQ_HANDLED
;
}
static
int
qt602240_check_reg_init
(
struct
qt602240_data
*
data
)
{
struct
qt602240_object
*
object
;
struct
device
*
dev
=
&
data
->
client
->
dev
;
int
index
=
0
;
int
i
,
j
;
u8
version
=
data
->
info
.
version
;
u8
*
init_vals
;
switch
(
version
)
{
case
QT602240_VER_20
:
init_vals
=
(
u8
*
)
init_vals_ver_20
;
break
;
case
QT602240_VER_21
:
init_vals
=
(
u8
*
)
init_vals_ver_21
;
break
;
case
QT602240_VER_22
:
init_vals
=
(
u8
*
)
init_vals_ver_22
;
break
;
default:
dev_err
(
dev
,
"Firmware version %d doesn't support
\n
"
,
version
);
return
-
EINVAL
;
}
for
(
i
=
0
;
i
<
data
->
info
.
object_num
;
i
++
)
{
object
=
data
->
object_table
+
i
;
if
(
!
qt602240_object_writable
(
object
->
type
))
continue
;
for
(
j
=
0
;
j
<
object
->
size
+
1
;
j
++
)
qt602240_write_object
(
data
,
object
->
type
,
j
,
init_vals
[
index
+
j
]);
index
+=
object
->
size
+
1
;
}
return
0
;
}
static
int
qt602240_check_matrix_size
(
struct
qt602240_data
*
data
)
{
const
struct
qt602240_platform_data
*
pdata
=
data
->
pdata
;
struct
device
*
dev
=
&
data
->
client
->
dev
;
int
mode
=
-
1
;
int
error
;
u8
val
;
dev_dbg
(
dev
,
"Number of X lines: %d
\n
"
,
pdata
->
x_line
);
dev_dbg
(
dev
,
"Number of Y lines: %d
\n
"
,
pdata
->
y_line
);
switch
(
pdata
->
x_line
)
{
case
0
...
15
:
if
(
pdata
->
y_line
<=
14
)
mode
=
0
;
break
;
case
16
:
if
(
pdata
->
y_line
<=
12
)
mode
=
1
;
if
(
pdata
->
y_line
==
13
||
pdata
->
y_line
==
14
)
mode
=
0
;
break
;
case
17
:
if
(
pdata
->
y_line
<=
11
)
mode
=
2
;
if
(
pdata
->
y_line
==
12
||
pdata
->
y_line
==
13
)
mode
=
1
;
break
;
case
18
:
if
(
pdata
->
y_line
<=
10
)
mode
=
3
;
if
(
pdata
->
y_line
==
11
||
pdata
->
y_line
==
12
)
mode
=
2
;
break
;
case
19
:
if
(
pdata
->
y_line
<=
9
)
mode
=
4
;
if
(
pdata
->
y_line
==
10
||
pdata
->
y_line
==
11
)
mode
=
3
;
break
;
case
20
:
mode
=
4
;
}
if
(
mode
<
0
)
{
dev_err
(
dev
,
"Invalid X/Y lines
\n
"
);
return
-
EINVAL
;
}
error
=
qt602240_read_object
(
data
,
QT602240_SPT_CTECONFIG
,
QT602240_CTE_MODE
,
&
val
);
if
(
error
)
return
error
;
if
(
mode
==
val
)
return
0
;
/* Change the CTE configuration */
qt602240_write_object
(
data
,
QT602240_SPT_CTECONFIG
,
QT602240_CTE_CTRL
,
1
);
qt602240_write_object
(
data
,
QT602240_SPT_CTECONFIG
,
QT602240_CTE_MODE
,
mode
);
qt602240_write_object
(
data
,
QT602240_SPT_CTECONFIG
,
QT602240_CTE_CTRL
,
0
);
return
0
;
}
static
int
qt602240_make_highchg
(
struct
qt602240_data
*
data
)
{
struct
device
*
dev
=
&
data
->
client
->
dev
;
int
count
=
10
;
int
error
;
u8
val
;
/* Read dummy message to make high CHG pin */
do
{
error
=
qt602240_read_object
(
data
,
QT602240_GEN_MESSAGE
,
0
,
&
val
);
if
(
error
)
return
error
;
}
while
((
val
!=
0xff
)
&&
--
count
);
if
(
!
count
)
{
dev_err
(
dev
,
"CHG pin isn't cleared
\n
"
);
return
-
EBUSY
;
}
return
0
;
}
static
void
qt602240_handle_pdata
(
struct
qt602240_data
*
data
)
{
const
struct
qt602240_platform_data
*
pdata
=
data
->
pdata
;
u8
voltage
;
/* Set touchscreen lines */
qt602240_write_object
(
data
,
QT602240_TOUCH_MULTI
,
QT602240_TOUCH_XSIZE
,
pdata
->
x_line
);
qt602240_write_object
(
data
,
QT602240_TOUCH_MULTI
,
QT602240_TOUCH_YSIZE
,
pdata
->
y_line
);
/* Set touchscreen orient */
qt602240_write_object
(
data
,
QT602240_TOUCH_MULTI
,
QT602240_TOUCH_ORIENT
,
pdata
->
orient
);
/* Set touchscreen burst length */
qt602240_write_object
(
data
,
QT602240_TOUCH_MULTI
,
QT602240_TOUCH_BLEN
,
pdata
->
blen
);
/* Set touchscreen threshold */
qt602240_write_object
(
data
,
QT602240_TOUCH_MULTI
,
QT602240_TOUCH_TCHTHR
,
pdata
->
threshold
);
/* Set touchscreen resolution */
qt602240_write_object
(
data
,
QT602240_TOUCH_MULTI
,
QT602240_TOUCH_XRANGE_LSB
,
(
pdata
->
x_size
-
1
)
&
0xff
);
qt602240_write_object
(
data
,
QT602240_TOUCH_MULTI
,
QT602240_TOUCH_XRANGE_MSB
,
(
pdata
->
x_size
-
1
)
>>
8
);
qt602240_write_object
(
data
,
QT602240_TOUCH_MULTI
,
QT602240_TOUCH_YRANGE_LSB
,
(
pdata
->
y_size
-
1
)
&
0xff
);
qt602240_write_object
(
data
,
QT602240_TOUCH_MULTI
,
QT602240_TOUCH_YRANGE_MSB
,
(
pdata
->
y_size
-
1
)
>>
8
);
/* Set touchscreen voltage */
if
(
data
->
info
.
version
>=
QT602240_VER_21
&&
pdata
->
voltage
)
{
if
(
pdata
->
voltage
<
QT602240_VOLTAGE_DEFAULT
)
{
voltage
=
(
QT602240_VOLTAGE_DEFAULT
-
pdata
->
voltage
)
/
QT602240_VOLTAGE_STEP
;
voltage
=
0xff
-
voltage
+
1
;
}
else
voltage
=
(
pdata
->
voltage
-
QT602240_VOLTAGE_DEFAULT
)
/
QT602240_VOLTAGE_STEP
;
qt602240_write_object
(
data
,
QT602240_SPT_CTECONFIG
,
QT602240_CTE_VOLTAGE
,
voltage
);
}
}
static
int
qt602240_get_info
(
struct
qt602240_data
*
data
)
{
struct
i2c_client
*
client
=
data
->
client
;
struct
qt602240_info
*
info
=
&
data
->
info
;
int
error
;
u8
val
;
error
=
qt602240_read_reg
(
client
,
QT602240_FAMILY_ID
,
&
val
);
if
(
error
)
return
error
;
info
->
family_id
=
val
;
error
=
qt602240_read_reg
(
client
,
QT602240_VARIANT_ID
,
&
val
);
if
(
error
)
return
error
;
info
->
variant_id
=
val
;
error
=
qt602240_read_reg
(
client
,
QT602240_VERSION
,
&
val
);
if
(
error
)
return
error
;
info
->
version
=
val
;
error
=
qt602240_read_reg
(
client
,
QT602240_BUILD
,
&
val
);
if
(
error
)
return
error
;
info
->
build
=
val
;
error
=
qt602240_read_reg
(
client
,
QT602240_OBJECT_NUM
,
&
val
);
if
(
error
)
return
error
;
info
->
object_num
=
val
;
return
0
;
}
static
int
qt602240_get_object_table
(
struct
qt602240_data
*
data
)
{
int
error
;
int
i
;
u16
reg
;
u8
reportid
=
0
;
u8
buf
[
QT602240_OBJECT_SIZE
];
for
(
i
=
0
;
i
<
data
->
info
.
object_num
;
i
++
)
{
struct
qt602240_object
*
object
=
data
->
object_table
+
i
;
reg
=
QT602240_OBJECT_START
+
QT602240_OBJECT_SIZE
*
i
;
error
=
qt602240_read_object_table
(
data
->
client
,
reg
,
buf
);
if
(
error
)
return
error
;
object
->
type
=
buf
[
0
];
object
->
start_address
=
(
buf
[
2
]
<<
8
)
|
buf
[
1
];
object
->
size
=
buf
[
3
];
object
->
instances
=
buf
[
4
];
object
->
num_report_ids
=
buf
[
5
];
if
(
object
->
num_report_ids
)
{
reportid
+=
object
->
num_report_ids
*
(
object
->
instances
+
1
);
object
->
max_reportid
=
reportid
;
}
}
return
0
;
}
static
int
qt602240_initialize
(
struct
qt602240_data
*
data
)
{
struct
i2c_client
*
client
=
data
->
client
;
struct
qt602240_info
*
info
=
&
data
->
info
;
int
error
;
u8
val
;
error
=
qt602240_get_info
(
data
);
if
(
error
)
return
error
;
data
->
object_table
=
kcalloc
(
info
->
object_num
,
sizeof
(
struct
qt602240_data
),
GFP_KERNEL
);
if
(
!
data
->
object_table
)
{
dev_err
(
&
client
->
dev
,
"Failed to allocate memory
\n
"
);
return
-
ENOMEM
;
}
/* Get object table information */
error
=
qt602240_get_object_table
(
data
);
if
(
error
)
return
error
;
/* Check register init values */
error
=
qt602240_check_reg_init
(
data
);
if
(
error
)
return
error
;
/* Check X/Y matrix size */
error
=
qt602240_check_matrix_size
(
data
);
if
(
error
)
return
error
;
error
=
qt602240_make_highchg
(
data
);
if
(
error
)
return
error
;
qt602240_handle_pdata
(
data
);
/* Backup to memory */
qt602240_write_object
(
data
,
QT602240_GEN_COMMAND
,
QT602240_COMMAND_BACKUPNV
,
QT602240_BACKUP_VALUE
);
msleep
(
QT602240_BACKUP_TIME
);
/* Soft reset */
qt602240_write_object
(
data
,
QT602240_GEN_COMMAND
,
QT602240_COMMAND_RESET
,
1
);
msleep
(
QT602240_RESET_TIME
);
/* Update matrix size at info struct */
error
=
qt602240_read_reg
(
client
,
QT602240_MATRIX_X_SIZE
,
&
val
);
if
(
error
)
return
error
;
info
->
matrix_xsize
=
val
;
error
=
qt602240_read_reg
(
client
,
QT602240_MATRIX_Y_SIZE
,
&
val
);
if
(
error
)
return
error
;
info
->
matrix_ysize
=
val
;
dev_info
(
&
client
->
dev
,
"Family ID: %d Variant ID: %d Version: %d Build: %d
\n
"
,
info
->
family_id
,
info
->
variant_id
,
info
->
version
,
info
->
build
);
dev_info
(
&
client
->
dev
,
"Matrix X Size: %d Matrix Y Size: %d Object Num: %d
\n
"
,
info
->
matrix_xsize
,
info
->
matrix_ysize
,
info
->
object_num
);
return
0
;
}
static
ssize_t
qt602240_object_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
qt602240_data
*
data
=
dev_get_drvdata
(
dev
);
struct
qt602240_object
*
object
;
int
count
=
0
;
int
i
,
j
;
int
error
;
u8
val
;
for
(
i
=
0
;
i
<
data
->
info
.
object_num
;
i
++
)
{
object
=
data
->
object_table
+
i
;
count
+=
sprintf
(
buf
+
count
,
"Object Table Element %d(Type %d)
\n
"
,
i
+
1
,
object
->
type
);
if
(
!
qt602240_object_readable
(
object
->
type
))
{
count
+=
sprintf
(
buf
+
count
,
"
\n
"
);
continue
;
}
for
(
j
=
0
;
j
<
object
->
size
+
1
;
j
++
)
{
error
=
qt602240_read_object
(
data
,
object
->
type
,
j
,
&
val
);
if
(
error
)
return
error
;
count
+=
sprintf
(
buf
+
count
,
" Byte %d: 0x%x (%d)
\n
"
,
j
,
val
,
val
);
}
count
+=
sprintf
(
buf
+
count
,
"
\n
"
);
}
return
count
;
}
static
int
qt602240_load_fw
(
struct
device
*
dev
,
const
char
*
fn
)
{
struct
qt602240_data
*
data
=
dev_get_drvdata
(
dev
);
struct
i2c_client
*
client
=
data
->
client
;
const
struct
firmware
*
fw
=
NULL
;
unsigned
int
frame_size
;
unsigned
int
pos
=
0
;
int
ret
;
ret
=
request_firmware
(
&
fw
,
fn
,
dev
);
if
(
ret
)
{
dev_err
(
dev
,
"Unable to open firmware %s
\n
"
,
fn
);
return
ret
;
}
/* Change to the bootloader mode */
qt602240_write_object
(
data
,
QT602240_GEN_COMMAND
,
QT602240_COMMAND_RESET
,
QT602240_BOOT_VALUE
);
msleep
(
QT602240_RESET_TIME
);
/* Change to slave address of bootloader */
if
(
client
->
addr
==
QT602240_APP_LOW
)
client
->
addr
=
QT602240_BOOT_LOW
;
else
client
->
addr
=
QT602240_BOOT_HIGH
;
ret
=
qt602240_check_bootloader
(
client
,
QT602240_WAITING_BOOTLOAD_CMD
);
if
(
ret
)
goto
out
;
/* Unlock bootloader */
qt602240_unlock_bootloader
(
client
);
while
(
pos
<
fw
->
size
)
{
ret
=
qt602240_check_bootloader
(
client
,
QT602240_WAITING_FRAME_DATA
);
if
(
ret
)
goto
out
;
frame_size
=
((
*
(
fw
->
data
+
pos
)
<<
8
)
|
*
(
fw
->
data
+
pos
+
1
));
/* We should add 2 at frame size as the the firmware data is not
* included the CRC bytes.
*/
frame_size
+=
2
;
/* Write one frame to device */
qt602240_fw_write
(
client
,
fw
->
data
+
pos
,
frame_size
);
ret
=
qt602240_check_bootloader
(
client
,
QT602240_FRAME_CRC_PASS
);
if
(
ret
)
goto
out
;
pos
+=
frame_size
;
dev_dbg
(
dev
,
"Updated %d bytes / %zd bytes
\n
"
,
pos
,
fw
->
size
);
}
out:
release_firmware
(
fw
);
/* Change to slave address of application */
if
(
client
->
addr
==
QT602240_BOOT_LOW
)
client
->
addr
=
QT602240_APP_LOW
;
else
client
->
addr
=
QT602240_APP_HIGH
;
return
ret
;
}
static
ssize_t
qt602240_update_fw_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
struct
qt602240_data
*
data
=
dev_get_drvdata
(
dev
);
unsigned
int
version
;
int
error
;
if
(
sscanf
(
buf
,
"%u"
,
&
version
)
!=
1
)
{
dev_err
(
dev
,
"Invalid values
\n
"
);
return
-
EINVAL
;
}
if
(
data
->
info
.
version
<
QT602240_VER_21
||
version
<
QT602240_VER_21
)
{
dev_err
(
dev
,
"FW update supported starting with version 21
\n
"
);
return
-
EINVAL
;
}
disable_irq
(
data
->
irq
);
error
=
qt602240_load_fw
(
dev
,
QT602240_FW_NAME
);
if
(
error
)
{
dev_err
(
dev
,
"The firmware update failed(%d)
\n
"
,
error
);
count
=
error
;
}
else
{
dev_dbg
(
dev
,
"The firmware update succeeded
\n
"
);
/* Wait for reset */
msleep
(
QT602240_FWRESET_TIME
);
kfree
(
data
->
object_table
);
data
->
object_table
=
NULL
;
qt602240_initialize
(
data
);
}
enable_irq
(
data
->
irq
);
return
count
;
}
static
DEVICE_ATTR
(
object
,
0444
,
qt602240_object_show
,
NULL
);
static
DEVICE_ATTR
(
update_fw
,
0664
,
NULL
,
qt602240_update_fw_store
);
static
struct
attribute
*
qt602240_attrs
[]
=
{
&
dev_attr_object
.
attr
,
&
dev_attr_update_fw
.
attr
,
NULL
};
static
const
struct
attribute_group
qt602240_attr_group
=
{
.
attrs
=
qt602240_attrs
,
};
static
void
qt602240_start
(
struct
qt602240_data
*
data
)
{
/* Touch enable */
qt602240_write_object
(
data
,
QT602240_TOUCH_MULTI
,
QT602240_TOUCH_CTRL
,
0x83
);
}
static
void
qt602240_stop
(
struct
qt602240_data
*
data
)
{
/* Touch disable */
qt602240_write_object
(
data
,
QT602240_TOUCH_MULTI
,
QT602240_TOUCH_CTRL
,
0
);
}
static
int
qt602240_input_open
(
struct
input_dev
*
dev
)
{
struct
qt602240_data
*
data
=
input_get_drvdata
(
dev
);
qt602240_start
(
data
);
return
0
;
}
static
void
qt602240_input_close
(
struct
input_dev
*
dev
)
{
struct
qt602240_data
*
data
=
input_get_drvdata
(
dev
);
qt602240_stop
(
data
);
}
static
int
__devinit
qt602240_probe
(
struct
i2c_client
*
client
,
const
struct
i2c_device_id
*
id
)
{
struct
qt602240_data
*
data
;
struct
input_dev
*
input_dev
;
int
error
;
if
(
!
client
->
dev
.
platform_data
)
return
-
EINVAL
;
data
=
kzalloc
(
sizeof
(
struct
qt602240_data
),
GFP_KERNEL
);
input_dev
=
input_allocate_device
();
if
(
!
data
||
!
input_dev
)
{
dev_err
(
&
client
->
dev
,
"Failed to allocate memory
\n
"
);
error
=
-
ENOMEM
;
goto
err_free_mem
;
}
input_dev
->
name
=
"AT42QT602240/ATMXT224 Touchscreen"
;
input_dev
->
id
.
bustype
=
BUS_I2C
;
input_dev
->
dev
.
parent
=
&
client
->
dev
;
input_dev
->
open
=
qt602240_input_open
;
input_dev
->
close
=
qt602240_input_close
;
__set_bit
(
EV_ABS
,
input_dev
->
evbit
);
__set_bit
(
EV_KEY
,
input_dev
->
evbit
);
__set_bit
(
BTN_TOUCH
,
input_dev
->
keybit
);
/* For single touch */
input_set_abs_params
(
input_dev
,
ABS_X
,
0
,
QT602240_MAX_XC
,
0
,
0
);
input_set_abs_params
(
input_dev
,
ABS_Y
,
0
,
QT602240_MAX_YC
,
0
,
0
);
/* For multi touch */
input_set_abs_params
(
input_dev
,
ABS_MT_TOUCH_MAJOR
,
0
,
QT602240_MAX_AREA
,
0
,
0
);
input_set_abs_params
(
input_dev
,
ABS_MT_POSITION_X
,
0
,
QT602240_MAX_XC
,
0
,
0
);
input_set_abs_params
(
input_dev
,
ABS_MT_POSITION_Y
,
0
,
QT602240_MAX_YC
,
0
,
0
);
input_set_drvdata
(
input_dev
,
data
);
data
->
client
=
client
;
data
->
input_dev
=
input_dev
;
data
->
pdata
=
client
->
dev
.
platform_data
;
data
->
irq
=
client
->
irq
;
i2c_set_clientdata
(
client
,
data
);
error
=
qt602240_initialize
(
data
);
if
(
error
)
goto
err_free_object
;
error
=
request_threaded_irq
(
client
->
irq
,
NULL
,
qt602240_interrupt
,
IRQF_TRIGGER_FALLING
,
client
->
dev
.
driver
->
name
,
data
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"Failed to register interrupt
\n
"
);
goto
err_free_object
;
}
error
=
input_register_device
(
input_dev
);
if
(
error
)
goto
err_free_irq
;
error
=
sysfs_create_group
(
&
client
->
dev
.
kobj
,
&
qt602240_attr_group
);
if
(
error
)
goto
err_unregister_device
;
return
0
;
err_unregister_device:
input_unregister_device
(
input_dev
);
input_dev
=
NULL
;
err_free_irq:
free_irq
(
client
->
irq
,
data
);
err_free_object:
kfree
(
data
->
object_table
);
err_free_mem:
input_free_device
(
input_dev
);
kfree
(
data
);
return
error
;
}
static
int
__devexit
qt602240_remove
(
struct
i2c_client
*
client
)
{
struct
qt602240_data
*
data
=
i2c_get_clientdata
(
client
);
sysfs_remove_group
(
&
client
->
dev
.
kobj
,
&
qt602240_attr_group
);
free_irq
(
data
->
irq
,
data
);
input_unregister_device
(
data
->
input_dev
);
kfree
(
data
->
object_table
);
kfree
(
data
);
return
0
;
}
#ifdef CONFIG_PM
static
int
qt602240_suspend
(
struct
i2c_client
*
client
,
pm_message_t
mesg
)
{
struct
qt602240_data
*
data
=
i2c_get_clientdata
(
client
);
struct
input_dev
*
input_dev
=
data
->
input_dev
;
mutex_lock
(
&
input_dev
->
mutex
);
if
(
input_dev
->
users
)
qt602240_stop
(
data
);
mutex_unlock
(
&
input_dev
->
mutex
);
return
0
;
}
static
int
qt602240_resume
(
struct
i2c_client
*
client
)
{
struct
qt602240_data
*
data
=
i2c_get_clientdata
(
client
);
struct
input_dev
*
input_dev
=
data
->
input_dev
;
/* Soft reset */
qt602240_write_object
(
data
,
QT602240_GEN_COMMAND
,
QT602240_COMMAND_RESET
,
1
);
msleep
(
QT602240_RESET_TIME
);
mutex_lock
(
&
input_dev
->
mutex
);
if
(
input_dev
->
users
)
qt602240_start
(
data
);
mutex_unlock
(
&
input_dev
->
mutex
);
return
0
;
}
#else
#define qt602240_suspend NULL
#define qt602240_resume NULL
#endif
static
const
struct
i2c_device_id
qt602240_id
[]
=
{
{
"qt602240_ts"
,
0
},
{
}
};
MODULE_DEVICE_TABLE
(
i2c
,
qt602240_id
);
static
struct
i2c_driver
qt602240_driver
=
{
.
driver
=
{
.
name
=
"qt602240_ts"
,
.
owner
=
THIS_MODULE
,
},
.
probe
=
qt602240_probe
,
.
remove
=
__devexit_p
(
qt602240_remove
),
.
suspend
=
qt602240_suspend
,
.
resume
=
qt602240_resume
,
.
id_table
=
qt602240_id
,
};
static
int
__init
qt602240_init
(
void
)
{
return
i2c_add_driver
(
&
qt602240_driver
);
}
static
void
__exit
qt602240_exit
(
void
)
{
i2c_del_driver
(
&
qt602240_driver
);
}
module_init
(
qt602240_init
);
module_exit
(
qt602240_exit
);
/* Module information */
MODULE_AUTHOR
(
"Joonyoung Shim <jy0922.shim@samsung.com>"
);
MODULE_DESCRIPTION
(
"AT42QT602240/ATMXT224 Touchscreen driver"
);
MODULE_LICENSE
(
"GPL"
);
drivers/input/touchscreen/tps6507x-ts.c
View file @
929343ef
...
...
@@ -355,9 +355,6 @@ static int __devexit tps6507x_ts_remove(struct platform_device *pdev)
struct
tps6507x_ts
*
tsc
=
tps6507x_dev
->
ts
;
struct
input_dev
*
input_dev
=
tsc
->
input_dev
;
if
(
!
tsc
)
return
0
;
cancel_delayed_work_sync
(
&
tsc
->
work
);
destroy_workqueue
(
tsc
->
wq
);
...
...
drivers/input/touchscreen/usbtouchscreen.c
View file @
929343ef
...
...
@@ -95,6 +95,7 @@ struct usbtouch_device_info {
int
(
*
get_pkt_len
)
(
unsigned
char
*
pkt
,
int
len
);
int
(
*
read_data
)
(
struct
usbtouch_usb
*
usbtouch
,
unsigned
char
*
pkt
);
int
(
*
alloc
)
(
struct
usbtouch_usb
*
usbtouch
);
int
(
*
init
)
(
struct
usbtouch_usb
*
usbtouch
);
void
(
*
exit
)
(
struct
usbtouch_usb
*
usbtouch
);
};
...
...
@@ -135,7 +136,7 @@ enum {
DEVTYPE_JASTEC
,
DEVTYPE_E2I
,
DEVTYPE_ZYTRONIC
,
DEVTYPE_TC
5UH
,
DEVTYPE_TC
45USB
,
DEVTYPE_NEXIO
,
};
...
...
@@ -222,8 +223,11 @@ static const struct usb_device_id usbtouch_devices[] = {
{
USB_DEVICE
(
0x14c8
,
0x0003
),
.
driver_info
=
DEVTYPE_ZYTRONIC
},
#endif
#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC5UH
{
USB_DEVICE
(
0x0664
,
0x0309
),
.
driver_info
=
DEVTYPE_TC5UH
},
#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB
/* TC5UH */
{
USB_DEVICE
(
0x0664
,
0x0309
),
.
driver_info
=
DEVTYPE_TC45USB
},
/* TC4UM */
{
USB_DEVICE
(
0x0664
,
0x0306
),
.
driver_info
=
DEVTYPE_TC45USB
},
#endif
#ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
...
...
@@ -507,7 +511,7 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
int
ret
=
-
ENOMEM
;
unsigned
char
*
buf
;
buf
=
kmalloc
(
2
,
GFP_
KERNEL
);
buf
=
kmalloc
(
2
,
GFP_
NOIO
);
if
(
!
buf
)
goto
err_nobuf
;
/* reset */
...
...
@@ -574,10 +578,10 @@ static int irtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
#endif
/*****************************************************************************
* ET&T TC5UH part
* ET&T TC5UH
/TC4UM
part
*/
#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC
5UH
static
int
tc
5uh
_read_data
(
struct
usbtouch_usb
*
dev
,
unsigned
char
*
pkt
)
#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC
45USB
static
int
tc
45usb
_read_data
(
struct
usbtouch_usb
*
dev
,
unsigned
char
*
pkt
)
{
dev
->
x
=
((
pkt
[
2
]
&
0x0F
)
<<
8
)
|
pkt
[
1
];
dev
->
y
=
((
pkt
[
4
]
&
0x0F
)
<<
8
)
|
pkt
[
3
];
...
...
@@ -732,11 +736,43 @@ static void nexio_ack_complete(struct urb *urb)
{
}
static
int
nexio_alloc
(
struct
usbtouch_usb
*
usbtouch
)
{
struct
nexio_priv
*
priv
;
int
ret
=
-
ENOMEM
;
usbtouch
->
priv
=
kmalloc
(
sizeof
(
struct
nexio_priv
),
GFP_KERNEL
);
if
(
!
usbtouch
->
priv
)
goto
out_buf
;
priv
=
usbtouch
->
priv
;
priv
->
ack_buf
=
kmemdup
(
nexio_ack_pkt
,
sizeof
(
nexio_ack_pkt
),
GFP_KERNEL
);
if
(
!
priv
->
ack_buf
)
goto
err_priv
;
priv
->
ack
=
usb_alloc_urb
(
0
,
GFP_KERNEL
);
if
(
!
priv
->
ack
)
{
dbg
(
"%s - usb_alloc_urb failed: usbtouch->ack"
,
__func__
);
goto
err_ack_buf
;
}
return
0
;
err_ack_buf:
kfree
(
priv
->
ack_buf
);
err_priv:
kfree
(
priv
);
out_buf:
return
ret
;
}
static
int
nexio_init
(
struct
usbtouch_usb
*
usbtouch
)
{
struct
usb_device
*
dev
=
interface_to_usbdev
(
usbtouch
->
interface
);
struct
usb_host_interface
*
interface
=
usbtouch
->
interface
->
cur_altsetting
;
struct
nexio_priv
*
priv
;
struct
nexio_priv
*
priv
=
usbtouch
->
priv
;
int
ret
=
-
ENOMEM
;
int
actual_len
,
i
;
unsigned
char
*
buf
;
...
...
@@ -755,7 +791,7 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
if
(
!
input_ep
||
!
output_ep
)
return
-
ENXIO
;
buf
=
kmalloc
(
NEXIO_BUFSIZE
,
GFP_
KERNEL
);
buf
=
kmalloc
(
NEXIO_BUFSIZE
,
GFP_
NOIO
);
if
(
!
buf
)
goto
out_buf
;
...
...
@@ -787,11 +823,11 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
switch
(
buf
[
0
])
{
case
0x83
:
/* firmware version */
if
(
!
firmware_ver
)
firmware_ver
=
kstrdup
(
&
buf
[
2
],
GFP_
KERNEL
);
firmware_ver
=
kstrdup
(
&
buf
[
2
],
GFP_
NOIO
);
break
;
case
0x84
:
/* device name */
if
(
!
device_name
)
device_name
=
kstrdup
(
&
buf
[
2
],
GFP_
KERNEL
);
device_name
=
kstrdup
(
&
buf
[
2
],
GFP_
NOIO
);
break
;
}
}
...
...
@@ -802,36 +838,11 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
kfree
(
firmware_ver
);
kfree
(
device_name
);
/* prepare ACK URB */
ret
=
-
ENOMEM
;
usbtouch
->
priv
=
kmalloc
(
sizeof
(
struct
nexio_priv
),
GFP_KERNEL
);
if
(
!
usbtouch
->
priv
)
goto
out_buf
;
priv
=
usbtouch
->
priv
;
priv
->
ack_buf
=
kmemdup
(
nexio_ack_pkt
,
sizeof
(
nexio_ack_pkt
),
GFP_KERNEL
);
if
(
!
priv
->
ack_buf
)
goto
err_priv
;
priv
->
ack
=
usb_alloc_urb
(
0
,
GFP_KERNEL
);
if
(
!
priv
->
ack
)
{
dbg
(
"%s - usb_alloc_urb failed: usbtouch->ack"
,
__func__
);
goto
err_ack_buf
;
}
usb_fill_bulk_urb
(
priv
->
ack
,
dev
,
usb_sndbulkpipe
(
dev
,
output_ep
),
priv
->
ack_buf
,
sizeof
(
nexio_ack_pkt
),
nexio_ack_complete
,
usbtouch
);
ret
=
0
;
goto
out_buf
;
err_ack_buf:
kfree
(
priv
->
ack_buf
);
err_priv:
kfree
(
priv
);
out_buf:
kfree
(
buf
);
return
ret
;
...
...
@@ -849,29 +860,32 @@ static void nexio_exit(struct usbtouch_usb *usbtouch)
static
int
nexio_read_data
(
struct
usbtouch_usb
*
usbtouch
,
unsigned
char
*
pkt
)
{
int
x
,
y
,
begin_x
,
begin_y
,
end_x
,
end_y
,
w
,
h
,
ret
;
struct
nexio_touch_packet
*
packet
=
(
void
*
)
pkt
;
struct
nexio_priv
*
priv
=
usbtouch
->
priv
;
unsigned
int
data_len
=
be16_to_cpu
(
packet
->
data_len
);
unsigned
int
x_len
=
be16_to_cpu
(
packet
->
x_len
);
unsigned
int
y_len
=
be16_to_cpu
(
packet
->
y_len
);
int
x
,
y
,
begin_x
,
begin_y
,
end_x
,
end_y
,
w
,
h
,
ret
;
/* got touch data? */
if
((
pkt
[
0
]
&
0xe0
)
!=
0xe0
)
return
0
;
if
(
be16_to_cpu
(
packet
->
data_len
)
>
0xff
)
packet
->
data_len
=
cpu_to_be16
(
be16_to_cpu
(
packet
->
data_len
)
-
0x100
)
;
if
(
be16_to_cpu
(
packet
->
x_len
)
>
0xff
)
packet
->
x_len
=
cpu_to_be16
(
be16_to_cpu
(
packet
->
x_len
)
-
0x80
)
;
if
(
data_len
>
0xff
)
data_len
-=
0x100
;
if
(
x_len
>
0xff
)
x_len
-=
0x80
;
/* send ACK */
ret
=
usb_submit_urb
(
priv
->
ack
,
GFP_ATOMIC
);
if
(
!
usbtouch
->
type
->
max_xc
)
{
usbtouch
->
type
->
max_xc
=
2
*
be16_to_cpu
(
packet
->
x_len
)
;
input_set_abs_params
(
usbtouch
->
input
,
ABS_X
,
0
,
2
*
be16_to_cpu
(
packet
->
x_len
)
,
0
,
0
);
usbtouch
->
type
->
max_yc
=
2
*
be16_to_cpu
(
packet
->
y_len
)
;
input_set_abs_params
(
usbtouch
->
input
,
ABS_Y
,
0
,
2
*
be16_to_cpu
(
packet
->
y_len
)
,
0
,
0
);
usbtouch
->
type
->
max_xc
=
2
*
x_len
;
input_set_abs_params
(
usbtouch
->
input
,
ABS_X
,
0
,
usbtouch
->
type
->
max_xc
,
0
,
0
);
usbtouch
->
type
->
max_yc
=
2
*
y_len
;
input_set_abs_params
(
usbtouch
->
input
,
ABS_Y
,
0
,
usbtouch
->
type
->
max_yc
,
0
,
0
);
}
/*
* The device reports state of IR sensors on X and Y axes.
...
...
@@ -881,22 +895,21 @@ static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
* it's disabled (and untested) here as there's no X driver for that.
*/
begin_x
=
end_x
=
begin_y
=
end_y
=
-
1
;
for
(
x
=
0
;
x
<
be16_to_cpu
(
packet
->
x_len
)
;
x
++
)
{
for
(
x
=
0
;
x
<
x_len
;
x
++
)
{
if
(
begin_x
==
-
1
&&
packet
->
data
[
x
]
>
NEXIO_THRESHOLD
)
{
begin_x
=
x
;
continue
;
}
if
(
end_x
==
-
1
&&
begin_x
!=
-
1
&&
packet
->
data
[
x
]
<
NEXIO_THRESHOLD
)
{
end_x
=
x
-
1
;
for
(
y
=
be16_to_cpu
(
packet
->
x_len
);
y
<
be16_to_cpu
(
packet
->
data_len
);
y
++
)
{
for
(
y
=
x_len
;
y
<
data_len
;
y
++
)
{
if
(
begin_y
==
-
1
&&
packet
->
data
[
y
]
>
NEXIO_THRESHOLD
)
{
begin_y
=
y
-
be16_to_cpu
(
packet
->
x_len
)
;
begin_y
=
y
-
x_len
;
continue
;
}
if
(
end_y
==
-
1
&&
begin_y
!=
-
1
&&
packet
->
data
[
y
]
<
NEXIO_THRESHOLD
)
{
end_y
=
y
-
1
-
be16_to_cpu
(
packet
->
x_len
)
;
end_y
=
y
-
1
-
x_len
;
w
=
end_x
-
begin_x
;
h
=
end_y
-
begin_y
;
#if 0
...
...
@@ -1104,14 +1117,14 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
},
#endif
#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC
5UH
[
DEVTYPE_TC
5UH
]
=
{
#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC
45USB
[
DEVTYPE_TC
45USB
]
=
{
.
min_xc
=
0x0
,
.
max_xc
=
0x0fff
,
.
min_yc
=
0x0
,
.
max_yc
=
0x0fff
,
.
rept_size
=
5
,
.
read_data
=
tc
5uh
_read_data
,
.
read_data
=
tc
45usb
_read_data
,
},
#endif
...
...
@@ -1120,6 +1133,7 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
.
rept_size
=
1024
,
.
irq_always
=
true
,
.
read_data
=
nexio_read_data
,
.
alloc
=
nexio_alloc
,
.
init
=
nexio_init
,
.
exit
=
nexio_exit
,
},
...
...
@@ -1263,6 +1277,7 @@ static void usbtouch_irq(struct urb *urb)
usbtouch
->
type
->
process_pkt
(
usbtouch
,
usbtouch
->
data
,
urb
->
actual_length
);
exit:
usb_mark_last_busy
(
interface_to_usbdev
(
usbtouch
->
interface
));
retval
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
if
(
retval
)
err
(
"%s - usb_submit_urb failed with result: %d"
,
...
...
@@ -1272,25 +1287,89 @@ static void usbtouch_irq(struct urb *urb)
static
int
usbtouch_open
(
struct
input_dev
*
input
)
{
struct
usbtouch_usb
*
usbtouch
=
input_get_drvdata
(
input
);
int
r
;
usbtouch
->
irq
->
dev
=
interface_to_usbdev
(
usbtouch
->
interface
);
r
=
usb_autopm_get_interface
(
usbtouch
->
interface
)
?
-
EIO
:
0
;
if
(
r
<
0
)
goto
out
;
if
(
!
usbtouch
->
type
->
irq_always
)
{
if
(
usb_submit_urb
(
usbtouch
->
irq
,
GFP_KERNEL
))
return
-
EIO
;
if
(
usb_submit_urb
(
usbtouch
->
irq
,
GFP_KERNEL
))
{
r
=
-
EIO
;
goto
out_put
;
}
}
return
0
;
usbtouch
->
interface
->
needs_remote_wakeup
=
1
;
out_put:
usb_autopm_put_interface
(
usbtouch
->
interface
);
out:
return
r
;
}
static
void
usbtouch_close
(
struct
input_dev
*
input
)
{
struct
usbtouch_usb
*
usbtouch
=
input_get_drvdata
(
input
);
int
r
;
if
(
!
usbtouch
->
type
->
irq_always
)
usb_kill_urb
(
usbtouch
->
irq
);
r
=
usb_autopm_get_interface
(
usbtouch
->
interface
);
usbtouch
->
interface
->
needs_remote_wakeup
=
0
;
if
(
!
r
)
usb_autopm_put_interface
(
usbtouch
->
interface
);
}
static
int
usbtouch_suspend
(
struct
usb_interface
*
intf
,
pm_message_t
message
)
{
struct
usbtouch_usb
*
usbtouch
=
usb_get_intfdata
(
intf
);
usb_kill_urb
(
usbtouch
->
irq
);
return
0
;
}
static
int
usbtouch_resume
(
struct
usb_interface
*
intf
)
{
struct
usbtouch_usb
*
usbtouch
=
usb_get_intfdata
(
intf
);
struct
input_dev
*
input
=
usbtouch
->
input
;
int
result
=
0
;
mutex_lock
(
&
input
->
mutex
);
if
(
input
->
users
||
usbtouch
->
type
->
irq_always
)
result
=
usb_submit_urb
(
usbtouch
->
irq
,
GFP_NOIO
);
mutex_unlock
(
&
input
->
mutex
);
return
result
;
}
static
int
usbtouch_reset_resume
(
struct
usb_interface
*
intf
)
{
struct
usbtouch_usb
*
usbtouch
=
usb_get_intfdata
(
intf
);
struct
input_dev
*
input
=
usbtouch
->
input
;
int
err
=
0
;
/* reinit the device */
if
(
usbtouch
->
type
->
init
)
{
err
=
usbtouch
->
type
->
init
(
usbtouch
);
if
(
err
)
{
dbg
(
"%s - type->init() failed, err: %d"
,
__func__
,
err
);
return
err
;
}
}
/* restart IO if needed */
mutex_lock
(
&
input
->
mutex
);
if
(
input
->
users
)
err
=
usb_submit_urb
(
usbtouch
->
irq
,
GFP_NOIO
);
mutex_unlock
(
&
input
->
mutex
);
return
err
;
}
static
void
usbtouch_free_buffers
(
struct
usb_device
*
udev
,
struct
usbtouch_usb
*
usbtouch
)
...
...
@@ -1411,12 +1490,21 @@ static int usbtouch_probe(struct usb_interface *intf,
usbtouch
->
irq
->
transfer_dma
=
usbtouch
->
data_dma
;
usbtouch
->
irq
->
transfer_flags
|=
URB_NO_TRANSFER_DMA_MAP
;
/* device specific init */
/* device specific allocations */
if
(
type
->
alloc
)
{
err
=
type
->
alloc
(
usbtouch
);
if
(
err
)
{
dbg
(
"%s - type->alloc() failed, err: %d"
,
__func__
,
err
);
goto
out_free_urb
;
}
}
/* device specific initialisation*/
if
(
type
->
init
)
{
err
=
type
->
init
(
usbtouch
);
if
(
err
)
{
dbg
(
"%s - type->init() failed, err: %d"
,
__func__
,
err
);
goto
out_
free_urb
;
goto
out_
do_exit
;
}
}
...
...
@@ -1429,8 +1517,11 @@ static int usbtouch_probe(struct usb_interface *intf,
usb_set_intfdata
(
intf
,
usbtouch
);
if
(
usbtouch
->
type
->
irq_always
)
{
/* this can't fail */
usb_autopm_get_interface
(
intf
);
err
=
usb_submit_urb
(
usbtouch
->
irq
,
GFP_KERNEL
);
if
(
err
)
{
usb_autopm_put_interface
(
intf
);
err
(
"%s - usb_submit_urb failed with result: %d"
,
__func__
,
err
);
goto
out_unregister_input
;
...
...
@@ -1481,7 +1572,11 @@ static struct usb_driver usbtouch_driver = {
.
name
=
"usbtouchscreen"
,
.
probe
=
usbtouch_probe
,
.
disconnect
=
usbtouch_disconnect
,
.
suspend
=
usbtouch_suspend
,
.
resume
=
usbtouch_resume
,
.
reset_resume
=
usbtouch_reset_resume
,
.
id_table
=
usbtouch_devices
,
.
supports_autosuspend
=
1
,
};
static
int
__init
usbtouch_init
(
void
)
...
...
include/linux/i2c/adp5588.h
View file @
929343ef
...
...
@@ -78,6 +78,40 @@
#define ADP5588_KEYMAPSIZE 80
#define GPI_PIN_ROW0 97
#define GPI_PIN_ROW1 98
#define GPI_PIN_ROW2 99
#define GPI_PIN_ROW3 100
#define GPI_PIN_ROW4 101
#define GPI_PIN_ROW5 102
#define GPI_PIN_ROW6 103
#define GPI_PIN_ROW7 104
#define GPI_PIN_COL0 105
#define GPI_PIN_COL1 106
#define GPI_PIN_COL2 107
#define GPI_PIN_COL3 108
#define GPI_PIN_COL4 109
#define GPI_PIN_COL5 110
#define GPI_PIN_COL6 111
#define GPI_PIN_COL7 112
#define GPI_PIN_COL8 113
#define GPI_PIN_COL9 114
#define GPI_PIN_ROW_BASE GPI_PIN_ROW0
#define GPI_PIN_ROW_END GPI_PIN_ROW7
#define GPI_PIN_COL_BASE GPI_PIN_COL0
#define GPI_PIN_COL_END GPI_PIN_COL9
#define GPI_PIN_BASE GPI_PIN_ROW_BASE
#define GPI_PIN_END GPI_PIN_COL_END
#define ADP5588_GPIMAPSIZE_MAX (GPI_PIN_END - GPI_PIN_BASE + 1)
struct
adp5588_gpi_map
{
unsigned
short
pin
;
unsigned
short
sw_evt
;
};
struct
adp5588_kpad_platform_data
{
int
rows
;
/* Number of rows */
int
cols
;
/* Number of columns */
...
...
@@ -87,6 +121,9 @@ struct adp5588_kpad_platform_data {
unsigned
en_keylock
:
1
;
/* Enable Key Lock feature */
unsigned
short
unlock_key1
;
/* Unlock Key 1 */
unsigned
short
unlock_key2
;
/* Unlock Key 2 */
const
struct
adp5588_gpi_map
*
gpimap
;
unsigned
short
gpimapsize
;
const
struct
adp5588_gpio_platform_data
*
gpio_data
;
};
struct
adp5588_gpio_platform_data
{
...
...
include/linux/i2c/mcs
5000_ts
.h
→
include/linux/i2c/mcs.h
View file @
929343ef
/*
* mcs5000_ts.h
*
* Copyright (C) 2009 Samsung Electronics Co.Ltd
* Copyright (C) 2009 - 2010 Samsung Electronics Co.Ltd
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
* Author: HeungJun Kim <riverful.kim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
...
...
@@ -11,14 +10,25 @@
*
*/
#ifndef __LINUX_MCS5000_TS_H
#define __LINUX_MCS5000_TS_H
#ifndef __LINUX_MCS_H
#define __LINUX_MCS_H
#define MCS_KEY_MAP(v, c) ((((v) & 0xff) << 16) | ((c) & 0xffff))
#define MCS_KEY_VAL(v) (((v) >> 16) & 0xff)
#define MCS_KEY_CODE(v) ((v) & 0xffff)
/* platform data for the MELFAS MCS-5000 touchscreen driver */
struct
mcs5000_ts_platform_data
{
struct
mcs_platform_data
{
void
(
*
cfg_pin
)(
void
);
int
x_size
;
int
y_size
;
/* touchscreen */
unsigned
int
x_size
;
unsigned
int
y_size
;
/* touchkey */
const
u32
*
keymap
;
unsigned
int
keymap_size
;
unsigned
int
key_maxval
;
bool
no_autorepeat
;
};
#endif
/* __LINUX_MCS
5000_TS
_H */
#endif
/* __LINUX_MCS_H */
include/linux/i2c/qt602240_ts.h
0 → 100644
View file @
929343ef
/*
* AT42QT602240/ATMXT224 Touchscreen driver
*
* Copyright (C) 2010 Samsung Electronics Co.Ltd
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef __LINUX_QT602240_TS_H
#define __LINUX_QT602240_TS_H
/* Orient */
#define QT602240_NORMAL 0x0
#define QT602240_DIAGONAL 0x1
#define QT602240_HORIZONTAL_FLIP 0x2
#define QT602240_ROTATED_90_COUNTER 0x3
#define QT602240_VERTICAL_FLIP 0x4
#define QT602240_ROTATED_90 0x5
#define QT602240_ROTATED_180 0x6
#define QT602240_DIAGONAL_COUNTER 0x7
/* The platform data for the AT42QT602240/ATMXT224 touchscreen driver */
struct
qt602240_platform_data
{
unsigned
int
x_line
;
unsigned
int
y_line
;
unsigned
int
x_size
;
unsigned
int
y_size
;
unsigned
int
blen
;
unsigned
int
threshold
;
unsigned
int
voltage
;
unsigned
char
orient
;
};
#endif
/* __LINUX_QT602240_TS_H */
include/linux/input.h
View file @
929343ef
...
...
@@ -691,9 +691,12 @@ struct input_absinfo {
#define ABS_TILT_X 0x1a
#define ABS_TILT_Y 0x1b
#define ABS_TOOL_WIDTH 0x1c
#define ABS_VOLUME 0x20
#define ABS_MISC 0x28
#define ABS_MT_SLOT 0x2f
/* MT slot being modified */
#define ABS_MT_TOUCH_MAJOR 0x30
/* Major axis of touching ellipse */
#define ABS_MT_TOUCH_MINOR 0x31
/* Minor axis (omit if circular) */
#define ABS_MT_WIDTH_MAJOR 0x32
/* Major axis of approaching ellipse */
...
...
@@ -706,6 +709,12 @@ struct input_absinfo {
#define ABS_MT_TRACKING_ID 0x39
/* Unique ID of initiated contact */
#define ABS_MT_PRESSURE 0x3a
/* Pressure on contact area */
#ifdef __KERNEL__
/* Implementation details, userspace should not care about these */
#define ABS_MT_FIRST ABS_MT_TOUCH_MAJOR
#define ABS_MT_LAST ABS_MT_PRESSURE
#endif
#define ABS_MAX 0x3f
#define ABS_CNT (ABS_MAX+1)
...
...
@@ -1047,6 +1056,14 @@ struct ff_effect {
#include <linux/timer.h>
#include <linux/mod_devicetable.h>
/**
* struct input_mt_slot - represents the state of an input MT slot
* @abs: holds current values of ABS_MT axes for this slot
*/
struct
input_mt_slot
{
int
abs
[
ABS_MT_LAST
-
ABS_MT_FIRST
+
1
];
};
/**
* struct input_dev - represents an input device
* @name: name of the device
...
...
@@ -1063,6 +1080,10 @@ struct ff_effect {
* @sndbit: bitmap of sound effects supported by the device
* @ffbit: bitmap of force feedback effects supported by the device
* @swbit: bitmap of switches present on the device
* @hint_events_per_packet: average number of events generated by the
* device in a packet (between EV_SYN/SYN_REPORT events). Used by
* event handlers to estimate size of the buffer needed to hold
* events.
* @keycodemax: size of keycode table
* @keycodesize: size of elements in keycode table
* @keycode: map of scancodes to keycodes for this device
...
...
@@ -1078,9 +1099,12 @@ struct ff_effect {
* @repeat_key: stores key code of the last key pressed; used to implement
* software autorepeat
* @timer: timer for software autorepeat
* @sync: set to 1 when there were no new events since last EV_SYNC
* @abs: current values for reports from absolute axes
* @rep: current values for autorepeat parameters (delay, rate)
* @mt: pointer to array of struct input_mt_slot holding current values
* of tracked contacts
* @mtsize: number of MT slots the device uses
* @slot: MT slot currently being transmitted
* @key: reflects current state of device's keys/buttons
* @led: reflects current state of device's LEDs
* @snd: reflects current state of sound effects
...
...
@@ -1119,6 +1143,7 @@ struct ff_effect {
* last user closes the device
* @going_away: marks devices that are in a middle of unregistering and
* causes input_open_device*() fail with -ENODEV.
* @sync: set to %true when there were no new events since last EV_SYN
* @dev: driver model's view of this device
* @h_list: list of input handles associated with the device. When
* accessing the list dev->mutex must be held
...
...
@@ -1140,6 +1165,8 @@ struct input_dev {
unsigned
long
ffbit
[
BITS_TO_LONGS
(
FF_CNT
)];
unsigned
long
swbit
[
BITS_TO_LONGS
(
SW_CNT
)];
unsigned
int
hint_events_per_packet
;
unsigned
int
keycodemax
;
unsigned
int
keycodesize
;
void
*
keycode
;
...
...
@@ -1153,11 +1180,13 @@ struct input_dev {
unsigned
int
repeat_key
;
struct
timer_list
timer
;
int
sync
;
int
abs
[
ABS_CNT
];
int
rep
[
REP_MAX
+
1
];
struct
input_mt_slot
*
mt
;
int
mtsize
;
int
slot
;
unsigned
long
key
[
BITS_TO_LONGS
(
KEY_CNT
)];
unsigned
long
led
[
BITS_TO_LONGS
(
LED_CNT
)];
unsigned
long
snd
[
BITS_TO_LONGS
(
SND_CNT
)];
...
...
@@ -1182,6 +1211,8 @@ struct input_dev {
unsigned
int
users
;
bool
going_away
;
bool
sync
;
struct
device
dev
;
struct
list_head
h_list
;
...
...
@@ -1406,8 +1437,28 @@ static inline void input_mt_sync(struct input_dev *dev)
input_event
(
dev
,
EV_SYN
,
SYN_MT_REPORT
,
0
);
}
static
inline
void
input_mt_slot
(
struct
input_dev
*
dev
,
int
slot
)
{
input_event
(
dev
,
EV_ABS
,
ABS_MT_SLOT
,
slot
);
}
void
input_set_capability
(
struct
input_dev
*
dev
,
unsigned
int
type
,
unsigned
int
code
);
/**
* input_set_events_per_packet - tell handlers about the driver event rate
* @dev: the input device used by the driver
* @n_events: the average number of events between calls to input_sync()
*
* If the event rate sent from a device is unusually large, use this
* function to set the expected event rate. This will allow handlers
* to set up an appropriate buffer size for the event stream, in order
* to minimize information loss.
*/
static
inline
void
input_set_events_per_packet
(
struct
input_dev
*
dev
,
int
n_events
)
{
dev
->
hint_events_per_packet
=
n_events
;
}
static
inline
void
input_set_abs_params
(
struct
input_dev
*
dev
,
int
axis
,
int
min
,
int
max
,
int
fuzz
,
int
flat
)
{
dev
->
absmin
[
axis
]
=
min
;
...
...
@@ -1485,5 +1536,8 @@ int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file);
int
input_ff_create_memless
(
struct
input_dev
*
dev
,
void
*
data
,
int
(
*
play_effect
)(
struct
input_dev
*
,
void
*
,
struct
ff_effect
*
));
int
input_mt_create_slots
(
struct
input_dev
*
dev
,
unsigned
int
num_slots
);
void
input_mt_destroy_slots
(
struct
input_dev
*
dev
);
#endif
#endif
include/linux/input/adxl34x.h
0 → 100644
View file @
929343ef
/*
* include/linux/input/adxl34x.h
*
* Digital Accelerometer characteristics are highly application specific
* and may vary between boards and models. The platform_data for the
* device's "struct device" holds this information.
*
* Copyright 2009 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#ifndef __LINUX_INPUT_ADXL34X_H__
#define __LINUX_INPUT_ADXL34X_H__
struct
adxl34x_platform_data
{
/*
* X,Y,Z Axis Offset:
* offer user offset adjustments in twoscompliment
* form with a scale factor of 15.6 mg/LSB (i.e. 0x7F = +2 g)
*/
s8
x_axis_offset
;
s8
y_axis_offset
;
s8
z_axis_offset
;
/*
* TAP_X/Y/Z Enable: Setting TAP_X, Y, or Z Enable enables X,
* Y, or Z participation in Tap detection. A '0' excludes the
* selected axis from participation in Tap detection.
* Setting the SUPPRESS bit suppresses Double Tap detection if
* acceleration greater than tap_threshold is present between
* taps.
*/
#define ADXL_SUPPRESS (1 << 3)
#define ADXL_TAP_X_EN (1 << 2)
#define ADXL_TAP_Y_EN (1 << 1)
#define ADXL_TAP_Z_EN (1 << 0)
u8
tap_axis_control
;
/*
* tap_threshold:
* holds the threshold value for tap detection/interrupts.
* The data format is unsigned. The scale factor is 62.5 mg/LSB
* (i.e. 0xFF = +16 g). A zero value may result in undesirable
* behavior if Tap/Double Tap is enabled.
*/
u8
tap_threshold
;
/*
* tap_duration:
* is an unsigned time value representing the maximum
* time that an event must be above the tap_threshold threshold
* to qualify as a tap event. The scale factor is 625 us/LSB. A zero
* value will prevent Tap/Double Tap functions from working.
*/
u8
tap_duration
;
/*
* tap_latency:
* is an unsigned time value representing the wait time
* from the detection of a tap event to the opening of the time
* window tap_window for a possible second tap event. The scale
* factor is 1.25 ms/LSB. A zero value will disable the Double Tap
* function.
*/
u8
tap_latency
;
/*
* tap_window:
* is an unsigned time value representing the amount
* of time after the expiration of tap_latency during which a second
* tap can begin. The scale factor is 1.25 ms/LSB. A zero value will
* disable the Double Tap function.
*/
u8
tap_window
;
/*
* act_axis_control:
* X/Y/Z Enable: A '1' enables X, Y, or Z participation in activity
* or inactivity detection. A '0' excludes the selected axis from
* participation. If all of the axes are excluded, the function is
* disabled.
* AC/DC: A '0' = DC coupled operation and a '1' = AC coupled
* operation. In DC coupled operation, the current acceleration is
* compared with activity_threshold and inactivity_threshold directly
* to determine whether activity or inactivity is detected. In AC
* coupled operation for activity detection, the acceleration value
* at the start of activity detection is taken as a reference value.
* New samples of acceleration are then compared to this
* reference value and if the magnitude of the difference exceeds
* activity_threshold the device will trigger an activity interrupt. In
* AC coupled operation for inactivity detection, a reference value
* is used again for comparison and is updated whenever the
* device exceeds the inactivity threshold. Once the reference
* value is selected, the device compares the magnitude of the
* difference between the reference value and the current
* acceleration with inactivity_threshold. If the difference is below
* inactivity_threshold for a total of inactivity_time, the device is
* considered inactive and the inactivity interrupt is triggered.
*/
#define ADXL_ACT_ACDC (1 << 7)
#define ADXL_ACT_X_EN (1 << 6)
#define ADXL_ACT_Y_EN (1 << 5)
#define ADXL_ACT_Z_EN (1 << 4)
#define ADXL_INACT_ACDC (1 << 3)
#define ADXL_INACT_X_EN (1 << 2)
#define ADXL_INACT_Y_EN (1 << 1)
#define ADXL_INACT_Z_EN (1 << 0)
u8
act_axis_control
;
/*
* activity_threshold:
* holds the threshold value for activity detection.
* The data format is unsigned. The scale factor is
* 62.5 mg/LSB. A zero value may result in undesirable behavior if
* Activity interrupt is enabled.
*/
u8
activity_threshold
;
/*
* inactivity_threshold:
* holds the threshold value for inactivity
* detection. The data format is unsigned. The scale
* factor is 62.5 mg/LSB. A zero value may result in undesirable
* behavior if Inactivity interrupt is enabled.
*/
u8
inactivity_threshold
;
/*
* inactivity_time:
* is an unsigned time value representing the
* amount of time that acceleration must be below the value in
* inactivity_threshold for inactivity to be declared. The scale factor
* is 1 second/LSB. Unlike the other interrupt functions, which
* operate on unfiltered data, the inactivity function operates on the
* filtered output data. At least one output sample must be
* generated for the inactivity interrupt to be triggered. This will
* result in the function appearing un-responsive if the
* inactivity_time register is set with a value less than the time
* constant of the Output Data Rate. A zero value will result in an
* interrupt when the output data is below inactivity_threshold.
*/
u8
inactivity_time
;
/*
* free_fall_threshold:
* holds the threshold value for Free-Fall detection.
* The data format is unsigned. The root-sum-square(RSS) value
* of all axes is calculated and compared to the value in
* free_fall_threshold to determine if a free fall event may be
* occurring. The scale factor is 62.5 mg/LSB. A zero value may
* result in undesirable behavior if Free-Fall interrupt is
* enabled. Values between 300 and 600 mg (0x05 to 0x09) are
* recommended.
*/
u8
free_fall_threshold
;
/*
* free_fall_time:
* is an unsigned time value representing the minimum
* time that the RSS value of all axes must be less than
* free_fall_threshold to generate a Free-Fall interrupt. The
* scale factor is 5 ms/LSB. A zero value may result in
* undesirable behavior if Free-Fall interrupt is enabled.
* Values between 100 to 350 ms (0x14 to 0x46) are recommended.
*/
u8
free_fall_time
;
/*
* data_rate:
* Selects device bandwidth and output data rate.
* RATE = 3200 Hz / (2^(15 - x)). Default value is 0x0A, or 100 Hz
* Output Data Rate. An Output Data Rate should be selected that
* is appropriate for the communication protocol and frequency
* selected. Selecting too high of an Output Data Rate with a low
* communication speed will result in samples being discarded.
*/
u8
data_rate
;
/*
* data_range:
* FULL_RES: When this bit is set with the device is
* in Full-Resolution Mode, where the output resolution increases
* with RANGE to maintain a 4 mg/LSB scale factor. When this
* bit is cleared the device is in 10-bit Mode and RANGE determine the
* maximum g-Range and scale factor.
*/
#define ADXL_FULL_RES (1 << 3)
#define ADXL_RANGE_PM_2g 0
#define ADXL_RANGE_PM_4g 1
#define ADXL_RANGE_PM_8g 2
#define ADXL_RANGE_PM_16g 3
u8
data_range
;
/*
* low_power_mode:
* A '0' = Normal operation and a '1' = Reduced
* power operation with somewhat higher noise.
*/
u8
low_power_mode
;
/*
* power_mode:
* LINK: A '1' with both the activity and inactivity functions
* enabled will delay the start of the activity function until
* inactivity is detected. Once activity is detected, inactivity
* detection will begin and prevent the detection of activity. This
* bit serially links the activity and inactivity functions. When '0'
* the inactivity and activity functions are concurrent. Additional
* information can be found in the Application section under Link
* Mode.
* AUTO_SLEEP: A '1' sets the ADXL34x to switch to Sleep Mode
* when inactivity (acceleration has been below inactivity_threshold
* for at least inactivity_time) is detected and the LINK bit is set.
* A '0' disables automatic switching to Sleep Mode. See SLEEP
* for further description.
*/
#define ADXL_LINK (1 << 5)
#define ADXL_AUTO_SLEEP (1 << 4)
u8
power_mode
;
/*
* fifo_mode:
* BYPASS The FIFO is bypassed
* FIFO FIFO collects up to 32 values then stops collecting data
* STREAM FIFO holds the last 32 data values. Once full, the FIFO's
* oldest data is lost as it is replaced with newer data
*
* DEFAULT should be ADXL_FIFO_STREAM
*/
#define ADXL_FIFO_BYPASS 0
#define ADXL_FIFO_FIFO 1
#define ADXL_FIFO_STREAM 2
u8
fifo_mode
;
/*
* watermark:
* The Watermark feature can be used to reduce the interrupt load
* of the system. The FIFO fills up to the value stored in watermark
* [1..32] and then generates an interrupt.
* A '0' disables the watermark feature.
*/
u8
watermark
;
u32
ev_type
;
/* EV_ABS or EV_REL */
u32
ev_code_x
;
/* ABS_X,Y,Z or REL_X,Y,Z */
u32
ev_code_y
;
/* ABS_X,Y,Z or REL_X,Y,Z */
u32
ev_code_z
;
/* ABS_X,Y,Z or REL_X,Y,Z */
/*
* A valid BTN or KEY Code; use tap_axis_control to disable
* event reporting
*/
u32
ev_code_tap
[
3
];
/* EV_KEY {X-Axis, Y-Axis, Z-Axis} */
/*
* A valid BTN or KEY Code for Free-Fall or Activity enables
* input event reporting. A '0' disables the Free-Fall or
* Activity reporting.
*/
u32
ev_code_ff
;
/* EV_KEY */
u32
ev_code_act_inactivity
;
/* EV_KEY */
/*
* Use ADXL34x INT2 instead of INT1
*/
u8
use_int2
;
/*
* ADXL346 only ORIENTATION SENSING feature
* The orientation function of the ADXL346 reports both 2-D and
* 3-D orientation concurrently.
*/
#define ADXL_EN_ORIENTATION_2D 1
#define ADXL_EN_ORIENTATION_3D 2
#define ADXL_EN_ORIENTATION_2D_3D 3
u8
orientation_enable
;
/*
* The width of the deadzone region between two or more
* orientation positions is determined by setting the Deadzone
* value. The deadzone region size can be specified with a
* resolution of 3.6deg. The deadzone angle represents the total
* angle where the orientation is considered invalid.
*/
#define ADXL_DEADZONE_ANGLE_0p0 0
/* !!!0.0 [deg] */
#define ADXL_DEADZONE_ANGLE_3p6 1
/* 3.6 [deg] */
#define ADXL_DEADZONE_ANGLE_7p2 2
/* 7.2 [deg] */
#define ADXL_DEADZONE_ANGLE_10p8 3
/* 10.8 [deg] */
#define ADXL_DEADZONE_ANGLE_14p4 4
/* 14.4 [deg] */
#define ADXL_DEADZONE_ANGLE_18p0 5
/* 18.0 [deg] */
#define ADXL_DEADZONE_ANGLE_21p6 6
/* 21.6 [deg] */
#define ADXL_DEADZONE_ANGLE_25p2 7
/* 25.2 [deg] */
u8
deadzone_angle
;
/*
* To eliminate most human motion such as walking or shaking,
* a Divisor value should be selected to effectively limit the
* orientation bandwidth. Set the depth of the filter used to
* low-pass filter the measured acceleration for stable
* orientation sensing
*/
#define ADXL_LP_FILTER_DIVISOR_2 0
#define ADXL_LP_FILTER_DIVISOR_4 1
#define ADXL_LP_FILTER_DIVISOR_8 2
#define ADXL_LP_FILTER_DIVISOR_16 3
#define ADXL_LP_FILTER_DIVISOR_32 4
#define ADXL_LP_FILTER_DIVISOR_64 5
#define ADXL_LP_FILTER_DIVISOR_128 6
#define ADXL_LP_FILTER_DIVISOR_256 7
u8
divisor_length
;
u32
ev_codes_orient_2d
[
4
];
/* EV_KEY {+X, -X, +Y, -Y} */
u32
ev_codes_orient_3d
[
6
];
/* EV_KEY {+Z, +Y, +X, -X, -Y, -Z} */
};
#endif
include/linux/input/cy8ctmg110_pdata.h
0 → 100644
View file @
929343ef
#ifndef _LINUX_CY8CTMG110_PDATA_H
#define _LINUX_CY8CTMG110_PDATA_H
struct
cy8ctmg110_pdata
{
int
reset_pin
;
/* Reset pin is wired to this GPIO (optional) */
int
irq_pin
;
/* IRQ pin is wired to this GPIO */
};
#endif
include/linux/input/matrix_keypad.h
View file @
929343ef
...
...
@@ -41,6 +41,9 @@ struct matrix_keymap_data {
* @col_scan_delay_us: delay, measured in microseconds, that is
* needed before we can keypad after activating column gpio
* @debounce_ms: debounce interval in milliseconds
* @clustered_irq: may be specified if interrupts of all row/column GPIOs
* are bundled to one single irq
* @clustered_irq_flags: flags that are needed for the clustered irq
* @active_low: gpio polarity
* @wakeup: controls whether the device should be set up as wakeup
* source
...
...
@@ -63,6 +66,9 @@ struct matrix_keypad_platform_data {
/* key debounce interval in milli-second */
unsigned
int
debounce_ms
;
unsigned
int
clustered_irq
;
unsigned
int
clustered_irq_flags
;
bool
active_low
;
bool
wakeup
;
bool
no_autorepeat
;
...
...
include/linux/spi/ads7846.h
View file @
929343ef
...
...
@@ -48,11 +48,12 @@ struct ads7846_platform_data {
* state if get_pendown_state == NULL
*/
int
(
*
get_pendown_state
)(
void
);
int
(
*
filter_init
)
(
struct
ads7846_platform_data
*
pdata
,
int
(
*
filter_init
)
(
const
struct
ads7846_platform_data
*
pdata
,
void
**
filter_data
);
int
(
*
filter
)
(
void
*
filter_data
,
int
data_idx
,
int
*
val
);
void
(
*
filter_cleanup
)(
void
*
filter_data
);
void
(
*
wait_for_sync
)(
void
);
bool
wakeup
;
unsigned
long
irq_flags
;
};
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment