/* * 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 * Copyright (C) 2007 Othello */ /* * Support for AR531X GPIO -- General Purpose Input/Output Pins */ #include #include #include #include #include #include #include #include #include #include #include #include #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<= 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<= AR5315_NUM_GPIO) return; ar531x_gpio_intr_Mask |= (1<= 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< 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