Commit ce1e6b9f authored by Russell King's avatar Russell King

Fix up SA1100 PCMCIA for IRQ handling changes.

Major SA1100 generic DMA cleanup.
Fix suspend/resume bugs.
Provide and use new SA1111 generic driver for SA1111-based devices.
parent e51b59f6
...@@ -24,5 +24,6 @@ if [ "$CONFIG_PCMCIA" != "n" ]; then ...@@ -24,5 +24,6 @@ if [ "$CONFIG_PCMCIA" != "n" ]; then
dep_tristate ' HD64465 host bridge support' CONFIG_HD64465_PCMCIA $CONFIG_PCMCIA dep_tristate ' HD64465 host bridge support' CONFIG_HD64465_PCMCIA $CONFIG_PCMCIA
fi fi
fi fi
dep_tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA
endmenu endmenu
...@@ -62,22 +62,24 @@ endif ...@@ -62,22 +62,24 @@ endif
obj-$(CONFIG_PCMCIA_SA1100) += sa1100_cs.o obj-$(CONFIG_PCMCIA_SA1100) += sa1100_cs.o
sa1100_cs-objs-y := sa1100_generic.o sa1100_cs-objs-y := sa1100_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSY) += sa1100_adsbitsy.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_ASSABET) += sa1100_assabet.o sa1100_cs-objs-$(CONFIG_SA1100_ASSABET) += sa1100_assabet.o
sa1100_cs-objs-$(CONFIG_ASSABET_NEPONSET) += sa1100_neponset.o sa1100_cs-objs-$(CONFIG_ASSABET_NEPONSET) += sa1100_neponset.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o sa1100_cs-objs-$(CONFIG_SA1100_BADGE4) += sa1100_badge4.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_CERF) += sa1100_cerf.o sa1100_cs-objs-$(CONFIG_SA1100_CERF) += sa1100_cerf.o
sa1100_cs-objs-$(CONFIG_SA1100_FLEXANET) += sa1100_flexanet.o
sa1100_cs-objs-$(CONFIG_SA1100_FREEBIRD) += sa1100_freebird.o
sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSMASTER) += sa1100_graphicsmaster.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSCLIENT) += sa1100_graphicsclient.o sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSCLIENT) += sa1100_graphicsclient.o
sa1100_cs-objs-$(CONFIG_SA1100_XP860) += sa1100_xp860.o sa1100_cs-objs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o
sa1100_cs-objs-$(CONFIG_SA1100_JORNADA720) += sa1100_jornada720.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_PANGOLIN) += sa1100_pangolin.o sa1100_cs-objs-$(CONFIG_SA1100_PANGOLIN) += sa1100_pangolin.o
sa1100_cs-objs-$(CONFIG_SA1100_YOPY) += sa1100_yopy.o sa1100_cs-objs-$(CONFIG_SA1100_PFS168) += sa1100_pfs168.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_FREEBIRD) += sa1100_freebird.o sa1100_cs-objs-$(CONFIG_SA1100_SHANNON) += sa1100_shannon.o
sa1100_cs-objs-$(CONFIG_SA1100_PFS168) += sa1100_pfs168.o
sa1100_cs-objs-$(CONFIG_SA1100_JORNADA720) += sa1100_jornada720.o
sa1100_cs-objs-$(CONFIG_SA1100_FLEXANET) += sa1100_flexanet.o
sa1100_cs-objs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o sa1100_cs-objs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o
sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSMASTER) += sa1100_graphicsmaster.o
sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSY) += sa1100_adsbitsy.o
sa1100_cs-objs-$(CONFIG_SA1100_STORK) += sa1100_stork.o sa1100_cs-objs-$(CONFIG_SA1100_STORK) += sa1100_stork.o
sa1100_cs-objs-$(CONFIG_SA1100_XP860) += sa1100_xp860.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_YOPY) += sa1100_yopy.o
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
...@@ -85,7 +87,7 @@ pcmcia_core.o: $(pcmcia_core-objs) ...@@ -85,7 +87,7 @@ pcmcia_core.o: $(pcmcia_core-objs)
$(LD) $(LD_RFLAG) -r -o $@ $(pcmcia_core-objs) $(LD) $(LD_RFLAG) -r -o $@ $(pcmcia_core-objs)
sa1100_cs.o: $(sa1100_cs-objs-y) sa1100_cs.o: $(sa1100_cs-objs-y)
$(LD) -r -o $@ $(sa1100_cs-objs-y) $(LD) -r -o $@ $(sort $(sa1100_cs-objs-y))
yenta_socket.o: $(yenta_socket-objs) yenta_socket.o: $(yenta_socket-objs)
$(LD) $(LD_RFLAG) -r -o $@ $(yenta_socket-objs) $(LD) $(LD_RFLAG) -r -o $@ $(yenta_socket-objs)
...@@ -38,9 +38,7 @@ ...@@ -38,9 +38,7 @@
#include <pcmcia/bulkmem.h> #include <pcmcia/bulkmem.h>
#include <pcmcia/cistpl.h> #include <pcmcia/cistpl.h>
#include "cs_internal.h" #include "cs_internal.h"
#include "sa1100_generic.h"
#include <asm/arch/pcmcia.h>
/* MECR: Expansion Memory Configuration Register /* MECR: Expansion Memory Configuration Register
* (SA-1100 Developers Manual, p.10-13; SA-1110 Developers Manual, p.10-24) * (SA-1100 Developers Manual, p.10-13; SA-1110 Developers Manual, p.10-24)
...@@ -157,15 +155,24 @@ static inline unsigned int sa1100_pcmcia_cmd_time(unsigned int cpu_clock_khz, ...@@ -157,15 +155,24 @@ static inline unsigned int sa1100_pcmcia_cmd_time(unsigned int cpu_clock_khz,
* use when responding to a Card Services query of some kind. * use when responding to a Card Services query of some kind.
*/ */
struct sa1100_pcmcia_socket { struct sa1100_pcmcia_socket {
/*
* Core PCMCIA state
*/
socket_state_t cs_state; socket_state_t cs_state;
struct pcmcia_state k_state;
unsigned int irq;
void (*handler)(void *, unsigned int);
void *handler_info;
pccard_io_map io_map[MAX_IO_WIN]; pccard_io_map io_map[MAX_IO_WIN];
pccard_mem_map mem_map[MAX_WIN]; pccard_mem_map mem_map[MAX_WIN];
ioaddr_t virt_io, phys_attr, phys_mem; void (*handler)(void *, unsigned int);
void *handler_info;
struct pcmcia_state k_state;
ioaddr_t phys_attr, phys_mem;
void *virt_io;
unsigned short speed_io, speed_attr, speed_mem; unsigned short speed_io, speed_attr, speed_mem;
/*
* Info from low level handler
*/
unsigned int irq;
}; };
...@@ -180,23 +187,57 @@ struct sa1100_pcmcia_socket { ...@@ -180,23 +187,57 @@ struct sa1100_pcmcia_socket {
/* /*
* Declaration for all implementation specific low_level operations. * Declaration for all machine specific init/exit functions.
*/ */
extern struct pcmcia_low_level assabet_pcmcia_ops; extern int pcmcia_adsbitsy_init(void);
extern struct pcmcia_low_level neponset_pcmcia_ops; extern void pcmcia_adsbitsy_exit(void);
extern struct pcmcia_low_level h3600_pcmcia_ops;
extern struct pcmcia_low_level cerf_pcmcia_ops; extern int pcmcia_assabet_init(void);
extern struct pcmcia_low_level gcplus_pcmcia_ops; extern void pcmcia_assabet_exit(void);
extern struct pcmcia_low_level xp860_pcmcia_ops;
extern struct pcmcia_low_level yopy_pcmcia_ops; extern int pcmcia_badge4_init(void);
extern struct pcmcia_low_level pangolin_pcmcia_ops; extern void pcmcia_badge4_exit(void);
extern struct pcmcia_low_level freebird_pcmcia_ops;
extern struct pcmcia_low_level pfs168_pcmcia_ops; extern int pcmcia_cerf_init(void);
extern struct pcmcia_low_level jornada720_pcmcia_ops; extern void pcmcia_cerf_exit(void);
extern struct pcmcia_low_level flexanet_pcmcia_ops;
extern struct pcmcia_low_level simpad_pcmcia_ops; extern int pcmcia_flexanet_init(void);
extern struct pcmcia_low_level graphicsmaster_pcmcia_ops; extern void pcmcia_flexanet_exit(void);
extern struct pcmcia_low_level adsbitsy_pcmcia_ops;
extern struct pcmcia_low_level stork_pcmcia_ops; extern int pcmcia_freebird_init(void);
extern void pcmcia_freebird_exit(void);
extern int pcmcia_gcplus_init(void);
extern void pcmcia_gcplus_exit(void);
extern int pcmcia_graphicsmaster_init(void);
extern void pcmcia_graphicsmaster_exit(void);
extern int pcmcia_jornada720_init(void);
extern void pcmcia_jornada720_exit(void);
extern int pcmcia_neponset_init(void);
extern void pcmcia_neponset_exit(void);
extern int pcmcia_pangolin_init(void);
extern void pcmcia_pangolin_exit(void);
extern int pcmcia_pfs168_init(void);
extern void pcmcia_pfs168_exit(void);
extern int pcmcia_shannon_init(void);
extern void pcmcia_shannon_exit(void);
extern int pcmcia_simpad_init(void);
extern void pcmcia_simpad_exit(void);
extern int pcmcia_stork_init(void);
extern void pcmcia_stork_exit(void);
extern int pcmcia_xp860_init(void);
extern void pcmcia_xp860_exit(void);
extern int pcmcia_yopy_init(void);
extern void pcmcia_yopy_exit(void);
#endif /* !defined(_PCMCIA_SA1100_H) */ #endif /* !defined(_PCMCIA_SA1100_H) */
...@@ -11,206 +11,97 @@ ...@@ -11,206 +11,97 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h>
#include <asm/delay.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/arch/pcmcia.h> #include "sa1100_generic.h"
#include "sa1111_generic.h"
static int adsbitsy_pcmcia_init(struct pcmcia_init *init) static int adsbitsy_pcmcia_init(struct pcmcia_init *init)
{ {
int return_val=0;
/* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */ /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
/* Disable Power 3.3V/5V for PCMCIA/CF */ /* Disable Power 3.3V/5V for PCMCIA/CF */
PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3; PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3;
INTPOL1 |= (1 << (S0_READY_NINT - SA1111_IRQ(32))) | /* Why? */
(1 << (S1_READY_NINT - SA1111_IRQ(32))) |
(1 << (S0_CD_VALID - SA1111_IRQ(32))) |
(1 << (S1_CD_VALID - SA1111_IRQ(32))) |
(1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
(1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
"GC Master PCMCIA (0) CD", NULL);
return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
"GC Master CF (1) CD", NULL);
return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
"GC Master PCMCIA (0) BVD1", NULL);
return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
"GC Master CF (1) BVD1", NULL);
MECR = 0x09430943; MECR = 0x09430943;
return (return_val<0) ? -1 : 2; return sa1111_pcmcia_init(init);
}
static int adsbitsy_pcmcia_shutdown(void)
{
free_irq(S0_CD_VALID, NULL);
free_irq(S1_CD_VALID, NULL);
free_irq(S0_BVD1_STSCHG, NULL);
free_irq(S1_BVD1_STSCHG, NULL);
INTPOL1 &= ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
(1 << (S1_CD_VALID - SA1111_IRQ(32))) |
(1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
(1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
return 0;
} }
static int adsbitsy_pcmcia_socket_state(struct pcmcia_state_array *state_array) static int
adsbitsy_pcmcia_configure_socket(const struct pcmcia_configure *conf)
{ {
unsigned long status; unsigned int pa_dwr_mask, pa_dwr_set;
int return_val=1; int ret;
if(state_array->size<2) return -1;
memset(state_array->state, 0,
(state_array->size)*sizeof(struct pcmcia_state));
status=PCSR;
state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0; switch (conf->sock) {
state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
return return_val;
}
static int adsbitsy_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
{
switch(info->sock){
case 0: case 0:
info->irq=S0_READY_NINT; pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
break;
case 1:
info->irq=S1_READY_NINT;
break;
default:
return -1;
}
return 0;
}
static int adsbitsy_pcmcia_configure_socket(const struct pcmcia_configure *configure)
{
unsigned long pccr=PCCR, gpio=PA_DWR;
switch(configure->sock){
case 0:
switch(configure->vcc){
case 0:
pccr = (pccr & ~PCCR_S0_FLT);
gpio |= GPIO_GPIO0 | GPIO_GPIO1;
break;
case 33:
pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1);
gpio &= ~GPIO_GPIO0;
break;
case 50:
pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1);
gpio |= GPIO_GPIO0;
break;
switch (conf->vcc) {
default: default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, case 0: pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1; break;
configure->vcc); case 33: pa_dwr_set = GPIO_GPIO1; break;
return -1; case 50: pa_dwr_set = GPIO_GPIO0; break;
} }
pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
break; break;
case 1: case 1:
switch(configure->vcc){ pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3;
case 0:
pccr = (pccr & ~PCCR_S1_FLT);
gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
break;
case 33:
pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
gpio |= GPIO_GPIO2;
break;
case 50:
pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN);
gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
gpio |= GPIO_GPIO3;
break;
switch (conf->vcc) {
default: default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, case 0: pa_dwr_set = 0; break;
configure->vcc); case 33: pa_dwr_set = GPIO_GPIO2; break;
return -1; case 50: pa_dwr_set = GPIO_GPIO3; break;
} }
if(configure->vpp!=configure->vcc && configure->vpp!=0){
printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
configure->vpp);
return -1;
}
pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
break;
default: default:
return -1; return -1;
} }
PCCR = pccr; if (conf->vpp != conf->vcc && conf->vpp != 0) {
PA_DWR = gpio; printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
__FUNCTION__, conf->vpp);
return -1;
}
ret = sa1111_pcmcia_configure_socket(conf);
if (ret == 0) {
unsigned long flags;
return 0; local_irq_save(flags);
PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
local_irq_restore(flags);
}
return ret;
} }
struct pcmcia_low_level adsbitsy_pcmcia_ops = { static struct pcmcia_low_level adsbitsy_pcmcia_ops = {
adsbitsy_pcmcia_init, init: adsbitsy_pcmcia_init,
adsbitsy_pcmcia_shutdown, shutdown: sa1111_pcmcia_shutdown,
adsbitsy_pcmcia_socket_state, socket_state: sa1111_pcmcia_socket_state,
adsbitsy_pcmcia_get_irq_info, get_irq_info: sa1111_pcmcia_get_irq_info,
adsbitsy_pcmcia_configure_socket configure_socket: adsbitsy_pcmcia_configure_socket,
socket_init: sa1111_pcmcia_socket_init,
socket_suspend: sa1111_pcmcia_socket_suspend,
}; };
int __init pcmcia_adsbitsy_init(void)
{
int ret = -ENODEV;
if (machine_is_adsbitsy())
ret = sa1100_register_pcmcia(&adsbitsy_pcmcia_ops);
return ret;
}
void __exit pcmcia_adsbitsy_exit(void)
{
sa1100_unregister_pcmcia(&adsbitsy_pcmcia_ops);
}
...@@ -4,146 +4,221 @@ ...@@ -4,146 +4,221 @@
* PCMCIA implementation routines for Assabet * PCMCIA implementation routines for Assabet
* *
*/ */
#include <linux/config.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/arch/pcmcia.h>
#include <asm/arch/assabet.h> #include <asm/arch/assabet.h>
static int assabet_pcmcia_init(struct pcmcia_init *init){ #include "sa1100_generic.h"
int irq, res;
/* Enable CF bus: */ static struct irqs {
ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF); int irq;
const char *str;
} irqs[] = {
{ ASSABET_IRQ_GPIO_CF_CD, "CF_CD" },
{ ASSABET_IRQ_GPIO_CF_BVD2, "CF_BVD2" },
{ ASSABET_IRQ_GPIO_CF_BVD1, "CF_BVD1" },
};
static int assabet_pcmcia_init(struct pcmcia_init *init)
{
int i, res;
/* Set transition detect */
set_irq_type(ASSABET_IRQ_GPIO_CF_IRQ, IRQT_FALLING);
/* All those are inputs */ /* Register interrupts */
GPDR &= ~(ASSABET_GPIO_CF_CD | ASSABET_GPIO_CF_BVD2 | ASSABET_GPIO_CF_BVD1 | ASSABET_GPIO_CF_IRQ); for (i = 0; i < ARRAY_SIZE(irqs); i++) {
set_irq_type(irqs[i].irq, IRQT_NOEDGE);
res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
irqs[i].str, NULL);
if (res)
goto irq_err;
}
/* Set transition detect */ /* There's only one slot, but it's "Slot 1": */
set_GPIO_IRQ_edge( ASSABET_GPIO_CF_CD|ASSABET_GPIO_CF_BVD2|ASSABET_GPIO_CF_BVD1, GPIO_BOTH_EDGES ); return 2;
set_GPIO_IRQ_edge( ASSABET_GPIO_CF_IRQ, GPIO_FALLING_EDGE );
/* Register interrupts */ irq_err:
irq = ASSABET_IRQ_GPIO_CF_CD; printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_CD", NULL ); __FUNCTION__, irqs[i].irq, res);
if( res < 0 ) goto irq_err;
irq = ASSABET_IRQ_GPIO_CF_BVD2;
res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD2", NULL );
if( res < 0 ) goto irq_err;
irq = ASSABET_IRQ_GPIO_CF_BVD1;
res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD1", NULL );
if( res < 0 ) goto irq_err;
/* There's only one slot, but it's "Slot 1": */ while (i--)
return 2; free_irq(irqs[i].irq, NULL);
irq_err: return res;
printk( KERN_ERR "%s: Request for IRQ %u failed\n", __FUNCTION__, irq );
return -1;
} }
/*
* Release all resources.
*/
static int assabet_pcmcia_shutdown(void) static int assabet_pcmcia_shutdown(void)
{ {
/* disable IRQs */ int i;
free_irq( ASSABET_IRQ_GPIO_CF_CD, NULL );
free_irq( ASSABET_IRQ_GPIO_CF_BVD2, NULL );
free_irq( ASSABET_IRQ_GPIO_CF_BVD1, NULL );
/* Disable CF bus: */
ASSABET_BCR_set(ASSABET_BCR_CF_BUS_OFF);
return 0; for (i = 0; i < ARRAY_SIZE(irqs); i++)
free_irq(irqs[i].irq, NULL);
return 0;
} }
static int assabet_pcmcia_socket_state(struct pcmcia_state_array static int
*state_array){ assabet_pcmcia_socket_state(struct pcmcia_state_array *state_array)
unsigned long levels; {
unsigned long levels;
if(state_array->size<2) return -1; if (state_array->size < 2)
return -1;
memset(state_array->state, 0, levels = GPLR;
(state_array->size)*sizeof(struct pcmcia_state));
levels=GPLR; state_array->state[1].detect = (levels & ASSABET_GPIO_CF_CD) ? 0 : 1;
state_array->state[1].ready = (levels & ASSABET_GPIO_CF_IRQ) ? 1 : 0;
state_array->state[1].bvd1 = (levels & ASSABET_GPIO_CF_BVD1) ? 1 : 0;
state_array->state[1].bvd2 = (levels & ASSABET_GPIO_CF_BVD2) ? 1 : 0;
state_array->state[1].wrprot = 0; /* Not available on Assabet. */
state_array->state[1].vs_3v = 1; /* Can only apply 3.3V on Assabet. */
state_array->state[1].vs_Xv = 0;
state_array->state[1].detect=((levels & ASSABET_GPIO_CF_CD)==0)?1:0; return 1;
}
state_array->state[1].ready=(levels & ASSABET_GPIO_CF_IRQ)?1:0; static int assabet_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
{
if (info->sock > 1)
return -1;
state_array->state[1].bvd1=(levels & ASSABET_GPIO_CF_BVD1)?1:0; if (info->sock == 1)
info->irq = ASSABET_IRQ_GPIO_CF_IRQ;
state_array->state[1].bvd2=(levels & ASSABET_GPIO_CF_BVD2)?1:0; return 0;
}
state_array->state[1].wrprot=0; /* Not available on Assabet. */ static int
assabet_pcmcia_configure_socket(const struct pcmcia_configure *configure)
{
unsigned int mask;
state_array->state[1].vs_3v=1; /* Can only apply 3.3V on Assabet. */ if (configure->sock > 1)
return -1;
state_array->state[1].vs_Xv=0; if (configure->sock == 0)
return 0;
return 1; switch (configure->vcc) {
} case 0:
mask = 0;
break;
static int assabet_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ case 50:
printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
__FUNCTION__);
if(info->sock>1) return -1; case 33: /* Can only apply 3.3V to the CF slot. */
mask = ASSABET_BCR_CF_PWR;
break;
if(info->sock==1) default:
info->irq=ASSABET_IRQ_GPIO_CF_IRQ; printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc);
return -1;
}
return 0; /* Silently ignore Vpp, output enable, speaker enable. */
}
static int assabet_pcmcia_configure_socket(const struct pcmcia_configure if (configure->reset)
*configure) mask |= ASSABET_BCR_CF_RST;
{
unsigned long value, flags;
if(configure->sock>1) return -1; ASSABET_BCR_frob(ASSABET_BCR_CF_RST | ASSABET_BCR_CF_PWR, mask);
if(configure->sock==0) return 0; /*
* Handle suspend mode properly. This prevents a
* flood of IRQs from the CF device.
*/
if (configure->irq)
enable_irq(ASSABET_IRQ_GPIO_CF_IRQ);
else
disable_irq(ASSABET_IRQ_GPIO_CF_IRQ);
save_flags_cli(flags); return 0;
}
value = BCR_value; /*
* Enable card status IRQs on (re-)initialisation. This can
* be called at initialisation, power management event, or
* pcmcia event.
*/
static int assabet_pcmcia_socket_init(int sock)
{
int i;
switch(configure->vcc){ if (sock == 1) {
case 0: /*
value &= ~ASSABET_BCR_CF_PWR; * Enable CF bus
break; */
ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF);
case 50: for (i = 0; i < ARRAY_SIZE(irqs); i++)
printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n", set_irq_type(irqs[i].irq, IRQT_BOTHEDGE);
__FUNCTION__); }
case 33: /* Can only apply 3.3V to the CF slot. */ return 0;
value |= ASSABET_BCR_CF_PWR; }
break;
default: /*
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, * Disable card status IRQs on suspend.
configure->vcc); */
restore_flags(flags); static int assabet_pcmcia_socket_suspend(int sock)
return -1; {
} int i;
value = (configure->reset) ? (value | ASSABET_BCR_CF_RST) : (value & ~ASSABET_BCR_CF_RST); if (sock == 1) {
for (i = 0; i < ARRAY_SIZE(irqs); i++)
set_irq_type(irqs[i].irq, IRQT_NOEDGE);
/* Silently ignore Vpp, output enable, speaker enable. */ /*
* Tristate the CF bus signals. Also assert CF
* reset as per user guide page 4-11.
*/
ASSABET_BCR_set(ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_CF_RST);
}
ASSABET_BCR = BCR_value = value; return 0;
}
static struct pcmcia_low_level assabet_pcmcia_ops = {
init: assabet_pcmcia_init,
shutdown: assabet_pcmcia_shutdown,
socket_state: assabet_pcmcia_socket_state,
get_irq_info: assabet_pcmcia_get_irq_info,
configure_socket: assabet_pcmcia_configure_socket,
restore_flags(flags); socket_init: assabet_pcmcia_socket_init,
socket_suspend: assabet_pcmcia_socket_suspend,
};
return 0; int __init pcmcia_assabet_init(void)
{
int ret = -ENODEV;
if (machine_is_assabet()) {
if (!machine_has_neponset())
ret = sa1100_register_pcmcia(&assabet_pcmcia_ops);
#ifndef CONFIG_ASSABET_NEPONSET
else
printk(KERN_ERR "Card Services disabled: missing "
"Neponset support\n");
#endif
}
return ret;
} }
struct pcmcia_low_level assabet_pcmcia_ops = { void __exit pcmcia_assabet_exit(void)
assabet_pcmcia_init, {
assabet_pcmcia_shutdown, sa1100_unregister_pcmcia(&assabet_pcmcia_ops);
assabet_pcmcia_socket_state, }
assabet_pcmcia_get_irq_info,
assabet_pcmcia_configure_socket
};
/*
* linux/drivers/pcmcia/sa1100_badge4.c
*
* BadgePAD 4 PCMCIA specific routines
*
* Christopher Hoover <ch@hpl.hp.com>
*
* Copyright (C) 2002 Hewlett-Packard Company
*
* 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/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <asm/hardware.h>
#include <asm/arch/badge4.h>
#include <asm/hardware/sa1111.h>
#include "sa1100_generic.h"
#include "sa1111_generic.h"
/*
* BadgePAD 4 Details
*
* PCM Vcc:
*
* PCM Vcc on BadgePAD 4 can be jumpered for 3.3V (short pins 1 and 3
* on JP6) or 5V (short pins 3 and 5 on JP6). N.B., 5V supply rail
* is enabled by the SA-1110's BADGE4_GPIO_PCMEN5V (GPIO 24).
*
* PCM Vpp:
*
* PCM Vpp on BadgePAD 4 can be jumpered for 12V (short pins 2 and 4
* on JP6) or tied to PCM Vcc (short pins 4 and 6 on JP6). N.B., 12V
* operation requires that the power supply actually supply 12V.
*
* CF Vcc:
*
* CF Vcc on BadgePAD 4 can be jumpered either for 3.3V (short pins 1
* and 2 on JP10) or 5V (short pins 2 and 3 on JP10). The note above
* about the 5V supply rail applies.
*
* There's no way programmatically to determine how a given board is
* jumpered. This code assumes a default jumpering: 5V PCM Vcc (pins
* 3 and 5 shorted) and PCM Vpp = PCM Vcc (pins 4 and 6 shorted) and
* no jumpering for CF Vcc. If this isn't correct, Override these
* defaults with a pcmv setup argument: pcmv=<pcm vcc>,<pcm vpp>,<cf
* vcc>. E.g. pcmv=33,120,50 indicates 3.3V PCM Vcc, 12.0V PCM Vpp,
* and 5.0V CF Vcc.
*
*/
static int badge4_pcmvcc = 50;
static int badge4_pcmvpp = 50;
static int badge4_cfvcc = 0;
static int badge4_pcmcia_init(struct pcmcia_init *init)
{
printk(KERN_INFO __FUNCTION__
": badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n",
badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc);
return sa1111_pcmcia_init(init);
}
static int badge4_pcmcia_shutdown(void)
{
int rc = sa1111_pcmcia_shutdown();
/* be sure to disable 5V use */
badge4_set_5V(BADGE4_5V_PCMCIA_SOCK0, 0);
badge4_set_5V(BADGE4_5V_PCMCIA_SOCK1, 0);
return rc;
}
static void complain_about_jumpering(const char *whom,
const char *supply,
int given, int wanted)
{
printk(KERN_ERR
"%s: %s %d.%dV wanted but board is jumpered for %s %d.%dV operation"
"; re-jumper the board and/or use pcmv=xx,xx,xx\n",
whom, supply,
wanted / 10, wanted % 10,
supply,
given / 10, given % 10);
}
static unsigned badge4_need_5V_bitmap = 0;
static int
badge4_pcmcia_configure_socket(const struct pcmcia_configure *conf)
{
int ret;
switch (conf->sock) {
case 0:
if ((conf->vcc != 0) &&
(conf->vcc != badge4_pcmvcc)) {
complain_about_jumpering(__FUNCTION__, "pcmvcc",
badge4_pcmvcc, conf->vcc);
return -1;
}
if ((conf->vpp != 0) &&
(conf->vpp != badge4_pcmvpp)) {
complain_about_jumpering(__FUNCTION__, "pcmvpp",
badge4_pcmvpp, conf->vpp);
return -1;
}
break;
case 1:
if ((conf->vcc != 0) &&
(conf->vcc != badge4_cfvcc)) {
complain_about_jumpering(__FUNCTION__, "cfvcc",
badge4_cfvcc, conf->vcc);
return -1;
}
break;
default:
return -1;
}
ret = sa1111_pcmcia_configure_socket(conf);
if (ret == 0) {
unsigned long flags;
int need5V;
local_irq_save(flags);
need5V = ((conf->vcc == 50) || (conf->vpp == 50));
badge4_set_5V(BADGE4_5V_PCMCIA_SOCK(conf->sock), need5V);
local_irq_restore(flags);
}
return 0;
}
static struct pcmcia_low_level badge4_pcmcia_ops = {
init: badge4_pcmcia_init,
shutdown: badge4_pcmcia_shutdown,
socket_state: sa1111_pcmcia_socket_state,
get_irq_info: sa1111_pcmcia_get_irq_info,
configure_socket: badge4_pcmcia_configure_socket,
socket_init: sa1111_pcmcia_socket_init,
socket_suspend: sa1111_pcmcia_socket_suspend,
};
int __init pcmcia_badge4_init(void)
{
int ret = -ENODEV;
if (machine_is_badge4())
ret = sa1100_register_pcmcia(&badge4_pcmcia_ops);
return ret;
}
void __exit pcmcia_badge4_exit(void)
{
sa1100_unregister_pcmcia(&badge4_pcmcia_ops);
}
static int __init pcmv_setup(char *s)
{
int v[4];
s = get_options(s, ARRAY_SIZE(v), v);
if (v[0] >= 1) badge4_pcmvcc = v[1];
if (v[0] >= 2) badge4_pcmvpp = v[2];
if (v[0] >= 3) badge4_cfvcc = v[3];
return 1;
}
__setup("pcmv=", pcmv_setup);
...@@ -5,45 +5,62 @@ ...@@ -5,45 +5,62 @@
* Based off the Assabet. * Based off the Assabet.
* *
*/ */
#include <linux/config.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/arch/pcmcia.h> #include "sa1100_generic.h"
#ifdef CONFIG_SA1100_CERF_CPLD
#define CERF_SOCKET 0
#else
#define CERF_SOCKET 1
#endif
static int cerf_pcmcia_init(struct pcmcia_init *init){ static struct irqs {
int irq, res; int irq;
const char *str;
} irqs[] = {
{ IRQ_GPIO_CF_CD, "CF_CD" },
{ IRQ_GPIO_CF_BVD2, "CF_BVD2" },
{ IRQ_GPIO_CF_BVD1, "CF_BVD1" }
};
GPDR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IRQ); static int cerf_pcmcia_init(struct pcmcia_init *init)
GPDR |= (GPIO_CF_RESET); {
int i, res;
set_GPIO_IRQ_edge( GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1, GPIO_BOTH_EDGES ); set_irq_type(IRQ_GPIO_CF_IRQ, IRQT_FALLING);
set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE );
irq = IRQ_GPIO_CF_CD; for (i = 0; i < ARRAY_SIZE(irqs); i++) {
res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_CD", NULL ); set_irq_type(irqs[i].irq, IRQT_NOEDGE);
if( res < 0 ) goto irq_err; res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
irq = IRQ_GPIO_CF_BVD2; irqs[i].str, NULL);
res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD2", NULL ); if (res)
if( res < 0 ) goto irq_err; goto irq_err;
irq = IRQ_GPIO_CF_BVD1; }
res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD1", NULL );
if( res < 0 ) goto irq_err;
return 2; return 2;
irq_err: irq_err:
printk( KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq ); printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
return -1; __FUNCTION__, irqs[i].irq, res);
while (i--)
free_irq(irqs[i].irq, NULL);
return res;
} }
static int cerf_pcmcia_shutdown(void) static int cerf_pcmcia_shutdown(void)
{ {
free_irq( IRQ_GPIO_CF_CD, NULL ); int i;
free_irq( IRQ_GPIO_CF_BVD2, NULL );
free_irq( IRQ_GPIO_CF_BVD1, NULL ); for (i = 0; i < ARRAY_SIZE(irqs); i++)
free_irq(irqs[i].irq, NULL);
return 0; return 0;
} }
...@@ -51,31 +68,18 @@ static int cerf_pcmcia_shutdown(void) ...@@ -51,31 +68,18 @@ static int cerf_pcmcia_shutdown(void)
static int cerf_pcmcia_socket_state(struct pcmcia_state_array static int cerf_pcmcia_socket_state(struct pcmcia_state_array
*state_array){ *state_array){
unsigned long levels; unsigned long levels;
#ifdef CONFIG_SA1100_CERF_CPLD int i = CERF_SOCKET;
int i = 0;
#else
int i = 1;
#endif
if(state_array->size<2) return -1; if(state_array->size<2) return -1;
memset(state_array->state, 0,
(state_array->size)*sizeof(struct pcmcia_state));
levels=GPLR; levels=GPLR;
state_array->state[i].detect=((levels & GPIO_CF_CD)==0)?1:0; state_array->state[i].detect=((levels & GPIO_CF_CD)==0)?1:0;
state_array->state[i].ready=(levels & GPIO_CF_IRQ)?1:0; state_array->state[i].ready=(levels & GPIO_CF_IRQ)?1:0;
state_array->state[i].bvd1=(levels & GPIO_CF_BVD1)?1:0; state_array->state[i].bvd1=(levels & GPIO_CF_BVD1)?1:0;
state_array->state[i].bvd2=(levels & GPIO_CF_BVD2)?1:0; state_array->state[i].bvd2=(levels & GPIO_CF_BVD2)?1:0;
state_array->state[i].wrprot=0; state_array->state[i].wrprot=0;
state_array->state[i].vs_3v=1; state_array->state[i].vs_3v=1;
state_array->state[i].vs_Xv=0; state_array->state[i].vs_Xv=0;
return 1; return 1;
...@@ -85,11 +89,7 @@ static int cerf_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ ...@@ -85,11 +89,7 @@ static int cerf_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
if(info->sock>1) return -1; if(info->sock>1) return -1;
#ifdef CONFIG_SA1100_CERF_CPLD if (info->sock == CERF_SOCKET)
if(info->sock==0)
#else
if(info->sock==1)
#endif
info->irq=IRQ_GPIO_CF_IRQ; info->irq=IRQ_GPIO_CF_IRQ;
return 0; return 0;
...@@ -98,20 +98,12 @@ static int cerf_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ ...@@ -98,20 +98,12 @@ static int cerf_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
static int cerf_pcmcia_configure_socket(const struct pcmcia_configure static int cerf_pcmcia_configure_socket(const struct pcmcia_configure
*configure) *configure)
{ {
unsigned long flags;
if(configure->sock>1) if(configure->sock>1)
return -1; return -1;
#ifdef CONFIG_SA1100_CERF_CPLD if (configure->sock != CERF_SOCKET)
if(configure->sock==1)
#else
if(configure->sock==0)
#endif
return 0; return 0;
save_flags_cli(flags);
switch(configure->vcc){ switch(configure->vcc){
case 0: case 0:
break; break;
...@@ -119,43 +111,76 @@ static int cerf_pcmcia_configure_socket(const struct pcmcia_configure ...@@ -119,43 +111,76 @@ static int cerf_pcmcia_configure_socket(const struct pcmcia_configure
case 50: case 50:
case 33: case 33:
#ifdef CONFIG_SA1100_CERF_CPLD #ifdef CONFIG_SA1100_CERF_CPLD
GPDR |= GPIO_PWR_SHUTDOWN; GPCR = GPIO_PWR_SHUTDOWN;
GPCR |= GPIO_PWR_SHUTDOWN;
#endif #endif
break; break;
default: default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc); configure->vcc);
restore_flags(flags);
return -1; return -1;
} }
if(configure->reset) if(configure->reset)
{ {
#ifdef CONFIG_SA1100_CERF_CPLD #ifdef CONFIG_SA1100_CERF_CPLD
GPDR |= GPIO_CF_RESET; GPSR = GPIO_CF_RESET;
GPSR |= GPIO_CF_RESET;
#endif #endif
} }
else else
{ {
#ifdef CONFIG_SA1100_CERF_CPLD #ifdef CONFIG_SA1100_CERF_CPLD
GPDR |= GPIO_CF_RESET; GPCR = GPIO_CF_RESET;
GPCR |= GPIO_CF_RESET;
#endif #endif
} }
restore_flags(flags); return 0;
}
static int cerf_pcmcia_socket_init(int sock)
{
int i;
if (sock == CERF_SOCKET)
for (i = 0; i < ARRAY_SIZE(irqs); i++)
set_irq_type(irqs[i].irq, IRQT_BOTHEDGE);
return 0; return 0;
} }
struct pcmcia_low_level cerf_pcmcia_ops = { static int cerf_pcmcia_socket_suspend(int sock)
cerf_pcmcia_init, {
cerf_pcmcia_shutdown, int i;
cerf_pcmcia_socket_state,
cerf_pcmcia_get_irq_info, if (sock == CERF_SOCKET)
cerf_pcmcia_configure_socket for (i = 0; i < ARRAY_SIZE(irqs); i++)
set_irq_type(irqs[i].irq, IRQT_NOEDGE);
return 0;
}
static struct pcmcia_low_level cerf_pcmcia_ops = {
init: cerf_pcmcia_init,
shutdown: cerf_pcmcia_shutdown,
socket_state: cerf_pcmcia_socket_state,
get_irq_info: cerf_pcmcia_get_irq_info,
configure_socket: cerf_pcmcia_configure_socket,
socket_init: cerf_pcmcia_socket_init,
socket_suspend: cerf_pcmcia_socket_suspend,
}; };
int __init pcmcia_cerf_init(void)
{
int ret = -ENODEV;
if (machine_is_cerf())
ret = sa1100_register_pcmcia(&cerf_pcmcia_ops);
return ret;
}
void __exit pcmcia_cerf_exit(void)
{
sa1100_unregister_pcmcia(&cerf_pcmcia_ops);
}
...@@ -4,16 +4,25 @@ ...@@ -4,16 +4,25 @@
* PCMCIA implementation routines for Flexanet. * PCMCIA implementation routines for Flexanet.
* by Jordi Colomer, 09/05/2001 * by Jordi Colomer, 09/05/2001
* *
* Yet to be defined.
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/arch/pcmcia.h> #include "sa1100_generic.h"
static struct {
int irq;
const char *name;
} irqs[] = {
{ IRQ_GPIO_CF1_CD, "CF1_CD" },
{ IRQ_GPIO_CF1_BVD1, "CF1_BVD1" },
{ IRQ_GPIO_CF2_CD, "CF2_CD" },
{ IRQ_GPIO_CF2_BVD1, "CF2_BVD1" }
};
/* /*
* Socket initialization. * Socket initialization.
...@@ -22,9 +31,37 @@ ...@@ -22,9 +31,37 @@
* Must return the number of slots. * Must return the number of slots.
* *
*/ */
static int flexanet_pcmcia_init(struct pcmcia_init *init){ static int flexanet_pcmcia_init(struct pcmcia_init *init)
{
return 0; int i, res;
/* Configure the GPIOs as inputs (BVD2 is not implemented) */
GPDR &= ~(GPIO_CF1_NCD | GPIO_CF1_BVD1 | GPIO_CF1_IRQ |
GPIO_CF2_NCD | GPIO_CF2_BVD1 | GPIO_CF2_IRQ );
/* Set IRQ edge */
set_irq_type(IRQ_GPIO_CF1_IRQ, IRQT_FALLING);
set_irq_type(IRQ_GPIO_CF2_IRQ, IRQT_FALLING);
/* Register the socket interrupts (not the card interrupts) */
for (i = 0; i < ARRAY_SIZE(irqs); i++) {
set_irq_type(irqs[i].irq, IRQT_NOEDGE);
res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
irqs[i].name, NULL);
if (res < 0)
break;
}
/* If we failed, then free all interrupts requested thus far. */
if (res < 0) {
printk(KERN_ERR "%s: request for IRQ%d failed: %d\n",
__FUNCTION__, irqs[i].irq, res);
while (i--)
free_irq(irqs[i].irq, NULL);
return res;
}
return 2;
} }
...@@ -34,6 +71,12 @@ static int flexanet_pcmcia_init(struct pcmcia_init *init){ ...@@ -34,6 +71,12 @@ static int flexanet_pcmcia_init(struct pcmcia_init *init){
*/ */
static int flexanet_pcmcia_shutdown(void) static int flexanet_pcmcia_shutdown(void)
{ {
int i;
/* disable IRQs */
for (i = 0; i < ARRAY_SIZE(irqs); i++)
free_irq(irqs[i].irq, NULL);
return 0; return 0;
} }
...@@ -46,7 +89,33 @@ static int flexanet_pcmcia_shutdown(void) ...@@ -46,7 +89,33 @@ static int flexanet_pcmcia_shutdown(void)
*/ */
static int flexanet_pcmcia_socket_state(struct pcmcia_state_array static int flexanet_pcmcia_socket_state(struct pcmcia_state_array
*state_array){ *state_array){
return -1; unsigned long levels;
if (state_array->size < 2)
return -1;
/* Sense the GPIOs, asynchronously */
levels = GPLR;
/* Socket 0 */
state_array->state[0].detect = ((levels & GPIO_CF1_NCD)==0)?1:0;
state_array->state[0].ready = (levels & GPIO_CF1_IRQ)?1:0;
state_array->state[0].bvd1 = (levels & GPIO_CF1_BVD1)?1:0;
state_array->state[0].bvd2 = 1;
state_array->state[0].wrprot = 0;
state_array->state[0].vs_3v = 1;
state_array->state[0].vs_Xv = 0;
/* Socket 1 */
state_array->state[1].detect = ((levels & GPIO_CF2_NCD)==0)?1:0;
state_array->state[1].ready = (levels & GPIO_CF2_IRQ)?1:0;
state_array->state[1].bvd1 = (levels & GPIO_CF2_BVD1)?1:0;
state_array->state[1].bvd2 = 1;
state_array->state[1].wrprot = 0;
state_array->state[1].vs_3v = 1;
state_array->state[1].vs_Xv = 0;
return 1;
} }
...@@ -56,7 +125,16 @@ static int flexanet_pcmcia_socket_state(struct pcmcia_state_array ...@@ -56,7 +125,16 @@ static int flexanet_pcmcia_socket_state(struct pcmcia_state_array
*/ */
static int flexanet_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ static int flexanet_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
return -1; /* check the socket index */
if (info->sock > 1)
return -1;
if (info->sock == 0)
info->irq = IRQ_GPIO_CF1_IRQ;
else if (info->sock == 1)
info->irq = IRQ_GPIO_CF2_IRQ;
return 0;
} }
...@@ -66,19 +144,105 @@ static int flexanet_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ ...@@ -66,19 +144,105 @@ static int flexanet_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
static int flexanet_pcmcia_configure_socket(const struct pcmcia_configure static int flexanet_pcmcia_configure_socket(const struct pcmcia_configure
*configure) *configure)
{ {
return -1; unsigned long value, flags, mask;
if (configure->sock > 1)
return -1;
/* Ignore the VCC level since it is 3.3V and always on */
switch (configure->vcc)
{
case 0:
printk(KERN_WARNING "%s(): CS asked to power off.\n", __FUNCTION__);
break;
case 50:
printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
__FUNCTION__);
case 33:
break;
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc);
return -1;
}
/* Reset the slot(s) using the controls in the BCR */
mask = 0;
switch (configure->sock)
{
case 0 : mask = FHH_BCR_CF1_RST; break;
case 1 : mask = FHH_BCR_CF2_RST; break;
}
local_irq_save(flags);
value = flexanet_BCR;
value = (configure->reset) ? (value | mask) : (value & ~mask);
FHH_BCR = flexanet_BCR = value;
local_irq_restore(flags);
return 0;
}
static int flexanet_pcmcia_socket_init(int sock)
{
if (sock == 0) {
set_irq_type(IRQ_GPIO_CF1_CD, IRQT_BOTHEDGE);
set_irq_type(IRQ_GPIO_CF1_BVD1, IRQT_BOTHEDGE);
} else if (sock == 1) {
set_irq_type(IRQ_GPIO_CF2_CD, IRQT_BOTHEDGE);
set_irq_type(IRQ_GPIO_CF2_BVD1, IRQT_BOTHEDGE);
}
return 0;
} }
static int flexanet_pcmcia_socket_suspend(int sock)
{
if (sock == 0) {
set_irq_type(IRQ_GPIO_CF1_CD, IRQT_NOEDGE);
set_irq_type(IRQ_GPIO_CF1_BVD1, IRQT_NOEDGE);
} else if (sock == 1) {
set_irq_type(IRQ_GPIO_CF2_CD, IRQT_NOEDGE);
set_irq_type(IRQ_GPIO_CF2_BVD1, IRQT_NOEDGE);
}
return 0;
}
/* /*
* The set of socket operations * The set of socket operations
* *
*/ */
struct pcmcia_low_level flexanet_pcmcia_ops = { static struct pcmcia_low_level flexanet_pcmcia_ops = {
flexanet_pcmcia_init, init: flexanet_pcmcia_init,
flexanet_pcmcia_shutdown, shutdown: flexanet_pcmcia_shutdown,
flexanet_pcmcia_socket_state, socket_state: flexanet_pcmcia_socket_state,
flexanet_pcmcia_get_irq_info, get_irq_info: flexanet_pcmcia_get_irq_info,
flexanet_pcmcia_configure_socket configure_socket: flexanet_pcmcia_configure_socket,
socket_init: flexanet_pcmcia_socket_init,
socket_suspend: flexanet_pcmcia_socket_suspend,
}; };
int __init pcmcia_flexanet_init(void)
{
int ret = -ENODEV;
if (machine_is_flexanet())
ret = sa1100_register_pcmcia(&flexanet_pcmcia_ops);
return ret;
}
void __exit pcmcia_flexanet_exit(void)
{
sa1100_unregister_pcmcia(&flexanet_pcmcia_ops);
}
...@@ -6,14 +6,22 @@ ...@@ -6,14 +6,22 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/arch/pcmcia.h> #include "sa1100_generic.h"
static struct irqs {
int irq;
const char *str;
} irqs[] = {
{ IRQ_GPIO_FREEBIRD_CF_CD, "CF_CD" },
{ IRQ_GPIO_FREEBIRD_CF_BVD, "CF_BVD1" },
};
static int freebird_pcmcia_init(struct pcmcia_init *init){ static int freebird_pcmcia_init(struct pcmcia_init *init){
int irq, res; int i, res;
/* Enable Linkup CF card */ /* Enable Linkup CF card */
LINKUP_PRC = 0xc0; LINKUP_PRC = 0xc0;
...@@ -26,37 +34,38 @@ static int freebird_pcmcia_init(struct pcmcia_init *init){ ...@@ -26,37 +34,38 @@ static int freebird_pcmcia_init(struct pcmcia_init *init){
mdelay(100); mdelay(100);
LINKUP_PRC = 0xc0; LINKUP_PRC = 0xc0;
/* All those are inputs */
////GPDR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IRQ);
GPDR &= ~(GPIO_FREEBIRD_CF_CD | GPIO_FREEBIRD_CF_IRQ | GPIO_FREEBIRD_CF_BVD);
/* Set transition detect */ /* Set transition detect */
//set_GPIO_IRQ_edge( GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1, GPIO_BOTH_EDGES ); set_irq_type(IRQ_GPIO_FREEBIRD_CF_IRQ, IRQT_FALLING);
//set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE );
set_GPIO_IRQ_edge(GPIO_FREEBIRD_CF_CD|GPIO_FREEBIRD_CF_BVD,GPIO_BOTH_EDGES);
set_GPIO_IRQ_edge(GPIO_FREEBIRD_CF_IRQ, GPIO_FALLING_EDGE);
/* Register interrupts */ /* Register interrupts */
irq = IRQ_GPIO_FREEBIRD_CF_CD; for (i = 0; i < ARRAY_SIZE(irqs); i++) {
res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_CD", NULL ); set_irq_type(irqs[i].irq, IRQT_NOEDGE);
if( res < 0 ) goto irq_err; res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
irq = IRQ_GPIO_FREEBIRD_CF_BVD; irqs[i].str, NULL);
res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD1", NULL ); if (res)
if( res < 0 ) goto irq_err; goto irq_err;
}
/* There's only one slot, but it's "Slot 1": */ /* There's only one slot, but it's "Slot 1": */
return 2; return 2;
irq_err: irq_err:
printk( KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq ); printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
return -1; __FUNCTION__, irqs[i].irq, res);
while (i--)
free_irq(irqs[i].irq, NULL);
return res;
} }
static int freebird_pcmcia_shutdown(void) static int freebird_pcmcia_shutdown(void)
{ {
int i;
/* disable IRQs */ /* disable IRQs */
free_irq( IRQ_GPIO_FREEBIRD_CF_CD, NULL ); for (i = 0; i < ARRAY_SIZE(irqs); i++)
free_irq( IRQ_GPIO_FREEBIRD_CF_BVD, NULL ); free_irq(irqs[i].irq, NULL);
/* Disable CF card */ /* Disable CF card */
LINKUP_PRC = 0x40; /* SSP=1 SOE=0 */ LINKUP_PRC = 0x40; /* SSP=1 SOE=0 */
...@@ -75,7 +84,7 @@ static int freebird_pcmcia_socket_state(struct pcmcia_state_array ...@@ -75,7 +84,7 @@ static int freebird_pcmcia_socket_state(struct pcmcia_state_array
(state_array->size)*sizeof(struct pcmcia_state)); (state_array->size)*sizeof(struct pcmcia_state));
levels = LINKUP_PRS; levels = LINKUP_PRS;
//printk("LINKUP_PRS=%x \n",levels); //printk("LINKUP_PRS=%x\n",levels);
state_array->state[0].detect= state_array->state[0].detect=
((levels & (LINKUP_CD1 | LINKUP_CD2))==0)?1:0; ((levels & (LINKUP_CD1 | LINKUP_CD2))==0)?1:0;
...@@ -114,7 +123,7 @@ static int freebird_pcmcia_configure_socket(const struct pcmcia_configure ...@@ -114,7 +123,7 @@ static int freebird_pcmcia_configure_socket(const struct pcmcia_configure
if(configure->sock==1) return 0; if(configure->sock==1) return 0;
save_flags_cli(flags); local_irq_save(flags);
value = 0xc0; /* SSP=1 SOE=1 CFE=1 */ value = 0xc0; /* SSP=1 SOE=1 CFE=1 */
...@@ -134,7 +143,7 @@ static int freebird_pcmcia_configure_socket(const struct pcmcia_configure ...@@ -134,7 +143,7 @@ static int freebird_pcmcia_configure_socket(const struct pcmcia_configure
default: default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc); configure->vcc);
restore_flags(flags); local_irq_restore(flags);
return -1; return -1;
} }
...@@ -145,16 +154,51 @@ static int freebird_pcmcia_configure_socket(const struct pcmcia_configure ...@@ -145,16 +154,51 @@ static int freebird_pcmcia_configure_socket(const struct pcmcia_configure
LINKUP_PRC = value; LINKUP_PRC = value;
//printk("LINKUP_PRC=%x\n",value); //printk("LINKUP_PRC=%x\n",value);
restore_flags(flags); local_irq_restore(flags);
return 0; return 0;
} }
struct pcmcia_low_level freebird_pcmcia_ops = { static int freebird_pcmcia_socket_init(int sock)
freebird_pcmcia_init, {
freebird_pcmcia_shutdown, if (sock == 1) {
freebird_pcmcia_socket_state, set_irq_type(IRQ_GPIO_FREEBIRD_CF_CD, IRQT_BOTHEDGE);
freebird_pcmcia_get_irq_info, set_irq_type(IRQ_GPIO_FREEBIRD_CF_BVD, IRQT_BOTHEDGE);
freebird_pcmcia_configure_socket }
return 0;
}
static int freebird_pcmcia_socket_suspend(int sock)
{
if (sock == 1) {
set_irq_type(IRQ_GPIO_FREEBIRD_CF_CD, IRQT_NOEDGE);
set_irq_type(IRQ_GPIO_FREEBIRD_CF_BVD, IRQT_NOEDGE);
}
return 0;
}
static struct pcmcia_low_level freebird_pcmcia_ops = {
init: freebird_pcmcia_init,
shutdown: freebird_pcmcia_shutdown,
socket_state: freebird_pcmcia_socket_state,
get_irq_info: freebird_pcmcia_get_irq_info,
configure_socket: freebird_pcmcia_configure_socket,
socket_init: freebird_pcmcia_socket_init,
socket_suspend: freebird_pcmcia_socket_suspend,
}; };
int __init pcmcia_freebird_init(void)
{
int ret = -ENODEV;
if (machine_is_freebird())
ret = sa1100_register_pcmcia(&freebird_pcmcia_ops);
return ret;
}
void __exit pcmcia_freebird_exit(void)
{
sa1100_unregister_pcmcia(&freebird_pcmcia_ops);
}
This diff is collapsed.
/*
* linux/include/asm/arch/pcmcia.h
*
* Copyright (C) 2000 John G Dorsey <john+@cs.cmu.edu>
*
* This file contains definitions for the low-level SA-1100 kernel PCMCIA
* interface. Please see linux/Documentation/arm/SA1100/PCMCIA for details.
*/
#ifndef _ASM_ARCH_PCMCIA
#define _ASM_ARCH_PCMCIA
/* Ideally, we'd support up to MAX_SOCK sockets, but the SA-1100 only
* has support for two. This shows up in lots of hardwired ways, such
* as the fact that MECR only has enough bits to configure two sockets.
* Since it's so entrenched in the hardware, limiting the software
* in this way doesn't seem too terrible.
*/
#define SA1100_PCMCIA_MAX_SOCK (2)
struct pcmcia_init {
void (*handler)(int irq, void *dev, struct pt_regs *regs);
};
struct pcmcia_state {
unsigned detect: 1,
ready: 1,
bvd1: 1,
bvd2: 1,
wrprot: 1,
vs_3v: 1,
vs_Xv: 1;
};
struct pcmcia_state_array {
unsigned int size;
struct pcmcia_state *state;
};
struct pcmcia_configure {
unsigned sock: 8,
vcc: 8,
vpp: 8,
output: 1,
speaker: 1,
reset: 1,
irq: 1;
};
struct pcmcia_irq_info {
unsigned int sock;
unsigned int irq;
};
struct pcmcia_low_level {
int (*init)(struct pcmcia_init *);
int (*shutdown)(void);
int (*socket_state)(struct pcmcia_state_array *);
int (*get_irq_info)(struct pcmcia_irq_info *);
int (*configure_socket)(const struct pcmcia_configure *);
/*
* Enable card status IRQs on (re-)initialisation. This can
* be called at initialisation, power management event, or
* pcmcia event.
*/
int (*socket_init)(int sock);
/*
* Disable card status IRQs and PCMCIA bus on suspend.
*/
int (*socket_suspend)(int sock);
};
extern int sa1100_register_pcmcia(struct pcmcia_low_level *);
extern void sa1100_unregister_pcmcia(struct pcmcia_low_level *);
#endif
...@@ -14,10 +14,13 @@ ...@@ -14,10 +14,13 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/init.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/arch/pcmcia.h> #include "sa1100_generic.h"
#error This is broken!
#define S0_CD_IRQ 60 // Socket 0 Card Detect IRQ #define S0_CD_IRQ 60 // Socket 0 Card Detect IRQ
#define S0_STS_IRQ 55 // Socket 0 PCMCIA IRQ #define S0_STS_IRQ 55 // Socket 0 PCMCIA IRQ
...@@ -47,8 +50,9 @@ static int gcplus_pcmcia_init(struct pcmcia_init *init) ...@@ -47,8 +50,9 @@ static int gcplus_pcmcia_init(struct pcmcia_init *init)
irq = S0_CD_IRQ; irq = S0_CD_IRQ;
res = request_irq(irq, init->handler, SA_INTERRUPT, "PCMCIA 0 CD", NULL); res = request_irq(irq, init->handler, SA_INTERRUPT, "PCMCIA 0 CD", NULL);
if (res < 0) { if (res < 0) {
printk(KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq); printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
return -1; __FUNCTION__, irq, res);
return res;
} }
return 1; // 1 PCMCIA Slot return 1; // 1 PCMCIA Slot
...@@ -106,7 +110,7 @@ static int gcplus_pcmcia_configure_socket(const struct pcmcia_configure ...@@ -106,7 +110,7 @@ static int gcplus_pcmcia_configure_socket(const struct pcmcia_configure
if(configure->sock>1) return -1; if(configure->sock>1) return -1;
save_flags_cli(flags); local_irq_save(flags);
switch (configure->vcc) { switch (configure->vcc) {
case 0: case 0:
...@@ -126,7 +130,7 @@ static int gcplus_pcmcia_configure_socket(const struct pcmcia_configure ...@@ -126,7 +130,7 @@ static int gcplus_pcmcia_configure_socket(const struct pcmcia_configure
default: default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc); configure->vcc);
restore_flags(flags); local_irq_restore(flags);
return -1; return -1;
} }
...@@ -139,16 +143,44 @@ static int gcplus_pcmcia_configure_socket(const struct pcmcia_configure ...@@ -139,16 +143,44 @@ static int gcplus_pcmcia_configure_socket(const struct pcmcia_configure
*PCMCIA_Power |= ADS_CS_PR_A_RESET; *PCMCIA_Power |= ADS_CS_PR_A_RESET;
mdelay(30); mdelay(30);
restore_flags(flags); local_irq_restore(flags);
return 0; return 0;
} }
struct pcmcia_low_level gcplus_pcmcia_ops = { static int gcplus_pcmcia_socket_init(int sock)
gcplus_pcmcia_init, {
gcplus_pcmcia_shutdown, return 0;
gcplus_pcmcia_socket_state, }
gcplus_pcmcia_get_irq_info,
gcplus_pcmcia_configure_socket static int gcplus_pcmcia_socket_suspend(int sock)
{
return 0;
}
static struct pcmcia_low_level gcplus_pcmcia_ops = {
init: gcplus_pcmcia_init,
shutdown: gcplus_pcmcia_shutdown,
socket_state: gcplus_pcmcia_socket_state,
get_irq_info: gcplus_pcmcia_get_irq_info,
configure_socket: gcplus_pcmcia_configure_socket,
socket_init: gcplus_pcmcia_socket_init,
socket_suspend: gcplus_pcmcia_socket_suspend,
}; };
int __init pcmcia_gcplus_init(void)
{
int ret = -ENODEV;
if (machine_is_gcplus())
ret = sa1100_register_pcmcia(&gcplus_pcmcia_ops);
return ret;
}
void __exit pcmcia_gcplus_exit(void)
{
sa1100_unregister_pcmcia(&gcplus_pcmcia_ops);
}
...@@ -10,11 +10,12 @@ ...@@ -10,11 +10,12 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h>
#include <asm/delay.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/arch/pcmcia.h> #include "sa1100_generic.h"
#include "sa1111_generic.h"
static int graphicsmaster_pcmcia_init(struct pcmcia_init *init) static int graphicsmaster_pcmcia_init(struct pcmcia_init *init)
{ {
...@@ -26,190 +27,82 @@ static int graphicsmaster_pcmcia_init(struct pcmcia_init *init) ...@@ -26,190 +27,82 @@ static int graphicsmaster_pcmcia_init(struct pcmcia_init *init)
/* Disable Power 3.3V/5V for PCMCIA/CF */ /* Disable Power 3.3V/5V for PCMCIA/CF */
PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3; PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3;
INTPOL1 |= (1 << (S0_READY_NINT - SA1111_IRQ(32))) | /* why? */
(1 << (S1_READY_NINT - SA1111_IRQ(32))) |
(1 << (S0_CD_VALID - SA1111_IRQ(32))) |
(1 << (S1_CD_VALID - SA1111_IRQ(32))) |
(1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
(1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
"GC Master PCMCIA (0) CD", NULL);
return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
"GC Master CF (1) CD", NULL);
return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
"GC Master PCMCIA (0) BVD1", NULL);
return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
"GC Master CF (1) BVD1", NULL);
MECR = 0x09430943; MECR = 0x09430943;
return (return_val<0) ? -1 : 2; return sa1111_pcmcia_init(init);
}
static int graphicsmaster_pcmcia_shutdown(void)
{
free_irq(S0_CD_VALID, NULL);
free_irq(S1_CD_VALID, NULL);
free_irq(S0_BVD1_STSCHG, NULL);
free_irq(S1_BVD1_STSCHG, NULL);
INTPOL1 &= ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
(1 << (S1_CD_VALID - SA1111_IRQ(32))) |
(1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
(1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
return 0;
}
static int graphicsmaster_pcmcia_socket_state(struct pcmcia_state_array *state_array)
{
unsigned long status;
int return_val=1;
if(state_array->size<2) return -1;
memset(state_array->state, 0,
(state_array->size)*sizeof(struct pcmcia_state));
status=PCSR;
state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
return return_val;
}
static int graphicsmaster_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
{
switch(info->sock){
case 0:
info->irq=S0_READY_NINT;
break;
case 1:
info->irq=S1_READY_NINT;
break;
default:
return -1;
}
return 0;
} }
static int graphicsmaster_pcmcia_configure_socket(const struct pcmcia_configure *configure) static int
graphicsmaster_pcmcia_configure_socket(const struct pcmcia_configure *conf)
{ {
unsigned long pccr=PCCR, gpio=PA_DWR; unsigned int pa_dwr_mask, pa_dwr_set;
int ret;
switch(configure->sock){ switch (conf->sock) {
case 0: case 0:
pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
switch(configure->vcc){ switch (conf->vcc) {
case 0:
pccr = (pccr & ~PCCR_S0_FLT);
gpio |= GPIO_GPIO0 | GPIO_GPIO1;
break;
case 33:
pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1);
gpio &= ~GPIO_GPIO0;
break;
case 50:
pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1);
gpio |= GPIO_GPIO0;
break;
default: default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, case 0: pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1; break;
configure->vcc); case 33: pa_dwr_set = GPIO_GPIO1; break;
return -1; case 50: pa_dwr_set = GPIO_GPIO0; break;
} }
pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
break; break;
case 1: case 1:
switch(configure->vcc){ pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3;
case 0:
pccr = (pccr & ~PCCR_S1_FLT);
gpio |= GPIO_GPIO2 | GPIO_GPIO3;
break;
case 33:
pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
gpio &= ~GPIO_GPIO2;
break;
case 50:
pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN);
gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
gpio |= GPIO_GPIO2;
break;
switch (conf->vcc) {
default: default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, case 0: pa_dwr_set = GPIO_GPIO2 | GPIO_GPIO3; break;
configure->vcc); case 33: pa_dwr_set = GPIO_GPIO3; break;
return -1; case 50: pa_dwr_set = GPIO_GPIO2; break;
}
if(configure->vpp!=configure->vcc && configure->vpp!=0){
printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
configure->vpp);
return -1;
} }
}
pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST); if (conf->vpp != conf->vcc && conf->vpp != 0) {
printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
break; conf->vpp);
default:
return -1; return -1;
} }
PCCR = pccr; ret = sa1111_pcmcia_configure_socket(conf);
PA_DWR = gpio; if (ret == 0) {
unsigned long flags;
local_irq_save(flags);
PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
local_irq_restore(flags);
}
return 0; return ret;
} }
struct pcmcia_low_level graphicsmaster_pcmcia_ops = { static struct pcmcia_low_level graphicsmaster_pcmcia_ops = {
graphicsmaster_pcmcia_init, init: graphicsmaster_pcmcia_init,
graphicsmaster_pcmcia_shutdown, shutdown: sa1111_pcmcia_shutdown,
graphicsmaster_pcmcia_socket_state, socket_state: sa1111_pcmcia_socket_state,
graphicsmaster_pcmcia_get_irq_info, get_irq_info: sa1111_pcmcia_get_irq_info,
graphicsmaster_pcmcia_configure_socket configure_socket: graphicsmaster_pcmcia_configure_socket,
socket_init: sa1111_pcmcia_socket_init,
socket_suspend: sa1111_pcmcia_socket_suspend,
}; };
int __init pcmcia_graphicsmaster_init(void)
{
int ret = -ENODEV;
if (machine_is_graphicsmaster())
ret = sa1100_register_pcmcia(&graphicsmaster_pcmcia_ops);
return ret;
}
void __exit pcmcia_graphicsmaster_exit(void)
{
sa1100_unregister_pcmcia(&graphicsmaster_pcmcia_ops);
}
...@@ -6,142 +6,192 @@ ...@@ -6,142 +6,192 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/arch/pcmcia.h> #include "sa1100_generic.h"
static struct irqs {
static int h3600_pcmcia_init(struct pcmcia_init *init){ int irq;
int irq, res; const char *str;
} irqs[] = {
/* Enable CF bus: */ { IRQ_GPIO_H3600_PCMCIA_CD0, "PCMCIA CD0" },
set_h3600_egpio(EGPIO_H3600_OPT_NVRAM_ON); { IRQ_GPIO_H3600_PCMCIA_CD1, "PCMCIA CD1" }
clr_h3600_egpio(EGPIO_H3600_OPT_RESET); };
/* All those are inputs */
GPDR &= ~(GPIO_H3600_PCMCIA_CD0 | GPIO_H3600_PCMCIA_CD1 | GPIO_H3600_PCMCIA_IRQ0| GPIO_H3600_PCMCIA_IRQ1);
/* Set transition detect */
set_GPIO_IRQ_edge( GPIO_H3600_PCMCIA_CD0 | GPIO_H3600_PCMCIA_CD1, GPIO_BOTH_EDGES );
set_GPIO_IRQ_edge( GPIO_H3600_PCMCIA_IRQ0| GPIO_H3600_PCMCIA_IRQ1, GPIO_FALLING_EDGE );
/* Register interrupts */
irq = IRQ_GPIO_H3600_PCMCIA_CD0;
res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD0", NULL );
if( res < 0 ) goto irq_err;
irq = IRQ_GPIO_H3600_PCMCIA_CD1;
res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD1", NULL );
if( res < 0 ) goto irq_err;
return 2;
irq_err: static int h3600_pcmcia_init(struct pcmcia_init *init)
printk( KERN_ERR __FUNCTION__ ": Request for IRQ %u failed\n", irq ); {
return -1; int i, res;
/*
* Set transition detect
*/
set_irq_type(IRQ_GPIO_H3600_PCMCIA_IRQ0, IRQT_FALLING);
set_irq_type(IRQ_GPIO_H3600_PCMCIA_IRQ1, IRQT_FALLING);
/*
* Register interrupts
*/
for (i = res = 0; i < ARRAY_SIZE(irqs); i++) {
res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
irqs[i].str, NULL);
if (res)
break;
}
if (res) {
printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
__FUNCTION__, irqs[i].irq, res);
while (i--)
free_irq(irqs[i].irq, NULL);
}
return res ? res : 2;
} }
static int h3600_pcmcia_shutdown(void) static int h3600_pcmcia_shutdown(void)
{ {
/* disable IRQs */ int i;
free_irq( IRQ_GPIO_H3600_PCMCIA_CD0, NULL );
free_irq( IRQ_GPIO_H3600_PCMCIA_CD1, NULL ); /*
* disable IRQs
*/
for (i = 0; i < ARRAY_SIZE(irqs); i++)
free_irq(irqs[i].irq, NULL);
/* Disable CF bus: */ /* Disable CF bus: */
clr_h3600_egpio(EGPIO_H3600_OPT_NVRAM_ON|EGPIO_H3600_OPT_ON); clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
set_h3600_egpio(EGPIO_H3600_OPT_RESET); clr_h3600_egpio(IPAQ_EGPIO_OPT_ON);
set_h3600_egpio(IPAQ_EGPIO_OPT_RESET);
return 0; return 0;
} }
static int h3600_pcmcia_socket_state(struct pcmcia_state_array static int
*state_array){ h3600_pcmcia_socket_state(struct pcmcia_state_array *state)
unsigned long levels; {
unsigned long levels;
if(state_array->size<2) return -1;
if (state->size < 2)
memset(state_array->state, 0, return -1;
(state_array->size)*sizeof(struct pcmcia_state));
levels = GPLR;
levels=GPLR;
state->state[0].detect = levels & GPIO_H3600_PCMCIA_CD0 ? 0 : 1;
state_array->state[0].detect=((levels & GPIO_H3600_PCMCIA_CD0)==0)?1:0; state->state[0].ready = levels & GPIO_H3600_PCMCIA_IRQ0 ? 1 : 0;
state_array->state[0].ready=(levels & GPIO_H3600_PCMCIA_IRQ0)?1:0; state->state[0].bvd1 = 0;
state_array->state[0].bvd1= 0; state->state[0].bvd2 = 0;
state_array->state[0].bvd2= 0; state->state[0].wrprot = 0; /* Not available on H3600. */
state_array->state[0].wrprot=0; /* Not available on H3600. */ state->state[0].vs_3v = 0;
state_array->state[0].vs_3v=0; state->state[0].vs_Xv = 0;
state_array->state[0].vs_Xv=0;
state->state[1].detect = levels & GPIO_H3600_PCMCIA_CD1 ? 0 : 1;
state_array->state[1].detect=((levels & GPIO_H3600_PCMCIA_CD1)==0)?1:0; state->state[1].ready = levels & GPIO_H3600_PCMCIA_IRQ1 ? 1 : 0;
state_array->state[1].ready=(levels & GPIO_H3600_PCMCIA_IRQ1)?1:0; state->state[1].bvd1 = 0;
state_array->state[1].bvd1=0; state->state[1].bvd2 = 0;
state_array->state[1].bvd2=0; state->state[1].wrprot = 0; /* Not available on H3600. */
state_array->state[1].wrprot=0; /* Not available on H3600. */ state->state[1].vs_3v = 0;
state_array->state[1].vs_3v=0; state->state[1].vs_Xv = 0;
state_array->state[1].vs_Xv=0;
return 1;
return 1;
} }
static int h3600_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ static int h3600_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
{
switch (info->sock) { switch (info->sock) {
case 0: case 0:
info->irq=IRQ_GPIO_H3600_PCMCIA_IRQ0; info->irq = IRQ_GPIO_H3600_PCMCIA_IRQ0;
break; break;
case 1: case 1:
info->irq=IRQ_GPIO_H3600_PCMCIA_IRQ1; info->irq = IRQ_GPIO_H3600_PCMCIA_IRQ1;
break; break;
default: default:
return -1; return -1;
} }
return 0; return 0;
} }
static int h3600_pcmcia_configure_socket(const struct pcmcia_configure static int
*configure) h3600_pcmcia_configure_socket(const struct pcmcia_configure *conf)
{ {
unsigned long flags; if (conf->sock > 1)
return -1;
if(configure->sock>1) return -1;
save_flags_cli(flags); if (conf->vcc != 0 && conf->vcc != 33 && conf->vcc != 50) {
printk(KERN_ERR "h3600_pcmcia: unrecognized Vcc %u.%uV\n",
conf->vcc / 10, conf->vcc % 10);
return -1;
}
switch (configure->vcc) { if (conf->reset)
case 0: set_h3600_egpio(IPAQ_EGPIO_CARD_RESET);
clr_h3600_egpio(EGPIO_H3600_OPT_ON); else
break; clr_h3600_egpio(IPAQ_EGPIO_CARD_RESET);
case 33: /* Silently ignore Vpp, output enable, speaker enable. */
case 50:
set_h3600_egpio(EGPIO_H3600_OPT_ON);
break;
default: return 0;
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, }
configure->vcc);
restore_flags(flags);
return -1;
}
if (configure->reset)
set_h3600_egpio(EGPIO_H3600_CARD_RESET);
else
clr_h3600_egpio(EGPIO_H3600_CARD_RESET);
/* Silently ignore Vpp, output enable, speaker enable. */
restore_flags(flags); static int h3600_pcmcia_socket_init(int sock)
{
/* Enable CF bus: */
set_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
set_h3600_egpio(IPAQ_EGPIO_OPT_ON);
clr_h3600_egpio(IPAQ_EGPIO_OPT_RESET);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(10*HZ / 1000);
switch (sock) {
case 0:
set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD0, IRQT_BOTHEDGE);
break;
case 1:
set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD1, IRQT_BOTHEDGE);
break;
}
return 0;
}
return 0; static int h3600_pcmcia_socket_suspend(int sock)
{
switch (sock) {
case 0:
set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD0, IRQT_NOEDGE);
break;
case 1:
set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD1, IRQT_NOEDGE);
break;
}
/*
* FIXME: This doesn't fit well. We don't have the mechanism in
* the generic PCMCIA layer to deal with the idea of two sockets
* on one bus. We rely on the cs.c behaviour shutting down
* socket 0 then socket 1.
*/
if (sock == 1) {
clr_h3600_egpio(IPAQ_EGPIO_OPT_ON);
clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
/* hmm, does this suck power? */
set_h3600_egpio(IPAQ_EGPIO_OPT_RESET);
}
return 0;
} }
struct pcmcia_low_level h3600_pcmcia_ops = { struct pcmcia_low_level h3600_pcmcia_ops = {
h3600_pcmcia_init, init: h3600_pcmcia_init,
h3600_pcmcia_shutdown, shutdown: h3600_pcmcia_shutdown,
h3600_pcmcia_socket_state, socket_state: h3600_pcmcia_socket_state,
h3600_pcmcia_get_irq_info, get_irq_info: h3600_pcmcia_get_irq_info,
h3600_pcmcia_configure_socket configure_socket: h3600_pcmcia_configure_socket,
socket_init: h3600_pcmcia_socket_init,
socket_suspend: h3600_pcmcia_socket_suspend,
}; };
...@@ -6,21 +6,24 @@ ...@@ -6,21 +6,24 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h>
#include <asm/delay.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/arch/pcmcia.h> #include "sa1100_generic.h"
#include "sa1111_generic.h"
#define SOCKET0_POWER GPIO_GPIO0 #define SOCKET0_POWER GPIO_GPIO0
#define SOCKET0_3V GPIO_GPIO2 #define SOCKET0_3V GPIO_GPIO2
#define SOCKET1_POWER (GPIO_GPIO1 | GPIO_GPIO3) #define SOCKET1_POWER (GPIO_GPIO1 | GPIO_GPIO3)
#define SOCKET1_3V GPIO_GPIO3 #warning *** Does SOCKET1_3V actually do anything?
#define SOCKET1_3V GPIO_GPIO3
static int jornada720_pcmcia_init(struct pcmcia_init *init) static int jornada720_pcmcia_init(struct pcmcia_init *init)
{ {
int return_val=0; /*
* What is all this crap for?
*/
GRER |= 0x00000002; GRER |= 0x00000002;
/* Set GPIO_A<3:1> to be outputs for PCMCIA/CF power controller: */ /* Set GPIO_A<3:1> to be outputs for PCMCIA/CF power controller: */
PA_DDR = 0; PA_DDR = 0;
...@@ -38,178 +41,82 @@ static int jornada720_pcmcia_init(struct pcmcia_init *init) ...@@ -38,178 +41,82 @@ static int jornada720_pcmcia_init(struct pcmcia_init *init)
PC_SDR = 0; PC_SDR = 0;
PC_SSR = 0; PC_SSR = 0;
INTPOL1 |= return sa1111_pcmcia_init(init);
(1 << (S0_READY_NINT - SA1111_IRQ(32))) |
(1 << (S1_READY_NINT - SA1111_IRQ(32))) |
(1 << (S0_CD_VALID - SA1111_IRQ(32))) |
(1 << (S1_CD_VALID - SA1111_IRQ(32))) |
(1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
(1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
"Jornada720 PCMCIA (0) CD", NULL);
return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
"Jornada720 CF (1) CD", NULL);
return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
"Jornada720 PCMCIA (0) BVD1", NULL);
return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
"Jornada720 CF (1) BVD1", NULL);
return (return_val<0) ? -1 : 2;
}
static int jornada720_pcmcia_shutdown(void)
{
free_irq(S0_CD_VALID, NULL);
free_irq(S1_CD_VALID, NULL);
free_irq(S0_BVD1_STSCHG, NULL);
free_irq(S1_BVD1_STSCHG, NULL);
INTPOL1 &=
~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
(1 << (S1_CD_VALID - SA1111_IRQ(32))) |
(1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
(1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
return 0;
}
static int jornada720_pcmcia_socket_state(struct pcmcia_state_array
*state_array)
{
unsigned long status;
int return_val=1;
if(state_array->size<2) return -1;
memset(state_array->state, 0,
(state_array->size)*sizeof(struct pcmcia_state));
status=PCSR;
state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
return return_val;
}
static int jornada720_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
{
switch(info->sock){
case 0:
info->irq=S0_READY_NINT;
break;
case 1:
info->irq=S1_READY_NINT;
break;
default:
return -1;
}
return 0;
} }
static int jornada720_pcmcia_configure_socket(const struct pcmcia_configure static int
*configure) jornada720_pcmcia_configure_socket(const struct pcmcia_configure *conf)
{ {
unsigned long pccr=PCCR, gpio=PA_DWR; unsigned int pa_dwr_mask, pa_dwr_set;
int ret;
printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__, printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__,
configure->sock, configure->vcc, configure->vpp); conf->sock, conf->vcc, conf->vpp);
switch(configure->sock){
switch (conf->sock) {
case 0: case 0:
switch(configure->vcc){ pa_dwr_mask = SOCKET0_POWER | SOCKET0_3V;
case 0:
pccr = (pccr & ~PCCR_S0_FLT);
gpio&=~(SOCKET0_POWER | SOCKET0_3V);
break;
case 33:
pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
gpio |= SOCKET0_POWER | SOCKET0_3V;
break;
case 50:
pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
gpio = (gpio & ~SOCKET0_3V) | SOCKET0_POWER;
break;
switch (conf->vcc) {
default: default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, case 0: pa_dwr_set = 0; break;
configure->vcc); case 33: pa_dwr_set = SOCKET0_POWER | SOCKET0_3V; break;
return -1; case 50: pa_dwr_set = SOCKET0_POWER; break;
}
switch(configure->vpp){
case 0:
break;
case 50:
printk(KERN_ERR "%s(): 5.0 Vpp %u\n", __FUNCTION__,
configure->vpp);
break;
case 120:
printk(KERN_ERR "%s(): 12 Vpp %u\n", __FUNCTION__,
configure->vpp);
break;
default:
printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__,
configure->vpp);
return -1;
} }
pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
break; break;
case 1: case 1:
switch(configure->vcc){ pa_dwr_mask = SOCKET1_POWER;
case 0:
pccr = (pccr & ~PCCR_S1_FLT);
gpio &= ~(SOCKET1_POWER);
break;
case 33:
pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
gpio |= SOCKET1_POWER;
break;
case 50:
pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN);
gpio = (gpio & ~(SOCKET1_POWER)) | SOCKET1_POWER;
break;
switch (conf->vcc) {
default: default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, case 0: pa_dwr_set = 0; break;
configure->vcc); case 33: pa_dwr_set = SOCKET1_POWER; break;
return -1; case 50: pa_dwr_set = SOCKET1_POWER; break;
} }
if(configure->vpp!=configure->vcc && configure->vpp!=0){
printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
configure->vpp);
return -1;
}
pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
break; break;
default: }
if (conf->vpp != conf->vcc && conf->vpp != 0) {
printk(KERN_ERR "%s(): slot cannot support VPP %u\n",
__FUNCTION__, conf->vpp);
return -1; return -1;
} }
PCCR = pccr;
PA_DWR = gpio; ret = sa1111_pcmcia_configure_socket(conf);
return 0; if (ret == 0) {
unsigned long flags;
local_irq_save(flags);
PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
locla_irq_restore(flags);
}
return ret;
} }
struct pcmcia_low_level jornada720_pcmcia_ops = { static struct pcmcia_low_level jornada720_pcmcia_ops = {
jornada720_pcmcia_init, init: jornada720_pcmcia_init,
jornada720_pcmcia_shutdown, shutdown: sa1111_pcmcia_shutdown,
jornada720_pcmcia_socket_state, socket_state: sa1111_pcmcia_socket_state,
jornada720_pcmcia_get_irq_info, get_irq_info: sa1111_pcmcia_get_irq_info,
jornada720_pcmcia_configure_socket configure_socket: jornada720_pcmcia_configure_socket,
socket_init: sa1111_pcmcia_socket_init,
socket_suspend: sa1111_pcmcia_socket_suspend,
}; };
int __init pcmcia_jornada720_init(void)
{
int ret = -ENODEV;
if (machine_is_jornada720())
ret = sa1100_register_pcmcia(&jornada720_pcmcia_ops);
return ret;
}
void __exit pcmcia_jornada720_exit(void)
{
sa1100_unregister_pcmcia(&jornada720_pcmcia_ops);
}
/* /*
* drivers/pcmcia/sa1100_neponset.c * linux/drivers/pcmcia/sa1100_neponset.c
* *
* Neponset PCMCIA specific routines * Neponset PCMCIA specific routines
*
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h>
#include <asm/delay.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/arch/pcmcia.h>
#include <asm/arch/assabet.h> #include <asm/arch/assabet.h>
#include <asm/hardware/sa1111.h>
static int neponset_pcmcia_init(struct pcmcia_init *init){ #include "sa1100_generic.h"
int return_val=0; #include "sa1111_generic.h"
/* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
/* MAX1600 to standby mode: */
PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP);
INTPOL1 |=
(1 << (S0_READY_NINT - SA1111_IRQ(32))) |
(1 << (S1_READY_NINT - SA1111_IRQ(32))) |
(1 << (S0_CD_VALID - SA1111_IRQ(32))) |
(1 << (S1_CD_VALID - SA1111_IRQ(32))) |
(1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
(1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
"Neponset PCMCIA (0) CD", NULL);
return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
"Neponset CF (1) CD", NULL);
return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
"Neponset PCMCIA (0) BVD1", NULL);
return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
"Neponset CF (1) BVD1", NULL);
return (return_val<0) ? -1 : 2;
}
static int neponset_pcmcia_shutdown(void){
free_irq(S0_CD_VALID, NULL); static int neponset_pcmcia_init(struct pcmcia_init *init)
free_irq(S1_CD_VALID, NULL); {
free_irq(S0_BVD1_STSCHG, NULL); /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
free_irq(S1_BVD1_STSCHG, NULL); PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
INTPOL1 &= /* MAX1600 to standby mode: */
~((1 << (S0_CD_VALID - SA1111_IRQ(32))) | PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
(1 << (S1_CD_VALID - SA1111_IRQ(32))) | NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP);
(1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
(1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
return 0; return sa1111_pcmcia_init(init);
} }
static int neponset_pcmcia_socket_state(struct pcmcia_state_array static int
*state_array){ neponset_pcmcia_configure_socket(const struct pcmcia_configure *conf)
unsigned long status; {
int return_val=1; unsigned int ncr_mask, pa_dwr_mask;
unsigned int ncr_set, pa_dwr_set;
if(state_array->size<2) return -1; int ret;
memset(state_array->state, 0, /* Neponset uses the Maxim MAX1600, with the following connections:
(state_array->size)*sizeof(struct pcmcia_state));
* MAX1600 Neponset
status=PCSR; *
* A0VCC SA-1111 GPIO A<1>
state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0; * A1VCC SA-1111 GPIO A<0>
* A0VPP CPLD NCR A0VPP
state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1; * A1VPP CPLD NCR A1VPP
* B0VCC SA-1111 GPIO A<2>
state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1; * B1VCC SA-1111 GPIO A<3>
* B0VPP ground (slot B is CF)
state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1; * B1VPP ground (slot B is CF)
*
state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1; * VX VCC (5V)
* VY VCC3_3 (3.3V)
state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0; * 12INA 12V
* 12INB ground (slot B is CF)
state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0; *
* The MAX1600 CODE pin is tied to ground, placing the device in
state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0; * "Standard Intel code" mode. Refer to the Maxim data sheet for
* the corresponding truth table.
state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1; */
state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1; switch (conf->sock) {
case 0:
state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1; pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
ncr_mask = NCR_A0VPP | NCR_A1VPP;
state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
switch (conf->vcc) {
state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0; default:
case 0: pa_dwr_set = 0; break;
state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0; case 33: pa_dwr_set = GPIO_GPIO1; break;
case 50: pa_dwr_set = GPIO_GPIO0; break;
return return_val; }
switch (conf->vpp) {
case 0: ncr_set = 0; break;
case 120: ncr_set = NCR_A1VPP; break;
default:
if (conf->vpp == conf->vcc)
ncr_set = NCR_A0VPP;
else {
printk(KERN_ERR "%s(): unrecognized VPP %u\n",
__FUNCTION__, conf->vpp);
return -1;
}
}
break;
case 1:
pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3;
ncr_mask = 0;
ncr_set = 0;
switch (conf->vcc) {
default:
case 0: pa_dwr_set = 0; break;
case 33: pa_dwr_set = GPIO_GPIO2; break;
case 50: pa_dwr_set = GPIO_GPIO3; break;
}
if (conf->vpp != conf->vcc && conf->vpp != 0) {
printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
__FUNCTION__, conf->vpp);
return -1;
}
break;
default:
return -1;
}
ret = sa1111_pcmcia_configure_socket(conf);
if (ret == 0) {
unsigned long flags;
local_irq_save(flags);
NCR_0 = (NCR_0 & ~ncr_mask) | ncr_set;
PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
local_irq_restore(flags);
}
return 0;
} }
static int neponset_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ static struct pcmcia_low_level neponset_pcmcia_ops = {
init: neponset_pcmcia_init,
shutdown: sa1111_pcmcia_shutdown,
socket_state: sa1111_pcmcia_socket_state,
get_irq_info: sa1111_pcmcia_get_irq_info,
configure_socket: neponset_pcmcia_configure_socket,
switch(info->sock){ socket_init: sa1111_pcmcia_socket_init,
case 0: socket_suspend: sa1111_pcmcia_socket_suspend,
info->irq=S0_READY_NINT; };
break;
case 1: int __init pcmcia_neponset_init(void)
info->irq=S1_READY_NINT; {
break; int ret = -ENODEV;
default: if (machine_is_assabet() && machine_has_neponset())
return -1; ret = sa1100_register_pcmcia(&neponset_pcmcia_ops);
}
return 0; return ret;
} }
static int neponset_pcmcia_configure_socket(const struct pcmcia_configure void __exit pcmcia_neponset_exit(void)
*configure){ {
unsigned long pccr=PCCR, ncr=NCR_0, gpio=PA_DWR; sa1100_unregister_pcmcia(&neponset_pcmcia_ops);
/* Neponset uses the Maxim MAX1600, with the following connections:
*
* MAX1600 Neponset
*
* A0VCC SA-1111 GPIO A<1>
* A1VCC SA-1111 GPIO A<0>
* A0VPP CPLD NCR A0VPP
* A1VPP CPLD NCR A1VPP
* B0VCC SA-1111 GPIO A<2>
* B1VCC SA-1111 GPIO A<3>
* B0VPP ground (slot B is CF)
* B1VPP ground (slot B is CF)
*
* VX VCC (5V)
* VY VCC3_3 (3.3V)
* 12INA 12V
* 12INB ground (slot B is CF)
*
* The MAX1600 CODE pin is tied to ground, placing the device in
* "Standard Intel code" mode. Refer to the Maxim data sheet for
* the corresponding truth table.
*/
switch(configure->sock){
case 0:
switch(configure->vcc){
case 0:
pccr=(pccr & ~PCCR_S0_FLT);
gpio&=~(GPIO_GPIO0 | GPIO_GPIO1);
break;
case 33:
pccr=(pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
gpio=(gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO1;
break;
case 50:
pccr=(pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
gpio=(gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO0;
break;
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc);
return -1;
}
switch(configure->vpp){
case 0:
ncr&=~(NCR_A0VPP | NCR_A1VPP);
break;
case 120:
ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A1VPP;
break;
default:
if(configure->vpp == configure->vcc)
ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A0VPP;
else {
printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__,
configure->vpp);
return -1;
}
}
pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
break;
case 1:
switch(configure->vcc){
case 0:
pccr=(pccr & ~PCCR_S1_FLT);
gpio&=~(GPIO_GPIO2 | GPIO_GPIO3);
break;
case 33:
pccr=(pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
gpio=(gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO2;
break;
case 50:
pccr=(pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN);
gpio=(gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO3;
break;
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc);
return -1;
}
if(configure->vpp!=configure->vcc && configure->vpp!=0){
printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
configure->vpp);
return -1;
}
pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
break;
default:
return -1;
}
PCCR = pccr;
NCR_0 = ncr;
PA_DWR = gpio;
return 0;
} }
struct pcmcia_low_level neponset_pcmcia_ops = {
neponset_pcmcia_init,
neponset_pcmcia_shutdown,
neponset_pcmcia_socket_state,
neponset_pcmcia_get_irq_info,
neponset_pcmcia_configure_socket
};
...@@ -4,48 +4,45 @@ ...@@ -4,48 +4,45 @@
* PCMCIA implementation routines for Pangolin * PCMCIA implementation routines for Pangolin
* *
*/ */
#include <linux/config.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/arch/pcmcia.h> #include "sa1100_generic.h"
static int pangolin_pcmcia_init(struct pcmcia_init *init){ static int pangolin_pcmcia_init(struct pcmcia_init *init){
int irq, res; int res;
/* set GPIO_PCMCIA_CD & GPIO_PCMCIA_IRQ as inputs */
GPDR &= ~(GPIO_PCMCIA_CD|GPIO_PCMCIA_IRQ);
#ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
/* set GPIO pins GPIO_PCMCIA_BUS_ON & GPIO_PCMCIA_RESET as output */
GPDR |= (GPIO_PCMCIA_BUS_ON|GPIO_PCMCIA_RESET);
/* Enable PCMCIA bus: */ /* Enable PCMCIA bus: */
GPCR = GPIO_PCMCIA_BUS_ON; GPCR = GPIO_PCMCIA_BUS_ON;
#else
/* set GPIO pin GPIO_PCMCIA_RESET as output */
GPDR |= GPIO_PCMCIA_RESET;
#endif #endif
/* Set transition detect */ /* Set transition detect */
set_GPIO_IRQ_edge( GPIO_PCMCIA_CD, GPIO_BOTH_EDGES ); set_irq_type(IRQ_PCMCIA_CD, IRQT_NOEDGE);
set_GPIO_IRQ_edge( GPIO_PCMCIA_IRQ, GPIO_FALLING_EDGE ); set_irq_type(IRQ_PCMCIA_IRQ, IRQT_FALLING);
/* Register interrupts */ /* Register interrupts */
irq = IRQ_PCMCIA_CD; res = request_irq(IRQ_PCMCIA_CD, init->handler, SA_INTERRUPT,
res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD", NULL ); "PCMCIA_CD", NULL);
if( res < 0 ) goto irq_err; if (res >= 0)
/* There's only one slot, but it's "Slot 1": */
/* There's only one slot, but it's "Slot 1": */ return 2;
return 2;
irq_err: irq_err:
printk( KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq ); printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
return -1; __FUNCTION__, IRQ_PCMCIA_CD, res);
return res;
} }
static int pangolin_pcmcia_shutdown(void) static int pangolin_pcmcia_shutdown(void)
{ {
/* disable IRQs */ /* disable IRQs */
free_irq( IRQ_PCMCIA_CD, NULL ); free_irq(IRQ_PCMCIA_CD, NULL);
#ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
/* Disable PCMCIA bus: */ /* Disable PCMCIA bus: */
GPSR = GPIO_PCMCIA_BUS_ON; GPSR = GPIO_PCMCIA_BUS_ON;
...@@ -105,7 +102,7 @@ static int pangolin_pcmcia_configure_socket(const struct pcmcia_configure ...@@ -105,7 +102,7 @@ static int pangolin_pcmcia_configure_socket(const struct pcmcia_configure
#ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
if(configure->sock==0) return 0; if(configure->sock==0) return 0;
#endif #endif
save_flags_cli(flags); local_irq_save(flags);
/* Murphy: BUS_ON different from POWER ? */ /* Murphy: BUS_ON different from POWER ? */
...@@ -129,7 +126,7 @@ static int pangolin_pcmcia_configure_socket(const struct pcmcia_configure ...@@ -129,7 +126,7 @@ static int pangolin_pcmcia_configure_socket(const struct pcmcia_configure
default: default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc); configure->vcc);
restore_flags(flags); local_irq_restore(flags);
return -1; return -1;
} }
#ifdef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE #ifdef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
...@@ -143,15 +140,47 @@ static int pangolin_pcmcia_configure_socket(const struct pcmcia_configure ...@@ -143,15 +140,47 @@ static int pangolin_pcmcia_configure_socket(const struct pcmcia_configure
} }
#endif #endif
/* Silently ignore Vpp, output enable, speaker enable. */ /* Silently ignore Vpp, output enable, speaker enable. */
restore_flags(flags); local_irq_restore(flags);
return 0; return 0;
} }
struct pcmcia_low_level pangolin_pcmcia_ops = { static int pangolin_pcmcia_socket_init(int sock)
pangolin_pcmcia_init, {
pangolin_pcmcia_shutdown, if (sock == 1)
pangolin_pcmcia_socket_state, set_irq_type(IRQ_PCmCIA_CD, IRQT_BOTHEDGE);
pangolin_pcmcia_get_irq_info, return 0;
pangolin_pcmcia_configure_socket }
static int pangolin_pcmcia_socket_suspend(int sock)
{
if (sock == 1)
set_irq_type(IRQ_PCmCIA_CD, IRQT_NOEDGE);
return 0;
}
static struct pcmcia_low_level pangolin_pcmcia_ops = {
init: pangolin_pcmcia_init,
shutdown: pangolin_pcmcia_shutdown,
socket_state: pangolin_pcmcia_socket_state,
get_irq_info: pangolin_pcmcia_get_irq_info,
configure_socket: pangolin_pcmcia_configure_socket,
socket_init: pangolin_pcmcia_socket_init,
socket_suspend, pangolin_pcmcia_socket_suspend,
}; };
int __init pcmcia_pangolin_init(void)
{
int ret = -ENODEV;
if (machine_is_pangolin())
ret = sa1100_register_pcmcia(&pangolin_pcmcia_ops);
return ret;
}
void __exit pcmcia_pangolin_exit(void)
{
sa1100_unregister_pcmcia(&pangolin_pcmcia_ops);
}
This diff is collapsed.
/*
* drivers/pcmcia/sa1100_shannon.c
*
* PCMCIA implementation routines for Shannon
*
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <asm/hardware.h>
#include <asm/arch/shannon.h>
#include <asm/irq.h>
#include "sa1100_generic.h"
static struct irqs {
int irq;
const char *str;
} irqs[] = {
{ SHANNON_IRQ_GPIO_EJECT_0, "PCMCIA_CD_0" },
{ SHANNON_IRQ_GPIO_EJECT_1, "PCMCIA_CD_1" },
};
static int shannon_pcmcia_init(struct pcmcia_init *init)
{
int i, res;
/* All those are inputs */
GPDR &= ~(SHANNON_GPIO_EJECT_0 | SHANNON_GPIO_EJECT_1 |
SHANNON_GPIO_RDY_0 | SHANNON_GPIO_RDY_1);
GAFR &= ~(SHANNON_GPIO_EJECT_0 | SHANNON_GPIO_EJECT_1 |
SHANNON_GPIO_RDY_0 | SHANNON_GPIO_RDY_1);
/* Set transition detect */
set_irq_type(SHANNON_IRQ_GPIO_RDY_0, IRQT_FALLING);
set_irq_type(SHANNON_IRQ_GPIO_RDY_1, IRQT_FALLING);
/* Register interrupts */
for (i = 0; i < ARRAY_SIZE(irqs); i++) {
set_irq_type(irqs[i].irq, IRQT_NOEDGE);
res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
irqs[i].str, NULL);
if (res)
goto irq_err;
}
return 2;
irq_err:
printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
__FUNCTION__, irqs[i].irq, res);
while (i--)
free_irq(irqs[i].irq, NULL);
return res;
}
static int shannon_pcmcia_shutdown(void)
{
int i;
/* disable IRQs */
for (i = 0; i < ARRAY_SIZE(irqs); i++)
free_irq(irqs[i].irq, NULL);
return 0;
}
static int shannon_pcmcia_socket_state(struct pcmcia_state_array *state_array)
{
unsigned long levels;
memset(state_array->state, 0,
state_array->size * sizeof(struct pcmcia_state));
levels = GPLR;
state_array->state[0].detect = (levels & SHANNON_GPIO_EJECT_0) ? 0 : 1;
state_array->state[0].ready = (levels & SHANNON_GPIO_RDY_0) ? 1 : 0;
state_array->state[0].wrprot = 0; /* Not available on Shannon. */
state_array->state[0].bvd1 = 1;
state_array->state[0].bvd2 = 1;
state_array->state[0].vs_3v = 1; /* FIXME Can only apply 3.3V on Shannon. */
state_array->state[0].vs_Xv = 0;
state_array->state[1].detect = (levels & SHANNON_GPIO_EJECT_1) ? 0 : 1;
state_array->state[1].ready = (levels & SHANNON_GPIO_RDY_1) ? 1 : 0;
state_array->state[1].wrprot = 0; /* Not available on Shannon. */
state_array->state[1].bvd1 = 1;
state_array->state[1].bvd2 = 1;
state_array->state[1].vs_3v = 1; /* FIXME Can only apply 3.3V on Shannon. */
state_array->state[1].vs_Xv = 0;
return 1;
}
static int shannon_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
{
if (info->sock == 0)
info->irq = SHANNON_IRQ_GPIO_RDY_0;
else if (info->sock == 1)
info->irq = SHANNON_IRQ_GPIO_RDY_1;
else return -1;
return 0;
}
static int shannon_pcmcia_configure_socket(const struct pcmcia_configure *configure)
{
switch (configure->vcc) {
case 0: /* power off */
printk(KERN_WARNING __FUNCTION__"(): CS asked for 0V, still applying 3.3V..\n");
break;
case 50:
printk(KERN_WARNING __FUNCTION__"(): CS asked for 5V, applying 3.3V..\n");
case 33:
break;
default:
printk(KERN_ERR __FUNCTION__"(): unrecognized Vcc %u\n",
configure->vcc);
return -1;
}
printk(KERN_WARNING __FUNCTION__"(): Warning, Can't perform reset\n");
/* Silently ignore Vpp, output enable, speaker enable. */
return 0;
}
static int shannon_pcmcia_socket_init(int sock)
{
if (sock == 0)
set_irq_type(SHANNON_IRQ_GPIO_EJECT_0, IRQT_BOTHEDGE);
else if (sock == 1)
set_irq_Type(SHANNON_IRQ_GPIO_EJECT_1, IRQT_BOTHEDGE);
return 0;
}
static int shannon_pcmcia_socket_suspend(int sock)
{
if (sock == 0)
set_irq_type(SHANNON_IRQ_GPIO_EJECT_0, IRQT_NOEDGE);
else if (sock == 1)
set_irq_type(SHANNON_IRQ_GPIO_EJECT_1, IRQT_NOEDGE);
return 0;
}
static struct pcmcia_low_level shannon_pcmcia_ops = {
init: shannon_pcmcia_init,
shutdown: shannon_pcmcia_shutdown,
socket_state: shannon_pcmcia_socket_state,
get_irq_info: shannon_pcmcia_get_irq_info,
configure_socket: shannon_pcmcia_configure_socket,
socket_init: shannon_pcmcia_socket_init,
socket_suspend: shannon_pcmcia_socket_suspend,
};
int __init pcmcia_shannon_init(void)
{
int ret = -ENODEV;
if (machine_is_shannon())
ret = sa1100_register_pcmcia(&shannon_pcmcia_ops);
return ret;
}
void __exit pcmcia_shannon_exit(void)
{
sa1100_unregister_pcmcia(&shannon_pcmcia_ops);
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
extern int sa1111_pcmcia_init(struct pcmcia_init *);
extern int sa1111_pcmcia_shutdown(void);
extern int sa1111_pcmcia_socket_state(struct pcmcia_state_array *);
extern int sa1111_pcmcia_get_irq_info(struct pcmcia_irq_info *);
extern int sa1111_pcmcia_configure_socket(const struct pcmcia_configure *);
extern int sa1111_pcmcia_socket_init(int);
extern int sa1111_pcmcia_socket_suspend(int);
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