📄 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/platform_device.h>#include <linux/slab.h>#include <linux/spinlock.h>#include <asm/hardware.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/mach/irq.h>#include <asm/hardware/locomo.h>/* M62332 output channel selection */#define M62332_EVR_CH 1 /* M62332 volume channel number */ /* 0 : CH.1 , 1 : CH. 2 *//* DAC send data */#define M62332_SLAVE_ADDR 0x4e /* Slave address */#define M62332_W_BIT 0x00 /* W bit (0 only) */#define M62332_SUB_ADDR 0x00 /* Sub address */#define M62332_A_BIT 0x00 /* A bit (0 only) *//* DAC setup and hold times (expressed in us) */#define DAC_BUS_FREE_TIME 5 /* 4.7 us */#define DAC_START_SETUP_TIME 5 /* 4.7 us */#define DAC_STOP_SETUP_TIME 4 /* 4.0 us */#define DAC_START_HOLD_TIME 5 /* 4.7 us */#define DAC_SCL_LOW_HOLD_TIME 5 /* 4.7 us */#define DAC_SCL_HIGH_HOLD_TIME 4 /* 4.0 us */#define DAC_DATA_SETUP_TIME 1 /* 250 ns */#define DAC_DATA_HOLD_TIME 1 /* 300 ns */#define DAC_LOW_SETUP_TIME 1 /* 300 ns */#define DAC_HIGH_SETUP_TIME 1 /* 1000 ns *//* the following is the overall data for the locomo chip */struct locomo { struct device *dev; unsigned long phys; unsigned int irq; spinlock_t lock; void __iomem *base;};struct locomo_dev_info { unsigned long offset; unsigned long length; unsigned int devid; unsigned int irq[1]; const char * name;};/* All the locomo devices. If offset is non-zero, the mapbase for the * locomo_dev will be set to the chip base plus offset. If offset is * zero, then the mapbase for the locomo_dev will be set to zero. An * offset of zero means the device only uses GPIOs or other helper * functions inside this file */static struct locomo_dev_info locomo_devices[] = { { .devid = LOCOMO_DEVID_KEYBOARD, .irq = { IRQ_LOCOMO_KEY, }, .name = "locomo-keyboard", .offset = LOCOMO_KEYBOARD, .length = 16, }, { .devid = LOCOMO_DEVID_FRONTLIGHT, .irq = {}, .name = "locomo-frontlight", .offset = LOCOMO_FRONTLIGHT, .length = 8, }, { .devid = LOCOMO_DEVID_BACKLIGHT, .irq = {}, .name = "locomo-backlight", .offset = LOCOMO_BACKLIGHT, .length = 8, }, { .devid = LOCOMO_DEVID_AUDIO, .irq = {}, .name = "locomo-audio", .offset = LOCOMO_AUDIO, .length = 4, }, { .devid = LOCOMO_DEVID_LED, .irq = {}, .name = "locomo-led", .offset = LOCOMO_LED, .length = 8, }, { .devid = LOCOMO_DEVID_UART, .irq = {}, .name = "locomo-uart", .offset = 0, .length = 0, },};/** 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 __iomem *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)) { desc_handle_irq(irq, d, regs); } } }}static void locomo_ack_irq(unsigned int irq){}static void locomo_mask_irq(unsigned int irq){ void __iomem *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 __iomem *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 __iomem *mapbase = get_irq_chipdata(irq); if (locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC) & 0x0001) { d = irq_desc + LOCOMO_IRQ_KEY_START; desc_handle_irq(LOCOMO_IRQ_KEY_START, d, regs); }}static void locomo_key_ack_irq(unsigned int irq){ void __iomem *mapbase = get_irq_chipdata(irq); unsigned int r; r = locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC); r &= ~(0x0100 << (irq - LOCOMO_IRQ_KEY_START)); locomo_writel(r, mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC);}static void locomo_key_mask_irq(unsigned int irq){ void __iomem *mapbase = get_irq_chipdata(irq); unsigned int r; r = locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC); r &= ~(0x0010 << (irq - LOCOMO_IRQ_KEY_START)); locomo_writel(r, mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC);}static void locomo_key_unmask_irq(unsigned int irq){ void __iomem *mapbase = get_irq_chipdata(irq); unsigned int r; r = locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC); r |= (0x0010 << (irq - LOCOMO_IRQ_KEY_START)); locomo_writel(r, mapbase + LOCOMO_KEYBOARD + 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 __iomem *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)) { desc_handle_irq(irq, d, regs); } } }}static void locomo_gpio_ack_irq(unsigned int irq){ void __iomem *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 __iomem *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 __iomem *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 __iomem *mapbase = get_irq_chipdata(irq); if (locomo_readl(mapbase + LOCOMO_LTINT) & 0x0001) { d = irq_desc + LOCOMO_IRQ_LT_START; desc_handle_irq(LOCOMO_IRQ_LT_START, d, regs); }}static void locomo_lt_ack_irq(unsigned int irq){ void __iomem *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 __iomem *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 __iomem *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 __iomem *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)) { desc_handle_irq(irq, d, regs); } } }}static void locomo_spi_ack_irq(unsigned int irq){ void __iomem *mapbase = get_irq_chipdata(irq); unsigned int r; r = locomo_readl(mapbase + LOCOMO_SPIWE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -