diff options
| author | Russell King <rmk@flint.arm.linux.org.uk> | 2003-03-30 11:14:49 +0100 |
|---|---|---|
| committer | Russell King <rmk@flint.arm.linux.org.uk> | 2003-03-30 11:14:49 +0100 |
| commit | 5e4301f1a686b8efeae458745928de2a4a75a2ec (patch) | |
| tree | 6cb2dcd7fb741c3bd3d32f7e8e292b376715e606 | |
| parent | 18e4786e89f773ff4bacebad598ae52151b1c4de (diff) | |
[PCMCIA] Reorganise SA11xx PCMCIA support.
The SA1100 PCMCIA structure didn't lend itself well to the device
model. With this reorganisation, we end up with a reasonable
structure which fits better with the driver model. It is now
obvious that SA11x0-based socket drivers are separate from
SA1111-based socket drivers, and are treated as two separate drivers
by the driver model.
29 files changed, 2237 insertions, 2834 deletions
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 357f836ea987..4cc8e3130ee2 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -82,10 +82,22 @@ config HD64465_PCMCIA config PCMCIA_SA1100 tristate "SA1100 support" depends on ARM && ARCH_SA1100 && PCMCIA + help + Say Y here to include support for SA11x0-based PCMCIA or CF + sockets, found on HP iPAQs, Yopy, and other StrongARM(R)/ + Xscale(R) embedded machines. + + This driver is also available as a module called sa1100_cs. config PCMCIA_SA1111 tristate "SA1111 support" - depends on PCMCIA_SA1100 && SA1111 + depends on ARM && ARCH_SA1100 && SA1111 && PCMCIA + help + Say Y here to include support for SA1111-based PCMCIA or CF + sockets, found on the Jornada 720, Graphicsmaster and other + StrongARM(R)/Xscale(R) embedded machines. + + This driver is also available as a module called sa1111_cs. config PCMCIA_PROBE bool diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index 9a593be3f399..32c8efc83192 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -11,8 +11,8 @@ obj-$(CONFIG_I82365) += i82365.o obj-$(CONFIG_I82092) += i82092.o obj-$(CONFIG_TCIC) += tcic.o obj-$(CONFIG_HD64465_PCMCIA) += hd64465_ss.o -obj-$(CONFIG_PCMCIA_SA1100) += sa1100_cs.o -obj-$(CONFIG_PCMCIA_SA1111) += sa1111_cs.o +obj-$(CONFIG_PCMCIA_SA1100) += sa11xx_core.o sa1100_cs.o +obj-$(CONFIG_PCMCIA_SA1111) += sa11xx_core.o sa1111_cs.o yenta_socket-y += pci_socket.o yenta.o diff --git a/drivers/pcmcia/sa1100.h b/drivers/pcmcia/sa1100.h index 01ba55d3adad..d2defe598531 100644 --- a/drivers/pcmcia/sa1100.h +++ b/drivers/pcmcia/sa1100.h @@ -152,36 +152,6 @@ static inline unsigned int sa1100_pcmcia_cmd_time(unsigned int cpu_clock_khz, struct pcmcia_low_level; -/* This structure encapsulates per-socket state which we might need to - * use when responding to a Card Services query of some kind. - */ -struct sa1100_pcmcia_socket { - /* - * Core PCMCIA state - */ - int nr; - struct resource res; - socket_state_t cs_state; - pccard_io_map io_map[MAX_IO_WIN]; - pccard_mem_map pc_mem_map[MAX_WIN]; - 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; - unsigned int irq_state; - - struct pcmcia_low_level *ops; -}; - - /* I/O pins replacing memory pins * (PCMCIA System Architecture, 2nd ed., by Don Anderson, p.75) * @@ -191,59 +161,4 @@ struct sa1100_pcmcia_socket { #define iostschg bvd1 #define iospkr bvd2 - -/* - * Declaration for all machine specific init/exit functions. - */ -extern int pcmcia_adsbitsy_init(struct device *); -extern void pcmcia_adsbitsy_exit(struct device *); - -extern int pcmcia_assabet_init(struct device *); -extern void pcmcia_assabet_exit(struct device *); - -extern int pcmcia_badge4_init(struct device *); -extern void pcmcia_badge4_exit(struct device *); - -extern int pcmcia_cerf_init(struct device *); -extern void pcmcia_cerf_exit(struct device *); - -extern int pcmcia_flexanet_init(struct device *); -extern void pcmcia_flexanet_exit(struct device *); - -extern int pcmcia_freebird_init(struct device *); -extern void pcmcia_freebird_exit(struct device *); - -extern int pcmcia_gcplus_init(struct device *); -extern void pcmcia_gcplus_exit(struct device *); - -extern int pcmcia_graphicsmaster_init(struct device *); -extern void pcmcia_graphicsmaster_exit(struct device *); - -extern int pcmcia_pangolin_init(struct device *); -extern void pcmcia_pangolin_exit(struct device *); - -extern int pcmcia_pfs168_init(struct device *); -extern void pcmcia_pfs168_exit(struct device *); - -extern int pcmcia_shannon_init(struct device *); -extern void pcmcia_shannon_exit(struct device *); - -extern int pcmcia_simpad_init(struct device *); -extern void pcmcia_simpad_exit(struct device *); - -extern int pcmcia_stork_init(struct device *); -extern void pcmcia_stork_exit(struct device *); - -extern int pcmcia_system3_init(struct device *); -extern void pcmcia_system3_exit(struct device *); - -extern int pcmcia_trizeps_init(struct device *); -extern void pcmcia_trizeps_exit(struct device *); - -extern int pcmcia_xp860_init(struct device *); -extern void pcmcia_xp860_exit(struct device *); - -extern int pcmcia_yopy_init(struct device *); -extern void pcmcia_yopy_exit(struct device *); - #endif /* !defined(_PCMCIA_SA1100_H) */ diff --git a/drivers/pcmcia/sa1100_adsbitsy.c b/drivers/pcmcia/sa1100_adsbitsy.c index d3da971f7c49..c60c66b0e984 100644 --- a/drivers/pcmcia/sa1100_adsbitsy.c +++ b/drivers/pcmcia/sa1100_adsbitsy.c @@ -18,93 +18,86 @@ #include <asm/hardware.h> #include <asm/mach-types.h> -#include "sa1100_generic.h" #include "sa1111_generic.h" -static int adsbitsy_pcmcia_init(struct pcmcia_init *init) +static int adsbitsy_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { - /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */ - PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); + /* 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; + /* Disable Power 3.3V/5V for PCMCIA/CF */ + PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3; - /* Why? */ - MECR = 0x09430943; + /* Why? */ + MECR = 0x09430943; - return sa1111_pcmcia_init(init); + return sa1111_pcmcia_init(skt); } static int -adsbitsy_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) +adsbitsy_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, const socket_state_t *state) { - unsigned int pa_dwr_mask, pa_dwr_set; - int ret; - - switch (sock) { - case 0: - pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1; - - switch (conf->vcc) { - default: - 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; - } - break; - - case 1: - pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3; - - 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; - } - - default: - return -1; - } - - 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(sock, 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 ret; + unsigned int pa_dwr_mask, pa_dwr_set; + int ret; + + switch (skt->nr) { + case 0: + pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1; + + switch (state->Vcc) { + default: + 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; + } + break; + + case 1: + pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3; + + switch (state->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; + } + + default: + return -1; + } + + if (state->Vpp != state->Vcc && state->Vpp != 0) { + printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n", + __FUNCTION__, state->Vpp); + return -1; + } + + ret = sa1111_pcmcia_configure_socket(skt, state); + 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 ret; } static struct pcmcia_low_level adsbitsy_pcmcia_ops = { - .owner = THIS_MODULE, - .init = adsbitsy_pcmcia_init, - .shutdown = sa1111_pcmcia_shutdown, - .socket_state = sa1111_pcmcia_socket_state, - .configure_socket = adsbitsy_pcmcia_configure_socket, - - .socket_init = sa1111_pcmcia_socket_init, - .socket_suspend = sa1111_pcmcia_socket_suspend, + .owner = THIS_MODULE, + .hw_init = adsbitsy_pcmcia_hw_init, + .hw_shutdown = sa1111_pcmcia_hw_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .configure_socket = adsbitsy_pcmcia_configure_socket, + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_adsbitsy_init(struct device *dev) { int ret = -ENODEV; if (machine_is_adsbitsy()) - ret = sa1100_register_pcmcia(&adsbitsy_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &adsbitsy_pcmcia_ops, 0, 2); return ret; } - -void __exit pcmcia_adsbitsy_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&adsbitsy_pcmcia_ops, dev); -} diff --git a/drivers/pcmcia/sa1100_assabet.c b/drivers/pcmcia/sa1100_assabet.c index acf86535d9ff..e25e160d7e61 100644 --- a/drivers/pcmcia/sa1100_assabet.c +++ b/drivers/pcmcia/sa1100_assabet.c @@ -20,85 +20,47 @@ #include "sa1100_generic.h" -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 struct pcmcia_irqs irqs[] = { + { 1, ASSABET_IRQ_GPIO_CF_CD, "CF CD" }, + { 1, ASSABET_IRQ_GPIO_CF_BVD2, "CF BVD2" }, + { 1, ASSABET_IRQ_GPIO_CF_BVD1, "CF BVD1" }, }; -static int assabet_pcmcia_init(struct pcmcia_init *init) +static int assabet_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { - int i, res; - - /* Register interrupts */ - for (i = 0; i < ARRAY_SIZE(irqs); i++) { - res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt, - SA_INTERRUPT, irqs[i].str, NULL); - if (res) - goto irq_err; - set_irq_type(irqs[i].irq, IRQT_NOEDGE); - } - - init->socket_irq[0] = NO_IRQ; - init->socket_irq[1] = ASSABET_IRQ_GPIO_CF_IRQ; - - /* There's only one slot, but it's "Slot 1": */ - return 2; - - irq_err: - printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n", - __FUNCTION__, irqs[i].irq, res); + skt->irq = ASSABET_IRQ_GPIO_CF_IRQ; - while (i--) - free_irq(irqs[i].irq, NULL); - - return res; + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } /* * Release all resources. */ -static int assabet_pcmcia_shutdown(void) +static void assabet_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt) { - int i; - - for (i = 0; i < ARRAY_SIZE(irqs); i++) - free_irq(irqs[i].irq, NULL); - - return 0; + sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); } static void -assabet_pcmcia_socket_state(int sock, struct pcmcia_state *state) +assabet_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, struct pcmcia_state *state) { unsigned long levels = GPLR; - if (sock == 1) { - state->detect = (levels & ASSABET_GPIO_CF_CD) ? 0 : 1; - state->ready = (levels & ASSABET_GPIO_CF_IRQ) ? 1 : 0; - state->bvd1 = (levels & ASSABET_GPIO_CF_BVD1) ? 1 : 0; - state->bvd2 = (levels & ASSABET_GPIO_CF_BVD2) ? 1 : 0; - state->wrprot = 0; /* Not available on Assabet. */ - state->vs_3v = 1; /* Can only apply 3.3V on Assabet. */ - state->vs_Xv = 0; - } + state->detect = (levels & ASSABET_GPIO_CF_CD) ? 0 : 1; + state->ready = (levels & ASSABET_GPIO_CF_IRQ) ? 1 : 0; + state->bvd1 = (levels & ASSABET_GPIO_CF_BVD1) ? 1 : 0; + state->bvd2 = (levels & ASSABET_GPIO_CF_BVD2) ? 1 : 0; + state->wrprot = 0; /* Not available on Assabet. */ + state->vs_3v = 1; /* Can only apply 3.3V on Assabet. */ + state->vs_Xv = 0; } static int -assabet_pcmcia_configure_socket(int sock, const struct pcmcia_configure *configure) +assabet_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, const socket_state_t *state) { unsigned int mask; - if (sock > 1) - return -1; - - if (sock == 0) - return 0; - - switch (configure->vcc) { + switch (state->Vcc) { case 0: mask = 0; break; @@ -113,13 +75,13 @@ assabet_pcmcia_configure_socket(int sock, const struct pcmcia_configure *configu default: printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); + state->Vcc); return -1; } /* Silently ignore Vpp, output enable, speaker enable. */ - if (configure->reset) + if (state->flags & SS_RESET) mask |= ASSABET_BCR_CF_RST; ASSABET_BCR_frob(ASSABET_BCR_CF_RST | ASSABET_BCR_CF_PWR, mask); @@ -132,48 +94,36 @@ assabet_pcmcia_configure_socket(int sock, const struct pcmcia_configure *configu * be called at initialisation, power management event, or * pcmcia event. */ -static int assabet_pcmcia_socket_init(int sock) +static void assabet_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { - int i; - - if (sock == 1) { - /* - * Enable CF bus - */ - ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF); - - for (i = 0; i < ARRAY_SIZE(irqs); i++) - set_irq_type(irqs[i].irq, IRQT_BOTHEDGE); - } + /* + * Enable CF bus + */ + ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF); - return 0; + sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } /* * Disable card status IRQs on suspend. */ -static int assabet_pcmcia_socket_suspend(int sock) +static void assabet_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - int i; - - if (sock == 1) { - for (i = 0; i < ARRAY_SIZE(irqs); i++) - set_irq_type(irqs[i].irq, IRQT_NOEDGE); - - /* - * 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); - } + sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); - return 0; + /* + * 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); } static struct pcmcia_low_level assabet_pcmcia_ops = { .owner = THIS_MODULE, - .init = assabet_pcmcia_init, - .shutdown = assabet_pcmcia_shutdown, + + .hw_init = assabet_pcmcia_hw_init, + .hw_shutdown = assabet_pcmcia_hw_shutdown, + .socket_state = assabet_pcmcia_socket_state, .configure_socket = assabet_pcmcia_configure_socket, @@ -185,20 +135,8 @@ int __init pcmcia_assabet_init(struct device *dev) { int ret = -ENODEV; - if (machine_is_assabet()) { - if (!machine_has_neponset()) - ret = sa1100_register_pcmcia(&assabet_pcmcia_ops, dev); -#ifndef CONFIG_ASSABET_NEPONSET - else - printk(KERN_ERR "Card Services disabled: missing " - "Neponset support\n"); -#endif - } - return ret; -} + if (machine_is_assabet() && !machine_has_neponset()) + ret = sa11xx_drv_pcmcia_probe(dev, &assabet_pcmcia_ops, 1, 1); -void __exit pcmcia_assabet_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&assabet_pcmcia_ops, dev); + return ret; } - diff --git a/drivers/pcmcia/sa1100_badge4.c b/drivers/pcmcia/sa1100_badge4.c index bbc5bdffea0f..6a70fb6093d3 100644 --- a/drivers/pcmcia/sa1100_badge4.c +++ b/drivers/pcmcia/sa1100_badge4.c @@ -24,7 +24,6 @@ #include <asm/arch/badge4.h> #include <asm/hardware/sa1111.h> -#include "sa1100_generic.h" #include "sa1111_generic.h" /* @@ -62,27 +61,6 @@ static int badge4_pcmvcc = 50; /* pins 3 and 5 jumpered on JP6 */ static int badge4_pcmvpp = 50; /* pins 2 and 4 jumpered on JP6 */ static int badge4_cfvcc = 33; /* pins 1 and 2 jumpered on JP10 */ -static int badge4_pcmcia_init(struct pcmcia_init *init) -{ - printk(KERN_INFO - "%s: badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n", - __FUNCTION__, - 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 5v0 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) @@ -97,32 +75,32 @@ static void complain_about_jumpering(const char *whom, } static int -badge4_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) +badge4_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, const socket_state_t *state) { int ret; - switch (sock) { + switch (skt->nr) { case 0: - if ((conf->vcc != 0) && - (conf->vcc != badge4_pcmvcc)) { + if ((state->Vcc != 0) && + (state->Vcc != badge4_pcmvcc)) { complain_about_jumpering(__FUNCTION__, "pcmvcc", - badge4_pcmvcc, conf->vcc); + badge4_pcmvcc, state->Vcc); // Apply power regardless of the jumpering. // return -1; } - if ((conf->vpp != 0) && - (conf->vpp != badge4_pcmvpp)) { + if ((state->Vpp != 0) && + (state->Vpp != badge4_pcmvpp)) { complain_about_jumpering(__FUNCTION__, "pcmvpp", - badge4_pcmvpp, conf->vpp); + badge4_pcmvpp, state->Vpp); return -1; } break; case 1: - if ((conf->vcc != 0) && - (conf->vcc != badge4_cfvcc)) { + if ((state->Vcc != 0) && + (state->Vcc != badge4_cfvcc)) { complain_about_jumpering(__FUNCTION__, "cfvcc", - badge4_cfvcc, conf->vcc); + badge4_cfvcc, state->Vcc); return -1; } break; @@ -131,16 +109,16 @@ badge4_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) return -1; } - ret = sa1111_pcmcia_configure_socket(sock, conf); + ret = sa1111_pcmcia_configure_socket(skt, state); if (ret == 0) { unsigned long flags; int need5V; local_irq_save(flags); - need5V = ((conf->vcc == 50) || (conf->vpp == 50)); + need5V = ((state->Vcc == 50) || (state->Vpp == 50)); - badge4_set_5V(BADGE4_5V_PCMCIA_SOCK(conf->sock), need5V); + badge4_set_5V(BADGE4_5V_PCMCIA_SOCK(skt->nr), need5V); local_irq_restore(flags); } @@ -150,8 +128,8 @@ badge4_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) static struct pcmcia_low_level badge4_pcmcia_ops = { .owner = THIS_MODULE, - .init = badge4_pcmcia_init, - .shutdown = badge4_pcmcia_shutdown, + .init = sa1111_pcmcia_hw_init, + .shutdown = sa1111_pcmcia_hw_shutdown, .socket_state = sa1111_pcmcia_socket_state, .configure_socket = badge4_pcmcia_configure_socket, @@ -163,15 +141,16 @@ int pcmcia_badge4_init(struct device *dev) { int ret = -ENODEV; - if (machine_is_badge4()) - ret = sa1100_register_pcmcia(&badge4_pcmcia_ops, dev); + if (machine_is_badge4()) { + printk(KERN_INFO + "%s: badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n", + __FUNCTION__, + badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc); - return ret; -} + ret = sa11xx_drv_pcmcia_probe(dev, &badge4_pcmcia_ops, 0, 2); + } -void __devexit pcmcia_badge4_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&badge4_pcmcia_ops, dev); + return ret; } static int __init pcmv_setup(char *s) diff --git a/drivers/pcmcia/sa1100_cerf.c b/drivers/pcmcia/sa1100_cerf.c index 7485a31fd74e..1f22aa2da907 100644 --- a/drivers/pcmcia/sa1100_cerf.c +++ b/drivers/pcmcia/sa1100_cerf.c @@ -23,139 +23,91 @@ #define CERF_SOCKET 1 #endif -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" } +static struct pcmcia_irqs irqs[] = { + { CERF_SOCKET, IRQ_GPIO_CF_CD, "CF_CD" }, + { CERF_SOCKET, IRQ_GPIO_CF_BVD2, "CF_BVD2" }, + { CERF_SOCKET, IRQ_GPIO_CF_BVD1, "CF_BVD1" } }; -static int cerf_pcmcia_init(struct pcmcia_init *init) +static int cerf_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { - int i, res; + skt->irq = IRQ_GPIO_CF_IRQ; - for (i = 0; i < ARRAY_SIZE(irqs); i++) { - res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt, SA_INTERRUPT, - irqs[i].str, NULL); - if (res) - goto irq_err; - set_irq_type(irqs[i].irq, IRQT_NOEDGE); - } - - init->socket_irq[CERF_SOCKET] = IRQ_GPIO_CF_IRQ; - - 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; + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int cerf_pcmcia_shutdown(void) +static void cerf_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt) { - int i; - - for (i = 0; i < ARRAY_SIZE(irqs); i++) - free_irq(irqs[i].irq, NULL); - - return 0; + sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static void cerf_pcmcia_socket_state(int sock, struct pcmcia_state *state) +static void +cerf_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, struct pcmcia_state *state) { - unsigned long levels=GPLR; - - if (sock == CERF_SOCKET) { - state->detect=((levels & GPIO_CF_CD)==0)?1:0; - state->ready=(levels & GPIO_CF_IRQ)?1:0; - state->bvd1=(levels & GPIO_CF_BVD1)?1:0; - state->bvd2=(levels & GPIO_CF_BVD2)?1:0; - state->wrprot=0; - state->vs_3v=1; - state->vs_Xv=0; - } + unsigned long levels = GPLR; + + state->detect=((levels & GPIO_CF_CD)==0)?1:0; + state->ready=(levels & GPIO_CF_IRQ)?1:0; + state->bvd1=(levels & GPIO_CF_BVD1)?1:0; + state->bvd2=(levels & GPIO_CF_BVD2)?1:0; + state->wrprot=0; + state->vs_3v=1; + state->vs_Xv=0; } -static int cerf_pcmcia_configure_socket(int sock, const struct pcmcia_configure - *configure) +static int +cerf_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, + const socket_state_t *state) { - if (sock>1) - return -1; - - if (sock != CERF_SOCKET) - return 0; + switch (state->Vcc) { + case 0: + break; - switch(configure->vcc){ - case 0: - break; - - case 50: - case 33: + case 50: + case 33: #ifdef CONFIG_SA1100_CERF_CPLD - GPCR = GPIO_PWR_SHUTDOWN; + GPCR = GPIO_PWR_SHUTDOWN; #endif - break; + break; - default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; - } + default: + printk(KERN_ERR "%s(): unrecognized Vcc %u\n", + __FUNCTION__, state->Vcc); + return -1; + } - if(configure->reset) - { + if (state->flags & SS_RESET) { #ifdef CONFIG_SA1100_CERF_CPLD - GPSR = GPIO_CF_RESET; + GPSR = GPIO_CF_RESET; #endif - } - else - { + } else { #ifdef CONFIG_SA1100_CERF_CPLD - GPCR = GPIO_CF_RESET; + GPCR = GPIO_CF_RESET; #endif - } + } - return 0; + return 0; } -static int cerf_pcmcia_socket_init(int sock) +static void cerf_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { - int i; - - if (sock == CERF_SOCKET) - for (i = 0; i < ARRAY_SIZE(irqs); i++) - set_irq_type(irqs[i].irq, IRQT_BOTHEDGE); - - return 0; + sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int cerf_pcmcia_socket_suspend(int sock) +static void cerf_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - int i; - - if (sock == CERF_SOCKET) - for (i = 0; i < ARRAY_SIZE(irqs); i++) - set_irq_type(irqs[i].irq, IRQT_NOEDGE); - - return 0; + sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } static struct pcmcia_low_level cerf_pcmcia_ops = { - .owner = THIS_MODULE, - .init = cerf_pcmcia_init, - .shutdown = cerf_pcmcia_shutdown, - .socket_state = cerf_pcmcia_socket_state, - .configure_socket = cerf_pcmcia_configure_socket, - - .socket_init = cerf_pcmcia_socket_init, - .socket_suspend = cerf_pcmcia_socket_suspend, + .owner = THIS_MODULE, + .init = cerf_pcmcia_hw_init, + .shutdown = cerf_pcmcia_hw_shutdown, + .socket_state = cerf_pcmcia_socket_state, + .configure_socket = cerf_pcmcia_configure_socket, + + .socket_init = cerf_pcmcia_socket_init, + .socket_suspend = cerf_pcmcia_socket_suspend, }; int __init pcmcia_cerf_init(struct device *dev) @@ -163,12 +115,7 @@ int __init pcmcia_cerf_init(struct device *dev) int ret = -ENODEV; if (machine_is_cerf()) - ret = sa1100_register_pcmcia(&cerf_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &cerf_pcmcia_ops, CERF_SOCKET, 1); return ret; } - -void __exit pcmcia_cerf_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&cerf_pcmcia_ops, dev); -} diff --git a/drivers/pcmcia/sa1100_flexanet.c b/drivers/pcmcia/sa1100_flexanet.c index c64e961eff50..538f84c364c2 100644 --- a/drivers/pcmcia/sa1100_flexanet.c +++ b/drivers/pcmcia/sa1100_flexanet.c @@ -16,69 +16,32 @@ #include <asm/irq.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" } +static struct pcmcia_irqs irqs[] = { + { 0, IRQ_GPIO_CF1_CD, "CF1_CD" }, + { 0, IRQ_GPIO_CF1_BVD1, "CF1_BVD1" }, + { 1, IRQ_GPIO_CF2_CD, "CF2_CD" }, + { 1, IRQ_GPIO_CF2_BVD1, "CF2_BVD1" } }; /* * Socket initialization. * * Called by sa1100_pcmcia_driver_init on startup. - * Must return the number of slots. - * */ -static int flexanet_pcmcia_init(struct pcmcia_init *init) +static int flexanet_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { - 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 ); - - /* Register the socket interrupts (not the card interrupts) */ - for (i = 0; i < ARRAY_SIZE(irqs); i++) { - res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt, SA_INTERRUPT, - irqs[i].name, NULL); - if (res < 0) - break; - set_irq_type(irqs[i].irq, IRQT_NOEDGE); - } - - init->socket_irq[0] = IRQ_GPIO_CF1_IRQ; - init->socket_irq[1] = IRQ_GPIO_CF2_IRQ; - - /* 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; + skt->irq = skt->nr ? IRQ_GPIO_CF2_IRQ : IRQ_GPIO_CF1_IRQ; + + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } /* * Socket shutdown - * */ -static int flexanet_pcmcia_shutdown(void) +static void flexanet_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt) { - int i; - - /* disable IRQs */ - for (i = 0; i < ARRAY_SIZE(irqs); i++) - free_irq(irqs[i].irq, NULL); - - return 0; + sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); } @@ -88,109 +51,96 @@ static int flexanet_pcmcia_shutdown(void) * Sockets in Flexanet are 3.3V only, without BVD2. * */ -static void flexanet_pcmcia_socket_state(int sock, struct pcmcia_state *state) +static void +flexanet_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, + struct pcmcia_state *state) { - unsigned long levels = GPLR; /* Sense the GPIOs, asynchronously */ - - switch (sock) { - case 0: /* Socket 0 */ - state->detect = ((levels & GPIO_CF1_NCD)==0)?1:0; - state->ready = (levels & GPIO_CF1_IRQ)?1:0; - state->bvd1 = (levels & GPIO_CF1_BVD1)?1:0; - state->bvd2 = 1; - state->wrprot = 0; - state->vs_3v = 1; - state->vs_Xv = 0; - break; - - case 1: /* Socket 1 */ - state->detect = ((levels & GPIO_CF2_NCD)==0)?1:0; - state->ready = (levels & GPIO_CF2_IRQ)?1:0; - state->bvd1 = (levels & GPIO_CF2_BVD1)?1:0; - state->bvd2 = 1; - state->wrprot = 0; - state->vs_3v = 1; - state->vs_Xv = 0; - break; - } + unsigned long levels = GPLR; /* Sense the GPIOs, asynchronously */ + + switch (skt->nr) { + ase 0: /* Socket 0 */ + state->detect = ((levels & GPIO_CF1_NCD)==0)?1:0; + state->ready = (levels & GPIO_CF1_IRQ)?1:0; + state->bvd1 = (levels & GPIO_CF1_BVD1)?1:0; + state->bvd2 = 1; + state->wrprot = 0; + state->vs_3v = 1; + state->vs_Xv = 0; + break; + + case 1: /* Socket 1 */ + state->detect = ((levels & GPIO_CF2_NCD)==0)?1:0; + state->ready = (levels & GPIO_CF2_IRQ)?1:0; + state->bvd1 = (levels & GPIO_CF2_BVD1)?1:0; + state->bvd2 = 1; + state->wrprot = 0; + state->vs_3v = 1; + state->vs_Xv = 0; + break; + } } /* * */ -static int flexanet_pcmcia_configure_socket(int sock, const struct pcmcia_configure - *configure) +static int +flexanet_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, + const socket_state_t *state) { - unsigned long value, flags, mask; + unsigned long value, flags, mask; - if (sock > 1) - return -1; + /* Ignore the VCC level since it is 3.3V and always on */ + switch (state->Vcc) { + case 0: + printk(KERN_WARNING "%s(): CS asked to power off.\n", + __FUNCTION__); + break; - /* 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 50: - printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n", - __FUNCTION__); + case 33: + break; - case 33: - break; + default: + printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, + state->Vcc); + return -1; + } - 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; - /* Reset the slot(s) using the controls in the BCR */ - mask = 0; + switch (skt->nr) { + case 0: + mask = FHH_BCR_CF1_RST; + break; + case 1: + mask = FHH_BCR_CF2_RST; + break; + } - switch (sock) - { - case 0 : mask = FHH_BCR_CF1_RST; break; - case 1 : mask = FHH_BCR_CF2_RST; break; - } + local_irq_save(flags); - local_irq_save(flags); + value = flexanet_BCR; + value = (state->flags & SS_RESET) ? (value | mask) : (value & ~mask); + FHH_BCR = flexanet_BCR = value; - value = flexanet_BCR; - value = (configure->reset) ? (value | mask) : (value & ~mask); - FHH_BCR = flexanet_BCR = value; + local_irq_restore(flags); - local_irq_restore(flags); - - return 0; + return 0; } -static int flexanet_pcmcia_socket_init(int sock) +static void flexanet_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { - 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; + sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int flexanet_pcmcia_socket_suspend(int sock) +static void flexanet_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - 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; + sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } /* @@ -198,14 +148,13 @@ static int flexanet_pcmcia_socket_suspend(int sock) * */ static struct pcmcia_low_level flexanet_pcmcia_ops = { - .owner = THIS_MODULE, - .init = flexanet_pcmcia_init, - .shutdown = flexanet_pcmcia_shutdown, - .socket_state = flexanet_pcmcia_socket_state, - .configure_socket = flexanet_pcmcia_configure_socket, - - .socket_init = flexanet_pcmcia_socket_init, - .socket_suspend = flexanet_pcmcia_socket_suspend, + .owner = THIS_MODULE, + .hw_init = flexanet_pcmcia_hw_init, + .hw_shutdown = flexanet_pcmcia_hw_shutdown, + .socket_state = flexanet_pcmcia_socket_state, + .configure_socket = flexanet_pcmcia_configure_socket, + .socket_init = flexanet_pcmcia_socket_init, + .socket_suspend = flexanet_pcmcia_socket_suspend, }; int __init pcmcia_flexanet_init(struct device *dev) @@ -213,13 +162,7 @@ int __init pcmcia_flexanet_init(struct device *dev) int ret = -ENODEV; if (machine_is_flexanet()) - ret = sa1100_register_pcmcia(&flexanet_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &flexanet_pcmcia_ops, 0, 2); return ret; } - -void __exit pcmcia_flexanet_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&flexanet_pcmcia_ops, dev); -} - diff --git a/drivers/pcmcia/sa1100_freebird.c b/drivers/pcmcia/sa1100_freebird.c index 37ac401f52f4..57c77d93574b 100644 --- a/drivers/pcmcia/sa1100_freebird.c +++ b/drivers/pcmcia/sa1100_freebird.c @@ -15,155 +15,113 @@ #include <asm/irq.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 struct pcmcia_irqs irqs[] = { + { 0, IRQ_GPIO_FREEBIRD_CF_CD, "CF_CD" }, + { 0, IRQ_GPIO_FREEBIRD_CF_BVD, "CF_BVD1" }, }; -static int freebird_pcmcia_init(struct pcmcia_init *init){ - int i, res; - - /* Enable Linkup CF card */ - LINKUP_PRC = 0xc0; - mdelay(100); - LINKUP_PRC = 0xc1; - mdelay(100); - LINKUP_PRC = 0xd1; - mdelay(100); - LINKUP_PRC = 0xd1; - mdelay(100); - LINKUP_PRC = 0xc0; - - /* Register interrupts */ - for (i = 0; i < ARRAY_SIZE(irqs); i++) { - res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt, SA_INTERRUPT, - irqs[i].str, NULL); - if (res) - goto irq_err; - set_irq_type(irqs[i].irq, IRQT_NOEDGE); - } - - init->socket_irq[0] = IRQ_GPIO_FREEBIRD_CF_IRQ; - - /* There's only one slot, but it's "Slot 1": */ - 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 freebird_pcmcia_init(struct sa1100_pcmcia_socket *skt) +{ + /* Enable Linkup CF card */ + LINKUP_PRC = 0xc0; + mdelay(100); + LINKUP_PRC = 0xc1; + mdelay(100); + LINKUP_PRC = 0xd1; + mdelay(100); + LINKUP_PRC = 0xd1; + mdelay(100); + LINKUP_PRC = 0xc0; + + skt->irq = IRQ_GPIO_FREEBIRD_CF_IRQ; + + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int freebird_pcmcia_shutdown(void) +static void freebird_pcmcia_shutdown(struct sa1100_pcmcia_socket *skt) { - int i; - - /* disable IRQs */ - for (i = 0; i < ARRAY_SIZE(irqs); i++) - free_irq(irqs[i].irq, NULL); - - /* Disable CF card */ - LINKUP_PRC = 0x40; /* SSP=1 SOE=0 */ - mdelay(100); + sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs); - return 0; + /* Disable CF card */ + LINKUP_PRC = 0x40; /* SSP=1 SOE=0 */ + mdelay(100); } -static void freebird_pcmcia_socket_state(int sock, struct pcmcia_state *state) +static void +freebird_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, struct pcmcia_state *state) { - unsigned long levels = LINKUP_PRS; -//printk("LINKUP_PRS=%x\n",levels); - - if (sock == 0) { - state->detect = ((levels & (LINKUP_CD1 | LINKUP_CD2))==0)?1:0; - state->ready = (levels & LINKUP_RDY)?1:0; - state->bvd1 = (levels & LINKUP_BVD1)?1:0; - state->bvd2 = (levels & LINKUP_BVD2)?1:0; - state->wrprot = 0; /* Not available on Assabet. */ - state->vs_3v = 1; /* Can only apply 3.3V on Assabet. */ - state->vs_Xv = 0; - } + unsigned long levels = LINKUP_PRS; +// printk("LINKUP_PRS=%x\n",levels); + + state->detect = ((levels & (LINKUP_CD1 | LINKUP_CD2))==0)?1:0; + state->ready = (levels & LINKUP_RDY)?1:0; + state->bvd1 = (levels & LINKUP_BVD1)?1:0; + state->bvd2 = (levels & LINKUP_BVD2)?1:0; + state->wrprot = 0; /* Not available on Assabet. */ + state->vs_3v = 1; /* Can only apply 3.3V on Assabet. */ + state->vs_Xv = 0; } -static int freebird_pcmcia_configure_socket(int sock, const struct pcmcia_configure - *configure) +static int +freebird_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, + socket_state_t *state) { - unsigned long value, flags; - - if(sock>1) return -1; - - if(sock==1) return 0; + unsigned long value, flags; - local_irq_save(flags); + local_irq_save(flags); - value = 0xc0; /* SSP=1 SOE=1 CFE=1 */ + value = 0xc0; /* SSP=1 SOE=1 CFE=1 */ - switch(configure->vcc){ - case 0: + switch (state->Vcc) { + case 0: + break; - break; + case 50: + printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n", + __FUNCTION__); - case 50: - printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n", - __FUNCTION__); + case 33: /* Can only apply 3.3V to the CF slot. */ + value |= LINKUP_S1; + break; - case 33: /* Can only apply 3.3V to the CF slot. */ - value |= LINKUP_S1; - break; + default: + printk(KERN_ERR "%s(): unrecognized Vcc %u\n", + __FUNCTION__, state->Vcc); + local_irq_restore(flags); + return -1; + } - default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - local_irq_restore(flags); - return -1; - } + if (state->flags & SS_RESET) + value |= LINKUP_RESET; - if (configure->reset) - value = (configure->reset) ? (value | LINKUP_RESET) : (value & ~LINKUP_RESET); + /* Silently ignore Vpp, output enable, speaker enable. */ - /* Silently ignore Vpp, output enable, speaker enable. */ + LINKUP_PRC = value; +// printk("LINKUP_PRC=%x\n",value); + local_irq_restore(flags); - LINKUP_PRC = value; -//printk("LINKUP_PRC=%x\n",value); - local_irq_restore(flags); - - return 0; + return 0; } -static int freebird_pcmcia_socket_init(int sock) +static void freebird_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { - 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; + sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int freebird_pcmcia_socket_suspend(int sock) +static void freebird_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - 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; + sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } static struct pcmcia_low_level freebird_pcmcia_ops = { - .owner = THIS_MODULE, - .init = freebird_pcmcia_init, - .shutdown = freebird_pcmcia_shutdown, - .socket_state = freebird_pcmcia_socket_state, - .configure_socket = freebird_pcmcia_configure_socket, - - .socket_init = freebird_pcmcia_socket_init, - .socket_suspend = freebird_pcmcia_socket_suspend, + .owner = THIS_MODULE, + .hw_init = freebird_pcmcia_hw_init, + .hw_shutdown = freebird_pcmcia_hw_shutdown, + .socket_state = freebird_pcmcia_socket_state, + .configure_socket = freebird_pcmcia_configure_socket, + + .socket_init = freebird_pcmcia_socket_init, + .socket_suspend = freebird_pcmcia_socket_suspend, }; int __init pcmcia_freebird_init(struct device *dev) @@ -171,12 +129,7 @@ int __init pcmcia_freebird_init(struct device *dev) int ret = -ENODEV; if (machine_is_freebird()) - ret = sa1100_register_pcmcia(&freebird_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &freebird_pcmcia_ops, 0, 1); return ret; } - -void __exit pcmcia_freebird_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&freebird_pcmcia_ops, dev); -} diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index 9bf100e8fab9..6ddba61ba2d8 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c @@ -37,1120 +37,124 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/config.h> -#include <linux/cpufreq.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/kernel.h> -#include <linux/workqueue.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/notifier.h> #include <linux/proc_fs.h> -#include <linux/version.h> #include <pcmcia/version.h> #include <pcmcia/cs_types.h> #include <pcmcia/cs.h> #include <pcmcia/ss.h> -#include <asm/hardware.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/system.h> -#include <asm/arch/assabet.h> - #include "sa1100.h" -#ifdef PCMCIA_DEBUG -static int pc_debug; -#endif - -/* 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 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; - -static struct timer_list poll_timer; -static struct work_struct sa1100_pcmcia_task; - -/* - * sa1100_pcmcia_default_mecr_timing - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * - * Calculate MECR clock wait states for given CPU clock - * speed and command wait state. This function can be over- - * written by a board specific version. - * - * The default is to simply calculate the BS values as specified in - * the INTEL SA1100 development manual - * "Expansion Memory (PCMCIA) Configuration Register (MECR)" - * that's section 10.2.5 in _my_ version of the manuial ;) - */ -static unsigned int -sa1100_pcmcia_default_mecr_timing(unsigned int sock, unsigned int cpu_speed, - unsigned int cmd_time) -{ - return sa1100_pcmcia_mecr_bs(cmd_time, cpu_speed); -} - -/* sa1100_pcmcia_set_mecr() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * - * set MECR value for socket <sock> based on this sockets - * io, mem and attribute space access speed. - * Call board specific BS value calculation to allow boards - * to tweak the BS values. - */ -static int -sa1100_pcmcia_set_mecr(struct sa1100_pcmcia_socket *skt, unsigned int cpu_clock) -{ - u32 mecr; - unsigned long flags; - unsigned int bs; - - local_irq_save(flags); - - bs = skt->ops->socket_get_timing(skt->nr, cpu_clock, skt->speed_io); - - mecr = MECR; - MECR_FAST_SET(mecr, skt->nr, 0); - MECR_BSIO_SET(mecr, skt->nr, bs ); - MECR_BSA_SET(mecr, skt->nr, bs ); - MECR_BSM_SET(mecr, skt->nr, bs ); - MECR = mecr; - - local_irq_restore(flags); - - DEBUG(4, "%s(): sock %u FAST %X BSM %X BSA %X BSIO %X\n", - __FUNCTION__, skt->nr, MECR_FAST_GET(mecr, skt->nr), - MECR_BSM_GET(mecr, skt->nr), MECR_BSA_GET(mecr, skt->nr), - MECR_BSIO_GET(mecr, skt->nr)); - - return 0; -} - -/* - * sa1100_pcmcia_config_skt - * ^^^^^^^^^^^^^^^^^^^^^^^^ - * - * Convert PCMCIA socket state to our socket configure structure. - */ -static int -sa1100_pcmcia_config_skt(struct sa1100_pcmcia_socket *skt, socket_state_t *state) -{ - struct pcmcia_configure conf; - int ret; - - 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; - - ret = skt->ops->configure_socket(skt->nr, &conf); - if (ret == 0) { - /* - * This really needs a better solution. The IRQ - * may or may not be claimed by the driver. - */ - if (skt->irq_state != 1 && state->io_irq) { - skt->irq_state = 1; - set_irq_type(skt->irq, IRQT_FALLING); - } else if (skt->irq_state == 1 && state->io_irq == 0) { - skt->irq_state = 0; - set_irq_type(skt->irq, IRQT_NOEDGE); - } - - skt->cs_state = *state; - } - - if (ret < 0) - printk(KERN_ERR "sa1100_pcmcia: unable to configure " - "socket %d\n", skt->nr); - - return ret; -} - -/* sa1100_pcmcia_sock_init() - * ^^^^^^^^^^^^^^^^^^^^^^^^^ - * - * (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 - */ -static int sa1100_pcmcia_sock_init(unsigned int sock) -{ - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); - - DEBUG(2, "%s(): initializing socket %u\n", __FUNCTION__, sock); - - sa1100_pcmcia_config_skt(skt, &dead_socket); - - return skt->ops->socket_init(skt->nr); -} - - -/* - * sa1100_pcmcia_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); - int ret; - - DEBUG(2, "%s(): suspending socket %u\n", __FUNCTION__, skt->nr); - - ret = sa1100_pcmcia_config_skt(skt, &dead_socket); - - if (ret == 0) - ret = skt->ops->socket_suspend(skt->nr); - - return ret; -} - - -/* sa1100_pcmcia_events() - * ^^^^^^^^^^^^^^^^^^^^^^ - * Helper routine to generate a Card Services event mask based on - * state information obtained from the kernel low-level PCMCIA layer - * in a recent (and previous) sampling. Updates `prev_state'. - * - * Returns: an event mask for the given socket state. - */ -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; - - if (state->detect != prev_state->detect) { - DEBUG(3, "%s(): card detect value %u\n", __FUNCTION__, state->detect); - - events |= SS_DETECT; - } - - if (state->ready != prev_state->ready) { - DEBUG(3, "%s(): card ready value %u\n", __FUNCTION__, state->ready); - - events |= flags & SS_IOCARD ? 0 : SS_READY; - } - - if (state->bvd1 != prev_state->bvd1) { - DEBUG(3, "%s(): card BVD1 value %u\n", __FUNCTION__, state->bvd1); - - events |= flags & SS_IOCARD ? SS_STSCHG : SS_BATDEAD; - } - - if (state->bvd2 != prev_state->bvd2) { - DEBUG(3, "%s(): card BVD2 value %u\n", __FUNCTION__, state->bvd2); - - events |= flags & SS_IOCARD ? 0 : SS_BATWARN; - } - - *prev_state = *state; - - events &= mask; - - 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() */ - - -/* sa1100_pcmcia_task_handler() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Processes serviceable socket events using the "eventd" thread context. - * - * Event processing (specifically, the invocation of the Card Services event - * 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) -{ - struct pcmcia_state state; - unsigned int all_events; - - DEBUG(4, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__); - - do { - unsigned int events; - int i; - - DEBUG(4, "%s(): interrogating low-level PCMCIA service\n", __FUNCTION__); - - all_events = 0; - - for (i = 0; i < sa1100_pcmcia_socket_count; i++) { - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i); - - memset(&state, 0, sizeof(state)); - - skt->ops->socket_state(skt->nr, &state); - - events = sa1100_pcmcia_events(&state, &skt->k_state, - skt->cs_state.csc_mask, - skt->cs_state.flags); - - if (events && skt->handler != NULL) - skt->handler(skt->handler_info, events); - all_events |= events; - } - } while(all_events); -} /* sa1100_pcmcia_task_handler() */ - -static DECLARE_WORK(sa1100_pcmcia_task, sa1100_pcmcia_task_handler, NULL); - - -/* sa1100_pcmcia_poll_event() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Let's poll for events in addition to IRQs since IRQ only is unreliable... - */ -static void sa1100_pcmcia_poll_event(unsigned long dummy) -{ - DEBUG(4, "%s(): polling for events\n", __FUNCTION__); - init_timer(&poll_timer); - poll_timer.function = sa1100_pcmcia_poll_event; - poll_timer.expires = jiffies + SA1100_PCMCIA_POLL_PERIOD; - add_timer(&poll_timer); - schedule_work(&sa1100_pcmcia_task); -} - - -/* sa1100_pcmcia_interrupt() - * ^^^^^^^^^^^^^^^^^^^^^^^^^ - * Service routine for socket driver interrupts (requested by the - * low-level PCMCIA init() operation via sa1100_pcmcia_thread()). - * The actual interrupt-servicing work is performed by - * sa1100_pcmcia_thread(), largely because the Card Services event- - * handling code performs scheduling operations which cannot be - * executed from within an interrupt context. - */ -void sa1100_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs) -{ - DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq); - schedule_work(&sa1100_pcmcia_task); -} - - -/* sa1100_pcmcia_register_callback() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the register_callback() operation for the in-kernel - * PCMCIA service (formerly SS_RegisterCallback in Card Services). If - * the function pointer `handler' is not NULL, remember the callback - * location in the state for `sock', and increment the usage counter - * for the driver module. (The callback is invoked from the interrupt - * service routine, sa1100_pcmcia_interrupt(), to notify Card Services - * of interesting events.) Otherwise, clear the callback pointer in the - * socket state and decrement the module usage count. - * - * Returns: 0 - */ -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 && !try_module_get(skt->ops->owner)) - return -ENODEV; - if (handler == NULL) { - skt->handler = NULL; - } else { - skt->handler_info = info; - skt->handler = handler; - } - if (!handler) - module_put(skt->ops->owner); - - return 0; -} - - -/* sa1100_pcmcia_inquire_socket() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the inquire_socket() operation for the in-kernel PCMCIA - * service (formerly SS_InquireSocket in Card Services). Of note is - * the setting of the SS_CAP_PAGE_REGS bit in the `features' field of - * `cap' to "trick" Card Services into tolerating large "I/O memory" - * addresses. Also set is SS_CAP_STATIC_MAP, which disables the memory - * resource database check. (Mapped memory is set up within the socket - * driver itself.) - * - * In conjunction with the STATIC_MAP capability is a new field, - * `io_offset', recommended by David Hinds. Rather than go through - * the SetIOMap interface (which is not quite suited for communicating - * window locations up from the socket driver), we just pass up - * an offset which is applied to client-requested base I/O addresses - * in alloc_io_space(). - * - * 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 sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); - int ret = -1; - - DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); - - 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; - - ret = 0; - } - - return ret; -} - - -/* sa1100_pcmcia_get_status() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the get_status() operation for the in-kernel PCMCIA - * service (formerly SS_GetStatus in Card Services). Essentially just - * fills in bits in `status' according to internal driver state or - * the value of the voltage detect chipselect register. - * - * As a debugging note, during card startup, the PCMCIA core issues - * three set_socket() commands in a row the first with RESET deasserted, - * the second with RESET asserted, and the last with RESET deasserted - * again. Following the third set_socket(), a get_status() command will - * be issued. The kernel is looking for the SS_READY flag (see - * setup_socket(), reset_socket(), and unreset_socket() in cs.c). - * - * Returns: 0 - */ -static int -sa1100_pcmcia_get_status(unsigned int sock, unsigned int *status) -{ - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); - struct pcmcia_state state; - unsigned int stat; - - DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); - - memset(&state, 0, sizeof(state)); - - skt->ops->socket_state(skt->nr, &state); - skt->k_state = state; - - stat = state.detect ? SS_DETECT : 0; - stat |= state.ready ? SS_READY : 0; - stat |= state.vs_3v ? SS_3VCARD : 0; - stat |= state.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: - */ - stat |= skt->cs_state.Vcc ? SS_POWERON : 0; - - if (skt->cs_state.flags & SS_IOCARD) - stat |= state.bvd1 ? SS_STSCHG : 0; - else { - if (state.bvd1 == 0) - stat |= SS_BATDEAD; - else if (state.bvd2 == 0) - stat |= SS_BATWARN; - } - - DEBUG(3, "\tstatus: %s%s%s%s%s%s%s%s\n", - 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 " : ""); - - *status = stat; - - return 0; -} /* sa1100_pcmcia_get_status() */ - - -/* sa1100_pcmcia_get_socket() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the get_socket() operation for the in-kernel PCMCIA - * service (formerly SS_GetSocket in Card Services). Not a very - * exciting routine. - * - * Returns: 0 - */ -static int -sa1100_pcmcia_get_socket(unsigned int sock, socket_state_t *state) -{ - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); - - DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); - - *state = skt->cs_state; - - return 0; -} - -/* sa1100_pcmcia_set_socket() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the set_socket() operation for the in-kernel PCMCIA - * service (formerly SS_SetSocket in Card Services). We more or - * 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 -sa1100_pcmcia_set_socket(unsigned int sock, socket_state_t *state) -{ - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); - - DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); - - 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 ":"", - (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"", - (state->csc_mask&SS_BATWARN)?"BATWARN ":"", - (state->csc_mask&SS_STSCHG)?"STSCHG ":"", - (state->flags==0)?"<NONE>":"", - (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"", - (state->flags&SS_IOCARD)?"IOCARD ":"", - (state->flags&SS_RESET)?"RESET ":"", - (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"", - (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":""); - DEBUG(3, "\tVcc %d Vpp %d irq %d\n", - state->Vcc, state->Vpp, state->io_irq); - - return sa1100_pcmcia_config_skt(skt, state); -} /* sa1100_pcmcia_set_socket() */ - - -/* sa1100_pcmcia_set_io_map() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the set_io_map() operation for the in-kernel PCMCIA - * service (formerly SS_SetIOMap in Card Services). We configure - * the map speed as requested, but override the address ranges - * supplied by Card Services. - * - * Returns: 0 on success, -1 on error - */ -static int -sa1100_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map) -{ - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); - - DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); - - 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 ":"", - (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", - (map->flags&MAP_0WS)?"0WS ":"", - (map->flags&MAP_WRPROT)?"WRPROT ":"", - (map->flags&MAP_USE_WAIT)?"USE_WAIT ":"", - (map->flags&MAP_PREFETCH)?"PREFETCH ":""); - - 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->speed == 0) - map->speed = SA1100_PCMCIA_IO_ACCESS; - - sa1100_pcmcia_set_mecr(skt, cpufreq_get(0)); - } - - if (map->stop == 1) - map->stop = PAGE_SIZE-1; - - map->stop -= map->start; - map->stop += (unsigned long)skt->virt_io; - map->start = (unsigned long)skt->virt_io; - - skt->io_map[map->map] = *map; - - return 0; -} /* sa1100_pcmcia_set_io_map() */ - - -/* sa1100_pcmcia_set_mem_map() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the set_mem_map() operation for the in-kernel PCMCIA - * service (formerly SS_SetMemMap in Card Services). We configure - * the map speed as requested, but override the address ranges - * supplied by Card Services. - * - * Returns: 0 on success, -1 on error - */ -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(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); - - 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 ":"", - (map->flags&MAP_0WS)?"0WS ":"", - (map->flags&MAP_WRPROT)?"WRPROT ":"", - (map->flags&MAP_ATTRIB)?"ATTRIB ":"", - (map->flags&MAP_USE_WAIT)?"USE_WAIT ":""); - - 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) { - /* - * When clients issue RequestMap, the access speed is not always - * properly configured. Choose some sensible defaults. - */ - if (map->speed == 0) { - if (skt->cs_state.Vcc == 33) - map->speed = SA1100_PCMCIA_3V_MEM_ACCESS; - else - map->speed = SA1100_PCMCIA_5V_MEM_ACCESS; - } - - sa1100_pcmcia_set_mecr(skt, cpufreq_get(0)); - - } - - if (map->sys_stop == 0) - map->sys_stop = PAGE_SIZE-1; - - start = (map->flags & MAP_ATTRIB) ? skt->phys_attr : skt->phys_mem; - map->sys_stop -= map->sys_start; - map->sys_stop += start + map->card_start; - map->sys_start = start + map->card_start; - - skt->pc_mem_map[map->map] = *map; - - return 0; -} /* sa1100_pcmcia_set_mem_map() */ - - -#if defined(CONFIG_PROC_FS) - -/* 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) -{ - struct sa1100_pcmcia_socket *skt = data; - unsigned int clock = cpufreq_get(0); - unsigned long mecr = MECR; - char *p = buf; - - 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", - 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", - 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", - 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, "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", skt->speed_io, - sa1100_pcmcia_cmd_time(clock, MECR_BSIO_GET(mecr, skt->nr))); - - p+=sprintf(p, "attribute: %u (%u)\n", skt->speed_attr, - sa1100_pcmcia_cmd_time(clock, MECR_BSA_GET(mecr, skt->nr))); - - p+=sprintf(p, "common : %u (%u)\n", skt->speed_mem, - sa1100_pcmcia_cmd_time(clock, MECR_BSM_GET(mecr, skt->nr))); - - 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 = PCMCIA_SOCKET(sock); -} - -#endif /* defined(CONFIG_PROC_FS) */ - -static struct pccard_operations sa1100_pcmcia_operations = { - .owner = THIS_MODULE, - .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, - .set_io_map = sa1100_pcmcia_set_io_map, - .set_mem_map = sa1100_pcmcia_set_mem_map, -#ifdef CONFIG_PROC_FS - .proc_setup = sa1100_pcmcia_proc_setup -#endif -}; - -#ifdef CONFIG_CPU_FREQ - -/* sa1100_pcmcia_update_mecr() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * When sa1100_pcmcia_notifier() decides that a MECR adjustment (due - * 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) -{ - unsigned int sock; - - for (sock = 0; sock < SA1100_PCMCIA_MAX_SOCK; ++sock) { - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); - sa1100_pcmcia_set_mecr(skt, clock); - } -} - -/* sa1100_pcmcia_notifier() - * ^^^^^^^^^^^^^^^^^^^^^^^^ - * When changing the processor core clock frequency, it is necessary - * to adjust the MECR timings accordingly. We've recorded the timings - * requested by Card Services, so this is just a matter of finding - * out what our current speed is, and then recomputing the new MECR - * values. - * - * Returns: 0 on success, -1 on error - */ -static int -sa1100_pcmcia_notifier(struct notifier_block *nb, unsigned long val, - void *data) -{ - struct cpufreq_freqs *freqs = data; - - switch (val) { - case CPUFREQ_PRECHANGE: - if (freqs->new > freqs->old) { - DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, " - "pre-updating\n", __FUNCTION__, - freqs->new / 1000, (freqs->new / 100) % 10, - freqs->old / 1000, (freqs->old / 100) % 10); - sa1100_pcmcia_update_mecr(freqs->new); - } - break; - - case CPUFREQ_POSTCHANGE: - if (freqs->new < freqs->old) { - DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, " - "post-updating\n", __FUNCTION__, - freqs->new / 1000, (freqs->new / 100) % 10, - freqs->old / 1000, (freqs->old / 100) % 10); - sa1100_pcmcia_update_mecr(freqs->new); - } - break; - } - - return 0; -} - -static struct notifier_block sa1100_pcmcia_notifier_block = { - .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 device *dev) -{ - struct pcmcia_init pcmcia_init; - struct pcmcia_socket_class_data *cls; - unsigned int i, cpu_clock; - int ret; - - /* - * Refuse to replace an existing driver. - */ - if (pcmcia_low_level) - return -EBUSY; - - pcmcia_low_level = ops; - - /* - * set default MECR calculation if the board specific - * code did not specify one... - */ - if (!ops->socket_get_timing) - ops->socket_get_timing = sa1100_pcmcia_default_mecr_timing; - - pcmcia_init.socket_irq[0] = NO_IRQ; - pcmcia_init.socket_irq[1] = NO_IRQ; - ret = ops->init(&pcmcia_init); - if (ret < 0) { - printk(KERN_ERR "Unable to initialize kernel PCMCIA service (%d).\n", ret); - goto out; - } - - sa1100_pcmcia_socket_count = ret; - - cpu_clock = cpufreq_get(0); - - for (i = 0; i < sa1100_pcmcia_socket_count; i++) { - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i); - memset(skt, 0, sizeof(*skt)); - } - - /* - * We initialize the MECR to default values here, because we are - * not guaranteed to see a SetIOMap operation at runtime. - */ - for (i = 0; i < sa1100_pcmcia_socket_count; i++) { - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i); - - skt->res.start = _PCMCIA(i); - skt->res.end = _PCMCIA(i) + PCMCIASp - 1; - skt->res.name = "PCMCIA"; - skt->res.flags = IORESOURCE_MEM; - - ret = request_resource(&iomem_resource, &skt->res); - if (ret) - goto out_err; - - skt->nr = i; - skt->ops = ops; - skt->irq = pcmcia_init.socket_irq[i]; - skt->irq_state = 0; - 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; - } - - ops->socket_state(skt->nr, &skt->k_state); - sa1100_pcmcia_set_mecr(skt, cpu_clock); - } - - cls = kmalloc(sizeof(struct pcmcia_socket_class_data), GFP_KERNEL); - if (!cls) { - ret = -ENOMEM; - goto out_err; - } - - memset(cls, 0, sizeof(struct pcmcia_socket_class_data)); - - cls->ops = &sa1100_pcmcia_operations; - cls->nsock = sa1100_pcmcia_socket_count; - dev->class_data = cls; - - /* - * 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; - if (skt->res.start) - release_resource(&skt->res); - } - - ops->shutdown(); - - out: - pcmcia_low_level = NULL; - return ret; -} -EXPORT_SYMBOL(sa1100_register_pcmcia); - -/* sa1100_unregister_pcmcia() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^ - * - * Unregister a previously registered pcmcia driver - */ -void sa1100_unregister_pcmcia(struct pcmcia_low_level *ops, struct device *dev) -{ - 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); - - 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_resource(&skt->res); - } - - ops->shutdown(); - - flush_scheduled_work(); - - kfree(dev->class_data); - dev->class_data = NULL; - - pcmcia_low_level = NULL; -} -EXPORT_SYMBOL(sa1100_unregister_pcmcia); - -static struct device_driver sa1100_pcmcia_driver = { - .name = "sa11x0-pcmcia", - .bus = &platform_bus_type, - .devclass = &pcmcia_socket_class, - .suspend = pcmcia_socket_dev_suspend, - .resume = pcmcia_socket_dev_resume, -}; - -static struct platform_device sa1100_pcmcia_device = { - .name = "sa11x0-pcmcia", - .id = 0, - .dev = { - .name = "Intel Corporation SA11x0 [PCMCIA]", - }, -}; - -struct ll_fns { - int (*init)(struct device *dev); - void (*exit)(struct device *dev); -}; - -static struct ll_fns sa1100_ll_fns[] = { +static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = { #ifdef CONFIG_SA1100_ASSABET - { .init = pcmcia_assabet_init, .exit = pcmcia_assabet_exit, }, + pcmcia_assabet_init, #endif #ifdef CONFIG_SA1100_CERF - { .init = pcmcia_cerf_init, .exit = pcmcia_cerf_exit, }, + pcmcia_cerf_init, #endif #ifdef CONFIG_SA1100_FLEXANET - { .init = pcmcia_flexanet_init, .exit = pcmcia_flexanet_exit, }, + pcmcia_flexanet_init, #endif #ifdef CONFIG_SA1100_FREEBIRD - { .init = pcmcia_freebird_init, .exit = pcmcia_freebird_exit, }, + pcmcia_freebird_init, #endif #ifdef CONFIG_SA1100_GRAPHICSCLIENT - { .init = pcmcia_gcplus_init, .exit = pcmcia_gcplus_exit, }, + pcmcia_gcplus_init, #endif #ifdef CONFIG_SA1100_H3600 - { .init = pcmcia_h3600_init, .exit = pcmcia_h3600_exit, }, + pcmcia_h3600_init, #endif #ifdef CONFIG_SA1100_PANGOLIN - { .init = pcmcia_pangolin_init, .exit = pcmcia_pangolin_exit, }, + pcmcia_pangolin_init, #endif #ifdef CONFIG_SA1100_SHANNON - { .init = pcmcia_shannon_init, .exit = pcmcia_shannon_exit, }, + pcmcia_shannon_init, #endif #ifdef CONFIG_SA1100_SIMPAD - { .init = pcmcia_simpad_init, .exit = pcmcia_simpad_exit, }, + pcmcia_simpad_init, #endif #ifdef CONFIG_SA1100_STORK - { .init = pcmcia_stork_init, .exit = pcmcia_stork_exit, }, + pcmcia_stork_init, #endif #ifdef CONFIG_SA1100_TRIZEPS - { .init = pcmcia_trizeps_init, .exit = pcmcia_trizeps_exit, }, + pcmcia_trizeps_init, #endif #ifdef CONFIG_SA1100_YOPY - { .init = pcmcia_yopy_init, .exit = pcmcia_yopy_exit, }, + pcmcia_yopy_init, #endif }; -/* 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) +static int sa11x0_drv_pcmcia_probe(struct device *dev) { - servinfo_t info; - int ret, i; - - printk(KERN_INFO "SA11x0 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; - } - -#ifdef CONFIG_CPU_FREQ - ret = cpufreq_register_notifier(&sa1100_pcmcia_notifier_block, - CPUFREQ_TRANSITION_NOTIFIER); - if (ret < 0) { - printk(KERN_ERR "Unable to register CPU frequency change " - "notifier (%d)\n", ret); - driver_unregister(&sa1100_pcmcia_driver); - return ret; - } -#endif - - driver_register(&sa1100_pcmcia_driver); + int i, ret = -ENODEV; /* * Initialise any "on-board" PCMCIA sockets. */ - for (i = 0; i < ARRAY_SIZE(sa1100_ll_fns); i++) { - ret = sa1100_ll_fns[i].init(&sa1100_pcmcia_device.dev); + for (i = 0; i < ARRAY_SIZE(sa11x0_pcmcia_hw_init); i++) { + ret = sa11x0_pcmcia_hw_init[i](dev); if (ret == 0) break; } - if (ret == 0) - platform_device_register(&sa1100_pcmcia_device); - - /* - * Don't fail if we don't find any on-board sockets. - */ - return 0; + return ret; } -/* sa1100_pcmcia_exit() +static struct device_driver sa11x0_pcmcia_driver = { + .probe = sa11x0_drv_pcmcia_probe, + .remove = sa11xx_drv_pcmcia_remove, + .name = "sa11x0-pcmcia", + .bus = &platform_bus_type, + .devclass = &pcmcia_socket_class, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, +}; + +static struct platform_device sa11x0_pcmcia_device = { + .name = "sa11x0-pcmcia", + .id = 0, + .dev = { + .name = "Intel Corporation SA11x0 [PCMCIA]", + }, +}; + +/* sa11x0_pcmcia_init() * ^^^^^^^^^^^^^^^^^^^^ - * Invokes the low-level kernel service to free IRQs associated with this - * socket controller and reset GPIO edge detection. + * + * This routine performs low-level PCMCIA initialization and then + * registers this socket driver with Card Services. + * + * Returns: 0 on success, -ve error code on failure */ -static void __exit sa1100_pcmcia_exit(void) +static int __init sa11x0_pcmcia_init(void) { - platform_device_unregister(&sa1100_pcmcia_device); + int ret; + ret = driver_register(&sa11x0_pcmcia_driver); + if (ret == 0) { + ret = platform_device_register(&sa11x0_pcmcia_device); + if (ret) + driver_unregister(&sa11x0_pcmcia_driver); + } -#ifdef CONFIG_CPU_FREQ - cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); -#endif + return ret; +} - driver_unregister(&sa1100_pcmcia_driver); +/* sa11x0_pcmcia_exit() + * ^^^^^^^^^^^^^^^^^^^^ + * Invokes the low-level kernel service to free IRQs associated with this + * socket controller and reset GPIO edge detection. + */ +static void __exit sa11x0_pcmcia_exit(void) +{ + platform_device_unregister(&sa11x0_pcmcia_device); + driver_unregister(&sa11x0_pcmcia_driver); } MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>"); -MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-1100 Socket Controller"); +MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11x0 Socket Controller"); MODULE_LICENSE("Dual MPL/GPL"); -module_init(sa1100_pcmcia_init); -module_exit(sa1100_pcmcia_exit); +module_init(sa11x0_pcmcia_init); +module_exit(sa11x0_pcmcia_exit); diff --git a/drivers/pcmcia/sa1100_generic.h b/drivers/pcmcia/sa1100_generic.h index 91fbea86d682..d00458fcbaba 100644 --- a/drivers/pcmcia/sa1100_generic.h +++ b/drivers/pcmcia/sa1100_generic.h @@ -1,74 +1,23 @@ -/* - * 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 +#include "sa11xx_core.h" -/* 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. +/* + * Declaration for all machine specific init/exit functions. */ -#define SA1100_PCMCIA_MAX_SOCK (2) - -struct pcmcia_init { - int socket_irq[SA1100_PCMCIA_MAX_SOCK]; -}; - -struct pcmcia_state { - unsigned detect: 1, - ready: 1, - bvd1: 1, - bvd2: 1, - wrprot: 1, - vs_3v: 1, - vs_Xv: 1; -}; - -struct pcmcia_configure { - unsigned vcc: 8, - vpp: 8, - output: 1, - speaker: 1, - reset: 1, - irq: 1; -}; - -struct pcmcia_low_level { - struct module *owner; - - int (*init)(struct pcmcia_init *); - int (*shutdown)(void); - void (*socket_state)(int sock, struct pcmcia_state *); - int (*configure_socket)(int sock, 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); - - /* - * Calculate MECR timing clock wait states - */ - unsigned int (*socket_get_timing)(unsigned int sock, - unsigned int cpu_speed, unsigned int cmd_time); -}; - -extern int sa1100_register_pcmcia(struct pcmcia_low_level *, struct device *); -extern void sa1100_unregister_pcmcia(struct pcmcia_low_level *, struct device *); -extern void sa1100_pcmcia_interrupt(int, void *, struct pt_regs *); - -#endif +extern int pcmcia_adsbitsy_init(struct device *); +extern int pcmcia_assabet_init(struct device *); +extern int pcmcia_badge4_init(struct device *); +extern int pcmcia_cerf_init(struct device *); +extern int pcmcia_flexanet_init(struct device *); +extern int pcmcia_freebird_init(struct device *); +extern int pcmcia_gcplus_init(struct device *); +extern int pcmcia_graphicsmaster_init(struct device *); +extern int pcmcia_h3600_init(struct device *); +extern int pcmcia_pangolin_init(struct device *); +extern int pcmcia_pfs168_init(struct device *); +extern int pcmcia_shannon_init(struct device *); +extern int pcmcia_simpad_init(struct device *); +extern int pcmcia_stork_init(struct device *); +extern int pcmcia_system3_init(struct device *); +extern int pcmcia_trizeps_init(struct device *); +extern int pcmcia_xp860_init(struct device *); +extern int pcmcia_yopy_init(struct device *); diff --git a/drivers/pcmcia/sa1100_graphicsclient.c b/drivers/pcmcia/sa1100_graphicsclient.c index 2bd36b4c576c..0960b48123ee 100644 --- a/drivers/pcmcia/sa1100_graphicsclient.c +++ b/drivers/pcmcia/sa1100_graphicsclient.c @@ -34,126 +34,113 @@ static volatile unsigned long *PCMCIA_Status = static volatile unsigned long *PCMCIA_Power = ((volatile unsigned long *) ADS_p2v(_ADS_CS_PR)); -static int gcplus_pcmcia_init(struct pcmcia_init *init) -{ - int irq, res; - - // Reset PCMCIA - // Reset Timing for CPLD(U2) version 8001E or later - *PCMCIA_Power &= ~ ADS_CS_PR_A_RESET; - udelay(12); // 12 uSec +static struct pcmcia_irqs irqs[] = { + { 0, S0_CD_IRQ, "PCMCIA 0 CD" }, +}; - *PCMCIA_Power |= ADS_CS_PR_A_RESET; - mdelay(30); // 30 mSec +static int gcplus_pcmcia_init(struct sa1100_pcmcia_socket *skt) +{ + // Reset PCMCIA + // Reset Timing for CPLD(U2) version 8001E or later + *PCMCIA_Power &= ~ ADS_CS_PR_A_RESET; + udelay(12); // 12 uSec - // Turn off 5V - *PCMCIA_Power &= ~0x03; + *PCMCIA_Power |= ADS_CS_PR_A_RESET; + mdelay(30); // 30 mSec - /* Register interrupts */ - irq = S0_CD_IRQ; - res = request_irq(irq, sa1100_pcmcia_interrupt, SA_INTERRUPT, "PCMCIA 0 CD", NULL); - if (res < 0) { - printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n", - __FUNCTION__, irq, res); - return res; - } + // Turn off 5V + *PCMCIA_Power &= ~0x03; - init->socket_irq[0] = S0_STS_IRQ; + skt->irq = S0_STS_IRQ; - return 1; // 1 PCMCIA Slot + /* Register interrupts */ + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int gcplus_pcmcia_shutdown(void) +static void gcplus_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt) { - /* disable IRQs */ - free_irq( S0_CD_IRQ, NULL); + /* disable IRQs */ + free_irq(S0_CD_IRQ, skt); - /* Shutdown PCMCIA power */ - mdelay(2); // 2msec - *PCMCIA_Power &= ~0x03; - - return 0; + /* Shutdown PCMCIA power */ + mdelay(2); // 2msec + *PCMCIA_Power &= ~0x03; } -static void gcplus_pcmcia_socket_state(int sock, struct pcmcia_state *state_array) +static void +gcplus_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, struct pcmcia_state *state) { - unsigned long levels = *PCMCIA_Status; - - if (sock == 0) { - state->detect=(levels & ADS_CS_ST_A_CD)?1:0; - state->ready=(levels & ADS_CS_ST_A_READY)?1:0; - state->bvd1= 0; - state->bvd2= 0; - state->wrprot=0; - state->vs_3v=0; - state->vs_Xv=0; - } + unsigned long levels = *PCMCIA_Status; + + state->detect=(levels & ADS_CS_ST_A_CD)?1:0; + state->ready=(levels & ADS_CS_ST_A_READY)?1:0; + state->bvd1= 0; + state->bvd2= 0; + state->wrprot=0; + state->vs_3v=0; + state->vs_Xv=0; } -static int gcplus_pcmcia_configure_socket(int sock, const struct pcmcia_configure - *configure) +static int +gcplus_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, + const socket_state_t *state) { - unsigned long flags; + unsigned long flags; - if(sock>1) return -1; + local_irq_save(flags); - local_irq_save(flags); + switch (state->Vcc) { + case 0: + *PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER); + break; - switch (configure->vcc) { - case 0: - *PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER); - break; + case 50: + *PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER); + *PCMCIA_Power |= ADS_CS_PR_A_5V_POWER; + break; - case 50: - *PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER); - *PCMCIA_Power |= ADS_CS_PR_A_5V_POWER; - break; + case 33: + *PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER); + *PCMCIA_Power |= ADS_CS_PR_A_3V_POWER; + break; - case 33: - *PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER); - *PCMCIA_Power |= ADS_CS_PR_A_3V_POWER; - break; + default: + printk(KERN_ERR "%s(): unrecognized Vcc %u\n", + __FUNCTION__, state->Vcc); + local_irq_restore(flags); + return -1; + } - default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - local_irq_restore(flags); - return -1; - } + /* Silently ignore Vpp, output enable, speaker enable. */ - /* Silently ignore Vpp, output enable, speaker enable. */ + // Reset PCMCIA + *PCMCIA_Power &= ~ ADS_CS_PR_A_RESET; + udelay(12); - // Reset PCMCIA - *PCMCIA_Power &= ~ ADS_CS_PR_A_RESET; - udelay(12); + *PCMCIA_Power |= ADS_CS_PR_A_RESET; + mdelay(30); - *PCMCIA_Power |= ADS_CS_PR_A_RESET; - mdelay(30); + local_irq_restore(flags); - local_irq_restore(flags); - - return 0; + return 0; } -static int gcplus_pcmcia_socket_init(int sock) +static void gcplus_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { - return 0; } -static int gcplus_pcmcia_socket_suspend(int sock) +static void gcplus_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - return 0; } static struct pcmcia_low_level gcplus_pcmcia_ops = { - .owner = THIS_MODULE, - .init = gcplus_pcmcia_init, - .shutdown = gcplus_pcmcia_shutdown, - .socket_state = gcplus_pcmcia_socket_state, - .configure_socket = gcplus_pcmcia_configure_socket, - - .socket_init = gcplus_pcmcia_socket_init, - .socket_suspend = gcplus_pcmcia_socket_suspend, + .owner = THIS_MODULE, + .hw_init = gcplus_pcmcia_hw_init, + .hw_shutdown = gcplus_pcmcia_hw_shutdown, + .socket_state = gcplus_pcmcia_socket_state, + .configure_socket = gcplus_pcmcia_configure_socket, + .socket_init = gcplus_pcmcia_socket_init, + .socket_suspend = gcplus_pcmcia_socket_suspend, }; int __init pcmcia_gcplus_init(struct device *dev) @@ -161,13 +148,7 @@ int __init pcmcia_gcplus_init(struct device *dev) int ret = -ENODEV; if (machine_is_gcplus()) - ret = sa1100_register_pcmcia(&gcplus_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &gcplus_pcmcia_ops, 0, 1); return ret; } - -void __exit pcmcia_gcplus_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&gcplus_pcmcia_ops, dev); -} - diff --git a/drivers/pcmcia/sa1100_graphicsmaster.c b/drivers/pcmcia/sa1100_graphicsmaster.c index 49c975ac5f13..79ed49ab264a 100644 --- a/drivers/pcmcia/sa1100_graphicsmaster.c +++ b/drivers/pcmcia/sa1100_graphicsmaster.c @@ -17,10 +17,9 @@ #include <asm/hardware.h> #include <asm/mach-types.h> -#include "sa1100_generic.h" #include "sa1111_generic.h" -static int graphicsmaster_pcmcia_init(struct pcmcia_init *init) +static int graphicsmaster_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { int return_val=0; @@ -33,65 +32,67 @@ static int graphicsmaster_pcmcia_init(struct pcmcia_init *init) /* why? */ MECR = 0x09430943; - return sa1111_pcmcia_init(init); + return sa1111_pcmcia_hwinit(skt); } static int -graphicsmaster_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) +graphicsmaster_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, + const socket_state_t *state) { - unsigned int pa_dwr_mask, pa_dwr_set; - int ret; - - switch (sock) { - case 0: - pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1; - - switch (conf->vcc) { - default: - 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; - } - break; - - case 1: - pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3; - - switch (conf->vcc) { - default: - 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; - } - } - - 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(sock, 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 ret; + unsigned int pa_dwr_mask, pa_dwr_set; + int ret; + + switch (skt->nr) { + case 0: + pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1; + + switch (state->Vcc) { + default: + 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; + } + break; + + case 1: + pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3; + + switch (state->Vcc) { + default: + 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; + } + break; + } + + if (state->Vpp != state->Vcc && state->Vpp != 0) { + printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", + __FUNCTION__, state->Vpp); + return -1; + } + + ret = sa1111_pcmcia_configure_socket(skt, state); + 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 ret; } static struct pcmcia_low_level graphicsmaster_pcmcia_ops = { - .owner = THIS_MODULE, - .init = graphicsmaster_pcmcia_init, - .shutdown = sa1111_pcmcia_shutdown, - .socket_state = sa1111_pcmcia_socket_state, - .configure_socket = graphicsmaster_pcmcia_configure_socket, - - .socket_init = sa1111_pcmcia_socket_init, - .socket_suspend = sa1111_pcmcia_socket_suspend, + .owner = THIS_MODULE, + .hw_init = graphicsmaster_pcmcia_init, + .hw_shutdown = sa1111_pcmcia_hw_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .configure_socket = graphicsmaster_pcmcia_configure_socket, + + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_graphicsmaster_init(struct device *dev) @@ -99,13 +100,7 @@ int __init pcmcia_graphicsmaster_init(struct device *dev) int ret = -ENODEV; if (machine_is_graphicsmaster()) - ret = sa1100_register_pcmcia(&graphicsmaster_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &graphicsmaster_pcmcia_ops, 0, 2); return ret; } - -void __exit pcmcia_graphicsmaster_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&graphicsmaster_pcmcia_ops, dev); -} - diff --git a/drivers/pcmcia/sa1100_h3600.c b/drivers/pcmcia/sa1100_h3600.c index 69509df2e177..76c78ad37ab8 100644 --- a/drivers/pcmcia/sa1100_h3600.c +++ b/drivers/pcmcia/sa1100_h3600.c @@ -8,6 +8,7 @@ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/device.h> +#include <linux/interrupt.h> #include <linux/init.h> #include <asm/hardware.h> @@ -17,65 +18,36 @@ #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" } +static struct pcmcia_irqs irqs[] = { + { 0, IRQ_GPIO_H3600_PCMCIA_CD0, "PCMCIA CD0" }, + { 1, IRQ_GPIO_H3600_PCMCIA_CD1, "PCMCIA CD1" } }; -static int h3600_pcmcia_init(struct pcmcia_init *init) +static int h3600_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { - int i, res; + skt->irq = skt->nr ? IRQ_GPIO_H3600_PCMCIA_IRQ1 + : IRQ_GPIO_H3600_PCMCIA_IRQ0; - /* - * Register interrupts - */ - for (i = res = 0; i < ARRAY_SIZE(irqs); i++) { - res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt, - 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); - } - - init->socket_irq[0] = IRQ_GPIO_H3600_PCMCIA_IRQ0; - init->socket_irq[1] = IRQ_GPIO_H3600_PCMCIA_IRQ1; - - return res ? res : 2; + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int h3600_pcmcia_shutdown(void) +static void h3600_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt) { - int i; - - /* - * disable IRQs - */ - for (i = 0; i < ARRAY_SIZE(irqs); i++) - free_irq(irqs[i].irq, NULL); + sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); /* 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; } -static void h3600_pcmcia_socket_state(int sock, struct pcmcia_state *state) +static void +h3600_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, struct pcmcia_state *state) { unsigned long levels = GPLR; - switch (sock) { + switch (skt->nr) { case 0: state->detect = levels & GPIO_H3600_PCMCIA_CD0 ? 0 : 1; state->ready = levels & GPIO_H3600_PCMCIA_IRQ0 ? 1 : 0; @@ -99,18 +71,15 @@ static void h3600_pcmcia_socket_state(int sock, struct pcmcia_state *state) } static int -h3600_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) +h3600_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, const socket_state_t *state) { - if (sock > 1) - return -1; - - if (conf->vcc != 0 && conf->vcc != 33 && conf->vcc != 50) { + if (state->Vcc != 0 && state->Vcc != 33 && state->Vcc != 50) { printk(KERN_ERR "h3600_pcmcia: unrecognized Vcc %u.%uV\n", - conf->vcc / 10, conf->vcc % 10); + state->Vcc / 10, state->Vcc % 10); return -1; } - if (conf->reset) + if (state->flags & SS_RESET) set_h3600_egpio(IPAQ_EGPIO_CARD_RESET); else clr_h3600_egpio(IPAQ_EGPIO_CARD_RESET); @@ -120,7 +89,7 @@ h3600_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) return 0; } -static int h3600_pcmcia_socket_init(int sock) +static void h3600_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { /* Enable CF bus: */ set_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON); @@ -130,28 +99,12 @@ static int h3600_pcmcia_socket_init(int sock) 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; + sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int h3600_pcmcia_socket_suspend(int sock) +static void h3600_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - 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; - } + sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); /* * FIXME: This doesn't fit well. We don't have the mechanism in @@ -159,20 +112,18 @@ static int h3600_pcmcia_socket_suspend(int sock) * on one bus. We rely on the cs.c behaviour shutting down * socket 0 then socket 1. */ - if (sock == 1) { + if (skt->nr == 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 = { .owner = THIS_MODULE, - .init = h3600_pcmcia_init, - .shutdown = h3600_pcmcia_shutdown, + .hw_init = h3600_pcmcia_hw_init, + .hw_shutdown = h3600_pcmcia_hw_shutdown, .socket_state = h3600_pcmcia_socket_state, .configure_socket = h3600_pcmcia_configure_socket, @@ -185,12 +136,7 @@ int __init pcmcia_h3600_init(struct device *dev) int ret = -ENODEV; if (machine_is_h3600()) - ret = sa1100_register_pcmcia(&h3600_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &h3600_pcmcia_ops, 0, 2); return ret; } - -void __exit pcmcia_h3600_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&h3600_pcmcia_ops, dev); -} diff --git a/drivers/pcmcia/sa1100_jornada720.c b/drivers/pcmcia/sa1100_jornada720.c index 3ab8b879f53e..84156d18259a 100644 --- a/drivers/pcmcia/sa1100_jornada720.c +++ b/drivers/pcmcia/sa1100_jornada720.c @@ -15,7 +15,6 @@ #include <asm/hardware/sa1111.h> #include <asm/mach-types.h> -#include "sa1100_generic.h" #include "sa1111_generic.h" #define SOCKET0_POWER GPIO_GPIO0 @@ -24,7 +23,7 @@ #warning *** Does SOCKET1_3V actually do anything? #define SOCKET1_3V GPIO_GPIO3 -static int jornada720_pcmcia_init(struct pcmcia_init *init) +static int jornada720_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { /* * What is all this crap for? @@ -46,23 +45,23 @@ static int jornada720_pcmcia_init(struct pcmcia_init *init) PC_SDR = 0; PC_SSR = 0; - return sa1111_pcmcia_init(init); + return sa1111_pcmcia_hw_init(skt); } static int -jornada720_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) +jornada720_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, const socket_state_t *state) { unsigned int pa_dwr_mask, pa_dwr_set; int ret; printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__, - sock, conf->vcc, conf->vpp); + skt->nr, state->Vcc, state->Vpp); - switch (sock) { + switch (skt->nr) { case 0: pa_dwr_mask = SOCKET0_POWER | SOCKET0_3V; - switch (conf->vcc) { + switch (state->Vcc) { default: case 0: pa_dwr_set = 0; break; case 33: pa_dwr_set = SOCKET0_POWER | SOCKET0_3V; break; @@ -73,7 +72,7 @@ printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__, case 1: pa_dwr_mask = SOCKET1_POWER; - switch (conf->vcc) { + switch (state->Vcc) { default: case 0: pa_dwr_set = 0; break; case 33: pa_dwr_set = SOCKET1_POWER; break; @@ -85,13 +84,13 @@ printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__, return -1; } - if (conf->vpp != conf->vcc && conf->vpp != 0) { + if (state->Vpp != state->Vcc && state->Vpp != 0) { printk(KERN_ERR "%s(): slot cannot support VPP %u\n", - __FUNCTION__, conf->vpp); + __FUNCTION__, state->Vpp); return -1; } - ret = sa1111_pcmcia_configure_socket(sock, conf); + ret = sa1111_pcmcia_configure_socket(skt, state); if (ret == 0) { unsigned long flags; @@ -105,8 +104,8 @@ printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__, static struct pcmcia_low_level jornada720_pcmcia_ops = { .owner = THIS_MODULE, - .init = jornada720_pcmcia_init, - .shutdown = sa1111_pcmcia_shutdown, + .hw_init = jornada720_pcmcia_hw_init, + .hw_shutdown = sa1111_pcmcia_hw_shutdown, .socket_state = sa1111_pcmcia_socket_state, .configure_socket = jornada720_pcmcia_configure_socket, @@ -119,12 +118,7 @@ int __init pcmcia_jornada720_init(struct device *dev) int ret = -ENODEV; if (machine_is_jornada720()) - ret = sa1100_register_pcmcia(&jornada720_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &jornada720_pcmcia_ops, 0, 2); return ret; } - -void __devexit pcmcia_jornada720_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&jornada720_pcmcia_ops, dev); -} diff --git a/drivers/pcmcia/sa1100_neponset.c b/drivers/pcmcia/sa1100_neponset.c index b12cd186c5f0..b0c3e6c26e7a 100644 --- a/drivers/pcmcia/sa1100_neponset.c +++ b/drivers/pcmcia/sa1100_neponset.c @@ -15,7 +15,6 @@ #include <asm/arch/neponset.h> #include <asm/hardware/sa1111.h> -#include "sa1100_generic.h" #include "sa1111_generic.h" /* @@ -42,52 +41,27 @@ * the corresponding truth table. */ -static int neponset_pcmcia_init(struct pcmcia_init *init) -{ - NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP); - - /* - * Set GPIO_A<3:0> to be outputs for the MAX1600, - * and switch to standby mode. - */ - PA_DDR = 0; - PA_SDR = 0; - PA_DWR = 0; - PA_SSR = 0; - - return sa1111_pcmcia_init(init); -} - static int -neponset_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) +neponset_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, const socket_state_t *state) { - unsigned int ncr_mask, pa_dwr_mask; - unsigned int ncr_set, pa_dwr_set; + unsigned int ncr_mask, ncr_set, pa_dwr_mask, pa_dwr_set; int ret; - switch (sock) { + switch (skt->nr) { 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; - } + if (state->Vpp == 0) + ncr_set = 0; + else if (state->Vpp == 120) + ncr_set = NCR_A1VPP; + else if (state->Vpp == state->Vcc) + ncr_set = NCR_A0VPP; + else { + printk(KERN_ERR "%s(): unrecognized VPP %u\n", + __FUNCTION__, state->Vpp); + return -1; } break; @@ -96,16 +70,9 @@ neponset_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) 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) { + if (state->Vpp != state->Vcc && state->Vpp != 0) { printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n", - __FUNCTION__, conf->vpp); + __FUNCTION__, state->Vpp); return -1; } break; @@ -114,41 +81,64 @@ neponset_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) return -1; } - ret = sa1111_pcmcia_configure_socket(sock, conf); + /* + * pa_dwr_set is the mask for selecting Vcc on both sockets. + * pa_dwr_mask selects which bits (and therefore socket) we change. + */ + switch (state->Vcc) { + default: + case 0: pa_dwr_set = 0; break; + case 33: pa_dwr_set = GPIO_GPIO1|GPIO_GPIO2; break; + case 50: pa_dwr_set = GPIO_GPIO0|GPIO_GPIO3; break; + } + + ret = sa1111_pcmcia_configure_socket(skt, state); 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; + + PA_DWR = (PA_DWR & ~pa_dwr_mask) | (pa_dwr_set & pa_dwr_mask); local_irq_restore(flags); } return 0; } +static void neponset_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) +{ + if (skt->nr == 0) + NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP); + + sa1111_pcmcia_socket_init(skt); +} + static struct pcmcia_low_level neponset_pcmcia_ops = { - .owner = THIS_MODULE, - .init = neponset_pcmcia_init, - .shutdown = sa1111_pcmcia_shutdown, - .socket_state = sa1111_pcmcia_socket_state, - .configure_socket = neponset_pcmcia_configure_socket, - - .socket_init = sa1111_pcmcia_socket_init, - .socket_suspend = sa1111_pcmcia_socket_suspend, + .owner = THIS_MODULE, + .hw_init = sa1111_pcmcia_hw_init, + .hw_shutdown = sa1111_pcmcia_hw_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .configure_socket = neponset_pcmcia_configure_socket, + .socket_init = neponset_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_neponset_init(struct device *dev) { - int ret = -ENODEV; - - if (machine_is_assabet()) - ret = sa1100_register_pcmcia(&neponset_pcmcia_ops, dev); + int ret = -ENODEV; + + if (machine_is_assabet()) { + /* + * Set GPIO_A<3:0> to be outputs for the MAX1600, + * and switch to standby mode. + */ + PA_DDR = 0; + PA_DWR = 0; + PA_SDR = 0; + PA_SSR = 0; + ret = sa11xx_drv_pcmcia_probe(dev, &neponset_pcmcia_ops, 0, 2); + } return ret; } - -void __devexit pcmcia_neponset_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&neponset_pcmcia_ops, dev); -} diff --git a/drivers/pcmcia/sa1100_pangolin.c b/drivers/pcmcia/sa1100_pangolin.c index 54827bc585d5..516a7dc9f5c7 100644 --- a/drivers/pcmcia/sa1100_pangolin.c +++ b/drivers/pcmcia/sa1100_pangolin.c @@ -22,134 +22,118 @@ #define PANGOLIN_SOCK 0 #endif -static int pangolin_pcmcia_init(struct pcmcia_init *init){ - int res; +static struct pcmcia_irqs irqs[] = { + { PANGOLIN_SOCK, IRQ_PCMCIA_CD, "PCMCIA CD" }, +}; + +static int pangolin_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) +{ + int res; #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE - /* Enable PCMCIA bus: */ - GPCR = GPIO_PCMCIA_BUS_ON; + /* Enable PCMCIA bus: */ + GPCR = GPIO_PCMCIA_BUS_ON; #endif - init->socket_irq[PANGOLIN_SOCK] = IRQ_PCMCIA_IRQ; - - /* Set transition detect */ - set_irq_type(IRQ_PCMCIA_CD, IRQT_NOEDGE); - set_irq_type(IRQ_PCMCIA_IRQ, IRQT_FALLING); + skt->irq = IRQ_PCMCIA_IRQ; - /* Register interrupts */ - res = request_irq(IRQ_PCMCIA_CD, sa1100_pcmcia_interrupt, 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%d failed (%d)\n", - __FUNCTION__, IRQ_PCMCIA_CD, res); - - return res; + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int pangolin_pcmcia_shutdown(void) +static void pangolin_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt) { - /* disable IRQs */ - free_irq(IRQ_PCMCIA_CD, NULL); + sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); + #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE - /* Disable PCMCIA bus: */ - GPSR = GPIO_PCMCIA_BUS_ON; + /* Disable PCMCIA bus: */ + GPSR = GPIO_PCMCIA_BUS_ON; #endif - return 0; } -static void pangolin_pcmcia_socket_state(int sock, struct pcmcia_state *state) +static void +pangolin_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, + struct pcmcia_state *state) { - unsigned long levels = GPLR;; - - if (sock == PANGOLIN_SOCK) { - state->detect=((levels & GPIO_PCMCIA_CD)==0)?1:0; - state->ready=(levels & GPIO_PCMCIA_IRQ)?1:0; - state->bvd1=1; /* Not available on Pangolin. */ - state->bvd2=1; /* Not available on Pangolin. */ - state->wrprot=0; /* Not available on Pangolin. */ - state->vs_3v=1; /* Can only apply 3.3V on Pangolin. */ - state->vs_Xv=0; - } + unsigned long levels = GPLR;; + + state->detect=((levels & GPIO_PCMCIA_CD)==0)?1:0; + state->ready=(levels & GPIO_PCMCIA_IRQ)?1:0; + state->bvd1=1; /* Not available on Pangolin. */ + state->bvd2=1; /* Not available on Pangolin. */ + state->wrprot=0; /* Not available on Pangolin. */ + state->vs_3v=1; /* Can only apply 3.3V on Pangolin. */ + state->vs_Xv=0; } -static int pangolin_pcmcia_configure_socket(int sock, const struct pcmcia_configure - *configure) +static int +pangolin_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, + const socket_state_t *state) { - unsigned long value, flags; + unsigned long value, flags; - if(sock>1) return -1; -#ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE - if(sock==0) return 0; -#endif - local_irq_save(flags); + local_irq_save(flags); - /* Murphy: BUS_ON different from POWER ? */ + /* Murphy: BUS_ON different from POWER ? */ - switch(configure->vcc){ - case 0: - break; + switch (state->Vcc) { + case 0: + break; #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE - case 50: - printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n", - __FUNCTION__); - case 33: /* Can only apply 3.3V to the CF slot. */ - break; + case 50: + printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n", + __FUNCTION__); + case 33: /* Can only apply 3.3V to the CF slot. */ + break; #else - case 50: - printk(KERN_WARNING "%s(): CS asked for 5V, determinded by jumper setting...\n", __FUNCTION__); - break; - case 33: - printk(KERN_WARNING "%s(): CS asked for 3.3V, determined by jumper setting...\n", __FUNCTION__); - break; + case 50: + printk(KERN_WARNING "%s(): CS asked for 5V, determinded by " + "jumper setting...\n", __FUNCTION__); + break; + case 33: + printk(KERN_WARNING "%s(): CS asked for 3.3V, determined by " + "jumper setting...\n", __FUNCTION__); + break; #endif - default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - local_irq_restore(flags); - return -1; - } + default: + printk(KERN_ERR "%s(): unrecognized Vcc %u\n", + __FUNCTION__, state->Vcc); + local_irq_restore(flags); + return -1; + } #ifdef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE - /* reset & unreset request */ - if(sock==0) { - if(configure->reset) { - GPSR |= GPIO_PCMCIA_RESET; - } else { - GPCR |= GPIO_PCMCIA_RESET; + /* reset & unreset request */ + if (skt->nr == 0) { + if (state->flags & SS_RESET) { + GPSR = GPIO_PCMCIA_RESET; + } else { + GPCR = GPIO_PCMCIA_RESET; + } } - } #endif - /* Silently ignore Vpp, output enable, speaker enable. */ - local_irq_restore(flags); - return 0; + /* Silently ignore Vpp, output enable, speaker enable. */ + local_irq_restore(flags); + return 0; } -static int pangolin_pcmcia_socket_init(int sock) +static void pangolin_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { - if (sock == 1) - set_irq_type(IRQ_PCMCIA_CD, IRQT_BOTHEDGE); - return 0; + sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int pangolin_pcmcia_socket_suspend(int sock) +static void pangolin_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - if (sock == 1) - set_irq_type(IRQ_PCMCIA_CD, IRQT_NOEDGE); - return 0; + sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } static struct pcmcia_low_level pangolin_pcmcia_ops = { - .owner = THIS_MODULE, - .init = pangolin_pcmcia_init, - .shutdown = pangolin_pcmcia_shutdown, - .socket_state = pangolin_pcmcia_socket_state, - .configure_socket = pangolin_pcmcia_configure_socket, - - .socket_init = pangolin_pcmcia_socket_init, - .socket_suspend = pangolin_pcmcia_socket_suspend, + .owner = THIS_MODULE, + .hw_init = pangolin_pcmcia_hw_init, + .hw_shutdown = pangolin_pcmcia_hw_shutdown, + .socket_state = pangolin_pcmcia_socket_state, + .configure_socket = pangolin_pcmcia_configure_socket, + + .socket_init = pangolin_pcmcia_socket_init, + .socket_suspend = pangolin_pcmcia_socket_suspend, }; int __init pcmcia_pangolin_init(struct device *dev) @@ -157,13 +141,7 @@ int __init pcmcia_pangolin_init(struct device *dev) int ret = -ENODEV; if (machine_is_pangolin()) - ret = sa1100_register_pcmcia(&pangolin_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &pangolin_pcmcia_ops, PANGOLIN_SOCK, 1); return ret; } - -void __exit pcmcia_pangolin_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&pangolin_pcmcia_ops, dev); -} - diff --git a/drivers/pcmcia/sa1100_pfs168.c b/drivers/pcmcia/sa1100_pfs168.c index 909951554101..85c0933606d8 100644 --- a/drivers/pcmcia/sa1100_pfs168.c +++ b/drivers/pcmcia/sa1100_pfs168.c @@ -16,10 +16,9 @@ #include <asm/mach-types.h> #include <asm/irq.h> -#include "sa1100_generic.h" #include "sa1111_generic.h" -static int pfs168_pcmcia_init(struct pcmcia_init *init) +static int pfs168_pcmcia_init(struct sa1100_pcmcia_socket *skt) { /* TPS2211 to standby mode: */ PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); @@ -27,11 +26,12 @@ static int pfs168_pcmcia_init(struct pcmcia_init *init) /* Set GPIO_A<3:0> to be outputs for PCMCIA (socket 0) power controller: */ PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); - return sa1111_pcmcia_init(init); + return sa1111_pcmcia_init(skt); } static int -pfs168_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) +pfs168_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, + const socket_state_t *state) { unsigned int pa_dwr_mask = 0, pa_dwr_set = 0; int ret; @@ -48,33 +48,33 @@ pfs168_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) * */ - switch (sock) { + switch (skt->nr) { case 0: pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3; - switch (conf->vcc) { + switch (state->Vcc) { default: case 0: pa_dwr_set = 0; break; case 33: pa_dwr_set = GPIO_GPIO0; break; case 50: pa_dwr_set = GPIO_GPIO1; break; } - switch (conf->vpp) { + switch (state->Vpp) { case 0: break; case 120: printk(KERN_ERR "%s(): PFS-168 does not support VPP %uV\n", - __FUNCTION__, conf->vpp / 10); + __FUNCTION__, state->Vpp / 10); return -1; break; default: - if (conf->vpp == conf->vcc) + if (state->Vpp == state->Vcc) pa_dwr_set |= GPIO_GPIO3; else { printk(KERN_ERR "%s(): unrecognized VPP %u\n", __FUNCTION__, - conf->vpp); + state->Vpp); return -1; } } @@ -91,24 +91,24 @@ pfs168_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) case 50: printk(KERN_ERR "%s(): PFS-168 CompactFlash socket does not support VCC %uV\n", - __FUNCTION__, conf->vcc / 10); + __FUNCTION__, state->Vcc / 10); return -1; default: printk(KERN_ERR "%s(): unrecognized VCC %u\n", __FUNCTION__, - conf->vcc); + state->Vcc); return -1; } - if (conf->vpp != conf->vcc && conf->vpp != 0) { + if (state->Vpp != state->Vcc && state->Vpp != 0) { printk(KERN_ERR "%s(): CompactFlash socket does not support VPP %uV\n" - __FUNCTION__, conf->vpp / 10); + __FUNCTION__, state->Vpp / 10); return -1; } break; } - ret = sa1111_pcmcia_configure_socket(sock, conf); + ret = sa1111_pcmcia_configure_socket(skt, state); if (ret == 0) { unsigned long flags; @@ -121,14 +121,13 @@ pfs168_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) } static struct pcmcia_low_level pfs168_pcmcia_ops = { - .owner = THIS_MODULE, - .init = pfs168_pcmcia_init, - .shutdown = sa1111_pcmcia_shutdown, - .socket_state = sa1111_pcmcia_socket_state, - .configure_socket = pfs168_pcmcia_configure_socket, - - .socket_init = sa1111_pcmcia_socket_init, - .socket_suspend = sa1111_pcmcia_socket_suspend, + .owner = THIS_MODULE, + .hw_init = pfs168_pcmcia_hw_init, + .hw_shutdown = sa1111_pcmcia_hw_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .configure_socket = pfs168_pcmcia_configure_socket, + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_pfs168_init(struct device *dev) @@ -136,12 +135,7 @@ int __init pcmcia_pfs168_init(struct device *dev) int ret = -ENODEV; if (machine_is_pfs168()) - ret = sa1100_register_pcmcia(&pfs168_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &pfs168_pcmcia_ops, 0, 2); return ret; } - -void __exit pcmcia_pfs168_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&pfs168_pcmcia_ops, dev); -} diff --git a/drivers/pcmcia/sa1100_shannon.c b/drivers/pcmcia/sa1100_shannon.c index 4995bd420a57..37217e50c608 100644 --- a/drivers/pcmcia/sa1100_shannon.c +++ b/drivers/pcmcia/sa1100_shannon.c @@ -16,64 +16,36 @@ #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 struct pcmcia_irqs irqs[] = { + { 0, SHANNON_IRQ_GPIO_EJECT_0, "PCMCIA_CD_0" }, + { 1, SHANNON_IRQ_GPIO_EJECT_1, "PCMCIA_CD_1" }, }; -static int shannon_pcmcia_init(struct pcmcia_init *init) +static int shannon_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { - 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); - init->socket_irq[0] = SHANNON_IRQ_GPIO_RDY_0; - init->socket_irq[1] = SHANNON_IRQ_GPIO_RDY_1; - - /* Register interrupts */ - for (i = 0; i < ARRAY_SIZE(irqs); i++) { - res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt, - SA_INTERRUPT, irqs[i].str, NULL); - if (res) - goto irq_err; - set_irq_type(irqs[i].irq, IRQT_NOEDGE); - } - - return 2; + skt->irq = skt->nr ? SHANNON_IRQ_GPIO_RDY_1 : SHANNON_IRQ_GPIO_RDY_0; - 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; + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int shannon_pcmcia_shutdown(void) +static void shannon_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt) { - int i; - - /* disable IRQs */ - for (i = 0; i < ARRAY_SIZE(irqs); i++) - free_irq(irqs[i].irq, NULL); - - return 0; + sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static void shannon_pcmcia_socket_state(int sock, struct pcmcia_state *state) +static void +shannon_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, + struct pcmcia_state *state) { unsigned long levels = GPLR; - switch (sock) { + switch (skt->nr) { case 0: state->detect = (levels & SHANNON_GPIO_EJECT_0) ? 0 : 1; state->ready = (levels & SHANNON_GPIO_RDY_0) ? 1 : 0; @@ -96,9 +68,11 @@ static void shannon_pcmcia_socket_state(int sock, struct pcmcia_state *state) } } -static int shannon_pcmcia_configure_socket(int sock, const struct pcmcia_configure *configure) +static int +shannon_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, + const socket_state_t *state) { - switch (configure->vcc) { + switch (state->Vcc) { case 0: /* power off */ printk(KERN_WARNING __FUNCTION__"(): CS asked for 0V, still applying 3.3V..\n"); break; @@ -108,7 +82,7 @@ static int shannon_pcmcia_configure_socket(int sock, const struct pcmcia_configu break; default: printk(KERN_ERR __FUNCTION__"(): unrecognized Vcc %u\n", - configure->vcc); + state->Vcc); return -1; } @@ -119,30 +93,20 @@ static int shannon_pcmcia_configure_socket(int sock, const struct pcmcia_configu return 0; } -static int shannon_pcmcia_socket_init(int sock) +static void shannon_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { - 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; + sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int shannon_pcmcia_socket_suspend(int sock) +static void shannon_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - 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; + sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } static struct pcmcia_low_level shannon_pcmcia_ops = { .owner = THIS_MODULE, - .init = shannon_pcmcia_init, - .shutdown = shannon_pcmcia_shutdown, + .hw_init = shannon_pcmcia_hw_init, + .hw_shutdown = shannon_pcmcia_hw_shutdown, .socket_state = shannon_pcmcia_socket_state, .configure_socket = shannon_pcmcia_configure_socket, @@ -155,12 +119,7 @@ int __init pcmcia_shannon_init(struct device *dev) int ret = -ENODEV; if (machine_is_shannon()) - ret = sa1100_register_pcmcia(&shannon_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &shannon_pcmcia_ops, 0, 2); return ret; } - -void __exit pcmcia_shannon_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&shannon_pcmcia_ops, dev); -} diff --git a/drivers/pcmcia/sa1100_simpad.c b/drivers/pcmcia/sa1100_simpad.c index a4e513893231..b54487f437ff 100644 --- a/drivers/pcmcia/sa1100_simpad.c +++ b/drivers/pcmcia/sa1100_simpad.c @@ -19,134 +19,110 @@ extern long get_cs3_shadow(void); extern void set_cs3_bit(int value); extern void clear_cs3_bit(int value); +static struct pcmcia_irqs irqs[] = { + { 1, IRQ_GPIO_CF_CD, "CF_CD" }, +}; -static int simpad_pcmcia_init(struct pcmcia_init *init){ - int irq, res; - - set_cs3_bit(PCMCIA_RESET); - clear_cs3_bit(PCMCIA_BUFF_DIS); - clear_cs3_bit(PCMCIA_RESET); - - clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); - - init->socket_irq[1] = IRQ_GPIO_CF_IRQ; - - /* Register interrupts */ - irq = IRQ_GPIO_CF_CD; - res = request_irq(irq, sa1100_pcmcia_interrupt, SA_INTERRUPT, - "CF_CD", NULL ); - if( res < 0 ) goto irq_err; +static int simpad_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) +{ + set_cs3_bit(PCMCIA_RESET); + clear_cs3_bit(PCMCIA_BUFF_DIS); + clear_cs3_bit(PCMCIA_RESET); - set_irq_type( IRQ_GPIO_CF_CD, IRQT_NOEDGE ); + clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); - /* There's only one slot, but it's "Slot 1": */ - return 2; + skt->irq = IRQ_GPIO_CF_IRQ; -irq_err: - printk( KERN_ERR "%s: request for IRQ%d failed (%d)\n", - __FUNCTION__, irq, res); - return res; + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int simpad_pcmcia_shutdown(void) +static void simpad_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt) { - /* disable IRQs */ - free_irq( IRQ_GPIO_CF_CD, NULL ); - - /* Disable CF bus: */ - - //set_cs3_bit(PCMCIA_BUFF_DIS); - clear_cs3_bit(PCMCIA_RESET); - - return 0; + sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); + + /* Disable CF bus: */ + //set_cs3_bit(PCMCIA_BUFF_DIS); + clear_cs3_bit(PCMCIA_RESET); } -static void simpad_pcmcia_socket_state(int sock, struct pcmcia_state *state) +static void +simpad_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, + struct pcmcia_state *state) { - if (sock == 1) { - unsigned long levels = GPLR; - unsigned long *cs3reg = CS3_BASE; - - state->detect=((levels & GPIO_CF_CD)==0)?1:0; - state->ready=(levels & GPIO_CF_IRQ)?1:0; - state->bvd1=1; /* Not available on Simpad. */ - state->bvd2=1; /* Not available on Simpad. */ - state->wrprot=0; /* Not available on Simpad. */ + unsigned long levels = GPLR; + unsigned long *cs3reg = CS3_BASE; + + state->detect=((levels & GPIO_CF_CD)==0)?1:0; + state->ready=(levels & GPIO_CF_IRQ)?1:0; + state->bvd1=1; /* Not available on Simpad. */ + state->bvd2=1; /* Not available on Simpad. */ + state->wrprot=0; /* Not available on Simpad. */ - if((*cs3reg & 0x0c) == 0x0c) { - state->vs_3v=0; - state->vs_Xv=0; - } else { - state->vs_3v=1; - state->vs_Xv=0; - } - } + if((*cs3reg & 0x0c) == 0x0c) { + state->vs_3v=0; + state->vs_Xv=0; + } else { + state->vs_3v=1; + state->vs_Xv=0; + } } -static int simpad_pcmcia_configure_socket(int sock, const struct pcmcia_configure - *configure) +static int +simpad_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, + const socket_state_t *state) { - unsigned long value, flags; - - if(sock>1) return -1; - - if(sock==0) return 0; - - local_irq_save(flags); - - /* Murphy: see table of MIC2562a-1 */ - - switch(configure->vcc){ - case 0: - clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); - break; - - case 33: - clear_cs3_bit(VCC_3V_EN|EN0); - set_cs3_bit(VCC_5V_EN|EN1); - break; - - case 50: - clear_cs3_bit(VCC_5V_EN|EN1); - set_cs3_bit(VCC_3V_EN|EN0); - break; - - default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); - local_irq_restore(flags); - return -1; - } - - /* Silently ignore Vpp, output enable, speaker enable. */ - - local_irq_restore(flags); - - return 0; + unsigned long value, flags; + + local_irq_save(flags); + + /* Murphy: see table of MIC2562a-1 */ + switch (state->Vcc) { + case 0: + clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); + break; + + case 33: + clear_cs3_bit(VCC_3V_EN|EN0); + set_cs3_bit(VCC_5V_EN|EN1); + break; + + case 50: + clear_cs3_bit(VCC_5V_EN|EN1); + set_cs3_bit(VCC_3V_EN|EN0); + break; + + default: + printk(KERN_ERR "%s(): unrecognized Vcc %u\n", + __FUNCTION__, state->Vcc); + clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); + local_irq_restore(flags); + return -1; + } + + /* Silently ignore Vpp, output enable, speaker enable. */ + local_irq_restore(flags); + + return 0; } -static int simpad_pcmcia_socket_init(int sock) +static void simpad_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { - set_irq_type(IRQ_GPIO_CF_CD, IRQT_BOTHEDGE); - return 0; + sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int simpad_pcmcia_socket_suspend(int sock) +static void simpad_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - set_irq_type(IRQ_GPIO_CF_CD, IRQT_NOEDGE); - return 0; + sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } static struct pcmcia_low_level simpad_pcmcia_ops = { - .owner = THIS_MODULE, - .init = simpad_pcmcia_init, - .shutdown = simpad_pcmcia_shutdown, - .socket_state = simpad_pcmcia_socket_state, - .configure_socket = simpad_pcmcia_configure_socket, - - .socket_init = simpad_pcmcia_socket_init, - .socket_suspend = simpad_pcmcia_socket_suspend, + .owner = THIS_MODULE, + .hw_init = simpad_pcmcia_hw_init, + .hw_shutdown = simpad_pcmcia_hw_shutdown, + .socket_state = simpad_pcmcia_socket_state, + .configure_socket = simpad_pcmcia_configure_socket, + .socket_init = simpad_pcmcia_socket_init, + .socket_suspend = simpad_pcmcia_socket_suspend, }; int __init pcmcia_simpad_init(struct device *dev) @@ -154,12 +130,7 @@ int __init pcmcia_simpad_init(struct device *dev) int ret = -ENODEV; if (machine_is_simpad()) - ret = sa1100_register_pcmcia(&simpad_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &simpad_pcmcia_ops, 1, 1); return ret; } - -void __exit pcmcia_simpad_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&simpad_pcmcia_ops, dev); -} diff --git a/drivers/pcmcia/sa1100_stork.c b/drivers/pcmcia/sa1100_stork.c index 504f8b4ac392..c3aa895bff30 100644 --- a/drivers/pcmcia/sa1100_stork.c +++ b/drivers/pcmcia/sa1100_stork.c @@ -32,62 +32,39 @@ static int debug = 0; -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 struct pcmcia_irqs irqs[] = { + { 0, IRQ_GPIO_STORK_PCMCIA_A_CARD_DETECT, "PCMCIA_CD0" }, + { 1, IRQ_GPIO_STORK_PCMCIA_B_CARD_DETECT, "PCMCIA_CD1" }, }; -static int stork_pcmcia_init(struct pcmcia_init *init) +static int stork_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { - int irq, res; - printk("in stork_pcmcia_init\n"); - init->socket_irq[0] = IRQ_GPIO_STORK_PCMCIA_A_RDY; - init->socket_irq[1] = IRQ_GPIO_STORK_PCMCIA_B_RDY; - - /* Register interrupts */ - for (i = 0; i < ARRAY_SIZE(irqs); i++) { - res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt, - SA_INTERRUPT, irqs[i].str, NULL); - if (res) - goto irq_err; - set_irq_type(irqs[i].irq, IRQT_NOEDGE); - } - - return 2; - - irq_err: - printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n", - __FUNCTION__, irq, res); + skt->irq = skt->nr ? IRQ_GPIO_STORK_PCMCIA_B_RDY + : IRQ_GPIO_STORK_PCMCIA_A_RDY; - while (i--) - free_irq(irqs[i].irq, NULL); - - return res; + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int stork_pcmcia_shutdown(void) +static void stork_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt) { int i; printk(__FUNCTION__ "\n"); /* disable IRQs */ - for (i = 0; i < ARRAY_SIZE(irqs); i++) - free_irq(irqs[i].irq, NULL); + sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); /* Disable CF bus: */ storkClearLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON); storkClearLatchA(STORK_PCMCIA_A_POWER_ON); storkClearLatchA(STORK_PCMCIA_B_POWER_ON); - return 0; } -static void stork_pcmcia_socket_state(int sock, struct pcmcia_state *state) +static void +stork_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, + struct pcmcia_state *state) { unsigned long levels = GPLR; @@ -95,7 +72,7 @@ static void stork_pcmcia_socket_state(int sock, struct pcmcia_state *state) printk(__FUNCTION__ " GPLR=%x IRQ[1:0]=%x\n", levels, (levels & (GPIO_STORK_PCMCIA_A_RDY|GPIO_STORK_PCMCIA_B_RDY))); - switch (sock) { + switch (skt->nr) { case 0: state->detect=((levels & GPIO_STORK_PCMCIA_A_CARD_DETECT)==0)?1:0; state->ready=(levels & GPIO_STORK_PCMCIA_A_RDY)?1:0; @@ -118,20 +95,19 @@ static void stork_pcmcia_socket_state(int sock, struct pcmcia_state *state) } } -static int stork_pcmcia_configure_socket(int sock, const struct pcmcia_configure *configure) +static int +stork_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, + const socket_state_t *state) { unsigned long flags; - int DETECT, RDY, POWER, RESET; - if (sock > 1) return -1; - - printk(__FUNCTION__ ": socket=%d vcc=%d vpp=%d reset=%d\n", - sock, configure->vcc, configure->vpp, configure->reset); + printk("%s: socket=%d vcc=%d vpp=%d reset=%d\n", __FUNCTION__, + skt->nr, state->Vcc, state->Vpp, state->flags & SS_RESET ? 1 : 0); local_irq_save(flags); - if (sock == 0) { + if (skt->nr == 0) { DETECT = GPIO_STORK_PCMCIA_A_CARD_DETECT; RDY = GPIO_STORK_PCMCIA_A_RDY; POWER = STORK_PCMCIA_A_POWER_ON; @@ -148,7 +124,7 @@ static int stork_pcmcia_configure_socket(int sock, const struct pcmcia_configure printk("no card detected - but resetting anyway\r\n"); } */ - switch (configure->vcc) { + switch (state->Vcc) { case 0: /* storkClearLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON); */ storkClearLatchA(POWER); @@ -162,12 +138,12 @@ static int stork_pcmcia_configure_socket(int sock, const struct pcmcia_configure default: printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); + state->Vcc); local_irq_restore(flags); return -1; } - if (configure->reset) + if (state->flags & SS_RESET) storkSetLatchB(RESET); else storkClearLatchB(RESET); @@ -176,43 +152,35 @@ static int stork_pcmcia_configure_socket(int sock, const struct pcmcia_configure /* silently ignore vpp and speaker enables. */ - printk(__FUNCTION__ ": finished\n"); + printk("%s: finished\n", __FUNCTION__); return 0; } -static int stork_pcmcia_socket_init(int sock) +static void stork_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { 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; + sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int stork_pcmcia_socket_suspend(int sock) +static void stork_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - 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! - */ + sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); + + /* + * Hack! + */ + if (skt->nr == 1) storkClearLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON); - } return 0; } static struct pcmcia_low_level stork_pcmcia_ops = { .owner = THIS_MODULE, - .init = stork_pcmcia_init, - .shutdown = stork_pcmcia_shutdown, + .hw_init = stork_pcmcia_hw_init, + .hw_shutdown = stork_pcmcia_hw_shutdown, .socket_state = stork_pcmcia_socket_state, .configure_socket = stork_pcmcia_configure_socket, @@ -225,13 +193,7 @@ int __init pcmcia_stork_init(struct device *dev) int ret = -ENODEV; if (machine_is_stork()) - ret = sa1100_register_pcmcia(&stork_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &stork_pcmcia_ops, 0, 2); return ret; } - -void __exit pcmcia_stork_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&stork_pcmcia_ops, dev); -} - diff --git a/drivers/pcmcia/sa1100_system3.c b/drivers/pcmcia/sa1100_system3.c index c0ed16a94b1f..28ac8ec5f736 100644 --- a/drivers/pcmcia/sa1100_system3.c +++ b/drivers/pcmcia/sa1100_system3.c @@ -37,7 +37,6 @@ #include <asm/irq.h> #include <asm/hardware/sa1111.h> -#include "sa1100_generic.h" #include "sa1111_generic.h" #define DEBUG 0 @@ -48,34 +47,24 @@ # define DPRINTK( x, args... ) /* nix */ #endif -int system3_pcmcia_init(struct pcmcia_init *init) +static int system3_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { - init->socket_irq[0] = IRQ_S0_READY_NINT; - init->socket_irq[1] = IRQ_S1_READY_NINT; + skt->irq = skt->nr ? IRQ_S1_READY_NINT : IRQ_S0_READY_NINT; /* Don't need no CD and BVD* interrupts */ - return 2; -} - -int system3_pcmcia_shutdown(void) -{ return 0; } -int system3_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) +void system3_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt) { - /* only CF ATM */ - if (sock == 0) - return -1; - - return sa1111_pcmcia_configure_socket(sock, conf); } -static void system3_pcmcia_socket_state(int sock, struct pcmcia_state *state) +static void +system3_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, struct pcmcia_state *state) { unsigned long status = PCSR; - switch (sock) { + switch (skt->nr) { #if 0 /* PCMCIA socket not yet connected */ case 0: state->detect = status & PCSR_S0_DETECT ? 0 : 1; @@ -100,15 +89,15 @@ static void system3_pcmcia_socket_state(int sock, struct pcmcia_state *state) } DPRINTK("Sock %d PCSR=0x%08lx, Sx_RDY_nIREQ=%d\n", - sock, status, state->ready); + skt->nr, status, state->ready); } struct pcmcia_low_level system3_pcmcia_ops = { .owner = THIS_MODULE, - .init = system3_pcmcia_init, - .shutdown = system3_pcmcia_shutdown, + .init = system3_pcmcia_hw_init, + .shutdown = system3_pcmcia_hw_shutdown, .socket_state = system3_pcmcia_socket_state, - .configure_socket = system3_pcmcia_configure_socket, + .configure_socket = sa1111_pcmcia_configure_socket, .socket_init = sa1111_pcmcia_socket_init, .socket_suspend = sa1111_pcmcia_socket_suspend, @@ -119,12 +108,8 @@ int __init pcmcia_system3_init(struct device *dev) int ret = -ENODEV; if (machine_is_pt_system3()) - ret = sa1100_register_pcmcia(&system3_pcmcia_ops, dev); + /* only CF ATM */ + ret = sa11xx_drv_pcmcia_probe(dev, &system3_pcmcia_ops, 1, 1); return ret; } - -void __exit pcmcia_system3_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&system3_pcmcia_ops, dev); -} diff --git a/drivers/pcmcia/sa1100_trizeps.c b/drivers/pcmcia/sa1100_trizeps.c index 77de63b6973a..752bba3b6c35 100644 --- a/drivers/pcmcia/sa1100_trizeps.c +++ b/drivers/pcmcia/sa1100_trizeps.c @@ -23,15 +23,18 @@ #include "sa1100_generic.h" #define NUMBER_OF_TRIZEPS_PCMCIA_SLOTS 1 + +static struct pcmcia_irqs irqs[] = { + { 0, TRIZEPS_IRQ_PCMCIA_CD0, "PCMCIA_CD0" }, +}; + /** * * ******************************************************/ -static int trizeps_pcmcia_init(struct pcmcia_init *init) +static int trizeps_pcmcia_init(struct sa1100_pcmcia_socket *skt) { - int res; - - init->socket_irq[0] = TRIZEPS_IRQ_PCMCIA_IRQ0; + skt->irq = TRIZEPS_IRQ_PCMCIA_IRQ0; /* Enable CF bus: */ TRIZEPS_BCR_clear(TRIZEPS_BCR1, TRIZEPS_nPCM_ENA_REG); @@ -40,74 +43,54 @@ static int trizeps_pcmcia_init(struct pcmcia_init *init) GPDR &= ~((GPIO_GPIO(TRIZEPS_GPIO_PCMCIA_CD0)) | (GPIO_GPIO(TRIZEPS_GPIO_PCMCIA_IRQ0))); - /* Register SOCKET interrupts */ - /* WHY? */ - res = request_irq(TRIZEPS_IRQ_PCMCIA_CD0, sa1100_pcmcia_interrupt, - SA_INTERRUPT, "PCMCIA_CD0", NULL ); - if( res < 0 ) goto irq_err; - set_irq_type(TRIZEPS_IRQ_PCMCIA_CD0, IRQT_NOEDGE); - - //MECR = 0x00060006; // Initialised on trizeps init - - // return=sa1100_pcmcia_socket_count (sa1100_generic.c) - // -> number of PCMCIA Slots - // Slot 0 -> Trizeps PCMCIA - // Slot 1 -> Trizeps ISA-Bus - return NUMBER_OF_TRIZEPS_PCMCIA_SLOTS; - - irq_err: - printk( KERN_ERR "%s(): PCMCIA Request for IRQ %u failed\n", __FUNCTION__, TRIZEPS_IRQ_PCMCIA_CD0 ); - return -1; + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } /** * * ******************************************************/ -static int trizeps_pcmcia_shutdown(void) +static void trizeps_pcmcia_shutdown(struct sa1100_pcmcia_socket *skt) { printk(">>>>>PCMCIA TRIZEPS shutdown\n"); - /* disable IRQs */ - free_irq(TRIZEPS_IRQ_PCMCIA_CD0, NULL ); + + sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); /* Disable CF bus: */ TRIZEPS_BCR_set(TRIZEPS_BCR1, TRIZEPS_nPCM_ENA_REG); - - return 0; } /** * - ******************************************************/ -static void trizeps_pcmcia_socket_state(int sock, struct pcmcia_state *state_array) +static void +trizeps_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, + struct pcmcia_state *state_array) { unsigned long levels = GPLR; - if (sock == 0) { - state->detect = ((levels & GPIO_GPIO(TRIZEPS_GPIO_PCMCIA_CD0)) == 0) ? 1 : 0; - state->ready = ((levels & GPIO_GPIO(TRIZEPS_GPIO_PCMCIA_IRQ0)) != 0) ? 1 : 0; - state->bvd1 = ((TRIZEPS_BCR1 & TRIZEPS_PCM_BVD1) !=0 ) ? 1 : 0; - state->bvd2 = ((TRIZEPS_BCR1 & TRIZEPS_PCM_BVD2) != 0) ? 1 : 0; - state->wrprot = 0; // not write protected - state->vs_3v = ((TRIZEPS_BCR1 & TRIZEPS_nPCM_VS1) == 0) ? 1 : 0; //VS1=0 -> vs_3v=1 - state->vs_Xv = ((TRIZEPS_BCR1 & TRIZEPS_nPCM_VS2) == 0) ? 1 : 0; //VS2=0 -> vs_Xv=1 - } + state->detect = ((levels & GPIO_GPIO(TRIZEPS_GPIO_PCMCIA_CD0)) == 0) ? 1 : 0; + state->ready = ((levels & GPIO_GPIO(TRIZEPS_GPIO_PCMCIA_IRQ0)) != 0) ? 1 : 0; + state->bvd1 = ((TRIZEPS_BCR1 & TRIZEPS_PCM_BVD1) !=0 ) ? 1 : 0; + state->bvd2 = ((TRIZEPS_BCR1 & TRIZEPS_PCM_BVD2) != 0) ? 1 : 0; + state->wrprot = 0; // not write protected + state->vs_3v = ((TRIZEPS_BCR1 & TRIZEPS_nPCM_VS1) == 0) ? 1 : 0; //VS1=0 -> vs_3v=1 + state->vs_Xv = ((TRIZEPS_BCR1 & TRIZEPS_nPCM_VS2) == 0) ? 1 : 0; //VS2=0 -> vs_Xv=1 } /** * * ******************************************************/ -static int trizeps_pcmcia_configure_socket(int sock, const struct pcmcia_configure *configure) +static int +trizeps_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, + const socket_state_t *state) { unsigned long flags; - if(sock>1) return -1; - local_irq_save(flags); - switch (configure->vcc) { + switch (state->Vcc) { case 0: printk(">>> PCMCIA Power off\n"); TRIZEPS_BCR_clear(TRIZEPS_BCR1, TRIZEPS_PCM_V3_EN_REG); @@ -126,19 +109,19 @@ static int trizeps_pcmcia_configure_socket(int sock, const struct pcmcia_configu break; default: printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); + state->Vcc); local_irq_restore(flags); return -1; } - if (configure->reset) + if (state->flags & SS_RESET) TRIZEPS_BCR_set(TRIZEPS_BCR1, TRIZEPS_nPCM_RESET_DISABLE); // Reset else TRIZEPS_BCR_clear(TRIZEPS_BCR1, TRIZEPS_nPCM_RESET_DISABLE); // no Reset /* printk(" vcc=%u vpp=%u -->reset=%i\n", - configure->vcc, - configure->vpp, + state->Vcc, + state->Vpp, ((BCR_read(1) & nPCM_RESET_DISABLE)? 1:0)); */ local_irq_restore(flags); @@ -146,16 +129,14 @@ static int trizeps_pcmcia_configure_socket(int sock, const struct pcmcia_configu return 0; } -static int trizeps_pcmcia_socket_init(int sock) +static void trizeps_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { - set_irq_type(TRIZEPS_IRQ_PCMCIA_CD0, IRQT_BOTHEDGE); - return 0; + sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int trizeps_pcmcia_socket_suspend(int sock) +static void trizeps_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - set_irq_type(TRIZEPS_IRQ_PCMCIA_CD0, IRQT_NOEDGE); - return 0; + sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } /** @@ -164,8 +145,8 @@ static int trizeps_pcmcia_socket_suspend(int sock) ******************************************************/ struct pcmcia_low_level trizeps_pcmcia_ops = { .owner = THIS_MODULE, - .init = trizeps_pcmcia_init, - .shutdown = trizeps_pcmcia_shutdown, + .hw_init = trizeps_pcmcia_hw_init, + .hw_shutdown = trizeps_pcmcia_hw_shutdown, .socket_state = trizeps_pcmcia_socket_state, .configure_socket = trizeps_pcmcia_configure_socket, .socket_init = trizeps_pcmcia_socket_init, @@ -174,13 +155,11 @@ struct pcmcia_low_level trizeps_pcmcia_ops = { int __init pcmcia_trizeps_init(struct device *dev) { - if (machine_is_trizeps()) { - return sa1100_register_pcmcia(&trizeps_pcmcia_ops, dev); - } - return -ENODEV; -} + int ret = -ENODEV; -void __exit pcmcia_trizeps_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&trizeps_pcmcia_ops, dev); + if (machine_is_trizeps()) + ret = sa11xx_drv_pcmcia_probe(dev, &trizeps_pcmcia_ops, 0, + NUMBER_OF_TRIZEPS_PCMCIA_SLOTS); + + return ret; } diff --git a/drivers/pcmcia/sa1100_xp860.c b/drivers/pcmcia/sa1100_xp860.c index 3bb1cc41396c..ea0629107f79 100644 --- a/drivers/pcmcia/sa1100_xp860.c +++ b/drivers/pcmcia/sa1100_xp860.c @@ -19,7 +19,7 @@ #define NCR_A0VPP (1<<16) #define NCR_A1VPP (1<<17) -static int xp860_pcmcia_init(struct pcmcia_init *init) +static int xp860_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */ PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); @@ -38,11 +38,11 @@ static int xp860_pcmcia_init(struct pcmcia_init *init) GPDR |= (NCR_A0VPP | NCR_A1VPP); GPCR &= ~(NCR_A0VPP | NCR_A1VPP); - return sa1111_pcmcia_init(init); + return sa1111_pcmcia_hw_init(skt); } static int -xp860_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) +xp860_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, const socket_state_t *state) { unsigned int gpio_mask, pa_dwr_mask; unsigned int gpio_set, pa_dwr_set; @@ -72,28 +72,28 @@ xp860_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) * the corresponding truth table. */ - switch (sock) { + switch (skt->nr) { case 0: pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1; gpio_mask = NCR_A0VPP | NCR_A1VPP; - switch (conf->vcc) { + switch (state->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) { + switch (state->Vpp) { case 0: gpio_set = 0; break; case 120: gpio_set = NCR_A1VPP; break; default: - if (conf->vpp == conf->vcc) + if (state->Vpp == state->Vcc) gpio_set = NCR_A0VPP; else { printk(KERN_ERR "%s(): unrecognized Vpp %u\n", - __FUNCTION__, conf->vpp); + __FUNCTION__, state->Vpp); return -1; } } @@ -104,22 +104,22 @@ xp860_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) gpio_mask = 0; gpio_set = 0; - switch (conf->vcc) { + switch (state->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) { + if (state->Vpp != state->Vcc && state->Vpp != 0) { printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", - __FUNCTION__, conf->vpp); + __FUNCTION__, state->Vpp); return -1; } break; } - ret = sa1111_pcmcia_configure_socket(sock, conf); + ret = sa1111_pcmcia_configure_socket(skt, state); if (ret == 0) { unsigned long flags; @@ -134,14 +134,13 @@ xp860_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) } static struct pcmcia_low_level xp860_pcmcia_ops = { - .owner = THIS_MODULE, - .init = xp860_pcmcia_init, - .shutdown = sa1111_pcmcia_shutdown, - .socket_state = sa1111_pcmcia_socket_state, - .configure_socket = xp860_pcmcia_configure_socket, - - .socket_init = sa1111_pcmcia_socket_init, - .socket_suspend = sa1111_pcmcia_socket_suspend, + .owner = THIS_MODULE, + .hw_init = xp860_pcmcia_hw_init, + .hw_shutdown = sa1111_pcmcia_hw_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .configure_socket = xp860_pcmcia_configure_socket, + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_xp860_init(struct device *dev) @@ -149,13 +148,7 @@ int __init pcmcia_xp860_init(struct device *dev) int ret = -ENODEV; if (machine_is_xp860()) - ret = sa1100_register_pcmcia(&xp860_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &xp860_pcmcia_ops, 0, 2); return ret; } - -void __exit pcmcia_xp860_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&xp860_pcmcia_ops, dev); -} - diff --git a/drivers/pcmcia/sa1100_yopy.c b/drivers/pcmcia/sa1100_yopy.c index 261aa7040a2a..d0eec8fae712 100644 --- a/drivers/pcmcia/sa1100_yopy.c +++ b/drivers/pcmcia/sa1100_yopy.c @@ -27,81 +27,51 @@ 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 struct pcmcia_irqs irqs[] = { + { 0, IRQ_CF_CD, "CF_CD" }, + { 0, IRQ_CF_BVD2, "CF_BVD2" }, + { 0, IRQ_CF_BVD1, "CF_BVD1" }, }; -static int yopy_pcmcia_init(struct pcmcia_init *init) +static int yopy_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { - int i, res; - - init->socket_irq[0] = IRQ_CF_IREQ; + skt->irq = IRQ_CF_IREQ; pcmcia_power(0); pcmcia_reset(1); - /* Register interrupts */ - for (i = 0; i < ARRAY_SIZE(irqs); i++) { - res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt, - SA_INTERRUPT, irqs[i].str, NULL); - if (res) - goto irq_err; - set_irq_type(irqs[i].irq, IRQT_NOEDGE); - } - - 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; + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int yopy_pcmcia_shutdown(void) +static void yopy_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt) { - int i; - - /* disable IRQs */ - for (i = 0; i < ARRAY_SIZE(irqs); i++) - free_irq(irqs[i].irq, NULL); + sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); /* Disable CF */ pcmcia_reset(1); pcmcia_power(0); - - return 0; } -static void yopy_pcmcia_socket_state(int sock, struct pcmcia_state_array *state) +static void +yopy_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, + struct pcmcia_state_array *state) { unsigned long levels = GPLR; - if (sock == 0) { - state->detect = (levels & GPIO_CF_CD) ? 0 : 1; - state->ready = (levels & GPIO_CF_READY) ? 1 : 0; - state->bvd1 = (levels & GPIO_CF_BVD1) ? 1 : 0; - state->bvd2 = (levels & GPIO_CF_BVD2) ? 1 : 0; - state->wrprot = 0; /* Not available on Yopy. */ - state->vs_3v = 0; /* FIXME Can only apply 3.3V on Yopy. */ - state->vs_Xv = 0; - } + state->detect = (levels & GPIO_CF_CD) ? 0 : 1; + state->ready = (levels & GPIO_CF_READY) ? 1 : 0; + state->bvd1 = (levels & GPIO_CF_BVD1) ? 1 : 0; + state->bvd2 = (levels & GPIO_CF_BVD2) ? 1 : 0; + state->wrprot = 0; /* Not available on Yopy. */ + state->vs_3v = 0; /* FIXME Can only apply 3.3V on Yopy. */ + state->vs_Xv = 0; } -static int yopy_pcmcia_configure_socket(int sock, const struct pcmcia_configure *configure) +static int +yopy_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, + const socket_state_t *state) { - if (sock != 0) - return -1; - - switch (configure->vcc) { + switch (state->Vcc) { case 0: /* power off */ pcmcia_power(0); break; @@ -112,35 +82,25 @@ static int yopy_pcmcia_configure_socket(int sock, const struct pcmcia_configure break; default: printk(KERN_ERR __FUNCTION__"(): unrecognized Vcc %u\n", - configure->vcc); + state->Vcc); return -1; } - pcmcia_reset(configure->reset); + pcmcia_reset(state->flags & SS_RESET ? 1 : 0); /* Silently ignore Vpp, output enable, speaker enable. */ return 0; } -static int yopy_pcmcia_socket_init(int sock) +static void yopy_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { - int i; - - for (i = 0; i < ARRAY_SIZE(irqs); i++) - set_irq_type(irqs[i].irq, IRQT_BOTHEDGE); - - return 0; + sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int yopy_pcmcia_socket_suspend(int sock) +static void yopy_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - int i; - - for (i = 0; i < ARRAY_SIZE(irqs); i++) - set_irq_type(irqs[i].irq, IRQT_NOEDGE); - - return 0; + sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } static struct pcmcia_low_level yopy_pcmcia_ops = { @@ -159,13 +119,7 @@ int __init pcmcia_yopy_init(struct device *dev) int ret = -ENODEV; if (machine_is_yopy()) - ret = sa1100_register_pcmcia(&yopy_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &yopy_pcmcia_ops, 0, 1); return ret; } - -void __exit pcmcia_yopy_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&yopy_pcmcia_ops, dev); -} - diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c index b274c9e600e7..1603014db1cf 100644 --- a/drivers/pcmcia/sa1111_generic.c +++ b/drivers/pcmcia/sa1111_generic.c @@ -1,5 +1,5 @@ /* - * linux/drivers/pcmcia/sa1100_sa1111.c + * linux/drivers/pcmcia/sa1111_generic.c * * We implement the generic parts of a SA1111 PCMCIA driver. This * basically means we handle everything except controlling the @@ -19,63 +19,34 @@ #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[] = { - { IRQ_S0_CD_VALID, "SA1111 PCMCIA card detect" }, - { IRQ_S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1" }, - { IRQ_S1_CD_VALID, "SA1111 CF card detect" }, - { IRQ_S1_BVD1_STSCHG, "SA1111 CF BVD1" }, +static struct pcmcia_irqs irqs[] = { + { 0, IRQ_S0_CD_VALID, "SA1111 PCMCIA card detect" }, + { 0, IRQ_S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1" }, + { 1, IRQ_S1_CD_VALID, "SA1111 CF card detect" }, + { 1, IRQ_S1_BVD1_STSCHG, "SA1111 CF BVD1" }, }; -static struct sa1111_dev *pcmcia; - -int sa1111_pcmcia_init(struct pcmcia_init *init) +int sa1111_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { - int i, ret; - - if (init->socket_irq[0] == NO_IRQ) - init->socket_irq[0] = IRQ_S0_READY_NINT; - if (init->socket_irq[1] == NO_IRQ) - init->socket_irq[1] = IRQ_S1_READY_NINT; - - for (i = ret = 0; i < ARRAY_SIZE(irqs); i++) { - ret = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt, - SA_INTERRUPT, irqs[i].str, NULL); - if (ret) - break; - set_irq_type(irqs[i].irq, IRQT_FALLING); - } - - 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); - } + if (skt->irq == NO_IRQ) + skt->irq = skt->nr ? IRQ_S1_READY_NINT : IRQ_S0_READY_NINT; - return ret ? -1 : 2; + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -int sa1111_pcmcia_shutdown(void) +void sa1111_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt) { - int i; - - for (i = 0; i < ARRAY_SIZE(irqs); i++) - free_irq(irqs[i].irq, NULL); - - return 0; + sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -void sa1111_pcmcia_socket_state(int sock, struct pcmcia_state *state) +void sa1111_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, struct pcmcia_state *state) { - unsigned long status = sa1111_readl(pcmcia->mapbase + SA1111_PCSR); + struct sa1111_dev *sadev = SA1111_DEV(skt->dev); + unsigned long status = sa1111_readl(sadev->mapbase + SA1111_PCSR); - switch (sock) { + switch (skt->nr) { case 0: state->detect = status & PCSR_S0_DETECT ? 0 : 1; state->ready = status & PCSR_S0_READY ? 1 : 0; @@ -98,91 +69,61 @@ void sa1111_pcmcia_socket_state(int sock, struct pcmcia_state *state) } } -int sa1111_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) +int sa1111_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, const socket_state_t *state) { - unsigned int rst, flt, wait, pse, irq, pccr_mask, val; + struct sa1111_dev *sadev = SA1111_DEV(skt->dev); + unsigned int pccr_skt_mask, pccr_set_mask, val; unsigned long flags; - switch (sock) { + switch (skt->nr) { case 0: - rst = PCCR_S0_RST; - flt = PCCR_S0_FLT; - wait = PCCR_S0_PWAITEN; - pse = PCCR_S0_PSE; - irq = IRQ_S0_READY_NINT; + pccr_skt_mask = PCCR_S0_RST|PCCR_S0_FLT|PCCR_S0_PWAITEN|PCCR_S0_PSE; break; case 1: - rst = PCCR_S1_RST; - flt = PCCR_S1_FLT; - wait = PCCR_S1_PWAITEN; - pse = PCCR_S1_PSE; - irq = IRQ_S1_READY_NINT; + pccr_skt_mask = PCCR_S1_RST|PCCR_S1_FLT|PCCR_S1_PWAITEN|PCCR_S1_PSE; break; default: return -1; } - switch (conf->vcc) { - case 0: - pccr_mask = 0; - break; - - case 33: - pccr_mask = wait; - break; + pccr_set_mask = 0; - 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; + if (state->Vcc != 0) + pccr_set_mask |= PCCR_S0_PWAITEN|PCCR_S1_PWAITEN; + if (state->Vcc == 50) + pccr_set_mask |= PCCR_S0_PSE|PCCR_S1_PSE; + if (state->flags & SS_RESET) + pccr_set_mask |= PCCR_S0_RST|PCCR_S1_RST; + if (state->flags & SS_OUTPUT_ENA) + pccr_set_mask |= PCCR_S0_FLT|PCCR_S1_FLT; local_irq_save(flags); - val = sa1111_readl(pcmcia->mapbase + SA1111_PCCR); - val = (val & ~(pse | flt | wait | rst)) | pccr_mask; - sa1111_writel(val, pcmcia->mapbase + SA1111_PCCR); + val = sa1111_readl(sadev->mapbase + SA1111_PCCR); + val &= ~pccr_skt_mask; + val |= pccr_set_mask & pccr_skt_mask; + sa1111_writel(val, sadev->mapbase + SA1111_PCCR); local_irq_restore(flags); return 0; } -int sa1111_pcmcia_socket_init(int sock) +void sa1111_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { - return 0; + sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -int sa1111_pcmcia_socket_suspend(int sock) +void sa1111_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - return 0; + sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } static int pcmcia_probe(struct device *dev) { struct sa1111_dev *sadev = SA1111_DEV(dev); - unsigned long flags; char *base; - local_irq_save(flags); - if (pcmcia) { - local_irq_restore(flags); - return -EBUSY; - } - - pcmcia = sadev; - local_irq_restore(flags); - if (!request_mem_region(sadev->res.start, 512, SA1111_DRIVER_NAME(sadev))) return -EBUSY; @@ -226,34 +167,8 @@ static int __devexit pcmcia_remove(struct device *dev) { struct sa1111_dev *sadev = SA1111_DEV(dev); -#ifdef CONFIG_SA1100_ADSBITSY - pcmcia_adsbitsy_exit(dev); -#endif -#ifdef CONFIG_SA1100_BADGE4 - pcmcia_badge4_exit(dev); -#endif -#ifdef CONFIG_SA1100_GRAPHICSMASTER - pcmcia_graphicsmaster_exit(dev); -#endif -#ifdef CONFIG_SA1100_JORNADA720 - pcmcia_jornada720_exit(dev); -#endif -#ifdef CONFIG_ASSABET_NEPONSET - pcmcia_neponset_exit(dev); -#endif -#ifdef CONFIG_SA1100_PFS168 - pcmcia_pfs_exit(dev); -#endif -#ifdef CONFIG_SA1100_PT_SYSTEM3 - pcmcia_system3_exit(dev); -#endif -#ifdef CONFIG_SA1100_XP860 - pcmcia_xp860_exit(dev); -#endif - + sa11xx_drv_pcmcia_remove(dev); release_mem_region(sadev->res.start, 512); - pcmcia = NULL; - return 0; } diff --git a/drivers/pcmcia/sa1111_generic.h b/drivers/pcmcia/sa1111_generic.h index 459d7b1145cd..27f3e35bda31 100644 --- a/drivers/pcmcia/sa1111_generic.h +++ b/drivers/pcmcia/sa1111_generic.h @@ -1,14 +1,12 @@ -extern int sa1111_pcmcia_init(struct pcmcia_init *); -extern int sa1111_pcmcia_shutdown(void); -extern void sa1111_pcmcia_socket_state(int sock, struct pcmcia_state *); -extern int sa1111_pcmcia_configure_socket(int sock, const struct pcmcia_configure *); -extern int sa1111_pcmcia_socket_init(int); -extern int sa1111_pcmcia_socket_suspend(int); +#include "sa11xx_core.h" +extern int sa1111_pcmcia_hw_init(struct sa1100_pcmcia_socket *); +extern void sa1111_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *); +extern void sa1111_pcmcia_socket_state(struct sa1100_pcmcia_socket *, struct pcmcia_state *); +extern int sa1111_pcmcia_configure_socket(struct sa1100_pcmcia_socket *, const socket_state_t *); +extern void sa1111_pcmcia_socket_init(struct sa1100_pcmcia_socket *); +extern void sa1111_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *); extern int pcmcia_jornada720_init(struct device *); -extern void pcmcia_jornada720_exit(struct device *); - extern int pcmcia_neponset_init(struct device *); -extern void pcmcia_neponset_exit(struct device *); diff --git a/drivers/pcmcia/sa11xx_core.c b/drivers/pcmcia/sa11xx_core.c new file mode 100644 index 000000000000..886c3056c924 --- /dev/null +++ b/drivers/pcmcia/sa11xx_core.c @@ -0,0 +1,1054 @@ +/*====================================================================== + + Device driver for the PCMCIA control functionality of StrongARM + SA-1100 microprocessors. + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is John G. Dorsey + <john+@cs.cmu.edu>. Portions created by John G. Dorsey are + Copyright (C) 1999 John G. Dorsey. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + 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> +#include <linux/config.h> +#include <linux/cpufreq.h> +#include <linux/delay.h> +#include <linux/ioport.h> +#include <linux/kernel.h> +#include <linux/workqueue.h> +#include <linux/timer.h> +#include <linux/mm.h> +#include <linux/notifier.h> +#include <linux/proc_fs.h> +#include <linux/version.h> +#include <linux/interrupt.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/system.h> + +#include "sa11xx_core.h" +#include "sa1100.h" + +#ifdef PCMCIA_DEBUG +static int pc_debug; +#endif + +/* 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]; + +#define PCMCIA_SOCKET(x) (sa1100_pcmcia_socket + (x)) + +/* + * sa1100_pcmcia_default_mecr_timing + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * + * Calculate MECR clock wait states for given CPU clock + * speed and command wait state. This function can be over- + * written by a board specific version. + * + * The default is to simply calculate the BS values as specified in + * the INTEL SA1100 development manual + * "Expansion Memory (PCMCIA) Configuration Register (MECR)" + * that's section 10.2.5 in _my_ version of the manual ;) + */ +static unsigned int +sa1100_pcmcia_default_mecr_timing(struct sa1100_pcmcia_socket *skt, + unsigned int cpu_speed, + unsigned int cmd_time) +{ + return sa1100_pcmcia_mecr_bs(cmd_time, cpu_speed); +} + +static unsigned short +calc_speed(unsigned short *spds, int num, unsigned short dflt) +{ + unsigned short speed = 0; + int i; + + for (i = 0; i < num; i++) + if (speed < spds[i]) + speed = spds[i]; + if (speed == 0) + speed = dflt; + + return speed; +} + +/* sa1100_pcmcia_set_mecr() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * + * set MECR value for socket <sock> based on this sockets + * io, mem and attribute space access speed. + * Call board specific BS value calculation to allow boards + * to tweak the BS values. + */ +static int +sa1100_pcmcia_set_mecr(struct sa1100_pcmcia_socket *skt, unsigned int cpu_clock) +{ + u32 mecr, old_mecr; + unsigned long flags; + unsigned short speed; + unsigned int bs_io, bs_mem, bs_attr; + int i; + + speed = calc_speed(skt->spd_io, MAX_IO_WIN, SA1100_PCMCIA_IO_ACCESS); + bs_io = skt->ops->socket_get_timing(skt, cpu_clock, speed); + + speed = calc_speed(skt->spd_mem, MAX_WIN, SA1100_PCMCIA_3V_MEM_ACCESS); + bs_mem = skt->ops->socket_get_timing(skt, cpu_clock, speed); + + speed = calc_speed(skt->spd_attr, MAX_WIN, SA1100_PCMCIA_3V_MEM_ACCESS); + bs_attr = skt->ops->socket_get_timing(skt, cpu_clock, speed); + + local_irq_save(flags); + + old_mecr = mecr = MECR; + MECR_FAST_SET(mecr, skt->nr, 0); + MECR_BSIO_SET(mecr, skt->nr, bs_io); + MECR_BSA_SET(mecr, skt->nr, bs_attr); + MECR_BSM_SET(mecr, skt->nr, bs_mem); + if (old_mecr != mecr) + MECR = mecr; + + local_irq_restore(flags); + + DEBUG(4, "%s(): sock %u FAST %X BSM %X BSA %X BSIO %X\n", + __FUNCTION__, skt->nr, MECR_FAST_GET(mecr, skt->nr), + MECR_BSM_GET(mecr, skt->nr), MECR_BSA_GET(mecr, skt->nr), + MECR_BSIO_GET(mecr, skt->nr)); + + return 0; +} + +static unsigned int sa1100_pcmcia_skt_state(struct sa1100_pcmcia_socket *skt) +{ + struct pcmcia_state state; + unsigned int stat; + + memset(&state, 0, sizeof(struct pcmcia_state)); + + skt->ops->socket_state(skt, &state); + + stat = state.detect ? SS_DETECT : 0; + stat |= state.ready ? SS_READY : 0; + stat |= state.wrprot ? SS_WRPROT : 0; + stat |= state.vs_3v ? SS_3VCARD : 0; + stat |= state.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: + */ + stat |= skt->cs_state.Vcc ? SS_POWERON : 0; + + if (skt->cs_state.flags & SS_IOCARD) + stat |= state.bvd1 ? SS_STSCHG : 0; + else { + if (state.bvd1 == 0) + stat |= SS_BATDEAD; + else if (state.bvd2 == 0) + stat |= SS_BATWARN; + } + return stat; +} + +/* + * sa1100_pcmcia_config_skt + * ^^^^^^^^^^^^^^^^^^^^^^^^ + * + * Convert PCMCIA socket state to our socket configure structure. + */ +static int +sa1100_pcmcia_config_skt(struct sa1100_pcmcia_socket *skt, socket_state_t *state) +{ + int ret; + + ret = skt->ops->configure_socket(skt, state); + if (ret == 0) { + /* + * This really needs a better solution. The IRQ + * may or may not be claimed by the driver. + */ + if (skt->irq_state != 1 && state->io_irq) { + skt->irq_state = 1; + set_irq_type(skt->irq, IRQT_FALLING); + } else if (skt->irq_state == 1 && state->io_irq == 0) { + skt->irq_state = 0; + set_irq_type(skt->irq, IRQT_NOEDGE); + } + + skt->cs_state = *state; + } + + if (ret < 0) + printk(KERN_ERR "sa1100_pcmcia: unable to configure " + "socket %d\n", skt->nr); + + return ret; +} + +/* sa1100_pcmcia_sock_init() + * ^^^^^^^^^^^^^^^^^^^^^^^^^ + * + * (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 + */ +static int sa1100_pcmcia_sock_init(unsigned int sock) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + + DEBUG(2, "%s(): initializing socket %u\n", __FUNCTION__, skt->nr); + + skt->ops->socket_init(skt); + sa1100_pcmcia_config_skt(skt, &dead_socket); + + return 0; +} + + +/* + * sa1100_pcmcia_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); + int ret; + + DEBUG(2, "%s(): suspending socket %u\n", __FUNCTION__, skt->nr); + + ret = sa1100_pcmcia_config_skt(skt, &dead_socket); + if (ret == 0) + skt->ops->socket_suspend(skt); + + return ret; +} + + +/* sa1100_pcmcia_task_handler() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Processes serviceable socket events using the "eventd" thread context. + * + * Event processing (specifically, the invocation of the Card Services event + * 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) +{ + struct sa1100_pcmcia_socket *skt = data; + unsigned int events; + + DEBUG(4, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__); + + do { + unsigned int status; + + status = sa1100_pcmcia_skt_state(skt); + + events = (status ^ skt->status) & skt->cs_state.csc_mask; + skt->status = status; + + 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 " : ""); + + if (events && skt->handler != NULL) + skt->handler(skt->handler_info, events); + } while (events); +} + +/* sa1100_pcmcia_poll_event() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Let's poll for events in addition to IRQs since IRQ only is unreliable... + */ +static void sa1100_pcmcia_poll_event(unsigned long dummy) +{ + struct sa1100_pcmcia_socket *skt = (struct sa1100_pcmcia_socket *)dummy; + DEBUG(4, "%s(): polling for events\n", __FUNCTION__); + + mod_timer(&skt->poll_timer, jiffies + SA1100_PCMCIA_POLL_PERIOD); + + schedule_work(&skt->work); +} + + +/* sa1100_pcmcia_interrupt() + * ^^^^^^^^^^^^^^^^^^^^^^^^^ + * Service routine for socket driver interrupts (requested by the + * low-level PCMCIA init() operation via sa1100_pcmcia_thread()). + * The actual interrupt-servicing work is performed by + * sa1100_pcmcia_thread(), largely because the Card Services event- + * 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) +{ + struct sa1100_pcmcia_socket *skt = dev; + + DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq); + + schedule_work(&skt->work); +} + +/* sa1100_pcmcia_register_callback() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the register_callback() operation for the in-kernel + * PCMCIA service (formerly SS_RegisterCallback in Card Services). If + * the function pointer `handler' is not NULL, remember the callback + * location in the state for `sock', and increment the usage counter + * for the driver module. (The callback is invoked from the interrupt + * service routine, sa1100_pcmcia_interrupt(), to notify Card Services + * of interesting events.) Otherwise, clear the callback pointer in the + * socket state and decrement the module usage count. + * + * Returns: 0 + */ +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) { + if (!try_module_get(skt->ops->owner)) + return -ENODEV; + skt->handler_info = info; + skt->handler = handler; + } else { + skt->handler = NULL; + module_put(skt->ops->owner); + } + + return 0; +} + + +/* sa1100_pcmcia_inquire_socket() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the inquire_socket() operation for the in-kernel PCMCIA + * service (formerly SS_InquireSocket in Card Services). We set + * SS_CAP_STATIC_MAP, which disables the memory resource database + * check. (Mapped memory is set up within the socket driver itself.) + * + * In conjunction with the STATIC_MAP capability is a new field, + * `io_offset', recommended by David Hinds. Rather than go through + * the SetIOMap interface (which is not quite suited for communicating + * window locations up from the socket driver), we just pass up + * an offset which is applied to client-requested base I/O addresses + * in alloc_io_space(). + * + * 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 sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + int ret = -1; + + if (skt) { + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); + + cap->features = 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; + + ret = 0; + } + + return ret; +} + + +/* sa1100_pcmcia_get_status() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the get_status() operation for the in-kernel PCMCIA + * service (formerly SS_GetStatus in Card Services). Essentially just + * fills in bits in `status' according to internal driver state or + * the value of the voltage detect chipselect register. + * + * As a debugging note, during card startup, the PCMCIA core issues + * three set_socket() commands in a row the first with RESET deasserted, + * the second with RESET asserted, and the last with RESET deasserted + * again. Following the third set_socket(), a get_status() command will + * be issued. The kernel is looking for the SS_READY flag (see + * setup_socket(), reset_socket(), and unreset_socket() in cs.c). + * + * Returns: 0 + */ +static int +sa1100_pcmcia_get_status(unsigned int sock, unsigned int *status) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + + skt->status = sa1100_pcmcia_skt_state(skt); + *status = skt->status; + + return 0; +} + + +/* sa1100_pcmcia_get_socket() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the get_socket() operation for the in-kernel PCMCIA + * service (formerly SS_GetSocket in Card Services). Not a very + * exciting routine. + * + * Returns: 0 + */ +static int +sa1100_pcmcia_get_socket(unsigned int sock, socket_state_t *state) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); + + *state = skt->cs_state; + + return 0; +} + +/* sa1100_pcmcia_set_socket() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the set_socket() operation for the in-kernel PCMCIA + * service (formerly SS_SetSocket in Card Services). We more or + * 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 +sa1100_pcmcia_set_socket(unsigned int sock, socket_state_t *state) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); + + 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 ":"", + (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"", + (state->csc_mask&SS_BATWARN)?"BATWARN ":"", + (state->csc_mask&SS_STSCHG)?"STSCHG ":"", + (state->flags==0)?"<NONE>":"", + (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"", + (state->flags&SS_IOCARD)?"IOCARD ":"", + (state->flags&SS_RESET)?"RESET ":"", + (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"", + (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":""); + DEBUG(3, "\tVcc %d Vpp %d irq %d\n", + state->Vcc, state->Vpp, state->io_irq); + + return sa1100_pcmcia_config_skt(skt, state); +} /* sa1100_pcmcia_set_socket() */ + + +/* sa1100_pcmcia_set_io_map() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the set_io_map() operation for the in-kernel PCMCIA + * service (formerly SS_SetIOMap in Card Services). We configure + * the map speed as requested, but override the address ranges + * supplied by Card Services. + * + * Returns: 0 on success, -1 on error + */ +static int +sa1100_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + unsigned short speed = map->speed; + + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); + + 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 ":"", + (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", + (map->flags&MAP_0WS)?"0WS ":"", + (map->flags&MAP_WRPROT)?"WRPROT ":"", + (map->flags&MAP_USE_WAIT)?"USE_WAIT ":"", + (map->flags&MAP_PREFETCH)?"PREFETCH ":""); + + 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 (speed == 0) + speed = SA1100_PCMCIA_IO_ACCESS; + } else { + speed = 0; + } + + skt->spd_io[map->map] = speed; + sa1100_pcmcia_set_mecr(skt, cpufreq_get(0)); + + if (map->stop == 1) + map->stop = PAGE_SIZE-1; + + map->stop -= map->start; + map->stop += (unsigned long)skt->virt_io; + map->start = (unsigned long)skt->virt_io; + + return 0; +} /* sa1100_pcmcia_set_io_map() */ + + +/* sa1100_pcmcia_set_mem_map() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the set_mem_map() operation for the in-kernel PCMCIA + * service (formerly SS_SetMemMap in Card Services). We configure + * the map speed as requested, but override the address ranges + * supplied by Card Services. + * + * Returns: 0 on success, -1 on error + */ +static int +sa1100_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + struct resource *res; + unsigned short speed = map->speed; + + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); + + DEBUG(3, "\tmap %u speed %u card_start %08x\n", + map->map, map->speed, 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 ":"", + (map->flags&MAP_0WS)?"0WS ":"", + (map->flags&MAP_WRPROT)?"WRPROT ":"", + (map->flags&MAP_ATTRIB)?"ATTRIB ":"", + (map->flags&MAP_USE_WAIT)?"USE_WAIT ":""); + + if (map->map >= MAX_WIN) + return -EINVAL; + + if (map->flags & MAP_ACTIVE) { + if (speed == 0) + speed = 300; + } else { + speed = 0; + } + + if (map->flags & MAP_ATTRIB) { + res = &skt->res_attr; + skt->spd_attr[map->map] = speed; + skt->spd_mem[map->map] = 0; + } else { + res = &skt->res_mem; + skt->spd_attr[map->map] = 0; + skt->spd_mem[map->map] = speed; + } + + sa1100_pcmcia_set_mecr(skt, cpufreq_get(0)); + + map->sys_stop -= map->sys_start; + map->sys_stop += res->start + map->card_start; + map->sys_start = res->start + map->card_start; + + return 0; +} + + +#if defined(CONFIG_PROC_FS) + +struct bittbl { + unsigned int mask; + const char *name; +}; + +static struct bittbl status_bits[] = { + { SS_WRPROT, "SS_WRPROT" }, + { SS_BATDEAD, "SS_BATDEAD" }, + { SS_BATWARN, "SS_BATWARN" }, + { SS_READY, "SS_READY" }, + { SS_DETECT, "SS_DETECT" }, + { SS_POWERON, "SS_POWERON" }, + { SS_STSCHG, "SS_STSCHG" }, + { SS_3VCARD, "SS_3VCARD" }, + { SS_XVCARD, "SS_XVCARD" }, +}; + +static struct bittbl conf_bits[] = { + { SS_PWR_AUTO, "SS_PWR_AUTO" }, + { SS_IOCARD, "SS_IOCARD" }, + { SS_RESET, "SS_RESET" }, + { SS_DMA_MODE, "SS_DMA_MODE" }, + { SS_SPKR_ENA, "SS_SPKR_ENA" }, + { SS_OUTPUT_ENA, "SS_OUTPUT_ENA" }, + { SS_DEBOUNCED, "SS_DEBOUNCED" }, +}; + +static void +dump_bits(char **p, const char *prefix, unsigned int val, struct bittbl *bits, int sz) +{ + char *b = *p; + int i; + + b += sprintf(b, "%-9s:", prefix); + for (i = 0; i < sz; i++) + if (val & bits[i].mask) + b += sprintf(b, " %s", bits[i].name); + *b++ = '\n'; + *p = b; +} + +/* 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) +{ + struct sa1100_pcmcia_socket *skt = data; + unsigned int clock = cpufreq_get(0); + unsigned long mecr = MECR; + char *p = buf; + + p+=sprintf(p, "slot : %d\n", skt->nr); + + dump_bits(&p, "status", skt->status, + status_bits, ARRAY_SIZE(status_bits)); + dump_bits(&p, "csc_mask", skt->cs_state.csc_mask, + status_bits, ARRAY_SIZE(status_bits)); + dump_bits(&p, "cs_flags", skt->cs_state.flags, + conf_bits, ARRAY_SIZE(conf_bits)); + + 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 (%d)\n", skt->cs_state.io_irq, skt->irq); + + p+=sprintf(p, "I/O : %u (%u)\n", + calc_speed(skt->spd_io, MAX_IO_WIN, SA1100_PCMCIA_IO_ACCESS), + sa1100_pcmcia_cmd_time(clock, MECR_BSIO_GET(mecr, skt->nr))); + + p+=sprintf(p, "attribute: %u (%u)\n", + calc_speed(skt->spd_attr, MAX_WIN, SA1100_PCMCIA_3V_MEM_ACCESS), + sa1100_pcmcia_cmd_time(clock, MECR_BSA_GET(mecr, skt->nr))); + + p+=sprintf(p, "common : %u (%u)\n", + calc_speed(skt->spd_mem, MAX_WIN, SA1100_PCMCIA_3V_MEM_ACCESS), + sa1100_pcmcia_cmd_time(clock, MECR_BSM_GET(mecr, skt->nr))); + + 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; + + 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 = PCMCIA_SOCKET(sock); +} +#else +#define sa1100_pcmcia_proc_setup NULL +#endif /* defined(CONFIG_PROC_FS) */ + +static struct pccard_operations sa11xx_pcmcia_operations = { + .owner = THIS_MODULE, + .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, + .set_io_map = sa1100_pcmcia_set_io_map, + .set_mem_map = sa1100_pcmcia_set_mem_map, + .proc_setup = sa1100_pcmcia_proc_setup +}; + +int sa11xx_request_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr) +{ + int i, res = 0; + + for (i = 0; i < nr; i++) { + if (irqs[i].sock != skt->nr) + continue; + res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt, + SA_INTERRUPT, irqs[i].str, skt); + if (res) + break; + set_irq_type(irqs[i].irq, IRQT_NOEDGE); + } + + if (res) { + printk(KERN_ERR "PCMCIA: request for IRQ%d failed (%d)\n", + irqs[i].irq, res); + + while (i--) + if (irqs[i].sock == skt->nr) + free_irq(irqs[i].irq, skt); + } + return res; +} +EXPORT_SYMBOL(sa11xx_request_irqs); + +void sa11xx_free_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr) +{ + int i; + + for (i = 0; i < nr; i++) + if (irqs[i].sock == skt->nr) + free_irq(irqs[i].irq, skt); +} +EXPORT_SYMBOL(sa11xx_free_irqs); + +void sa11xx_disable_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr) +{ + int i; + + for (i = 0; i < nr; i++) + if (irqs[i].sock == skt->nr) + set_irq_type(irqs[i].irq, IRQT_NOEDGE); +} +EXPORT_SYMBOL(sa11xx_disable_irqs); + +void sa11xx_enable_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr) +{ + int i; + + for (i = 0; i < nr; i++) + if (irqs[i].sock == skt->nr) { + set_irq_type(irqs[i].irq, IRQT_RISING); + set_irq_type(irqs[i].irq, IRQT_BOTHEDGE); + } +} +EXPORT_SYMBOL(sa11xx_enable_irqs); + +static const char *skt_names[] = { + "PCMCIA socket 0", + "PCMCIA socket 1", +}; + +int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr) +{ + struct pcmcia_socket_class_data *cls; + unsigned int cpu_clock; + int ret, i; + + cls = kmalloc(sizeof(struct pcmcia_socket_class_data), GFP_KERNEL); + if (!cls) { + ret = -ENOMEM; + goto out; + } + + memset(cls, 0, sizeof(struct pcmcia_socket_class_data)); + cls->ops = &sa11xx_pcmcia_operations; + cls->nsock = nr; + + /* + * set default MECR calculation if the board specific + * code did not specify one... + */ + if (!ops->socket_get_timing) + ops->socket_get_timing = sa1100_pcmcia_default_mecr_timing; + + cpu_clock = cpufreq_get(0); + + /* + * Initialise the per-socket structure. + */ + for (i = 0; i < nr; i++) { + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i); + memset(skt, 0, sizeof(*skt)); + + INIT_WORK(&skt->work, sa1100_pcmcia_task_handler, skt); + + init_timer(&skt->poll_timer); + skt->poll_timer.function = sa1100_pcmcia_poll_event; + skt->poll_timer.data = (unsigned long)skt; + skt->poll_timer.expires = jiffies + SA1100_PCMCIA_POLL_PERIOD; + + skt->nr = first + i; + skt->irq = NO_IRQ; + skt->dev = dev; + skt->ops = ops; + + skt->res_skt.start = _PCMCIA(skt->nr); + skt->res_skt.end = _PCMCIA(skt->nr) + PCMCIASp - 1; + skt->res_skt.name = skt_names[skt->nr]; + skt->res_skt.flags = IORESOURCE_MEM; + + ret = request_resource(&iomem_resource, &skt->res_skt); + if (ret) + goto out_err_1; + + skt->res_io.start = _PCMCIAIO(skt->nr); + skt->res_io.end = _PCMCIAIO(skt->nr) + PCMCIAIOSp - 1; + skt->res_io.name = "io"; + skt->res_io.flags = IORESOURCE_MEM | IORESOURCE_BUSY; + + ret = request_resource(&skt->res_skt, &skt->res_io); + if (ret) + goto out_err_2; + + skt->res_mem.start = _PCMCIAMem(skt->nr); + skt->res_mem.end = _PCMCIAMem(skt->nr) + PCMCIAMemSp - 1; + skt->res_mem.name = "memory"; + skt->res_mem.flags = IORESOURCE_MEM; + + ret = request_resource(&skt->res_skt, &skt->res_mem); + if (ret) + goto out_err_3; + + skt->res_attr.start = _PCMCIAAttr(skt->nr); + skt->res_attr.end = _PCMCIAAttr(skt->nr) + PCMCIAAttrSp - 1; + skt->res_attr.name = "attribute"; + skt->res_attr.flags = IORESOURCE_MEM; + + ret = request_resource(&skt->res_skt, &skt->res_attr); + if (ret) + goto out_err_4; + + skt->virt_io = ioremap(skt->res_io.start, 0x10000); + if (skt->virt_io == NULL) { + ret = -ENOMEM; + goto out_err_5; + } + + /* + * We initialize the MECR to default values here, because + * we are not guaranteed to see a SetIOMap operation at + * runtime. + */ + sa1100_pcmcia_set_mecr(skt, cpu_clock); + + ret = ops->hw_init(skt); + if (ret) + goto out_err_6; + + skt->status = sa1100_pcmcia_skt_state(skt); + add_timer(&skt->poll_timer); + } + + dev->class_data = cls; + return 0; + + do { + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i); + + del_timer_sync(&skt->poll_timer); + flush_scheduled_work(); + + ops->hw_shutdown(skt); + out_err_6: + iounmap(skt->virt_io); + out_err_5: + release_resource(&skt->res_attr); + out_err_4: + release_resource(&skt->res_mem); + out_err_3: + release_resource(&skt->res_io); + out_err_2: + release_resource(&skt->res_skt); + out_err_1: + i--; + } while (i > 0); + + kfree(cls); + + out: + return ret; +} +EXPORT_SYMBOL(sa11xx_drv_pcmcia_probe); + +int sa11xx_drv_pcmcia_remove(struct device *dev) +{ + struct pcmcia_socket_class_data *cls = dev->class_data; + int i; + + dev->class_data = NULL; + + for (i = 0; i < cls->nsock; i++) { + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(cls->sock_offset + i); + + skt->ops->hw_shutdown(skt); + + del_timer_sync(&skt->poll_timer); + flush_scheduled_work(); + + sa1100_pcmcia_config_skt(skt, &dead_socket); + + iounmap(skt->virt_io); + skt->virt_io = NULL; + release_resource(&skt->res_attr); + release_resource(&skt->res_mem); + release_resource(&skt->res_io); + release_resource(&skt->res_skt); + } + + kfree(cls); + + return 0; +} +EXPORT_SYMBOL(sa11xx_drv_pcmcia_remove); + +#ifdef CONFIG_CPU_FREQ + +/* sa1100_pcmcia_update_mecr() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * When sa1100_pcmcia_notifier() decides that a MECR adjustment (due + * 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) +{ + unsigned int sock; + + for (sock = 0; sock < SA1100_PCMCIA_MAX_SOCK; ++sock) { + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + sa1100_pcmcia_set_mecr(skt, clock); + } +} + +/* sa1100_pcmcia_notifier() + * ^^^^^^^^^^^^^^^^^^^^^^^^ + * When changing the processor core clock frequency, it is necessary + * to adjust the MECR timings accordingly. We've recorded the timings + * requested by Card Services, so this is just a matter of finding + * out what our current speed is, and then recomputing the new MECR + * values. + * + * Returns: 0 on success, -1 on error + */ +static int +sa1100_pcmcia_notifier(struct notifier_block *nb, unsigned long val, + void *data) +{ + struct cpufreq_freqs *freqs = data; + + switch (val) { + case CPUFREQ_PRECHANGE: + if (freqs->new > freqs->old) { + DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, " + "pre-updating\n", __FUNCTION__, + freqs->new / 1000, (freqs->new / 100) % 10, + freqs->old / 1000, (freqs->old / 100) % 10); + sa1100_pcmcia_update_mecr(freqs->new); + } + break; + + case CPUFREQ_POSTCHANGE: + if (freqs->new < freqs->old) { + DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, " + "post-updating\n", __FUNCTION__, + freqs->new / 1000, (freqs->new / 100) % 10, + freqs->old / 1000, (freqs->old / 100) % 10); + sa1100_pcmcia_update_mecr(freqs->new); + } + break; + } + + return 0; +} + +static struct notifier_block sa1100_pcmcia_notifier_block = { + .notifier_call = sa1100_pcmcia_notifier +}; + +static int __init sa11xx_pcmcia_init(void) +{ + int ret; + + printk(KERN_INFO "SA11xx PCMCIA (CS release %s)\n", CS_RELEASE); + + ret = cpufreq_register_notifier(&sa1100_pcmcia_notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); + if (ret < 0) + printk(KERN_ERR "Unable to register CPU frequency change " + "notifier (%d)\n", ret); + + return ret; +} +module_init(sa11xx_pcmcia_init); + +static void __exit sa11xx_pcmcia_exit(void) +{ + cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); +} + +module_exit(sa11xx_pcmcia_exit); +#endif + +MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>"); +MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11xx core socket driver"); +MODULE_LICENSE("Dual MPL/GPL"); diff --git a/drivers/pcmcia/sa11xx_core.h b/drivers/pcmcia/sa11xx_core.h new file mode 100644 index 000000000000..570491f2d96d --- /dev/null +++ b/drivers/pcmcia/sa11xx_core.h @@ -0,0 +1,122 @@ +/* + * 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 + +#include <linux/proc_fs.h> +/* include the world */ +#include <pcmcia/version.h> +#include <pcmcia/cs_types.h> +#include <pcmcia/cs.h> +#include <pcmcia/ss.h> +#include <pcmcia/bulkmem.h> +#include <pcmcia/cistpl.h> +#include "cs_internal.h" + +struct device; + +/* 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_state { + unsigned detect: 1, + ready: 1, + bvd1: 1, + bvd2: 1, + wrprot: 1, + vs_3v: 1, + vs_Xv: 1; +}; + +/* + * This structure encapsulates per-socket state which we might need to + * use when responding to a Card Services query of some kind. + */ +struct sa1100_pcmcia_socket { + /* + * Info from low level handler + */ + struct device *dev; + unsigned int nr; + unsigned int irq; + + /* + * Core PCMCIA state + */ + struct pcmcia_low_level *ops; + + unsigned int status; + socket_state_t cs_state; + void (*handler)(void *, unsigned int); + void *handler_info; + + unsigned short spd_io[MAX_IO_WIN]; + unsigned short spd_mem[MAX_WIN]; + unsigned short spd_attr[MAX_WIN]; + + struct resource res_skt; + struct resource res_io; + struct resource res_mem; + struct resource res_attr; + void *virt_io; + + unsigned int irq_state; + + struct timer_list poll_timer; + struct work_struct work; +}; + +struct pcmcia_low_level { + struct module *owner; + + int (*hw_init)(struct sa1100_pcmcia_socket *); + void (*hw_shutdown)(struct sa1100_pcmcia_socket *); + + void (*socket_state)(struct sa1100_pcmcia_socket *, struct pcmcia_state *); + int (*configure_socket)(struct sa1100_pcmcia_socket *, const socket_state_t *); + + /* + * Enable card status IRQs on (re-)initialisation. This can + * be called at initialisation, power management event, or + * pcmcia event. + */ + void (*socket_init)(struct sa1100_pcmcia_socket *); + + /* + * Disable card status IRQs and PCMCIA bus on suspend. + */ + void (*socket_suspend)(struct sa1100_pcmcia_socket *); + + /* + * Calculate MECR timing clock wait states + */ + unsigned int (*socket_get_timing)(struct sa1100_pcmcia_socket *, + unsigned int cpu_speed, unsigned int cmd_time); +}; + +struct pcmcia_irqs { + int sock; + int irq; + const char *str; +}; + +int sa11xx_request_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr); +void sa11xx_free_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr); +void sa11xx_disable_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr); +void sa11xx_enable_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr); + +extern int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr); +extern int sa11xx_drv_pcmcia_remove(struct device *dev); + +#endif |
