|  | /* | 
|  | *  linux/arch/arm/mach-omap1/ams-delta-fiq-handler.S | 
|  | * | 
|  | *  Based on  linux/arch/arm/lib/floppydma.S | 
|  | *  Renamed and modified to work with 2.6 kernel by Matt Callow | 
|  | *  Copyright (C) 1995, 1996 Russell King | 
|  | *  Copyright (C) 2004 Pete Trapps | 
|  | *  Copyright (C) 2006 Matt Callow | 
|  | *  Copyright (C) 2010 Janusz Krzysztofik | 
|  | * | 
|  | * 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/linkage.h> | 
|  |  | 
|  | #include <plat/io.h> | 
|  | #include <plat/board-ams-delta.h> | 
|  |  | 
|  | #include <mach/ams-delta-fiq.h> | 
|  |  | 
|  | /* | 
|  | * GPIO related definitions, copied from arch/arm/plat-omap/gpio.c. | 
|  | * Unfortunately, those were not placed in a separate header file. | 
|  | */ | 
|  | #define OMAP1510_GPIO_BASE		0xFFFCE000 | 
|  | #define OMAP1510_GPIO_DATA_INPUT	0x00 | 
|  | #define OMAP1510_GPIO_DATA_OUTPUT	0x04 | 
|  | #define OMAP1510_GPIO_DIR_CONTROL	0x08 | 
|  | #define OMAP1510_GPIO_INT_CONTROL	0x0c | 
|  | #define OMAP1510_GPIO_INT_MASK		0x10 | 
|  | #define OMAP1510_GPIO_INT_STATUS	0x14 | 
|  | #define OMAP1510_GPIO_PIN_CONTROL	0x18 | 
|  |  | 
|  | /* GPIO register bitmasks */ | 
|  | #define KEYBRD_DATA_MASK		(0x1 << AMS_DELTA_GPIO_PIN_KEYBRD_DATA) | 
|  | #define KEYBRD_CLK_MASK			(0x1 << AMS_DELTA_GPIO_PIN_KEYBRD_CLK) | 
|  | #define MODEM_IRQ_MASK			(0x1 << AMS_DELTA_GPIO_PIN_MODEM_IRQ) | 
|  | #define HOOK_SWITCH_MASK		(0x1 << AMS_DELTA_GPIO_PIN_HOOK_SWITCH) | 
|  | #define OTHERS_MASK			(MODEM_IRQ_MASK | HOOK_SWITCH_MASK) | 
|  |  | 
|  | /* IRQ handler register bitmasks */ | 
|  | #define DEFERRED_FIQ_MASK		(0x1 << (INT_DEFERRED_FIQ % IH2_BASE)) | 
|  | #define GPIO_BANK1_MASK  		(0x1 << INT_GPIO_BANK1) | 
|  |  | 
|  | /* Driver buffer byte offsets */ | 
|  | #define BUF_MASK			(FIQ_MASK * 4) | 
|  | #define BUF_STATE			(FIQ_STATE * 4) | 
|  | #define BUF_KEYS_CNT			(FIQ_KEYS_CNT * 4) | 
|  | #define BUF_TAIL_OFFSET			(FIQ_TAIL_OFFSET * 4) | 
|  | #define BUF_HEAD_OFFSET			(FIQ_HEAD_OFFSET * 4) | 
|  | #define BUF_BUF_LEN			(FIQ_BUF_LEN * 4) | 
|  | #define BUF_KEY				(FIQ_KEY * 4) | 
|  | #define BUF_MISSED_KEYS			(FIQ_MISSED_KEYS * 4) | 
|  | #define BUF_BUFFER_START		(FIQ_BUFFER_START * 4) | 
|  | #define BUF_GPIO_INT_MASK		(FIQ_GPIO_INT_MASK * 4) | 
|  | #define BUF_KEYS_HICNT			(FIQ_KEYS_HICNT * 4) | 
|  | #define BUF_IRQ_PEND			(FIQ_IRQ_PEND * 4) | 
|  | #define BUF_SIR_CODE_L1			(FIQ_SIR_CODE_L1 * 4) | 
|  | #define BUF_SIR_CODE_L2			(IRQ_SIR_CODE_L2 * 4) | 
|  | #define BUF_CNT_INT_00			(FIQ_CNT_INT_00 * 4) | 
|  | #define BUF_CNT_INT_KEY			(FIQ_CNT_INT_KEY * 4) | 
|  | #define BUF_CNT_INT_MDM			(FIQ_CNT_INT_MDM * 4) | 
|  | #define BUF_CNT_INT_03			(FIQ_CNT_INT_03 * 4) | 
|  | #define BUF_CNT_INT_HSW			(FIQ_CNT_INT_HSW * 4) | 
|  | #define BUF_CNT_INT_05			(FIQ_CNT_INT_05 * 4) | 
|  | #define BUF_CNT_INT_06			(FIQ_CNT_INT_06 * 4) | 
|  | #define BUF_CNT_INT_07			(FIQ_CNT_INT_07 * 4) | 
|  | #define BUF_CNT_INT_08			(FIQ_CNT_INT_08 * 4) | 
|  | #define BUF_CNT_INT_09			(FIQ_CNT_INT_09 * 4) | 
|  | #define BUF_CNT_INT_10			(FIQ_CNT_INT_10 * 4) | 
|  | #define BUF_CNT_INT_11			(FIQ_CNT_INT_11 * 4) | 
|  | #define BUF_CNT_INT_12			(FIQ_CNT_INT_12 * 4) | 
|  | #define BUF_CNT_INT_13			(FIQ_CNT_INT_13 * 4) | 
|  | #define BUF_CNT_INT_14			(FIQ_CNT_INT_14 * 4) | 
|  | #define BUF_CNT_INT_15			(FIQ_CNT_INT_15 * 4) | 
|  | #define BUF_CIRC_BUFF			(FIQ_CIRC_BUFF * 4) | 
|  |  | 
|  |  | 
|  | /* | 
|  | * Register useage | 
|  | * r8  - temporary | 
|  | * r9  - the driver buffer | 
|  | * r10 - temporary | 
|  | * r11 - interrupts mask | 
|  | * r12 - base pointers | 
|  | * r13 - interrupts status | 
|  | */ | 
|  |  | 
|  | .text | 
|  |  | 
|  | .global qwerty_fiqin_end | 
|  |  | 
|  | ENTRY(qwerty_fiqin_start) | 
|  | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ | 
|  | @ FIQ intrrupt handler | 
|  | ldr r12, omap_ih1_base			@ set pointer to level1 handler | 
|  |  | 
|  | ldr r11, [r12, #IRQ_MIR_REG_OFFSET]	@ fetch interrupts mask | 
|  |  | 
|  | ldr r13, [r12, #IRQ_ITR_REG_OFFSET]	@ fetch interrupts status | 
|  | bics r13, r13, r11			@ clear masked - any left? | 
|  | beq exit				@ none - spurious FIQ? exit | 
|  |  | 
|  | ldr r10, [r12, #IRQ_SIR_FIQ_REG_OFFSET]	@ get requested interrupt number | 
|  |  | 
|  | mov r8, #2				@ reset FIQ agreement | 
|  | str r8, [r12, #IRQ_CONTROL_REG_OFFSET] | 
|  |  | 
|  | cmp r10, #INT_GPIO_BANK1		@ is it GPIO bank interrupt? | 
|  | beq gpio				@ yes - process it | 
|  |  | 
|  | mov r8, #1 | 
|  | orr r8, r11, r8, lsl r10		@ mask spurious interrupt | 
|  | str r8, [r12, #IRQ_MIR_REG_OFFSET] | 
|  | exit: | 
|  | subs	pc, lr, #4			@ return from FIQ | 
|  | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ | 
|  |  | 
|  |  | 
|  | @@@@@@@@@@@@@@@@@@@@@@@@@@@ | 
|  | gpio:	@ GPIO bank interrupt handler | 
|  | ldr r12, omap1510_gpio_base		@ set base pointer to GPIO bank | 
|  |  | 
|  | ldr r11, [r12, #OMAP1510_GPIO_INT_MASK]	@ fetch GPIO interrupts mask | 
|  | restart: | 
|  | ldr r13, [r12, #OMAP1510_GPIO_INT_STATUS]	@ fetch status bits | 
|  | bics r13, r13, r11			@ clear masked - any left? | 
|  | beq exit				@ no - spurious interrupt? exit | 
|  |  | 
|  | orr r11, r11, r13			@ mask all requested interrupts | 
|  | str r11, [r12, #OMAP1510_GPIO_INT_MASK] | 
|  |  | 
|  | ands r10, r13, #KEYBRD_CLK_MASK		@ extract keyboard status - set? | 
|  | beq hksw				@ no - try next source | 
|  |  | 
|  |  | 
|  | @@@@@@@@@@@@@@@@@@@@@@ | 
|  | @ Keyboard clock FIQ mode interrupt handler | 
|  | @ r10 now contains KEYBRD_CLK_MASK, use it | 
|  | str r10, [r12, #OMAP1510_GPIO_INT_STATUS]	@ ack the interrupt | 
|  | bic r11, r11, r10				@ unmask it | 
|  | str r11, [r12, #OMAP1510_GPIO_INT_MASK] | 
|  |  | 
|  | @ Process keyboard data | 
|  | ldr r8, [r12, #OMAP1510_GPIO_DATA_INPUT]	@ fetch GPIO input | 
|  |  | 
|  | ldr r10, [r9, #BUF_STATE]		@ fetch kbd interface state | 
|  | cmp r10, #0				@ are we expecting start bit? | 
|  | bne data				@ no - go to data processing | 
|  |  | 
|  | ands r8, r8, #KEYBRD_DATA_MASK		@ check start bit - detected? | 
|  | beq hksw				@ no - try next source | 
|  |  | 
|  | @ r8 contains KEYBRD_DATA_MASK, use it | 
|  | str r8, [r9, #BUF_STATE]		@ enter data processing state | 
|  | @ r10 already contains 0, reuse it | 
|  | str r10, [r9, #BUF_KEY]			@ clear keycode | 
|  | mov r10, #2				@ reset input bit mask | 
|  | str r10, [r9, #BUF_MASK] | 
|  |  | 
|  | @ Mask other GPIO line interrupts till key done | 
|  | str r11, [r9, #BUF_GPIO_INT_MASK]	@ save mask for later restore | 
|  | mvn r11, #KEYBRD_CLK_MASK		@ prepare all except kbd mask | 
|  | str r11, [r12, #OMAP1510_GPIO_INT_MASK]	@ store into the mask register | 
|  |  | 
|  | b restart				@ restart | 
|  |  | 
|  | data:	ldr r10, [r9, #BUF_MASK]		@ fetch current input bit mask | 
|  |  | 
|  | @ r8 still contains GPIO input bits | 
|  | ands r8, r8, #KEYBRD_DATA_MASK		@ is keyboard data line low? | 
|  | ldreq r8, [r9, #BUF_KEY]		@ yes - fetch collected so far, | 
|  | orreq r8, r8, r10			@ set 1 at current mask position | 
|  | streq r8, [r9, #BUF_KEY]		@ and save back | 
|  |  | 
|  | mov r10, r10, lsl #1			@ shift mask left | 
|  | bics r10, r10, #0x800			@ have we got all the bits? | 
|  | strne r10, [r9, #BUF_MASK]		@ not yet - store the mask | 
|  | bne restart				@ and restart | 
|  |  | 
|  | @ r10 already contains 0, reuse it | 
|  | str r10, [r9, #BUF_STATE]		@ reset state to start | 
|  |  | 
|  | @ Key done - restore interrupt mask | 
|  | ldr r10, [r9, #BUF_GPIO_INT_MASK]	@ fetch saved mask | 
|  | and r11, r11, r10			@ unmask all saved as unmasked | 
|  | str r11, [r12, #OMAP1510_GPIO_INT_MASK]	@ restore into the mask register | 
|  |  | 
|  | @ Try appending the keycode to the circular buffer | 
|  | ldr r10, [r9, #BUF_KEYS_CNT]		@ get saved keystrokes count | 
|  | ldr r8, [r9, #BUF_BUF_LEN]		@ get buffer size | 
|  | cmp r10, r8				@ is buffer full? | 
|  | beq hksw				@ yes - key lost, next source | 
|  |  | 
|  | add r10, r10, #1			@ incremet keystrokes counter | 
|  | str r10, [r9, #BUF_KEYS_CNT] | 
|  |  | 
|  | ldr r10, [r9, #BUF_TAIL_OFFSET]		@ get buffer tail offset | 
|  | @ r8 already contains buffer size | 
|  | cmp r10, r8				@ end of buffer? | 
|  | moveq r10, #0				@ yes - rewind to buffer start | 
|  |  | 
|  | ldr r12, [r9, #BUF_BUFFER_START]	@ get buffer start address | 
|  | add r12, r12, r10, LSL #2		@ calculate buffer tail address | 
|  | ldr r8, [r9, #BUF_KEY]			@ get last keycode | 
|  | str r8, [r12]				@ append it to the buffer tail | 
|  |  | 
|  | add r10, r10, #1			@ increment buffer tail offset | 
|  | str r10, [r9, #BUF_TAIL_OFFSET] | 
|  |  | 
|  | ldr r10, [r9, #BUF_CNT_INT_KEY]		@ increment interrupts counter | 
|  | add r10, r10, #1 | 
|  | str r10, [r9, #BUF_CNT_INT_KEY] | 
|  | @@@@@@@@@@@@@@@@@@@@@@@@ | 
|  |  | 
|  |  | 
|  | hksw:	@Is hook switch interrupt requested? | 
|  | tst r13, #HOOK_SWITCH_MASK 		@ is hook switch status bit set? | 
|  | beq mdm					@ no - try next source | 
|  |  | 
|  |  | 
|  | @@@@@@@@@@@@@@@@@@@@@@@@ | 
|  | @ Hook switch interrupt FIQ mode simple handler | 
|  |  | 
|  | @ Don't toggle active edge, the switch always bounces | 
|  |  | 
|  | @ Increment hook switch interrupt counter | 
|  | ldr r10, [r9, #BUF_CNT_INT_HSW] | 
|  | add r10, r10, #1 | 
|  | str r10, [r9, #BUF_CNT_INT_HSW] | 
|  | @@@@@@@@@@@@@@@@@@@@@@@@ | 
|  |  | 
|  |  | 
|  | mdm:	@Is it a modem interrupt? | 
|  | tst r13, #MODEM_IRQ_MASK 		@ is modem status bit set? | 
|  | beq irq					@ no - check for next interrupt | 
|  |  | 
|  |  | 
|  | @@@@@@@@@@@@@@@@@@@@@@@@ | 
|  | @ Modem FIQ mode interrupt handler stub | 
|  |  | 
|  | @ Increment modem interrupt counter | 
|  | ldr r10, [r9, #BUF_CNT_INT_MDM] | 
|  | add r10, r10, #1 | 
|  | str r10, [r9, #BUF_CNT_INT_MDM] | 
|  | @@@@@@@@@@@@@@@@@@@@@@@@ | 
|  |  | 
|  |  | 
|  | irq:	@ Place deferred_fiq interrupt request | 
|  | ldr r12, deferred_fiq_ih_base		@ set pointer to IRQ handler | 
|  | mov r10, #DEFERRED_FIQ_MASK		@ set deferred_fiq bit | 
|  | str r10, [r12, #IRQ_ISR_REG_OFFSET] 	@ place it in the ISR register | 
|  |  | 
|  | ldr r12, omap1510_gpio_base		@ set pointer back to GPIO bank | 
|  | b restart				@ check for next GPIO interrupt | 
|  | @@@@@@@@@@@@@@@@@@@@@@@@@@@ | 
|  |  | 
|  |  | 
|  | /* | 
|  | * Virtual addresses for IO | 
|  | */ | 
|  | omap_ih1_base: | 
|  | .word OMAP1_IO_ADDRESS(OMAP_IH1_BASE) | 
|  | deferred_fiq_ih_base: | 
|  | .word OMAP1_IO_ADDRESS(DEFERRED_FIQ_IH_BASE) | 
|  | omap1510_gpio_base: | 
|  | .word OMAP1_IO_ADDRESS(OMAP1510_GPIO_BASE) | 
|  | qwerty_fiqin_end: | 
|  |  | 
|  | /* | 
|  | * Check the size of the FIQ, | 
|  | * it cannot go beyond 0xffff0200, and is copied to 0xffff001c | 
|  | */ | 
|  | .if (qwerty_fiqin_end - qwerty_fiqin_start) > (0x200 - 0x1c) | 
|  | .err | 
|  | .endif |