diff options
Diffstat (limited to 'drivers/pcmcia/pxa2xx_lubbock.c')
-rw-r--r-- | drivers/pcmcia/pxa2xx_lubbock.c | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/drivers/pcmcia/pxa2xx_lubbock.c b/drivers/pcmcia/pxa2xx_lubbock.c new file mode 100644 index 00000000000..fd1f691c7c2 --- /dev/null +++ b/drivers/pcmcia/pxa2xx_lubbock.c @@ -0,0 +1,269 @@ +/* + * linux/drivers/pcmcia/pxa2xx_lubbock.c + * + * Author: George Davis + * Created: Jan 10, 2002 + * Copyright: MontaVista Software Inc. + * + * 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. + * + * Originally based upon linux/drivers/pcmcia/sa1100_neponset.c + * + * Lubbock PCMCIA specific routines. + * + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/delay.h> + +#include <asm/hardware.h> +#include <asm/hardware/sa1111.h> +#include <asm/mach-types.h> +#include <asm/arch/pxa-regs.h> +#include <asm/arch/lubbock.h> + +#include "sa1111_generic.h" + +static int +lubbock_pcmcia_hw_init(struct soc_pcmcia_socket *skt) +{ + /* + * Setup default state of GPIO outputs + * before we enable them as outputs. + */ + GPSR(GPIO48_nPOE) = + GPIO_bit(GPIO48_nPOE) | + GPIO_bit(GPIO49_nPWE) | + GPIO_bit(GPIO50_nPIOR) | + GPIO_bit(GPIO51_nPIOW) | + GPIO_bit(GPIO52_nPCE_1) | + GPIO_bit(GPIO53_nPCE_2); + + pxa_gpio_mode(GPIO48_nPOE_MD); + pxa_gpio_mode(GPIO49_nPWE_MD); + pxa_gpio_mode(GPIO50_nPIOR_MD); + pxa_gpio_mode(GPIO51_nPIOW_MD); + pxa_gpio_mode(GPIO52_nPCE_1_MD); + pxa_gpio_mode(GPIO53_nPCE_2_MD); + pxa_gpio_mode(GPIO54_pSKTSEL_MD); + pxa_gpio_mode(GPIO55_nPREG_MD); + pxa_gpio_mode(GPIO56_nPWAIT_MD); + pxa_gpio_mode(GPIO57_nIOIS16_MD); + + return sa1111_pcmcia_hw_init(skt); +} + +static int +lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, + const socket_state_t *state) +{ + unsigned int pa_dwr_mask, pa_dwr_set, misc_mask, misc_set; + int ret = 0; + + pa_dwr_mask = pa_dwr_set = misc_mask = misc_set = 0; + + /* Lubbock uses the Maxim MAX1602, with the following connections: + * + * Socket 0 (PCMCIA): + * MAX1602 Lubbock Register + * Pin Signal + * ----- ------- ---------------------- + * A0VPP S0_PWR0 SA-1111 GPIO A<0> + * A1VPP S0_PWR1 SA-1111 GPIO A<1> + * A0VCC S0_PWR2 SA-1111 GPIO A<2> + * A1VCC S0_PWR3 SA-1111 GPIO A<3> + * VX VCC + * VY +3.3V + * 12IN +12V + * CODE +3.3V Cirrus Code, CODE = High (VY) + * + * Socket 1 (CF): + * MAX1602 Lubbock Register + * Pin Signal + * ----- ------- ---------------------- + * A0VPP GND VPP is not connected + * A1VPP GND VPP is not connected + * A0VCC S1_PWR0 MISC_WR<14> + * A1VCC S1_PWR1 MISC_WR<15> + * VX VCC + * VY +3.3V + * 12IN GND VPP is not connected + * CODE +3.3V Cirrus Code, CODE = High (VY) + * + */ + + again: + switch (skt->nr) { + case 0: + pa_dwr_mask = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3; + + switch (state->Vcc) { + case 0: /* Hi-Z */ + break; + + case 33: /* VY */ + pa_dwr_set |= GPIO_A3; + break; + + case 50: /* VX */ + pa_dwr_set |= GPIO_A2; + break; + + default: + printk(KERN_ERR "%s(): unrecognized Vcc %u\n", + __FUNCTION__, state->Vcc); + ret = -1; + } + + switch (state->Vpp) { + case 0: /* Hi-Z */ + break; + + case 120: /* 12IN */ + pa_dwr_set |= GPIO_A1; + break; + + default: /* VCC */ + if (state->Vpp == state->Vcc) + pa_dwr_set |= GPIO_A0; + else { + printk(KERN_ERR "%s(): unrecognized Vpp %u\n", + __FUNCTION__, state->Vpp); + ret = -1; + break; + } + } + break; + + case 1: + misc_mask = (1 << 15) | (1 << 14); + + switch (state->Vcc) { + case 0: /* Hi-Z */ + break; + + case 33: /* VY */ + misc_set |= 1 << 15; + break; + + case 50: /* VX */ + misc_set |= 1 << 14; + break; + + default: + printk(KERN_ERR "%s(): unrecognized Vcc %u\n", + __FUNCTION__, state->Vcc); + ret = -1; + break; + } + + if (state->Vpp != state->Vcc && state->Vpp != 0) { + printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", + __FUNCTION__, state->Vpp); + ret = -1; + break; + } + break; + + default: + ret = -1; + } + + if (ret == 0) + ret = sa1111_pcmcia_configure_socket(skt, state); + + if (ret == 0) { + lubbock_set_misc_wr(misc_mask, misc_set); + sa1111_set_io(SA1111_DEV(skt->dev), pa_dwr_mask, pa_dwr_set); + } + +#if 1 + if (ret == 0 && state->Vcc == 33) { + struct pcmcia_state new_state; + + /* + * HACK ALERT: + * We can't sense the voltage properly on Lubbock before + * actually applying some power to the socket (catch 22). + * Resense the socket Voltage Sense pins after applying + * socket power. + * + * Note: It takes about 2.5ms for the MAX1602 VCC output + * to rise. + */ + mdelay(3); + + sa1111_pcmcia_socket_state(skt, &new_state); + + if (!new_state.vs_3v && !new_state.vs_Xv) { + /* + * Switch to 5V, Configure socket with 5V voltage + */ + lubbock_set_misc_wr(misc_mask, 0); + sa1111_set_io(SA1111_DEV(skt->dev), pa_dwr_mask, 0); + + /* + * It takes about 100ms to turn off Vcc. + */ + mdelay(100); + + /* + * We need to hack around the const qualifier as + * well to keep this ugly workaround localized and + * not force it to the rest of the code. Barf bags + * avaliable in the seat pocket in front of you! + */ + ((socket_state_t *)state)->Vcc = 50; + ((socket_state_t *)state)->Vpp = 50; + goto again; + } + } +#endif + + return ret; +} + +static struct pcmcia_low_level lubbock_pcmcia_ops = { + .owner = THIS_MODULE, + .hw_init = lubbock_pcmcia_hw_init, + .hw_shutdown = sa1111_pcmcia_hw_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .configure_socket = lubbock_pcmcia_configure_socket, + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, + .first = 0, + .nr = 2, +}; + +#include "pxa2xx_base.h" + +int __init pcmcia_lubbock_init(struct sa1111_dev *sadev) +{ + int ret = -ENODEV; + + if (machine_is_lubbock()) { + /* + * Set GPIO_A<3:0> to be outputs for the MAX1600, + * and switch to standby mode. + */ + sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0); + sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0); + sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0); + + /* Set CF Socket 1 power to standby mode. */ + lubbock_set_misc_wr((1 << 15) | (1 << 14), 0); + + sadev->dev.platform_data = &lubbock_pcmcia_ops; + ret = pxa2xx_drv_pcmcia_probe(&sadev->dev); + } + + return ret; +} + +MODULE_LICENSE("GPL"); |