2019-05-19 16:51:31 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2011-01-20 10:38:47 +03:00
/*
* Keyboard class input driver for the NVIDIA Tegra SoC internal matrix
* keyboard controller
*
* Copyright ( c ) 2009 - 2011 , NVIDIA Corporation .
*/
2011-07-30 23:01:48 +04:00
# include <linux/kernel.h>
2011-01-20 10:38:47 +03:00
# include <linux/module.h>
# include <linux/input.h>
# include <linux/platform_device.h>
# include <linux/delay.h>
# include <linux/io.h>
# include <linux/interrupt.h>
2011-12-29 21:58:16 +04:00
# include <linux/of.h>
2013-03-31 11:41:12 +04:00
# include <linux/of_device.h>
2011-01-20 10:38:47 +03:00
# include <linux/clk.h>
# include <linux/slab.h>
2013-02-16 05:04:12 +04:00
# include <linux/input/matrix_keypad.h>
2013-11-07 03:48:16 +04:00
# include <linux/reset.h>
2013-03-18 08:30:05 +04:00
# include <linux/err.h>
2011-01-20 10:38:47 +03:00
2013-02-16 05:04:12 +04:00
# define KBC_MAX_KPENT 8
2013-03-31 11:41:12 +04:00
/* Maximum row/column supported by Tegra KBC yet is 16x8 */
# define KBC_MAX_GPIO 24
/* Maximum keys supported by Tegra KBC yet is 16 x 8*/
# define KBC_MAX_KEY (16 * 8)
2013-02-16 05:04:12 +04:00
2011-01-20 10:38:47 +03:00
# define KBC_MAX_DEBOUNCE_CNT 0x3ffu
/* KBC row scan time and delay for beginning the row scan. */
# define KBC_ROW_SCAN_TIME 16
# define KBC_ROW_SCAN_DLY 5
/* KBC uses a 32KHz clock so a cycle = 1/32Khz */
2011-07-30 23:01:48 +04:00
# define KBC_CYCLE_MS 32
2011-01-20 10:38:47 +03:00
/* KBC Registers */
/* KBC Control Register */
# define KBC_CONTROL_0 0x0
# define KBC_FIFO_TH_CNT_SHIFT(cnt) (cnt << 14)
# define KBC_DEBOUNCE_CNT_SHIFT(cnt) (cnt << 4)
# define KBC_CONTROL_FIFO_CNT_INT_EN (1 << 3)
2012-01-23 11:27:54 +04:00
# define KBC_CONTROL_KEYPRESS_INT_EN (1 << 1)
2011-01-20 10:38:47 +03:00
# define KBC_CONTROL_KBC_EN (1 << 0)
/* KBC Interrupt Register */
# define KBC_INT_0 0x4
# define KBC_INT_FIFO_CNT_INT_STATUS (1 << 2)
2011-12-30 07:27:44 +04:00
# define KBC_INT_KEYPRESS_INT_STATUS (1 << 0)
2011-01-20 10:38:47 +03:00
# define KBC_ROW_CFG0_0 0x8
# define KBC_COL_CFG0_0 0x18
2011-09-09 02:34:11 +04:00
# define KBC_TO_CNT_0 0x24
2011-01-20 10:38:47 +03:00
# define KBC_INIT_DLY_0 0x28
# define KBC_RPT_DLY_0 0x2c
# define KBC_KP_ENT0_0 0x30
# define KBC_KP_ENT1_0 0x34
# define KBC_ROW0_MASK_0 0x38
# define KBC_ROW_SHIFT 3
2013-02-16 05:04:12 +04:00
enum tegra_pin_type {
PIN_CFG_IGNORE ,
PIN_CFG_COL ,
PIN_CFG_ROW ,
} ;
2013-03-31 11:41:12 +04:00
/* Tegra KBC hw support */
struct tegra_kbc_hw_support {
int max_rows ;
int max_columns ;
} ;
2013-02-16 05:04:12 +04:00
struct tegra_kbc_pin_cfg {
enum tegra_pin_type type ;
unsigned char num ;
} ;
2011-01-20 10:38:47 +03:00
struct tegra_kbc {
2013-02-16 05:04:12 +04:00
struct device * dev ;
unsigned int debounce_cnt ;
unsigned int repeat_cnt ;
struct tegra_kbc_pin_cfg pin_cfg [ KBC_MAX_GPIO ] ;
const struct matrix_keymap_data * keymap_data ;
bool wakeup ;
2011-01-20 10:38:47 +03:00
void __iomem * mmio ;
struct input_dev * idev ;
2013-02-16 05:04:12 +04:00
int irq ;
2011-01-20 10:38:47 +03:00
spinlock_t lock ;
unsigned int repoll_dly ;
unsigned long cp_dly_jiffies ;
2011-09-09 02:34:11 +04:00
unsigned int cp_to_wkup_dly ;
2011-02-18 19:38:02 +03:00
bool use_fn_map ;
2011-04-28 10:18:15 +04:00
bool use_ghost_filter ;
2011-12-30 07:27:44 +04:00
bool keypress_caused_wake ;
2011-02-18 19:38:02 +03:00
unsigned short keycode [ KBC_MAX_KEY * 2 ] ;
2011-01-20 10:38:47 +03:00
unsigned short current_keys [ KBC_MAX_KPENT ] ;
unsigned int num_pressed_keys ;
2011-12-30 07:27:44 +04:00
u32 wakeup_key ;
2011-01-20 10:38:47 +03:00
struct timer_list timer ;
struct clk * clk ;
2013-11-07 03:48:16 +04:00
struct reset_control * rst ;
2013-03-31 11:41:12 +04:00
const struct tegra_kbc_hw_support * hw_support ;
int max_keys ;
int num_rows_and_columns ;
2011-01-20 10:38:47 +03:00
} ;
static void tegra_kbc_report_released_keys ( struct input_dev * input ,
unsigned short old_keycodes [ ] ,
unsigned int old_num_keys ,
unsigned short new_keycodes [ ] ,
unsigned int new_num_keys )
{
unsigned int i , j ;
for ( i = 0 ; i < old_num_keys ; i + + ) {
for ( j = 0 ; j < new_num_keys ; j + + )
if ( old_keycodes [ i ] = = new_keycodes [ j ] )
break ;
if ( j = = new_num_keys )
input_report_key ( input , old_keycodes [ i ] , 0 ) ;
}
}
static void tegra_kbc_report_pressed_keys ( struct input_dev * input ,
unsigned char scancodes [ ] ,
unsigned short keycodes [ ] ,
unsigned int num_pressed_keys )
{
unsigned int i ;
for ( i = 0 ; i < num_pressed_keys ; i + + ) {
input_event ( input , EV_MSC , MSC_SCAN , scancodes [ i ] ) ;
input_report_key ( input , keycodes [ i ] , 1 ) ;
}
}
static void tegra_kbc_report_keys ( struct tegra_kbc * kbc )
{
unsigned char scancodes [ KBC_MAX_KPENT ] ;
unsigned short keycodes [ KBC_MAX_KPENT ] ;
u32 val = 0 ;
unsigned int i ;
unsigned int num_down = 0 ;
2011-02-18 19:38:02 +03:00
bool fn_keypress = false ;
2011-04-28 10:18:15 +04:00
bool key_in_same_row = false ;
bool key_in_same_col = false ;
2011-01-20 10:38:47 +03:00
for ( i = 0 ; i < KBC_MAX_KPENT ; i + + ) {
if ( ( i % 4 ) = = 0 )
val = readl ( kbc - > mmio + KBC_KP_ENT0_0 + i ) ;
if ( val & 0x80 ) {
unsigned int col = val & 0x07 ;
unsigned int row = ( val > > 3 ) & 0x0f ;
unsigned char scancode =
MATRIX_SCAN_CODE ( row , col , KBC_ROW_SHIFT ) ;
scancodes [ num_down ] = scancode ;
2011-02-18 19:38:02 +03:00
keycodes [ num_down ] = kbc - > keycode [ scancode ] ;
/* If driver uses Fn map, do not report the Fn key. */
if ( ( keycodes [ num_down ] = = KEY_FN ) & & kbc - > use_fn_map )
fn_keypress = true ;
else
num_down + + ;
2011-01-20 10:38:47 +03:00
}
val > > = 8 ;
}
2011-02-18 19:38:02 +03:00
2011-04-28 10:18:15 +04:00
/*
* Matrix keyboard designs are prone to keyboard ghosting .
* Ghosting occurs if there are 3 keys such that -
* any 2 of the 3 keys share a row , and any 2 of them share a column .
* If so ignore the key presses for this iteration .
*/
2011-09-09 20:24:20 +04:00
if ( kbc - > use_ghost_filter & & num_down > = 3 ) {
2011-04-28 10:18:15 +04:00
for ( i = 0 ; i < num_down ; i + + ) {
unsigned int j ;
u8 curr_col = scancodes [ i ] & 0x07 ;
u8 curr_row = scancodes [ i ] > > KBC_ROW_SHIFT ;
/*
* Find 2 keys such that one key is in the same row
* and the other is in the same column as the i - th key .
*/
for ( j = i + 1 ; j < num_down ; j + + ) {
u8 col = scancodes [ j ] & 0x07 ;
u8 row = scancodes [ j ] > > KBC_ROW_SHIFT ;
if ( col = = curr_col )
key_in_same_col = true ;
if ( row = = curr_row )
key_in_same_row = true ;
}
}
}
2011-02-18 19:38:02 +03:00
/*
* If the platform uses Fn keymaps , translate keys on a Fn keypress .
2013-03-31 11:41:12 +04:00
* Function keycodes are max_keys apart from the plain keycodes .
2011-02-18 19:38:02 +03:00
*/
if ( fn_keypress ) {
for ( i = 0 ; i < num_down ; i + + ) {
2013-03-31 11:41:12 +04:00
scancodes [ i ] + = kbc - > max_keys ;
2011-02-18 19:38:02 +03:00
keycodes [ i ] = kbc - > keycode [ scancodes [ i ] ] ;
}
}
2011-04-28 10:18:15 +04:00
/* Ignore the key presses for this iteration? */
if ( key_in_same_col & & key_in_same_row )
return ;
2011-01-20 10:38:47 +03:00
tegra_kbc_report_released_keys ( kbc - > idev ,
kbc - > current_keys , kbc - > num_pressed_keys ,
keycodes , num_down ) ;
tegra_kbc_report_pressed_keys ( kbc - > idev , scancodes , keycodes , num_down ) ;
input_sync ( kbc - > idev ) ;
memcpy ( kbc - > current_keys , keycodes , sizeof ( kbc - > current_keys ) ) ;
kbc - > num_pressed_keys = num_down ;
}
2011-09-09 02:34:11 +04:00
static void tegra_kbc_set_fifo_interrupt ( struct tegra_kbc * kbc , bool enable )
{
u32 val ;
val = readl ( kbc - > mmio + KBC_CONTROL_0 ) ;
if ( enable )
val | = KBC_CONTROL_FIFO_CNT_INT_EN ;
else
val & = ~ KBC_CONTROL_FIFO_CNT_INT_EN ;
writel ( val , kbc - > mmio + KBC_CONTROL_0 ) ;
}
2017-10-24 19:40:57 +03:00
static void tegra_kbc_keypress_timer ( struct timer_list * t )
2011-01-20 10:38:47 +03:00
{
2017-10-24 19:40:57 +03:00
struct tegra_kbc * kbc = from_timer ( kbc , t , timer ) ;
2011-01-20 10:38:47 +03:00
unsigned long flags ;
u32 val ;
unsigned int i ;
2011-09-09 20:24:20 +04:00
spin_lock_irqsave ( & kbc - > lock , flags ) ;
2011-01-20 10:38:47 +03:00
val = ( readl ( kbc - > mmio + KBC_INT_0 ) > > 4 ) & 0xf ;
if ( val ) {
unsigned long dly ;
tegra_kbc_report_keys ( kbc ) ;
/*
* If more than one keys are pressed we need not wait
* for the repoll delay .
*/
dly = ( val = = 1 ) ? kbc - > repoll_dly : 1 ;
mod_timer ( & kbc - > timer , jiffies + msecs_to_jiffies ( dly ) ) ;
} else {
/* Release any pressed keys and exit the polling loop */
for ( i = 0 ; i < kbc - > num_pressed_keys ; i + + )
input_report_key ( kbc - > idev , kbc - > current_keys [ i ] , 0 ) ;
input_sync ( kbc - > idev ) ;
kbc - > num_pressed_keys = 0 ;
/* All keys are released so enable the keypress interrupt */
2011-09-09 02:34:11 +04:00
tegra_kbc_set_fifo_interrupt ( kbc , true ) ;
2011-01-20 10:38:47 +03:00
}
2011-09-09 20:24:20 +04:00
spin_unlock_irqrestore ( & kbc - > lock , flags ) ;
2011-01-20 10:38:47 +03:00
}
static irqreturn_t tegra_kbc_isr ( int irq , void * args )
{
struct tegra_kbc * kbc = args ;
2011-09-09 20:24:20 +04:00
unsigned long flags ;
2011-09-09 02:34:11 +04:00
u32 val ;
2011-01-20 10:38:47 +03:00
2011-09-09 20:24:20 +04:00
spin_lock_irqsave ( & kbc - > lock , flags ) ;
2011-01-20 10:38:47 +03:00
/*
* Quickly bail out & reenable interrupts if the fifo threshold
* count interrupt wasn ' t the interrupt source
*/
val = readl ( kbc - > mmio + KBC_INT_0 ) ;
writel ( val , kbc - > mmio + KBC_INT_0 ) ;
if ( val & KBC_INT_FIFO_CNT_INT_STATUS ) {
/*
2011-09-09 20:24:20 +04:00
* Until all keys are released , defer further processing to
* the polling loop in tegra_kbc_keypress_timer .
2011-01-20 10:38:47 +03:00
*/
2011-09-09 20:24:20 +04:00
tegra_kbc_set_fifo_interrupt ( kbc , false ) ;
2011-01-20 10:38:47 +03:00
mod_timer ( & kbc - > timer , jiffies + kbc - > cp_dly_jiffies ) ;
2011-12-30 07:27:44 +04:00
} else if ( val & KBC_INT_KEYPRESS_INT_STATUS ) {
/* We can be here only through system resume path */
kbc - > keypress_caused_wake = true ;
2011-01-20 10:38:47 +03:00
}
2011-09-09 20:24:20 +04:00
spin_unlock_irqrestore ( & kbc - > lock , flags ) ;
2011-01-20 10:38:47 +03:00
return IRQ_HANDLED ;
}
static void tegra_kbc_setup_wakekeys ( struct tegra_kbc * kbc , bool filter )
{
int i ;
unsigned int rst_val ;
2011-05-12 01:24:10 +04:00
/* Either mask all keys or none. */
2013-02-16 05:04:12 +04:00
rst_val = ( filter & & ! kbc - > wakeup ) ? ~ 0 : 0 ;
2011-01-20 10:38:47 +03:00
2013-03-31 11:41:12 +04:00
for ( i = 0 ; i < kbc - > hw_support - > max_rows ; i + + )
2011-01-20 10:38:47 +03:00
writel ( rst_val , kbc - > mmio + KBC_ROW0_MASK_0 + i * 4 ) ;
}
static void tegra_kbc_config_pins ( struct tegra_kbc * kbc )
{
int i ;
for ( i = 0 ; i < KBC_MAX_GPIO ; i + + ) {
u32 r_shft = 5 * ( i % 6 ) ;
u32 c_shft = 4 * ( i % 8 ) ;
2011-01-29 09:05:14 +03:00
u32 r_mask = 0x1f < < r_shft ;
u32 c_mask = 0x0f < < c_shft ;
2011-01-20 10:38:47 +03:00
u32 r_offs = ( i / 6 ) * 4 + KBC_ROW_CFG0_0 ;
u32 c_offs = ( i / 8 ) * 4 + KBC_COL_CFG0_0 ;
u32 row_cfg = readl ( kbc - > mmio + r_offs ) ;
u32 col_cfg = readl ( kbc - > mmio + c_offs ) ;
row_cfg & = ~ r_mask ;
col_cfg & = ~ c_mask ;
2013-02-16 05:04:12 +04:00
switch ( kbc - > pin_cfg [ i ] . type ) {
2012-02-03 12:27:30 +04:00
case PIN_CFG_ROW :
2013-02-16 05:04:12 +04:00
row_cfg | = ( ( kbc - > pin_cfg [ i ] . num < < 1 ) | 1 ) < < r_shft ;
2012-02-03 12:27:30 +04:00
break ;
case PIN_CFG_COL :
2013-02-16 05:04:12 +04:00
col_cfg | = ( ( kbc - > pin_cfg [ i ] . num < < 1 ) | 1 ) < < c_shft ;
2012-02-03 12:27:30 +04:00
break ;
case PIN_CFG_IGNORE :
break ;
}
2011-01-20 10:38:47 +03:00
writel ( row_cfg , kbc - > mmio + r_offs ) ;
writel ( col_cfg , kbc - > mmio + c_offs ) ;
}
}
static int tegra_kbc_start ( struct tegra_kbc * kbc )
{
unsigned int debounce_cnt ;
u32 val = 0 ;
2017-08-31 21:35:29 +03:00
int ret ;
2011-01-20 10:38:47 +03:00
2017-08-31 21:35:29 +03:00
ret = clk_prepare_enable ( kbc - > clk ) ;
if ( ret )
return ret ;
2011-01-20 10:38:47 +03:00
/* Reset the KBC controller to clear all previous status.*/
2013-11-07 03:48:16 +04:00
reset_control_assert ( kbc - > rst ) ;
2011-01-20 10:38:47 +03:00
udelay ( 100 ) ;
2016-08-22 23:25:56 +03:00
reset_control_deassert ( kbc - > rst ) ;
2011-01-20 10:38:47 +03:00
udelay ( 100 ) ;
tegra_kbc_config_pins ( kbc ) ;
tegra_kbc_setup_wakekeys ( kbc , false ) ;
2013-02-16 05:04:12 +04:00
writel ( kbc - > repeat_cnt , kbc - > mmio + KBC_RPT_DLY_0 ) ;
2011-01-20 10:38:47 +03:00
/* Keyboard debounce count is maximum of 12 bits. */
2013-02-16 05:04:12 +04:00
debounce_cnt = min ( kbc - > debounce_cnt , KBC_MAX_DEBOUNCE_CNT ) ;
2011-01-20 10:38:47 +03:00
val = KBC_DEBOUNCE_CNT_SHIFT ( debounce_cnt ) ;
val | = KBC_FIFO_TH_CNT_SHIFT ( 1 ) ; /* set fifo interrupt threshold to 1 */
val | = KBC_CONTROL_FIFO_CNT_INT_EN ; /* interrupt on FIFO threshold */
val | = KBC_CONTROL_KBC_EN ; /* enable */
writel ( val , kbc - > mmio + KBC_CONTROL_0 ) ;
/*
* Compute the delay ( ns ) from interrupt mode to continuous polling
* mode so the timer routine is scheduled appropriately .
*/
val = readl ( kbc - > mmio + KBC_INIT_DLY_0 ) ;
kbc - > cp_dly_jiffies = usecs_to_jiffies ( ( val & 0xfffff ) * 32 ) ;
kbc - > num_pressed_keys = 0 ;
/*
* Atomically clear out any remaining entries in the key FIFO
* and enable keyboard interrupts .
*/
while ( 1 ) {
val = readl ( kbc - > mmio + KBC_INT_0 ) ;
val > > = 4 ;
if ( ! val )
break ;
val = readl ( kbc - > mmio + KBC_KP_ENT0_0 ) ;
val = readl ( kbc - > mmio + KBC_KP_ENT1_0 ) ;
}
writel ( 0x7 , kbc - > mmio + KBC_INT_0 ) ;
enable_irq ( kbc - > irq ) ;
return 0 ;
}
static void tegra_kbc_stop ( struct tegra_kbc * kbc )
{
unsigned long flags ;
u32 val ;
spin_lock_irqsave ( & kbc - > lock , flags ) ;
val = readl ( kbc - > mmio + KBC_CONTROL_0 ) ;
val & = ~ 1 ;
writel ( val , kbc - > mmio + KBC_CONTROL_0 ) ;
spin_unlock_irqrestore ( & kbc - > lock , flags ) ;
disable_irq ( kbc - > irq ) ;
del_timer_sync ( & kbc - > timer ) ;
2012-06-05 08:29:39 +04:00
clk_disable_unprepare ( kbc - > clk ) ;
2011-01-20 10:38:47 +03:00
}
static int tegra_kbc_open ( struct input_dev * dev )
{
struct tegra_kbc * kbc = input_get_drvdata ( dev ) ;
return tegra_kbc_start ( kbc ) ;
}
static void tegra_kbc_close ( struct input_dev * dev )
{
struct tegra_kbc * kbc = input_get_drvdata ( dev ) ;
return tegra_kbc_stop ( kbc ) ;
}
2013-02-16 05:04:12 +04:00
static bool tegra_kbc_check_pin_cfg ( const struct tegra_kbc * kbc ,
unsigned int * num_rows )
2011-01-20 10:38:47 +03:00
{
int i ;
* num_rows = 0 ;
for ( i = 0 ; i < KBC_MAX_GPIO ; i + + ) {
2013-02-16 05:04:12 +04:00
const struct tegra_kbc_pin_cfg * pin_cfg = & kbc - > pin_cfg [ i ] ;
2011-01-20 10:38:47 +03:00
2012-02-03 12:27:30 +04:00
switch ( pin_cfg - > type ) {
case PIN_CFG_ROW :
2013-03-31 11:41:12 +04:00
if ( pin_cfg - > num > = kbc - > hw_support - > max_rows ) {
2013-02-16 05:04:12 +04:00
dev_err ( kbc - > dev ,
2011-01-20 10:38:47 +03:00
" pin_cfg[%d]: invalid row number %d \n " ,
i , pin_cfg - > num ) ;
return false ;
}
( * num_rows ) + + ;
2012-02-03 12:27:30 +04:00
break ;
case PIN_CFG_COL :
2013-03-31 11:41:12 +04:00
if ( pin_cfg - > num > = kbc - > hw_support - > max_columns ) {
2013-02-16 05:04:12 +04:00
dev_err ( kbc - > dev ,
2011-01-20 10:38:47 +03:00
" pin_cfg[%d]: invalid column number %d \n " ,
i , pin_cfg - > num ) ;
return false ;
}
2012-02-03 12:27:30 +04:00
break ;
case PIN_CFG_IGNORE :
break ;
default :
2013-02-16 05:04:12 +04:00
dev_err ( kbc - > dev ,
2012-02-03 12:27:30 +04:00
" pin_cfg[%d]: invalid entry type %d \n " ,
pin_cfg - > type , pin_cfg - > num ) ;
return false ;
2011-01-20 10:38:47 +03:00
}
}
return true ;
}
2013-02-16 05:04:12 +04:00
static int tegra_kbc_parse_dt ( struct tegra_kbc * kbc )
2011-12-29 21:58:16 +04:00
{
2013-02-16 05:04:12 +04:00
struct device_node * np = kbc - > dev - > of_node ;
2012-03-14 08:36:29 +04:00
u32 prop ;
int i ;
2013-01-07 06:32:22 +04:00
u32 num_rows = 0 ;
u32 num_cols = 0 ;
u32 cols_cfg [ KBC_MAX_GPIO ] ;
u32 rows_cfg [ KBC_MAX_GPIO ] ;
int proplen ;
int ret ;
2012-03-14 08:36:29 +04:00
if ( ! of_property_read_u32 ( np , " nvidia,debounce-delay-ms " , & prop ) )
2013-02-16 05:04:12 +04:00
kbc - > debounce_cnt = prop ;
2011-12-29 21:58:16 +04:00
2012-03-14 08:36:29 +04:00
if ( ! of_property_read_u32 ( np , " nvidia,repeat-delay-ms " , & prop ) )
2013-02-16 05:04:12 +04:00
kbc - > repeat_cnt = prop ;
2011-12-29 21:58:16 +04:00
2012-03-14 08:36:29 +04:00
if ( of_find_property ( np , " nvidia,needs-ghost-filter " , NULL ) )
2013-02-16 05:04:12 +04:00
kbc - > use_ghost_filter = true ;
2011-12-29 21:58:16 +04:00
2015-10-23 09:38:40 +03:00
if ( of_property_read_bool ( np , " wakeup-source " ) | |
of_property_read_bool ( np , " nvidia,wakeup-source " ) ) /* legacy */
2013-02-16 05:04:12 +04:00
kbc - > wakeup = true ;
2011-12-29 21:58:16 +04:00
2013-01-07 06:32:22 +04:00
if ( ! of_get_property ( np , " nvidia,kbc-row-pins " , & proplen ) ) {
2013-02-16 05:04:12 +04:00
dev_err ( kbc - > dev , " property nvidia,kbc-row-pins not found \n " ) ;
return - ENOENT ;
2013-01-07 06:32:22 +04:00
}
num_rows = proplen / sizeof ( u32 ) ;
if ( ! of_get_property ( np , " nvidia,kbc-col-pins " , & proplen ) ) {
2013-02-16 05:04:12 +04:00
dev_err ( kbc - > dev , " property nvidia,kbc-col-pins not found \n " ) ;
return - ENOENT ;
2013-01-07 06:32:22 +04:00
}
num_cols = proplen / sizeof ( u32 ) ;
2013-03-31 11:41:12 +04:00
if ( num_rows > kbc - > hw_support - > max_rows ) {
dev_err ( kbc - > dev ,
" Number of rows is more than supported by hardware \n " ) ;
return - EINVAL ;
}
if ( num_cols > kbc - > hw_support - > max_columns ) {
dev_err ( kbc - > dev ,
" Number of cols is more than supported by hardware \n " ) ;
return - EINVAL ;
}
2013-01-07 06:32:22 +04:00
if ( ! of_get_property ( np , " linux,keymap " , & proplen ) ) {
2013-02-16 05:04:12 +04:00
dev_err ( kbc - > dev , " property linux,keymap not found \n " ) ;
return - ENOENT ;
2011-12-29 21:58:16 +04:00
}
2013-01-07 06:32:22 +04:00
if ( ! num_rows | | ! num_cols | | ( ( num_rows + num_cols ) > KBC_MAX_GPIO ) ) {
2013-02-16 05:04:12 +04:00
dev_err ( kbc - > dev ,
2016-06-23 19:55:48 +03:00
" keypad rows/columns not properly specified \n " ) ;
2013-02-16 05:04:12 +04:00
return - EINVAL ;
2013-01-07 06:32:22 +04:00
}
/* Set all pins as non-configured */
2013-03-31 11:41:12 +04:00
for ( i = 0 ; i < kbc - > num_rows_and_columns ; i + + )
2013-02-16 05:04:12 +04:00
kbc - > pin_cfg [ i ] . type = PIN_CFG_IGNORE ;
2013-01-07 06:32:22 +04:00
ret = of_property_read_u32_array ( np , " nvidia,kbc-row-pins " ,
rows_cfg , num_rows ) ;
if ( ret < 0 ) {
2013-02-16 05:04:12 +04:00
dev_err ( kbc - > dev , " Rows configurations are not proper \n " ) ;
return - EINVAL ;
2013-01-07 06:32:22 +04:00
}
ret = of_property_read_u32_array ( np , " nvidia,kbc-col-pins " ,
cols_cfg , num_cols ) ;
if ( ret < 0 ) {
2013-02-16 05:04:12 +04:00
dev_err ( kbc - > dev , " Cols configurations are not proper \n " ) ;
return - EINVAL ;
2013-01-07 06:32:22 +04:00
}
for ( i = 0 ; i < num_rows ; i + + ) {
2013-02-16 05:04:12 +04:00
kbc - > pin_cfg [ rows_cfg [ i ] ] . type = PIN_CFG_ROW ;
kbc - > pin_cfg [ rows_cfg [ i ] ] . num = i ;
2013-01-07 06:32:22 +04:00
}
for ( i = 0 ; i < num_cols ; i + + ) {
2013-02-16 05:04:12 +04:00
kbc - > pin_cfg [ cols_cfg [ i ] ] . type = PIN_CFG_COL ;
kbc - > pin_cfg [ cols_cfg [ i ] ] . num = i ;
2011-12-29 21:58:16 +04:00
}
2013-02-16 05:04:12 +04:00
return 0 ;
2011-12-29 21:58:16 +04:00
}
2013-03-31 11:41:12 +04:00
static const struct tegra_kbc_hw_support tegra20_kbc_hw_support = {
. max_rows = 16 ,
. max_columns = 8 ,
} ;
static const struct tegra_kbc_hw_support tegra11_kbc_hw_support = {
. max_rows = 11 ,
. max_columns = 8 ,
} ;
static const struct of_device_id tegra_kbc_of_match [ ] = {
{ . compatible = " nvidia,tegra114-kbc " , . data = & tegra11_kbc_hw_support } ,
{ . compatible = " nvidia,tegra30-kbc " , . data = & tegra20_kbc_hw_support } ,
{ . compatible = " nvidia,tegra20-kbc " , . data = & tegra20_kbc_hw_support } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , tegra_kbc_of_match ) ;
2012-11-24 09:38:25 +04:00
static int tegra_kbc_probe ( struct platform_device * pdev )
2011-01-20 10:38:47 +03:00
{
struct tegra_kbc * kbc ;
struct resource * res ;
int err ;
int num_rows = 0 ;
unsigned int debounce_cnt ;
unsigned int scan_time_rows ;
2013-03-31 11:41:12 +04:00
unsigned int keymap_rows ;
const struct of_device_id * match ;
2013-10-06 11:50:31 +04:00
match = of_match_device ( tegra_kbc_of_match , & pdev - > dev ) ;
2011-01-20 10:38:47 +03:00
2013-02-16 05:04:12 +04:00
kbc = devm_kzalloc ( & pdev - > dev , sizeof ( * kbc ) , GFP_KERNEL ) ;
if ( ! kbc ) {
dev_err ( & pdev - > dev , " failed to alloc memory for kbc \n " ) ;
return - ENOMEM ;
}
kbc - > dev = & pdev - > dev ;
2013-03-31 11:41:12 +04:00
kbc - > hw_support = match - > data ;
kbc - > max_keys = kbc - > hw_support - > max_rows *
kbc - > hw_support - > max_columns ;
kbc - > num_rows_and_columns = kbc - > hw_support - > max_rows +
kbc - > hw_support - > max_columns ;
keymap_rows = kbc - > max_keys ;
2013-02-16 05:04:12 +04:00
spin_lock_init ( & kbc - > lock ) ;
2011-01-20 10:38:47 +03:00
2013-02-16 05:04:12 +04:00
err = tegra_kbc_parse_dt ( kbc ) ;
if ( err )
return err ;
2011-12-29 21:58:16 +04:00
2013-02-16 05:04:12 +04:00
if ( ! tegra_kbc_check_pin_cfg ( kbc , & num_rows ) )
2013-01-07 06:31:20 +04:00
return - EINVAL ;
2013-02-16 05:04:12 +04:00
kbc - > irq = platform_get_irq ( pdev , 0 ) ;
2019-08-14 20:46:38 +03:00
if ( kbc - > irq < 0 )
2013-01-07 06:31:20 +04:00
return - ENXIO ;
2011-01-20 10:38:47 +03:00
2013-02-16 05:04:12 +04:00
kbc - > idev = devm_input_allocate_device ( & pdev - > dev ) ;
if ( ! kbc - > idev ) {
2013-01-07 06:31:20 +04:00
dev_err ( & pdev - > dev , " failed to allocate input device \n " ) ;
return - ENOMEM ;
2011-01-20 10:38:47 +03:00
}
2017-10-24 19:40:57 +03:00
timer_setup ( & kbc - > timer , tegra_kbc_keypress_timer , 0 ) ;
2011-01-20 10:38:47 +03:00
2013-08-15 11:07:43 +04:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2013-03-18 08:30:05 +04:00
kbc - > mmio = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( kbc - > mmio ) )
return PTR_ERR ( kbc - > mmio ) ;
2011-01-20 10:38:47 +03:00
2013-01-07 06:31:20 +04:00
kbc - > clk = devm_clk_get ( & pdev - > dev , NULL ) ;
2011-01-20 10:38:47 +03:00
if ( IS_ERR ( kbc - > clk ) ) {
dev_err ( & pdev - > dev , " failed to get keyboard clock \n " ) ;
2013-01-07 06:31:20 +04:00
return PTR_ERR ( kbc - > clk ) ;
2011-01-20 10:38:47 +03:00
}
2013-11-07 03:48:16 +04:00
kbc - > rst = devm_reset_control_get ( & pdev - > dev , " kbc " ) ;
if ( IS_ERR ( kbc - > rst ) ) {
dev_err ( & pdev - > dev , " failed to get keyboard reset \n " ) ;
return PTR_ERR ( kbc - > rst ) ;
}
2011-01-20 10:38:47 +03:00
/*
* The time delay between two consecutive reads of the FIFO is
* the sum of the repeat time and the time taken for scanning
* the rows . There is an additional delay before the row scanning
* starts . The repoll delay is computed in milliseconds .
*/
2013-02-16 05:04:12 +04:00
debounce_cnt = min ( kbc - > debounce_cnt , KBC_MAX_DEBOUNCE_CNT ) ;
2011-01-20 10:38:47 +03:00
scan_time_rows = ( KBC_ROW_SCAN_TIME + debounce_cnt ) * num_rows ;
2013-02-16 05:04:12 +04:00
kbc - > repoll_dly = KBC_ROW_SCAN_DLY + scan_time_rows + kbc - > repeat_cnt ;
2011-07-30 23:01:48 +04:00
kbc - > repoll_dly = DIV_ROUND_UP ( kbc - > repoll_dly , KBC_CYCLE_MS ) ;
2011-01-20 10:38:47 +03:00
2013-02-16 05:04:12 +04:00
kbc - > idev - > name = pdev - > name ;
kbc - > idev - > id . bustype = BUS_HOST ;
kbc - > idev - > dev . parent = & pdev - > dev ;
kbc - > idev - > open = tegra_kbc_open ;
kbc - > idev - > close = tegra_kbc_close ;
2011-01-20 10:38:47 +03:00
2013-02-16 05:04:12 +04:00
if ( kbc - > keymap_data & & kbc - > use_fn_map )
2013-01-07 06:34:48 +04:00
keymap_rows * = 2 ;
2013-02-16 05:04:12 +04:00
err = matrix_keypad_build_keymap ( kbc - > keymap_data , NULL ,
2013-03-31 11:41:12 +04:00
keymap_rows ,
kbc - > hw_support - > max_columns ,
2013-02-16 05:04:12 +04:00
kbc - > keycode , kbc - > idev ) ;
2012-05-11 09:37:08 +04:00
if ( err ) {
2012-05-11 09:37:15 +04:00
dev_err ( & pdev - > dev , " failed to setup keymap \n " ) ;
2013-01-07 06:31:20 +04:00
return err ;
2012-05-11 09:37:08 +04:00
}
2013-02-16 05:04:12 +04:00
__set_bit ( EV_REP , kbc - > idev - > evbit ) ;
input_set_capability ( kbc - > idev , EV_MSC , MSC_SCAN ) ;
2012-05-11 09:37:08 +04:00
2013-02-16 05:04:12 +04:00
input_set_drvdata ( kbc - > idev , kbc ) ;
2011-01-20 10:38:47 +03:00
2013-01-07 06:31:20 +04:00
err = devm_request_irq ( & pdev - > dev , kbc - > irq , tegra_kbc_isr ,
2021-03-26 00:43:18 +03:00
IRQF_TRIGGER_HIGH | IRQF_NO_AUTOEN ,
pdev - > name , kbc ) ;
2011-01-20 10:38:47 +03:00
if ( err ) {
dev_err ( & pdev - > dev , " failed to request keyboard IRQ \n " ) ;
2013-01-07 06:31:20 +04:00
return err ;
2011-01-20 10:38:47 +03:00
}
err = input_register_device ( kbc - > idev ) ;
if ( err ) {
dev_err ( & pdev - > dev , " failed to register input device \n " ) ;
2013-01-07 06:31:20 +04:00
return err ;
2011-01-20 10:38:47 +03:00
}
platform_set_drvdata ( pdev , kbc ) ;
2013-02-16 05:04:12 +04:00
device_init_wakeup ( & pdev - > dev , kbc - > wakeup ) ;
2011-01-20 10:38:47 +03:00
return 0 ;
}
# ifdef CONFIG_PM_SLEEP
2013-01-07 06:30:21 +04:00
static void tegra_kbc_set_keypress_interrupt ( struct tegra_kbc * kbc , bool enable )
{
u32 val ;
val = readl ( kbc - > mmio + KBC_CONTROL_0 ) ;
if ( enable )
val | = KBC_CONTROL_KEYPRESS_INT_EN ;
else
val & = ~ KBC_CONTROL_KEYPRESS_INT_EN ;
writel ( val , kbc - > mmio + KBC_CONTROL_0 ) ;
}
2011-01-20 10:38:47 +03:00
static int tegra_kbc_suspend ( struct device * dev )
{
struct platform_device * pdev = to_platform_device ( dev ) ;
struct tegra_kbc * kbc = platform_get_drvdata ( pdev ) ;
2011-09-09 02:34:11 +04:00
mutex_lock ( & kbc - > idev - > mutex ) ;
2011-01-20 10:38:47 +03:00
if ( device_may_wakeup ( & pdev - > dev ) ) {
2011-09-09 02:34:11 +04:00
disable_irq ( kbc - > irq ) ;
del_timer_sync ( & kbc - > timer ) ;
tegra_kbc_set_fifo_interrupt ( kbc , false ) ;
2011-01-20 10:38:47 +03:00
/* Forcefully clear the interrupt status */
writel ( 0x7 , kbc - > mmio + KBC_INT_0 ) ;
2011-09-09 02:34:11 +04:00
/*
* Store the previous resident time of continuous polling mode .
* Force the keyboard into interrupt mode .
*/
kbc - > cp_to_wkup_dly = readl ( kbc - > mmio + KBC_TO_CNT_0 ) ;
writel ( 0 , kbc - > mmio + KBC_TO_CNT_0 ) ;
tegra_kbc_setup_wakekeys ( kbc , true ) ;
2011-01-20 10:38:47 +03:00
msleep ( 30 ) ;
2011-09-09 02:34:11 +04:00
2011-12-30 07:27:44 +04:00
kbc - > keypress_caused_wake = false ;
2012-01-23 11:27:54 +04:00
/* Enable keypress interrupt before going into suspend. */
tegra_kbc_set_keypress_interrupt ( kbc , true ) ;
2011-12-30 07:27:44 +04:00
enable_irq ( kbc - > irq ) ;
2011-09-09 02:34:11 +04:00
enable_irq_wake ( kbc - > irq ) ;
2011-01-20 10:38:47 +03:00
} else {
2020-10-05 07:16:07 +03:00
if ( input_device_enabled ( kbc - > idev ) )
2011-01-20 10:38:47 +03:00
tegra_kbc_stop ( kbc ) ;
}
2011-09-09 02:34:11 +04:00
mutex_unlock ( & kbc - > idev - > mutex ) ;
2011-01-20 10:38:47 +03:00
return 0 ;
}
static int tegra_kbc_resume ( struct device * dev )
{
struct platform_device * pdev = to_platform_device ( dev ) ;
struct tegra_kbc * kbc = platform_get_drvdata ( pdev ) ;
int err = 0 ;
2011-09-09 02:34:11 +04:00
mutex_lock ( & kbc - > idev - > mutex ) ;
2011-01-20 10:38:47 +03:00
if ( device_may_wakeup ( & pdev - > dev ) ) {
disable_irq_wake ( kbc - > irq ) ;
tegra_kbc_setup_wakekeys ( kbc , false ) ;
2012-01-23 11:27:54 +04:00
/* We will use fifo interrupts for key detection. */
tegra_kbc_set_keypress_interrupt ( kbc , false ) ;
2011-09-09 02:34:11 +04:00
/* Restore the resident time of continuous polling mode. */
writel ( kbc - > cp_to_wkup_dly , kbc - > mmio + KBC_TO_CNT_0 ) ;
tegra_kbc_set_fifo_interrupt ( kbc , true ) ;
2011-12-30 07:27:44 +04:00
if ( kbc - > keypress_caused_wake & & kbc - > wakeup_key ) {
/*
* We can ' t report events directly from the ISR
* because timekeeping is stopped when processing
* wakeup request and we get a nasty warning when
* we try to call do_gettimeofday ( ) in evdev
* handler .
*/
input_report_key ( kbc - > idev , kbc - > wakeup_key , 1 ) ;
input_sync ( kbc - > idev ) ;
input_report_key ( kbc - > idev , kbc - > wakeup_key , 0 ) ;
input_sync ( kbc - > idev ) ;
}
2011-01-20 10:38:47 +03:00
} else {
2020-10-05 07:16:07 +03:00
if ( input_device_enabled ( kbc - > idev ) )
2011-01-20 10:38:47 +03:00
err = tegra_kbc_start ( kbc ) ;
}
2011-09-09 02:34:11 +04:00
mutex_unlock ( & kbc - > idev - > mutex ) ;
2011-01-20 10:38:47 +03:00
return err ;
}
# endif
static SIMPLE_DEV_PM_OPS ( tegra_kbc_pm_ops , tegra_kbc_suspend , tegra_kbc_resume ) ;
static struct platform_driver tegra_kbc_driver = {
. probe = tegra_kbc_probe ,
. driver = {
. name = " tegra-kbc " ,
. pm = & tegra_kbc_pm_ops ,
2011-12-29 21:58:16 +04:00
. of_match_table = tegra_kbc_of_match ,
2011-01-20 10:38:47 +03:00
} ,
} ;
2011-11-29 23:08:39 +04:00
module_platform_driver ( tegra_kbc_driver ) ;
2011-01-20 10:38:47 +03:00
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Rakesh Iyer <riyer@nvidia.com> " ) ;
MODULE_DESCRIPTION ( " Tegra matrix keyboard controller driver " ) ;
MODULE_ALIAS ( " platform:tegra-kbc " ) ;