📄 locomo.c
字号:
/* * linux/arch/arm/common/locomo.c * * Sharp LoCoMo support * * 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. * * This file contains all generic LoCoMo support. * * All initialization functions provided here are intended to be called * from machine specific code with proper arguments when required. * * Based on sa1111.c */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/device.h>#include <linux/slab.h>#include <linux/spinlock.h>#include <asm/hardware.h>#include <asm/mach-types.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/mach/irq.h>#include <asm/hardware/locomo.h>/* the following is the overall data for the locomo chip */struct locomo { struct device *dev; unsigned long phys; unsigned int irq; void *base;};struct locomo_dev_info { unsigned long offset; unsigned long length; unsigned int devid; unsigned int irq[1]; const char * name;};static struct locomo_dev_info locomo_devices[] = {};/** LoCoMo interrupt handling stuff. * NOTE: LoCoMo has a 1 to many mapping on all of its IRQs. * that is, there is only one real hardware interrupt * we determine which interrupt it is by reading some IO memory. * We have two levels of expansion, first in the handler for the * hardware interrupt we generate an interrupt * IRQ_LOCOMO_*_BASE and those handlers generate more interrupts * * hardware irq reads LOCOMO_ICR & 0x0f00 * IRQ_LOCOMO_KEY_BASE * IRQ_LOCOMO_GPIO_BASE * IRQ_LOCOMO_LT_BASE * IRQ_LOCOMO_SPI_BASE * IRQ_LOCOMO_KEY_BASE reads LOCOMO_KIC & 0x0001 * IRQ_LOCOMO_KEY * IRQ_LOCOMO_GPIO_BASE reads LOCOMO_GIR & LOCOMO_GPD & 0xffff * IRQ_LOCOMO_GPIO[0-15] * IRQ_LOCOMO_LT_BASE reads LOCOMO_LTINT & 0x0001 * IRQ_LOCOMO_LT * IRQ_LOCOMO_SPI_BASE reads LOCOMO_SPIIR & 0x000F * IRQ_LOCOMO_SPI_RFR * IRQ_LOCOMO_SPI_RFW * IRQ_LOCOMO_SPI_OVRN * IRQ_LOCOMO_SPI_TEND */#define LOCOMO_IRQ_START (IRQ_LOCOMO_KEY_BASE)#define LOCOMO_IRQ_KEY_START (IRQ_LOCOMO_KEY)#define LOCOMO_IRQ_GPIO_START (IRQ_LOCOMO_GPIO0)#define LOCOMO_IRQ_LT_START (IRQ_LOCOMO_LT)#define LOCOMO_IRQ_SPI_START (IRQ_LOCOMO_SPI_RFR)static void locomo_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs){ int req, i; struct irqdesc *d; void *mapbase = get_irq_chipdata(irq); /* Acknowledge the parent IRQ */ desc->chip->ack(irq); /* check why this interrupt was generated */ req = locomo_readl(mapbase + LOCOMO_ICR) & 0x0f00; if (req) { /* generate the next interrupt(s) */ irq = LOCOMO_IRQ_START; d = irq_desc + irq; for (i = 0; i <= 3; i++, d++, irq++) { if (req & (0x0100 << i)) { d->handle(irq, d, regs); } } }}static void locomo_ack_irq(unsigned int irq){}static void locomo_mask_irq(unsigned int irq){ void *mapbase = get_irq_chipdata(irq); unsigned int r; r = locomo_readl(mapbase + LOCOMO_ICR); r &= ~(0x0010 << (irq - LOCOMO_IRQ_START)); locomo_writel(r, mapbase + LOCOMO_ICR);}static void locomo_unmask_irq(unsigned int irq){ void *mapbase = get_irq_chipdata(irq); unsigned int r; r = locomo_readl(mapbase + LOCOMO_ICR); r |= (0x0010 << (irq - LOCOMO_IRQ_START)); locomo_writel(r, mapbase + LOCOMO_ICR);}static struct irqchip locomo_chip = { .ack = locomo_ack_irq, .mask = locomo_mask_irq, .unmask = locomo_unmask_irq,};static void locomo_key_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs){ struct irqdesc *d; void *mapbase = get_irq_chipdata(irq); if (locomo_readl(mapbase + LOCOMO_KIC) & 0x0001) { d = irq_desc + LOCOMO_IRQ_KEY_START; d->handle(LOCOMO_IRQ_KEY_START, d, regs); }}static void locomo_key_ack_irq(unsigned int irq){ void *mapbase = get_irq_chipdata(irq); unsigned int r; r = locomo_readl(mapbase + LOCOMO_KIC); r &= ~(0x0100 << (irq - LOCOMO_IRQ_KEY_START)); locomo_writel(r, mapbase + LOCOMO_KIC);}static void locomo_key_mask_irq(unsigned int irq){ void *mapbase = get_irq_chipdata(irq); unsigned int r; r = locomo_readl(mapbase + LOCOMO_KIC); r &= ~(0x0010 << (irq - LOCOMO_IRQ_KEY_START)); locomo_writel(r, mapbase + LOCOMO_KIC);}static void locomo_key_unmask_irq(unsigned int irq){ void *mapbase = get_irq_chipdata(irq); unsigned int r; r = locomo_readl(mapbase + LOCOMO_KIC); r |= (0x0010 << (irq - LOCOMO_IRQ_KEY_START)); locomo_writel(r, mapbase + LOCOMO_KIC);}static struct irqchip locomo_key_chip = { .ack = locomo_key_ack_irq, .mask = locomo_key_mask_irq, .unmask = locomo_key_unmask_irq,};static void locomo_gpio_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs){ int req, i; struct irqdesc *d; void *mapbase = get_irq_chipdata(irq); req = locomo_readl(mapbase + LOCOMO_GIR) & locomo_readl(mapbase + LOCOMO_GPD) & 0xffff; if (req) { irq = LOCOMO_IRQ_GPIO_START; d = irq_desc + LOCOMO_IRQ_GPIO_START; for (i = 0; i <= 15; i++, irq++, d++) { if (req & (0x0001 << i)) { d->handle(irq, d, regs); } } }}static void locomo_gpio_ack_irq(unsigned int irq){ void *mapbase = get_irq_chipdata(irq); unsigned int r; r = locomo_readl(mapbase + LOCOMO_GWE); r |= (0x0001 << (irq - LOCOMO_IRQ_GPIO_START)); locomo_writel(r, mapbase + LOCOMO_GWE); r = locomo_readl(mapbase + LOCOMO_GIS); r &= ~(0x0001 << (irq - LOCOMO_IRQ_GPIO_START)); locomo_writel(r, mapbase + LOCOMO_GIS); r = locomo_readl(mapbase + LOCOMO_GWE); r &= ~(0x0001 << (irq - LOCOMO_IRQ_GPIO_START)); locomo_writel(r, mapbase + LOCOMO_GWE);}static void locomo_gpio_mask_irq(unsigned int irq){ void *mapbase = get_irq_chipdata(irq); unsigned int r; r = locomo_readl(mapbase + LOCOMO_GIE); r &= ~(0x0001 << (irq - LOCOMO_IRQ_GPIO_START)); locomo_writel(r, mapbase + LOCOMO_GIE);}static void locomo_gpio_unmask_irq(unsigned int irq){ void *mapbase = get_irq_chipdata(irq); unsigned int r; r = locomo_readl(mapbase + LOCOMO_GIE); r |= (0x0001 << (irq - LOCOMO_IRQ_GPIO_START)); locomo_writel(r, mapbase + LOCOMO_GIE);}static struct irqchip locomo_gpio_chip = { .ack = locomo_gpio_ack_irq, .mask = locomo_gpio_mask_irq, .unmask = locomo_gpio_unmask_irq,};static void locomo_lt_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs){ struct irqdesc *d; void *mapbase = get_irq_chipdata(irq); if (locomo_readl(mapbase + LOCOMO_LTINT) & 0x0001) { d = irq_desc + LOCOMO_IRQ_LT_START; d->handle(LOCOMO_IRQ_LT_START, d, regs); }}static void locomo_lt_ack_irq(unsigned int irq){ void *mapbase = get_irq_chipdata(irq); unsigned int r; r = locomo_readl(mapbase + LOCOMO_LTINT); r &= ~(0x0100 << (irq - LOCOMO_IRQ_LT_START)); locomo_writel(r, mapbase + LOCOMO_LTINT);}static void locomo_lt_mask_irq(unsigned int irq){ void *mapbase = get_irq_chipdata(irq); unsigned int r; r = locomo_readl(mapbase + LOCOMO_LTINT); r &= ~(0x0010 << (irq - LOCOMO_IRQ_LT_START)); locomo_writel(r, mapbase + LOCOMO_LTINT);}static void locomo_lt_unmask_irq(unsigned int irq){ void *mapbase = get_irq_chipdata(irq); unsigned int r; r = locomo_readl(mapbase + LOCOMO_LTINT); r |= (0x0010 << (irq - LOCOMO_IRQ_LT_START)); locomo_writel(r, mapbase + LOCOMO_LTINT);}static struct irqchip locomo_lt_chip = { .ack = locomo_lt_ack_irq, .mask = locomo_lt_mask_irq, .unmask = locomo_lt_unmask_irq,};static void locomo_spi_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs){ int req, i; struct irqdesc *d; void *mapbase = get_irq_chipdata(irq); req = locomo_readl(mapbase + LOCOMO_SPIIR) & 0x000F; if (req) { irq = LOCOMO_IRQ_SPI_START; d = irq_desc + irq; for (i = 0; i <= 3; i++, irq++, d++) { if (req & (0x0001 << i)) { d->handle(irq, d, regs); } } }}static void locomo_spi_ack_irq(unsigned int irq){ void *mapbase = get_irq_chipdata(irq); unsigned int r; r = locomo_readl(mapbase + LOCOMO_SPIWE); r |= (0x0001 << (irq - LOCOMO_IRQ_SPI_START)); locomo_writel(r, mapbase + LOCOMO_SPIWE); r = locomo_readl(mapbase + LOCOMO_SPIIS); r &= ~(0x0001 << (irq - LOCOMO_IRQ_SPI_START)); locomo_writel(r, mapbase + LOCOMO_SPIIS); r = locomo_readl(mapbase + LOCOMO_SPIWE); r &= ~(0x0001 << (irq - LOCOMO_IRQ_SPI_START)); locomo_writel(r, mapbase + LOCOMO_SPIWE);}static void locomo_spi_mask_irq(unsigned int irq){ void *mapbase = get_irq_chipdata(irq); unsigned int r; r = locomo_readl(mapbase + LOCOMO_SPIIE); r &= ~(0x0001 << (irq - LOCOMO_IRQ_SPI_START)); locomo_writel(r, mapbase + LOCOMO_SPIIE);}static void locomo_spi_unmask_irq(unsigned int irq){ void *mapbase = get_irq_chipdata(irq); unsigned int r; r = locomo_readl(mapbase + LOCOMO_SPIIE); r |= (0x0001 << (irq - LOCOMO_IRQ_SPI_START)); locomo_writel(r, mapbase + LOCOMO_SPIIE);}static struct irqchip locomo_spi_chip = { .ack = locomo_spi_ack_irq, .mask = locomo_spi_mask_irq, .unmask = locomo_spi_unmask_irq,};static void locomo_setup_irq(struct locomo *lchip){ int irq; void *irqbase = lchip->base; /* * Install handler for IRQ_LOCOMO_HW. */ set_irq_type(lchip->irq, IRQT_FALLING); set_irq_chipdata(lchip->irq, irqbase); set_irq_chained_handler(lchip->irq, locomo_handler); /* Install handlers for IRQ_LOCOMO_*_BASE */ set_irq_chip(IRQ_LOCOMO_KEY_BASE, &locomo_chip); set_irq_chipdata(IRQ_LOCOMO_KEY_BASE, irqbase); set_irq_chained_handler(IRQ_LOCOMO_KEY_BASE, locomo_key_handler); set_irq_flags(IRQ_LOCOMO_KEY_BASE, IRQF_VALID | IRQF_PROBE); set_irq_chip(IRQ_LOCOMO_GPIO_BASE, &locomo_chip); set_irq_chipdata(IRQ_LOCOMO_GPIO_BASE, irqbase); set_irq_chained_handler(IRQ_LOCOMO_GPIO_BASE, locomo_gpio_handler); set_irq_flags(IRQ_LOCOMO_GPIO_BASE, IRQF_VALID | IRQF_PROBE); set_irq_chip(IRQ_LOCOMO_LT_BASE, &locomo_chip); set_irq_chipdata(IRQ_LOCOMO_LT_BASE, irqbase); set_irq_chained_handler(IRQ_LOCOMO_LT_BASE, locomo_lt_handler);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -