linux-mips.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Alchemy: XXS1500 PCMCIA driver rewrite
@ 2009-09-29 18:50 Manuel Lauss
  2009-09-29 19:46 ` Florian Fainelli
  2009-10-02 10:59 ` Wolfram Sang
  0 siblings, 2 replies; 10+ messages in thread
From: Manuel Lauss @ 2009-09-29 18:50 UTC (permalink / raw)
  To: linux-pcmcia; +Cc: Linux-MIPS, Manuel Lauss, Florian Fainelli

Rewritten XXS1500 PCMCIA socket driver, standalone (doesn't
depend on au1000_generic.c) and added carddetect IRQ support.

Cc: Florian Fainelli <florian@openwrt.org>
Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
Against latest linus-git, compile-tested only.
CC'ing Florian, he might still have a testsystem.

 arch/mips/alchemy/xxs1500/Makefile      |    2 +-
 arch/mips/alchemy/xxs1500/board_setup.c |   16 --
 arch/mips/alchemy/xxs1500/platform.c    |   63 ++++++
 drivers/pcmcia/Kconfig                  |   10 +
 drivers/pcmcia/Makefile                 |    3 +-
 drivers/pcmcia/au1000_xxs1500.c         |  188 ----------------
 drivers/pcmcia/xxs1500_ss.c             |  357 +++++++++++++++++++++++++++++++
 7 files changed, 433 insertions(+), 206 deletions(-)
 create mode 100644 arch/mips/alchemy/xxs1500/platform.c
 delete mode 100644 drivers/pcmcia/au1000_xxs1500.c
 create mode 100644 drivers/pcmcia/xxs1500_ss.c

diff --git a/arch/mips/alchemy/xxs1500/Makefile b/arch/mips/alchemy/xxs1500/Makefile
index db3c526..3a79a90 100644
--- a/arch/mips/alchemy/xxs1500/Makefile
+++ b/arch/mips/alchemy/xxs1500/Makefile
@@ -5,4 +5,4 @@
 # Makefile for MyCable XXS1500 board.
 #
 
-lib-y := init.o board_setup.o irqmap.o
+lib-y := init.o board_setup.o irqmap.o platform.o
diff --git a/arch/mips/alchemy/xxs1500/board_setup.c b/arch/mips/alchemy/xxs1500/board_setup.c
index 4de2d48..6d6de53 100644
--- a/arch/mips/alchemy/xxs1500/board_setup.c
+++ b/arch/mips/alchemy/xxs1500/board_setup.c
@@ -68,22 +68,6 @@ void __init board_setup(void)
 	/* Enable DTR = USB power up */
 	au_writel(0x01, UART3_ADDR + UART_MCR); /* UART_MCR_DTR is 0x01??? */
 
-#ifdef CONFIG_PCMCIA_XXS1500
-	/* GPIO 0, 1, and 4 are inputs */
-	alchemy_gpio_direction_input(0);
-	alchemy_gpio_direction_input(1);
-	alchemy_gpio_direction_input(4);
-
-	/* GPIO2 208/9/10/11 are inputs */
-	alchemy_gpio_direction_input(208);
-	alchemy_gpio_direction_input(209);
-	alchemy_gpio_direction_input(210);
-	alchemy_gpio_direction_input(211);
-
-	/* Turn off power */
-	alchemy_gpio_direction_output(214, 0);
-#endif
-
 #ifdef CONFIG_PCI
 #if defined(__MIPSEB__)
 	au_writel(0xf | (2 << 6) | (1 << 4), Au1500_PCI_CFG);
diff --git a/arch/mips/alchemy/xxs1500/platform.c b/arch/mips/alchemy/xxs1500/platform.c
new file mode 100644
index 0000000..9edbdfd
--- /dev/null
+++ b/arch/mips/alchemy/xxs1500/platform.c
@@ -0,0 +1,63 @@
+/*
+ * XXS1500 board platform device registration
+ *
+ * Copyright (C) 2009 Manuel Lauss
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-au1x00/au1000.h>
+
+static struct resource xxs1500_pcmcia_res[] = {
+	{
+		.name	= "pseudo-io",
+		.flags	= IORESOURCE_MEM,
+		.start	= 0xF0000000,
+		.end	= 0xF0040000 - 1,
+	},
+	{
+		.name	= "pseudo-attr",
+		.flags	= IORESOURCE_MEM,
+		.start	= 0xF4000000,
+		.end	= 0xF4040000 - 1,
+	},
+	{
+		.name	= "pseudo-mem",
+		.flags	= IORESOURCE_MEM,
+		.start	= 0xF8000000,
+		.end	= 0xF8040000 - 1,
+	},
+};
+
+static struct platform_device xxs1500_pcmcia_dev = {
+	.name		= "xxs1500_pcmcia",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(xxs1500_pcmcia_res),
+	.resource	= xxs1500_pcmcia_res,
+};
+
+static struct platform_device *xxs1500_devs[] __initdata = {
+	&xxs1500_pcmcia_dev,
+};
+
+static int __init xxs1500_dev_init(void)
+{
+	return platform_add_devices(xxs1500_devs,
+				    ARRAY_SIZE(xxs1500_devs));
+}
+device_initcall(xxs1500_dev_init);
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index fbf965b..c094108 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -192,6 +192,16 @@ config PCMCIA_AU1X00
 	tristate "Au1x00 pcmcia support"
 	depends on SOC_AU1X00 && PCMCIA
 
+config PCMCIA_XXS1500
+	tristate "MyCable XXS1500 PCMCIA socket support"
+	depends on PCMCIA && MIPS_XXS1500
+	select 64BIT_PHYS_ADDR
+	help
+	  Support for the PCMCIA/CF socket interface on MyCable XXS1500
+	  systems.
+
+	  This driver is also available as a module called xxs1500_ss.ko
+
 config PCMCIA_SA1100
 	tristate "SA1100 support"
 	depends on ARM && ARCH_SA1100 && PCMCIA
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index 3247828..95433f7 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -47,7 +47,6 @@ au1x00_ss-$(CONFIG_MIPS_DB1100)			+= au1000_db1x00.o
 au1x00_ss-$(CONFIG_MIPS_DB1200)			+= au1000_db1x00.o
 au1x00_ss-$(CONFIG_MIPS_DB1500)			+= au1000_db1x00.o
 au1x00_ss-$(CONFIG_MIPS_DB1550)			+= au1000_db1x00.o
-au1x00_ss-$(CONFIG_MIPS_XXS1500)		+= au1000_xxs1500.o
 
 sa1111_cs-y					+= sa1111_generic.o
 sa1111_cs-$(CONFIG_ASSABET_NEPONSET)		+= sa1100_neponset.o
@@ -77,3 +76,5 @@ pxa2xx-obj-$(CONFIG_MACH_E740)			+= pxa2xx_e740.o
 pxa2xx-obj-$(CONFIG_MACH_STARGATE2)		+= pxa2xx_stargate2.o
 
 obj-$(CONFIG_PCMCIA_PXA2XX)			+= pxa2xx_core.o $(pxa2xx-obj-y)
+
+obj-$(CONFIG_PCMCIA_XXS1500)			+= xxs1500_ss.o
diff --git a/drivers/pcmcia/au1000_xxs1500.c b/drivers/pcmcia/au1000_xxs1500.c
deleted file mode 100644
index b43d47b..0000000
--- a/drivers/pcmcia/au1000_xxs1500.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- *
- * MyCable board specific pcmcia routines.
- *
- * Copyright 2003 MontaVista Software Inc.
- * Author: Pete Popov, MontaVista Software, Inc.
- *         	ppopov@mvista.com or source@mvista.com
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- *  for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * ########################################################################
- *
- *
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/proc_fs.h>
-#include <linux/types.h>
-
-#include <pcmcia/cs_types.h>
-#include <pcmcia/cs.h>
-#include <pcmcia/ss.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/bus_ops.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
-#include <asm/au1000.h>
-#include <asm/au1000_pcmcia.h>
-
-#define PCMCIA_MAX_SOCK		0
-#define PCMCIA_NUM_SOCKS	(PCMCIA_MAX_SOCK + 1)
-#define PCMCIA_IRQ		AU1000_GPIO_4
-
-#if 0
-#define DEBUG(x, args...)	printk(__func__ ": " x, ##args)
-#else
-#define DEBUG(x,args...)
-#endif
-
-static int xxs1500_pcmcia_init(struct pcmcia_init *init)
-{
-	return PCMCIA_NUM_SOCKS;
-}
-
-static int xxs1500_pcmcia_shutdown(void)
-{
-	/* turn off power */
-	au_writel(au_readl(GPIO2_PINSTATE) | (1<<14)|(1<<30),
-			GPIO2_OUTPUT);
-	au_sync_delay(100);
-
-	/* assert reset */
-	au_writel(au_readl(GPIO2_PINSTATE) | (1<<4)|(1<<20),
-			GPIO2_OUTPUT);
-	au_sync_delay(100);
-	return 0;
-}
-
-
-static int
-xxs1500_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state)
-{
-	u32 inserted; u32 vs;
-	unsigned long gpio, gpio2;
-
-	if(sock > PCMCIA_MAX_SOCK) return -1;
-
-	gpio = au_readl(SYS_PINSTATERD);
-	gpio2 = au_readl(GPIO2_PINSTATE);
-
-	vs = gpio2 & ((1<<8) | (1<<9));
-	inserted = (!(gpio & 0x1) && !(gpio & 0x2));
-
-	state->ready = 0;
-	state->vs_Xv = 0;
-	state->vs_3v = 0;
-	state->detect = 0;
-
-	if (inserted) {
-		switch (vs) {
-			case 0:
-			case 1:
-			case 2:
-				state->vs_3v=1;
-				break;
-			case 3: /* 5V */
-			default:
-				/* return without setting 'detect' */
-				printk(KERN_ERR "au1x00_cs: unsupported VS\n",
-						vs);
-				return;
-		}
-		state->detect = 1;
-	}
-
-	if (state->detect) {
-		state->ready = 1;
-	}
-
-	state->bvd1= gpio2 & (1<<10);
-	state->bvd2 = gpio2 & (1<<11);
-	state->wrprot=0;
-	return 1;
-}
-
-
-static int xxs1500_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
-{
-
-	if(info->sock > PCMCIA_MAX_SOCK) return -1;
-	info->irq = PCMCIA_IRQ;
-	return 0;
-}
-
-
-static int
-xxs1500_pcmcia_configure_socket(const struct pcmcia_configure *configure)
-{
-
-	if(configure->sock > PCMCIA_MAX_SOCK) return -1;
-
-	DEBUG("Vcc %dV Vpp %dV, reset %d\n",
-			configure->vcc, configure->vpp, configure->reset);
-
-	switch(configure->vcc){
-		case 33: /* Vcc 3.3V */
-			/* turn on power */
-			DEBUG("turn on power\n");
-			au_writel((au_readl(GPIO2_PINSTATE) & ~(1<<14))|(1<<30),
-					GPIO2_OUTPUT);
-			au_sync_delay(100);
-			break;
-		case 50: /* Vcc 5V */
-		default: /* what's this ? */
-			printk(KERN_ERR "au1x00_cs: unsupported VCC\n");
-		case 0:  /* Vcc 0 */
-			/* turn off power */
-			au_sync_delay(100);
-			au_writel(au_readl(GPIO2_PINSTATE) | (1<<14)|(1<<30),
-					GPIO2_OUTPUT);
-			break;
-	}
-
-	if (!configure->reset) {
-		DEBUG("deassert reset\n");
-		au_writel((au_readl(GPIO2_PINSTATE) & ~(1<<4))|(1<<20),
-				GPIO2_OUTPUT);
-		au_sync_delay(100);
-		au_writel((au_readl(GPIO2_PINSTATE) & ~(1<<5))|(1<<21),
-				GPIO2_OUTPUT);
-	}
-	else {
-		DEBUG("assert reset\n");
-		au_writel(au_readl(GPIO2_PINSTATE) | (1<<4)|(1<<20),
-				GPIO2_OUTPUT);
-	}
-	au_sync_delay(100);
-	return 0;
-}
-
-struct pcmcia_low_level xxs1500_pcmcia_ops = {
-	xxs1500_pcmcia_init,
-	xxs1500_pcmcia_shutdown,
-	xxs1500_pcmcia_socket_state,
-	xxs1500_pcmcia_get_irq_info,
-	xxs1500_pcmcia_configure_socket
-};
diff --git a/drivers/pcmcia/xxs1500_ss.c b/drivers/pcmcia/xxs1500_ss.c
new file mode 100644
index 0000000..4e36930
--- /dev/null
+++ b/drivers/pcmcia/xxs1500_ss.c
@@ -0,0 +1,357 @@
+/*
+ * PCMCIA socket code for the MyCable XXS1500 system.
+ *
+ * Copyright (c) 2009 Manuel Lauss <manuel.lauss@gmail.com>
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/resource.h>
+#include <linux/spinlock.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cistpl.h>
+
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/mach-au1x00/au1000.h>
+
+#define MEM_MAP_SIZE	0x400000
+#define IO_MAP_SIZE	0x1000
+
+
+/*
+ * 3.3V cards only; all interfacing is done via gpios:
+ *
+ * 0/1:  carddetect (00 = card present, xx = huh)
+ * 4:	 card irq
+ * 204:  reset (high-act)
+ * 205:  buffer enable (low-act)
+ * 208/209: card voltage key (00,01,10,11)
+ * 210:  battwarn
+ * 211:  batdead
+ * 214:  power (low-act)
+ */
+#define GPIO_CDA	0
+#define GPIO_CDB	1
+#define GPIO_CARDIRQ	4
+#define GPIO_RESET	204
+#define GPIO_OUTEN	205
+#define GPIO_VSL	208
+#define GPIO_VSH	209
+#define GPIO_BATTDEAD	210
+#define GPIO_BATTWARN	211
+#define GPIO_POWER	214
+
+struct xxs1500_pcmcia_sock {
+	struct pcmcia_socket	socket;
+	void		*virt_io;
+
+	/* the "pseudo" addresses of the PCMCIA space. */
+	unsigned long	phys_io;
+	unsigned long	phys_attr;
+	unsigned long	phys_mem;
+
+	/* previous flags for set_socket() */
+	unsigned int old_flags;
+};
+
+#define to_xxs_socket(x) container_of(x, struct xxs1500_pcmcia_sock, socket)
+
+static irqreturn_t cdirq(int irq, void *data)
+{
+	struct xxs1500_pcmcia_sock *sock = data;
+
+	pcmcia_parse_events(&sock->socket, SS_DETECT);
+
+	return IRQ_HANDLED;
+}
+
+static int xxs1500_pcmcia_configure(struct pcmcia_socket *skt,
+				    struct socket_state_t *state)
+{
+	struct xxs1500_pcmcia_sock *sock = to_xxs_socket(skt);
+	unsigned int changed;
+
+	/* power control */
+	switch (state->Vcc) {
+	case 0:
+		gpio_set_value(GPIO_POWER, 1);	/* power off */
+		break;
+	case 33:
+		gpio_set_value(GPIO_POWER, 0);	/* power on */
+		break;
+	case 50:
+	default:
+		return -EINVAL;
+	}
+
+	changed = state->flags ^ sock->old_flags;
+
+	if (changed & SS_RESET) {
+		if (state->flags & SS_RESET) {
+			gpio_set_value(GPIO_RESET, 1);	/* assert reset */
+			gpio_set_value(GPIO_OUTEN, 1);	/* buffers off */
+		} else {
+			gpio_set_value(GPIO_RESET, 0);	/* deassert reset */
+			gpio_set_value(GPIO_OUTEN, 0);	/* buffers on */
+			msleep(500);
+		}
+	}
+
+	sock->old_flags = state->flags;
+
+	return 0;
+}
+
+static int xxs1500_pcmcia_get_status(struct pcmcia_socket *skt,
+				     unsigned int *value)
+{
+	unsigned int status;
+	int i;
+
+	status = 0;
+
+	/* check carddetects: GPIO[0:1] must both be low */
+	if (!gpio_get_value(GPIO_CDA) && !gpio_get_value(GPIO_CDB))
+		status |= SS_DETECT;
+
+	/* determine card voltage: GPIO[208:209] binary value */
+	i = (!!gpio_get_value(GPIO_VSL)) | ((!!gpio_get_value(GPIO_VSH)) << 1);
+
+	switch (i) {
+	case 0:
+	case 1:
+	case 2:
+		status |= SS_3VCARD;	/* 3V card */
+		break;
+	case 3:				/* 5V card, unsupported */
+	default:
+		status |= SS_XVCARD;	/* treated as unsupported in core */
+	}
+
+	/* GPIO214: low active power switch */
+	status |= gpio_get_value(GPIO_POWER) ? 0 : SS_POWERON;
+
+	/* GPIO204: high-active reset line */
+	status |= gpio_get_value(GPIO_RESET) ? SS_RESET : SS_READY;
+
+	/* other stuff */
+	status |= gpio_get_value(GPIO_BATTDEAD) ? 0 : SS_BATDEAD;
+	status |= gpio_get_value(GPIO_BATTWARN) ? 0 : SS_BATWARN;
+
+	*value = status;
+
+	return 0;
+}
+
+static int xxs1500_pcmcia_sock_init(struct pcmcia_socket *skt)
+{
+	gpio_direction_input(GPIO_CDA);
+	gpio_direction_input(GPIO_CDB);
+	gpio_direction_input(GPIO_VSL);
+	gpio_direction_input(GPIO_VSH);
+	gpio_direction_input(GPIO_BATTDEAD);
+	gpio_direction_input(GPIO_BATTWARN);
+	gpio_direction_output(GPIO_RESET, 1);	/* assert reset */
+	gpio_direction_output(GPIO_OUTEN, 1);	/* disable buffers */
+	gpio_direction_output(GPIO_POWER, 1);	/* power off */
+
+	return 0;
+}
+
+static int xxs1500_pcmcia_sock_suspend(struct pcmcia_socket *skt)
+{
+	return 0;
+}
+
+static int au1x00_pcmcia_set_io_map(struct pcmcia_socket *skt,
+				    struct pccard_io_map *map)
+{
+	struct xxs1500_pcmcia_sock *sock = to_xxs_socket(skt);
+
+	map->start = (u32)sock->virt_io;
+	map->stop = map->start + IO_MAP_SIZE;
+
+	return 0;
+}
+
+static int au1x00_pcmcia_set_mem_map(struct pcmcia_socket *skt,
+				     struct pccard_mem_map *map)
+{
+	struct xxs1500_pcmcia_sock *sock = to_xxs_socket(skt);
+
+	if (map->flags & MAP_ATTRIB)
+		map->static_start = sock->phys_attr + map->card_start;
+	else
+		map->static_start = sock->phys_mem + map->card_start;
+
+	return 0;
+}
+
+static struct pccard_operations xxs1500_pcmcia_operations = {
+	.init			= xxs1500_pcmcia_sock_init,
+	.suspend		= xxs1500_pcmcia_sock_suspend,
+	.get_status		= xxs1500_pcmcia_get_status,
+	.set_socket		= xxs1500_pcmcia_configure,
+	.set_io_map		= au1x00_pcmcia_set_io_map,
+	.set_mem_map		= au1x00_pcmcia_set_mem_map,
+};
+
+static int __devinit xxs1500_pcmcia_probe(struct platform_device *pdev)
+{
+	struct xxs1500_pcmcia_sock *sock;
+	struct resource *r;
+	phys_t physio;
+	int ret, irq;
+
+	sock = kzalloc(sizeof(struct xxs1500_pcmcia_sock), GFP_KERNEL);
+	if (!sock)
+		return -ENOMEM;
+
+	ret = -ENODEV;
+
+	/*
+	 * pseudo-attr:  The 32bit address of the PCMCIA attribute space
+	 * for this socket (usually the 36bit address shifted 4 to the
+	 * right).
+	 */
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pseudo-attr");
+	if (!r) {
+		dev_err(&pdev->dev, "missing 'pseudo-attr' resource!\n");
+		goto out0;
+	}
+	sock->phys_attr = r->start;
+
+	/*
+	 * pseudo-mem:  The 32bit address of the PCMCIA memory space for
+	 * this socket (usually the 36bit address shifted 4 to the right)
+	 */
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pseudo-mem");
+	if (!r) {
+		dev_err(&pdev->dev, "missing 'pseudo-mem' resource!\n");
+		goto out0;
+	}
+	sock->phys_mem = r->start;
+
+	/*
+	 * pseudo-io:  The 32bit address of the PCMCIA IO space for this
+	 * socket (usually the 36bit address shifted 4 to the right).
+	 */
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pseudo-io");
+	if (!r) {
+		dev_err(&pdev->dev, "missing 'pseudo-io' resource!\n");
+		goto out0;
+	}
+	sock->phys_io = r->start;
+
+
+	/* for io must remap the full 36bit address (for reference see
+	 * alchemy/common/setup.c::__fixup_bigphys_addr)
+	 */
+	physio = ((phys_t)sock->phys_io) << 4;
+
+	/*
+	 * PCMCIA client drivers use the inb/outb macros to access
+	 * the IO registers.  Since mips_io_port_base is added
+	 * to the access address of the mips implementation of
+	 * inb/outb, we need to subtract it here because we want
+	 * to access the I/O or MEM address directly, without
+	 * going through this "mips_io_port_base" mechanism.
+	 */
+	sock->virt_io = (void *)(ioremap(physio, IO_MAP_SIZE) -
+				 mips_io_port_base);
+
+	if (!sock->virt_io) {
+		dev_err(&pdev->dev, "cannot remap IO area\n");
+		ret = -ENOMEM;
+		goto out0;
+	}
+
+	sock->socket.ops	= &xxs1500_pcmcia_operations;
+	sock->socket.owner	= THIS_MODULE;
+	sock->socket.pci_irq	= gpio_to_irq(GPIO_CARDIRQ);
+	sock->socket.features	= SS_CAP_STATIC_MAP | SS_CAP_PCCARD;
+	sock->socket.map_size	= MEM_MAP_SIZE;
+	sock->socket.io_offset	= (unsigned long)sock->virt_io;
+	sock->socket.dev.parent	= &pdev->dev;
+	sock->socket.resource_ops = &pccard_static_ops;
+
+	platform_set_drvdata(pdev, sock);
+
+	/* setup carddetect irq: use one of the 2 GPIOs as an
+	 * edge detector.
+	 */
+	irq = gpio_to_irq(GPIO_CDA);
+	set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
+	ret = request_irq(irq, cdirq, 0, "pcmcia_carddetect", sock);
+	if (ret) {
+		dev_err(&pdev->dev, "cannot setup cd irq\n");
+		goto out1;
+	}
+
+	ret = pcmcia_register_socket(&sock->socket);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register\n");
+		goto out2;
+	}
+
+	printk(KERN_INFO "MyCable XXS1500 PCMCIA socket services\n");
+
+	return 0;
+
+out2:
+	free_irq(gpio_to_irq(GPIO_CDA), sock);
+out1:
+	iounmap((void *)(sock->virt_io + (u32)mips_io_port_base));
+out0:
+	kfree(sock);
+	return ret;
+}
+
+static int __devexit xxs1500_pcmcia_remove(struct platform_device *pdev)
+{
+	struct xxs1500_pcmcia_sock *sock = platform_get_drvdata(pdev);
+
+	pcmcia_unregister_socket(&sock->socket);
+	free_irq(gpio_to_irq(GPIO_CDA), sock);
+	iounmap((void *)(sock->virt_io + (u32)mips_io_port_base));
+	kfree(sock);
+
+	return 0;
+}
+
+static struct platform_driver xxs1500_pcmcia_socket_driver = {
+	.driver	= {
+		.name	= "xxs1500_pcmcia",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= xxs1500_pcmcia_probe,
+	.remove		= __devexit_p(xxs1500_pcmcia_remove),
+};
+
+int __init xxs1500_pcmcia_socket_load(void)
+{
+	return platform_driver_register(&xxs1500_pcmcia_socket_driver);
+}
+
+void  __exit xxs1500_pcmcia_socket_unload(void)
+{
+	platform_driver_unregister(&xxs1500_pcmcia_socket_driver);
+}
+
+module_init(xxs1500_pcmcia_socket_load);
+module_exit(xxs1500_pcmcia_socket_unload);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PCMCIA Socket Services for MyCable XXS1500 systems");
+MODULE_AUTHOR("Manuel Lauss");
-- 
1.6.5.rc1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH] Alchemy: XXS1500 PCMCIA driver rewrite
  2009-09-29 18:50 [PATCH] Alchemy: XXS1500 PCMCIA driver rewrite Manuel Lauss
@ 2009-09-29 19:46 ` Florian Fainelli
  2009-10-02 10:59 ` Wolfram Sang
  1 sibling, 0 replies; 10+ messages in thread
From: Florian Fainelli @ 2009-09-29 19:46 UTC (permalink / raw)
  To: Manuel Lauss; +Cc: linux-pcmcia, Linux-MIPS, Manuel Lauss

Hi Manuel,

Le mardi 29 septembre 2009 20:50:36, Manuel Lauss a écrit :
> Rewritten XXS1500 PCMCIA socket driver, standalone (doesn't
> depend on au1000_generic.c) and added carddetect IRQ support.

Thanks for CC'ing me, will make my best to test this driver, soon.

> 
> Cc: Florian Fainelli <florian@openwrt.org>
> Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
> ---
> Against latest linus-git, compile-tested only.
> CC'ing Florian, he might still have a testsystem.
> 
>  arch/mips/alchemy/xxs1500/Makefile      |    2 +-
>  arch/mips/alchemy/xxs1500/board_setup.c |   16 --
>  arch/mips/alchemy/xxs1500/platform.c    |   63 ++++++
>  drivers/pcmcia/Kconfig                  |   10 +
>  drivers/pcmcia/Makefile                 |    3 +-
>  drivers/pcmcia/au1000_xxs1500.c         |  188 ----------------
>  drivers/pcmcia/xxs1500_ss.c             |  357
>  +++++++++++++++++++++++++++++++ 7 files changed, 433 insertions(+), 206
>  deletions(-)
>  create mode 100644 arch/mips/alchemy/xxs1500/platform.c
>  delete mode 100644 drivers/pcmcia/au1000_xxs1500.c
>  create mode 100644 drivers/pcmcia/xxs1500_ss.c
> 
> diff --git a/arch/mips/alchemy/xxs1500/Makefile
>  b/arch/mips/alchemy/xxs1500/Makefile index db3c526..3a79a90 100644
> --- a/arch/mips/alchemy/xxs1500/Makefile
> +++ b/arch/mips/alchemy/xxs1500/Makefile
> @@ -5,4 +5,4 @@
>  # Makefile for MyCable XXS1500 board.
>  #
> 
> -lib-y := init.o board_setup.o irqmap.o
> +lib-y := init.o board_setup.o irqmap.o platform.o
> diff --git a/arch/mips/alchemy/xxs1500/board_setup.c
>  b/arch/mips/alchemy/xxs1500/board_setup.c index 4de2d48..6d6de53 100644
> --- a/arch/mips/alchemy/xxs1500/board_setup.c
> +++ b/arch/mips/alchemy/xxs1500/board_setup.c
> @@ -68,22 +68,6 @@ void __init board_setup(void)
>  	/* Enable DTR = USB power up */
>  	au_writel(0x01, UART3_ADDR + UART_MCR); /* UART_MCR_DTR is 0x01??? */
> 
> -#ifdef CONFIG_PCMCIA_XXS1500
> -	/* GPIO 0, 1, and 4 are inputs */
> -	alchemy_gpio_direction_input(0);
> -	alchemy_gpio_direction_input(1);
> -	alchemy_gpio_direction_input(4);
> -
> -	/* GPIO2 208/9/10/11 are inputs */
> -	alchemy_gpio_direction_input(208);
> -	alchemy_gpio_direction_input(209);
> -	alchemy_gpio_direction_input(210);
> -	alchemy_gpio_direction_input(211);
> -
> -	/* Turn off power */
> -	alchemy_gpio_direction_output(214, 0);
> -#endif
> -
>  #ifdef CONFIG_PCI
>  #if defined(__MIPSEB__)
>  	au_writel(0xf | (2 << 6) | (1 << 4), Au1500_PCI_CFG);
> diff --git a/arch/mips/alchemy/xxs1500/platform.c
>  b/arch/mips/alchemy/xxs1500/platform.c new file mode 100644
> index 0000000..9edbdfd
> --- /dev/null
> +++ b/arch/mips/alchemy/xxs1500/platform.c
> @@ -0,0 +1,63 @@
> +/*
> + * XXS1500 board platform device registration
> + *
> + * Copyright (C) 2009 Manuel Lauss
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 
>  USA + */
> +
> +#include <linux/init.h>
> +#include <linux/platform_device.h>
> +
> +#include <asm/mach-au1x00/au1000.h>
> +
> +static struct resource xxs1500_pcmcia_res[] = {
> +	{
> +		.name	= "pseudo-io",
> +		.flags	= IORESOURCE_MEM,
> +		.start	= 0xF0000000,
> +		.end	= 0xF0040000 - 1,
> +	},
> +	{
> +		.name	= "pseudo-attr",
> +		.flags	= IORESOURCE_MEM,
> +		.start	= 0xF4000000,
> +		.end	= 0xF4040000 - 1,
> +	},
> +	{
> +		.name	= "pseudo-mem",
> +		.flags	= IORESOURCE_MEM,
> +		.start	= 0xF8000000,
> +		.end	= 0xF8040000 - 1,
> +	},
> +};
> +
> +static struct platform_device xxs1500_pcmcia_dev = {
> +	.name		= "xxs1500_pcmcia",
> +	.id		= -1,
> +	.num_resources	= ARRAY_SIZE(xxs1500_pcmcia_res),
> +	.resource	= xxs1500_pcmcia_res,
> +};
> +
> +static struct platform_device *xxs1500_devs[] __initdata = {
> +	&xxs1500_pcmcia_dev,
> +};
> +
> +static int __init xxs1500_dev_init(void)
> +{
> +	return platform_add_devices(xxs1500_devs,
> +				    ARRAY_SIZE(xxs1500_devs));
> +}
> +device_initcall(xxs1500_dev_init);
> diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
> index fbf965b..c094108 100644
> --- a/drivers/pcmcia/Kconfig
> +++ b/drivers/pcmcia/Kconfig
> @@ -192,6 +192,16 @@ config PCMCIA_AU1X00
>  	tristate "Au1x00 pcmcia support"
>  	depends on SOC_AU1X00 && PCMCIA
> 
> +config PCMCIA_XXS1500
> +	tristate "MyCable XXS1500 PCMCIA socket support"
> +	depends on PCMCIA && MIPS_XXS1500
> +	select 64BIT_PHYS_ADDR
> +	help
> +	  Support for the PCMCIA/CF socket interface on MyCable XXS1500
> +	  systems.
> +
> +	  This driver is also available as a module called xxs1500_ss.ko
> +
>  config PCMCIA_SA1100
>  	tristate "SA1100 support"
>  	depends on ARM && ARCH_SA1100 && PCMCIA
> diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
> index 3247828..95433f7 100644
> --- a/drivers/pcmcia/Makefile
> +++ b/drivers/pcmcia/Makefile
> @@ -47,7 +47,6 @@ au1x00_ss-$(CONFIG_MIPS_DB1100)			+= au1000_db1x00.o
>  au1x00_ss-$(CONFIG_MIPS_DB1200)			+= au1000_db1x00.o
>  au1x00_ss-$(CONFIG_MIPS_DB1500)			+= au1000_db1x00.o
>  au1x00_ss-$(CONFIG_MIPS_DB1550)			+= au1000_db1x00.o
> -au1x00_ss-$(CONFIG_MIPS_XXS1500)		+= au1000_xxs1500.o
> 
>  sa1111_cs-y					+= sa1111_generic.o
>  sa1111_cs-$(CONFIG_ASSABET_NEPONSET)		+= sa1100_neponset.o
> @@ -77,3 +76,5 @@ pxa2xx-obj-$(CONFIG_MACH_E740)			+= pxa2xx_e740.o
>  pxa2xx-obj-$(CONFIG_MACH_STARGATE2)		+= pxa2xx_stargate2.o
> 
>  obj-$(CONFIG_PCMCIA_PXA2XX)			+= pxa2xx_core.o $(pxa2xx-obj-y)
> +
> +obj-$(CONFIG_PCMCIA_XXS1500)			+= xxs1500_ss.o
> diff --git a/drivers/pcmcia/au1000_xxs1500.c
>  b/drivers/pcmcia/au1000_xxs1500.c deleted file mode 100644
> index b43d47b..0000000
> --- a/drivers/pcmcia/au1000_xxs1500.c
> +++ /dev/null
> @@ -1,188 +0,0 @@
> -/*
> - *
> - * MyCable board specific pcmcia routines.
> - *
> - * Copyright 2003 MontaVista Software Inc.
> - * Author: Pete Popov, MontaVista Software, Inc.
> - *         	ppopov@mvista.com or source@mvista.com
> - *
> - *
>  ######################################################################## -
>  *
> - *  This program is free software; you can distribute it and/or modify it
> - *  under the terms of the GNU General Public License (Version 2) as
> - *  published by the Free Software Foundation.
> - *
> - *  This program is distributed in the hope it will be useful, but WITHOUT
> - *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> - *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> - *  for more details.
> - *
> - *  You should have received a copy of the GNU General Public License
>  along - *  with this program; if not, write to the Free Software
>  Foundation, Inc., - *  59 Temple Place - Suite 330, Boston MA 02111-1307,
>  USA.
> - *
> - *
>  ######################################################################## -
>  *
> - *
> - */
> -#include <linux/module.h>
> -#include <linux/init.h>
> -#include <linux/delay.h>
> -#include <linux/ioport.h>
> -#include <linux/kernel.h>
> -#include <linux/timer.h>
> -#include <linux/mm.h>
> -#include <linux/proc_fs.h>
> -#include <linux/types.h>
> -
> -#include <pcmcia/cs_types.h>
> -#include <pcmcia/cs.h>
> -#include <pcmcia/ss.h>
> -#include <pcmcia/cistpl.h>
> -#include <pcmcia/bus_ops.h>
> -
> -#include <asm/io.h>
> -#include <asm/irq.h>
> -#include <asm/system.h>
> -
> -#include <asm/au1000.h>
> -#include <asm/au1000_pcmcia.h>
> -
> -#define PCMCIA_MAX_SOCK		0
> -#define PCMCIA_NUM_SOCKS	(PCMCIA_MAX_SOCK + 1)
> -#define PCMCIA_IRQ		AU1000_GPIO_4
> -
> -#if 0
> -#define DEBUG(x, args...)	printk(__func__ ": " x, ##args)
> -#else
> -#define DEBUG(x,args...)
> -#endif
> -
> -static int xxs1500_pcmcia_init(struct pcmcia_init *init)
> -{
> -	return PCMCIA_NUM_SOCKS;
> -}
> -
> -static int xxs1500_pcmcia_shutdown(void)
> -{
> -	/* turn off power */
> -	au_writel(au_readl(GPIO2_PINSTATE) | (1<<14)|(1<<30),
> -			GPIO2_OUTPUT);
> -	au_sync_delay(100);
> -
> -	/* assert reset */
> -	au_writel(au_readl(GPIO2_PINSTATE) | (1<<4)|(1<<20),
> -			GPIO2_OUTPUT);
> -	au_sync_delay(100);
> -	return 0;
> -}
> -
> -
> -static int
> -xxs1500_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state)
> -{
> -	u32 inserted; u32 vs;
> -	unsigned long gpio, gpio2;
> -
> -	if(sock > PCMCIA_MAX_SOCK) return -1;
> -
> -	gpio = au_readl(SYS_PINSTATERD);
> -	gpio2 = au_readl(GPIO2_PINSTATE);
> -
> -	vs = gpio2 & ((1<<8) | (1<<9));
> -	inserted = (!(gpio & 0x1) && !(gpio & 0x2));
> -
> -	state->ready = 0;
> -	state->vs_Xv = 0;
> -	state->vs_3v = 0;
> -	state->detect = 0;
> -
> -	if (inserted) {
> -		switch (vs) {
> -			case 0:
> -			case 1:
> -			case 2:
> -				state->vs_3v=1;
> -				break;
> -			case 3: /* 5V */
> -			default:
> -				/* return without setting 'detect' */
> -				printk(KERN_ERR "au1x00_cs: unsupported VS\n",
> -						vs);
> -				return;
> -		}
> -		state->detect = 1;
> -	}
> -
> -	if (state->detect) {
> -		state->ready = 1;
> -	}
> -
> -	state->bvd1= gpio2 & (1<<10);
> -	state->bvd2 = gpio2 & (1<<11);
> -	state->wrprot=0;
> -	return 1;
> -}
> -
> -
> -static int xxs1500_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
> -{
> -
> -	if(info->sock > PCMCIA_MAX_SOCK) return -1;
> -	info->irq = PCMCIA_IRQ;
> -	return 0;
> -}
> -
> -
> -static int
> -xxs1500_pcmcia_configure_socket(const struct pcmcia_configure *configure)
> -{
> -
> -	if(configure->sock > PCMCIA_MAX_SOCK) return -1;
> -
> -	DEBUG("Vcc %dV Vpp %dV, reset %d\n",
> -			configure->vcc, configure->vpp, configure->reset);
> -
> -	switch(configure->vcc){
> -		case 33: /* Vcc 3.3V */
> -			/* turn on power */
> -			DEBUG("turn on power\n");
> -			au_writel((au_readl(GPIO2_PINSTATE) & ~(1<<14))|(1<<30),
> -					GPIO2_OUTPUT);
> -			au_sync_delay(100);
> -			break;
> -		case 50: /* Vcc 5V */
> -		default: /* what's this ? */
> -			printk(KERN_ERR "au1x00_cs: unsupported VCC\n");
> -		case 0:  /* Vcc 0 */
> -			/* turn off power */
> -			au_sync_delay(100);
> -			au_writel(au_readl(GPIO2_PINSTATE) | (1<<14)|(1<<30),
> -					GPIO2_OUTPUT);
> -			break;
> -	}
> -
> -	if (!configure->reset) {
> -		DEBUG("deassert reset\n");
> -		au_writel((au_readl(GPIO2_PINSTATE) & ~(1<<4))|(1<<20),
> -				GPIO2_OUTPUT);
> -		au_sync_delay(100);
> -		au_writel((au_readl(GPIO2_PINSTATE) & ~(1<<5))|(1<<21),
> -				GPIO2_OUTPUT);
> -	}
> -	else {
> -		DEBUG("assert reset\n");
> -		au_writel(au_readl(GPIO2_PINSTATE) | (1<<4)|(1<<20),
> -				GPIO2_OUTPUT);
> -	}
> -	au_sync_delay(100);
> -	return 0;
> -}
> -
> -struct pcmcia_low_level xxs1500_pcmcia_ops = {
> -	xxs1500_pcmcia_init,
> -	xxs1500_pcmcia_shutdown,
> -	xxs1500_pcmcia_socket_state,
> -	xxs1500_pcmcia_get_irq_info,
> -	xxs1500_pcmcia_configure_socket
> -};
> diff --git a/drivers/pcmcia/xxs1500_ss.c b/drivers/pcmcia/xxs1500_ss.c
> new file mode 100644
> index 0000000..4e36930
> --- /dev/null
> +++ b/drivers/pcmcia/xxs1500_ss.c
> @@ -0,0 +1,357 @@
> +/*
> + * PCMCIA socket code for the MyCable XXS1500 system.
> + *
> + * Copyright (c) 2009 Manuel Lauss <manuel.lauss@gmail.com>
> + *
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/gpio.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/ioport.h>
> +#include <linux/mm.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm.h>
> +#include <linux/resource.h>
> +#include <linux/spinlock.h>
> +
> +#include <pcmcia/cs_types.h>
> +#include <pcmcia/cs.h>
> +#include <pcmcia/ss.h>
> +#include <pcmcia/cistpl.h>
> +
> +#include <asm/irq.h>
> +#include <asm/system.h>
> +#include <asm/mach-au1x00/au1000.h>
> +
> +#define MEM_MAP_SIZE	0x400000
> +#define IO_MAP_SIZE	0x1000
> +
> +
> +/*
> + * 3.3V cards only; all interfacing is done via gpios:
> + *
> + * 0/1:  carddetect (00 = card present, xx = huh)
> + * 4:	 card irq
> + * 204:  reset (high-act)
> + * 205:  buffer enable (low-act)
> + * 208/209: card voltage key (00,01,10,11)
> + * 210:  battwarn
> + * 211:  batdead
> + * 214:  power (low-act)
> + */
> +#define GPIO_CDA	0
> +#define GPIO_CDB	1
> +#define GPIO_CARDIRQ	4
> +#define GPIO_RESET	204
> +#define GPIO_OUTEN	205
> +#define GPIO_VSL	208
> +#define GPIO_VSH	209
> +#define GPIO_BATTDEAD	210
> +#define GPIO_BATTWARN	211
> +#define GPIO_POWER	214
> +
> +struct xxs1500_pcmcia_sock {
> +	struct pcmcia_socket	socket;
> +	void		*virt_io;
> +
> +	/* the "pseudo" addresses of the PCMCIA space. */
> +	unsigned long	phys_io;
> +	unsigned long	phys_attr;
> +	unsigned long	phys_mem;
> +
> +	/* previous flags for set_socket() */
> +	unsigned int old_flags;
> +};
> +
> +#define to_xxs_socket(x) container_of(x, struct xxs1500_pcmcia_sock,
>  socket) +
> +static irqreturn_t cdirq(int irq, void *data)
> +{
> +	struct xxs1500_pcmcia_sock *sock = data;
> +
> +	pcmcia_parse_events(&sock->socket, SS_DETECT);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int xxs1500_pcmcia_configure(struct pcmcia_socket *skt,
> +				    struct socket_state_t *state)
> +{
> +	struct xxs1500_pcmcia_sock *sock = to_xxs_socket(skt);
> +	unsigned int changed;
> +
> +	/* power control */
> +	switch (state->Vcc) {
> +	case 0:
> +		gpio_set_value(GPIO_POWER, 1);	/* power off */
> +		break;
> +	case 33:
> +		gpio_set_value(GPIO_POWER, 0);	/* power on */
> +		break;
> +	case 50:
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	changed = state->flags ^ sock->old_flags;
> +
> +	if (changed & SS_RESET) {
> +		if (state->flags & SS_RESET) {
> +			gpio_set_value(GPIO_RESET, 1);	/* assert reset */
> +			gpio_set_value(GPIO_OUTEN, 1);	/* buffers off */
> +		} else {
> +			gpio_set_value(GPIO_RESET, 0);	/* deassert reset */
> +			gpio_set_value(GPIO_OUTEN, 0);	/* buffers on */
> +			msleep(500);
> +		}
> +	}
> +
> +	sock->old_flags = state->flags;
> +
> +	return 0;
> +}
> +
> +static int xxs1500_pcmcia_get_status(struct pcmcia_socket *skt,
> +				     unsigned int *value)
> +{
> +	unsigned int status;
> +	int i;
> +
> +	status = 0;
> +
> +	/* check carddetects: GPIO[0:1] must both be low */
> +	if (!gpio_get_value(GPIO_CDA) && !gpio_get_value(GPIO_CDB))
> +		status |= SS_DETECT;
> +
> +	/* determine card voltage: GPIO[208:209] binary value */
> +	i = (!!gpio_get_value(GPIO_VSL)) | ((!!gpio_get_value(GPIO_VSH)) << 1);
> +
> +	switch (i) {
> +	case 0:
> +	case 1:
> +	case 2:
> +		status |= SS_3VCARD;	/* 3V card */
> +		break;
> +	case 3:				/* 5V card, unsupported */
> +	default:
> +		status |= SS_XVCARD;	/* treated as unsupported in core */
> +	}
> +
> +	/* GPIO214: low active power switch */
> +	status |= gpio_get_value(GPIO_POWER) ? 0 : SS_POWERON;
> +
> +	/* GPIO204: high-active reset line */
> +	status |= gpio_get_value(GPIO_RESET) ? SS_RESET : SS_READY;
> +
> +	/* other stuff */
> +	status |= gpio_get_value(GPIO_BATTDEAD) ? 0 : SS_BATDEAD;
> +	status |= gpio_get_value(GPIO_BATTWARN) ? 0 : SS_BATWARN;
> +
> +	*value = status;
> +
> +	return 0;
> +}
> +
> +static int xxs1500_pcmcia_sock_init(struct pcmcia_socket *skt)
> +{
> +	gpio_direction_input(GPIO_CDA);
> +	gpio_direction_input(GPIO_CDB);
> +	gpio_direction_input(GPIO_VSL);
> +	gpio_direction_input(GPIO_VSH);
> +	gpio_direction_input(GPIO_BATTDEAD);
> +	gpio_direction_input(GPIO_BATTWARN);
> +	gpio_direction_output(GPIO_RESET, 1);	/* assert reset */
> +	gpio_direction_output(GPIO_OUTEN, 1);	/* disable buffers */
> +	gpio_direction_output(GPIO_POWER, 1);	/* power off */
> +
> +	return 0;
> +}
> +
> +static int xxs1500_pcmcia_sock_suspend(struct pcmcia_socket *skt)
> +{
> +	return 0;
> +}
> +
> +static int au1x00_pcmcia_set_io_map(struct pcmcia_socket *skt,
> +				    struct pccard_io_map *map)
> +{
> +	struct xxs1500_pcmcia_sock *sock = to_xxs_socket(skt);
> +
> +	map->start = (u32)sock->virt_io;
> +	map->stop = map->start + IO_MAP_SIZE;
> +
> +	return 0;
> +}
> +
> +static int au1x00_pcmcia_set_mem_map(struct pcmcia_socket *skt,
> +				     struct pccard_mem_map *map)
> +{
> +	struct xxs1500_pcmcia_sock *sock = to_xxs_socket(skt);
> +
> +	if (map->flags & MAP_ATTRIB)
> +		map->static_start = sock->phys_attr + map->card_start;
> +	else
> +		map->static_start = sock->phys_mem + map->card_start;
> +
> +	return 0;
> +}
> +
> +static struct pccard_operations xxs1500_pcmcia_operations = {
> +	.init			= xxs1500_pcmcia_sock_init,
> +	.suspend		= xxs1500_pcmcia_sock_suspend,
> +	.get_status		= xxs1500_pcmcia_get_status,
> +	.set_socket		= xxs1500_pcmcia_configure,
> +	.set_io_map		= au1x00_pcmcia_set_io_map,
> +	.set_mem_map		= au1x00_pcmcia_set_mem_map,
> +};
> +
> +static int __devinit xxs1500_pcmcia_probe(struct platform_device *pdev)
> +{
> +	struct xxs1500_pcmcia_sock *sock;
> +	struct resource *r;
> +	phys_t physio;
> +	int ret, irq;
> +
> +	sock = kzalloc(sizeof(struct xxs1500_pcmcia_sock), GFP_KERNEL);
> +	if (!sock)
> +		return -ENOMEM;
> +
> +	ret = -ENODEV;
> +
> +	/*
> +	 * pseudo-attr:  The 32bit address of the PCMCIA attribute space
> +	 * for this socket (usually the 36bit address shifted 4 to the
> +	 * right).
> +	 */
> +	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pseudo-attr");
> +	if (!r) {
> +		dev_err(&pdev->dev, "missing 'pseudo-attr' resource!\n");
> +		goto out0;
> +	}
> +	sock->phys_attr = r->start;
> +
> +	/*
> +	 * pseudo-mem:  The 32bit address of the PCMCIA memory space for
> +	 * this socket (usually the 36bit address shifted 4 to the right)
> +	 */
> +	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pseudo-mem");
> +	if (!r) {
> +		dev_err(&pdev->dev, "missing 'pseudo-mem' resource!\n");
> +		goto out0;
> +	}
> +	sock->phys_mem = r->start;
> +
> +	/*
> +	 * pseudo-io:  The 32bit address of the PCMCIA IO space for this
> +	 * socket (usually the 36bit address shifted 4 to the right).
> +	 */
> +	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pseudo-io");
> +	if (!r) {
> +		dev_err(&pdev->dev, "missing 'pseudo-io' resource!\n");
> +		goto out0;
> +	}
> +	sock->phys_io = r->start;
> +
> +
> +	/* for io must remap the full 36bit address (for reference see
> +	 * alchemy/common/setup.c::__fixup_bigphys_addr)
> +	 */
> +	physio = ((phys_t)sock->phys_io) << 4;
> +
> +	/*
> +	 * PCMCIA client drivers use the inb/outb macros to access
> +	 * the IO registers.  Since mips_io_port_base is added
> +	 * to the access address of the mips implementation of
> +	 * inb/outb, we need to subtract it here because we want
> +	 * to access the I/O or MEM address directly, without
> +	 * going through this "mips_io_port_base" mechanism.
> +	 */
> +	sock->virt_io = (void *)(ioremap(physio, IO_MAP_SIZE) -
> +				 mips_io_port_base);
> +
> +	if (!sock->virt_io) {
> +		dev_err(&pdev->dev, "cannot remap IO area\n");
> +		ret = -ENOMEM;
> +		goto out0;
> +	}
> +
> +	sock->socket.ops	= &xxs1500_pcmcia_operations;
> +	sock->socket.owner	= THIS_MODULE;
> +	sock->socket.pci_irq	= gpio_to_irq(GPIO_CARDIRQ);
> +	sock->socket.features	= SS_CAP_STATIC_MAP | SS_CAP_PCCARD;
> +	sock->socket.map_size	= MEM_MAP_SIZE;
> +	sock->socket.io_offset	= (unsigned long)sock->virt_io;
> +	sock->socket.dev.parent	= &pdev->dev;
> +	sock->socket.resource_ops = &pccard_static_ops;
> +
> +	platform_set_drvdata(pdev, sock);
> +
> +	/* setup carddetect irq: use one of the 2 GPIOs as an
> +	 * edge detector.
> +	 */
> +	irq = gpio_to_irq(GPIO_CDA);
> +	set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
> +	ret = request_irq(irq, cdirq, 0, "pcmcia_carddetect", sock);
> +	if (ret) {
> +		dev_err(&pdev->dev, "cannot setup cd irq\n");
> +		goto out1;
> +	}
> +
> +	ret = pcmcia_register_socket(&sock->socket);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to register\n");
> +		goto out2;
> +	}
> +
> +	printk(KERN_INFO "MyCable XXS1500 PCMCIA socket services\n");
> +
> +	return 0;
> +
> +out2:
> +	free_irq(gpio_to_irq(GPIO_CDA), sock);
> +out1:
> +	iounmap((void *)(sock->virt_io + (u32)mips_io_port_base));
> +out0:
> +	kfree(sock);
> +	return ret;
> +}
> +
> +static int __devexit xxs1500_pcmcia_remove(struct platform_device *pdev)
> +{
> +	struct xxs1500_pcmcia_sock *sock = platform_get_drvdata(pdev);
> +
> +	pcmcia_unregister_socket(&sock->socket);
> +	free_irq(gpio_to_irq(GPIO_CDA), sock);
> +	iounmap((void *)(sock->virt_io + (u32)mips_io_port_base));
> +	kfree(sock);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver xxs1500_pcmcia_socket_driver = {
> +	.driver	= {
> +		.name	= "xxs1500_pcmcia",
> +		.owner	= THIS_MODULE,
> +	},
> +	.probe		= xxs1500_pcmcia_probe,
> +	.remove		= __devexit_p(xxs1500_pcmcia_remove),
> +};
> +
> +int __init xxs1500_pcmcia_socket_load(void)
> +{
> +	return platform_driver_register(&xxs1500_pcmcia_socket_driver);
> +}
> +
> +void  __exit xxs1500_pcmcia_socket_unload(void)
> +{
> +	platform_driver_unregister(&xxs1500_pcmcia_socket_driver);
> +}
> +
> +module_init(xxs1500_pcmcia_socket_load);
> +module_exit(xxs1500_pcmcia_socket_unload);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("PCMCIA Socket Services for MyCable XXS1500 systems");
> +MODULE_AUTHOR("Manuel Lauss");
> 

-- 
Best regards, Florian Fainelli
Email: florian@openwrt.org
Web: http://openwrt.org
IRC: [florian] on irc.freenode.net
-------------------------------

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Alchemy: XXS1500 PCMCIA driver rewrite
  2009-09-29 18:50 [PATCH] Alchemy: XXS1500 PCMCIA driver rewrite Manuel Lauss
  2009-09-29 19:46 ` Florian Fainelli
@ 2009-10-02 10:59 ` Wolfram Sang
  2009-10-02 11:15   ` Manuel Lauss
  1 sibling, 1 reply; 10+ messages in thread
From: Wolfram Sang @ 2009-10-02 10:59 UTC (permalink / raw)
  To: Manuel Lauss; +Cc: linux-pcmcia, Linux-MIPS, Florian Fainelli, Manuel Lauss

[-- Attachment #1: Type: text/plain, Size: 416 bytes --]


> Rewritten XXS1500 PCMCIA socket driver, standalone (doesn't
> depend on au1000_generic.c) and added carddetect IRQ support.

I am not familiar with the details here. Why did you choose to drop the generic
au1000-part for this and the other driver?

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Alchemy: XXS1500 PCMCIA driver rewrite
  2009-10-02 10:59 ` Wolfram Sang
@ 2009-10-02 11:15   ` Manuel Lauss
  2009-10-02 12:54     ` Wolfram Sang
  0 siblings, 1 reply; 10+ messages in thread
From: Manuel Lauss @ 2009-10-02 11:15 UTC (permalink / raw)
  To: Wolfram Sang; +Cc: linux-pcmcia, Linux-MIPS, Florian Fainelli, Manuel Lauss

Servus Wolfram,

On Fri, Oct 2, 2009 at 12:59 PM, Wolfram Sang <w.sang@pengutronix.de> wrote:
>
>> Rewritten XXS1500 PCMCIA socket driver, standalone (doesn't
>> depend on au1000_generic.c) and added carddetect IRQ support.
>
> I am not familiar with the details here. Why did you choose to drop the generic
> au1000-part for this and the other driver?

I want to get rid of au1000_generic.[ch] eventually or at least all of
its contents
except the static mapping and resource allocation functions, which are board-
independent.  On the other hand these are so short that I opted to
just duplicate
them into the xxs1500_ss.c and db1xxx_ss.c (other patch) files.  The db1xxx_ss
(for the Alchemy demoboards) is supposed to be an example on how to set up
PCMCIA on Alchemy SoCs.

Danke,
        Manuel Lauss

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Alchemy: XXS1500 PCMCIA driver rewrite
  2009-10-02 11:15   ` Manuel Lauss
@ 2009-10-02 12:54     ` Wolfram Sang
  2009-10-02 14:32       ` Manuel Lauss
  0 siblings, 1 reply; 10+ messages in thread
From: Wolfram Sang @ 2009-10-02 12:54 UTC (permalink / raw)
  To: Manuel Lauss; +Cc: linux-pcmcia, Linux-MIPS, Florian Fainelli, Manuel Lauss

[-- Attachment #1: Type: text/plain, Size: 1084 bytes --]


> >> Rewritten XXS1500 PCMCIA socket driver, standalone (doesn't
> >> depend on au1000_generic.c) and added carddetect IRQ support.
> >
> > I am not familiar with the details here. Why did you choose to drop the generic
> > au1000-part for this and the other driver?
> 
> I want to get rid of au1000_generic.[ch] eventually or at least all of its
> contents except the static mapping and resource allocation functions, which
> are board- independent.  On the other hand these are so short that I opted to
> just duplicate them into the xxs1500_ss.c and db1xxx_ss.c (other patch)
> files.  The db1xxx_ss (for the Alchemy demoboards) is supposed to be an
> example on how to set up PCMCIA on Alchemy SoCs.

Yeah, I saw that you want to remove it, still I don't know why :) Is it feature
incomplete and updating is impossible? Is the concept outdated? Could you
enlighten me on that?

Regards,

   Wolfram

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Alchemy: XXS1500 PCMCIA driver rewrite
  2009-10-02 12:54     ` Wolfram Sang
@ 2009-10-02 14:32       ` Manuel Lauss
  2009-10-03 10:22         ` Wolfram Sang
  0 siblings, 1 reply; 10+ messages in thread
From: Manuel Lauss @ 2009-10-02 14:32 UTC (permalink / raw)
  To: Wolfram Sang; +Cc: linux-pcmcia, Linux-MIPS, Florian Fainelli, Manuel Lauss

On Fri, Oct 2, 2009 at 2:54 PM, Wolfram Sang <w.sang@pengutronix.de> wrote:
>
>> >> Rewritten XXS1500 PCMCIA socket driver, standalone (doesn't
>> >> depend on au1000_generic.c) and added carddetect IRQ support.
>> >
>> > I am not familiar with the details here. Why did you choose to drop the generic
>> > au1000-part for this and the other driver?
>>
>> I want to get rid of au1000_generic.[ch] eventually or at least all of its
>> contents except the static mapping and resource allocation functions, which
>> are board- independent.  On the other hand these are so short that I opted to
>> just duplicate them into the xxs1500_ss.c and db1xxx_ss.c (other patch)
>> files.  The db1xxx_ss (for the Alchemy demoboards) is supposed to be an
>> example on how to set up PCMCIA on Alchemy SoCs.
>
> Yeah, I saw that you want to remove it, still I don't know why :) Is it feature
> incomplete and updating is impossible? Is the concept outdated? Could you
> enlighten me on that?

I started out with the intention to fix its styling issues, add carddetect irq
support, etc.  In the end it was easier to write a quick-and-dirty standalone
full-features socket driver for the DB1200 and extend it to support the
other DB/PB boards. While I was at it I modified my driver for the xxs1500,
that's all.

The only *technical* reason I have is a personal dislike for how the current
one works: it forces every conceivable board to add dozens of cpp macros
for mem/io ranges and gets registered by board-independent code.
Hardly convincing, I know.

        Manuel Lauss

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Alchemy: XXS1500 PCMCIA driver rewrite
  2009-10-02 14:32       ` Manuel Lauss
@ 2009-10-03 10:22         ` Wolfram Sang
  2009-10-03 11:49           ` Manuel Lauss
  0 siblings, 1 reply; 10+ messages in thread
From: Wolfram Sang @ 2009-10-03 10:22 UTC (permalink / raw)
  To: Manuel Lauss; +Cc: linux-pcmcia, Linux-MIPS, Florian Fainelli, Manuel Lauss

[-- Attachment #1: Type: text/plain, Size: 1630 bytes --]

> > Yeah, I saw that you want to remove it, still I don't know why :) Is it feature
> > incomplete and updating is impossible? Is the concept outdated? Could you
> > enlighten me on that?
> 
> I started out with the intention to fix its styling issues, add carddetect irq
> support, etc.  In the end it was easier to write a quick-and-dirty standalone
> full-features socket driver for the DB1200 and extend it to support the
> other DB/PB boards. While I was at it I modified my driver for the xxs1500,
> that's all.

Okay, that explains.

> 
> The only *technical* reason I have is a personal dislike for how the current
> one works: it forces every conceivable board to add dozens of cpp macros
> for mem/io ranges and gets registered by board-independent code.
> Hardly convincing, I know.

Well, you have the (to me) pretty convincing technical argument that your
drivers provide more features and less crashes which is a clear benefit for
users. If we remove the generic au1000-part, then it might even be in the same
amount in LoC. Okay, we lose a bit of maintainability if a bug is found in a
section which was shared among the former users of generic, as it has to be
updated for each of the three drivers, but well... Are there any plans to
convert pb1x00 as well?

Maybe I find time to look a bit more into it, but I can't test anything, of
course, so the more additional comments/test-reports the better.

Regards,

   Wolfram

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Alchemy: XXS1500 PCMCIA driver rewrite
  2009-10-03 10:22         ` Wolfram Sang
@ 2009-10-03 11:49           ` Manuel Lauss
  2009-10-03 14:03             ` Ralf Baechle
  0 siblings, 1 reply; 10+ messages in thread
From: Manuel Lauss @ 2009-10-03 11:49 UTC (permalink / raw)
  To: Wolfram Sang; +Cc: linux-pcmcia, Linux-MIPS, Florian Fainelli, Manuel Lauss

On Sat, Oct 3, 2009 at 12:22 PM, Wolfram Sang <w.sang@pengutronix.de> wrote:
>> > Yeah, I saw that you want to remove it, still I don't know why :) Is it feature
>> > incomplete and updating is impossible? Is the concept outdated? Could you
>> > enlighten me on that?
>>
>> I started out with the intention to fix its styling issues, add carddetect irq
>> support, etc.  In the end it was easier to write a quick-and-dirty standalone
>> full-features socket driver for the DB1200 and extend it to support the
>> other DB/PB boards. While I was at it I modified my driver for the xxs1500,
>> that's all.
>
> Okay, that explains.
>
>>
>> The only *technical* reason I have is a personal dislike for how the current
>> one works: it forces every conceivable board to add dozens of cpp macros
>> for mem/io ranges and gets registered by board-independent code.
>> Hardly convincing, I know.
>
> Well, you have the (to me) pretty convincing technical argument that your
> drivers provide more features and less crashes which is a clear benefit for
> users. If we remove the generic au1000-part, then it might even be in the same
> amount in LoC. Okay, we lose a bit of maintainability if a bug is found in a
> section which was shared among the former users of generic, as it has to be
> updated for each of the three drivers, but well... Are there any plans to
> convert pb1x00 as well?

The new db1xxx_ss.c already supports all boards pb1x00 is supposed to,
except for the PB1000 (the very first Alchemy devboard), which has a
rather awkward carddetect irq scheme, so I kept the au1000_pb1x00.c
for it.  Unfortunately I don't have this board to test on, and *if* there are
any linux users with this board, they choose to remain silent (the driver
hasn't built for it in years, so go figure).  I'd rather get rid of
PB1000 support
altogether...


> Maybe I find time to look a bit more into it, but I can't test anything, of
> course, so the more additional comments/test-reports the better.

Thanks.  As I mentioned, the db1xxx_ss part works on my Db1200/Db1300
boards; I don't have any others to test on.

        Manuel Lauss

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Alchemy: XXS1500 PCMCIA driver rewrite
  2009-10-03 11:49           ` Manuel Lauss
@ 2009-10-03 14:03             ` Ralf Baechle
  2009-10-03 14:36               ` Manuel Lauss
  0 siblings, 1 reply; 10+ messages in thread
From: Ralf Baechle @ 2009-10-03 14:03 UTC (permalink / raw)
  To: Manuel Lauss
  Cc: Wolfram Sang, linux-pcmcia, Linux-MIPS, Florian Fainelli,
	Manuel Lauss

On Sat, Oct 03, 2009 at 01:49:42PM +0200, Manuel Lauss wrote:

> On Sat, Oct 3, 2009 at 12:22 PM, Wolfram Sang <w.sang@pengutronix.de> wrote:
> >> > Yeah, I saw that you want to remove it, still I don't know why :) Is it feature
> >> > incomplete and updating is impossible? Is the concept outdated? Could you
> >> > enlighten me on that?
> >>
> >> I started out with the intention to fix its styling issues, add carddetect irq
> >> support, etc.  In the end it was easier to write a quick-and-dirty standalone
> >> full-features socket driver for the DB1200 and extend it to support the
> >> other DB/PB boards. While I was at it I modified my driver for the xxs1500,
> >> that's all.
> >
> > Okay, that explains.
> >
> >>
> >> The only *technical* reason I have is a personal dislike for how the current
> >> one works: it forces every conceivable board to add dozens of cpp macros
> >> for mem/io ranges and gets registered by board-independent code.
> >> Hardly convincing, I know.
> >
> > Well, you have the (to me) pretty convincing technical argument that your
> > drivers provide more features and less crashes which is a clear benefit for
> > users. If we remove the generic au1000-part, then it might even be in the same
> > amount in LoC. Okay, we lose a bit of maintainability if a bug is found in a
> > section which was shared among the former users of generic, as it has to be
> > updated for each of the three drivers, but well... Are there any plans to
> > convert pb1x00 as well?
> 
> The new db1xxx_ss.c already supports all boards pb1x00 is supposed to,
> except for the PB1000 (the very first Alchemy devboard), which has a
> rather awkward carddetect irq scheme, so I kept the au1000_pb1x00.c
> for it.  Unfortunately I don't have this board to test on, and *if* there are
> any linux users with this board, they choose to remain silent (the driver
> hasn't built for it in years, so go figure).  I'd rather get rid of
> PB1000 support
> altogether...
> 
> 
> > Maybe I find time to look a bit more into it, but I can't test anything, of
> > course, so the more additional comments/test-reports the better.
> 
> Thanks.  As I mentioned, the db1xxx_ss part works on my Db1200/Db1300
> boards; I don't have any others to test on.

Deending on the urgency you assign to these patches I can keep them in
my queue for 2.6.33 and push them upstream for linux-next.

  Ralf

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Alchemy: XXS1500 PCMCIA driver rewrite
  2009-10-03 14:03             ` Ralf Baechle
@ 2009-10-03 14:36               ` Manuel Lauss
  0 siblings, 0 replies; 10+ messages in thread
From: Manuel Lauss @ 2009-10-03 14:36 UTC (permalink / raw)
  To: Ralf Baechle
  Cc: Wolfram Sang, linux-pcmcia, Linux-MIPS, Florian Fainelli,
	Manuel Lauss

Hi Ralf,

> Deending on the urgency you assign to these patches I can keep them in
> my queue for 2.6.33 and push them upstream for linux-next.

No hurry; 2.6.33 is fine. I've fixed a few typos and thinkos in them and will
resend soon.  I'd just like to get these in your queue first, so I can base my
DB1300 work on it.

Thanks!
        Manuel Lauss

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2009-10-03 14:36 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-09-29 18:50 [PATCH] Alchemy: XXS1500 PCMCIA driver rewrite Manuel Lauss
2009-09-29 19:46 ` Florian Fainelli
2009-10-02 10:59 ` Wolfram Sang
2009-10-02 11:15   ` Manuel Lauss
2009-10-02 12:54     ` Wolfram Sang
2009-10-02 14:32       ` Manuel Lauss
2009-10-03 10:22         ` Wolfram Sang
2009-10-03 11:49           ` Manuel Lauss
2009-10-03 14:03             ` Ralf Baechle
2009-10-03 14:36               ` Manuel Lauss

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).