Commit 64c4813d9ea0d646a0652bd9dcc5b40db6ddce69
Exists in
master
and in
4 other branches
Merge master.kernel.org:/home/rmk/linux-2.6-arm
Showing 34 changed files Inline Diff
- arch/arm/common/locomo.c
- arch/arm/common/sa1111.c
- arch/arm/kernel/ecard.c
- arch/arm/kernel/irq.c
- arch/arm/kernel/smp.c
- arch/arm/mach-footbridge/isa-irq.c
- arch/arm/mach-h720x/common.c
- arch/arm/mach-h720x/cpu-h7202.c
- arch/arm/mach-imx/irq.c
- arch/arm/mach-integrator/integrator_cp.c
- arch/arm/mach-ixp2000/core.c
- arch/arm/mach-ixp2000/ixdp2x00.c
- arch/arm/mach-ixp2000/ixdp2x01.c
- arch/arm/mach-lh7a40x/common.h
- arch/arm/mach-omap1/fpga.c
- arch/arm/mach-pxa/irq.c
- arch/arm/mach-pxa/lubbock.c
- arch/arm/mach-pxa/mainstone.c
- arch/arm/mach-s3c2410/bast-irq.c
- arch/arm/mach-s3c2410/irq.c
- arch/arm/mach-s3c2410/pm.c
- arch/arm/mach-s3c2410/s3c2440-irq.c
- arch/arm/mach-sa1100/irq.c
- arch/arm/mach-sa1100/neponset.c
- arch/arm/mach-versatile/core.c
- arch/arm/mm/proc-arm6_7.S
- arch/arm/plat-omap/gpio.c
- drivers/pcmcia/pxa2xx_base.c
- drivers/pcmcia/pxa2xx_mainstone.c
- drivers/pcmcia/pxa2xx_sharpsl.c
- drivers/pcmcia/sa1100_generic.c
- drivers/pcmcia/sa1111_generic.c
- drivers/pcmcia/sa11xx_base.c
- include/asm-arm/mach/irq.h
arch/arm/common/locomo.c
| 1 | /* | 1 | /* |
| 2 | * linux/arch/arm/common/locomo.c | 2 | * linux/arch/arm/common/locomo.c |
| 3 | * | 3 | * |
| 4 | * Sharp LoCoMo support | 4 | * Sharp LoCoMo support |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
| 8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
| 9 | * | 9 | * |
| 10 | * This file contains all generic LoCoMo support. | 10 | * This file contains all generic LoCoMo support. |
| 11 | * | 11 | * |
| 12 | * All initialization functions provided here are intended to be called | 12 | * All initialization functions provided here are intended to be called |
| 13 | * from machine specific code with proper arguments when required. | 13 | * from machine specific code with proper arguments when required. |
| 14 | * | 14 | * |
| 15 | * Based on sa1111.c | 15 | * Based on sa1111.c |
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | #include <linux/config.h> | 18 | #include <linux/config.h> |
| 19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
| 21 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
| 22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
| 23 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
| 24 | #include <linux/ioport.h> | 24 | #include <linux/ioport.h> |
| 25 | #include <linux/device.h> | 25 | #include <linux/device.h> |
| 26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
| 27 | #include <linux/spinlock.h> | 27 | #include <linux/spinlock.h> |
| 28 | 28 | ||
| 29 | #include <asm/hardware.h> | 29 | #include <asm/hardware.h> |
| 30 | #include <asm/mach-types.h> | 30 | #include <asm/mach-types.h> |
| 31 | #include <asm/io.h> | 31 | #include <asm/io.h> |
| 32 | #include <asm/irq.h> | 32 | #include <asm/irq.h> |
| 33 | #include <asm/mach/irq.h> | 33 | #include <asm/mach/irq.h> |
| 34 | 34 | ||
| 35 | #include <asm/hardware/locomo.h> | 35 | #include <asm/hardware/locomo.h> |
| 36 | 36 | ||
| 37 | /* M62332 output channel selection */ | 37 | /* M62332 output channel selection */ |
| 38 | #define M62332_EVR_CH 1 /* M62332 volume channel number */ | 38 | #define M62332_EVR_CH 1 /* M62332 volume channel number */ |
| 39 | /* 0 : CH.1 , 1 : CH. 2 */ | 39 | /* 0 : CH.1 , 1 : CH. 2 */ |
| 40 | /* DAC send data */ | 40 | /* DAC send data */ |
| 41 | #define M62332_SLAVE_ADDR 0x4e /* Slave address */ | 41 | #define M62332_SLAVE_ADDR 0x4e /* Slave address */ |
| 42 | #define M62332_W_BIT 0x00 /* W bit (0 only) */ | 42 | #define M62332_W_BIT 0x00 /* W bit (0 only) */ |
| 43 | #define M62332_SUB_ADDR 0x00 /* Sub address */ | 43 | #define M62332_SUB_ADDR 0x00 /* Sub address */ |
| 44 | #define M62332_A_BIT 0x00 /* A bit (0 only) */ | 44 | #define M62332_A_BIT 0x00 /* A bit (0 only) */ |
| 45 | 45 | ||
| 46 | /* DAC setup and hold times (expressed in us) */ | 46 | /* DAC setup and hold times (expressed in us) */ |
| 47 | #define DAC_BUS_FREE_TIME 5 /* 4.7 us */ | 47 | #define DAC_BUS_FREE_TIME 5 /* 4.7 us */ |
| 48 | #define DAC_START_SETUP_TIME 5 /* 4.7 us */ | 48 | #define DAC_START_SETUP_TIME 5 /* 4.7 us */ |
| 49 | #define DAC_STOP_SETUP_TIME 4 /* 4.0 us */ | 49 | #define DAC_STOP_SETUP_TIME 4 /* 4.0 us */ |
| 50 | #define DAC_START_HOLD_TIME 5 /* 4.7 us */ | 50 | #define DAC_START_HOLD_TIME 5 /* 4.7 us */ |
| 51 | #define DAC_SCL_LOW_HOLD_TIME 5 /* 4.7 us */ | 51 | #define DAC_SCL_LOW_HOLD_TIME 5 /* 4.7 us */ |
| 52 | #define DAC_SCL_HIGH_HOLD_TIME 4 /* 4.0 us */ | 52 | #define DAC_SCL_HIGH_HOLD_TIME 4 /* 4.0 us */ |
| 53 | #define DAC_DATA_SETUP_TIME 1 /* 250 ns */ | 53 | #define DAC_DATA_SETUP_TIME 1 /* 250 ns */ |
| 54 | #define DAC_DATA_HOLD_TIME 1 /* 300 ns */ | 54 | #define DAC_DATA_HOLD_TIME 1 /* 300 ns */ |
| 55 | #define DAC_LOW_SETUP_TIME 1 /* 300 ns */ | 55 | #define DAC_LOW_SETUP_TIME 1 /* 300 ns */ |
| 56 | #define DAC_HIGH_SETUP_TIME 1 /* 1000 ns */ | 56 | #define DAC_HIGH_SETUP_TIME 1 /* 1000 ns */ |
| 57 | 57 | ||
| 58 | /* the following is the overall data for the locomo chip */ | 58 | /* the following is the overall data for the locomo chip */ |
| 59 | struct locomo { | 59 | struct locomo { |
| 60 | struct device *dev; | 60 | struct device *dev; |
| 61 | unsigned long phys; | 61 | unsigned long phys; |
| 62 | unsigned int irq; | 62 | unsigned int irq; |
| 63 | spinlock_t lock; | 63 | spinlock_t lock; |
| 64 | void *base; | 64 | void *base; |
| 65 | }; | 65 | }; |
| 66 | 66 | ||
| 67 | struct locomo_dev_info { | 67 | struct locomo_dev_info { |
| 68 | unsigned long offset; | 68 | unsigned long offset; |
| 69 | unsigned long length; | 69 | unsigned long length; |
| 70 | unsigned int devid; | 70 | unsigned int devid; |
| 71 | unsigned int irq[1]; | 71 | unsigned int irq[1]; |
| 72 | const char * name; | 72 | const char * name; |
| 73 | }; | 73 | }; |
| 74 | 74 | ||
| 75 | /* All the locomo devices. If offset is non-zero, the mapbase for the | 75 | /* All the locomo devices. If offset is non-zero, the mapbase for the |
| 76 | * locomo_dev will be set to the chip base plus offset. If offset is | 76 | * locomo_dev will be set to the chip base plus offset. If offset is |
| 77 | * zero, then the mapbase for the locomo_dev will be set to zero. An | 77 | * zero, then the mapbase for the locomo_dev will be set to zero. An |
| 78 | * offset of zero means the device only uses GPIOs or other helper | 78 | * offset of zero means the device only uses GPIOs or other helper |
| 79 | * functions inside this file */ | 79 | * functions inside this file */ |
| 80 | static struct locomo_dev_info locomo_devices[] = { | 80 | static struct locomo_dev_info locomo_devices[] = { |
| 81 | { | 81 | { |
| 82 | .devid = LOCOMO_DEVID_KEYBOARD, | 82 | .devid = LOCOMO_DEVID_KEYBOARD, |
| 83 | .irq = { | 83 | .irq = { |
| 84 | IRQ_LOCOMO_KEY, | 84 | IRQ_LOCOMO_KEY, |
| 85 | }, | 85 | }, |
| 86 | .name = "locomo-keyboard", | 86 | .name = "locomo-keyboard", |
| 87 | .offset = LOCOMO_KEYBOARD, | 87 | .offset = LOCOMO_KEYBOARD, |
| 88 | .length = 16, | 88 | .length = 16, |
| 89 | }, | 89 | }, |
| 90 | { | 90 | { |
| 91 | .devid = LOCOMO_DEVID_FRONTLIGHT, | 91 | .devid = LOCOMO_DEVID_FRONTLIGHT, |
| 92 | .irq = {}, | 92 | .irq = {}, |
| 93 | .name = "locomo-frontlight", | 93 | .name = "locomo-frontlight", |
| 94 | .offset = LOCOMO_FRONTLIGHT, | 94 | .offset = LOCOMO_FRONTLIGHT, |
| 95 | .length = 8, | 95 | .length = 8, |
| 96 | 96 | ||
| 97 | }, | 97 | }, |
| 98 | { | 98 | { |
| 99 | .devid = LOCOMO_DEVID_BACKLIGHT, | 99 | .devid = LOCOMO_DEVID_BACKLIGHT, |
| 100 | .irq = {}, | 100 | .irq = {}, |
| 101 | .name = "locomo-backlight", | 101 | .name = "locomo-backlight", |
| 102 | .offset = LOCOMO_BACKLIGHT, | 102 | .offset = LOCOMO_BACKLIGHT, |
| 103 | .length = 8, | 103 | .length = 8, |
| 104 | }, | 104 | }, |
| 105 | { | 105 | { |
| 106 | .devid = LOCOMO_DEVID_AUDIO, | 106 | .devid = LOCOMO_DEVID_AUDIO, |
| 107 | .irq = {}, | 107 | .irq = {}, |
| 108 | .name = "locomo-audio", | 108 | .name = "locomo-audio", |
| 109 | .offset = LOCOMO_AUDIO, | 109 | .offset = LOCOMO_AUDIO, |
| 110 | .length = 4, | 110 | .length = 4, |
| 111 | }, | 111 | }, |
| 112 | { | 112 | { |
| 113 | .devid = LOCOMO_DEVID_LED, | 113 | .devid = LOCOMO_DEVID_LED, |
| 114 | .irq = {}, | 114 | .irq = {}, |
| 115 | .name = "locomo-led", | 115 | .name = "locomo-led", |
| 116 | .offset = LOCOMO_LED, | 116 | .offset = LOCOMO_LED, |
| 117 | .length = 8, | 117 | .length = 8, |
| 118 | }, | 118 | }, |
| 119 | { | 119 | { |
| 120 | .devid = LOCOMO_DEVID_UART, | 120 | .devid = LOCOMO_DEVID_UART, |
| 121 | .irq = {}, | 121 | .irq = {}, |
| 122 | .name = "locomo-uart", | 122 | .name = "locomo-uart", |
| 123 | .offset = 0, | 123 | .offset = 0, |
| 124 | .length = 0, | 124 | .length = 0, |
| 125 | }, | 125 | }, |
| 126 | }; | 126 | }; |
| 127 | 127 | ||
| 128 | 128 | ||
| 129 | /** LoCoMo interrupt handling stuff. | 129 | /** LoCoMo interrupt handling stuff. |
| 130 | * NOTE: LoCoMo has a 1 to many mapping on all of its IRQs. | 130 | * NOTE: LoCoMo has a 1 to many mapping on all of its IRQs. |
| 131 | * that is, there is only one real hardware interrupt | 131 | * that is, there is only one real hardware interrupt |
| 132 | * we determine which interrupt it is by reading some IO memory. | 132 | * we determine which interrupt it is by reading some IO memory. |
| 133 | * We have two levels of expansion, first in the handler for the | 133 | * We have two levels of expansion, first in the handler for the |
| 134 | * hardware interrupt we generate an interrupt | 134 | * hardware interrupt we generate an interrupt |
| 135 | * IRQ_LOCOMO_*_BASE and those handlers generate more interrupts | 135 | * IRQ_LOCOMO_*_BASE and those handlers generate more interrupts |
| 136 | * | 136 | * |
| 137 | * hardware irq reads LOCOMO_ICR & 0x0f00 | 137 | * hardware irq reads LOCOMO_ICR & 0x0f00 |
| 138 | * IRQ_LOCOMO_KEY_BASE | 138 | * IRQ_LOCOMO_KEY_BASE |
| 139 | * IRQ_LOCOMO_GPIO_BASE | 139 | * IRQ_LOCOMO_GPIO_BASE |
| 140 | * IRQ_LOCOMO_LT_BASE | 140 | * IRQ_LOCOMO_LT_BASE |
| 141 | * IRQ_LOCOMO_SPI_BASE | 141 | * IRQ_LOCOMO_SPI_BASE |
| 142 | * IRQ_LOCOMO_KEY_BASE reads LOCOMO_KIC & 0x0001 | 142 | * IRQ_LOCOMO_KEY_BASE reads LOCOMO_KIC & 0x0001 |
| 143 | * IRQ_LOCOMO_KEY | 143 | * IRQ_LOCOMO_KEY |
| 144 | * IRQ_LOCOMO_GPIO_BASE reads LOCOMO_GIR & LOCOMO_GPD & 0xffff | 144 | * IRQ_LOCOMO_GPIO_BASE reads LOCOMO_GIR & LOCOMO_GPD & 0xffff |
| 145 | * IRQ_LOCOMO_GPIO[0-15] | 145 | * IRQ_LOCOMO_GPIO[0-15] |
| 146 | * IRQ_LOCOMO_LT_BASE reads LOCOMO_LTINT & 0x0001 | 146 | * IRQ_LOCOMO_LT_BASE reads LOCOMO_LTINT & 0x0001 |
| 147 | * IRQ_LOCOMO_LT | 147 | * IRQ_LOCOMO_LT |
| 148 | * IRQ_LOCOMO_SPI_BASE reads LOCOMO_SPIIR & 0x000F | 148 | * IRQ_LOCOMO_SPI_BASE reads LOCOMO_SPIIR & 0x000F |
| 149 | * IRQ_LOCOMO_SPI_RFR | 149 | * IRQ_LOCOMO_SPI_RFR |
| 150 | * IRQ_LOCOMO_SPI_RFW | 150 | * IRQ_LOCOMO_SPI_RFW |
| 151 | * IRQ_LOCOMO_SPI_OVRN | 151 | * IRQ_LOCOMO_SPI_OVRN |
| 152 | * IRQ_LOCOMO_SPI_TEND | 152 | * IRQ_LOCOMO_SPI_TEND |
| 153 | */ | 153 | */ |
| 154 | 154 | ||
| 155 | #define LOCOMO_IRQ_START (IRQ_LOCOMO_KEY_BASE) | 155 | #define LOCOMO_IRQ_START (IRQ_LOCOMO_KEY_BASE) |
| 156 | #define LOCOMO_IRQ_KEY_START (IRQ_LOCOMO_KEY) | 156 | #define LOCOMO_IRQ_KEY_START (IRQ_LOCOMO_KEY) |
| 157 | #define LOCOMO_IRQ_GPIO_START (IRQ_LOCOMO_GPIO0) | 157 | #define LOCOMO_IRQ_GPIO_START (IRQ_LOCOMO_GPIO0) |
| 158 | #define LOCOMO_IRQ_LT_START (IRQ_LOCOMO_LT) | 158 | #define LOCOMO_IRQ_LT_START (IRQ_LOCOMO_LT) |
| 159 | #define LOCOMO_IRQ_SPI_START (IRQ_LOCOMO_SPI_RFR) | 159 | #define LOCOMO_IRQ_SPI_START (IRQ_LOCOMO_SPI_RFR) |
| 160 | 160 | ||
| 161 | static void locomo_handler(unsigned int irq, struct irqdesc *desc, | 161 | static void locomo_handler(unsigned int irq, struct irqdesc *desc, |
| 162 | struct pt_regs *regs) | 162 | struct pt_regs *regs) |
| 163 | { | 163 | { |
| 164 | int req, i; | 164 | int req, i; |
| 165 | struct irqdesc *d; | 165 | struct irqdesc *d; |
| 166 | void *mapbase = get_irq_chipdata(irq); | 166 | void *mapbase = get_irq_chipdata(irq); |
| 167 | 167 | ||
| 168 | /* Acknowledge the parent IRQ */ | 168 | /* Acknowledge the parent IRQ */ |
| 169 | desc->chip->ack(irq); | 169 | desc->chip->ack(irq); |
| 170 | 170 | ||
| 171 | /* check why this interrupt was generated */ | 171 | /* check why this interrupt was generated */ |
| 172 | req = locomo_readl(mapbase + LOCOMO_ICR) & 0x0f00; | 172 | req = locomo_readl(mapbase + LOCOMO_ICR) & 0x0f00; |
| 173 | 173 | ||
| 174 | if (req) { | 174 | if (req) { |
| 175 | /* generate the next interrupt(s) */ | 175 | /* generate the next interrupt(s) */ |
| 176 | irq = LOCOMO_IRQ_START; | 176 | irq = LOCOMO_IRQ_START; |
| 177 | d = irq_desc + irq; | 177 | d = irq_desc + irq; |
| 178 | for (i = 0; i <= 3; i++, d++, irq++) { | 178 | for (i = 0; i <= 3; i++, d++, irq++) { |
| 179 | if (req & (0x0100 << i)) { | 179 | if (req & (0x0100 << i)) { |
| 180 | d->handle(irq, d, regs); | 180 | desc_handle_irq(irq, d, regs); |
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | } | 183 | } |
| 184 | } | 184 | } |
| 185 | } | 185 | } |
| 186 | 186 | ||
| 187 | static void locomo_ack_irq(unsigned int irq) | 187 | static void locomo_ack_irq(unsigned int irq) |
| 188 | { | 188 | { |
| 189 | } | 189 | } |
| 190 | 190 | ||
| 191 | static void locomo_mask_irq(unsigned int irq) | 191 | static void locomo_mask_irq(unsigned int irq) |
| 192 | { | 192 | { |
| 193 | void *mapbase = get_irq_chipdata(irq); | 193 | void *mapbase = get_irq_chipdata(irq); |
| 194 | unsigned int r; | 194 | unsigned int r; |
| 195 | r = locomo_readl(mapbase + LOCOMO_ICR); | 195 | r = locomo_readl(mapbase + LOCOMO_ICR); |
| 196 | r &= ~(0x0010 << (irq - LOCOMO_IRQ_START)); | 196 | r &= ~(0x0010 << (irq - LOCOMO_IRQ_START)); |
| 197 | locomo_writel(r, mapbase + LOCOMO_ICR); | 197 | locomo_writel(r, mapbase + LOCOMO_ICR); |
| 198 | } | 198 | } |
| 199 | 199 | ||
| 200 | static void locomo_unmask_irq(unsigned int irq) | 200 | static void locomo_unmask_irq(unsigned int irq) |
| 201 | { | 201 | { |
| 202 | void *mapbase = get_irq_chipdata(irq); | 202 | void *mapbase = get_irq_chipdata(irq); |
| 203 | unsigned int r; | 203 | unsigned int r; |
| 204 | r = locomo_readl(mapbase + LOCOMO_ICR); | 204 | r = locomo_readl(mapbase + LOCOMO_ICR); |
| 205 | r |= (0x0010 << (irq - LOCOMO_IRQ_START)); | 205 | r |= (0x0010 << (irq - LOCOMO_IRQ_START)); |
| 206 | locomo_writel(r, mapbase + LOCOMO_ICR); | 206 | locomo_writel(r, mapbase + LOCOMO_ICR); |
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | static struct irqchip locomo_chip = { | 209 | static struct irqchip locomo_chip = { |
| 210 | .ack = locomo_ack_irq, | 210 | .ack = locomo_ack_irq, |
| 211 | .mask = locomo_mask_irq, | 211 | .mask = locomo_mask_irq, |
| 212 | .unmask = locomo_unmask_irq, | 212 | .unmask = locomo_unmask_irq, |
| 213 | }; | 213 | }; |
| 214 | 214 | ||
| 215 | static void locomo_key_handler(unsigned int irq, struct irqdesc *desc, | 215 | static void locomo_key_handler(unsigned int irq, struct irqdesc *desc, |
| 216 | struct pt_regs *regs) | 216 | struct pt_regs *regs) |
| 217 | { | 217 | { |
| 218 | struct irqdesc *d; | 218 | struct irqdesc *d; |
| 219 | void *mapbase = get_irq_chipdata(irq); | 219 | void *mapbase = get_irq_chipdata(irq); |
| 220 | 220 | ||
| 221 | if (locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC) & 0x0001) { | 221 | if (locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC) & 0x0001) { |
| 222 | d = irq_desc + LOCOMO_IRQ_KEY_START; | 222 | d = irq_desc + LOCOMO_IRQ_KEY_START; |
| 223 | d->handle(LOCOMO_IRQ_KEY_START, d, regs); | 223 | desc_handle_irq(LOCOMO_IRQ_KEY_START, d, regs); |
| 224 | } | 224 | } |
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | static void locomo_key_ack_irq(unsigned int irq) | 227 | static void locomo_key_ack_irq(unsigned int irq) |
| 228 | { | 228 | { |
| 229 | void *mapbase = get_irq_chipdata(irq); | 229 | void *mapbase = get_irq_chipdata(irq); |
| 230 | unsigned int r; | 230 | unsigned int r; |
| 231 | r = locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC); | 231 | r = locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC); |
| 232 | r &= ~(0x0100 << (irq - LOCOMO_IRQ_KEY_START)); | 232 | r &= ~(0x0100 << (irq - LOCOMO_IRQ_KEY_START)); |
| 233 | locomo_writel(r, mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC); | 233 | locomo_writel(r, mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC); |
| 234 | } | 234 | } |
| 235 | 235 | ||
| 236 | static void locomo_key_mask_irq(unsigned int irq) | 236 | static void locomo_key_mask_irq(unsigned int irq) |
| 237 | { | 237 | { |
| 238 | void *mapbase = get_irq_chipdata(irq); | 238 | void *mapbase = get_irq_chipdata(irq); |
| 239 | unsigned int r; | 239 | unsigned int r; |
| 240 | r = locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC); | 240 | r = locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC); |
| 241 | r &= ~(0x0010 << (irq - LOCOMO_IRQ_KEY_START)); | 241 | r &= ~(0x0010 << (irq - LOCOMO_IRQ_KEY_START)); |
| 242 | locomo_writel(r, mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC); | 242 | locomo_writel(r, mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC); |
| 243 | } | 243 | } |
| 244 | 244 | ||
| 245 | static void locomo_key_unmask_irq(unsigned int irq) | 245 | static void locomo_key_unmask_irq(unsigned int irq) |
| 246 | { | 246 | { |
| 247 | void *mapbase = get_irq_chipdata(irq); | 247 | void *mapbase = get_irq_chipdata(irq); |
| 248 | unsigned int r; | 248 | unsigned int r; |
| 249 | r = locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC); | 249 | r = locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC); |
| 250 | r |= (0x0010 << (irq - LOCOMO_IRQ_KEY_START)); | 250 | r |= (0x0010 << (irq - LOCOMO_IRQ_KEY_START)); |
| 251 | locomo_writel(r, mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC); | 251 | locomo_writel(r, mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC); |
| 252 | } | 252 | } |
| 253 | 253 | ||
| 254 | static struct irqchip locomo_key_chip = { | 254 | static struct irqchip locomo_key_chip = { |
| 255 | .ack = locomo_key_ack_irq, | 255 | .ack = locomo_key_ack_irq, |
| 256 | .mask = locomo_key_mask_irq, | 256 | .mask = locomo_key_mask_irq, |
| 257 | .unmask = locomo_key_unmask_irq, | 257 | .unmask = locomo_key_unmask_irq, |
| 258 | }; | 258 | }; |
| 259 | 259 | ||
| 260 | static void locomo_gpio_handler(unsigned int irq, struct irqdesc *desc, | 260 | static void locomo_gpio_handler(unsigned int irq, struct irqdesc *desc, |
| 261 | struct pt_regs *regs) | 261 | struct pt_regs *regs) |
| 262 | { | 262 | { |
| 263 | int req, i; | 263 | int req, i; |
| 264 | struct irqdesc *d; | 264 | struct irqdesc *d; |
| 265 | void *mapbase = get_irq_chipdata(irq); | 265 | void *mapbase = get_irq_chipdata(irq); |
| 266 | 266 | ||
| 267 | req = locomo_readl(mapbase + LOCOMO_GIR) & | 267 | req = locomo_readl(mapbase + LOCOMO_GIR) & |
| 268 | locomo_readl(mapbase + LOCOMO_GPD) & | 268 | locomo_readl(mapbase + LOCOMO_GPD) & |
| 269 | 0xffff; | 269 | 0xffff; |
| 270 | 270 | ||
| 271 | if (req) { | 271 | if (req) { |
| 272 | irq = LOCOMO_IRQ_GPIO_START; | 272 | irq = LOCOMO_IRQ_GPIO_START; |
| 273 | d = irq_desc + LOCOMO_IRQ_GPIO_START; | 273 | d = irq_desc + LOCOMO_IRQ_GPIO_START; |
| 274 | for (i = 0; i <= 15; i++, irq++, d++) { | 274 | for (i = 0; i <= 15; i++, irq++, d++) { |
| 275 | if (req & (0x0001 << i)) { | 275 | if (req & (0x0001 << i)) { |
| 276 | d->handle(irq, d, regs); | 276 | desc_handle_irq(irq, d, regs); |
| 277 | } | 277 | } |
| 278 | } | 278 | } |
| 279 | } | 279 | } |
| 280 | } | 280 | } |
| 281 | 281 | ||
| 282 | static void locomo_gpio_ack_irq(unsigned int irq) | 282 | static void locomo_gpio_ack_irq(unsigned int irq) |
| 283 | { | 283 | { |
| 284 | void *mapbase = get_irq_chipdata(irq); | 284 | void *mapbase = get_irq_chipdata(irq); |
| 285 | unsigned int r; | 285 | unsigned int r; |
| 286 | r = locomo_readl(mapbase + LOCOMO_GWE); | 286 | r = locomo_readl(mapbase + LOCOMO_GWE); |
| 287 | r |= (0x0001 << (irq - LOCOMO_IRQ_GPIO_START)); | 287 | r |= (0x0001 << (irq - LOCOMO_IRQ_GPIO_START)); |
| 288 | locomo_writel(r, mapbase + LOCOMO_GWE); | 288 | locomo_writel(r, mapbase + LOCOMO_GWE); |
| 289 | 289 | ||
| 290 | r = locomo_readl(mapbase + LOCOMO_GIS); | 290 | r = locomo_readl(mapbase + LOCOMO_GIS); |
| 291 | r &= ~(0x0001 << (irq - LOCOMO_IRQ_GPIO_START)); | 291 | r &= ~(0x0001 << (irq - LOCOMO_IRQ_GPIO_START)); |
| 292 | locomo_writel(r, mapbase + LOCOMO_GIS); | 292 | locomo_writel(r, mapbase + LOCOMO_GIS); |
| 293 | 293 | ||
| 294 | r = locomo_readl(mapbase + LOCOMO_GWE); | 294 | r = locomo_readl(mapbase + LOCOMO_GWE); |
| 295 | r &= ~(0x0001 << (irq - LOCOMO_IRQ_GPIO_START)); | 295 | r &= ~(0x0001 << (irq - LOCOMO_IRQ_GPIO_START)); |
| 296 | locomo_writel(r, mapbase + LOCOMO_GWE); | 296 | locomo_writel(r, mapbase + LOCOMO_GWE); |
| 297 | } | 297 | } |
| 298 | 298 | ||
| 299 | static void locomo_gpio_mask_irq(unsigned int irq) | 299 | static void locomo_gpio_mask_irq(unsigned int irq) |
| 300 | { | 300 | { |
| 301 | void *mapbase = get_irq_chipdata(irq); | 301 | void *mapbase = get_irq_chipdata(irq); |
| 302 | unsigned int r; | 302 | unsigned int r; |
| 303 | r = locomo_readl(mapbase + LOCOMO_GIE); | 303 | r = locomo_readl(mapbase + LOCOMO_GIE); |
| 304 | r &= ~(0x0001 << (irq - LOCOMO_IRQ_GPIO_START)); | 304 | r &= ~(0x0001 << (irq - LOCOMO_IRQ_GPIO_START)); |
| 305 | locomo_writel(r, mapbase + LOCOMO_GIE); | 305 | locomo_writel(r, mapbase + LOCOMO_GIE); |
| 306 | } | 306 | } |
| 307 | 307 | ||
| 308 | static void locomo_gpio_unmask_irq(unsigned int irq) | 308 | static void locomo_gpio_unmask_irq(unsigned int irq) |
| 309 | { | 309 | { |
| 310 | void *mapbase = get_irq_chipdata(irq); | 310 | void *mapbase = get_irq_chipdata(irq); |
| 311 | unsigned int r; | 311 | unsigned int r; |
| 312 | r = locomo_readl(mapbase + LOCOMO_GIE); | 312 | r = locomo_readl(mapbase + LOCOMO_GIE); |
| 313 | r |= (0x0001 << (irq - LOCOMO_IRQ_GPIO_START)); | 313 | r |= (0x0001 << (irq - LOCOMO_IRQ_GPIO_START)); |
| 314 | locomo_writel(r, mapbase + LOCOMO_GIE); | 314 | locomo_writel(r, mapbase + LOCOMO_GIE); |
| 315 | } | 315 | } |
| 316 | 316 | ||
| 317 | static struct irqchip locomo_gpio_chip = { | 317 | static struct irqchip locomo_gpio_chip = { |
| 318 | .ack = locomo_gpio_ack_irq, | 318 | .ack = locomo_gpio_ack_irq, |
| 319 | .mask = locomo_gpio_mask_irq, | 319 | .mask = locomo_gpio_mask_irq, |
| 320 | .unmask = locomo_gpio_unmask_irq, | 320 | .unmask = locomo_gpio_unmask_irq, |
| 321 | }; | 321 | }; |
| 322 | 322 | ||
| 323 | static void locomo_lt_handler(unsigned int irq, struct irqdesc *desc, | 323 | static void locomo_lt_handler(unsigned int irq, struct irqdesc *desc, |
| 324 | struct pt_regs *regs) | 324 | struct pt_regs *regs) |
| 325 | { | 325 | { |
| 326 | struct irqdesc *d; | 326 | struct irqdesc *d; |
| 327 | void *mapbase = get_irq_chipdata(irq); | 327 | void *mapbase = get_irq_chipdata(irq); |
| 328 | 328 | ||
| 329 | if (locomo_readl(mapbase + LOCOMO_LTINT) & 0x0001) { | 329 | if (locomo_readl(mapbase + LOCOMO_LTINT) & 0x0001) { |
| 330 | d = irq_desc + LOCOMO_IRQ_LT_START; | 330 | d = irq_desc + LOCOMO_IRQ_LT_START; |
| 331 | d->handle(LOCOMO_IRQ_LT_START, d, regs); | 331 | desc_handle_irq(LOCOMO_IRQ_LT_START, d, regs); |
| 332 | } | 332 | } |
| 333 | } | 333 | } |
| 334 | 334 | ||
| 335 | static void locomo_lt_ack_irq(unsigned int irq) | 335 | static void locomo_lt_ack_irq(unsigned int irq) |
| 336 | { | 336 | { |
| 337 | void *mapbase = get_irq_chipdata(irq); | 337 | void *mapbase = get_irq_chipdata(irq); |
| 338 | unsigned int r; | 338 | unsigned int r; |
| 339 | r = locomo_readl(mapbase + LOCOMO_LTINT); | 339 | r = locomo_readl(mapbase + LOCOMO_LTINT); |
| 340 | r &= ~(0x0100 << (irq - LOCOMO_IRQ_LT_START)); | 340 | r &= ~(0x0100 << (irq - LOCOMO_IRQ_LT_START)); |
| 341 | locomo_writel(r, mapbase + LOCOMO_LTINT); | 341 | locomo_writel(r, mapbase + LOCOMO_LTINT); |
| 342 | } | 342 | } |
| 343 | 343 | ||
| 344 | static void locomo_lt_mask_irq(unsigned int irq) | 344 | static void locomo_lt_mask_irq(unsigned int irq) |
| 345 | { | 345 | { |
| 346 | void *mapbase = get_irq_chipdata(irq); | 346 | void *mapbase = get_irq_chipdata(irq); |
| 347 | unsigned int r; | 347 | unsigned int r; |
| 348 | r = locomo_readl(mapbase + LOCOMO_LTINT); | 348 | r = locomo_readl(mapbase + LOCOMO_LTINT); |
| 349 | r &= ~(0x0010 << (irq - LOCOMO_IRQ_LT_START)); | 349 | r &= ~(0x0010 << (irq - LOCOMO_IRQ_LT_START)); |
| 350 | locomo_writel(r, mapbase + LOCOMO_LTINT); | 350 | locomo_writel(r, mapbase + LOCOMO_LTINT); |
| 351 | } | 351 | } |
| 352 | 352 | ||
| 353 | static void locomo_lt_unmask_irq(unsigned int irq) | 353 | static void locomo_lt_unmask_irq(unsigned int irq) |
| 354 | { | 354 | { |
| 355 | void *mapbase = get_irq_chipdata(irq); | 355 | void *mapbase = get_irq_chipdata(irq); |
| 356 | unsigned int r; | 356 | unsigned int r; |
| 357 | r = locomo_readl(mapbase + LOCOMO_LTINT); | 357 | r = locomo_readl(mapbase + LOCOMO_LTINT); |
| 358 | r |= (0x0010 << (irq - LOCOMO_IRQ_LT_START)); | 358 | r |= (0x0010 << (irq - LOCOMO_IRQ_LT_START)); |
| 359 | locomo_writel(r, mapbase + LOCOMO_LTINT); | 359 | locomo_writel(r, mapbase + LOCOMO_LTINT); |
| 360 | } | 360 | } |
| 361 | 361 | ||
| 362 | static struct irqchip locomo_lt_chip = { | 362 | static struct irqchip locomo_lt_chip = { |
| 363 | .ack = locomo_lt_ack_irq, | 363 | .ack = locomo_lt_ack_irq, |
| 364 | .mask = locomo_lt_mask_irq, | 364 | .mask = locomo_lt_mask_irq, |
| 365 | .unmask = locomo_lt_unmask_irq, | 365 | .unmask = locomo_lt_unmask_irq, |
| 366 | }; | 366 | }; |
| 367 | 367 | ||
| 368 | static void locomo_spi_handler(unsigned int irq, struct irqdesc *desc, | 368 | static void locomo_spi_handler(unsigned int irq, struct irqdesc *desc, |
| 369 | struct pt_regs *regs) | 369 | struct pt_regs *regs) |
| 370 | { | 370 | { |
| 371 | int req, i; | 371 | int req, i; |
| 372 | struct irqdesc *d; | 372 | struct irqdesc *d; |
| 373 | void *mapbase = get_irq_chipdata(irq); | 373 | void *mapbase = get_irq_chipdata(irq); |
| 374 | 374 | ||
| 375 | req = locomo_readl(mapbase + LOCOMO_SPIIR) & 0x000F; | 375 | req = locomo_readl(mapbase + LOCOMO_SPIIR) & 0x000F; |
| 376 | if (req) { | 376 | if (req) { |
| 377 | irq = LOCOMO_IRQ_SPI_START; | 377 | irq = LOCOMO_IRQ_SPI_START; |
| 378 | d = irq_desc + irq; | 378 | d = irq_desc + irq; |
| 379 | 379 | ||
| 380 | for (i = 0; i <= 3; i++, irq++, d++) { | 380 | for (i = 0; i <= 3; i++, irq++, d++) { |
| 381 | if (req & (0x0001 << i)) { | 381 | if (req & (0x0001 << i)) { |
| 382 | d->handle(irq, d, regs); | 382 | desc_handle_irq(irq, d, regs); |
| 383 | } | 383 | } |
| 384 | } | 384 | } |
| 385 | } | 385 | } |
| 386 | } | 386 | } |
| 387 | 387 | ||
| 388 | static void locomo_spi_ack_irq(unsigned int irq) | 388 | static void locomo_spi_ack_irq(unsigned int irq) |
| 389 | { | 389 | { |
| 390 | void *mapbase = get_irq_chipdata(irq); | 390 | void *mapbase = get_irq_chipdata(irq); |
| 391 | unsigned int r; | 391 | unsigned int r; |
| 392 | r = locomo_readl(mapbase + LOCOMO_SPIWE); | 392 | r = locomo_readl(mapbase + LOCOMO_SPIWE); |
| 393 | r |= (0x0001 << (irq - LOCOMO_IRQ_SPI_START)); | 393 | r |= (0x0001 << (irq - LOCOMO_IRQ_SPI_START)); |
| 394 | locomo_writel(r, mapbase + LOCOMO_SPIWE); | 394 | locomo_writel(r, mapbase + LOCOMO_SPIWE); |
| 395 | 395 | ||
| 396 | r = locomo_readl(mapbase + LOCOMO_SPIIS); | 396 | r = locomo_readl(mapbase + LOCOMO_SPIIS); |
| 397 | r &= ~(0x0001 << (irq - LOCOMO_IRQ_SPI_START)); | 397 | r &= ~(0x0001 << (irq - LOCOMO_IRQ_SPI_START)); |
| 398 | locomo_writel(r, mapbase + LOCOMO_SPIIS); | 398 | locomo_writel(r, mapbase + LOCOMO_SPIIS); |
| 399 | 399 | ||
| 400 | r = locomo_readl(mapbase + LOCOMO_SPIWE); | 400 | r = locomo_readl(mapbase + LOCOMO_SPIWE); |
| 401 | r &= ~(0x0001 << (irq - LOCOMO_IRQ_SPI_START)); | 401 | r &= ~(0x0001 << (irq - LOCOMO_IRQ_SPI_START)); |
| 402 | locomo_writel(r, mapbase + LOCOMO_SPIWE); | 402 | locomo_writel(r, mapbase + LOCOMO_SPIWE); |
| 403 | } | 403 | } |
| 404 | 404 | ||
| 405 | static void locomo_spi_mask_irq(unsigned int irq) | 405 | static void locomo_spi_mask_irq(unsigned int irq) |
| 406 | { | 406 | { |
| 407 | void *mapbase = get_irq_chipdata(irq); | 407 | void *mapbase = get_irq_chipdata(irq); |
| 408 | unsigned int r; | 408 | unsigned int r; |
| 409 | r = locomo_readl(mapbase + LOCOMO_SPIIE); | 409 | r = locomo_readl(mapbase + LOCOMO_SPIIE); |
| 410 | r &= ~(0x0001 << (irq - LOCOMO_IRQ_SPI_START)); | 410 | r &= ~(0x0001 << (irq - LOCOMO_IRQ_SPI_START)); |
| 411 | locomo_writel(r, mapbase + LOCOMO_SPIIE); | 411 | locomo_writel(r, mapbase + LOCOMO_SPIIE); |
| 412 | } | 412 | } |
| 413 | 413 | ||
| 414 | static void locomo_spi_unmask_irq(unsigned int irq) | 414 | static void locomo_spi_unmask_irq(unsigned int irq) |
| 415 | { | 415 | { |
| 416 | void *mapbase = get_irq_chipdata(irq); | 416 | void *mapbase = get_irq_chipdata(irq); |
| 417 | unsigned int r; | 417 | unsigned int r; |
| 418 | r = locomo_readl(mapbase + LOCOMO_SPIIE); | 418 | r = locomo_readl(mapbase + LOCOMO_SPIIE); |
| 419 | r |= (0x0001 << (irq - LOCOMO_IRQ_SPI_START)); | 419 | r |= (0x0001 << (irq - LOCOMO_IRQ_SPI_START)); |
| 420 | locomo_writel(r, mapbase + LOCOMO_SPIIE); | 420 | locomo_writel(r, mapbase + LOCOMO_SPIIE); |
| 421 | } | 421 | } |
| 422 | 422 | ||
| 423 | static struct irqchip locomo_spi_chip = { | 423 | static struct irqchip locomo_spi_chip = { |
| 424 | .ack = locomo_spi_ack_irq, | 424 | .ack = locomo_spi_ack_irq, |
| 425 | .mask = locomo_spi_mask_irq, | 425 | .mask = locomo_spi_mask_irq, |
| 426 | .unmask = locomo_spi_unmask_irq, | 426 | .unmask = locomo_spi_unmask_irq, |
| 427 | }; | 427 | }; |
| 428 | 428 | ||
| 429 | static void locomo_setup_irq(struct locomo *lchip) | 429 | static void locomo_setup_irq(struct locomo *lchip) |
| 430 | { | 430 | { |
| 431 | int irq; | 431 | int irq; |
| 432 | void *irqbase = lchip->base; | 432 | void *irqbase = lchip->base; |
| 433 | 433 | ||
| 434 | /* | 434 | /* |
| 435 | * Install handler for IRQ_LOCOMO_HW. | 435 | * Install handler for IRQ_LOCOMO_HW. |
| 436 | */ | 436 | */ |
| 437 | set_irq_type(lchip->irq, IRQT_FALLING); | 437 | set_irq_type(lchip->irq, IRQT_FALLING); |
| 438 | set_irq_chipdata(lchip->irq, irqbase); | 438 | set_irq_chipdata(lchip->irq, irqbase); |
| 439 | set_irq_chained_handler(lchip->irq, locomo_handler); | 439 | set_irq_chained_handler(lchip->irq, locomo_handler); |
| 440 | 440 | ||
| 441 | /* Install handlers for IRQ_LOCOMO_*_BASE */ | 441 | /* Install handlers for IRQ_LOCOMO_*_BASE */ |
| 442 | set_irq_chip(IRQ_LOCOMO_KEY_BASE, &locomo_chip); | 442 | set_irq_chip(IRQ_LOCOMO_KEY_BASE, &locomo_chip); |
| 443 | set_irq_chipdata(IRQ_LOCOMO_KEY_BASE, irqbase); | 443 | set_irq_chipdata(IRQ_LOCOMO_KEY_BASE, irqbase); |
| 444 | set_irq_chained_handler(IRQ_LOCOMO_KEY_BASE, locomo_key_handler); | 444 | set_irq_chained_handler(IRQ_LOCOMO_KEY_BASE, locomo_key_handler); |
| 445 | set_irq_flags(IRQ_LOCOMO_KEY_BASE, IRQF_VALID | IRQF_PROBE); | 445 | set_irq_flags(IRQ_LOCOMO_KEY_BASE, IRQF_VALID | IRQF_PROBE); |
| 446 | 446 | ||
| 447 | set_irq_chip(IRQ_LOCOMO_GPIO_BASE, &locomo_chip); | 447 | set_irq_chip(IRQ_LOCOMO_GPIO_BASE, &locomo_chip); |
| 448 | set_irq_chipdata(IRQ_LOCOMO_GPIO_BASE, irqbase); | 448 | set_irq_chipdata(IRQ_LOCOMO_GPIO_BASE, irqbase); |
| 449 | set_irq_chained_handler(IRQ_LOCOMO_GPIO_BASE, locomo_gpio_handler); | 449 | set_irq_chained_handler(IRQ_LOCOMO_GPIO_BASE, locomo_gpio_handler); |
| 450 | set_irq_flags(IRQ_LOCOMO_GPIO_BASE, IRQF_VALID | IRQF_PROBE); | 450 | set_irq_flags(IRQ_LOCOMO_GPIO_BASE, IRQF_VALID | IRQF_PROBE); |
| 451 | 451 | ||
| 452 | set_irq_chip(IRQ_LOCOMO_LT_BASE, &locomo_chip); | 452 | set_irq_chip(IRQ_LOCOMO_LT_BASE, &locomo_chip); |
| 453 | set_irq_chipdata(IRQ_LOCOMO_LT_BASE, irqbase); | 453 | set_irq_chipdata(IRQ_LOCOMO_LT_BASE, irqbase); |
| 454 | set_irq_chained_handler(IRQ_LOCOMO_LT_BASE, locomo_lt_handler); | 454 | set_irq_chained_handler(IRQ_LOCOMO_LT_BASE, locomo_lt_handler); |
| 455 | set_irq_flags(IRQ_LOCOMO_LT_BASE, IRQF_VALID | IRQF_PROBE); | 455 | set_irq_flags(IRQ_LOCOMO_LT_BASE, IRQF_VALID | IRQF_PROBE); |
| 456 | 456 | ||
| 457 | set_irq_chip(IRQ_LOCOMO_SPI_BASE, &locomo_chip); | 457 | set_irq_chip(IRQ_LOCOMO_SPI_BASE, &locomo_chip); |
| 458 | set_irq_chipdata(IRQ_LOCOMO_SPI_BASE, irqbase); | 458 | set_irq_chipdata(IRQ_LOCOMO_SPI_BASE, irqbase); |
| 459 | set_irq_chained_handler(IRQ_LOCOMO_SPI_BASE, locomo_spi_handler); | 459 | set_irq_chained_handler(IRQ_LOCOMO_SPI_BASE, locomo_spi_handler); |
| 460 | set_irq_flags(IRQ_LOCOMO_SPI_BASE, IRQF_VALID | IRQF_PROBE); | 460 | set_irq_flags(IRQ_LOCOMO_SPI_BASE, IRQF_VALID | IRQF_PROBE); |
| 461 | 461 | ||
| 462 | /* install handlers for IRQ_LOCOMO_KEY_BASE generated interrupts */ | 462 | /* install handlers for IRQ_LOCOMO_KEY_BASE generated interrupts */ |
| 463 | set_irq_chip(LOCOMO_IRQ_KEY_START, &locomo_key_chip); | 463 | set_irq_chip(LOCOMO_IRQ_KEY_START, &locomo_key_chip); |
| 464 | set_irq_chipdata(LOCOMO_IRQ_KEY_START, irqbase); | 464 | set_irq_chipdata(LOCOMO_IRQ_KEY_START, irqbase); |
| 465 | set_irq_handler(LOCOMO_IRQ_KEY_START, do_edge_IRQ); | 465 | set_irq_handler(LOCOMO_IRQ_KEY_START, do_edge_IRQ); |
| 466 | set_irq_flags(LOCOMO_IRQ_KEY_START, IRQF_VALID | IRQF_PROBE); | 466 | set_irq_flags(LOCOMO_IRQ_KEY_START, IRQF_VALID | IRQF_PROBE); |
| 467 | 467 | ||
| 468 | /* install handlers for IRQ_LOCOMO_GPIO_BASE generated interrupts */ | 468 | /* install handlers for IRQ_LOCOMO_GPIO_BASE generated interrupts */ |
| 469 | for (irq = LOCOMO_IRQ_GPIO_START; irq < LOCOMO_IRQ_GPIO_START + 16; irq++) { | 469 | for (irq = LOCOMO_IRQ_GPIO_START; irq < LOCOMO_IRQ_GPIO_START + 16; irq++) { |
| 470 | set_irq_chip(irq, &locomo_gpio_chip); | 470 | set_irq_chip(irq, &locomo_gpio_chip); |
| 471 | set_irq_chipdata(irq, irqbase); | 471 | set_irq_chipdata(irq, irqbase); |
| 472 | set_irq_handler(irq, do_edge_IRQ); | 472 | set_irq_handler(irq, do_edge_IRQ); |
| 473 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 473 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
| 474 | } | 474 | } |
| 475 | 475 | ||
| 476 | /* install handlers for IRQ_LOCOMO_LT_BASE generated interrupts */ | 476 | /* install handlers for IRQ_LOCOMO_LT_BASE generated interrupts */ |
| 477 | set_irq_chip(LOCOMO_IRQ_LT_START, &locomo_lt_chip); | 477 | set_irq_chip(LOCOMO_IRQ_LT_START, &locomo_lt_chip); |
| 478 | set_irq_chipdata(LOCOMO_IRQ_LT_START, irqbase); | 478 | set_irq_chipdata(LOCOMO_IRQ_LT_START, irqbase); |
| 479 | set_irq_handler(LOCOMO_IRQ_LT_START, do_edge_IRQ); | 479 | set_irq_handler(LOCOMO_IRQ_LT_START, do_edge_IRQ); |
| 480 | set_irq_flags(LOCOMO_IRQ_LT_START, IRQF_VALID | IRQF_PROBE); | 480 | set_irq_flags(LOCOMO_IRQ_LT_START, IRQF_VALID | IRQF_PROBE); |
| 481 | 481 | ||
| 482 | /* install handlers for IRQ_LOCOMO_SPI_BASE generated interrupts */ | 482 | /* install handlers for IRQ_LOCOMO_SPI_BASE generated interrupts */ |
| 483 | for (irq = LOCOMO_IRQ_SPI_START; irq < LOCOMO_IRQ_SPI_START + 3; irq++) { | 483 | for (irq = LOCOMO_IRQ_SPI_START; irq < LOCOMO_IRQ_SPI_START + 3; irq++) { |
| 484 | set_irq_chip(irq, &locomo_spi_chip); | 484 | set_irq_chip(irq, &locomo_spi_chip); |
| 485 | set_irq_chipdata(irq, irqbase); | 485 | set_irq_chipdata(irq, irqbase); |
| 486 | set_irq_handler(irq, do_edge_IRQ); | 486 | set_irq_handler(irq, do_edge_IRQ); |
| 487 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 487 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
| 488 | } | 488 | } |
| 489 | } | 489 | } |
| 490 | 490 | ||
| 491 | 491 | ||
| 492 | static void locomo_dev_release(struct device *_dev) | 492 | static void locomo_dev_release(struct device *_dev) |
| 493 | { | 493 | { |
| 494 | struct locomo_dev *dev = LOCOMO_DEV(_dev); | 494 | struct locomo_dev *dev = LOCOMO_DEV(_dev); |
| 495 | 495 | ||
| 496 | kfree(dev); | 496 | kfree(dev); |
| 497 | } | 497 | } |
| 498 | 498 | ||
| 499 | static int | 499 | static int |
| 500 | locomo_init_one_child(struct locomo *lchip, struct locomo_dev_info *info) | 500 | locomo_init_one_child(struct locomo *lchip, struct locomo_dev_info *info) |
| 501 | { | 501 | { |
| 502 | struct locomo_dev *dev; | 502 | struct locomo_dev *dev; |
| 503 | int ret; | 503 | int ret; |
| 504 | 504 | ||
| 505 | dev = kmalloc(sizeof(struct locomo_dev), GFP_KERNEL); | 505 | dev = kmalloc(sizeof(struct locomo_dev), GFP_KERNEL); |
| 506 | if (!dev) { | 506 | if (!dev) { |
| 507 | ret = -ENOMEM; | 507 | ret = -ENOMEM; |
| 508 | goto out; | 508 | goto out; |
| 509 | } | 509 | } |
| 510 | memset(dev, 0, sizeof(struct locomo_dev)); | 510 | memset(dev, 0, sizeof(struct locomo_dev)); |
| 511 | 511 | ||
| 512 | strncpy(dev->dev.bus_id,info->name,sizeof(dev->dev.bus_id)); | 512 | strncpy(dev->dev.bus_id,info->name,sizeof(dev->dev.bus_id)); |
| 513 | /* | 513 | /* |
| 514 | * If the parent device has a DMA mask associated with it, | 514 | * If the parent device has a DMA mask associated with it, |
| 515 | * propagate it down to the children. | 515 | * propagate it down to the children. |
| 516 | */ | 516 | */ |
| 517 | if (lchip->dev->dma_mask) { | 517 | if (lchip->dev->dma_mask) { |
| 518 | dev->dma_mask = *lchip->dev->dma_mask; | 518 | dev->dma_mask = *lchip->dev->dma_mask; |
| 519 | dev->dev.dma_mask = &dev->dma_mask; | 519 | dev->dev.dma_mask = &dev->dma_mask; |
| 520 | } | 520 | } |
| 521 | 521 | ||
| 522 | dev->devid = info->devid; | 522 | dev->devid = info->devid; |
| 523 | dev->dev.parent = lchip->dev; | 523 | dev->dev.parent = lchip->dev; |
| 524 | dev->dev.bus = &locomo_bus_type; | 524 | dev->dev.bus = &locomo_bus_type; |
| 525 | dev->dev.release = locomo_dev_release; | 525 | dev->dev.release = locomo_dev_release; |
| 526 | dev->dev.coherent_dma_mask = lchip->dev->coherent_dma_mask; | 526 | dev->dev.coherent_dma_mask = lchip->dev->coherent_dma_mask; |
| 527 | 527 | ||
| 528 | if (info->offset) | 528 | if (info->offset) |
| 529 | dev->mapbase = lchip->base + info->offset; | 529 | dev->mapbase = lchip->base + info->offset; |
| 530 | else | 530 | else |
| 531 | dev->mapbase = 0; | 531 | dev->mapbase = 0; |
| 532 | dev->length = info->length; | 532 | dev->length = info->length; |
| 533 | 533 | ||
| 534 | memmove(dev->irq, info->irq, sizeof(dev->irq)); | 534 | memmove(dev->irq, info->irq, sizeof(dev->irq)); |
| 535 | 535 | ||
| 536 | ret = device_register(&dev->dev); | 536 | ret = device_register(&dev->dev); |
| 537 | if (ret) { | 537 | if (ret) { |
| 538 | out: | 538 | out: |
| 539 | kfree(dev); | 539 | kfree(dev); |
| 540 | } | 540 | } |
| 541 | return ret; | 541 | return ret; |
| 542 | } | 542 | } |
| 543 | 543 | ||
| 544 | /** | 544 | /** |
| 545 | * locomo_probe - probe for a single LoCoMo chip. | 545 | * locomo_probe - probe for a single LoCoMo chip. |
| 546 | * @phys_addr: physical address of device. | 546 | * @phys_addr: physical address of device. |
| 547 | * | 547 | * |
| 548 | * Probe for a LoCoMo chip. This must be called | 548 | * Probe for a LoCoMo chip. This must be called |
| 549 | * before any other locomo-specific code. | 549 | * before any other locomo-specific code. |
| 550 | * | 550 | * |
| 551 | * Returns: | 551 | * Returns: |
| 552 | * %-ENODEV device not found. | 552 | * %-ENODEV device not found. |
| 553 | * %-EBUSY physical address already marked in-use. | 553 | * %-EBUSY physical address already marked in-use. |
| 554 | * %0 successful. | 554 | * %0 successful. |
| 555 | */ | 555 | */ |
| 556 | static int | 556 | static int |
| 557 | __locomo_probe(struct device *me, struct resource *mem, int irq) | 557 | __locomo_probe(struct device *me, struct resource *mem, int irq) |
| 558 | { | 558 | { |
| 559 | struct locomo *lchip; | 559 | struct locomo *lchip; |
| 560 | unsigned long r; | 560 | unsigned long r; |
| 561 | int i, ret = -ENODEV; | 561 | int i, ret = -ENODEV; |
| 562 | 562 | ||
| 563 | lchip = kmalloc(sizeof(struct locomo), GFP_KERNEL); | 563 | lchip = kmalloc(sizeof(struct locomo), GFP_KERNEL); |
| 564 | if (!lchip) | 564 | if (!lchip) |
| 565 | return -ENOMEM; | 565 | return -ENOMEM; |
| 566 | 566 | ||
| 567 | memset(lchip, 0, sizeof(struct locomo)); | 567 | memset(lchip, 0, sizeof(struct locomo)); |
| 568 | 568 | ||
| 569 | spin_lock_init(&lchip->lock); | 569 | spin_lock_init(&lchip->lock); |
| 570 | 570 | ||
| 571 | lchip->dev = me; | 571 | lchip->dev = me; |
| 572 | dev_set_drvdata(lchip->dev, lchip); | 572 | dev_set_drvdata(lchip->dev, lchip); |
| 573 | 573 | ||
| 574 | lchip->phys = mem->start; | 574 | lchip->phys = mem->start; |
| 575 | lchip->irq = irq; | 575 | lchip->irq = irq; |
| 576 | 576 | ||
| 577 | /* | 577 | /* |
| 578 | * Map the whole region. This also maps the | 578 | * Map the whole region. This also maps the |
| 579 | * registers for our children. | 579 | * registers for our children. |
| 580 | */ | 580 | */ |
| 581 | lchip->base = ioremap(mem->start, PAGE_SIZE); | 581 | lchip->base = ioremap(mem->start, PAGE_SIZE); |
| 582 | if (!lchip->base) { | 582 | if (!lchip->base) { |
| 583 | ret = -ENOMEM; | 583 | ret = -ENOMEM; |
| 584 | goto out; | 584 | goto out; |
| 585 | } | 585 | } |
| 586 | 586 | ||
| 587 | /* locomo initialize */ | 587 | /* locomo initialize */ |
| 588 | locomo_writel(0, lchip->base + LOCOMO_ICR); | 588 | locomo_writel(0, lchip->base + LOCOMO_ICR); |
| 589 | /* KEYBOARD */ | 589 | /* KEYBOARD */ |
| 590 | locomo_writel(0, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KIC); | 590 | locomo_writel(0, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KIC); |
| 591 | 591 | ||
| 592 | /* GPIO */ | 592 | /* GPIO */ |
| 593 | locomo_writel(0, lchip->base + LOCOMO_GPO); | 593 | locomo_writel(0, lchip->base + LOCOMO_GPO); |
| 594 | locomo_writel( (LOCOMO_GPIO(2) | LOCOMO_GPIO(3) | LOCOMO_GPIO(13) | LOCOMO_GPIO(14)) | 594 | locomo_writel( (LOCOMO_GPIO(2) | LOCOMO_GPIO(3) | LOCOMO_GPIO(13) | LOCOMO_GPIO(14)) |
| 595 | , lchip->base + LOCOMO_GPE); | 595 | , lchip->base + LOCOMO_GPE); |
| 596 | locomo_writel( (LOCOMO_GPIO(2) | LOCOMO_GPIO(3) | LOCOMO_GPIO(13) | LOCOMO_GPIO(14)) | 596 | locomo_writel( (LOCOMO_GPIO(2) | LOCOMO_GPIO(3) | LOCOMO_GPIO(13) | LOCOMO_GPIO(14)) |
| 597 | , lchip->base + LOCOMO_GPD); | 597 | , lchip->base + LOCOMO_GPD); |
| 598 | locomo_writel(0, lchip->base + LOCOMO_GIE); | 598 | locomo_writel(0, lchip->base + LOCOMO_GIE); |
| 599 | 599 | ||
| 600 | /* FrontLight */ | 600 | /* FrontLight */ |
| 601 | locomo_writel(0, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS); | 601 | locomo_writel(0, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS); |
| 602 | locomo_writel(0, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALD); | 602 | locomo_writel(0, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALD); |
| 603 | /* Longtime timer */ | 603 | /* Longtime timer */ |
| 604 | locomo_writel(0, lchip->base + LOCOMO_LTINT); | 604 | locomo_writel(0, lchip->base + LOCOMO_LTINT); |
| 605 | /* SPI */ | 605 | /* SPI */ |
| 606 | locomo_writel(0, lchip->base + LOCOMO_SPIIE); | 606 | locomo_writel(0, lchip->base + LOCOMO_SPIIE); |
| 607 | 607 | ||
| 608 | locomo_writel(6 + 8 + 320 + 30 - 10, lchip->base + LOCOMO_ASD); | 608 | locomo_writel(6 + 8 + 320 + 30 - 10, lchip->base + LOCOMO_ASD); |
| 609 | r = locomo_readl(lchip->base + LOCOMO_ASD); | 609 | r = locomo_readl(lchip->base + LOCOMO_ASD); |
| 610 | r |= 0x8000; | 610 | r |= 0x8000; |
| 611 | locomo_writel(r, lchip->base + LOCOMO_ASD); | 611 | locomo_writel(r, lchip->base + LOCOMO_ASD); |
| 612 | 612 | ||
| 613 | locomo_writel(6 + 8 + 320 + 30 - 10 - 128 + 4, lchip->base + LOCOMO_HSD); | 613 | locomo_writel(6 + 8 + 320 + 30 - 10 - 128 + 4, lchip->base + LOCOMO_HSD); |
| 614 | r = locomo_readl(lchip->base + LOCOMO_HSD); | 614 | r = locomo_readl(lchip->base + LOCOMO_HSD); |
| 615 | r |= 0x8000; | 615 | r |= 0x8000; |
| 616 | locomo_writel(r, lchip->base + LOCOMO_HSD); | 616 | locomo_writel(r, lchip->base + LOCOMO_HSD); |
| 617 | 617 | ||
| 618 | locomo_writel(128 / 8, lchip->base + LOCOMO_HSC); | 618 | locomo_writel(128 / 8, lchip->base + LOCOMO_HSC); |
| 619 | 619 | ||
| 620 | /* XON */ | 620 | /* XON */ |
| 621 | locomo_writel(0x80, lchip->base + LOCOMO_TADC); | 621 | locomo_writel(0x80, lchip->base + LOCOMO_TADC); |
| 622 | udelay(1000); | 622 | udelay(1000); |
| 623 | /* CLK9MEN */ | 623 | /* CLK9MEN */ |
| 624 | r = locomo_readl(lchip->base + LOCOMO_TADC); | 624 | r = locomo_readl(lchip->base + LOCOMO_TADC); |
| 625 | r |= 0x10; | 625 | r |= 0x10; |
| 626 | locomo_writel(r, lchip->base + LOCOMO_TADC); | 626 | locomo_writel(r, lchip->base + LOCOMO_TADC); |
| 627 | udelay(100); | 627 | udelay(100); |
| 628 | 628 | ||
| 629 | /* init DAC */ | 629 | /* init DAC */ |
| 630 | r = locomo_readl(lchip->base + LOCOMO_DAC); | 630 | r = locomo_readl(lchip->base + LOCOMO_DAC); |
| 631 | r |= LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB; | 631 | r |= LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB; |
| 632 | locomo_writel(r, lchip->base + LOCOMO_DAC); | 632 | locomo_writel(r, lchip->base + LOCOMO_DAC); |
| 633 | 633 | ||
| 634 | r = locomo_readl(lchip->base + LOCOMO_VER); | 634 | r = locomo_readl(lchip->base + LOCOMO_VER); |
| 635 | printk(KERN_INFO "LoCoMo Chip: %lu%lu\n", (r >> 8), (r & 0xff)); | 635 | printk(KERN_INFO "LoCoMo Chip: %lu%lu\n", (r >> 8), (r & 0xff)); |
| 636 | 636 | ||
| 637 | /* | 637 | /* |
| 638 | * The interrupt controller must be initialised before any | 638 | * The interrupt controller must be initialised before any |
| 639 | * other device to ensure that the interrupts are available. | 639 | * other device to ensure that the interrupts are available. |
| 640 | */ | 640 | */ |
| 641 | if (lchip->irq != NO_IRQ) | 641 | if (lchip->irq != NO_IRQ) |
| 642 | locomo_setup_irq(lchip); | 642 | locomo_setup_irq(lchip); |
| 643 | 643 | ||
| 644 | for (i = 0; i < ARRAY_SIZE(locomo_devices); i++) | 644 | for (i = 0; i < ARRAY_SIZE(locomo_devices); i++) |
| 645 | locomo_init_one_child(lchip, &locomo_devices[i]); | 645 | locomo_init_one_child(lchip, &locomo_devices[i]); |
| 646 | 646 | ||
| 647 | return 0; | 647 | return 0; |
| 648 | 648 | ||
| 649 | out: | 649 | out: |
| 650 | kfree(lchip); | 650 | kfree(lchip); |
| 651 | return ret; | 651 | return ret; |
| 652 | } | 652 | } |
| 653 | 653 | ||
| 654 | static void __locomo_remove(struct locomo *lchip) | 654 | static int locomo_remove_child(struct device *dev, void *data) |
| 655 | { | 655 | { |
| 656 | struct list_head *l, *n; | 656 | device_unregister(dev); |
| 657 | return 0; | ||
| 658 | } | ||
| 657 | 659 | ||
| 658 | list_for_each_safe(l, n, &lchip->dev->children) { | 660 | static void __locomo_remove(struct locomo *lchip) |
| 659 | struct device *d = list_to_dev(l); | 661 | { |
| 660 | 662 | device_for_each_child(lchip->dev, NULL, locomo_remove_child); | |
| 661 | device_unregister(d); | ||
| 662 | } | ||
| 663 | 663 | ||
| 664 | if (lchip->irq != NO_IRQ) { | 664 | if (lchip->irq != NO_IRQ) { |
| 665 | set_irq_chained_handler(lchip->irq, NULL); | 665 | set_irq_chained_handler(lchip->irq, NULL); |
| 666 | set_irq_data(lchip->irq, NULL); | 666 | set_irq_data(lchip->irq, NULL); |
| 667 | } | 667 | } |
| 668 | 668 | ||
| 669 | iounmap(lchip->base); | 669 | iounmap(lchip->base); |
| 670 | kfree(lchip); | 670 | kfree(lchip); |
| 671 | } | 671 | } |
| 672 | 672 | ||
| 673 | static int locomo_probe(struct device *dev) | 673 | static int locomo_probe(struct device *dev) |
| 674 | { | 674 | { |
| 675 | struct platform_device *pdev = to_platform_device(dev); | 675 | struct platform_device *pdev = to_platform_device(dev); |
| 676 | struct resource *mem; | 676 | struct resource *mem; |
| 677 | int irq; | 677 | int irq; |
| 678 | 678 | ||
| 679 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 679 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 680 | if (!mem) | 680 | if (!mem) |
| 681 | return -EINVAL; | 681 | return -EINVAL; |
| 682 | irq = platform_get_irq(pdev, 0); | 682 | irq = platform_get_irq(pdev, 0); |
| 683 | 683 | ||
| 684 | return __locomo_probe(dev, mem, irq); | 684 | return __locomo_probe(dev, mem, irq); |
| 685 | } | 685 | } |
| 686 | 686 | ||
| 687 | static int locomo_remove(struct device *dev) | 687 | static int locomo_remove(struct device *dev) |
| 688 | { | 688 | { |
| 689 | struct locomo *lchip = dev_get_drvdata(dev); | 689 | struct locomo *lchip = dev_get_drvdata(dev); |
| 690 | 690 | ||
| 691 | if (lchip) { | 691 | if (lchip) { |
| 692 | __locomo_remove(lchip); | 692 | __locomo_remove(lchip); |
| 693 | dev_set_drvdata(dev, NULL); | 693 | dev_set_drvdata(dev, NULL); |
| 694 | } | 694 | } |
| 695 | 695 | ||
| 696 | return 0; | 696 | return 0; |
| 697 | } | 697 | } |
| 698 | 698 | ||
| 699 | /* | 699 | /* |
| 700 | * Not sure if this should be on the system bus or not yet. | 700 | * Not sure if this should be on the system bus or not yet. |
| 701 | * We really want some way to register a system device at | 701 | * We really want some way to register a system device at |
| 702 | * the per-machine level, and then have this driver pick | 702 | * the per-machine level, and then have this driver pick |
| 703 | * up the registered devices. | 703 | * up the registered devices. |
| 704 | */ | 704 | */ |
| 705 | static struct device_driver locomo_device_driver = { | 705 | static struct device_driver locomo_device_driver = { |
| 706 | .name = "locomo", | 706 | .name = "locomo", |
| 707 | .bus = &platform_bus_type, | 707 | .bus = &platform_bus_type, |
| 708 | .probe = locomo_probe, | 708 | .probe = locomo_probe, |
| 709 | .remove = locomo_remove, | 709 | .remove = locomo_remove, |
| 710 | }; | 710 | }; |
| 711 | 711 | ||
| 712 | /* | 712 | /* |
| 713 | * Get the parent device driver (us) structure | 713 | * Get the parent device driver (us) structure |
| 714 | * from a child function device | 714 | * from a child function device |
| 715 | */ | 715 | */ |
| 716 | static inline struct locomo *locomo_chip_driver(struct locomo_dev *ldev) | 716 | static inline struct locomo *locomo_chip_driver(struct locomo_dev *ldev) |
| 717 | { | 717 | { |
| 718 | return (struct locomo *)dev_get_drvdata(ldev->dev.parent); | 718 | return (struct locomo *)dev_get_drvdata(ldev->dev.parent); |
| 719 | } | 719 | } |
| 720 | 720 | ||
| 721 | void locomo_gpio_set_dir(struct locomo_dev *ldev, unsigned int bits, unsigned int dir) | 721 | void locomo_gpio_set_dir(struct locomo_dev *ldev, unsigned int bits, unsigned int dir) |
| 722 | { | 722 | { |
| 723 | struct locomo *lchip = locomo_chip_driver(ldev); | 723 | struct locomo *lchip = locomo_chip_driver(ldev); |
| 724 | unsigned long flags; | 724 | unsigned long flags; |
| 725 | unsigned int r; | 725 | unsigned int r; |
| 726 | 726 | ||
| 727 | spin_lock_irqsave(&lchip->lock, flags); | 727 | spin_lock_irqsave(&lchip->lock, flags); |
| 728 | 728 | ||
| 729 | r = locomo_readl(lchip->base + LOCOMO_GPD); | 729 | r = locomo_readl(lchip->base + LOCOMO_GPD); |
| 730 | r &= ~bits; | 730 | r &= ~bits; |
| 731 | locomo_writel(r, lchip->base + LOCOMO_GPD); | 731 | locomo_writel(r, lchip->base + LOCOMO_GPD); |
| 732 | 732 | ||
| 733 | r = locomo_readl(lchip->base + LOCOMO_GPE); | 733 | r = locomo_readl(lchip->base + LOCOMO_GPE); |
| 734 | if (dir) | 734 | if (dir) |
| 735 | r |= bits; | 735 | r |= bits; |
| 736 | else | 736 | else |
| 737 | r &= ~bits; | 737 | r &= ~bits; |
| 738 | locomo_writel(r, lchip->base + LOCOMO_GPE); | 738 | locomo_writel(r, lchip->base + LOCOMO_GPE); |
| 739 | 739 | ||
| 740 | spin_unlock_irqrestore(&lchip->lock, flags); | 740 | spin_unlock_irqrestore(&lchip->lock, flags); |
| 741 | } | 741 | } |
| 742 | 742 | ||
| 743 | unsigned int locomo_gpio_read_level(struct locomo_dev *ldev, unsigned int bits) | 743 | unsigned int locomo_gpio_read_level(struct locomo_dev *ldev, unsigned int bits) |
| 744 | { | 744 | { |
| 745 | struct locomo *lchip = locomo_chip_driver(ldev); | 745 | struct locomo *lchip = locomo_chip_driver(ldev); |
| 746 | unsigned long flags; | 746 | unsigned long flags; |
| 747 | unsigned int ret; | 747 | unsigned int ret; |
| 748 | 748 | ||
| 749 | spin_lock_irqsave(&lchip->lock, flags); | 749 | spin_lock_irqsave(&lchip->lock, flags); |
| 750 | ret = locomo_readl(lchip->base + LOCOMO_GPL); | 750 | ret = locomo_readl(lchip->base + LOCOMO_GPL); |
| 751 | spin_unlock_irqrestore(&lchip->lock, flags); | 751 | spin_unlock_irqrestore(&lchip->lock, flags); |
| 752 | 752 | ||
| 753 | ret &= bits; | 753 | ret &= bits; |
| 754 | return ret; | 754 | return ret; |
| 755 | } | 755 | } |
| 756 | 756 | ||
| 757 | unsigned int locomo_gpio_read_output(struct locomo_dev *ldev, unsigned int bits) | 757 | unsigned int locomo_gpio_read_output(struct locomo_dev *ldev, unsigned int bits) |
| 758 | { | 758 | { |
| 759 | struct locomo *lchip = locomo_chip_driver(ldev); | 759 | struct locomo *lchip = locomo_chip_driver(ldev); |
| 760 | unsigned long flags; | 760 | unsigned long flags; |
| 761 | unsigned int ret; | 761 | unsigned int ret; |
| 762 | 762 | ||
| 763 | spin_lock_irqsave(&lchip->lock, flags); | 763 | spin_lock_irqsave(&lchip->lock, flags); |
| 764 | ret = locomo_readl(lchip->base + LOCOMO_GPO); | 764 | ret = locomo_readl(lchip->base + LOCOMO_GPO); |
| 765 | spin_unlock_irqrestore(&lchip->lock, flags); | 765 | spin_unlock_irqrestore(&lchip->lock, flags); |
| 766 | 766 | ||
| 767 | ret &= bits; | 767 | ret &= bits; |
| 768 | return ret; | 768 | return ret; |
| 769 | } | 769 | } |
| 770 | 770 | ||
| 771 | void locomo_gpio_write(struct locomo_dev *ldev, unsigned int bits, unsigned int set) | 771 | void locomo_gpio_write(struct locomo_dev *ldev, unsigned int bits, unsigned int set) |
| 772 | { | 772 | { |
| 773 | struct locomo *lchip = locomo_chip_driver(ldev); | 773 | struct locomo *lchip = locomo_chip_driver(ldev); |
| 774 | unsigned long flags; | 774 | unsigned long flags; |
| 775 | unsigned int r; | 775 | unsigned int r; |
| 776 | 776 | ||
| 777 | spin_lock_irqsave(&lchip->lock, flags); | 777 | spin_lock_irqsave(&lchip->lock, flags); |
| 778 | 778 | ||
| 779 | r = locomo_readl(lchip->base + LOCOMO_GPO); | 779 | r = locomo_readl(lchip->base + LOCOMO_GPO); |
| 780 | if (set) | 780 | if (set) |
| 781 | r |= bits; | 781 | r |= bits; |
| 782 | else | 782 | else |
| 783 | r &= ~bits; | 783 | r &= ~bits; |
| 784 | locomo_writel(r, lchip->base + LOCOMO_GPO); | 784 | locomo_writel(r, lchip->base + LOCOMO_GPO); |
| 785 | 785 | ||
| 786 | spin_unlock_irqrestore(&lchip->lock, flags); | 786 | spin_unlock_irqrestore(&lchip->lock, flags); |
| 787 | } | 787 | } |
| 788 | 788 | ||
| 789 | static void locomo_m62332_sendbit(void *mapbase, int bit) | 789 | static void locomo_m62332_sendbit(void *mapbase, int bit) |
| 790 | { | 790 | { |
| 791 | unsigned int r; | 791 | unsigned int r; |
| 792 | 792 | ||
| 793 | r = locomo_readl(mapbase + LOCOMO_DAC); | 793 | r = locomo_readl(mapbase + LOCOMO_DAC); |
| 794 | r &= ~(LOCOMO_DAC_SCLOEB); | 794 | r &= ~(LOCOMO_DAC_SCLOEB); |
| 795 | locomo_writel(r, mapbase + LOCOMO_DAC); | 795 | locomo_writel(r, mapbase + LOCOMO_DAC); |
| 796 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ | 796 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ |
| 797 | udelay(DAC_DATA_HOLD_TIME); /* 300 nsec */ | 797 | udelay(DAC_DATA_HOLD_TIME); /* 300 nsec */ |
| 798 | r = locomo_readl(mapbase + LOCOMO_DAC); | 798 | r = locomo_readl(mapbase + LOCOMO_DAC); |
| 799 | r &= ~(LOCOMO_DAC_SCLOEB); | 799 | r &= ~(LOCOMO_DAC_SCLOEB); |
| 800 | locomo_writel(r, mapbase + LOCOMO_DAC); | 800 | locomo_writel(r, mapbase + LOCOMO_DAC); |
| 801 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ | 801 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ |
| 802 | udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ | 802 | udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ |
| 803 | 803 | ||
| 804 | if (bit & 1) { | 804 | if (bit & 1) { |
| 805 | r = locomo_readl(mapbase + LOCOMO_DAC); | 805 | r = locomo_readl(mapbase + LOCOMO_DAC); |
| 806 | r |= LOCOMO_DAC_SDAOEB; | 806 | r |= LOCOMO_DAC_SDAOEB; |
| 807 | locomo_writel(r, mapbase + LOCOMO_DAC); | 807 | locomo_writel(r, mapbase + LOCOMO_DAC); |
| 808 | udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ | 808 | udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ |
| 809 | } else { | 809 | } else { |
| 810 | r = locomo_readl(mapbase + LOCOMO_DAC); | 810 | r = locomo_readl(mapbase + LOCOMO_DAC); |
| 811 | r &= ~(LOCOMO_DAC_SDAOEB); | 811 | r &= ~(LOCOMO_DAC_SDAOEB); |
| 812 | locomo_writel(r, mapbase + LOCOMO_DAC); | 812 | locomo_writel(r, mapbase + LOCOMO_DAC); |
| 813 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ | 813 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ |
| 814 | } | 814 | } |
| 815 | 815 | ||
| 816 | udelay(DAC_DATA_SETUP_TIME); /* 250 nsec */ | 816 | udelay(DAC_DATA_SETUP_TIME); /* 250 nsec */ |
| 817 | r = locomo_readl(mapbase + LOCOMO_DAC); | 817 | r = locomo_readl(mapbase + LOCOMO_DAC); |
| 818 | r |= LOCOMO_DAC_SCLOEB; | 818 | r |= LOCOMO_DAC_SCLOEB; |
| 819 | locomo_writel(r, mapbase + LOCOMO_DAC); | 819 | locomo_writel(r, mapbase + LOCOMO_DAC); |
| 820 | udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ | 820 | udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ |
| 821 | udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.0 usec */ | 821 | udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.0 usec */ |
| 822 | } | 822 | } |
| 823 | 823 | ||
| 824 | void locomo_m62332_senddata(struct locomo_dev *ldev, unsigned int dac_data, int channel) | 824 | void locomo_m62332_senddata(struct locomo_dev *ldev, unsigned int dac_data, int channel) |
| 825 | { | 825 | { |
| 826 | struct locomo *lchip = locomo_chip_driver(ldev); | 826 | struct locomo *lchip = locomo_chip_driver(ldev); |
| 827 | int i; | 827 | int i; |
| 828 | unsigned char data; | 828 | unsigned char data; |
| 829 | unsigned int r; | 829 | unsigned int r; |
| 830 | void *mapbase = lchip->base; | 830 | void *mapbase = lchip->base; |
| 831 | unsigned long flags; | 831 | unsigned long flags; |
| 832 | 832 | ||
| 833 | spin_lock_irqsave(&lchip->lock, flags); | 833 | spin_lock_irqsave(&lchip->lock, flags); |
| 834 | 834 | ||
| 835 | /* Start */ | 835 | /* Start */ |
| 836 | udelay(DAC_BUS_FREE_TIME); /* 5.0 usec */ | 836 | udelay(DAC_BUS_FREE_TIME); /* 5.0 usec */ |
| 837 | r = locomo_readl(mapbase + LOCOMO_DAC); | 837 | r = locomo_readl(mapbase + LOCOMO_DAC); |
| 838 | r |= LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB; | 838 | r |= LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB; |
| 839 | locomo_writel(r, mapbase + LOCOMO_DAC); | 839 | locomo_writel(r, mapbase + LOCOMO_DAC); |
| 840 | udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ | 840 | udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ |
| 841 | udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.0 usec */ | 841 | udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.0 usec */ |
| 842 | r = locomo_readl(mapbase + LOCOMO_DAC); | 842 | r = locomo_readl(mapbase + LOCOMO_DAC); |
| 843 | r &= ~(LOCOMO_DAC_SDAOEB); | 843 | r &= ~(LOCOMO_DAC_SDAOEB); |
| 844 | locomo_writel(r, mapbase + LOCOMO_DAC); | 844 | locomo_writel(r, mapbase + LOCOMO_DAC); |
| 845 | udelay(DAC_START_HOLD_TIME); /* 5.0 usec */ | 845 | udelay(DAC_START_HOLD_TIME); /* 5.0 usec */ |
| 846 | udelay(DAC_DATA_HOLD_TIME); /* 300 nsec */ | 846 | udelay(DAC_DATA_HOLD_TIME); /* 300 nsec */ |
| 847 | 847 | ||
| 848 | /* Send slave address and W bit (LSB is W bit) */ | 848 | /* Send slave address and W bit (LSB is W bit) */ |
| 849 | data = (M62332_SLAVE_ADDR << 1) | M62332_W_BIT; | 849 | data = (M62332_SLAVE_ADDR << 1) | M62332_W_BIT; |
| 850 | for (i = 1; i <= 8; i++) { | 850 | for (i = 1; i <= 8; i++) { |
| 851 | locomo_m62332_sendbit(mapbase, data >> (8 - i)); | 851 | locomo_m62332_sendbit(mapbase, data >> (8 - i)); |
| 852 | } | 852 | } |
| 853 | 853 | ||
| 854 | /* Check A bit */ | 854 | /* Check A bit */ |
| 855 | r = locomo_readl(mapbase + LOCOMO_DAC); | 855 | r = locomo_readl(mapbase + LOCOMO_DAC); |
| 856 | r &= ~(LOCOMO_DAC_SCLOEB); | 856 | r &= ~(LOCOMO_DAC_SCLOEB); |
| 857 | locomo_writel(r, mapbase + LOCOMO_DAC); | 857 | locomo_writel(r, mapbase + LOCOMO_DAC); |
| 858 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ | 858 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ |
| 859 | udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ | 859 | udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ |
| 860 | r = locomo_readl(mapbase + LOCOMO_DAC); | 860 | r = locomo_readl(mapbase + LOCOMO_DAC); |
| 861 | r &= ~(LOCOMO_DAC_SDAOEB); | 861 | r &= ~(LOCOMO_DAC_SDAOEB); |
| 862 | locomo_writel(r, mapbase + LOCOMO_DAC); | 862 | locomo_writel(r, mapbase + LOCOMO_DAC); |
| 863 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ | 863 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ |
| 864 | r = locomo_readl(mapbase + LOCOMO_DAC); | 864 | r = locomo_readl(mapbase + LOCOMO_DAC); |
| 865 | r |= LOCOMO_DAC_SCLOEB; | 865 | r |= LOCOMO_DAC_SCLOEB; |
| 866 | locomo_writel(r, mapbase + LOCOMO_DAC); | 866 | locomo_writel(r, mapbase + LOCOMO_DAC); |
| 867 | udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ | 867 | udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ |
| 868 | udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.7 usec */ | 868 | udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.7 usec */ |
| 869 | if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) { /* High is error */ | 869 | if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) { /* High is error */ |
| 870 | printk(KERN_WARNING "locomo: m62332_senddata Error 1\n"); | 870 | printk(KERN_WARNING "locomo: m62332_senddata Error 1\n"); |
| 871 | return; | 871 | return; |
| 872 | } | 872 | } |
| 873 | 873 | ||
| 874 | /* Send Sub address (LSB is channel select) */ | 874 | /* Send Sub address (LSB is channel select) */ |
| 875 | /* channel = 0 : ch1 select */ | 875 | /* channel = 0 : ch1 select */ |
| 876 | /* = 1 : ch2 select */ | 876 | /* = 1 : ch2 select */ |
| 877 | data = M62332_SUB_ADDR + channel; | 877 | data = M62332_SUB_ADDR + channel; |
| 878 | for (i = 1; i <= 8; i++) { | 878 | for (i = 1; i <= 8; i++) { |
| 879 | locomo_m62332_sendbit(mapbase, data >> (8 - i)); | 879 | locomo_m62332_sendbit(mapbase, data >> (8 - i)); |
| 880 | } | 880 | } |
| 881 | 881 | ||
| 882 | /* Check A bit */ | 882 | /* Check A bit */ |
| 883 | r = locomo_readl(mapbase + LOCOMO_DAC); | 883 | r = locomo_readl(mapbase + LOCOMO_DAC); |
| 884 | r &= ~(LOCOMO_DAC_SCLOEB); | 884 | r &= ~(LOCOMO_DAC_SCLOEB); |
| 885 | locomo_writel(r, mapbase + LOCOMO_DAC); | 885 | locomo_writel(r, mapbase + LOCOMO_DAC); |
| 886 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ | 886 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ |
| 887 | udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ | 887 | udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ |
| 888 | r = locomo_readl(mapbase + LOCOMO_DAC); | 888 | r = locomo_readl(mapbase + LOCOMO_DAC); |
| 889 | r &= ~(LOCOMO_DAC_SDAOEB); | 889 | r &= ~(LOCOMO_DAC_SDAOEB); |
| 890 | locomo_writel(r, mapbase + LOCOMO_DAC); | 890 | locomo_writel(r, mapbase + LOCOMO_DAC); |
| 891 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ | 891 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ |
| 892 | r = locomo_readl(mapbase + LOCOMO_DAC); | 892 | r = locomo_readl(mapbase + LOCOMO_DAC); |
| 893 | r |= LOCOMO_DAC_SCLOEB; | 893 | r |= LOCOMO_DAC_SCLOEB; |
| 894 | locomo_writel(r, mapbase + LOCOMO_DAC); | 894 | locomo_writel(r, mapbase + LOCOMO_DAC); |
| 895 | udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ | 895 | udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ |
| 896 | udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.7 usec */ | 896 | udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.7 usec */ |
| 897 | if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) { /* High is error */ | 897 | if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) { /* High is error */ |
| 898 | printk(KERN_WARNING "locomo: m62332_senddata Error 2\n"); | 898 | printk(KERN_WARNING "locomo: m62332_senddata Error 2\n"); |
| 899 | return; | 899 | return; |
| 900 | } | 900 | } |
| 901 | 901 | ||
| 902 | /* Send DAC data */ | 902 | /* Send DAC data */ |
| 903 | for (i = 1; i <= 8; i++) { | 903 | for (i = 1; i <= 8; i++) { |
| 904 | locomo_m62332_sendbit(mapbase, dac_data >> (8 - i)); | 904 | locomo_m62332_sendbit(mapbase, dac_data >> (8 - i)); |
| 905 | } | 905 | } |
| 906 | 906 | ||
| 907 | /* Check A bit */ | 907 | /* Check A bit */ |
| 908 | r = locomo_readl(mapbase + LOCOMO_DAC); | 908 | r = locomo_readl(mapbase + LOCOMO_DAC); |
| 909 | r &= ~(LOCOMO_DAC_SCLOEB); | 909 | r &= ~(LOCOMO_DAC_SCLOEB); |
| 910 | locomo_writel(r, mapbase + LOCOMO_DAC); | 910 | locomo_writel(r, mapbase + LOCOMO_DAC); |
| 911 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ | 911 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ |
| 912 | udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ | 912 | udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ |
| 913 | r = locomo_readl(mapbase + LOCOMO_DAC); | 913 | r = locomo_readl(mapbase + LOCOMO_DAC); |
| 914 | r &= ~(LOCOMO_DAC_SDAOEB); | 914 | r &= ~(LOCOMO_DAC_SDAOEB); |
| 915 | locomo_writel(r, mapbase + LOCOMO_DAC); | 915 | locomo_writel(r, mapbase + LOCOMO_DAC); |
| 916 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ | 916 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ |
| 917 | r = locomo_readl(mapbase + LOCOMO_DAC); | 917 | r = locomo_readl(mapbase + LOCOMO_DAC); |
| 918 | r |= LOCOMO_DAC_SCLOEB; | 918 | r |= LOCOMO_DAC_SCLOEB; |
| 919 | locomo_writel(r, mapbase + LOCOMO_DAC); | 919 | locomo_writel(r, mapbase + LOCOMO_DAC); |
| 920 | udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ | 920 | udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ |
| 921 | udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.7 usec */ | 921 | udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.7 usec */ |
| 922 | if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) { /* High is error */ | 922 | if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) { /* High is error */ |
| 923 | printk(KERN_WARNING "locomo: m62332_senddata Error 3\n"); | 923 | printk(KERN_WARNING "locomo: m62332_senddata Error 3\n"); |
| 924 | return; | 924 | return; |
| 925 | } | 925 | } |
| 926 | 926 | ||
| 927 | /* stop */ | 927 | /* stop */ |
| 928 | r = locomo_readl(mapbase + LOCOMO_DAC); | 928 | r = locomo_readl(mapbase + LOCOMO_DAC); |
| 929 | r &= ~(LOCOMO_DAC_SCLOEB); | 929 | r &= ~(LOCOMO_DAC_SCLOEB); |
| 930 | locomo_writel(r, mapbase + LOCOMO_DAC); | 930 | locomo_writel(r, mapbase + LOCOMO_DAC); |
| 931 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ | 931 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ |
| 932 | udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ | 932 | udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ |
| 933 | r = locomo_readl(mapbase + LOCOMO_DAC); | 933 | r = locomo_readl(mapbase + LOCOMO_DAC); |
| 934 | r |= LOCOMO_DAC_SCLOEB; | 934 | r |= LOCOMO_DAC_SCLOEB; |
| 935 | locomo_writel(r, mapbase + LOCOMO_DAC); | 935 | locomo_writel(r, mapbase + LOCOMO_DAC); |
| 936 | udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ | 936 | udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ |
| 937 | udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4 usec */ | 937 | udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4 usec */ |
| 938 | r = locomo_readl(mapbase + LOCOMO_DAC); | 938 | r = locomo_readl(mapbase + LOCOMO_DAC); |
| 939 | r |= LOCOMO_DAC_SDAOEB; | 939 | r |= LOCOMO_DAC_SDAOEB; |
| 940 | locomo_writel(r, mapbase + LOCOMO_DAC); | 940 | locomo_writel(r, mapbase + LOCOMO_DAC); |
| 941 | udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ | 941 | udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ |
| 942 | udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4 usec */ | 942 | udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4 usec */ |
| 943 | 943 | ||
| 944 | r = locomo_readl(mapbase + LOCOMO_DAC); | 944 | r = locomo_readl(mapbase + LOCOMO_DAC); |
| 945 | r |= LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB; | 945 | r |= LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB; |
| 946 | locomo_writel(r, mapbase + LOCOMO_DAC); | 946 | locomo_writel(r, mapbase + LOCOMO_DAC); |
| 947 | udelay(DAC_LOW_SETUP_TIME); /* 1000 nsec */ | 947 | udelay(DAC_LOW_SETUP_TIME); /* 1000 nsec */ |
| 948 | udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ | 948 | udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ |
| 949 | 949 | ||
| 950 | spin_unlock_irqrestore(&lchip->lock, flags); | 950 | spin_unlock_irqrestore(&lchip->lock, flags); |
| 951 | } | 951 | } |
| 952 | 952 | ||
| 953 | /* | 953 | /* |
| 954 | * LoCoMo "Register Access Bus." | 954 | * LoCoMo "Register Access Bus." |
| 955 | * | 955 | * |
| 956 | * We model this as a regular bus type, and hang devices directly | 956 | * We model this as a regular bus type, and hang devices directly |
| 957 | * off this. | 957 | * off this. |
| 958 | */ | 958 | */ |
| 959 | static int locomo_match(struct device *_dev, struct device_driver *_drv) | 959 | static int locomo_match(struct device *_dev, struct device_driver *_drv) |
| 960 | { | 960 | { |
| 961 | struct locomo_dev *dev = LOCOMO_DEV(_dev); | 961 | struct locomo_dev *dev = LOCOMO_DEV(_dev); |
| 962 | struct locomo_driver *drv = LOCOMO_DRV(_drv); | 962 | struct locomo_driver *drv = LOCOMO_DRV(_drv); |
| 963 | 963 | ||
| 964 | return dev->devid == drv->devid; | 964 | return dev->devid == drv->devid; |
| 965 | } | 965 | } |
| 966 | 966 | ||
| 967 | static int locomo_bus_suspend(struct device *dev, pm_message_t state) | 967 | static int locomo_bus_suspend(struct device *dev, pm_message_t state) |
| 968 | { | 968 | { |
| 969 | struct locomo_dev *ldev = LOCOMO_DEV(dev); | 969 | struct locomo_dev *ldev = LOCOMO_DEV(dev); |
| 970 | struct locomo_driver *drv = LOCOMO_DRV(dev->driver); | 970 | struct locomo_driver *drv = LOCOMO_DRV(dev->driver); |
| 971 | int ret = 0; | 971 | int ret = 0; |
| 972 | 972 | ||
| 973 | if (drv && drv->suspend) | 973 | if (drv && drv->suspend) |
| 974 | ret = drv->suspend(ldev, state); | 974 | ret = drv->suspend(ldev, state); |
| 975 | return ret; | 975 | return ret; |
| 976 | } | 976 | } |
| 977 | 977 | ||
| 978 | static int locomo_bus_resume(struct device *dev) | 978 | static int locomo_bus_resume(struct device *dev) |
| 979 | { | 979 | { |
| 980 | struct locomo_dev *ldev = LOCOMO_DEV(dev); | 980 | struct locomo_dev *ldev = LOCOMO_DEV(dev); |
| 981 | struct locomo_driver *drv = LOCOMO_DRV(dev->driver); | 981 | struct locomo_driver *drv = LOCOMO_DRV(dev->driver); |
| 982 | int ret = 0; | 982 | int ret = 0; |
| 983 | 983 | ||
| 984 | if (drv && drv->resume) | 984 | if (drv && drv->resume) |
| 985 | ret = drv->resume(ldev); | 985 | ret = drv->resume(ldev); |
| 986 | return ret; | 986 | return ret; |
| 987 | } | 987 | } |
| 988 | 988 | ||
| 989 | static int locomo_bus_probe(struct device *dev) | 989 | static int locomo_bus_probe(struct device *dev) |
| 990 | { | 990 | { |
| 991 | struct locomo_dev *ldev = LOCOMO_DEV(dev); | 991 | struct locomo_dev *ldev = LOCOMO_DEV(dev); |
| 992 | struct locomo_driver *drv = LOCOMO_DRV(dev->driver); | 992 | struct locomo_driver *drv = LOCOMO_DRV(dev->driver); |
| 993 | int ret = -ENODEV; | 993 | int ret = -ENODEV; |
| 994 | 994 | ||
| 995 | if (drv->probe) | 995 | if (drv->probe) |
| 996 | ret = drv->probe(ldev); | 996 | ret = drv->probe(ldev); |
| 997 | return ret; | 997 | return ret; |
| 998 | } | 998 | } |
| 999 | 999 | ||
| 1000 | static int locomo_bus_remove(struct device *dev) | 1000 | static int locomo_bus_remove(struct device *dev) |
| 1001 | { | 1001 | { |
| 1002 | struct locomo_dev *ldev = LOCOMO_DEV(dev); | 1002 | struct locomo_dev *ldev = LOCOMO_DEV(dev); |
| 1003 | struct locomo_driver *drv = LOCOMO_DRV(dev->driver); | 1003 | struct locomo_driver *drv = LOCOMO_DRV(dev->driver); |
| 1004 | int ret = 0; | 1004 | int ret = 0; |
| 1005 | 1005 | ||
| 1006 | if (drv->remove) | 1006 | if (drv->remove) |
| 1007 | ret = drv->remove(ldev); | 1007 | ret = drv->remove(ldev); |
| 1008 | return ret; | 1008 | return ret; |
| 1009 | } | 1009 | } |
| 1010 | 1010 | ||
| 1011 | struct bus_type locomo_bus_type = { | 1011 | struct bus_type locomo_bus_type = { |
| 1012 | .name = "locomo-bus", | 1012 | .name = "locomo-bus", |
| 1013 | .match = locomo_match, | 1013 | .match = locomo_match, |
| 1014 | .suspend = locomo_bus_suspend, | 1014 | .suspend = locomo_bus_suspend, |
| 1015 | .resume = locomo_bus_resume, | 1015 | .resume = locomo_bus_resume, |
| 1016 | }; | 1016 | }; |
| 1017 | 1017 | ||
| 1018 | int locomo_driver_register(struct locomo_driver *driver) | 1018 | int locomo_driver_register(struct locomo_driver *driver) |
| 1019 | { | 1019 | { |
| 1020 | driver->drv.probe = locomo_bus_probe; | 1020 | driver->drv.probe = locomo_bus_probe; |
| 1021 | driver->drv.remove = locomo_bus_remove; | 1021 | driver->drv.remove = locomo_bus_remove; |
| 1022 | driver->drv.bus = &locomo_bus_type; | 1022 | driver->drv.bus = &locomo_bus_type; |
| 1023 | return driver_register(&driver->drv); | 1023 | return driver_register(&driver->drv); |
| 1024 | } | 1024 | } |
| 1025 | 1025 | ||
| 1026 | void locomo_driver_unregister(struct locomo_driver *driver) | 1026 | void locomo_driver_unregister(struct locomo_driver *driver) |
| 1027 | { | 1027 | { |
| 1028 | driver_unregister(&driver->drv); | 1028 | driver_unregister(&driver->drv); |
| 1029 | } | 1029 | } |
| 1030 | 1030 | ||
| 1031 | static int __init locomo_init(void) | 1031 | static int __init locomo_init(void) |
| 1032 | { | 1032 | { |
| 1033 | int ret = bus_register(&locomo_bus_type); | 1033 | int ret = bus_register(&locomo_bus_type); |
| 1034 | if (ret == 0) | 1034 | if (ret == 0) |
| 1035 | driver_register(&locomo_device_driver); | 1035 | driver_register(&locomo_device_driver); |
| 1036 | return ret; | 1036 | return ret; |
| 1037 | } | 1037 | } |
| 1038 | 1038 | ||
| 1039 | static void __exit locomo_exit(void) | 1039 | static void __exit locomo_exit(void) |
| 1040 | { | 1040 | { |
| 1041 | driver_unregister(&locomo_device_driver); | 1041 | driver_unregister(&locomo_device_driver); |
| 1042 | bus_unregister(&locomo_bus_type); | 1042 | bus_unregister(&locomo_bus_type); |
| 1043 | } | 1043 | } |
| 1044 | 1044 | ||
| 1045 | module_init(locomo_init); | 1045 | module_init(locomo_init); |
| 1046 | module_exit(locomo_exit); | 1046 | module_exit(locomo_exit); |
| 1047 | 1047 | ||
| 1048 | MODULE_DESCRIPTION("Sharp LoCoMo core driver"); | 1048 | MODULE_DESCRIPTION("Sharp LoCoMo core driver"); |
| 1049 | MODULE_LICENSE("GPL"); | 1049 | MODULE_LICENSE("GPL"); |
| 1050 | MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>"); | 1050 | MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>"); |
| 1051 | 1051 | ||
| 1052 | EXPORT_SYMBOL(locomo_driver_register); | 1052 | EXPORT_SYMBOL(locomo_driver_register); |
| 1053 | EXPORT_SYMBOL(locomo_driver_unregister); | 1053 | EXPORT_SYMBOL(locomo_driver_unregister); |
| 1054 | EXPORT_SYMBOL(locomo_gpio_set_dir); | 1054 | EXPORT_SYMBOL(locomo_gpio_set_dir); |
| 1055 | EXPORT_SYMBOL(locomo_gpio_read_level); | 1055 | EXPORT_SYMBOL(locomo_gpio_read_level); |
| 1056 | EXPORT_SYMBOL(locomo_gpio_read_output); | 1056 | EXPORT_SYMBOL(locomo_gpio_read_output); |
| 1057 | EXPORT_SYMBOL(locomo_gpio_write); | 1057 | EXPORT_SYMBOL(locomo_gpio_write); |
arch/arm/common/sa1111.c
| 1 | /* | 1 | /* |
| 2 | * linux/arch/arm/mach-sa1100/sa1111.c | 2 | * linux/arch/arm/mach-sa1100/sa1111.c |
| 3 | * | 3 | * |
| 4 | * SA1111 support | 4 | * SA1111 support |
| 5 | * | 5 | * |
| 6 | * Original code by John Dorsey | 6 | * Original code by John Dorsey |
| 7 | * | 7 | * |
| 8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
| 9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
| 10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
| 11 | * | 11 | * |
| 12 | * This file contains all generic SA1111 support. | 12 | * This file contains all generic SA1111 support. |
| 13 | * | 13 | * |
| 14 | * All initialization functions provided here are intended to be called | 14 | * All initialization functions provided here are intended to be called |
| 15 | * from machine specific code with proper arguments when required. | 15 | * from machine specific code with proper arguments when required. |
| 16 | */ | 16 | */ |
| 17 | #include <linux/config.h> | 17 | #include <linux/config.h> |
| 18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
| 19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
| 20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
| 21 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
| 22 | #include <linux/ptrace.h> | 22 | #include <linux/ptrace.h> |
| 23 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
| 24 | #include <linux/ioport.h> | 24 | #include <linux/ioport.h> |
| 25 | #include <linux/device.h> | 25 | #include <linux/device.h> |
| 26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
| 27 | #include <linux/spinlock.h> | 27 | #include <linux/spinlock.h> |
| 28 | #include <linux/dma-mapping.h> | 28 | #include <linux/dma-mapping.h> |
| 29 | 29 | ||
| 30 | #include <asm/hardware.h> | 30 | #include <asm/hardware.h> |
| 31 | #include <asm/mach-types.h> | 31 | #include <asm/mach-types.h> |
| 32 | #include <asm/io.h> | 32 | #include <asm/io.h> |
| 33 | #include <asm/irq.h> | 33 | #include <asm/irq.h> |
| 34 | #include <asm/mach/irq.h> | 34 | #include <asm/mach/irq.h> |
| 35 | 35 | ||
| 36 | #include <asm/hardware/sa1111.h> | 36 | #include <asm/hardware/sa1111.h> |
| 37 | 37 | ||
| 38 | #ifdef CONFIG_ARCH_PXA | 38 | #ifdef CONFIG_ARCH_PXA |
| 39 | #include <asm/arch/pxa-regs.h> | 39 | #include <asm/arch/pxa-regs.h> |
| 40 | #endif | 40 | #endif |
| 41 | 41 | ||
| 42 | extern void __init sa1110_mb_enable(void); | 42 | extern void __init sa1110_mb_enable(void); |
| 43 | 43 | ||
| 44 | /* | 44 | /* |
| 45 | * We keep the following data for the overall SA1111. Note that the | 45 | * We keep the following data for the overall SA1111. Note that the |
| 46 | * struct device and struct resource are "fake"; they should be supplied | 46 | * struct device and struct resource are "fake"; they should be supplied |
| 47 | * by the bus above us. However, in the interests of getting all SA1111 | 47 | * by the bus above us. However, in the interests of getting all SA1111 |
| 48 | * drivers converted over to the device model, we provide this as an | 48 | * drivers converted over to the device model, we provide this as an |
| 49 | * anchor point for all the other drivers. | 49 | * anchor point for all the other drivers. |
| 50 | */ | 50 | */ |
| 51 | struct sa1111 { | 51 | struct sa1111 { |
| 52 | struct device *dev; | 52 | struct device *dev; |
| 53 | unsigned long phys; | 53 | unsigned long phys; |
| 54 | int irq; | 54 | int irq; |
| 55 | spinlock_t lock; | 55 | spinlock_t lock; |
| 56 | void __iomem *base; | 56 | void __iomem *base; |
| 57 | }; | 57 | }; |
| 58 | 58 | ||
| 59 | /* | 59 | /* |
| 60 | * We _really_ need to eliminate this. Its only users | 60 | * We _really_ need to eliminate this. Its only users |
| 61 | * are the PWM and DMA checking code. | 61 | * are the PWM and DMA checking code. |
| 62 | */ | 62 | */ |
| 63 | static struct sa1111 *g_sa1111; | 63 | static struct sa1111 *g_sa1111; |
| 64 | 64 | ||
| 65 | struct sa1111_dev_info { | 65 | struct sa1111_dev_info { |
| 66 | unsigned long offset; | 66 | unsigned long offset; |
| 67 | unsigned long skpcr_mask; | 67 | unsigned long skpcr_mask; |
| 68 | unsigned int devid; | 68 | unsigned int devid; |
| 69 | unsigned int irq[6]; | 69 | unsigned int irq[6]; |
| 70 | }; | 70 | }; |
| 71 | 71 | ||
| 72 | static struct sa1111_dev_info sa1111_devices[] = { | 72 | static struct sa1111_dev_info sa1111_devices[] = { |
| 73 | { | 73 | { |
| 74 | .offset = SA1111_USB, | 74 | .offset = SA1111_USB, |
| 75 | .skpcr_mask = SKPCR_UCLKEN, | 75 | .skpcr_mask = SKPCR_UCLKEN, |
| 76 | .devid = SA1111_DEVID_USB, | 76 | .devid = SA1111_DEVID_USB, |
| 77 | .irq = { | 77 | .irq = { |
| 78 | IRQ_USBPWR, | 78 | IRQ_USBPWR, |
| 79 | IRQ_HCIM, | 79 | IRQ_HCIM, |
| 80 | IRQ_HCIBUFFACC, | 80 | IRQ_HCIBUFFACC, |
| 81 | IRQ_HCIRMTWKP, | 81 | IRQ_HCIRMTWKP, |
| 82 | IRQ_NHCIMFCIR, | 82 | IRQ_NHCIMFCIR, |
| 83 | IRQ_USB_PORT_RESUME | 83 | IRQ_USB_PORT_RESUME |
| 84 | }, | 84 | }, |
| 85 | }, | 85 | }, |
| 86 | { | 86 | { |
| 87 | .offset = 0x0600, | 87 | .offset = 0x0600, |
| 88 | .skpcr_mask = SKPCR_I2SCLKEN | SKPCR_L3CLKEN, | 88 | .skpcr_mask = SKPCR_I2SCLKEN | SKPCR_L3CLKEN, |
| 89 | .devid = SA1111_DEVID_SAC, | 89 | .devid = SA1111_DEVID_SAC, |
| 90 | .irq = { | 90 | .irq = { |
| 91 | AUDXMTDMADONEA, | 91 | AUDXMTDMADONEA, |
| 92 | AUDXMTDMADONEB, | 92 | AUDXMTDMADONEB, |
| 93 | AUDRCVDMADONEA, | 93 | AUDRCVDMADONEA, |
| 94 | AUDRCVDMADONEB | 94 | AUDRCVDMADONEB |
| 95 | }, | 95 | }, |
| 96 | }, | 96 | }, |
| 97 | { | 97 | { |
| 98 | .offset = 0x0800, | 98 | .offset = 0x0800, |
| 99 | .skpcr_mask = SKPCR_SCLKEN, | 99 | .skpcr_mask = SKPCR_SCLKEN, |
| 100 | .devid = SA1111_DEVID_SSP, | 100 | .devid = SA1111_DEVID_SSP, |
| 101 | }, | 101 | }, |
| 102 | { | 102 | { |
| 103 | .offset = SA1111_KBD, | 103 | .offset = SA1111_KBD, |
| 104 | .skpcr_mask = SKPCR_PTCLKEN, | 104 | .skpcr_mask = SKPCR_PTCLKEN, |
| 105 | .devid = SA1111_DEVID_PS2, | 105 | .devid = SA1111_DEVID_PS2, |
| 106 | .irq = { | 106 | .irq = { |
| 107 | IRQ_TPRXINT, | 107 | IRQ_TPRXINT, |
| 108 | IRQ_TPTXINT | 108 | IRQ_TPTXINT |
| 109 | }, | 109 | }, |
| 110 | }, | 110 | }, |
| 111 | { | 111 | { |
| 112 | .offset = SA1111_MSE, | 112 | .offset = SA1111_MSE, |
| 113 | .skpcr_mask = SKPCR_PMCLKEN, | 113 | .skpcr_mask = SKPCR_PMCLKEN, |
| 114 | .devid = SA1111_DEVID_PS2, | 114 | .devid = SA1111_DEVID_PS2, |
| 115 | .irq = { | 115 | .irq = { |
| 116 | IRQ_MSRXINT, | 116 | IRQ_MSRXINT, |
| 117 | IRQ_MSTXINT | 117 | IRQ_MSTXINT |
| 118 | }, | 118 | }, |
| 119 | }, | 119 | }, |
| 120 | { | 120 | { |
| 121 | .offset = 0x1800, | 121 | .offset = 0x1800, |
| 122 | .skpcr_mask = 0, | 122 | .skpcr_mask = 0, |
| 123 | .devid = SA1111_DEVID_PCMCIA, | 123 | .devid = SA1111_DEVID_PCMCIA, |
| 124 | .irq = { | 124 | .irq = { |
| 125 | IRQ_S0_READY_NINT, | 125 | IRQ_S0_READY_NINT, |
| 126 | IRQ_S0_CD_VALID, | 126 | IRQ_S0_CD_VALID, |
| 127 | IRQ_S0_BVD1_STSCHG, | 127 | IRQ_S0_BVD1_STSCHG, |
| 128 | IRQ_S1_READY_NINT, | 128 | IRQ_S1_READY_NINT, |
| 129 | IRQ_S1_CD_VALID, | 129 | IRQ_S1_CD_VALID, |
| 130 | IRQ_S1_BVD1_STSCHG, | 130 | IRQ_S1_BVD1_STSCHG, |
| 131 | }, | 131 | }, |
| 132 | }, | 132 | }, |
| 133 | }; | 133 | }; |
| 134 | 134 | ||
| 135 | /* | 135 | /* |
| 136 | * SA1111 interrupt support. Since clearing an IRQ while there are | 136 | * SA1111 interrupt support. Since clearing an IRQ while there are |
| 137 | * active IRQs causes the interrupt output to pulse, the upper levels | 137 | * active IRQs causes the interrupt output to pulse, the upper levels |
| 138 | * will call us again if there are more interrupts to process. | 138 | * will call us again if there are more interrupts to process. |
| 139 | */ | 139 | */ |
| 140 | static void | 140 | static void |
| 141 | sa1111_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) | 141 | sa1111_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) |
| 142 | { | 142 | { |
| 143 | unsigned int stat0, stat1, i; | 143 | unsigned int stat0, stat1, i; |
| 144 | void __iomem *base = desc->data; | 144 | void __iomem *base = desc->data; |
| 145 | 145 | ||
| 146 | stat0 = sa1111_readl(base + SA1111_INTSTATCLR0); | 146 | stat0 = sa1111_readl(base + SA1111_INTSTATCLR0); |
| 147 | stat1 = sa1111_readl(base + SA1111_INTSTATCLR1); | 147 | stat1 = sa1111_readl(base + SA1111_INTSTATCLR1); |
| 148 | 148 | ||
| 149 | sa1111_writel(stat0, base + SA1111_INTSTATCLR0); | 149 | sa1111_writel(stat0, base + SA1111_INTSTATCLR0); |
| 150 | 150 | ||
| 151 | desc->chip->ack(irq); | 151 | desc->chip->ack(irq); |
| 152 | 152 | ||
| 153 | sa1111_writel(stat1, base + SA1111_INTSTATCLR1); | 153 | sa1111_writel(stat1, base + SA1111_INTSTATCLR1); |
| 154 | 154 | ||
| 155 | if (stat0 == 0 && stat1 == 0) { | 155 | if (stat0 == 0 && stat1 == 0) { |
| 156 | do_bad_IRQ(irq, desc, regs); | 156 | do_bad_IRQ(irq, desc, regs); |
| 157 | return; | 157 | return; |
| 158 | } | 158 | } |
| 159 | 159 | ||
| 160 | for (i = IRQ_SA1111_START; stat0; i++, stat0 >>= 1) | 160 | for (i = IRQ_SA1111_START; stat0; i++, stat0 >>= 1) |
| 161 | if (stat0 & 1) | 161 | if (stat0 & 1) |
| 162 | do_edge_IRQ(i, irq_desc + i, regs); | 162 | do_edge_IRQ(i, irq_desc + i, regs); |
| 163 | 163 | ||
| 164 | for (i = IRQ_SA1111_START + 32; stat1; i++, stat1 >>= 1) | 164 | for (i = IRQ_SA1111_START + 32; stat1; i++, stat1 >>= 1) |
| 165 | if (stat1 & 1) | 165 | if (stat1 & 1) |
| 166 | do_edge_IRQ(i, irq_desc + i, regs); | 166 | do_edge_IRQ(i, irq_desc + i, regs); |
| 167 | 167 | ||
| 168 | /* For level-based interrupts */ | 168 | /* For level-based interrupts */ |
| 169 | desc->chip->unmask(irq); | 169 | desc->chip->unmask(irq); |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | #define SA1111_IRQMASK_LO(x) (1 << (x - IRQ_SA1111_START)) | 172 | #define SA1111_IRQMASK_LO(x) (1 << (x - IRQ_SA1111_START)) |
| 173 | #define SA1111_IRQMASK_HI(x) (1 << (x - IRQ_SA1111_START - 32)) | 173 | #define SA1111_IRQMASK_HI(x) (1 << (x - IRQ_SA1111_START - 32)) |
| 174 | 174 | ||
| 175 | static void sa1111_ack_irq(unsigned int irq) | 175 | static void sa1111_ack_irq(unsigned int irq) |
| 176 | { | 176 | { |
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | static void sa1111_mask_lowirq(unsigned int irq) | 179 | static void sa1111_mask_lowirq(unsigned int irq) |
| 180 | { | 180 | { |
| 181 | void __iomem *mapbase = get_irq_chipdata(irq); | 181 | void __iomem *mapbase = get_irq_chipdata(irq); |
| 182 | unsigned long ie0; | 182 | unsigned long ie0; |
| 183 | 183 | ||
| 184 | ie0 = sa1111_readl(mapbase + SA1111_INTEN0); | 184 | ie0 = sa1111_readl(mapbase + SA1111_INTEN0); |
| 185 | ie0 &= ~SA1111_IRQMASK_LO(irq); | 185 | ie0 &= ~SA1111_IRQMASK_LO(irq); |
| 186 | writel(ie0, mapbase + SA1111_INTEN0); | 186 | writel(ie0, mapbase + SA1111_INTEN0); |
| 187 | } | 187 | } |
| 188 | 188 | ||
| 189 | static void sa1111_unmask_lowirq(unsigned int irq) | 189 | static void sa1111_unmask_lowirq(unsigned int irq) |
| 190 | { | 190 | { |
| 191 | void __iomem *mapbase = get_irq_chipdata(irq); | 191 | void __iomem *mapbase = get_irq_chipdata(irq); |
| 192 | unsigned long ie0; | 192 | unsigned long ie0; |
| 193 | 193 | ||
| 194 | ie0 = sa1111_readl(mapbase + SA1111_INTEN0); | 194 | ie0 = sa1111_readl(mapbase + SA1111_INTEN0); |
| 195 | ie0 |= SA1111_IRQMASK_LO(irq); | 195 | ie0 |= SA1111_IRQMASK_LO(irq); |
| 196 | sa1111_writel(ie0, mapbase + SA1111_INTEN0); | 196 | sa1111_writel(ie0, mapbase + SA1111_INTEN0); |
| 197 | } | 197 | } |
| 198 | 198 | ||
| 199 | /* | 199 | /* |
| 200 | * Attempt to re-trigger the interrupt. The SA1111 contains a register | 200 | * Attempt to re-trigger the interrupt. The SA1111 contains a register |
| 201 | * (INTSET) which claims to do this. However, in practice no amount of | 201 | * (INTSET) which claims to do this. However, in practice no amount of |
| 202 | * manipulation of INTEN and INTSET guarantees that the interrupt will | 202 | * manipulation of INTEN and INTSET guarantees that the interrupt will |
| 203 | * be triggered. In fact, its very difficult, if not impossible to get | 203 | * be triggered. In fact, its very difficult, if not impossible to get |
| 204 | * INTSET to re-trigger the interrupt. | 204 | * INTSET to re-trigger the interrupt. |
| 205 | */ | 205 | */ |
| 206 | static int sa1111_retrigger_lowirq(unsigned int irq) | 206 | static int sa1111_retrigger_lowirq(unsigned int irq) |
| 207 | { | 207 | { |
| 208 | unsigned int mask = SA1111_IRQMASK_LO(irq); | 208 | unsigned int mask = SA1111_IRQMASK_LO(irq); |
| 209 | void __iomem *mapbase = get_irq_chipdata(irq); | 209 | void __iomem *mapbase = get_irq_chipdata(irq); |
| 210 | unsigned long ip0; | 210 | unsigned long ip0; |
| 211 | int i; | 211 | int i; |
| 212 | 212 | ||
| 213 | ip0 = sa1111_readl(mapbase + SA1111_INTPOL0); | 213 | ip0 = sa1111_readl(mapbase + SA1111_INTPOL0); |
| 214 | for (i = 0; i < 8; i++) { | 214 | for (i = 0; i < 8; i++) { |
| 215 | sa1111_writel(ip0 ^ mask, mapbase + SA1111_INTPOL0); | 215 | sa1111_writel(ip0 ^ mask, mapbase + SA1111_INTPOL0); |
| 216 | sa1111_writel(ip0, mapbase + SA1111_INTPOL0); | 216 | sa1111_writel(ip0, mapbase + SA1111_INTPOL0); |
| 217 | if (sa1111_readl(mapbase + SA1111_INTSTATCLR1) & mask) | 217 | if (sa1111_readl(mapbase + SA1111_INTSTATCLR1) & mask) |
| 218 | break; | 218 | break; |
| 219 | } | 219 | } |
| 220 | 220 | ||
| 221 | if (i == 8) | 221 | if (i == 8) |
| 222 | printk(KERN_ERR "Danger Will Robinson: failed to " | 222 | printk(KERN_ERR "Danger Will Robinson: failed to " |
| 223 | "re-trigger IRQ%d\n", irq); | 223 | "re-trigger IRQ%d\n", irq); |
| 224 | return i == 8 ? -1 : 0; | 224 | return i == 8 ? -1 : 0; |
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | static int sa1111_type_lowirq(unsigned int irq, unsigned int flags) | 227 | static int sa1111_type_lowirq(unsigned int irq, unsigned int flags) |
| 228 | { | 228 | { |
| 229 | unsigned int mask = SA1111_IRQMASK_LO(irq); | 229 | unsigned int mask = SA1111_IRQMASK_LO(irq); |
| 230 | void __iomem *mapbase = get_irq_chipdata(irq); | 230 | void __iomem *mapbase = get_irq_chipdata(irq); |
| 231 | unsigned long ip0; | 231 | unsigned long ip0; |
| 232 | 232 | ||
| 233 | if (flags == IRQT_PROBE) | 233 | if (flags == IRQT_PROBE) |
| 234 | return 0; | 234 | return 0; |
| 235 | 235 | ||
| 236 | if ((!(flags & __IRQT_RISEDGE) ^ !(flags & __IRQT_FALEDGE)) == 0) | 236 | if ((!(flags & __IRQT_RISEDGE) ^ !(flags & __IRQT_FALEDGE)) == 0) |
| 237 | return -EINVAL; | 237 | return -EINVAL; |
| 238 | 238 | ||
| 239 | ip0 = sa1111_readl(mapbase + SA1111_INTPOL0); | 239 | ip0 = sa1111_readl(mapbase + SA1111_INTPOL0); |
| 240 | if (flags & __IRQT_RISEDGE) | 240 | if (flags & __IRQT_RISEDGE) |
| 241 | ip0 &= ~mask; | 241 | ip0 &= ~mask; |
| 242 | else | 242 | else |
| 243 | ip0 |= mask; | 243 | ip0 |= mask; |
| 244 | sa1111_writel(ip0, mapbase + SA1111_INTPOL0); | 244 | sa1111_writel(ip0, mapbase + SA1111_INTPOL0); |
| 245 | sa1111_writel(ip0, mapbase + SA1111_WAKEPOL0); | 245 | sa1111_writel(ip0, mapbase + SA1111_WAKEPOL0); |
| 246 | 246 | ||
| 247 | return 0; | 247 | return 0; |
| 248 | } | 248 | } |
| 249 | 249 | ||
| 250 | static int sa1111_wake_lowirq(unsigned int irq, unsigned int on) | 250 | static int sa1111_wake_lowirq(unsigned int irq, unsigned int on) |
| 251 | { | 251 | { |
| 252 | unsigned int mask = SA1111_IRQMASK_LO(irq); | 252 | unsigned int mask = SA1111_IRQMASK_LO(irq); |
| 253 | void __iomem *mapbase = get_irq_chipdata(irq); | 253 | void __iomem *mapbase = get_irq_chipdata(irq); |
| 254 | unsigned long we0; | 254 | unsigned long we0; |
| 255 | 255 | ||
| 256 | we0 = sa1111_readl(mapbase + SA1111_WAKEEN0); | 256 | we0 = sa1111_readl(mapbase + SA1111_WAKEEN0); |
| 257 | if (on) | 257 | if (on) |
| 258 | we0 |= mask; | 258 | we0 |= mask; |
| 259 | else | 259 | else |
| 260 | we0 &= ~mask; | 260 | we0 &= ~mask; |
| 261 | sa1111_writel(we0, mapbase + SA1111_WAKEEN0); | 261 | sa1111_writel(we0, mapbase + SA1111_WAKEEN0); |
| 262 | 262 | ||
| 263 | return 0; | 263 | return 0; |
| 264 | } | 264 | } |
| 265 | 265 | ||
| 266 | static struct irqchip sa1111_low_chip = { | 266 | static struct irqchip sa1111_low_chip = { |
| 267 | .ack = sa1111_ack_irq, | 267 | .ack = sa1111_ack_irq, |
| 268 | .mask = sa1111_mask_lowirq, | 268 | .mask = sa1111_mask_lowirq, |
| 269 | .unmask = sa1111_unmask_lowirq, | 269 | .unmask = sa1111_unmask_lowirq, |
| 270 | .retrigger = sa1111_retrigger_lowirq, | 270 | .retrigger = sa1111_retrigger_lowirq, |
| 271 | .type = sa1111_type_lowirq, | 271 | .set_type = sa1111_type_lowirq, |
| 272 | .wake = sa1111_wake_lowirq, | 272 | .set_wake = sa1111_wake_lowirq, |
| 273 | }; | 273 | }; |
| 274 | 274 | ||
| 275 | static void sa1111_mask_highirq(unsigned int irq) | 275 | static void sa1111_mask_highirq(unsigned int irq) |
| 276 | { | 276 | { |
| 277 | void __iomem *mapbase = get_irq_chipdata(irq); | 277 | void __iomem *mapbase = get_irq_chipdata(irq); |
| 278 | unsigned long ie1; | 278 | unsigned long ie1; |
| 279 | 279 | ||
| 280 | ie1 = sa1111_readl(mapbase + SA1111_INTEN1); | 280 | ie1 = sa1111_readl(mapbase + SA1111_INTEN1); |
| 281 | ie1 &= ~SA1111_IRQMASK_HI(irq); | 281 | ie1 &= ~SA1111_IRQMASK_HI(irq); |
| 282 | sa1111_writel(ie1, mapbase + SA1111_INTEN1); | 282 | sa1111_writel(ie1, mapbase + SA1111_INTEN1); |
| 283 | } | 283 | } |
| 284 | 284 | ||
| 285 | static void sa1111_unmask_highirq(unsigned int irq) | 285 | static void sa1111_unmask_highirq(unsigned int irq) |
| 286 | { | 286 | { |
| 287 | void __iomem *mapbase = get_irq_chipdata(irq); | 287 | void __iomem *mapbase = get_irq_chipdata(irq); |
| 288 | unsigned long ie1; | 288 | unsigned long ie1; |
| 289 | 289 | ||
| 290 | ie1 = sa1111_readl(mapbase + SA1111_INTEN1); | 290 | ie1 = sa1111_readl(mapbase + SA1111_INTEN1); |
| 291 | ie1 |= SA1111_IRQMASK_HI(irq); | 291 | ie1 |= SA1111_IRQMASK_HI(irq); |
| 292 | sa1111_writel(ie1, mapbase + SA1111_INTEN1); | 292 | sa1111_writel(ie1, mapbase + SA1111_INTEN1); |
| 293 | } | 293 | } |
| 294 | 294 | ||
| 295 | /* | 295 | /* |
| 296 | * Attempt to re-trigger the interrupt. The SA1111 contains a register | 296 | * Attempt to re-trigger the interrupt. The SA1111 contains a register |
| 297 | * (INTSET) which claims to do this. However, in practice no amount of | 297 | * (INTSET) which claims to do this. However, in practice no amount of |
| 298 | * manipulation of INTEN and INTSET guarantees that the interrupt will | 298 | * manipulation of INTEN and INTSET guarantees that the interrupt will |
| 299 | * be triggered. In fact, its very difficult, if not impossible to get | 299 | * be triggered. In fact, its very difficult, if not impossible to get |
| 300 | * INTSET to re-trigger the interrupt. | 300 | * INTSET to re-trigger the interrupt. |
| 301 | */ | 301 | */ |
| 302 | static int sa1111_retrigger_highirq(unsigned int irq) | 302 | static int sa1111_retrigger_highirq(unsigned int irq) |
| 303 | { | 303 | { |
| 304 | unsigned int mask = SA1111_IRQMASK_HI(irq); | 304 | unsigned int mask = SA1111_IRQMASK_HI(irq); |
| 305 | void __iomem *mapbase = get_irq_chipdata(irq); | 305 | void __iomem *mapbase = get_irq_chipdata(irq); |
| 306 | unsigned long ip1; | 306 | unsigned long ip1; |
| 307 | int i; | 307 | int i; |
| 308 | 308 | ||
| 309 | ip1 = sa1111_readl(mapbase + SA1111_INTPOL1); | 309 | ip1 = sa1111_readl(mapbase + SA1111_INTPOL1); |
| 310 | for (i = 0; i < 8; i++) { | 310 | for (i = 0; i < 8; i++) { |
| 311 | sa1111_writel(ip1 ^ mask, mapbase + SA1111_INTPOL1); | 311 | sa1111_writel(ip1 ^ mask, mapbase + SA1111_INTPOL1); |
| 312 | sa1111_writel(ip1, mapbase + SA1111_INTPOL1); | 312 | sa1111_writel(ip1, mapbase + SA1111_INTPOL1); |
| 313 | if (sa1111_readl(mapbase + SA1111_INTSTATCLR1) & mask) | 313 | if (sa1111_readl(mapbase + SA1111_INTSTATCLR1) & mask) |
| 314 | break; | 314 | break; |
| 315 | } | 315 | } |
| 316 | 316 | ||
| 317 | if (i == 8) | 317 | if (i == 8) |
| 318 | printk(KERN_ERR "Danger Will Robinson: failed to " | 318 | printk(KERN_ERR "Danger Will Robinson: failed to " |
| 319 | "re-trigger IRQ%d\n", irq); | 319 | "re-trigger IRQ%d\n", irq); |
| 320 | return i == 8 ? -1 : 0; | 320 | return i == 8 ? -1 : 0; |
| 321 | } | 321 | } |
| 322 | 322 | ||
| 323 | static int sa1111_type_highirq(unsigned int irq, unsigned int flags) | 323 | static int sa1111_type_highirq(unsigned int irq, unsigned int flags) |
| 324 | { | 324 | { |
| 325 | unsigned int mask = SA1111_IRQMASK_HI(irq); | 325 | unsigned int mask = SA1111_IRQMASK_HI(irq); |
| 326 | void __iomem *mapbase = get_irq_chipdata(irq); | 326 | void __iomem *mapbase = get_irq_chipdata(irq); |
| 327 | unsigned long ip1; | 327 | unsigned long ip1; |
| 328 | 328 | ||
| 329 | if (flags == IRQT_PROBE) | 329 | if (flags == IRQT_PROBE) |
| 330 | return 0; | 330 | return 0; |
| 331 | 331 | ||
| 332 | if ((!(flags & __IRQT_RISEDGE) ^ !(flags & __IRQT_FALEDGE)) == 0) | 332 | if ((!(flags & __IRQT_RISEDGE) ^ !(flags & __IRQT_FALEDGE)) == 0) |
| 333 | return -EINVAL; | 333 | return -EINVAL; |
| 334 | 334 | ||
| 335 | ip1 = sa1111_readl(mapbase + SA1111_INTPOL1); | 335 | ip1 = sa1111_readl(mapbase + SA1111_INTPOL1); |
| 336 | if (flags & __IRQT_RISEDGE) | 336 | if (flags & __IRQT_RISEDGE) |
| 337 | ip1 &= ~mask; | 337 | ip1 &= ~mask; |
| 338 | else | 338 | else |
| 339 | ip1 |= mask; | 339 | ip1 |= mask; |
| 340 | sa1111_writel(ip1, mapbase + SA1111_INTPOL1); | 340 | sa1111_writel(ip1, mapbase + SA1111_INTPOL1); |
| 341 | sa1111_writel(ip1, mapbase + SA1111_WAKEPOL1); | 341 | sa1111_writel(ip1, mapbase + SA1111_WAKEPOL1); |
| 342 | 342 | ||
| 343 | return 0; | 343 | return 0; |
| 344 | } | 344 | } |
| 345 | 345 | ||
| 346 | static int sa1111_wake_highirq(unsigned int irq, unsigned int on) | 346 | static int sa1111_wake_highirq(unsigned int irq, unsigned int on) |
| 347 | { | 347 | { |
| 348 | unsigned int mask = SA1111_IRQMASK_HI(irq); | 348 | unsigned int mask = SA1111_IRQMASK_HI(irq); |
| 349 | void __iomem *mapbase = get_irq_chipdata(irq); | 349 | void __iomem *mapbase = get_irq_chipdata(irq); |
| 350 | unsigned long we1; | 350 | unsigned long we1; |
| 351 | 351 | ||
| 352 | we1 = sa1111_readl(mapbase + SA1111_WAKEEN1); | 352 | we1 = sa1111_readl(mapbase + SA1111_WAKEEN1); |
| 353 | if (on) | 353 | if (on) |
| 354 | we1 |= mask; | 354 | we1 |= mask; |
| 355 | else | 355 | else |
| 356 | we1 &= ~mask; | 356 | we1 &= ~mask; |
| 357 | sa1111_writel(we1, mapbase + SA1111_WAKEEN1); | 357 | sa1111_writel(we1, mapbase + SA1111_WAKEEN1); |
| 358 | 358 | ||
| 359 | return 0; | 359 | return 0; |
| 360 | } | 360 | } |
| 361 | 361 | ||
| 362 | static struct irqchip sa1111_high_chip = { | 362 | static struct irqchip sa1111_high_chip = { |
| 363 | .ack = sa1111_ack_irq, | 363 | .ack = sa1111_ack_irq, |
| 364 | .mask = sa1111_mask_highirq, | 364 | .mask = sa1111_mask_highirq, |
| 365 | .unmask = sa1111_unmask_highirq, | 365 | .unmask = sa1111_unmask_highirq, |
| 366 | .retrigger = sa1111_retrigger_highirq, | 366 | .retrigger = sa1111_retrigger_highirq, |
| 367 | .type = sa1111_type_highirq, | 367 | .set_type = sa1111_type_highirq, |
| 368 | .wake = sa1111_wake_highirq, | 368 | .set_wake = sa1111_wake_highirq, |
| 369 | }; | 369 | }; |
| 370 | 370 | ||
| 371 | static void sa1111_setup_irq(struct sa1111 *sachip) | 371 | static void sa1111_setup_irq(struct sa1111 *sachip) |
| 372 | { | 372 | { |
| 373 | void __iomem *irqbase = sachip->base + SA1111_INTC; | 373 | void __iomem *irqbase = sachip->base + SA1111_INTC; |
| 374 | unsigned int irq; | 374 | unsigned int irq; |
| 375 | 375 | ||
| 376 | /* | 376 | /* |
| 377 | * We're guaranteed that this region hasn't been taken. | 377 | * We're guaranteed that this region hasn't been taken. |
| 378 | */ | 378 | */ |
| 379 | request_mem_region(sachip->phys + SA1111_INTC, 512, "irq"); | 379 | request_mem_region(sachip->phys + SA1111_INTC, 512, "irq"); |
| 380 | 380 | ||
| 381 | /* disable all IRQs */ | 381 | /* disable all IRQs */ |
| 382 | sa1111_writel(0, irqbase + SA1111_INTEN0); | 382 | sa1111_writel(0, irqbase + SA1111_INTEN0); |
| 383 | sa1111_writel(0, irqbase + SA1111_INTEN1); | 383 | sa1111_writel(0, irqbase + SA1111_INTEN1); |
| 384 | sa1111_writel(0, irqbase + SA1111_WAKEEN0); | 384 | sa1111_writel(0, irqbase + SA1111_WAKEEN0); |
| 385 | sa1111_writel(0, irqbase + SA1111_WAKEEN1); | 385 | sa1111_writel(0, irqbase + SA1111_WAKEEN1); |
| 386 | 386 | ||
| 387 | /* | 387 | /* |
| 388 | * detect on rising edge. Note: Feb 2001 Errata for SA1111 | 388 | * detect on rising edge. Note: Feb 2001 Errata for SA1111 |
| 389 | * specifies that S0ReadyInt and S1ReadyInt should be '1'. | 389 | * specifies that S0ReadyInt and S1ReadyInt should be '1'. |
| 390 | */ | 390 | */ |
| 391 | sa1111_writel(0, irqbase + SA1111_INTPOL0); | 391 | sa1111_writel(0, irqbase + SA1111_INTPOL0); |
| 392 | sa1111_writel(SA1111_IRQMASK_HI(IRQ_S0_READY_NINT) | | 392 | sa1111_writel(SA1111_IRQMASK_HI(IRQ_S0_READY_NINT) | |
| 393 | SA1111_IRQMASK_HI(IRQ_S1_READY_NINT), | 393 | SA1111_IRQMASK_HI(IRQ_S1_READY_NINT), |
| 394 | irqbase + SA1111_INTPOL1); | 394 | irqbase + SA1111_INTPOL1); |
| 395 | 395 | ||
| 396 | /* clear all IRQs */ | 396 | /* clear all IRQs */ |
| 397 | sa1111_writel(~0, irqbase + SA1111_INTSTATCLR0); | 397 | sa1111_writel(~0, irqbase + SA1111_INTSTATCLR0); |
| 398 | sa1111_writel(~0, irqbase + SA1111_INTSTATCLR1); | 398 | sa1111_writel(~0, irqbase + SA1111_INTSTATCLR1); |
| 399 | 399 | ||
| 400 | for (irq = IRQ_GPAIN0; irq <= SSPROR; irq++) { | 400 | for (irq = IRQ_GPAIN0; irq <= SSPROR; irq++) { |
| 401 | set_irq_chip(irq, &sa1111_low_chip); | 401 | set_irq_chip(irq, &sa1111_low_chip); |
| 402 | set_irq_chipdata(irq, irqbase); | 402 | set_irq_chipdata(irq, irqbase); |
| 403 | set_irq_handler(irq, do_edge_IRQ); | 403 | set_irq_handler(irq, do_edge_IRQ); |
| 404 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 404 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
| 405 | } | 405 | } |
| 406 | 406 | ||
| 407 | for (irq = AUDXMTDMADONEA; irq <= IRQ_S1_BVD1_STSCHG; irq++) { | 407 | for (irq = AUDXMTDMADONEA; irq <= IRQ_S1_BVD1_STSCHG; irq++) { |
| 408 | set_irq_chip(irq, &sa1111_high_chip); | 408 | set_irq_chip(irq, &sa1111_high_chip); |
| 409 | set_irq_chipdata(irq, irqbase); | 409 | set_irq_chipdata(irq, irqbase); |
| 410 | set_irq_handler(irq, do_edge_IRQ); | 410 | set_irq_handler(irq, do_edge_IRQ); |
| 411 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 411 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
| 412 | } | 412 | } |
| 413 | 413 | ||
| 414 | /* | 414 | /* |
| 415 | * Register SA1111 interrupt | 415 | * Register SA1111 interrupt |
| 416 | */ | 416 | */ |
| 417 | set_irq_type(sachip->irq, IRQT_RISING); | 417 | set_irq_type(sachip->irq, IRQT_RISING); |
| 418 | set_irq_data(sachip->irq, irqbase); | 418 | set_irq_data(sachip->irq, irqbase); |
| 419 | set_irq_chained_handler(sachip->irq, sa1111_irq_handler); | 419 | set_irq_chained_handler(sachip->irq, sa1111_irq_handler); |
| 420 | } | 420 | } |
| 421 | 421 | ||
| 422 | /* | 422 | /* |
| 423 | * Bring the SA1111 out of reset. This requires a set procedure: | 423 | * Bring the SA1111 out of reset. This requires a set procedure: |
| 424 | * 1. nRESET asserted (by hardware) | 424 | * 1. nRESET asserted (by hardware) |
| 425 | * 2. CLK turned on from SA1110 | 425 | * 2. CLK turned on from SA1110 |
| 426 | * 3. nRESET deasserted | 426 | * 3. nRESET deasserted |
| 427 | * 4. VCO turned on, PLL_BYPASS turned off | 427 | * 4. VCO turned on, PLL_BYPASS turned off |
| 428 | * 5. Wait lock time, then assert RCLKEn | 428 | * 5. Wait lock time, then assert RCLKEn |
| 429 | * 7. PCR set to allow clocking of individual functions | 429 | * 7. PCR set to allow clocking of individual functions |
| 430 | * | 430 | * |
| 431 | * Until we've done this, the only registers we can access are: | 431 | * Until we've done this, the only registers we can access are: |
| 432 | * SBI_SKCR | 432 | * SBI_SKCR |
| 433 | * SBI_SMCR | 433 | * SBI_SMCR |
| 434 | * SBI_SKID | 434 | * SBI_SKID |
| 435 | */ | 435 | */ |
| 436 | static void sa1111_wake(struct sa1111 *sachip) | 436 | static void sa1111_wake(struct sa1111 *sachip) |
| 437 | { | 437 | { |
| 438 | unsigned long flags, r; | 438 | unsigned long flags, r; |
| 439 | 439 | ||
| 440 | spin_lock_irqsave(&sachip->lock, flags); | 440 | spin_lock_irqsave(&sachip->lock, flags); |
| 441 | 441 | ||
| 442 | #ifdef CONFIG_ARCH_SA1100 | 442 | #ifdef CONFIG_ARCH_SA1100 |
| 443 | /* | 443 | /* |
| 444 | * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111: | 444 | * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111: |
| 445 | * (SA-1110 Developer's Manual, section 9.1.2.1) | 445 | * (SA-1110 Developer's Manual, section 9.1.2.1) |
| 446 | */ | 446 | */ |
| 447 | GAFR |= GPIO_32_768kHz; | 447 | GAFR |= GPIO_32_768kHz; |
| 448 | GPDR |= GPIO_32_768kHz; | 448 | GPDR |= GPIO_32_768kHz; |
| 449 | TUCR = TUCR_3_6864MHz; | 449 | TUCR = TUCR_3_6864MHz; |
| 450 | #elif CONFIG_ARCH_PXA | 450 | #elif CONFIG_ARCH_PXA |
| 451 | pxa_gpio_mode(GPIO11_3_6MHz_MD); | 451 | pxa_gpio_mode(GPIO11_3_6MHz_MD); |
| 452 | #else | 452 | #else |
| 453 | #error missing clock setup | 453 | #error missing clock setup |
| 454 | #endif | 454 | #endif |
| 455 | 455 | ||
| 456 | /* | 456 | /* |
| 457 | * Turn VCO on, and disable PLL Bypass. | 457 | * Turn VCO on, and disable PLL Bypass. |
| 458 | */ | 458 | */ |
| 459 | r = sa1111_readl(sachip->base + SA1111_SKCR); | 459 | r = sa1111_readl(sachip->base + SA1111_SKCR); |
| 460 | r &= ~SKCR_VCO_OFF; | 460 | r &= ~SKCR_VCO_OFF; |
| 461 | sa1111_writel(r, sachip->base + SA1111_SKCR); | 461 | sa1111_writel(r, sachip->base + SA1111_SKCR); |
| 462 | r |= SKCR_PLL_BYPASS | SKCR_OE_EN; | 462 | r |= SKCR_PLL_BYPASS | SKCR_OE_EN; |
| 463 | sa1111_writel(r, sachip->base + SA1111_SKCR); | 463 | sa1111_writel(r, sachip->base + SA1111_SKCR); |
| 464 | 464 | ||
| 465 | /* | 465 | /* |
| 466 | * Wait lock time. SA1111 manual _doesn't_ | 466 | * Wait lock time. SA1111 manual _doesn't_ |
| 467 | * specify a figure for this! We choose 100us. | 467 | * specify a figure for this! We choose 100us. |
| 468 | */ | 468 | */ |
| 469 | udelay(100); | 469 | udelay(100); |
| 470 | 470 | ||
| 471 | /* | 471 | /* |
| 472 | * Enable RCLK. We also ensure that RDYEN is set. | 472 | * Enable RCLK. We also ensure that RDYEN is set. |
| 473 | */ | 473 | */ |
| 474 | r |= SKCR_RCLKEN | SKCR_RDYEN; | 474 | r |= SKCR_RCLKEN | SKCR_RDYEN; |
| 475 | sa1111_writel(r, sachip->base + SA1111_SKCR); | 475 | sa1111_writel(r, sachip->base + SA1111_SKCR); |
| 476 | 476 | ||
| 477 | /* | 477 | /* |
| 478 | * Wait 14 RCLK cycles for the chip to finish coming out | 478 | * Wait 14 RCLK cycles for the chip to finish coming out |
| 479 | * of reset. (RCLK=24MHz). This is 590ns. | 479 | * of reset. (RCLK=24MHz). This is 590ns. |
| 480 | */ | 480 | */ |
| 481 | udelay(1); | 481 | udelay(1); |
| 482 | 482 | ||
| 483 | /* | 483 | /* |
| 484 | * Ensure all clocks are initially off. | 484 | * Ensure all clocks are initially off. |
| 485 | */ | 485 | */ |
| 486 | sa1111_writel(0, sachip->base + SA1111_SKPCR); | 486 | sa1111_writel(0, sachip->base + SA1111_SKPCR); |
| 487 | 487 | ||
| 488 | spin_unlock_irqrestore(&sachip->lock, flags); | 488 | spin_unlock_irqrestore(&sachip->lock, flags); |
| 489 | } | 489 | } |
| 490 | 490 | ||
| 491 | #ifdef CONFIG_ARCH_SA1100 | 491 | #ifdef CONFIG_ARCH_SA1100 |
| 492 | 492 | ||
| 493 | static u32 sa1111_dma_mask[] = { | 493 | static u32 sa1111_dma_mask[] = { |
| 494 | ~0, | 494 | ~0, |
| 495 | ~(1 << 20), | 495 | ~(1 << 20), |
| 496 | ~(1 << 23), | 496 | ~(1 << 23), |
| 497 | ~(1 << 24), | 497 | ~(1 << 24), |
| 498 | ~(1 << 25), | 498 | ~(1 << 25), |
| 499 | ~(1 << 20), | 499 | ~(1 << 20), |
| 500 | ~(1 << 20), | 500 | ~(1 << 20), |
| 501 | 0, | 501 | 0, |
| 502 | }; | 502 | }; |
| 503 | 503 | ||
| 504 | /* | 504 | /* |
| 505 | * Configure the SA1111 shared memory controller. | 505 | * Configure the SA1111 shared memory controller. |
| 506 | */ | 506 | */ |
| 507 | void | 507 | void |
| 508 | sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac, | 508 | sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac, |
| 509 | unsigned int cas_latency) | 509 | unsigned int cas_latency) |
| 510 | { | 510 | { |
| 511 | unsigned int smcr = SMCR_DTIM | SMCR_MBGE | FInsrt(drac, SMCR_DRAC); | 511 | unsigned int smcr = SMCR_DTIM | SMCR_MBGE | FInsrt(drac, SMCR_DRAC); |
| 512 | 512 | ||
| 513 | if (cas_latency == 3) | 513 | if (cas_latency == 3) |
| 514 | smcr |= SMCR_CLAT; | 514 | smcr |= SMCR_CLAT; |
| 515 | 515 | ||
| 516 | sa1111_writel(smcr, sachip->base + SA1111_SMCR); | 516 | sa1111_writel(smcr, sachip->base + SA1111_SMCR); |
| 517 | 517 | ||
| 518 | /* | 518 | /* |
| 519 | * Now clear the bits in the DMA mask to work around the SA1111 | 519 | * Now clear the bits in the DMA mask to work around the SA1111 |
| 520 | * DMA erratum (Intel StrongARM SA-1111 Microprocessor Companion | 520 | * DMA erratum (Intel StrongARM SA-1111 Microprocessor Companion |
| 521 | * Chip Specification Update, June 2000, Erratum #7). | 521 | * Chip Specification Update, June 2000, Erratum #7). |
| 522 | */ | 522 | */ |
| 523 | if (sachip->dev->dma_mask) | 523 | if (sachip->dev->dma_mask) |
| 524 | *sachip->dev->dma_mask &= sa1111_dma_mask[drac >> 2]; | 524 | *sachip->dev->dma_mask &= sa1111_dma_mask[drac >> 2]; |
| 525 | 525 | ||
| 526 | sachip->dev->coherent_dma_mask &= sa1111_dma_mask[drac >> 2]; | 526 | sachip->dev->coherent_dma_mask &= sa1111_dma_mask[drac >> 2]; |
| 527 | } | 527 | } |
| 528 | 528 | ||
| 529 | #endif | 529 | #endif |
| 530 | 530 | ||
| 531 | static void sa1111_dev_release(struct device *_dev) | 531 | static void sa1111_dev_release(struct device *_dev) |
| 532 | { | 532 | { |
| 533 | struct sa1111_dev *dev = SA1111_DEV(_dev); | 533 | struct sa1111_dev *dev = SA1111_DEV(_dev); |
| 534 | 534 | ||
| 535 | release_resource(&dev->res); | 535 | release_resource(&dev->res); |
| 536 | kfree(dev); | 536 | kfree(dev); |
| 537 | } | 537 | } |
| 538 | 538 | ||
| 539 | static int | 539 | static int |
| 540 | sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, | 540 | sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, |
| 541 | struct sa1111_dev_info *info) | 541 | struct sa1111_dev_info *info) |
| 542 | { | 542 | { |
| 543 | struct sa1111_dev *dev; | 543 | struct sa1111_dev *dev; |
| 544 | int ret; | 544 | int ret; |
| 545 | 545 | ||
| 546 | dev = kmalloc(sizeof(struct sa1111_dev), GFP_KERNEL); | 546 | dev = kmalloc(sizeof(struct sa1111_dev), GFP_KERNEL); |
| 547 | if (!dev) { | 547 | if (!dev) { |
| 548 | ret = -ENOMEM; | 548 | ret = -ENOMEM; |
| 549 | goto out; | 549 | goto out; |
| 550 | } | 550 | } |
| 551 | memset(dev, 0, sizeof(struct sa1111_dev)); | 551 | memset(dev, 0, sizeof(struct sa1111_dev)); |
| 552 | 552 | ||
| 553 | snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), | 553 | snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), |
| 554 | "%4.4lx", info->offset); | 554 | "%4.4lx", info->offset); |
| 555 | 555 | ||
| 556 | dev->devid = info->devid; | 556 | dev->devid = info->devid; |
| 557 | dev->dev.parent = sachip->dev; | 557 | dev->dev.parent = sachip->dev; |
| 558 | dev->dev.bus = &sa1111_bus_type; | 558 | dev->dev.bus = &sa1111_bus_type; |
| 559 | dev->dev.release = sa1111_dev_release; | 559 | dev->dev.release = sa1111_dev_release; |
| 560 | dev->dev.coherent_dma_mask = sachip->dev->coherent_dma_mask; | 560 | dev->dev.coherent_dma_mask = sachip->dev->coherent_dma_mask; |
| 561 | dev->res.start = sachip->phys + info->offset; | 561 | dev->res.start = sachip->phys + info->offset; |
| 562 | dev->res.end = dev->res.start + 511; | 562 | dev->res.end = dev->res.start + 511; |
| 563 | dev->res.name = dev->dev.bus_id; | 563 | dev->res.name = dev->dev.bus_id; |
| 564 | dev->res.flags = IORESOURCE_MEM; | 564 | dev->res.flags = IORESOURCE_MEM; |
| 565 | dev->mapbase = sachip->base + info->offset; | 565 | dev->mapbase = sachip->base + info->offset; |
| 566 | dev->skpcr_mask = info->skpcr_mask; | 566 | dev->skpcr_mask = info->skpcr_mask; |
| 567 | memmove(dev->irq, info->irq, sizeof(dev->irq)); | 567 | memmove(dev->irq, info->irq, sizeof(dev->irq)); |
| 568 | 568 | ||
| 569 | ret = request_resource(parent, &dev->res); | 569 | ret = request_resource(parent, &dev->res); |
| 570 | if (ret) { | 570 | if (ret) { |
| 571 | printk("SA1111: failed to allocate resource for %s\n", | 571 | printk("SA1111: failed to allocate resource for %s\n", |
| 572 | dev->res.name); | 572 | dev->res.name); |
| 573 | kfree(dev); | 573 | kfree(dev); |
| 574 | goto out; | 574 | goto out; |
| 575 | } | 575 | } |
| 576 | 576 | ||
| 577 | 577 | ||
| 578 | ret = device_register(&dev->dev); | 578 | ret = device_register(&dev->dev); |
| 579 | if (ret) { | 579 | if (ret) { |
| 580 | release_resource(&dev->res); | 580 | release_resource(&dev->res); |
| 581 | kfree(dev); | 581 | kfree(dev); |
| 582 | goto out; | 582 | goto out; |
| 583 | } | 583 | } |
| 584 | 584 | ||
| 585 | /* | 585 | /* |
| 586 | * If the parent device has a DMA mask associated with it, | 586 | * If the parent device has a DMA mask associated with it, |
| 587 | * propagate it down to the children. | 587 | * propagate it down to the children. |
| 588 | */ | 588 | */ |
| 589 | if (sachip->dev->dma_mask) { | 589 | if (sachip->dev->dma_mask) { |
| 590 | dev->dma_mask = *sachip->dev->dma_mask; | 590 | dev->dma_mask = *sachip->dev->dma_mask; |
| 591 | dev->dev.dma_mask = &dev->dma_mask; | 591 | dev->dev.dma_mask = &dev->dma_mask; |
| 592 | 592 | ||
| 593 | if (dev->dma_mask != 0xffffffffUL) { | 593 | if (dev->dma_mask != 0xffffffffUL) { |
| 594 | ret = dmabounce_register_dev(&dev->dev, 1024, 4096); | 594 | ret = dmabounce_register_dev(&dev->dev, 1024, 4096); |
| 595 | if (ret) { | 595 | if (ret) { |
| 596 | printk("SA1111: Failed to register %s with dmabounce", dev->dev.bus_id); | 596 | printk("SA1111: Failed to register %s with dmabounce", dev->dev.bus_id); |
| 597 | device_unregister(&dev->dev); | 597 | device_unregister(&dev->dev); |
| 598 | } | 598 | } |
| 599 | } | 599 | } |
| 600 | } | 600 | } |
| 601 | 601 | ||
| 602 | out: | 602 | out: |
| 603 | return ret; | 603 | return ret; |
| 604 | } | 604 | } |
| 605 | 605 | ||
| 606 | /** | 606 | /** |
| 607 | * sa1111_probe - probe for a single SA1111 chip. | 607 | * sa1111_probe - probe for a single SA1111 chip. |
| 608 | * @phys_addr: physical address of device. | 608 | * @phys_addr: physical address of device. |
| 609 | * | 609 | * |
| 610 | * Probe for a SA1111 chip. This must be called | 610 | * Probe for a SA1111 chip. This must be called |
| 611 | * before any other SA1111-specific code. | 611 | * before any other SA1111-specific code. |
| 612 | * | 612 | * |
| 613 | * Returns: | 613 | * Returns: |
| 614 | * %-ENODEV device not found. | 614 | * %-ENODEV device not found. |
| 615 | * %-EBUSY physical address already marked in-use. | 615 | * %-EBUSY physical address already marked in-use. |
| 616 | * %0 successful. | 616 | * %0 successful. |
| 617 | */ | 617 | */ |
| 618 | static int | 618 | static int |
| 619 | __sa1111_probe(struct device *me, struct resource *mem, int irq) | 619 | __sa1111_probe(struct device *me, struct resource *mem, int irq) |
| 620 | { | 620 | { |
| 621 | struct sa1111 *sachip; | 621 | struct sa1111 *sachip; |
| 622 | unsigned long id; | 622 | unsigned long id; |
| 623 | unsigned int has_devs, val; | 623 | unsigned int has_devs, val; |
| 624 | int i, ret = -ENODEV; | 624 | int i, ret = -ENODEV; |
| 625 | 625 | ||
| 626 | sachip = kmalloc(sizeof(struct sa1111), GFP_KERNEL); | 626 | sachip = kmalloc(sizeof(struct sa1111), GFP_KERNEL); |
| 627 | if (!sachip) | 627 | if (!sachip) |
| 628 | return -ENOMEM; | 628 | return -ENOMEM; |
| 629 | 629 | ||
| 630 | memset(sachip, 0, sizeof(struct sa1111)); | 630 | memset(sachip, 0, sizeof(struct sa1111)); |
| 631 | 631 | ||
| 632 | spin_lock_init(&sachip->lock); | 632 | spin_lock_init(&sachip->lock); |
| 633 | 633 | ||
| 634 | sachip->dev = me; | 634 | sachip->dev = me; |
| 635 | dev_set_drvdata(sachip->dev, sachip); | 635 | dev_set_drvdata(sachip->dev, sachip); |
| 636 | 636 | ||
| 637 | sachip->phys = mem->start; | 637 | sachip->phys = mem->start; |
| 638 | sachip->irq = irq; | 638 | sachip->irq = irq; |
| 639 | 639 | ||
| 640 | /* | 640 | /* |
| 641 | * Map the whole region. This also maps the | 641 | * Map the whole region. This also maps the |
| 642 | * registers for our children. | 642 | * registers for our children. |
| 643 | */ | 643 | */ |
| 644 | sachip->base = ioremap(mem->start, PAGE_SIZE * 2); | 644 | sachip->base = ioremap(mem->start, PAGE_SIZE * 2); |
| 645 | if (!sachip->base) { | 645 | if (!sachip->base) { |
| 646 | ret = -ENOMEM; | 646 | ret = -ENOMEM; |
| 647 | goto out; | 647 | goto out; |
| 648 | } | 648 | } |
| 649 | 649 | ||
| 650 | /* | 650 | /* |
| 651 | * Probe for the chip. Only touch the SBI registers. | 651 | * Probe for the chip. Only touch the SBI registers. |
| 652 | */ | 652 | */ |
| 653 | id = sa1111_readl(sachip->base + SA1111_SKID); | 653 | id = sa1111_readl(sachip->base + SA1111_SKID); |
| 654 | if ((id & SKID_ID_MASK) != SKID_SA1111_ID) { | 654 | if ((id & SKID_ID_MASK) != SKID_SA1111_ID) { |
| 655 | printk(KERN_DEBUG "SA1111 not detected: ID = %08lx\n", id); | 655 | printk(KERN_DEBUG "SA1111 not detected: ID = %08lx\n", id); |
| 656 | ret = -ENODEV; | 656 | ret = -ENODEV; |
| 657 | goto unmap; | 657 | goto unmap; |
| 658 | } | 658 | } |
| 659 | 659 | ||
| 660 | printk(KERN_INFO "SA1111 Microprocessor Companion Chip: " | 660 | printk(KERN_INFO "SA1111 Microprocessor Companion Chip: " |
| 661 | "silicon revision %lx, metal revision %lx\n", | 661 | "silicon revision %lx, metal revision %lx\n", |
| 662 | (id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK)); | 662 | (id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK)); |
| 663 | 663 | ||
| 664 | /* | 664 | /* |
| 665 | * We found it. Wake the chip up, and initialise. | 665 | * We found it. Wake the chip up, and initialise. |
| 666 | */ | 666 | */ |
| 667 | sa1111_wake(sachip); | 667 | sa1111_wake(sachip); |
| 668 | 668 | ||
| 669 | #ifdef CONFIG_ARCH_SA1100 | 669 | #ifdef CONFIG_ARCH_SA1100 |
| 670 | /* | 670 | /* |
| 671 | * The SDRAM configuration of the SA1110 and the SA1111 must | 671 | * The SDRAM configuration of the SA1110 and the SA1111 must |
| 672 | * match. This is very important to ensure that SA1111 accesses | 672 | * match. This is very important to ensure that SA1111 accesses |
| 673 | * don't corrupt the SDRAM. Note that this ungates the SA1111's | 673 | * don't corrupt the SDRAM. Note that this ungates the SA1111's |
| 674 | * MBGNT signal, so we must have called sa1110_mb_disable() | 674 | * MBGNT signal, so we must have called sa1110_mb_disable() |
| 675 | * beforehand. | 675 | * beforehand. |
| 676 | */ | 676 | */ |
| 677 | sa1111_configure_smc(sachip, 1, | 677 | sa1111_configure_smc(sachip, 1, |
| 678 | FExtr(MDCNFG, MDCNFG_SA1110_DRAC0), | 678 | FExtr(MDCNFG, MDCNFG_SA1110_DRAC0), |
| 679 | FExtr(MDCNFG, MDCNFG_SA1110_TDL0)); | 679 | FExtr(MDCNFG, MDCNFG_SA1110_TDL0)); |
| 680 | 680 | ||
| 681 | /* | 681 | /* |
| 682 | * We only need to turn on DCLK whenever we want to use the | 682 | * We only need to turn on DCLK whenever we want to use the |
| 683 | * DMA. It can otherwise be held firmly in the off position. | 683 | * DMA. It can otherwise be held firmly in the off position. |
| 684 | * (currently, we always enable it.) | 684 | * (currently, we always enable it.) |
| 685 | */ | 685 | */ |
| 686 | val = sa1111_readl(sachip->base + SA1111_SKPCR); | 686 | val = sa1111_readl(sachip->base + SA1111_SKPCR); |
| 687 | sa1111_writel(val | SKPCR_DCLKEN, sachip->base + SA1111_SKPCR); | 687 | sa1111_writel(val | SKPCR_DCLKEN, sachip->base + SA1111_SKPCR); |
| 688 | 688 | ||
| 689 | /* | 689 | /* |
| 690 | * Enable the SA1110 memory bus request and grant signals. | 690 | * Enable the SA1110 memory bus request and grant signals. |
| 691 | */ | 691 | */ |
| 692 | sa1110_mb_enable(); | 692 | sa1110_mb_enable(); |
| 693 | #endif | 693 | #endif |
| 694 | 694 | ||
| 695 | /* | 695 | /* |
| 696 | * The interrupt controller must be initialised before any | 696 | * The interrupt controller must be initialised before any |
| 697 | * other device to ensure that the interrupts are available. | 697 | * other device to ensure that the interrupts are available. |
| 698 | */ | 698 | */ |
| 699 | if (sachip->irq != NO_IRQ) | 699 | if (sachip->irq != NO_IRQ) |
| 700 | sa1111_setup_irq(sachip); | 700 | sa1111_setup_irq(sachip); |
| 701 | 701 | ||
| 702 | g_sa1111 = sachip; | 702 | g_sa1111 = sachip; |
| 703 | 703 | ||
| 704 | has_devs = ~0; | 704 | has_devs = ~0; |
| 705 | if (machine_is_assabet() || machine_is_jornada720() || | 705 | if (machine_is_assabet() || machine_is_jornada720() || |
| 706 | machine_is_badge4()) | 706 | machine_is_badge4()) |
| 707 | has_devs &= ~(1 << 4); | 707 | has_devs &= ~(1 << 4); |
| 708 | else | 708 | else |
| 709 | has_devs &= ~(1 << 1); | 709 | has_devs &= ~(1 << 1); |
| 710 | 710 | ||
| 711 | for (i = 0; i < ARRAY_SIZE(sa1111_devices); i++) | 711 | for (i = 0; i < ARRAY_SIZE(sa1111_devices); i++) |
| 712 | if (has_devs & (1 << i)) | 712 | if (has_devs & (1 << i)) |
| 713 | sa1111_init_one_child(sachip, mem, &sa1111_devices[i]); | 713 | sa1111_init_one_child(sachip, mem, &sa1111_devices[i]); |
| 714 | 714 | ||
| 715 | return 0; | 715 | return 0; |
| 716 | 716 | ||
| 717 | unmap: | 717 | unmap: |
| 718 | iounmap(sachip->base); | 718 | iounmap(sachip->base); |
| 719 | out: | 719 | out: |
| 720 | kfree(sachip); | 720 | kfree(sachip); |
| 721 | return ret; | 721 | return ret; |
| 722 | } | 722 | } |
| 723 | 723 | ||
| 724 | static int sa1111_remove_one(struct device *dev, void *data) | 724 | static int sa1111_remove_one(struct device *dev, void *data) |
| 725 | { | 725 | { |
| 726 | device_unregister(dev); | 726 | device_unregister(dev); |
| 727 | return 0; | 727 | return 0; |
| 728 | } | 728 | } |
| 729 | 729 | ||
| 730 | static void __sa1111_remove(struct sa1111 *sachip) | 730 | static void __sa1111_remove(struct sa1111 *sachip) |
| 731 | { | 731 | { |
| 732 | void __iomem *irqbase = sachip->base + SA1111_INTC; | 732 | void __iomem *irqbase = sachip->base + SA1111_INTC; |
| 733 | 733 | ||
| 734 | device_for_each_child(sachip->dev, NULL, sa1111_remove_one); | 734 | device_for_each_child(sachip->dev, NULL, sa1111_remove_one); |
| 735 | 735 | ||
| 736 | /* disable all IRQs */ | 736 | /* disable all IRQs */ |
| 737 | sa1111_writel(0, irqbase + SA1111_INTEN0); | 737 | sa1111_writel(0, irqbase + SA1111_INTEN0); |
| 738 | sa1111_writel(0, irqbase + SA1111_INTEN1); | 738 | sa1111_writel(0, irqbase + SA1111_INTEN1); |
| 739 | sa1111_writel(0, irqbase + SA1111_WAKEEN0); | 739 | sa1111_writel(0, irqbase + SA1111_WAKEEN0); |
| 740 | sa1111_writel(0, irqbase + SA1111_WAKEEN1); | 740 | sa1111_writel(0, irqbase + SA1111_WAKEEN1); |
| 741 | 741 | ||
| 742 | if (sachip->irq != NO_IRQ) { | 742 | if (sachip->irq != NO_IRQ) { |
| 743 | set_irq_chained_handler(sachip->irq, NULL); | 743 | set_irq_chained_handler(sachip->irq, NULL); |
| 744 | set_irq_data(sachip->irq, NULL); | 744 | set_irq_data(sachip->irq, NULL); |
| 745 | 745 | ||
| 746 | release_mem_region(sachip->phys + SA1111_INTC, 512); | 746 | release_mem_region(sachip->phys + SA1111_INTC, 512); |
| 747 | } | 747 | } |
| 748 | 748 | ||
| 749 | iounmap(sachip->base); | 749 | iounmap(sachip->base); |
| 750 | kfree(sachip); | 750 | kfree(sachip); |
| 751 | } | 751 | } |
| 752 | 752 | ||
| 753 | /* | 753 | /* |
| 754 | * According to the "Intel StrongARM SA-1111 Microprocessor Companion | 754 | * According to the "Intel StrongARM SA-1111 Microprocessor Companion |
| 755 | * Chip Specification Update" (June 2000), erratum #7, there is a | 755 | * Chip Specification Update" (June 2000), erratum #7, there is a |
| 756 | * significant bug in the SA1111 SDRAM shared memory controller. If | 756 | * significant bug in the SA1111 SDRAM shared memory controller. If |
| 757 | * an access to a region of memory above 1MB relative to the bank base, | 757 | * an access to a region of memory above 1MB relative to the bank base, |
| 758 | * it is important that address bit 10 _NOT_ be asserted. Depending | 758 | * it is important that address bit 10 _NOT_ be asserted. Depending |
| 759 | * on the configuration of the RAM, bit 10 may correspond to one | 759 | * on the configuration of the RAM, bit 10 may correspond to one |
| 760 | * of several different (processor-relative) address bits. | 760 | * of several different (processor-relative) address bits. |
| 761 | * | 761 | * |
| 762 | * This routine only identifies whether or not a given DMA address | 762 | * This routine only identifies whether or not a given DMA address |
| 763 | * is susceptible to the bug. | 763 | * is susceptible to the bug. |
| 764 | * | 764 | * |
| 765 | * This should only get called for sa1111_device types due to the | 765 | * This should only get called for sa1111_device types due to the |
| 766 | * way we configure our device dma_masks. | 766 | * way we configure our device dma_masks. |
| 767 | */ | 767 | */ |
| 768 | int dma_needs_bounce(struct device *dev, dma_addr_t addr, size_t size) | 768 | int dma_needs_bounce(struct device *dev, dma_addr_t addr, size_t size) |
| 769 | { | 769 | { |
| 770 | /* | 770 | /* |
| 771 | * Section 4.6 of the "Intel StrongARM SA-1111 Development Module | 771 | * Section 4.6 of the "Intel StrongARM SA-1111 Development Module |
| 772 | * User's Guide" mentions that jumpers R51 and R52 control the | 772 | * User's Guide" mentions that jumpers R51 and R52 control the |
| 773 | * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or | 773 | * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or |
| 774 | * SDRAM bank 1 on Neponset). The default configuration selects | 774 | * SDRAM bank 1 on Neponset). The default configuration selects |
| 775 | * Assabet, so any address in bank 1 is necessarily invalid. | 775 | * Assabet, so any address in bank 1 is necessarily invalid. |
| 776 | */ | 776 | */ |
| 777 | return ((machine_is_assabet() || machine_is_pfs168()) && | 777 | return ((machine_is_assabet() || machine_is_pfs168()) && |
| 778 | (addr >= 0xc8000000 || (addr + size) >= 0xc8000000)); | 778 | (addr >= 0xc8000000 || (addr + size) >= 0xc8000000)); |
| 779 | } | 779 | } |
| 780 | 780 | ||
| 781 | struct sa1111_save_data { | 781 | struct sa1111_save_data { |
| 782 | unsigned int skcr; | 782 | unsigned int skcr; |
| 783 | unsigned int skpcr; | 783 | unsigned int skpcr; |
| 784 | unsigned int skcdr; | 784 | unsigned int skcdr; |
| 785 | unsigned char skaud; | 785 | unsigned char skaud; |
| 786 | unsigned char skpwm0; | 786 | unsigned char skpwm0; |
| 787 | unsigned char skpwm1; | 787 | unsigned char skpwm1; |
| 788 | 788 | ||
| 789 | /* | 789 | /* |
| 790 | * Interrupt controller | 790 | * Interrupt controller |
| 791 | */ | 791 | */ |
| 792 | unsigned int intpol0; | 792 | unsigned int intpol0; |
| 793 | unsigned int intpol1; | 793 | unsigned int intpol1; |
| 794 | unsigned int inten0; | 794 | unsigned int inten0; |
| 795 | unsigned int inten1; | 795 | unsigned int inten1; |
| 796 | unsigned int wakepol0; | 796 | unsigned int wakepol0; |
| 797 | unsigned int wakepol1; | 797 | unsigned int wakepol1; |
| 798 | unsigned int wakeen0; | 798 | unsigned int wakeen0; |
| 799 | unsigned int wakeen1; | 799 | unsigned int wakeen1; |
| 800 | }; | 800 | }; |
| 801 | 801 | ||
| 802 | #ifdef CONFIG_PM | 802 | #ifdef CONFIG_PM |
| 803 | 803 | ||
| 804 | static int sa1111_suspend(struct device *dev, pm_message_t state, u32 level) | 804 | static int sa1111_suspend(struct device *dev, pm_message_t state, u32 level) |
| 805 | { | 805 | { |
| 806 | struct sa1111 *sachip = dev_get_drvdata(dev); | 806 | struct sa1111 *sachip = dev_get_drvdata(dev); |
| 807 | struct sa1111_save_data *save; | 807 | struct sa1111_save_data *save; |
| 808 | unsigned long flags; | 808 | unsigned long flags; |
| 809 | unsigned int val; | 809 | unsigned int val; |
| 810 | void __iomem *base; | 810 | void __iomem *base; |
| 811 | 811 | ||
| 812 | if (level != SUSPEND_DISABLE) | 812 | if (level != SUSPEND_DISABLE) |
| 813 | return 0; | 813 | return 0; |
| 814 | 814 | ||
| 815 | save = kmalloc(sizeof(struct sa1111_save_data), GFP_KERNEL); | 815 | save = kmalloc(sizeof(struct sa1111_save_data), GFP_KERNEL); |
| 816 | if (!save) | 816 | if (!save) |
| 817 | return -ENOMEM; | 817 | return -ENOMEM; |
| 818 | dev->power.saved_state = save; | 818 | dev->power.saved_state = save; |
| 819 | 819 | ||
| 820 | spin_lock_irqsave(&sachip->lock, flags); | 820 | spin_lock_irqsave(&sachip->lock, flags); |
| 821 | 821 | ||
| 822 | /* | 822 | /* |
| 823 | * Save state. | 823 | * Save state. |
| 824 | */ | 824 | */ |
| 825 | base = sachip->base; | 825 | base = sachip->base; |
| 826 | save->skcr = sa1111_readl(base + SA1111_SKCR); | 826 | save->skcr = sa1111_readl(base + SA1111_SKCR); |
| 827 | save->skpcr = sa1111_readl(base + SA1111_SKPCR); | 827 | save->skpcr = sa1111_readl(base + SA1111_SKPCR); |
| 828 | save->skcdr = sa1111_readl(base + SA1111_SKCDR); | 828 | save->skcdr = sa1111_readl(base + SA1111_SKCDR); |
| 829 | save->skaud = sa1111_readl(base + SA1111_SKAUD); | 829 | save->skaud = sa1111_readl(base + SA1111_SKAUD); |
| 830 | save->skpwm0 = sa1111_readl(base + SA1111_SKPWM0); | 830 | save->skpwm0 = sa1111_readl(base + SA1111_SKPWM0); |
| 831 | save->skpwm1 = sa1111_readl(base + SA1111_SKPWM1); | 831 | save->skpwm1 = sa1111_readl(base + SA1111_SKPWM1); |
| 832 | 832 | ||
| 833 | base = sachip->base + SA1111_INTC; | 833 | base = sachip->base + SA1111_INTC; |
| 834 | save->intpol0 = sa1111_readl(base + SA1111_INTPOL0); | 834 | save->intpol0 = sa1111_readl(base + SA1111_INTPOL0); |
| 835 | save->intpol1 = sa1111_readl(base + SA1111_INTPOL1); | 835 | save->intpol1 = sa1111_readl(base + SA1111_INTPOL1); |
| 836 | save->inten0 = sa1111_readl(base + SA1111_INTEN0); | 836 | save->inten0 = sa1111_readl(base + SA1111_INTEN0); |
| 837 | save->inten1 = sa1111_readl(base + SA1111_INTEN1); | 837 | save->inten1 = sa1111_readl(base + SA1111_INTEN1); |
| 838 | save->wakepol0 = sa1111_readl(base + SA1111_WAKEPOL0); | 838 | save->wakepol0 = sa1111_readl(base + SA1111_WAKEPOL0); |
| 839 | save->wakepol1 = sa1111_readl(base + SA1111_WAKEPOL1); | 839 | save->wakepol1 = sa1111_readl(base + SA1111_WAKEPOL1); |
| 840 | save->wakeen0 = sa1111_readl(base + SA1111_WAKEEN0); | 840 | save->wakeen0 = sa1111_readl(base + SA1111_WAKEEN0); |
| 841 | save->wakeen1 = sa1111_readl(base + SA1111_WAKEEN1); | 841 | save->wakeen1 = sa1111_readl(base + SA1111_WAKEEN1); |
| 842 | 842 | ||
| 843 | /* | 843 | /* |
| 844 | * Disable. | 844 | * Disable. |
| 845 | */ | 845 | */ |
| 846 | val = sa1111_readl(sachip->base + SA1111_SKCR); | 846 | val = sa1111_readl(sachip->base + SA1111_SKCR); |
| 847 | sa1111_writel(val | SKCR_SLEEP, sachip->base + SA1111_SKCR); | 847 | sa1111_writel(val | SKCR_SLEEP, sachip->base + SA1111_SKCR); |
| 848 | sa1111_writel(0, sachip->base + SA1111_SKPWM0); | 848 | sa1111_writel(0, sachip->base + SA1111_SKPWM0); |
| 849 | sa1111_writel(0, sachip->base + SA1111_SKPWM1); | 849 | sa1111_writel(0, sachip->base + SA1111_SKPWM1); |
| 850 | 850 | ||
| 851 | spin_unlock_irqrestore(&sachip->lock, flags); | 851 | spin_unlock_irqrestore(&sachip->lock, flags); |
| 852 | 852 | ||
| 853 | return 0; | 853 | return 0; |
| 854 | } | 854 | } |
| 855 | 855 | ||
| 856 | /* | 856 | /* |
| 857 | * sa1111_resume - Restore the SA1111 device state. | 857 | * sa1111_resume - Restore the SA1111 device state. |
| 858 | * @dev: device to restore | 858 | * @dev: device to restore |
| 859 | * @level: resume level | 859 | * @level: resume level |
| 860 | * | 860 | * |
| 861 | * Restore the general state of the SA1111; clock control and | 861 | * Restore the general state of the SA1111; clock control and |
| 862 | * interrupt controller. Other parts of the SA1111 must be | 862 | * interrupt controller. Other parts of the SA1111 must be |
| 863 | * restored by their respective drivers, and must be called | 863 | * restored by their respective drivers, and must be called |
| 864 | * via LDM after this function. | 864 | * via LDM after this function. |
| 865 | */ | 865 | */ |
| 866 | static int sa1111_resume(struct device *dev, u32 level) | 866 | static int sa1111_resume(struct device *dev, u32 level) |
| 867 | { | 867 | { |
| 868 | struct sa1111 *sachip = dev_get_drvdata(dev); | 868 | struct sa1111 *sachip = dev_get_drvdata(dev); |
| 869 | struct sa1111_save_data *save; | 869 | struct sa1111_save_data *save; |
| 870 | unsigned long flags, id; | 870 | unsigned long flags, id; |
| 871 | void __iomem *base; | 871 | void __iomem *base; |
| 872 | 872 | ||
| 873 | if (level != RESUME_ENABLE) | 873 | if (level != RESUME_ENABLE) |
| 874 | return 0; | 874 | return 0; |
| 875 | 875 | ||
| 876 | save = (struct sa1111_save_data *)dev->power.saved_state; | 876 | save = (struct sa1111_save_data *)dev->power.saved_state; |
| 877 | if (!save) | 877 | if (!save) |
| 878 | return 0; | 878 | return 0; |
| 879 | 879 | ||
| 880 | spin_lock_irqsave(&sachip->lock, flags); | 880 | spin_lock_irqsave(&sachip->lock, flags); |
| 881 | 881 | ||
| 882 | /* | 882 | /* |
| 883 | * Ensure that the SA1111 is still here. | 883 | * Ensure that the SA1111 is still here. |
| 884 | * FIXME: shouldn't do this here. | 884 | * FIXME: shouldn't do this here. |
| 885 | */ | 885 | */ |
| 886 | id = sa1111_readl(sachip->base + SA1111_SKID); | 886 | id = sa1111_readl(sachip->base + SA1111_SKID); |
| 887 | if ((id & SKID_ID_MASK) != SKID_SA1111_ID) { | 887 | if ((id & SKID_ID_MASK) != SKID_SA1111_ID) { |
| 888 | __sa1111_remove(sachip); | 888 | __sa1111_remove(sachip); |
| 889 | dev_set_drvdata(dev, NULL); | 889 | dev_set_drvdata(dev, NULL); |
| 890 | kfree(save); | 890 | kfree(save); |
| 891 | return 0; | 891 | return 0; |
| 892 | } | 892 | } |
| 893 | 893 | ||
| 894 | /* | 894 | /* |
| 895 | * First of all, wake up the chip. | 895 | * First of all, wake up the chip. |
| 896 | */ | 896 | */ |
| 897 | sa1111_wake(sachip); | 897 | sa1111_wake(sachip); |
| 898 | sa1111_writel(0, sachip->base + SA1111_INTC + SA1111_INTEN0); | 898 | sa1111_writel(0, sachip->base + SA1111_INTC + SA1111_INTEN0); |
| 899 | sa1111_writel(0, sachip->base + SA1111_INTC + SA1111_INTEN1); | 899 | sa1111_writel(0, sachip->base + SA1111_INTC + SA1111_INTEN1); |
| 900 | 900 | ||
| 901 | base = sachip->base; | 901 | base = sachip->base; |
| 902 | sa1111_writel(save->skcr, base + SA1111_SKCR); | 902 | sa1111_writel(save->skcr, base + SA1111_SKCR); |
| 903 | sa1111_writel(save->skpcr, base + SA1111_SKPCR); | 903 | sa1111_writel(save->skpcr, base + SA1111_SKPCR); |
| 904 | sa1111_writel(save->skcdr, base + SA1111_SKCDR); | 904 | sa1111_writel(save->skcdr, base + SA1111_SKCDR); |
| 905 | sa1111_writel(save->skaud, base + SA1111_SKAUD); | 905 | sa1111_writel(save->skaud, base + SA1111_SKAUD); |
| 906 | sa1111_writel(save->skpwm0, base + SA1111_SKPWM0); | 906 | sa1111_writel(save->skpwm0, base + SA1111_SKPWM0); |
| 907 | sa1111_writel(save->skpwm1, base + SA1111_SKPWM1); | 907 | sa1111_writel(save->skpwm1, base + SA1111_SKPWM1); |
| 908 | 908 | ||
| 909 | base = sachip->base + SA1111_INTC; | 909 | base = sachip->base + SA1111_INTC; |
| 910 | sa1111_writel(save->intpol0, base + SA1111_INTPOL0); | 910 | sa1111_writel(save->intpol0, base + SA1111_INTPOL0); |
| 911 | sa1111_writel(save->intpol1, base + SA1111_INTPOL1); | 911 | sa1111_writel(save->intpol1, base + SA1111_INTPOL1); |
| 912 | sa1111_writel(save->inten0, base + SA1111_INTEN0); | 912 | sa1111_writel(save->inten0, base + SA1111_INTEN0); |
| 913 | sa1111_writel(save->inten1, base + SA1111_INTEN1); | 913 | sa1111_writel(save->inten1, base + SA1111_INTEN1); |
| 914 | sa1111_writel(save->wakepol0, base + SA1111_WAKEPOL0); | 914 | sa1111_writel(save->wakepol0, base + SA1111_WAKEPOL0); |
| 915 | sa1111_writel(save->wakepol1, base + SA1111_WAKEPOL1); | 915 | sa1111_writel(save->wakepol1, base + SA1111_WAKEPOL1); |
| 916 | sa1111_writel(save->wakeen0, base + SA1111_WAKEEN0); | 916 | sa1111_writel(save->wakeen0, base + SA1111_WAKEEN0); |
| 917 | sa1111_writel(save->wakeen1, base + SA1111_WAKEEN1); | 917 | sa1111_writel(save->wakeen1, base + SA1111_WAKEEN1); |
| 918 | 918 | ||
| 919 | spin_unlock_irqrestore(&sachip->lock, flags); | 919 | spin_unlock_irqrestore(&sachip->lock, flags); |
| 920 | 920 | ||
| 921 | dev->power.saved_state = NULL; | 921 | dev->power.saved_state = NULL; |
| 922 | kfree(save); | 922 | kfree(save); |
| 923 | 923 | ||
| 924 | return 0; | 924 | return 0; |
| 925 | } | 925 | } |
| 926 | 926 | ||
| 927 | #else | 927 | #else |
| 928 | #define sa1111_suspend NULL | 928 | #define sa1111_suspend NULL |
| 929 | #define sa1111_resume NULL | 929 | #define sa1111_resume NULL |
| 930 | #endif | 930 | #endif |
| 931 | 931 | ||
| 932 | static int sa1111_probe(struct device *dev) | 932 | static int sa1111_probe(struct device *dev) |
| 933 | { | 933 | { |
| 934 | struct platform_device *pdev = to_platform_device(dev); | 934 | struct platform_device *pdev = to_platform_device(dev); |
| 935 | struct resource *mem; | 935 | struct resource *mem; |
| 936 | int irq; | 936 | int irq; |
| 937 | 937 | ||
| 938 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 938 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 939 | if (!mem) | 939 | if (!mem) |
| 940 | return -EINVAL; | 940 | return -EINVAL; |
| 941 | irq = platform_get_irq(pdev, 0); | 941 | irq = platform_get_irq(pdev, 0); |
| 942 | 942 | ||
| 943 | return __sa1111_probe(dev, mem, irq); | 943 | return __sa1111_probe(dev, mem, irq); |
| 944 | } | 944 | } |
| 945 | 945 | ||
| 946 | static int sa1111_remove(struct device *dev) | 946 | static int sa1111_remove(struct device *dev) |
| 947 | { | 947 | { |
| 948 | struct sa1111 *sachip = dev_get_drvdata(dev); | 948 | struct sa1111 *sachip = dev_get_drvdata(dev); |
| 949 | 949 | ||
| 950 | if (sachip) { | 950 | if (sachip) { |
| 951 | __sa1111_remove(sachip); | 951 | __sa1111_remove(sachip); |
| 952 | dev_set_drvdata(dev, NULL); | 952 | dev_set_drvdata(dev, NULL); |
| 953 | 953 | ||
| 954 | #ifdef CONFIG_PM | 954 | #ifdef CONFIG_PM |
| 955 | kfree(dev->power.saved_state); | 955 | kfree(dev->power.saved_state); |
| 956 | dev->power.saved_state = NULL; | 956 | dev->power.saved_state = NULL; |
| 957 | #endif | 957 | #endif |
| 958 | } | 958 | } |
| 959 | 959 | ||
| 960 | return 0; | 960 | return 0; |
| 961 | } | 961 | } |
| 962 | 962 | ||
| 963 | /* | 963 | /* |
| 964 | * Not sure if this should be on the system bus or not yet. | 964 | * Not sure if this should be on the system bus or not yet. |
| 965 | * We really want some way to register a system device at | 965 | * We really want some way to register a system device at |
| 966 | * the per-machine level, and then have this driver pick | 966 | * the per-machine level, and then have this driver pick |
| 967 | * up the registered devices. | 967 | * up the registered devices. |
| 968 | * | 968 | * |
| 969 | * We also need to handle the SDRAM configuration for | 969 | * We also need to handle the SDRAM configuration for |
| 970 | * PXA250/SA1110 machine classes. | 970 | * PXA250/SA1110 machine classes. |
| 971 | */ | 971 | */ |
| 972 | static struct device_driver sa1111_device_driver = { | 972 | static struct device_driver sa1111_device_driver = { |
| 973 | .name = "sa1111", | 973 | .name = "sa1111", |
| 974 | .bus = &platform_bus_type, | 974 | .bus = &platform_bus_type, |
| 975 | .probe = sa1111_probe, | 975 | .probe = sa1111_probe, |
| 976 | .remove = sa1111_remove, | 976 | .remove = sa1111_remove, |
| 977 | .suspend = sa1111_suspend, | 977 | .suspend = sa1111_suspend, |
| 978 | .resume = sa1111_resume, | 978 | .resume = sa1111_resume, |
| 979 | }; | 979 | }; |
| 980 | 980 | ||
| 981 | /* | 981 | /* |
| 982 | * Get the parent device driver (us) structure | 982 | * Get the parent device driver (us) structure |
| 983 | * from a child function device | 983 | * from a child function device |
| 984 | */ | 984 | */ |
| 985 | static inline struct sa1111 *sa1111_chip_driver(struct sa1111_dev *sadev) | 985 | static inline struct sa1111 *sa1111_chip_driver(struct sa1111_dev *sadev) |
| 986 | { | 986 | { |
| 987 | return (struct sa1111 *)dev_get_drvdata(sadev->dev.parent); | 987 | return (struct sa1111 *)dev_get_drvdata(sadev->dev.parent); |
| 988 | } | 988 | } |
| 989 | 989 | ||
| 990 | /* | 990 | /* |
| 991 | * The bits in the opdiv field are non-linear. | 991 | * The bits in the opdiv field are non-linear. |
| 992 | */ | 992 | */ |
| 993 | static unsigned char opdiv_table[] = { 1, 4, 2, 8 }; | 993 | static unsigned char opdiv_table[] = { 1, 4, 2, 8 }; |
| 994 | 994 | ||
| 995 | static unsigned int __sa1111_pll_clock(struct sa1111 *sachip) | 995 | static unsigned int __sa1111_pll_clock(struct sa1111 *sachip) |
| 996 | { | 996 | { |
| 997 | unsigned int skcdr, fbdiv, ipdiv, opdiv; | 997 | unsigned int skcdr, fbdiv, ipdiv, opdiv; |
| 998 | 998 | ||
| 999 | skcdr = sa1111_readl(sachip->base + SA1111_SKCDR); | 999 | skcdr = sa1111_readl(sachip->base + SA1111_SKCDR); |
| 1000 | 1000 | ||
| 1001 | fbdiv = (skcdr & 0x007f) + 2; | 1001 | fbdiv = (skcdr & 0x007f) + 2; |
| 1002 | ipdiv = ((skcdr & 0x0f80) >> 7) + 2; | 1002 | ipdiv = ((skcdr & 0x0f80) >> 7) + 2; |
| 1003 | opdiv = opdiv_table[(skcdr & 0x3000) >> 12]; | 1003 | opdiv = opdiv_table[(skcdr & 0x3000) >> 12]; |
| 1004 | 1004 | ||
| 1005 | return 3686400 * fbdiv / (ipdiv * opdiv); | 1005 | return 3686400 * fbdiv / (ipdiv * opdiv); |
| 1006 | } | 1006 | } |
| 1007 | 1007 | ||
| 1008 | /** | 1008 | /** |
| 1009 | * sa1111_pll_clock - return the current PLL clock frequency. | 1009 | * sa1111_pll_clock - return the current PLL clock frequency. |
| 1010 | * @sadev: SA1111 function block | 1010 | * @sadev: SA1111 function block |
| 1011 | * | 1011 | * |
| 1012 | * BUG: we should look at SKCR. We also blindly believe that | 1012 | * BUG: we should look at SKCR. We also blindly believe that |
| 1013 | * the chip is being fed with the 3.6864MHz clock. | 1013 | * the chip is being fed with the 3.6864MHz clock. |
| 1014 | * | 1014 | * |
| 1015 | * Returns the PLL clock in Hz. | 1015 | * Returns the PLL clock in Hz. |
| 1016 | */ | 1016 | */ |
| 1017 | unsigned int sa1111_pll_clock(struct sa1111_dev *sadev) | 1017 | unsigned int sa1111_pll_clock(struct sa1111_dev *sadev) |
| 1018 | { | 1018 | { |
| 1019 | struct sa1111 *sachip = sa1111_chip_driver(sadev); | 1019 | struct sa1111 *sachip = sa1111_chip_driver(sadev); |
| 1020 | 1020 | ||
| 1021 | return __sa1111_pll_clock(sachip); | 1021 | return __sa1111_pll_clock(sachip); |
| 1022 | } | 1022 | } |
| 1023 | 1023 | ||
| 1024 | /** | 1024 | /** |
| 1025 | * sa1111_select_audio_mode - select I2S or AC link mode | 1025 | * sa1111_select_audio_mode - select I2S or AC link mode |
| 1026 | * @sadev: SA1111 function block | 1026 | * @sadev: SA1111 function block |
| 1027 | * @mode: One of %SA1111_AUDIO_ACLINK or %SA1111_AUDIO_I2S | 1027 | * @mode: One of %SA1111_AUDIO_ACLINK or %SA1111_AUDIO_I2S |
| 1028 | * | 1028 | * |
| 1029 | * Frob the SKCR to select AC Link mode or I2S mode for | 1029 | * Frob the SKCR to select AC Link mode or I2S mode for |
| 1030 | * the audio block. | 1030 | * the audio block. |
| 1031 | */ | 1031 | */ |
| 1032 | void sa1111_select_audio_mode(struct sa1111_dev *sadev, int mode) | 1032 | void sa1111_select_audio_mode(struct sa1111_dev *sadev, int mode) |
| 1033 | { | 1033 | { |
| 1034 | struct sa1111 *sachip = sa1111_chip_driver(sadev); | 1034 | struct sa1111 *sachip = sa1111_chip_driver(sadev); |
| 1035 | unsigned long flags; | 1035 | unsigned long flags; |
| 1036 | unsigned int val; | 1036 | unsigned int val; |
| 1037 | 1037 | ||
| 1038 | spin_lock_irqsave(&sachip->lock, flags); | 1038 | spin_lock_irqsave(&sachip->lock, flags); |
| 1039 | 1039 | ||
| 1040 | val = sa1111_readl(sachip->base + SA1111_SKCR); | 1040 | val = sa1111_readl(sachip->base + SA1111_SKCR); |
| 1041 | if (mode == SA1111_AUDIO_I2S) { | 1041 | if (mode == SA1111_AUDIO_I2S) { |
| 1042 | val &= ~SKCR_SELAC; | 1042 | val &= ~SKCR_SELAC; |
| 1043 | } else { | 1043 | } else { |
| 1044 | val |= SKCR_SELAC; | 1044 | val |= SKCR_SELAC; |
| 1045 | } | 1045 | } |
| 1046 | sa1111_writel(val, sachip->base + SA1111_SKCR); | 1046 | sa1111_writel(val, sachip->base + SA1111_SKCR); |
| 1047 | 1047 | ||
| 1048 | spin_unlock_irqrestore(&sachip->lock, flags); | 1048 | spin_unlock_irqrestore(&sachip->lock, flags); |
| 1049 | } | 1049 | } |
| 1050 | 1050 | ||
| 1051 | /** | 1051 | /** |
| 1052 | * sa1111_set_audio_rate - set the audio sample rate | 1052 | * sa1111_set_audio_rate - set the audio sample rate |
| 1053 | * @sadev: SA1111 SAC function block | 1053 | * @sadev: SA1111 SAC function block |
| 1054 | * @rate: sample rate to select | 1054 | * @rate: sample rate to select |
| 1055 | */ | 1055 | */ |
| 1056 | int sa1111_set_audio_rate(struct sa1111_dev *sadev, int rate) | 1056 | int sa1111_set_audio_rate(struct sa1111_dev *sadev, int rate) |
| 1057 | { | 1057 | { |
| 1058 | struct sa1111 *sachip = sa1111_chip_driver(sadev); | 1058 | struct sa1111 *sachip = sa1111_chip_driver(sadev); |
| 1059 | unsigned int div; | 1059 | unsigned int div; |
| 1060 | 1060 | ||
| 1061 | if (sadev->devid != SA1111_DEVID_SAC) | 1061 | if (sadev->devid != SA1111_DEVID_SAC) |
| 1062 | return -EINVAL; | 1062 | return -EINVAL; |
| 1063 | 1063 | ||
| 1064 | div = (__sa1111_pll_clock(sachip) / 256 + rate / 2) / rate; | 1064 | div = (__sa1111_pll_clock(sachip) / 256 + rate / 2) / rate; |
| 1065 | if (div == 0) | 1065 | if (div == 0) |
| 1066 | div = 1; | 1066 | div = 1; |
| 1067 | if (div > 128) | 1067 | if (div > 128) |
| 1068 | div = 128; | 1068 | div = 128; |
| 1069 | 1069 | ||
| 1070 | sa1111_writel(div - 1, sachip->base + SA1111_SKAUD); | 1070 | sa1111_writel(div - 1, sachip->base + SA1111_SKAUD); |
| 1071 | 1071 | ||
| 1072 | return 0; | 1072 | return 0; |
| 1073 | } | 1073 | } |
| 1074 | 1074 | ||
| 1075 | /** | 1075 | /** |
| 1076 | * sa1111_get_audio_rate - get the audio sample rate | 1076 | * sa1111_get_audio_rate - get the audio sample rate |
| 1077 | * @sadev: SA1111 SAC function block device | 1077 | * @sadev: SA1111 SAC function block device |
| 1078 | */ | 1078 | */ |
| 1079 | int sa1111_get_audio_rate(struct sa1111_dev *sadev) | 1079 | int sa1111_get_audio_rate(struct sa1111_dev *sadev) |
| 1080 | { | 1080 | { |
| 1081 | struct sa1111 *sachip = sa1111_chip_driver(sadev); | 1081 | struct sa1111 *sachip = sa1111_chip_driver(sadev); |
| 1082 | unsigned long div; | 1082 | unsigned long div; |
| 1083 | 1083 | ||
| 1084 | if (sadev->devid != SA1111_DEVID_SAC) | 1084 | if (sadev->devid != SA1111_DEVID_SAC) |
| 1085 | return -EINVAL; | 1085 | return -EINVAL; |
| 1086 | 1086 | ||
| 1087 | div = sa1111_readl(sachip->base + SA1111_SKAUD) + 1; | 1087 | div = sa1111_readl(sachip->base + SA1111_SKAUD) + 1; |
| 1088 | 1088 | ||
| 1089 | return __sa1111_pll_clock(sachip) / (256 * div); | 1089 | return __sa1111_pll_clock(sachip) / (256 * div); |
| 1090 | } | 1090 | } |
| 1091 | 1091 | ||
| 1092 | void sa1111_set_io_dir(struct sa1111_dev *sadev, | 1092 | void sa1111_set_io_dir(struct sa1111_dev *sadev, |
| 1093 | unsigned int bits, unsigned int dir, | 1093 | unsigned int bits, unsigned int dir, |
| 1094 | unsigned int sleep_dir) | 1094 | unsigned int sleep_dir) |
| 1095 | { | 1095 | { |
| 1096 | struct sa1111 *sachip = sa1111_chip_driver(sadev); | 1096 | struct sa1111 *sachip = sa1111_chip_driver(sadev); |
| 1097 | unsigned long flags; | 1097 | unsigned long flags; |
| 1098 | unsigned int val; | 1098 | unsigned int val; |
| 1099 | void __iomem *gpio = sachip->base + SA1111_GPIO; | 1099 | void __iomem *gpio = sachip->base + SA1111_GPIO; |
| 1100 | 1100 | ||
| 1101 | #define MODIFY_BITS(port, mask, dir) \ | 1101 | #define MODIFY_BITS(port, mask, dir) \ |
| 1102 | if (mask) { \ | 1102 | if (mask) { \ |
| 1103 | val = sa1111_readl(port); \ | 1103 | val = sa1111_readl(port); \ |
| 1104 | val &= ~(mask); \ | 1104 | val &= ~(mask); \ |
| 1105 | val |= (dir) & (mask); \ | 1105 | val |= (dir) & (mask); \ |
| 1106 | sa1111_writel(val, port); \ | 1106 | sa1111_writel(val, port); \ |
| 1107 | } | 1107 | } |
| 1108 | 1108 | ||
| 1109 | spin_lock_irqsave(&sachip->lock, flags); | 1109 | spin_lock_irqsave(&sachip->lock, flags); |
| 1110 | MODIFY_BITS(gpio + SA1111_GPIO_PADDR, bits & 15, dir); | 1110 | MODIFY_BITS(gpio + SA1111_GPIO_PADDR, bits & 15, dir); |
| 1111 | MODIFY_BITS(gpio + SA1111_GPIO_PBDDR, (bits >> 8) & 255, dir >> 8); | 1111 | MODIFY_BITS(gpio + SA1111_GPIO_PBDDR, (bits >> 8) & 255, dir >> 8); |
| 1112 | MODIFY_BITS(gpio + SA1111_GPIO_PCDDR, (bits >> 16) & 255, dir >> 16); | 1112 | MODIFY_BITS(gpio + SA1111_GPIO_PCDDR, (bits >> 16) & 255, dir >> 16); |
| 1113 | 1113 | ||
| 1114 | MODIFY_BITS(gpio + SA1111_GPIO_PASDR, bits & 15, sleep_dir); | 1114 | MODIFY_BITS(gpio + SA1111_GPIO_PASDR, bits & 15, sleep_dir); |
| 1115 | MODIFY_BITS(gpio + SA1111_GPIO_PBSDR, (bits >> 8) & 255, sleep_dir >> 8); | 1115 | MODIFY_BITS(gpio + SA1111_GPIO_PBSDR, (bits >> 8) & 255, sleep_dir >> 8); |
| 1116 | MODIFY_BITS(gpio + SA1111_GPIO_PCSDR, (bits >> 16) & 255, sleep_dir >> 16); | 1116 | MODIFY_BITS(gpio + SA1111_GPIO_PCSDR, (bits >> 16) & 255, sleep_dir >> 16); |
| 1117 | spin_unlock_irqrestore(&sachip->lock, flags); | 1117 | spin_unlock_irqrestore(&sachip->lock, flags); |
| 1118 | } | 1118 | } |
| 1119 | 1119 | ||
| 1120 | void sa1111_set_io(struct sa1111_dev *sadev, unsigned int bits, unsigned int v) | 1120 | void sa1111_set_io(struct sa1111_dev *sadev, unsigned int bits, unsigned int v) |
| 1121 | { | 1121 | { |
| 1122 | struct sa1111 *sachip = sa1111_chip_driver(sadev); | 1122 | struct sa1111 *sachip = sa1111_chip_driver(sadev); |
| 1123 | unsigned long flags; | 1123 | unsigned long flags; |
| 1124 | unsigned int val; | 1124 | unsigned int val; |
| 1125 | void __iomem *gpio = sachip->base + SA1111_GPIO; | 1125 | void __iomem *gpio = sachip->base + SA1111_GPIO; |
| 1126 | 1126 | ||
| 1127 | spin_lock_irqsave(&sachip->lock, flags); | 1127 | spin_lock_irqsave(&sachip->lock, flags); |
| 1128 | MODIFY_BITS(gpio + SA1111_GPIO_PADWR, bits & 15, v); | 1128 | MODIFY_BITS(gpio + SA1111_GPIO_PADWR, bits & 15, v); |
| 1129 | MODIFY_BITS(gpio + SA1111_GPIO_PBDWR, (bits >> 8) & 255, v >> 8); | 1129 | MODIFY_BITS(gpio + SA1111_GPIO_PBDWR, (bits >> 8) & 255, v >> 8); |
| 1130 | MODIFY_BITS(gpio + SA1111_GPIO_PCDWR, (bits >> 16) & 255, v >> 16); | 1130 | MODIFY_BITS(gpio + SA1111_GPIO_PCDWR, (bits >> 16) & 255, v >> 16); |
| 1131 | spin_unlock_irqrestore(&sachip->lock, flags); | 1131 | spin_unlock_irqrestore(&sachip->lock, flags); |
| 1132 | } | 1132 | } |
| 1133 | 1133 | ||
| 1134 | void sa1111_set_sleep_io(struct sa1111_dev *sadev, unsigned int bits, unsigned int v) | 1134 | void sa1111_set_sleep_io(struct sa1111_dev *sadev, unsigned int bits, unsigned int v) |
| 1135 | { | 1135 | { |
| 1136 | struct sa1111 *sachip = sa1111_chip_driver(sadev); | 1136 | struct sa1111 *sachip = sa1111_chip_driver(sadev); |
| 1137 | unsigned long flags; | 1137 | unsigned long flags; |
| 1138 | unsigned int val; | 1138 | unsigned int val; |
| 1139 | void __iomem *gpio = sachip->base + SA1111_GPIO; | 1139 | void __iomem *gpio = sachip->base + SA1111_GPIO; |
| 1140 | 1140 | ||
| 1141 | spin_lock_irqsave(&sachip->lock, flags); | 1141 | spin_lock_irqsave(&sachip->lock, flags); |
| 1142 | MODIFY_BITS(gpio + SA1111_GPIO_PASSR, bits & 15, v); | 1142 | MODIFY_BITS(gpio + SA1111_GPIO_PASSR, bits & 15, v); |
| 1143 | MODIFY_BITS(gpio + SA1111_GPIO_PBSSR, (bits >> 8) & 255, v >> 8); | 1143 | MODIFY_BITS(gpio + SA1111_GPIO_PBSSR, (bits >> 8) & 255, v >> 8); |
| 1144 | MODIFY_BITS(gpio + SA1111_GPIO_PCSSR, (bits >> 16) & 255, v >> 16); | 1144 | MODIFY_BITS(gpio + SA1111_GPIO_PCSSR, (bits >> 16) & 255, v >> 16); |
| 1145 | spin_unlock_irqrestore(&sachip->lock, flags); | 1145 | spin_unlock_irqrestore(&sachip->lock, flags); |
| 1146 | } | 1146 | } |
| 1147 | 1147 | ||
| 1148 | /* | 1148 | /* |
| 1149 | * Individual device operations. | 1149 | * Individual device operations. |
| 1150 | */ | 1150 | */ |
| 1151 | 1151 | ||
| 1152 | /** | 1152 | /** |
| 1153 | * sa1111_enable_device - enable an on-chip SA1111 function block | 1153 | * sa1111_enable_device - enable an on-chip SA1111 function block |
| 1154 | * @sadev: SA1111 function block device to enable | 1154 | * @sadev: SA1111 function block device to enable |
| 1155 | */ | 1155 | */ |
| 1156 | void sa1111_enable_device(struct sa1111_dev *sadev) | 1156 | void sa1111_enable_device(struct sa1111_dev *sadev) |
| 1157 | { | 1157 | { |
| 1158 | struct sa1111 *sachip = sa1111_chip_driver(sadev); | 1158 | struct sa1111 *sachip = sa1111_chip_driver(sadev); |
| 1159 | unsigned long flags; | 1159 | unsigned long flags; |
| 1160 | unsigned int val; | 1160 | unsigned int val; |
| 1161 | 1161 | ||
| 1162 | spin_lock_irqsave(&sachip->lock, flags); | 1162 | spin_lock_irqsave(&sachip->lock, flags); |
| 1163 | val = sa1111_readl(sachip->base + SA1111_SKPCR); | 1163 | val = sa1111_readl(sachip->base + SA1111_SKPCR); |
| 1164 | sa1111_writel(val | sadev->skpcr_mask, sachip->base + SA1111_SKPCR); | 1164 | sa1111_writel(val | sadev->skpcr_mask, sachip->base + SA1111_SKPCR); |
| 1165 | spin_unlock_irqrestore(&sachip->lock, flags); | 1165 | spin_unlock_irqrestore(&sachip->lock, flags); |
| 1166 | } | 1166 | } |
| 1167 | 1167 | ||
| 1168 | /** | 1168 | /** |
| 1169 | * sa1111_disable_device - disable an on-chip SA1111 function block | 1169 | * sa1111_disable_device - disable an on-chip SA1111 function block |
| 1170 | * @sadev: SA1111 function block device to disable | 1170 | * @sadev: SA1111 function block device to disable |
| 1171 | */ | 1171 | */ |
| 1172 | void sa1111_disable_device(struct sa1111_dev *sadev) | 1172 | void sa1111_disable_device(struct sa1111_dev *sadev) |
| 1173 | { | 1173 | { |
| 1174 | struct sa1111 *sachip = sa1111_chip_driver(sadev); | 1174 | struct sa1111 *sachip = sa1111_chip_driver(sadev); |
| 1175 | unsigned long flags; | 1175 | unsigned long flags; |
| 1176 | unsigned int val; | 1176 | unsigned int val; |
| 1177 | 1177 | ||
| 1178 | spin_lock_irqsave(&sachip->lock, flags); | 1178 | spin_lock_irqsave(&sachip->lock, flags); |
| 1179 | val = sa1111_readl(sachip->base + SA1111_SKPCR); | 1179 | val = sa1111_readl(sachip->base + SA1111_SKPCR); |
| 1180 | sa1111_writel(val & ~sadev->skpcr_mask, sachip->base + SA1111_SKPCR); | 1180 | sa1111_writel(val & ~sadev->skpcr_mask, sachip->base + SA1111_SKPCR); |
| 1181 | spin_unlock_irqrestore(&sachip->lock, flags); | 1181 | spin_unlock_irqrestore(&sachip->lock, flags); |
| 1182 | } | 1182 | } |
| 1183 | 1183 | ||
| 1184 | /* | 1184 | /* |
| 1185 | * SA1111 "Register Access Bus." | 1185 | * SA1111 "Register Access Bus." |
| 1186 | * | 1186 | * |
| 1187 | * We model this as a regular bus type, and hang devices directly | 1187 | * We model this as a regular bus type, and hang devices directly |
| 1188 | * off this. | 1188 | * off this. |
| 1189 | */ | 1189 | */ |
| 1190 | static int sa1111_match(struct device *_dev, struct device_driver *_drv) | 1190 | static int sa1111_match(struct device *_dev, struct device_driver *_drv) |
| 1191 | { | 1191 | { |
| 1192 | struct sa1111_dev *dev = SA1111_DEV(_dev); | 1192 | struct sa1111_dev *dev = SA1111_DEV(_dev); |
| 1193 | struct sa1111_driver *drv = SA1111_DRV(_drv); | 1193 | struct sa1111_driver *drv = SA1111_DRV(_drv); |
| 1194 | 1194 | ||
| 1195 | return dev->devid == drv->devid; | 1195 | return dev->devid == drv->devid; |
| 1196 | } | 1196 | } |
| 1197 | 1197 | ||
| 1198 | static int sa1111_bus_suspend(struct device *dev, pm_message_t state) | 1198 | static int sa1111_bus_suspend(struct device *dev, pm_message_t state) |
| 1199 | { | 1199 | { |
| 1200 | struct sa1111_dev *sadev = SA1111_DEV(dev); | 1200 | struct sa1111_dev *sadev = SA1111_DEV(dev); |
| 1201 | struct sa1111_driver *drv = SA1111_DRV(dev->driver); | 1201 | struct sa1111_driver *drv = SA1111_DRV(dev->driver); |
| 1202 | int ret = 0; | 1202 | int ret = 0; |
| 1203 | 1203 | ||
| 1204 | if (drv && drv->suspend) | 1204 | if (drv && drv->suspend) |
| 1205 | ret = drv->suspend(sadev, state); | 1205 | ret = drv->suspend(sadev, state); |
| 1206 | return ret; | 1206 | return ret; |
| 1207 | } | 1207 | } |
| 1208 | 1208 | ||
| 1209 | static int sa1111_bus_resume(struct device *dev) | 1209 | static int sa1111_bus_resume(struct device *dev) |
| 1210 | { | 1210 | { |
| 1211 | struct sa1111_dev *sadev = SA1111_DEV(dev); | 1211 | struct sa1111_dev *sadev = SA1111_DEV(dev); |
| 1212 | struct sa1111_driver *drv = SA1111_DRV(dev->driver); | 1212 | struct sa1111_driver *drv = SA1111_DRV(dev->driver); |
| 1213 | int ret = 0; | 1213 | int ret = 0; |
| 1214 | 1214 | ||
| 1215 | if (drv && drv->resume) | 1215 | if (drv && drv->resume) |
| 1216 | ret = drv->resume(sadev); | 1216 | ret = drv->resume(sadev); |
| 1217 | return ret; | 1217 | return ret; |
| 1218 | } | 1218 | } |
| 1219 | 1219 | ||
| 1220 | static int sa1111_bus_probe(struct device *dev) | 1220 | static int sa1111_bus_probe(struct device *dev) |
| 1221 | { | 1221 | { |
| 1222 | struct sa1111_dev *sadev = SA1111_DEV(dev); | 1222 | struct sa1111_dev *sadev = SA1111_DEV(dev); |
| 1223 | struct sa1111_driver *drv = SA1111_DRV(dev->driver); | 1223 | struct sa1111_driver *drv = SA1111_DRV(dev->driver); |
| 1224 | int ret = -ENODEV; | 1224 | int ret = -ENODEV; |
| 1225 | 1225 | ||
| 1226 | if (drv->probe) | 1226 | if (drv->probe) |
| 1227 | ret = drv->probe(sadev); | 1227 | ret = drv->probe(sadev); |
| 1228 | return ret; | 1228 | return ret; |
| 1229 | } | 1229 | } |
| 1230 | 1230 | ||
| 1231 | static int sa1111_bus_remove(struct device *dev) | 1231 | static int sa1111_bus_remove(struct device *dev) |
| 1232 | { | 1232 | { |
| 1233 | struct sa1111_dev *sadev = SA1111_DEV(dev); | 1233 | struct sa1111_dev *sadev = SA1111_DEV(dev); |
| 1234 | struct sa1111_driver *drv = SA1111_DRV(dev->driver); | 1234 | struct sa1111_driver *drv = SA1111_DRV(dev->driver); |
| 1235 | int ret = 0; | 1235 | int ret = 0; |
| 1236 | 1236 | ||
| 1237 | if (drv->remove) | 1237 | if (drv->remove) |
| 1238 | ret = drv->remove(sadev); | 1238 | ret = drv->remove(sadev); |
| 1239 | return ret; | 1239 | return ret; |
| 1240 | } | 1240 | } |
| 1241 | 1241 | ||
| 1242 | struct bus_type sa1111_bus_type = { | 1242 | struct bus_type sa1111_bus_type = { |
| 1243 | .name = "sa1111-rab", | 1243 | .name = "sa1111-rab", |
| 1244 | .match = sa1111_match, | 1244 | .match = sa1111_match, |
| 1245 | .suspend = sa1111_bus_suspend, | 1245 | .suspend = sa1111_bus_suspend, |
| 1246 | .resume = sa1111_bus_resume, | 1246 | .resume = sa1111_bus_resume, |
| 1247 | }; | 1247 | }; |
| 1248 | 1248 | ||
| 1249 | int sa1111_driver_register(struct sa1111_driver *driver) | 1249 | int sa1111_driver_register(struct sa1111_driver *driver) |
| 1250 | { | 1250 | { |
| 1251 | driver->drv.probe = sa1111_bus_probe; | 1251 | driver->drv.probe = sa1111_bus_probe; |
| 1252 | driver->drv.remove = sa1111_bus_remove; | 1252 | driver->drv.remove = sa1111_bus_remove; |
| 1253 | driver->drv.bus = &sa1111_bus_type; | 1253 | driver->drv.bus = &sa1111_bus_type; |
| 1254 | return driver_register(&driver->drv); | 1254 | return driver_register(&driver->drv); |
| 1255 | } | 1255 | } |
| 1256 | 1256 | ||
| 1257 | void sa1111_driver_unregister(struct sa1111_driver *driver) | 1257 | void sa1111_driver_unregister(struct sa1111_driver *driver) |
| 1258 | { | 1258 | { |
| 1259 | driver_unregister(&driver->drv); | 1259 | driver_unregister(&driver->drv); |
| 1260 | } | 1260 | } |
| 1261 | 1261 | ||
| 1262 | static int __init sa1111_init(void) | 1262 | static int __init sa1111_init(void) |
| 1263 | { | 1263 | { |
| 1264 | int ret = bus_register(&sa1111_bus_type); | 1264 | int ret = bus_register(&sa1111_bus_type); |
| 1265 | if (ret == 0) | 1265 | if (ret == 0) |
| 1266 | driver_register(&sa1111_device_driver); | 1266 | driver_register(&sa1111_device_driver); |
| 1267 | return ret; | 1267 | return ret; |
| 1268 | } | 1268 | } |
| 1269 | 1269 | ||
| 1270 | static void __exit sa1111_exit(void) | 1270 | static void __exit sa1111_exit(void) |
| 1271 | { | 1271 | { |
| 1272 | driver_unregister(&sa1111_device_driver); | 1272 | driver_unregister(&sa1111_device_driver); |
| 1273 | bus_unregister(&sa1111_bus_type); | 1273 | bus_unregister(&sa1111_bus_type); |
| 1274 | } | 1274 | } |
| 1275 | 1275 | ||
| 1276 | module_init(sa1111_init); | 1276 | module_init(sa1111_init); |
| 1277 | module_exit(sa1111_exit); | 1277 | module_exit(sa1111_exit); |
| 1278 | 1278 | ||
| 1279 | MODULE_DESCRIPTION("Intel Corporation SA1111 core driver"); | 1279 | MODULE_DESCRIPTION("Intel Corporation SA1111 core driver"); |
| 1280 | MODULE_LICENSE("GPL"); | 1280 | MODULE_LICENSE("GPL"); |
| 1281 | 1281 | ||
| 1282 | EXPORT_SYMBOL(sa1111_select_audio_mode); | 1282 | EXPORT_SYMBOL(sa1111_select_audio_mode); |
| 1283 | EXPORT_SYMBOL(sa1111_set_audio_rate); | 1283 | EXPORT_SYMBOL(sa1111_set_audio_rate); |
| 1284 | EXPORT_SYMBOL(sa1111_get_audio_rate); | 1284 | EXPORT_SYMBOL(sa1111_get_audio_rate); |
| 1285 | EXPORT_SYMBOL(sa1111_set_io_dir); | 1285 | EXPORT_SYMBOL(sa1111_set_io_dir); |
| 1286 | EXPORT_SYMBOL(sa1111_set_io); | 1286 | EXPORT_SYMBOL(sa1111_set_io); |
| 1287 | EXPORT_SYMBOL(sa1111_set_sleep_io); | 1287 | EXPORT_SYMBOL(sa1111_set_sleep_io); |
| 1288 | EXPORT_SYMBOL(sa1111_enable_device); | 1288 | EXPORT_SYMBOL(sa1111_enable_device); |
| 1289 | EXPORT_SYMBOL(sa1111_disable_device); | 1289 | EXPORT_SYMBOL(sa1111_disable_device); |
| 1290 | EXPORT_SYMBOL(sa1111_pll_clock); | 1290 | EXPORT_SYMBOL(sa1111_pll_clock); |
| 1291 | EXPORT_SYMBOL(sa1111_bus_type); | 1291 | EXPORT_SYMBOL(sa1111_bus_type); |
| 1292 | EXPORT_SYMBOL(sa1111_driver_register); | 1292 | EXPORT_SYMBOL(sa1111_driver_register); |
| 1293 | EXPORT_SYMBOL(sa1111_driver_unregister); | 1293 | EXPORT_SYMBOL(sa1111_driver_unregister); |
| 1294 | 1294 |
arch/arm/kernel/ecard.c
| 1 | /* | 1 | /* |
| 2 | * linux/arch/arm/kernel/ecard.c | 2 | * linux/arch/arm/kernel/ecard.c |
| 3 | * | 3 | * |
| 4 | * Copyright 1995-2001 Russell King | 4 | * Copyright 1995-2001 Russell King |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
| 8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
| 9 | * | 9 | * |
| 10 | * Find all installed expansion cards, and handle interrupts from them. | 10 | * Find all installed expansion cards, and handle interrupts from them. |
| 11 | * | 11 | * |
| 12 | * Created from information from Acorns RiscOS3 PRMs | 12 | * Created from information from Acorns RiscOS3 PRMs |
| 13 | * | 13 | * |
| 14 | * 08-Dec-1996 RMK Added code for the 9'th expansion card - the ether | 14 | * 08-Dec-1996 RMK Added code for the 9'th expansion card - the ether |
| 15 | * podule slot. | 15 | * podule slot. |
| 16 | * 06-May-1997 RMK Added blacklist for cards whose loader doesn't work. | 16 | * 06-May-1997 RMK Added blacklist for cards whose loader doesn't work. |
| 17 | * 12-Sep-1997 RMK Created new handling of interrupt enables/disables | 17 | * 12-Sep-1997 RMK Created new handling of interrupt enables/disables |
| 18 | * - cards can now register their own routine to control | 18 | * - cards can now register their own routine to control |
| 19 | * interrupts (recommended). | 19 | * interrupts (recommended). |
| 20 | * 29-Sep-1997 RMK Expansion card interrupt hardware not being re-enabled | 20 | * 29-Sep-1997 RMK Expansion card interrupt hardware not being re-enabled |
| 21 | * on reset from Linux. (Caused cards not to respond | 21 | * on reset from Linux. (Caused cards not to respond |
| 22 | * under RiscOS without hard reset). | 22 | * under RiscOS without hard reset). |
| 23 | * 15-Feb-1998 RMK Added DMA support | 23 | * 15-Feb-1998 RMK Added DMA support |
| 24 | * 12-Sep-1998 RMK Added EASI support | 24 | * 12-Sep-1998 RMK Added EASI support |
| 25 | * 10-Jan-1999 RMK Run loaders in a simulated RISC OS environment. | 25 | * 10-Jan-1999 RMK Run loaders in a simulated RISC OS environment. |
| 26 | * 17-Apr-1999 RMK Support for EASI Type C cycles. | 26 | * 17-Apr-1999 RMK Support for EASI Type C cycles. |
| 27 | */ | 27 | */ |
| 28 | #define ECARD_C | 28 | #define ECARD_C |
| 29 | 29 | ||
| 30 | #include <linux/config.h> | 30 | #include <linux/config.h> |
| 31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
| 32 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
| 33 | #include <linux/types.h> | 33 | #include <linux/types.h> |
| 34 | #include <linux/sched.h> | 34 | #include <linux/sched.h> |
| 35 | #include <linux/interrupt.h> | 35 | #include <linux/interrupt.h> |
| 36 | #include <linux/completion.h> | 36 | #include <linux/completion.h> |
| 37 | #include <linux/reboot.h> | 37 | #include <linux/reboot.h> |
| 38 | #include <linux/mm.h> | 38 | #include <linux/mm.h> |
| 39 | #include <linux/slab.h> | 39 | #include <linux/slab.h> |
| 40 | #include <linux/proc_fs.h> | 40 | #include <linux/proc_fs.h> |
| 41 | #include <linux/device.h> | 41 | #include <linux/device.h> |
| 42 | #include <linux/init.h> | 42 | #include <linux/init.h> |
| 43 | 43 | ||
| 44 | #include <asm/dma.h> | 44 | #include <asm/dma.h> |
| 45 | #include <asm/ecard.h> | 45 | #include <asm/ecard.h> |
| 46 | #include <asm/hardware.h> | 46 | #include <asm/hardware.h> |
| 47 | #include <asm/io.h> | 47 | #include <asm/io.h> |
| 48 | #include <asm/irq.h> | 48 | #include <asm/irq.h> |
| 49 | #include <asm/mmu_context.h> | 49 | #include <asm/mmu_context.h> |
| 50 | #include <asm/mach/irq.h> | 50 | #include <asm/mach/irq.h> |
| 51 | #include <asm/tlbflush.h> | 51 | #include <asm/tlbflush.h> |
| 52 | 52 | ||
| 53 | #ifndef CONFIG_ARCH_RPC | 53 | #ifndef CONFIG_ARCH_RPC |
| 54 | #define HAVE_EXPMASK | 54 | #define HAVE_EXPMASK |
| 55 | #endif | 55 | #endif |
| 56 | 56 | ||
| 57 | struct ecard_request { | 57 | struct ecard_request { |
| 58 | void (*fn)(struct ecard_request *); | 58 | void (*fn)(struct ecard_request *); |
| 59 | ecard_t *ec; | 59 | ecard_t *ec; |
| 60 | unsigned int address; | 60 | unsigned int address; |
| 61 | unsigned int length; | 61 | unsigned int length; |
| 62 | unsigned int use_loader; | 62 | unsigned int use_loader; |
| 63 | void *buffer; | 63 | void *buffer; |
| 64 | struct completion *complete; | 64 | struct completion *complete; |
| 65 | }; | 65 | }; |
| 66 | 66 | ||
| 67 | struct expcard_blacklist { | 67 | struct expcard_blacklist { |
| 68 | unsigned short manufacturer; | 68 | unsigned short manufacturer; |
| 69 | unsigned short product; | 69 | unsigned short product; |
| 70 | const char *type; | 70 | const char *type; |
| 71 | }; | 71 | }; |
| 72 | 72 | ||
| 73 | static ecard_t *cards; | 73 | static ecard_t *cards; |
| 74 | static ecard_t *slot_to_expcard[MAX_ECARDS]; | 74 | static ecard_t *slot_to_expcard[MAX_ECARDS]; |
| 75 | static unsigned int ectcr; | 75 | static unsigned int ectcr; |
| 76 | #ifdef HAS_EXPMASK | 76 | #ifdef HAS_EXPMASK |
| 77 | static unsigned int have_expmask; | 77 | static unsigned int have_expmask; |
| 78 | #endif | 78 | #endif |
| 79 | 79 | ||
| 80 | /* List of descriptions of cards which don't have an extended | 80 | /* List of descriptions of cards which don't have an extended |
| 81 | * identification, or chunk directories containing a description. | 81 | * identification, or chunk directories containing a description. |
| 82 | */ | 82 | */ |
| 83 | static struct expcard_blacklist __initdata blacklist[] = { | 83 | static struct expcard_blacklist __initdata blacklist[] = { |
| 84 | { MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1" } | 84 | { MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1" } |
| 85 | }; | 85 | }; |
| 86 | 86 | ||
| 87 | asmlinkage extern int | 87 | asmlinkage extern int |
| 88 | ecard_loader_reset(unsigned long base, loader_t loader); | 88 | ecard_loader_reset(unsigned long base, loader_t loader); |
| 89 | asmlinkage extern int | 89 | asmlinkage extern int |
| 90 | ecard_loader_read(int off, unsigned long base, loader_t loader); | 90 | ecard_loader_read(int off, unsigned long base, loader_t loader); |
| 91 | 91 | ||
| 92 | static inline unsigned short ecard_getu16(unsigned char *v) | 92 | static inline unsigned short ecard_getu16(unsigned char *v) |
| 93 | { | 93 | { |
| 94 | return v[0] | v[1] << 8; | 94 | return v[0] | v[1] << 8; |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | static inline signed long ecard_gets24(unsigned char *v) | 97 | static inline signed long ecard_gets24(unsigned char *v) |
| 98 | { | 98 | { |
| 99 | return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0); | 99 | return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0); |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | static inline ecard_t *slot_to_ecard(unsigned int slot) | 102 | static inline ecard_t *slot_to_ecard(unsigned int slot) |
| 103 | { | 103 | { |
| 104 | return slot < MAX_ECARDS ? slot_to_expcard[slot] : NULL; | 104 | return slot < MAX_ECARDS ? slot_to_expcard[slot] : NULL; |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | /* ===================== Expansion card daemon ======================== */ | 107 | /* ===================== Expansion card daemon ======================== */ |
| 108 | /* | 108 | /* |
| 109 | * Since the loader programs on the expansion cards need to be run | 109 | * Since the loader programs on the expansion cards need to be run |
| 110 | * in a specific environment, create a separate task with this | 110 | * in a specific environment, create a separate task with this |
| 111 | * environment up, and pass requests to this task as and when we | 111 | * environment up, and pass requests to this task as and when we |
| 112 | * need to. | 112 | * need to. |
| 113 | * | 113 | * |
| 114 | * This should allow 99% of loaders to be called from Linux. | 114 | * This should allow 99% of loaders to be called from Linux. |
| 115 | * | 115 | * |
| 116 | * From a security standpoint, we trust the card vendors. This | 116 | * From a security standpoint, we trust the card vendors. This |
| 117 | * may be a misplaced trust. | 117 | * may be a misplaced trust. |
| 118 | */ | 118 | */ |
| 119 | static void ecard_task_reset(struct ecard_request *req) | 119 | static void ecard_task_reset(struct ecard_request *req) |
| 120 | { | 120 | { |
| 121 | struct expansion_card *ec = req->ec; | 121 | struct expansion_card *ec = req->ec; |
| 122 | struct resource *res; | 122 | struct resource *res; |
| 123 | 123 | ||
| 124 | res = ec->slot_no == 8 | 124 | res = ec->slot_no == 8 |
| 125 | ? &ec->resource[ECARD_RES_MEMC] | 125 | ? &ec->resource[ECARD_RES_MEMC] |
| 126 | : ec->type == ECARD_EASI | 126 | : ec->type == ECARD_EASI |
| 127 | ? &ec->resource[ECARD_RES_EASI] | 127 | ? &ec->resource[ECARD_RES_EASI] |
| 128 | : &ec->resource[ECARD_RES_IOCSYNC]; | 128 | : &ec->resource[ECARD_RES_IOCSYNC]; |
| 129 | 129 | ||
| 130 | ecard_loader_reset(res->start, ec->loader); | 130 | ecard_loader_reset(res->start, ec->loader); |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | static void ecard_task_readbytes(struct ecard_request *req) | 133 | static void ecard_task_readbytes(struct ecard_request *req) |
| 134 | { | 134 | { |
| 135 | struct expansion_card *ec = req->ec; | 135 | struct expansion_card *ec = req->ec; |
| 136 | unsigned char *buf = req->buffer; | 136 | unsigned char *buf = req->buffer; |
| 137 | unsigned int len = req->length; | 137 | unsigned int len = req->length; |
| 138 | unsigned int off = req->address; | 138 | unsigned int off = req->address; |
| 139 | 139 | ||
| 140 | if (ec->slot_no == 8) { | 140 | if (ec->slot_no == 8) { |
| 141 | void __iomem *base = (void __iomem *) | 141 | void __iomem *base = (void __iomem *) |
| 142 | ec->resource[ECARD_RES_MEMC].start; | 142 | ec->resource[ECARD_RES_MEMC].start; |
| 143 | 143 | ||
| 144 | /* | 144 | /* |
| 145 | * The card maintains an index which increments the address | 145 | * The card maintains an index which increments the address |
| 146 | * into a 4096-byte page on each access. We need to keep | 146 | * into a 4096-byte page on each access. We need to keep |
| 147 | * track of the counter. | 147 | * track of the counter. |
| 148 | */ | 148 | */ |
| 149 | static unsigned int index; | 149 | static unsigned int index; |
| 150 | unsigned int page; | 150 | unsigned int page; |
| 151 | 151 | ||
| 152 | page = (off >> 12) * 4; | 152 | page = (off >> 12) * 4; |
| 153 | if (page > 256 * 4) | 153 | if (page > 256 * 4) |
| 154 | return; | 154 | return; |
| 155 | 155 | ||
| 156 | off &= 4095; | 156 | off &= 4095; |
| 157 | 157 | ||
| 158 | /* | 158 | /* |
| 159 | * If we are reading offset 0, or our current index is | 159 | * If we are reading offset 0, or our current index is |
| 160 | * greater than the offset, reset the hardware index counter. | 160 | * greater than the offset, reset the hardware index counter. |
| 161 | */ | 161 | */ |
| 162 | if (off == 0 || index > off) { | 162 | if (off == 0 || index > off) { |
| 163 | writeb(0, base); | 163 | writeb(0, base); |
| 164 | index = 0; | 164 | index = 0; |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | /* | 167 | /* |
| 168 | * Increment the hardware index counter until we get to the | 168 | * Increment the hardware index counter until we get to the |
| 169 | * required offset. The read bytes are discarded. | 169 | * required offset. The read bytes are discarded. |
| 170 | */ | 170 | */ |
| 171 | while (index < off) { | 171 | while (index < off) { |
| 172 | readb(base + page); | 172 | readb(base + page); |
| 173 | index += 1; | 173 | index += 1; |
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | while (len--) { | 176 | while (len--) { |
| 177 | *buf++ = readb(base + page); | 177 | *buf++ = readb(base + page); |
| 178 | index += 1; | 178 | index += 1; |
| 179 | } | 179 | } |
| 180 | } else { | 180 | } else { |
| 181 | unsigned long base = (ec->type == ECARD_EASI | 181 | unsigned long base = (ec->type == ECARD_EASI |
| 182 | ? &ec->resource[ECARD_RES_EASI] | 182 | ? &ec->resource[ECARD_RES_EASI] |
| 183 | : &ec->resource[ECARD_RES_IOCSYNC])->start; | 183 | : &ec->resource[ECARD_RES_IOCSYNC])->start; |
| 184 | void __iomem *pbase = (void __iomem *)base; | 184 | void __iomem *pbase = (void __iomem *)base; |
| 185 | 185 | ||
| 186 | if (!req->use_loader || !ec->loader) { | 186 | if (!req->use_loader || !ec->loader) { |
| 187 | off *= 4; | 187 | off *= 4; |
| 188 | while (len--) { | 188 | while (len--) { |
| 189 | *buf++ = readb(pbase + off); | 189 | *buf++ = readb(pbase + off); |
| 190 | off += 4; | 190 | off += 4; |
| 191 | } | 191 | } |
| 192 | } else { | 192 | } else { |
| 193 | while(len--) { | 193 | while(len--) { |
| 194 | /* | 194 | /* |
| 195 | * The following is required by some | 195 | * The following is required by some |
| 196 | * expansion card loader programs. | 196 | * expansion card loader programs. |
| 197 | */ | 197 | */ |
| 198 | *(unsigned long *)0x108 = 0; | 198 | *(unsigned long *)0x108 = 0; |
| 199 | *buf++ = ecard_loader_read(off++, base, | 199 | *buf++ = ecard_loader_read(off++, base, |
| 200 | ec->loader); | 200 | ec->loader); |
| 201 | } | 201 | } |
| 202 | } | 202 | } |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | } | 205 | } |
| 206 | 206 | ||
| 207 | static DECLARE_WAIT_QUEUE_HEAD(ecard_wait); | 207 | static DECLARE_WAIT_QUEUE_HEAD(ecard_wait); |
| 208 | static struct ecard_request *ecard_req; | 208 | static struct ecard_request *ecard_req; |
| 209 | static DECLARE_MUTEX(ecard_sem); | 209 | static DECLARE_MUTEX(ecard_sem); |
| 210 | 210 | ||
| 211 | /* | 211 | /* |
| 212 | * Set up the expansion card daemon's page tables. | 212 | * Set up the expansion card daemon's page tables. |
| 213 | */ | 213 | */ |
| 214 | static void ecard_init_pgtables(struct mm_struct *mm) | 214 | static void ecard_init_pgtables(struct mm_struct *mm) |
| 215 | { | 215 | { |
| 216 | struct vm_area_struct vma; | 216 | struct vm_area_struct vma; |
| 217 | 217 | ||
| 218 | /* We want to set up the page tables for the following mapping: | 218 | /* We want to set up the page tables for the following mapping: |
| 219 | * Virtual Physical | 219 | * Virtual Physical |
| 220 | * 0x03000000 0x03000000 | 220 | * 0x03000000 0x03000000 |
| 221 | * 0x03010000 unmapped | 221 | * 0x03010000 unmapped |
| 222 | * 0x03210000 0x03210000 | 222 | * 0x03210000 0x03210000 |
| 223 | * 0x03400000 unmapped | 223 | * 0x03400000 unmapped |
| 224 | * 0x08000000 0x08000000 | 224 | * 0x08000000 0x08000000 |
| 225 | * 0x10000000 unmapped | 225 | * 0x10000000 unmapped |
| 226 | * | 226 | * |
| 227 | * FIXME: we don't follow this 100% yet. | 227 | * FIXME: we don't follow this 100% yet. |
| 228 | */ | 228 | */ |
| 229 | pgd_t *src_pgd, *dst_pgd; | 229 | pgd_t *src_pgd, *dst_pgd; |
| 230 | 230 | ||
| 231 | src_pgd = pgd_offset(mm, (unsigned long)IO_BASE); | 231 | src_pgd = pgd_offset(mm, (unsigned long)IO_BASE); |
| 232 | dst_pgd = pgd_offset(mm, IO_START); | 232 | dst_pgd = pgd_offset(mm, IO_START); |
| 233 | 233 | ||
| 234 | memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (IO_SIZE / PGDIR_SIZE)); | 234 | memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (IO_SIZE / PGDIR_SIZE)); |
| 235 | 235 | ||
| 236 | src_pgd = pgd_offset(mm, EASI_BASE); | 236 | src_pgd = pgd_offset(mm, EASI_BASE); |
| 237 | dst_pgd = pgd_offset(mm, EASI_START); | 237 | dst_pgd = pgd_offset(mm, EASI_START); |
| 238 | 238 | ||
| 239 | memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (EASI_SIZE / PGDIR_SIZE)); | 239 | memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (EASI_SIZE / PGDIR_SIZE)); |
| 240 | 240 | ||
| 241 | vma.vm_mm = mm; | 241 | vma.vm_mm = mm; |
| 242 | 242 | ||
| 243 | flush_tlb_range(&vma, IO_START, IO_START + IO_SIZE); | 243 | flush_tlb_range(&vma, IO_START, IO_START + IO_SIZE); |
| 244 | flush_tlb_range(&vma, EASI_START, EASI_START + EASI_SIZE); | 244 | flush_tlb_range(&vma, EASI_START, EASI_START + EASI_SIZE); |
| 245 | } | 245 | } |
| 246 | 246 | ||
| 247 | static int ecard_init_mm(void) | 247 | static int ecard_init_mm(void) |
| 248 | { | 248 | { |
| 249 | struct mm_struct * mm = mm_alloc(); | 249 | struct mm_struct * mm = mm_alloc(); |
| 250 | struct mm_struct *active_mm = current->active_mm; | 250 | struct mm_struct *active_mm = current->active_mm; |
| 251 | 251 | ||
| 252 | if (!mm) | 252 | if (!mm) |
| 253 | return -ENOMEM; | 253 | return -ENOMEM; |
| 254 | 254 | ||
| 255 | current->mm = mm; | 255 | current->mm = mm; |
| 256 | current->active_mm = mm; | 256 | current->active_mm = mm; |
| 257 | activate_mm(active_mm, mm); | 257 | activate_mm(active_mm, mm); |
| 258 | mmdrop(active_mm); | 258 | mmdrop(active_mm); |
| 259 | ecard_init_pgtables(mm); | 259 | ecard_init_pgtables(mm); |
| 260 | return 0; | 260 | return 0; |
| 261 | } | 261 | } |
| 262 | 262 | ||
| 263 | static int | 263 | static int |
| 264 | ecard_task(void * unused) | 264 | ecard_task(void * unused) |
| 265 | { | 265 | { |
| 266 | daemonize("kecardd"); | 266 | daemonize("kecardd"); |
| 267 | 267 | ||
| 268 | /* | 268 | /* |
| 269 | * Allocate a mm. We're not a lazy-TLB kernel task since we need | 269 | * Allocate a mm. We're not a lazy-TLB kernel task since we need |
| 270 | * to set page table entries where the user space would be. Note | 270 | * to set page table entries where the user space would be. Note |
| 271 | * that this also creates the page tables. Failure is not an | 271 | * that this also creates the page tables. Failure is not an |
| 272 | * option here. | 272 | * option here. |
| 273 | */ | 273 | */ |
| 274 | if (ecard_init_mm()) | 274 | if (ecard_init_mm()) |
| 275 | panic("kecardd: unable to alloc mm\n"); | 275 | panic("kecardd: unable to alloc mm\n"); |
| 276 | 276 | ||
| 277 | while (1) { | 277 | while (1) { |
| 278 | struct ecard_request *req; | 278 | struct ecard_request *req; |
| 279 | 279 | ||
| 280 | wait_event_interruptible(ecard_wait, ecard_req != NULL); | 280 | wait_event_interruptible(ecard_wait, ecard_req != NULL); |
| 281 | 281 | ||
| 282 | req = xchg(&ecard_req, NULL); | 282 | req = xchg(&ecard_req, NULL); |
| 283 | if (req != NULL) { | 283 | if (req != NULL) { |
| 284 | req->fn(req); | 284 | req->fn(req); |
| 285 | complete(req->complete); | 285 | complete(req->complete); |
| 286 | } | 286 | } |
| 287 | } | 287 | } |
| 288 | } | 288 | } |
| 289 | 289 | ||
| 290 | /* | 290 | /* |
| 291 | * Wake the expansion card daemon to action our request. | 291 | * Wake the expansion card daemon to action our request. |
| 292 | * | 292 | * |
| 293 | * FIXME: The test here is not sufficient to detect if the | 293 | * FIXME: The test here is not sufficient to detect if the |
| 294 | * kcardd is running. | 294 | * kcardd is running. |
| 295 | */ | 295 | */ |
| 296 | static void ecard_call(struct ecard_request *req) | 296 | static void ecard_call(struct ecard_request *req) |
| 297 | { | 297 | { |
| 298 | DECLARE_COMPLETION(completion); | 298 | DECLARE_COMPLETION(completion); |
| 299 | 299 | ||
| 300 | req->complete = &completion; | 300 | req->complete = &completion; |
| 301 | 301 | ||
| 302 | down(&ecard_sem); | 302 | down(&ecard_sem); |
| 303 | ecard_req = req; | 303 | ecard_req = req; |
| 304 | wake_up(&ecard_wait); | 304 | wake_up(&ecard_wait); |
| 305 | 305 | ||
| 306 | /* | 306 | /* |
| 307 | * Now wait for kecardd to run. | 307 | * Now wait for kecardd to run. |
| 308 | */ | 308 | */ |
| 309 | wait_for_completion(&completion); | 309 | wait_for_completion(&completion); |
| 310 | up(&ecard_sem); | 310 | up(&ecard_sem); |
| 311 | } | 311 | } |
| 312 | 312 | ||
| 313 | /* ======================= Mid-level card control ===================== */ | 313 | /* ======================= Mid-level card control ===================== */ |
| 314 | 314 | ||
| 315 | static void | 315 | static void |
| 316 | ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld) | 316 | ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld) |
| 317 | { | 317 | { |
| 318 | struct ecard_request req; | 318 | struct ecard_request req; |
| 319 | 319 | ||
| 320 | req.fn = ecard_task_readbytes; | 320 | req.fn = ecard_task_readbytes; |
| 321 | req.ec = ec; | 321 | req.ec = ec; |
| 322 | req.address = off; | 322 | req.address = off; |
| 323 | req.length = len; | 323 | req.length = len; |
| 324 | req.use_loader = useld; | 324 | req.use_loader = useld; |
| 325 | req.buffer = addr; | 325 | req.buffer = addr; |
| 326 | 326 | ||
| 327 | ecard_call(&req); | 327 | ecard_call(&req); |
| 328 | } | 328 | } |
| 329 | 329 | ||
| 330 | int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num) | 330 | int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num) |
| 331 | { | 331 | { |
| 332 | struct ex_chunk_dir excd; | 332 | struct ex_chunk_dir excd; |
| 333 | int index = 16; | 333 | int index = 16; |
| 334 | int useld = 0; | 334 | int useld = 0; |
| 335 | 335 | ||
| 336 | if (!ec->cid.cd) | 336 | if (!ec->cid.cd) |
| 337 | return 0; | 337 | return 0; |
| 338 | 338 | ||
| 339 | while(1) { | 339 | while(1) { |
| 340 | ecard_readbytes(&excd, ec, index, 8, useld); | 340 | ecard_readbytes(&excd, ec, index, 8, useld); |
| 341 | index += 8; | 341 | index += 8; |
| 342 | if (c_id(&excd) == 0) { | 342 | if (c_id(&excd) == 0) { |
| 343 | if (!useld && ec->loader) { | 343 | if (!useld && ec->loader) { |
| 344 | useld = 1; | 344 | useld = 1; |
| 345 | index = 0; | 345 | index = 0; |
| 346 | continue; | 346 | continue; |
| 347 | } | 347 | } |
| 348 | return 0; | 348 | return 0; |
| 349 | } | 349 | } |
| 350 | if (c_id(&excd) == 0xf0) { /* link */ | 350 | if (c_id(&excd) == 0xf0) { /* link */ |
| 351 | index = c_start(&excd); | 351 | index = c_start(&excd); |
| 352 | continue; | 352 | continue; |
| 353 | } | 353 | } |
| 354 | if (c_id(&excd) == 0x80) { /* loader */ | 354 | if (c_id(&excd) == 0x80) { /* loader */ |
| 355 | if (!ec->loader) { | 355 | if (!ec->loader) { |
| 356 | ec->loader = (loader_t)kmalloc(c_len(&excd), | 356 | ec->loader = (loader_t)kmalloc(c_len(&excd), |
| 357 | GFP_KERNEL); | 357 | GFP_KERNEL); |
| 358 | if (ec->loader) | 358 | if (ec->loader) |
| 359 | ecard_readbytes(ec->loader, ec, | 359 | ecard_readbytes(ec->loader, ec, |
| 360 | (int)c_start(&excd), | 360 | (int)c_start(&excd), |
| 361 | c_len(&excd), useld); | 361 | c_len(&excd), useld); |
| 362 | else | 362 | else |
| 363 | return 0; | 363 | return 0; |
| 364 | } | 364 | } |
| 365 | continue; | 365 | continue; |
| 366 | } | 366 | } |
| 367 | if (c_id(&excd) == id && num-- == 0) | 367 | if (c_id(&excd) == id && num-- == 0) |
| 368 | break; | 368 | break; |
| 369 | } | 369 | } |
| 370 | 370 | ||
| 371 | if (c_id(&excd) & 0x80) { | 371 | if (c_id(&excd) & 0x80) { |
| 372 | switch (c_id(&excd) & 0x70) { | 372 | switch (c_id(&excd) & 0x70) { |
| 373 | case 0x70: | 373 | case 0x70: |
| 374 | ecard_readbytes((unsigned char *)excd.d.string, ec, | 374 | ecard_readbytes((unsigned char *)excd.d.string, ec, |
| 375 | (int)c_start(&excd), c_len(&excd), | 375 | (int)c_start(&excd), c_len(&excd), |
| 376 | useld); | 376 | useld); |
| 377 | break; | 377 | break; |
| 378 | case 0x00: | 378 | case 0x00: |
| 379 | break; | 379 | break; |
| 380 | } | 380 | } |
| 381 | } | 381 | } |
| 382 | cd->start_offset = c_start(&excd); | 382 | cd->start_offset = c_start(&excd); |
| 383 | memcpy(cd->d.string, excd.d.string, 256); | 383 | memcpy(cd->d.string, excd.d.string, 256); |
| 384 | return 1; | 384 | return 1; |
| 385 | } | 385 | } |
| 386 | 386 | ||
| 387 | /* ======================= Interrupt control ============================ */ | 387 | /* ======================= Interrupt control ============================ */ |
| 388 | 388 | ||
| 389 | static void ecard_def_irq_enable(ecard_t *ec, int irqnr) | 389 | static void ecard_def_irq_enable(ecard_t *ec, int irqnr) |
| 390 | { | 390 | { |
| 391 | #ifdef HAS_EXPMASK | 391 | #ifdef HAS_EXPMASK |
| 392 | if (irqnr < 4 && have_expmask) { | 392 | if (irqnr < 4 && have_expmask) { |
| 393 | have_expmask |= 1 << irqnr; | 393 | have_expmask |= 1 << irqnr; |
| 394 | __raw_writeb(have_expmask, EXPMASK_ENABLE); | 394 | __raw_writeb(have_expmask, EXPMASK_ENABLE); |
| 395 | } | 395 | } |
| 396 | #endif | 396 | #endif |
| 397 | } | 397 | } |
| 398 | 398 | ||
| 399 | static void ecard_def_irq_disable(ecard_t *ec, int irqnr) | 399 | static void ecard_def_irq_disable(ecard_t *ec, int irqnr) |
| 400 | { | 400 | { |
| 401 | #ifdef HAS_EXPMASK | 401 | #ifdef HAS_EXPMASK |
| 402 | if (irqnr < 4 && have_expmask) { | 402 | if (irqnr < 4 && have_expmask) { |
| 403 | have_expmask &= ~(1 << irqnr); | 403 | have_expmask &= ~(1 << irqnr); |
| 404 | __raw_writeb(have_expmask, EXPMASK_ENABLE); | 404 | __raw_writeb(have_expmask, EXPMASK_ENABLE); |
| 405 | } | 405 | } |
| 406 | #endif | 406 | #endif |
| 407 | } | 407 | } |
| 408 | 408 | ||
| 409 | static int ecard_def_irq_pending(ecard_t *ec) | 409 | static int ecard_def_irq_pending(ecard_t *ec) |
| 410 | { | 410 | { |
| 411 | return !ec->irqmask || readb(ec->irqaddr) & ec->irqmask; | 411 | return !ec->irqmask || readb(ec->irqaddr) & ec->irqmask; |
| 412 | } | 412 | } |
| 413 | 413 | ||
| 414 | static void ecard_def_fiq_enable(ecard_t *ec, int fiqnr) | 414 | static void ecard_def_fiq_enable(ecard_t *ec, int fiqnr) |
| 415 | { | 415 | { |
| 416 | panic("ecard_def_fiq_enable called - impossible"); | 416 | panic("ecard_def_fiq_enable called - impossible"); |
| 417 | } | 417 | } |
| 418 | 418 | ||
| 419 | static void ecard_def_fiq_disable(ecard_t *ec, int fiqnr) | 419 | static void ecard_def_fiq_disable(ecard_t *ec, int fiqnr) |
| 420 | { | 420 | { |
| 421 | panic("ecard_def_fiq_disable called - impossible"); | 421 | panic("ecard_def_fiq_disable called - impossible"); |
| 422 | } | 422 | } |
| 423 | 423 | ||
| 424 | static int ecard_def_fiq_pending(ecard_t *ec) | 424 | static int ecard_def_fiq_pending(ecard_t *ec) |
| 425 | { | 425 | { |
| 426 | return !ec->fiqmask || readb(ec->fiqaddr) & ec->fiqmask; | 426 | return !ec->fiqmask || readb(ec->fiqaddr) & ec->fiqmask; |
| 427 | } | 427 | } |
| 428 | 428 | ||
| 429 | static expansioncard_ops_t ecard_default_ops = { | 429 | static expansioncard_ops_t ecard_default_ops = { |
| 430 | ecard_def_irq_enable, | 430 | ecard_def_irq_enable, |
| 431 | ecard_def_irq_disable, | 431 | ecard_def_irq_disable, |
| 432 | ecard_def_irq_pending, | 432 | ecard_def_irq_pending, |
| 433 | ecard_def_fiq_enable, | 433 | ecard_def_fiq_enable, |
| 434 | ecard_def_fiq_disable, | 434 | ecard_def_fiq_disable, |
| 435 | ecard_def_fiq_pending | 435 | ecard_def_fiq_pending |
| 436 | }; | 436 | }; |
| 437 | 437 | ||
| 438 | /* | 438 | /* |
| 439 | * Enable and disable interrupts from expansion cards. | 439 | * Enable and disable interrupts from expansion cards. |
| 440 | * (interrupts are disabled for these functions). | 440 | * (interrupts are disabled for these functions). |
| 441 | * | 441 | * |
| 442 | * They are not meant to be called directly, but via enable/disable_irq. | 442 | * They are not meant to be called directly, but via enable/disable_irq. |
| 443 | */ | 443 | */ |
| 444 | static void ecard_irq_unmask(unsigned int irqnr) | 444 | static void ecard_irq_unmask(unsigned int irqnr) |
| 445 | { | 445 | { |
| 446 | ecard_t *ec = slot_to_ecard(irqnr - 32); | 446 | ecard_t *ec = slot_to_ecard(irqnr - 32); |
| 447 | 447 | ||
| 448 | if (ec) { | 448 | if (ec) { |
| 449 | if (!ec->ops) | 449 | if (!ec->ops) |
| 450 | ec->ops = &ecard_default_ops; | 450 | ec->ops = &ecard_default_ops; |
| 451 | 451 | ||
| 452 | if (ec->claimed && ec->ops->irqenable) | 452 | if (ec->claimed && ec->ops->irqenable) |
| 453 | ec->ops->irqenable(ec, irqnr); | 453 | ec->ops->irqenable(ec, irqnr); |
| 454 | else | 454 | else |
| 455 | printk(KERN_ERR "ecard: rejecting request to " | 455 | printk(KERN_ERR "ecard: rejecting request to " |
| 456 | "enable IRQs for %d\n", irqnr); | 456 | "enable IRQs for %d\n", irqnr); |
| 457 | } | 457 | } |
| 458 | } | 458 | } |
| 459 | 459 | ||
| 460 | static void ecard_irq_mask(unsigned int irqnr) | 460 | static void ecard_irq_mask(unsigned int irqnr) |
| 461 | { | 461 | { |
| 462 | ecard_t *ec = slot_to_ecard(irqnr - 32); | 462 | ecard_t *ec = slot_to_ecard(irqnr - 32); |
| 463 | 463 | ||
| 464 | if (ec) { | 464 | if (ec) { |
| 465 | if (!ec->ops) | 465 | if (!ec->ops) |
| 466 | ec->ops = &ecard_default_ops; | 466 | ec->ops = &ecard_default_ops; |
| 467 | 467 | ||
| 468 | if (ec->ops && ec->ops->irqdisable) | 468 | if (ec->ops && ec->ops->irqdisable) |
| 469 | ec->ops->irqdisable(ec, irqnr); | 469 | ec->ops->irqdisable(ec, irqnr); |
| 470 | } | 470 | } |
| 471 | } | 471 | } |
| 472 | 472 | ||
| 473 | static struct irqchip ecard_chip = { | 473 | static struct irqchip ecard_chip = { |
| 474 | .ack = ecard_irq_mask, | 474 | .ack = ecard_irq_mask, |
| 475 | .mask = ecard_irq_mask, | 475 | .mask = ecard_irq_mask, |
| 476 | .unmask = ecard_irq_unmask, | 476 | .unmask = ecard_irq_unmask, |
| 477 | }; | 477 | }; |
| 478 | 478 | ||
| 479 | void ecard_enablefiq(unsigned int fiqnr) | 479 | void ecard_enablefiq(unsigned int fiqnr) |
| 480 | { | 480 | { |
| 481 | ecard_t *ec = slot_to_ecard(fiqnr); | 481 | ecard_t *ec = slot_to_ecard(fiqnr); |
| 482 | 482 | ||
| 483 | if (ec) { | 483 | if (ec) { |
| 484 | if (!ec->ops) | 484 | if (!ec->ops) |
| 485 | ec->ops = &ecard_default_ops; | 485 | ec->ops = &ecard_default_ops; |
| 486 | 486 | ||
| 487 | if (ec->claimed && ec->ops->fiqenable) | 487 | if (ec->claimed && ec->ops->fiqenable) |
| 488 | ec->ops->fiqenable(ec, fiqnr); | 488 | ec->ops->fiqenable(ec, fiqnr); |
| 489 | else | 489 | else |
| 490 | printk(KERN_ERR "ecard: rejecting request to " | 490 | printk(KERN_ERR "ecard: rejecting request to " |
| 491 | "enable FIQs for %d\n", fiqnr); | 491 | "enable FIQs for %d\n", fiqnr); |
| 492 | } | 492 | } |
| 493 | } | 493 | } |
| 494 | 494 | ||
| 495 | void ecard_disablefiq(unsigned int fiqnr) | 495 | void ecard_disablefiq(unsigned int fiqnr) |
| 496 | { | 496 | { |
| 497 | ecard_t *ec = slot_to_ecard(fiqnr); | 497 | ecard_t *ec = slot_to_ecard(fiqnr); |
| 498 | 498 | ||
| 499 | if (ec) { | 499 | if (ec) { |
| 500 | if (!ec->ops) | 500 | if (!ec->ops) |
| 501 | ec->ops = &ecard_default_ops; | 501 | ec->ops = &ecard_default_ops; |
| 502 | 502 | ||
| 503 | if (ec->ops->fiqdisable) | 503 | if (ec->ops->fiqdisable) |
| 504 | ec->ops->fiqdisable(ec, fiqnr); | 504 | ec->ops->fiqdisable(ec, fiqnr); |
| 505 | } | 505 | } |
| 506 | } | 506 | } |
| 507 | 507 | ||
| 508 | static void ecard_dump_irq_state(void) | 508 | static void ecard_dump_irq_state(void) |
| 509 | { | 509 | { |
| 510 | ecard_t *ec; | 510 | ecard_t *ec; |
| 511 | 511 | ||
| 512 | printk("Expansion card IRQ state:\n"); | 512 | printk("Expansion card IRQ state:\n"); |
| 513 | 513 | ||
| 514 | for (ec = cards; ec; ec = ec->next) { | 514 | for (ec = cards; ec; ec = ec->next) { |
| 515 | if (ec->slot_no == 8) | 515 | if (ec->slot_no == 8) |
| 516 | continue; | 516 | continue; |
| 517 | 517 | ||
| 518 | printk(" %d: %sclaimed, ", | 518 | printk(" %d: %sclaimed, ", |
| 519 | ec->slot_no, ec->claimed ? "" : "not "); | 519 | ec->slot_no, ec->claimed ? "" : "not "); |
| 520 | 520 | ||
| 521 | if (ec->ops && ec->ops->irqpending && | 521 | if (ec->ops && ec->ops->irqpending && |
| 522 | ec->ops != &ecard_default_ops) | 522 | ec->ops != &ecard_default_ops) |
| 523 | printk("irq %spending\n", | 523 | printk("irq %spending\n", |
| 524 | ec->ops->irqpending(ec) ? "" : "not "); | 524 | ec->ops->irqpending(ec) ? "" : "not "); |
| 525 | else | 525 | else |
| 526 | printk("irqaddr %p, mask = %02X, status = %02X\n", | 526 | printk("irqaddr %p, mask = %02X, status = %02X\n", |
| 527 | ec->irqaddr, ec->irqmask, readb(ec->irqaddr)); | 527 | ec->irqaddr, ec->irqmask, readb(ec->irqaddr)); |
| 528 | } | 528 | } |
| 529 | } | 529 | } |
| 530 | 530 | ||
| 531 | static void ecard_check_lockup(struct irqdesc *desc) | 531 | static void ecard_check_lockup(struct irqdesc *desc) |
| 532 | { | 532 | { |
| 533 | static unsigned long last; | 533 | static unsigned long last; |
| 534 | static int lockup; | 534 | static int lockup; |
| 535 | 535 | ||
| 536 | /* | 536 | /* |
| 537 | * If the timer interrupt has not run since the last million | 537 | * If the timer interrupt has not run since the last million |
| 538 | * unrecognised expansion card interrupts, then there is | 538 | * unrecognised expansion card interrupts, then there is |
| 539 | * something seriously wrong. Disable the expansion card | 539 | * something seriously wrong. Disable the expansion card |
| 540 | * interrupts so at least we can continue. | 540 | * interrupts so at least we can continue. |
| 541 | * | 541 | * |
| 542 | * Maybe we ought to start a timer to re-enable them some time | 542 | * Maybe we ought to start a timer to re-enable them some time |
| 543 | * later? | 543 | * later? |
| 544 | */ | 544 | */ |
| 545 | if (last == jiffies) { | 545 | if (last == jiffies) { |
| 546 | lockup += 1; | 546 | lockup += 1; |
| 547 | if (lockup > 1000000) { | 547 | if (lockup > 1000000) { |
| 548 | printk(KERN_ERR "\nInterrupt lockup detected - " | 548 | printk(KERN_ERR "\nInterrupt lockup detected - " |
| 549 | "disabling all expansion card interrupts\n"); | 549 | "disabling all expansion card interrupts\n"); |
| 550 | 550 | ||
| 551 | desc->chip->mask(IRQ_EXPANSIONCARD); | 551 | desc->chip->mask(IRQ_EXPANSIONCARD); |
| 552 | ecard_dump_irq_state(); | 552 | ecard_dump_irq_state(); |
| 553 | } | 553 | } |
| 554 | } else | 554 | } else |
| 555 | lockup = 0; | 555 | lockup = 0; |
| 556 | 556 | ||
| 557 | /* | 557 | /* |
| 558 | * If we did not recognise the source of this interrupt, | 558 | * If we did not recognise the source of this interrupt, |
| 559 | * warn the user, but don't flood the user with these messages. | 559 | * warn the user, but don't flood the user with these messages. |
| 560 | */ | 560 | */ |
| 561 | if (!last || time_after(jiffies, last + 5*HZ)) { | 561 | if (!last || time_after(jiffies, last + 5*HZ)) { |
| 562 | last = jiffies; | 562 | last = jiffies; |
| 563 | printk(KERN_WARNING "Unrecognised interrupt from backplane\n"); | 563 | printk(KERN_WARNING "Unrecognised interrupt from backplane\n"); |
| 564 | ecard_dump_irq_state(); | 564 | ecard_dump_irq_state(); |
| 565 | } | 565 | } |
| 566 | } | 566 | } |
| 567 | 567 | ||
| 568 | static void | 568 | static void |
| 569 | ecard_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) | 569 | ecard_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) |
| 570 | { | 570 | { |
| 571 | ecard_t *ec; | 571 | ecard_t *ec; |
| 572 | int called = 0; | 572 | int called = 0; |
| 573 | 573 | ||
| 574 | desc->chip->mask(irq); | 574 | desc->chip->mask(irq); |
| 575 | for (ec = cards; ec; ec = ec->next) { | 575 | for (ec = cards; ec; ec = ec->next) { |
| 576 | int pending; | 576 | int pending; |
| 577 | 577 | ||
| 578 | if (!ec->claimed || ec->irq == NO_IRQ || ec->slot_no == 8) | 578 | if (!ec->claimed || ec->irq == NO_IRQ || ec->slot_no == 8) |
| 579 | continue; | 579 | continue; |
| 580 | 580 | ||
| 581 | if (ec->ops && ec->ops->irqpending) | 581 | if (ec->ops && ec->ops->irqpending) |
| 582 | pending = ec->ops->irqpending(ec); | 582 | pending = ec->ops->irqpending(ec); |
| 583 | else | 583 | else |
| 584 | pending = ecard_default_ops.irqpending(ec); | 584 | pending = ecard_default_ops.irqpending(ec); |
| 585 | 585 | ||
| 586 | if (pending) { | 586 | if (pending) { |
| 587 | struct irqdesc *d = irq_desc + ec->irq; | 587 | struct irqdesc *d = irq_desc + ec->irq; |
| 588 | d->handle(ec->irq, d, regs); | 588 | desc_handle_irq(ec->irq, d, regs); |
| 589 | called ++; | 589 | called ++; |
| 590 | } | 590 | } |
| 591 | } | 591 | } |
| 592 | desc->chip->unmask(irq); | 592 | desc->chip->unmask(irq); |
| 593 | 593 | ||
| 594 | if (called == 0) | 594 | if (called == 0) |
| 595 | ecard_check_lockup(desc); | 595 | ecard_check_lockup(desc); |
| 596 | } | 596 | } |
| 597 | 597 | ||
| 598 | #ifdef HAS_EXPMASK | 598 | #ifdef HAS_EXPMASK |
| 599 | static unsigned char priority_masks[] = | 599 | static unsigned char priority_masks[] = |
| 600 | { | 600 | { |
| 601 | 0xf0, 0xf1, 0xf3, 0xf7, 0xff, 0xff, 0xff, 0xff | 601 | 0xf0, 0xf1, 0xf3, 0xf7, 0xff, 0xff, 0xff, 0xff |
| 602 | }; | 602 | }; |
| 603 | 603 | ||
| 604 | static unsigned char first_set[] = | 604 | static unsigned char first_set[] = |
| 605 | { | 605 | { |
| 606 | 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, | 606 | 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, |
| 607 | 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00 | 607 | 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00 |
| 608 | }; | 608 | }; |
| 609 | 609 | ||
| 610 | static void | 610 | static void |
| 611 | ecard_irqexp_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) | 611 | ecard_irqexp_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) |
| 612 | { | 612 | { |
| 613 | const unsigned int statusmask = 15; | 613 | const unsigned int statusmask = 15; |
| 614 | unsigned int status; | 614 | unsigned int status; |
| 615 | 615 | ||
| 616 | status = __raw_readb(EXPMASK_STATUS) & statusmask; | 616 | status = __raw_readb(EXPMASK_STATUS) & statusmask; |
| 617 | if (status) { | 617 | if (status) { |
| 618 | unsigned int slot = first_set[status]; | 618 | unsigned int slot = first_set[status]; |
| 619 | ecard_t *ec = slot_to_ecard(slot); | 619 | ecard_t *ec = slot_to_ecard(slot); |
| 620 | 620 | ||
| 621 | if (ec->claimed) { | 621 | if (ec->claimed) { |
| 622 | struct irqdesc *d = irqdesc + ec->irq; | 622 | struct irqdesc *d = irqdesc + ec->irq; |
| 623 | /* | 623 | /* |
| 624 | * this ugly code is so that we can operate a | 624 | * this ugly code is so that we can operate a |
| 625 | * prioritorising system: | 625 | * prioritorising system: |
| 626 | * | 626 | * |
| 627 | * Card 0 highest priority | 627 | * Card 0 highest priority |
| 628 | * Card 1 | 628 | * Card 1 |
| 629 | * Card 2 | 629 | * Card 2 |
| 630 | * Card 3 lowest priority | 630 | * Card 3 lowest priority |
| 631 | * | 631 | * |
| 632 | * Serial cards should go in 0/1, ethernet/scsi in 2/3 | 632 | * Serial cards should go in 0/1, ethernet/scsi in 2/3 |
| 633 | * otherwise you will lose serial data at high speeds! | 633 | * otherwise you will lose serial data at high speeds! |
| 634 | */ | 634 | */ |
| 635 | d->handle(ec->irq, d, regs); | 635 | desc_handle_irq(ec->irq, d, regs); |
| 636 | } else { | 636 | } else { |
| 637 | printk(KERN_WARNING "card%d: interrupt from unclaimed " | 637 | printk(KERN_WARNING "card%d: interrupt from unclaimed " |
| 638 | "card???\n", slot); | 638 | "card???\n", slot); |
| 639 | have_expmask &= ~(1 << slot); | 639 | have_expmask &= ~(1 << slot); |
| 640 | __raw_writeb(have_expmask, EXPMASK_ENABLE); | 640 | __raw_writeb(have_expmask, EXPMASK_ENABLE); |
| 641 | } | 641 | } |
| 642 | } else | 642 | } else |
| 643 | printk(KERN_WARNING "Wild interrupt from backplane (masks)\n"); | 643 | printk(KERN_WARNING "Wild interrupt from backplane (masks)\n"); |
| 644 | } | 644 | } |
| 645 | 645 | ||
| 646 | static int __init ecard_probeirqhw(void) | 646 | static int __init ecard_probeirqhw(void) |
| 647 | { | 647 | { |
| 648 | ecard_t *ec; | 648 | ecard_t *ec; |
| 649 | int found; | 649 | int found; |
| 650 | 650 | ||
| 651 | __raw_writeb(0x00, EXPMASK_ENABLE); | 651 | __raw_writeb(0x00, EXPMASK_ENABLE); |
| 652 | __raw_writeb(0xff, EXPMASK_STATUS); | 652 | __raw_writeb(0xff, EXPMASK_STATUS); |
| 653 | found = (__raw_readb(EXPMASK_STATUS) & 15) == 0; | 653 | found = (__raw_readb(EXPMASK_STATUS) & 15) == 0; |
| 654 | __raw_writeb(0xff, EXPMASK_ENABLE); | 654 | __raw_writeb(0xff, EXPMASK_ENABLE); |
| 655 | 655 | ||
| 656 | if (found) { | 656 | if (found) { |
| 657 | printk(KERN_DEBUG "Expansion card interrupt " | 657 | printk(KERN_DEBUG "Expansion card interrupt " |
| 658 | "management hardware found\n"); | 658 | "management hardware found\n"); |
| 659 | 659 | ||
| 660 | /* for each card present, set a bit to '1' */ | 660 | /* for each card present, set a bit to '1' */ |
| 661 | have_expmask = 0x80000000; | 661 | have_expmask = 0x80000000; |
| 662 | 662 | ||
| 663 | for (ec = cards; ec; ec = ec->next) | 663 | for (ec = cards; ec; ec = ec->next) |
| 664 | have_expmask |= 1 << ec->slot_no; | 664 | have_expmask |= 1 << ec->slot_no; |
| 665 | 665 | ||
| 666 | __raw_writeb(have_expmask, EXPMASK_ENABLE); | 666 | __raw_writeb(have_expmask, EXPMASK_ENABLE); |
| 667 | } | 667 | } |
| 668 | 668 | ||
| 669 | return found; | 669 | return found; |
| 670 | } | 670 | } |
| 671 | #else | 671 | #else |
| 672 | #define ecard_irqexp_handler NULL | 672 | #define ecard_irqexp_handler NULL |
| 673 | #define ecard_probeirqhw() (0) | 673 | #define ecard_probeirqhw() (0) |
| 674 | #endif | 674 | #endif |
| 675 | 675 | ||
| 676 | #ifndef IO_EC_MEMC8_BASE | 676 | #ifndef IO_EC_MEMC8_BASE |
| 677 | #define IO_EC_MEMC8_BASE 0 | 677 | #define IO_EC_MEMC8_BASE 0 |
| 678 | #endif | 678 | #endif |
| 679 | 679 | ||
| 680 | unsigned int __ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed) | 680 | unsigned int __ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed) |
| 681 | { | 681 | { |
| 682 | unsigned long address = 0; | 682 | unsigned long address = 0; |
| 683 | int slot = ec->slot_no; | 683 | int slot = ec->slot_no; |
| 684 | 684 | ||
| 685 | if (ec->slot_no == 8) | 685 | if (ec->slot_no == 8) |
| 686 | return IO_EC_MEMC8_BASE; | 686 | return IO_EC_MEMC8_BASE; |
| 687 | 687 | ||
| 688 | ectcr &= ~(1 << slot); | 688 | ectcr &= ~(1 << slot); |
| 689 | 689 | ||
| 690 | switch (type) { | 690 | switch (type) { |
| 691 | case ECARD_MEMC: | 691 | case ECARD_MEMC: |
| 692 | if (slot < 4) | 692 | if (slot < 4) |
| 693 | address = IO_EC_MEMC_BASE + (slot << 12); | 693 | address = IO_EC_MEMC_BASE + (slot << 12); |
| 694 | break; | 694 | break; |
| 695 | 695 | ||
| 696 | case ECARD_IOC: | 696 | case ECARD_IOC: |
| 697 | if (slot < 4) | 697 | if (slot < 4) |
| 698 | address = IO_EC_IOC_BASE + (slot << 12); | 698 | address = IO_EC_IOC_BASE + (slot << 12); |
| 699 | #ifdef IO_EC_IOC4_BASE | 699 | #ifdef IO_EC_IOC4_BASE |
| 700 | else | 700 | else |
| 701 | address = IO_EC_IOC4_BASE + ((slot - 4) << 12); | 701 | address = IO_EC_IOC4_BASE + ((slot - 4) << 12); |
| 702 | #endif | 702 | #endif |
| 703 | if (address) | 703 | if (address) |
| 704 | address += speed << 17; | 704 | address += speed << 17; |
| 705 | break; | 705 | break; |
| 706 | 706 | ||
| 707 | #ifdef IO_EC_EASI_BASE | 707 | #ifdef IO_EC_EASI_BASE |
| 708 | case ECARD_EASI: | 708 | case ECARD_EASI: |
| 709 | address = IO_EC_EASI_BASE + (slot << 22); | 709 | address = IO_EC_EASI_BASE + (slot << 22); |
| 710 | if (speed == ECARD_FAST) | 710 | if (speed == ECARD_FAST) |
| 711 | ectcr |= 1 << slot; | 711 | ectcr |= 1 << slot; |
| 712 | break; | 712 | break; |
| 713 | #endif | 713 | #endif |
| 714 | default: | 714 | default: |
| 715 | break; | 715 | break; |
| 716 | } | 716 | } |
| 717 | 717 | ||
| 718 | #ifdef IOMD_ECTCR | 718 | #ifdef IOMD_ECTCR |
| 719 | iomd_writeb(ectcr, IOMD_ECTCR); | 719 | iomd_writeb(ectcr, IOMD_ECTCR); |
| 720 | #endif | 720 | #endif |
| 721 | return address; | 721 | return address; |
| 722 | } | 722 | } |
| 723 | 723 | ||
| 724 | static int ecard_prints(char *buffer, ecard_t *ec) | 724 | static int ecard_prints(char *buffer, ecard_t *ec) |
| 725 | { | 725 | { |
| 726 | char *start = buffer; | 726 | char *start = buffer; |
| 727 | 727 | ||
| 728 | buffer += sprintf(buffer, " %d: %s ", ec->slot_no, | 728 | buffer += sprintf(buffer, " %d: %s ", ec->slot_no, |
| 729 | ec->type == ECARD_EASI ? "EASI" : " "); | 729 | ec->type == ECARD_EASI ? "EASI" : " "); |
| 730 | 730 | ||
| 731 | if (ec->cid.id == 0) { | 731 | if (ec->cid.id == 0) { |
| 732 | struct in_chunk_dir incd; | 732 | struct in_chunk_dir incd; |
| 733 | 733 | ||
| 734 | buffer += sprintf(buffer, "[%04X:%04X] ", | 734 | buffer += sprintf(buffer, "[%04X:%04X] ", |
| 735 | ec->cid.manufacturer, ec->cid.product); | 735 | ec->cid.manufacturer, ec->cid.product); |
| 736 | 736 | ||
| 737 | if (!ec->card_desc && ec->cid.cd && | 737 | if (!ec->card_desc && ec->cid.cd && |
| 738 | ecard_readchunk(&incd, ec, 0xf5, 0)) { | 738 | ecard_readchunk(&incd, ec, 0xf5, 0)) { |
| 739 | ec->card_desc = kmalloc(strlen(incd.d.string)+1, GFP_KERNEL); | 739 | ec->card_desc = kmalloc(strlen(incd.d.string)+1, GFP_KERNEL); |
| 740 | 740 | ||
| 741 | if (ec->card_desc) | 741 | if (ec->card_desc) |
| 742 | strcpy((char *)ec->card_desc, incd.d.string); | 742 | strcpy((char *)ec->card_desc, incd.d.string); |
| 743 | } | 743 | } |
| 744 | 744 | ||
| 745 | buffer += sprintf(buffer, "%s\n", ec->card_desc ? ec->card_desc : "*unknown*"); | 745 | buffer += sprintf(buffer, "%s\n", ec->card_desc ? ec->card_desc : "*unknown*"); |
| 746 | } else | 746 | } else |
| 747 | buffer += sprintf(buffer, "Simple card %d\n", ec->cid.id); | 747 | buffer += sprintf(buffer, "Simple card %d\n", ec->cid.id); |
| 748 | 748 | ||
| 749 | return buffer - start; | 749 | return buffer - start; |
| 750 | } | 750 | } |
| 751 | 751 | ||
| 752 | static int get_ecard_dev_info(char *buf, char **start, off_t pos, int count) | 752 | static int get_ecard_dev_info(char *buf, char **start, off_t pos, int count) |
| 753 | { | 753 | { |
| 754 | ecard_t *ec = cards; | 754 | ecard_t *ec = cards; |
| 755 | off_t at = 0; | 755 | off_t at = 0; |
| 756 | int len, cnt; | 756 | int len, cnt; |
| 757 | 757 | ||
| 758 | cnt = 0; | 758 | cnt = 0; |
| 759 | while (ec && count > cnt) { | 759 | while (ec && count > cnt) { |
| 760 | len = ecard_prints(buf, ec); | 760 | len = ecard_prints(buf, ec); |
| 761 | at += len; | 761 | at += len; |
| 762 | if (at >= pos) { | 762 | if (at >= pos) { |
| 763 | if (!*start) { | 763 | if (!*start) { |
| 764 | *start = buf + (pos - (at - len)); | 764 | *start = buf + (pos - (at - len)); |
| 765 | cnt = at - pos; | 765 | cnt = at - pos; |
| 766 | } else | 766 | } else |
| 767 | cnt += len; | 767 | cnt += len; |
| 768 | buf += len; | 768 | buf += len; |
| 769 | } | 769 | } |
| 770 | ec = ec->next; | 770 | ec = ec->next; |
| 771 | } | 771 | } |
| 772 | return (count > cnt) ? cnt : count; | 772 | return (count > cnt) ? cnt : count; |
| 773 | } | 773 | } |
| 774 | 774 | ||
| 775 | static struct proc_dir_entry *proc_bus_ecard_dir = NULL; | 775 | static struct proc_dir_entry *proc_bus_ecard_dir = NULL; |
| 776 | 776 | ||
| 777 | static void ecard_proc_init(void) | 777 | static void ecard_proc_init(void) |
| 778 | { | 778 | { |
| 779 | proc_bus_ecard_dir = proc_mkdir("ecard", proc_bus); | 779 | proc_bus_ecard_dir = proc_mkdir("ecard", proc_bus); |
| 780 | create_proc_info_entry("devices", 0, proc_bus_ecard_dir, | 780 | create_proc_info_entry("devices", 0, proc_bus_ecard_dir, |
| 781 | get_ecard_dev_info); | 781 | get_ecard_dev_info); |
| 782 | } | 782 | } |
| 783 | 783 | ||
| 784 | #define ec_set_resource(ec,nr,st,sz) \ | 784 | #define ec_set_resource(ec,nr,st,sz) \ |
| 785 | do { \ | 785 | do { \ |
| 786 | (ec)->resource[nr].name = ec->dev.bus_id; \ | 786 | (ec)->resource[nr].name = ec->dev.bus_id; \ |
| 787 | (ec)->resource[nr].start = st; \ | 787 | (ec)->resource[nr].start = st; \ |
| 788 | (ec)->resource[nr].end = (st) + (sz) - 1; \ | 788 | (ec)->resource[nr].end = (st) + (sz) - 1; \ |
| 789 | (ec)->resource[nr].flags = IORESOURCE_MEM; \ | 789 | (ec)->resource[nr].flags = IORESOURCE_MEM; \ |
| 790 | } while (0) | 790 | } while (0) |
| 791 | 791 | ||
| 792 | static void __init ecard_free_card(struct expansion_card *ec) | 792 | static void __init ecard_free_card(struct expansion_card *ec) |
| 793 | { | 793 | { |
| 794 | int i; | 794 | int i; |
| 795 | 795 | ||
| 796 | for (i = 0; i < ECARD_NUM_RESOURCES; i++) | 796 | for (i = 0; i < ECARD_NUM_RESOURCES; i++) |
| 797 | if (ec->resource[i].flags) | 797 | if (ec->resource[i].flags) |
| 798 | release_resource(&ec->resource[i]); | 798 | release_resource(&ec->resource[i]); |
| 799 | 799 | ||
| 800 | kfree(ec); | 800 | kfree(ec); |
| 801 | } | 801 | } |
| 802 | 802 | ||
| 803 | static struct expansion_card *__init ecard_alloc_card(int type, int slot) | 803 | static struct expansion_card *__init ecard_alloc_card(int type, int slot) |
| 804 | { | 804 | { |
| 805 | struct expansion_card *ec; | 805 | struct expansion_card *ec; |
| 806 | unsigned long base; | 806 | unsigned long base; |
| 807 | int i; | 807 | int i; |
| 808 | 808 | ||
| 809 | ec = kmalloc(sizeof(ecard_t), GFP_KERNEL); | 809 | ec = kmalloc(sizeof(ecard_t), GFP_KERNEL); |
| 810 | if (!ec) { | 810 | if (!ec) { |
| 811 | ec = ERR_PTR(-ENOMEM); | 811 | ec = ERR_PTR(-ENOMEM); |
| 812 | goto nomem; | 812 | goto nomem; |
| 813 | } | 813 | } |
| 814 | 814 | ||
| 815 | memset(ec, 0, sizeof(ecard_t)); | 815 | memset(ec, 0, sizeof(ecard_t)); |
| 816 | 816 | ||
| 817 | ec->slot_no = slot; | 817 | ec->slot_no = slot; |
| 818 | ec->type = type; | 818 | ec->type = type; |
| 819 | ec->irq = NO_IRQ; | 819 | ec->irq = NO_IRQ; |
| 820 | ec->fiq = NO_IRQ; | 820 | ec->fiq = NO_IRQ; |
| 821 | ec->dma = NO_DMA; | 821 | ec->dma = NO_DMA; |
| 822 | ec->ops = &ecard_default_ops; | 822 | ec->ops = &ecard_default_ops; |
| 823 | 823 | ||
| 824 | snprintf(ec->dev.bus_id, sizeof(ec->dev.bus_id), "ecard%d", slot); | 824 | snprintf(ec->dev.bus_id, sizeof(ec->dev.bus_id), "ecard%d", slot); |
| 825 | ec->dev.parent = NULL; | 825 | ec->dev.parent = NULL; |
| 826 | ec->dev.bus = &ecard_bus_type; | 826 | ec->dev.bus = &ecard_bus_type; |
| 827 | ec->dev.dma_mask = &ec->dma_mask; | 827 | ec->dev.dma_mask = &ec->dma_mask; |
| 828 | ec->dma_mask = (u64)0xffffffff; | 828 | ec->dma_mask = (u64)0xffffffff; |
| 829 | 829 | ||
| 830 | if (slot < 4) { | 830 | if (slot < 4) { |
| 831 | ec_set_resource(ec, ECARD_RES_MEMC, | 831 | ec_set_resource(ec, ECARD_RES_MEMC, |
| 832 | PODSLOT_MEMC_BASE + (slot << 14), | 832 | PODSLOT_MEMC_BASE + (slot << 14), |
| 833 | PODSLOT_MEMC_SIZE); | 833 | PODSLOT_MEMC_SIZE); |
| 834 | base = PODSLOT_IOC0_BASE + (slot << 14); | 834 | base = PODSLOT_IOC0_BASE + (slot << 14); |
| 835 | } else | 835 | } else |
| 836 | base = PODSLOT_IOC4_BASE + ((slot - 4) << 14); | 836 | base = PODSLOT_IOC4_BASE + ((slot - 4) << 14); |
| 837 | 837 | ||
| 838 | #ifdef CONFIG_ARCH_RPC | 838 | #ifdef CONFIG_ARCH_RPC |
| 839 | if (slot < 8) { | 839 | if (slot < 8) { |
| 840 | ec_set_resource(ec, ECARD_RES_EASI, | 840 | ec_set_resource(ec, ECARD_RES_EASI, |
| 841 | PODSLOT_EASI_BASE + (slot << 24), | 841 | PODSLOT_EASI_BASE + (slot << 24), |
| 842 | PODSLOT_EASI_SIZE); | 842 | PODSLOT_EASI_SIZE); |
| 843 | } | 843 | } |
| 844 | 844 | ||
| 845 | if (slot == 8) { | 845 | if (slot == 8) { |
| 846 | ec_set_resource(ec, ECARD_RES_MEMC, NETSLOT_BASE, NETSLOT_SIZE); | 846 | ec_set_resource(ec, ECARD_RES_MEMC, NETSLOT_BASE, NETSLOT_SIZE); |
| 847 | } else | 847 | } else |
| 848 | #endif | 848 | #endif |
| 849 | 849 | ||
| 850 | for (i = 0; i <= ECARD_RES_IOCSYNC - ECARD_RES_IOCSLOW; i++) | 850 | for (i = 0; i <= ECARD_RES_IOCSYNC - ECARD_RES_IOCSLOW; i++) |
| 851 | ec_set_resource(ec, i + ECARD_RES_IOCSLOW, | 851 | ec_set_resource(ec, i + ECARD_RES_IOCSLOW, |
| 852 | base + (i << 19), PODSLOT_IOC_SIZE); | 852 | base + (i << 19), PODSLOT_IOC_SIZE); |
| 853 | 853 | ||
| 854 | for (i = 0; i < ECARD_NUM_RESOURCES; i++) { | 854 | for (i = 0; i < ECARD_NUM_RESOURCES; i++) { |
| 855 | if (ec->resource[i].flags && | 855 | if (ec->resource[i].flags && |
| 856 | request_resource(&iomem_resource, &ec->resource[i])) { | 856 | request_resource(&iomem_resource, &ec->resource[i])) { |
| 857 | printk(KERN_ERR "%s: resource(s) not available\n", | 857 | printk(KERN_ERR "%s: resource(s) not available\n", |
| 858 | ec->dev.bus_id); | 858 | ec->dev.bus_id); |
| 859 | ec->resource[i].end -= ec->resource[i].start; | 859 | ec->resource[i].end -= ec->resource[i].start; |
| 860 | ec->resource[i].start = 0; | 860 | ec->resource[i].start = 0; |
| 861 | ec->resource[i].flags = 0; | 861 | ec->resource[i].flags = 0; |
| 862 | } | 862 | } |
| 863 | } | 863 | } |
| 864 | 864 | ||
| 865 | nomem: | 865 | nomem: |
| 866 | return ec; | 866 | return ec; |
| 867 | } | 867 | } |
| 868 | 868 | ||
| 869 | static ssize_t ecard_show_irq(struct device *dev, struct device_attribute *attr, char *buf) | 869 | static ssize_t ecard_show_irq(struct device *dev, struct device_attribute *attr, char *buf) |
| 870 | { | 870 | { |
| 871 | struct expansion_card *ec = ECARD_DEV(dev); | 871 | struct expansion_card *ec = ECARD_DEV(dev); |
| 872 | return sprintf(buf, "%u\n", ec->irq); | 872 | return sprintf(buf, "%u\n", ec->irq); |
| 873 | } | 873 | } |
| 874 | 874 | ||
| 875 | static ssize_t ecard_show_dma(struct device *dev, struct device_attribute *attr, char *buf) | 875 | static ssize_t ecard_show_dma(struct device *dev, struct device_attribute *attr, char *buf) |
| 876 | { | 876 | { |
| 877 | struct expansion_card *ec = ECARD_DEV(dev); | 877 | struct expansion_card *ec = ECARD_DEV(dev); |
| 878 | return sprintf(buf, "%u\n", ec->dma); | 878 | return sprintf(buf, "%u\n", ec->dma); |
| 879 | } | 879 | } |
| 880 | 880 | ||
| 881 | static ssize_t ecard_show_resources(struct device *dev, struct device_attribute *attr, char *buf) | 881 | static ssize_t ecard_show_resources(struct device *dev, struct device_attribute *attr, char *buf) |
| 882 | { | 882 | { |
| 883 | struct expansion_card *ec = ECARD_DEV(dev); | 883 | struct expansion_card *ec = ECARD_DEV(dev); |
| 884 | char *str = buf; | 884 | char *str = buf; |
| 885 | int i; | 885 | int i; |
| 886 | 886 | ||
| 887 | for (i = 0; i < ECARD_NUM_RESOURCES; i++) | 887 | for (i = 0; i < ECARD_NUM_RESOURCES; i++) |
| 888 | str += sprintf(str, "%08lx %08lx %08lx\n", | 888 | str += sprintf(str, "%08lx %08lx %08lx\n", |
| 889 | ec->resource[i].start, | 889 | ec->resource[i].start, |
| 890 | ec->resource[i].end, | 890 | ec->resource[i].end, |
| 891 | ec->resource[i].flags); | 891 | ec->resource[i].flags); |
| 892 | 892 | ||
| 893 | return str - buf; | 893 | return str - buf; |
| 894 | } | 894 | } |
| 895 | 895 | ||
| 896 | static ssize_t ecard_show_vendor(struct device *dev, struct device_attribute *attr, char *buf) | 896 | static ssize_t ecard_show_vendor(struct device *dev, struct device_attribute *attr, char *buf) |
| 897 | { | 897 | { |
| 898 | struct expansion_card *ec = ECARD_DEV(dev); | 898 | struct expansion_card *ec = ECARD_DEV(dev); |
| 899 | return sprintf(buf, "%u\n", ec->cid.manufacturer); | 899 | return sprintf(buf, "%u\n", ec->cid.manufacturer); |
| 900 | } | 900 | } |
| 901 | 901 | ||
| 902 | static ssize_t ecard_show_device(struct device *dev, struct device_attribute *attr, char *buf) | 902 | static ssize_t ecard_show_device(struct device *dev, struct device_attribute *attr, char *buf) |
| 903 | { | 903 | { |
| 904 | struct expansion_card *ec = ECARD_DEV(dev); | 904 | struct expansion_card *ec = ECARD_DEV(dev); |
| 905 | return sprintf(buf, "%u\n", ec->cid.product); | 905 | return sprintf(buf, "%u\n", ec->cid.product); |
| 906 | } | 906 | } |
| 907 | 907 | ||
| 908 | static ssize_t ecard_show_type(struct device *dev, struct device_attribute *attr, char *buf) | 908 | static ssize_t ecard_show_type(struct device *dev, struct device_attribute *attr, char *buf) |
| 909 | { | 909 | { |
| 910 | struct expansion_card *ec = ECARD_DEV(dev); | 910 | struct expansion_card *ec = ECARD_DEV(dev); |
| 911 | return sprintf(buf, "%s\n", ec->type == ECARD_EASI ? "EASI" : "IOC"); | 911 | return sprintf(buf, "%s\n", ec->type == ECARD_EASI ? "EASI" : "IOC"); |
| 912 | } | 912 | } |
| 913 | 913 | ||
| 914 | static struct device_attribute ecard_dev_attrs[] = { | 914 | static struct device_attribute ecard_dev_attrs[] = { |
| 915 | __ATTR(device, S_IRUGO, ecard_show_device, NULL), | 915 | __ATTR(device, S_IRUGO, ecard_show_device, NULL), |
| 916 | __ATTR(dma, S_IRUGO, ecard_show_dma, NULL), | 916 | __ATTR(dma, S_IRUGO, ecard_show_dma, NULL), |
| 917 | __ATTR(irq, S_IRUGO, ecard_show_irq, NULL), | 917 | __ATTR(irq, S_IRUGO, ecard_show_irq, NULL), |
| 918 | __ATTR(resource, S_IRUGO, ecard_show_resources, NULL), | 918 | __ATTR(resource, S_IRUGO, ecard_show_resources, NULL), |
| 919 | __ATTR(type, S_IRUGO, ecard_show_type, NULL), | 919 | __ATTR(type, S_IRUGO, ecard_show_type, NULL), |
| 920 | __ATTR(vendor, S_IRUGO, ecard_show_vendor, NULL), | 920 | __ATTR(vendor, S_IRUGO, ecard_show_vendor, NULL), |
| 921 | __ATTR_NULL, | 921 | __ATTR_NULL, |
| 922 | }; | 922 | }; |
| 923 | 923 | ||
| 924 | 924 | ||
| 925 | int ecard_request_resources(struct expansion_card *ec) | 925 | int ecard_request_resources(struct expansion_card *ec) |
| 926 | { | 926 | { |
| 927 | int i, err = 0; | 927 | int i, err = 0; |
| 928 | 928 | ||
| 929 | for (i = 0; i < ECARD_NUM_RESOURCES; i++) { | 929 | for (i = 0; i < ECARD_NUM_RESOURCES; i++) { |
| 930 | if (ecard_resource_end(ec, i) && | 930 | if (ecard_resource_end(ec, i) && |
| 931 | !request_mem_region(ecard_resource_start(ec, i), | 931 | !request_mem_region(ecard_resource_start(ec, i), |
| 932 | ecard_resource_len(ec, i), | 932 | ecard_resource_len(ec, i), |
| 933 | ec->dev.driver->name)) { | 933 | ec->dev.driver->name)) { |
| 934 | err = -EBUSY; | 934 | err = -EBUSY; |
| 935 | break; | 935 | break; |
| 936 | } | 936 | } |
| 937 | } | 937 | } |
| 938 | 938 | ||
| 939 | if (err) { | 939 | if (err) { |
| 940 | while (i--) | 940 | while (i--) |
| 941 | if (ecard_resource_end(ec, i)) | 941 | if (ecard_resource_end(ec, i)) |
| 942 | release_mem_region(ecard_resource_start(ec, i), | 942 | release_mem_region(ecard_resource_start(ec, i), |
| 943 | ecard_resource_len(ec, i)); | 943 | ecard_resource_len(ec, i)); |
| 944 | } | 944 | } |
| 945 | return err; | 945 | return err; |
| 946 | } | 946 | } |
| 947 | EXPORT_SYMBOL(ecard_request_resources); | 947 | EXPORT_SYMBOL(ecard_request_resources); |
| 948 | 948 | ||
| 949 | void ecard_release_resources(struct expansion_card *ec) | 949 | void ecard_release_resources(struct expansion_card *ec) |
| 950 | { | 950 | { |
| 951 | int i; | 951 | int i; |
| 952 | 952 | ||
| 953 | for (i = 0; i < ECARD_NUM_RESOURCES; i++) | 953 | for (i = 0; i < ECARD_NUM_RESOURCES; i++) |
| 954 | if (ecard_resource_end(ec, i)) | 954 | if (ecard_resource_end(ec, i)) |
| 955 | release_mem_region(ecard_resource_start(ec, i), | 955 | release_mem_region(ecard_resource_start(ec, i), |
| 956 | ecard_resource_len(ec, i)); | 956 | ecard_resource_len(ec, i)); |
| 957 | } | 957 | } |
| 958 | EXPORT_SYMBOL(ecard_release_resources); | 958 | EXPORT_SYMBOL(ecard_release_resources); |
| 959 | 959 | ||
| 960 | /* | 960 | /* |
| 961 | * Probe for an expansion card. | 961 | * Probe for an expansion card. |
| 962 | * | 962 | * |
| 963 | * If bit 1 of the first byte of the card is set, then the | 963 | * If bit 1 of the first byte of the card is set, then the |
| 964 | * card does not exist. | 964 | * card does not exist. |
| 965 | */ | 965 | */ |
| 966 | static int __init | 966 | static int __init |
| 967 | ecard_probe(int slot, card_type_t type) | 967 | ecard_probe(int slot, card_type_t type) |
| 968 | { | 968 | { |
| 969 | ecard_t **ecp; | 969 | ecard_t **ecp; |
| 970 | ecard_t *ec; | 970 | ecard_t *ec; |
| 971 | struct ex_ecid cid; | 971 | struct ex_ecid cid; |
| 972 | int i, rc; | 972 | int i, rc; |
| 973 | 973 | ||
| 974 | ec = ecard_alloc_card(type, slot); | 974 | ec = ecard_alloc_card(type, slot); |
| 975 | if (IS_ERR(ec)) { | 975 | if (IS_ERR(ec)) { |
| 976 | rc = PTR_ERR(ec); | 976 | rc = PTR_ERR(ec); |
| 977 | goto nomem; | 977 | goto nomem; |
| 978 | } | 978 | } |
| 979 | 979 | ||
| 980 | rc = -ENODEV; | 980 | rc = -ENODEV; |
| 981 | if ((ec->podaddr = ecard_address(ec, type, ECARD_SYNC)) == 0) | 981 | if ((ec->podaddr = ecard_address(ec, type, ECARD_SYNC)) == 0) |
| 982 | goto nodev; | 982 | goto nodev; |
| 983 | 983 | ||
| 984 | cid.r_zero = 1; | 984 | cid.r_zero = 1; |
| 985 | ecard_readbytes(&cid, ec, 0, 16, 0); | 985 | ecard_readbytes(&cid, ec, 0, 16, 0); |
| 986 | if (cid.r_zero) | 986 | if (cid.r_zero) |
| 987 | goto nodev; | 987 | goto nodev; |
| 988 | 988 | ||
| 989 | ec->cid.id = cid.r_id; | 989 | ec->cid.id = cid.r_id; |
| 990 | ec->cid.cd = cid.r_cd; | 990 | ec->cid.cd = cid.r_cd; |
| 991 | ec->cid.is = cid.r_is; | 991 | ec->cid.is = cid.r_is; |
| 992 | ec->cid.w = cid.r_w; | 992 | ec->cid.w = cid.r_w; |
| 993 | ec->cid.manufacturer = ecard_getu16(cid.r_manu); | 993 | ec->cid.manufacturer = ecard_getu16(cid.r_manu); |
| 994 | ec->cid.product = ecard_getu16(cid.r_prod); | 994 | ec->cid.product = ecard_getu16(cid.r_prod); |
| 995 | ec->cid.country = cid.r_country; | 995 | ec->cid.country = cid.r_country; |
| 996 | ec->cid.irqmask = cid.r_irqmask; | 996 | ec->cid.irqmask = cid.r_irqmask; |
| 997 | ec->cid.irqoff = ecard_gets24(cid.r_irqoff); | 997 | ec->cid.irqoff = ecard_gets24(cid.r_irqoff); |
| 998 | ec->cid.fiqmask = cid.r_fiqmask; | 998 | ec->cid.fiqmask = cid.r_fiqmask; |
| 999 | ec->cid.fiqoff = ecard_gets24(cid.r_fiqoff); | 999 | ec->cid.fiqoff = ecard_gets24(cid.r_fiqoff); |
| 1000 | ec->fiqaddr = | 1000 | ec->fiqaddr = |
| 1001 | ec->irqaddr = (void __iomem *)ioaddr(ec->podaddr); | 1001 | ec->irqaddr = (void __iomem *)ioaddr(ec->podaddr); |
| 1002 | 1002 | ||
| 1003 | if (ec->cid.is) { | 1003 | if (ec->cid.is) { |
| 1004 | ec->irqmask = ec->cid.irqmask; | 1004 | ec->irqmask = ec->cid.irqmask; |
| 1005 | ec->irqaddr += ec->cid.irqoff; | 1005 | ec->irqaddr += ec->cid.irqoff; |
| 1006 | ec->fiqmask = ec->cid.fiqmask; | 1006 | ec->fiqmask = ec->cid.fiqmask; |
| 1007 | ec->fiqaddr += ec->cid.fiqoff; | 1007 | ec->fiqaddr += ec->cid.fiqoff; |
| 1008 | } else { | 1008 | } else { |
| 1009 | ec->irqmask = 1; | 1009 | ec->irqmask = 1; |
| 1010 | ec->fiqmask = 4; | 1010 | ec->fiqmask = 4; |
| 1011 | } | 1011 | } |
| 1012 | 1012 | ||
| 1013 | for (i = 0; i < sizeof(blacklist) / sizeof(*blacklist); i++) | 1013 | for (i = 0; i < sizeof(blacklist) / sizeof(*blacklist); i++) |
| 1014 | if (blacklist[i].manufacturer == ec->cid.manufacturer && | 1014 | if (blacklist[i].manufacturer == ec->cid.manufacturer && |
| 1015 | blacklist[i].product == ec->cid.product) { | 1015 | blacklist[i].product == ec->cid.product) { |
| 1016 | ec->card_desc = blacklist[i].type; | 1016 | ec->card_desc = blacklist[i].type; |
| 1017 | break; | 1017 | break; |
| 1018 | } | 1018 | } |
| 1019 | 1019 | ||
| 1020 | /* | 1020 | /* |
| 1021 | * hook the interrupt handlers | 1021 | * hook the interrupt handlers |
| 1022 | */ | 1022 | */ |
| 1023 | if (slot < 8) { | 1023 | if (slot < 8) { |
| 1024 | ec->irq = 32 + slot; | 1024 | ec->irq = 32 + slot; |
| 1025 | set_irq_chip(ec->irq, &ecard_chip); | 1025 | set_irq_chip(ec->irq, &ecard_chip); |
| 1026 | set_irq_handler(ec->irq, do_level_IRQ); | 1026 | set_irq_handler(ec->irq, do_level_IRQ); |
| 1027 | set_irq_flags(ec->irq, IRQF_VALID); | 1027 | set_irq_flags(ec->irq, IRQF_VALID); |
| 1028 | } | 1028 | } |
| 1029 | 1029 | ||
| 1030 | #ifdef IO_EC_MEMC8_BASE | 1030 | #ifdef IO_EC_MEMC8_BASE |
| 1031 | if (slot == 8) | 1031 | if (slot == 8) |
| 1032 | ec->irq = 11; | 1032 | ec->irq = 11; |
| 1033 | #endif | 1033 | #endif |
| 1034 | #ifdef CONFIG_ARCH_RPC | 1034 | #ifdef CONFIG_ARCH_RPC |
| 1035 | /* On RiscPC, only first two slots have DMA capability */ | 1035 | /* On RiscPC, only first two slots have DMA capability */ |
| 1036 | if (slot < 2) | 1036 | if (slot < 2) |
| 1037 | ec->dma = 2 + slot; | 1037 | ec->dma = 2 + slot; |
| 1038 | #endif | 1038 | #endif |
| 1039 | 1039 | ||
| 1040 | for (ecp = &cards; *ecp; ecp = &(*ecp)->next); | 1040 | for (ecp = &cards; *ecp; ecp = &(*ecp)->next); |
| 1041 | 1041 | ||
| 1042 | *ecp = ec; | 1042 | *ecp = ec; |
| 1043 | slot_to_expcard[slot] = ec; | 1043 | slot_to_expcard[slot] = ec; |
| 1044 | 1044 | ||
| 1045 | device_register(&ec->dev); | 1045 | device_register(&ec->dev); |
| 1046 | 1046 | ||
| 1047 | return 0; | 1047 | return 0; |
| 1048 | 1048 | ||
| 1049 | nodev: | 1049 | nodev: |
| 1050 | ecard_free_card(ec); | 1050 | ecard_free_card(ec); |
| 1051 | nomem: | 1051 | nomem: |
| 1052 | return rc; | 1052 | return rc; |
| 1053 | } | 1053 | } |
| 1054 | 1054 | ||
| 1055 | /* | 1055 | /* |
| 1056 | * Initialise the expansion card system. | 1056 | * Initialise the expansion card system. |
| 1057 | * Locate all hardware - interrupt management and | 1057 | * Locate all hardware - interrupt management and |
| 1058 | * actual cards. | 1058 | * actual cards. |
| 1059 | */ | 1059 | */ |
| 1060 | static int __init ecard_init(void) | 1060 | static int __init ecard_init(void) |
| 1061 | { | 1061 | { |
| 1062 | int slot, irqhw, ret; | 1062 | int slot, irqhw, ret; |
| 1063 | 1063 | ||
| 1064 | ret = kernel_thread(ecard_task, NULL, CLONE_KERNEL); | 1064 | ret = kernel_thread(ecard_task, NULL, CLONE_KERNEL); |
| 1065 | if (ret < 0) { | 1065 | if (ret < 0) { |
| 1066 | printk(KERN_ERR "Ecard: unable to create kernel thread: %d\n", | 1066 | printk(KERN_ERR "Ecard: unable to create kernel thread: %d\n", |
| 1067 | ret); | 1067 | ret); |
| 1068 | return ret; | 1068 | return ret; |
| 1069 | } | 1069 | } |
| 1070 | 1070 | ||
| 1071 | printk("Probing expansion cards\n"); | 1071 | printk("Probing expansion cards\n"); |
| 1072 | 1072 | ||
| 1073 | for (slot = 0; slot < 8; slot ++) { | 1073 | for (slot = 0; slot < 8; slot ++) { |
| 1074 | if (ecard_probe(slot, ECARD_EASI) == -ENODEV) | 1074 | if (ecard_probe(slot, ECARD_EASI) == -ENODEV) |
| 1075 | ecard_probe(slot, ECARD_IOC); | 1075 | ecard_probe(slot, ECARD_IOC); |
| 1076 | } | 1076 | } |
| 1077 | 1077 | ||
| 1078 | #ifdef IO_EC_MEMC8_BASE | 1078 | #ifdef IO_EC_MEMC8_BASE |
| 1079 | ecard_probe(8, ECARD_IOC); | 1079 | ecard_probe(8, ECARD_IOC); |
| 1080 | #endif | 1080 | #endif |
| 1081 | 1081 | ||
| 1082 | irqhw = ecard_probeirqhw(); | 1082 | irqhw = ecard_probeirqhw(); |
| 1083 | 1083 | ||
| 1084 | set_irq_chained_handler(IRQ_EXPANSIONCARD, | 1084 | set_irq_chained_handler(IRQ_EXPANSIONCARD, |
| 1085 | irqhw ? ecard_irqexp_handler : ecard_irq_handler); | 1085 | irqhw ? ecard_irqexp_handler : ecard_irq_handler); |
| 1086 | 1086 | ||
| 1087 | ecard_proc_init(); | 1087 | ecard_proc_init(); |
| 1088 | 1088 | ||
| 1089 | return 0; | 1089 | return 0; |
| 1090 | } | 1090 | } |
| 1091 | 1091 | ||
| 1092 | subsys_initcall(ecard_init); | 1092 | subsys_initcall(ecard_init); |
| 1093 | 1093 | ||
| 1094 | /* | 1094 | /* |
| 1095 | * ECARD "bus" | 1095 | * ECARD "bus" |
| 1096 | */ | 1096 | */ |
| 1097 | static const struct ecard_id * | 1097 | static const struct ecard_id * |
| 1098 | ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec) | 1098 | ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec) |
| 1099 | { | 1099 | { |
| 1100 | int i; | 1100 | int i; |
| 1101 | 1101 | ||
| 1102 | for (i = 0; ids[i].manufacturer != 65535; i++) | 1102 | for (i = 0; ids[i].manufacturer != 65535; i++) |
| 1103 | if (ec->cid.manufacturer == ids[i].manufacturer && | 1103 | if (ec->cid.manufacturer == ids[i].manufacturer && |
| 1104 | ec->cid.product == ids[i].product) | 1104 | ec->cid.product == ids[i].product) |
| 1105 | return ids + i; | 1105 | return ids + i; |
| 1106 | 1106 | ||
| 1107 | return NULL; | 1107 | return NULL; |
| 1108 | } | 1108 | } |
| 1109 | 1109 | ||
| 1110 | static int ecard_drv_probe(struct device *dev) | 1110 | static int ecard_drv_probe(struct device *dev) |
| 1111 | { | 1111 | { |
| 1112 | struct expansion_card *ec = ECARD_DEV(dev); | 1112 | struct expansion_card *ec = ECARD_DEV(dev); |
| 1113 | struct ecard_driver *drv = ECARD_DRV(dev->driver); | 1113 | struct ecard_driver *drv = ECARD_DRV(dev->driver); |
| 1114 | const struct ecard_id *id; | 1114 | const struct ecard_id *id; |
| 1115 | int ret; | 1115 | int ret; |
| 1116 | 1116 | ||
| 1117 | id = ecard_match_device(drv->id_table, ec); | 1117 | id = ecard_match_device(drv->id_table, ec); |
| 1118 | 1118 | ||
| 1119 | ecard_claim(ec); | 1119 | ecard_claim(ec); |
| 1120 | ret = drv->probe(ec, id); | 1120 | ret = drv->probe(ec, id); |
| 1121 | if (ret) | 1121 | if (ret) |
| 1122 | ecard_release(ec); | 1122 | ecard_release(ec); |
| 1123 | return ret; | 1123 | return ret; |
| 1124 | } | 1124 | } |
| 1125 | 1125 | ||
| 1126 | static int ecard_drv_remove(struct device *dev) | 1126 | static int ecard_drv_remove(struct device *dev) |
| 1127 | { | 1127 | { |
| 1128 | struct expansion_card *ec = ECARD_DEV(dev); | 1128 | struct expansion_card *ec = ECARD_DEV(dev); |
| 1129 | struct ecard_driver *drv = ECARD_DRV(dev->driver); | 1129 | struct ecard_driver *drv = ECARD_DRV(dev->driver); |
| 1130 | 1130 | ||
| 1131 | drv->remove(ec); | 1131 | drv->remove(ec); |
| 1132 | ecard_release(ec); | 1132 | ecard_release(ec); |
| 1133 | 1133 | ||
| 1134 | return 0; | 1134 | return 0; |
| 1135 | } | 1135 | } |
| 1136 | 1136 | ||
| 1137 | /* | 1137 | /* |
| 1138 | * Before rebooting, we must make sure that the expansion card is in a | 1138 | * Before rebooting, we must make sure that the expansion card is in a |
| 1139 | * sensible state, so it can be re-detected. This means that the first | 1139 | * sensible state, so it can be re-detected. This means that the first |
| 1140 | * page of the ROM must be visible. We call the expansion cards reset | 1140 | * page of the ROM must be visible. We call the expansion cards reset |
| 1141 | * handler, if any. | 1141 | * handler, if any. |
| 1142 | */ | 1142 | */ |
| 1143 | static void ecard_drv_shutdown(struct device *dev) | 1143 | static void ecard_drv_shutdown(struct device *dev) |
| 1144 | { | 1144 | { |
| 1145 | struct expansion_card *ec = ECARD_DEV(dev); | 1145 | struct expansion_card *ec = ECARD_DEV(dev); |
| 1146 | struct ecard_driver *drv = ECARD_DRV(dev->driver); | 1146 | struct ecard_driver *drv = ECARD_DRV(dev->driver); |
| 1147 | struct ecard_request req; | 1147 | struct ecard_request req; |
| 1148 | 1148 | ||
| 1149 | if (drv->shutdown) | 1149 | if (drv->shutdown) |
| 1150 | drv->shutdown(ec); | 1150 | drv->shutdown(ec); |
| 1151 | ecard_release(ec); | 1151 | ecard_release(ec); |
| 1152 | 1152 | ||
| 1153 | /* | 1153 | /* |
| 1154 | * If this card has a loader, call the reset handler. | 1154 | * If this card has a loader, call the reset handler. |
| 1155 | */ | 1155 | */ |
| 1156 | if (ec->loader) { | 1156 | if (ec->loader) { |
| 1157 | req.fn = ecard_task_reset; | 1157 | req.fn = ecard_task_reset; |
| 1158 | req.ec = ec; | 1158 | req.ec = ec; |
| 1159 | ecard_call(&req); | 1159 | ecard_call(&req); |
| 1160 | } | 1160 | } |
| 1161 | } | 1161 | } |
| 1162 | 1162 | ||
| 1163 | int ecard_register_driver(struct ecard_driver *drv) | 1163 | int ecard_register_driver(struct ecard_driver *drv) |
| 1164 | { | 1164 | { |
| 1165 | drv->drv.bus = &ecard_bus_type; | 1165 | drv->drv.bus = &ecard_bus_type; |
| 1166 | drv->drv.probe = ecard_drv_probe; | 1166 | drv->drv.probe = ecard_drv_probe; |
| 1167 | drv->drv.remove = ecard_drv_remove; | 1167 | drv->drv.remove = ecard_drv_remove; |
| 1168 | drv->drv.shutdown = ecard_drv_shutdown; | 1168 | drv->drv.shutdown = ecard_drv_shutdown; |
| 1169 | 1169 | ||
| 1170 | return driver_register(&drv->drv); | 1170 | return driver_register(&drv->drv); |
| 1171 | } | 1171 | } |
| 1172 | 1172 | ||
| 1173 | void ecard_remove_driver(struct ecard_driver *drv) | 1173 | void ecard_remove_driver(struct ecard_driver *drv) |
| 1174 | { | 1174 | { |
| 1175 | driver_unregister(&drv->drv); | 1175 | driver_unregister(&drv->drv); |
| 1176 | } | 1176 | } |
| 1177 | 1177 | ||
| 1178 | static int ecard_match(struct device *_dev, struct device_driver *_drv) | 1178 | static int ecard_match(struct device *_dev, struct device_driver *_drv) |
| 1179 | { | 1179 | { |
| 1180 | struct expansion_card *ec = ECARD_DEV(_dev); | 1180 | struct expansion_card *ec = ECARD_DEV(_dev); |
| 1181 | struct ecard_driver *drv = ECARD_DRV(_drv); | 1181 | struct ecard_driver *drv = ECARD_DRV(_drv); |
| 1182 | int ret; | 1182 | int ret; |
| 1183 | 1183 | ||
| 1184 | if (drv->id_table) { | 1184 | if (drv->id_table) { |
| 1185 | ret = ecard_match_device(drv->id_table, ec) != NULL; | 1185 | ret = ecard_match_device(drv->id_table, ec) != NULL; |
| 1186 | } else { | 1186 | } else { |
| 1187 | ret = ec->cid.id == drv->id; | 1187 | ret = ec->cid.id == drv->id; |
| 1188 | } | 1188 | } |
| 1189 | 1189 | ||
| 1190 | return ret; | 1190 | return ret; |
| 1191 | } | 1191 | } |
| 1192 | 1192 | ||
| 1193 | struct bus_type ecard_bus_type = { | 1193 | struct bus_type ecard_bus_type = { |
| 1194 | .name = "ecard", | 1194 | .name = "ecard", |
| 1195 | .dev_attrs = ecard_dev_attrs, | 1195 | .dev_attrs = ecard_dev_attrs, |
| 1196 | .match = ecard_match, | 1196 | .match = ecard_match, |
| 1197 | }; | 1197 | }; |
| 1198 | 1198 | ||
| 1199 | static int ecard_bus_init(void) | 1199 | static int ecard_bus_init(void) |
| 1200 | { | 1200 | { |
| 1201 | return bus_register(&ecard_bus_type); | 1201 | return bus_register(&ecard_bus_type); |
| 1202 | } | 1202 | } |
| 1203 | 1203 | ||
| 1204 | postcore_initcall(ecard_bus_init); | 1204 | postcore_initcall(ecard_bus_init); |
| 1205 | 1205 | ||
| 1206 | EXPORT_SYMBOL(ecard_readchunk); | 1206 | EXPORT_SYMBOL(ecard_readchunk); |
| 1207 | EXPORT_SYMBOL(__ecard_address); | 1207 | EXPORT_SYMBOL(__ecard_address); |
| 1208 | EXPORT_SYMBOL(ecard_register_driver); | 1208 | EXPORT_SYMBOL(ecard_register_driver); |
| 1209 | EXPORT_SYMBOL(ecard_remove_driver); | 1209 | EXPORT_SYMBOL(ecard_remove_driver); |
| 1210 | EXPORT_SYMBOL(ecard_bus_type); | 1210 | EXPORT_SYMBOL(ecard_bus_type); |
| 1211 | 1211 |
arch/arm/kernel/irq.c
| 1 | /* | 1 | /* |
| 2 | * linux/arch/arm/kernel/irq.c | 2 | * linux/arch/arm/kernel/irq.c |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 1992 Linus Torvalds | 4 | * Copyright (C) 1992 Linus Torvalds |
| 5 | * Modifications for ARM processor Copyright (C) 1995-2000 Russell King. | 5 | * Modifications for ARM processor Copyright (C) 1995-2000 Russell King. |
| 6 | * | 6 | * |
| 7 | * Support for Dynamic Tick Timer Copyright (C) 2004-2005 Nokia Corporation. | 7 | * Support for Dynamic Tick Timer Copyright (C) 2004-2005 Nokia Corporation. |
| 8 | * Dynamic Tick Timer written by Tony Lindgren <tony@atomide.com> and | 8 | * Dynamic Tick Timer written by Tony Lindgren <tony@atomide.com> and |
| 9 | * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>. | 9 | * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>. |
| 10 | * | 10 | * |
| 11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
| 13 | * published by the Free Software Foundation. | 13 | * published by the Free Software Foundation. |
| 14 | * | 14 | * |
| 15 | * This file contains the code used by various IRQ handling routines: | 15 | * This file contains the code used by various IRQ handling routines: |
| 16 | * asking for different IRQ's should be done through these routines | 16 | * asking for different IRQ's should be done through these routines |
| 17 | * instead of just grabbing them. Thus setups with different IRQ numbers | 17 | * instead of just grabbing them. Thus setups with different IRQ numbers |
| 18 | * shouldn't result in any weird surprises, and installing new handlers | 18 | * shouldn't result in any weird surprises, and installing new handlers |
| 19 | * should be easier. | 19 | * should be easier. |
| 20 | * | 20 | * |
| 21 | * IRQ's are in fact implemented a bit like signal handlers for the kernel. | 21 | * IRQ's are in fact implemented a bit like signal handlers for the kernel. |
| 22 | * Naturally it's not a 1:1 relation, but there are similarities. | 22 | * Naturally it's not a 1:1 relation, but there are similarities. |
| 23 | */ | 23 | */ |
| 24 | #include <linux/config.h> | 24 | #include <linux/config.h> |
| 25 | #include <linux/kernel_stat.h> | 25 | #include <linux/kernel_stat.h> |
| 26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
| 27 | #include <linux/signal.h> | 27 | #include <linux/signal.h> |
| 28 | #include <linux/ioport.h> | 28 | #include <linux/ioport.h> |
| 29 | #include <linux/interrupt.h> | 29 | #include <linux/interrupt.h> |
| 30 | #include <linux/ptrace.h> | 30 | #include <linux/ptrace.h> |
| 31 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
| 32 | #include <linux/random.h> | 32 | #include <linux/random.h> |
| 33 | #include <linux/smp.h> | 33 | #include <linux/smp.h> |
| 34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
| 35 | #include <linux/seq_file.h> | 35 | #include <linux/seq_file.h> |
| 36 | #include <linux/errno.h> | 36 | #include <linux/errno.h> |
| 37 | #include <linux/list.h> | 37 | #include <linux/list.h> |
| 38 | #include <linux/kallsyms.h> | 38 | #include <linux/kallsyms.h> |
| 39 | #include <linux/proc_fs.h> | 39 | #include <linux/proc_fs.h> |
| 40 | 40 | ||
| 41 | #include <asm/irq.h> | 41 | #include <asm/irq.h> |
| 42 | #include <asm/system.h> | 42 | #include <asm/system.h> |
| 43 | #include <asm/mach/irq.h> | 43 | #include <asm/mach/irq.h> |
| 44 | #include <asm/mach/time.h> | 44 | #include <asm/mach/time.h> |
| 45 | 45 | ||
| 46 | /* | 46 | /* |
| 47 | * Maximum IRQ count. Currently, this is arbitary. However, it should | 47 | * Maximum IRQ count. Currently, this is arbitary. However, it should |
| 48 | * not be set too low to prevent false triggering. Conversely, if it | 48 | * not be set too low to prevent false triggering. Conversely, if it |
| 49 | * is set too high, then you could miss a stuck IRQ. | 49 | * is set too high, then you could miss a stuck IRQ. |
| 50 | * | 50 | * |
| 51 | * Maybe we ought to set a timer and re-enable the IRQ at a later time? | 51 | * Maybe we ought to set a timer and re-enable the IRQ at a later time? |
| 52 | */ | 52 | */ |
| 53 | #define MAX_IRQ_CNT 100000 | 53 | #define MAX_IRQ_CNT 100000 |
| 54 | 54 | ||
| 55 | static int noirqdebug; | 55 | static int noirqdebug; |
| 56 | static volatile unsigned long irq_err_count; | 56 | static volatile unsigned long irq_err_count; |
| 57 | static DEFINE_SPINLOCK(irq_controller_lock); | 57 | static DEFINE_SPINLOCK(irq_controller_lock); |
| 58 | static LIST_HEAD(irq_pending); | 58 | static LIST_HEAD(irq_pending); |
| 59 | 59 | ||
| 60 | struct irqdesc irq_desc[NR_IRQS]; | 60 | struct irqdesc irq_desc[NR_IRQS]; |
| 61 | void (*init_arch_irq)(void) __initdata = NULL; | 61 | void (*init_arch_irq)(void) __initdata = NULL; |
| 62 | 62 | ||
| 63 | /* | 63 | /* |
| 64 | * No architecture-specific irq_finish function defined in arm/arch/irqs.h. | 64 | * No architecture-specific irq_finish function defined in arm/arch/irqs.h. |
| 65 | */ | 65 | */ |
| 66 | #ifndef irq_finish | 66 | #ifndef irq_finish |
| 67 | #define irq_finish(irq) do { } while (0) | 67 | #define irq_finish(irq) do { } while (0) |
| 68 | #endif | 68 | #endif |
| 69 | 69 | ||
| 70 | /* | 70 | /* |
| 71 | * Dummy mask/unmask handler | 71 | * Dummy mask/unmask handler |
| 72 | */ | 72 | */ |
| 73 | void dummy_mask_unmask_irq(unsigned int irq) | 73 | void dummy_mask_unmask_irq(unsigned int irq) |
| 74 | { | 74 | { |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | irqreturn_t no_action(int irq, void *dev_id, struct pt_regs *regs) | 77 | irqreturn_t no_action(int irq, void *dev_id, struct pt_regs *regs) |
| 78 | { | 78 | { |
| 79 | return IRQ_NONE; | 79 | return IRQ_NONE; |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | void do_bad_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) | 82 | void do_bad_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) |
| 83 | { | 83 | { |
| 84 | irq_err_count += 1; | 84 | irq_err_count += 1; |
| 85 | printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq); | 85 | printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq); |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | static struct irqchip bad_chip = { | 88 | static struct irqchip bad_chip = { |
| 89 | .ack = dummy_mask_unmask_irq, | 89 | .ack = dummy_mask_unmask_irq, |
| 90 | .mask = dummy_mask_unmask_irq, | 90 | .mask = dummy_mask_unmask_irq, |
| 91 | .unmask = dummy_mask_unmask_irq, | 91 | .unmask = dummy_mask_unmask_irq, |
| 92 | }; | 92 | }; |
| 93 | 93 | ||
| 94 | static struct irqdesc bad_irq_desc = { | 94 | static struct irqdesc bad_irq_desc = { |
| 95 | .chip = &bad_chip, | 95 | .chip = &bad_chip, |
| 96 | .handle = do_bad_IRQ, | 96 | .handle = do_bad_IRQ, |
| 97 | .pend = LIST_HEAD_INIT(bad_irq_desc.pend), | 97 | .pend = LIST_HEAD_INIT(bad_irq_desc.pend), |
| 98 | .disable_depth = 1, | 98 | .disable_depth = 1, |
| 99 | }; | 99 | }; |
| 100 | 100 | ||
| 101 | #ifdef CONFIG_SMP | 101 | #ifdef CONFIG_SMP |
| 102 | void synchronize_irq(unsigned int irq) | 102 | void synchronize_irq(unsigned int irq) |
| 103 | { | 103 | { |
| 104 | struct irqdesc *desc = irq_desc + irq; | 104 | struct irqdesc *desc = irq_desc + irq; |
| 105 | 105 | ||
| 106 | while (desc->running) | 106 | while (desc->running) |
| 107 | barrier(); | 107 | barrier(); |
| 108 | } | 108 | } |
| 109 | EXPORT_SYMBOL(synchronize_irq); | 109 | EXPORT_SYMBOL(synchronize_irq); |
| 110 | 110 | ||
| 111 | #define smp_set_running(desc) do { desc->running = 1; } while (0) | 111 | #define smp_set_running(desc) do { desc->running = 1; } while (0) |
| 112 | #define smp_clear_running(desc) do { desc->running = 0; } while (0) | 112 | #define smp_clear_running(desc) do { desc->running = 0; } while (0) |
| 113 | #else | 113 | #else |
| 114 | #define smp_set_running(desc) do { } while (0) | 114 | #define smp_set_running(desc) do { } while (0) |
| 115 | #define smp_clear_running(desc) do { } while (0) | 115 | #define smp_clear_running(desc) do { } while (0) |
| 116 | #endif | 116 | #endif |
| 117 | 117 | ||
| 118 | /** | 118 | /** |
| 119 | * disable_irq_nosync - disable an irq without waiting | 119 | * disable_irq_nosync - disable an irq without waiting |
| 120 | * @irq: Interrupt to disable | 120 | * @irq: Interrupt to disable |
| 121 | * | 121 | * |
| 122 | * Disable the selected interrupt line. Enables and disables | 122 | * Disable the selected interrupt line. Enables and disables |
| 123 | * are nested. We do this lazily. | 123 | * are nested. We do this lazily. |
| 124 | * | 124 | * |
| 125 | * This function may be called from IRQ context. | 125 | * This function may be called from IRQ context. |
| 126 | */ | 126 | */ |
| 127 | void disable_irq_nosync(unsigned int irq) | 127 | void disable_irq_nosync(unsigned int irq) |
| 128 | { | 128 | { |
| 129 | struct irqdesc *desc = irq_desc + irq; | 129 | struct irqdesc *desc = irq_desc + irq; |
| 130 | unsigned long flags; | 130 | unsigned long flags; |
| 131 | 131 | ||
| 132 | spin_lock_irqsave(&irq_controller_lock, flags); | 132 | spin_lock_irqsave(&irq_controller_lock, flags); |
| 133 | desc->disable_depth++; | 133 | desc->disable_depth++; |
| 134 | list_del_init(&desc->pend); | 134 | list_del_init(&desc->pend); |
| 135 | spin_unlock_irqrestore(&irq_controller_lock, flags); | 135 | spin_unlock_irqrestore(&irq_controller_lock, flags); |
| 136 | } | 136 | } |
| 137 | EXPORT_SYMBOL(disable_irq_nosync); | 137 | EXPORT_SYMBOL(disable_irq_nosync); |
| 138 | 138 | ||
| 139 | /** | 139 | /** |
| 140 | * disable_irq - disable an irq and wait for completion | 140 | * disable_irq - disable an irq and wait for completion |
| 141 | * @irq: Interrupt to disable | 141 | * @irq: Interrupt to disable |
| 142 | * | 142 | * |
| 143 | * Disable the selected interrupt line. Enables and disables | 143 | * Disable the selected interrupt line. Enables and disables |
| 144 | * are nested. This functions waits for any pending IRQ | 144 | * are nested. This functions waits for any pending IRQ |
| 145 | * handlers for this interrupt to complete before returning. | 145 | * handlers for this interrupt to complete before returning. |
| 146 | * If you use this function while holding a resource the IRQ | 146 | * If you use this function while holding a resource the IRQ |
| 147 | * handler may need you will deadlock. | 147 | * handler may need you will deadlock. |
| 148 | * | 148 | * |
| 149 | * This function may be called - with care - from IRQ context. | 149 | * This function may be called - with care - from IRQ context. |
| 150 | */ | 150 | */ |
| 151 | void disable_irq(unsigned int irq) | 151 | void disable_irq(unsigned int irq) |
| 152 | { | 152 | { |
| 153 | struct irqdesc *desc = irq_desc + irq; | 153 | struct irqdesc *desc = irq_desc + irq; |
| 154 | 154 | ||
| 155 | disable_irq_nosync(irq); | 155 | disable_irq_nosync(irq); |
| 156 | if (desc->action) | 156 | if (desc->action) |
| 157 | synchronize_irq(irq); | 157 | synchronize_irq(irq); |
| 158 | } | 158 | } |
| 159 | EXPORT_SYMBOL(disable_irq); | 159 | EXPORT_SYMBOL(disable_irq); |
| 160 | 160 | ||
| 161 | /** | 161 | /** |
| 162 | * enable_irq - enable interrupt handling on an irq | 162 | * enable_irq - enable interrupt handling on an irq |
| 163 | * @irq: Interrupt to enable | 163 | * @irq: Interrupt to enable |
| 164 | * | 164 | * |
| 165 | * Re-enables the processing of interrupts on this IRQ line. | 165 | * Re-enables the processing of interrupts on this IRQ line. |
| 166 | * Note that this may call the interrupt handler, so you may | 166 | * Note that this may call the interrupt handler, so you may |
| 167 | * get unexpected results if you hold IRQs disabled. | 167 | * get unexpected results if you hold IRQs disabled. |
| 168 | * | 168 | * |
| 169 | * This function may be called from IRQ context. | 169 | * This function may be called from IRQ context. |
| 170 | */ | 170 | */ |
| 171 | void enable_irq(unsigned int irq) | 171 | void enable_irq(unsigned int irq) |
| 172 | { | 172 | { |
| 173 | struct irqdesc *desc = irq_desc + irq; | 173 | struct irqdesc *desc = irq_desc + irq; |
| 174 | unsigned long flags; | 174 | unsigned long flags; |
| 175 | 175 | ||
| 176 | spin_lock_irqsave(&irq_controller_lock, flags); | 176 | spin_lock_irqsave(&irq_controller_lock, flags); |
| 177 | if (unlikely(!desc->disable_depth)) { | 177 | if (unlikely(!desc->disable_depth)) { |
| 178 | printk("enable_irq(%u) unbalanced from %p\n", irq, | 178 | printk("enable_irq(%u) unbalanced from %p\n", irq, |
| 179 | __builtin_return_address(0)); | 179 | __builtin_return_address(0)); |
| 180 | } else if (!--desc->disable_depth) { | 180 | } else if (!--desc->disable_depth) { |
| 181 | desc->probing = 0; | 181 | desc->probing = 0; |
| 182 | desc->chip->unmask(irq); | 182 | desc->chip->unmask(irq); |
| 183 | 183 | ||
| 184 | /* | 184 | /* |
| 185 | * If the interrupt is waiting to be processed, | 185 | * If the interrupt is waiting to be processed, |
| 186 | * try to re-run it. We can't directly run it | 186 | * try to re-run it. We can't directly run it |
| 187 | * from here since the caller might be in an | 187 | * from here since the caller might be in an |
| 188 | * interrupt-protected region. | 188 | * interrupt-protected region. |
| 189 | */ | 189 | */ |
| 190 | if (desc->pending && list_empty(&desc->pend)) { | 190 | if (desc->pending && list_empty(&desc->pend)) { |
| 191 | desc->pending = 0; | 191 | desc->pending = 0; |
| 192 | if (!desc->chip->retrigger || | 192 | if (!desc->chip->retrigger || |
| 193 | desc->chip->retrigger(irq)) | 193 | desc->chip->retrigger(irq)) |
| 194 | list_add(&desc->pend, &irq_pending); | 194 | list_add(&desc->pend, &irq_pending); |
| 195 | } | 195 | } |
| 196 | } | 196 | } |
| 197 | spin_unlock_irqrestore(&irq_controller_lock, flags); | 197 | spin_unlock_irqrestore(&irq_controller_lock, flags); |
| 198 | } | 198 | } |
| 199 | EXPORT_SYMBOL(enable_irq); | 199 | EXPORT_SYMBOL(enable_irq); |
| 200 | 200 | ||
| 201 | /* | 201 | /* |
| 202 | * Enable wake on selected irq | 202 | * Enable wake on selected irq |
| 203 | */ | 203 | */ |
| 204 | void enable_irq_wake(unsigned int irq) | 204 | void enable_irq_wake(unsigned int irq) |
| 205 | { | 205 | { |
| 206 | struct irqdesc *desc = irq_desc + irq; | 206 | struct irqdesc *desc = irq_desc + irq; |
| 207 | unsigned long flags; | 207 | unsigned long flags; |
| 208 | 208 | ||
| 209 | spin_lock_irqsave(&irq_controller_lock, flags); | 209 | spin_lock_irqsave(&irq_controller_lock, flags); |
| 210 | if (desc->chip->wake) | 210 | if (desc->chip->set_wake) |
| 211 | desc->chip->wake(irq, 1); | 211 | desc->chip->set_wake(irq, 1); |
| 212 | spin_unlock_irqrestore(&irq_controller_lock, flags); | 212 | spin_unlock_irqrestore(&irq_controller_lock, flags); |
| 213 | } | 213 | } |
| 214 | EXPORT_SYMBOL(enable_irq_wake); | 214 | EXPORT_SYMBOL(enable_irq_wake); |
| 215 | 215 | ||
| 216 | void disable_irq_wake(unsigned int irq) | 216 | void disable_irq_wake(unsigned int irq) |
| 217 | { | 217 | { |
| 218 | struct irqdesc *desc = irq_desc + irq; | 218 | struct irqdesc *desc = irq_desc + irq; |
| 219 | unsigned long flags; | 219 | unsigned long flags; |
| 220 | 220 | ||
| 221 | spin_lock_irqsave(&irq_controller_lock, flags); | 221 | spin_lock_irqsave(&irq_controller_lock, flags); |
| 222 | if (desc->chip->wake) | 222 | if (desc->chip->set_wake) |
| 223 | desc->chip->wake(irq, 0); | 223 | desc->chip->set_wake(irq, 0); |
| 224 | spin_unlock_irqrestore(&irq_controller_lock, flags); | 224 | spin_unlock_irqrestore(&irq_controller_lock, flags); |
| 225 | } | 225 | } |
| 226 | EXPORT_SYMBOL(disable_irq_wake); | 226 | EXPORT_SYMBOL(disable_irq_wake); |
| 227 | 227 | ||
| 228 | int show_interrupts(struct seq_file *p, void *v) | 228 | int show_interrupts(struct seq_file *p, void *v) |
| 229 | { | 229 | { |
| 230 | int i = *(loff_t *) v, cpu; | 230 | int i = *(loff_t *) v, cpu; |
| 231 | struct irqaction * action; | 231 | struct irqaction * action; |
| 232 | unsigned long flags; | 232 | unsigned long flags; |
| 233 | 233 | ||
| 234 | if (i == 0) { | 234 | if (i == 0) { |
| 235 | char cpuname[12]; | 235 | char cpuname[12]; |
| 236 | 236 | ||
| 237 | seq_printf(p, " "); | 237 | seq_printf(p, " "); |
| 238 | for_each_present_cpu(cpu) { | 238 | for_each_present_cpu(cpu) { |
| 239 | sprintf(cpuname, "CPU%d", cpu); | 239 | sprintf(cpuname, "CPU%d", cpu); |
| 240 | seq_printf(p, " %10s", cpuname); | 240 | seq_printf(p, " %10s", cpuname); |
| 241 | } | 241 | } |
| 242 | seq_putc(p, '\n'); | 242 | seq_putc(p, '\n'); |
| 243 | } | 243 | } |
| 244 | 244 | ||
| 245 | if (i < NR_IRQS) { | 245 | if (i < NR_IRQS) { |
| 246 | spin_lock_irqsave(&irq_controller_lock, flags); | 246 | spin_lock_irqsave(&irq_controller_lock, flags); |
| 247 | action = irq_desc[i].action; | 247 | action = irq_desc[i].action; |
| 248 | if (!action) | 248 | if (!action) |
| 249 | goto unlock; | 249 | goto unlock; |
| 250 | 250 | ||
| 251 | seq_printf(p, "%3d: ", i); | 251 | seq_printf(p, "%3d: ", i); |
| 252 | for_each_present_cpu(cpu) | 252 | for_each_present_cpu(cpu) |
| 253 | seq_printf(p, "%10u ", kstat_cpu(cpu).irqs[i]); | 253 | seq_printf(p, "%10u ", kstat_cpu(cpu).irqs[i]); |
| 254 | seq_printf(p, " %s", action->name); | 254 | seq_printf(p, " %s", action->name); |
| 255 | for (action = action->next; action; action = action->next) | 255 | for (action = action->next; action; action = action->next) |
| 256 | seq_printf(p, ", %s", action->name); | 256 | seq_printf(p, ", %s", action->name); |
| 257 | 257 | ||
| 258 | seq_putc(p, '\n'); | 258 | seq_putc(p, '\n'); |
| 259 | unlock: | 259 | unlock: |
| 260 | spin_unlock_irqrestore(&irq_controller_lock, flags); | 260 | spin_unlock_irqrestore(&irq_controller_lock, flags); |
| 261 | } else if (i == NR_IRQS) { | 261 | } else if (i == NR_IRQS) { |
| 262 | #ifdef CONFIG_ARCH_ACORN | 262 | #ifdef CONFIG_ARCH_ACORN |
| 263 | show_fiq_list(p, v); | 263 | show_fiq_list(p, v); |
| 264 | #endif | 264 | #endif |
| 265 | #ifdef CONFIG_SMP | 265 | #ifdef CONFIG_SMP |
| 266 | show_ipi_list(p); | 266 | show_ipi_list(p); |
| 267 | #endif | 267 | #endif |
| 268 | seq_printf(p, "Err: %10lu\n", irq_err_count); | 268 | seq_printf(p, "Err: %10lu\n", irq_err_count); |
| 269 | } | 269 | } |
| 270 | return 0; | 270 | return 0; |
| 271 | } | 271 | } |
| 272 | 272 | ||
| 273 | /* | 273 | /* |
| 274 | * IRQ lock detection. | 274 | * IRQ lock detection. |
| 275 | * | 275 | * |
| 276 | * Hopefully, this should get us out of a few locked situations. | 276 | * Hopefully, this should get us out of a few locked situations. |
| 277 | * However, it may take a while for this to happen, since we need | 277 | * However, it may take a while for this to happen, since we need |
| 278 | * a large number if IRQs to appear in the same jiffie with the | 278 | * a large number if IRQs to appear in the same jiffie with the |
| 279 | * same instruction pointer (or within 2 instructions). | 279 | * same instruction pointer (or within 2 instructions). |
| 280 | */ | 280 | */ |
| 281 | static int check_irq_lock(struct irqdesc *desc, int irq, struct pt_regs *regs) | 281 | static int check_irq_lock(struct irqdesc *desc, int irq, struct pt_regs *regs) |
| 282 | { | 282 | { |
| 283 | unsigned long instr_ptr = instruction_pointer(regs); | 283 | unsigned long instr_ptr = instruction_pointer(regs); |
| 284 | 284 | ||
| 285 | if (desc->lck_jif == jiffies && | 285 | if (desc->lck_jif == jiffies && |
| 286 | desc->lck_pc >= instr_ptr && desc->lck_pc < instr_ptr + 8) { | 286 | desc->lck_pc >= instr_ptr && desc->lck_pc < instr_ptr + 8) { |
| 287 | desc->lck_cnt += 1; | 287 | desc->lck_cnt += 1; |
| 288 | 288 | ||
| 289 | if (desc->lck_cnt > MAX_IRQ_CNT) { | 289 | if (desc->lck_cnt > MAX_IRQ_CNT) { |
| 290 | printk(KERN_ERR "IRQ LOCK: IRQ%d is locking the system, disabled\n", irq); | 290 | printk(KERN_ERR "IRQ LOCK: IRQ%d is locking the system, disabled\n", irq); |
| 291 | return 1; | 291 | return 1; |
| 292 | } | 292 | } |
| 293 | } else { | 293 | } else { |
| 294 | desc->lck_cnt = 0; | 294 | desc->lck_cnt = 0; |
| 295 | desc->lck_pc = instruction_pointer(regs); | 295 | desc->lck_pc = instruction_pointer(regs); |
| 296 | desc->lck_jif = jiffies; | 296 | desc->lck_jif = jiffies; |
| 297 | } | 297 | } |
| 298 | return 0; | 298 | return 0; |
| 299 | } | 299 | } |
| 300 | 300 | ||
| 301 | static void | 301 | static void |
| 302 | report_bad_irq(unsigned int irq, struct pt_regs *regs, struct irqdesc *desc, int ret) | 302 | report_bad_irq(unsigned int irq, struct pt_regs *regs, struct irqdesc *desc, int ret) |
| 303 | { | 303 | { |
| 304 | static int count = 100; | 304 | static int count = 100; |
| 305 | struct irqaction *action; | 305 | struct irqaction *action; |
| 306 | 306 | ||
| 307 | if (!count || noirqdebug) | 307 | if (!count || noirqdebug) |
| 308 | return; | 308 | return; |
| 309 | 309 | ||
| 310 | count--; | 310 | count--; |
| 311 | 311 | ||
| 312 | if (ret != IRQ_HANDLED && ret != IRQ_NONE) { | 312 | if (ret != IRQ_HANDLED && ret != IRQ_NONE) { |
| 313 | printk("irq%u: bogus retval mask %x\n", irq, ret); | 313 | printk("irq%u: bogus retval mask %x\n", irq, ret); |
| 314 | } else { | 314 | } else { |
| 315 | printk("irq%u: nobody cared\n", irq); | 315 | printk("irq%u: nobody cared\n", irq); |
| 316 | } | 316 | } |
| 317 | show_regs(regs); | 317 | show_regs(regs); |
| 318 | dump_stack(); | 318 | dump_stack(); |
| 319 | printk(KERN_ERR "handlers:"); | 319 | printk(KERN_ERR "handlers:"); |
| 320 | action = desc->action; | 320 | action = desc->action; |
| 321 | do { | 321 | do { |
| 322 | printk("\n" KERN_ERR "[<%p>]", action->handler); | 322 | printk("\n" KERN_ERR "[<%p>]", action->handler); |
| 323 | print_symbol(" (%s)", (unsigned long)action->handler); | 323 | print_symbol(" (%s)", (unsigned long)action->handler); |
| 324 | action = action->next; | 324 | action = action->next; |
| 325 | } while (action); | 325 | } while (action); |
| 326 | printk("\n"); | 326 | printk("\n"); |
| 327 | } | 327 | } |
| 328 | 328 | ||
| 329 | static int | 329 | static int |
| 330 | __do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs) | 330 | __do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs) |
| 331 | { | 331 | { |
| 332 | unsigned int status; | 332 | unsigned int status; |
| 333 | int ret, retval = 0; | 333 | int ret, retval = 0; |
| 334 | 334 | ||
| 335 | spin_unlock(&irq_controller_lock); | 335 | spin_unlock(&irq_controller_lock); |
| 336 | 336 | ||
| 337 | #ifdef CONFIG_NO_IDLE_HZ | 337 | #ifdef CONFIG_NO_IDLE_HZ |
| 338 | if (!(action->flags & SA_TIMER) && system_timer->dyn_tick != NULL) { | 338 | if (!(action->flags & SA_TIMER) && system_timer->dyn_tick != NULL) { |
| 339 | write_seqlock(&xtime_lock); | 339 | write_seqlock(&xtime_lock); |
| 340 | if (system_timer->dyn_tick->state & DYN_TICK_ENABLED) | 340 | if (system_timer->dyn_tick->state & DYN_TICK_ENABLED) |
| 341 | system_timer->dyn_tick->handler(irq, 0, regs); | 341 | system_timer->dyn_tick->handler(irq, 0, regs); |
| 342 | write_sequnlock(&xtime_lock); | 342 | write_sequnlock(&xtime_lock); |
| 343 | } | 343 | } |
| 344 | #endif | 344 | #endif |
| 345 | 345 | ||
| 346 | if (!(action->flags & SA_INTERRUPT)) | 346 | if (!(action->flags & SA_INTERRUPT)) |
| 347 | local_irq_enable(); | 347 | local_irq_enable(); |
| 348 | 348 | ||
| 349 | status = 0; | 349 | status = 0; |
| 350 | do { | 350 | do { |
| 351 | ret = action->handler(irq, action->dev_id, regs); | 351 | ret = action->handler(irq, action->dev_id, regs); |
| 352 | if (ret == IRQ_HANDLED) | 352 | if (ret == IRQ_HANDLED) |
| 353 | status |= action->flags; | 353 | status |= action->flags; |
| 354 | retval |= ret; | 354 | retval |= ret; |
| 355 | action = action->next; | 355 | action = action->next; |
| 356 | } while (action); | 356 | } while (action); |
| 357 | 357 | ||
| 358 | if (status & SA_SAMPLE_RANDOM) | 358 | if (status & SA_SAMPLE_RANDOM) |
| 359 | add_interrupt_randomness(irq); | 359 | add_interrupt_randomness(irq); |
| 360 | 360 | ||
| 361 | spin_lock_irq(&irq_controller_lock); | 361 | spin_lock_irq(&irq_controller_lock); |
| 362 | 362 | ||
| 363 | return retval; | 363 | return retval; |
| 364 | } | 364 | } |
| 365 | 365 | ||
| 366 | /* | 366 | /* |
| 367 | * This is for software-decoded IRQs. The caller is expected to | 367 | * This is for software-decoded IRQs. The caller is expected to |
| 368 | * handle the ack, clear, mask and unmask issues. | 368 | * handle the ack, clear, mask and unmask issues. |
| 369 | */ | 369 | */ |
| 370 | void | 370 | void |
| 371 | do_simple_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) | 371 | do_simple_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) |
| 372 | { | 372 | { |
| 373 | struct irqaction *action; | 373 | struct irqaction *action; |
| 374 | const unsigned int cpu = smp_processor_id(); | 374 | const unsigned int cpu = smp_processor_id(); |
| 375 | 375 | ||
| 376 | desc->triggered = 1; | 376 | desc->triggered = 1; |
| 377 | 377 | ||
| 378 | kstat_cpu(cpu).irqs[irq]++; | 378 | kstat_cpu(cpu).irqs[irq]++; |
| 379 | 379 | ||
| 380 | smp_set_running(desc); | 380 | smp_set_running(desc); |
| 381 | 381 | ||
| 382 | action = desc->action; | 382 | action = desc->action; |
| 383 | if (action) { | 383 | if (action) { |
| 384 | int ret = __do_irq(irq, action, regs); | 384 | int ret = __do_irq(irq, action, regs); |
| 385 | if (ret != IRQ_HANDLED) | 385 | if (ret != IRQ_HANDLED) |
| 386 | report_bad_irq(irq, regs, desc, ret); | 386 | report_bad_irq(irq, regs, desc, ret); |
| 387 | } | 387 | } |
| 388 | 388 | ||
| 389 | smp_clear_running(desc); | 389 | smp_clear_running(desc); |
| 390 | } | 390 | } |
| 391 | 391 | ||
| 392 | /* | 392 | /* |
| 393 | * Most edge-triggered IRQ implementations seem to take a broken | 393 | * Most edge-triggered IRQ implementations seem to take a broken |
| 394 | * approach to this. Hence the complexity. | 394 | * approach to this. Hence the complexity. |
| 395 | */ | 395 | */ |
| 396 | void | 396 | void |
| 397 | do_edge_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) | 397 | do_edge_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) |
| 398 | { | 398 | { |
| 399 | const unsigned int cpu = smp_processor_id(); | 399 | const unsigned int cpu = smp_processor_id(); |
| 400 | 400 | ||
| 401 | desc->triggered = 1; | 401 | desc->triggered = 1; |
| 402 | 402 | ||
| 403 | /* | 403 | /* |
| 404 | * If we're currently running this IRQ, or its disabled, | 404 | * If we're currently running this IRQ, or its disabled, |
| 405 | * we shouldn't process the IRQ. Instead, turn on the | 405 | * we shouldn't process the IRQ. Instead, turn on the |
| 406 | * hardware masks. | 406 | * hardware masks. |
| 407 | */ | 407 | */ |
| 408 | if (unlikely(desc->running || desc->disable_depth)) | 408 | if (unlikely(desc->running || desc->disable_depth)) |
| 409 | goto running; | 409 | goto running; |
| 410 | 410 | ||
| 411 | /* | 411 | /* |
| 412 | * Acknowledge and clear the IRQ, but don't mask it. | 412 | * Acknowledge and clear the IRQ, but don't mask it. |
| 413 | */ | 413 | */ |
| 414 | desc->chip->ack(irq); | 414 | desc->chip->ack(irq); |
| 415 | 415 | ||
| 416 | /* | 416 | /* |
| 417 | * Mark the IRQ currently in progress. | 417 | * Mark the IRQ currently in progress. |
| 418 | */ | 418 | */ |
| 419 | desc->running = 1; | 419 | desc->running = 1; |
| 420 | 420 | ||
| 421 | kstat_cpu(cpu).irqs[irq]++; | 421 | kstat_cpu(cpu).irqs[irq]++; |
| 422 | 422 | ||
| 423 | do { | 423 | do { |
| 424 | struct irqaction *action; | 424 | struct irqaction *action; |
| 425 | 425 | ||
| 426 | action = desc->action; | 426 | action = desc->action; |
| 427 | if (!action) | 427 | if (!action) |
| 428 | break; | 428 | break; |
| 429 | 429 | ||
| 430 | if (desc->pending && !desc->disable_depth) { | 430 | if (desc->pending && !desc->disable_depth) { |
| 431 | desc->pending = 0; | 431 | desc->pending = 0; |
| 432 | desc->chip->unmask(irq); | 432 | desc->chip->unmask(irq); |
| 433 | } | 433 | } |
| 434 | 434 | ||
| 435 | __do_irq(irq, action, regs); | 435 | __do_irq(irq, action, regs); |
| 436 | } while (desc->pending && !desc->disable_depth); | 436 | } while (desc->pending && !desc->disable_depth); |
| 437 | 437 | ||
| 438 | desc->running = 0; | 438 | desc->running = 0; |
| 439 | 439 | ||
| 440 | /* | 440 | /* |
| 441 | * If we were disabled or freed, shut down the handler. | 441 | * If we were disabled or freed, shut down the handler. |
| 442 | */ | 442 | */ |
| 443 | if (likely(desc->action && !check_irq_lock(desc, irq, regs))) | 443 | if (likely(desc->action && !check_irq_lock(desc, irq, regs))) |
| 444 | return; | 444 | return; |
| 445 | 445 | ||
| 446 | running: | 446 | running: |
| 447 | /* | 447 | /* |
| 448 | * We got another IRQ while this one was masked or | 448 | * We got another IRQ while this one was masked or |
| 449 | * currently running. Delay it. | 449 | * currently running. Delay it. |
| 450 | */ | 450 | */ |
| 451 | desc->pending = 1; | 451 | desc->pending = 1; |
| 452 | desc->chip->mask(irq); | 452 | desc->chip->mask(irq); |
| 453 | desc->chip->ack(irq); | 453 | desc->chip->ack(irq); |
| 454 | } | 454 | } |
| 455 | 455 | ||
| 456 | /* | 456 | /* |
| 457 | * Level-based IRQ handler. Nice and simple. | 457 | * Level-based IRQ handler. Nice and simple. |
| 458 | */ | 458 | */ |
| 459 | void | 459 | void |
| 460 | do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) | 460 | do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) |
| 461 | { | 461 | { |
| 462 | struct irqaction *action; | 462 | struct irqaction *action; |
| 463 | const unsigned int cpu = smp_processor_id(); | 463 | const unsigned int cpu = smp_processor_id(); |
| 464 | 464 | ||
| 465 | desc->triggered = 1; | 465 | desc->triggered = 1; |
| 466 | 466 | ||
| 467 | /* | 467 | /* |
| 468 | * Acknowledge, clear _AND_ disable the interrupt. | 468 | * Acknowledge, clear _AND_ disable the interrupt. |
| 469 | */ | 469 | */ |
| 470 | desc->chip->ack(irq); | 470 | desc->chip->ack(irq); |
| 471 | 471 | ||
| 472 | if (likely(!desc->disable_depth)) { | 472 | if (likely(!desc->disable_depth)) { |
| 473 | kstat_cpu(cpu).irqs[irq]++; | 473 | kstat_cpu(cpu).irqs[irq]++; |
| 474 | 474 | ||
| 475 | smp_set_running(desc); | 475 | smp_set_running(desc); |
| 476 | 476 | ||
| 477 | /* | 477 | /* |
| 478 | * Return with this interrupt masked if no action | 478 | * Return with this interrupt masked if no action |
| 479 | */ | 479 | */ |
| 480 | action = desc->action; | 480 | action = desc->action; |
| 481 | if (action) { | 481 | if (action) { |
| 482 | int ret = __do_irq(irq, desc->action, regs); | 482 | int ret = __do_irq(irq, desc->action, regs); |
| 483 | 483 | ||
| 484 | if (ret != IRQ_HANDLED) | 484 | if (ret != IRQ_HANDLED) |
| 485 | report_bad_irq(irq, regs, desc, ret); | 485 | report_bad_irq(irq, regs, desc, ret); |
| 486 | 486 | ||
| 487 | if (likely(!desc->disable_depth && | 487 | if (likely(!desc->disable_depth && |
| 488 | !check_irq_lock(desc, irq, regs))) | 488 | !check_irq_lock(desc, irq, regs))) |
| 489 | desc->chip->unmask(irq); | 489 | desc->chip->unmask(irq); |
| 490 | } | 490 | } |
| 491 | 491 | ||
| 492 | smp_clear_running(desc); | 492 | smp_clear_running(desc); |
| 493 | } | 493 | } |
| 494 | } | 494 | } |
| 495 | 495 | ||
| 496 | static void do_pending_irqs(struct pt_regs *regs) | 496 | static void do_pending_irqs(struct pt_regs *regs) |
| 497 | { | 497 | { |
| 498 | struct list_head head, *l, *n; | 498 | struct list_head head, *l, *n; |
| 499 | 499 | ||
| 500 | do { | 500 | do { |
| 501 | struct irqdesc *desc; | 501 | struct irqdesc *desc; |
| 502 | 502 | ||
| 503 | /* | 503 | /* |
| 504 | * First, take the pending interrupts off the list. | 504 | * First, take the pending interrupts off the list. |
| 505 | * The act of calling the handlers may add some IRQs | 505 | * The act of calling the handlers may add some IRQs |
| 506 | * back onto the list. | 506 | * back onto the list. |
| 507 | */ | 507 | */ |
| 508 | head = irq_pending; | 508 | head = irq_pending; |
| 509 | INIT_LIST_HEAD(&irq_pending); | 509 | INIT_LIST_HEAD(&irq_pending); |
| 510 | head.next->prev = &head; | 510 | head.next->prev = &head; |
| 511 | head.prev->next = &head; | 511 | head.prev->next = &head; |
| 512 | 512 | ||
| 513 | /* | 513 | /* |
| 514 | * Now run each entry. We must delete it from our | 514 | * Now run each entry. We must delete it from our |
| 515 | * list before calling the handler. | 515 | * list before calling the handler. |
| 516 | */ | 516 | */ |
| 517 | list_for_each_safe(l, n, &head) { | 517 | list_for_each_safe(l, n, &head) { |
| 518 | desc = list_entry(l, struct irqdesc, pend); | 518 | desc = list_entry(l, struct irqdesc, pend); |
| 519 | list_del_init(&desc->pend); | 519 | list_del_init(&desc->pend); |
| 520 | desc->handle(desc - irq_desc, desc, regs); | 520 | desc_handle_irq(desc - irq_desc, desc, regs); |
| 521 | } | 521 | } |
| 522 | 522 | ||
| 523 | /* | 523 | /* |
| 524 | * The list must be empty. | 524 | * The list must be empty. |
| 525 | */ | 525 | */ |
| 526 | BUG_ON(!list_empty(&head)); | 526 | BUG_ON(!list_empty(&head)); |
| 527 | } while (!list_empty(&irq_pending)); | 527 | } while (!list_empty(&irq_pending)); |
| 528 | } | 528 | } |
| 529 | 529 | ||
| 530 | /* | 530 | /* |
| 531 | * do_IRQ handles all hardware IRQ's. Decoded IRQs should not | 531 | * do_IRQ handles all hardware IRQ's. Decoded IRQs should not |
| 532 | * come via this function. Instead, they should provide their | 532 | * come via this function. Instead, they should provide their |
| 533 | * own 'handler' | 533 | * own 'handler' |
| 534 | */ | 534 | */ |
| 535 | asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs) | 535 | asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs) |
| 536 | { | 536 | { |
| 537 | struct irqdesc *desc = irq_desc + irq; | 537 | struct irqdesc *desc = irq_desc + irq; |
| 538 | 538 | ||
| 539 | /* | 539 | /* |
| 540 | * Some hardware gives randomly wrong interrupts. Rather | 540 | * Some hardware gives randomly wrong interrupts. Rather |
| 541 | * than crashing, do something sensible. | 541 | * than crashing, do something sensible. |
| 542 | */ | 542 | */ |
| 543 | if (irq >= NR_IRQS) | 543 | if (irq >= NR_IRQS) |
| 544 | desc = &bad_irq_desc; | 544 | desc = &bad_irq_desc; |
| 545 | 545 | ||
| 546 | irq_enter(); | 546 | irq_enter(); |
| 547 | spin_lock(&irq_controller_lock); | 547 | spin_lock(&irq_controller_lock); |
| 548 | desc->handle(irq, desc, regs); | 548 | desc_handle_irq(irq, desc, regs); |
| 549 | 549 | ||
| 550 | /* | 550 | /* |
| 551 | * Now re-run any pending interrupts. | 551 | * Now re-run any pending interrupts. |
| 552 | */ | 552 | */ |
| 553 | if (!list_empty(&irq_pending)) | 553 | if (!list_empty(&irq_pending)) |
| 554 | do_pending_irqs(regs); | 554 | do_pending_irqs(regs); |
| 555 | 555 | ||
| 556 | irq_finish(irq); | 556 | irq_finish(irq); |
| 557 | 557 | ||
| 558 | spin_unlock(&irq_controller_lock); | 558 | spin_unlock(&irq_controller_lock); |
| 559 | irq_exit(); | 559 | irq_exit(); |
| 560 | } | 560 | } |
| 561 | 561 | ||
| 562 | void __set_irq_handler(unsigned int irq, irq_handler_t handle, int is_chained) | 562 | void __set_irq_handler(unsigned int irq, irq_handler_t handle, int is_chained) |
| 563 | { | 563 | { |
| 564 | struct irqdesc *desc; | 564 | struct irqdesc *desc; |
| 565 | unsigned long flags; | 565 | unsigned long flags; |
| 566 | 566 | ||
| 567 | if (irq >= NR_IRQS) { | 567 | if (irq >= NR_IRQS) { |
| 568 | printk(KERN_ERR "Trying to install handler for IRQ%d\n", irq); | 568 | printk(KERN_ERR "Trying to install handler for IRQ%d\n", irq); |
| 569 | return; | 569 | return; |
| 570 | } | 570 | } |
| 571 | 571 | ||
| 572 | if (handle == NULL) | 572 | if (handle == NULL) |
| 573 | handle = do_bad_IRQ; | 573 | handle = do_bad_IRQ; |
| 574 | 574 | ||
| 575 | desc = irq_desc + irq; | 575 | desc = irq_desc + irq; |
| 576 | 576 | ||
| 577 | if (is_chained && desc->chip == &bad_chip) | 577 | if (is_chained && desc->chip == &bad_chip) |
| 578 | printk(KERN_WARNING "Trying to install chained handler for IRQ%d\n", irq); | 578 | printk(KERN_WARNING "Trying to install chained handler for IRQ%d\n", irq); |
| 579 | 579 | ||
| 580 | spin_lock_irqsave(&irq_controller_lock, flags); | 580 | spin_lock_irqsave(&irq_controller_lock, flags); |
| 581 | if (handle == do_bad_IRQ) { | 581 | if (handle == do_bad_IRQ) { |
| 582 | desc->chip->mask(irq); | 582 | desc->chip->mask(irq); |
| 583 | desc->chip->ack(irq); | 583 | desc->chip->ack(irq); |
| 584 | desc->disable_depth = 1; | 584 | desc->disable_depth = 1; |
| 585 | } | 585 | } |
| 586 | desc->handle = handle; | 586 | desc->handle = handle; |
| 587 | if (handle != do_bad_IRQ && is_chained) { | 587 | if (handle != do_bad_IRQ && is_chained) { |
| 588 | desc->valid = 0; | 588 | desc->valid = 0; |
| 589 | desc->probe_ok = 0; | 589 | desc->probe_ok = 0; |
| 590 | desc->disable_depth = 0; | 590 | desc->disable_depth = 0; |
| 591 | desc->chip->unmask(irq); | 591 | desc->chip->unmask(irq); |
| 592 | } | 592 | } |
| 593 | spin_unlock_irqrestore(&irq_controller_lock, flags); | 593 | spin_unlock_irqrestore(&irq_controller_lock, flags); |
| 594 | } | 594 | } |
| 595 | 595 | ||
| 596 | void set_irq_chip(unsigned int irq, struct irqchip *chip) | 596 | void set_irq_chip(unsigned int irq, struct irqchip *chip) |
| 597 | { | 597 | { |
| 598 | struct irqdesc *desc; | 598 | struct irqdesc *desc; |
| 599 | unsigned long flags; | 599 | unsigned long flags; |
| 600 | 600 | ||
| 601 | if (irq >= NR_IRQS) { | 601 | if (irq >= NR_IRQS) { |
| 602 | printk(KERN_ERR "Trying to install chip for IRQ%d\n", irq); | 602 | printk(KERN_ERR "Trying to install chip for IRQ%d\n", irq); |
| 603 | return; | 603 | return; |
| 604 | } | 604 | } |
| 605 | 605 | ||
| 606 | if (chip == NULL) | 606 | if (chip == NULL) |
| 607 | chip = &bad_chip; | 607 | chip = &bad_chip; |
| 608 | 608 | ||
| 609 | desc = irq_desc + irq; | 609 | desc = irq_desc + irq; |
| 610 | spin_lock_irqsave(&irq_controller_lock, flags); | 610 | spin_lock_irqsave(&irq_controller_lock, flags); |
| 611 | desc->chip = chip; | 611 | desc->chip = chip; |
| 612 | spin_unlock_irqrestore(&irq_controller_lock, flags); | 612 | spin_unlock_irqrestore(&irq_controller_lock, flags); |
| 613 | } | 613 | } |
| 614 | 614 | ||
| 615 | int set_irq_type(unsigned int irq, unsigned int type) | 615 | int set_irq_type(unsigned int irq, unsigned int type) |
| 616 | { | 616 | { |
| 617 | struct irqdesc *desc; | 617 | struct irqdesc *desc; |
| 618 | unsigned long flags; | 618 | unsigned long flags; |
| 619 | int ret = -ENXIO; | 619 | int ret = -ENXIO; |
| 620 | 620 | ||
| 621 | if (irq >= NR_IRQS) { | 621 | if (irq >= NR_IRQS) { |
| 622 | printk(KERN_ERR "Trying to set irq type for IRQ%d\n", irq); | 622 | printk(KERN_ERR "Trying to set irq type for IRQ%d\n", irq); |
| 623 | return -ENODEV; | 623 | return -ENODEV; |
| 624 | } | 624 | } |
| 625 | 625 | ||
| 626 | desc = irq_desc + irq; | 626 | desc = irq_desc + irq; |
| 627 | if (desc->chip->type) { | 627 | if (desc->chip->set_type) { |
| 628 | spin_lock_irqsave(&irq_controller_lock, flags); | 628 | spin_lock_irqsave(&irq_controller_lock, flags); |
| 629 | ret = desc->chip->type(irq, type); | 629 | ret = desc->chip->set_type(irq, type); |
| 630 | spin_unlock_irqrestore(&irq_controller_lock, flags); | 630 | spin_unlock_irqrestore(&irq_controller_lock, flags); |
| 631 | } | 631 | } |
| 632 | 632 | ||
| 633 | return ret; | 633 | return ret; |
| 634 | } | 634 | } |
| 635 | EXPORT_SYMBOL(set_irq_type); | 635 | EXPORT_SYMBOL(set_irq_type); |
| 636 | 636 | ||
| 637 | void set_irq_flags(unsigned int irq, unsigned int iflags) | 637 | void set_irq_flags(unsigned int irq, unsigned int iflags) |
| 638 | { | 638 | { |
| 639 | struct irqdesc *desc; | 639 | struct irqdesc *desc; |
| 640 | unsigned long flags; | 640 | unsigned long flags; |
| 641 | 641 | ||
| 642 | if (irq >= NR_IRQS) { | 642 | if (irq >= NR_IRQS) { |
| 643 | printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq); | 643 | printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq); |
| 644 | return; | 644 | return; |
| 645 | } | 645 | } |
| 646 | 646 | ||
| 647 | desc = irq_desc + irq; | 647 | desc = irq_desc + irq; |
| 648 | spin_lock_irqsave(&irq_controller_lock, flags); | 648 | spin_lock_irqsave(&irq_controller_lock, flags); |
| 649 | desc->valid = (iflags & IRQF_VALID) != 0; | 649 | desc->valid = (iflags & IRQF_VALID) != 0; |
| 650 | desc->probe_ok = (iflags & IRQF_PROBE) != 0; | 650 | desc->probe_ok = (iflags & IRQF_PROBE) != 0; |
| 651 | desc->noautoenable = (iflags & IRQF_NOAUTOEN) != 0; | 651 | desc->noautoenable = (iflags & IRQF_NOAUTOEN) != 0; |
| 652 | spin_unlock_irqrestore(&irq_controller_lock, flags); | 652 | spin_unlock_irqrestore(&irq_controller_lock, flags); |
| 653 | } | 653 | } |
| 654 | 654 | ||
| 655 | int setup_irq(unsigned int irq, struct irqaction *new) | 655 | int setup_irq(unsigned int irq, struct irqaction *new) |
| 656 | { | 656 | { |
| 657 | int shared = 0; | 657 | int shared = 0; |
| 658 | struct irqaction *old, **p; | 658 | struct irqaction *old, **p; |
| 659 | unsigned long flags; | 659 | unsigned long flags; |
| 660 | struct irqdesc *desc; | 660 | struct irqdesc *desc; |
| 661 | 661 | ||
| 662 | /* | 662 | /* |
| 663 | * Some drivers like serial.c use request_irq() heavily, | 663 | * Some drivers like serial.c use request_irq() heavily, |
| 664 | * so we have to be careful not to interfere with a | 664 | * so we have to be careful not to interfere with a |
| 665 | * running system. | 665 | * running system. |
| 666 | */ | 666 | */ |
| 667 | if (new->flags & SA_SAMPLE_RANDOM) { | 667 | if (new->flags & SA_SAMPLE_RANDOM) { |
| 668 | /* | 668 | /* |
| 669 | * This function might sleep, we want to call it first, | 669 | * This function might sleep, we want to call it first, |
| 670 | * outside of the atomic block. | 670 | * outside of the atomic block. |
| 671 | * Yes, this might clear the entropy pool if the wrong | 671 | * Yes, this might clear the entropy pool if the wrong |
| 672 | * driver is attempted to be loaded, without actually | 672 | * driver is attempted to be loaded, without actually |
| 673 | * installing a new handler, but is this really a problem, | 673 | * installing a new handler, but is this really a problem, |
| 674 | * only the sysadmin is able to do this. | 674 | * only the sysadmin is able to do this. |
| 675 | */ | 675 | */ |
| 676 | rand_initialize_irq(irq); | 676 | rand_initialize_irq(irq); |
| 677 | } | 677 | } |
| 678 | 678 | ||
| 679 | /* | 679 | /* |
| 680 | * The following block of code has to be executed atomically | 680 | * The following block of code has to be executed atomically |
| 681 | */ | 681 | */ |
| 682 | desc = irq_desc + irq; | 682 | desc = irq_desc + irq; |
| 683 | spin_lock_irqsave(&irq_controller_lock, flags); | 683 | spin_lock_irqsave(&irq_controller_lock, flags); |
| 684 | p = &desc->action; | 684 | p = &desc->action; |
| 685 | if ((old = *p) != NULL) { | 685 | if ((old = *p) != NULL) { |
| 686 | /* Can't share interrupts unless both agree to */ | 686 | /* Can't share interrupts unless both agree to */ |
| 687 | if (!(old->flags & new->flags & SA_SHIRQ)) { | 687 | if (!(old->flags & new->flags & SA_SHIRQ)) { |
| 688 | spin_unlock_irqrestore(&irq_controller_lock, flags); | 688 | spin_unlock_irqrestore(&irq_controller_lock, flags); |
| 689 | return -EBUSY; | 689 | return -EBUSY; |
| 690 | } | 690 | } |
| 691 | 691 | ||
| 692 | /* add new interrupt at end of irq queue */ | 692 | /* add new interrupt at end of irq queue */ |
| 693 | do { | 693 | do { |
| 694 | p = &old->next; | 694 | p = &old->next; |
| 695 | old = *p; | 695 | old = *p; |
| 696 | } while (old); | 696 | } while (old); |
| 697 | shared = 1; | 697 | shared = 1; |
| 698 | } | 698 | } |
| 699 | 699 | ||
| 700 | *p = new; | 700 | *p = new; |
| 701 | 701 | ||
| 702 | if (!shared) { | 702 | if (!shared) { |
| 703 | desc->probing = 0; | 703 | desc->probing = 0; |
| 704 | desc->running = 0; | 704 | desc->running = 0; |
| 705 | desc->pending = 0; | 705 | desc->pending = 0; |
| 706 | desc->disable_depth = 1; | 706 | desc->disable_depth = 1; |
| 707 | if (!desc->noautoenable) { | 707 | if (!desc->noautoenable) { |
| 708 | desc->disable_depth = 0; | 708 | desc->disable_depth = 0; |
| 709 | desc->chip->unmask(irq); | 709 | desc->chip->unmask(irq); |
| 710 | } | 710 | } |
| 711 | } | 711 | } |
| 712 | 712 | ||
| 713 | spin_unlock_irqrestore(&irq_controller_lock, flags); | 713 | spin_unlock_irqrestore(&irq_controller_lock, flags); |
| 714 | return 0; | 714 | return 0; |
| 715 | } | 715 | } |
| 716 | 716 | ||
| 717 | /** | 717 | /** |
| 718 | * request_irq - allocate an interrupt line | 718 | * request_irq - allocate an interrupt line |
| 719 | * @irq: Interrupt line to allocate | 719 | * @irq: Interrupt line to allocate |
| 720 | * @handler: Function to be called when the IRQ occurs | 720 | * @handler: Function to be called when the IRQ occurs |
| 721 | * @irqflags: Interrupt type flags | 721 | * @irqflags: Interrupt type flags |
| 722 | * @devname: An ascii name for the claiming device | 722 | * @devname: An ascii name for the claiming device |
| 723 | * @dev_id: A cookie passed back to the handler function | 723 | * @dev_id: A cookie passed back to the handler function |
| 724 | * | 724 | * |
| 725 | * This call allocates interrupt resources and enables the | 725 | * This call allocates interrupt resources and enables the |
| 726 | * interrupt line and IRQ handling. From the point this | 726 | * interrupt line and IRQ handling. From the point this |
| 727 | * call is made your handler function may be invoked. Since | 727 | * call is made your handler function may be invoked. Since |
| 728 | * your handler function must clear any interrupt the board | 728 | * your handler function must clear any interrupt the board |
| 729 | * raises, you must take care both to initialise your hardware | 729 | * raises, you must take care both to initialise your hardware |
| 730 | * and to set up the interrupt handler in the right order. | 730 | * and to set up the interrupt handler in the right order. |
| 731 | * | 731 | * |
| 732 | * Dev_id must be globally unique. Normally the address of the | 732 | * Dev_id must be globally unique. Normally the address of the |
| 733 | * device data structure is used as the cookie. Since the handler | 733 | * device data structure is used as the cookie. Since the handler |
| 734 | * receives this value it makes sense to use it. | 734 | * receives this value it makes sense to use it. |
| 735 | * | 735 | * |
| 736 | * If your interrupt is shared you must pass a non NULL dev_id | 736 | * If your interrupt is shared you must pass a non NULL dev_id |
| 737 | * as this is required when freeing the interrupt. | 737 | * as this is required when freeing the interrupt. |
| 738 | * | 738 | * |
| 739 | * Flags: | 739 | * Flags: |
| 740 | * | 740 | * |
| 741 | * SA_SHIRQ Interrupt is shared | 741 | * SA_SHIRQ Interrupt is shared |
| 742 | * | 742 | * |
| 743 | * SA_INTERRUPT Disable local interrupts while processing | 743 | * SA_INTERRUPT Disable local interrupts while processing |
| 744 | * | 744 | * |
| 745 | * SA_SAMPLE_RANDOM The interrupt can be used for entropy | 745 | * SA_SAMPLE_RANDOM The interrupt can be used for entropy |
| 746 | * | 746 | * |
| 747 | */ | 747 | */ |
| 748 | int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), | 748 | int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), |
| 749 | unsigned long irq_flags, const char * devname, void *dev_id) | 749 | unsigned long irq_flags, const char * devname, void *dev_id) |
| 750 | { | 750 | { |
| 751 | unsigned long retval; | 751 | unsigned long retval; |
| 752 | struct irqaction *action; | 752 | struct irqaction *action; |
| 753 | 753 | ||
| 754 | if (irq >= NR_IRQS || !irq_desc[irq].valid || !handler || | 754 | if (irq >= NR_IRQS || !irq_desc[irq].valid || !handler || |
| 755 | (irq_flags & SA_SHIRQ && !dev_id)) | 755 | (irq_flags & SA_SHIRQ && !dev_id)) |
| 756 | return -EINVAL; | 756 | return -EINVAL; |
| 757 | 757 | ||
| 758 | action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); | 758 | action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); |
| 759 | if (!action) | 759 | if (!action) |
| 760 | return -ENOMEM; | 760 | return -ENOMEM; |
| 761 | 761 | ||
| 762 | action->handler = handler; | 762 | action->handler = handler; |
| 763 | action->flags = irq_flags; | 763 | action->flags = irq_flags; |
| 764 | cpus_clear(action->mask); | 764 | cpus_clear(action->mask); |
| 765 | action->name = devname; | 765 | action->name = devname; |
| 766 | action->next = NULL; | 766 | action->next = NULL; |
| 767 | action->dev_id = dev_id; | 767 | action->dev_id = dev_id; |
| 768 | 768 | ||
| 769 | retval = setup_irq(irq, action); | 769 | retval = setup_irq(irq, action); |
| 770 | 770 | ||
| 771 | if (retval) | 771 | if (retval) |
| 772 | kfree(action); | 772 | kfree(action); |
| 773 | return retval; | 773 | return retval; |
| 774 | } | 774 | } |
| 775 | 775 | ||
| 776 | EXPORT_SYMBOL(request_irq); | 776 | EXPORT_SYMBOL(request_irq); |
| 777 | 777 | ||
| 778 | /** | 778 | /** |
| 779 | * free_irq - free an interrupt | 779 | * free_irq - free an interrupt |
| 780 | * @irq: Interrupt line to free | 780 | * @irq: Interrupt line to free |
| 781 | * @dev_id: Device identity to free | 781 | * @dev_id: Device identity to free |
| 782 | * | 782 | * |
| 783 | * Remove an interrupt handler. The handler is removed and if the | 783 | * Remove an interrupt handler. The handler is removed and if the |
| 784 | * interrupt line is no longer in use by any driver it is disabled. | 784 | * interrupt line is no longer in use by any driver it is disabled. |
| 785 | * On a shared IRQ the caller must ensure the interrupt is disabled | 785 | * On a shared IRQ the caller must ensure the interrupt is disabled |
| 786 | * on the card it drives before calling this function. | 786 | * on the card it drives before calling this function. |
| 787 | * | 787 | * |
| 788 | * This function must not be called from interrupt context. | 788 | * This function must not be called from interrupt context. |
| 789 | */ | 789 | */ |
| 790 | void free_irq(unsigned int irq, void *dev_id) | 790 | void free_irq(unsigned int irq, void *dev_id) |
| 791 | { | 791 | { |
| 792 | struct irqaction * action, **p; | 792 | struct irqaction * action, **p; |
| 793 | unsigned long flags; | 793 | unsigned long flags; |
| 794 | 794 | ||
| 795 | if (irq >= NR_IRQS || !irq_desc[irq].valid) { | 795 | if (irq >= NR_IRQS || !irq_desc[irq].valid) { |
| 796 | printk(KERN_ERR "Trying to free IRQ%d\n",irq); | 796 | printk(KERN_ERR "Trying to free IRQ%d\n",irq); |
| 797 | dump_stack(); | 797 | dump_stack(); |
| 798 | return; | 798 | return; |
| 799 | } | 799 | } |
| 800 | 800 | ||
| 801 | spin_lock_irqsave(&irq_controller_lock, flags); | 801 | spin_lock_irqsave(&irq_controller_lock, flags); |
| 802 | for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) { | 802 | for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) { |
| 803 | if (action->dev_id != dev_id) | 803 | if (action->dev_id != dev_id) |
| 804 | continue; | 804 | continue; |
| 805 | 805 | ||
| 806 | /* Found it - now free it */ | 806 | /* Found it - now free it */ |
| 807 | *p = action->next; | 807 | *p = action->next; |
| 808 | break; | 808 | break; |
| 809 | } | 809 | } |
| 810 | spin_unlock_irqrestore(&irq_controller_lock, flags); | 810 | spin_unlock_irqrestore(&irq_controller_lock, flags); |
| 811 | 811 | ||
| 812 | if (!action) { | 812 | if (!action) { |
| 813 | printk(KERN_ERR "Trying to free free IRQ%d\n",irq); | 813 | printk(KERN_ERR "Trying to free free IRQ%d\n",irq); |
| 814 | dump_stack(); | 814 | dump_stack(); |
| 815 | } else { | 815 | } else { |
| 816 | synchronize_irq(irq); | 816 | synchronize_irq(irq); |
| 817 | kfree(action); | 817 | kfree(action); |
| 818 | } | 818 | } |
| 819 | } | 819 | } |
| 820 | 820 | ||
| 821 | EXPORT_SYMBOL(free_irq); | 821 | EXPORT_SYMBOL(free_irq); |
| 822 | 822 | ||
| 823 | static DECLARE_MUTEX(probe_sem); | 823 | static DECLARE_MUTEX(probe_sem); |
| 824 | 824 | ||
| 825 | /* Start the interrupt probing. Unlike other architectures, | 825 | /* Start the interrupt probing. Unlike other architectures, |
| 826 | * we don't return a mask of interrupts from probe_irq_on, | 826 | * we don't return a mask of interrupts from probe_irq_on, |
| 827 | * but return the number of interrupts enabled for the probe. | 827 | * but return the number of interrupts enabled for the probe. |
| 828 | * The interrupts which have been enabled for probing is | 828 | * The interrupts which have been enabled for probing is |
| 829 | * instead recorded in the irq_desc structure. | 829 | * instead recorded in the irq_desc structure. |
| 830 | */ | 830 | */ |
| 831 | unsigned long probe_irq_on(void) | 831 | unsigned long probe_irq_on(void) |
| 832 | { | 832 | { |
| 833 | unsigned int i, irqs = 0; | 833 | unsigned int i, irqs = 0; |
| 834 | unsigned long delay; | 834 | unsigned long delay; |
| 835 | 835 | ||
| 836 | down(&probe_sem); | 836 | down(&probe_sem); |
| 837 | 837 | ||
| 838 | /* | 838 | /* |
| 839 | * first snaffle up any unassigned but | 839 | * first snaffle up any unassigned but |
| 840 | * probe-able interrupts | 840 | * probe-able interrupts |
| 841 | */ | 841 | */ |
| 842 | spin_lock_irq(&irq_controller_lock); | 842 | spin_lock_irq(&irq_controller_lock); |
| 843 | for (i = 0; i < NR_IRQS; i++) { | 843 | for (i = 0; i < NR_IRQS; i++) { |
| 844 | if (!irq_desc[i].probe_ok || irq_desc[i].action) | 844 | if (!irq_desc[i].probe_ok || irq_desc[i].action) |
| 845 | continue; | 845 | continue; |
| 846 | 846 | ||
| 847 | irq_desc[i].probing = 1; | 847 | irq_desc[i].probing = 1; |
| 848 | irq_desc[i].triggered = 0; | 848 | irq_desc[i].triggered = 0; |
| 849 | if (irq_desc[i].chip->type) | 849 | if (irq_desc[i].chip->set_type) |
| 850 | irq_desc[i].chip->type(i, IRQT_PROBE); | 850 | irq_desc[i].chip->set_type(i, IRQT_PROBE); |
| 851 | irq_desc[i].chip->unmask(i); | 851 | irq_desc[i].chip->unmask(i); |
| 852 | irqs += 1; | 852 | irqs += 1; |
| 853 | } | 853 | } |
| 854 | spin_unlock_irq(&irq_controller_lock); | 854 | spin_unlock_irq(&irq_controller_lock); |
| 855 | 855 | ||
| 856 | /* | 856 | /* |
| 857 | * wait for spurious interrupts to mask themselves out again | 857 | * wait for spurious interrupts to mask themselves out again |
| 858 | */ | 858 | */ |
| 859 | for (delay = jiffies + HZ/10; time_before(jiffies, delay); ) | 859 | for (delay = jiffies + HZ/10; time_before(jiffies, delay); ) |
| 860 | /* min 100ms delay */; | 860 | /* min 100ms delay */; |
| 861 | 861 | ||
| 862 | /* | 862 | /* |
| 863 | * now filter out any obviously spurious interrupts | 863 | * now filter out any obviously spurious interrupts |
| 864 | */ | 864 | */ |
| 865 | spin_lock_irq(&irq_controller_lock); | 865 | spin_lock_irq(&irq_controller_lock); |
| 866 | for (i = 0; i < NR_IRQS; i++) { | 866 | for (i = 0; i < NR_IRQS; i++) { |
| 867 | if (irq_desc[i].probing && irq_desc[i].triggered) { | 867 | if (irq_desc[i].probing && irq_desc[i].triggered) { |
| 868 | irq_desc[i].probing = 0; | 868 | irq_desc[i].probing = 0; |
| 869 | irqs -= 1; | 869 | irqs -= 1; |
| 870 | } | 870 | } |
| 871 | } | 871 | } |
| 872 | spin_unlock_irq(&irq_controller_lock); | 872 | spin_unlock_irq(&irq_controller_lock); |
| 873 | 873 | ||
| 874 | return irqs; | 874 | return irqs; |
| 875 | } | 875 | } |
| 876 | 876 | ||
| 877 | EXPORT_SYMBOL(probe_irq_on); | 877 | EXPORT_SYMBOL(probe_irq_on); |
| 878 | 878 | ||
| 879 | unsigned int probe_irq_mask(unsigned long irqs) | 879 | unsigned int probe_irq_mask(unsigned long irqs) |
| 880 | { | 880 | { |
| 881 | unsigned int mask = 0, i; | 881 | unsigned int mask = 0, i; |
| 882 | 882 | ||
| 883 | spin_lock_irq(&irq_controller_lock); | 883 | spin_lock_irq(&irq_controller_lock); |
| 884 | for (i = 0; i < 16 && i < NR_IRQS; i++) | 884 | for (i = 0; i < 16 && i < NR_IRQS; i++) |
| 885 | if (irq_desc[i].probing && irq_desc[i].triggered) | 885 | if (irq_desc[i].probing && irq_desc[i].triggered) |
| 886 | mask |= 1 << i; | 886 | mask |= 1 << i; |
| 887 | spin_unlock_irq(&irq_controller_lock); | 887 | spin_unlock_irq(&irq_controller_lock); |
| 888 | 888 | ||
| 889 | up(&probe_sem); | 889 | up(&probe_sem); |
| 890 | 890 | ||
| 891 | return mask; | 891 | return mask; |
| 892 | } | 892 | } |
| 893 | EXPORT_SYMBOL(probe_irq_mask); | 893 | EXPORT_SYMBOL(probe_irq_mask); |
| 894 | 894 | ||
| 895 | /* | 895 | /* |
| 896 | * Possible return values: | 896 | * Possible return values: |
| 897 | * >= 0 - interrupt number | 897 | * >= 0 - interrupt number |
| 898 | * -1 - no interrupt/many interrupts | 898 | * -1 - no interrupt/many interrupts |
| 899 | */ | 899 | */ |
| 900 | int probe_irq_off(unsigned long irqs) | 900 | int probe_irq_off(unsigned long irqs) |
| 901 | { | 901 | { |
| 902 | unsigned int i; | 902 | unsigned int i; |
| 903 | int irq_found = NO_IRQ; | 903 | int irq_found = NO_IRQ; |
| 904 | 904 | ||
| 905 | /* | 905 | /* |
| 906 | * look at the interrupts, and find exactly one | 906 | * look at the interrupts, and find exactly one |
| 907 | * that we were probing has been triggered | 907 | * that we were probing has been triggered |
| 908 | */ | 908 | */ |
| 909 | spin_lock_irq(&irq_controller_lock); | 909 | spin_lock_irq(&irq_controller_lock); |
| 910 | for (i = 0; i < NR_IRQS; i++) { | 910 | for (i = 0; i < NR_IRQS; i++) { |
| 911 | if (irq_desc[i].probing && | 911 | if (irq_desc[i].probing && |
| 912 | irq_desc[i].triggered) { | 912 | irq_desc[i].triggered) { |
| 913 | if (irq_found != NO_IRQ) { | 913 | if (irq_found != NO_IRQ) { |
| 914 | irq_found = NO_IRQ; | 914 | irq_found = NO_IRQ; |
| 915 | goto out; | 915 | goto out; |
| 916 | } | 916 | } |
| 917 | irq_found = i; | 917 | irq_found = i; |
| 918 | } | 918 | } |
| 919 | } | 919 | } |
| 920 | 920 | ||
| 921 | if (irq_found == -1) | 921 | if (irq_found == -1) |
| 922 | irq_found = NO_IRQ; | 922 | irq_found = NO_IRQ; |
| 923 | out: | 923 | out: |
| 924 | spin_unlock_irq(&irq_controller_lock); | 924 | spin_unlock_irq(&irq_controller_lock); |
| 925 | 925 | ||
| 926 | up(&probe_sem); | 926 | up(&probe_sem); |
| 927 | 927 | ||
| 928 | return irq_found; | 928 | return irq_found; |
| 929 | } | 929 | } |
| 930 | 930 | ||
| 931 | EXPORT_SYMBOL(probe_irq_off); | 931 | EXPORT_SYMBOL(probe_irq_off); |
| 932 | 932 | ||
| 933 | #ifdef CONFIG_SMP | 933 | #ifdef CONFIG_SMP |
| 934 | static void route_irq(struct irqdesc *desc, unsigned int irq, unsigned int cpu) | 934 | static void route_irq(struct irqdesc *desc, unsigned int irq, unsigned int cpu) |
| 935 | { | 935 | { |
| 936 | pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", irq, desc->cpu, cpu); | 936 | pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", irq, desc->cpu, cpu); |
| 937 | 937 | ||
| 938 | spin_lock_irq(&irq_controller_lock); | 938 | spin_lock_irq(&irq_controller_lock); |
| 939 | desc->cpu = cpu; | 939 | desc->cpu = cpu; |
| 940 | desc->chip->set_cpu(desc, irq, cpu); | 940 | desc->chip->set_cpu(desc, irq, cpu); |
| 941 | spin_unlock_irq(&irq_controller_lock); | 941 | spin_unlock_irq(&irq_controller_lock); |
| 942 | } | 942 | } |
| 943 | 943 | ||
| 944 | #ifdef CONFIG_PROC_FS | 944 | #ifdef CONFIG_PROC_FS |
| 945 | static int | 945 | static int |
| 946 | irq_affinity_read_proc(char *page, char **start, off_t off, int count, | 946 | irq_affinity_read_proc(char *page, char **start, off_t off, int count, |
| 947 | int *eof, void *data) | 947 | int *eof, void *data) |
| 948 | { | 948 | { |
| 949 | struct irqdesc *desc = irq_desc + ((int)data); | 949 | struct irqdesc *desc = irq_desc + ((int)data); |
| 950 | int len = cpumask_scnprintf(page, count, desc->affinity); | 950 | int len = cpumask_scnprintf(page, count, desc->affinity); |
| 951 | 951 | ||
| 952 | if (count - len < 2) | 952 | if (count - len < 2) |
| 953 | return -EINVAL; | 953 | return -EINVAL; |
| 954 | page[len++] = '\n'; | 954 | page[len++] = '\n'; |
| 955 | page[len] = '\0'; | 955 | page[len] = '\0'; |
| 956 | 956 | ||
| 957 | return len; | 957 | return len; |
| 958 | } | 958 | } |
| 959 | 959 | ||
| 960 | static int | 960 | static int |
| 961 | irq_affinity_write_proc(struct file *file, const char __user *buffer, | 961 | irq_affinity_write_proc(struct file *file, const char __user *buffer, |
| 962 | unsigned long count, void *data) | 962 | unsigned long count, void *data) |
| 963 | { | 963 | { |
| 964 | unsigned int irq = (unsigned int)data; | 964 | unsigned int irq = (unsigned int)data; |
| 965 | struct irqdesc *desc = irq_desc + irq; | 965 | struct irqdesc *desc = irq_desc + irq; |
| 966 | cpumask_t affinity, tmp; | 966 | cpumask_t affinity, tmp; |
| 967 | int ret = -EIO; | 967 | int ret = -EIO; |
| 968 | 968 | ||
| 969 | if (!desc->chip->set_cpu) | 969 | if (!desc->chip->set_cpu) |
| 970 | goto out; | 970 | goto out; |
| 971 | 971 | ||
| 972 | ret = cpumask_parse(buffer, count, affinity); | 972 | ret = cpumask_parse(buffer, count, affinity); |
| 973 | if (ret) | 973 | if (ret) |
| 974 | goto out; | 974 | goto out; |
| 975 | 975 | ||
| 976 | cpus_and(tmp, affinity, cpu_online_map); | 976 | cpus_and(tmp, affinity, cpu_online_map); |
| 977 | if (cpus_empty(tmp)) { | 977 | if (cpus_empty(tmp)) { |
| 978 | ret = -EINVAL; | 978 | ret = -EINVAL; |
| 979 | goto out; | 979 | goto out; |
| 980 | } | 980 | } |
| 981 | 981 | ||
| 982 | desc->affinity = affinity; | 982 | desc->affinity = affinity; |
| 983 | route_irq(desc, irq, first_cpu(tmp)); | 983 | route_irq(desc, irq, first_cpu(tmp)); |
| 984 | ret = count; | 984 | ret = count; |
| 985 | 985 | ||
| 986 | out: | 986 | out: |
| 987 | return ret; | 987 | return ret; |
| 988 | } | 988 | } |
| 989 | #endif | 989 | #endif |
| 990 | #endif | 990 | #endif |
| 991 | 991 | ||
| 992 | void __init init_irq_proc(void) | 992 | void __init init_irq_proc(void) |
| 993 | { | 993 | { |
| 994 | #if defined(CONFIG_SMP) && defined(CONFIG_PROC_FS) | 994 | #if defined(CONFIG_SMP) && defined(CONFIG_PROC_FS) |
| 995 | struct proc_dir_entry *dir; | 995 | struct proc_dir_entry *dir; |
| 996 | int irq; | 996 | int irq; |
| 997 | 997 | ||
| 998 | dir = proc_mkdir("irq", 0); | 998 | dir = proc_mkdir("irq", 0); |
| 999 | if (!dir) | 999 | if (!dir) |
| 1000 | return; | 1000 | return; |
| 1001 | 1001 | ||
| 1002 | for (irq = 0; irq < NR_IRQS; irq++) { | 1002 | for (irq = 0; irq < NR_IRQS; irq++) { |
| 1003 | struct proc_dir_entry *entry; | 1003 | struct proc_dir_entry *entry; |
| 1004 | struct irqdesc *desc; | 1004 | struct irqdesc *desc; |
| 1005 | char name[16]; | 1005 | char name[16]; |
| 1006 | 1006 | ||
| 1007 | desc = irq_desc + irq; | 1007 | desc = irq_desc + irq; |
| 1008 | memset(name, 0, sizeof(name)); | 1008 | memset(name, 0, sizeof(name)); |
| 1009 | snprintf(name, sizeof(name) - 1, "%u", irq); | 1009 | snprintf(name, sizeof(name) - 1, "%u", irq); |
| 1010 | 1010 | ||
| 1011 | desc->procdir = proc_mkdir(name, dir); | 1011 | desc->procdir = proc_mkdir(name, dir); |
| 1012 | if (!desc->procdir) | 1012 | if (!desc->procdir) |
| 1013 | continue; | 1013 | continue; |
| 1014 | 1014 | ||
| 1015 | entry = create_proc_entry("smp_affinity", 0600, desc->procdir); | 1015 | entry = create_proc_entry("smp_affinity", 0600, desc->procdir); |
| 1016 | if (entry) { | 1016 | if (entry) { |
| 1017 | entry->nlink = 1; | 1017 | entry->nlink = 1; |
| 1018 | entry->data = (void *)irq; | 1018 | entry->data = (void *)irq; |
| 1019 | entry->read_proc = irq_affinity_read_proc; | 1019 | entry->read_proc = irq_affinity_read_proc; |
| 1020 | entry->write_proc = irq_affinity_write_proc; | 1020 | entry->write_proc = irq_affinity_write_proc; |
| 1021 | } | 1021 | } |
| 1022 | } | 1022 | } |
| 1023 | #endif | 1023 | #endif |
| 1024 | } | 1024 | } |
| 1025 | 1025 | ||
| 1026 | void __init init_IRQ(void) | 1026 | void __init init_IRQ(void) |
| 1027 | { | 1027 | { |
| 1028 | struct irqdesc *desc; | 1028 | struct irqdesc *desc; |
| 1029 | extern void init_dma(void); | 1029 | extern void init_dma(void); |
| 1030 | int irq; | 1030 | int irq; |
| 1031 | 1031 | ||
| 1032 | #ifdef CONFIG_SMP | 1032 | #ifdef CONFIG_SMP |
| 1033 | bad_irq_desc.affinity = CPU_MASK_ALL; | 1033 | bad_irq_desc.affinity = CPU_MASK_ALL; |
| 1034 | bad_irq_desc.cpu = smp_processor_id(); | 1034 | bad_irq_desc.cpu = smp_processor_id(); |
| 1035 | #endif | 1035 | #endif |
| 1036 | 1036 | ||
| 1037 | for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) { | 1037 | for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) { |
| 1038 | *desc = bad_irq_desc; | 1038 | *desc = bad_irq_desc; |
| 1039 | INIT_LIST_HEAD(&desc->pend); | 1039 | INIT_LIST_HEAD(&desc->pend); |
| 1040 | } | 1040 | } |
| 1041 | 1041 | ||
| 1042 | init_arch_irq(); | 1042 | init_arch_irq(); |
| 1043 | init_dma(); | 1043 | init_dma(); |
| 1044 | } | 1044 | } |
| 1045 | 1045 | ||
| 1046 | static int __init noirqdebug_setup(char *str) | 1046 | static int __init noirqdebug_setup(char *str) |
| 1047 | { | 1047 | { |
| 1048 | noirqdebug = 1; | 1048 | noirqdebug = 1; |
| 1049 | return 1; | 1049 | return 1; |
| 1050 | } | 1050 | } |
| 1051 | 1051 | ||
| 1052 | __setup("noirqdebug", noirqdebug_setup); | 1052 | __setup("noirqdebug", noirqdebug_setup); |
| 1053 | 1053 |
arch/arm/kernel/smp.c
| 1 | /* | 1 | /* |
| 2 | * linux/arch/arm/kernel/smp.c | 2 | * linux/arch/arm/kernel/smp.c |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2002 ARM Limited, All Rights Reserved. | 4 | * Copyright (C) 2002 ARM Limited, All Rights Reserved. |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
| 8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
| 9 | */ | 9 | */ |
| 10 | #include <linux/config.h> | 10 | #include <linux/config.h> |
| 11 | #include <linux/delay.h> | 11 | #include <linux/delay.h> |
| 12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
| 13 | #include <linux/spinlock.h> | 13 | #include <linux/spinlock.h> |
| 14 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
| 15 | #include <linux/interrupt.h> | 15 | #include <linux/interrupt.h> |
| 16 | #include <linux/cache.h> | 16 | #include <linux/cache.h> |
| 17 | #include <linux/profile.h> | 17 | #include <linux/profile.h> |
| 18 | #include <linux/errno.h> | 18 | #include <linux/errno.h> |
| 19 | #include <linux/mm.h> | 19 | #include <linux/mm.h> |
| 20 | #include <linux/cpu.h> | 20 | #include <linux/cpu.h> |
| 21 | #include <linux/smp.h> | 21 | #include <linux/smp.h> |
| 22 | #include <linux/seq_file.h> | 22 | #include <linux/seq_file.h> |
| 23 | 23 | ||
| 24 | #include <asm/atomic.h> | 24 | #include <asm/atomic.h> |
| 25 | #include <asm/cacheflush.h> | 25 | #include <asm/cacheflush.h> |
| 26 | #include <asm/cpu.h> | 26 | #include <asm/cpu.h> |
| 27 | #include <asm/mmu_context.h> | 27 | #include <asm/mmu_context.h> |
| 28 | #include <asm/pgtable.h> | 28 | #include <asm/pgtable.h> |
| 29 | #include <asm/pgalloc.h> | 29 | #include <asm/pgalloc.h> |
| 30 | #include <asm/processor.h> | 30 | #include <asm/processor.h> |
| 31 | #include <asm/tlbflush.h> | 31 | #include <asm/tlbflush.h> |
| 32 | #include <asm/ptrace.h> | 32 | #include <asm/ptrace.h> |
| 33 | 33 | ||
| 34 | /* | 34 | /* |
| 35 | * bitmask of present and online CPUs. | 35 | * bitmask of present and online CPUs. |
| 36 | * The present bitmask indicates that the CPU is physically present. | 36 | * The present bitmask indicates that the CPU is physically present. |
| 37 | * The online bitmask indicates that the CPU is up and running. | 37 | * The online bitmask indicates that the CPU is up and running. |
| 38 | */ | 38 | */ |
| 39 | cpumask_t cpu_possible_map; | 39 | cpumask_t cpu_possible_map; |
| 40 | cpumask_t cpu_online_map; | 40 | cpumask_t cpu_online_map; |
| 41 | 41 | ||
| 42 | /* | 42 | /* |
| 43 | * as from 2.5, kernels no longer have an init_tasks structure | 43 | * as from 2.5, kernels no longer have an init_tasks structure |
| 44 | * so we need some other way of telling a new secondary core | 44 | * so we need some other way of telling a new secondary core |
| 45 | * where to place its SVC stack | 45 | * where to place its SVC stack |
| 46 | */ | 46 | */ |
| 47 | struct secondary_data secondary_data; | 47 | struct secondary_data secondary_data; |
| 48 | 48 | ||
| 49 | /* | 49 | /* |
| 50 | * structures for inter-processor calls | 50 | * structures for inter-processor calls |
| 51 | * - A collection of single bit ipi messages. | 51 | * - A collection of single bit ipi messages. |
| 52 | */ | 52 | */ |
| 53 | struct ipi_data { | 53 | struct ipi_data { |
| 54 | spinlock_t lock; | 54 | spinlock_t lock; |
| 55 | unsigned long ipi_count; | 55 | unsigned long ipi_count; |
| 56 | unsigned long bits; | 56 | unsigned long bits; |
| 57 | }; | 57 | }; |
| 58 | 58 | ||
| 59 | static DEFINE_PER_CPU(struct ipi_data, ipi_data) = { | 59 | static DEFINE_PER_CPU(struct ipi_data, ipi_data) = { |
| 60 | .lock = SPIN_LOCK_UNLOCKED, | 60 | .lock = SPIN_LOCK_UNLOCKED, |
| 61 | }; | 61 | }; |
| 62 | 62 | ||
| 63 | enum ipi_msg_type { | 63 | enum ipi_msg_type { |
| 64 | IPI_TIMER, | 64 | IPI_TIMER, |
| 65 | IPI_RESCHEDULE, | 65 | IPI_RESCHEDULE, |
| 66 | IPI_CALL_FUNC, | 66 | IPI_CALL_FUNC, |
| 67 | IPI_CPU_STOP, | 67 | IPI_CPU_STOP, |
| 68 | }; | 68 | }; |
| 69 | 69 | ||
| 70 | struct smp_call_struct { | 70 | struct smp_call_struct { |
| 71 | void (*func)(void *info); | 71 | void (*func)(void *info); |
| 72 | void *info; | 72 | void *info; |
| 73 | int wait; | 73 | int wait; |
| 74 | cpumask_t pending; | 74 | cpumask_t pending; |
| 75 | cpumask_t unfinished; | 75 | cpumask_t unfinished; |
| 76 | }; | 76 | }; |
| 77 | 77 | ||
| 78 | static struct smp_call_struct * volatile smp_call_function_data; | 78 | static struct smp_call_struct * volatile smp_call_function_data; |
| 79 | static DEFINE_SPINLOCK(smp_call_function_lock); | 79 | static DEFINE_SPINLOCK(smp_call_function_lock); |
| 80 | 80 | ||
| 81 | int __cpuinit __cpu_up(unsigned int cpu) | 81 | int __cpuinit __cpu_up(unsigned int cpu) |
| 82 | { | 82 | { |
| 83 | struct task_struct *idle; | 83 | struct task_struct *idle; |
| 84 | pgd_t *pgd; | 84 | pgd_t *pgd; |
| 85 | pmd_t *pmd; | 85 | pmd_t *pmd; |
| 86 | int ret; | 86 | int ret; |
| 87 | 87 | ||
| 88 | /* | 88 | /* |
| 89 | * Spawn a new process manually. Grab a pointer to | 89 | * Spawn a new process manually. Grab a pointer to |
| 90 | * its task struct so we can mess with it | 90 | * its task struct so we can mess with it |
| 91 | */ | 91 | */ |
| 92 | idle = fork_idle(cpu); | 92 | idle = fork_idle(cpu); |
| 93 | if (IS_ERR(idle)) { | 93 | if (IS_ERR(idle)) { |
| 94 | printk(KERN_ERR "CPU%u: fork() failed\n", cpu); | 94 | printk(KERN_ERR "CPU%u: fork() failed\n", cpu); |
| 95 | return PTR_ERR(idle); | 95 | return PTR_ERR(idle); |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | /* | 98 | /* |
| 99 | * Allocate initial page tables to allow the new CPU to | 99 | * Allocate initial page tables to allow the new CPU to |
| 100 | * enable the MMU safely. This essentially means a set | 100 | * enable the MMU safely. This essentially means a set |
| 101 | * of our "standard" page tables, with the addition of | 101 | * of our "standard" page tables, with the addition of |
| 102 | * a 1:1 mapping for the physical address of the kernel. | 102 | * a 1:1 mapping for the physical address of the kernel. |
| 103 | */ | 103 | */ |
| 104 | pgd = pgd_alloc(&init_mm); | 104 | pgd = pgd_alloc(&init_mm); |
| 105 | pmd = pmd_offset(pgd, PHYS_OFFSET); | 105 | pmd = pmd_offset(pgd, PHYS_OFFSET); |
| 106 | *pmd = __pmd((PHYS_OFFSET & PGDIR_MASK) | | 106 | *pmd = __pmd((PHYS_OFFSET & PGDIR_MASK) | |
| 107 | PMD_TYPE_SECT | PMD_SECT_AP_WRITE); | 107 | PMD_TYPE_SECT | PMD_SECT_AP_WRITE); |
| 108 | 108 | ||
| 109 | /* | 109 | /* |
| 110 | * We need to tell the secondary core where to find | 110 | * We need to tell the secondary core where to find |
| 111 | * its stack and the page tables. | 111 | * its stack and the page tables. |
| 112 | */ | 112 | */ |
| 113 | secondary_data.stack = (void *)idle->thread_info + THREAD_SIZE - 8; | 113 | secondary_data.stack = (void *)idle->thread_info + THREAD_START_SP; |
| 114 | secondary_data.pgdir = virt_to_phys(pgd); | 114 | secondary_data.pgdir = virt_to_phys(pgd); |
| 115 | wmb(); | 115 | wmb(); |
| 116 | 116 | ||
| 117 | /* | 117 | /* |
| 118 | * Now bring the CPU into our world. | 118 | * Now bring the CPU into our world. |
| 119 | */ | 119 | */ |
| 120 | ret = boot_secondary(cpu, idle); | 120 | ret = boot_secondary(cpu, idle); |
| 121 | if (ret == 0) { | 121 | if (ret == 0) { |
| 122 | unsigned long timeout; | 122 | unsigned long timeout; |
| 123 | 123 | ||
| 124 | /* | 124 | /* |
| 125 | * CPU was successfully started, wait for it | 125 | * CPU was successfully started, wait for it |
| 126 | * to come online or time out. | 126 | * to come online or time out. |
| 127 | */ | 127 | */ |
| 128 | timeout = jiffies + HZ; | 128 | timeout = jiffies + HZ; |
| 129 | while (time_before(jiffies, timeout)) { | 129 | while (time_before(jiffies, timeout)) { |
| 130 | if (cpu_online(cpu)) | 130 | if (cpu_online(cpu)) |
| 131 | break; | 131 | break; |
| 132 | 132 | ||
| 133 | udelay(10); | 133 | udelay(10); |
| 134 | barrier(); | 134 | barrier(); |
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | if (!cpu_online(cpu)) | 137 | if (!cpu_online(cpu)) |
| 138 | ret = -EIO; | 138 | ret = -EIO; |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | secondary_data.stack = 0; | 141 | secondary_data.stack = 0; |
| 142 | secondary_data.pgdir = 0; | 142 | secondary_data.pgdir = 0; |
| 143 | 143 | ||
| 144 | *pmd_offset(pgd, PHYS_OFFSET) = __pmd(0); | 144 | *pmd_offset(pgd, PHYS_OFFSET) = __pmd(0); |
| 145 | pgd_free(pgd); | 145 | pgd_free(pgd); |
| 146 | 146 | ||
| 147 | if (ret) { | 147 | if (ret) { |
| 148 | printk(KERN_CRIT "CPU%u: processor failed to boot\n", cpu); | 148 | printk(KERN_CRIT "CPU%u: processor failed to boot\n", cpu); |
| 149 | 149 | ||
| 150 | /* | 150 | /* |
| 151 | * FIXME: We need to clean up the new idle thread. --rmk | 151 | * FIXME: We need to clean up the new idle thread. --rmk |
| 152 | */ | 152 | */ |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | return ret; | 155 | return ret; |
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | /* | 158 | /* |
| 159 | * This is the secondary CPU boot entry. We're using this CPUs | 159 | * This is the secondary CPU boot entry. We're using this CPUs |
| 160 | * idle thread stack, but a set of temporary page tables. | 160 | * idle thread stack, but a set of temporary page tables. |
| 161 | */ | 161 | */ |
| 162 | asmlinkage void __cpuinit secondary_start_kernel(void) | 162 | asmlinkage void __cpuinit secondary_start_kernel(void) |
| 163 | { | 163 | { |
| 164 | struct mm_struct *mm = &init_mm; | 164 | struct mm_struct *mm = &init_mm; |
| 165 | unsigned int cpu = smp_processor_id(); | 165 | unsigned int cpu = smp_processor_id(); |
| 166 | 166 | ||
| 167 | printk("CPU%u: Booted secondary processor\n", cpu); | 167 | printk("CPU%u: Booted secondary processor\n", cpu); |
| 168 | 168 | ||
| 169 | /* | 169 | /* |
| 170 | * All kernel threads share the same mm context; grab a | 170 | * All kernel threads share the same mm context; grab a |
| 171 | * reference and switch to it. | 171 | * reference and switch to it. |
| 172 | */ | 172 | */ |
| 173 | atomic_inc(&mm->mm_users); | 173 | atomic_inc(&mm->mm_users); |
| 174 | atomic_inc(&mm->mm_count); | 174 | atomic_inc(&mm->mm_count); |
| 175 | current->active_mm = mm; | 175 | current->active_mm = mm; |
| 176 | cpu_set(cpu, mm->cpu_vm_mask); | 176 | cpu_set(cpu, mm->cpu_vm_mask); |
| 177 | cpu_switch_mm(mm->pgd, mm); | 177 | cpu_switch_mm(mm->pgd, mm); |
| 178 | enter_lazy_tlb(mm, current); | 178 | enter_lazy_tlb(mm, current); |
| 179 | local_flush_tlb_all(); | 179 | local_flush_tlb_all(); |
| 180 | 180 | ||
| 181 | cpu_init(); | 181 | cpu_init(); |
| 182 | 182 | ||
| 183 | /* | 183 | /* |
| 184 | * Give the platform a chance to do its own initialisation. | 184 | * Give the platform a chance to do its own initialisation. |
| 185 | */ | 185 | */ |
| 186 | platform_secondary_init(cpu); | 186 | platform_secondary_init(cpu); |
| 187 | 187 | ||
| 188 | /* | 188 | /* |
| 189 | * Enable local interrupts. | 189 | * Enable local interrupts. |
| 190 | */ | 190 | */ |
| 191 | local_irq_enable(); | 191 | local_irq_enable(); |
| 192 | local_fiq_enable(); | 192 | local_fiq_enable(); |
| 193 | 193 | ||
| 194 | calibrate_delay(); | 194 | calibrate_delay(); |
| 195 | 195 | ||
| 196 | smp_store_cpu_info(cpu); | 196 | smp_store_cpu_info(cpu); |
| 197 | 197 | ||
| 198 | /* | 198 | /* |
| 199 | * OK, now it's safe to let the boot CPU continue | 199 | * OK, now it's safe to let the boot CPU continue |
| 200 | */ | 200 | */ |
| 201 | cpu_set(cpu, cpu_online_map); | 201 | cpu_set(cpu, cpu_online_map); |
| 202 | 202 | ||
| 203 | /* | 203 | /* |
| 204 | * OK, it's off to the idle thread for us | 204 | * OK, it's off to the idle thread for us |
| 205 | */ | 205 | */ |
| 206 | cpu_idle(); | 206 | cpu_idle(); |
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | /* | 209 | /* |
| 210 | * Called by both boot and secondaries to move global data into | 210 | * Called by both boot and secondaries to move global data into |
| 211 | * per-processor storage. | 211 | * per-processor storage. |
| 212 | */ | 212 | */ |
| 213 | void __cpuinit smp_store_cpu_info(unsigned int cpuid) | 213 | void __cpuinit smp_store_cpu_info(unsigned int cpuid) |
| 214 | { | 214 | { |
| 215 | struct cpuinfo_arm *cpu_info = &per_cpu(cpu_data, cpuid); | 215 | struct cpuinfo_arm *cpu_info = &per_cpu(cpu_data, cpuid); |
| 216 | 216 | ||
| 217 | cpu_info->loops_per_jiffy = loops_per_jiffy; | 217 | cpu_info->loops_per_jiffy = loops_per_jiffy; |
| 218 | } | 218 | } |
| 219 | 219 | ||
| 220 | void __init smp_cpus_done(unsigned int max_cpus) | 220 | void __init smp_cpus_done(unsigned int max_cpus) |
| 221 | { | 221 | { |
| 222 | int cpu; | 222 | int cpu; |
| 223 | unsigned long bogosum = 0; | 223 | unsigned long bogosum = 0; |
| 224 | 224 | ||
| 225 | for_each_online_cpu(cpu) | 225 | for_each_online_cpu(cpu) |
| 226 | bogosum += per_cpu(cpu_data, cpu).loops_per_jiffy; | 226 | bogosum += per_cpu(cpu_data, cpu).loops_per_jiffy; |
| 227 | 227 | ||
| 228 | printk(KERN_INFO "SMP: Total of %d processors activated " | 228 | printk(KERN_INFO "SMP: Total of %d processors activated " |
| 229 | "(%lu.%02lu BogoMIPS).\n", | 229 | "(%lu.%02lu BogoMIPS).\n", |
| 230 | num_online_cpus(), | 230 | num_online_cpus(), |
| 231 | bogosum / (500000/HZ), | 231 | bogosum / (500000/HZ), |
| 232 | (bogosum / (5000/HZ)) % 100); | 232 | (bogosum / (5000/HZ)) % 100); |
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | void __init smp_prepare_boot_cpu(void) | 235 | void __init smp_prepare_boot_cpu(void) |
| 236 | { | 236 | { |
| 237 | unsigned int cpu = smp_processor_id(); | 237 | unsigned int cpu = smp_processor_id(); |
| 238 | 238 | ||
| 239 | cpu_set(cpu, cpu_possible_map); | 239 | cpu_set(cpu, cpu_possible_map); |
| 240 | cpu_set(cpu, cpu_present_map); | 240 | cpu_set(cpu, cpu_present_map); |
| 241 | cpu_set(cpu, cpu_online_map); | 241 | cpu_set(cpu, cpu_online_map); |
| 242 | } | 242 | } |
| 243 | 243 | ||
| 244 | static void send_ipi_message(cpumask_t callmap, enum ipi_msg_type msg) | 244 | static void send_ipi_message(cpumask_t callmap, enum ipi_msg_type msg) |
| 245 | { | 245 | { |
| 246 | unsigned long flags; | 246 | unsigned long flags; |
| 247 | unsigned int cpu; | 247 | unsigned int cpu; |
| 248 | 248 | ||
| 249 | local_irq_save(flags); | 249 | local_irq_save(flags); |
| 250 | 250 | ||
| 251 | for_each_cpu_mask(cpu, callmap) { | 251 | for_each_cpu_mask(cpu, callmap) { |
| 252 | struct ipi_data *ipi = &per_cpu(ipi_data, cpu); | 252 | struct ipi_data *ipi = &per_cpu(ipi_data, cpu); |
| 253 | 253 | ||
| 254 | spin_lock(&ipi->lock); | 254 | spin_lock(&ipi->lock); |
| 255 | ipi->bits |= 1 << msg; | 255 | ipi->bits |= 1 << msg; |
| 256 | spin_unlock(&ipi->lock); | 256 | spin_unlock(&ipi->lock); |
| 257 | } | 257 | } |
| 258 | 258 | ||
| 259 | /* | 259 | /* |
| 260 | * Call the platform specific cross-CPU call function. | 260 | * Call the platform specific cross-CPU call function. |
| 261 | */ | 261 | */ |
| 262 | smp_cross_call(callmap); | 262 | smp_cross_call(callmap); |
| 263 | 263 | ||
| 264 | local_irq_restore(flags); | 264 | local_irq_restore(flags); |
| 265 | } | 265 | } |
| 266 | 266 | ||
| 267 | /* | 267 | /* |
| 268 | * You must not call this function with disabled interrupts, from a | 268 | * You must not call this function with disabled interrupts, from a |
| 269 | * hardware interrupt handler, nor from a bottom half handler. | 269 | * hardware interrupt handler, nor from a bottom half handler. |
| 270 | */ | 270 | */ |
| 271 | int smp_call_function_on_cpu(void (*func)(void *info), void *info, int retry, | 271 | int smp_call_function_on_cpu(void (*func)(void *info), void *info, int retry, |
| 272 | int wait, cpumask_t callmap) | 272 | int wait, cpumask_t callmap) |
| 273 | { | 273 | { |
| 274 | struct smp_call_struct data; | 274 | struct smp_call_struct data; |
| 275 | unsigned long timeout; | 275 | unsigned long timeout; |
| 276 | int ret = 0; | 276 | int ret = 0; |
| 277 | 277 | ||
| 278 | data.func = func; | 278 | data.func = func; |
| 279 | data.info = info; | 279 | data.info = info; |
| 280 | data.wait = wait; | 280 | data.wait = wait; |
| 281 | 281 | ||
| 282 | cpu_clear(smp_processor_id(), callmap); | 282 | cpu_clear(smp_processor_id(), callmap); |
| 283 | if (cpus_empty(callmap)) | 283 | if (cpus_empty(callmap)) |
| 284 | goto out; | 284 | goto out; |
| 285 | 285 | ||
| 286 | data.pending = callmap; | 286 | data.pending = callmap; |
| 287 | if (wait) | 287 | if (wait) |
| 288 | data.unfinished = callmap; | 288 | data.unfinished = callmap; |
| 289 | 289 | ||
| 290 | /* | 290 | /* |
| 291 | * try to get the mutex on smp_call_function_data | 291 | * try to get the mutex on smp_call_function_data |
| 292 | */ | 292 | */ |
| 293 | spin_lock(&smp_call_function_lock); | 293 | spin_lock(&smp_call_function_lock); |
| 294 | smp_call_function_data = &data; | 294 | smp_call_function_data = &data; |
| 295 | 295 | ||
| 296 | send_ipi_message(callmap, IPI_CALL_FUNC); | 296 | send_ipi_message(callmap, IPI_CALL_FUNC); |
| 297 | 297 | ||
| 298 | timeout = jiffies + HZ; | 298 | timeout = jiffies + HZ; |
| 299 | while (!cpus_empty(data.pending) && time_before(jiffies, timeout)) | 299 | while (!cpus_empty(data.pending) && time_before(jiffies, timeout)) |
| 300 | barrier(); | 300 | barrier(); |
| 301 | 301 | ||
| 302 | /* | 302 | /* |
| 303 | * did we time out? | 303 | * did we time out? |
| 304 | */ | 304 | */ |
| 305 | if (!cpus_empty(data.pending)) { | 305 | if (!cpus_empty(data.pending)) { |
| 306 | /* | 306 | /* |
| 307 | * this may be causing our panic - report it | 307 | * this may be causing our panic - report it |
| 308 | */ | 308 | */ |
| 309 | printk(KERN_CRIT | 309 | printk(KERN_CRIT |
| 310 | "CPU%u: smp_call_function timeout for %p(%p)\n" | 310 | "CPU%u: smp_call_function timeout for %p(%p)\n" |
| 311 | " callmap %lx pending %lx, %swait\n", | 311 | " callmap %lx pending %lx, %swait\n", |
| 312 | smp_processor_id(), func, info, callmap, data.pending, | 312 | smp_processor_id(), func, info, callmap, data.pending, |
| 313 | wait ? "" : "no "); | 313 | wait ? "" : "no "); |
| 314 | 314 | ||
| 315 | /* | 315 | /* |
| 316 | * TRACE | 316 | * TRACE |
| 317 | */ | 317 | */ |
| 318 | timeout = jiffies + (5 * HZ); | 318 | timeout = jiffies + (5 * HZ); |
| 319 | while (!cpus_empty(data.pending) && time_before(jiffies, timeout)) | 319 | while (!cpus_empty(data.pending) && time_before(jiffies, timeout)) |
| 320 | barrier(); | 320 | barrier(); |
| 321 | 321 | ||
| 322 | if (cpus_empty(data.pending)) | 322 | if (cpus_empty(data.pending)) |
| 323 | printk(KERN_CRIT " RESOLVED\n"); | 323 | printk(KERN_CRIT " RESOLVED\n"); |
| 324 | else | 324 | else |
| 325 | printk(KERN_CRIT " STILL STUCK\n"); | 325 | printk(KERN_CRIT " STILL STUCK\n"); |
| 326 | } | 326 | } |
| 327 | 327 | ||
| 328 | /* | 328 | /* |
| 329 | * whatever happened, we're done with the data, so release it | 329 | * whatever happened, we're done with the data, so release it |
| 330 | */ | 330 | */ |
| 331 | smp_call_function_data = NULL; | 331 | smp_call_function_data = NULL; |
| 332 | spin_unlock(&smp_call_function_lock); | 332 | spin_unlock(&smp_call_function_lock); |
| 333 | 333 | ||
| 334 | if (!cpus_empty(data.pending)) { | 334 | if (!cpus_empty(data.pending)) { |
| 335 | ret = -ETIMEDOUT; | 335 | ret = -ETIMEDOUT; |
| 336 | goto out; | 336 | goto out; |
| 337 | } | 337 | } |
| 338 | 338 | ||
| 339 | if (wait) | 339 | if (wait) |
| 340 | while (!cpus_empty(data.unfinished)) | 340 | while (!cpus_empty(data.unfinished)) |
| 341 | barrier(); | 341 | barrier(); |
| 342 | out: | 342 | out: |
| 343 | 343 | ||
| 344 | return 0; | 344 | return 0; |
| 345 | } | 345 | } |
| 346 | 346 | ||
| 347 | int smp_call_function(void (*func)(void *info), void *info, int retry, | 347 | int smp_call_function(void (*func)(void *info), void *info, int retry, |
| 348 | int wait) | 348 | int wait) |
| 349 | { | 349 | { |
| 350 | return smp_call_function_on_cpu(func, info, retry, wait, | 350 | return smp_call_function_on_cpu(func, info, retry, wait, |
| 351 | cpu_online_map); | 351 | cpu_online_map); |
| 352 | } | 352 | } |
| 353 | 353 | ||
| 354 | void show_ipi_list(struct seq_file *p) | 354 | void show_ipi_list(struct seq_file *p) |
| 355 | { | 355 | { |
| 356 | unsigned int cpu; | 356 | unsigned int cpu; |
| 357 | 357 | ||
| 358 | seq_puts(p, "IPI:"); | 358 | seq_puts(p, "IPI:"); |
| 359 | 359 | ||
| 360 | for_each_present_cpu(cpu) | 360 | for_each_present_cpu(cpu) |
| 361 | seq_printf(p, " %10lu", per_cpu(ipi_data, cpu).ipi_count); | 361 | seq_printf(p, " %10lu", per_cpu(ipi_data, cpu).ipi_count); |
| 362 | 362 | ||
| 363 | seq_putc(p, '\n'); | 363 | seq_putc(p, '\n'); |
| 364 | } | 364 | } |
| 365 | 365 | ||
| 366 | static void ipi_timer(struct pt_regs *regs) | 366 | static void ipi_timer(struct pt_regs *regs) |
| 367 | { | 367 | { |
| 368 | int user = user_mode(regs); | 368 | int user = user_mode(regs); |
| 369 | 369 | ||
| 370 | irq_enter(); | 370 | irq_enter(); |
| 371 | profile_tick(CPU_PROFILING, regs); | 371 | profile_tick(CPU_PROFILING, regs); |
| 372 | update_process_times(user); | 372 | update_process_times(user); |
| 373 | irq_exit(); | 373 | irq_exit(); |
| 374 | } | 374 | } |
| 375 | 375 | ||
| 376 | /* | 376 | /* |
| 377 | * ipi_call_function - handle IPI from smp_call_function() | 377 | * ipi_call_function - handle IPI from smp_call_function() |
| 378 | * | 378 | * |
| 379 | * Note that we copy data out of the cross-call structure and then | 379 | * Note that we copy data out of the cross-call structure and then |
| 380 | * let the caller know that we're here and have done with their data | 380 | * let the caller know that we're here and have done with their data |
| 381 | */ | 381 | */ |
| 382 | static void ipi_call_function(unsigned int cpu) | 382 | static void ipi_call_function(unsigned int cpu) |
| 383 | { | 383 | { |
| 384 | struct smp_call_struct *data = smp_call_function_data; | 384 | struct smp_call_struct *data = smp_call_function_data; |
| 385 | void (*func)(void *info) = data->func; | 385 | void (*func)(void *info) = data->func; |
| 386 | void *info = data->info; | 386 | void *info = data->info; |
| 387 | int wait = data->wait; | 387 | int wait = data->wait; |
| 388 | 388 | ||
| 389 | cpu_clear(cpu, data->pending); | 389 | cpu_clear(cpu, data->pending); |
| 390 | 390 | ||
| 391 | func(info); | 391 | func(info); |
| 392 | 392 | ||
| 393 | if (wait) | 393 | if (wait) |
| 394 | cpu_clear(cpu, data->unfinished); | 394 | cpu_clear(cpu, data->unfinished); |
| 395 | } | 395 | } |
| 396 | 396 | ||
| 397 | static DEFINE_SPINLOCK(stop_lock); | 397 | static DEFINE_SPINLOCK(stop_lock); |
| 398 | 398 | ||
| 399 | /* | 399 | /* |
| 400 | * ipi_cpu_stop - handle IPI from smp_send_stop() | 400 | * ipi_cpu_stop - handle IPI from smp_send_stop() |
| 401 | */ | 401 | */ |
| 402 | static void ipi_cpu_stop(unsigned int cpu) | 402 | static void ipi_cpu_stop(unsigned int cpu) |
| 403 | { | 403 | { |
| 404 | spin_lock(&stop_lock); | 404 | spin_lock(&stop_lock); |
| 405 | printk(KERN_CRIT "CPU%u: stopping\n", cpu); | 405 | printk(KERN_CRIT "CPU%u: stopping\n", cpu); |
| 406 | dump_stack(); | 406 | dump_stack(); |
| 407 | spin_unlock(&stop_lock); | 407 | spin_unlock(&stop_lock); |
| 408 | 408 | ||
| 409 | cpu_clear(cpu, cpu_online_map); | 409 | cpu_clear(cpu, cpu_online_map); |
| 410 | 410 | ||
| 411 | local_fiq_disable(); | 411 | local_fiq_disable(); |
| 412 | local_irq_disable(); | 412 | local_irq_disable(); |
| 413 | 413 | ||
| 414 | while (1) | 414 | while (1) |
| 415 | cpu_relax(); | 415 | cpu_relax(); |
| 416 | } | 416 | } |
| 417 | 417 | ||
| 418 | /* | 418 | /* |
| 419 | * Main handler for inter-processor interrupts | 419 | * Main handler for inter-processor interrupts |
| 420 | * | 420 | * |
| 421 | * For ARM, the ipimask now only identifies a single | 421 | * For ARM, the ipimask now only identifies a single |
| 422 | * category of IPI (Bit 1 IPIs have been replaced by a | 422 | * category of IPI (Bit 1 IPIs have been replaced by a |
| 423 | * different mechanism): | 423 | * different mechanism): |
| 424 | * | 424 | * |
| 425 | * Bit 0 - Inter-processor function call | 425 | * Bit 0 - Inter-processor function call |
| 426 | */ | 426 | */ |
| 427 | void do_IPI(struct pt_regs *regs) | 427 | void do_IPI(struct pt_regs *regs) |
| 428 | { | 428 | { |
| 429 | unsigned int cpu = smp_processor_id(); | 429 | unsigned int cpu = smp_processor_id(); |
| 430 | struct ipi_data *ipi = &per_cpu(ipi_data, cpu); | 430 | struct ipi_data *ipi = &per_cpu(ipi_data, cpu); |
| 431 | 431 | ||
| 432 | ipi->ipi_count++; | 432 | ipi->ipi_count++; |
| 433 | 433 | ||
| 434 | for (;;) { | 434 | for (;;) { |
| 435 | unsigned long msgs; | 435 | unsigned long msgs; |
| 436 | 436 | ||
| 437 | spin_lock(&ipi->lock); | 437 | spin_lock(&ipi->lock); |
| 438 | msgs = ipi->bits; | 438 | msgs = ipi->bits; |
| 439 | ipi->bits = 0; | 439 | ipi->bits = 0; |
| 440 | spin_unlock(&ipi->lock); | 440 | spin_unlock(&ipi->lock); |
| 441 | 441 | ||
| 442 | if (!msgs) | 442 | if (!msgs) |
| 443 | break; | 443 | break; |
| 444 | 444 | ||
| 445 | do { | 445 | do { |
| 446 | unsigned nextmsg; | 446 | unsigned nextmsg; |
| 447 | 447 | ||
| 448 | nextmsg = msgs & -msgs; | 448 | nextmsg = msgs & -msgs; |
| 449 | msgs &= ~nextmsg; | 449 | msgs &= ~nextmsg; |
| 450 | nextmsg = ffz(~nextmsg); | 450 | nextmsg = ffz(~nextmsg); |
| 451 | 451 | ||
| 452 | switch (nextmsg) { | 452 | switch (nextmsg) { |
| 453 | case IPI_TIMER: | 453 | case IPI_TIMER: |
| 454 | ipi_timer(regs); | 454 | ipi_timer(regs); |
| 455 | break; | 455 | break; |
| 456 | 456 | ||
| 457 | case IPI_RESCHEDULE: | 457 | case IPI_RESCHEDULE: |
| 458 | /* | 458 | /* |
| 459 | * nothing more to do - eveything is | 459 | * nothing more to do - eveything is |
| 460 | * done on the interrupt return path | 460 | * done on the interrupt return path |
| 461 | */ | 461 | */ |
| 462 | break; | 462 | break; |
| 463 | 463 | ||
| 464 | case IPI_CALL_FUNC: | 464 | case IPI_CALL_FUNC: |
| 465 | ipi_call_function(cpu); | 465 | ipi_call_function(cpu); |
| 466 | break; | 466 | break; |
| 467 | 467 | ||
| 468 | case IPI_CPU_STOP: | 468 | case IPI_CPU_STOP: |
| 469 | ipi_cpu_stop(cpu); | 469 | ipi_cpu_stop(cpu); |
| 470 | break; | 470 | break; |
| 471 | 471 | ||
| 472 | default: | 472 | default: |
| 473 | printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n", | 473 | printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n", |
| 474 | cpu, nextmsg); | 474 | cpu, nextmsg); |
| 475 | break; | 475 | break; |
| 476 | } | 476 | } |
| 477 | } while (msgs); | 477 | } while (msgs); |
| 478 | } | 478 | } |
| 479 | } | 479 | } |
| 480 | 480 | ||
| 481 | void smp_send_reschedule(int cpu) | 481 | void smp_send_reschedule(int cpu) |
| 482 | { | 482 | { |
| 483 | send_ipi_message(cpumask_of_cpu(cpu), IPI_RESCHEDULE); | 483 | send_ipi_message(cpumask_of_cpu(cpu), IPI_RESCHEDULE); |
| 484 | } | 484 | } |
| 485 | 485 | ||
| 486 | void smp_send_timer(void) | 486 | void smp_send_timer(void) |
| 487 | { | 487 | { |
| 488 | cpumask_t mask = cpu_online_map; | 488 | cpumask_t mask = cpu_online_map; |
| 489 | cpu_clear(smp_processor_id(), mask); | 489 | cpu_clear(smp_processor_id(), mask); |
| 490 | send_ipi_message(mask, IPI_TIMER); | 490 | send_ipi_message(mask, IPI_TIMER); |
| 491 | } | 491 | } |
| 492 | 492 | ||
| 493 | void smp_send_stop(void) | 493 | void smp_send_stop(void) |
| 494 | { | 494 | { |
| 495 | cpumask_t mask = cpu_online_map; | 495 | cpumask_t mask = cpu_online_map; |
| 496 | cpu_clear(smp_processor_id(), mask); | 496 | cpu_clear(smp_processor_id(), mask); |
| 497 | send_ipi_message(mask, IPI_CPU_STOP); | 497 | send_ipi_message(mask, IPI_CPU_STOP); |
| 498 | } | 498 | } |
| 499 | 499 | ||
| 500 | /* | 500 | /* |
| 501 | * not supported here | 501 | * not supported here |
| 502 | */ | 502 | */ |
| 503 | int __init setup_profiling_timer(unsigned int multiplier) | 503 | int __init setup_profiling_timer(unsigned int multiplier) |
| 504 | { | 504 | { |
| 505 | return -EINVAL; | 505 | return -EINVAL; |
| 506 | } | 506 | } |
| 507 | 507 | ||
| 508 | static int | 508 | static int |
| 509 | on_each_cpu_mask(void (*func)(void *), void *info, int retry, int wait, | 509 | on_each_cpu_mask(void (*func)(void *), void *info, int retry, int wait, |
| 510 | cpumask_t mask) | 510 | cpumask_t mask) |
| 511 | { | 511 | { |
| 512 | int ret = 0; | 512 | int ret = 0; |
| 513 | 513 | ||
| 514 | preempt_disable(); | 514 | preempt_disable(); |
| 515 | 515 | ||
| 516 | ret = smp_call_function_on_cpu(func, info, retry, wait, mask); | 516 | ret = smp_call_function_on_cpu(func, info, retry, wait, mask); |
| 517 | if (cpu_isset(smp_processor_id(), mask)) | 517 | if (cpu_isset(smp_processor_id(), mask)) |
| 518 | func(info); | 518 | func(info); |
| 519 | 519 | ||
| 520 | preempt_enable(); | 520 | preempt_enable(); |
| 521 | 521 | ||
| 522 | return ret; | 522 | return ret; |
| 523 | } | 523 | } |
| 524 | 524 | ||
| 525 | /**********************************************************************/ | 525 | /**********************************************************************/ |
| 526 | 526 | ||
| 527 | /* | 527 | /* |
| 528 | * TLB operations | 528 | * TLB operations |
| 529 | */ | 529 | */ |
| 530 | struct tlb_args { | 530 | struct tlb_args { |
| 531 | struct vm_area_struct *ta_vma; | 531 | struct vm_area_struct *ta_vma; |
| 532 | unsigned long ta_start; | 532 | unsigned long ta_start; |
| 533 | unsigned long ta_end; | 533 | unsigned long ta_end; |
| 534 | }; | 534 | }; |
| 535 | 535 | ||
| 536 | static inline void ipi_flush_tlb_all(void *ignored) | 536 | static inline void ipi_flush_tlb_all(void *ignored) |
| 537 | { | 537 | { |
| 538 | local_flush_tlb_all(); | 538 | local_flush_tlb_all(); |
| 539 | } | 539 | } |
| 540 | 540 | ||
| 541 | static inline void ipi_flush_tlb_mm(void *arg) | 541 | static inline void ipi_flush_tlb_mm(void *arg) |
| 542 | { | 542 | { |
| 543 | struct mm_struct *mm = (struct mm_struct *)arg; | 543 | struct mm_struct *mm = (struct mm_struct *)arg; |
| 544 | 544 | ||
| 545 | local_flush_tlb_mm(mm); | 545 | local_flush_tlb_mm(mm); |
| 546 | } | 546 | } |
| 547 | 547 | ||
| 548 | static inline void ipi_flush_tlb_page(void *arg) | 548 | static inline void ipi_flush_tlb_page(void *arg) |
| 549 | { | 549 | { |
| 550 | struct tlb_args *ta = (struct tlb_args *)arg; | 550 | struct tlb_args *ta = (struct tlb_args *)arg; |
| 551 | 551 | ||
| 552 | local_flush_tlb_page(ta->ta_vma, ta->ta_start); | 552 | local_flush_tlb_page(ta->ta_vma, ta->ta_start); |
| 553 | } | 553 | } |
| 554 | 554 | ||
| 555 | static inline void ipi_flush_tlb_kernel_page(void *arg) | 555 | static inline void ipi_flush_tlb_kernel_page(void *arg) |
| 556 | { | 556 | { |
| 557 | struct tlb_args *ta = (struct tlb_args *)arg; | 557 | struct tlb_args *ta = (struct tlb_args *)arg; |
| 558 | 558 | ||
| 559 | local_flush_tlb_kernel_page(ta->ta_start); | 559 | local_flush_tlb_kernel_page(ta->ta_start); |
| 560 | } | 560 | } |
| 561 | 561 | ||
| 562 | static inline void ipi_flush_tlb_range(void *arg) | 562 | static inline void ipi_flush_tlb_range(void *arg) |
| 563 | { | 563 | { |
| 564 | struct tlb_args *ta = (struct tlb_args *)arg; | 564 | struct tlb_args *ta = (struct tlb_args *)arg; |
| 565 | 565 | ||
| 566 | local_flush_tlb_range(ta->ta_vma, ta->ta_start, ta->ta_end); | 566 | local_flush_tlb_range(ta->ta_vma, ta->ta_start, ta->ta_end); |
| 567 | } | 567 | } |
| 568 | 568 | ||
| 569 | static inline void ipi_flush_tlb_kernel_range(void *arg) | 569 | static inline void ipi_flush_tlb_kernel_range(void *arg) |
| 570 | { | 570 | { |
| 571 | struct tlb_args *ta = (struct tlb_args *)arg; | 571 | struct tlb_args *ta = (struct tlb_args *)arg; |
| 572 | 572 | ||
| 573 | local_flush_tlb_kernel_range(ta->ta_start, ta->ta_end); | 573 | local_flush_tlb_kernel_range(ta->ta_start, ta->ta_end); |
| 574 | } | 574 | } |
| 575 | 575 | ||
| 576 | void flush_tlb_all(void) | 576 | void flush_tlb_all(void) |
| 577 | { | 577 | { |
| 578 | on_each_cpu(ipi_flush_tlb_all, NULL, 1, 1); | 578 | on_each_cpu(ipi_flush_tlb_all, NULL, 1, 1); |
| 579 | } | 579 | } |
| 580 | 580 | ||
| 581 | void flush_tlb_mm(struct mm_struct *mm) | 581 | void flush_tlb_mm(struct mm_struct *mm) |
| 582 | { | 582 | { |
| 583 | cpumask_t mask = mm->cpu_vm_mask; | 583 | cpumask_t mask = mm->cpu_vm_mask; |
| 584 | 584 | ||
| 585 | on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, 1, mask); | 585 | on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, 1, mask); |
| 586 | } | 586 | } |
| 587 | 587 | ||
| 588 | void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) | 588 | void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) |
| 589 | { | 589 | { |
| 590 | cpumask_t mask = vma->vm_mm->cpu_vm_mask; | 590 | cpumask_t mask = vma->vm_mm->cpu_vm_mask; |
| 591 | struct tlb_args ta; | 591 | struct tlb_args ta; |
| 592 | 592 | ||
| 593 | ta.ta_vma = vma; | 593 | ta.ta_vma = vma; |
| 594 | ta.ta_start = uaddr; | 594 | ta.ta_start = uaddr; |
| 595 | 595 | ||
| 596 | on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, 1, mask); | 596 | on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, 1, mask); |
| 597 | } | 597 | } |
| 598 | 598 | ||
| 599 | void flush_tlb_kernel_page(unsigned long kaddr) | 599 | void flush_tlb_kernel_page(unsigned long kaddr) |
| 600 | { | 600 | { |
| 601 | struct tlb_args ta; | 601 | struct tlb_args ta; |
| 602 | 602 | ||
| 603 | ta.ta_start = kaddr; | 603 | ta.ta_start = kaddr; |
| 604 | 604 | ||
| 605 | on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1, 1); | 605 | on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1, 1); |
| 606 | } | 606 | } |
| 607 | 607 | ||
| 608 | void flush_tlb_range(struct vm_area_struct *vma, | 608 | void flush_tlb_range(struct vm_area_struct *vma, |
| 609 | unsigned long start, unsigned long end) | 609 | unsigned long start, unsigned long end) |
| 610 | { | 610 | { |
| 611 | cpumask_t mask = vma->vm_mm->cpu_vm_mask; | 611 | cpumask_t mask = vma->vm_mm->cpu_vm_mask; |
| 612 | struct tlb_args ta; | 612 | struct tlb_args ta; |
| 613 | 613 | ||
| 614 | ta.ta_vma = vma; | 614 | ta.ta_vma = vma; |
| 615 | ta.ta_start = start; | 615 | ta.ta_start = start; |
| 616 | ta.ta_end = end; | 616 | ta.ta_end = end; |
| 617 | 617 | ||
| 618 | on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, 1, mask); | 618 | on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, 1, mask); |
| 619 | } | 619 | } |
| 620 | 620 | ||
| 621 | void flush_tlb_kernel_range(unsigned long start, unsigned long end) | 621 | void flush_tlb_kernel_range(unsigned long start, unsigned long end) |
| 622 | { | 622 | { |
| 623 | struct tlb_args ta; | 623 | struct tlb_args ta; |
| 624 | 624 | ||
| 625 | ta.ta_start = start; | 625 | ta.ta_start = start; |
| 626 | ta.ta_end = end; | 626 | ta.ta_end = end; |
| 627 | 627 | ||
| 628 | on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1, 1); | 628 | on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1, 1); |
| 629 | } | 629 | } |
| 630 | 630 |
arch/arm/mach-footbridge/isa-irq.c
| 1 | /* | 1 | /* |
| 2 | * linux/arch/arm/mach-footbridge/irq.c | 2 | * linux/arch/arm/mach-footbridge/irq.c |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 1996-2000 Russell King | 4 | * Copyright (C) 1996-2000 Russell King |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
| 8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
| 9 | * | 9 | * |
| 10 | * Changelog: | 10 | * Changelog: |
| 11 | * 22-Aug-1998 RMK Restructured IRQ routines | 11 | * 22-Aug-1998 RMK Restructured IRQ routines |
| 12 | * 03-Sep-1998 PJB Merged CATS support | 12 | * 03-Sep-1998 PJB Merged CATS support |
| 13 | * 20-Jan-1998 RMK Started merge of EBSA286, CATS and NetWinder | 13 | * 20-Jan-1998 RMK Started merge of EBSA286, CATS and NetWinder |
| 14 | * 26-Jan-1999 PJB Don't use IACK on CATS | 14 | * 26-Jan-1999 PJB Don't use IACK on CATS |
| 15 | * 16-Mar-1999 RMK Added autodetect of ISA PICs | 15 | * 16-Mar-1999 RMK Added autodetect of ISA PICs |
| 16 | */ | 16 | */ |
| 17 | #include <linux/ioport.h> | 17 | #include <linux/ioport.h> |
| 18 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
| 19 | #include <linux/list.h> | 19 | #include <linux/list.h> |
| 20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
| 21 | 21 | ||
| 22 | #include <asm/mach/irq.h> | 22 | #include <asm/mach/irq.h> |
| 23 | 23 | ||
| 24 | #include <asm/hardware.h> | 24 | #include <asm/hardware.h> |
| 25 | #include <asm/hardware/dec21285.h> | 25 | #include <asm/hardware/dec21285.h> |
| 26 | #include <asm/irq.h> | 26 | #include <asm/irq.h> |
| 27 | #include <asm/io.h> | 27 | #include <asm/io.h> |
| 28 | #include <asm/mach-types.h> | 28 | #include <asm/mach-types.h> |
| 29 | 29 | ||
| 30 | static void isa_mask_pic_lo_irq(unsigned int irq) | 30 | static void isa_mask_pic_lo_irq(unsigned int irq) |
| 31 | { | 31 | { |
| 32 | unsigned int mask = 1 << (irq & 7); | 32 | unsigned int mask = 1 << (irq & 7); |
| 33 | 33 | ||
| 34 | outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO); | 34 | outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO); |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | static void isa_ack_pic_lo_irq(unsigned int irq) | 37 | static void isa_ack_pic_lo_irq(unsigned int irq) |
| 38 | { | 38 | { |
| 39 | unsigned int mask = 1 << (irq & 7); | 39 | unsigned int mask = 1 << (irq & 7); |
| 40 | 40 | ||
| 41 | outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO); | 41 | outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO); |
| 42 | outb(0x20, PIC_LO); | 42 | outb(0x20, PIC_LO); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | static void isa_unmask_pic_lo_irq(unsigned int irq) | 45 | static void isa_unmask_pic_lo_irq(unsigned int irq) |
| 46 | { | 46 | { |
| 47 | unsigned int mask = 1 << (irq & 7); | 47 | unsigned int mask = 1 << (irq & 7); |
| 48 | 48 | ||
| 49 | outb(inb(PIC_MASK_LO) & ~mask, PIC_MASK_LO); | 49 | outb(inb(PIC_MASK_LO) & ~mask, PIC_MASK_LO); |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | static struct irqchip isa_lo_chip = { | 52 | static struct irqchip isa_lo_chip = { |
| 53 | .ack = isa_ack_pic_lo_irq, | 53 | .ack = isa_ack_pic_lo_irq, |
| 54 | .mask = isa_mask_pic_lo_irq, | 54 | .mask = isa_mask_pic_lo_irq, |
| 55 | .unmask = isa_unmask_pic_lo_irq, | 55 | .unmask = isa_unmask_pic_lo_irq, |
| 56 | }; | 56 | }; |
| 57 | 57 | ||
| 58 | static void isa_mask_pic_hi_irq(unsigned int irq) | 58 | static void isa_mask_pic_hi_irq(unsigned int irq) |
| 59 | { | 59 | { |
| 60 | unsigned int mask = 1 << (irq & 7); | 60 | unsigned int mask = 1 << (irq & 7); |
| 61 | 61 | ||
| 62 | outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI); | 62 | outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI); |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | static void isa_ack_pic_hi_irq(unsigned int irq) | 65 | static void isa_ack_pic_hi_irq(unsigned int irq) |
| 66 | { | 66 | { |
| 67 | unsigned int mask = 1 << (irq & 7); | 67 | unsigned int mask = 1 << (irq & 7); |
| 68 | 68 | ||
| 69 | outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI); | 69 | outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI); |
| 70 | outb(0x62, PIC_LO); | 70 | outb(0x62, PIC_LO); |
| 71 | outb(0x20, PIC_HI); | 71 | outb(0x20, PIC_HI); |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | static void isa_unmask_pic_hi_irq(unsigned int irq) | 74 | static void isa_unmask_pic_hi_irq(unsigned int irq) |
| 75 | { | 75 | { |
| 76 | unsigned int mask = 1 << (irq & 7); | 76 | unsigned int mask = 1 << (irq & 7); |
| 77 | 77 | ||
| 78 | outb(inb(PIC_MASK_HI) & ~mask, PIC_MASK_HI); | 78 | outb(inb(PIC_MASK_HI) & ~mask, PIC_MASK_HI); |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | static struct irqchip isa_hi_chip = { | 81 | static struct irqchip isa_hi_chip = { |
| 82 | .ack = isa_ack_pic_hi_irq, | 82 | .ack = isa_ack_pic_hi_irq, |
| 83 | .mask = isa_mask_pic_hi_irq, | 83 | .mask = isa_mask_pic_hi_irq, |
| 84 | .unmask = isa_unmask_pic_hi_irq, | 84 | .unmask = isa_unmask_pic_hi_irq, |
| 85 | }; | 85 | }; |
| 86 | 86 | ||
| 87 | static void | 87 | static void |
| 88 | isa_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) | 88 | isa_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) |
| 89 | { | 89 | { |
| 90 | unsigned int isa_irq = *(unsigned char *)PCIIACK_BASE; | 90 | unsigned int isa_irq = *(unsigned char *)PCIIACK_BASE; |
| 91 | 91 | ||
| 92 | if (isa_irq < _ISA_IRQ(0) || isa_irq >= _ISA_IRQ(16)) { | 92 | if (isa_irq < _ISA_IRQ(0) || isa_irq >= _ISA_IRQ(16)) { |
| 93 | do_bad_IRQ(isa_irq, desc, regs); | 93 | do_bad_IRQ(isa_irq, desc, regs); |
| 94 | return; | 94 | return; |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | desc = irq_desc + isa_irq; | 97 | desc = irq_desc + isa_irq; |
| 98 | desc->handle(isa_irq, desc, regs); | 98 | desc_handle_irq(isa_irq, desc, regs); |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | static struct irqaction irq_cascade = { .handler = no_action, .name = "cascade", }; | 101 | static struct irqaction irq_cascade = { .handler = no_action, .name = "cascade", }; |
| 102 | static struct resource pic1_resource = { "pic1", 0x20, 0x3f }; | 102 | static struct resource pic1_resource = { "pic1", 0x20, 0x3f }; |
| 103 | static struct resource pic2_resource = { "pic2", 0xa0, 0xbf }; | 103 | static struct resource pic2_resource = { "pic2", 0xa0, 0xbf }; |
| 104 | 104 | ||
| 105 | void __init isa_init_irq(unsigned int host_irq) | 105 | void __init isa_init_irq(unsigned int host_irq) |
| 106 | { | 106 | { |
| 107 | unsigned int irq; | 107 | unsigned int irq; |
| 108 | 108 | ||
| 109 | /* | 109 | /* |
| 110 | * Setup, and then probe for an ISA PIC | 110 | * Setup, and then probe for an ISA PIC |
| 111 | * If the PIC is not there, then we | 111 | * If the PIC is not there, then we |
| 112 | * ignore the PIC. | 112 | * ignore the PIC. |
| 113 | */ | 113 | */ |
| 114 | outb(0x11, PIC_LO); | 114 | outb(0x11, PIC_LO); |
| 115 | outb(_ISA_IRQ(0), PIC_MASK_LO); /* IRQ number */ | 115 | outb(_ISA_IRQ(0), PIC_MASK_LO); /* IRQ number */ |
| 116 | outb(0x04, PIC_MASK_LO); /* Slave on Ch2 */ | 116 | outb(0x04, PIC_MASK_LO); /* Slave on Ch2 */ |
| 117 | outb(0x01, PIC_MASK_LO); /* x86 */ | 117 | outb(0x01, PIC_MASK_LO); /* x86 */ |
| 118 | outb(0xf5, PIC_MASK_LO); /* pattern: 11110101 */ | 118 | outb(0xf5, PIC_MASK_LO); /* pattern: 11110101 */ |
| 119 | 119 | ||
| 120 | outb(0x11, PIC_HI); | 120 | outb(0x11, PIC_HI); |
| 121 | outb(_ISA_IRQ(8), PIC_MASK_HI); /* IRQ number */ | 121 | outb(_ISA_IRQ(8), PIC_MASK_HI); /* IRQ number */ |
| 122 | outb(0x02, PIC_MASK_HI); /* Slave on Ch1 */ | 122 | outb(0x02, PIC_MASK_HI); /* Slave on Ch1 */ |
| 123 | outb(0x01, PIC_MASK_HI); /* x86 */ | 123 | outb(0x01, PIC_MASK_HI); /* x86 */ |
| 124 | outb(0xfa, PIC_MASK_HI); /* pattern: 11111010 */ | 124 | outb(0xfa, PIC_MASK_HI); /* pattern: 11111010 */ |
| 125 | 125 | ||
| 126 | outb(0x0b, PIC_LO); | 126 | outb(0x0b, PIC_LO); |
| 127 | outb(0x0b, PIC_HI); | 127 | outb(0x0b, PIC_HI); |
| 128 | 128 | ||
| 129 | if (inb(PIC_MASK_LO) == 0xf5 && inb(PIC_MASK_HI) == 0xfa) { | 129 | if (inb(PIC_MASK_LO) == 0xf5 && inb(PIC_MASK_HI) == 0xfa) { |
| 130 | outb(0xff, PIC_MASK_LO);/* mask all IRQs */ | 130 | outb(0xff, PIC_MASK_LO);/* mask all IRQs */ |
| 131 | outb(0xff, PIC_MASK_HI);/* mask all IRQs */ | 131 | outb(0xff, PIC_MASK_HI);/* mask all IRQs */ |
| 132 | } else { | 132 | } else { |
| 133 | printk(KERN_INFO "IRQ: ISA PIC not found\n"); | 133 | printk(KERN_INFO "IRQ: ISA PIC not found\n"); |
| 134 | host_irq = (unsigned int)-1; | 134 | host_irq = (unsigned int)-1; |
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | if (host_irq != (unsigned int)-1) { | 137 | if (host_irq != (unsigned int)-1) { |
| 138 | for (irq = _ISA_IRQ(0); irq < _ISA_IRQ(8); irq++) { | 138 | for (irq = _ISA_IRQ(0); irq < _ISA_IRQ(8); irq++) { |
| 139 | set_irq_chip(irq, &isa_lo_chip); | 139 | set_irq_chip(irq, &isa_lo_chip); |
| 140 | set_irq_handler(irq, do_level_IRQ); | 140 | set_irq_handler(irq, do_level_IRQ); |
| 141 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 141 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | for (irq = _ISA_IRQ(8); irq < _ISA_IRQ(16); irq++) { | 144 | for (irq = _ISA_IRQ(8); irq < _ISA_IRQ(16); irq++) { |
| 145 | set_irq_chip(irq, &isa_hi_chip); | 145 | set_irq_chip(irq, &isa_hi_chip); |
| 146 | set_irq_handler(irq, do_level_IRQ); | 146 | set_irq_handler(irq, do_level_IRQ); |
| 147 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 147 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | request_resource(&ioport_resource, &pic1_resource); | 150 | request_resource(&ioport_resource, &pic1_resource); |
| 151 | request_resource(&ioport_resource, &pic2_resource); | 151 | request_resource(&ioport_resource, &pic2_resource); |
| 152 | setup_irq(IRQ_ISA_CASCADE, &irq_cascade); | 152 | setup_irq(IRQ_ISA_CASCADE, &irq_cascade); |
| 153 | 153 | ||
| 154 | set_irq_chained_handler(host_irq, isa_irq_handler); | 154 | set_irq_chained_handler(host_irq, isa_irq_handler); |
| 155 | 155 | ||
| 156 | /* | 156 | /* |
| 157 | * On the NetWinder, don't automatically | 157 | * On the NetWinder, don't automatically |
| 158 | * enable ISA IRQ11 when it is requested. | 158 | * enable ISA IRQ11 when it is requested. |
| 159 | * There appears to be a missing pull-up | 159 | * There appears to be a missing pull-up |
| 160 | * resistor on this line. | 160 | * resistor on this line. |
| 161 | */ | 161 | */ |
| 162 | if (machine_is_netwinder()) | 162 | if (machine_is_netwinder()) |
| 163 | set_irq_flags(_ISA_IRQ(11), IRQF_VALID | | 163 | set_irq_flags(_ISA_IRQ(11), IRQF_VALID | |
| 164 | IRQF_PROBE | IRQF_NOAUTOEN); | 164 | IRQF_PROBE | IRQF_NOAUTOEN); |
| 165 | } | 165 | } |
| 166 | } | 166 | } |
| 167 | 167 | ||
| 168 | 168 | ||
| 169 | 169 |
arch/arm/mach-h720x/common.c
| 1 | /* | 1 | /* |
| 2 | * linux/arch/arm/mach-h720x/common.c | 2 | * linux/arch/arm/mach-h720x/common.c |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2003 Thomas Gleixner <tglx@linutronix.de> | 4 | * Copyright (C) 2003 Thomas Gleixner <tglx@linutronix.de> |
| 5 | * 2003 Robert Schwebel <r.schwebel@pengutronix.de> | 5 | * 2003 Robert Schwebel <r.schwebel@pengutronix.de> |
| 6 | * 2004 Sascha Hauer <s.hauer@pengutronix.de> | 6 | * 2004 Sascha Hauer <s.hauer@pengutronix.de> |
| 7 | * | 7 | * |
| 8 | * common stuff for Hynix h720x processors | 8 | * common stuff for Hynix h720x processors |
| 9 | * | 9 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of the GNU General Public License version 2 as | 11 | * it under the terms of the GNU General Public License version 2 as |
| 12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
| 13 | * | 13 | * |
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| 16 | #include <linux/sched.h> | 16 | #include <linux/sched.h> |
| 17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
| 18 | #include <linux/mman.h> | 18 | #include <linux/mman.h> |
| 19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
| 20 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
| 21 | 21 | ||
| 22 | #include <asm/page.h> | 22 | #include <asm/page.h> |
| 23 | #include <asm/pgtable.h> | 23 | #include <asm/pgtable.h> |
| 24 | #include <asm/dma.h> | 24 | #include <asm/dma.h> |
| 25 | #include <asm/io.h> | 25 | #include <asm/io.h> |
| 26 | #include <asm/hardware.h> | 26 | #include <asm/hardware.h> |
| 27 | #include <asm/irq.h> | 27 | #include <asm/irq.h> |
| 28 | #include <asm/mach/irq.h> | 28 | #include <asm/mach/irq.h> |
| 29 | #include <asm/mach/map.h> | 29 | #include <asm/mach/map.h> |
| 30 | #include <asm/arch/irqs.h> | 30 | #include <asm/arch/irqs.h> |
| 31 | 31 | ||
| 32 | #include <asm/mach/dma.h> | 32 | #include <asm/mach/dma.h> |
| 33 | 33 | ||
| 34 | #if 0 | 34 | #if 0 |
| 35 | #define IRQDBG(args...) printk(args) | 35 | #define IRQDBG(args...) printk(args) |
| 36 | #else | 36 | #else |
| 37 | #define IRQDBG(args...) do {} while(0) | 37 | #define IRQDBG(args...) do {} while(0) |
| 38 | #endif | 38 | #endif |
| 39 | 39 | ||
| 40 | void __init arch_dma_init(dma_t *dma) | 40 | void __init arch_dma_init(dma_t *dma) |
| 41 | { | 41 | { |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | /* | 44 | /* |
| 45 | * Return usecs since last timer reload | 45 | * Return usecs since last timer reload |
| 46 | * (timercount * (usecs perjiffie)) / (ticks per jiffie) | 46 | * (timercount * (usecs perjiffie)) / (ticks per jiffie) |
| 47 | */ | 47 | */ |
| 48 | unsigned long h720x_gettimeoffset(void) | 48 | unsigned long h720x_gettimeoffset(void) |
| 49 | { | 49 | { |
| 50 | return (CPU_REG (TIMER_VIRT, TM0_COUNT) * tick_usec) / LATCH; | 50 | return (CPU_REG (TIMER_VIRT, TM0_COUNT) * tick_usec) / LATCH; |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | /* | 53 | /* |
| 54 | * mask Global irq's | 54 | * mask Global irq's |
| 55 | */ | 55 | */ |
| 56 | static void mask_global_irq (unsigned int irq ) | 56 | static void mask_global_irq (unsigned int irq ) |
| 57 | { | 57 | { |
| 58 | CPU_REG (IRQC_VIRT, IRQC_IER) &= ~(1 << irq); | 58 | CPU_REG (IRQC_VIRT, IRQC_IER) &= ~(1 << irq); |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | /* | 61 | /* |
| 62 | * unmask Global irq's | 62 | * unmask Global irq's |
| 63 | */ | 63 | */ |
| 64 | static void unmask_global_irq (unsigned int irq ) | 64 | static void unmask_global_irq (unsigned int irq ) |
| 65 | { | 65 | { |
| 66 | CPU_REG (IRQC_VIRT, IRQC_IER) |= (1 << irq); | 66 | CPU_REG (IRQC_VIRT, IRQC_IER) |= (1 << irq); |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | 69 | ||
| 70 | /* | 70 | /* |
| 71 | * ack GPIO irq's | 71 | * ack GPIO irq's |
| 72 | * Ack only for edge triggered int's valid | 72 | * Ack only for edge triggered int's valid |
| 73 | */ | 73 | */ |
| 74 | static void inline ack_gpio_irq(u32 irq) | 74 | static void inline ack_gpio_irq(u32 irq) |
| 75 | { | 75 | { |
| 76 | u32 reg_base = GPIO_VIRT(IRQ_TO_REGNO(irq)); | 76 | u32 reg_base = GPIO_VIRT(IRQ_TO_REGNO(irq)); |
| 77 | u32 bit = IRQ_TO_BIT(irq); | 77 | u32 bit = IRQ_TO_BIT(irq); |
| 78 | if ( (CPU_REG (reg_base, GPIO_EDGE) & bit)) | 78 | if ( (CPU_REG (reg_base, GPIO_EDGE) & bit)) |
| 79 | CPU_REG (reg_base, GPIO_CLR) = bit; | 79 | CPU_REG (reg_base, GPIO_CLR) = bit; |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | /* | 82 | /* |
| 83 | * mask GPIO irq's | 83 | * mask GPIO irq's |
| 84 | */ | 84 | */ |
| 85 | static void inline mask_gpio_irq(u32 irq) | 85 | static void inline mask_gpio_irq(u32 irq) |
| 86 | { | 86 | { |
| 87 | u32 reg_base = GPIO_VIRT(IRQ_TO_REGNO(irq)); | 87 | u32 reg_base = GPIO_VIRT(IRQ_TO_REGNO(irq)); |
| 88 | u32 bit = IRQ_TO_BIT(irq); | 88 | u32 bit = IRQ_TO_BIT(irq); |
| 89 | CPU_REG (reg_base, GPIO_MASK) &= ~bit; | 89 | CPU_REG (reg_base, GPIO_MASK) &= ~bit; |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | /* | 92 | /* |
| 93 | * unmask GPIO irq's | 93 | * unmask GPIO irq's |
| 94 | */ | 94 | */ |
| 95 | static void inline unmask_gpio_irq(u32 irq) | 95 | static void inline unmask_gpio_irq(u32 irq) |
| 96 | { | 96 | { |
| 97 | u32 reg_base = GPIO_VIRT(IRQ_TO_REGNO(irq)); | 97 | u32 reg_base = GPIO_VIRT(IRQ_TO_REGNO(irq)); |
| 98 | u32 bit = IRQ_TO_BIT(irq); | 98 | u32 bit = IRQ_TO_BIT(irq); |
| 99 | CPU_REG (reg_base, GPIO_MASK) |= bit; | 99 | CPU_REG (reg_base, GPIO_MASK) |= bit; |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | static void | 102 | static void |
| 103 | h720x_gpio_handler(unsigned int mask, unsigned int irq, | 103 | h720x_gpio_handler(unsigned int mask, unsigned int irq, |
| 104 | struct irqdesc *desc, struct pt_regs *regs) | 104 | struct irqdesc *desc, struct pt_regs *regs) |
| 105 | { | 105 | { |
| 106 | IRQDBG("%s irq: %d\n",__FUNCTION__,irq); | 106 | IRQDBG("%s irq: %d\n",__FUNCTION__,irq); |
| 107 | desc = irq_desc + irq; | 107 | desc = irq_desc + irq; |
| 108 | while (mask) { | 108 | while (mask) { |
| 109 | if (mask & 1) { | 109 | if (mask & 1) { |
| 110 | IRQDBG("handling irq %d\n", irq); | 110 | IRQDBG("handling irq %d\n", irq); |
| 111 | desc->handle(irq, desc, regs); | 111 | desc_handle_irq(irq, desc, regs); |
| 112 | } | 112 | } |
| 113 | irq++; | 113 | irq++; |
| 114 | desc++; | 114 | desc++; |
| 115 | mask >>= 1; | 115 | mask >>= 1; |
| 116 | } | 116 | } |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | static void | 119 | static void |
| 120 | h720x_gpioa_demux_handler(unsigned int irq_unused, struct irqdesc *desc, | 120 | h720x_gpioa_demux_handler(unsigned int irq_unused, struct irqdesc *desc, |
| 121 | struct pt_regs *regs) | 121 | struct pt_regs *regs) |
| 122 | { | 122 | { |
| 123 | unsigned int mask, irq; | 123 | unsigned int mask, irq; |
| 124 | 124 | ||
| 125 | mask = CPU_REG(GPIO_A_VIRT,GPIO_STAT); | 125 | mask = CPU_REG(GPIO_A_VIRT,GPIO_STAT); |
| 126 | irq = IRQ_CHAINED_GPIOA(0); | 126 | irq = IRQ_CHAINED_GPIOA(0); |
| 127 | IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq); | 127 | IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq); |
| 128 | h720x_gpio_handler(mask, irq, desc, regs); | 128 | h720x_gpio_handler(mask, irq, desc, regs); |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | static void | 131 | static void |
| 132 | h720x_gpiob_demux_handler(unsigned int irq_unused, struct irqdesc *desc, | 132 | h720x_gpiob_demux_handler(unsigned int irq_unused, struct irqdesc *desc, |
| 133 | struct pt_regs *regs) | 133 | struct pt_regs *regs) |
| 134 | { | 134 | { |
| 135 | unsigned int mask, irq; | 135 | unsigned int mask, irq; |
| 136 | mask = CPU_REG(GPIO_B_VIRT,GPIO_STAT); | 136 | mask = CPU_REG(GPIO_B_VIRT,GPIO_STAT); |
| 137 | irq = IRQ_CHAINED_GPIOB(0); | 137 | irq = IRQ_CHAINED_GPIOB(0); |
| 138 | IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq); | 138 | IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq); |
| 139 | h720x_gpio_handler(mask, irq, desc, regs); | 139 | h720x_gpio_handler(mask, irq, desc, regs); |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | static void | 142 | static void |
| 143 | h720x_gpioc_demux_handler(unsigned int irq_unused, struct irqdesc *desc, | 143 | h720x_gpioc_demux_handler(unsigned int irq_unused, struct irqdesc *desc, |
| 144 | struct pt_regs *regs) | 144 | struct pt_regs *regs) |
| 145 | { | 145 | { |
| 146 | unsigned int mask, irq; | 146 | unsigned int mask, irq; |
| 147 | 147 | ||
| 148 | mask = CPU_REG(GPIO_C_VIRT,GPIO_STAT); | 148 | mask = CPU_REG(GPIO_C_VIRT,GPIO_STAT); |
| 149 | irq = IRQ_CHAINED_GPIOC(0); | 149 | irq = IRQ_CHAINED_GPIOC(0); |
| 150 | IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq); | 150 | IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq); |
| 151 | h720x_gpio_handler(mask, irq, desc, regs); | 151 | h720x_gpio_handler(mask, irq, desc, regs); |
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | static void | 154 | static void |
| 155 | h720x_gpiod_demux_handler(unsigned int irq_unused, struct irqdesc *desc, | 155 | h720x_gpiod_demux_handler(unsigned int irq_unused, struct irqdesc *desc, |
| 156 | struct pt_regs *regs) | 156 | struct pt_regs *regs) |
| 157 | { | 157 | { |
| 158 | unsigned int mask, irq; | 158 | unsigned int mask, irq; |
| 159 | 159 | ||
| 160 | mask = CPU_REG(GPIO_D_VIRT,GPIO_STAT); | 160 | mask = CPU_REG(GPIO_D_VIRT,GPIO_STAT); |
| 161 | irq = IRQ_CHAINED_GPIOD(0); | 161 | irq = IRQ_CHAINED_GPIOD(0); |
| 162 | IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq); | 162 | IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq); |
| 163 | h720x_gpio_handler(mask, irq, desc, regs); | 163 | h720x_gpio_handler(mask, irq, desc, regs); |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | #ifdef CONFIG_CPU_H7202 | 166 | #ifdef CONFIG_CPU_H7202 |
| 167 | static void | 167 | static void |
| 168 | h720x_gpioe_demux_handler(unsigned int irq_unused, struct irqdesc *desc, | 168 | h720x_gpioe_demux_handler(unsigned int irq_unused, struct irqdesc *desc, |
| 169 | struct pt_regs *regs) | 169 | struct pt_regs *regs) |
| 170 | { | 170 | { |
| 171 | unsigned int mask, irq; | 171 | unsigned int mask, irq; |
| 172 | 172 | ||
| 173 | mask = CPU_REG(GPIO_E_VIRT,GPIO_STAT); | 173 | mask = CPU_REG(GPIO_E_VIRT,GPIO_STAT); |
| 174 | irq = IRQ_CHAINED_GPIOE(0); | 174 | irq = IRQ_CHAINED_GPIOE(0); |
| 175 | IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq); | 175 | IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq); |
| 176 | h720x_gpio_handler(mask, irq, desc, regs); | 176 | h720x_gpio_handler(mask, irq, desc, regs); |
| 177 | } | 177 | } |
| 178 | #endif | 178 | #endif |
| 179 | 179 | ||
| 180 | static struct irqchip h720x_global_chip = { | 180 | static struct irqchip h720x_global_chip = { |
| 181 | .ack = mask_global_irq, | 181 | .ack = mask_global_irq, |
| 182 | .mask = mask_global_irq, | 182 | .mask = mask_global_irq, |
| 183 | .unmask = unmask_global_irq, | 183 | .unmask = unmask_global_irq, |
| 184 | }; | 184 | }; |
| 185 | 185 | ||
| 186 | static struct irqchip h720x_gpio_chip = { | 186 | static struct irqchip h720x_gpio_chip = { |
| 187 | .ack = ack_gpio_irq, | 187 | .ack = ack_gpio_irq, |
| 188 | .mask = mask_gpio_irq, | 188 | .mask = mask_gpio_irq, |
| 189 | .unmask = unmask_gpio_irq, | 189 | .unmask = unmask_gpio_irq, |
| 190 | }; | 190 | }; |
| 191 | 191 | ||
| 192 | /* | 192 | /* |
| 193 | * Initialize IRQ's, mask all, enable multiplexed irq's | 193 | * Initialize IRQ's, mask all, enable multiplexed irq's |
| 194 | */ | 194 | */ |
| 195 | void __init h720x_init_irq (void) | 195 | void __init h720x_init_irq (void) |
| 196 | { | 196 | { |
| 197 | int irq; | 197 | int irq; |
| 198 | 198 | ||
| 199 | /* Mask global irq's */ | 199 | /* Mask global irq's */ |
| 200 | CPU_REG (IRQC_VIRT, IRQC_IER) = 0x0; | 200 | CPU_REG (IRQC_VIRT, IRQC_IER) = 0x0; |
| 201 | 201 | ||
| 202 | /* Mask all multiplexed irq's */ | 202 | /* Mask all multiplexed irq's */ |
| 203 | CPU_REG (GPIO_A_VIRT, GPIO_MASK) = 0x0; | 203 | CPU_REG (GPIO_A_VIRT, GPIO_MASK) = 0x0; |
| 204 | CPU_REG (GPIO_B_VIRT, GPIO_MASK) = 0x0; | 204 | CPU_REG (GPIO_B_VIRT, GPIO_MASK) = 0x0; |
| 205 | CPU_REG (GPIO_C_VIRT, GPIO_MASK) = 0x0; | 205 | CPU_REG (GPIO_C_VIRT, GPIO_MASK) = 0x0; |
| 206 | CPU_REG (GPIO_D_VIRT, GPIO_MASK) = 0x0; | 206 | CPU_REG (GPIO_D_VIRT, GPIO_MASK) = 0x0; |
| 207 | 207 | ||
| 208 | /* Initialize global IRQ's, fast path */ | 208 | /* Initialize global IRQ's, fast path */ |
| 209 | for (irq = 0; irq < NR_GLBL_IRQS; irq++) { | 209 | for (irq = 0; irq < NR_GLBL_IRQS; irq++) { |
| 210 | set_irq_chip(irq, &h720x_global_chip); | 210 | set_irq_chip(irq, &h720x_global_chip); |
| 211 | set_irq_handler(irq, do_level_IRQ); | 211 | set_irq_handler(irq, do_level_IRQ); |
| 212 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 212 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
| 213 | } | 213 | } |
| 214 | 214 | ||
| 215 | /* Initialize multiplexed IRQ's, slow path */ | 215 | /* Initialize multiplexed IRQ's, slow path */ |
| 216 | for (irq = IRQ_CHAINED_GPIOA(0) ; irq <= IRQ_CHAINED_GPIOD(31); irq++) { | 216 | for (irq = IRQ_CHAINED_GPIOA(0) ; irq <= IRQ_CHAINED_GPIOD(31); irq++) { |
| 217 | set_irq_chip(irq, &h720x_gpio_chip); | 217 | set_irq_chip(irq, &h720x_gpio_chip); |
| 218 | set_irq_handler(irq, do_edge_IRQ); | 218 | set_irq_handler(irq, do_edge_IRQ); |
| 219 | set_irq_flags(irq, IRQF_VALID ); | 219 | set_irq_flags(irq, IRQF_VALID ); |
| 220 | } | 220 | } |
| 221 | set_irq_chained_handler(IRQ_GPIOA, h720x_gpioa_demux_handler); | 221 | set_irq_chained_handler(IRQ_GPIOA, h720x_gpioa_demux_handler); |
| 222 | set_irq_chained_handler(IRQ_GPIOB, h720x_gpiob_demux_handler); | 222 | set_irq_chained_handler(IRQ_GPIOB, h720x_gpiob_demux_handler); |
| 223 | set_irq_chained_handler(IRQ_GPIOC, h720x_gpioc_demux_handler); | 223 | set_irq_chained_handler(IRQ_GPIOC, h720x_gpioc_demux_handler); |
| 224 | set_irq_chained_handler(IRQ_GPIOD, h720x_gpiod_demux_handler); | 224 | set_irq_chained_handler(IRQ_GPIOD, h720x_gpiod_demux_handler); |
| 225 | 225 | ||
| 226 | #ifdef CONFIG_CPU_H7202 | 226 | #ifdef CONFIG_CPU_H7202 |
| 227 | for (irq = IRQ_CHAINED_GPIOE(0) ; irq <= IRQ_CHAINED_GPIOE(31); irq++) { | 227 | for (irq = IRQ_CHAINED_GPIOE(0) ; irq <= IRQ_CHAINED_GPIOE(31); irq++) { |
| 228 | set_irq_chip(irq, &h720x_gpio_chip); | 228 | set_irq_chip(irq, &h720x_gpio_chip); |
| 229 | set_irq_handler(irq, do_edge_IRQ); | 229 | set_irq_handler(irq, do_edge_IRQ); |
| 230 | set_irq_flags(irq, IRQF_VALID ); | 230 | set_irq_flags(irq, IRQF_VALID ); |
| 231 | } | 231 | } |
| 232 | set_irq_chained_handler(IRQ_GPIOE, h720x_gpioe_demux_handler); | 232 | set_irq_chained_handler(IRQ_GPIOE, h720x_gpioe_demux_handler); |
| 233 | #endif | 233 | #endif |
| 234 | 234 | ||
| 235 | /* Enable multiplexed irq's */ | 235 | /* Enable multiplexed irq's */ |
| 236 | CPU_REG (IRQC_VIRT, IRQC_IER) = IRQ_ENA_MUX; | 236 | CPU_REG (IRQC_VIRT, IRQC_IER) = IRQ_ENA_MUX; |
| 237 | } | 237 | } |
| 238 | 238 | ||
| 239 | static struct map_desc h720x_io_desc[] __initdata = { | 239 | static struct map_desc h720x_io_desc[] __initdata = { |
| 240 | { IO_VIRT, IO_PHYS, IO_SIZE, MT_DEVICE }, | 240 | { IO_VIRT, IO_PHYS, IO_SIZE, MT_DEVICE }, |
| 241 | }; | 241 | }; |
| 242 | 242 | ||
| 243 | /* Initialize io tables */ | 243 | /* Initialize io tables */ |
| 244 | void __init h720x_map_io(void) | 244 | void __init h720x_map_io(void) |
| 245 | { | 245 | { |
| 246 | iotable_init(h720x_io_desc,ARRAY_SIZE(h720x_io_desc)); | 246 | iotable_init(h720x_io_desc,ARRAY_SIZE(h720x_io_desc)); |
| 247 | } | 247 | } |
| 248 | 248 |
arch/arm/mach-h720x/cpu-h7202.c
| 1 | /* | 1 | /* |
| 2 | * linux/arch/arm/mach-h720x/cpu-h7202.c | 2 | * linux/arch/arm/mach-h720x/cpu-h7202.c |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2003 Thomas Gleixner <tglx@linutronix.de> | 4 | * Copyright (C) 2003 Thomas Gleixner <tglx@linutronix.de> |
| 5 | * 2003 Robert Schwebel <r.schwebel@pengutronix.de> | 5 | * 2003 Robert Schwebel <r.schwebel@pengutronix.de> |
| 6 | * 2004 Sascha Hauer <s.hauer@pengutronix.de> | 6 | * 2004 Sascha Hauer <s.hauer@pengutronix.de> |
| 7 | * | 7 | * |
| 8 | * processor specific stuff for the Hynix h7202 | 8 | * processor specific stuff for the Hynix h7202 |
| 9 | * | 9 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of the GNU General Public License version 2 as | 11 | * it under the terms of the GNU General Public License version 2 as |
| 12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
| 13 | * | 13 | * |
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| 16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
| 17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
| 18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
| 19 | #include <asm/types.h> | 19 | #include <asm/types.h> |
| 20 | #include <asm/hardware.h> | 20 | #include <asm/hardware.h> |
| 21 | #include <asm/irq.h> | 21 | #include <asm/irq.h> |
| 22 | #include <asm/arch/irqs.h> | 22 | #include <asm/arch/irqs.h> |
| 23 | #include <asm/mach/irq.h> | 23 | #include <asm/mach/irq.h> |
| 24 | #include <asm/mach/time.h> | 24 | #include <asm/mach/time.h> |
| 25 | #include <linux/device.h> | 25 | #include <linux/device.h> |
| 26 | #include <linux/serial_8250.h> | 26 | #include <linux/serial_8250.h> |
| 27 | #include "common.h" | 27 | #include "common.h" |
| 28 | 28 | ||
| 29 | static struct resource h7202ps2_resources[] = { | 29 | static struct resource h7202ps2_resources[] = { |
| 30 | [0] = { | 30 | [0] = { |
| 31 | .start = 0x8002c000, | 31 | .start = 0x8002c000, |
| 32 | .end = 0x8002c040, | 32 | .end = 0x8002c040, |
| 33 | .flags = IORESOURCE_MEM, | 33 | .flags = IORESOURCE_MEM, |
| 34 | }, | 34 | }, |
| 35 | [1] = { | 35 | [1] = { |
| 36 | .start = IRQ_PS2, | 36 | .start = IRQ_PS2, |
| 37 | .end = IRQ_PS2, | 37 | .end = IRQ_PS2, |
| 38 | .flags = IORESOURCE_IRQ, | 38 | .flags = IORESOURCE_IRQ, |
| 39 | }, | 39 | }, |
| 40 | }; | 40 | }; |
| 41 | 41 | ||
| 42 | static struct platform_device h7202ps2_device = { | 42 | static struct platform_device h7202ps2_device = { |
| 43 | .name = "h7202ps2", | 43 | .name = "h7202ps2", |
| 44 | .id = -1, | 44 | .id = -1, |
| 45 | .num_resources = ARRAY_SIZE(h7202ps2_resources), | 45 | .num_resources = ARRAY_SIZE(h7202ps2_resources), |
| 46 | .resource = h7202ps2_resources, | 46 | .resource = h7202ps2_resources, |
| 47 | }; | 47 | }; |
| 48 | 48 | ||
| 49 | static struct plat_serial8250_port serial_platform_data[] = { | 49 | static struct plat_serial8250_port serial_platform_data[] = { |
| 50 | { | 50 | { |
| 51 | .membase = (void*)SERIAL0_VIRT, | 51 | .membase = (void*)SERIAL0_VIRT, |
| 52 | .mapbase = SERIAL0_BASE, | 52 | .mapbase = SERIAL0_BASE, |
| 53 | .irq = IRQ_UART0, | 53 | .irq = IRQ_UART0, |
| 54 | .uartclk = 2*1843200, | 54 | .uartclk = 2*1843200, |
| 55 | .regshift = 2, | 55 | .regshift = 2, |
| 56 | .iotype = UPIO_MEM, | 56 | .iotype = UPIO_MEM, |
| 57 | .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, | 57 | .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, |
| 58 | }, | 58 | }, |
| 59 | { | 59 | { |
| 60 | .membase = (void*)SERIAL1_VIRT, | 60 | .membase = (void*)SERIAL1_VIRT, |
| 61 | .mapbase = SERIAL1_BASE, | 61 | .mapbase = SERIAL1_BASE, |
| 62 | .irq = IRQ_UART1, | 62 | .irq = IRQ_UART1, |
| 63 | .uartclk = 2*1843200, | 63 | .uartclk = 2*1843200, |
| 64 | .regshift = 2, | 64 | .regshift = 2, |
| 65 | .iotype = UPIO_MEM, | 65 | .iotype = UPIO_MEM, |
| 66 | .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, | 66 | .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, |
| 67 | }, | 67 | }, |
| 68 | #ifdef CONFIG_H7202_SERIAL23 | 68 | #ifdef CONFIG_H7202_SERIAL23 |
| 69 | { | 69 | { |
| 70 | .membase = (void*)SERIAL2_VIRT, | 70 | .membase = (void*)SERIAL2_VIRT, |
| 71 | .mapbase = SERIAL2_BASE, | 71 | .mapbase = SERIAL2_BASE, |
| 72 | .irq = IRQ_UART2, | 72 | .irq = IRQ_UART2, |
| 73 | .uartclk = 2*1843200, | 73 | .uartclk = 2*1843200, |
| 74 | .regshift = 2, | 74 | .regshift = 2, |
| 75 | .iotype = UPIO_MEM, | 75 | .iotype = UPIO_MEM, |
| 76 | .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, | 76 | .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, |
| 77 | }, | 77 | }, |
| 78 | { | 78 | { |
| 79 | .membase = (void*)SERIAL3_VIRT, | 79 | .membase = (void*)SERIAL3_VIRT, |
| 80 | .mapbase = SERIAL3_BASE, | 80 | .mapbase = SERIAL3_BASE, |
| 81 | .irq = IRQ_UART3, | 81 | .irq = IRQ_UART3, |
| 82 | .uartclk = 2*1843200, | 82 | .uartclk = 2*1843200, |
| 83 | .regshift = 2, | 83 | .regshift = 2, |
| 84 | .iotype = UPIO_MEM, | 84 | .iotype = UPIO_MEM, |
| 85 | .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, | 85 | .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, |
| 86 | }, | 86 | }, |
| 87 | #endif | 87 | #endif |
| 88 | { }, | 88 | { }, |
| 89 | }; | 89 | }; |
| 90 | 90 | ||
| 91 | static struct platform_device serial_device = { | 91 | static struct platform_device serial_device = { |
| 92 | .name = "serial8250", | 92 | .name = "serial8250", |
| 93 | .id = 0, | 93 | .id = 0, |
| 94 | .dev = { | 94 | .dev = { |
| 95 | .platform_data = serial_platform_data, | 95 | .platform_data = serial_platform_data, |
| 96 | }, | 96 | }, |
| 97 | }; | 97 | }; |
| 98 | 98 | ||
| 99 | static struct platform_device *devices[] __initdata = { | 99 | static struct platform_device *devices[] __initdata = { |
| 100 | &h7202ps2_device, | 100 | &h7202ps2_device, |
| 101 | &serial_device, | 101 | &serial_device, |
| 102 | }; | 102 | }; |
| 103 | 103 | ||
| 104 | /* Although we have two interrupt lines for the timers, we only have one | 104 | /* Although we have two interrupt lines for the timers, we only have one |
| 105 | * status register which clears all pending timer interrupts on reading. So | 105 | * status register which clears all pending timer interrupts on reading. So |
| 106 | * we have to handle all timer interrupts in one place. | 106 | * we have to handle all timer interrupts in one place. |
| 107 | */ | 107 | */ |
| 108 | static void | 108 | static void |
| 109 | h7202_timerx_demux_handler(unsigned int irq_unused, struct irqdesc *desc, | 109 | h7202_timerx_demux_handler(unsigned int irq_unused, struct irqdesc *desc, |
| 110 | struct pt_regs *regs) | 110 | struct pt_regs *regs) |
| 111 | { | 111 | { |
| 112 | unsigned int mask, irq; | 112 | unsigned int mask, irq; |
| 113 | 113 | ||
| 114 | mask = CPU_REG (TIMER_VIRT, TIMER_TOPSTAT); | 114 | mask = CPU_REG (TIMER_VIRT, TIMER_TOPSTAT); |
| 115 | 115 | ||
| 116 | if ( mask & TSTAT_T0INT ) { | 116 | if ( mask & TSTAT_T0INT ) { |
| 117 | write_seqlock(&xtime_lock); | 117 | write_seqlock(&xtime_lock); |
| 118 | timer_tick(regs); | 118 | timer_tick(regs); |
| 119 | write_sequnlock(&xtime_lock); | 119 | write_sequnlock(&xtime_lock); |
| 120 | if( mask == TSTAT_T0INT ) | 120 | if( mask == TSTAT_T0INT ) |
| 121 | return; | 121 | return; |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | mask >>= 1; | 124 | mask >>= 1; |
| 125 | irq = IRQ_TIMER1; | 125 | irq = IRQ_TIMER1; |
| 126 | desc = irq_desc + irq; | 126 | desc = irq_desc + irq; |
| 127 | while (mask) { | 127 | while (mask) { |
| 128 | if (mask & 1) | 128 | if (mask & 1) |
| 129 | desc->handle(irq, desc, regs); | 129 | desc_handle_irq(irq, desc, regs); |
| 130 | irq++; | 130 | irq++; |
| 131 | desc++; | 131 | desc++; |
| 132 | mask >>= 1; | 132 | mask >>= 1; |
| 133 | } | 133 | } |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | /* | 136 | /* |
| 137 | * Timer interrupt handler | 137 | * Timer interrupt handler |
| 138 | */ | 138 | */ |
| 139 | static irqreturn_t | 139 | static irqreturn_t |
| 140 | h7202_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 140 | h7202_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) |
| 141 | { | 141 | { |
| 142 | h7202_timerx_demux_handler(0, NULL, regs); | 142 | h7202_timerx_demux_handler(0, NULL, regs); |
| 143 | return IRQ_HANDLED; | 143 | return IRQ_HANDLED; |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | /* | 146 | /* |
| 147 | * mask multiplexed timer irq's | 147 | * mask multiplexed timer irq's |
| 148 | */ | 148 | */ |
| 149 | static void inline mask_timerx_irq (u32 irq) | 149 | static void inline mask_timerx_irq (u32 irq) |
| 150 | { | 150 | { |
| 151 | unsigned int bit; | 151 | unsigned int bit; |
| 152 | bit = 2 << ((irq == IRQ_TIMER64B) ? 4 : (irq - IRQ_TIMER1)); | 152 | bit = 2 << ((irq == IRQ_TIMER64B) ? 4 : (irq - IRQ_TIMER1)); |
| 153 | CPU_REG (TIMER_VIRT, TIMER_TOPCTRL) &= ~bit; | 153 | CPU_REG (TIMER_VIRT, TIMER_TOPCTRL) &= ~bit; |
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | /* | 156 | /* |
| 157 | * unmask multiplexed timer irq's | 157 | * unmask multiplexed timer irq's |
| 158 | */ | 158 | */ |
| 159 | static void inline unmask_timerx_irq (u32 irq) | 159 | static void inline unmask_timerx_irq (u32 irq) |
| 160 | { | 160 | { |
| 161 | unsigned int bit; | 161 | unsigned int bit; |
| 162 | bit = 2 << ((irq == IRQ_TIMER64B) ? 4 : (irq - IRQ_TIMER1)); | 162 | bit = 2 << ((irq == IRQ_TIMER64B) ? 4 : (irq - IRQ_TIMER1)); |
| 163 | CPU_REG (TIMER_VIRT, TIMER_TOPCTRL) |= bit; | 163 | CPU_REG (TIMER_VIRT, TIMER_TOPCTRL) |= bit; |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | static struct irqchip h7202_timerx_chip = { | 166 | static struct irqchip h7202_timerx_chip = { |
| 167 | .ack = mask_timerx_irq, | 167 | .ack = mask_timerx_irq, |
| 168 | .mask = mask_timerx_irq, | 168 | .mask = mask_timerx_irq, |
| 169 | .unmask = unmask_timerx_irq, | 169 | .unmask = unmask_timerx_irq, |
| 170 | }; | 170 | }; |
| 171 | 171 | ||
| 172 | static struct irqaction h7202_timer_irq = { | 172 | static struct irqaction h7202_timer_irq = { |
| 173 | .name = "h7202 Timer Tick", | 173 | .name = "h7202 Timer Tick", |
| 174 | .flags = SA_INTERRUPT | SA_TIMER, | 174 | .flags = SA_INTERRUPT | SA_TIMER, |
| 175 | .handler = h7202_timer_interrupt, | 175 | .handler = h7202_timer_interrupt, |
| 176 | }; | 176 | }; |
| 177 | 177 | ||
| 178 | /* | 178 | /* |
| 179 | * Setup TIMER0 as system timer | 179 | * Setup TIMER0 as system timer |
| 180 | */ | 180 | */ |
| 181 | void __init h7202_init_time(void) | 181 | void __init h7202_init_time(void) |
| 182 | { | 182 | { |
| 183 | CPU_REG (TIMER_VIRT, TM0_PERIOD) = LATCH; | 183 | CPU_REG (TIMER_VIRT, TM0_PERIOD) = LATCH; |
| 184 | CPU_REG (TIMER_VIRT, TM0_CTRL) = TM_RESET; | 184 | CPU_REG (TIMER_VIRT, TM0_CTRL) = TM_RESET; |
| 185 | CPU_REG (TIMER_VIRT, TM0_CTRL) = TM_REPEAT | TM_START; | 185 | CPU_REG (TIMER_VIRT, TM0_CTRL) = TM_REPEAT | TM_START; |
| 186 | CPU_REG (TIMER_VIRT, TIMER_TOPCTRL) = ENABLE_TM0_INTR | TIMER_ENABLE_BIT; | 186 | CPU_REG (TIMER_VIRT, TIMER_TOPCTRL) = ENABLE_TM0_INTR | TIMER_ENABLE_BIT; |
| 187 | 187 | ||
| 188 | setup_irq(IRQ_TIMER0, &h7202_timer_irq); | 188 | setup_irq(IRQ_TIMER0, &h7202_timer_irq); |
| 189 | } | 189 | } |
| 190 | 190 | ||
| 191 | struct sys_timer h7202_timer = { | 191 | struct sys_timer h7202_timer = { |
| 192 | .init = h7202_init_time, | 192 | .init = h7202_init_time, |
| 193 | .offset = h720x_gettimeoffset, | 193 | .offset = h720x_gettimeoffset, |
| 194 | }; | 194 | }; |
| 195 | 195 | ||
| 196 | void __init h7202_init_irq (void) | 196 | void __init h7202_init_irq (void) |
| 197 | { | 197 | { |
| 198 | int irq; | 198 | int irq; |
| 199 | 199 | ||
| 200 | CPU_REG (GPIO_E_VIRT, GPIO_MASK) = 0x0; | 200 | CPU_REG (GPIO_E_VIRT, GPIO_MASK) = 0x0; |
| 201 | 201 | ||
| 202 | for (irq = IRQ_TIMER1; | 202 | for (irq = IRQ_TIMER1; |
| 203 | irq < IRQ_CHAINED_TIMERX(NR_TIMERX_IRQS); irq++) { | 203 | irq < IRQ_CHAINED_TIMERX(NR_TIMERX_IRQS); irq++) { |
| 204 | mask_timerx_irq(irq); | 204 | mask_timerx_irq(irq); |
| 205 | set_irq_chip(irq, &h7202_timerx_chip); | 205 | set_irq_chip(irq, &h7202_timerx_chip); |
| 206 | set_irq_handler(irq, do_edge_IRQ); | 206 | set_irq_handler(irq, do_edge_IRQ); |
| 207 | set_irq_flags(irq, IRQF_VALID ); | 207 | set_irq_flags(irq, IRQF_VALID ); |
| 208 | } | 208 | } |
| 209 | set_irq_chained_handler(IRQ_TIMERX, h7202_timerx_demux_handler); | 209 | set_irq_chained_handler(IRQ_TIMERX, h7202_timerx_demux_handler); |
| 210 | 210 | ||
| 211 | h720x_init_irq(); | 211 | h720x_init_irq(); |
| 212 | } | 212 | } |
| 213 | 213 | ||
| 214 | void __init init_hw_h7202(void) | 214 | void __init init_hw_h7202(void) |
| 215 | { | 215 | { |
| 216 | /* Enable clocks */ | 216 | /* Enable clocks */ |
| 217 | CPU_REG (PMU_BASE, PMU_PLL_CTRL) |= PLL_2_EN | PLL_1_EN | PLL_3_MUTE; | 217 | CPU_REG (PMU_BASE, PMU_PLL_CTRL) |= PLL_2_EN | PLL_1_EN | PLL_3_MUTE; |
| 218 | 218 | ||
| 219 | CPU_REG (SERIAL0_VIRT, SERIAL_ENABLE) = SERIAL_ENABLE_EN; | 219 | CPU_REG (SERIAL0_VIRT, SERIAL_ENABLE) = SERIAL_ENABLE_EN; |
| 220 | CPU_REG (SERIAL1_VIRT, SERIAL_ENABLE) = SERIAL_ENABLE_EN; | 220 | CPU_REG (SERIAL1_VIRT, SERIAL_ENABLE) = SERIAL_ENABLE_EN; |
| 221 | #ifdef CONFIG_H7202_SERIAL23 | 221 | #ifdef CONFIG_H7202_SERIAL23 |
| 222 | CPU_REG (SERIAL2_VIRT, SERIAL_ENABLE) = SERIAL_ENABLE_EN; | 222 | CPU_REG (SERIAL2_VIRT, SERIAL_ENABLE) = SERIAL_ENABLE_EN; |
| 223 | CPU_REG (SERIAL3_VIRT, SERIAL_ENABLE) = SERIAL_ENABLE_EN; | 223 | CPU_REG (SERIAL3_VIRT, SERIAL_ENABLE) = SERIAL_ENABLE_EN; |
| 224 | CPU_IO (GPIO_AMULSEL) = AMULSEL_USIN2 | AMULSEL_USOUT2 | | 224 | CPU_IO (GPIO_AMULSEL) = AMULSEL_USIN2 | AMULSEL_USOUT2 | |
| 225 | AMULSEL_USIN3 | AMULSEL_USOUT3; | 225 | AMULSEL_USIN3 | AMULSEL_USOUT3; |
| 226 | #endif | 226 | #endif |
| 227 | (void) platform_add_devices(devices, ARRAY_SIZE(devices)); | 227 | (void) platform_add_devices(devices, ARRAY_SIZE(devices)); |
| 228 | } | 228 | } |
| 229 | 229 |
arch/arm/mach-imx/irq.c
| 1 | /* | 1 | /* |
| 2 | * linux/arch/arm/mach-imx/irq.c | 2 | * linux/arch/arm/mach-imx/irq.c |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 1999 ARM Limited | 4 | * Copyright (C) 1999 ARM Limited |
| 5 | * Copyright (C) 2002 Shane Nay (shane@minirl.com) | 5 | * Copyright (C) 2002 Shane Nay (shane@minirl.com) |
| 6 | * | 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
| 8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
| 9 | * the Free Software Foundation; either version 2 of the License, or | 9 | * the Free Software Foundation; either version 2 of the License, or |
| 10 | * (at your option) any later version. | 10 | * (at your option) any later version. |
| 11 | * | 11 | * |
| 12 | * This program is distributed in the hope that it will be useful, | 12 | * This program is distributed in the hope that it will be useful, |
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 | * GNU General Public License for more details. | 15 | * GNU General Public License for more details. |
| 16 | * | 16 | * |
| 17 | * You should have received a copy of the GNU General Public License | 17 | * You should have received a copy of the GNU General Public License |
| 18 | * along with this program; if not, write to the Free Software | 18 | * along with this program; if not, write to the Free Software |
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 20 | * | 20 | * |
| 21 | * 03/03/2004 Sascha Hauer <sascha@saschahauer.de> | 21 | * 03/03/2004 Sascha Hauer <sascha@saschahauer.de> |
| 22 | * Copied from the motorola bsp package and added gpio demux | 22 | * Copied from the motorola bsp package and added gpio demux |
| 23 | * interrupt handler | 23 | * interrupt handler |
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
| 27 | #include <linux/list.h> | 27 | #include <linux/list.h> |
| 28 | #include <linux/timer.h> | 28 | #include <linux/timer.h> |
| 29 | 29 | ||
| 30 | #include <asm/hardware.h> | 30 | #include <asm/hardware.h> |
| 31 | #include <asm/irq.h> | 31 | #include <asm/irq.h> |
| 32 | #include <asm/io.h> | 32 | #include <asm/io.h> |
| 33 | 33 | ||
| 34 | #include <asm/mach/irq.h> | 34 | #include <asm/mach/irq.h> |
| 35 | 35 | ||
| 36 | /* | 36 | /* |
| 37 | * | 37 | * |
| 38 | * We simply use the ENABLE DISABLE registers inside of the IMX | 38 | * We simply use the ENABLE DISABLE registers inside of the IMX |
| 39 | * to turn on/off specific interrupts. FIXME- We should | 39 | * to turn on/off specific interrupts. FIXME- We should |
| 40 | * also add support for the accelerated interrupt controller | 40 | * also add support for the accelerated interrupt controller |
| 41 | * by putting offets to irq jump code in the appropriate | 41 | * by putting offets to irq jump code in the appropriate |
| 42 | * places. | 42 | * places. |
| 43 | * | 43 | * |
| 44 | */ | 44 | */ |
| 45 | 45 | ||
| 46 | #define INTENNUM_OFF 0x8 | 46 | #define INTENNUM_OFF 0x8 |
| 47 | #define INTDISNUM_OFF 0xC | 47 | #define INTDISNUM_OFF 0xC |
| 48 | 48 | ||
| 49 | #define VA_AITC_BASE IO_ADDRESS(IMX_AITC_BASE) | 49 | #define VA_AITC_BASE IO_ADDRESS(IMX_AITC_BASE) |
| 50 | #define IMX_AITC_INTDISNUM (VA_AITC_BASE + INTDISNUM_OFF) | 50 | #define IMX_AITC_INTDISNUM (VA_AITC_BASE + INTDISNUM_OFF) |
| 51 | #define IMX_AITC_INTENNUM (VA_AITC_BASE + INTENNUM_OFF) | 51 | #define IMX_AITC_INTENNUM (VA_AITC_BASE + INTENNUM_OFF) |
| 52 | 52 | ||
| 53 | #if 0 | 53 | #if 0 |
| 54 | #define DEBUG_IRQ(fmt...) printk(fmt) | 54 | #define DEBUG_IRQ(fmt...) printk(fmt) |
| 55 | #else | 55 | #else |
| 56 | #define DEBUG_IRQ(fmt...) do { } while (0) | 56 | #define DEBUG_IRQ(fmt...) do { } while (0) |
| 57 | #endif | 57 | #endif |
| 58 | 58 | ||
| 59 | static void | 59 | static void |
| 60 | imx_mask_irq(unsigned int irq) | 60 | imx_mask_irq(unsigned int irq) |
| 61 | { | 61 | { |
| 62 | __raw_writel(irq, IMX_AITC_INTDISNUM); | 62 | __raw_writel(irq, IMX_AITC_INTDISNUM); |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | static void | 65 | static void |
| 66 | imx_unmask_irq(unsigned int irq) | 66 | imx_unmask_irq(unsigned int irq) |
| 67 | { | 67 | { |
| 68 | __raw_writel(irq, IMX_AITC_INTENNUM); | 68 | __raw_writel(irq, IMX_AITC_INTENNUM); |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | static int | 71 | static int |
| 72 | imx_gpio_irq_type(unsigned int _irq, unsigned int type) | 72 | imx_gpio_irq_type(unsigned int _irq, unsigned int type) |
| 73 | { | 73 | { |
| 74 | unsigned int irq_type = 0, irq, reg, bit; | 74 | unsigned int irq_type = 0, irq, reg, bit; |
| 75 | 75 | ||
| 76 | irq = _irq - IRQ_GPIOA(0); | 76 | irq = _irq - IRQ_GPIOA(0); |
| 77 | reg = irq >> 5; | 77 | reg = irq >> 5; |
| 78 | bit = 1 << (irq % 32); | 78 | bit = 1 << (irq % 32); |
| 79 | 79 | ||
| 80 | if (type == IRQT_PROBE) { | 80 | if (type == IRQT_PROBE) { |
| 81 | /* Don't mess with enabled GPIOs using preconfigured edges or | 81 | /* Don't mess with enabled GPIOs using preconfigured edges or |
| 82 | GPIOs set to alternate function during probe */ | 82 | GPIOs set to alternate function during probe */ |
| 83 | /* TODO: support probe */ | 83 | /* TODO: support probe */ |
| 84 | // if ((GPIO_IRQ_rising_edge[idx] | GPIO_IRQ_falling_edge[idx]) & | 84 | // if ((GPIO_IRQ_rising_edge[idx] | GPIO_IRQ_falling_edge[idx]) & |
| 85 | // GPIO_bit(gpio)) | 85 | // GPIO_bit(gpio)) |
| 86 | // return 0; | 86 | // return 0; |
| 87 | // if (GAFR(gpio) & (0x3 << (((gpio) & 0xf)*2))) | 87 | // if (GAFR(gpio) & (0x3 << (((gpio) & 0xf)*2))) |
| 88 | // return 0; | 88 | // return 0; |
| 89 | // type = __IRQT_RISEDGE | __IRQT_FALEDGE; | 89 | // type = __IRQT_RISEDGE | __IRQT_FALEDGE; |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | GIUS(reg) |= bit; | 92 | GIUS(reg) |= bit; |
| 93 | DDIR(reg) &= ~(bit); | 93 | DDIR(reg) &= ~(bit); |
| 94 | 94 | ||
| 95 | DEBUG_IRQ("setting type of irq %d to ", _irq); | 95 | DEBUG_IRQ("setting type of irq %d to ", _irq); |
| 96 | 96 | ||
| 97 | if (type & __IRQT_RISEDGE) { | 97 | if (type & __IRQT_RISEDGE) { |
| 98 | DEBUG_IRQ("rising edges\n"); | 98 | DEBUG_IRQ("rising edges\n"); |
| 99 | irq_type = 0x0; | 99 | irq_type = 0x0; |
| 100 | } | 100 | } |
| 101 | if (type & __IRQT_FALEDGE) { | 101 | if (type & __IRQT_FALEDGE) { |
| 102 | DEBUG_IRQ("falling edges\n"); | 102 | DEBUG_IRQ("falling edges\n"); |
| 103 | irq_type = 0x1; | 103 | irq_type = 0x1; |
| 104 | } | 104 | } |
| 105 | if (type & __IRQT_LOWLVL) { | 105 | if (type & __IRQT_LOWLVL) { |
| 106 | DEBUG_IRQ("low level\n"); | 106 | DEBUG_IRQ("low level\n"); |
| 107 | irq_type = 0x3; | 107 | irq_type = 0x3; |
| 108 | } | 108 | } |
| 109 | if (type & __IRQT_HIGHLVL) { | 109 | if (type & __IRQT_HIGHLVL) { |
| 110 | DEBUG_IRQ("high level\n"); | 110 | DEBUG_IRQ("high level\n"); |
| 111 | irq_type = 0x2; | 111 | irq_type = 0x2; |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | if (irq % 32 < 16) { | 114 | if (irq % 32 < 16) { |
| 115 | ICR1(reg) = (ICR1(reg) & ~(0x3 << ((irq % 16) * 2))) | | 115 | ICR1(reg) = (ICR1(reg) & ~(0x3 << ((irq % 16) * 2))) | |
| 116 | (irq_type << ((irq % 16) * 2)); | 116 | (irq_type << ((irq % 16) * 2)); |
| 117 | } else { | 117 | } else { |
| 118 | ICR2(reg) = (ICR2(reg) & ~(0x3 << ((irq % 16) * 2))) | | 118 | ICR2(reg) = (ICR2(reg) & ~(0x3 << ((irq % 16) * 2))) | |
| 119 | (irq_type << ((irq % 16) * 2)); | 119 | (irq_type << ((irq % 16) * 2)); |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | return 0; | 122 | return 0; |
| 123 | 123 | ||
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | static void | 126 | static void |
| 127 | imx_gpio_ack_irq(unsigned int irq) | 127 | imx_gpio_ack_irq(unsigned int irq) |
| 128 | { | 128 | { |
| 129 | DEBUG_IRQ("%s: irq %d\n", __FUNCTION__, irq); | 129 | DEBUG_IRQ("%s: irq %d\n", __FUNCTION__, irq); |
| 130 | ISR(IRQ_TO_REG(irq)) |= 1 << ((irq - IRQ_GPIOA(0)) % 32); | 130 | ISR(IRQ_TO_REG(irq)) |= 1 << ((irq - IRQ_GPIOA(0)) % 32); |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | static void | 133 | static void |
| 134 | imx_gpio_mask_irq(unsigned int irq) | 134 | imx_gpio_mask_irq(unsigned int irq) |
| 135 | { | 135 | { |
| 136 | DEBUG_IRQ("%s: irq %d\n", __FUNCTION__, irq); | 136 | DEBUG_IRQ("%s: irq %d\n", __FUNCTION__, irq); |
| 137 | IMR(IRQ_TO_REG(irq)) &= ~( 1 << ((irq - IRQ_GPIOA(0)) % 32)); | 137 | IMR(IRQ_TO_REG(irq)) &= ~( 1 << ((irq - IRQ_GPIOA(0)) % 32)); |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | static void | 140 | static void |
| 141 | imx_gpio_unmask_irq(unsigned int irq) | 141 | imx_gpio_unmask_irq(unsigned int irq) |
| 142 | { | 142 | { |
| 143 | DEBUG_IRQ("%s: irq %d\n", __FUNCTION__, irq); | 143 | DEBUG_IRQ("%s: irq %d\n", __FUNCTION__, irq); |
| 144 | IMR(IRQ_TO_REG(irq)) |= 1 << ((irq - IRQ_GPIOA(0)) % 32); | 144 | IMR(IRQ_TO_REG(irq)) |= 1 << ((irq - IRQ_GPIOA(0)) % 32); |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | static void | 147 | static void |
| 148 | imx_gpio_handler(unsigned int mask, unsigned int irq, | 148 | imx_gpio_handler(unsigned int mask, unsigned int irq, |
| 149 | struct irqdesc *desc, struct pt_regs *regs) | 149 | struct irqdesc *desc, struct pt_regs *regs) |
| 150 | { | 150 | { |
| 151 | desc = irq_desc + irq; | 151 | desc = irq_desc + irq; |
| 152 | while (mask) { | 152 | while (mask) { |
| 153 | if (mask & 1) { | 153 | if (mask & 1) { |
| 154 | DEBUG_IRQ("handling irq %d\n", irq); | 154 | DEBUG_IRQ("handling irq %d\n", irq); |
| 155 | desc->handle(irq, desc, regs); | 155 | desc_handle_irq(irq, desc, regs); |
| 156 | } | 156 | } |
| 157 | irq++; | 157 | irq++; |
| 158 | desc++; | 158 | desc++; |
| 159 | mask >>= 1; | 159 | mask >>= 1; |
| 160 | } | 160 | } |
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | static void | 163 | static void |
| 164 | imx_gpioa_demux_handler(unsigned int irq_unused, struct irqdesc *desc, | 164 | imx_gpioa_demux_handler(unsigned int irq_unused, struct irqdesc *desc, |
| 165 | struct pt_regs *regs) | 165 | struct pt_regs *regs) |
| 166 | { | 166 | { |
| 167 | unsigned int mask, irq; | 167 | unsigned int mask, irq; |
| 168 | 168 | ||
| 169 | mask = ISR(0); | 169 | mask = ISR(0); |
| 170 | irq = IRQ_GPIOA(0); | 170 | irq = IRQ_GPIOA(0); |
| 171 | imx_gpio_handler(mask, irq, desc, regs); | 171 | imx_gpio_handler(mask, irq, desc, regs); |
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | static void | 174 | static void |
| 175 | imx_gpiob_demux_handler(unsigned int irq_unused, struct irqdesc *desc, | 175 | imx_gpiob_demux_handler(unsigned int irq_unused, struct irqdesc *desc, |
| 176 | struct pt_regs *regs) | 176 | struct pt_regs *regs) |
| 177 | { | 177 | { |
| 178 | unsigned int mask, irq; | 178 | unsigned int mask, irq; |
| 179 | 179 | ||
| 180 | mask = ISR(1); | 180 | mask = ISR(1); |
| 181 | irq = IRQ_GPIOB(0); | 181 | irq = IRQ_GPIOB(0); |
| 182 | imx_gpio_handler(mask, irq, desc, regs); | 182 | imx_gpio_handler(mask, irq, desc, regs); |
| 183 | } | 183 | } |
| 184 | 184 | ||
| 185 | static void | 185 | static void |
| 186 | imx_gpioc_demux_handler(unsigned int irq_unused, struct irqdesc *desc, | 186 | imx_gpioc_demux_handler(unsigned int irq_unused, struct irqdesc *desc, |
| 187 | struct pt_regs *regs) | 187 | struct pt_regs *regs) |
| 188 | { | 188 | { |
| 189 | unsigned int mask, irq; | 189 | unsigned int mask, irq; |
| 190 | 190 | ||
| 191 | mask = ISR(2); | 191 | mask = ISR(2); |
| 192 | irq = IRQ_GPIOC(0); | 192 | irq = IRQ_GPIOC(0); |
| 193 | imx_gpio_handler(mask, irq, desc, regs); | 193 | imx_gpio_handler(mask, irq, desc, regs); |
| 194 | } | 194 | } |
| 195 | 195 | ||
| 196 | static void | 196 | static void |
| 197 | imx_gpiod_demux_handler(unsigned int irq_unused, struct irqdesc *desc, | 197 | imx_gpiod_demux_handler(unsigned int irq_unused, struct irqdesc *desc, |
| 198 | struct pt_regs *regs) | 198 | struct pt_regs *regs) |
| 199 | { | 199 | { |
| 200 | unsigned int mask, irq; | 200 | unsigned int mask, irq; |
| 201 | 201 | ||
| 202 | mask = ISR(3); | 202 | mask = ISR(3); |
| 203 | irq = IRQ_GPIOD(0); | 203 | irq = IRQ_GPIOD(0); |
| 204 | imx_gpio_handler(mask, irq, desc, regs); | 204 | imx_gpio_handler(mask, irq, desc, regs); |
| 205 | } | 205 | } |
| 206 | 206 | ||
| 207 | static struct irqchip imx_internal_chip = { | 207 | static struct irqchip imx_internal_chip = { |
| 208 | .ack = imx_mask_irq, | 208 | .ack = imx_mask_irq, |
| 209 | .mask = imx_mask_irq, | 209 | .mask = imx_mask_irq, |
| 210 | .unmask = imx_unmask_irq, | 210 | .unmask = imx_unmask_irq, |
| 211 | }; | 211 | }; |
| 212 | 212 | ||
| 213 | static struct irqchip imx_gpio_chip = { | 213 | static struct irqchip imx_gpio_chip = { |
| 214 | .ack = imx_gpio_ack_irq, | 214 | .ack = imx_gpio_ack_irq, |
| 215 | .mask = imx_gpio_mask_irq, | 215 | .mask = imx_gpio_mask_irq, |
| 216 | .unmask = imx_gpio_unmask_irq, | 216 | .unmask = imx_gpio_unmask_irq, |
| 217 | .type = imx_gpio_irq_type, | 217 | .set_type = imx_gpio_irq_type, |
| 218 | }; | 218 | }; |
| 219 | 219 | ||
| 220 | void __init | 220 | void __init |
| 221 | imx_init_irq(void) | 221 | imx_init_irq(void) |
| 222 | { | 222 | { |
| 223 | unsigned int irq; | 223 | unsigned int irq; |
| 224 | 224 | ||
| 225 | DEBUG_IRQ("Initializing imx interrupts\n"); | 225 | DEBUG_IRQ("Initializing imx interrupts\n"); |
| 226 | 226 | ||
| 227 | /* Mask all interrupts initially */ | 227 | /* Mask all interrupts initially */ |
| 228 | IMR(0) = 0; | 228 | IMR(0) = 0; |
| 229 | IMR(1) = 0; | 229 | IMR(1) = 0; |
| 230 | IMR(2) = 0; | 230 | IMR(2) = 0; |
| 231 | IMR(3) = 0; | 231 | IMR(3) = 0; |
| 232 | 232 | ||
| 233 | for (irq = 0; irq < IMX_IRQS; irq++) { | 233 | for (irq = 0; irq < IMX_IRQS; irq++) { |
| 234 | set_irq_chip(irq, &imx_internal_chip); | 234 | set_irq_chip(irq, &imx_internal_chip); |
| 235 | set_irq_handler(irq, do_level_IRQ); | 235 | set_irq_handler(irq, do_level_IRQ); |
| 236 | set_irq_flags(irq, IRQF_VALID); | 236 | set_irq_flags(irq, IRQF_VALID); |
| 237 | } | 237 | } |
| 238 | 238 | ||
| 239 | for (irq = IRQ_GPIOA(0); irq < IRQ_GPIOD(32); irq++) { | 239 | for (irq = IRQ_GPIOA(0); irq < IRQ_GPIOD(32); irq++) { |
| 240 | set_irq_chip(irq, &imx_gpio_chip); | 240 | set_irq_chip(irq, &imx_gpio_chip); |
| 241 | set_irq_handler(irq, do_edge_IRQ); | 241 | set_irq_handler(irq, do_edge_IRQ); |
| 242 | set_irq_flags(irq, IRQF_VALID); | 242 | set_irq_flags(irq, IRQF_VALID); |
| 243 | } | 243 | } |
| 244 | 244 | ||
| 245 | set_irq_chained_handler(GPIO_INT_PORTA, imx_gpioa_demux_handler); | 245 | set_irq_chained_handler(GPIO_INT_PORTA, imx_gpioa_demux_handler); |
| 246 | set_irq_chained_handler(GPIO_INT_PORTB, imx_gpiob_demux_handler); | 246 | set_irq_chained_handler(GPIO_INT_PORTB, imx_gpiob_demux_handler); |
| 247 | set_irq_chained_handler(GPIO_INT_PORTC, imx_gpioc_demux_handler); | 247 | set_irq_chained_handler(GPIO_INT_PORTC, imx_gpioc_demux_handler); |
| 248 | set_irq_chained_handler(GPIO_INT_PORTD, imx_gpiod_demux_handler); | 248 | set_irq_chained_handler(GPIO_INT_PORTD, imx_gpiod_demux_handler); |
| 249 | 249 | ||
| 250 | /* Disable all interrupts initially. */ | 250 | /* Disable all interrupts initially. */ |
| 251 | /* In IMX this is done in the bootloader. */ | 251 | /* In IMX this is done in the bootloader. */ |
| 252 | } | 252 | } |
| 253 | 253 |
arch/arm/mach-integrator/integrator_cp.c
| 1 | /* | 1 | /* |
| 2 | * linux/arch/arm/mach-integrator/integrator_cp.c | 2 | * linux/arch/arm/mach-integrator/integrator_cp.c |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2003 Deep Blue Solutions Ltd | 4 | * Copyright (C) 2003 Deep Blue Solutions Ltd |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; either version 2 of the License. | 8 | * the Free Software Foundation; either version 2 of the License. |
| 9 | */ | 9 | */ |
| 10 | #include <linux/types.h> | 10 | #include <linux/types.h> |
| 11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
| 12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
| 13 | #include <linux/list.h> | 13 | #include <linux/list.h> |
| 14 | #include <linux/device.h> | 14 | #include <linux/device.h> |
| 15 | #include <linux/dma-mapping.h> | 15 | #include <linux/dma-mapping.h> |
| 16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
| 17 | #include <linux/string.h> | 17 | #include <linux/string.h> |
| 18 | #include <linux/sysdev.h> | 18 | #include <linux/sysdev.h> |
| 19 | 19 | ||
| 20 | #include <asm/hardware.h> | 20 | #include <asm/hardware.h> |
| 21 | #include <asm/io.h> | 21 | #include <asm/io.h> |
| 22 | #include <asm/irq.h> | 22 | #include <asm/irq.h> |
| 23 | #include <asm/setup.h> | 23 | #include <asm/setup.h> |
| 24 | #include <asm/mach-types.h> | 24 | #include <asm/mach-types.h> |
| 25 | #include <asm/hardware/amba.h> | 25 | #include <asm/hardware/amba.h> |
| 26 | #include <asm/hardware/amba_kmi.h> | 26 | #include <asm/hardware/amba_kmi.h> |
| 27 | #include <asm/hardware/amba_clcd.h> | 27 | #include <asm/hardware/amba_clcd.h> |
| 28 | #include <asm/hardware/icst525.h> | 28 | #include <asm/hardware/icst525.h> |
| 29 | 29 | ||
| 30 | #include <asm/arch/cm.h> | 30 | #include <asm/arch/cm.h> |
| 31 | #include <asm/arch/lm.h> | 31 | #include <asm/arch/lm.h> |
| 32 | 32 | ||
| 33 | #include <asm/mach/arch.h> | 33 | #include <asm/mach/arch.h> |
| 34 | #include <asm/mach/flash.h> | 34 | #include <asm/mach/flash.h> |
| 35 | #include <asm/mach/irq.h> | 35 | #include <asm/mach/irq.h> |
| 36 | #include <asm/mach/mmc.h> | 36 | #include <asm/mach/mmc.h> |
| 37 | #include <asm/mach/map.h> | 37 | #include <asm/mach/map.h> |
| 38 | #include <asm/mach/time.h> | 38 | #include <asm/mach/time.h> |
| 39 | 39 | ||
| 40 | #include "common.h" | 40 | #include "common.h" |
| 41 | #include "clock.h" | 41 | #include "clock.h" |
| 42 | 42 | ||
| 43 | #define INTCP_PA_MMC_BASE 0x1c000000 | 43 | #define INTCP_PA_MMC_BASE 0x1c000000 |
| 44 | #define INTCP_PA_AACI_BASE 0x1d000000 | 44 | #define INTCP_PA_AACI_BASE 0x1d000000 |
| 45 | 45 | ||
| 46 | #define INTCP_PA_FLASH_BASE 0x24000000 | 46 | #define INTCP_PA_FLASH_BASE 0x24000000 |
| 47 | #define INTCP_FLASH_SIZE SZ_32M | 47 | #define INTCP_FLASH_SIZE SZ_32M |
| 48 | 48 | ||
| 49 | #define INTCP_PA_CLCD_BASE 0xc0000000 | 49 | #define INTCP_PA_CLCD_BASE 0xc0000000 |
| 50 | 50 | ||
| 51 | #define INTCP_VA_CIC_BASE 0xf1000040 | 51 | #define INTCP_VA_CIC_BASE 0xf1000040 |
| 52 | #define INTCP_VA_PIC_BASE 0xf1400000 | 52 | #define INTCP_VA_PIC_BASE 0xf1400000 |
| 53 | #define INTCP_VA_SIC_BASE 0xfca00000 | 53 | #define INTCP_VA_SIC_BASE 0xfca00000 |
| 54 | 54 | ||
| 55 | #define INTCP_PA_ETH_BASE 0xc8000000 | 55 | #define INTCP_PA_ETH_BASE 0xc8000000 |
| 56 | #define INTCP_ETH_SIZE 0x10 | 56 | #define INTCP_ETH_SIZE 0x10 |
| 57 | 57 | ||
| 58 | #define INTCP_VA_CTRL_BASE 0xfcb00000 | 58 | #define INTCP_VA_CTRL_BASE 0xfcb00000 |
| 59 | #define INTCP_FLASHPROG 0x04 | 59 | #define INTCP_FLASHPROG 0x04 |
| 60 | #define CINTEGRATOR_FLASHPROG_FLVPPEN (1 << 0) | 60 | #define CINTEGRATOR_FLASHPROG_FLVPPEN (1 << 0) |
| 61 | #define CINTEGRATOR_FLASHPROG_FLWREN (1 << 1) | 61 | #define CINTEGRATOR_FLASHPROG_FLWREN (1 << 1) |
| 62 | 62 | ||
| 63 | /* | 63 | /* |
| 64 | * Logical Physical | 64 | * Logical Physical |
| 65 | * f1000000 10000000 Core module registers | 65 | * f1000000 10000000 Core module registers |
| 66 | * f1100000 11000000 System controller registers | 66 | * f1100000 11000000 System controller registers |
| 67 | * f1200000 12000000 EBI registers | 67 | * f1200000 12000000 EBI registers |
| 68 | * f1300000 13000000 Counter/Timer | 68 | * f1300000 13000000 Counter/Timer |
| 69 | * f1400000 14000000 Interrupt controller | 69 | * f1400000 14000000 Interrupt controller |
| 70 | * f1600000 16000000 UART 0 | 70 | * f1600000 16000000 UART 0 |
| 71 | * f1700000 17000000 UART 1 | 71 | * f1700000 17000000 UART 1 |
| 72 | * f1a00000 1a000000 Debug LEDs | 72 | * f1a00000 1a000000 Debug LEDs |
| 73 | * f1b00000 1b000000 GPIO | 73 | * f1b00000 1b000000 GPIO |
| 74 | */ | 74 | */ |
| 75 | 75 | ||
| 76 | static struct map_desc intcp_io_desc[] __initdata = { | 76 | static struct map_desc intcp_io_desc[] __initdata = { |
| 77 | { IO_ADDRESS(INTEGRATOR_HDR_BASE), INTEGRATOR_HDR_BASE, SZ_4K, MT_DEVICE }, | 77 | { IO_ADDRESS(INTEGRATOR_HDR_BASE), INTEGRATOR_HDR_BASE, SZ_4K, MT_DEVICE }, |
| 78 | { IO_ADDRESS(INTEGRATOR_SC_BASE), INTEGRATOR_SC_BASE, SZ_4K, MT_DEVICE }, | 78 | { IO_ADDRESS(INTEGRATOR_SC_BASE), INTEGRATOR_SC_BASE, SZ_4K, MT_DEVICE }, |
| 79 | { IO_ADDRESS(INTEGRATOR_EBI_BASE), INTEGRATOR_EBI_BASE, SZ_4K, MT_DEVICE }, | 79 | { IO_ADDRESS(INTEGRATOR_EBI_BASE), INTEGRATOR_EBI_BASE, SZ_4K, MT_DEVICE }, |
| 80 | { IO_ADDRESS(INTEGRATOR_CT_BASE), INTEGRATOR_CT_BASE, SZ_4K, MT_DEVICE }, | 80 | { IO_ADDRESS(INTEGRATOR_CT_BASE), INTEGRATOR_CT_BASE, SZ_4K, MT_DEVICE }, |
| 81 | { IO_ADDRESS(INTEGRATOR_IC_BASE), INTEGRATOR_IC_BASE, SZ_4K, MT_DEVICE }, | 81 | { IO_ADDRESS(INTEGRATOR_IC_BASE), INTEGRATOR_IC_BASE, SZ_4K, MT_DEVICE }, |
| 82 | { IO_ADDRESS(INTEGRATOR_UART0_BASE), INTEGRATOR_UART0_BASE, SZ_4K, MT_DEVICE }, | 82 | { IO_ADDRESS(INTEGRATOR_UART0_BASE), INTEGRATOR_UART0_BASE, SZ_4K, MT_DEVICE }, |
| 83 | { IO_ADDRESS(INTEGRATOR_UART1_BASE), INTEGRATOR_UART1_BASE, SZ_4K, MT_DEVICE }, | 83 | { IO_ADDRESS(INTEGRATOR_UART1_BASE), INTEGRATOR_UART1_BASE, SZ_4K, MT_DEVICE }, |
| 84 | { IO_ADDRESS(INTEGRATOR_DBG_BASE), INTEGRATOR_DBG_BASE, SZ_4K, MT_DEVICE }, | 84 | { IO_ADDRESS(INTEGRATOR_DBG_BASE), INTEGRATOR_DBG_BASE, SZ_4K, MT_DEVICE }, |
| 85 | { IO_ADDRESS(INTEGRATOR_GPIO_BASE), INTEGRATOR_GPIO_BASE, SZ_4K, MT_DEVICE }, | 85 | { IO_ADDRESS(INTEGRATOR_GPIO_BASE), INTEGRATOR_GPIO_BASE, SZ_4K, MT_DEVICE }, |
| 86 | { 0xfca00000, 0xca000000, SZ_4K, MT_DEVICE }, | 86 | { 0xfca00000, 0xca000000, SZ_4K, MT_DEVICE }, |
| 87 | { 0xfcb00000, 0xcb000000, SZ_4K, MT_DEVICE }, | 87 | { 0xfcb00000, 0xcb000000, SZ_4K, MT_DEVICE }, |
| 88 | }; | 88 | }; |
| 89 | 89 | ||
| 90 | static void __init intcp_map_io(void) | 90 | static void __init intcp_map_io(void) |
| 91 | { | 91 | { |
| 92 | iotable_init(intcp_io_desc, ARRAY_SIZE(intcp_io_desc)); | 92 | iotable_init(intcp_io_desc, ARRAY_SIZE(intcp_io_desc)); |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | #define cic_writel __raw_writel | 95 | #define cic_writel __raw_writel |
| 96 | #define cic_readl __raw_readl | 96 | #define cic_readl __raw_readl |
| 97 | #define pic_writel __raw_writel | 97 | #define pic_writel __raw_writel |
| 98 | #define pic_readl __raw_readl | 98 | #define pic_readl __raw_readl |
| 99 | #define sic_writel __raw_writel | 99 | #define sic_writel __raw_writel |
| 100 | #define sic_readl __raw_readl | 100 | #define sic_readl __raw_readl |
| 101 | 101 | ||
| 102 | static void cic_mask_irq(unsigned int irq) | 102 | static void cic_mask_irq(unsigned int irq) |
| 103 | { | 103 | { |
| 104 | irq -= IRQ_CIC_START; | 104 | irq -= IRQ_CIC_START; |
| 105 | cic_writel(1 << irq, INTCP_VA_CIC_BASE + IRQ_ENABLE_CLEAR); | 105 | cic_writel(1 << irq, INTCP_VA_CIC_BASE + IRQ_ENABLE_CLEAR); |
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | static void cic_unmask_irq(unsigned int irq) | 108 | static void cic_unmask_irq(unsigned int irq) |
| 109 | { | 109 | { |
| 110 | irq -= IRQ_CIC_START; | 110 | irq -= IRQ_CIC_START; |
| 111 | cic_writel(1 << irq, INTCP_VA_CIC_BASE + IRQ_ENABLE_SET); | 111 | cic_writel(1 << irq, INTCP_VA_CIC_BASE + IRQ_ENABLE_SET); |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | static struct irqchip cic_chip = { | 114 | static struct irqchip cic_chip = { |
| 115 | .ack = cic_mask_irq, | 115 | .ack = cic_mask_irq, |
| 116 | .mask = cic_mask_irq, | 116 | .mask = cic_mask_irq, |
| 117 | .unmask = cic_unmask_irq, | 117 | .unmask = cic_unmask_irq, |
| 118 | }; | 118 | }; |
| 119 | 119 | ||
| 120 | static void pic_mask_irq(unsigned int irq) | 120 | static void pic_mask_irq(unsigned int irq) |
| 121 | { | 121 | { |
| 122 | irq -= IRQ_PIC_START; | 122 | irq -= IRQ_PIC_START; |
| 123 | pic_writel(1 << irq, INTCP_VA_PIC_BASE + IRQ_ENABLE_CLEAR); | 123 | pic_writel(1 << irq, INTCP_VA_PIC_BASE + IRQ_ENABLE_CLEAR); |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | static void pic_unmask_irq(unsigned int irq) | 126 | static void pic_unmask_irq(unsigned int irq) |
| 127 | { | 127 | { |
| 128 | irq -= IRQ_PIC_START; | 128 | irq -= IRQ_PIC_START; |
| 129 | pic_writel(1 << irq, INTCP_VA_PIC_BASE + IRQ_ENABLE_SET); | 129 | pic_writel(1 << irq, INTCP_VA_PIC_BASE + IRQ_ENABLE_SET); |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | static struct irqchip pic_chip = { | 132 | static struct irqchip pic_chip = { |
| 133 | .ack = pic_mask_irq, | 133 | .ack = pic_mask_irq, |
| 134 | .mask = pic_mask_irq, | 134 | .mask = pic_mask_irq, |
| 135 | .unmask = pic_unmask_irq, | 135 | .unmask = pic_unmask_irq, |
| 136 | }; | 136 | }; |
| 137 | 137 | ||
| 138 | static void sic_mask_irq(unsigned int irq) | 138 | static void sic_mask_irq(unsigned int irq) |
| 139 | { | 139 | { |
| 140 | irq -= IRQ_SIC_START; | 140 | irq -= IRQ_SIC_START; |
| 141 | sic_writel(1 << irq, INTCP_VA_SIC_BASE + IRQ_ENABLE_CLEAR); | 141 | sic_writel(1 << irq, INTCP_VA_SIC_BASE + IRQ_ENABLE_CLEAR); |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | static void sic_unmask_irq(unsigned int irq) | 144 | static void sic_unmask_irq(unsigned int irq) |
| 145 | { | 145 | { |
| 146 | irq -= IRQ_SIC_START; | 146 | irq -= IRQ_SIC_START; |
| 147 | sic_writel(1 << irq, INTCP_VA_SIC_BASE + IRQ_ENABLE_SET); | 147 | sic_writel(1 << irq, INTCP_VA_SIC_BASE + IRQ_ENABLE_SET); |
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | static struct irqchip sic_chip = { | 150 | static struct irqchip sic_chip = { |
| 151 | .ack = sic_mask_irq, | 151 | .ack = sic_mask_irq, |
| 152 | .mask = sic_mask_irq, | 152 | .mask = sic_mask_irq, |
| 153 | .unmask = sic_unmask_irq, | 153 | .unmask = sic_unmask_irq, |
| 154 | }; | 154 | }; |
| 155 | 155 | ||
| 156 | static void | 156 | static void |
| 157 | sic_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) | 157 | sic_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) |
| 158 | { | 158 | { |
| 159 | unsigned long status = sic_readl(INTCP_VA_SIC_BASE + IRQ_STATUS); | 159 | unsigned long status = sic_readl(INTCP_VA_SIC_BASE + IRQ_STATUS); |
| 160 | 160 | ||
| 161 | if (status == 0) { | 161 | if (status == 0) { |
| 162 | do_bad_IRQ(irq, desc, regs); | 162 | do_bad_IRQ(irq, desc, regs); |
| 163 | return; | 163 | return; |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | do { | 166 | do { |
| 167 | irq = ffs(status) - 1; | 167 | irq = ffs(status) - 1; |
| 168 | status &= ~(1 << irq); | 168 | status &= ~(1 << irq); |
| 169 | 169 | ||
| 170 | irq += IRQ_SIC_START; | 170 | irq += IRQ_SIC_START; |
| 171 | 171 | ||
| 172 | desc = irq_desc + irq; | 172 | desc = irq_desc + irq; |
| 173 | desc->handle(irq, desc, regs); | 173 | desc_handle_irq(irq, desc, regs); |
| 174 | } while (status); | 174 | } while (status); |
| 175 | } | 175 | } |
| 176 | 176 | ||
| 177 | static void __init intcp_init_irq(void) | 177 | static void __init intcp_init_irq(void) |
| 178 | { | 178 | { |
| 179 | unsigned int i; | 179 | unsigned int i; |
| 180 | 180 | ||
| 181 | /* | 181 | /* |
| 182 | * Disable all interrupt sources | 182 | * Disable all interrupt sources |
| 183 | */ | 183 | */ |
| 184 | pic_writel(0xffffffff, INTCP_VA_PIC_BASE + IRQ_ENABLE_CLEAR); | 184 | pic_writel(0xffffffff, INTCP_VA_PIC_BASE + IRQ_ENABLE_CLEAR); |
| 185 | pic_writel(0xffffffff, INTCP_VA_PIC_BASE + FIQ_ENABLE_CLEAR); | 185 | pic_writel(0xffffffff, INTCP_VA_PIC_BASE + FIQ_ENABLE_CLEAR); |
| 186 | 186 | ||
| 187 | for (i = IRQ_PIC_START; i <= IRQ_PIC_END; i++) { | 187 | for (i = IRQ_PIC_START; i <= IRQ_PIC_END; i++) { |
| 188 | if (i == 11) | 188 | if (i == 11) |
| 189 | i = 22; | 189 | i = 22; |
| 190 | if (i == IRQ_CP_CPPLDINT) | 190 | if (i == IRQ_CP_CPPLDINT) |
| 191 | i++; | 191 | i++; |
| 192 | if (i == 29) | 192 | if (i == 29) |
| 193 | break; | 193 | break; |
| 194 | set_irq_chip(i, &pic_chip); | 194 | set_irq_chip(i, &pic_chip); |
| 195 | set_irq_handler(i, do_level_IRQ); | 195 | set_irq_handler(i, do_level_IRQ); |
| 196 | set_irq_flags(i, IRQF_VALID | IRQF_PROBE); | 196 | set_irq_flags(i, IRQF_VALID | IRQF_PROBE); |
| 197 | } | 197 | } |
| 198 | 198 | ||
| 199 | cic_writel(0xffffffff, INTCP_VA_CIC_BASE + IRQ_ENABLE_CLEAR); | 199 | cic_writel(0xffffffff, INTCP_VA_CIC_BASE + IRQ_ENABLE_CLEAR); |
| 200 | cic_writel(0xffffffff, INTCP_VA_CIC_BASE + FIQ_ENABLE_CLEAR); | 200 | cic_writel(0xffffffff, INTCP_VA_CIC_BASE + FIQ_ENABLE_CLEAR); |
| 201 | 201 | ||
| 202 | for (i = IRQ_CIC_START; i <= IRQ_CIC_END; i++) { | 202 | for (i = IRQ_CIC_START; i <= IRQ_CIC_END; i++) { |
| 203 | set_irq_chip(i, &cic_chip); | 203 | set_irq_chip(i, &cic_chip); |
| 204 | set_irq_handler(i, do_level_IRQ); | 204 | set_irq_handler(i, do_level_IRQ); |
| 205 | set_irq_flags(i, IRQF_VALID); | 205 | set_irq_flags(i, IRQF_VALID); |
| 206 | } | 206 | } |
| 207 | 207 | ||
| 208 | sic_writel(0x00000fff, INTCP_VA_SIC_BASE + IRQ_ENABLE_CLEAR); | 208 | sic_writel(0x00000fff, INTCP_VA_SIC_BASE + IRQ_ENABLE_CLEAR); |
| 209 | sic_writel(0x00000fff, INTCP_VA_SIC_BASE + FIQ_ENABLE_CLEAR); | 209 | sic_writel(0x00000fff, INTCP_VA_SIC_BASE + FIQ_ENABLE_CLEAR); |
| 210 | 210 | ||
| 211 | for (i = IRQ_SIC_START; i <= IRQ_SIC_END; i++) { | 211 | for (i = IRQ_SIC_START; i <= IRQ_SIC_END; i++) { |
| 212 | set_irq_chip(i, &sic_chip); | 212 | set_irq_chip(i, &sic_chip); |
| 213 | set_irq_handler(i, do_level_IRQ); | 213 | set_irq_handler(i, do_level_IRQ); |
| 214 | set_irq_flags(i, IRQF_VALID | IRQF_PROBE); | 214 | set_irq_flags(i, IRQF_VALID | IRQF_PROBE); |
| 215 | } | 215 | } |
| 216 | 216 | ||
| 217 | set_irq_handler(IRQ_CP_CPPLDINT, sic_handle_irq); | 217 | set_irq_handler(IRQ_CP_CPPLDINT, sic_handle_irq); |
| 218 | pic_unmask_irq(IRQ_CP_CPPLDINT); | 218 | pic_unmask_irq(IRQ_CP_CPPLDINT); |
| 219 | } | 219 | } |
| 220 | 220 | ||
| 221 | /* | 221 | /* |
| 222 | * Clock handling | 222 | * Clock handling |
| 223 | */ | 223 | */ |
| 224 | #define CM_LOCK (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET) | 224 | #define CM_LOCK (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET) |
| 225 | #define CM_AUXOSC (IO_ADDRESS(INTEGRATOR_HDR_BASE)+0x1c) | 225 | #define CM_AUXOSC (IO_ADDRESS(INTEGRATOR_HDR_BASE)+0x1c) |
| 226 | 226 | ||
| 227 | static const struct icst525_params cp_auxvco_params = { | 227 | static const struct icst525_params cp_auxvco_params = { |
| 228 | .ref = 24000, | 228 | .ref = 24000, |
| 229 | .vco_max = 320000, | 229 | .vco_max = 320000, |
| 230 | .vd_min = 8, | 230 | .vd_min = 8, |
| 231 | .vd_max = 263, | 231 | .vd_max = 263, |
| 232 | .rd_min = 3, | 232 | .rd_min = 3, |
| 233 | .rd_max = 65, | 233 | .rd_max = 65, |
| 234 | }; | 234 | }; |
| 235 | 235 | ||
| 236 | static void cp_auxvco_set(struct clk *clk, struct icst525_vco vco) | 236 | static void cp_auxvco_set(struct clk *clk, struct icst525_vco vco) |
| 237 | { | 237 | { |
| 238 | u32 val; | 238 | u32 val; |
| 239 | 239 | ||
| 240 | val = readl(CM_AUXOSC) & ~0x7ffff; | 240 | val = readl(CM_AUXOSC) & ~0x7ffff; |
| 241 | val |= vco.v | (vco.r << 9) | (vco.s << 16); | 241 | val |= vco.v | (vco.r << 9) | (vco.s << 16); |
| 242 | 242 | ||
| 243 | writel(0xa05f, CM_LOCK); | 243 | writel(0xa05f, CM_LOCK); |
| 244 | writel(val, CM_AUXOSC); | 244 | writel(val, CM_AUXOSC); |
| 245 | writel(0, CM_LOCK); | 245 | writel(0, CM_LOCK); |
| 246 | } | 246 | } |
| 247 | 247 | ||
| 248 | static struct clk cp_clcd_clk = { | 248 | static struct clk cp_clcd_clk = { |
| 249 | .name = "CLCDCLK", | 249 | .name = "CLCDCLK", |
| 250 | .params = &cp_auxvco_params, | 250 | .params = &cp_auxvco_params, |
| 251 | .setvco = cp_auxvco_set, | 251 | .setvco = cp_auxvco_set, |
| 252 | }; | 252 | }; |
| 253 | 253 | ||
| 254 | static struct clk cp_mmci_clk = { | 254 | static struct clk cp_mmci_clk = { |
| 255 | .name = "MCLK", | 255 | .name = "MCLK", |
| 256 | .rate = 14745600, | 256 | .rate = 14745600, |
| 257 | }; | 257 | }; |
| 258 | 258 | ||
| 259 | /* | 259 | /* |
| 260 | * Flash handling. | 260 | * Flash handling. |
| 261 | */ | 261 | */ |
| 262 | static int intcp_flash_init(void) | 262 | static int intcp_flash_init(void) |
| 263 | { | 263 | { |
| 264 | u32 val; | 264 | u32 val; |
| 265 | 265 | ||
| 266 | val = readl(INTCP_VA_CTRL_BASE + INTCP_FLASHPROG); | 266 | val = readl(INTCP_VA_CTRL_BASE + INTCP_FLASHPROG); |
| 267 | val |= CINTEGRATOR_FLASHPROG_FLWREN; | 267 | val |= CINTEGRATOR_FLASHPROG_FLWREN; |
| 268 | writel(val, INTCP_VA_CTRL_BASE + INTCP_FLASHPROG); | 268 | writel(val, INTCP_VA_CTRL_BASE + INTCP_FLASHPROG); |
| 269 | 269 | ||
| 270 | return 0; | 270 | return 0; |
| 271 | } | 271 | } |
| 272 | 272 | ||
| 273 | static void intcp_flash_exit(void) | 273 | static void intcp_flash_exit(void) |
| 274 | { | 274 | { |
| 275 | u32 val; | 275 | u32 val; |
| 276 | 276 | ||
| 277 | val = readl(INTCP_VA_CTRL_BASE + INTCP_FLASHPROG); | 277 | val = readl(INTCP_VA_CTRL_BASE + INTCP_FLASHPROG); |
| 278 | val &= ~(CINTEGRATOR_FLASHPROG_FLVPPEN|CINTEGRATOR_FLASHPROG_FLWREN); | 278 | val &= ~(CINTEGRATOR_FLASHPROG_FLVPPEN|CINTEGRATOR_FLASHPROG_FLWREN); |
| 279 | writel(val, INTCP_VA_CTRL_BASE + INTCP_FLASHPROG); | 279 | writel(val, INTCP_VA_CTRL_BASE + INTCP_FLASHPROG); |
| 280 | } | 280 | } |
| 281 | 281 | ||
| 282 | static void intcp_flash_set_vpp(int on) | 282 | static void intcp_flash_set_vpp(int on) |
| 283 | { | 283 | { |
| 284 | u32 val; | 284 | u32 val; |
| 285 | 285 | ||
| 286 | val = readl(INTCP_VA_CTRL_BASE + INTCP_FLASHPROG); | 286 | val = readl(INTCP_VA_CTRL_BASE + INTCP_FLASHPROG); |
| 287 | if (on) | 287 | if (on) |
| 288 | val |= CINTEGRATOR_FLASHPROG_FLVPPEN; | 288 | val |= CINTEGRATOR_FLASHPROG_FLVPPEN; |
| 289 | else | 289 | else |
| 290 | val &= ~CINTEGRATOR_FLASHPROG_FLVPPEN; | 290 | val &= ~CINTEGRATOR_FLASHPROG_FLVPPEN; |
| 291 | writel(val, INTCP_VA_CTRL_BASE + INTCP_FLASHPROG); | 291 | writel(val, INTCP_VA_CTRL_BASE + INTCP_FLASHPROG); |
| 292 | } | 292 | } |
| 293 | 293 | ||
| 294 | static struct flash_platform_data intcp_flash_data = { | 294 | static struct flash_platform_data intcp_flash_data = { |
| 295 | .map_name = "cfi_probe", | 295 | .map_name = "cfi_probe", |
| 296 | .width = 4, | 296 | .width = 4, |
| 297 | .init = intcp_flash_init, | 297 | .init = intcp_flash_init, |
| 298 | .exit = intcp_flash_exit, | 298 | .exit = intcp_flash_exit, |
| 299 | .set_vpp = intcp_flash_set_vpp, | 299 | .set_vpp = intcp_flash_set_vpp, |
| 300 | }; | 300 | }; |
| 301 | 301 | ||
| 302 | static struct resource intcp_flash_resource = { | 302 | static struct resource intcp_flash_resource = { |
| 303 | .start = INTCP_PA_FLASH_BASE, | 303 | .start = INTCP_PA_FLASH_BASE, |
| 304 | .end = INTCP_PA_FLASH_BASE + INTCP_FLASH_SIZE - 1, | 304 | .end = INTCP_PA_FLASH_BASE + INTCP_FLASH_SIZE - 1, |
| 305 | .flags = IORESOURCE_MEM, | 305 | .flags = IORESOURCE_MEM, |
| 306 | }; | 306 | }; |
| 307 | 307 | ||
| 308 | static struct platform_device intcp_flash_device = { | 308 | static struct platform_device intcp_flash_device = { |
| 309 | .name = "armflash", | 309 | .name = "armflash", |
| 310 | .id = 0, | 310 | .id = 0, |
| 311 | .dev = { | 311 | .dev = { |
| 312 | .platform_data = &intcp_flash_data, | 312 | .platform_data = &intcp_flash_data, |
| 313 | }, | 313 | }, |
| 314 | .num_resources = 1, | 314 | .num_resources = 1, |
| 315 | .resource = &intcp_flash_resource, | 315 | .resource = &intcp_flash_resource, |
| 316 | }; | 316 | }; |
| 317 | 317 | ||
| 318 | static struct resource smc91x_resources[] = { | 318 | static struct resource smc91x_resources[] = { |
| 319 | [0] = { | 319 | [0] = { |
| 320 | .start = INTCP_PA_ETH_BASE, | 320 | .start = INTCP_PA_ETH_BASE, |
| 321 | .end = INTCP_PA_ETH_BASE + INTCP_ETH_SIZE - 1, | 321 | .end = INTCP_PA_ETH_BASE + INTCP_ETH_SIZE - 1, |
| 322 | .flags = IORESOURCE_MEM, | 322 | .flags = IORESOURCE_MEM, |
| 323 | }, | 323 | }, |
| 324 | [1] = { | 324 | [1] = { |
| 325 | .start = IRQ_CP_ETHINT, | 325 | .start = IRQ_CP_ETHINT, |
| 326 | .end = IRQ_CP_ETHINT, | 326 | .end = IRQ_CP_ETHINT, |
| 327 | .flags = IORESOURCE_IRQ, | 327 | .flags = IORESOURCE_IRQ, |
| 328 | }, | 328 | }, |
| 329 | }; | 329 | }; |
| 330 | 330 | ||
| 331 | static struct platform_device smc91x_device = { | 331 | static struct platform_device smc91x_device = { |
| 332 | .name = "smc91x", | 332 | .name = "smc91x", |
| 333 | .id = 0, | 333 | .id = 0, |
| 334 | .num_resources = ARRAY_SIZE(smc91x_resources), | 334 | .num_resources = ARRAY_SIZE(smc91x_resources), |
| 335 | .resource = smc91x_resources, | 335 | .resource = smc91x_resources, |
| 336 | }; | 336 | }; |
| 337 | 337 | ||
| 338 | static struct platform_device *intcp_devs[] __initdata = { | 338 | static struct platform_device *intcp_devs[] __initdata = { |
| 339 | &intcp_flash_device, | 339 | &intcp_flash_device, |
| 340 | &smc91x_device, | 340 | &smc91x_device, |
| 341 | }; | 341 | }; |
| 342 | 342 | ||
| 343 | /* | 343 | /* |
| 344 | * It seems that the card insertion interrupt remains active after | 344 | * It seems that the card insertion interrupt remains active after |
| 345 | * we've acknowledged it. We therefore ignore the interrupt, and | 345 | * we've acknowledged it. We therefore ignore the interrupt, and |
| 346 | * rely on reading it from the SIC. This also means that we must | 346 | * rely on reading it from the SIC. This also means that we must |
| 347 | * clear the latched interrupt. | 347 | * clear the latched interrupt. |
| 348 | */ | 348 | */ |
| 349 | static unsigned int mmc_status(struct device *dev) | 349 | static unsigned int mmc_status(struct device *dev) |
| 350 | { | 350 | { |
| 351 | unsigned int status = readl(0xfca00004); | 351 | unsigned int status = readl(0xfca00004); |
| 352 | writel(8, 0xfcb00008); | 352 | writel(8, 0xfcb00008); |
| 353 | 353 | ||
| 354 | return status & 8; | 354 | return status & 8; |
| 355 | } | 355 | } |
| 356 | 356 | ||
| 357 | static struct mmc_platform_data mmc_data = { | 357 | static struct mmc_platform_data mmc_data = { |
| 358 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, | 358 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, |
| 359 | .status = mmc_status, | 359 | .status = mmc_status, |
| 360 | }; | 360 | }; |
| 361 | 361 | ||
| 362 | static struct amba_device mmc_device = { | 362 | static struct amba_device mmc_device = { |
| 363 | .dev = { | 363 | .dev = { |
| 364 | .bus_id = "mb:1c", | 364 | .bus_id = "mb:1c", |
| 365 | .platform_data = &mmc_data, | 365 | .platform_data = &mmc_data, |
| 366 | }, | 366 | }, |
| 367 | .res = { | 367 | .res = { |
| 368 | .start = INTCP_PA_MMC_BASE, | 368 | .start = INTCP_PA_MMC_BASE, |
| 369 | .end = INTCP_PA_MMC_BASE + SZ_4K - 1, | 369 | .end = INTCP_PA_MMC_BASE + SZ_4K - 1, |
| 370 | .flags = IORESOURCE_MEM, | 370 | .flags = IORESOURCE_MEM, |
| 371 | }, | 371 | }, |
| 372 | .irq = { IRQ_CP_MMCIINT0, IRQ_CP_MMCIINT1 }, | 372 | .irq = { IRQ_CP_MMCIINT0, IRQ_CP_MMCIINT1 }, |
| 373 | .periphid = 0, | 373 | .periphid = 0, |
| 374 | }; | 374 | }; |
| 375 | 375 | ||
| 376 | static struct amba_device aaci_device = { | 376 | static struct amba_device aaci_device = { |
| 377 | .dev = { | 377 | .dev = { |
| 378 | .bus_id = "mb:1d", | 378 | .bus_id = "mb:1d", |
| 379 | }, | 379 | }, |
| 380 | .res = { | 380 | .res = { |
| 381 | .start = INTCP_PA_AACI_BASE, | 381 | .start = INTCP_PA_AACI_BASE, |
| 382 | .end = INTCP_PA_AACI_BASE + SZ_4K - 1, | 382 | .end = INTCP_PA_AACI_BASE + SZ_4K - 1, |
| 383 | .flags = IORESOURCE_MEM, | 383 | .flags = IORESOURCE_MEM, |
| 384 | }, | 384 | }, |
| 385 | .irq = { IRQ_CP_AACIINT, NO_IRQ }, | 385 | .irq = { IRQ_CP_AACIINT, NO_IRQ }, |
| 386 | .periphid = 0, | 386 | .periphid = 0, |
| 387 | }; | 387 | }; |
| 388 | 388 | ||
| 389 | 389 | ||
| 390 | /* | 390 | /* |
| 391 | * CLCD support | 391 | * CLCD support |
| 392 | */ | 392 | */ |
| 393 | static struct clcd_panel vga = { | 393 | static struct clcd_panel vga = { |
| 394 | .mode = { | 394 | .mode = { |
| 395 | .name = "VGA", | 395 | .name = "VGA", |
| 396 | .refresh = 60, | 396 | .refresh = 60, |
| 397 | .xres = 640, | 397 | .xres = 640, |
| 398 | .yres = 480, | 398 | .yres = 480, |
| 399 | .pixclock = 39721, | 399 | .pixclock = 39721, |
| 400 | .left_margin = 40, | 400 | .left_margin = 40, |
| 401 | .right_margin = 24, | 401 | .right_margin = 24, |
| 402 | .upper_margin = 32, | 402 | .upper_margin = 32, |
| 403 | .lower_margin = 11, | 403 | .lower_margin = 11, |
| 404 | .hsync_len = 96, | 404 | .hsync_len = 96, |
| 405 | .vsync_len = 2, | 405 | .vsync_len = 2, |
| 406 | .sync = 0, | 406 | .sync = 0, |
| 407 | .vmode = FB_VMODE_NONINTERLACED, | 407 | .vmode = FB_VMODE_NONINTERLACED, |
| 408 | }, | 408 | }, |
| 409 | .width = -1, | 409 | .width = -1, |
| 410 | .height = -1, | 410 | .height = -1, |
| 411 | .tim2 = TIM2_BCD | TIM2_IPC, | 411 | .tim2 = TIM2_BCD | TIM2_IPC, |
| 412 | .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), | 412 | .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), |
| 413 | .bpp = 16, | 413 | .bpp = 16, |
| 414 | .grayscale = 0, | 414 | .grayscale = 0, |
| 415 | }; | 415 | }; |
| 416 | 416 | ||
| 417 | /* | 417 | /* |
| 418 | * Ensure VGA is selected. | 418 | * Ensure VGA is selected. |
| 419 | */ | 419 | */ |
| 420 | static void cp_clcd_enable(struct clcd_fb *fb) | 420 | static void cp_clcd_enable(struct clcd_fb *fb) |
| 421 | { | 421 | { |
| 422 | u32 val; | 422 | u32 val; |
| 423 | 423 | ||
| 424 | if (fb->fb.var.bits_per_pixel <= 8) | 424 | if (fb->fb.var.bits_per_pixel <= 8) |
| 425 | val = CM_CTRL_LCDMUXSEL_VGA_8421BPP; | 425 | val = CM_CTRL_LCDMUXSEL_VGA_8421BPP; |
| 426 | else if (fb->fb.var.bits_per_pixel <= 16) | 426 | else if (fb->fb.var.bits_per_pixel <= 16) |
| 427 | val = CM_CTRL_LCDMUXSEL_VGA_16BPP; | 427 | val = CM_CTRL_LCDMUXSEL_VGA_16BPP; |
| 428 | else | 428 | else |
| 429 | val = 0; /* no idea for this, don't trust the docs */ | 429 | val = 0; /* no idea for this, don't trust the docs */ |
| 430 | 430 | ||
| 431 | cm_control(CM_CTRL_LCDMUXSEL_MASK| | 431 | cm_control(CM_CTRL_LCDMUXSEL_MASK| |
| 432 | CM_CTRL_LCDEN0| | 432 | CM_CTRL_LCDEN0| |
| 433 | CM_CTRL_LCDEN1| | 433 | CM_CTRL_LCDEN1| |
| 434 | CM_CTRL_STATIC1| | 434 | CM_CTRL_STATIC1| |
| 435 | CM_CTRL_STATIC2| | 435 | CM_CTRL_STATIC2| |
| 436 | CM_CTRL_STATIC| | 436 | CM_CTRL_STATIC| |
| 437 | CM_CTRL_n24BITEN, val); | 437 | CM_CTRL_n24BITEN, val); |
| 438 | } | 438 | } |
| 439 | 439 | ||
| 440 | static unsigned long framesize = SZ_1M; | 440 | static unsigned long framesize = SZ_1M; |
| 441 | 441 | ||
| 442 | static int cp_clcd_setup(struct clcd_fb *fb) | 442 | static int cp_clcd_setup(struct clcd_fb *fb) |
| 443 | { | 443 | { |
| 444 | dma_addr_t dma; | 444 | dma_addr_t dma; |
| 445 | 445 | ||
| 446 | fb->panel = &vga; | 446 | fb->panel = &vga; |
| 447 | 447 | ||
| 448 | fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize, | 448 | fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize, |
| 449 | &dma, GFP_KERNEL); | 449 | &dma, GFP_KERNEL); |
| 450 | if (!fb->fb.screen_base) { | 450 | if (!fb->fb.screen_base) { |
| 451 | printk(KERN_ERR "CLCD: unable to map framebuffer\n"); | 451 | printk(KERN_ERR "CLCD: unable to map framebuffer\n"); |
| 452 | return -ENOMEM; | 452 | return -ENOMEM; |
| 453 | } | 453 | } |
| 454 | 454 | ||
| 455 | fb->fb.fix.smem_start = dma; | 455 | fb->fb.fix.smem_start = dma; |
| 456 | fb->fb.fix.smem_len = framesize; | 456 | fb->fb.fix.smem_len = framesize; |
| 457 | 457 | ||
| 458 | return 0; | 458 | return 0; |
| 459 | } | 459 | } |
| 460 | 460 | ||
| 461 | static int cp_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma) | 461 | static int cp_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma) |
| 462 | { | 462 | { |
| 463 | return dma_mmap_writecombine(&fb->dev->dev, vma, | 463 | return dma_mmap_writecombine(&fb->dev->dev, vma, |
| 464 | fb->fb.screen_base, | 464 | fb->fb.screen_base, |
| 465 | fb->fb.fix.smem_start, | 465 | fb->fb.fix.smem_start, |
| 466 | fb->fb.fix.smem_len); | 466 | fb->fb.fix.smem_len); |
| 467 | } | 467 | } |
| 468 | 468 | ||
| 469 | static void cp_clcd_remove(struct clcd_fb *fb) | 469 | static void cp_clcd_remove(struct clcd_fb *fb) |
| 470 | { | 470 | { |
| 471 | dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len, | 471 | dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len, |
| 472 | fb->fb.screen_base, fb->fb.fix.smem_start); | 472 | fb->fb.screen_base, fb->fb.fix.smem_start); |
| 473 | } | 473 | } |
| 474 | 474 | ||
| 475 | static struct clcd_board clcd_data = { | 475 | static struct clcd_board clcd_data = { |
| 476 | .name = "Integrator/CP", | 476 | .name = "Integrator/CP", |
| 477 | .check = clcdfb_check, | 477 | .check = clcdfb_check, |
| 478 | .decode = clcdfb_decode, | 478 | .decode = clcdfb_decode, |
| 479 | .enable = cp_clcd_enable, | 479 | .enable = cp_clcd_enable, |
| 480 | .setup = cp_clcd_setup, | 480 | .setup = cp_clcd_setup, |
| 481 | .mmap = cp_clcd_mmap, | 481 | .mmap = cp_clcd_mmap, |
| 482 | .remove = cp_clcd_remove, | 482 | .remove = cp_clcd_remove, |
| 483 | }; | 483 | }; |
| 484 | 484 | ||
| 485 | static struct amba_device clcd_device = { | 485 | static struct amba_device clcd_device = { |
| 486 | .dev = { | 486 | .dev = { |
| 487 | .bus_id = "mb:c0", | 487 | .bus_id = "mb:c0", |
| 488 | .coherent_dma_mask = ~0, | 488 | .coherent_dma_mask = ~0, |
| 489 | .platform_data = &clcd_data, | 489 | .platform_data = &clcd_data, |
| 490 | }, | 490 | }, |
| 491 | .res = { | 491 | .res = { |
| 492 | .start = INTCP_PA_CLCD_BASE, | 492 | .start = INTCP_PA_CLCD_BASE, |
| 493 | .end = INTCP_PA_CLCD_BASE + SZ_4K - 1, | 493 | .end = INTCP_PA_CLCD_BASE + SZ_4K - 1, |
| 494 | .flags = IORESOURCE_MEM, | 494 | .flags = IORESOURCE_MEM, |
| 495 | }, | 495 | }, |
| 496 | .dma_mask = ~0, | 496 | .dma_mask = ~0, |
| 497 | .irq = { IRQ_CP_CLCDCINT, NO_IRQ }, | 497 | .irq = { IRQ_CP_CLCDCINT, NO_IRQ }, |
| 498 | .periphid = 0, | 498 | .periphid = 0, |
| 499 | }; | 499 | }; |
| 500 | 500 | ||
| 501 | static struct amba_device *amba_devs[] __initdata = { | 501 | static struct amba_device *amba_devs[] __initdata = { |
| 502 | &mmc_device, | 502 | &mmc_device, |
| 503 | &aaci_device, | 503 | &aaci_device, |
| 504 | &clcd_device, | 504 | &clcd_device, |
| 505 | }; | 505 | }; |
| 506 | 506 | ||
| 507 | static void __init intcp_init(void) | 507 | static void __init intcp_init(void) |
| 508 | { | 508 | { |
| 509 | int i; | 509 | int i; |
| 510 | 510 | ||
| 511 | clk_register(&cp_clcd_clk); | 511 | clk_register(&cp_clcd_clk); |
| 512 | clk_register(&cp_mmci_clk); | 512 | clk_register(&cp_mmci_clk); |
| 513 | 513 | ||
| 514 | platform_add_devices(intcp_devs, ARRAY_SIZE(intcp_devs)); | 514 | platform_add_devices(intcp_devs, ARRAY_SIZE(intcp_devs)); |
| 515 | 515 | ||
| 516 | for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { | 516 | for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { |
| 517 | struct amba_device *d = amba_devs[i]; | 517 | struct amba_device *d = amba_devs[i]; |
| 518 | amba_device_register(d, &iomem_resource); | 518 | amba_device_register(d, &iomem_resource); |
| 519 | } | 519 | } |
| 520 | } | 520 | } |
| 521 | 521 | ||
| 522 | #define TIMER_CTRL_IE (1 << 5) /* Interrupt Enable */ | 522 | #define TIMER_CTRL_IE (1 << 5) /* Interrupt Enable */ |
| 523 | 523 | ||
| 524 | static void __init intcp_timer_init(void) | 524 | static void __init intcp_timer_init(void) |
| 525 | { | 525 | { |
| 526 | integrator_time_init(1000000 / HZ, TIMER_CTRL_IE); | 526 | integrator_time_init(1000000 / HZ, TIMER_CTRL_IE); |
| 527 | } | 527 | } |
| 528 | 528 | ||
| 529 | static struct sys_timer cp_timer = { | 529 | static struct sys_timer cp_timer = { |
| 530 | .init = intcp_timer_init, | 530 | .init = intcp_timer_init, |
| 531 | .offset = integrator_gettimeoffset, | 531 | .offset = integrator_gettimeoffset, |
| 532 | }; | 532 | }; |
| 533 | 533 | ||
| 534 | MACHINE_START(CINTEGRATOR, "ARM-IntegratorCP") | 534 | MACHINE_START(CINTEGRATOR, "ARM-IntegratorCP") |
| 535 | /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */ | 535 | /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */ |
| 536 | .phys_ram = 0x00000000, | 536 | .phys_ram = 0x00000000, |
| 537 | .phys_io = 0x16000000, | 537 | .phys_io = 0x16000000, |
| 538 | .io_pg_offst = ((0xf1600000) >> 18) & 0xfffc, | 538 | .io_pg_offst = ((0xf1600000) >> 18) & 0xfffc, |
| 539 | .boot_params = 0x00000100, | 539 | .boot_params = 0x00000100, |
| 540 | .map_io = intcp_map_io, | 540 | .map_io = intcp_map_io, |
| 541 | .init_irq = intcp_init_irq, | 541 | .init_irq = intcp_init_irq, |
| 542 | .timer = &cp_timer, | 542 | .timer = &cp_timer, |
| 543 | .init_machine = intcp_init, | 543 | .init_machine = intcp_init, |
| 544 | MACHINE_END | 544 | MACHINE_END |
| 545 | 545 |
arch/arm/mach-ixp2000/core.c
| 1 | /* | 1 | /* |
| 2 | * arch/arm/mach-ixp2000/common.c | 2 | * arch/arm/mach-ixp2000/common.c |
| 3 | * | 3 | * |
| 4 | * Common routines used by all IXP2400/2800 based platforms. | 4 | * Common routines used by all IXP2400/2800 based platforms. |
| 5 | * | 5 | * |
| 6 | * Author: Deepak Saxena <dsaxena@plexity.net> | 6 | * Author: Deepak Saxena <dsaxena@plexity.net> |
| 7 | * | 7 | * |
| 8 | * Copyright 2004 (C) MontaVista Software, Inc. | 8 | * Copyright 2004 (C) MontaVista Software, Inc. |
| 9 | * | 9 | * |
| 10 | * Based on work Copyright (C) 2002-2003 Intel Corporation | 10 | * Based on work Copyright (C) 2002-2003 Intel Corporation |
| 11 | * | 11 | * |
| 12 | * This file is licensed under the terms of the GNU General Public | 12 | * This file is licensed under the terms of the GNU General Public |
| 13 | * License version 2. This program is licensed "as is" without any | 13 | * License version 2. This program is licensed "as is" without any |
| 14 | * warranty of any kind, whether express or implied. | 14 | * warranty of any kind, whether express or implied. |
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | #include <linux/config.h> | 17 | #include <linux/config.h> |
| 18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
| 19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
| 20 | #include <linux/spinlock.h> | 20 | #include <linux/spinlock.h> |
| 21 | #include <linux/sched.h> | 21 | #include <linux/sched.h> |
| 22 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
| 23 | #include <linux/serial.h> | 23 | #include <linux/serial.h> |
| 24 | #include <linux/tty.h> | 24 | #include <linux/tty.h> |
| 25 | #include <linux/bitops.h> | 25 | #include <linux/bitops.h> |
| 26 | #include <linux/serial_8250.h> | 26 | #include <linux/serial_8250.h> |
| 27 | #include <linux/mm.h> | 27 | #include <linux/mm.h> |
| 28 | 28 | ||
| 29 | #include <asm/types.h> | 29 | #include <asm/types.h> |
| 30 | #include <asm/setup.h> | 30 | #include <asm/setup.h> |
| 31 | #include <asm/memory.h> | 31 | #include <asm/memory.h> |
| 32 | #include <asm/hardware.h> | 32 | #include <asm/hardware.h> |
| 33 | #include <asm/mach-types.h> | 33 | #include <asm/mach-types.h> |
| 34 | #include <asm/irq.h> | 34 | #include <asm/irq.h> |
| 35 | #include <asm/system.h> | 35 | #include <asm/system.h> |
| 36 | #include <asm/tlbflush.h> | 36 | #include <asm/tlbflush.h> |
| 37 | #include <asm/pgtable.h> | 37 | #include <asm/pgtable.h> |
| 38 | 38 | ||
| 39 | #include <asm/mach/map.h> | 39 | #include <asm/mach/map.h> |
| 40 | #include <asm/mach/time.h> | 40 | #include <asm/mach/time.h> |
| 41 | #include <asm/mach/irq.h> | 41 | #include <asm/mach/irq.h> |
| 42 | 42 | ||
| 43 | #include <asm/arch/gpio.h> | 43 | #include <asm/arch/gpio.h> |
| 44 | 44 | ||
| 45 | static DEFINE_SPINLOCK(ixp2000_slowport_lock); | 45 | static DEFINE_SPINLOCK(ixp2000_slowport_lock); |
| 46 | static unsigned long ixp2000_slowport_irq_flags; | 46 | static unsigned long ixp2000_slowport_irq_flags; |
| 47 | 47 | ||
| 48 | /************************************************************************* | 48 | /************************************************************************* |
| 49 | * Slowport access routines | 49 | * Slowport access routines |
| 50 | *************************************************************************/ | 50 | *************************************************************************/ |
| 51 | void ixp2000_acquire_slowport(struct slowport_cfg *new_cfg, struct slowport_cfg *old_cfg) | 51 | void ixp2000_acquire_slowport(struct slowport_cfg *new_cfg, struct slowport_cfg *old_cfg) |
| 52 | { | 52 | { |
| 53 | 53 | ||
| 54 | spin_lock_irqsave(&ixp2000_slowport_lock, ixp2000_slowport_irq_flags); | 54 | spin_lock_irqsave(&ixp2000_slowport_lock, ixp2000_slowport_irq_flags); |
| 55 | 55 | ||
| 56 | old_cfg->CCR = *IXP2000_SLOWPORT_CCR; | 56 | old_cfg->CCR = *IXP2000_SLOWPORT_CCR; |
| 57 | old_cfg->WTC = *IXP2000_SLOWPORT_WTC2; | 57 | old_cfg->WTC = *IXP2000_SLOWPORT_WTC2; |
| 58 | old_cfg->RTC = *IXP2000_SLOWPORT_RTC2; | 58 | old_cfg->RTC = *IXP2000_SLOWPORT_RTC2; |
| 59 | old_cfg->PCR = *IXP2000_SLOWPORT_PCR; | 59 | old_cfg->PCR = *IXP2000_SLOWPORT_PCR; |
| 60 | old_cfg->ADC = *IXP2000_SLOWPORT_ADC; | 60 | old_cfg->ADC = *IXP2000_SLOWPORT_ADC; |
| 61 | 61 | ||
| 62 | ixp2000_reg_write(IXP2000_SLOWPORT_CCR, new_cfg->CCR); | 62 | ixp2000_reg_write(IXP2000_SLOWPORT_CCR, new_cfg->CCR); |
| 63 | ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, new_cfg->WTC); | 63 | ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, new_cfg->WTC); |
| 64 | ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, new_cfg->RTC); | 64 | ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, new_cfg->RTC); |
| 65 | ixp2000_reg_write(IXP2000_SLOWPORT_PCR, new_cfg->PCR); | 65 | ixp2000_reg_write(IXP2000_SLOWPORT_PCR, new_cfg->PCR); |
| 66 | ixp2000_reg_write(IXP2000_SLOWPORT_ADC, new_cfg->ADC); | 66 | ixp2000_reg_write(IXP2000_SLOWPORT_ADC, new_cfg->ADC); |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | void ixp2000_release_slowport(struct slowport_cfg *old_cfg) | 69 | void ixp2000_release_slowport(struct slowport_cfg *old_cfg) |
| 70 | { | 70 | { |
| 71 | ixp2000_reg_write(IXP2000_SLOWPORT_CCR, old_cfg->CCR); | 71 | ixp2000_reg_write(IXP2000_SLOWPORT_CCR, old_cfg->CCR); |
| 72 | ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, old_cfg->WTC); | 72 | ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, old_cfg->WTC); |
| 73 | ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, old_cfg->RTC); | 73 | ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, old_cfg->RTC); |
| 74 | ixp2000_reg_write(IXP2000_SLOWPORT_PCR, old_cfg->PCR); | 74 | ixp2000_reg_write(IXP2000_SLOWPORT_PCR, old_cfg->PCR); |
| 75 | ixp2000_reg_write(IXP2000_SLOWPORT_ADC, old_cfg->ADC); | 75 | ixp2000_reg_write(IXP2000_SLOWPORT_ADC, old_cfg->ADC); |
| 76 | 76 | ||
| 77 | spin_unlock_irqrestore(&ixp2000_slowport_lock, | 77 | spin_unlock_irqrestore(&ixp2000_slowport_lock, |
| 78 | ixp2000_slowport_irq_flags); | 78 | ixp2000_slowport_irq_flags); |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | /************************************************************************* | 81 | /************************************************************************* |
| 82 | * Chip specific mappings shared by all IXP2000 systems | 82 | * Chip specific mappings shared by all IXP2000 systems |
| 83 | *************************************************************************/ | 83 | *************************************************************************/ |
| 84 | static struct map_desc ixp2000_io_desc[] __initdata = { | 84 | static struct map_desc ixp2000_io_desc[] __initdata = { |
| 85 | { | 85 | { |
| 86 | .virtual = IXP2000_CAP_VIRT_BASE, | 86 | .virtual = IXP2000_CAP_VIRT_BASE, |
| 87 | .physical = IXP2000_CAP_PHYS_BASE, | 87 | .physical = IXP2000_CAP_PHYS_BASE, |
| 88 | .length = IXP2000_CAP_SIZE, | 88 | .length = IXP2000_CAP_SIZE, |
| 89 | .type = MT_DEVICE | 89 | .type = MT_DEVICE |
| 90 | }, { | 90 | }, { |
| 91 | .virtual = IXP2000_INTCTL_VIRT_BASE, | 91 | .virtual = IXP2000_INTCTL_VIRT_BASE, |
| 92 | .physical = IXP2000_INTCTL_PHYS_BASE, | 92 | .physical = IXP2000_INTCTL_PHYS_BASE, |
| 93 | .length = IXP2000_INTCTL_SIZE, | 93 | .length = IXP2000_INTCTL_SIZE, |
| 94 | .type = MT_DEVICE | 94 | .type = MT_DEVICE |
| 95 | }, { | 95 | }, { |
| 96 | .virtual = IXP2000_PCI_CREG_VIRT_BASE, | 96 | .virtual = IXP2000_PCI_CREG_VIRT_BASE, |
| 97 | .physical = IXP2000_PCI_CREG_PHYS_BASE, | 97 | .physical = IXP2000_PCI_CREG_PHYS_BASE, |
| 98 | .length = IXP2000_PCI_CREG_SIZE, | 98 | .length = IXP2000_PCI_CREG_SIZE, |
| 99 | .type = MT_DEVICE | 99 | .type = MT_DEVICE |
| 100 | }, { | 100 | }, { |
| 101 | .virtual = IXP2000_PCI_CSR_VIRT_BASE, | 101 | .virtual = IXP2000_PCI_CSR_VIRT_BASE, |
| 102 | .physical = IXP2000_PCI_CSR_PHYS_BASE, | 102 | .physical = IXP2000_PCI_CSR_PHYS_BASE, |
| 103 | .length = IXP2000_PCI_CSR_SIZE, | 103 | .length = IXP2000_PCI_CSR_SIZE, |
| 104 | .type = MT_DEVICE | 104 | .type = MT_DEVICE |
| 105 | }, { | 105 | }, { |
| 106 | .virtual = IXP2000_MSF_VIRT_BASE, | 106 | .virtual = IXP2000_MSF_VIRT_BASE, |
| 107 | .physical = IXP2000_MSF_PHYS_BASE, | 107 | .physical = IXP2000_MSF_PHYS_BASE, |
| 108 | .length = IXP2000_MSF_SIZE, | 108 | .length = IXP2000_MSF_SIZE, |
| 109 | .type = MT_DEVICE | 109 | .type = MT_DEVICE |
| 110 | }, { | 110 | }, { |
| 111 | .virtual = IXP2000_PCI_IO_VIRT_BASE, | 111 | .virtual = IXP2000_PCI_IO_VIRT_BASE, |
| 112 | .physical = IXP2000_PCI_IO_PHYS_BASE, | 112 | .physical = IXP2000_PCI_IO_PHYS_BASE, |
| 113 | .length = IXP2000_PCI_IO_SIZE, | 113 | .length = IXP2000_PCI_IO_SIZE, |
| 114 | .type = MT_DEVICE | 114 | .type = MT_DEVICE |
| 115 | }, { | 115 | }, { |
| 116 | .virtual = IXP2000_PCI_CFG0_VIRT_BASE, | 116 | .virtual = IXP2000_PCI_CFG0_VIRT_BASE, |
| 117 | .physical = IXP2000_PCI_CFG0_PHYS_BASE, | 117 | .physical = IXP2000_PCI_CFG0_PHYS_BASE, |
| 118 | .length = IXP2000_PCI_CFG0_SIZE, | 118 | .length = IXP2000_PCI_CFG0_SIZE, |
| 119 | .type = MT_DEVICE | 119 | .type = MT_DEVICE |
| 120 | }, { | 120 | }, { |
| 121 | .virtual = IXP2000_PCI_CFG1_VIRT_BASE, | 121 | .virtual = IXP2000_PCI_CFG1_VIRT_BASE, |
| 122 | .physical = IXP2000_PCI_CFG1_PHYS_BASE, | 122 | .physical = IXP2000_PCI_CFG1_PHYS_BASE, |
| 123 | .length = IXP2000_PCI_CFG1_SIZE, | 123 | .length = IXP2000_PCI_CFG1_SIZE, |
| 124 | .type = MT_DEVICE | 124 | .type = MT_DEVICE |
| 125 | } | 125 | } |
| 126 | }; | 126 | }; |
| 127 | 127 | ||
| 128 | void __init ixp2000_map_io(void) | 128 | void __init ixp2000_map_io(void) |
| 129 | { | 129 | { |
| 130 | extern unsigned int processor_id; | 130 | extern unsigned int processor_id; |
| 131 | 131 | ||
| 132 | /* | 132 | /* |
| 133 | * On IXP2400 CPUs we need to use MT_IXP2000_DEVICE for | 133 | * On IXP2400 CPUs we need to use MT_IXP2000_DEVICE for |
| 134 | * tweaking the PMDs so XCB=101. On IXP2800s we use the normal | 134 | * tweaking the PMDs so XCB=101. On IXP2800s we use the normal |
| 135 | * PMD flags. | 135 | * PMD flags. |
| 136 | */ | 136 | */ |
| 137 | if ((processor_id & 0xfffffff0) == 0x69054190) { | 137 | if ((processor_id & 0xfffffff0) == 0x69054190) { |
| 138 | int i; | 138 | int i; |
| 139 | 139 | ||
| 140 | printk(KERN_INFO "Enabling IXP2400 erratum #66 workaround\n"); | 140 | printk(KERN_INFO "Enabling IXP2400 erratum #66 workaround\n"); |
| 141 | 141 | ||
| 142 | for(i=0;i<ARRAY_SIZE(ixp2000_io_desc);i++) | 142 | for(i=0;i<ARRAY_SIZE(ixp2000_io_desc);i++) |
| 143 | ixp2000_io_desc[i].type = MT_IXP2000_DEVICE; | 143 | ixp2000_io_desc[i].type = MT_IXP2000_DEVICE; |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | iotable_init(ixp2000_io_desc, ARRAY_SIZE(ixp2000_io_desc)); | 146 | iotable_init(ixp2000_io_desc, ARRAY_SIZE(ixp2000_io_desc)); |
| 147 | 147 | ||
| 148 | /* Set slowport to 8-bit mode. */ | 148 | /* Set slowport to 8-bit mode. */ |
| 149 | ixp2000_reg_write(IXP2000_SLOWPORT_FRM, 1); | 149 | ixp2000_reg_write(IXP2000_SLOWPORT_FRM, 1); |
| 150 | } | 150 | } |
| 151 | 151 | ||
| 152 | 152 | ||
| 153 | /************************************************************************* | 153 | /************************************************************************* |
| 154 | * Serial port support for IXP2000 | 154 | * Serial port support for IXP2000 |
| 155 | *************************************************************************/ | 155 | *************************************************************************/ |
| 156 | static struct plat_serial8250_port ixp2000_serial_port[] = { | 156 | static struct plat_serial8250_port ixp2000_serial_port[] = { |
| 157 | { | 157 | { |
| 158 | .mapbase = IXP2000_UART_PHYS_BASE, | 158 | .mapbase = IXP2000_UART_PHYS_BASE, |
| 159 | .membase = (char *)(IXP2000_UART_VIRT_BASE + 3), | 159 | .membase = (char *)(IXP2000_UART_VIRT_BASE + 3), |
| 160 | .irq = IRQ_IXP2000_UART, | 160 | .irq = IRQ_IXP2000_UART, |
| 161 | .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, | 161 | .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, |
| 162 | .iotype = UPIO_MEM, | 162 | .iotype = UPIO_MEM, |
| 163 | .regshift = 2, | 163 | .regshift = 2, |
| 164 | .uartclk = 50000000, | 164 | .uartclk = 50000000, |
| 165 | }, | 165 | }, |
| 166 | { }, | 166 | { }, |
| 167 | }; | 167 | }; |
| 168 | 168 | ||
| 169 | static struct resource ixp2000_uart_resource = { | 169 | static struct resource ixp2000_uart_resource = { |
| 170 | .start = IXP2000_UART_PHYS_BASE, | 170 | .start = IXP2000_UART_PHYS_BASE, |
| 171 | .end = IXP2000_UART_PHYS_BASE + 0xffff, | 171 | .end = IXP2000_UART_PHYS_BASE + 0xffff, |
| 172 | .flags = IORESOURCE_MEM, | 172 | .flags = IORESOURCE_MEM, |
| 173 | }; | 173 | }; |
| 174 | 174 | ||
| 175 | static struct platform_device ixp2000_serial_device = { | 175 | static struct platform_device ixp2000_serial_device = { |
| 176 | .name = "serial8250", | 176 | .name = "serial8250", |
| 177 | .id = 0, | 177 | .id = 0, |
| 178 | .dev = { | 178 | .dev = { |
| 179 | .platform_data = ixp2000_serial_port, | 179 | .platform_data = ixp2000_serial_port, |
| 180 | }, | 180 | }, |
| 181 | .num_resources = 1, | 181 | .num_resources = 1, |
| 182 | .resource = &ixp2000_uart_resource, | 182 | .resource = &ixp2000_uart_resource, |
| 183 | }; | 183 | }; |
| 184 | 184 | ||
| 185 | void __init ixp2000_uart_init(void) | 185 | void __init ixp2000_uart_init(void) |
| 186 | { | 186 | { |
| 187 | platform_device_register(&ixp2000_serial_device); | 187 | platform_device_register(&ixp2000_serial_device); |
| 188 | } | 188 | } |
| 189 | 189 | ||
| 190 | 190 | ||
| 191 | /************************************************************************* | 191 | /************************************************************************* |
| 192 | * Timer-tick functions for IXP2000 | 192 | * Timer-tick functions for IXP2000 |
| 193 | *************************************************************************/ | 193 | *************************************************************************/ |
| 194 | static unsigned ticks_per_jiffy; | 194 | static unsigned ticks_per_jiffy; |
| 195 | static unsigned ticks_per_usec; | 195 | static unsigned ticks_per_usec; |
| 196 | static unsigned next_jiffy_time; | 196 | static unsigned next_jiffy_time; |
| 197 | static volatile unsigned long *missing_jiffy_timer_csr; | 197 | static volatile unsigned long *missing_jiffy_timer_csr; |
| 198 | 198 | ||
| 199 | unsigned long ixp2000_gettimeoffset (void) | 199 | unsigned long ixp2000_gettimeoffset (void) |
| 200 | { | 200 | { |
| 201 | unsigned long offset; | 201 | unsigned long offset; |
| 202 | 202 | ||
| 203 | offset = next_jiffy_time - *missing_jiffy_timer_csr; | 203 | offset = next_jiffy_time - *missing_jiffy_timer_csr; |
| 204 | 204 | ||
| 205 | return offset / ticks_per_usec; | 205 | return offset / ticks_per_usec; |
| 206 | } | 206 | } |
| 207 | 207 | ||
| 208 | static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 208 | static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) |
| 209 | { | 209 | { |
| 210 | write_seqlock(&xtime_lock); | 210 | write_seqlock(&xtime_lock); |
| 211 | 211 | ||
| 212 | /* clear timer 1 */ | 212 | /* clear timer 1 */ |
| 213 | ixp2000_reg_write(IXP2000_T1_CLR, 1); | 213 | ixp2000_reg_write(IXP2000_T1_CLR, 1); |
| 214 | 214 | ||
| 215 | while ((next_jiffy_time - *missing_jiffy_timer_csr) > ticks_per_jiffy) { | 215 | while ((next_jiffy_time - *missing_jiffy_timer_csr) > ticks_per_jiffy) { |
| 216 | timer_tick(regs); | 216 | timer_tick(regs); |
| 217 | next_jiffy_time -= ticks_per_jiffy; | 217 | next_jiffy_time -= ticks_per_jiffy; |
| 218 | } | 218 | } |
| 219 | 219 | ||
| 220 | write_sequnlock(&xtime_lock); | 220 | write_sequnlock(&xtime_lock); |
| 221 | 221 | ||
| 222 | return IRQ_HANDLED; | 222 | return IRQ_HANDLED; |
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | static struct irqaction ixp2000_timer_irq = { | 225 | static struct irqaction ixp2000_timer_irq = { |
| 226 | .name = "IXP2000 Timer Tick", | 226 | .name = "IXP2000 Timer Tick", |
| 227 | .flags = SA_INTERRUPT | SA_TIMER, | 227 | .flags = SA_INTERRUPT | SA_TIMER, |
| 228 | .handler = ixp2000_timer_interrupt, | 228 | .handler = ixp2000_timer_interrupt, |
| 229 | }; | 229 | }; |
| 230 | 230 | ||
| 231 | void __init ixp2000_init_time(unsigned long tick_rate) | 231 | void __init ixp2000_init_time(unsigned long tick_rate) |
| 232 | { | 232 | { |
| 233 | ticks_per_jiffy = (tick_rate + HZ/2) / HZ; | 233 | ticks_per_jiffy = (tick_rate + HZ/2) / HZ; |
| 234 | ticks_per_usec = tick_rate / 1000000; | 234 | ticks_per_usec = tick_rate / 1000000; |
| 235 | 235 | ||
| 236 | /* | 236 | /* |
| 237 | * We use timer 1 as our timer interrupt. | 237 | * We use timer 1 as our timer interrupt. |
| 238 | */ | 238 | */ |
| 239 | ixp2000_reg_write(IXP2000_T1_CLR, 0); | 239 | ixp2000_reg_write(IXP2000_T1_CLR, 0); |
| 240 | ixp2000_reg_write(IXP2000_T1_CLD, ticks_per_jiffy - 1); | 240 | ixp2000_reg_write(IXP2000_T1_CLD, ticks_per_jiffy - 1); |
| 241 | ixp2000_reg_write(IXP2000_T1_CTL, (1 << 7)); | 241 | ixp2000_reg_write(IXP2000_T1_CTL, (1 << 7)); |
| 242 | 242 | ||
| 243 | /* | 243 | /* |
| 244 | * We use a second timer as a monotonic counter for tracking | 244 | * We use a second timer as a monotonic counter for tracking |
| 245 | * missed jiffies. The IXP2000 has four timers, but if we're | 245 | * missed jiffies. The IXP2000 has four timers, but if we're |
| 246 | * on an A-step IXP2800, timer 2 and 3 don't work, so on those | 246 | * on an A-step IXP2800, timer 2 and 3 don't work, so on those |
| 247 | * chips we use timer 4. Timer 4 is the only timer that can | 247 | * chips we use timer 4. Timer 4 is the only timer that can |
| 248 | * be used for the watchdog, so we use timer 2 if we're on a | 248 | * be used for the watchdog, so we use timer 2 if we're on a |
| 249 | * non-buggy chip. | 249 | * non-buggy chip. |
| 250 | */ | 250 | */ |
| 251 | if ((*IXP2000_PRODUCT_ID & 0x001ffef0) == 0x00000000) { | 251 | if ((*IXP2000_PRODUCT_ID & 0x001ffef0) == 0x00000000) { |
| 252 | printk(KERN_INFO "Enabling IXP2800 erratum #25 workaround\n"); | 252 | printk(KERN_INFO "Enabling IXP2800 erratum #25 workaround\n"); |
| 253 | 253 | ||
| 254 | ixp2000_reg_write(IXP2000_T4_CLR, 0); | 254 | ixp2000_reg_write(IXP2000_T4_CLR, 0); |
| 255 | ixp2000_reg_write(IXP2000_T4_CLD, -1); | 255 | ixp2000_reg_write(IXP2000_T4_CLD, -1); |
| 256 | ixp2000_reg_write(IXP2000_T4_CTL, (1 << 7)); | 256 | ixp2000_reg_write(IXP2000_T4_CTL, (1 << 7)); |
| 257 | missing_jiffy_timer_csr = IXP2000_T4_CSR; | 257 | missing_jiffy_timer_csr = IXP2000_T4_CSR; |
| 258 | } else { | 258 | } else { |
| 259 | ixp2000_reg_write(IXP2000_T2_CLR, 0); | 259 | ixp2000_reg_write(IXP2000_T2_CLR, 0); |
| 260 | ixp2000_reg_write(IXP2000_T2_CLD, -1); | 260 | ixp2000_reg_write(IXP2000_T2_CLD, -1); |
| 261 | ixp2000_reg_write(IXP2000_T2_CTL, (1 << 7)); | 261 | ixp2000_reg_write(IXP2000_T2_CTL, (1 << 7)); |
| 262 | missing_jiffy_timer_csr = IXP2000_T2_CSR; | 262 | missing_jiffy_timer_csr = IXP2000_T2_CSR; |
| 263 | } | 263 | } |
| 264 | next_jiffy_time = 0xffffffff; | 264 | next_jiffy_time = 0xffffffff; |
| 265 | 265 | ||
| 266 | /* register for interrupt */ | 266 | /* register for interrupt */ |
| 267 | setup_irq(IRQ_IXP2000_TIMER1, &ixp2000_timer_irq); | 267 | setup_irq(IRQ_IXP2000_TIMER1, &ixp2000_timer_irq); |
| 268 | } | 268 | } |
| 269 | 269 | ||
| 270 | /************************************************************************* | 270 | /************************************************************************* |
| 271 | * GPIO helpers | 271 | * GPIO helpers |
| 272 | *************************************************************************/ | 272 | *************************************************************************/ |
| 273 | static unsigned long GPIO_IRQ_falling_edge; | 273 | static unsigned long GPIO_IRQ_falling_edge; |
| 274 | static unsigned long GPIO_IRQ_rising_edge; | 274 | static unsigned long GPIO_IRQ_rising_edge; |
| 275 | static unsigned long GPIO_IRQ_level_low; | 275 | static unsigned long GPIO_IRQ_level_low; |
| 276 | static unsigned long GPIO_IRQ_level_high; | 276 | static unsigned long GPIO_IRQ_level_high; |
| 277 | 277 | ||
| 278 | static void update_gpio_int_csrs(void) | 278 | static void update_gpio_int_csrs(void) |
| 279 | { | 279 | { |
| 280 | ixp2000_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge); | 280 | ixp2000_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge); |
| 281 | ixp2000_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge); | 281 | ixp2000_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge); |
| 282 | ixp2000_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low); | 282 | ixp2000_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low); |
| 283 | ixp2000_reg_write(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high); | 283 | ixp2000_reg_write(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high); |
| 284 | } | 284 | } |
| 285 | 285 | ||
| 286 | void gpio_line_config(int line, int direction) | 286 | void gpio_line_config(int line, int direction) |
| 287 | { | 287 | { |
| 288 | unsigned long flags; | 288 | unsigned long flags; |
| 289 | 289 | ||
| 290 | local_irq_save(flags); | 290 | local_irq_save(flags); |
| 291 | if (direction == GPIO_OUT) { | 291 | if (direction == GPIO_OUT) { |
| 292 | irq_desc[line + IRQ_IXP2000_GPIO0].valid = 0; | 292 | irq_desc[line + IRQ_IXP2000_GPIO0].valid = 0; |
| 293 | 293 | ||
| 294 | /* if it's an output, it ain't an interrupt anymore */ | 294 | /* if it's an output, it ain't an interrupt anymore */ |
| 295 | GPIO_IRQ_falling_edge &= ~(1 << line); | 295 | GPIO_IRQ_falling_edge &= ~(1 << line); |
| 296 | GPIO_IRQ_rising_edge &= ~(1 << line); | 296 | GPIO_IRQ_rising_edge &= ~(1 << line); |
| 297 | GPIO_IRQ_level_low &= ~(1 << line); | 297 | GPIO_IRQ_level_low &= ~(1 << line); |
| 298 | GPIO_IRQ_level_high &= ~(1 << line); | 298 | GPIO_IRQ_level_high &= ~(1 << line); |
| 299 | update_gpio_int_csrs(); | 299 | update_gpio_int_csrs(); |
| 300 | 300 | ||
| 301 | ixp2000_reg_write(IXP2000_GPIO_PDSR, 1 << line); | 301 | ixp2000_reg_write(IXP2000_GPIO_PDSR, 1 << line); |
| 302 | } else if (direction == GPIO_IN) { | 302 | } else if (direction == GPIO_IN) { |
| 303 | ixp2000_reg_write(IXP2000_GPIO_PDCR, 1 << line); | 303 | ixp2000_reg_write(IXP2000_GPIO_PDCR, 1 << line); |
| 304 | } | 304 | } |
| 305 | local_irq_restore(flags); | 305 | local_irq_restore(flags); |
| 306 | } | 306 | } |
| 307 | 307 | ||
| 308 | 308 | ||
| 309 | /************************************************************************* | 309 | /************************************************************************* |
| 310 | * IRQ handling IXP2000 | 310 | * IRQ handling IXP2000 |
| 311 | *************************************************************************/ | 311 | *************************************************************************/ |
| 312 | static void ixp2000_GPIO_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) | 312 | static void ixp2000_GPIO_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) |
| 313 | { | 313 | { |
| 314 | int i; | 314 | int i; |
| 315 | unsigned long status = *IXP2000_GPIO_INST; | 315 | unsigned long status = *IXP2000_GPIO_INST; |
| 316 | 316 | ||
| 317 | for (i = 0; i <= 7; i++) { | 317 | for (i = 0; i <= 7; i++) { |
| 318 | if (status & (1<<i)) { | 318 | if (status & (1<<i)) { |
| 319 | desc = irq_desc + i + IRQ_IXP2000_GPIO0; | 319 | desc = irq_desc + i + IRQ_IXP2000_GPIO0; |
| 320 | desc->handle(i + IRQ_IXP2000_GPIO0, desc, regs); | 320 | desc_handle_irq(i + IRQ_IXP2000_GPIO0, desc, regs); |
| 321 | } | 321 | } |
| 322 | } | 322 | } |
| 323 | } | 323 | } |
| 324 | 324 | ||
| 325 | static int ixp2000_GPIO_irq_type(unsigned int irq, unsigned int type) | 325 | static int ixp2000_GPIO_irq_type(unsigned int irq, unsigned int type) |
| 326 | { | 326 | { |
| 327 | int line = irq - IRQ_IXP2000_GPIO0; | 327 | int line = irq - IRQ_IXP2000_GPIO0; |
| 328 | 328 | ||
| 329 | /* | 329 | /* |
| 330 | * First, configure this GPIO line as an input. | 330 | * First, configure this GPIO line as an input. |
| 331 | */ | 331 | */ |
| 332 | ixp2000_reg_write(IXP2000_GPIO_PDCR, 1 << line); | 332 | ixp2000_reg_write(IXP2000_GPIO_PDCR, 1 << line); |
| 333 | 333 | ||
| 334 | /* | 334 | /* |
| 335 | * Then, set the proper trigger type. | 335 | * Then, set the proper trigger type. |
| 336 | */ | 336 | */ |
| 337 | if (type & IRQT_FALLING) | 337 | if (type & IRQT_FALLING) |
| 338 | GPIO_IRQ_falling_edge |= 1 << line; | 338 | GPIO_IRQ_falling_edge |= 1 << line; |
| 339 | else | 339 | else |
| 340 | GPIO_IRQ_falling_edge &= ~(1 << line); | 340 | GPIO_IRQ_falling_edge &= ~(1 << line); |
| 341 | if (type & IRQT_RISING) | 341 | if (type & IRQT_RISING) |
| 342 | GPIO_IRQ_rising_edge |= 1 << line; | 342 | GPIO_IRQ_rising_edge |= 1 << line; |
| 343 | else | 343 | else |
| 344 | GPIO_IRQ_rising_edge &= ~(1 << line); | 344 | GPIO_IRQ_rising_edge &= ~(1 << line); |
| 345 | if (type & IRQT_LOW) | 345 | if (type & IRQT_LOW) |
| 346 | GPIO_IRQ_level_low |= 1 << line; | 346 | GPIO_IRQ_level_low |= 1 << line; |
| 347 | else | 347 | else |
| 348 | GPIO_IRQ_level_low &= ~(1 << line); | 348 | GPIO_IRQ_level_low &= ~(1 << line); |
| 349 | if (type & IRQT_HIGH) | 349 | if (type & IRQT_HIGH) |
| 350 | GPIO_IRQ_level_high |= 1 << line; | 350 | GPIO_IRQ_level_high |= 1 << line; |
| 351 | else | 351 | else |
| 352 | GPIO_IRQ_level_high &= ~(1 << line); | 352 | GPIO_IRQ_level_high &= ~(1 << line); |
| 353 | update_gpio_int_csrs(); | 353 | update_gpio_int_csrs(); |
| 354 | 354 | ||
| 355 | /* | 355 | /* |
| 356 | * Finally, mark the corresponding IRQ as valid. | 356 | * Finally, mark the corresponding IRQ as valid. |
| 357 | */ | 357 | */ |
| 358 | irq_desc[irq].valid = 1; | 358 | irq_desc[irq].valid = 1; |
| 359 | 359 | ||
| 360 | return 0; | 360 | return 0; |
| 361 | } | 361 | } |
| 362 | 362 | ||
| 363 | static void ixp2000_GPIO_irq_mask_ack(unsigned int irq) | 363 | static void ixp2000_GPIO_irq_mask_ack(unsigned int irq) |
| 364 | { | 364 | { |
| 365 | ixp2000_reg_write(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0))); | 365 | ixp2000_reg_write(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0))); |
| 366 | 366 | ||
| 367 | ixp2000_reg_write(IXP2000_GPIO_EDSR, (1 << (irq - IRQ_IXP2000_GPIO0))); | 367 | ixp2000_reg_write(IXP2000_GPIO_EDSR, (1 << (irq - IRQ_IXP2000_GPIO0))); |
| 368 | ixp2000_reg_write(IXP2000_GPIO_LDSR, (1 << (irq - IRQ_IXP2000_GPIO0))); | 368 | ixp2000_reg_write(IXP2000_GPIO_LDSR, (1 << (irq - IRQ_IXP2000_GPIO0))); |
| 369 | ixp2000_reg_write(IXP2000_GPIO_INST, (1 << (irq - IRQ_IXP2000_GPIO0))); | 369 | ixp2000_reg_write(IXP2000_GPIO_INST, (1 << (irq - IRQ_IXP2000_GPIO0))); |
| 370 | } | 370 | } |
| 371 | 371 | ||
| 372 | static void ixp2000_GPIO_irq_mask(unsigned int irq) | 372 | static void ixp2000_GPIO_irq_mask(unsigned int irq) |
| 373 | { | 373 | { |
| 374 | ixp2000_reg_write(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0))); | 374 | ixp2000_reg_write(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0))); |
| 375 | } | 375 | } |
| 376 | 376 | ||
| 377 | static void ixp2000_GPIO_irq_unmask(unsigned int irq) | 377 | static void ixp2000_GPIO_irq_unmask(unsigned int irq) |
| 378 | { | 378 | { |
| 379 | ixp2000_reg_write(IXP2000_GPIO_INSR, (1 << (irq - IRQ_IXP2000_GPIO0))); | 379 | ixp2000_reg_write(IXP2000_GPIO_INSR, (1 << (irq - IRQ_IXP2000_GPIO0))); |
| 380 | } | 380 | } |
| 381 | 381 | ||
| 382 | static struct irqchip ixp2000_GPIO_irq_chip = { | 382 | static struct irqchip ixp2000_GPIO_irq_chip = { |
| 383 | .type = ixp2000_GPIO_irq_type, | 383 | .ack = ixp2000_GPIO_irq_mask_ack, |
| 384 | .ack = ixp2000_GPIO_irq_mask_ack, | 384 | .mask = ixp2000_GPIO_irq_mask, |
| 385 | .mask = ixp2000_GPIO_irq_mask, | 385 | .unmask = ixp2000_GPIO_irq_unmask |
| 386 | .unmask = ixp2000_GPIO_irq_unmask | 386 | .set_type = ixp2000_GPIO_irq_type, |
| 387 | }; | 387 | }; |
| 388 | 388 | ||
| 389 | static void ixp2000_pci_irq_mask(unsigned int irq) | 389 | static void ixp2000_pci_irq_mask(unsigned int irq) |
| 390 | { | 390 | { |
| 391 | unsigned long temp = *IXP2000_PCI_XSCALE_INT_ENABLE; | 391 | unsigned long temp = *IXP2000_PCI_XSCALE_INT_ENABLE; |
| 392 | if (irq == IRQ_IXP2000_PCIA) | 392 | if (irq == IRQ_IXP2000_PCIA) |
| 393 | ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 26))); | 393 | ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 26))); |
| 394 | else if (irq == IRQ_IXP2000_PCIB) | 394 | else if (irq == IRQ_IXP2000_PCIB) |
| 395 | ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 27))); | 395 | ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 27))); |
| 396 | } | 396 | } |
| 397 | 397 | ||
| 398 | static void ixp2000_pci_irq_unmask(unsigned int irq) | 398 | static void ixp2000_pci_irq_unmask(unsigned int irq) |
| 399 | { | 399 | { |
| 400 | unsigned long temp = *IXP2000_PCI_XSCALE_INT_ENABLE; | 400 | unsigned long temp = *IXP2000_PCI_XSCALE_INT_ENABLE; |
| 401 | if (irq == IRQ_IXP2000_PCIA) | 401 | if (irq == IRQ_IXP2000_PCIA) |
| 402 | ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp | (1 << 26))); | 402 | ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp | (1 << 26))); |
| 403 | else if (irq == IRQ_IXP2000_PCIB) | 403 | else if (irq == IRQ_IXP2000_PCIB) |
| 404 | ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp | (1 << 27))); | 404 | ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp | (1 << 27))); |
| 405 | } | 405 | } |
| 406 | 406 | ||
| 407 | static struct irqchip ixp2000_pci_irq_chip = { | 407 | static struct irqchip ixp2000_pci_irq_chip = { |
| 408 | .ack = ixp2000_pci_irq_mask, | 408 | .ack = ixp2000_pci_irq_mask, |
| 409 | .mask = ixp2000_pci_irq_mask, | 409 | .mask = ixp2000_pci_irq_mask, |
| 410 | .unmask = ixp2000_pci_irq_unmask | 410 | .unmask = ixp2000_pci_irq_unmask |
| 411 | }; | 411 | }; |
| 412 | 412 | ||
| 413 | static void ixp2000_irq_mask(unsigned int irq) | 413 | static void ixp2000_irq_mask(unsigned int irq) |
| 414 | { | 414 | { |
| 415 | ixp2000_reg_write(IXP2000_IRQ_ENABLE_CLR, (1 << irq)); | 415 | ixp2000_reg_write(IXP2000_IRQ_ENABLE_CLR, (1 << irq)); |
| 416 | } | 416 | } |
| 417 | 417 | ||
| 418 | static void ixp2000_irq_unmask(unsigned int irq) | 418 | static void ixp2000_irq_unmask(unsigned int irq) |
| 419 | { | 419 | { |
| 420 | ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << irq)); | 420 | ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << irq)); |
| 421 | } | 421 | } |
| 422 | 422 | ||
| 423 | static struct irqchip ixp2000_irq_chip = { | 423 | static struct irqchip ixp2000_irq_chip = { |
| 424 | .ack = ixp2000_irq_mask, | 424 | .ack = ixp2000_irq_mask, |
| 425 | .mask = ixp2000_irq_mask, | 425 | .mask = ixp2000_irq_mask, |
| 426 | .unmask = ixp2000_irq_unmask | 426 | .unmask = ixp2000_irq_unmask |
| 427 | }; | 427 | }; |
| 428 | 428 | ||
| 429 | void __init ixp2000_init_irq(void) | 429 | void __init ixp2000_init_irq(void) |
| 430 | { | 430 | { |
| 431 | int irq; | 431 | int irq; |
| 432 | 432 | ||
| 433 | /* | 433 | /* |
| 434 | * Mask all sources | 434 | * Mask all sources |
| 435 | */ | 435 | */ |
| 436 | ixp2000_reg_write(IXP2000_IRQ_ENABLE_CLR, 0xffffffff); | 436 | ixp2000_reg_write(IXP2000_IRQ_ENABLE_CLR, 0xffffffff); |
| 437 | ixp2000_reg_write(IXP2000_FIQ_ENABLE_CLR, 0xffffffff); | 437 | ixp2000_reg_write(IXP2000_FIQ_ENABLE_CLR, 0xffffffff); |
| 438 | 438 | ||
| 439 | /* clear all GPIO edge/level detects */ | 439 | /* clear all GPIO edge/level detects */ |
| 440 | ixp2000_reg_write(IXP2000_GPIO_REDR, 0); | 440 | ixp2000_reg_write(IXP2000_GPIO_REDR, 0); |
| 441 | ixp2000_reg_write(IXP2000_GPIO_FEDR, 0); | 441 | ixp2000_reg_write(IXP2000_GPIO_FEDR, 0); |
| 442 | ixp2000_reg_write(IXP2000_GPIO_LSHR, 0); | 442 | ixp2000_reg_write(IXP2000_GPIO_LSHR, 0); |
| 443 | ixp2000_reg_write(IXP2000_GPIO_LSLR, 0); | 443 | ixp2000_reg_write(IXP2000_GPIO_LSLR, 0); |
| 444 | ixp2000_reg_write(IXP2000_GPIO_INCR, -1); | 444 | ixp2000_reg_write(IXP2000_GPIO_INCR, -1); |
| 445 | 445 | ||
| 446 | /* clear PCI interrupt sources */ | 446 | /* clear PCI interrupt sources */ |
| 447 | ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, 0); | 447 | ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, 0); |
| 448 | 448 | ||
| 449 | /* | 449 | /* |
| 450 | * Certain bits in the IRQ status register of the | 450 | * Certain bits in the IRQ status register of the |
| 451 | * IXP2000 are reserved. Instead of trying to map | 451 | * IXP2000 are reserved. Instead of trying to map |
| 452 | * things non 1:1 from bit position to IRQ number, | 452 | * things non 1:1 from bit position to IRQ number, |
| 453 | * we mark the reserved IRQs as invalid. This makes | 453 | * we mark the reserved IRQs as invalid. This makes |
| 454 | * our mask/unmask code much simpler. | 454 | * our mask/unmask code much simpler. |
| 455 | */ | 455 | */ |
| 456 | for (irq = IRQ_IXP2000_SOFT_INT; irq <= IRQ_IXP2000_THDB3; irq++) { | 456 | for (irq = IRQ_IXP2000_SOFT_INT; irq <= IRQ_IXP2000_THDB3; irq++) { |
| 457 | if ((1 << irq) & IXP2000_VALID_IRQ_MASK) { | 457 | if ((1 << irq) & IXP2000_VALID_IRQ_MASK) { |
| 458 | set_irq_chip(irq, &ixp2000_irq_chip); | 458 | set_irq_chip(irq, &ixp2000_irq_chip); |
| 459 | set_irq_handler(irq, do_level_IRQ); | 459 | set_irq_handler(irq, do_level_IRQ); |
| 460 | set_irq_flags(irq, IRQF_VALID); | 460 | set_irq_flags(irq, IRQF_VALID); |
| 461 | } else set_irq_flags(irq, 0); | 461 | } else set_irq_flags(irq, 0); |
| 462 | } | 462 | } |
| 463 | 463 | ||
| 464 | /* | 464 | /* |
| 465 | * GPIO IRQs are invalid until someone sets the interrupt mode | 465 | * GPIO IRQs are invalid until someone sets the interrupt mode |
| 466 | * by calling set_irq_type(). | 466 | * by calling set_irq_type(). |
| 467 | */ | 467 | */ |
| 468 | for (irq = IRQ_IXP2000_GPIO0; irq <= IRQ_IXP2000_GPIO7; irq++) { | 468 | for (irq = IRQ_IXP2000_GPIO0; irq <= IRQ_IXP2000_GPIO7; irq++) { |
| 469 | set_irq_chip(irq, &ixp2000_GPIO_irq_chip); | 469 | set_irq_chip(irq, &ixp2000_GPIO_irq_chip); |
| 470 | set_irq_handler(irq, do_level_IRQ); | 470 | set_irq_handler(irq, do_level_IRQ); |
| 471 | set_irq_flags(irq, 0); | 471 | set_irq_flags(irq, 0); |
| 472 | } | 472 | } |
| 473 | set_irq_chained_handler(IRQ_IXP2000_GPIO, ixp2000_GPIO_irq_handler); | 473 | set_irq_chained_handler(IRQ_IXP2000_GPIO, ixp2000_GPIO_irq_handler); |
| 474 | 474 | ||
| 475 | /* | 475 | /* |
| 476 | * Enable PCI irqs. The actual PCI[AB] decoding is done in | 476 | * Enable PCI irqs. The actual PCI[AB] decoding is done in |
| 477 | * entry-macro.S, so we don't need a chained handler for the | 477 | * entry-macro.S, so we don't need a chained handler for the |
| 478 | * PCI interrupt source. | 478 | * PCI interrupt source. |
| 479 | */ | 479 | */ |
| 480 | ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << IRQ_IXP2000_PCI)); | 480 | ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << IRQ_IXP2000_PCI)); |
| 481 | for (irq = IRQ_IXP2000_PCIA; irq <= IRQ_IXP2000_PCIB; irq++) { | 481 | for (irq = IRQ_IXP2000_PCIA; irq <= IRQ_IXP2000_PCIB; irq++) { |
| 482 | set_irq_chip(irq, &ixp2000_pci_irq_chip); | 482 | set_irq_chip(irq, &ixp2000_pci_irq_chip); |
| 483 | set_irq_handler(irq, do_level_IRQ); | 483 | set_irq_handler(irq, do_level_IRQ); |
| 484 | set_irq_flags(irq, IRQF_VALID); | 484 | set_irq_flags(irq, IRQF_VALID); |
| 485 | } | 485 | } |
| 486 | } | 486 | } |
| 487 | 487 | ||
| 488 | 488 |
arch/arm/mach-ixp2000/ixdp2x00.c
| 1 | /* | 1 | /* |
| 2 | * arch/arm/mach-ixp2000/ixdp2x00.c | 2 | * arch/arm/mach-ixp2000/ixdp2x00.c |
| 3 | * | 3 | * |
| 4 | * Code common to IXDP2400 and IXDP2800 platforms. | 4 | * Code common to IXDP2400 and IXDP2800 platforms. |
| 5 | * | 5 | * |
| 6 | * Original Author: Naeem Afzal <naeem.m.afzal@intel.com> | 6 | * Original Author: Naeem Afzal <naeem.m.afzal@intel.com> |
| 7 | * Maintainer: Deepak Saxena <dsaxena@plexity.net> | 7 | * Maintainer: Deepak Saxena <dsaxena@plexity.net> |
| 8 | * | 8 | * |
| 9 | * Copyright (C) 2002 Intel Corp. | 9 | * Copyright (C) 2002 Intel Corp. |
| 10 | * Copyright (C) 2003-2004 MontaVista Software, Inc. | 10 | * Copyright (C) 2003-2004 MontaVista Software, Inc. |
| 11 | * | 11 | * |
| 12 | * This program is free software; you can redistribute it and/or modify it | 12 | * This program is free software; you can redistribute it and/or modify it |
| 13 | * under the terms of the GNU General Public License as published by the | 13 | * under the terms of the GNU General Public License as published by the |
| 14 | * Free Software Foundation; either version 2 of the License, or (at your | 14 | * Free Software Foundation; either version 2 of the License, or (at your |
| 15 | * option) any later version. | 15 | * option) any later version. |
| 16 | */ | 16 | */ |
| 17 | #include <linux/config.h> | 17 | #include <linux/config.h> |
| 18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
| 19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
| 20 | #include <linux/mm.h> | 20 | #include <linux/mm.h> |
| 21 | #include <linux/sched.h> | 21 | #include <linux/sched.h> |
| 22 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
| 23 | #include <linux/device.h> | 23 | #include <linux/device.h> |
| 24 | #include <linux/bitops.h> | 24 | #include <linux/bitops.h> |
| 25 | #include <linux/pci.h> | 25 | #include <linux/pci.h> |
| 26 | #include <linux/ioport.h> | 26 | #include <linux/ioport.h> |
| 27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
| 28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
| 29 | 29 | ||
| 30 | #include <asm/io.h> | 30 | #include <asm/io.h> |
| 31 | #include <asm/irq.h> | 31 | #include <asm/irq.h> |
| 32 | #include <asm/pgtable.h> | 32 | #include <asm/pgtable.h> |
| 33 | #include <asm/page.h> | 33 | #include <asm/page.h> |
| 34 | #include <asm/system.h> | 34 | #include <asm/system.h> |
| 35 | #include <asm/hardware.h> | 35 | #include <asm/hardware.h> |
| 36 | #include <asm/mach-types.h> | 36 | #include <asm/mach-types.h> |
| 37 | 37 | ||
| 38 | #include <asm/mach/pci.h> | 38 | #include <asm/mach/pci.h> |
| 39 | #include <asm/mach/map.h> | 39 | #include <asm/mach/map.h> |
| 40 | #include <asm/mach/irq.h> | 40 | #include <asm/mach/irq.h> |
| 41 | #include <asm/mach/time.h> | 41 | #include <asm/mach/time.h> |
| 42 | #include <asm/mach/flash.h> | 42 | #include <asm/mach/flash.h> |
| 43 | #include <asm/mach/arch.h> | 43 | #include <asm/mach/arch.h> |
| 44 | 44 | ||
| 45 | #include <asm/arch/gpio.h> | 45 | #include <asm/arch/gpio.h> |
| 46 | 46 | ||
| 47 | 47 | ||
| 48 | /************************************************************************* | 48 | /************************************************************************* |
| 49 | * IXDP2x00 IRQ Initialization | 49 | * IXDP2x00 IRQ Initialization |
| 50 | *************************************************************************/ | 50 | *************************************************************************/ |
| 51 | static volatile unsigned long *board_irq_mask; | 51 | static volatile unsigned long *board_irq_mask; |
| 52 | static volatile unsigned long *board_irq_stat; | 52 | static volatile unsigned long *board_irq_stat; |
| 53 | static unsigned long board_irq_count; | 53 | static unsigned long board_irq_count; |
| 54 | 54 | ||
| 55 | #ifdef CONFIG_ARCH_IXDP2400 | 55 | #ifdef CONFIG_ARCH_IXDP2400 |
| 56 | /* | 56 | /* |
| 57 | * Slowport configuration for accessing CPLD registers on IXDP2x00 | 57 | * Slowport configuration for accessing CPLD registers on IXDP2x00 |
| 58 | */ | 58 | */ |
| 59 | static struct slowport_cfg slowport_cpld_cfg = { | 59 | static struct slowport_cfg slowport_cpld_cfg = { |
| 60 | .CCR = SLOWPORT_CCR_DIV_2, | 60 | .CCR = SLOWPORT_CCR_DIV_2, |
| 61 | .WTC = 0x00000070, | 61 | .WTC = 0x00000070, |
| 62 | .RTC = 0x00000070, | 62 | .RTC = 0x00000070, |
| 63 | .PCR = SLOWPORT_MODE_FLASH, | 63 | .PCR = SLOWPORT_MODE_FLASH, |
| 64 | .ADC = SLOWPORT_ADDR_WIDTH_24 | SLOWPORT_DATA_WIDTH_8 | 64 | .ADC = SLOWPORT_ADDR_WIDTH_24 | SLOWPORT_DATA_WIDTH_8 |
| 65 | }; | 65 | }; |
| 66 | #endif | 66 | #endif |
| 67 | 67 | ||
| 68 | static void ixdp2x00_irq_mask(unsigned int irq) | 68 | static void ixdp2x00_irq_mask(unsigned int irq) |
| 69 | { | 69 | { |
| 70 | unsigned long dummy; | 70 | unsigned long dummy; |
| 71 | static struct slowport_cfg old_cfg; | 71 | static struct slowport_cfg old_cfg; |
| 72 | 72 | ||
| 73 | /* | 73 | /* |
| 74 | * This is ugly in common code but really don't know | 74 | * This is ugly in common code but really don't know |
| 75 | * of a better way to handle it. :( | 75 | * of a better way to handle it. :( |
| 76 | */ | 76 | */ |
| 77 | #ifdef CONFIG_ARCH_IXDP2400 | 77 | #ifdef CONFIG_ARCH_IXDP2400 |
| 78 | if (machine_is_ixdp2400()) | 78 | if (machine_is_ixdp2400()) |
| 79 | ixp2000_acquire_slowport(&slowport_cpld_cfg, &old_cfg); | 79 | ixp2000_acquire_slowport(&slowport_cpld_cfg, &old_cfg); |
| 80 | #endif | 80 | #endif |
| 81 | 81 | ||
| 82 | dummy = *board_irq_mask; | 82 | dummy = *board_irq_mask; |
| 83 | dummy |= IXP2000_BOARD_IRQ_MASK(irq); | 83 | dummy |= IXP2000_BOARD_IRQ_MASK(irq); |
| 84 | ixp2000_reg_write(board_irq_mask, dummy); | 84 | ixp2000_reg_write(board_irq_mask, dummy); |
| 85 | 85 | ||
| 86 | #ifdef CONFIG_ARCH_IXDP2400 | 86 | #ifdef CONFIG_ARCH_IXDP2400 |
| 87 | if (machine_is_ixdp2400()) | 87 | if (machine_is_ixdp2400()) |
| 88 | ixp2000_release_slowport(&old_cfg); | 88 | ixp2000_release_slowport(&old_cfg); |
| 89 | #endif | 89 | #endif |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | static void ixdp2x00_irq_unmask(unsigned int irq) | 92 | static void ixdp2x00_irq_unmask(unsigned int irq) |
| 93 | { | 93 | { |
| 94 | unsigned long dummy; | 94 | unsigned long dummy; |
| 95 | static struct slowport_cfg old_cfg; | 95 | static struct slowport_cfg old_cfg; |
| 96 | 96 | ||
| 97 | #ifdef CONFIG_ARCH_IXDP2400 | 97 | #ifdef CONFIG_ARCH_IXDP2400 |
| 98 | if (machine_is_ixdp2400()) | 98 | if (machine_is_ixdp2400()) |
| 99 | ixp2000_acquire_slowport(&slowport_cpld_cfg, &old_cfg); | 99 | ixp2000_acquire_slowport(&slowport_cpld_cfg, &old_cfg); |
| 100 | #endif | 100 | #endif |
| 101 | 101 | ||
| 102 | dummy = *board_irq_mask; | 102 | dummy = *board_irq_mask; |
| 103 | dummy &= ~IXP2000_BOARD_IRQ_MASK(irq); | 103 | dummy &= ~IXP2000_BOARD_IRQ_MASK(irq); |
| 104 | ixp2000_reg_write(board_irq_mask, dummy); | 104 | ixp2000_reg_write(board_irq_mask, dummy); |
| 105 | 105 | ||
| 106 | if (machine_is_ixdp2400()) | 106 | if (machine_is_ixdp2400()) |
| 107 | ixp2000_release_slowport(&old_cfg); | 107 | ixp2000_release_slowport(&old_cfg); |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | static void ixdp2x00_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) | 110 | static void ixdp2x00_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) |
| 111 | { | 111 | { |
| 112 | volatile u32 ex_interrupt = 0; | 112 | volatile u32 ex_interrupt = 0; |
| 113 | static struct slowport_cfg old_cfg; | 113 | static struct slowport_cfg old_cfg; |
| 114 | int i; | 114 | int i; |
| 115 | 115 | ||
| 116 | desc->chip->mask(irq); | 116 | desc->chip->mask(irq); |
| 117 | 117 | ||
| 118 | #ifdef CONFIG_ARCH_IXDP2400 | 118 | #ifdef CONFIG_ARCH_IXDP2400 |
| 119 | if (machine_is_ixdp2400()) | 119 | if (machine_is_ixdp2400()) |
| 120 | ixp2000_acquire_slowport(&slowport_cpld_cfg, &old_cfg); | 120 | ixp2000_acquire_slowport(&slowport_cpld_cfg, &old_cfg); |
| 121 | #endif | 121 | #endif |
| 122 | ex_interrupt = *board_irq_stat & 0xff; | 122 | ex_interrupt = *board_irq_stat & 0xff; |
| 123 | if (machine_is_ixdp2400()) | 123 | if (machine_is_ixdp2400()) |
| 124 | ixp2000_release_slowport(&old_cfg); | 124 | ixp2000_release_slowport(&old_cfg); |
| 125 | 125 | ||
| 126 | if(!ex_interrupt) { | 126 | if(!ex_interrupt) { |
| 127 | printk(KERN_ERR "Spurious IXDP2x00 CPLD interrupt!\n"); | 127 | printk(KERN_ERR "Spurious IXDP2x00 CPLD interrupt!\n"); |
| 128 | return; | 128 | return; |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | for(i = 0; i < board_irq_count; i++) { | 131 | for(i = 0; i < board_irq_count; i++) { |
| 132 | if(ex_interrupt & (1 << i)) { | 132 | if(ex_interrupt & (1 << i)) { |
| 133 | struct irqdesc *cpld_desc; | 133 | struct irqdesc *cpld_desc; |
| 134 | int cpld_irq = IXP2000_BOARD_IRQ(0) + i; | 134 | int cpld_irq = IXP2000_BOARD_IRQ(0) + i; |
| 135 | cpld_desc = irq_desc + cpld_irq; | 135 | cpld_desc = irq_desc + cpld_irq; |
| 136 | cpld_desc->handle(cpld_irq, cpld_desc, regs); | 136 | desc_handle_irq(cpld_irq, cpld_desc, regs); |
| 137 | } | 137 | } |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | desc->chip->unmask(irq); | 140 | desc->chip->unmask(irq); |
| 141 | } | 141 | } |
| 142 | 142 | ||
| 143 | static struct irqchip ixdp2x00_cpld_irq_chip = { | 143 | static struct irqchip ixdp2x00_cpld_irq_chip = { |
| 144 | .ack = ixdp2x00_irq_mask, | 144 | .ack = ixdp2x00_irq_mask, |
| 145 | .mask = ixdp2x00_irq_mask, | 145 | .mask = ixdp2x00_irq_mask, |
| 146 | .unmask = ixdp2x00_irq_unmask | 146 | .unmask = ixdp2x00_irq_unmask |
| 147 | }; | 147 | }; |
| 148 | 148 | ||
| 149 | void ixdp2x00_init_irq(volatile unsigned long *stat_reg, volatile unsigned long *mask_reg, unsigned long nr_irqs) | 149 | void ixdp2x00_init_irq(volatile unsigned long *stat_reg, volatile unsigned long *mask_reg, unsigned long nr_irqs) |
| 150 | { | 150 | { |
| 151 | unsigned int irq; | 151 | unsigned int irq; |
| 152 | 152 | ||
| 153 | ixp2000_init_irq(); | 153 | ixp2000_init_irq(); |
| 154 | 154 | ||
| 155 | if (!ixdp2x00_master_npu()) | 155 | if (!ixdp2x00_master_npu()) |
| 156 | return; | 156 | return; |
| 157 | 157 | ||
| 158 | board_irq_stat = stat_reg; | 158 | board_irq_stat = stat_reg; |
| 159 | board_irq_mask = mask_reg; | 159 | board_irq_mask = mask_reg; |
| 160 | board_irq_count = nr_irqs; | 160 | board_irq_count = nr_irqs; |
| 161 | 161 | ||
| 162 | *board_irq_mask = 0xffffffff; | 162 | *board_irq_mask = 0xffffffff; |
| 163 | 163 | ||
| 164 | for(irq = IXP2000_BOARD_IRQ(0); irq < IXP2000_BOARD_IRQ(board_irq_count); irq++) { | 164 | for(irq = IXP2000_BOARD_IRQ(0); irq < IXP2000_BOARD_IRQ(board_irq_count); irq++) { |
| 165 | set_irq_chip(irq, &ixdp2x00_cpld_irq_chip); | 165 | set_irq_chip(irq, &ixdp2x00_cpld_irq_chip); |
| 166 | set_irq_handler(irq, do_level_IRQ); | 166 | set_irq_handler(irq, do_level_IRQ); |
| 167 | set_irq_flags(irq, IRQF_VALID); | 167 | set_irq_flags(irq, IRQF_VALID); |
| 168 | } | 168 | } |
| 169 | 169 | ||
| 170 | /* Hook into PCI interrupt */ | 170 | /* Hook into PCI interrupt */ |
| 171 | set_irq_chained_handler(IRQ_IXP2000_PCIB, &ixdp2x00_irq_handler); | 171 | set_irq_chained_handler(IRQ_IXP2000_PCIB, &ixdp2x00_irq_handler); |
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | /************************************************************************* | 174 | /************************************************************************* |
| 175 | * IXDP2x00 memory map | 175 | * IXDP2x00 memory map |
| 176 | *************************************************************************/ | 176 | *************************************************************************/ |
| 177 | static struct map_desc ixdp2x00_io_desc __initdata = { | 177 | static struct map_desc ixdp2x00_io_desc __initdata = { |
| 178 | .virtual = IXDP2X00_VIRT_CPLD_BASE, | 178 | .virtual = IXDP2X00_VIRT_CPLD_BASE, |
| 179 | .physical = IXDP2X00_PHYS_CPLD_BASE, | 179 | .physical = IXDP2X00_PHYS_CPLD_BASE, |
| 180 | .length = IXDP2X00_CPLD_SIZE, | 180 | .length = IXDP2X00_CPLD_SIZE, |
| 181 | .type = MT_DEVICE | 181 | .type = MT_DEVICE |
| 182 | }; | 182 | }; |
| 183 | 183 | ||
| 184 | void __init ixdp2x00_map_io(void) | 184 | void __init ixdp2x00_map_io(void) |
| 185 | { | 185 | { |
| 186 | ixp2000_map_io(); | 186 | ixp2000_map_io(); |
| 187 | 187 | ||
| 188 | iotable_init(&ixdp2x00_io_desc, 1); | 188 | iotable_init(&ixdp2x00_io_desc, 1); |
| 189 | } | 189 | } |
| 190 | 190 | ||
| 191 | /************************************************************************* | 191 | /************************************************************************* |
| 192 | * IXDP2x00-common PCI init | 192 | * IXDP2x00-common PCI init |
| 193 | * | 193 | * |
| 194 | * The IXDP2[48]00 has a horrid PCI bus layout. Basically the board | 194 | * The IXDP2[48]00 has a horrid PCI bus layout. Basically the board |
| 195 | * contains two NPUs (ingress and egress) connected over PCI, both running | 195 | * contains two NPUs (ingress and egress) connected over PCI, both running |
| 196 | * instances of the kernel. So far so good. Peers on the PCI bus running | 196 | * instances of the kernel. So far so good. Peers on the PCI bus running |
| 197 | * Linux is a common design in telecom systems. The problem is that instead | 197 | * Linux is a common design in telecom systems. The problem is that instead |
| 198 | * of all the devices being controlled by a single host, different | 198 | * of all the devices being controlled by a single host, different |
| 199 | * devices are controlles by different NPUs on the same bus, leading to | 199 | * devices are controlles by different NPUs on the same bus, leading to |
| 200 | * multiple hosts on the bus. The exact bus layout looks like: | 200 | * multiple hosts on the bus. The exact bus layout looks like: |
| 201 | * | 201 | * |
| 202 | * Bus 0 | 202 | * Bus 0 |
| 203 | * Master NPU <-------------------+-------------------> Slave NPU | 203 | * Master NPU <-------------------+-------------------> Slave NPU |
| 204 | * | | 204 | * | |
| 205 | * | | 205 | * | |
| 206 | * P2P | 206 | * P2P |
| 207 | * | | 207 | * | |
| 208 | * | 208 | * |
| 209 | * Bus 1 | | 209 | * Bus 1 | |
| 210 | * <--+------+---------+---------+------+--> | 210 | * <--+------+---------+---------+------+--> |
| 211 | * | | | | | | 211 | * | | | | | |
| 212 | * | | | | | | 212 | * | | | | | |
| 213 | * ... Dev PMC Media Eth0 Eth1 ... | 213 | * ... Dev PMC Media Eth0 Eth1 ... |
| 214 | * | 214 | * |
| 215 | * The master controlls all but Eth1, which is controlled by the | 215 | * The master controlls all but Eth1, which is controlled by the |
| 216 | * slave. What this means is that the both the master and the slave | 216 | * slave. What this means is that the both the master and the slave |
| 217 | * have to scan the bus, but only one of them can enumerate the bus. | 217 | * have to scan the bus, but only one of them can enumerate the bus. |
| 218 | * In addition, after the bus is scanned, each kernel must remove | 218 | * In addition, after the bus is scanned, each kernel must remove |
| 219 | * the device(s) it does not control from the PCI dev list otherwise | 219 | * the device(s) it does not control from the PCI dev list otherwise |
| 220 | * a driver on each NPU will try to manage it and we will have horrible | 220 | * a driver on each NPU will try to manage it and we will have horrible |
| 221 | * conflicts. Oh..and the slave NPU needs to see the master NPU | 221 | * conflicts. Oh..and the slave NPU needs to see the master NPU |
| 222 | * for Intel's drivers to work properly. Closed source drivers... | 222 | * for Intel's drivers to work properly. Closed source drivers... |
| 223 | * | 223 | * |
| 224 | * The way we deal with this is fairly simple but ugly: | 224 | * The way we deal with this is fairly simple but ugly: |
| 225 | * | 225 | * |
| 226 | * 1) Let master scan and enumerate the bus completely. | 226 | * 1) Let master scan and enumerate the bus completely. |
| 227 | * 2) Master deletes Eth1 from device list. | 227 | * 2) Master deletes Eth1 from device list. |
| 228 | * 3) Slave scans bus and then deletes all but Eth1 (Eth0 on slave) | 228 | * 3) Slave scans bus and then deletes all but Eth1 (Eth0 on slave) |
| 229 | * from device list. | 229 | * from device list. |
| 230 | * 4) Find HW designers and LART them. | 230 | * 4) Find HW designers and LART them. |
| 231 | * | 231 | * |
| 232 | * The boards also do not do normal PCI IRQ routing, or any sort of | 232 | * The boards also do not do normal PCI IRQ routing, or any sort of |
| 233 | * sensical swizzling, so we just need to check where on the bus a | 233 | * sensical swizzling, so we just need to check where on the bus a |
| 234 | * device sits and figure out to which CPLD pin the interrupt is routed. | 234 | * device sits and figure out to which CPLD pin the interrupt is routed. |
| 235 | * See ixdp2[48]00.c files. | 235 | * See ixdp2[48]00.c files. |
| 236 | * | 236 | * |
| 237 | *************************************************************************/ | 237 | *************************************************************************/ |
| 238 | void ixdp2x00_slave_pci_postinit(void) | 238 | void ixdp2x00_slave_pci_postinit(void) |
| 239 | { | 239 | { |
| 240 | struct pci_dev *dev; | 240 | struct pci_dev *dev; |
| 241 | 241 | ||
| 242 | /* | 242 | /* |
| 243 | * Remove PMC device is there is one | 243 | * Remove PMC device is there is one |
| 244 | */ | 244 | */ |
| 245 | if((dev = pci_find_slot(1, IXDP2X00_PMC_DEVFN))) | 245 | if((dev = pci_find_slot(1, IXDP2X00_PMC_DEVFN))) |
| 246 | pci_remove_bus_device(dev); | 246 | pci_remove_bus_device(dev); |
| 247 | 247 | ||
| 248 | dev = pci_find_slot(0, IXDP2X00_21555_DEVFN); | 248 | dev = pci_find_slot(0, IXDP2X00_21555_DEVFN); |
| 249 | pci_remove_bus_device(dev); | 249 | pci_remove_bus_device(dev); |
| 250 | } | 250 | } |
| 251 | 251 | ||
| 252 | /************************************************************************** | 252 | /************************************************************************** |
| 253 | * IXDP2x00 Machine Setup | 253 | * IXDP2x00 Machine Setup |
| 254 | *************************************************************************/ | 254 | *************************************************************************/ |
| 255 | static struct flash_platform_data ixdp2x00_platform_data = { | 255 | static struct flash_platform_data ixdp2x00_platform_data = { |
| 256 | .map_name = "cfi_probe", | 256 | .map_name = "cfi_probe", |
| 257 | .width = 1, | 257 | .width = 1, |
| 258 | }; | 258 | }; |
| 259 | 259 | ||
| 260 | static struct ixp2000_flash_data ixdp2x00_flash_data = { | 260 | static struct ixp2000_flash_data ixdp2x00_flash_data = { |
| 261 | .platform_data = &ixdp2x00_platform_data, | 261 | .platform_data = &ixdp2x00_platform_data, |
| 262 | .nr_banks = 1 | 262 | .nr_banks = 1 |
| 263 | }; | 263 | }; |
| 264 | 264 | ||
| 265 | static struct resource ixdp2x00_flash_resource = { | 265 | static struct resource ixdp2x00_flash_resource = { |
| 266 | .start = 0xc4000000, | 266 | .start = 0xc4000000, |
| 267 | .end = 0xc4000000 + 0x00ffffff, | 267 | .end = 0xc4000000 + 0x00ffffff, |
| 268 | .flags = IORESOURCE_MEM, | 268 | .flags = IORESOURCE_MEM, |
| 269 | }; | 269 | }; |
| 270 | 270 | ||
| 271 | static struct platform_device ixdp2x00_flash = { | 271 | static struct platform_device ixdp2x00_flash = { |
| 272 | .name = "IXP2000-Flash", | 272 | .name = "IXP2000-Flash", |
| 273 | .id = 0, | 273 | .id = 0, |
| 274 | .dev = { | 274 | .dev = { |
| 275 | .platform_data = &ixdp2x00_flash_data, | 275 | .platform_data = &ixdp2x00_flash_data, |
| 276 | }, | 276 | }, |
| 277 | .num_resources = 1, | 277 | .num_resources = 1, |
| 278 | .resource = &ixdp2x00_flash_resource, | 278 | .resource = &ixdp2x00_flash_resource, |
| 279 | }; | 279 | }; |
| 280 | 280 | ||
| 281 | static struct ixp2000_i2c_pins ixdp2x00_i2c_gpio_pins = { | 281 | static struct ixp2000_i2c_pins ixdp2x00_i2c_gpio_pins = { |
| 282 | .sda_pin = IXDP2X00_GPIO_SDA, | 282 | .sda_pin = IXDP2X00_GPIO_SDA, |
| 283 | .scl_pin = IXDP2X00_GPIO_SCL, | 283 | .scl_pin = IXDP2X00_GPIO_SCL, |
| 284 | }; | 284 | }; |
| 285 | 285 | ||
| 286 | static struct platform_device ixdp2x00_i2c_controller = { | 286 | static struct platform_device ixdp2x00_i2c_controller = { |
| 287 | .name = "IXP2000-I2C", | 287 | .name = "IXP2000-I2C", |
| 288 | .id = 0, | 288 | .id = 0, |
| 289 | .dev = { | 289 | .dev = { |
| 290 | .platform_data = &ixdp2x00_i2c_gpio_pins, | 290 | .platform_data = &ixdp2x00_i2c_gpio_pins, |
| 291 | }, | 291 | }, |
| 292 | .num_resources = 0 | 292 | .num_resources = 0 |
| 293 | }; | 293 | }; |
| 294 | 294 | ||
| 295 | static struct platform_device *ixdp2x00_devices[] __initdata = { | 295 | static struct platform_device *ixdp2x00_devices[] __initdata = { |
| 296 | &ixdp2x00_flash, | 296 | &ixdp2x00_flash, |
| 297 | &ixdp2x00_i2c_controller | 297 | &ixdp2x00_i2c_controller |
| 298 | }; | 298 | }; |
| 299 | 299 | ||
| 300 | void __init ixdp2x00_init_machine(void) | 300 | void __init ixdp2x00_init_machine(void) |
| 301 | { | 301 | { |
| 302 | gpio_line_set(IXDP2X00_GPIO_I2C_ENABLE, 1); | 302 | gpio_line_set(IXDP2X00_GPIO_I2C_ENABLE, 1); |
| 303 | gpio_line_config(IXDP2X00_GPIO_I2C_ENABLE, GPIO_OUT); | 303 | gpio_line_config(IXDP2X00_GPIO_I2C_ENABLE, GPIO_OUT); |
| 304 | 304 | ||
| 305 | platform_add_devices(ixdp2x00_devices, ARRAY_SIZE(ixdp2x00_devices)); | 305 | platform_add_devices(ixdp2x00_devices, ARRAY_SIZE(ixdp2x00_devices)); |
| 306 | ixp2000_uart_init(); | 306 | ixp2000_uart_init(); |
| 307 | } | 307 | } |
| 308 | 308 | ||
| 309 | 309 |
arch/arm/mach-ixp2000/ixdp2x01.c
| 1 | /* | 1 | /* |
| 2 | * arch/arm/mach-ixp2000/ixdp2x01.c | 2 | * arch/arm/mach-ixp2000/ixdp2x01.c |
| 3 | * | 3 | * |
| 4 | * Code common to Intel IXDP2401 and IXDP2801 platforms | 4 | * Code common to Intel IXDP2401 and IXDP2801 platforms |
| 5 | * | 5 | * |
| 6 | * Original Author: Andrzej Mialkowski <andrzej.mialkowski@intel.com> | 6 | * Original Author: Andrzej Mialkowski <andrzej.mialkowski@intel.com> |
| 7 | * Maintainer: Deepak Saxena <dsaxena@plexity.net> | 7 | * Maintainer: Deepak Saxena <dsaxena@plexity.net> |
| 8 | * | 8 | * |
| 9 | * Copyright (C) 2002-2003 Intel Corp. | 9 | * Copyright (C) 2002-2003 Intel Corp. |
| 10 | * Copyright (C) 2003-2004 MontaVista Software, Inc. | 10 | * Copyright (C) 2003-2004 MontaVista Software, Inc. |
| 11 | * | 11 | * |
| 12 | * This program is free software; you can redistribute it and/or modify it | 12 | * This program is free software; you can redistribute it and/or modify it |
| 13 | * under the terms of the GNU General Public License as published by the | 13 | * under the terms of the GNU General Public License as published by the |
| 14 | * Free Software Foundation; either version 2 of the License, or (at your | 14 | * Free Software Foundation; either version 2 of the License, or (at your |
| 15 | * option) any later version. | 15 | * option) any later version. |
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | #include <linux/config.h> | 18 | #include <linux/config.h> |
| 19 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
| 20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
| 21 | #include <linux/mm.h> | 21 | #include <linux/mm.h> |
| 22 | #include <linux/sched.h> | 22 | #include <linux/sched.h> |
| 23 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
| 24 | #include <linux/bitops.h> | 24 | #include <linux/bitops.h> |
| 25 | #include <linux/pci.h> | 25 | #include <linux/pci.h> |
| 26 | #include <linux/ioport.h> | 26 | #include <linux/ioport.h> |
| 27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
| 28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
| 29 | #include <linux/serial.h> | 29 | #include <linux/serial.h> |
| 30 | #include <linux/tty.h> | 30 | #include <linux/tty.h> |
| 31 | #include <linux/serial_core.h> | 31 | #include <linux/serial_core.h> |
| 32 | #include <linux/device.h> | 32 | #include <linux/device.h> |
| 33 | 33 | ||
| 34 | #include <asm/io.h> | 34 | #include <asm/io.h> |
| 35 | #include <asm/irq.h> | 35 | #include <asm/irq.h> |
| 36 | #include <asm/pgtable.h> | 36 | #include <asm/pgtable.h> |
| 37 | #include <asm/page.h> | 37 | #include <asm/page.h> |
| 38 | #include <asm/system.h> | 38 | #include <asm/system.h> |
| 39 | #include <asm/hardware.h> | 39 | #include <asm/hardware.h> |
| 40 | #include <asm/mach-types.h> | 40 | #include <asm/mach-types.h> |
| 41 | 41 | ||
| 42 | #include <asm/mach/pci.h> | 42 | #include <asm/mach/pci.h> |
| 43 | #include <asm/mach/map.h> | 43 | #include <asm/mach/map.h> |
| 44 | #include <asm/mach/irq.h> | 44 | #include <asm/mach/irq.h> |
| 45 | #include <asm/mach/time.h> | 45 | #include <asm/mach/time.h> |
| 46 | #include <asm/mach/arch.h> | 46 | #include <asm/mach/arch.h> |
| 47 | #include <asm/mach/flash.h> | 47 | #include <asm/mach/flash.h> |
| 48 | 48 | ||
| 49 | /************************************************************************* | 49 | /************************************************************************* |
| 50 | * IXDP2x01 IRQ Handling | 50 | * IXDP2x01 IRQ Handling |
| 51 | *************************************************************************/ | 51 | *************************************************************************/ |
| 52 | static void ixdp2x01_irq_mask(unsigned int irq) | 52 | static void ixdp2x01_irq_mask(unsigned int irq) |
| 53 | { | 53 | { |
| 54 | ixp2000_reg_write(IXDP2X01_INT_MASK_SET_REG, | 54 | ixp2000_reg_write(IXDP2X01_INT_MASK_SET_REG, |
| 55 | IXP2000_BOARD_IRQ_MASK(irq)); | 55 | IXP2000_BOARD_IRQ_MASK(irq)); |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | static void ixdp2x01_irq_unmask(unsigned int irq) | 58 | static void ixdp2x01_irq_unmask(unsigned int irq) |
| 59 | { | 59 | { |
| 60 | ixp2000_reg_write(IXDP2X01_INT_MASK_CLR_REG, | 60 | ixp2000_reg_write(IXDP2X01_INT_MASK_CLR_REG, |
| 61 | IXP2000_BOARD_IRQ_MASK(irq)); | 61 | IXP2000_BOARD_IRQ_MASK(irq)); |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | static u32 valid_irq_mask; | 64 | static u32 valid_irq_mask; |
| 65 | 65 | ||
| 66 | static void ixdp2x01_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) | 66 | static void ixdp2x01_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) |
| 67 | { | 67 | { |
| 68 | u32 ex_interrupt; | 68 | u32 ex_interrupt; |
| 69 | int i; | 69 | int i; |
| 70 | 70 | ||
| 71 | desc->chip->mask(irq); | 71 | desc->chip->mask(irq); |
| 72 | 72 | ||
| 73 | ex_interrupt = *IXDP2X01_INT_STAT_REG & valid_irq_mask; | 73 | ex_interrupt = *IXDP2X01_INT_STAT_REG & valid_irq_mask; |
| 74 | 74 | ||
| 75 | if (!ex_interrupt) { | 75 | if (!ex_interrupt) { |
| 76 | printk(KERN_ERR "Spurious IXDP2X01 CPLD interrupt!\n"); | 76 | printk(KERN_ERR "Spurious IXDP2X01 CPLD interrupt!\n"); |
| 77 | return; | 77 | return; |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | for (i = 0; i < IXP2000_BOARD_IRQS; i++) { | 80 | for (i = 0; i < IXP2000_BOARD_IRQS; i++) { |
| 81 | if (ex_interrupt & (1 << i)) { | 81 | if (ex_interrupt & (1 << i)) { |
| 82 | struct irqdesc *cpld_desc; | 82 | struct irqdesc *cpld_desc; |
| 83 | int cpld_irq = IXP2000_BOARD_IRQ(0) + i; | 83 | int cpld_irq = IXP2000_BOARD_IRQ(0) + i; |
| 84 | cpld_desc = irq_desc + cpld_irq; | 84 | cpld_desc = irq_desc + cpld_irq; |
| 85 | cpld_desc->handle(cpld_irq, cpld_desc, regs); | 85 | desc_handle_irq(cpld_irq, cpld_desc, regs); |
| 86 | } | 86 | } |
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | desc->chip->unmask(irq); | 89 | desc->chip->unmask(irq); |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | static struct irqchip ixdp2x01_irq_chip = { | 92 | static struct irqchip ixdp2x01_irq_chip = { |
| 93 | .mask = ixdp2x01_irq_mask, | 93 | .mask = ixdp2x01_irq_mask, |
| 94 | .ack = ixdp2x01_irq_mask, | 94 | .ack = ixdp2x01_irq_mask, |
| 95 | .unmask = ixdp2x01_irq_unmask | 95 | .unmask = ixdp2x01_irq_unmask |
| 96 | }; | 96 | }; |
| 97 | 97 | ||
| 98 | /* | 98 | /* |
| 99 | * We only do anything if we are the master NPU on the board. | 99 | * We only do anything if we are the master NPU on the board. |
| 100 | * The slave NPU only has the ethernet chip going directly to | 100 | * The slave NPU only has the ethernet chip going directly to |
| 101 | * the PCIB interrupt input. | 101 | * the PCIB interrupt input. |
| 102 | */ | 102 | */ |
| 103 | void __init ixdp2x01_init_irq(void) | 103 | void __init ixdp2x01_init_irq(void) |
| 104 | { | 104 | { |
| 105 | int irq = 0; | 105 | int irq = 0; |
| 106 | 106 | ||
| 107 | /* initialize chip specific interrupts */ | 107 | /* initialize chip specific interrupts */ |
| 108 | ixp2000_init_irq(); | 108 | ixp2000_init_irq(); |
| 109 | 109 | ||
| 110 | if (machine_is_ixdp2401()) | 110 | if (machine_is_ixdp2401()) |
| 111 | valid_irq_mask = IXDP2401_VALID_IRQ_MASK; | 111 | valid_irq_mask = IXDP2401_VALID_IRQ_MASK; |
| 112 | else | 112 | else |
| 113 | valid_irq_mask = IXDP2801_VALID_IRQ_MASK; | 113 | valid_irq_mask = IXDP2801_VALID_IRQ_MASK; |
| 114 | 114 | ||
| 115 | /* Mask all interrupts from CPLD, disable simulation */ | 115 | /* Mask all interrupts from CPLD, disable simulation */ |
| 116 | ixp2000_reg_write(IXDP2X01_INT_MASK_SET_REG, 0xffffffff); | 116 | ixp2000_reg_write(IXDP2X01_INT_MASK_SET_REG, 0xffffffff); |
| 117 | ixp2000_reg_write(IXDP2X01_INT_SIM_REG, 0); | 117 | ixp2000_reg_write(IXDP2X01_INT_SIM_REG, 0); |
| 118 | 118 | ||
| 119 | for (irq = NR_IXP2000_IRQS; irq < NR_IXDP2X01_IRQS; irq++) { | 119 | for (irq = NR_IXP2000_IRQS; irq < NR_IXDP2X01_IRQS; irq++) { |
| 120 | if (irq & valid_irq_mask) { | 120 | if (irq & valid_irq_mask) { |
| 121 | set_irq_chip(irq, &ixdp2x01_irq_chip); | 121 | set_irq_chip(irq, &ixdp2x01_irq_chip); |
| 122 | set_irq_handler(irq, do_level_IRQ); | 122 | set_irq_handler(irq, do_level_IRQ); |
| 123 | set_irq_flags(irq, IRQF_VALID); | 123 | set_irq_flags(irq, IRQF_VALID); |
| 124 | } else { | 124 | } else { |
| 125 | set_irq_flags(irq, 0); | 125 | set_irq_flags(irq, 0); |
| 126 | } | 126 | } |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | /* Hook into PCI interrupts */ | 129 | /* Hook into PCI interrupts */ |
| 130 | set_irq_chained_handler(IRQ_IXP2000_PCIB, &ixdp2x01_irq_handler); | 130 | set_irq_chained_handler(IRQ_IXP2000_PCIB, &ixdp2x01_irq_handler); |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | 133 | ||
| 134 | /************************************************************************* | 134 | /************************************************************************* |
| 135 | * IXDP2x01 memory map and serial ports | 135 | * IXDP2x01 memory map and serial ports |
| 136 | *************************************************************************/ | 136 | *************************************************************************/ |
| 137 | static struct map_desc ixdp2x01_io_desc __initdata = { | 137 | static struct map_desc ixdp2x01_io_desc __initdata = { |
| 138 | .virtual = IXDP2X01_VIRT_CPLD_BASE, | 138 | .virtual = IXDP2X01_VIRT_CPLD_BASE, |
| 139 | .physical = IXDP2X01_PHYS_CPLD_BASE, | 139 | .physical = IXDP2X01_PHYS_CPLD_BASE, |
| 140 | .length = IXDP2X01_CPLD_REGION_SIZE, | 140 | .length = IXDP2X01_CPLD_REGION_SIZE, |
| 141 | .type = MT_DEVICE | 141 | .type = MT_DEVICE |
| 142 | }; | 142 | }; |
| 143 | 143 | ||
| 144 | static struct uart_port ixdp2x01_serial_ports[2] = { | 144 | static struct uart_port ixdp2x01_serial_ports[2] = { |
| 145 | { | 145 | { |
| 146 | .membase = (char *)(IXDP2X01_UART1_VIRT_BASE), | 146 | .membase = (char *)(IXDP2X01_UART1_VIRT_BASE), |
| 147 | .mapbase = (unsigned long)IXDP2X01_UART1_PHYS_BASE, | 147 | .mapbase = (unsigned long)IXDP2X01_UART1_PHYS_BASE, |
| 148 | .irq = IRQ_IXDP2X01_UART1, | 148 | .irq = IRQ_IXDP2X01_UART1, |
| 149 | .flags = UPF_SKIP_TEST, | 149 | .flags = UPF_SKIP_TEST, |
| 150 | .iotype = UPIO_MEM32, | 150 | .iotype = UPIO_MEM32, |
| 151 | .regshift = 2, | 151 | .regshift = 2, |
| 152 | .uartclk = IXDP2X01_UART_CLK, | 152 | .uartclk = IXDP2X01_UART_CLK, |
| 153 | .line = 1, | 153 | .line = 1, |
| 154 | .type = PORT_16550A, | 154 | .type = PORT_16550A, |
| 155 | .fifosize = 16 | 155 | .fifosize = 16 |
| 156 | }, { | 156 | }, { |
| 157 | .membase = (char *)(IXDP2X01_UART2_VIRT_BASE), | 157 | .membase = (char *)(IXDP2X01_UART2_VIRT_BASE), |
| 158 | .mapbase = (unsigned long)IXDP2X01_UART2_PHYS_BASE, | 158 | .mapbase = (unsigned long)IXDP2X01_UART2_PHYS_BASE, |
| 159 | .irq = IRQ_IXDP2X01_UART2, | 159 | .irq = IRQ_IXDP2X01_UART2, |
| 160 | .flags = UPF_SKIP_TEST, | 160 | .flags = UPF_SKIP_TEST, |
| 161 | .iotype = UPIO_MEM32, | 161 | .iotype = UPIO_MEM32, |
| 162 | .regshift = 2, | 162 | .regshift = 2, |
| 163 | .uartclk = IXDP2X01_UART_CLK, | 163 | .uartclk = IXDP2X01_UART_CLK, |
| 164 | .line = 2, | 164 | .line = 2, |
| 165 | .type = PORT_16550A, | 165 | .type = PORT_16550A, |
| 166 | .fifosize = 16 | 166 | .fifosize = 16 |
| 167 | }, | 167 | }, |
| 168 | }; | 168 | }; |
| 169 | 169 | ||
| 170 | static void __init ixdp2x01_map_io(void) | 170 | static void __init ixdp2x01_map_io(void) |
| 171 | { | 171 | { |
| 172 | ixp2000_map_io(); | 172 | ixp2000_map_io(); |
| 173 | 173 | ||
| 174 | iotable_init(&ixdp2x01_io_desc, 1); | 174 | iotable_init(&ixdp2x01_io_desc, 1); |
| 175 | 175 | ||
| 176 | early_serial_setup(&ixdp2x01_serial_ports[0]); | 176 | early_serial_setup(&ixdp2x01_serial_ports[0]); |
| 177 | early_serial_setup(&ixdp2x01_serial_ports[1]); | 177 | early_serial_setup(&ixdp2x01_serial_ports[1]); |
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | 180 | ||
| 181 | /************************************************************************* | 181 | /************************************************************************* |
| 182 | * IXDP2x01 timer tick configuration | 182 | * IXDP2x01 timer tick configuration |
| 183 | *************************************************************************/ | 183 | *************************************************************************/ |
| 184 | static unsigned int ixdp2x01_clock; | 184 | static unsigned int ixdp2x01_clock; |
| 185 | 185 | ||
| 186 | static int __init ixdp2x01_clock_setup(char *str) | 186 | static int __init ixdp2x01_clock_setup(char *str) |
| 187 | { | 187 | { |
| 188 | ixdp2x01_clock = simple_strtoul(str, NULL, 10); | 188 | ixdp2x01_clock = simple_strtoul(str, NULL, 10); |
| 189 | 189 | ||
| 190 | return 1; | 190 | return 1; |
| 191 | } | 191 | } |
| 192 | 192 | ||
| 193 | __setup("ixdp2x01_clock=", ixdp2x01_clock_setup); | 193 | __setup("ixdp2x01_clock=", ixdp2x01_clock_setup); |
| 194 | 194 | ||
| 195 | static void __init ixdp2x01_timer_init(void) | 195 | static void __init ixdp2x01_timer_init(void) |
| 196 | { | 196 | { |
| 197 | if (!ixdp2x01_clock) | 197 | if (!ixdp2x01_clock) |
| 198 | ixdp2x01_clock = 50000000; | 198 | ixdp2x01_clock = 50000000; |
| 199 | 199 | ||
| 200 | ixp2000_init_time(ixdp2x01_clock); | 200 | ixp2000_init_time(ixdp2x01_clock); |
| 201 | } | 201 | } |
| 202 | 202 | ||
| 203 | static struct sys_timer ixdp2x01_timer = { | 203 | static struct sys_timer ixdp2x01_timer = { |
| 204 | .init = ixdp2x01_timer_init, | 204 | .init = ixdp2x01_timer_init, |
| 205 | .offset = ixp2000_gettimeoffset, | 205 | .offset = ixp2000_gettimeoffset, |
| 206 | }; | 206 | }; |
| 207 | 207 | ||
| 208 | /************************************************************************* | 208 | /************************************************************************* |
| 209 | * IXDP2x01 PCI | 209 | * IXDP2x01 PCI |
| 210 | *************************************************************************/ | 210 | *************************************************************************/ |
| 211 | void __init ixdp2x01_pci_preinit(void) | 211 | void __init ixdp2x01_pci_preinit(void) |
| 212 | { | 212 | { |
| 213 | ixp2000_reg_write(IXP2000_PCI_ADDR_EXT, 0x00000000); | 213 | ixp2000_reg_write(IXP2000_PCI_ADDR_EXT, 0x00000000); |
| 214 | ixp2000_pci_preinit(); | 214 | ixp2000_pci_preinit(); |
| 215 | } | 215 | } |
| 216 | 216 | ||
| 217 | #define DEVPIN(dev, pin) ((pin) | ((dev) << 3)) | 217 | #define DEVPIN(dev, pin) ((pin) | ((dev) << 3)) |
| 218 | 218 | ||
| 219 | static int __init ixdp2x01_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) | 219 | static int __init ixdp2x01_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) |
| 220 | { | 220 | { |
| 221 | u8 bus = dev->bus->number; | 221 | u8 bus = dev->bus->number; |
| 222 | u32 devpin = DEVPIN(PCI_SLOT(dev->devfn), pin); | 222 | u32 devpin = DEVPIN(PCI_SLOT(dev->devfn), pin); |
| 223 | struct pci_bus *tmp_bus = dev->bus; | 223 | struct pci_bus *tmp_bus = dev->bus; |
| 224 | 224 | ||
| 225 | /* Primary bus, no interrupts here */ | 225 | /* Primary bus, no interrupts here */ |
| 226 | if (bus == 0) { | 226 | if (bus == 0) { |
| 227 | return -1; | 227 | return -1; |
| 228 | } | 228 | } |
| 229 | 229 | ||
| 230 | /* Lookup first leaf in bus tree */ | 230 | /* Lookup first leaf in bus tree */ |
| 231 | while ((tmp_bus->parent != NULL) && (tmp_bus->parent->parent != NULL)) { | 231 | while ((tmp_bus->parent != NULL) && (tmp_bus->parent->parent != NULL)) { |
| 232 | tmp_bus = tmp_bus->parent; | 232 | tmp_bus = tmp_bus->parent; |
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | /* Select between known bridges */ | 235 | /* Select between known bridges */ |
| 236 | switch (tmp_bus->self->devfn | (tmp_bus->self->bus->number << 8)) { | 236 | switch (tmp_bus->self->devfn | (tmp_bus->self->bus->number << 8)) { |
| 237 | /* Device is located after first MB bridge */ | 237 | /* Device is located after first MB bridge */ |
| 238 | case 0x0008: | 238 | case 0x0008: |
| 239 | if (tmp_bus == dev->bus) { | 239 | if (tmp_bus == dev->bus) { |
| 240 | /* Device is located directy after first MB bridge */ | 240 | /* Device is located directy after first MB bridge */ |
| 241 | switch (devpin) { | 241 | switch (devpin) { |
| 242 | case DEVPIN(1, 1): /* Onboard 82546 ch 0 */ | 242 | case DEVPIN(1, 1): /* Onboard 82546 ch 0 */ |
| 243 | if (machine_is_ixdp2401()) | 243 | if (machine_is_ixdp2401()) |
| 244 | return IRQ_IXDP2401_INTA_82546; | 244 | return IRQ_IXDP2401_INTA_82546; |
| 245 | return -1; | 245 | return -1; |
| 246 | case DEVPIN(1, 2): /* Onboard 82546 ch 1 */ | 246 | case DEVPIN(1, 2): /* Onboard 82546 ch 1 */ |
| 247 | if (machine_is_ixdp2401()) | 247 | if (machine_is_ixdp2401()) |
| 248 | return IRQ_IXDP2401_INTB_82546; | 248 | return IRQ_IXDP2401_INTB_82546; |
| 249 | return -1; | 249 | return -1; |
| 250 | case DEVPIN(0, 1): /* PMC INTA# */ | 250 | case DEVPIN(0, 1): /* PMC INTA# */ |
| 251 | return IRQ_IXDP2X01_SPCI_PMC_INTA; | 251 | return IRQ_IXDP2X01_SPCI_PMC_INTA; |
| 252 | case DEVPIN(0, 2): /* PMC INTB# */ | 252 | case DEVPIN(0, 2): /* PMC INTB# */ |
| 253 | return IRQ_IXDP2X01_SPCI_PMC_INTB; | 253 | return IRQ_IXDP2X01_SPCI_PMC_INTB; |
| 254 | case DEVPIN(0, 3): /* PMC INTC# */ | 254 | case DEVPIN(0, 3): /* PMC INTC# */ |
| 255 | return IRQ_IXDP2X01_SPCI_PMC_INTC; | 255 | return IRQ_IXDP2X01_SPCI_PMC_INTC; |
| 256 | case DEVPIN(0, 4): /* PMC INTD# */ | 256 | case DEVPIN(0, 4): /* PMC INTD# */ |
| 257 | return IRQ_IXDP2X01_SPCI_PMC_INTD; | 257 | return IRQ_IXDP2X01_SPCI_PMC_INTD; |
| 258 | } | 258 | } |
| 259 | } | 259 | } |
| 260 | break; | 260 | break; |
| 261 | case 0x0010: | 261 | case 0x0010: |
| 262 | if (tmp_bus == dev->bus) { | 262 | if (tmp_bus == dev->bus) { |
| 263 | /* Device is located directy after second MB bridge */ | 263 | /* Device is located directy after second MB bridge */ |
| 264 | /* Secondary bus of second bridge */ | 264 | /* Secondary bus of second bridge */ |
| 265 | switch (devpin) { | 265 | switch (devpin) { |
| 266 | case DEVPIN(0, 1): /* DB#0 */ | 266 | case DEVPIN(0, 1): /* DB#0 */ |
| 267 | return IRQ_IXDP2X01_SPCI_DB_0; | 267 | return IRQ_IXDP2X01_SPCI_DB_0; |
| 268 | case DEVPIN(1, 1): /* DB#1 */ | 268 | case DEVPIN(1, 1): /* DB#1 */ |
| 269 | return IRQ_IXDP2X01_SPCI_DB_1; | 269 | return IRQ_IXDP2X01_SPCI_DB_1; |
| 270 | } | 270 | } |
| 271 | } else { | 271 | } else { |
| 272 | /* Device is located indirectly after second MB bridge */ | 272 | /* Device is located indirectly after second MB bridge */ |
| 273 | /* Not supported now */ | 273 | /* Not supported now */ |
| 274 | } | 274 | } |
| 275 | break; | 275 | break; |
| 276 | } | 276 | } |
| 277 | 277 | ||
| 278 | return -1; | 278 | return -1; |
| 279 | } | 279 | } |
| 280 | 280 | ||
| 281 | 281 | ||
| 282 | static int ixdp2x01_pci_setup(int nr, struct pci_sys_data *sys) | 282 | static int ixdp2x01_pci_setup(int nr, struct pci_sys_data *sys) |
| 283 | { | 283 | { |
| 284 | sys->mem_offset = 0xe0000000; | 284 | sys->mem_offset = 0xe0000000; |
| 285 | 285 | ||
| 286 | if (machine_is_ixdp2801()) | 286 | if (machine_is_ixdp2801()) |
| 287 | sys->mem_offset -= ((*IXP2000_PCI_ADDR_EXT & 0xE000) << 16); | 287 | sys->mem_offset -= ((*IXP2000_PCI_ADDR_EXT & 0xE000) << 16); |
| 288 | 288 | ||
| 289 | return ixp2000_pci_setup(nr, sys); | 289 | return ixp2000_pci_setup(nr, sys); |
| 290 | } | 290 | } |
| 291 | 291 | ||
| 292 | struct hw_pci ixdp2x01_pci __initdata = { | 292 | struct hw_pci ixdp2x01_pci __initdata = { |
| 293 | .nr_controllers = 1, | 293 | .nr_controllers = 1, |
| 294 | .setup = ixdp2x01_pci_setup, | 294 | .setup = ixdp2x01_pci_setup, |
| 295 | .preinit = ixdp2x01_pci_preinit, | 295 | .preinit = ixdp2x01_pci_preinit, |
| 296 | .scan = ixp2000_pci_scan_bus, | 296 | .scan = ixp2000_pci_scan_bus, |
| 297 | .map_irq = ixdp2x01_pci_map_irq, | 297 | .map_irq = ixdp2x01_pci_map_irq, |
| 298 | }; | 298 | }; |
| 299 | 299 | ||
| 300 | int __init ixdp2x01_pci_init(void) | 300 | int __init ixdp2x01_pci_init(void) |
| 301 | { | 301 | { |
| 302 | 302 | ||
| 303 | pci_common_init(&ixdp2x01_pci); | 303 | pci_common_init(&ixdp2x01_pci); |
| 304 | return 0; | 304 | return 0; |
| 305 | } | 305 | } |
| 306 | 306 | ||
| 307 | subsys_initcall(ixdp2x01_pci_init); | 307 | subsys_initcall(ixdp2x01_pci_init); |
| 308 | 308 | ||
| 309 | /************************************************************************* | 309 | /************************************************************************* |
| 310 | * IXDP2x01 Machine Intialization | 310 | * IXDP2x01 Machine Intialization |
| 311 | *************************************************************************/ | 311 | *************************************************************************/ |
| 312 | static struct flash_platform_data ixdp2x01_flash_platform_data = { | 312 | static struct flash_platform_data ixdp2x01_flash_platform_data = { |
| 313 | .map_name = "cfi_probe", | 313 | .map_name = "cfi_probe", |
| 314 | .width = 1, | 314 | .width = 1, |
| 315 | }; | 315 | }; |
| 316 | 316 | ||
| 317 | static unsigned long ixdp2x01_flash_bank_setup(unsigned long ofs) | 317 | static unsigned long ixdp2x01_flash_bank_setup(unsigned long ofs) |
| 318 | { | 318 | { |
| 319 | ixp2000_reg_write(IXDP2X01_CPLD_FLASH_REG, | 319 | ixp2000_reg_write(IXDP2X01_CPLD_FLASH_REG, |
| 320 | ((ofs >> IXDP2X01_FLASH_WINDOW_BITS) | IXDP2X01_CPLD_FLASH_INTERN)); | 320 | ((ofs >> IXDP2X01_FLASH_WINDOW_BITS) | IXDP2X01_CPLD_FLASH_INTERN)); |
| 321 | return (ofs & IXDP2X01_FLASH_WINDOW_MASK); | 321 | return (ofs & IXDP2X01_FLASH_WINDOW_MASK); |
| 322 | } | 322 | } |
| 323 | 323 | ||
| 324 | static struct ixp2000_flash_data ixdp2x01_flash_data = { | 324 | static struct ixp2000_flash_data ixdp2x01_flash_data = { |
| 325 | .platform_data = &ixdp2x01_flash_platform_data, | 325 | .platform_data = &ixdp2x01_flash_platform_data, |
| 326 | .bank_setup = ixdp2x01_flash_bank_setup | 326 | .bank_setup = ixdp2x01_flash_bank_setup |
| 327 | }; | 327 | }; |
| 328 | 328 | ||
| 329 | static struct resource ixdp2x01_flash_resource = { | 329 | static struct resource ixdp2x01_flash_resource = { |
| 330 | .start = 0xc4000000, | 330 | .start = 0xc4000000, |
| 331 | .end = 0xc4000000 + 0x01ffffff, | 331 | .end = 0xc4000000 + 0x01ffffff, |
| 332 | .flags = IORESOURCE_MEM, | 332 | .flags = IORESOURCE_MEM, |
| 333 | }; | 333 | }; |
| 334 | 334 | ||
| 335 | static struct platform_device ixdp2x01_flash = { | 335 | static struct platform_device ixdp2x01_flash = { |
| 336 | .name = "IXP2000-Flash", | 336 | .name = "IXP2000-Flash", |
| 337 | .id = 0, | 337 | .id = 0, |
| 338 | .dev = { | 338 | .dev = { |
| 339 | .platform_data = &ixdp2x01_flash_data, | 339 | .platform_data = &ixdp2x01_flash_data, |
| 340 | }, | 340 | }, |
| 341 | .num_resources = 1, | 341 | .num_resources = 1, |
| 342 | .resource = &ixdp2x01_flash_resource, | 342 | .resource = &ixdp2x01_flash_resource, |
| 343 | }; | 343 | }; |
| 344 | 344 | ||
| 345 | static struct ixp2000_i2c_pins ixdp2x01_i2c_gpio_pins = { | 345 | static struct ixp2000_i2c_pins ixdp2x01_i2c_gpio_pins = { |
| 346 | .sda_pin = IXDP2X01_GPIO_SDA, | 346 | .sda_pin = IXDP2X01_GPIO_SDA, |
| 347 | .scl_pin = IXDP2X01_GPIO_SCL, | 347 | .scl_pin = IXDP2X01_GPIO_SCL, |
| 348 | }; | 348 | }; |
| 349 | 349 | ||
| 350 | static struct platform_device ixdp2x01_i2c_controller = { | 350 | static struct platform_device ixdp2x01_i2c_controller = { |
| 351 | .name = "IXP2000-I2C", | 351 | .name = "IXP2000-I2C", |
| 352 | .id = 0, | 352 | .id = 0, |
| 353 | .dev = { | 353 | .dev = { |
| 354 | .platform_data = &ixdp2x01_i2c_gpio_pins, | 354 | .platform_data = &ixdp2x01_i2c_gpio_pins, |
| 355 | }, | 355 | }, |
| 356 | .num_resources = 0 | 356 | .num_resources = 0 |
| 357 | }; | 357 | }; |
| 358 | 358 | ||
| 359 | static struct platform_device *ixdp2x01_devices[] __initdata = { | 359 | static struct platform_device *ixdp2x01_devices[] __initdata = { |
| 360 | &ixdp2x01_flash, | 360 | &ixdp2x01_flash, |
| 361 | &ixdp2x01_i2c_controller | 361 | &ixdp2x01_i2c_controller |
| 362 | }; | 362 | }; |
| 363 | 363 | ||
| 364 | static void __init ixdp2x01_init_machine(void) | 364 | static void __init ixdp2x01_init_machine(void) |
| 365 | { | 365 | { |
| 366 | ixp2000_reg_write(IXDP2X01_CPLD_FLASH_REG, | 366 | ixp2000_reg_write(IXDP2X01_CPLD_FLASH_REG, |
| 367 | (IXDP2X01_CPLD_FLASH_BANK_MASK | IXDP2X01_CPLD_FLASH_INTERN)); | 367 | (IXDP2X01_CPLD_FLASH_BANK_MASK | IXDP2X01_CPLD_FLASH_INTERN)); |
| 368 | 368 | ||
| 369 | ixdp2x01_flash_data.nr_banks = | 369 | ixdp2x01_flash_data.nr_banks = |
| 370 | ((*IXDP2X01_CPLD_FLASH_REG & IXDP2X01_CPLD_FLASH_BANK_MASK) + 1); | 370 | ((*IXDP2X01_CPLD_FLASH_REG & IXDP2X01_CPLD_FLASH_BANK_MASK) + 1); |
| 371 | 371 | ||
| 372 | platform_add_devices(ixdp2x01_devices, ARRAY_SIZE(ixdp2x01_devices)); | 372 | platform_add_devices(ixdp2x01_devices, ARRAY_SIZE(ixdp2x01_devices)); |
| 373 | ixp2000_uart_init(); | 373 | ixp2000_uart_init(); |
| 374 | } | 374 | } |
| 375 | 375 | ||
| 376 | 376 | ||
| 377 | #ifdef CONFIG_ARCH_IXDP2401 | 377 | #ifdef CONFIG_ARCH_IXDP2401 |
| 378 | MACHINE_START(IXDP2401, "Intel IXDP2401 Development Platform") | 378 | MACHINE_START(IXDP2401, "Intel IXDP2401 Development Platform") |
| 379 | /* Maintainer: MontaVista Software, Inc. */ | 379 | /* Maintainer: MontaVista Software, Inc. */ |
| 380 | .phys_ram = 0x00000000, | 380 | .phys_ram = 0x00000000, |
| 381 | .phys_io = IXP2000_UART_PHYS_BASE, | 381 | .phys_io = IXP2000_UART_PHYS_BASE, |
| 382 | .io_pg_offst = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc, | 382 | .io_pg_offst = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc, |
| 383 | .boot_params = 0x00000100, | 383 | .boot_params = 0x00000100, |
| 384 | .map_io = ixdp2x01_map_io, | 384 | .map_io = ixdp2x01_map_io, |
| 385 | .init_irq = ixdp2x01_init_irq, | 385 | .init_irq = ixdp2x01_init_irq, |
| 386 | .timer = &ixdp2x01_timer, | 386 | .timer = &ixdp2x01_timer, |
| 387 | .init_machine = ixdp2x01_init_machine, | 387 | .init_machine = ixdp2x01_init_machine, |
| 388 | MACHINE_END | 388 | MACHINE_END |
| 389 | #endif | 389 | #endif |
| 390 | 390 | ||
| 391 | #ifdef CONFIG_ARCH_IXDP2801 | 391 | #ifdef CONFIG_ARCH_IXDP2801 |
| 392 | MACHINE_START(IXDP2801, "Intel IXDP2801 Development Platform") | 392 | MACHINE_START(IXDP2801, "Intel IXDP2801 Development Platform") |
| 393 | /* Maintainer: MontaVista Software, Inc. */ | 393 | /* Maintainer: MontaVista Software, Inc. */ |
| 394 | .phys_ram = 0x00000000, | 394 | .phys_ram = 0x00000000, |
| 395 | .phys_io = IXP2000_UART_PHYS_BASE, | 395 | .phys_io = IXP2000_UART_PHYS_BASE, |
| 396 | .io_pg_offst = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc, | 396 | .io_pg_offst = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc, |
| 397 | .boot_params = 0x00000100, | 397 | .boot_params = 0x00000100, |
| 398 | .map_io = ixdp2x01_map_io, | 398 | .map_io = ixdp2x01_map_io, |
| 399 | .init_irq = ixdp2x01_init_irq, | 399 | .init_irq = ixdp2x01_init_irq, |
| 400 | .timer = &ixdp2x01_timer, | 400 | .timer = &ixdp2x01_timer, |
| 401 | .init_machine = ixdp2x01_init_machine, | 401 | .init_machine = ixdp2x01_init_machine, |
| 402 | MACHINE_END | 402 | MACHINE_END |
| 403 | #endif | 403 | #endif |
| 404 | 404 | ||
| 405 | 405 | ||
| 406 | 406 |
arch/arm/mach-lh7a40x/common.h
| 1 | /* arch/arm/mach-lh7a40x/common.h | 1 | /* arch/arm/mach-lh7a40x/common.h |
| 2 | * | 2 | * |
| 3 | * Copyright (C) 2004 Marc Singer | 3 | * Copyright (C) 2004 Marc Singer |
| 4 | * | 4 | * |
| 5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
| 6 | * modify it under the terms of the GNU General Public License | 6 | * modify it under the terms of the GNU General Public License |
| 7 | * version 2 as published by the Free Software Foundation. | 7 | * version 2 as published by the Free Software Foundation. |
| 8 | * | 8 | * |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | extern struct sys_timer lh7a40x_timer; | 11 | extern struct sys_timer lh7a40x_timer; |
| 12 | 12 | ||
| 13 | extern void lh7a400_init_irq (void); | 13 | extern void lh7a400_init_irq (void); |
| 14 | extern void lh7a404_init_irq (void); | 14 | extern void lh7a404_init_irq (void); |
| 15 | 15 | ||
| 16 | #define IRQ_DISPATCH(irq) irq_desc[irq].handle ((irq), &irq_desc[irq], regs) | 16 | #define IRQ_DISPATCH(irq) desc_handle_irq((irq),(irq_desc + irq), regs) |
| 17 | 17 |
arch/arm/mach-omap1/fpga.c
| 1 | /* | 1 | /* |
| 2 | * linux/arch/arm/mach-omap/fpga.c | 2 | * linux/arch/arm/mach-omap/fpga.c |
| 3 | * | 3 | * |
| 4 | * Interrupt handler for OMAP-1510 Innovator FPGA | 4 | * Interrupt handler for OMAP-1510 Innovator FPGA |
| 5 | * | 5 | * |
| 6 | * Copyright (C) 2001 RidgeRun, Inc. | 6 | * Copyright (C) 2001 RidgeRun, Inc. |
| 7 | * Author: Greg Lonnon <glonnon@ridgerun.com> | 7 | * Author: Greg Lonnon <glonnon@ridgerun.com> |
| 8 | * | 8 | * |
| 9 | * Copyright (C) 2002 MontaVista Software, Inc. | 9 | * Copyright (C) 2002 MontaVista Software, Inc. |
| 10 | * | 10 | * |
| 11 | * Separated FPGA interrupts from innovator1510.c and cleaned up for 2.6 | 11 | * Separated FPGA interrupts from innovator1510.c and cleaned up for 2.6 |
| 12 | * Copyright (C) 2004 Nokia Corporation by Tony Lindrgen <tony@atomide.com> | 12 | * Copyright (C) 2004 Nokia Corporation by Tony Lindrgen <tony@atomide.com> |
| 13 | * | 13 | * |
| 14 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
| 15 | * it under the terms of the GNU General Public License version 2 as | 15 | * it under the terms of the GNU General Public License version 2 as |
| 16 | * published by the Free Software Foundation. | 16 | * published by the Free Software Foundation. |
| 17 | */ | 17 | */ |
| 18 | 18 | ||
| 19 | #include <linux/config.h> | 19 | #include <linux/config.h> |
| 20 | #include <linux/types.h> | 20 | #include <linux/types.h> |
| 21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
| 22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
| 23 | #include <linux/device.h> | 23 | #include <linux/device.h> |
| 24 | #include <linux/errno.h> | 24 | #include <linux/errno.h> |
| 25 | 25 | ||
| 26 | #include <asm/hardware.h> | 26 | #include <asm/hardware.h> |
| 27 | #include <asm/io.h> | 27 | #include <asm/io.h> |
| 28 | #include <asm/irq.h> | 28 | #include <asm/irq.h> |
| 29 | #include <asm/mach/irq.h> | 29 | #include <asm/mach/irq.h> |
| 30 | 30 | ||
| 31 | #include <asm/arch/fpga.h> | 31 | #include <asm/arch/fpga.h> |
| 32 | #include <asm/arch/gpio.h> | 32 | #include <asm/arch/gpio.h> |
| 33 | 33 | ||
| 34 | static void fpga_mask_irq(unsigned int irq) | 34 | static void fpga_mask_irq(unsigned int irq) |
| 35 | { | 35 | { |
| 36 | irq -= OMAP1510_IH_FPGA_BASE; | 36 | irq -= OMAP1510_IH_FPGA_BASE; |
| 37 | 37 | ||
| 38 | if (irq < 8) | 38 | if (irq < 8) |
| 39 | __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO) | 39 | __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO) |
| 40 | & ~(1 << irq)), OMAP1510_FPGA_IMR_LO); | 40 | & ~(1 << irq)), OMAP1510_FPGA_IMR_LO); |
| 41 | else if (irq < 16) | 41 | else if (irq < 16) |
| 42 | __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_HI) | 42 | __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_HI) |
| 43 | & ~(1 << (irq - 8))), OMAP1510_FPGA_IMR_HI); | 43 | & ~(1 << (irq - 8))), OMAP1510_FPGA_IMR_HI); |
| 44 | else | 44 | else |
| 45 | __raw_writeb((__raw_readb(INNOVATOR_FPGA_IMR2) | 45 | __raw_writeb((__raw_readb(INNOVATOR_FPGA_IMR2) |
| 46 | & ~(1 << (irq - 16))), INNOVATOR_FPGA_IMR2); | 46 | & ~(1 << (irq - 16))), INNOVATOR_FPGA_IMR2); |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | 49 | ||
| 50 | static inline u32 get_fpga_unmasked_irqs(void) | 50 | static inline u32 get_fpga_unmasked_irqs(void) |
| 51 | { | 51 | { |
| 52 | return | 52 | return |
| 53 | ((__raw_readb(OMAP1510_FPGA_ISR_LO) & | 53 | ((__raw_readb(OMAP1510_FPGA_ISR_LO) & |
| 54 | __raw_readb(OMAP1510_FPGA_IMR_LO))) | | 54 | __raw_readb(OMAP1510_FPGA_IMR_LO))) | |
| 55 | ((__raw_readb(OMAP1510_FPGA_ISR_HI) & | 55 | ((__raw_readb(OMAP1510_FPGA_ISR_HI) & |
| 56 | __raw_readb(OMAP1510_FPGA_IMR_HI)) << 8) | | 56 | __raw_readb(OMAP1510_FPGA_IMR_HI)) << 8) | |
| 57 | ((__raw_readb(INNOVATOR_FPGA_ISR2) & | 57 | ((__raw_readb(INNOVATOR_FPGA_ISR2) & |
| 58 | __raw_readb(INNOVATOR_FPGA_IMR2)) << 16); | 58 | __raw_readb(INNOVATOR_FPGA_IMR2)) << 16); |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | 61 | ||
| 62 | static void fpga_ack_irq(unsigned int irq) | 62 | static void fpga_ack_irq(unsigned int irq) |
| 63 | { | 63 | { |
| 64 | /* Don't need to explicitly ACK FPGA interrupts */ | 64 | /* Don't need to explicitly ACK FPGA interrupts */ |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | static void fpga_unmask_irq(unsigned int irq) | 67 | static void fpga_unmask_irq(unsigned int irq) |
| 68 | { | 68 | { |
| 69 | irq -= OMAP1510_IH_FPGA_BASE; | 69 | irq -= OMAP1510_IH_FPGA_BASE; |
| 70 | 70 | ||
| 71 | if (irq < 8) | 71 | if (irq < 8) |
| 72 | __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO) | (1 << irq)), | 72 | __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO) | (1 << irq)), |
| 73 | OMAP1510_FPGA_IMR_LO); | 73 | OMAP1510_FPGA_IMR_LO); |
| 74 | else if (irq < 16) | 74 | else if (irq < 16) |
| 75 | __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_HI) | 75 | __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_HI) |
| 76 | | (1 << (irq - 8))), OMAP1510_FPGA_IMR_HI); | 76 | | (1 << (irq - 8))), OMAP1510_FPGA_IMR_HI); |
| 77 | else | 77 | else |
| 78 | __raw_writeb((__raw_readb(INNOVATOR_FPGA_IMR2) | 78 | __raw_writeb((__raw_readb(INNOVATOR_FPGA_IMR2) |
| 79 | | (1 << (irq - 16))), INNOVATOR_FPGA_IMR2); | 79 | | (1 << (irq - 16))), INNOVATOR_FPGA_IMR2); |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | static void fpga_mask_ack_irq(unsigned int irq) | 82 | static void fpga_mask_ack_irq(unsigned int irq) |
| 83 | { | 83 | { |
| 84 | fpga_mask_irq(irq); | 84 | fpga_mask_irq(irq); |
| 85 | fpga_ack_irq(irq); | 85 | fpga_ack_irq(irq); |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | void innovator_fpga_IRQ_demux(unsigned int irq, struct irqdesc *desc, | 88 | void innovator_fpga_IRQ_demux(unsigned int irq, struct irqdesc *desc, |
| 89 | struct pt_regs *regs) | 89 | struct pt_regs *regs) |
| 90 | { | 90 | { |
| 91 | struct irqdesc *d; | 91 | struct irqdesc *d; |
| 92 | u32 stat; | 92 | u32 stat; |
| 93 | int fpga_irq; | 93 | int fpga_irq; |
| 94 | 94 | ||
| 95 | stat = get_fpga_unmasked_irqs(); | 95 | stat = get_fpga_unmasked_irqs(); |
| 96 | 96 | ||
| 97 | if (!stat) | 97 | if (!stat) |
| 98 | return; | 98 | return; |
| 99 | 99 | ||
| 100 | for (fpga_irq = OMAP1510_IH_FPGA_BASE; | 100 | for (fpga_irq = OMAP1510_IH_FPGA_BASE; |
| 101 | (fpga_irq < (OMAP1510_IH_FPGA_BASE + NR_FPGA_IRQS)) && stat; | 101 | (fpga_irq < (OMAP1510_IH_FPGA_BASE + NR_FPGA_IRQS)) && stat; |
| 102 | fpga_irq++, stat >>= 1) { | 102 | fpga_irq++, stat >>= 1) { |
| 103 | if (stat & 1) { | 103 | if (stat & 1) { |
| 104 | d = irq_desc + fpga_irq; | 104 | d = irq_desc + fpga_irq; |
| 105 | d->handle(fpga_irq, d, regs); | 105 | desc_handle_irq(fpga_irq, d, regs); |
| 106 | } | 106 | } |
| 107 | } | 107 | } |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | static struct irqchip omap_fpga_irq_ack = { | 110 | static struct irqchip omap_fpga_irq_ack = { |
| 111 | .ack = fpga_mask_ack_irq, | 111 | .ack = fpga_mask_ack_irq, |
| 112 | .mask = fpga_mask_irq, | 112 | .mask = fpga_mask_irq, |
| 113 | .unmask = fpga_unmask_irq, | 113 | .unmask = fpga_unmask_irq, |
| 114 | }; | 114 | }; |
| 115 | 115 | ||
| 116 | 116 | ||
| 117 | static struct irqchip omap_fpga_irq = { | 117 | static struct irqchip omap_fpga_irq = { |
| 118 | .ack = fpga_ack_irq, | 118 | .ack = fpga_ack_irq, |
| 119 | .mask = fpga_mask_irq, | 119 | .mask = fpga_mask_irq, |
| 120 | .unmask = fpga_unmask_irq, | 120 | .unmask = fpga_unmask_irq, |
| 121 | }; | 121 | }; |
| 122 | 122 | ||
| 123 | /* | 123 | /* |
| 124 | * All of the FPGA interrupt request inputs except for the touchscreen are | 124 | * All of the FPGA interrupt request inputs except for the touchscreen are |
| 125 | * edge-sensitive; the touchscreen is level-sensitive. The edge-sensitive | 125 | * edge-sensitive; the touchscreen is level-sensitive. The edge-sensitive |
| 126 | * interrupts are acknowledged as a side-effect of reading the interrupt | 126 | * interrupts are acknowledged as a side-effect of reading the interrupt |
| 127 | * status register from the FPGA. The edge-sensitive interrupt inputs | 127 | * status register from the FPGA. The edge-sensitive interrupt inputs |
| 128 | * cause a problem with level interrupt requests, such as Ethernet. The | 128 | * cause a problem with level interrupt requests, such as Ethernet. The |
| 129 | * problem occurs when a level interrupt request is asserted while its | 129 | * problem occurs when a level interrupt request is asserted while its |
| 130 | * interrupt input is masked in the FPGA, which results in a missed | 130 | * interrupt input is masked in the FPGA, which results in a missed |
| 131 | * interrupt. | 131 | * interrupt. |
| 132 | * | 132 | * |
| 133 | * In an attempt to workaround the problem with missed interrupts, the | 133 | * In an attempt to workaround the problem with missed interrupts, the |
| 134 | * mask_ack routine for all of the FPGA interrupts has been changed from | 134 | * mask_ack routine for all of the FPGA interrupts has been changed from |
| 135 | * fpga_mask_ack_irq() to fpga_ack_irq() so that the specific FPGA interrupt | 135 | * fpga_mask_ack_irq() to fpga_ack_irq() so that the specific FPGA interrupt |
| 136 | * being serviced is left unmasked. We can do this because the FPGA cascade | 136 | * being serviced is left unmasked. We can do this because the FPGA cascade |
| 137 | * interrupt is installed with the SA_INTERRUPT flag, which leaves all | 137 | * interrupt is installed with the SA_INTERRUPT flag, which leaves all |
| 138 | * interrupts masked at the CPU while an FPGA interrupt handler executes. | 138 | * interrupts masked at the CPU while an FPGA interrupt handler executes. |
| 139 | * | 139 | * |
| 140 | * Limited testing indicates that this workaround appears to be effective | 140 | * Limited testing indicates that this workaround appears to be effective |
| 141 | * for the smc9194 Ethernet driver used on the Innovator. It should work | 141 | * for the smc9194 Ethernet driver used on the Innovator. It should work |
| 142 | * on other FPGA interrupts as well, but any drivers that explicitly mask | 142 | * on other FPGA interrupts as well, but any drivers that explicitly mask |
| 143 | * interrupts at the interrupt controller via disable_irq/enable_irq | 143 | * interrupts at the interrupt controller via disable_irq/enable_irq |
| 144 | * could pose a problem. | 144 | * could pose a problem. |
| 145 | */ | 145 | */ |
| 146 | void omap1510_fpga_init_irq(void) | 146 | void omap1510_fpga_init_irq(void) |
| 147 | { | 147 | { |
| 148 | int i; | 148 | int i; |
| 149 | 149 | ||
| 150 | __raw_writeb(0, OMAP1510_FPGA_IMR_LO); | 150 | __raw_writeb(0, OMAP1510_FPGA_IMR_LO); |
| 151 | __raw_writeb(0, OMAP1510_FPGA_IMR_HI); | 151 | __raw_writeb(0, OMAP1510_FPGA_IMR_HI); |
| 152 | __raw_writeb(0, INNOVATOR_FPGA_IMR2); | 152 | __raw_writeb(0, INNOVATOR_FPGA_IMR2); |
| 153 | 153 | ||
| 154 | for (i = OMAP1510_IH_FPGA_BASE; i < (OMAP1510_IH_FPGA_BASE + NR_FPGA_IRQS); i++) { | 154 | for (i = OMAP1510_IH_FPGA_BASE; i < (OMAP1510_IH_FPGA_BASE + NR_FPGA_IRQS); i++) { |
| 155 | 155 | ||
| 156 | if (i == OMAP1510_INT_FPGA_TS) { | 156 | if (i == OMAP1510_INT_FPGA_TS) { |
| 157 | /* | 157 | /* |
| 158 | * The touchscreen interrupt is level-sensitive, so | 158 | * The touchscreen interrupt is level-sensitive, so |
| 159 | * we'll use the regular mask_ack routine for it. | 159 | * we'll use the regular mask_ack routine for it. |
| 160 | */ | 160 | */ |
| 161 | set_irq_chip(i, &omap_fpga_irq_ack); | 161 | set_irq_chip(i, &omap_fpga_irq_ack); |
| 162 | } | 162 | } |
| 163 | else { | 163 | else { |
| 164 | /* | 164 | /* |
| 165 | * All FPGA interrupts except the touchscreen are | 165 | * All FPGA interrupts except the touchscreen are |
| 166 | * edge-sensitive, so we won't mask them. | 166 | * edge-sensitive, so we won't mask them. |
| 167 | */ | 167 | */ |
| 168 | set_irq_chip(i, &omap_fpga_irq); | 168 | set_irq_chip(i, &omap_fpga_irq); |
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | set_irq_handler(i, do_edge_IRQ); | 171 | set_irq_handler(i, do_edge_IRQ); |
| 172 | set_irq_flags(i, IRQF_VALID); | 172 | set_irq_flags(i, IRQF_VALID); |
| 173 | } | 173 | } |
| 174 | 174 | ||
| 175 | /* | 175 | /* |
| 176 | * The FPGA interrupt line is connected to GPIO13. Claim this pin for | 176 | * The FPGA interrupt line is connected to GPIO13. Claim this pin for |
| 177 | * the ARM. | 177 | * the ARM. |
| 178 | * | 178 | * |
| 179 | * NOTE: For general GPIO/MPUIO access and interrupts, please see | 179 | * NOTE: For general GPIO/MPUIO access and interrupts, please see |
| 180 | * gpio.[ch] | 180 | * gpio.[ch] |
| 181 | */ | 181 | */ |
| 182 | omap_request_gpio(13); | 182 | omap_request_gpio(13); |
| 183 | omap_set_gpio_direction(13, 1); | 183 | omap_set_gpio_direction(13, 1); |
| 184 | omap_set_gpio_edge_ctrl(13, OMAP_GPIO_RISING_EDGE); | 184 | omap_set_gpio_edge_ctrl(13, OMAP_GPIO_RISING_EDGE); |
| 185 | set_irq_chained_handler(OMAP1510_INT_FPGA, innovator_fpga_IRQ_demux); | 185 | set_irq_chained_handler(OMAP1510_INT_FPGA, innovator_fpga_IRQ_demux); |
| 186 | } | 186 | } |
| 187 | 187 | ||
| 188 | EXPORT_SYMBOL(omap1510_fpga_init_irq); | 188 | EXPORT_SYMBOL(omap1510_fpga_init_irq); |
| 189 | 189 |
arch/arm/mach-pxa/irq.c
| 1 | /* | 1 | /* |
| 2 | * linux/arch/arm/mach-pxa/irq.c | 2 | * linux/arch/arm/mach-pxa/irq.c |
| 3 | * | 3 | * |
| 4 | * Generic PXA IRQ handling, GPIO IRQ demultiplexing, etc. | 4 | * Generic PXA IRQ handling, GPIO IRQ demultiplexing, etc. |
| 5 | * | 5 | * |
| 6 | * Author: Nicolas Pitre | 6 | * Author: Nicolas Pitre |
| 7 | * Created: Jun 15, 2001 | 7 | * Created: Jun 15, 2001 |
| 8 | * Copyright: MontaVista Software Inc. | 8 | * Copyright: MontaVista Software Inc. |
| 9 | * | 9 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of the GNU General Public License version 2 as | 11 | * it under the terms of the GNU General Public License version 2 as |
| 12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
| 13 | */ | 13 | */ |
| 14 | 14 | ||
| 15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
| 16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
| 18 | #include <linux/ptrace.h> | 18 | #include <linux/ptrace.h> |
| 19 | 19 | ||
| 20 | #include <asm/hardware.h> | 20 | #include <asm/hardware.h> |
| 21 | #include <asm/irq.h> | 21 | #include <asm/irq.h> |
| 22 | #include <asm/mach/irq.h> | 22 | #include <asm/mach/irq.h> |
| 23 | #include <asm/arch/pxa-regs.h> | 23 | #include <asm/arch/pxa-regs.h> |
| 24 | 24 | ||
| 25 | #include "generic.h" | 25 | #include "generic.h" |
| 26 | 26 | ||
| 27 | 27 | ||
| 28 | /* | 28 | /* |
| 29 | * This is for peripheral IRQs internal to the PXA chip. | 29 | * This is for peripheral IRQs internal to the PXA chip. |
| 30 | */ | 30 | */ |
| 31 | 31 | ||
| 32 | static void pxa_mask_low_irq(unsigned int irq) | 32 | static void pxa_mask_low_irq(unsigned int irq) |
| 33 | { | 33 | { |
| 34 | ICMR &= ~(1 << (irq + PXA_IRQ_SKIP)); | 34 | ICMR &= ~(1 << (irq + PXA_IRQ_SKIP)); |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | static void pxa_unmask_low_irq(unsigned int irq) | 37 | static void pxa_unmask_low_irq(unsigned int irq) |
| 38 | { | 38 | { |
| 39 | ICMR |= (1 << (irq + PXA_IRQ_SKIP)); | 39 | ICMR |= (1 << (irq + PXA_IRQ_SKIP)); |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | static struct irqchip pxa_internal_chip_low = { | 42 | static struct irqchip pxa_internal_chip_low = { |
| 43 | .ack = pxa_mask_low_irq, | 43 | .ack = pxa_mask_low_irq, |
| 44 | .mask = pxa_mask_low_irq, | 44 | .mask = pxa_mask_low_irq, |
| 45 | .unmask = pxa_unmask_low_irq, | 45 | .unmask = pxa_unmask_low_irq, |
| 46 | }; | 46 | }; |
| 47 | 47 | ||
| 48 | #if PXA_INTERNAL_IRQS > 32 | 48 | #if PXA_INTERNAL_IRQS > 32 |
| 49 | 49 | ||
| 50 | /* | 50 | /* |
| 51 | * This is for the second set of internal IRQs as found on the PXA27x. | 51 | * This is for the second set of internal IRQs as found on the PXA27x. |
| 52 | */ | 52 | */ |
| 53 | 53 | ||
| 54 | static void pxa_mask_high_irq(unsigned int irq) | 54 | static void pxa_mask_high_irq(unsigned int irq) |
| 55 | { | 55 | { |
| 56 | ICMR2 &= ~(1 << (irq - 32 + PXA_IRQ_SKIP)); | 56 | ICMR2 &= ~(1 << (irq - 32 + PXA_IRQ_SKIP)); |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | static void pxa_unmask_high_irq(unsigned int irq) | 59 | static void pxa_unmask_high_irq(unsigned int irq) |
| 60 | { | 60 | { |
| 61 | ICMR2 |= (1 << (irq - 32 + PXA_IRQ_SKIP)); | 61 | ICMR2 |= (1 << (irq - 32 + PXA_IRQ_SKIP)); |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | static struct irqchip pxa_internal_chip_high = { | 64 | static struct irqchip pxa_internal_chip_high = { |
| 65 | .ack = pxa_mask_high_irq, | 65 | .ack = pxa_mask_high_irq, |
| 66 | .mask = pxa_mask_high_irq, | 66 | .mask = pxa_mask_high_irq, |
| 67 | .unmask = pxa_unmask_high_irq, | 67 | .unmask = pxa_unmask_high_irq, |
| 68 | }; | 68 | }; |
| 69 | 69 | ||
| 70 | #endif | 70 | #endif |
| 71 | 71 | ||
| 72 | /* | 72 | /* |
| 73 | * PXA GPIO edge detection for IRQs: | 73 | * PXA GPIO edge detection for IRQs: |
| 74 | * IRQs are generated on Falling-Edge, Rising-Edge, or both. | 74 | * IRQs are generated on Falling-Edge, Rising-Edge, or both. |
| 75 | * Use this instead of directly setting GRER/GFER. | 75 | * Use this instead of directly setting GRER/GFER. |
| 76 | */ | 76 | */ |
| 77 | 77 | ||
| 78 | static long GPIO_IRQ_rising_edge[4]; | 78 | static long GPIO_IRQ_rising_edge[4]; |
| 79 | static long GPIO_IRQ_falling_edge[4]; | 79 | static long GPIO_IRQ_falling_edge[4]; |
| 80 | static long GPIO_IRQ_mask[4]; | 80 | static long GPIO_IRQ_mask[4]; |
| 81 | 81 | ||
| 82 | static int pxa_gpio_irq_type(unsigned int irq, unsigned int type) | 82 | static int pxa_gpio_irq_type(unsigned int irq, unsigned int type) |
| 83 | { | 83 | { |
| 84 | int gpio, idx; | 84 | int gpio, idx; |
| 85 | 85 | ||
| 86 | gpio = IRQ_TO_GPIO(irq); | 86 | gpio = IRQ_TO_GPIO(irq); |
| 87 | idx = gpio >> 5; | 87 | idx = gpio >> 5; |
| 88 | 88 | ||
| 89 | if (type == IRQT_PROBE) { | 89 | if (type == IRQT_PROBE) { |
| 90 | /* Don't mess with enabled GPIOs using preconfigured edges or | 90 | /* Don't mess with enabled GPIOs using preconfigured edges or |
| 91 | GPIOs set to alternate function during probe */ | 91 | GPIOs set to alternate function during probe */ |
| 92 | if ((GPIO_IRQ_rising_edge[idx] | GPIO_IRQ_falling_edge[idx]) & | 92 | if ((GPIO_IRQ_rising_edge[idx] | GPIO_IRQ_falling_edge[idx]) & |
| 93 | GPIO_bit(gpio)) | 93 | GPIO_bit(gpio)) |
| 94 | return 0; | 94 | return 0; |
| 95 | if (GAFR(gpio) & (0x3 << (((gpio) & 0xf)*2))) | 95 | if (GAFR(gpio) & (0x3 << (((gpio) & 0xf)*2))) |
| 96 | return 0; | 96 | return 0; |
| 97 | type = __IRQT_RISEDGE | __IRQT_FALEDGE; | 97 | type = __IRQT_RISEDGE | __IRQT_FALEDGE; |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | /* printk(KERN_DEBUG "IRQ%d (GPIO%d): ", irq, gpio); */ | 100 | /* printk(KERN_DEBUG "IRQ%d (GPIO%d): ", irq, gpio); */ |
| 101 | 101 | ||
| 102 | pxa_gpio_mode(gpio | GPIO_IN); | 102 | pxa_gpio_mode(gpio | GPIO_IN); |
| 103 | 103 | ||
| 104 | if (type & __IRQT_RISEDGE) { | 104 | if (type & __IRQT_RISEDGE) { |
| 105 | /* printk("rising "); */ | 105 | /* printk("rising "); */ |
| 106 | __set_bit (gpio, GPIO_IRQ_rising_edge); | 106 | __set_bit (gpio, GPIO_IRQ_rising_edge); |
| 107 | } else | 107 | } else |
| 108 | __clear_bit (gpio, GPIO_IRQ_rising_edge); | 108 | __clear_bit (gpio, GPIO_IRQ_rising_edge); |
| 109 | 109 | ||
| 110 | if (type & __IRQT_FALEDGE) { | 110 | if (type & __IRQT_FALEDGE) { |
| 111 | /* printk("falling "); */ | 111 | /* printk("falling "); */ |
| 112 | __set_bit (gpio, GPIO_IRQ_falling_edge); | 112 | __set_bit (gpio, GPIO_IRQ_falling_edge); |
| 113 | } else | 113 | } else |
| 114 | __clear_bit (gpio, GPIO_IRQ_falling_edge); | 114 | __clear_bit (gpio, GPIO_IRQ_falling_edge); |
| 115 | 115 | ||
| 116 | /* printk("edges\n"); */ | 116 | /* printk("edges\n"); */ |
| 117 | 117 | ||
| 118 | GRER(gpio) = GPIO_IRQ_rising_edge[idx] & GPIO_IRQ_mask[idx]; | 118 | GRER(gpio) = GPIO_IRQ_rising_edge[idx] & GPIO_IRQ_mask[idx]; |
| 119 | GFER(gpio) = GPIO_IRQ_falling_edge[idx] & GPIO_IRQ_mask[idx]; | 119 | GFER(gpio) = GPIO_IRQ_falling_edge[idx] & GPIO_IRQ_mask[idx]; |
| 120 | return 0; | 120 | return 0; |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | /* | 123 | /* |
| 124 | * GPIO IRQs must be acknowledged. This is for GPIO 0 and 1. | 124 | * GPIO IRQs must be acknowledged. This is for GPIO 0 and 1. |
| 125 | */ | 125 | */ |
| 126 | 126 | ||
| 127 | static void pxa_ack_low_gpio(unsigned int irq) | 127 | static void pxa_ack_low_gpio(unsigned int irq) |
| 128 | { | 128 | { |
| 129 | GEDR0 = (1 << (irq - IRQ_GPIO0)); | 129 | GEDR0 = (1 << (irq - IRQ_GPIO0)); |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | static struct irqchip pxa_low_gpio_chip = { | 132 | static struct irqchip pxa_low_gpio_chip = { |
| 133 | .ack = pxa_ack_low_gpio, | 133 | .ack = pxa_ack_low_gpio, |
| 134 | .mask = pxa_mask_low_irq, | 134 | .mask = pxa_mask_low_irq, |
| 135 | .unmask = pxa_unmask_low_irq, | 135 | .unmask = pxa_unmask_low_irq, |
| 136 | .type = pxa_gpio_irq_type, | 136 | .set_type = pxa_gpio_irq_type, |
| 137 | }; | 137 | }; |
| 138 | 138 | ||
| 139 | /* | 139 | /* |
| 140 | * Demux handler for GPIO>=2 edge detect interrupts | 140 | * Demux handler for GPIO>=2 edge detect interrupts |
| 141 | */ | 141 | */ |
| 142 | 142 | ||
| 143 | static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc, | 143 | static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc, |
| 144 | struct pt_regs *regs) | 144 | struct pt_regs *regs) |
| 145 | { | 145 | { |
| 146 | unsigned int mask; | 146 | unsigned int mask; |
| 147 | int loop; | 147 | int loop; |
| 148 | 148 | ||
| 149 | do { | 149 | do { |
| 150 | loop = 0; | 150 | loop = 0; |
| 151 | 151 | ||
| 152 | mask = GEDR0 & ~3; | 152 | mask = GEDR0 & ~3; |
| 153 | if (mask) { | 153 | if (mask) { |
| 154 | GEDR0 = mask; | 154 | GEDR0 = mask; |
| 155 | irq = IRQ_GPIO(2); | 155 | irq = IRQ_GPIO(2); |
| 156 | desc = irq_desc + irq; | 156 | desc = irq_desc + irq; |
| 157 | mask >>= 2; | 157 | mask >>= 2; |
| 158 | do { | 158 | do { |
| 159 | if (mask & 1) | 159 | if (mask & 1) |
| 160 | desc->handle(irq, desc, regs); | 160 | desc_handle_irq(irq, desc, regs); |
| 161 | irq++; | 161 | irq++; |
| 162 | desc++; | 162 | desc++; |
| 163 | mask >>= 1; | 163 | mask >>= 1; |
| 164 | } while (mask); | 164 | } while (mask); |
| 165 | loop = 1; | 165 | loop = 1; |
| 166 | } | 166 | } |
| 167 | 167 | ||
| 168 | mask = GEDR1; | 168 | mask = GEDR1; |
| 169 | if (mask) { | 169 | if (mask) { |
| 170 | GEDR1 = mask; | 170 | GEDR1 = mask; |
| 171 | irq = IRQ_GPIO(32); | 171 | irq = IRQ_GPIO(32); |
| 172 | desc = irq_desc + irq; | 172 | desc = irq_desc + irq; |
| 173 | do { | 173 | do { |
| 174 | if (mask & 1) | 174 | if (mask & 1) |
| 175 | desc->handle(irq, desc, regs); | 175 | desc_handle_irq(irq, desc, regs); |
| 176 | irq++; | 176 | irq++; |
| 177 | desc++; | 177 | desc++; |
| 178 | mask >>= 1; | 178 | mask >>= 1; |
| 179 | } while (mask); | 179 | } while (mask); |
| 180 | loop = 1; | 180 | loop = 1; |
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | mask = GEDR2; | 183 | mask = GEDR2; |
| 184 | if (mask) { | 184 | if (mask) { |
| 185 | GEDR2 = mask; | 185 | GEDR2 = mask; |
| 186 | irq = IRQ_GPIO(64); | 186 | irq = IRQ_GPIO(64); |
| 187 | desc = irq_desc + irq; | 187 | desc = irq_desc + irq; |
| 188 | do { | 188 | do { |
| 189 | if (mask & 1) | 189 | if (mask & 1) |
| 190 | desc->handle(irq, desc, regs); | 190 | desc_handle_irq(irq, desc, regs); |
| 191 | irq++; | 191 | irq++; |
| 192 | desc++; | 192 | desc++; |
| 193 | mask >>= 1; | 193 | mask >>= 1; |
| 194 | } while (mask); | 194 | } while (mask); |
| 195 | loop = 1; | 195 | loop = 1; |
| 196 | } | 196 | } |
| 197 | 197 | ||
| 198 | #if PXA_LAST_GPIO >= 96 | 198 | #if PXA_LAST_GPIO >= 96 |
| 199 | mask = GEDR3; | 199 | mask = GEDR3; |
| 200 | if (mask) { | 200 | if (mask) { |
| 201 | GEDR3 = mask; | 201 | GEDR3 = mask; |
| 202 | irq = IRQ_GPIO(96); | 202 | irq = IRQ_GPIO(96); |
| 203 | desc = irq_desc + irq; | 203 | desc = irq_desc + irq; |
| 204 | do { | 204 | do { |
| 205 | if (mask & 1) | 205 | if (mask & 1) |
| 206 | desc->handle(irq, desc, regs); | 206 | desc_handle_irq(irq, desc, regs); |
| 207 | irq++; | 207 | irq++; |
| 208 | desc++; | 208 | desc++; |
| 209 | mask >>= 1; | 209 | mask >>= 1; |
| 210 | } while (mask); | 210 | } while (mask); |
| 211 | loop = 1; | 211 | loop = 1; |
| 212 | } | 212 | } |
| 213 | #endif | 213 | #endif |
| 214 | } while (loop); | 214 | } while (loop); |
| 215 | } | 215 | } |
| 216 | 216 | ||
| 217 | static void pxa_ack_muxed_gpio(unsigned int irq) | 217 | static void pxa_ack_muxed_gpio(unsigned int irq) |
| 218 | { | 218 | { |
| 219 | int gpio = irq - IRQ_GPIO(2) + 2; | 219 | int gpio = irq - IRQ_GPIO(2) + 2; |
| 220 | GEDR(gpio) = GPIO_bit(gpio); | 220 | GEDR(gpio) = GPIO_bit(gpio); |
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | static void pxa_mask_muxed_gpio(unsigned int irq) | 223 | static void pxa_mask_muxed_gpio(unsigned int irq) |
| 224 | { | 224 | { |
| 225 | int gpio = irq - IRQ_GPIO(2) + 2; | 225 | int gpio = irq - IRQ_GPIO(2) + 2; |
| 226 | __clear_bit(gpio, GPIO_IRQ_mask); | 226 | __clear_bit(gpio, GPIO_IRQ_mask); |
| 227 | GRER(gpio) &= ~GPIO_bit(gpio); | 227 | GRER(gpio) &= ~GPIO_bit(gpio); |
| 228 | GFER(gpio) &= ~GPIO_bit(gpio); | 228 | GFER(gpio) &= ~GPIO_bit(gpio); |
| 229 | } | 229 | } |
| 230 | 230 | ||
| 231 | static void pxa_unmask_muxed_gpio(unsigned int irq) | 231 | static void pxa_unmask_muxed_gpio(unsigned int irq) |
| 232 | { | 232 | { |
| 233 | int gpio = irq - IRQ_GPIO(2) + 2; | 233 | int gpio = irq - IRQ_GPIO(2) + 2; |
| 234 | int idx = gpio >> 5; | 234 | int idx = gpio >> 5; |
| 235 | __set_bit(gpio, GPIO_IRQ_mask); | 235 | __set_bit(gpio, GPIO_IRQ_mask); |
| 236 | GRER(gpio) = GPIO_IRQ_rising_edge[idx] & GPIO_IRQ_mask[idx]; | 236 | GRER(gpio) = GPIO_IRQ_rising_edge[idx] & GPIO_IRQ_mask[idx]; |
| 237 | GFER(gpio) = GPIO_IRQ_falling_edge[idx] & GPIO_IRQ_mask[idx]; | 237 | GFER(gpio) = GPIO_IRQ_falling_edge[idx] & GPIO_IRQ_mask[idx]; |
| 238 | } | 238 | } |
| 239 | 239 | ||
| 240 | static struct irqchip pxa_muxed_gpio_chip = { | 240 | static struct irqchip pxa_muxed_gpio_chip = { |
| 241 | .ack = pxa_ack_muxed_gpio, | 241 | .ack = pxa_ack_muxed_gpio, |
| 242 | .mask = pxa_mask_muxed_gpio, | 242 | .mask = pxa_mask_muxed_gpio, |
| 243 | .unmask = pxa_unmask_muxed_gpio, | 243 | .unmask = pxa_unmask_muxed_gpio, |
| 244 | .type = pxa_gpio_irq_type, | 244 | .set_type = pxa_gpio_irq_type, |
| 245 | }; | 245 | }; |
| 246 | 246 | ||
| 247 | 247 | ||
| 248 | void __init pxa_init_irq(void) | 248 | void __init pxa_init_irq(void) |
| 249 | { | 249 | { |
| 250 | int irq; | 250 | int irq; |
| 251 | 251 | ||
| 252 | /* disable all IRQs */ | 252 | /* disable all IRQs */ |
| 253 | ICMR = 0; | 253 | ICMR = 0; |
| 254 | 254 | ||
| 255 | /* all IRQs are IRQ, not FIQ */ | 255 | /* all IRQs are IRQ, not FIQ */ |
| 256 | ICLR = 0; | 256 | ICLR = 0; |
| 257 | 257 | ||
| 258 | /* clear all GPIO edge detects */ | 258 | /* clear all GPIO edge detects */ |
| 259 | GFER0 = 0; | 259 | GFER0 = 0; |
| 260 | GFER1 = 0; | 260 | GFER1 = 0; |
| 261 | GFER2 = 0; | 261 | GFER2 = 0; |
| 262 | GRER0 = 0; | 262 | GRER0 = 0; |
| 263 | GRER1 = 0; | 263 | GRER1 = 0; |
| 264 | GRER2 = 0; | 264 | GRER2 = 0; |
| 265 | GEDR0 = GEDR0; | 265 | GEDR0 = GEDR0; |
| 266 | GEDR1 = GEDR1; | 266 | GEDR1 = GEDR1; |
| 267 | GEDR2 = GEDR2; | 267 | GEDR2 = GEDR2; |
| 268 | 268 | ||
| 269 | #ifdef CONFIG_PXA27x | 269 | #ifdef CONFIG_PXA27x |
| 270 | /* And similarly for the extra regs on the PXA27x */ | 270 | /* And similarly for the extra regs on the PXA27x */ |
| 271 | ICMR2 = 0; | 271 | ICMR2 = 0; |
| 272 | ICLR2 = 0; | 272 | ICLR2 = 0; |
| 273 | GFER3 = 0; | 273 | GFER3 = 0; |
| 274 | GRER3 = 0; | 274 | GRER3 = 0; |
| 275 | GEDR3 = GEDR3; | 275 | GEDR3 = GEDR3; |
| 276 | #endif | 276 | #endif |
| 277 | 277 | ||
| 278 | /* only unmasked interrupts kick us out of idle */ | 278 | /* only unmasked interrupts kick us out of idle */ |
| 279 | ICCR = 1; | 279 | ICCR = 1; |
| 280 | 280 | ||
| 281 | /* GPIO 0 and 1 must have their mask bit always set */ | 281 | /* GPIO 0 and 1 must have their mask bit always set */ |
| 282 | GPIO_IRQ_mask[0] = 3; | 282 | GPIO_IRQ_mask[0] = 3; |
| 283 | 283 | ||
| 284 | for (irq = PXA_IRQ(PXA_IRQ_SKIP); irq <= PXA_IRQ(31); irq++) { | 284 | for (irq = PXA_IRQ(PXA_IRQ_SKIP); irq <= PXA_IRQ(31); irq++) { |
| 285 | set_irq_chip(irq, &pxa_internal_chip_low); | 285 | set_irq_chip(irq, &pxa_internal_chip_low); |
| 286 | set_irq_handler(irq, do_level_IRQ); | 286 | set_irq_handler(irq, do_level_IRQ); |
| 287 | set_irq_flags(irq, IRQF_VALID); | 287 | set_irq_flags(irq, IRQF_VALID); |
| 288 | } | 288 | } |
| 289 | 289 | ||
| 290 | #if PXA_INTERNAL_IRQS > 32 | 290 | #if PXA_INTERNAL_IRQS > 32 |
| 291 | for (irq = PXA_IRQ(32); irq < PXA_IRQ(PXA_INTERNAL_IRQS); irq++) { | 291 | for (irq = PXA_IRQ(32); irq < PXA_IRQ(PXA_INTERNAL_IRQS); irq++) { |
| 292 | set_irq_chip(irq, &pxa_internal_chip_high); | 292 | set_irq_chip(irq, &pxa_internal_chip_high); |
| 293 | set_irq_handler(irq, do_level_IRQ); | 293 | set_irq_handler(irq, do_level_IRQ); |
| 294 | set_irq_flags(irq, IRQF_VALID); | 294 | set_irq_flags(irq, IRQF_VALID); |
| 295 | } | 295 | } |
| 296 | #endif | 296 | #endif |
| 297 | 297 | ||
| 298 | for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) { | 298 | for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) { |
| 299 | set_irq_chip(irq, &pxa_low_gpio_chip); | 299 | set_irq_chip(irq, &pxa_low_gpio_chip); |
| 300 | set_irq_handler(irq, do_edge_IRQ); | 300 | set_irq_handler(irq, do_edge_IRQ); |
| 301 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 301 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
| 302 | } | 302 | } |
| 303 | 303 | ||
| 304 | for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(PXA_LAST_GPIO); irq++) { | 304 | for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(PXA_LAST_GPIO); irq++) { |
| 305 | set_irq_chip(irq, &pxa_muxed_gpio_chip); | 305 | set_irq_chip(irq, &pxa_muxed_gpio_chip); |
| 306 | set_irq_handler(irq, do_edge_IRQ); | 306 | set_irq_handler(irq, do_edge_IRQ); |
| 307 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 307 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
| 308 | } | 308 | } |
| 309 | 309 | ||
| 310 | /* Install handler for GPIO>=2 edge detect interrupts */ | 310 | /* Install handler for GPIO>=2 edge detect interrupts */ |
| 311 | set_irq_chip(IRQ_GPIO_2_x, &pxa_internal_chip_low); | 311 | set_irq_chip(IRQ_GPIO_2_x, &pxa_internal_chip_low); |
| 312 | set_irq_chained_handler(IRQ_GPIO_2_x, pxa_gpio_demux_handler); | 312 | set_irq_chained_handler(IRQ_GPIO_2_x, pxa_gpio_demux_handler); |
| 313 | } | 313 | } |
| 314 | 314 |
arch/arm/mach-pxa/lubbock.c
| 1 | /* | 1 | /* |
| 2 | * linux/arch/arm/mach-pxa/lubbock.c | 2 | * linux/arch/arm/mach-pxa/lubbock.c |
| 3 | * | 3 | * |
| 4 | * Support for the Intel DBPXA250 Development Platform. | 4 | * Support for the Intel DBPXA250 Development Platform. |
| 5 | * | 5 | * |
| 6 | * Author: Nicolas Pitre | 6 | * Author: Nicolas Pitre |
| 7 | * Created: Jun 15, 2001 | 7 | * Created: Jun 15, 2001 |
| 8 | * Copyright: MontaVista Software Inc. | 8 | * Copyright: MontaVista Software Inc. |
| 9 | * | 9 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of the GNU General Public License version 2 as | 11 | * it under the terms of the GNU General Public License version 2 as |
| 12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
| 13 | */ | 13 | */ |
| 14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
| 15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
| 16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
| 17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
| 18 | #include <linux/sysdev.h> | 18 | #include <linux/sysdev.h> |
| 19 | #include <linux/major.h> | 19 | #include <linux/major.h> |
| 20 | #include <linux/fb.h> | 20 | #include <linux/fb.h> |
| 21 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
| 22 | 22 | ||
| 23 | #include <asm/setup.h> | 23 | #include <asm/setup.h> |
| 24 | #include <asm/memory.h> | 24 | #include <asm/memory.h> |
| 25 | #include <asm/mach-types.h> | 25 | #include <asm/mach-types.h> |
| 26 | #include <asm/hardware.h> | 26 | #include <asm/hardware.h> |
| 27 | #include <asm/irq.h> | 27 | #include <asm/irq.h> |
| 28 | 28 | ||
| 29 | #include <asm/mach/arch.h> | 29 | #include <asm/mach/arch.h> |
| 30 | #include <asm/mach/map.h> | 30 | #include <asm/mach/map.h> |
| 31 | #include <asm/mach/irq.h> | 31 | #include <asm/mach/irq.h> |
| 32 | 32 | ||
| 33 | #include <asm/hardware/sa1111.h> | 33 | #include <asm/hardware/sa1111.h> |
| 34 | 34 | ||
| 35 | #include <asm/arch/pxa-regs.h> | 35 | #include <asm/arch/pxa-regs.h> |
| 36 | #include <asm/arch/lubbock.h> | 36 | #include <asm/arch/lubbock.h> |
| 37 | #include <asm/arch/udc.h> | 37 | #include <asm/arch/udc.h> |
| 38 | #include <asm/arch/pxafb.h> | 38 | #include <asm/arch/pxafb.h> |
| 39 | #include <asm/arch/mmc.h> | 39 | #include <asm/arch/mmc.h> |
| 40 | 40 | ||
| 41 | #include "generic.h" | 41 | #include "generic.h" |
| 42 | 42 | ||
| 43 | 43 | ||
| 44 | #define LUB_MISC_WR __LUB_REG(LUBBOCK_FPGA_PHYS + 0x080) | 44 | #define LUB_MISC_WR __LUB_REG(LUBBOCK_FPGA_PHYS + 0x080) |
| 45 | 45 | ||
| 46 | void lubbock_set_misc_wr(unsigned int mask, unsigned int set) | 46 | void lubbock_set_misc_wr(unsigned int mask, unsigned int set) |
| 47 | { | 47 | { |
| 48 | unsigned long flags; | 48 | unsigned long flags; |
| 49 | 49 | ||
| 50 | local_irq_save(flags); | 50 | local_irq_save(flags); |
| 51 | LUB_MISC_WR = (LUB_MISC_WR & ~mask) | (set & mask); | 51 | LUB_MISC_WR = (LUB_MISC_WR & ~mask) | (set & mask); |
| 52 | local_irq_restore(flags); | 52 | local_irq_restore(flags); |
| 53 | } | 53 | } |
| 54 | EXPORT_SYMBOL(lubbock_set_misc_wr); | 54 | EXPORT_SYMBOL(lubbock_set_misc_wr); |
| 55 | 55 | ||
| 56 | static unsigned long lubbock_irq_enabled; | 56 | static unsigned long lubbock_irq_enabled; |
| 57 | 57 | ||
| 58 | static void lubbock_mask_irq(unsigned int irq) | 58 | static void lubbock_mask_irq(unsigned int irq) |
| 59 | { | 59 | { |
| 60 | int lubbock_irq = (irq - LUBBOCK_IRQ(0)); | 60 | int lubbock_irq = (irq - LUBBOCK_IRQ(0)); |
| 61 | LUB_IRQ_MASK_EN = (lubbock_irq_enabled &= ~(1 << lubbock_irq)); | 61 | LUB_IRQ_MASK_EN = (lubbock_irq_enabled &= ~(1 << lubbock_irq)); |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | static void lubbock_unmask_irq(unsigned int irq) | 64 | static void lubbock_unmask_irq(unsigned int irq) |
| 65 | { | 65 | { |
| 66 | int lubbock_irq = (irq - LUBBOCK_IRQ(0)); | 66 | int lubbock_irq = (irq - LUBBOCK_IRQ(0)); |
| 67 | /* the irq can be acknowledged only if deasserted, so it's done here */ | 67 | /* the irq can be acknowledged only if deasserted, so it's done here */ |
| 68 | LUB_IRQ_SET_CLR &= ~(1 << lubbock_irq); | 68 | LUB_IRQ_SET_CLR &= ~(1 << lubbock_irq); |
| 69 | LUB_IRQ_MASK_EN = (lubbock_irq_enabled |= (1 << lubbock_irq)); | 69 | LUB_IRQ_MASK_EN = (lubbock_irq_enabled |= (1 << lubbock_irq)); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | static struct irqchip lubbock_irq_chip = { | 72 | static struct irqchip lubbock_irq_chip = { |
| 73 | .ack = lubbock_mask_irq, | 73 | .ack = lubbock_mask_irq, |
| 74 | .mask = lubbock_mask_irq, | 74 | .mask = lubbock_mask_irq, |
| 75 | .unmask = lubbock_unmask_irq, | 75 | .unmask = lubbock_unmask_irq, |
| 76 | }; | 76 | }; |
| 77 | 77 | ||
| 78 | static void lubbock_irq_handler(unsigned int irq, struct irqdesc *desc, | 78 | static void lubbock_irq_handler(unsigned int irq, struct irqdesc *desc, |
| 79 | struct pt_regs *regs) | 79 | struct pt_regs *regs) |
| 80 | { | 80 | { |
| 81 | unsigned long pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled; | 81 | unsigned long pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled; |
| 82 | do { | 82 | do { |
| 83 | GEDR(0) = GPIO_bit(0); /* clear our parent irq */ | 83 | GEDR(0) = GPIO_bit(0); /* clear our parent irq */ |
| 84 | if (likely(pending)) { | 84 | if (likely(pending)) { |
| 85 | irq = LUBBOCK_IRQ(0) + __ffs(pending); | 85 | irq = LUBBOCK_IRQ(0) + __ffs(pending); |
| 86 | desc = irq_desc + irq; | 86 | desc = irq_desc + irq; |
| 87 | desc->handle(irq, desc, regs); | 87 | desc_handle_irq(irq, desc, regs); |
| 88 | } | 88 | } |
| 89 | pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled; | 89 | pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled; |
| 90 | } while (pending); | 90 | } while (pending); |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | static void __init lubbock_init_irq(void) | 93 | static void __init lubbock_init_irq(void) |
| 94 | { | 94 | { |
| 95 | int irq; | 95 | int irq; |
| 96 | 96 | ||
| 97 | pxa_init_irq(); | 97 | pxa_init_irq(); |
| 98 | 98 | ||
| 99 | /* setup extra lubbock irqs */ | 99 | /* setup extra lubbock irqs */ |
| 100 | for (irq = LUBBOCK_IRQ(0); irq <= LUBBOCK_LAST_IRQ; irq++) { | 100 | for (irq = LUBBOCK_IRQ(0); irq <= LUBBOCK_LAST_IRQ; irq++) { |
| 101 | set_irq_chip(irq, &lubbock_irq_chip); | 101 | set_irq_chip(irq, &lubbock_irq_chip); |
| 102 | set_irq_handler(irq, do_level_IRQ); | 102 | set_irq_handler(irq, do_level_IRQ); |
| 103 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 103 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | set_irq_chained_handler(IRQ_GPIO(0), lubbock_irq_handler); | 106 | set_irq_chained_handler(IRQ_GPIO(0), lubbock_irq_handler); |
| 107 | set_irq_type(IRQ_GPIO(0), IRQT_FALLING); | 107 | set_irq_type(IRQ_GPIO(0), IRQT_FALLING); |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | #ifdef CONFIG_PM | 110 | #ifdef CONFIG_PM |
| 111 | 111 | ||
| 112 | static int lubbock_irq_resume(struct sys_device *dev) | 112 | static int lubbock_irq_resume(struct sys_device *dev) |
| 113 | { | 113 | { |
| 114 | LUB_IRQ_MASK_EN = lubbock_irq_enabled; | 114 | LUB_IRQ_MASK_EN = lubbock_irq_enabled; |
| 115 | return 0; | 115 | return 0; |
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | static struct sysdev_class lubbock_irq_sysclass = { | 118 | static struct sysdev_class lubbock_irq_sysclass = { |
| 119 | set_kset_name("cpld_irq"), | 119 | set_kset_name("cpld_irq"), |
| 120 | .resume = lubbock_irq_resume, | 120 | .resume = lubbock_irq_resume, |
| 121 | }; | 121 | }; |
| 122 | 122 | ||
| 123 | static struct sys_device lubbock_irq_device = { | 123 | static struct sys_device lubbock_irq_device = { |
| 124 | .cls = &lubbock_irq_sysclass, | 124 | .cls = &lubbock_irq_sysclass, |
| 125 | }; | 125 | }; |
| 126 | 126 | ||
| 127 | static int __init lubbock_irq_device_init(void) | 127 | static int __init lubbock_irq_device_init(void) |
| 128 | { | 128 | { |
| 129 | int ret = sysdev_class_register(&lubbock_irq_sysclass); | 129 | int ret = sysdev_class_register(&lubbock_irq_sysclass); |
| 130 | if (ret == 0) | 130 | if (ret == 0) |
| 131 | ret = sysdev_register(&lubbock_irq_device); | 131 | ret = sysdev_register(&lubbock_irq_device); |
| 132 | return ret; | 132 | return ret; |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | device_initcall(lubbock_irq_device_init); | 135 | device_initcall(lubbock_irq_device_init); |
| 136 | 136 | ||
| 137 | #endif | 137 | #endif |
| 138 | 138 | ||
| 139 | static int lubbock_udc_is_connected(void) | 139 | static int lubbock_udc_is_connected(void) |
| 140 | { | 140 | { |
| 141 | return (LUB_MISC_RD & (1 << 9)) == 0; | 141 | return (LUB_MISC_RD & (1 << 9)) == 0; |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | static struct pxa2xx_udc_mach_info udc_info __initdata = { | 144 | static struct pxa2xx_udc_mach_info udc_info __initdata = { |
| 145 | .udc_is_connected = lubbock_udc_is_connected, | 145 | .udc_is_connected = lubbock_udc_is_connected, |
| 146 | // no D+ pullup; lubbock can't connect/disconnect in software | 146 | // no D+ pullup; lubbock can't connect/disconnect in software |
| 147 | }; | 147 | }; |
| 148 | 148 | ||
| 149 | static struct resource sa1111_resources[] = { | 149 | static struct resource sa1111_resources[] = { |
| 150 | [0] = { | 150 | [0] = { |
| 151 | .start = 0x10000000, | 151 | .start = 0x10000000, |
| 152 | .end = 0x10001fff, | 152 | .end = 0x10001fff, |
| 153 | .flags = IORESOURCE_MEM, | 153 | .flags = IORESOURCE_MEM, |
| 154 | }, | 154 | }, |
| 155 | [1] = { | 155 | [1] = { |
| 156 | .start = LUBBOCK_SA1111_IRQ, | 156 | .start = LUBBOCK_SA1111_IRQ, |
| 157 | .end = LUBBOCK_SA1111_IRQ, | 157 | .end = LUBBOCK_SA1111_IRQ, |
| 158 | .flags = IORESOURCE_IRQ, | 158 | .flags = IORESOURCE_IRQ, |
| 159 | }, | 159 | }, |
| 160 | }; | 160 | }; |
| 161 | 161 | ||
| 162 | static struct platform_device sa1111_device = { | 162 | static struct platform_device sa1111_device = { |
| 163 | .name = "sa1111", | 163 | .name = "sa1111", |
| 164 | .id = -1, | 164 | .id = -1, |
| 165 | .num_resources = ARRAY_SIZE(sa1111_resources), | 165 | .num_resources = ARRAY_SIZE(sa1111_resources), |
| 166 | .resource = sa1111_resources, | 166 | .resource = sa1111_resources, |
| 167 | }; | 167 | }; |
| 168 | 168 | ||
| 169 | static struct resource smc91x_resources[] = { | 169 | static struct resource smc91x_resources[] = { |
| 170 | [0] = { | 170 | [0] = { |
| 171 | .name = "smc91x-regs", | 171 | .name = "smc91x-regs", |
| 172 | .start = 0x0c000000, | 172 | .start = 0x0c000000, |
| 173 | .end = 0x0c0fffff, | 173 | .end = 0x0c0fffff, |
| 174 | .flags = IORESOURCE_MEM, | 174 | .flags = IORESOURCE_MEM, |
| 175 | }, | 175 | }, |
| 176 | [1] = { | 176 | [1] = { |
| 177 | .start = LUBBOCK_ETH_IRQ, | 177 | .start = LUBBOCK_ETH_IRQ, |
| 178 | .end = LUBBOCK_ETH_IRQ, | 178 | .end = LUBBOCK_ETH_IRQ, |
| 179 | .flags = IORESOURCE_IRQ, | 179 | .flags = IORESOURCE_IRQ, |
| 180 | }, | 180 | }, |
| 181 | [2] = { | 181 | [2] = { |
| 182 | .name = "smc91x-attrib", | 182 | .name = "smc91x-attrib", |
| 183 | .start = 0x0e000000, | 183 | .start = 0x0e000000, |
| 184 | .end = 0x0e0fffff, | 184 | .end = 0x0e0fffff, |
| 185 | .flags = IORESOURCE_MEM, | 185 | .flags = IORESOURCE_MEM, |
| 186 | }, | 186 | }, |
| 187 | }; | 187 | }; |
| 188 | 188 | ||
| 189 | static struct platform_device smc91x_device = { | 189 | static struct platform_device smc91x_device = { |
| 190 | .name = "smc91x", | 190 | .name = "smc91x", |
| 191 | .id = -1, | 191 | .id = -1, |
| 192 | .num_resources = ARRAY_SIZE(smc91x_resources), | 192 | .num_resources = ARRAY_SIZE(smc91x_resources), |
| 193 | .resource = smc91x_resources, | 193 | .resource = smc91x_resources, |
| 194 | }; | 194 | }; |
| 195 | 195 | ||
| 196 | static struct platform_device *devices[] __initdata = { | 196 | static struct platform_device *devices[] __initdata = { |
| 197 | &sa1111_device, | 197 | &sa1111_device, |
| 198 | &smc91x_device, | 198 | &smc91x_device, |
| 199 | }; | 199 | }; |
| 200 | 200 | ||
| 201 | static struct pxafb_mach_info sharp_lm8v31 __initdata = { | 201 | static struct pxafb_mach_info sharp_lm8v31 __initdata = { |
| 202 | .pixclock = 270000, | 202 | .pixclock = 270000, |
| 203 | .xres = 640, | 203 | .xres = 640, |
| 204 | .yres = 480, | 204 | .yres = 480, |
| 205 | .bpp = 16, | 205 | .bpp = 16, |
| 206 | .hsync_len = 1, | 206 | .hsync_len = 1, |
| 207 | .left_margin = 3, | 207 | .left_margin = 3, |
| 208 | .right_margin = 3, | 208 | .right_margin = 3, |
| 209 | .vsync_len = 1, | 209 | .vsync_len = 1, |
| 210 | .upper_margin = 0, | 210 | .upper_margin = 0, |
| 211 | .lower_margin = 0, | 211 | .lower_margin = 0, |
| 212 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | 212 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, |
| 213 | .cmap_greyscale = 0, | 213 | .cmap_greyscale = 0, |
| 214 | .cmap_inverse = 0, | 214 | .cmap_inverse = 0, |
| 215 | .cmap_static = 0, | 215 | .cmap_static = 0, |
| 216 | .lccr0 = LCCR0_SDS, | 216 | .lccr0 = LCCR0_SDS, |
| 217 | .lccr3 = LCCR3_PCP | LCCR3_Acb(255), | 217 | .lccr3 = LCCR3_PCP | LCCR3_Acb(255), |
| 218 | }; | 218 | }; |
| 219 | 219 | ||
| 220 | static int lubbock_mci_init(struct device *dev, irqreturn_t (*lubbock_detect_int)(int, void *, struct pt_regs *), void *data) | 220 | static int lubbock_mci_init(struct device *dev, irqreturn_t (*lubbock_detect_int)(int, void *, struct pt_regs *), void *data) |
| 221 | { | 221 | { |
| 222 | /* setup GPIO for PXA25x MMC controller */ | 222 | /* setup GPIO for PXA25x MMC controller */ |
| 223 | pxa_gpio_mode(GPIO6_MMCCLK_MD); | 223 | pxa_gpio_mode(GPIO6_MMCCLK_MD); |
| 224 | pxa_gpio_mode(GPIO8_MMCCS0_MD); | 224 | pxa_gpio_mode(GPIO8_MMCCS0_MD); |
| 225 | 225 | ||
| 226 | return 0; | 226 | return 0; |
| 227 | } | 227 | } |
| 228 | 228 | ||
| 229 | static struct pxamci_platform_data lubbock_mci_platform_data = { | 229 | static struct pxamci_platform_data lubbock_mci_platform_data = { |
| 230 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, | 230 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, |
| 231 | .init = lubbock_mci_init, | 231 | .init = lubbock_mci_init, |
| 232 | }; | 232 | }; |
| 233 | 233 | ||
| 234 | static void __init lubbock_init(void) | 234 | static void __init lubbock_init(void) |
| 235 | { | 235 | { |
| 236 | pxa_set_udc_info(&udc_info); | 236 | pxa_set_udc_info(&udc_info); |
| 237 | set_pxa_fb_info(&sharp_lm8v31); | 237 | set_pxa_fb_info(&sharp_lm8v31); |
| 238 | pxa_set_mci_info(&lubbock_mci_platform_data); | 238 | pxa_set_mci_info(&lubbock_mci_platform_data); |
| 239 | (void) platform_add_devices(devices, ARRAY_SIZE(devices)); | 239 | (void) platform_add_devices(devices, ARRAY_SIZE(devices)); |
| 240 | } | 240 | } |
| 241 | 241 | ||
| 242 | static struct map_desc lubbock_io_desc[] __initdata = { | 242 | static struct map_desc lubbock_io_desc[] __initdata = { |
| 243 | { LUBBOCK_FPGA_VIRT, LUBBOCK_FPGA_PHYS, 0x00100000, MT_DEVICE }, /* CPLD */ | 243 | { LUBBOCK_FPGA_VIRT, LUBBOCK_FPGA_PHYS, 0x00100000, MT_DEVICE }, /* CPLD */ |
| 244 | }; | 244 | }; |
| 245 | 245 | ||
| 246 | static void __init lubbock_map_io(void) | 246 | static void __init lubbock_map_io(void) |
| 247 | { | 247 | { |
| 248 | pxa_map_io(); | 248 | pxa_map_io(); |
| 249 | iotable_init(lubbock_io_desc, ARRAY_SIZE(lubbock_io_desc)); | 249 | iotable_init(lubbock_io_desc, ARRAY_SIZE(lubbock_io_desc)); |
| 250 | 250 | ||
| 251 | /* This enables the BTUART */ | 251 | /* This enables the BTUART */ |
| 252 | pxa_gpio_mode(GPIO42_BTRXD_MD); | 252 | pxa_gpio_mode(GPIO42_BTRXD_MD); |
| 253 | pxa_gpio_mode(GPIO43_BTTXD_MD); | 253 | pxa_gpio_mode(GPIO43_BTTXD_MD); |
| 254 | pxa_gpio_mode(GPIO44_BTCTS_MD); | 254 | pxa_gpio_mode(GPIO44_BTCTS_MD); |
| 255 | pxa_gpio_mode(GPIO45_BTRTS_MD); | 255 | pxa_gpio_mode(GPIO45_BTRTS_MD); |
| 256 | 256 | ||
| 257 | /* This is for the SMC chip select */ | 257 | /* This is for the SMC chip select */ |
| 258 | pxa_gpio_mode(GPIO79_nCS_3_MD); | 258 | pxa_gpio_mode(GPIO79_nCS_3_MD); |
| 259 | 259 | ||
| 260 | /* setup sleep mode values */ | 260 | /* setup sleep mode values */ |
| 261 | PWER = 0x00000002; | 261 | PWER = 0x00000002; |
| 262 | PFER = 0x00000000; | 262 | PFER = 0x00000000; |
| 263 | PRER = 0x00000002; | 263 | PRER = 0x00000002; |
| 264 | PGSR0 = 0x00008000; | 264 | PGSR0 = 0x00008000; |
| 265 | PGSR1 = 0x003F0202; | 265 | PGSR1 = 0x003F0202; |
| 266 | PGSR2 = 0x0001C000; | 266 | PGSR2 = 0x0001C000; |
| 267 | PCFR |= PCFR_OPDE; | 267 | PCFR |= PCFR_OPDE; |
| 268 | } | 268 | } |
| 269 | 269 | ||
| 270 | MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform (aka Lubbock)") | 270 | MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform (aka Lubbock)") |
| 271 | /* Maintainer: MontaVista Software Inc. */ | 271 | /* Maintainer: MontaVista Software Inc. */ |
| 272 | .phys_ram = 0xa0000000, | 272 | .phys_ram = 0xa0000000, |
| 273 | .phys_io = 0x40000000, | 273 | .phys_io = 0x40000000, |
| 274 | .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, | 274 | .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, |
| 275 | .map_io = lubbock_map_io, | 275 | .map_io = lubbock_map_io, |
| 276 | .init_irq = lubbock_init_irq, | 276 | .init_irq = lubbock_init_irq, |
| 277 | .timer = &pxa_timer, | 277 | .timer = &pxa_timer, |
| 278 | .init_machine = lubbock_init, | 278 | .init_machine = lubbock_init, |
| 279 | MACHINE_END | 279 | MACHINE_END |
| 280 | 280 |
arch/arm/mach-pxa/mainstone.c
| 1 | /* | 1 | /* |
| 2 | * linux/arch/arm/mach-pxa/mainstone.c | 2 | * linux/arch/arm/mach-pxa/mainstone.c |
| 3 | * | 3 | * |
| 4 | * Support for the Intel HCDDBBVA0 Development Platform. | 4 | * Support for the Intel HCDDBBVA0 Development Platform. |
| 5 | * (go figure how they came up with such name...) | 5 | * (go figure how they came up with such name...) |
| 6 | * | 6 | * |
| 7 | * Author: Nicolas Pitre | 7 | * Author: Nicolas Pitre |
| 8 | * Created: Nov 05, 2002 | 8 | * Created: Nov 05, 2002 |
| 9 | * Copyright: MontaVista Software Inc. | 9 | * Copyright: MontaVista Software Inc. |
| 10 | * | 10 | * |
| 11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
| 13 | * published by the Free Software Foundation. | 13 | * published by the Free Software Foundation. |
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| 16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
| 17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
| 18 | #include <linux/sysdev.h> | 18 | #include <linux/sysdev.h> |
| 19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
| 20 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
| 21 | #include <linux/bitops.h> | 21 | #include <linux/bitops.h> |
| 22 | #include <linux/fb.h> | 22 | #include <linux/fb.h> |
| 23 | 23 | ||
| 24 | #include <asm/types.h> | 24 | #include <asm/types.h> |
| 25 | #include <asm/setup.h> | 25 | #include <asm/setup.h> |
| 26 | #include <asm/memory.h> | 26 | #include <asm/memory.h> |
| 27 | #include <asm/mach-types.h> | 27 | #include <asm/mach-types.h> |
| 28 | #include <asm/hardware.h> | 28 | #include <asm/hardware.h> |
| 29 | #include <asm/irq.h> | 29 | #include <asm/irq.h> |
| 30 | 30 | ||
| 31 | #include <asm/mach/arch.h> | 31 | #include <asm/mach/arch.h> |
| 32 | #include <asm/mach/map.h> | 32 | #include <asm/mach/map.h> |
| 33 | #include <asm/mach/irq.h> | 33 | #include <asm/mach/irq.h> |
| 34 | 34 | ||
| 35 | #include <asm/arch/pxa-regs.h> | 35 | #include <asm/arch/pxa-regs.h> |
| 36 | #include <asm/arch/mainstone.h> | 36 | #include <asm/arch/mainstone.h> |
| 37 | #include <asm/arch/audio.h> | 37 | #include <asm/arch/audio.h> |
| 38 | #include <asm/arch/pxafb.h> | 38 | #include <asm/arch/pxafb.h> |
| 39 | #include <asm/arch/mmc.h> | 39 | #include <asm/arch/mmc.h> |
| 40 | 40 | ||
| 41 | #include "generic.h" | 41 | #include "generic.h" |
| 42 | 42 | ||
| 43 | 43 | ||
| 44 | static unsigned long mainstone_irq_enabled; | 44 | static unsigned long mainstone_irq_enabled; |
| 45 | 45 | ||
| 46 | static void mainstone_mask_irq(unsigned int irq) | 46 | static void mainstone_mask_irq(unsigned int irq) |
| 47 | { | 47 | { |
| 48 | int mainstone_irq = (irq - MAINSTONE_IRQ(0)); | 48 | int mainstone_irq = (irq - MAINSTONE_IRQ(0)); |
| 49 | MST_INTMSKENA = (mainstone_irq_enabled &= ~(1 << mainstone_irq)); | 49 | MST_INTMSKENA = (mainstone_irq_enabled &= ~(1 << mainstone_irq)); |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | static void mainstone_unmask_irq(unsigned int irq) | 52 | static void mainstone_unmask_irq(unsigned int irq) |
| 53 | { | 53 | { |
| 54 | int mainstone_irq = (irq - MAINSTONE_IRQ(0)); | 54 | int mainstone_irq = (irq - MAINSTONE_IRQ(0)); |
| 55 | /* the irq can be acknowledged only if deasserted, so it's done here */ | 55 | /* the irq can be acknowledged only if deasserted, so it's done here */ |
| 56 | MST_INTSETCLR &= ~(1 << mainstone_irq); | 56 | MST_INTSETCLR &= ~(1 << mainstone_irq); |
| 57 | MST_INTMSKENA = (mainstone_irq_enabled |= (1 << mainstone_irq)); | 57 | MST_INTMSKENA = (mainstone_irq_enabled |= (1 << mainstone_irq)); |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | static struct irqchip mainstone_irq_chip = { | 60 | static struct irqchip mainstone_irq_chip = { |
| 61 | .ack = mainstone_mask_irq, | 61 | .ack = mainstone_mask_irq, |
| 62 | .mask = mainstone_mask_irq, | 62 | .mask = mainstone_mask_irq, |
| 63 | .unmask = mainstone_unmask_irq, | 63 | .unmask = mainstone_unmask_irq, |
| 64 | }; | 64 | }; |
| 65 | 65 | ||
| 66 | static void mainstone_irq_handler(unsigned int irq, struct irqdesc *desc, | 66 | static void mainstone_irq_handler(unsigned int irq, struct irqdesc *desc, |
| 67 | struct pt_regs *regs) | 67 | struct pt_regs *regs) |
| 68 | { | 68 | { |
| 69 | unsigned long pending = MST_INTSETCLR & mainstone_irq_enabled; | 69 | unsigned long pending = MST_INTSETCLR & mainstone_irq_enabled; |
| 70 | do { | 70 | do { |
| 71 | GEDR(0) = GPIO_bit(0); /* clear useless edge notification */ | 71 | GEDR(0) = GPIO_bit(0); /* clear useless edge notification */ |
| 72 | if (likely(pending)) { | 72 | if (likely(pending)) { |
| 73 | irq = MAINSTONE_IRQ(0) + __ffs(pending); | 73 | irq = MAINSTONE_IRQ(0) + __ffs(pending); |
| 74 | desc = irq_desc + irq; | 74 | desc = irq_desc + irq; |
| 75 | desc->handle(irq, desc, regs); | 75 | desc_handle_irq(irq, desc, regs); |
| 76 | } | 76 | } |
| 77 | pending = MST_INTSETCLR & mainstone_irq_enabled; | 77 | pending = MST_INTSETCLR & mainstone_irq_enabled; |
| 78 | } while (pending); | 78 | } while (pending); |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | static void __init mainstone_init_irq(void) | 81 | static void __init mainstone_init_irq(void) |
| 82 | { | 82 | { |
| 83 | int irq; | 83 | int irq; |
| 84 | 84 | ||
| 85 | pxa_init_irq(); | 85 | pxa_init_irq(); |
| 86 | 86 | ||
| 87 | /* setup extra Mainstone irqs */ | 87 | /* setup extra Mainstone irqs */ |
| 88 | for(irq = MAINSTONE_IRQ(0); irq <= MAINSTONE_IRQ(15); irq++) { | 88 | for(irq = MAINSTONE_IRQ(0); irq <= MAINSTONE_IRQ(15); irq++) { |
| 89 | set_irq_chip(irq, &mainstone_irq_chip); | 89 | set_irq_chip(irq, &mainstone_irq_chip); |
| 90 | set_irq_handler(irq, do_level_IRQ); | 90 | set_irq_handler(irq, do_level_IRQ); |
| 91 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 91 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
| 92 | } | 92 | } |
| 93 | set_irq_flags(MAINSTONE_IRQ(8), 0); | 93 | set_irq_flags(MAINSTONE_IRQ(8), 0); |
| 94 | set_irq_flags(MAINSTONE_IRQ(12), 0); | 94 | set_irq_flags(MAINSTONE_IRQ(12), 0); |
| 95 | 95 | ||
| 96 | MST_INTMSKENA = 0; | 96 | MST_INTMSKENA = 0; |
| 97 | MST_INTSETCLR = 0; | 97 | MST_INTSETCLR = 0; |
| 98 | 98 | ||
| 99 | set_irq_chained_handler(IRQ_GPIO(0), mainstone_irq_handler); | 99 | set_irq_chained_handler(IRQ_GPIO(0), mainstone_irq_handler); |
| 100 | set_irq_type(IRQ_GPIO(0), IRQT_FALLING); | 100 | set_irq_type(IRQ_GPIO(0), IRQT_FALLING); |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | #ifdef CONFIG_PM | 103 | #ifdef CONFIG_PM |
| 104 | 104 | ||
| 105 | static int mainstone_irq_resume(struct sys_device *dev) | 105 | static int mainstone_irq_resume(struct sys_device *dev) |
| 106 | { | 106 | { |
| 107 | MST_INTMSKENA = mainstone_irq_enabled; | 107 | MST_INTMSKENA = mainstone_irq_enabled; |
| 108 | return 0; | 108 | return 0; |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | static struct sysdev_class mainstone_irq_sysclass = { | 111 | static struct sysdev_class mainstone_irq_sysclass = { |
| 112 | set_kset_name("cpld_irq"), | 112 | set_kset_name("cpld_irq"), |
| 113 | .resume = mainstone_irq_resume, | 113 | .resume = mainstone_irq_resume, |
| 114 | }; | 114 | }; |
| 115 | 115 | ||
| 116 | static struct sys_device mainstone_irq_device = { | 116 | static struct sys_device mainstone_irq_device = { |
| 117 | .cls = &mainstone_irq_sysclass, | 117 | .cls = &mainstone_irq_sysclass, |
| 118 | }; | 118 | }; |
| 119 | 119 | ||
| 120 | static int __init mainstone_irq_device_init(void) | 120 | static int __init mainstone_irq_device_init(void) |
| 121 | { | 121 | { |
| 122 | int ret = sysdev_class_register(&mainstone_irq_sysclass); | 122 | int ret = sysdev_class_register(&mainstone_irq_sysclass); |
| 123 | if (ret == 0) | 123 | if (ret == 0) |
| 124 | ret = sysdev_register(&mainstone_irq_device); | 124 | ret = sysdev_register(&mainstone_irq_device); |
| 125 | return ret; | 125 | return ret; |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | device_initcall(mainstone_irq_device_init); | 128 | device_initcall(mainstone_irq_device_init); |
| 129 | 129 | ||
| 130 | #endif | 130 | #endif |
| 131 | 131 | ||
| 132 | 132 | ||
| 133 | static struct resource smc91x_resources[] = { | 133 | static struct resource smc91x_resources[] = { |
| 134 | [0] = { | 134 | [0] = { |
| 135 | .start = (MST_ETH_PHYS + 0x300), | 135 | .start = (MST_ETH_PHYS + 0x300), |
| 136 | .end = (MST_ETH_PHYS + 0xfffff), | 136 | .end = (MST_ETH_PHYS + 0xfffff), |
| 137 | .flags = IORESOURCE_MEM, | 137 | .flags = IORESOURCE_MEM, |
| 138 | }, | 138 | }, |
| 139 | [1] = { | 139 | [1] = { |
| 140 | .start = MAINSTONE_IRQ(3), | 140 | .start = MAINSTONE_IRQ(3), |
| 141 | .end = MAINSTONE_IRQ(3), | 141 | .end = MAINSTONE_IRQ(3), |
| 142 | .flags = IORESOURCE_IRQ, | 142 | .flags = IORESOURCE_IRQ, |
| 143 | } | 143 | } |
| 144 | }; | 144 | }; |
| 145 | 145 | ||
| 146 | static struct platform_device smc91x_device = { | 146 | static struct platform_device smc91x_device = { |
| 147 | .name = "smc91x", | 147 | .name = "smc91x", |
| 148 | .id = 0, | 148 | .id = 0, |
| 149 | .num_resources = ARRAY_SIZE(smc91x_resources), | 149 | .num_resources = ARRAY_SIZE(smc91x_resources), |
| 150 | .resource = smc91x_resources, | 150 | .resource = smc91x_resources, |
| 151 | }; | 151 | }; |
| 152 | 152 | ||
| 153 | static int mst_audio_startup(snd_pcm_substream_t *substream, void *priv) | 153 | static int mst_audio_startup(snd_pcm_substream_t *substream, void *priv) |
| 154 | { | 154 | { |
| 155 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 155 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
| 156 | MST_MSCWR2 &= ~MST_MSCWR2_AC97_SPKROFF; | 156 | MST_MSCWR2 &= ~MST_MSCWR2_AC97_SPKROFF; |
| 157 | return 0; | 157 | return 0; |
| 158 | } | 158 | } |
| 159 | 159 | ||
| 160 | static void mst_audio_shutdown(snd_pcm_substream_t *substream, void *priv) | 160 | static void mst_audio_shutdown(snd_pcm_substream_t *substream, void *priv) |
| 161 | { | 161 | { |
| 162 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 162 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
| 163 | MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF; | 163 | MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF; |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | static long mst_audio_suspend_mask; | 166 | static long mst_audio_suspend_mask; |
| 167 | 167 | ||
| 168 | static void mst_audio_suspend(void *priv) | 168 | static void mst_audio_suspend(void *priv) |
| 169 | { | 169 | { |
| 170 | mst_audio_suspend_mask = MST_MSCWR2; | 170 | mst_audio_suspend_mask = MST_MSCWR2; |
| 171 | MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF; | 171 | MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF; |
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | static void mst_audio_resume(void *priv) | 174 | static void mst_audio_resume(void *priv) |
| 175 | { | 175 | { |
| 176 | MST_MSCWR2 &= mst_audio_suspend_mask | ~MST_MSCWR2_AC97_SPKROFF; | 176 | MST_MSCWR2 &= mst_audio_suspend_mask | ~MST_MSCWR2_AC97_SPKROFF; |
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | static pxa2xx_audio_ops_t mst_audio_ops = { | 179 | static pxa2xx_audio_ops_t mst_audio_ops = { |
| 180 | .startup = mst_audio_startup, | 180 | .startup = mst_audio_startup, |
| 181 | .shutdown = mst_audio_shutdown, | 181 | .shutdown = mst_audio_shutdown, |
| 182 | .suspend = mst_audio_suspend, | 182 | .suspend = mst_audio_suspend, |
| 183 | .resume = mst_audio_resume, | 183 | .resume = mst_audio_resume, |
| 184 | }; | 184 | }; |
| 185 | 185 | ||
| 186 | static struct platform_device mst_audio_device = { | 186 | static struct platform_device mst_audio_device = { |
| 187 | .name = "pxa2xx-ac97", | 187 | .name = "pxa2xx-ac97", |
| 188 | .id = -1, | 188 | .id = -1, |
| 189 | .dev = { .platform_data = &mst_audio_ops }, | 189 | .dev = { .platform_data = &mst_audio_ops }, |
| 190 | }; | 190 | }; |
| 191 | 191 | ||
| 192 | static void mainstone_backlight_power(int on) | 192 | static void mainstone_backlight_power(int on) |
| 193 | { | 193 | { |
| 194 | if (on) { | 194 | if (on) { |
| 195 | pxa_gpio_mode(GPIO16_PWM0_MD); | 195 | pxa_gpio_mode(GPIO16_PWM0_MD); |
| 196 | pxa_set_cken(CKEN0_PWM0, 1); | 196 | pxa_set_cken(CKEN0_PWM0, 1); |
| 197 | PWM_CTRL0 = 0; | 197 | PWM_CTRL0 = 0; |
| 198 | PWM_PWDUTY0 = 0x3ff; | 198 | PWM_PWDUTY0 = 0x3ff; |
| 199 | PWM_PERVAL0 = 0x3ff; | 199 | PWM_PERVAL0 = 0x3ff; |
| 200 | } else { | 200 | } else { |
| 201 | PWM_CTRL0 = 0; | 201 | PWM_CTRL0 = 0; |
| 202 | PWM_PWDUTY0 = 0x0; | 202 | PWM_PWDUTY0 = 0x0; |
| 203 | PWM_PERVAL0 = 0x3FF; | 203 | PWM_PERVAL0 = 0x3FF; |
| 204 | pxa_set_cken(CKEN0_PWM0, 0); | 204 | pxa_set_cken(CKEN0_PWM0, 0); |
| 205 | } | 205 | } |
| 206 | } | 206 | } |
| 207 | 207 | ||
| 208 | static struct pxafb_mach_info toshiba_ltm04c380k __initdata = { | 208 | static struct pxafb_mach_info toshiba_ltm04c380k __initdata = { |
| 209 | .pixclock = 50000, | 209 | .pixclock = 50000, |
| 210 | .xres = 640, | 210 | .xres = 640, |
| 211 | .yres = 480, | 211 | .yres = 480, |
| 212 | .bpp = 16, | 212 | .bpp = 16, |
| 213 | .hsync_len = 1, | 213 | .hsync_len = 1, |
| 214 | .left_margin = 0x9f, | 214 | .left_margin = 0x9f, |
| 215 | .right_margin = 1, | 215 | .right_margin = 1, |
| 216 | .vsync_len = 44, | 216 | .vsync_len = 44, |
| 217 | .upper_margin = 0, | 217 | .upper_margin = 0, |
| 218 | .lower_margin = 0, | 218 | .lower_margin = 0, |
| 219 | .sync = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, | 219 | .sync = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, |
| 220 | .lccr0 = LCCR0_Act, | 220 | .lccr0 = LCCR0_Act, |
| 221 | .lccr3 = LCCR3_PCP, | 221 | .lccr3 = LCCR3_PCP, |
| 222 | .pxafb_backlight_power = mainstone_backlight_power, | 222 | .pxafb_backlight_power = mainstone_backlight_power, |
| 223 | }; | 223 | }; |
| 224 | 224 | ||
| 225 | static struct pxafb_mach_info toshiba_ltm035a776c __initdata = { | 225 | static struct pxafb_mach_info toshiba_ltm035a776c __initdata = { |
| 226 | .pixclock = 110000, | 226 | .pixclock = 110000, |
| 227 | .xres = 240, | 227 | .xres = 240, |
| 228 | .yres = 320, | 228 | .yres = 320, |
| 229 | .bpp = 16, | 229 | .bpp = 16, |
| 230 | .hsync_len = 4, | 230 | .hsync_len = 4, |
| 231 | .left_margin = 8, | 231 | .left_margin = 8, |
| 232 | .right_margin = 20, | 232 | .right_margin = 20, |
| 233 | .vsync_len = 3, | 233 | .vsync_len = 3, |
| 234 | .upper_margin = 1, | 234 | .upper_margin = 1, |
| 235 | .lower_margin = 10, | 235 | .lower_margin = 10, |
| 236 | .sync = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, | 236 | .sync = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, |
| 237 | .lccr0 = LCCR0_Act, | 237 | .lccr0 = LCCR0_Act, |
| 238 | .lccr3 = LCCR3_PCP, | 238 | .lccr3 = LCCR3_PCP, |
| 239 | .pxafb_backlight_power = mainstone_backlight_power, | 239 | .pxafb_backlight_power = mainstone_backlight_power, |
| 240 | }; | 240 | }; |
| 241 | 241 | ||
| 242 | static int mainstone_mci_init(struct device *dev, irqreturn_t (*mstone_detect_int)(int, void *, struct pt_regs *), void *data) | 242 | static int mainstone_mci_init(struct device *dev, irqreturn_t (*mstone_detect_int)(int, void *, struct pt_regs *), void *data) |
| 243 | { | 243 | { |
| 244 | int err; | 244 | int err; |
| 245 | 245 | ||
| 246 | /* | 246 | /* |
| 247 | * setup GPIO for PXA27x MMC controller | 247 | * setup GPIO for PXA27x MMC controller |
| 248 | */ | 248 | */ |
| 249 | pxa_gpio_mode(GPIO32_MMCCLK_MD); | 249 | pxa_gpio_mode(GPIO32_MMCCLK_MD); |
| 250 | pxa_gpio_mode(GPIO112_MMCCMD_MD); | 250 | pxa_gpio_mode(GPIO112_MMCCMD_MD); |
| 251 | pxa_gpio_mode(GPIO92_MMCDAT0_MD); | 251 | pxa_gpio_mode(GPIO92_MMCDAT0_MD); |
| 252 | pxa_gpio_mode(GPIO109_MMCDAT1_MD); | 252 | pxa_gpio_mode(GPIO109_MMCDAT1_MD); |
| 253 | pxa_gpio_mode(GPIO110_MMCDAT2_MD); | 253 | pxa_gpio_mode(GPIO110_MMCDAT2_MD); |
| 254 | pxa_gpio_mode(GPIO111_MMCDAT3_MD); | 254 | pxa_gpio_mode(GPIO111_MMCDAT3_MD); |
| 255 | 255 | ||
| 256 | /* make sure SD/Memory Stick multiplexer's signals | 256 | /* make sure SD/Memory Stick multiplexer's signals |
| 257 | * are routed to MMC controller | 257 | * are routed to MMC controller |
| 258 | */ | 258 | */ |
| 259 | MST_MSCWR1 &= ~MST_MSCWR1_MS_SEL; | 259 | MST_MSCWR1 &= ~MST_MSCWR1_MS_SEL; |
| 260 | 260 | ||
| 261 | err = request_irq(MAINSTONE_MMC_IRQ, mstone_detect_int, SA_INTERRUPT, | 261 | err = request_irq(MAINSTONE_MMC_IRQ, mstone_detect_int, SA_INTERRUPT, |
| 262 | "MMC card detect", data); | 262 | "MMC card detect", data); |
| 263 | if (err) { | 263 | if (err) { |
| 264 | printk(KERN_ERR "mainstone_mci_init: MMC/SD: can't request MMC card detect IRQ\n"); | 264 | printk(KERN_ERR "mainstone_mci_init: MMC/SD: can't request MMC card detect IRQ\n"); |
| 265 | return -1; | 265 | return -1; |
| 266 | } | 266 | } |
| 267 | 267 | ||
| 268 | return 0; | 268 | return 0; |
| 269 | } | 269 | } |
| 270 | 270 | ||
| 271 | static void mainstone_mci_setpower(struct device *dev, unsigned int vdd) | 271 | static void mainstone_mci_setpower(struct device *dev, unsigned int vdd) |
| 272 | { | 272 | { |
| 273 | struct pxamci_platform_data* p_d = dev->platform_data; | 273 | struct pxamci_platform_data* p_d = dev->platform_data; |
| 274 | 274 | ||
| 275 | if (( 1 << vdd) & p_d->ocr_mask) { | 275 | if (( 1 << vdd) & p_d->ocr_mask) { |
| 276 | printk(KERN_DEBUG "%s: on\n", __FUNCTION__); | 276 | printk(KERN_DEBUG "%s: on\n", __FUNCTION__); |
| 277 | MST_MSCWR1 |= MST_MSCWR1_MMC_ON; | 277 | MST_MSCWR1 |= MST_MSCWR1_MMC_ON; |
| 278 | MST_MSCWR1 &= ~MST_MSCWR1_MS_SEL; | 278 | MST_MSCWR1 &= ~MST_MSCWR1_MS_SEL; |
| 279 | } else { | 279 | } else { |
| 280 | printk(KERN_DEBUG "%s: off\n", __FUNCTION__); | 280 | printk(KERN_DEBUG "%s: off\n", __FUNCTION__); |
| 281 | MST_MSCWR1 &= ~MST_MSCWR1_MMC_ON; | 281 | MST_MSCWR1 &= ~MST_MSCWR1_MMC_ON; |
| 282 | } | 282 | } |
| 283 | } | 283 | } |
| 284 | 284 | ||
| 285 | static void mainstone_mci_exit(struct device *dev, void *data) | 285 | static void mainstone_mci_exit(struct device *dev, void *data) |
| 286 | { | 286 | { |
| 287 | free_irq(MAINSTONE_MMC_IRQ, data); | 287 | free_irq(MAINSTONE_MMC_IRQ, data); |
| 288 | } | 288 | } |
| 289 | 289 | ||
| 290 | static struct pxamci_platform_data mainstone_mci_platform_data = { | 290 | static struct pxamci_platform_data mainstone_mci_platform_data = { |
| 291 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, | 291 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, |
| 292 | .init = mainstone_mci_init, | 292 | .init = mainstone_mci_init, |
| 293 | .setpower = mainstone_mci_setpower, | 293 | .setpower = mainstone_mci_setpower, |
| 294 | .exit = mainstone_mci_exit, | 294 | .exit = mainstone_mci_exit, |
| 295 | }; | 295 | }; |
| 296 | 296 | ||
| 297 | static void __init mainstone_init(void) | 297 | static void __init mainstone_init(void) |
| 298 | { | 298 | { |
| 299 | /* | 299 | /* |
| 300 | * On Mainstone, we route AC97_SYSCLK via GPIO45 to | 300 | * On Mainstone, we route AC97_SYSCLK via GPIO45 to |
| 301 | * the audio daughter card | 301 | * the audio daughter card |
| 302 | */ | 302 | */ |
| 303 | pxa_gpio_mode(GPIO45_SYSCLK_AC97_MD); | 303 | pxa_gpio_mode(GPIO45_SYSCLK_AC97_MD); |
| 304 | 304 | ||
| 305 | platform_device_register(&smc91x_device); | 305 | platform_device_register(&smc91x_device); |
| 306 | platform_device_register(&mst_audio_device); | 306 | platform_device_register(&mst_audio_device); |
| 307 | 307 | ||
| 308 | /* reading Mainstone's "Virtual Configuration Register" | 308 | /* reading Mainstone's "Virtual Configuration Register" |
| 309 | might be handy to select LCD type here */ | 309 | might be handy to select LCD type here */ |
| 310 | if (0) | 310 | if (0) |
| 311 | set_pxa_fb_info(&toshiba_ltm04c380k); | 311 | set_pxa_fb_info(&toshiba_ltm04c380k); |
| 312 | else | 312 | else |
| 313 | set_pxa_fb_info(&toshiba_ltm035a776c); | 313 | set_pxa_fb_info(&toshiba_ltm035a776c); |
| 314 | 314 | ||
| 315 | pxa_set_mci_info(&mainstone_mci_platform_data); | 315 | pxa_set_mci_info(&mainstone_mci_platform_data); |
| 316 | } | 316 | } |
| 317 | 317 | ||
| 318 | 318 | ||
| 319 | static struct map_desc mainstone_io_desc[] __initdata = { | 319 | static struct map_desc mainstone_io_desc[] __initdata = { |
| 320 | { MST_FPGA_VIRT, MST_FPGA_PHYS, 0x00100000, MT_DEVICE }, /* CPLD */ | 320 | { MST_FPGA_VIRT, MST_FPGA_PHYS, 0x00100000, MT_DEVICE }, /* CPLD */ |
| 321 | }; | 321 | }; |
| 322 | 322 | ||
| 323 | static void __init mainstone_map_io(void) | 323 | static void __init mainstone_map_io(void) |
| 324 | { | 324 | { |
| 325 | pxa_map_io(); | 325 | pxa_map_io(); |
| 326 | iotable_init(mainstone_io_desc, ARRAY_SIZE(mainstone_io_desc)); | 326 | iotable_init(mainstone_io_desc, ARRAY_SIZE(mainstone_io_desc)); |
| 327 | 327 | ||
| 328 | /* initialize sleep mode regs (wake-up sources, etc) */ | 328 | /* initialize sleep mode regs (wake-up sources, etc) */ |
| 329 | PGSR0 = 0x00008800; | 329 | PGSR0 = 0x00008800; |
| 330 | PGSR1 = 0x00000002; | 330 | PGSR1 = 0x00000002; |
| 331 | PGSR2 = 0x0001FC00; | 331 | PGSR2 = 0x0001FC00; |
| 332 | PGSR3 = 0x00001F81; | 332 | PGSR3 = 0x00001F81; |
| 333 | PWER = 0xC0000002; | 333 | PWER = 0xC0000002; |
| 334 | PRER = 0x00000002; | 334 | PRER = 0x00000002; |
| 335 | PFER = 0x00000002; | 335 | PFER = 0x00000002; |
| 336 | /* for use I SRAM as framebuffer. */ | 336 | /* for use I SRAM as framebuffer. */ |
| 337 | PSLR |= 0xF04; | 337 | PSLR |= 0xF04; |
| 338 | PCFR = 0x66; | 338 | PCFR = 0x66; |
| 339 | /* For Keypad wakeup. */ | 339 | /* For Keypad wakeup. */ |
| 340 | KPC &=~KPC_ASACT; | 340 | KPC &=~KPC_ASACT; |
| 341 | KPC |=KPC_AS; | 341 | KPC |=KPC_AS; |
| 342 | PKWR = 0x000FD000; | 342 | PKWR = 0x000FD000; |
| 343 | /* Need read PKWR back after set it. */ | 343 | /* Need read PKWR back after set it. */ |
| 344 | PKWR; | 344 | PKWR; |
| 345 | } | 345 | } |
| 346 | 346 | ||
| 347 | MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)") | 347 | MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)") |
| 348 | /* Maintainer: MontaVista Software Inc. */ | 348 | /* Maintainer: MontaVista Software Inc. */ |
| 349 | .phys_ram = 0xa0000000, | 349 | .phys_ram = 0xa0000000, |
| 350 | .phys_io = 0x40000000, | 350 | .phys_io = 0x40000000, |
| 351 | .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, | 351 | .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, |
| 352 | .map_io = mainstone_map_io, | 352 | .map_io = mainstone_map_io, |
| 353 | .init_irq = mainstone_init_irq, | 353 | .init_irq = mainstone_init_irq, |
| 354 | .timer = &pxa_timer, | 354 | .timer = &pxa_timer, |
| 355 | .init_machine = mainstone_init, | 355 | .init_machine = mainstone_init, |
| 356 | MACHINE_END | 356 | MACHINE_END |
| 357 | 357 |
arch/arm/mach-s3c2410/bast-irq.c
| 1 | /* linux/arch/arm/mach-s3c2410/bast-irq.c | 1 | /* linux/arch/arm/mach-s3c2410/bast-irq.c |
| 2 | * | 2 | * |
| 3 | * Copyright (c) 2004 Simtec Electronics | 3 | * Copyright (c) 2004 Simtec Electronics |
| 4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
| 5 | * | 5 | * |
| 6 | * http://www.simtec.co.uk/products/EB2410ITX/ | 6 | * http://www.simtec.co.uk/products/EB2410ITX/ |
| 7 | * | 7 | * |
| 8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
| 9 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
| 10 | * the Free Software Foundation; either version 2 of the License, or | 10 | * the Free Software Foundation; either version 2 of the License, or |
| 11 | * (at your option) any later version. | 11 | * (at your option) any later version. |
| 12 | * | 12 | * |
| 13 | * This program is distributed in the hope that it will be useful, | 13 | * This program is distributed in the hope that it will be useful, |
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
| 17 | * | 17 | * |
| 18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
| 19 | * along with this program; if not, write to the Free Software | 19 | * along with this program; if not, write to the Free Software |
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 21 | * | 21 | * |
| 22 | * Modifications: | 22 | * Modifications: |
| 23 | * 08-Jan-2003 BJD Moved from central IRQ code | 23 | * 08-Jan-2003 BJD Moved from central IRQ code |
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | 26 | ||
| 27 | #include <linux/init.h> | 27 | #include <linux/init.h> |
| 28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
| 29 | #include <linux/ioport.h> | 29 | #include <linux/ioport.h> |
| 30 | #include <linux/ptrace.h> | 30 | #include <linux/ptrace.h> |
| 31 | #include <linux/sysdev.h> | 31 | #include <linux/sysdev.h> |
| 32 | 32 | ||
| 33 | #include <asm/hardware.h> | 33 | #include <asm/hardware.h> |
| 34 | #include <asm/irq.h> | 34 | #include <asm/irq.h> |
| 35 | #include <asm/io.h> | 35 | #include <asm/io.h> |
| 36 | 36 | ||
| 37 | #include <asm/mach/irq.h> | 37 | #include <asm/mach/irq.h> |
| 38 | #include <asm/hardware/s3c2410/irq.h> | 38 | #include <asm/hardware/s3c2410/irq.h> |
| 39 | 39 | ||
| 40 | #if 0 | 40 | #if 0 |
| 41 | #include <asm/debug-ll.h> | 41 | #include <asm/debug-ll.h> |
| 42 | #endif | 42 | #endif |
| 43 | 43 | ||
| 44 | #define irqdbf(x...) | 44 | #define irqdbf(x...) |
| 45 | #define irqdbf2(x...) | 45 | #define irqdbf2(x...) |
| 46 | 46 | ||
| 47 | 47 | ||
| 48 | /* handle PC104 ISA interrupts from the system CPLD */ | 48 | /* handle PC104 ISA interrupts from the system CPLD */ |
| 49 | 49 | ||
| 50 | /* table of ISA irq nos to the relevant mask... zero means | 50 | /* table of ISA irq nos to the relevant mask... zero means |
| 51 | * the irq is not implemented | 51 | * the irq is not implemented |
| 52 | */ | 52 | */ |
| 53 | static unsigned char bast_pc104_irqmasks[] = { | 53 | static unsigned char bast_pc104_irqmasks[] = { |
| 54 | 0, /* 0 */ | 54 | 0, /* 0 */ |
| 55 | 0, /* 1 */ | 55 | 0, /* 1 */ |
| 56 | 0, /* 2 */ | 56 | 0, /* 2 */ |
| 57 | 1, /* 3 */ | 57 | 1, /* 3 */ |
| 58 | 0, /* 4 */ | 58 | 0, /* 4 */ |
| 59 | 2, /* 5 */ | 59 | 2, /* 5 */ |
| 60 | 0, /* 6 */ | 60 | 0, /* 6 */ |
| 61 | 4, /* 7 */ | 61 | 4, /* 7 */ |
| 62 | 0, /* 8 */ | 62 | 0, /* 8 */ |
| 63 | 0, /* 9 */ | 63 | 0, /* 9 */ |
| 64 | 8, /* 10 */ | 64 | 8, /* 10 */ |
| 65 | 0, /* 11 */ | 65 | 0, /* 11 */ |
| 66 | 0, /* 12 */ | 66 | 0, /* 12 */ |
| 67 | 0, /* 13 */ | 67 | 0, /* 13 */ |
| 68 | 0, /* 14 */ | 68 | 0, /* 14 */ |
| 69 | 0, /* 15 */ | 69 | 0, /* 15 */ |
| 70 | }; | 70 | }; |
| 71 | 71 | ||
| 72 | static unsigned char bast_pc104_irqs[] = { 3, 5, 7, 10 }; | 72 | static unsigned char bast_pc104_irqs[] = { 3, 5, 7, 10 }; |
| 73 | 73 | ||
| 74 | static void | 74 | static void |
| 75 | bast_pc104_mask(unsigned int irqno) | 75 | bast_pc104_mask(unsigned int irqno) |
| 76 | { | 76 | { |
| 77 | unsigned long temp; | 77 | unsigned long temp; |
| 78 | 78 | ||
| 79 | temp = __raw_readb(BAST_VA_PC104_IRQMASK); | 79 | temp = __raw_readb(BAST_VA_PC104_IRQMASK); |
| 80 | temp &= ~bast_pc104_irqmasks[irqno]; | 80 | temp &= ~bast_pc104_irqmasks[irqno]; |
| 81 | __raw_writeb(temp, BAST_VA_PC104_IRQMASK); | 81 | __raw_writeb(temp, BAST_VA_PC104_IRQMASK); |
| 82 | 82 | ||
| 83 | if (temp == 0) | 83 | if (temp == 0) |
| 84 | bast_extint_mask(IRQ_ISA); | 84 | bast_extint_mask(IRQ_ISA); |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | static void | 87 | static void |
| 88 | bast_pc104_ack(unsigned int irqno) | 88 | bast_pc104_ack(unsigned int irqno) |
| 89 | { | 89 | { |
| 90 | bast_extint_ack(IRQ_ISA); | 90 | bast_extint_ack(IRQ_ISA); |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | static void | 93 | static void |
| 94 | bast_pc104_unmask(unsigned int irqno) | 94 | bast_pc104_unmask(unsigned int irqno) |
| 95 | { | 95 | { |
| 96 | unsigned long temp; | 96 | unsigned long temp; |
| 97 | 97 | ||
| 98 | temp = __raw_readb(BAST_VA_PC104_IRQMASK); | 98 | temp = __raw_readb(BAST_VA_PC104_IRQMASK); |
| 99 | temp |= bast_pc104_irqmasks[irqno]; | 99 | temp |= bast_pc104_irqmasks[irqno]; |
| 100 | __raw_writeb(temp, BAST_VA_PC104_IRQMASK); | 100 | __raw_writeb(temp, BAST_VA_PC104_IRQMASK); |
| 101 | 101 | ||
| 102 | bast_extint_unmask(IRQ_ISA); | 102 | bast_extint_unmask(IRQ_ISA); |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | static struct bast_pc104_chip = { | 105 | static struct bast_pc104_chip = { |
| 106 | .mask = bast_pc104_mask, | 106 | .mask = bast_pc104_mask, |
| 107 | .unmask = bast_pc104_unmask, | 107 | .unmask = bast_pc104_unmask, |
| 108 | .ack = bast_pc104_ack | 108 | .ack = bast_pc104_ack |
| 109 | }; | 109 | }; |
| 110 | 110 | ||
| 111 | static void | 111 | static void |
| 112 | bast_irq_pc104_demux(unsigned int irq, | 112 | bast_irq_pc104_demux(unsigned int irq, |
| 113 | struct irqdesc *desc, | 113 | struct irqdesc *desc, |
| 114 | struct pt_regs *regs) | 114 | struct pt_regs *regs) |
| 115 | { | 115 | { |
| 116 | unsigned int stat; | 116 | unsigned int stat; |
| 117 | unsigned int irqno; | 117 | unsigned int irqno; |
| 118 | int i; | 118 | int i; |
| 119 | 119 | ||
| 120 | stat = __raw_readb(BAST_VA_PC104_IRQREQ) & 0xf; | 120 | stat = __raw_readb(BAST_VA_PC104_IRQREQ) & 0xf; |
| 121 | 121 | ||
| 122 | for (i = 0; i < 4 && stat != 0; i++) { | 122 | for (i = 0; i < 4 && stat != 0; i++) { |
| 123 | if (stat & 1) { | 123 | if (stat & 1) { |
| 124 | irqno = bast_pc104_irqs[i]; | 124 | irqno = bast_pc104_irqs[i]; |
| 125 | desc = irq_desc + irqno; | 125 | desc = irq_desc + irqno; |
| 126 | 126 | ||
| 127 | desc->handle(irqno, desc, regs); | 127 | desc_handle_irq(irqno, desc, regs); |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | stat >>= 1; | 130 | stat >>= 1; |
| 131 | } | 131 | } |
| 132 | } | 132 | } |
| 133 | 133 |
arch/arm/mach-s3c2410/irq.c
| 1 | /* linux/arch/arm/mach-s3c2410/irq.c | 1 | /* linux/arch/arm/mach-s3c2410/irq.c |
| 2 | * | 2 | * |
| 3 | * Copyright (c) 2003,2004 Simtec Electronics | 3 | * Copyright (c) 2003,2004 Simtec Electronics |
| 4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; either version 2 of the License, or | 8 | * the Free Software Foundation; either version 2 of the License, or |
| 9 | * (at your option) any later version. | 9 | * (at your option) any later version. |
| 10 | * | 10 | * |
| 11 | * This program is distributed in the hope that it will be useful, | 11 | * This program is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | * GNU General Public License for more details. | 14 | * GNU General Public License for more details. |
| 15 | * | 15 | * |
| 16 | * You should have received a copy of the GNU General Public License | 16 | * You should have received a copy of the GNU General Public License |
| 17 | * along with this program; if not, write to the Free Software | 17 | * along with this program; if not, write to the Free Software |
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 19 | * | 19 | * |
| 20 | * Changelog: | 20 | * Changelog: |
| 21 | * | 21 | * |
| 22 | * 22-Jul-2004 Ben Dooks <ben@simtec.co.uk> | 22 | * 22-Jul-2004 Ben Dooks <ben@simtec.co.uk> |
| 23 | * Fixed compile warnings | 23 | * Fixed compile warnings |
| 24 | * | 24 | * |
| 25 | * 22-Jul-2004 Roc Wu <cooloney@yahoo.com.cn> | 25 | * 22-Jul-2004 Roc Wu <cooloney@yahoo.com.cn> |
| 26 | * Fixed s3c_extirq_type | 26 | * Fixed s3c_extirq_type |
| 27 | * | 27 | * |
| 28 | * 21-Jul-2004 Arnaud Patard (Rtp) <arnaud.patard@rtp-net.org> | 28 | * 21-Jul-2004 Arnaud Patard (Rtp) <arnaud.patard@rtp-net.org> |
| 29 | * Addition of ADC/TC demux | 29 | * Addition of ADC/TC demux |
| 30 | * | 30 | * |
| 31 | * 04-Oct-2004 Klaus Fetscher <k.fetscher@fetron.de> | 31 | * 04-Oct-2004 Klaus Fetscher <k.fetscher@fetron.de> |
| 32 | * Fix for set_irq_type() on low EINT numbers | 32 | * Fix for set_irq_type() on low EINT numbers |
| 33 | * | 33 | * |
| 34 | * 05-Oct-2004 Ben Dooks <ben@simtec.co.uk> | 34 | * 05-Oct-2004 Ben Dooks <ben@simtec.co.uk> |
| 35 | * Tidy up KF's patch and sort out new release | 35 | * Tidy up KF's patch and sort out new release |
| 36 | * | 36 | * |
| 37 | * 05-Oct-2004 Ben Dooks <ben@simtec.co.uk> | 37 | * 05-Oct-2004 Ben Dooks <ben@simtec.co.uk> |
| 38 | * Add support for power management controls | 38 | * Add support for power management controls |
| 39 | * | 39 | * |
| 40 | * 04-Nov-2004 Ben Dooks | 40 | * 04-Nov-2004 Ben Dooks |
| 41 | * Fix standard IRQ wake for EINT0..4 and RTC | 41 | * Fix standard IRQ wake for EINT0..4 and RTC |
| 42 | * | 42 | * |
| 43 | * 22-Feb-2005 Ben Dooks | 43 | * 22-Feb-2005 Ben Dooks |
| 44 | * Fixed edge-triggering on ADC IRQ | 44 | * Fixed edge-triggering on ADC IRQ |
| 45 | * | 45 | * |
| 46 | * 28-Jun-2005 Ben Dooks | 46 | * 28-Jun-2005 Ben Dooks |
| 47 | * Mark IRQ_LCD valid | 47 | * Mark IRQ_LCD valid |
| 48 | * | 48 | * |
| 49 | * 25-Jul-2005 Ben Dooks | 49 | * 25-Jul-2005 Ben Dooks |
| 50 | * Split the S3C2440 IRQ code to seperate file | 50 | * Split the S3C2440 IRQ code to seperate file |
| 51 | */ | 51 | */ |
| 52 | 52 | ||
| 53 | #include <linux/init.h> | 53 | #include <linux/init.h> |
| 54 | #include <linux/module.h> | 54 | #include <linux/module.h> |
| 55 | #include <linux/interrupt.h> | 55 | #include <linux/interrupt.h> |
| 56 | #include <linux/ioport.h> | 56 | #include <linux/ioport.h> |
| 57 | #include <linux/ptrace.h> | 57 | #include <linux/ptrace.h> |
| 58 | #include <linux/sysdev.h> | 58 | #include <linux/sysdev.h> |
| 59 | 59 | ||
| 60 | #include <asm/hardware.h> | 60 | #include <asm/hardware.h> |
| 61 | #include <asm/irq.h> | 61 | #include <asm/irq.h> |
| 62 | #include <asm/io.h> | 62 | #include <asm/io.h> |
| 63 | 63 | ||
| 64 | #include <asm/mach/irq.h> | 64 | #include <asm/mach/irq.h> |
| 65 | 65 | ||
| 66 | #include <asm/arch/regs-irq.h> | 66 | #include <asm/arch/regs-irq.h> |
| 67 | #include <asm/arch/regs-gpio.h> | 67 | #include <asm/arch/regs-gpio.h> |
| 68 | 68 | ||
| 69 | #include "cpu.h" | 69 | #include "cpu.h" |
| 70 | #include "pm.h" | 70 | #include "pm.h" |
| 71 | #include "irq.h" | 71 | #include "irq.h" |
| 72 | 72 | ||
| 73 | /* wakeup irq control */ | 73 | /* wakeup irq control */ |
| 74 | 74 | ||
| 75 | #ifdef CONFIG_PM | 75 | #ifdef CONFIG_PM |
| 76 | 76 | ||
| 77 | /* state for IRQs over sleep */ | 77 | /* state for IRQs over sleep */ |
| 78 | 78 | ||
| 79 | /* default is to allow for EINT0..EINT15, and IRQ_RTC as wakeup sources | 79 | /* default is to allow for EINT0..EINT15, and IRQ_RTC as wakeup sources |
| 80 | * | 80 | * |
| 81 | * set bit to 1 in allow bitfield to enable the wakeup settings on it | 81 | * set bit to 1 in allow bitfield to enable the wakeup settings on it |
| 82 | */ | 82 | */ |
| 83 | 83 | ||
| 84 | unsigned long s3c_irqwake_intallow = 1L << (IRQ_RTC - IRQ_EINT0) | 0xfL; | 84 | unsigned long s3c_irqwake_intallow = 1L << (IRQ_RTC - IRQ_EINT0) | 0xfL; |
| 85 | unsigned long s3c_irqwake_intmask = 0xffffffffL; | 85 | unsigned long s3c_irqwake_intmask = 0xffffffffL; |
| 86 | unsigned long s3c_irqwake_eintallow = 0x0000fff0L; | 86 | unsigned long s3c_irqwake_eintallow = 0x0000fff0L; |
| 87 | unsigned long s3c_irqwake_eintmask = 0xffffffffL; | 87 | unsigned long s3c_irqwake_eintmask = 0xffffffffL; |
| 88 | 88 | ||
| 89 | static int | 89 | static int |
| 90 | s3c_irq_wake(unsigned int irqno, unsigned int state) | 90 | s3c_irq_wake(unsigned int irqno, unsigned int state) |
| 91 | { | 91 | { |
| 92 | unsigned long irqbit = 1 << (irqno - IRQ_EINT0); | 92 | unsigned long irqbit = 1 << (irqno - IRQ_EINT0); |
| 93 | 93 | ||
| 94 | if (!(s3c_irqwake_intallow & irqbit)) | 94 | if (!(s3c_irqwake_intallow & irqbit)) |
| 95 | return -ENOENT; | 95 | return -ENOENT; |
| 96 | 96 | ||
| 97 | printk(KERN_INFO "wake %s for irq %d\n", | 97 | printk(KERN_INFO "wake %s for irq %d\n", |
| 98 | state ? "enabled" : "disabled", irqno); | 98 | state ? "enabled" : "disabled", irqno); |
| 99 | 99 | ||
| 100 | if (!state) | 100 | if (!state) |
| 101 | s3c_irqwake_intmask |= irqbit; | 101 | s3c_irqwake_intmask |= irqbit; |
| 102 | else | 102 | else |
| 103 | s3c_irqwake_intmask &= ~irqbit; | 103 | s3c_irqwake_intmask &= ~irqbit; |
| 104 | 104 | ||
| 105 | return 0; | 105 | return 0; |
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | static int | 108 | static int |
| 109 | s3c_irqext_wake(unsigned int irqno, unsigned int state) | 109 | s3c_irqext_wake(unsigned int irqno, unsigned int state) |
| 110 | { | 110 | { |
| 111 | unsigned long bit = 1L << (irqno - EXTINT_OFF); | 111 | unsigned long bit = 1L << (irqno - EXTINT_OFF); |
| 112 | 112 | ||
| 113 | if (!(s3c_irqwake_eintallow & bit)) | 113 | if (!(s3c_irqwake_eintallow & bit)) |
| 114 | return -ENOENT; | 114 | return -ENOENT; |
| 115 | 115 | ||
| 116 | printk(KERN_INFO "wake %s for irq %d\n", | 116 | printk(KERN_INFO "wake %s for irq %d\n", |
| 117 | state ? "enabled" : "disabled", irqno); | 117 | state ? "enabled" : "disabled", irqno); |
| 118 | 118 | ||
| 119 | if (!state) | 119 | if (!state) |
| 120 | s3c_irqwake_eintmask |= bit; | 120 | s3c_irqwake_eintmask |= bit; |
| 121 | else | 121 | else |
| 122 | s3c_irqwake_eintmask &= ~bit; | 122 | s3c_irqwake_eintmask &= ~bit; |
| 123 | 123 | ||
| 124 | return 0; | 124 | return 0; |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | #else | 127 | #else |
| 128 | #define s3c_irqext_wake NULL | 128 | #define s3c_irqext_wake NULL |
| 129 | #define s3c_irq_wake NULL | 129 | #define s3c_irq_wake NULL |
| 130 | #endif | 130 | #endif |
| 131 | 131 | ||
| 132 | 132 | ||
| 133 | static void | 133 | static void |
| 134 | s3c_irq_mask(unsigned int irqno) | 134 | s3c_irq_mask(unsigned int irqno) |
| 135 | { | 135 | { |
| 136 | unsigned long mask; | 136 | unsigned long mask; |
| 137 | 137 | ||
| 138 | irqno -= IRQ_EINT0; | 138 | irqno -= IRQ_EINT0; |
| 139 | 139 | ||
| 140 | mask = __raw_readl(S3C2410_INTMSK); | 140 | mask = __raw_readl(S3C2410_INTMSK); |
| 141 | mask |= 1UL << irqno; | 141 | mask |= 1UL << irqno; |
| 142 | __raw_writel(mask, S3C2410_INTMSK); | 142 | __raw_writel(mask, S3C2410_INTMSK); |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | static inline void | 145 | static inline void |
| 146 | s3c_irq_ack(unsigned int irqno) | 146 | s3c_irq_ack(unsigned int irqno) |
| 147 | { | 147 | { |
| 148 | unsigned long bitval = 1UL << (irqno - IRQ_EINT0); | 148 | unsigned long bitval = 1UL << (irqno - IRQ_EINT0); |
| 149 | 149 | ||
| 150 | __raw_writel(bitval, S3C2410_SRCPND); | 150 | __raw_writel(bitval, S3C2410_SRCPND); |
| 151 | __raw_writel(bitval, S3C2410_INTPND); | 151 | __raw_writel(bitval, S3C2410_INTPND); |
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | static inline void | 154 | static inline void |
| 155 | s3c_irq_maskack(unsigned int irqno) | 155 | s3c_irq_maskack(unsigned int irqno) |
| 156 | { | 156 | { |
| 157 | unsigned long bitval = 1UL << (irqno - IRQ_EINT0); | 157 | unsigned long bitval = 1UL << (irqno - IRQ_EINT0); |
| 158 | unsigned long mask; | 158 | unsigned long mask; |
| 159 | 159 | ||
| 160 | mask = __raw_readl(S3C2410_INTMSK); | 160 | mask = __raw_readl(S3C2410_INTMSK); |
| 161 | __raw_writel(mask|bitval, S3C2410_INTMSK); | 161 | __raw_writel(mask|bitval, S3C2410_INTMSK); |
| 162 | 162 | ||
| 163 | __raw_writel(bitval, S3C2410_SRCPND); | 163 | __raw_writel(bitval, S3C2410_SRCPND); |
| 164 | __raw_writel(bitval, S3C2410_INTPND); | 164 | __raw_writel(bitval, S3C2410_INTPND); |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | 167 | ||
| 168 | static void | 168 | static void |
| 169 | s3c_irq_unmask(unsigned int irqno) | 169 | s3c_irq_unmask(unsigned int irqno) |
| 170 | { | 170 | { |
| 171 | unsigned long mask; | 171 | unsigned long mask; |
| 172 | 172 | ||
| 173 | if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23) | 173 | if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23) |
| 174 | irqdbf2("s3c_irq_unmask %d\n", irqno); | 174 | irqdbf2("s3c_irq_unmask %d\n", irqno); |
| 175 | 175 | ||
| 176 | irqno -= IRQ_EINT0; | 176 | irqno -= IRQ_EINT0; |
| 177 | 177 | ||
| 178 | mask = __raw_readl(S3C2410_INTMSK); | 178 | mask = __raw_readl(S3C2410_INTMSK); |
| 179 | mask &= ~(1UL << irqno); | 179 | mask &= ~(1UL << irqno); |
| 180 | __raw_writel(mask, S3C2410_INTMSK); | 180 | __raw_writel(mask, S3C2410_INTMSK); |
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | struct irqchip s3c_irq_level_chip = { | 183 | struct irqchip s3c_irq_level_chip = { |
| 184 | .ack = s3c_irq_maskack, | 184 | .ack = s3c_irq_maskack, |
| 185 | .mask = s3c_irq_mask, | 185 | .mask = s3c_irq_mask, |
| 186 | .unmask = s3c_irq_unmask, | 186 | .unmask = s3c_irq_unmask, |
| 187 | .wake = s3c_irq_wake | 187 | .set_wake = s3c_irq_wake |
| 188 | }; | 188 | }; |
| 189 | 189 | ||
| 190 | static struct irqchip s3c_irq_chip = { | 190 | static struct irqchip s3c_irq_chip = { |
| 191 | .ack = s3c_irq_ack, | 191 | .ack = s3c_irq_ack, |
| 192 | .mask = s3c_irq_mask, | 192 | .mask = s3c_irq_mask, |
| 193 | .unmask = s3c_irq_unmask, | 193 | .unmask = s3c_irq_unmask, |
| 194 | .wake = s3c_irq_wake | 194 | .set_wake = s3c_irq_wake |
| 195 | }; | 195 | }; |
| 196 | 196 | ||
| 197 | /* S3C2410_EINTMASK | 197 | /* S3C2410_EINTMASK |
| 198 | * S3C2410_EINTPEND | 198 | * S3C2410_EINTPEND |
| 199 | */ | 199 | */ |
| 200 | 200 | ||
| 201 | static void | 201 | static void |
| 202 | s3c_irqext_mask(unsigned int irqno) | 202 | s3c_irqext_mask(unsigned int irqno) |
| 203 | { | 203 | { |
| 204 | unsigned long mask; | 204 | unsigned long mask; |
| 205 | 205 | ||
| 206 | irqno -= EXTINT_OFF; | 206 | irqno -= EXTINT_OFF; |
| 207 | 207 | ||
| 208 | mask = __raw_readl(S3C2410_EINTMASK); | 208 | mask = __raw_readl(S3C2410_EINTMASK); |
| 209 | mask |= ( 1UL << irqno); | 209 | mask |= ( 1UL << irqno); |
| 210 | __raw_writel(mask, S3C2410_EINTMASK); | 210 | __raw_writel(mask, S3C2410_EINTMASK); |
| 211 | 211 | ||
| 212 | if (irqno <= (IRQ_EINT7 - EXTINT_OFF)) { | 212 | if (irqno <= (IRQ_EINT7 - EXTINT_OFF)) { |
| 213 | /* check to see if all need masking */ | 213 | /* check to see if all need masking */ |
| 214 | 214 | ||
| 215 | if ((mask & (0xf << 4)) == (0xf << 4)) { | 215 | if ((mask & (0xf << 4)) == (0xf << 4)) { |
| 216 | /* all masked, mask the parent */ | 216 | /* all masked, mask the parent */ |
| 217 | s3c_irq_mask(IRQ_EINT4t7); | 217 | s3c_irq_mask(IRQ_EINT4t7); |
| 218 | } | 218 | } |
| 219 | } else { | 219 | } else { |
| 220 | /* todo: the same check as above for the rest of the irq regs...*/ | 220 | /* todo: the same check as above for the rest of the irq regs...*/ |
| 221 | 221 | ||
| 222 | } | 222 | } |
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | static void | 225 | static void |
| 226 | s3c_irqext_ack(unsigned int irqno) | 226 | s3c_irqext_ack(unsigned int irqno) |
| 227 | { | 227 | { |
| 228 | unsigned long req; | 228 | unsigned long req; |
| 229 | unsigned long bit; | 229 | unsigned long bit; |
| 230 | unsigned long mask; | 230 | unsigned long mask; |
| 231 | 231 | ||
| 232 | bit = 1UL << (irqno - EXTINT_OFF); | 232 | bit = 1UL << (irqno - EXTINT_OFF); |
| 233 | 233 | ||
| 234 | 234 | ||
| 235 | mask = __raw_readl(S3C2410_EINTMASK); | 235 | mask = __raw_readl(S3C2410_EINTMASK); |
| 236 | 236 | ||
| 237 | __raw_writel(bit, S3C2410_EINTPEND); | 237 | __raw_writel(bit, S3C2410_EINTPEND); |
| 238 | 238 | ||
| 239 | req = __raw_readl(S3C2410_EINTPEND); | 239 | req = __raw_readl(S3C2410_EINTPEND); |
| 240 | req &= ~mask; | 240 | req &= ~mask; |
| 241 | 241 | ||
| 242 | /* not sure if we should be acking the parent irq... */ | 242 | /* not sure if we should be acking the parent irq... */ |
| 243 | 243 | ||
| 244 | if (irqno <= IRQ_EINT7 ) { | 244 | if (irqno <= IRQ_EINT7 ) { |
| 245 | if ((req & 0xf0) == 0) | 245 | if ((req & 0xf0) == 0) |
| 246 | s3c_irq_ack(IRQ_EINT4t7); | 246 | s3c_irq_ack(IRQ_EINT4t7); |
| 247 | } else { | 247 | } else { |
| 248 | if ((req >> 8) == 0) | 248 | if ((req >> 8) == 0) |
| 249 | s3c_irq_ack(IRQ_EINT8t23); | 249 | s3c_irq_ack(IRQ_EINT8t23); |
| 250 | } | 250 | } |
| 251 | } | 251 | } |
| 252 | 252 | ||
| 253 | static void | 253 | static void |
| 254 | s3c_irqext_unmask(unsigned int irqno) | 254 | s3c_irqext_unmask(unsigned int irqno) |
| 255 | { | 255 | { |
| 256 | unsigned long mask; | 256 | unsigned long mask; |
| 257 | 257 | ||
| 258 | irqno -= EXTINT_OFF; | 258 | irqno -= EXTINT_OFF; |
| 259 | 259 | ||
| 260 | mask = __raw_readl(S3C2410_EINTMASK); | 260 | mask = __raw_readl(S3C2410_EINTMASK); |
| 261 | mask &= ~( 1UL << irqno); | 261 | mask &= ~( 1UL << irqno); |
| 262 | __raw_writel(mask, S3C2410_EINTMASK); | 262 | __raw_writel(mask, S3C2410_EINTMASK); |
| 263 | 263 | ||
| 264 | s3c_irq_unmask((irqno <= (IRQ_EINT7 - EXTINT_OFF)) ? IRQ_EINT4t7 : IRQ_EINT8t23); | 264 | s3c_irq_unmask((irqno <= (IRQ_EINT7 - EXTINT_OFF)) ? IRQ_EINT4t7 : IRQ_EINT8t23); |
| 265 | } | 265 | } |
| 266 | 266 | ||
| 267 | static int | 267 | static int |
| 268 | s3c_irqext_type(unsigned int irq, unsigned int type) | 268 | s3c_irqext_type(unsigned int irq, unsigned int type) |
| 269 | { | 269 | { |
| 270 | void __iomem *extint_reg; | 270 | void __iomem *extint_reg; |
| 271 | void __iomem *gpcon_reg; | 271 | void __iomem *gpcon_reg; |
| 272 | unsigned long gpcon_offset, extint_offset; | 272 | unsigned long gpcon_offset, extint_offset; |
| 273 | unsigned long newvalue = 0, value; | 273 | unsigned long newvalue = 0, value; |
| 274 | 274 | ||
| 275 | if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3)) | 275 | if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3)) |
| 276 | { | 276 | { |
| 277 | gpcon_reg = S3C2410_GPFCON; | 277 | gpcon_reg = S3C2410_GPFCON; |
| 278 | extint_reg = S3C2410_EXTINT0; | 278 | extint_reg = S3C2410_EXTINT0; |
| 279 | gpcon_offset = (irq - IRQ_EINT0) * 2; | 279 | gpcon_offset = (irq - IRQ_EINT0) * 2; |
| 280 | extint_offset = (irq - IRQ_EINT0) * 4; | 280 | extint_offset = (irq - IRQ_EINT0) * 4; |
| 281 | } | 281 | } |
| 282 | else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7)) | 282 | else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7)) |
| 283 | { | 283 | { |
| 284 | gpcon_reg = S3C2410_GPFCON; | 284 | gpcon_reg = S3C2410_GPFCON; |
| 285 | extint_reg = S3C2410_EXTINT0; | 285 | extint_reg = S3C2410_EXTINT0; |
| 286 | gpcon_offset = (irq - (EXTINT_OFF)) * 2; | 286 | gpcon_offset = (irq - (EXTINT_OFF)) * 2; |
| 287 | extint_offset = (irq - (EXTINT_OFF)) * 4; | 287 | extint_offset = (irq - (EXTINT_OFF)) * 4; |
| 288 | } | 288 | } |
| 289 | else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15)) | 289 | else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15)) |
| 290 | { | 290 | { |
| 291 | gpcon_reg = S3C2410_GPGCON; | 291 | gpcon_reg = S3C2410_GPGCON; |
| 292 | extint_reg = S3C2410_EXTINT1; | 292 | extint_reg = S3C2410_EXTINT1; |
| 293 | gpcon_offset = (irq - IRQ_EINT8) * 2; | 293 | gpcon_offset = (irq - IRQ_EINT8) * 2; |
| 294 | extint_offset = (irq - IRQ_EINT8) * 4; | 294 | extint_offset = (irq - IRQ_EINT8) * 4; |
| 295 | } | 295 | } |
| 296 | else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23)) | 296 | else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23)) |
| 297 | { | 297 | { |
| 298 | gpcon_reg = S3C2410_GPGCON; | 298 | gpcon_reg = S3C2410_GPGCON; |
| 299 | extint_reg = S3C2410_EXTINT2; | 299 | extint_reg = S3C2410_EXTINT2; |
| 300 | gpcon_offset = (irq - IRQ_EINT8) * 2; | 300 | gpcon_offset = (irq - IRQ_EINT8) * 2; |
| 301 | extint_offset = (irq - IRQ_EINT16) * 4; | 301 | extint_offset = (irq - IRQ_EINT16) * 4; |
| 302 | } else | 302 | } else |
| 303 | return -1; | 303 | return -1; |
| 304 | 304 | ||
| 305 | /* Set the GPIO to external interrupt mode */ | 305 | /* Set the GPIO to external interrupt mode */ |
| 306 | value = __raw_readl(gpcon_reg); | 306 | value = __raw_readl(gpcon_reg); |
| 307 | value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset); | 307 | value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset); |
| 308 | __raw_writel(value, gpcon_reg); | 308 | __raw_writel(value, gpcon_reg); |
| 309 | 309 | ||
| 310 | /* Set the external interrupt to pointed trigger type */ | 310 | /* Set the external interrupt to pointed trigger type */ |
| 311 | switch (type) | 311 | switch (type) |
| 312 | { | 312 | { |
| 313 | case IRQT_NOEDGE: | 313 | case IRQT_NOEDGE: |
| 314 | printk(KERN_WARNING "No edge setting!\n"); | 314 | printk(KERN_WARNING "No edge setting!\n"); |
| 315 | break; | 315 | break; |
| 316 | 316 | ||
| 317 | case IRQT_RISING: | 317 | case IRQT_RISING: |
| 318 | newvalue = S3C2410_EXTINT_RISEEDGE; | 318 | newvalue = S3C2410_EXTINT_RISEEDGE; |
| 319 | break; | 319 | break; |
| 320 | 320 | ||
| 321 | case IRQT_FALLING: | 321 | case IRQT_FALLING: |
| 322 | newvalue = S3C2410_EXTINT_FALLEDGE; | 322 | newvalue = S3C2410_EXTINT_FALLEDGE; |
| 323 | break; | 323 | break; |
| 324 | 324 | ||
| 325 | case IRQT_BOTHEDGE: | 325 | case IRQT_BOTHEDGE: |
| 326 | newvalue = S3C2410_EXTINT_BOTHEDGE; | 326 | newvalue = S3C2410_EXTINT_BOTHEDGE; |
| 327 | break; | 327 | break; |
| 328 | 328 | ||
| 329 | case IRQT_LOW: | 329 | case IRQT_LOW: |
| 330 | newvalue = S3C2410_EXTINT_LOWLEV; | 330 | newvalue = S3C2410_EXTINT_LOWLEV; |
| 331 | break; | 331 | break; |
| 332 | 332 | ||
| 333 | case IRQT_HIGH: | 333 | case IRQT_HIGH: |
| 334 | newvalue = S3C2410_EXTINT_HILEV; | 334 | newvalue = S3C2410_EXTINT_HILEV; |
| 335 | break; | 335 | break; |
| 336 | 336 | ||
| 337 | default: | 337 | default: |
| 338 | printk(KERN_ERR "No such irq type %d", type); | 338 | printk(KERN_ERR "No such irq type %d", type); |
| 339 | return -1; | 339 | return -1; |
| 340 | } | 340 | } |
| 341 | 341 | ||
| 342 | value = __raw_readl(extint_reg); | 342 | value = __raw_readl(extint_reg); |
| 343 | value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset); | 343 | value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset); |
| 344 | __raw_writel(value, extint_reg); | 344 | __raw_writel(value, extint_reg); |
| 345 | 345 | ||
| 346 | return 0; | 346 | return 0; |
| 347 | } | 347 | } |
| 348 | 348 | ||
| 349 | static struct irqchip s3c_irqext_chip = { | 349 | static struct irqchip s3c_irqext_chip = { |
| 350 | .mask = s3c_irqext_mask, | 350 | .mask = s3c_irqext_mask, |
| 351 | .unmask = s3c_irqext_unmask, | 351 | .unmask = s3c_irqext_unmask, |
| 352 | .ack = s3c_irqext_ack, | 352 | .ack = s3c_irqext_ack, |
| 353 | .type = s3c_irqext_type, | 353 | .set_type = s3c_irqext_type, |
| 354 | .wake = s3c_irqext_wake | 354 | .set_wake = s3c_irqext_wake |
| 355 | }; | 355 | }; |
| 356 | 356 | ||
| 357 | static struct irqchip s3c_irq_eint0t4 = { | 357 | static struct irqchip s3c_irq_eint0t4 = { |
| 358 | .ack = s3c_irq_ack, | 358 | .ack = s3c_irq_ack, |
| 359 | .mask = s3c_irq_mask, | 359 | .mask = s3c_irq_mask, |
| 360 | .unmask = s3c_irq_unmask, | 360 | .unmask = s3c_irq_unmask, |
| 361 | .wake = s3c_irq_wake, | 361 | .set_wake = s3c_irq_wake, |
| 362 | .type = s3c_irqext_type, | 362 | .set_type = s3c_irqext_type, |
| 363 | }; | 363 | }; |
| 364 | 364 | ||
| 365 | /* mask values for the parent registers for each of the interrupt types */ | 365 | /* mask values for the parent registers for each of the interrupt types */ |
| 366 | 366 | ||
| 367 | #define INTMSK_UART0 (1UL << (IRQ_UART0 - IRQ_EINT0)) | 367 | #define INTMSK_UART0 (1UL << (IRQ_UART0 - IRQ_EINT0)) |
| 368 | #define INTMSK_UART1 (1UL << (IRQ_UART1 - IRQ_EINT0)) | 368 | #define INTMSK_UART1 (1UL << (IRQ_UART1 - IRQ_EINT0)) |
| 369 | #define INTMSK_UART2 (1UL << (IRQ_UART2 - IRQ_EINT0)) | 369 | #define INTMSK_UART2 (1UL << (IRQ_UART2 - IRQ_EINT0)) |
| 370 | #define INTMSK_ADCPARENT (1UL << (IRQ_ADCPARENT - IRQ_EINT0)) | 370 | #define INTMSK_ADCPARENT (1UL << (IRQ_ADCPARENT - IRQ_EINT0)) |
| 371 | 371 | ||
| 372 | 372 | ||
| 373 | /* UART0 */ | 373 | /* UART0 */ |
| 374 | 374 | ||
| 375 | static void | 375 | static void |
| 376 | s3c_irq_uart0_mask(unsigned int irqno) | 376 | s3c_irq_uart0_mask(unsigned int irqno) |
| 377 | { | 377 | { |
| 378 | s3c_irqsub_mask(irqno, INTMSK_UART0, 7); | 378 | s3c_irqsub_mask(irqno, INTMSK_UART0, 7); |
| 379 | } | 379 | } |
| 380 | 380 | ||
| 381 | static void | 381 | static void |
| 382 | s3c_irq_uart0_unmask(unsigned int irqno) | 382 | s3c_irq_uart0_unmask(unsigned int irqno) |
| 383 | { | 383 | { |
| 384 | s3c_irqsub_unmask(irqno, INTMSK_UART0); | 384 | s3c_irqsub_unmask(irqno, INTMSK_UART0); |
| 385 | } | 385 | } |
| 386 | 386 | ||
| 387 | static void | 387 | static void |
| 388 | s3c_irq_uart0_ack(unsigned int irqno) | 388 | s3c_irq_uart0_ack(unsigned int irqno) |
| 389 | { | 389 | { |
| 390 | s3c_irqsub_maskack(irqno, INTMSK_UART0, 7); | 390 | s3c_irqsub_maskack(irqno, INTMSK_UART0, 7); |
| 391 | } | 391 | } |
| 392 | 392 | ||
| 393 | static struct irqchip s3c_irq_uart0 = { | 393 | static struct irqchip s3c_irq_uart0 = { |
| 394 | .mask = s3c_irq_uart0_mask, | 394 | .mask = s3c_irq_uart0_mask, |
| 395 | .unmask = s3c_irq_uart0_unmask, | 395 | .unmask = s3c_irq_uart0_unmask, |
| 396 | .ack = s3c_irq_uart0_ack, | 396 | .ack = s3c_irq_uart0_ack, |
| 397 | }; | 397 | }; |
| 398 | 398 | ||
| 399 | /* UART1 */ | 399 | /* UART1 */ |
| 400 | 400 | ||
| 401 | static void | 401 | static void |
| 402 | s3c_irq_uart1_mask(unsigned int irqno) | 402 | s3c_irq_uart1_mask(unsigned int irqno) |
| 403 | { | 403 | { |
| 404 | s3c_irqsub_mask(irqno, INTMSK_UART1, 7 << 3); | 404 | s3c_irqsub_mask(irqno, INTMSK_UART1, 7 << 3); |
| 405 | } | 405 | } |
| 406 | 406 | ||
| 407 | static void | 407 | static void |
| 408 | s3c_irq_uart1_unmask(unsigned int irqno) | 408 | s3c_irq_uart1_unmask(unsigned int irqno) |
| 409 | { | 409 | { |
| 410 | s3c_irqsub_unmask(irqno, INTMSK_UART1); | 410 | s3c_irqsub_unmask(irqno, INTMSK_UART1); |
| 411 | } | 411 | } |
| 412 | 412 | ||
| 413 | static void | 413 | static void |
| 414 | s3c_irq_uart1_ack(unsigned int irqno) | 414 | s3c_irq_uart1_ack(unsigned int irqno) |
| 415 | { | 415 | { |
| 416 | s3c_irqsub_maskack(irqno, INTMSK_UART1, 7 << 3); | 416 | s3c_irqsub_maskack(irqno, INTMSK_UART1, 7 << 3); |
| 417 | } | 417 | } |
| 418 | 418 | ||
| 419 | static struct irqchip s3c_irq_uart1 = { | 419 | static struct irqchip s3c_irq_uart1 = { |
| 420 | .mask = s3c_irq_uart1_mask, | 420 | .mask = s3c_irq_uart1_mask, |
| 421 | .unmask = s3c_irq_uart1_unmask, | 421 | .unmask = s3c_irq_uart1_unmask, |
| 422 | .ack = s3c_irq_uart1_ack, | 422 | .ack = s3c_irq_uart1_ack, |
| 423 | }; | 423 | }; |
| 424 | 424 | ||
| 425 | /* UART2 */ | 425 | /* UART2 */ |
| 426 | 426 | ||
| 427 | static void | 427 | static void |
| 428 | s3c_irq_uart2_mask(unsigned int irqno) | 428 | s3c_irq_uart2_mask(unsigned int irqno) |
| 429 | { | 429 | { |
| 430 | s3c_irqsub_mask(irqno, INTMSK_UART2, 7 << 6); | 430 | s3c_irqsub_mask(irqno, INTMSK_UART2, 7 << 6); |
| 431 | } | 431 | } |
| 432 | 432 | ||
| 433 | static void | 433 | static void |
| 434 | s3c_irq_uart2_unmask(unsigned int irqno) | 434 | s3c_irq_uart2_unmask(unsigned int irqno) |
| 435 | { | 435 | { |
| 436 | s3c_irqsub_unmask(irqno, INTMSK_UART2); | 436 | s3c_irqsub_unmask(irqno, INTMSK_UART2); |
| 437 | } | 437 | } |
| 438 | 438 | ||
| 439 | static void | 439 | static void |
| 440 | s3c_irq_uart2_ack(unsigned int irqno) | 440 | s3c_irq_uart2_ack(unsigned int irqno) |
| 441 | { | 441 | { |
| 442 | s3c_irqsub_maskack(irqno, INTMSK_UART2, 7 << 6); | 442 | s3c_irqsub_maskack(irqno, INTMSK_UART2, 7 << 6); |
| 443 | } | 443 | } |
| 444 | 444 | ||
| 445 | static struct irqchip s3c_irq_uart2 = { | 445 | static struct irqchip s3c_irq_uart2 = { |
| 446 | .mask = s3c_irq_uart2_mask, | 446 | .mask = s3c_irq_uart2_mask, |
| 447 | .unmask = s3c_irq_uart2_unmask, | 447 | .unmask = s3c_irq_uart2_unmask, |
| 448 | .ack = s3c_irq_uart2_ack, | 448 | .ack = s3c_irq_uart2_ack, |
| 449 | }; | 449 | }; |
| 450 | 450 | ||
| 451 | /* ADC and Touchscreen */ | 451 | /* ADC and Touchscreen */ |
| 452 | 452 | ||
| 453 | static void | 453 | static void |
| 454 | s3c_irq_adc_mask(unsigned int irqno) | 454 | s3c_irq_adc_mask(unsigned int irqno) |
| 455 | { | 455 | { |
| 456 | s3c_irqsub_mask(irqno, INTMSK_ADCPARENT, 3 << 9); | 456 | s3c_irqsub_mask(irqno, INTMSK_ADCPARENT, 3 << 9); |
| 457 | } | 457 | } |
| 458 | 458 | ||
| 459 | static void | 459 | static void |
| 460 | s3c_irq_adc_unmask(unsigned int irqno) | 460 | s3c_irq_adc_unmask(unsigned int irqno) |
| 461 | { | 461 | { |
| 462 | s3c_irqsub_unmask(irqno, INTMSK_ADCPARENT); | 462 | s3c_irqsub_unmask(irqno, INTMSK_ADCPARENT); |
| 463 | } | 463 | } |
| 464 | 464 | ||
| 465 | static void | 465 | static void |
| 466 | s3c_irq_adc_ack(unsigned int irqno) | 466 | s3c_irq_adc_ack(unsigned int irqno) |
| 467 | { | 467 | { |
| 468 | s3c_irqsub_ack(irqno, INTMSK_ADCPARENT, 3 << 9); | 468 | s3c_irqsub_ack(irqno, INTMSK_ADCPARENT, 3 << 9); |
| 469 | } | 469 | } |
| 470 | 470 | ||
| 471 | static struct irqchip s3c_irq_adc = { | 471 | static struct irqchip s3c_irq_adc = { |
| 472 | .mask = s3c_irq_adc_mask, | 472 | .mask = s3c_irq_adc_mask, |
| 473 | .unmask = s3c_irq_adc_unmask, | 473 | .unmask = s3c_irq_adc_unmask, |
| 474 | .ack = s3c_irq_adc_ack, | 474 | .ack = s3c_irq_adc_ack, |
| 475 | }; | 475 | }; |
| 476 | 476 | ||
| 477 | /* irq demux for adc */ | 477 | /* irq demux for adc */ |
| 478 | static void s3c_irq_demux_adc(unsigned int irq, | 478 | static void s3c_irq_demux_adc(unsigned int irq, |
| 479 | struct irqdesc *desc, | 479 | struct irqdesc *desc, |
| 480 | struct pt_regs *regs) | 480 | struct pt_regs *regs) |
| 481 | { | 481 | { |
| 482 | unsigned int subsrc, submsk; | 482 | unsigned int subsrc, submsk; |
| 483 | unsigned int offset = 9; | 483 | unsigned int offset = 9; |
| 484 | struct irqdesc *mydesc; | 484 | struct irqdesc *mydesc; |
| 485 | 485 | ||
| 486 | /* read the current pending interrupts, and the mask | 486 | /* read the current pending interrupts, and the mask |
| 487 | * for what it is available */ | 487 | * for what it is available */ |
| 488 | 488 | ||
| 489 | subsrc = __raw_readl(S3C2410_SUBSRCPND); | 489 | subsrc = __raw_readl(S3C2410_SUBSRCPND); |
| 490 | submsk = __raw_readl(S3C2410_INTSUBMSK); | 490 | submsk = __raw_readl(S3C2410_INTSUBMSK); |
| 491 | 491 | ||
| 492 | subsrc &= ~submsk; | 492 | subsrc &= ~submsk; |
| 493 | subsrc >>= offset; | 493 | subsrc >>= offset; |
| 494 | subsrc &= 3; | 494 | subsrc &= 3; |
| 495 | 495 | ||
| 496 | if (subsrc != 0) { | 496 | if (subsrc != 0) { |
| 497 | if (subsrc & 1) { | 497 | if (subsrc & 1) { |
| 498 | mydesc = irq_desc + IRQ_TC; | 498 | mydesc = irq_desc + IRQ_TC; |
| 499 | mydesc->handle( IRQ_TC, mydesc, regs); | 499 | desc_handle_irq(IRQ_TC, mydesc, regs); |
| 500 | } | 500 | } |
| 501 | if (subsrc & 2) { | 501 | if (subsrc & 2) { |
| 502 | mydesc = irq_desc + IRQ_ADC; | 502 | mydesc = irq_desc + IRQ_ADC; |
| 503 | mydesc->handle(IRQ_ADC, mydesc, regs); | 503 | desc_handle_irq(IRQ_ADC, mydesc, regs); |
| 504 | } | 504 | } |
| 505 | } | 505 | } |
| 506 | } | 506 | } |
| 507 | 507 | ||
| 508 | static void s3c_irq_demux_uart(unsigned int start, | 508 | static void s3c_irq_demux_uart(unsigned int start, |
| 509 | struct pt_regs *regs) | 509 | struct pt_regs *regs) |
| 510 | { | 510 | { |
| 511 | unsigned int subsrc, submsk; | 511 | unsigned int subsrc, submsk; |
| 512 | unsigned int offset = start - IRQ_S3CUART_RX0; | 512 | unsigned int offset = start - IRQ_S3CUART_RX0; |
| 513 | struct irqdesc *desc; | 513 | struct irqdesc *desc; |
| 514 | 514 | ||
| 515 | /* read the current pending interrupts, and the mask | 515 | /* read the current pending interrupts, and the mask |
| 516 | * for what it is available */ | 516 | * for what it is available */ |
| 517 | 517 | ||
| 518 | subsrc = __raw_readl(S3C2410_SUBSRCPND); | 518 | subsrc = __raw_readl(S3C2410_SUBSRCPND); |
| 519 | submsk = __raw_readl(S3C2410_INTSUBMSK); | 519 | submsk = __raw_readl(S3C2410_INTSUBMSK); |
| 520 | 520 | ||
| 521 | irqdbf2("s3c_irq_demux_uart: start=%d (%d), subsrc=0x%08x,0x%08x\n", | 521 | irqdbf2("s3c_irq_demux_uart: start=%d (%d), subsrc=0x%08x,0x%08x\n", |
| 522 | start, offset, subsrc, submsk); | 522 | start, offset, subsrc, submsk); |
| 523 | 523 | ||
| 524 | subsrc &= ~submsk; | 524 | subsrc &= ~submsk; |
| 525 | subsrc >>= offset; | 525 | subsrc >>= offset; |
| 526 | subsrc &= 7; | 526 | subsrc &= 7; |
| 527 | 527 | ||
| 528 | if (subsrc != 0) { | 528 | if (subsrc != 0) { |
| 529 | desc = irq_desc + start; | 529 | desc = irq_desc + start; |
| 530 | 530 | ||
| 531 | if (subsrc & 1) | 531 | if (subsrc & 1) |
| 532 | desc->handle(start, desc, regs); | 532 | desc_handle_irq(start, desc, regs); |
| 533 | 533 | ||
| 534 | desc++; | 534 | desc++; |
| 535 | 535 | ||
| 536 | if (subsrc & 2) | 536 | if (subsrc & 2) |
| 537 | desc->handle(start+1, desc, regs); | 537 | desc_handle_irq(start+1, desc, regs); |
| 538 | 538 | ||
| 539 | desc++; | 539 | desc++; |
| 540 | 540 | ||
| 541 | if (subsrc & 4) | 541 | if (subsrc & 4) |
| 542 | desc->handle(start+2, desc, regs); | 542 | desc_handle_irq(start+2, desc, regs); |
| 543 | } | 543 | } |
| 544 | } | 544 | } |
| 545 | 545 | ||
| 546 | /* uart demux entry points */ | 546 | /* uart demux entry points */ |
| 547 | 547 | ||
| 548 | static void | 548 | static void |
| 549 | s3c_irq_demux_uart0(unsigned int irq, | 549 | s3c_irq_demux_uart0(unsigned int irq, |
| 550 | struct irqdesc *desc, | 550 | struct irqdesc *desc, |
| 551 | struct pt_regs *regs) | 551 | struct pt_regs *regs) |
| 552 | { | 552 | { |
| 553 | irq = irq; | 553 | irq = irq; |
| 554 | s3c_irq_demux_uart(IRQ_S3CUART_RX0, regs); | 554 | s3c_irq_demux_uart(IRQ_S3CUART_RX0, regs); |
| 555 | } | 555 | } |
| 556 | 556 | ||
| 557 | static void | 557 | static void |
| 558 | s3c_irq_demux_uart1(unsigned int irq, | 558 | s3c_irq_demux_uart1(unsigned int irq, |
| 559 | struct irqdesc *desc, | 559 | struct irqdesc *desc, |
| 560 | struct pt_regs *regs) | 560 | struct pt_regs *regs) |
| 561 | { | 561 | { |
| 562 | irq = irq; | 562 | irq = irq; |
| 563 | s3c_irq_demux_uart(IRQ_S3CUART_RX1, regs); | 563 | s3c_irq_demux_uart(IRQ_S3CUART_RX1, regs); |
| 564 | } | 564 | } |
| 565 | 565 | ||
| 566 | static void | 566 | static void |
| 567 | s3c_irq_demux_uart2(unsigned int irq, | 567 | s3c_irq_demux_uart2(unsigned int irq, |
| 568 | struct irqdesc *desc, | 568 | struct irqdesc *desc, |
| 569 | struct pt_regs *regs) | 569 | struct pt_regs *regs) |
| 570 | { | 570 | { |
| 571 | irq = irq; | 571 | irq = irq; |
| 572 | s3c_irq_demux_uart(IRQ_S3CUART_RX2, regs); | 572 | s3c_irq_demux_uart(IRQ_S3CUART_RX2, regs); |
| 573 | } | 573 | } |
| 574 | 574 | ||
| 575 | 575 | ||
| 576 | /* s3c24xx_init_irq | 576 | /* s3c24xx_init_irq |
| 577 | * | 577 | * |
| 578 | * Initialise S3C2410 IRQ system | 578 | * Initialise S3C2410 IRQ system |
| 579 | */ | 579 | */ |
| 580 | 580 | ||
| 581 | void __init s3c24xx_init_irq(void) | 581 | void __init s3c24xx_init_irq(void) |
| 582 | { | 582 | { |
| 583 | unsigned long pend; | 583 | unsigned long pend; |
| 584 | unsigned long last; | 584 | unsigned long last; |
| 585 | int irqno; | 585 | int irqno; |
| 586 | int i; | 586 | int i; |
| 587 | 587 | ||
| 588 | irqdbf("s3c2410_init_irq: clearing interrupt status flags\n"); | 588 | irqdbf("s3c2410_init_irq: clearing interrupt status flags\n"); |
| 589 | 589 | ||
| 590 | /* first, clear all interrupts pending... */ | 590 | /* first, clear all interrupts pending... */ |
| 591 | 591 | ||
| 592 | last = 0; | 592 | last = 0; |
| 593 | for (i = 0; i < 4; i++) { | 593 | for (i = 0; i < 4; i++) { |
| 594 | pend = __raw_readl(S3C2410_EINTPEND); | 594 | pend = __raw_readl(S3C2410_EINTPEND); |
| 595 | 595 | ||
| 596 | if (pend == 0 || pend == last) | 596 | if (pend == 0 || pend == last) |
| 597 | break; | 597 | break; |
| 598 | 598 | ||
| 599 | __raw_writel(pend, S3C2410_EINTPEND); | 599 | __raw_writel(pend, S3C2410_EINTPEND); |
| 600 | printk("irq: clearing pending ext status %08x\n", (int)pend); | 600 | printk("irq: clearing pending ext status %08x\n", (int)pend); |
| 601 | last = pend; | 601 | last = pend; |
| 602 | } | 602 | } |
| 603 | 603 | ||
| 604 | last = 0; | 604 | last = 0; |
| 605 | for (i = 0; i < 4; i++) { | 605 | for (i = 0; i < 4; i++) { |
| 606 | pend = __raw_readl(S3C2410_INTPND); | 606 | pend = __raw_readl(S3C2410_INTPND); |
| 607 | 607 | ||
| 608 | if (pend == 0 || pend == last) | 608 | if (pend == 0 || pend == last) |
| 609 | break; | 609 | break; |
| 610 | 610 | ||
| 611 | __raw_writel(pend, S3C2410_SRCPND); | 611 | __raw_writel(pend, S3C2410_SRCPND); |
| 612 | __raw_writel(pend, S3C2410_INTPND); | 612 | __raw_writel(pend, S3C2410_INTPND); |
| 613 | printk("irq: clearing pending status %08x\n", (int)pend); | 613 | printk("irq: clearing pending status %08x\n", (int)pend); |
| 614 | last = pend; | 614 | last = pend; |
| 615 | } | 615 | } |
| 616 | 616 | ||
| 617 | last = 0; | 617 | last = 0; |
| 618 | for (i = 0; i < 4; i++) { | 618 | for (i = 0; i < 4; i++) { |
| 619 | pend = __raw_readl(S3C2410_SUBSRCPND); | 619 | pend = __raw_readl(S3C2410_SUBSRCPND); |
| 620 | 620 | ||
| 621 | if (pend == 0 || pend == last) | 621 | if (pend == 0 || pend == last) |
| 622 | break; | 622 | break; |
| 623 | 623 | ||
| 624 | printk("irq: clearing subpending status %08x\n", (int)pend); | 624 | printk("irq: clearing subpending status %08x\n", (int)pend); |
| 625 | __raw_writel(pend, S3C2410_SUBSRCPND); | 625 | __raw_writel(pend, S3C2410_SUBSRCPND); |
| 626 | last = pend; | 626 | last = pend; |
| 627 | } | 627 | } |
| 628 | 628 | ||
| 629 | /* register the main interrupts */ | 629 | /* register the main interrupts */ |
| 630 | 630 | ||
| 631 | irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n"); | 631 | irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n"); |
| 632 | 632 | ||
| 633 | for (irqno = IRQ_BATT_FLT; irqno <= IRQ_ADCPARENT; irqno++) { | 633 | for (irqno = IRQ_BATT_FLT; irqno <= IRQ_ADCPARENT; irqno++) { |
| 634 | /* set all the s3c2410 internal irqs */ | 634 | /* set all the s3c2410 internal irqs */ |
| 635 | 635 | ||
| 636 | switch (irqno) { | 636 | switch (irqno) { |
| 637 | /* deal with the special IRQs (cascaded) */ | 637 | /* deal with the special IRQs (cascaded) */ |
| 638 | 638 | ||
| 639 | case IRQ_UART0: | 639 | case IRQ_UART0: |
| 640 | case IRQ_UART1: | 640 | case IRQ_UART1: |
| 641 | case IRQ_UART2: | 641 | case IRQ_UART2: |
| 642 | case IRQ_ADCPARENT: | 642 | case IRQ_ADCPARENT: |
| 643 | set_irq_chip(irqno, &s3c_irq_level_chip); | 643 | set_irq_chip(irqno, &s3c_irq_level_chip); |
| 644 | set_irq_handler(irqno, do_level_IRQ); | 644 | set_irq_handler(irqno, do_level_IRQ); |
| 645 | break; | 645 | break; |
| 646 | 646 | ||
| 647 | case IRQ_RESERVED6: | 647 | case IRQ_RESERVED6: |
| 648 | case IRQ_RESERVED24: | 648 | case IRQ_RESERVED24: |
| 649 | /* no IRQ here */ | 649 | /* no IRQ here */ |
| 650 | break; | 650 | break; |
| 651 | 651 | ||
| 652 | default: | 652 | default: |
| 653 | //irqdbf("registering irq %d (s3c irq)\n", irqno); | 653 | //irqdbf("registering irq %d (s3c irq)\n", irqno); |
| 654 | set_irq_chip(irqno, &s3c_irq_chip); | 654 | set_irq_chip(irqno, &s3c_irq_chip); |
| 655 | set_irq_handler(irqno, do_edge_IRQ); | 655 | set_irq_handler(irqno, do_edge_IRQ); |
| 656 | set_irq_flags(irqno, IRQF_VALID); | 656 | set_irq_flags(irqno, IRQF_VALID); |
| 657 | } | 657 | } |
| 658 | } | 658 | } |
| 659 | 659 | ||
| 660 | /* setup the cascade irq handlers */ | 660 | /* setup the cascade irq handlers */ |
| 661 | 661 | ||
| 662 | set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0); | 662 | set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0); |
| 663 | set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1); | 663 | set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1); |
| 664 | set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2); | 664 | set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2); |
| 665 | set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc); | 665 | set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc); |
| 666 | 666 | ||
| 667 | 667 | ||
| 668 | /* external interrupts */ | 668 | /* external interrupts */ |
| 669 | 669 | ||
| 670 | for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) { | 670 | for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) { |
| 671 | irqdbf("registering irq %d (ext int)\n", irqno); | 671 | irqdbf("registering irq %d (ext int)\n", irqno); |
| 672 | set_irq_chip(irqno, &s3c_irq_eint0t4); | 672 | set_irq_chip(irqno, &s3c_irq_eint0t4); |
| 673 | set_irq_handler(irqno, do_edge_IRQ); | 673 | set_irq_handler(irqno, do_edge_IRQ); |
| 674 | set_irq_flags(irqno, IRQF_VALID); | 674 | set_irq_flags(irqno, IRQF_VALID); |
| 675 | } | 675 | } |
| 676 | 676 | ||
| 677 | for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) { | 677 | for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) { |
| 678 | irqdbf("registering irq %d (extended s3c irq)\n", irqno); | 678 | irqdbf("registering irq %d (extended s3c irq)\n", irqno); |
| 679 | set_irq_chip(irqno, &s3c_irqext_chip); | 679 | set_irq_chip(irqno, &s3c_irqext_chip); |
| 680 | set_irq_handler(irqno, do_edge_IRQ); | 680 | set_irq_handler(irqno, do_edge_IRQ); |
| 681 | set_irq_flags(irqno, IRQF_VALID); | 681 | set_irq_flags(irqno, IRQF_VALID); |
| 682 | } | 682 | } |
| 683 | 683 | ||
| 684 | /* register the uart interrupts */ | 684 | /* register the uart interrupts */ |
| 685 | 685 | ||
| 686 | irqdbf("s3c2410: registering external interrupts\n"); | 686 | irqdbf("s3c2410: registering external interrupts\n"); |
| 687 | 687 | ||
| 688 | for (irqno = IRQ_S3CUART_RX0; irqno <= IRQ_S3CUART_ERR0; irqno++) { | 688 | for (irqno = IRQ_S3CUART_RX0; irqno <= IRQ_S3CUART_ERR0; irqno++) { |
| 689 | irqdbf("registering irq %d (s3c uart0 irq)\n", irqno); | 689 | irqdbf("registering irq %d (s3c uart0 irq)\n", irqno); |
| 690 | set_irq_chip(irqno, &s3c_irq_uart0); | 690 | set_irq_chip(irqno, &s3c_irq_uart0); |
| 691 | set_irq_handler(irqno, do_level_IRQ); | 691 | set_irq_handler(irqno, do_level_IRQ); |
| 692 | set_irq_flags(irqno, IRQF_VALID); | 692 | set_irq_flags(irqno, IRQF_VALID); |
| 693 | } | 693 | } |
| 694 | 694 | ||
| 695 | for (irqno = IRQ_S3CUART_RX1; irqno <= IRQ_S3CUART_ERR1; irqno++) { | 695 | for (irqno = IRQ_S3CUART_RX1; irqno <= IRQ_S3CUART_ERR1; irqno++) { |
| 696 | irqdbf("registering irq %d (s3c uart1 irq)\n", irqno); | 696 | irqdbf("registering irq %d (s3c uart1 irq)\n", irqno); |
| 697 | set_irq_chip(irqno, &s3c_irq_uart1); | 697 | set_irq_chip(irqno, &s3c_irq_uart1); |
| 698 | set_irq_handler(irqno, do_level_IRQ); | 698 | set_irq_handler(irqno, do_level_IRQ); |
| 699 | set_irq_flags(irqno, IRQF_VALID); | 699 | set_irq_flags(irqno, IRQF_VALID); |
| 700 | } | 700 | } |
| 701 | 701 | ||
| 702 | for (irqno = IRQ_S3CUART_RX2; irqno <= IRQ_S3CUART_ERR2; irqno++) { | 702 | for (irqno = IRQ_S3CUART_RX2; irqno <= IRQ_S3CUART_ERR2; irqno++) { |
| 703 | irqdbf("registering irq %d (s3c uart2 irq)\n", irqno); | 703 | irqdbf("registering irq %d (s3c uart2 irq)\n", irqno); |
| 704 | set_irq_chip(irqno, &s3c_irq_uart2); | 704 | set_irq_chip(irqno, &s3c_irq_uart2); |
| 705 | set_irq_handler(irqno, do_level_IRQ); | 705 | set_irq_handler(irqno, do_level_IRQ); |
| 706 | set_irq_flags(irqno, IRQF_VALID); | 706 | set_irq_flags(irqno, IRQF_VALID); |
| 707 | } | 707 | } |
| 708 | 708 | ||
| 709 | for (irqno = IRQ_TC; irqno <= IRQ_ADC; irqno++) { | 709 | for (irqno = IRQ_TC; irqno <= IRQ_ADC; irqno++) { |
| 710 | irqdbf("registering irq %d (s3c adc irq)\n", irqno); | 710 | irqdbf("registering irq %d (s3c adc irq)\n", irqno); |
| 711 | set_irq_chip(irqno, &s3c_irq_adc); | 711 | set_irq_chip(irqno, &s3c_irq_adc); |
| 712 | set_irq_handler(irqno, do_edge_IRQ); | 712 | set_irq_handler(irqno, do_edge_IRQ); |
| 713 | set_irq_flags(irqno, IRQF_VALID); | 713 | set_irq_flags(irqno, IRQF_VALID); |
| 714 | } | 714 | } |
| 715 | 715 | ||
| 716 | irqdbf("s3c2410: registered interrupt handlers\n"); | 716 | irqdbf("s3c2410: registered interrupt handlers\n"); |
| 717 | } | 717 | } |
| 718 | 718 |
arch/arm/mach-s3c2410/pm.c
| 1 | /* linux/arch/arm/mach-s3c2410/pm.c | 1 | /* linux/arch/arm/mach-s3c2410/pm.c |
| 2 | * | 2 | * |
| 3 | * Copyright (c) 2004 Simtec Electronics | 3 | * Copyright (c) 2004 Simtec Electronics |
| 4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
| 5 | * | 5 | * |
| 6 | * S3C2410 Power Manager (Suspend-To-RAM) support | 6 | * S3C2410 Power Manager (Suspend-To-RAM) support |
| 7 | * | 7 | * |
| 8 | * See Documentation/arm/Samsung-S3C24XX/Suspend.txt for more information | 8 | * See Documentation/arm/Samsung-S3C24XX/Suspend.txt for more information |
| 9 | * | 9 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
| 12 | * the Free Software Foundation; either version 2 of the License, or | 12 | * the Free Software Foundation; either version 2 of the License, or |
| 13 | * (at your option) any later version. | 13 | * (at your option) any later version. |
| 14 | * | 14 | * |
| 15 | * This program is distributed in the hope that it will be useful, | 15 | * This program is distributed in the hope that it will be useful, |
| 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 18 | * GNU General Public License for more details. | 18 | * GNU General Public License for more details. |
| 19 | * | 19 | * |
| 20 | * You should have received a copy of the GNU General Public License | 20 | * You should have received a copy of the GNU General Public License |
| 21 | * along with this program; if not, write to the Free Software | 21 | * along with this program; if not, write to the Free Software |
| 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 23 | * | 23 | * |
| 24 | * Parts based on arch/arm/mach-pxa/pm.c | 24 | * Parts based on arch/arm/mach-pxa/pm.c |
| 25 | * | 25 | * |
| 26 | * Thanks to Dimitry Andric for debugging | 26 | * Thanks to Dimitry Andric for debugging |
| 27 | * | 27 | * |
| 28 | * Modifications: | 28 | * Modifications: |
| 29 | * 10-Mar-2005 LCVR Changed S3C2410_VA_UART to S3C24XX_VA_UART | 29 | * 10-Mar-2005 LCVR Changed S3C2410_VA_UART to S3C24XX_VA_UART |
| 30 | */ | 30 | */ |
| 31 | 31 | ||
| 32 | #include <linux/config.h> | 32 | #include <linux/config.h> |
| 33 | #include <linux/init.h> | 33 | #include <linux/init.h> |
| 34 | #include <linux/suspend.h> | 34 | #include <linux/suspend.h> |
| 35 | #include <linux/errno.h> | 35 | #include <linux/errno.h> |
| 36 | #include <linux/time.h> | 36 | #include <linux/time.h> |
| 37 | #include <linux/interrupt.h> | 37 | #include <linux/interrupt.h> |
| 38 | #include <linux/crc32.h> | 38 | #include <linux/crc32.h> |
| 39 | #include <linux/ioport.h> | 39 | #include <linux/ioport.h> |
| 40 | #include <linux/delay.h> | 40 | #include <linux/delay.h> |
| 41 | 41 | ||
| 42 | #include <asm/hardware.h> | 42 | #include <asm/hardware.h> |
| 43 | #include <asm/io.h> | 43 | #include <asm/io.h> |
| 44 | 44 | ||
| 45 | #include <asm/arch/regs-serial.h> | 45 | #include <asm/arch/regs-serial.h> |
| 46 | #include <asm/arch/regs-clock.h> | 46 | #include <asm/arch/regs-clock.h> |
| 47 | #include <asm/arch/regs-gpio.h> | 47 | #include <asm/arch/regs-gpio.h> |
| 48 | #include <asm/arch/regs-mem.h> | 48 | #include <asm/arch/regs-mem.h> |
| 49 | #include <asm/arch/regs-irq.h> | 49 | #include <asm/arch/regs-irq.h> |
| 50 | 50 | ||
| 51 | #include <asm/mach/time.h> | 51 | #include <asm/mach/time.h> |
| 52 | 52 | ||
| 53 | #include "pm.h" | 53 | #include "pm.h" |
| 54 | 54 | ||
| 55 | /* for external use */ | 55 | /* for external use */ |
| 56 | 56 | ||
| 57 | unsigned long s3c_pm_flags; | 57 | unsigned long s3c_pm_flags; |
| 58 | 58 | ||
| 59 | /* cache functions from arch/arm/mm/proc-arm920.S */ | 59 | /* cache functions from arch/arm/mm/proc-arm920.S */ |
| 60 | 60 | ||
| 61 | extern void arm920_flush_kern_cache_all(void); | 61 | extern void arm920_flush_kern_cache_all(void); |
| 62 | 62 | ||
| 63 | #define PFX "s3c24xx-pm: " | 63 | #define PFX "s3c24xx-pm: " |
| 64 | 64 | ||
| 65 | static struct sleep_save core_save[] = { | 65 | static struct sleep_save core_save[] = { |
| 66 | SAVE_ITEM(S3C2410_LOCKTIME), | 66 | SAVE_ITEM(S3C2410_LOCKTIME), |
| 67 | SAVE_ITEM(S3C2410_CLKCON), | 67 | SAVE_ITEM(S3C2410_CLKCON), |
| 68 | 68 | ||
| 69 | /* we restore the timings here, with the proviso that the board | 69 | /* we restore the timings here, with the proviso that the board |
| 70 | * brings the system up in an slower, or equal frequency setting | 70 | * brings the system up in an slower, or equal frequency setting |
| 71 | * to the original system. | 71 | * to the original system. |
| 72 | * | 72 | * |
| 73 | * if we cannot guarantee this, then things are going to go very | 73 | * if we cannot guarantee this, then things are going to go very |
| 74 | * wrong here, as we modify the refresh and both pll settings. | 74 | * wrong here, as we modify the refresh and both pll settings. |
| 75 | */ | 75 | */ |
| 76 | 76 | ||
| 77 | SAVE_ITEM(S3C2410_BWSCON), | 77 | SAVE_ITEM(S3C2410_BWSCON), |
| 78 | SAVE_ITEM(S3C2410_BANKCON0), | 78 | SAVE_ITEM(S3C2410_BANKCON0), |
| 79 | SAVE_ITEM(S3C2410_BANKCON1), | 79 | SAVE_ITEM(S3C2410_BANKCON1), |
| 80 | SAVE_ITEM(S3C2410_BANKCON2), | 80 | SAVE_ITEM(S3C2410_BANKCON2), |
| 81 | SAVE_ITEM(S3C2410_BANKCON3), | 81 | SAVE_ITEM(S3C2410_BANKCON3), |
| 82 | SAVE_ITEM(S3C2410_BANKCON4), | 82 | SAVE_ITEM(S3C2410_BANKCON4), |
| 83 | SAVE_ITEM(S3C2410_BANKCON5), | 83 | SAVE_ITEM(S3C2410_BANKCON5), |
| 84 | 84 | ||
| 85 | SAVE_ITEM(S3C2410_CLKDIVN), | 85 | SAVE_ITEM(S3C2410_CLKDIVN), |
| 86 | SAVE_ITEM(S3C2410_MPLLCON), | 86 | SAVE_ITEM(S3C2410_MPLLCON), |
| 87 | SAVE_ITEM(S3C2410_UPLLCON), | 87 | SAVE_ITEM(S3C2410_UPLLCON), |
| 88 | SAVE_ITEM(S3C2410_CLKSLOW), | 88 | SAVE_ITEM(S3C2410_CLKSLOW), |
| 89 | SAVE_ITEM(S3C2410_REFRESH), | 89 | SAVE_ITEM(S3C2410_REFRESH), |
| 90 | }; | 90 | }; |
| 91 | 91 | ||
| 92 | /* this lot should be really saved by the IRQ code */ | 92 | /* this lot should be really saved by the IRQ code */ |
| 93 | static struct sleep_save irq_save[] = { | 93 | static struct sleep_save irq_save[] = { |
| 94 | SAVE_ITEM(S3C2410_EXTINT0), | 94 | SAVE_ITEM(S3C2410_EXTINT0), |
| 95 | SAVE_ITEM(S3C2410_EXTINT1), | 95 | SAVE_ITEM(S3C2410_EXTINT1), |
| 96 | SAVE_ITEM(S3C2410_EXTINT2), | 96 | SAVE_ITEM(S3C2410_EXTINT2), |
| 97 | SAVE_ITEM(S3C2410_EINFLT0), | 97 | SAVE_ITEM(S3C2410_EINFLT0), |
| 98 | SAVE_ITEM(S3C2410_EINFLT1), | 98 | SAVE_ITEM(S3C2410_EINFLT1), |
| 99 | SAVE_ITEM(S3C2410_EINFLT2), | 99 | SAVE_ITEM(S3C2410_EINFLT2), |
| 100 | SAVE_ITEM(S3C2410_EINFLT3), | 100 | SAVE_ITEM(S3C2410_EINFLT3), |
| 101 | SAVE_ITEM(S3C2410_EINTMASK), | 101 | SAVE_ITEM(S3C2410_EINTMASK), |
| 102 | SAVE_ITEM(S3C2410_INTMSK) | 102 | SAVE_ITEM(S3C2410_INTMSK) |
| 103 | }; | 103 | }; |
| 104 | 104 | ||
| 105 | static struct sleep_save gpio_save[] = { | 105 | static struct sleep_save gpio_save[] = { |
| 106 | SAVE_ITEM(S3C2410_GPACON), | 106 | SAVE_ITEM(S3C2410_GPACON), |
| 107 | SAVE_ITEM(S3C2410_GPADAT), | 107 | SAVE_ITEM(S3C2410_GPADAT), |
| 108 | 108 | ||
| 109 | SAVE_ITEM(S3C2410_GPBCON), | 109 | SAVE_ITEM(S3C2410_GPBCON), |
| 110 | SAVE_ITEM(S3C2410_GPBDAT), | 110 | SAVE_ITEM(S3C2410_GPBDAT), |
| 111 | SAVE_ITEM(S3C2410_GPBUP), | 111 | SAVE_ITEM(S3C2410_GPBUP), |
| 112 | 112 | ||
| 113 | SAVE_ITEM(S3C2410_GPCCON), | 113 | SAVE_ITEM(S3C2410_GPCCON), |
| 114 | SAVE_ITEM(S3C2410_GPCDAT), | 114 | SAVE_ITEM(S3C2410_GPCDAT), |
| 115 | SAVE_ITEM(S3C2410_GPCUP), | 115 | SAVE_ITEM(S3C2410_GPCUP), |
| 116 | 116 | ||
| 117 | SAVE_ITEM(S3C2410_GPDCON), | 117 | SAVE_ITEM(S3C2410_GPDCON), |
| 118 | SAVE_ITEM(S3C2410_GPDDAT), | 118 | SAVE_ITEM(S3C2410_GPDDAT), |
| 119 | SAVE_ITEM(S3C2410_GPDUP), | 119 | SAVE_ITEM(S3C2410_GPDUP), |
| 120 | 120 | ||
| 121 | SAVE_ITEM(S3C2410_GPECON), | 121 | SAVE_ITEM(S3C2410_GPECON), |
| 122 | SAVE_ITEM(S3C2410_GPEDAT), | 122 | SAVE_ITEM(S3C2410_GPEDAT), |
| 123 | SAVE_ITEM(S3C2410_GPEUP), | 123 | SAVE_ITEM(S3C2410_GPEUP), |
| 124 | 124 | ||
| 125 | SAVE_ITEM(S3C2410_GPFCON), | 125 | SAVE_ITEM(S3C2410_GPFCON), |
| 126 | SAVE_ITEM(S3C2410_GPFDAT), | 126 | SAVE_ITEM(S3C2410_GPFDAT), |
| 127 | SAVE_ITEM(S3C2410_GPFUP), | 127 | SAVE_ITEM(S3C2410_GPFUP), |
| 128 | 128 | ||
| 129 | SAVE_ITEM(S3C2410_GPGCON), | 129 | SAVE_ITEM(S3C2410_GPGCON), |
| 130 | SAVE_ITEM(S3C2410_GPGDAT), | 130 | SAVE_ITEM(S3C2410_GPGDAT), |
| 131 | SAVE_ITEM(S3C2410_GPGUP), | 131 | SAVE_ITEM(S3C2410_GPGUP), |
| 132 | 132 | ||
| 133 | SAVE_ITEM(S3C2410_GPHCON), | 133 | SAVE_ITEM(S3C2410_GPHCON), |
| 134 | SAVE_ITEM(S3C2410_GPHDAT), | 134 | SAVE_ITEM(S3C2410_GPHDAT), |
| 135 | SAVE_ITEM(S3C2410_GPHUP), | 135 | SAVE_ITEM(S3C2410_GPHUP), |
| 136 | 136 | ||
| 137 | SAVE_ITEM(S3C2410_DCLKCON), | 137 | SAVE_ITEM(S3C2410_DCLKCON), |
| 138 | }; | 138 | }; |
| 139 | 139 | ||
| 140 | #ifdef CONFIG_S3C2410_PM_DEBUG | 140 | #ifdef CONFIG_S3C2410_PM_DEBUG |
| 141 | 141 | ||
| 142 | #define SAVE_UART(va) \ | 142 | #define SAVE_UART(va) \ |
| 143 | SAVE_ITEM((va) + S3C2410_ULCON), \ | 143 | SAVE_ITEM((va) + S3C2410_ULCON), \ |
| 144 | SAVE_ITEM((va) + S3C2410_UCON), \ | 144 | SAVE_ITEM((va) + S3C2410_UCON), \ |
| 145 | SAVE_ITEM((va) + S3C2410_UFCON), \ | 145 | SAVE_ITEM((va) + S3C2410_UFCON), \ |
| 146 | SAVE_ITEM((va) + S3C2410_UMCON), \ | 146 | SAVE_ITEM((va) + S3C2410_UMCON), \ |
| 147 | SAVE_ITEM((va) + S3C2410_UBRDIV) | 147 | SAVE_ITEM((va) + S3C2410_UBRDIV) |
| 148 | 148 | ||
| 149 | static struct sleep_save uart_save[] = { | 149 | static struct sleep_save uart_save[] = { |
| 150 | SAVE_UART(S3C24XX_VA_UART0), | 150 | SAVE_UART(S3C24XX_VA_UART0), |
| 151 | SAVE_UART(S3C24XX_VA_UART1), | 151 | SAVE_UART(S3C24XX_VA_UART1), |
| 152 | #ifndef CONFIG_CPU_S3C2400 | 152 | #ifndef CONFIG_CPU_S3C2400 |
| 153 | SAVE_UART(S3C24XX_VA_UART2), | 153 | SAVE_UART(S3C24XX_VA_UART2), |
| 154 | #endif | 154 | #endif |
| 155 | }; | 155 | }; |
| 156 | 156 | ||
| 157 | /* debug | 157 | /* debug |
| 158 | * | 158 | * |
| 159 | * we send the debug to printascii() to allow it to be seen if the | 159 | * we send the debug to printascii() to allow it to be seen if the |
| 160 | * system never wakes up from the sleep | 160 | * system never wakes up from the sleep |
| 161 | */ | 161 | */ |
| 162 | 162 | ||
| 163 | extern void printascii(const char *); | 163 | extern void printascii(const char *); |
| 164 | 164 | ||
| 165 | static void pm_dbg(const char *fmt, ...) | 165 | static void pm_dbg(const char *fmt, ...) |
| 166 | { | 166 | { |
| 167 | va_list va; | 167 | va_list va; |
| 168 | char buff[256]; | 168 | char buff[256]; |
| 169 | 169 | ||
| 170 | va_start(va, fmt); | 170 | va_start(va, fmt); |
| 171 | vsprintf(buff, fmt, va); | 171 | vsprintf(buff, fmt, va); |
| 172 | va_end(va); | 172 | va_end(va); |
| 173 | 173 | ||
| 174 | printascii(buff); | 174 | printascii(buff); |
| 175 | } | 175 | } |
| 176 | 176 | ||
| 177 | static void s3c2410_pm_debug_init(void) | 177 | static void s3c2410_pm_debug_init(void) |
| 178 | { | 178 | { |
| 179 | unsigned long tmp = __raw_readl(S3C2410_CLKCON); | 179 | unsigned long tmp = __raw_readl(S3C2410_CLKCON); |
| 180 | 180 | ||
| 181 | /* re-start uart clocks */ | 181 | /* re-start uart clocks */ |
| 182 | tmp |= S3C2410_CLKCON_UART0; | 182 | tmp |= S3C2410_CLKCON_UART0; |
| 183 | tmp |= S3C2410_CLKCON_UART1; | 183 | tmp |= S3C2410_CLKCON_UART1; |
| 184 | tmp |= S3C2410_CLKCON_UART2; | 184 | tmp |= S3C2410_CLKCON_UART2; |
| 185 | 185 | ||
| 186 | __raw_writel(tmp, S3C2410_CLKCON); | 186 | __raw_writel(tmp, S3C2410_CLKCON); |
| 187 | udelay(10); | 187 | udelay(10); |
| 188 | } | 188 | } |
| 189 | 189 | ||
| 190 | #define DBG(fmt...) pm_dbg(fmt) | 190 | #define DBG(fmt...) pm_dbg(fmt) |
| 191 | #else | 191 | #else |
| 192 | #define DBG(fmt...) printk(KERN_DEBUG fmt) | 192 | #define DBG(fmt...) printk(KERN_DEBUG fmt) |
| 193 | 193 | ||
| 194 | #define s3c2410_pm_debug_init() do { } while(0) | 194 | #define s3c2410_pm_debug_init() do { } while(0) |
| 195 | 195 | ||
| 196 | static struct sleep_save uart_save[] = {}; | 196 | static struct sleep_save uart_save[] = {}; |
| 197 | #endif | 197 | #endif |
| 198 | 198 | ||
| 199 | #if defined(CONFIG_S3C2410_PM_CHECK) && CONFIG_S3C2410_PM_CHECK_CHUNKSIZE != 0 | 199 | #if defined(CONFIG_S3C2410_PM_CHECK) && CONFIG_S3C2410_PM_CHECK_CHUNKSIZE != 0 |
| 200 | 200 | ||
| 201 | /* suspend checking code... | 201 | /* suspend checking code... |
| 202 | * | 202 | * |
| 203 | * this next area does a set of crc checks over all the installed | 203 | * this next area does a set of crc checks over all the installed |
| 204 | * memory, so the system can verify if the resume was ok. | 204 | * memory, so the system can verify if the resume was ok. |
| 205 | * | 205 | * |
| 206 | * CONFIG_S3C2410_PM_CHECK_CHUNKSIZE defines the block-size for the CRC, | 206 | * CONFIG_S3C2410_PM_CHECK_CHUNKSIZE defines the block-size for the CRC, |
| 207 | * increasing it will mean that the area corrupted will be less easy to spot, | 207 | * increasing it will mean that the area corrupted will be less easy to spot, |
| 208 | * and reducing the size will cause the CRC save area to grow | 208 | * and reducing the size will cause the CRC save area to grow |
| 209 | */ | 209 | */ |
| 210 | 210 | ||
| 211 | #define CHECK_CHUNKSIZE (CONFIG_S3C2410_PM_CHECK_CHUNKSIZE * 1024) | 211 | #define CHECK_CHUNKSIZE (CONFIG_S3C2410_PM_CHECK_CHUNKSIZE * 1024) |
| 212 | 212 | ||
| 213 | static u32 crc_size; /* size needed for the crc block */ | 213 | static u32 crc_size; /* size needed for the crc block */ |
| 214 | static u32 *crcs; /* allocated over suspend/resume */ | 214 | static u32 *crcs; /* allocated over suspend/resume */ |
| 215 | 215 | ||
| 216 | typedef u32 *(run_fn_t)(struct resource *ptr, u32 *arg); | 216 | typedef u32 *(run_fn_t)(struct resource *ptr, u32 *arg); |
| 217 | 217 | ||
| 218 | /* s3c2410_pm_run_res | 218 | /* s3c2410_pm_run_res |
| 219 | * | 219 | * |
| 220 | * go thorugh the given resource list, and look for system ram | 220 | * go thorugh the given resource list, and look for system ram |
| 221 | */ | 221 | */ |
| 222 | 222 | ||
| 223 | static void s3c2410_pm_run_res(struct resource *ptr, run_fn_t fn, u32 *arg) | 223 | static void s3c2410_pm_run_res(struct resource *ptr, run_fn_t fn, u32 *arg) |
| 224 | { | 224 | { |
| 225 | while (ptr != NULL) { | 225 | while (ptr != NULL) { |
| 226 | if (ptr->child != NULL) | 226 | if (ptr->child != NULL) |
| 227 | s3c2410_pm_run_res(ptr->child, fn, arg); | 227 | s3c2410_pm_run_res(ptr->child, fn, arg); |
| 228 | 228 | ||
| 229 | if ((ptr->flags & IORESOURCE_MEM) && | 229 | if ((ptr->flags & IORESOURCE_MEM) && |
| 230 | strcmp(ptr->name, "System RAM") == 0) { | 230 | strcmp(ptr->name, "System RAM") == 0) { |
| 231 | DBG("Found system RAM at %08lx..%08lx\n", | 231 | DBG("Found system RAM at %08lx..%08lx\n", |
| 232 | ptr->start, ptr->end); | 232 | ptr->start, ptr->end); |
| 233 | arg = (fn)(ptr, arg); | 233 | arg = (fn)(ptr, arg); |
| 234 | } | 234 | } |
| 235 | 235 | ||
| 236 | ptr = ptr->sibling; | 236 | ptr = ptr->sibling; |
| 237 | } | 237 | } |
| 238 | } | 238 | } |
| 239 | 239 | ||
| 240 | static void s3c2410_pm_run_sysram(run_fn_t fn, u32 *arg) | 240 | static void s3c2410_pm_run_sysram(run_fn_t fn, u32 *arg) |
| 241 | { | 241 | { |
| 242 | s3c2410_pm_run_res(&iomem_resource, fn, arg); | 242 | s3c2410_pm_run_res(&iomem_resource, fn, arg); |
| 243 | } | 243 | } |
| 244 | 244 | ||
| 245 | static u32 *s3c2410_pm_countram(struct resource *res, u32 *val) | 245 | static u32 *s3c2410_pm_countram(struct resource *res, u32 *val) |
| 246 | { | 246 | { |
| 247 | u32 size = (u32)(res->end - res->start)+1; | 247 | u32 size = (u32)(res->end - res->start)+1; |
| 248 | 248 | ||
| 249 | size += CHECK_CHUNKSIZE-1; | 249 | size += CHECK_CHUNKSIZE-1; |
| 250 | size /= CHECK_CHUNKSIZE; | 250 | size /= CHECK_CHUNKSIZE; |
| 251 | 251 | ||
| 252 | DBG("Area %08lx..%08lx, %d blocks\n", res->start, res->end, size); | 252 | DBG("Area %08lx..%08lx, %d blocks\n", res->start, res->end, size); |
| 253 | 253 | ||
| 254 | *val += size * sizeof(u32); | 254 | *val += size * sizeof(u32); |
| 255 | return val; | 255 | return val; |
| 256 | } | 256 | } |
| 257 | 257 | ||
| 258 | /* s3c2410_pm_prepare_check | 258 | /* s3c2410_pm_prepare_check |
| 259 | * | 259 | * |
| 260 | * prepare the necessary information for creating the CRCs. This | 260 | * prepare the necessary information for creating the CRCs. This |
| 261 | * must be done before the final save, as it will require memory | 261 | * must be done before the final save, as it will require memory |
| 262 | * allocating, and thus touching bits of the kernel we do not | 262 | * allocating, and thus touching bits of the kernel we do not |
| 263 | * know about. | 263 | * know about. |
| 264 | */ | 264 | */ |
| 265 | 265 | ||
| 266 | static void s3c2410_pm_check_prepare(void) | 266 | static void s3c2410_pm_check_prepare(void) |
| 267 | { | 267 | { |
| 268 | crc_size = 0; | 268 | crc_size = 0; |
| 269 | 269 | ||
| 270 | s3c2410_pm_run_sysram(s3c2410_pm_countram, &crc_size); | 270 | s3c2410_pm_run_sysram(s3c2410_pm_countram, &crc_size); |
| 271 | 271 | ||
| 272 | DBG("s3c2410_pm_prepare_check: %u checks needed\n", crc_size); | 272 | DBG("s3c2410_pm_prepare_check: %u checks needed\n", crc_size); |
| 273 | 273 | ||
| 274 | crcs = kmalloc(crc_size+4, GFP_KERNEL); | 274 | crcs = kmalloc(crc_size+4, GFP_KERNEL); |
| 275 | if (crcs == NULL) | 275 | if (crcs == NULL) |
| 276 | printk(KERN_ERR "Cannot allocated CRC save area\n"); | 276 | printk(KERN_ERR "Cannot allocated CRC save area\n"); |
| 277 | } | 277 | } |
| 278 | 278 | ||
| 279 | static u32 *s3c2410_pm_makecheck(struct resource *res, u32 *val) | 279 | static u32 *s3c2410_pm_makecheck(struct resource *res, u32 *val) |
| 280 | { | 280 | { |
| 281 | unsigned long addr, left; | 281 | unsigned long addr, left; |
| 282 | 282 | ||
| 283 | for (addr = res->start; addr < res->end; | 283 | for (addr = res->start; addr < res->end; |
| 284 | addr += CHECK_CHUNKSIZE) { | 284 | addr += CHECK_CHUNKSIZE) { |
| 285 | left = res->end - addr; | 285 | left = res->end - addr; |
| 286 | 286 | ||
| 287 | if (left > CHECK_CHUNKSIZE) | 287 | if (left > CHECK_CHUNKSIZE) |
| 288 | left = CHECK_CHUNKSIZE; | 288 | left = CHECK_CHUNKSIZE; |
| 289 | 289 | ||
| 290 | *val = crc32_le(~0, phys_to_virt(addr), left); | 290 | *val = crc32_le(~0, phys_to_virt(addr), left); |
| 291 | val++; | 291 | val++; |
| 292 | } | 292 | } |
| 293 | 293 | ||
| 294 | return val; | 294 | return val; |
| 295 | } | 295 | } |
| 296 | 296 | ||
| 297 | /* s3c2410_pm_check_store | 297 | /* s3c2410_pm_check_store |
| 298 | * | 298 | * |
| 299 | * compute the CRC values for the memory blocks before the final | 299 | * compute the CRC values for the memory blocks before the final |
| 300 | * sleep. | 300 | * sleep. |
| 301 | */ | 301 | */ |
| 302 | 302 | ||
| 303 | static void s3c2410_pm_check_store(void) | 303 | static void s3c2410_pm_check_store(void) |
| 304 | { | 304 | { |
| 305 | if (crcs != NULL) | 305 | if (crcs != NULL) |
| 306 | s3c2410_pm_run_sysram(s3c2410_pm_makecheck, crcs); | 306 | s3c2410_pm_run_sysram(s3c2410_pm_makecheck, crcs); |
| 307 | } | 307 | } |
| 308 | 308 | ||
| 309 | /* in_region | 309 | /* in_region |
| 310 | * | 310 | * |
| 311 | * return TRUE if the area defined by ptr..ptr+size contatins the | 311 | * return TRUE if the area defined by ptr..ptr+size contatins the |
| 312 | * what..what+whatsz | 312 | * what..what+whatsz |
| 313 | */ | 313 | */ |
| 314 | 314 | ||
| 315 | static inline int in_region(void *ptr, int size, void *what, size_t whatsz) | 315 | static inline int in_region(void *ptr, int size, void *what, size_t whatsz) |
| 316 | { | 316 | { |
| 317 | if ((what+whatsz) < ptr) | 317 | if ((what+whatsz) < ptr) |
| 318 | return 0; | 318 | return 0; |
| 319 | 319 | ||
| 320 | if (what > (ptr+size)) | 320 | if (what > (ptr+size)) |
| 321 | return 0; | 321 | return 0; |
| 322 | 322 | ||
| 323 | return 1; | 323 | return 1; |
| 324 | } | 324 | } |
| 325 | 325 | ||
| 326 | static u32 *s3c2410_pm_runcheck(struct resource *res, u32 *val) | 326 | static u32 *s3c2410_pm_runcheck(struct resource *res, u32 *val) |
| 327 | { | 327 | { |
| 328 | void *save_at = phys_to_virt(s3c2410_sleep_save_phys); | 328 | void *save_at = phys_to_virt(s3c2410_sleep_save_phys); |
| 329 | unsigned long addr; | 329 | unsigned long addr; |
| 330 | unsigned long left; | 330 | unsigned long left; |
| 331 | void *ptr; | 331 | void *ptr; |
| 332 | u32 calc; | 332 | u32 calc; |
| 333 | 333 | ||
| 334 | for (addr = res->start; addr < res->end; | 334 | for (addr = res->start; addr < res->end; |
| 335 | addr += CHECK_CHUNKSIZE) { | 335 | addr += CHECK_CHUNKSIZE) { |
| 336 | left = res->end - addr; | 336 | left = res->end - addr; |
| 337 | 337 | ||
| 338 | if (left > CHECK_CHUNKSIZE) | 338 | if (left > CHECK_CHUNKSIZE) |
| 339 | left = CHECK_CHUNKSIZE; | 339 | left = CHECK_CHUNKSIZE; |
| 340 | 340 | ||
| 341 | ptr = phys_to_virt(addr); | 341 | ptr = phys_to_virt(addr); |
| 342 | 342 | ||
| 343 | if (in_region(ptr, left, crcs, crc_size)) { | 343 | if (in_region(ptr, left, crcs, crc_size)) { |
| 344 | DBG("skipping %08lx, has crc block in\n", addr); | 344 | DBG("skipping %08lx, has crc block in\n", addr); |
| 345 | goto skip_check; | 345 | goto skip_check; |
| 346 | } | 346 | } |
| 347 | 347 | ||
| 348 | if (in_region(ptr, left, save_at, 32*4 )) { | 348 | if (in_region(ptr, left, save_at, 32*4 )) { |
| 349 | DBG("skipping %08lx, has save block in\n", addr); | 349 | DBG("skipping %08lx, has save block in\n", addr); |
| 350 | goto skip_check; | 350 | goto skip_check; |
| 351 | } | 351 | } |
| 352 | 352 | ||
| 353 | /* calculate and check the checksum */ | 353 | /* calculate and check the checksum */ |
| 354 | 354 | ||
| 355 | calc = crc32_le(~0, ptr, left); | 355 | calc = crc32_le(~0, ptr, left); |
| 356 | if (calc != *val) { | 356 | if (calc != *val) { |
| 357 | printk(KERN_ERR PFX "Restore CRC error at " | 357 | printk(KERN_ERR PFX "Restore CRC error at " |
| 358 | "%08lx (%08x vs %08x)\n", addr, calc, *val); | 358 | "%08lx (%08x vs %08x)\n", addr, calc, *val); |
| 359 | 359 | ||
| 360 | DBG("Restore CRC error at %08lx (%08x vs %08x)\n", | 360 | DBG("Restore CRC error at %08lx (%08x vs %08x)\n", |
| 361 | addr, calc, *val); | 361 | addr, calc, *val); |
| 362 | } | 362 | } |
| 363 | 363 | ||
| 364 | skip_check: | 364 | skip_check: |
| 365 | val++; | 365 | val++; |
| 366 | } | 366 | } |
| 367 | 367 | ||
| 368 | return val; | 368 | return val; |
| 369 | } | 369 | } |
| 370 | 370 | ||
| 371 | /* s3c2410_pm_check_restore | 371 | /* s3c2410_pm_check_restore |
| 372 | * | 372 | * |
| 373 | * check the CRCs after the restore event and free the memory used | 373 | * check the CRCs after the restore event and free the memory used |
| 374 | * to hold them | 374 | * to hold them |
| 375 | */ | 375 | */ |
| 376 | 376 | ||
| 377 | static void s3c2410_pm_check_restore(void) | 377 | static void s3c2410_pm_check_restore(void) |
| 378 | { | 378 | { |
| 379 | if (crcs != NULL) { | 379 | if (crcs != NULL) { |
| 380 | s3c2410_pm_run_sysram(s3c2410_pm_runcheck, crcs); | 380 | s3c2410_pm_run_sysram(s3c2410_pm_runcheck, crcs); |
| 381 | kfree(crcs); | 381 | kfree(crcs); |
| 382 | crcs = NULL; | 382 | crcs = NULL; |
| 383 | } | 383 | } |
| 384 | } | 384 | } |
| 385 | 385 | ||
| 386 | #else | 386 | #else |
| 387 | 387 | ||
| 388 | #define s3c2410_pm_check_prepare() do { } while(0) | 388 | #define s3c2410_pm_check_prepare() do { } while(0) |
| 389 | #define s3c2410_pm_check_restore() do { } while(0) | 389 | #define s3c2410_pm_check_restore() do { } while(0) |
| 390 | #define s3c2410_pm_check_store() do { } while(0) | 390 | #define s3c2410_pm_check_store() do { } while(0) |
| 391 | #endif | 391 | #endif |
| 392 | 392 | ||
| 393 | /* helper functions to save and restore register state */ | 393 | /* helper functions to save and restore register state */ |
| 394 | 394 | ||
| 395 | void s3c2410_pm_do_save(struct sleep_save *ptr, int count) | 395 | void s3c2410_pm_do_save(struct sleep_save *ptr, int count) |
| 396 | { | 396 | { |
| 397 | for (; count > 0; count--, ptr++) { | 397 | for (; count > 0; count--, ptr++) { |
| 398 | ptr->val = __raw_readl(ptr->reg); | 398 | ptr->val = __raw_readl(ptr->reg); |
| 399 | DBG("saved %p value %08lx\n", ptr->reg, ptr->val); | 399 | DBG("saved %p value %08lx\n", ptr->reg, ptr->val); |
| 400 | } | 400 | } |
| 401 | } | 401 | } |
| 402 | 402 | ||
| 403 | /* s3c2410_pm_do_restore | 403 | /* s3c2410_pm_do_restore |
| 404 | * | 404 | * |
| 405 | * restore the system from the given list of saved registers | 405 | * restore the system from the given list of saved registers |
| 406 | * | 406 | * |
| 407 | * Note, we do not use DBG() in here, as the system may not have | 407 | * Note, we do not use DBG() in here, as the system may not have |
| 408 | * restore the UARTs state yet | 408 | * restore the UARTs state yet |
| 409 | */ | 409 | */ |
| 410 | 410 | ||
| 411 | void s3c2410_pm_do_restore(struct sleep_save *ptr, int count) | 411 | void s3c2410_pm_do_restore(struct sleep_save *ptr, int count) |
| 412 | { | 412 | { |
| 413 | for (; count > 0; count--, ptr++) { | 413 | for (; count > 0; count--, ptr++) { |
| 414 | printk(KERN_DEBUG "restore %p (restore %08lx, was %08x)\n", | 414 | printk(KERN_DEBUG "restore %p (restore %08lx, was %08x)\n", |
| 415 | ptr->reg, ptr->val, __raw_readl(ptr->reg)); | 415 | ptr->reg, ptr->val, __raw_readl(ptr->reg)); |
| 416 | 416 | ||
| 417 | __raw_writel(ptr->val, ptr->reg); | 417 | __raw_writel(ptr->val, ptr->reg); |
| 418 | } | 418 | } |
| 419 | } | 419 | } |
| 420 | 420 | ||
| 421 | /* s3c2410_pm_do_restore_core | 421 | /* s3c2410_pm_do_restore_core |
| 422 | * | 422 | * |
| 423 | * similar to s3c2410_pm_do_restore_core | 423 | * similar to s3c2410_pm_do_restore_core |
| 424 | * | 424 | * |
| 425 | * WARNING: Do not put any debug in here that may effect memory or use | 425 | * WARNING: Do not put any debug in here that may effect memory or use |
| 426 | * peripherals, as things may be changing! | 426 | * peripherals, as things may be changing! |
| 427 | */ | 427 | */ |
| 428 | 428 | ||
| 429 | static void s3c2410_pm_do_restore_core(struct sleep_save *ptr, int count) | 429 | static void s3c2410_pm_do_restore_core(struct sleep_save *ptr, int count) |
| 430 | { | 430 | { |
| 431 | for (; count > 0; count--, ptr++) { | 431 | for (; count > 0; count--, ptr++) { |
| 432 | __raw_writel(ptr->val, ptr->reg); | 432 | __raw_writel(ptr->val, ptr->reg); |
| 433 | } | 433 | } |
| 434 | } | 434 | } |
| 435 | 435 | ||
| 436 | /* s3c2410_pm_show_resume_irqs | 436 | /* s3c2410_pm_show_resume_irqs |
| 437 | * | 437 | * |
| 438 | * print any IRQs asserted at resume time (ie, we woke from) | 438 | * print any IRQs asserted at resume time (ie, we woke from) |
| 439 | */ | 439 | */ |
| 440 | 440 | ||
| 441 | static void s3c2410_pm_show_resume_irqs(int start, unsigned long which, | 441 | static void s3c2410_pm_show_resume_irqs(int start, unsigned long which, |
| 442 | unsigned long mask) | 442 | unsigned long mask) |
| 443 | { | 443 | { |
| 444 | int i; | 444 | int i; |
| 445 | 445 | ||
| 446 | which &= ~mask; | 446 | which &= ~mask; |
| 447 | 447 | ||
| 448 | for (i = 0; i <= 31; i++) { | 448 | for (i = 0; i <= 31; i++) { |
| 449 | if ((which) & (1L<<i)) { | 449 | if ((which) & (1L<<i)) { |
| 450 | DBG("IRQ %d asserted at resume\n", start+i); | 450 | DBG("IRQ %d asserted at resume\n", start+i); |
| 451 | } | 451 | } |
| 452 | } | 452 | } |
| 453 | } | 453 | } |
| 454 | 454 | ||
| 455 | /* s3c2410_pm_check_resume_pin | 455 | /* s3c2410_pm_check_resume_pin |
| 456 | * | 456 | * |
| 457 | * check to see if the pin is configured correctly for sleep mode, and | 457 | * check to see if the pin is configured correctly for sleep mode, and |
| 458 | * make any necessary adjustments if it is not | 458 | * make any necessary adjustments if it is not |
| 459 | */ | 459 | */ |
| 460 | 460 | ||
| 461 | static void s3c2410_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs) | 461 | static void s3c2410_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs) |
| 462 | { | 462 | { |
| 463 | unsigned long irqstate; | 463 | unsigned long irqstate; |
| 464 | unsigned long pinstate; | 464 | unsigned long pinstate; |
| 465 | int irq = s3c2410_gpio_getirq(pin); | 465 | int irq = s3c2410_gpio_getirq(pin); |
| 466 | 466 | ||
| 467 | if (irqoffs < 4) | 467 | if (irqoffs < 4) |
| 468 | irqstate = s3c_irqwake_intmask & (1L<<irqoffs); | 468 | irqstate = s3c_irqwake_intmask & (1L<<irqoffs); |
| 469 | else | 469 | else |
| 470 | irqstate = s3c_irqwake_eintmask & (1L<<irqoffs); | 470 | irqstate = s3c_irqwake_eintmask & (1L<<irqoffs); |
| 471 | 471 | ||
| 472 | pinstate = s3c2410_gpio_getcfg(pin); | 472 | pinstate = s3c2410_gpio_getcfg(pin); |
| 473 | pinstate >>= S3C2410_GPIO_OFFSET(pin)*2; | 473 | pinstate >>= S3C2410_GPIO_OFFSET(pin)*2; |
| 474 | 474 | ||
| 475 | if (!irqstate) { | 475 | if (!irqstate) { |
| 476 | if (pinstate == 0x02) | 476 | if (pinstate == 0x02) |
| 477 | DBG("Leaving IRQ %d (pin %d) enabled\n", irq, pin); | 477 | DBG("Leaving IRQ %d (pin %d) enabled\n", irq, pin); |
| 478 | } else { | 478 | } else { |
| 479 | if (pinstate == 0x02) { | 479 | if (pinstate == 0x02) { |
| 480 | DBG("Disabling IRQ %d (pin %d)\n", irq, pin); | 480 | DBG("Disabling IRQ %d (pin %d)\n", irq, pin); |
| 481 | s3c2410_gpio_cfgpin(pin, 0x00); | 481 | s3c2410_gpio_cfgpin(pin, 0x00); |
| 482 | } | 482 | } |
| 483 | } | 483 | } |
| 484 | } | 484 | } |
| 485 | 485 | ||
| 486 | /* s3c2410_pm_configure_extint | 486 | /* s3c2410_pm_configure_extint |
| 487 | * | 487 | * |
| 488 | * configure all external interrupt pins | 488 | * configure all external interrupt pins |
| 489 | */ | 489 | */ |
| 490 | 490 | ||
| 491 | static void s3c2410_pm_configure_extint(void) | 491 | static void s3c2410_pm_configure_extint(void) |
| 492 | { | 492 | { |
| 493 | int pin; | 493 | int pin; |
| 494 | 494 | ||
| 495 | /* for each of the external interrupts (EINT0..EINT15) we | 495 | /* for each of the external interrupts (EINT0..EINT15) we |
| 496 | * need to check wether it is an external interrupt source, | 496 | * need to check wether it is an external interrupt source, |
| 497 | * and then configure it as an input if it is not | 497 | * and then configure it as an input if it is not |
| 498 | */ | 498 | */ |
| 499 | 499 | ||
| 500 | for (pin = S3C2410_GPF0; pin <= S3C2410_GPF7; pin++) { | 500 | for (pin = S3C2410_GPF0; pin <= S3C2410_GPF7; pin++) { |
| 501 | s3c2410_pm_check_resume_pin(pin, pin - S3C2410_GPF0); | 501 | s3c2410_pm_check_resume_pin(pin, pin - S3C2410_GPF0); |
| 502 | } | 502 | } |
| 503 | 503 | ||
| 504 | for (pin = S3C2410_GPG0; pin <= S3C2410_GPG7; pin++) { | 504 | for (pin = S3C2410_GPG0; pin <= S3C2410_GPG7; pin++) { |
| 505 | s3c2410_pm_check_resume_pin(pin, (pin - S3C2410_GPG0)+8); | 505 | s3c2410_pm_check_resume_pin(pin, (pin - S3C2410_GPG0)+8); |
| 506 | } | 506 | } |
| 507 | } | 507 | } |
| 508 | 508 | ||
| 509 | #define any_allowed(mask, allow) (((mask) & (allow)) != (allow)) | 509 | #define any_allowed(mask, allow) (((mask) & (allow)) != (allow)) |
| 510 | 510 | ||
| 511 | /* s3c2410_pm_enter | 511 | /* s3c2410_pm_enter |
| 512 | * | 512 | * |
| 513 | * central control for sleep/resume process | 513 | * central control for sleep/resume process |
| 514 | */ | 514 | */ |
| 515 | 515 | ||
| 516 | static int s3c2410_pm_enter(suspend_state_t state) | 516 | static int s3c2410_pm_enter(suspend_state_t state) |
| 517 | { | 517 | { |
| 518 | unsigned long regs_save[16]; | 518 | unsigned long regs_save[16]; |
| 519 | unsigned long tmp; | 519 | unsigned long tmp; |
| 520 | 520 | ||
| 521 | /* ensure the debug is initialised (if enabled) */ | 521 | /* ensure the debug is initialised (if enabled) */ |
| 522 | 522 | ||
| 523 | s3c2410_pm_debug_init(); | 523 | s3c2410_pm_debug_init(); |
| 524 | 524 | ||
| 525 | DBG("s3c2410_pm_enter(%d)\n", state); | 525 | DBG("s3c2410_pm_enter(%d)\n", state); |
| 526 | 526 | ||
| 527 | if (state != PM_SUSPEND_MEM) { | 527 | if (state != PM_SUSPEND_MEM) { |
| 528 | printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supported\n"); | 528 | printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supported\n"); |
| 529 | return -EINVAL; | 529 | return -EINVAL; |
| 530 | } | 530 | } |
| 531 | 531 | ||
| 532 | /* check if we have anything to wake-up with... bad things seem | 532 | /* check if we have anything to wake-up with... bad things seem |
| 533 | * to happen if you suspend with no wakeup (system will often | 533 | * to happen if you suspend with no wakeup (system will often |
| 534 | * require a full power-cycle) | 534 | * require a full power-cycle) |
| 535 | */ | 535 | */ |
| 536 | 536 | ||
| 537 | if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) && | 537 | if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) && |
| 538 | !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) { | 538 | !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) { |
| 539 | printk(KERN_ERR PFX "No sources enabled for wake-up!\n"); | 539 | printk(KERN_ERR PFX "No sources enabled for wake-up!\n"); |
| 540 | printk(KERN_ERR PFX "Aborting sleep\n"); | 540 | printk(KERN_ERR PFX "Aborting sleep\n"); |
| 541 | return -EINVAL; | 541 | return -EINVAL; |
| 542 | } | 542 | } |
| 543 | 543 | ||
| 544 | /* prepare check area if configured */ | 544 | /* prepare check area if configured */ |
| 545 | 545 | ||
| 546 | s3c2410_pm_check_prepare(); | 546 | s3c2410_pm_check_prepare(); |
| 547 | 547 | ||
| 548 | /* store the physical address of the register recovery block */ | 548 | /* store the physical address of the register recovery block */ |
| 549 | 549 | ||
| 550 | s3c2410_sleep_save_phys = virt_to_phys(regs_save); | 550 | s3c2410_sleep_save_phys = virt_to_phys(regs_save); |
| 551 | 551 | ||
| 552 | DBG("s3c2410_sleep_save_phys=0x%08lx\n", s3c2410_sleep_save_phys); | 552 | DBG("s3c2410_sleep_save_phys=0x%08lx\n", s3c2410_sleep_save_phys); |
| 553 | 553 | ||
| 554 | /* ensure at least GESTATUS3 has the resume address */ | 554 | /* ensure at least GESTATUS3 has the resume address */ |
| 555 | 555 | ||
| 556 | __raw_writel(virt_to_phys(s3c2410_cpu_resume), S3C2410_GSTATUS3); | 556 | __raw_writel(virt_to_phys(s3c2410_cpu_resume), S3C2410_GSTATUS3); |
| 557 | 557 | ||
| 558 | DBG("GSTATUS3 0x%08x\n", __raw_readl(S3C2410_GSTATUS3)); | 558 | DBG("GSTATUS3 0x%08x\n", __raw_readl(S3C2410_GSTATUS3)); |
| 559 | DBG("GSTATUS4 0x%08x\n", __raw_readl(S3C2410_GSTATUS4)); | 559 | DBG("GSTATUS4 0x%08x\n", __raw_readl(S3C2410_GSTATUS4)); |
| 560 | 560 | ||
| 561 | /* save all necessary core registers not covered by the drivers */ | 561 | /* save all necessary core registers not covered by the drivers */ |
| 562 | 562 | ||
| 563 | s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save)); | 563 | s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save)); |
| 564 | s3c2410_pm_do_save(irq_save, ARRAY_SIZE(irq_save)); | 564 | s3c2410_pm_do_save(irq_save, ARRAY_SIZE(irq_save)); |
| 565 | s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save)); | 565 | s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save)); |
| 566 | s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save)); | 566 | s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save)); |
| 567 | 567 | ||
| 568 | /* set the irq configuration for wake */ | 568 | /* set the irq configuration for wake */ |
| 569 | 569 | ||
| 570 | s3c2410_pm_configure_extint(); | 570 | s3c2410_pm_configure_extint(); |
| 571 | 571 | ||
| 572 | DBG("sleep: irq wakeup masks: %08lx,%08lx\n", | 572 | DBG("sleep: irq wakeup masks: %08lx,%08lx\n", |
| 573 | s3c_irqwake_intmask, s3c_irqwake_eintmask); | 573 | s3c_irqwake_intmask, s3c_irqwake_eintmask); |
| 574 | 574 | ||
| 575 | __raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK); | 575 | __raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK); |
| 576 | __raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK); | 576 | __raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK); |
| 577 | 577 | ||
| 578 | /* ack any outstanding external interrupts before we go to sleep */ | 578 | /* ack any outstanding external interrupts before we go to sleep */ |
| 579 | 579 | ||
| 580 | __raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND); | 580 | __raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND); |
| 581 | 581 | ||
| 582 | /* flush cache back to ram */ | 582 | /* flush cache back to ram */ |
| 583 | 583 | ||
| 584 | arm920_flush_kern_cache_all(); | 584 | arm920_flush_kern_cache_all(); |
| 585 | 585 | ||
| 586 | s3c2410_pm_check_store(); | 586 | s3c2410_pm_check_store(); |
| 587 | 587 | ||
| 588 | // need to make some form of time-delta | ||
| 589 | |||
| 590 | /* send the cpu to sleep... */ | 588 | /* send the cpu to sleep... */ |
| 591 | 589 | ||
| 592 | __raw_writel(0x00, S3C2410_CLKCON); /* turn off clocks over sleep */ | 590 | __raw_writel(0x00, S3C2410_CLKCON); /* turn off clocks over sleep */ |
| 593 | 591 | ||
| 594 | s3c2410_cpu_suspend(regs_save); | 592 | s3c2410_cpu_suspend(regs_save); |
| 593 | |||
| 594 | /* restore the cpu state */ | ||
| 595 | |||
| 596 | cpu_init(); | ||
| 595 | 597 | ||
| 596 | /* unset the return-from-sleep flag, to ensure reset */ | 598 | /* unset the return-from-sleep flag, to ensure reset */ |
| 597 | 599 | ||
| 598 | tmp = __raw_readl(S3C2410_GSTATUS2); | 600 | tmp = __raw_readl(S3C2410_GSTATUS2); |
| 599 | tmp &= S3C2410_GSTATUS2_OFFRESET; | 601 | tmp &= S3C2410_GSTATUS2_OFFRESET; |
| 600 | __raw_writel(tmp, S3C2410_GSTATUS2); | 602 | __raw_writel(tmp, S3C2410_GSTATUS2); |
| 601 | 603 | ||
| 602 | /* restore the system state */ | 604 | /* restore the system state */ |
| 603 | 605 | ||
| 604 | s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save)); | 606 | s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save)); |
| 605 | s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save)); | 607 | s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save)); |
| 606 | s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save)); | 608 | s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save)); |
| 607 | s3c2410_pm_do_restore(uart_save, ARRAY_SIZE(uart_save)); | 609 | s3c2410_pm_do_restore(uart_save, ARRAY_SIZE(uart_save)); |
| 608 | 610 | ||
| 609 | s3c2410_pm_debug_init(); | 611 | s3c2410_pm_debug_init(); |
| 610 | 612 | ||
| 611 | /* check what irq (if any) restored the system */ | 613 | /* check what irq (if any) restored the system */ |
| 612 | 614 | ||
| 613 | DBG("post sleep: IRQs 0x%08x, 0x%08x\n", | 615 | DBG("post sleep: IRQs 0x%08x, 0x%08x\n", |
| 614 | __raw_readl(S3C2410_SRCPND), | 616 | __raw_readl(S3C2410_SRCPND), |
| 615 | __raw_readl(S3C2410_EINTPEND)); | 617 | __raw_readl(S3C2410_EINTPEND)); |
| 616 | 618 | ||
| 617 | s3c2410_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND), | 619 | s3c2410_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND), |
| 618 | s3c_irqwake_intmask); | 620 | s3c_irqwake_intmask); |
| 619 | 621 | ||
| 620 | s3c2410_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND), | 622 | s3c2410_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND), |
| 621 | s3c_irqwake_eintmask); | 623 | s3c_irqwake_eintmask); |
| 622 | 624 | ||
| 623 | DBG("post sleep, preparing to return\n"); | 625 | DBG("post sleep, preparing to return\n"); |
| 624 | 626 | ||
| 625 | s3c2410_pm_check_restore(); | 627 | s3c2410_pm_check_restore(); |
| 626 | 628 | ||
| 627 | /* ok, let's return from sleep */ | 629 | /* ok, let's return from sleep */ |
| 628 | 630 | ||
| 629 | DBG("S3C2410 PM Resume (post-restore)\n"); | 631 | DBG("S3C2410 PM Resume (post-restore)\n"); |
| 630 | return 0; | 632 | return 0; |
| 631 | } | 633 | } |
| 632 | 634 | ||
| 633 | /* | 635 | /* |
| 634 | * Called after processes are frozen, but before we shut down devices. | 636 | * Called after processes are frozen, but before we shut down devices. |
| 635 | */ | 637 | */ |
| 636 | static int s3c2410_pm_prepare(suspend_state_t state) | 638 | static int s3c2410_pm_prepare(suspend_state_t state) |
| 637 | { | 639 | { |
| 638 | return 0; | 640 | return 0; |
| 639 | } | 641 | } |
| 640 | 642 | ||
| 641 | /* | 643 | /* |
| 642 | * Called after devices are re-setup, but before processes are thawed. | 644 | * Called after devices are re-setup, but before processes are thawed. |
| 643 | */ | 645 | */ |
| 644 | static int s3c2410_pm_finish(suspend_state_t state) | 646 | static int s3c2410_pm_finish(suspend_state_t state) |
| 645 | { | 647 | { |
| 646 | return 0; | 648 | return 0; |
| 647 | } | 649 | } |
| 648 | 650 | ||
| 649 | /* | 651 | /* |
| 650 | * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk. | 652 | * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk. |
| 651 | */ | 653 | */ |
| 652 | static struct pm_ops s3c2410_pm_ops = { | 654 | static struct pm_ops s3c2410_pm_ops = { |
| 653 | .pm_disk_mode = PM_DISK_FIRMWARE, | 655 | .pm_disk_mode = PM_DISK_FIRMWARE, |
| 654 | .prepare = s3c2410_pm_prepare, | 656 | .prepare = s3c2410_pm_prepare, |
| 655 | .enter = s3c2410_pm_enter, | 657 | .enter = s3c2410_pm_enter, |
| 656 | .finish = s3c2410_pm_finish, | 658 | .finish = s3c2410_pm_finish, |
| 657 | }; | 659 | }; |
| 658 | 660 | ||
| 659 | /* s3c2410_pm_init | 661 | /* s3c2410_pm_init |
| 660 | * | 662 | * |
| 661 | * Attach the power management functions. This should be called | 663 | * Attach the power management functions. This should be called |
| 662 | * from the board specific initialisation if the board supports | 664 | * from the board specific initialisation if the board supports |
| 663 | * it. | 665 | * it. |
| 664 | */ | 666 | */ |
| 665 | 667 | ||
| 666 | int __init s3c2410_pm_init(void) | 668 | int __init s3c2410_pm_init(void) |
| 667 | { | 669 | { |
| 668 | printk("S3C2410 Power Management, (c) 2004 Simtec Electronics\n"); | 670 | printk("S3C2410 Power Management, (c) 2004 Simtec Electronics\n"); |
| 669 | 671 | ||
| 670 | pm_set_ops(&s3c2410_pm_ops); | 672 | pm_set_ops(&s3c2410_pm_ops); |
| 671 | return 0; | 673 | return 0; |
arch/arm/mach-s3c2410/s3c2440-irq.c
| 1 | /* linux/arch/arm/mach-s3c2410/s3c2440-irq.c | 1 | /* linux/arch/arm/mach-s3c2410/s3c2440-irq.c |
| 2 | * | 2 | * |
| 3 | * Copyright (c) 2003,2004 Simtec Electronics | 3 | * Copyright (c) 2003,2004 Simtec Electronics |
| 4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; either version 2 of the License, or | 8 | * the Free Software Foundation; either version 2 of the License, or |
| 9 | * (at your option) any later version. | 9 | * (at your option) any later version. |
| 10 | * | 10 | * |
| 11 | * This program is distributed in the hope that it will be useful, | 11 | * This program is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | * GNU General Public License for more details. | 14 | * GNU General Public License for more details. |
| 15 | * | 15 | * |
| 16 | * You should have received a copy of the GNU General Public License | 16 | * You should have received a copy of the GNU General Public License |
| 17 | * along with this program; if not, write to the Free Software | 17 | * along with this program; if not, write to the Free Software |
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 19 | * | 19 | * |
| 20 | * Changelog: | 20 | * Changelog: |
| 21 | * 25-Jul-2005 BJD Split from irq.c | 21 | * 25-Jul-2005 BJD Split from irq.c |
| 22 | * | 22 | * |
| 23 | */ | 23 | */ |
| 24 | 24 | ||
| 25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
| 26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
| 27 | #include <linux/interrupt.h> | 27 | #include <linux/interrupt.h> |
| 28 | #include <linux/ioport.h> | 28 | #include <linux/ioport.h> |
| 29 | #include <linux/ptrace.h> | 29 | #include <linux/ptrace.h> |
| 30 | #include <linux/sysdev.h> | 30 | #include <linux/sysdev.h> |
| 31 | 31 | ||
| 32 | #include <asm/hardware.h> | 32 | #include <asm/hardware.h> |
| 33 | #include <asm/irq.h> | 33 | #include <asm/irq.h> |
| 34 | #include <asm/io.h> | 34 | #include <asm/io.h> |
| 35 | 35 | ||
| 36 | #include <asm/mach/irq.h> | 36 | #include <asm/mach/irq.h> |
| 37 | 37 | ||
| 38 | #include <asm/arch/regs-irq.h> | 38 | #include <asm/arch/regs-irq.h> |
| 39 | #include <asm/arch/regs-gpio.h> | 39 | #include <asm/arch/regs-gpio.h> |
| 40 | 40 | ||
| 41 | #include "cpu.h" | 41 | #include "cpu.h" |
| 42 | #include "pm.h" | 42 | #include "pm.h" |
| 43 | #include "irq.h" | 43 | #include "irq.h" |
| 44 | 44 | ||
| 45 | /* WDT/AC97 */ | 45 | /* WDT/AC97 */ |
| 46 | 46 | ||
| 47 | static void s3c_irq_demux_wdtac97(unsigned int irq, | 47 | static void s3c_irq_demux_wdtac97(unsigned int irq, |
| 48 | struct irqdesc *desc, | 48 | struct irqdesc *desc, |
| 49 | struct pt_regs *regs) | 49 | struct pt_regs *regs) |
| 50 | { | 50 | { |
| 51 | unsigned int subsrc, submsk; | 51 | unsigned int subsrc, submsk; |
| 52 | struct irqdesc *mydesc; | 52 | struct irqdesc *mydesc; |
| 53 | 53 | ||
| 54 | /* read the current pending interrupts, and the mask | 54 | /* read the current pending interrupts, and the mask |
| 55 | * for what it is available */ | 55 | * for what it is available */ |
| 56 | 56 | ||
| 57 | subsrc = __raw_readl(S3C2410_SUBSRCPND); | 57 | subsrc = __raw_readl(S3C2410_SUBSRCPND); |
| 58 | submsk = __raw_readl(S3C2410_INTSUBMSK); | 58 | submsk = __raw_readl(S3C2410_INTSUBMSK); |
| 59 | 59 | ||
| 60 | subsrc &= ~submsk; | 60 | subsrc &= ~submsk; |
| 61 | subsrc >>= 13; | 61 | subsrc >>= 13; |
| 62 | subsrc &= 3; | 62 | subsrc &= 3; |
| 63 | 63 | ||
| 64 | if (subsrc != 0) { | 64 | if (subsrc != 0) { |
| 65 | if (subsrc & 1) { | 65 | if (subsrc & 1) { |
| 66 | mydesc = irq_desc + IRQ_S3C2440_WDT; | 66 | mydesc = irq_desc + IRQ_S3C2440_WDT; |
| 67 | mydesc->handle( IRQ_S3C2440_WDT, mydesc, regs); | 67 | desc_handle_irq(IRQ_S3C2440_WDT, mydesc, regs); |
| 68 | } | 68 | } |
| 69 | if (subsrc & 2) { | 69 | if (subsrc & 2) { |
| 70 | mydesc = irq_desc + IRQ_S3C2440_AC97; | 70 | mydesc = irq_desc + IRQ_S3C2440_AC97; |
| 71 | mydesc->handle(IRQ_S3C2440_AC97, mydesc, regs); | 71 | desc_handle_irq(IRQ_S3C2440_AC97, mydesc, regs); |
| 72 | } | 72 | } |
| 73 | } | 73 | } |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | 76 | ||
| 77 | #define INTMSK_WDT (1UL << (IRQ_WDT - IRQ_EINT0)) | 77 | #define INTMSK_WDT (1UL << (IRQ_WDT - IRQ_EINT0)) |
| 78 | 78 | ||
| 79 | static void | 79 | static void |
| 80 | s3c_irq_wdtac97_mask(unsigned int irqno) | 80 | s3c_irq_wdtac97_mask(unsigned int irqno) |
| 81 | { | 81 | { |
| 82 | s3c_irqsub_mask(irqno, INTMSK_WDT, 3<<13); | 82 | s3c_irqsub_mask(irqno, INTMSK_WDT, 3<<13); |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | static void | 85 | static void |
| 86 | s3c_irq_wdtac97_unmask(unsigned int irqno) | 86 | s3c_irq_wdtac97_unmask(unsigned int irqno) |
| 87 | { | 87 | { |
| 88 | s3c_irqsub_unmask(irqno, INTMSK_WDT); | 88 | s3c_irqsub_unmask(irqno, INTMSK_WDT); |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | static void | 91 | static void |
| 92 | s3c_irq_wdtac97_ack(unsigned int irqno) | 92 | s3c_irq_wdtac97_ack(unsigned int irqno) |
| 93 | { | 93 | { |
| 94 | s3c_irqsub_maskack(irqno, INTMSK_WDT, 3<<13); | 94 | s3c_irqsub_maskack(irqno, INTMSK_WDT, 3<<13); |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | static struct irqchip s3c_irq_wdtac97 = { | 97 | static struct irqchip s3c_irq_wdtac97 = { |
| 98 | .mask = s3c_irq_wdtac97_mask, | 98 | .mask = s3c_irq_wdtac97_mask, |
| 99 | .unmask = s3c_irq_wdtac97_unmask, | 99 | .unmask = s3c_irq_wdtac97_unmask, |
| 100 | .ack = s3c_irq_wdtac97_ack, | 100 | .ack = s3c_irq_wdtac97_ack, |
| 101 | }; | 101 | }; |
| 102 | 102 | ||
| 103 | /* camera irq */ | 103 | /* camera irq */ |
| 104 | 104 | ||
| 105 | static void s3c_irq_demux_cam(unsigned int irq, | 105 | static void s3c_irq_demux_cam(unsigned int irq, |
| 106 | struct irqdesc *desc, | 106 | struct irqdesc *desc, |
| 107 | struct pt_regs *regs) | 107 | struct pt_regs *regs) |
| 108 | { | 108 | { |
| 109 | unsigned int subsrc, submsk; | 109 | unsigned int subsrc, submsk; |
| 110 | struct irqdesc *mydesc; | 110 | struct irqdesc *mydesc; |
| 111 | 111 | ||
| 112 | /* read the current pending interrupts, and the mask | 112 | /* read the current pending interrupts, and the mask |
| 113 | * for what it is available */ | 113 | * for what it is available */ |
| 114 | 114 | ||
| 115 | subsrc = __raw_readl(S3C2410_SUBSRCPND); | 115 | subsrc = __raw_readl(S3C2410_SUBSRCPND); |
| 116 | submsk = __raw_readl(S3C2410_INTSUBMSK); | 116 | submsk = __raw_readl(S3C2410_INTSUBMSK); |
| 117 | 117 | ||
| 118 | subsrc &= ~submsk; | 118 | subsrc &= ~submsk; |
| 119 | subsrc >>= 11; | 119 | subsrc >>= 11; |
| 120 | subsrc &= 3; | 120 | subsrc &= 3; |
| 121 | 121 | ||
| 122 | if (subsrc != 0) { | 122 | if (subsrc != 0) { |
| 123 | if (subsrc & 1) { | 123 | if (subsrc & 1) { |
| 124 | mydesc = irq_desc + IRQ_S3C2440_CAM_C; | 124 | mydesc = irq_desc + IRQ_S3C2440_CAM_C; |
| 125 | mydesc->handle( IRQ_S3C2440_WDT, mydesc, regs); | 125 | desc_handle_irq(IRQ_S3C2440_CAM_C, mydesc, regs); |
| 126 | } | 126 | } |
| 127 | if (subsrc & 2) { | 127 | if (subsrc & 2) { |
| 128 | mydesc = irq_desc + IRQ_S3C2440_CAM_P; | 128 | mydesc = irq_desc + IRQ_S3C2440_CAM_P; |
| 129 | mydesc->handle(IRQ_S3C2440_AC97, mydesc, regs); | 129 | desc_handle_irq(IRQ_S3C2440_CAM_P, mydesc, regs); |
| 130 | } | 130 | } |
| 131 | } | 131 | } |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | #define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0)) | 134 | #define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0)) |
| 135 | 135 | ||
| 136 | static void | 136 | static void |
| 137 | s3c_irq_cam_mask(unsigned int irqno) | 137 | s3c_irq_cam_mask(unsigned int irqno) |
| 138 | { | 138 | { |
| 139 | s3c_irqsub_mask(irqno, INTMSK_CAM, 3<<11); | 139 | s3c_irqsub_mask(irqno, INTMSK_CAM, 3<<11); |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | static void | 142 | static void |
| 143 | s3c_irq_cam_unmask(unsigned int irqno) | 143 | s3c_irq_cam_unmask(unsigned int irqno) |
| 144 | { | 144 | { |
| 145 | s3c_irqsub_unmask(irqno, INTMSK_CAM); | 145 | s3c_irqsub_unmask(irqno, INTMSK_CAM); |
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | static void | 148 | static void |
| 149 | s3c_irq_cam_ack(unsigned int irqno) | 149 | s3c_irq_cam_ack(unsigned int irqno) |
| 150 | { | 150 | { |
| 151 | s3c_irqsub_maskack(irqno, INTMSK_CAM, 3<<11); | 151 | s3c_irqsub_maskack(irqno, INTMSK_CAM, 3<<11); |
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | static struct irqchip s3c_irq_cam = { | 154 | static struct irqchip s3c_irq_cam = { |
| 155 | .mask = s3c_irq_cam_mask, | 155 | .mask = s3c_irq_cam_mask, |
| 156 | .unmask = s3c_irq_cam_unmask, | 156 | .unmask = s3c_irq_cam_unmask, |
| 157 | .ack = s3c_irq_cam_ack, | 157 | .ack = s3c_irq_cam_ack, |
| 158 | }; | 158 | }; |
| 159 | 159 | ||
| 160 | static int s3c2440_irq_add(struct sys_device *sysdev) | 160 | static int s3c2440_irq_add(struct sys_device *sysdev) |
| 161 | { | 161 | { |
| 162 | unsigned int irqno; | 162 | unsigned int irqno; |
| 163 | 163 | ||
| 164 | printk("S3C2440: IRQ Support\n"); | 164 | printk("S3C2440: IRQ Support\n"); |
| 165 | 165 | ||
| 166 | set_irq_chip(IRQ_NFCON, &s3c_irq_level_chip); | 166 | set_irq_chip(IRQ_NFCON, &s3c_irq_level_chip); |
| 167 | set_irq_handler(IRQ_NFCON, do_level_IRQ); | 167 | set_irq_handler(IRQ_NFCON, do_level_IRQ); |
| 168 | set_irq_flags(IRQ_NFCON, IRQF_VALID); | 168 | set_irq_flags(IRQ_NFCON, IRQF_VALID); |
| 169 | 169 | ||
| 170 | /* add new chained handler for wdt, ac7 */ | 170 | /* add new chained handler for wdt, ac7 */ |
| 171 | 171 | ||
| 172 | set_irq_chip(IRQ_WDT, &s3c_irq_level_chip); | 172 | set_irq_chip(IRQ_WDT, &s3c_irq_level_chip); |
| 173 | set_irq_handler(IRQ_WDT, do_level_IRQ); | 173 | set_irq_handler(IRQ_WDT, do_level_IRQ); |
| 174 | set_irq_chained_handler(IRQ_WDT, s3c_irq_demux_wdtac97); | 174 | set_irq_chained_handler(IRQ_WDT, s3c_irq_demux_wdtac97); |
| 175 | 175 | ||
| 176 | for (irqno = IRQ_S3C2440_WDT; irqno <= IRQ_S3C2440_AC97; irqno++) { | 176 | for (irqno = IRQ_S3C2440_WDT; irqno <= IRQ_S3C2440_AC97; irqno++) { |
| 177 | set_irq_chip(irqno, &s3c_irq_wdtac97); | 177 | set_irq_chip(irqno, &s3c_irq_wdtac97); |
| 178 | set_irq_handler(irqno, do_level_IRQ); | 178 | set_irq_handler(irqno, do_level_IRQ); |
| 179 | set_irq_flags(irqno, IRQF_VALID); | 179 | set_irq_flags(irqno, IRQF_VALID); |
| 180 | } | 180 | } |
| 181 | 181 | ||
| 182 | /* add chained handler for camera */ | 182 | /* add chained handler for camera */ |
| 183 | 183 | ||
| 184 | set_irq_chip(IRQ_CAM, &s3c_irq_level_chip); | 184 | set_irq_chip(IRQ_CAM, &s3c_irq_level_chip); |
| 185 | set_irq_handler(IRQ_CAM, do_level_IRQ); | 185 | set_irq_handler(IRQ_CAM, do_level_IRQ); |
| 186 | set_irq_chained_handler(IRQ_CAM, s3c_irq_demux_cam); | 186 | set_irq_chained_handler(IRQ_CAM, s3c_irq_demux_cam); |
| 187 | 187 | ||
| 188 | for (irqno = IRQ_S3C2440_CAM_C; irqno <= IRQ_S3C2440_CAM_P; irqno++) { | 188 | for (irqno = IRQ_S3C2440_CAM_C; irqno <= IRQ_S3C2440_CAM_P; irqno++) { |
| 189 | set_irq_chip(irqno, &s3c_irq_cam); | 189 | set_irq_chip(irqno, &s3c_irq_cam); |
| 190 | set_irq_handler(irqno, do_level_IRQ); | 190 | set_irq_handler(irqno, do_level_IRQ); |
| 191 | set_irq_flags(irqno, IRQF_VALID); | 191 | set_irq_flags(irqno, IRQF_VALID); |
| 192 | } | 192 | } |
| 193 | 193 | ||
| 194 | return 0; | 194 | return 0; |
| 195 | } | 195 | } |
| 196 | 196 | ||
| 197 | static struct sysdev_driver s3c2440_irq_driver = { | 197 | static struct sysdev_driver s3c2440_irq_driver = { |
| 198 | .add = s3c2440_irq_add, | 198 | .add = s3c2440_irq_add, |
| 199 | }; | 199 | }; |
| 200 | 200 | ||
| 201 | static int s3c24xx_irq_driver(void) | 201 | static int s3c24xx_irq_driver(void) |
| 202 | { | 202 | { |
| 203 | return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_irq_driver); | 203 | return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_irq_driver); |
| 204 | } | 204 | } |
| 205 | 205 | ||
| 206 | arch_initcall(s3c24xx_irq_driver); | 206 | arch_initcall(s3c24xx_irq_driver); |
| 207 | 207 | ||
| 208 | 208 |
arch/arm/mach-sa1100/irq.c
| 1 | /* | 1 | /* |
| 2 | * linux/arch/arm/mach-sa1100/irq.c | 2 | * linux/arch/arm/mach-sa1100/irq.c |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 1999-2001 Nicolas Pitre | 4 | * Copyright (C) 1999-2001 Nicolas Pitre |
| 5 | * | 5 | * |
| 6 | * Generic IRQ handling for the SA11x0, GPIO 11-27 IRQ demultiplexing. | 6 | * Generic IRQ handling for the SA11x0, GPIO 11-27 IRQ demultiplexing. |
| 7 | * | 7 | * |
| 8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
| 9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
| 10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
| 11 | */ | 11 | */ |
| 12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
| 13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 14 | #include <linux/ioport.h> | 14 | #include <linux/ioport.h> |
| 15 | #include <linux/ptrace.h> | 15 | #include <linux/ptrace.h> |
| 16 | #include <linux/sysdev.h> | 16 | #include <linux/sysdev.h> |
| 17 | 17 | ||
| 18 | #include <asm/hardware.h> | 18 | #include <asm/hardware.h> |
| 19 | #include <asm/irq.h> | 19 | #include <asm/irq.h> |
| 20 | #include <asm/mach/irq.h> | 20 | #include <asm/mach/irq.h> |
| 21 | 21 | ||
| 22 | #include "generic.h" | 22 | #include "generic.h" |
| 23 | 23 | ||
| 24 | 24 | ||
| 25 | /* | 25 | /* |
| 26 | * SA1100 GPIO edge detection for IRQs: | 26 | * SA1100 GPIO edge detection for IRQs: |
| 27 | * IRQs are generated on Falling-Edge, Rising-Edge, or both. | 27 | * IRQs are generated on Falling-Edge, Rising-Edge, or both. |
| 28 | * Use this instead of directly setting GRER/GFER. | 28 | * Use this instead of directly setting GRER/GFER. |
| 29 | */ | 29 | */ |
| 30 | static int GPIO_IRQ_rising_edge; | 30 | static int GPIO_IRQ_rising_edge; |
| 31 | static int GPIO_IRQ_falling_edge; | 31 | static int GPIO_IRQ_falling_edge; |
| 32 | static int GPIO_IRQ_mask = (1 << 11) - 1; | 32 | static int GPIO_IRQ_mask = (1 << 11) - 1; |
| 33 | 33 | ||
| 34 | /* | 34 | /* |
| 35 | * To get the GPIO number from an IRQ number | 35 | * To get the GPIO number from an IRQ number |
| 36 | */ | 36 | */ |
| 37 | #define GPIO_11_27_IRQ(i) ((i) - 21) | 37 | #define GPIO_11_27_IRQ(i) ((i) - 21) |
| 38 | #define GPIO11_27_MASK(irq) (1 << GPIO_11_27_IRQ(irq)) | 38 | #define GPIO11_27_MASK(irq) (1 << GPIO_11_27_IRQ(irq)) |
| 39 | 39 | ||
| 40 | static int sa1100_gpio_type(unsigned int irq, unsigned int type) | 40 | static int sa1100_gpio_type(unsigned int irq, unsigned int type) |
| 41 | { | 41 | { |
| 42 | unsigned int mask; | 42 | unsigned int mask; |
| 43 | 43 | ||
| 44 | if (irq <= 10) | 44 | if (irq <= 10) |
| 45 | mask = 1 << irq; | 45 | mask = 1 << irq; |
| 46 | else | 46 | else |
| 47 | mask = GPIO11_27_MASK(irq); | 47 | mask = GPIO11_27_MASK(irq); |
| 48 | 48 | ||
| 49 | if (type == IRQT_PROBE) { | 49 | if (type == IRQT_PROBE) { |
| 50 | if ((GPIO_IRQ_rising_edge | GPIO_IRQ_falling_edge) & mask) | 50 | if ((GPIO_IRQ_rising_edge | GPIO_IRQ_falling_edge) & mask) |
| 51 | return 0; | 51 | return 0; |
| 52 | type = __IRQT_RISEDGE | __IRQT_FALEDGE; | 52 | type = __IRQT_RISEDGE | __IRQT_FALEDGE; |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | if (type & __IRQT_RISEDGE) { | 55 | if (type & __IRQT_RISEDGE) { |
| 56 | GPIO_IRQ_rising_edge |= mask; | 56 | GPIO_IRQ_rising_edge |= mask; |
| 57 | } else | 57 | } else |
| 58 | GPIO_IRQ_rising_edge &= ~mask; | 58 | GPIO_IRQ_rising_edge &= ~mask; |
| 59 | if (type & __IRQT_FALEDGE) { | 59 | if (type & __IRQT_FALEDGE) { |
| 60 | GPIO_IRQ_falling_edge |= mask; | 60 | GPIO_IRQ_falling_edge |= mask; |
| 61 | } else | 61 | } else |
| 62 | GPIO_IRQ_falling_edge &= ~mask; | 62 | GPIO_IRQ_falling_edge &= ~mask; |
| 63 | 63 | ||
| 64 | GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; | 64 | GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; |
| 65 | GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; | 65 | GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; |
| 66 | 66 | ||
| 67 | return 0; | 67 | return 0; |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | /* | 70 | /* |
| 71 | * GPIO IRQs must be acknowledged. This is for IRQs from 0 to 10. | 71 | * GPIO IRQs must be acknowledged. This is for IRQs from 0 to 10. |
| 72 | */ | 72 | */ |
| 73 | static void sa1100_low_gpio_ack(unsigned int irq) | 73 | static void sa1100_low_gpio_ack(unsigned int irq) |
| 74 | { | 74 | { |
| 75 | GEDR = (1 << irq); | 75 | GEDR = (1 << irq); |
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | static void sa1100_low_gpio_mask(unsigned int irq) | 78 | static void sa1100_low_gpio_mask(unsigned int irq) |
| 79 | { | 79 | { |
| 80 | ICMR &= ~(1 << irq); | 80 | ICMR &= ~(1 << irq); |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | static void sa1100_low_gpio_unmask(unsigned int irq) | 83 | static void sa1100_low_gpio_unmask(unsigned int irq) |
| 84 | { | 84 | { |
| 85 | ICMR |= 1 << irq; | 85 | ICMR |= 1 << irq; |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | static int sa1100_low_gpio_wake(unsigned int irq, unsigned int on) | 88 | static int sa1100_low_gpio_wake(unsigned int irq, unsigned int on) |
| 89 | { | 89 | { |
| 90 | if (on) | 90 | if (on) |
| 91 | PWER |= 1 << irq; | 91 | PWER |= 1 << irq; |
| 92 | else | 92 | else |
| 93 | PWER &= ~(1 << irq); | 93 | PWER &= ~(1 << irq); |
| 94 | return 0; | 94 | return 0; |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | static struct irqchip sa1100_low_gpio_chip = { | 97 | static struct irqchip sa1100_low_gpio_chip = { |
| 98 | .ack = sa1100_low_gpio_ack, | 98 | .ack = sa1100_low_gpio_ack, |
| 99 | .mask = sa1100_low_gpio_mask, | 99 | .mask = sa1100_low_gpio_mask, |
| 100 | .unmask = sa1100_low_gpio_unmask, | 100 | .unmask = sa1100_low_gpio_unmask, |
| 101 | .type = sa1100_gpio_type, | 101 | .set_type = sa1100_gpio_type, |
| 102 | .wake = sa1100_low_gpio_wake, | 102 | .set_wake = sa1100_low_gpio_wake, |
| 103 | }; | 103 | }; |
| 104 | 104 | ||
| 105 | /* | 105 | /* |
| 106 | * IRQ11 (GPIO11 through 27) handler. We enter here with the | 106 | * IRQ11 (GPIO11 through 27) handler. We enter here with the |
| 107 | * irq_controller_lock held, and IRQs disabled. Decode the IRQ | 107 | * irq_controller_lock held, and IRQs disabled. Decode the IRQ |
| 108 | * and call the handler. | 108 | * and call the handler. |
| 109 | */ | 109 | */ |
| 110 | static void | 110 | static void |
| 111 | sa1100_high_gpio_handler(unsigned int irq, struct irqdesc *desc, | 111 | sa1100_high_gpio_handler(unsigned int irq, struct irqdesc *desc, |
| 112 | struct pt_regs *regs) | 112 | struct pt_regs *regs) |
| 113 | { | 113 | { |
| 114 | unsigned int mask; | 114 | unsigned int mask; |
| 115 | 115 | ||
| 116 | mask = GEDR & 0xfffff800; | 116 | mask = GEDR & 0xfffff800; |
| 117 | do { | 117 | do { |
| 118 | /* | 118 | /* |
| 119 | * clear down all currently active IRQ sources. | 119 | * clear down all currently active IRQ sources. |
| 120 | * We will be processing them all. | 120 | * We will be processing them all. |
| 121 | */ | 121 | */ |
| 122 | GEDR = mask; | 122 | GEDR = mask; |
| 123 | 123 | ||
| 124 | irq = IRQ_GPIO11; | 124 | irq = IRQ_GPIO11; |
| 125 | desc = irq_desc + irq; | 125 | desc = irq_desc + irq; |
| 126 | mask >>= 11; | 126 | mask >>= 11; |
| 127 | do { | 127 | do { |
| 128 | if (mask & 1) | 128 | if (mask & 1) |
| 129 | desc->handle(irq, desc, regs); | 129 | desc_handle_irq(irq, desc, regs); |
| 130 | mask >>= 1; | 130 | mask >>= 1; |
| 131 | irq++; | 131 | irq++; |
| 132 | desc++; | 132 | desc++; |
| 133 | } while (mask); | 133 | } while (mask); |
| 134 | 134 | ||
| 135 | mask = GEDR & 0xfffff800; | 135 | mask = GEDR & 0xfffff800; |
| 136 | } while (mask); | 136 | } while (mask); |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | /* | 139 | /* |
| 140 | * Like GPIO0 to 10, GPIO11-27 IRQs need to be handled specially. | 140 | * Like GPIO0 to 10, GPIO11-27 IRQs need to be handled specially. |
| 141 | * In addition, the IRQs are all collected up into one bit in the | 141 | * In addition, the IRQs are all collected up into one bit in the |
| 142 | * interrupt controller registers. | 142 | * interrupt controller registers. |
| 143 | */ | 143 | */ |
| 144 | static void sa1100_high_gpio_ack(unsigned int irq) | 144 | static void sa1100_high_gpio_ack(unsigned int irq) |
| 145 | { | 145 | { |
| 146 | unsigned int mask = GPIO11_27_MASK(irq); | 146 | unsigned int mask = GPIO11_27_MASK(irq); |
| 147 | 147 | ||
| 148 | GEDR = mask; | 148 | GEDR = mask; |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | static void sa1100_high_gpio_mask(unsigned int irq) | 151 | static void sa1100_high_gpio_mask(unsigned int irq) |
| 152 | { | 152 | { |
| 153 | unsigned int mask = GPIO11_27_MASK(irq); | 153 | unsigned int mask = GPIO11_27_MASK(irq); |
| 154 | 154 | ||
| 155 | GPIO_IRQ_mask &= ~mask; | 155 | GPIO_IRQ_mask &= ~mask; |
| 156 | 156 | ||
| 157 | GRER &= ~mask; | 157 | GRER &= ~mask; |
| 158 | GFER &= ~mask; | 158 | GFER &= ~mask; |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | static void sa1100_high_gpio_unmask(unsigned int irq) | 161 | static void sa1100_high_gpio_unmask(unsigned int irq) |
| 162 | { | 162 | { |
| 163 | unsigned int mask = GPIO11_27_MASK(irq); | 163 | unsigned int mask = GPIO11_27_MASK(irq); |
| 164 | 164 | ||
| 165 | GPIO_IRQ_mask |= mask; | 165 | GPIO_IRQ_mask |= mask; |
| 166 | 166 | ||
| 167 | GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; | 167 | GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; |
| 168 | GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; | 168 | GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; |
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | static int sa1100_high_gpio_wake(unsigned int irq, unsigned int on) | 171 | static int sa1100_high_gpio_wake(unsigned int irq, unsigned int on) |
| 172 | { | 172 | { |
| 173 | if (on) | 173 | if (on) |
| 174 | PWER |= GPIO11_27_MASK(irq); | 174 | PWER |= GPIO11_27_MASK(irq); |
| 175 | else | 175 | else |
| 176 | PWER &= ~GPIO11_27_MASK(irq); | 176 | PWER &= ~GPIO11_27_MASK(irq); |
| 177 | return 0; | 177 | return 0; |
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | static struct irqchip sa1100_high_gpio_chip = { | 180 | static struct irqchip sa1100_high_gpio_chip = { |
| 181 | .ack = sa1100_high_gpio_ack, | 181 | .ack = sa1100_high_gpio_ack, |
| 182 | .mask = sa1100_high_gpio_mask, | 182 | .mask = sa1100_high_gpio_mask, |
| 183 | .unmask = sa1100_high_gpio_unmask, | 183 | .unmask = sa1100_high_gpio_unmask, |
| 184 | .type = sa1100_gpio_type, | 184 | .set_type = sa1100_gpio_type, |
| 185 | .wake = sa1100_high_gpio_wake, | 185 | .set_wake = sa1100_high_gpio_wake, |
| 186 | }; | 186 | }; |
| 187 | 187 | ||
| 188 | /* | 188 | /* |
| 189 | * We don't need to ACK IRQs on the SA1100 unless they're GPIOs | 189 | * We don't need to ACK IRQs on the SA1100 unless they're GPIOs |
| 190 | * this is for internal IRQs i.e. from 11 to 31. | 190 | * this is for internal IRQs i.e. from 11 to 31. |
| 191 | */ | 191 | */ |
| 192 | static void sa1100_mask_irq(unsigned int irq) | 192 | static void sa1100_mask_irq(unsigned int irq) |
| 193 | { | 193 | { |
| 194 | ICMR &= ~(1 << irq); | 194 | ICMR &= ~(1 << irq); |
| 195 | } | 195 | } |
| 196 | 196 | ||
| 197 | static void sa1100_unmask_irq(unsigned int irq) | 197 | static void sa1100_unmask_irq(unsigned int irq) |
| 198 | { | 198 | { |
| 199 | ICMR |= (1 << irq); | 199 | ICMR |= (1 << irq); |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | static struct irqchip sa1100_normal_chip = { | 202 | static struct irqchip sa1100_normal_chip = { |
| 203 | .ack = sa1100_mask_irq, | 203 | .ack = sa1100_mask_irq, |
| 204 | .mask = sa1100_mask_irq, | 204 | .mask = sa1100_mask_irq, |
| 205 | .unmask = sa1100_unmask_irq, | 205 | .unmask = sa1100_unmask_irq, |
| 206 | }; | 206 | }; |
| 207 | 207 | ||
| 208 | static struct resource irq_resource = { | 208 | static struct resource irq_resource = { |
| 209 | .name = "irqs", | 209 | .name = "irqs", |
| 210 | .start = 0x90050000, | 210 | .start = 0x90050000, |
| 211 | .end = 0x9005ffff, | 211 | .end = 0x9005ffff, |
| 212 | }; | 212 | }; |
| 213 | 213 | ||
| 214 | static struct sa1100irq_state { | 214 | static struct sa1100irq_state { |
| 215 | unsigned int saved; | 215 | unsigned int saved; |
| 216 | unsigned int icmr; | 216 | unsigned int icmr; |
| 217 | unsigned int iclr; | 217 | unsigned int iclr; |
| 218 | unsigned int iccr; | 218 | unsigned int iccr; |
| 219 | } sa1100irq_state; | 219 | } sa1100irq_state; |
| 220 | 220 | ||
| 221 | static int sa1100irq_suspend(struct sys_device *dev, pm_message_t state) | 221 | static int sa1100irq_suspend(struct sys_device *dev, pm_message_t state) |
| 222 | { | 222 | { |
| 223 | struct sa1100irq_state *st = &sa1100irq_state; | 223 | struct sa1100irq_state *st = &sa1100irq_state; |
| 224 | 224 | ||
| 225 | st->saved = 1; | 225 | st->saved = 1; |
| 226 | st->icmr = ICMR; | 226 | st->icmr = ICMR; |
| 227 | st->iclr = ICLR; | 227 | st->iclr = ICLR; |
| 228 | st->iccr = ICCR; | 228 | st->iccr = ICCR; |
| 229 | 229 | ||
| 230 | /* | 230 | /* |
| 231 | * Disable all GPIO-based interrupts. | 231 | * Disable all GPIO-based interrupts. |
| 232 | */ | 232 | */ |
| 233 | ICMR &= ~(IC_GPIO11_27|IC_GPIO10|IC_GPIO9|IC_GPIO8|IC_GPIO7| | 233 | ICMR &= ~(IC_GPIO11_27|IC_GPIO10|IC_GPIO9|IC_GPIO8|IC_GPIO7| |
| 234 | IC_GPIO6|IC_GPIO5|IC_GPIO4|IC_GPIO3|IC_GPIO2| | 234 | IC_GPIO6|IC_GPIO5|IC_GPIO4|IC_GPIO3|IC_GPIO2| |
| 235 | IC_GPIO1|IC_GPIO0); | 235 | IC_GPIO1|IC_GPIO0); |
| 236 | 236 | ||
| 237 | /* | 237 | /* |
| 238 | * Set the appropriate edges for wakeup. | 238 | * Set the appropriate edges for wakeup. |
| 239 | */ | 239 | */ |
| 240 | GRER = PWER & GPIO_IRQ_rising_edge; | 240 | GRER = PWER & GPIO_IRQ_rising_edge; |
| 241 | GFER = PWER & GPIO_IRQ_falling_edge; | 241 | GFER = PWER & GPIO_IRQ_falling_edge; |
| 242 | 242 | ||
| 243 | /* | 243 | /* |
| 244 | * Clear any pending GPIO interrupts. | 244 | * Clear any pending GPIO interrupts. |
| 245 | */ | 245 | */ |
| 246 | GEDR = GEDR; | 246 | GEDR = GEDR; |
| 247 | 247 | ||
| 248 | return 0; | 248 | return 0; |
| 249 | } | 249 | } |
| 250 | 250 | ||
| 251 | static int sa1100irq_resume(struct sys_device *dev) | 251 | static int sa1100irq_resume(struct sys_device *dev) |
| 252 | { | 252 | { |
| 253 | struct sa1100irq_state *st = &sa1100irq_state; | 253 | struct sa1100irq_state *st = &sa1100irq_state; |
| 254 | 254 | ||
| 255 | if (st->saved) { | 255 | if (st->saved) { |
| 256 | ICCR = st->iccr; | 256 | ICCR = st->iccr; |
| 257 | ICLR = st->iclr; | 257 | ICLR = st->iclr; |
| 258 | 258 | ||
| 259 | GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; | 259 | GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; |
| 260 | GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; | 260 | GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; |
| 261 | 261 | ||
| 262 | ICMR = st->icmr; | 262 | ICMR = st->icmr; |
| 263 | } | 263 | } |
| 264 | return 0; | 264 | return 0; |
| 265 | } | 265 | } |
| 266 | 266 | ||
| 267 | static struct sysdev_class sa1100irq_sysclass = { | 267 | static struct sysdev_class sa1100irq_sysclass = { |
| 268 | set_kset_name("sa11x0-irq"), | 268 | set_kset_name("sa11x0-irq"), |
| 269 | .suspend = sa1100irq_suspend, | 269 | .suspend = sa1100irq_suspend, |
| 270 | .resume = sa1100irq_resume, | 270 | .resume = sa1100irq_resume, |
| 271 | }; | 271 | }; |
| 272 | 272 | ||
| 273 | static struct sys_device sa1100irq_device = { | 273 | static struct sys_device sa1100irq_device = { |
| 274 | .id = 0, | 274 | .id = 0, |
| 275 | .cls = &sa1100irq_sysclass, | 275 | .cls = &sa1100irq_sysclass, |
| 276 | }; | 276 | }; |
| 277 | 277 | ||
| 278 | static int __init sa1100irq_init_devicefs(void) | 278 | static int __init sa1100irq_init_devicefs(void) |
| 279 | { | 279 | { |
| 280 | sysdev_class_register(&sa1100irq_sysclass); | 280 | sysdev_class_register(&sa1100irq_sysclass); |
| 281 | return sysdev_register(&sa1100irq_device); | 281 | return sysdev_register(&sa1100irq_device); |
| 282 | } | 282 | } |
| 283 | 283 | ||
| 284 | device_initcall(sa1100irq_init_devicefs); | 284 | device_initcall(sa1100irq_init_devicefs); |
| 285 | 285 | ||
| 286 | void __init sa1100_init_irq(void) | 286 | void __init sa1100_init_irq(void) |
| 287 | { | 287 | { |
| 288 | unsigned int irq; | 288 | unsigned int irq; |
| 289 | 289 | ||
| 290 | request_resource(&iomem_resource, &irq_resource); | 290 | request_resource(&iomem_resource, &irq_resource); |
| 291 | 291 | ||
| 292 | /* disable all IRQs */ | 292 | /* disable all IRQs */ |
| 293 | ICMR = 0; | 293 | ICMR = 0; |
| 294 | 294 | ||
| 295 | /* all IRQs are IRQ, not FIQ */ | 295 | /* all IRQs are IRQ, not FIQ */ |
| 296 | ICLR = 0; | 296 | ICLR = 0; |
| 297 | 297 | ||
| 298 | /* clear all GPIO edge detects */ | 298 | /* clear all GPIO edge detects */ |
| 299 | GFER = 0; | 299 | GFER = 0; |
| 300 | GRER = 0; | 300 | GRER = 0; |
| 301 | GEDR = -1; | 301 | GEDR = -1; |
| 302 | 302 | ||
| 303 | /* | 303 | /* |
| 304 | * Whatever the doc says, this has to be set for the wait-on-irq | 304 | * Whatever the doc says, this has to be set for the wait-on-irq |
| 305 | * instruction to work... on a SA1100 rev 9 at least. | 305 | * instruction to work... on a SA1100 rev 9 at least. |
| 306 | */ | 306 | */ |
| 307 | ICCR = 1; | 307 | ICCR = 1; |
| 308 | 308 | ||
| 309 | for (irq = 0; irq <= 10; irq++) { | 309 | for (irq = 0; irq <= 10; irq++) { |
| 310 | set_irq_chip(irq, &sa1100_low_gpio_chip); | 310 | set_irq_chip(irq, &sa1100_low_gpio_chip); |
| 311 | set_irq_handler(irq, do_edge_IRQ); | 311 | set_irq_handler(irq, do_edge_IRQ); |
| 312 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 312 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
| 313 | } | 313 | } |
| 314 | 314 | ||
| 315 | for (irq = 12; irq <= 31; irq++) { | 315 | for (irq = 12; irq <= 31; irq++) { |
| 316 | set_irq_chip(irq, &sa1100_normal_chip); | 316 | set_irq_chip(irq, &sa1100_normal_chip); |
| 317 | set_irq_handler(irq, do_level_IRQ); | 317 | set_irq_handler(irq, do_level_IRQ); |
| 318 | set_irq_flags(irq, IRQF_VALID); | 318 | set_irq_flags(irq, IRQF_VALID); |
| 319 | } | 319 | } |
| 320 | 320 | ||
| 321 | for (irq = 32; irq <= 48; irq++) { | 321 | for (irq = 32; irq <= 48; irq++) { |
| 322 | set_irq_chip(irq, &sa1100_high_gpio_chip); | 322 | set_irq_chip(irq, &sa1100_high_gpio_chip); |
| 323 | set_irq_handler(irq, do_edge_IRQ); | 323 | set_irq_handler(irq, do_edge_IRQ); |
| 324 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 324 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
| 325 | } | 325 | } |
| 326 | 326 | ||
| 327 | /* | 327 | /* |
| 328 | * Install handler for GPIO 11-27 edge detect interrupts | 328 | * Install handler for GPIO 11-27 edge detect interrupts |
| 329 | */ | 329 | */ |
| 330 | set_irq_chip(IRQ_GPIO11_27, &sa1100_normal_chip); | 330 | set_irq_chip(IRQ_GPIO11_27, &sa1100_normal_chip); |
| 331 | set_irq_chained_handler(IRQ_GPIO11_27, sa1100_high_gpio_handler); | 331 | set_irq_chained_handler(IRQ_GPIO11_27, sa1100_high_gpio_handler); |
| 332 | } | 332 | } |
| 333 | 333 |
arch/arm/mach-sa1100/neponset.c
| 1 | /* | 1 | /* |
| 2 | * linux/arch/arm/mach-sa1100/neponset.c | 2 | * linux/arch/arm/mach-sa1100/neponset.c |
| 3 | * | 3 | * |
| 4 | */ | 4 | */ |
| 5 | #include <linux/kernel.h> | 5 | #include <linux/kernel.h> |
| 6 | #include <linux/init.h> | 6 | #include <linux/init.h> |
| 7 | #include <linux/ptrace.h> | 7 | #include <linux/ptrace.h> |
| 8 | #include <linux/tty.h> | 8 | #include <linux/tty.h> |
| 9 | #include <linux/ioport.h> | 9 | #include <linux/ioport.h> |
| 10 | #include <linux/serial_core.h> | 10 | #include <linux/serial_core.h> |
| 11 | #include <linux/device.h> | 11 | #include <linux/device.h> |
| 12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
| 13 | 13 | ||
| 14 | #include <asm/hardware.h> | 14 | #include <asm/hardware.h> |
| 15 | #include <asm/mach-types.h> | 15 | #include <asm/mach-types.h> |
| 16 | #include <asm/irq.h> | 16 | #include <asm/irq.h> |
| 17 | #include <asm/mach/map.h> | 17 | #include <asm/mach/map.h> |
| 18 | #include <asm/mach/irq.h> | 18 | #include <asm/mach/irq.h> |
| 19 | #include <asm/mach/serial_sa1100.h> | 19 | #include <asm/mach/serial_sa1100.h> |
| 20 | #include <asm/arch/assabet.h> | 20 | #include <asm/arch/assabet.h> |
| 21 | #include <asm/arch/neponset.h> | 21 | #include <asm/arch/neponset.h> |
| 22 | #include <asm/hardware/sa1111.h> | 22 | #include <asm/hardware/sa1111.h> |
| 23 | #include <asm/sizes.h> | 23 | #include <asm/sizes.h> |
| 24 | 24 | ||
| 25 | /* | 25 | /* |
| 26 | * Install handler for Neponset IRQ. Note that we have to loop here | 26 | * Install handler for Neponset IRQ. Note that we have to loop here |
| 27 | * since the ETHERNET and USAR IRQs are level based, and we need to | 27 | * since the ETHERNET and USAR IRQs are level based, and we need to |
| 28 | * ensure that the IRQ signal is deasserted before returning. This | 28 | * ensure that the IRQ signal is deasserted before returning. This |
| 29 | * is rather unfortunate. | 29 | * is rather unfortunate. |
| 30 | */ | 30 | */ |
| 31 | static void | 31 | static void |
| 32 | neponset_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) | 32 | neponset_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) |
| 33 | { | 33 | { |
| 34 | unsigned int irr; | 34 | unsigned int irr; |
| 35 | 35 | ||
| 36 | while (1) { | 36 | while (1) { |
| 37 | struct irqdesc *d; | 37 | struct irqdesc *d; |
| 38 | 38 | ||
| 39 | /* | 39 | /* |
| 40 | * Acknowledge the parent IRQ. | 40 | * Acknowledge the parent IRQ. |
| 41 | */ | 41 | */ |
| 42 | desc->chip->ack(irq); | 42 | desc->chip->ack(irq); |
| 43 | 43 | ||
| 44 | /* | 44 | /* |
| 45 | * Read the interrupt reason register. Let's have all | 45 | * Read the interrupt reason register. Let's have all |
| 46 | * active IRQ bits high. Note: there is a typo in the | 46 | * active IRQ bits high. Note: there is a typo in the |
| 47 | * Neponset user's guide for the SA1111 IRR level. | 47 | * Neponset user's guide for the SA1111 IRR level. |
| 48 | */ | 48 | */ |
| 49 | irr = IRR ^ (IRR_ETHERNET | IRR_USAR); | 49 | irr = IRR ^ (IRR_ETHERNET | IRR_USAR); |
| 50 | 50 | ||
| 51 | if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0) | 51 | if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0) |
| 52 | break; | 52 | break; |
| 53 | 53 | ||
| 54 | /* | 54 | /* |
| 55 | * Since there is no individual mask, we have to | 55 | * Since there is no individual mask, we have to |
| 56 | * mask the parent IRQ. This is safe, since we'll | 56 | * mask the parent IRQ. This is safe, since we'll |
| 57 | * recheck the register for any pending IRQs. | 57 | * recheck the register for any pending IRQs. |
| 58 | */ | 58 | */ |
| 59 | if (irr & (IRR_ETHERNET | IRR_USAR)) { | 59 | if (irr & (IRR_ETHERNET | IRR_USAR)) { |
| 60 | desc->chip->mask(irq); | 60 | desc->chip->mask(irq); |
| 61 | 61 | ||
| 62 | if (irr & IRR_ETHERNET) { | 62 | if (irr & IRR_ETHERNET) { |
| 63 | d = irq_desc + IRQ_NEPONSET_SMC9196; | 63 | d = irq_desc + IRQ_NEPONSET_SMC9196; |
| 64 | d->handle(IRQ_NEPONSET_SMC9196, d, regs); | 64 | desc_handle_irq(IRQ_NEPONSET_SMC9196, d, regs); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | if (irr & IRR_USAR) { | 67 | if (irr & IRR_USAR) { |
| 68 | d = irq_desc + IRQ_NEPONSET_USAR; | 68 | d = irq_desc + IRQ_NEPONSET_USAR; |
| 69 | d->handle(IRQ_NEPONSET_USAR, d, regs); | 69 | desc_handle_irq(IRQ_NEPONSET_USAR, d, regs); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | desc->chip->unmask(irq); | 72 | desc->chip->unmask(irq); |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | if (irr & IRR_SA1111) { | 75 | if (irr & IRR_SA1111) { |
| 76 | d = irq_desc + IRQ_NEPONSET_SA1111; | 76 | d = irq_desc + IRQ_NEPONSET_SA1111; |
| 77 | d->handle(IRQ_NEPONSET_SA1111, d, regs); | 77 | desc_handle_irq(IRQ_NEPONSET_SA1111, d, regs); |
| 78 | } | 78 | } |
| 79 | } | 79 | } |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | static void neponset_set_mctrl(struct uart_port *port, u_int mctrl) | 82 | static void neponset_set_mctrl(struct uart_port *port, u_int mctrl) |
| 83 | { | 83 | { |
| 84 | u_int mdm_ctl0 = MDM_CTL_0; | 84 | u_int mdm_ctl0 = MDM_CTL_0; |
| 85 | 85 | ||
| 86 | if (port->mapbase == _Ser1UTCR0) { | 86 | if (port->mapbase == _Ser1UTCR0) { |
| 87 | if (mctrl & TIOCM_RTS) | 87 | if (mctrl & TIOCM_RTS) |
| 88 | mdm_ctl0 &= ~MDM_CTL0_RTS2; | 88 | mdm_ctl0 &= ~MDM_CTL0_RTS2; |
| 89 | else | 89 | else |
| 90 | mdm_ctl0 |= MDM_CTL0_RTS2; | 90 | mdm_ctl0 |= MDM_CTL0_RTS2; |
| 91 | 91 | ||
| 92 | if (mctrl & TIOCM_DTR) | 92 | if (mctrl & TIOCM_DTR) |
| 93 | mdm_ctl0 &= ~MDM_CTL0_DTR2; | 93 | mdm_ctl0 &= ~MDM_CTL0_DTR2; |
| 94 | else | 94 | else |
| 95 | mdm_ctl0 |= MDM_CTL0_DTR2; | 95 | mdm_ctl0 |= MDM_CTL0_DTR2; |
| 96 | } else if (port->mapbase == _Ser3UTCR0) { | 96 | } else if (port->mapbase == _Ser3UTCR0) { |
| 97 | if (mctrl & TIOCM_RTS) | 97 | if (mctrl & TIOCM_RTS) |
| 98 | mdm_ctl0 &= ~MDM_CTL0_RTS1; | 98 | mdm_ctl0 &= ~MDM_CTL0_RTS1; |
| 99 | else | 99 | else |
| 100 | mdm_ctl0 |= MDM_CTL0_RTS1; | 100 | mdm_ctl0 |= MDM_CTL0_RTS1; |
| 101 | 101 | ||
| 102 | if (mctrl & TIOCM_DTR) | 102 | if (mctrl & TIOCM_DTR) |
| 103 | mdm_ctl0 &= ~MDM_CTL0_DTR1; | 103 | mdm_ctl0 &= ~MDM_CTL0_DTR1; |
| 104 | else | 104 | else |
| 105 | mdm_ctl0 |= MDM_CTL0_DTR1; | 105 | mdm_ctl0 |= MDM_CTL0_DTR1; |
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | MDM_CTL_0 = mdm_ctl0; | 108 | MDM_CTL_0 = mdm_ctl0; |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | static u_int neponset_get_mctrl(struct uart_port *port) | 111 | static u_int neponset_get_mctrl(struct uart_port *port) |
| 112 | { | 112 | { |
| 113 | u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR; | 113 | u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR; |
| 114 | u_int mdm_ctl1 = MDM_CTL_1; | 114 | u_int mdm_ctl1 = MDM_CTL_1; |
| 115 | 115 | ||
| 116 | if (port->mapbase == _Ser1UTCR0) { | 116 | if (port->mapbase == _Ser1UTCR0) { |
| 117 | if (mdm_ctl1 & MDM_CTL1_DCD2) | 117 | if (mdm_ctl1 & MDM_CTL1_DCD2) |
| 118 | ret &= ~TIOCM_CD; | 118 | ret &= ~TIOCM_CD; |
| 119 | if (mdm_ctl1 & MDM_CTL1_CTS2) | 119 | if (mdm_ctl1 & MDM_CTL1_CTS2) |
| 120 | ret &= ~TIOCM_CTS; | 120 | ret &= ~TIOCM_CTS; |
| 121 | if (mdm_ctl1 & MDM_CTL1_DSR2) | 121 | if (mdm_ctl1 & MDM_CTL1_DSR2) |
| 122 | ret &= ~TIOCM_DSR; | 122 | ret &= ~TIOCM_DSR; |
| 123 | } else if (port->mapbase == _Ser3UTCR0) { | 123 | } else if (port->mapbase == _Ser3UTCR0) { |
| 124 | if (mdm_ctl1 & MDM_CTL1_DCD1) | 124 | if (mdm_ctl1 & MDM_CTL1_DCD1) |
| 125 | ret &= ~TIOCM_CD; | 125 | ret &= ~TIOCM_CD; |
| 126 | if (mdm_ctl1 & MDM_CTL1_CTS1) | 126 | if (mdm_ctl1 & MDM_CTL1_CTS1) |
| 127 | ret &= ~TIOCM_CTS; | 127 | ret &= ~TIOCM_CTS; |
| 128 | if (mdm_ctl1 & MDM_CTL1_DSR1) | 128 | if (mdm_ctl1 & MDM_CTL1_DSR1) |
| 129 | ret &= ~TIOCM_DSR; | 129 | ret &= ~TIOCM_DSR; |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | return ret; | 132 | return ret; |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | static struct sa1100_port_fns neponset_port_fns __initdata = { | 135 | static struct sa1100_port_fns neponset_port_fns __initdata = { |
| 136 | .set_mctrl = neponset_set_mctrl, | 136 | .set_mctrl = neponset_set_mctrl, |
| 137 | .get_mctrl = neponset_get_mctrl, | 137 | .get_mctrl = neponset_get_mctrl, |
| 138 | }; | 138 | }; |
| 139 | 139 | ||
| 140 | static int neponset_probe(struct device *dev) | 140 | static int neponset_probe(struct device *dev) |
| 141 | { | 141 | { |
| 142 | sa1100_register_uart_fns(&neponset_port_fns); | 142 | sa1100_register_uart_fns(&neponset_port_fns); |
| 143 | 143 | ||
| 144 | /* | 144 | /* |
| 145 | * Install handler for GPIO25. | 145 | * Install handler for GPIO25. |
| 146 | */ | 146 | */ |
| 147 | set_irq_type(IRQ_GPIO25, IRQT_RISING); | 147 | set_irq_type(IRQ_GPIO25, IRQT_RISING); |
| 148 | set_irq_chained_handler(IRQ_GPIO25, neponset_irq_handler); | 148 | set_irq_chained_handler(IRQ_GPIO25, neponset_irq_handler); |
| 149 | 149 | ||
| 150 | /* | 150 | /* |
| 151 | * We would set IRQ_GPIO25 to be a wake-up IRQ, but | 151 | * We would set IRQ_GPIO25 to be a wake-up IRQ, but |
| 152 | * unfortunately something on the Neponset activates | 152 | * unfortunately something on the Neponset activates |
| 153 | * this IRQ on sleep (ethernet?) | 153 | * this IRQ on sleep (ethernet?) |
| 154 | */ | 154 | */ |
| 155 | #if 0 | 155 | #if 0 |
| 156 | enable_irq_wake(IRQ_GPIO25); | 156 | enable_irq_wake(IRQ_GPIO25); |
| 157 | #endif | 157 | #endif |
| 158 | 158 | ||
| 159 | /* | 159 | /* |
| 160 | * Setup other Neponset IRQs. SA1111 will be done by the | 160 | * Setup other Neponset IRQs. SA1111 will be done by the |
| 161 | * generic SA1111 code. | 161 | * generic SA1111 code. |
| 162 | */ | 162 | */ |
| 163 | set_irq_handler(IRQ_NEPONSET_SMC9196, do_simple_IRQ); | 163 | set_irq_handler(IRQ_NEPONSET_SMC9196, do_simple_IRQ); |
| 164 | set_irq_flags(IRQ_NEPONSET_SMC9196, IRQF_VALID | IRQF_PROBE); | 164 | set_irq_flags(IRQ_NEPONSET_SMC9196, IRQF_VALID | IRQF_PROBE); |
| 165 | set_irq_handler(IRQ_NEPONSET_USAR, do_simple_IRQ); | 165 | set_irq_handler(IRQ_NEPONSET_USAR, do_simple_IRQ); |
| 166 | set_irq_flags(IRQ_NEPONSET_USAR, IRQF_VALID | IRQF_PROBE); | 166 | set_irq_flags(IRQ_NEPONSET_USAR, IRQF_VALID | IRQF_PROBE); |
| 167 | 167 | ||
| 168 | /* | 168 | /* |
| 169 | * Disable GPIO 0/1 drivers so the buttons work on the module. | 169 | * Disable GPIO 0/1 drivers so the buttons work on the module. |
| 170 | */ | 170 | */ |
| 171 | NCR_0 = NCR_GP01_OFF; | 171 | NCR_0 = NCR_GP01_OFF; |
| 172 | 172 | ||
| 173 | return 0; | 173 | return 0; |
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | #ifdef CONFIG_PM | 176 | #ifdef CONFIG_PM |
| 177 | 177 | ||
| 178 | /* | 178 | /* |
| 179 | * LDM power management. | 179 | * LDM power management. |
| 180 | */ | 180 | */ |
| 181 | static int neponset_suspend(struct device *dev, pm_message_t state, u32 level) | 181 | static int neponset_suspend(struct device *dev, pm_message_t state, u32 level) |
| 182 | { | 182 | { |
| 183 | /* | 183 | /* |
| 184 | * Save state. | 184 | * Save state. |
| 185 | */ | 185 | */ |
| 186 | if (level == SUSPEND_SAVE_STATE || | 186 | if (level == SUSPEND_SAVE_STATE || |
| 187 | level == SUSPEND_DISABLE || | 187 | level == SUSPEND_DISABLE || |
| 188 | level == SUSPEND_POWER_DOWN) { | 188 | level == SUSPEND_POWER_DOWN) { |
| 189 | if (!dev->power.saved_state) | 189 | if (!dev->power.saved_state) |
| 190 | dev->power.saved_state = kmalloc(sizeof(unsigned int), GFP_KERNEL); | 190 | dev->power.saved_state = kmalloc(sizeof(unsigned int), GFP_KERNEL); |
| 191 | if (!dev->power.saved_state) | 191 | if (!dev->power.saved_state) |
| 192 | return -ENOMEM; | 192 | return -ENOMEM; |
| 193 | 193 | ||
| 194 | *(unsigned int *)dev->power.saved_state = NCR_0; | 194 | *(unsigned int *)dev->power.saved_state = NCR_0; |
| 195 | } | 195 | } |
| 196 | 196 | ||
| 197 | return 0; | 197 | return 0; |
| 198 | } | 198 | } |
| 199 | 199 | ||
| 200 | static int neponset_resume(struct device *dev, u32 level) | 200 | static int neponset_resume(struct device *dev, u32 level) |
| 201 | { | 201 | { |
| 202 | if (level == RESUME_RESTORE_STATE || level == RESUME_ENABLE) { | 202 | if (level == RESUME_RESTORE_STATE || level == RESUME_ENABLE) { |
| 203 | if (dev->power.saved_state) { | 203 | if (dev->power.saved_state) { |
| 204 | NCR_0 = *(unsigned int *)dev->power.saved_state; | 204 | NCR_0 = *(unsigned int *)dev->power.saved_state; |
| 205 | kfree(dev->power.saved_state); | 205 | kfree(dev->power.saved_state); |
| 206 | dev->power.saved_state = NULL; | 206 | dev->power.saved_state = NULL; |
| 207 | } | 207 | } |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | return 0; | 210 | return 0; |
| 211 | } | 211 | } |
| 212 | 212 | ||
| 213 | #else | 213 | #else |
| 214 | #define neponset_suspend NULL | 214 | #define neponset_suspend NULL |
| 215 | #define neponset_resume NULL | 215 | #define neponset_resume NULL |
| 216 | #endif | 216 | #endif |
| 217 | 217 | ||
| 218 | static struct device_driver neponset_device_driver = { | 218 | static struct device_driver neponset_device_driver = { |
| 219 | .name = "neponset", | 219 | .name = "neponset", |
| 220 | .bus = &platform_bus_type, | 220 | .bus = &platform_bus_type, |
| 221 | .probe = neponset_probe, | 221 | .probe = neponset_probe, |
| 222 | .suspend = neponset_suspend, | 222 | .suspend = neponset_suspend, |
| 223 | .resume = neponset_resume, | 223 | .resume = neponset_resume, |
| 224 | }; | 224 | }; |
| 225 | 225 | ||
| 226 | static struct resource neponset_resources[] = { | 226 | static struct resource neponset_resources[] = { |
| 227 | [0] = { | 227 | [0] = { |
| 228 | .start = 0x10000000, | 228 | .start = 0x10000000, |
| 229 | .end = 0x17ffffff, | 229 | .end = 0x17ffffff, |
| 230 | .flags = IORESOURCE_MEM, | 230 | .flags = IORESOURCE_MEM, |
| 231 | }, | 231 | }, |
| 232 | }; | 232 | }; |
| 233 | 233 | ||
| 234 | static struct platform_device neponset_device = { | 234 | static struct platform_device neponset_device = { |
| 235 | .name = "neponset", | 235 | .name = "neponset", |
| 236 | .id = 0, | 236 | .id = 0, |
| 237 | .num_resources = ARRAY_SIZE(neponset_resources), | 237 | .num_resources = ARRAY_SIZE(neponset_resources), |
| 238 | .resource = neponset_resources, | 238 | .resource = neponset_resources, |
| 239 | }; | 239 | }; |
| 240 | 240 | ||
| 241 | static struct resource sa1111_resources[] = { | 241 | static struct resource sa1111_resources[] = { |
| 242 | [0] = { | 242 | [0] = { |
| 243 | .start = 0x40000000, | 243 | .start = 0x40000000, |
| 244 | .end = 0x40001fff, | 244 | .end = 0x40001fff, |
| 245 | .flags = IORESOURCE_MEM, | 245 | .flags = IORESOURCE_MEM, |
| 246 | }, | 246 | }, |
| 247 | [1] = { | 247 | [1] = { |
| 248 | .start = IRQ_NEPONSET_SA1111, | 248 | .start = IRQ_NEPONSET_SA1111, |
| 249 | .end = IRQ_NEPONSET_SA1111, | 249 | .end = IRQ_NEPONSET_SA1111, |
| 250 | .flags = IORESOURCE_IRQ, | 250 | .flags = IORESOURCE_IRQ, |
| 251 | }, | 251 | }, |
| 252 | }; | 252 | }; |
| 253 | 253 | ||
| 254 | static u64 sa1111_dmamask = 0xffffffffUL; | 254 | static u64 sa1111_dmamask = 0xffffffffUL; |
| 255 | 255 | ||
| 256 | static struct platform_device sa1111_device = { | 256 | static struct platform_device sa1111_device = { |
| 257 | .name = "sa1111", | 257 | .name = "sa1111", |
| 258 | .id = 0, | 258 | .id = 0, |
| 259 | .dev = { | 259 | .dev = { |
| 260 | .dma_mask = &sa1111_dmamask, | 260 | .dma_mask = &sa1111_dmamask, |
| 261 | .coherent_dma_mask = 0xffffffff, | 261 | .coherent_dma_mask = 0xffffffff, |
| 262 | }, | 262 | }, |
| 263 | .num_resources = ARRAY_SIZE(sa1111_resources), | 263 | .num_resources = ARRAY_SIZE(sa1111_resources), |
| 264 | .resource = sa1111_resources, | 264 | .resource = sa1111_resources, |
| 265 | }; | 265 | }; |
| 266 | 266 | ||
| 267 | static struct resource smc91x_resources[] = { | 267 | static struct resource smc91x_resources[] = { |
| 268 | [0] = { | 268 | [0] = { |
| 269 | .name = "smc91x-regs", | 269 | .name = "smc91x-regs", |
| 270 | .start = SA1100_CS3_PHYS, | 270 | .start = SA1100_CS3_PHYS, |
| 271 | .end = SA1100_CS3_PHYS + 0x01ffffff, | 271 | .end = SA1100_CS3_PHYS + 0x01ffffff, |
| 272 | .flags = IORESOURCE_MEM, | 272 | .flags = IORESOURCE_MEM, |
| 273 | }, | 273 | }, |
| 274 | [1] = { | 274 | [1] = { |
| 275 | .start = IRQ_NEPONSET_SMC9196, | 275 | .start = IRQ_NEPONSET_SMC9196, |
| 276 | .end = IRQ_NEPONSET_SMC9196, | 276 | .end = IRQ_NEPONSET_SMC9196, |
| 277 | .flags = IORESOURCE_IRQ, | 277 | .flags = IORESOURCE_IRQ, |
| 278 | }, | 278 | }, |
| 279 | [2] = { | 279 | [2] = { |
| 280 | .name = "smc91x-attrib", | 280 | .name = "smc91x-attrib", |
| 281 | .start = SA1100_CS3_PHYS + 0x02000000, | 281 | .start = SA1100_CS3_PHYS + 0x02000000, |
| 282 | .end = SA1100_CS3_PHYS + 0x03ffffff, | 282 | .end = SA1100_CS3_PHYS + 0x03ffffff, |
| 283 | .flags = IORESOURCE_MEM, | 283 | .flags = IORESOURCE_MEM, |
| 284 | }, | 284 | }, |
| 285 | }; | 285 | }; |
| 286 | 286 | ||
| 287 | static struct platform_device smc91x_device = { | 287 | static struct platform_device smc91x_device = { |
| 288 | .name = "smc91x", | 288 | .name = "smc91x", |
| 289 | .id = 0, | 289 | .id = 0, |
| 290 | .num_resources = ARRAY_SIZE(smc91x_resources), | 290 | .num_resources = ARRAY_SIZE(smc91x_resources), |
| 291 | .resource = smc91x_resources, | 291 | .resource = smc91x_resources, |
| 292 | }; | 292 | }; |
| 293 | 293 | ||
| 294 | static struct platform_device *devices[] __initdata = { | 294 | static struct platform_device *devices[] __initdata = { |
| 295 | &neponset_device, | 295 | &neponset_device, |
| 296 | &sa1111_device, | 296 | &sa1111_device, |
| 297 | &smc91x_device, | 297 | &smc91x_device, |
| 298 | }; | 298 | }; |
| 299 | 299 | ||
| 300 | static int __init neponset_init(void) | 300 | static int __init neponset_init(void) |
| 301 | { | 301 | { |
| 302 | driver_register(&neponset_device_driver); | 302 | driver_register(&neponset_device_driver); |
| 303 | 303 | ||
| 304 | /* | 304 | /* |
| 305 | * The Neponset is only present on the Assabet machine type. | 305 | * The Neponset is only present on the Assabet machine type. |
| 306 | */ | 306 | */ |
| 307 | if (!machine_is_assabet()) | 307 | if (!machine_is_assabet()) |
| 308 | return -ENODEV; | 308 | return -ENODEV; |
| 309 | 309 | ||
| 310 | /* | 310 | /* |
| 311 | * Ensure that the memory bus request/grant signals are setup, | 311 | * Ensure that the memory bus request/grant signals are setup, |
| 312 | * and the grant is held in its inactive state, whether or not | 312 | * and the grant is held in its inactive state, whether or not |
| 313 | * we actually have a Neponset attached. | 313 | * we actually have a Neponset attached. |
| 314 | */ | 314 | */ |
| 315 | sa1110_mb_disable(); | 315 | sa1110_mb_disable(); |
| 316 | 316 | ||
| 317 | if (!machine_has_neponset()) { | 317 | if (!machine_has_neponset()) { |
| 318 | printk(KERN_DEBUG "Neponset expansion board not present\n"); | 318 | printk(KERN_DEBUG "Neponset expansion board not present\n"); |
| 319 | return -ENODEV; | 319 | return -ENODEV; |
| 320 | } | 320 | } |
| 321 | 321 | ||
| 322 | if (WHOAMI != 0x11) { | 322 | if (WHOAMI != 0x11) { |
| 323 | printk(KERN_WARNING "Neponset board detected, but " | 323 | printk(KERN_WARNING "Neponset board detected, but " |
| 324 | "wrong ID: %02x\n", WHOAMI); | 324 | "wrong ID: %02x\n", WHOAMI); |
| 325 | return -ENODEV; | 325 | return -ENODEV; |
| 326 | } | 326 | } |
| 327 | 327 | ||
| 328 | return platform_add_devices(devices, ARRAY_SIZE(devices)); | 328 | return platform_add_devices(devices, ARRAY_SIZE(devices)); |
| 329 | } | 329 | } |
| 330 | 330 | ||
| 331 | subsys_initcall(neponset_init); | 331 | subsys_initcall(neponset_init); |
| 332 | 332 | ||
| 333 | static struct map_desc neponset_io_desc[] __initdata = { | 333 | static struct map_desc neponset_io_desc[] __initdata = { |
| 334 | /* virtual physical length type */ | 334 | /* virtual physical length type */ |
| 335 | { 0xf3000000, 0x10000000, SZ_1M, MT_DEVICE }, /* System Registers */ | 335 | { 0xf3000000, 0x10000000, SZ_1M, MT_DEVICE }, /* System Registers */ |
| 336 | { 0xf4000000, 0x40000000, SZ_1M, MT_DEVICE } /* SA-1111 */ | 336 | { 0xf4000000, 0x40000000, SZ_1M, MT_DEVICE } /* SA-1111 */ |
| 337 | }; | 337 | }; |
| 338 | 338 | ||
| 339 | void __init neponset_map_io(void) | 339 | void __init neponset_map_io(void) |
| 340 | { | 340 | { |
| 341 | iotable_init(neponset_io_desc, ARRAY_SIZE(neponset_io_desc)); | 341 | iotable_init(neponset_io_desc, ARRAY_SIZE(neponset_io_desc)); |
| 342 | } | 342 | } |
| 343 | 343 |
arch/arm/mach-versatile/core.c
| 1 | /* | 1 | /* |
| 2 | * linux/arch/arm/mach-versatile/core.c | 2 | * linux/arch/arm/mach-versatile/core.c |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 1999 - 2003 ARM Limited | 4 | * Copyright (C) 1999 - 2003 ARM Limited |
| 5 | * Copyright (C) 2000 Deep Blue Solutions Ltd | 5 | * Copyright (C) 2000 Deep Blue Solutions Ltd |
| 6 | * | 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
| 8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
| 9 | * the Free Software Foundation; either version 2 of the License, or | 9 | * the Free Software Foundation; either version 2 of the License, or |
| 10 | * (at your option) any later version. | 10 | * (at your option) any later version. |
| 11 | * | 11 | * |
| 12 | * This program is distributed in the hope that it will be useful, | 12 | * This program is distributed in the hope that it will be useful, |
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 | * GNU General Public License for more details. | 15 | * GNU General Public License for more details. |
| 16 | * | 16 | * |
| 17 | * You should have received a copy of the GNU General Public License | 17 | * You should have received a copy of the GNU General Public License |
| 18 | * along with this program; if not, write to the Free Software | 18 | * along with this program; if not, write to the Free Software |
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 20 | */ | 20 | */ |
| 21 | #include <linux/config.h> | 21 | #include <linux/config.h> |
| 22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
| 23 | #include <linux/device.h> | 23 | #include <linux/device.h> |
| 24 | #include <linux/dma-mapping.h> | 24 | #include <linux/dma-mapping.h> |
| 25 | #include <linux/sysdev.h> | 25 | #include <linux/sysdev.h> |
| 26 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
| 27 | 27 | ||
| 28 | #include <asm/system.h> | 28 | #include <asm/system.h> |
| 29 | #include <asm/hardware.h> | 29 | #include <asm/hardware.h> |
| 30 | #include <asm/io.h> | 30 | #include <asm/io.h> |
| 31 | #include <asm/irq.h> | 31 | #include <asm/irq.h> |
| 32 | #include <asm/leds.h> | 32 | #include <asm/leds.h> |
| 33 | #include <asm/mach-types.h> | 33 | #include <asm/mach-types.h> |
| 34 | #include <asm/hardware/amba.h> | 34 | #include <asm/hardware/amba.h> |
| 35 | #include <asm/hardware/amba_clcd.h> | 35 | #include <asm/hardware/amba_clcd.h> |
| 36 | #include <asm/hardware/arm_timer.h> | 36 | #include <asm/hardware/arm_timer.h> |
| 37 | #include <asm/hardware/icst307.h> | 37 | #include <asm/hardware/icst307.h> |
| 38 | 38 | ||
| 39 | #include <asm/mach/arch.h> | 39 | #include <asm/mach/arch.h> |
| 40 | #include <asm/mach/flash.h> | 40 | #include <asm/mach/flash.h> |
| 41 | #include <asm/mach/irq.h> | 41 | #include <asm/mach/irq.h> |
| 42 | #include <asm/mach/time.h> | 42 | #include <asm/mach/time.h> |
| 43 | #include <asm/mach/map.h> | 43 | #include <asm/mach/map.h> |
| 44 | #include <asm/mach/mmc.h> | 44 | #include <asm/mach/mmc.h> |
| 45 | 45 | ||
| 46 | #include "core.h" | 46 | #include "core.h" |
| 47 | #include "clock.h" | 47 | #include "clock.h" |
| 48 | 48 | ||
| 49 | /* | 49 | /* |
| 50 | * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx | 50 | * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx |
| 51 | * is the (PA >> 12). | 51 | * is the (PA >> 12). |
| 52 | * | 52 | * |
| 53 | * Setup a VA for the Versatile Vectored Interrupt Controller. | 53 | * Setup a VA for the Versatile Vectored Interrupt Controller. |
| 54 | */ | 54 | */ |
| 55 | #define VA_VIC_BASE IO_ADDRESS(VERSATILE_VIC_BASE) | 55 | #define VA_VIC_BASE IO_ADDRESS(VERSATILE_VIC_BASE) |
| 56 | #define VA_SIC_BASE IO_ADDRESS(VERSATILE_SIC_BASE) | 56 | #define VA_SIC_BASE IO_ADDRESS(VERSATILE_SIC_BASE) |
| 57 | 57 | ||
| 58 | static void vic_mask_irq(unsigned int irq) | 58 | static void vic_mask_irq(unsigned int irq) |
| 59 | { | 59 | { |
| 60 | irq -= IRQ_VIC_START; | 60 | irq -= IRQ_VIC_START; |
| 61 | writel(1 << irq, VA_VIC_BASE + VIC_IRQ_ENABLE_CLEAR); | 61 | writel(1 << irq, VA_VIC_BASE + VIC_IRQ_ENABLE_CLEAR); |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | static void vic_unmask_irq(unsigned int irq) | 64 | static void vic_unmask_irq(unsigned int irq) |
| 65 | { | 65 | { |
| 66 | irq -= IRQ_VIC_START; | 66 | irq -= IRQ_VIC_START; |
| 67 | writel(1 << irq, VA_VIC_BASE + VIC_IRQ_ENABLE); | 67 | writel(1 << irq, VA_VIC_BASE + VIC_IRQ_ENABLE); |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | static struct irqchip vic_chip = { | 70 | static struct irqchip vic_chip = { |
| 71 | .ack = vic_mask_irq, | 71 | .ack = vic_mask_irq, |
| 72 | .mask = vic_mask_irq, | 72 | .mask = vic_mask_irq, |
| 73 | .unmask = vic_unmask_irq, | 73 | .unmask = vic_unmask_irq, |
| 74 | }; | 74 | }; |
| 75 | 75 | ||
| 76 | static void sic_mask_irq(unsigned int irq) | 76 | static void sic_mask_irq(unsigned int irq) |
| 77 | { | 77 | { |
| 78 | irq -= IRQ_SIC_START; | 78 | irq -= IRQ_SIC_START; |
| 79 | writel(1 << irq, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR); | 79 | writel(1 << irq, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR); |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | static void sic_unmask_irq(unsigned int irq) | 82 | static void sic_unmask_irq(unsigned int irq) |
| 83 | { | 83 | { |
| 84 | irq -= IRQ_SIC_START; | 84 | irq -= IRQ_SIC_START; |
| 85 | writel(1 << irq, VA_SIC_BASE + SIC_IRQ_ENABLE_SET); | 85 | writel(1 << irq, VA_SIC_BASE + SIC_IRQ_ENABLE_SET); |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | static struct irqchip sic_chip = { | 88 | static struct irqchip sic_chip = { |
| 89 | .ack = sic_mask_irq, | 89 | .ack = sic_mask_irq, |
| 90 | .mask = sic_mask_irq, | 90 | .mask = sic_mask_irq, |
| 91 | .unmask = sic_unmask_irq, | 91 | .unmask = sic_unmask_irq, |
| 92 | }; | 92 | }; |
| 93 | 93 | ||
| 94 | static void | 94 | static void |
| 95 | sic_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) | 95 | sic_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) |
| 96 | { | 96 | { |
| 97 | unsigned long status = readl(VA_SIC_BASE + SIC_IRQ_STATUS); | 97 | unsigned long status = readl(VA_SIC_BASE + SIC_IRQ_STATUS); |
| 98 | 98 | ||
| 99 | if (status == 0) { | 99 | if (status == 0) { |
| 100 | do_bad_IRQ(irq, desc, regs); | 100 | do_bad_IRQ(irq, desc, regs); |
| 101 | return; | 101 | return; |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | do { | 104 | do { |
| 105 | irq = ffs(status) - 1; | 105 | irq = ffs(status) - 1; |
| 106 | status &= ~(1 << irq); | 106 | status &= ~(1 << irq); |
| 107 | 107 | ||
| 108 | irq += IRQ_SIC_START; | 108 | irq += IRQ_SIC_START; |
| 109 | 109 | ||
| 110 | desc = irq_desc + irq; | 110 | desc = irq_desc + irq; |
| 111 | desc->handle(irq, desc, regs); | 111 | desc_handle_irq(irq, desc, regs); |
| 112 | } while (status); | 112 | } while (status); |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | #if 1 | 115 | #if 1 |
| 116 | #define IRQ_MMCI0A IRQ_VICSOURCE22 | 116 | #define IRQ_MMCI0A IRQ_VICSOURCE22 |
| 117 | #define IRQ_AACI IRQ_VICSOURCE24 | 117 | #define IRQ_AACI IRQ_VICSOURCE24 |
| 118 | #define IRQ_ETH IRQ_VICSOURCE25 | 118 | #define IRQ_ETH IRQ_VICSOURCE25 |
| 119 | #define PIC_MASK 0xFFD00000 | 119 | #define PIC_MASK 0xFFD00000 |
| 120 | #else | 120 | #else |
| 121 | #define IRQ_MMCI0A IRQ_SIC_MMCI0A | 121 | #define IRQ_MMCI0A IRQ_SIC_MMCI0A |
| 122 | #define IRQ_AACI IRQ_SIC_AACI | 122 | #define IRQ_AACI IRQ_SIC_AACI |
| 123 | #define IRQ_ETH IRQ_SIC_ETH | 123 | #define IRQ_ETH IRQ_SIC_ETH |
| 124 | #define PIC_MASK 0 | 124 | #define PIC_MASK 0 |
| 125 | #endif | 125 | #endif |
| 126 | 126 | ||
| 127 | void __init versatile_init_irq(void) | 127 | void __init versatile_init_irq(void) |
| 128 | { | 128 | { |
| 129 | unsigned int i, value; | 129 | unsigned int i, value; |
| 130 | 130 | ||
| 131 | /* Disable all interrupts initially. */ | 131 | /* Disable all interrupts initially. */ |
| 132 | 132 | ||
| 133 | writel(0, VA_VIC_BASE + VIC_INT_SELECT); | 133 | writel(0, VA_VIC_BASE + VIC_INT_SELECT); |
| 134 | writel(0, VA_VIC_BASE + VIC_IRQ_ENABLE); | 134 | writel(0, VA_VIC_BASE + VIC_IRQ_ENABLE); |
| 135 | writel(~0, VA_VIC_BASE + VIC_IRQ_ENABLE_CLEAR); | 135 | writel(~0, VA_VIC_BASE + VIC_IRQ_ENABLE_CLEAR); |
| 136 | writel(0, VA_VIC_BASE + VIC_IRQ_STATUS); | 136 | writel(0, VA_VIC_BASE + VIC_IRQ_STATUS); |
| 137 | writel(0, VA_VIC_BASE + VIC_ITCR); | 137 | writel(0, VA_VIC_BASE + VIC_ITCR); |
| 138 | writel(~0, VA_VIC_BASE + VIC_IRQ_SOFT_CLEAR); | 138 | writel(~0, VA_VIC_BASE + VIC_IRQ_SOFT_CLEAR); |
| 139 | 139 | ||
| 140 | /* | 140 | /* |
| 141 | * Make sure we clear all existing interrupts | 141 | * Make sure we clear all existing interrupts |
| 142 | */ | 142 | */ |
| 143 | writel(0, VA_VIC_BASE + VIC_VECT_ADDR); | 143 | writel(0, VA_VIC_BASE + VIC_VECT_ADDR); |
| 144 | for (i = 0; i < 19; i++) { | 144 | for (i = 0; i < 19; i++) { |
| 145 | value = readl(VA_VIC_BASE + VIC_VECT_ADDR); | 145 | value = readl(VA_VIC_BASE + VIC_VECT_ADDR); |
| 146 | writel(value, VA_VIC_BASE + VIC_VECT_ADDR); | 146 | writel(value, VA_VIC_BASE + VIC_VECT_ADDR); |
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | for (i = 0; i < 16; i++) { | 149 | for (i = 0; i < 16; i++) { |
| 150 | value = readl(VA_VIC_BASE + VIC_VECT_CNTL0 + (i * 4)); | 150 | value = readl(VA_VIC_BASE + VIC_VECT_CNTL0 + (i * 4)); |
| 151 | writel(value | VICVectCntl_Enable | i, VA_VIC_BASE + VIC_VECT_CNTL0 + (i * 4)); | 151 | writel(value | VICVectCntl_Enable | i, VA_VIC_BASE + VIC_VECT_CNTL0 + (i * 4)); |
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | writel(32, VA_VIC_BASE + VIC_DEF_VECT_ADDR); | 154 | writel(32, VA_VIC_BASE + VIC_DEF_VECT_ADDR); |
| 155 | 155 | ||
| 156 | for (i = IRQ_VIC_START; i <= IRQ_VIC_END; i++) { | 156 | for (i = IRQ_VIC_START; i <= IRQ_VIC_END; i++) { |
| 157 | if (i != IRQ_VICSOURCE31) { | 157 | if (i != IRQ_VICSOURCE31) { |
| 158 | set_irq_chip(i, &vic_chip); | 158 | set_irq_chip(i, &vic_chip); |
| 159 | set_irq_handler(i, do_level_IRQ); | 159 | set_irq_handler(i, do_level_IRQ); |
| 160 | set_irq_flags(i, IRQF_VALID | IRQF_PROBE); | 160 | set_irq_flags(i, IRQF_VALID | IRQF_PROBE); |
| 161 | } | 161 | } |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | set_irq_handler(IRQ_VICSOURCE31, sic_handle_irq); | 164 | set_irq_handler(IRQ_VICSOURCE31, sic_handle_irq); |
| 165 | vic_unmask_irq(IRQ_VICSOURCE31); | 165 | vic_unmask_irq(IRQ_VICSOURCE31); |
| 166 | 166 | ||
| 167 | /* Do second interrupt controller */ | 167 | /* Do second interrupt controller */ |
| 168 | writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR); | 168 | writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR); |
| 169 | 169 | ||
| 170 | for (i = IRQ_SIC_START; i <= IRQ_SIC_END; i++) { | 170 | for (i = IRQ_SIC_START; i <= IRQ_SIC_END; i++) { |
| 171 | if ((PIC_MASK & (1 << (i - IRQ_SIC_START))) == 0) { | 171 | if ((PIC_MASK & (1 << (i - IRQ_SIC_START))) == 0) { |
| 172 | set_irq_chip(i, &sic_chip); | 172 | set_irq_chip(i, &sic_chip); |
| 173 | set_irq_handler(i, do_level_IRQ); | 173 | set_irq_handler(i, do_level_IRQ); |
| 174 | set_irq_flags(i, IRQF_VALID | IRQF_PROBE); | 174 | set_irq_flags(i, IRQF_VALID | IRQF_PROBE); |
| 175 | } | 175 | } |
| 176 | } | 176 | } |
| 177 | 177 | ||
| 178 | /* | 178 | /* |
| 179 | * Interrupts on secondary controller from 0 to 8 are routed to | 179 | * Interrupts on secondary controller from 0 to 8 are routed to |
| 180 | * source 31 on PIC. | 180 | * source 31 on PIC. |
| 181 | * Interrupts from 21 to 31 are routed directly to the VIC on | 181 | * Interrupts from 21 to 31 are routed directly to the VIC on |
| 182 | * the corresponding number on primary controller. This is controlled | 182 | * the corresponding number on primary controller. This is controlled |
| 183 | * by setting PIC_ENABLEx. | 183 | * by setting PIC_ENABLEx. |
| 184 | */ | 184 | */ |
| 185 | writel(PIC_MASK, VA_SIC_BASE + SIC_INT_PIC_ENABLE); | 185 | writel(PIC_MASK, VA_SIC_BASE + SIC_INT_PIC_ENABLE); |
| 186 | } | 186 | } |
| 187 | 187 | ||
| 188 | static struct map_desc versatile_io_desc[] __initdata = { | 188 | static struct map_desc versatile_io_desc[] __initdata = { |
| 189 | { IO_ADDRESS(VERSATILE_SYS_BASE), VERSATILE_SYS_BASE, SZ_4K, MT_DEVICE }, | 189 | { IO_ADDRESS(VERSATILE_SYS_BASE), VERSATILE_SYS_BASE, SZ_4K, MT_DEVICE }, |
| 190 | { IO_ADDRESS(VERSATILE_SIC_BASE), VERSATILE_SIC_BASE, SZ_4K, MT_DEVICE }, | 190 | { IO_ADDRESS(VERSATILE_SIC_BASE), VERSATILE_SIC_BASE, SZ_4K, MT_DEVICE }, |
| 191 | { IO_ADDRESS(VERSATILE_VIC_BASE), VERSATILE_VIC_BASE, SZ_4K, MT_DEVICE }, | 191 | { IO_ADDRESS(VERSATILE_VIC_BASE), VERSATILE_VIC_BASE, SZ_4K, MT_DEVICE }, |
| 192 | { IO_ADDRESS(VERSATILE_SCTL_BASE), VERSATILE_SCTL_BASE, SZ_4K * 9, MT_DEVICE }, | 192 | { IO_ADDRESS(VERSATILE_SCTL_BASE), VERSATILE_SCTL_BASE, SZ_4K * 9, MT_DEVICE }, |
| 193 | #ifdef CONFIG_MACH_VERSATILE_AB | 193 | #ifdef CONFIG_MACH_VERSATILE_AB |
| 194 | { IO_ADDRESS(VERSATILE_GPIO0_BASE), VERSATILE_GPIO0_BASE, SZ_4K, MT_DEVICE }, | 194 | { IO_ADDRESS(VERSATILE_GPIO0_BASE), VERSATILE_GPIO0_BASE, SZ_4K, MT_DEVICE }, |
| 195 | { IO_ADDRESS(VERSATILE_IB2_BASE), VERSATILE_IB2_BASE, SZ_64M, MT_DEVICE }, | 195 | { IO_ADDRESS(VERSATILE_IB2_BASE), VERSATILE_IB2_BASE, SZ_64M, MT_DEVICE }, |
| 196 | #endif | 196 | #endif |
| 197 | #ifdef CONFIG_DEBUG_LL | 197 | #ifdef CONFIG_DEBUG_LL |
| 198 | { IO_ADDRESS(VERSATILE_UART0_BASE), VERSATILE_UART0_BASE, SZ_4K, MT_DEVICE }, | 198 | { IO_ADDRESS(VERSATILE_UART0_BASE), VERSATILE_UART0_BASE, SZ_4K, MT_DEVICE }, |
| 199 | #endif | 199 | #endif |
| 200 | #ifdef CONFIG_PCI | 200 | #ifdef CONFIG_PCI |
| 201 | { IO_ADDRESS(VERSATILE_PCI_CORE_BASE), VERSATILE_PCI_CORE_BASE, SZ_4K, MT_DEVICE }, | 201 | { IO_ADDRESS(VERSATILE_PCI_CORE_BASE), VERSATILE_PCI_CORE_BASE, SZ_4K, MT_DEVICE }, |
| 202 | { VERSATILE_PCI_VIRT_BASE, VERSATILE_PCI_BASE, VERSATILE_PCI_BASE_SIZE, MT_DEVICE }, | 202 | { VERSATILE_PCI_VIRT_BASE, VERSATILE_PCI_BASE, VERSATILE_PCI_BASE_SIZE, MT_DEVICE }, |
| 203 | { VERSATILE_PCI_CFG_VIRT_BASE, VERSATILE_PCI_CFG_BASE, VERSATILE_PCI_CFG_BASE_SIZE, MT_DEVICE }, | 203 | { VERSATILE_PCI_CFG_VIRT_BASE, VERSATILE_PCI_CFG_BASE, VERSATILE_PCI_CFG_BASE_SIZE, MT_DEVICE }, |
| 204 | #if 0 | 204 | #if 0 |
| 205 | { VERSATILE_PCI_VIRT_MEM_BASE0, VERSATILE_PCI_MEM_BASE0, SZ_16M, MT_DEVICE }, | 205 | { VERSATILE_PCI_VIRT_MEM_BASE0, VERSATILE_PCI_MEM_BASE0, SZ_16M, MT_DEVICE }, |
| 206 | { VERSATILE_PCI_VIRT_MEM_BASE1, VERSATILE_PCI_MEM_BASE1, SZ_16M, MT_DEVICE }, | 206 | { VERSATILE_PCI_VIRT_MEM_BASE1, VERSATILE_PCI_MEM_BASE1, SZ_16M, MT_DEVICE }, |
| 207 | { VERSATILE_PCI_VIRT_MEM_BASE2, VERSATILE_PCI_MEM_BASE2, SZ_16M, MT_DEVICE }, | 207 | { VERSATILE_PCI_VIRT_MEM_BASE2, VERSATILE_PCI_MEM_BASE2, SZ_16M, MT_DEVICE }, |
| 208 | #endif | 208 | #endif |
| 209 | #endif | 209 | #endif |
| 210 | }; | 210 | }; |
| 211 | 211 | ||
| 212 | void __init versatile_map_io(void) | 212 | void __init versatile_map_io(void) |
| 213 | { | 213 | { |
| 214 | iotable_init(versatile_io_desc, ARRAY_SIZE(versatile_io_desc)); | 214 | iotable_init(versatile_io_desc, ARRAY_SIZE(versatile_io_desc)); |
| 215 | } | 215 | } |
| 216 | 216 | ||
| 217 | #define VERSATILE_REFCOUNTER (IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_24MHz_OFFSET) | 217 | #define VERSATILE_REFCOUNTER (IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_24MHz_OFFSET) |
| 218 | 218 | ||
| 219 | /* | 219 | /* |
| 220 | * This is the Versatile sched_clock implementation. This has | 220 | * This is the Versatile sched_clock implementation. This has |
| 221 | * a resolution of 41.7ns, and a maximum value of about 179s. | 221 | * a resolution of 41.7ns, and a maximum value of about 179s. |
| 222 | */ | 222 | */ |
| 223 | unsigned long long sched_clock(void) | 223 | unsigned long long sched_clock(void) |
| 224 | { | 224 | { |
| 225 | unsigned long long v; | 225 | unsigned long long v; |
| 226 | 226 | ||
| 227 | v = (unsigned long long)readl(VERSATILE_REFCOUNTER) * 125; | 227 | v = (unsigned long long)readl(VERSATILE_REFCOUNTER) * 125; |
| 228 | do_div(v, 3); | 228 | do_div(v, 3); |
| 229 | 229 | ||
| 230 | return v; | 230 | return v; |
| 231 | } | 231 | } |
| 232 | 232 | ||
| 233 | 233 | ||
| 234 | #define VERSATILE_FLASHCTRL (IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_FLASH_OFFSET) | 234 | #define VERSATILE_FLASHCTRL (IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_FLASH_OFFSET) |
| 235 | 235 | ||
| 236 | static int versatile_flash_init(void) | 236 | static int versatile_flash_init(void) |
| 237 | { | 237 | { |
| 238 | u32 val; | 238 | u32 val; |
| 239 | 239 | ||
| 240 | val = __raw_readl(VERSATILE_FLASHCTRL); | 240 | val = __raw_readl(VERSATILE_FLASHCTRL); |
| 241 | val &= ~VERSATILE_FLASHPROG_FLVPPEN; | 241 | val &= ~VERSATILE_FLASHPROG_FLVPPEN; |
| 242 | __raw_writel(val, VERSATILE_FLASHCTRL); | 242 | __raw_writel(val, VERSATILE_FLASHCTRL); |
| 243 | 243 | ||
| 244 | return 0; | 244 | return 0; |
| 245 | } | 245 | } |
| 246 | 246 | ||
| 247 | static void versatile_flash_exit(void) | 247 | static void versatile_flash_exit(void) |
| 248 | { | 248 | { |
| 249 | u32 val; | 249 | u32 val; |
| 250 | 250 | ||
| 251 | val = __raw_readl(VERSATILE_FLASHCTRL); | 251 | val = __raw_readl(VERSATILE_FLASHCTRL); |
| 252 | val &= ~VERSATILE_FLASHPROG_FLVPPEN; | 252 | val &= ~VERSATILE_FLASHPROG_FLVPPEN; |
| 253 | __raw_writel(val, VERSATILE_FLASHCTRL); | 253 | __raw_writel(val, VERSATILE_FLASHCTRL); |
| 254 | } | 254 | } |
| 255 | 255 | ||
| 256 | static void versatile_flash_set_vpp(int on) | 256 | static void versatile_flash_set_vpp(int on) |
| 257 | { | 257 | { |
| 258 | u32 val; | 258 | u32 val; |
| 259 | 259 | ||
| 260 | val = __raw_readl(VERSATILE_FLASHCTRL); | 260 | val = __raw_readl(VERSATILE_FLASHCTRL); |
| 261 | if (on) | 261 | if (on) |
| 262 | val |= VERSATILE_FLASHPROG_FLVPPEN; | 262 | val |= VERSATILE_FLASHPROG_FLVPPEN; |
| 263 | else | 263 | else |
| 264 | val &= ~VERSATILE_FLASHPROG_FLVPPEN; | 264 | val &= ~VERSATILE_FLASHPROG_FLVPPEN; |
| 265 | __raw_writel(val, VERSATILE_FLASHCTRL); | 265 | __raw_writel(val, VERSATILE_FLASHCTRL); |
| 266 | } | 266 | } |
| 267 | 267 | ||
| 268 | static struct flash_platform_data versatile_flash_data = { | 268 | static struct flash_platform_data versatile_flash_data = { |
| 269 | .map_name = "cfi_probe", | 269 | .map_name = "cfi_probe", |
| 270 | .width = 4, | 270 | .width = 4, |
| 271 | .init = versatile_flash_init, | 271 | .init = versatile_flash_init, |
| 272 | .exit = versatile_flash_exit, | 272 | .exit = versatile_flash_exit, |
| 273 | .set_vpp = versatile_flash_set_vpp, | 273 | .set_vpp = versatile_flash_set_vpp, |
| 274 | }; | 274 | }; |
| 275 | 275 | ||
| 276 | static struct resource versatile_flash_resource = { | 276 | static struct resource versatile_flash_resource = { |
| 277 | .start = VERSATILE_FLASH_BASE, | 277 | .start = VERSATILE_FLASH_BASE, |
| 278 | .end = VERSATILE_FLASH_BASE + VERSATILE_FLASH_SIZE, | 278 | .end = VERSATILE_FLASH_BASE + VERSATILE_FLASH_SIZE, |
| 279 | .flags = IORESOURCE_MEM, | 279 | .flags = IORESOURCE_MEM, |
| 280 | }; | 280 | }; |
| 281 | 281 | ||
| 282 | static struct platform_device versatile_flash_device = { | 282 | static struct platform_device versatile_flash_device = { |
| 283 | .name = "armflash", | 283 | .name = "armflash", |
| 284 | .id = 0, | 284 | .id = 0, |
| 285 | .dev = { | 285 | .dev = { |
| 286 | .platform_data = &versatile_flash_data, | 286 | .platform_data = &versatile_flash_data, |
| 287 | }, | 287 | }, |
| 288 | .num_resources = 1, | 288 | .num_resources = 1, |
| 289 | .resource = &versatile_flash_resource, | 289 | .resource = &versatile_flash_resource, |
| 290 | }; | 290 | }; |
| 291 | 291 | ||
| 292 | static struct resource smc91x_resources[] = { | 292 | static struct resource smc91x_resources[] = { |
| 293 | [0] = { | 293 | [0] = { |
| 294 | .start = VERSATILE_ETH_BASE, | 294 | .start = VERSATILE_ETH_BASE, |
| 295 | .end = VERSATILE_ETH_BASE + SZ_64K - 1, | 295 | .end = VERSATILE_ETH_BASE + SZ_64K - 1, |
| 296 | .flags = IORESOURCE_MEM, | 296 | .flags = IORESOURCE_MEM, |
| 297 | }, | 297 | }, |
| 298 | [1] = { | 298 | [1] = { |
| 299 | .start = IRQ_ETH, | 299 | .start = IRQ_ETH, |
| 300 | .end = IRQ_ETH, | 300 | .end = IRQ_ETH, |
| 301 | .flags = IORESOURCE_IRQ, | 301 | .flags = IORESOURCE_IRQ, |
| 302 | }, | 302 | }, |
| 303 | }; | 303 | }; |
| 304 | 304 | ||
| 305 | static struct platform_device smc91x_device = { | 305 | static struct platform_device smc91x_device = { |
| 306 | .name = "smc91x", | 306 | .name = "smc91x", |
| 307 | .id = 0, | 307 | .id = 0, |
| 308 | .num_resources = ARRAY_SIZE(smc91x_resources), | 308 | .num_resources = ARRAY_SIZE(smc91x_resources), |
| 309 | .resource = smc91x_resources, | 309 | .resource = smc91x_resources, |
| 310 | }; | 310 | }; |
| 311 | 311 | ||
| 312 | #define VERSATILE_SYSMCI (IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_MCI_OFFSET) | 312 | #define VERSATILE_SYSMCI (IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_MCI_OFFSET) |
| 313 | 313 | ||
| 314 | unsigned int mmc_status(struct device *dev) | 314 | unsigned int mmc_status(struct device *dev) |
| 315 | { | 315 | { |
| 316 | struct amba_device *adev = container_of(dev, struct amba_device, dev); | 316 | struct amba_device *adev = container_of(dev, struct amba_device, dev); |
| 317 | u32 mask; | 317 | u32 mask; |
| 318 | 318 | ||
| 319 | if (adev->res.start == VERSATILE_MMCI0_BASE) | 319 | if (adev->res.start == VERSATILE_MMCI0_BASE) |
| 320 | mask = 1; | 320 | mask = 1; |
| 321 | else | 321 | else |
| 322 | mask = 2; | 322 | mask = 2; |
| 323 | 323 | ||
| 324 | return readl(VERSATILE_SYSMCI) & mask; | 324 | return readl(VERSATILE_SYSMCI) & mask; |
| 325 | } | 325 | } |
| 326 | 326 | ||
| 327 | static struct mmc_platform_data mmc0_plat_data = { | 327 | static struct mmc_platform_data mmc0_plat_data = { |
| 328 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, | 328 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, |
| 329 | .status = mmc_status, | 329 | .status = mmc_status, |
| 330 | }; | 330 | }; |
| 331 | 331 | ||
| 332 | /* | 332 | /* |
| 333 | * Clock handling | 333 | * Clock handling |
| 334 | */ | 334 | */ |
| 335 | static const struct icst307_params versatile_oscvco_params = { | 335 | static const struct icst307_params versatile_oscvco_params = { |
| 336 | .ref = 24000, | 336 | .ref = 24000, |
| 337 | .vco_max = 200000, | 337 | .vco_max = 200000, |
| 338 | .vd_min = 4 + 8, | 338 | .vd_min = 4 + 8, |
| 339 | .vd_max = 511 + 8, | 339 | .vd_max = 511 + 8, |
| 340 | .rd_min = 1 + 2, | 340 | .rd_min = 1 + 2, |
| 341 | .rd_max = 127 + 2, | 341 | .rd_max = 127 + 2, |
| 342 | }; | 342 | }; |
| 343 | 343 | ||
| 344 | static void versatile_oscvco_set(struct clk *clk, struct icst307_vco vco) | 344 | static void versatile_oscvco_set(struct clk *clk, struct icst307_vco vco) |
| 345 | { | 345 | { |
| 346 | unsigned long sys_lock = IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_LOCK_OFFSET; | 346 | unsigned long sys_lock = IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_LOCK_OFFSET; |
| 347 | #if defined(CONFIG_ARCH_VERSATILE_PB) | 347 | #if defined(CONFIG_ARCH_VERSATILE_PB) |
| 348 | unsigned long sys_osc = IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_OSC4_OFFSET; | 348 | unsigned long sys_osc = IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_OSC4_OFFSET; |
| 349 | #elif defined(CONFIG_MACH_VERSATILE_AB) | 349 | #elif defined(CONFIG_MACH_VERSATILE_AB) |
| 350 | unsigned long sys_osc = IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_OSC1_OFFSET; | 350 | unsigned long sys_osc = IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_OSC1_OFFSET; |
| 351 | #endif | 351 | #endif |
| 352 | u32 val; | 352 | u32 val; |
| 353 | 353 | ||
| 354 | val = readl(sys_osc) & ~0x7ffff; | 354 | val = readl(sys_osc) & ~0x7ffff; |
| 355 | val |= vco.v | (vco.r << 9) | (vco.s << 16); | 355 | val |= vco.v | (vco.r << 9) | (vco.s << 16); |
| 356 | 356 | ||
| 357 | writel(0xa05f, sys_lock); | 357 | writel(0xa05f, sys_lock); |
| 358 | writel(val, sys_osc); | 358 | writel(val, sys_osc); |
| 359 | writel(0, sys_lock); | 359 | writel(0, sys_lock); |
| 360 | } | 360 | } |
| 361 | 361 | ||
| 362 | static struct clk versatile_clcd_clk = { | 362 | static struct clk versatile_clcd_clk = { |
| 363 | .name = "CLCDCLK", | 363 | .name = "CLCDCLK", |
| 364 | .params = &versatile_oscvco_params, | 364 | .params = &versatile_oscvco_params, |
| 365 | .setvco = versatile_oscvco_set, | 365 | .setvco = versatile_oscvco_set, |
| 366 | }; | 366 | }; |
| 367 | 367 | ||
| 368 | /* | 368 | /* |
| 369 | * CLCD support. | 369 | * CLCD support. |
| 370 | */ | 370 | */ |
| 371 | #define SYS_CLCD_MODE_MASK (3 << 0) | 371 | #define SYS_CLCD_MODE_MASK (3 << 0) |
| 372 | #define SYS_CLCD_MODE_888 (0 << 0) | 372 | #define SYS_CLCD_MODE_888 (0 << 0) |
| 373 | #define SYS_CLCD_MODE_5551 (1 << 0) | 373 | #define SYS_CLCD_MODE_5551 (1 << 0) |
| 374 | #define SYS_CLCD_MODE_565_RLSB (2 << 0) | 374 | #define SYS_CLCD_MODE_565_RLSB (2 << 0) |
| 375 | #define SYS_CLCD_MODE_565_BLSB (3 << 0) | 375 | #define SYS_CLCD_MODE_565_BLSB (3 << 0) |
| 376 | #define SYS_CLCD_NLCDIOON (1 << 2) | 376 | #define SYS_CLCD_NLCDIOON (1 << 2) |
| 377 | #define SYS_CLCD_VDDPOSSWITCH (1 << 3) | 377 | #define SYS_CLCD_VDDPOSSWITCH (1 << 3) |
| 378 | #define SYS_CLCD_PWR3V5SWITCH (1 << 4) | 378 | #define SYS_CLCD_PWR3V5SWITCH (1 << 4) |
| 379 | #define SYS_CLCD_ID_MASK (0x1f << 8) | 379 | #define SYS_CLCD_ID_MASK (0x1f << 8) |
| 380 | #define SYS_CLCD_ID_SANYO_3_8 (0x00 << 8) | 380 | #define SYS_CLCD_ID_SANYO_3_8 (0x00 << 8) |
| 381 | #define SYS_CLCD_ID_UNKNOWN_8_4 (0x01 << 8) | 381 | #define SYS_CLCD_ID_UNKNOWN_8_4 (0x01 << 8) |
| 382 | #define SYS_CLCD_ID_EPSON_2_2 (0x02 << 8) | 382 | #define SYS_CLCD_ID_EPSON_2_2 (0x02 << 8) |
| 383 | #define SYS_CLCD_ID_SANYO_2_5 (0x07 << 8) | 383 | #define SYS_CLCD_ID_SANYO_2_5 (0x07 << 8) |
| 384 | #define SYS_CLCD_ID_VGA (0x1f << 8) | 384 | #define SYS_CLCD_ID_VGA (0x1f << 8) |
| 385 | 385 | ||
| 386 | static struct clcd_panel vga = { | 386 | static struct clcd_panel vga = { |
| 387 | .mode = { | 387 | .mode = { |
| 388 | .name = "VGA", | 388 | .name = "VGA", |
| 389 | .refresh = 60, | 389 | .refresh = 60, |
| 390 | .xres = 640, | 390 | .xres = 640, |
| 391 | .yres = 480, | 391 | .yres = 480, |
| 392 | .pixclock = 39721, | 392 | .pixclock = 39721, |
| 393 | .left_margin = 40, | 393 | .left_margin = 40, |
| 394 | .right_margin = 24, | 394 | .right_margin = 24, |
| 395 | .upper_margin = 32, | 395 | .upper_margin = 32, |
| 396 | .lower_margin = 11, | 396 | .lower_margin = 11, |
| 397 | .hsync_len = 96, | 397 | .hsync_len = 96, |
| 398 | .vsync_len = 2, | 398 | .vsync_len = 2, |
| 399 | .sync = 0, | 399 | .sync = 0, |
| 400 | .vmode = FB_VMODE_NONINTERLACED, | 400 | .vmode = FB_VMODE_NONINTERLACED, |
| 401 | }, | 401 | }, |
| 402 | .width = -1, | 402 | .width = -1, |
| 403 | .height = -1, | 403 | .height = -1, |
| 404 | .tim2 = TIM2_BCD | TIM2_IPC, | 404 | .tim2 = TIM2_BCD | TIM2_IPC, |
| 405 | .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), | 405 | .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), |
| 406 | .bpp = 16, | 406 | .bpp = 16, |
| 407 | }; | 407 | }; |
| 408 | 408 | ||
| 409 | static struct clcd_panel sanyo_3_8_in = { | 409 | static struct clcd_panel sanyo_3_8_in = { |
| 410 | .mode = { | 410 | .mode = { |
| 411 | .name = "Sanyo QVGA", | 411 | .name = "Sanyo QVGA", |
| 412 | .refresh = 116, | 412 | .refresh = 116, |
| 413 | .xres = 320, | 413 | .xres = 320, |
| 414 | .yres = 240, | 414 | .yres = 240, |
| 415 | .pixclock = 100000, | 415 | .pixclock = 100000, |
| 416 | .left_margin = 6, | 416 | .left_margin = 6, |
| 417 | .right_margin = 6, | 417 | .right_margin = 6, |
| 418 | .upper_margin = 5, | 418 | .upper_margin = 5, |
| 419 | .lower_margin = 5, | 419 | .lower_margin = 5, |
| 420 | .hsync_len = 6, | 420 | .hsync_len = 6, |
| 421 | .vsync_len = 6, | 421 | .vsync_len = 6, |
| 422 | .sync = 0, | 422 | .sync = 0, |
| 423 | .vmode = FB_VMODE_NONINTERLACED, | 423 | .vmode = FB_VMODE_NONINTERLACED, |
| 424 | }, | 424 | }, |
| 425 | .width = -1, | 425 | .width = -1, |
| 426 | .height = -1, | 426 | .height = -1, |
| 427 | .tim2 = TIM2_BCD, | 427 | .tim2 = TIM2_BCD, |
| 428 | .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), | 428 | .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), |
| 429 | .bpp = 16, | 429 | .bpp = 16, |
| 430 | }; | 430 | }; |
| 431 | 431 | ||
| 432 | static struct clcd_panel sanyo_2_5_in = { | 432 | static struct clcd_panel sanyo_2_5_in = { |
| 433 | .mode = { | 433 | .mode = { |
| 434 | .name = "Sanyo QVGA Portrait", | 434 | .name = "Sanyo QVGA Portrait", |
| 435 | .refresh = 116, | 435 | .refresh = 116, |
| 436 | .xres = 240, | 436 | .xres = 240, |
| 437 | .yres = 320, | 437 | .yres = 320, |
| 438 | .pixclock = 100000, | 438 | .pixclock = 100000, |
| 439 | .left_margin = 20, | 439 | .left_margin = 20, |
| 440 | .right_margin = 10, | 440 | .right_margin = 10, |
| 441 | .upper_margin = 2, | 441 | .upper_margin = 2, |
| 442 | .lower_margin = 2, | 442 | .lower_margin = 2, |
| 443 | .hsync_len = 10, | 443 | .hsync_len = 10, |
| 444 | .vsync_len = 2, | 444 | .vsync_len = 2, |
| 445 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | 445 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, |
| 446 | .vmode = FB_VMODE_NONINTERLACED, | 446 | .vmode = FB_VMODE_NONINTERLACED, |
| 447 | }, | 447 | }, |
| 448 | .width = -1, | 448 | .width = -1, |
| 449 | .height = -1, | 449 | .height = -1, |
| 450 | .tim2 = TIM2_IVS | TIM2_IHS | TIM2_IPC, | 450 | .tim2 = TIM2_IVS | TIM2_IHS | TIM2_IPC, |
| 451 | .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), | 451 | .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), |
| 452 | .bpp = 16, | 452 | .bpp = 16, |
| 453 | }; | 453 | }; |
| 454 | 454 | ||
| 455 | static struct clcd_panel epson_2_2_in = { | 455 | static struct clcd_panel epson_2_2_in = { |
| 456 | .mode = { | 456 | .mode = { |
| 457 | .name = "Epson QCIF", | 457 | .name = "Epson QCIF", |
| 458 | .refresh = 390, | 458 | .refresh = 390, |
| 459 | .xres = 176, | 459 | .xres = 176, |
| 460 | .yres = 220, | 460 | .yres = 220, |
| 461 | .pixclock = 62500, | 461 | .pixclock = 62500, |
| 462 | .left_margin = 3, | 462 | .left_margin = 3, |
| 463 | .right_margin = 2, | 463 | .right_margin = 2, |
| 464 | .upper_margin = 1, | 464 | .upper_margin = 1, |
| 465 | .lower_margin = 0, | 465 | .lower_margin = 0, |
| 466 | .hsync_len = 3, | 466 | .hsync_len = 3, |
| 467 | .vsync_len = 2, | 467 | .vsync_len = 2, |
| 468 | .sync = 0, | 468 | .sync = 0, |
| 469 | .vmode = FB_VMODE_NONINTERLACED, | 469 | .vmode = FB_VMODE_NONINTERLACED, |
| 470 | }, | 470 | }, |
| 471 | .width = -1, | 471 | .width = -1, |
| 472 | .height = -1, | 472 | .height = -1, |
| 473 | .tim2 = TIM2_BCD | TIM2_IPC, | 473 | .tim2 = TIM2_BCD | TIM2_IPC, |
| 474 | .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), | 474 | .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), |
| 475 | .bpp = 16, | 475 | .bpp = 16, |
| 476 | }; | 476 | }; |
| 477 | 477 | ||
| 478 | /* | 478 | /* |
| 479 | * Detect which LCD panel is connected, and return the appropriate | 479 | * Detect which LCD panel is connected, and return the appropriate |
| 480 | * clcd_panel structure. Note: we do not have any information on | 480 | * clcd_panel structure. Note: we do not have any information on |
| 481 | * the required timings for the 8.4in panel, so we presently assume | 481 | * the required timings for the 8.4in panel, so we presently assume |
| 482 | * VGA timings. | 482 | * VGA timings. |
| 483 | */ | 483 | */ |
| 484 | static struct clcd_panel *versatile_clcd_panel(void) | 484 | static struct clcd_panel *versatile_clcd_panel(void) |
| 485 | { | 485 | { |
| 486 | unsigned long sys_clcd = IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET; | 486 | unsigned long sys_clcd = IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET; |
| 487 | struct clcd_panel *panel = &vga; | 487 | struct clcd_panel *panel = &vga; |
| 488 | u32 val; | 488 | u32 val; |
| 489 | 489 | ||
| 490 | val = readl(sys_clcd) & SYS_CLCD_ID_MASK; | 490 | val = readl(sys_clcd) & SYS_CLCD_ID_MASK; |
| 491 | if (val == SYS_CLCD_ID_SANYO_3_8) | 491 | if (val == SYS_CLCD_ID_SANYO_3_8) |
| 492 | panel = &sanyo_3_8_in; | 492 | panel = &sanyo_3_8_in; |
| 493 | else if (val == SYS_CLCD_ID_SANYO_2_5) | 493 | else if (val == SYS_CLCD_ID_SANYO_2_5) |
| 494 | panel = &sanyo_2_5_in; | 494 | panel = &sanyo_2_5_in; |
| 495 | else if (val == SYS_CLCD_ID_EPSON_2_2) | 495 | else if (val == SYS_CLCD_ID_EPSON_2_2) |
| 496 | panel = &epson_2_2_in; | 496 | panel = &epson_2_2_in; |
| 497 | else if (val == SYS_CLCD_ID_VGA) | 497 | else if (val == SYS_CLCD_ID_VGA) |
| 498 | panel = &vga; | 498 | panel = &vga; |
| 499 | else { | 499 | else { |
| 500 | printk(KERN_ERR "CLCD: unknown LCD panel ID 0x%08x, using VGA\n", | 500 | printk(KERN_ERR "CLCD: unknown LCD panel ID 0x%08x, using VGA\n", |
| 501 | val); | 501 | val); |
| 502 | panel = &vga; | 502 | panel = &vga; |
| 503 | } | 503 | } |
| 504 | 504 | ||
| 505 | return panel; | 505 | return panel; |
| 506 | } | 506 | } |
| 507 | 507 | ||
| 508 | /* | 508 | /* |
| 509 | * Disable all display connectors on the interface module. | 509 | * Disable all display connectors on the interface module. |
| 510 | */ | 510 | */ |
| 511 | static void versatile_clcd_disable(struct clcd_fb *fb) | 511 | static void versatile_clcd_disable(struct clcd_fb *fb) |
| 512 | { | 512 | { |
| 513 | unsigned long sys_clcd = IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET; | 513 | unsigned long sys_clcd = IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET; |
| 514 | u32 val; | 514 | u32 val; |
| 515 | 515 | ||
| 516 | val = readl(sys_clcd); | 516 | val = readl(sys_clcd); |
| 517 | val &= ~SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH; | 517 | val &= ~SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH; |
| 518 | writel(val, sys_clcd); | 518 | writel(val, sys_clcd); |
| 519 | 519 | ||
| 520 | #ifdef CONFIG_MACH_VERSATILE_AB | 520 | #ifdef CONFIG_MACH_VERSATILE_AB |
| 521 | /* | 521 | /* |
| 522 | * If the LCD is Sanyo 2x5 in on the IB2 board, turn the back-light off | 522 | * If the LCD is Sanyo 2x5 in on the IB2 board, turn the back-light off |
| 523 | */ | 523 | */ |
| 524 | if (fb->panel == &sanyo_2_5_in) { | 524 | if (fb->panel == &sanyo_2_5_in) { |
| 525 | unsigned long versatile_ib2_ctrl = IO_ADDRESS(VERSATILE_IB2_CTRL); | 525 | unsigned long versatile_ib2_ctrl = IO_ADDRESS(VERSATILE_IB2_CTRL); |
| 526 | unsigned long ctrl; | 526 | unsigned long ctrl; |
| 527 | 527 | ||
| 528 | ctrl = readl(versatile_ib2_ctrl); | 528 | ctrl = readl(versatile_ib2_ctrl); |
| 529 | ctrl &= ~0x01; | 529 | ctrl &= ~0x01; |
| 530 | writel(ctrl, versatile_ib2_ctrl); | 530 | writel(ctrl, versatile_ib2_ctrl); |
| 531 | } | 531 | } |
| 532 | #endif | 532 | #endif |
| 533 | } | 533 | } |
| 534 | 534 | ||
| 535 | /* | 535 | /* |
| 536 | * Enable the relevant connector on the interface module. | 536 | * Enable the relevant connector on the interface module. |
| 537 | */ | 537 | */ |
| 538 | static void versatile_clcd_enable(struct clcd_fb *fb) | 538 | static void versatile_clcd_enable(struct clcd_fb *fb) |
| 539 | { | 539 | { |
| 540 | unsigned long sys_clcd = IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET; | 540 | unsigned long sys_clcd = IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET; |
| 541 | u32 val; | 541 | u32 val; |
| 542 | 542 | ||
| 543 | val = readl(sys_clcd); | 543 | val = readl(sys_clcd); |
| 544 | val &= ~SYS_CLCD_MODE_MASK; | 544 | val &= ~SYS_CLCD_MODE_MASK; |
| 545 | 545 | ||
| 546 | switch (fb->fb.var.green.length) { | 546 | switch (fb->fb.var.green.length) { |
| 547 | case 5: | 547 | case 5: |
| 548 | val |= SYS_CLCD_MODE_5551; | 548 | val |= SYS_CLCD_MODE_5551; |
| 549 | break; | 549 | break; |
| 550 | case 6: | 550 | case 6: |
| 551 | val |= SYS_CLCD_MODE_565_RLSB; | 551 | val |= SYS_CLCD_MODE_565_RLSB; |
| 552 | break; | 552 | break; |
| 553 | case 8: | 553 | case 8: |
| 554 | val |= SYS_CLCD_MODE_888; | 554 | val |= SYS_CLCD_MODE_888; |
| 555 | break; | 555 | break; |
| 556 | } | 556 | } |
| 557 | 557 | ||
| 558 | /* | 558 | /* |
| 559 | * Set the MUX | 559 | * Set the MUX |
| 560 | */ | 560 | */ |
| 561 | writel(val, sys_clcd); | 561 | writel(val, sys_clcd); |
| 562 | 562 | ||
| 563 | /* | 563 | /* |
| 564 | * And now enable the PSUs | 564 | * And now enable the PSUs |
| 565 | */ | 565 | */ |
| 566 | val |= SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH; | 566 | val |= SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH; |
| 567 | writel(val, sys_clcd); | 567 | writel(val, sys_clcd); |
| 568 | 568 | ||
| 569 | #ifdef CONFIG_MACH_VERSATILE_AB | 569 | #ifdef CONFIG_MACH_VERSATILE_AB |
| 570 | /* | 570 | /* |
| 571 | * If the LCD is Sanyo 2x5 in on the IB2 board, turn the back-light on | 571 | * If the LCD is Sanyo 2x5 in on the IB2 board, turn the back-light on |
| 572 | */ | 572 | */ |
| 573 | if (fb->panel == &sanyo_2_5_in) { | 573 | if (fb->panel == &sanyo_2_5_in) { |
| 574 | unsigned long versatile_ib2_ctrl = IO_ADDRESS(VERSATILE_IB2_CTRL); | 574 | unsigned long versatile_ib2_ctrl = IO_ADDRESS(VERSATILE_IB2_CTRL); |
| 575 | unsigned long ctrl; | 575 | unsigned long ctrl; |
| 576 | 576 | ||
| 577 | ctrl = readl(versatile_ib2_ctrl); | 577 | ctrl = readl(versatile_ib2_ctrl); |
| 578 | ctrl |= 0x01; | 578 | ctrl |= 0x01; |
| 579 | writel(ctrl, versatile_ib2_ctrl); | 579 | writel(ctrl, versatile_ib2_ctrl); |
| 580 | } | 580 | } |
| 581 | #endif | 581 | #endif |
| 582 | } | 582 | } |
| 583 | 583 | ||
| 584 | static unsigned long framesize = SZ_1M; | 584 | static unsigned long framesize = SZ_1M; |
| 585 | 585 | ||
| 586 | static int versatile_clcd_setup(struct clcd_fb *fb) | 586 | static int versatile_clcd_setup(struct clcd_fb *fb) |
| 587 | { | 587 | { |
| 588 | dma_addr_t dma; | 588 | dma_addr_t dma; |
| 589 | 589 | ||
| 590 | fb->panel = versatile_clcd_panel(); | 590 | fb->panel = versatile_clcd_panel(); |
| 591 | 591 | ||
| 592 | fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize, | 592 | fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize, |
| 593 | &dma, GFP_KERNEL); | 593 | &dma, GFP_KERNEL); |
| 594 | if (!fb->fb.screen_base) { | 594 | if (!fb->fb.screen_base) { |
| 595 | printk(KERN_ERR "CLCD: unable to map framebuffer\n"); | 595 | printk(KERN_ERR "CLCD: unable to map framebuffer\n"); |
| 596 | return -ENOMEM; | 596 | return -ENOMEM; |
| 597 | } | 597 | } |
| 598 | 598 | ||
| 599 | fb->fb.fix.smem_start = dma; | 599 | fb->fb.fix.smem_start = dma; |
| 600 | fb->fb.fix.smem_len = framesize; | 600 | fb->fb.fix.smem_len = framesize; |
| 601 | 601 | ||
| 602 | return 0; | 602 | return 0; |
| 603 | } | 603 | } |
| 604 | 604 | ||
| 605 | static int versatile_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma) | 605 | static int versatile_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma) |
| 606 | { | 606 | { |
| 607 | return dma_mmap_writecombine(&fb->dev->dev, vma, | 607 | return dma_mmap_writecombine(&fb->dev->dev, vma, |
| 608 | fb->fb.screen_base, | 608 | fb->fb.screen_base, |
| 609 | fb->fb.fix.smem_start, | 609 | fb->fb.fix.smem_start, |
| 610 | fb->fb.fix.smem_len); | 610 | fb->fb.fix.smem_len); |
| 611 | } | 611 | } |
| 612 | 612 | ||
| 613 | static void versatile_clcd_remove(struct clcd_fb *fb) | 613 | static void versatile_clcd_remove(struct clcd_fb *fb) |
| 614 | { | 614 | { |
| 615 | dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len, | 615 | dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len, |
| 616 | fb->fb.screen_base, fb->fb.fix.smem_start); | 616 | fb->fb.screen_base, fb->fb.fix.smem_start); |
| 617 | } | 617 | } |
| 618 | 618 | ||
| 619 | static struct clcd_board clcd_plat_data = { | 619 | static struct clcd_board clcd_plat_data = { |
| 620 | .name = "Versatile", | 620 | .name = "Versatile", |
| 621 | .check = clcdfb_check, | 621 | .check = clcdfb_check, |
| 622 | .decode = clcdfb_decode, | 622 | .decode = clcdfb_decode, |
| 623 | .disable = versatile_clcd_disable, | 623 | .disable = versatile_clcd_disable, |
| 624 | .enable = versatile_clcd_enable, | 624 | .enable = versatile_clcd_enable, |
| 625 | .setup = versatile_clcd_setup, | 625 | .setup = versatile_clcd_setup, |
| 626 | .mmap = versatile_clcd_mmap, | 626 | .mmap = versatile_clcd_mmap, |
| 627 | .remove = versatile_clcd_remove, | 627 | .remove = versatile_clcd_remove, |
| 628 | }; | 628 | }; |
| 629 | 629 | ||
| 630 | #define AACI_IRQ { IRQ_AACI, NO_IRQ } | 630 | #define AACI_IRQ { IRQ_AACI, NO_IRQ } |
| 631 | #define AACI_DMA { 0x80, 0x81 } | 631 | #define AACI_DMA { 0x80, 0x81 } |
| 632 | #define MMCI0_IRQ { IRQ_MMCI0A,IRQ_SIC_MMCI0B } | 632 | #define MMCI0_IRQ { IRQ_MMCI0A,IRQ_SIC_MMCI0B } |
| 633 | #define MMCI0_DMA { 0x84, 0 } | 633 | #define MMCI0_DMA { 0x84, 0 } |
| 634 | #define KMI0_IRQ { IRQ_SIC_KMI0, NO_IRQ } | 634 | #define KMI0_IRQ { IRQ_SIC_KMI0, NO_IRQ } |
| 635 | #define KMI0_DMA { 0, 0 } | 635 | #define KMI0_DMA { 0, 0 } |
| 636 | #define KMI1_IRQ { IRQ_SIC_KMI1, NO_IRQ } | 636 | #define KMI1_IRQ { IRQ_SIC_KMI1, NO_IRQ } |
| 637 | #define KMI1_DMA { 0, 0 } | 637 | #define KMI1_DMA { 0, 0 } |
| 638 | 638 | ||
| 639 | /* | 639 | /* |
| 640 | * These devices are connected directly to the multi-layer AHB switch | 640 | * These devices are connected directly to the multi-layer AHB switch |
| 641 | */ | 641 | */ |
| 642 | #define SMC_IRQ { NO_IRQ, NO_IRQ } | 642 | #define SMC_IRQ { NO_IRQ, NO_IRQ } |
| 643 | #define SMC_DMA { 0, 0 } | 643 | #define SMC_DMA { 0, 0 } |
| 644 | #define MPMC_IRQ { NO_IRQ, NO_IRQ } | 644 | #define MPMC_IRQ { NO_IRQ, NO_IRQ } |
| 645 | #define MPMC_DMA { 0, 0 } | 645 | #define MPMC_DMA { 0, 0 } |
| 646 | #define CLCD_IRQ { IRQ_CLCDINT, NO_IRQ } | 646 | #define CLCD_IRQ { IRQ_CLCDINT, NO_IRQ } |
| 647 | #define CLCD_DMA { 0, 0 } | 647 | #define CLCD_DMA { 0, 0 } |
| 648 | #define DMAC_IRQ { IRQ_DMAINT, NO_IRQ } | 648 | #define DMAC_IRQ { IRQ_DMAINT, NO_IRQ } |
| 649 | #define DMAC_DMA { 0, 0 } | 649 | #define DMAC_DMA { 0, 0 } |
| 650 | 650 | ||
| 651 | /* | 651 | /* |
| 652 | * These devices are connected via the core APB bridge | 652 | * These devices are connected via the core APB bridge |
| 653 | */ | 653 | */ |
| 654 | #define SCTL_IRQ { NO_IRQ, NO_IRQ } | 654 | #define SCTL_IRQ { NO_IRQ, NO_IRQ } |
| 655 | #define SCTL_DMA { 0, 0 } | 655 | #define SCTL_DMA { 0, 0 } |
| 656 | #define WATCHDOG_IRQ { IRQ_WDOGINT, NO_IRQ } | 656 | #define WATCHDOG_IRQ { IRQ_WDOGINT, NO_IRQ } |
| 657 | #define WATCHDOG_DMA { 0, 0 } | 657 | #define WATCHDOG_DMA { 0, 0 } |
| 658 | #define GPIO0_IRQ { IRQ_GPIOINT0, NO_IRQ } | 658 | #define GPIO0_IRQ { IRQ_GPIOINT0, NO_IRQ } |
| 659 | #define GPIO0_DMA { 0, 0 } | 659 | #define GPIO0_DMA { 0, 0 } |
| 660 | #define GPIO1_IRQ { IRQ_GPIOINT1, NO_IRQ } | 660 | #define GPIO1_IRQ { IRQ_GPIOINT1, NO_IRQ } |
| 661 | #define GPIO1_DMA { 0, 0 } | 661 | #define GPIO1_DMA { 0, 0 } |
| 662 | #define RTC_IRQ { IRQ_RTCINT, NO_IRQ } | 662 | #define RTC_IRQ { IRQ_RTCINT, NO_IRQ } |
| 663 | #define RTC_DMA { 0, 0 } | 663 | #define RTC_DMA { 0, 0 } |
| 664 | 664 | ||
| 665 | /* | 665 | /* |
| 666 | * These devices are connected via the DMA APB bridge | 666 | * These devices are connected via the DMA APB bridge |
| 667 | */ | 667 | */ |
| 668 | #define SCI_IRQ { IRQ_SCIINT, NO_IRQ } | 668 | #define SCI_IRQ { IRQ_SCIINT, NO_IRQ } |
| 669 | #define SCI_DMA { 7, 6 } | 669 | #define SCI_DMA { 7, 6 } |
| 670 | #define UART0_IRQ { IRQ_UARTINT0, NO_IRQ } | 670 | #define UART0_IRQ { IRQ_UARTINT0, NO_IRQ } |
| 671 | #define UART0_DMA { 15, 14 } | 671 | #define UART0_DMA { 15, 14 } |
| 672 | #define UART1_IRQ { IRQ_UARTINT1, NO_IRQ } | 672 | #define UART1_IRQ { IRQ_UARTINT1, NO_IRQ } |
| 673 | #define UART1_DMA { 13, 12 } | 673 | #define UART1_DMA { 13, 12 } |
| 674 | #define UART2_IRQ { IRQ_UARTINT2, NO_IRQ } | 674 | #define UART2_IRQ { IRQ_UARTINT2, NO_IRQ } |
| 675 | #define UART2_DMA { 11, 10 } | 675 | #define UART2_DMA { 11, 10 } |
| 676 | #define SSP_IRQ { IRQ_SSPINT, NO_IRQ } | 676 | #define SSP_IRQ { IRQ_SSPINT, NO_IRQ } |
| 677 | #define SSP_DMA { 9, 8 } | 677 | #define SSP_DMA { 9, 8 } |
| 678 | 678 | ||
| 679 | /* FPGA Primecells */ | 679 | /* FPGA Primecells */ |
| 680 | AMBA_DEVICE(aaci, "fpga:04", AACI, NULL); | 680 | AMBA_DEVICE(aaci, "fpga:04", AACI, NULL); |
| 681 | AMBA_DEVICE(mmc0, "fpga:05", MMCI0, &mmc0_plat_data); | 681 | AMBA_DEVICE(mmc0, "fpga:05", MMCI0, &mmc0_plat_data); |
| 682 | AMBA_DEVICE(kmi0, "fpga:06", KMI0, NULL); | 682 | AMBA_DEVICE(kmi0, "fpga:06", KMI0, NULL); |
| 683 | AMBA_DEVICE(kmi1, "fpga:07", KMI1, NULL); | 683 | AMBA_DEVICE(kmi1, "fpga:07", KMI1, NULL); |
| 684 | 684 | ||
| 685 | /* DevChip Primecells */ | 685 | /* DevChip Primecells */ |
| 686 | AMBA_DEVICE(smc, "dev:00", SMC, NULL); | 686 | AMBA_DEVICE(smc, "dev:00", SMC, NULL); |
| 687 | AMBA_DEVICE(mpmc, "dev:10", MPMC, NULL); | 687 | AMBA_DEVICE(mpmc, "dev:10", MPMC, NULL); |
| 688 | AMBA_DEVICE(clcd, "dev:20", CLCD, &clcd_plat_data); | 688 | AMBA_DEVICE(clcd, "dev:20", CLCD, &clcd_plat_data); |
| 689 | AMBA_DEVICE(dmac, "dev:30", DMAC, NULL); | 689 | AMBA_DEVICE(dmac, "dev:30", DMAC, NULL); |
| 690 | AMBA_DEVICE(sctl, "dev:e0", SCTL, NULL); | 690 | AMBA_DEVICE(sctl, "dev:e0", SCTL, NULL); |
| 691 | AMBA_DEVICE(wdog, "dev:e1", WATCHDOG, NULL); | 691 | AMBA_DEVICE(wdog, "dev:e1", WATCHDOG, NULL); |
| 692 | AMBA_DEVICE(gpio0, "dev:e4", GPIO0, NULL); | 692 | AMBA_DEVICE(gpio0, "dev:e4", GPIO0, NULL); |
| 693 | AMBA_DEVICE(gpio1, "dev:e5", GPIO1, NULL); | 693 | AMBA_DEVICE(gpio1, "dev:e5", GPIO1, NULL); |
| 694 | AMBA_DEVICE(rtc, "dev:e8", RTC, NULL); | 694 | AMBA_DEVICE(rtc, "dev:e8", RTC, NULL); |
| 695 | AMBA_DEVICE(sci0, "dev:f0", SCI, NULL); | 695 | AMBA_DEVICE(sci0, "dev:f0", SCI, NULL); |
| 696 | AMBA_DEVICE(uart0, "dev:f1", UART0, NULL); | 696 | AMBA_DEVICE(uart0, "dev:f1", UART0, NULL); |
| 697 | AMBA_DEVICE(uart1, "dev:f2", UART1, NULL); | 697 | AMBA_DEVICE(uart1, "dev:f2", UART1, NULL); |
| 698 | AMBA_DEVICE(uart2, "dev:f3", UART2, NULL); | 698 | AMBA_DEVICE(uart2, "dev:f3", UART2, NULL); |
| 699 | AMBA_DEVICE(ssp0, "dev:f4", SSP, NULL); | 699 | AMBA_DEVICE(ssp0, "dev:f4", SSP, NULL); |
| 700 | 700 | ||
| 701 | static struct amba_device *amba_devs[] __initdata = { | 701 | static struct amba_device *amba_devs[] __initdata = { |
| 702 | &dmac_device, | 702 | &dmac_device, |
| 703 | &uart0_device, | 703 | &uart0_device, |
| 704 | &uart1_device, | 704 | &uart1_device, |
| 705 | &uart2_device, | 705 | &uart2_device, |
| 706 | &smc_device, | 706 | &smc_device, |
| 707 | &mpmc_device, | 707 | &mpmc_device, |
| 708 | &clcd_device, | 708 | &clcd_device, |
| 709 | &sctl_device, | 709 | &sctl_device, |
| 710 | &wdog_device, | 710 | &wdog_device, |
| 711 | &gpio0_device, | 711 | &gpio0_device, |
| 712 | &gpio1_device, | 712 | &gpio1_device, |
| 713 | &rtc_device, | 713 | &rtc_device, |
| 714 | &sci0_device, | 714 | &sci0_device, |
| 715 | &ssp0_device, | 715 | &ssp0_device, |
| 716 | &aaci_device, | 716 | &aaci_device, |
| 717 | &mmc0_device, | 717 | &mmc0_device, |
| 718 | &kmi0_device, | 718 | &kmi0_device, |
| 719 | &kmi1_device, | 719 | &kmi1_device, |
| 720 | }; | 720 | }; |
| 721 | 721 | ||
| 722 | #ifdef CONFIG_LEDS | 722 | #ifdef CONFIG_LEDS |
| 723 | #define VA_LEDS_BASE (IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_LED_OFFSET) | 723 | #define VA_LEDS_BASE (IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_LED_OFFSET) |
| 724 | 724 | ||
| 725 | static void versatile_leds_event(led_event_t ledevt) | 725 | static void versatile_leds_event(led_event_t ledevt) |
| 726 | { | 726 | { |
| 727 | unsigned long flags; | 727 | unsigned long flags; |
| 728 | u32 val; | 728 | u32 val; |
| 729 | 729 | ||
| 730 | local_irq_save(flags); | 730 | local_irq_save(flags); |
| 731 | val = readl(VA_LEDS_BASE); | 731 | val = readl(VA_LEDS_BASE); |
| 732 | 732 | ||
| 733 | switch (ledevt) { | 733 | switch (ledevt) { |
| 734 | case led_idle_start: | 734 | case led_idle_start: |
| 735 | val = val & ~VERSATILE_SYS_LED0; | 735 | val = val & ~VERSATILE_SYS_LED0; |
| 736 | break; | 736 | break; |
| 737 | 737 | ||
| 738 | case led_idle_end: | 738 | case led_idle_end: |
| 739 | val = val | VERSATILE_SYS_LED0; | 739 | val = val | VERSATILE_SYS_LED0; |
| 740 | break; | 740 | break; |
| 741 | 741 | ||
| 742 | case led_timer: | 742 | case led_timer: |
| 743 | val = val ^ VERSATILE_SYS_LED1; | 743 | val = val ^ VERSATILE_SYS_LED1; |
| 744 | break; | 744 | break; |
| 745 | 745 | ||
| 746 | case led_halted: | 746 | case led_halted: |
| 747 | val = 0; | 747 | val = 0; |
| 748 | break; | 748 | break; |
| 749 | 749 | ||
| 750 | default: | 750 | default: |
| 751 | break; | 751 | break; |
| 752 | } | 752 | } |
| 753 | 753 | ||
| 754 | writel(val, VA_LEDS_BASE); | 754 | writel(val, VA_LEDS_BASE); |
| 755 | local_irq_restore(flags); | 755 | local_irq_restore(flags); |
| 756 | } | 756 | } |
| 757 | #endif /* CONFIG_LEDS */ | 757 | #endif /* CONFIG_LEDS */ |
| 758 | 758 | ||
| 759 | void __init versatile_init(void) | 759 | void __init versatile_init(void) |
| 760 | { | 760 | { |
| 761 | int i; | 761 | int i; |
| 762 | 762 | ||
| 763 | clk_register(&versatile_clcd_clk); | 763 | clk_register(&versatile_clcd_clk); |
| 764 | 764 | ||
| 765 | platform_device_register(&versatile_flash_device); | 765 | platform_device_register(&versatile_flash_device); |
| 766 | platform_device_register(&smc91x_device); | 766 | platform_device_register(&smc91x_device); |
| 767 | 767 | ||
| 768 | for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { | 768 | for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { |
| 769 | struct amba_device *d = amba_devs[i]; | 769 | struct amba_device *d = amba_devs[i]; |
| 770 | amba_device_register(d, &iomem_resource); | 770 | amba_device_register(d, &iomem_resource); |
| 771 | } | 771 | } |
| 772 | 772 | ||
| 773 | #ifdef CONFIG_LEDS | 773 | #ifdef CONFIG_LEDS |
| 774 | leds_event = versatile_leds_event; | 774 | leds_event = versatile_leds_event; |
| 775 | #endif | 775 | #endif |
| 776 | } | 776 | } |
| 777 | 777 | ||
| 778 | /* | 778 | /* |
| 779 | * Where is the timer (VA)? | 779 | * Where is the timer (VA)? |
| 780 | */ | 780 | */ |
| 781 | #define TIMER0_VA_BASE IO_ADDRESS(VERSATILE_TIMER0_1_BASE) | 781 | #define TIMER0_VA_BASE IO_ADDRESS(VERSATILE_TIMER0_1_BASE) |
| 782 | #define TIMER1_VA_BASE (IO_ADDRESS(VERSATILE_TIMER0_1_BASE) + 0x20) | 782 | #define TIMER1_VA_BASE (IO_ADDRESS(VERSATILE_TIMER0_1_BASE) + 0x20) |
| 783 | #define TIMER2_VA_BASE IO_ADDRESS(VERSATILE_TIMER2_3_BASE) | 783 | #define TIMER2_VA_BASE IO_ADDRESS(VERSATILE_TIMER2_3_BASE) |
| 784 | #define TIMER3_VA_BASE (IO_ADDRESS(VERSATILE_TIMER2_3_BASE) + 0x20) | 784 | #define TIMER3_VA_BASE (IO_ADDRESS(VERSATILE_TIMER2_3_BASE) + 0x20) |
| 785 | #define VA_IC_BASE IO_ADDRESS(VERSATILE_VIC_BASE) | 785 | #define VA_IC_BASE IO_ADDRESS(VERSATILE_VIC_BASE) |
| 786 | 786 | ||
| 787 | /* | 787 | /* |
| 788 | * How long is the timer interval? | 788 | * How long is the timer interval? |
| 789 | */ | 789 | */ |
| 790 | #define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10) | 790 | #define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10) |
| 791 | #if TIMER_INTERVAL >= 0x100000 | 791 | #if TIMER_INTERVAL >= 0x100000 |
| 792 | #define TIMER_RELOAD (TIMER_INTERVAL >> 8) | 792 | #define TIMER_RELOAD (TIMER_INTERVAL >> 8) |
| 793 | #define TIMER_DIVISOR (TIMER_CTRL_DIV256) | 793 | #define TIMER_DIVISOR (TIMER_CTRL_DIV256) |
| 794 | #define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC) | 794 | #define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC) |
| 795 | #elif TIMER_INTERVAL >= 0x10000 | 795 | #elif TIMER_INTERVAL >= 0x10000 |
| 796 | #define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */ | 796 | #define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */ |
| 797 | #define TIMER_DIVISOR (TIMER_CTRL_DIV16) | 797 | #define TIMER_DIVISOR (TIMER_CTRL_DIV16) |
| 798 | #define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC) | 798 | #define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC) |
| 799 | #else | 799 | #else |
| 800 | #define TIMER_RELOAD (TIMER_INTERVAL) | 800 | #define TIMER_RELOAD (TIMER_INTERVAL) |
| 801 | #define TIMER_DIVISOR (TIMER_CTRL_DIV1) | 801 | #define TIMER_DIVISOR (TIMER_CTRL_DIV1) |
| 802 | #define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) | 802 | #define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) |
| 803 | #endif | 803 | #endif |
| 804 | 804 | ||
| 805 | /* | 805 | /* |
| 806 | * Returns number of ms since last clock interrupt. Note that interrupts | 806 | * Returns number of ms since last clock interrupt. Note that interrupts |
| 807 | * will have been disabled by do_gettimeoffset() | 807 | * will have been disabled by do_gettimeoffset() |
| 808 | */ | 808 | */ |
| 809 | static unsigned long versatile_gettimeoffset(void) | 809 | static unsigned long versatile_gettimeoffset(void) |
| 810 | { | 810 | { |
| 811 | unsigned long ticks1, ticks2, status; | 811 | unsigned long ticks1, ticks2, status; |
| 812 | 812 | ||
| 813 | /* | 813 | /* |
| 814 | * Get the current number of ticks. Note that there is a race | 814 | * Get the current number of ticks. Note that there is a race |
| 815 | * condition between us reading the timer and checking for | 815 | * condition between us reading the timer and checking for |
| 816 | * an interrupt. We get around this by ensuring that the | 816 | * an interrupt. We get around this by ensuring that the |
| 817 | * counter has not reloaded between our two reads. | 817 | * counter has not reloaded between our two reads. |
| 818 | */ | 818 | */ |
| 819 | ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff; | 819 | ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff; |
| 820 | do { | 820 | do { |
| 821 | ticks1 = ticks2; | 821 | ticks1 = ticks2; |
| 822 | status = __raw_readl(VA_IC_BASE + VIC_IRQ_RAW_STATUS); | 822 | status = __raw_readl(VA_IC_BASE + VIC_IRQ_RAW_STATUS); |
| 823 | ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff; | 823 | ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff; |
| 824 | } while (ticks2 > ticks1); | 824 | } while (ticks2 > ticks1); |
| 825 | 825 | ||
| 826 | /* | 826 | /* |
| 827 | * Number of ticks since last interrupt. | 827 | * Number of ticks since last interrupt. |
| 828 | */ | 828 | */ |
| 829 | ticks1 = TIMER_RELOAD - ticks2; | 829 | ticks1 = TIMER_RELOAD - ticks2; |
| 830 | 830 | ||
| 831 | /* | 831 | /* |
| 832 | * Interrupt pending? If so, we've reloaded once already. | 832 | * Interrupt pending? If so, we've reloaded once already. |
| 833 | * | 833 | * |
| 834 | * FIXME: Need to check this is effectively timer 0 that expires | 834 | * FIXME: Need to check this is effectively timer 0 that expires |
| 835 | */ | 835 | */ |
| 836 | if (status & IRQMASK_TIMERINT0_1) | 836 | if (status & IRQMASK_TIMERINT0_1) |
| 837 | ticks1 += TIMER_RELOAD; | 837 | ticks1 += TIMER_RELOAD; |
| 838 | 838 | ||
| 839 | /* | 839 | /* |
| 840 | * Convert the ticks to usecs | 840 | * Convert the ticks to usecs |
| 841 | */ | 841 | */ |
| 842 | return TICKS2USECS(ticks1); | 842 | return TICKS2USECS(ticks1); |
| 843 | } | 843 | } |
| 844 | 844 | ||
| 845 | /* | 845 | /* |
| 846 | * IRQ handler for the timer | 846 | * IRQ handler for the timer |
| 847 | */ | 847 | */ |
| 848 | static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 848 | static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) |
| 849 | { | 849 | { |
| 850 | write_seqlock(&xtime_lock); | 850 | write_seqlock(&xtime_lock); |
| 851 | 851 | ||
| 852 | // ...clear the interrupt | 852 | // ...clear the interrupt |
| 853 | writel(1, TIMER0_VA_BASE + TIMER_INTCLR); | 853 | writel(1, TIMER0_VA_BASE + TIMER_INTCLR); |
| 854 | 854 | ||
| 855 | timer_tick(regs); | 855 | timer_tick(regs); |
| 856 | 856 | ||
| 857 | write_sequnlock(&xtime_lock); | 857 | write_sequnlock(&xtime_lock); |
| 858 | 858 | ||
| 859 | return IRQ_HANDLED; | 859 | return IRQ_HANDLED; |
| 860 | } | 860 | } |
| 861 | 861 | ||
| 862 | static struct irqaction versatile_timer_irq = { | 862 | static struct irqaction versatile_timer_irq = { |
| 863 | .name = "Versatile Timer Tick", | 863 | .name = "Versatile Timer Tick", |
| 864 | .flags = SA_INTERRUPT | SA_TIMER, | 864 | .flags = SA_INTERRUPT | SA_TIMER, |
| 865 | .handler = versatile_timer_interrupt, | 865 | .handler = versatile_timer_interrupt, |
| 866 | }; | 866 | }; |
| 867 | 867 | ||
| 868 | /* | 868 | /* |
| 869 | * Set up timer interrupt, and return the current time in seconds. | 869 | * Set up timer interrupt, and return the current time in seconds. |
| 870 | */ | 870 | */ |
| 871 | static void __init versatile_timer_init(void) | 871 | static void __init versatile_timer_init(void) |
| 872 | { | 872 | { |
| 873 | u32 val; | 873 | u32 val; |
| 874 | 874 | ||
| 875 | /* | 875 | /* |
| 876 | * set clock frequency: | 876 | * set clock frequency: |
| 877 | * VERSATILE_REFCLK is 32KHz | 877 | * VERSATILE_REFCLK is 32KHz |
| 878 | * VERSATILE_TIMCLK is 1MHz | 878 | * VERSATILE_TIMCLK is 1MHz |
| 879 | */ | 879 | */ |
| 880 | val = readl(IO_ADDRESS(VERSATILE_SCTL_BASE)); | 880 | val = readl(IO_ADDRESS(VERSATILE_SCTL_BASE)); |
| 881 | writel((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) | | 881 | writel((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) | |
| 882 | (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) | | 882 | (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) | |
| 883 | (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) | | 883 | (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) | |
| 884 | (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel) | val, | 884 | (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel) | val, |
| 885 | IO_ADDRESS(VERSATILE_SCTL_BASE)); | 885 | IO_ADDRESS(VERSATILE_SCTL_BASE)); |
| 886 | 886 | ||
| 887 | /* | 887 | /* |
| 888 | * Initialise to a known state (all timers off) | 888 | * Initialise to a known state (all timers off) |
| 889 | */ | 889 | */ |
| 890 | writel(0, TIMER0_VA_BASE + TIMER_CTRL); | 890 | writel(0, TIMER0_VA_BASE + TIMER_CTRL); |
| 891 | writel(0, TIMER1_VA_BASE + TIMER_CTRL); | 891 | writel(0, TIMER1_VA_BASE + TIMER_CTRL); |
| 892 | writel(0, TIMER2_VA_BASE + TIMER_CTRL); | 892 | writel(0, TIMER2_VA_BASE + TIMER_CTRL); |
| 893 | writel(0, TIMER3_VA_BASE + TIMER_CTRL); | 893 | writel(0, TIMER3_VA_BASE + TIMER_CTRL); |
| 894 | 894 | ||
| 895 | writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD); | 895 | writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD); |
| 896 | writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_VALUE); | 896 | writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_VALUE); |
| 897 | writel(TIMER_DIVISOR | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC | | 897 | writel(TIMER_DIVISOR | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC | |
| 898 | TIMER_CTRL_IE, TIMER0_VA_BASE + TIMER_CTRL); | 898 | TIMER_CTRL_IE, TIMER0_VA_BASE + TIMER_CTRL); |
| 899 | 899 | ||
| 900 | /* | 900 | /* |
| 901 | * Make irqs happen for the system timer | 901 | * Make irqs happen for the system timer |
| 902 | */ | 902 | */ |
| 903 | setup_irq(IRQ_TIMERINT0_1, &versatile_timer_irq); | 903 | setup_irq(IRQ_TIMERINT0_1, &versatile_timer_irq); |
| 904 | } | 904 | } |
| 905 | 905 | ||
| 906 | struct sys_timer versatile_timer = { | 906 | struct sys_timer versatile_timer = { |
| 907 | .init = versatile_timer_init, | 907 | .init = versatile_timer_init, |
| 908 | .offset = versatile_gettimeoffset, | 908 | .offset = versatile_gettimeoffset, |
| 909 | }; | 909 | }; |
| 910 | 910 |
arch/arm/mm/proc-arm6_7.S
| 1 | /* | 1 | /* |
| 2 | * linux/arch/arm/mm/proc-arm6,7.S | 2 | * linux/arch/arm/mm/proc-arm6,7.S |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 1997-2000 Russell King | 4 | * Copyright (C) 1997-2000 Russell King |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
| 8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
| 9 | * | 9 | * |
| 10 | * These are the low level assembler for performing cache and TLB | 10 | * These are the low level assembler for performing cache and TLB |
| 11 | * functions on the ARM610 & ARM710. | 11 | * functions on the ARM610 & ARM710. |
| 12 | */ | 12 | */ |
| 13 | #include <linux/linkage.h> | 13 | #include <linux/linkage.h> |
| 14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
| 15 | #include <asm/assembler.h> | 15 | #include <asm/assembler.h> |
| 16 | #include <asm/constants.h> | 16 | #include <asm/constants.h> |
| 17 | #include <asm/pgtable.h> | 17 | #include <asm/pgtable.h> |
| 18 | #include <asm/procinfo.h> | 18 | #include <asm/procinfo.h> |
| 19 | #include <asm/ptrace.h> | 19 | #include <asm/ptrace.h> |
| 20 | 20 | ||
| 21 | ENTRY(cpu_arm6_dcache_clean_area) | 21 | ENTRY(cpu_arm6_dcache_clean_area) |
| 22 | ENTRY(cpu_arm7_dcache_clean_area) | 22 | ENTRY(cpu_arm7_dcache_clean_area) |
| 23 | mov pc, lr | 23 | mov pc, lr |
| 24 | 24 | ||
| 25 | /* | 25 | /* |
| 26 | * Function: arm6_7_data_abort () | 26 | * Function: arm6_7_data_abort () |
| 27 | * | 27 | * |
| 28 | * Params : r2 = address of aborted instruction | 28 | * Params : r2 = address of aborted instruction |
| 29 | * : sp = pointer to registers | 29 | * : sp = pointer to registers |
| 30 | * | 30 | * |
| 31 | * Purpose : obtain information about current aborted instruction | 31 | * Purpose : obtain information about current aborted instruction |
| 32 | * | 32 | * |
| 33 | * Returns : r0 = address of abort | 33 | * Returns : r0 = address of abort |
| 34 | * : r1 = FSR | 34 | * : r1 = FSR |
| 35 | */ | 35 | */ |
| 36 | 36 | ||
| 37 | ENTRY(cpu_arm7_data_abort) | 37 | ENTRY(cpu_arm7_data_abort) |
| 38 | mrc p15, 0, r1, c5, c0, 0 @ get FSR | 38 | mrc p15, 0, r1, c5, c0, 0 @ get FSR |
| 39 | mrc p15, 0, r0, c6, c0, 0 @ get FAR | 39 | mrc p15, 0, r0, c6, c0, 0 @ get FAR |
| 40 | ldr r8, [r0] @ read arm instruction | 40 | ldr r8, [r0] @ read arm instruction |
| 41 | tst r8, #1 << 20 @ L = 1 -> write? | 41 | tst r8, #1 << 20 @ L = 0 -> write? |
| 42 | orreq r1, r1, #1 << 8 @ yes. | 42 | orreq r1, r1, #1 << 11 @ yes. |
| 43 | and r7, r8, #15 << 24 | 43 | and r7, r8, #15 << 24 |
| 44 | add pc, pc, r7, lsr #22 @ Now branch to the relevant processing routine | 44 | add pc, pc, r7, lsr #22 @ Now branch to the relevant processing routine |
| 45 | nop | 45 | nop |
| 46 | 46 | ||
| 47 | /* 0 */ b .data_unknown | 47 | /* 0 */ b .data_unknown |
| 48 | /* 1 */ mov pc, lr @ swp | 48 | /* 1 */ mov pc, lr @ swp |
| 49 | /* 2 */ b .data_unknown | 49 | /* 2 */ b .data_unknown |
| 50 | /* 3 */ b .data_unknown | 50 | /* 3 */ b .data_unknown |
| 51 | /* 4 */ b .data_arm_lateldrpostconst @ ldr rd, [rn], #m | 51 | /* 4 */ b .data_arm_lateldrpostconst @ ldr rd, [rn], #m |
| 52 | /* 5 */ b .data_arm_lateldrpreconst @ ldr rd, [rn, #m] | 52 | /* 5 */ b .data_arm_lateldrpreconst @ ldr rd, [rn, #m] |
| 53 | /* 6 */ b .data_arm_lateldrpostreg @ ldr rd, [rn], rm | 53 | /* 6 */ b .data_arm_lateldrpostreg @ ldr rd, [rn], rm |
| 54 | /* 7 */ b .data_arm_lateldrprereg @ ldr rd, [rn, rm] | 54 | /* 7 */ b .data_arm_lateldrprereg @ ldr rd, [rn, rm] |
| 55 | /* 8 */ b .data_arm_ldmstm @ ldm*a rn, <rlist> | 55 | /* 8 */ b .data_arm_ldmstm @ ldm*a rn, <rlist> |
| 56 | /* 9 */ b .data_arm_ldmstm @ ldm*b rn, <rlist> | 56 | /* 9 */ b .data_arm_ldmstm @ ldm*b rn, <rlist> |
| 57 | /* a */ b .data_unknown | 57 | /* a */ b .data_unknown |
| 58 | /* b */ b .data_unknown | 58 | /* b */ b .data_unknown |
| 59 | /* c */ mov pc, lr @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m | 59 | /* c */ mov pc, lr @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m |
| 60 | /* d */ mov pc, lr @ ldc rd, [rn, #m] | 60 | /* d */ mov pc, lr @ ldc rd, [rn, #m] |
| 61 | /* e */ b .data_unknown | 61 | /* e */ b .data_unknown |
| 62 | /* f */ | 62 | /* f */ |
| 63 | .data_unknown: @ Part of jumptable | 63 | .data_unknown: @ Part of jumptable |
| 64 | mov r0, r2 | 64 | mov r0, r2 |
| 65 | mov r1, r8 | 65 | mov r1, r8 |
| 66 | mov r2, sp | 66 | mov r2, sp |
| 67 | bl baddataabort | 67 | bl baddataabort |
| 68 | b ret_from_exception | 68 | b ret_from_exception |
| 69 | 69 | ||
| 70 | ENTRY(cpu_arm6_data_abort) | 70 | ENTRY(cpu_arm6_data_abort) |
| 71 | mrc p15, 0, r1, c5, c0, 0 @ get FSR | 71 | mrc p15, 0, r1, c5, c0, 0 @ get FSR |
| 72 | mrc p15, 0, r0, c6, c0, 0 @ get FAR | 72 | mrc p15, 0, r0, c6, c0, 0 @ get FAR |
| 73 | ldr r8, [r2] @ read arm instruction | 73 | ldr r8, [r2] @ read arm instruction |
| 74 | tst r8, #1 << 20 @ L = 1 -> write? | 74 | tst r8, #1 << 20 @ L = 0 -> write? |
| 75 | orreq r1, r1, #1 << 8 @ yes. | 75 | orreq r1, r1, #1 << 11 @ yes. |
| 76 | and r7, r8, #14 << 24 | 76 | and r7, r8, #14 << 24 |
| 77 | teq r7, #8 << 24 @ was it ldm/stm | 77 | teq r7, #8 << 24 @ was it ldm/stm |
| 78 | movne pc, lr | 78 | movne pc, lr |
| 79 | 79 | ||
| 80 | .data_arm_ldmstm: | 80 | .data_arm_ldmstm: |
| 81 | tst r8, #1 << 21 @ check writeback bit | 81 | tst r8, #1 << 21 @ check writeback bit |
| 82 | moveq pc, lr @ no writeback -> no fixup | 82 | moveq pc, lr @ no writeback -> no fixup |
| 83 | mov r7, #0x11 | 83 | mov r7, #0x11 |
| 84 | orr r7, r7, #0x1100 | 84 | orr r7, r7, #0x1100 |
| 85 | and r6, r8, r7 | 85 | and r6, r8, r7 |
| 86 | and r2, r8, r7, lsl #1 | 86 | and r2, r8, r7, lsl #1 |
| 87 | add r6, r6, r2, lsr #1 | 87 | add r6, r6, r2, lsr #1 |
| 88 | and r2, r8, r7, lsl #2 | 88 | and r2, r8, r7, lsl #2 |
| 89 | add r6, r6, r2, lsr #2 | 89 | add r6, r6, r2, lsr #2 |
| 90 | and r2, r8, r7, lsl #3 | 90 | and r2, r8, r7, lsl #3 |
| 91 | add r6, r6, r2, lsr #3 | 91 | add r6, r6, r2, lsr #3 |
| 92 | add r6, r6, r6, lsr #8 | 92 | add r6, r6, r6, lsr #8 |
| 93 | add r6, r6, r6, lsr #4 | 93 | add r6, r6, r6, lsr #4 |
| 94 | and r6, r6, #15 @ r6 = no. of registers to transfer. | 94 | and r6, r6, #15 @ r6 = no. of registers to transfer. |
| 95 | and r5, r8, #15 << 16 @ Extract 'n' from instruction | 95 | and r5, r8, #15 << 16 @ Extract 'n' from instruction |
| 96 | ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' | 96 | ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' |
| 97 | tst r8, #1 << 23 @ Check U bit | 97 | tst r8, #1 << 23 @ Check U bit |
| 98 | subne r7, r7, r6, lsl #2 @ Undo increment | 98 | subne r7, r7, r6, lsl #2 @ Undo increment |
| 99 | addeq r7, r7, r6, lsl #2 @ Undo decrement | 99 | addeq r7, r7, r6, lsl #2 @ Undo decrement |
| 100 | str r7, [sp, r5, lsr #14] @ Put register 'Rn' | 100 | str r7, [sp, r5, lsr #14] @ Put register 'Rn' |
| 101 | mov pc, lr | 101 | mov pc, lr |
| 102 | 102 | ||
| 103 | .data_arm_apply_r6_and_rn: | 103 | .data_arm_apply_r6_and_rn: |
| 104 | and r5, r8, #15 << 16 @ Extract 'n' from instruction | 104 | and r5, r8, #15 << 16 @ Extract 'n' from instruction |
| 105 | ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' | 105 | ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' |
| 106 | tst r8, #1 << 23 @ Check U bit | 106 | tst r8, #1 << 23 @ Check U bit |
| 107 | subne r7, r7, r6 @ Undo incrmenet | 107 | subne r7, r7, r6 @ Undo incrmenet |
| 108 | addeq r7, r7, r6 @ Undo decrement | 108 | addeq r7, r7, r6 @ Undo decrement |
| 109 | str r7, [sp, r5, lsr #14] @ Put register 'Rn' | 109 | str r7, [sp, r5, lsr #14] @ Put register 'Rn' |
| 110 | mov pc, lr | 110 | mov pc, lr |
| 111 | 111 | ||
| 112 | .data_arm_lateldrpreconst: | 112 | .data_arm_lateldrpreconst: |
| 113 | tst r8, #1 << 21 @ check writeback bit | 113 | tst r8, #1 << 21 @ check writeback bit |
| 114 | moveq pc, lr @ no writeback -> no fixup | 114 | moveq pc, lr @ no writeback -> no fixup |
| 115 | .data_arm_lateldrpostconst: | 115 | .data_arm_lateldrpostconst: |
| 116 | movs r2, r8, lsl #20 @ Get offset | 116 | movs r2, r8, lsl #20 @ Get offset |
| 117 | moveq pc, lr @ zero -> no fixup | 117 | moveq pc, lr @ zero -> no fixup |
| 118 | and r5, r8, #15 << 16 @ Extract 'n' from instruction | 118 | and r5, r8, #15 << 16 @ Extract 'n' from instruction |
| 119 | ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' | 119 | ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' |
| 120 | tst r8, #1 << 23 @ Check U bit | 120 | tst r8, #1 << 23 @ Check U bit |
| 121 | subne r7, r7, r2, lsr #20 @ Undo increment | 121 | subne r7, r7, r2, lsr #20 @ Undo increment |
| 122 | addeq r7, r7, r2, lsr #20 @ Undo decrement | 122 | addeq r7, r7, r2, lsr #20 @ Undo decrement |
| 123 | str r7, [sp, r5, lsr #14] @ Put register 'Rn' | 123 | str r7, [sp, r5, lsr #14] @ Put register 'Rn' |
| 124 | mov pc, lr | 124 | mov pc, lr |
| 125 | 125 | ||
| 126 | .data_arm_lateldrprereg: | 126 | .data_arm_lateldrprereg: |
| 127 | tst r8, #1 << 21 @ check writeback bit | 127 | tst r8, #1 << 21 @ check writeback bit |
| 128 | moveq pc, lr @ no writeback -> no fixup | 128 | moveq pc, lr @ no writeback -> no fixup |
| 129 | .data_arm_lateldrpostreg: | 129 | .data_arm_lateldrpostreg: |
| 130 | and r7, r8, #15 @ Extract 'm' from instruction | 130 | and r7, r8, #15 @ Extract 'm' from instruction |
| 131 | ldr r6, [sp, r7, lsl #2] @ Get register 'Rm' | 131 | ldr r6, [sp, r7, lsl #2] @ Get register 'Rm' |
| 132 | mov r5, r8, lsr #7 @ get shift count | 132 | mov r5, r8, lsr #7 @ get shift count |
| 133 | ands r5, r5, #31 | 133 | ands r5, r5, #31 |
| 134 | and r7, r8, #0x70 @ get shift type | 134 | and r7, r8, #0x70 @ get shift type |
| 135 | orreq r7, r7, #8 @ shift count = 0 | 135 | orreq r7, r7, #8 @ shift count = 0 |
| 136 | add pc, pc, r7 | 136 | add pc, pc, r7 |
| 137 | nop | 137 | nop |
| 138 | 138 | ||
| 139 | mov r6, r6, lsl r5 @ 0: LSL #!0 | 139 | mov r6, r6, lsl r5 @ 0: LSL #!0 |
| 140 | b .data_arm_apply_r6_and_rn | 140 | b .data_arm_apply_r6_and_rn |
| 141 | b .data_arm_apply_r6_and_rn @ 1: LSL #0 | 141 | b .data_arm_apply_r6_and_rn @ 1: LSL #0 |
| 142 | nop | 142 | nop |
| 143 | b .data_unknown @ 2: MUL? | 143 | b .data_unknown @ 2: MUL? |
| 144 | nop | 144 | nop |
| 145 | b .data_unknown @ 3: MUL? | 145 | b .data_unknown @ 3: MUL? |
| 146 | nop | 146 | nop |
| 147 | mov r6, r6, lsr r5 @ 4: LSR #!0 | 147 | mov r6, r6, lsr r5 @ 4: LSR #!0 |
| 148 | b .data_arm_apply_r6_and_rn | 148 | b .data_arm_apply_r6_and_rn |
| 149 | mov r6, r6, lsr #32 @ 5: LSR #32 | 149 | mov r6, r6, lsr #32 @ 5: LSR #32 |
| 150 | b .data_arm_apply_r6_and_rn | 150 | b .data_arm_apply_r6_and_rn |
| 151 | b .data_unknown @ 6: MUL? | 151 | b .data_unknown @ 6: MUL? |
| 152 | nop | 152 | nop |
| 153 | b .data_unknown @ 7: MUL? | 153 | b .data_unknown @ 7: MUL? |
| 154 | nop | 154 | nop |
| 155 | mov r6, r6, asr r5 @ 8: ASR #!0 | 155 | mov r6, r6, asr r5 @ 8: ASR #!0 |
| 156 | b .data_arm_apply_r6_and_rn | 156 | b .data_arm_apply_r6_and_rn |
| 157 | mov r6, r6, asr #32 @ 9: ASR #32 | 157 | mov r6, r6, asr #32 @ 9: ASR #32 |
| 158 | b .data_arm_apply_r6_and_rn | 158 | b .data_arm_apply_r6_and_rn |
| 159 | b .data_unknown @ A: MUL? | 159 | b .data_unknown @ A: MUL? |
| 160 | nop | 160 | nop |
| 161 | b .data_unknown @ B: MUL? | 161 | b .data_unknown @ B: MUL? |
| 162 | nop | 162 | nop |
| 163 | mov r6, r6, ror r5 @ C: ROR #!0 | 163 | mov r6, r6, ror r5 @ C: ROR #!0 |
| 164 | b .data_arm_apply_r6_and_rn | 164 | b .data_arm_apply_r6_and_rn |
| 165 | mov r6, r6, rrx @ D: RRX | 165 | mov r6, r6, rrx @ D: RRX |
| 166 | b .data_arm_apply_r6_and_rn | 166 | b .data_arm_apply_r6_and_rn |
| 167 | b .data_unknown @ E: MUL? | 167 | b .data_unknown @ E: MUL? |
| 168 | nop | 168 | nop |
| 169 | b .data_unknown @ F: MUL? | 169 | b .data_unknown @ F: MUL? |
| 170 | 170 | ||
| 171 | /* | 171 | /* |
| 172 | * Function: arm6_7_proc_init (void) | 172 | * Function: arm6_7_proc_init (void) |
| 173 | * : arm6_7_proc_fin (void) | 173 | * : arm6_7_proc_fin (void) |
| 174 | * | 174 | * |
| 175 | * Notes : This processor does not require these | 175 | * Notes : This processor does not require these |
| 176 | */ | 176 | */ |
| 177 | ENTRY(cpu_arm6_proc_init) | 177 | ENTRY(cpu_arm6_proc_init) |
| 178 | ENTRY(cpu_arm7_proc_init) | 178 | ENTRY(cpu_arm7_proc_init) |
| 179 | mov pc, lr | 179 | mov pc, lr |
| 180 | 180 | ||
| 181 | ENTRY(cpu_arm6_proc_fin) | 181 | ENTRY(cpu_arm6_proc_fin) |
| 182 | ENTRY(cpu_arm7_proc_fin) | 182 | ENTRY(cpu_arm7_proc_fin) |
| 183 | mov r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE | 183 | mov r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE |
| 184 | msr cpsr_c, r0 | 184 | msr cpsr_c, r0 |
| 185 | mov r0, #0x31 @ ....S..DP...M | 185 | mov r0, #0x31 @ ....S..DP...M |
| 186 | mcr p15, 0, r0, c1, c0, 0 @ disable caches | 186 | mcr p15, 0, r0, c1, c0, 0 @ disable caches |
| 187 | mov pc, lr | 187 | mov pc, lr |
| 188 | 188 | ||
| 189 | ENTRY(cpu_arm6_do_idle) | 189 | ENTRY(cpu_arm6_do_idle) |
| 190 | ENTRY(cpu_arm7_do_idle) | 190 | ENTRY(cpu_arm7_do_idle) |
| 191 | mov pc, lr | 191 | mov pc, lr |
| 192 | 192 | ||
| 193 | /* | 193 | /* |
| 194 | * Function: arm6_7_switch_mm(unsigned long pgd_phys) | 194 | * Function: arm6_7_switch_mm(unsigned long pgd_phys) |
| 195 | * Params : pgd_phys Physical address of page table | 195 | * Params : pgd_phys Physical address of page table |
| 196 | * Purpose : Perform a task switch, saving the old processes state, and restoring | 196 | * Purpose : Perform a task switch, saving the old processes state, and restoring |
| 197 | * the new. | 197 | * the new. |
| 198 | */ | 198 | */ |
| 199 | ENTRY(cpu_arm6_switch_mm) | 199 | ENTRY(cpu_arm6_switch_mm) |
| 200 | ENTRY(cpu_arm7_switch_mm) | 200 | ENTRY(cpu_arm7_switch_mm) |
| 201 | mov r1, #0 | 201 | mov r1, #0 |
| 202 | mcr p15, 0, r1, c7, c0, 0 @ flush cache | 202 | mcr p15, 0, r1, c7, c0, 0 @ flush cache |
| 203 | mcr p15, 0, r0, c2, c0, 0 @ update page table ptr | 203 | mcr p15, 0, r0, c2, c0, 0 @ update page table ptr |
| 204 | mcr p15, 0, r1, c5, c0, 0 @ flush TLBs | 204 | mcr p15, 0, r1, c5, c0, 0 @ flush TLBs |
| 205 | mov pc, lr | 205 | mov pc, lr |
| 206 | 206 | ||
| 207 | /* | 207 | /* |
| 208 | * Function: arm6_7_set_pte(pte_t *ptep, pte_t pte) | 208 | * Function: arm6_7_set_pte(pte_t *ptep, pte_t pte) |
| 209 | * Params : r0 = Address to set | 209 | * Params : r0 = Address to set |
| 210 | * : r1 = value to set | 210 | * : r1 = value to set |
| 211 | * Purpose : Set a PTE and flush it out of any WB cache | 211 | * Purpose : Set a PTE and flush it out of any WB cache |
| 212 | */ | 212 | */ |
| 213 | .align 5 | 213 | .align 5 |
| 214 | ENTRY(cpu_arm6_set_pte) | 214 | ENTRY(cpu_arm6_set_pte) |
| 215 | ENTRY(cpu_arm7_set_pte) | 215 | ENTRY(cpu_arm7_set_pte) |
| 216 | str r1, [r0], #-2048 @ linux version | 216 | str r1, [r0], #-2048 @ linux version |
| 217 | 217 | ||
| 218 | eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY | 218 | eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY |
| 219 | 219 | ||
| 220 | bic r2, r1, #PTE_SMALL_AP_MASK | 220 | bic r2, r1, #PTE_SMALL_AP_MASK |
| 221 | bic r2, r2, #PTE_TYPE_MASK | 221 | bic r2, r2, #PTE_TYPE_MASK |
| 222 | orr r2, r2, #PTE_TYPE_SMALL | 222 | orr r2, r2, #PTE_TYPE_SMALL |
| 223 | 223 | ||
| 224 | tst r1, #L_PTE_USER @ User? | 224 | tst r1, #L_PTE_USER @ User? |
| 225 | orrne r2, r2, #PTE_SMALL_AP_URO_SRW | 225 | orrne r2, r2, #PTE_SMALL_AP_URO_SRW |
| 226 | 226 | ||
| 227 | tst r1, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty? | 227 | tst r1, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty? |
| 228 | orreq r2, r2, #PTE_SMALL_AP_UNO_SRW | 228 | orreq r2, r2, #PTE_SMALL_AP_UNO_SRW |
| 229 | 229 | ||
| 230 | tst r1, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young | 230 | tst r1, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young |
| 231 | movne r2, #0 | 231 | movne r2, #0 |
| 232 | 232 | ||
| 233 | str r2, [r0] @ hardware version | 233 | str r2, [r0] @ hardware version |
| 234 | mov pc, lr | 234 | mov pc, lr |
| 235 | 235 | ||
| 236 | /* | 236 | /* |
| 237 | * Function: _arm6_7_reset | 237 | * Function: _arm6_7_reset |
| 238 | * Params : r0 = address to jump to | 238 | * Params : r0 = address to jump to |
| 239 | * Notes : This sets up everything for a reset | 239 | * Notes : This sets up everything for a reset |
| 240 | */ | 240 | */ |
| 241 | ENTRY(cpu_arm6_reset) | 241 | ENTRY(cpu_arm6_reset) |
| 242 | ENTRY(cpu_arm7_reset) | 242 | ENTRY(cpu_arm7_reset) |
| 243 | mov r1, #0 | 243 | mov r1, #0 |
| 244 | mcr p15, 0, r1, c7, c0, 0 @ flush cache | 244 | mcr p15, 0, r1, c7, c0, 0 @ flush cache |
| 245 | mcr p15, 0, r1, c5, c0, 0 @ flush TLB | 245 | mcr p15, 0, r1, c5, c0, 0 @ flush TLB |
| 246 | mov r1, #0x30 | 246 | mov r1, #0x30 |
| 247 | mcr p15, 0, r1, c1, c0, 0 @ turn off MMU etc | 247 | mcr p15, 0, r1, c1, c0, 0 @ turn off MMU etc |
| 248 | mov pc, r0 | 248 | mov pc, r0 |
| 249 | 249 | ||
| 250 | __INIT | 250 | __INIT |
| 251 | 251 | ||
| 252 | .type __arm6_setup, #function | 252 | .type __arm6_setup, #function |
| 253 | __arm6_setup: mov r0, #0 | 253 | __arm6_setup: mov r0, #0 |
| 254 | mcr p15, 0, r0, c7, c0 @ flush caches on v3 | 254 | mcr p15, 0, r0, c7, c0 @ flush caches on v3 |
| 255 | mcr p15, 0, r0, c5, c0 @ flush TLBs on v3 | 255 | mcr p15, 0, r0, c5, c0 @ flush TLBs on v3 |
| 256 | mov r0, #0x3d @ . ..RS BLDP WCAM | 256 | mov r0, #0x3d @ . ..RS BLDP WCAM |
| 257 | orr r0, r0, #0x100 @ . ..01 0011 1101 | 257 | orr r0, r0, #0x100 @ . ..01 0011 1101 |
| 258 | mov pc, lr | 258 | mov pc, lr |
| 259 | .size __arm6_setup, . - __arm6_setup | 259 | .size __arm6_setup, . - __arm6_setup |
| 260 | 260 | ||
| 261 | .type __arm7_setup, #function | 261 | .type __arm7_setup, #function |
| 262 | __arm7_setup: mov r0, #0 | 262 | __arm7_setup: mov r0, #0 |
| 263 | mcr p15, 0, r0, c7, c0 @ flush caches on v3 | 263 | mcr p15, 0, r0, c7, c0 @ flush caches on v3 |
| 264 | mcr p15, 0, r0, c5, c0 @ flush TLBs on v3 | 264 | mcr p15, 0, r0, c5, c0 @ flush TLBs on v3 |
| 265 | mcr p15, 0, r0, c3, c0 @ load domain access register | 265 | mcr p15, 0, r0, c3, c0 @ load domain access register |
| 266 | mov r0, #0x7d @ . ..RS BLDP WCAM | 266 | mov r0, #0x7d @ . ..RS BLDP WCAM |
| 267 | orr r0, r0, #0x100 @ . ..01 0111 1101 | 267 | orr r0, r0, #0x100 @ . ..01 0111 1101 |
| 268 | mov pc, lr | 268 | mov pc, lr |
| 269 | .size __arm7_setup, . - __arm7_setup | 269 | .size __arm7_setup, . - __arm7_setup |
| 270 | 270 | ||
| 271 | __INITDATA | 271 | __INITDATA |
| 272 | 272 | ||
| 273 | /* | 273 | /* |
| 274 | * Purpose : Function pointers used to access above functions - all calls | 274 | * Purpose : Function pointers used to access above functions - all calls |
| 275 | * come through these | 275 | * come through these |
| 276 | */ | 276 | */ |
| 277 | .type arm6_processor_functions, #object | 277 | .type arm6_processor_functions, #object |
| 278 | ENTRY(arm6_processor_functions) | 278 | ENTRY(arm6_processor_functions) |
| 279 | .word cpu_arm6_data_abort | 279 | .word cpu_arm6_data_abort |
| 280 | .word cpu_arm6_proc_init | 280 | .word cpu_arm6_proc_init |
| 281 | .word cpu_arm6_proc_fin | 281 | .word cpu_arm6_proc_fin |
| 282 | .word cpu_arm6_reset | 282 | .word cpu_arm6_reset |
| 283 | .word cpu_arm6_do_idle | 283 | .word cpu_arm6_do_idle |
| 284 | .word cpu_arm6_dcache_clean_area | 284 | .word cpu_arm6_dcache_clean_area |
| 285 | .word cpu_arm6_switch_mm | 285 | .word cpu_arm6_switch_mm |
| 286 | .word cpu_arm6_set_pte | 286 | .word cpu_arm6_set_pte |
| 287 | .size arm6_processor_functions, . - arm6_processor_functions | 287 | .size arm6_processor_functions, . - arm6_processor_functions |
| 288 | 288 | ||
| 289 | /* | 289 | /* |
| 290 | * Purpose : Function pointers used to access above functions - all calls | 290 | * Purpose : Function pointers used to access above functions - all calls |
| 291 | * come through these | 291 | * come through these |
| 292 | */ | 292 | */ |
| 293 | .type arm7_processor_functions, #object | 293 | .type arm7_processor_functions, #object |
| 294 | ENTRY(arm7_processor_functions) | 294 | ENTRY(arm7_processor_functions) |
| 295 | .word cpu_arm7_data_abort | 295 | .word cpu_arm7_data_abort |
| 296 | .word cpu_arm7_proc_init | 296 | .word cpu_arm7_proc_init |
| 297 | .word cpu_arm7_proc_fin | 297 | .word cpu_arm7_proc_fin |
| 298 | .word cpu_arm7_reset | 298 | .word cpu_arm7_reset |
| 299 | .word cpu_arm7_do_idle | 299 | .word cpu_arm7_do_idle |
| 300 | .word cpu_arm7_dcache_clean_area | 300 | .word cpu_arm7_dcache_clean_area |
| 301 | .word cpu_arm7_switch_mm | 301 | .word cpu_arm7_switch_mm |
| 302 | .word cpu_arm7_set_pte | 302 | .word cpu_arm7_set_pte |
| 303 | .size arm7_processor_functions, . - arm7_processor_functions | 303 | .size arm7_processor_functions, . - arm7_processor_functions |
| 304 | 304 | ||
| 305 | .section ".rodata" | 305 | .section ".rodata" |
| 306 | 306 | ||
| 307 | .type cpu_arch_name, #object | 307 | .type cpu_arch_name, #object |
| 308 | cpu_arch_name: .asciz "armv3" | 308 | cpu_arch_name: .asciz "armv3" |
| 309 | .size cpu_arch_name, . - cpu_arch_name | 309 | .size cpu_arch_name, . - cpu_arch_name |
| 310 | 310 | ||
| 311 | .type cpu_elf_name, #object | 311 | .type cpu_elf_name, #object |
| 312 | cpu_elf_name: .asciz "v3" | 312 | cpu_elf_name: .asciz "v3" |
| 313 | .size cpu_elf_name, . - cpu_elf_name | 313 | .size cpu_elf_name, . - cpu_elf_name |
| 314 | 314 | ||
| 315 | .type cpu_arm6_name, #object | 315 | .type cpu_arm6_name, #object |
| 316 | cpu_arm6_name: .asciz "ARM6" | 316 | cpu_arm6_name: .asciz "ARM6" |
| 317 | .size cpu_arm6_name, . - cpu_arm6_name | 317 | .size cpu_arm6_name, . - cpu_arm6_name |
| 318 | 318 | ||
| 319 | .type cpu_arm610_name, #object | 319 | .type cpu_arm610_name, #object |
| 320 | cpu_arm610_name: | 320 | cpu_arm610_name: |
| 321 | .asciz "ARM610" | 321 | .asciz "ARM610" |
| 322 | .size cpu_arm610_name, . - cpu_arm610_name | 322 | .size cpu_arm610_name, . - cpu_arm610_name |
| 323 | 323 | ||
| 324 | .type cpu_arm7_name, #object | 324 | .type cpu_arm7_name, #object |
| 325 | cpu_arm7_name: .asciz "ARM7" | 325 | cpu_arm7_name: .asciz "ARM7" |
| 326 | .size cpu_arm7_name, . - cpu_arm7_name | 326 | .size cpu_arm7_name, . - cpu_arm7_name |
| 327 | 327 | ||
| 328 | .type cpu_arm710_name, #object | 328 | .type cpu_arm710_name, #object |
| 329 | cpu_arm710_name: | 329 | cpu_arm710_name: |
| 330 | .asciz "ARM710" | 330 | .asciz "ARM710" |
| 331 | .size cpu_arm710_name, . - cpu_arm710_name | 331 | .size cpu_arm710_name, . - cpu_arm710_name |
| 332 | 332 | ||
| 333 | .align | 333 | .align |
| 334 | 334 | ||
| 335 | .section ".proc.info", #alloc, #execinstr | 335 | .section ".proc.info", #alloc, #execinstr |
| 336 | 336 | ||
| 337 | .type __arm6_proc_info, #object | 337 | .type __arm6_proc_info, #object |
| 338 | __arm6_proc_info: | 338 | __arm6_proc_info: |
| 339 | .long 0x41560600 | 339 | .long 0x41560600 |
| 340 | .long 0xfffffff0 | 340 | .long 0xfffffff0 |
| 341 | .long 0x00000c1e | 341 | .long 0x00000c1e |
| 342 | b __arm6_setup | 342 | b __arm6_setup |
| 343 | .long cpu_arch_name | 343 | .long cpu_arch_name |
| 344 | .long cpu_elf_name | 344 | .long cpu_elf_name |
| 345 | .long HWCAP_SWP | HWCAP_26BIT | 345 | .long HWCAP_SWP | HWCAP_26BIT |
| 346 | .long cpu_arm6_name | 346 | .long cpu_arm6_name |
| 347 | .long arm6_processor_functions | 347 | .long arm6_processor_functions |
| 348 | .long v3_tlb_fns | 348 | .long v3_tlb_fns |
| 349 | .long v3_user_fns | 349 | .long v3_user_fns |
| 350 | .long v3_cache_fns | 350 | .long v3_cache_fns |
| 351 | .size __arm6_proc_info, . - __arm6_proc_info | 351 | .size __arm6_proc_info, . - __arm6_proc_info |
| 352 | 352 | ||
| 353 | .type __arm610_proc_info, #object | 353 | .type __arm610_proc_info, #object |
| 354 | __arm610_proc_info: | 354 | __arm610_proc_info: |
| 355 | .long 0x41560610 | 355 | .long 0x41560610 |
| 356 | .long 0xfffffff0 | 356 | .long 0xfffffff0 |
| 357 | .long 0x00000c1e | 357 | .long 0x00000c1e |
| 358 | b __arm6_setup | 358 | b __arm6_setup |
| 359 | .long cpu_arch_name | 359 | .long cpu_arch_name |
| 360 | .long cpu_elf_name | 360 | .long cpu_elf_name |
| 361 | .long HWCAP_SWP | HWCAP_26BIT | 361 | .long HWCAP_SWP | HWCAP_26BIT |
| 362 | .long cpu_arm610_name | 362 | .long cpu_arm610_name |
| 363 | .long arm6_processor_functions | 363 | .long arm6_processor_functions |
| 364 | .long v3_tlb_fns | 364 | .long v3_tlb_fns |
| 365 | .long v3_user_fns | 365 | .long v3_user_fns |
| 366 | .long v3_cache_fns | 366 | .long v3_cache_fns |
| 367 | .size __arm610_proc_info, . - __arm610_proc_info | 367 | .size __arm610_proc_info, . - __arm610_proc_info |
| 368 | 368 | ||
| 369 | .type __arm7_proc_info, #object | 369 | .type __arm7_proc_info, #object |
| 370 | __arm7_proc_info: | 370 | __arm7_proc_info: |
| 371 | .long 0x41007000 | 371 | .long 0x41007000 |
| 372 | .long 0xffffff00 | 372 | .long 0xffffff00 |
| 373 | .long 0x00000c1e | 373 | .long 0x00000c1e |
| 374 | b __arm7_setup | 374 | b __arm7_setup |
| 375 | .long cpu_arch_name | 375 | .long cpu_arch_name |
| 376 | .long cpu_elf_name | 376 | .long cpu_elf_name |
| 377 | .long HWCAP_SWP | HWCAP_26BIT | 377 | .long HWCAP_SWP | HWCAP_26BIT |
| 378 | .long cpu_arm7_name | 378 | .long cpu_arm7_name |
| 379 | .long arm7_processor_functions | 379 | .long arm7_processor_functions |
| 380 | .long v3_tlb_fns | 380 | .long v3_tlb_fns |
| 381 | .long v3_user_fns | 381 | .long v3_user_fns |
| 382 | .long v3_cache_fns | 382 | .long v3_cache_fns |
| 383 | .size __arm7_proc_info, . - __arm7_proc_info | 383 | .size __arm7_proc_info, . - __arm7_proc_info |
| 384 | 384 | ||
| 385 | .type __arm710_proc_info, #object | 385 | .type __arm710_proc_info, #object |
| 386 | __arm710_proc_info: | 386 | __arm710_proc_info: |
| 387 | .long 0x41007100 | 387 | .long 0x41007100 |
| 388 | .long 0xfff8ff00 | 388 | .long 0xfff8ff00 |
| 389 | .long PMD_TYPE_SECT | \ | 389 | .long PMD_TYPE_SECT | \ |
| 390 | PMD_SECT_BUFFERABLE | \ | 390 | PMD_SECT_BUFFERABLE | \ |
| 391 | PMD_SECT_CACHEABLE | \ | 391 | PMD_SECT_CACHEABLE | \ |
| 392 | PMD_BIT4 | \ | 392 | PMD_BIT4 | \ |
| 393 | PMD_SECT_AP_WRITE | \ | 393 | PMD_SECT_AP_WRITE | \ |
| 394 | PMD_SECT_AP_READ | 394 | PMD_SECT_AP_READ |
| 395 | b __arm7_setup | 395 | b __arm7_setup |
| 396 | .long cpu_arch_name | 396 | .long cpu_arch_name |
| 397 | .long cpu_elf_name | 397 | .long cpu_elf_name |
| 398 | .long HWCAP_SWP | HWCAP_26BIT | 398 | .long HWCAP_SWP | HWCAP_26BIT |
| 399 | .long cpu_arm710_name | 399 | .long cpu_arm710_name |
| 400 | .long arm7_processor_functions | 400 | .long arm7_processor_functions |
| 401 | .long v3_tlb_fns | 401 | .long v3_tlb_fns |
| 402 | .long v3_user_fns | 402 | .long v3_user_fns |
| 403 | .long v3_cache_fns | 403 | .long v3_cache_fns |
| 404 | .size __arm710_proc_info, . - __arm710_proc_info | 404 | .size __arm710_proc_info, . - __arm710_proc_info |
| 405 | 405 |
arch/arm/plat-omap/gpio.c
| 1 | /* | 1 | /* |
| 2 | * linux/arch/arm/plat-omap/gpio.c | 2 | * linux/arch/arm/plat-omap/gpio.c |
| 3 | * | 3 | * |
| 4 | * Support functions for OMAP GPIO | 4 | * Support functions for OMAP GPIO |
| 5 | * | 5 | * |
| 6 | * Copyright (C) 2003 Nokia Corporation | 6 | * Copyright (C) 2003 Nokia Corporation |
| 7 | * Written by Juha Yrjรถlรค <juha.yrjola@nokia.com> | 7 | * Written by Juha Yrjรถlรค <juha.yrjola@nokia.com> |
| 8 | * | 8 | * |
| 9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
| 10 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
| 11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
| 12 | */ | 12 | */ |
| 13 | 13 | ||
| 14 | #include <linux/config.h> | 14 | #include <linux/config.h> |
| 15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
| 16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 17 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
| 18 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
| 19 | #include <linux/ptrace.h> | 19 | #include <linux/ptrace.h> |
| 20 | 20 | ||
| 21 | #include <asm/hardware.h> | 21 | #include <asm/hardware.h> |
| 22 | #include <asm/irq.h> | 22 | #include <asm/irq.h> |
| 23 | #include <asm/arch/irqs.h> | 23 | #include <asm/arch/irqs.h> |
| 24 | #include <asm/arch/gpio.h> | 24 | #include <asm/arch/gpio.h> |
| 25 | #include <asm/mach/irq.h> | 25 | #include <asm/mach/irq.h> |
| 26 | 26 | ||
| 27 | #include <asm/io.h> | 27 | #include <asm/io.h> |
| 28 | 28 | ||
| 29 | /* | 29 | /* |
| 30 | * OMAP1510 GPIO registers | 30 | * OMAP1510 GPIO registers |
| 31 | */ | 31 | */ |
| 32 | #define OMAP1510_GPIO_BASE 0xfffce000 | 32 | #define OMAP1510_GPIO_BASE 0xfffce000 |
| 33 | #define OMAP1510_GPIO_DATA_INPUT 0x00 | 33 | #define OMAP1510_GPIO_DATA_INPUT 0x00 |
| 34 | #define OMAP1510_GPIO_DATA_OUTPUT 0x04 | 34 | #define OMAP1510_GPIO_DATA_OUTPUT 0x04 |
| 35 | #define OMAP1510_GPIO_DIR_CONTROL 0x08 | 35 | #define OMAP1510_GPIO_DIR_CONTROL 0x08 |
| 36 | #define OMAP1510_GPIO_INT_CONTROL 0x0c | 36 | #define OMAP1510_GPIO_INT_CONTROL 0x0c |
| 37 | #define OMAP1510_GPIO_INT_MASK 0x10 | 37 | #define OMAP1510_GPIO_INT_MASK 0x10 |
| 38 | #define OMAP1510_GPIO_INT_STATUS 0x14 | 38 | #define OMAP1510_GPIO_INT_STATUS 0x14 |
| 39 | #define OMAP1510_GPIO_PIN_CONTROL 0x18 | 39 | #define OMAP1510_GPIO_PIN_CONTROL 0x18 |
| 40 | 40 | ||
| 41 | #define OMAP1510_IH_GPIO_BASE 64 | 41 | #define OMAP1510_IH_GPIO_BASE 64 |
| 42 | 42 | ||
| 43 | /* | 43 | /* |
| 44 | * OMAP1610 specific GPIO registers | 44 | * OMAP1610 specific GPIO registers |
| 45 | */ | 45 | */ |
| 46 | #define OMAP1610_GPIO1_BASE 0xfffbe400 | 46 | #define OMAP1610_GPIO1_BASE 0xfffbe400 |
| 47 | #define OMAP1610_GPIO2_BASE 0xfffbec00 | 47 | #define OMAP1610_GPIO2_BASE 0xfffbec00 |
| 48 | #define OMAP1610_GPIO3_BASE 0xfffbb400 | 48 | #define OMAP1610_GPIO3_BASE 0xfffbb400 |
| 49 | #define OMAP1610_GPIO4_BASE 0xfffbbc00 | 49 | #define OMAP1610_GPIO4_BASE 0xfffbbc00 |
| 50 | #define OMAP1610_GPIO_REVISION 0x0000 | 50 | #define OMAP1610_GPIO_REVISION 0x0000 |
| 51 | #define OMAP1610_GPIO_SYSCONFIG 0x0010 | 51 | #define OMAP1610_GPIO_SYSCONFIG 0x0010 |
| 52 | #define OMAP1610_GPIO_SYSSTATUS 0x0014 | 52 | #define OMAP1610_GPIO_SYSSTATUS 0x0014 |
| 53 | #define OMAP1610_GPIO_IRQSTATUS1 0x0018 | 53 | #define OMAP1610_GPIO_IRQSTATUS1 0x0018 |
| 54 | #define OMAP1610_GPIO_IRQENABLE1 0x001c | 54 | #define OMAP1610_GPIO_IRQENABLE1 0x001c |
| 55 | #define OMAP1610_GPIO_DATAIN 0x002c | 55 | #define OMAP1610_GPIO_DATAIN 0x002c |
| 56 | #define OMAP1610_GPIO_DATAOUT 0x0030 | 56 | #define OMAP1610_GPIO_DATAOUT 0x0030 |
| 57 | #define OMAP1610_GPIO_DIRECTION 0x0034 | 57 | #define OMAP1610_GPIO_DIRECTION 0x0034 |
| 58 | #define OMAP1610_GPIO_EDGE_CTRL1 0x0038 | 58 | #define OMAP1610_GPIO_EDGE_CTRL1 0x0038 |
| 59 | #define OMAP1610_GPIO_EDGE_CTRL2 0x003c | 59 | #define OMAP1610_GPIO_EDGE_CTRL2 0x003c |
| 60 | #define OMAP1610_GPIO_CLEAR_IRQENABLE1 0x009c | 60 | #define OMAP1610_GPIO_CLEAR_IRQENABLE1 0x009c |
| 61 | #define OMAP1610_GPIO_CLEAR_DATAOUT 0x00b0 | 61 | #define OMAP1610_GPIO_CLEAR_DATAOUT 0x00b0 |
| 62 | #define OMAP1610_GPIO_SET_IRQENABLE1 0x00dc | 62 | #define OMAP1610_GPIO_SET_IRQENABLE1 0x00dc |
| 63 | #define OMAP1610_GPIO_SET_DATAOUT 0x00f0 | 63 | #define OMAP1610_GPIO_SET_DATAOUT 0x00f0 |
| 64 | 64 | ||
| 65 | /* | 65 | /* |
| 66 | * OMAP730 specific GPIO registers | 66 | * OMAP730 specific GPIO registers |
| 67 | */ | 67 | */ |
| 68 | #define OMAP730_GPIO1_BASE 0xfffbc000 | 68 | #define OMAP730_GPIO1_BASE 0xfffbc000 |
| 69 | #define OMAP730_GPIO2_BASE 0xfffbc800 | 69 | #define OMAP730_GPIO2_BASE 0xfffbc800 |
| 70 | #define OMAP730_GPIO3_BASE 0xfffbd000 | 70 | #define OMAP730_GPIO3_BASE 0xfffbd000 |
| 71 | #define OMAP730_GPIO4_BASE 0xfffbd800 | 71 | #define OMAP730_GPIO4_BASE 0xfffbd800 |
| 72 | #define OMAP730_GPIO5_BASE 0xfffbe000 | 72 | #define OMAP730_GPIO5_BASE 0xfffbe000 |
| 73 | #define OMAP730_GPIO6_BASE 0xfffbe800 | 73 | #define OMAP730_GPIO6_BASE 0xfffbe800 |
| 74 | #define OMAP730_GPIO_DATA_INPUT 0x00 | 74 | #define OMAP730_GPIO_DATA_INPUT 0x00 |
| 75 | #define OMAP730_GPIO_DATA_OUTPUT 0x04 | 75 | #define OMAP730_GPIO_DATA_OUTPUT 0x04 |
| 76 | #define OMAP730_GPIO_DIR_CONTROL 0x08 | 76 | #define OMAP730_GPIO_DIR_CONTROL 0x08 |
| 77 | #define OMAP730_GPIO_INT_CONTROL 0x0c | 77 | #define OMAP730_GPIO_INT_CONTROL 0x0c |
| 78 | #define OMAP730_GPIO_INT_MASK 0x10 | 78 | #define OMAP730_GPIO_INT_MASK 0x10 |
| 79 | #define OMAP730_GPIO_INT_STATUS 0x14 | 79 | #define OMAP730_GPIO_INT_STATUS 0x14 |
| 80 | 80 | ||
| 81 | #define OMAP_MPUIO_MASK (~OMAP_MAX_GPIO_LINES & 0xff) | 81 | #define OMAP_MPUIO_MASK (~OMAP_MAX_GPIO_LINES & 0xff) |
| 82 | 82 | ||
| 83 | struct gpio_bank { | 83 | struct gpio_bank { |
| 84 | u32 base; | 84 | u32 base; |
| 85 | u16 irq; | 85 | u16 irq; |
| 86 | u16 virtual_irq_start; | 86 | u16 virtual_irq_start; |
| 87 | u8 method; | 87 | u8 method; |
| 88 | u32 reserved_map; | 88 | u32 reserved_map; |
| 89 | spinlock_t lock; | 89 | spinlock_t lock; |
| 90 | }; | 90 | }; |
| 91 | 91 | ||
| 92 | #define METHOD_MPUIO 0 | 92 | #define METHOD_MPUIO 0 |
| 93 | #define METHOD_GPIO_1510 1 | 93 | #define METHOD_GPIO_1510 1 |
| 94 | #define METHOD_GPIO_1610 2 | 94 | #define METHOD_GPIO_1610 2 |
| 95 | #define METHOD_GPIO_730 3 | 95 | #define METHOD_GPIO_730 3 |
| 96 | 96 | ||
| 97 | #if defined(CONFIG_ARCH_OMAP16XX) | 97 | #if defined(CONFIG_ARCH_OMAP16XX) |
| 98 | static struct gpio_bank gpio_bank_1610[5] = { | 98 | static struct gpio_bank gpio_bank_1610[5] = { |
| 99 | { OMAP_MPUIO_BASE, INT_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO}, | 99 | { OMAP_MPUIO_BASE, INT_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO}, |
| 100 | { OMAP1610_GPIO1_BASE, INT_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_1610 }, | 100 | { OMAP1610_GPIO1_BASE, INT_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_1610 }, |
| 101 | { OMAP1610_GPIO2_BASE, INT_1610_GPIO_BANK2, IH_GPIO_BASE + 16, METHOD_GPIO_1610 }, | 101 | { OMAP1610_GPIO2_BASE, INT_1610_GPIO_BANK2, IH_GPIO_BASE + 16, METHOD_GPIO_1610 }, |
| 102 | { OMAP1610_GPIO3_BASE, INT_1610_GPIO_BANK3, IH_GPIO_BASE + 32, METHOD_GPIO_1610 }, | 102 | { OMAP1610_GPIO3_BASE, INT_1610_GPIO_BANK3, IH_GPIO_BASE + 32, METHOD_GPIO_1610 }, |
| 103 | { OMAP1610_GPIO4_BASE, INT_1610_GPIO_BANK4, IH_GPIO_BASE + 48, METHOD_GPIO_1610 }, | 103 | { OMAP1610_GPIO4_BASE, INT_1610_GPIO_BANK4, IH_GPIO_BASE + 48, METHOD_GPIO_1610 }, |
| 104 | }; | 104 | }; |
| 105 | #endif | 105 | #endif |
| 106 | 106 | ||
| 107 | #ifdef CONFIG_ARCH_OMAP1510 | 107 | #ifdef CONFIG_ARCH_OMAP1510 |
| 108 | static struct gpio_bank gpio_bank_1510[2] = { | 108 | static struct gpio_bank gpio_bank_1510[2] = { |
| 109 | { OMAP_MPUIO_BASE, INT_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO }, | 109 | { OMAP_MPUIO_BASE, INT_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO }, |
| 110 | { OMAP1510_GPIO_BASE, INT_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_1510 } | 110 | { OMAP1510_GPIO_BASE, INT_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_1510 } |
| 111 | }; | 111 | }; |
| 112 | #endif | 112 | #endif |
| 113 | 113 | ||
| 114 | #ifdef CONFIG_ARCH_OMAP730 | 114 | #ifdef CONFIG_ARCH_OMAP730 |
| 115 | static struct gpio_bank gpio_bank_730[7] = { | 115 | static struct gpio_bank gpio_bank_730[7] = { |
| 116 | { OMAP_MPUIO_BASE, INT_730_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO }, | 116 | { OMAP_MPUIO_BASE, INT_730_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO }, |
| 117 | { OMAP730_GPIO1_BASE, INT_730_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_730 }, | 117 | { OMAP730_GPIO1_BASE, INT_730_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_730 }, |
| 118 | { OMAP730_GPIO2_BASE, INT_730_GPIO_BANK2, IH_GPIO_BASE + 32, METHOD_GPIO_730 }, | 118 | { OMAP730_GPIO2_BASE, INT_730_GPIO_BANK2, IH_GPIO_BASE + 32, METHOD_GPIO_730 }, |
| 119 | { OMAP730_GPIO3_BASE, INT_730_GPIO_BANK3, IH_GPIO_BASE + 64, METHOD_GPIO_730 }, | 119 | { OMAP730_GPIO3_BASE, INT_730_GPIO_BANK3, IH_GPIO_BASE + 64, METHOD_GPIO_730 }, |
| 120 | { OMAP730_GPIO4_BASE, INT_730_GPIO_BANK4, IH_GPIO_BASE + 96, METHOD_GPIO_730 }, | 120 | { OMAP730_GPIO4_BASE, INT_730_GPIO_BANK4, IH_GPIO_BASE + 96, METHOD_GPIO_730 }, |
| 121 | { OMAP730_GPIO5_BASE, INT_730_GPIO_BANK5, IH_GPIO_BASE + 128, METHOD_GPIO_730 }, | 121 | { OMAP730_GPIO5_BASE, INT_730_GPIO_BANK5, IH_GPIO_BASE + 128, METHOD_GPIO_730 }, |
| 122 | { OMAP730_GPIO6_BASE, INT_730_GPIO_BANK6, IH_GPIO_BASE + 160, METHOD_GPIO_730 }, | 122 | { OMAP730_GPIO6_BASE, INT_730_GPIO_BANK6, IH_GPIO_BASE + 160, METHOD_GPIO_730 }, |
| 123 | }; | 123 | }; |
| 124 | #endif | 124 | #endif |
| 125 | 125 | ||
| 126 | static struct gpio_bank *gpio_bank; | 126 | static struct gpio_bank *gpio_bank; |
| 127 | static int gpio_bank_count; | 127 | static int gpio_bank_count; |
| 128 | 128 | ||
| 129 | static inline struct gpio_bank *get_gpio_bank(int gpio) | 129 | static inline struct gpio_bank *get_gpio_bank(int gpio) |
| 130 | { | 130 | { |
| 131 | #ifdef CONFIG_ARCH_OMAP1510 | 131 | #ifdef CONFIG_ARCH_OMAP1510 |
| 132 | if (cpu_is_omap1510()) { | 132 | if (cpu_is_omap1510()) { |
| 133 | if (OMAP_GPIO_IS_MPUIO(gpio)) | 133 | if (OMAP_GPIO_IS_MPUIO(gpio)) |
| 134 | return &gpio_bank[0]; | 134 | return &gpio_bank[0]; |
| 135 | return &gpio_bank[1]; | 135 | return &gpio_bank[1]; |
| 136 | } | 136 | } |
| 137 | #endif | 137 | #endif |
| 138 | #if defined(CONFIG_ARCH_OMAP16XX) | 138 | #if defined(CONFIG_ARCH_OMAP16XX) |
| 139 | if (cpu_is_omap16xx()) { | 139 | if (cpu_is_omap16xx()) { |
| 140 | if (OMAP_GPIO_IS_MPUIO(gpio)) | 140 | if (OMAP_GPIO_IS_MPUIO(gpio)) |
| 141 | return &gpio_bank[0]; | 141 | return &gpio_bank[0]; |
| 142 | return &gpio_bank[1 + (gpio >> 4)]; | 142 | return &gpio_bank[1 + (gpio >> 4)]; |
| 143 | } | 143 | } |
| 144 | #endif | 144 | #endif |
| 145 | #ifdef CONFIG_ARCH_OMAP730 | 145 | #ifdef CONFIG_ARCH_OMAP730 |
| 146 | if (cpu_is_omap730()) { | 146 | if (cpu_is_omap730()) { |
| 147 | if (OMAP_GPIO_IS_MPUIO(gpio)) | 147 | if (OMAP_GPIO_IS_MPUIO(gpio)) |
| 148 | return &gpio_bank[0]; | 148 | return &gpio_bank[0]; |
| 149 | return &gpio_bank[1 + (gpio >> 5)]; | 149 | return &gpio_bank[1 + (gpio >> 5)]; |
| 150 | } | 150 | } |
| 151 | #endif | 151 | #endif |
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | static inline int get_gpio_index(int gpio) | 154 | static inline int get_gpio_index(int gpio) |
| 155 | { | 155 | { |
| 156 | if (cpu_is_omap730()) | 156 | if (cpu_is_omap730()) |
| 157 | return gpio & 0x1f; | 157 | return gpio & 0x1f; |
| 158 | else | 158 | else |
| 159 | return gpio & 0x0f; | 159 | return gpio & 0x0f; |
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | static inline int gpio_valid(int gpio) | 162 | static inline int gpio_valid(int gpio) |
| 163 | { | 163 | { |
| 164 | if (gpio < 0) | 164 | if (gpio < 0) |
| 165 | return -1; | 165 | return -1; |
| 166 | if (OMAP_GPIO_IS_MPUIO(gpio)) { | 166 | if (OMAP_GPIO_IS_MPUIO(gpio)) { |
| 167 | if ((gpio & OMAP_MPUIO_MASK) > 16) | 167 | if ((gpio & OMAP_MPUIO_MASK) > 16) |
| 168 | return -1; | 168 | return -1; |
| 169 | return 0; | 169 | return 0; |
| 170 | } | 170 | } |
| 171 | #ifdef CONFIG_ARCH_OMAP1510 | 171 | #ifdef CONFIG_ARCH_OMAP1510 |
| 172 | if (cpu_is_omap1510() && gpio < 16) | 172 | if (cpu_is_omap1510() && gpio < 16) |
| 173 | return 0; | 173 | return 0; |
| 174 | #endif | 174 | #endif |
| 175 | #if defined(CONFIG_ARCH_OMAP16XX) | 175 | #if defined(CONFIG_ARCH_OMAP16XX) |
| 176 | if ((cpu_is_omap16xx()) && gpio < 64) | 176 | if ((cpu_is_omap16xx()) && gpio < 64) |
| 177 | return 0; | 177 | return 0; |
| 178 | #endif | 178 | #endif |
| 179 | #ifdef CONFIG_ARCH_OMAP730 | 179 | #ifdef CONFIG_ARCH_OMAP730 |
| 180 | if (cpu_is_omap730() && gpio < 192) | 180 | if (cpu_is_omap730() && gpio < 192) |
| 181 | return 0; | 181 | return 0; |
| 182 | #endif | 182 | #endif |
| 183 | return -1; | 183 | return -1; |
| 184 | } | 184 | } |
| 185 | 185 | ||
| 186 | static int check_gpio(int gpio) | 186 | static int check_gpio(int gpio) |
| 187 | { | 187 | { |
| 188 | if (unlikely(gpio_valid(gpio)) < 0) { | 188 | if (unlikely(gpio_valid(gpio)) < 0) { |
| 189 | printk(KERN_ERR "omap-gpio: invalid GPIO %d\n", gpio); | 189 | printk(KERN_ERR "omap-gpio: invalid GPIO %d\n", gpio); |
| 190 | dump_stack(); | 190 | dump_stack(); |
| 191 | return -1; | 191 | return -1; |
| 192 | } | 192 | } |
| 193 | return 0; | 193 | return 0; |
| 194 | } | 194 | } |
| 195 | 195 | ||
| 196 | static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) | 196 | static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) |
| 197 | { | 197 | { |
| 198 | u32 reg = bank->base; | 198 | u32 reg = bank->base; |
| 199 | u32 l; | 199 | u32 l; |
| 200 | 200 | ||
| 201 | switch (bank->method) { | 201 | switch (bank->method) { |
| 202 | case METHOD_MPUIO: | 202 | case METHOD_MPUIO: |
| 203 | reg += OMAP_MPUIO_IO_CNTL; | 203 | reg += OMAP_MPUIO_IO_CNTL; |
| 204 | break; | 204 | break; |
| 205 | case METHOD_GPIO_1510: | 205 | case METHOD_GPIO_1510: |
| 206 | reg += OMAP1510_GPIO_DIR_CONTROL; | 206 | reg += OMAP1510_GPIO_DIR_CONTROL; |
| 207 | break; | 207 | break; |
| 208 | case METHOD_GPIO_1610: | 208 | case METHOD_GPIO_1610: |
| 209 | reg += OMAP1610_GPIO_DIRECTION; | 209 | reg += OMAP1610_GPIO_DIRECTION; |
| 210 | break; | 210 | break; |
| 211 | case METHOD_GPIO_730: | 211 | case METHOD_GPIO_730: |
| 212 | reg += OMAP730_GPIO_DIR_CONTROL; | 212 | reg += OMAP730_GPIO_DIR_CONTROL; |
| 213 | break; | 213 | break; |
| 214 | } | 214 | } |
| 215 | l = __raw_readl(reg); | 215 | l = __raw_readl(reg); |
| 216 | if (is_input) | 216 | if (is_input) |
| 217 | l |= 1 << gpio; | 217 | l |= 1 << gpio; |
| 218 | else | 218 | else |
| 219 | l &= ~(1 << gpio); | 219 | l &= ~(1 << gpio); |
| 220 | __raw_writel(l, reg); | 220 | __raw_writel(l, reg); |
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | void omap_set_gpio_direction(int gpio, int is_input) | 223 | void omap_set_gpio_direction(int gpio, int is_input) |
| 224 | { | 224 | { |
| 225 | struct gpio_bank *bank; | 225 | struct gpio_bank *bank; |
| 226 | 226 | ||
| 227 | if (check_gpio(gpio) < 0) | 227 | if (check_gpio(gpio) < 0) |
| 228 | return; | 228 | return; |
| 229 | bank = get_gpio_bank(gpio); | 229 | bank = get_gpio_bank(gpio); |
| 230 | spin_lock(&bank->lock); | 230 | spin_lock(&bank->lock); |
| 231 | _set_gpio_direction(bank, get_gpio_index(gpio), is_input); | 231 | _set_gpio_direction(bank, get_gpio_index(gpio), is_input); |
| 232 | spin_unlock(&bank->lock); | 232 | spin_unlock(&bank->lock); |
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable) | 235 | static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable) |
| 236 | { | 236 | { |
| 237 | u32 reg = bank->base; | 237 | u32 reg = bank->base; |
| 238 | u32 l = 0; | 238 | u32 l = 0; |
| 239 | 239 | ||
| 240 | switch (bank->method) { | 240 | switch (bank->method) { |
| 241 | case METHOD_MPUIO: | 241 | case METHOD_MPUIO: |
| 242 | reg += OMAP_MPUIO_OUTPUT; | 242 | reg += OMAP_MPUIO_OUTPUT; |
| 243 | l = __raw_readl(reg); | 243 | l = __raw_readl(reg); |
| 244 | if (enable) | 244 | if (enable) |
| 245 | l |= 1 << gpio; | 245 | l |= 1 << gpio; |
| 246 | else | 246 | else |
| 247 | l &= ~(1 << gpio); | 247 | l &= ~(1 << gpio); |
| 248 | break; | 248 | break; |
| 249 | case METHOD_GPIO_1510: | 249 | case METHOD_GPIO_1510: |
| 250 | reg += OMAP1510_GPIO_DATA_OUTPUT; | 250 | reg += OMAP1510_GPIO_DATA_OUTPUT; |
| 251 | l = __raw_readl(reg); | 251 | l = __raw_readl(reg); |
| 252 | if (enable) | 252 | if (enable) |
| 253 | l |= 1 << gpio; | 253 | l |= 1 << gpio; |
| 254 | else | 254 | else |
| 255 | l &= ~(1 << gpio); | 255 | l &= ~(1 << gpio); |
| 256 | break; | 256 | break; |
| 257 | case METHOD_GPIO_1610: | 257 | case METHOD_GPIO_1610: |
| 258 | if (enable) | 258 | if (enable) |
| 259 | reg += OMAP1610_GPIO_SET_DATAOUT; | 259 | reg += OMAP1610_GPIO_SET_DATAOUT; |
| 260 | else | 260 | else |
| 261 | reg += OMAP1610_GPIO_CLEAR_DATAOUT; | 261 | reg += OMAP1610_GPIO_CLEAR_DATAOUT; |
| 262 | l = 1 << gpio; | 262 | l = 1 << gpio; |
| 263 | break; | 263 | break; |
| 264 | case METHOD_GPIO_730: | 264 | case METHOD_GPIO_730: |
| 265 | reg += OMAP730_GPIO_DATA_OUTPUT; | 265 | reg += OMAP730_GPIO_DATA_OUTPUT; |
| 266 | l = __raw_readl(reg); | 266 | l = __raw_readl(reg); |
| 267 | if (enable) | 267 | if (enable) |
| 268 | l |= 1 << gpio; | 268 | l |= 1 << gpio; |
| 269 | else | 269 | else |
| 270 | l &= ~(1 << gpio); | 270 | l &= ~(1 << gpio); |
| 271 | break; | 271 | break; |
| 272 | default: | 272 | default: |
| 273 | BUG(); | 273 | BUG(); |
| 274 | return; | 274 | return; |
| 275 | } | 275 | } |
| 276 | __raw_writel(l, reg); | 276 | __raw_writel(l, reg); |
| 277 | } | 277 | } |
| 278 | 278 | ||
| 279 | void omap_set_gpio_dataout(int gpio, int enable) | 279 | void omap_set_gpio_dataout(int gpio, int enable) |
| 280 | { | 280 | { |
| 281 | struct gpio_bank *bank; | 281 | struct gpio_bank *bank; |
| 282 | 282 | ||
| 283 | if (check_gpio(gpio) < 0) | 283 | if (check_gpio(gpio) < 0) |
| 284 | return; | 284 | return; |
| 285 | bank = get_gpio_bank(gpio); | 285 | bank = get_gpio_bank(gpio); |
| 286 | spin_lock(&bank->lock); | 286 | spin_lock(&bank->lock); |
| 287 | _set_gpio_dataout(bank, get_gpio_index(gpio), enable); | 287 | _set_gpio_dataout(bank, get_gpio_index(gpio), enable); |
| 288 | spin_unlock(&bank->lock); | 288 | spin_unlock(&bank->lock); |
| 289 | } | 289 | } |
| 290 | 290 | ||
| 291 | int omap_get_gpio_datain(int gpio) | 291 | int omap_get_gpio_datain(int gpio) |
| 292 | { | 292 | { |
| 293 | struct gpio_bank *bank; | 293 | struct gpio_bank *bank; |
| 294 | u32 reg; | 294 | u32 reg; |
| 295 | 295 | ||
| 296 | if (check_gpio(gpio) < 0) | 296 | if (check_gpio(gpio) < 0) |
| 297 | return -1; | 297 | return -1; |
| 298 | bank = get_gpio_bank(gpio); | 298 | bank = get_gpio_bank(gpio); |
| 299 | reg = bank->base; | 299 | reg = bank->base; |
| 300 | switch (bank->method) { | 300 | switch (bank->method) { |
| 301 | case METHOD_MPUIO: | 301 | case METHOD_MPUIO: |
| 302 | reg += OMAP_MPUIO_INPUT_LATCH; | 302 | reg += OMAP_MPUIO_INPUT_LATCH; |
| 303 | break; | 303 | break; |
| 304 | case METHOD_GPIO_1510: | 304 | case METHOD_GPIO_1510: |
| 305 | reg += OMAP1510_GPIO_DATA_INPUT; | 305 | reg += OMAP1510_GPIO_DATA_INPUT; |
| 306 | break; | 306 | break; |
| 307 | case METHOD_GPIO_1610: | 307 | case METHOD_GPIO_1610: |
| 308 | reg += OMAP1610_GPIO_DATAIN; | 308 | reg += OMAP1610_GPIO_DATAIN; |
| 309 | break; | 309 | break; |
| 310 | case METHOD_GPIO_730: | 310 | case METHOD_GPIO_730: |
| 311 | reg += OMAP730_GPIO_DATA_INPUT; | 311 | reg += OMAP730_GPIO_DATA_INPUT; |
| 312 | break; | 312 | break; |
| 313 | default: | 313 | default: |
| 314 | BUG(); | 314 | BUG(); |
| 315 | return -1; | 315 | return -1; |
| 316 | } | 316 | } |
| 317 | return (__raw_readl(reg) & (1 << get_gpio_index(gpio))) != 0; | 317 | return (__raw_readl(reg) & (1 << get_gpio_index(gpio))) != 0; |
| 318 | } | 318 | } |
| 319 | 319 | ||
| 320 | static void _set_gpio_edge_ctrl(struct gpio_bank *bank, int gpio, int edge) | 320 | static void _set_gpio_edge_ctrl(struct gpio_bank *bank, int gpio, int edge) |
| 321 | { | 321 | { |
| 322 | u32 reg = bank->base; | 322 | u32 reg = bank->base; |
| 323 | u32 l; | 323 | u32 l; |
| 324 | 324 | ||
| 325 | switch (bank->method) { | 325 | switch (bank->method) { |
| 326 | case METHOD_MPUIO: | 326 | case METHOD_MPUIO: |
| 327 | reg += OMAP_MPUIO_GPIO_INT_EDGE; | 327 | reg += OMAP_MPUIO_GPIO_INT_EDGE; |
| 328 | l = __raw_readl(reg); | 328 | l = __raw_readl(reg); |
| 329 | if (edge == OMAP_GPIO_RISING_EDGE) | 329 | if (edge == OMAP_GPIO_RISING_EDGE) |
| 330 | l |= 1 << gpio; | 330 | l |= 1 << gpio; |
| 331 | else | 331 | else |
| 332 | l &= ~(1 << gpio); | 332 | l &= ~(1 << gpio); |
| 333 | __raw_writel(l, reg); | 333 | __raw_writel(l, reg); |
| 334 | break; | 334 | break; |
| 335 | case METHOD_GPIO_1510: | 335 | case METHOD_GPIO_1510: |
| 336 | reg += OMAP1510_GPIO_INT_CONTROL; | 336 | reg += OMAP1510_GPIO_INT_CONTROL; |
| 337 | l = __raw_readl(reg); | 337 | l = __raw_readl(reg); |
| 338 | if (edge == OMAP_GPIO_RISING_EDGE) | 338 | if (edge == OMAP_GPIO_RISING_EDGE) |
| 339 | l |= 1 << gpio; | 339 | l |= 1 << gpio; |
| 340 | else | 340 | else |
| 341 | l &= ~(1 << gpio); | 341 | l &= ~(1 << gpio); |
| 342 | __raw_writel(l, reg); | 342 | __raw_writel(l, reg); |
| 343 | break; | 343 | break; |
| 344 | case METHOD_GPIO_1610: | 344 | case METHOD_GPIO_1610: |
| 345 | edge &= 0x03; | 345 | edge &= 0x03; |
| 346 | if (gpio & 0x08) | 346 | if (gpio & 0x08) |
| 347 | reg += OMAP1610_GPIO_EDGE_CTRL2; | 347 | reg += OMAP1610_GPIO_EDGE_CTRL2; |
| 348 | else | 348 | else |
| 349 | reg += OMAP1610_GPIO_EDGE_CTRL1; | 349 | reg += OMAP1610_GPIO_EDGE_CTRL1; |
| 350 | gpio &= 0x07; | 350 | gpio &= 0x07; |
| 351 | l = __raw_readl(reg); | 351 | l = __raw_readl(reg); |
| 352 | l &= ~(3 << (gpio << 1)); | 352 | l &= ~(3 << (gpio << 1)); |
| 353 | l |= edge << (gpio << 1); | 353 | l |= edge << (gpio << 1); |
| 354 | __raw_writel(l, reg); | 354 | __raw_writel(l, reg); |
| 355 | break; | 355 | break; |
| 356 | case METHOD_GPIO_730: | 356 | case METHOD_GPIO_730: |
| 357 | reg += OMAP730_GPIO_INT_CONTROL; | 357 | reg += OMAP730_GPIO_INT_CONTROL; |
| 358 | l = __raw_readl(reg); | 358 | l = __raw_readl(reg); |
| 359 | if (edge == OMAP_GPIO_RISING_EDGE) | 359 | if (edge == OMAP_GPIO_RISING_EDGE) |
| 360 | l |= 1 << gpio; | 360 | l |= 1 << gpio; |
| 361 | else | 361 | else |
| 362 | l &= ~(1 << gpio); | 362 | l &= ~(1 << gpio); |
| 363 | __raw_writel(l, reg); | 363 | __raw_writel(l, reg); |
| 364 | break; | 364 | break; |
| 365 | default: | 365 | default: |
| 366 | BUG(); | 366 | BUG(); |
| 367 | return; | 367 | return; |
| 368 | } | 368 | } |
| 369 | } | 369 | } |
| 370 | 370 | ||
| 371 | void omap_set_gpio_edge_ctrl(int gpio, int edge) | 371 | void omap_set_gpio_edge_ctrl(int gpio, int edge) |
| 372 | { | 372 | { |
| 373 | struct gpio_bank *bank; | 373 | struct gpio_bank *bank; |
| 374 | 374 | ||
| 375 | if (check_gpio(gpio) < 0) | 375 | if (check_gpio(gpio) < 0) |
| 376 | return; | 376 | return; |
| 377 | bank = get_gpio_bank(gpio); | 377 | bank = get_gpio_bank(gpio); |
| 378 | spin_lock(&bank->lock); | 378 | spin_lock(&bank->lock); |
| 379 | _set_gpio_edge_ctrl(bank, get_gpio_index(gpio), edge); | 379 | _set_gpio_edge_ctrl(bank, get_gpio_index(gpio), edge); |
| 380 | spin_unlock(&bank->lock); | 380 | spin_unlock(&bank->lock); |
| 381 | } | 381 | } |
| 382 | 382 | ||
| 383 | 383 | ||
| 384 | static int _get_gpio_edge_ctrl(struct gpio_bank *bank, int gpio) | 384 | static int _get_gpio_edge_ctrl(struct gpio_bank *bank, int gpio) |
| 385 | { | 385 | { |
| 386 | u32 reg = bank->base, l; | 386 | u32 reg = bank->base, l; |
| 387 | 387 | ||
| 388 | switch (bank->method) { | 388 | switch (bank->method) { |
| 389 | case METHOD_MPUIO: | 389 | case METHOD_MPUIO: |
| 390 | l = __raw_readl(reg + OMAP_MPUIO_GPIO_INT_EDGE); | 390 | l = __raw_readl(reg + OMAP_MPUIO_GPIO_INT_EDGE); |
| 391 | return (l & (1 << gpio)) ? | 391 | return (l & (1 << gpio)) ? |
| 392 | OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE; | 392 | OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE; |
| 393 | case METHOD_GPIO_1510: | 393 | case METHOD_GPIO_1510: |
| 394 | l = __raw_readl(reg + OMAP1510_GPIO_INT_CONTROL); | 394 | l = __raw_readl(reg + OMAP1510_GPIO_INT_CONTROL); |
| 395 | return (l & (1 << gpio)) ? | 395 | return (l & (1 << gpio)) ? |
| 396 | OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE; | 396 | OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE; |
| 397 | case METHOD_GPIO_1610: | 397 | case METHOD_GPIO_1610: |
| 398 | if (gpio & 0x08) | 398 | if (gpio & 0x08) |
| 399 | reg += OMAP1610_GPIO_EDGE_CTRL2; | 399 | reg += OMAP1610_GPIO_EDGE_CTRL2; |
| 400 | else | 400 | else |
| 401 | reg += OMAP1610_GPIO_EDGE_CTRL1; | 401 | reg += OMAP1610_GPIO_EDGE_CTRL1; |
| 402 | return (__raw_readl(reg) >> ((gpio & 0x07) << 1)) & 0x03; | 402 | return (__raw_readl(reg) >> ((gpio & 0x07) << 1)) & 0x03; |
| 403 | case METHOD_GPIO_730: | 403 | case METHOD_GPIO_730: |
| 404 | l = __raw_readl(reg + OMAP730_GPIO_INT_CONTROL); | 404 | l = __raw_readl(reg + OMAP730_GPIO_INT_CONTROL); |
| 405 | return (l & (1 << gpio)) ? | 405 | return (l & (1 << gpio)) ? |
| 406 | OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE; | 406 | OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE; |
| 407 | default: | 407 | default: |
| 408 | BUG(); | 408 | BUG(); |
| 409 | return -1; | 409 | return -1; |
| 410 | } | 410 | } |
| 411 | } | 411 | } |
| 412 | 412 | ||
| 413 | static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) | 413 | static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) |
| 414 | { | 414 | { |
| 415 | u32 reg = bank->base; | 415 | u32 reg = bank->base; |
| 416 | 416 | ||
| 417 | switch (bank->method) { | 417 | switch (bank->method) { |
| 418 | case METHOD_MPUIO: | 418 | case METHOD_MPUIO: |
| 419 | /* MPUIO irqstatus is reset by reading the status register, | 419 | /* MPUIO irqstatus is reset by reading the status register, |
| 420 | * so do nothing here */ | 420 | * so do nothing here */ |
| 421 | return; | 421 | return; |
| 422 | case METHOD_GPIO_1510: | 422 | case METHOD_GPIO_1510: |
| 423 | reg += OMAP1510_GPIO_INT_STATUS; | 423 | reg += OMAP1510_GPIO_INT_STATUS; |
| 424 | break; | 424 | break; |
| 425 | case METHOD_GPIO_1610: | 425 | case METHOD_GPIO_1610: |
| 426 | reg += OMAP1610_GPIO_IRQSTATUS1; | 426 | reg += OMAP1610_GPIO_IRQSTATUS1; |
| 427 | break; | 427 | break; |
| 428 | case METHOD_GPIO_730: | 428 | case METHOD_GPIO_730: |
| 429 | reg += OMAP730_GPIO_INT_STATUS; | 429 | reg += OMAP730_GPIO_INT_STATUS; |
| 430 | break; | 430 | break; |
| 431 | default: | 431 | default: |
| 432 | BUG(); | 432 | BUG(); |
| 433 | return; | 433 | return; |
| 434 | } | 434 | } |
| 435 | __raw_writel(gpio_mask, reg); | 435 | __raw_writel(gpio_mask, reg); |
| 436 | } | 436 | } |
| 437 | 437 | ||
| 438 | static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio) | 438 | static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio) |
| 439 | { | 439 | { |
| 440 | _clear_gpio_irqbank(bank, 1 << get_gpio_index(gpio)); | 440 | _clear_gpio_irqbank(bank, 1 << get_gpio_index(gpio)); |
| 441 | } | 441 | } |
| 442 | 442 | ||
| 443 | static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enable) | 443 | static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enable) |
| 444 | { | 444 | { |
| 445 | u32 reg = bank->base; | 445 | u32 reg = bank->base; |
| 446 | u32 l; | 446 | u32 l; |
| 447 | 447 | ||
| 448 | switch (bank->method) { | 448 | switch (bank->method) { |
| 449 | case METHOD_MPUIO: | 449 | case METHOD_MPUIO: |
| 450 | reg += OMAP_MPUIO_GPIO_MASKIT; | 450 | reg += OMAP_MPUIO_GPIO_MASKIT; |
| 451 | l = __raw_readl(reg); | 451 | l = __raw_readl(reg); |
| 452 | if (enable) | 452 | if (enable) |
| 453 | l &= ~(gpio_mask); | 453 | l &= ~(gpio_mask); |
| 454 | else | 454 | else |
| 455 | l |= gpio_mask; | 455 | l |= gpio_mask; |
| 456 | break; | 456 | break; |
| 457 | case METHOD_GPIO_1510: | 457 | case METHOD_GPIO_1510: |
| 458 | reg += OMAP1510_GPIO_INT_MASK; | 458 | reg += OMAP1510_GPIO_INT_MASK; |
| 459 | l = __raw_readl(reg); | 459 | l = __raw_readl(reg); |
| 460 | if (enable) | 460 | if (enable) |
| 461 | l &= ~(gpio_mask); | 461 | l &= ~(gpio_mask); |
| 462 | else | 462 | else |
| 463 | l |= gpio_mask; | 463 | l |= gpio_mask; |
| 464 | break; | 464 | break; |
| 465 | case METHOD_GPIO_1610: | 465 | case METHOD_GPIO_1610: |
| 466 | if (enable) | 466 | if (enable) |
| 467 | reg += OMAP1610_GPIO_SET_IRQENABLE1; | 467 | reg += OMAP1610_GPIO_SET_IRQENABLE1; |
| 468 | else | 468 | else |
| 469 | reg += OMAP1610_GPIO_CLEAR_IRQENABLE1; | 469 | reg += OMAP1610_GPIO_CLEAR_IRQENABLE1; |
| 470 | l = gpio_mask; | 470 | l = gpio_mask; |
| 471 | break; | 471 | break; |
| 472 | case METHOD_GPIO_730: | 472 | case METHOD_GPIO_730: |
| 473 | reg += OMAP730_GPIO_INT_MASK; | 473 | reg += OMAP730_GPIO_INT_MASK; |
| 474 | l = __raw_readl(reg); | 474 | l = __raw_readl(reg); |
| 475 | if (enable) | 475 | if (enable) |
| 476 | l &= ~(gpio_mask); | 476 | l &= ~(gpio_mask); |
| 477 | else | 477 | else |
| 478 | l |= gpio_mask; | 478 | l |= gpio_mask; |
| 479 | break; | 479 | break; |
| 480 | default: | 480 | default: |
| 481 | BUG(); | 481 | BUG(); |
| 482 | return; | 482 | return; |
| 483 | } | 483 | } |
| 484 | __raw_writel(l, reg); | 484 | __raw_writel(l, reg); |
| 485 | } | 485 | } |
| 486 | 486 | ||
| 487 | static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable) | 487 | static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable) |
| 488 | { | 488 | { |
| 489 | _enable_gpio_irqbank(bank, 1 << get_gpio_index(gpio), enable); | 489 | _enable_gpio_irqbank(bank, 1 << get_gpio_index(gpio), enable); |
| 490 | } | 490 | } |
| 491 | 491 | ||
| 492 | int omap_request_gpio(int gpio) | 492 | int omap_request_gpio(int gpio) |
| 493 | { | 493 | { |
| 494 | struct gpio_bank *bank; | 494 | struct gpio_bank *bank; |
| 495 | 495 | ||
| 496 | if (check_gpio(gpio) < 0) | 496 | if (check_gpio(gpio) < 0) |
| 497 | return -EINVAL; | 497 | return -EINVAL; |
| 498 | 498 | ||
| 499 | bank = get_gpio_bank(gpio); | 499 | bank = get_gpio_bank(gpio); |
| 500 | spin_lock(&bank->lock); | 500 | spin_lock(&bank->lock); |
| 501 | if (unlikely(bank->reserved_map & (1 << get_gpio_index(gpio)))) { | 501 | if (unlikely(bank->reserved_map & (1 << get_gpio_index(gpio)))) { |
| 502 | printk(KERN_ERR "omap-gpio: GPIO %d is already reserved!\n", gpio); | 502 | printk(KERN_ERR "omap-gpio: GPIO %d is already reserved!\n", gpio); |
| 503 | dump_stack(); | 503 | dump_stack(); |
| 504 | spin_unlock(&bank->lock); | 504 | spin_unlock(&bank->lock); |
| 505 | return -1; | 505 | return -1; |
| 506 | } | 506 | } |
| 507 | bank->reserved_map |= (1 << get_gpio_index(gpio)); | 507 | bank->reserved_map |= (1 << get_gpio_index(gpio)); |
| 508 | #ifdef CONFIG_ARCH_OMAP1510 | 508 | #ifdef CONFIG_ARCH_OMAP1510 |
| 509 | if (bank->method == METHOD_GPIO_1510) { | 509 | if (bank->method == METHOD_GPIO_1510) { |
| 510 | u32 reg; | 510 | u32 reg; |
| 511 | 511 | ||
| 512 | /* Claim the pin for the ARM */ | 512 | /* Claim the pin for the ARM */ |
| 513 | reg = bank->base + OMAP1510_GPIO_PIN_CONTROL; | 513 | reg = bank->base + OMAP1510_GPIO_PIN_CONTROL; |
| 514 | __raw_writel(__raw_readl(reg) | (1 << get_gpio_index(gpio)), reg); | 514 | __raw_writel(__raw_readl(reg) | (1 << get_gpio_index(gpio)), reg); |
| 515 | } | 515 | } |
| 516 | #endif | 516 | #endif |
| 517 | spin_unlock(&bank->lock); | 517 | spin_unlock(&bank->lock); |
| 518 | 518 | ||
| 519 | return 0; | 519 | return 0; |
| 520 | } | 520 | } |
| 521 | 521 | ||
| 522 | void omap_free_gpio(int gpio) | 522 | void omap_free_gpio(int gpio) |
| 523 | { | 523 | { |
| 524 | struct gpio_bank *bank; | 524 | struct gpio_bank *bank; |
| 525 | 525 | ||
| 526 | if (check_gpio(gpio) < 0) | 526 | if (check_gpio(gpio) < 0) |
| 527 | return; | 527 | return; |
| 528 | bank = get_gpio_bank(gpio); | 528 | bank = get_gpio_bank(gpio); |
| 529 | spin_lock(&bank->lock); | 529 | spin_lock(&bank->lock); |
| 530 | if (unlikely(!(bank->reserved_map & (1 << get_gpio_index(gpio))))) { | 530 | if (unlikely(!(bank->reserved_map & (1 << get_gpio_index(gpio))))) { |
| 531 | printk(KERN_ERR "omap-gpio: GPIO %d wasn't reserved!\n", gpio); | 531 | printk(KERN_ERR "omap-gpio: GPIO %d wasn't reserved!\n", gpio); |
| 532 | dump_stack(); | 532 | dump_stack(); |
| 533 | spin_unlock(&bank->lock); | 533 | spin_unlock(&bank->lock); |
| 534 | return; | 534 | return; |
| 535 | } | 535 | } |
| 536 | bank->reserved_map &= ~(1 << get_gpio_index(gpio)); | 536 | bank->reserved_map &= ~(1 << get_gpio_index(gpio)); |
| 537 | _set_gpio_direction(bank, get_gpio_index(gpio), 1); | 537 | _set_gpio_direction(bank, get_gpio_index(gpio), 1); |
| 538 | _set_gpio_irqenable(bank, gpio, 0); | 538 | _set_gpio_irqenable(bank, gpio, 0); |
| 539 | _clear_gpio_irqstatus(bank, gpio); | 539 | _clear_gpio_irqstatus(bank, gpio); |
| 540 | spin_unlock(&bank->lock); | 540 | spin_unlock(&bank->lock); |
| 541 | } | 541 | } |
| 542 | 542 | ||
| 543 | /* | 543 | /* |
| 544 | * We need to unmask the GPIO bank interrupt as soon as possible to | 544 | * We need to unmask the GPIO bank interrupt as soon as possible to |
| 545 | * avoid missing GPIO interrupts for other lines in the bank. | 545 | * avoid missing GPIO interrupts for other lines in the bank. |
| 546 | * Then we need to mask-read-clear-unmask the triggered GPIO lines | 546 | * Then we need to mask-read-clear-unmask the triggered GPIO lines |
| 547 | * in the bank to avoid missing nested interrupts for a GPIO line. | 547 | * in the bank to avoid missing nested interrupts for a GPIO line. |
| 548 | * If we wait to unmask individual GPIO lines in the bank after the | 548 | * If we wait to unmask individual GPIO lines in the bank after the |
| 549 | * line's interrupt handler has been run, we may miss some nested | 549 | * line's interrupt handler has been run, we may miss some nested |
| 550 | * interrupts. | 550 | * interrupts. |
| 551 | */ | 551 | */ |
| 552 | static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, | 552 | static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, |
| 553 | struct pt_regs *regs) | 553 | struct pt_regs *regs) |
| 554 | { | 554 | { |
| 555 | u32 isr_reg = 0; | 555 | u32 isr_reg = 0; |
| 556 | u32 isr; | 556 | u32 isr; |
| 557 | unsigned int gpio_irq; | 557 | unsigned int gpio_irq; |
| 558 | struct gpio_bank *bank; | 558 | struct gpio_bank *bank; |
| 559 | 559 | ||
| 560 | desc->chip->ack(irq); | 560 | desc->chip->ack(irq); |
| 561 | 561 | ||
| 562 | bank = (struct gpio_bank *) desc->data; | 562 | bank = (struct gpio_bank *) desc->data; |
| 563 | if (bank->method == METHOD_MPUIO) | 563 | if (bank->method == METHOD_MPUIO) |
| 564 | isr_reg = bank->base + OMAP_MPUIO_GPIO_INT; | 564 | isr_reg = bank->base + OMAP_MPUIO_GPIO_INT; |
| 565 | #ifdef CONFIG_ARCH_OMAP1510 | 565 | #ifdef CONFIG_ARCH_OMAP1510 |
| 566 | if (bank->method == METHOD_GPIO_1510) | 566 | if (bank->method == METHOD_GPIO_1510) |
| 567 | isr_reg = bank->base + OMAP1510_GPIO_INT_STATUS; | 567 | isr_reg = bank->base + OMAP1510_GPIO_INT_STATUS; |
| 568 | #endif | 568 | #endif |
| 569 | #if defined(CONFIG_ARCH_OMAP16XX) | 569 | #if defined(CONFIG_ARCH_OMAP16XX) |
| 570 | if (bank->method == METHOD_GPIO_1610) | 570 | if (bank->method == METHOD_GPIO_1610) |
| 571 | isr_reg = bank->base + OMAP1610_GPIO_IRQSTATUS1; | 571 | isr_reg = bank->base + OMAP1610_GPIO_IRQSTATUS1; |
| 572 | #endif | 572 | #endif |
| 573 | #ifdef CONFIG_ARCH_OMAP730 | 573 | #ifdef CONFIG_ARCH_OMAP730 |
| 574 | if (bank->method == METHOD_GPIO_730) | 574 | if (bank->method == METHOD_GPIO_730) |
| 575 | isr_reg = bank->base + OMAP730_GPIO_INT_STATUS; | 575 | isr_reg = bank->base + OMAP730_GPIO_INT_STATUS; |
| 576 | #endif | 576 | #endif |
| 577 | 577 | ||
| 578 | isr = __raw_readl(isr_reg); | 578 | isr = __raw_readl(isr_reg); |
| 579 | _enable_gpio_irqbank(bank, isr, 0); | 579 | _enable_gpio_irqbank(bank, isr, 0); |
| 580 | _clear_gpio_irqbank(bank, isr); | 580 | _clear_gpio_irqbank(bank, isr); |
| 581 | _enable_gpio_irqbank(bank, isr, 1); | 581 | _enable_gpio_irqbank(bank, isr, 1); |
| 582 | desc->chip->unmask(irq); | 582 | desc->chip->unmask(irq); |
| 583 | 583 | ||
| 584 | if (unlikely(!isr)) | 584 | if (unlikely(!isr)) |
| 585 | return; | 585 | return; |
| 586 | 586 | ||
| 587 | gpio_irq = bank->virtual_irq_start; | 587 | gpio_irq = bank->virtual_irq_start; |
| 588 | for (; isr != 0; isr >>= 1, gpio_irq++) { | 588 | for (; isr != 0; isr >>= 1, gpio_irq++) { |
| 589 | struct irqdesc *d; | 589 | struct irqdesc *d; |
| 590 | if (!(isr & 1)) | 590 | if (!(isr & 1)) |
| 591 | continue; | 591 | continue; |
| 592 | d = irq_desc + gpio_irq; | 592 | d = irq_desc + gpio_irq; |
| 593 | d->handle(gpio_irq, d, regs); | 593 | desc_handle_irq(gpio_irq, d, regs); |
| 594 | } | 594 | } |
| 595 | } | 595 | } |
| 596 | 596 | ||
| 597 | static void gpio_ack_irq(unsigned int irq) | 597 | static void gpio_ack_irq(unsigned int irq) |
| 598 | { | 598 | { |
| 599 | unsigned int gpio = irq - IH_GPIO_BASE; | 599 | unsigned int gpio = irq - IH_GPIO_BASE; |
| 600 | struct gpio_bank *bank = get_gpio_bank(gpio); | 600 | struct gpio_bank *bank = get_gpio_bank(gpio); |
| 601 | 601 | ||
| 602 | _clear_gpio_irqstatus(bank, gpio); | 602 | _clear_gpio_irqstatus(bank, gpio); |
| 603 | } | 603 | } |
| 604 | 604 | ||
| 605 | static void gpio_mask_irq(unsigned int irq) | 605 | static void gpio_mask_irq(unsigned int irq) |
| 606 | { | 606 | { |
| 607 | unsigned int gpio = irq - IH_GPIO_BASE; | 607 | unsigned int gpio = irq - IH_GPIO_BASE; |
| 608 | struct gpio_bank *bank = get_gpio_bank(gpio); | 608 | struct gpio_bank *bank = get_gpio_bank(gpio); |
| 609 | 609 | ||
| 610 | _set_gpio_irqenable(bank, gpio, 0); | 610 | _set_gpio_irqenable(bank, gpio, 0); |
| 611 | } | 611 | } |
| 612 | 612 | ||
| 613 | static void gpio_unmask_irq(unsigned int irq) | 613 | static void gpio_unmask_irq(unsigned int irq) |
| 614 | { | 614 | { |
| 615 | unsigned int gpio = irq - IH_GPIO_BASE; | 615 | unsigned int gpio = irq - IH_GPIO_BASE; |
| 616 | struct gpio_bank *bank = get_gpio_bank(gpio); | 616 | struct gpio_bank *bank = get_gpio_bank(gpio); |
| 617 | 617 | ||
| 618 | if (_get_gpio_edge_ctrl(bank, get_gpio_index(gpio)) == OMAP_GPIO_NO_EDGE) { | 618 | if (_get_gpio_edge_ctrl(bank, get_gpio_index(gpio)) == OMAP_GPIO_NO_EDGE) { |
| 619 | printk(KERN_ERR "OMAP GPIO %d: trying to enable GPIO IRQ while no edge is set\n", | 619 | printk(KERN_ERR "OMAP GPIO %d: trying to enable GPIO IRQ while no edge is set\n", |
| 620 | gpio); | 620 | gpio); |
| 621 | _set_gpio_edge_ctrl(bank, get_gpio_index(gpio), OMAP_GPIO_RISING_EDGE); | 621 | _set_gpio_edge_ctrl(bank, get_gpio_index(gpio), OMAP_GPIO_RISING_EDGE); |
| 622 | } | 622 | } |
| 623 | _set_gpio_irqenable(bank, gpio, 1); | 623 | _set_gpio_irqenable(bank, gpio, 1); |
| 624 | } | 624 | } |
| 625 | 625 | ||
| 626 | static void mpuio_ack_irq(unsigned int irq) | 626 | static void mpuio_ack_irq(unsigned int irq) |
| 627 | { | 627 | { |
| 628 | /* The ISR is reset automatically, so do nothing here. */ | 628 | /* The ISR is reset automatically, so do nothing here. */ |
| 629 | } | 629 | } |
| 630 | 630 | ||
| 631 | static void mpuio_mask_irq(unsigned int irq) | 631 | static void mpuio_mask_irq(unsigned int irq) |
| 632 | { | 632 | { |
| 633 | unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE); | 633 | unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE); |
| 634 | struct gpio_bank *bank = get_gpio_bank(gpio); | 634 | struct gpio_bank *bank = get_gpio_bank(gpio); |
| 635 | 635 | ||
| 636 | _set_gpio_irqenable(bank, gpio, 0); | 636 | _set_gpio_irqenable(bank, gpio, 0); |
| 637 | } | 637 | } |
| 638 | 638 | ||
| 639 | static void mpuio_unmask_irq(unsigned int irq) | 639 | static void mpuio_unmask_irq(unsigned int irq) |
| 640 | { | 640 | { |
| 641 | unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE); | 641 | unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE); |
| 642 | struct gpio_bank *bank = get_gpio_bank(gpio); | 642 | struct gpio_bank *bank = get_gpio_bank(gpio); |
| 643 | 643 | ||
| 644 | _set_gpio_irqenable(bank, gpio, 1); | 644 | _set_gpio_irqenable(bank, gpio, 1); |
| 645 | } | 645 | } |
| 646 | 646 | ||
| 647 | static struct irqchip gpio_irq_chip = { | 647 | static struct irqchip gpio_irq_chip = { |
| 648 | .ack = gpio_ack_irq, | 648 | .ack = gpio_ack_irq, |
| 649 | .mask = gpio_mask_irq, | 649 | .mask = gpio_mask_irq, |
| 650 | .unmask = gpio_unmask_irq, | 650 | .unmask = gpio_unmask_irq, |
| 651 | }; | 651 | }; |
| 652 | 652 | ||
| 653 | static struct irqchip mpuio_irq_chip = { | 653 | static struct irqchip mpuio_irq_chip = { |
| 654 | .ack = mpuio_ack_irq, | 654 | .ack = mpuio_ack_irq, |
| 655 | .mask = mpuio_mask_irq, | 655 | .mask = mpuio_mask_irq, |
| 656 | .unmask = mpuio_unmask_irq | 656 | .unmask = mpuio_unmask_irq |
| 657 | }; | 657 | }; |
| 658 | 658 | ||
| 659 | static int initialized = 0; | 659 | static int initialized = 0; |
| 660 | 660 | ||
| 661 | static int __init _omap_gpio_init(void) | 661 | static int __init _omap_gpio_init(void) |
| 662 | { | 662 | { |
| 663 | int i; | 663 | int i; |
| 664 | struct gpio_bank *bank; | 664 | struct gpio_bank *bank; |
| 665 | 665 | ||
| 666 | initialized = 1; | 666 | initialized = 1; |
| 667 | 667 | ||
| 668 | #ifdef CONFIG_ARCH_OMAP1510 | 668 | #ifdef CONFIG_ARCH_OMAP1510 |
| 669 | if (cpu_is_omap1510()) { | 669 | if (cpu_is_omap1510()) { |
| 670 | printk(KERN_INFO "OMAP1510 GPIO hardware\n"); | 670 | printk(KERN_INFO "OMAP1510 GPIO hardware\n"); |
| 671 | gpio_bank_count = 2; | 671 | gpio_bank_count = 2; |
| 672 | gpio_bank = gpio_bank_1510; | 672 | gpio_bank = gpio_bank_1510; |
| 673 | } | 673 | } |
| 674 | #endif | 674 | #endif |
| 675 | #if defined(CONFIG_ARCH_OMAP16XX) | 675 | #if defined(CONFIG_ARCH_OMAP16XX) |
| 676 | if (cpu_is_omap16xx()) { | 676 | if (cpu_is_omap16xx()) { |
| 677 | int rev; | 677 | int rev; |
| 678 | 678 | ||
| 679 | gpio_bank_count = 5; | 679 | gpio_bank_count = 5; |
| 680 | gpio_bank = gpio_bank_1610; | 680 | gpio_bank = gpio_bank_1610; |
| 681 | rev = omap_readw(gpio_bank[1].base + OMAP1610_GPIO_REVISION); | 681 | rev = omap_readw(gpio_bank[1].base + OMAP1610_GPIO_REVISION); |
| 682 | printk(KERN_INFO "OMAP GPIO hardware version %d.%d\n", | 682 | printk(KERN_INFO "OMAP GPIO hardware version %d.%d\n", |
| 683 | (rev >> 4) & 0x0f, rev & 0x0f); | 683 | (rev >> 4) & 0x0f, rev & 0x0f); |
| 684 | } | 684 | } |
| 685 | #endif | 685 | #endif |
| 686 | #ifdef CONFIG_ARCH_OMAP730 | 686 | #ifdef CONFIG_ARCH_OMAP730 |
| 687 | if (cpu_is_omap730()) { | 687 | if (cpu_is_omap730()) { |
| 688 | printk(KERN_INFO "OMAP730 GPIO hardware\n"); | 688 | printk(KERN_INFO "OMAP730 GPIO hardware\n"); |
| 689 | gpio_bank_count = 7; | 689 | gpio_bank_count = 7; |
| 690 | gpio_bank = gpio_bank_730; | 690 | gpio_bank = gpio_bank_730; |
| 691 | } | 691 | } |
| 692 | #endif | 692 | #endif |
| 693 | for (i = 0; i < gpio_bank_count; i++) { | 693 | for (i = 0; i < gpio_bank_count; i++) { |
| 694 | int j, gpio_count = 16; | 694 | int j, gpio_count = 16; |
| 695 | 695 | ||
| 696 | bank = &gpio_bank[i]; | 696 | bank = &gpio_bank[i]; |
| 697 | bank->reserved_map = 0; | 697 | bank->reserved_map = 0; |
| 698 | bank->base = IO_ADDRESS(bank->base); | 698 | bank->base = IO_ADDRESS(bank->base); |
| 699 | spin_lock_init(&bank->lock); | 699 | spin_lock_init(&bank->lock); |
| 700 | if (bank->method == METHOD_MPUIO) { | 700 | if (bank->method == METHOD_MPUIO) { |
| 701 | omap_writew(0xFFFF, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_MASKIT); | 701 | omap_writew(0xFFFF, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_MASKIT); |
| 702 | } | 702 | } |
| 703 | #ifdef CONFIG_ARCH_OMAP1510 | 703 | #ifdef CONFIG_ARCH_OMAP1510 |
| 704 | if (bank->method == METHOD_GPIO_1510) { | 704 | if (bank->method == METHOD_GPIO_1510) { |
| 705 | __raw_writew(0xffff, bank->base + OMAP1510_GPIO_INT_MASK); | 705 | __raw_writew(0xffff, bank->base + OMAP1510_GPIO_INT_MASK); |
| 706 | __raw_writew(0x0000, bank->base + OMAP1510_GPIO_INT_STATUS); | 706 | __raw_writew(0x0000, bank->base + OMAP1510_GPIO_INT_STATUS); |
| 707 | } | 707 | } |
| 708 | #endif | 708 | #endif |
| 709 | #if defined(CONFIG_ARCH_OMAP16XX) | 709 | #if defined(CONFIG_ARCH_OMAP16XX) |
| 710 | if (bank->method == METHOD_GPIO_1610) { | 710 | if (bank->method == METHOD_GPIO_1610) { |
| 711 | __raw_writew(0x0000, bank->base + OMAP1610_GPIO_IRQENABLE1); | 711 | __raw_writew(0x0000, bank->base + OMAP1610_GPIO_IRQENABLE1); |
| 712 | __raw_writew(0xffff, bank->base + OMAP1610_GPIO_IRQSTATUS1); | 712 | __raw_writew(0xffff, bank->base + OMAP1610_GPIO_IRQSTATUS1); |
| 713 | } | 713 | } |
| 714 | #endif | 714 | #endif |
| 715 | #ifdef CONFIG_ARCH_OMAP730 | 715 | #ifdef CONFIG_ARCH_OMAP730 |
| 716 | if (bank->method == METHOD_GPIO_730) { | 716 | if (bank->method == METHOD_GPIO_730) { |
| 717 | __raw_writel(0xffffffff, bank->base + OMAP730_GPIO_INT_MASK); | 717 | __raw_writel(0xffffffff, bank->base + OMAP730_GPIO_INT_MASK); |
| 718 | __raw_writel(0x00000000, bank->base + OMAP730_GPIO_INT_STATUS); | 718 | __raw_writel(0x00000000, bank->base + OMAP730_GPIO_INT_STATUS); |
| 719 | 719 | ||
| 720 | gpio_count = 32; /* 730 has 32-bit GPIOs */ | 720 | gpio_count = 32; /* 730 has 32-bit GPIOs */ |
| 721 | } | 721 | } |
| 722 | #endif | 722 | #endif |
| 723 | for (j = bank->virtual_irq_start; | 723 | for (j = bank->virtual_irq_start; |
| 724 | j < bank->virtual_irq_start + gpio_count; j++) { | 724 | j < bank->virtual_irq_start + gpio_count; j++) { |
| 725 | if (bank->method == METHOD_MPUIO) | 725 | if (bank->method == METHOD_MPUIO) |
| 726 | set_irq_chip(j, &mpuio_irq_chip); | 726 | set_irq_chip(j, &mpuio_irq_chip); |
| 727 | else | 727 | else |
| 728 | set_irq_chip(j, &gpio_irq_chip); | 728 | set_irq_chip(j, &gpio_irq_chip); |
| 729 | set_irq_handler(j, do_simple_IRQ); | 729 | set_irq_handler(j, do_simple_IRQ); |
| 730 | set_irq_flags(j, IRQF_VALID); | 730 | set_irq_flags(j, IRQF_VALID); |
| 731 | } | 731 | } |
| 732 | set_irq_chained_handler(bank->irq, gpio_irq_handler); | 732 | set_irq_chained_handler(bank->irq, gpio_irq_handler); |
| 733 | set_irq_data(bank->irq, bank); | 733 | set_irq_data(bank->irq, bank); |
| 734 | } | 734 | } |
| 735 | 735 | ||
| 736 | /* Enable system clock for GPIO module. | 736 | /* Enable system clock for GPIO module. |
| 737 | * The CAM_CLK_CTRL *is* really the right place. */ | 737 | * The CAM_CLK_CTRL *is* really the right place. */ |
| 738 | if (cpu_is_omap1610() || cpu_is_omap1710()) | 738 | if (cpu_is_omap1610() || cpu_is_omap1710()) |
| 739 | omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04, ULPD_CAM_CLK_CTRL); | 739 | omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04, ULPD_CAM_CLK_CTRL); |
| 740 | 740 | ||
| 741 | return 0; | 741 | return 0; |
| 742 | } | 742 | } |
| 743 | 743 | ||
| 744 | /* | 744 | /* |
| 745 | * This may get called early from board specific init | 745 | * This may get called early from board specific init |
| 746 | */ | 746 | */ |
| 747 | int omap_gpio_init(void) | 747 | int omap_gpio_init(void) |
| 748 | { | 748 | { |
| 749 | if (!initialized) | 749 | if (!initialized) |
| 750 | return _omap_gpio_init(); | 750 | return _omap_gpio_init(); |
| 751 | else | 751 | else |
| 752 | return 0; | 752 | return 0; |
| 753 | } | 753 | } |
| 754 | 754 | ||
| 755 | EXPORT_SYMBOL(omap_request_gpio); | 755 | EXPORT_SYMBOL(omap_request_gpio); |
| 756 | EXPORT_SYMBOL(omap_free_gpio); | 756 | EXPORT_SYMBOL(omap_free_gpio); |
| 757 | EXPORT_SYMBOL(omap_set_gpio_direction); | 757 | EXPORT_SYMBOL(omap_set_gpio_direction); |
| 758 | EXPORT_SYMBOL(omap_set_gpio_dataout); | 758 | EXPORT_SYMBOL(omap_set_gpio_dataout); |
| 759 | EXPORT_SYMBOL(omap_get_gpio_datain); | 759 | EXPORT_SYMBOL(omap_get_gpio_datain); |
| 760 | EXPORT_SYMBOL(omap_set_gpio_edge_ctrl); | 760 | EXPORT_SYMBOL(omap_set_gpio_edge_ctrl); |
| 761 | 761 | ||
| 762 | arch_initcall(omap_gpio_init); | 762 | arch_initcall(omap_gpio_init); |
| 763 | 763 |
drivers/pcmcia/pxa2xx_base.c
| 1 | /*====================================================================== | 1 | /*====================================================================== |
| 2 | 2 | ||
| 3 | Device driver for the PCMCIA control functionality of PXA2xx | 3 | Device driver for the PCMCIA control functionality of PXA2xx |
| 4 | microprocessors. | 4 | microprocessors. |
| 5 | 5 | ||
| 6 | The contents of this file may be used under the | 6 | The contents of this file may be used under the |
| 7 | terms of the GNU Public License version 2 (the "GPL") | 7 | terms of the GNU Public License version 2 (the "GPL") |
| 8 | 8 | ||
| 9 | (c) Ian Molton (spyro@f2s.com) 2003 | 9 | (c) Ian Molton (spyro@f2s.com) 2003 |
| 10 | (c) Stefan Eletzhofer (stefan.eletzhofer@inquant.de) 2003,4 | 10 | (c) Stefan Eletzhofer (stefan.eletzhofer@inquant.de) 2003,4 |
| 11 | 11 | ||
| 12 | derived from sa11xx_base.c | 12 | derived from sa11xx_base.c |
| 13 | 13 | ||
| 14 | Portions created by John G. Dorsey are | 14 | Portions created by John G. Dorsey are |
| 15 | Copyright (C) 1999 John G. Dorsey. | 15 | Copyright (C) 1999 John G. Dorsey. |
| 16 | 16 | ||
| 17 | ======================================================================*/ | 17 | ======================================================================*/ |
| 18 | 18 | ||
| 19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
| 21 | #include <linux/config.h> | 21 | #include <linux/config.h> |
| 22 | #include <linux/cpufreq.h> | 22 | #include <linux/cpufreq.h> |
| 23 | #include <linux/ioport.h> | 23 | #include <linux/ioport.h> |
| 24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
| 25 | #include <linux/spinlock.h> | 25 | #include <linux/spinlock.h> |
| 26 | 26 | ||
| 27 | #include <asm/hardware.h> | 27 | #include <asm/hardware.h> |
| 28 | #include <asm/io.h> | 28 | #include <asm/io.h> |
| 29 | #include <asm/irq.h> | 29 | #include <asm/irq.h> |
| 30 | #include <asm/system.h> | 30 | #include <asm/system.h> |
| 31 | #include <asm/arch/pxa-regs.h> | 31 | #include <asm/arch/pxa-regs.h> |
| 32 | 32 | ||
| 33 | #include <pcmcia/cs_types.h> | 33 | #include <pcmcia/cs_types.h> |
| 34 | #include <pcmcia/ss.h> | 34 | #include <pcmcia/ss.h> |
| 35 | #include <pcmcia/bulkmem.h> | 35 | #include <pcmcia/bulkmem.h> |
| 36 | #include <pcmcia/cistpl.h> | 36 | #include <pcmcia/cistpl.h> |
| 37 | 37 | ||
| 38 | #include "cs_internal.h" | 38 | #include "cs_internal.h" |
| 39 | #include "soc_common.h" | 39 | #include "soc_common.h" |
| 40 | #include "pxa2xx_base.h" | 40 | #include "pxa2xx_base.h" |
| 41 | 41 | ||
| 42 | 42 | ||
| 43 | #define MCXX_SETUP_MASK (0x7f) | 43 | #define MCXX_SETUP_MASK (0x7f) |
| 44 | #define MCXX_ASST_MASK (0x1f) | 44 | #define MCXX_ASST_MASK (0x1f) |
| 45 | #define MCXX_HOLD_MASK (0x3f) | 45 | #define MCXX_HOLD_MASK (0x3f) |
| 46 | #define MCXX_SETUP_SHIFT (0) | 46 | #define MCXX_SETUP_SHIFT (0) |
| 47 | #define MCXX_ASST_SHIFT (7) | 47 | #define MCXX_ASST_SHIFT (7) |
| 48 | #define MCXX_HOLD_SHIFT (14) | 48 | #define MCXX_HOLD_SHIFT (14) |
| 49 | 49 | ||
| 50 | static inline u_int pxa2xx_mcxx_hold(u_int pcmcia_cycle_ns, | 50 | static inline u_int pxa2xx_mcxx_hold(u_int pcmcia_cycle_ns, |
| 51 | u_int mem_clk_10khz) | 51 | u_int mem_clk_10khz) |
| 52 | { | 52 | { |
| 53 | u_int code = pcmcia_cycle_ns * mem_clk_10khz; | 53 | u_int code = pcmcia_cycle_ns * mem_clk_10khz; |
| 54 | return (code / 300000) + ((code % 300000) ? 1 : 0) - 1; | 54 | return (code / 300000) + ((code % 300000) ? 1 : 0) - 1; |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | static inline u_int pxa2xx_mcxx_asst(u_int pcmcia_cycle_ns, | 57 | static inline u_int pxa2xx_mcxx_asst(u_int pcmcia_cycle_ns, |
| 58 | u_int mem_clk_10khz) | 58 | u_int mem_clk_10khz) |
| 59 | { | 59 | { |
| 60 | u_int code = pcmcia_cycle_ns * mem_clk_10khz; | 60 | u_int code = pcmcia_cycle_ns * mem_clk_10khz; |
| 61 | return (code / 300000) + ((code % 300000) ? 1 : 0) - 1; | 61 | return (code / 300000) + ((code % 300000) ? 1 : 0) - 1; |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | static inline u_int pxa2xx_mcxx_setup(u_int pcmcia_cycle_ns, | 64 | static inline u_int pxa2xx_mcxx_setup(u_int pcmcia_cycle_ns, |
| 65 | u_int mem_clk_10khz) | 65 | u_int mem_clk_10khz) |
| 66 | { | 66 | { |
| 67 | u_int code = pcmcia_cycle_ns * mem_clk_10khz; | 67 | u_int code = pcmcia_cycle_ns * mem_clk_10khz; |
| 68 | return (code / 100000) + ((code % 100000) ? 1 : 0) - 1; | 68 | return (code / 100000) + ((code % 100000) ? 1 : 0) - 1; |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | /* This function returns the (approximate) command assertion period, in | 71 | /* This function returns the (approximate) command assertion period, in |
| 72 | * nanoseconds, for a given CPU clock frequency and MCXX_ASST value: | 72 | * nanoseconds, for a given CPU clock frequency and MCXX_ASST value: |
| 73 | */ | 73 | */ |
| 74 | static inline u_int pxa2xx_pcmcia_cmd_time(u_int mem_clk_10khz, | 74 | static inline u_int pxa2xx_pcmcia_cmd_time(u_int mem_clk_10khz, |
| 75 | u_int pcmcia_mcxx_asst) | 75 | u_int pcmcia_mcxx_asst) |
| 76 | { | 76 | { |
| 77 | return (300000 * (pcmcia_mcxx_asst + 1) / mem_clk_10khz); | 77 | return (300000 * (pcmcia_mcxx_asst + 1) / mem_clk_10khz); |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | static int pxa2xx_pcmcia_set_mcmem( int sock, int speed, int clock ) | 80 | static int pxa2xx_pcmcia_set_mcmem( int sock, int speed, int clock ) |
| 81 | { | 81 | { |
| 82 | MCMEM(sock) = ((pxa2xx_mcxx_setup(speed, clock) | 82 | MCMEM(sock) = ((pxa2xx_mcxx_setup(speed, clock) |
| 83 | & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) | 83 | & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) |
| 84 | | ((pxa2xx_mcxx_asst(speed, clock) | 84 | | ((pxa2xx_mcxx_asst(speed, clock) |
| 85 | & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) | 85 | & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) |
| 86 | | ((pxa2xx_mcxx_hold(speed, clock) | 86 | | ((pxa2xx_mcxx_hold(speed, clock) |
| 87 | & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); | 87 | & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); |
| 88 | 88 | ||
| 89 | return 0; | 89 | return 0; |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | static int pxa2xx_pcmcia_set_mcio( int sock, int speed, int clock ) | 92 | static int pxa2xx_pcmcia_set_mcio( int sock, int speed, int clock ) |
| 93 | { | 93 | { |
| 94 | MCIO(sock) = ((pxa2xx_mcxx_setup(speed, clock) | 94 | MCIO(sock) = ((pxa2xx_mcxx_setup(speed, clock) |
| 95 | & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) | 95 | & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) |
| 96 | | ((pxa2xx_mcxx_asst(speed, clock) | 96 | | ((pxa2xx_mcxx_asst(speed, clock) |
| 97 | & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) | 97 | & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) |
| 98 | | ((pxa2xx_mcxx_hold(speed, clock) | 98 | | ((pxa2xx_mcxx_hold(speed, clock) |
| 99 | & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); | 99 | & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); |
| 100 | 100 | ||
| 101 | return 0; | 101 | return 0; |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | static int pxa2xx_pcmcia_set_mcatt( int sock, int speed, int clock ) | 104 | static int pxa2xx_pcmcia_set_mcatt( int sock, int speed, int clock ) |
| 105 | { | 105 | { |
| 106 | MCATT(sock) = ((pxa2xx_mcxx_setup(speed, clock) | 106 | MCATT(sock) = ((pxa2xx_mcxx_setup(speed, clock) |
| 107 | & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) | 107 | & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) |
| 108 | | ((pxa2xx_mcxx_asst(speed, clock) | 108 | | ((pxa2xx_mcxx_asst(speed, clock) |
| 109 | & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) | 109 | & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) |
| 110 | | ((pxa2xx_mcxx_hold(speed, clock) | 110 | | ((pxa2xx_mcxx_hold(speed, clock) |
| 111 | & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); | 111 | & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); |
| 112 | 112 | ||
| 113 | return 0; | 113 | return 0; |
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | static int pxa2xx_pcmcia_set_mcxx(struct soc_pcmcia_socket *skt, unsigned int clk) | 116 | static int pxa2xx_pcmcia_set_mcxx(struct soc_pcmcia_socket *skt, unsigned int clk) |
| 117 | { | 117 | { |
| 118 | struct soc_pcmcia_timing timing; | 118 | struct soc_pcmcia_timing timing; |
| 119 | int sock = skt->nr; | 119 | int sock = skt->nr; |
| 120 | 120 | ||
| 121 | soc_common_pcmcia_get_timing(skt, &timing); | 121 | soc_common_pcmcia_get_timing(skt, &timing); |
| 122 | 122 | ||
| 123 | pxa2xx_pcmcia_set_mcmem(sock, timing.mem, clk); | 123 | pxa2xx_pcmcia_set_mcmem(sock, timing.mem, clk); |
| 124 | pxa2xx_pcmcia_set_mcatt(sock, timing.attr, clk); | 124 | pxa2xx_pcmcia_set_mcatt(sock, timing.attr, clk); |
| 125 | pxa2xx_pcmcia_set_mcio(sock, timing.io, clk); | 125 | pxa2xx_pcmcia_set_mcio(sock, timing.io, clk); |
| 126 | 126 | ||
| 127 | return 0; | 127 | return 0; |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | static int pxa2xx_pcmcia_set_timing(struct soc_pcmcia_socket *skt) | 130 | static int pxa2xx_pcmcia_set_timing(struct soc_pcmcia_socket *skt) |
| 131 | { | 131 | { |
| 132 | unsigned int clk = get_memclk_frequency_10khz(); | 132 | unsigned int clk = get_memclk_frequency_10khz(); |
| 133 | return pxa2xx_pcmcia_set_mcxx(skt, clk); | 133 | return pxa2xx_pcmcia_set_mcxx(skt, clk); |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | #ifdef CONFIG_CPU_FREQ | 136 | #ifdef CONFIG_CPU_FREQ |
| 137 | 137 | ||
| 138 | static int | 138 | static int |
| 139 | pxa2xx_pcmcia_frequency_change(struct soc_pcmcia_socket *skt, | 139 | pxa2xx_pcmcia_frequency_change(struct soc_pcmcia_socket *skt, |
| 140 | unsigned long val, | 140 | unsigned long val, |
| 141 | struct cpufreq_freqs *freqs) | 141 | struct cpufreq_freqs *freqs) |
| 142 | { | 142 | { |
| 143 | #warning "it's not clear if this is right since the core CPU (N) clock has no effect on the memory (L) clock" | 143 | #warning "it's not clear if this is right since the core CPU (N) clock has no effect on the memory (L) clock" |
| 144 | switch (val) { | 144 | switch (val) { |
| 145 | case CPUFREQ_PRECHANGE: | 145 | case CPUFREQ_PRECHANGE: |
| 146 | if (freqs->new > freqs->old) { | 146 | if (freqs->new > freqs->old) { |
| 147 | debug(skt, 2, "new frequency %u.%uMHz > %u.%uMHz, " | 147 | debug(skt, 2, "new frequency %u.%uMHz > %u.%uMHz, " |
| 148 | "pre-updating\n", | 148 | "pre-updating\n", |
| 149 | freqs->new / 1000, (freqs->new / 100) % 10, | 149 | freqs->new / 1000, (freqs->new / 100) % 10, |
| 150 | freqs->old / 1000, (freqs->old / 100) % 10); | 150 | freqs->old / 1000, (freqs->old / 100) % 10); |
| 151 | pxa2xx_pcmcia_set_mcxx(skt, freqs->new); | 151 | pxa2xx_pcmcia_set_mcxx(skt, freqs->new); |
| 152 | } | 152 | } |
| 153 | break; | 153 | break; |
| 154 | 154 | ||
| 155 | case CPUFREQ_POSTCHANGE: | 155 | case CPUFREQ_POSTCHANGE: |
| 156 | if (freqs->new < freqs->old) { | 156 | if (freqs->new < freqs->old) { |
| 157 | debug(skt, 2, "new frequency %u.%uMHz < %u.%uMHz, " | 157 | debug(skt, 2, "new frequency %u.%uMHz < %u.%uMHz, " |
| 158 | "post-updating\n", | 158 | "post-updating\n", |
| 159 | freqs->new / 1000, (freqs->new / 100) % 10, | 159 | freqs->new / 1000, (freqs->new / 100) % 10, |
| 160 | freqs->old / 1000, (freqs->old / 100) % 10); | 160 | freqs->old / 1000, (freqs->old / 100) % 10); |
| 161 | pxa2xx_pcmcia_set_mcxx(skt, freqs->new); | 161 | pxa2xx_pcmcia_set_mcxx(skt, freqs->new); |
| 162 | } | 162 | } |
| 163 | break; | 163 | break; |
| 164 | } | 164 | } |
| 165 | return 0; | 165 | return 0; |
| 166 | } | 166 | } |
| 167 | #endif | 167 | #endif |
| 168 | 168 | ||
| 169 | int pxa2xx_drv_pcmcia_probe(struct device *dev) | 169 | int pxa2xx_drv_pcmcia_probe(struct device *dev) |
| 170 | { | 170 | { |
| 171 | int ret; | 171 | int ret; |
| 172 | struct pcmcia_low_level *ops; | 172 | struct pcmcia_low_level *ops; |
| 173 | int first, nr; | 173 | int first, nr; |
| 174 | 174 | ||
| 175 | if (!dev || !dev->platform_data) | 175 | if (!dev || !dev->platform_data) |
| 176 | return -ENODEV; | 176 | return -ENODEV; |
| 177 | 177 | ||
| 178 | ops = (struct pcmcia_low_level *)dev->platform_data; | 178 | ops = (struct pcmcia_low_level *)dev->platform_data; |
| 179 | first = ops->first; | 179 | first = ops->first; |
| 180 | nr = ops->nr; | 180 | nr = ops->nr; |
| 181 | 181 | ||
| 182 | /* Provide our PXA2xx specific timing routines. */ | 182 | /* Provide our PXA2xx specific timing routines. */ |
| 183 | ops->set_timing = pxa2xx_pcmcia_set_timing; | 183 | ops->set_timing = pxa2xx_pcmcia_set_timing; |
| 184 | #ifdef CONFIG_CPU_FREQ | 184 | #ifdef CONFIG_CPU_FREQ |
| 185 | ops->frequency_change = pxa2xx_pcmcia_frequency_change; | 185 | ops->frequency_change = pxa2xx_pcmcia_frequency_change; |
| 186 | #endif | 186 | #endif |
| 187 | 187 | ||
| 188 | ret = soc_common_drv_pcmcia_probe(dev, ops, first, nr); | 188 | ret = soc_common_drv_pcmcia_probe(dev, ops, first, nr); |
| 189 | 189 | ||
| 190 | if (ret == 0) { | 190 | if (ret == 0) { |
| 191 | /* | 191 | /* |
| 192 | * We have at least one socket, so set MECR:CIT | 192 | * We have at least one socket, so set MECR:CIT |
| 193 | * (Card Is There) | 193 | * (Card Is There) |
| 194 | */ | 194 | */ |
| 195 | MECR |= MECR_CIT; | 195 | MECR |= MECR_CIT; |
| 196 | 196 | ||
| 197 | /* Set MECR:NOS (Number Of Sockets) */ | 197 | /* Set MECR:NOS (Number Of Sockets) */ |
| 198 | if (nr > 1) | 198 | if (nr > 1) |
| 199 | MECR |= MECR_NOS; | 199 | MECR |= MECR_NOS; |
| 200 | else | 200 | else |
| 201 | MECR &= ~MECR_NOS; | 201 | MECR &= ~MECR_NOS; |
| 202 | } | 202 | } |
| 203 | 203 | ||
| 204 | return ret; | 204 | return ret; |
| 205 | } | 205 | } |
| 206 | EXPORT_SYMBOL(pxa2xx_drv_pcmcia_probe); | 206 | EXPORT_SYMBOL(pxa2xx_drv_pcmcia_probe); |
| 207 | 207 | ||
| 208 | static int pxa2xx_drv_pcmcia_suspend(struct device *dev, pm_message_t state, u32 level) | 208 | static int pxa2xx_drv_pcmcia_suspend(struct device *dev, pm_message_t state, u32 level) |
| 209 | { | 209 | { |
| 210 | int ret = 0; | 210 | int ret = 0; |
| 211 | if (level == SUSPEND_SAVE_STATE) | 211 | if (level == SUSPEND_SAVE_STATE) |
| 212 | ret = pcmcia_socket_dev_suspend(dev, state); | 212 | ret = pcmcia_socket_dev_suspend(dev, state); |
| 213 | return ret; | 213 | return ret; |
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | static int pxa2xx_drv_pcmcia_resume(struct device *dev, u32 level) | 216 | static int pxa2xx_drv_pcmcia_resume(struct device *dev, u32 level) |
| 217 | { | 217 | { |
| 218 | int ret = 0; | 218 | int ret = 0; |
| 219 | if (level == RESUME_RESTORE_STATE) | 219 | if (level == RESUME_RESTORE_STATE) |
| 220 | { | 220 | { |
| 221 | struct pcmcia_low_level *ops = dev->platform_data; | 221 | struct pcmcia_low_level *ops = dev->platform_data; |
| 222 | int nr = ops ? ops->nr : 0; | 222 | int nr = ops ? ops->nr : 0; |
| 223 | 223 | ||
| 224 | MECR = nr > 1 ? MECR_CIT | MECR_NOS : (nr > 0 ? MECR_CIT : 0); | 224 | MECR = nr > 1 ? MECR_CIT | MECR_NOS : (nr > 0 ? MECR_CIT : 0); |
| 225 | ret = pcmcia_socket_dev_resume(dev); | 225 | ret = pcmcia_socket_dev_resume(dev); |
| 226 | } | 226 | } |
| 227 | return ret; | 227 | return ret; |
| 228 | } | 228 | } |
| 229 | 229 | ||
| 230 | static struct device_driver pxa2xx_pcmcia_driver = { | 230 | static struct device_driver pxa2xx_pcmcia_driver = { |
| 231 | .probe = pxa2xx_drv_pcmcia_probe, | 231 | .probe = pxa2xx_drv_pcmcia_probe, |
| 232 | .remove = soc_common_drv_pcmcia_remove, | 232 | .remove = soc_common_drv_pcmcia_remove, |
| 233 | .suspend = pxa2xx_drv_pcmcia_suspend, | 233 | .suspend = pxa2xx_drv_pcmcia_suspend, |
| 234 | .resume = pxa2xx_drv_pcmcia_resume, | 234 | .resume = pxa2xx_drv_pcmcia_resume, |
| 235 | .name = "pxa2xx-pcmcia", | 235 | .name = "pxa2xx-pcmcia", |
| 236 | .bus = &platform_bus_type, | 236 | .bus = &platform_bus_type, |
| 237 | }; | 237 | }; |
| 238 | 238 | ||
| 239 | static int __init pxa2xx_pcmcia_init(void) | 239 | static int __init pxa2xx_pcmcia_init(void) |
| 240 | { | 240 | { |
| 241 | return driver_register(&pxa2xx_pcmcia_driver); | 241 | return driver_register(&pxa2xx_pcmcia_driver); |
| 242 | } | 242 | } |
| 243 | 243 | ||
| 244 | static void __exit pxa2xx_pcmcia_exit(void) | 244 | static void __exit pxa2xx_pcmcia_exit(void) |
| 245 | { | 245 | { |
| 246 | driver_unregister(&pxa2xx_pcmcia_driver); | 246 | driver_unregister(&pxa2xx_pcmcia_driver); |
| 247 | } | 247 | } |
| 248 | 248 | ||
| 249 | module_init(pxa2xx_pcmcia_init); | 249 | fs_initcall(pxa2xx_pcmcia_init); |
| 250 | module_exit(pxa2xx_pcmcia_exit); | 250 | module_exit(pxa2xx_pcmcia_exit); |
| 251 | 251 | ||
| 252 | MODULE_AUTHOR("Stefan Eletzhofer <stefan.eletzhofer@inquant.de> and Ian Molton <spyro@f2s.com>"); | 252 | MODULE_AUTHOR("Stefan Eletzhofer <stefan.eletzhofer@inquant.de> and Ian Molton <spyro@f2s.com>"); |
| 253 | MODULE_DESCRIPTION("Linux PCMCIA Card Services: PXA2xx core socket driver"); | 253 | MODULE_DESCRIPTION("Linux PCMCIA Card Services: PXA2xx core socket driver"); |
| 254 | MODULE_LICENSE("GPL"); | 254 | MODULE_LICENSE("GPL"); |
| 255 | 255 |
drivers/pcmcia/pxa2xx_mainstone.c
| 1 | /* | 1 | /* |
| 2 | * linux/drivers/pcmcia/pxa2xx_mainstone.c | 2 | * linux/drivers/pcmcia/pxa2xx_mainstone.c |
| 3 | * | 3 | * |
| 4 | * Mainstone PCMCIA specific routines. | 4 | * Mainstone PCMCIA specific routines. |
| 5 | * | 5 | * |
| 6 | * Created: May 12, 2004 | 6 | * Created: May 12, 2004 |
| 7 | * Author: Nicolas Pitre | 7 | * Author: Nicolas Pitre |
| 8 | * Copyright: MontaVista Software Inc. | 8 | * Copyright: MontaVista Software Inc. |
| 9 | * | 9 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of the GNU General Public License version 2 as | 11 | * it under the terms of the GNU General Public License version 2 as |
| 12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
| 13 | */ | 13 | */ |
| 14 | 14 | ||
| 15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
| 16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
| 17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
| 18 | #include <linux/errno.h> | 18 | #include <linux/errno.h> |
| 19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
| 20 | #include <linux/device.h> | 20 | #include <linux/device.h> |
| 21 | 21 | ||
| 22 | #include <pcmcia/ss.h> | 22 | #include <pcmcia/ss.h> |
| 23 | 23 | ||
| 24 | #include <asm/hardware.h> | 24 | #include <asm/hardware.h> |
| 25 | #include <asm/irq.h> | 25 | #include <asm/irq.h> |
| 26 | 26 | ||
| 27 | #include <asm/arch/pxa-regs.h> | 27 | #include <asm/arch/pxa-regs.h> |
| 28 | #include <asm/arch/mainstone.h> | 28 | #include <asm/arch/mainstone.h> |
| 29 | 29 | ||
| 30 | #include "soc_common.h" | 30 | #include "soc_common.h" |
| 31 | 31 | ||
| 32 | 32 | ||
| 33 | static struct pcmcia_irqs irqs[] = { | 33 | static struct pcmcia_irqs irqs[] = { |
| 34 | { 0, MAINSTONE_S0_CD_IRQ, "PCMCIA0 CD" }, | 34 | { 0, MAINSTONE_S0_CD_IRQ, "PCMCIA0 CD" }, |
| 35 | { 1, MAINSTONE_S1_CD_IRQ, "PCMCIA1 CD" }, | 35 | { 1, MAINSTONE_S1_CD_IRQ, "PCMCIA1 CD" }, |
| 36 | { 0, MAINSTONE_S0_STSCHG_IRQ, "PCMCIA0 STSCHG" }, | 36 | { 0, MAINSTONE_S0_STSCHG_IRQ, "PCMCIA0 STSCHG" }, |
| 37 | { 1, MAINSTONE_S1_STSCHG_IRQ, "PCMCIA1 STSCHG" }, | 37 | { 1, MAINSTONE_S1_STSCHG_IRQ, "PCMCIA1 STSCHG" }, |
| 38 | }; | 38 | }; |
| 39 | 39 | ||
| 40 | static int mst_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | 40 | static int mst_pcmcia_hw_init(struct soc_pcmcia_socket *skt) |
| 41 | { | 41 | { |
| 42 | /* | 42 | /* |
| 43 | * Setup default state of GPIO outputs | 43 | * Setup default state of GPIO outputs |
| 44 | * before we enable them as outputs. | 44 | * before we enable them as outputs. |
| 45 | */ | 45 | */ |
| 46 | GPSR(GPIO48_nPOE) = | 46 | GPSR(GPIO48_nPOE) = |
| 47 | GPIO_bit(GPIO48_nPOE) | | 47 | GPIO_bit(GPIO48_nPOE) | |
| 48 | GPIO_bit(GPIO49_nPWE) | | 48 | GPIO_bit(GPIO49_nPWE) | |
| 49 | GPIO_bit(GPIO50_nPIOR) | | 49 | GPIO_bit(GPIO50_nPIOR) | |
| 50 | GPIO_bit(GPIO51_nPIOW) | | 50 | GPIO_bit(GPIO51_nPIOW) | |
| 51 | GPIO_bit(GPIO85_nPCE_1) | | 51 | GPIO_bit(GPIO85_nPCE_1) | |
| 52 | GPIO_bit(GPIO54_nPCE_2); | 52 | GPIO_bit(GPIO54_nPCE_2); |
| 53 | 53 | ||
| 54 | pxa_gpio_mode(GPIO48_nPOE_MD); | 54 | pxa_gpio_mode(GPIO48_nPOE_MD); |
| 55 | pxa_gpio_mode(GPIO49_nPWE_MD); | 55 | pxa_gpio_mode(GPIO49_nPWE_MD); |
| 56 | pxa_gpio_mode(GPIO50_nPIOR_MD); | 56 | pxa_gpio_mode(GPIO50_nPIOR_MD); |
| 57 | pxa_gpio_mode(GPIO51_nPIOW_MD); | 57 | pxa_gpio_mode(GPIO51_nPIOW_MD); |
| 58 | pxa_gpio_mode(GPIO85_nPCE_1_MD); | 58 | pxa_gpio_mode(GPIO85_nPCE_1_MD); |
| 59 | pxa_gpio_mode(GPIO54_nPCE_2_MD); | 59 | pxa_gpio_mode(GPIO54_nPCE_2_MD); |
| 60 | pxa_gpio_mode(GPIO79_pSKTSEL_MD); | 60 | pxa_gpio_mode(GPIO79_pSKTSEL_MD); |
| 61 | pxa_gpio_mode(GPIO55_nPREG_MD); | 61 | pxa_gpio_mode(GPIO55_nPREG_MD); |
| 62 | pxa_gpio_mode(GPIO56_nPWAIT_MD); | 62 | pxa_gpio_mode(GPIO56_nPWAIT_MD); |
| 63 | pxa_gpio_mode(GPIO57_nIOIS16_MD); | 63 | pxa_gpio_mode(GPIO57_nIOIS16_MD); |
| 64 | 64 | ||
| 65 | skt->irq = (skt->nr == 0) ? MAINSTONE_S0_IRQ : MAINSTONE_S1_IRQ; | 65 | skt->irq = (skt->nr == 0) ? MAINSTONE_S0_IRQ : MAINSTONE_S1_IRQ; |
| 66 | return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); | 66 | return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | static void mst_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) | 69 | static void mst_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) |
| 70 | { | 70 | { |
| 71 | soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); | 71 | soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | static unsigned long mst_pcmcia_status[2]; | 74 | static unsigned long mst_pcmcia_status[2]; |
| 75 | 75 | ||
| 76 | static void mst_pcmcia_socket_state(struct soc_pcmcia_socket *skt, | 76 | static void mst_pcmcia_socket_state(struct soc_pcmcia_socket *skt, |
| 77 | struct pcmcia_state *state) | 77 | struct pcmcia_state *state) |
| 78 | { | 78 | { |
| 79 | unsigned long status, flip; | 79 | unsigned long status, flip; |
| 80 | 80 | ||
| 81 | status = (skt->nr == 0) ? MST_PCMCIA0 : MST_PCMCIA1; | 81 | status = (skt->nr == 0) ? MST_PCMCIA0 : MST_PCMCIA1; |
| 82 | flip = (status ^ mst_pcmcia_status[skt->nr]) & MST_PCMCIA_nSTSCHG_BVD1; | 82 | flip = (status ^ mst_pcmcia_status[skt->nr]) & MST_PCMCIA_nSTSCHG_BVD1; |
| 83 | 83 | ||
| 84 | /* | 84 | /* |
| 85 | * Workaround for STSCHG which can't be deasserted: | 85 | * Workaround for STSCHG which can't be deasserted: |
| 86 | * We therefore disable/enable corresponding IRQs | 86 | * We therefore disable/enable corresponding IRQs |
| 87 | * as needed to avoid IRQ locks. | 87 | * as needed to avoid IRQ locks. |
| 88 | */ | 88 | */ |
| 89 | if (flip) { | 89 | if (flip) { |
| 90 | mst_pcmcia_status[skt->nr] = status; | 90 | mst_pcmcia_status[skt->nr] = status; |
| 91 | if (status & MST_PCMCIA_nSTSCHG_BVD1) | 91 | if (status & MST_PCMCIA_nSTSCHG_BVD1) |
| 92 | enable_irq( (skt->nr == 0) ? MAINSTONE_S0_STSCHG_IRQ | 92 | enable_irq( (skt->nr == 0) ? MAINSTONE_S0_STSCHG_IRQ |
| 93 | : MAINSTONE_S1_STSCHG_IRQ ); | 93 | : MAINSTONE_S1_STSCHG_IRQ ); |
| 94 | else | 94 | else |
| 95 | disable_irq( (skt->nr == 0) ? MAINSTONE_S0_STSCHG_IRQ | 95 | disable_irq( (skt->nr == 0) ? MAINSTONE_S0_STSCHG_IRQ |
| 96 | : MAINSTONE_S1_STSCHG_IRQ ); | 96 | : MAINSTONE_S1_STSCHG_IRQ ); |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | state->detect = (status & MST_PCMCIA_nCD) ? 0 : 1; | 99 | state->detect = (status & MST_PCMCIA_nCD) ? 0 : 1; |
| 100 | state->ready = (status & MST_PCMCIA_nIRQ) ? 1 : 0; | 100 | state->ready = (status & MST_PCMCIA_nIRQ) ? 1 : 0; |
| 101 | state->bvd1 = (status & MST_PCMCIA_nSTSCHG_BVD1) ? 1 : 0; | 101 | state->bvd1 = (status & MST_PCMCIA_nSTSCHG_BVD1) ? 1 : 0; |
| 102 | state->bvd2 = (status & MST_PCMCIA_nSPKR_BVD2) ? 1 : 0; | 102 | state->bvd2 = (status & MST_PCMCIA_nSPKR_BVD2) ? 1 : 0; |
| 103 | state->vs_3v = (status & MST_PCMCIA_nVS1) ? 0 : 1; | 103 | state->vs_3v = (status & MST_PCMCIA_nVS1) ? 0 : 1; |
| 104 | state->vs_Xv = (status & MST_PCMCIA_nVS2) ? 0 : 1; | 104 | state->vs_Xv = (status & MST_PCMCIA_nVS2) ? 0 : 1; |
| 105 | state->wrprot = 0; /* not available */ | 105 | state->wrprot = 0; /* not available */ |
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | static int mst_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, | 108 | static int mst_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, |
| 109 | const socket_state_t *state) | 109 | const socket_state_t *state) |
| 110 | { | 110 | { |
| 111 | unsigned long power = 0; | 111 | unsigned long power = 0; |
| 112 | int ret = 0; | 112 | int ret = 0; |
| 113 | 113 | ||
| 114 | switch (state->Vcc) { | 114 | switch (state->Vcc) { |
| 115 | case 0: power |= MST_PCMCIA_PWR_VCC_0; break; | 115 | case 0: power |= MST_PCMCIA_PWR_VCC_0; break; |
| 116 | case 33: power |= MST_PCMCIA_PWR_VCC_33; break; | 116 | case 33: power |= MST_PCMCIA_PWR_VCC_33; break; |
| 117 | case 50: power |= MST_PCMCIA_PWR_VCC_50; break; | 117 | case 50: power |= MST_PCMCIA_PWR_VCC_50; break; |
| 118 | default: | 118 | default: |
| 119 | printk(KERN_ERR "%s(): bad Vcc %u\n", | 119 | printk(KERN_ERR "%s(): bad Vcc %u\n", |
| 120 | __FUNCTION__, state->Vcc); | 120 | __FUNCTION__, state->Vcc); |
| 121 | ret = -1; | 121 | ret = -1; |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | switch (state->Vpp) { | 124 | switch (state->Vpp) { |
| 125 | case 0: power |= MST_PCMCIA_PWR_VPP_0; break; | 125 | case 0: power |= MST_PCMCIA_PWR_VPP_0; break; |
| 126 | case 120: power |= MST_PCMCIA_PWR_VPP_120; break; | 126 | case 120: power |= MST_PCMCIA_PWR_VPP_120; break; |
| 127 | default: | 127 | default: |
| 128 | if(state->Vpp == state->Vcc) { | 128 | if(state->Vpp == state->Vcc) { |
| 129 | power |= MST_PCMCIA_PWR_VPP_VCC; | 129 | power |= MST_PCMCIA_PWR_VPP_VCC; |
| 130 | } else { | 130 | } else { |
| 131 | printk(KERN_ERR "%s(): bad Vpp %u\n", | 131 | printk(KERN_ERR "%s(): bad Vpp %u\n", |
| 132 | __FUNCTION__, state->Vpp); | 132 | __FUNCTION__, state->Vpp); |
| 133 | ret = -1; | 133 | ret = -1; |
| 134 | } | 134 | } |
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | if (state->flags & SS_RESET) | 137 | if (state->flags & SS_RESET) |
| 138 | power |= MST_PCMCIA_RESET; | 138 | power |= MST_PCMCIA_RESET; |
| 139 | 139 | ||
| 140 | switch (skt->nr) { | 140 | switch (skt->nr) { |
| 141 | case 0: MST_PCMCIA0 = power; break; | 141 | case 0: MST_PCMCIA0 = power; break; |
| 142 | case 1: MST_PCMCIA1 = power; break; | 142 | case 1: MST_PCMCIA1 = power; break; |
| 143 | default: ret = -1; | 143 | default: ret = -1; |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | return ret; | 146 | return ret; |
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | static void mst_pcmcia_socket_init(struct soc_pcmcia_socket *skt) | 149 | static void mst_pcmcia_socket_init(struct soc_pcmcia_socket *skt) |
| 150 | { | 150 | { |
| 151 | } | 151 | } |
| 152 | 152 | ||
| 153 | static void mst_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) | 153 | static void mst_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) |
| 154 | { | 154 | { |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | static struct pcmcia_low_level mst_pcmcia_ops = { | 157 | static struct pcmcia_low_level mst_pcmcia_ops = { |
| 158 | .owner = THIS_MODULE, | 158 | .owner = THIS_MODULE, |
| 159 | .hw_init = mst_pcmcia_hw_init, | 159 | .hw_init = mst_pcmcia_hw_init, |
| 160 | .hw_shutdown = mst_pcmcia_hw_shutdown, | 160 | .hw_shutdown = mst_pcmcia_hw_shutdown, |
| 161 | .socket_state = mst_pcmcia_socket_state, | 161 | .socket_state = mst_pcmcia_socket_state, |
| 162 | .configure_socket = mst_pcmcia_configure_socket, | 162 | .configure_socket = mst_pcmcia_configure_socket, |
| 163 | .socket_init = mst_pcmcia_socket_init, | 163 | .socket_init = mst_pcmcia_socket_init, |
| 164 | .socket_suspend = mst_pcmcia_socket_suspend, | 164 | .socket_suspend = mst_pcmcia_socket_suspend, |
| 165 | .nr = 2, | 165 | .nr = 2, |
| 166 | }; | 166 | }; |
| 167 | 167 | ||
| 168 | static struct platform_device *mst_pcmcia_device; | 168 | static struct platform_device *mst_pcmcia_device; |
| 169 | 169 | ||
| 170 | static int __init mst_pcmcia_init(void) | 170 | static int __init mst_pcmcia_init(void) |
| 171 | { | 171 | { |
| 172 | int ret; | 172 | int ret; |
| 173 | 173 | ||
| 174 | mst_pcmcia_device = kmalloc(sizeof(*mst_pcmcia_device), GFP_KERNEL); | 174 | mst_pcmcia_device = kmalloc(sizeof(*mst_pcmcia_device), GFP_KERNEL); |
| 175 | if (!mst_pcmcia_device) | 175 | if (!mst_pcmcia_device) |
| 176 | return -ENOMEM; | 176 | return -ENOMEM; |
| 177 | memset(mst_pcmcia_device, 0, sizeof(*mst_pcmcia_device)); | 177 | memset(mst_pcmcia_device, 0, sizeof(*mst_pcmcia_device)); |
| 178 | mst_pcmcia_device->name = "pxa2xx-pcmcia"; | 178 | mst_pcmcia_device->name = "pxa2xx-pcmcia"; |
| 179 | mst_pcmcia_device->dev.platform_data = &mst_pcmcia_ops; | 179 | mst_pcmcia_device->dev.platform_data = &mst_pcmcia_ops; |
| 180 | 180 | ||
| 181 | ret = platform_device_register(mst_pcmcia_device); | 181 | ret = platform_device_register(mst_pcmcia_device); |
| 182 | if (ret) | 182 | if (ret) |
| 183 | kfree(mst_pcmcia_device); | 183 | kfree(mst_pcmcia_device); |
| 184 | 184 | ||
| 185 | return ret; | 185 | return ret; |
| 186 | } | 186 | } |
| 187 | 187 | ||
| 188 | static void __exit mst_pcmcia_exit(void) | 188 | static void __exit mst_pcmcia_exit(void) |
| 189 | { | 189 | { |
| 190 | /* | 190 | /* |
| 191 | * This call is supposed to free our mst_pcmcia_device. | 191 | * This call is supposed to free our mst_pcmcia_device. |
| 192 | * Unfortunately platform_device don't have a free method, and | 192 | * Unfortunately platform_device don't have a free method, and |
| 193 | * we can't assume it's free of any reference at this point so we | 193 | * we can't assume it's free of any reference at this point so we |
| 194 | * can't free it either. | 194 | * can't free it either. |
| 195 | */ | 195 | */ |
| 196 | platform_device_unregister(mst_pcmcia_device); | 196 | platform_device_unregister(mst_pcmcia_device); |
| 197 | } | 197 | } |
| 198 | 198 | ||
| 199 | module_init(mst_pcmcia_init); | 199 | fs_initcall(mst_pcmcia_init); |
| 200 | module_exit(mst_pcmcia_exit); | 200 | module_exit(mst_pcmcia_exit); |
| 201 | 201 | ||
| 202 | MODULE_LICENSE("GPL"); | 202 | MODULE_LICENSE("GPL"); |
| 203 | 203 |
drivers/pcmcia/pxa2xx_sharpsl.c
| 1 | /* | 1 | /* |
| 2 | * Sharp SL-C7xx Series PCMCIA routines | 2 | * Sharp SL-C7xx Series PCMCIA routines |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2004-2005 Richard Purdie | 4 | * Copyright (c) 2004-2005 Richard Purdie |
| 5 | * | 5 | * |
| 6 | * Based on Sharp's 2.4 kernel patches and pxa2xx_mainstone.c | 6 | * Based on Sharp's 2.4 kernel patches and pxa2xx_mainstone.c |
| 7 | * | 7 | * |
| 8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
| 9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
| 10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
| 11 | * | 11 | * |
| 12 | */ | 12 | */ |
| 13 | 13 | ||
| 14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
| 15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
| 16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
| 17 | #include <linux/errno.h> | 17 | #include <linux/errno.h> |
| 18 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
| 19 | #include <linux/device.h> | 19 | #include <linux/device.h> |
| 20 | 20 | ||
| 21 | #include <asm/hardware.h> | 21 | #include <asm/hardware.h> |
| 22 | #include <asm/irq.h> | 22 | #include <asm/irq.h> |
| 23 | 23 | ||
| 24 | #include <asm/hardware/scoop.h> | 24 | #include <asm/hardware/scoop.h> |
| 25 | #include <asm/arch/corgi.h> | 25 | #include <asm/arch/corgi.h> |
| 26 | #include <asm/arch/pxa-regs.h> | 26 | #include <asm/arch/pxa-regs.h> |
| 27 | 27 | ||
| 28 | #include "soc_common.h" | 28 | #include "soc_common.h" |
| 29 | 29 | ||
| 30 | #define NO_KEEP_VS 0x0001 | 30 | #define NO_KEEP_VS 0x0001 |
| 31 | 31 | ||
| 32 | static unsigned char keep_vs; | 32 | static unsigned char keep_vs; |
| 33 | static unsigned char keep_rd; | 33 | static unsigned char keep_rd; |
| 34 | 34 | ||
| 35 | static struct pcmcia_irqs irqs[] = { | 35 | static struct pcmcia_irqs irqs[] = { |
| 36 | { 0, CORGI_IRQ_GPIO_CF_CD, "PCMCIA0 CD"}, | 36 | { 0, CORGI_IRQ_GPIO_CF_CD, "PCMCIA0 CD"}, |
| 37 | }; | 37 | }; |
| 38 | 38 | ||
| 39 | static void sharpsl_pcmcia_init_reset(void) | 39 | static void sharpsl_pcmcia_init_reset(void) |
| 40 | { | 40 | { |
| 41 | reset_scoop(&corgiscoop_device.dev); | 41 | reset_scoop(&corgiscoop_device.dev); |
| 42 | keep_vs = NO_KEEP_VS; | 42 | keep_vs = NO_KEEP_VS; |
| 43 | keep_rd = 0; | 43 | keep_rd = 0; |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | 46 | static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt) |
| 47 | { | 47 | { |
| 48 | int ret; | 48 | int ret; |
| 49 | 49 | ||
| 50 | /* | 50 | /* |
| 51 | * Setup default state of GPIO outputs | 51 | * Setup default state of GPIO outputs |
| 52 | * before we enable them as outputs. | 52 | * before we enable them as outputs. |
| 53 | */ | 53 | */ |
| 54 | GPSR(GPIO48_nPOE) = | 54 | GPSR(GPIO48_nPOE) = |
| 55 | GPIO_bit(GPIO48_nPOE) | | 55 | GPIO_bit(GPIO48_nPOE) | |
| 56 | GPIO_bit(GPIO49_nPWE) | | 56 | GPIO_bit(GPIO49_nPWE) | |
| 57 | GPIO_bit(GPIO50_nPIOR) | | 57 | GPIO_bit(GPIO50_nPIOR) | |
| 58 | GPIO_bit(GPIO51_nPIOW) | | 58 | GPIO_bit(GPIO51_nPIOW) | |
| 59 | GPIO_bit(GPIO52_nPCE_1) | | 59 | GPIO_bit(GPIO52_nPCE_1) | |
| 60 | GPIO_bit(GPIO53_nPCE_2); | 60 | GPIO_bit(GPIO53_nPCE_2); |
| 61 | 61 | ||
| 62 | pxa_gpio_mode(GPIO48_nPOE_MD); | 62 | pxa_gpio_mode(GPIO48_nPOE_MD); |
| 63 | pxa_gpio_mode(GPIO49_nPWE_MD); | 63 | pxa_gpio_mode(GPIO49_nPWE_MD); |
| 64 | pxa_gpio_mode(GPIO50_nPIOR_MD); | 64 | pxa_gpio_mode(GPIO50_nPIOR_MD); |
| 65 | pxa_gpio_mode(GPIO51_nPIOW_MD); | 65 | pxa_gpio_mode(GPIO51_nPIOW_MD); |
| 66 | pxa_gpio_mode(GPIO52_nPCE_1_MD); | 66 | pxa_gpio_mode(GPIO52_nPCE_1_MD); |
| 67 | pxa_gpio_mode(GPIO53_nPCE_2_MD); | 67 | pxa_gpio_mode(GPIO53_nPCE_2_MD); |
| 68 | pxa_gpio_mode(GPIO54_pSKTSEL_MD); | 68 | pxa_gpio_mode(GPIO54_pSKTSEL_MD); |
| 69 | pxa_gpio_mode(GPIO55_nPREG_MD); | 69 | pxa_gpio_mode(GPIO55_nPREG_MD); |
| 70 | pxa_gpio_mode(GPIO56_nPWAIT_MD); | 70 | pxa_gpio_mode(GPIO56_nPWAIT_MD); |
| 71 | pxa_gpio_mode(GPIO57_nIOIS16_MD); | 71 | pxa_gpio_mode(GPIO57_nIOIS16_MD); |
| 72 | 72 | ||
| 73 | /* Register interrupts */ | 73 | /* Register interrupts */ |
| 74 | ret = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); | 74 | ret = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); |
| 75 | 75 | ||
| 76 | if (ret) { | 76 | if (ret) { |
| 77 | printk(KERN_ERR "Request for Compact Flash IRQ failed\n"); | 77 | printk(KERN_ERR "Request for Compact Flash IRQ failed\n"); |
| 78 | return ret; | 78 | return ret; |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | /* Enable interrupt */ | 81 | /* Enable interrupt */ |
| 82 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR, 0x00C0); | 82 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR, 0x00C0); |
| 83 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR, 0x0101); | 83 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR, 0x0101); |
| 84 | keep_vs = NO_KEEP_VS; | 84 | keep_vs = NO_KEEP_VS; |
| 85 | 85 | ||
| 86 | skt->irq = CORGI_IRQ_GPIO_CF_IRQ; | 86 | skt->irq = CORGI_IRQ_GPIO_CF_IRQ; |
| 87 | 87 | ||
| 88 | return 0; | 88 | return 0; |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | static void sharpsl_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) | 91 | static void sharpsl_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) |
| 92 | { | 92 | { |
| 93 | soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); | 93 | soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); |
| 94 | 94 | ||
| 95 | /* CF_BUS_OFF */ | 95 | /* CF_BUS_OFF */ |
| 96 | sharpsl_pcmcia_init_reset(); | 96 | sharpsl_pcmcia_init_reset(); |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | 99 | ||
| 100 | static void sharpsl_pcmcia_socket_state(struct soc_pcmcia_socket *skt, | 100 | static void sharpsl_pcmcia_socket_state(struct soc_pcmcia_socket *skt, |
| 101 | struct pcmcia_state *state) | 101 | struct pcmcia_state *state) |
| 102 | { | 102 | { |
| 103 | unsigned short cpr, csr; | 103 | unsigned short cpr, csr; |
| 104 | 104 | ||
| 105 | cpr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR); | 105 | cpr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR); |
| 106 | 106 | ||
| 107 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_IRM, 0x00FF); | 107 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_IRM, 0x00FF); |
| 108 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_ISR, 0x0000); | 108 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_ISR, 0x0000); |
| 109 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_IRM, 0x0000); | 109 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_IRM, 0x0000); |
| 110 | csr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CSR); | 110 | csr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CSR); |
| 111 | if (csr & 0x0004) { | 111 | if (csr & 0x0004) { |
| 112 | /* card eject */ | 112 | /* card eject */ |
| 113 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000); | 113 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000); |
| 114 | keep_vs = NO_KEEP_VS; | 114 | keep_vs = NO_KEEP_VS; |
| 115 | } | 115 | } |
| 116 | else if (!(keep_vs & NO_KEEP_VS)) { | 116 | else if (!(keep_vs & NO_KEEP_VS)) { |
| 117 | /* keep vs1,vs2 */ | 117 | /* keep vs1,vs2 */ |
| 118 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000); | 118 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000); |
| 119 | csr |= keep_vs; | 119 | csr |= keep_vs; |
| 120 | } | 120 | } |
| 121 | else if (cpr & 0x0003) { | 121 | else if (cpr & 0x0003) { |
| 122 | /* power on */ | 122 | /* power on */ |
| 123 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000); | 123 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000); |
| 124 | keep_vs = (csr & 0x00C0); | 124 | keep_vs = (csr & 0x00C0); |
| 125 | } | 125 | } |
| 126 | else { | 126 | else { |
| 127 | /* card detect */ | 127 | /* card detect */ |
| 128 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0002); | 128 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0002); |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | state->detect = (csr & 0x0004) ? 0 : 1; | 131 | state->detect = (csr & 0x0004) ? 0 : 1; |
| 132 | state->ready = (csr & 0x0002) ? 1 : 0; | 132 | state->ready = (csr & 0x0002) ? 1 : 0; |
| 133 | state->bvd1 = (csr & 0x0010) ? 1 : 0; | 133 | state->bvd1 = (csr & 0x0010) ? 1 : 0; |
| 134 | state->bvd2 = (csr & 0x0020) ? 1 : 0; | 134 | state->bvd2 = (csr & 0x0020) ? 1 : 0; |
| 135 | state->wrprot = (csr & 0x0008) ? 1 : 0; | 135 | state->wrprot = (csr & 0x0008) ? 1 : 0; |
| 136 | state->vs_3v = (csr & 0x0040) ? 0 : 1; | 136 | state->vs_3v = (csr & 0x0040) ? 0 : 1; |
| 137 | state->vs_Xv = (csr & 0x0080) ? 0 : 1; | 137 | state->vs_Xv = (csr & 0x0080) ? 0 : 1; |
| 138 | 138 | ||
| 139 | if ((cpr & 0x0080) && ((cpr & 0x8040) != 0x8040)) { | 139 | if ((cpr & 0x0080) && ((cpr & 0x8040) != 0x8040)) { |
| 140 | printk(KERN_ERR "sharpsl_pcmcia_socket_state(): CPR=%04X, Low voltage!\n", cpr); | 140 | printk(KERN_ERR "sharpsl_pcmcia_socket_state(): CPR=%04X, Low voltage!\n", cpr); |
| 141 | } | 141 | } |
| 142 | 142 | ||
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | 145 | ||
| 146 | static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, | 146 | static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, |
| 147 | const socket_state_t *state) | 147 | const socket_state_t *state) |
| 148 | { | 148 | { |
| 149 | unsigned long flags; | 149 | unsigned long flags; |
| 150 | 150 | ||
| 151 | unsigned short cpr, ncpr, ccr, nccr, mcr, nmcr, imr, nimr; | 151 | unsigned short cpr, ncpr, ccr, nccr, mcr, nmcr, imr, nimr; |
| 152 | 152 | ||
| 153 | switch (state->Vcc) { | 153 | switch (state->Vcc) { |
| 154 | case 0: break; | 154 | case 0: break; |
| 155 | case 33: break; | 155 | case 33: break; |
| 156 | case 50: break; | 156 | case 50: break; |
| 157 | default: | 157 | default: |
| 158 | printk(KERN_ERR "sharpsl_pcmcia_configure_socket(): bad Vcc %u\n", state->Vcc); | 158 | printk(KERN_ERR "sharpsl_pcmcia_configure_socket(): bad Vcc %u\n", state->Vcc); |
| 159 | return -1; | 159 | return -1; |
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | if ((state->Vpp!=state->Vcc) && (state->Vpp!=0)) { | 162 | if ((state->Vpp!=state->Vcc) && (state->Vpp!=0)) { |
| 163 | printk(KERN_ERR "CF slot cannot support Vpp %u\n", state->Vpp); | 163 | printk(KERN_ERR "CF slot cannot support Vpp %u\n", state->Vpp); |
| 164 | return -1; | 164 | return -1; |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | local_irq_save(flags); | 167 | local_irq_save(flags); |
| 168 | 168 | ||
| 169 | nmcr = (mcr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR)) & ~0x0010; | 169 | nmcr = (mcr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR)) & ~0x0010; |
| 170 | ncpr = (cpr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR)) & ~0x0083; | 170 | ncpr = (cpr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR)) & ~0x0083; |
| 171 | nccr = (ccr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CCR)) & ~0x0080; | 171 | nccr = (ccr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CCR)) & ~0x0080; |
| 172 | nimr = (imr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR)) & ~0x003E; | 172 | nimr = (imr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR)) & ~0x003E; |
| 173 | 173 | ||
| 174 | ncpr |= (state->Vcc == 33) ? 0x0001 : | 174 | ncpr |= (state->Vcc == 33) ? 0x0001 : |
| 175 | (state->Vcc == 50) ? 0x0002 : 0; | 175 | (state->Vcc == 50) ? 0x0002 : 0; |
| 176 | nmcr |= (state->flags&SS_IOCARD) ? 0x0010 : 0; | 176 | nmcr |= (state->flags&SS_IOCARD) ? 0x0010 : 0; |
| 177 | ncpr |= (state->flags&SS_OUTPUT_ENA) ? 0x0080 : 0; | 177 | ncpr |= (state->flags&SS_OUTPUT_ENA) ? 0x0080 : 0; |
| 178 | nccr |= (state->flags&SS_RESET)? 0x0080: 0; | 178 | nccr |= (state->flags&SS_RESET)? 0x0080: 0; |
| 179 | nimr |= ((skt->status&SS_DETECT) ? 0x0004 : 0)| | 179 | nimr |= ((skt->status&SS_DETECT) ? 0x0004 : 0)| |
| 180 | ((skt->status&SS_READY) ? 0x0002 : 0)| | 180 | ((skt->status&SS_READY) ? 0x0002 : 0)| |
| 181 | ((skt->status&SS_BATDEAD)? 0x0010 : 0)| | 181 | ((skt->status&SS_BATDEAD)? 0x0010 : 0)| |
| 182 | ((skt->status&SS_BATWARN)? 0x0020 : 0)| | 182 | ((skt->status&SS_BATWARN)? 0x0020 : 0)| |
| 183 | ((skt->status&SS_STSCHG) ? 0x0010 : 0)| | 183 | ((skt->status&SS_STSCHG) ? 0x0010 : 0)| |
| 184 | ((skt->status&SS_WRPROT) ? 0x0008 : 0); | 184 | ((skt->status&SS_WRPROT) ? 0x0008 : 0); |
| 185 | 185 | ||
| 186 | if (!(ncpr & 0x0003)) { | 186 | if (!(ncpr & 0x0003)) { |
| 187 | keep_rd = 0; | 187 | keep_rd = 0; |
| 188 | } else if (!keep_rd) { | 188 | } else if (!keep_rd) { |
| 189 | if (nccr & 0x0080) | 189 | if (nccr & 0x0080) |
| 190 | keep_rd = 1; | 190 | keep_rd = 1; |
| 191 | else | 191 | else |
| 192 | nccr |= 0x0080; | 192 | nccr |= 0x0080; |
| 193 | } | 193 | } |
| 194 | 194 | ||
| 195 | if (mcr != nmcr) | 195 | if (mcr != nmcr) |
| 196 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR, nmcr); | 196 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR, nmcr); |
| 197 | if (cpr != ncpr) | 197 | if (cpr != ncpr) |
| 198 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR, ncpr); | 198 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR, ncpr); |
| 199 | if (ccr != nccr) | 199 | if (ccr != nccr) |
| 200 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_CCR, nccr); | 200 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_CCR, nccr); |
| 201 | if (imr != nimr) | 201 | if (imr != nimr) |
| 202 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR, nimr); | 202 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR, nimr); |
| 203 | 203 | ||
| 204 | local_irq_restore(flags); | 204 | local_irq_restore(flags); |
| 205 | 205 | ||
| 206 | return 0; | 206 | return 0; |
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | static void sharpsl_pcmcia_socket_init(struct soc_pcmcia_socket *skt) | 209 | static void sharpsl_pcmcia_socket_init(struct soc_pcmcia_socket *skt) |
| 210 | { | 210 | { |
| 211 | } | 211 | } |
| 212 | 212 | ||
| 213 | static void sharpsl_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) | 213 | static void sharpsl_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) |
| 214 | { | 214 | { |
| 215 | } | 215 | } |
| 216 | 216 | ||
| 217 | static struct pcmcia_low_level sharpsl_pcmcia_ops = { | 217 | static struct pcmcia_low_level sharpsl_pcmcia_ops = { |
| 218 | .owner = THIS_MODULE, | 218 | .owner = THIS_MODULE, |
| 219 | .hw_init = sharpsl_pcmcia_hw_init, | 219 | .hw_init = sharpsl_pcmcia_hw_init, |
| 220 | .hw_shutdown = sharpsl_pcmcia_hw_shutdown, | 220 | .hw_shutdown = sharpsl_pcmcia_hw_shutdown, |
| 221 | .socket_state = sharpsl_pcmcia_socket_state, | 221 | .socket_state = sharpsl_pcmcia_socket_state, |
| 222 | .configure_socket = sharpsl_pcmcia_configure_socket, | 222 | .configure_socket = sharpsl_pcmcia_configure_socket, |
| 223 | .socket_init = sharpsl_pcmcia_socket_init, | 223 | .socket_init = sharpsl_pcmcia_socket_init, |
| 224 | .socket_suspend = sharpsl_pcmcia_socket_suspend, | 224 | .socket_suspend = sharpsl_pcmcia_socket_suspend, |
| 225 | .first = 0, | 225 | .first = 0, |
| 226 | .nr = 1, | 226 | .nr = 1, |
| 227 | }; | 227 | }; |
| 228 | 228 | ||
| 229 | static struct platform_device *sharpsl_pcmcia_device; | 229 | static struct platform_device *sharpsl_pcmcia_device; |
| 230 | 230 | ||
| 231 | static int __init sharpsl_pcmcia_init(void) | 231 | static int __init sharpsl_pcmcia_init(void) |
| 232 | { | 232 | { |
| 233 | int ret; | 233 | int ret; |
| 234 | 234 | ||
| 235 | sharpsl_pcmcia_device = kmalloc(sizeof(*sharpsl_pcmcia_device), GFP_KERNEL); | 235 | sharpsl_pcmcia_device = kmalloc(sizeof(*sharpsl_pcmcia_device), GFP_KERNEL); |
| 236 | if (!sharpsl_pcmcia_device) | 236 | if (!sharpsl_pcmcia_device) |
| 237 | return -ENOMEM; | 237 | return -ENOMEM; |
| 238 | memset(sharpsl_pcmcia_device, 0, sizeof(*sharpsl_pcmcia_device)); | 238 | memset(sharpsl_pcmcia_device, 0, sizeof(*sharpsl_pcmcia_device)); |
| 239 | sharpsl_pcmcia_device->name = "pxa2xx-pcmcia"; | 239 | sharpsl_pcmcia_device->name = "pxa2xx-pcmcia"; |
| 240 | sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops; | 240 | sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops; |
| 241 | 241 | ||
| 242 | ret = platform_device_register(sharpsl_pcmcia_device); | 242 | ret = platform_device_register(sharpsl_pcmcia_device); |
| 243 | if (ret) | 243 | if (ret) |
| 244 | kfree(sharpsl_pcmcia_device); | 244 | kfree(sharpsl_pcmcia_device); |
| 245 | 245 | ||
| 246 | return ret; | 246 | return ret; |
| 247 | } | 247 | } |
| 248 | 248 | ||
| 249 | static void __exit sharpsl_pcmcia_exit(void) | 249 | static void __exit sharpsl_pcmcia_exit(void) |
| 250 | { | 250 | { |
| 251 | /* | 251 | /* |
| 252 | * This call is supposed to free our sharpsl_pcmcia_device. | 252 | * This call is supposed to free our sharpsl_pcmcia_device. |
| 253 | * Unfortunately platform_device don't have a free method, and | 253 | * Unfortunately platform_device don't have a free method, and |
| 254 | * we can't assume it's free of any reference at this point so we | 254 | * we can't assume it's free of any reference at this point so we |
| 255 | * can't free it either. | 255 | * can't free it either. |
| 256 | */ | 256 | */ |
| 257 | platform_device_unregister(sharpsl_pcmcia_device); | 257 | platform_device_unregister(sharpsl_pcmcia_device); |
| 258 | } | 258 | } |
| 259 | 259 | ||
| 260 | module_init(sharpsl_pcmcia_init); | 260 | fs_initcall(sharpsl_pcmcia_init); |
| 261 | module_exit(sharpsl_pcmcia_exit); | 261 | module_exit(sharpsl_pcmcia_exit); |
| 262 | 262 | ||
| 263 | MODULE_DESCRIPTION("Sharp SL Series PCMCIA Support"); | 263 | MODULE_DESCRIPTION("Sharp SL Series PCMCIA Support"); |
| 264 | MODULE_LICENSE("GPL"); | 264 | MODULE_LICENSE("GPL"); |
| 265 | 265 |
drivers/pcmcia/sa1100_generic.c
| 1 | /*====================================================================== | 1 | /*====================================================================== |
| 2 | 2 | ||
| 3 | Device driver for the PCMCIA control functionality of StrongARM | 3 | Device driver for the PCMCIA control functionality of StrongARM |
| 4 | SA-1100 microprocessors. | 4 | SA-1100 microprocessors. |
| 5 | 5 | ||
| 6 | The contents of this file are subject to the Mozilla Public | 6 | The contents of this file are subject to the Mozilla Public |
| 7 | License Version 1.1 (the "License"); you may not use this file | 7 | License Version 1.1 (the "License"); you may not use this file |
| 8 | except in compliance with the License. You may obtain a copy of | 8 | except in compliance with the License. You may obtain a copy of |
| 9 | the License at http://www.mozilla.org/MPL/ | 9 | the License at http://www.mozilla.org/MPL/ |
| 10 | 10 | ||
| 11 | Software distributed under the License is distributed on an "AS | 11 | Software distributed under the License is distributed on an "AS |
| 12 | IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or | 12 | IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or |
| 13 | implied. See the License for the specific language governing | 13 | implied. See the License for the specific language governing |
| 14 | rights and limitations under the License. | 14 | rights and limitations under the License. |
| 15 | 15 | ||
| 16 | The initial developer of the original code is John G. Dorsey | 16 | The initial developer of the original code is John G. Dorsey |
| 17 | <john+@cs.cmu.edu>. Portions created by John G. Dorsey are | 17 | <john+@cs.cmu.edu>. Portions created by John G. Dorsey are |
| 18 | Copyright (C) 1999 John G. Dorsey. All Rights Reserved. | 18 | Copyright (C) 1999 John G. Dorsey. All Rights Reserved. |
| 19 | 19 | ||
| 20 | Alternatively, the contents of this file may be used under the | 20 | Alternatively, the contents of this file may be used under the |
| 21 | terms of the GNU Public License version 2 (the "GPL"), in which | 21 | terms of the GNU Public License version 2 (the "GPL"), in which |
| 22 | case the provisions of the GPL are applicable instead of the | 22 | case the provisions of the GPL are applicable instead of the |
| 23 | above. If you wish to allow the use of your version of this file | 23 | above. If you wish to allow the use of your version of this file |
| 24 | only under the terms of the GPL and not to allow others to use | 24 | only under the terms of the GPL and not to allow others to use |
| 25 | your version of this file under the MPL, indicate your decision | 25 | your version of this file under the MPL, indicate your decision |
| 26 | by deleting the provisions above and replace them with the notice | 26 | by deleting the provisions above and replace them with the notice |
| 27 | and other provisions required by the GPL. If you do not delete | 27 | and other provisions required by the GPL. If you do not delete |
| 28 | the provisions above, a recipient may use your version of this | 28 | the provisions above, a recipient may use your version of this |
| 29 | file under either the MPL or the GPL. | 29 | file under either the MPL or the GPL. |
| 30 | 30 | ||
| 31 | ======================================================================*/ | 31 | ======================================================================*/ |
| 32 | 32 | ||
| 33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
| 34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
| 35 | #include <linux/config.h> | 35 | #include <linux/config.h> |
| 36 | 36 | ||
| 37 | #include <pcmcia/cs_types.h> | 37 | #include <pcmcia/cs_types.h> |
| 38 | #include <pcmcia/cs.h> | 38 | #include <pcmcia/cs.h> |
| 39 | #include <pcmcia/ss.h> | 39 | #include <pcmcia/ss.h> |
| 40 | 40 | ||
| 41 | #include "sa1100_generic.h" | 41 | #include "sa1100_generic.h" |
| 42 | 42 | ||
| 43 | static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = { | 43 | static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = { |
| 44 | #ifdef CONFIG_SA1100_ASSABET | 44 | #ifdef CONFIG_SA1100_ASSABET |
| 45 | pcmcia_assabet_init, | 45 | pcmcia_assabet_init, |
| 46 | #endif | 46 | #endif |
| 47 | #ifdef CONFIG_SA1100_CERF | 47 | #ifdef CONFIG_SA1100_CERF |
| 48 | pcmcia_cerf_init, | 48 | pcmcia_cerf_init, |
| 49 | #endif | 49 | #endif |
| 50 | #ifdef CONFIG_SA1100_H3600 | 50 | #ifdef CONFIG_SA1100_H3600 |
| 51 | pcmcia_h3600_init, | 51 | pcmcia_h3600_init, |
| 52 | #endif | 52 | #endif |
| 53 | #ifdef CONFIG_SA1100_SHANNON | 53 | #ifdef CONFIG_SA1100_SHANNON |
| 54 | pcmcia_shannon_init, | 54 | pcmcia_shannon_init, |
| 55 | #endif | 55 | #endif |
| 56 | #ifdef CONFIG_SA1100_SIMPAD | 56 | #ifdef CONFIG_SA1100_SIMPAD |
| 57 | pcmcia_simpad_init, | 57 | pcmcia_simpad_init, |
| 58 | #endif | 58 | #endif |
| 59 | }; | 59 | }; |
| 60 | 60 | ||
| 61 | static int sa11x0_drv_pcmcia_probe(struct device *dev) | 61 | static int sa11x0_drv_pcmcia_probe(struct device *dev) |
| 62 | { | 62 | { |
| 63 | int i, ret = -ENODEV; | 63 | int i, ret = -ENODEV; |
| 64 | 64 | ||
| 65 | /* | 65 | /* |
| 66 | * Initialise any "on-board" PCMCIA sockets. | 66 | * Initialise any "on-board" PCMCIA sockets. |
| 67 | */ | 67 | */ |
| 68 | for (i = 0; i < ARRAY_SIZE(sa11x0_pcmcia_hw_init); i++) { | 68 | for (i = 0; i < ARRAY_SIZE(sa11x0_pcmcia_hw_init); i++) { |
| 69 | ret = sa11x0_pcmcia_hw_init[i](dev); | 69 | ret = sa11x0_pcmcia_hw_init[i](dev); |
| 70 | if (ret == 0) | 70 | if (ret == 0) |
| 71 | break; | 71 | break; |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | return ret; | 74 | return ret; |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | static int sa11x0_drv_pcmcia_suspend(struct device *dev, pm_message_t state, u32 level) | 77 | static int sa11x0_drv_pcmcia_suspend(struct device *dev, pm_message_t state, u32 level) |
| 78 | { | 78 | { |
| 79 | int ret = 0; | 79 | int ret = 0; |
| 80 | if (level == SUSPEND_SAVE_STATE) | 80 | if (level == SUSPEND_SAVE_STATE) |
| 81 | ret = pcmcia_socket_dev_suspend(dev, state); | 81 | ret = pcmcia_socket_dev_suspend(dev, state); |
| 82 | return ret; | 82 | return ret; |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | static int sa11x0_drv_pcmcia_resume(struct device *dev, u32 level) | 85 | static int sa11x0_drv_pcmcia_resume(struct device *dev, u32 level) |
| 86 | { | 86 | { |
| 87 | int ret = 0; | 87 | int ret = 0; |
| 88 | if (level == RESUME_RESTORE_STATE) | 88 | if (level == RESUME_RESTORE_STATE) |
| 89 | ret = pcmcia_socket_dev_resume(dev); | 89 | ret = pcmcia_socket_dev_resume(dev); |
| 90 | return ret; | 90 | return ret; |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | static struct device_driver sa11x0_pcmcia_driver = { | 93 | static struct device_driver sa11x0_pcmcia_driver = { |
| 94 | .probe = sa11x0_drv_pcmcia_probe, | 94 | .probe = sa11x0_drv_pcmcia_probe, |
| 95 | .remove = soc_common_drv_pcmcia_remove, | 95 | .remove = soc_common_drv_pcmcia_remove, |
| 96 | .name = "sa11x0-pcmcia", | 96 | .name = "sa11x0-pcmcia", |
| 97 | .bus = &platform_bus_type, | 97 | .bus = &platform_bus_type, |
| 98 | .suspend = sa11x0_drv_pcmcia_suspend, | 98 | .suspend = sa11x0_drv_pcmcia_suspend, |
| 99 | .resume = sa11x0_drv_pcmcia_resume, | 99 | .resume = sa11x0_drv_pcmcia_resume, |
| 100 | }; | 100 | }; |
| 101 | 101 | ||
| 102 | /* sa11x0_pcmcia_init() | 102 | /* sa11x0_pcmcia_init() |
| 103 | * ^^^^^^^^^^^^^^^^^^^^ | 103 | * ^^^^^^^^^^^^^^^^^^^^ |
| 104 | * | 104 | * |
| 105 | * This routine performs low-level PCMCIA initialization and then | 105 | * This routine performs low-level PCMCIA initialization and then |
| 106 | * registers this socket driver with Card Services. | 106 | * registers this socket driver with Card Services. |
| 107 | * | 107 | * |
| 108 | * Returns: 0 on success, -ve error code on failure | 108 | * Returns: 0 on success, -ve error code on failure |
| 109 | */ | 109 | */ |
| 110 | static int __init sa11x0_pcmcia_init(void) | 110 | static int __init sa11x0_pcmcia_init(void) |
| 111 | { | 111 | { |
| 112 | return driver_register(&sa11x0_pcmcia_driver); | 112 | return driver_register(&sa11x0_pcmcia_driver); |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | /* sa11x0_pcmcia_exit() | 115 | /* sa11x0_pcmcia_exit() |
| 116 | * ^^^^^^^^^^^^^^^^^^^^ | 116 | * ^^^^^^^^^^^^^^^^^^^^ |
| 117 | * Invokes the low-level kernel service to free IRQs associated with this | 117 | * Invokes the low-level kernel service to free IRQs associated with this |
| 118 | * socket controller and reset GPIO edge detection. | 118 | * socket controller and reset GPIO edge detection. |
| 119 | */ | 119 | */ |
| 120 | static void __exit sa11x0_pcmcia_exit(void) | 120 | static void __exit sa11x0_pcmcia_exit(void) |
| 121 | { | 121 | { |
| 122 | driver_unregister(&sa11x0_pcmcia_driver); | 122 | driver_unregister(&sa11x0_pcmcia_driver); |
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>"); | 125 | MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>"); |
| 126 | MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11x0 Socket Controller"); | 126 | MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11x0 Socket Controller"); |
| 127 | MODULE_LICENSE("Dual MPL/GPL"); | 127 | MODULE_LICENSE("Dual MPL/GPL"); |
| 128 | 128 | ||
| 129 | module_init(sa11x0_pcmcia_init); | 129 | fs_initcall(sa11x0_pcmcia_init); |
| 130 | module_exit(sa11x0_pcmcia_exit); | 130 | module_exit(sa11x0_pcmcia_exit); |
| 131 | 131 |
drivers/pcmcia/sa1111_generic.c
| 1 | /* | 1 | /* |
| 2 | * linux/drivers/pcmcia/sa1111_generic.c | 2 | * linux/drivers/pcmcia/sa1111_generic.c |
| 3 | * | 3 | * |
| 4 | * We implement the generic parts of a SA1111 PCMCIA driver. This | 4 | * We implement the generic parts of a SA1111 PCMCIA driver. This |
| 5 | * basically means we handle everything except controlling the | 5 | * basically means we handle everything except controlling the |
| 6 | * power. Power is machine specific... | 6 | * power. Power is machine specific... |
| 7 | */ | 7 | */ |
| 8 | #include <linux/config.h> | 8 | #include <linux/config.h> |
| 9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
| 10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
| 11 | #include <linux/ioport.h> | 11 | #include <linux/ioport.h> |
| 12 | #include <linux/device.h> | 12 | #include <linux/device.h> |
| 13 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
| 14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
| 15 | 15 | ||
| 16 | #include <pcmcia/ss.h> | 16 | #include <pcmcia/ss.h> |
| 17 | 17 | ||
| 18 | #include <asm/hardware.h> | 18 | #include <asm/hardware.h> |
| 19 | #include <asm/hardware/sa1111.h> | 19 | #include <asm/hardware/sa1111.h> |
| 20 | #include <asm/io.h> | 20 | #include <asm/io.h> |
| 21 | #include <asm/irq.h> | 21 | #include <asm/irq.h> |
| 22 | 22 | ||
| 23 | #include "sa1111_generic.h" | 23 | #include "sa1111_generic.h" |
| 24 | 24 | ||
| 25 | static struct pcmcia_irqs irqs[] = { | 25 | static struct pcmcia_irqs irqs[] = { |
| 26 | { 0, IRQ_S0_CD_VALID, "SA1111 PCMCIA card detect" }, | 26 | { 0, IRQ_S0_CD_VALID, "SA1111 PCMCIA card detect" }, |
| 27 | { 0, IRQ_S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1" }, | 27 | { 0, IRQ_S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1" }, |
| 28 | { 1, IRQ_S1_CD_VALID, "SA1111 CF card detect" }, | 28 | { 1, IRQ_S1_CD_VALID, "SA1111 CF card detect" }, |
| 29 | { 1, IRQ_S1_BVD1_STSCHG, "SA1111 CF BVD1" }, | 29 | { 1, IRQ_S1_BVD1_STSCHG, "SA1111 CF BVD1" }, |
| 30 | }; | 30 | }; |
| 31 | 31 | ||
| 32 | int sa1111_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | 32 | int sa1111_pcmcia_hw_init(struct soc_pcmcia_socket *skt) |
| 33 | { | 33 | { |
| 34 | if (skt->irq == NO_IRQ) | 34 | if (skt->irq == NO_IRQ) |
| 35 | skt->irq = skt->nr ? IRQ_S1_READY_NINT : IRQ_S0_READY_NINT; | 35 | skt->irq = skt->nr ? IRQ_S1_READY_NINT : IRQ_S0_READY_NINT; |
| 36 | 36 | ||
| 37 | return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); | 37 | return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | void sa1111_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) | 40 | void sa1111_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) |
| 41 | { | 41 | { |
| 42 | soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); | 42 | soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state) | 45 | void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state) |
| 46 | { | 46 | { |
| 47 | struct sa1111_dev *sadev = SA1111_DEV(skt->dev); | 47 | struct sa1111_dev *sadev = SA1111_DEV(skt->dev); |
| 48 | unsigned long status = sa1111_readl(sadev->mapbase + SA1111_PCSR); | 48 | unsigned long status = sa1111_readl(sadev->mapbase + SA1111_PCSR); |
| 49 | 49 | ||
| 50 | switch (skt->nr) { | 50 | switch (skt->nr) { |
| 51 | case 0: | 51 | case 0: |
| 52 | state->detect = status & PCSR_S0_DETECT ? 0 : 1; | 52 | state->detect = status & PCSR_S0_DETECT ? 0 : 1; |
| 53 | state->ready = status & PCSR_S0_READY ? 1 : 0; | 53 | state->ready = status & PCSR_S0_READY ? 1 : 0; |
| 54 | state->bvd1 = status & PCSR_S0_BVD1 ? 1 : 0; | 54 | state->bvd1 = status & PCSR_S0_BVD1 ? 1 : 0; |
| 55 | state->bvd2 = status & PCSR_S0_BVD2 ? 1 : 0; | 55 | state->bvd2 = status & PCSR_S0_BVD2 ? 1 : 0; |
| 56 | state->wrprot = status & PCSR_S0_WP ? 1 : 0; | 56 | state->wrprot = status & PCSR_S0_WP ? 1 : 0; |
| 57 | state->vs_3v = status & PCSR_S0_VS1 ? 0 : 1; | 57 | state->vs_3v = status & PCSR_S0_VS1 ? 0 : 1; |
| 58 | state->vs_Xv = status & PCSR_S0_VS2 ? 0 : 1; | 58 | state->vs_Xv = status & PCSR_S0_VS2 ? 0 : 1; |
| 59 | break; | 59 | break; |
| 60 | 60 | ||
| 61 | case 1: | 61 | case 1: |
| 62 | state->detect = status & PCSR_S1_DETECT ? 0 : 1; | 62 | state->detect = status & PCSR_S1_DETECT ? 0 : 1; |
| 63 | state->ready = status & PCSR_S1_READY ? 1 : 0; | 63 | state->ready = status & PCSR_S1_READY ? 1 : 0; |
| 64 | state->bvd1 = status & PCSR_S1_BVD1 ? 1 : 0; | 64 | state->bvd1 = status & PCSR_S1_BVD1 ? 1 : 0; |
| 65 | state->bvd2 = status & PCSR_S1_BVD2 ? 1 : 0; | 65 | state->bvd2 = status & PCSR_S1_BVD2 ? 1 : 0; |
| 66 | state->wrprot = status & PCSR_S1_WP ? 1 : 0; | 66 | state->wrprot = status & PCSR_S1_WP ? 1 : 0; |
| 67 | state->vs_3v = status & PCSR_S1_VS1 ? 0 : 1; | 67 | state->vs_3v = status & PCSR_S1_VS1 ? 0 : 1; |
| 68 | state->vs_Xv = status & PCSR_S1_VS2 ? 0 : 1; | 68 | state->vs_Xv = status & PCSR_S1_VS2 ? 0 : 1; |
| 69 | break; | 69 | break; |
| 70 | } | 70 | } |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | int sa1111_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) | 73 | int sa1111_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) |
| 74 | { | 74 | { |
| 75 | struct sa1111_dev *sadev = SA1111_DEV(skt->dev); | 75 | struct sa1111_dev *sadev = SA1111_DEV(skt->dev); |
| 76 | unsigned int pccr_skt_mask, pccr_set_mask, val; | 76 | unsigned int pccr_skt_mask, pccr_set_mask, val; |
| 77 | unsigned long flags; | 77 | unsigned long flags; |
| 78 | 78 | ||
| 79 | switch (skt->nr) { | 79 | switch (skt->nr) { |
| 80 | case 0: | 80 | case 0: |
| 81 | pccr_skt_mask = PCCR_S0_RST|PCCR_S0_FLT|PCCR_S0_PWAITEN|PCCR_S0_PSE; | 81 | pccr_skt_mask = PCCR_S0_RST|PCCR_S0_FLT|PCCR_S0_PWAITEN|PCCR_S0_PSE; |
| 82 | break; | 82 | break; |
| 83 | 83 | ||
| 84 | case 1: | 84 | case 1: |
| 85 | pccr_skt_mask = PCCR_S1_RST|PCCR_S1_FLT|PCCR_S1_PWAITEN|PCCR_S1_PSE; | 85 | pccr_skt_mask = PCCR_S1_RST|PCCR_S1_FLT|PCCR_S1_PWAITEN|PCCR_S1_PSE; |
| 86 | break; | 86 | break; |
| 87 | 87 | ||
| 88 | default: | 88 | default: |
| 89 | return -1; | 89 | return -1; |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | pccr_set_mask = 0; | 92 | pccr_set_mask = 0; |
| 93 | 93 | ||
| 94 | if (state->Vcc != 0) | 94 | if (state->Vcc != 0) |
| 95 | pccr_set_mask |= PCCR_S0_PWAITEN|PCCR_S1_PWAITEN; | 95 | pccr_set_mask |= PCCR_S0_PWAITEN|PCCR_S1_PWAITEN; |
| 96 | if (state->Vcc == 50) | 96 | if (state->Vcc == 50) |
| 97 | pccr_set_mask |= PCCR_S0_PSE|PCCR_S1_PSE; | 97 | pccr_set_mask |= PCCR_S0_PSE|PCCR_S1_PSE; |
| 98 | if (state->flags & SS_RESET) | 98 | if (state->flags & SS_RESET) |
| 99 | pccr_set_mask |= PCCR_S0_RST|PCCR_S1_RST; | 99 | pccr_set_mask |= PCCR_S0_RST|PCCR_S1_RST; |
| 100 | if (state->flags & SS_OUTPUT_ENA) | 100 | if (state->flags & SS_OUTPUT_ENA) |
| 101 | pccr_set_mask |= PCCR_S0_FLT|PCCR_S1_FLT; | 101 | pccr_set_mask |= PCCR_S0_FLT|PCCR_S1_FLT; |
| 102 | 102 | ||
| 103 | local_irq_save(flags); | 103 | local_irq_save(flags); |
| 104 | val = sa1111_readl(sadev->mapbase + SA1111_PCCR); | 104 | val = sa1111_readl(sadev->mapbase + SA1111_PCCR); |
| 105 | val &= ~pccr_skt_mask; | 105 | val &= ~pccr_skt_mask; |
| 106 | val |= pccr_set_mask & pccr_skt_mask; | 106 | val |= pccr_set_mask & pccr_skt_mask; |
| 107 | sa1111_writel(val, sadev->mapbase + SA1111_PCCR); | 107 | sa1111_writel(val, sadev->mapbase + SA1111_PCCR); |
| 108 | local_irq_restore(flags); | 108 | local_irq_restore(flags); |
| 109 | 109 | ||
| 110 | return 0; | 110 | return 0; |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | void sa1111_pcmcia_socket_init(struct soc_pcmcia_socket *skt) | 113 | void sa1111_pcmcia_socket_init(struct soc_pcmcia_socket *skt) |
| 114 | { | 114 | { |
| 115 | soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); | 115 | soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); |
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | void sa1111_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) | 118 | void sa1111_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) |
| 119 | { | 119 | { |
| 120 | soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); | 120 | soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | static int pcmcia_probe(struct sa1111_dev *dev) | 123 | static int pcmcia_probe(struct sa1111_dev *dev) |
| 124 | { | 124 | { |
| 125 | char *base; | 125 | char *base; |
| 126 | 126 | ||
| 127 | if (!request_mem_region(dev->res.start, 512, | 127 | if (!request_mem_region(dev->res.start, 512, |
| 128 | SA1111_DRIVER_NAME(dev))) | 128 | SA1111_DRIVER_NAME(dev))) |
| 129 | return -EBUSY; | 129 | return -EBUSY; |
| 130 | 130 | ||
| 131 | base = dev->mapbase; | 131 | base = dev->mapbase; |
| 132 | 132 | ||
| 133 | /* | 133 | /* |
| 134 | * Initialise the suspend state. | 134 | * Initialise the suspend state. |
| 135 | */ | 135 | */ |
| 136 | sa1111_writel(PCSSR_S0_SLEEP | PCSSR_S1_SLEEP, base + SA1111_PCSSR); | 136 | sa1111_writel(PCSSR_S0_SLEEP | PCSSR_S1_SLEEP, base + SA1111_PCSSR); |
| 137 | sa1111_writel(PCCR_S0_FLT | PCCR_S1_FLT, base + SA1111_PCCR); | 137 | sa1111_writel(PCCR_S0_FLT | PCCR_S1_FLT, base + SA1111_PCCR); |
| 138 | 138 | ||
| 139 | #ifdef CONFIG_SA1100_BADGE4 | 139 | #ifdef CONFIG_SA1100_BADGE4 |
| 140 | pcmcia_badge4_init(&dev->dev); | 140 | pcmcia_badge4_init(&dev->dev); |
| 141 | #endif | 141 | #endif |
| 142 | #ifdef CONFIG_SA1100_JORNADA720 | 142 | #ifdef CONFIG_SA1100_JORNADA720 |
| 143 | pcmcia_jornada720_init(&dev->dev); | 143 | pcmcia_jornada720_init(&dev->dev); |
| 144 | #endif | 144 | #endif |
| 145 | #ifdef CONFIG_ARCH_LUBBOCK | 145 | #ifdef CONFIG_ARCH_LUBBOCK |
| 146 | pcmcia_lubbock_init(dev); | 146 | pcmcia_lubbock_init(dev); |
| 147 | #endif | 147 | #endif |
| 148 | #ifdef CONFIG_ASSABET_NEPONSET | 148 | #ifdef CONFIG_ASSABET_NEPONSET |
| 149 | pcmcia_neponset_init(dev); | 149 | pcmcia_neponset_init(dev); |
| 150 | #endif | 150 | #endif |
| 151 | return 0; | 151 | return 0; |
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | static int __devexit pcmcia_remove(struct sa1111_dev *dev) | 154 | static int __devexit pcmcia_remove(struct sa1111_dev *dev) |
| 155 | { | 155 | { |
| 156 | soc_common_drv_pcmcia_remove(&dev->dev); | 156 | soc_common_drv_pcmcia_remove(&dev->dev); |
| 157 | release_mem_region(dev->res.start, 512); | 157 | release_mem_region(dev->res.start, 512); |
| 158 | return 0; | 158 | return 0; |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | static int pcmcia_suspend(struct sa1111_dev *dev, pm_message_t state) | 161 | static int pcmcia_suspend(struct sa1111_dev *dev, pm_message_t state) |
| 162 | { | 162 | { |
| 163 | return pcmcia_socket_dev_suspend(&dev->dev, state); | 163 | return pcmcia_socket_dev_suspend(&dev->dev, state); |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | static int pcmcia_resume(struct sa1111_dev *dev) | 166 | static int pcmcia_resume(struct sa1111_dev *dev) |
| 167 | { | 167 | { |
| 168 | return pcmcia_socket_dev_resume(&dev->dev); | 168 | return pcmcia_socket_dev_resume(&dev->dev); |
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | static struct sa1111_driver pcmcia_driver = { | 171 | static struct sa1111_driver pcmcia_driver = { |
| 172 | .drv = { | 172 | .drv = { |
| 173 | .name = "sa1111-pcmcia", | 173 | .name = "sa1111-pcmcia", |
| 174 | }, | 174 | }, |
| 175 | .devid = SA1111_DEVID_PCMCIA, | 175 | .devid = SA1111_DEVID_PCMCIA, |
| 176 | .probe = pcmcia_probe, | 176 | .probe = pcmcia_probe, |
| 177 | .remove = __devexit_p(pcmcia_remove), | 177 | .remove = __devexit_p(pcmcia_remove), |
| 178 | .suspend = pcmcia_suspend, | 178 | .suspend = pcmcia_suspend, |
| 179 | .resume = pcmcia_resume, | 179 | .resume = pcmcia_resume, |
| 180 | }; | 180 | }; |
| 181 | 181 | ||
| 182 | static int __init sa1111_drv_pcmcia_init(void) | 182 | static int __init sa1111_drv_pcmcia_init(void) |
| 183 | { | 183 | { |
| 184 | return sa1111_driver_register(&pcmcia_driver); | 184 | return sa1111_driver_register(&pcmcia_driver); |
| 185 | } | 185 | } |
| 186 | 186 | ||
| 187 | static void __exit sa1111_drv_pcmcia_exit(void) | 187 | static void __exit sa1111_drv_pcmcia_exit(void) |
| 188 | { | 188 | { |
| 189 | sa1111_driver_unregister(&pcmcia_driver); | 189 | sa1111_driver_unregister(&pcmcia_driver); |
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | module_init(sa1111_drv_pcmcia_init); | 192 | fs_initcall(sa1111_drv_pcmcia_init); |
| 193 | module_exit(sa1111_drv_pcmcia_exit); | 193 | module_exit(sa1111_drv_pcmcia_exit); |
| 194 | 194 | ||
| 195 | MODULE_DESCRIPTION("SA1111 PCMCIA card socket driver"); | 195 | MODULE_DESCRIPTION("SA1111 PCMCIA card socket driver"); |
| 196 | MODULE_LICENSE("GPL"); | 196 | MODULE_LICENSE("GPL"); |
| 197 | 197 |
drivers/pcmcia/sa11xx_base.c
| 1 | /*====================================================================== | 1 | /*====================================================================== |
| 2 | 2 | ||
| 3 | Device driver for the PCMCIA control functionality of StrongARM | 3 | Device driver for the PCMCIA control functionality of StrongARM |
| 4 | SA-1100 microprocessors. | 4 | SA-1100 microprocessors. |
| 5 | 5 | ||
| 6 | The contents of this file are subject to the Mozilla Public | 6 | The contents of this file are subject to the Mozilla Public |
| 7 | License Version 1.1 (the "License"); you may not use this file | 7 | License Version 1.1 (the "License"); you may not use this file |
| 8 | except in compliance with the License. You may obtain a copy of | 8 | except in compliance with the License. You may obtain a copy of |
| 9 | the License at http://www.mozilla.org/MPL/ | 9 | the License at http://www.mozilla.org/MPL/ |
| 10 | 10 | ||
| 11 | Software distributed under the License is distributed on an "AS | 11 | Software distributed under the License is distributed on an "AS |
| 12 | IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or | 12 | IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or |
| 13 | implied. See the License for the specific language governing | 13 | implied. See the License for the specific language governing |
| 14 | rights and limitations under the License. | 14 | rights and limitations under the License. |
| 15 | 15 | ||
| 16 | The initial developer of the original code is John G. Dorsey | 16 | The initial developer of the original code is John G. Dorsey |
| 17 | <john+@cs.cmu.edu>. Portions created by John G. Dorsey are | 17 | <john+@cs.cmu.edu>. Portions created by John G. Dorsey are |
| 18 | Copyright (C) 1999 John G. Dorsey. All Rights Reserved. | 18 | Copyright (C) 1999 John G. Dorsey. All Rights Reserved. |
| 19 | 19 | ||
| 20 | Alternatively, the contents of this file may be used under the | 20 | Alternatively, the contents of this file may be used under the |
| 21 | terms of the GNU Public License version 2 (the "GPL"), in which | 21 | terms of the GNU Public License version 2 (the "GPL"), in which |
| 22 | case the provisions of the GPL are applicable instead of the | 22 | case the provisions of the GPL are applicable instead of the |
| 23 | above. If you wish to allow the use of your version of this file | 23 | above. If you wish to allow the use of your version of this file |
| 24 | only under the terms of the GPL and not to allow others to use | 24 | only under the terms of the GPL and not to allow others to use |
| 25 | your version of this file under the MPL, indicate your decision | 25 | your version of this file under the MPL, indicate your decision |
| 26 | by deleting the provisions above and replace them with the notice | 26 | by deleting the provisions above and replace them with the notice |
| 27 | and other provisions required by the GPL. If you do not delete | 27 | and other provisions required by the GPL. If you do not delete |
| 28 | the provisions above, a recipient may use your version of this | 28 | the provisions above, a recipient may use your version of this |
| 29 | file under either the MPL or the GPL. | 29 | file under either the MPL or the GPL. |
| 30 | 30 | ||
| 31 | ======================================================================*/ | 31 | ======================================================================*/ |
| 32 | 32 | ||
| 33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
| 34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
| 35 | #include <linux/config.h> | 35 | #include <linux/config.h> |
| 36 | #include <linux/cpufreq.h> | 36 | #include <linux/cpufreq.h> |
| 37 | #include <linux/ioport.h> | 37 | #include <linux/ioport.h> |
| 38 | #include <linux/kernel.h> | 38 | #include <linux/kernel.h> |
| 39 | #include <linux/spinlock.h> | 39 | #include <linux/spinlock.h> |
| 40 | 40 | ||
| 41 | #include <asm/hardware.h> | 41 | #include <asm/hardware.h> |
| 42 | #include <asm/io.h> | 42 | #include <asm/io.h> |
| 43 | #include <asm/irq.h> | 43 | #include <asm/irq.h> |
| 44 | #include <asm/system.h> | 44 | #include <asm/system.h> |
| 45 | 45 | ||
| 46 | #include "soc_common.h" | 46 | #include "soc_common.h" |
| 47 | #include "sa11xx_base.h" | 47 | #include "sa11xx_base.h" |
| 48 | 48 | ||
| 49 | 49 | ||
| 50 | /* | 50 | /* |
| 51 | * sa1100_pcmcia_default_mecr_timing | 51 | * sa1100_pcmcia_default_mecr_timing |
| 52 | * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | 52 | * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 53 | * | 53 | * |
| 54 | * Calculate MECR clock wait states for given CPU clock | 54 | * Calculate MECR clock wait states for given CPU clock |
| 55 | * speed and command wait state. This function can be over- | 55 | * speed and command wait state. This function can be over- |
| 56 | * written by a board specific version. | 56 | * written by a board specific version. |
| 57 | * | 57 | * |
| 58 | * The default is to simply calculate the BS values as specified in | 58 | * The default is to simply calculate the BS values as specified in |
| 59 | * the INTEL SA1100 development manual | 59 | * the INTEL SA1100 development manual |
| 60 | * "Expansion Memory (PCMCIA) Configuration Register (MECR)" | 60 | * "Expansion Memory (PCMCIA) Configuration Register (MECR)" |
| 61 | * that's section 10.2.5 in _my_ version of the manual ;) | 61 | * that's section 10.2.5 in _my_ version of the manual ;) |
| 62 | */ | 62 | */ |
| 63 | static unsigned int | 63 | static unsigned int |
| 64 | sa1100_pcmcia_default_mecr_timing(struct soc_pcmcia_socket *skt, | 64 | sa1100_pcmcia_default_mecr_timing(struct soc_pcmcia_socket *skt, |
| 65 | unsigned int cpu_speed, | 65 | unsigned int cpu_speed, |
| 66 | unsigned int cmd_time) | 66 | unsigned int cmd_time) |
| 67 | { | 67 | { |
| 68 | return sa1100_pcmcia_mecr_bs(cmd_time, cpu_speed); | 68 | return sa1100_pcmcia_mecr_bs(cmd_time, cpu_speed); |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | /* sa1100_pcmcia_set_mecr() | 71 | /* sa1100_pcmcia_set_mecr() |
| 72 | * ^^^^^^^^^^^^^^^^^^^^^^^^ | 72 | * ^^^^^^^^^^^^^^^^^^^^^^^^ |
| 73 | * | 73 | * |
| 74 | * set MECR value for socket <sock> based on this sockets | 74 | * set MECR value for socket <sock> based on this sockets |
| 75 | * io, mem and attribute space access speed. | 75 | * io, mem and attribute space access speed. |
| 76 | * Call board specific BS value calculation to allow boards | 76 | * Call board specific BS value calculation to allow boards |
| 77 | * to tweak the BS values. | 77 | * to tweak the BS values. |
| 78 | */ | 78 | */ |
| 79 | static int | 79 | static int |
| 80 | sa1100_pcmcia_set_mecr(struct soc_pcmcia_socket *skt, unsigned int cpu_clock) | 80 | sa1100_pcmcia_set_mecr(struct soc_pcmcia_socket *skt, unsigned int cpu_clock) |
| 81 | { | 81 | { |
| 82 | struct soc_pcmcia_timing timing; | 82 | struct soc_pcmcia_timing timing; |
| 83 | u32 mecr, old_mecr; | 83 | u32 mecr, old_mecr; |
| 84 | unsigned long flags; | 84 | unsigned long flags; |
| 85 | unsigned int bs_io, bs_mem, bs_attr; | 85 | unsigned int bs_io, bs_mem, bs_attr; |
| 86 | 86 | ||
| 87 | soc_common_pcmcia_get_timing(skt, &timing); | 87 | soc_common_pcmcia_get_timing(skt, &timing); |
| 88 | 88 | ||
| 89 | bs_io = skt->ops->get_timing(skt, cpu_clock, timing.io); | 89 | bs_io = skt->ops->get_timing(skt, cpu_clock, timing.io); |
| 90 | bs_mem = skt->ops->get_timing(skt, cpu_clock, timing.mem); | 90 | bs_mem = skt->ops->get_timing(skt, cpu_clock, timing.mem); |
| 91 | bs_attr = skt->ops->get_timing(skt, cpu_clock, timing.attr); | 91 | bs_attr = skt->ops->get_timing(skt, cpu_clock, timing.attr); |
| 92 | 92 | ||
| 93 | local_irq_save(flags); | 93 | local_irq_save(flags); |
| 94 | 94 | ||
| 95 | old_mecr = mecr = MECR; | 95 | old_mecr = mecr = MECR; |
| 96 | MECR_FAST_SET(mecr, skt->nr, 0); | 96 | MECR_FAST_SET(mecr, skt->nr, 0); |
| 97 | MECR_BSIO_SET(mecr, skt->nr, bs_io); | 97 | MECR_BSIO_SET(mecr, skt->nr, bs_io); |
| 98 | MECR_BSA_SET(mecr, skt->nr, bs_attr); | 98 | MECR_BSA_SET(mecr, skt->nr, bs_attr); |
| 99 | MECR_BSM_SET(mecr, skt->nr, bs_mem); | 99 | MECR_BSM_SET(mecr, skt->nr, bs_mem); |
| 100 | if (old_mecr != mecr) | 100 | if (old_mecr != mecr) |
| 101 | MECR = mecr; | 101 | MECR = mecr; |
| 102 | 102 | ||
| 103 | local_irq_restore(flags); | 103 | local_irq_restore(flags); |
| 104 | 104 | ||
| 105 | debug(skt, 2, "FAST %X BSM %X BSA %X BSIO %X\n", | 105 | debug(skt, 2, "FAST %X BSM %X BSA %X BSIO %X\n", |
| 106 | MECR_FAST_GET(mecr, skt->nr), | 106 | MECR_FAST_GET(mecr, skt->nr), |
| 107 | MECR_BSM_GET(mecr, skt->nr), MECR_BSA_GET(mecr, skt->nr), | 107 | MECR_BSM_GET(mecr, skt->nr), MECR_BSA_GET(mecr, skt->nr), |
| 108 | MECR_BSIO_GET(mecr, skt->nr)); | 108 | MECR_BSIO_GET(mecr, skt->nr)); |
| 109 | 109 | ||
| 110 | return 0; | 110 | return 0; |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | #ifdef CONFIG_CPU_FREQ | 113 | #ifdef CONFIG_CPU_FREQ |
| 114 | static int | 114 | static int |
| 115 | sa1100_pcmcia_frequency_change(struct soc_pcmcia_socket *skt, | 115 | sa1100_pcmcia_frequency_change(struct soc_pcmcia_socket *skt, |
| 116 | unsigned long val, | 116 | unsigned long val, |
| 117 | struct cpufreq_freqs *freqs) | 117 | struct cpufreq_freqs *freqs) |
| 118 | { | 118 | { |
| 119 | switch (val) { | 119 | switch (val) { |
| 120 | case CPUFREQ_PRECHANGE: | 120 | case CPUFREQ_PRECHANGE: |
| 121 | if (freqs->new > freqs->old) | 121 | if (freqs->new > freqs->old) |
| 122 | sa1100_pcmcia_set_mecr(skt, freqs->new); | 122 | sa1100_pcmcia_set_mecr(skt, freqs->new); |
| 123 | break; | 123 | break; |
| 124 | 124 | ||
| 125 | case CPUFREQ_POSTCHANGE: | 125 | case CPUFREQ_POSTCHANGE: |
| 126 | if (freqs->new < freqs->old) | 126 | if (freqs->new < freqs->old) |
| 127 | sa1100_pcmcia_set_mecr(skt, freqs->new); | 127 | sa1100_pcmcia_set_mecr(skt, freqs->new); |
| 128 | break; | 128 | break; |
| 129 | case CPUFREQ_RESUMECHANGE: | 129 | case CPUFREQ_RESUMECHANGE: |
| 130 | sa1100_pcmcia_set_mecr(skt, freqs->new); | 130 | sa1100_pcmcia_set_mecr(skt, freqs->new); |
| 131 | break; | 131 | break; |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | return 0; | 134 | return 0; |
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | #endif | 137 | #endif |
| 138 | 138 | ||
| 139 | static int | 139 | static int |
| 140 | sa1100_pcmcia_set_timing(struct soc_pcmcia_socket *skt) | 140 | sa1100_pcmcia_set_timing(struct soc_pcmcia_socket *skt) |
| 141 | { | 141 | { |
| 142 | return sa1100_pcmcia_set_mecr(skt, cpufreq_get(0)); | 142 | return sa1100_pcmcia_set_mecr(skt, cpufreq_get(0)); |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | static int | 145 | static int |
| 146 | sa1100_pcmcia_show_timing(struct soc_pcmcia_socket *skt, char *buf) | 146 | sa1100_pcmcia_show_timing(struct soc_pcmcia_socket *skt, char *buf) |
| 147 | { | 147 | { |
| 148 | struct soc_pcmcia_timing timing; | 148 | struct soc_pcmcia_timing timing; |
| 149 | unsigned int clock = cpufreq_get(0); | 149 | unsigned int clock = cpufreq_get(0); |
| 150 | unsigned long mecr = MECR; | 150 | unsigned long mecr = MECR; |
| 151 | char *p = buf; | 151 | char *p = buf; |
| 152 | 152 | ||
| 153 | soc_common_pcmcia_get_timing(skt, &timing); | 153 | soc_common_pcmcia_get_timing(skt, &timing); |
| 154 | 154 | ||
| 155 | p+=sprintf(p, "I/O : %u (%u)\n", timing.io, | 155 | p+=sprintf(p, "I/O : %u (%u)\n", timing.io, |
| 156 | sa1100_pcmcia_cmd_time(clock, MECR_BSIO_GET(mecr, skt->nr))); | 156 | sa1100_pcmcia_cmd_time(clock, MECR_BSIO_GET(mecr, skt->nr))); |
| 157 | 157 | ||
| 158 | p+=sprintf(p, "attribute: %u (%u)\n", timing.attr, | 158 | p+=sprintf(p, "attribute: %u (%u)\n", timing.attr, |
| 159 | sa1100_pcmcia_cmd_time(clock, MECR_BSA_GET(mecr, skt->nr))); | 159 | sa1100_pcmcia_cmd_time(clock, MECR_BSA_GET(mecr, skt->nr))); |
| 160 | 160 | ||
| 161 | p+=sprintf(p, "common : %u (%u)\n", timing.mem, | 161 | p+=sprintf(p, "common : %u (%u)\n", timing.mem, |
| 162 | sa1100_pcmcia_cmd_time(clock, MECR_BSM_GET(mecr, skt->nr))); | 162 | sa1100_pcmcia_cmd_time(clock, MECR_BSM_GET(mecr, skt->nr))); |
| 163 | 163 | ||
| 164 | return p - buf; | 164 | return p - buf; |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, | 167 | int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, |
| 168 | int first, int nr) | 168 | int first, int nr) |
| 169 | { | 169 | { |
| 170 | /* | 170 | /* |
| 171 | * set default MECR calculation if the board specific | 171 | * set default MECR calculation if the board specific |
| 172 | * code did not specify one... | 172 | * code did not specify one... |
| 173 | */ | 173 | */ |
| 174 | if (!ops->get_timing) | 174 | if (!ops->get_timing) |
| 175 | ops->get_timing = sa1100_pcmcia_default_mecr_timing; | 175 | ops->get_timing = sa1100_pcmcia_default_mecr_timing; |
| 176 | 176 | ||
| 177 | /* Provide our SA11x0 specific timing routines. */ | 177 | /* Provide our SA11x0 specific timing routines. */ |
| 178 | ops->set_timing = sa1100_pcmcia_set_timing; | 178 | ops->set_timing = sa1100_pcmcia_set_timing; |
| 179 | ops->show_timing = sa1100_pcmcia_show_timing; | 179 | ops->show_timing = sa1100_pcmcia_show_timing; |
| 180 | #ifdef CONFIG_CPU_FREQ | 180 | #ifdef CONFIG_CPU_FREQ |
| 181 | ops->frequency_change = sa1100_pcmcia_frequency_change; | 181 | ops->frequency_change = sa1100_pcmcia_frequency_change; |
| 182 | #endif | 182 | #endif |
| 183 | 183 | ||
| 184 | return soc_common_drv_pcmcia_probe(dev, ops, first, nr); | 184 | return soc_common_drv_pcmcia_probe(dev, ops, first, nr); |
| 185 | } | 185 | } |
| 186 | EXPORT_SYMBOL(sa11xx_drv_pcmcia_probe); | 186 | EXPORT_SYMBOL(sa11xx_drv_pcmcia_probe); |
| 187 | 187 | ||
| 188 | static int __init sa11xx_pcmcia_init(void) | 188 | static int __init sa11xx_pcmcia_init(void) |
| 189 | { | 189 | { |
| 190 | return 0; | 190 | return 0; |
| 191 | } | 191 | } |
| 192 | module_init(sa11xx_pcmcia_init); | 192 | fs_initcall(sa11xx_pcmcia_init); |
| 193 | 193 | ||
| 194 | static void __exit sa11xx_pcmcia_exit(void) {} | 194 | static void __exit sa11xx_pcmcia_exit(void) {} |
| 195 | 195 | ||
| 196 | module_exit(sa11xx_pcmcia_exit); | 196 | module_exit(sa11xx_pcmcia_exit); |
| 197 | 197 | ||
| 198 | MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>"); | 198 | MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>"); |
| 199 | MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11xx core socket driver"); | 199 | MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11xx core socket driver"); |
| 200 | MODULE_LICENSE("Dual MPL/GPL"); | 200 | MODULE_LICENSE("Dual MPL/GPL"); |
| 201 | 201 |
include/asm-arm/mach/irq.h
| 1 | /* | 1 | /* |
| 2 | * linux/include/asm-arm/mach/irq.h | 2 | * linux/include/asm-arm/mach/irq.h |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 1995-2000 Russell King. | 4 | * Copyright (C) 1995-2000 Russell King. |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
| 8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
| 9 | */ | 9 | */ |
| 10 | #ifndef __ASM_ARM_MACH_IRQ_H | 10 | #ifndef __ASM_ARM_MACH_IRQ_H |
| 11 | #define __ASM_ARM_MACH_IRQ_H | 11 | #define __ASM_ARM_MACH_IRQ_H |
| 12 | 12 | ||
| 13 | struct irqdesc; | 13 | struct irqdesc; |
| 14 | struct pt_regs; | 14 | struct pt_regs; |
| 15 | struct seq_file; | 15 | struct seq_file; |
| 16 | 16 | ||
| 17 | typedef void (*irq_handler_t)(unsigned int, struct irqdesc *, struct pt_regs *); | 17 | typedef void (*irq_handler_t)(unsigned int, struct irqdesc *, struct pt_regs *); |
| 18 | typedef void (*irq_control_t)(unsigned int); | 18 | typedef void (*irq_control_t)(unsigned int); |
| 19 | 19 | ||
| 20 | struct irqchip { | 20 | struct irqchip { |
| 21 | /* | 21 | /* |
| 22 | * Acknowledge the IRQ. | 22 | * Acknowledge the IRQ. |
| 23 | * If this is a level-based IRQ, then it is expected to mask the IRQ | 23 | * If this is a level-based IRQ, then it is expected to mask the IRQ |
| 24 | * as well. | 24 | * as well. |
| 25 | */ | 25 | */ |
| 26 | void (*ack)(unsigned int); | 26 | void (*ack)(unsigned int); |
| 27 | /* | 27 | /* |
| 28 | * Mask the IRQ in hardware. | 28 | * Mask the IRQ in hardware. |
| 29 | */ | 29 | */ |
| 30 | void (*mask)(unsigned int); | 30 | void (*mask)(unsigned int); |
| 31 | /* | 31 | /* |
| 32 | * Unmask the IRQ in hardware. | 32 | * Unmask the IRQ in hardware. |
| 33 | */ | 33 | */ |
| 34 | void (*unmask)(unsigned int); | 34 | void (*unmask)(unsigned int); |
| 35 | /* | 35 | /* |
| 36 | * Ask the hardware to re-trigger the IRQ. | 36 | * Ask the hardware to re-trigger the IRQ. |
| 37 | * Note: This method _must_ _not_ call the interrupt handler. | 37 | * Note: This method _must_ _not_ call the interrupt handler. |
| 38 | * If you are unable to retrigger the interrupt, do not | 38 | * If you are unable to retrigger the interrupt, do not |
| 39 | * provide a function, or if you do, return non-zero. | 39 | * provide a function, or if you do, return non-zero. |
| 40 | */ | 40 | */ |
| 41 | int (*retrigger)(unsigned int); | 41 | int (*retrigger)(unsigned int); |
| 42 | /* | 42 | /* |
| 43 | * Set the type of the IRQ. | 43 | * Set the type of the IRQ. |
| 44 | */ | 44 | */ |
| 45 | int (*type)(unsigned int, unsigned int); | 45 | int (*set_type)(unsigned int, unsigned int); |
| 46 | /* | 46 | /* |
| 47 | * Set wakeup-enable on the selected IRQ | 47 | * Set wakeup-enable on the selected IRQ |
| 48 | */ | 48 | */ |
| 49 | int (*wake)(unsigned int, unsigned int); | 49 | int (*set_wake)(unsigned int, unsigned int); |
| 50 | 50 | ||
| 51 | #ifdef CONFIG_SMP | 51 | #ifdef CONFIG_SMP |
| 52 | /* | 52 | /* |
| 53 | * Route an interrupt to a CPU | 53 | * Route an interrupt to a CPU |
| 54 | */ | 54 | */ |
| 55 | void (*set_cpu)(struct irqdesc *desc, unsigned int irq, unsigned int cpu); | 55 | void (*set_cpu)(struct irqdesc *desc, unsigned int irq, unsigned int cpu); |
| 56 | #endif | 56 | #endif |
| 57 | }; | 57 | }; |
| 58 | 58 | ||
| 59 | struct irqdesc { | 59 | struct irqdesc { |
| 60 | irq_handler_t handle; | 60 | irq_handler_t handle; |
| 61 | struct irqchip *chip; | 61 | struct irqchip *chip; |
| 62 | struct irqaction *action; | 62 | struct irqaction *action; |
| 63 | struct list_head pend; | 63 | struct list_head pend; |
| 64 | void *chipdata; | 64 | void *chipdata; |
| 65 | void *data; | 65 | void *data; |
| 66 | unsigned int disable_depth; | 66 | unsigned int disable_depth; |
| 67 | 67 | ||
| 68 | unsigned int triggered: 1; /* IRQ has occurred */ | 68 | unsigned int triggered: 1; /* IRQ has occurred */ |
| 69 | unsigned int running : 1; /* IRQ is running */ | 69 | unsigned int running : 1; /* IRQ is running */ |
| 70 | unsigned int pending : 1; /* IRQ is pending */ | 70 | unsigned int pending : 1; /* IRQ is pending */ |
| 71 | unsigned int probing : 1; /* IRQ in use for a probe */ | 71 | unsigned int probing : 1; /* IRQ in use for a probe */ |
| 72 | unsigned int probe_ok : 1; /* IRQ can be used for probe */ | 72 | unsigned int probe_ok : 1; /* IRQ can be used for probe */ |
| 73 | unsigned int valid : 1; /* IRQ claimable */ | 73 | unsigned int valid : 1; /* IRQ claimable */ |
| 74 | unsigned int noautoenable : 1; /* don't automatically enable IRQ */ | 74 | unsigned int noautoenable : 1; /* don't automatically enable IRQ */ |
| 75 | unsigned int unused :25; | 75 | unsigned int unused :25; |
| 76 | 76 | ||
| 77 | struct proc_dir_entry *procdir; | 77 | struct proc_dir_entry *procdir; |
| 78 | 78 | ||
| 79 | #ifdef CONFIG_SMP | 79 | #ifdef CONFIG_SMP |
| 80 | cpumask_t affinity; | 80 | cpumask_t affinity; |
| 81 | unsigned int cpu; | 81 | unsigned int cpu; |
| 82 | #endif | 82 | #endif |
| 83 | 83 | ||
| 84 | /* | 84 | /* |
| 85 | * IRQ lock detection | 85 | * IRQ lock detection |
| 86 | */ | 86 | */ |
| 87 | unsigned int lck_cnt; | 87 | unsigned int lck_cnt; |
| 88 | unsigned int lck_pc; | 88 | unsigned int lck_pc; |
| 89 | unsigned int lck_jif; | 89 | unsigned int lck_jif; |
| 90 | }; | 90 | }; |
| 91 | 91 | ||
| 92 | extern struct irqdesc irq_desc[]; | 92 | extern struct irqdesc irq_desc[]; |
| 93 | |||
| 94 | /* | ||
| 95 | * Helpful inline function for calling irq descriptor handlers. | ||
| 96 | */ | ||
| 97 | static inline void desc_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) | ||
| 98 | { | ||
| 99 | desc->handle(irq, desc, regs); | ||
| 100 | } | ||
| 93 | 101 | ||
| 94 | /* | 102 | /* |
| 95 | * This is internal. Do not use it. | 103 | * This is internal. Do not use it. |
| 96 | */ | 104 | */ |
| 97 | extern void (*init_arch_irq)(void); | 105 | extern void (*init_arch_irq)(void); |
| 98 | extern void init_FIQ(void); | 106 | extern void init_FIQ(void); |
| 99 | extern int show_fiq_list(struct seq_file *, void *); | 107 | extern int show_fiq_list(struct seq_file *, void *); |
| 100 | void __set_irq_handler(unsigned int irq, irq_handler_t, int); | 108 | void __set_irq_handler(unsigned int irq, irq_handler_t, int); |
| 101 | 109 | ||
| 102 | /* | 110 | /* |
| 103 | * External stuff. | 111 | * External stuff. |
| 104 | */ | 112 | */ |
| 105 | #define set_irq_handler(irq,handler) __set_irq_handler(irq,handler,0) | 113 | #define set_irq_handler(irq,handler) __set_irq_handler(irq,handler,0) |
| 106 | #define set_irq_chained_handler(irq,handler) __set_irq_handler(irq,handler,1) | 114 | #define set_irq_chained_handler(irq,handler) __set_irq_handler(irq,handler,1) |
| 107 | #define set_irq_data(irq,d) do { irq_desc[irq].data = d; } while (0) | 115 | #define set_irq_data(irq,d) do { irq_desc[irq].data = d; } while (0) |
| 108 | #define set_irq_chipdata(irq,d) do { irq_desc[irq].chipdata = d; } while (0) | 116 | #define set_irq_chipdata(irq,d) do { irq_desc[irq].chipdata = d; } while (0) |
| 109 | #define get_irq_chipdata(irq) (irq_desc[irq].chipdata) | 117 | #define get_irq_chipdata(irq) (irq_desc[irq].chipdata) |
| 110 | 118 | ||
| 111 | void set_irq_chip(unsigned int irq, struct irqchip *); | 119 | void set_irq_chip(unsigned int irq, struct irqchip *); |
| 112 | void set_irq_flags(unsigned int irq, unsigned int flags); | 120 | void set_irq_flags(unsigned int irq, unsigned int flags); |
| 113 | 121 | ||
| 114 | #define IRQF_VALID (1 << 0) | 122 | #define IRQF_VALID (1 << 0) |
| 115 | #define IRQF_PROBE (1 << 1) | 123 | #define IRQF_PROBE (1 << 1) |
| 116 | #define IRQF_NOAUTOEN (1 << 2) | 124 | #define IRQF_NOAUTOEN (1 << 2) |
| 117 | 125 | ||
| 118 | /* | 126 | /* |
| 119 | * Built-in IRQ handlers. | 127 | * Built-in IRQ handlers. |
| 120 | */ | 128 | */ |
| 121 | void do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs); | 129 | void do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs); |
| 122 | void do_edge_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs); | 130 | void do_edge_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs); |
| 123 | void do_simple_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs); | 131 | void do_simple_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs); |
| 124 | void do_bad_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs); | 132 | void do_bad_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs); |
| 125 | void dummy_mask_unmask_irq(unsigned int irq); | 133 | void dummy_mask_unmask_irq(unsigned int irq); |
| 126 | 134 | ||
| 127 | #endif | 135 | #endif |
| 128 | 136 |