Skip to content

Commit

Permalink
[PCMCIA] e740 PCMCIA socket driver.
Browse files Browse the repository at this point in the history
This patch adds the platform specific support needed to control the
PCMCIA hardware on the Toshiba e740.

Signed-off-by: Ian Molton <[email protected]>
  • Loading branch information
Ian Molton committed Dec 15, 2008
1 parent b1ae1b7 commit e38a970
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 1 deletion.
2 changes: 1 addition & 1 deletion drivers/pcmcia/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ config PCMCIA_PXA2XX
depends on ARM && ARCH_PXA && PCMCIA
depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \
|| MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \
|| ARCH_VIPER)
|| ARCH_VIPER || ARCH_PXA_ESERIES)
help
Say Y here to include support for the PXA2xx PCMCIA controller

Expand Down
1 change: 1 addition & 0 deletions drivers/pcmcia/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -72,5 +72,6 @@ pxa2xx-obj-$(CONFIG_ARCH_VIPER) += pxa2xx_viper.o
pxa2xx-obj-$(CONFIG_TRIZEPS_PCMCIA) += pxa2xx_trizeps4.o
pxa2xx-obj-$(CONFIG_MACH_PALMTX) += pxa2xx_palmtx.o
pxa2xx-obj-$(CONFIG_MACH_PALMLD) += pxa2xx_palmld.o
pxa2xx-obj-$(CONFIG_MACH_E740) += pxa2xx_e740.o

obj-$(CONFIG_PCMCIA_PXA2XX) += pxa2xx_core.o $(pxa2xx-obj-y)
176 changes: 176 additions & 0 deletions drivers/pcmcia/pxa2xx_e740.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/*
* Toshiba e740 PCMCIA specific routines.
*
* (c) 2004 Ian Molton <[email protected]>
*
* 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/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>

#include <mach/hardware.h>
#include <mach/pxa-regs.h>
#include <mach/eseries-gpio.h>

#include <asm/irq.h>
#include <asm/mach-types.h>

#include "soc_common.h"

static struct pcmcia_irqs cd_irqs[] = {
{
.sock = 0,
.irq = IRQ_GPIO(GPIO_E740_PCMCIA_CD0),
.str = "CF card detect"
},
{
.sock = 1,
.irq = IRQ_GPIO(GPIO_E740_PCMCIA_CD1),
.str = "Wifi switch"
},
};

static int e740_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
{
skt->irq = skt->nr == 0 ? IRQ_GPIO(GPIO_E740_PCMCIA_RDY0) :
IRQ_GPIO(GPIO_E740_PCMCIA_RDY1);

return soc_pcmcia_request_irqs(skt, &cd_irqs[skt->nr], 1);
}

/*
* Release all resources.
*/
static void e740_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
{
soc_pcmcia_free_irqs(skt, &cd_irqs[skt->nr], 1);
}

static void e740_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
struct pcmcia_state *state)
{
if (skt->nr == 0) {
state->detect = gpio_get_value(GPIO_E740_PCMCIA_CD0) ? 0 : 1;
state->ready = gpio_get_value(GPIO_E740_PCMCIA_RDY0) ? 1 : 0;
} else {
state->detect = gpio_get_value(GPIO_E740_PCMCIA_CD1) ? 0 : 1;
state->ready = gpio_get_value(GPIO_E740_PCMCIA_RDY1) ? 1 : 0;
}

state->vs_3v = 1;
state->bvd1 = 1;
state->bvd2 = 1;
state->wrprot = 0;
state->vs_Xv = 0;
}

static int e740_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
const socket_state_t *state)
{
if (state->flags & SS_RESET) {
if (skt->nr == 0)
gpio_set_value(GPIO_E740_PCMCIA_RST0, 1);
else
gpio_set_value(GPIO_E740_PCMCIA_RST1, 1);
} else {
if (skt->nr == 0)
gpio_set_value(GPIO_E740_PCMCIA_RST0, 0);
else
gpio_set_value(GPIO_E740_PCMCIA_RST1, 0);
}

switch (state->Vcc) {
case 0: /* Socket off */
if (skt->nr == 0)
gpio_set_value(GPIO_E740_PCMCIA_PWR0, 0);
else
gpio_set_value(GPIO_E740_PCMCIA_PWR1, 1);
break;
case 50:
case 33: /* socket on */
if (skt->nr == 0)
gpio_set_value(GPIO_E740_PCMCIA_PWR0, 1);
else
gpio_set_value(GPIO_E740_PCMCIA_PWR1, 0);
break;
default:
printk(KERN_ERR "e740_cs: Unsupported Vcc: %d\n", state->Vcc);
}

return 0;
}

/*
* Enable card status IRQs on (re-)initialisation. This can
* be called at initialisation, power management event, or
* pcmcia event.
*/
static void e740_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
{
soc_pcmcia_enable_irqs(skt, cd_irqs, ARRAY_SIZE(cd_irqs));
}

/*
* Disable card status IRQs on suspend.
*/
static void e740_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
{
soc_pcmcia_disable_irqs(skt, cd_irqs, ARRAY_SIZE(cd_irqs));
}

static struct pcmcia_low_level e740_pcmcia_ops = {
.owner = THIS_MODULE,
.hw_init = e740_pcmcia_hw_init,
.hw_shutdown = e740_pcmcia_hw_shutdown,
.socket_state = e740_pcmcia_socket_state,
.configure_socket = e740_pcmcia_configure_socket,
.socket_init = e740_pcmcia_socket_init,
.socket_suspend = e740_pcmcia_socket_suspend,
.nr = 2,
};

static struct platform_device *e740_pcmcia_device;

static int __init e740_pcmcia_init(void)
{
int ret;

if (!machine_is_e740())
return -ENODEV;

e740_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
if (!e740_pcmcia_device)
return -ENOMEM;

ret = platform_device_add_data(e740_pcmcia_device, &e740_pcmcia_ops,
sizeof(e740_pcmcia_ops));

if (!ret)
ret = platform_device_add(e740_pcmcia_device);

if (ret)
platform_device_put(e740_pcmcia_device);

return ret;
}

static void __exit e740_pcmcia_exit(void)
{
platform_device_unregister(e740_pcmcia_device);
}

module_init(e740_pcmcia_init);
module_exit(e740_pcmcia_exit);

MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Ian Molton <[email protected]>");
MODULE_ALIAS("platform:pxa2xx-pcmcia");
MODULE_DESCRIPTION("e740 PCMCIA platform support");

0 comments on commit e38a970

Please sign in to comment.