diff options
| author | Linus Torvalds <torvalds@penguin.transmeta.com> | 2002-03-04 22:58:48 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@penguin.transmeta.com> | 2002-03-04 22:58:48 -0800 |
| commit | f60852d2d272bf0c3339f78b04b927b854233ebc (patch) | |
| tree | 1e0c20ba7db41f1e4c96e3d0b71a77850158abf2 | |
| parent | a22655dcc61ec0adb5c12841a0955a3ad5d7c8a8 (diff) | |
| parent | ed78e24bb038b0e8e43f753a569e1d1d65f5e38d (diff) | |
Merge bk://bk.arm.linux.org.uk
into penguin.transmeta.com:/home/penguin/torvalds/repositories/kernel/linux
73 files changed, 3300 insertions, 2685 deletions
diff --git a/arch/arm/config.in b/arch/arm/config.in index 7fdca800a30f..f69db6f8608e 100644 --- a/arch/arm/config.in +++ b/arch/arm/config.in @@ -682,7 +682,6 @@ comment 'Kernel hacking' bool 'Compile kernel without frame pointer' CONFIG_NO_FRAME_POINTER bool 'Verbose user fault messages' CONFIG_DEBUG_USER bool 'Include debugging information in kernel binary' CONFIG_DEBUG_INFO -dep_bool 'Disable pgtable cache' CONFIG_NO_PGT_CACHE $CONFIG_CPU_26 bool 'Kernel debugging' CONFIG_DEBUG_KERNEL dep_bool ' Debug memory allocations' CONFIG_DEBUG_SLAB $CONFIG_DEBUG_KERNEL diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index 035f0f43699a..a84ba04ad73e 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c @@ -169,10 +169,6 @@ EXPORT_SYMBOL(__virt_to_bus); EXPORT_SYMBOL(__bus_to_virt); #endif -#ifndef CONFIG_NO_PGT_CACHE -EXPORT_SYMBOL(quicklists); -#endif - /* string / mem functions */ EXPORT_SYMBOL_NOVERS(strcpy); EXPORT_SYMBOL_NOVERS(strncpy); diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index e0b2eac9faa0..c95b4f4b68e3 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -95,9 +95,6 @@ void cpu_idle(void) idle(); leds_event(led_idle_end); schedule(); -#ifndef CONFIG_NO_PGT_CACHE - check_pgt_cache(); -#endif } } diff --git a/arch/arm/mach-adifcc/mm.c b/arch/arm/mach-adifcc/mm.c index 3d0db7087fdf..a77f235f5c24 100644 --- a/arch/arm/mach-adifcc/mm.c +++ b/arch/arm/mach-adifcc/mm.c @@ -14,7 +14,7 @@ static struct map_desc adifcc_io_desc[] __initdata = { /* on-board devices */ - { 0xff400000, 0x00400000, 0x00300000, DOMAIN_IO, 1, 1, 0, 0}, + { 0xff400000, 0x00400000, 0x00300000, DOMAIN_IO, 0, 1, 0, 0}, LAST_DESC }; diff --git a/arch/arm/mach-anakin/mm.c b/arch/arm/mach-anakin/mm.c index 631e7d7daebe..39bb59668930 100644 --- a/arch/arm/mach-anakin/mm.c +++ b/arch/arm/mach-anakin/mm.c @@ -20,7 +20,7 @@ static struct map_desc anakin_io_desc[] __initdata = { { IO_BASE, IO_START, IO_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, - { FLASH_BASE, FLASH_START, FLASH_SIZE, DOMAIN_IO, 1, 1, 0, 0 }, + { FLASH_BASE, FLASH_START, FLASH_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, { VGA_BASE, VGA_START, VGA_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, LAST_DESC }; diff --git a/arch/arm/mach-arc/mm.c b/arch/arm/mach-arc/mm.c index aec1dad545c8..6a96065fbab2 100644 --- a/arch/arm/mach-arc/mm.c +++ b/arch/arm/mach-arc/mm.c @@ -78,15 +78,16 @@ pgd_t *get_pgd_slow(struct mm_struct *mm) if (!new_pmd) goto no_pmd; - new_pte = pte_alloc(mm, new_pmd, 0); + new_pte = pte_alloc_map(mm, new_pmd, 0); if (!new_pte) goto no_pte; init_pgd = pgd_offset_k(0); init_pmd = pmd_offset(init_pgd, 0); - init_pte = pte_offset(init_pmd, 0); - + init_pte = pte_offset_map_nested(init_pmd, 0); set_pte(new_pte, *init_pte); + pte_unmap_nested(init_pte); + pte_unmap(new_pte); /* * most of the page table entries are zeroed diff --git a/arch/arm/mach-clps711x/autcpu12.c b/arch/arm/mach-clps711x/autcpu12.c index dff16c19364d..82b2839ed899 100644 --- a/arch/arm/mach-clps711x/autcpu12.c +++ b/arch/arm/mach-clps711x/autcpu12.c @@ -51,7 +51,7 @@ static struct map_desc autcpu12_io_desc[] __initdata = { /* virtual, physical, length, domain, r, w, c, b */ /* memory-mapped extra io and CS8900A Ethernet chip */ /* ethernet chip */ - { AUTCPU12_VIRT_CS8900A, AUTCPU12_PHYS_CS8900A, SZ_1M, DOMAIN_IO, 1, 1, 0, 0 }, + { AUTCPU12_VIRT_CS8900A, AUTCPU12_PHYS_CS8900A, SZ_1M, DOMAIN_IO, 0, 1, 0, 0 }, LAST_DESC }; diff --git a/arch/arm/mach-clps711x/edb7211-mm.c b/arch/arm/mach-clps711x/edb7211-mm.c index e4e970451f18..47e999599226 100644 --- a/arch/arm/mach-clps711x/edb7211-mm.c +++ b/arch/arm/mach-clps711x/edb7211-mm.c @@ -56,12 +56,12 @@ static struct map_desc edb7211_io_desc[] __initdata = { /* virtual, physical, length, domain, r, w, c, b */ /* memory-mapped extra keyboard row and CS8900A Ethernet chip */ - { EP7211_VIRT_EXTKBD, EP7211_PHYS_EXTKBD, MB1, DOMAIN_IO, 1, 1, 0, 0 }, - { EP7211_VIRT_CS8900A, EP7211_PHYS_CS8900A, MB1, DOMAIN_IO, 1, 1, 0, 0 }, + { EP7211_VIRT_EXTKBD, EP7211_PHYS_EXTKBD, MB1, DOMAIN_IO, 0, 1, 0, 0 }, + { EP7211_VIRT_CS8900A, EP7211_PHYS_CS8900A, MB1, DOMAIN_IO, 0, 1, 0, 0 }, /* flash banks */ - { EP7211_VIRT_FLASH1, EP7211_PHYS_FLASH1, MB1 * 8, DOMAIN_KERNEL, 1, 1, 0, 0 }, - { EP7211_VIRT_FLASH2, EP7211_PHYS_FLASH2, MB1 * 8, DOMAIN_KERNEL, 1, 1, 0, 0 }, + { EP7211_VIRT_FLASH1, EP7211_PHYS_FLASH1, MB1 * 8, DOMAIN_KERNEL, 0, 1, 0, 0 }, + { EP7211_VIRT_FLASH2, EP7211_PHYS_FLASH2, MB1 * 8, DOMAIN_KERNEL, 0, 1, 0, 0 }, LAST_DESC }; diff --git a/arch/arm/mach-sa1100/adsbitsy.c b/arch/arm/mach-sa1100/adsbitsy.c index eedeabb18634..72e7c953061c 100644 --- a/arch/arm/mach-sa1100/adsbitsy.c +++ b/arch/arm/mach-sa1100/adsbitsy.c @@ -125,7 +125,7 @@ fixup_adsbitsy(struct machine_desc *desc, struct param_struct *params, static struct map_desc adsbitsy_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xf4000000, 0x18000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA1111 */ + { 0xf4000000, 0x18000000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA1111 */ LAST_DESC }; diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c index 35d05f80e31b..5f8ed1c0d556 100644 --- a/arch/arm/mach-sa1100/assabet.c +++ b/arch/arm/mach-sa1100/assabet.c @@ -230,8 +230,8 @@ fixup_assabet(struct machine_desc *desc, struct param_struct *params, static struct map_desc assabet_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xf1000000, 0x12000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Board Control Register */ - { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* MQ200 */ + { 0xf1000000, 0x12000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Board Control Register */ + { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* MQ200 */ /* f3000000 - neponset system registers */ /* f4000000 - neponset SA1111 registers */ LAST_DESC diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c index bf2385ab4cd4..8ebd37634fc5 100644 --- a/arch/arm/mach-sa1100/cerf.c +++ b/arch/arm/mach-sa1100/cerf.c @@ -64,11 +64,11 @@ fixup_cerf(struct machine_desc *desc, struct param_struct *params, static struct map_desc cerf_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xf0000000, 0x08000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Crystal Ethernet Chip */ + { 0xf0000000, 0x08000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Crystal Ethernet Chip */ #ifdef CONFIG_SA1100_CERF_CPLD - { 0xf1000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* CPLD Chip */ - { 0xf2000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* CerfPDA Bluetooth */ - { 0xf3000000, 0x18000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* CerfPDA Serial */ + { 0xf1000000, 0x40000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD Chip */ + { 0xf2000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CerfPDA Bluetooth */ + { 0xf3000000, 0x18000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CerfPDA Serial */ #endif LAST_DESC }; diff --git a/arch/arm/mach-sa1100/empeg.c b/arch/arm/mach-sa1100/empeg.c index 682e99d522d2..d35f3c71534a 100644 --- a/arch/arm/mach-sa1100/empeg.c +++ b/arch/arm/mach-sa1100/empeg.c @@ -31,7 +31,7 @@ fixup_empeg(struct machine_desc *desc, struct param_struct *params, static struct map_desc empeg_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { EMPEG_FLASHBASE, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */ + { EMPEG_FLASHBASE, 0x00000000, 0x00200000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash */ LAST_DESC }; diff --git a/arch/arm/mach-sa1100/flexanet.c b/arch/arm/mach-sa1100/flexanet.c index 8ce7cea310c8..a470b49e3815 100644 --- a/arch/arm/mach-sa1100/flexanet.c +++ b/arch/arm/mach-sa1100/flexanet.c @@ -172,10 +172,10 @@ fixup_flexanet(struct machine_desc *desc, struct param_struct *params, static struct map_desc flexanet_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xf0000000, 0x10000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* Board Control Register */ - { 0xf1000000, 0x18000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Ethernet controller */ - { 0xD0000000, 0x40000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Instrument boards */ - { 0xD8000000, 0x48000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* External peripherals */ + { 0xf0000000, 0x10000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* Board Control Register */ + { 0xf1000000, 0x18000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Ethernet controller */ + { 0xD0000000, 0x40000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Instrument boards */ + { 0xD8000000, 0x48000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* External peripherals */ LAST_DESC }; diff --git a/arch/arm/mach-sa1100/freebird.c b/arch/arm/mach-sa1100/freebird.c index 3a28685b6a21..c0b6e5f7b9d1 100644 --- a/arch/arm/mach-sa1100/freebird.c +++ b/arch/arm/mach-sa1100/freebird.c @@ -66,8 +66,8 @@ fixup_freebird(struct machine_desc *desc, struct param_struct *params, static struct map_desc freebird_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xf0000000, 0x12000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Board Control Register */ - { 0xf2000000, 0x19000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0}, + { 0xf0000000, 0x12000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Board Control Register */ + { 0xf2000000, 0x19000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0}, LAST_DESC }; diff --git a/arch/arm/mach-sa1100/graphicsclient.c b/arch/arm/mach-sa1100/graphicsclient.c index 9178fed76dec..9997cdc11686 100644 --- a/arch/arm/mach-sa1100/graphicsclient.c +++ b/arch/arm/mach-sa1100/graphicsclient.c @@ -32,67 +32,62 @@ * Handlers for GraphicsClient's external IRQ logic */ -static void ADS_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs ) +static void +gc_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) { - int i; + unsigned int mask; + + while ((mask = ADS_INT_ST1 | (ADS_INT_ST2 << 8))) { + /* clear the parent IRQ */ + GEDR = GPIO_GPIO0; - while( (irq = ADS_INT_ST1 | (ADS_INT_ST2 << 8)) ){ - for( i = 0; i < 16; i++ ) - if( irq & (1<<i) ) - do_IRQ( ADS_EXT_IRQ(i), regs ); + irq = ADS_EXT_IRQ(0); + desc = irq_desc + irq; + + do { + if (mask & 1) + desc->handle(irq, desc, regs); + mask >>= 1; + irq++; + desc++; + } while (mask); } } -static struct irqaction ADS_ext_irq = { - name: "ADS_ext_IRQ", - handler: ADS_IRQ_demux, - flags: SA_INTERRUPT -}; - -static void ADS_mask_and_ack_irq0(unsigned int irq) +static void gc_mask_irq1(unsigned int irq) { int mask = (1 << (irq - ADS_EXT_IRQ(0))); ADS_INT_EN1 &= ~mask; ADS_INT_ST1 = mask; } -static void ADS_mask_irq0(unsigned int irq) -{ - ADS_INT_ST1 = (1 << (irq - ADS_EXT_IRQ(0))); -} - -static void ADS_unmask_irq0(unsigned int irq) +static void gc_unmask_irq1(unsigned int irq) { ADS_INT_EN1 |= (1 << (irq - ADS_EXT_IRQ(0))); } -static struct irqchip ADS0_chip = { - ack: ADS_mask_and_ack_irq0, - mask: ADS_mask_irq0, - unmask: ADS_unmask_irq0, +static struct irqchip gc_irq1_chip = { + ack: gc_mask_irq1, + mask: gc_mask_irq1, + unmask: gc_unmask_irq1, }; -static void ADS_mask_and_ack_irq1(unsigned int irq) +static void gc_mask_irq2(unsigned int irq) { int mask = (1 << (irq - ADS_EXT_IRQ(8))); ADS_INT_EN2 &= ~mask; ADS_INT_ST2 = mask; } -static void ADS_mask_irq1(unsigned int irq) -{ - ADS_INT_ST2 = (1 << (irq - ADS_EXT_IRQ(8))); -} - -static void ADS_unmask_irq1(unsigned int irq) +static void gc_unmask_irq2(unsigned int irq) { ADS_INT_EN2 |= (1 << (irq - ADS_EXT_IRQ(8))); } -static struct irqchip ADS1_chip = { - ack: ADS_mask_and_ack_irq1, - mask: ADS_mask_irq1, - unmask: ADS_unmask_irq1, +static struct irqchip gc_irq2_chip = { + ack: gc_mask_irq2, + mask: gc_mask_irq2, + unmask: gc_unmask_irq2, }; static void __init graphicsclient_init_irq(void) @@ -105,22 +100,23 @@ static void __init graphicsclient_init_irq(void) /* disable all IRQs */ ADS_INT_EN1 = 0; ADS_INT_EN2 = 0; + /* clear all IRQs */ ADS_INT_ST1 = 0xff; ADS_INT_ST2 = 0xff; for (irq = ADS_EXT_IRQ(0); irq <= ADS_EXT_IRQ(7); irq++) { - set_irq_chip(irq, &ADS0_chip); + set_irq_chip(irq, &gc_irq1_chip); set_irq_handler(irq, do_level_IRQ); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } for (irq = ADS_EXT_IRQ(8); irq <= ADS_EXT_IRQ(15); irq++) { - set_irq_chip(irq, &ADS1_chip); + set_irq_chip(irq, &gc_irq2_chip); set_irq_handler(irq, do_level_IRQ); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } - set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_FALLING_EDGE); - setup_arm_irq( IRQ_GPIO0, &ADS_ext_irq ); + set_irq_type(IRQ_GPIO0, IRQT_FALLING); + set_irq_chained_handler(IRQ_GPIO0, gc_irq_handler); } @@ -148,111 +144,6 @@ static struct map_desc graphicsclient_io_desc[] __initdata = { LAST_DESC }; -static struct gc_uart_ctrl_data_t gc_uart_ctrl_data[] = { - { GPIO_GC_UART0_CTS, 0, NULL,NULL }, - { GPIO_GC_UART1_CTS, 0, NULL,NULL }, - { GPIO_GC_UART2_CTS, 0, NULL,NULL } -}; - -#error Old code. Someone needs to decide what to do with this -#if 0 -static void -graphicsclient_cts_intr(int irq, void *dev_id, struct pt_regs *regs) -{ - struct gc_uart_ctrl_data_t * uart_data = (struct gc_uart_ctrl_data_t *)dev_id; - int cts = !(GPLR & uart_data->cts_gpio); - - /* NOTE: I supose that we will no get any interrupt - if the GPIO is not changed, so maybe - the cts_prev_state can be removed ... */ - if (cts != uart_data->cts_prev_state) { - uart_data->cts_prev_state = cts; - - uart_handle_cts_change(uart_data->info, cts); - } -} - -static int -graphicsclient_register_cts_intr(int gpio, int irq, - struct gc_uart_ctrl_data_t *uart_data) -{ - int ret = 0; - - set_GPIO_IRQ_edge(gpio, GPIO_BOTH_EDGES); - - ret = request_irq(irq, graphicsclient_cts_intr, - 0, "GC RS232 CTS", uart_data); - if (ret) { - printk(KERN_ERR "uart_open: failed to register CTS irq (%d)\n", - ret); - free_irq(irq, uart_data); - } - - return ret; -} - -static int -graphicsclient_uart_open(struct uart_port *port, struct uart_info *info) -{ - int ret = 0; - - if (port->mapbase == _Ser1UTCR0) { - Ser1SDCR0 |= SDCR0_UART; - /* Set RTS Output */ - GPSR = GPIO_GC_UART0_RTS; - - gc_uart_ctrl_data[0].cts_prev_state = 0; - gc_uart_ctrl_data[0].info = info; - gc_uart_ctrl_data[0].port = port; - - /* register uart0 CTS irq */ - ret = graphicsclient_register_cts_intr(GPIO_GC_UART0_CTS, - IRQ_GC_UART0_CTS, - &gc_uart_ctrl_data[0]); - } else if (port->mapbase == _Ser2UTCR0) { - Ser2UTCR4 = Ser2HSCR0 = 0; - /* Set RTS Output */ - GPSR = GPIO_GC_UART1_RTS; - - gc_uart_ctrl_data[1].cts_prev_state = 0; - gc_uart_ctrl_data[1].info = info; - gc_uart_ctrl_data[1].port = port; - - /* register uart1 CTS irq */ - ret = graphicsclient_register_cts_intr(GPIO_GC_UART1_CTS, - IRQ_GC_UART1_CTS, - &gc_uart_ctrl_data[1]); - } else if (port->mapbase == _Ser3UTCR0) { - /* Set RTS Output */ - GPSR = GPIO_GC_UART2_RTS; - - gc_uart_ctrl_data[2].cts_prev_state = 0; - gc_uart_ctrl_data[2].info = info; - gc_uart_ctrl_data[2].port = port; - - /* register uart2 CTS irq */ - ret = graphicsclient_register_cts_intr(GPIO_GC_UART2_CTS, - IRQ_GC_UART2_CTS, - &gc_uart_ctrl_data[2]); - } - return ret; -} - -static int -graphicsclient_uart_close(struct uart_port *port, struct uart_info *info) -{ - if (port->mapbase == _Ser1UTCR0) { - free_irq(IRQ_GC_UART0_CTS, &gc_uart_ctrl_data[0]); - } else if (port->mapbase == _Ser2UTCR0) { - free_irq(IRQ_GC_UART1_CTS, &gc_uart_ctrl_data[1]); - } else if (port->mapbase == _Ser3UTCR0) { - free_irq(IRQ_GC_UART2_CTS, &gc_uart_ctrl_data[2]); - } - - return 0; -} -#endif - static u_int graphicsclient_get_mctrl(struct uart_port *port) { u_int result = TIOCM_CD | TIOCM_DSR; diff --git a/arch/arm/mach-sa1100/graphicsmaster.c b/arch/arm/mach-sa1100/graphicsmaster.c index c4e52db5e428..b2eaecb33257 100644 --- a/arch/arm/mach-sa1100/graphicsmaster.c +++ b/arch/arm/mach-sa1100/graphicsmaster.c @@ -93,68 +93,62 @@ __initcall(graphicsmaster_init); * Handlers for GraphicsMaster's external IRQ logic */ -static void ADS_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs ) +static void +gm_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) { - int i; - - while( (irq = ADS_INT_ST1 | (ADS_INT_ST2 << 8)) ){ - for( i = 0; i < 16; i++ ) - if( irq & (1<<i) ) { - do_IRQ( ADS_EXT_IRQ(i), regs ); - } + unsigned int mask; + + while ((mask = ADS_INT_ST1 | (ADS_INT_ST2 << 8))) { + /* clear the parent IRQ */ + GEDR = GPIO_GPIO0; + + irq = ADS_EXT_IRQ(0); + desc = irq_desc + irq; + + do { + if (mask & 1) + desc->handle(irq, desc, regs); + mask >>= 1; + irq++; + desc++; + } while (mask); } } -static struct irqaction ADS_ext_irq = { - name: "ADS_ext_IRQ", - handler: ADS_IRQ_demux, - flags: SA_INTERRUPT -}; - -static void ADS_mask_and_ack_irq0(unsigned int irq) +static void gm_mask_irq1(unsigned int irq) { int mask = (1 << (irq - ADS_EXT_IRQ(0))); ADS_INT_EN1 &= ~mask; ADS_INT_ST1 = mask; } -static void ADS_mask_irq0(unsigned int irq) -{ - ADS_INT_ST1 = (1 << (irq - ADS_EXT_IRQ(0))); -} - -static void ADS_unmask_irq0(unsigned int irq) +static void gm_unmask_irq1(unsigned int irq) { ADS_INT_EN1 |= (1 << (irq - ADS_EXT_IRQ(0))); } -static struct irqchip ADS0_chip = { - ack: ADS_mask_and_ack_irq0, - mask: ADS_mask_irq0, - unmask: ADS_unmask_irq0, +static struct irqchip gm_irq1_chip = { + ack: gm_mask_irq1, + mask: gm_mask_irq1, + unmask: gm_unmask_irq1, }; -static void ADS_mask_and_ack_irq1(unsigned int irq) +static void gm_mask_irq2(unsigned int irq) { int mask = (1 << (irq - ADS_EXT_IRQ(8))); ADS_INT_EN2 &= ~mask; ADS_INT_ST2 = mask; } -static void ADS_mask_irq1(unsigned int irq) -{ - ADS_INT_ST2 = (1 << (irq - ADS_EXT_IRQ(8))); -} - -static void ADS_unmask_irq1(unsigned int irq) +static void gm_unmask_irq2(unsigned int irq) { ADS_INT_EN2 |= (1 << (irq - ADS_EXT_IRQ(8))); } -static struct irqchip ADS1_chip = { - ack: ADS_mask_irq1, - mask: ADS_mask_irq1, - unmask: ADS_mask_irq1, +static struct irqchip gm_irq2_chip = { + ack: gm_mask_irq2, + mask: gm_mask_irq2, + unmask: gm_unmask_irq2, }; static void __init graphicsmaster_init_irq(void) @@ -167,22 +161,23 @@ static void __init graphicsmaster_init_irq(void) /* disable all IRQs */ ADS_INT_EN1 = 0; ADS_INT_EN2 = 0; + /* clear all IRQs */ ADS_INT_ST1 = 0xff; ADS_INT_ST2 = 0xff; for (irq = ADS_EXT_IRQ(0); irq <= ADS_EXT_IRQ(7); irq++) { - set_irq_chip(irq, &ADS0_chip); + set_irq_chip(irq, &gm_irq1_chip); set_irq_handler(irq, do_level_IRQ); set_irq_flags(irq, IRQF_PROBE | IRQF_VALID); } for (irq = ADS_EXT_IRQ(8); irq <= ADS_EXT_IRQ(15); irq++) { - set_irq_chip(irq, &ADS1_chip); + set_irq_chip(irq, &gm_irq2_chip); set_irq_handler(irq, do_level_IRQ); set_irq_flags(irq, IRQF_PROBE | IRQF_VALID); } - set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_FALLING_EDGE); - setup_arm_irq( IRQ_GPIO0, &ADS_ext_irq ); + set_irq_type(IRQ_GPIO0, IRQT_FALLING); + set_irq_chained_handler(IRQ_GPIO0, gm_irq_handler); } @@ -206,9 +201,9 @@ fixup_graphicsmaster(struct machine_desc *desc, struct param_struct *params, static struct map_desc graphicsmaster_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xf0000000, 0x10000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* CPLD */ - { 0xf1000000, 0x40000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* CAN */ - { 0xf4000000, 0x18000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */ + { 0xf0000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */ + { 0xf1000000, 0x40000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CAN */ + { 0xf4000000, 0x18000000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */ LAST_DESC }; diff --git a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c index 633166a0ae05..6ce68739ce4a 100644 --- a/arch/arm/mach-sa1100/h3600.c +++ b/arch/arm/mach-sa1100/h3600.c @@ -489,9 +489,9 @@ static struct sa1100_port_fns h3600_port_fns __initdata = { static struct map_desc h3600_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { H3600_EGPIO_VIRT, 0x49000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* EGPIO 0 CS#5 */ - { H3600_BANK_2_VIRT, 0x10000000, 0x02800000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 2 CS#2 */ - { H3600_BANK_4_VIRT, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 4 CS#4 */ + { H3600_EGPIO_VIRT, 0x49000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* EGPIO 0 CS#5 */ + { H3600_BANK_2_VIRT, 0x10000000, 0x02800000, DOMAIN_IO, 0, 1, 0, 0 }, /* static memory bank 2 CS#2 */ + { H3600_BANK_4_VIRT, 0x40000000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* static memory bank 4 CS#4 */ LAST_DESC }; diff --git a/arch/arm/mach-sa1100/huw_webpanel.c b/arch/arm/mach-sa1100/huw_webpanel.c index 41a8ec5eedbf..98aba2ee8e8b 100644 --- a/arch/arm/mach-sa1100/huw_webpanel.c +++ b/arch/arm/mach-sa1100/huw_webpanel.c @@ -77,7 +77,7 @@ fixup_huw_webpanel(struct machine_desc *desc, struct param_struct *params, **/ static struct map_desc huw_webpanel_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xf0000000, 0xc1fb8000, 0x00048000, DOMAIN_IO, 1, 1, 0, 0 }, /* Parameter */ + { 0xf0000000, 0xc1fb8000, 0x00048000, DOMAIN_IO, 0, 1, 0, 0 }, /* Parameter */ { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Paules CS3, write only */ LAST_DESC }; diff --git a/arch/arm/mach-sa1100/itsy.c b/arch/arm/mach-sa1100/itsy.c index b715af6c3b9b..4594855326b1 100644 --- a/arch/arm/mach-sa1100/itsy.c +++ b/arch/arm/mach-sa1100/itsy.c @@ -31,8 +31,8 @@ fixup_itsy(struct machine_desc *desc, struct param_struct *params, likely wrong. */ static struct map_desc itsy_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ - { 0xf0000000, 0x49000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* EGPIO 0 */ + { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */ + { 0xf0000000, 0x49000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* EGPIO 0 */ LAST_DESC }; diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c index c9dd8efc1379..98e94f85a9c1 100644 --- a/arch/arm/mach-sa1100/jornada720.c +++ b/arch/arm/mach-sa1100/jornada720.c @@ -66,9 +66,9 @@ fixup_jornada720(struct machine_desc *desc, struct param_struct *params, static struct map_desc jornada720_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xf0000000, 0x48000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Epson registers */ - { 0xf1000000, 0x48200000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Epson frame buffer */ - { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */ + { 0xf0000000, 0x48000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Epson registers */ + { 0xf1000000, 0x48200000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Epson frame buffer */ + { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */ LAST_DESC }; diff --git a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c index fd1895dd4e32..4141747fcc80 100644 --- a/arch/arm/mach-sa1100/lart.c +++ b/arch/arm/mach-sa1100/lart.c @@ -18,8 +18,8 @@ static struct map_desc lart_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* main flash memory */ - { 0xec000000, 0x08000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* main flash, alternative location */ + { 0xe8000000, 0x00000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* main flash memory */ + { 0xec000000, 0x08000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* main flash, alternative location */ LAST_DESC }; diff --git a/arch/arm/mach-sa1100/nanoengine.c b/arch/arm/mach-sa1100/nanoengine.c index 8aad8bd919b3..bf12430352cd 100644 --- a/arch/arm/mach-sa1100/nanoengine.c +++ b/arch/arm/mach-sa1100/nanoengine.c @@ -34,9 +34,9 @@ fixup_nanoengine(struct machine_desc *desc, struct param_struct *params, static struct map_desc nanoengine_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ - { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* System Registers */ - { 0xf1000000, 0x18A00000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Internal PCI Config Space */ + { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */ + { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* System Registers */ + { 0xf1000000, 0x18A00000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Internal PCI Config Space */ LAST_DESC }; diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c index e9ecf3498a6d..34158578a552 100644 --- a/arch/arm/mach-sa1100/neponset.c +++ b/arch/arm/mach-sa1100/neponset.c @@ -184,8 +184,8 @@ __initcall(neponset_init); static struct map_desc neponset_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xf3000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* System Registers */ - { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */ + { 0xf3000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* System Registers */ + { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */ LAST_DESC }; diff --git a/arch/arm/mach-sa1100/omnimeter.c b/arch/arm/mach-sa1100/omnimeter.c index 76eaa1fb724d..604d9265a46f 100644 --- a/arch/arm/mach-sa1100/omnimeter.c +++ b/arch/arm/mach-sa1100/omnimeter.c @@ -54,7 +54,7 @@ fixup_omnimeter(struct machine_desc *desc, struct param_struct *params, static struct map_desc omnimeter_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xd2000000, 0x10000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* TS */ + { 0xd2000000, 0x10000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* TS */ LAST_DESC }; diff --git a/arch/arm/mach-sa1100/pangolin.c b/arch/arm/mach-sa1100/pangolin.c index f27c7f4aa836..37c4f6cbdf6a 100644 --- a/arch/arm/mach-sa1100/pangolin.c +++ b/arch/arm/mach-sa1100/pangolin.c @@ -30,7 +30,7 @@ fixup_pangolin(struct machine_desc *desc, struct param_struct *params, static struct map_desc pangolin_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* MQ200 */ + { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* MQ200 */ LAST_DESC }; diff --git a/arch/arm/mach-sa1100/pfs168.c b/arch/arm/mach-sa1100/pfs168.c index 8820c4a97b3f..18a1396deccf 100644 --- a/arch/arm/mach-sa1100/pfs168.c +++ b/arch/arm/mach-sa1100/pfs168.c @@ -103,20 +103,20 @@ fixup_pfs168(struct machine_desc *desc, struct param_struct *params, static struct map_desc pfs168_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ - { 0xf0000000, 0x10000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* 16C752 DUART port A (COM5) */ - { 0xf0001000, 0x10800000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* 16C752 DUART port B (COM6) */ - { 0xf0002000, 0x11000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* COM1 RTS control (SYSC1RTS) */ - { 0xf0003000, 0x11400000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* Status LED control (SYSLED) */ - { 0xf0004000, 0x11800000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* DTMF code read (SYSDTMF) */ - { 0xf0005000, 0x11c00000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* LCD configure, enable (SYSLCDDE) */ - { 0xf0006000, 0x12000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* COM1 DSR and motion sense (SYSC1DSR) */ - { 0xf0007000, 0x12800000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* COM3 xmit enable (SYSC3TEN) */ - { 0xf0008000, 0x13000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* Control register A (SYSCTLA) */ - { 0xf0009000, 0x13800000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* Control register B (SYSCTLB) */ - { 0xf000a000, 0x18000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* SMC91C96 */ - { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* MQ200 */ - { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */ + { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */ + { 0xf0000000, 0x10000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* 16C752 DUART port A (COM5) */ + { 0xf0001000, 0x10800000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* 16C752 DUART port B (COM6) */ + { 0xf0002000, 0x11000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* COM1 RTS control (SYSC1RTS) */ + { 0xf0003000, 0x11400000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* Status LED control (SYSLED) */ + { 0xf0004000, 0x11800000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* DTMF code read (SYSDTMF) */ + { 0xf0005000, 0x11c00000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* LCD configure, enable (SYSLCDDE) */ + { 0xf0006000, 0x12000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* COM1 DSR and motion sense (SYSC1DSR) */ + { 0xf0007000, 0x12800000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* COM3 xmit enable (SYSC3TEN) */ + { 0xf0008000, 0x13000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* Control register A (SYSCTLA) */ + { 0xf0009000, 0x13800000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* Control register B (SYSCTLB) */ + { 0xf000a000, 0x18000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* SMC91C96 */ + { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* MQ200 */ + { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */ LAST_DESC }; diff --git a/arch/arm/mach-sa1100/pleb.c b/arch/arm/mach-sa1100/pleb.c index 49c608198034..d6fb7a186491 100644 --- a/arch/arm/mach-sa1100/pleb.c +++ b/arch/arm/mach-sa1100/pleb.c @@ -35,8 +35,8 @@ fixup_pleb(struct machine_desc *desc, struct param_struct *params, static struct map_desc pleb_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* main flash memory */ - { 0xe8400000, 0x08000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* main flash, alternative location */ + { 0xe8000000, 0x00000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* main flash memory */ + { 0xe8400000, 0x08000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* main flash, alternative location */ LAST_DESC }; diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c index 3f897f5c98ce..ec23699c6b38 100644 --- a/arch/arm/mach-sa1100/simpad.c +++ b/arch/arm/mach-sa1100/simpad.c @@ -58,7 +58,7 @@ fixup_simpad(struct machine_desc *desc, struct param_struct *params, static struct map_desc simpad_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* MQ200 */ + { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* MQ200 */ { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Paules CS3, write only */ LAST_DESC }; diff --git a/arch/arm/mach-sa1100/stork.c b/arch/arm/mach-sa1100/stork.c index eacf6f8d786f..b57d653571c9 100644 --- a/arch/arm/mach-sa1100/stork.c +++ b/arch/arm/mach-sa1100/stork.c @@ -305,10 +305,10 @@ stork_kbd_unexpected_up(unsigned char code) struct map_desc stork_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ - { STORK_VM_BASE_CS1, STORK_VM_OFF_CS1, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* EGPIO 0 */ - { 0xf1000000, 0x10000000, 0x02800000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 2 */ - { 0xf3800000, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 4 */ + { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */ + { STORK_VM_BASE_CS1, STORK_VM_OFF_CS1, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* EGPIO 0 */ + { 0xf1000000, 0x10000000, 0x02800000, DOMAIN_IO, 0, 1, 0, 0 }, /* static memory bank 2 */ + { 0xf3800000, 0x40000000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* static memory bank 4 */ LAST_DESC }; diff --git a/arch/arm/mach-sa1100/system3.c b/arch/arm/mach-sa1100/system3.c index 9745fea25720..34d08d17dc75 100644 --- a/arch/arm/mach-sa1100/system3.c +++ b/arch/arm/mach-sa1100/system3.c @@ -58,6 +58,7 @@ #include "generic.h" #include "sa1111.h" +#include <asm/hardware/sa1111.h> #define DEBUG 1 @@ -74,19 +75,17 @@ /* init funcs */ static void __init fixup_system3(struct machine_desc *desc, struct param_struct *params, char **cmdline, struct meminfo *mi); -static void __init get_system3_scr(void); static int __init system3_init(void); static void __init system3_init_irq(void); static void __init system3_map_io(void); -static void system3_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs ); -static int system3_get_mctrl(struct uart_port *port); +static u_int system3_get_mctrl(struct uart_port *port); static void system3_set_mctrl(struct uart_port *port, u_int mctrl); static void system3_uart_pm(struct uart_port *port, u_int state, u_int oldstate); static int sdram_notifier(struct notifier_block *nb, unsigned long event, void *data); -static int system3_lcd_power(int on); -static int system3_backlight_power(int on); +static void system3_lcd_power(int on); +static void system3_backlight_power(int on); extern void convert_to_tag_list(struct param_struct *params, int mem_init); @@ -101,9 +100,9 @@ extern void convert_to_tag_list(struct param_struct *params, int mem_init); static struct map_desc system3_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ - { 0xf3000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* System Registers */ - { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */ + { 0xe8000000, 0x00000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */ + { 0xf3000000, PT_CPLD_BASE, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* System Registers */ + { 0xf4000000, PT_SA1111_BASE, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */ LAST_DESC }; @@ -113,12 +112,6 @@ static struct sa1100_port_fns system3_port_fns __initdata = { pm: system3_uart_pm, }; -static struct irqaction system3_irq = { - name: "PT Digital Board SA1111 IRQ", - handler: system3_IRQ_demux, - flags: SA_INTERRUPT -}; - static struct notifier_block system3_clkchg_block = { notifier_call: sdram_notifier, }; @@ -145,56 +138,82 @@ static void __init system3_map_io(void) /********************************************************************* * Install IRQ handler */ -static void system3_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs ) +static void +system3_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) { u_char irr; - for(;;){ - //irr = PTCPLD_REG_IRQSR & (PT_IRQ_LAN | PT_IRQ_USAR | PT_IRQ_SA1111); - irr = PT_IRQSR & (PT_IRQ_LAN | PT_IRQ_SA1111); + //DPRINTK( "irq=%d, desc=%p, regs=%p\n", irq, desc, regs ); - irr ^= (PT_IRQ_LAN); - if (!irr) break; + while (1) { + struct irqdesc *d; - if( irr & PT_IRQ_LAN ) - do_IRQ(IRQ_SYSTEM3_SMC9196, regs); + /* + * Acknowledge the parent IRQ. + */ + desc->chip->ack(irq); -#if 0 - /* Highspeed Serial Bus not yet used */ - if( irr & PT_IRQ_USAR ) - do_IRQ(PT_USAR_IRQ, regs); -#endif + /* + * Read the interrupt reason register. Let's have all + * active IRQ bits high. Note: there is a typo in the + * Neponset user's guide for the SA1111 IRR level. + */ + //irr = PT_IRQSR & (PT_IRR_LAN | PT_IRR_SA1111); + irr = PT_IRQSR & (PT_IRR_SA1111); - if( irr & PT_IRQ_SA1111 ) - sa1111_IRQ_demux(irq, dev_id, regs); - } -} + /* SMC IRQ is low-active, so "switch" bit over */ + //irr ^= (PT_IRR_LAN); + //DPRINTK( "irr=0x%02x\n", irr ); -static void __init system3_init_irq(void) -{ - int irq; + if ((irr & (PT_IRR_LAN | PT_IRR_SA1111)) == 0) + break; - DPRINTK( "%s\n", "START" ); + /* + * Since there is no individual mask, we have to + * mask the parent IRQ. This is safe, since we'll + * recheck the register for any pending IRQs. + */ + if (irr & (PT_IRR_LAN)) { + desc->chip->mask(irq); + + if (irr & PT_IRR_LAN) { + //DPRINTK( "SMC9196, irq=%d\n", IRQ_SYSTEM3_SMC9196 ); + d = irq_desc + IRQ_SYSTEM3_SMC9196; + d->handle(IRQ_SYSTEM3_SMC9196, d, regs); + } + +#if 0 /* no SSP yet on system 4 */ + if (irr & IRR_USAR) { + d = irq_desc + IRQ_NEPONSET_USAR; + d->handle(IRQ_NEPONSET_USAR, d, regs); + } +#endif - /* SA1111 IRQ not routed to a GPIO. */ - sa1111_init_irq(-1); + desc->chip->unmask(irq); + } - /* setup extra IRQs */ - irq = IRQ_SYSTEM3_SMC9196; - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; + if (irr & PT_IRR_SA1111) { + //DPRINTK( "SA1111, irq=%d\n", IRQ_SYSTEM3_SA1111 ); + d = irq_desc + IRQ_SYSTEM3_SA1111; + d->handle(IRQ_SYSTEM3_SA1111, d, regs); + } + } +} -#if 0 - /* Highspeed Serial Bus not yet used */ - irq = PT_USAR_IRQ; - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; -#endif +static void __init system3_init_irq(void) +{ + /* + * Install handler for GPIO25. + */ + set_irq_type(IRQ_GPIO25, IRQT_RISING); + set_irq_chained_handler(IRQ_GPIO25, system3_irq_handler); - /* IRQ by CPLD */ - set_GPIO_IRQ_edge( GPIO_GPIO(25), GPIO_RISING_EDGE ); - setup_arm_irq( IRQ_GPIO25, &system3_irq ); + /* + * install eth irq + */ + set_irq_handler(IRQ_SYSTEM3_SMC9196, do_simple_IRQ); + set_irq_flags(IRQ_SYSTEM3_SMC9196, IRQF_VALID | IRQF_PROBE); } /********************************************************************** @@ -270,7 +289,7 @@ static void system3_set_mctrl(struct uart_port *port, u_int mctrl) } } -static int system3_get_mctrl(struct uart_port *port) +static u_int system3_get_mctrl(struct uart_port *port) { u_int ret = 0; u_int irqsr = PT_IRQSR; @@ -358,12 +377,8 @@ static void system3_lcd_brightness(unsigned char value) static void system3_lcd_power(int on) { -#error why is backlight stuff here??? if (on) { system3_lcd_on(); - system3_lcd_backlight_on(); - system3_lcd_contrast(0x95); - system3_lcd_brightness(240); } else { system3_lcd_off(); } @@ -407,10 +422,12 @@ static int __init system3_init(void) */ sa1110_mb_disable(); + system3_init_irq(); + /* * Probe for a SA1111. */ - ret = sa1111_probe(0x40000000); + ret = sa1111_probe(PT_SA1111_BASE); if (ret < 0) { printk( KERN_WARNING"PT Digital Board: no SA1111 found!\n" ); goto DONE; @@ -443,7 +460,11 @@ static int __init system3_init(void) */ sa1110_mb_enable(); - system3_init_irq(); + /* + * Initialise SA1111 IRQs + */ + sa1111_init_irq(IRQ_SYSTEM3_SA1111); + #if defined( CONFIG_CPU_FREQ ) ret = cpufreq_register_notifier(&system3_clkchg_block); @@ -453,6 +474,7 @@ static int __init system3_init(void) } #endif + ret = 0; DONE: DPRINTK( "ret=%d\n", ret ); diff --git a/arch/arm/mach-sa1100/victor.c b/arch/arm/mach-sa1100/victor.c index a4378e32d4a2..27611b41fd7a 100644 --- a/arch/arm/mach-sa1100/victor.c +++ b/arch/arm/mach-sa1100/victor.c @@ -60,7 +60,7 @@ fixup_victor(struct machine_desc *desc, struct param_struct *params, static struct map_desc victor_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */ + { 0xe8000000, 0x00000000, 0x00200000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash */ LAST_DESC }; diff --git a/arch/arm/mach-sa1100/xp860.c b/arch/arm/mach-sa1100/xp860.c index 4e9f38b56869..c4ad798742ee 100644 --- a/arch/arm/mach-sa1100/xp860.c +++ b/arch/arm/mach-sa1100/xp860.c @@ -67,9 +67,9 @@ fixup_xp860(struct machine_desc *desc, struct param_struct *params, static struct map_desc xp860_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SCSI */ - { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* LAN */ - { 0xf4000000, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */ + { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SCSI */ + { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN */ + { 0xf4000000, 0x40000000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */ LAST_DESC }; diff --git a/arch/arm/mach-sa1100/yopy.c b/arch/arm/mach-sa1100/yopy.c index fa8b5c8fc9c6..fc36c00aa49b 100644 --- a/arch/arm/mach-sa1100/yopy.c +++ b/arch/arm/mach-sa1100/yopy.c @@ -69,9 +69,9 @@ __initcall(yopy_hw_init); static struct map_desc yopy_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x04000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash 0 */ - { 0xec000000, 0x08000000, 0x04000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash 1 */ - { 0xf0000000, 0x48000000, 0x00300000, DOMAIN_IO, 1, 1, 0, 0 }, /* LCD */ + { 0xe8000000, 0x00000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash 0 */ + { 0xec000000, 0x08000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash 1 */ + { 0xf0000000, 0x48000000, 0x00300000, DOMAIN_IO, 0, 1, 0, 0 }, /* LCD */ { 0xf1000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* EGPIO */ LAST_DESC }; diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index 30a10cb07775..22428e7d98b4 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -151,7 +151,7 @@ static void adjust_pte(struct vm_area_struct *vma, unsigned long address) if (pmd_bad(*pmd)) goto bad_pmd; - pte = pte_offset(pmd, address); + pte = pte_offset_map(pmd, address); entry = *pte; /* @@ -164,6 +164,7 @@ static void adjust_pte(struct vm_area_struct *vma, unsigned long address) set_pte(pte, entry); flush_tlb_page(vma, address); } + pte_unmap(pte); return; bad_pgd: diff --git a/arch/arm/mm/fault-common.c b/arch/arm/mm/fault-common.c index 699e5208d1d4..b39fd67963f7 100644 --- a/arch/arm/mm/fault-common.c +++ b/arch/arm/mm/fault-common.c @@ -83,11 +83,15 @@ void show_pte(struct mm_struct *mm, unsigned long addr) break; } - pte = pte_offset(pmd, addr); +#ifndef CONFIG_HIGHMEM + /* We must not map this if we have highmem enabled */ + pte = pte_offset_map(pmd, addr); printk(", *pte = %08lx", pte_val(*pte)); #ifdef CONFIG_CPU_32 printk(", *ppte = %08lx", pte_val(pte[-PTRS_PER_PTE])); #endif + pte_unmap(pte); +#endif } while(0); printk("\n"); diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index b2fcc416756f..c9b4ba1f39ea 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -64,38 +64,6 @@ static struct meminfo meminfo __initdata = { 0, }; */ struct page *empty_zero_page; -#ifndef CONFIG_NO_PGT_CACHE -struct pgtable_cache_struct quicklists; - -int do_check_pgt_cache(int low, int high) -{ - int freed = 0; - - if(pgtable_cache_size > high) { - do { - if(pgd_quicklist) { - free_pgd_slow(get_pgd_fast()); - freed++; - } - if(pmd_quicklist) { - pmd_free_slow(pmd_alloc_one_fast(NULL, 0)); - freed++; - } - if(pte_quicklist) { - pte_free_slow(pte_alloc_one_fast(NULL, 0)); - freed++; - } - } while(pgtable_cache_size > low); - } - return freed; -} -#else -int do_check_pgt_cache(int low, int high) -{ - return 0; -} -#endif - /* This is currently broken * PG_skip is used on sparc/sparc64 architectures to "skip" certain * parts of the address space. @@ -145,9 +113,6 @@ void show_mem(void) printk("%d slab pages\n", slab); printk("%d pages shared\n", shared); printk("%d pages swap cached\n", cached); -#ifndef CONFIG_NO_PGT_CACHE - printk("%ld page tables cached\n", pgtable_cache_size); -#endif show_buffers(); } diff --git a/arch/arm/mm/minicache.c b/arch/arm/mm/minicache.c index 8aa87e9b2487..7f20b9d0ea85 100644 --- a/arch/arm/mm/minicache.c +++ b/arch/arm/mm/minicache.c @@ -58,7 +58,7 @@ static int __init minicache_init(void) pmd = pmd_alloc(&init_mm, pgd, minicache_address); if (!pmd) BUG(); - minicache_pte = pte_alloc(&init_mm, pmd, minicache_address); + minicache_pte = pte_alloc_kernel(&init_mm, pmd, minicache_address); if (!minicache_pte) BUG(); diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c index 10605d6aa11e..d8dfc4e019ac 100644 --- a/arch/arm/mm/mm-armv.c +++ b/arch/arm/mm/mm-armv.c @@ -98,11 +98,15 @@ pgd_t *get_pgd_slow(struct mm_struct *mm) if (!new_pmd) goto no_pmd; - new_pte = pte_alloc(mm, new_pmd, 0); + new_pte = pte_alloc_map(mm, new_pmd, 0); if (!new_pte) goto no_pte; + init_pmd = pmd_offset(init_pgd, 0); + init_pte = pte_offset_map_nested(init_pmd, 0); set_pte(new_pte, *init_pte); + pte_unmap_nested(init_pte); + pte_unmap(new_pte); spin_unlock(&mm->page_table_lock); } @@ -138,7 +142,7 @@ no_pgd: void free_pgd_slow(pgd_t *pgd) { pmd_t *pmd; - pte_t *pte; + struct page *pte; if (!pgd) return; @@ -153,7 +157,7 @@ void free_pgd_slow(pgd_t *pgd) goto free; } - pte = pte_offset(pmd, 0); + pte = pmd_page(*pmd); pmd_clear(pmd); pte_free(pte); pmd_free(pmd); @@ -198,7 +202,7 @@ alloc_init_page(unsigned long virt, unsigned long phys, int domain, int prot) set_pmd(pmdp, __mk_pmd(ptep, PMD_TYPE_TABLE | PMD_DOMAIN(domain))); } - ptep = pte_offset(pmdp, virt); + ptep = pte_offset_kernel(pmdp, virt); set_pte(ptep, mk_pte_phys(phys, __pgprot(prot))); } @@ -225,6 +229,20 @@ static void __init create_mapping(struct map_desc *md) int prot_sect, prot_pte; long off; + if (md->prot_read && md->prot_write && + !md->cacheable && !md->bufferable) { + printk(KERN_WARNING "Security risk: creating user " + "accessible mapping for 0x%08lx at 0x%08lx\n", + md->physical, md->virtual); + } + + if (md->virtual != vectors_base() && md->virtual < PAGE_OFFSET) { + printk(KERN_WARNING "MM: not creating mapping for " + "0x%08lx at 0x%08lx in user region\n", + md->physical, md->virtual); + return; + } + prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | (md->prot_read ? L_PTE_USER : 0) | (md->prot_write ? L_PTE_WRITE : 0) | diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S index f4a2ed50ba23..3e67f274c60a 100644 --- a/arch/arm/mm/proc-xscale.S +++ b/arch/arm/mm/proc-xscale.S @@ -663,8 +663,8 @@ cpu_manu_name: cpu_80200_name: .asciz "XScale-80200" -cpu_cotulla_name: - .asciz "XScale-Cotulla" +cpu_pxa250_name: + .asciz "XScale-PXA250" .align @@ -734,11 +734,11 @@ cpu_80200_info: .long cpu_80200_name .size cpu_80200_info, . - cpu_80200_info - .type cpu_cotulla_info, #object -cpu_cotulla_info: + .type cpu_pxa250_info, #object +cpu_pxa250_info: .long cpu_manu_name - .long cpu_cotulla_name - .size cpu_cotulla_info, . - cpu_cotulla_info + .long cpu_pxa250_name + .size cpu_pxa250_info, . - cpu_pxa250_info .type cpu_arch_name, #object cpu_arch_name: @@ -767,8 +767,8 @@ __80200_proc_info: .long v4wbi_tlb_fns .size __80200_proc_info, . - __80200_proc_info - .type __cotulla_proc_info,#object -__cotulla_proc_info: + .type __pxa250_proc_info,#object +__pxa250_proc_info: .long 0x69052100 .long 0xfffffff0 .long 0x00000c0e @@ -776,8 +776,9 @@ __cotulla_proc_info: .long cpu_arch_name .long cpu_elf_name .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP - .long cpu_cotulla_info + .long cpu_pxa250_info .long xscale_processor_functions .long v4wbi_tlb_fns .size __cotulla_proc_info, . - __cotulla_proc_info + .size __pxa250_proc_info, . - __pxa250_proc_info diff --git a/drivers/pcmcia/Config.in b/drivers/pcmcia/Config.in index 6556020c1231..ae5294fa23db 100644 --- a/drivers/pcmcia/Config.in +++ b/drivers/pcmcia/Config.in @@ -24,5 +24,6 @@ if [ "$CONFIG_PCMCIA" != "n" ]; then dep_tristate ' HD64465 host bridge support' CONFIG_HD64465_PCMCIA $CONFIG_PCMCIA fi fi +dep_tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA endmenu diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index f4c21c2ba25b..dda91ec562e0 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -62,22 +62,25 @@ endif obj-$(CONFIG_PCMCIA_SA1100) += sa1100_cs.o sa1100_cs-objs-y := sa1100_generic.o +sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSY) += sa1100_adsbitsy.o sa1111_generic.o sa1100_cs-objs-$(CONFIG_SA1100_ASSABET) += sa1100_assabet.o -sa1100_cs-objs-$(CONFIG_ASSABET_NEPONSET) += sa1100_neponset.o -sa1100_cs-objs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o +sa1100_cs-objs-$(CONFIG_ASSABET_NEPONSET) += sa1100_neponset.o sa1111_generic.o +sa1100_cs-objs-$(CONFIG_SA1100_BADGE4) += sa1100_badge4.o sa1111_generic.o sa1100_cs-objs-$(CONFIG_SA1100_CERF) += sa1100_cerf.o +sa1100_cs-objs-$(CONFIG_SA1100_FLEXANET) += sa1100_flexanet.o +sa1100_cs-objs-$(CONFIG_SA1100_FREEBIRD) += sa1100_freebird.o +sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSMASTER) += sa1100_graphicsmaster.o sa1111_generic.o sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSCLIENT) += sa1100_graphicsclient.o -sa1100_cs-objs-$(CONFIG_SA1100_XP860) += sa1100_xp860.o +sa1100_cs-objs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o +sa1100_cs-objs-$(CONFIG_SA1100_JORNADA720) += sa1100_jornada720.o sa1111_generic.o sa1100_cs-objs-$(CONFIG_SA1100_PANGOLIN) += sa1100_pangolin.o -sa1100_cs-objs-$(CONFIG_SA1100_YOPY) += sa1100_yopy.o -sa1100_cs-objs-$(CONFIG_SA1100_FREEBIRD) += sa1100_freebird.o -sa1100_cs-objs-$(CONFIG_SA1100_PFS168) += sa1100_pfs168.o -sa1100_cs-objs-$(CONFIG_SA1100_JORNADA720) += sa1100_jornada720.o -sa1100_cs-objs-$(CONFIG_SA1100_FLEXANET) += sa1100_flexanet.o +sa1100_cs-objs-$(CONFIG_SA1100_PFS168) += sa1100_pfs168.o sa1111_generic.o +sa1100_cs-objs-$(CONFIG_SA1100_PT_SYSTEM3) += sa1100_system3.o sa1111_generic.o +sa1100_cs-objs-$(CONFIG_SA1100_SHANNON) += sa1100_shannon.o sa1100_cs-objs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o -sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSMASTER) += sa1100_graphicsmaster.o -sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSY) += sa1100_adsbitsy.o sa1100_cs-objs-$(CONFIG_SA1100_STORK) += sa1100_stork.o +sa1100_cs-objs-$(CONFIG_SA1100_XP860) += sa1100_xp860.o sa1111_generic.o +sa1100_cs-objs-$(CONFIG_SA1100_YOPY) += sa1100_yopy.o include $(TOPDIR)/Rules.make @@ -85,7 +88,7 @@ pcmcia_core.o: $(pcmcia_core-objs) $(LD) $(LD_RFLAG) -r -o $@ $(pcmcia_core-objs) sa1100_cs.o: $(sa1100_cs-objs-y) - $(LD) -r -o $@ $(sa1100_cs-objs-y) + $(LD) -r -o $@ $(sort $(sa1100_cs-objs-y)) yenta_socket.o: $(yenta_socket-objs) $(LD) $(LD_RFLAG) -r -o $@ $(yenta_socket-objs) diff --git a/drivers/pcmcia/sa1100.h b/drivers/pcmcia/sa1100.h index eda4f6d7d6db..8f45ca6e3aaf 100644 --- a/drivers/pcmcia/sa1100.h +++ b/drivers/pcmcia/sa1100.h @@ -38,9 +38,7 @@ #include <pcmcia/bulkmem.h> #include <pcmcia/cistpl.h> #include "cs_internal.h" - -#include <asm/arch/pcmcia.h> - +#include "sa1100_generic.h" /* MECR: Expansion Memory Configuration Register * (SA-1100 Developers Manual, p.10-13; SA-1110 Developers Manual, p.10-24) @@ -157,15 +155,24 @@ static inline unsigned int sa1100_pcmcia_cmd_time(unsigned int cpu_clock_khz, * use when responding to a Card Services query of some kind. */ struct sa1100_pcmcia_socket { + /* + * Core PCMCIA state + */ socket_state_t cs_state; - struct pcmcia_state k_state; - unsigned int irq; - void (*handler)(void *, unsigned int); - void *handler_info; pccard_io_map io_map[MAX_IO_WIN]; pccard_mem_map mem_map[MAX_WIN]; - ioaddr_t virt_io, phys_attr, phys_mem; + void (*handler)(void *, unsigned int); + void *handler_info; + + struct pcmcia_state k_state; + ioaddr_t phys_attr, phys_mem; + void *virt_io; unsigned short speed_io, speed_attr, speed_mem; + + /* + * Info from low level handler + */ + unsigned int irq; }; @@ -180,23 +187,60 @@ struct sa1100_pcmcia_socket { /* - * Declaration for all implementation specific low_level operations. + * Declaration for all machine specific init/exit functions. */ -extern struct pcmcia_low_level assabet_pcmcia_ops; -extern struct pcmcia_low_level neponset_pcmcia_ops; -extern struct pcmcia_low_level h3600_pcmcia_ops; -extern struct pcmcia_low_level cerf_pcmcia_ops; -extern struct pcmcia_low_level gcplus_pcmcia_ops; -extern struct pcmcia_low_level xp860_pcmcia_ops; -extern struct pcmcia_low_level yopy_pcmcia_ops; -extern struct pcmcia_low_level pangolin_pcmcia_ops; -extern struct pcmcia_low_level freebird_pcmcia_ops; -extern struct pcmcia_low_level pfs168_pcmcia_ops; -extern struct pcmcia_low_level jornada720_pcmcia_ops; -extern struct pcmcia_low_level flexanet_pcmcia_ops; -extern struct pcmcia_low_level simpad_pcmcia_ops; -extern struct pcmcia_low_level graphicsmaster_pcmcia_ops; -extern struct pcmcia_low_level adsbitsy_pcmcia_ops; -extern struct pcmcia_low_level stork_pcmcia_ops; +extern int pcmcia_adsbitsy_init(void); +extern void pcmcia_adsbitsy_exit(void); + +extern int pcmcia_assabet_init(void); +extern void pcmcia_assabet_exit(void); + +extern int pcmcia_badge4_init(void); +extern void pcmcia_badge4_exit(void); + +extern int pcmcia_cerf_init(void); +extern void pcmcia_cerf_exit(void); + +extern int pcmcia_flexanet_init(void); +extern void pcmcia_flexanet_exit(void); + +extern int pcmcia_freebird_init(void); +extern void pcmcia_freebird_exit(void); + +extern int pcmcia_gcplus_init(void); +extern void pcmcia_gcplus_exit(void); + +extern int pcmcia_graphicsmaster_init(void); +extern void pcmcia_graphicsmaster_exit(void); + +extern int pcmcia_jornada720_init(void); +extern void pcmcia_jornada720_exit(void); + +extern int pcmcia_neponset_init(void); +extern void pcmcia_neponset_exit(void); + +extern int pcmcia_pangolin_init(void); +extern void pcmcia_pangolin_exit(void); + +extern int pcmcia_pfs168_init(void); +extern void pcmcia_pfs168_exit(void); + +extern int pcmcia_shannon_init(void); +extern void pcmcia_shannon_exit(void); + +extern int pcmcia_simpad_init(void); +extern void pcmcia_simpad_exit(void); + +extern int pcmcia_stork_init(void); +extern void pcmcia_stork_exit(void); + +extern int pcmcia_system3_init(void); +extern void pcmcia_system3_exit(void); + +extern int pcmcia_xp860_init(void); +extern void pcmcia_xp860_exit(void); + +extern int pcmcia_yopy_init(void); +extern void pcmcia_yopy_exit(void); #endif /* !defined(_PCMCIA_SA1100_H) */ diff --git a/drivers/pcmcia/sa1100_adsbitsy.c b/drivers/pcmcia/sa1100_adsbitsy.c index 1793f24faa70..17d87ab2e2a4 100644 --- a/drivers/pcmcia/sa1100_adsbitsy.c +++ b/drivers/pcmcia/sa1100_adsbitsy.c @@ -11,206 +11,97 @@ */ #include <linux/kernel.h> #include <linux/sched.h> +#include <linux/init.h> -#include <asm/delay.h> #include <asm/hardware.h> -#include <asm/irq.h> -#include <asm/arch/pcmcia.h> + +#include "sa1100_generic.h" +#include "sa1111_generic.h" static int adsbitsy_pcmcia_init(struct pcmcia_init *init) { - int return_val=0; - /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */ PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); /* Disable Power 3.3V/5V for PCMCIA/CF */ PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3; - INTPOL1 |= (1 << (S0_READY_NINT - SA1111_IRQ(32))) | - (1 << (S1_READY_NINT - SA1111_IRQ(32))) | - (1 << (S0_CD_VALID - SA1111_IRQ(32))) | - (1 << (S1_CD_VALID - SA1111_IRQ(32))) | - (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) | - (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))); - - return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT, - "GC Master PCMCIA (0) CD", NULL); - return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT, - "GC Master CF (1) CD", NULL); - return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT, - "GC Master PCMCIA (0) BVD1", NULL); - return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT, - "GC Master CF (1) BVD1", NULL); - + /* Why? */ MECR = 0x09430943; - return (return_val<0) ? -1 : 2; -} - -static int adsbitsy_pcmcia_shutdown(void) -{ - - free_irq(S0_CD_VALID, NULL); - free_irq(S1_CD_VALID, NULL); - free_irq(S0_BVD1_STSCHG, NULL); - free_irq(S1_BVD1_STSCHG, NULL); - - INTPOL1 &= ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) | - (1 << (S1_CD_VALID - SA1111_IRQ(32))) | - (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) | - (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)))); - - return 0; + return sa1111_pcmcia_init(init); } -static int adsbitsy_pcmcia_socket_state(struct pcmcia_state_array *state_array) +static int +adsbitsy_pcmcia_configure_socket(const struct pcmcia_configure *conf) { - unsigned long status; - int return_val=1; - - if(state_array->size<2) return -1; - - memset(state_array->state, 0, - (state_array->size)*sizeof(struct pcmcia_state)); - - status=PCSR; - - state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0; - - state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1; - - state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1; - - state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1; - - state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1; + unsigned int pa_dwr_mask, pa_dwr_set; + int ret; - state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0; - - state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0; - - state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0; - - state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1; - - state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1; - - state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1; - - state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1; - - state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0; - - state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0; - - return return_val; -} - -static int adsbitsy_pcmcia_get_irq_info(struct pcmcia_irq_info *info) -{ - - switch(info->sock){ + switch (conf->sock) { case 0: - info->irq=S0_READY_NINT; - break; - - case 1: - info->irq=S1_READY_NINT; - break; - - default: - return -1; - } - - return 0; -} - -static int adsbitsy_pcmcia_configure_socket(const struct pcmcia_configure *configure) -{ - unsigned long pccr=PCCR, gpio=PA_DWR; - - switch(configure->sock){ - case 0: - - switch(configure->vcc){ - case 0: - pccr = (pccr & ~PCCR_S0_FLT); - gpio |= GPIO_GPIO0 | GPIO_GPIO1; - break; - - case 33: - pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN; - gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1); - gpio &= ~GPIO_GPIO0; - break; - - case 50: - pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN); - gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1); - gpio |= GPIO_GPIO0; - break; + pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1; + switch (conf->vcc) { default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; + case 0: pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1; break; + case 33: pa_dwr_set = GPIO_GPIO1; break; + case 50: pa_dwr_set = GPIO_GPIO0; break; } - - pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST); - break; case 1: - switch(configure->vcc){ - case 0: - pccr = (pccr & ~PCCR_S1_FLT); - gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3); - break; - - case 33: - pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN; - gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3); - gpio |= GPIO_GPIO2; - break; - - case 50: - pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN); - gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3); - gpio |= GPIO_GPIO3; - break; + pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3; + switch (conf->vcc) { default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; + case 0: pa_dwr_set = 0; break; + case 33: pa_dwr_set = GPIO_GPIO2; break; + case 50: pa_dwr_set = GPIO_GPIO3; break; } - if(configure->vpp!=configure->vcc && configure->vpp!=0){ - printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__, - configure->vpp); - return -1; - } - - pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST); - - break; - default: return -1; } - PCCR = pccr; - PA_DWR = gpio; + if (conf->vpp != conf->vcc && conf->vpp != 0) { + printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n", + __FUNCTION__, conf->vpp); + return -1; + } + + ret = sa1111_pcmcia_configure_socket(conf); + if (ret == 0) { + unsigned long flags; - return 0; + local_irq_save(flags); + PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set; + local_irq_restore(flags); + } + + return ret; } -struct pcmcia_low_level adsbitsy_pcmcia_ops = { - adsbitsy_pcmcia_init, - adsbitsy_pcmcia_shutdown, - adsbitsy_pcmcia_socket_state, - adsbitsy_pcmcia_get_irq_info, - adsbitsy_pcmcia_configure_socket +static struct pcmcia_low_level adsbitsy_pcmcia_ops = { + init: adsbitsy_pcmcia_init, + shutdown: sa1111_pcmcia_shutdown, + socket_state: sa1111_pcmcia_socket_state, + get_irq_info: sa1111_pcmcia_get_irq_info, + configure_socket: adsbitsy_pcmcia_configure_socket, + + socket_init: sa1111_pcmcia_socket_init, + socket_suspend: sa1111_pcmcia_socket_suspend, }; +int __init pcmcia_adsbitsy_init(void) +{ + int ret = -ENODEV; + if (machine_is_adsbitsy()) + ret = sa1100_register_pcmcia(&adsbitsy_pcmcia_ops); + return ret; +} + +void __exit pcmcia_adsbitsy_exit(void) +{ + sa1100_unregister_pcmcia(&adsbitsy_pcmcia_ops); +} diff --git a/drivers/pcmcia/sa1100_assabet.c b/drivers/pcmcia/sa1100_assabet.c index 2dd8c9d03919..1a7cc433cf85 100644 --- a/drivers/pcmcia/sa1100_assabet.c +++ b/drivers/pcmcia/sa1100_assabet.c @@ -4,146 +4,221 @@ * PCMCIA implementation routines for Assabet * */ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> +#include <linux/init.h> #include <asm/hardware.h> #include <asm/irq.h> -#include <asm/arch/pcmcia.h> #include <asm/arch/assabet.h> -static int assabet_pcmcia_init(struct pcmcia_init *init){ - int irq, res; +#include "sa1100_generic.h" - /* Enable CF bus: */ - ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF); +static struct irqs { + int irq; + const char *str; +} irqs[] = { + { ASSABET_IRQ_GPIO_CF_CD, "CF_CD" }, + { ASSABET_IRQ_GPIO_CF_BVD2, "CF_BVD2" }, + { ASSABET_IRQ_GPIO_CF_BVD1, "CF_BVD1" }, +}; + +static int assabet_pcmcia_init(struct pcmcia_init *init) +{ + int i, res; + + /* Set transition detect */ + set_irq_type(ASSABET_IRQ_GPIO_CF_IRQ, IRQT_FALLING); - /* All those are inputs */ - GPDR &= ~(ASSABET_GPIO_CF_CD | ASSABET_GPIO_CF_BVD2 | ASSABET_GPIO_CF_BVD1 | ASSABET_GPIO_CF_IRQ); + /* Register interrupts */ + for (i = 0; i < ARRAY_SIZE(irqs); i++) { + set_irq_type(irqs[i].irq, IRQT_NOEDGE); + res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT, + irqs[i].str, NULL); + if (res) + goto irq_err; + } - /* Set transition detect */ - set_GPIO_IRQ_edge( ASSABET_GPIO_CF_CD|ASSABET_GPIO_CF_BVD2|ASSABET_GPIO_CF_BVD1, GPIO_BOTH_EDGES ); - set_GPIO_IRQ_edge( ASSABET_GPIO_CF_IRQ, GPIO_FALLING_EDGE ); + /* There's only one slot, but it's "Slot 1": */ + return 2; - /* Register interrupts */ - irq = ASSABET_IRQ_GPIO_CF_CD; - res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_CD", NULL ); - if( res < 0 ) goto irq_err; - irq = ASSABET_IRQ_GPIO_CF_BVD2; - res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD2", NULL ); - if( res < 0 ) goto irq_err; - irq = ASSABET_IRQ_GPIO_CF_BVD1; - res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD1", NULL ); - if( res < 0 ) goto irq_err; + irq_err: + printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n", + __FUNCTION__, irqs[i].irq, res); - /* There's only one slot, but it's "Slot 1": */ - return 2; + while (i--) + free_irq(irqs[i].irq, NULL); -irq_err: - printk( KERN_ERR "%s: Request for IRQ %u failed\n", __FUNCTION__, irq ); - return -1; + return res; } +/* + * Release all resources. + */ static int assabet_pcmcia_shutdown(void) { - /* disable IRQs */ - free_irq( ASSABET_IRQ_GPIO_CF_CD, NULL ); - free_irq( ASSABET_IRQ_GPIO_CF_BVD2, NULL ); - free_irq( ASSABET_IRQ_GPIO_CF_BVD1, NULL ); - - /* Disable CF bus: */ - ASSABET_BCR_set(ASSABET_BCR_CF_BUS_OFF); + int i; - return 0; + for (i = 0; i < ARRAY_SIZE(irqs); i++) + free_irq(irqs[i].irq, NULL); + + return 0; } -static int assabet_pcmcia_socket_state(struct pcmcia_state_array - *state_array){ - unsigned long levels; +static int +assabet_pcmcia_socket_state(struct pcmcia_state_array *state_array) +{ + unsigned long levels; - if(state_array->size<2) return -1; + if (state_array->size < 2) + return -1; - memset(state_array->state, 0, - (state_array->size)*sizeof(struct pcmcia_state)); + levels = GPLR; - levels=GPLR; + state_array->state[1].detect = (levels & ASSABET_GPIO_CF_CD) ? 0 : 1; + state_array->state[1].ready = (levels & ASSABET_GPIO_CF_IRQ) ? 1 : 0; + state_array->state[1].bvd1 = (levels & ASSABET_GPIO_CF_BVD1) ? 1 : 0; + state_array->state[1].bvd2 = (levels & ASSABET_GPIO_CF_BVD2) ? 1 : 0; + state_array->state[1].wrprot = 0; /* Not available on Assabet. */ + state_array->state[1].vs_3v = 1; /* Can only apply 3.3V on Assabet. */ + state_array->state[1].vs_Xv = 0; - state_array->state[1].detect=((levels & ASSABET_GPIO_CF_CD)==0)?1:0; + return 1; +} - state_array->state[1].ready=(levels & ASSABET_GPIO_CF_IRQ)?1:0; +static int assabet_pcmcia_get_irq_info(struct pcmcia_irq_info *info) +{ + if (info->sock > 1) + return -1; - state_array->state[1].bvd1=(levels & ASSABET_GPIO_CF_BVD1)?1:0; + if (info->sock == 1) + info->irq = ASSABET_IRQ_GPIO_CF_IRQ; - state_array->state[1].bvd2=(levels & ASSABET_GPIO_CF_BVD2)?1:0; + return 0; +} - state_array->state[1].wrprot=0; /* Not available on Assabet. */ +static int +assabet_pcmcia_configure_socket(const struct pcmcia_configure *configure) +{ + unsigned int mask; - state_array->state[1].vs_3v=1; /* Can only apply 3.3V on Assabet. */ + if (configure->sock > 1) + return -1; - state_array->state[1].vs_Xv=0; + if (configure->sock == 0) + return 0; - return 1; -} + switch (configure->vcc) { + case 0: + mask = 0; + break; -static int assabet_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ + case 50: + printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n", + __FUNCTION__); - if(info->sock>1) return -1; + case 33: /* Can only apply 3.3V to the CF slot. */ + mask = ASSABET_BCR_CF_PWR; + break; - if(info->sock==1) - info->irq=ASSABET_IRQ_GPIO_CF_IRQ; + default: + printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, + configure->vcc); + return -1; + } - return 0; -} + /* Silently ignore Vpp, output enable, speaker enable. */ -static int assabet_pcmcia_configure_socket(const struct pcmcia_configure - *configure) -{ - unsigned long value, flags; + if (configure->reset) + mask |= ASSABET_BCR_CF_RST; - if(configure->sock>1) return -1; + ASSABET_BCR_frob(ASSABET_BCR_CF_RST | ASSABET_BCR_CF_PWR, mask); - if(configure->sock==0) return 0; + /* + * Handle suspend mode properly. This prevents a + * flood of IRQs from the CF device. + */ + if (configure->irq) + enable_irq(ASSABET_IRQ_GPIO_CF_IRQ); + else + disable_irq(ASSABET_IRQ_GPIO_CF_IRQ); - save_flags_cli(flags); + return 0; +} - value = BCR_value; +/* + * Enable card status IRQs on (re-)initialisation. This can + * be called at initialisation, power management event, or + * pcmcia event. + */ +static int assabet_pcmcia_socket_init(int sock) +{ + int i; - switch(configure->vcc){ - case 0: - value &= ~ASSABET_BCR_CF_PWR; - break; + if (sock == 1) { + /* + * Enable CF bus + */ + ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF); - case 50: - printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n", - __FUNCTION__); + for (i = 0; i < ARRAY_SIZE(irqs); i++) + set_irq_type(irqs[i].irq, IRQT_BOTHEDGE); + } - case 33: /* Can only apply 3.3V to the CF slot. */ - value |= ASSABET_BCR_CF_PWR; - break; + return 0; +} - default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - restore_flags(flags); - return -1; - } +/* + * Disable card status IRQs on suspend. + */ +static int assabet_pcmcia_socket_suspend(int sock) +{ + int i; - value = (configure->reset) ? (value | ASSABET_BCR_CF_RST) : (value & ~ASSABET_BCR_CF_RST); + if (sock == 1) { + for (i = 0; i < ARRAY_SIZE(irqs); i++) + set_irq_type(irqs[i].irq, IRQT_NOEDGE); - /* Silently ignore Vpp, output enable, speaker enable. */ + /* + * Tristate the CF bus signals. Also assert CF + * reset as per user guide page 4-11. + */ + ASSABET_BCR_set(ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_CF_RST); + } - ASSABET_BCR = BCR_value = value; + return 0; +} + +static struct pcmcia_low_level assabet_pcmcia_ops = { + init: assabet_pcmcia_init, + shutdown: assabet_pcmcia_shutdown, + socket_state: assabet_pcmcia_socket_state, + get_irq_info: assabet_pcmcia_get_irq_info, + configure_socket: assabet_pcmcia_configure_socket, - restore_flags(flags); + socket_init: assabet_pcmcia_socket_init, + socket_suspend: assabet_pcmcia_socket_suspend, +}; - return 0; +int __init pcmcia_assabet_init(void) +{ + int ret = -ENODEV; + + if (machine_is_assabet()) { + if (!machine_has_neponset()) + ret = sa1100_register_pcmcia(&assabet_pcmcia_ops); +#ifndef CONFIG_ASSABET_NEPONSET + else + printk(KERN_ERR "Card Services disabled: missing " + "Neponset support\n"); +#endif + } + return ret; } -struct pcmcia_low_level assabet_pcmcia_ops = { - assabet_pcmcia_init, - assabet_pcmcia_shutdown, - assabet_pcmcia_socket_state, - assabet_pcmcia_get_irq_info, - assabet_pcmcia_configure_socket -}; +void __exit pcmcia_assabet_exit(void) +{ + sa1100_unregister_pcmcia(&assabet_pcmcia_ops); +} diff --git a/drivers/pcmcia/sa1100_badge4.c b/drivers/pcmcia/sa1100_badge4.c new file mode 100644 index 000000000000..41cba02b9944 --- /dev/null +++ b/drivers/pcmcia/sa1100_badge4.c @@ -0,0 +1,186 @@ +/* + * linux/drivers/pcmcia/sa1100_badge4.c + * + * BadgePAD 4 PCMCIA specific routines + * + * Christopher Hoover <ch@hpl.hp.com> + * + * Copyright (C) 2002 Hewlett-Packard Company + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/init.h> + +#include <asm/hardware.h> +#include <asm/arch/badge4.h> +#include <asm/hardware/sa1111.h> + +#include "sa1100_generic.h" +#include "sa1111_generic.h" + +/* + * BadgePAD 4 Details + * + * PCM Vcc: + * + * PCM Vcc on BadgePAD 4 can be jumpered for 3.3V (short pins 1 and 3 + * on JP6) or 5V (short pins 3 and 5 on JP6). N.B., 5V supply rail + * is enabled by the SA-1110's BADGE4_GPIO_PCMEN5V (GPIO 24). + * + * PCM Vpp: + * + * PCM Vpp on BadgePAD 4 can be jumpered for 12V (short pins 2 and 4 + * on JP6) or tied to PCM Vcc (short pins 4 and 6 on JP6). N.B., 12V + * operation requires that the power supply actually supply 12V. + * + * CF Vcc: + * + * CF Vcc on BadgePAD 4 can be jumpered either for 3.3V (short pins 1 + * and 2 on JP10) or 5V (short pins 2 and 3 on JP10). The note above + * about the 5V supply rail applies. + * + * There's no way programmatically to determine how a given board is + * jumpered. This code assumes a default jumpering: 5V PCM Vcc (pins + * 3 and 5 shorted) and PCM Vpp = PCM Vcc (pins 4 and 6 shorted) and + * no jumpering for CF Vcc. If this isn't correct, Override these + * defaults with a pcmv setup argument: pcmv=<pcm vcc>,<pcm vpp>,<cf + * vcc>. E.g. pcmv=33,120,50 indicates 3.3V PCM Vcc, 12.0V PCM Vpp, + * and 5.0V CF Vcc. + * + */ + +static int badge4_pcmvcc = 50; +static int badge4_pcmvpp = 50; +static int badge4_cfvcc = 0; + +static int badge4_pcmcia_init(struct pcmcia_init *init) +{ + printk(KERN_INFO __FUNCTION__ + ": badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n", + badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc); + + return sa1111_pcmcia_init(init); +} + +static int badge4_pcmcia_shutdown(void) +{ + int rc = sa1111_pcmcia_shutdown(); + + /* be sure to disable 5V use */ + badge4_set_5V(BADGE4_5V_PCMCIA_SOCK0, 0); + badge4_set_5V(BADGE4_5V_PCMCIA_SOCK1, 0); + + return rc; +} + +static void complain_about_jumpering(const char *whom, + const char *supply, + int given, int wanted) +{ + printk(KERN_ERR + "%s: %s %d.%dV wanted but board is jumpered for %s %d.%dV operation" + "; re-jumper the board and/or use pcmv=xx,xx,xx\n", + whom, supply, + wanted / 10, wanted % 10, + supply, + given / 10, given % 10); +} + +static unsigned badge4_need_5V_bitmap = 0; + +static int +badge4_pcmcia_configure_socket(const struct pcmcia_configure *conf) +{ + int ret; + + switch (conf->sock) { + case 0: + if ((conf->vcc != 0) && + (conf->vcc != badge4_pcmvcc)) { + complain_about_jumpering(__FUNCTION__, "pcmvcc", + badge4_pcmvcc, conf->vcc); + return -1; + } + if ((conf->vpp != 0) && + (conf->vpp != badge4_pcmvpp)) { + complain_about_jumpering(__FUNCTION__, "pcmvpp", + badge4_pcmvpp, conf->vpp); + return -1; + } + break; + + case 1: + if ((conf->vcc != 0) && + (conf->vcc != badge4_cfvcc)) { + complain_about_jumpering(__FUNCTION__, "cfvcc", + badge4_cfvcc, conf->vcc); + return -1; + } + break; + + default: + return -1; + } + + ret = sa1111_pcmcia_configure_socket(conf); + if (ret == 0) { + unsigned long flags; + int need5V; + + local_irq_save(flags); + + need5V = ((conf->vcc == 50) || (conf->vpp == 50)); + + badge4_set_5V(BADGE4_5V_PCMCIA_SOCK(conf->sock), need5V); + + local_irq_restore(flags); + } + + return 0; +} + +static struct pcmcia_low_level badge4_pcmcia_ops = { + init: badge4_pcmcia_init, + shutdown: badge4_pcmcia_shutdown, + socket_state: sa1111_pcmcia_socket_state, + get_irq_info: sa1111_pcmcia_get_irq_info, + configure_socket: badge4_pcmcia_configure_socket, + + socket_init: sa1111_pcmcia_socket_init, + socket_suspend: sa1111_pcmcia_socket_suspend, +}; + +int __init pcmcia_badge4_init(void) +{ + int ret = -ENODEV; + + if (machine_is_badge4()) + ret = sa1100_register_pcmcia(&badge4_pcmcia_ops); + + return ret; +} + +void __exit pcmcia_badge4_exit(void) +{ + sa1100_unregister_pcmcia(&badge4_pcmcia_ops); +} + +static int __init pcmv_setup(char *s) +{ + int v[4]; + + s = get_options(s, ARRAY_SIZE(v), v); + + if (v[0] >= 1) badge4_pcmvcc = v[1]; + if (v[0] >= 2) badge4_pcmvpp = v[2]; + if (v[0] >= 3) badge4_cfvcc = v[3]; + + return 1; +} + +__setup("pcmv=", pcmv_setup); diff --git a/drivers/pcmcia/sa1100_cerf.c b/drivers/pcmcia/sa1100_cerf.c index 3b19eeba5924..f3142cea6deb 100644 --- a/drivers/pcmcia/sa1100_cerf.c +++ b/drivers/pcmcia/sa1100_cerf.c @@ -5,45 +5,62 @@ * Based off the Assabet. * */ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> +#include <linux/init.h> #include <asm/hardware.h> #include <asm/irq.h> -#include <asm/arch/pcmcia.h> +#include "sa1100_generic.h" +#ifdef CONFIG_SA1100_CERF_CPLD +#define CERF_SOCKET 0 +#else +#define CERF_SOCKET 1 +#endif -static int cerf_pcmcia_init(struct pcmcia_init *init){ - int irq, res; +static struct irqs { + int irq; + const char *str; +} irqs[] = { + { IRQ_GPIO_CF_CD, "CF_CD" }, + { IRQ_GPIO_CF_BVD2, "CF_BVD2" }, + { IRQ_GPIO_CF_BVD1, "CF_BVD1" } +}; - GPDR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IRQ); - GPDR |= (GPIO_CF_RESET); +static int cerf_pcmcia_init(struct pcmcia_init *init) +{ + int i, res; - set_GPIO_IRQ_edge( GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1, GPIO_BOTH_EDGES ); - set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE ); + set_irq_type(IRQ_GPIO_CF_IRQ, IRQT_FALLING); - irq = IRQ_GPIO_CF_CD; - res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_CD", NULL ); - if( res < 0 ) goto irq_err; - irq = IRQ_GPIO_CF_BVD2; - res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD2", NULL ); - if( res < 0 ) goto irq_err; - irq = IRQ_GPIO_CF_BVD1; - res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD1", NULL ); - if( res < 0 ) goto irq_err; + for (i = 0; i < ARRAY_SIZE(irqs); i++) { + set_irq_type(irqs[i].irq, IRQT_NOEDGE); + res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT, + irqs[i].str, NULL); + if (res) + goto irq_err; + } return 2; -irq_err: - printk( KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq ); - return -1; + irq_err: + printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n", + __FUNCTION__, irqs[i].irq, res); + + while (i--) + free_irq(irqs[i].irq, NULL); + + return res; } static int cerf_pcmcia_shutdown(void) { - free_irq( IRQ_GPIO_CF_CD, NULL ); - free_irq( IRQ_GPIO_CF_BVD2, NULL ); - free_irq( IRQ_GPIO_CF_BVD1, NULL ); + int i; + + for (i = 0; i < ARRAY_SIZE(irqs); i++) + free_irq(irqs[i].irq, NULL); return 0; } @@ -51,31 +68,18 @@ static int cerf_pcmcia_shutdown(void) static int cerf_pcmcia_socket_state(struct pcmcia_state_array *state_array){ unsigned long levels; -#ifdef CONFIG_SA1100_CERF_CPLD - int i = 0; -#else - int i = 1; -#endif + int i = CERF_SOCKET; if(state_array->size<2) return -1; - memset(state_array->state, 0, - (state_array->size)*sizeof(struct pcmcia_state)); - levels=GPLR; state_array->state[i].detect=((levels & GPIO_CF_CD)==0)?1:0; - state_array->state[i].ready=(levels & GPIO_CF_IRQ)?1:0; - state_array->state[i].bvd1=(levels & GPIO_CF_BVD1)?1:0; - state_array->state[i].bvd2=(levels & GPIO_CF_BVD2)?1:0; - state_array->state[i].wrprot=0; - state_array->state[i].vs_3v=1; - state_array->state[i].vs_Xv=0; return 1; @@ -85,11 +89,7 @@ static int cerf_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ if(info->sock>1) return -1; -#ifdef CONFIG_SA1100_CERF_CPLD - if(info->sock==0) -#else - if(info->sock==1) -#endif + if (info->sock == CERF_SOCKET) info->irq=IRQ_GPIO_CF_IRQ; return 0; @@ -98,20 +98,12 @@ static int cerf_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ static int cerf_pcmcia_configure_socket(const struct pcmcia_configure *configure) { - unsigned long flags; - if(configure->sock>1) return -1; -#ifdef CONFIG_SA1100_CERF_CPLD - if(configure->sock==1) -#else - if(configure->sock==0) -#endif + if (configure->sock != CERF_SOCKET) return 0; - save_flags_cli(flags); - switch(configure->vcc){ case 0: break; @@ -119,43 +111,76 @@ static int cerf_pcmcia_configure_socket(const struct pcmcia_configure case 50: case 33: #ifdef CONFIG_SA1100_CERF_CPLD - GPDR |= GPIO_PWR_SHUTDOWN; - GPCR |= GPIO_PWR_SHUTDOWN; + GPCR = GPIO_PWR_SHUTDOWN; #endif break; default: printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, configure->vcc); - restore_flags(flags); return -1; } if(configure->reset) { #ifdef CONFIG_SA1100_CERF_CPLD - GPDR |= GPIO_CF_RESET; - GPSR |= GPIO_CF_RESET; + GPSR = GPIO_CF_RESET; #endif } else { #ifdef CONFIG_SA1100_CERF_CPLD - GPDR |= GPIO_CF_RESET; - GPCR |= GPIO_CF_RESET; + GPCR = GPIO_CF_RESET; #endif } - restore_flags(flags); + return 0; +} + +static int cerf_pcmcia_socket_init(int sock) +{ + int i; + + if (sock == CERF_SOCKET) + for (i = 0; i < ARRAY_SIZE(irqs); i++) + set_irq_type(irqs[i].irq, IRQT_BOTHEDGE); return 0; } -struct pcmcia_low_level cerf_pcmcia_ops = { - cerf_pcmcia_init, - cerf_pcmcia_shutdown, - cerf_pcmcia_socket_state, - cerf_pcmcia_get_irq_info, - cerf_pcmcia_configure_socket +static int cerf_pcmcia_socket_suspend(int sock) +{ + int i; + + if (sock == CERF_SOCKET) + for (i = 0; i < ARRAY_SIZE(irqs); i++) + set_irq_type(irqs[i].irq, IRQT_NOEDGE); + + return 0; +} + +static struct pcmcia_low_level cerf_pcmcia_ops = { + init: cerf_pcmcia_init, + shutdown: cerf_pcmcia_shutdown, + socket_state: cerf_pcmcia_socket_state, + get_irq_info: cerf_pcmcia_get_irq_info, + configure_socket: cerf_pcmcia_configure_socket, + + socket_init: cerf_pcmcia_socket_init, + socket_suspend: cerf_pcmcia_socket_suspend, }; +int __init pcmcia_cerf_init(void) +{ + int ret = -ENODEV; + + if (machine_is_cerf()) + ret = sa1100_register_pcmcia(&cerf_pcmcia_ops); + + return ret; +} + +void __exit pcmcia_cerf_exit(void) +{ + sa1100_unregister_pcmcia(&cerf_pcmcia_ops); +} diff --git a/drivers/pcmcia/sa1100_flexanet.c b/drivers/pcmcia/sa1100_flexanet.c index 14f94bc810fb..edb8c9c029cf 100644 --- a/drivers/pcmcia/sa1100_flexanet.c +++ b/drivers/pcmcia/sa1100_flexanet.c @@ -4,16 +4,25 @@ * PCMCIA implementation routines for Flexanet. * by Jordi Colomer, 09/05/2001 * - * Yet to be defined. */ #include <linux/kernel.h> #include <linux/sched.h> +#include <linux/init.h> #include <asm/hardware.h> #include <asm/irq.h> -#include <asm/arch/pcmcia.h> - +#include "sa1100_generic.h" + +static struct { + int irq; + const char *name; +} irqs[] = { + { IRQ_GPIO_CF1_CD, "CF1_CD" }, + { IRQ_GPIO_CF1_BVD1, "CF1_BVD1" }, + { IRQ_GPIO_CF2_CD, "CF2_CD" }, + { IRQ_GPIO_CF2_BVD1, "CF2_BVD1" } +}; /* * Socket initialization. @@ -22,9 +31,37 @@ * Must return the number of slots. * */ -static int flexanet_pcmcia_init(struct pcmcia_init *init){ - - return 0; +static int flexanet_pcmcia_init(struct pcmcia_init *init) +{ + int i, res; + + /* Configure the GPIOs as inputs (BVD2 is not implemented) */ + GPDR &= ~(GPIO_CF1_NCD | GPIO_CF1_BVD1 | GPIO_CF1_IRQ | + GPIO_CF2_NCD | GPIO_CF2_BVD1 | GPIO_CF2_IRQ ); + + /* Set IRQ edge */ + set_irq_type(IRQ_GPIO_CF1_IRQ, IRQT_FALLING); + set_irq_type(IRQ_GPIO_CF2_IRQ, IRQT_FALLING); + + /* Register the socket interrupts (not the card interrupts) */ + for (i = 0; i < ARRAY_SIZE(irqs); i++) { + set_irq_type(irqs[i].irq, IRQT_NOEDGE); + res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT, + irqs[i].name, NULL); + if (res < 0) + break; + } + + /* If we failed, then free all interrupts requested thus far. */ + if (res < 0) { + printk(KERN_ERR "%s: request for IRQ%d failed: %d\n", + __FUNCTION__, irqs[i].irq, res); + while (i--) + free_irq(irqs[i].irq, NULL); + return res; + } + + return 2; } @@ -34,6 +71,12 @@ static int flexanet_pcmcia_init(struct pcmcia_init *init){ */ static int flexanet_pcmcia_shutdown(void) { + int i; + + /* disable IRQs */ + for (i = 0; i < ARRAY_SIZE(irqs); i++) + free_irq(irqs[i].irq, NULL); + return 0; } @@ -46,7 +89,33 @@ static int flexanet_pcmcia_shutdown(void) */ static int flexanet_pcmcia_socket_state(struct pcmcia_state_array *state_array){ - return -1; + unsigned long levels; + + if (state_array->size < 2) + return -1; + + /* Sense the GPIOs, asynchronously */ + levels = GPLR; + + /* Socket 0 */ + state_array->state[0].detect = ((levels & GPIO_CF1_NCD)==0)?1:0; + state_array->state[0].ready = (levels & GPIO_CF1_IRQ)?1:0; + state_array->state[0].bvd1 = (levels & GPIO_CF1_BVD1)?1:0; + state_array->state[0].bvd2 = 1; + state_array->state[0].wrprot = 0; + state_array->state[0].vs_3v = 1; + state_array->state[0].vs_Xv = 0; + + /* Socket 1 */ + state_array->state[1].detect = ((levels & GPIO_CF2_NCD)==0)?1:0; + state_array->state[1].ready = (levels & GPIO_CF2_IRQ)?1:0; + state_array->state[1].bvd1 = (levels & GPIO_CF2_BVD1)?1:0; + state_array->state[1].bvd2 = 1; + state_array->state[1].wrprot = 0; + state_array->state[1].vs_3v = 1; + state_array->state[1].vs_Xv = 0; + + return 1; } @@ -56,7 +125,16 @@ static int flexanet_pcmcia_socket_state(struct pcmcia_state_array */ static int flexanet_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ - return -1; + /* check the socket index */ + if (info->sock > 1) + return -1; + + if (info->sock == 0) + info->irq = IRQ_GPIO_CF1_IRQ; + else if (info->sock == 1) + info->irq = IRQ_GPIO_CF2_IRQ; + + return 0; } @@ -66,19 +144,105 @@ static int flexanet_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ static int flexanet_pcmcia_configure_socket(const struct pcmcia_configure *configure) { - return -1; + unsigned long value, flags, mask; + + + if (configure->sock > 1) + return -1; + + /* Ignore the VCC level since it is 3.3V and always on */ + switch (configure->vcc) + { + case 0: + printk(KERN_WARNING "%s(): CS asked to power off.\n", __FUNCTION__); + break; + + case 50: + printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n", + __FUNCTION__); + + case 33: + break; + + default: + printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, + configure->vcc); + return -1; + } + + /* Reset the slot(s) using the controls in the BCR */ + mask = 0; + + switch (configure->sock) + { + case 0 : mask = FHH_BCR_CF1_RST; break; + case 1 : mask = FHH_BCR_CF2_RST; break; + } + + local_irq_save(flags); + + value = flexanet_BCR; + value = (configure->reset) ? (value | mask) : (value & ~mask); + FHH_BCR = flexanet_BCR = value; + + local_irq_restore(flags); + + return 0; +} + +static int flexanet_pcmcia_socket_init(int sock) +{ + if (sock == 0) { + set_irq_type(IRQ_GPIO_CF1_CD, IRQT_BOTHEDGE); + set_irq_type(IRQ_GPIO_CF1_BVD1, IRQT_BOTHEDGE); + } else if (sock == 1) { + set_irq_type(IRQ_GPIO_CF2_CD, IRQT_BOTHEDGE); + set_irq_type(IRQ_GPIO_CF2_BVD1, IRQT_BOTHEDGE); + } + + return 0; } +static int flexanet_pcmcia_socket_suspend(int sock) +{ + if (sock == 0) { + set_irq_type(IRQ_GPIO_CF1_CD, IRQT_NOEDGE); + set_irq_type(IRQ_GPIO_CF1_BVD1, IRQT_NOEDGE); + } else if (sock == 1) { + set_irq_type(IRQ_GPIO_CF2_CD, IRQT_NOEDGE); + set_irq_type(IRQ_GPIO_CF2_BVD1, IRQT_NOEDGE); + } + + return 0; +} /* * The set of socket operations * */ -struct pcmcia_low_level flexanet_pcmcia_ops = { - flexanet_pcmcia_init, - flexanet_pcmcia_shutdown, - flexanet_pcmcia_socket_state, - flexanet_pcmcia_get_irq_info, - flexanet_pcmcia_configure_socket +static struct pcmcia_low_level flexanet_pcmcia_ops = { + init: flexanet_pcmcia_init, + shutdown: flexanet_pcmcia_shutdown, + socket_state: flexanet_pcmcia_socket_state, + get_irq_info: flexanet_pcmcia_get_irq_info, + configure_socket: flexanet_pcmcia_configure_socket, + + socket_init: flexanet_pcmcia_socket_init, + socket_suspend: flexanet_pcmcia_socket_suspend, }; +int __init pcmcia_flexanet_init(void) +{ + int ret = -ENODEV; + + if (machine_is_flexanet()) + ret = sa1100_register_pcmcia(&flexanet_pcmcia_ops); + + return ret; +} + +void __exit pcmcia_flexanet_exit(void) +{ + sa1100_unregister_pcmcia(&flexanet_pcmcia_ops); +} + diff --git a/drivers/pcmcia/sa1100_freebird.c b/drivers/pcmcia/sa1100_freebird.c index f47bd57a5e7f..99cbb28a0e66 100644 --- a/drivers/pcmcia/sa1100_freebird.c +++ b/drivers/pcmcia/sa1100_freebird.c @@ -6,14 +6,22 @@ */ #include <linux/kernel.h> #include <linux/sched.h> +#include <linux/init.h> #include <asm/hardware.h> #include <asm/irq.h> -#include <asm/arch/pcmcia.h> - +#include "sa1100_generic.h" + +static struct irqs { + int irq; + const char *str; +} irqs[] = { + { IRQ_GPIO_FREEBIRD_CF_CD, "CF_CD" }, + { IRQ_GPIO_FREEBIRD_CF_BVD, "CF_BVD1" }, +}; static int freebird_pcmcia_init(struct pcmcia_init *init){ - int irq, res; + int i, res; /* Enable Linkup CF card */ LINKUP_PRC = 0xc0; @@ -26,37 +34,38 @@ static int freebird_pcmcia_init(struct pcmcia_init *init){ mdelay(100); LINKUP_PRC = 0xc0; - /* All those are inputs */ - ////GPDR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IRQ); - GPDR &= ~(GPIO_FREEBIRD_CF_CD | GPIO_FREEBIRD_CF_IRQ | GPIO_FREEBIRD_CF_BVD); - /* Set transition detect */ - //set_GPIO_IRQ_edge( GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1, GPIO_BOTH_EDGES ); - //set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE ); - set_GPIO_IRQ_edge(GPIO_FREEBIRD_CF_CD|GPIO_FREEBIRD_CF_BVD,GPIO_BOTH_EDGES); - set_GPIO_IRQ_edge(GPIO_FREEBIRD_CF_IRQ, GPIO_FALLING_EDGE); + set_irq_type(IRQ_GPIO_FREEBIRD_CF_IRQ, IRQT_FALLING); /* Register interrupts */ - irq = IRQ_GPIO_FREEBIRD_CF_CD; - res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_CD", NULL ); - if( res < 0 ) goto irq_err; - irq = IRQ_GPIO_FREEBIRD_CF_BVD; - res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD1", NULL ); - if( res < 0 ) goto irq_err; + for (i = 0; i < ARRAY_SIZE(irqs); i++) { + set_irq_type(irqs[i].irq, IRQT_NOEDGE); + res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT, + irqs[i].str, NULL); + if (res) + goto irq_err; + } /* There's only one slot, but it's "Slot 1": */ return 2; irq_err: - printk( KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq ); - return -1; + printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n", + __FUNCTION__, irqs[i].irq, res); + + while (i--) + free_irq(irqs[i].irq, NULL); + + return res; } static int freebird_pcmcia_shutdown(void) { + int i; + /* disable IRQs */ - free_irq( IRQ_GPIO_FREEBIRD_CF_CD, NULL ); - free_irq( IRQ_GPIO_FREEBIRD_CF_BVD, NULL ); + for (i = 0; i < ARRAY_SIZE(irqs); i++) + free_irq(irqs[i].irq, NULL); /* Disable CF card */ LINKUP_PRC = 0x40; /* SSP=1 SOE=0 */ @@ -75,7 +84,7 @@ static int freebird_pcmcia_socket_state(struct pcmcia_state_array (state_array->size)*sizeof(struct pcmcia_state)); levels = LINKUP_PRS; -//printk("LINKUP_PRS=%x \n",levels); +//printk("LINKUP_PRS=%x\n",levels); state_array->state[0].detect= ((levels & (LINKUP_CD1 | LINKUP_CD2))==0)?1:0; @@ -114,7 +123,7 @@ static int freebird_pcmcia_configure_socket(const struct pcmcia_configure if(configure->sock==1) return 0; - save_flags_cli(flags); + local_irq_save(flags); value = 0xc0; /* SSP=1 SOE=1 CFE=1 */ @@ -134,7 +143,7 @@ static int freebird_pcmcia_configure_socket(const struct pcmcia_configure default: printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, configure->vcc); - restore_flags(flags); + local_irq_restore(flags); return -1; } @@ -145,16 +154,51 @@ static int freebird_pcmcia_configure_socket(const struct pcmcia_configure LINKUP_PRC = value; //printk("LINKUP_PRC=%x\n",value); - restore_flags(flags); + local_irq_restore(flags); return 0; } -struct pcmcia_low_level freebird_pcmcia_ops = { - freebird_pcmcia_init, - freebird_pcmcia_shutdown, - freebird_pcmcia_socket_state, - freebird_pcmcia_get_irq_info, - freebird_pcmcia_configure_socket +static int freebird_pcmcia_socket_init(int sock) +{ + if (sock == 1) { + set_irq_type(IRQ_GPIO_FREEBIRD_CF_CD, IRQT_BOTHEDGE); + set_irq_type(IRQ_GPIO_FREEBIRD_CF_BVD, IRQT_BOTHEDGE); + } + return 0; +} + +static int freebird_pcmcia_socket_suspend(int sock) +{ + if (sock == 1) { + set_irq_type(IRQ_GPIO_FREEBIRD_CF_CD, IRQT_NOEDGE); + set_irq_type(IRQ_GPIO_FREEBIRD_CF_BVD, IRQT_NOEDGE); + } + return 0; +} + +static struct pcmcia_low_level freebird_pcmcia_ops = { + init: freebird_pcmcia_init, + shutdown: freebird_pcmcia_shutdown, + socket_state: freebird_pcmcia_socket_state, + get_irq_info: freebird_pcmcia_get_irq_info, + configure_socket: freebird_pcmcia_configure_socket, + + socket_init: freebird_pcmcia_socket_init, + socket_suspend: freebird_pcmcia_socket_suspend, }; +int __init pcmcia_freebird_init(void) +{ + int ret = -ENODEV; + + if (machine_is_freebird()) + ret = sa1100_register_pcmcia(&freebird_pcmcia_ops); + + return ret; +} + +void __exit pcmcia_freebird_exit(void) +{ + sa1100_unregister_pcmcia(&freebird_pcmcia_ops); +} diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index 5b73df88e510..a70ac75a0047 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c @@ -29,6 +29,10 @@ file under either the MPL or the GPL. ======================================================================*/ +/* + * Please see linux/Documentation/arm/SA1100/PCMCIA for more information + * on the low-level kernel interface. + */ #include <linux/module.h> #include <linux/init.h> @@ -43,6 +47,7 @@ #include <linux/notifier.h> #include <linux/proc_fs.h> #include <linux/version.h> +#include <linux/cpufreq.h> #include <pcmcia/version.h> #include <pcmcia/cs_types.h> @@ -62,338 +67,94 @@ static int pc_debug; #endif -MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>"); -MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-1100 Socket Controller"); - /* This structure maintains housekeeping state for each socket, such * as the last known values of the card detect pins, or the Card Services * callback value associated with the socket: */ -static struct sa1100_pcmcia_socket -sa1100_pcmcia_socket[SA1100_PCMCIA_MAX_SOCK]; - static int sa1100_pcmcia_socket_count; +static struct sa1100_pcmcia_socket sa1100_pcmcia_socket[SA1100_PCMCIA_MAX_SOCK]; +#define PCMCIA_SOCKET(x) (sa1100_pcmcia_socket + (x)) /* Returned by the low-level PCMCIA interface: */ static struct pcmcia_low_level *pcmcia_low_level; -/* Event poll timer structure */ static struct timer_list poll_timer; - - -/* Prototypes for routines which are used internally: */ - -static int sa1100_pcmcia_driver_init(void); -static void sa1100_pcmcia_driver_shutdown(void); -static void sa1100_pcmcia_task_handler(void *data); -static void sa1100_pcmcia_poll_event(unsigned long data); -static void sa1100_pcmcia_interrupt(int irq, void *dev, - struct pt_regs *regs); static struct tq_struct sa1100_pcmcia_task; -#ifdef CONFIG_PROC_FS -static int sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos, - int count, int *eof, void *data); -#endif - - -/* Prototypes for operations which are exported to the - * new-and-impr^H^H^H^H^H^H^H^H^H^H in-kernel PCMCIA core: +/* + * sa1100_pcmcia_state_to_config + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * + * Convert PCMCIA socket state to our socket configure structure. */ +static struct pcmcia_configure +sa1100_pcmcia_state_to_config(unsigned int sock, socket_state_t *state) +{ + struct pcmcia_configure conf; -static int sa1100_pcmcia_init(unsigned int sock); -static int sa1100_pcmcia_suspend(unsigned int sock); -static int sa1100_pcmcia_register_callback(unsigned int sock, - void (*handler)(void *, - unsigned int), - void *info); -static int sa1100_pcmcia_inquire_socket(unsigned int sock, - socket_cap_t *cap); -static int sa1100_pcmcia_get_status(unsigned int sock, u_int *value); -static int sa1100_pcmcia_get_socket(unsigned int sock, - socket_state_t *state); -static int sa1100_pcmcia_set_socket(unsigned int sock, - socket_state_t *state); -static int sa1100_pcmcia_get_io_map(unsigned int sock, - struct pccard_io_map *io); -static int sa1100_pcmcia_set_io_map(unsigned int sock, - struct pccard_io_map *io); -static int sa1100_pcmcia_get_mem_map(unsigned int sock, - struct pccard_mem_map *mem); -static int sa1100_pcmcia_set_mem_map(unsigned int sock, - struct pccard_mem_map *mem); -#ifdef CONFIG_PROC_FS -static void sa1100_pcmcia_proc_setup(unsigned int sock, - struct proc_dir_entry *base); -#endif - -static struct pccard_operations sa1100_pcmcia_operations = { - sa1100_pcmcia_init, - sa1100_pcmcia_suspend, - sa1100_pcmcia_register_callback, - sa1100_pcmcia_inquire_socket, - sa1100_pcmcia_get_status, - sa1100_pcmcia_get_socket, - sa1100_pcmcia_set_socket, - sa1100_pcmcia_get_io_map, - sa1100_pcmcia_set_io_map, - sa1100_pcmcia_get_mem_map, - sa1100_pcmcia_set_mem_map, -#ifdef CONFIG_PROC_FS - sa1100_pcmcia_proc_setup -#endif -}; - -#ifdef CONFIG_CPU_FREQ -/* forward declaration */ -static struct notifier_block sa1100_pcmcia_notifier_block; -#endif + conf.sock = sock; + conf.vcc = state->Vcc; + conf.vpp = state->Vpp; + conf.output = state->flags & SS_OUTPUT_ENA ? 1 : 0; + conf.speaker = state->flags & SS_SPKR_ENA ? 1 : 0; + conf.reset = state->flags & SS_RESET ? 1 : 0; + conf.irq = state->io_irq != 0; + return conf; +} -/* sa1100_pcmcia_driver_init() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * - * This routine performs a basic sanity check to ensure that this - * kernel has been built with the appropriate board-specific low-level - * PCMCIA support, performs low-level PCMCIA initialization, registers - * this socket driver with Card Services, and then spawns the daemon - * thread which is the real workhorse of the socket driver. +/* sa1100_pcmcia_sock_init() + * ^^^^^^^^^^^^^^^^^^^^^^^^^ * - * Please see linux/Documentation/arm/SA1100/PCMCIA for more information - * on the low-level kernel interface. + * (Re-)Initialise the socket, turning on status interrupts + * and PCMCIA bus. This must wait for power to stabilise + * so that the card status signals report correctly. * - * Returns: 0 on success, -1 on error - */ -static int __init sa1100_pcmcia_driver_init(void){ - servinfo_t info; - struct pcmcia_init pcmcia_init; - struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK]; - struct pcmcia_state_array state_array; - unsigned int i, clock; - unsigned long mecr; - - printk(KERN_INFO "SA-1100 PCMCIA (CS release %s)\n", CS_RELEASE); - - CardServices(GetCardServicesInfo, &info); - - if(info.Revision!=CS_RELEASE_CODE){ - printk(KERN_ERR "Card Services release codes do not match\n"); - return -1; - } - - if(machine_is_assabet()){ -#ifdef CONFIG_SA1100_ASSABET - if(machine_has_neponset()){ -#ifdef CONFIG_ASSABET_NEPONSET - pcmcia_low_level=&neponset_pcmcia_ops; -#else - printk(KERN_ERR "Card Services disabled: missing Neponset support\n"); - return -1; -#endif - }else{ - pcmcia_low_level=&assabet_pcmcia_ops; - } -#endif - } else if (machine_is_freebird()) { -#ifdef CONFIG_SA1100_FREEBIRD - pcmcia_low_level = &freebird_pcmcia_ops; -#endif - } else if (machine_is_h3600()) { -#ifdef CONFIG_SA1100_H3600 - pcmcia_low_level = &h3600_pcmcia_ops; -#endif - } else if (machine_is_cerf()) { -#ifdef CONFIG_SA1100_CERF - pcmcia_low_level = &cerf_pcmcia_ops; -#endif - } else if (machine_is_graphicsclient()) { -#ifdef CONFIG_SA1100_GRAPHICSCLIENT - pcmcia_low_level = &gcplus_pcmcia_ops; -#endif - } else if (machine_is_xp860()) { -#ifdef CONFIG_SA1100_XP860 - pcmcia_low_level = &xp860_pcmcia_ops; -#endif - } else if (machine_is_yopy()) { -#ifdef CONFIG_SA1100_YOPY - pcmcia_low_level = &yopy_pcmcia_ops; -#endif - } else if (machine_is_pangolin()) { -#ifdef CONFIG_SA1100_PANGOLIN - pcmcia_low_level = &pangolin_pcmcia_ops; -#endif - } else if (machine_is_jornada720()) { -#ifdef CONFIG_SA1100_JORNADA720 - pcmcia_low_level = &jornada720_pcmcia_ops; -#endif - } else if(machine_is_pfs168()){ -#ifdef CONFIG_SA1100_PFS168 - pcmcia_low_level=&pfs168_pcmcia_ops; -#endif - } else if(machine_is_flexanet()){ -#ifdef CONFIG_SA1100_FLEXANET - pcmcia_low_level=&flexanet_pcmcia_ops; -#endif - } else if(machine_is_simpad()){ -#ifdef CONFIG_SA1100_SIMPAD - pcmcia_low_level=&simpad_pcmcia_ops; -#endif - } else if(machine_is_graphicsmaster()) { -#ifdef CONFIG_SA1100_GRAPHICSMASTER - pcmcia_low_level=&graphicsmaster_pcmcia_ops; -#endif - } else if(machine_is_adsbitsy()) { -#ifdef CONFIG_SA1100_ADSBITSY - pcmcia_low_level=&adsbitsy_pcmcia_ops; -#endif - } else if(machine_is_stork()) { -#ifdef CONFIG_SA1100_STORK - pcmcia_low_level=&stork_pcmcia_ops; -#endif - } - - if (!pcmcia_low_level) { - printk(KERN_ERR "This hardware is not supported by the SA1100 Card Service driver\n"); - return -ENODEV; - } - - pcmcia_init.handler=sa1100_pcmcia_interrupt; - - if((sa1100_pcmcia_socket_count=pcmcia_low_level->init(&pcmcia_init))<0){ - printk(KERN_ERR "Unable to initialize kernel PCMCIA service.\n"); - return -EIO; - } - - state_array.size=sa1100_pcmcia_socket_count; - state_array.state=state; - - if(pcmcia_low_level->socket_state(&state_array)<0){ - printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n"); - return -EIO; - } - - /* We initialize the MECR to default values here, because we are - * not guaranteed to see a SetIOMap operation at runtime. - */ - mecr=0; - - clock = get_cclk_frequency() * 100; - - for(i=0; i<sa1100_pcmcia_socket_count; ++i){ - sa1100_pcmcia_socket[i].k_state=state[i]; - - /* This is an interim fix. Apparently, SetSocket is no longer - * called to initialize each socket (prior to the first detect - * event). For now, we'll just manually set up the mask. - */ - sa1100_pcmcia_socket[i].cs_state.csc_mask=SS_DETECT; - - sa1100_pcmcia_socket[i].virt_io=(i==0)?PCMCIA_IO_0_BASE:PCMCIA_IO_1_BASE; - sa1100_pcmcia_socket[i].phys_attr=_PCMCIAAttr(i); - sa1100_pcmcia_socket[i].phys_mem=_PCMCIAMem(i); - - MECR_FAST_SET(mecr, i, 0); - MECR_BSIO_SET(mecr, i, - sa1100_pcmcia_mecr_bs(SA1100_PCMCIA_IO_ACCESS, clock)); - MECR_BSA_SET(mecr, i, - sa1100_pcmcia_mecr_bs(SA1100_PCMCIA_5V_MEM_ACCESS, clock)); - MECR_BSM_SET(mecr, i, - sa1100_pcmcia_mecr_bs(SA1100_PCMCIA_5V_MEM_ACCESS, clock)); - - sa1100_pcmcia_socket[i].speed_io=SA1100_PCMCIA_IO_ACCESS; - sa1100_pcmcia_socket[i].speed_attr=SA1100_PCMCIA_5V_MEM_ACCESS; - sa1100_pcmcia_socket[i].speed_mem=SA1100_PCMCIA_5V_MEM_ACCESS; - } - - MECR=mecr; - -#ifdef CONFIG_CPU_FREQ - if(cpufreq_register_notifier(&sa1100_pcmcia_notifier_block) < 0){ - printk(KERN_ERR "Unable to register CPU frequency change notifier\n"); - return -ENXIO; - } -#endif - - /* Only advertise as many sockets as we can detect: */ - if(register_ss_entry(sa1100_pcmcia_socket_count, - &sa1100_pcmcia_operations)<0){ - printk(KERN_ERR "Unable to register socket service routine\n"); - return -ENXIO; - } - - /* Start the event poll timer. It will reschedule by itself afterwards. */ - sa1100_pcmcia_poll_event(0); - - DEBUG(1, "sa1100: initialization complete\n"); - - return 0; - -} /* sa1100_pcmcia_driver_init() */ - -module_init(sa1100_pcmcia_driver_init); - - -/* sa1100_pcmcia_driver_shutdown() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Invokes the low-level kernel service to free IRQs associated with this - * socket controller and reset GPIO edge detection. + * Returns: 0 */ -static void __exit sa1100_pcmcia_driver_shutdown(void){ +static int sa1100_pcmcia_sock_init(unsigned int sock) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + struct pcmcia_configure conf; - del_timer_sync(&poll_timer); - unregister_ss_entry(&sa1100_pcmcia_operations); -#ifdef CONFIG_CPU_FREQ - cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block); -#endif - pcmcia_low_level->shutdown(); - flush_scheduled_tasks(); + DEBUG(2, "%s(): initializing socket %u\n", __FUNCTION__, sock); - DEBUG(1, "sa1100: shutdown complete\n"); -} + skt->cs_state = dead_socket; -module_exit(sa1100_pcmcia_driver_shutdown); + conf = sa1100_pcmcia_state_to_config(sock, &dead_socket); + pcmcia_low_level->configure_socket(&conf); -/* sa1100_pcmcia_init() - * ^^^^^^^^^^^^^^^^^^^^ - * We perform all of the interesting initialization tasks in - * sa1100_pcmcia_driver_init(). - * - * Returns: 0 - */ -static int sa1100_pcmcia_init(unsigned int sock){ - - DEBUG(2, "%s(): initializing socket %u\n", __FUNCTION__, sock); - - return 0; + return pcmcia_low_level->socket_init(sock); } -/* sa1100_pcmcia_suspend() +/* + * sa1100_pcmcia_suspend() * ^^^^^^^^^^^^^^^^^^^^^^^ - * We don't currently perform any actions on a suspend. + * + * Remove power on the socket, disable IRQs from the card. + * Turn off status interrupts, and disable the PCMCIA bus. * * Returns: 0 */ static int sa1100_pcmcia_suspend(unsigned int sock) { + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); struct pcmcia_configure conf; int ret; DEBUG(2, "%s(): suspending socket %u\n", __FUNCTION__, sock); - conf.sock = sock; - conf.vcc = 0; - conf.vpp = 0; - conf.output = 0; - conf.speaker = 0; - conf.reset = 1; + conf = sa1100_pcmcia_state_to_config(sock, &dead_socket); ret = pcmcia_low_level->configure_socket(&conf); - if (ret == 0) - sa1100_pcmcia_socket[sock].cs_state = dead_socket; + if (ret == 0) { + skt->cs_state = dead_socket; + ret = pcmcia_low_level->socket_suspend(sock); + } return ret; } @@ -407,52 +168,50 @@ static int sa1100_pcmcia_suspend(unsigned int sock) * * Returns: an event mask for the given socket state. */ -static inline unsigned sa1100_pcmcia_events(struct pcmcia_state *state, - struct pcmcia_state *prev_state, - unsigned int mask, - unsigned int flags){ - unsigned int events=0; - - if(state->detect!=prev_state->detect){ +static inline unsigned int +sa1100_pcmcia_events(struct pcmcia_state *state, + struct pcmcia_state *prev_state, + unsigned int mask, unsigned int flags) +{ + unsigned int events = 0; - DEBUG(2, "%s(): card detect value %u\n", __FUNCTION__, state->detect); + if (state->detect != prev_state->detect) { + DEBUG(3, "%s(): card detect value %u\n", __FUNCTION__, state->detect); - events|=mask&SS_DETECT; + events |= SS_DETECT; } - if(state->ready!=prev_state->ready){ - - DEBUG(2, "%s(): card ready value %u\n", __FUNCTION__, state->ready); + if (state->ready != prev_state->ready) { + DEBUG(3, "%s(): card ready value %u\n", __FUNCTION__, state->ready); - events|=mask&((flags&SS_IOCARD)?0:SS_READY); + events |= flags & SS_IOCARD ? 0 : SS_READY; } - if(state->bvd1!=prev_state->bvd1){ - - DEBUG(2, "%s(): card BVD1 value %u\n", __FUNCTION__, state->bvd1); + if (state->bvd1 != prev_state->bvd1) { + DEBUG(3, "%s(): card BVD1 value %u\n", __FUNCTION__, state->bvd1); - events|=mask&(flags&SS_IOCARD)?SS_STSCHG:SS_BATDEAD; + events |= flags & SS_IOCARD ? SS_STSCHG : SS_BATDEAD; } - if(state->bvd2!=prev_state->bvd2){ + if (state->bvd2 != prev_state->bvd2) { + DEBUG(3, "%s(): card BVD2 value %u\n", __FUNCTION__, state->bvd2); - DEBUG(2, "%s(): card BVD2 value %u\n", __FUNCTION__, state->bvd2); - - events|=mask&(flags&SS_IOCARD)?0:SS_BATWARN; + events |= flags & SS_IOCARD ? 0 : SS_BATWARN; } - DEBUG(2, "events: %s%s%s%s%s%s\n", - (events==0)?"<NONE>":"", - (events&SS_DETECT)?"DETECT ":"", - (events&SS_READY)?"READY ":"", - (events&SS_BATDEAD)?"BATDEAD ":"", - (events&SS_BATWARN)?"BATWARN ":"", - (events&SS_STSCHG)?"STSCHG ":""); + *prev_state = *state; - *prev_state=*state; + events &= mask; - return events; + DEBUG(2, "events: %s%s%s%s%s%s\n", + events == 0 ? "<NONE>" : "", + events & SS_DETECT ? "DETECT " : "", + events & SS_READY ? "READY " : "", + events & SS_BATDEAD ? "BATDEAD " : "", + events & SS_BATWARN ? "BATWARN " : "", + events & SS_STSCHG ? "STSCHG " : ""); + return events; } /* sa1100_pcmcia_events() */ @@ -464,38 +223,43 @@ static inline unsigned sa1100_pcmcia_events(struct pcmcia_state *state, * callback) occurs in this thread rather than in the actual interrupt * handler due to the use of scheduling operations in the PCMCIA core. */ -static void sa1100_pcmcia_task_handler(void *data) { +static void sa1100_pcmcia_task_handler(void *data) +{ struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK]; struct pcmcia_state_array state_array; - int i, events, all_events, irq_status; + unsigned int all_events; - DEBUG(2, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__); + DEBUG(4, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__); - state_array.size=sa1100_pcmcia_socket_count; - state_array.state=state; + state_array.size = sa1100_pcmcia_socket_count; + state_array.state = state; do { + unsigned int events; + int ret, i; - DEBUG(3, "%s(): interrogating low-level PCMCIA service\n", __FUNCTION__); + memset(state, 0, sizeof(state)); - if((irq_status=pcmcia_low_level->socket_state(&state_array))<0) - printk(KERN_ERR "Error in kernel low-level PCMCIA service.\n"); + DEBUG(4, "%s(): interrogating low-level PCMCIA service\n", __FUNCTION__); - all_events=0; + ret = pcmcia_low_level->socket_state(&state_array); + if (ret < 0) { + printk(KERN_ERR "sa1100_pcmcia: unable to read socket status\n"); + break; + } - if(irq_status>0){ + all_events = 0; - for(i=0; i<state_array.size; ++i, all_events|=events) - if((events= - sa1100_pcmcia_events(&state[i], - &sa1100_pcmcia_socket[i].k_state, - sa1100_pcmcia_socket[i].cs_state.csc_mask, - sa1100_pcmcia_socket[i].cs_state.flags))) - if(sa1100_pcmcia_socket[i].handler!=NULL) - sa1100_pcmcia_socket[i].handler(sa1100_pcmcia_socket[i].handler_info, - events); - } + for (i = 0; i < state_array.size; i++, all_events |= events) { + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i); + + events = sa1100_pcmcia_events(&state[i], &skt->k_state, + skt->cs_state.csc_mask, + skt->cs_state.flags); + if (events && sa1100_pcmcia_socket[i].handler != NULL) + skt->handler(skt->handler_info, events); + } } while(all_events); } /* sa1100_pcmcia_task_handler() */ @@ -510,7 +274,7 @@ static struct tq_struct sa1100_pcmcia_task = { */ static void sa1100_pcmcia_poll_event(unsigned long dummy) { - DEBUG(3, "%s(): polling for events\n", __FUNCTION__); + DEBUG(4, "%s(): polling for events\n", __FUNCTION__); poll_timer.function = sa1100_pcmcia_poll_event; poll_timer.expires = jiffies + SA1100_PCMCIA_POLL_PERIOD; add_timer(&poll_timer); @@ -527,7 +291,8 @@ static void sa1100_pcmcia_poll_event(unsigned long dummy) * handling code performs scheduling operations which cannot be * executed from within an interrupt context. */ -static void sa1100_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs){ +static void sa1100_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs) +{ DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq); schedule_task(&sa1100_pcmcia_task); } @@ -546,17 +311,20 @@ static void sa1100_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs){ * * Returns: 0 */ -static int sa1100_pcmcia_register_callback(unsigned int sock, - void (*handler)(void *, - unsigned int), - void *info){ - if(handler==NULL){ - sa1100_pcmcia_socket[sock].handler=NULL; +static int +sa1100_pcmcia_register_callback(unsigned int sock, + void (*handler)(void *, unsigned int), + void *info) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + + if (handler == NULL) { + skt->handler = NULL; MOD_DEC_USE_COUNT; } else { MOD_INC_USE_COUNT; - sa1100_pcmcia_socket[sock].handler=handler; - sa1100_pcmcia_socket[sock].handler_info=info; + skt->handler_info = info; + skt->handler = handler; } return 0; @@ -580,51 +348,41 @@ static int sa1100_pcmcia_register_callback(unsigned int sock, * an offset which is applied to client-requested base I/O addresses * in alloc_io_space(). * - * Returns: 0 on success, -1 if no pin has been configured for `sock' + * SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the + * force_low argument to validate_mem() in rsrc_mgr.c -- since in + * general, the mapped * addresses of the PCMCIA memory regions + * will not be within 0xffff, setting force_low would be + * undesirable. + * + * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory + * resource database; we instead pass up physical address ranges + * and allow other parts of Card Services to deal with remapping. + * + * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but + * not 32-bit CardBus devices. + * + * Return value is irrelevant; the pcmcia subsystem ignores it. */ -static int sa1100_pcmcia_inquire_socket(unsigned int sock, - socket_cap_t *cap){ - struct pcmcia_irq_info irq_info; - - DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock); - - if(sock>=sa1100_pcmcia_socket_count){ - printk(KERN_ERR "sa1100: socket %u not configured\n", sock); - return -1; - } +static int +sa1100_pcmcia_inquire_socket(unsigned int sock, socket_cap_t *cap) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + int ret = -1; - /* SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the - * force_low argument to validate_mem() in rsrc_mgr.c -- since in - * general, the mapped * addresses of the PCMCIA memory regions - * will not be within 0xffff, setting force_low would be - * undesirable. - * - * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory - * resource database; we instead pass up physical address ranges - * and allow other parts of Card Services to deal with remapping. - * - * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but - * not 32-bit CardBus devices. - */ - cap->features=(SS_CAP_PAGE_REGS | SS_CAP_STATIC_MAP | SS_CAP_PCCARD); + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); - irq_info.sock=sock; - irq_info.irq=-1; + if (sock < sa1100_pcmcia_socket_count) { + cap->features = SS_CAP_PAGE_REGS | SS_CAP_STATIC_MAP | SS_CAP_PCCARD; + cap->irq_mask = 0; + cap->map_size = PAGE_SIZE; + cap->pci_irq = skt->irq; + cap->io_offset = (unsigned long)skt->virt_io; - if(pcmcia_low_level->get_irq_info(&irq_info)<0){ - printk(KERN_ERR "Error obtaining IRQ info from kernel for socket %u\n", - sock); - return -1; + ret = 0; } - cap->irq_mask=0; - cap->map_size=PAGE_SIZE; - cap->pci_irq=irq_info.irq; - cap->io_offset=sa1100_pcmcia_socket[sock].virt_io; - - return 0; - -} /* sa1100_pcmcia_inquire_socket() */ + return ret; +} /* sa1100_pcmcia_get_status() @@ -643,58 +401,61 @@ static int sa1100_pcmcia_inquire_socket(unsigned int sock, * * Returns: 0 */ -static int sa1100_pcmcia_get_status(unsigned int sock, - unsigned int *status){ +static int +sa1100_pcmcia_get_status(unsigned int sock, unsigned int *status) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK]; struct pcmcia_state_array state_array; + unsigned int stat; + + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); - DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock); + state_array.size = sa1100_pcmcia_socket_count; + state_array.state = state; - state_array.size=sa1100_pcmcia_socket_count; - state_array.state=state; + memset(state, 0, sizeof(state)); - if((pcmcia_low_level->socket_state(&state_array))<0){ - printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n"); + if ((pcmcia_low_level->socket_state(&state_array)) < 0) { + printk(KERN_ERR "sa1100_pcmcia: unable to get socket status\n"); return -1; } - sa1100_pcmcia_socket[sock].k_state=state[sock]; + skt->k_state = state[sock]; - *status=state[sock].detect?SS_DETECT:0; - - *status|=state[sock].ready?SS_READY:0; + stat = state[sock].detect ? SS_DETECT : 0; + stat |= state[sock].ready ? SS_READY : 0; + stat |= state[sock].vs_3v ? SS_3VCARD : 0; + stat |= state[sock].vs_Xv ? SS_XVCARD : 0; /* The power status of individual sockets is not available * explicitly from the hardware, so we just remember the state * and regurgitate it upon request: */ - *status|=sa1100_pcmcia_socket[sock].cs_state.Vcc?SS_POWERON:0; + stat |= skt->cs_state.Vcc ? SS_POWERON : 0; - if(sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD) - *status|=state[sock].bvd1?SS_STSCHG:0; + if (skt->cs_state.flags & SS_IOCARD) + stat |= state[sock].bvd1 ? SS_STSCHG : 0; else { - if(state[sock].bvd1==0) - *status|=SS_BATDEAD; - else if(state[sock].bvd2==0) - *status|=SS_BATWARN; + if (state[sock].bvd1 == 0) + stat |= SS_BATDEAD; + else if (state[sock].bvd2 == 0) + stat |= SS_BATWARN; } - *status|=state[sock].vs_3v?SS_3VCARD:0; - - *status|=state[sock].vs_Xv?SS_XVCARD:0; - DEBUG(3, "\tstatus: %s%s%s%s%s%s%s%s\n", - (*status&SS_DETECT)?"DETECT ":"", - (*status&SS_READY)?"READY ":"", - (*status&SS_BATDEAD)?"BATDEAD ":"", - (*status&SS_BATWARN)?"BATWARN ":"", - (*status&SS_POWERON)?"POWERON ":"", - (*status&SS_STSCHG)?"STSCHG ":"", - (*status&SS_3VCARD)?"3VCARD ":"", - (*status&SS_XVCARD)?"XVCARD ":""); + stat & SS_DETECT ? "DETECT " : "", + stat & SS_READY ? "READY " : "", + stat & SS_BATDEAD ? "BATDEAD " : "", + stat & SS_BATWARN ? "BATWARN " : "", + stat & SS_POWERON ? "POWERON " : "", + stat & SS_STSCHG ? "STSCHG " : "", + stat & SS_3VCARD ? "3VCARD " : "", + stat & SS_XVCARD ? "XVCARD " : ""); - return 0; + *status = stat; + return 0; } /* sa1100_pcmcia_get_status() */ @@ -706,20 +467,18 @@ static int sa1100_pcmcia_get_status(unsigned int sock, * * Returns: 0 */ -static int sa1100_pcmcia_get_socket(unsigned int sock, - socket_state_t *state){ +static int +sa1100_pcmcia_get_socket(unsigned int sock, socket_state_t *state) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); - DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock); + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); - /* This information was given to us in an earlier call to set_socket(), - * so we're just regurgitating it here: - */ - *state=sa1100_pcmcia_socket[sock].cs_state; + *state = skt->cs_state; return 0; } - /* sa1100_pcmcia_set_socket() * ^^^^^^^^^^^^^^^^^^^^^^^^^^ * Implements the set_socket() operation for the in-kernel PCMCIA @@ -730,14 +489,15 @@ static int sa1100_pcmcia_get_socket(unsigned int sock, * * Returns: 0 */ -static int sa1100_pcmcia_set_socket(unsigned int sock, - socket_state_t *state){ - struct pcmcia_configure configure; +static int +sa1100_pcmcia_set_socket(unsigned int sock, socket_state_t *state) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + struct pcmcia_configure conf; - DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock); + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); - DEBUG(3, "\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n" - "\tVcc %d Vpp %d irq %d\n", + DEBUG(3, "\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n", (state->csc_mask==0)?"<NONE>":"", (state->csc_mask&SS_DETECT)?"DETECT ":"", (state->csc_mask&SS_READY)?"READY ":"", @@ -749,25 +509,20 @@ static int sa1100_pcmcia_set_socket(unsigned int sock, (state->flags&SS_IOCARD)?"IOCARD ":"", (state->flags&SS_RESET)?"RESET ":"", (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"", - (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"", + (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":""); + DEBUG(3, "\tVcc %d Vpp %d irq %d\n", state->Vcc, state->Vpp, state->io_irq); - configure.sock=sock; - configure.vcc=state->Vcc; - configure.vpp=state->Vpp; - configure.output=(state->flags&SS_OUTPUT_ENA)?1:0; - configure.speaker=(state->flags&SS_SPKR_ENA)?1:0; - configure.reset=(state->flags&SS_RESET)?1:0; + conf = sa1100_pcmcia_state_to_config(sock, state); - if(pcmcia_low_level->configure_socket(&configure)<0){ - printk(KERN_ERR "Unable to configure socket %u\n", sock); + if (pcmcia_low_level->configure_socket(&conf) < 0) { + printk(KERN_ERR "sa1100_pcmcia: unable to configure socket %d\n", sock); return -1; } - sa1100_pcmcia_socket[sock].cs_state=*state; + skt->cs_state = *state; return 0; - } /* sa1100_pcmcia_set_socket() */ @@ -779,20 +534,20 @@ static int sa1100_pcmcia_set_socket(unsigned int sock, * * Returns: 0 on success, -1 if the map index was out of range */ -static int sa1100_pcmcia_get_io_map(unsigned int sock, - struct pccard_io_map *map){ +static int +sa1100_pcmcia_get_io_map(unsigned int sock, struct pccard_io_map *map) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + int ret = -1; - DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); - if(map->map>=MAX_IO_WIN){ - printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, - map->map); - return -1; + if (map->map < MAX_IO_WIN) { + *map = skt->io_map[map->map]; + ret = 0; } - *map=sa1100_pcmcia_socket[sock].io_map[map->map]; - - return 0; + return ret; } @@ -805,16 +560,16 @@ static int sa1100_pcmcia_get_io_map(unsigned int sock, * * Returns: 0 on success, -1 on error */ -static int sa1100_pcmcia_set_io_map(unsigned int sock, - struct pccard_io_map *map){ - unsigned int clock, speed; - unsigned long mecr, start; +static int +sa1100_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); - DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); - DEBUG(4, "\tmap %u speed %u\n\tstart 0x%08lx stop 0x%08lx\n" - "\tflags: %s%s%s%s%s%s%s%s\n", - map->map, map->speed, map->start, map->stop, + DEBUG(3, "\tmap %u speed %u\n\tstart 0x%08x stop 0x%08x\n", + map->map, map->speed, map->start, map->stop); + DEBUG(3, "\tflags: %s%s%s%s%s%s%s%s\n", (map->flags==0)?"<NONE>":"", (map->flags&MAP_ACTIVE)?"ACTIVE ":"", (map->flags&MAP_16BIT)?"16BIT ":"", @@ -824,45 +579,45 @@ static int sa1100_pcmcia_set_io_map(unsigned int sock, (map->flags&MAP_USE_WAIT)?"USE_WAIT ":"", (map->flags&MAP_PREFETCH)?"PREFETCH ":""); - if(map->map>=MAX_IO_WIN){ + if (map->map >= MAX_IO_WIN) { printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, map->map); return -1; } - if(map->flags&MAP_ACTIVE){ + if (map->flags & MAP_ACTIVE) { + unsigned int clock, speed = map->speed; + unsigned long mecr; - speed=(map->speed>0)?map->speed:SA1100_PCMCIA_IO_ACCESS; + if (speed == 0) + speed = SA1100_PCMCIA_IO_ACCESS; - clock = get_cclk_frequency() * 100; + clock = cpufreq_get(0); - mecr=MECR; + mecr = MECR; MECR_BSIO_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock)); - sa1100_pcmcia_socket[sock].speed_io=speed; + skt->speed_io = speed; DEBUG(4, "%s(): FAST%u %lx BSM%u %lx BSA%u %lx BSIO%u %lx\n", __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock, MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), sock, MECR_BSIO_GET(mecr, sock)); - MECR=mecr; - + MECR = mecr; } - start=map->start; - - if(map->stop==1) - map->stop=PAGE_SIZE-1; + if (map->stop == 1) + map->stop = PAGE_SIZE-1; - map->start=sa1100_pcmcia_socket[sock].virt_io; - map->stop=map->start+(map->stop-start); + map->stop -= map->start; + map->stop += (unsigned long)skt->virt_io; + map->start = (unsigned long)skt->virt_io; - sa1100_pcmcia_socket[sock].io_map[map->map]=*map; + skt->io_map[map->map] = *map; return 0; - } /* sa1100_pcmcia_set_io_map() */ @@ -875,20 +630,20 @@ static int sa1100_pcmcia_set_io_map(unsigned int sock, * * Returns: 0 on success, -1 if the map index was out of range */ -static int sa1100_pcmcia_get_mem_map(unsigned int sock, - struct pccard_mem_map *map){ +static int +sa1100_pcmcia_get_mem_map(unsigned int sock, struct pccard_mem_map *map) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + int ret = -1; - DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); - if(map->map>=MAX_WIN){ - printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, - map->map); - return -1; + if (map->map < MAX_WIN) { + *map = skt->mem_map[map->map]; + ret = 0; } - *map=sa1100_pcmcia_socket[sock].mem_map[map->map]; - - return 0; + return ret; } @@ -901,18 +656,18 @@ static int sa1100_pcmcia_get_mem_map(unsigned int sock, * * Returns: 0 on success, -1 on error */ -static int sa1100_pcmcia_set_mem_map(unsigned int sock, - struct pccard_mem_map *map){ - unsigned int clock, speed; - unsigned long mecr, start; +static int +sa1100_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + unsigned long start; - DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); - DEBUG(4, "\tmap %u speed %u\n\tsys_start %#lx\n" - "\tsys_stop %#lx\n\tcard_start %#x\n" - "\tflags: %s%s%s%s%s%s%s%s\n", - map->map, map->speed, map->sys_start, map->sys_stop, - map->card_start, (map->flags==0)?"<NONE>":"", + DEBUG(3, "\tmap %u speed %u sys_start %08lx sys_stop %08lx card_start %08x\n", + map->map, map->speed, map->sys_start, map->sys_stop, map->card_start); + DEBUG(3, "\tflags: %s%s%s%s%s%s%s%s\n", + (map->flags==0)?"<NONE>":"", (map->flags&MAP_ACTIVE)?"ACTIVE ":"", (map->flags&MAP_16BIT)?"16BIT ":"", (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", @@ -921,177 +676,175 @@ static int sa1100_pcmcia_set_mem_map(unsigned int sock, (map->flags&MAP_ATTRIB)?"ATTRIB ":"", (map->flags&MAP_USE_WAIT)?"USE_WAIT ":""); - if(map->map>=MAX_WIN){ + if (map->map >= MAX_WIN){ printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, map->map); return -1; } - if(map->flags&MAP_ACTIVE){ + if (map->flags & MAP_ACTIVE) { + unsigned int clock, speed = map->speed; + unsigned long mecr; - /* When clients issue RequestMap, the access speed is not always - * properly configured: + /* + * When clients issue RequestMap, the access speed is not always + * properly configured. Choose some sensible defaults. */ - if(map->speed > 0) - speed = map->speed; - else - switch(sa1100_pcmcia_socket[sock].cs_state.Vcc){ - case 33: + if (speed == 0) { + if (skt->cs_state.Vcc == 33) speed = SA1100_PCMCIA_3V_MEM_ACCESS; - break; - default: + else speed = SA1100_PCMCIA_5V_MEM_ACCESS; - } + } - clock = get_cclk_frequency() * 100; - - mecr=MECR; - - if(map->flags&MAP_ATTRIB){ + clock = cpufreq_get(0); - MECR_BSA_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock)); - sa1100_pcmcia_socket[sock].speed_attr=speed; + /* Fixme: MECR is not pre-empt safe. */ + mecr = MECR; + if (map->flags & MAP_ATTRIB) { + MECR_BSA_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock)); + skt->speed_attr = speed; } else { - MECR_BSM_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock)); - sa1100_pcmcia_socket[sock].speed_mem=speed; - + skt->speed_mem = speed; } - + DEBUG(4, "%s(): FAST%u %lx BSM%u %lx BSA%u %lx BSIO%u %lx\n", __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock, MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), sock, MECR_BSIO_GET(mecr, sock)); - - MECR=mecr; + MECR = mecr; } - start=map->sys_start; - - if(map->sys_stop==0) - map->sys_stop=PAGE_SIZE-1; + start = (map->flags & MAP_ATTRIB) ? skt->phys_attr : skt->phys_mem; - map->sys_start=(map->flags & MAP_ATTRIB)?\ - sa1100_pcmcia_socket[sock].phys_attr:\ - sa1100_pcmcia_socket[sock].phys_mem; + if (map->sys_stop == 0) + map->sys_stop = PAGE_SIZE-1; - map->sys_stop=map->sys_start+(map->sys_stop-start); + map->sys_stop -= map->sys_start; + map->sys_stop += start; + map->sys_start = start; - sa1100_pcmcia_socket[sock].mem_map[map->map]=*map; + skt->mem_map[map->map] = *map; return 0; - } /* sa1100_pcmcia_set_mem_map() */ #if defined(CONFIG_PROC_FS) -/* sa1100_pcmcia_proc_setup() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the proc_setup() operation for the in-kernel PCMCIA - * service (formerly SS_ProcSetup in Card Services). - * - * Returns: 0 on success, -1 on error - */ -static void sa1100_pcmcia_proc_setup(unsigned int sock, - struct proc_dir_entry *base){ - struct proc_dir_entry *entry; - - DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); - - if((entry=create_proc_entry("status", 0, base))==NULL){ - printk(KERN_ERR "Unable to install \"status\" procfs entry\n"); - return; - } - - entry->read_proc=sa1100_pcmcia_proc_status; - entry->data=(void *)sock; -} - - /* sa1100_pcmcia_proc_status() * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ * Implements the /proc/bus/pccard/??/status file. * * Returns: the number of characters added to the buffer */ -static int sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos, - int count, int *eof, void *data){ - char *p=buf; - unsigned int sock=(unsigned int)data; - unsigned int clock = get_cclk_frequency() * 100; +static int +sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + unsigned int sock = (unsigned int)data; + unsigned int clock = cpufreq_get(0); + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); unsigned long mecr = MECR; + char *p = buf; - p+=sprintf(p, "k_flags : %s%s%s%s%s%s%s\n", - sa1100_pcmcia_socket[sock].k_state.detect?"detect ":"", - sa1100_pcmcia_socket[sock].k_state.ready?"ready ":"", - sa1100_pcmcia_socket[sock].k_state.bvd1?"bvd1 ":"", - sa1100_pcmcia_socket[sock].k_state.bvd2?"bvd2 ":"", - sa1100_pcmcia_socket[sock].k_state.wrprot?"wrprot ":"", - sa1100_pcmcia_socket[sock].k_state.vs_3v?"vs_3v ":"", - sa1100_pcmcia_socket[sock].k_state.vs_Xv?"vs_Xv ":""); + p+=sprintf(p, "k_state : %s%s%s%s%s%s%s\n", + skt->k_state.detect ? "detect " : "", + skt->k_state.ready ? "ready " : "", + skt->k_state.bvd1 ? "bvd1 " : "", + skt->k_state.bvd2 ? "bvd2 " : "", + skt->k_state.wrprot ? "wrprot " : "", + skt->k_state.vs_3v ? "vs_3v " : "", + skt->k_state.vs_Xv ? "vs_Xv " : ""); p+=sprintf(p, "status : %s%s%s%s%s%s%s%s%s\n", - sa1100_pcmcia_socket[sock].k_state.detect?"SS_DETECT ":"", - sa1100_pcmcia_socket[sock].k_state.ready?"SS_READY ":"", - sa1100_pcmcia_socket[sock].cs_state.Vcc?"SS_POWERON ":"", - sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\ - "SS_IOCARD ":"", - (sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD && - sa1100_pcmcia_socket[sock].k_state.bvd1)?"SS_STSCHG ":"", - ((sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 && - (sa1100_pcmcia_socket[sock].k_state.bvd1==0))?"SS_BATDEAD ":"", - ((sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 && - (sa1100_pcmcia_socket[sock].k_state.bvd2==0))?"SS_BATWARN ":"", - sa1100_pcmcia_socket[sock].k_state.vs_3v?"SS_3VCARD ":"", - sa1100_pcmcia_socket[sock].k_state.vs_Xv?"SS_XVCARD ":""); + skt->k_state.detect ? "SS_DETECT " : "", + skt->k_state.ready ? "SS_READY " : "", + skt->cs_state.Vcc ? "SS_POWERON " : "", + skt->cs_state.flags & SS_IOCARD ? "SS_IOCARD " : "", + (skt->cs_state.flags & SS_IOCARD && + skt->k_state.bvd1) ? "SS_STSCHG " : "", + ((skt->cs_state.flags & SS_IOCARD)==0 && + (skt->k_state.bvd1==0)) ? "SS_BATDEAD " : "", + ((skt->cs_state.flags & SS_IOCARD)==0 && + (skt->k_state.bvd2==0)) ? "SS_BATWARN " : "", + skt->k_state.vs_3v ? "SS_3VCARD " : "", + skt->k_state.vs_Xv ? "SS_XVCARD " : ""); p+=sprintf(p, "mask : %s%s%s%s%s\n", - sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_DETECT?\ - "SS_DETECT ":"", - sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_READY?\ - "SS_READY ":"", - sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_BATDEAD?\ - "SS_BATDEAD ":"", - sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_BATWARN?\ - "SS_BATWARN ":"", - sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_STSCHG?\ - "SS_STSCHG ":""); + skt->cs_state.csc_mask & SS_DETECT ? "SS_DETECT " : "", + skt->cs_state.csc_mask & SS_READY ? "SS_READY " : "", + skt->cs_state.csc_mask & SS_BATDEAD ? "SS_BATDEAD " : "", + skt->cs_state.csc_mask & SS_BATWARN ? "SS_BATWARN " : "", + skt->cs_state.csc_mask & SS_STSCHG ? "SS_STSCHG " : ""); p+=sprintf(p, "cs_flags : %s%s%s%s%s\n", - sa1100_pcmcia_socket[sock].cs_state.flags&SS_PWR_AUTO?\ - "SS_PWR_AUTO ":"", - sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\ - "SS_IOCARD ":"", - sa1100_pcmcia_socket[sock].cs_state.flags&SS_RESET?\ - "SS_RESET ":"", - sa1100_pcmcia_socket[sock].cs_state.flags&SS_SPKR_ENA?\ - "SS_SPKR_ENA ":"", - sa1100_pcmcia_socket[sock].cs_state.flags&SS_OUTPUT_ENA?\ - "SS_OUTPUT_ENA ":""); - - p+=sprintf(p, "Vcc : %d\n", sa1100_pcmcia_socket[sock].cs_state.Vcc); - - p+=sprintf(p, "Vpp : %d\n", sa1100_pcmcia_socket[sock].cs_state.Vpp); + skt->cs_state.flags & SS_PWR_AUTO ? "SS_PWR_AUTO " : "", + skt->cs_state.flags & SS_IOCARD ? "SS_IOCARD " : "", + skt->cs_state.flags & SS_RESET ? "SS_RESET " : "", + skt->cs_state.flags & SS_SPKR_ENA ? "SS_SPKR_ENA " : "", + skt->cs_state.flags & SS_OUTPUT_ENA ? "SS_OUTPUT_ENA " : ""); - p+=sprintf(p, "irq : %d\n", sa1100_pcmcia_socket[sock].cs_state.io_irq); + p+=sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc); + p+=sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp); + p+=sprintf(p, "IRQ : %d\n", skt->cs_state.io_irq); - p+=sprintf(p, "I/O : %u (%u)\n", sa1100_pcmcia_socket[sock].speed_io, + p+=sprintf(p, "I/O : %u (%u)\n", skt->speed_io, sa1100_pcmcia_cmd_time(clock, MECR_BSIO_GET(mecr, sock))); - p+=sprintf(p, "attribute: %u (%u)\n", sa1100_pcmcia_socket[sock].speed_attr, + p+=sprintf(p, "attribute: %u (%u)\n", skt->speed_attr, sa1100_pcmcia_cmd_time(clock, MECR_BSA_GET(mecr, sock))); - p+=sprintf(p, "common : %u (%u)\n", sa1100_pcmcia_socket[sock].speed_mem, + p+=sprintf(p, "common : %u (%u)\n", skt->speed_mem, sa1100_pcmcia_cmd_time(clock, MECR_BSM_GET(mecr, sock))); return p-buf; } +/* sa1100_pcmcia_proc_setup() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the proc_setup() operation for the in-kernel PCMCIA + * service (formerly SS_ProcSetup in Card Services). + * + * Returns: 0 on success, -1 on error + */ +static void +sa1100_pcmcia_proc_setup(unsigned int sock, struct proc_dir_entry *base) +{ + struct proc_dir_entry *entry; + + DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); + + if ((entry = create_proc_entry("status", 0, base)) == NULL){ + printk(KERN_ERR "unable to install \"status\" procfs entry\n"); + return; + } + + entry->read_proc = sa1100_pcmcia_proc_status; + entry->data = (void *)sock; +} + #endif /* defined(CONFIG_PROC_FS) */ +static struct pccard_operations sa1100_pcmcia_operations = { + init: sa1100_pcmcia_sock_init, + suspend: sa1100_pcmcia_suspend, + register_callback: sa1100_pcmcia_register_callback, + inquire_socket: sa1100_pcmcia_inquire_socket, + get_status: sa1100_pcmcia_get_status, + get_socket: sa1100_pcmcia_get_socket, + set_socket: sa1100_pcmcia_set_socket, + get_io_map: sa1100_pcmcia_get_io_map, + set_io_map: sa1100_pcmcia_set_io_map, + get_mem_map: sa1100_pcmcia_get_mem_map, + set_mem_map: sa1100_pcmcia_set_mem_map, +#ifdef CONFIG_PROC_FS + proc_setup: sa1100_pcmcia_proc_setup +#endif +}; #ifdef CONFIG_CPU_FREQ @@ -1101,25 +854,23 @@ static int sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos, * to a core clock frequency change) is needed, this routine establishes * new BS_xx values consistent with the clock speed `clock'. */ -static void sa1100_pcmcia_update_mecr(unsigned int clock){ +static void sa1100_pcmcia_update_mecr(unsigned int clock) +{ unsigned int sock; unsigned long mecr = MECR; for(sock = 0; sock < SA1100_PCMCIA_MAX_SOCK; ++sock){ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); MECR_BSIO_SET(mecr, sock, - sa1100_pcmcia_mecr_bs(sa1100_pcmcia_socket[sock].speed_io, - clock)); + sa1100_pcmcia_mecr_bs(skt->speed_io, clock)); MECR_BSA_SET(mecr, sock, - sa1100_pcmcia_mecr_bs(sa1100_pcmcia_socket[sock].speed_attr, - clock)); + sa1100_pcmcia_mecr_bs(skt->speed_attr, clock)); MECR_BSM_SET(mecr, sock, - sa1100_pcmcia_mecr_bs(sa1100_pcmcia_socket[sock].speed_mem, - clock)); + sa1100_pcmcia_mecr_bs(skt->speed_mem, clock)); } MECR = mecr; - } /* sa1100_pcmcia_notifier() @@ -1132,53 +883,371 @@ static void sa1100_pcmcia_update_mecr(unsigned int clock){ * * Returns: 0 on success, -1 on error */ -static int sa1100_pcmcia_notifier(struct notifier_block *nb, - unsigned long val, void *data){ +static int +sa1100_pcmcia_notifier(struct notifier_block *nb, unsigned long val, + void *data) +{ struct cpufreq_info *ci = data; - switch(val){ - case CPUFREQ_MINMAX: - - break; - + switch (val) { case CPUFREQ_PRECHANGE: - - if(ci->new_freq > ci->old_freq){ + if (ci->new_freq > ci->old_freq) { DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, pre-updating\n", __FUNCTION__, ci->new_freq / 1000, (ci->new_freq / 100) % 10, ci->old_freq / 1000, (ci->old_freq / 100) % 10); sa1100_pcmcia_update_mecr(ci->new_freq); } - break; case CPUFREQ_POSTCHANGE: - - if(ci->new_freq < ci->old_freq){ + if (ci->new_freq < ci->old_freq) { DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, post-updating\n", __FUNCTION__, ci->new_freq / 1000, (ci->new_freq / 100) % 10, ci->old_freq / 1000, (ci->old_freq / 100) % 10); sa1100_pcmcia_update_mecr(ci->new_freq); } - break; - - default: - printk(KERN_ERR "%s(): unknown CPU frequency event %lx\n", __FUNCTION__, - val); - return -1; - } return 0; - } static struct notifier_block sa1100_pcmcia_notifier_block = { - notifier_call: sa1100_pcmcia_notifier + notifier_call: sa1100_pcmcia_notifier }; +#endif + +/* sa1100_register_pcmcia() + * ^^^^^^^^^^^^^^^^^^^^^^^^ + * + * Register an SA1100 PCMCIA low level driver with the SA1100 core. + */ +int sa1100_register_pcmcia(struct pcmcia_low_level *ops) +{ + struct pcmcia_init pcmcia_init; + struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK]; + struct pcmcia_state_array state_array; + unsigned int i, clock; + unsigned long mecr; + int ret; + + /* + * Refuse to replace an existing driver. + */ + if (pcmcia_low_level) + return -EBUSY; + + pcmcia_low_level = ops; + + pcmcia_init.handler = sa1100_pcmcia_interrupt; + ret = ops->init(&pcmcia_init); + if (ret < 0) { + printk(KERN_ERR "Unable to initialize kernel PCMCIA service (%d).\n", ret); + if (ret == -1) + ret = -EIO; + goto out; + } + + sa1100_pcmcia_socket_count = ret; + + state_array.size = ret; + state_array.state = state; + + memset(state, 0, sizeof(state)); + + if (ops->socket_state(&state_array) < 0) { + printk(KERN_ERR "Unable to get PCMCIA status driver.\n"); + ret = -EIO; + goto shutdown; + } + + /* + * We initialize the MECR to default values here, because we are + * not guaranteed to see a SetIOMap operation at runtime. + */ + mecr = 0; + + clock = cpufreq_get(0); + + for (i = 0; i < sa1100_pcmcia_socket_count; i++) { + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i); + struct pcmcia_irq_info irq_info; + + if (!request_mem_region(_PCMCIA(i), PCMCIASp, "PCMCIA")) { + ret = -EBUSY; + goto out_err; + } + + irq_info.sock = i; + irq_info.irq = -1; + ret = ops->get_irq_info(&irq_info); + if (ret < 0) + printk(KERN_ERR "Unable to get IRQ for socket %u (%d)\n", i, ret); + + skt->irq = irq_info.irq; + skt->k_state = state[i]; + skt->speed_io = SA1100_PCMCIA_IO_ACCESS; + skt->speed_attr = SA1100_PCMCIA_5V_MEM_ACCESS; + skt->speed_mem = SA1100_PCMCIA_5V_MEM_ACCESS; + skt->phys_attr = _PCMCIAAttr(i); + skt->phys_mem = _PCMCIAMem(i); + skt->virt_io = ioremap(_PCMCIAIO(i), 0x10000); + + if (skt->virt_io == NULL) { + ret = -ENOMEM; + goto out_err; + } + + MECR_FAST_SET(mecr, i, 0); + MECR_BSIO_SET(mecr, i, sa1100_pcmcia_mecr_bs(skt->speed_io, clock)); + MECR_BSA_SET(mecr, i, sa1100_pcmcia_mecr_bs(skt->speed_attr, clock)); + MECR_BSM_SET(mecr, i, sa1100_pcmcia_mecr_bs(skt->speed_mem, clock)); + } + + MECR = mecr; + + /* Only advertise as many sockets as we can detect */ + ret = register_ss_entry(sa1100_pcmcia_socket_count, + &sa1100_pcmcia_operations); + if (ret < 0) { + printk(KERN_ERR "Unable to register sockets\n"); + goto out_err; + } + + /* + * Start the event poll timer. It will reschedule by itself afterwards. + */ + sa1100_pcmcia_poll_event(0); + return 0; + + out_err: + for (i = 0; i < sa1100_pcmcia_socket_count; i++) { + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i); + iounmap(skt->virt_io); + skt->virt_io = NULL; + release_mem_region(_PCMCIA(i), PCMCIASp); + } + + shutdown: + ops->shutdown(); + + out: + pcmcia_low_level = NULL; + return ret; +} + +/* sa1100_unregister_pcmcia() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * + * Unregister a previously registered pcmcia driver + */ +void sa1100_unregister_pcmcia(struct pcmcia_low_level *ops) +{ + int i; + + if (!ops) + return; + + if (ops != pcmcia_low_level) { + printk(KERN_DEBUG "PCMCIA: Trying to unregister wrong " + "low-level driver (%p != %p)", ops, + pcmcia_low_level); + return; + } + + del_timer_sync(&poll_timer); + + unregister_ss_entry(&sa1100_pcmcia_operations); + + for (i = 0; i < sa1100_pcmcia_socket_count; i++) { + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i); + + iounmap(skt->virt_io); + skt->virt_io = NULL; + + release_mem_region(_PCMCIA(i), PCMCIASp); + } + + ops->shutdown(); + + flush_scheduled_tasks(); + + pcmcia_low_level = NULL; +} + +/* sa1100_pcmcia_init() + * ^^^^^^^^^^^^^^^^^^^^ + * + * This routine performs a basic sanity check to ensure that this + * kernel has been built with the appropriate board-specific low-level + * PCMCIA support, performs low-level PCMCIA initialization, registers + * this socket driver with Card Services, and then spawns the daemon + * thread which is the real workhorse of the socket driver. + * + * Returns: 0 on success, -1 on error + */ +static int __init sa1100_pcmcia_init(void) +{ + servinfo_t info; + int ret, i; + + printk(KERN_INFO "SA-1100 PCMCIA (CS release %s)\n", CS_RELEASE); + + CardServices(GetCardServicesInfo, &info); + if (info.Revision != CS_RELEASE_CODE) { + printk(KERN_ERR "Card Services release codes do not match\n"); + return -EINVAL; + } + + for (i = 0; i < SA1100_PCMCIA_MAX_SOCK; i++) { + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i); + skt->speed_io = SA1100_PCMCIA_IO_ACCESS; + skt->speed_attr = SA1100_PCMCIA_5V_MEM_ACCESS; + skt->speed_mem = SA1100_PCMCIA_5V_MEM_ACCESS; + } + +#ifdef CONFIG_CPU_FREQ + ret = cpufreq_register_notifier(&sa1100_pcmcia_notifier_block); + if (ret < 0) { + printk(KERN_ERR "Unable to register CPU frequency change " + "notifier (%d)\n", ret); + return ret; + } +#endif + +#ifdef CONFIG_SA1100_ADSBITSY + pcmcia_adsbitsy_init(); +#endif +#ifdef CONFIG_SA1100_ASSABET + pcmcia_assabet_init(); +#endif +#ifdef CONFIG_SA1100_BADGE4 + pcmcia_badge4_init(); +#endif +#ifdef CONFIG_SA1100_CERF + pcmcia_cerf_init(); +#endif +#ifdef CONFIG_SA1100_FLEXANET + pcmcia_flexanet_init(); +#endif +#ifdef CONFIG_SA1100_FREEBIRD + pcmcia_freebird_init(); +#endif +#ifdef CONFIG_SA1100_GRAPHICSCLIENT + pcmcia_gcplus_init(); +#endif +#ifdef CONFIG_SA1100_GRAPHICSMASTER + pcmcia_graphicsmaster_init(); +#endif +#ifdef CONFIG_SA1100_JORNADA720 + pcmcia_jornada720_init(); +#endif +#ifdef CONFIG_ASSABET_NEPONSET + pcmcia_neponset_init(); +#endif +#ifdef CONFIG_SA1100_PANGOLIN + pcmcia_pangolin_init(); +#endif +#ifdef CONFIG_SA1100_PFS168 + pcmcia_pfs_init(); +#endif +#ifdef CONFIG_SA1100_PT_SYSTEM3 + pcmcia_system3_init(); +#endif +#ifdef CONFIG_SA1100_SHANNON + pcmcia_shannon_init(); +#endif +#ifdef CONFIG_SA1100_SIMPAD + pcmcia_simpad_init(); +#endif +#ifdef CONFIG_SA1100_STORK + pcmcia_stork_init(); +#endif +#ifdef CONFIG_SA1100_XP860 + pcmcia_xp860_init(); +#endif +#ifdef CONFIG_SA1100_YOPY + pcmcia_yopy_init(); #endif + return 0; +} + +/* sa1100_pcmcia_exit() + * ^^^^^^^^^^^^^^^^^^^^ + * Invokes the low-level kernel service to free IRQs associated with this + * socket controller and reset GPIO edge detection. + */ +static void __exit sa1100_pcmcia_exit(void) +{ +#ifdef CONFIG_SA1100_ADSBITSY + pcmcia_adsbitsy_exit(); +#endif +#ifdef CONFIG_SA1100_ASSABET + pcmcia_assabet_exit(); +#endif +#ifdef CONFIG_SA1100_BADGE4 + pcmcia_badge4_exit(); +#endif +#ifdef CONFIG_SA1100_CERF + pcmcia_cerf_exit(); +#endif +#ifdef CONFIG_SA1100_FLEXANET + pcmcia_flexanet_exit(); +#endif +#ifdef CONFIG_SA1100_FREEBIRD + pcmcia_freebird_exit(); +#endif +#ifdef CONFIG_SA1100_GRAPHICSCLIENT + pcmcia_gcplus_exit(); +#endif +#ifdef CONFIG_SA1100_GRAPHICSMASTER + pcmcia_graphicsmaster_exit(); +#endif +#ifdef CONFIG_SA1100_JORNADA720 + pcmcia_jornada720_exit(); +#endif +#ifdef CONFIG_ASSABET_NEPONSET + pcmcia_neponset_exit(); +#endif +#ifdef CONFIG_SA1100_PANGOLIN + pcmcia_pangolin_exit(); +#endif +#ifdef CONFIG_SA1100_PFS168 + pcmcia_pfs_exit(); +#endif +#ifdef CONFIG_SA1100_SHANNON + pcmcia_shannon_exit(); +#endif +#ifdef CONFIG_SA1100_SIMPAD + pcmcia_simpad_exit(); +#endif +#ifdef CONFIG_SA1100_STORK + pcmcia_stork_exit(); +#endif +#ifdef CONFIG_SA1100_XP860 + pcmcia_xp860_exit(); +#endif +#ifdef CONFIG_SA1100_YOPY + pcmcia_yopy_exit(); +#endif + + if (pcmcia_low_level) { + printk(KERN_ERR "PCMCIA: low level driver still registered\n"); + sa1100_unregister_pcmcia(pcmcia_low_level); + } + +#ifdef CONFIG_CPU_FREQ + cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block); +#endif +} + +MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>"); +MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-1100 Socket Controller"); +MODULE_LICENSE("Dual MPL/GPL"); + +module_init(sa1100_pcmcia_init); +module_exit(sa1100_pcmcia_exit); diff --git a/drivers/pcmcia/sa1100_generic.h b/drivers/pcmcia/sa1100_generic.h new file mode 100644 index 000000000000..ae44461a8bb4 --- /dev/null +++ b/drivers/pcmcia/sa1100_generic.h @@ -0,0 +1,77 @@ +/* + * linux/include/asm/arch/pcmcia.h + * + * Copyright (C) 2000 John G Dorsey <john+@cs.cmu.edu> + * + * This file contains definitions for the low-level SA-1100 kernel PCMCIA + * interface. Please see linux/Documentation/arm/SA1100/PCMCIA for details. + */ +#ifndef _ASM_ARCH_PCMCIA +#define _ASM_ARCH_PCMCIA + +/* Ideally, we'd support up to MAX_SOCK sockets, but the SA-1100 only + * has support for two. This shows up in lots of hardwired ways, such + * as the fact that MECR only has enough bits to configure two sockets. + * Since it's so entrenched in the hardware, limiting the software + * in this way doesn't seem too terrible. + */ +#define SA1100_PCMCIA_MAX_SOCK (2) + +struct pcmcia_init { + void (*handler)(int irq, void *dev, struct pt_regs *regs); +}; + +struct pcmcia_state { + unsigned detect: 1, + ready: 1, + bvd1: 1, + bvd2: 1, + wrprot: 1, + vs_3v: 1, + vs_Xv: 1; +}; + +struct pcmcia_state_array { + unsigned int size; + struct pcmcia_state *state; +}; + +struct pcmcia_configure { + unsigned sock: 8, + vcc: 8, + vpp: 8, + output: 1, + speaker: 1, + reset: 1, + irq: 1; +}; + +struct pcmcia_irq_info { + unsigned int sock; + unsigned int irq; +}; + +struct pcmcia_low_level { + int (*init)(struct pcmcia_init *); + int (*shutdown)(void); + int (*socket_state)(struct pcmcia_state_array *); + int (*get_irq_info)(struct pcmcia_irq_info *); + int (*configure_socket)(const struct pcmcia_configure *); + + /* + * Enable card status IRQs on (re-)initialisation. This can + * be called at initialisation, power management event, or + * pcmcia event. + */ + int (*socket_init)(int sock); + + /* + * Disable card status IRQs and PCMCIA bus on suspend. + */ + int (*socket_suspend)(int sock); +}; + +extern int sa1100_register_pcmcia(struct pcmcia_low_level *); +extern void sa1100_unregister_pcmcia(struct pcmcia_low_level *); + +#endif diff --git a/drivers/pcmcia/sa1100_graphicsclient.c b/drivers/pcmcia/sa1100_graphicsclient.c index 0320d5cf4c10..6a3691df82ef 100644 --- a/drivers/pcmcia/sa1100_graphicsclient.c +++ b/drivers/pcmcia/sa1100_graphicsclient.c @@ -14,10 +14,13 @@ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/delay.h> +#include <linux/init.h> #include <asm/hardware.h> #include <asm/irq.h> -#include <asm/arch/pcmcia.h> +#include "sa1100_generic.h" + +#error This is broken! #define S0_CD_IRQ 60 // Socket 0 Card Detect IRQ #define S0_STS_IRQ 55 // Socket 0 PCMCIA IRQ @@ -47,8 +50,9 @@ static int gcplus_pcmcia_init(struct pcmcia_init *init) irq = S0_CD_IRQ; res = request_irq(irq, init->handler, SA_INTERRUPT, "PCMCIA 0 CD", NULL); if (res < 0) { - printk(KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq); - return -1; + printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n", + __FUNCTION__, irq, res); + return res; } return 1; // 1 PCMCIA Slot @@ -106,7 +110,7 @@ static int gcplus_pcmcia_configure_socket(const struct pcmcia_configure if(configure->sock>1) return -1; - save_flags_cli(flags); + local_irq_save(flags); switch (configure->vcc) { case 0: @@ -126,7 +130,7 @@ static int gcplus_pcmcia_configure_socket(const struct pcmcia_configure default: printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, configure->vcc); - restore_flags(flags); + local_irq_restore(flags); return -1; } @@ -139,16 +143,44 @@ static int gcplus_pcmcia_configure_socket(const struct pcmcia_configure *PCMCIA_Power |= ADS_CS_PR_A_RESET; mdelay(30); - restore_flags(flags); + local_irq_restore(flags); return 0; } -struct pcmcia_low_level gcplus_pcmcia_ops = { - gcplus_pcmcia_init, - gcplus_pcmcia_shutdown, - gcplus_pcmcia_socket_state, - gcplus_pcmcia_get_irq_info, - gcplus_pcmcia_configure_socket +static int gcplus_pcmcia_socket_init(int sock) +{ + return 0; +} + +static int gcplus_pcmcia_socket_suspend(int sock) +{ + return 0; +} + +static struct pcmcia_low_level gcplus_pcmcia_ops = { + init: gcplus_pcmcia_init, + shutdown: gcplus_pcmcia_shutdown, + socket_state: gcplus_pcmcia_socket_state, + get_irq_info: gcplus_pcmcia_get_irq_info, + configure_socket: gcplus_pcmcia_configure_socket, + + socket_init: gcplus_pcmcia_socket_init, + socket_suspend: gcplus_pcmcia_socket_suspend, }; +int __init pcmcia_gcplus_init(void) +{ + int ret = -ENODEV; + + if (machine_is_gcplus()) + ret = sa1100_register_pcmcia(&gcplus_pcmcia_ops); + + return ret; +} + +void __exit pcmcia_gcplus_exit(void) +{ + sa1100_unregister_pcmcia(&gcplus_pcmcia_ops); +} + diff --git a/drivers/pcmcia/sa1100_graphicsmaster.c b/drivers/pcmcia/sa1100_graphicsmaster.c index 637be9d44ff1..8aeafa167cff 100644 --- a/drivers/pcmcia/sa1100_graphicsmaster.c +++ b/drivers/pcmcia/sa1100_graphicsmaster.c @@ -10,11 +10,12 @@ */ #include <linux/kernel.h> #include <linux/sched.h> +#include <linux/init.h> -#include <asm/delay.h> #include <asm/hardware.h> -#include <asm/irq.h> -#include <asm/arch/pcmcia.h> + +#include "sa1100_generic.h" +#include "sa1111_generic.h" static int graphicsmaster_pcmcia_init(struct pcmcia_init *init) { @@ -26,190 +27,82 @@ static int graphicsmaster_pcmcia_init(struct pcmcia_init *init) /* Disable Power 3.3V/5V for PCMCIA/CF */ PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3; - INTPOL1 |= (1 << (S0_READY_NINT - SA1111_IRQ(32))) | - (1 << (S1_READY_NINT - SA1111_IRQ(32))) | - (1 << (S0_CD_VALID - SA1111_IRQ(32))) | - (1 << (S1_CD_VALID - SA1111_IRQ(32))) | - (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) | - (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))); - - return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT, - "GC Master PCMCIA (0) CD", NULL); - return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT, - "GC Master CF (1) CD", NULL); - return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT, - "GC Master PCMCIA (0) BVD1", NULL); - return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT, - "GC Master CF (1) BVD1", NULL); - + /* why? */ MECR = 0x09430943; - return (return_val<0) ? -1 : 2; -} - -static int graphicsmaster_pcmcia_shutdown(void) -{ - - free_irq(S0_CD_VALID, NULL); - free_irq(S1_CD_VALID, NULL); - free_irq(S0_BVD1_STSCHG, NULL); - free_irq(S1_BVD1_STSCHG, NULL); - - INTPOL1 &= ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) | - (1 << (S1_CD_VALID - SA1111_IRQ(32))) | - (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) | - (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)))); - - return 0; -} - -static int graphicsmaster_pcmcia_socket_state(struct pcmcia_state_array *state_array) -{ - unsigned long status; - int return_val=1; - - if(state_array->size<2) return -1; - - memset(state_array->state, 0, - (state_array->size)*sizeof(struct pcmcia_state)); - - status=PCSR; - - state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0; - - state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1; - - state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1; - - state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1; - - state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1; - - state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0; - - state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0; - - state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0; - - state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1; - - state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1; - - state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1; - - state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1; - - state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0; - - state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0; - - return return_val; -} - -static int graphicsmaster_pcmcia_get_irq_info(struct pcmcia_irq_info *info) -{ - - switch(info->sock){ - case 0: - info->irq=S0_READY_NINT; - break; - - case 1: - info->irq=S1_READY_NINT; - break; - - default: - return -1; - } - - return 0; + return sa1111_pcmcia_init(init); } -static int graphicsmaster_pcmcia_configure_socket(const struct pcmcia_configure *configure) +static int +graphicsmaster_pcmcia_configure_socket(const struct pcmcia_configure *conf) { - unsigned long pccr=PCCR, gpio=PA_DWR; + unsigned int pa_dwr_mask, pa_dwr_set; + int ret; - switch(configure->sock){ + switch (conf->sock) { case 0: + pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1; - switch(configure->vcc){ - case 0: - pccr = (pccr & ~PCCR_S0_FLT); - gpio |= GPIO_GPIO0 | GPIO_GPIO1; - break; - - case 33: - pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN; - gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1); - gpio &= ~GPIO_GPIO0; - break; - - case 50: - pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN); - gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1); - gpio |= GPIO_GPIO0; - break; - + switch (conf->vcc) { default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; + case 0: pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1; break; + case 33: pa_dwr_set = GPIO_GPIO1; break; + case 50: pa_dwr_set = GPIO_GPIO0; break; } - - pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST); - break; case 1: - switch(configure->vcc){ - case 0: - pccr = (pccr & ~PCCR_S1_FLT); - gpio |= GPIO_GPIO2 | GPIO_GPIO3; - break; - - case 33: - pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN; - gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3); - gpio &= ~GPIO_GPIO2; - break; - - case 50: - pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN); - gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3); - gpio |= GPIO_GPIO2; - break; + pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3; + switch (conf->vcc) { default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; - } - - if(configure->vpp!=configure->vcc && configure->vpp!=0){ - printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__, - configure->vpp); - return -1; + case 0: pa_dwr_set = GPIO_GPIO2 | GPIO_GPIO3; break; + case 33: pa_dwr_set = GPIO_GPIO3; break; + case 50: pa_dwr_set = GPIO_GPIO2; break; } + } - pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST); - - break; - - default: + if (conf->vpp != conf->vcc && conf->vpp != 0) { + printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__, + conf->vpp); return -1; } - PCCR = pccr; - PA_DWR = gpio; + ret = sa1111_pcmcia_configure_socket(conf); + if (ret == 0) { + unsigned long flags; + + local_irq_save(flags); + PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set; + local_irq_restore(flags); + } - return 0; + return ret; } -struct pcmcia_low_level graphicsmaster_pcmcia_ops = { - graphicsmaster_pcmcia_init, - graphicsmaster_pcmcia_shutdown, - graphicsmaster_pcmcia_socket_state, - graphicsmaster_pcmcia_get_irq_info, - graphicsmaster_pcmcia_configure_socket +static struct pcmcia_low_level graphicsmaster_pcmcia_ops = { + init: graphicsmaster_pcmcia_init, + shutdown: sa1111_pcmcia_shutdown, + socket_state: sa1111_pcmcia_socket_state, + get_irq_info: sa1111_pcmcia_get_irq_info, + configure_socket: graphicsmaster_pcmcia_configure_socket, + + socket_init: sa1111_pcmcia_socket_init, + socket_suspend: sa1111_pcmcia_socket_suspend, }; +int __init pcmcia_graphicsmaster_init(void) +{ + int ret = -ENODEV; + + if (machine_is_graphicsmaster()) + ret = sa1100_register_pcmcia(&graphicsmaster_pcmcia_ops); + + return ret; +} + +void __exit pcmcia_graphicsmaster_exit(void) +{ + sa1100_unregister_pcmcia(&graphicsmaster_pcmcia_ops); +} + diff --git a/drivers/pcmcia/sa1100_h3600.c b/drivers/pcmcia/sa1100_h3600.c index b8977769ea46..b9310ea18e51 100644 --- a/drivers/pcmcia/sa1100_h3600.c +++ b/drivers/pcmcia/sa1100_h3600.c @@ -6,142 +6,192 @@ */ #include <linux/kernel.h> #include <linux/sched.h> +#include <linux/init.h> #include <asm/hardware.h> #include <asm/irq.h> -#include <asm/arch/pcmcia.h> - - -static int h3600_pcmcia_init(struct pcmcia_init *init){ - int irq, res; - - /* Enable CF bus: */ - set_h3600_egpio(EGPIO_H3600_OPT_NVRAM_ON); - clr_h3600_egpio(EGPIO_H3600_OPT_RESET); - - /* All those are inputs */ - GPDR &= ~(GPIO_H3600_PCMCIA_CD0 | GPIO_H3600_PCMCIA_CD1 | GPIO_H3600_PCMCIA_IRQ0| GPIO_H3600_PCMCIA_IRQ1); - - /* Set transition detect */ - set_GPIO_IRQ_edge( GPIO_H3600_PCMCIA_CD0 | GPIO_H3600_PCMCIA_CD1, GPIO_BOTH_EDGES ); - set_GPIO_IRQ_edge( GPIO_H3600_PCMCIA_IRQ0| GPIO_H3600_PCMCIA_IRQ1, GPIO_FALLING_EDGE ); - - /* Register interrupts */ - irq = IRQ_GPIO_H3600_PCMCIA_CD0; - res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD0", NULL ); - if( res < 0 ) goto irq_err; - irq = IRQ_GPIO_H3600_PCMCIA_CD1; - res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD1", NULL ); - if( res < 0 ) goto irq_err; - - return 2; +#include "sa1100_generic.h" + +static struct irqs { + int irq; + const char *str; +} irqs[] = { + { IRQ_GPIO_H3600_PCMCIA_CD0, "PCMCIA CD0" }, + { IRQ_GPIO_H3600_PCMCIA_CD1, "PCMCIA CD1" } +}; -irq_err: - printk( KERN_ERR __FUNCTION__ ": Request for IRQ %u failed\n", irq ); - return -1; +static int h3600_pcmcia_init(struct pcmcia_init *init) +{ + int i, res; + + /* + * Set transition detect + */ + set_irq_type(IRQ_GPIO_H3600_PCMCIA_IRQ0, IRQT_FALLING); + set_irq_type(IRQ_GPIO_H3600_PCMCIA_IRQ1, IRQT_FALLING); + + /* + * Register interrupts + */ + for (i = res = 0; i < ARRAY_SIZE(irqs); i++) { + res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT, + irqs[i].str, NULL); + if (res) + break; + } + + if (res) { + printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n", + __FUNCTION__, irqs[i].irq, res); + + while (i--) + free_irq(irqs[i].irq, NULL); + } + + return res ? res : 2; } static int h3600_pcmcia_shutdown(void) { - /* disable IRQs */ - free_irq( IRQ_GPIO_H3600_PCMCIA_CD0, NULL ); - free_irq( IRQ_GPIO_H3600_PCMCIA_CD1, NULL ); + int i; + + /* + * disable IRQs + */ + for (i = 0; i < ARRAY_SIZE(irqs); i++) + free_irq(irqs[i].irq, NULL); - /* Disable CF bus: */ - clr_h3600_egpio(EGPIO_H3600_OPT_NVRAM_ON|EGPIO_H3600_OPT_ON); - set_h3600_egpio(EGPIO_H3600_OPT_RESET); + /* Disable CF bus: */ + clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON); + clr_h3600_egpio(IPAQ_EGPIO_OPT_ON); + set_h3600_egpio(IPAQ_EGPIO_OPT_RESET); - return 0; + return 0; } -static int h3600_pcmcia_socket_state(struct pcmcia_state_array - *state_array){ - unsigned long levels; - - if(state_array->size<2) return -1; - - memset(state_array->state, 0, - (state_array->size)*sizeof(struct pcmcia_state)); - - levels=GPLR; - - state_array->state[0].detect=((levels & GPIO_H3600_PCMCIA_CD0)==0)?1:0; - state_array->state[0].ready=(levels & GPIO_H3600_PCMCIA_IRQ0)?1:0; - state_array->state[0].bvd1= 0; - state_array->state[0].bvd2= 0; - state_array->state[0].wrprot=0; /* Not available on H3600. */ - state_array->state[0].vs_3v=0; - state_array->state[0].vs_Xv=0; - - state_array->state[1].detect=((levels & GPIO_H3600_PCMCIA_CD1)==0)?1:0; - state_array->state[1].ready=(levels & GPIO_H3600_PCMCIA_IRQ1)?1:0; - state_array->state[1].bvd1=0; - state_array->state[1].bvd2=0; - state_array->state[1].wrprot=0; /* Not available on H3600. */ - state_array->state[1].vs_3v=0; - state_array->state[1].vs_Xv=0; - - return 1; +static int +h3600_pcmcia_socket_state(struct pcmcia_state_array *state) +{ + unsigned long levels; + + if (state->size < 2) + return -1; + + levels = GPLR; + + state->state[0].detect = levels & GPIO_H3600_PCMCIA_CD0 ? 0 : 1; + state->state[0].ready = levels & GPIO_H3600_PCMCIA_IRQ0 ? 1 : 0; + state->state[0].bvd1 = 0; + state->state[0].bvd2 = 0; + state->state[0].wrprot = 0; /* Not available on H3600. */ + state->state[0].vs_3v = 0; + state->state[0].vs_Xv = 0; + + state->state[1].detect = levels & GPIO_H3600_PCMCIA_CD1 ? 0 : 1; + state->state[1].ready = levels & GPIO_H3600_PCMCIA_IRQ1 ? 1 : 0; + state->state[1].bvd1 = 0; + state->state[1].bvd2 = 0; + state->state[1].wrprot = 0; /* Not available on H3600. */ + state->state[1].vs_3v = 0; + state->state[1].vs_Xv = 0; + + return 1; } -static int h3600_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ - - switch (info->sock) { - case 0: - info->irq=IRQ_GPIO_H3600_PCMCIA_IRQ0; - break; - case 1: - info->irq=IRQ_GPIO_H3600_PCMCIA_IRQ1; - break; - default: - return -1; - } - return 0; +static int h3600_pcmcia_get_irq_info(struct pcmcia_irq_info *info) +{ + switch (info->sock) { + case 0: + info->irq = IRQ_GPIO_H3600_PCMCIA_IRQ0; + break; + case 1: + info->irq = IRQ_GPIO_H3600_PCMCIA_IRQ1; + break; + default: + return -1; + } + return 0; } -static int h3600_pcmcia_configure_socket(const struct pcmcia_configure - *configure) +static int +h3600_pcmcia_configure_socket(const struct pcmcia_configure *conf) { - unsigned long flags; - - if(configure->sock>1) return -1; + if (conf->sock > 1) + return -1; - save_flags_cli(flags); + if (conf->vcc != 0 && conf->vcc != 33 && conf->vcc != 50) { + printk(KERN_ERR "h3600_pcmcia: unrecognized Vcc %u.%uV\n", + conf->vcc / 10, conf->vcc % 10); + return -1; + } - switch (configure->vcc) { - case 0: - clr_h3600_egpio(EGPIO_H3600_OPT_ON); - break; + if (conf->reset) + set_h3600_egpio(IPAQ_EGPIO_CARD_RESET); + else + clr_h3600_egpio(IPAQ_EGPIO_CARD_RESET); - case 33: - case 50: - set_h3600_egpio(EGPIO_H3600_OPT_ON); - break; + /* Silently ignore Vpp, output enable, speaker enable. */ - default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - restore_flags(flags); - return -1; - } - - if (configure->reset) - set_h3600_egpio(EGPIO_H3600_CARD_RESET); - else - clr_h3600_egpio(EGPIO_H3600_CARD_RESET); - - /* Silently ignore Vpp, output enable, speaker enable. */ + return 0; +} - restore_flags(flags); +static int h3600_pcmcia_socket_init(int sock) +{ + /* Enable CF bus: */ + set_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON); + set_h3600_egpio(IPAQ_EGPIO_OPT_ON); + clr_h3600_egpio(IPAQ_EGPIO_OPT_RESET); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(10*HZ / 1000); + + switch (sock) { + case 0: + set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD0, IRQT_BOTHEDGE); + break; + case 1: + set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD1, IRQT_BOTHEDGE); + break; + } + + return 0; +} - return 0; +static int h3600_pcmcia_socket_suspend(int sock) +{ + switch (sock) { + case 0: + set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD0, IRQT_NOEDGE); + break; + case 1: + set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD1, IRQT_NOEDGE); + break; + } + + /* + * FIXME: This doesn't fit well. We don't have the mechanism in + * the generic PCMCIA layer to deal with the idea of two sockets + * on one bus. We rely on the cs.c behaviour shutting down + * socket 0 then socket 1. + */ + if (sock == 1) { + clr_h3600_egpio(IPAQ_EGPIO_OPT_ON); + clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON); + /* hmm, does this suck power? */ + set_h3600_egpio(IPAQ_EGPIO_OPT_RESET); + } + + return 0; } struct pcmcia_low_level h3600_pcmcia_ops = { - h3600_pcmcia_init, - h3600_pcmcia_shutdown, - h3600_pcmcia_socket_state, - h3600_pcmcia_get_irq_info, - h3600_pcmcia_configure_socket + init: h3600_pcmcia_init, + shutdown: h3600_pcmcia_shutdown, + socket_state: h3600_pcmcia_socket_state, + get_irq_info: h3600_pcmcia_get_irq_info, + configure_socket: h3600_pcmcia_configure_socket, + + socket_init: h3600_pcmcia_socket_init, + socket_suspend: h3600_pcmcia_socket_suspend, }; diff --git a/drivers/pcmcia/sa1100_jornada720.c b/drivers/pcmcia/sa1100_jornada720.c index 071f550f2394..a5d07781929a 100644 --- a/drivers/pcmcia/sa1100_jornada720.c +++ b/drivers/pcmcia/sa1100_jornada720.c @@ -6,21 +6,24 @@ */ #include <linux/kernel.h> #include <linux/sched.h> +#include <linux/init.h> -#include <asm/delay.h> #include <asm/hardware.h> -#include <asm/irq.h> -#include <asm/arch/pcmcia.h> + +#include "sa1100_generic.h" +#include "sa1111_generic.h" #define SOCKET0_POWER GPIO_GPIO0 #define SOCKET0_3V GPIO_GPIO2 #define SOCKET1_POWER (GPIO_GPIO1 | GPIO_GPIO3) -#define SOCKET1_3V GPIO_GPIO3 +#warning *** Does SOCKET1_3V actually do anything? +#define SOCKET1_3V GPIO_GPIO3 static int jornada720_pcmcia_init(struct pcmcia_init *init) { - int return_val=0; - + /* + * What is all this crap for? + */ GRER |= 0x00000002; /* Set GPIO_A<3:1> to be outputs for PCMCIA/CF power controller: */ PA_DDR = 0; @@ -38,178 +41,82 @@ static int jornada720_pcmcia_init(struct pcmcia_init *init) PC_SDR = 0; PC_SSR = 0; - INTPOL1 |= - (1 << (S0_READY_NINT - SA1111_IRQ(32))) | - (1 << (S1_READY_NINT - SA1111_IRQ(32))) | - (1 << (S0_CD_VALID - SA1111_IRQ(32))) | - (1 << (S1_CD_VALID - SA1111_IRQ(32))) | - (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) | - (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))); - - return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT, - "Jornada720 PCMCIA (0) CD", NULL); - return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT, - "Jornada720 CF (1) CD", NULL); - return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT, - "Jornada720 PCMCIA (0) BVD1", NULL); - return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT, - "Jornada720 CF (1) BVD1", NULL); - - return (return_val<0) ? -1 : 2; -} - -static int jornada720_pcmcia_shutdown(void) -{ - free_irq(S0_CD_VALID, NULL); - free_irq(S1_CD_VALID, NULL); - free_irq(S0_BVD1_STSCHG, NULL); - free_irq(S1_BVD1_STSCHG, NULL); - - INTPOL1 &= - ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) | - (1 << (S1_CD_VALID - SA1111_IRQ(32))) | - (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) | - (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)))); - - return 0; -} - -static int jornada720_pcmcia_socket_state(struct pcmcia_state_array - *state_array) -{ - unsigned long status; - int return_val=1; - - if(state_array->size<2) return -1; - - memset(state_array->state, 0, - (state_array->size)*sizeof(struct pcmcia_state)); - status=PCSR; - state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0; - state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1; - state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1; - state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1; - state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1; - state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0; - state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0; - state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0; - state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1; - state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1; - state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1; - state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1; - state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0; - state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0; - return return_val; -} - -static int jornada720_pcmcia_get_irq_info(struct pcmcia_irq_info *info) -{ - switch(info->sock){ - case 0: - info->irq=S0_READY_NINT; - break; - - case 1: - info->irq=S1_READY_NINT; - break; - - default: - return -1; - } - return 0; + return sa1111_pcmcia_init(init); } -static int jornada720_pcmcia_configure_socket(const struct pcmcia_configure - *configure) +static int +jornada720_pcmcia_configure_socket(const struct pcmcia_configure *conf) { - unsigned long pccr=PCCR, gpio=PA_DWR; + unsigned int pa_dwr_mask, pa_dwr_set; + int ret; printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__, - configure->sock, configure->vcc, configure->vpp); - switch(configure->sock){ + conf->sock, conf->vcc, conf->vpp); + + switch (conf->sock) { case 0: - switch(configure->vcc){ - case 0: - pccr = (pccr & ~PCCR_S0_FLT); - gpio&=~(SOCKET0_POWER | SOCKET0_3V); - break; - - case 33: - pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN; - gpio |= SOCKET0_POWER | SOCKET0_3V; - break; - - case 50: - pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN); - gpio = (gpio & ~SOCKET0_3V) | SOCKET0_POWER; - break; + pa_dwr_mask = SOCKET0_POWER | SOCKET0_3V; + switch (conf->vcc) { default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; - } - switch(configure->vpp){ - case 0: - break; - case 50: - printk(KERN_ERR "%s(): 5.0 Vpp %u\n", __FUNCTION__, - configure->vpp); - break; - case 120: - printk(KERN_ERR "%s(): 12 Vpp %u\n", __FUNCTION__, - configure->vpp); - break; - default: - printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__, - configure->vpp); - return -1; + case 0: pa_dwr_set = 0; break; + case 33: pa_dwr_set = SOCKET0_POWER | SOCKET0_3V; break; + case 50: pa_dwr_set = SOCKET0_POWER; break; } - pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST); break; case 1: - switch(configure->vcc){ - case 0: - pccr = (pccr & ~PCCR_S1_FLT); - gpio &= ~(SOCKET1_POWER); - break; - - case 33: - pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN; - gpio |= SOCKET1_POWER; - break; - - case 50: - pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN); - gpio = (gpio & ~(SOCKET1_POWER)) | SOCKET1_POWER; - break; + pa_dwr_mask = SOCKET1_POWER; + switch (conf->vcc) { default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; + case 0: pa_dwr_set = 0; break; + case 33: pa_dwr_set = SOCKET1_POWER; break; + case 50: pa_dwr_set = SOCKET1_POWER; break; } - if(configure->vpp!=configure->vcc && configure->vpp!=0){ - printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__, - configure->vpp); - return -1; - } - pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST); break; - default: + } + + if (conf->vpp != conf->vcc && conf->vpp != 0) { + printk(KERN_ERR "%s(): slot cannot support VPP %u\n", + __FUNCTION__, conf->vpp); return -1; } - PCCR = pccr; - PA_DWR = gpio; - return 0; + + ret = sa1111_pcmcia_configure_socket(conf); + if (ret == 0) { + unsigned long flags; + + local_irq_save(flags); + PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set; + locla_irq_restore(flags); + } + + return ret; } -struct pcmcia_low_level jornada720_pcmcia_ops = { - jornada720_pcmcia_init, - jornada720_pcmcia_shutdown, - jornada720_pcmcia_socket_state, - jornada720_pcmcia_get_irq_info, - jornada720_pcmcia_configure_socket +static struct pcmcia_low_level jornada720_pcmcia_ops = { + init: jornada720_pcmcia_init, + shutdown: sa1111_pcmcia_shutdown, + socket_state: sa1111_pcmcia_socket_state, + get_irq_info: sa1111_pcmcia_get_irq_info, + configure_socket: jornada720_pcmcia_configure_socket, + + socket_init: sa1111_pcmcia_socket_init, + socket_suspend: sa1111_pcmcia_socket_suspend, }; +int __init pcmcia_jornada720_init(void) +{ + int ret = -ENODEV; + + if (machine_is_jornada720()) + ret = sa1100_register_pcmcia(&jornada720_pcmcia_ops); + + return ret; +} + +void __exit pcmcia_jornada720_exit(void) +{ + sa1100_unregister_pcmcia(&jornada720_pcmcia_ops); +} diff --git a/drivers/pcmcia/sa1100_neponset.c b/drivers/pcmcia/sa1100_neponset.c index 9a556c3bec09..12408343d653 100644 --- a/drivers/pcmcia/sa1100_neponset.c +++ b/drivers/pcmcia/sa1100_neponset.c @@ -1,249 +1,145 @@ /* - * drivers/pcmcia/sa1100_neponset.c + * linux/drivers/pcmcia/sa1100_neponset.c * * Neponset PCMCIA specific routines - * */ #include <linux/kernel.h> #include <linux/sched.h> +#include <linux/init.h> -#include <asm/delay.h> #include <asm/hardware.h> -#include <asm/irq.h> -#include <asm/arch/pcmcia.h> #include <asm/arch/assabet.h> +#include <asm/hardware/sa1111.h> -static int neponset_pcmcia_init(struct pcmcia_init *init){ - int return_val=0; - - /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */ - PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); - - /* MAX1600 to standby mode: */ - PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); - NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP); - - INTPOL1 |= - (1 << (S0_READY_NINT - SA1111_IRQ(32))) | - (1 << (S1_READY_NINT - SA1111_IRQ(32))) | - (1 << (S0_CD_VALID - SA1111_IRQ(32))) | - (1 << (S1_CD_VALID - SA1111_IRQ(32))) | - (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) | - (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))); - - return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT, - "Neponset PCMCIA (0) CD", NULL); - return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT, - "Neponset CF (1) CD", NULL); - return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT, - "Neponset PCMCIA (0) BVD1", NULL); - return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT, - "Neponset CF (1) BVD1", NULL); - - return (return_val<0) ? -1 : 2; -} - -static int neponset_pcmcia_shutdown(void){ +#include "sa1100_generic.h" +#include "sa1111_generic.h" - free_irq(S0_CD_VALID, NULL); - free_irq(S1_CD_VALID, NULL); - free_irq(S0_BVD1_STSCHG, NULL); - free_irq(S1_BVD1_STSCHG, NULL); +static int neponset_pcmcia_init(struct pcmcia_init *init) +{ + /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */ + PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); - INTPOL1 &= - ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) | - (1 << (S1_CD_VALID - SA1111_IRQ(32))) | - (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) | - (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)))); + /* MAX1600 to standby mode: */ + PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); + NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP); - return 0; + return sa1111_pcmcia_init(init); } -static int neponset_pcmcia_socket_state(struct pcmcia_state_array - *state_array){ - unsigned long status; - int return_val=1; - - if(state_array->size<2) return -1; - - memset(state_array->state, 0, - (state_array->size)*sizeof(struct pcmcia_state)); - - status=PCSR; - - state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0; - - state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1; - - state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1; - - state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1; - - state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1; - - state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0; - - state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0; - - state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0; - - state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1; - - state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1; - - state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1; - - state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1; - - state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0; - - state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0; - - return return_val; +static int +neponset_pcmcia_configure_socket(const struct pcmcia_configure *conf) +{ + unsigned int ncr_mask, pa_dwr_mask; + unsigned int ncr_set, pa_dwr_set; + int ret; + + /* Neponset uses the Maxim MAX1600, with the following connections: + + * MAX1600 Neponset + * + * A0VCC SA-1111 GPIO A<1> + * A1VCC SA-1111 GPIO A<0> + * A0VPP CPLD NCR A0VPP + * A1VPP CPLD NCR A1VPP + * B0VCC SA-1111 GPIO A<2> + * B1VCC SA-1111 GPIO A<3> + * B0VPP ground (slot B is CF) + * B1VPP ground (slot B is CF) + * + * VX VCC (5V) + * VY VCC3_3 (3.3V) + * 12INA 12V + * 12INB ground (slot B is CF) + * + * The MAX1600 CODE pin is tied to ground, placing the device in + * "Standard Intel code" mode. Refer to the Maxim data sheet for + * the corresponding truth table. + */ + + switch (conf->sock) { + case 0: + pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1; + ncr_mask = NCR_A0VPP | NCR_A1VPP; + + switch (conf->vcc) { + default: + case 0: pa_dwr_set = 0; break; + case 33: pa_dwr_set = GPIO_GPIO1; break; + case 50: pa_dwr_set = GPIO_GPIO0; break; + } + + switch (conf->vpp) { + case 0: ncr_set = 0; break; + case 120: ncr_set = NCR_A1VPP; break; + default: + if (conf->vpp == conf->vcc) + ncr_set = NCR_A0VPP; + else { + printk(KERN_ERR "%s(): unrecognized VPP %u\n", + __FUNCTION__, conf->vpp); + return -1; + } + } + break; + + case 1: + pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3; + ncr_mask = 0; + ncr_set = 0; + + switch (conf->vcc) { + default: + case 0: pa_dwr_set = 0; break; + case 33: pa_dwr_set = GPIO_GPIO2; break; + case 50: pa_dwr_set = GPIO_GPIO3; break; + } + + if (conf->vpp != conf->vcc && conf->vpp != 0) { + printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n", + __FUNCTION__, conf->vpp); + return -1; + } + break; + + default: + return -1; + } + + ret = sa1111_pcmcia_configure_socket(conf); + if (ret == 0) { + unsigned long flags; + + local_irq_save(flags); + NCR_0 = (NCR_0 & ~ncr_mask) | ncr_set; + PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set; + local_irq_restore(flags); + } + + return 0; } -static int neponset_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ +static struct pcmcia_low_level neponset_pcmcia_ops = { + init: neponset_pcmcia_init, + shutdown: sa1111_pcmcia_shutdown, + socket_state: sa1111_pcmcia_socket_state, + get_irq_info: sa1111_pcmcia_get_irq_info, + configure_socket: neponset_pcmcia_configure_socket, - switch(info->sock){ - case 0: - info->irq=S0_READY_NINT; - break; + socket_init: sa1111_pcmcia_socket_init, + socket_suspend: sa1111_pcmcia_socket_suspend, +}; - case 1: - info->irq=S1_READY_NINT; - break; +int __init pcmcia_neponset_init(void) +{ + int ret = -ENODEV; - default: - return -1; - } + if (machine_is_assabet() && machine_has_neponset()) + ret = sa1100_register_pcmcia(&neponset_pcmcia_ops); - return 0; + return ret; } -static int neponset_pcmcia_configure_socket(const struct pcmcia_configure - *configure){ - unsigned long pccr=PCCR, ncr=NCR_0, gpio=PA_DWR; - - /* Neponset uses the Maxim MAX1600, with the following connections: - * - * MAX1600 Neponset - * - * A0VCC SA-1111 GPIO A<1> - * A1VCC SA-1111 GPIO A<0> - * A0VPP CPLD NCR A0VPP - * A1VPP CPLD NCR A1VPP - * B0VCC SA-1111 GPIO A<2> - * B1VCC SA-1111 GPIO A<3> - * B0VPP ground (slot B is CF) - * B1VPP ground (slot B is CF) - * - * VX VCC (5V) - * VY VCC3_3 (3.3V) - * 12INA 12V - * 12INB ground (slot B is CF) - * - * The MAX1600 CODE pin is tied to ground, placing the device in - * "Standard Intel code" mode. Refer to the Maxim data sheet for - * the corresponding truth table. - */ - - switch(configure->sock){ - case 0: - - switch(configure->vcc){ - case 0: - pccr=(pccr & ~PCCR_S0_FLT); - gpio&=~(GPIO_GPIO0 | GPIO_GPIO1); - break; - - case 33: - pccr=(pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN; - gpio=(gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO1; - break; - - case 50: - pccr=(pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN); - gpio=(gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO0; - break; - - default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; - } - - switch(configure->vpp){ - case 0: - ncr&=~(NCR_A0VPP | NCR_A1VPP); - break; - - case 120: - ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A1VPP; - break; - - default: - if(configure->vpp == configure->vcc) - ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A0VPP; - else { - printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__, - configure->vpp); - return -1; - } - } - - pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST); - - break; - - case 1: - switch(configure->vcc){ - case 0: - pccr=(pccr & ~PCCR_S1_FLT); - gpio&=~(GPIO_GPIO2 | GPIO_GPIO3); - break; - - case 33: - pccr=(pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN; - gpio=(gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO2; - break; - - case 50: - pccr=(pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN); - gpio=(gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO3; - break; - - default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; - } - - if(configure->vpp!=configure->vcc && configure->vpp!=0){ - printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__, - configure->vpp); - return -1; - } - - pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST); - - break; - - default: - return -1; - } - - PCCR = pccr; - NCR_0 = ncr; - PA_DWR = gpio; - - return 0; +void __exit pcmcia_neponset_exit(void) +{ + sa1100_unregister_pcmcia(&neponset_pcmcia_ops); } - -struct pcmcia_low_level neponset_pcmcia_ops = { - neponset_pcmcia_init, - neponset_pcmcia_shutdown, - neponset_pcmcia_socket_state, - neponset_pcmcia_get_irq_info, - neponset_pcmcia_configure_socket -}; - diff --git a/drivers/pcmcia/sa1100_pangolin.c b/drivers/pcmcia/sa1100_pangolin.c index 9e68e50dc066..35455466f8f7 100644 --- a/drivers/pcmcia/sa1100_pangolin.c +++ b/drivers/pcmcia/sa1100_pangolin.c @@ -4,48 +4,45 @@ * PCMCIA implementation routines for Pangolin * */ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> +#include <linux/init.h> #include <asm/hardware.h> #include <asm/irq.h> -#include <asm/arch/pcmcia.h> +#include "sa1100_generic.h" static int pangolin_pcmcia_init(struct pcmcia_init *init){ - int irq, res; + int res; - /* set GPIO_PCMCIA_CD & GPIO_PCMCIA_IRQ as inputs */ - GPDR &= ~(GPIO_PCMCIA_CD|GPIO_PCMCIA_IRQ); #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE - /* set GPIO pins GPIO_PCMCIA_BUS_ON & GPIO_PCMCIA_RESET as output */ - GPDR |= (GPIO_PCMCIA_BUS_ON|GPIO_PCMCIA_RESET); /* Enable PCMCIA bus: */ GPCR = GPIO_PCMCIA_BUS_ON; -#else - /* set GPIO pin GPIO_PCMCIA_RESET as output */ - GPDR |= GPIO_PCMCIA_RESET; #endif + /* Set transition detect */ - set_GPIO_IRQ_edge( GPIO_PCMCIA_CD, GPIO_BOTH_EDGES ); - set_GPIO_IRQ_edge( GPIO_PCMCIA_IRQ, GPIO_FALLING_EDGE ); + set_irq_type(IRQ_PCMCIA_CD, IRQT_NOEDGE); + set_irq_type(IRQ_PCMCIA_IRQ, IRQT_FALLING); /* Register interrupts */ - irq = IRQ_PCMCIA_CD; - res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD", NULL ); - if( res < 0 ) goto irq_err; - - /* There's only one slot, but it's "Slot 1": */ - return 2; + res = request_irq(IRQ_PCMCIA_CD, init->handler, SA_INTERRUPT, + "PCMCIA_CD", NULL); + if (res >= 0) + /* There's only one slot, but it's "Slot 1": */ + return 2; irq_err: - printk( KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq ); - return -1; + printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n", + __FUNCTION__, IRQ_PCMCIA_CD, res); + + return res; } static int pangolin_pcmcia_shutdown(void) { /* disable IRQs */ - free_irq( IRQ_PCMCIA_CD, NULL ); + free_irq(IRQ_PCMCIA_CD, NULL); #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE /* Disable PCMCIA bus: */ GPSR = GPIO_PCMCIA_BUS_ON; @@ -105,7 +102,7 @@ static int pangolin_pcmcia_configure_socket(const struct pcmcia_configure #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE if(configure->sock==0) return 0; #endif - save_flags_cli(flags); + local_irq_save(flags); /* Murphy: BUS_ON different from POWER ? */ @@ -129,7 +126,7 @@ static int pangolin_pcmcia_configure_socket(const struct pcmcia_configure default: printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, configure->vcc); - restore_flags(flags); + local_irq_restore(flags); return -1; } #ifdef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE @@ -143,15 +140,47 @@ static int pangolin_pcmcia_configure_socket(const struct pcmcia_configure } #endif /* Silently ignore Vpp, output enable, speaker enable. */ - restore_flags(flags); + local_irq_restore(flags); return 0; } -struct pcmcia_low_level pangolin_pcmcia_ops = { - pangolin_pcmcia_init, - pangolin_pcmcia_shutdown, - pangolin_pcmcia_socket_state, - pangolin_pcmcia_get_irq_info, - pangolin_pcmcia_configure_socket +static int pangolin_pcmcia_socket_init(int sock) +{ + if (sock == 1) + set_irq_type(IRQ_PCmCIA_CD, IRQT_BOTHEDGE); + return 0; +} + +static int pangolin_pcmcia_socket_suspend(int sock) +{ + if (sock == 1) + set_irq_type(IRQ_PCmCIA_CD, IRQT_NOEDGE); + return 0; +} + +static struct pcmcia_low_level pangolin_pcmcia_ops = { + init: pangolin_pcmcia_init, + shutdown: pangolin_pcmcia_shutdown, + socket_state: pangolin_pcmcia_socket_state, + get_irq_info: pangolin_pcmcia_get_irq_info, + configure_socket: pangolin_pcmcia_configure_socket, + + socket_init: pangolin_pcmcia_socket_init, + socket_suspend, pangolin_pcmcia_socket_suspend, }; +int __init pcmcia_pangolin_init(void) +{ + int ret = -ENODEV; + + if (machine_is_pangolin()) + ret = sa1100_register_pcmcia(&pangolin_pcmcia_ops); + + return ret; +} + +void __exit pcmcia_pangolin_exit(void) +{ + sa1100_unregister_pcmcia(&pangolin_pcmcia_ops); +} + diff --git a/drivers/pcmcia/sa1100_pfs168.c b/drivers/pcmcia/sa1100_pfs168.c index ce9128c46a73..af028d61b682 100644 --- a/drivers/pcmcia/sa1100_pfs168.c +++ b/drivers/pcmcia/sa1100_pfs168.c @@ -7,121 +7,31 @@ */ #include <linux/kernel.h> #include <linux/sched.h> +#include <linux/init.h> #include <asm/delay.h> #include <asm/hardware.h> #include <asm/irq.h> -#include <asm/arch/pcmcia.h> -static int pfs168_pcmcia_init(struct pcmcia_init *init){ - int return_val=0; +#include "sa1100_generic.h" +#include "sa1111_generic.h" +static int pfs168_pcmcia_init(struct pcmcia_init *init) +{ /* TPS2211 to standby mode: */ PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); /* Set GPIO_A<3:0> to be outputs for PCMCIA (socket 0) power controller: */ PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); - INTPOL1 |= - (1 << (S0_READY_NINT - SA1111_IRQ(32))) | - (1 << (S1_READY_NINT - SA1111_IRQ(32))) | - (1 << (S0_CD_VALID - SA1111_IRQ(32))) | - (1 << (S1_CD_VALID - SA1111_IRQ(32))) | - (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) | - (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))); - - return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT, - "PFS168 PCMCIA (0) CD", NULL); - return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT, - "PFS168 CF (1) CD", NULL); - return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT, - "PFS168 PCMCIA (0) BVD1", NULL); - return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT, - "PFS168 CF (1) BVD1", NULL); - - return (return_val<0) ? -1 : 2; + return sa1111_pcmcia_init(init); } -static int pfs168_pcmcia_shutdown(void){ - - free_irq(S0_CD_VALID, NULL); - free_irq(S1_CD_VALID, NULL); - free_irq(S0_BVD1_STSCHG, NULL); - free_irq(S1_BVD1_STSCHG, NULL); - - INTPOL1 &= - ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) | - (1 << (S1_CD_VALID - SA1111_IRQ(32))) | - (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) | - (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)))); - - return 0; -} - -static int pfs168_pcmcia_socket_state(struct pcmcia_state_array - *state_array){ - unsigned long status; - int return_val=1; - - if(state_array->size<2) return -1; - - memset(state_array->state, 0, - (state_array->size)*sizeof(struct pcmcia_state)); - - status=PCSR; - - state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0; - - state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1; - - state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1; - - state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1; - - state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1; - - state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0; - - state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0; - - state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0; - - state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1; - - state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1; - - state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1; - - state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1; - - state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0; - - state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0; - - return return_val; -} - -static int pfs168_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ - - switch(info->sock){ - case 0: - info->irq=S0_READY_NINT; - break; - - case 1: - info->irq=S1_READY_NINT; - break; - - default: - return -1; - } - - return 0; -} - -static int pfs168_pcmcia_configure_socket(const struct pcmcia_configure - *configure){ - unsigned long pccr=PCCR, gpio=PA_DWR; +static int +pfs168_pcmcia_configure_socket(const struct pcmcia_configure *conf) +{ + unsigned int pa_dwr_mask = 0, pa_dwr_set = 0; + int ret; /* PFS168 uses the Texas Instruments TPS2211 for PCMCIA (socket 0) voltage control only, * with the following connections: @@ -135,103 +45,100 @@ static int pfs168_pcmcia_configure_socket(const struct pcmcia_configure * */ - switch(configure->sock){ + switch (conf->sock) { case 0: + pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3; - switch(configure->vcc){ - case 0: - pccr = (pccr & ~PCCR_S0_FLT); - gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1); - break; - - case 33: - pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN; - gpio = (gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO0; - break; - - case 50: - pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN); - gpio = (gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO1; - break; - + switch (conf->vcc) { default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; + case 0: pa_dwr_set = 0; break; + case 33: pa_dwr_set = GPIO_GPIO0; break; + case 50: pa_dwr_set = GPIO_GPIO1; break; } - switch(configure->vpp){ + switch (conf->vpp) { case 0: - gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3); break; case 120: - printk(KERN_ERR "%s(): PFS-168 does not support Vpp %uV\n", __FUNCTION__, - configure->vpp/10); + printk(KERN_ERR "%s(): PFS-168 does not support VPP %uV\n", + __FUNCTION__, conf->vpp / 10); return -1; break; default: - if(configure->vpp == configure->vcc) - gpio = (gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO3; + if (conf->vpp == conf->vcc) + pa_dwr_set |= GPIO_GPIO3; else { - printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__, - configure->vpp); + printk(KERN_ERR "%s(): unrecognized VPP %u\n", __FUNCTION__, + conf->vpp); return -1; } } - - pccr = (configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST); - - PA_DWR = gpio; - break; case 1: - switch(configure->vcc){ - case 0: - pccr = (pccr & ~PCCR_S1_FLT); - break; + pa_dwr_mask = 0; + pa_dwr_set = 0; + switch (conf->vcc) { + case 0: case 33: - pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN; break; case 50: - printk(KERN_ERR "%s(): PFS-168 CompactFlash socket does not support Vcc %uV\n", __FUNCTION__, - configure->vcc/10); + printk(KERN_ERR "%s(): PFS-168 CompactFlash socket does not support VCC %uV\n", + __FUNCTION__, conf->vcc / 10); return -1; - break; default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); + printk(KERN_ERR "%s(): unrecognized VCC %u\n", __FUNCTION__, + conf->vcc); return -1; } - if(configure->vpp!=configure->vcc && configure->vpp!=0){ - printk(KERN_ERR "%s(): CompactFlash socket does not support Vpp %uV\n", __FUNCTION__, - configure->vpp/10); + if (conf->vpp != conf->vcc && conf->vpp != 0) { + printk(KERN_ERR "%s(): CompactFlash socket does not support VPP %uV\n" + __FUNCTION__, conf->vpp / 10); return -1; } - - pccr = (configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST); - break; - - default: - return -1; } - PCCR = pccr; + ret = sa1111_pcmcia_configure_socket(conf); + if (ret == 0) { + unsigned long flags; + + local_irq_save(flags); + PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set; + local_irq_restore(flags); + } return 0; } -struct pcmcia_low_level pfs168_pcmcia_ops = { - pfs168_pcmcia_init, - pfs168_pcmcia_shutdown, - pfs168_pcmcia_socket_state, - pfs168_pcmcia_get_irq_info, - pfs168_pcmcia_configure_socket +static struct pcmcia_low_level pfs168_pcmcia_ops = { + init: pfs168_pcmcia_init, + shutdown: sa1111_pcmcia_shutdown, + socket_state: sa1111_pcmcia_socket_state, + get_irq_info: sa1111_pcmcia_get_irq_info, + configure_socket: pfs168_pcmcia_configure_socket, + + socket_init: sa1111_pcmcia_socket_init, + socket_suspend: sa1111_pcmcia_socket_suspend, }; + +int __init pcmcia_pfs168_init(void) +{ + int ret = -ENODEV; + + if (machine_is_pfs168()) + ret = sa1100_register_pcmcia(&pfs168_pcmcia_ops); + + return ret; +} + +void __exit pcmcia_pfs168_exit(void) +{ + sa1100_unregister_pcmcia(&pfs168_pcmcia_ops); +} diff --git a/drivers/pcmcia/sa1100_shannon.c b/drivers/pcmcia/sa1100_shannon.c new file mode 100644 index 000000000000..7cfe0105a225 --- /dev/null +++ b/drivers/pcmcia/sa1100_shannon.c @@ -0,0 +1,177 @@ +/* + * drivers/pcmcia/sa1100_shannon.c + * + * PCMCIA implementation routines for Shannon + * + */ +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/init.h> + +#include <asm/hardware.h> +#include <asm/arch/shannon.h> +#include <asm/irq.h> +#include "sa1100_generic.h" + +static struct irqs { + int irq; + const char *str; +} irqs[] = { + { SHANNON_IRQ_GPIO_EJECT_0, "PCMCIA_CD_0" }, + { SHANNON_IRQ_GPIO_EJECT_1, "PCMCIA_CD_1" }, +}; + +static int shannon_pcmcia_init(struct pcmcia_init *init) +{ + int i, res; + + /* All those are inputs */ + GPDR &= ~(SHANNON_GPIO_EJECT_0 | SHANNON_GPIO_EJECT_1 | + SHANNON_GPIO_RDY_0 | SHANNON_GPIO_RDY_1); + GAFR &= ~(SHANNON_GPIO_EJECT_0 | SHANNON_GPIO_EJECT_1 | + SHANNON_GPIO_RDY_0 | SHANNON_GPIO_RDY_1); + + /* Set transition detect */ + set_irq_type(SHANNON_IRQ_GPIO_RDY_0, IRQT_FALLING); + set_irq_type(SHANNON_IRQ_GPIO_RDY_1, IRQT_FALLING); + + /* Register interrupts */ + for (i = 0; i < ARRAY_SIZE(irqs); i++) { + set_irq_type(irqs[i].irq, IRQT_NOEDGE); + res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT, + irqs[i].str, NULL); + if (res) + goto irq_err; + } + + return 2; + + irq_err: + printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n", + __FUNCTION__, irqs[i].irq, res); + + while (i--) + free_irq(irqs[i].irq, NULL); + + return res; +} + +static int shannon_pcmcia_shutdown(void) +{ + int i; + + /* disable IRQs */ + for (i = 0; i < ARRAY_SIZE(irqs); i++) + free_irq(irqs[i].irq, NULL); + + return 0; +} + +static int shannon_pcmcia_socket_state(struct pcmcia_state_array *state_array) +{ + unsigned long levels; + + memset(state_array->state, 0, + state_array->size * sizeof(struct pcmcia_state)); + + levels = GPLR; + + state_array->state[0].detect = (levels & SHANNON_GPIO_EJECT_0) ? 0 : 1; + state_array->state[0].ready = (levels & SHANNON_GPIO_RDY_0) ? 1 : 0; + state_array->state[0].wrprot = 0; /* Not available on Shannon. */ + state_array->state[0].bvd1 = 1; + state_array->state[0].bvd2 = 1; + state_array->state[0].vs_3v = 1; /* FIXME Can only apply 3.3V on Shannon. */ + state_array->state[0].vs_Xv = 0; + + state_array->state[1].detect = (levels & SHANNON_GPIO_EJECT_1) ? 0 : 1; + state_array->state[1].ready = (levels & SHANNON_GPIO_RDY_1) ? 1 : 0; + state_array->state[1].wrprot = 0; /* Not available on Shannon. */ + state_array->state[1].bvd1 = 1; + state_array->state[1].bvd2 = 1; + state_array->state[1].vs_3v = 1; /* FIXME Can only apply 3.3V on Shannon. */ + state_array->state[1].vs_Xv = 0; + + return 1; +} + +static int shannon_pcmcia_get_irq_info(struct pcmcia_irq_info *info) +{ + if (info->sock == 0) + info->irq = SHANNON_IRQ_GPIO_RDY_0; + else if (info->sock == 1) + info->irq = SHANNON_IRQ_GPIO_RDY_1; + else return -1; + + return 0; +} + +static int shannon_pcmcia_configure_socket(const struct pcmcia_configure *configure) +{ + + switch (configure->vcc) { + case 0: /* power off */ + printk(KERN_WARNING __FUNCTION__"(): CS asked for 0V, still applying 3.3V..\n"); + break; + case 50: + printk(KERN_WARNING __FUNCTION__"(): CS asked for 5V, applying 3.3V..\n"); + case 33: + break; + default: + printk(KERN_ERR __FUNCTION__"(): unrecognized Vcc %u\n", + configure->vcc); + return -1; + } + + printk(KERN_WARNING __FUNCTION__"(): Warning, Can't perform reset\n"); + + /* Silently ignore Vpp, output enable, speaker enable. */ + + return 0; +} + +static int shannon_pcmcia_socket_init(int sock) +{ + if (sock == 0) + set_irq_type(SHANNON_IRQ_GPIO_EJECT_0, IRQT_BOTHEDGE); + else if (sock == 1) + set_irq_Type(SHANNON_IRQ_GPIO_EJECT_1, IRQT_BOTHEDGE); + + return 0; +} + +static int shannon_pcmcia_socket_suspend(int sock) +{ + if (sock == 0) + set_irq_type(SHANNON_IRQ_GPIO_EJECT_0, IRQT_NOEDGE); + else if (sock == 1) + set_irq_type(SHANNON_IRQ_GPIO_EJECT_1, IRQT_NOEDGE); + + return 0; +} + +static struct pcmcia_low_level shannon_pcmcia_ops = { + init: shannon_pcmcia_init, + shutdown: shannon_pcmcia_shutdown, + socket_state: shannon_pcmcia_socket_state, + get_irq_info: shannon_pcmcia_get_irq_info, + configure_socket: shannon_pcmcia_configure_socket, + + socket_init: shannon_pcmcia_socket_init, + socket_suspend: shannon_pcmcia_socket_suspend, +}; + +int __init pcmcia_shannon_init(void) +{ + int ret = -ENODEV; + + if (machine_is_shannon()) + ret = sa1100_register_pcmcia(&shannon_pcmcia_ops); + + return ret; +} + +void __exit pcmcia_shannon_exit(void) +{ + sa1100_unregister_pcmcia(&shannon_pcmcia_ops); +} diff --git a/drivers/pcmcia/sa1100_simpad.c b/drivers/pcmcia/sa1100_simpad.c index 0da5af015751..bbe79bdf8fc1 100644 --- a/drivers/pcmcia/sa1100_simpad.c +++ b/drivers/pcmcia/sa1100_simpad.c @@ -6,10 +6,11 @@ */ #include <linux/kernel.h> #include <linux/sched.h> +#include <linux/init.h> #include <asm/hardware.h> #include <asm/irq.h> -#include <asm/arch/pcmcia.h> +#include "sa1100_generic.h" extern long get_cs3_shadow(void); extern void set_cs3_bit(int value); @@ -19,9 +20,6 @@ extern void clear_cs3_bit(int value); static int simpad_pcmcia_init(struct pcmcia_init *init){ int irq, res; - /* set GPIO_CF_CD & GPIO_CF_IRQ as inputs */ - GPDR &= ~(GPIO_CF_CD|GPIO_CF_IRQ); - set_cs3_bit(PCMCIA_RESET); clear_cs3_bit(PCMCIA_BUFF_DIS); clear_cs3_bit(PCMCIA_RESET); @@ -29,8 +27,8 @@ static int simpad_pcmcia_init(struct pcmcia_init *init){ clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); /* Set transition detect */ - set_GPIO_IRQ_edge( GPIO_CF_CD, GPIO_BOTH_EDGES ); - set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE ); + set_irq_type( IRQ_GPIO_CF_CD, IRQT_NOEDGE ); + set_irq_type( IRQ_GPIO_CF_IRQ, IRQT_FALLING ); /* Register interrupts */ irq = IRQ_GPIO_CF_CD; @@ -41,8 +39,9 @@ static int simpad_pcmcia_init(struct pcmcia_init *init){ return 2; irq_err: - printk( KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq ); - return -1; + printk( KERN_ERR "%s: request for IRQ%d failed (%d)\n", + __FUNCTION__, irq, res); + return res; } static int simpad_pcmcia_shutdown(void) @@ -112,7 +111,7 @@ static int simpad_pcmcia_configure_socket(const struct pcmcia_configure if(configure->sock==0) return 0; - save_flags_cli(flags); + local_irq_save(flags); /* Murphy: see table of MIC2562a-1 */ @@ -135,22 +134,51 @@ static int simpad_pcmcia_configure_socket(const struct pcmcia_configure printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, configure->vcc); clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); - restore_flags(flags); + local_irq_restore(flags); return -1; } /* Silently ignore Vpp, output enable, speaker enable. */ - restore_flags(flags); + local_irq_restore(flags); return 0; } -struct pcmcia_low_level simpad_pcmcia_ops = { - simpad_pcmcia_init, - simpad_pcmcia_shutdown, - simpad_pcmcia_socket_state, - simpad_pcmcia_get_irq_info, - simpad_pcmcia_configure_socket +static int simpad_pcmcia_socket_init(int sock) +{ + set_irq_type(IRQ_GPIO_CF_CD, IRQT_BOTHEDGE); + return 0; +} + +static int simpad_pcmcia_socket_suspend(int sock) +{ + set_irq_type(IRQ_GPIO_CF_CD, IRQT_NOEDGE); + return 0; +} + +static struct pcmcia_low_level simpad_pcmcia_ops = { + init: simpad_pcmcia_init, + shutdown: simpad_pcmcia_shutdown, + socket_state: simpad_pcmcia_socket_state, + get_irq_info: simpad_pcmcia_get_irq_info, + configure_socket: simpad_pcmcia_configure_socket, + + socket_init: simpad_pcmcia_socket_init, + socket_suspend: simpad_pcmcia_socket_suspend, }; +int __init pcmcia_simpad_init(void) +{ + int ret = -ENODEV; + + if (machine_is_simpad()) + ret = sa1100_register_pcmcia(&simpad_pcmcia_ops); + + return ret; +} + +void __exit pcmcia_simpad_exit(void) +{ + sa1100_unregister_pcmcia(&simpad_pcmcia_ops); +} diff --git a/drivers/pcmcia/sa1100_stork.c b/drivers/pcmcia/sa1100_stork.c index 3ca0ea808de7..c172acce8305 100644 --- a/drivers/pcmcia/sa1100_stork.c +++ b/drivers/pcmcia/sa1100_stork.c @@ -18,8 +18,6 @@ * PCMCIA implementation routines for stork * */ - -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> @@ -28,50 +26,58 @@ #include <asm/hardware.h> #include <asm/irq.h> -#include <asm/arch/pcmcia.h> +#include "sa1100_generic.h" static int debug = 0; -static struct pcmcia_init sa1100_stork_pcmcia_init; +static struct irqs { + int irq; + const char *str; +} irqs[] = { + { IRQ_GPIO_STORK_PCMCIA_A_CARD_DETECT, "PCMCIA_CD0" }, + { IRQ_GPIO_STORK_PCMCIA_B_CARD_DETECT, "PCMCIA_CD1" }, +}; static int stork_pcmcia_init(struct pcmcia_init *init) { - int irq, res; - printk("in stork_pcmcia_init\n"); - - sa1100_stork_pcmcia_init = *init; - - /* Enable CF bus: */ - storkSetLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON); + int irq, res; - /* All those are inputs */ - GPDR &= ~(GPIO_STORK_PCMCIA_A_CARD_DETECT | GPIO_STORK_PCMCIA_B_CARD_DETECT | GPIO_STORK_PCMCIA_A_RDY| GPIO_STORK_PCMCIA_B_RDY); + printk("in stork_pcmcia_init\n"); /* Set transition detect */ - set_GPIO_IRQ_edge( GPIO_STORK_PCMCIA_A_CARD_DETECT | GPIO_STORK_PCMCIA_B_CARD_DETECT, GPIO_BOTH_EDGES ); - set_GPIO_IRQ_edge( GPIO_STORK_PCMCIA_A_RDY| GPIO_STORK_PCMCIA_B_RDY, GPIO_FALLING_EDGE ); + set_irq_type(IRQ_GPIO_STORK_PCMCIA_A_RDY, IRQT_FALLING); + set_irq_type(IRQ_GPIO_STORK_PCMCIA_B_RDY, IRQT_FALLING); /* Register interrupts */ - irq = IRQ_GPIO_STORK_PCMCIA_A_CARD_DETECT; - res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD0", NULL ); - if( res < 0 ) goto irq_err; - irq = IRQ_GPIO_STORK_PCMCIA_B_CARD_DETECT; - res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD1", NULL ); - if( res < 0 ) goto irq_err; + for (i = 0; i < ARRAY_SIZE(irqs); i++) { + set_irq_type(irqs[i].irq, IRQT_NOEDGE); + res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT, + irqs[i].str, NULL); + if (res) + goto irq_err; + } return 2; irq_err: - printk( KERN_ERR __FUNCTION__ ": Request for IRQ %u failed\n", irq ); - return -1; + printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n", + __FUNCTION__, irq, res); + + while (i--) + free_irq(irqs[i].irq, NULL); + + return res; } static int stork_pcmcia_shutdown(void) { + int i; + printk(__FUNCTION__ "\n"); + /* disable IRQs */ - free_irq( IRQ_GPIO_STORK_PCMCIA_A_CARD_DETECT, NULL ); - free_irq( IRQ_GPIO_STORK_PCMCIA_B_CARD_DETECT, NULL ); + for (i = 0; i < ARRAY_SIZE(irqs); i++) + free_irq(irqs[i].irq, NULL); /* Disable CF bus: */ storkClearLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON); @@ -140,7 +146,7 @@ static int stork_pcmcia_configure_socket(const struct pcmcia_configure *configur printk(__FUNCTION__ ": socket=%d vcc=%d vpp=%d reset=%d\n", card, configure->vcc, configure->vpp, configure->reset); - save_flags_cli(flags); + local_irq_save(flags); if (card == 0) { DETECT = GPIO_STORK_PCMCIA_A_CARD_DETECT; @@ -174,7 +180,7 @@ static int stork_pcmcia_configure_socket(const struct pcmcia_configure *configur default: printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, configure->vcc); - restore_flags(flags); + local_irq_restore(flags); return -1; } @@ -183,7 +189,7 @@ static int stork_pcmcia_configure_socket(const struct pcmcia_configure *configur else storkClearLatchB(RESET); - restore_flags(flags); + local_irq_restore(flags); /* silently ignore vpp and speaker enables. */ @@ -192,11 +198,57 @@ static int stork_pcmcia_configure_socket(const struct pcmcia_configure *configur return 0; } -struct pcmcia_low_level stork_pcmcia_ops = { - stork_pcmcia_init, - stork_pcmcia_shutdown, - stork_pcmcia_socket_state, - stork_pcmcia_get_irq_info, - stork_pcmcia_configure_socket +static int stork_pcmcia_socket_init(int sock) +{ + storkSetLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON); + + if (sock == 0) + set_irq_type(IRQ_GPIO_STORK_PCMCIA_A_CARD_DETECT, IRQT_BOTHEDGE); + else if (sock == 1) + set_irq_type(IRQ_GPIO_STORK_PCMCIA_B_CARD_DETECT, IRQT_BOTHEDGE); + + return 0; +} + +static int stork_pcmcia_socket_suspend(int sock) +{ + if (sock == 0) + set_irq_type(IRQ_GPIO_STORK_PCMCIA_A_CARD_DETECT, IRQT_NOEDGE); + else if (sock == 1) { + set_irq_type(IRQ_GPIO_STORK_PCMCIA_B_CARD_DETECT, IRQT_NOEDGE); + + /* + * Hack! + */ + storkClearLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON); + } + + return 0; +} + +static struct pcmcia_low_level stork_pcmcia_ops = { + init: stork_pcmcia_init, + shutdown: stork_pcmcia_shutdown, + socket_state: stork_pcmcia_socket_state, + get_irq_info: stork_pcmcia_get_irq_info, + configure_socket: stork_pcmcia_configure_socket, + + socket_init: stork_pcmcia_socket_init, + socket_suspend: stork_pcmcia_socket_suspend, }; +int __init pcmcia_stork_init(void) +{ + int ret = -ENODEV; + + if (machine_is_stork()) + ret = sa1100_register_pcmcia(&stork_pcmcia_ops); + + return ret; +} + +void __exit pcmcia_stork_exit(void) +{ + sa1100_unregister_pcmcia(&stork_pcmcia_ops); +} + diff --git a/drivers/pcmcia/sa1100_system3.c b/drivers/pcmcia/sa1100_system3.c new file mode 100644 index 000000000000..fc4bed07c4a3 --- /dev/null +++ b/drivers/pcmcia/sa1100_system3.c @@ -0,0 +1,131 @@ +/* + * drivers/pcmcia/sa1100_system3.c + * + * PT Diagital Board PCMCIA specific routines + * + * Copyright (C) 2001 Stefan Eletzhofer <stefan.eletzhofer@eletztrick.de> + * + * $Id: sa1100_system3.c,v 1.1.4.2 2002/02/25 13:56:45 seletz Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * $Log: sa1100_system3.c,v $ + * Revision 1.1.4.2 2002/02/25 13:56:45 seletz + * - more cleanups + * - setup interrupts for CF card only ATM + * + * Revision 1.1.4.1 2002/02/14 02:23:27 seletz + * - 2.5.2-rmk6 PCMCIA changes + * + * Revision 1.1.2.1 2002/02/13 23:49:33 seletz + * - added from 2.4.16-rmk2 + * - cleanups + * + * + */ +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/ioport.h> + +#include <asm/hardware.h> +#include <asm/irq.h> +#include <asm/hardware/sa1111.h> + +#include "sa1100_generic.h" +#include "sa1111_generic.h" + +#define DEBUG 0 + +#ifdef DEBUG +# define DPRINTK( x, args... ) printk( "%s: line %d: "x, __FUNCTION__, __LINE__, ## args ); +#else +# define DPRINTK( x, args... ) /* nix */ +#endif + +int system3_pcmcia_init(struct pcmcia_init *init) +{ + /* Don't need no CD and BVD* interrupts */ + return 2; +} + +int system3_pcmcia_shutdown(void) +{ + return 0; +} + +int system3_pcmcia_configure_socket(const struct pcmcia_configure *conf) +{ + if (!conf) + return -1; + + /* only CF ATM */ + if (conf->sock == 0) + return -1; + + return sa1111_pcmcia_configure_socket( conf ); +} + +static int system3_pcmcia_socket_state(struct pcmcia_state_array + *state) +{ + unsigned long status = 0; + + if(state->size<2) return -1; + + memset(state->state, 0, + (state->size)*sizeof(struct pcmcia_state)); + + status=PCSR; + +#if 0 /* PCMCIA socket not yet connected */ + state->state[0].detect = status & PCSR_S0_DETECT ? 0 : 1; + state->state[0].ready = status & PCSR_S0_READY ? 1 : 0; + state->state[0].bvd1 = status & PCSR_S0_BVD1 ? 1 : 0; + state->state[0].bvd2 = 1; + state->state[0].wrprot = status & PCSR_S0_WP ? 1 : 0; + state->state[0].vs_3v = 1; + state->state[0].vs_Xv = 0; +#endif + + state->state[1].detect = status & PCSR_S1_DETECT ? 0 : 1; + state->state[1].ready = status & PCSR_S1_READY ? 1 : 0; + state->state[1].bvd1 = status & PCSR_S1_BVD1 ? 1 : 0; + state->state[1].bvd2 = 1; + state->state[1].wrprot = status & PCSR_S1_WP ? 1 : 0; + state->state[1].vs_3v = 1; + state->state[1].vs_Xv = 0; + + DPRINTK( "PCSR=0x%08lx, S1_RDY_nIREQ=%d\n", status, + state->state[1].ready ); + + return 1; +} + +struct pcmcia_low_level system3_pcmcia_ops = { + init: system3_pcmcia_init, + shutdown: system3_pcmcia_shutdown, + socket_state: system3_pcmcia_socket_state, + get_irq_info: sa1111_pcmcia_get_irq_info, + configure_socket: system3_pcmcia_configure_socket, + + socket_init: sa1111_pcmcia_socket_init, + socket_suspend: sa1111_pcmcia_socket_suspend, +}; + +int __init pcmcia_system3_init(void) +{ + int ret = -ENODEV; + + if (machine_is_pt_system3()) + ret = sa1100_register_pcmcia(&system3_pcmcia_ops); + + return ret; +} + +void __exit pcmcia_system3_exit(void) +{ + sa1100_unregister_pcmcia(&system3_pcmcia_ops); +} diff --git a/drivers/pcmcia/sa1100_xp860.c b/drivers/pcmcia/sa1100_xp860.c index cd92680dbe4e..84c315a97cdd 100644 --- a/drivers/pcmcia/sa1100_xp860.c +++ b/drivers/pcmcia/sa1100_xp860.c @@ -7,128 +7,46 @@ #include <linux/kernel.h> #include <linux/delay.h> #include <linux/sched.h> +#include <linux/init.h> #include <asm/hardware.h> #include <asm/irq.h> -#include <asm/arch/pcmcia.h> +#include "sa1100_generic.h" #define NCR_A0VPP (1<<16) #define NCR_A1VPP (1<<17) -static int xp860_pcmcia_init(struct pcmcia_init *init){ - int return_val=0; - +static int xp860_pcmcia_init(struct pcmcia_init *init) +{ /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */ PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); /* MAX1600 to standby mode: */ PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); + +#error Consider the following comment + /* + * 1- Please move GPDR initialisation where it is interrupt or preemption + * safe (like from xp860_map_io). + * 2- The GPCR line is bogus i.e. it will simply have absolutely no effect. + * Please see its definition in the SA1110 manual. + * 3- Please do not use NCR_* values! + */ GPDR |= (NCR_A0VPP | NCR_A1VPP); GPCR &= ~(NCR_A0VPP | NCR_A1VPP); - INTPOL1 |= - (1 << (S0_READY_NINT - SA1111_IRQ(32))) | - (1 << (S1_READY_NINT - SA1111_IRQ(32))) | - (1 << (S0_CD_VALID - SA1111_IRQ(32))) | - (1 << (S1_CD_VALID - SA1111_IRQ(32))) | - (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) | - (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))); - - return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT, - "XP860 PCMCIA (0) CD", NULL); - return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT, - "XP860 CF (1) CD", NULL); - return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT, - "XP860 PCMCIA (0) BVD1", NULL); - return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT, - "XP860 CF (1) BVD1", NULL); - - return (return_val<0) ? -1 : 2; -} - -static int xp860_pcmcia_shutdown(void){ - - free_irq(S0_CD_VALID, NULL); - free_irq(S1_CD_VALID, NULL); - free_irq(S0_BVD1_STSCHG, NULL); - free_irq(S1_BVD1_STSCHG, NULL); - - INTPOL1 &= - ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) | - (1 << (S1_CD_VALID - SA1111_IRQ(32))) | - (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) | - (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)))); - - return 0; -} - -static int xp860_pcmcia_socket_state(struct pcmcia_state_array - *state_array){ - unsigned long status; - int return_val=1; - - if(state_array->size<2) return -1; - - memset(state_array->state, 0, - (state_array->size)*sizeof(struct pcmcia_state)); - - status=PCSR; - - state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0; - - state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1; - - state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1; - - state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1; - - state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1; - - state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0; - - state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0; - - state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0; - - state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1; - - state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1; - - state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1; - - state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1; - - state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0; - - state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0; - - return return_val; + return sa1111_pcmcia_init(init); } -static int xp860_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ - - switch(info->sock){ - case 0: - info->irq=S0_READY_NINT; - break; - - case 1: - info->irq=S1_READY_NINT; - break; - - default: - return -1; - } - - return 0; -} - -static int xp860_pcmcia_configure_socket(const struct pcmcia_configure - *configure){ - unsigned long pccr=PCCR, ncr=GPLR, gpio=PA_DWR; - +static int +xp860_pcmcia_configure_socket(const struct pcmcia_configure *conf) +{ + unsigned int gpio_mask, pa_dwr_mask; + unsigned int gpio_set, pa_dwr_set; + int ret; /* Neponset uses the Maxim MAX1600, with the following connections: +#warning ^^^ This isn't a neponset! * * MAX1600 Neponset * @@ -151,105 +69,90 @@ static int xp860_pcmcia_configure_socket(const struct pcmcia_configure * the corresponding truth table. */ - switch(configure->sock){ + switch (conf->sock) { case 0: - - switch(configure->vcc){ - case 0: - gpio&=~(GPIO_GPIO0 | GPIO_GPIO1); - break; - - case 33: - pccr=(pccr & ~PCCR_S0_PSE); - gpio=(gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO1; - break; - - case 50: - pccr=(pccr | PCCR_S0_PSE); - gpio=(gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO0; - break; + pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1; + gpio_mask = NCR_A0VPP | NCR_A1VPP; + switch (conf->vcc) { default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; + case 0: pa_dwr_set = 0; break; + case 33: pa_dwr_set = GPIO_GPIO1; break; + case 50: pa_dwr_set = GPIO_GPIO0; break; } - switch(configure->vpp){ - case 0: - ncr&=~(NCR_A0VPP | NCR_A1VPP); - break; - - case 120: - ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A1VPP; - break; + switch (conf->vpp) { + case 0: gpio_set = 0; break; + case 120: gpio_set = NCR_A1VPP; break; default: - if(configure->vpp == configure->vcc) - ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A0VPP; + if (conf->vpp == conf->vcc) + gpio_set = NCR_A0VPP; else { - printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__, - configure->vpp); + printk(KERN_ERR "%s(): unrecognized Vpp %u\n", + __FUNCTION__, conf->vpp); return -1; } } - - pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST); - pccr=(configure->output)?(pccr | PCCR_S0_FLT):(pccr & ~PCCR_S0_FLT); - break; case 1: - switch(configure->vcc){ - case 0: - gpio&=~(GPIO_GPIO2 | GPIO_GPIO3); - break; - - case 33: - pccr=(pccr & ~PCCR_S1_PSE); - gpio=(gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO2; - break; - - case 50: - pccr=(pccr | PCCR_S1_PSE); - gpio=(gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO3; - break; + pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3; + gpio_mask = 0; + gpio_set = 0; + switch (conf->vcc) { default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; + case 0: pa_dwr_set = 0; break; + case 33: pa_dwr_set = GPIO_GPIO2; break; + case 50: pa_dwr_set = GPIO_GPIO3; break; } - if(configure->vpp!=configure->vcc && configure->vpp!=0){ - printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__, - configure->vpp); + if (conf->vpp != conf->vcc && conf->vpp != 0) { + printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", + __FUNCTION__, conf->vpp); return -1; } - - pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST); - pccr=(configure->output)?(pccr | PCCR_S1_FLT):(pccr & ~PCCR_S1_FLT); - break; - - default: - return -1; } - PCCR = pccr; - ncr &= NCR_A0VPP|NCR_A1VPP; - GPSR = ncr; - GPCR = (~ncr)&(NCR_A0VPP|NCR_A1VPP); - PA_DWR = gpio; + ret = sa1111_pcmcia_configure_socket(conf); + if (ret == 0) { + unsigned long flags; + + local_irq_save(flags); + PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set; + GPSR = gpio_set; + GPCR = gpio_set ^ gpio_mask; + local_irq_restore(flags); + } - return 0; + return ret; } -struct pcmcia_low_level xp860_pcmcia_ops = { - xp860_pcmcia_init, - xp860_pcmcia_shutdown, - xp860_pcmcia_socket_state, - xp860_pcmcia_get_irq_info, - xp860_pcmcia_configure_socket +static struct pcmcia_low_level xp860_pcmcia_ops = { + init: xp860_pcmcia_init, + shutdown: sa1111_pcmcia_shutdown, + socket_state: sa1111_pcmcia_socket_state, + get_irq_info: sa1111_pcmcia_get_irq_info, + configure_socket: xp860_pcmcia_configure_socket, + + socket_init: sa1111_pcmcia_socket_init, + socket_suspend: sa1111_pcmcia_socket_suspend, }; +int __init pcmcia_xp860_init(void) +{ + int ret = -ENODEV; + + if (machine_is_xp860()) + ret = sa1100_register_pcmcia(&xp860_pcmcia_ops); + + return ret; +} + +void __exit pcmcia_xp860_exit(void) +{ + sa1100_unregister_pcmcia(&xp860_pcmcia_ops); +} + diff --git a/drivers/pcmcia/sa1100_yopy.c b/drivers/pcmcia/sa1100_yopy.c index 25d502d3d2c1..4bdb837cd6f1 100644 --- a/drivers/pcmcia/sa1100_yopy.c +++ b/drivers/pcmcia/sa1100_yopy.c @@ -6,10 +6,11 @@ */ #include <linux/kernel.h> #include <linux/sched.h> +#include <linux/init.h> #include <asm/hardware.h> #include <asm/irq.h> -#include <asm/arch/pcmcia.h> +#include "sa1100_generic.h" static inline void pcmcia_power(int on) { @@ -23,45 +24,53 @@ static inline void pcmcia_reset(int reset) yopy_gpio_set(GPIO_CF_RESET, reset); } +static struct irqs { + int irq; + const char *str; +} irqs[] = { + { IRQ_CF_CD, "CF_CD" }, + { IRQ_CF_BVD2, "CF_BVD2" }, + { IRQ_CF_BVD1, "CF_BVD1" }, +}; + static int yopy_pcmcia_init(struct pcmcia_init *init) { - int irq, res; + int i, res; pcmcia_power(0); pcmcia_reset(1); - /* All those are inputs */ - GPDR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IREQ); - GAFR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IREQ); - /* Set transition detect */ - set_GPIO_IRQ_edge( GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1, - GPIO_BOTH_EDGES ); - set_GPIO_IRQ_edge( GPIO_CF_IREQ, GPIO_FALLING_EDGE ); + set_irq_type(IRQ_CF_IREQ, IRQT_FALLING); /* Register interrupts */ - irq = IRQ_CF_CD; - res = request_irq(irq, init->handler, SA_INTERRUPT, "CF_CD", NULL); - if (res < 0) goto irq_err; - irq = IRQ_CF_BVD2; - res = request_irq(irq, init->handler, SA_INTERRUPT, "CF_BVD2", NULL); - if (res < 0) goto irq_err; - irq = IRQ_CF_BVD1; - res = request_irq(irq, init->handler, SA_INTERRUPT, "CF_BVD1", NULL); - if (res < 0) goto irq_err; + for (i = 0; i < ARRAY_SIZE(irqs); i++) { + set_irq_type(irqs[i].irq, IRQT_NOEDGE); + res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT, + irqs[i].str, NULL); + if (res) + goto irq_err; + } return 1; -irq_err: - printk(KERN_ERR "%s: Request for IRQ %d failed\n", __FUNCTION__, irq); - return -1; + + irq_err: + printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n", + __FUNCTION__, irqs[i].irq, res); + + while (i--) + free_irq(irqs[i].irq, NULL); + + return res; } static int yopy_pcmcia_shutdown(void) { + int i; + /* disable IRQs */ - free_irq( IRQ_CF_CD, NULL ); - free_irq( IRQ_CF_BVD2, NULL ); - free_irq( IRQ_CF_BVD1, NULL ); + for (i = 0; i < ARRAY_SIZE(irqs); i++) + free_irq(irqs[i].irq, NULL); /* Disable CF */ pcmcia_reset(1); @@ -109,7 +118,7 @@ static int yopy_pcmcia_configure_socket(const struct pcmcia_configure *configure return -1; switch (configure->vcc) { - case 0: /* power off */; + case 0: /* power off */ pcmcia_power(0); break; case 50: @@ -130,10 +139,49 @@ static int yopy_pcmcia_configure_socket(const struct pcmcia_configure *configure return 0; } -struct pcmcia_low_level yopy_pcmcia_ops = { - yopy_pcmcia_init, - yopy_pcmcia_shutdown, - yopy_pcmcia_socket_state, - yopy_pcmcia_get_irq_info, - yopy_pcmcia_configure_socket +static int yopy_pcmcia_socket_init(int sock) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(irqs); i++) + set_irq_type(irqs[i].irq, IRQT_BOTHEDGE); + + return 0; +} + +static int yopy_pcmcia_socket_suspend(int sock) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(irqs); i++) + set_irq_type(irqs[i].irq, IRQT_NOEDGE); + + return 0; +} + +static struct pcmcia_low_level yopy_pcmcia_ops = { + init: yopy_pcmcia_init, + shutdown: yopy_pcmcia_shutdown, + socket_state: yopy_pcmcia_socket_state, + get_irq_info: yopy_pcmcia_get_irq_info, + configure_socket: yopy_pcmcia_configure_socket, + + socket_init: yopy_pcmcia_socket_init, + socket_suspend: yopy_pcmcia_socket_suspend, }; + +int __init pcmcia_yopy_init(void) +{ + int ret = -ENODEV; + + if (machine_is_yopy()) + ret = sa1100_register_pcmcia(&yopy_pcmcia_ops); + + return ret; +} + +void __exit pcmcia_yopy_exit(void) +{ + sa1100_unregister_pcmcia(&yopy_pcmcia_ops); +} + diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c new file mode 100644 index 000000000000..bd2b7fb28afd --- /dev/null +++ b/drivers/pcmcia/sa1111_generic.c @@ -0,0 +1,180 @@ +/* + * linux/drivers/pcmcia/sa1100_sa1111.c + * + * We implement the generic parts of a SA1111 PCMCIA driver. This + * basically means we handle everything except controlling the + * power. Power is machine specific... + */ +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/ioport.h> + +#include <asm/hardware.h> +#include <asm/hardware/sa1111.h> +#include <asm/irq.h> + +#include "sa1100_generic.h" +#include "sa1111_generic.h" + +static struct irqs { + int irq; + const char *str; +} irqs[] = { + { S0_CD_VALID, "SA1111 PCMCIA card detect" }, + { S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1" }, + { S1_CD_VALID, "SA1111 CF card detect" }, + { S1_BVD1_STSCHG, "SA1111 CF BVD1" }, +}; + +int sa1111_pcmcia_init(struct pcmcia_init *init) +{ + int i, ret; + + if (!request_mem_region(_PCCR, 512, "PCMCIA")) + return -1; + + for (i = ret = 0; i < ARRAY_SIZE(irqs); i++) { + set_irq_type(irqs[i].irq, IRQT_FALLING); + ret = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT, + irqs[i].str, NULL); + if (ret) + break; + } + + if (i < ARRAY_SIZE(irqs)) { + printk(KERN_ERR "sa1111_pcmcia: unable to grab IRQ%d (%d)\n", + irqs[i].irq, ret); + while (i--) + free_irq(irqs[i].irq, NULL); + + release_mem_region(_PCCR, 16); + } + + return ret ? -1 : 2; +} + +int sa1111_pcmcia_shutdown(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(irqs); i++) + free_irq(irqs[i].irq, NULL); + + release_mem_region(_PCCR, 512); + + return 0; +} + +int sa1111_pcmcia_socket_state(struct pcmcia_state_array *state) +{ + unsigned long status; + + if (state->size < 2) + return -1; + + status = PCSR; + + state->state[0].detect = status & PCSR_S0_DETECT ? 0 : 1; + state->state[0].ready = status & PCSR_S0_READY ? 1 : 0; + state->state[0].bvd1 = status & PCSR_S0_BVD1 ? 1 : 0; + state->state[0].bvd2 = status & PCSR_S0_BVD2 ? 1 : 0; + state->state[0].wrprot = status & PCSR_S0_WP ? 1 : 0; + state->state[0].vs_3v = status & PCSR_S0_VS1 ? 0 : 1; + state->state[0].vs_Xv = status & PCSR_S0_VS2 ? 0 : 1; + + state->state[1].detect = status & PCSR_S1_DETECT ? 0 : 1; + state->state[1].ready = status & PCSR_S1_READY ? 1 : 0; + state->state[1].bvd1 = status & PCSR_S1_BVD1 ? 1 : 0; + state->state[1].bvd2 = status & PCSR_S1_BVD2 ? 1 : 0; + state->state[1].wrprot = status & PCSR_S1_WP ? 1 : 0; + state->state[1].vs_3v = status & PCSR_S1_VS1 ? 0 : 1; + state->state[1].vs_Xv = status & PCSR_S1_VS2 ? 0 : 1; + + return 1; +} + +int sa1111_pcmcia_get_irq_info(struct pcmcia_irq_info *info) +{ + int ret = 0; + + switch (info->sock) { + case 0: info->irq = S0_READY_NINT; break; + case 1: info->irq = S1_READY_NINT; break; + default: ret = 1; + } + + return ret; +} + +int sa1111_pcmcia_configure_socket(const struct pcmcia_configure *conf) +{ + unsigned int rst, flt, wait, pse, irq, pccr_mask; + unsigned long flags; + + switch (conf->sock) { + case 0: + rst = PCCR_S0_RST; + flt = PCCR_S0_FLT; + wait = PCCR_S0_PWAITEN; + pse = PCCR_S0_PSE; + irq = S0_READY_NINT; + break; + + case 1: + rst = PCCR_S1_RST; + flt = PCCR_S1_FLT; + wait = PCCR_S1_PWAITEN; + pse = PCCR_S1_PSE; + irq = S1_READY_NINT; + break; + + default: + return -1; + } + + switch (conf->vcc) { + case 0: + pccr_mask = 0; + break; + + case 33: + pccr_mask = wait; + break; + + case 50: + pccr_mask = pse | wait; + break; + + default: + printk(KERN_ERR "sa1111_pcmcia: unrecognised VCC %u\n", + conf->vcc); + return -1; + } + + if (conf->reset) + pccr_mask |= rst; + + if (conf->output) + pccr_mask |= flt; + + local_irq_save(flags); + PCCR = (PCCR & ~(pse | flt | wait | rst)) | pccr_mask; + local_irq_restore(flags); + + if (conf->irq) + enable_irq(irq); + else + disable_irq(irq); + + return 0; +} + +int sa1111_pcmcia_socket_init(int sock) +{ + return 0; +} + +int sa1111_pcmcia_socket_suspend(int sock) +{ + return 0; +} diff --git a/drivers/pcmcia/sa1111_generic.h b/drivers/pcmcia/sa1111_generic.h new file mode 100644 index 000000000000..90e4e28dbd20 --- /dev/null +++ b/drivers/pcmcia/sa1111_generic.h @@ -0,0 +1,7 @@ +extern int sa1111_pcmcia_init(struct pcmcia_init *); +extern int sa1111_pcmcia_shutdown(void); +extern int sa1111_pcmcia_socket_state(struct pcmcia_state_array *); +extern int sa1111_pcmcia_get_irq_info(struct pcmcia_irq_info *); +extern int sa1111_pcmcia_configure_socket(const struct pcmcia_configure *); +extern int sa1111_pcmcia_socket_init(int); +extern int sa1111_pcmcia_socket_suspend(int); diff --git a/fs/partitions/Config.in b/fs/partitions/Config.in index faaee4ed11d6..83b3a60a65db 100644 --- a/fs/partitions/Config.in +++ b/fs/partitions/Config.in @@ -38,7 +38,7 @@ else fi if [ "$CONFIG_AMIGA" != "y" -a "$CONFIG_ATARI" != "y" -a \ "$CONFIG_MAC" != "y" -a "$CONFIG_SGI_IP22" != "y" -a \ - "$CONFIG_SGI_IP27" != "y" ]; then + "$CONFIG_ARM" != "y" -a "$CONFIG_SGI_IP27" != "y" ]; then define_bool CONFIG_MSDOS_PARTITION y fi if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_AFFS_FS" = "y" ]; then diff --git a/include/asm-arm/arch-sa1100/graphicsclient.h b/include/asm-arm/arch-sa1100/graphicsclient.h index 794cbfe675bd..024e38709f1b 100644 --- a/include/asm-arm/arch-sa1100/graphicsclient.h +++ b/include/asm-arm/arch-sa1100/graphicsclient.h @@ -76,15 +76,6 @@ #define IRQ_GC_UART1_CTS IRQ_GPIO16 #define IRQ_GC_UART2_CTS IRQ_GPIO17 -#ifndef __ASSEMBLY__ -struct gc_uart_ctrl_data_t { - int cts_gpio; - int cts_prev_state; - struct uart_info *info; - struct uart_port *port; -}; -#endif /* __ASSEMBLY__ */ - /* LEDs */ #define ADS_LED0 GPIO_GPIO20 /* on-board D22 */ diff --git a/include/asm-arm/arch-sa1100/irqs.h b/include/asm-arm/arch-sa1100/irqs.h index 3105834da48c..d8caa5c836b4 100644 --- a/include/asm-arm/arch-sa1100/irqs.h +++ b/include/asm-arm/arch-sa1100/irqs.h @@ -151,4 +151,5 @@ #define IRQ_NEPONSET_SA1111 (IRQ_BOARD_START + 2) /* PT Digital Board Interrupts (CONFIG_SA1100_PT_SYSTEM3) */ -#define IRQ_SYSTEM3_SMC9196 (IRQ_BOARD_START + 0) +#define IRQ_SYSTEM3_SA1111 (IRQ_BOARD_START + 0) +#define IRQ_SYSTEM3_SMC9196 (IRQ_BOARD_START + 1) diff --git a/include/asm-arm/arch-sa1100/system3.h b/include/asm-arm/arch-sa1100/system3.h index 11d24a5c1dfa..b83a41e0c88f 100644 --- a/include/asm-arm/arch-sa1100/system3.h +++ b/include/asm-arm/arch-sa1100/system3.h @@ -67,17 +67,17 @@ /* System ID register */ /* IRQ Source Register */ -#define PT_IRQ_LAN ( 1<<0 ) -#define PT_IRQ_X ( 1<<1 ) -#define PT_IRQ_SA1111 ( 1<<2 ) -#define PT_IRQ_RS1 ( 1<<3 ) -#define PT_IRQ_RS1_RING ( 1<<4 ) -#define PT_IRQ_RS1_DCD ( 1<<5 ) -#define PT_IRQ_RS1_DSR ( 1<<6 ) -#define PT_IRQ_RS2 ( 1<<7 ) +#define PT_IRR_LAN ( 1<<0 ) +#define PT_IRR_X ( 1<<1 ) +#define PT_IRR_SA1111 ( 1<<2 ) +#define PT_IRR_RS1 ( 1<<3 ) +#define PT_IRR_RS1_RING ( 1<<4 ) +#define PT_IRR_RS1_DCD ( 1<<5 ) +#define PT_IRR_RS1_DSR ( 1<<6 ) +#define PT_IRR_RS2 ( 1<<7 ) /* FIXME */ -#define PT_IRQ_USAR ( 1<<1 ) +#define PT_IRR_USAR ( 1<<1 ) /* CTRL 0 */ #define PT_CTRL0_USBSLAVE ( 1<<0 ) diff --git a/include/asm-arm/pgalloc.h b/include/asm-arm/pgalloc.h index 3e154ed38f7f..0945e2e4d280 100644 --- a/include/asm-arm/pgalloc.h +++ b/include/asm-arm/pgalloc.h @@ -14,136 +14,20 @@ #include <asm/processor.h> -/* - * Get the cache handling stuff now. - */ #include <asm/proc/cache.h> - -/* - * ARM processors do not cache TLB tables in RAM. - */ -#define flush_tlb_pgtables(mm,start,end) do { } while (0) - -/* - * Processor specific parts... - */ #include <asm/proc/pgalloc.h> /* - * Page table cache stuff - */ -#ifndef CONFIG_NO_PGT_CACHE - -#ifdef CONFIG_SMP -#error Pgtable caches have to be per-CPU, so that no locking is needed. -#endif /* CONFIG_SMP */ - -extern struct pgtable_cache_struct { - unsigned long *pgd_cache; - unsigned long *pte_cache; - unsigned long pgtable_cache_sz; -} quicklists; - -#define pgd_quicklist (quicklists.pgd_cache) -#define pmd_quicklist ((unsigned long *)0) -#define pte_quicklist (quicklists.pte_cache) -#define pgtable_cache_size (quicklists.pgtable_cache_sz) - -/* used for quicklists */ -#define __pgd_next(pgd) (((unsigned long *)pgd)[1]) -#define __pte_next(pte) (((unsigned long *)pte)[0]) - -static inline pgd_t *get_pgd_fast(void) -{ - unsigned long *ret; - - preempt_disable(); - if ((ret = pgd_quicklist) != NULL) { - pgd_quicklist = (unsigned long *)__pgd_next(ret); - ret[1] = ret[2]; - clean_dcache_entry(ret + 1); - pgtable_cache_size--; - } - preempt_enable(); - return (pgd_t *)ret; -} - -static inline void free_pgd_fast(pgd_t *pgd) -{ - preempt_disable(); - __pgd_next(pgd) = (unsigned long) pgd_quicklist; - pgd_quicklist = (unsigned long *) pgd; - pgtable_cache_size++; - preempt_enable(); -} - -static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) -{ - unsigned long *ret; - - preempt_disable(); - if((ret = pte_quicklist) != NULL) { - pte_quicklist = (unsigned long *)__pte_next(ret); - ret[0] = 0; - clean_dcache_entry(ret); - pgtable_cache_size--; - } - preempt_enable(); - return (pte_t *)ret; -} - -static inline void free_pte_fast(pte_t *pte) -{ - preempt_disable(); - __pte_next(pte) = (unsigned long) pte_quicklist; - pte_quicklist = (unsigned long *) pte; - pgtable_cache_size++; - preempt_enable(); -} - -#else /* CONFIG_NO_PGT_CACHE */ - -#define pgd_quicklist ((unsigned long *)0) -#define pmd_quicklist ((unsigned long *)0) -#define pte_quicklist ((unsigned long *)0) - -#define get_pgd_fast() ((pgd_t *)0) -#define pte_alloc_one_fast(mm,addr) ((pte_t *)0) - -#define free_pgd_fast(pgd) free_pgd_slow(pgd) -#define free_pte_fast(pte) pte_free_slow(pte) - -#endif /* CONFIG_NO_PGT_CACHE */ - -#define pte_free(pte) free_pte_fast(pte) - - -/* * Since we have only two-level page tables, these are trivial */ -#define pmd_alloc_one_fast(mm,addr) ({ BUG(); ((pmd_t *)1); }) #define pmd_alloc_one(mm,addr) ({ BUG(); ((pmd_t *)2); }) -#define pmd_free_slow(pmd) do { } while (0) -#define pmd_free_fast(pmd) do { } while (0) #define pmd_free(pmd) do { } while (0) #define pgd_populate(mm,pmd,pte) BUG() extern pgd_t *get_pgd_slow(struct mm_struct *mm); extern void free_pgd_slow(pgd_t *pgd); -static inline pgd_t *pgd_alloc(struct mm_struct *mm) -{ - pgd_t *pgd; - - pgd = get_pgd_fast(); - if (!pgd) - pgd = get_pgd_slow(mm); - - return pgd; -} - -#define pgd_free(pgd) free_pgd_fast(pgd) - -extern int do_check_pgt_cache(int, int); +#define pgd_alloc(mm) get_pgd_slow(mm) +#define pgd_free(pgd) free_pgd_slow(pgd) #endif diff --git a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h index 1a19ac6a2f7f..4d468743909e 100644 --- a/include/asm-arm/pgtable.h +++ b/include/asm-arm/pgtable.h @@ -13,7 +13,6 @@ #include <linux/config.h> #include <asm/arch/memory.h> #include <asm/arch/vmalloc.h> -#include <asm/proc-fns.h> /* * PMD_SHIFT determines the size of the area a second-level page table can map @@ -146,8 +145,16 @@ static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot) #define pmd_offset(dir, addr) ((pmd_t *)(dir)) /* Find an entry in the third-level page table.. */ -#define __pte_offset(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) -#define pte_offset(dir, addr) ((pte_t *)pmd_page(*(dir)) + __pte_offset(addr)) +#define __pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) + +#define pmd_page(dir) ((struct page *)__pmd_page(dir)) + +#define __pte_offset(dir, addr) ((pte_t *)__pmd_page(*(dir)) + __pte_index(addr)) +#define pte_offset_kernel __pte_offset +#define pte_offset_map __pte_offset +#define pte_offset_map_nested __pte_offset +#define pte_unmap(pte) do { } while (0) +#define pte_unmap_nested(pte) do { } while (0) #include <asm/proc/pgtable.h> diff --git a/include/asm-arm/proc-armv/pgalloc.h b/include/asm-arm/proc-armv/pgalloc.h index f5db111e1e78..d1d35bf9650b 100644 --- a/include/asm-arm/proc-armv/pgalloc.h +++ b/include/asm-arm/proc-armv/pgalloc.h @@ -18,7 +18,8 @@ extern kmem_cache_t *pte_cache; * from the Linux copy. The processor copies are offset by -PTRS_PER_PTE * words from the Linux copy. */ -static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address) +static inline pte_t * +pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr) { pte_t *pte; @@ -28,10 +29,21 @@ static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address) return pte; } +static inline struct page * +pte_alloc_one(struct mm_struct *mm, unsigned long addr) +{ + pte_t *pte; + + pte = kmem_cache_alloc(pte_cache, GFP_KERNEL); + if (pte) + pte += PTRS_PER_PTE; + return (struct page *)pte; +} + /* * Free one PTE table. */ -static inline void pte_free_slow(pte_t *pte) +static inline void pte_free_kernel(pte_t *pte) { if (pte) { pte -= PTRS_PER_PTE; @@ -39,6 +51,15 @@ static inline void pte_free_slow(pte_t *pte) } } +static inline void pte_free(struct page *pte) +{ + pte_t *_pte = (pte_t *)pte; + if (pte) { + _pte -= PTRS_PER_PTE; + kmem_cache_free(pte_cache, _pte); + } +} + /* * Populate the pmdp entry with a pointer to the pte. This pmd is part * of the mm address space. @@ -46,12 +67,14 @@ static inline void pte_free_slow(pte_t *pte) * If 'mm' is the init tasks mm, then we are doing a vmalloc, and we * need to set stuff up correctly for it. */ +#define pmd_populate_kernel(mm,pmdp,pte) \ + do { \ + BUG_ON(mm != &init_mm); \ + set_pmd(pmdp, __mk_pmd(pte, _PAGE_KERNEL_TABLE));\ + } while (0) + #define pmd_populate(mm,pmdp,pte) \ do { \ - unsigned long __prot; \ - if (mm == &init_mm) \ - __prot = _PAGE_KERNEL_TABLE; \ - else \ - __prot = _PAGE_USER_TABLE; \ - set_pmd(pmdp, __mk_pmd(pte, __prot)); \ + BUG_ON(mm == &init_mm); \ + set_pmd(pmdp, __mk_pmd(pte, _PAGE_USER_TABLE)); \ } while (0) diff --git a/include/asm-arm/proc-armv/pgtable.h b/include/asm-arm/proc-armv/pgtable.h index d0da2c4a8d20..bdf9640ddd0b 100644 --- a/include/asm-arm/proc-armv/pgtable.h +++ b/include/asm-arm/proc-armv/pgtable.h @@ -125,7 +125,7 @@ static inline pmd_t __mk_pmd(pte_t *ptep, unsigned long prot) return pmd; } -static inline unsigned long pmd_page(pmd_t pmd) +static inline unsigned long __pmd_page(pmd_t pmd) { unsigned long ptr; |
