Commit 40878b17 authored by Russell King's avatar Russell King

[ARM] Fix lubbock PCMCIA driver.

- access SA1111 GPIO using sa1111_set_io functions.
- access Lubbock misc register using lubbock_set_misc_wr
- fix CF voltage selection.
- don't fiddle with PCMCIA voltage selection when selecting CF
  voltage.
- wait for the voltage switches to stabilise before reading the
  new card state.
parent 7f0f8627
......@@ -20,9 +20,11 @@
#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 "sa1111_generic.h"
......@@ -30,14 +32,10 @@ static int
lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
const socket_state_t *state)
{
unsigned long flags, gpio, misc_wr;
int ret = 1;
struct pcmcia_state new_state;
local_irq_save(flags);
unsigned int pa_dwr_mask, pa_dwr_set, misc_mask, misc_set;
int ret = 0;
gpio = PA_DWR;
misc_wr = LUB_MISC_WR;
pa_dwr_mask = pa_dwr_set = misc_mask = misc_set = 0;
/* Lubbock uses the Maxim MAX1602, with the following connections:
*
......@@ -61,7 +59,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
* A0VPP GND VPP is not connected
* A1VPP GND VPP is not connected
* A0VCC S1_PWR0 MISC_WR<14>
* A1VCC S1_PWR0 MISC_WR<15>
* A1VCC S1_PWR1 MISC_WR<15>
* VX VCC
* VY +3.3V
* 12IN GND VPP is not connected
......@@ -69,116 +67,134 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
*
*/
again:
switch(skt->nr){
again:
switch (skt->nr) {
case 0:
pa_dwr_mask = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3;
switch(state->Vcc){
case 0:
gpio &= ~(GPIO_bit(2) | GPIO_bit(3));
switch (state->Vcc) {
case 0: /* Hi-Z */
break;
case 33:
gpio = (gpio & ~(GPIO_bit(2) | GPIO_bit(3))) | GPIO_bit(3);
case 33: /* VY */
pa_dwr_set |= GPIO_A3;
break;
case 50:
gpio = (gpio & ~(GPIO_bit(2) | GPIO_bit(3))) | GPIO_bit(2);
case 50: /* VX */
pa_dwr_set |= GPIO_A2;
break;
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, state->Vcc);
printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
__FUNCTION__, state->Vcc);
ret = -1;
}
switch(state->Vpp){
case 0:
gpio &= ~(GPIO_bit(0) | GPIO_bit(1));
switch (state->Vpp) {
case 0: /* Hi-Z */
break;
case 120:
gpio = (gpio & ~(GPIO_bit(0) | GPIO_bit(1))) | GPIO_bit(1);
case 120: /* 12IN */
pa_dwr_set |= GPIO_A1;
break;
default:
/* REVISIT: I'm not sure about this? Is this correct?
Is it always safe or do we have potential problems
with bogus combinations of Vcc and Vpp settings? */
if(state->Vpp == state->Vcc)
gpio = (gpio & ~(GPIO_bit(0) | GPIO_bit(1))) | GPIO_bit(0);
default: /* VCC */
if (state->Vpp == state->Vcc)
pa_dwr_set |= GPIO_A0;
else {
printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__, state->Vpp);
printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
__FUNCTION__, state->Vpp);
ret = -1;
break;
}
}
break;
case 1:
switch(state->Vcc){
case 0:
misc_wr &= ~((1 << 15) | (1 << 14));
misc_mask = (1 << 15) | (1 << 14);
switch (state->Vcc) {
case 0: /* Hi-Z */
break;
case 33:
misc_wr = (misc_wr & ~(1 << 15)) | (1 << 14);
gpio = (gpio & ~(GPIO_bit(2) | GPIO_bit(3))) | GPIO_bit(2);
case 33: /* VY */
misc_set |= 1 << 15;
break;
case 50:
misc_wr = (misc_wr & ~(1 << 15)) | (1 << 14);
case 50: /* VX */
misc_set |= 1 << 14;
break;
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, state->Vcc);
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);
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) {
sa1111_pcmcia_configure_socket(skt, state);
LUB_MISC_WR = misc_wr;
PA_DWR = gpio;
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 (ret > 0) {
ret = 0;
#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.
* 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 (state->Vcc == 33 && !new_state.vs_3v && !new_state.vs_Xv) {
/* Switch to 5V, Configure socket with 5V voltage */
PA_DWR &= ~(GPIO_bit(0) | GPIO_bit(1) | GPIO_bit(2) | GPIO_bit(3));
PA_DDR &= ~(GPIO_bit(0) | GPIO_bit(1) | GPIO_bit(2) | GPIO_bit(3));
/* 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! */
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
}
#endif
local_irq_restore(flags);
return ret;
}
......@@ -196,7 +212,7 @@ static struct pcmcia_low_level lubbock_pcmcia_ops = {
#include "pxa2xx_base.h"
int __init pcmcia_lubbock_init(struct device *dev)
int __init pcmcia_lubbock_init(struct sa1111_dev *sadev)
{
int ret = -ENODEV;
......@@ -205,16 +221,15 @@ int __init pcmcia_lubbock_init(struct device *dev)
* Set GPIO_A<3:0> to be outputs for the MAX1600,
* and switch to standby mode.
*/
PA_DWR = 0;
PA_DDR = 0;
PA_SDR = 0;
PA_SSR = 0;
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. */
LUB_MISC_WR &= ~(GPIO_bit(15) | GPIO_bit(14));
lubbock_set_misc_wr((1 << 15) | (1 << 14), 0);
dev->platform_data = &lubbock_pcmcia_ops;
ret = pxa2xx_drv_pcmcia_probe(dev);
sadev->dev.platform_data = &lubbock_pcmcia_ops;
ret = pxa2xx_drv_pcmcia_probe(&sadev->dev);
}
return ret;
......
......@@ -149,7 +149,7 @@ static int pcmcia_probe(struct sa1111_dev *dev)
pcmcia_jornada720_init(&dev->dev);
#endif
#ifdef CONFIG_ARCH_LUBBOCK
pcmcia_lubbock_init(&dev->dev);
pcmcia_lubbock_init(dev);
#endif
#ifdef CONFIG_ASSABET_NEPONSET
pcmcia_neponset_init(dev);
......
......@@ -10,6 +10,6 @@ extern void sa1111_pcmcia_socket_suspend(struct soc_pcmcia_socket *);
extern int pcmcia_badge4_init(struct device *);
extern int pcmcia_jornada720_init(struct device *);
extern int pcmcia_lubbock_init(struct device *);
extern int pcmcia_lubbock_init(struct sa1111_dev *);
extern int pcmcia_neponset_init(struct sa1111_dev *);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment