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
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
Show 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