summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk@flint.arm.linux.org.uk>2003-03-30 11:14:49 +0100
committerRussell King <rmk@flint.arm.linux.org.uk>2003-03-30 11:14:49 +0100
commit5e4301f1a686b8efeae458745928de2a4a75a2ec (patch)
tree6cb2dcd7fb741c3bd3d32f7e8e292b376715e606
parent18e4786e89f773ff4bacebad598ae52151b1c4de (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.
-rw-r--r--drivers/pcmcia/Kconfig14
-rw-r--r--drivers/pcmcia/Makefile4
-rw-r--r--drivers/pcmcia/sa1100.h85
-rw-r--r--drivers/pcmcia/sa1100_adsbitsy.c131
-rw-r--r--drivers/pcmcia/sa1100_assabet.c144
-rw-r--r--drivers/pcmcia/sa1100_badge4.c69
-rw-r--r--drivers/pcmcia/sa1100_cerf.c161
-rw-r--r--drivers/pcmcia/sa1100_flexanet.c227
-rw-r--r--drivers/pcmcia/sa1100_freebird.c201
-rw-r--r--drivers/pcmcia/sa1100_generic.c1124
-rw-r--r--drivers/pcmcia/sa1100_generic.h93
-rw-r--r--drivers/pcmcia/sa1100_graphicsclient.c167
-rw-r--r--drivers/pcmcia/sa1100_graphicsmaster.c117
-rw-r--r--drivers/pcmcia/sa1100_h3600.c104
-rw-r--r--drivers/pcmcia/sa1100_jornada720.c32
-rw-r--r--drivers/pcmcia/sa1100_neponset.c124
-rw-r--r--drivers/pcmcia/sa1100_pangolin.c180
-rw-r--r--drivers/pcmcia/sa1100_pfs168.c52
-rw-r--r--drivers/pcmcia/sa1100_shannon.c89
-rw-r--r--drivers/pcmcia/sa1100_simpad.c193
-rw-r--r--drivers/pcmcia/sa1100_stork.c108
-rw-r--r--drivers/pcmcia/sa1100_system3.c39
-rw-r--r--drivers/pcmcia/sa1100_trizeps.c103
-rw-r--r--drivers/pcmcia/sa1100_xp860.c47
-rw-r--r--drivers/pcmcia/sa1100_yopy.c106
-rw-r--r--drivers/pcmcia/sa1111_generic.c165
-rw-r--r--drivers/pcmcia/sa1111_generic.h16
-rw-r--r--drivers/pcmcia/sa11xx_core.c1054
-rw-r--r--drivers/pcmcia/sa11xx_core.h122
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