Просмотр исходного кода

add gpio support to atheros, fixes #1861, thanks Othello

SVN-Revision: 10724
John Crispin 18 лет назад
Родитель
Сommit
b526f65baf

+ 1 - 1
package/gpioctl/Makefile

@@ -19,7 +19,7 @@ define Package/gpioctl
   SECTION:=utils
   CATEGORY:=Utilities
   TITLE:=Tool for controlling gpio pins
-  DEPENDS:=@LINUX_2_6&&(@TARGET_ixp4xx||@TARGET_brcm47xx)
+  DEPENDS:=@LINUX_2_6&&(@TARGET_ixp4xx||@TARGET_brcm47xx||@TARGET_atheros)
 endef
 
 define Package/gpioctl/description

+ 2 - 1
target/linux/atheros/config-2.6.23

@@ -50,6 +50,7 @@ CONFIG_DMA_NONCOHERENT=y
 CONFIG_FS_POSIX_ACL=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 # CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set
+CONFIG_GPIO_DEVICE=y
 CONFIG_HAS_DMA=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
@@ -127,10 +128,10 @@ CONFIG_MTD_PHYSMAP_START=0x0
 CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-3
 CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_REDBOOT_PARTS_READONLY=y
-# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_SLRAM is not set
 CONFIG_MTD_SPIFLASH=y
+CONFIG_NEW_GPIO=y
 # CONFIG_NO_IOPORT is not set
 # CONFIG_PAGE_SIZE_16KB is not set
 CONFIG_PAGE_SIZE_4KB=y

+ 2 - 0
target/linux/atheros/config-2.6.24

@@ -194,3 +194,5 @@ CONFIG_TRAD_SIGNALS=y
 # CONFIG_USER_NS is not set
 # CONFIG_VGASTATE is not set
 CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NEW_GPIO=y
+CONFIG_GPIO_DEVICE=y

+ 1 - 1
target/linux/atheros/files/arch/mips/atheros/Makefile

@@ -8,6 +8,6 @@
 # Copyright (C) 2006 Felix Fietkau <[email protected]>
 #
 
-obj-y += board.o prom.o reset.o
+obj-y += board.o prom.o reset.o gpio.o
 obj-$(CONFIG_ATHEROS_AR5312) += ar5312/
 obj-$(CONFIG_ATHEROS_AR5315) += ar5315/

+ 1 - 1
target/linux/atheros/files/arch/mips/atheros/ar5312/board.c

@@ -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
 

+ 5 - 1
target/linux/atheros/files/arch/mips/atheros/ar5312/irq.c

@@ -23,7 +23,9 @@
 #include <asm/time.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include "../ar531x.h"
+
+#include <ar531x.h>
+#include <gpio.h>
 
 /*
  * Called when an interrupt is received, this function
@@ -53,6 +55,8 @@ asmlinkage void ar5312_irq_dispatch(void)
 			(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_GPIO)
+			ar5312_gpio_irq_dispatch(); 
 		else if ((ar531x_misc_intrs & AR531X_ISR_UART0))
 			do_IRQ(AR531X_MISC_IRQ_UART0);
 		else if (ar531x_misc_intrs & AR531X_ISR_WD)

+ 1 - 1
target/linux/atheros/files/arch/mips/atheros/ar5315/board.c

@@ -26,7 +26,7 @@
 #include <asm/time.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include "../ar531x.h"
+#include <ar531x.h>
 
 static int is_5315 = 0;
 

+ 3 - 1
target/linux/atheros/files/arch/mips/atheros/ar5315/irq.c

@@ -23,7 +23,9 @@
 #include <asm/bootinfo.h>
 #include <asm/irq_cpu.h>
 #include <asm/io.h>
-#include "../ar531x.h"
+
+#include <ar531x.h>
+#include <gpio.h>
 
 static u32 gpiointmask = 0, gpiointval = 0;
 

+ 22 - 1
target/linux/atheros/files/arch/mips/atheros/board.c

@@ -25,7 +25,7 @@
 #include <asm/bootinfo.h>
 #include <asm/irq_cpu.h>
 #include <asm/io.h>
-#include "ar531x.h"
+#include <ar531x.h>
 
 char *board_config, *radio_config;
 
@@ -216,3 +216,24 @@ void __init arch_init_irq(void)
 	DO_AR5312(ar5312_misc_intr_init(AR531X_MISC_IRQ_BASE);)
 	DO_AR5315(ar5315_misc_intr_init(AR531X_MISC_IRQ_BASE);)
 }
+
+static int __init ar531x_register_gpiodev(void)
+{
+	static struct resource res = {
+		.start = 0xFFFFFFFF,
+	};
+	struct platform_device *pdev;
+
+	printk(KERN_INFO "ar531x: Registering GPIODEV device\n");
+	
+	pdev = platform_device_register_simple("GPIODEV", 0, &res, 1);
+
+	if (!pdev) {
+		printk(KERN_ERR "ar531x: GPIODEV init failed\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+device_initcall(ar531x_register_gpiodev);

+ 339 - 0
target/linux/atheros/files/arch/mips/atheros/gpio.c

@@ -0,0 +1,339 @@
+/*
+ * 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 <[email protected]>
+ * Copyright (C) 2007 Othello <[email protected]>
+ */
+
+/*
+ * Support for AR531X GPIO -- General Purpose Input/Output Pins
+ */
+
+#include <linux/autoconf.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+
+#include <asm/addrspace.h>
+#include <asm/io.h>
+#include <asm/irq_cpu.h>
+#include <asm/gpio.h>
+#include "ar531x.h"
+/* 
+   GPIO Interrupt Support
+      Make use of request_irq() and the function gpio_to_irq() to trap gpio events
+ */
+
+/* Global variables */
+static u32 ar531x_gpio_intr_Mask = 0;
+/*
+    AR5312: I don't have any devices with this chip. Assumed to be similar to AR5215
+    will someone who has one try the code and remove this message if it works?
+ */
+
+#ifdef CONFIG_ATHEROS_AR5315
+/*
+    AR5315: Up to 2 GPIO pins may be monitored simultaneously
+    specifying more pins if you already have 2 will not have any effect
+        however, the excess gpio irqs will also be triggered if a valid gpio being monitored triggers
+    only high, low or edge triggered interrupt supported
+ */
+static unsigned int ar5315_gpio_set_type_gpio = 0;
+static unsigned int ar5315_gpio_set_type_lvl = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
+#endif
+
+#ifdef CONFIG_ATHEROS_AR5312
+/* Enable the specified AR5312_GPIO_IRQ interrupt */
+static void ar5312_gpio_intr_enable(unsigned int irq) {
+	u32 reg;
+	unsigned int gpio;
+	unsigned int imr;
+
+	gpio = irq - (AR531X_GPIO_IRQ(0));
+	if (gpio >= AR531X_NUM_GPIO)
+		return;
+	ar531x_gpio_intr_Mask |= (1<<gpio);
+
+	reg = sysRegRead(AR531X_GPIO_CR);
+	reg &= ~(AR531X_GPIO_CR_M(gpio) | AR531X_GPIO_CR_UART(gpio) | AR531X_GPIO_CR_INT(gpio));
+	reg |= AR531X_GPIO_CR_I(gpio);
+	reg |= AR531X_GPIO_CR_INT(gpio);
+
+	sysRegWrite(AR531X_GPIO_CR, reg);
+	(void)sysRegRead(AR531X_GPIO_CR); /* flush to hardware */
+
+	imr = sysRegRead(AR531X_IMR);
+	imr |= AR531X_ISR_GPIO;
+	sysRegWrite(AR531X_IMR, imr);
+	imr = sysRegRead(AR531X_IMR); /* flush write buffer */
+}
+
+/* Disable the specified AR5312_GPIO_IRQ interrupt */
+static void ar5312_gpio_intr_disable(unsigned int irq) {
+	u32 reg;
+	unsigned int gpio;
+	gpio = irq - (AR531X_GPIO_IRQ(0));
+	if (gpio >= AR531X_NUM_GPIO)
+		return;
+
+	reg = sysRegRead(AR531X_GPIO_CR);
+	reg &= ~(AR531X_GPIO_CR_M(gpio) | AR531X_GPIO_CR_UART(gpio) | AR531X_GPIO_CR_INT(gpio));
+	reg |= AR531X_GPIO_CR_I(gpio);
+	/* No GPIO_CR_INT bit */
+
+	sysRegWrite(AR531X_GPIO_CR, reg);
+	(void)sysRegRead(AR531X_GPIO_CR); /* flush to hardware */
+
+	/* Disable Interrupt if no gpio needs triggering */
+	if (ar531x_gpio_intr_Mask != 0) {
+		unsigned int imr;
+
+		imr = sysRegRead(AR531X_IMR);
+		imr &= ~AR531X_ISR_GPIO;
+		sysRegWrite(AR531X_IMR, imr);
+		imr = sysRegRead(AR531X_IMR); /* flush write buffer */
+	}
+
+	ar531x_gpio_intr_Mask &= ~(1<<gpio);
+}
+
+/* Turn on the specified AR5312_GPIO_IRQ interrupt */
+static unsigned int ar5312_gpio_intr_startup(unsigned int irq) {
+	ar5312_gpio_intr_enable(irq);
+	return 0;
+}
+
+static void ar5312_gpio_intr_end(unsigned int irq) {
+	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+		ar5312_gpio_intr_enable(irq);
+}
+
+asmlinkage void ar5312_gpio_irq_dispatch(void) {
+	int i;
+	u32 gpioIntPending;
+	gpioIntPending = sysRegRead(AR531X_GPIO_DI) & ar531x_gpio_intr_Mask;
+	sysRegWrite(AR531X_ISR, sysRegRead(AR531X_IMR) | ~AR531X_ISR_GPIO);
+	for (i=0; i<AR531X_GPIO_IRQ_COUNT; i++) {
+	if (gpioIntPending & (1 << i))
+		do_IRQ(AR531X_GPIO_IRQ(i));
+	}
+}
+#endif	/* #ifdef CONFIG_ATHEROS_AR5312 */
+
+#ifdef CONFIG_ATHEROS_AR5315
+/* Enable the specified AR5315_GPIO_IRQ interrupt */
+static void ar5315_gpio_intr_enable(unsigned int irq) {
+	u32 reg;
+	unsigned int gpio;
+	unsigned int imr;
+	unsigned int i;
+
+	gpio = irq - (AR531X_GPIO_IRQ(0));
+	if (gpio >= AR5315_NUM_GPIO)
+		return;
+	ar531x_gpio_intr_Mask |= (1<<gpio);
+
+	reg = sysRegRead(AR5315_GPIO_CR);
+	reg &= ~(AR5315_GPIO_CR_M(gpio));
+	reg |= AR5315_GPIO_CR_I(gpio);
+	sysRegWrite(AR5315_GPIO_CR, reg);
+	(void)sysRegRead(AR5315_GPIO_CR); /* flush write to hardware */
+
+	/* Locate a free register slot to enable gpio intr 
+	   will fail silently if no more slots are available
+	 */
+	reg = sysRegRead(AR5315_GPIO_INT);
+	for (i=0 ; i<=AR5315_GPIO_INT_MAX_Y ; i++) {
+		/* Free slot means trigger level = 0 */
+		if ( AR5315_GPIO_INT_LVL_OFF ==
+		    (reg & AR5315_GPIO_INT_LVL_M) ) {
+
+			unsigned int def_lvl = AR5315_GPIO_INT_LVL_EDGE;
+			if (ar5315_gpio_set_type_gpio == gpio)
+				def_lvl = ar5315_gpio_set_type_lvl;
+
+			/* Set the gpio level trigger mode */
+/*			reg &= ~(AR5315_GPIO_INT_LVL_M(i)); */
+			reg |= AR5315_GPIO_INT_LVL(i);
+
+			/* Enable the gpio pin */
+			reg &= ~(AR5315_GPIO_INT_M);
+			reg |= AR5315_GPIO_INT_S(i);
+
+			sysRegWrite(AR5315_GPIO_INT, reg);
+			(void)sysRegRead(AR5315_GPIO_INT); /* flush write to hardware */
+
+			/* break out of for loop */
+			break;
+		} /* end if trigger level for slot i is 0 */
+	} /* end for each slot */
+
+	imr = sysRegRead(AR5315_IMR);
+	imr |= AR5315_ISR_GPIO;
+	sysRegWrite(AR5315_IMR, imr);
+	imr = sysRegRead(AR5315_IMR); /* flush write buffer */
+}
+
+
+/* Disable the specified AR5315_GPIO_IRQ interrupt */
+static void ar5315_gpio_intr_disable(unsigned int irq) {
+	u32 reg;
+	unsigned int gpio;
+	unsigned int i;
+
+	gpio = irq - (AR531X_GPIO_IRQ(0));
+	if (gpio >= AR5315_NUM_GPIO)
+		return;
+
+	reg = sysRegRead(AR5315_GPIO_CR);
+	reg &= ~(AR5315_GPIO_CR_M(gpio));
+	reg |= AR5315_GPIO_CR_I(gpio);
+	sysRegWrite(AR5315_GPIO_CR, reg);
+	(void)sysRegRead(AR5315_GPIO_CR); /* flush write to hardware */
+
+	/* Locate a the correct register slot to disable gpio intr */
+	reg = sysRegRead(AR5315_GPIO_INT);
+	for (i=0 ; i<=AR5315_GPIO_INT_MAX_Y ; i++) {
+		/* If this correct  */
+		if ( AR5315_GPIO_INT_S(i) ==
+		    (reg & AR5315_GPIO_INT_M) ) {
+			/* Clear the gpio level trigger mode */
+			reg &= ~(AR5315_GPIO_INT_LVL_M);
+
+			sysRegWrite(AR5315_GPIO_INT, reg);
+			(void)sysRegRead(AR5315_GPIO_INT); /* flush write to hardware */
+			break;
+		} /* end if trigger level for slot i is 0 */
+	} /* end for each slot */
+
+	/* Disable interrupt only if no gpio needs triggering */
+	if (ar531x_gpio_intr_Mask != 0) {
+		unsigned int imr;
+
+		imr = sysRegRead(AR5315_IMR);
+		imr &= ~AR5315_ISR_GPIO;
+		sysRegWrite(AR5315_IMR, imr);
+		imr = sysRegRead(AR5315_IMR); /* flush write buffer */
+	}
+
+	ar531x_gpio_intr_Mask &= ~(1<<gpio);
+}
+
+/* Turn on the specified AR5315_GPIO_IRQ interrupt */
+static unsigned int ar5315_gpio_intr_startup(unsigned int irq) {
+	ar5315_gpio_intr_enable(irq);
+	return 0;
+}
+
+static void ar5315_gpio_intr_end(unsigned int irq) {
+	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+		ar5315_gpio_intr_enable(irq);
+}
+
+static int ar5315_gpio_intr_set_type(unsigned int irq, unsigned int flow_type) {
+	ar5315_gpio_set_type_gpio = irq - (AR531X_GPIO_IRQ(0));
+	if (ar5315_gpio_set_type_gpio > AR5315_NUM_GPIO)
+		return -EINVAL;
+	switch (flow_type & IRQF_TRIGGER_MASK) {
+		case IRQF_TRIGGER_RISING:
+		case IRQF_TRIGGER_FALLING:
+			printk(KERN_WARNING "AR5315 GPIO %u falling back to edge triggered\n", ar5315_gpio_set_type_gpio);
+		case IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING:
+			ar5315_gpio_set_type_lvl = AR5315_GPIO_INT_LVL_EDGE;
+			break;
+		case IRQF_TRIGGER_LOW:
+			ar5315_gpio_set_type_lvl = AR5315_GPIO_INT_LVL_LOW;
+			break;
+		case IRQF_TRIGGER_HIGH:
+			ar5315_gpio_set_type_lvl = AR5315_GPIO_INT_LVL_HIGH;
+			break;
+		default:
+			return -EINVAL;
+	}
+	return 0;
+}
+
+asmlinkage void ar5315_gpio_irq_dispatch(void){
+	int i;
+	u32 gpioIntPending;
+	gpioIntPending = sysRegRead(AR5315_GPIO_DI) & ar531x_gpio_intr_Mask;
+	sysRegWrite(AR5315_ISR, sysRegRead(AR5315_IMR) | ~AR5315_ISR_GPIO);
+	for (i=0; i<AR531X_GPIO_IRQ_COUNT; i++) {
+	if (gpioIntPending & (1 << i))
+		do_IRQ(AR531X_GPIO_IRQ(i));
+	}
+}
+#endif /* #ifdef CONFIG_ATHEROS_AR5315  */
+
+/* Common Code */
+static struct irq_chip ar531x_gpio_intr_controller = {
+	.typename	= "AR531X GPIO",
+};
+
+/* ARGSUSED */
+irqreturn_t
+spurious_gpio_handler(int cpl, void *dev_id)
+{
+	u32 gpioDataIn;
+	DO_AR5312(gpioDataIn = sysRegRead(AR531X_GPIO_DI);)
+	DO_AR5315(gpioDataIn = sysRegRead(AR5315_GPIO_DI);)
+
+	printk("spurious_gpio_handler: 0x%08x dev=%p DI=0x%08x gpioIntMask=0x%08x\n",
+		cpl, dev_id, gpioDataIn, ar531x_gpio_intr_Mask);
+
+	return IRQ_NONE;
+}
+
+static struct irqaction spurious_gpio  = {
+	.handler	= spurious_gpio_handler,
+	.name		= "spurious_gpio",
+};
+
+/* Initialize AR531X GPIO interrupts */
+static int __init ar531x_gpio_init(void)
+{
+	int i;
+
+	DO_AR5312( \
+		ar531x_gpio_intr_controller.startup = ar5312_gpio_intr_startup; \
+		ar531x_gpio_intr_controller.shutdown = ar5312_gpio_intr_disable; \
+		ar531x_gpio_intr_controller.enable = ar5312_gpio_intr_enable; \
+		ar531x_gpio_intr_controller.disable = ar5312_gpio_intr_disable; \
+		ar531x_gpio_intr_controller.ack = ar5312_gpio_intr_disable; \
+		ar531x_gpio_intr_controller.end = ar5312_gpio_intr_end; \
+	)
+
+	DO_AR5315( \
+		ar531x_gpio_intr_controller.startup = ar5315_gpio_intr_startup; \
+		ar531x_gpio_intr_controller.shutdown = ar5315_gpio_intr_disable; \
+		ar531x_gpio_intr_controller.enable = ar5315_gpio_intr_enable; \
+		ar531x_gpio_intr_controller.disable = ar5315_gpio_intr_disable; \
+		ar531x_gpio_intr_controller.ack = ar5315_gpio_intr_disable; \
+		ar531x_gpio_intr_controller.end = ar5315_gpio_intr_end; \
+		ar531x_gpio_intr_controller.set_type = ar5315_gpio_intr_set_type; \
+	)
+
+	for (i = AR531X_GPIO_IRQ_BASE;
+	     i < AR531X_GPIO_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 = &ar531x_gpio_intr_controller;
+	}
+
+	setup_irq(AR531X_GPIO_IRQ_NONE, &spurious_gpio);
+
+	return 0;
+}
+
+subsys_initcall(ar531x_gpio_init);
+

+ 1 - 1
target/linux/atheros/files/arch/mips/atheros/prom.c

@@ -23,7 +23,7 @@
 
 #include <asm/bootinfo.h>
 #include <asm/addrspace.h>
-#include "ar531x.h"
+#include <ar531x.h>
 
 void __init prom_init(void)
 {

+ 1 - 2
target/linux/atheros/files/arch/mips/atheros/reset.c

@@ -7,8 +7,7 @@
 #include <linux/netlink.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
-#include "ar531x.h"
-#include "ar5315/ar5315.h"
+#include <ar531x.h>
 
 #define AR531X_RESET_GPIO_IRQ	(AR531X_GPIO_IRQ_BASE + bcfg->resetConfigGpio)
 

+ 0 - 0
target/linux/atheros/files/arch/mips/atheros/ar5312/ar5312.h → target/linux/atheros/files/include/asm-mips/mach-atheros/ar5312/ar5312.h


+ 6 - 0
target/linux/atheros/files/arch/mips/atheros/ar5315/ar5315.h → target/linux/atheros/files/include/asm-mips/mach-atheros/ar5315/ar5315.h

@@ -349,6 +349,12 @@
 #define AR5315_GPIO_INT_LVL(x)             ((x) << 6)                  /* interrupt level */
 #define AR5315_GPIO_INT_LVL_M              ((0x3) << 6)                /* mask for int level */
 
+#define AR5315_GPIO_INT_MAX_Y				1   /* Maximum value of Y for AR5313_GPIO_INT_* macros */
+#define AR5315_GPIO_INT_LVL_OFF				0   /* Triggerring off */
+#define AR5315_GPIO_INT_LVL_LOW				1   /* Low Level Triggered */
+#define AR5315_GPIO_INT_LVL_HIGH			2   /* High Level Triggered */
+#define AR5315_GPIO_INT_LVL_EDGE			3   /* Edge Triggered */
+
 #define AR5315_RESET_GPIO       5
 #define AR5315_NUM_GPIO         22
 

+ 6 - 4
target/linux/atheros/files/arch/mips/atheros/ar531x.h → target/linux/atheros/files/include/asm-mips/mach-atheros/ar531x.h

@@ -4,8 +4,8 @@
 #include <linux/version.h>
 #include <asm/cpu-info.h>
 #include <ar531x_platform.h>
-#include "ar5312/ar5312.h"
-#include "ar5315/ar5315.h"
+#include <ar5312/ar5312.h>
+#include <ar5315/ar5315.h>
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24))
 extern void (*board_time_init)(void);
@@ -76,8 +76,8 @@ static inline int clz(unsigned long val)
 #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
-#define AR531X_GPIO_IRQ(n)              AR531X_MISC_IRQ_BASE+(n)+1
+#define AR531X_GPIO_IRQ_NONE            AR531X_GPIO_IRQ_BASE+0
+#define AR531X_GPIO_IRQ(n)              AR531X_GPIO_IRQ_BASE+(n)+1
 #define AR531X_GPIO_IRQ_COUNT           22
 
 #define sysRegRead(phys)	\
@@ -167,4 +167,6 @@ static inline u32 sysRegMask(u32 phys, u32 mask, u32 value)
 	return reg;
 }
 
+#define AR531X_NUM_GPIO		8
+
 #endif

+ 134 - 0
target/linux/atheros/files/include/asm-mips/mach-atheros/gpio.h

@@ -0,0 +1,134 @@
+#ifndef _ATHEROS_GPIO_H_
+#define _ATHEROS_GPIO_H_
+
+#include "ar531x.h"
+
+/* Common AR531X global variables */
+/* extern u32 ar531x_gpio_intr_Mask; */
+
+/* AR5312 exported routines */
+#ifdef CONFIG_ATHEROS_AR5312
+asmlinkage void ar5312_gpio_irq_dispatch(void);
+#endif
+
+/* AR5315 exported routines */
+#ifdef CONFIG_ATHEROS_AR5315
+asmlinkage void ar5315_gpio_irq_dispatch(void);
+#endif
+
+/*
+ * Wrappers for the generic GPIO layer
+ */
+
+/* Sets a gpio to input, or returns ENXIO for non-existent gpio */
+static inline int gpio_direction_input(unsigned gpio) {
+	DO_AR5312(	if (gpio > AR531X_NUM_GPIO) {			\
+				return -ENXIO;				\
+			} else {					\
+				sysRegWrite(AR531X_GPIO_CR,		\
+					( sysRegRead(AR531X_GPIO_CR) &	\
+					  ~(AR531X_GPIO_CR_M(gpio)) ) |	\
+					  AR531X_GPIO_CR_I(gpio) );	\
+				return 0;				\
+			}						\
+	)
+	DO_AR5315(	if (gpio > AR5315_NUM_GPIO) {			\
+				return -ENXIO;				\
+			} else {					\
+				sysRegWrite(AR5315_GPIO_CR,		\
+					( sysRegRead(AR5315_GPIO_CR) &	\
+					  ~(AR5315_GPIO_CR_M(gpio)) ) |	\
+					  AR5315_GPIO_CR_I(gpio) );	\
+				return 0;				\
+			}						\
+	)
+}
+
+/* Sets a gpio to output with value, or returns ENXIO for non-existent gpio */
+static inline int gpio_direction_output(unsigned gpio, int value) {
+	DO_AR5312(	if (gpio > AR531X_NUM_GPIO) {			\
+				return -ENXIO;				\
+			} else {					\
+				sysRegWrite(AR531X_GPIO_DO,		\
+					( (sysRegRead(AR531X_GPIO_DO) &	\
+					  ~(1 << gpio) ) |		\
+					  ((value!=0) << gpio)) );	\
+				sysRegWrite(AR531X_GPIO_CR,		\
+					sysRegRead(AR531X_GPIO_CR) |	\
+					AR531X_GPIO_CR_O(gpio) );	\
+				return 0;				\
+			}						\
+	)
+	DO_AR5315(	if (gpio > AR5315_NUM_GPIO) {			\
+				return -ENXIO;				\
+			} else {					\
+				sysRegWrite(AR5315_GPIO_DO,		\
+					( (sysRegRead(AR5315_GPIO_DO) &	\
+					  ~(1 << gpio)) |		\
+					  ((value!=0) << gpio)) );	\
+				sysRegWrite(AR5315_GPIO_CR,		\
+					sysRegRead(AR5315_GPIO_CR) |	\
+					AR5315_GPIO_CR_O(gpio) );	\
+				return 0;				\
+			}						\
+	)
+}
+
+/* Reads the gpio pin.  Unchecked function */
+static inline int gpio_get_value(unsigned gpio) {
+	DO_AR5312(return (sysRegRead(AR531X_GPIO_DI) & (1 << gpio));)
+	DO_AR5315(return (sysRegRead(AR5315_GPIO_DI) & (1 << gpio));)
+}
+
+/* Writes to the gpio pin.  Unchecked function */
+static inline void gpio_set_value(unsigned gpio, int value) {
+	DO_AR5312(	sysRegWrite(AR531X_GPIO_DO,	\
+			( (sysRegRead(AR531X_GPIO_DO) &	\
+			  ~(1 << gpio)) |		\
+			  ((value!=0) << gpio)) );	\
+	)
+	DO_AR5315(	sysRegWrite(AR5315_GPIO_DO,	\
+			( (sysRegRead(AR5315_GPIO_DO) &	\
+			  ~(1 << gpio)) |		\
+			  ((value!=0) << gpio)) );	\
+	)
+}
+
+static inline int gpio_request(unsigned gpio, const char *label) {
+	return 0;
+}
+
+static inline void gpio_free(unsigned gpio) {
+}
+
+/* Returns IRQ to attach for gpio.  Unchecked function */
+static inline int gpio_to_irq(unsigned gpio) {
+	return AR531X_GPIO_IRQ(gpio);
+}
+
+/* Returns gpio for IRQ attached.  Unchecked function */
+static inline int irq_to_gpio(unsigned irq) {
+	return (irq - (AR531X_GPIO_IRQ(0)));
+}
+
+/* #include <asm-generic/gpio.h> */ /* cansleep wrappers */
+/* platforms that don't directly support access to GPIOs through I2C, SPI,
+ * or other blocking infrastructure can use these wrappers.
+ */
+
+static inline int gpio_cansleep(unsigned gpio) {
+        return 0;
+}
+
+static inline int gpio_get_value_cansleep(unsigned gpio) {
+        might_sleep();
+        return gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value_cansleep(unsigned gpio, int value) {
+        might_sleep();
+        gpio_set_value(gpio, value);
+}
+
+#endif
+

+ 5 - 4
target/linux/atheros/patches-2.6.23/100-board.patch

@@ -1,7 +1,7 @@
 diff -urN linux.old/arch/mips/Kconfig linux.dev/arch/mips/Kconfig
 --- linux.old/arch/mips/Kconfig	2007-02-02 23:55:52.912446784 +0100
 +++ linux.dev/arch/mips/Kconfig	2007-02-03 21:50:25.262027104 +0100
-@@ -45,6 +45,15 @@
+@@ -44,6 +44,16 @@
  	  note that a kernel built with this option selected will not be
  	  able to run on normal units.
  
@@ -13,18 +13,19 @@ diff -urN linux.old/arch/mips/Kconfig linux.dev/arch/mips/Kconfig
 +	select SYS_HAS_CPU_MIPS32_R1
 +	select SYS_SUPPORTS_BIG_ENDIAN
 +	select SYS_SUPPORTS_32BIT_KERNEL
++	select GENERIC_GPIO
 +
  config MIPS_COBALT
  	bool "Cobalt Server"
  	select DMA_NONCOHERENT
-@@ -658,6 +668,7 @@
+@@ -597,6 +607,7 @@
  
  endchoice
  
 +source "arch/mips/atheros/Kconfig"
  source "arch/mips/au1000/Kconfig"
- source "arch/mips/ddb5xxx/Kconfig"
- source "arch/mips/gt64120/ev64120/Kconfig"
+ source "arch/mips/jazz/Kconfig"
+ source "arch/mips/pmc-sierra/Kconfig"
 diff -urN linux.old/arch/mips/Makefile linux.dev/arch/mips/Makefile
 --- linux.old/arch/mips/Makefile	2007-02-02 23:55:52.913446632 +0100
 +++ linux.dev/arch/mips/Makefile	2007-02-03 17:40:29.193776000 +0100

+ 2 - 1
target/linux/atheros/patches-2.6.24/100-board.patch

@@ -1,7 +1,7 @@
 diff -urN linux.old/arch/mips/Kconfig linux.dev/arch/mips/Kconfig
 --- linux.old/arch/mips/Kconfig	2007-02-02 23:55:52.912446784 +0100
 +++ linux.dev/arch/mips/Kconfig	2007-02-03 21:50:25.262027104 +0100
-@@ -45,6 +45,17 @@
+@@ -45,6 +45,18 @@
  	  note that a kernel built with this option selected will not be
  	  able to run on normal units.
  
@@ -15,6 +15,7 @@ diff -urN linux.old/arch/mips/Kconfig linux.dev/arch/mips/Kconfig
 +	select SYS_HAS_CPU_MIPS32_R1
 +	select SYS_SUPPORTS_BIG_ENDIAN
 +	select SYS_SUPPORTS_32BIT_KERNEL
++	select GENERIC_GPIO
 +
  config MIPS_COBALT
  	bool "Cobalt Server"