Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
Commits
ba28f22e
Commit
ba28f22e
authored
Apr 08, 2009
by
Dmitry Torokhov
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'next' into for-linus
parents
577c9c45
59cc1dd9
Changes
28
Show whitespace changes
Inline
Side-by-side
Showing
28 changed files
with
3062 additions
and
200 deletions
+3062
-200
Documentation/input/rotary-encoder.txt
Documentation/input/rotary-encoder.txt
+101
-0
arch/mips/include/asm/mach-rc32434/gpio.h
arch/mips/include/asm/mach-rc32434/gpio.h
+3
-0
arch/mips/rb532/devices.c
arch/mips/rb532/devices.c
+1
-18
drivers/input/input.c
drivers/input/input.c
+10
-3
drivers/input/keyboard/atkbd.c
drivers/input/keyboard/atkbd.c
+62
-73
drivers/input/keyboard/bf54x-keys.c
drivers/input/keyboard/bf54x-keys.c
+2
-2
drivers/input/keyboard/hilkbd.c
drivers/input/keyboard/hilkbd.c
+80
-60
drivers/input/misc/Kconfig
drivers/input/misc/Kconfig
+23
-0
drivers/input/misc/Makefile
drivers/input/misc/Makefile
+15
-13
drivers/input/misc/ati_remote2.c
drivers/input/misc/ati_remote2.c
+261
-16
drivers/input/misc/rb532_button.c
drivers/input/misc/rb532_button.c
+120
-0
drivers/input/misc/rotary_encoder.c
drivers/input/misc/rotary_encoder.c
+221
-0
drivers/input/mouse/Kconfig
drivers/input/mouse/Kconfig
+11
-0
drivers/input/mouse/Makefile
drivers/input/mouse/Makefile
+5
-4
drivers/input/mouse/hgpk.c
drivers/input/mouse/hgpk.c
+1
-1
drivers/input/mouse/maplemouse.c
drivers/input/mouse/maplemouse.c
+147
-0
drivers/input/mouse/pc110pad.c
drivers/input/mouse/pc110pad.c
+1
-4
drivers/input/serio/i8042-x86ia64io.h
drivers/input/serio/i8042-x86ia64io.h
+8
-0
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Kconfig
+58
-0
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/Makefile
+3
-0
drivers/input/touchscreen/ad7877.c
drivers/input/touchscreen/ad7877.c
+844
-0
drivers/input/touchscreen/ad7879.c
drivers/input/touchscreen/ad7879.c
+782
-0
drivers/input/touchscreen/mainstone-wm97xx.c
drivers/input/touchscreen/mainstone-wm97xx.c
+2
-1
drivers/input/touchscreen/ucb1400_ts.c
drivers/input/touchscreen/ucb1400_ts.c
+4
-1
drivers/input/touchscreen/wm97xx-core.c
drivers/input/touchscreen/wm97xx-core.c
+9
-4
drivers/input/touchscreen/zylonite-wm97xx.c
drivers/input/touchscreen/zylonite-wm97xx.c
+240
-0
include/linux/rotary_encoder.h
include/linux/rotary_encoder.h
+13
-0
include/linux/spi/ad7879.h
include/linux/spi/ad7879.h
+35
-0
No files found.
Documentation/input/rotary-encoder.txt
0 → 100644
View file @
ba28f22e
rotary-encoder - a generic driver for GPIO connected devices
Daniel Mack <daniel@caiaq.de>, Feb 2009
0. Function
-----------
Rotary encoders are devices which are connected to the CPU or other
peripherals with two wires. The outputs are phase-shifted by 90 degrees
and by triggering on falling and rising edges, the turn direction can
be determined.
The phase diagram of these two outputs look like this:
_____ _____ _____
| | | | | |
Channel A ____| |_____| |_____| |____
: : : : : : : : : : : :
__ _____ _____ _____
| | | | | | |
Channel B |_____| |_____| |_____| |__
: : : : : : : : : : : :
Event a b c d a b c d a b c d
|<-------->|
one step
For more information, please see
http://en.wikipedia.org/wiki/Rotary_encoder
1. Events / state machine
-------------------------
a) Rising edge on channel A, channel B in low state
This state is used to recognize a clockwise turn
b) Rising edge on channel B, channel A in high state
When entering this state, the encoder is put into 'armed' state,
meaning that there it has seen half the way of a one-step transition.
c) Falling edge on channel A, channel B in high state
This state is used to recognize a counter-clockwise turn
d) Falling edge on channel B, channel A in low state
Parking position. If the encoder enters this state, a full transition
should have happend, unless it flipped back on half the way. The
'armed' state tells us about that.
2. Platform requirements
------------------------
As there is no hardware dependent call in this driver, the platform it is
used with must support gpiolib. Another requirement is that IRQs must be
able to fire on both edges.
3. Board integration
--------------------
To use this driver in your system, register a platform_device with the
name 'rotary-encoder' and associate the IRQs and some specific platform
data with it.
struct rotary_encoder_platform_data is declared in
include/linux/rotary-encoder.h and needs to be filled with the number of
steps the encoder has and can carry information about externally inverted
signals (because of used invertig buffer or other reasons).
Because GPIO to IRQ mapping is platform specific, this information must
be given in seperately to the driver. See the example below.
---------<snip>---------
/* board support file example */
#include <linux/input.h>
#include <linux/rotary_encoder.h>
#define GPIO_ROTARY_A 1
#define GPIO_ROTARY_B 2
static struct rotary_encoder_platform_data my_rotary_encoder_info = {
.steps = 24,
.axis = ABS_X,
.gpio_a = GPIO_ROTARY_A,
.gpio_b = GPIO_ROTARY_B,
.inverted_a = 0,
.inverted_b = 0,
};
static struct platform_device rotary_encoder_device = {
.name = "rotary-encoder",
.id = 0,
.dev = {
.platform_data = &my_rotary_encoder_info,
}
};
arch/mips/include/asm/mach-rc32434/gpio.h
View file @
ba28f22e
...
...
@@ -80,6 +80,9 @@ struct rb532_gpio_reg {
/* Compact Flash GPIO pin */
#define CF_GPIO_NUM 13
/* S1 button GPIO (shared with UART0_SIN) */
#define GPIO_BTN_S1 1
extern
void
rb532_gpio_set_ilevel
(
int
bit
,
unsigned
gpio
);
extern
void
rb532_gpio_set_istat
(
int
bit
,
unsigned
gpio
);
extern
void
rb532_gpio_set_func
(
unsigned
gpio
);
...
...
arch/mips/rb532/devices.c
View file @
ba28f22e
...
...
@@ -200,26 +200,9 @@ static struct platform_device rb532_led = {
.
id
=
-
1
,
};
static
struct
gpio_keys_button
rb532_gpio_btn
[]
=
{
{
.
gpio
=
1
,
.
code
=
BTN_0
,
.
desc
=
"S1"
,
.
active_low
=
1
,
}
};
static
struct
gpio_keys_platform_data
rb532_gpio_btn_data
=
{
.
buttons
=
rb532_gpio_btn
,
.
nbuttons
=
ARRAY_SIZE
(
rb532_gpio_btn
),
};
static
struct
platform_device
rb532_button
=
{
.
name
=
"gpio-keys
"
,
.
name
=
"rb532-button
"
,
.
id
=
-
1
,
.
dev
=
{
.
platform_data
=
&
rb532_gpio_btn_data
,
}
};
static
struct
resource
rb532_wdt_res
[]
=
{
...
...
drivers/input/input.c
View file @
ba28f22e
...
...
@@ -132,6 +132,11 @@ static void input_start_autorepeat(struct input_dev *dev, int code)
}
}
static
void
input_stop_autorepeat
(
struct
input_dev
*
dev
)
{
del_timer
(
&
dev
->
timer
);
}
#define INPUT_IGNORE_EVENT 0
#define INPUT_PASS_TO_HANDLERS 1
#define INPUT_PASS_TO_DEVICE 2
...
...
@@ -167,6 +172,8 @@ static void input_handle_event(struct input_dev *dev,
__change_bit
(
code
,
dev
->
key
);
if
(
value
)
input_start_autorepeat
(
dev
,
code
);
else
input_stop_autorepeat
(
dev
);
}
disposition
=
INPUT_PASS_TO_HANDLERS
;
...
...
@@ -737,11 +744,11 @@ static inline void input_wakeup_procfs_readers(void)
static
unsigned
int
input_proc_devices_poll
(
struct
file
*
file
,
poll_table
*
wait
)
{
int
state
=
input_devices_state
;
poll_wait
(
file
,
&
input_devices_poll_wait
,
wait
);
if
(
state
!=
input_devices_state
)
if
(
file
->
f_version
!=
input_devices_state
)
{
file
->
f_version
=
input_devices_state
;
return
POLLIN
|
POLLRDNORM
;
}
return
0
;
}
...
...
drivers/input/keyboard/atkbd.c
View file @
ba28f22e
...
...
@@ -229,7 +229,8 @@ struct atkbd {
/*
* System-specific ketymap fixup routine
*/
static
void
(
*
atkbd_platform_fixup
)(
struct
atkbd
*
);
static
void
(
*
atkbd_platform_fixup
)(
struct
atkbd
*
,
const
void
*
data
);
static
void
*
atkbd_platform_fixup_data
;
static
ssize_t
atkbd_attr_show_helper
(
struct
device
*
dev
,
char
*
buf
,
ssize_t
(
*
handler
)(
struct
atkbd
*
,
char
*
));
...
...
@@ -834,87 +835,64 @@ static void atkbd_disconnect(struct serio *serio)
}
/*
* Most special keys (Fn+F?) on Dell laptops do not generate release
* events so we have to do it ourselves.
* generate release events for the keycodes given in data
*/
static
void
atkbd_dell_laptop_keymap_fixup
(
struct
atkbd
*
atkbd
)
static
void
atkbd_apply_forced_release_keylist
(
struct
atkbd
*
atkbd
,
const
void
*
data
)
{
static
const
unsigned
int
forced_release_keys
[]
=
{
0x85
,
0x86
,
0x87
,
0x88
,
0x89
,
0x8a
,
0x8b
,
0x8f
,
0x93
,
};
int
i
;
const
unsigned
int
*
keys
=
data
;
unsigned
int
i
;
if
(
atkbd
->
set
==
2
)
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
forced_release_keys
);
i
++
)
__set_bit
(
forced_release_keys
[
i
],
atkbd
->
force_release_mask
);
for
(
i
=
0
;
keys
[
i
]
!=
-
1U
;
i
++
)
__set_bit
(
keys
[
i
],
atkbd
->
force_release_mask
);
}
/*
* Most special keys (Fn+F?) on Dell laptops do not generate release
* events so we have to do it ourselves.
*/
static
unsigned
int
atkbd_dell_laptop_forced_release_keys
[]
=
{
0x85
,
0x86
,
0x87
,
0x88
,
0x89
,
0x8a
,
0x8b
,
0x8f
,
0x93
,
-
1U
};
/*
* Perform fixup for HP system that doesn't generate release
* for its video switch
*/
static
void
atkbd_hp_keymap_fixup
(
struct
atkbd
*
atkbd
)
{
static
const
unsigned
int
forced_release_keys
[]
=
{
0x94
,
};
int
i
;
if
(
atkbd
->
set
==
2
)
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
forced_release_keys
);
i
++
)
__set_bit
(
forced_release_keys
[
i
],
atkbd
->
force_release_mask
);
}
static
unsigned
int
atkbd_hp_forced_release_keys
[]
=
{
0x94
,
-
1U
};
/*
* Inventec system with broken key release on volume keys
*/
static
void
atkbd_inventec_keymap_fixup
(
struct
atkbd
*
atkbd
)
{
const
unsigned
int
forced_release_keys
[]
=
{
0xae
,
0xb0
,
};
int
i
;
if
(
atkbd
->
set
==
2
)
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
forced_release_keys
);
i
++
)
__set_bit
(
forced_release_keys
[
i
],
atkbd
->
force_release_mask
);
}
static
unsigned
int
atkbd_inventec_forced_release_keys
[]
=
{
0xae
,
0xb0
,
-
1U
};
/*
* Perform fixup for HP Pavilion ZV6100 laptop that doesn't generate release
* for its volume buttons
*/
static
void
atkbd_hp_zv6100_keymap_fixup
(
struct
atkbd
*
atkbd
)
{
const
unsigned
int
forced_release_keys
[]
=
{
0xae
,
0xb0
,
};
int
i
;
if
(
atkbd
->
set
==
2
)
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
forced_release_keys
);
i
++
)
__set_bit
(
forced_release_keys
[
i
],
atkbd
->
force_release_mask
);
}
static
unsigned
int
atkbd_hp_zv6100_forced_release_keys
[]
=
{
0xae
,
0xb0
,
-
1U
};
/*
* Samsung NC10 with Fn+F? key release not working
*/
static
void
atkbd_samsung_keymap_fixup
(
struct
atkbd
*
atkbd
)
{
const
unsigned
int
forced_release_keys
[]
=
{
0x82
,
0x83
,
0x84
,
0x86
,
0x88
,
0x89
,
0xb3
,
0xf7
,
0xf9
,
};
int
i
;
static
unsigned
int
atkbd_samsung_forced_release_keys
[]
=
{
0x82
,
0x83
,
0x84
,
0x86
,
0x88
,
0x89
,
0xb3
,
0xf7
,
0xf9
,
-
1U
};
if
(
atkbd
->
set
==
2
)
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
forced_release_keys
);
i
++
)
__set_bit
(
forced_release_keys
[
i
],
atkbd
->
force_release_mask
);
}
/*
* The volume up and volume down special keys on a Fujitsu Amilo PA 1510 laptop
* do not generate release events so we have to do it ourselves.
*/
static
unsigned
int
atkbd_amilo_pa1510_forced_release_keys
[]
=
{
0xb0
,
0xae
,
-
1U
};
/*
* atkbd_set_keycode_table() initializes keyboard's keycode table
...
...
@@ -967,7 +945,7 @@ static void atkbd_set_keycode_table(struct atkbd *atkbd)
* Perform additional fixups
*/
if
(
atkbd_platform_fixup
)
atkbd_platform_fixup
(
atkbd
);
atkbd_platform_fixup
(
atkbd
,
atkbd_platform_fixup_data
);
}
/*
...
...
@@ -1492,9 +1470,11 @@ static ssize_t atkbd_show_err_count(struct atkbd *atkbd, char *buf)
return
sprintf
(
buf
,
"%lu
\n
"
,
atkbd
->
err_count
);
}
static
int
__init
atkbd_setup_f
ixup
(
const
struct
dmi_system_id
*
id
)
static
int
__init
atkbd_setup_f
orced_release
(
const
struct
dmi_system_id
*
id
)
{
atkbd_platform_fixup
=
id
->
driver_data
;
atkbd_platform_fixup
=
atkbd_apply_forced_release_keylist
;
atkbd_platform_fixup_data
=
id
->
driver_data
;
return
0
;
}
...
...
@@ -1505,8 +1485,8 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
DMI_MATCH
(
DMI_SYS_VENDOR
,
"Dell Inc."
),
DMI_MATCH
(
DMI_CHASSIS_TYPE
,
"8"
),
/* Portable */
},
.
callback
=
atkbd_setup_f
ixup
,
.
driver_data
=
atkbd_dell_laptop_
keymap_fixup
,
.
callback
=
atkbd_setup_f
orced_release
,
.
driver_data
=
atkbd_dell_laptop_
forced_release_keys
,
},
{
.
ident
=
"Dell Laptop"
,
...
...
@@ -1514,8 +1494,8 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
DMI_MATCH
(
DMI_SYS_VENDOR
,
"Dell Computer Corporation"
),
DMI_MATCH
(
DMI_CHASSIS_TYPE
,
"8"
),
/* Portable */
},
.
callback
=
atkbd_setup_f
ixup
,
.
driver_data
=
atkbd_dell_laptop_
keymap_fixup
,
.
callback
=
atkbd_setup_f
orced_release
,
.
driver_data
=
atkbd_dell_laptop_
forced_release_keys
,
},
{
.
ident
=
"HP 2133"
,
...
...
@@ -1523,8 +1503,8 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
DMI_MATCH
(
DMI_SYS_VENDOR
,
"Hewlett-Packard"
),
DMI_MATCH
(
DMI_PRODUCT_NAME
,
"HP 2133"
),
},
.
callback
=
atkbd_setup_f
ixup
,
.
driver_data
=
atkbd_hp_
keymap_fixup
,
.
callback
=
atkbd_setup_f
orced_release
,
.
driver_data
=
atkbd_hp_
forced_release_keys
,
},
{
.
ident
=
"HP Pavilion ZV6100"
,
...
...
@@ -1532,8 +1512,8 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
DMI_MATCH
(
DMI_SYS_VENDOR
,
"Hewlett-Packard"
),
DMI_MATCH
(
DMI_PRODUCT_NAME
,
"Pavilion ZV6100"
),
},
.
callback
=
atkbd_setup_f
ixup
,
.
driver_data
=
atkbd_hp_zv6100_
keymap_fixup
,
.
callback
=
atkbd_setup_f
orced_release
,
.
driver_data
=
atkbd_hp_zv6100_
forced_release_keys
,
},
{
.
ident
=
"Inventec Symphony"
,
...
...
@@ -1541,8 +1521,8 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
DMI_MATCH
(
DMI_SYS_VENDOR
,
"INVENTEC"
),
DMI_MATCH
(
DMI_PRODUCT_NAME
,
"SYMPHONY 6.0/7.0"
),
},
.
callback
=
atkbd_setup_f
ixup
,
.
driver_data
=
atkbd_inventec_
keymap_fixup
,
.
callback
=
atkbd_setup_f
orced_release
,
.
driver_data
=
atkbd_inventec_
forced_release_keys
,
},
{
.
ident
=
"Samsung NC10"
,
...
...
@@ -1550,8 +1530,17 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
DMI_MATCH
(
DMI_SYS_VENDOR
,
"SAMSUNG ELECTRONICS CO., LTD."
),
DMI_MATCH
(
DMI_PRODUCT_NAME
,
"NC10"
),
},
.
callback
=
atkbd_setup_fixup
,
.
driver_data
=
atkbd_samsung_keymap_fixup
,
.
callback
=
atkbd_setup_forced_release
,
.
driver_data
=
atkbd_samsung_forced_release_keys
,
},
{
.
ident
=
"Fujitsu Amilo PA 1510"
,
.
matches
=
{
DMI_MATCH
(
DMI_SYS_VENDOR
,
"FUJITSU SIEMENS"
),
DMI_MATCH
(
DMI_PRODUCT_NAME
,
"AMILO Pa 1510"
),
},
.
callback
=
atkbd_setup_forced_release
,
.
driver_data
=
atkbd_amilo_pa1510_forced_release_keys
,
},
{
}
};
...
...
drivers/input/keyboard/bf54x-keys.c
View file @
ba28f22e
...
...
@@ -211,8 +211,8 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
if
(
!
pdata
->
debounce_time
||
pdata
->
debounce_time
>
MAX_MULT
||
!
pdata
->
coldrive_time
||
pdata
->
coldrive_time
>
MAX_MULT
)
{
printk
(
KERN_
ERR
DRV_NAME
": Invalid Debounce/Colum
drive Time from p
data
\n
"
);
printk
(
KERN_
WARNING
DRV_NAME
": Invalid Debounce/Colum
ndrive Time in platform
data
\n
"
);
bfin_write_KPAD_MSEL
(
0xFF0
);
/* Default MSEL */
}
else
{
bfin_write_KPAD_MSEL
(
...
...
drivers/input/keyboard/hilkbd.c
View file @
ba28f22e
...
...
@@ -198,45 +198,28 @@ static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len)
}
/* initialise HIL */
static
int
__init
hil_keyb_init
(
void
)
/* initialize HIL */
static
int
__devinit
hil_keyb_init
(
void
)
{
unsigned
char
c
;
unsigned
int
i
,
kbid
;
wait_queue_head_t
hil_wait
;
int
err
;
if
(
hil_dev
.
dev
)
{
if
(
hil_dev
.
dev
)
return
-
ENODEV
;
/* already initialized */
}
init_waitqueue_head
(
&
hil_wait
);
spin_lock_init
(
&
hil_dev
.
lock
);
hil_dev
.
dev
=
input_allocate_device
();
if
(
!
hil_dev
.
dev
)
return
-
ENOMEM
;
#if defined(CONFIG_HP300)
if
(
!
MACH_IS_HP300
)
{
err
=
-
ENODEV
;
goto
err1
;
}
if
(
!
hwreg_present
((
void
*
)(
HILBASE
+
HIL_DATA
)))
{
printk
(
KERN_ERR
"HIL: hardware register was not found
\n
"
);
err
=
-
ENODEV
;
goto
err1
;
}
if
(
!
request_region
(
HILBASE
+
HIL_DATA
,
2
,
"hil"
))
{
printk
(
KERN_ERR
"HIL: IOPORT region already used
\n
"
);
err
=
-
EIO
;
goto
err1
;
}
#endif
err
=
request_irq
(
HIL_IRQ
,
hil_interrupt
,
0
,
"hil"
,
hil_dev
.
dev_id
);
if
(
err
)
{
printk
(
KERN_ERR
"HIL: Can't get IRQ
\n
"
);
goto
err
2
;
goto
err
1
;
}
/* Turn on interrupts */
...
...
@@ -246,11 +229,9 @@ hil_keyb_init(void)
hil_dev
.
valid
=
0
;
/* clear any pending data */
hil_do
(
HIL_READKBDSADR
,
NULL
,
0
);
init_waitqueue_head
(
&
hil_wait
);
wait_event_interruptible_timeout
(
hil_wait
,
hil_dev
.
valid
,
3
*
HZ
);
if
(
!
hil_dev
.
valid
)
{
wait_event_interruptible_timeout
(
hil_wait
,
hil_dev
.
valid
,
3
*
HZ
);
if
(
!
hil_dev
.
valid
)
printk
(
KERN_WARNING
"HIL: timed out, assuming no keyboard present
\n
"
);
}
c
=
hil_dev
.
c
;
hil_dev
.
valid
=
0
;
...
...
@@ -268,7 +249,7 @@ hil_keyb_init(void)
for
(
i
=
0
;
i
<
HIL_KEYCODES_SET1_TBLSIZE
;
i
++
)
if
(
hphilkeyb_keycode
[
i
]
!=
KEY_RESERVED
)
set_bit
(
hphilkeyb_keycode
[
i
],
hil_dev
.
dev
->
keybit
);
__
set_bit
(
hphilkeyb_keycode
[
i
],
hil_dev
.
dev
->
keybit
);
hil_dev
.
dev
->
evbit
[
0
]
=
BIT_MASK
(
EV_KEY
)
|
BIT_MASK
(
EV_REP
);
hil_dev
.
dev
->
ledbit
[
0
]
=
BIT_MASK
(
LED_NUML
)
|
BIT_MASK
(
LED_CAPSL
)
|
...
...
@@ -287,34 +268,45 @@ hil_keyb_init(void)
err
=
input_register_device
(
hil_dev
.
dev
);
if
(
err
)
{
printk
(
KERN_ERR
"HIL: Can't register device
\n
"
);
goto
err
3
;
goto
err
2
;
}
printk
(
KERN_INFO
"input: %s, ID %d at 0x%08lx (irq %d) found and attached
\n
"
,
hil_dev
.
dev
->
name
,
kbid
,
HILBASE
,
HIL_IRQ
);
return
0
;
err
3
:
err
2
:
hil_do
(
HIL_INTOFF
,
NULL
,
0
);
disable_irq
(
HIL_IRQ
);
free_irq
(
HIL_IRQ
,
hil_dev
.
dev_id
);
err2:
#if defined(CONFIG_HP300)
release_region
(
HILBASE
+
HIL_DATA
,
2
);
err1:
#endif
input_free_device
(
hil_dev
.
dev
);
hil_dev
.
dev
=
NULL
;
return
err
;
}
static
void
__devexit
hil_keyb_exit
(
void
)
{
if
(
HIL_IRQ
)
free_irq
(
HIL_IRQ
,
hil_dev
.
dev_id
);
/* Turn off interrupts */
hil_do
(
HIL_INTOFF
,
NULL
,
0
);
input_unregister_device
(
hil_dev
.
dev
);
hil_dev
.
dev
=
NULL
;
}
#if defined(CONFIG_PARISC)
static
int
__init
hil_init_chip
(
struct
parisc_device
*
dev
)
static
int
__devinit
hil_probe_chip
(
struct
parisc_device
*
dev
)
{
/* Only allow one HIL keyboard */
if
(
hil_dev
.
dev
)
return
-
ENODEV
;
if
(
!
dev
->
irq
)
{
printk
(
KERN_WARNING
"HIL: IRQ not found for HIL bus at 0x%08lx
\n
"
,
dev
->
hpa
.
start
);
printk
(
KERN_WARNING
"HIL: IRQ not found for HIL bus at 0x%p
\n
"
,
(
void
*
)
dev
->
hpa
.
start
);
return
-
ENODEV
;
}
...
...
@@ -327,51 +319,79 @@ hil_init_chip(struct parisc_device *dev)
return
hil_keyb_init
();
}
static
int
__devexit
hil_remove_chip
(
struct
parisc_device
*
dev
)
{
hil_keyb_exit
();
return
0
;
}
static
struct
parisc_device_id
hil_tbl
[]
=
{
{
HPHW_FIO
,
HVERSION_REV_ANY_ID
,
HVERSION_ANY_ID
,
0x00073
},
{
0
,
}
};
#if 0
/* Disabled to avoid conflicts with the HP SDC HIL drivers */
MODULE_DEVICE_TABLE(parisc, hil_tbl);
#endif
static
struct
parisc_driver
hil_driver
=
{
.
name
=
"hil"
,
.
id_table
=
hil_tbl
,
.
probe
=
hil_init_chip
,
.
probe
=
hil_probe_chip
,
.
remove
=
__devexit_p
(
hil_remove_chip
),
};
#endif
/* CONFIG_PARISC */
static
int
__init
hil_init
(
void
)
{
#if defined(CONFIG_PARISC)
return
register_parisc_driver
(
&
hil_driver
);
#else
return
hil_keyb_init
();
#endif
}
static
void
__exit
hil_exit
(
void
)
{
if
(
HIL_IRQ
)
{
disable_irq
(
HIL_IRQ
);
free_irq
(
HIL_IRQ
,
hil_dev
.
dev_id
);
unregister_parisc_driver
(
&
hil_driver
);
}
#else
/* !CONFIG_PARISC */
static
int
__init
hil_init
(
void
)
{
int
error
;
/* Only allow one HIL keyboard */
if
(
hil_dev
.
dev
)
return
-
EBUSY
;
if
(
!
MACH_IS_HP300
)
return
-
ENODEV
;
if
(
!
hwreg_present
((
void
*
)(
HILBASE
+
HIL_DATA
)))
{
printk
(
KERN_ERR
"HIL: hardware register was not found
\n
"
);
return
-
ENODEV
;
}
/* Turn off interrupts */
hil_do
(
HIL_INTOFF
,
NULL
,
0
);
if
(
!
request_region
(
HILBASE
+
HIL_DATA
,
2
,
"hil"
))
{
printk
(
KERN_ERR
"HIL: IOPORT region already used
\n
"
);
return
-
EIO
;
}
input_unregister_device
(
hil_dev
.
dev
);
error
=
hil_keyb_init
();
if
(
error
)
{
release_region
(
HILBASE
+
HIL_DATA
,
2
);
return
error
;
}
hil_dev
.
dev
=
NULL
;
return
0
;
}
#if defined(CONFIG_PARISC)
unregister_parisc_driver
(
&
hil_driver
);
#else
release_region
(
HILBASE
+
HIL_DATA
,
2
);
#endif
static
void
__exit
hil_exit
(
void
)
{
hil_keyb_exit
();
release_region
(
HILBASE
+
HIL_DATA
,
2
);
}
#endif
/* CONFIG_PARISC */
module_init
(
hil_init
);
module_exit
(
hil_exit
);
drivers/input/misc/Kconfig
View file @
ba28f22e
...
...
@@ -227,4 +227,27 @@ config INPUT_PCF50633_PMU
Say Y to include support for delivering PMU events via input
layer on NXP PCF50633.
config INPUT_GPIO_ROTARY_ENCODER
tristate "Rotary encoders connected to GPIO pins"
depends on GPIOLIB && GENERIC_GPIO
help
Say Y here to add support for rotary encoders connected to GPIO lines.
Check file:Documentation/incput/rotary_encoder.txt for more
information.
To compile this driver as a module, choose M here: the
module will be called rotary_encoder.
config INPUT_RB532_BUTTON
tristate "Mikrotik Routerboard 532 button interface"
depends on MIKROTIK_RB532
depends on GPIOLIB && GENERIC_GPIO
select INPUT_POLLDEV
help
Say Y here if you want support for the S1 button built into
Mikrotik's Routerboard 532.
To compile this driver as a module, choose M here: the
module will be called rb532_button.
endif
drivers/input/misc/Makefile
View file @
ba28f22e
...
...
@@ -4,21 +4,23 @@
# Each configuration option enables a list of files.
obj-$(CONFIG_INPUT_SPARCSPKR)
+=
sparcspkr.o
obj-$(CONFIG_INPUT_PCSPKR)
+=
pcspkr.o
obj-$(CONFIG_INPUT_M68K_BEEP)
+=
m68kspkr.o
obj-$(CONFIG_INPUT_IXP4XX_BEEPER)
+=
ixp4xx-beeper.o
obj-$(CONFIG_INPUT_COBALT_BTNS)
+=
cobalt_btns.o
obj-$(CONFIG_INPUT_WISTRON_BTNS)
+=
wistron_btns.o
obj-$(CONFIG_INPUT_ATLAS_BTNS)
+=
atlas_btns.o
obj-$(CONFIG_INPUT_APANEL)
+=
apanel.o
obj-$(CONFIG_INPUT_ATI_REMOTE)
+=
ati_remote.o
obj-$(CONFIG_INPUT_ATI_REMOTE2)
+=
ati_remote2.o
obj-$(CONFIG_INPUT_KEYSPAN_REMOTE)
+=
keyspan_remote.o
obj-$(CONFIG_INPUT_POWERMATE)
+=
powermate.o
obj-$(CONFIG_INPUT_YEALINK)
+=
yealink.o
obj-$(CONFIG_INPUT_ATLAS_BTNS)
+=
atlas_btns.o
obj-$(CONFIG_INPUT_CM109)
+=
cm109.o
obj-$(CONFIG_INPUT_COBALT_BTNS)
+=
cobalt_btns.o
obj-$(CONFIG_HP_SDC_RTC)
+=
hp_sdc_rtc.o
obj-$(CONFIG_INPUT_
UINPUT)
+=
uinput
.o
obj-$(CONFIG_INPUT_
APANEL)
+=
apanel
.o
obj-$(CONFIG_INPUT_
SGI_BTNS)
+=
sgi_btns
.o
obj-$(CONFIG_INPUT_
IXP4XX_BEEPER)
+=
ixp4xx-beeper
.o
obj-$(CONFIG_INPUT_
KEYSPAN_REMOTE)
+=
keyspan_remote
.o
obj-$(CONFIG_INPUT_
M68K_BEEP)
+=
m68kspkr
.o
obj-$(CONFIG_INPUT_PCF50633_PMU)
+=
pcf50633-input.o
obj-$(CONFIG_INPUT_PCSPKR)
+=
pcspkr.o
obj-$(CONFIG_INPUT_POWERMATE)
+=
powermate.o
obj-$(CONFIG_INPUT_RB532_BUTTON)
+=
rb532_button.o
obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER)
+=
rotary_encoder.o
obj-$(CONFIG_INPUT_SGI_BTNS)
+=
sgi_btns.o
obj-$(CONFIG_INPUT_SPARCSPKR)
+=
sparcspkr.o
obj-$(CONFIG_INPUT_UINPUT)
+=
uinput.o
obj-$(CONFIG_INPUT_WISTRON_BTNS)
+=
wistron_btns.o
obj-$(CONFIG_INPUT_YEALINK)
+=
yealink.o
drivers/input/misc/ati_remote2.c
View file @
ba28f22e
...
...
@@ -31,12 +31,73 @@ MODULE_LICENSE("GPL");
* newly configured "channel".
*/
static
unsigned
int
channel_mask
=
0xFFFF
;
module_param
(
channel_mask
,
uint
,
0644
);
enum
{
ATI_REMOTE2_MAX_CHANNEL_MASK
=
0xFFFF
,
ATI_REMOTE2_MAX_MODE_MASK
=
0x1F
,
};
static
int
ati_remote2_set_mask
(
const
char
*
val
,
struct
kernel_param
*
kp
,
unsigned
int
max
)
{
unsigned
long
mask
;
int
ret
;
if
(
!
val
)
return
-
EINVAL
;
ret
=
strict_strtoul
(
val
,
0
,
&
mask
);
if
(
ret
)
return
ret
;
if
(
mask
&
~
max
)
return
-
EINVAL
;
*
(
unsigned
int
*
)
kp
->
arg
=
mask
;
return
0
;
}
static
int
ati_remote2_set_channel_mask
(
const
char
*
val
,
struct
kernel_param
*
kp
)
{
pr_debug
(
"%s()
\n
"
,
__func__
);
return
ati_remote2_set_mask
(
val
,
kp
,
ATI_REMOTE2_MAX_CHANNEL_MASK
);
}
static
int
ati_remote2_get_channel_mask
(
char
*
buffer
,
struct
kernel_param
*
kp
)
{
pr_debug
(
"%s()
\n
"
,
__func__
);
return
sprintf
(
buffer
,
"0x%04x"
,
*
(
unsigned
int
*
)
kp
->
arg
);
}
static
int
ati_remote2_set_mode_mask
(
const
char
*
val
,
struct
kernel_param
*
kp
)
{
pr_debug
(
"%s()
\n
"
,
__func__
);
return
ati_remote2_set_mask
(
val
,
kp
,
ATI_REMOTE2_MAX_MODE_MASK
);
}
static
int
ati_remote2_get_mode_mask
(
char
*
buffer
,
struct
kernel_param
*
kp
)
{
pr_debug
(
"%s()
\n
"
,
__func__
);
return
sprintf
(
buffer
,
"0x%02x"
,
*
(
unsigned
int
*
)
kp
->
arg
);
}
static
unsigned
int
channel_mask
=
ATI_REMOTE2_MAX_CHANNEL_MASK
;
#define param_check_channel_mask(name, p) __param_check(name, p, unsigned int)
#define param_set_channel_mask ati_remote2_set_channel_mask
#define param_get_channel_mask ati_remote2_get_channel_mask
module_param
(
channel_mask
,
channel_mask
,
0644
);
MODULE_PARM_DESC
(
channel_mask
,
"Bitmask of channels to accept <15:Channel16>...<1:Channel2><0:Channel1>"
);
static
unsigned
int
mode_mask
=
0x1F
;
module_param
(
mode_mask
,
uint
,
0644
);
static
unsigned
int
mode_mask
=
ATI_REMOTE2_MAX_MODE_MASK
;
#define param_check_mode_mask(name, p) __param_check(name, p, unsigned int)
#define param_set_mode_mask ati_remote2_set_mode_mask
#define param_get_mode_mask ati_remote2_get_mode_mask
module_param
(
mode_mask
,
mode_mask
,
0644
);
MODULE_PARM_DESC
(
mode_mask
,
"Bitmask of modes to accept <4:PC><3:AUX4><2:AUX3><1:AUX2><0:AUX1>"
);
static
struct
usb_device_id
ati_remote2_id_table
[]
=
{
...
...
@@ -133,12 +194,18 @@ struct ati_remote2 {
u16
keycode
[
ATI_REMOTE2_MODES
][
ARRAY_SIZE
(
ati_remote2_key_table
)];
unsigned
int
flags
;
unsigned
int
channel_mask
;
unsigned
int
mode_mask
;
};
static
int
ati_remote2_probe
(
struct
usb_interface
*
interface
,
const
struct
usb_device_id
*
id
);
static
void
ati_remote2_disconnect
(
struct
usb_interface
*
interface
);
static
int
ati_remote2_suspend
(
struct
usb_interface
*
interface
,
pm_message_t
message
);
static
int
ati_remote2_resume
(
struct
usb_interface
*
interface
);
static
int
ati_remote2_reset_resume
(
struct
usb_interface
*
interface
);
static
int
ati_remote2_pre_reset
(
struct
usb_interface
*
interface
);
static
int
ati_remote2_post_reset
(
struct
usb_interface
*
interface
);
static
struct
usb_driver
ati_remote2_driver
=
{
.
name
=
"ati_remote2"
,
...
...
@@ -147,6 +214,9 @@ static struct usb_driver ati_remote2_driver = {
.
id_table
=
ati_remote2_id_table
,
.
suspend
=
ati_remote2_suspend
,
.
resume
=
ati_remote2_resume
,
.
reset_resume
=
ati_remote2_reset_resume
,
.
pre_reset
=
ati_remote2_pre_reset
,
.
post_reset
=
ati_remote2_post_reset
,
.
supports_autosuspend
=
1
,
};
...
...
@@ -238,7 +308,7 @@ static void ati_remote2_input_mouse(struct ati_remote2 *ar2)
channel
=
data
[
0
]
>>
4
;
if
(
!
((
1
<<
channel
)
&
channel_mask
))
if
(
!
((
1
<<
channel
)
&
ar2
->
channel_mask
))
return
;
mode
=
data
[
0
]
&
0x0F
;
...
...
@@ -250,7 +320,7 @@ static void ati_remote2_input_mouse(struct ati_remote2 *ar2)
return
;
}
if
(
!
((
1
<<
mode
)
&
mode_mask
))
if
(
!
((
1
<<
mode
)
&
ar2
->
mode_mask
))
return
;
input_event
(
idev
,
EV_REL
,
REL_X
,
(
s8
)
data
[
1
]);
...
...
@@ -277,7 +347,7 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2)
channel
=
data
[
0
]
>>
4
;
if
(
!
((
1
<<
channel
)
&
channel_mask
))
if
(
!
((
1
<<
channel
)
&
ar2
->
channel_mask
))
return
;
mode
=
data
[
0
]
&
0x0F
;
...
...
@@ -305,7 +375,7 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2)
ar2
->
mode
=
mode
;
}
if
(
!
((
1
<<
mode
)
&
mode_mask
))
if
(
!
((
1
<<
mode
)
&
ar2
->
mode_mask
))
return
;
index
=
ati_remote2_lookup
(
hw_code
);
...
...
@@ -410,7 +480,7 @@ static int ati_remote2_getkeycode(struct input_dev *idev,
int
index
,
mode
;
mode
=
scancode
>>
8
;
if
(
mode
>
ATI_REMOTE2_PC
||
!
((
1
<<
mode
)
&
mode_mask
))
if
(
mode
>
ATI_REMOTE2_PC
||
!
((
1
<<
mode
)
&
ar2
->
mode_mask
))
return
-
EINVAL
;
index
=
ati_remote2_lookup
(
scancode
&
0xFF
);
...
...
@@ -427,7 +497,7 @@ static int ati_remote2_setkeycode(struct input_dev *idev, int scancode, int keyc
int
index
,
mode
,
old_keycode
;
mode
=
scancode
>>
8
;
if
(
mode
>
ATI_REMOTE2_PC
||
!
((
1
<<
mode
)
&
mode_mask
))
if
(
mode
>
ATI_REMOTE2_PC
||
!
((
1
<<
mode
)
&
ar2
->
mode_mask
))
return
-
EINVAL
;
index
=
ati_remote2_lookup
(
scancode
&
0xFF
);
...
...
@@ -550,7 +620,7 @@ static void ati_remote2_urb_cleanup(struct ati_remote2 *ar2)
}
}
static
int
ati_remote2_setup
(
struct
ati_remote2
*
ar2
)
static
int
ati_remote2_setup
(
struct
ati_remote2
*
ar2
,
unsigned
int
ch_mask
)
{
int
r
,
i
,
channel
;
...
...
@@ -565,8 +635,8 @@ static int ati_remote2_setup(struct ati_remote2 *ar2)
channel
=
0
;
for
(
i
=
0
;
i
<
16
;
i
++
)
{
if
((
1
<<
i
)
&
ch
annel
_mask
)
{
if
(
!
(
~
(
1
<<
i
)
&
0xFFFF
&
channel
_mask
))
if
((
1
<<
i
)
&
ch_mask
)
{
if
(
!
(
~
(
1
<<
i
)
&
ch
_mask
))
channel
=
i
+
1
;
break
;
}
...
...
@@ -585,6 +655,99 @@ static int ati_remote2_setup(struct ati_remote2 *ar2)
return
0
;
}
static
ssize_t
ati_remote2_show_channel_mask
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
usb_device
*
udev
=
to_usb_device
(
dev
);
struct
usb_interface
*
intf
=
usb_ifnum_to_if
(
udev
,
0
);
struct
ati_remote2
*
ar2
=
usb_get_intfdata
(
intf
);
return
sprintf
(
buf
,
"0x%04x
\n
"
,
ar2
->
channel_mask
);
}
static
ssize_t
ati_remote2_store_channel_mask
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
struct
usb_device
*
udev
=
to_usb_device
(
dev
);
struct
usb_interface
*
intf
=
usb_ifnum_to_if
(
udev
,
0
);
struct
ati_remote2
*
ar2
=
usb_get_intfdata
(
intf
);
unsigned
long
mask
;
int
r
;
if
(
strict_strtoul
(
buf
,
0
,
&
mask
))
return
-
EINVAL
;
if
(
mask
&
~
ATI_REMOTE2_MAX_CHANNEL_MASK
)
return
-
EINVAL
;
r
=
usb_autopm_get_interface
(
ar2
->
intf
[
0
]);
if
(
r
)
{
dev_err
(
&
ar2
->
intf
[
0
]
->
dev
,
"%s(): usb_autopm_get_interface() = %d
\n
"
,
__func__
,
r
);
return
r
;
}
mutex_lock
(
&
ati_remote2_mutex
);
if
(
mask
!=
ar2
->
channel_mask
&&
!
ati_remote2_setup
(
ar2
,
mask
))
ar2
->
channel_mask
=
mask
;
mutex_unlock
(
&
ati_remote2_mutex
);
usb_autopm_put_interface
(
ar2
->
intf
[
0
]);
return
count
;
}
static
ssize_t
ati_remote2_show_mode_mask
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
usb_device
*
udev
=
to_usb_device
(
dev
);
struct
usb_interface
*
intf
=
usb_ifnum_to_if
(
udev
,
0
);
struct
ati_remote2
*
ar2
=
usb_get_intfdata
(
intf
);
return
sprintf
(
buf
,
"0x%02x
\n
"
,
ar2
->
mode_mask
);
}
static
ssize_t
ati_remote2_store_mode_mask
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
struct
usb_device
*
udev
=
to_usb_device
(
dev
);
struct
usb_interface
*
intf
=
usb_ifnum_to_if
(
udev
,
0
);
struct
ati_remote2
*
ar2
=
usb_get_intfdata
(
intf
);
unsigned
long
mask
;
if
(
strict_strtoul
(
buf
,
0
,
&
mask
))
return
-
EINVAL
;
if
(
mask
&
~
ATI_REMOTE2_MAX_MODE_MASK
)
return
-
EINVAL
;
ar2
->
mode_mask
=
mask
;
return
count
;
}
static
DEVICE_ATTR
(
channel_mask
,
0644
,
ati_remote2_show_channel_mask
,
ati_remote2_store_channel_mask
);
static
DEVICE_ATTR
(
mode_mask
,
0644
,
ati_remote2_show_mode_mask
,
ati_remote2_store_mode_mask
);
static
struct
attribute
*
ati_remote2_attrs
[]
=
{
&
dev_attr_channel_mask
.
attr
,
&
dev_attr_mode_mask
.
attr
,
NULL
,
};
static
struct
attribute_group
ati_remote2_attr_group
=
{
.
attrs
=
ati_remote2_attrs
,
};
static
int
ati_remote2_probe
(
struct
usb_interface
*
interface
,
const
struct
usb_device_id
*
id
)
{
struct
usb_device
*
udev
=
interface_to_usbdev
(
interface
);
...
...
@@ -615,7 +778,10 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d
if
(
r
)
goto
fail2
;
r
=
ati_remote2_setup
(
ar2
);
ar2
->
channel_mask
=
channel_mask
;
ar2
->
mode_mask
=
mode_mask
;
r
=
ati_remote2_setup
(
ar2
,
ar2
->
channel_mask
);
if
(
r
)
goto
fail2
;
...
...
@@ -624,19 +790,24 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d
strlcat
(
ar2
->
name
,
"ATI Remote Wonder II"
,
sizeof
(
ar2
->
name
));
r
=
ati_remote2_input_init
(
ar2
);
r
=
sysfs_create_group
(
&
udev
->
dev
.
kobj
,
&
ati_remote2_attr_group
);
if
(
r
)
goto
fail2
;
r
=
ati_remote2_input_init
(
ar2
);
if
(
r
)
goto
fail3
;
usb_set_intfdata
(
interface
,
ar2
);
interface
->
needs_remote_wakeup
=
1
;
return
0
;
fail3:
sysfs_remove_group
(
&
udev
->
dev
.
kobj
,
&
ati_remote2_attr_group
);
fail2:
ati_remote2_urb_cleanup
(
ar2
);
usb_driver_release_interface
(
&
ati_remote2_driver
,
ar2
->
intf
[
1
]);
fail1:
kfree
(
ar2
);
...
...
@@ -657,6 +828,8 @@ static void ati_remote2_disconnect(struct usb_interface *interface)
input_unregister_device
(
ar2
->
idev
);
sysfs_remove_group
(
&
ar2
->
udev
->
dev
.
kobj
,
&
ati_remote2_attr_group
);
ati_remote2_urb_cleanup
(
ar2
);
usb_driver_release_interface
(
&
ati_remote2_driver
,
ar2
->
intf
[
1
]);
...
...
@@ -715,6 +888,78 @@ static int ati_remote2_resume(struct usb_interface *interface)
return
r
;
}
static
int
ati_remote2_reset_resume
(
struct
usb_interface
*
interface
)
{
struct
ati_remote2
*
ar2
;
struct
usb_host_interface
*
alt
=
interface
->
cur_altsetting
;
int
r
=
0
;
if
(
alt
->
desc
.
bInterfaceNumber
)
return
0
;
ar2
=
usb_get_intfdata
(
interface
);
dev_dbg
(
&
ar2
->
intf
[
0
]
->
dev
,
"%s()
\n
"
,
__func__
);
mutex_lock
(
&
ati_remote2_mutex
);
r
=
ati_remote2_setup
(
ar2
,
ar2
->
channel_mask
);
if
(
r
)
goto
out
;
if
(
ar2
->
flags
&
ATI_REMOTE2_OPENED
)
r
=
ati_remote2_submit_urbs
(
ar2
);
if
(
!
r
)
ar2
->
flags
&=
~
ATI_REMOTE2_SUSPENDED
;
out:
mutex_unlock
(
&
ati_remote2_mutex
);
return
r
;
}
static
int
ati_remote2_pre_reset
(
struct
usb_interface
*
interface
)
{
struct
ati_remote2
*
ar2
;
struct
usb_host_interface
*
alt
=
interface
->
cur_altsetting
;
if
(
alt
->
desc
.
bInterfaceNumber
)
return
0
;
ar2
=
usb_get_intfdata
(
interface
);
dev_dbg
(
&
ar2
->
intf
[
0
]
->
dev
,
"%s()
\n
"
,
__func__
);
mutex_lock
(
&
ati_remote2_mutex
);
if
(
ar2
->
flags
==
ATI_REMOTE2_OPENED
)
ati_remote2_kill_urbs
(
ar2
);
return
0
;
}
static
int
ati_remote2_post_reset
(
struct
usb_interface
*
interface
)
{
struct
ati_remote2
*
ar2
;
struct
usb_host_interface
*
alt
=
interface
->
cur_altsetting
;
int
r
=
0
;
if
(
alt
->
desc
.
bInterfaceNumber
)
return
0
;
ar2
=
usb_get_intfdata
(
interface
);
dev_dbg
(
&
ar2
->
intf
[
0
]
->
dev
,
"%s()
\n
"
,
__func__
);
if
(
ar2
->
flags
==
ATI_REMOTE2_OPENED
)
r
=
ati_remote2_submit_urbs
(
ar2
);
mutex_unlock
(
&
ati_remote2_mutex
);
return
r
;
}
static
int
__init
ati_remote2_init
(
void
)
{
int
r
;
...
...
drivers/input/misc/rb532_button.c
0 → 100644
View file @
ba28f22e
/*
* Support for the S1 button on Routerboard 532
*
* Copyright (C) 2009 Phil Sutter <n0-1@freewrt.org>
*/
#include <linux/input-polldev.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <asm/mach-rc32434/gpio.h>
#include <asm/mach-rc32434/rb.h>
#define DRV_NAME "rb532-button"
#define RB532_BTN_RATE 100
/* msec */
#define RB532_BTN_KSYM BTN_0
/* The S1 button state is provided by GPIO pin 1. But as this
* pin is also used for uart input as alternate function, the
* operational modes must be switched first:
* 1) disable uart using set_latch_u5()
* 2) turn off alternate function implicitly through
* gpio_direction_input()
* 3) read the GPIO's current value
* 4) undo step 2 by enabling alternate function (in this
* mode the GPIO direction is fixed, so no change needed)
* 5) turn on uart again
* The GPIO value occurs to be inverted, so pin high means
* button is not pressed.
*/
static
bool
rb532_button_pressed
(
void
)
{
int
val
;
set_latch_u5
(
0
,
LO_FOFF
);
gpio_direction_input
(
GPIO_BTN_S1
);
val
=
gpio_get_value
(
GPIO_BTN_S1
);
rb532_gpio_set_func
(
GPIO_BTN_S1
);
set_latch_u5
(
LO_FOFF
,
0
);
return
!
val
;
}
static
void
rb532_button_poll
(
struct
input_polled_dev
*
poll_dev
)
{
input_report_key
(
poll_dev
->
input
,
RB532_BTN_KSYM
,
rb532_button_pressed
());
input_sync
(
poll_dev
->
input
);
}
static
int
__devinit
rb532_button_probe
(
struct
platform_device
*
pdev
)
{
struct
input_polled_dev
*
poll_dev
;
int
error
;
poll_dev
=
input_allocate_polled_device
();
if
(
!
poll_dev
)
return
-
ENOMEM
;
poll_dev
->
poll
=
rb532_button_poll
;
poll_dev
->
poll_interval
=
RB532_BTN_RATE
;
poll_dev
->
input
->
name
=
"rb532 button"
;
poll_dev
->
input
->
phys
=
"rb532/button0"
;
poll_dev
->
input
->
id
.
bustype
=
BUS_HOST
;
poll_dev
->
input
->
dev
.
parent
=
&
pdev
->
dev
;
dev_set_drvdata
(
&
pdev
->
dev
,
poll_dev
);
input_set_capability
(
poll_dev
->
input
,
EV_KEY
,
RB532_BTN_KSYM
);
error
=
input_register_polled_device
(
poll_dev
);
if
(
error
)
{
input_free_polled_device
(
poll_dev
);
return
error
;
}
return
0
;
}
static
int
__devexit
rb532_button_remove
(
struct
platform_device
*
pdev
)
{
struct
input_polled_dev
*
poll_dev
=
dev_get_drvdata
(
&
pdev
->
dev
);
input_unregister_polled_device
(
poll_dev
);
input_free_polled_device
(
poll_dev
);
dev_set_drvdata
(
&
pdev
->
dev
,
NULL
);
return
0
;
}
static
struct
platform_driver
rb532_button_driver
=
{
.
probe
=
rb532_button_probe
,
.
remove
=
__devexit_p
(
rb532_button_remove
),
.
driver
=
{
.
name
=
DRV_NAME
,
.
owner
=
THIS_MODULE
,
},
};
static
int
__init
rb532_button_init
(
void
)
{
return
platform_driver_register
(
&
rb532_button_driver
);
}
static
void
__exit
rb532_button_exit
(
void
)
{
platform_driver_unregister
(
&
rb532_button_driver
);
}
module_init
(
rb532_button_init
);
module_exit
(
rb532_button_exit
);
MODULE_AUTHOR
(
"Phil Sutter <n0-1@freewrt.org>"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_DESCRIPTION
(
"Support for S1 button on Routerboard 532"
);
MODULE_ALIAS
(
"platform:"
DRV_NAME
);
drivers/input/misc/rotary_encoder.c
0 → 100644
View file @
ba28f22e
/*
* rotary_encoder.c
*
* (c) 2009 Daniel Mack <daniel@caiaq.de>
*
* state machine code inspired by code from Tim Ruetz
*
* A generic driver for rotary encoders connected to GPIO lines.
* See file:Documentation/input/rotary_encoder.txt for more information
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/rotary_encoder.h>
#define DRV_NAME "rotary-encoder"
struct
rotary_encoder
{
unsigned
int
irq_a
;
unsigned
int
irq_b
;
unsigned
int
pos
;
unsigned
int
armed
;
unsigned
int
dir
;
struct
input_dev
*
input
;
struct
rotary_encoder_platform_data
*
pdata
;
};
static
irqreturn_t
rotary_encoder_irq
(
int
irq
,
void
*
dev_id
)
{
struct
rotary_encoder
*
encoder
=
dev_id
;
struct
rotary_encoder_platform_data
*
pdata
=
encoder
->
pdata
;
int
a
=
!!
gpio_get_value
(
pdata
->
gpio_a
);
int
b
=
!!
gpio_get_value
(
pdata
->
gpio_b
);
int
state
;
a
^=
pdata
->
inverted_a
;
b
^=
pdata
->
inverted_b
;
state
=
(
a
<<
1
)
|
b
;
switch
(
state
)
{
case
0x0
:
if
(
!
encoder
->
armed
)
break
;
if
(
encoder
->
dir
)
{
/* turning counter-clockwise */
encoder
->
pos
+=
pdata
->
steps
;
encoder
->
pos
--
;
encoder
->
pos
%=
pdata
->
steps
;
}
else
{
/* turning clockwise */
encoder
->
pos
++
;
encoder
->
pos
%=
pdata
->
steps
;
}
input_report_abs
(
encoder
->
input
,
pdata
->
axis
,
encoder
->
pos
);
input_sync
(
encoder
->
input
);
encoder
->
armed
=
0
;
break
;
case
0x1
:
case
0x2
:
if
(
encoder
->
armed
)
encoder
->
dir
=
state
-
1
;
break
;
case
0x3
:
encoder
->
armed
=
1
;
break
;
}
return
IRQ_HANDLED
;
}
static
int
__devinit
rotary_encoder_probe
(
struct
platform_device
*
pdev
)
{
struct
rotary_encoder_platform_data
*
pdata
=
pdev
->
dev
.
platform_data
;
struct
rotary_encoder
*
encoder
;
struct
input_dev
*
input
;
int
err
;
if
(
!
pdata
||
!
pdata
->
steps
)
{
dev_err
(
&
pdev
->
dev
,
"invalid platform data
\n
"
);
return
-
ENOENT
;
}
encoder
=
kzalloc
(
sizeof
(
struct
rotary_encoder
),
GFP_KERNEL
);
input
=
input_allocate_device
();
if
(
!
encoder
||
!
input
)
{
dev_err
(
&
pdev
->
dev
,
"failed to allocate memory for device
\n
"
);
err
=
-
ENOMEM
;
goto
exit_free_mem
;
}
encoder
->
input
=
input
;
encoder
->
pdata
=
pdata
;
encoder
->
irq_a
=
gpio_to_irq
(
pdata
->
gpio_a
);
encoder
->
irq_b
=
gpio_to_irq
(
pdata
->
gpio_b
);
/* create and register the input driver */
input
->
name
=
pdev
->
name
;
input
->
id
.
bustype
=
BUS_HOST
;
input
->
dev
.
parent
=
&
pdev
->
dev
;
input
->
evbit
[
0
]
=
BIT_MASK
(
EV_ABS
);
input_set_abs_params
(
encoder
->
input
,
pdata
->
axis
,
0
,
pdata
->
steps
,
0
,
1
);
err
=
input_register_device
(
input
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"failed to register input device
\n
"
);
goto
exit_free_mem
;
}
/* request the GPIOs */
err
=
gpio_request
(
pdata
->
gpio_a
,
DRV_NAME
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"unable to request GPIO %d
\n
"
,
pdata
->
gpio_a
);
goto
exit_unregister_input
;
}
err
=
gpio_request
(
pdata
->
gpio_b
,
DRV_NAME
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"unable to request GPIO %d
\n
"
,
pdata
->
gpio_b
);
goto
exit_free_gpio_a
;
}
/* request the IRQs */
err
=
request_irq
(
encoder
->
irq_a
,
&
rotary_encoder_irq
,
IORESOURCE_IRQ_HIGHEDGE
|
IORESOURCE_IRQ_LOWEDGE
,
DRV_NAME
,
encoder
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"unable to request IRQ %d
\n
"
,
encoder
->
irq_a
);
goto
exit_free_gpio_b
;
}
err
=
request_irq
(
encoder
->
irq_b
,
&
rotary_encoder_irq
,
IORESOURCE_IRQ_HIGHEDGE
|
IORESOURCE_IRQ_LOWEDGE
,
DRV_NAME
,
encoder
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"unable to request IRQ %d
\n
"
,
encoder
->
irq_b
);
goto
exit_free_irq_a
;
}
platform_set_drvdata
(
pdev
,
encoder
);
return
0
;
exit_free_irq_a:
free_irq
(
encoder
->
irq_a
,
encoder
);
exit_free_gpio_b:
gpio_free
(
pdata
->
gpio_b
);
exit_free_gpio_a:
gpio_free
(
pdata
->
gpio_a
);
exit_unregister_input:
input_unregister_device
(
input
);
input
=
NULL
;
/* so we don't try to free it */
exit_free_mem:
input_free_device
(
input
);
kfree
(
encoder
);
return
err
;
}
static
int
__devexit
rotary_encoder_remove
(
struct
platform_device
*
pdev
)
{
struct
rotary_encoder
*
encoder
=
platform_get_drvdata
(
pdev
);
struct
rotary_encoder_platform_data
*
pdata
=
pdev
->
dev
.
platform_data
;
free_irq
(
encoder
->
irq_a
,
encoder
);
free_irq
(
encoder
->
irq_b
,
encoder
);
gpio_free
(
pdata
->
gpio_a
);
gpio_free
(
pdata
->
gpio_b
);
input_unregister_device
(
encoder
->
input
);
platform_set_drvdata
(
pdev
,
NULL
);
kfree
(
encoder
);
return
0
;
}
static
struct
platform_driver
rotary_encoder_driver
=
{
.
probe
=
rotary_encoder_probe
,
.
remove
=
__devexit_p
(
rotary_encoder_remove
),
.
driver
=
{
.
name
=
DRV_NAME
,
.
owner
=
THIS_MODULE
,
}
};
static
int
__init
rotary_encoder_init
(
void
)
{
return
platform_driver_register
(
&
rotary_encoder_driver
);
}
static
void
__exit
rotary_encoder_exit
(
void
)
{
platform_driver_unregister
(
&
rotary_encoder_driver
);
}
module_init
(
rotary_encoder_init
);
module_exit
(
rotary_encoder_exit
);
MODULE_ALIAS
(
"platform:"
DRV_NAME
);
MODULE_DESCRIPTION
(
"GPIO rotary encoder driver"
);
MODULE_AUTHOR
(
"Daniel Mack <daniel@caiaq.de>"
);
MODULE_LICENSE
(
"GPL v2"
);
drivers/input/mouse/Kconfig
View file @
ba28f22e
...
...
@@ -292,4 +292,15 @@ config MOUSE_PXA930_TRKBALL
help
Say Y here to support PXA930 Trackball mouse.
config MOUSE_MAPLE
tristate "Maple mouse (for the Dreamcast)"
depends on MAPLE
help
This driver supports the Maple mouse on the SEGA Dreamcast.
Most Dreamcast users, who have a mouse, will say Y here.
To compile this driver as a module choose M here: the module will be
called maplemouse.
endif
drivers/input/mouse/Makefile
View file @
ba28f22e
...
...
@@ -6,18 +6,19 @@
obj-$(CONFIG_MOUSE_AMIGA)
+=
amimouse.o
obj-$(CONFIG_MOUSE_APPLETOUCH)
+=
appletouch.o
obj-$(CONFIG_MOUSE_BCM5974)
+=
bcm5974.o
obj-$(CONFIG_MOUSE_ATARI)
+=
atarimouse.o
obj-$(CONFIG_MOUSE_RISCPC)
+=
rpcmouse.o
obj-$(CONFIG_MOUSE_BCM5974)
+=
bcm5974.o
obj-$(CONFIG_MOUSE_GPIO)
+=
gpio_mouse.o
obj-$(CONFIG_MOUSE_HIL)
+=
hil_ptr.o
obj-$(CONFIG_MOUSE_INPORT)
+=
inport.o
obj-$(CONFIG_MOUSE_LOGIBM)
+=
logibm.o
obj-$(CONFIG_MOUSE_MAPLE)
+=
maplemouse.o
obj-$(CONFIG_MOUSE_PC110PAD)
+=
pc110pad.o
obj-$(CONFIG_MOUSE_PS2)
+=
psmouse.o
obj-$(CONFIG_MOUSE_PXA930_TRKBALL)
+=
pxa930_trkball.o
obj-$(CONFIG_MOUSE_RISCPC)
+=
rpcmouse.o
obj-$(CONFIG_MOUSE_SERIAL)
+=
sermouse.o
obj-$(CONFIG_MOUSE_HIL)
+=
hil_ptr.o
obj-$(CONFIG_MOUSE_VSXXXAA)
+=
vsxxxaa.o
obj-$(CONFIG_MOUSE_GPIO)
+=
gpio_mouse.o
psmouse-objs
:=
psmouse-base.o synaptics.o
...
...
drivers/input/mouse/hgpk.c
View file @
ba28f22e
...
...
@@ -472,7 +472,7 @@ static enum hgpk_model_t hgpk_get_model(struct psmouse *psmouse)
return
-
EIO
;
}
hgpk_dbg
(
psmouse
,
"ID: %02x %02x %02x"
,
param
[
0
],
param
[
1
],
param
[
2
]);
hgpk_dbg
(
psmouse
,
"ID: %02x %02x %02x
\n
"
,
param
[
0
],
param
[
1
],
param
[
2
]);
/* HGPK signature: 0x67, 0x00, 0x<model> */
if
(
param
[
0
]
!=
0x67
||
param
[
1
]
!=
0x00
)
...
...
drivers/input/mouse/maplemouse.c
0 → 100644
View file @
ba28f22e
/*
* SEGA Dreamcast mouse driver
* Based on drivers/usb/usbmouse.c
*
* Copyright Yaegashi Takeshi, 2001
* Adrian McMenamin, 2008
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/maple.h>
MODULE_AUTHOR
(
"Adrian McMenamin <adrian@mcmen.demon.co.uk>"
);
MODULE_DESCRIPTION
(
"SEGA Dreamcast mouse driver"
);
MODULE_LICENSE
(
"GPL"
);
struct
dc_mouse
{
struct
input_dev
*
dev
;
struct
maple_device
*
mdev
;
};
static
void
dc_mouse_callback
(
struct
mapleq
*
mq
)
{
int
buttons
,
relx
,
rely
,
relz
;
struct
maple_device
*
mapledev
=
mq
->
dev
;
struct
dc_mouse
*
mse
=
maple_get_drvdata
(
mapledev
);
struct
input_dev
*
dev
=
mse
->
dev
;
unsigned
char
*
res
=
mq
->
recvbuf
;
buttons
=
~
res
[
8
];
relx
=
*
(
unsigned
short
*
)(
res
+
12
)
-
512
;
rely
=
*
(
unsigned
short
*
)(
res
+
14
)
-
512
;
relz
=
*
(
unsigned
short
*
)(
res
+
16
)
-
512
;
input_report_key
(
dev
,
BTN_LEFT
,
buttons
&
4
);
input_report_key
(
dev
,
BTN_MIDDLE
,
buttons
&
9
);
input_report_key
(
dev
,
BTN_RIGHT
,
buttons
&
2
);
input_report_rel
(
dev
,
REL_X
,
relx
);
input_report_rel
(
dev
,
REL_Y
,
rely
);
input_report_rel
(
dev
,
REL_WHEEL
,
relz
);
input_sync
(
dev
);
}
static
int
dc_mouse_open
(
struct
input_dev
*
dev
)
{
struct
dc_mouse
*
mse
=
dev
->
dev
.
platform_data
;
maple_getcond_callback
(
mse
->
mdev
,
dc_mouse_callback
,
HZ
/
50
,
MAPLE_FUNC_MOUSE
);
return
0
;
}
static
void
dc_mouse_close
(
struct
input_dev
*
dev
)
{
struct
dc_mouse
*
mse
=
dev
->
dev
.
platform_data
;
maple_getcond_callback
(
mse
->
mdev
,
dc_mouse_callback
,
0
,
MAPLE_FUNC_MOUSE
);
}
static
int
__devinit
probe_maple_mouse
(
struct
device
*
dev
)
{
struct
maple_device
*
mdev
=
to_maple_dev
(
dev
);
struct
maple_driver
*
mdrv
=
to_maple_driver
(
dev
->
driver
);
struct
input_dev
*
input_dev
;
struct
dc_mouse
*
mse
;
int
error
;
mse
=
kzalloc
(
sizeof
(
struct
dc_mouse
),
GFP_KERNEL
);
input_dev
=
input_allocate_device
();
if
(
!
mse
||
!
input_dev
)
{
error
=
-
ENOMEM
;
goto
fail
;
}
mse
->
dev
=
input_dev
;
mse
->
mdev
=
mdev
;
input_set_drvdata
(
input_dev
,
mse
);
input_dev
->
evbit
[
0
]
=
BIT_MASK
(
EV_KEY
)
|
BIT_MASK
(
EV_REL
);
input_dev
->
keybit
[
BIT_WORD
(
BTN_MOUSE
)]
=
BIT_MASK
(
BTN_LEFT
)
|
BIT_MASK
(
BTN_RIGHT
)
|
BIT_MASK
(
BTN_MIDDLE
);
input_dev
->
relbit
[
0
]
=
BIT_MASK
(
REL_X
)
|
BIT_MASK
(
REL_Y
)
|
BIT_MASK
(
REL_WHEEL
);
input_dev
->
name
=
mdev
->
product_name
;
input_dev
->
id
.
bustype
=
BUS_HOST
;
input_dev
->
open
=
dc_mouse_open
;
input_dev
->
close
=
dc_mouse_close
;
mdev
->
driver
=
mdrv
;
maple_set_drvdata
(
mdev
,
mse
);
error
=
input_register_device
(
input_dev
);
if
(
error
)
goto
fail
;
return
0
;
fail:
input_free_device
(
input_dev
);
maple_set_drvdata
(
mdev
,
NULL
);
kfree
(
mse
);
mdev
->
driver
=
NULL
;
return
error
;
}
static
int
__devexit
remove_maple_mouse
(
struct
device
*
dev
)
{
struct
maple_device
*
mdev
=
to_maple_dev
(
dev
);
struct
dc_mouse
*
mse
=
maple_get_drvdata
(
mdev
);
mdev
->
callback
=
NULL
;
input_unregister_device
(
mse
->
dev
);
maple_set_drvdata
(
mdev
,
NULL
);
kfree
(
mse
);
return
0
;
}
static
struct
maple_driver
dc_mouse_driver
=
{
.
function
=
MAPLE_FUNC_MOUSE
,
.
drv
=
{
.
name
=
"Dreamcast_mouse"
,
.
probe
=
probe_maple_mouse
,
.
remove
=
__devexit_p
(
remove_maple_mouse
),
},
};
static
int
__init
dc_mouse_init
(
void
)
{
return
maple_driver_register
(
&
dc_mouse_driver
);
}
static
void
__exit
dc_mouse_exit
(
void
)
{
maple_driver_unregister
(
&
dc_mouse_driver
);
}
module_init
(
dc_mouse_init
);
module_exit
(
dc_mouse_exit
);
drivers/input/mouse/pc110pad.c
View file @
ba28f22e
...
...
@@ -111,11 +111,8 @@ static int __init pc110pad_init(void)
struct
pci_dev
*
dev
;
int
err
;
dev
=
pci_get_device
(
PCI_ANY_ID
,
PCI_ANY_ID
,
NULL
);
if
(
dev
)
{
pci_dev_put
(
dev
);
if
(
!
no_pci_devices
())
return
-
ENODEV
;
}
if
(
!
request_region
(
pc110pad_io
,
4
,
"pc110pad"
))
{
printk
(
KERN_ERR
"pc110pad: I/O area %#x-%#x in use.
\n
"
,
...
...
drivers/input/serio/i8042-x86ia64io.h
View file @
ba28f22e
...
...
@@ -151,6 +151,14 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
DMI_MATCH
(
DMI_PRODUCT_VERSION
,
"01"
),
},
},
{
.
ident
=
"HP DV9700"
,
.
matches
=
{
DMI_MATCH
(
DMI_SYS_VENDOR
,
"Hewlett-Packard"
),
DMI_MATCH
(
DMI_PRODUCT_NAME
,
"HP Pavilion dv9700"
),
DMI_MATCH
(
DMI_PRODUCT_VERSION
,
"Rev 1"
),
},
},
{
}
};
...
...
drivers/input/touchscreen/Kconfig
View file @
ba28f22e
...
...
@@ -29,6 +29,51 @@ config TOUCHSCREEN_ADS7846
To compile this driver as a module, choose M here: the
module will be called ads7846.
config TOUCHSCREEN_AD7877
tristate "AD7877 based touchscreens"
depends on SPI_MASTER
help
Say Y here if you have a touchscreen interface using the
AD7877 controller, and your board-specific initialization
code includes that in its table of SPI devices.
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
module will be called ad7877.
config TOUCHSCREEN_AD7879_I2C
tristate "AD7879 based touchscreens: AD7879-1 I2C Interface"
depends on I2C
select TOUCHSCREEN_AD7879
help
Say Y here if you have a touchscreen interface using the
AD7879-1 controller, and your board-specific initialization
code includes that in its table of I2C devices.
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
module will be called ad7879.
config TOUCHSCREEN_AD7879_SPI
tristate "AD7879 based touchscreens: AD7879 SPI Interface"
depends on SPI_MASTER && TOUCHSCREEN_AD7879_I2C = n
select TOUCHSCREEN_AD7879
help
Say Y here if you have a touchscreen interface using the
AD7879 controller, and your board-specific initialization
code includes that in its table of SPI devices.
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
module will be called ad7879.
config TOUCHSCREEN_AD7879
tristate
default n
config TOUCHSCREEN_BITSY
tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
depends on SA1100_BITSY
...
...
@@ -308,6 +353,19 @@ config TOUCHSCREEN_WM97XX_MAINSTONE
To compile this driver as a module, choose M here: the
module will be called mainstone-wm97xx.
config TOUCHSCREEN_WM97XX_ZYLONITE
tristate "Zylonite accelerated touch"
depends on TOUCHSCREEN_WM97XX && MACH_ZYLONITE
select TOUCHSCREEN_WM9713
help
Say Y here for support for streaming mode with the touchscreen
on Zylonite systems.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called zylonite-wm97xx.
config TOUCHSCREEN_USB_COMPOSITE
tristate "USB Touchscreen Driver"
depends on USB_ARCH_HAS_HCD
...
...
drivers/input/touchscreen/Makefile
View file @
ba28f22e
...
...
@@ -6,6 +6,8 @@
wm97xx-ts-y
:=
wm97xx-core.o
obj-$(CONFIG_TOUCHSCREEN_AD7877)
+=
ad7877.o
obj-$(CONFIG_TOUCHSCREEN_AD7879)
+=
ad7879.o
obj-$(CONFIG_TOUCHSCREEN_ADS7846)
+=
ads7846.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC)
+=
atmel_tsadcc.o
obj-$(CONFIG_TOUCHSCREEN_BITSY)
+=
h3600_ts_input.o
...
...
@@ -34,3 +36,4 @@ 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
obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)
+=
zylonite-wm97xx.o
drivers/input/touchscreen/ad7877.c
0 → 100644
View file @
ba28f22e
/*
* Copyright (C) 2006-2008 Michael Hennerich, Analog Devices Inc.
*
* Description: AD7877 based touchscreen, sensor (ADCs), DAC and GPIO driver
* Based on: ads7846.c
*
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see the file COPYING, or write
* to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* History:
* Copyright (c) 2005 David Brownell
* Copyright (c) 2006 Nokia Corporation
* Various changes: Imre Deak <imre.deak@nokia.com>
*
* Using code from:
* - corgi_ts.c
* Copyright (C) 2004-2005 Richard Purdie
* - omap_ts.[hc], ads7846.h, ts_osk.c
* Copyright (C) 2002 MontaVista Software
* Copyright (C) 2004 Texas Instruments
* Copyright (C) 2005 Dirk Behme
*/
#include <linux/device.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/spi/ad7877.h>
#include <asm/irq.h>
#define TS_PEN_UP_TIMEOUT msecs_to_jiffies(50)
#define MAX_SPI_FREQ_HZ 20000000
#define MAX_12BIT ((1<<12)-1)
#define AD7877_REG_ZEROS 0
#define AD7877_REG_CTRL1 1
#define AD7877_REG_CTRL2 2
#define AD7877_REG_ALERT 3
#define AD7877_REG_AUX1HIGH 4
#define AD7877_REG_AUX1LOW 5
#define AD7877_REG_BAT1HIGH 6
#define AD7877_REG_BAT1LOW 7
#define AD7877_REG_BAT2HIGH 8
#define AD7877_REG_BAT2LOW 9
#define AD7877_REG_TEMP1HIGH 10
#define AD7877_REG_TEMP1LOW 11
#define AD7877_REG_SEQ0 12
#define AD7877_REG_SEQ1 13
#define AD7877_REG_DAC 14
#define AD7877_REG_NONE1 15
#define AD7877_REG_EXTWRITE 15
#define AD7877_REG_XPLUS 16
#define AD7877_REG_YPLUS 17
#define AD7877_REG_Z2 18
#define AD7877_REG_aux1 19
#define AD7877_REG_aux2 20
#define AD7877_REG_aux3 21
#define AD7877_REG_bat1 22
#define AD7877_REG_bat2 23
#define AD7877_REG_temp1 24
#define AD7877_REG_temp2 25
#define AD7877_REG_Z1 26
#define AD7877_REG_GPIOCTRL1 27
#define AD7877_REG_GPIOCTRL2 28
#define AD7877_REG_GPIODATA 29
#define AD7877_REG_NONE2 30
#define AD7877_REG_NONE3 31
#define AD7877_SEQ_YPLUS_BIT (1<<11)
#define AD7877_SEQ_XPLUS_BIT (1<<10)
#define AD7877_SEQ_Z2_BIT (1<<9)
#define AD7877_SEQ_AUX1_BIT (1<<8)
#define AD7877_SEQ_AUX2_BIT (1<<7)
#define AD7877_SEQ_AUX3_BIT (1<<6)
#define AD7877_SEQ_BAT1_BIT (1<<5)
#define AD7877_SEQ_BAT2_BIT (1<<4)
#define AD7877_SEQ_TEMP1_BIT (1<<3)
#define AD7877_SEQ_TEMP2_BIT (1<<2)
#define AD7877_SEQ_Z1_BIT (1<<1)
enum
{
AD7877_SEQ_YPOS
=
0
,
AD7877_SEQ_XPOS
=
1
,
AD7877_SEQ_Z2
=
2
,
AD7877_SEQ_AUX1
=
3
,
AD7877_SEQ_AUX2
=
4
,
AD7877_SEQ_AUX3
=
5
,
AD7877_SEQ_BAT1
=
6
,
AD7877_SEQ_BAT2
=
7
,
AD7877_SEQ_TEMP1
=
8
,
AD7877_SEQ_TEMP2
=
9
,
AD7877_SEQ_Z1
=
10
,
AD7877_NR_SENSE
=
11
,
};
/* DAC Register Default RANGE 0 to Vcc, Volatge Mode, DAC On */
#define AD7877_DAC_CONF 0x1
/* If gpio3 is set AUX3/GPIO3 acts as GPIO Output */
#define AD7877_EXTW_GPIO_3_CONF 0x1C4
#define AD7877_EXTW_GPIO_DATA 0x200
/* Control REG 2 */
#define AD7877_TMR(x) ((x & 0x3) << 0)
#define AD7877_REF(x) ((x & 0x1) << 2)
#define AD7877_POL(x) ((x & 0x1) << 3)
#define AD7877_FCD(x) ((x & 0x3) << 4)
#define AD7877_PM(x) ((x & 0x3) << 6)
#define AD7877_ACQ(x) ((x & 0x3) << 8)
#define AD7877_AVG(x) ((x & 0x3) << 10)
/* Control REG 1 */
#define AD7877_SER (1 << 11)
/* non-differential */
#define AD7877_DFR (0 << 11)
/* differential */
#define AD7877_MODE_NOC (0)
/* Do not convert */
#define AD7877_MODE_SCC (1)
/* Single channel conversion */
#define AD7877_MODE_SEQ0 (2)
/* Sequence 0 in Slave Mode */
#define AD7877_MODE_SEQ1 (3)
/* Sequence 1 in Master Mode */
#define AD7877_CHANADD(x) ((x&0xF)<<7)
#define AD7877_READADD(x) ((x)<<2)
#define AD7877_WRITEADD(x) ((x)<<12)
#define AD7877_READ_CHAN(x) (AD7877_WRITEADD(AD7877_REG_CTRL1) | AD7877_SER | \
AD7877_MODE_SCC | AD7877_CHANADD(AD7877_REG_ ## x) | \
AD7877_READADD(AD7877_REG_ ## x))
#define AD7877_MM_SEQUENCE (AD7877_SEQ_YPLUS_BIT | AD7877_SEQ_XPLUS_BIT | \
AD7877_SEQ_Z2_BIT | AD7877_SEQ_Z1_BIT)
/*
* Non-touchscreen sensors only use single-ended conversions.
*/
struct
ser_req
{
u16
reset
;
u16
ref_on
;
u16
command
;
u16
sample
;
struct
spi_message
msg
;
struct
spi_transfer
xfer
[
6
];
};
struct
ad7877
{
struct
input_dev
*
input
;
char
phys
[
32
];
struct
spi_device
*
spi
;
u16
model
;
u16
vref_delay_usecs
;
u16
x_plate_ohms
;
u16
pressure_max
;
u16
cmd_crtl1
;
u16
cmd_crtl2
;
u16
cmd_dummy
;
u16
dac
;
u8
stopacq_polarity
;
u8
first_conversion_delay
;
u8
acquisition_time
;
u8
averaging
;
u8
pen_down_acc_interval
;
u16
conversion_data
[
AD7877_NR_SENSE
];
struct
spi_transfer
xfer
[
AD7877_NR_SENSE
+
2
];
struct
spi_message
msg
;
struct
mutex
mutex
;
unsigned
disabled
:
1
;
/* P: mutex */
unsigned
gpio3
:
1
;
/* P: mutex */
unsigned
gpio4
:
1
;
/* P: mutex */
spinlock_t
lock
;
struct
timer_list
timer
;
/* P: lock */
unsigned
pending
:
1
;
/* P: lock */
};
static
int
gpio3
;
module_param
(
gpio3
,
int
,
0
);
MODULE_PARM_DESC
(
gpio3
,
"If gpio3 is set to 1 AUX3 acts as GPIO3"
);
/*
* ad7877_read/write are only used for initial setup and for sysfs controls.
* The main traffic is done using spi_async() in the interrupt handler.
*/
static
int
ad7877_read
(
struct
spi_device
*
spi
,
u16
reg
)
{
struct
ser_req
*
req
;
int
status
,
ret
;
req
=
kzalloc
(
sizeof
*
req
,
GFP_KERNEL
);
if
(
!
req
)
return
-
ENOMEM
;
spi_message_init
(
&
req
->
msg
);
req
->
command
=
(
u16
)
(
AD7877_WRITEADD
(
AD7877_REG_CTRL1
)
|
AD7877_READADD
(
reg
));
req
->
xfer
[
0
].
tx_buf
=
&
req
->
command
;
req
->
xfer
[
0
].
len
=
2
;
req
->
xfer
[
1
].
rx_buf
=
&
req
->
sample
;
req
->
xfer
[
1
].
len
=
2
;
spi_message_add_tail
(
&
req
->
xfer
[
0
],
&
req
->
msg
);
spi_message_add_tail
(
&
req
->
xfer
[
1
],
&
req
->
msg
);
status
=
spi_sync
(
spi
,
&
req
->
msg
);
ret
=
status
?
:
req
->
sample
;
kfree
(
req
);
return
ret
;
}
static
int
ad7877_write
(
struct
spi_device
*
spi
,
u16
reg
,
u16
val
)
{
struct
ser_req
*
req
;
int
status
;
req
=
kzalloc
(
sizeof
*
req
,
GFP_KERNEL
);
if
(
!
req
)
return
-
ENOMEM
;
spi_message_init
(
&
req
->
msg
);
req
->
command
=
(
u16
)
(
AD7877_WRITEADD
(
reg
)
|
(
val
&
MAX_12BIT
));
req
->
xfer
[
0
].
tx_buf
=
&
req
->
command
;
req
->
xfer
[
0
].
len
=
2
;
spi_message_add_tail
(
&
req
->
xfer
[
0
],
&
req
->
msg
);
status
=
spi_sync
(
spi
,
&
req
->
msg
);
kfree
(
req
);
return
status
;
}
static
int
ad7877_read_adc
(
struct
spi_device
*
spi
,
unsigned
command
)
{
struct
ad7877
*
ts
=
dev_get_drvdata
(
&
spi
->
dev
);
struct
ser_req
*
req
;
int
status
;
int
sample
;
int
i
;
req
=
kzalloc
(
sizeof
*
req
,
GFP_KERNEL
);
if
(
!
req
)
return
-
ENOMEM
;
spi_message_init
(
&
req
->
msg
);
/* activate reference, so it has time to settle; */
req
->
ref_on
=
AD7877_WRITEADD
(
AD7877_REG_CTRL2
)
|
AD7877_POL
(
ts
->
stopacq_polarity
)
|
AD7877_AVG
(
0
)
|
AD7877_PM
(
2
)
|
AD7877_TMR
(
0
)
|
AD7877_ACQ
(
ts
->
acquisition_time
)
|
AD7877_FCD
(
0
);
req
->
reset
=
AD7877_WRITEADD
(
AD7877_REG_CTRL1
)
|
AD7877_MODE_NOC
;
req
->
command
=
(
u16
)
command
;
req
->
xfer
[
0
].
tx_buf
=
&
req
->
reset
;
req
->
xfer
[
0
].
len
=
2
;
req
->
xfer
[
1
].
tx_buf
=
&
req
->
ref_on
;
req
->
xfer
[
1
].
len
=
2
;
req
->
xfer
[
1
].
delay_usecs
=
ts
->
vref_delay_usecs
;
req
->
xfer
[
2
].
tx_buf
=
&
req
->
command
;
req
->
xfer
[
2
].
len
=
2
;
req
->
xfer
[
2
].
delay_usecs
=
ts
->
vref_delay_usecs
;
req
->
xfer
[
3
].
rx_buf
=
&
req
->
sample
;
req
->
xfer
[
3
].
len
=
2
;
req
->
xfer
[
4
].
tx_buf
=
&
ts
->
cmd_crtl2
;
/*REF OFF*/
req
->
xfer
[
4
].
len
=
2
;
req
->
xfer
[
5
].
tx_buf
=
&
ts
->
cmd_crtl1
;
/*DEFAULT*/
req
->
xfer
[
5
].
len
=
2
;
/* group all the transfers together, so we can't interfere with
* reading touchscreen state; disable penirq while sampling
*/
for
(
i
=
0
;
i
<
6
;
i
++
)
spi_message_add_tail
(
&
req
->
xfer
[
i
],
&
req
->
msg
);
status
=
spi_sync
(
spi
,
&
req
->
msg
);
sample
=
req
->
sample
;
kfree
(
req
);
return
status
?
:
sample
;
}
static
void
ad7877_rx
(
struct
ad7877
*
ts
)
{
struct
input_dev
*
input_dev
=
ts
->
input
;
unsigned
Rt
;
u16
x
,
y
,
z1
,
z2
;
x
=
ts
->
conversion_data
[
AD7877_SEQ_XPOS
]
&
MAX_12BIT
;
y
=
ts
->
conversion_data
[
AD7877_SEQ_YPOS
]
&
MAX_12BIT
;
z1
=
ts
->
conversion_data
[
AD7877_SEQ_Z1
]
&
MAX_12BIT
;
z2
=
ts
->
conversion_data
[
AD7877_SEQ_Z2
]
&
MAX_12BIT
;
/*
* The samples processed here are already preprocessed by the AD7877.
* The preprocessing function consists of an averaging filter.
* The combination of 'first conversion delay' and averaging provides a robust solution,
* discarding the spurious noise in the signal and keeping only the data of interest.
* The size of the averaging filter is programmable. (dev.platform_data, see linux/spi/ad7877.h)
* Other user-programmable conversion controls include variable acquisition time,
* and first conversion delay. Up to 16 averages can be taken per conversion.
*/
if
(
likely
(
x
&&
z1
))
{
/* compute touch pressure resistance using equation #1 */
Rt
=
(
z2
-
z1
)
*
x
*
ts
->
x_plate_ohms
;
Rt
/=
z1
;
Rt
=
(
Rt
+
2047
)
>>
12
;
input_report_abs
(
input_dev
,
ABS_X
,
x
);
input_report_abs
(
input_dev
,
ABS_Y
,
y
);
input_report_abs
(
input_dev
,
ABS_PRESSURE
,
Rt
);
input_sync
(
input_dev
);
}
}
static
inline
void
ad7877_ts_event_release
(
struct
ad7877
*
ts
)
{
struct
input_dev
*
input_dev
=
ts
->
input
;
input_report_abs
(
input_dev
,
ABS_PRESSURE
,
0
);
input_sync
(
input_dev
);
}
static
void
ad7877_timer
(
unsigned
long
handle
)
{
struct
ad7877
*
ts
=
(
void
*
)
handle
;
ad7877_ts_event_release
(
ts
);
}
static
irqreturn_t
ad7877_irq
(
int
irq
,
void
*
handle
)
{
struct
ad7877
*
ts
=
handle
;
unsigned
long
flags
;
int
status
;
/*
* The repeated conversion sequencer controlled by TMR kicked off
* too fast. We ignore the last and process the sample sequence
* currently in the queue. It can't be older than 9.4ms, and we
* need to avoid that ts->msg doesn't get issued twice while in work.
*/
spin_lock_irqsave
(
&
ts
->
lock
,
flags
);
if
(
!
ts
->
pending
)
{
ts
->
pending
=
1
;
status
=
spi_async
(
ts
->
spi
,
&
ts
->
msg
);
if
(
status
)
dev_err
(
&
ts
->
spi
->
dev
,
"spi_sync --> %d
\n
"
,
status
);
}
spin_unlock_irqrestore
(
&
ts
->
lock
,
flags
);
return
IRQ_HANDLED
;
}
static
void
ad7877_callback
(
void
*
_ts
)
{
struct
ad7877
*
ts
=
_ts
;
spin_lock_irq
(
&
ts
->
lock
);
ad7877_rx
(
ts
);
ts
->
pending
=
0
;
mod_timer
(
&
ts
->
timer
,
jiffies
+
TS_PEN_UP_TIMEOUT
);
spin_unlock_irq
(
&
ts
->
lock
);
}
static
void
ad7877_disable
(
struct
ad7877
*
ts
)
{
mutex_lock
(
&
ts
->
mutex
);
if
(
!
ts
->
disabled
)
{
ts
->
disabled
=
1
;
disable_irq
(
ts
->
spi
->
irq
);
/* Wait for spi_async callback */
while
(
ts
->
pending
)
msleep
(
1
);
if
(
del_timer_sync
(
&
ts
->
timer
))
ad7877_ts_event_release
(
ts
);
}
/* we know the chip's in lowpower mode since we always
* leave it that way after every request
*/
mutex_unlock
(
&
ts
->
mutex
);
}
static
void
ad7877_enable
(
struct
ad7877
*
ts
)
{
mutex_lock
(
&
ts
->
mutex
);
if
(
ts
->
disabled
)
{
ts
->
disabled
=
0
;
enable_irq
(
ts
->
spi
->
irq
);
}
mutex_unlock
(
&
ts
->
mutex
);
}
#define SHOW(name) static ssize_t \
name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \
{ \
struct ad7877 *ts = dev_get_drvdata(dev); \
ssize_t v = ad7877_read_adc(ts->spi, \
AD7877_READ_CHAN(name)); \
if (v < 0) \
return v; \
return sprintf(buf, "%u\n", (unsigned) v); \
} \
static DEVICE_ATTR(name, S_IRUGO, name ## _show, NULL);
SHOW
(
aux1
)
SHOW
(
aux2
)
SHOW
(
aux3
)
SHOW
(
bat1
)
SHOW
(
bat2
)
SHOW
(
temp1
)
SHOW
(
temp2
)
static
ssize_t
ad7877_disable_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
ad7877
*
ts
=
dev_get_drvdata
(
dev
);
return
sprintf
(
buf
,
"%u
\n
"
,
ts
->
disabled
);
}
static
ssize_t
ad7877_disable_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
struct
ad7877
*
ts
=
dev_get_drvdata
(
dev
);
unsigned
long
val
;
int
error
;
error
=
strict_strtoul
(
buf
,
10
,
&
val
);
if
(
error
)
return
error
;
if
(
val
)
ad7877_disable
(
ts
);
else
ad7877_enable
(
ts
);
return
count
;
}
static
DEVICE_ATTR
(
disable
,
0664
,
ad7877_disable_show
,
ad7877_disable_store
);
static
ssize_t
ad7877_dac_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
ad7877
*
ts
=
dev_get_drvdata
(
dev
);
return
sprintf
(
buf
,
"%u
\n
"
,
ts
->
dac
);
}
static
ssize_t
ad7877_dac_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
struct
ad7877
*
ts
=
dev_get_drvdata
(
dev
);
unsigned
long
val
;
int
error
;
error
=
strict_strtoul
(
buf
,
10
,
&
val
);
if
(
error
)
return
error
;
mutex_lock
(
&
ts
->
mutex
);
ts
->
dac
=
val
&
0xFF
;
ad7877_write
(
ts
->
spi
,
AD7877_REG_DAC
,
(
ts
->
dac
<<
4
)
|
AD7877_DAC_CONF
);
mutex_unlock
(
&
ts
->
mutex
);
return
count
;
}
static
DEVICE_ATTR
(
dac
,
0664
,
ad7877_dac_show
,
ad7877_dac_store
);
static
ssize_t
ad7877_gpio3_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
ad7877
*
ts
=
dev_get_drvdata
(
dev
);
return
sprintf
(
buf
,
"%u
\n
"
,
ts
->
gpio3
);
}
static
ssize_t
ad7877_gpio3_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
struct
ad7877
*
ts
=
dev_get_drvdata
(
dev
);
unsigned
long
val
;
int
error
;
error
=
strict_strtoul
(
buf
,
10
,
&
val
);
if
(
error
)
return
error
;
mutex_lock
(
&
ts
->
mutex
);
ts
->
gpio3
=
!!
val
;
ad7877_write
(
ts
->
spi
,
AD7877_REG_EXTWRITE
,
AD7877_EXTW_GPIO_DATA
|
(
ts
->
gpio4
<<
4
)
|
(
ts
->
gpio3
<<
5
));
mutex_unlock
(
&
ts
->
mutex
);
return
count
;
}
static
DEVICE_ATTR
(
gpio3
,
0664
,
ad7877_gpio3_show
,
ad7877_gpio3_store
);
static
ssize_t
ad7877_gpio4_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
ad7877
*
ts
=
dev_get_drvdata
(
dev
);
return
sprintf
(
buf
,
"%u
\n
"
,
ts
->
gpio4
);
}
static
ssize_t
ad7877_gpio4_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
struct
ad7877
*
ts
=
dev_get_drvdata
(
dev
);
unsigned
long
val
;
int
error
;
error
=
strict_strtoul
(
buf
,
10
,
&
val
);
if
(
error
)
return
error
;
mutex_lock
(
&
ts
->
mutex
);
ts
->
gpio4
=
!!
val
;
ad7877_write
(
ts
->
spi
,
AD7877_REG_EXTWRITE
,
AD7877_EXTW_GPIO_DATA
|
(
ts
->
gpio4
<<
4
)
|
(
ts
->
gpio3
<<
5
));
mutex_unlock
(
&
ts
->
mutex
);
return
count
;
}
static
DEVICE_ATTR
(
gpio4
,
0664
,
ad7877_gpio4_show
,
ad7877_gpio4_store
);
static
struct
attribute
*
ad7877_attributes
[]
=
{
&
dev_attr_temp1
.
attr
,
&
dev_attr_temp2
.
attr
,
&
dev_attr_aux1
.
attr
,
&
dev_attr_aux2
.
attr
,
&
dev_attr_bat1
.
attr
,
&
dev_attr_bat2
.
attr
,
&
dev_attr_disable
.
attr
,
&
dev_attr_dac
.
attr
,
&
dev_attr_gpio4
.
attr
,
NULL
};
static
const
struct
attribute_group
ad7877_attr_group
=
{
.
attrs
=
ad7877_attributes
,
};
static
void
ad7877_setup_ts_def_msg
(
struct
spi_device
*
spi
,
struct
ad7877
*
ts
)
{
struct
spi_message
*
m
;
int
i
;
ts
->
cmd_crtl2
=
AD7877_WRITEADD
(
AD7877_REG_CTRL2
)
|
AD7877_POL
(
ts
->
stopacq_polarity
)
|
AD7877_AVG
(
ts
->
averaging
)
|
AD7877_PM
(
1
)
|
AD7877_TMR
(
ts
->
pen_down_acc_interval
)
|
AD7877_ACQ
(
ts
->
acquisition_time
)
|
AD7877_FCD
(
ts
->
first_conversion_delay
);
ad7877_write
(
spi
,
AD7877_REG_CTRL2
,
ts
->
cmd_crtl2
);
ts
->
cmd_crtl1
=
AD7877_WRITEADD
(
AD7877_REG_CTRL1
)
|
AD7877_READADD
(
AD7877_REG_XPLUS
-
1
)
|
AD7877_MODE_SEQ1
|
AD7877_DFR
;
ad7877_write
(
spi
,
AD7877_REG_CTRL1
,
ts
->
cmd_crtl1
);
ts
->
cmd_dummy
=
0
;
m
=
&
ts
->
msg
;
spi_message_init
(
m
);
m
->
complete
=
ad7877_callback
;
m
->
context
=
ts
;
ts
->
xfer
[
0
].
tx_buf
=
&
ts
->
cmd_crtl1
;
ts
->
xfer
[
0
].
len
=
2
;
spi_message_add_tail
(
&
ts
->
xfer
[
0
],
m
);
ts
->
xfer
[
1
].
tx_buf
=
&
ts
->
cmd_dummy
;
/* Send ZERO */
ts
->
xfer
[
1
].
len
=
2
;
spi_message_add_tail
(
&
ts
->
xfer
[
1
],
m
);
for
(
i
=
0
;
i
<
11
;
i
++
)
{
ts
->
xfer
[
i
+
2
].
rx_buf
=
&
ts
->
conversion_data
[
AD7877_SEQ_YPOS
+
i
];
ts
->
xfer
[
i
+
2
].
len
=
2
;
spi_message_add_tail
(
&
ts
->
xfer
[
i
+
2
],
m
);
}
}
static
int
__devinit
ad7877_probe
(
struct
spi_device
*
spi
)
{
struct
ad7877
*
ts
;
struct
input_dev
*
input_dev
;
struct
ad7877_platform_data
*
pdata
=
spi
->
dev
.
platform_data
;
int
err
;
u16
verify
;
if
(
!
spi
->
irq
)
{
dev_dbg
(
&
spi
->
dev
,
"no IRQ?
\n
"
);
return
-
ENODEV
;
}
if
(
!
pdata
)
{
dev_dbg
(
&
spi
->
dev
,
"no platform data?
\n
"
);
return
-
ENODEV
;
}
/* don't exceed max specified SPI CLK frequency */
if
(
spi
->
max_speed_hz
>
MAX_SPI_FREQ_HZ
)
{
dev_dbg
(
&
spi
->
dev
,
"SPI CLK %d Hz?
\n
"
,
spi
->
max_speed_hz
);
return
-
EINVAL
;
}
ts
=
kzalloc
(
sizeof
(
struct
ad7877
),
GFP_KERNEL
);
input_dev
=
input_allocate_device
();
if
(
!
ts
||
!
input_dev
)
{
err
=
-
ENOMEM
;
goto
err_free_mem
;
}
dev_set_drvdata
(
&
spi
->
dev
,
ts
);
ts
->
spi
=
spi
;
ts
->
input
=
input_dev
;
setup_timer
(
&
ts
->
timer
,
ad7877_timer
,
(
unsigned
long
)
ts
);
mutex_init
(
&
ts
->
mutex
);
spin_lock_init
(
&
ts
->
lock
);
ts
->
model
=
pdata
->
model
?
:
7877
;
ts
->
vref_delay_usecs
=
pdata
->
vref_delay_usecs
?
:
100
;
ts
->
x_plate_ohms
=
pdata
->
x_plate_ohms
?
:
400
;
ts
->
pressure_max
=
pdata
->
pressure_max
?
:
~
0
;
ts
->
stopacq_polarity
=
pdata
->
stopacq_polarity
;
ts
->
first_conversion_delay
=
pdata
->
first_conversion_delay
;
ts
->
acquisition_time
=
pdata
->
acquisition_time
;
ts
->
averaging
=
pdata
->
averaging
;
ts
->
pen_down_acc_interval
=
pdata
->
pen_down_acc_interval
;
snprintf
(
ts
->
phys
,
sizeof
(
ts
->
phys
),
"%s/input0"
,
dev_name
(
&
spi
->
dev
));
input_dev
->
name
=
"AD7877 Touchscreen"
;
input_dev
->
phys
=
ts
->
phys
;
input_dev
->
dev
.
parent
=
&
spi
->
dev
;
__set_bit
(
EV_ABS
,
input_dev
->
evbit
);
__set_bit
(
ABS_X
,
input_dev
->
absbit
);
__set_bit
(
ABS_Y
,
input_dev
->
absbit
);
__set_bit
(
ABS_PRESSURE
,
input_dev
->
absbit
);
input_set_abs_params
(
input_dev
,
ABS_X
,
pdata
->
x_min
?
:
0
,
pdata
->
x_max
?
:
MAX_12BIT
,
0
,
0
);
input_set_abs_params
(
input_dev
,
ABS_Y
,
pdata
->
y_min
?
:
0
,
pdata
->
y_max
?
:
MAX_12BIT
,
0
,
0
);
input_set_abs_params
(
input_dev
,
ABS_PRESSURE
,
pdata
->
pressure_min
,
pdata
->
pressure_max
,
0
,
0
);
ad7877_write
(
spi
,
AD7877_REG_SEQ1
,
AD7877_MM_SEQUENCE
);
verify
=
ad7877_read
(
spi
,
AD7877_REG_SEQ1
);
if
(
verify
!=
AD7877_MM_SEQUENCE
){
dev_err
(
&
spi
->
dev
,
"%s: Failed to probe %s
\n
"
,
dev_name
(
&
spi
->
dev
),
input_dev
->
name
);
err
=
-
ENODEV
;
goto
err_free_mem
;
}
if
(
gpio3
)
ad7877_write
(
spi
,
AD7877_REG_EXTWRITE
,
AD7877_EXTW_GPIO_3_CONF
);
ad7877_setup_ts_def_msg
(
spi
,
ts
);
/* Request AD7877 /DAV GPIO interrupt */
err
=
request_irq
(
spi
->
irq
,
ad7877_irq
,
IRQF_TRIGGER_FALLING
|
IRQF_SAMPLE_RANDOM
,
spi
->
dev
.
driver
->
name
,
ts
);
if
(
err
)
{
dev_dbg
(
&
spi
->
dev
,
"irq %d busy?
\n
"
,
spi
->
irq
);
goto
err_free_mem
;
}
err
=
sysfs_create_group
(
&
spi
->
dev
.
kobj
,
&
ad7877_attr_group
);
if
(
err
)
goto
err_free_irq
;
err
=
device_create_file
(
&
spi
->
dev
,
gpio3
?
&
dev_attr_gpio3
:
&
dev_attr_aux3
);
if
(
err
)
goto
err_remove_attr_group
;
err
=
input_register_device
(
input_dev
);
if
(
err
)
goto
err_remove_attr
;
return
0
;
err_remove_attr:
device_remove_file
(
&
spi
->
dev
,
gpio3
?
&
dev_attr_gpio3
:
&
dev_attr_aux3
);
err_remove_attr_group:
sysfs_remove_group
(
&
spi
->
dev
.
kobj
,
&
ad7877_attr_group
);
err_free_irq:
free_irq
(
spi
->
irq
,
ts
);
err_free_mem:
input_free_device
(
input_dev
);
kfree
(
ts
);
dev_set_drvdata
(
&
spi
->
dev
,
NULL
);
return
err
;
}
static
int
__devexit
ad7877_remove
(
struct
spi_device
*
spi
)
{
struct
ad7877
*
ts
=
dev_get_drvdata
(
&
spi
->
dev
);
sysfs_remove_group
(
&
spi
->
dev
.
kobj
,
&
ad7877_attr_group
);
device_remove_file
(
&
spi
->
dev
,
gpio3
?
&
dev_attr_gpio3
:
&
dev_attr_aux3
);
ad7877_disable
(
ts
);
free_irq
(
ts
->
spi
->
irq
,
ts
);
input_unregister_device
(
ts
->
input
);
kfree
(
ts
);
dev_dbg
(
&
spi
->
dev
,
"unregistered touchscreen
\n
"
);
dev_set_drvdata
(
&
spi
->
dev
,
NULL
);
return
0
;
}
#ifdef CONFIG_PM
static
int
ad7877_suspend
(
struct
spi_device
*
spi
,
pm_message_t
message
)
{
struct
ad7877
*
ts
=
dev_get_drvdata
(
&
spi
->
dev
);
ad7877_disable
(
ts
);
return
0
;
}
static
int
ad7877_resume
(
struct
spi_device
*
spi
)
{
struct
ad7877
*
ts
=
dev_get_drvdata
(
&
spi
->
dev
);
ad7877_enable
(
ts
);
return
0
;
}
#else
#define ad7877_suspend NULL
#define ad7877_resume NULL
#endif
static
struct
spi_driver
ad7877_driver
=
{
.
driver
=
{
.
name
=
"ad7877"
,
.
bus
=
&
spi_bus_type
,
.
owner
=
THIS_MODULE
,
},
.
probe
=
ad7877_probe
,
.
remove
=
__devexit_p
(
ad7877_remove
),
.
suspend
=
ad7877_suspend
,
.
resume
=
ad7877_resume
,
};
static
int
__init
ad7877_init
(
void
)
{
return
spi_register_driver
(
&
ad7877_driver
);
}
module_init
(
ad7877_init
);
static
void
__exit
ad7877_exit
(
void
)
{
spi_unregister_driver
(
&
ad7877_driver
);
}
module_exit
(
ad7877_exit
);
MODULE_AUTHOR
(
"Michael Hennerich <hennerich@blackfin.uclinux.org>"
);
MODULE_DESCRIPTION
(
"AD7877 touchscreen Driver"
);
MODULE_LICENSE
(
"GPL"
);
drivers/input/touchscreen/ad7879.c
0 → 100644
View file @
ba28f22e
/*
* Copyright (C) 2008 Michael Hennerich, Analog Devices Inc.
*
* Description: AD7879 based touchscreen, and GPIO driver (I2C/SPI Interface)
*
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see the file COPYING, or write
* to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* History:
* Copyright (c) 2005 David Brownell
* Copyright (c) 2006 Nokia Corporation
* Various changes: Imre Deak <imre.deak@nokia.com>
*
* Using code from:
* - corgi_ts.c
* Copyright (C) 2004-2005 Richard Purdie
* - omap_ts.[hc], ads7846.h, ts_osk.c
* Copyright (C) 2002 MontaVista Software
* Copyright (C) 2004 Texas Instruments
* Copyright (C) 2005 Dirk Behme
* - ad7877.c
* Copyright (C) 2006-2008 Analog Devices Inc.
*/
#include <linux/device.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/spi/spi.h>
#include <linux/i2c.h>
#include <linux/spi/ad7879.h>
#define AD7879_REG_ZEROS 0
#define AD7879_REG_CTRL1 1
#define AD7879_REG_CTRL2 2
#define AD7879_REG_CTRL3 3
#define AD7879_REG_AUX1HIGH 4
#define AD7879_REG_AUX1LOW 5
#define AD7879_REG_TEMP1HIGH 6
#define AD7879_REG_TEMP1LOW 7
#define AD7879_REG_XPLUS 8
#define AD7879_REG_YPLUS 9
#define AD7879_REG_Z1 10
#define AD7879_REG_Z2 11
#define AD7879_REG_AUXVBAT 12
#define AD7879_REG_TEMP 13
#define AD7879_REG_REVID 14
/* Control REG 1 */
#define AD7879_TMR(x) ((x & 0xFF) << 0)
#define AD7879_ACQ(x) ((x & 0x3) << 8)
#define AD7879_MODE_NOC (0 << 10)
/* Do not convert */
#define AD7879_MODE_SCC (1 << 10)
/* Single channel conversion */
#define AD7879_MODE_SEQ0 (2 << 10)
/* Sequence 0 in Slave Mode */
#define AD7879_MODE_SEQ1 (3 << 10)
/* Sequence 1 in Master Mode */
#define AD7879_MODE_INT (1 << 15)
/* PENIRQ disabled INT enabled */
/* Control REG 2 */
#define AD7879_FCD(x) ((x & 0x3) << 0)
#define AD7879_RESET (1 << 4)
#define AD7879_MFS(x) ((x & 0x3) << 5)
#define AD7879_AVG(x) ((x & 0x3) << 7)
#define AD7879_SER (1 << 9)
/* non-differential */
#define AD7879_DFR (0 << 9)
/* differential */
#define AD7879_GPIOPOL (1 << 10)
#define AD7879_GPIODIR (1 << 11)
#define AD7879_GPIO_DATA (1 << 12)
#define AD7879_GPIO_EN (1 << 13)
#define AD7879_PM(x) ((x & 0x3) << 14)
#define AD7879_PM_SHUTDOWN (0)
#define AD7879_PM_DYN (1)
#define AD7879_PM_FULLON (2)
/* Control REG 3 */
#define AD7879_TEMPMASK_BIT (1<<15)
#define AD7879_AUXVBATMASK_BIT (1<<14)
#define AD7879_INTMODE_BIT (1<<13)
#define AD7879_GPIOALERTMASK_BIT (1<<12)
#define AD7879_AUXLOW_BIT (1<<11)
#define AD7879_AUXHIGH_BIT (1<<10)
#define AD7879_TEMPLOW_BIT (1<<9)
#define AD7879_TEMPHIGH_BIT (1<<8)
#define AD7879_YPLUS_BIT (1<<7)
#define AD7879_XPLUS_BIT (1<<6)
#define AD7879_Z1_BIT (1<<5)
#define AD7879_Z2_BIT (1<<4)
#define AD7879_AUX_BIT (1<<3)
#define AD7879_VBAT_BIT (1<<2)
#define AD7879_TEMP_BIT (1<<1)
enum
{
AD7879_SEQ_XPOS
=
0
,
AD7879_SEQ_YPOS
=
1
,
AD7879_SEQ_Z1
=
2
,
AD7879_SEQ_Z2
=
3
,
AD7879_NR_SENSE
=
4
,
};
#define MAX_12BIT ((1<<12)-1)
#define TS_PEN_UP_TIMEOUT msecs_to_jiffies(50)
#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
#define AD7879_DEVID 0x7A
typedef
struct
spi_device
bus_device
;
#elif defined(CONFIG_TOUCHSCREEN_AD7879_I2C) || defined(CONFIG_TOUCHSCREEN_AD7879_I2C_MODULE)
#define AD7879_DEVID 0x79
typedef
struct
i2c_client
bus_device
;
#endif
struct
ad7879
{
bus_device
*
bus
;
struct
input_dev
*
input
;
struct
work_struct
work
;
struct
timer_list
timer
;
struct
mutex
mutex
;
unsigned
disabled
:
1
;
/* P: mutex */
#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
struct
spi_message
msg
;
struct
spi_transfer
xfer
[
AD7879_NR_SENSE
+
1
];
u16
cmd
;
#endif
u16
conversion_data
[
AD7879_NR_SENSE
];
char
phys
[
32
];
u8
first_conversion_delay
;
u8
acquisition_time
;
u8
averaging
;
u8
pen_down_acc_interval
;
u8
median
;
u16
x_plate_ohms
;
u16
pressure_max
;
u16
gpio_init
;
u16
cmd_crtl1
;
u16
cmd_crtl2
;
u16
cmd_crtl3
;
unsigned
gpio
:
1
;
};
static
int
ad7879_read
(
bus_device
*
,
u8
);
static
int
ad7879_write
(
bus_device
*
,
u8
,
u16
);
static
void
ad7879_collect
(
struct
ad7879
*
);
static
void
ad7879_report
(
struct
ad7879
*
ts
)
{
struct
input_dev
*
input_dev
=
ts
->
input
;
unsigned
Rt
;
u16
x
,
y
,
z1
,
z2
;
x
=
ts
->
conversion_data
[
AD7879_SEQ_XPOS
]
&
MAX_12BIT
;
y
=
ts
->
conversion_data
[
AD7879_SEQ_YPOS
]
&
MAX_12BIT
;
z1
=
ts
->
conversion_data
[
AD7879_SEQ_Z1
]
&
MAX_12BIT
;
z2
=
ts
->
conversion_data
[
AD7879_SEQ_Z2
]
&
MAX_12BIT
;
/*
* The samples processed here are already preprocessed by the AD7879.
* The preprocessing function consists of a median and an averaging filter.
* The combination of these two techniques provides a robust solution,
* discarding the spurious noise in the signal and keeping only the data of interest.
* The size of both filters is programmable. (dev.platform_data, see linux/spi/ad7879.h)
* Other user-programmable conversion controls include variable acquisition time,
* and first conversion delay. Up to 16 averages can be taken per conversion.
*/
if
(
likely
(
x
&&
z1
))
{
/* compute touch pressure resistance using equation #1 */
Rt
=
(
z2
-
z1
)
*
x
*
ts
->
x_plate_ohms
;
Rt
/=
z1
;
Rt
=
(
Rt
+
2047
)
>>
12
;
input_report_abs
(
input_dev
,
ABS_X
,
x
);
input_report_abs
(
input_dev
,
ABS_Y
,
y
);
input_report_abs
(
input_dev
,
ABS_PRESSURE
,
Rt
);
input_sync
(
input_dev
);
}
}
static
void
ad7879_work
(
struct
work_struct
*
work
)
{
struct
ad7879
*
ts
=
container_of
(
work
,
struct
ad7879
,
work
);
/* use keventd context to read the result registers */
ad7879_collect
(
ts
);
ad7879_report
(
ts
);
mod_timer
(
&
ts
->
timer
,
jiffies
+
TS_PEN_UP_TIMEOUT
);
}
static
void
ad7879_ts_event_release
(
struct
ad7879
*
ts
)
{
struct
input_dev
*
input_dev
=
ts
->
input
;
input_report_abs
(
input_dev
,
ABS_PRESSURE
,
0
);
input_sync
(
input_dev
);
}
static
void
ad7879_timer
(
unsigned
long
handle
)
{
struct
ad7879
*
ts
=
(
void
*
)
handle
;
ad7879_ts_event_release
(
ts
);
}
static
irqreturn_t
ad7879_irq
(
int
irq
,
void
*
handle
)
{
struct
ad7879
*
ts
=
handle
;
/* The repeated conversion sequencer controlled by TMR kicked off too fast.
* We ignore the last and process the sample sequence currently in the queue.
* It can't be older than 9.4ms
*/
if
(
!
work_pending
(
&
ts
->
work
))
schedule_work
(
&
ts
->
work
);
return
IRQ_HANDLED
;
}
static
void
ad7879_setup
(
struct
ad7879
*
ts
)
{
ts
->
cmd_crtl3
=
AD7879_YPLUS_BIT
|
AD7879_XPLUS_BIT
|
AD7879_Z2_BIT
|
AD7879_Z1_BIT
|
AD7879_TEMPMASK_BIT
|
AD7879_AUXVBATMASK_BIT
|
AD7879_GPIOALERTMASK_BIT
;
ts
->
cmd_crtl2
=
AD7879_PM
(
AD7879_PM_DYN
)
|
AD7879_DFR
|
AD7879_AVG
(
ts
->
averaging
)
|
AD7879_MFS
(
ts
->
median
)
|
AD7879_FCD
(
ts
->
first_conversion_delay
)
|
ts
->
gpio_init
;
ts
->
cmd_crtl1
=
AD7879_MODE_INT
|
AD7879_MODE_SEQ1
|
AD7879_ACQ
(
ts
->
acquisition_time
)
|
AD7879_TMR
(
ts
->
pen_down_acc_interval
);
ad7879_write
(
ts
->
bus
,
AD7879_REG_CTRL2
,
ts
->
cmd_crtl2
);
ad7879_write
(
ts
->
bus
,
AD7879_REG_CTRL3
,
ts
->
cmd_crtl3
);
ad7879_write
(
ts
->
bus
,
AD7879_REG_CTRL1
,
ts
->
cmd_crtl1
);
}
static
void
ad7879_disable
(
struct
ad7879
*
ts
)
{
mutex_lock
(
&
ts
->
mutex
);
if
(
!
ts
->
disabled
)
{
ts
->
disabled
=
1
;
disable_irq
(
ts
->
bus
->
irq
);
cancel_work_sync
(
&
ts
->
work
);
if
(
del_timer_sync
(
&
ts
->
timer
))
ad7879_ts_event_release
(
ts
);
ad7879_write
(
ts
->
bus
,
AD7879_REG_CTRL2
,
AD7879_PM
(
AD7879_PM_SHUTDOWN
));
}
mutex_unlock
(
&
ts
->
mutex
);
}
static
void
ad7879_enable
(
struct
ad7879
*
ts
)
{
mutex_lock
(
&
ts
->
mutex
);
if
(
ts
->
disabled
)
{
ad7879_setup
(
ts
);
ts
->
disabled
=
0
;
enable_irq
(
ts
->
bus
->
irq
);
}
mutex_unlock
(
&
ts
->
mutex
);
}
static
ssize_t
ad7879_disable_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
ad7879
*
ts
=
dev_get_drvdata
(
dev
);
return
sprintf
(
buf
,
"%u
\n
"
,
ts
->
disabled
);
}
static
ssize_t
ad7879_disable_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
struct
ad7879
*
ts
=
dev_get_drvdata
(
dev
);
unsigned
long
val
;
int
error
;
error
=
strict_strtoul
(
buf
,
10
,
&
val
);
if
(
error
)
return
error
;
if
(
val
)
ad7879_disable
(
ts
);
else
ad7879_enable
(
ts
);
return
count
;
}
static
DEVICE_ATTR
(
disable
,
0664
,
ad7879_disable_show
,
ad7879_disable_store
);
static
ssize_t
ad7879_gpio_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
ad7879
*
ts
=
dev_get_drvdata
(
dev
);
return
sprintf
(
buf
,
"%u
\n
"
,
ts
->
gpio
);
}
static
ssize_t
ad7879_gpio_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
struct
ad7879
*
ts
=
dev_get_drvdata
(
dev
);
unsigned
long
val
;
int
error
;
error
=
strict_strtoul
(
buf
,
10
,
&
val
);
if
(
error
)
return
error
;
mutex_lock
(
&
ts
->
mutex
);
ts
->
gpio
=
!!
val
;
error
=
ad7879_write
(
ts
->
bus
,
AD7879_REG_CTRL2
,
ts
->
gpio
?
ts
->
cmd_crtl2
&
~
AD7879_GPIO_DATA
:
ts
->
cmd_crtl2
|
AD7879_GPIO_DATA
);
mutex_unlock
(
&
ts
->
mutex
);
return
error
?
:
count
;
}
static
DEVICE_ATTR
(
gpio
,
0664
,
ad7879_gpio_show
,
ad7879_gpio_store
);
static
struct
attribute
*
ad7879_attributes
[]
=
{
&
dev_attr_disable
.
attr
,
&
dev_attr_gpio
.
attr
,
NULL
};
static
const
struct
attribute_group
ad7879_attr_group
=
{
.
attrs
=
ad7879_attributes
,
};
static
int
__devinit
ad7879_construct
(
bus_device
*
bus
,
struct
ad7879
*
ts
)
{
struct
input_dev
*
input_dev
;
struct
ad7879_platform_data
*
pdata
=
bus
->
dev
.
platform_data
;
int
err
;
u16
revid
;
if
(
!
bus
->
irq
)
{
dev_err
(
&
bus
->
dev
,
"no IRQ?
\n
"
);
return
-
ENODEV
;
}
if
(
!
pdata
)
{
dev_err
(
&
bus
->
dev
,
"no platform data?
\n
"
);
return
-
ENODEV
;
}
input_dev
=
input_allocate_device
();
if
(
!
input_dev
)
return
-
ENOMEM
;
ts
->
input
=
input_dev
;
setup_timer
(
&
ts
->
timer
,
ad7879_timer
,
(
unsigned
long
)
ts
);
INIT_WORK
(
&
ts
->
work
,
ad7879_work
);
mutex_init
(
&
ts
->
mutex
);
ts
->
x_plate_ohms
=
pdata
->
x_plate_ohms
?
:
400
;
ts
->
pressure_max
=
pdata
->
pressure_max
?
:
~
0
;
ts
->
first_conversion_delay
=
pdata
->
first_conversion_delay
;
ts
->
acquisition_time
=
pdata
->
acquisition_time
;
ts
->
averaging
=
pdata
->
averaging
;
ts
->
pen_down_acc_interval
=
pdata
->
pen_down_acc_interval
;
ts
->
median
=
pdata
->
median
;
if
(
pdata
->
gpio_output
)
ts
->
gpio_init
=
AD7879_GPIO_EN
|
(
pdata
->
gpio_default
?
0
:
AD7879_GPIO_DATA
);
else
ts
->
gpio_init
=
AD7879_GPIO_EN
|
AD7879_GPIODIR
;
snprintf
(
ts
->
phys
,
sizeof
(
ts
->
phys
),
"%s/input0"
,
dev_name
(
&
bus
->
dev
));
input_dev
->
name
=
"AD7879 Touchscreen"
;
input_dev
->
phys
=
ts
->
phys
;
input_dev
->
dev
.
parent
=
&
bus
->
dev
;
__set_bit
(
EV_ABS
,
input_dev
->
evbit
);
__set_bit
(
ABS_X
,
input_dev
->
absbit
);
__set_bit
(
ABS_Y
,
input_dev
->
absbit
);
__set_bit
(
ABS_PRESSURE
,
input_dev
->
absbit
);
input_set_abs_params
(
input_dev
,
ABS_X
,
pdata
->
x_min
?
:
0
,
pdata
->
x_max
?
:
MAX_12BIT
,
0
,
0
);
input_set_abs_params
(
input_dev
,
ABS_Y
,
pdata
->
y_min
?
:
0
,
pdata
->
y_max
?
:
MAX_12BIT
,
0
,
0
);
input_set_abs_params
(
input_dev
,
ABS_PRESSURE
,
pdata
->
pressure_min
,
pdata
->
pressure_max
,
0
,
0
);
err
=
ad7879_write
(
bus
,
AD7879_REG_CTRL2
,
AD7879_RESET
);
if
(
err
<
0
)
{
dev_err
(
&
bus
->
dev
,
"Failed to write %s
\n
"
,
input_dev
->
name
);
goto
err_free_mem
;
}
revid
=
ad7879_read
(
bus
,
AD7879_REG_REVID
);
if
((
revid
&
0xFF
)
!=
AD7879_DEVID
)
{
dev_err
(
&
bus
->
dev
,
"Failed to probe %s
\n
"
,
input_dev
->
name
);
err
=
-
ENODEV
;
goto
err_free_mem
;
}
ad7879_setup
(
ts
);
err
=
request_irq
(
bus
->
irq
,
ad7879_irq
,
IRQF_TRIGGER_FALLING
|
IRQF_SAMPLE_RANDOM
,
bus
->
dev
.
driver
->
name
,
ts
);
if
(
err
)
{
dev_err
(
&
bus
->
dev
,
"irq %d busy?
\n
"
,
bus
->
irq
);
goto
err_free_mem
;
}
err
=
sysfs_create_group
(
&
bus
->
dev
.
kobj
,
&
ad7879_attr_group
);
if
(
err
)
goto
err_free_irq
;
err
=
input_register_device
(
input_dev
);
if
(
err
)
goto
err_remove_attr
;
dev_info
(
&
bus
->
dev
,
"Rev.%d touchscreen, irq %d
\n
"
,
revid
>>
8
,
bus
->
irq
);
return
0
;
err_remove_attr:
sysfs_remove_group
(
&
bus
->
dev
.
kobj
,
&
ad7879_attr_group
);
err_free_irq:
free_irq
(
bus
->
irq
,
ts
);
err_free_mem:
input_free_device
(
input_dev
);
return
err
;
}
static
int
__devexit
ad7879_destroy
(
bus_device
*
bus
,
struct
ad7879
*
ts
)
{
ad7879_disable
(
ts
);
sysfs_remove_group
(
&
ts
->
bus
->
dev
.
kobj
,
&
ad7879_attr_group
);
free_irq
(
ts
->
bus
->
irq
,
ts
);
input_unregister_device
(
ts
->
input
);
dev_dbg
(
&
bus
->
dev
,
"unregistered touchscreen
\n
"
);
return
0
;
}
#ifdef CONFIG_PM
static
int
ad7879_suspend
(
bus_device
*
bus
,
pm_message_t
message
)
{
struct
ad7879
*
ts
=
dev_get_drvdata
(
&
bus
->
dev
);
ad7879_disable
(
ts
);
return
0
;
}
static
int
ad7879_resume
(
bus_device
*
bus
)
{
struct
ad7879
*
ts
=
dev_get_drvdata
(
&
bus
->
dev
);
ad7879_enable
(
ts
);
return
0
;
}
#else
#define ad7879_suspend NULL
#define ad7879_resume NULL
#endif
#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
#define MAX_SPI_FREQ_HZ 5000000
#define AD7879_CMD_MAGIC 0xE000
#define AD7879_CMD_READ (1 << 10)
#define AD7879_WRITECMD(reg) (AD7879_CMD_MAGIC | (reg & 0xF))
#define AD7879_READCMD(reg) (AD7879_CMD_MAGIC | AD7879_CMD_READ | (reg & 0xF))
struct
ser_req
{
u16
command
;
u16
data
;
struct
spi_message
msg
;
struct
spi_transfer
xfer
[
2
];
};
/*
* ad7879_read/write are only used for initial setup and for sysfs controls.
* The main traffic is done in ad7879_collect().
*/
static
int
ad7879_read
(
struct
spi_device
*
spi
,
u8
reg
)
{
struct
ser_req
*
req
;
int
status
,
ret
;
req
=
kzalloc
(
sizeof
*
req
,
GFP_KERNEL
);
if
(
!
req
)
return
-
ENOMEM
;
spi_message_init
(
&
req
->
msg
);
req
->
command
=
(
u16
)
AD7879_READCMD
(
reg
);
req
->
xfer
[
0
].
tx_buf
=
&
req
->
command
;
req
->
xfer
[
0
].
len
=
2
;
req
->
xfer
[
1
].
rx_buf
=
&
req
->
data
;
req
->
xfer
[
1
].
len
=
2
;
spi_message_add_tail
(
&
req
->
xfer
[
0
],
&
req
->
msg
);
spi_message_add_tail
(
&
req
->
xfer
[
1
],
&
req
->
msg
);
status
=
spi_sync
(
spi
,
&
req
->
msg
);
ret
=
status
?
:
req
->
data
;
kfree
(
req
);
return
ret
;
}
static
int
ad7879_write
(
struct
spi_device
*
spi
,
u8
reg
,
u16
val
)
{
struct
ser_req
*
req
;
int
status
;
req
=
kzalloc
(
sizeof
*
req
,
GFP_KERNEL
);
if
(
!
req
)
return
-
ENOMEM
;
spi_message_init
(
&
req
->
msg
);
req
->
command
=
(
u16
)
AD7879_WRITECMD
(
reg
);
req
->
xfer
[
0
].
tx_buf
=
&
req
->
command
;
req
->
xfer
[
0
].
len
=
2
;
req
->
data
=
val
;
req
->
xfer
[
1
].
tx_buf
=
&
req
->
data
;
req
->
xfer
[
1
].
len
=
2
;
spi_message_add_tail
(
&
req
->
xfer
[
0
],
&
req
->
msg
);
spi_message_add_tail
(
&
req
->
xfer
[
1
],
&
req
->
msg
);
status
=
spi_sync
(
spi
,
&
req
->
msg
);
kfree
(
req
);
return
status
;
}
static
void
ad7879_collect
(
struct
ad7879
*
ts
)
{
int
status
=
spi_sync
(
ts
->
bus
,
&
ts
->
msg
);
if
(
status
)
dev_err
(
&
ts
->
bus
->
dev
,
"spi_sync --> %d
\n
"
,
status
);
}
static
void
ad7879_setup_ts_def_msg
(
struct
ad7879
*
ts
)
{
struct
spi_message
*
m
;
int
i
;
ts
->
cmd
=
(
u16
)
AD7879_READCMD
(
AD7879_REG_XPLUS
);
m
=
&
ts
->
msg
;
spi_message_init
(
m
);
ts
->
xfer
[
0
].
tx_buf
=
&
ts
->
cmd
;
ts
->
xfer
[
0
].
len
=
2
;
spi_message_add_tail
(
&
ts
->
xfer
[
0
],
m
);
for
(
i
=
0
;
i
<
AD7879_NR_SENSE
;
i
++
)
{
ts
->
xfer
[
i
+
1
].
rx_buf
=
&
ts
->
conversion_data
[
i
];
ts
->
xfer
[
i
+
1
].
len
=
2
;
spi_message_add_tail
(
&
ts
->
xfer
[
i
+
1
],
m
);
}
}
static
int
__devinit
ad7879_probe
(
struct
spi_device
*
spi
)
{
struct
ad7879
*
ts
;
int
error
;
/* don't exceed max specified SPI CLK frequency */
if
(
spi
->
max_speed_hz
>
MAX_SPI_FREQ_HZ
)
{
dev_err
(
&
spi
->
dev
,
"SPI CLK %d Hz?
\n
"
,
spi
->
max_speed_hz
);
return
-
EINVAL
;
}
ts
=
kzalloc
(
sizeof
(
struct
ad7879
),
GFP_KERNEL
);
if
(
!
ts
)
return
-
ENOMEM
;
dev_set_drvdata
(
&
spi
->
dev
,
ts
);
ts
->
bus
=
spi
;
ad7879_setup_ts_def_msg
(
ts
);
error
=
ad7879_construct
(
spi
,
ts
);
if
(
error
)
{
dev_set_drvdata
(
&
spi
->
dev
,
NULL
);
kfree
(
ts
);
}
return
0
;
}
static
int
__devexit
ad7879_remove
(
struct
spi_device
*
spi
)
{
struct
ad7879
*
ts
=
dev_get_drvdata
(
&
spi
->
dev
);
ad7879_destroy
(
spi
,
ts
);
dev_set_drvdata
(
&
spi
->
dev
,
NULL
);
kfree
(
ts
);
return
0
;
}
static
struct
spi_driver
ad7879_driver
=
{
.
driver
=
{
.
name
=
"ad7879"
,
.
bus
=
&
spi_bus_type
,
.
owner
=
THIS_MODULE
,
},
.
probe
=
ad7879_probe
,
.
remove
=
__devexit_p
(
ad7879_remove
),
.
suspend
=
ad7879_suspend
,
.
resume
=
ad7879_resume
,
};
static
int
__init
ad7879_init
(
void
)
{
return
spi_register_driver
(
&
ad7879_driver
);
}
module_init
(
ad7879_init
);
static
void
__exit
ad7879_exit
(
void
)
{
spi_unregister_driver
(
&
ad7879_driver
);
}
module_exit
(
ad7879_exit
);
#elif defined(CONFIG_TOUCHSCREEN_AD7879_I2C) || defined(CONFIG_TOUCHSCREEN_AD7879_I2C_MODULE)
/* All registers are word-sized.
* AD7879 uses a high-byte first convention.
*/
static
int
ad7879_read
(
struct
i2c_client
*
client
,
u8
reg
)
{
return
swab16
(
i2c_smbus_read_word_data
(
client
,
reg
));
}
static
int
ad7879_write
(
struct
i2c_client
*
client
,
u8
reg
,
u16
val
)
{
return
i2c_smbus_write_word_data
(
client
,
reg
,
swab16
(
val
));
}
static
void
ad7879_collect
(
struct
ad7879
*
ts
)
{
int
i
;
for
(
i
=
0
;
i
<
AD7879_NR_SENSE
;
i
++
)
ts
->
conversion_data
[
i
]
=
ad7879_read
(
ts
->
bus
,
AD7879_REG_XPLUS
+
i
);
}
static
int
__devinit
ad7879_probe
(
struct
i2c_client
*
client
,
const
struct
i2c_device_id
*
id
)
{
struct
ad7879
*
ts
;
int
error
;
if
(
!
i2c_check_functionality
(
client
->
adapter
,
I2C_FUNC_SMBUS_WORD_DATA
))
{
dev_err
(
&
client
->
dev
,
"SMBUS Word Data not Supported
\n
"
);
return
-
EIO
;
}
ts
=
kzalloc
(
sizeof
(
struct
ad7879
),
GFP_KERNEL
);
if
(
!
ts
)
return
-
ENOMEM
;
i2c_set_clientdata
(
client
,
ts
);
ts
->
bus
=
client
;
error
=
ad7879_construct
(
client
,
ts
);
if
(
error
)
{
i2c_set_clientdata
(
client
,
NULL
);
kfree
(
ts
);
}
return
0
;
}
static
int
__devexit
ad7879_remove
(
struct
i2c_client
*
client
)
{
struct
ad7879
*
ts
=
dev_get_drvdata
(
&
client
->
dev
);
ad7879_destroy
(
client
,
ts
);
i2c_set_clientdata
(
client
,
NULL
);
kfree
(
ts
);
return
0
;
}
static
const
struct
i2c_device_id
ad7879_id
[]
=
{
{
"ad7879"
,
0
},
{
}
};
MODULE_DEVICE_TABLE
(
i2c
,
ad7879_id
);
static
struct
i2c_driver
ad7879_driver
=
{
.
driver
=
{
.
name
=
"ad7879"
,
.
owner
=
THIS_MODULE
,
},
.
probe
=
ad7879_probe
,
.
remove
=
__devexit_p
(
ad7879_remove
),
.
suspend
=
ad7879_suspend
,
.
resume
=
ad7879_resume
,
.
id_table
=
ad7879_id
,
};
static
int
__init
ad7879_init
(
void
)
{
return
i2c_add_driver
(
&
ad7879_driver
);
}
module_init
(
ad7879_init
);
static
void
__exit
ad7879_exit
(
void
)
{
i2c_del_driver
(
&
ad7879_driver
);
}
module_exit
(
ad7879_exit
);
#endif
MODULE_AUTHOR
(
"Michael Hennerich <hennerich@blackfin.uclinux.org>"
);
MODULE_DESCRIPTION
(
"AD7879(-1) touchscreen Driver"
);
MODULE_LICENSE
(
"GPL"
);
drivers/input/touchscreen/mainstone-wm97xx.c
View file @
ba28f22e
...
...
@@ -162,6 +162,7 @@ static int wm97xx_acc_pen_down(struct wm97xx *wm)
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_report_key
(
wm
->
input_dev
,
BTN_TOUCH
,
(
p
!=
0
));
input_sync
(
wm
->
input_dev
);
reads
++
;
}
while
(
reads
<
cinfo
[
sp_idx
].
reads
);
...
...
@@ -245,7 +246,7 @@ static void wm97xx_irq_enable(struct wm97xx *wm, int enable)
if
(
enable
)
enable_irq
(
wm
->
pen_irq
);
else
disable_irq
(
wm
->
pen_irq
);
disable_irq
_nosync
(
wm
->
pen_irq
);
}
static
struct
wm97xx_mach_ops
mainstone_mach_ops
=
{
...
...
drivers/input/touchscreen/ucb1400_ts.c
View file @
ba28f22e
...
...
@@ -151,12 +151,14 @@ static void ucb1400_ts_evt_add(struct input_dev *idev, u16 pressure, u16 x, u16
input_report_abs
(
idev
,
ABS_X
,
x
);
input_report_abs
(
idev
,
ABS_Y
,
y
);
input_report_abs
(
idev
,
ABS_PRESSURE
,
pressure
);
input_report_key
(
idev
,
BTN_TOUCH
,
1
);
input_sync
(
idev
);
}
static
void
ucb1400_ts_event_release
(
struct
input_dev
*
idev
)
{
input_report_abs
(
idev
,
ABS_PRESSURE
,
0
);
input_report_key
(
idev
,
BTN_TOUCH
,
0
);
input_sync
(
idev
);
}
...
...
@@ -377,7 +379,8 @@ static int ucb1400_ts_probe(struct platform_device *dev)
ucb
->
ts_idev
->
id
.
product
=
ucb
->
id
;
ucb
->
ts_idev
->
open
=
ucb1400_ts_open
;
ucb
->
ts_idev
->
close
=
ucb1400_ts_close
;
ucb
->
ts_idev
->
evbit
[
0
]
=
BIT_MASK
(
EV_ABS
);
ucb
->
ts_idev
->
evbit
[
0
]
=
BIT_MASK
(
EV_ABS
)
|
BIT_MASK
(
EV_KEY
);
ucb
->
ts_idev
->
keybit
[
BIT_WORD
(
BTN_TOUCH
)]
=
BIT_MASK
(
BTN_TOUCH
);
ucb1400_adc_enable
(
ucb
->
ac97
);
x_res
=
ucb1400_ts_read_xres
(
ucb
);
...
...
drivers/input/touchscreen/wm97xx-core.c
View file @
ba28f22e
...
...
@@ -409,6 +409,7 @@ static int wm97xx_read_samples(struct wm97xx *wm)
wm
->
pen_is_down
=
0
;
dev_dbg
(
wm
->
dev
,
"pen up
\n
"
);
input_report_abs
(
wm
->
input_dev
,
ABS_PRESSURE
,
0
);
input_report_key
(
wm
->
input_dev
,
BTN_TOUCH
,
0
);
input_sync
(
wm
->
input_dev
);
}
else
if
(
!
(
rc
&
RC_AGAIN
))
{
/* We need high frequency updates only while
...
...
@@ -433,6 +434,7 @@ static int wm97xx_read_samples(struct wm97xx *wm)
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_report_key
(
wm
->
input_dev
,
BTN_TOUCH
,
1
);
input_sync
(
wm
->
input_dev
);
wm
->
pen_is_down
=
1
;
wm
->
ts_reader_interval
=
wm
->
ts_reader_min_interval
;
...
...
@@ -628,18 +630,21 @@ static int wm97xx_probe(struct device *dev)
wm
->
input_dev
->
phys
=
"wm97xx"
;
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
);
__set_bit
(
EV_ABS
,
wm
->
input_dev
->
evbit
);
__set_bit
(
EV_KEY
,
wm
->
input_dev
->
evbit
);
__set_bit
(
BTN_TOUCH
,
wm
->
input_dev
->
keybit
);
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
;
...
...
drivers/input/touchscreen/zylonite-wm97xx.c
0 → 100644
View file @
ba28f22e
/*
* zylonite-wm97xx.c -- Zylonite Continuous Touch screen driver
*
* Copyright 2004, 2007, 2008 Wolfson Microelectronics PLC.
* Author: Mark Brown <broonie@opensource.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 supporting interrupt driven
* and continuous operation on Marvell Zylonite development systems
* (which have a WM9713 on board).
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/wm97xx.h>
#include <mach/hardware.h>
#include <mach/mfp.h>
#include <mach/regs-ac97.h>
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
[]
=
{
{
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
;
/*
* 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)"
);
/*
* 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 machines */
static
void
wm97xx_acc_pen_up
(
struct
wm97xx
*
wm
)
{
int
i
;
msleep
(
1
);
for
(
i
=
0
;
i
<
16
;
i
++
)
MODR
;
}
static
int
wm97xx_acc_pen_down
(
struct
wm97xx
*
wm
)
{
u16
x
,
y
,
p
=
0x100
|
WM97XX_ADCSEL_PRES
;
int
reads
=
0
;
static
u16
last
,
tries
;
/* 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.
*/
msleep
(
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_report_key
(
wm
->
input_dev
,
BTN_TOUCH
,
(
p
!=
0
));
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
;
/* 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
,
"zylonite accelerated touchscreen driver, %d samples/sec
\n
"
,
cinfo
[
sp_idx
].
speed
);
return
0
;
}
static
void
wm97xx_irq_enable
(
struct
wm97xx
*
wm
,
int
enable
)
{
if
(
enable
)
enable_irq
(
wm
->
pen_irq
);
else
disable_irq_nosync
(
wm
->
pen_irq
);
}
static
struct
wm97xx_mach_ops
zylonite_mach_ops
=
{
.
acc_enabled
=
1
,
.
acc_pen_up
=
wm97xx_acc_pen_up
,
.
acc_pen_down
=
wm97xx_acc_pen_down
,
.
acc_startup
=
wm97xx_acc_startup
,
.
irq_enable
=
wm97xx_irq_enable
,
.
irq_gpio
=
WM97XX_GPIO_2
,
};
static
int
zylonite_wm97xx_probe
(
struct
platform_device
*
pdev
)
{
struct
wm97xx
*
wm
=
platform_get_drvdata
(
pdev
);
int
gpio_touch_irq
;
if
(
cpu_is_pxa320
())
gpio_touch_irq
=
mfp_to_gpio
(
MFP_PIN_GPIO15
);
else
gpio_touch_irq
=
mfp_to_gpio
(
MFP_PIN_GPIO26
);
wm
->
pen_irq
=
IRQ_GPIO
(
gpio_touch_irq
);
set_irq_type
(
IRQ_GPIO
(
gpio_touch_irq
),
IRQ_TYPE_EDGE_BOTH
);
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
);
return
wm97xx_register_mach_ops
(
wm
,
&
zylonite_mach_ops
);
}
static
int
zylonite_wm97xx_remove
(
struct
platform_device
*
pdev
)
{
struct
wm97xx
*
wm
=
platform_get_drvdata
(
pdev
);
wm97xx_unregister_mach_ops
(
wm
);
return
0
;
}
static
struct
platform_driver
zylonite_wm97xx_driver
=
{
.
probe
=
zylonite_wm97xx_probe
,
.
remove
=
zylonite_wm97xx_remove
,
.
driver
=
{
.
name
=
"wm97xx-touch"
,
},
};
static
int
__init
zylonite_wm97xx_init
(
void
)
{
return
platform_driver_register
(
&
zylonite_wm97xx_driver
);
}
static
void
__exit
zylonite_wm97xx_exit
(
void
)
{
platform_driver_unregister
(
&
zylonite_wm97xx_driver
);
}
module_init
(
zylonite_wm97xx_init
);
module_exit
(
zylonite_wm97xx_exit
);
/* Module information */
MODULE_AUTHOR
(
"Mark Brown <broonie@opensource.wolfsonmicro.com>"
);
MODULE_DESCRIPTION
(
"wm97xx continuous touch driver for Zylonite"
);
MODULE_LICENSE
(
"GPL"
);
include/linux/rotary_encoder.h
0 → 100644
View file @
ba28f22e
#ifndef __ROTARY_ENCODER_H__
#define __ROTARY_ENCODER_H__
struct
rotary_encoder_platform_data
{
unsigned
int
steps
;
unsigned
int
axis
;
unsigned
int
gpio_a
;
unsigned
int
gpio_b
;
unsigned
int
inverted_a
;
unsigned
int
inverted_b
;
};
#endif
/* __ROTARY_ENCODER_H__ */
include/linux/spi/ad7879.h
0 → 100644
View file @
ba28f22e
/* linux/spi/ad7879.h */
/* Touchscreen characteristics vary between boards and models. The
* platform_data for the device's "struct device" holds this information.
*
* It's OK if the min/max values are zero.
*/
struct
ad7879_platform_data
{
u16
model
;
/* 7879 */
u16
x_plate_ohms
;
u16
x_min
,
x_max
;
u16
y_min
,
y_max
;
u16
pressure_min
,
pressure_max
;
/* [0..255] 0=OFF Starts at 1=550us and goes
* all the way to 9.440ms in steps of 35us.
*/
u8
pen_down_acc_interval
;
/* [0..15] Starts at 0=128us and goes all the
* way to 4.096ms in steps of 128us.
*/
u8
first_conversion_delay
;
/* [0..3] 0 = 2us, 1 = 4us, 2 = 8us, 3 = 16us */
u8
acquisition_time
;
/* [0..3] Average X middle samples 0 = 2, 1 = 4, 2 = 8, 3 = 16 */
u8
averaging
;
/* [0..3] Perform X measurements 0 = OFF,
* 1 = 4, 2 = 8, 3 = 16 (median > averaging)
*/
u8
median
;
/* 1 = AUX/VBAT/GPIO set to GPIO Output */
u8
gpio_output
;
/* Initial GPIO pin state (valid if gpio_output = 1) */
u8
gpio_default
;
};
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