This commit was manufactured by cvs2svn to create branch 'fedora'.
[linux-2.6.git] / drivers / pcmcia / soc_common.c
similarity index 56%
rename from drivers/pcmcia/sa11xx_core.c
rename to drivers/pcmcia/soc_common.c
index d7249c0..ff8b521 100644 (file)
@@ -1,7 +1,7 @@
 /*======================================================================
 
-    Device driver for the PCMCIA control functionality of StrongARM
-    SA-1100 microprocessors.
+    Common support code for the PCMCIA control functionality of
+    integrated SOCs like the SA-11x0 and PXA2xx microprocessors.
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
     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/moduleparam.h>
 #include <linux/init.h>
-#include <linux/config.h>
-#include <linux/cpufreq.h>
-#include <linux/ioport.h>
 #include <linux/kernel.h>
 #include <linux/timer.h>
 #include <linux/mm.h>
-#include <linux/notifier.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 
 #include <asm/irq.h>
 #include <asm/system.h>
 
-#include "sa11xx_core.h"
-#include "sa1100.h"
+#include "soc_common.h"
 
 #ifdef DEBUG
-static int pc_debug;
 
+static int pc_debug;
 module_param(pc_debug, int, 0644);
 
-#define debug(skt, lvl, fmt, arg...) do {                      \
-       if (pc_debug > (lvl))                                   \
-               printk(KERN_DEBUG "skt%u: %s: " fmt,            \
-                      (skt)->nr, __func__ , ## arg);           \
-} while (0)
+void soc_pcmcia_debug(struct soc_pcmcia_socket *skt, const char *func,
+                     int lvl, const char *fmt, ...)
+{
+       va_list args;
+       if (pc_debug > lvl) {
+               printk(KERN_DEBUG "skt%u: %s: ", skt->nr, func);
+               va_start(args, fmt);
+               printk(fmt, args);
+               va_end(args);
+       }
+}
 
-#else
-#define debug(skt, lvl, fmt, arg...) do { } while (0)
 #endif
 
-#define to_sa1100_socket(x)    container_of(x, struct sa1100_pcmcia_socket, socket)
-
-/*
- * 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);
-}
+#define to_soc_pcmcia_socket(x)        container_of(x, struct soc_pcmcia_socket, socket)
 
 static unsigned short
 calc_speed(unsigned short *spds, int num, unsigned short dflt)
@@ -108,52 +83,15 @@ calc_speed(unsigned short *spds, int num, unsigned short 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)
+void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *skt, struct soc_pcmcia_timing *timing)
 {
-       u32 mecr, old_mecr;
-       unsigned long flags;
-       unsigned short speed;
-       unsigned int bs_io, bs_mem, bs_attr;
-
-       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(skt, 2, "FAST %X  BSM %X  BSA %X  BSIO %X\n",
-             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;
+       timing->io = calc_speed(skt->spd_io, MAX_IO_WIN, SOC_PCMCIA_IO_ACCESS);
+       timing->mem = calc_speed(skt->spd_mem, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS);
+       timing->attr = calc_speed(skt->spd_attr, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS);
 }
+EXPORT_SYMBOL(soc_common_pcmcia_get_timing);
 
-static unsigned int sa1100_pcmcia_skt_state(struct sa1100_pcmcia_socket *skt)
+static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt)
 {
        struct pcmcia_state state;
        unsigned int stat;
@@ -186,13 +124,13 @@ static unsigned int sa1100_pcmcia_skt_state(struct sa1100_pcmcia_socket *skt)
 }
 
 /*
- * sa1100_pcmcia_config_skt
- * ^^^^^^^^^^^^^^^^^^^^^^^^
+ * soc_common_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)
+soc_common_pcmcia_config_skt(struct soc_pcmcia_socket *skt, socket_state_t *state)
 {
        int ret;
 
@@ -214,14 +152,14 @@ sa1100_pcmcia_config_skt(struct sa1100_pcmcia_socket *skt, socket_state_t *state
        }
 
        if (ret < 0)
-               printk(KERN_ERR "sa1100_pcmcia: unable to configure "
+               printk(KERN_ERR "soc_common_pcmcia: unable to configure "
                       "socket %d\n", skt->nr);
 
        return ret;
 }
 
-/* sa1100_pcmcia_sock_init()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^
+/* soc_common_pcmcia_sock_init()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  *
  * (Re-)Initialise the socket, turning on status interrupts
  * and PCMCIA bus.  This must wait for power to stabilise
@@ -229,9 +167,9 @@ sa1100_pcmcia_config_skt(struct sa1100_pcmcia_socket *skt, socket_state_t *state
  *
  * Returns: 0
  */
-static int sa1100_pcmcia_sock_init(struct pcmcia_socket *sock)
+static int soc_common_pcmcia_sock_init(struct pcmcia_socket *sock)
 {
-       struct sa1100_pcmcia_socket *skt = to_sa1100_socket(sock);
+       struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
 
        debug(skt, 2, "initializing socket\n");
 
@@ -241,22 +179,22 @@ static int sa1100_pcmcia_sock_init(struct pcmcia_socket *sock)
 
 
 /*
- * sa1100_pcmcia_suspend()
- * ^^^^^^^^^^^^^^^^^^^^^^^
+ * soc_common_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(struct pcmcia_socket *sock)
+static int soc_common_pcmcia_suspend(struct pcmcia_socket *sock)
 {
-       struct sa1100_pcmcia_socket *skt = to_sa1100_socket(sock);
+       struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
        int ret;
 
        debug(skt, 2, "suspending socket\n");
 
-       ret = sa1100_pcmcia_config_skt(skt, &dead_socket);
+       ret = soc_common_pcmcia_config_skt(skt, &dead_socket);
        if (ret == 0)
                skt->ops->socket_suspend(skt);
 
@@ -265,10 +203,7 @@ static int sa1100_pcmcia_suspend(struct pcmcia_socket *sock)
 
 static spinlock_t status_lock = SPIN_LOCK_UNLOCKED;
 
-/* sa1100_check_status()
- * ^^^^^^^^^^^^^^^^^^^^^
- */
-static void sa1100_check_status(struct sa1100_pcmcia_socket *skt)
+static void soc_common_check_status(struct soc_pcmcia_socket *skt)
 {
        unsigned int events;
 
@@ -278,7 +213,7 @@ static void sa1100_check_status(struct sa1100_pcmcia_socket *skt)
                unsigned int status;
                unsigned long flags;
 
-               status = sa1100_pcmcia_skt_state(skt);
+               status = soc_common_pcmcia_skt_state(skt);
 
                spin_lock_irqsave(&status_lock, flags);
                events = (status ^ skt->status) & skt->cs_state.csc_mask;
@@ -298,45 +233,40 @@ static void sa1100_check_status(struct sa1100_pcmcia_socket *skt)
        } 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)
+/* Let's poll for events in addition to IRQs since IRQ only is unreliable... */
+static void soc_common_pcmcia_poll_event(unsigned long dummy)
 {
-       struct sa1100_pcmcia_socket *skt = (struct sa1100_pcmcia_socket *)dummy;
+       struct soc_pcmcia_socket *skt = (struct soc_pcmcia_socket *)dummy;
        debug(skt, 4, "polling for events\n");
 
-       mod_timer(&skt->poll_timer, jiffies + SA1100_PCMCIA_POLL_PERIOD);
+       mod_timer(&skt->poll_timer, jiffies + SOC_PCMCIA_POLL_PERIOD);
 
-       sa1100_check_status(skt);
+       soc_common_check_status(skt);
 }
 
 
-/* sa1100_pcmcia_interrupt()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^
+/*
  * Service routine for socket driver interrupts (requested by the
- * low-level PCMCIA init() operation via sa1100_pcmcia_thread()).
+ * low-level PCMCIA init() operation via soc_common_pcmcia_thread()).
  * The actual interrupt-servicing work is performed by
- * sa1100_pcmcia_thread(), largely because the Card Services event-
+ * soc_common_pcmcia_thread(), largely because the Card Services event-
  * handling code performs scheduling operations which cannot be
  * executed from within an interrupt context.
  */
-static irqreturn_t sa1100_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs)
+static irqreturn_t soc_common_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs)
 {
-       struct sa1100_pcmcia_socket *skt = dev;
+       struct soc_pcmcia_socket *skt = dev;
 
        debug(skt, 3, "servicing IRQ %d\n", irq);
 
-       sa1100_check_status(skt);
+       soc_common_check_status(skt);
 
        return IRQ_HANDLED;
 }
 
 
-/* sa1100_pcmcia_get_status()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^
- * Implements the get_status() operation for the in-kernel PCMCIA
+/*
+ *  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.
@@ -351,39 +281,37 @@ static irqreturn_t sa1100_pcmcia_interrupt(int irq, void *dev, struct pt_regs *r
  * Returns: 0
  */
 static int
-sa1100_pcmcia_get_status(struct pcmcia_socket *sock, unsigned int *status)
+soc_common_pcmcia_get_status(struct pcmcia_socket *sock, unsigned int *status)
 {
-       struct sa1100_pcmcia_socket *skt = to_sa1100_socket(sock);
+       struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
 
-       skt->status = sa1100_pcmcia_skt_state(skt);
+       skt->status = soc_common_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 
+ * service (formerly SS_GetSocket in Card Services). Not a very
  * exciting routine.
  *
  * Returns: 0
  */
 static int
-sa1100_pcmcia_get_socket(struct pcmcia_socket *sock, socket_state_t *state)
+soc_common_pcmcia_get_socket(struct pcmcia_socket *sock, socket_state_t *state)
 {
-  struct sa1100_pcmcia_socket *skt = to_sa1100_socket(sock);
+       struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
 
-  debug(skt, 2, "\n");
+       debug(skt, 2, "\n");
 
-  *state = skt->cs_state;
+       *state = skt->cs_state;
 
-  return 0;
+       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
@@ -393,31 +321,30 @@ sa1100_pcmcia_get_socket(struct pcmcia_socket *sock, socket_state_t *state)
  * Returns: 0
  */
 static int
-sa1100_pcmcia_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
+soc_common_pcmcia_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 {
-  struct sa1100_pcmcia_socket *skt = to_sa1100_socket(sock);
-
-  debug(skt, 2, "mask: %s%s%s%s%s%sflags: %s%s%s%s%s%sVcc %d Vpp %d irq %d\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 ":"",
-       state->Vcc, state->Vpp, state->io_irq);
-
-  return sa1100_pcmcia_config_skt(skt, state);
-}  /* sa1100_pcmcia_set_socket() */
-
-
-/* sa1100_pcmcia_set_io_map()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^
+       struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
+
+       debug(skt, 2, "mask: %s%s%s%s%s%sflags: %s%s%s%s%s%sVcc %d Vpp %d irq %d\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 ":"",
+                       state->Vcc, state->Vpp, state->io_irq);
+
+       return soc_common_pcmcia_config_skt(skt, state);
+}
+
+
+/*
  * 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
@@ -426,9 +353,9 @@ sa1100_pcmcia_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
  * Returns: 0 on success, -1 on error
  */
 static int
-sa1100_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *map)
+soc_common_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *map)
 {
-       struct sa1100_pcmcia_socket *skt = to_sa1100_socket(sock);
+       struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
        unsigned short speed = map->speed;
 
        debug(skt, 2, "map %u  speed %u start 0x%08x stop 0x%08x\n",
@@ -451,13 +378,13 @@ sa1100_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *map)
 
        if (map->flags & MAP_ACTIVE) {
                if (speed == 0)
-                       speed = SA1100_PCMCIA_IO_ACCESS;
+                       speed = SOC_PCMCIA_IO_ACCESS;
        } else {
                speed = 0;
        }
 
        skt->spd_io[map->map] = speed;
-       sa1100_pcmcia_set_mecr(skt, cpufreq_get(0));
+       skt->ops->set_timing(skt);
 
        if (map->stop == 1)
                map->stop = PAGE_SIZE-1;
@@ -467,11 +394,10 @@ sa1100_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *map)
        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
@@ -480,9 +406,9 @@ sa1100_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *map)
  * Returns: 0 on success, -1 on error
  */
 static int
-sa1100_pcmcia_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *map)
+soc_common_pcmcia_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *map)
 {
-       struct sa1100_pcmcia_socket *skt = to_sa1100_socket(sock);
+       struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
        struct resource *res;
        unsigned short speed = map->speed;
 
@@ -518,7 +444,7 @@ sa1100_pcmcia_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *map
                skt->spd_mem[map->map] = speed;
        }
 
-       sa1100_pcmcia_set_mecr(skt, cpufreq_get(0));
+       skt->ops->set_timing(skt);
 
        map->sys_stop -= map->sys_start;
        map->sys_stop += res->start + map->card_start;
@@ -567,18 +493,15 @@ dump_bits(char **p, const char *prefix, unsigned int val, struct bittbl *bits, i
        *p = b;
 }
 
-/* show_status()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+/*
  * Implements the /sys/class/pcmcia_socket/??/status file.
  *
  * Returns: the number of characters added to the buffer
  */
 static ssize_t show_status(struct class_device *class_dev, char *buf)
 {
-       struct sa1100_pcmcia_socket *skt = container_of(class_dev, 
-                               struct sa1100_pcmcia_socket, socket.dev);
-       unsigned int clock = cpufreq_get(0);
-       unsigned long mecr = MECR;
+       struct soc_pcmcia_socket *skt =
+               container_of(class_dev, struct soc_pcmcia_socket, socket.dev);
        char *p = buf;
 
        p+=sprintf(p, "slot     : %d\n", skt->nr);
@@ -593,42 +516,34 @@ static ssize_t show_status(struct class_device *class_dev, char *buf)
        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)));
+       if (skt->ops->show_timing)
+               p+=skt->ops->show_timing(skt, p);
 
        return p-buf;
 }
 static CLASS_DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
 
 
-static struct pccard_operations sa11xx_pcmcia_operations = {
-       .init                   = sa1100_pcmcia_sock_init,
-       .suspend                = sa1100_pcmcia_suspend,
-       .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,
+static struct pccard_operations soc_common_pcmcia_operations = {
+       .init                   = soc_common_pcmcia_sock_init,
+       .suspend                = soc_common_pcmcia_suspend,
+       .get_status             = soc_common_pcmcia_get_status,
+       .get_socket             = soc_common_pcmcia_get_socket,
+       .set_socket             = soc_common_pcmcia_set_socket,
+       .set_io_map             = soc_common_pcmcia_set_io_map,
+       .set_mem_map            = soc_common_pcmcia_set_mem_map,
 };
 
-int sa11xx_request_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr)
+
+int soc_pcmcia_request_irqs(struct soc_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,
+               res = request_irq(irqs[i].irq, soc_common_pcmcia_interrupt,
                                  SA_INTERRUPT, irqs[i].str, skt);
                if (res)
                        break;
@@ -645,9 +560,10 @@ int sa11xx_request_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *ir
        }
        return res;
 }
-EXPORT_SYMBOL(sa11xx_request_irqs);
+EXPORT_SYMBOL(soc_pcmcia_request_irqs);
 
-void sa11xx_free_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr)
+void soc_pcmcia_free_irqs(struct soc_pcmcia_socket *skt,
+                         struct pcmcia_irqs *irqs, int nr)
 {
        int i;
 
@@ -655,9 +571,10 @@ void sa11xx_free_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs
                if (irqs[i].sock == skt->nr)
                        free_irq(irqs[i].irq, skt);
 }
-EXPORT_SYMBOL(sa11xx_free_irqs);
+EXPORT_SYMBOL(soc_pcmcia_free_irqs);
 
-void sa11xx_disable_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr)
+void soc_pcmcia_disable_irqs(struct soc_pcmcia_socket *skt,
+                            struct pcmcia_irqs *irqs, int nr)
 {
        int i;
 
@@ -665,9 +582,10 @@ void sa11xx_disable_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *i
                if (irqs[i].sock == skt->nr)
                        set_irq_type(irqs[i].irq, IRQT_NOEDGE);
 }
-EXPORT_SYMBOL(sa11xx_disable_irqs);
+EXPORT_SYMBOL(soc_pcmcia_disable_irqs);
 
-void sa11xx_enable_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr)
+void soc_pcmcia_enable_irqs(struct soc_pcmcia_socket *skt,
+                           struct pcmcia_irqs *irqs, int nr)
 {
        int i;
 
@@ -677,10 +595,11 @@ void sa11xx_enable_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *ir
                        set_irq_type(irqs[i].irq, IRQT_BOTHEDGE);
                }
 }
-EXPORT_SYMBOL(sa11xx_enable_irqs);
+EXPORT_SYMBOL(soc_pcmcia_enable_irqs);
+
 
-static LIST_HEAD(sa1100_sockets);
-static DECLARE_MUTEX(sa1100_sockets_lock);
+LIST_HEAD(soc_pcmcia_sockets);
+DECLARE_MUTEX(soc_pcmcia_sockets_lock);
 
 static const char *skt_names[] = {
        "PCMCIA socket 0",
@@ -689,26 +608,18 @@ static const char *skt_names[] = {
 
 struct skt_dev_info {
        int nskt;
-       struct sa1100_pcmcia_socket skt[0];
+       struct soc_pcmcia_socket skt[0];
 };
 
 #define SKT_DEV_INFO_SIZE(n) \
-       (sizeof(struct skt_dev_info) + (n)*sizeof(struct sa1100_pcmcia_socket))
+       (sizeof(struct skt_dev_info) + (n)*sizeof(struct soc_pcmcia_socket))
 
-int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr)
+int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr)
 {
        struct skt_dev_info *sinfo;
-       unsigned int cpu_clock;
        int ret, i;
 
-       /*
-        * 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;
-
-       down(&sa1100_sockets_lock);
+       down(&soc_pcmcia_sockets_lock);
 
        sinfo = kmalloc(SKT_DEV_INFO_SIZE(nr), GFP_KERNEL);
        if (!sinfo) {
@@ -719,22 +630,20 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, in
        memset(sinfo, 0, SKT_DEV_INFO_SIZE(nr));
        sinfo->nskt = nr;
 
-       cpu_clock = cpufreq_get(0);
-
        /*
         * Initialise the per-socket structure.
         */
        for (i = 0; i < nr; i++) {
-               struct sa1100_pcmcia_socket *skt = &sinfo->skt[i];
+               struct soc_pcmcia_socket *skt = &sinfo->skt[i];
 
-               skt->socket.ops = &sa11xx_pcmcia_operations;
+               skt->socket.ops = &soc_common_pcmcia_operations;
                skt->socket.owner = ops->owner;
                skt->socket.dev.dev = dev;
 
                init_timer(&skt->poll_timer);
-               skt->poll_timer.function = sa1100_pcmcia_poll_event;
+               skt->poll_timer.function = soc_common_pcmcia_poll_event;
                skt->poll_timer.data = (unsigned long)skt;
-               skt->poll_timer.expires = jiffies + SA1100_PCMCIA_POLL_PERIOD;
+               skt->poll_timer.expires = jiffies + SOC_PCMCIA_POLL_PERIOD;
 
                skt->nr         = first + i;
                skt->irq        = NO_IRQ;
@@ -772,7 +681,7 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, in
                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;
@@ -783,14 +692,14 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, in
                        goto out_err_5;
                }
 
-               list_add(&skt->node, &sa1100_sockets);
+               list_add(&skt->node, &soc_pcmcia_sockets);
 
                /*
-                * We initialize the MECR to default values here, because
+                * We initialize default socket timing here, because
                 * we are not guaranteed to see a SetIOMap operation at
                 * runtime.
                 */
-               sa1100_pcmcia_set_mecr(skt, cpu_clock);
+               ops->set_timing(skt);
 
                ret = ops->hw_init(skt);
                if (ret)
@@ -802,7 +711,7 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, in
                skt->socket.pci_irq = skt->irq;
                skt->socket.io_offset = (unsigned long)skt->virt_io;
 
-               skt->status = sa1100_pcmcia_skt_state(skt);
+               skt->status = soc_common_pcmcia_skt_state(skt);
 
                ret = pcmcia_register_socket(&skt->socket);
                if (ret)
@@ -820,7 +729,7 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, in
        goto out;
 
        do {
-               struct sa1100_pcmcia_socket *skt = &sinfo->skt[i];
+               struct soc_pcmcia_socket *skt = &sinfo->skt[i];
 
                del_timer_sync(&skt->poll_timer);
                pcmcia_unregister_socket(&skt->socket);
@@ -847,21 +756,20 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, in
        kfree(sinfo);
 
  out:
-       up(&sa1100_sockets_lock);
+       up(&soc_pcmcia_sockets_lock);
        return ret;
 }
-EXPORT_SYMBOL(sa11xx_drv_pcmcia_probe);
 
-int sa11xx_drv_pcmcia_remove(struct device *dev)
+int soc_common_drv_pcmcia_remove(struct device *dev)
 {
        struct skt_dev_info *sinfo = dev_get_drvdata(dev);
        int i;
 
        dev_set_drvdata(dev, NULL);
 
-       down(&sa1100_sockets_lock);
+       down(&soc_pcmcia_sockets_lock);
        for (i = 0; i < sinfo->nskt; i++) {
-               struct sa1100_pcmcia_socket *skt = &sinfo->skt[i];
+               struct soc_pcmcia_socket *skt = &sinfo->skt[i];
 
                del_timer_sync(&skt->poll_timer);
 
@@ -871,7 +779,7 @@ int sa11xx_drv_pcmcia_remove(struct device *dev)
 
                skt->ops->hw_shutdown(skt);
 
-               sa1100_pcmcia_config_skt(skt, &dead_socket);
+               soc_common_pcmcia_config_skt(skt, &dead_socket);
 
                list_del(&skt->node);
                iounmap(skt->virt_io);
@@ -881,91 +789,9 @@ int sa11xx_drv_pcmcia_remove(struct device *dev)
                release_resource(&skt->res_io);
                release_resource(&skt->res_skt);
        }
-       up(&sa1100_sockets_lock);
+       up(&soc_pcmcia_sockets_lock);
 
        kfree(sinfo);
 
        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)
-{
-       struct sa1100_pcmcia_socket *skt;
-
-       down(&sa1100_sockets_lock);
-       list_for_each_entry(skt, &sa1100_sockets, node)
-               sa1100_pcmcia_set_mecr(skt, clock);
-       up(&sa1100_sockets_lock);
-}
-
-/* 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)
-                       sa1100_pcmcia_update_mecr(freqs->new);
-               break;
-
-       case CPUFREQ_POSTCHANGE:
-               if (freqs->new < freqs->old)
-                       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\n");
-
-       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");