@@ -37,7 +37,7 @@ obj-$(CONFIG_MACH_OMAP_PALMZ71) += boar
obj-$(CONFIG_MACH_OMAP_PALMTT) += board-palmtt.o
obj-$(CONFIG_MACH_NOKIA770) += board-nokia770.o
obj-$(CONFIG_MACH_AMS_DELTA) += board-ams-delta.o
-obj-$(CONFIG_AMS_DELTA_FIQ) += ams-delta-fiq-handler.o
+obj-$(CONFIG_AMS_DELTA_FIQ) += ams-delta-fiq.o ams-delta-fiq-handler.o
obj-$(CONFIG_MACH_SX1) += board-sx1.o board-sx1-mmc.o
obj-$(CONFIG_MACH_HERALD) += board-htcherald.o
@@ -0,0 +1,175 @@
+/*
+ * Amstrad E3 FIQ handling
+ *
+ * Copyright (C) 2009 Janusz Krzysztofik
+ * Copyright (c) 2006 Matt Callow
+ * Copyright (c) 2004 Amstrad Plc
+ * Copyright (C) 2001 RidgeRun, Inc.
+ *
+ * Parts of this code are taken from linux/arch/arm/mach-omap/irq.c
+ * in the MontaVista 2.4 kernel (and the Amstrad changes therein)
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/gpio.h>
+#include <asm/fiq.h>
+#include <mach/ams-delta-fiq.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <plat/board-ams-delta.h>
+#include <plat/mux.h>
+#include <plat/board.h>
+#include <plat/common.h>
+
+static struct fiq_handler fh = {
+ .name = "ams-delta-fiq"
+};
+
+/*
+ * This buffer is shared between FIQ and IRQ contexts.
+ * The FIQ and IRQ isrs can both read and write it.
+ * It is structured as a header section several 32bit slots,
+ * followed by the circular buffer where the FIQ isr stores
+ * characters received from the qwerty keyboard.
+ * See ams-delta-fiq.h for details of offsets.
+ */
+unsigned int fiq_buffer[1024];
+EXPORT_SYMBOL(fiq_buffer);
+
+static unsigned int fiq_buffer_irq[FIQ_CIRC_BUFF];
+
+static irqreturn_t deferred_fiq(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ int list_index, buffer_offset;
+ int irq_num;
+ const unsigned int cpu = smp_processor_id();
+
+ /*
+ * Call the interrupt handler for each GPIO interrupt
+ * where the FIQ interrupt counter > the IRQ counter
+ */
+ for (buffer_offset = FIQ_CNT_INT_04;
+ buffer_offset >= FIQ_CNT_INT_CHAR; buffer_offset--) {
+ while (fiq_buffer[buffer_offset] >
+ fiq_buffer_irq[buffer_offset]) {
+
+ list_index = buffer_offset - FIQ_CNT_INT_00;
+ irq_num = list_index + IH_GPIO_BASE;
+
+ if (irq_desc[irq_num].action->handler != NULL) {
+ irq_desc[irq_num].action->handler(irq_num,
+ irq_desc[irq_num].action->dev_id);
+ /* keep /proc/interrupts up to date */
+ kstat_cpu(cpu).softirqs[irq_num]++;
+
+ /*
+ * Increment the IRQ count to ensure one IRQ
+ * call per FIQ. There is a corresponding
+ * increment in the FIQ handler having and
+ * IRQ & FIQ level counters avoids any races.
+ * There is a possibility that two calls to this
+ * handler occur when keyboard and modem
+ * interrupts are close together. Although both
+ * interrupts will be serviced during the first
+ * one. This should have no serious effect apart
+ * from an unecessary call through here on
+ * occasion, but that's better than missing one.
+ */
+ fiq_buffer_irq[buffer_offset]++;
+ } else {
+ printk(KERN_WARNING
+ "!!! NULL HANDLER for[%d]!!!\n",
+ irq_num);
+ fiq_buffer_irq[buffer_offset]++;
+ }
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+void __init ams_delta_init_fiq(void)
+{
+ int retval;
+ void *fiqhandler_start;
+ unsigned int fiqhandler_length;
+ struct pt_regs FIQ_regs;
+ unsigned long val, offset;
+ int i;
+
+ fiqhandler_start = &qwerty_fiqin_start;
+ fiqhandler_length = &qwerty_fiqin_end - &qwerty_fiqin_start;
+ printk(KERN_INFO "Installing fiq handler from %p, length 0x%x\r\n",
+ fiqhandler_start, fiqhandler_length);
+
+ retval = claim_fiq(&fh);
+ if (retval) {
+ printk(KERN_ERR "ams_delta_init_fiq(): couldn't claim FIQ."
+ " ret = %d\n\r", retval);
+ return;
+ }
+
+ if (request_irq(INT_OS_TIMER, deferred_fiq, 0, "deferred_fiq", 0) < 0) {
+ printk(KERN_ERR "Failed to get OS_TIMER\r\n");
+ release_fiq(&fh);
+ return;
+ }
+
+ set_fiq_handler(fiqhandler_start, fiqhandler_length);
+
+ /*
+ * Initialise the buffer which is shared
+ * between FIQ mode and IRQ mode
+ */
+ fiq_buffer[FIQ_GPIO_INT_MASK] = 0;
+ fiq_buffer[FIQ_MASK] = 0;
+ fiq_buffer[FIQ_STATE] = 0;
+ fiq_buffer[FIQ_CHAR] = 0;
+ fiq_buffer[FIQ_CHAR_CNT] = 0;
+ fiq_buffer[FIQ_CHAR_HICNT] = 0;
+ fiq_buffer[FIQ_FRNT_OFFSET] = 0;
+ fiq_buffer[FIQ_BACK_OFFSET] = 0;
+ fiq_buffer[FIQ_BUF_LEN] = 256;
+ fiq_buffer[FIQ_MISSED_CHARS] = 0;
+ fiq_buffer[FIQ_BUFFER_START] =
+ (unsigned int) &fiq_buffer[FIQ_CIRC_BUFF];
+
+ for (i = FIQ_CNT_INT_00; i <= FIQ_CNT_INT_15; i++) {
+ fiq_buffer[i] = 0;
+ fiq_buffer_irq[i] = 0;
+ }
+
+ /*
+ * FIQ mode r9 always points to the fiq_buffer, becauses the FIQ isr
+ * will run in an unpredictable context. The fiq_buffer is the FIQ isr's
+ * only means of communication with the IRQ level and other kernel
+ * context code.
+ */
+ FIQ_regs.ARM_r9 = (unsigned int)fiq_buffer;
+ FIQ_regs.ARM_r10 = 0;
+ FIQ_regs.ARM_sp = 0;
+
+ set_fiq_regs(&FIQ_regs);
+
+ printk(KERN_INFO "request_fiq(): fiq_buffer = %p\n", fiq_buffer);
+
+ /*
+ * Set FIQ, priority 0, tigger rising on the GPIO INT
+ * It would be nice to use omap_irq_set_cfg() here, but it's static
+ */
+ val = 1 | ((IRQ_TYPE_EDGE_RISING & 0x1) << 1);
+ offset = IRQ_ILR0_REG_OFFSET + INT_GPIO_BANK1 * 0x4;
+ omap_writel(val, OMAP_IH1_BASE + offset);
+}
@@ -0,0 +1,57 @@
+/*
+ * arch/arm/mach-omap1/include/ams-delta-fiq.h
+ *
+ * Taken from the original Amstrad modifications to fiq.h
+ *
+ * Copyright (c) 2004 Amstrad Plc
+ * Copyright (c) 2006 Matt Callow
+ *
+ * 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.
+ */
+
+/*
+ * These are the offsets from the begining of the fiq_buffer. They are here
+ * as the buffer and header need to be accessed by drivers servicing devices
+ * which generate GPIO interrupts - e.g. qwerty, modem, smartcard
+ */
+
+#define FIQ_MASK 0
+#define FIQ_STATE 1
+#define FIQ_CHAR_CNT 2
+#define FIQ_FRNT_OFFSET 3
+#define FIQ_BACK_OFFSET 4
+#define FIQ_BUF_LEN 5
+#define FIQ_CHAR 6
+#define FIQ_MISSED_CHARS 7
+#define FIQ_BUFFER_START 8
+#define FIQ_GPIO_INT_MASK 9
+#define FIQ_CHAR_HICNT 10
+#define FIQ_IRQ_PEND 11
+#define FIQ_SIR_CODE_L1 12
+#define IRQ_SIR_CODE_L2 13
+
+#define FIQ_CNT_INT_00 14
+#define FIQ_CNT_INT_CHAR 15
+#define FIQ_CNT_INT_MDM 16
+#define FIQ_CNT_INT_FIQ 17
+#define FIQ_CNT_INT_04 18
+#define FIQ_CNT_INT_05 19
+#define FIQ_CNT_INT_KBD 20
+#define FIQ_CNT_INT_07 21
+#define FIQ_CNT_INT_08 22
+#define FIQ_CNT_INT_09 23
+#define FIQ_CNT_INT_10 24
+#define FIQ_CNT_INT_11 25
+#define FIQ_CNT_INT_12 26
+#define FIQ_CNT_INT_13 27
+#define FIQ_CNT_INT_14 28
+#define FIQ_CNT_INT_15 29
+
+#define FIQ_CIRC_BUFF 30 /*Start of circular buffer */
+
+extern unsigned int fiq_buffer[];
+extern unsigned char qwerty_fiqin_start, qwerty_fiqin_end;
+
+extern void __init ams_delta_init_fiq(void);