diff options
Diffstat (limited to 'drivers/pcmcia')
29 files changed, 1686 insertions, 360 deletions
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index ddc741e6ecb..309eb557f9a 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -146,7 +146,7 @@ config I82365 config TCIC tristate "Databook TCIC host bridge support" - depends on PCMCIA + depends on PCMCIA && ISA select PCCARD_NONSTATIC help Say Y here to include support for the Databook TCIC family of PCMCIA @@ -154,6 +154,16 @@ config TCIC "Bridge" is the name used for the hardware inside your computer that PCMCIA cards are plugged into. If unsure, say N. +config PCMCIA_M8XX + tristate "MPC8xx PCMCIA support" + depends on PCMCIA && PPC && 8xx + select PCCARD_NONSTATIC + help + Say Y here to include support for PowerPC 8xx series PCMCIA + controller. + + This driver is also available as a module called m8xx_pcmcia. + config HD64465_PCMCIA tristate "HD64465 host bridge support" depends on HD64465 && PCMCIA diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index a41fbb38fdc..bcecf5133b7 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_PD6729) += pd6729.o obj-$(CONFIG_I82365) += i82365.o obj-$(CONFIG_I82092) += i82092.o obj-$(CONFIG_TCIC) += tcic.o +obj-$(CONFIG_PCMCIA_M8XX) += m8xx_pcmcia.o obj-$(CONFIG_HD64465_PCMCIA) += hd64465_ss.o obj-$(CONFIG_PCMCIA_SA1100) += sa11xx_core.o sa1100_cs.o obj-$(CONFIG_PCMCIA_SA1111) += sa11xx_core.o sa1111_cs.o @@ -42,12 +43,14 @@ pxa2xx_core-y += soc_common.o pxa2xx_base.o au1x00_ss-y += au1000_generic.o au1x00_ss-$(CONFIG_MIPS_PB1000) += au1000_pb1x00.o au1x00_ss-$(CONFIG_MIPS_PB1100) += au1000_pb1x00.o +au1x00_ss-$(CONFIG_MIPS_PB1200) += au1000_db1x00.o au1x00_ss-$(CONFIG_MIPS_PB1500) += au1000_pb1x00.o au1x00_ss-$(CONFIG_MIPS_DB1000) += au1000_db1x00.o au1x00_ss-$(CONFIG_MIPS_DB1100) += au1000_db1x00.o +au1x00_ss-$(CONFIG_MIPS_DB1200) += au1000_db1x00.o au1x00_ss-$(CONFIG_MIPS_DB1500) += au1000_db1x00.o au1x00_ss-$(CONFIG_MIPS_DB1550) += au1000_db1x00.o -au1x00_ss-$(CONFIG_MIPS_XXS1500) += au1000_xxs1500.o +au1x00_ss-$(CONFIG_MIPS_XXS1500) += au1000_xxs1500.o sa1111_cs-y += sa1111_generic.o sa1111_cs-$(CONFIG_ASSABET_NEPONSET) += sa1100_neponset.o @@ -57,6 +60,7 @@ sa1111_cs-$(CONFIG_SA1100_JORNADA720) += sa1100_jornada720.o sa1100_cs-y += sa1100_generic.o sa1100_cs-$(CONFIG_SA1100_ASSABET) += sa1100_assabet.o sa1100_cs-$(CONFIG_SA1100_CERF) += sa1100_cerf.o +sa1100_cs-$(CONFIG_SA1100_COLLIE) += pxa2xx_sharpsl.o sa1100_cs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o sa1100_cs-$(CONFIG_SA1100_SHANNON) += sa1100_shannon.o sa1100_cs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o diff --git a/drivers/pcmcia/au1000_db1x00.c b/drivers/pcmcia/au1000_db1x00.c index 42cf8bfbcc9..abc13f28ba3 100644 --- a/drivers/pcmcia/au1000_db1x00.c +++ b/drivers/pcmcia/au1000_db1x00.c @@ -30,6 +30,7 @@ * */ +#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -40,7 +41,15 @@ #include <asm/irq.h> #include <asm/signal.h> #include <asm/mach-au1x00/au1000.h> -#include <asm/mach-db1x00/db1x00.h> + +#if defined(CONFIG_MIPS_DB1200) + #include <db1200.h> +#elif defined(CONFIG_MIPS_PB1200) + #include <pb1200.h> +#else + #include <asm/mach-db1x00/db1x00.h> + static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR; +#endif #include "au1000_generic.h" @@ -50,7 +59,6 @@ #define debug(x,args...) #endif -static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR; struct au1000_pcmcia_socket au1000_pcmcia_socket[PCMCIA_NUM_SOCKS]; extern int au1x00_pcmcia_socket_probe(struct device *, struct pcmcia_low_level *, int, int); @@ -59,6 +67,8 @@ static int db1x00_pcmcia_hw_init(struct au1000_pcmcia_socket *skt) { #ifdef CONFIG_MIPS_DB1550 skt->irq = skt->nr ? AU1000_GPIO_5 : AU1000_GPIO_3; +#elif defined(CONFIG_MIPS_DB1200) || defined(CONFIG_MIPS_PB1200) + skt->irq = skt->nr ? BOARD_PC1_INT : BOARD_PC0_INT; #else skt->irq = skt->nr ? AU1000_GPIO_5 : AU1000_GPIO_2; #endif @@ -85,11 +95,19 @@ db1x00_pcmcia_socket_state(struct au1000_pcmcia_socket *skt, struct pcmcia_state switch (skt->nr) { case 0: vs = bcsr->status & 0x3; +#if defined(CONFIG_MIPS_DB1200) || defined(CONFIG_MIPS_PB1200) + inserted = BOARD_CARD_INSERTED(0); +#else inserted = !(bcsr->status & (1<<4)); +#endif break; case 1: vs = (bcsr->status & 0xC)>>2; +#if defined(CONFIG_MIPS_DB1200) || defined(CONFIG_MIPS_PB1200) + inserted = BOARD_CARD_INSERTED(1); +#else inserted = !(bcsr->status & (1<<5)); +#endif break; default:/* should never happen */ return; diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c index 470ef756252..87302c548c2 100644 --- a/drivers/pcmcia/au1000_generic.c +++ b/drivers/pcmcia/au1000_generic.c @@ -42,7 +42,7 @@ #include <linux/notifier.h> #include <linux/interrupt.h> #include <linux/spinlock.h> -#include <linux/device.h> +#include <linux/platform_device.h> #include <asm/io.h> #include <asm/irq.h> @@ -490,7 +490,7 @@ int au1x00_drv_pcmcia_remove(struct device *dev) flush_scheduled_work(); skt->ops->hw_shutdown(skt); au1x00_pcmcia_config_skt(skt, &dead_socket); - iounmap(skt->virt_io); + iounmap(skt->virt_io + (u32)mips_io_port_base); skt->virt_io = NULL; } @@ -519,36 +519,15 @@ static int au1x00_drv_pcmcia_probe(struct device *dev) } -static int au1x00_drv_pcmcia_suspend(struct device *dev, pm_message_t state, u32 level) -{ - int ret = 0; - if (level == SUSPEND_SAVE_STATE) - ret = pcmcia_socket_dev_suspend(dev, state); - return ret; -} - -static int au1x00_drv_pcmcia_resume(struct device *dev, u32 level) -{ - int ret = 0; - if (level == RESUME_RESTORE_STATE) - ret = pcmcia_socket_dev_resume(dev); - return ret; -} - - static struct device_driver au1x00_pcmcia_driver = { .probe = au1x00_drv_pcmcia_probe, .remove = au1x00_drv_pcmcia_remove, .name = "au1x00-pcmcia", .bus = &platform_bus_type, - .suspend = au1x00_drv_pcmcia_suspend, - .resume = au1x00_drv_pcmcia_resume + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; -static struct platform_device au1x00_device = { - .name = "au1x00-pcmcia", - .id = 0, -}; /* au1x00_pcmcia_init() * @@ -562,7 +541,6 @@ static int __init au1x00_pcmcia_init(void) int error = 0; if ((error = driver_register(&au1x00_pcmcia_driver))) return error; - platform_device_register(&au1x00_device); return error; } @@ -573,7 +551,6 @@ static int __init au1x00_pcmcia_init(void) static void __exit au1x00_pcmcia_exit(void) { driver_unregister(&au1x00_pcmcia_driver); - platform_device_unregister(&au1x00_device); } module_init(au1x00_pcmcia_init); diff --git a/drivers/pcmcia/au1000_generic.h b/drivers/pcmcia/au1000_generic.h index d5122b1ea94..f2c970b5f4f 100644 --- a/drivers/pcmcia/au1000_generic.h +++ b/drivers/pcmcia/au1000_generic.h @@ -22,6 +22,8 @@ #define __ASM_AU1000_PCMCIA_H /* include the world */ +#include <linux/config.h> + #include <pcmcia/cs_types.h> #include <pcmcia/cs.h> #include <pcmcia/ss.h> @@ -44,13 +46,13 @@ /* pcmcia socket 1 needs external glue logic so the memory map * differs from board to board. */ -#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1550) +#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1550) || defined(CONFIG_MIPS_PB1200) #define AU1X_SOCK1_IO 0xF08000000 #define AU1X_SOCK1_PHYS_ATTR 0xF48000000 #define AU1X_SOCK1_PHYS_MEM 0xF88000000 #define AU1X_SOCK1_PSEUDO_PHYS_ATTR 0xF4800000 #define AU1X_SOCK1_PSEUDO_PHYS_MEM 0xF8800000 -#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) || defined(CONFIG_MIPS_DB1500) || defined(CONFIG_MIPS_DB1550) +#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) || defined(CONFIG_MIPS_DB1500) || defined(CONFIG_MIPS_DB1550) || defined(CONFIG_MIPS_DB1200) #define AU1X_SOCK1_IO 0xF04000000 #define AU1X_SOCK1_PHYS_ATTR 0xF44000000 #define AU1X_SOCK1_PHYS_MEM 0xF84000000 diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c index d414a3bb50b..fd5522ede86 100644 --- a/drivers/pcmcia/au1000_pb1x00.c +++ b/drivers/pcmcia/au1000_pb1x00.c @@ -21,6 +21,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. */ +#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/delay.h> @@ -30,7 +31,6 @@ #include <linux/timer.h> #include <linux/mm.h> #include <linux/proc_fs.h> -#include <linux/version.h> #include <linux/types.h> #include <pcmcia/cs_types.h> diff --git a/drivers/pcmcia/au1000_xxs1500.c b/drivers/pcmcia/au1000_xxs1500.c index f113b69d699..01874b0bb03 100644 --- a/drivers/pcmcia/au1000_xxs1500.c +++ b/drivers/pcmcia/au1000_xxs1500.c @@ -27,7 +27,6 @@ */ #include <linux/module.h> #include <linux/init.h> -#include <linux/config.h> #include <linux/delay.h> #include <linux/ioport.h> #include <linux/kernel.h> @@ -35,7 +34,6 @@ #include <linux/timer.h> #include <linux/mm.h> #include <linux/proc_fs.h> -#include <linux/version.h> #include <linux/types.h> #include <pcmcia/cs_types.h> diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c index 1d755e20880..3f6d51d1137 100644 --- a/drivers/pcmcia/cardbus.c +++ b/drivers/pcmcia/cardbus.c @@ -228,6 +228,11 @@ int cb_alloc(struct pcmcia_socket * s) pci_bus_size_bridges(bus); pci_bus_assign_resources(bus); cardbus_assign_irqs(bus, s->pci_irq); + + /* socket specific tune function */ + if (s->tune_bridge) + s->tune_bridge(s, bus); + pci_enable_bridges(bus); pci_bus_add_devices(bus); diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 3afb682255a..2dc3e611a9a 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -334,10 +334,8 @@ void destroy_cis_cache(struct pcmcia_socket *s) /* * If there was a fake CIS, destroy that as well. */ - if (s->fake_cis) { - kfree(s->fake_cis); - s->fake_cis = NULL; - } + kfree(s->fake_cis); + s->fake_cis = NULL; } EXPORT_SYMBOL(destroy_cis_cache); @@ -386,10 +384,8 @@ int verify_cis_cache(struct pcmcia_socket *s) int pcmcia_replace_cis(struct pcmcia_socket *s, cisdump_t *cis) { - if (s->fake_cis != NULL) { - kfree(s->fake_cis); - s->fake_cis = NULL; - } + kfree(s->fake_cis); + s->fake_cis = NULL; if (cis->Length > CISTPL_MAX_CIS_SIZE) return CS_BAD_SIZE; s->fake_cis = kmalloc(cis->Length, GFP_KERNEL); diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index fabd3529ceb..a30aa74304a 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -331,10 +331,8 @@ static void shutdown_socket(struct pcmcia_socket *s) cb_free(s); #endif s->functions = 0; - if (s->config) { - kfree(s->config); - s->config = NULL; - } + kfree(s->config); + s->config = NULL; { int status; @@ -515,6 +513,11 @@ static int socket_insert(struct pcmcia_socket *skt) ret = socket_setup(skt, setup_delay); if (ret == CS_SUCCESS) { skt->state |= SOCKET_PRESENT; + + printk(KERN_NOTICE "pccard: %s card inserted into slot %d\n", + (skt->state & SOCKET_CARDBUS) ? "CardBus" : "PCMCIA", + skt->sock); + #ifdef CONFIG_CARDBUS if (skt->state & SOCKET_CARDBUS) { cb_alloc(skt); @@ -600,6 +603,7 @@ static int socket_resume(struct pcmcia_socket *skt) static void socket_remove(struct pcmcia_socket *skt) { + printk(KERN_NOTICE "pccard: card ejected from slot %d\n", skt->sock); socket_shutdown(skt); cs_socket_put(skt); } @@ -689,6 +693,9 @@ static int pccardd(void *__skt) schedule(); try_to_freeze(); } + /* make sure we are running before we exit */ + set_current_state(TASK_RUNNING); + remove_wait_queue(&skt->thread_wait, &wait); /* remove from the device core */ diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 080608c7381..7f8219f3fd9 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -544,6 +544,9 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f list_add_tail(&p_dev->socket_device_list, &s->devices_list); spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); + printk(KERN_NOTICE "pcmcia: registering new device %s\n", + p_dev->devname); + pcmcia_device_query(p_dev); if (device_register(&p_dev->dev)) { @@ -1157,7 +1160,8 @@ static struct pcmcia_callback pcmcia_bus_callback = { .requery = pcmcia_bus_rescan, }; -static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev) +static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev, + struct class_interface *class_intf) { struct pcmcia_socket *socket = class_get_devdata(class_dev); int ret; @@ -1192,7 +1196,8 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev) return 0; } -static void pcmcia_bus_remove_socket(struct class_device *class_dev) +static void pcmcia_bus_remove_socket(struct class_device *class_dev, + struct class_interface *class_intf) { struct pcmcia_socket *socket = class_get_devdata(class_dev); diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c index 316f8bcc878..561706ba449 100644 --- a/drivers/pcmcia/hd64465_ss.c +++ b/drivers/pcmcia/hd64465_ss.c @@ -37,7 +37,7 @@ #include <asm/errno.h> #include <linux/irq.h> #include <linux/interrupt.h> -#include <linux/device.h> +#include <linux/platform_device.h> #include <asm/io.h> #include <asm/hd64465/hd64465.h> @@ -844,27 +844,11 @@ static void hs_exit_socket(hs_socket_t *sp) local_irq_restore(flags); } -static int hd64465_suspend(struct device *dev, pm_message_t state, u32 level) -{ - int ret = 0; - if (level == SUSPEND_SAVE_STATE) - ret = pcmcia_socket_dev_suspend(dev, state); - return ret; -} - -static int hd64465_resume(struct device *dev, u32 level) -{ - int ret = 0; - if (level == RESUME_RESTORE_STATE) - ret = pcmcia_socket_dev_resume(dev); - return ret; -} - static struct device_driver hd64465_driver = { .name = "hd64465-pcmcia", .bus = &platform_bus_type, - .suspend = hd64465_suspend, - .resume = hd64465_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; static struct platform_device hd64465_device = { diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index a713015e822..4d56bc9926d 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -47,7 +47,7 @@ #include <linux/delay.h> #include <linux/workqueue.h> #include <linux/interrupt.h> -#include <linux/device.h> +#include <linux/platform_device.h> #include <linux/bitops.h> #include <asm/irq.h> #include <asm/io.h> @@ -1332,33 +1332,14 @@ static struct pccard_operations pcic_operations = { /*====================================================================*/ -static int i82365_suspend(struct device *dev, pm_message_t state, u32 level) -{ - int ret = 0; - if (level == SUSPEND_SAVE_STATE) - ret = pcmcia_socket_dev_suspend(dev, state); - return ret; -} - -static int i82365_resume(struct device *dev, u32 level) -{ - int ret = 0; - if (level == RESUME_RESTORE_STATE) - ret = pcmcia_socket_dev_resume(dev); - return ret; -} - static struct device_driver i82365_driver = { .name = "i82365", .bus = &platform_bus_type, - .suspend = i82365_suspend, - .resume = i82365_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; -static struct platform_device i82365_device = { - .name = "i82365", - .id = 0, -}; +static struct platform_device *i82365_device; static int __init init_i82365(void) { @@ -1368,7 +1349,14 @@ static int __init init_i82365(void) if (ret) return ret; - ret = platform_device_register(&i82365_device); + i82365_device = platform_device_alloc("i82365", 0); + if (i82365_device) { + ret = platform_device_add(i82365_device); + if (ret) + platform_device_put(i82365_device); + } else + ret = -ENOMEM; + if (ret) { driver_unregister(&i82365_driver); return ret; @@ -1381,7 +1369,8 @@ static int __init init_i82365(void) if (sockets == 0) { printk("not found.\n"); - platform_device_unregister(&i82365_device); + platform_device_unregister(i82365_device); + release_region(i365_base, 2); driver_unregister(&i82365_driver); return -ENODEV; } @@ -1392,7 +1381,7 @@ static int __init init_i82365(void) /* register sockets with the pcmcia core */ for (i = 0; i < sockets; i++) { - socket[i].socket.dev.dev = &i82365_device.dev; + socket[i].socket.dev.dev = &i82365_device->dev; socket[i].socket.ops = &pcic_operations; socket[i].socket.resource_ops = &pccard_nonstatic_ops; socket[i].socket.owner = THIS_MODULE; @@ -1430,7 +1419,7 @@ static void __exit exit_i82365(void) if (socket[i].flags & IS_REGISTERED) pcmcia_unregister_socket(&socket[i].socket); } - platform_device_unregister(&i82365_device); + platform_device_unregister(i82365_device); if (poll_interval != 0) del_timer_sync(&poll_timer); if (grab_irq != 0) diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c index 65f3ee3d4d3..078579ae635 100644 --- a/drivers/pcmcia/m32r_cfc.c +++ b/drivers/pcmcia/m32r_cfc.c @@ -23,7 +23,7 @@ #include <linux/delay.h> #include <linux/workqueue.h> #include <linux/interrupt.h> -#include <linux/device.h> +#include <linux/platform_device.h> #include <linux/bitops.h> #include <asm/irq.h> #include <asm/io.h> @@ -355,9 +355,10 @@ static void add_pcc_socket(ulong base, int irq, ulong mapaddr, kio_addr_t ioaddr #ifndef CONFIG_PLAT_USRV /* insert interrupt */ request_irq(irq, pcc_interrupt, 0, "m32r_cfc", pcc_interrupt); +#ifndef CONFIG_PLAT_MAPPI3 /* eject interrupt */ request_irq(irq+1, pcc_interrupt, 0, "m32r_cfc", pcc_interrupt); - +#endif debug(3, "m32r_cfc: enable CFMSK, RDYSEL\n"); pcc_set(pcc_sockets, (unsigned int)PLD_CFIMASK, 0x01); #endif /* CONFIG_PLAT_USRV */ @@ -731,28 +732,11 @@ static struct pccard_operations pcc_operations = { /*====================================================================*/ -static int m32r_pcc_suspend(struct device *dev, pm_message_t state, u32 level) -{ - int ret = 0; - if (level == SUSPEND_SAVE_STATE) - ret = pcmcia_socket_dev_suspend(dev, state); - return ret; -} - -static int m32r_pcc_resume(struct device *dev, u32 level) -{ - int ret = 0; - if (level == RESUME_RESTORE_STATE) - ret = pcmcia_socket_dev_resume(dev); - return ret; -} - - static struct device_driver pcc_driver = { .name = "cfc", .bus = &platform_bus_type, - .suspend = m32r_pcc_suspend, - .resume = m32r_pcc_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; static struct platform_device pcc_device = { diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c index 7b14d7efd68..356a6fb416a 100644 --- a/drivers/pcmcia/m32r_pcc.c +++ b/drivers/pcmcia/m32r_pcc.c @@ -23,7 +23,7 @@ #include <linux/delay.h> #include <linux/workqueue.h> #include <linux/interrupt.h> -#include <linux/device.h> +#include <linux/platform_device.h> #include <asm/irq.h> #include <asm/io.h> #include <asm/bitops.h> @@ -695,28 +695,11 @@ static struct pccard_operations pcc_operations = { /*====================================================================*/ -static int m32r_pcc_suspend(struct device *dev, pm_message_t state, u32 level) -{ - int ret = 0; - if (level == SUSPEND_SAVE_STATE) - ret = pcmcia_socket_dev_suspend(dev, state); - return ret; -} - -static int m32r_pcc_resume(struct device *dev, u32 level) -{ - int ret = 0; - if (level == RESUME_RESTORE_STATE) - ret = pcmcia_socket_dev_resume(dev); - return ret; -} - - static struct device_driver pcc_driver = { .name = "pcc", .bus = &platform_bus_type, - .suspend = m32r_pcc_suspend, - .resume = m32r_pcc_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; static struct platform_device pcc_device = { diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c new file mode 100644 index 00000000000..6d9f71cfcb3 --- /dev/null +++ b/drivers/pcmcia/m8xx_pcmcia.c @@ -0,0 +1,1272 @@ +/* + * m8xx_pcmcia.c - Linux PCMCIA socket driver for the mpc8xx series. + * + * (C) 1999-2000 Magnus Damm <damm@bitsmart.com> + * (C) 2001-2002 Montavista Software, Inc. + * <mlocke@mvista.com> + * + * Support for two slots by Cyclades Corporation + * <oliver.kurth@cyclades.de> + * Further fixes, v2.6 kernel port + * <marcelo.tosatti@cyclades.com> + * + * "The ExCA standard specifies that socket controllers should provide + * two IO and five memory windows per socket, which can be independently + * configured and positioned in the host address space and mapped to + * arbitrary segments of card address space. " - David A Hinds. 1999 + * + * This controller does _not_ meet the ExCA standard. + * + * m8xx pcmcia controller brief info: + * + 8 windows (attrib, mem, i/o) + * + up to two slots (SLOT_A and SLOT_B) + * + inputpins, outputpins, event and mask registers. + * - no offset register. sigh. + * + * Because of the lacking offset register we must map the whole card. + * We assign each memory window PCMCIA_MEM_WIN_SIZE address space. + * Make sure there is (PCMCIA_MEM_WIN_SIZE * PCMCIA_MEM_WIN_NO + * * PCMCIA_SOCKETS_NO) bytes at PCMCIA_MEM_WIN_BASE. + * The i/o windows are dynamically allocated at PCMCIA_IO_WIN_BASE. + * They are maximum 64KByte each... + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/fcntl.h> +#include <linux/string.h> + +#include <asm/io.h> +#include <asm/bitops.h> +#include <asm/system.h> + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/timer.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> + +#include <asm/mpc8xx.h> +#include <asm/8xx_immap.h> +#include <asm/irq.h> + +#include <pcmcia/version.h> +#include <pcmcia/cs_types.h> +#include <pcmcia/cs.h> +#include <pcmcia/ss.h> + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +module_param(pc_debug, int, 0); +#define dprintk(args...) printk(KERN_DEBUG "m8xx_pcmcia: " args); +#else +#define dprintk(args...) +#endif + +#define pcmcia_info(args...) printk(KERN_INFO "m8xx_pcmcia: "args) +#define pcmcia_error(args...) printk(KERN_ERR "m8xx_pcmcia: "args) + +static const char *version = "Version 0.06, Aug 2005"; +MODULE_LICENSE("Dual MPL/GPL"); + +#if !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B) + +/* The RPX series use SLOT_B */ +#if defined(CONFIG_RPXCLASSIC) || defined(CONFIG_RPXLITE) +#define CONFIG_PCMCIA_SLOT_B +#define CONFIG_BD_IS_MHZ +#endif + +/* The ADS board use SLOT_A */ +#ifdef CONFIG_ADS +#define CONFIG_PCMCIA_SLOT_A +#define CONFIG_BD_IS_MHZ +#endif + +/* The FADS series are a mess */ +#ifdef CONFIG_FADS +#if defined(CONFIG_MPC860T) || defined(CONFIG_MPC860) || defined(CONFIG_MPC821) +#define CONFIG_PCMCIA_SLOT_A +#else +#define CONFIG_PCMCIA_SLOT_B +#endif +#endif + +/* Cyclades ACS uses both slots */ +#ifdef CONFIG_PRxK +#define CONFIG_PCMCIA_SLOT_A +#define CONFIG_PCMCIA_SLOT_B +#endif + +#endif /* !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B) */ + +#if defined(CONFIG_PCMCIA_SLOT_A) && defined(CONFIG_PCMCIA_SLOT_B) + +#define PCMCIA_SOCKETS_NO 2 +/* We have only 8 windows, dualsocket support will be limited. */ +#define PCMCIA_MEM_WIN_NO 2 +#define PCMCIA_IO_WIN_NO 2 +#define PCMCIA_SLOT_MSG "SLOT_A and SLOT_B" + +#elif defined(CONFIG_PCMCIA_SLOT_A) || defined(CONFIG_PCMCIA_SLOT_B) + +#define PCMCIA_SOCKETS_NO 1 +/* full support for one slot */ +#define PCMCIA_MEM_WIN_NO 5 +#define PCMCIA_IO_WIN_NO 2 + +/* define _slot_ to be able to optimize macros */ + +#ifdef CONFIG_PCMCIA_SLOT_A +#define _slot_ 0 +#define PCMCIA_SLOT_MSG "SLOT_A" +#else +#define _slot_ 1 +#define PCMCIA_SLOT_MSG "SLOT_B" +#endif + +#else +#error m8xx_pcmcia: Bad configuration! +#endif + +/* ------------------------------------------------------------------------- */ + +#define PCMCIA_MEM_WIN_BASE 0xe0000000 /* base address for memory window 0 */ +#define PCMCIA_MEM_WIN_SIZE 0x04000000 /* each memory window is 64 MByte */ +#define PCMCIA_IO_WIN_BASE _IO_BASE /* base address for io window 0 */ + +#define PCMCIA_SCHLVL PCMCIA_INTERRUPT /* Status Change Interrupt Level */ + +/* ------------------------------------------------------------------------- */ + +/* 2.4.x and newer has this always in HZ */ +#define M8XX_BUSFREQ ((((bd_t *)&(__res))->bi_busfreq)) + +static int pcmcia_schlvl = PCMCIA_SCHLVL; + +static spinlock_t events_lock = SPIN_LOCK_UNLOCKED; + + +#define PCMCIA_SOCKET_KEY_5V 1 +#define PCMCIA_SOCKET_KEY_LV 2 + +/* look up table for pgcrx registers */ +static u32 *m8xx_pgcrx[2] = { + &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pgcra, + &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pgcrb +}; + +/* + * This structure is used to address each window in the PCMCIA controller. + * + * Keep in mind that we assume that pcmcia_win[n+1] is mapped directly + * after pcmcia_win[n]... + */ + +struct pcmcia_win { + u32 br; + u32 or; +}; + +/* + * For some reason the hardware guys decided to make both slots share + * some registers. + * + * Could someone invent object oriented hardware ? + * + * The macros are used to get the right bit from the registers. + * SLOT_A : slot = 0 + * SLOT_B : slot = 1 + */ + +#define M8XX_PCMCIA_VS1(slot) (0x80000000 >> (slot << 4)) +#define M8XX_PCMCIA_VS2(slot) (0x40000000 >> (slot << 4)) +#define M8XX_PCMCIA_VS_MASK(slot) (0xc0000000 >> (slot << 4)) +#define M8XX_PCMCIA_VS_SHIFT(slot) (30 - (slot << 4)) + +#define M8XX_PCMCIA_WP(slot) (0x20000000 >> (slot << 4)) +#define M8XX_PCMCIA_CD2(slot) (0x10000000 >> (slot << 4)) +#define M8XX_PCMCIA_CD1(slot) (0x08000000 >> (slot << 4)) +#define M8XX_PCMCIA_BVD2(slot) (0x04000000 >> (slot << 4)) +#define M8XX_PCMCIA_BVD1(slot) (0x02000000 >> (slot << 4)) +#define M8XX_PCMCIA_RDY(slot) (0x01000000 >> (slot << 4)) +#define M8XX_PCMCIA_RDY_L(slot) (0x00800000 >> (slot << 4)) +#define M8XX_PCMCIA_RDY_H(slot) (0x00400000 >> (slot << 4)) +#define M8XX_PCMCIA_RDY_R(slot) (0x00200000 >> (slot << 4)) +#define M8XX_PCMCIA_RDY_F(slot) (0x00100000 >> (slot << 4)) +#define M8XX_PCMCIA_MASK(slot) (0xFFFF0000 >> (slot << 4)) + +#define M8XX_PCMCIA_POR_VALID 0x00000001 +#define M8XX_PCMCIA_POR_WRPROT 0x00000002 +#define M8XX_PCMCIA_POR_ATTRMEM 0x00000010 +#define M8XX_PCMCIA_POR_IO 0x00000018 +#define M8XX_PCMCIA_POR_16BIT 0x00000040 + +#define M8XX_PGCRX(slot) m8xx_pgcrx[slot] + +#define M8XX_PGCRX_CXOE 0x00000080 +#define M8XX_PGCRX_CXRESET 0x00000040 + +/* we keep one lookup table per socket to check flags */ + +#define PCMCIA_EVENTS_MAX 5 /* 4 max at a time + termination */ + +struct event_table { + u32 regbit; + u32 eventbit; +}; + +struct socket_info { + void (*handler)(void *info, u32 events); + void *info; + + u32 slot; + + socket_state_t state; + struct pccard_mem_map mem_win[PCMCIA_MEM_WIN_NO]; + struct pccard_io_map io_win[PCMCIA_IO_WIN_NO]; + struct event_table events[PCMCIA_EVENTS_MAX]; + struct pcmcia_socket socket; +}; + +static struct socket_info socket[PCMCIA_SOCKETS_NO]; + +/* + * Search this table to see if the windowsize is + * supported... + */ + +#define M8XX_SIZES_NO 32 + +static const u32 m8xx_size_to_gray[M8XX_SIZES_NO] = +{ + 0x00000001, 0x00000002, 0x00000008, 0x00000004, + 0x00000080, 0x00000040, 0x00000010, 0x00000020, + 0x00008000, 0x00004000, 0x00001000, 0x00002000, + 0x00000100, 0x00000200, 0x00000800, 0x00000400, + + 0x0fffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x01000000, 0x02000000, 0xffffffff, 0x04000000, + 0x00010000, 0x00020000, 0x00080000, 0x00040000, + 0x00800000, 0x00400000, 0x00100000, 0x00200000 +}; + +/* ------------------------------------------------------------------------- */ + +static irqreturn_t m8xx_interrupt(int irq, void *dev, struct pt_regs *regs); + +#define PCMCIA_BMT_LIMIT (15*4) /* Bus Monitor Timeout value */ + +/* ------------------------------------------------------------------------- */ +/* board specific stuff: */ +/* voltage_set(), hardware_enable() and hardware_disable() */ +/* ------------------------------------------------------------------------- */ +/* RPX Boards from Embedded Planet */ + +#if defined(CONFIG_RPXCLASSIC) || defined(CONFIG_RPXLITE) + +/* The RPX boards seems to have it's bus monitor timeout set to 6*8 clocks. + * SYPCR is write once only, therefore must the slowest memory be faster + * than the bus monitor or we will get a machine check due to the bus timeout. + */ + +#define PCMCIA_BOARD_MSG "RPX CLASSIC or RPX LITE" + +#undef PCMCIA_BMT_LIMIT +#define PCMCIA_BMT_LIMIT (6*8) + +static int voltage_set(int slot, int vcc, int vpp) +{ + u32 reg = 0; + + switch(vcc) { + case 0: break; + case 33: + reg |= BCSR1_PCVCTL4; + break; + case 50: + reg |= BCSR1_PCVCTL5; + break; + default: + return 1; + } + + switch(vpp) { + case 0: break; + case 33: + case 50: + if(vcc == vpp) + reg |= BCSR1_PCVCTL6; + else + return 1; + break; + case 120: + reg |= BCSR1_PCVCTL7; + default: + return 1; + } + + if(!((vcc == 50) || (vcc == 0))) + return 1; + + /* first, turn off all power */ + + out_be32(((u32 *)RPX_CSR_ADDR), in_be32(((u32 *)RPX_CSR_ADDR)) & ~(BCSR1_PCVCTL4 | BCSR1_PCVCTL5 | BCSR1_PCVCTL6 | BCSR1_PCVCTL7)); + + /* enable new powersettings */ + + out_be32(((u32 *)RPX_CSR_ADDR), in_be32(((u32 *)RPX_CSR_ADDR)) | reg); + + return 0; +} + +#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V +#define hardware_enable(_slot_) /* No hardware to enable */ +#define hardware_disable(_slot_) /* No hardware to disable */ + +#endif /* CONFIG_RPXCLASSIC */ + +/* FADS Boards from Motorola */ + +#if defined(CONFIG_FADS) + +#define PCMCIA_BOARD_MSG "FADS" + +static int voltage_set(int slot, int vcc, int vpp) +{ + u32 reg = 0; + + switch(vcc) { + case 0: + break; + case 33: + reg |= BCSR1_PCCVCC0; + break; + case 50: + reg |= BCSR1_PCCVCC1; + break; + default: + return 1; + } + + switch(vpp) { + case 0: + break; + case 33: + case 50: + if(vcc == vpp) + reg |= BCSR1_PCCVPP1; + else + return 1; + break; + case 120: + if ((vcc == 33) || (vcc == 50)) + reg |= BCSR1_PCCVPP0; + else + return 1; + default: + return 1; + } + + /* first, turn off all power */ + out_be32(&((u32 *)BCSR1), in_be32(&((u32 *)BCSR1)) & ~(BCSR1_PCCVCC_MASK | BCSR1_PCCVPP_MASK)); + + /* enable new powersettings */ + out_be32(&((u32 *)BCSR1), in_be32(&((u32 *)BCSR1)) | reg); + + return 0; +} + +#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V + +static void hardware_enable(int slot) +{ + out_be32(&((u32 *)BCSR1), in_be32(&((u32 *)BCSR1)) & ~BCSR1_PCCEN); +} + +static void hardware_disable(int slot) +{ + out_be32(&((u32 *)BCSR1), in_be32(&((u32 *)BCSR1)) | BCSR1_PCCEN); +} + +#endif + +/* ------------------------------------------------------------------------- */ +/* Motorola MBX860 */ + +#if defined(CONFIG_MBX) + +#define PCMCIA_BOARD_MSG "MBX" + +static int voltage_set(int slot, int vcc, int vpp) +{ + u8 reg = 0; + + switch(vcc) { + case 0: + break; + case 33: + reg |= CSR2_VCC_33; + break; + case 50: + reg |= CSR2_VCC_50; + break; + default: + return 1; + } + + switch(vpp) { + case 0: + break; + case 33: + case 50: + if(vcc == vpp) + reg |= CSR2_VPP_VCC; + else + return 1; + break; + case 120: + if ((vcc == 33) || (vcc == 50)) + reg |= CSR2_VPP_12; + else + return 1; + default: + return 1; + } + + /* first, turn off all power */ + out_8(&((u8 *)MBX_CSR2_ADDR), in_8(&((u8 *)MBX_CSR2_ADDR)) & ~(CSR2_VCC_MASK | CSR2_VPP_MASK)); + + /* enable new powersettings */ + out_8(&((u8 *)MBX_CSR2_ADDR), in_8(&((u8 *)MBX_CSR2_ADDR)) | reg); + + return 0; +} + +#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V +#define hardware_enable(_slot_) /* No hardware to enable */ +#define hardware_disable(_slot_) /* No hardware to disable */ + +#endif /* CONFIG_MBX */ + +#if defined(CONFIG_PRxK) +#include <asm/cpld.h> +extern volatile fpga_pc_regs *fpga_pc; + +#define PCMCIA_BOARD_MSG "MPC855T" + +static int voltage_set(int slot, int vcc, int vpp) +{ + u8 reg = 0; + u8 regread; + cpld_regs *ccpld = get_cpld(); + + switch(vcc) { + case 0: + break; + case 33: + reg |= PCMCIA_VCC_33; + break; + case 50: + reg |= PCMCIA_VCC_50; + break; + default: + return 1; + } + + switch(vpp) { + case 0: + break; + case 33: + case 50: + if(vcc == vpp) + reg |= PCMCIA_VPP_VCC; + else + return 1; + break; + case 120: + if ((vcc == 33) || (vcc == 50)) + reg |= PCMCIA_VPP_12; + else + return 1; + default: + return 1; + } + + reg = reg >> (slot << 2); + regread = in_8(&ccpld->fpga_pc_ctl); + if (reg != (regread & ((PCMCIA_VCC_MASK | PCMCIA_VPP_MASK) >> (slot << 2)))) { + /* enable new powersettings */ + regread = regread & ~((PCMCIA_VCC_MASK | PCMCIA_VPP_MASK) >> (slot << 2)); + out_8(&ccpld->fpga_pc_ctl, reg | regread); + msleep(100); + } + + return 0; +} + +#define socket_get(_slot_) PCMCIA_SOCKET_KEY_LV +#define hardware_enable(_slot_) /* No hardware to enable */ +#define hardware_disable(_slot_) /* No hardware to disable */ + +#endif /* CONFIG_PRxK */ + +static void m8xx_shutdown(void) +{ + u32 m, i; + struct pcmcia_win *w; + + for(i = 0; i < PCMCIA_SOCKETS_NO; i++){ + w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; + + out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, M8XX_PCMCIA_MASK(i)); + out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per) & ~M8XX_PCMCIA_MASK(i)); + + /* turn off interrupt and disable CxOE */ + out_be32(M8XX_PGCRX(i), M8XX_PGCRX_CXOE); + + /* turn off memory windows */ + for(m = 0; m < PCMCIA_MEM_WIN_NO; m++) { + out_be32(&w->or, 0); /* set to not valid */ + w++; + } + + /* turn off voltage */ + voltage_set(i, 0, 0); + + /* disable external hardware */ + hardware_disable(i); + } + + free_irq(pcmcia_schlvl, NULL); +} + +static struct device_driver m8xx_driver = { + .name = "m8xx-pcmcia", + .bus = &platform_bus_type, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, +}; + +static struct platform_device m8xx_device = { + .name = "m8xx-pcmcia", + .id = 0, +}; + +static u32 pending_events[PCMCIA_SOCKETS_NO]; +static spinlock_t pending_event_lock = SPIN_LOCK_UNLOCKED; + +static irqreturn_t m8xx_interrupt(int irq, void *dev, struct pt_regs *regs) +{ + struct socket_info *s; + struct event_table *e; + unsigned int i, events, pscr, pipr, per; + + dprintk("Interrupt!\n"); + /* get interrupt sources */ + + pscr = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr); + pipr = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr); + per = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per); + + for(i = 0; i < PCMCIA_SOCKETS_NO; i++) { + s = &socket[i]; + e = &s->events[0]; + events = 0; + + while(e->regbit) { + if(pscr & e->regbit) + events |= e->eventbit; + + e++; + } + + /* + * report only if both card detect signals are the same + * not too nice done, + * we depend on that CD2 is the bit to the left of CD1... + */ + if(events & SS_DETECT) + if(((pipr & M8XX_PCMCIA_CD2(i)) >> 1) ^ + (pipr & M8XX_PCMCIA_CD1(i))) + { + events &= ~SS_DETECT; + } + +#ifdef PCMCIA_GLITCHY_CD + /* + * I've experienced CD problems with my ADS board. + * We make an extra check to see if there was a + * real change of Card detection. + */ + + if((events & SS_DETECT) && + ((pipr & + (M8XX_PCMCIA_CD2(i) | M8XX_PCMCIA_CD1(i))) == 0) && + (s->state.Vcc | s->state.Vpp)) { + events &= ~SS_DETECT; + /*printk( "CD glitch workaround - CD = 0x%08x!\n", + (pipr & (M8XX_PCMCIA_CD2(i) + | M8XX_PCMCIA_CD1(i))));*/ + } +#endif + + /* call the handler */ + + dprintk("slot %u: events = 0x%02x, pscr = 0x%08x, " + "pipr = 0x%08x\n", + i, events, pscr, pipr); + + if(events) { + spin_lock(&pending_event_lock); + pending_events[i] |= events; + spin_unlock(&pending_event_lock); + /* + * Turn off RDY_L bits in the PER mask on + * CD interrupt receival. + * + * They can generate bad interrupts on the + * ACS4,8,16,32. - marcelo + */ + per &= ~M8XX_PCMCIA_RDY_L(0); + per &= ~M8XX_PCMCIA_RDY_L(1); + + out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, per); + + if (events) + pcmcia_parse_events(&socket[i].socket, events); + } + } + + /* clear the interrupt sources */ + out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, pscr); + + dprintk("Interrupt done.\n"); + + return IRQ_HANDLED; +} + +static u32 m8xx_get_graycode(u32 size) +{ + u32 k; + + for(k = 0; k < M8XX_SIZES_NO; k++) + if(m8xx_size_to_gray[k] == size) + break; + + if((k == M8XX_SIZES_NO) || (m8xx_size_to_gray[k] == -1)) + k = -1; + + return k; +} + +static u32 m8xx_get_speed(u32 ns, u32 is_io) +{ + u32 reg, clocks, psst, psl, psht; + + if(!ns) { + + /* + * We get called with IO maps setup to 0ns + * if not specified by the user. + * They should be 255ns. + */ + + if(is_io) + ns = 255; + else + ns = 100; /* fast memory if 0 */ + } + + /* + * In PSST, PSL, PSHT fields we tell the controller + * timing parameters in CLKOUT clock cycles. + * CLKOUT is the same as GCLK2_50. + */ + +/* how we want to adjust the timing - in percent */ + +#define ADJ 180 /* 80 % longer accesstime - to be sure */ + + clocks = ((M8XX_BUSFREQ / 1000) * ns) / 1000; + clocks = (clocks * ADJ) / (100*1000); + if(clocks >= PCMCIA_BMT_LIMIT) { + printk( "Max access time limit reached\n"); + clocks = PCMCIA_BMT_LIMIT-1; + } + + psst = clocks / 7; /* setup time */ + psht = clocks / 7; /* hold time */ + psl = (clocks * 5) / 7; /* strobe length */ + + psst += clocks - (psst + psht + psl); + + reg = psst << 12; + reg |= psl << 7; + reg |= psht << 16; + + return reg; +} + +static int m8xx_get_status(struct pcmcia_socket *sock, unsigned int *value) +{ + int lsock = container_of(sock, struct socket_info, socket)->slot; + struct socket_info *s = &socket[lsock]; + unsigned int pipr, reg; + + pipr = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr); + + *value = ((pipr & (M8XX_PCMCIA_CD1(lsock) + | M8XX_PCMCIA_CD2(lsock))) == 0) ? SS_DETECT : 0; + *value |= (pipr & M8XX_PCMCIA_WP(lsock)) ? SS_WRPROT : 0; + + if (s->state.flags & SS_IOCARD) + *value |= (pipr & M8XX_PCMCIA_BVD1(lsock)) ? SS_STSCHG : 0; + else { + *value |= (pipr & M8XX_PCMCIA_RDY(lsock)) ? SS_READY : 0; + *value |= (pipr & M8XX_PCMCIA_BVD1(lsock)) ? SS_BATDEAD : 0; + *value |= (pipr & M8XX_PCMCIA_BVD2(lsock)) ? SS_BATWARN : 0; + } + + if (s->state.Vcc | s->state.Vpp) + *value |= SS_POWERON; + + /* + * Voltage detection: + * This driver only supports 16-Bit pc-cards. + * Cardbus is not handled here. + * + * To determine what voltage to use we must read the VS1 and VS2 pin. + * Depending on what socket type is present, + * different combinations mean different things. + * + * Card Key Socket Key VS1 VS2 Card Vcc for CIS parse + * + * 5V 5V, LV* NC NC 5V only 5V (if available) + * + * 5V 5V, LV* GND NC 5 or 3.3V as low as possible + * + * 5V 5V, LV* GND GND 5, 3.3, x.xV as low as possible + * + * LV* 5V - - shall not fit into socket + * + * LV* LV* GND NC 3.3V only 3.3V + * + * LV* LV* NC GND x.xV x.xV (if avail.) + * + * LV* LV* GND GND 3.3 or x.xV as low as possible + * + * *LV means Low Voltage + * + * + * That gives us the following table: + * + * Socket VS1 VS2 Voltage + * + * 5V NC NC 5V + * 5V NC GND none (should not be possible) + * 5V GND NC >= 3.3V + * 5V GND GND >= x.xV + * + * LV NC NC 5V (if available) + * LV NC GND x.xV (if available) + * LV GND NC 3.3V + * LV GND GND >= x.xV + * + * So, how do I determine if I have a 5V or a LV + * socket on my board? Look at the socket! + * + * + * Socket with 5V key: + * ++--------------------------------------------+ + * || | + * || || + * || || + * | | + * +---------------------------------------------+ + * + * Socket with LV key: + * ++--------------------------------------------+ + * || | + * | || + * | || + * | | + * +---------------------------------------------+ + * + * + * With other words - LV only cards does not fit + * into the 5V socket! + */ + + /* read out VS1 and VS2 */ + + reg = (pipr & M8XX_PCMCIA_VS_MASK(lsock)) + >> M8XX_PCMCIA_VS_SHIFT(lsock); + + if(socket_get(lsock) == PCMCIA_SOCKET_KEY_LV) { + switch(reg) { + case 1: + *value |= SS_3VCARD; + break; /* GND, NC - 3.3V only */ + case 2: + *value |= SS_XVCARD; + break; /* NC. GND - x.xV only */ + }; + } + + dprintk("GetStatus(%d) = %#2.2x\n", lsock, *value); + return 0; +} + +static int m8xx_get_socket(struct pcmcia_socket *sock, socket_state_t *state) +{ + int lsock = container_of(sock, struct socket_info, socket)->slot; + *state = socket[lsock].state; /* copy the whole structure */ + + dprintk("GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, " + "io_irq %d, csc_mask %#2.2x\n", lsock, state->flags, + state->Vcc, state->Vpp, state->io_irq, state->csc_mask); + return 0; +} + +static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state) +{ + int lsock = container_of(sock, struct socket_info, socket)->slot; + struct socket_info *s = &socket[lsock]; + struct event_table *e; + unsigned int reg; + unsigned long flags; + + dprintk( "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " + "io_irq %d, csc_mask %#2.2x)\n", lsock, state->flags, + state->Vcc, state->Vpp, state->io_irq, state->csc_mask); + + /* First, set voltage - bail out if invalid */ + if(voltage_set(lsock, state->Vcc, state->Vpp)) + return -EINVAL; + + /* Take care of reset... */ + if(state->flags & SS_RESET) + out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) | M8XX_PGCRX_CXRESET); /* active high */ + else + out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) & ~M8XX_PGCRX_CXRESET); + + /* ... and output enable. */ + + /* The CxOE signal is connected to a 74541 on the ADS. + I guess most other boards used the ADS as a reference. + I tried to control the CxOE signal with SS_OUTPUT_ENA, + but the reset signal seems connected via the 541. + If the CxOE is left high are some signals tristated and + no pullups are present -> the cards act wierd. + So right now the buffers are enabled if the power is on. */ + + if(state->Vcc || state->Vpp) + out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) & ~M8XX_PGCRX_CXOE); /* active low */ + else + out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) | M8XX_PGCRX_CXOE); + + /* + * We'd better turn off interrupts before + * we mess with the events-table.. + */ + + spin_lock_irqsave(&events_lock, flags); + + /* + * Play around with the interrupt mask to be able to + * give the events the generic pcmcia driver wants us to. + */ + + e = &s->events[0]; + reg = 0; + + if(state->csc_mask & SS_DETECT) { + e->eventbit = SS_DETECT; + reg |= e->regbit = (M8XX_PCMCIA_CD2(lsock) + | M8XX_PCMCIA_CD1(lsock)); + e++; + } + if(state->flags & SS_IOCARD) { + /* + * I/O card + */ + if(state->csc_mask & SS_STSCHG) { + e->eventbit = SS_STSCHG; + reg |= e->regbit = M8XX_PCMCIA_BVD1(lsock); + e++; + } + /* + * If io_irq is non-zero we should enable irq. + */ + if(state->io_irq) { + out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) | mk_int_int_mask(state->io_irq) << 24); + /* + * Strange thing here: + * The manual does not tell us which interrupt + * the sources generate. + * Anyhow, I found out that RDY_L generates IREQLVL. + * + * We use level triggerd interrupts, and they don't + * have to be cleared in PSCR in the interrupt handler. + */ + reg |= M8XX_PCMCIA_RDY_L(lsock); + } + else + out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) & 0x00ffffff); + } + else { + /* + * Memory card + */ + if(state->csc_mask & SS_BATDEAD) { + e->eventbit = SS_BATDEAD; + reg |= e->regbit = M8XX_PCMCIA_BVD1(lsock); + e++; + } + if(state->csc_mask & SS_BATWARN) { + e->eventbit = SS_BATWARN; + reg |= e->regbit = M8XX_PCMCIA_BVD2(lsock); + e++; + } + /* What should I trigger on - low/high,raise,fall? */ + if(state->csc_mask & SS_READY) { + e->eventbit = SS_READY; + reg |= e->regbit = 0; //?? + e++; + } + } + + e->regbit = 0; /* terminate list */ + + /* + * Clear the status changed . + * Port A and Port B share the same port. + * Writing ones will clear the bits. + */ + + out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, reg); + + /* + * Write the mask. + * Port A and Port B share the same port. + * Need for read-modify-write. + * Ones will enable the interrupt. + */ + + /* + reg |= ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per + & M8XX_PCMCIA_MASK(lsock); + */ + + reg |= in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per) & + (M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1)); + + out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, reg); + + spin_unlock_irqrestore(&events_lock, flags); + + /* copy the struct and modify the copy */ + + s->state = *state; + + return 0; +} + +static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io) +{ + int lsock = container_of(sock, struct socket_info, socket)->slot; + + struct socket_info *s = &socket[lsock]; + struct pcmcia_win *w; + unsigned int reg, winnr; + +#define M8XX_SIZE (io->stop - io->start + 1) +#define M8XX_BASE (PCMCIA_IO_WIN_BASE + io->start) + + dprintk( "SetIOMap(%d, %d, %#2.2x, %d ns, " + "%#4.4x-%#4.4x)\n", lsock, io->map, io->flags, + io->speed, io->start, io->stop); + + if ((io->map >= PCMCIA_IO_WIN_NO) || (io->start > 0xffff) + || (io->stop > 0xffff) || (io->stop < io->start)) + return -EINVAL; + + if((reg = m8xx_get_graycode(M8XX_SIZE)) == -1) + return -EINVAL; + + if(io->flags & MAP_ACTIVE) { + + dprintk( "io->flags & MAP_ACTIVE\n"); + + winnr = (PCMCIA_MEM_WIN_NO * PCMCIA_SOCKETS_NO) + + (lsock * PCMCIA_IO_WIN_NO) + io->map; + + /* setup registers */ + + w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; + w += winnr; + + out_be32(&w->or, 0); /* turn off window first */ + out_be32(&w->br, M8XX_BASE); + + reg <<= 27; + reg |= M8XX_PCMCIA_POR_IO |(lsock << 2); + + reg |= m8xx_get_speed(io->speed, 1); + + if(io->flags & MAP_WRPROT) + reg |= M8XX_PCMCIA_POR_WRPROT; + + /*if(io->flags & (MAP_16BIT | MAP_AUTOSZ))*/ + if(io->flags & MAP_16BIT) + reg |= M8XX_PCMCIA_POR_16BIT; + + if(io->flags & MAP_ACTIVE) + reg |= M8XX_PCMCIA_POR_VALID; + + out_be32(&w->or, reg); + + dprintk("Socket %u: Mapped io window %u at %#8.8x, " + "OR = %#8.8x.\n", lsock, io->map, w->br, w->or); + } else { + /* shutdown IO window */ + winnr = (PCMCIA_MEM_WIN_NO * PCMCIA_SOCKETS_NO) + + (lsock * PCMCIA_IO_WIN_NO) + io->map; + + /* setup registers */ + + w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; + w += winnr; + + out_be32(&w->or, 0); /* turn off window */ + out_be32(&w->br, 0); /* turn off base address */ + + dprintk("Socket %u: Unmapped io window %u at %#8.8x, " + "OR = %#8.8x.\n", lsock, io->map, w->br, w->or); + } + + /* copy the struct and modify the copy */ + s->io_win[io->map] = *io; + s->io_win[io->map].flags &= (MAP_WRPROT + | MAP_16BIT + | MAP_ACTIVE); + dprintk("SetIOMap exit\n"); + + return 0; +} + +static int m8xx_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *mem) +{ + int lsock = container_of(sock, struct socket_info, socket)->slot; + struct socket_info *s = &socket[lsock]; + struct pcmcia_win *w; + struct pccard_mem_map *old; + unsigned int reg, winnr; + + dprintk( "SetMemMap(%d, %d, %#2.2x, %d ns, " + "%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags, + mem->speed, mem->static_start, mem->card_start); + + if ((mem->map >= PCMCIA_MEM_WIN_NO) +// || ((mem->s) >= PCMCIA_MEM_WIN_SIZE) + || (mem->card_start >= 0x04000000) + || (mem->static_start & 0xfff) /* 4KByte resolution */ + || (mem->card_start & 0xfff)) + return -EINVAL; + + if((reg = m8xx_get_graycode(PCMCIA_MEM_WIN_SIZE)) == -1) { + printk( "Cannot set size to 0x%08x.\n", PCMCIA_MEM_WIN_SIZE); + return -EINVAL; + } + reg <<= 27; + + winnr = (lsock * PCMCIA_MEM_WIN_NO) + mem->map; + + /* Setup the window in the pcmcia controller */ + + w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; + w += winnr; + + reg |= lsock << 2; + + reg |= m8xx_get_speed(mem->speed, 0); + + if(mem->flags & MAP_ATTRIB) + reg |= M8XX_PCMCIA_POR_ATTRMEM; + + if(mem->flags & MAP_WRPROT) + reg |= M8XX_PCMCIA_POR_WRPROT; + + if(mem->flags & MAP_16BIT) + reg |= M8XX_PCMCIA_POR_16BIT; + + if(mem->flags & MAP_ACTIVE) + reg |= M8XX_PCMCIA_POR_VALID; + + out_be32(&w->or, reg); + + dprintk("Socket %u: Mapped memory window %u at %#8.8x, " + "OR = %#8.8x.\n", lsock, mem->map, w->br, w->or); + + if(mem->flags & MAP_ACTIVE) { + /* get the new base address */ + mem->static_start = PCMCIA_MEM_WIN_BASE + + (PCMCIA_MEM_WIN_SIZE * winnr) + + mem->card_start; + } + + dprintk("SetMemMap(%d, %d, %#2.2x, %d ns, " + "%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags, + mem->speed, mem->static_start, mem->card_start); + + /* copy the struct and modify the copy */ + + old = &s->mem_win[mem->map]; + + *old = *mem; + old->flags &= (MAP_ATTRIB + | MAP_WRPROT + | MAP_16BIT + | MAP_ACTIVE); + + return 0; +} + +static int m8xx_sock_init(struct pcmcia_socket *sock) +{ + int i; + pccard_io_map io = { 0, 0, 0, 0, 1 }; + pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 }; + + dprintk( "sock_init(%d)\n", s); + + m8xx_set_socket(sock, &dead_socket); + for (i = 0; i < PCMCIA_IO_WIN_NO; i++) { + io.map = i; + m8xx_set_io_map(sock, &io); + } + for (i = 0; i < PCMCIA_MEM_WIN_NO; i++) { + mem.map = i; + m8xx_set_mem_map(sock, &mem); + } + + return 0; + +} + +static int m8xx_suspend(struct pcmcia_socket *sock) +{ + return m8xx_set_socket(sock, &dead_socket); +} + +static struct pccard_operations m8xx_services = { + .init = m8xx_sock_init, + .suspend = m8xx_suspend, + .get_status = m8xx_get_status, + .get_socket = m8xx_get_socket, + .set_socket = m8xx_set_socket, + .set_io_map = m8xx_set_io_map, + .set_mem_map = m8xx_set_mem_map, +}; + +static int __init m8xx_init(void) +{ + struct pcmcia_win *w; + unsigned int i,m; + + pcmcia_info("%s\n", version); + + if (driver_register(&m8xx_driver)) + return -1; + + pcmcia_info(PCMCIA_BOARD_MSG " using " PCMCIA_SLOT_MSG + " with IRQ %u.\n", pcmcia_schlvl); + + /* Configure Status change interrupt */ + + if(request_irq(pcmcia_schlvl, m8xx_interrupt, 0, + "m8xx_pcmcia", NULL)) { + pcmcia_error("Cannot allocate IRQ %u for SCHLVL!\n", + pcmcia_schlvl); + return -1; + } + + w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; + + out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, + M8XX_PCMCIA_MASK(0)| M8XX_PCMCIA_MASK(1)); + + out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, + in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per) & + ~(M8XX_PCMCIA_MASK(0)| M8XX_PCMCIA_MASK(1))); + +/* connect interrupt and disable CxOE */ + + out_be32(M8XX_PGCRX(0), M8XX_PGCRX_CXOE | (mk_int_int_mask(pcmcia_schlvl) << 16)); + out_be32(M8XX_PGCRX(1), M8XX_PGCRX_CXOE | (mk_int_int_mask(pcmcia_schlvl) << 16)); + +/* intialize the fixed memory windows */ + + for(i = 0; i < PCMCIA_SOCKETS_NO; i++){ + for(m = 0; m < PCMCIA_MEM_WIN_NO; m++) { + out_be32(&w->br, PCMCIA_MEM_WIN_BASE + + (PCMCIA_MEM_WIN_SIZE + * (m + i * PCMCIA_MEM_WIN_NO))); + + out_be32(&w->or, 0); /* set to not valid */ + + w++; + } + } + +/* turn off voltage */ + voltage_set(0, 0, 0); + voltage_set(1, 0, 0); + +/* Enable external hardware */ + hardware_enable(0); + hardware_enable(1); + + platform_device_register(&m8xx_device); + + for (i = 0 ; i < PCMCIA_SOCKETS_NO; i++) { + socket[i].slot = i; + socket[i].socket.owner = THIS_MODULE; + socket[i].socket.features = SS_CAP_PCCARD | SS_CAP_MEM_ALIGN | SS_CAP_STATIC_MAP; + socket[i].socket.irq_mask = 0x000; + socket[i].socket.map_size = 0x1000; + socket[i].socket.io_offset = 0; + socket[i].socket.pci_irq = i ? 7 : 9; + socket[i].socket.ops = &m8xx_services; + socket[i].socket.resource_ops = &pccard_nonstatic_ops; + socket[i].socket.cb_dev = NULL; + socket[i].socket.dev.dev = &m8xx_device.dev; + } + + for (i = 0; i < PCMCIA_SOCKETS_NO; i++) + pcmcia_register_socket(&socket[i].socket); + + return 0; +} + +static void __exit m8xx_exit(void) +{ + int i; + + for (i = 0; i < PCMCIA_SOCKETS_NO; i++) + pcmcia_unregister_socket(&socket[i].socket); + + m8xx_shutdown(); + + platform_device_unregister(&m8xx_device); + driver_unregister(&m8xx_driver); +} + +module_init(m8xx_init); +module_exit(m8xx_exit); diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c index 08d1c928826..47b5ade95bd 100644 --- a/drivers/pcmcia/omap_cf.c +++ b/drivers/pcmcia/omap_cf.c @@ -12,7 +12,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/sched.h> -#include <linux/device.h> +#include <linux/platform_device.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/delay.h> @@ -22,7 +22,6 @@ #include <asm/hardware.h> #include <asm/io.h> -#include <asm/mach-types.h> #include <asm/sizes.h> #include <asm/arch/mux.h> @@ -330,27 +329,13 @@ static int __devexit omap_cf_remove(struct device *dev) return 0; } -static int omap_cf_suspend(struct device *dev, pm_message_t mesg, u32 level) -{ - if (level != SUSPEND_SAVE_STATE) - return 0; - return pcmcia_socket_dev_suspend(dev, mesg); -} - -static int omap_cf_resume(struct device *dev, u32 level) -{ - if (level != RESUME_RESTORE_STATE) - return 0; - return pcmcia_socket_dev_resume(dev); -} - static struct device_driver omap_cf_driver = { .name = (char *) driver_name, .bus = &platform_bus_type, .probe = omap_cf_probe, .remove = __devexit_p(omap_cf_remove), - .suspend = omap_cf_suspend, - .resume = omap_cf_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; static int __init omap_cf_init(void) diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index 325c992f7d8..7fa18fb814b 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -23,6 +23,7 @@ #include <linux/ioport.h> #include <linux/kernel.h> #include <linux/spinlock.h> +#include <linux/platform_device.h> #include <asm/hardware.h> #include <asm/io.h> @@ -205,32 +206,20 @@ int pxa2xx_drv_pcmcia_probe(struct device *dev) } EXPORT_SYMBOL(pxa2xx_drv_pcmcia_probe); -static int pxa2xx_drv_pcmcia_suspend(struct device *dev, pm_message_t state, u32 level) +static int pxa2xx_drv_pcmcia_resume(struct device *dev) { - int ret = 0; - if (level == SUSPEND_SAVE_STATE) - ret = pcmcia_socket_dev_suspend(dev, state); - return ret; -} + struct pcmcia_low_level *ops = dev->platform_data; + int nr = ops ? ops->nr : 0; -static int pxa2xx_drv_pcmcia_resume(struct device *dev, u32 level) -{ - int ret = 0; - if (level == RESUME_RESTORE_STATE) - { - struct pcmcia_low_level *ops = dev->platform_data; - int nr = ops ? ops->nr : 0; - - MECR = nr > 1 ? MECR_CIT | MECR_NOS : (nr > 0 ? MECR_CIT : 0); - ret = pcmcia_socket_dev_resume(dev); - } - return ret; + MECR = nr > 1 ? MECR_CIT | MECR_NOS : (nr > 0 ? MECR_CIT : 0); + + return pcmcia_socket_dev_resume(dev); } static struct device_driver pxa2xx_pcmcia_driver = { .probe = pxa2xx_drv_pcmcia_probe, .remove = soc_common_drv_pcmcia_remove, - .suspend = pxa2xx_drv_pcmcia_suspend, + .suspend = pcmcia_socket_dev_suspend, .resume = pxa2xx_drv_pcmcia_resume, .name = "pxa2xx-pcmcia", .bus = &platform_bus_type, diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c index bbe69b07ce5..5209d8c7764 100644 --- a/drivers/pcmcia/pxa2xx_mainstone.c +++ b/drivers/pcmcia/pxa2xx_mainstone.c @@ -17,7 +17,7 @@ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/interrupt.h> -#include <linux/device.h> +#include <linux/platform_device.h> #include <pcmcia/ss.h> diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c index a1178a600e3..56c58831e80 100644 --- a/drivers/pcmcia/pxa2xx_sharpsl.c +++ b/drivers/pcmcia/pxa2xx_sharpsl.c @@ -16,17 +16,26 @@ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/interrupt.h> -#include <linux/device.h> +#include <linux/platform_device.h> +#include <asm/mach-types.h> #include <asm/hardware.h> #include <asm/irq.h> #include <asm/hardware/scoop.h> -#include <asm/arch/pxa-regs.h> #include "soc_common.h" #define NO_KEEP_VS 0x0001 +/* PCMCIA to Scoop linkage + + There is no easy way to link multiple scoop devices into one + single entity for the pxa2xx_pcmcia device so this structure + is used which is setup by the platform code +*/ +struct scoop_pcmcia_config *platform_scoop_config; +#define SCOOP_DEV platform_scoop_config->devs + static void sharpsl_pcmcia_init_reset(struct scoop_pcmcia_dev *scoopdev) { reset_scoop(scoopdev->dev); @@ -38,36 +47,16 @@ static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { int ret; - /* - * Setup default state of GPIO outputs - * before we enable them as outputs. - */ - GPSR(GPIO48_nPOE) = - GPIO_bit(GPIO48_nPOE) | - GPIO_bit(GPIO49_nPWE) | - GPIO_bit(GPIO50_nPIOR) | - GPIO_bit(GPIO51_nPIOW) | - GPIO_bit(GPIO52_nPCE_1) | - GPIO_bit(GPIO53_nPCE_2); - - pxa_gpio_mode(GPIO48_nPOE_MD); - pxa_gpio_mode(GPIO49_nPWE_MD); - pxa_gpio_mode(GPIO50_nPIOR_MD); - pxa_gpio_mode(GPIO51_nPIOW_MD); - pxa_gpio_mode(GPIO52_nPCE_1_MD); - pxa_gpio_mode(GPIO53_nPCE_2_MD); - pxa_gpio_mode(GPIO54_pSKTSEL_MD); - pxa_gpio_mode(GPIO55_nPREG_MD); - pxa_gpio_mode(GPIO56_nPWAIT_MD); - pxa_gpio_mode(GPIO57_nIOIS16_MD); + if (platform_scoop_config->pcmcia_init) + platform_scoop_config->pcmcia_init(); /* Register interrupts */ - if (scoop_devs[skt->nr].cd_irq >= 0) { + if (SCOOP_DEV[skt->nr].cd_irq >= 0) { struct pcmcia_irqs cd_irq; cd_irq.sock = skt->nr; - cd_irq.irq = scoop_devs[skt->nr].cd_irq; - cd_irq.str = scoop_devs[skt->nr].cd_irq_str; + cd_irq.irq = SCOOP_DEV[skt->nr].cd_irq; + cd_irq.str = SCOOP_DEV[skt->nr].cd_irq_str; ret = soc_pcmcia_request_irqs(skt, &cd_irq, 1); if (ret) { @@ -76,19 +65,19 @@ static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt) } } - skt->irq = scoop_devs[skt->nr].irq; + skt->irq = SCOOP_DEV[skt->nr].irq; return 0; } static void sharpsl_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) { - if (scoop_devs[skt->nr].cd_irq >= 0) { + if (SCOOP_DEV[skt->nr].cd_irq >= 0) { struct pcmcia_irqs cd_irq; cd_irq.sock = skt->nr; - cd_irq.irq = scoop_devs[skt->nr].cd_irq; - cd_irq.str = scoop_devs[skt->nr].cd_irq_str; + cd_irq.irq = SCOOP_DEV[skt->nr].cd_irq; + cd_irq.str = SCOOP_DEV[skt->nr].cd_irq_str; soc_pcmcia_free_irqs(skt, &cd_irq, 1); } } @@ -98,9 +87,9 @@ static void sharpsl_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state) { unsigned short cpr, csr; - struct device *scoop = scoop_devs[skt->nr].dev; + struct device *scoop = SCOOP_DEV[skt->nr].dev; - cpr = read_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR); + cpr = read_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR); write_scoop_reg(scoop, SCOOP_IRM, 0x00FF); write_scoop_reg(scoop, SCOOP_ISR, 0x0000); @@ -109,21 +98,25 @@ static void sharpsl_pcmcia_socket_state(struct soc_pcmcia_socket *skt, if (csr & 0x0004) { /* card eject */ write_scoop_reg(scoop, SCOOP_CDR, 0x0000); - scoop_devs[skt->nr].keep_vs = NO_KEEP_VS; + SCOOP_DEV[skt->nr].keep_vs = NO_KEEP_VS; } - else if (!(scoop_devs[skt->nr].keep_vs & NO_KEEP_VS)) { + else if (!(SCOOP_DEV[skt->nr].keep_vs & NO_KEEP_VS)) { /* keep vs1,vs2 */ write_scoop_reg(scoop, SCOOP_CDR, 0x0000); - csr |= scoop_devs[skt->nr].keep_vs; + csr |= SCOOP_DEV[skt->nr].keep_vs; } else if (cpr & 0x0003) { /* power on */ write_scoop_reg(scoop, SCOOP_CDR, 0x0000); - scoop_devs[skt->nr].keep_vs = (csr & 0x00C0); + SCOOP_DEV[skt->nr].keep_vs = (csr & 0x00C0); } else { /* card detect */ - write_scoop_reg(scoop, SCOOP_CDR, 0x0002); + if ((machine_is_spitz() || machine_is_borzoi()) && skt->nr == 1) { + write_scoop_reg(scoop, SCOOP_CDR, 0x0000); + } else { + write_scoop_reg(scoop, SCOOP_CDR, 0x0002); + } } state->detect = (csr & 0x0004) ? 0 : 1; @@ -137,7 +130,6 @@ static void sharpsl_pcmcia_socket_state(struct soc_pcmcia_socket *skt, if ((cpr & 0x0080) && ((cpr & 0x8040) != 0x8040)) { printk(KERN_ERR "sharpsl_pcmcia_socket_state(): CPR=%04X, Low voltage!\n", cpr); } - } @@ -145,7 +137,7 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) { unsigned long flags; - struct device *scoop = scoop_devs[skt->nr].dev; + struct device *scoop = SCOOP_DEV[skt->nr].dev; unsigned short cpr, ncpr, ccr, nccr, mcr, nmcr, imr, nimr; @@ -170,8 +162,13 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, nccr = (ccr = read_scoop_reg(scoop, SCOOP_CCR)) & ~0x0080; nimr = (imr = read_scoop_reg(scoop, SCOOP_IMR)) & ~0x003E; - ncpr |= (state->Vcc == 33) ? 0x0001 : - (state->Vcc == 50) ? 0x0002 : 0; + if ((machine_is_spitz() || machine_is_borzoi() || machine_is_akita()) && skt->nr == 0) { + ncpr |= (state->Vcc == 33) ? 0x0002 : + (state->Vcc == 50) ? 0x0002 : 0; + } else { + ncpr |= (state->Vcc == 33) ? 0x0001 : + (state->Vcc == 50) ? 0x0002 : 0; + } nmcr |= (state->flags&SS_IOCARD) ? 0x0010 : 0; ncpr |= (state->flags&SS_OUTPUT_ENA) ? 0x0080 : 0; nccr |= (state->flags&SS_RESET)? 0x0080: 0; @@ -183,18 +180,22 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, ((skt->status&SS_WRPROT) ? 0x0008 : 0); if (!(ncpr & 0x0003)) { - scoop_devs[skt->nr].keep_rd = 0; - } else if (!scoop_devs[skt->nr].keep_rd) { + SCOOP_DEV[skt->nr].keep_rd = 0; + } else if (!SCOOP_DEV[skt->nr].keep_rd) { if (nccr & 0x0080) - scoop_devs[skt->nr].keep_rd = 1; + SCOOP_DEV[skt->nr].keep_rd = 1; else nccr |= 0x0080; } if (mcr != nmcr) write_scoop_reg(scoop, SCOOP_MCR, nmcr); - if (cpr != ncpr) - write_scoop_reg(scoop, SCOOP_CPR, ncpr); + if (cpr != ncpr) { + if (platform_scoop_config->power_ctrl) + platform_scoop_config->power_ctrl(scoop, ncpr , skt->nr); + else + write_scoop_reg(scoop, SCOOP_CPR, ncpr); + } if (ccr != nccr) write_scoop_reg(scoop, SCOOP_CCR, nccr); if (imr != nimr) @@ -207,39 +208,62 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, static void sharpsl_pcmcia_socket_init(struct soc_pcmcia_socket *skt) { - sharpsl_pcmcia_init_reset(&scoop_devs[skt->nr]); + sharpsl_pcmcia_init_reset(&SCOOP_DEV[skt->nr]); /* Enable interrupt */ - write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_IMR, 0x00C0); - write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_MCR, 0x0101); - scoop_devs[skt->nr].keep_vs = NO_KEEP_VS; + write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_IMR, 0x00C0); + write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_MCR, 0x0101); + SCOOP_DEV[skt->nr].keep_vs = NO_KEEP_VS; + + if (machine_is_collie()) + /* We need to disable SS_OUTPUT_ENA here. */ + write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR, read_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR) & ~0x0080); } static void sharpsl_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) { /* CF_BUS_OFF */ - sharpsl_pcmcia_init_reset(&scoop_devs[skt->nr]); + sharpsl_pcmcia_init_reset(&SCOOP_DEV[skt->nr]); + + if (machine_is_collie()) + /* We need to disable SS_OUTPUT_ENA here. */ + write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR, read_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR) & ~0x0080); } static struct pcmcia_low_level sharpsl_pcmcia_ops = { - .owner = THIS_MODULE, - .hw_init = sharpsl_pcmcia_hw_init, - .hw_shutdown = sharpsl_pcmcia_hw_shutdown, - .socket_state = sharpsl_pcmcia_socket_state, - .configure_socket = sharpsl_pcmcia_configure_socket, - .socket_init = sharpsl_pcmcia_socket_init, - .socket_suspend = sharpsl_pcmcia_socket_suspend, - .first = 0, - .nr = 0, + .owner = THIS_MODULE, + .hw_init = sharpsl_pcmcia_hw_init, + .hw_shutdown = sharpsl_pcmcia_hw_shutdown, + .socket_state = sharpsl_pcmcia_socket_state, + .configure_socket = sharpsl_pcmcia_configure_socket, + .socket_init = sharpsl_pcmcia_socket_init, + .socket_suspend = sharpsl_pcmcia_socket_suspend, + .first = 0, + .nr = 0, }; +#ifdef CONFIG_SA1100_COLLIE +#include "sa11xx_base.h" + +int __init pcmcia_collie_init(struct device *dev) +{ + int ret = -ENODEV; + + if (machine_is_collie()) + ret = sa11xx_drv_pcmcia_probe(dev, &sharpsl_pcmcia_ops, 0, 1); + + return ret; +} + +#else + static struct platform_device *sharpsl_pcmcia_device; static int __init sharpsl_pcmcia_init(void) { int ret; - sharpsl_pcmcia_ops.nr=scoop_num; + sharpsl_pcmcia_ops.nr=platform_scoop_config->num_devs; sharpsl_pcmcia_device = kmalloc(sizeof(*sharpsl_pcmcia_device), GFP_KERNEL); if (!sharpsl_pcmcia_device) return -ENOMEM; @@ -247,7 +271,7 @@ static int __init sharpsl_pcmcia_init(void) memset(sharpsl_pcmcia_device, 0, sizeof(*sharpsl_pcmcia_device)); sharpsl_pcmcia_device->name = "pxa2xx-pcmcia"; sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops; - sharpsl_pcmcia_device->dev.parent=scoop_devs[0].dev; + sharpsl_pcmcia_device->dev.parent=platform_scoop_config->devs[0].dev; ret = platform_device_register(sharpsl_pcmcia_device); if (ret) @@ -269,6 +293,7 @@ static void __exit sharpsl_pcmcia_exit(void) fs_initcall(sharpsl_pcmcia_init); module_exit(sharpsl_pcmcia_exit); +#endif MODULE_DESCRIPTION("Sharp SL Series PCMCIA Support"); MODULE_LICENSE("GPL"); diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index c42455d20eb..00960a379b9 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -691,7 +691,7 @@ static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned unsigned long size = end - start + 1; int ret = 0; - if (end <= start) + if (end < start) return -EINVAL; down(&rsrc_sem); @@ -724,7 +724,7 @@ static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long unsigned long size = end - start + 1; int ret = 0; - if (end <= start) + if (end < start) return -EINVAL; if (end > IO_SPACE_LIMIT) @@ -779,7 +779,7 @@ static int nonstatic_autoadd_resources(struct pcmcia_socket *s) if (!s->cb_dev || !s->cb_dev->bus) return -ENODEV; -#if defined(CONFIG_X86) || defined(CONFIG_X86_64) +#if defined(CONFIG_X86) /* If this is the root bus, the risk of hitting * some strange system devices which aren't protected * by either ACPI resource tables or properly requested @@ -817,7 +817,7 @@ static int nonstatic_autoadd_resources(struct pcmcia_socket *s) /* if we got at least one of IO, and one of MEM, we can be glad and * activate the PCMCIA subsystem */ - if (done & (IORESOURCE_MEM | IORESOURCE_IO)) + if (done == (IORESOURCE_MEM | IORESOURCE_IO)) s->resource_setup_done = 1; return 0; @@ -925,7 +925,7 @@ static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size return -EINVAL; } } - if (end_addr <= start_addr) + if (end_addr < start_addr) return -EINVAL; ret = adjust_io(s, add, start_addr, end_addr); @@ -977,7 +977,7 @@ static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, siz return -EINVAL; } } - if (end_addr <= start_addr) + if (end_addr < start_addr) return -EINVAL; ret = adjust_memory(s, add, start_addr, end_addr); @@ -994,7 +994,8 @@ static struct class_device_attribute *pccard_rsrc_attributes[] = { NULL, }; -static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev) +static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev, + struct class_interface *class_intf) { struct pcmcia_socket *s = class_get_devdata(class_dev); struct class_device_attribute **attr; @@ -1011,7 +1012,8 @@ static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev) return ret; } -static void __devexit pccard_sysfs_remove_rsrc(struct class_device *class_dev) +static void __devexit pccard_sysfs_remove_rsrc(struct class_device *class_dev, + struct class_interface *class_intf) { struct pcmcia_socket *s = class_get_devdata(class_dev); struct class_device_attribute **attr; diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index d4ed508b38b..6d441ec75c6 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c @@ -33,13 +33,18 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/config.h> +#include <linux/platform_device.h> #include <pcmcia/cs_types.h> #include <pcmcia/cs.h> #include <pcmcia/ss.h> +#include <asm/hardware/scoop.h> + #include "sa1100_generic.h" +int __init pcmcia_collie_init(struct device *dev); + static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = { #ifdef CONFIG_SA1100_ASSABET pcmcia_assabet_init, @@ -56,6 +61,9 @@ static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = { #ifdef CONFIG_SA1100_SIMPAD pcmcia_simpad_init, #endif +#ifdef CONFIG_SA1100_COLLIE + pcmcia_collie_init, +#endif }; static int sa11x0_drv_pcmcia_probe(struct device *dev) @@ -74,29 +82,13 @@ static int sa11x0_drv_pcmcia_probe(struct device *dev) return ret; } -static int sa11x0_drv_pcmcia_suspend(struct device *dev, pm_message_t state, u32 level) -{ - int ret = 0; - if (level == SUSPEND_SAVE_STATE) - ret = pcmcia_socket_dev_suspend(dev, state); - return ret; -} - -static int sa11x0_drv_pcmcia_resume(struct device *dev, u32 level) -{ - int ret = 0; - if (level == RESUME_RESTORE_STATE) - ret = pcmcia_socket_dev_resume(dev); - return ret; -} - static struct device_driver sa11x0_pcmcia_driver = { .probe = sa11x0_drv_pcmcia_probe, .remove = soc_common_drv_pcmcia_remove, .name = "sa11x0-pcmcia", .bus = &platform_bus_type, - .suspend = sa11x0_drv_pcmcia_suspend, - .resume = sa11x0_drv_pcmcia_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; /* sa11x0_pcmcia_init() diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c index bb90a1448a5..81ded52c895 100644 --- a/drivers/pcmcia/sa1111_generic.c +++ b/drivers/pcmcia/sa1111_generic.c @@ -122,7 +122,7 @@ void sa1111_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) static int pcmcia_probe(struct sa1111_dev *dev) { - char *base; + void __iomem *base; if (!request_mem_region(dev->res.start, 512, SA1111_DRIVER_NAME(dev))) diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 888b70e6a48..9e7ccd8a432 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -66,7 +66,7 @@ void soc_pcmcia_debug(struct soc_pcmcia_socket *skt, const char *func, if (pc_debug > lvl) { printk(KERN_DEBUG "skt%u: %s: ", skt->nr, func); va_start(args, fmt); - printk(fmt, args); + vprintk(fmt, args); va_end(args); } } @@ -321,8 +321,6 @@ soc_common_pcmcia_get_socket(struct pcmcia_socket *sock, socket_state_t *state) * less punt all of this work and let the kernel handle the details * of power configuration, reset, &c. We also record the value of * `state' in order to regurgitate it to the PCMCIA core later. - * - * Returns: 0 */ static int soc_common_pcmcia_set_socket(struct pcmcia_socket *sock, socket_state_t *state) @@ -407,7 +405,7 @@ soc_common_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *m * the map speed as requested, but override the address ranges * supplied by Card Services. * - * Returns: 0 on success, -1 on error + * Returns: 0 on success, -ERRNO on error */ static int soc_common_pcmcia_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *map) @@ -655,8 +653,8 @@ static void soc_pcmcia_cpufreq_unregister(void) } #else -#define soc_pcmcia_cpufreq_register() -#define soc_pcmcia_cpufreq_unregister() +static int soc_pcmcia_cpufreq_register(void) { return 0; } +static void soc_pcmcia_cpufreq_unregister(void) {} #endif int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr) @@ -738,7 +736,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops goto out_err_5; } - if ( list_empty(&soc_pcmcia_sockets) ) + if (list_empty(&soc_pcmcia_sockets)) soc_pcmcia_cpufreq_register(); list_add(&skt->node, &soc_pcmcia_sockets); @@ -839,7 +837,7 @@ int soc_common_drv_pcmcia_remove(struct device *dev) release_resource(&skt->res_io); release_resource(&skt->res_skt); } - if ( list_empty(&soc_pcmcia_sockets) ) + if (list_empty(&soc_pcmcia_sockets)) soc_pcmcia_cpufreq_unregister(); up(&soc_pcmcia_sockets_lock); diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c index 1040a6c1a8a..4a3150a7854 100644 --- a/drivers/pcmcia/socket_sysfs.c +++ b/drivers/pcmcia/socket_sysfs.c @@ -341,7 +341,8 @@ static struct bin_attribute pccard_cis_attr = { .write = pccard_store_cis, }; -static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev) +static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev, + struct class_interface *class_intf) { struct class_device_attribute **attr; int ret = 0; @@ -357,7 +358,8 @@ static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev) return ret; } -static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev) +static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev, + struct class_interface *class_intf) { struct class_device_attribute **attr; diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c index d5a61eae611..e3126386437 100644 --- a/drivers/pcmcia/tcic.c +++ b/drivers/pcmcia/tcic.c @@ -44,7 +44,7 @@ #include <linux/ioport.h> #include <linux/delay.h> #include <linux/workqueue.h> -#include <linux/device.h> +#include <linux/platform_device.h> #include <linux/bitops.h> #include <asm/io.h> @@ -372,27 +372,11 @@ static int __init get_tcic_id(void) /*====================================================================*/ -static int tcic_drv_suspend(struct device *dev, pm_message_t state, u32 level) -{ - int ret = 0; - if (level == SUSPEND_SAVE_STATE) - ret = pcmcia_socket_dev_suspend(dev, state); - return ret; -} - -static int tcic_drv_resume(struct device *dev, u32 level) -{ - int ret = 0; - if (level == RESUME_RESTORE_STATE) - ret = pcmcia_socket_dev_resume(dev); - return ret; -} - static struct device_driver tcic_driver = { .name = "tcic-pcmcia", .bus = &platform_bus_type, - .suspend = tcic_drv_suspend, - .resume = tcic_drv_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; static struct platform_device tcic_device = { diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h index fbe233e19ce..539b5cd1a59 100644 --- a/drivers/pcmcia/ti113x.h +++ b/drivers/pcmcia/ti113x.h @@ -59,6 +59,7 @@ #define TI122X_SCR_SER_STEP 0xc0000000 #define TI122X_SCR_INTRTIE 0x20000000 +#define TIXX21_SCR_TIEALL 0x10000000 #define TI122X_SCR_CBRSVD 0x00400000 #define TI122X_SCR_MRBURSTDN 0x00008000 #define TI122X_SCR_MRBURSTUP 0x00004000 @@ -153,6 +154,12 @@ /* EnE test register */ #define ENE_TEST_C9 0xc9 /* 8bit */ #define ENE_TEST_C9_TLTENABLE 0x02 +#define ENE_TEST_C9_PFENABLE_F0 0x04 +#define ENE_TEST_C9_PFENABLE_F1 0x08 +#define ENE_TEST_C9_PFENABLE (ENE_TEST_C9_PFENABLE_F0 | ENE_TEST_C9_PFENABLE_F0) +#define ENE_TEST_C9_WPDISALBLE_F0 0x40 +#define ENE_TEST_C9_WPDISALBLE_F1 0x80 +#define ENE_TEST_C9_WPDISALBLE (ENE_TEST_C9_WPDISALBLE_F0 | ENE_TEST_C9_WPDISALBLE_F1) /* * Texas Instruments CardBus controller overrides. @@ -618,6 +625,7 @@ static int ti12xx_2nd_slot_empty(struct yenta_socket *socket) int devfn; unsigned int state; int ret = 1; + u32 sysctl; /* catch the two-slot controllers */ switch (socket->dev->device) { @@ -640,6 +648,24 @@ static int ti12xx_2nd_slot_empty(struct yenta_socket *socket) */ break; + case PCI_DEVICE_ID_TI_X515: + case PCI_DEVICE_ID_TI_X420: + case PCI_DEVICE_ID_TI_X620: + case PCI_DEVICE_ID_TI_XX21_XX11: + case PCI_DEVICE_ID_TI_7410: + case PCI_DEVICE_ID_TI_7610: + /* + * those are either single or dual slot CB with additional functions + * like 1394, smartcard reader, etc. check the TIEALL flag for them + * the TIEALL flag binds the IRQ of all functions toghether. + * we catch the single slot variants later. + */ + sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL); + if (sysctl & TIXX21_SCR_TIEALL) + return 0; + + break; + /* single-slot controllers have the 2nd slot empty always :) */ default: return 1; @@ -652,6 +678,15 @@ static int ti12xx_2nd_slot_empty(struct yenta_socket *socket) if (!func) return 1; + /* + * check that the device id of both slots match. this is needed for the + * XX21 and the XX11 controller that share the same device id for single + * and dual slot controllers. return '2nd slot empty'. we already checked + * if the interrupt is tied to another function. + */ + if (socket->dev->device != func->device) + goto out; + slot2 = pci_get_drvdata(func); if (!slot2) goto out; @@ -791,16 +826,6 @@ static int ti12xx_override(struct yenta_socket *socket) config_writel(socket, TI113X_SYSTEM_CONTROL, val); /* - * for EnE bridges only: clear testbit TLTEnable. this makes the - * RME Hammerfall DSP sound card working. - */ - if (socket->dev->vendor == PCI_VENDOR_ID_ENE) { - u8 test_c9 = config_readb(socket, ENE_TEST_C9); - test_c9 &= ~ENE_TEST_C9_TLTENABLE; - config_writeb(socket, ENE_TEST_C9, test_c9); - } - - /* * Yenta expects controllers to use CSCINT to route * CSC interrupts to PCI rather than INTVAL. */ @@ -841,5 +866,78 @@ static int ti1250_override(struct yenta_socket *socket) return ti12xx_override(socket); } + +/** + * EnE specific part. EnE bridges are register compatible with TI bridges but + * have their own test registers and more important their own little problems. + * Some fixup code to make everybody happy (TM). + */ + +#ifdef CONFIG_CARDBUS +/** + * set/clear various test bits: + * Defaults to clear the bit. + * - mask (u8) defines what bits to change + * - bits (u8) is the values to change them to + * -> it's + * current = (current & ~mask) | bits + */ +/* pci ids of devices that wants to have the bit set */ +#define DEVID(_vend,_dev,_subvend,_subdev,mask,bits) { \ + .vendor = _vend, \ + .device = _dev, \ + .subvendor = _subvend, \ + .subdevice = _subdev, \ + .driver_data = ((mask) << 8 | (bits)), \ + } +static struct pci_device_id ene_tune_tbl[] = { + /* Echo Audio products based on motorola DSP56301 and DSP56361 */ + DEVID(PCI_VENDOR_ID_MOTOROLA, 0x1801, 0xECC0, PCI_ANY_ID, + ENE_TEST_C9_TLTENABLE | ENE_TEST_C9_PFENABLE, ENE_TEST_C9_TLTENABLE), + DEVID(PCI_VENDOR_ID_MOTOROLA, 0x3410, 0xECC0, PCI_ANY_ID, + ENE_TEST_C9_TLTENABLE | ENE_TEST_C9_PFENABLE, ENE_TEST_C9_TLTENABLE), + + {} +}; + +static void ene_tune_bridge(struct pcmcia_socket *sock, struct pci_bus *bus) +{ + struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); + struct pci_dev *dev; + struct pci_device_id *id = NULL; + u8 test_c9, old_c9, mask, bits; + + list_for_each_entry(dev, &bus->devices, bus_list) { + id = (struct pci_device_id *) pci_match_id(ene_tune_tbl, dev); + if (id) + break; + } + + test_c9 = old_c9 = config_readb(socket, ENE_TEST_C9); + if (id) { + mask = (id->driver_data >> 8) & 0xFF; + bits = id->driver_data & 0xFF; + + test_c9 = (test_c9 & ~mask) | bits; + } + else + /* default to clear TLTEnable bit, old behaviour */ + test_c9 &= ~ENE_TEST_C9_TLTENABLE; + + printk(KERN_INFO "yenta EnE: chaning testregister 0xC9, %02x -> %02x\n", old_c9, test_c9); + config_writeb(socket, ENE_TEST_C9, test_c9); +} + +static int ene_override(struct yenta_socket *socket) +{ + /* install tune_bridge() function */ + socket->socket.tune_bridge = ene_tune_bridge; + + return ti1250_override(socket); +} +#else +# define ene_override ti1250_override +#endif + #endif /* _LINUX_TI113X_H */ diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c index 17bb2da6752..38a028c725d 100644 --- a/drivers/pcmcia/vrc4171_card.c +++ b/drivers/pcmcia/vrc4171_card.c @@ -24,6 +24,7 @@ #include <linux/spinlock.h> #include <linux/sched.h> #include <linux/types.h> +#include <linux/platform_device.h> #include <asm/io.h> @@ -774,31 +775,11 @@ static int __devinit vrc4171_card_setup(char *options) __setup("vrc4171_card=", vrc4171_card_setup); -static int vrc4171_card_suspend(struct device *dev, pm_message_t state, u32 level) -{ - int retval = 0; - - if (level == SUSPEND_SAVE_STATE) - retval = pcmcia_socket_dev_suspend(dev, state); - - return retval; -} - -static int vrc4171_card_resume(struct device *dev, u32 level) -{ - int retval = 0; - - if (level == RESUME_RESTORE_STATE) - retval = pcmcia_socket_dev_resume(dev); - - return retval; -} - static struct device_driver vrc4171_card_driver = { .name = vrc4171_card_name, .bus = &platform_bus_type, - .suspend = vrc4171_card_suspend, - .resume = vrc4171_card_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; static int __devinit vrc4171_card_init(void) diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index ba4d78e5b12..ec6ab65f087 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -151,6 +151,40 @@ static void exca_writew(struct yenta_socket *socket, unsigned reg, u16 val) readb(socket->base + 0x800 + reg + 1); } +static ssize_t show_yenta_registers(struct device *yentadev, struct device_attribute *attr, char *buf) +{ + struct pci_dev *dev = to_pci_dev(yentadev); + struct yenta_socket *socket = pci_get_drvdata(dev); + int offset = 0, i; + + offset = snprintf(buf, PAGE_SIZE, "CB registers:"); + for (i = 0; i < 0x24; i += 4) { + unsigned val; + if (!(i & 15)) + offset += snprintf(buf + offset, PAGE_SIZE - offset, "\n%02x:", i); + val = cb_readl(socket, i); + offset += snprintf(buf + offset, PAGE_SIZE - offset, " %08x", val); + } + + offset += snprintf(buf + offset, PAGE_SIZE - offset, "\n\nExCA registers:"); + for (i = 0; i < 0x45; i++) { + unsigned char val; + if (!(i & 7)) { + if (i & 8) { + memcpy(buf + offset, " -", 2); + offset += 2; + } else + offset += snprintf(buf + offset, PAGE_SIZE - offset, "\n%02x:", i); + } + val = exca_readb(socket, i); + offset += snprintf(buf + offset, PAGE_SIZE - offset, " %02x", val); + } + buf[offset++] = '\n'; + return offset; +} + +static DEVICE_ATTR(yenta_registers, S_IRUSR, show_yenta_registers, NULL); + /* * Ugh, mixed-mode cardbus and 16-bit pccard state: things depend * on what kind of card is inserted.. @@ -559,12 +593,6 @@ static void yenta_interrogate(struct yenta_socket *socket) static int yenta_sock_init(struct pcmcia_socket *sock) { struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); - u16 bridge; - - bridge = config_readw(socket, CB_BRIDGE_CONTROL) & ~CB_BRIDGE_INTR; - if (!socket->cb_irq) - bridge |= CB_BRIDGE_INTR; - config_writew(socket, CB_BRIDGE_CONTROL, bridge); exca_writeb(socket, I365_GBLCTL, 0x00); exca_writeb(socket, I365_GENCTL, 0x00); @@ -771,6 +799,9 @@ static void yenta_close(struct pci_dev *dev) { struct yenta_socket *sock = pci_get_drvdata(dev); + /* Remove the register attributes */ + device_remove_file(&dev->dev, &dev_attr_yenta_registers); + /* we don't want a dying socket registered */ pcmcia_unregister_socket(&sock->socket); @@ -819,6 +850,7 @@ enum { CARDBUS_TYPE_TOPIC95, CARDBUS_TYPE_TOPIC97, CARDBUS_TYPE_O2MICRO, + CARDBUS_TYPE_ENE, }; /* @@ -865,6 +897,12 @@ static struct cardbus_type cardbus_type[] = { .override = o2micro_override, .restore_state = o2micro_restore_state, }, + [CARDBUS_TYPE_ENE] = { + .override = ene_override, + .save_state = ti_save_state, + .restore_state = ti_restore_state, + .sock_init = ti_init, + }, }; @@ -883,16 +921,8 @@ static unsigned int yenta_probe_irq(struct yenta_socket *socket, u32 isa_irq_mas { int i; unsigned long val; - u16 bridge_ctrl; u32 mask; - /* Set up ISA irq routing to probe the ISA irqs.. */ - bridge_ctrl = config_readw(socket, CB_BRIDGE_CONTROL); - if (!(bridge_ctrl & CB_BRIDGE_INTR)) { - bridge_ctrl |= CB_BRIDGE_INTR; - config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl); - } - /* * Probe for usable interrupts using the force * register to generate bogus card status events. @@ -914,9 +944,6 @@ static unsigned int yenta_probe_irq(struct yenta_socket *socket, u32 isa_irq_mas mask = probe_irq_mask(val) & 0xffff; - bridge_ctrl &= ~CB_BRIDGE_INTR; - config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl); - return mask; } @@ -944,18 +971,11 @@ static irqreturn_t yenta_probe_handler(int irq, void *dev_id, struct pt_regs *re /* probes the PCI interrupt, use only on override functions */ static int yenta_probe_cb_irq(struct yenta_socket *socket) { - u16 bridge_ctrl; - if (!socket->cb_irq) return -1; socket->probe_status = 0; - /* disable ISA interrupts */ - bridge_ctrl = config_readw(socket, CB_BRIDGE_CONTROL); - bridge_ctrl &= ~CB_BRIDGE_INTR; - config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl); - if (request_irq(socket->cb_irq, yenta_probe_handler, SA_SHIRQ, "yenta", socket)) { printk(KERN_WARNING "Yenta: request_irq() in yenta_probe_cb_irq() failed!\n"); return -1; @@ -966,7 +986,7 @@ static int yenta_probe_cb_irq(struct yenta_socket *socket) cb_writel(socket, CB_SOCKET_EVENT, -1); cb_writel(socket, CB_SOCKET_MASK, CB_CSTSMASK); cb_writel(socket, CB_SOCKET_FORCE, CB_FCARDSTS); - + msleep(100); /* disable interrupts */ @@ -1004,11 +1024,12 @@ static void yenta_config_init(struct yenta_socket *socket) { u16 bridge; struct pci_dev *dev = socket->dev; + struct pci_bus_region region; - pci_set_power_state(socket->dev, 0); + pcibios_resource_to_bus(socket->dev, ®ion, &dev->resource[0]); config_writel(socket, CB_LEGACY_MODE_BASE, 0); - config_writel(socket, PCI_BASE_ADDRESS_0, dev->resource[0].start); + config_writel(socket, PCI_BASE_ADDRESS_0, region.start); config_writew(socket, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY | @@ -1031,8 +1052,8 @@ static void yenta_config_init(struct yenta_socket *socket) * - PCI interrupts enabled if a PCI interrupt exists.. */ bridge = config_readw(socket, CB_BRIDGE_CONTROL); - bridge &= ~(CB_BRIDGE_CRST | CB_BRIDGE_PREFETCH1 | CB_BRIDGE_INTR | CB_BRIDGE_ISAEN | CB_BRIDGE_VGAEN); - bridge |= CB_BRIDGE_PREFETCH0 | CB_BRIDGE_POSTEN | CB_BRIDGE_INTR; + bridge &= ~(CB_BRIDGE_CRST | CB_BRIDGE_PREFETCH1 | CB_BRIDGE_ISAEN | CB_BRIDGE_VGAEN); + bridge |= CB_BRIDGE_PREFETCH0 | CB_BRIDGE_POSTEN; config_writew(socket, CB_BRIDGE_CONTROL, bridge); } @@ -1154,8 +1175,11 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i /* Register it with the pcmcia layer.. */ ret = pcmcia_register_socket(&socket->socket); - if (ret == 0) + if (ret == 0) { + /* Add the yenta register attributes */ + device_create_file(&dev->dev, &dev_attr_yenta_registers); goto out; + } unmap: iounmap(socket->base); @@ -1265,10 +1289,22 @@ static struct pci_device_id yenta_table [] = { CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1250, TI1250), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1410, TI1250), - CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1211, TI12XX), - CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1225, TI12XX), - CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1410, TI1250), - CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1420, TI12XX), + CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX21_XX11, TI12XX), + CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_X515, TI12XX), + CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_X420, TI12XX), + CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_X620, TI12XX), + CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_7410, TI12XX), + CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_7510, TI12XX), + CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_7610, TI12XX), + + CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_710, TI12XX), + CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_712, TI12XX), + CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_720, TI12XX), + CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_722, TI12XX), + CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1211, ENE), + CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1225, ENE), + CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1410, ENE), + CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1420, ENE), CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C465, RICOH), CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C466, RICOH), |