]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
refactor atheros system code - also add support for the reset button (sends netlink...
authorFelix Fietkau <nbd@openwrt.org>
Wed, 4 Jul 2007 03:55:23 +0000 (03:55 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Wed, 4 Jul 2007 03:55:23 +0000 (03:55 +0000)
SVN-Revision: 7869

13 files changed:
target/linux/atheros-2.6/files/arch/mips/atheros/Makefile
target/linux/atheros-2.6/files/arch/mips/atheros/ar5312/Makefile [new file with mode: 0644]
target/linux/atheros-2.6/files/arch/mips/atheros/ar5312/ar5312.h [moved from target/linux/atheros-2.6/files/arch/mips/atheros/ar5312.h with 100% similarity]
target/linux/atheros-2.6/files/arch/mips/atheros/ar5312/board.c [moved from target/linux/atheros-2.6/files/arch/mips/atheros/ar5312.c with 74% similarity]
target/linux/atheros-2.6/files/arch/mips/atheros/ar5312/irq.c [new file with mode: 0644]
target/linux/atheros-2.6/files/arch/mips/atheros/ar5315/Makefile [new file with mode: 0644]
target/linux/atheros-2.6/files/arch/mips/atheros/ar5315/ar5315.h [moved from target/linux/atheros-2.6/files/arch/mips/atheros/ar5315.h with 98% similarity]
target/linux/atheros-2.6/files/arch/mips/atheros/ar5315/board.c [moved from target/linux/atheros-2.6/files/arch/mips/atheros/ar5315.c with 63% similarity]
target/linux/atheros-2.6/files/arch/mips/atheros/ar5315/irq.c [new file with mode: 0644]
target/linux/atheros-2.6/files/arch/mips/atheros/ar531x.h
target/linux/atheros-2.6/files/arch/mips/atheros/board.c
target/linux/atheros-2.6/files/arch/mips/atheros/irq.c [deleted file]
target/linux/atheros-2.6/files/arch/mips/atheros/reset.c [new file with mode: 0644]

index aff65d723adb53c7b7b6aa2e31d82d02ba85f5fa..2c2b991bc49f22615e56d285cbd0e95cb22553d4 100644 (file)
@@ -3,20 +3,11 @@
 # License.  See the file "COPYING" in the main directory of this archive
 # for more details.
 #
-# Copyright (C) 2003 Atheros Communications, Inc.,  All Rights Reserved.
 # Copyright (C) 2006 FON Technology, SL.
 # Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
 # Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
 #
 
-# Makefile for Atheros ar531x boards
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-
-obj-y += board.o prom.o irq.o
-obj-$(CONFIG_ATHEROS_AR5312) += ar5312.o
-obj-$(CONFIG_ATHEROS_AR5315) += ar5315.o
-
+obj-y += board.o prom.o reset.o
+obj-$(CONFIG_ATHEROS_AR5312) += ar5312/
+obj-$(CONFIG_ATHEROS_AR5315) += ar5315/
diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/ar5312/Makefile b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5312/Makefile
new file mode 100644 (file)
index 0000000..6c50d99
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 2007 FON Technology, SL.
+# Copyright (C) 2007 Imre Kaloz <kaloz@openwrt.org>
+# Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
+#
+
+obj-y := board.o irq.o
similarity index 74%
rename from target/linux/atheros-2.6/files/arch/mips/atheros/ar5312.c
rename to target/linux/atheros-2.6/files/arch/mips/atheros/ar5312/board.c
index 57d56eb0e5e69e265efec2136a908f50600d842f..21073dbbbb78765be0486ca0a9bc6cb7f4d62acb 100644 (file)
@@ -27,7 +27,7 @@
 #include <asm/time.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include "ar531x.h"
+#include "../ar531x.h"
 
 #define NO_PHY 0x1f
 
@@ -312,47 +312,6 @@ int __init ar5312_init_devices(void)
 }
 
 
-/*
- * Called when an interrupt is received, this function
- * determines exactly which interrupt it was, and it
- * invokes the appropriate handler.
- *
- * Implicitly, we also define interrupt priority by
- * choosing which to dispatch first.
- */
-asmlinkage void ar5312_irq_dispatch(void)
-{
-       int pending = read_c0_status() & read_c0_cause();
-
-       if (pending & CAUSEF_IP2)
-               do_IRQ(AR5312_IRQ_WLAN0_INTRS);
-       else if (pending & CAUSEF_IP3)
-               do_IRQ(AR5312_IRQ_ENET0_INTRS);
-       else if (pending & CAUSEF_IP4)
-               do_IRQ(AR5312_IRQ_ENET1_INTRS);
-       else if (pending & CAUSEF_IP5)
-               do_IRQ(AR5312_IRQ_WLAN1_INTRS);
-       else if (pending & CAUSEF_IP6) {
-               unsigned int ar531x_misc_intrs = sysRegRead(AR531X_ISR) & sysRegRead(AR531X_IMR);
-
-               if (ar531x_misc_intrs & AR531X_ISR_TIMER) {
-                       do_IRQ(AR531X_MISC_IRQ_TIMER);
-                       (void)sysRegRead(AR531X_TIMER);
-               } else if (ar531x_misc_intrs & AR531X_ISR_AHBPROC)
-                       do_IRQ(AR531X_MISC_IRQ_AHB_PROC);
-               else if ((ar531x_misc_intrs & AR531X_ISR_UART0))
-                       do_IRQ(AR531X_MISC_IRQ_UART0);
-               else if (ar531x_misc_intrs & AR531X_ISR_WD)
-                       do_IRQ(AR531X_MISC_IRQ_WATCHDOG);
-               else
-                       do_IRQ(AR531X_MISC_IRQ_NONE);
-       } else if (pending & CAUSEF_IP7) {
-               do_IRQ(AR531X_IRQ_CPU_CLOCK);
-       }
-       else
-               do_IRQ(AR531X_IRQ_NONE);
-}
-
 static void ar5312_halt(void)
 {
         while (1);
@@ -451,110 +410,6 @@ static void __init ar5312_time_init(void)
 }
 
 
-/* Enable the specified AR531X_MISC_IRQ interrupt */
-static void
-ar5312_misc_intr_enable(unsigned int irq)
-{
-       unsigned int imr;
-
-       imr = sysRegRead(AR531X_IMR);
-       imr |= (1 << (irq - AR531X_MISC_IRQ_BASE - 1));
-       sysRegWrite(AR531X_IMR, imr);
-       sysRegRead(AR531X_IMR); /* flush write buffer */
-}
-
-/* Disable the specified AR531X_MISC_IRQ interrupt */
-static void
-ar5312_misc_intr_disable(unsigned int irq)
-{
-       unsigned int imr;
-
-       imr = sysRegRead(AR531X_IMR);
-       imr &= ~(1 << (irq - AR531X_MISC_IRQ_BASE - 1));
-       sysRegWrite(AR531X_IMR, imr);
-       sysRegRead(AR531X_IMR); /* flush write buffer */
-}
-
-/* Turn on the specified AR531X_MISC_IRQ interrupt */
-static unsigned int
-ar5312_misc_intr_startup(unsigned int irq)
-{
-       ar5312_misc_intr_enable(irq);
-       return 0;
-}
-
-/* Turn off the specified AR531X_MISC_IRQ interrupt */
-static void
-ar5312_misc_intr_shutdown(unsigned int irq)
-{
-       ar5312_misc_intr_disable(irq);
-}
-
-static void
-ar5312_misc_intr_ack(unsigned int irq)
-{
-       ar5312_misc_intr_disable(irq);
-}
-
-static void
-ar5312_misc_intr_end(unsigned int irq)
-{
-       if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
-               ar5312_misc_intr_enable(irq);
-}
-
-static struct irq_chip ar5312_misc_intr_controller = {
-       .typename       = "AR5312 misc",
-       .startup        = ar5312_misc_intr_startup,
-       .shutdown       = ar5312_misc_intr_shutdown,
-       .enable         = ar5312_misc_intr_enable,
-       .disable        = ar5312_misc_intr_disable,
-       .ack            = ar5312_misc_intr_ack,
-       .end            = ar5312_misc_intr_end,
-};
-
-static irqreturn_t ar5312_ahb_proc_handler(int cpl, void *dev_id)
-{
-       u32 proc1 = sysRegRead(AR531X_PROC1);
-       u32 procAddr = sysRegRead(AR531X_PROCADDR); /* clears error state */
-       u32 dma1 = sysRegRead(AR531X_DMA1);
-       u32 dmaAddr = sysRegRead(AR531X_DMAADDR);   /* clears error state */
-
-       printk("AHB interrupt: PROCADDR=0x%8.8x  PROC1=0x%8.8x  DMAADDR=0x%8.8x  DMA1=0x%8.8x\n",
-                       procAddr, proc1, dmaAddr, dma1);
-               
-       machine_restart("AHB error"); /* Catastrophic failure */
-       return IRQ_HANDLED;
-}
-
-
-static struct irqaction ar5312_ahb_proc_interrupt  = {
-       .handler        = ar5312_ahb_proc_handler,
-       .flags          = SA_INTERRUPT,
-       .name           = "ar5312_ahb_proc_interrupt",
-};
-
-
-static struct irqaction cascade  = {
-       .handler        = no_action,
-       .flags          = SA_INTERRUPT,
-       .name           = "cascade",
-};
-
-void __init ar5312_misc_intr_init(int irq_base)
-{
-       int i;
-
-       for (i = irq_base; i < irq_base + AR531X_MISC_IRQ_COUNT; i++) {
-               irq_desc[i].status = IRQ_DISABLED;
-               irq_desc[i].action = NULL;
-               irq_desc[i].depth = 1;
-               irq_desc[i].chip = &ar5312_misc_intr_controller;
-       }
-       setup_irq(AR531X_MISC_IRQ_AHB_PROC, &ar5312_ahb_proc_interrupt);
-       setup_irq(AR5312_IRQ_MISC_INTRS, &cascade);
-}
-
 void __init ar5312_prom_init(void)
 {
        u32 memsize, memcfg, bank0AC, bank1AC;
diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/ar5312/irq.c b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5312/irq.c
new file mode 100644 (file)
index 0000000..8345a31
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 Atheros Communications, Inc.,  All Rights Reserved.
+ * Copyright (C) 2006 FON Technology, SL.
+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ */
+
+/*
+ * Platform devices for Atheros SoCs
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <asm/bootinfo.h>
+#include <asm/time.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include "../ar531x.h"
+
+/*
+ * Called when an interrupt is received, this function
+ * determines exactly which interrupt it was, and it
+ * invokes the appropriate handler.
+ *
+ * Implicitly, we also define interrupt priority by
+ * choosing which to dispatch first.
+ */
+asmlinkage void ar5312_irq_dispatch(void)
+{
+       int pending = read_c0_status() & read_c0_cause();
+
+       if (pending & CAUSEF_IP2)
+               do_IRQ(AR5312_IRQ_WLAN0_INTRS);
+       else if (pending & CAUSEF_IP3)
+               do_IRQ(AR5312_IRQ_ENET0_INTRS);
+       else if (pending & CAUSEF_IP4)
+               do_IRQ(AR5312_IRQ_ENET1_INTRS);
+       else if (pending & CAUSEF_IP5)
+               do_IRQ(AR5312_IRQ_WLAN1_INTRS);
+       else if (pending & CAUSEF_IP6) {
+               unsigned int ar531x_misc_intrs = sysRegRead(AR531X_ISR) & sysRegRead(AR531X_IMR);
+
+               if (ar531x_misc_intrs & AR531X_ISR_TIMER) {
+                       do_IRQ(AR531X_MISC_IRQ_TIMER);
+                       (void)sysRegRead(AR531X_TIMER);
+               } else if (ar531x_misc_intrs & AR531X_ISR_AHBPROC)
+                       do_IRQ(AR531X_MISC_IRQ_AHB_PROC);
+               else if ((ar531x_misc_intrs & AR531X_ISR_UART0))
+                       do_IRQ(AR531X_MISC_IRQ_UART0);
+               else if (ar531x_misc_intrs & AR531X_ISR_WD)
+                       do_IRQ(AR531X_MISC_IRQ_WATCHDOG);
+               else
+                       do_IRQ(AR531X_MISC_IRQ_NONE);
+       } else if (pending & CAUSEF_IP7) {
+               do_IRQ(AR531X_IRQ_CPU_CLOCK);
+       }
+       else
+               do_IRQ(AR531X_IRQ_NONE);
+}
+
+
+/* Enable the specified AR531X_MISC_IRQ interrupt */
+static void
+ar5312_misc_intr_enable(unsigned int irq)
+{
+       unsigned int imr;
+
+       imr = sysRegRead(AR531X_IMR);
+       imr |= (1 << (irq - AR531X_MISC_IRQ_BASE - 1));
+       sysRegWrite(AR531X_IMR, imr);
+       sysRegRead(AR531X_IMR); /* flush write buffer */
+}
+
+/* Disable the specified AR531X_MISC_IRQ interrupt */
+static void
+ar5312_misc_intr_disable(unsigned int irq)
+{
+       unsigned int imr;
+
+       imr = sysRegRead(AR531X_IMR);
+       imr &= ~(1 << (irq - AR531X_MISC_IRQ_BASE - 1));
+       sysRegWrite(AR531X_IMR, imr);
+       sysRegRead(AR531X_IMR); /* flush write buffer */
+}
+
+/* Turn on the specified AR531X_MISC_IRQ interrupt */
+static unsigned int
+ar5312_misc_intr_startup(unsigned int irq)
+{
+       ar5312_misc_intr_enable(irq);
+       return 0;
+}
+
+/* Turn off the specified AR531X_MISC_IRQ interrupt */
+static void
+ar5312_misc_intr_shutdown(unsigned int irq)
+{
+       ar5312_misc_intr_disable(irq);
+}
+
+static void
+ar5312_misc_intr_ack(unsigned int irq)
+{
+       ar5312_misc_intr_disable(irq);
+}
+
+static void
+ar5312_misc_intr_end(unsigned int irq)
+{
+       if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+               ar5312_misc_intr_enable(irq);
+}
+
+static struct irq_chip ar5312_misc_intr_controller = {
+       .typename       = "AR5312 misc",
+       .startup        = ar5312_misc_intr_startup,
+       .shutdown       = ar5312_misc_intr_shutdown,
+       .enable         = ar5312_misc_intr_enable,
+       .disable        = ar5312_misc_intr_disable,
+       .ack            = ar5312_misc_intr_ack,
+       .end            = ar5312_misc_intr_end,
+};
+
+static irqreturn_t ar5312_ahb_proc_handler(int cpl, void *dev_id)
+{
+       u32 proc1 = sysRegRead(AR531X_PROC1);
+       u32 procAddr = sysRegRead(AR531X_PROCADDR); /* clears error state */
+       u32 dma1 = sysRegRead(AR531X_DMA1);
+       u32 dmaAddr = sysRegRead(AR531X_DMAADDR);   /* clears error state */
+
+       printk("AHB interrupt: PROCADDR=0x%8.8x  PROC1=0x%8.8x  DMAADDR=0x%8.8x  DMA1=0x%8.8x\n",
+                       procAddr, proc1, dmaAddr, dma1);
+               
+       machine_restart("AHB error"); /* Catastrophic failure */
+       return IRQ_HANDLED;
+}
+
+
+static struct irqaction ar5312_ahb_proc_interrupt  = {
+       .handler        = ar5312_ahb_proc_handler,
+       .flags          = SA_INTERRUPT,
+       .name           = "ar5312_ahb_proc_interrupt",
+};
+
+
+static struct irqaction cascade  = {
+       .handler        = no_action,
+       .flags          = SA_INTERRUPT,
+       .name           = "cascade",
+};
+
+void __init ar5312_misc_intr_init(int irq_base)
+{
+       int i;
+
+       for (i = irq_base; i < irq_base + AR531X_MISC_IRQ_COUNT; i++) {
+               irq_desc[i].status = IRQ_DISABLED;
+               irq_desc[i].action = NULL;
+               irq_desc[i].depth = 1;
+               irq_desc[i].chip = &ar5312_misc_intr_controller;
+       }
+       setup_irq(AR531X_MISC_IRQ_AHB_PROC, &ar5312_ahb_proc_interrupt);
+       setup_irq(AR5312_IRQ_MISC_INTRS, &cascade);
+}
+
+
diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/ar5315/Makefile b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5315/Makefile
new file mode 100644 (file)
index 0000000..6c50d99
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 2007 FON Technology, SL.
+# Copyright (C) 2007 Imre Kaloz <kaloz@openwrt.org>
+# Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
+#
+
+obj-y := board.o irq.o
similarity index 98%
rename from target/linux/atheros-2.6/files/arch/mips/atheros/ar5315.h
rename to target/linux/atheros-2.6/files/arch/mips/atheros/ar5315/ar5315.h
index c3eeed18b8271b2b648b2fa5294e1e38b5d996de..567141cb760392c1783c92f5726acf3251196e03 100644 (file)
 
 #define AR5315_GPIO_CR_M(x)                (1 << (x))                  /* mask for i/o */
 #define AR5315_GPIO_CR_O(x)                (1 << (x))                  /* output */
-#define AR5315_GPIO_CR_I(x)                (0 << (x))                  /* input */
+#define AR5315_GPIO_CR_I(x)                (0)                         /* input */
 
-#define AR5315_GPIO_INT_S(x,Y)             ((x) << (8 * (Y)))          /* interrupt enable */
-#define AR5315_GPIO_INT_M(Y)               ((0x3F) << (8 * (Y)))       /* mask for int */
-#define AR5315_GPIO_INT_LVL(x,Y)           ((x) << (8 * (Y) + 6))      /* interrupt level */
-#define AR5315_GPIO_INT_LVL_M(Y)           ((0x3) << (8 * (Y) + 6))    /* mask for int level */
+#define AR5315_GPIO_INT_S(x)               (x)                         /* interrupt enable */
+#define AR5315_GPIO_INT_M                  (0x3F)                      /* mask for int */
+#define AR5315_GPIO_INT_LVL(x)             ((x) << 6)                  /* interrupt level */
+#define AR5315_GPIO_INT_LVL_M              ((0x3) << 6)                /* mask for int level */
 
 #define AR5315_RESET_GPIO       5
 #define AR5315_NUM_GPIO         22
similarity index 63%
rename from target/linux/atheros-2.6/files/arch/mips/atheros/ar5315.c
rename to target/linux/atheros-2.6/files/arch/mips/atheros/ar5315/board.c
index 0255ae3246c4686de7a02f1749d3739d97e0499d..8247d8548c5ee00ebabf545af1a725cee586b79a 100644 (file)
 #include <asm/time.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include "ar531x.h"
+#include "../ar531x.h"
 
 static int is_5315 = 0;
+
 static struct resource ar5315_eth_res[] = {
        {
                .name = "eth0_membase",
@@ -182,7 +183,6 @@ int __init ar5315_init_devices(void)
 {
        struct ar531x_config *config;
        struct ar531x_boarddata *bcfg;
-       u32 devid;
        int dev = 0;
 
        if (!is_5315)
@@ -193,9 +193,10 @@ int __init ar5315_init_devices(void)
        bcfg = (struct ar531x_boarddata *) board_config;
 
 #if 0
+       {
        /* Detect the hardware based on the device ID */
-       devid = sysRegRead(AR5315_SREV) & AR5315_REV_MAJ >> AR5315_REV_MAJ_S;
-       switch(devid) {
+       u32 devid = sysRegRead(AR5315_SREV) & AR5315_REV_MAJ >> AR5315_REV_MAJ_S;
+               switch(devid) {
                case 0x9:
                        mips_machtype = MACH_ATHEROS_AR2317;
                        break;
@@ -204,6 +205,7 @@ int __init ar5315_init_devices(void)
                default:
                        mips_machtype = MACH_ATHEROS_AR2315;
                        break;
+               }
        }
 #endif
 
@@ -220,48 +222,11 @@ int __init ar5315_init_devices(void)
        ar5315_devs[dev++] = &ar5315_eth;
        ar5315_devs[dev++] = &ar5315_wmac;
        ar5315_devs[dev++] = &ar5315_spiflash;
+                       
 
        return platform_add_devices(ar5315_devs, dev);
 }
 
-
-/*
- * Called when an interrupt is received, this function
- * determines exactly which interrupt it was, and it
- * invokes the appropriate handler.
- *
- * Implicitly, we also define interrupt priority by
- * choosing which to dispatch first.
- */
-asmlinkage void ar5315_irq_dispatch(void)
-{
-       int pending = read_c0_status() & read_c0_cause();
-
-       if (pending & CAUSEF_IP3)
-               do_IRQ(AR5315_IRQ_WLAN0_INTRS);
-       else if (pending & CAUSEF_IP4)
-               do_IRQ(AR5315_IRQ_ENET0_INTRS);
-       else if (pending & CAUSEF_IP2) {
-               unsigned int ar531x_misc_intrs = sysRegRead(AR5315_ISR) & sysRegRead(AR5315_IMR);
-
-           if (ar531x_misc_intrs & AR5315_ISR_TIMER)
-                       do_IRQ(AR531X_MISC_IRQ_TIMER);
-               else if (ar531x_misc_intrs & AR5315_ISR_AHB)
-                       do_IRQ(AR531X_MISC_IRQ_AHB_PROC);
-               else if (ar531x_misc_intrs & AR5315_ISR_GPIO) {
-                       sysRegWrite(AR5315_ISR, sysRegRead(AR5315_IMR) | ~AR5315_ISR_GPIO);
-               } else if (ar531x_misc_intrs & AR5315_ISR_UART0)
-                       do_IRQ(AR531X_MISC_IRQ_UART0);
-               else if (ar531x_misc_intrs & AR5315_ISR_WD)
-                       do_IRQ(AR531X_MISC_IRQ_WATCHDOG);
-               else
-                       do_IRQ(AR531X_MISC_IRQ_NONE);
-       } else if (pending & CAUSEF_IP7)
-               do_IRQ(AR531X_IRQ_CPU_CLOCK);
-       else
-               do_IRQ(AR531X_IRQ_NONE);
-}
-
 static void ar5315_halt(void)
 {
         while (1);
@@ -362,169 +327,6 @@ static void __init ar5315_time_init(void)
        mips_hpt_frequency = ar5315_cpu_frequency() / 2;
 }
 
-
-
-/* Enable the specified AR531X_MISC_IRQ interrupt */
-static void
-ar5315_misc_intr_enable(unsigned int irq)
-{
-       unsigned int imr;
-
-       imr = sysRegRead(AR5315_IMR);
-       switch(irq)
-       {
-          case AR531X_MISC_IRQ_TIMER:
-            imr |= AR5315_ISR_TIMER;
-            break;
-
-          case AR531X_MISC_IRQ_AHB_PROC:
-            imr |= AR5315_ISR_AHB;
-            break;
-
-          case AR531X_MISC_IRQ_AHB_DMA:
-            imr |= 0/* ?? */;
-            break;
-
-          case AR531X_MISC_IRQ_GPIO:
-            imr |= AR5315_ISR_GPIO;
-            break;
-
-          case AR531X_MISC_IRQ_UART0:
-            imr |= AR5315_ISR_UART0;
-            break;
-
-
-          case AR531X_MISC_IRQ_WATCHDOG:
-            imr |= AR5315_ISR_WD;
-            break;
-
-          case AR531X_MISC_IRQ_LOCAL:
-            imr |= 0/* ?? */;
-            break;
-
-       }
-       sysRegWrite(AR5315_IMR, imr);
-       imr=sysRegRead(AR5315_IMR); /* flush write buffer */
-}
-
-/* Disable the specified AR531X_MISC_IRQ interrupt */
-static void
-ar5315_misc_intr_disable(unsigned int irq)
-{
-       unsigned int imr;
-
-       imr = sysRegRead(AR5315_IMR);
-       switch(irq)
-       {
-          case AR531X_MISC_IRQ_TIMER:
-            imr &= (~AR5315_ISR_TIMER);
-            break;
-
-          case AR531X_MISC_IRQ_AHB_PROC:
-            imr &= (~AR5315_ISR_AHB);
-            break;
-
-          case AR531X_MISC_IRQ_AHB_DMA:
-            imr &= 0/* ?? */;
-            break;
-
-          case AR531X_MISC_IRQ_GPIO:
-            imr &= ~AR5315_ISR_GPIO;
-            break;
-
-          case AR531X_MISC_IRQ_UART0:
-            imr &= (~AR5315_ISR_UART0);
-            break;
-
-          case AR531X_MISC_IRQ_WATCHDOG:
-            imr &= (~AR5315_ISR_WD);
-            break;
-
-          case AR531X_MISC_IRQ_LOCAL:
-            imr &= ~0/* ?? */;
-            break;
-
-       }
-       sysRegWrite(AR5315_IMR, imr);
-       sysRegRead(AR5315_IMR); /* flush write buffer */
-}
-
-/* Turn on the specified AR531X_MISC_IRQ interrupt */
-static unsigned int
-ar5315_misc_intr_startup(unsigned int irq)
-{
-       ar5315_misc_intr_enable(irq);
-       return 0;
-}
-
-/* Turn off the specified AR531X_MISC_IRQ interrupt */
-static void
-ar5315_misc_intr_shutdown(unsigned int irq)
-{
-       ar5315_misc_intr_disable(irq);
-}
-
-static void
-ar5315_misc_intr_ack(unsigned int irq)
-{
-       ar5315_misc_intr_disable(irq);
-}
-
-static void
-ar5315_misc_intr_end(unsigned int irq)
-{
-       if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
-               ar5315_misc_intr_enable(irq);
-}
-
-static struct irq_chip ar5315_misc_intr_controller = {
-       .typename       = "AR5315 misc",
-       .startup        = ar5315_misc_intr_startup,
-       .shutdown       = ar5315_misc_intr_shutdown,
-       .enable         = ar5315_misc_intr_enable,
-       .disable        = ar5315_misc_intr_disable,
-       .ack            = ar5315_misc_intr_ack,
-       .end            = ar5315_misc_intr_end,
-};
-
-static irqreturn_t ar5315_ahb_proc_handler(int cpl, void *dev_id)
-{
-    sysRegWrite(AR5315_AHB_ERR0,AHB_ERROR_DET);
-    sysRegRead(AR5315_AHB_ERR1);
-
-    printk("AHB fatal error\n");
-    machine_restart("AHB error"); /* Catastrophic failure */
-
-    return IRQ_HANDLED;
-}
-
-static struct irqaction ar5315_ahb_proc_interrupt  = {
-       .handler        = ar5315_ahb_proc_handler,
-       .flags          = SA_INTERRUPT,
-       .name           = "ar5315_ahb_proc_interrupt",
-};
-
-
-static struct irqaction cascade  = {
-       .handler        = no_action,
-       .flags          = SA_INTERRUPT,
-       .name           = "cascade",
-};
-
-void ar5315_misc_intr_init(int irq_base)
-{
-       int i;
-
-       for (i = irq_base; i < irq_base + AR531X_MISC_IRQ_COUNT; i++) {
-               irq_desc[i].status = IRQ_DISABLED;
-               irq_desc[i].action = NULL;
-               irq_desc[i].depth = 1;
-               irq_desc[i].chip = &ar5315_misc_intr_controller;
-       }
-       setup_irq(AR531X_MISC_IRQ_AHB_PROC, &ar5315_ahb_proc_interrupt);
-       setup_irq(AR5315_IRQ_MISC_INTRS, &cascade);
-}
-
 void __init ar5315_prom_init(void)
 {
        u32 memsize, memcfg;
diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/ar5315/irq.c b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5315/irq.c
new file mode 100644 (file)
index 0000000..3713ebd
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 Atheros Communications, Inc.,  All Rights Reserved.
+ * Copyright (C) 2006 FON Technology, SL.
+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ */
+
+/*
+ * Platform devices for Atheros SoCs
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/interrupt.h>
+#include <asm/bootinfo.h>
+#include <asm/irq_cpu.h>
+#include <asm/io.h>
+#include "../ar531x.h"
+
+static u32 gpiointmask = 0, gpiointval = 0;
+
+static inline void ar5315_gpio_irq(void)
+{
+       u32 pend;
+       sysRegWrite(AR5315_ISR, sysRegRead(AR5315_IMR) | ~AR5315_ISR_GPIO);
+
+       /* only do one gpio interrupt at a time */
+       pend = (sysRegRead(AR5315_GPIO_DI) ^ gpiointval) & gpiointmask;
+       if (!pend)
+               return;
+
+       do_IRQ(AR531X_GPIO_IRQ_BASE + 31 - clz(pend));
+}
+
+
+/*
+ * Called when an interrupt is received, this function
+ * determines exactly which interrupt it was, and it
+ * invokes the appropriate handler.
+ *
+ * Implicitly, we also define interrupt priority by
+ * choosing which to dispatch first.
+ */
+asmlinkage void ar5315_irq_dispatch(void)
+{
+       int pending = read_c0_status() & read_c0_cause();
+
+       if (pending & CAUSEF_IP3)
+               do_IRQ(AR5315_IRQ_WLAN0_INTRS);
+       else if (pending & CAUSEF_IP4)
+               do_IRQ(AR5315_IRQ_ENET0_INTRS);
+       else if (pending & CAUSEF_IP2) {
+               unsigned int ar531x_misc_intrs = sysRegRead(AR5315_ISR) & sysRegRead(AR5315_IMR);
+
+               if (ar531x_misc_intrs & AR5315_ISR_SPI)
+                       do_IRQ(AR531X_MISC_IRQ_SPI);
+               else if (ar531x_misc_intrs & AR5315_ISR_TIMER)
+                       do_IRQ(AR531X_MISC_IRQ_TIMER);
+               else if (ar531x_misc_intrs & AR5315_ISR_AHB)
+                       do_IRQ(AR531X_MISC_IRQ_AHB_PROC);
+               else if (ar531x_misc_intrs & AR5315_ISR_GPIO)
+                       ar5315_gpio_irq();
+               else if (ar531x_misc_intrs & AR5315_ISR_UART0)
+                       do_IRQ(AR531X_MISC_IRQ_UART0);
+               else if (ar531x_misc_intrs & AR5315_ISR_WD)
+                       do_IRQ(AR531X_MISC_IRQ_WATCHDOG);
+               else
+                       do_IRQ(AR531X_MISC_IRQ_NONE);
+       } else if (pending & CAUSEF_IP7)
+               do_IRQ(AR531X_IRQ_CPU_CLOCK);
+       else
+               do_IRQ(AR531X_IRQ_NONE);
+}
+
+static void ar5315_gpio_intr_enable(unsigned int irq)
+{
+       u32 gpio, mask;
+       gpio = irq - AR531X_GPIO_IRQ_BASE;
+       mask = 1 << gpio;
+       gpiointmask |= mask;
+
+       /* reconfigure GPIO line as input */
+       sysRegMask(AR5315_GPIO_CR, AR5315_GPIO_CR_M(gpio), AR5315_GPIO_CR_I(gpio));
+       
+       /* Enable interrupt with edge detection */
+       sysRegMask(AR5315_GPIO_INT, AR5315_GPIO_INT_M | AR5315_GPIO_INT_LVL_M, gpio | AR5315_GPIO_INT_LVL(3));
+}
+
+static void ar5315_gpio_intr_disable(unsigned int irq)
+{
+       u32 gpio, mask;
+       gpio = irq - AR531X_GPIO_IRQ_BASE;
+       mask = 1 << gpio;
+
+       gpiointmask &= ~mask;
+
+       /* Disable interrupt with edge detection */
+       sysRegMask(AR5315_GPIO_INT, AR5315_GPIO_INT_M | AR5315_GPIO_INT_LVL_M, gpio | AR5315_GPIO_INT_LVL(0));
+}
+
+/* Turn on the specified AR531X_MISC_IRQ interrupt */
+static unsigned int ar5315_gpio_intr_startup(unsigned int irq)
+{
+       ar5315_gpio_intr_enable(irq);
+       return 0;
+}
+
+/* Turn off the specified AR531X_MISC_IRQ interrupt */
+static void
+ar5315_gpio_intr_shutdown(unsigned int irq)
+{
+       ar5315_gpio_intr_disable(irq);
+}
+
+static void
+ar5315_gpio_intr_ack(unsigned int irq)
+{
+       ar5315_gpio_intr_disable(irq);
+}
+
+static void
+ar5315_gpio_intr_end(unsigned int irq)
+{
+       if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+               ar5315_gpio_intr_enable(irq);
+}
+
+static struct irq_chip ar5315_gpio_intr_controller = {
+       .typename       = "AR5315 GPIO",
+       .startup        = ar5315_gpio_intr_startup,
+       .shutdown       = ar5315_gpio_intr_shutdown,
+       .enable         = ar5315_gpio_intr_enable,
+       .disable        = ar5315_gpio_intr_disable,
+       .ack            = ar5315_gpio_intr_ack,
+       .end            = ar5315_gpio_intr_end,
+};
+
+
+/* Enable the specified AR531X_MISC_IRQ interrupt */
+static void
+ar5315_misc_intr_enable(unsigned int irq)
+{
+       unsigned int imr;
+
+       imr = sysRegRead(AR5315_IMR);
+       switch(irq)
+       {
+          case AR531X_MISC_IRQ_SPI:
+                imr |= AR5315_ISR_SPI;
+                break;
+
+          case AR531X_MISC_IRQ_TIMER:
+            imr |= AR5315_ISR_TIMER;
+            break;
+
+          case AR531X_MISC_IRQ_AHB_PROC:
+            imr |= AR5315_ISR_AHB;
+            break;
+
+          case AR531X_MISC_IRQ_AHB_DMA:
+            imr |= 0/* ?? */;
+            break;
+
+          case AR531X_MISC_IRQ_GPIO:
+            imr |= AR5315_ISR_GPIO;
+            break;
+
+          case AR531X_MISC_IRQ_UART0:
+            imr |= AR5315_ISR_UART0;
+            break;
+
+
+          case AR531X_MISC_IRQ_WATCHDOG:
+            imr |= AR5315_ISR_WD;
+            break;
+
+          case AR531X_MISC_IRQ_LOCAL:
+            imr |= 0/* ?? */;
+            break;
+
+       }
+       sysRegWrite(AR5315_IMR, imr);
+       imr=sysRegRead(AR5315_IMR); /* flush write buffer */
+}
+
+/* Disable the specified AR531X_MISC_IRQ interrupt */
+static void
+ar5315_misc_intr_disable(unsigned int irq)
+{
+       unsigned int imr;
+
+       imr = sysRegRead(AR5315_IMR);
+       switch(irq)
+       {
+          case AR531X_MISC_IRQ_SPI:
+                imr &= ~AR5315_ISR_SPI;
+                break;
+                
+          case AR531X_MISC_IRQ_TIMER:
+            imr &= (~AR5315_ISR_TIMER);
+            break;
+
+          case AR531X_MISC_IRQ_AHB_PROC:
+            imr &= (~AR5315_ISR_AHB);
+            break;
+
+          case AR531X_MISC_IRQ_AHB_DMA:
+            imr &= 0/* ?? */;
+            break;
+
+          case AR531X_MISC_IRQ_GPIO:
+            imr &= ~AR5315_ISR_GPIO;
+            break;
+
+          case AR531X_MISC_IRQ_UART0:
+            imr &= (~AR5315_ISR_UART0);
+            break;
+
+          case AR531X_MISC_IRQ_WATCHDOG:
+            imr &= (~AR5315_ISR_WD);
+            break;
+
+          case AR531X_MISC_IRQ_LOCAL:
+            imr &= ~0/* ?? */;
+            break;
+
+       }
+       sysRegWrite(AR5315_IMR, imr);
+       sysRegRead(AR5315_IMR); /* flush write buffer */
+}
+
+/* Turn on the specified AR531X_MISC_IRQ interrupt */
+static unsigned int
+ar5315_misc_intr_startup(unsigned int irq)
+{
+       ar5315_misc_intr_enable(irq);
+       return 0;
+}
+
+/* Turn off the specified AR531X_MISC_IRQ interrupt */
+static void
+ar5315_misc_intr_shutdown(unsigned int irq)
+{
+       ar5315_misc_intr_disable(irq);
+}
+
+static void
+ar5315_misc_intr_ack(unsigned int irq)
+{
+       ar5315_misc_intr_disable(irq);
+}
+
+static void
+ar5315_misc_intr_end(unsigned int irq)
+{
+       if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+               ar5315_misc_intr_enable(irq);
+}
+
+static struct irq_chip ar5315_misc_intr_controller = {
+       .typename       = "AR5315 misc",
+       .startup        = ar5315_misc_intr_startup,
+       .shutdown       = ar5315_misc_intr_shutdown,
+       .enable         = ar5315_misc_intr_enable,
+       .disable        = ar5315_misc_intr_disable,
+       .ack            = ar5315_misc_intr_ack,
+       .end            = ar5315_misc_intr_end,
+};
+
+static irqreturn_t ar5315_ahb_proc_handler(int cpl, void *dev_id)
+{
+    sysRegWrite(AR5315_AHB_ERR0,AHB_ERROR_DET);
+    sysRegRead(AR5315_AHB_ERR1);
+
+    printk("AHB fatal error\n");
+    machine_restart("AHB error"); /* Catastrophic failure */
+
+    return IRQ_HANDLED;
+}
+
+static struct irqaction ar5315_ahb_proc_interrupt  = {
+       .handler        = ar5315_ahb_proc_handler,
+       .flags          = SA_INTERRUPT,
+       .name           = "ar5315_ahb_proc_interrupt",
+};
+
+
+static struct irqaction cascade  = {
+       .handler        = no_action,
+       .flags          = SA_INTERRUPT,
+       .name           = "cascade",
+};
+
+static void ar5315_gpio_intr_init(int irq_base)
+{
+       int i;
+
+       for (i = irq_base; i < irq_base + AR531X_GPIO_IRQ_COUNT; i++) {
+               irq_desc[i].status = IRQ_DISABLED;
+               irq_desc[i].action = NULL;
+               irq_desc[i].depth = 1;
+               irq_desc[i].chip = &ar5315_gpio_intr_controller;
+       }
+       setup_irq(AR531X_MISC_IRQ_GPIO, &cascade);
+       gpiointval = sysRegRead(AR5315_GPIO_DI);
+}
+
+void ar5315_misc_intr_init(int irq_base)
+{
+       int i;
+
+       for (i = irq_base; i < irq_base + AR531X_MISC_IRQ_COUNT; i++) {
+               irq_desc[i].status = IRQ_DISABLED;
+               irq_desc[i].action = NULL;
+               irq_desc[i].depth = 1;
+               irq_desc[i].chip = &ar5315_misc_intr_controller;
+       }
+       setup_irq(AR531X_MISC_IRQ_AHB_PROC, &ar5315_ahb_proc_interrupt);
+       setup_irq(AR5315_IRQ_MISC_INTRS, &cascade);
+       ar5315_gpio_intr_init(AR531X_GPIO_IRQ_BASE);
+}
+
index 56f63030ce822919b7764dca1b5e4da0f20ec990..5256a548ce6c49bfe8c5abaf43e73631321f4f64 100644 (file)
@@ -3,8 +3,32 @@
 
 #include <asm/cpu-info.h>
 #include <ar531x_platform.h>
-#include "ar5312.h"
-#include "ar5315.h"
+#include "ar5312/ar5312.h"
+#include "ar5315/ar5315.h"
+
+
+/*
+ * C access to CLZ instruction
+ * (count leading zeroes).
+ */
+static inline int clz(unsigned long val)
+{
+       int ret;
+
+       __asm__ volatile (
+               ".set\tnoreorder\n\t"
+               ".set\tnoat\n\t"
+               ".set\tmips32\n\t"
+               "clz\t%0,%1\n\t"
+               ".set\tmips0\n\t"
+               ".set\tat\n\t"
+               ".set\treorder"
+               : "=r" (ret)
+               : "r" (val)
+       );
+       
+       return ret;
+}
 
 /*                                                                             
  * Atheros CPUs before the AR2315 are using MIPS 4Kc core, later designs are
 #define DO_AR5315(...)
 #endif
 
-#include <irq.h>
-
-#define AR531X_HIGH_PRIO                0x10
 #define AR531X_MISC_IRQ_BASE           0x20
-#define AR531X_GPIO_IRQ_BASE            0x30
+#define AR531X_GPIO_IRQ_BASE           0x30
 
 /* Software's idea of interrupts handled by "CPU Interrupt Controller" */
 #define AR531X_IRQ_NONE                MIPS_CPU_IRQ_BASE+0
@@ -47,7 +68,8 @@
 #define AR531X_MISC_IRQ_UART0_DMA      AR531X_MISC_IRQ_BASE+6
 #define AR531X_MISC_IRQ_WATCHDOG       AR531X_MISC_IRQ_BASE+7
 #define AR531X_MISC_IRQ_LOCAL          AR531X_MISC_IRQ_BASE+8
-#define AR531X_MISC_IRQ_COUNT          9
+#define AR531X_MISC_IRQ_SPI            AR531X_MISC_IRQ_BASE+9
+#define AR531X_MISC_IRQ_COUNT          10
 
 /* GPIO Interrupts [0..7], share AR531X_MISC_IRQ_GPIO */
 #define AR531X_GPIO_IRQ_NONE            AR531X_MISC_IRQ_BASE+0
@@ -127,5 +149,18 @@ extern void ar5315_prom_init(void);
 extern void ar5315_misc_intr_init(int irq_base);
 extern void ar5315_plat_setup(void);
 extern asmlinkage void ar5315_irq_dispatch(void);
+extern void ar5315_pci_irq(int irq);
+static inline u32 sysRegMask(u32 phys, u32 mask, u32 value)
+{
+       u32 reg;
+       
+       reg = sysRegRead(phys);
+       reg &= ~mask;
+       reg |= value & mask;
+       sysRegWrite(phys, reg);
+       reg = sysRegRead(phys); /* flush write to the hardware */
+
+       return reg;
+}
 
 #endif
index d26eda4d08d5def9ce46df8535f5fe1b99605850..1ea66c0c1913cc398823fe6817f6c79db669629f 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/serial.h>
 #include <linux/serial_core.h>
 #include <asm/bootinfo.h>
+#include <asm/irq_cpu.h>
 #include <asm/io.h>
 #include "ar531x.h"
 
@@ -189,4 +190,18 @@ void __init plat_timer_setup(struct irqaction *irq)
        write_c0_compare(count + 1000);
 }
 
+asmlinkage void plat_irq_dispatch(void)
+{
+       DO_AR5312(ar5312_irq_dispatch();)
+       DO_AR5315(ar5315_irq_dispatch();)
+}
 
+void __init arch_init_irq(void)
+{
+       clear_c0_status(ST0_IM);
+       mips_cpu_irq_init();
+
+       /* Initialize interrupt controllers */
+       DO_AR5312(ar5312_misc_intr_init(AR531X_MISC_IRQ_BASE);)
+       DO_AR5315(ar5315_misc_intr_init(AR531X_MISC_IRQ_BASE);)
+}
diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/irq.c b/target/linux/atheros-2.6/files/arch/mips/atheros/irq.c
deleted file mode 100644 (file)
index 5665aa3..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2003 Atheros Communications, Inc.,  All Rights Reserved.
- * Copyright (C) 2006 FON Technology, SL.
- * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
- * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
- */
-
-/*
- * Interrupt support for AR531X WiSOC.
- */
-
-#include <linux/autoconf.h>
-#include <linux/init.h>
-#include <linux/kernel_stat.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/pm.h>
-#include <linux/delay.h>
-#include <linux/reboot.h>
-#include <linux/irq.h>
-#include <asm/bootinfo.h>
-#include <asm/mipsregs.h>
-#include <asm/irq_cpu.h>
-#include "ar531x.h"
-
-
-/* ARGSUSED */
-irqreturn_t
-spurious_irq_handler(int cpl, void *dev_id)
-{
-    /* 
-    printk("spurious_irq_handler: %d  cause=0x%8.8x  status=0x%8.8x\n",
-          cpl, cause_intrs, status_intrs); 
-    */
-       return IRQ_NONE;
-}
-
-/* ARGSUSED */
-irqreturn_t
-spurious_misc_handler(int cpl, void *dev_id)
-{
-    /*
-    printk("spurious_misc_handler: 0x%x isr=0x%8.8x imr=0x%8.8x\n",
-          cpl, ar531x_isr, ar531x_imr);
-    */
-       return IRQ_NONE;
-}
-
-static struct irqaction spurious_irq  = {
-       .handler        = spurious_irq_handler,
-       .flags          = SA_INTERRUPT,
-       .name           = "spurious_irq",
-};
-
-static struct irqaction spurious_misc  = {
-       .handler        = spurious_misc_handler,
-       .flags          = SA_INTERRUPT,
-       .name           = "spurious_misc",
-};
-
-asmlinkage void plat_irq_dispatch(void)
-{
-       DO_AR5312(ar5312_irq_dispatch();)
-       DO_AR5315(ar5315_irq_dispatch();)
-}
-
-void __init arch_init_irq(void)
-{
-       clear_c0_status(ST0_IM);
-       mips_cpu_irq_init();
-
-       /* Initialize interrupt controllers */
-       DO_AR5312(ar5312_misc_intr_init(AR531X_MISC_IRQ_BASE);)
-       DO_AR5315(ar5315_misc_intr_init(AR531X_MISC_IRQ_BASE);)
-
-       /* Default "spurious interrupt" handlers */
-       setup_irq(AR531X_IRQ_NONE, &spurious_irq);
-       setup_irq(AR531X_MISC_IRQ_NONE, &spurious_misc);
-}
diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/reset.c b/target/linux/atheros-2.6/files/arch/mips/atheros/reset.c
new file mode 100644 (file)
index 0000000..d62c5e1
--- /dev/null
@@ -0,0 +1,108 @@
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/kobject.h>
+#include <linux/workqueue.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <net/sock.h>
+#include <asm/uaccess.h>
+#include "ar531x.h"
+#include "ar5315/ar5315.h"
+
+struct event_t {
+       struct work_struct wq;
+       int set;
+       long int jiffies;
+};
+
+extern struct sock *uevent_sock;
+extern u64 uevent_next_seqnum(void);
+static int seen;
+
+static inline void add_msg(struct sk_buff *skb, char *msg)
+{
+       char *scratch;
+       scratch = skb_put(skb, strlen(msg) + 1);
+       sprintf(scratch, msg);
+}
+
+static void hotplug_button(struct work_struct *wq)
+{
+       struct sk_buff *skb;
+       struct event_t *event;
+       size_t len;
+       char *scratch, *s;
+       char buf[128];
+       
+       event = container_of(wq, struct event_t, wq);
+       if (!uevent_sock)
+               goto done;
+
+       /* allocate message with the maximum possible size */
+       s = event->set ? "pressed" : "released";
+       len = strlen(s) + 2;
+       skb = alloc_skb(len + 2048, GFP_KERNEL);
+       if (!skb)
+               goto done;
+       
+       /* add header */
+       scratch = skb_put(skb, len);
+       sprintf(scratch, "%s@",s);
+
+       /* copy keys to our continuous event payload buffer */
+       add_msg(skb, "HOME=/");
+       add_msg(skb, "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
+       add_msg(skb, "SUBSYSTEM=button");
+       add_msg(skb, "BUTTON=reset");
+       add_msg(skb, (event->set ? "ACTION=pressed" : "ACTION=released"));
+       sprintf(buf, "SEEN=%ld", (event->jiffies - seen)/HZ);
+       add_msg(skb, buf);
+       snprintf(buf, 128, "SEQNUM=%llu", uevent_next_seqnum());
+       add_msg(skb, buf);
+
+       NETLINK_CB(skb).dst_group = 1;
+       netlink_broadcast(uevent_sock, skb, 0, 1, GFP_KERNEL);
+
+done:
+       kfree(event);
+}
+
+static irqreturn_t button_handler(int irq, void *dev_id)
+{
+       static int pressed = 0;
+       struct event_t *event;
+       u32 gpio = ~0;
+
+       event = (struct event_t *) kzalloc(sizeof(struct event_t), GFP_ATOMIC);
+       if (!event)
+               return IRQ_NONE;
+       
+       pressed = !pressed;
+
+       DO_AR5315(gpio = sysRegRead(AR5315_GPIO_DI);)
+       gpio &= 1 << (irq - AR531X_GPIO_IRQ_BASE);
+
+       event->set = gpio;
+       event->jiffies = jiffies;
+
+       INIT_WORK(&event->wq, (void *)(void *)hotplug_button);
+       schedule_work(&event->wq);
+
+       seen = jiffies;
+
+       return IRQ_HANDLED;
+}
+
+int __init ar531x_init_reset(void)
+{
+       struct ar531x_boarddata *bcfg;
+       bcfg = (struct ar531x_boarddata *) board_config;
+
+       seen = jiffies;
+       request_irq(AR531X_GPIO_IRQ_BASE + bcfg->resetConfigGpio, &button_handler, IRQF_SAMPLE_RANDOM, "ar531x_reset", NULL);
+
+       return 0;
+}
+
+module_init(ar531x_init_reset);