mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-31 05:54:26 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			236 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			236 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 76a102bd5c9d792db19c6c72eafdecea0311a0c9 Mon Sep 17 00:00:00 2001
 | |
| From: Craig Hughes <craig@gumstix.com>
 | |
| Date: Fri, 30 Oct 2009 14:16:27 -0400
 | |
| Subject: [PATCH] [ARM] pxa: Gumstix Verdex PCMCIA support
 | |
| 
 | |
| Needed for the Libertas CS wireless device.
 | |
| 
 | |
| Signed-off-by: Bobby Powers <bobbypowers@gmail.com>
 | |
| ---
 | |
|  drivers/pcmcia/Kconfig          |    3 +-
 | |
|  drivers/pcmcia/Makefile         |    3 +
 | |
|  drivers/pcmcia/pxa2xx_gumstix.c |  194 +++++++++++++++++++++++++++++++++++++++
 | |
|  3 files changed, 199 insertions(+), 1 deletions(-)
 | |
|  create mode 100644 drivers/pcmcia/pxa2xx_gumstix.c
 | |
| 
 | |
| --- a/drivers/pcmcia/Kconfig
 | |
| +++ b/drivers/pcmcia/Kconfig
 | |
| @@ -215,7 +215,7 @@ config PCMCIA_PXA2XX
 | |
|  	depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \
 | |
|  		    || MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \
 | |
|  		    || ARCOM_PCMCIA || ARCH_PXA_ESERIES || MACH_STARGATE2 \
 | |
| -		    || MACH_VPAC270 || MACH_BALLOON3)
 | |
| +		    || MACH_VPAC270 || MACH_BALLOON3 || ARCH_GUMSTIX)
 | |
|  	select PCMCIA_SOC_COMMON
 | |
|  	help
 | |
|  	  Say Y here to include support for the PXA2xx PCMCIA controller
 | |
| --- a/drivers/pcmcia/Makefile
 | |
| +++ b/drivers/pcmcia/Makefile
 | |
| @@ -71,6 +71,9 @@ pxa2xx-obj-$(CONFIG_MACH_STARGATE2)		+=
 | |
|  pxa2xx-obj-$(CONFIG_MACH_VPAC270)		+= pxa2xx_vpac270.o
 | |
|  pxa2xx-obj-$(CONFIG_MACH_BALLOON3)		+= pxa2xx_balloon3.o
 | |
|  
 | |
| +pxa2xx-obj-$(CONFIG_MACH_GUMSTIX_VERDEX)	+= pxa2xx_cs.o
 | |
| +pxa2xx_cs-objs					:= pxa2xx_gumstix.o
 | |
| +
 | |
|  obj-$(CONFIG_PCMCIA_PXA2XX)			+= pxa2xx_base.o $(pxa2xx-obj-y)
 | |
|  
 | |
|  obj-$(CONFIG_PCMCIA_XXS1500)			+= xxs1500_ss.o
 | |
| --- /dev/null
 | |
| +++ b/drivers/pcmcia/pxa2xx_gumstix.c
 | |
| @@ -0,0 +1,194 @@
 | |
| +/*
 | |
| + * linux/drivers/pcmcia/pxa2xx_gumstix.c
 | |
| + *
 | |
| + * Gumstix PCMCIA specific routines. Based on Mainstone
 | |
| + *
 | |
| + * Copyright 2004, Craig Hughes <craig@gumstix.com>
 | |
| + *
 | |
| + * This program is free software; you can redistribute it and/or modify
 | |
| + * it under the terms of the GNU General Public License version 2 as
 | |
| + * published by the Free Software Foundation.
 | |
| + */
 | |
| +
 | |
| +#include <linux/module.h>
 | |
| +#include <linux/init.h>
 | |
| +#include <linux/kernel.h>
 | |
| +#include <linux/errno.h>
 | |
| +#include <linux/interrupt.h>
 | |
| +#include <linux/irq.h>
 | |
| +#include <linux/gpio.h>
 | |
| +
 | |
| +#include <linux/delay.h>
 | |
| +#include <linux/platform_device.h>
 | |
| +
 | |
| +#include <pcmcia/ss.h>
 | |
| +
 | |
| +#include <mach/hardware.h>
 | |
| +#include <asm/mach-types.h>
 | |
| +
 | |
| +#ifdef CONFIG_MACH_GUMSTIX_VERDEX
 | |
| +#include <mach/pxa27x.h>
 | |
| +#else
 | |
| +#include <mach/pxa27x.h>
 | |
| +#endif
 | |
| +
 | |
| +#include <asm/io.h>
 | |
| +#include <mach/gpio.h>
 | |
| +#include <mach/gumstix.h>
 | |
| +#include "soc_common.h"
 | |
| +
 | |
| +#define ARRAY_AND_SIZE(x)	(x), ARRAY_SIZE(x)
 | |
| +
 | |
| +static struct pcmcia_irqs gumstix_pcmcia_irqs0[] = {
 | |
| +	{ 0, GUMSTIX_S0_nCD_IRQ,	"CF0 nCD"     },
 | |
| +	{ 0, GUMSTIX_S0_nSTSCHG_IRQ,	"CF0 nSTSCHG" },
 | |
| +};
 | |
| +
 | |
| +static struct pcmcia_irqs gumstix_pcmcia_irqs1[] = {
 | |
| +	{ 1, GUMSTIX_S1_nCD_IRQ,	"CF1 nCD"     },
 | |
| +	{ 1, GUMSTIX_S1_nSTSCHG_IRQ,	"CF1 nSTSCHG" },
 | |
| +};
 | |
| +
 | |
| +
 | |
| +static int net_cf_vx_mode = 0;
 | |
| +
 | |
| +static int gumstix_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 | |
| +{
 | |
| +/* Note: The verdex_pcmcia_pin_config is moved to gumstix_verdex.c in order to use mfp_pxa2xx_config
 | |
| +   for board-specific pin configuration instead of the old deprecated pxa_gpio_mode function.  Thus,
 | |
| +   only the IRQ init is still needed to be done here. */
 | |
| +	skt->irq = (skt->nr == 0) ? ((net_cf_vx_mode == 0) ? GUMSTIX_S0_PRDY_nBSY_IRQ : GUMSTIX_S0_PRDY_nBSY_OLD_IRQ) : GUMSTIX_S1_PRDY_nBSY_IRQ;
 | |
| +
 | |
| +	return (skt->nr == 0) ? soc_pcmcia_request_irqs(skt, gumstix_pcmcia_irqs0, ARRAY_SIZE(gumstix_pcmcia_irqs0)) :
 | |
| +				soc_pcmcia_request_irqs(skt, gumstix_pcmcia_irqs1, ARRAY_SIZE(gumstix_pcmcia_irqs1));
 | |
| +}
 | |
| +
 | |
| +static void gumstix_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
 | |
| +{
 | |
| +	if(skt->nr == 0)
 | |
| +	{
 | |
| +		soc_pcmcia_free_irqs(skt, gumstix_pcmcia_irqs0, ARRAY_SIZE(gumstix_pcmcia_irqs0));
 | |
| +	} else {
 | |
| +		soc_pcmcia_free_irqs(skt, gumstix_pcmcia_irqs1, ARRAY_SIZE(gumstix_pcmcia_irqs1));
 | |
| +	}
 | |
| +
 | |
| +	if (net_cf_vx_mode) {
 | |
| +	    	gpio_free(GPIO_GUMSTIX_CF_OLD_RESET);
 | |
| +	} else {
 | |
| +		gpio_free(GPIO_GUMSTIX_CF_RESET);
 | |
| +	}
 | |
| +
 | |
| +}
 | |
| +
 | |
| +static void gumstix_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
 | |
| +				    struct pcmcia_state *state)
 | |
| +{
 | |
| +	unsigned int cd, prdy_nbsy, nbvd1;
 | |
| +	if(skt->nr == 0)
 | |
| +	{
 | |
| +		cd = GPIO_GUMSTIX_nCD_0;
 | |
| +		if(net_cf_vx_mode)
 | |
| +			prdy_nbsy = GPIO_GUMSTIX_PRDY_nBSY_0_OLD;
 | |
| +		else
 | |
| +			prdy_nbsy = GPIO_GUMSTIX_PRDY_nBSY_0;
 | |
| +		nbvd1 = GPIO_GUMSTIX_nBVD1_0;
 | |
| +	} else {
 | |
| +		cd = GPIO_GUMSTIX_nCD_1;
 | |
| +		prdy_nbsy = GPIO_GUMSTIX_PRDY_nBSY_1;
 | |
| +		nbvd1 = GPIO_GUMSTIX_nBVD1_1;
 | |
| +	}
 | |
| +	state->detect = !(GPLR(cd) & GPIO_bit(cd));
 | |
| +	state->ready  = !!(GPLR(prdy_nbsy) & GPIO_bit(prdy_nbsy));
 | |
| +	state->bvd1   = !!(GPLR(nbvd1) & GPIO_bit(nbvd1));
 | |
| +	state->bvd2   = 1;
 | |
| +	state->vs_3v  = 0;
 | |
| +	state->vs_Xv  = 0;
 | |
| +	state->wrprot = 0;
 | |
| +}
 | |
| +
 | |
| +static int gumstix_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
 | |
| +				       const socket_state_t *state)
 | |
| +{
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static void gumstix_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
 | |
| +{
 | |
| +	if(skt->nr) {
 | |
| +		soc_pcmcia_enable_irqs(skt, gumstix_pcmcia_irqs0, ARRAY_SIZE(gumstix_pcmcia_irqs0));
 | |
| +	} else {
 | |
| +		soc_pcmcia_enable_irqs(skt, gumstix_pcmcia_irqs1, ARRAY_SIZE(gumstix_pcmcia_irqs1));
 | |
| +	}
 | |
| +}
 | |
| +
 | |
| +static void gumstix_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
 | |
| +{
 | |
| +	if(skt->nr) {
 | |
| +		soc_pcmcia_disable_irqs(skt, gumstix_pcmcia_irqs0, ARRAY_SIZE(gumstix_pcmcia_irqs0));
 | |
| +	} else {
 | |
| +		soc_pcmcia_disable_irqs(skt, gumstix_pcmcia_irqs1, ARRAY_SIZE(gumstix_pcmcia_irqs1));
 | |
| +	}
 | |
| +}
 | |
| +
 | |
| +static struct pcmcia_low_level gumstix_pcmcia_ops = {
 | |
| +	.owner			= THIS_MODULE,
 | |
| +	.hw_init		= gumstix_pcmcia_hw_init,
 | |
| +	.hw_shutdown		= gumstix_pcmcia_hw_shutdown,
 | |
| +	.socket_state		= gumstix_pcmcia_socket_state,
 | |
| +	.configure_socket	= gumstix_pcmcia_configure_socket,
 | |
| +	.socket_init		= gumstix_pcmcia_socket_init,
 | |
| +	.socket_suspend		= gumstix_pcmcia_socket_suspend,
 | |
| +	.nr			= 2,
 | |
| +};
 | |
| +
 | |
| +static struct platform_device *gumstix_pcmcia_device;
 | |
| +
 | |
| +extern int __init gumstix_get_cf_cards(void);
 | |
| +
 | |
| +#ifdef CONFIG_MACH_GUMSTIX_VERDEX
 | |
| +extern int __init gumstix_check_if_netCF_vx(void);
 | |
| +#endif
 | |
| +
 | |
| +static int __init gumstix_pcmcia_init(void)
 | |
| +{
 | |
| +	int ret;
 | |
| +
 | |
| +#ifdef CONFIG_MACH_GUMSTIX_VERDEX
 | |
| +	net_cf_vx_mode = gumstix_check_if_netCF_vx();
 | |
| +#endif
 | |
| +
 | |
| +	gumstix_pcmcia_ops.nr = gumstix_get_cf_cards();
 | |
| +
 | |
| +	gumstix_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
 | |
| +	if (!gumstix_pcmcia_device)
 | |
| +		return -ENOMEM;
 | |
| +
 | |
| +	ret = platform_device_add_data(gumstix_pcmcia_device, &gumstix_pcmcia_ops,
 | |
| +				       sizeof(gumstix_pcmcia_ops));
 | |
| +
 | |
| +	if (ret == 0) {
 | |
| +		printk(KERN_INFO "Registering gumstix PCMCIA interface.\n");
 | |
| +		ret = platform_device_add(gumstix_pcmcia_device);
 | |
| +	}
 | |
| +
 | |
| +	if (ret)
 | |
| +		platform_device_put(gumstix_pcmcia_device);
 | |
| +
 | |
| +	return ret;
 | |
| +}
 | |
| +
 | |
| +static void __exit gumstix_pcmcia_exit(void)
 | |
| +{
 | |
| +	/*
 | |
| +	 * This call is supposed to free our gumstix_pcmcia_device.
 | |
| +	 * Unfortunately platform_device don't have a free method, and
 | |
| +	 * we can't assume it's free of any reference at this point so we
 | |
| +	 * can't free it either.
 | |
| +	 */
 | |
| +	platform_device_unregister(gumstix_pcmcia_device);
 | |
| +}
 | |
| +
 | |
| +fs_initcall(gumstix_pcmcia_init);
 | |
| +module_exit(gumstix_pcmcia_exit);
 | |
| +
 | |
| +MODULE_LICENSE("GPL");
 |