From e8704ac96d42a4f3093dc253b7f2b44cf8c150e8 Mon Sep 17 00:00:00 2001 From: Naveen Kumar Gaddipati Date: Wed, 16 Jun 2010 10:34:44 +0530 Subject: ske_driver: support for internal keypad Added the driver to support the internal keypad on ux500 platform ST-Ericsson Id:CR 256008 Signed-off-by: Naveen Kumar Gaddipati Signed-off-by: Mian Yousaf Kaukab Change-Id: I8f776d4ff1e8ac4bc3ad0b629c1144b7e5daefb8 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/2541 Reviewed-by: Jonas ABERG --- arch/arm/mach-ux500/board-mop500.c | 6 + arch/arm/mach-ux500/clock.c | 2 +- arch/arm/mach-ux500/devices.c | 232 +++++++++++++++++++++++++++++ arch/arm/mach-ux500/include/mach/devices.h | 1 + arch/arm/mach-ux500/include/mach/irqs.h | 1 + arch/arm/mach-ux500/include/mach/kpd.h | 60 ++++---- 6 files changed, 274 insertions(+), 28 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index 782a9801aa2..a52bc7e6231 100755 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c @@ -124,6 +124,9 @@ static struct gpio_altfun_data gpio_altfun_table[] = { __GPIO_ALT(GPIO_ALT_TP_SET_EXT_CLK, 228, 228, 0, NMK_GPIO_ALT_A, "u8500_tp"), #endif +#ifdef CONFIG_KEYPAD_SKE + __GPIO_ALT(GPIO_ALT_KEYPAD, 153, 168, 0, NMK_GPIO_ALT_A, "ske-kp"), +#endif }; @@ -1309,6 +1312,9 @@ static struct platform_device *platform_board_devs[] __initdata = { &ux500_hash1_device, #endif &u8500_leds_controller, +#ifdef CONFIG_KEYPAD_SKE + &ske_keypad_device, +#endif }; static void __init mop500_platdata_init(void) diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c index 056ecc26140..5ab9027368b 100755 --- a/arch/arm/mach-ux500/clock.c +++ b/arch/arm/mach-ux500/clock.c @@ -433,7 +433,7 @@ static struct clk_lookup u8500_common_clkregs[] = { CLK(gpio2, "gpioblock2", NULL), CLK(sdi5, "sdi5", NULL), CLK(uart2, "uart2", NULL), - CLK(ske, "ske", NULL), + CLK(ske, "ske-kp", NULL), CLK(sdi2, "sdi2", NULL), CLK(i2c0, "nmk-i2c.0", NULL), CLK(fsmc, "fsmc", NULL), diff --git a/arch/arm/mach-ux500/devices.c b/arch/arm/mach-ux500/devices.c index 711b02b45be..aab9f3e6501 100755 --- a/arch/arm/mach-ux500/devices.c +++ b/arch/arm/mach-ux500/devices.c @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -43,6 +44,7 @@ #include #include #include +#include void __init u8500_register_device(struct platform_device *dev, void *data) { @@ -726,7 +728,237 @@ struct amba_device ux500_uart2_device = { }; #endif +#ifdef CONFIG_KEYPAD_SKE + +#define KEYPAD_DEBOUNCE_PERIOD_SKE 64 +#define ROW_PIN_I0 164 +#define ROW_PIN_I3 161 +#define ROW_PIN_I4 156 +#define ROW_PIN_I7 153 +#define COL_PIN_O0 168 +#define COL_PIN_O3 165 +#define COL_PIN_O4 160 +#define COL_PIN_O7 157 + +/* ske_set_gpio_column - Disables Pull up + * @start: start column pin + * @end: end column pin + * This function disables the pull up for output pins +*/ +int ske_set_gpio_column(int start, int end) +{ + int i; + int status = 0; + + for (i = start; i <= end; i++) { + status = gpio_request(i, "ske"); + if (status < 0) { + printk(KERN_ERR "%s: gpio request failed \n", __func__); + return status; + } + status = nmk_gpio_set_pull(i, NMK_GPIO_PULL_UP); + if (status < 0) { + printk(KERN_ERR "%s: gpio set pull failed \n", __func__); + return status; + } + gpio_free(i); + } + return status; +} +/* ske_set_gpio_row - enable the input pins + * @start: start row pin + * @end: end row pin + * This function enable the input pins +*/ +int ske_set_gpio_row(int start, int end) +{ + int i = 0; + int status = 0; + + for (i = start; i <= end; i++) { + status = gpio_request(i, "ske"); + if (status < 0) { + printk(KERN_ERR "%s: gpio request failed \n", __func__); + return status; + } + status = gpio_direction_output(i, 1); + if (status < 0) { + printk(KERN_ERR "%s: gpio direction failed \n", __func__); + gpio_free(i); + return status; + } + gpio_set_value(i, 1); + gpio_free(i); + } + return status; +} +/** + * ske_kp_init - enable the gpio configuration + * @kp: keypad device data pointer + * + * This function is used to enable the gpio configuration for keypad + * + */ +static int ske_kp_init(struct keypad_t *kp) +{ + int ret; + ret = ske_set_gpio_row(ROW_PIN_I3, ROW_PIN_I0); + if (ret < 0) + goto err; + ret = ske_set_gpio_row(ROW_PIN_I7, ROW_PIN_I4); + if (ret < 0) + goto err; + ret = ske_set_gpio_column(COL_PIN_O3, COL_PIN_O0); + if (ret < 0) + goto err; + ret = ske_set_gpio_column(COL_PIN_O7, COL_PIN_O4); + if (ret < 0) + goto err; + ret = stm_gpio_altfuncenable(GPIO_ALT_KEYPAD); + if (ret) + goto err; + return 0; +err: + printk(KERN_ERR "%s: failed \n", __func__); + return ret; +} +/** + * ske_kp_exit - disable the gpio configuration + * @kp: keypad device data pointer + * + * This function is used to disable the gpio configuration for keypad + * + */ +static int ske_kp_exit(struct keypad_t *kp) +{ + stm_gpio_altfuncdisable(GPIO_ALT_KEYPAD); + return 0; +} + +/* + * Initializes the key scan table (lookup table) as per pre-defined the scan + * codes to be passed to upper layer with respective key codes + */ +u8 const kpd_lookup_tbl[MAX_KPROW][MAX_KPROW] = { + { + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_MENU, + KEY_RESERVED, + KEY_RESERVED + }, + { + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_3, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED + }, + { + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_END, + KEY_RESERVED, + KEY_RESERVED + }, + { + KEY_RESERVED, + KEY_RESERVED, + KEY_7, + KEY_DOWN, + KEY_UP, + KEY_VOLUMEDOWN, + KEY_RESERVED, + KEY_RESERVED + }, + { + KEY_RESERVED, + KEY_4, + KEY_VOLUMEUP, + KEY_LEFT, + KEY_RESERVED, + KEY_0, + KEY_RESERVED, + KEY_RESERVED + }, + { + KEY_9, + KEY_RESERVED, + KEY_RIGHT, + KEY_RESERVED, + KEY_RESERVED, + KEY_1, + KEY_RESERVED, + KEY_RESERVED + }, + { + KEY_RESERVED, + KEY_RESERVED, + KEY_BACK, + KEY_RESERVED, + KEY_SEND, + KEY_RESERVED, + KEY_RESERVED, + KEY_2 + }, + { + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_ENTER, + KEY_RESERVED + } +}; + +static struct keypad_device keypad_board = { + .init = ske_kp_init, + .exit = ske_kp_exit, + .kcode_tbl = (u8 *) kpd_lookup_tbl, + .krow = MAX_KPROW, + .kcol = MAX_KPCOL, + .debounce_period = KEYPAD_DEBOUNCE_PERIOD_SKE, + .irqtype = 0, + .int_status = KP_INT_DISABLED, + .int_line_behaviour = INT_LINE_NOTSET, +}; + +struct resource keypad_resources[] = { + [0] = { + .start = U8500_SKE_BASE, + .end = U8500_SKE_BASE + SZ_4K - 1, + .name = "ux500_ske_base", + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_SKE_KP, + .end = IRQ_SKE_KP, + .name = "ux500_ske_irq", + .flags = IORESOURCE_IRQ, + }, +}; +struct platform_device ske_keypad_device = { + .name = "ske-kp", + .id = -1, + .dev = { + .platform_data = &keypad_board, + }, + .num_resources = ARRAY_SIZE(keypad_resources), + .resource = keypad_resources, +}; +#endif #if defined(CONFIG_U5500_MLOADER_HELPER) struct platform_device mloader_helper_device = { .name = "mloader_helper", diff --git a/arch/arm/mach-ux500/include/mach/devices.h b/arch/arm/mach-ux500/include/mach/devices.h index 73ddb146626..5acb60460f3 100755 --- a/arch/arm/mach-ux500/include/mach/devices.h +++ b/arch/arm/mach-ux500/include/mach/devices.h @@ -50,6 +50,7 @@ extern struct platform_device ux500_musb_device; extern struct amba_device ux500_uart0_device; extern struct amba_device ux500_uart1_device; extern struct amba_device ux500_uart2_device; +extern struct platform_device ske_keypad_device; #ifdef CONFIG_U5500_MLOADER_HELPER extern struct platform_device mloader_helper_device; diff --git a/arch/arm/mach-ux500/include/mach/irqs.h b/arch/arm/mach-ux500/include/mach/irqs.h index b883d013773..88e51d1c4da 100755 --- a/arch/arm/mach-ux500/include/mach/irqs.h +++ b/arch/arm/mach-ux500/include/mach/irqs.h @@ -51,6 +51,7 @@ #define IRQ_SDMMC1 (IRQ_SPI_START + 50) #define IRQ_I2C4 (IRQ_SPI_START + 51) #define IRQ_SSP1 (IRQ_SPI_START + 52) +#define IRQ_SKE_KP (IRQ_SPI_START + 54) #define IRQ_I2C2 (IRQ_SPI_START + 55) #define IRQ_SDMMC3 (IRQ_SPI_START + 59) #define IRQ_SDMMC0 (IRQ_SPI_START + 60) diff --git a/arch/arm/mach-ux500/include/mach/kpd.h b/arch/arm/mach-ux500/include/mach/kpd.h index 46177466078..ffff8eea193 100755 --- a/arch/arm/mach-ux500/include/mach/kpd.h +++ b/arch/arm/mach-ux500/include/mach/kpd.h @@ -14,12 +14,14 @@ #define CONFIG_AUTOSCAN_ENABLED 1 #endif #include +#include #define MAX_KPROW 8 #define MAX_KPCOL 8 +#define MAX_KEYS (MAX_KPROW * MAX_KPCOL) /*keypad related Constants*/ -#define KEYPAD_RELEASE_PERIOD 11 /*110 Msec, repeate key scan time */ -#define KEYPAD_SCAN_PERIOD 4 /*40Msec for new keypress */ +#define KEYPAD_RELEASE_PERIOD 11 /*11 msec, repeate key scan time */ +#define KEYPAD_SCAN_PERIOD 4 /*4msec for new keypress */ #define KEYPAD_STATE_DEFAULT 0 #define KEYPAD_STATE_PRESSED 1 #define KEYPAD_STATE_PRESSACK 2 @@ -33,18 +35,18 @@ struct keypad_t; * struct keypad_device - Device data structure for platform specific data * @init: pointer to keypad init function * @exit: pointer to keypad deinitialisation function - * @autoscan_check: pointer to read autoscan status function, not used + * @autoscan_check: pointer to read autoscan status function * currently * @autoscan_disable: pointer to autoscan feature disable function, * not used currently * @autoscan_results: pointer to read autoscan results function - * @autoscan_en: pointer to enable autoscan feature function, not used + * @autoscan_en: pointer to enable autoscan feature function * currently * @irqen: pointer to enable irq function * @irqdis: pointer to disable irq function * @kcode_tbl: lookup table for keycodes * @krow: mask for available rows, value is 0xFF - * @kcol: mask for available columns, value is 0xFF + * @kcol: mask for available columns, value is 0xFF * @irqdis_int: pointer to disable irq function, to be called from ISR * @debounce_period: platform specific debounce time, can be fine tuned later * @irqtype: type of interrupt @@ -54,47 +56,51 @@ struct keypad_t; * @enable_wakeup: specifies if keypad event can wake up system from sleep */ struct keypad_device { - int (*init)(struct keypad_t *kp); - int (*exit)(struct keypad_t *kp); - int (*autoscan_check)(void); - void (*autoscan_disable)(void); - int (*autoscan_results)(struct keypad_t *kp); - void (*autoscan_en)(void); - int (*irqen)(struct keypad_t *kp); - int (*irqdis)(struct keypad_t *kp); /* normal disable */ - u8 *kcode_tbl; - u8 krow; - u8 kcol; - int (*irqdis_int)(struct keypad_t *kp); - /* func used wen disable in interrupt handler */ - u8 debounce_period; - unsigned long irqtype; - u8 irq; /*IRQ no*/ - u8 int_status; - u8 int_line_behaviour; - bool enable_wakeup; + int (*init)(struct keypad_t *kp); + int (*exit)(struct keypad_t *kp); + int (*autoscan_check)(void); + void (*autoscan_disable)(void); + int (*autoscan_results)(struct keypad_t *kp); + void (*autoscan_en)(void); + int (*irqen)(struct keypad_t *kp); + int (*irqdis)(struct keypad_t *kp); + u8 *kcode_tbl; + u8 krow; + u8 kcol; + int (*irqdis_int)(struct keypad_t *kp); + u8 debounce_period; + unsigned long irqtype; + u8 irq; + u8 int_status; + u8 int_line_behaviour; + bool enable_wakeup; }; - /** * struct keypad_t - keypad data structure used internally by keypad driver * @irq: irq no * @mode: 0 for interrupt mode, 1 for polling mode + * @ske_regs: ske regsiters base address + * @cr_lock: spinlock variable * @key_state: array for saving keystates * @lockbits: used for synchronisation in ISR * @inp_dev: pointer to input device object - * @address_for_data: not used * @kscan_work: work queue * @board: keypad platform device + * @key_cnt: count the keys pressed + * @clk: clock structure pointer */ struct keypad_t { int irq; int mode; + void __iomem *ske_regs; int key_state[MAX_KPROW][MAX_KPCOL]; unsigned long lockbits; + spinlock_t cr_lock; struct input_dev *inp_dev; - void *address_for_data; struct delayed_work kscan_work; struct keypad_device *board; + int key_cnt; + struct clk *clk; }; /** * enum kp_int_status - enum for INTR status -- cgit v1.2.3