@ -6,8 +6,10 @@
*/
# include <common.h>
# include <dm.h>
# include <fdtdec.h>
# include <input.h>
# include <keyboard.h>
# include <key_matrix.h>
# include <stdio_dev.h>
# include <tegra-kbc.h>
@ -40,14 +42,13 @@ enum {
} ;
/* keyboard controller config and state */
static struct keyb {
struct input_config input ; /* The input layer */
struct tegra_kbd_priv {
struct input_config * input ; /* The input layer */
struct key_matrix matrix ; /* The key matrix layer */
struct kbc_tegra * kbc ; /* tegra keyboard controller */
unsigned char inited ; /* 1 if keyboard has been inited */
unsigned char first_scan ; /* 1 if this is our first key scan */
unsigned char created ; /* 1 if driver has been created */
/*
* After init we must wait a short time before polling the keyboard .
@ -58,17 +59,17 @@ static struct keyb {
unsigned int start_time_ms ; /* Time that we inited (in ms) */
unsigned int last_poll_ms ; /* Time we should last polled */
unsigned int next_repeat_ms ; /* Next time we repeat a key */
} config ;
} ;
/**
* reads the keyboard fifo for current keypresses
*
* @ param config Keyboard config
* @ param priv Keyboard private data
* @ param fifo Place to put fifo results
* @ param max_keycodes Maximum number of key codes to put in the fifo
* @ return number of items put into fifo
*/
static int tegra_kbc_find_keys ( struct keyb * config , int * fifo ,
static int tegra_kbc_find_keys ( struct tegra_kbd_priv * priv , int * fifo ,
int max_keycodes )
{
struct key_matrix_key keys [ KBC_MAX_KPENT ] , * key ;
@ -78,7 +79,7 @@ static int tegra_kbc_find_keys(struct keyb *config, int *fifo,
for ( key = keys , i = 0 ; i < KBC_MAX_KPENT ; i + + , key + + ) {
/* Get next word */
if ( ! ( i & 3 ) )
kp_ent = readl ( & config - > kbc - > kp_ent [ i / 4 ] ) ;
kp_ent = readl ( & priv - > kbc - > kp_ent [ i / 4 ] ) ;
key - > valid = ( kp_ent & KBC_KPENT_VALID ) ! = 0 ;
key - > row = ( kp_ent > > 3 ) & 0xf ;
@ -87,7 +88,7 @@ static int tegra_kbc_find_keys(struct keyb *config, int *fifo,
/* Shift to get next entry */
kp_ent > > = 8 ;
}
return key_matrix_decode ( & config - > matrix , keys , KBC_MAX_KPENT , fifo ,
return key_matrix_decode ( & priv - > matrix , keys , KBC_MAX_KPENT , fifo ,
max_keycodes ) ;
}
@ -106,10 +107,10 @@ static int tegra_kbc_find_keys(struct keyb *config, int *fifo,
* Note : if fifo_cnt is 0 , we will tell the input layer that no keys are
* pressed .
*
* @ param config Keyboard config
* @ param priv Keyboard private data
* @ param fifo_cnt Number of entries in the keyboard fifo
*/
static void process_fifo ( struct keyb * config , int fifo_cnt )
static void process_fifo ( struct tegra_kbd_priv * priv , int fifo_cnt )
{
int fifo [ KBC_MAX_KPENT ] ;
int cnt = 0 ;
@ -117,9 +118,9 @@ static void process_fifo(struct keyb *config, int fifo_cnt)
/* Always call input_send_keycodes() at least once */
do {
if ( fifo_cnt )
cnt = tegra_kbc_find_keys ( config , fifo , KBC_MAX_KPENT ) ;
cnt = tegra_kbc_find_keys ( priv , fifo , KBC_MAX_KPENT ) ;
input_send_keycodes ( & config - > input , fifo , cnt ) ;
input_send_keycodes ( priv - > input , fifo , cnt ) ;
} while ( - - fifo_cnt > 0 ) ;
}
@ -127,24 +128,24 @@ static void process_fifo(struct keyb *config, int fifo_cnt)
* Check the keyboard controller and emit ASCII characters for any keys that
* are pressed .
*
* @ param config Keyboard config
* @ param priv Keyboard private data
*/
static void check_for_keys ( struct keyb * config )
static void check_for_keys ( struct tegra_kbd_priv * priv )
{
int fifo_cnt ;
if ( ! config - > first_scan & &
get_timer ( config - > last_poll_ms ) < KBC_REPEAT_RATE_MS )
if ( ! priv - > first_scan & &
get_timer ( priv - > last_poll_ms ) < KBC_REPEAT_RATE_MS )
return ;
config - > last_poll_ms = get_timer ( 0 ) ;
config - > first_scan = 0 ;
priv - > last_poll_ms = get_timer ( 0 ) ;
priv - > first_scan = 0 ;
/*
* Once we get here we know the keyboard has been scanned . So if there
* scan waiting for us , we know that nothing is held down .
*/
fifo_cnt = ( readl ( & config - > kbc - > interrupt ) > > 4 ) & 0xf ;
process_fifo ( config , fifo_cnt ) ;
fifo_cnt = ( readl ( & priv - > kbc - > interrupt ) > > 4 ) & 0xf ;
process_fifo ( priv , fifo_cnt ) ;
}
/**
@ -153,22 +154,22 @@ static void check_for_keys(struct keyb *config)
* Wkup mode to Continous polling mode and the repoll time . We can
* deduct the time that ' s already elapsed .
*
* @ param config Keyboard config
* @ param priv Keyboard private data
*/
static void kbd_wait_for_fifo_init ( struct keyb * config )
static void kbd_wait_for_fifo_init ( struct tegra_kbd_priv * priv )
{
if ( ! config - > inited ) {
if ( ! priv - > inited ) {
unsigned long elapsed_time ;
long delay_ms ;
elapsed_time = get_timer ( config - > start_time_ms ) ;
delay_ms = config - > init_dly_ms - elapsed_time ;
elapsed_time = get_timer ( priv - > start_time_ms ) ;
delay_ms = priv - > init_dly_ms - elapsed_time ;
if ( delay_ms > 0 ) {
udelay ( delay_ms * 1000 ) ;
debug ( " %s: delay %ldms \n " , __func__ , delay_ms ) ;
}
config - > inited = 1 ;
priv - > inited = 1 ;
}
}
@ -183,38 +184,16 @@ static void kbd_wait_for_fifo_init(struct keyb *config)
*/
static int tegra_kbc_check ( struct input_config * input )
{
kbd_wait_for_fifo_init ( & config ) ;
check_for_keys ( & config ) ;
return 1 ;
}
struct tegra_kbd_priv * priv = dev_get_priv ( input - > dev ) ;
/**
* Test if keys are available to be read
*
* @ return 0 if no keys available , 1 if keys are available
*/
static int kbd_tstc ( struct stdio_dev * dev )
{
/* Just get input to do this for us */
return input_tstc ( & config . input ) ;
}
kbd_wait_for_fifo_init ( priv ) ;
check_for_keys ( priv ) ;
/**
* Read a key
*
* TODO : U - Boot wants 0 for no key , but Ctrl - @ is a valid key . . .
*
* @ return ASCII key code , or 0 if no key , or - 1 if error
*/
static int kbd_getc ( struct stdio_dev * dev )
{
/* Just get input to do this for us */
return input_getc ( & config . input ) ;
return 1 ;
}
/* configures keyboard GPIO registers to use the rows and columns */
static void config_kbc_gpio ( struct kbc_tegra * kbc )
static void config_kbc_gpio ( struct tegra_kbd_priv * priv , struct kbc_tegra * kbc )
{
int i ;
@ -233,10 +212,10 @@ static void config_kbc_gpio(struct kbc_tegra *kbc)
row_cfg & = ~ r_mask ;
col_cfg & = ~ c_mask ;
if ( i < config . matrix . num_rows ) {
if ( i < priv - > matrix . num_rows ) {
row_cfg | = ( ( i < < 1 ) | 1 ) < < r_shift ;
} else {
col_cfg | = ( ( ( i - config . matrix . num_rows ) < < 1 ) | 1 )
col_cfg | = ( ( ( i - priv - > matrix . num_rows ) < < 1 ) | 1 )
< < c_shift ;
}
@ -248,9 +227,9 @@ static void config_kbc_gpio(struct kbc_tegra *kbc)
/**
* Start up the keyboard device
*/
static void tegra_kbc_open ( void )
static void tegra_kbc_open ( struct tegra_kbd_priv * priv )
{
struct kbc_tegra * kbc = config . kbc ;
struct kbc_tegra * kbc = priv - > kbc ;
unsigned int scan_period ;
u32 val ;
@ -265,16 +244,32 @@ static void tegra_kbc_open(void)
* Before reading from the keyboard we must wait for the init_dly
* plus the rpt_delay , plus 2 ms for the row scan time .
*/
config . init_dly_ms = scan_period * 2 + 2 ;
priv - > init_dly_ms = scan_period * 2 + 2 ;
val = KBC_DEBOUNCE_COUNT < < KBC_DEBOUNCE_CNT_SHIFT ;
val | = 1 < < KBC_FIFO_TH_CNT_SHIFT ; /* fifo interrupt threshold */
val | = KBC_CONTROL_KBC_EN ; /* enable */
writel ( val , & kbc - > control ) ;
config . start_time_ms = get_timer ( 0 ) ;
config . last_poll_ms = config . next_repeat_ms = get_timer ( 0 ) ;
config . first_scan = 1 ;
priv - > start_time_ms = get_timer ( 0 ) ;
priv - > last_poll_ms = get_timer ( 0 ) ;
priv - > next_repeat_ms = priv - > last_poll_ms ;
priv - > first_scan = 1 ;
}
static int tegra_kbd_start ( struct udevice * dev )
{
struct tegra_kbd_priv * priv = dev_get_priv ( dev ) ;
/* Set up pin mux and enable the clock */
funcmux_select ( PERIPH_ID_KBC , FUNCMUX_DEFAULT ) ;
clock_enable ( PERIPH_ID_KBC ) ;
config_kbc_gpio ( priv , priv - > kbc ) ;
tegra_kbc_open ( priv ) ;
debug ( " %s: Tegra keyboard ready \n " , __func__ ) ;
return 0 ;
}
/**
@ -289,89 +284,73 @@ static void tegra_kbc_open(void)
*
* @ return 0 if ok , - ve on error
*/
static int init_ tegra_key boar d( struct stdio_dev * dev )
static int tegra_kbd_probe ( struct udevice * dev )
{
/* check if already created */
if ( config . created )
return 0 ;
# if CONFIG_IS_ENABLED(OF_CONTROL)
int node ;
node = fdtdec_next_compatible ( gd - > fdt_blob , 0 ,
COMPAT_NVIDIA_TEGRA20_KBC ) ;
if ( node < 0 ) {
debug ( " %s: cannot locate keyboard node \n " , __func__ ) ;
return node ;
}
config . kbc = ( struct kbc_tegra * ) fdtdec_get_addr ( gd - > fdt_blob ,
node , " reg " ) ;
if ( ( fdt_addr_t ) config . kbc = = FDT_ADDR_T_NONE ) {
struct tegra_kbd_priv * priv = dev_get_priv ( dev ) ;
struct keyboard_priv * uc_priv = dev_get_uclass_priv ( dev ) ;
struct stdio_dev * sdev = & uc_priv - > sdev ;
struct input_config * input = & uc_priv - > input ;
int node = dev - > of_offset ;
int ret ;
priv - > kbc = ( struct kbc_tegra * ) dev_get_addr ( dev ) ;
if ( ( fdt_addr_t ) priv - > kbc = = FDT_ADDR_T_NONE ) {
debug ( " %s: No keyboard register found \n " , __func__ ) ;
return - 1 ;
return - EINVAL ;
}
input_set_delays ( & config . input , KBC_REPEAT_DELAY_MS ,
KBC_REPEAT_RATE_MS ) ;
input_set_delays ( input , KBC_REPEAT_DELAY_MS , KBC_REPEAT_RATE_MS ) ;
/* Decode the keyboard matrix information (16 rows, 8 columns) */
if ( key_matrix_init ( & config . matrix , 16 , 8 , 1 ) ) {
debug ( " %s: Could not init key matrix \n " , __func__ ) ;
return - 1 ;
ret = key_matrix_init ( & priv - > matrix , 16 , 8 , 1 ) ;
if ( ret ) {
debug ( " %s: Could not init key matrix: %d \n " , __func__ , ret ) ;
return ret ;
}
if ( key_matrix_decode_fdt ( & config . matrix , gd - > fdt_blob , node ) ) {
debug ( " %s: Could not decode key matrix from fdt \n " , __func__ ) ;
return - 1 ;
ret = key_matrix_decode_fdt ( & priv - > matrix , gd - > fdt_blob , node ) ;
if ( ret ) {
debug ( " %s: Could not decode key matrix from fdt: %d \n " ,
__func__ , ret ) ;
return ret ;
}
if ( config . matrix . fn_keycode ) {
if ( input_add_table ( & config . input , KEY_FN , - 1 ,
config . matrix . fn_keycode ,
config . matrix . key_count ) )
return - 1 ;
if ( priv - > matrix . fn_keycode ) {
ret = input_add_table ( input , KEY_FN , - 1 ,
priv - > matrix . fn_keycode ,
priv - > matrix . key_count ) ;
if ( ret ) {
debug ( " %s: input_add_table() failed \n " , __func__ ) ;
return ret ;
}
}
# else
# error "Tegra keyboard driver requires FDT definitions"
# endif
/* Set up pin mux and enable the clock */
funcmux_select ( PERIPH_ID_KBC , FUNCMUX_DEFAULT ) ;
clock_enable ( PERIPH_ID_KBC ) ;
config_kbc_gpio ( config . kbc ) ;
tegra_kbc_open ( ) ;
config . created = 1 ;
debug ( " %s: Tegra keyboard ready \n " , __func__ ) ;
/* Register the device. init_tegra_keyboard() will be called soon */
priv - > input = input ;
input - > dev = dev ;
input - > read_keys = tegra_kbc_check ;
input_add_tables ( input ) ;
strcpy ( sdev - > name , " tegra-kbc " ) ;
ret = input_stdio_register ( sdev ) ;
if ( ret ) {
debug ( " %s: input_stdio_register() failed \n " , __func__ ) ;
return ret ;
}
return 0 ;
}
int drv_keyboard_init ( void )
{
struct stdio_dev dev ;
char * stdinname = getenv ( " stdin " ) ;
int error ;
if ( input_init ( & config . input , 0 ) ) {
debug ( " %s: Cannot set up input \n " , __func__ ) ;
return - 1 ;
}
config . input . read_keys = tegra_kbc_check ;
input_add_tables ( input ) ;
static const struct keyboard_ops tegra_kbd_ops = {
. start = tegra_kbd_start ,
} ;
memset ( & dev , ' \0 ' , sizeof ( dev ) ) ;
strcpy ( dev . name , " tegra-kbc " ) ;
dev . flags = DEV_FLAGS_INPUT ;
dev . getc = kbd_getc ;
dev . tstc = kbd_tstc ;
dev . start = init_tegra_keyboard ;
static const struct udevice_id tegra_kbd_ids [ ] = {
{ . compatible = " nvidia,tegra20-kbc " } ,
{ }
} ;
/* Register the device. init_tegra_keyboard() will be called soon */
error = input_stdio_register ( & dev ) ;
if ( error )
return error ;
# ifdef CONFIG_CONSOLE_MUX
error = iomux_doenv ( stdin , stdinname ) ;
if ( error )
return error ;
# endif
return 0 ;
}
U_BOOT_DRIVER ( tegra_kbd ) = {
. name = " tegra_kbd " ,
. id = UCLASS_KEYBOARD ,
. of_match = tegra_kbd_ids ,
. probe = tegra_kbd_probe ,
. ops = & tegra_kbd_ops ,
. priv_auto_alloc_size = sizeof ( struct tegra_kbd_priv ) ,
} ;