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
nexedi
linux
Commits
308f0a58
Commit
308f0a58
authored
Apr 24, 2008
by
Dmitry Torokhov
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into for-linus
parents
0035a1dc
b345dc7d
Changes
49
Show whitespace changes
Inline
Side-by-side
Showing
49 changed files
with
3904 additions
and
119 deletions
+3904
-119
MAINTAINERS
MAINTAINERS
+10
-0
drivers/char/keyboard.c
drivers/char/keyboard.c
+5
-1
drivers/hid/usbhid/hid-quirks.c
drivers/hid/usbhid/hid-quirks.c
+4
-0
drivers/input/input-polldev.c
drivers/input/input-polldev.c
+3
-3
drivers/input/joystick/Kconfig
drivers/input/joystick/Kconfig
+12
-0
drivers/input/joystick/Makefile
drivers/input/joystick/Makefile
+2
-1
drivers/input/joystick/xpad.c
drivers/input/joystick/xpad.c
+189
-24
drivers/input/joystick/zhenhua.c
drivers/input/joystick/zhenhua.c
+243
-0
drivers/input/keyboard/aaed2000_kbd.c
drivers/input/keyboard/aaed2000_kbd.c
+4
-0
drivers/input/keyboard/bf54x-keys.c
drivers/input/keyboard/bf54x-keys.c
+34
-3
drivers/input/keyboard/corgikbd.c
drivers/input/keyboard/corgikbd.c
+2
-0
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/gpio_keys.c
+4
-1
drivers/input/keyboard/jornada680_kbd.c
drivers/input/keyboard/jornada680_kbd.c
+2
-0
drivers/input/keyboard/jornada720_kbd.c
drivers/input/keyboard/jornada720_kbd.c
+4
-0
drivers/input/keyboard/locomokbd.c
drivers/input/keyboard/locomokbd.c
+48
-25
drivers/input/keyboard/omap-keypad.c
drivers/input/keyboard/omap-keypad.c
+7
-2
drivers/input/keyboard/pxa27x_keypad.c
drivers/input/keyboard/pxa27x_keypad.c
+4
-0
drivers/input/keyboard/spitzkbd.c
drivers/input/keyboard/spitzkbd.c
+1
-0
drivers/input/keyboard/tosakbd.c
drivers/input/keyboard/tosakbd.c
+20
-3
drivers/input/misc/cobalt_btns.c
drivers/input/misc/cobalt_btns.c
+3
-0
drivers/input/mouse/gpio_mouse.c
drivers/input/mouse/gpio_mouse.c
+4
-0
drivers/input/serio/Kconfig
drivers/input/serio/Kconfig
+10
-0
drivers/input/serio/Makefile
drivers/input/serio/Makefile
+1
-0
drivers/input/serio/at32psif.c
drivers/input/serio/at32psif.c
+375
-0
drivers/input/serio/i8042-x86ia64io.h
drivers/input/serio/i8042-x86ia64io.h
+6
-6
drivers/input/serio/rpckbd.c
drivers/input/serio/rpckbd.c
+2
-0
drivers/input/tablet/Kconfig
drivers/input/tablet/Kconfig
+5
-5
drivers/input/tablet/aiptek.c
drivers/input/tablet/aiptek.c
+2
-0
drivers/input/tablet/wacom.h
drivers/input/tablet/wacom.h
+3
-0
drivers/input/tablet/wacom_sys.c
drivers/input/tablet/wacom_sys.c
+66
-10
drivers/input/tablet/wacom_wac.c
drivers/input/tablet/wacom_wac.c
+2
-0
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Kconfig
+53
-0
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/Makefile
+7
-0
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/ads7846.c
+10
-12
drivers/input/touchscreen/corgi_ts.c
drivers/input/touchscreen/corgi_ts.c
+2
-0
drivers/input/touchscreen/jornada720_ts.c
drivers/input/touchscreen/jornada720_ts.c
+4
-0
drivers/input/touchscreen/mainstone-wm97xx.c
drivers/input/touchscreen/mainstone-wm97xx.c
+302
-0
drivers/input/touchscreen/ucb1400_ts.c
drivers/input/touchscreen/ucb1400_ts.c
+0
-4
drivers/input/touchscreen/usbtouchscreen.c
drivers/input/touchscreen/usbtouchscreen.c
+19
-12
drivers/input/touchscreen/wm9705.c
drivers/input/touchscreen/wm9705.c
+353
-0
drivers/input/touchscreen/wm9712.c
drivers/input/touchscreen/wm9712.c
+462
-0
drivers/input/touchscreen/wm9713.c
drivers/input/touchscreen/wm9713.c
+460
-0
drivers/input/touchscreen/wm97xx-core.c
drivers/input/touchscreen/wm97xx-core.c
+829
-0
drivers/macintosh/mac_hid.c
drivers/macintosh/mac_hid.c
+6
-0
include/linux/input.h
include/linux/input.h
+2
-6
include/linux/keyboard.h
include/linux/keyboard.h
+1
-0
include/linux/serio.h
include/linux/serio.h
+1
-0
include/linux/spi/ads7846.h
include/linux/spi/ads7846.h
+2
-1
include/linux/wm97xx.h
include/linux/wm97xx.h
+314
-0
No files found.
MAINTAINERS
View file @
308f0a58
...
...
@@ -4343,6 +4343,16 @@ L: linux-wireless@vger.kernel.org
W: http://oops.ghostprotocols.net:81/blog
S: Maintained
WM97XX TOUCHSCREEN DRIVERS
P: Mark Brown
M: broonie@opensource.wolfsonmicro.com
P: Liam Girdwood
M: liam.girdwood@wolfsonmicro.com
L: linux-input@vger.kernel.org
T: git git://opensource.wolfsonmicro.com/linux-2.6-touch
W: http://opensource.wolfsonmicro.com/node/7
S: Supported
X.25 NETWORK LAYER
P: Henner Eisen
M: eis@baty.hanse.de
...
...
drivers/char/keyboard.c
View file @
308f0a58
...
...
@@ -42,6 +42,7 @@
#include <linux/input.h>
#include <linux/reboot.h>
#include <linux/notifier.h>
#include <linux/jiffies.h>
extern
void
ctrl_alt_del
(
void
);
...
...
@@ -928,7 +929,8 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
if
(
up_flag
)
{
if
(
brl_timeout
)
{
if
(
!
committing
||
jiffies
-
releasestart
>
(
brl_timeout
*
HZ
)
/
1000
)
{
time_after
(
jiffies
,
releasestart
+
msecs_to_jiffies
(
brl_timeout
)))
{
committing
=
pressed
;
releasestart
=
jiffies
;
}
...
...
@@ -1237,6 +1239,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
}
param
.
shift
=
shift_final
=
(
shift_state
|
kbd
->
slockstate
)
^
kbd
->
lockstate
;
param
.
ledstate
=
kbd
->
ledflagstate
;
key_map
=
key_maps
[
shift_final
];
if
(
atomic_notifier_call_chain
(
&
keyboard_notifier_list
,
KBD_KEYCODE
,
&
param
)
==
NOTIFY_STOP
||
!
key_map
)
{
...
...
@@ -1285,6 +1288,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
(
*
k_handler
[
type
])(
vc
,
keysym
&
0xff
,
!
down
);
param
.
ledstate
=
kbd
->
ledflagstate
;
atomic_notifier_call_chain
(
&
keyboard_notifier_list
,
KBD_POST_KEYSYM
,
&
param
);
if
(
type
!=
KT_SLOCK
)
...
...
drivers/hid/usbhid/hid-quirks.c
View file @
308f0a58
...
...
@@ -405,6 +405,9 @@
#define USB_VENDOR_ID_YEALINK 0x6993
#define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K 0xb001
#define USB_VENDOR_ID_KYE 0x0458
#define USB_DEVICE_ID_KYE_GPEN_560 0x5003
/*
* Alphabetically sorted blacklist by quirk type.
*/
...
...
@@ -703,6 +706,7 @@ static const struct hid_blacklist {
{
USB_VENDOR_ID_LOGITECH
,
USB_DEVICE_ID_LOGITECH_HARMONY_63
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_LOGITECH
,
USB_DEVICE_ID_LOGITECH_HARMONY_64
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR
,
USB_DEVICE_ID_N_S_HARMONY
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_KYE
,
USB_DEVICE_ID_KYE_GPEN_560
,
HID_QUIRK_IGNORE
},
{
0
,
0
}
};
...
...
drivers/input/input-polldev.c
View file @
308f0a58
...
...
@@ -73,7 +73,7 @@ static void input_polled_device_work(struct work_struct *work)
static
int
input_open_polled_device
(
struct
input_dev
*
input
)
{
struct
input_polled_dev
*
dev
=
input
->
private
;
struct
input_polled_dev
*
dev
=
input
_get_drvdata
(
input
)
;
int
error
;
error
=
input_polldev_start_workqueue
();
...
...
@@ -91,7 +91,7 @@ static int input_open_polled_device(struct input_dev *input)
static
void
input_close_polled_device
(
struct
input_dev
*
input
)
{
struct
input_polled_dev
*
dev
=
input
->
private
;
struct
input_polled_dev
*
dev
=
input
_get_drvdata
(
input
)
;
cancel_delayed_work_sync
(
&
dev
->
work
);
input_polldev_stop_workqueue
();
...
...
@@ -151,10 +151,10 @@ int input_register_polled_device(struct input_polled_dev *dev)
{
struct
input_dev
*
input
=
dev
->
input
;
input_set_drvdata
(
input
,
dev
);
INIT_DELAYED_WORK
(
&
dev
->
work
,
input_polled_device_work
);
if
(
!
dev
->
poll_interval
)
dev
->
poll_interval
=
500
;
input
->
private
=
dev
;
input
->
open
=
input_open_polled_device
;
input
->
close
=
input_close_polled_device
;
...
...
drivers/input/joystick/Kconfig
View file @
308f0a58
...
...
@@ -193,6 +193,18 @@ config JOYSTICK_TWIDJOY
To compile this driver as a module, choose M here: the
module will be called twidjoy.
config JOYSTICK_ZHENHUA
tristate "5-byte Zhenhua RC transmitter"
select SERIO
help
Say Y here if you have a Zhen Hua PPM-4CH transmitter which is
supplied with a ready to fly micro electric indoor helicopters
such as EasyCopter, Lama, MiniCopter, DragonFly or Jabo and want
to use it via serial cable as a joystick.
To compile this driver as a module, choose M here: the
module will be called zhenhua.
config JOYSTICK_DB9
tristate "Multisystem, Sega Genesis, Saturn joysticks and gamepads"
depends on PARPORT
...
...
drivers/input/joystick/Makefile
View file @
308f0a58
...
...
@@ -15,6 +15,7 @@ obj-$(CONFIG_JOYSTICK_GF2K) += gf2k.o
obj-$(CONFIG_JOYSTICK_GRIP)
+=
grip.o
obj-$(CONFIG_JOYSTICK_GRIP_MP)
+=
grip_mp.o
obj-$(CONFIG_JOYSTICK_GUILLEMOT)
+=
guillemot.o
obj-$(CONFIG_JOYSTICK_IFORCE)
+=
iforce/
obj-$(CONFIG_JOYSTICK_INTERACT)
+=
interact.o
obj-$(CONFIG_JOYSTICK_JOYDUMP)
+=
joydump.o
obj-$(CONFIG_JOYSTICK_MAGELLAN)
+=
magellan.o
...
...
@@ -27,5 +28,5 @@ obj-$(CONFIG_JOYSTICK_TURBOGRAFX) += turbografx.o
obj-$(CONFIG_JOYSTICK_TWIDJOY)
+=
twidjoy.o
obj-$(CONFIG_JOYSTICK_WARRIOR)
+=
warrior.o
obj-$(CONFIG_JOYSTICK_XPAD)
+=
xpad.o
obj-$(CONFIG_JOYSTICK_ZHENHUA)
+=
zhenhua.o
obj-$(CONFIG_JOYSTICK_IFORCE)
+=
iforce/
drivers/input/joystick/xpad.c
View file @
308f0a58
/*
* X-Box gamepad
- v0.0.6
* X-Box gamepad
driver
*
* Copyright (c) 2002 Marko Friedemann <mfr@bmx-chemnitz.de>
* 2004 Oliver Schwartz <Oliver.Schwartz@gmx.de>,
...
...
@@ -68,6 +68,8 @@
* - dance pads will map D-PAD to buttons, not axes
* - pass the module paramater 'dpad_to_buttons' to force
* the D-PAD to map to buttons if your pad is not detected
*
* Later changes can be tracked in SCM.
*/
#include <linux/kernel.h>
...
...
@@ -77,7 +79,6 @@
#include <linux/module.h>
#include <linux/usb/input.h>
#define DRIVER_VERSION "v0.0.6"
#define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>"
#define DRIVER_DESC "X-Box pad driver"
...
...
@@ -87,10 +88,12 @@
but we map them to axes when possible to simplify things */
#define MAP_DPAD_TO_BUTTONS 0
#define MAP_DPAD_TO_AXES 1
#define MAP_DPAD_UNKNOWN
-1
#define MAP_DPAD_UNKNOWN
2
#define XTYPE_XBOX 0
#define XTYPE_XBOX360 1
#define XTYPE_XBOX360W 2
#define XTYPE_UNKNOWN 3
static
int
dpad_to_buttons
;
module_param
(
dpad_to_buttons
,
bool
,
S_IRUGO
);
...
...
@@ -107,8 +110,10 @@ static const struct xpad_device {
{
0x045e
,
0x0289
,
"Microsoft X-Box pad v2 (US)"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX
},
{
0x045e
,
0x0285
,
"Microsoft X-Box pad (Japan)"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX
},
{
0x045e
,
0x0287
,
"Microsoft Xbox Controller S"
,
MAP_DPAD_TO_AXES
,
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
},
{
0x044f
,
0x0f07
,
"Thrustmaster, Inc. Controller"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX
},
{
0x046d
,
0xc242
,
"Logitech Chillstream Controller"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX360
},
{
0x046d
,
0xca84
,
"Logitech Xbox Cordless Controller"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX
},
{
0x046d
,
0xca88
,
"Logitech Compact Controller for Xbox"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX
},
{
0x05fd
,
0x1007
,
"Mad Catz Controller (unverified)"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX
},
...
...
@@ -135,18 +140,26 @@ static const struct xpad_device {
{
0x0f30
,
0x8888
,
"BigBen XBMiniPad Controller"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX
},
{
0x102c
,
0xff0c
,
"Joytech Wireless Advanced Controller"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX
},
{
0x12ab
,
0x8809
,
"Xbox DDR dancepad"
,
MAP_DPAD_TO_BUTTONS
,
XTYPE_XBOX
},
{
0x1430
,
0x4748
,
"RedOctane Guitar Hero X-plorer"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX360
},
{
0x1430
,
0x8888
,
"TX6500+ Dance Pad (first generation)"
,
MAP_DPAD_TO_BUTTONS
,
XTYPE_XBOX
},
{
0x045e
,
0x028e
,
"Microsoft X-Box 360 pad"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX360
},
{
0xffff
,
0xffff
,
"Chinese-made Xbox Controller"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX
},
{
0x0000
,
0x0000
,
"Generic X-Box pad"
,
MAP_DPAD_UNKNOWN
,
XTYPE_
XBOX
}
{
0x0000
,
0x0000
,
"Generic X-Box pad"
,
MAP_DPAD_UNKNOWN
,
XTYPE_
UNKNOWN
}
};
static
const
signed
short
xpad_btn
[]
=
{
BTN_A
,
BTN_B
,
BTN_C
,
BTN_X
,
BTN_Y
,
BTN_Z
,
/* "analog" buttons */
/* 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 */
-
1
/* terminating entry */
};
/* original xbox controllers only */
static
const
signed
short
xpad_btn
[]
=
{
BTN_C
,
BTN_Z
,
/* "analog" buttons */
-
1
/* terminating entry */
};
/* only used if MAP_DPAD_TO_BUTTONS */
static
const
signed
short
xpad_btn_pad
[]
=
{
BTN_LEFT
,
BTN_RIGHT
,
/* d-pad left, right */
...
...
@@ -173,12 +186,27 @@ static const signed short xpad_abs_pad[] = {
-
1
/* terminating entry */
};
/* Xbox 360 has a vendor-specific (sub)class, so we cannot match it with only
* USB_INTERFACE_INFO, more to that this device has 4 InterfaceProtocols,
* but we need only one of them. */
/* Xbox 360 has a vendor-specific class, so we cannot match it with only
* USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we
* match against vendor id as well. Wired Xbox 360 devices have protocol 1,
* wireless controllers have protocol 129. */
#define XPAD_XBOX360_VENDOR_PROTOCOL(vend,pr) \
.match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, \
.idVendor = (vend), \
.bInterfaceClass = USB_CLASS_VENDOR_SPEC, \
.bInterfaceSubClass = 93, \
.bInterfaceProtocol = (pr)
#define XPAD_XBOX360_VENDOR(vend) \
{ XPAD_XBOX360_VENDOR_PROTOCOL(vend,1) }, \
{ XPAD_XBOX360_VENDOR_PROTOCOL(vend,129) }
static
struct
usb_device_id
xpad_table
[]
=
{
{
USB_INTERFACE_INFO
(
'X'
,
'B'
,
0
)
},
/* X-Box USB-IF not approved class */
{
USB_DEVICE_INTERFACE_PROTOCOL
(
0x045e
,
0x028e
,
1
)
},
/* X-Box 360 controller */
XPAD_XBOX360_VENDOR
(
0x045e
),
/* Microsoft X-Box 360 controllers */
XPAD_XBOX360_VENDOR
(
0x046d
),
/* Logitech X-Box 360 style controllers */
XPAD_XBOX360_VENDOR
(
0x0738
),
/* Mad Catz X-Box 360 controllers */
XPAD_XBOX360_VENDOR
(
0x0e6f
),
/* 0x0e6f X-Box 360 controllers */
XPAD_XBOX360_VENDOR
(
0x1430
),
/* RedOctane X-Box 360 controllers */
{
}
};
...
...
@@ -188,10 +216,15 @@ struct usb_xpad {
struct
input_dev
*
dev
;
/* input device interface */
struct
usb_device
*
udev
;
/* usb device */
int
pad_present
;
struct
urb
*
irq_in
;
/* urb for interrupt in report */
unsigned
char
*
idata
;
/* input data */
dma_addr_t
idata_dma
;
struct
urb
*
bulk_out
;
unsigned
char
*
bdata
;
#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
struct
urb
*
irq_out
;
/* urb for interrupt out report */
unsigned
char
*
odata
;
/* output data */
...
...
@@ -227,13 +260,13 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
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
)));
~
(
__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
)));
~
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
18
)));
/* triggers left/right */
input_report_abs
(
dev
,
ABS_Z
,
data
[
10
]);
...
...
@@ -321,13 +354,13 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
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
)));
~
(
__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
)));
~
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
12
)));
/* triggers left/right */
input_report_abs
(
dev
,
ABS_Z
,
data
[
4
]);
...
...
@@ -336,6 +369,39 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
input_sync
(
dev
);
}
/*
* xpad360w_process_packet
*
* Completes a request by converting the data into events for the
* input subsystem. It is version for xbox 360 wireless controller.
*
* Byte.Bit
* 00.1 - Status change: The controller or headset has connected/disconnected
* Bits 01.7 and 01.6 are valid
* 01.7 - Controller present
* 01.6 - Headset present
* 01.1 - Pad state (Bytes 4+) valid
*
*/
static
void
xpad360w_process_packet
(
struct
usb_xpad
*
xpad
,
u16
cmd
,
unsigned
char
*
data
)
{
/* Presence change */
if
(
data
[
0
]
&
0x08
)
{
if
(
data
[
1
]
&
0x80
)
{
xpad
->
pad_present
=
1
;
usb_submit_urb
(
xpad
->
bulk_out
,
GFP_ATOMIC
);
}
else
xpad
->
pad_present
=
0
;
}
/* Valid pad data */
if
(
!
(
data
[
1
]
&
0x1
))
return
;
xpad360_process_packet
(
xpad
,
cmd
,
&
data
[
4
]);
}
static
void
xpad_irq_in
(
struct
urb
*
urb
)
{
struct
usb_xpad
*
xpad
=
urb
->
context
;
...
...
@@ -358,10 +424,16 @@ static void xpad_irq_in(struct urb *urb)
goto
exit
;
}
if
(
xpad
->
xtype
==
XTYPE_XBOX360
)
switch
(
xpad
->
xtype
)
{
case
XTYPE_XBOX360
:
xpad360_process_packet
(
xpad
,
0
,
xpad
->
idata
);
else
break
;
case
XTYPE_XBOX360W
:
xpad360w_process_packet
(
xpad
,
0
,
xpad
->
idata
);
break
;
default:
xpad_process_packet
(
xpad
,
0
,
xpad
->
idata
);
}
exit:
retval
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
...
...
@@ -399,6 +471,23 @@ static void xpad_irq_out(struct urb *urb)
__FUNCTION__
,
retval
);
}
static
void
xpad_bulk_out
(
struct
urb
*
urb
)
{
switch
(
urb
->
status
)
{
case
0
:
/* success */
break
;
case
-
ECONNRESET
:
case
-
ENOENT
:
case
-
ESHUTDOWN
:
/* this urb is terminated, clean up */
dbg
(
"%s - urb shutting down with status: %d"
,
__FUNCTION__
,
urb
->
status
);
break
;
default:
dbg
(
"%s - nonzero urb status received: %d"
,
__FUNCTION__
,
urb
->
status
);
}
}
static
int
xpad_init_output
(
struct
usb_interface
*
intf
,
struct
usb_xpad
*
xpad
)
{
struct
usb_endpoint_descriptor
*
ep_irq_out
;
...
...
@@ -408,7 +497,7 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
return
0
;
xpad
->
odata
=
usb_buffer_alloc
(
xpad
->
udev
,
XPAD_PKT_LEN
,
GFP_
ATOMIC
,
&
xpad
->
odata_dma
);
GFP_
KERNEL
,
&
xpad
->
odata_dma
);
if
(
!
xpad
->
odata
)
goto
fail1
;
...
...
@@ -469,6 +558,7 @@ static int xpad_play_effect(struct input_dev *dev, void *data,
xpad
->
odata
[
5
]
=
0x00
;
xpad
->
odata
[
6
]
=
0x00
;
xpad
->
odata
[
7
]
=
0x00
;
xpad
->
irq_out
->
transfer_buffer_length
=
8
;
usb_submit_urb
(
xpad
->
irq_out
,
GFP_KERNEL
);
}
...
...
@@ -477,6 +567,9 @@ static int xpad_play_effect(struct input_dev *dev, void *data,
static
int
xpad_init_ff
(
struct
usb_xpad
*
xpad
)
{
if
(
xpad
->
xtype
!=
XTYPE_XBOX360
)
return
0
;
input_set_capability
(
xpad
->
dev
,
EV_FF
,
FF_RUMBLE
);
return
input_ff_create_memless
(
xpad
->
dev
,
NULL
,
xpad_play_effect
);
...
...
@@ -502,6 +595,7 @@ static void xpad_send_led_command(struct usb_xpad *xpad, int command)
xpad
->
odata
[
0
]
=
0x01
;
xpad
->
odata
[
1
]
=
0x03
;
xpad
->
odata
[
2
]
=
command
;
xpad
->
irq_out
->
transfer_buffer_length
=
3
;
usb_submit_urb
(
xpad
->
irq_out
,
GFP_KERNEL
);
mutex_unlock
(
&
xpad
->
odata_mutex
);
}
...
...
@@ -574,6 +668,10 @@ static int xpad_open(struct input_dev *dev)
{
struct
usb_xpad
*
xpad
=
input_get_drvdata
(
dev
);
/* URB was submitted in probe */
if
(
xpad
->
xtype
==
XTYPE_XBOX360W
)
return
0
;
xpad
->
irq_in
->
dev
=
xpad
->
udev
;
if
(
usb_submit_urb
(
xpad
->
irq_in
,
GFP_KERNEL
))
return
-
EIO
;
...
...
@@ -585,6 +683,7 @@ static void xpad_close(struct input_dev *dev)
{
struct
usb_xpad
*
xpad
=
input_get_drvdata
(
dev
);
if
(
xpad
->
xtype
!=
XTYPE_XBOX360W
)
usb_kill_urb
(
xpad
->
irq_in
);
xpad_stop_output
(
xpad
);
}
...
...
@@ -632,7 +731,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
goto
fail1
;
xpad
->
idata
=
usb_buffer_alloc
(
udev
,
XPAD_PKT_LEN
,
GFP_
ATOMIC
,
&
xpad
->
idata_dma
);
GFP_
KERNEL
,
&
xpad
->
idata_dma
);
if
(
!
xpad
->
idata
)
goto
fail1
;
...
...
@@ -644,7 +743,16 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
xpad
->
dpad_mapping
=
xpad_device
[
i
].
dpad_mapping
;
xpad
->
xtype
=
xpad_device
[
i
].
xtype
;
if
(
xpad
->
dpad_mapping
==
MAP_DPAD_UNKNOWN
)
xpad
->
dpad_mapping
=
dpad_to_buttons
;
xpad
->
dpad_mapping
=
!
dpad_to_buttons
;
if
(
xpad
->
xtype
==
XTYPE_UNKNOWN
)
{
if
(
intf
->
cur_altsetting
->
desc
.
bInterfaceClass
==
USB_CLASS_VENDOR_SPEC
)
{
if
(
intf
->
cur_altsetting
->
desc
.
bInterfaceProtocol
==
129
)
xpad
->
xtype
=
XTYPE_XBOX360W
;
else
xpad
->
xtype
=
XTYPE_XBOX360
;
}
else
xpad
->
xtype
=
XTYPE_XBOX
;
}
xpad
->
dev
=
input_dev
;
usb_make_path
(
udev
,
xpad
->
phys
,
sizeof
(
xpad
->
phys
));
strlcat
(
xpad
->
phys
,
"/input0"
,
sizeof
(
xpad
->
phys
));
...
...
@@ -662,11 +770,14 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
input_dev
->
evbit
[
0
]
=
BIT_MASK
(
EV_KEY
)
|
BIT_MASK
(
EV_ABS
);
/* set up buttons */
for
(
i
=
0
;
xpad_btn
[
i
]
>=
0
;
i
++
)
set_bit
(
xpad_btn
[
i
],
input_dev
->
keybit
);
if
(
xpad
->
xtype
==
XTYPE_XBOX360
)
for
(
i
=
0
;
xpad_
common_
btn
[
i
]
>=
0
;
i
++
)
set_bit
(
xpad_
common_
btn
[
i
],
input_dev
->
keybit
);
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
);
else
for
(
i
=
0
;
xpad_btn
[
i
]
>=
0
;
i
++
)
set_bit
(
xpad_btn
[
i
],
input_dev
->
keybit
);
if
(
xpad
->
dpad_mapping
==
MAP_DPAD_TO_BUTTONS
)
for
(
i
=
0
;
xpad_btn_pad
[
i
]
>=
0
;
i
++
)
set_bit
(
xpad_btn_pad
[
i
],
input_dev
->
keybit
);
...
...
@@ -703,8 +814,57 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
goto
fail4
;
usb_set_intfdata
(
intf
,
xpad
);
/*
* Submit the int URB immediatly rather than waiting for open
* because we get status messages from the device whether
* or not any controllers are attached. In fact, it's
* exactly the message that a controller has arrived that
* we're waiting for.
*/
if
(
xpad
->
xtype
==
XTYPE_XBOX360W
)
{
xpad
->
irq_in
->
dev
=
xpad
->
udev
;
error
=
usb_submit_urb
(
xpad
->
irq_in
,
GFP_KERNEL
);
if
(
error
)
goto
fail4
;
/*
* Setup the message to set the LEDs on the
* controller when it shows up
*/
xpad
->
bulk_out
=
usb_alloc_urb
(
0
,
GFP_KERNEL
);
if
(
!
xpad
->
bulk_out
)
goto
fail5
;
xpad
->
bdata
=
kzalloc
(
XPAD_PKT_LEN
,
GFP_KERNEL
);
if
(
!
xpad
->
bdata
)
goto
fail6
;
xpad
->
bdata
[
2
]
=
0x08
;
switch
(
intf
->
cur_altsetting
->
desc
.
bInterfaceNumber
)
{
case
0
:
xpad
->
bdata
[
3
]
=
0x42
;
break
;
case
2
:
xpad
->
bdata
[
3
]
=
0x43
;
break
;
case
4
:
xpad
->
bdata
[
3
]
=
0x44
;
break
;
case
6
:
xpad
->
bdata
[
3
]
=
0x45
;
}
ep_irq_in
=
&
intf
->
cur_altsetting
->
endpoint
[
1
].
desc
;
usb_fill_bulk_urb
(
xpad
->
bulk_out
,
udev
,
usb_sndbulkpipe
(
udev
,
ep_irq_in
->
bEndpointAddress
),
xpad
->
bdata
,
XPAD_PKT_LEN
,
xpad_bulk_out
,
xpad
);
}
return
0
;
fail6:
usb_free_urb
(
xpad
->
bulk_out
);
fail5:
usb_kill_urb
(
xpad
->
irq_in
);
fail4:
usb_free_urb
(
xpad
->
irq_in
);
fail3:
xpad_deinit_output
(
xpad
);
fail2:
usb_buffer_free
(
udev
,
XPAD_PKT_LEN
,
xpad
->
idata
,
xpad
->
idata_dma
);
...
...
@@ -723,6 +883,11 @@ static void xpad_disconnect(struct usb_interface *intf)
xpad_led_disconnect
(
xpad
);
input_unregister_device
(
xpad
->
dev
);
xpad_deinit_output
(
xpad
);
if
(
xpad
->
xtype
==
XTYPE_XBOX360W
)
{
usb_kill_urb
(
xpad
->
bulk_out
);
usb_free_urb
(
xpad
->
bulk_out
);
usb_kill_urb
(
xpad
->
irq_in
);
}
usb_free_urb
(
xpad
->
irq_in
);
usb_buffer_free
(
xpad
->
udev
,
XPAD_PKT_LEN
,
xpad
->
idata
,
xpad
->
idata_dma
);
...
...
@@ -741,7 +906,7 @@ static int __init usb_xpad_init(void)
{
int
result
=
usb_register
(
&
xpad_driver
);
if
(
result
==
0
)
info
(
DRIVER_DESC
":"
DRIVER_VERSION
);
info
(
DRIVER_DESC
);
return
result
;
}
...
...
drivers/input/joystick/zhenhua.c
0 → 100644
View file @
308f0a58
/*
* derived from "twidjoy.c"
*
* Copyright (c) 2008 Martin Kebert
* Copyright (c) 2001 Arndt Schoenewald
* Copyright (c) 2000-2001 Vojtech Pavlik
* Copyright (c) 2000 Mark Fletcher
*
*/
/*
* Driver to use 4CH RC transmitter using Zhen Hua 5-byte protocol (Walkera Lama,
* EasyCopter etc.) as a joystick under Linux.
*
* RC transmitters using Zhen Hua 5-byte protocol are cheap four channels
* transmitters for control a RC planes or RC helicopters with possibility to
* connect on a serial port.
* Data coming from transmitter is in this order:
* 1. byte = synchronisation byte
* 2. byte = X axis
* 3. byte = Y axis
* 4. byte = RZ axis
* 5. byte = Z axis
* (and this is repeated)
*
* For questions or feedback regarding this driver module please contact:
* Martin Kebert <gkmarty@gmail.com> - but I am not a C-programmer nor kernel
* coder :-(
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/init.h>
#define DRIVER_DESC "RC transmitter with 5-byte Zhen Hua protocol joystick driver"
MODULE_DESCRIPTION
(
DRIVER_DESC
);
MODULE_LICENSE
(
"GPL"
);
/*
* Constants.
*/
#define ZHENHUA_MAX_LENGTH 5
/*
* Zhen Hua data.
*/
struct
zhenhua
{
struct
input_dev
*
dev
;
int
idx
;
unsigned
char
data
[
ZHENHUA_MAX_LENGTH
];
char
phys
[
32
];
};
/* bits in all incoming bytes needs to be "reversed" */
static
int
zhenhua_bitreverse
(
int
x
)
{
x
=
((
x
&
0xaa
)
>>
1
)
|
((
x
&
0x55
)
<<
1
);
x
=
((
x
&
0xcc
)
>>
2
)
|
((
x
&
0x33
)
<<
2
);
x
=
((
x
&
0xf0
)
>>
4
)
|
((
x
&
0x0f
)
<<
4
);
return
x
;
}
/*
* zhenhua_process_packet() decodes packets the driver receives from the
* RC transmitter. It updates the data accordingly.
*/
static
void
zhenhua_process_packet
(
struct
zhenhua
*
zhenhua
)
{
struct
input_dev
*
dev
=
zhenhua
->
dev
;
unsigned
char
*
data
=
zhenhua
->
data
;
input_report_abs
(
dev
,
ABS_Y
,
data
[
1
]);
input_report_abs
(
dev
,
ABS_X
,
data
[
2
]);
input_report_abs
(
dev
,
ABS_RZ
,
data
[
3
]);
input_report_abs
(
dev
,
ABS_Z
,
data
[
4
]);
input_sync
(
dev
);
}
/*
* zhenhua_interrupt() is called by the low level driver when characters
* are ready for us. We then buffer them for further processing, or call the
* packet processing routine.
*/
static
irqreturn_t
zhenhua_interrupt
(
struct
serio
*
serio
,
unsigned
char
data
,
unsigned
int
flags
)
{
struct
zhenhua
*
zhenhua
=
serio_get_drvdata
(
serio
);
/* All Zhen Hua packets are 5 bytes. The fact that the first byte
* is allways 0xf7 and all others are in range 0x32 - 0xc8 (50-200)
* can be used to check and regain sync. */
if
(
data
==
0xef
)
zhenhua
->
idx
=
0
;
/* this byte starts a new packet */
else
if
(
zhenhua
->
idx
==
0
)
return
IRQ_HANDLED
;
/* wrong MSB -- ignore this byte */
if
(
zhenhua
->
idx
<
ZHENHUA_MAX_LENGTH
)
zhenhua
->
data
[
zhenhua
->
idx
++
]
=
zhenhua_bitreverse
(
data
);
if
(
zhenhua
->
idx
==
ZHENHUA_MAX_LENGTH
)
{
zhenhua_process_packet
(
zhenhua
);
zhenhua
->
idx
=
0
;
}
return
IRQ_HANDLED
;
}
/*
* zhenhua_disconnect() is the opposite of zhenhua_connect()
*/
static
void
zhenhua_disconnect
(
struct
serio
*
serio
)
{
struct
zhenhua
*
zhenhua
=
serio_get_drvdata
(
serio
);
serio_close
(
serio
);
serio_set_drvdata
(
serio
,
NULL
);
input_unregister_device
(
zhenhua
->
dev
);
kfree
(
zhenhua
);
}
/*
* zhenhua_connect() is the routine that is called when someone adds a
* new serio device. It looks for the Twiddler, and if found, registers
* it as an input device.
*/
static
int
zhenhua_connect
(
struct
serio
*
serio
,
struct
serio_driver
*
drv
)
{
struct
zhenhua
*
zhenhua
;
struct
input_dev
*
input_dev
;
int
err
=
-
ENOMEM
;
zhenhua
=
kzalloc
(
sizeof
(
struct
zhenhua
),
GFP_KERNEL
);
input_dev
=
input_allocate_device
();
if
(
!
zhenhua
||
!
input_dev
)
goto
fail1
;
zhenhua
->
dev
=
input_dev
;
snprintf
(
zhenhua
->
phys
,
sizeof
(
zhenhua
->
phys
),
"%s/input0"
,
serio
->
phys
);
input_dev
->
name
=
"Zhen Hua 5-byte device"
;
input_dev
->
phys
=
zhenhua
->
phys
;
input_dev
->
id
.
bustype
=
BUS_RS232
;
input_dev
->
id
.
vendor
=
SERIO_ZHENHUA
;
input_dev
->
id
.
product
=
0x0001
;
input_dev
->
id
.
version
=
0x0100
;
input_dev
->
dev
.
parent
=
&
serio
->
dev
;
input_dev
->
evbit
[
0
]
=
BIT
(
EV_ABS
);
input_set_abs_params
(
input_dev
,
ABS_X
,
50
,
200
,
0
,
0
);
input_set_abs_params
(
input_dev
,
ABS_Y
,
50
,
200
,
0
,
0
);
input_set_abs_params
(
input_dev
,
ABS_Z
,
50
,
200
,
0
,
0
);
input_set_abs_params
(
input_dev
,
ABS_RZ
,
50
,
200
,
0
,
0
);
serio_set_drvdata
(
serio
,
zhenhua
);
err
=
serio_open
(
serio
,
drv
);
if
(
err
)
goto
fail2
;
err
=
input_register_device
(
zhenhua
->
dev
);
if
(
err
)
goto
fail3
;
return
0
;
fail3:
serio_close
(
serio
);
fail2:
serio_set_drvdata
(
serio
,
NULL
);
fail1:
input_free_device
(
input_dev
);
kfree
(
zhenhua
);
return
err
;
}
/*
* The serio driver structure.
*/
static
struct
serio_device_id
zhenhua_serio_ids
[]
=
{
{
.
type
=
SERIO_RS232
,
.
proto
=
SERIO_ZHENHUA
,
.
id
=
SERIO_ANY
,
.
extra
=
SERIO_ANY
,
},
{
0
}
};
MODULE_DEVICE_TABLE
(
serio
,
zhenhua_serio_ids
);
static
struct
serio_driver
zhenhua_drv
=
{
.
driver
=
{
.
name
=
"zhenhua"
,
},
.
description
=
DRIVER_DESC
,
.
id_table
=
zhenhua_serio_ids
,
.
interrupt
=
zhenhua_interrupt
,
.
connect
=
zhenhua_connect
,
.
disconnect
=
zhenhua_disconnect
,
};
/*
* The functions for inserting/removing us as a module.
*/
static
int
__init
zhenhua_init
(
void
)
{
return
serio_register_driver
(
&
zhenhua_drv
);
}
static
void
__exit
zhenhua_exit
(
void
)
{
serio_unregister_driver
(
&
zhenhua_drv
);
}
module_init
(
zhenhua_init
);
module_exit
(
zhenhua_exit
);
drivers/input/keyboard/aaed2000_kbd.c
View file @
308f0a58
...
...
@@ -156,11 +156,15 @@ static int __devexit aaedkbd_remove(struct platform_device *pdev)
return
0
;
}
/* work with hotplug and coldplug */
MODULE_ALIAS
(
"platform:aaed2000-keyboard"
);
static
struct
platform_driver
aaedkbd_driver
=
{
.
probe
=
aaedkbd_probe
,
.
remove
=
__devexit_p
(
aaedkbd_remove
),
.
driver
=
{
.
name
=
"aaed2000-keyboard"
,
.
owner
=
THIS_MODULE
,
},
};
...
...
drivers/input/keyboard/bf54x-keys.c
View file @
308f0a58
...
...
@@ -312,6 +312,8 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
bfin_write_KPAD_CTL
(
bfin_read_KPAD_CTL
()
|
KPAD_EN
);
device_init_wakeup
(
&
pdev
->
dev
,
1
);
printk
(
KERN_ERR
DRV_NAME
": Blackfin BF54x Keypad registered IRQ %d
\n
"
,
bf54x_kpad
->
irq
);
...
...
@@ -354,12 +356,40 @@ static int __devexit bfin_kpad_remove(struct platform_device *pdev)
return
0
;
}
#ifdef CONFIG_PM
static
int
bfin_kpad_suspend
(
struct
platform_device
*
pdev
,
pm_message_t
state
)
{
struct
bf54x_kpad
*
bf54x_kpad
=
platform_get_drvdata
(
pdev
);
if
(
device_may_wakeup
(
&
pdev
->
dev
))
enable_irq_wake
(
bf54x_kpad
->
irq
);
return
0
;
}
static
int
bfin_kpad_resume
(
struct
platform_device
*
pdev
)
{
struct
bf54x_kpad
*
bf54x_kpad
=
platform_get_drvdata
(
pdev
);
if
(
device_may_wakeup
(
&
pdev
->
dev
))
disable_irq_wake
(
bf54x_kpad
->
irq
);
return
0
;
}
#else
# define bfin_kpad_suspend NULL
# define bfin_kpad_resume NULL
#endif
struct
platform_driver
bfin_kpad_device_driver
=
{
.
probe
=
bfin_kpad_probe
,
.
remove
=
__devexit_p
(
bfin_kpad_remove
),
.
driver
=
{
.
name
=
DRV_NAME
,
}
.
owner
=
THIS_MODULE
,
},
.
probe
=
bfin_kpad_probe
,
.
remove
=
__devexit_p
(
bfin_kpad_remove
),
.
suspend
=
bfin_kpad_suspend
,
.
resume
=
bfin_kpad_resume
,
};
static
int
__init
bfin_kpad_init
(
void
)
...
...
@@ -378,3 +408,4 @@ module_exit(bfin_kpad_exit);
MODULE_LICENSE
(
"GPL"
);
MODULE_AUTHOR
(
"Michael Hennerich <hennerich@blackfin.uclinux.org>"
);
MODULE_DESCRIPTION
(
"Keypad driver for BF54x Processors"
);
MODULE_ALIAS
(
"platform:bf54x-keys"
);
drivers/input/keyboard/corgikbd.c
View file @
308f0a58
...
...
@@ -392,6 +392,7 @@ static struct platform_driver corgikbd_driver = {
.
resume
=
corgikbd_resume
,
.
driver
=
{
.
name
=
"corgi-keyboard"
,
.
owner
=
THIS_MODULE
,
},
};
...
...
@@ -411,3 +412,4 @@ module_exit(corgikbd_exit);
MODULE_AUTHOR
(
"Richard Purdie <rpurdie@rpsys.net>"
);
MODULE_DESCRIPTION
(
"Corgi Keyboard Driver"
);
MODULE_LICENSE
(
"GPLv2"
);
MODULE_ALIAS
(
"platform:corgi-keyboard"
);
drivers/input/keyboard/gpio_keys.c
View file @
308f0a58
...
...
@@ -43,10 +43,11 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
input_event
(
input
,
type
,
button
->
code
,
!!
state
);
input_sync
(
input
);
return
IRQ_HANDLED
;
}
}
return
IRQ_
HANDLED
;
return
IRQ_
NONE
;
}
static
int
__devinit
gpio_keys_probe
(
struct
platform_device
*
pdev
)
...
...
@@ -213,6 +214,7 @@ struct platform_driver gpio_keys_device_driver = {
.
resume
=
gpio_keys_resume
,
.
driver
=
{
.
name
=
"gpio-keys"
,
.
owner
=
THIS_MODULE
,
}
};
...
...
@@ -232,3 +234,4 @@ module_exit(gpio_keys_exit);
MODULE_LICENSE
(
"GPL"
);
MODULE_AUTHOR
(
"Phil Blundell <pb@handhelds.org>"
);
MODULE_DESCRIPTION
(
"Keyboard driver for CPU GPIOs"
);
MODULE_ALIAS
(
"platform:gpio-keys"
);
drivers/input/keyboard/jornada680_kbd.c
View file @
308f0a58
...
...
@@ -254,6 +254,7 @@ static int __devexit jornada680kbd_remove(struct platform_device *pdev)
static
struct
platform_driver
jornada680kbd_driver
=
{
.
driver
=
{
.
name
=
"jornada680_kbd"
,
.
owner
=
THIS_MODULE
,
},
.
probe
=
jornada680kbd_probe
,
.
remove
=
__devexit_p
(
jornada680kbd_remove
),
...
...
@@ -275,3 +276,4 @@ module_exit(jornada680kbd_exit);
MODULE_AUTHOR
(
"Kristoffer Ericson <kristoffer.ericson@gmail.com>"
);
MODULE_DESCRIPTION
(
"HP Jornada 620/660/680/690 Keyboard Driver"
);
MODULE_LICENSE
(
"GPLv2"
);
MODULE_ALIAS
(
"platform:jornada680_kbd"
);
drivers/input/keyboard/jornada720_kbd.c
View file @
308f0a58
...
...
@@ -162,9 +162,13 @@ static int __devexit jornada720_kbd_remove(struct platform_device *pdev)
return
0
;
}
/* work with hotplug and coldplug */
MODULE_ALIAS
(
"platform:jornada720_kbd"
);
static
struct
platform_driver
jornada720_kbd_driver
=
{
.
driver
=
{
.
name
=
"jornada720_kbd"
,
.
owner
=
THIS_MODULE
,
},
.
probe
=
jornada720_kbd_probe
,
.
remove
=
__devexit_p
(
jornada720_kbd_remove
),
...
...
drivers/input/keyboard/locomokbd.c
View file @
308f0a58
/*
* Copyright (c) 2005 John Lenz
* LoCoMo keyboard driver for Linux-based ARM PDAs:
* - SHARP Zaurus Collie (SL-5500)
* - SHARP Zaurus Poodle (SL-5600)
*
* Copyright (c) 2005 John Lenz
* Based on from xtkbd.c
*/
/*
* LoCoMo keyboard driver for Linux/ARM
*/
/*
*
*
* 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
...
...
@@ -47,7 +45,8 @@ MODULE_LICENSE("GPL");
#define KEY_CONTACT KEY_F18
#define KEY_CENTER KEY_F15
static
unsigned
char
locomokbd_keycode
[
LOCOMOKBD_NUMKEYS
]
=
{
static
const
unsigned
char
locomokbd_keycode
[
LOCOMOKBD_NUMKEYS
]
__devinitconst
=
{
0
,
KEY_ESC
,
KEY_ACTIVITY
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
/* 0 - 9 */
0
,
0
,
0
,
0
,
0
,
0
,
0
,
KEY_MENU
,
KEY_HOME
,
KEY_CONTACT
,
/* 10 - 19 */
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
/* 20 - 29 */
...
...
@@ -67,22 +66,21 @@ static unsigned char locomokbd_keycode[LOCOMOKBD_NUMKEYS] = {
#define KB_COLS 8
#define KB_ROWMASK(r) (1 << (r))
#define SCANCODE(c,r) ( ((c)<<4) + (r) + 1 )
#define NR_SCANCODES 128
#define KB_DELAY 8
#define SCAN_INTERVAL (HZ/10)
#define LOCOMOKBD_PRESSED 1
struct
locomokbd
{
unsigned
char
keycode
[
LOCOMOKBD_NUMKEYS
];
struct
input_dev
*
input
;
char
phys
[
32
];
struct
locomo_dev
*
ldev
;
unsigned
long
base
;
spinlock_t
lock
;
struct
timer_list
timer
;
unsigned
long
suspend_jiffies
;
unsigned
int
count_cancel
;
};
/* helper functions for reading the keyboard matrix */
...
...
@@ -128,7 +126,7 @@ static inline void locomokbd_reset_col(unsigned long membase, int col)
/* Scan the hardware keyboard and push any changes up through the input layer */
static
void
locomokbd_scankeyboard
(
struct
locomokbd
*
locomokbd
)
{
unsigned
int
row
,
col
,
rowd
,
scancode
;
unsigned
int
row
,
col
,
rowd
;
unsigned
long
flags
;
unsigned
int
num_pressed
;
unsigned
long
membase
=
locomokbd
->
base
;
...
...
@@ -145,13 +143,33 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd)
rowd
=
~
locomo_readl
(
membase
+
LOCOMO_KIB
);
for
(
row
=
0
;
row
<
KB_ROWS
;
row
++
)
{
unsigned
int
scancode
,
pressed
,
key
;
scancode
=
SCANCODE
(
col
,
row
);
if
(
rowd
&
KB_ROWMASK
(
row
))
{
num_pressed
+=
1
;
input_report_key
(
locomokbd
->
input
,
locomokbd
->
keycode
[
scancode
],
1
);
}
else
{
input_report_key
(
locomokbd
->
input
,
locomokbd
->
keycode
[
scancode
],
0
);
}
pressed
=
rowd
&
KB_ROWMASK
(
row
);
key
=
locomokbd
->
keycode
[
scancode
];
input_report_key
(
locomokbd
->
input
,
key
,
pressed
);
if
(
likely
(
!
pressed
))
continue
;
num_pressed
++
;
/* The "Cancel/ESC" key is labeled "On/Off" on
* Collie and Poodle and should suspend the device
* if it was pressed for more than a second. */
if
(
unlikely
(
key
==
KEY_ESC
))
{
if
(
!
time_after
(
jiffies
,
locomokbd
->
suspend_jiffies
+
HZ
))
continue
;
if
(
locomokbd
->
count_cancel
++
!=
(
HZ
/
SCAN_INTERVAL
+
1
))
continue
;
input_event
(
locomokbd
->
input
,
EV_PWR
,
KEY_SUSPEND
,
1
);
locomokbd
->
suspend_jiffies
=
jiffies
;
}
else
locomokbd
->
count_cancel
=
0
;
}
locomokbd_reset_col
(
membase
,
col
);
}
...
...
@@ -162,6 +180,8 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd)
/* if any keys are pressed, enable the timer */
if
(
num_pressed
)
mod_timer
(
&
locomokbd
->
timer
,
jiffies
+
SCAN_INTERVAL
);
else
locomokbd
->
count_cancel
=
0
;
spin_unlock_irqrestore
(
&
locomokbd
->
lock
,
flags
);
}
...
...
@@ -186,10 +206,11 @@ static irqreturn_t locomokbd_interrupt(int irq, void *dev_id)
static
void
locomokbd_timer_callback
(
unsigned
long
data
)
{
struct
locomokbd
*
locomokbd
=
(
struct
locomokbd
*
)
data
;
locomokbd_scankeyboard
(
locomokbd
);
}
static
int
locomokbd_probe
(
struct
locomo_dev
*
dev
)
static
int
__devinit
locomokbd_probe
(
struct
locomo_dev
*
dev
)
{
struct
locomokbd
*
locomokbd
;
struct
input_dev
*
input_dev
;
...
...
@@ -211,7 +232,6 @@ static int locomokbd_probe(struct locomo_dev *dev)
goto
err_free_mem
;
}
locomokbd
->
ldev
=
dev
;
locomo_set_drvdata
(
dev
,
locomokbd
);
locomokbd
->
base
=
(
unsigned
long
)
dev
->
mapbase
;
...
...
@@ -222,6 +242,8 @@ static int locomokbd_probe(struct locomo_dev *dev)
locomokbd
->
timer
.
function
=
locomokbd_timer_callback
;
locomokbd
->
timer
.
data
=
(
unsigned
long
)
locomokbd
;
locomokbd
->
suspend_jiffies
=
jiffies
;
locomokbd
->
input
=
input_dev
;
strcpy
(
locomokbd
->
phys
,
"locomokbd/input0"
);
...
...
@@ -233,9 +255,10 @@ static int locomokbd_probe(struct locomo_dev *dev)
input_dev
->
id
.
version
=
0x0100
;
input_dev
->
dev
.
parent
=
&
dev
->
dev
;
input_dev
->
evbit
[
0
]
=
BIT_MASK
(
EV_KEY
)
|
BIT_MASK
(
EV_REP
);
input_dev
->
evbit
[
0
]
=
BIT_MASK
(
EV_KEY
)
|
BIT_MASK
(
EV_REP
)
|
BIT_MASK
(
EV_PWR
);
input_dev
->
keycode
=
locomokbd
->
keycode
;
input_dev
->
keycodesize
=
sizeof
(
unsigned
char
);
input_dev
->
keycodesize
=
sizeof
(
locomokbd_keycode
[
0
]
);
input_dev
->
keycodemax
=
ARRAY_SIZE
(
locomokbd_keycode
);
memcpy
(
locomokbd
->
keycode
,
locomokbd_keycode
,
sizeof
(
locomokbd
->
keycode
));
...
...
@@ -268,7 +291,7 @@ static int locomokbd_probe(struct locomo_dev *dev)
return
err
;
}
static
int
locomokbd_remove
(
struct
locomo_dev
*
dev
)
static
int
__devexit
locomokbd_remove
(
struct
locomo_dev
*
dev
)
{
struct
locomokbd
*
locomokbd
=
locomo_get_drvdata
(
dev
);
...
...
@@ -292,7 +315,7 @@ static struct locomo_driver keyboard_driver = {
},
.
devid
=
LOCOMO_DEVID_KEYBOARD
,
.
probe
=
locomokbd_probe
,
.
remove
=
locomokbd_remove
,
.
remove
=
__devexit_p
(
locomokbd_remove
)
,
};
static
int
__init
locomokbd_init
(
void
)
...
...
drivers/input/keyboard/omap-keypad.c
View file @
308f0a58
...
...
@@ -352,6 +352,9 @@ static int __init omap_kp_probe(struct platform_device *pdev)
}
omap_set_gpio_direction
(
row_gpios
[
row_idx
],
1
);
}
}
else
{
col_idx
=
0
;
row_idx
=
0
;
}
setup_timer
(
&
omap_kp
->
timer
,
omap_kp_timer
,
(
unsigned
long
)
omap_kp
);
...
...
@@ -415,10 +418,10 @@ static int __init omap_kp_probe(struct platform_device *pdev)
err3:
device_remove_file
(
&
pdev
->
dev
,
&
dev_attr_enable
);
err2:
for
(
i
=
row_idx
-
1
;
i
>=
0
;
i
--
)
for
(
i
=
row_idx
-
1
;
i
>=
0
;
i
--
)
omap_free_gpio
(
row_gpios
[
i
]);
err1:
for
(
i
=
col_idx
-
1
;
i
>=
0
;
i
--
)
for
(
i
=
col_idx
-
1
;
i
>=
0
;
i
--
)
omap_free_gpio
(
col_gpios
[
i
]);
kfree
(
omap_kp
);
...
...
@@ -464,6 +467,7 @@ static struct platform_driver omap_kp_driver = {
.
resume
=
omap_kp_resume
,
.
driver
=
{
.
name
=
"omap-keypad"
,
.
owner
=
THIS_MODULE
,
},
};
...
...
@@ -484,3 +488,4 @@ module_exit(omap_kp_exit);
MODULE_AUTHOR
(
"Timo Teräs"
);
MODULE_DESCRIPTION
(
"OMAP Keypad Driver"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_ALIAS
(
"platform:omap-keypad"
);
drivers/input/keyboard/pxa27x_keypad.c
View file @
308f0a58
...
...
@@ -545,6 +545,9 @@ static int __devexit pxa27x_keypad_remove(struct platform_device *pdev)
return
0
;
}
/* work with hotplug and coldplug */
MODULE_ALIAS
(
"platform:pxa27x-keypad"
);
static
struct
platform_driver
pxa27x_keypad_driver
=
{
.
probe
=
pxa27x_keypad_probe
,
.
remove
=
__devexit_p
(
pxa27x_keypad_remove
),
...
...
@@ -552,6 +555,7 @@ static struct platform_driver pxa27x_keypad_driver = {
.
resume
=
pxa27x_keypad_resume
,
.
driver
=
{
.
name
=
"pxa27x-keypad"
,
.
owner
=
THIS_MODULE
,
},
};
...
...
drivers/input/keyboard/spitzkbd.c
View file @
308f0a58
...
...
@@ -494,3 +494,4 @@ module_exit(spitzkbd_exit);
MODULE_AUTHOR
(
"Richard Purdie <rpurdie@rpsys.net>"
);
MODULE_DESCRIPTION
(
"Spitz Keyboard Driver"
);
MODULE_LICENSE
(
"GPLv2"
);
MODULE_ALIAS
(
"platform:spitz-keyboard"
);
drivers/input/keyboard/tosakbd.c
View file @
308f0a58
...
...
@@ -52,7 +52,7 @@ KEY_X, KEY_F, KEY_SPACE, KEY_APOSTROPHE, TOSA_KEY_MAIL, KEY_LEFT, KEY_DOWN, KEY_
struct
tosakbd
{
unsigned
int
keycode
[
ARRAY_SIZE
(
tosakbd_keycode
)];
struct
input_dev
*
input
;
int
suspended
;
spinlock_t
lock
;
/* protect kbd scanning */
struct
timer_list
timer
;
};
...
...
@@ -133,6 +133,9 @@ static void tosakbd_scankeyboard(struct platform_device *dev)
spin_lock_irqsave
(
&
tosakbd
->
lock
,
flags
);
if
(
tosakbd
->
suspended
)
goto
out
;
for
(
col
=
0
;
col
<
TOSA_KEY_STROBE_NUM
;
col
++
)
{
/*
* Discharge the output driver capacitatance
...
...
@@ -174,6 +177,7 @@ static void tosakbd_scankeyboard(struct platform_device *dev)
if
(
num_pressed
)
mod_timer
(
&
tosakbd
->
timer
,
jiffies
+
SCAN_INTERVAL
);
out:
spin_unlock_irqrestore
(
&
tosakbd
->
lock
,
flags
);
}
...
...
@@ -200,6 +204,7 @@ static irqreturn_t tosakbd_interrupt(int irq, void *__dev)
static
void
tosakbd_timer_callback
(
unsigned
long
__dev
)
{
struct
platform_device
*
dev
=
(
struct
platform_device
*
)
__dev
;
tosakbd_scankeyboard
(
dev
);
}
...
...
@@ -207,6 +212,13 @@ static void tosakbd_timer_callback(unsigned long __dev)
static
int
tosakbd_suspend
(
struct
platform_device
*
dev
,
pm_message_t
state
)
{
struct
tosakbd
*
tosakbd
=
platform_get_drvdata
(
dev
);
unsigned
long
flags
;
spin_lock_irqsave
(
&
tosakbd
->
lock
,
flags
);
PGSR1
=
(
PGSR1
&
~
TOSA_GPIO_LOW_STROBE_BIT
);
PGSR2
=
(
PGSR2
&
~
TOSA_GPIO_HIGH_STROBE_BIT
);
tosakbd
->
suspended
=
1
;
spin_unlock_irqrestore
(
&
tosakbd
->
lock
,
flags
);
del_timer_sync
(
&
tosakbd
->
timer
);
...
...
@@ -215,6 +227,9 @@ static int tosakbd_suspend(struct platform_device *dev, pm_message_t state)
static
int
tosakbd_resume
(
struct
platform_device
*
dev
)
{
struct
tosakbd
*
tosakbd
=
platform_get_drvdata
(
dev
);
tosakbd
->
suspended
=
0
;
tosakbd_scankeyboard
(
dev
);
return
0
;
...
...
@@ -365,8 +380,8 @@ static int __devinit tosakbd_probe(struct platform_device *pdev) {
return
error
;
}
static
int
__devexit
tosakbd_remove
(
struct
platform_device
*
dev
)
{
static
int
__devexit
tosakbd_remove
(
struct
platform_device
*
dev
)
{
int
i
;
struct
tosakbd
*
tosakbd
=
platform_get_drvdata
(
dev
);
...
...
@@ -394,6 +409,7 @@ static struct platform_driver tosakbd_driver = {
.
resume
=
tosakbd_resume
,
.
driver
=
{
.
name
=
"tosa-keyboard"
,
.
owner
=
THIS_MODULE
,
},
};
...
...
@@ -413,3 +429,4 @@ module_exit(tosakbd_exit);
MODULE_AUTHOR
(
"Dirk Opfer <Dirk@Opfer-Online.de>"
);
MODULE_DESCRIPTION
(
"Tosa Keyboard Driver"
);
MODULE_LICENSE
(
"GPL v2"
);
MODULE_ALIAS
(
"platform:tosa-keyboard"
);
drivers/input/misc/cobalt_btns.c
View file @
308f0a58
...
...
@@ -148,6 +148,9 @@ static int __devexit cobalt_buttons_remove(struct platform_device *pdev)
return
0
;
}
/* work with hotplug and coldplug */
MODULE_ALIAS
(
"platform:Cobalt buttons"
);
static
struct
platform_driver
cobalt_buttons_driver
=
{
.
probe
=
cobalt_buttons_probe
,
.
remove
=
__devexit_p
(
cobalt_buttons_remove
),
...
...
drivers/input/mouse/gpio_mouse.c
View file @
308f0a58
...
...
@@ -171,10 +171,14 @@ static int __devexit gpio_mouse_remove(struct platform_device *pdev)
return
0
;
}
/* work with hotplug and coldplug */
MODULE_ALIAS
(
"platform:gpio_mouse"
);
struct
platform_driver
gpio_mouse_device_driver
=
{
.
remove
=
__devexit_p
(
gpio_mouse_remove
),
.
driver
=
{
.
name
=
"gpio_mouse"
,
.
owner
=
THIS_MODULE
,
}
};
...
...
drivers/input/serio/Kconfig
View file @
308f0a58
...
...
@@ -88,6 +88,16 @@ config SERIO_RPCKBD
To compile this driver as a module, choose M here: the
module will be called rpckbd.
config SERIO_AT32PSIF
tristate "AVR32 PSIF PS/2 keyboard and mouse controller"
depends on AVR32
help
Say Y here if you want to use the PSIF peripheral on AVR32 devices
and connect a PS/2 keyboard and/or mouse to it.
To compile this driver as a module, choose M here: the module will
be called at32psif.
config SERIO_AMBAKMI
tristate "AMBA KMI keyboard controller"
depends on ARM_AMBA
...
...
drivers/input/serio/Makefile
View file @
308f0a58
...
...
@@ -12,6 +12,7 @@ obj-$(CONFIG_SERIO_CT82C710) += ct82c710.o
obj-$(CONFIG_SERIO_RPCKBD)
+=
rpckbd.o
obj-$(CONFIG_SERIO_SA1111)
+=
sa1111ps2.o
obj-$(CONFIG_SERIO_AMBAKMI)
+=
ambakmi.o
obj-$(CONFIG_SERIO_AT32PSIF)
+=
at32psif.o
obj-$(CONFIG_SERIO_Q40KBD)
+=
q40kbd.o
obj-$(CONFIG_SERIO_GSCPS2)
+=
gscps2.o
obj-$(CONFIG_HP_SDC)
+=
hp_sdc.o
...
...
drivers/input/serio/at32psif.c
0 → 100644
View file @
308f0a58
/*
* Copyright (C) 2007 Atmel Corporation
*
* Driver for the AT32AP700X PS/2 controller (PSIF).
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
/* PSIF register offsets */
#define PSIF_CR 0x00
#define PSIF_RHR 0x04
#define PSIF_THR 0x08
#define PSIF_SR 0x10
#define PSIF_IER 0x14
#define PSIF_IDR 0x18
#define PSIF_IMR 0x1c
#define PSIF_PSR 0x24
/* Bitfields in control register. */
#define PSIF_CR_RXDIS_OFFSET 1
#define PSIF_CR_RXDIS_SIZE 1
#define PSIF_CR_RXEN_OFFSET 0
#define PSIF_CR_RXEN_SIZE 1
#define PSIF_CR_SWRST_OFFSET 15
#define PSIF_CR_SWRST_SIZE 1
#define PSIF_CR_TXDIS_OFFSET 9
#define PSIF_CR_TXDIS_SIZE 1
#define PSIF_CR_TXEN_OFFSET 8
#define PSIF_CR_TXEN_SIZE 1
/* Bitfields in interrupt disable, enable, mask and status register. */
#define PSIF_NACK_OFFSET 8
#define PSIF_NACK_SIZE 1
#define PSIF_OVRUN_OFFSET 5
#define PSIF_OVRUN_SIZE 1
#define PSIF_PARITY_OFFSET 9
#define PSIF_PARITY_SIZE 1
#define PSIF_RXRDY_OFFSET 4
#define PSIF_RXRDY_SIZE 1
#define PSIF_TXEMPTY_OFFSET 1
#define PSIF_TXEMPTY_SIZE 1
#define PSIF_TXRDY_OFFSET 0
#define PSIF_TXRDY_SIZE 1
/* Bitfields in prescale register. */
#define PSIF_PSR_PRSCV_OFFSET 0
#define PSIF_PSR_PRSCV_SIZE 12
/* Bitfields in receive hold register. */
#define PSIF_RHR_RXDATA_OFFSET 0
#define PSIF_RHR_RXDATA_SIZE 8
/* Bitfields in transmit hold register. */
#define PSIF_THR_TXDATA_OFFSET 0
#define PSIF_THR_TXDATA_SIZE 8
/* Bit manipulation macros */
#define PSIF_BIT(name) \
(1 << PSIF_##name##_OFFSET)
#define PSIF_BF(name, value) \
(((value) & ((1 << PSIF_##name##_SIZE) - 1)) \
<< PSIF_##name##_OFFSET)
#define PSIF_BFEXT(name, value) \
(((value) >> PSIF_##name##_OFFSET) \
& ((1 << PSIF_##name##_SIZE) - 1))
#define PSIF_BFINS(name, value, old) \
(((old) & ~(((1 << PSIF_##name##_SIZE) - 1) \
<< PSIF_##name##_OFFSET)) \
| PSIF_BF(name, value))
/* Register access macros */
#define psif_readl(port, reg) \
__raw_readl((port)->regs + PSIF_##reg)
#define psif_writel(port, reg, value) \
__raw_writel((value), (port)->regs + PSIF_##reg)
struct
psif
{
struct
platform_device
*
pdev
;
struct
clk
*
pclk
;
struct
serio
*
io
;
void
__iomem
*
regs
;
unsigned
int
irq
;
unsigned
int
open
;
/* Prevent concurrent writes to PSIF THR. */
spinlock_t
lock
;
};
static
irqreturn_t
psif_interrupt
(
int
irq
,
void
*
_ptr
)
{
struct
psif
*
psif
=
_ptr
;
int
retval
=
IRQ_NONE
;
unsigned
int
io_flags
=
0
;
unsigned
long
status
;
status
=
psif_readl
(
psif
,
SR
);
if
(
status
&
PSIF_BIT
(
RXRDY
))
{
unsigned
char
val
=
(
unsigned
char
)
psif_readl
(
psif
,
RHR
);
if
(
status
&
PSIF_BIT
(
PARITY
))
io_flags
|=
SERIO_PARITY
;
if
(
status
&
PSIF_BIT
(
OVRUN
))
dev_err
(
&
psif
->
pdev
->
dev
,
"overrun read error
\n
"
);
serio_interrupt
(
psif
->
io
,
val
,
io_flags
);
retval
=
IRQ_HANDLED
;
}
return
retval
;
}
static
int
psif_write
(
struct
serio
*
io
,
unsigned
char
val
)
{
struct
psif
*
psif
=
io
->
port_data
;
unsigned
long
flags
;
int
timeout
=
10
;
int
retval
=
0
;
spin_lock_irqsave
(
&
psif
->
lock
,
flags
);
while
(
!
(
psif_readl
(
psif
,
SR
)
&
PSIF_BIT
(
TXEMPTY
))
&&
timeout
--
)
msleep
(
10
);
if
(
timeout
>=
0
)
{
psif_writel
(
psif
,
THR
,
val
);
}
else
{
dev_dbg
(
&
psif
->
pdev
->
dev
,
"timeout writing to THR
\n
"
);
retval
=
-
EBUSY
;
}
spin_unlock_irqrestore
(
&
psif
->
lock
,
flags
);
return
retval
;
}
static
int
psif_open
(
struct
serio
*
io
)
{
struct
psif
*
psif
=
io
->
port_data
;
int
retval
;
retval
=
clk_enable
(
psif
->
pclk
);
if
(
retval
)
goto
out
;
psif_writel
(
psif
,
CR
,
PSIF_BIT
(
CR_TXEN
)
|
PSIF_BIT
(
CR_RXEN
));
psif_writel
(
psif
,
IER
,
PSIF_BIT
(
RXRDY
));
psif
->
open
=
1
;
out:
return
retval
;
}
static
void
psif_close
(
struct
serio
*
io
)
{
struct
psif
*
psif
=
io
->
port_data
;
psif
->
open
=
0
;
psif_writel
(
psif
,
IDR
,
~
0UL
);
psif_writel
(
psif
,
CR
,
PSIF_BIT
(
CR_TXDIS
)
|
PSIF_BIT
(
CR_RXDIS
));
clk_disable
(
psif
->
pclk
);
}
static
void
psif_set_prescaler
(
struct
psif
*
psif
)
{
unsigned
long
prscv
;
unsigned
long
rate
=
clk_get_rate
(
psif
->
pclk
);
/* PRSCV = Pulse length (100 us) * PSIF module frequency. */
prscv
=
100
*
(
rate
/
1000000UL
);
if
(
prscv
>
((
1
<<
PSIF_PSR_PRSCV_SIZE
)
-
1
))
{
prscv
=
(
1
<<
PSIF_PSR_PRSCV_SIZE
)
-
1
;
dev_dbg
(
&
psif
->
pdev
->
dev
,
"pclk too fast, "
"prescaler set to max
\n
"
);
}
clk_enable
(
psif
->
pclk
);
psif_writel
(
psif
,
PSR
,
prscv
);
clk_disable
(
psif
->
pclk
);
}
static
int
__init
psif_probe
(
struct
platform_device
*
pdev
)
{
struct
resource
*
regs
;
struct
psif
*
psif
;
struct
serio
*
io
;
struct
clk
*
pclk
;
int
irq
;
int
ret
;
psif
=
kzalloc
(
sizeof
(
struct
psif
),
GFP_KERNEL
);
if
(
!
psif
)
{
dev_dbg
(
&
pdev
->
dev
,
"out of memory
\n
"
);
ret
=
-
ENOMEM
;
goto
out
;
}
psif
->
pdev
=
pdev
;
io
=
kzalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
!
io
)
{
dev_dbg
(
&
pdev
->
dev
,
"out of memory
\n
"
);
ret
=
-
ENOMEM
;
goto
out_free_psif
;
}
psif
->
io
=
io
;
regs
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
if
(
!
regs
)
{
dev_dbg
(
&
pdev
->
dev
,
"no mmio resources defined
\n
"
);
ret
=
-
ENOMEM
;
goto
out_free_io
;
}
psif
->
regs
=
ioremap
(
regs
->
start
,
regs
->
end
-
regs
->
start
+
1
);
if
(
!
psif
->
regs
)
{
ret
=
-
ENOMEM
;
dev_dbg
(
&
pdev
->
dev
,
"could not map I/O memory
\n
"
);
goto
out_free_io
;
}
pclk
=
clk_get
(
&
pdev
->
dev
,
"pclk"
);
if
(
IS_ERR
(
pclk
))
{
dev_dbg
(
&
pdev
->
dev
,
"could not get peripheral clock
\n
"
);
ret
=
PTR_ERR
(
pclk
);
goto
out_iounmap
;
}
psif
->
pclk
=
pclk
;
/* Reset the PSIF to enter at a known state. */
ret
=
clk_enable
(
pclk
);
if
(
ret
)
{
dev_dbg
(
&
pdev
->
dev
,
"could not enable pclk
\n
"
);
goto
out_put_clk
;
}
psif_writel
(
psif
,
CR
,
PSIF_BIT
(
CR_SWRST
));
clk_disable
(
pclk
);
irq
=
platform_get_irq
(
pdev
,
0
);
if
(
irq
<
0
)
{
dev_dbg
(
&
pdev
->
dev
,
"could not get irq
\n
"
);
ret
=
-
ENXIO
;
goto
out_put_clk
;
}
ret
=
request_irq
(
irq
,
psif_interrupt
,
IRQF_SHARED
,
"at32psif"
,
psif
);
if
(
ret
)
{
dev_dbg
(
&
pdev
->
dev
,
"could not request irq %d
\n
"
,
irq
);
goto
out_put_clk
;
}
psif
->
irq
=
irq
;
io
->
id
.
type
=
SERIO_8042
;
io
->
write
=
psif_write
;
io
->
open
=
psif_open
;
io
->
close
=
psif_close
;
snprintf
(
io
->
name
,
sizeof
(
io
->
name
),
"AVR32 PS/2 port%d"
,
pdev
->
id
);
snprintf
(
io
->
phys
,
sizeof
(
io
->
phys
),
"at32psif/serio%d"
,
pdev
->
id
);
io
->
port_data
=
psif
;
io
->
dev
.
parent
=
&
pdev
->
dev
;
psif_set_prescaler
(
psif
);
spin_lock_init
(
&
psif
->
lock
);
serio_register_port
(
psif
->
io
);
platform_set_drvdata
(
pdev
,
psif
);
dev_info
(
&
pdev
->
dev
,
"Atmel AVR32 PSIF PS/2 driver on 0x%08x irq %d
\n
"
,
(
int
)
psif
->
regs
,
psif
->
irq
);
return
0
;
out_put_clk:
clk_put
(
psif
->
pclk
);
out_iounmap:
iounmap
(
psif
->
regs
);
out_free_io:
kfree
(
io
);
out_free_psif:
kfree
(
psif
);
out:
return
ret
;
}
static
int
__exit
psif_remove
(
struct
platform_device
*
pdev
)
{
struct
psif
*
psif
=
platform_get_drvdata
(
pdev
);
psif_writel
(
psif
,
IDR
,
~
0UL
);
psif_writel
(
psif
,
CR
,
PSIF_BIT
(
CR_TXDIS
)
|
PSIF_BIT
(
CR_RXDIS
));
serio_unregister_port
(
psif
->
io
);
iounmap
(
psif
->
regs
);
free_irq
(
psif
->
irq
,
psif
);
clk_put
(
psif
->
pclk
);
kfree
(
psif
);
platform_set_drvdata
(
pdev
,
NULL
);
return
0
;
}
#ifdef CONFIG_PM
static
int
psif_suspend
(
struct
platform_device
*
pdev
,
pm_message_t
state
)
{
struct
psif
*
psif
=
platform_get_drvdata
(
pdev
);
if
(
psif
->
open
)
{
psif_writel
(
psif
,
CR
,
PSIF_BIT
(
CR_RXDIS
)
|
PSIF_BIT
(
CR_TXDIS
));
clk_disable
(
psif
->
pclk
);
}
return
0
;
}
static
int
psif_resume
(
struct
platform_device
*
pdev
)
{
struct
psif
*
psif
=
platform_get_drvdata
(
pdev
);
if
(
psif
->
open
)
{
clk_enable
(
psif
->
pclk
);
psif_set_prescaler
(
psif
);
psif_writel
(
psif
,
CR
,
PSIF_BIT
(
CR_RXEN
)
|
PSIF_BIT
(
CR_TXEN
));
}
return
0
;
}
#else
#define psif_suspend NULL
#define psif_resume NULL
#endif
static
struct
platform_driver
psif_driver
=
{
.
remove
=
__exit_p
(
psif_remove
),
.
driver
=
{
.
name
=
"atmel_psif"
,
},
.
suspend
=
psif_suspend
,
.
resume
=
psif_resume
,
};
static
int
__init
psif_init
(
void
)
{
return
platform_driver_probe
(
&
psif_driver
,
psif_probe
);
}
static
void
__exit
psif_exit
(
void
)
{
platform_driver_unregister
(
&
psif_driver
);
}
module_init
(
psif_init
);
module_exit
(
psif_exit
);
MODULE_AUTHOR
(
"Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>"
);
MODULE_DESCRIPTION
(
"Atmel AVR32 PSIF PS/2 driver"
);
MODULE_LICENSE
(
"GPL"
);
drivers/input/serio/i8042-x86ia64io.h
View file @
308f0a58
...
...
@@ -370,10 +370,10 @@ static int i8042_pnp_kbd_probe(struct pnp_dev *dev, const struct pnp_device_id *
if
(
pnp_irq_valid
(
dev
,
0
))
i8042_pnp_kbd_irq
=
pnp_irq
(
dev
,
0
);
str
n
cpy
(
i8042_pnp_kbd_name
,
did
->
id
,
sizeof
(
i8042_pnp_kbd_name
));
str
l
cpy
(
i8042_pnp_kbd_name
,
did
->
id
,
sizeof
(
i8042_pnp_kbd_name
));
if
(
strlen
(
pnp_dev_name
(
dev
)))
{
str
n
cat
(
i8042_pnp_kbd_name
,
":"
,
sizeof
(
i8042_pnp_kbd_name
));
str
n
cat
(
i8042_pnp_kbd_name
,
pnp_dev_name
(
dev
),
sizeof
(
i8042_pnp_kbd_name
));
str
l
cat
(
i8042_pnp_kbd_name
,
":"
,
sizeof
(
i8042_pnp_kbd_name
));
str
l
cat
(
i8042_pnp_kbd_name
,
pnp_dev_name
(
dev
),
sizeof
(
i8042_pnp_kbd_name
));
}
i8042_pnp_kbd_devices
++
;
...
...
@@ -391,10 +391,10 @@ static int i8042_pnp_aux_probe(struct pnp_dev *dev, const struct pnp_device_id *
if
(
pnp_irq_valid
(
dev
,
0
))
i8042_pnp_aux_irq
=
pnp_irq
(
dev
,
0
);
str
n
cpy
(
i8042_pnp_aux_name
,
did
->
id
,
sizeof
(
i8042_pnp_aux_name
));
str
l
cpy
(
i8042_pnp_aux_name
,
did
->
id
,
sizeof
(
i8042_pnp_aux_name
));
if
(
strlen
(
pnp_dev_name
(
dev
)))
{
str
n
cat
(
i8042_pnp_aux_name
,
":"
,
sizeof
(
i8042_pnp_aux_name
));
str
n
cat
(
i8042_pnp_aux_name
,
pnp_dev_name
(
dev
),
sizeof
(
i8042_pnp_aux_name
));
str
l
cat
(
i8042_pnp_aux_name
,
":"
,
sizeof
(
i8042_pnp_aux_name
));
str
l
cat
(
i8042_pnp_aux_name
,
pnp_dev_name
(
dev
),
sizeof
(
i8042_pnp_aux_name
));
}
i8042_pnp_aux_devices
++
;
...
...
drivers/input/serio/rpckbd.c
View file @
308f0a58
...
...
@@ -45,6 +45,7 @@
MODULE_AUTHOR
(
"Vojtech Pavlik, Russell King"
);
MODULE_DESCRIPTION
(
"Acorn RiscPC PS/2 keyboard controller driver"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_ALIAS
(
"platform:kart"
);
static
int
rpckbd_write
(
struct
serio
*
port
,
unsigned
char
val
)
{
...
...
@@ -140,6 +141,7 @@ static struct platform_driver rpckbd_driver = {
.
remove
=
__devexit_p
(
rpckbd_remove
),
.
driver
=
{
.
name
=
"kart"
,
.
owner
=
THIS_MODULE
,
},
};
...
...
drivers/input/tablet/Kconfig
View file @
308f0a58
...
...
@@ -25,14 +25,14 @@ config TABLET_USB_ACECAD
module will be called acecad.
config TABLET_USB_AIPTEK
tristate "Aiptek 6000U/8000U tablet support (USB)"
tristate "Aiptek 6000U/8000U
and Genius G_PEN
tablet support (USB)"
depends on USB_ARCH_HAS_HCD
select USB
help
Say Y here if you want to use the USB version of the Aiptek 6000U
or Aiptek 8000U tablet. Make sure to say Y to "Mouse support"
(CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
(CONFIG_INPUT_EVDEV) as well.
Say Y here if you want to use the USB version of the Aiptek 6000U
,
Aiptek 8000U or Genius G-PEN 560 tablet. Make sure to say Y to
"Mouse support" (CONFIG_INPUT_MOUSEDEV) and/or "Event interface
support"
(CONFIG_INPUT_EVDEV) as well.
To compile this driver as a module, choose M here: the
module will be called aiptek.
...
...
drivers/input/tablet/aiptek.c
View file @
308f0a58
...
...
@@ -184,6 +184,7 @@
*/
#define USB_VENDOR_ID_AIPTEK 0x08ca
#define USB_VENDOR_ID_KYE 0x0458
#define USB_REQ_GET_REPORT 0x01
#define USB_REQ_SET_REPORT 0x09
...
...
@@ -832,6 +833,7 @@ static const struct usb_device_id aiptek_ids[] = {
{
USB_DEVICE
(
USB_VENDOR_ID_AIPTEK
,
0x22
)},
{
USB_DEVICE
(
USB_VENDOR_ID_AIPTEK
,
0x23
)},
{
USB_DEVICE
(
USB_VENDOR_ID_AIPTEK
,
0x24
)},
{
USB_DEVICE
(
USB_VENDOR_ID_KYE
,
0x5003
)},
{}
};
...
...
drivers/input/tablet/wacom.h
View file @
308f0a58
...
...
@@ -101,8 +101,11 @@ struct wacom {
dma_addr_t
data_dma
;
struct
input_dev
*
dev
;
struct
usb_device
*
usbdev
;
struct
usb_interface
*
intf
;
struct
urb
*
irq
;
struct
wacom_wac
*
wacom_wac
;
struct
mutex
lock
;
int
open
:
1
;
char
phys
[
32
];
};
...
...
drivers/input/tablet/wacom_sys.c
View file @
308f0a58
...
...
@@ -70,6 +70,7 @@ static void wacom_sys_irq(struct urb *urb)
input_sync
(
get_input_dev
(
&
wcombo
));
exit:
usb_mark_last_busy
(
wacom
->
usbdev
);
retval
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
if
(
retval
)
err
(
"%s - usb_submit_urb failed with result %d"
,
...
...
@@ -124,10 +125,25 @@ static int wacom_open(struct input_dev *dev)
{
struct
wacom
*
wacom
=
input_get_drvdata
(
dev
);
mutex_lock
(
&
wacom
->
lock
);
wacom
->
irq
->
dev
=
wacom
->
usbdev
;
if
(
usb_submit_urb
(
wacom
->
irq
,
GFP_KERNEL
))
if
(
usb_autopm_get_interface
(
wacom
->
intf
)
<
0
)
{
mutex_unlock
(
&
wacom
->
lock
);
return
-
EIO
;
}
if
(
usb_submit_urb
(
wacom
->
irq
,
GFP_KERNEL
))
{
usb_autopm_put_interface
(
wacom
->
intf
);
mutex_unlock
(
&
wacom
->
lock
);
return
-
EIO
;
}
wacom
->
open
=
1
;
wacom
->
intf
->
needs_remote_wakeup
=
1
;
mutex_unlock
(
&
wacom
->
lock
);
return
0
;
}
...
...
@@ -135,7 +151,11 @@ static void wacom_close(struct input_dev *dev)
{
struct
wacom
*
wacom
=
input_get_drvdata
(
dev
);
mutex_lock
(
&
wacom
->
lock
);
usb_kill_urb
(
wacom
->
irq
);
wacom
->
open
=
0
;
wacom
->
intf
->
needs_remote_wakeup
=
0
;
mutex_unlock
(
&
wacom
->
lock
);
}
void
input_dev_mo
(
struct
input_dev
*
input_dev
,
struct
wacom_wac
*
wacom_wac
)
...
...
@@ -243,6 +263,8 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
wacom
->
usbdev
=
dev
;
wacom
->
dev
=
input_dev
;
wacom
->
intf
=
intf
;
mutex_init
(
&
wacom
->
lock
);
usb_make_path
(
dev
,
wacom
->
phys
,
sizeof
(
wacom
->
phys
));
strlcat
(
wacom
->
phys
,
"/input0"
,
sizeof
(
wacom
->
phys
));
...
...
@@ -304,23 +326,57 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
static
void
wacom_disconnect
(
struct
usb_interface
*
intf
)
{
struct
wacom
*
wacom
=
usb_get_intfdata
(
intf
);
struct
wacom
*
wacom
=
usb_get_intfdata
(
intf
);
usb_set_intfdata
(
intf
,
NULL
);
if
(
wacom
)
{
usb_kill_urb
(
wacom
->
irq
);
input_unregister_device
(
wacom
->
dev
);
usb_free_urb
(
wacom
->
irq
);
usb_buffer_free
(
interface_to_usbdev
(
intf
),
10
,
wacom
->
wacom_wac
->
data
,
wacom
->
data_dma
);
kfree
(
wacom
->
wacom_wac
);
kfree
(
wacom
);
}
}
static
int
wacom_suspend
(
struct
usb_interface
*
intf
,
pm_message_t
message
)
{
struct
wacom
*
wacom
=
usb_get_intfdata
(
intf
);
mutex_lock
(
&
wacom
->
lock
);
usb_kill_urb
(
wacom
->
irq
);
mutex_unlock
(
&
wacom
->
lock
);
return
0
;
}
static
int
wacom_resume
(
struct
usb_interface
*
intf
)
{
struct
wacom
*
wacom
=
usb_get_intfdata
(
intf
);
int
rv
;
mutex_lock
(
&
wacom
->
lock
);
if
(
wacom
->
open
)
rv
=
usb_submit_urb
(
wacom
->
irq
,
GFP_NOIO
);
else
rv
=
0
;
mutex_unlock
(
&
wacom
->
lock
);
return
rv
;
}
static
int
wacom_reset_resume
(
struct
usb_interface
*
intf
)
{
return
wacom_resume
(
intf
);
}
static
struct
usb_driver
wacom_driver
=
{
.
name
=
"wacom"
,
.
probe
=
wacom_probe
,
.
disconnect
=
wacom_disconnect
,
.
suspend
=
wacom_suspend
,
.
resume
=
wacom_resume
,
.
reset_resume
=
wacom_reset_resume
,
.
supports_autosuspend
=
1
,
};
static
int
__init
wacom_init
(
void
)
...
...
drivers/input/tablet/wacom_wac.c
View file @
308f0a58
...
...
@@ -649,6 +649,7 @@ static struct wacom_features wacom_features[] = {
{
"Wacom Intuos3 6x11"
,
10
,
54204
,
31750
,
1023
,
63
,
INTUOS3
},
{
"Wacom Intuos3 4x6"
,
10
,
31496
,
19685
,
1023
,
63
,
INTUOS3S
},
{
"Wacom Cintiq 21UX"
,
10
,
87200
,
65600
,
1023
,
63
,
CINTIQ
},
{
"Wacom Cintiq 20WSX"
,
10
,
86680
,
54180
,
1023
,
63
,
WACOM_BEE
},
{
"Wacom Cintiq 12WX"
,
10
,
53020
,
33440
,
1023
,
63
,
WACOM_BEE
},
{
"Wacom Intuos2 6x8"
,
10
,
20320
,
16240
,
1023
,
31
,
INTUOS
},
{
}
...
...
@@ -702,6 +703,7 @@ static struct usb_device_id wacom_ids[] = {
{
USB_DEVICE
(
USB_VENDOR_ID_WACOM
,
0xB5
)
},
{
USB_DEVICE
(
USB_VENDOR_ID_WACOM
,
0xB7
)
},
{
USB_DEVICE
(
USB_VENDOR_ID_WACOM
,
0x3F
)
},
{
USB_DEVICE
(
USB_VENDOR_ID_WACOM
,
0xC5
)
},
{
USB_DEVICE
(
USB_VENDOR_ID_WACOM
,
0xC6
)
},
{
USB_DEVICE
(
USB_VENDOR_ID_WACOM
,
0x47
)
},
{
}
...
...
drivers/input/touchscreen/Kconfig
View file @
308f0a58
...
...
@@ -185,6 +185,59 @@ config TOUCHSCREEN_UCB1400
To compile this driver as a module, choose M here: the
module will be called ucb1400_ts.
config TOUCHSCREEN_WM97XX
tristate "Support for WM97xx AC97 touchscreen controllers"
depends on AC97_BUS
help
Say Y here if you have a Wolfson Microelectronics WM97xx
touchscreen connected to your system. Note that this option
only enables core driver, you will also need to select
support for appropriate chip below.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called wm97xx-ts.
config TOUCHSCREEN_WM9705
bool "WM9705 Touchscreen interface support"
depends on TOUCHSCREEN_WM97XX
help
Say Y here if you have a Wolfson Microelectronics WM9705
touchscreen controller connected to your system.
If unsure, say N.
config TOUCHSCREEN_WM9712
bool "WM9712 Touchscreen interface support"
depends on TOUCHSCREEN_WM97XX
help
Say Y here if you have a Wolfson Microelectronics WM9712
touchscreen controller connected to your system.
If unsure, say N.
config TOUCHSCREEN_WM9713
bool "WM9713 Touchscreen interface support"
depends on TOUCHSCREEN_WM97XX
help
Say Y here if you have a Wolfson Microelectronics WM9713 touchscreen
controller connected to your system.
If unsure, say N.
config TOUCHSCREEN_WM97XX_MAINSTONE
tristate "WM97xx Mainstone accelerated touch"
depends on TOUCHSCREEN_WM97XX && ARCH_PXA
help
Say Y here for support for streaming mode with WM97xx touchscreens
on Mainstone systems.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called mainstone-wm97xx.
config TOUCHSCREEN_USB_COMPOSITE
tristate "USB Touchscreen Driver"
depends on USB_ARCH_HAS_HCD
...
...
drivers/input/touchscreen/Makefile
View file @
308f0a58
...
...
@@ -4,6 +4,8 @@
# Each configuration option enables a list of files.
wm97xx-ts-y
:=
wm97xx-core.o
obj-$(CONFIG_TOUCHSCREEN_ADS7846)
+=
ads7846.o
obj-$(CONFIG_TOUCHSCREEN_BITSY)
+=
h3600_ts_input.o
obj-$(CONFIG_TOUCHSCREEN_CORGI)
+=
corgi_ts.o
...
...
@@ -19,3 +21,8 @@ obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)
+=
touchright.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN)
+=
touchwin.o
obj-$(CONFIG_TOUCHSCREEN_UCB1400)
+=
ucb1400_ts.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX)
+=
wm97xx-ts.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705)
+=
wm9705.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712)
+=
wm9712.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713)
+=
wm9713.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE)
+=
mainstone-wm97xx.o
drivers/input/touchscreen/ads7846.c
View file @
308f0a58
...
...
@@ -87,6 +87,7 @@ struct ads7846 {
#endif
u16
model
;
u16
vref_mv
;
u16
vref_delay_usecs
;
u16
x_plate_ohms
;
u16
pressure_max
;
...
...
@@ -184,9 +185,6 @@ struct ads7846 {
* The range is GND..vREF. The ads7843 and ads7835 must use external vREF;
* ads7846 lets that pin be unconnected, to use internal vREF.
*/
static
unsigned
vREF_mV
;
module_param
(
vREF_mV
,
uint
,
0
);
MODULE_PARM_DESC
(
vREF_mV
,
"external vREF voltage, in milliVolts"
);
struct
ser_req
{
u8
ref_on
;
...
...
@@ -213,7 +211,6 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
struct
ads7846
*
ts
=
dev_get_drvdata
(
dev
);
struct
ser_req
*
req
=
kzalloc
(
sizeof
*
req
,
GFP_KERNEL
);
int
status
;
int
uninitialized_var
(
sample
);
int
use_internal
;
if
(
!
req
)
...
...
@@ -270,13 +267,13 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
if
(
status
==
0
)
{
/* on-wire is a must-ignore bit, a BE12 value, then padding */
s
ample
=
be16_to_cpu
(
req
->
sample
);
s
ample
=
sample
>>
3
;
s
ample
&=
0x0fff
;
s
tatus
=
be16_to_cpu
(
req
->
sample
);
s
tatus
=
status
>>
3
;
s
tatus
&=
0x0fff
;
}
kfree
(
req
);
return
status
?
status
:
sample
;
return
status
;
}
#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
...
...
@@ -317,7 +314,7 @@ static inline unsigned vaux_adjust(struct ads7846 *ts, ssize_t v)
unsigned
retval
=
v
;
/* external resistors may scale vAUX into 0..vREF */
retval
*=
vREF_mV
;
retval
*=
ts
->
vref_mv
;
retval
=
retval
>>
12
;
return
retval
;
}
...
...
@@ -375,14 +372,14 @@ static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)
/* hwmon sensors need a reference voltage */
switch
(
ts
->
model
)
{
case
7846
:
if
(
!
vREF_mV
)
{
if
(
!
ts
->
vref_mv
)
{
dev_dbg
(
&
spi
->
dev
,
"assuming 2.5V internal vREF
\n
"
);
vREF_mV
=
2500
;
ts
->
vref_mv
=
2500
;
}
break
;
case
7845
:
case
7843
:
if
(
!
vREF_mV
)
{
if
(
!
ts
->
vref_mv
)
{
dev_warn
(
&
spi
->
dev
,
"external vREF for ADS%d not specified
\n
"
,
ts
->
model
);
...
...
@@ -875,6 +872,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ts
->
spi
=
spi
;
ts
->
input
=
input_dev
;
ts
->
vref_mv
=
pdata
->
vref_mv
;
hrtimer_init
(
&
ts
->
timer
,
CLOCK_MONOTONIC
,
HRTIMER_MODE_REL
);
ts
->
timer
.
function
=
ads7846_timer
;
...
...
drivers/input/touchscreen/corgi_ts.c
View file @
308f0a58
...
...
@@ -361,6 +361,7 @@ static struct platform_driver corgits_driver = {
.
resume
=
corgits_resume
,
.
driver
=
{
.
name
=
"corgi-ts"
,
.
owner
=
THIS_MODULE
,
},
};
...
...
@@ -380,3 +381,4 @@ module_exit(corgits_exit);
MODULE_AUTHOR
(
"Richard Purdie <rpurdie@rpsys.net>"
);
MODULE_DESCRIPTION
(
"Corgi TouchScreen Driver"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_ALIAS
(
"platform:corgi-ts"
);
drivers/input/touchscreen/jornada720_ts.c
View file @
308f0a58
...
...
@@ -160,11 +160,15 @@ static int __devexit jornada720_ts_remove(struct platform_device *pdev)
return
0
;
}
/* work with hotplug and coldplug */
MODULE_ALIAS
(
"platform:jornada_ts"
);
static
struct
platform_driver
jornada720_ts_driver
=
{
.
probe
=
jornada720_ts_probe
,
.
remove
=
__devexit_p
(
jornada720_ts_remove
),
.
driver
=
{
.
name
=
"jornada_ts"
,
.
owner
=
THIS_MODULE
,
},
};
...
...
drivers/input/touchscreen/mainstone-wm97xx.c
0 → 100644
View file @
308f0a58
/*
* mainstone-wm97xx.c -- Mainstone Continuous Touch screen driver for
* Wolfson WM97xx AC97 Codecs.
*
* Copyright 2004, 2007 Wolfson Microelectronics PLC.
* Author: Liam Girdwood
* liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
* Parts Copyright : Ian Molton <spyro@f2s.com>
* Andrew Zabolotny <zap@homelink.ru>
*
* 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.
*
* Notes:
* This is a wm97xx extended touch driver to capture touch
* data in a continuous manner on the Intel XScale archictecture
*
* Features:
* - codecs supported:- WM9705, WM9712, WM9713
* - processors supported:- Intel XScale PXA25x, PXA26x, PXA27x
*
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/wm97xx.h>
#include <linux/io.h>
#include <asm/arch/pxa-regs.h>
#define VERSION "0.13"
struct
continuous
{
u16
id
;
/* codec id */
u8
code
;
/* continuous code */
u8
reads
;
/* number of coord reads per read cycle */
u32
speed
;
/* number of coords per second */
};
#define WM_READS(sp) ((sp / HZ) + 1)
static
const
struct
continuous
cinfo
[]
=
{
{
WM9705_ID2
,
0
,
WM_READS
(
94
),
94
},
{
WM9705_ID2
,
1
,
WM_READS
(
188
),
188
},
{
WM9705_ID2
,
2
,
WM_READS
(
375
),
375
},
{
WM9705_ID2
,
3
,
WM_READS
(
750
),
750
},
{
WM9712_ID2
,
0
,
WM_READS
(
94
),
94
},
{
WM9712_ID2
,
1
,
WM_READS
(
188
),
188
},
{
WM9712_ID2
,
2
,
WM_READS
(
375
),
375
},
{
WM9712_ID2
,
3
,
WM_READS
(
750
),
750
},
{
WM9713_ID2
,
0
,
WM_READS
(
94
),
94
},
{
WM9713_ID2
,
1
,
WM_READS
(
120
),
120
},
{
WM9713_ID2
,
2
,
WM_READS
(
154
),
154
},
{
WM9713_ID2
,
3
,
WM_READS
(
188
),
188
},
};
/* continuous speed index */
static
int
sp_idx
;
static
u16
last
,
tries
;
/*
* Pen sampling frequency (Hz) in continuous mode.
*/
static
int
cont_rate
=
200
;
module_param
(
cont_rate
,
int
,
0
);
MODULE_PARM_DESC
(
cont_rate
,
"Sampling rate in continuous mode (Hz)"
);
/*
* Pen down detection.
*
* This driver can either poll or use an interrupt to indicate a pen down
* event. If the irq request fails then it will fall back to polling mode.
*/
static
int
pen_int
;
module_param
(
pen_int
,
int
,
0
);
MODULE_PARM_DESC
(
pen_int
,
"Pen down detection (1 = interrupt, 0 = polling)"
);
/*
* Pressure readback.
*
* Set to 1 to read back pen down pressure
*/
static
int
pressure
;
module_param
(
pressure
,
int
,
0
);
MODULE_PARM_DESC
(
pressure
,
"Pressure readback (1 = pressure, 0 = no pressure)"
);
/*
* AC97 touch data slot.
*
* Touch screen readback data ac97 slot
*/
static
int
ac97_touch_slot
=
5
;
module_param
(
ac97_touch_slot
,
int
,
0
);
MODULE_PARM_DESC
(
ac97_touch_slot
,
"Touch screen data slot AC97 number"
);
/* flush AC97 slot 5 FIFO on pxa machines */
#ifdef CONFIG_PXA27x
static
void
wm97xx_acc_pen_up
(
struct
wm97xx
*
wm
)
{
schedule_timeout_uninterruptible
(
1
);
while
(
MISR
&
(
1
<<
2
))
MODR
;
}
#else
static
void
wm97xx_acc_pen_up
(
struct
wm97xx
*
wm
)
{
int
count
=
16
;
schedule_timeout_uninterruptible
(
1
);
while
(
count
<
16
)
{
MODR
;
count
--
;
}
}
#endif
static
int
wm97xx_acc_pen_down
(
struct
wm97xx
*
wm
)
{
u16
x
,
y
,
p
=
0x100
|
WM97XX_ADCSEL_PRES
;
int
reads
=
0
;
/* When the AC97 queue has been drained we need to allow time
* to buffer up samples otherwise we end up spinning polling
* for samples. The controller can't have a suitably low
* threashold set to use the notifications it gives.
*/
schedule_timeout_uninterruptible
(
1
);
if
(
tries
>
5
)
{
tries
=
0
;
return
RC_PENUP
;
}
x
=
MODR
;
if
(
x
==
last
)
{
tries
++
;
return
RC_AGAIN
;
}
last
=
x
;
do
{
if
(
reads
)
x
=
MODR
;
y
=
MODR
;
if
(
pressure
)
p
=
MODR
;
/* are samples valid */
if
((
x
&
WM97XX_ADCSRC_MASK
)
!=
WM97XX_ADCSEL_X
||
(
y
&
WM97XX_ADCSRC_MASK
)
!=
WM97XX_ADCSEL_Y
||
(
p
&
WM97XX_ADCSRC_MASK
)
!=
WM97XX_ADCSEL_PRES
)
goto
up
;
/* coordinate is good */
tries
=
0
;
input_report_abs
(
wm
->
input_dev
,
ABS_X
,
x
&
0xfff
);
input_report_abs
(
wm
->
input_dev
,
ABS_Y
,
y
&
0xfff
);
input_report_abs
(
wm
->
input_dev
,
ABS_PRESSURE
,
p
&
0xfff
);
input_sync
(
wm
->
input_dev
);
reads
++
;
}
while
(
reads
<
cinfo
[
sp_idx
].
reads
);
up:
return
RC_PENDOWN
|
RC_AGAIN
;
}
static
int
wm97xx_acc_startup
(
struct
wm97xx
*
wm
)
{
int
idx
=
0
;
/* check we have a codec */
if
(
wm
->
ac97
==
NULL
)
return
-
ENODEV
;
/* Go you big red fire engine */
for
(
idx
=
0
;
idx
<
ARRAY_SIZE
(
cinfo
);
idx
++
)
{
if
(
wm
->
id
!=
cinfo
[
idx
].
id
)
continue
;
sp_idx
=
idx
;
if
(
cont_rate
<=
cinfo
[
idx
].
speed
)
break
;
}
wm
->
acc_rate
=
cinfo
[
sp_idx
].
code
;
wm
->
acc_slot
=
ac97_touch_slot
;
dev_info
(
wm
->
dev
,
"mainstone accelerated touchscreen driver, %d samples/sec
\n
"
,
cinfo
[
sp_idx
].
speed
);
/* codec specific irq config */
if
(
pen_int
)
{
switch
(
wm
->
id
)
{
case
WM9705_ID2
:
wm
->
pen_irq
=
IRQ_GPIO
(
4
);
set_irq_type
(
IRQ_GPIO
(
4
),
IRQT_BOTHEDGE
);
break
;
case
WM9712_ID2
:
case
WM9713_ID2
:
/* enable pen down interrupt */
/* use PEN_DOWN GPIO 13 to assert IRQ on GPIO line 2 */
wm
->
pen_irq
=
MAINSTONE_AC97_IRQ
;
wm97xx_config_gpio
(
wm
,
WM97XX_GPIO_13
,
WM97XX_GPIO_IN
,
WM97XX_GPIO_POL_HIGH
,
WM97XX_GPIO_STICKY
,
WM97XX_GPIO_WAKE
);
wm97xx_config_gpio
(
wm
,
WM97XX_GPIO_2
,
WM97XX_GPIO_OUT
,
WM97XX_GPIO_POL_HIGH
,
WM97XX_GPIO_NOTSTICKY
,
WM97XX_GPIO_NOWAKE
);
break
;
default:
dev_err
(
wm
->
dev
,
"pen down irq not supported on this device
\n
"
);
pen_int
=
0
;
break
;
}
}
return
0
;
}
static
void
wm97xx_acc_shutdown
(
struct
wm97xx
*
wm
)
{
/* codec specific deconfig */
if
(
pen_int
)
{
switch
(
wm
->
id
&
0xffff
)
{
case
WM9705_ID2
:
wm
->
pen_irq
=
0
;
break
;
case
WM9712_ID2
:
case
WM9713_ID2
:
/* disable interrupt */
wm
->
pen_irq
=
0
;
break
;
}
}
}
static
void
wm97xx_irq_enable
(
struct
wm97xx
*
wm
,
int
enable
)
{
if
(
enable
)
enable_irq
(
wm
->
pen_irq
);
else
disable_irq
(
wm
->
pen_irq
);
}
static
struct
wm97xx_mach_ops
mainstone_mach_ops
=
{
.
acc_enabled
=
1
,
.
acc_pen_up
=
wm97xx_acc_pen_up
,
.
acc_pen_down
=
wm97xx_acc_pen_down
,
.
acc_startup
=
wm97xx_acc_startup
,
.
acc_shutdown
=
wm97xx_acc_shutdown
,
.
irq_enable
=
wm97xx_irq_enable
,
.
irq_gpio
=
WM97XX_GPIO_2
,
};
static
int
mainstone_wm97xx_probe
(
struct
platform_device
*
pdev
)
{
struct
wm97xx
*
wm
=
platform_get_drvdata
(
pdev
);
return
wm97xx_register_mach_ops
(
wm
,
&
mainstone_mach_ops
);
}
static
int
mainstone_wm97xx_remove
(
struct
platform_device
*
pdev
)
{
struct
wm97xx
*
wm
=
platform_get_drvdata
(
pdev
);
wm97xx_unregister_mach_ops
(
wm
);
return
0
;
}
static
struct
platform_driver
mainstone_wm97xx_driver
=
{
.
probe
=
mainstone_wm97xx_probe
,
.
remove
=
mainstone_wm97xx_remove
,
.
driver
=
{
.
name
=
"wm97xx-touch"
,
},
};
static
int
__init
mainstone_wm97xx_init
(
void
)
{
return
platform_driver_register
(
&
mainstone_wm97xx_driver
);
}
static
void
__exit
mainstone_wm97xx_exit
(
void
)
{
platform_driver_unregister
(
&
mainstone_wm97xx_driver
);
}
module_init
(
mainstone_wm97xx_init
);
module_exit
(
mainstone_wm97xx_exit
);
/* Module information */
MODULE_AUTHOR
(
"Liam Girdwood <liam.girdwood@wolfsonmicro.com>"
);
MODULE_DESCRIPTION
(
"wm97xx continuous touch driver for mainstone"
);
MODULE_LICENSE
(
"GPL"
);
drivers/input/touchscreen/ucb1400_ts.c
View file @
308f0a58
...
...
@@ -427,10 +427,6 @@ static int ucb1400_detect_irq(struct ucb1400 *ucb)
unsigned
long
mask
,
timeout
;
mask
=
probe_irq_on
();
if
(
!
mask
)
{
probe_irq_off
(
mask
);
return
-
EBUSY
;
}
/* Enable the ADC interrupt. */
ucb1400_reg_write
(
ucb
,
UCB_IE_RIS
,
UCB_IE_ADC
);
...
...
drivers/input/touchscreen/usbtouchscreen.c
View file @
308f0a58
...
...
@@ -396,9 +396,12 @@ static int gunze_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
static
int
dmc_tsc10_init
(
struct
usbtouch_usb
*
usbtouch
)
{
struct
usb_device
*
dev
=
usbtouch
->
udev
;
int
ret
;
unsigned
char
buf
[
2
]
;
int
ret
=
-
ENOMEM
;
unsigned
char
*
buf
;
buf
=
kmalloc
(
2
,
GFP_KERNEL
);
if
(
!
buf
)
goto
err_nobuf
;
/* reset */
buf
[
0
]
=
buf
[
1
]
=
0xFF
;
ret
=
usb_control_msg
(
dev
,
usb_rcvctrlpipe
(
dev
,
0
),
...
...
@@ -406,9 +409,11 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
USB_DIR_IN
|
USB_TYPE_VENDOR
|
USB_RECIP_DEVICE
,
0
,
0
,
buf
,
2
,
USB_CTRL_SET_TIMEOUT
);
if
(
ret
<
0
)
return
ret
;
if
(
buf
[
0
]
!=
0x06
||
buf
[
1
]
!=
0x00
)
return
-
ENODEV
;
goto
err_out
;
if
(
buf
[
0
]
!=
0x06
||
buf
[
1
]
!=
0x00
)
{
ret
=
-
ENODEV
;
goto
err_out
;
}
/* set coordinate output rate */
buf
[
0
]
=
buf
[
1
]
=
0xFF
;
...
...
@@ -417,20 +422,22 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
USB_DIR_IN
|
USB_TYPE_VENDOR
|
USB_RECIP_DEVICE
,
TSC10_RATE_150
,
0
,
buf
,
2
,
USB_CTRL_SET_TIMEOUT
);
if
(
ret
<
0
)
return
re
t
;
goto
err_ou
t
;
if
((
buf
[
0
]
!=
0x06
||
buf
[
1
]
!=
0x00
)
&&
(
buf
[
0
]
!=
0x15
||
buf
[
1
]
!=
0x01
))
return
-
ENODEV
;
(
buf
[
0
]
!=
0x15
||
buf
[
1
]
!=
0x01
))
{
ret
=
-
ENODEV
;
goto
err_out
;
}
/* start sending data */
ret
=
usb_control_msg
(
dev
,
usb_rcvctrlpipe
(
dev
,
0
),
TSC10_CMD_DATA1
,
USB_DIR_OUT
|
USB_TYPE_VENDOR
|
USB_RECIP_DEVICE
,
0
,
0
,
NULL
,
0
,
USB_CTRL_SET_TIMEOUT
);
if
(
ret
<
0
)
err_out:
kfree
(
buf
);
err_nobuf:
return
ret
;
return
0
;
}
...
...
drivers/input/touchscreen/wm9705.c
0 → 100644
View file @
308f0a58
/*
* wm9705.c -- Codec driver for Wolfson WM9705 AC97 Codec.
*
* Copyright 2003, 2004, 2005, 2006, 2007 Wolfson Microelectronics PLC.
* Author: Liam Girdwood
* liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
* Parts Copyright : Ian Molton <spyro@f2s.com>
* Andrew Zabolotny <zap@homelink.ru>
* Russell King <rmk@arm.linux.org.uk>
*
* 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/moduleparam.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/bitops.h>
#include <linux/wm97xx.h>
#define TS_NAME "wm97xx"
#define WM9705_VERSION "1.00"
#define DEFAULT_PRESSURE 0xb0c0
/*
* Module parameters
*/
/*
* Set current used for pressure measurement.
*
* Set pil = 2 to use 400uA
* pil = 1 to use 200uA and
* pil = 0 to disable pressure measurement.
*
* This is used to increase the range of values returned by the adc
* when measureing touchpanel pressure.
*/
static
int
pil
;
module_param
(
pil
,
int
,
0
);
MODULE_PARM_DESC
(
pil
,
"Set current used for pressure measurement."
);
/*
* Set threshold for pressure measurement.
*
* Pen down pressure below threshold is ignored.
*/
static
int
pressure
=
DEFAULT_PRESSURE
&
0xfff
;
module_param
(
pressure
,
int
,
0
);
MODULE_PARM_DESC
(
pressure
,
"Set threshold for pressure measurement."
);
/*
* Set adc sample delay.
*
* For accurate touchpanel measurements, some settling time may be
* required between the switch matrix applying a voltage across the
* touchpanel plate and the ADC sampling the signal.
*
* This delay can be set by setting delay = n, where n is the array
* position of the delay in the array delay_table below.
* Long delays > 1ms are supported for completeness, but are not
* recommended.
*/
static
int
delay
=
4
;
module_param
(
delay
,
int
,
0
);
MODULE_PARM_DESC
(
delay
,
"Set adc sample delay."
);
/*
* Pen detect comparator threshold.
*
* 0 to Vmid in 15 steps, 0 = use zero power comparator with Vmid threshold
* i.e. 1 = Vmid/15 threshold
* 15 = Vmid/1 threshold
*
* Adjust this value if you are having problems with pen detect not
* detecting any down events.
*/
static
int
pdd
=
8
;
module_param
(
pdd
,
int
,
0
);
MODULE_PARM_DESC
(
pdd
,
"Set pen detect comparator threshold"
);
/*
* Set adc mask function.
*
* Sources of glitch noise, such as signals driving an LCD display, may feed
* through to the touch screen plates and affect measurement accuracy. In
* order to minimise this, a signal may be applied to the MASK pin to delay or
* synchronise the sampling.
*
* 0 = No delay or sync
* 1 = High on pin stops conversions
* 2 = Edge triggered, edge on pin delays conversion by delay param (above)
* 3 = Edge triggered, edge on pin starts conversion after delay param
*/
static
int
mask
;
module_param
(
mask
,
int
,
0
);
MODULE_PARM_DESC
(
mask
,
"Set adc mask function."
);
/*
* ADC sample delay times in uS
*/
static
const
int
delay_table
[]
=
{
21
,
/* 1 AC97 Link frames */
42
,
/* 2 */
84
,
/* 4 */
167
,
/* 8 */
333
,
/* 16 */
667
,
/* 32 */
1000
,
/* 48 */
1333
,
/* 64 */
2000
,
/* 96 */
2667
,
/* 128 */
3333
,
/* 160 */
4000
,
/* 192 */
4667
,
/* 224 */
5333
,
/* 256 */
6000
,
/* 288 */
0
/* No delay, switch matrix always on */
};
/*
* Delay after issuing a POLL command.
*
* The delay is 3 AC97 link frames + the touchpanel settling delay
*/
static
inline
void
poll_delay
(
int
d
)
{
udelay
(
3
*
AC97_LINK_FRAME
+
delay_table
[
d
]);
}
/*
* set up the physical settings of the WM9705
*/
static
void
wm9705_phy_init
(
struct
wm97xx
*
wm
)
{
u16
dig1
=
0
,
dig2
=
WM97XX_RPR
;
/*
* mute VIDEO and AUX as they share X and Y touchscreen
* inputs on the WM9705
*/
wm97xx_reg_write
(
wm
,
AC97_AUX
,
0x8000
);
wm97xx_reg_write
(
wm
,
AC97_VIDEO
,
0x8000
);
/* touchpanel pressure current*/
if
(
pil
==
2
)
{
dig2
|=
WM9705_PIL
;
dev_dbg
(
wm
->
dev
,
"setting pressure measurement current to 400uA."
);
}
else
if
(
pil
)
dev_dbg
(
wm
->
dev
,
"setting pressure measurement current to 200uA."
);
if
(
!
pil
)
pressure
=
0
;
/* polling mode sample settling delay */
if
(
delay
!=
4
)
{
if
(
delay
<
0
||
delay
>
15
)
{
dev_dbg
(
wm
->
dev
,
"supplied delay out of range."
);
delay
=
4
;
}
}
dig1
&=
0xff0f
;
dig1
|=
WM97XX_DELAY
(
delay
);
dev_dbg
(
wm
->
dev
,
"setting adc sample delay to %d u Secs."
,
delay_table
[
delay
]);
/* WM9705 pdd */
dig2
|=
(
pdd
&
0x000f
);
dev_dbg
(
wm
->
dev
,
"setting pdd to Vmid/%d"
,
1
-
(
pdd
&
0x000f
));
/* mask */
dig2
|=
((
mask
&
0x3
)
<<
4
);
wm97xx_reg_write
(
wm
,
AC97_WM97XX_DIGITISER1
,
dig1
);
wm97xx_reg_write
(
wm
,
AC97_WM97XX_DIGITISER2
,
dig2
);
}
static
void
wm9705_dig_enable
(
struct
wm97xx
*
wm
,
int
enable
)
{
if
(
enable
)
{
wm97xx_reg_write
(
wm
,
AC97_WM97XX_DIGITISER2
,
wm
->
dig
[
2
]
|
WM97XX_PRP_DET_DIG
);
wm97xx_reg_read
(
wm
,
AC97_WM97XX_DIGITISER_RD
);
/* dummy read */
}
else
wm97xx_reg_write
(
wm
,
AC97_WM97XX_DIGITISER2
,
wm
->
dig
[
2
]
&
~
WM97XX_PRP_DET_DIG
);
}
static
void
wm9705_aux_prepare
(
struct
wm97xx
*
wm
)
{
memcpy
(
wm
->
dig_save
,
wm
->
dig
,
sizeof
(
wm
->
dig
));
wm97xx_reg_write
(
wm
,
AC97_WM97XX_DIGITISER1
,
0
);
wm97xx_reg_write
(
wm
,
AC97_WM97XX_DIGITISER2
,
WM97XX_PRP_DET_DIG
);
}
static
void
wm9705_dig_restore
(
struct
wm97xx
*
wm
)
{
wm97xx_reg_write
(
wm
,
AC97_WM97XX_DIGITISER1
,
wm
->
dig_save
[
1
]);
wm97xx_reg_write
(
wm
,
AC97_WM97XX_DIGITISER2
,
wm
->
dig_save
[
2
]);
}
static
inline
int
is_pden
(
struct
wm97xx
*
wm
)
{
return
wm
->
dig
[
2
]
&
WM9705_PDEN
;
}
/*
* Read a sample from the WM9705 adc in polling mode.
*/
static
int
wm9705_poll_sample
(
struct
wm97xx
*
wm
,
int
adcsel
,
int
*
sample
)
{
int
timeout
=
5
*
delay
;
if
(
!
wm
->
pen_probably_down
)
{
u16
data
=
wm97xx_reg_read
(
wm
,
AC97_WM97XX_DIGITISER_RD
);
if
(
!
(
data
&
WM97XX_PEN_DOWN
))
return
RC_PENUP
;
wm
->
pen_probably_down
=
1
;
}
/* set up digitiser */
if
(
adcsel
&
0x8000
)
adcsel
=
((
adcsel
&
0x7fff
)
+
3
)
<<
12
;
if
(
wm
->
mach_ops
&&
wm
->
mach_ops
->
pre_sample
)
wm
->
mach_ops
->
pre_sample
(
adcsel
);
wm97xx_reg_write
(
wm
,
AC97_WM97XX_DIGITISER1
,
adcsel
|
WM97XX_POLL
|
WM97XX_DELAY
(
delay
));
/* wait 3 AC97 time slots + delay for conversion */
poll_delay
(
delay
);
/* wait for POLL to go low */
while
((
wm97xx_reg_read
(
wm
,
AC97_WM97XX_DIGITISER1
)
&
WM97XX_POLL
)
&&
timeout
)
{
udelay
(
AC97_LINK_FRAME
);
timeout
--
;
}
if
(
timeout
==
0
)
{
/* If PDEN is set, we can get a timeout when pen goes up */
if
(
is_pden
(
wm
))
wm
->
pen_probably_down
=
0
;
else
dev_dbg
(
wm
->
dev
,
"adc sample timeout"
);
return
RC_PENUP
;
}
*
sample
=
wm97xx_reg_read
(
wm
,
AC97_WM97XX_DIGITISER_RD
);
if
(
wm
->
mach_ops
&&
wm
->
mach_ops
->
post_sample
)
wm
->
mach_ops
->
post_sample
(
adcsel
);
/* check we have correct sample */
if
((
*
sample
&
WM97XX_ADCSEL_MASK
)
!=
adcsel
)
{
dev_dbg
(
wm
->
dev
,
"adc wrong sample, read %x got %x"
,
adcsel
,
*
sample
&
WM97XX_ADCSEL_MASK
);
return
RC_PENUP
;
}
if
(
!
(
*
sample
&
WM97XX_PEN_DOWN
))
{
wm
->
pen_probably_down
=
0
;
return
RC_PENUP
;
}
return
RC_VALID
;
}
/*
* Sample the WM9705 touchscreen in polling mode
*/
static
int
wm9705_poll_touch
(
struct
wm97xx
*
wm
,
struct
wm97xx_data
*
data
)
{
int
rc
;
rc
=
wm9705_poll_sample
(
wm
,
WM97XX_ADCSEL_X
,
&
data
->
x
);
if
(
rc
!=
RC_VALID
)
return
rc
;
rc
=
wm9705_poll_sample
(
wm
,
WM97XX_ADCSEL_Y
,
&
data
->
y
);
if
(
rc
!=
RC_VALID
)
return
rc
;
if
(
pil
)
{
rc
=
wm9705_poll_sample
(
wm
,
WM97XX_ADCSEL_PRES
,
&
data
->
p
);
if
(
rc
!=
RC_VALID
)
return
rc
;
}
else
data
->
p
=
DEFAULT_PRESSURE
;
return
RC_VALID
;
}
/*
* Enable WM9705 continuous mode, i.e. touch data is streamed across
* an AC97 slot
*/
static
int
wm9705_acc_enable
(
struct
wm97xx
*
wm
,
int
enable
)
{
u16
dig1
,
dig2
;
int
ret
=
0
;
dig1
=
wm
->
dig
[
1
];
dig2
=
wm
->
dig
[
2
];
if
(
enable
)
{
/* continous mode */
if
(
wm
->
mach_ops
->
acc_startup
&&
(
ret
=
wm
->
mach_ops
->
acc_startup
(
wm
))
<
0
)
return
ret
;
dig1
&=
~
(
WM97XX_CM_RATE_MASK
|
WM97XX_ADCSEL_MASK
|
WM97XX_DELAY_MASK
|
WM97XX_SLT_MASK
);
dig1
|=
WM97XX_CTC
|
WM97XX_COO
|
WM97XX_SLEN
|
WM97XX_DELAY
(
delay
)
|
WM97XX_SLT
(
wm
->
acc_slot
)
|
WM97XX_RATE
(
wm
->
acc_rate
);
if
(
pil
)
dig1
|=
WM97XX_ADCSEL_PRES
;
dig2
|=
WM9705_PDEN
;
}
else
{
dig1
&=
~
(
WM97XX_CTC
|
WM97XX_COO
|
WM97XX_SLEN
);
dig2
&=
~
WM9705_PDEN
;
if
(
wm
->
mach_ops
->
acc_shutdown
)
wm
->
mach_ops
->
acc_shutdown
(
wm
);
}
wm97xx_reg_write
(
wm
,
AC97_WM97XX_DIGITISER1
,
dig1
);
wm97xx_reg_write
(
wm
,
AC97_WM97XX_DIGITISER2
,
dig2
);
return
ret
;
}
struct
wm97xx_codec_drv
wm9705_codec
=
{
.
id
=
WM9705_ID2
,
.
name
=
"wm9705"
,
.
poll_sample
=
wm9705_poll_sample
,
.
poll_touch
=
wm9705_poll_touch
,
.
acc_enable
=
wm9705_acc_enable
,
.
phy_init
=
wm9705_phy_init
,
.
dig_enable
=
wm9705_dig_enable
,
.
dig_restore
=
wm9705_dig_restore
,
.
aux_prepare
=
wm9705_aux_prepare
,
};
EXPORT_SYMBOL_GPL
(
wm9705_codec
);
/* Module information */
MODULE_AUTHOR
(
"Liam Girdwood <liam.girdwood@wolfsonmicro.com>"
);
MODULE_DESCRIPTION
(
"WM9705 Touch Screen Driver"
);
MODULE_LICENSE
(
"GPL"
);
drivers/input/touchscreen/wm9712.c
0 → 100644
View file @
308f0a58
/*
* wm9712.c -- Codec driver for Wolfson WM9712 AC97 Codecs.
*
* Copyright 2003, 2004, 2005, 2006, 2007 Wolfson Microelectronics PLC.
* Author: Liam Girdwood
* liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
* Parts Copyright : Ian Molton <spyro@f2s.com>
* Andrew Zabolotny <zap@homelink.ru>
* Russell King <rmk@arm.linux.org.uk>
*
* 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/moduleparam.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/bitops.h>
#include <linux/wm97xx.h>
#define TS_NAME "wm97xx"
#define WM9712_VERSION "1.00"
#define DEFAULT_PRESSURE 0xb0c0
/*
* Module parameters
*/
/*
* Set internal pull up for pen detect.
*
* Pull up is in the range 1.02k (least sensitive) to 64k (most sensitive)
* i.e. pull up resistance = 64k Ohms / rpu.
*
* Adjust this value if you are having problems with pen detect not
* detecting any down event.
*/
static
int
rpu
=
8
;
module_param
(
rpu
,
int
,
0
);
MODULE_PARM_DESC
(
rpu
,
"Set internal pull up resitor for pen detect."
);
/*
* Set current used for pressure measurement.
*
* Set pil = 2 to use 400uA
* pil = 1 to use 200uA and
* pil = 0 to disable pressure measurement.
*
* This is used to increase the range of values returned by the adc
* when measureing touchpanel pressure.
*/
static
int
pil
;
module_param
(
pil
,
int
,
0
);
MODULE_PARM_DESC
(
pil
,
"Set current used for pressure measurement."
);
/*
* Set threshold for pressure measurement.
*
* Pen down pressure below threshold is ignored.
*/
static
int
pressure
=
DEFAULT_PRESSURE
&
0xfff
;
module_param
(
pressure
,
int
,
0
);
MODULE_PARM_DESC
(
pressure
,
"Set threshold for pressure measurement."
);
/*
* Set adc sample delay.
*
* For accurate touchpanel measurements, some settling time may be
* required between the switch matrix applying a voltage across the
* touchpanel plate and the ADC sampling the signal.
*
* This delay can be set by setting delay = n, where n is the array
* position of the delay in the array delay_table below.
* Long delays > 1ms are supported for completeness, but are not
* recommended.
*/
static
int
delay
=
3
;
module_param
(
delay
,
int
,
0
);
MODULE_PARM_DESC
(
delay
,
"Set adc sample delay."
);
/*
* Set five_wire = 1 to use a 5 wire touchscreen.
*
* NOTE: Five wire mode does not allow for readback of pressure.
*/
static
int
five_wire
;
module_param
(
five_wire
,
int
,
0
);
MODULE_PARM_DESC
(
five_wire
,
"Set to '1' to use 5-wire touchscreen."
);
/*
* Set adc mask function.
*
* Sources of glitch noise, such as signals driving an LCD display, may feed
* through to the touch screen plates and affect measurement accuracy. In
* order to minimise this, a signal may be applied to the MASK pin to delay or
* synchronise the sampling.
*
* 0 = No delay or sync
* 1 = High on pin stops conversions
* 2 = Edge triggered, edge on pin delays conversion by delay param (above)
* 3 = Edge triggered, edge on pin starts conversion after delay param
*/
static
int
mask
;
module_param
(
mask
,
int
,
0
);
MODULE_PARM_DESC
(
mask
,
"Set adc mask function."
);
/*
* Coordinate Polling Enable.
*
* Set to 1 to enable coordinate polling. e.g. x,y[,p] is sampled together
* for every poll.
*/
static
int
coord
;
module_param
(
coord
,
int
,
0
);
MODULE_PARM_DESC
(
coord
,
"Polling coordinate mode"
);
/*
* ADC sample delay times in uS
*/
static
const
int
delay_table
[]
=
{
21
,
/* 1 AC97 Link frames */
42
,
/* 2 */
84
,
/* 4 */
167
,
/* 8 */
333
,
/* 16 */
667
,
/* 32 */
1000
,
/* 48 */
1333
,
/* 64 */
2000
,
/* 96 */
2667
,
/* 128 */
3333
,
/* 160 */
4000
,
/* 192 */
4667
,
/* 224 */
5333
,
/* 256 */
6000
,
/* 288 */
0
/* No delay, switch matrix always on */
};
/*
* Delay after issuing a POLL command.
*
* The delay is 3 AC97 link frames + the touchpanel settling delay
*/
static
inline
void
poll_delay
(
int
d
)
{
udelay
(
3
*
AC97_LINK_FRAME
+
delay_table
[
d
]);
}
/*
* set up the physical settings of the WM9712
*/
static
void
wm9712_phy_init
(
struct
wm97xx
*
wm
)
{
u16
dig1
=
0
;
u16
dig2
=
WM97XX_RPR
|
WM9712_RPU
(
1
);
/* WM9712 rpu */
if
(
rpu
)
{
dig2
&=
0xffc0
;
dig2
|=
WM9712_RPU
(
rpu
);
dev_dbg
(
wm
->
dev
,
"setting pen detect pull-up to %d Ohms"
,
64000
/
rpu
);
}
/* touchpanel pressure current*/
if
(
pil
==
2
)
{
dig2
|=
WM9712_PIL
;
dev_dbg
(
wm
->
dev
,
"setting pressure measurement current to 400uA."
);
}
else
if
(
pil
)
dev_dbg
(
wm
->
dev
,
"setting pressure measurement current to 200uA."
);
if
(
!
pil
)
pressure
=
0
;
/* WM9712 five wire */
if
(
five_wire
)
{
dig2
|=
WM9712_45W
;
dev_dbg
(
wm
->
dev
,
"setting 5-wire touchscreen mode."
);
}
/* polling mode sample settling delay */
if
(
delay
<
0
||
delay
>
15
)
{
dev_dbg
(
wm
->
dev
,
"supplied delay out of range."
);
delay
=
4
;
}
dig1
&=
0xff0f
;
dig1
|=
WM97XX_DELAY
(
delay
);
dev_dbg
(
wm
->
dev
,
"setting adc sample delay to %d u Secs."
,
delay_table
[
delay
]);
/* mask */
dig2
|=
((
mask
&
0x3
)
<<
6
);
if
(
mask
)
{
u16
reg
;
/* Set GPIO4 as Mask Pin*/
reg
=
wm97xx_reg_read
(
wm
,
AC97_MISC_AFE
);
wm97xx_reg_write
(
wm
,
AC97_MISC_AFE
,
reg
|
WM97XX_GPIO_4
);
reg
=
wm97xx_reg_read
(
wm
,
AC97_GPIO_CFG
);
wm97xx_reg_write
(
wm
,
AC97_GPIO_CFG
,
reg
|
WM97XX_GPIO_4
);
}
/* wait - coord mode */
if
(
coord
)
dig2
|=
WM9712_WAIT
;
wm97xx_reg_write
(
wm
,
AC97_WM97XX_DIGITISER1
,
dig1
);
wm97xx_reg_write
(
wm
,
AC97_WM97XX_DIGITISER2
,
dig2
);
}
static
void
wm9712_dig_enable
(
struct
wm97xx
*
wm
,
int
enable
)
{
u16
dig2
=
wm
->
dig
[
2
];
if
(
enable
)
{
wm97xx_reg_write
(
wm
,
AC97_WM97XX_DIGITISER2
,
dig2
|
WM97XX_PRP_DET_DIG
);
wm97xx_reg_read
(
wm
,
AC97_WM97XX_DIGITISER_RD
);
/* dummy read */
}
else
wm97xx_reg_write
(
wm
,
AC97_WM97XX_DIGITISER2
,
dig2
&
~
WM97XX_PRP_DET_DIG
);
}
static
void
wm9712_aux_prepare
(
struct
wm97xx
*
wm
)
{
memcpy
(
wm
->
dig_save
,
wm
->
dig
,
sizeof
(
wm
->
dig
));
wm97xx_reg_write
(
wm
,
AC97_WM97XX_DIGITISER1
,
0
);
wm97xx_reg_write
(
wm
,
AC97_WM97XX_DIGITISER2
,
WM97XX_PRP_DET_DIG
);
}
static
void
wm9712_dig_restore
(
struct
wm97xx
*
wm
)
{
wm97xx_reg_write
(
wm
,
AC97_WM97XX_DIGITISER1
,
wm
->
dig_save
[
1
]);
wm97xx_reg_write
(
wm
,
AC97_WM97XX_DIGITISER2
,
wm
->
dig_save
[
2
]);
}
static
inline
int
is_pden
(
struct
wm97xx
*
wm
)
{
return
wm
->
dig
[
2
]
&
WM9712_PDEN
;
}
/*
* Read a sample from the WM9712 adc in polling mode.
*/
static
int
wm9712_poll_sample
(
struct
wm97xx
*
wm
,
int
adcsel
,
int
*
sample
)
{
int
timeout
=
5
*
delay
;
if
(
!
wm
->
pen_probably_down
)
{
u16
data
=
wm97xx_reg_read
(
wm
,
AC97_WM97XX_DIGITISER_RD
);
if
(
!
(
data
&
WM97XX_PEN_DOWN
))
return
RC_PENUP
;
wm
->
pen_probably_down
=
1
;
}
/* set up digitiser */
if
(
adcsel
&
0x8000
)
adcsel
=
((
adcsel
&
0x7fff
)
+
3
)
<<
12
;
if
(
wm
->
mach_ops
&&
wm
->
mach_ops
->
pre_sample
)
wm
->
mach_ops
->
pre_sample
(
adcsel
);
wm97xx_reg_write
(
wm
,
AC97_WM97XX_DIGITISER1
,
adcsel
|
WM97XX_POLL
|
WM97XX_DELAY
(
delay
));
/* wait 3 AC97 time slots + delay for conversion */
poll_delay
(
delay
);
/* wait for POLL to go low */
while
((
wm97xx_reg_read
(
wm
,
AC97_WM97XX_DIGITISER1
)
&
WM97XX_POLL
)
&&
timeout
)
{
udelay
(
AC97_LINK_FRAME
);
timeout
--
;
}
if
(
timeout
<=
0
)
{
/* If PDEN is set, we can get a timeout when pen goes up */
if
(
is_pden
(
wm
))
wm
->
pen_probably_down
=
0
;
else
dev_dbg
(
wm
->
dev
,
"adc sample timeout"
);
return
RC_PENUP
;
}
*
sample
=
wm97xx_reg_read
(
wm
,
AC97_WM97XX_DIGITISER_RD
);
if
(
wm
->
mach_ops
&&
wm
->
mach_ops
->
post_sample
)
wm
->
mach_ops
->
post_sample
(
adcsel
);
/* check we have correct sample */
if
((
*
sample
&
WM97XX_ADCSEL_MASK
)
!=
adcsel
)
{
dev_dbg
(
wm
->
dev
,
"adc wrong sample, read %x got %x"
,
adcsel
,
*
sample
&
WM97XX_ADCSEL_MASK
);
return
RC_PENUP
;
}
if
(
!
(
*
sample
&
WM97XX_PEN_DOWN
))
{
wm
->
pen_probably_down
=
0
;
return
RC_PENUP
;
}
return
RC_VALID
;
}
/*
* Read a coord from the WM9712 adc in polling mode.
*/
static
int
wm9712_poll_coord
(
struct
wm97xx
*
wm
,
struct
wm97xx_data
*
data
)
{
int
timeout
=
5
*
delay
;
if
(
!
wm
->
pen_probably_down
)
{
u16
data_rd
=
wm97xx_reg_read
(
wm
,
AC97_WM97XX_DIGITISER_RD
);
if
(
!
(
data_rd
&
WM97XX_PEN_DOWN
))
return
RC_PENUP
;
wm
->
pen_probably_down
=
1
;
}
/* set up digitiser */
if
(
wm
->
mach_ops
&&
wm
->
mach_ops
->
pre_sample
)
wm
->
mach_ops
->
pre_sample
(
WM97XX_ADCSEL_X
|
WM97XX_ADCSEL_Y
);
wm97xx_reg_write
(
wm
,
AC97_WM97XX_DIGITISER1
,
WM97XX_COO
|
WM97XX_POLL
|
WM97XX_DELAY
(
delay
));
/* wait 3 AC97 time slots + delay for conversion and read x */
poll_delay
(
delay
);
data
->
x
=
wm97xx_reg_read
(
wm
,
AC97_WM97XX_DIGITISER_RD
);
/* wait for POLL to go low */
while
((
wm97xx_reg_read
(
wm
,
AC97_WM97XX_DIGITISER1
)
&
WM97XX_POLL
)
&&
timeout
)
{
udelay
(
AC97_LINK_FRAME
);
timeout
--
;
}
if
(
timeout
<=
0
)
{
/* If PDEN is set, we can get a timeout when pen goes up */
if
(
is_pden
(
wm
))
wm
->
pen_probably_down
=
0
;
else
dev_dbg
(
wm
->
dev
,
"adc sample timeout"
);
return
RC_PENUP
;
}
/* read back y data */
data
->
y
=
wm97xx_reg_read
(
wm
,
AC97_WM97XX_DIGITISER_RD
);
if
(
pil
)
data
->
p
=
wm97xx_reg_read
(
wm
,
AC97_WM97XX_DIGITISER_RD
);
else
data
->
p
=
DEFAULT_PRESSURE
;
if
(
wm
->
mach_ops
&&
wm
->
mach_ops
->
post_sample
)
wm
->
mach_ops
->
post_sample
(
WM97XX_ADCSEL_X
|
WM97XX_ADCSEL_Y
);
/* check we have correct sample */
if
(
!
(
data
->
x
&
WM97XX_ADCSEL_X
)
||
!
(
data
->
y
&
WM97XX_ADCSEL_Y
))
goto
err
;
if
(
pil
&&
!
(
data
->
p
&
WM97XX_ADCSEL_PRES
))
goto
err
;
if
(
!
(
data
->
x
&
WM97XX_PEN_DOWN
)
||
!
(
data
->
y
&
WM97XX_PEN_DOWN
))
{
wm
->
pen_probably_down
=
0
;
return
RC_PENUP
;
}
return
RC_VALID
;
err:
return
0
;
}
/*
* Sample the WM9712 touchscreen in polling mode
*/
static
int
wm9712_poll_touch
(
struct
wm97xx
*
wm
,
struct
wm97xx_data
*
data
)
{
int
rc
;
if
(
coord
)
{
rc
=
wm9712_poll_coord
(
wm
,
data
);
if
(
rc
!=
RC_VALID
)
return
rc
;
}
else
{
rc
=
wm9712_poll_sample
(
wm
,
WM97XX_ADCSEL_X
,
&
data
->
x
);
if
(
rc
!=
RC_VALID
)
return
rc
;
rc
=
wm9712_poll_sample
(
wm
,
WM97XX_ADCSEL_Y
,
&
data
->
y
);
if
(
rc
!=
RC_VALID
)
return
rc
;
if
(
pil
&&
!
five_wire
)
{
rc
=
wm9712_poll_sample
(
wm
,
WM97XX_ADCSEL_PRES
,
&
data
->
p
);
if
(
rc
!=
RC_VALID
)
return
rc
;
}
else
data
->
p
=
DEFAULT_PRESSURE
;
}
return
RC_VALID
;
}
/*
* Enable WM9712 continuous mode, i.e. touch data is streamed across
* an AC97 slot
*/
static
int
wm9712_acc_enable
(
struct
wm97xx
*
wm
,
int
enable
)
{
u16
dig1
,
dig2
;
int
ret
=
0
;
dig1
=
wm
->
dig
[
1
];
dig2
=
wm
->
dig
[
2
];
if
(
enable
)
{
/* continous mode */
if
(
wm
->
mach_ops
->
acc_startup
)
{
ret
=
wm
->
mach_ops
->
acc_startup
(
wm
);
if
(
ret
<
0
)
return
ret
;
}
dig1
&=
~
(
WM97XX_CM_RATE_MASK
|
WM97XX_ADCSEL_MASK
|
WM97XX_DELAY_MASK
|
WM97XX_SLT_MASK
);
dig1
|=
WM97XX_CTC
|
WM97XX_COO
|
WM97XX_SLEN
|
WM97XX_DELAY
(
delay
)
|
WM97XX_SLT
(
wm
->
acc_slot
)
|
WM97XX_RATE
(
wm
->
acc_rate
);
if
(
pil
)
dig1
|=
WM97XX_ADCSEL_PRES
;
dig2
|=
WM9712_PDEN
;
}
else
{
dig1
&=
~
(
WM97XX_CTC
|
WM97XX_COO
|
WM97XX_SLEN
);
dig2
&=
~
WM9712_PDEN
;
if
(
wm
->
mach_ops
->
acc_shutdown
)
wm
->
mach_ops
->
acc_shutdown
(
wm
);
}
wm97xx_reg_write
(
wm
,
AC97_WM97XX_DIGITISER1
,
dig1
);
wm97xx_reg_write
(
wm
,
AC97_WM97XX_DIGITISER2
,
dig2
);
return
0
;
}
struct
wm97xx_codec_drv
wm9712_codec
=
{
.
id
=
WM9712_ID2
,
.
name
=
"wm9712"
,
.
poll_sample
=
wm9712_poll_sample
,
.
poll_touch
=
wm9712_poll_touch
,
.
acc_enable
=
wm9712_acc_enable
,
.
phy_init
=
wm9712_phy_init
,
.
dig_enable
=
wm9712_dig_enable
,
.
dig_restore
=
wm9712_dig_restore
,
.
aux_prepare
=
wm9712_aux_prepare
,
};
EXPORT_SYMBOL_GPL
(
wm9712_codec
);
/* Module information */
MODULE_AUTHOR
(
"Liam Girdwood <liam.girdwood@wolfsonmicro.com>"
);
MODULE_DESCRIPTION
(
"WM9712 Touch Screen Driver"
);
MODULE_LICENSE
(
"GPL"
);
drivers/input/touchscreen/wm9713.c
0 → 100644
View file @
308f0a58
/*
* wm9713.c -- Codec touch driver for Wolfson WM9713 AC97 Codec.
*
* Copyright 2003, 2004, 2005, 2006, 2007, 2008 Wolfson Microelectronics PLC.
* Author: Liam Girdwood
* liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
* Parts Copyright : Ian Molton <spyro@f2s.com>
* Andrew Zabolotny <zap@homelink.ru>
* Russell King <rmk@arm.linux.org.uk>
*
* 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/moduleparam.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/bitops.h>
#include <linux/wm97xx.h>
#define TS_NAME "wm97xx"
#define WM9713_VERSION "1.00"
#define DEFAULT_PRESSURE 0xb0c0
/*
* Module parameters
*/
/*
* Set internal pull up for pen detect.
*
* Pull up is in the range 1.02k (least sensitive) to 64k (most sensitive)
* i.e. pull up resistance = 64k Ohms / rpu.
*
* Adjust this value if you are having problems with pen detect not
* detecting any down event.
*/
static
int
rpu
=
8
;
module_param
(
rpu
,
int
,
0
);
MODULE_PARM_DESC
(
rpu
,
"Set internal pull up resitor for pen detect."
);
/*
* Set current used for pressure measurement.
*
* Set pil = 2 to use 400uA
* pil = 1 to use 200uA and
* pil = 0 to disable pressure measurement.
*
* This is used to increase the range of values returned by the adc
* when measureing touchpanel pressure.
*/
static
int
pil
;
module_param
(
pil
,
int
,
0
);
MODULE_PARM_DESC
(
pil
,
"Set current used for pressure measurement."
);
/*
* Set threshold for pressure measurement.
*
* Pen down pressure below threshold is ignored.
*/
static
int
pressure
=
DEFAULT_PRESSURE
&
0xfff
;
module_param
(
pressure
,
int
,
0
);
MODULE_PARM_DESC
(
pressure
,
"Set threshold for pressure measurement."
);
/*
* Set adc sample delay.
*
* For accurate touchpanel measurements, some settling time may be
* required between the switch matrix applying a voltage across the
* touchpanel plate and the ADC sampling the signal.
*
* This delay can be set by setting delay = n, where n is the array
* position of the delay in the array delay_table below.
* Long delays > 1ms are supported for completeness, but are not
* recommended.
*/
static
int
delay
=
4
;
module_param
(
delay
,
int
,
0
);
MODULE_PARM_DESC
(
delay
,
"Set adc sample delay."
);
/*
* Set adc mask function.
*
* Sources of glitch noise, such as signals driving an LCD display, may feed
* through to the touch screen plates and affect measurement accuracy. In
* order to minimise this, a signal may be applied to the MASK pin to delay or
* synchronise the sampling.
*
* 0 = No delay or sync
* 1 = High on pin stops conversions
* 2 = Edge triggered, edge on pin delays conversion by delay param (above)
* 3 = Edge triggered, edge on pin starts conversion after delay param
*/
static
int
mask
;
module_param
(
mask
,
int
,
0
);
MODULE_PARM_DESC
(
mask
,
"Set adc mask function."
);
/*
* Coordinate Polling Enable.
*
* Set to 1 to enable coordinate polling. e.g. x,y[,p] is sampled together
* for every poll.
*/
static
int
coord
;
module_param
(
coord
,
int
,
0
);
MODULE_PARM_DESC
(
coord
,
"Polling coordinate mode"
);
/*
* ADC sample delay times in uS
*/
static
const
int
delay_table
[]
=
{
21
,
/* 1 AC97 Link frames */
42
,
/* 2 */
84
,
/* 4 */
167
,
/* 8 */
333
,
/* 16 */
667
,
/* 32 */
1000
,
/* 48 */
1333
,
/* 64 */
2000
,
/* 96 */
2667
,
/* 128 */
3333
,
/* 160 */
4000
,
/* 192 */
4667
,
/* 224 */
5333
,
/* 256 */
6000
,
/* 288 */
0
/* No delay, switch matrix always on */
};
/*
* Delay after issuing a POLL command.
*
* The delay is 3 AC97 link frames + the touchpanel settling delay
*/
static
inline
void
poll_delay
(
int
d
)
{
udelay
(
3
*
AC97_LINK_FRAME
+
delay_table
[
d
]);
}
/*
* set up the physical settings of the WM9713
*/
static
void
wm9713_phy_init
(
struct
wm97xx
*
wm
)
{
u16
dig1
=
0
,
dig2
,
dig3
;
/* default values */
dig2
=
WM97XX_DELAY
(
4
)
|
WM97XX_SLT
(
5
);
dig3
=
WM9712_RPU
(
1
);
/* rpu */
if
(
rpu
)
{
dig3
&=
0xffc0
;
dig3
|=
WM9712_RPU
(
rpu
);
dev_info
(
wm
->
dev
,
"setting pen detect pull-up to %d Ohms
\n
"
,
64000
/
rpu
);
}
/* touchpanel pressure */
if
(
pil
==
2
)
{
dig3
|=
WM9712_PIL
;
dev_info
(
wm
->
dev
,
"setting pressure measurement current to 400uA."
);
}
else
if
(
pil
)
dev_info
(
wm
->
dev
,
"setting pressure measurement current to 200uA."
);
if
(
!
pil
)
pressure
=
0
;
/* sample settling delay */
if
(
delay
<
0
||
delay
>
15
)
{
dev_info
(
wm
->
dev
,
"supplied delay out of range."
);
delay
=
4
;
dev_info
(
wm
->
dev
,
"setting adc sample delay to %d u Secs."
,
delay_table
[
delay
]);
}
dig2
&=
0xff0f
;
dig2
|=
WM97XX_DELAY
(
delay
);
/* mask */
dig3
|=
((
mask
&
0x3
)
<<
4
);
if
(
coord
)
dig3
|=
WM9713_WAIT
;
wm
->
misc
=
wm97xx_reg_read
(
wm
,
0x5a
);
wm97xx_reg_write
(
wm
,
AC97_WM9713_DIG1
,
dig1
);
wm97xx_reg_write
(
wm
,
AC97_WM9713_DIG2
,
dig2
);
wm97xx_reg_write
(
wm
,
AC97_WM9713_DIG3
,
dig3
);
wm97xx_reg_write
(
wm
,
AC97_GPIO_STICKY
,
0x0
);
}
static
void
wm9713_dig_enable
(
struct
wm97xx
*
wm
,
int
enable
)
{
u16
val
;
if
(
enable
)
{
val
=
wm97xx_reg_read
(
wm
,
AC97_EXTENDED_MID
);
wm97xx_reg_write
(
wm
,
AC97_EXTENDED_MID
,
val
&
0x7fff
);
wm97xx_reg_write
(
wm
,
AC97_WM9713_DIG3
,
wm
->
dig
[
2
]
|
WM97XX_PRP_DET_DIG
);
wm97xx_reg_read
(
wm
,
AC97_WM97XX_DIGITISER_RD
);
/* dummy read */
}
else
{
wm97xx_reg_write
(
wm
,
AC97_WM9713_DIG3
,
wm
->
dig
[
2
]
&
~
WM97XX_PRP_DET_DIG
);
val
=
wm97xx_reg_read
(
wm
,
AC97_EXTENDED_MID
);
wm97xx_reg_write
(
wm
,
AC97_EXTENDED_MID
,
val
|
0x8000
);
}
}
static
void
wm9713_dig_restore
(
struct
wm97xx
*
wm
)
{
wm97xx_reg_write
(
wm
,
AC97_WM9713_DIG1
,
wm
->
dig_save
[
0
]);
wm97xx_reg_write
(
wm
,
AC97_WM9713_DIG2
,
wm
->
dig_save
[
1
]);
wm97xx_reg_write
(
wm
,
AC97_WM9713_DIG3
,
wm
->
dig_save
[
2
]);
}
static
void
wm9713_aux_prepare
(
struct
wm97xx
*
wm
)
{
memcpy
(
wm
->
dig_save
,
wm
->
dig
,
sizeof
(
wm
->
dig
));
wm97xx_reg_write
(
wm
,
AC97_WM9713_DIG1
,
0
);
wm97xx_reg_write
(
wm
,
AC97_WM9713_DIG2
,
0
);
wm97xx_reg_write
(
wm
,
AC97_WM9713_DIG3
,
WM97XX_PRP_DET_DIG
);
}
static
inline
int
is_pden
(
struct
wm97xx
*
wm
)
{
return
wm
->
dig
[
2
]
&
WM9713_PDEN
;
}
/*
* Read a sample from the WM9713 adc in polling mode.
*/
static
int
wm9713_poll_sample
(
struct
wm97xx
*
wm
,
int
adcsel
,
int
*
sample
)
{
u16
dig1
;
int
timeout
=
5
*
delay
;
if
(
!
wm
->
pen_probably_down
)
{
u16
data
=
wm97xx_reg_read
(
wm
,
AC97_WM97XX_DIGITISER_RD
);
if
(
!
(
data
&
WM97XX_PEN_DOWN
))
return
RC_PENUP
;
wm
->
pen_probably_down
=
1
;
}
/* set up digitiser */
if
(
adcsel
&
0x8000
)
adcsel
=
1
<<
((
adcsel
&
0x7fff
)
+
3
);
dig1
=
wm97xx_reg_read
(
wm
,
AC97_WM9713_DIG1
);
dig1
&=
~
WM9713_ADCSEL_MASK
;
if
(
wm
->
mach_ops
&&
wm
->
mach_ops
->
pre_sample
)
wm
->
mach_ops
->
pre_sample
(
adcsel
);
wm97xx_reg_write
(
wm
,
AC97_WM9713_DIG1
,
dig1
|
adcsel
|
WM9713_POLL
);
/* wait 3 AC97 time slots + delay for conversion */
poll_delay
(
delay
);
/* wait for POLL to go low */
while
((
wm97xx_reg_read
(
wm
,
AC97_WM9713_DIG1
)
&
WM9713_POLL
)
&&
timeout
)
{
udelay
(
AC97_LINK_FRAME
);
timeout
--
;
}
if
(
timeout
<=
0
)
{
/* If PDEN is set, we can get a timeout when pen goes up */
if
(
is_pden
(
wm
))
wm
->
pen_probably_down
=
0
;
else
dev_dbg
(
wm
->
dev
,
"adc sample timeout"
);
return
RC_PENUP
;
}
*
sample
=
wm97xx_reg_read
(
wm
,
AC97_WM97XX_DIGITISER_RD
);
if
(
wm
->
mach_ops
&&
wm
->
mach_ops
->
post_sample
)
wm
->
mach_ops
->
post_sample
(
adcsel
);
/* check we have correct sample */
if
((
*
sample
&
WM97XX_ADCSRC_MASK
)
!=
ffs
(
adcsel
>>
1
)
<<
12
)
{
dev_dbg
(
wm
->
dev
,
"adc wrong sample, read %x got %x"
,
adcsel
,
*
sample
&
WM97XX_ADCSRC_MASK
);
return
RC_PENUP
;
}
if
(
!
(
*
sample
&
WM97XX_PEN_DOWN
))
{
wm
->
pen_probably_down
=
0
;
return
RC_PENUP
;
}
return
RC_VALID
;
}
/*
* Read a coordinate from the WM9713 adc in polling mode.
*/
static
int
wm9713_poll_coord
(
struct
wm97xx
*
wm
,
struct
wm97xx_data
*
data
)
{
u16
dig1
;
int
timeout
=
5
*
delay
;
if
(
!
wm
->
pen_probably_down
)
{
u16
val
=
wm97xx_reg_read
(
wm
,
AC97_WM97XX_DIGITISER_RD
);
if
(
!
(
val
&
WM97XX_PEN_DOWN
))
return
RC_PENUP
;
wm
->
pen_probably_down
=
1
;
}
/* set up digitiser */
dig1
=
wm97xx_reg_read
(
wm
,
AC97_WM9713_DIG1
);
dig1
&=
~
WM9713_ADCSEL_MASK
;
if
(
pil
)
dig1
|=
WM9713_ADCSEL_PRES
;
if
(
wm
->
mach_ops
&&
wm
->
mach_ops
->
pre_sample
)
wm
->
mach_ops
->
pre_sample
(
WM97XX_ADCSEL_X
|
WM97XX_ADCSEL_Y
);
wm97xx_reg_write
(
wm
,
AC97_WM9713_DIG1
,
dig1
|
WM9713_POLL
|
WM9713_COO
);
/* wait 3 AC97 time slots + delay for conversion */
poll_delay
(
delay
);
data
->
x
=
wm97xx_reg_read
(
wm
,
AC97_WM97XX_DIGITISER_RD
);
/* wait for POLL to go low */
while
((
wm97xx_reg_read
(
wm
,
AC97_WM9713_DIG1
)
&
WM9713_POLL
)
&&
timeout
)
{
udelay
(
AC97_LINK_FRAME
);
timeout
--
;
}
if
(
timeout
<=
0
)
{
/* If PDEN is set, we can get a timeout when pen goes up */
if
(
is_pden
(
wm
))
wm
->
pen_probably_down
=
0
;
else
dev_dbg
(
wm
->
dev
,
"adc sample timeout"
);
return
RC_PENUP
;
}
/* read back data */
data
->
y
=
wm97xx_reg_read
(
wm
,
AC97_WM97XX_DIGITISER_RD
);
if
(
pil
)
data
->
p
=
wm97xx_reg_read
(
wm
,
AC97_WM97XX_DIGITISER_RD
);
else
data
->
p
=
DEFAULT_PRESSURE
;
if
(
wm
->
mach_ops
&&
wm
->
mach_ops
->
post_sample
)
wm
->
mach_ops
->
post_sample
(
WM97XX_ADCSEL_X
|
WM97XX_ADCSEL_Y
);
/* check we have correct sample */
if
(
!
(
data
->
x
&
WM97XX_ADCSEL_X
)
||
!
(
data
->
y
&
WM97XX_ADCSEL_Y
))
goto
err
;
if
(
pil
&&
!
(
data
->
p
&
WM97XX_ADCSEL_PRES
))
goto
err
;
if
(
!
(
data
->
x
&
WM97XX_PEN_DOWN
)
||
!
(
data
->
y
&
WM97XX_PEN_DOWN
))
{
wm
->
pen_probably_down
=
0
;
return
RC_PENUP
;
}
return
RC_VALID
;
err:
return
0
;
}
/*
* Sample the WM9713 touchscreen in polling mode
*/
static
int
wm9713_poll_touch
(
struct
wm97xx
*
wm
,
struct
wm97xx_data
*
data
)
{
int
rc
;
if
(
coord
)
{
rc
=
wm9713_poll_coord
(
wm
,
data
);
if
(
rc
!=
RC_VALID
)
return
rc
;
}
else
{
rc
=
wm9713_poll_sample
(
wm
,
WM9713_ADCSEL_X
,
&
data
->
x
);
if
(
rc
!=
RC_VALID
)
return
rc
;
rc
=
wm9713_poll_sample
(
wm
,
WM9713_ADCSEL_Y
,
&
data
->
y
);
if
(
rc
!=
RC_VALID
)
return
rc
;
if
(
pil
)
{
rc
=
wm9713_poll_sample
(
wm
,
WM9713_ADCSEL_PRES
,
&
data
->
p
);
if
(
rc
!=
RC_VALID
)
return
rc
;
}
else
data
->
p
=
DEFAULT_PRESSURE
;
}
return
RC_VALID
;
}
/*
* Enable WM9713 continuous mode, i.e. touch data is streamed across
* an AC97 slot
*/
static
int
wm9713_acc_enable
(
struct
wm97xx
*
wm
,
int
enable
)
{
u16
dig1
,
dig2
,
dig3
;
int
ret
=
0
;
dig1
=
wm
->
dig
[
0
];
dig2
=
wm
->
dig
[
1
];
dig3
=
wm
->
dig
[
2
];
if
(
enable
)
{
/* continous mode */
if
(
wm
->
mach_ops
->
acc_startup
&&
(
ret
=
wm
->
mach_ops
->
acc_startup
(
wm
))
<
0
)
return
ret
;
dig1
&=
~
WM9713_ADCSEL_MASK
;
dig1
|=
WM9713_CTC
|
WM9713_COO
|
WM9713_ADCSEL_X
|
WM9713_ADCSEL_Y
;
if
(
pil
)
dig1
|=
WM9713_ADCSEL_PRES
;
dig2
&=
~
(
WM97XX_DELAY_MASK
|
WM97XX_SLT_MASK
|
WM97XX_CM_RATE_MASK
);
dig2
|=
WM97XX_SLEN
|
WM97XX_DELAY
(
delay
)
|
WM97XX_SLT
(
wm
->
acc_slot
)
|
WM97XX_RATE
(
wm
->
acc_rate
);
dig3
|=
WM9713_PDEN
;
}
else
{
dig1
&=
~
(
WM9713_CTC
|
WM9713_COO
);
dig2
&=
~
WM97XX_SLEN
;
dig3
&=
~
WM9713_PDEN
;
if
(
wm
->
mach_ops
->
acc_shutdown
)
wm
->
mach_ops
->
acc_shutdown
(
wm
);
}
wm97xx_reg_write
(
wm
,
AC97_WM9713_DIG1
,
dig1
);
wm97xx_reg_write
(
wm
,
AC97_WM9713_DIG2
,
dig2
);
wm97xx_reg_write
(
wm
,
AC97_WM9713_DIG3
,
dig3
);
return
ret
;
}
struct
wm97xx_codec_drv
wm9713_codec
=
{
.
id
=
WM9713_ID2
,
.
name
=
"wm9713"
,
.
poll_sample
=
wm9713_poll_sample
,
.
poll_touch
=
wm9713_poll_touch
,
.
acc_enable
=
wm9713_acc_enable
,
.
phy_init
=
wm9713_phy_init
,
.
dig_enable
=
wm9713_dig_enable
,
.
dig_restore
=
wm9713_dig_restore
,
.
aux_prepare
=
wm9713_aux_prepare
,
};
EXPORT_SYMBOL_GPL
(
wm9713_codec
);
/* Module information */
MODULE_AUTHOR
(
"Liam Girdwood <liam.girdwood@wolfsonmicro.com>"
);
MODULE_DESCRIPTION
(
"WM9713 Touch Screen Driver"
);
MODULE_LICENSE
(
"GPL"
);
drivers/input/touchscreen/wm97xx-core.c
0 → 100644
View file @
308f0a58
/*
* wm97xx-core.c -- Touch screen driver core for Wolfson WM9705, WM9712
* and WM9713 AC97 Codecs.
*
* Copyright 2003, 2004, 2005, 2006, 2007, 2008 Wolfson Microelectronics PLC.
* Author: Liam Girdwood
* liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
* Parts Copyright : Ian Molton <spyro@f2s.com>
* Andrew Zabolotny <zap@homelink.ru>
* Russell King <rmk@arm.linux.org.uk>
*
* 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.
*
* Notes:
*
* Features:
* - supports WM9705, WM9712, WM9713
* - polling mode
* - continuous mode (arch-dependent)
* - adjustable rpu/dpp settings
* - adjustable pressure current
* - adjustable sample settle delay
* - 4 and 5 wire touchscreens (5 wire is WM9712 only)
* - pen down detection
* - battery monitor
* - sample AUX adcs
* - power management
* - codec GPIO
* - codec event notification
* Todo
* - Support for async sampling control for noisy LCDs.
*
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/proc_fs.h>
#include <linux/pm.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/workqueue.h>
#include <linux/wm97xx.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#define TS_NAME "wm97xx"
#define WM_CORE_VERSION "1.00"
#define DEFAULT_PRESSURE 0xb0c0
/*
* Touchscreen absolute values
*
* These parameters are used to help the input layer discard out of
* range readings and reduce jitter etc.
*
* o min, max:- indicate the min and max values your touch screen returns
* o fuzz:- use a higher number to reduce jitter
*
* The default values correspond to Mainstone II in QVGA mode
*
* Please read
* Documentation/input/input-programming.txt for more details.
*/
static
int
abs_x
[
3
]
=
{
350
,
3900
,
5
};
module_param_array
(
abs_x
,
int
,
NULL
,
0
);
MODULE_PARM_DESC
(
abs_x
,
"Touchscreen absolute X min, max, fuzz"
);
static
int
abs_y
[
3
]
=
{
320
,
3750
,
40
};
module_param_array
(
abs_y
,
int
,
NULL
,
0
);
MODULE_PARM_DESC
(
abs_y
,
"Touchscreen absolute Y min, max, fuzz"
);
static
int
abs_p
[
3
]
=
{
0
,
150
,
4
};
module_param_array
(
abs_p
,
int
,
NULL
,
0
);
MODULE_PARM_DESC
(
abs_p
,
"Touchscreen absolute Pressure min, max, fuzz"
);
/*
* wm97xx IO access, all IO locking done by AC97 layer
*/
int
wm97xx_reg_read
(
struct
wm97xx
*
wm
,
u16
reg
)
{
if
(
wm
->
ac97
)
return
wm
->
ac97
->
bus
->
ops
->
read
(
wm
->
ac97
,
reg
);
else
return
-
1
;
}
EXPORT_SYMBOL_GPL
(
wm97xx_reg_read
);
void
wm97xx_reg_write
(
struct
wm97xx
*
wm
,
u16
reg
,
u16
val
)
{
/* cache digitiser registers */
if
(
reg
>=
AC97_WM9713_DIG1
&&
reg
<=
AC97_WM9713_DIG3
)
wm
->
dig
[(
reg
-
AC97_WM9713_DIG1
)
>>
1
]
=
val
;
/* cache gpio regs */
if
(
reg
>=
AC97_GPIO_CFG
&&
reg
<=
AC97_MISC_AFE
)
wm
->
gpio
[(
reg
-
AC97_GPIO_CFG
)
>>
1
]
=
val
;
/* wm9713 irq reg */
if
(
reg
==
0x5a
)
wm
->
misc
=
val
;
if
(
wm
->
ac97
)
wm
->
ac97
->
bus
->
ops
->
write
(
wm
->
ac97
,
reg
,
val
);
}
EXPORT_SYMBOL_GPL
(
wm97xx_reg_write
);
/**
* wm97xx_read_aux_adc - Read the aux adc.
* @wm: wm97xx device.
* @adcsel: codec ADC to be read
*
* Reads the selected AUX ADC.
*/
int
wm97xx_read_aux_adc
(
struct
wm97xx
*
wm
,
u16
adcsel
)
{
int
power_adc
=
0
,
auxval
;
u16
power
=
0
;
/* get codec */
mutex_lock
(
&
wm
->
codec_mutex
);
/* When the touchscreen is not in use, we may have to power up
* the AUX ADC before we can use sample the AUX inputs->
*/
if
(
wm
->
id
==
WM9713_ID2
&&
(
power
=
wm97xx_reg_read
(
wm
,
AC97_EXTENDED_MID
))
&
0x8000
)
{
power_adc
=
1
;
wm97xx_reg_write
(
wm
,
AC97_EXTENDED_MID
,
power
&
0x7fff
);
}
/* Prepare the codec for AUX reading */
wm
->
codec
->
aux_prepare
(
wm
);
/* Turn polling mode on to read AUX ADC */
wm
->
pen_probably_down
=
1
;
wm
->
codec
->
poll_sample
(
wm
,
adcsel
,
&
auxval
);
if
(
power_adc
)
wm97xx_reg_write
(
wm
,
AC97_EXTENDED_MID
,
power
|
0x8000
);
wm
->
codec
->
dig_restore
(
wm
);
wm
->
pen_probably_down
=
0
;
mutex_unlock
(
&
wm
->
codec_mutex
);
return
auxval
&
0xfff
;
}
EXPORT_SYMBOL_GPL
(
wm97xx_read_aux_adc
);
/**
* wm97xx_get_gpio - Get the status of a codec GPIO.
* @wm: wm97xx device.
* @gpio: gpio
*
* Get the status of a codec GPIO pin
*/
enum
wm97xx_gpio_status
wm97xx_get_gpio
(
struct
wm97xx
*
wm
,
u32
gpio
)
{
u16
status
;
enum
wm97xx_gpio_status
ret
;
mutex_lock
(
&
wm
->
codec_mutex
);
status
=
wm97xx_reg_read
(
wm
,
AC97_GPIO_STATUS
);
if
(
status
&
gpio
)
ret
=
WM97XX_GPIO_HIGH
;
else
ret
=
WM97XX_GPIO_LOW
;
mutex_unlock
(
&
wm
->
codec_mutex
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
wm97xx_get_gpio
);
/**
* wm97xx_set_gpio - Set the status of a codec GPIO.
* @wm: wm97xx device.
* @gpio: gpio
*
*
* Set the status of a codec GPIO pin
*/
void
wm97xx_set_gpio
(
struct
wm97xx
*
wm
,
u32
gpio
,
enum
wm97xx_gpio_status
status
)
{
u16
reg
;
mutex_lock
(
&
wm
->
codec_mutex
);
reg
=
wm97xx_reg_read
(
wm
,
AC97_GPIO_STATUS
);
if
(
status
&
WM97XX_GPIO_HIGH
)
reg
|=
gpio
;
else
reg
&=
~
gpio
;
if
(
wm
->
id
==
WM9712_ID2
)
wm97xx_reg_write
(
wm
,
AC97_GPIO_STATUS
,
reg
<<
1
);
else
wm97xx_reg_write
(
wm
,
AC97_GPIO_STATUS
,
reg
);
mutex_unlock
(
&
wm
->
codec_mutex
);
}
EXPORT_SYMBOL_GPL
(
wm97xx_set_gpio
);
/*
* Codec GPIO pin configuration, this sets pin direction, polarity,
* stickyness and wake up.
*/
void
wm97xx_config_gpio
(
struct
wm97xx
*
wm
,
u32
gpio
,
enum
wm97xx_gpio_dir
dir
,
enum
wm97xx_gpio_pol
pol
,
enum
wm97xx_gpio_sticky
sticky
,
enum
wm97xx_gpio_wake
wake
)
{
u16
reg
;
mutex_lock
(
&
wm
->
codec_mutex
);
reg
=
wm97xx_reg_read
(
wm
,
AC97_GPIO_POLARITY
);
if
(
pol
==
WM97XX_GPIO_POL_HIGH
)
reg
|=
gpio
;
else
reg
&=
~
gpio
;
wm97xx_reg_write
(
wm
,
AC97_GPIO_POLARITY
,
reg
);
reg
=
wm97xx_reg_read
(
wm
,
AC97_GPIO_STICKY
);
if
(
sticky
==
WM97XX_GPIO_STICKY
)
reg
|=
gpio
;
else
reg
&=
~
gpio
;
wm97xx_reg_write
(
wm
,
AC97_GPIO_STICKY
,
reg
);
reg
=
wm97xx_reg_read
(
wm
,
AC97_GPIO_WAKEUP
);
if
(
wake
==
WM97XX_GPIO_WAKE
)
reg
|=
gpio
;
else
reg
&=
~
gpio
;
wm97xx_reg_write
(
wm
,
AC97_GPIO_WAKEUP
,
reg
);
reg
=
wm97xx_reg_read
(
wm
,
AC97_GPIO_CFG
);
if
(
dir
==
WM97XX_GPIO_IN
)
reg
|=
gpio
;
else
reg
&=
~
gpio
;
wm97xx_reg_write
(
wm
,
AC97_GPIO_CFG
,
reg
);
mutex_unlock
(
&
wm
->
codec_mutex
);
}
EXPORT_SYMBOL_GPL
(
wm97xx_config_gpio
);
/*
* Configure the WM97XX_PRP value to use while system is suspended.
* If a value other than 0 is set then WM97xx pen detection will be
* left enabled in the configured mode while the system is in suspend,
* the device has users and suspend has not been disabled via the
* wakeup sysfs entries.
*
* @wm: WM97xx device to configure
* @mode: WM97XX_PRP value to configure while suspended
*/
void
wm97xx_set_suspend_mode
(
struct
wm97xx
*
wm
,
u16
mode
)
{
wm
->
suspend_mode
=
mode
;
device_init_wakeup
(
&
wm
->
input_dev
->
dev
,
mode
!=
0
);
}
EXPORT_SYMBOL_GPL
(
wm97xx_set_suspend_mode
);
/*
* Handle a pen down interrupt.
*/
static
void
wm97xx_pen_irq_worker
(
struct
work_struct
*
work
)
{
struct
wm97xx
*
wm
=
container_of
(
work
,
struct
wm97xx
,
pen_event_work
);
int
pen_was_down
=
wm
->
pen_is_down
;
/* do we need to enable the touch panel reader */
if
(
wm
->
id
==
WM9705_ID2
)
{
if
(
wm97xx_reg_read
(
wm
,
AC97_WM97XX_DIGITISER_RD
)
&
WM97XX_PEN_DOWN
)
wm
->
pen_is_down
=
1
;
else
wm
->
pen_is_down
=
0
;
}
else
{
u16
status
,
pol
;
mutex_lock
(
&
wm
->
codec_mutex
);
status
=
wm97xx_reg_read
(
wm
,
AC97_GPIO_STATUS
);
pol
=
wm97xx_reg_read
(
wm
,
AC97_GPIO_POLARITY
);
if
(
WM97XX_GPIO_13
&
pol
&
status
)
{
wm
->
pen_is_down
=
1
;
wm97xx_reg_write
(
wm
,
AC97_GPIO_POLARITY
,
pol
&
~
WM97XX_GPIO_13
);
}
else
{
wm
->
pen_is_down
=
0
;
wm97xx_reg_write
(
wm
,
AC97_GPIO_POLARITY
,
pol
|
WM97XX_GPIO_13
);
}
if
(
wm
->
id
==
WM9712_ID2
)
wm97xx_reg_write
(
wm
,
AC97_GPIO_STATUS
,
(
status
&
~
WM97XX_GPIO_13
)
<<
1
);
else
wm97xx_reg_write
(
wm
,
AC97_GPIO_STATUS
,
status
&
~
WM97XX_GPIO_13
);
mutex_unlock
(
&
wm
->
codec_mutex
);
}
/* If the system is not using continuous mode or it provides a
* pen down operation then we need to schedule polls while the
* pen is down. Otherwise the machine driver is responsible
* for scheduling reads.
*/
if
(
!
wm
->
mach_ops
->
acc_enabled
||
wm
->
mach_ops
->
acc_pen_down
)
{
if
(
wm
->
pen_is_down
&&
!
pen_was_down
)
{
/* Data is not availiable immediately on pen down */
queue_delayed_work
(
wm
->
ts_workq
,
&
wm
->
ts_reader
,
1
);
}
/* Let ts_reader report the pen up for debounce. */
if
(
!
wm
->
pen_is_down
&&
pen_was_down
)
wm
->
pen_is_down
=
1
;
}
if
(
!
wm
->
pen_is_down
&&
wm
->
mach_ops
->
acc_enabled
)
wm
->
mach_ops
->
acc_pen_up
(
wm
);
wm
->
mach_ops
->
irq_enable
(
wm
,
1
);
}
/*
* Codec PENDOWN irq handler
*
* We have to disable the codec interrupt in the handler because it
* can take upto 1ms to clear the interrupt source. We schedule a task
* in a work queue to do the actual interaction with the chip. The
* interrupt is then enabled again in the slow handler when the source
* has been cleared.
*/
static
irqreturn_t
wm97xx_pen_interrupt
(
int
irq
,
void
*
dev_id
)
{
struct
wm97xx
*
wm
=
dev_id
;
if
(
!
work_pending
(
&
wm
->
pen_event_work
))
{
wm
->
mach_ops
->
irq_enable
(
wm
,
0
);
queue_work
(
wm
->
ts_workq
,
&
wm
->
pen_event_work
);
}
return
IRQ_HANDLED
;
}
/*
* initialise pen IRQ handler and workqueue
*/
static
int
wm97xx_init_pen_irq
(
struct
wm97xx
*
wm
)
{
u16
reg
;
/* If an interrupt is supplied an IRQ enable operation must also be
* provided. */
BUG_ON
(
!
wm
->
mach_ops
->
irq_enable
);
if
(
request_irq
(
wm
->
pen_irq
,
wm97xx_pen_interrupt
,
IRQF_SHARED
|
IRQF_SAMPLE_RANDOM
,
"wm97xx-pen"
,
wm
))
{
dev_err
(
wm
->
dev
,
"Failed to register pen down interrupt, polling"
);
wm
->
pen_irq
=
0
;
return
-
EINVAL
;
}
/* Configure GPIO as interrupt source on WM971x */
if
(
wm
->
id
!=
WM9705_ID2
)
{
BUG_ON
(
!
wm
->
mach_ops
->
irq_gpio
);
reg
=
wm97xx_reg_read
(
wm
,
AC97_MISC_AFE
);
wm97xx_reg_write
(
wm
,
AC97_MISC_AFE
,
reg
&
~
(
wm
->
mach_ops
->
irq_gpio
));
reg
=
wm97xx_reg_read
(
wm
,
0x5a
);
wm97xx_reg_write
(
wm
,
0x5a
,
reg
&
~
0x0001
);
}
return
0
;
}
static
int
wm97xx_read_samples
(
struct
wm97xx
*
wm
)
{
struct
wm97xx_data
data
;
int
rc
;
mutex_lock
(
&
wm
->
codec_mutex
);
if
(
wm
->
mach_ops
&&
wm
->
mach_ops
->
acc_enabled
)
rc
=
wm
->
mach_ops
->
acc_pen_down
(
wm
);
else
rc
=
wm
->
codec
->
poll_touch
(
wm
,
&
data
);
if
(
rc
&
RC_PENUP
)
{
if
(
wm
->
pen_is_down
)
{
wm
->
pen_is_down
=
0
;
dev_dbg
(
wm
->
dev
,
"pen up
\n
"
);
input_report_abs
(
wm
->
input_dev
,
ABS_PRESSURE
,
0
);
input_sync
(
wm
->
input_dev
);
}
else
if
(
!
(
rc
&
RC_AGAIN
))
{
/* We need high frequency updates only while
* pen is down, the user never will be able to
* touch screen faster than a few times per
* second... On the other hand, when the user
* is actively working with the touchscreen we
* don't want to lose the quick response. So we
* will slowly increase sleep time after the
* pen is up and quicky restore it to ~one task
* switch when pen is down again.
*/
if
(
wm
->
ts_reader_interval
<
HZ
/
10
)
wm
->
ts_reader_interval
++
;
}
}
else
if
(
rc
&
RC_VALID
)
{
dev_dbg
(
wm
->
dev
,
"pen down: x=%x:%d, y=%x:%d, pressure=%x:%d
\n
"
,
data
.
x
>>
12
,
data
.
x
&
0xfff
,
data
.
y
>>
12
,
data
.
y
&
0xfff
,
data
.
p
>>
12
,
data
.
p
&
0xfff
);
input_report_abs
(
wm
->
input_dev
,
ABS_X
,
data
.
x
&
0xfff
);
input_report_abs
(
wm
->
input_dev
,
ABS_Y
,
data
.
y
&
0xfff
);
input_report_abs
(
wm
->
input_dev
,
ABS_PRESSURE
,
data
.
p
&
0xfff
);
input_sync
(
wm
->
input_dev
);
wm
->
pen_is_down
=
1
;
wm
->
ts_reader_interval
=
wm
->
ts_reader_min_interval
;
}
else
if
(
rc
&
RC_PENDOWN
)
{
dev_dbg
(
wm
->
dev
,
"pen down
\n
"
);
wm
->
pen_is_down
=
1
;
wm
->
ts_reader_interval
=
wm
->
ts_reader_min_interval
;
}
mutex_unlock
(
&
wm
->
codec_mutex
);
return
rc
;
}
/*
* The touchscreen sample reader.
*/
static
void
wm97xx_ts_reader
(
struct
work_struct
*
work
)
{
int
rc
;
struct
wm97xx
*
wm
=
container_of
(
work
,
struct
wm97xx
,
ts_reader
.
work
);
BUG_ON
(
!
wm
->
codec
);
do
{
rc
=
wm97xx_read_samples
(
wm
);
}
while
(
rc
&
RC_AGAIN
);
if
(
wm
->
pen_is_down
||
!
wm
->
pen_irq
)
queue_delayed_work
(
wm
->
ts_workq
,
&
wm
->
ts_reader
,
wm
->
ts_reader_interval
);
}
/**
* wm97xx_ts_input_open - Open the touch screen input device.
* @idev: Input device to be opened.
*
* Called by the input sub system to open a wm97xx touchscreen device.
* Starts the touchscreen thread and touch digitiser.
*/
static
int
wm97xx_ts_input_open
(
struct
input_dev
*
idev
)
{
struct
wm97xx
*
wm
=
input_get_drvdata
(
idev
);
wm
->
ts_workq
=
create_singlethread_workqueue
(
"kwm97xx"
);
if
(
wm
->
ts_workq
==
NULL
)
{
dev_err
(
wm
->
dev
,
"Failed to create workqueue
\n
"
);
return
-
EINVAL
;
}
/* start digitiser */
if
(
wm
->
mach_ops
&&
wm
->
mach_ops
->
acc_enabled
)
wm
->
codec
->
acc_enable
(
wm
,
1
);
wm
->
codec
->
dig_enable
(
wm
,
1
);
INIT_DELAYED_WORK
(
&
wm
->
ts_reader
,
wm97xx_ts_reader
);
INIT_WORK
(
&
wm
->
pen_event_work
,
wm97xx_pen_irq_worker
);
wm
->
ts_reader_min_interval
=
HZ
>=
100
?
HZ
/
100
:
1
;
if
(
wm
->
ts_reader_min_interval
<
1
)
wm
->
ts_reader_min_interval
=
1
;
wm
->
ts_reader_interval
=
wm
->
ts_reader_min_interval
;
wm
->
pen_is_down
=
0
;
if
(
wm
->
pen_irq
)
wm97xx_init_pen_irq
(
wm
);
else
dev_err
(
wm
->
dev
,
"No IRQ specified
\n
"
);
/* If we either don't have an interrupt for pen down events or
* failed to acquire it then we need to poll.
*/
if
(
wm
->
pen_irq
==
0
)
queue_delayed_work
(
wm
->
ts_workq
,
&
wm
->
ts_reader
,
wm
->
ts_reader_interval
);
return
0
;
}
/**
* wm97xx_ts_input_close - Close the touch screen input device.
* @idev: Input device to be closed.
*
* Called by the input sub system to close a wm97xx touchscreen
* device. Kills the touchscreen thread and stops the touch
* digitiser.
*/
static
void
wm97xx_ts_input_close
(
struct
input_dev
*
idev
)
{
struct
wm97xx
*
wm
=
input_get_drvdata
(
idev
);
u16
reg
;
if
(
wm
->
pen_irq
)
{
/* Return the interrupt to GPIO usage (disabling it) */
if
(
wm
->
id
!=
WM9705_ID2
)
{
BUG_ON
(
!
wm
->
mach_ops
->
irq_gpio
);
reg
=
wm97xx_reg_read
(
wm
,
AC97_MISC_AFE
);
wm97xx_reg_write
(
wm
,
AC97_MISC_AFE
,
reg
|
wm
->
mach_ops
->
irq_gpio
);
}
free_irq
(
wm
->
pen_irq
,
wm
);
}
wm
->
pen_is_down
=
0
;
/* Balance out interrupt disables/enables */
if
(
cancel_work_sync
(
&
wm
->
pen_event_work
))
wm
->
mach_ops
->
irq_enable
(
wm
,
1
);
/* ts_reader rearms itself so we need to explicitly stop it
* before we destroy the workqueue.
*/
cancel_delayed_work_sync
(
&
wm
->
ts_reader
);
destroy_workqueue
(
wm
->
ts_workq
);
/* stop digitiser */
wm
->
codec
->
dig_enable
(
wm
,
0
);
if
(
wm
->
mach_ops
&&
wm
->
mach_ops
->
acc_enabled
)
wm
->
codec
->
acc_enable
(
wm
,
0
);
}
static
int
wm97xx_probe
(
struct
device
*
dev
)
{
struct
wm97xx
*
wm
;
int
ret
=
0
,
id
=
0
;
wm
=
kzalloc
(
sizeof
(
struct
wm97xx
),
GFP_KERNEL
);
if
(
!
wm
)
return
-
ENOMEM
;
mutex_init
(
&
wm
->
codec_mutex
);
wm
->
dev
=
dev
;
dev
->
driver_data
=
wm
;
wm
->
ac97
=
to_ac97_t
(
dev
);
/* check that we have a supported codec */
id
=
wm97xx_reg_read
(
wm
,
AC97_VENDOR_ID1
);
if
(
id
!=
WM97XX_ID1
)
{
dev_err
(
dev
,
"Device with vendor %04x is not a wm97xx
\n
"
,
id
);
ret
=
-
ENODEV
;
goto
alloc_err
;
}
wm
->
id
=
wm97xx_reg_read
(
wm
,
AC97_VENDOR_ID2
);
dev_info
(
wm
->
dev
,
"detected a wm97%02x codec
\n
"
,
wm
->
id
&
0xff
);
switch
(
wm
->
id
&
0xff
)
{
#ifdef CONFIG_TOUCHSCREEN_WM9705
case
0x05
:
wm
->
codec
=
&
wm9705_codec
;
break
;
#endif
#ifdef CONFIG_TOUCHSCREEN_WM9712
case
0x12
:
wm
->
codec
=
&
wm9712_codec
;
break
;
#endif
#ifdef CONFIG_TOUCHSCREEN_WM9713
case
0x13
:
wm
->
codec
=
&
wm9713_codec
;
break
;
#endif
default:
dev_err
(
wm
->
dev
,
"Support for wm97%02x not compiled in.
\n
"
,
wm
->
id
&
0xff
);
ret
=
-
ENODEV
;
goto
alloc_err
;
}
wm
->
input_dev
=
input_allocate_device
();
if
(
wm
->
input_dev
==
NULL
)
{
ret
=
-
ENOMEM
;
goto
alloc_err
;
}
/* set up touch configuration */
wm
->
input_dev
->
name
=
"wm97xx touchscreen"
;
wm
->
input_dev
->
open
=
wm97xx_ts_input_open
;
wm
->
input_dev
->
close
=
wm97xx_ts_input_close
;
set_bit
(
EV_ABS
,
wm
->
input_dev
->
evbit
);
set_bit
(
ABS_X
,
wm
->
input_dev
->
absbit
);
set_bit
(
ABS_Y
,
wm
->
input_dev
->
absbit
);
set_bit
(
ABS_PRESSURE
,
wm
->
input_dev
->
absbit
);
input_set_abs_params
(
wm
->
input_dev
,
ABS_X
,
abs_x
[
0
],
abs_x
[
1
],
abs_x
[
2
],
0
);
input_set_abs_params
(
wm
->
input_dev
,
ABS_Y
,
abs_y
[
0
],
abs_y
[
1
],
abs_y
[
2
],
0
);
input_set_abs_params
(
wm
->
input_dev
,
ABS_PRESSURE
,
abs_p
[
0
],
abs_p
[
1
],
abs_p
[
2
],
0
);
input_set_drvdata
(
wm
->
input_dev
,
wm
);
wm
->
input_dev
->
dev
.
parent
=
dev
;
ret
=
input_register_device
(
wm
->
input_dev
);
if
(
ret
<
0
)
goto
dev_alloc_err
;
/* set up physical characteristics */
wm
->
codec
->
phy_init
(
wm
);
/* load gpio cache */
wm
->
gpio
[
0
]
=
wm97xx_reg_read
(
wm
,
AC97_GPIO_CFG
);
wm
->
gpio
[
1
]
=
wm97xx_reg_read
(
wm
,
AC97_GPIO_POLARITY
);
wm
->
gpio
[
2
]
=
wm97xx_reg_read
(
wm
,
AC97_GPIO_STICKY
);
wm
->
gpio
[
3
]
=
wm97xx_reg_read
(
wm
,
AC97_GPIO_WAKEUP
);
wm
->
gpio
[
4
]
=
wm97xx_reg_read
(
wm
,
AC97_GPIO_STATUS
);
wm
->
gpio
[
5
]
=
wm97xx_reg_read
(
wm
,
AC97_MISC_AFE
);
/* register our battery device */
wm
->
battery_dev
=
platform_device_alloc
(
"wm97xx-battery"
,
-
1
);
if
(
!
wm
->
battery_dev
)
{
ret
=
-
ENOMEM
;
goto
batt_err
;
}
platform_set_drvdata
(
wm
->
battery_dev
,
wm
);
wm
->
battery_dev
->
dev
.
parent
=
dev
;
ret
=
platform_device_add
(
wm
->
battery_dev
);
if
(
ret
<
0
)
goto
batt_reg_err
;
/* register our extended touch device (for machine specific
* extensions) */
wm
->
touch_dev
=
platform_device_alloc
(
"wm97xx-touch"
,
-
1
);
if
(
!
wm
->
touch_dev
)
{
ret
=
-
ENOMEM
;
goto
touch_err
;
}
platform_set_drvdata
(
wm
->
touch_dev
,
wm
);
wm
->
touch_dev
->
dev
.
parent
=
dev
;
ret
=
platform_device_add
(
wm
->
touch_dev
);
if
(
ret
<
0
)
goto
touch_reg_err
;
return
ret
;
touch_reg_err:
platform_device_put
(
wm
->
touch_dev
);
touch_err:
platform_device_unregister
(
wm
->
battery_dev
);
wm
->
battery_dev
=
NULL
;
batt_reg_err:
platform_device_put
(
wm
->
battery_dev
);
batt_err:
input_unregister_device
(
wm
->
input_dev
);
wm
->
input_dev
=
NULL
;
dev_alloc_err:
input_free_device
(
wm
->
input_dev
);
alloc_err:
kfree
(
wm
);
return
ret
;
}
static
int
wm97xx_remove
(
struct
device
*
dev
)
{
struct
wm97xx
*
wm
=
dev_get_drvdata
(
dev
);
platform_device_unregister
(
wm
->
battery_dev
);
platform_device_unregister
(
wm
->
touch_dev
);
input_unregister_device
(
wm
->
input_dev
);
kfree
(
wm
);
return
0
;
}
#ifdef CONFIG_PM
static
int
wm97xx_suspend
(
struct
device
*
dev
,
pm_message_t
state
)
{
struct
wm97xx
*
wm
=
dev_get_drvdata
(
dev
);
u16
reg
;
int
suspend_mode
;
if
(
device_may_wakeup
(
&
wm
->
input_dev
->
dev
))
suspend_mode
=
wm
->
suspend_mode
;
else
suspend_mode
=
0
;
if
(
wm
->
input_dev
->
users
)
cancel_delayed_work_sync
(
&
wm
->
ts_reader
);
/* Power down the digitiser (bypassing the cache for resume) */
reg
=
wm97xx_reg_read
(
wm
,
AC97_WM97XX_DIGITISER2
);
reg
&=
~
WM97XX_PRP_DET_DIG
;
if
(
wm
->
input_dev
->
users
)
reg
|=
suspend_mode
;
wm
->
ac97
->
bus
->
ops
->
write
(
wm
->
ac97
,
AC97_WM97XX_DIGITISER2
,
reg
);
/* WM9713 has an additional power bit - turn it off if there
* are no users or if suspend mode is zero. */
if
(
wm
->
id
==
WM9713_ID2
&&
(
!
wm
->
input_dev
->
users
||
!
suspend_mode
))
{
reg
=
wm97xx_reg_read
(
wm
,
AC97_EXTENDED_MID
)
|
0x8000
;
wm97xx_reg_write
(
wm
,
AC97_EXTENDED_MID
,
reg
);
}
return
0
;
}
static
int
wm97xx_resume
(
struct
device
*
dev
)
{
struct
wm97xx
*
wm
=
dev_get_drvdata
(
dev
);
/* restore digitiser and gpios */
if
(
wm
->
id
==
WM9713_ID2
)
{
wm97xx_reg_write
(
wm
,
AC97_WM9713_DIG1
,
wm
->
dig
[
0
]);
wm97xx_reg_write
(
wm
,
0x5a
,
wm
->
misc
);
if
(
wm
->
input_dev
->
users
)
{
u16
reg
;
reg
=
wm97xx_reg_read
(
wm
,
AC97_EXTENDED_MID
)
&
0x7fff
;
wm97xx_reg_write
(
wm
,
AC97_EXTENDED_MID
,
reg
);
}
}
wm97xx_reg_write
(
wm
,
AC97_WM9713_DIG2
,
wm
->
dig
[
1
]);
wm97xx_reg_write
(
wm
,
AC97_WM9713_DIG3
,
wm
->
dig
[
2
]);
wm97xx_reg_write
(
wm
,
AC97_GPIO_CFG
,
wm
->
gpio
[
0
]);
wm97xx_reg_write
(
wm
,
AC97_GPIO_POLARITY
,
wm
->
gpio
[
1
]);
wm97xx_reg_write
(
wm
,
AC97_GPIO_STICKY
,
wm
->
gpio
[
2
]);
wm97xx_reg_write
(
wm
,
AC97_GPIO_WAKEUP
,
wm
->
gpio
[
3
]);
wm97xx_reg_write
(
wm
,
AC97_GPIO_STATUS
,
wm
->
gpio
[
4
]);
wm97xx_reg_write
(
wm
,
AC97_MISC_AFE
,
wm
->
gpio
[
5
]);
if
(
wm
->
input_dev
->
users
&&
!
wm
->
pen_irq
)
{
wm
->
ts_reader_interval
=
wm
->
ts_reader_min_interval
;
queue_delayed_work
(
wm
->
ts_workq
,
&
wm
->
ts_reader
,
wm
->
ts_reader_interval
);
}
return
0
;
}
#else
#define wm97xx_suspend NULL
#define wm97xx_resume NULL
#endif
/*
* Machine specific operations
*/
int
wm97xx_register_mach_ops
(
struct
wm97xx
*
wm
,
struct
wm97xx_mach_ops
*
mach_ops
)
{
mutex_lock
(
&
wm
->
codec_mutex
);
if
(
wm
->
mach_ops
)
{
mutex_unlock
(
&
wm
->
codec_mutex
);
return
-
EINVAL
;
}
wm
->
mach_ops
=
mach_ops
;
mutex_unlock
(
&
wm
->
codec_mutex
);
return
0
;
}
EXPORT_SYMBOL_GPL
(
wm97xx_register_mach_ops
);
void
wm97xx_unregister_mach_ops
(
struct
wm97xx
*
wm
)
{
mutex_lock
(
&
wm
->
codec_mutex
);
wm
->
mach_ops
=
NULL
;
mutex_unlock
(
&
wm
->
codec_mutex
);
}
EXPORT_SYMBOL_GPL
(
wm97xx_unregister_mach_ops
);
static
struct
device_driver
wm97xx_driver
=
{
.
name
=
"ac97"
,
.
bus
=
&
ac97_bus_type
,
.
owner
=
THIS_MODULE
,
.
probe
=
wm97xx_probe
,
.
remove
=
wm97xx_remove
,
.
suspend
=
wm97xx_suspend
,
.
resume
=
wm97xx_resume
,
};
static
int
__init
wm97xx_init
(
void
)
{
return
driver_register
(
&
wm97xx_driver
);
}
static
void
__exit
wm97xx_exit
(
void
)
{
driver_unregister
(
&
wm97xx_driver
);
}
module_init
(
wm97xx_init
);
module_exit
(
wm97xx_exit
);
/* Module information */
MODULE_AUTHOR
(
"Liam Girdwood <liam.girdwood@wolfsonmicro.com>"
);
MODULE_DESCRIPTION
(
"WM97xx Core - Touch Screen / AUX ADC / GPIO Driver"
);
MODULE_LICENSE
(
"GPL"
);
drivers/macintosh/mac_hid.c
View file @
308f0a58
...
...
@@ -103,6 +103,9 @@ int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down)
return
0
;
}
static
struct
lock_class_key
emumousebtn_event_class
;
static
struct
lock_class_key
emumousebtn_mutex_class
;
static
int
emumousebtn_input_register
(
void
)
{
int
ret
;
...
...
@@ -111,6 +114,9 @@ static int emumousebtn_input_register(void)
if
(
!
emumousebtn
)
return
-
ENOMEM
;
lockdep_set_class
(
emumousebtn
->
event_lock
,
&
emumousebtn_event_class
);
lockdep_set_class
(
emumousebtn
->
mutex
,
&
emumousebtn_mutex_class
);
emumousebtn
->
name
=
"Macintosh mouse button emulation"
;
emumousebtn
->
id
.
bustype
=
BUS_ADB
;
emumousebtn
->
id
.
vendor
=
0x0001
;
...
...
include/linux/input.h
View file @
308f0a58
...
...
@@ -1025,10 +1025,6 @@ struct ff_effect {
* @node: used to place the device onto input_dev_list
*/
struct
input_dev
{
/* private: */
void
*
private
;
/* do not use */
/* public: */
const
char
*
name
;
const
char
*
phys
;
const
char
*
uniq
;
...
...
@@ -1238,12 +1234,12 @@ static inline void input_put_device(struct input_dev *dev)
static
inline
void
*
input_get_drvdata
(
struct
input_dev
*
dev
)
{
return
dev
->
private
;
return
dev
_get_drvdata
(
&
dev
->
dev
)
;
}
static
inline
void
input_set_drvdata
(
struct
input_dev
*
dev
,
void
*
data
)
{
dev
->
private
=
data
;
dev
_set_drvdata
(
&
dev
->
dev
,
data
)
;
}
int
__must_check
input_register_device
(
struct
input_dev
*
);
...
...
include/linux/keyboard.h
View file @
308f0a58
...
...
@@ -33,6 +33,7 @@ struct keyboard_notifier_param {
struct
vc_data
*
vc
;
/* VC on which the keyboard press was done */
int
down
;
/* Pressure of the key? */
int
shift
;
/* Current shift mask */
int
ledstate
;
/* Current led state */
unsigned
int
value
;
/* keycode, unicode value or keysym */
};
...
...
include/linux/serio.h
View file @
308f0a58
...
...
@@ -211,5 +211,6 @@ static inline void serio_unpin_driver(struct serio *serio)
#define SERIO_TOUCHWIN 0x33
#define SERIO_TAOSEVM 0x34
#define SERIO_FUJITSU 0x35
#define SERIO_ZHENHUA 0x36
#endif
include/linux/spi/ads7846.h
View file @
308f0a58
...
...
@@ -14,7 +14,8 @@ enum ads7846_filter {
struct
ads7846_platform_data
{
u16
model
;
/* 7843, 7845, 7846. */
u16
vref_delay_usecs
;
/* 0 for external vref; etc */
int
keep_vref_on
:
1
;
/* set to keep vref on for differential
u16
vref_mv
;
/* external vref value, milliVolts */
bool
keep_vref_on
;
/* set to keep vref on for differential
* measurements as well */
/* Settling time of the analog signals; a function of Vcc and the
...
...
include/linux/wm97xx.h
0 → 100644
View file @
308f0a58
/*
* Register bits and API for Wolfson WM97xx series of codecs
*/
#ifndef _LINUX_WM97XX_H
#define _LINUX_WM97XX_H
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
#include <sound/initval.h>
#include <linux/types.h>
#include <linux/list.h>
#include <linux/input.h>
/* Input device layer */
#include <linux/platform_device.h>
/*
* WM97xx AC97 Touchscreen registers
*/
#define AC97_WM97XX_DIGITISER1 0x76
#define AC97_WM97XX_DIGITISER2 0x78
#define AC97_WM97XX_DIGITISER_RD 0x7a
#define AC97_WM9713_DIG1 0x74
#define AC97_WM9713_DIG2 AC97_WM97XX_DIGITISER1
#define AC97_WM9713_DIG3 AC97_WM97XX_DIGITISER2
/*
* WM97xx register bits
*/
#define WM97XX_POLL 0x8000
/* initiate a polling measurement */
#define WM97XX_ADCSEL_X 0x1000
/* x coord measurement */
#define WM97XX_ADCSEL_Y 0x2000
/* y coord measurement */
#define WM97XX_ADCSEL_PRES 0x3000
/* pressure measurement */
#define WM97XX_ADCSEL_MASK 0x7000
#define WM97XX_COO 0x0800
/* enable coordinate mode */
#define WM97XX_CTC 0x0400
/* enable continuous mode */
#define WM97XX_CM_RATE_93 0x0000
/* 93.75Hz continuous rate */
#define WM97XX_CM_RATE_187 0x0100
/* 187.5Hz continuous rate */
#define WM97XX_CM_RATE_375 0x0200
/* 375Hz continuous rate */
#define WM97XX_CM_RATE_750 0x0300
/* 750Hz continuous rate */
#define WM97XX_CM_RATE_8K 0x00f0
/* 8kHz continuous rate */
#define WM97XX_CM_RATE_12K 0x01f0
/* 12kHz continuous rate */
#define WM97XX_CM_RATE_24K 0x02f0
/* 24kHz continuous rate */
#define WM97XX_CM_RATE_48K 0x03f0
/* 48kHz continuous rate */
#define WM97XX_CM_RATE_MASK 0x03f0
#define WM97XX_RATE(i) (((i & 3) << 8) | ((i & 4) ? 0xf0 : 0))
#define WM97XX_DELAY(i) ((i << 4) & 0x00f0)
/* sample delay times */
#define WM97XX_DELAY_MASK 0x00f0
#define WM97XX_SLEN 0x0008
/* slot read back enable */
#define WM97XX_SLT(i) ((i - 5) & 0x7)
/* panel slot (5-11) */
#define WM97XX_SLT_MASK 0x0007
#define WM97XX_PRP_DETW 0x4000
/* detect on, digitise off, wake */
#define WM97XX_PRP_DET 0x8000
/* detect on, digitise off, no wake */
#define WM97XX_PRP_DET_DIG 0xc000
/* setect on, digitise on */
#define WM97XX_RPR 0x2000
/* wake up on pen down */
#define WM97XX_PEN_DOWN 0x8000
/* pen is down */
#define WM97XX_ADCSRC_MASK 0x7000
/* ADC source mask */
#define WM97XX_AUX_ID1 0x8001
#define WM97XX_AUX_ID2 0x8002
#define WM97XX_AUX_ID3 0x8003
#define WM97XX_AUX_ID4 0x8004
/* WM9712 Bits */
#define WM9712_45W 0x1000
/* set for 5-wire touchscreen */
#define WM9712_PDEN 0x0800
/* measure only when pen down */
#define WM9712_WAIT 0x0200
/* wait until adc is read before next sample */
#define WM9712_PIL 0x0100
/* current used for pressure measurement. set 400uA else 200uA */
#define WM9712_MASK_HI 0x0040
/* hi on mask pin (47) stops conversions */
#define WM9712_MASK_EDGE 0x0080
/* rising/falling edge on pin delays sample */
#define WM9712_MASK_SYNC 0x00c0
/* rising/falling edge on mask initiates sample */
#define WM9712_RPU(i) (i&0x3f)
/* internal pull up on pen detect (64k / rpu) */
#define WM9712_PD(i) (0x1 << i)
/* power management */
/* WM9712 Registers */
#define AC97_WM9712_POWER 0x24
#define AC97_WM9712_REV 0x58
/* WM9705 Bits */
#define WM9705_PDEN 0x1000
/* measure only when pen is down */
#define WM9705_PINV 0x0800
/* inverts sense of pen down output */
#define WM9705_BSEN 0x0400
/* BUSY flag enable, pin47 is 1 when busy */
#define WM9705_BINV 0x0200
/* invert BUSY (pin47) output */
#define WM9705_WAIT 0x0100
/* wait until adc is read before next sample */
#define WM9705_PIL 0x0080
/* current used for pressure measurement. set 400uA else 200uA */
#define WM9705_PHIZ 0x0040
/* set PHONE and PCBEEP inputs to high impedance */
#define WM9705_MASK_HI 0x0010
/* hi on mask stops conversions */
#define WM9705_MASK_EDGE 0x0020
/* rising/falling edge on pin delays sample */
#define WM9705_MASK_SYNC 0x0030
/* rising/falling edge on mask initiates sample */
#define WM9705_PDD(i) (i & 0x000f)
/* pen detect comparator threshold */
/* WM9713 Bits */
#define WM9713_PDPOL 0x0400
/* Pen down polarity */
#define WM9713_POLL 0x0200
/* initiate a polling measurement */
#define WM9713_CTC 0x0100
/* enable continuous mode */
#define WM9713_ADCSEL_X 0x0002
/* X measurement */
#define WM9713_ADCSEL_Y 0x0004
/* Y measurement */
#define WM9713_ADCSEL_PRES 0x0008
/* Pressure measurement */
#define WM9713_COO 0x0001
/* enable coordinate mode */
#define WM9713_PDEN 0x0800
/* measure only when pen down */
#define WM9713_ADCSEL_MASK 0x00fe
/* ADC selection mask */
#define WM9713_WAIT 0x0200
/* coordinate wait */
/* AUX ADC ID's */
#define TS_COMP1 0x0
#define TS_COMP2 0x1
#define TS_BMON 0x2
#define TS_WIPER 0x3
/* ID numbers */
#define WM97XX_ID1 0x574d
#define WM9712_ID2 0x4c12
#define WM9705_ID2 0x4c05
#define WM9713_ID2 0x4c13
/* Codec GPIO's */
#define WM97XX_MAX_GPIO 16
#define WM97XX_GPIO_1 (1 << 1)
#define WM97XX_GPIO_2 (1 << 2)
#define WM97XX_GPIO_3 (1 << 3)
#define WM97XX_GPIO_4 (1 << 4)
#define WM97XX_GPIO_5 (1 << 5)
#define WM97XX_GPIO_6 (1 << 6)
#define WM97XX_GPIO_7 (1 << 7)
#define WM97XX_GPIO_8 (1 << 8)
#define WM97XX_GPIO_9 (1 << 9)
#define WM97XX_GPIO_10 (1 << 10)
#define WM97XX_GPIO_11 (1 << 11)
#define WM97XX_GPIO_12 (1 << 12)
#define WM97XX_GPIO_13 (1 << 13)
#define WM97XX_GPIO_14 (1 << 14)
#define WM97XX_GPIO_15 (1 << 15)
#define AC97_LINK_FRAME 21
/* time in uS for AC97 link frame */
/*---------------- Return codes from sample reading functions ---------------*/
/* More data is available; call the sample gathering function again */
#define RC_AGAIN 0x00000001
/* The returned sample is valid */
#define RC_VALID 0x00000002
/* The pen is up (the first RC_VALID without RC_PENUP means pen is down) */
#define RC_PENUP 0x00000004
/* The pen is down (RC_VALID implies RC_PENDOWN, but sometimes it is helpful
to tell the handler that the pen is down but we don't know yet his coords,
so the handler should not sleep or wait for pendown irq) */
#define RC_PENDOWN 0x00000008
/*
* The wm97xx driver provides a private API for writing platform-specific
* drivers.
*/
/* The structure used to return arch specific sampled data into */
struct
wm97xx_data
{
int
x
;
int
y
;
int
p
;
};
/*
* Codec GPIO status
*/
enum
wm97xx_gpio_status
{
WM97XX_GPIO_HIGH
,
WM97XX_GPIO_LOW
};
/*
* Codec GPIO direction
*/
enum
wm97xx_gpio_dir
{
WM97XX_GPIO_IN
,
WM97XX_GPIO_OUT
};
/*
* Codec GPIO polarity
*/
enum
wm97xx_gpio_pol
{
WM97XX_GPIO_POL_HIGH
,
WM97XX_GPIO_POL_LOW
};
/*
* Codec GPIO sticky
*/
enum
wm97xx_gpio_sticky
{
WM97XX_GPIO_STICKY
,
WM97XX_GPIO_NOTSTICKY
};
/*
* Codec GPIO wake
*/
enum
wm97xx_gpio_wake
{
WM97XX_GPIO_WAKE
,
WM97XX_GPIO_NOWAKE
};
/*
* Digitiser ioctl commands
*/
#define WM97XX_DIG_START 0x1
#define WM97XX_DIG_STOP 0x2
#define WM97XX_PHY_INIT 0x3
#define WM97XX_AUX_PREPARE 0x4
#define WM97XX_DIG_RESTORE 0x5
struct
wm97xx
;
extern
struct
wm97xx_codec_drv
wm9705_codec
;
extern
struct
wm97xx_codec_drv
wm9712_codec
;
extern
struct
wm97xx_codec_drv
wm9713_codec
;
/*
* Codec driver interface - allows mapping to WM9705/12/13 and newer codecs
*/
struct
wm97xx_codec_drv
{
u16
id
;
char
*
name
;
/* read 1 sample */
int
(
*
poll_sample
)
(
struct
wm97xx
*
,
int
adcsel
,
int
*
sample
);
/* read X,Y,[P] in poll */
int
(
*
poll_touch
)
(
struct
wm97xx
*
,
struct
wm97xx_data
*
);
int
(
*
acc_enable
)
(
struct
wm97xx
*
,
int
enable
);
void
(
*
phy_init
)
(
struct
wm97xx
*
);
void
(
*
dig_enable
)
(
struct
wm97xx
*
,
int
enable
);
void
(
*
dig_restore
)
(
struct
wm97xx
*
);
void
(
*
aux_prepare
)
(
struct
wm97xx
*
);
};
/* Machine specific and accelerated touch operations */
struct
wm97xx_mach_ops
{
/* accelerated touch readback - coords are transmited on AC97 link */
int
acc_enabled
;
void
(
*
acc_pen_up
)
(
struct
wm97xx
*
);
int
(
*
acc_pen_down
)
(
struct
wm97xx
*
);
int
(
*
acc_startup
)
(
struct
wm97xx
*
);
void
(
*
acc_shutdown
)
(
struct
wm97xx
*
);
/* interrupt mask control - required for accelerated operation */
void
(
*
irq_enable
)
(
struct
wm97xx
*
,
int
enable
);
/* GPIO pin used for accelerated operation */
int
irq_gpio
;
/* pre and post sample - can be used to minimise any analog noise */
void
(
*
pre_sample
)
(
int
);
/* function to run before sampling */
void
(
*
post_sample
)
(
int
);
/* function to run after sampling */
};
struct
wm97xx
{
u16
dig
[
3
],
id
,
gpio
[
6
],
misc
;
/* Cached codec registers */
u16
dig_save
[
3
];
/* saved during aux reading */
struct
wm97xx_codec_drv
*
codec
;
/* attached codec driver*/
struct
input_dev
*
input_dev
;
/* touchscreen input device */
struct
snd_ac97
*
ac97
;
/* ALSA codec access */
struct
device
*
dev
;
/* ALSA device */
struct
platform_device
*
battery_dev
;
struct
platform_device
*
touch_dev
;
struct
wm97xx_mach_ops
*
mach_ops
;
struct
mutex
codec_mutex
;
struct
delayed_work
ts_reader
;
/* Used to poll touchscreen */
unsigned
long
ts_reader_interval
;
/* Current interval for timer */
unsigned
long
ts_reader_min_interval
;
/* Minimum interval */
unsigned
int
pen_irq
;
/* Pen IRQ number in use */
struct
workqueue_struct
*
ts_workq
;
struct
work_struct
pen_event_work
;
u16
acc_slot
;
/* AC97 slot used for acc touch data */
u16
acc_rate
;
/* acc touch data rate */
unsigned
pen_is_down
:
1
;
/* Pen is down */
unsigned
aux_waiting
:
1
;
/* aux measurement waiting */
unsigned
pen_probably_down
:
1
;
/* used in polling mode */
u16
suspend_mode
;
/* PRP in suspend mode */
};
/*
* Codec GPIO access (not supported on WM9705)
* This can be used to set/get codec GPIO and Virtual GPIO status.
*/
enum
wm97xx_gpio_status
wm97xx_get_gpio
(
struct
wm97xx
*
wm
,
u32
gpio
);
void
wm97xx_set_gpio
(
struct
wm97xx
*
wm
,
u32
gpio
,
enum
wm97xx_gpio_status
status
);
void
wm97xx_config_gpio
(
struct
wm97xx
*
wm
,
u32
gpio
,
enum
wm97xx_gpio_dir
dir
,
enum
wm97xx_gpio_pol
pol
,
enum
wm97xx_gpio_sticky
sticky
,
enum
wm97xx_gpio_wake
wake
);
void
wm97xx_set_suspend_mode
(
struct
wm97xx
*
wm
,
u16
mode
);
/* codec AC97 IO access */
int
wm97xx_reg_read
(
struct
wm97xx
*
wm
,
u16
reg
);
void
wm97xx_reg_write
(
struct
wm97xx
*
wm
,
u16
reg
,
u16
val
);
/* aux adc readback */
int
wm97xx_read_aux_adc
(
struct
wm97xx
*
wm
,
u16
adcsel
);
/* machine ops */
int
wm97xx_register_mach_ops
(
struct
wm97xx
*
,
struct
wm97xx_mach_ops
*
);
void
wm97xx_unregister_mach_ops
(
struct
wm97xx
*
);
#endif
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