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,156 +32,170 @@ 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);
gpio = PA_DWR;
misc_wr = LUB_MISC_WR;
/* 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_PWR0 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:
switch(state->Vcc){
case 0:
gpio &= ~(GPIO_bit(2) | GPIO_bit(3));
break;
case 33:
gpio = (gpio & ~(GPIO_bit(2) | GPIO_bit(3))) | GPIO_bit(3);
break;
case 50:
gpio = (gpio & ~(GPIO_bit(2) | GPIO_bit(3))) | GPIO_bit(2);
break;
default:
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));
break;
case 120:
gpio = (gpio & ~(GPIO_bit(0) | GPIO_bit(1))) | GPIO_bit(1);
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);
else {
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));
break;
case 33:
misc_wr = (misc_wr & ~(1 << 15)) | (1 << 14);
gpio = (gpio & ~(GPIO_bit(2) | GPIO_bit(3))) | GPIO_bit(2);
break;
case 50:
misc_wr = (misc_wr & ~(1 << 15)) | (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) {
sa1111_pcmcia_configure_socket(skt, state);
LUB_MISC_WR = misc_wr;
PA_DWR = gpio;
}
if (ret > 0) {
ret = 0;
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
/*
* 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.
*/
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! */
((socket_state_t *)state)->Vcc = 50;
((socket_state_t *)state)->Vpp = 50;
goto again;
}
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
}
local_irq_restore(flags);
return ret;
return ret;
}
static struct pcmcia_low_level lubbock_pcmcia_ops = {
......@@ -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