/* * Copyright 2001, 2007-2008 MontaVista Software Inc. * Author: MontaVista Software, Inc. <source@mvista.com> * * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* * This may assume that we don't get interrupts from * both edges at once, or if we do, that we don't care.
*/
__raw_writel(1 << bit, base + IC_FALLINGCLR);
__raw_writel(1 << bit, base + IC_RISINGCLR);
wmb();
}
/* * This may assume that we don't get interrupts from * both edges at once, or if we do, that we don't care.
*/
__raw_writel(1 << bit, base + IC_FALLINGCLR);
__raw_writel(1 << bit, base + IC_RISINGCLR);
wmb();
}
__raw_writel(1 << bit, base + IC_WAKECLR);
__raw_writel(1 << bit, base + IC_MASKCLR);
__raw_writel(1 << bit, base + IC_RISINGCLR);
__raw_writel(1 << bit, base + IC_FALLINGCLR);
wmb();
}
staticint au1x_ic1_setwake(struct irq_data *d, unsignedint on)
{ int bit = d->irq - AU1000_INTC1_INT_BASE; unsignedlong wakemsk, flags;
/* only GPIO 0-7 can act as wakeup source. Fortunately these * are wired up identically on all supported variants.
*/ if ((bit < 0) || (bit > 7)) return -EINVAL;
/* * irq_chips for both ICs; this way the mask handlers can be * as short as possible.
*/ staticstruct irq_chip au1x_ic0_chip = {
.name = "Alchemy-IC0",
.irq_ack = au1x_ic0_ack,
.irq_mask = au1x_ic0_mask,
.irq_mask_ack = au1x_ic0_maskack,
.irq_unmask = au1x_ic0_unmask,
.irq_set_type = au1x_ic_settype,
};
/* * au1300_gpic_chgcfg - change PIN configuration. * @gpio: pin to change (0-based GPIO number from datasheet). * @clr: clear all bits set in 'clr'. * @set: set these bits. * * modifies a pins' configuration register, bits set in @clr will * be cleared in the register, bits in @set will be set.
*/ staticinlinevoid au1300_gpic_chgcfg(unsignedint gpio, unsignedlong clr, unsignedlong set)
{ void __iomem *r = AU1300_GPIC_ADDR; unsignedlong l;
r += gpio * 4; /* offset into pin config array */
l = __raw_readl(r + AU1300_GPIC_PINCFG);
l &= ~clr;
l |= set;
__raw_writel(l, r + AU1300_GPIC_PINCFG);
wmb();
}
/* * au1300_pinfunc_to_gpio - assign a pin as GPIO input (GPIO ctrl). * @pin: pin (0-based GPIO number from datasheet). * * Assigns a GPIO pin to the GPIO controller, so its level can either * be read or set through the generic GPIO functions. * If you need a GPOUT, use au1300_gpio_set_value(pin, 0/1). * REVISIT: is this function really necessary?
*/ void au1300_pinfunc_to_gpio(enum au1300_multifunc_pins gpio)
{
au1300_gpio_direction_input(gpio + AU1300_GPIO_BASE);
}
EXPORT_SYMBOL_GPL(au1300_pinfunc_to_gpio);
/* * au1300_pinfunc_to_dev - assign a pin to the device function. * @pin: pin (0-based GPIO number from datasheet). * * Assigns a GPIO pin to its associated device function; the pin will be * driven by the device and not through GPIO functions.
*/ void au1300_pinfunc_to_dev(enum au1300_multifunc_pins gpio)
{ void __iomem *r = AU1300_GPIC_ADDR; unsignedlong bit;
r += GPIC_GPIO_BANKOFF(gpio);
bit = GPIC_GPIO_TO_BIT(gpio);
__raw_writel(bit, r + AU1300_GPIC_DEVSEL);
wmb();
}
EXPORT_SYMBOL_GPL(au1300_pinfunc_to_dev);
/* * au1300_set_irq_priority - set internal priority of IRQ. * @irq: irq to set priority (linux irq number). * @p: priority (0 = highest, 3 = lowest).
*/ void au1300_set_irq_priority(unsignedint irq, int p)
{
irq -= ALCHEMY_GPIC_INT_BASE;
au1300_gpic_chgcfg(irq, GPIC_CFG_IL_MASK, GPIC_CFG_IL_SET(p));
}
EXPORT_SYMBOL_GPL(au1300_set_irq_priority);
/* * au1300_set_dbdma_gpio - assign a gpio to one of the DBDMA triggers. * @dchan: dbdma trigger select (0, 1). * @gpio: pin to assign as trigger. * * DBDMA controller has 2 external trigger sources; this function * assigns a GPIO to the selected trigger.
*/ void au1300_set_dbdma_gpio(int dchan, unsignedint gpio)
{ unsignedlong r;
if ((dchan >= 0) && (dchan <= 1)) {
r = __raw_readl(AU1300_GPIC_ADDR + AU1300_GPIC_DMASEL);
r &= ~(0xff << (8 * dchan));
r |= (gpio & 0x7f) << (8 * dchan);
__raw_writel(r, AU1300_GPIC_ADDR + AU1300_GPIC_DMASEL);
wmb();
}
}
switch (type) { case IRQ_TYPE_LEVEL_HIGH:
s = GPIC_CFG_IC_LEVEL_HIGH;
name = "high";
hdl = handle_level_irq; break; case IRQ_TYPE_LEVEL_LOW:
s = GPIC_CFG_IC_LEVEL_LOW;
name = "low";
hdl = handle_level_irq; break; case IRQ_TYPE_EDGE_RISING:
s = GPIC_CFG_IC_EDGE_RISE;
name = "posedge";
hdl = handle_edge_irq; break; case IRQ_TYPE_EDGE_FALLING:
s = GPIC_CFG_IC_EDGE_FALL;
name = "negedge";
hdl = handle_edge_irq; break; case IRQ_TYPE_EDGE_BOTH:
s = GPIC_CFG_IC_EDGE_BOTH;
name = "bothedge";
hdl = handle_edge_irq; break; case IRQ_TYPE_NONE:
s = GPIC_CFG_IC_OFF;
name = "disabled";
hdl = handle_level_irq; break; default: return -EINVAL;
}
staticinlinevoid ic_init(void __iomem *base)
{ /* initialize interrupt controller to a safe state */
__raw_writel(0xffffffff, base + IC_CFG0CLR);
__raw_writel(0xffffffff, base + IC_CFG1CLR);
__raw_writel(0xffffffff, base + IC_CFG2CLR);
__raw_writel(0xffffffff, base + IC_MASKCLR);
__raw_writel(0xffffffff, base + IC_ASSIGNCLR);
__raw_writel(0xffffffff, base + IC_WAKECLR);
__raw_writel(0xffffffff, base + IC_SRCSET);
__raw_writel(0xffffffff, base + IC_FALLINGCLR);
__raw_writel(0xffffffff, base + IC_RISINGCLR);
__raw_writel(0x00000000, base + IC_TESTBIT);
wmb();
}
__raw_writel(d[0], base + IC_CFG0SET);
__raw_writel(d[1], base + IC_CFG1SET);
__raw_writel(d[2], base + IC_CFG2SET);
__raw_writel(d[3], base + IC_SRCSET);
__raw_writel(d[4], base + IC_ASSIGNSET);
__raw_writel(d[5], base + IC_WAKESET);
wmb();
/* save misc register(s) */
alchemy_gpic_pmdata[4] = __raw_readl(base + AU1300_GPIC_DMASEL);
/* molto silenzioso */
__raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x0);
__raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x4);
__raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x8);
__raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0xc);
wmb();
/* save pin/int-type configuration */
base += AU1300_GPIC_PINCFG; for (i = 0; i < ALCHEMY_GPIC_INT_NUM; i++)
alchemy_gpic_pmdata[i + 5] = __raw_readl(base + (i << 2));
/* disable all first */
__raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x0);
__raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x4);
__raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x8);
__raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0xc);
wmb();
/* restore pin/int-type configurations */
base += AU1300_GPIC_PINCFG; for (i = 0; i < ALCHEMY_GPIC_INT_NUM; i++)
__raw_writel(alchemy_gpic_pmdata[i + 5], base + (i << 2));
wmb();
/* restore misc register(s) */
base = (void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR);
__raw_writel(alchemy_gpic_pmdata[4], base + AU1300_GPIC_DMASEL);
wmb();
/* finally restore masks */
__raw_writel(alchemy_gpic_pmdata[0], base + AU1300_GPIC_IEN + 0x0);
__raw_writel(alchemy_gpic_pmdata[1], base + AU1300_GPIC_IEN + 0x4);
__raw_writel(alchemy_gpic_pmdata[2], base + AU1300_GPIC_IEN + 0x8);
__raw_writel(alchemy_gpic_pmdata[3], base + AU1300_GPIC_IEN + 0xc);
wmb();
}
/* register all 64 possible IC0+IC1 irq sources as type "none". * Use set_irq_type() to set edge/level behaviour at runtime.
*/ for (irq_nr = AU1000_INTC0_INT_BASE;
(irq_nr < AU1000_INTC0_INT_BASE + 32); irq_nr++)
au1x_ic_settype(irq_get_irq_data(irq_nr), IRQ_TYPE_NONE);
/* disable & ack all possible interrupt sources */ for (i = 0; i < 4; i++) {
bank_base = AU1300_GPIC_ADDR + (i * 4);
__raw_writel(~0UL, bank_base + AU1300_GPIC_IDIS);
wmb();
__raw_writel(~0UL, bank_base + AU1300_GPIC_IPEND);
wmb();
}
/* register an irq_chip for them, with 2nd highest priority */ for (i = ALCHEMY_GPIC_INT_BASE; i <= ALCHEMY_GPIC_INT_LAST; i++) {
au1300_set_irq_priority(i, 1);
au1300_gpic_settype(irq_get_irq_data(i), IRQ_TYPE_NONE);
}
/* setup known on-chip sources */ while ((i = dints->irq) != -1) {
au1300_gpic_settype(irq_get_irq_data(i), dints->type);
au1300_set_irq_priority(i, dints->prio);
if (dints->internal)
au1300_pinfunc_to_dev(i - ALCHEMY_GPIC_INT_BASE);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.