/*======================================================================
- 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)
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;
}
/*
- * 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;
}
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
*
* 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");
/*
- * 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);
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;
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;
} 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.
* 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
* 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
* 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",
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;
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
* 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;
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;
*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);
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;
}
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;
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;
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;
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",
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) {
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;
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;
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)
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)
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);
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);
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);
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");