Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
03366e7b
Commit
03366e7b
authored
Feb 06, 2008
by
Dmitry Torokhov
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'pxa-keypad'
parents
c18bab80
e0f2677f
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
633 additions
and
292 deletions
+633
-292
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Kconfig
+4
-4
drivers/input/keyboard/Makefile
drivers/input/keyboard/Makefile
+1
-1
drivers/input/keyboard/pxa27x_keyboard.c
drivers/input/keyboard/pxa27x_keyboard.c
+0
-274
drivers/input/keyboard/pxa27x_keypad.c
drivers/input/keyboard/pxa27x_keypad.c
+572
-0
include/asm-arm/arch-pxa/pxa27x_keyboard.h
include/asm-arm/arch-pxa/pxa27x_keyboard.h
+0
-13
include/asm-arm/arch-pxa/pxa27x_keypad.h
include/asm-arm/arch-pxa/pxa27x_keypad.h
+56
-0
No files found.
drivers/input/keyboard/Kconfig
View file @
03366e7b
...
...
@@ -260,13 +260,13 @@ config KEYBOARD_OMAP
module will be called omap-keypad.
config KEYBOARD_PXA27x
tristate "PXA27x
keyboar
d support"
depends on PXA27x
tristate "PXA27x
/PXA3xx keypa
d support"
depends on PXA27x
|| PXA3xx
help
Enable support for PXA27x
matrix keyboar
d controller
Enable support for PXA27x
/PXA3xx keypa
d controller
To compile this driver as a module, choose M here: the
module will be called pxa27x_key
boar
d.
module will be called pxa27x_key
pa
d.
config KEYBOARD_AAED2000
tristate "AAED-2000 keyboard"
...
...
drivers/input/keyboard/Makefile
View file @
03366e7b
...
...
@@ -19,7 +19,7 @@ obj-$(CONFIG_KEYBOARD_TOSA) += tosakbd.o
obj-$(CONFIG_KEYBOARD_HIL)
+=
hil_kbd.o
obj-$(CONFIG_KEYBOARD_HIL_OLD)
+=
hilkbd.o
obj-$(CONFIG_KEYBOARD_OMAP)
+=
omap-keypad.o
obj-$(CONFIG_KEYBOARD_PXA27x)
+=
pxa27x_key
boar
d.o
obj-$(CONFIG_KEYBOARD_PXA27x)
+=
pxa27x_key
pa
d.o
obj-$(CONFIG_KEYBOARD_AAED2000)
+=
aaed2000_kbd.o
obj-$(CONFIG_KEYBOARD_GPIO)
+=
gpio_keys.o
obj-$(CONFIG_KEYBOARD_HP6XX)
+=
jornada680_kbd.o
...
...
drivers/input/keyboard/pxa27x_keyboard.c
deleted
100644 → 0
View file @
c18bab80
/*
* linux/drivers/input/keyboard/pxa27x_keyboard.c
*
* Driver for the pxa27x matrix keyboard controller.
*
* Created: Feb 22, 2007
* Author: Rodolfo Giometti <giometti@linux.it>
*
* Based on a previous implementations by Kevin O'Connor
* <kevin_at_koconnor.net> and Alex Osborne <bobofdoom@gmail.com> and
* on some suggestions by Nicolas Pitre <nico@cam.org>.
*
* 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/clk.h>
#include <linux/err.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/arch/hardware.h>
#include <asm/arch/pxa-regs.h>
#include <asm/arch/irqs.h>
#include <asm/arch/pxa27x_keyboard.h>
#define DRIVER_NAME "pxa27x-keyboard"
#define KPASMKP(col) (col/2 == 0 ? KPASMKP0 : \
col/2 == 1 ? KPASMKP1 : \
col/2 == 2 ? KPASMKP2 : KPASMKP3)
#define KPASMKPx_MKC(row, col) (1 << (row + 16 * (col % 2)))
static
struct
clk
*
pxakbd_clk
;
static
irqreturn_t
pxakbd_irq_handler
(
int
irq
,
void
*
dev_id
)
{
struct
platform_device
*
pdev
=
dev_id
;
struct
pxa27x_keyboard_platform_data
*
pdata
=
pdev
->
dev
.
platform_data
;
struct
input_dev
*
input_dev
=
platform_get_drvdata
(
pdev
);
unsigned
long
kpc
=
KPC
;
int
p
,
row
,
col
,
rel
;
if
(
kpc
&
KPC_DI
)
{
unsigned
long
kpdk
=
KPDK
;
if
(
!
(
kpdk
&
KPDK_DKP
))
{
/* better luck next time */
}
else
if
(
kpc
&
KPC_REE0
)
{
unsigned
long
kprec
=
KPREC
;
KPREC
=
0x7f
;
if
(
kprec
&
KPREC_OF0
)
rel
=
(
kprec
&
0xff
)
+
0x7f
;
else
if
(
kprec
&
KPREC_UF0
)
rel
=
(
kprec
&
0xff
)
-
0x7f
-
0xff
;
else
rel
=
(
kprec
&
0xff
)
-
0x7f
;
if
(
rel
)
{
input_report_rel
(
input_dev
,
REL_WHEEL
,
rel
);
input_sync
(
input_dev
);
}
}
}
if
(
kpc
&
KPC_MI
)
{
/* report the status of every button */
for
(
row
=
0
;
row
<
pdata
->
nr_rows
;
row
++
)
{
for
(
col
=
0
;
col
<
pdata
->
nr_cols
;
col
++
)
{
p
=
KPASMKP
(
col
)
&
KPASMKPx_MKC
(
row
,
col
)
?
1
:
0
;
pr_debug
(
"keycode %x - pressed %x
\n
"
,
pdata
->
keycodes
[
row
][
col
],
p
);
input_report_key
(
input_dev
,
pdata
->
keycodes
[
row
][
col
],
p
);
}
}
input_sync
(
input_dev
);
}
return
IRQ_HANDLED
;
}
static
int
pxakbd_open
(
struct
input_dev
*
dev
)
{
/* Set keypad control register */
KPC
|=
(
KPC_ASACT
|
KPC_MS_ALL
|
(
2
<<
6
)
|
KPC_REE0
|
KPC_DK_DEB_SEL
|
KPC_ME
|
KPC_MIE
|
KPC_DE
|
KPC_DIE
);
KPC
&=
~
KPC_AS
;
/* disable automatic scan */
KPC
&=
~
KPC_IMKP
;
/* do not ignore multiple keypresses */
/* Set rotary count to mid-point value */
KPREC
=
0x7F
;
/* Enable unit clock */
clk_enable
(
pxakbd_clk
);
return
0
;
}
static
void
pxakbd_close
(
struct
input_dev
*
dev
)
{
/* Disable clock unit */
clk_disable
(
pxakbd_clk
);
}
#ifdef CONFIG_PM
static
int
pxakbd_suspend
(
struct
platform_device
*
pdev
,
pm_message_t
state
)
{
struct
pxa27x_keyboard_platform_data
*
pdata
=
pdev
->
dev
.
platform_data
;
/* Save controller status */
pdata
->
reg_kpc
=
KPC
;
pdata
->
reg_kprec
=
KPREC
;
return
0
;
}
static
int
pxakbd_resume
(
struct
platform_device
*
pdev
)
{
struct
pxa27x_keyboard_platform_data
*
pdata
=
pdev
->
dev
.
platform_data
;
struct
input_dev
*
input_dev
=
platform_get_drvdata
(
pdev
);
mutex_lock
(
&
input_dev
->
mutex
);
if
(
input_dev
->
users
)
{
/* Restore controller status */
KPC
=
pdata
->
reg_kpc
;
KPREC
=
pdata
->
reg_kprec
;
/* Enable unit clock */
clk_disable
(
pxakbd_clk
);
clk_enable
(
pxakbd_clk
);
}
mutex_unlock
(
&
input_dev
->
mutex
);
return
0
;
}
#else
#define pxakbd_suspend NULL
#define pxakbd_resume NULL
#endif
static
int
__devinit
pxakbd_probe
(
struct
platform_device
*
pdev
)
{
struct
pxa27x_keyboard_platform_data
*
pdata
=
pdev
->
dev
.
platform_data
;
struct
input_dev
*
input_dev
;
int
i
,
row
,
col
,
error
;
pxakbd_clk
=
clk_get
(
&
pdev
->
dev
,
"KBDCLK"
);
if
(
IS_ERR
(
pxakbd_clk
))
{
error
=
PTR_ERR
(
pxakbd_clk
);
goto
err_clk
;
}
/* Create and register the input driver. */
input_dev
=
input_allocate_device
();
if
(
!
input_dev
)
{
printk
(
KERN_ERR
"Cannot request keypad device
\n
"
);
error
=
-
ENOMEM
;
goto
err_alloc
;
}
input_dev
->
name
=
DRIVER_NAME
;
input_dev
->
id
.
bustype
=
BUS_HOST
;
input_dev
->
open
=
pxakbd_open
;
input_dev
->
close
=
pxakbd_close
;
input_dev
->
dev
.
parent
=
&
pdev
->
dev
;
input_dev
->
evbit
[
0
]
=
BIT_MASK
(
EV_KEY
)
|
BIT_MASK
(
EV_REP
)
|
BIT_MASK
(
EV_REL
);
input_dev
->
relbit
[
BIT_WORD
(
REL_WHEEL
)]
=
BIT_MASK
(
REL_WHEEL
);
for
(
row
=
0
;
row
<
pdata
->
nr_rows
;
row
++
)
{
for
(
col
=
0
;
col
<
pdata
->
nr_cols
;
col
++
)
{
int
code
=
pdata
->
keycodes
[
row
][
col
];
if
(
code
>
0
)
set_bit
(
code
,
input_dev
->
keybit
);
}
}
error
=
request_irq
(
IRQ_KEYPAD
,
pxakbd_irq_handler
,
IRQF_DISABLED
,
DRIVER_NAME
,
pdev
);
if
(
error
)
{
printk
(
KERN_ERR
"Cannot request keypad IRQ
\n
"
);
goto
err_free_dev
;
}
platform_set_drvdata
(
pdev
,
input_dev
);
/* Register the input device */
error
=
input_register_device
(
input_dev
);
if
(
error
)
goto
err_free_irq
;
/* Setup GPIOs. */
for
(
i
=
0
;
i
<
pdata
->
nr_rows
+
pdata
->
nr_cols
;
i
++
)
pxa_gpio_mode
(
pdata
->
gpio_modes
[
i
]);
/*
* Store rows/cols info into keyboard registers.
*/
KPC
|=
(
pdata
->
nr_rows
-
1
)
<<
26
;
KPC
|=
(
pdata
->
nr_cols
-
1
)
<<
23
;
for
(
col
=
0
;
col
<
pdata
->
nr_cols
;
col
++
)
KPC
|=
KPC_MS0
<<
col
;
return
0
;
err_free_irq:
platform_set_drvdata
(
pdev
,
NULL
);
free_irq
(
IRQ_KEYPAD
,
pdev
);
err_free_dev:
input_free_device
(
input_dev
);
err_alloc:
clk_put
(
pxakbd_clk
);
err_clk:
return
error
;
}
static
int
__devexit
pxakbd_remove
(
struct
platform_device
*
pdev
)
{
struct
input_dev
*
input_dev
=
platform_get_drvdata
(
pdev
);
input_unregister_device
(
input_dev
);
free_irq
(
IRQ_KEYPAD
,
pdev
);
clk_put
(
pxakbd_clk
);
platform_set_drvdata
(
pdev
,
NULL
);
return
0
;
}
static
struct
platform_driver
pxakbd_driver
=
{
.
probe
=
pxakbd_probe
,
.
remove
=
__devexit_p
(
pxakbd_remove
),
.
suspend
=
pxakbd_suspend
,
.
resume
=
pxakbd_resume
,
.
driver
=
{
.
name
=
DRIVER_NAME
,
},
};
static
int
__init
pxakbd_init
(
void
)
{
return
platform_driver_register
(
&
pxakbd_driver
);
}
static
void
__exit
pxakbd_exit
(
void
)
{
platform_driver_unregister
(
&
pxakbd_driver
);
}
module_init
(
pxakbd_init
);
module_exit
(
pxakbd_exit
);
MODULE_DESCRIPTION
(
"PXA27x Matrix Keyboard Driver"
);
MODULE_LICENSE
(
"GPL"
);
drivers/input/keyboard/pxa27x_keypad.c
0 → 100644
View file @
03366e7b
/*
* linux/drivers/input/keyboard/pxa27x_keypad.c
*
* Driver for the pxa27x matrix keyboard controller.
*
* Created: Feb 22, 2007
* Author: Rodolfo Giometti <giometti@linux.it>
*
* Based on a previous implementations by Kevin O'Connor
* <kevin_at_koconnor.net> and Alex Osborne <bobofdoom@gmail.com> and
* on some suggestions by Nicolas Pitre <nico@cam.org>.
*
* 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/clk.h>
#include <linux/err.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/arch/hardware.h>
#include <asm/arch/pxa27x_keypad.h>
/*
* Keypad Controller registers
*/
#define KPC 0x0000
/* Keypad Control register */
#define KPDK 0x0008
/* Keypad Direct Key register */
#define KPREC 0x0010
/* Keypad Rotary Encoder register */
#define KPMK 0x0018
/* Keypad Matrix Key register */
#define KPAS 0x0020
/* Keypad Automatic Scan register */
/* Keypad Automatic Scan Multiple Key Presser register 0-3 */
#define KPASMKP0 0x0028
#define KPASMKP1 0x0030
#define KPASMKP2 0x0038
#define KPASMKP3 0x0040
#define KPKDI 0x0048
/* bit definitions */
#define KPC_MKRN(n) ((((n) & 0x7) - 1) << 26)
/* matrix key row number */
#define KPC_MKCN(n) ((((n) & 0x7) - 1) << 23)
/* matrix key column number */
#define KPC_DKN(n) ((((n) & 0x7) - 1) << 6)
/* direct key number */
#define KPC_AS (0x1 << 30)
/* Automatic Scan bit */
#define KPC_ASACT (0x1 << 29)
/* Automatic Scan on Activity */
#define KPC_MI (0x1 << 22)
/* Matrix interrupt bit */
#define KPC_IMKP (0x1 << 21)
/* Ignore Multiple Key Press */
#define KPC_MS(n) (0x1 << (13 + (n)))
/* Matrix scan line 'n' */
#define KPC_MS_ALL (0xff << 13)
#define KPC_ME (0x1 << 12)
/* Matrix Keypad Enable */
#define KPC_MIE (0x1 << 11)
/* Matrix Interrupt Enable */
#define KPC_DK_DEB_SEL (0x1 << 9)
/* Direct Keypad Debounce Select */
#define KPC_DI (0x1 << 5)
/* Direct key interrupt bit */
#define KPC_RE_ZERO_DEB (0x1 << 4)
/* Rotary Encoder Zero Debounce */
#define KPC_REE1 (0x1 << 3)
/* Rotary Encoder1 Enable */
#define KPC_REE0 (0x1 << 2)
/* Rotary Encoder0 Enable */
#define KPC_DE (0x1 << 1)
/* Direct Keypad Enable */
#define KPC_DIE (0x1 << 0)
/* Direct Keypad interrupt Enable */
#define KPDK_DKP (0x1 << 31)
#define KPDK_DK(n) ((n) & 0xff)
#define KPREC_OF1 (0x1 << 31)
#define kPREC_UF1 (0x1 << 30)
#define KPREC_OF0 (0x1 << 15)
#define KPREC_UF0 (0x1 << 14)
#define KPREC_RECOUNT0(n) ((n) & 0xff)
#define KPREC_RECOUNT1(n) (((n) >> 16) & 0xff)
#define KPMK_MKP (0x1 << 31)
#define KPAS_SO (0x1 << 31)
#define KPASMKPx_SO (0x1 << 31)
#define KPAS_MUKP(n) (((n) >> 26) & 0x1f)
#define KPAS_RP(n) (((n) >> 4) & 0xf)
#define KPAS_CP(n) ((n) & 0xf)
#define KPASMKP_MKC_MASK (0xff)
#define keypad_readl(off) __raw_readl(keypad->mmio_base + (off))
#define keypad_writel(off, v) __raw_writel((v), keypad->mmio_base + (off))
#define MAX_MATRIX_KEY_NUM (8 * 8)
struct
pxa27x_keypad
{
struct
pxa27x_keypad_platform_data
*
pdata
;
struct
clk
*
clk
;
struct
input_dev
*
input_dev
;
void
__iomem
*
mmio_base
;
/* matrix key code map */
unsigned
int
matrix_keycodes
[
MAX_MATRIX_KEY_NUM
];
/* state row bits of each column scan */
uint32_t
matrix_key_state
[
MAX_MATRIX_KEY_COLS
];
uint32_t
direct_key_state
;
unsigned
int
direct_key_mask
;
int
rotary_rel_code
[
2
];
int
rotary_up_key
[
2
];
int
rotary_down_key
[
2
];
};
static
void
pxa27x_keypad_build_keycode
(
struct
pxa27x_keypad
*
keypad
)
{
struct
pxa27x_keypad_platform_data
*
pdata
=
keypad
->
pdata
;
struct
input_dev
*
input_dev
=
keypad
->
input_dev
;
unsigned
int
*
key
;
int
i
;
key
=
&
pdata
->
matrix_key_map
[
0
];
for
(
i
=
0
;
i
<
pdata
->
matrix_key_map_size
;
i
++
,
key
++
)
{
int
row
=
((
*
key
)
>>
28
)
&
0xf
;
int
col
=
((
*
key
)
>>
24
)
&
0xf
;
int
code
=
(
*
key
)
&
0xffffff
;
keypad
->
matrix_keycodes
[(
row
<<
3
)
+
col
]
=
code
;
set_bit
(
code
,
input_dev
->
keybit
);
}
keypad
->
rotary_up_key
[
0
]
=
pdata
->
rotary0_up_key
;
keypad
->
rotary_up_key
[
1
]
=
pdata
->
rotary1_up_key
;
keypad
->
rotary_down_key
[
0
]
=
pdata
->
rotary0_down_key
;
keypad
->
rotary_down_key
[
1
]
=
pdata
->
rotary1_down_key
;
keypad
->
rotary_rel_code
[
0
]
=
pdata
->
rotary0_rel_code
;
keypad
->
rotary_rel_code
[
1
]
=
pdata
->
rotary1_rel_code
;
if
(
pdata
->
rotary0_up_key
&&
pdata
->
rotary0_down_key
)
{
set_bit
(
pdata
->
rotary0_up_key
,
input_dev
->
keybit
);
set_bit
(
pdata
->
rotary0_down_key
,
input_dev
->
keybit
);
}
else
set_bit
(
pdata
->
rotary0_rel_code
,
input_dev
->
relbit
);
if
(
pdata
->
rotary1_up_key
&&
pdata
->
rotary1_down_key
)
{
set_bit
(
pdata
->
rotary1_up_key
,
input_dev
->
keybit
);
set_bit
(
pdata
->
rotary1_down_key
,
input_dev
->
keybit
);
}
else
set_bit
(
pdata
->
rotary1_rel_code
,
input_dev
->
relbit
);
}
static
inline
unsigned
int
lookup_matrix_keycode
(
struct
pxa27x_keypad
*
keypad
,
int
row
,
int
col
)
{
return
keypad
->
matrix_keycodes
[(
row
<<
3
)
+
col
];
}
static
void
pxa27x_keypad_scan_matrix
(
struct
pxa27x_keypad
*
keypad
)
{
struct
pxa27x_keypad_platform_data
*
pdata
=
keypad
->
pdata
;
int
row
,
col
,
num_keys_pressed
=
0
;
uint32_t
new_state
[
MAX_MATRIX_KEY_COLS
];
uint32_t
kpas
=
keypad_readl
(
KPAS
);
num_keys_pressed
=
KPAS_MUKP
(
kpas
);
memset
(
new_state
,
0
,
sizeof
(
new_state
));
if
(
num_keys_pressed
==
0
)
goto
scan
;
if
(
num_keys_pressed
==
1
)
{
col
=
KPAS_CP
(
kpas
);
row
=
KPAS_RP
(
kpas
);
/* if invalid row/col, treat as no key pressed */
if
(
col
>=
pdata
->
matrix_key_cols
||
row
>=
pdata
->
matrix_key_rows
)
goto
scan
;
new_state
[
col
]
=
(
1
<<
row
);
goto
scan
;
}
if
(
num_keys_pressed
>
1
)
{
uint32_t
kpasmkp0
=
keypad_readl
(
KPASMKP0
);
uint32_t
kpasmkp1
=
keypad_readl
(
KPASMKP1
);
uint32_t
kpasmkp2
=
keypad_readl
(
KPASMKP2
);
uint32_t
kpasmkp3
=
keypad_readl
(
KPASMKP3
);
new_state
[
0
]
=
kpasmkp0
&
KPASMKP_MKC_MASK
;
new_state
[
1
]
=
(
kpasmkp0
>>
16
)
&
KPASMKP_MKC_MASK
;
new_state
[
2
]
=
kpasmkp1
&
KPASMKP_MKC_MASK
;
new_state
[
3
]
=
(
kpasmkp1
>>
16
)
&
KPASMKP_MKC_MASK
;
new_state
[
4
]
=
kpasmkp2
&
KPASMKP_MKC_MASK
;
new_state
[
5
]
=
(
kpasmkp2
>>
16
)
&
KPASMKP_MKC_MASK
;
new_state
[
6
]
=
kpasmkp3
&
KPASMKP_MKC_MASK
;
new_state
[
7
]
=
(
kpasmkp3
>>
16
)
&
KPASMKP_MKC_MASK
;
}
scan:
for
(
col
=
0
;
col
<
pdata
->
matrix_key_cols
;
col
++
)
{
uint32_t
bits_changed
;
bits_changed
=
keypad
->
matrix_key_state
[
col
]
^
new_state
[
col
];
if
(
bits_changed
==
0
)
continue
;
for
(
row
=
0
;
row
<
pdata
->
matrix_key_rows
;
row
++
)
{
if
((
bits_changed
&
(
1
<<
row
))
==
0
)
continue
;
input_report_key
(
keypad
->
input_dev
,
lookup_matrix_keycode
(
keypad
,
row
,
col
),
new_state
[
col
]
&
(
1
<<
row
));
}
}
input_sync
(
keypad
->
input_dev
);
memcpy
(
keypad
->
matrix_key_state
,
new_state
,
sizeof
(
new_state
));
}
#define DEFAULT_KPREC (0x007f007f)
static
inline
int
rotary_delta
(
uint32_t
kprec
)
{
if
(
kprec
&
KPREC_OF0
)
return
(
kprec
&
0xff
)
+
0x7f
;
else
if
(
kprec
&
KPREC_UF0
)
return
(
kprec
&
0xff
)
-
0x7f
-
0xff
;
else
return
(
kprec
&
0xff
)
-
0x7f
;
}
static
void
report_rotary_event
(
struct
pxa27x_keypad
*
keypad
,
int
r
,
int
delta
)
{
struct
input_dev
*
dev
=
keypad
->
input_dev
;
if
(
delta
==
0
)
return
;
if
(
keypad
->
rotary_up_key
[
r
]
&&
keypad
->
rotary_down_key
[
r
])
{
int
keycode
=
(
delta
>
0
)
?
keypad
->
rotary_up_key
[
r
]
:
keypad
->
rotary_down_key
[
r
];
/* simulate a press-n-release */
input_report_key
(
dev
,
keycode
,
1
);
input_sync
(
dev
);
input_report_key
(
dev
,
keycode
,
0
);
input_sync
(
dev
);
}
else
{
input_report_rel
(
dev
,
keypad
->
rotary_rel_code
[
r
],
delta
);
input_sync
(
dev
);
}
}
static
void
pxa27x_keypad_scan_rotary
(
struct
pxa27x_keypad
*
keypad
)
{
struct
pxa27x_keypad_platform_data
*
pdata
=
keypad
->
pdata
;
uint32_t
kprec
;
/* read and reset to default count value */
kprec
=
keypad_readl
(
KPREC
);
keypad_writel
(
KPREC
,
DEFAULT_KPREC
);
if
(
pdata
->
enable_rotary0
)
report_rotary_event
(
keypad
,
0
,
rotary_delta
(
kprec
));
if
(
pdata
->
enable_rotary1
)
report_rotary_event
(
keypad
,
1
,
rotary_delta
(
kprec
>>
16
));
}
static
void
pxa27x_keypad_scan_direct
(
struct
pxa27x_keypad
*
keypad
)
{
struct
pxa27x_keypad_platform_data
*
pdata
=
keypad
->
pdata
;
unsigned
int
new_state
;
uint32_t
kpdk
,
bits_changed
;
int
i
;
kpdk
=
keypad_readl
(
KPDK
);
if
(
pdata
->
enable_rotary0
||
pdata
->
enable_rotary1
)
pxa27x_keypad_scan_rotary
(
keypad
);
if
(
pdata
->
direct_key_map
==
NULL
)
return
;
new_state
=
KPDK_DK
(
kpdk
)
&
keypad
->
direct_key_mask
;
bits_changed
=
keypad
->
direct_key_state
^
new_state
;
if
(
bits_changed
==
0
)
return
;
for
(
i
=
0
;
i
<
pdata
->
direct_key_num
;
i
++
)
{
if
(
bits_changed
&
(
1
<<
i
))
input_report_key
(
keypad
->
input_dev
,
pdata
->
direct_key_map
[
i
],
(
new_state
&
(
1
<<
i
)));
}
input_sync
(
keypad
->
input_dev
);
keypad
->
direct_key_state
=
new_state
;
}
static
irqreturn_t
pxa27x_keypad_irq_handler
(
int
irq
,
void
*
dev_id
)
{
struct
pxa27x_keypad
*
keypad
=
dev_id
;
unsigned
long
kpc
=
keypad_readl
(
KPC
);
if
(
kpc
&
KPC_DI
)
pxa27x_keypad_scan_direct
(
keypad
);
if
(
kpc
&
KPC_MI
)
pxa27x_keypad_scan_matrix
(
keypad
);
return
IRQ_HANDLED
;
}
static
void
pxa27x_keypad_config
(
struct
pxa27x_keypad
*
keypad
)
{
struct
pxa27x_keypad_platform_data
*
pdata
=
keypad
->
pdata
;
unsigned
int
mask
=
0
,
direct_key_num
=
0
;
unsigned
long
kpc
=
0
;
/* enable matrix keys with automatic scan */
if
(
pdata
->
matrix_key_rows
&&
pdata
->
matrix_key_cols
)
{
kpc
|=
KPC_ASACT
|
KPC_MIE
|
KPC_ME
|
KPC_MS_ALL
;
kpc
|=
KPC_MKRN
(
pdata
->
matrix_key_rows
)
|
KPC_MKCN
(
pdata
->
matrix_key_cols
);
}
/* enable rotary key, debounce interval same as direct keys */
if
(
pdata
->
enable_rotary0
)
{
mask
|=
0x03
;
direct_key_num
=
2
;
kpc
|=
KPC_REE0
;
}
if
(
pdata
->
enable_rotary1
)
{
mask
|=
0x0c
;
direct_key_num
=
4
;
kpc
|=
KPC_REE1
;
}
if
(
pdata
->
direct_key_num
>
direct_key_num
)
direct_key_num
=
pdata
->
direct_key_num
;
keypad
->
direct_key_mask
=
((
2
<<
direct_key_num
)
-
1
)
&
~
mask
;
/* enable direct key */
if
(
direct_key_num
)
kpc
|=
KPC_DE
|
KPC_DIE
|
KPC_DKN
(
direct_key_num
);
keypad_writel
(
KPC
,
kpc
|
KPC_RE_ZERO_DEB
);
keypad_writel
(
KPREC
,
DEFAULT_KPREC
);
keypad_writel
(
KPKDI
,
pdata
->
debounce_interval
);
}
static
int
pxa27x_keypad_open
(
struct
input_dev
*
dev
)
{
struct
pxa27x_keypad
*
keypad
=
input_get_drvdata
(
dev
);
/* Enable unit clock */
clk_enable
(
keypad
->
clk
);
pxa27x_keypad_config
(
keypad
);
return
0
;
}
static
void
pxa27x_keypad_close
(
struct
input_dev
*
dev
)
{
struct
pxa27x_keypad
*
keypad
=
input_get_drvdata
(
dev
);
/* Disable clock unit */
clk_disable
(
keypad
->
clk
);
}
#ifdef CONFIG_PM
static
int
pxa27x_keypad_suspend
(
struct
platform_device
*
pdev
,
pm_message_t
state
)
{
struct
pxa27x_keypad
*
keypad
=
platform_get_drvdata
(
pdev
);
clk_disable
(
keypad
->
clk
);
return
0
;
}
static
int
pxa27x_keypad_resume
(
struct
platform_device
*
pdev
)
{
struct
pxa27x_keypad
*
keypad
=
platform_get_drvdata
(
pdev
);
struct
input_dev
*
input_dev
=
keypad
->
input_dev
;
mutex_lock
(
&
input_dev
->
mutex
);
if
(
input_dev
->
users
)
{
/* Enable unit clock */
clk_enable
(
keypad
->
clk
);
pxa27x_keypad_config
(
keypad
);
}
mutex_unlock
(
&
input_dev
->
mutex
);
return
0
;
}
#else
#define pxa27x_keypad_suspend NULL
#define pxa27x_keypad_resume NULL
#endif
#define res_size(res) ((res)->end - (res)->start + 1)
static
int
__devinit
pxa27x_keypad_probe
(
struct
platform_device
*
pdev
)
{
struct
pxa27x_keypad
*
keypad
;
struct
input_dev
*
input_dev
;
struct
resource
*
res
;
int
irq
,
error
;
keypad
=
kzalloc
(
sizeof
(
struct
pxa27x_keypad
),
GFP_KERNEL
);
if
(
keypad
==
NULL
)
{
dev_err
(
&
pdev
->
dev
,
"failed to allocate driver data
\n
"
);
return
-
ENOMEM
;
}
keypad
->
pdata
=
pdev
->
dev
.
platform_data
;
if
(
keypad
->
pdata
==
NULL
)
{
dev_err
(
&
pdev
->
dev
,
"no platform data defined
\n
"
);
error
=
-
EINVAL
;
goto
failed_free
;
}
irq
=
platform_get_irq
(
pdev
,
0
);
if
(
irq
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"failed to get keypad irq
\n
"
);
error
=
-
ENXIO
;
goto
failed_free
;
}
res
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
if
(
res
==
NULL
)
{
dev_err
(
&
pdev
->
dev
,
"failed to get I/O memory
\n
"
);
error
=
-
ENXIO
;
goto
failed_free
;
}
res
=
request_mem_region
(
res
->
start
,
res_size
(
res
),
pdev
->
name
);
if
(
res
==
NULL
)
{
dev_err
(
&
pdev
->
dev
,
"failed to request I/O memory
\n
"
);
error
=
-
EBUSY
;
goto
failed_free
;
}
keypad
->
mmio_base
=
ioremap
(
res
->
start
,
res_size
(
res
));
if
(
keypad
->
mmio_base
==
NULL
)
{
dev_err
(
&
pdev
->
dev
,
"failed to remap I/O memory
\n
"
);
error
=
-
ENXIO
;
goto
failed_free_mem
;
}
keypad
->
clk
=
clk_get
(
&
pdev
->
dev
,
"KBDCLK"
);
if
(
IS_ERR
(
keypad
->
clk
))
{
dev_err
(
&
pdev
->
dev
,
"failed to get keypad clock
\n
"
);
error
=
PTR_ERR
(
keypad
->
clk
);
goto
failed_free_io
;
}
/* Create and register the input driver. */
input_dev
=
input_allocate_device
();
if
(
!
input_dev
)
{
dev_err
(
&
pdev
->
dev
,
"failed to allocate input device
\n
"
);
error
=
-
ENOMEM
;
goto
failed_put_clk
;
}
input_dev
->
name
=
pdev
->
name
;
input_dev
->
id
.
bustype
=
BUS_HOST
;
input_dev
->
open
=
pxa27x_keypad_open
;
input_dev
->
close
=
pxa27x_keypad_close
;
input_dev
->
dev
.
parent
=
&
pdev
->
dev
;
keypad
->
input_dev
=
input_dev
;
input_set_drvdata
(
input_dev
,
keypad
);
input_dev
->
evbit
[
0
]
=
BIT_MASK
(
EV_KEY
)
|
BIT_MASK
(
EV_REP
)
|
BIT_MASK
(
EV_REL
);
pxa27x_keypad_build_keycode
(
keypad
);
platform_set_drvdata
(
pdev
,
keypad
);
error
=
request_irq
(
irq
,
pxa27x_keypad_irq_handler
,
IRQF_DISABLED
,
pdev
->
name
,
keypad
);
if
(
error
)
{
dev_err
(
&
pdev
->
dev
,
"failed to request IRQ
\n
"
);
goto
failed_free_dev
;
}
/* Register the input device */
error
=
input_register_device
(
input_dev
);
if
(
error
)
{
dev_err
(
&
pdev
->
dev
,
"failed to register input device
\n
"
);
goto
failed_free_irq
;
}
return
0
;
failed_free_irq:
free_irq
(
irq
,
pdev
);
platform_set_drvdata
(
pdev
,
NULL
);
failed_free_dev:
input_free_device
(
input_dev
);
failed_put_clk:
clk_put
(
keypad
->
clk
);
failed_free_io:
iounmap
(
keypad
->
mmio_base
);
failed_free_mem:
release_mem_region
(
res
->
start
,
res_size
(
res
));
failed_free:
kfree
(
keypad
);
return
error
;
}
static
int
__devexit
pxa27x_keypad_remove
(
struct
platform_device
*
pdev
)
{
struct
pxa27x_keypad
*
keypad
=
platform_get_drvdata
(
pdev
);
struct
resource
*
res
;
free_irq
(
platform_get_irq
(
pdev
,
0
),
pdev
);
clk_disable
(
keypad
->
clk
);
clk_put
(
keypad
->
clk
);
input_unregister_device
(
keypad
->
input_dev
);
input_free_device
(
keypad
->
input_dev
);
iounmap
(
keypad
->
mmio_base
);
res
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
release_mem_region
(
res
->
start
,
res_size
(
res
));
platform_set_drvdata
(
pdev
,
NULL
);
kfree
(
keypad
);
return
0
;
}
static
struct
platform_driver
pxa27x_keypad_driver
=
{
.
probe
=
pxa27x_keypad_probe
,
.
remove
=
__devexit_p
(
pxa27x_keypad_remove
),
.
suspend
=
pxa27x_keypad_suspend
,
.
resume
=
pxa27x_keypad_resume
,
.
driver
=
{
.
name
=
"pxa27x-keypad"
,
},
};
static
int
__init
pxa27x_keypad_init
(
void
)
{
return
platform_driver_register
(
&
pxa27x_keypad_driver
);
}
static
void
__exit
pxa27x_keypad_exit
(
void
)
{
platform_driver_unregister
(
&
pxa27x_keypad_driver
);
}
module_init
(
pxa27x_keypad_init
);
module_exit
(
pxa27x_keypad_exit
);
MODULE_DESCRIPTION
(
"PXA27x Keypad Controller Driver"
);
MODULE_LICENSE
(
"GPL"
);
include/asm-arm/arch-pxa/pxa27x_keyboard.h
deleted
100644 → 0
View file @
c18bab80
#define PXAKBD_MAXROW 8
#define PXAKBD_MAXCOL 8
struct
pxa27x_keyboard_platform_data
{
int
nr_rows
,
nr_cols
;
int
keycodes
[
PXAKBD_MAXROW
][
PXAKBD_MAXCOL
];
int
gpio_modes
[
PXAKBD_MAXROW
+
PXAKBD_MAXCOL
];
#ifdef CONFIG_PM
u32
reg_kpc
;
u32
reg_kprec
;
#endif
};
include/asm-arm/arch-pxa/pxa27x_keypad.h
0 → 100644
View file @
03366e7b
#ifndef __ASM_ARCH_PXA27x_KEYPAD_H
#define __ASM_ARCH_PXA27x_KEYPAD_H
#include <linux/input.h>
#define MAX_MATRIX_KEY_ROWS (8)
#define MAX_MATRIX_KEY_COLS (8)
/* pxa3xx keypad platform specific parameters
*
* NOTE:
* 1. direct_key_num indicates the number of keys in the direct keypad
* _plus_ the number of rotary-encoder sensor inputs, this can be
* left as 0 if only rotary encoders are enabled, the driver will
* automatically calculate this
*
* 2. direct_key_map is the key code map for the direct keys, if rotary
* encoder(s) are enabled, direct key 0/1(2/3) will be ignored
*
* 3. rotary can be either interpreted as a relative input event (e.g.
* REL_WHEEL/REL_HWHEEL) or specific keys (e.g. UP/DOWN/LEFT/RIGHT)
*
* 4. matrix key and direct key will use the same debounce_interval by
* default, which should be sufficient in most cases
*/
struct
pxa27x_keypad_platform_data
{
/* code map for the matrix keys */
unsigned
int
matrix_key_rows
;
unsigned
int
matrix_key_cols
;
unsigned
int
*
matrix_key_map
;
int
matrix_key_map_size
;
/* direct keys */
int
direct_key_num
;
unsigned
int
direct_key_map
[
8
];
/* rotary encoders 0 */
int
enable_rotary0
;
int
rotary0_rel_code
;
int
rotary0_up_key
;
int
rotary0_down_key
;
/* rotary encoders 1 */
int
enable_rotary1
;
int
rotary1_rel_code
;
int
rotary1_up_key
;
int
rotary1_down_key
;
/* key debounce interval */
unsigned
int
debounce_interval
;
};
#define KEY(row, col, val) (((row) << 28) | ((col) << 24) | (val))
#endif
/* __ASM_ARCH_PXA27x_KEYPAD_H */
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