Psion PCMCIA driver patch for linux/drivers/pcmcia/ files

This patch contains updates to the following files:
./drivers/pcmcia/Config.in
./drivers/pcmcia/Makefile
./drivers/pcmcia/psion_etna.c
./drivers/pcmcia/psion_etna.h


diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/pcmcia/Config.in linux-2.4.19-rmk2/drivers/pcmcia/Config.in
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/pcmcia/Config.in linux-2.4.19-rmk2/drivers/pcmcia/Config.in
--- /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/pcmcia/Config.in	2002-10-02 22:05:15.000000000 -0700
+++ linux-2.4.19-rmk2/drivers/pcmcia/Config.in	2002-10-02 22:07:30.000000000 -0700
@@ -31,6 +31,7 @@
 if [ "$CONFIG_ARM" = "y" ]; then
    dep_tristate '  CLPS6700 support' CONFIG_PCMCIA_CLPS6700 $CONFIG_ARCH_CLPS711X $CONFIG_PCMCIA
    dep_tristate '  SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA
+   dep_tristate '  Psion ETNA support' CONFIG_PCMCIA_ETNA $CONFIG_ARCH_PSIONW $CONFIG_PCMCIA
 fi
 
 endmenu
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/pcmcia/Makefile linux-2.4.19-rmk2/drivers/pcmcia/Makefile
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/pcmcia/Makefile linux-2.4.19-rmk2/drivers/pcmcia/Makefile
--- /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/pcmcia/Makefile	2002-10-02 22:05:15.000000000 -0700
+++ linux-2.4.19-rmk2/drivers/pcmcia/Makefile	2002-10-02 22:07:30.000000000 -0700
@@ -61,6 +61,7 @@
 
 obj-$(CONFIG_PCMCIA_CLPS6700)	+= clps6700.o
 obj-$(CONFIG_PCMCIA_SA1100)	+= sa1100_cs.o
+obj-$(CONFIG_PCMCIA_ETNA)	+= psion_etna.o
 
 sa1100_cs-objs-y				:= sa1100_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSY)	+= sa1100_adsbitsy.o sa1111_generic.o
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/pcmcia/psion_etna.c linux-2.4.19-rmk2/drivers/pcmcia/psion_etna.c
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/pcmcia/psion_etna.c linux-2.4.19-rmk2/drivers/pcmcia/psion_etna.c
--- /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/pcmcia/psion_etna.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.19-rmk2/drivers/pcmcia/psion_etna.c	2002-10-02 22:07:30.000000000 -0700
@@ -0,0 +1,650 @@
+/*
+ * psion_etna.c - Psion-specific PCMCIA functions
+ * 
+ * Copyright (C) 2001 Tony Lindgren <tony@atomide.com>
+ * Copyright (C) 2001 Shane Nay <shane@place.org>
+ * 
+ * Contains code from the clps6700 driver for linux,
+ * Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * Contains code from the Psion 5 ETNA driver for linux, 
+ * Copyright (C) 1999 Werner Almesberger.
+ *
+ * This driver is currently a big mess, so a rewrite is needed.
+ * But, it works, so we'll clean it up later.
+ *
+ * ETNA only has one interrupt that is shared with the card and
+ * the socket. The ETNA interrupt handler schedules a socket
+ * interrupt only if the interrupt is not a card interrupt.
+ * See irq.c on the ETNA interrupt handler.
+ *
+ * The code is currently all over the place. See also ide.h and
+ * irq.c.
+ *
+ * Psion is configured to trigger IRQ_MCINT with the CF card door
+ * switch. Epoc uses this, we don't.
+ *
+ * The various ETNA registers are not fully deciphered, mostly
+ * just working Epoc values are written to the registers without
+ * really knowing what they do.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/page.h>
+
+#include <asm/hardware/psionw.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bus_ops.h>
+
+#include "psion_etna.h"
+
+MODULE_AUTHOR("Tony Lindgren");
+MODULE_DESCRIPTION("PSION ETNA PCMCIA socket driver");
+
+#define NR_ETNA		1
+
+static u8 cur_cfg = 0x1;	/* Current card configuration */
+static u8 initialized;
+
+struct etna_skt {
+	u_int			nr;
+	u_int			physbase;
+	u_int			regbase;
+	u_int			pmr;
+	u_int			cpcr;
+	u_int			cpcr_3v3;
+	u_int			cpcr_5v0;
+	u_int			cur_pmr;
+	u_int			cur_cicr;
+	u_int			cur_pcimr;
+	u_int			cur_cpcr;
+	void			(*handler)(void *, u_int);
+	void			*handler_info;
+
+	u_int			ev_pending;
+	spinlock_t		ev_lock;
+};
+
+static struct etna_skt *skts[NR_ETNA];
+
+static int etna_sock_init(u_int sock)
+{
+	struct etna_skt *skt = skts[sock];
+
+	skt->cur_cicr  = 0;		/* PC card interface config reg */
+	skt->cur_pmr   = skt->pmr;	/* Power mgmt reg */
+	skt->cur_pcimr = 0;		/* PC card mask reg */
+	skt->cur_cpcr  = skt->cpcr;	/* Card power ctrl reg */
+
+	DEBUG_ETNA("ETNA skt%d: sock_init()\n", sock);
+	return 0;
+}
+
+static int etna_suspend(u_int sock)
+{
+	DEBUG_ETNA("ETNA: etna_suspend\n");
+	etna_powerdown(1);
+	return 0;
+}
+
+static int etna_register_callback(u_int sock, void (*handler)(void *, u_int), 
+				  void *info)
+{
+	struct etna_skt *skt = skts[sock];
+
+	DEBUG_ETNA("ETNA: skt%d: register_callback: %p (%p)\n", sock, handler, info);
+	skt->handler_info = info;
+	skt->handler = handler;
+
+	return 0;
+} 
+
+static int etna_inquire_socket(u_int sock, socket_cap_t *cap)
+{
+
+	DEBUG_ETNA("ETNA: etna_inquire_socket\n");
+
+#if 0
+	/* Leaving out SS_CAP_SATIC_MAP makes the card detection not to work*/
+	cap->features = (SS_CAP_PAGE_REGS | SS_CAP_PCCARD | 
+		SS_CAP_STATIC_MAP);
+#endif
+
+	cap->features = (SS_CAP_PAGE_REGS | SS_CAP_PCCARD | 
+		SS_CAP_STATIC_MAP | SS_CAP_MEM_ALIGN);
+
+	cap->irq_mask  = 0;
+	cap->map_size  = PAGE_SIZE;
+        cap->pci_irq   = IRQ_EINT1;
+	cap->cb_dev    = NULL;
+	cap->bus       = NULL;
+	cap->io_offset = 0;
+
+	return 0;
+}
+
+
+static int __etna_get_status(struct etna_skt *skt)
+{
+	unsigned int etna_state = 0;
+	int cardint, status, sktpower;
+
+	DEBUG_ETNA("ETNA: __etna_get_status\n");
+
+	etna_state = (SS_DETECT | SS_READY);
+
+	sktpower = etna_readb(ETNA_SKT_ACTIVE);
+	status = etna_readb(ETNA_SKT_STATUS);
+
+	// Check if there is a card in the socket
+	if (status & SKT_CARD_OUT) {
+		DEBUG_ETNA("ETNA: Int: Card is not inserted: 0x%02x\n", status);
+		etna_state &= ~SS_DETECT;
+		etna_state &= ~SS_READY;
+	}
+
+	// Check that the card has power if in socket
+	if (!sktpower) {
+		DEBUG_ETNA("ETNA: Int: No socket power\n");
+		etna_state &= ~SS_READY;
+		etna_powerup();
+	}
+
+	// Test for socket ready
+	if ( (status & SKT_BUSY) || (status & SKT_NOT_READY) ) {
+		DEBUG_ETNA("ETNA: Int: Socket busy or not ready: 0x%02x\n", status);
+		etna_state &= ~SS_READY;
+	}
+
+	/* Force some unknown values ready */
+	etna_state &= ~SS_BATWARN;
+	etna_state &= ~SS_BATDEAD;
+	etna_state &= ~SS_XVCARD;
+	etna_state |= SS_3VCARD;
+	
+	// Clear pending status. What sets this on?
+	etna_state &= ~SS_PENDING;
+
+	DEBUG_ETNA("ETNA: Status: skt%d: status: %08x -> %s %s %s %s %s %s)\n",
+		skt->nr, status,
+	        etna_state & SS_READY   ? "rdy" : "---",
+	        etna_state & SS_DETECT  ? "det" : "---",
+	        etna_state & SS_BATWARN ? "bw"  : "--",
+		etna_state & SS_BATDEAD ? "bd"  : "--",
+		etna_state & SS_3VCARD  ? "3v"  : "--",
+		etna_state & SS_XVCARD  ? "xv"  : "--");
+
+	return etna_state;
+}
+
+static int etna_get_status(u_int sock, u_int *valp)
+{
+	struct etna_skt *skt = skts[sock];
+	*valp = __etna_get_status(skt);
+	return 0; /* not used! */
+}
+
+static int etna_get_socket(u_int sock, socket_state_t *state)
+{
+	DEBUG_ETNA("ETNA: etna_get_socket\n");
+	return -EINVAL;
+}
+
+static int etna_set_socket(u_int sock, socket_state_t *state)
+{
+	struct etna_skt *skt = skts[sock];
+	unsigned long flags;
+	u_int cpcr = skt->cur_cpcr, pmr = skt->cur_pmr, cicr = skt->cur_cicr;
+	u_int pcimr = 0;
+	DEBUG_ETNA("ETNA: etna_set_socket with sock=%d\n", sock);
+
+	if (state->flags & SS_RESET) {
+		DEBUG_ETNA("ETNA Socket: SS_RESET\n");
+	} else if (state->flags & SS_OUTPUT_ENA) {
+		DEBUG_ETNA("ETNA Socket: SS_OUTPUT_ENA\n");
+	}
+
+	if (state->flags & SS_IOCARD) {
+		DEBUG_ETNA("ETNA Socket: SS_IOCARD\n");
+	} else {
+		if (state->csc_mask & SS_BATDEAD) {
+			DEBUG_ETNA("ETNA Socket: SS_BATDEAD\n");
+			pcimr = 0;
+		}
+		if (state->csc_mask & SS_BATWARN) {
+			DEBUG_ETNA("ETNA Socket: SS_BATWARN\n");
+			pcimr = 0;
+		}
+		if (state->csc_mask & SS_READY) {
+			DEBUG_ETNA("ETNA Socket: SS_READY\n");
+			pcimr = 0x41;
+		}
+	}
+
+	if (state->csc_mask & SS_DETECT) {
+		DEBUG_ETNA("ETNA Socket: SS_DETECT\n");
+		pcimr = 0x41;
+	}
+
+	switch (state->Vcc) {
+	case 0:				break;
+	case 33: cpcr |= skt->cpcr_3v3; break;
+	case 50: cpcr |= skt->cpcr_5v0; break;
+	default: return -EINVAL;
+	}
+
+	DEBUG_ETNA("skt%d: PMR: %04x, CPCR: %04x, CICR: %04x PCIMR: %04x "
+		"(Vcc = %d, flags = %c%c%c%c, csc = %c%c%c%c%c)\n",
+		sock, pmr, cpcr, cicr, pcimr, state->Vcc,
+		state->flags & SS_RESET      ? 'r' : '-',
+		state->flags & SS_PWR_AUTO   ? 'p' : '-',
+		state->flags & SS_IOCARD     ? 'i' : '-',
+		state->flags & SS_OUTPUT_ENA ? 'o' : '-',
+		state->csc_mask & SS_STSCHG  ? 's' : '-',
+		state->csc_mask & SS_BATDEAD ? 'd' : '-',
+		state->csc_mask & SS_BATWARN ? 'w' : '-',
+		state->csc_mask & SS_READY   ? 'r' : '-',
+		state->csc_mask & SS_DETECT  ? 'c' : '-');
+
+	save_flags_cli(flags);
+
+	if (skt->cur_cpcr != cpcr) {
+		skt->cur_cpcr = cpcr;
+		//__raw_writel(skt->cur_cpcr, skt->regbase + CPCR);
+	}
+
+	if (skt->cur_pmr != pmr) {
+		skt->cur_pmr = pmr;
+		//__raw_writel(skt->cur_pmr, skt->regbase + PMR);
+	}
+
+	/* Enable card interrutps */
+	if (skt->cur_pcimr != pcimr) {
+		skt->cur_pcimr = pcimr;
+		__raw_writeb(skt->cur_pcimr, skt->regbase + PCIMR);
+	}
+	if (skt->cur_cicr != cicr) {
+		skt->cur_cicr = cicr;
+		//__raw_writel(skt->cur_cicr, skt->regbase + CICR);
+	}
+
+	restore_flags(flags);
+
+	return 0;
+}
+
+static int etna_get_io_map(u_int sock, struct pccard_io_map *io)
+{
+	return -EINVAL;
+}
+
+static int etna_set_io_map(u_int sock, struct pccard_io_map *map)
+{
+
+	unsigned long start;
+
+	DEBUG_ETNA("ETNA: etna_set_io_map\n");
+	
+	DEBUG_ETNA("ETNA: card speed: %u\n", map->speed);
+
+	start=map->start;
+	if(map->stop==1)
+		map->stop=PAGE_SIZE-1;
+
+	map->start = CF1_V_BASE;
+	map->stop=map->start+(map->stop-start);
+
+	return 0;
+}
+
+static int etna_get_mem_map(u_int sock, struct pccard_mem_map *mem)
+{
+	DEBUG_ETNA("ETNA: etna_get_mem_map\n");
+	return -EINVAL;
+}
+
+/*
+ * Set the memory map attributes for this socket.  (ie, mem->speed)
+ * Note that since we have SS_CAP_STATIC_MAP set, we don't need to do
+ * any mapping here at all; we just need to return the address (suitable
+ * for ioremap) to map the requested space in mem->sys_start.
+ *
+ * flags & MAP_ATTRIB indicates whether we want attribute space.
+ */
+static int etna_set_mem_map(u_int sock, struct pccard_mem_map *mem)
+{
+	struct etna_skt *skt = skts[sock];
+	u_int off;
+	unsigned long start;
+
+	start = mem->sys_start;
+	if(mem->sys_stop==0)
+		mem->sys_stop=PAGE_SIZE-1;
+
+	// Only CF_ATTR_BASE 0x00000000 makes dump_cis work
+	if (mem->flags & MAP_ATTRIB)
+		off = CF_ATTR_BASE;
+	else
+		off = CF_MEM_BASE;	/* This may not be right */	
+	
+	mem->sys_start  = skt->physbase + off;
+	mem->sys_start += mem->card_start;
+
+	////mem->sys_stop=mem->sys_start+(mem->sys_stop-start);
+
+	return 0;
+}
+
+static void etna_proc_setup(u_int sock, struct proc_dir_entry *base)
+{
+}
+
+static struct pccard_operations etna_operations = {
+	init:			etna_sock_init,
+	suspend:		etna_suspend,
+	register_callback:	etna_register_callback,
+	inquire_socket:		etna_inquire_socket,
+	get_status:		etna_get_status,
+	get_socket:		etna_get_socket,
+	set_socket:		etna_set_socket,
+	get_io_map:		etna_get_io_map,
+	set_io_map:		etna_set_io_map,
+	get_mem_map:		etna_get_mem_map,
+	set_mem_map:		etna_set_mem_map,
+	proc_setup:		etna_proc_setup
+};
+
+static void etna_bh(void *dummy)
+{
+	int i;
+
+	DEBUG_ETNA("ETNA: etna_bh\n");
+	for (i = 0; i < NR_ETNA; i++) {
+		struct etna_skt *skt = skts[i];
+		unsigned long flags;
+		u_int events;
+
+		if (!skt)
+			continue;
+
+		/*
+		 * Note!  We must read the pending event state
+		 * with interrupts disabled, otherwise we race
+		 * with our own interrupt routine!
+		 */
+		spin_lock_irqsave(&skt->ev_lock, flags);
+		events = skt->ev_pending;
+		skt->ev_pending = 0;
+		spin_unlock_irqrestore(&skt->ev_lock, flags);	
+
+		if (skt->handler && events)
+			skt->handler(skt->handler_info, events);
+	}
+}
+
+static struct tq_struct etna_task = {
+	routine:	etna_bh
+};
+
+/*
+ * Handles card insert and eject.
+ * Scheduled from mask_etna_irq, as there seems to be only
+ * one interrupt for ETNA and the CF card.
+ */
+void etna_interrupt(void)
+{
+	struct etna_skt *skt = skts[0];
+	int status, sktpower, cardpower;
+	int events;
+
+	DEBUG_ETNA("ETNA: etna_interrupt\n");
+
+	/* We may get called from ide init */
+	if (!initialized) {
+		return;
+	}
+
+	events = __etna_get_status(skt);
+
+	if ( (events & SS_DETECT) && (events & SS_READY) ) {
+		DEBUG_ETNA("ETNA: Int: Nothing to do, returning\n");
+		return;
+	}
+
+	spin_lock(&skt->ev_lock);
+	skt->ev_pending |= events;
+	spin_unlock(&skt->ev_lock);
+	schedule_task(&etna_task);
+}
+
+
+static int __init etna_init_skt(int nr)
+{
+	struct etna_skt *skt;
+
+	DEBUG_ETNA("ETNA: etna_init_skt\n");
+	skt = kmalloc(sizeof(struct etna_skt), GFP_KERNEL);
+	if (!skt)
+		return -ENOMEM;
+
+	memset(skt, 0, sizeof(struct etna_skt));
+
+	spin_lock_init(&skt->ev_lock);
+
+	skt->nr       = nr;
+	//skt->physbase = nr ? 0x50000000 : 0x40000000;
+	skt->physbase = CF1_P_BASE;
+	DEBUG_ETNA("ETNA: skt->physbase=0x%x\n", skt->physbase);
+
+	skt->cur_pmr  = skt->pmr;
+	//skt->regbase = (u_int)__ioremap(skt->physbase + CF_REG_BASE,
+	//	CF_REG_SIZE, 0);
+	skt->regbase = ETNA_V_BASE;
+
+	if (!skt->regbase)
+	goto err_free;
+
+	skts[nr] = skt;
+	return 0;
+
+err_unmap:
+	iounmap((void *)skt->regbase);
+err_free:
+	kfree(skt);
+	skts[nr] = NULL;
+	return 1;
+}
+
+static void etna_free_resources(void)
+{
+	int i;
+
+	DEBUG_ETNA("ETNA: etna_free_resources\n");
+	for (i = NR_ETNA; i >= 0; i--) {
+		struct etna_skt *skt = skts[i];
+		skts[i] = NULL;
+		if (skt == NULL)
+			continue;
+		//free_irq(IRQ_EINT1, skt); /* Socket interrupt */
+		if (skt->regbase) {
+			__raw_writeb(0,	skt->regbase + PCIMR);	/* Card int mask */
+
+		}
+
+		//iounmap((void *)skt->regbase); /* Using ETNA_V_BASE for now */
+		kfree(skt);
+	}
+}
+
+static int __init etna_init(void)
+{
+	int err, nr;
+
+	printk("ETNA: Initializing CF controller\n");
+	
+	for (nr = 0; nr < NR_ETNA; nr++) {
+		err = etna_init_skt(nr);
+		if (err)
+			goto free;
+	}
+
+	err = register_ss_entry(nr, &etna_operations);
+	if (err)
+		goto free;
+
+
+	initialized = 1;
+	etna_powerup();
+
+	return 0;
+
+free:
+	printk("ETNA: Failed to initialize\n");
+	etna_free_resources();
+	/*
+	 * An error occurred.  Unmap and free all ETNA
+	 */
+	return err;
+}
+
+void etna_powerup(int lock)
+{
+	DEBUG_ETNA("ETNA: CompactFlash PCMCIA controller warm init\n");
+
+	/* Turn on the power if it is not already on */
+	start_pump(lock);
+	mdelay(30);	/* Needed for some cards */
+	etna_init_hw();
+
+	/* Restore the card configuration */
+	etna_set_cf(cur_cfg);
+
+	/* Clear the ETNA interrupts */
+	__raw_writeb(0x01, ETNA_V_BASE + ETNA_INT_CLEAR);
+
+	/* Turn on ETNA interrupt */
+	__raw_writeb(0x01, ETNA_V_BASE + ETNA_INT_MASK);
+
+	//enable_irq(IRQ_EINT1);
+}
+
+/*
+ * Powers down the card and ETNA.
+ * Some of these steps may not be necessary.
+ */
+void etna_powerdown(int lock)
+{
+	int cfg;
+	long flags;
+
+	DEBUG_ETNA("ETNA: Powering down the CF controller\n");
+
+	if (lock)
+		save_flags_cli(flags);
+
+	//disable_irq(IRQ_EINT1);
+
+	/* Save the current card configuration */
+	cur_cfg = CF1_READB(CF_CUR_CFG);
+
+	/* Turn off card interrupts */
+	__raw_writeb(0, ETNA_V_BASE + ETNA_INT_MASK);
+
+	/* Clear card interrupts */
+	__raw_writeb(0xff, ETNA_V_BASE + ETNA_INT_CLEAR);
+
+	/* 
+	 * Writing this makes power up fail with garbage
+	 * if something does not come up right.
+	 */
+	__raw_writeb(0, ETNA_V_BASE + ETNA_SKT_CTRL);
+
+	__raw_writeb(0, ETNA_V_BASE + ETNA_SKT_ACTIVE);
+	__raw_writeb(0, ETNA_V_BASE + ETNA_SKT_CFG);
+	__raw_writeb(0, ETNA_V_BASE + ETNA_WAKE_1);
+	__raw_writeb(0, ETNA_V_BASE + ETNA_WAKE_2);
+
+	/* Power down the CF card */
+	cfg = psionw_readb(PBDR);
+	if (!(cfg & PBDR_VPCEN)) {
+		psionw_writeb(cfg | PBDR_VPCEN, PBDR);
+	}
+
+	/* Delay is needed here */
+	mdelay(20);
+
+#if 0
+	/* Power down the ETNA socket */
+	cfg = psionw_readb(PDDR);
+	if (cfg & PDDR_ETNA_PWR) {
+		//psionw_writeb(cfg & ~PDDR_ETNA_PWR, PDDR);
+	}
+#endif
+
+	if (lock)
+		restore_flags(flags);
+}
+
+void psion_debug_etna(void)
+{
+	debug_gpio();
+
+	printk("ETNA: ATTR_BASE = 0x%08x ATTR_BASE + 4 = 0x%08x\n",
+	       CF1_READL(0),
+	       CF1_READL(4));
+
+	printk("ETNA: MEM_BASE = 0x%08x MEM_BASE + 4 = 0x%08x\n",
+	       CF1_MEM_READL(0),
+	       CF1_MEM_READL(4));
+
+	printk("ETNA: SKT_STATUS=0x%02x SKT_CFG=0x%02x SKT_CTRL=0x%02x SKT_ACTIVE=0x%02x\n",
+	       __raw_readb(ETNA_V_BASE + ETNA_SKT_STATUS),
+	       __raw_readb(ETNA_V_BASE + ETNA_SKT_CFG),
+	       __raw_readb(ETNA_V_BASE + ETNA_SKT_CTRL),
+	       __raw_readb(ETNA_V_BASE + ETNA_SKT_ACTIVE));
+
+	printk("ETNA: ETNA_INT_STATUS=0x%02x ETNA_INT_MASK=0x%02x\n",
+	       __raw_readb(ETNA_V_BASE + ETNA_INT_STATUS),
+	       __raw_readb(ETNA_V_BASE + ETNA_INT_MASK));
+
+	printk("CF1: 0x200=0x%02x 0x202=0x%02x 0x204=0x%02x\n",
+	       CF1_READB(CF_CUR_CFG),
+	       CF1_READB(0x202),
+	       CF1_READB(0x204));
+	DEBUG_CF1_REG("CFG_REG", CF_CFG_REG);
+
+	printk("MEMCFG1: 0x%08x MEMCFG2=0x%08x\n", 
+	       psionw_readl(MEMCFG1), psionw_readl(MEMCFG2));
+
+	printk("CF1 READ TEST: 0x%x\n",
+	       CF1_INB(0x3f6));
+}
+
+static void __exit etna_exit(void)
+{
+	unregister_ss_entry(&etna_operations);
+	etna_free_resources();
+}
+
+module_init(etna_init);
+module_exit(etna_exit);
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/pcmcia/psion_etna.h linux-2.4.19-rmk2/drivers/pcmcia/psion_etna.h
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/pcmcia/psion_etna.h linux-2.4.19-rmk2/drivers/pcmcia/psion_etna.h
--- /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/pcmcia/psion_etna.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.19-rmk2/drivers/pcmcia/psion_etna.h	2002-10-06 14:29:29.000000000 -0700
@@ -0,0 +1,175 @@
+#include <asm/arch/psionw-power.h>
+
+extern void debug_gpio(void);
+
+#define GET_ETNA_UNKNOWN_0	__raw_readb(ETNA_V_BASE + ETNA_UNKNOWN_0)
+#define GET_ETNA_UNKNOWN_1	__raw_readb(ETNA_V_BASE + ETNA_UNKNOWN_1)
+#define GET_ETNA_UNKNOWN_2	__raw_readb(ETNA_V_BASE + ETNA_UNKNOWN_2)
+#define GET_ETNA_UNKNOWN_3	__raw_readb(ETNA_V_BASE + ETNA_UNKNOWN_3)
+#define GET_ETNA_UNKNOWN_4	__raw_readb(ETNA_V_BASE + ETNA_UNKNOWN_4)
+#define GET_ETNA_UNKNOWN_5	__raw_readb(ETNA_V_BASE + ETNA_UNKNOWN_5)
+#define GET_ETNA_INT_STATUS	__raw_readb(ETNA_V_BASE + ETNA_INT_STATUS)
+#define GET_ETNA_INT_MASK	__raw_readb(ETNA_V_BASE + ETNA_INT_MASK)
+#define GET_ETNA_INT_CLEAR	__raw_readb(ETNA_V_BASE + ETNA_INT_CLEAR)
+#define GET_ETNA_SKT_STATUS	__raw_readb(ETNA_V_BASE + ETNA_SKT_STATUS)
+#define GET_ETNA_SKT_CFG	__raw_readb(ETNA_V_BASE + ETNA_SKT_CFG)
+#define GET_ETNA_SKT_WAKE1	__raw_readb(ETNA_V_BASE + ETNA_SKT_WAKE1)
+#define GET_ETNA_SKT_ACTIVE	__raw_readb(ETNA_V_BASE + ETNA_SKT_ACTIVE)
+#define GET_ETNA_UNKNOWN_E	__raw_readb(ETNA_V_BASE + ETNA_UNKNOWN_E)
+#define GET_ETNA_SKT_WAKE2	__raw_readb(ETNA_V_BASE + ETNA_SKT_WAKE2)
+
+//#define ETNA_DEBUG 1
+
+#ifdef ETNA_DEBUG
+#define DEBUG_ETNA(x...)		printk(x)
+
+#define DEBUG_ETNA_REG(desc, p)		printk("ETNA: %s: Port 0x%08x = 0x%02x\n", \
+						(desc), \
+						skt->regbase + (p), \
+						__raw_readb(skt->regbase + (p)))
+
+#define DEBUG_CF1_REG(desc, p)		printk("CF: %s: Port 0x%08x = 0x%02x\n", \
+						(desc), \
+						CF1_V_BASE + CF_ATTR_BASE + (p), \
+						__raw_readl(CF1_V_BASE + CF_ATTR_BASE + (p)))
+
+#define DEBUG_READ_TEST(desc)		printk("CF: %s: Port 0x3f6 = 0x%02x\n", (desc), CF1_INB(0x3f6))
+
+#else
+#define DEBUG_ETNA(x...)		do { ; } while(0)
+#define DEBUG_ETNA_REG(desc,p)		do { ; } while(0)
+#define DEBUG_CF1_REG(desc,p)		do { ; } while(0)
+#define DEBUG_READ_TEST(desc)		do { ; } while(0)
+#endif
+
+#define CF1_READB(p)			(*(volatile u8 *)(CF1_V_BASE + CF_ATTR_BASE + (p)))
+#define CF1_WRITEB(v,p)			(*(volatile u8 *)(CF1_V_BASE + CF_ATTR_BASE + (p)) = (v))
+
+#define CF1_READL(p)			__raw_readl(CF1_V_BASE + CF_ATTR_BASE + (p))
+#define CF1_WRITEL(v,p)			__raw_writel((v), CF1_V_BASE + CF_ATTR_BASE + (p))
+
+#define CF1_INB(p)			(*(volatile uint8_t *)(CF1_V_BASE + CF_IO8_BASE + (p)))
+#define CF1_INW(p)			(*(volatile uint32_t *)(CF1_V_BASE + CF_IO16_BASE + (p)) & 0xffff)
+
+#define CF1_MEM_READB(p)		(*(volatile u8 *)(CF1_V_BASE + CF_MEM_BASE + (p)))
+#define CF1_MEM_READL(p)		__raw_readl(CF1_V_BASE + CF_MEM_BASE + (p))
+
+#define CF_DEF_CONFIG	0x1		/* Use the first one the CF card */
+
+#define PCISR		0x06		/* PC card int status reg */
+#define PCIMR		0x07		/* PC card int mask reg */
+#define PCICR		0x08		/* PC card int clear reg */
+
+
+/*
+ * Sets up the ETNA hardware
+ */
+static __inline__
+void etna_init_hw(void)
+{
+	int cfg;
+	unsigned long flags;
+
+	save_flags_cli(flags);
+
+#if defined(CONFIG_PSIONW_5MXPRO24MB) | defined(CONFIG_PSIONW_5MXPRO32MB)
+	/* Set the memory wait states to PCMCIA */
+	// FIXME5MX: Should be checked...
+	psionw_writel(0x93930002, MEMCFG1);
+#endif
+
+	/* Clear the door switch interrupt (not in use) */
+	psionw_writel(1, MCEOI);
+
+	/* Power up the CF card */
+	cfg = psionw_readb(PBDR);
+	DEBUG_ETNA("PBDR = 0x%x\n", cfg);
+	if (cfg & PBDR_VPCEN) {
+		DEBUG_ETNA("Clearing no CF power bit in PBDR\n");
+		psionw_writeb(cfg & ~PBDR_VPCEN, PBDR);
+	}
+
+	/* Wake up the socket */
+	__raw_writeb(0x88, ETNA_V_BASE + ETNA_WAKE_1);
+	__raw_writeb(0x10, ETNA_V_BASE + ETNA_WAKE_2);
+
+	/* Configure the ETNA socket */
+	__raw_writeb(0x41, ETNA_V_BASE + ETNA_SKT_CTRL);
+
+	/* Activate the socket */
+	__raw_writeb(0x66, ETNA_V_BASE + ETNA_SKT_ACTIVE);
+
+	restore_flags(flags);
+}
+
+/*
+ * Sets the CF card configuration to selected value.
+ */
+static __inline__
+void etna_set_cf(int cf_config)
+{
+	int loops;
+
+	//static int count = 0;
+	//count++;
+	//cpu_cache_clean_invalidate_all();
+	//printk("XXX\n");
+ again:
+	loops = 0;
+
+	DEBUG_ETNA("ETNA: Restoring selected card configuration to: 0x%x\n", cf_config);
+
+	while (CF1_READB(CF_CUR_CFG) != cf_config) {
+		loops++;
+
+		/* Clear pending interrupts for both sockets at CCSR */
+		CF1_WRITEB(0, 0x202);
+
+		/* Restore the selected card configuration */
+		CF1_WRITEB(cf_config, 0x200);
+
+		mdelay(100);
+
+		if (loops > 20) {
+			printk("ETNA: Unable to restore card configuration: 0x%02x != 0x%02x\n",
+			       CF1_READB(CF_CUR_CFG), cf_config);
+			return;
+		}
+	}
+
+	/*
+	 * Did the configuration stay?
+	 */
+	while (CF1_READB(CF_CUR_CFG) != cf_config) {
+		//printk("XXX etna_cf_called total %d times\n", count);
+		printk("XXX Trying again\n");
+		goto again;
+	}
+}
+
+/*
+ * Initializes the ETNA hardware. Any previous card configuration
+ * is lost. Needed on 5mx Pro when booting without Epoc. Called
+ * from ide.h
+ */
+static __inline__ 
+void etna_cold_init(void)
+{
+	printk("ETNA: CompactFlash PCMCIA controller hard init\n");
+
+	/* Turn on the power if it is not already on */
+	start_pump(1);
+	mdelay(30);	/* Needed for some cards */
+	etna_init_hw();
+
+	/* Set the card configuration */
+	etna_set_cf(CF_DEF_CONFIG);
+
+	/* Clear the ETNA interrupts */
+	__raw_writeb(0x01, ETNA_V_BASE + ETNA_INT_CLEAR);
+
+	/* Turn on ETNA interrupt */
+	__raw_writeb(0x01, ETNA_V_BASE + ETNA_INT_MASK);
+
+	//enable_irq(IRQ_EINT1);
+}
