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
dep_tristate ' HD64465 host bridge support' CONFIG_HD64465_PCMCIA $CONFIG_PCMCIA
fi
fi
dep_tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA
endmenu
......@@ -62,22 +62,24 @@ endif
obj-$(CONFIG_PCMCIA_SA1100) += sa1100_cs.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_ASSABET_NEPONSET) += sa1100_neponset.o
sa1100_cs-objs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o
sa1100_cs-objs-$(CONFIG_ASSABET_NEPONSET) += sa1100_neponset.o sa1111_generic.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_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_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_YOPY) += sa1100_yopy.o
sa1100_cs-objs-$(CONFIG_SA1100_FREEBIRD) += sa1100_freebird.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_PFS168) += sa1100_pfs168.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_SHANNON) += sa1100_shannon.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_XP860) += sa1100_xp860.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_YOPY) += sa1100_yopy.o
include $(TOPDIR)/Rules.make
......@@ -85,7 +87,7 @@ pcmcia_core.o: $(pcmcia_core-objs)
$(LD) $(LD_RFLAG) -r -o $@ $(pcmcia_core-objs)
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)
$(LD) $(LD_RFLAG) -r -o $@ $(yenta_socket-objs)
......@@ -38,9 +38,7 @@
#include <pcmcia/bulkmem.h>
#include <pcmcia/cistpl.h>
#include "cs_internal.h"
#include <asm/arch/pcmcia.h>
#include "sa1100_generic.h"
/* MECR: Expansion Memory Configuration Register
* (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,
* use when responding to a Card Services query of some kind.
*/
struct sa1100_pcmcia_socket {
/*
* Core PCMCIA 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_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;
/*
* Info from low level handler
*/
unsigned int irq;
};
......@@ -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 struct pcmcia_low_level neponset_pcmcia_ops;
extern struct pcmcia_low_level h3600_pcmcia_ops;
extern struct pcmcia_low_level cerf_pcmcia_ops;
extern struct pcmcia_low_level gcplus_pcmcia_ops;
extern struct pcmcia_low_level xp860_pcmcia_ops;
extern struct pcmcia_low_level yopy_pcmcia_ops;
extern struct pcmcia_low_level pangolin_pcmcia_ops;
extern struct pcmcia_low_level freebird_pcmcia_ops;
extern struct pcmcia_low_level pfs168_pcmcia_ops;
extern struct pcmcia_low_level jornada720_pcmcia_ops;
extern struct pcmcia_low_level flexanet_pcmcia_ops;
extern struct pcmcia_low_level simpad_pcmcia_ops;
extern struct pcmcia_low_level graphicsmaster_pcmcia_ops;
extern struct pcmcia_low_level adsbitsy_pcmcia_ops;
extern struct pcmcia_low_level stork_pcmcia_ops;
extern int pcmcia_adsbitsy_init(void);
extern void pcmcia_adsbitsy_exit(void);
extern int pcmcia_assabet_init(void);
extern void pcmcia_assabet_exit(void);
extern int pcmcia_badge4_init(void);
extern void pcmcia_badge4_exit(void);
extern int pcmcia_cerf_init(void);
extern void pcmcia_cerf_exit(void);
extern int pcmcia_flexanet_init(void);
extern void pcmcia_flexanet_exit(void);
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) */
......@@ -11,206 +11,97 @@
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <asm/delay.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)
{
int return_val=0;
/* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
/* Disable Power 3.3V/5V for PCMCIA/CF */
PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3;
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,
"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);
/* Why? */
MECR = 0x09430943;
return (return_val<0) ? -1 : 2;
}
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;
return sa1111_pcmcia_init(init);
}
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;
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;
unsigned int pa_dwr_mask, pa_dwr_set;
int ret;
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 adsbitsy_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
{
switch(info->sock){
switch (conf->sock) {
case 0:
info->irq=S0_READY_NINT;
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;
pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
switch (conf->vcc) {
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc);
return -1;
case 0: pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1; break;
case 33: pa_dwr_set = GPIO_GPIO1; break;
case 50: pa_dwr_set = GPIO_GPIO0; break;
}
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_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;
pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3;
switch (conf->vcc) {
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc);
return -1;
case 0: pa_dwr_set = 0; break;
case 33: pa_dwr_set = GPIO_GPIO2; break;
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:
return -1;
}
PCCR = pccr;
PA_DWR = gpio;
if (conf->vpp != conf->vcc && conf->vpp != 0) {
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 = {
adsbitsy_pcmcia_init,
adsbitsy_pcmcia_shutdown,
adsbitsy_pcmcia_socket_state,
adsbitsy_pcmcia_get_irq_info,
adsbitsy_pcmcia_configure_socket
static struct pcmcia_low_level adsbitsy_pcmcia_ops = {
init: adsbitsy_pcmcia_init,
shutdown: sa1111_pcmcia_shutdown,
socket_state: sa1111_pcmcia_socket_state,
get_irq_info: sa1111_pcmcia_get_irq_info,
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 @@
* PCMCIA implementation routines for Assabet
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/arch/pcmcia.h>
#include <asm/arch/assabet.h>
static int assabet_pcmcia_init(struct pcmcia_init *init){
int irq, res;
#include "sa1100_generic.h"
/* Enable CF bus: */
ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF);
static struct irqs {
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 */
GPDR &= ~(ASSABET_GPIO_CF_CD | ASSABET_GPIO_CF_BVD2 | ASSABET_GPIO_CF_BVD1 | ASSABET_GPIO_CF_IRQ);
/* 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;
}
/* Set transition detect */
set_GPIO_IRQ_edge( ASSABET_GPIO_CF_CD|ASSABET_GPIO_CF_BVD2|ASSABET_GPIO_CF_BVD1, GPIO_BOTH_EDGES );
set_GPIO_IRQ_edge( ASSABET_GPIO_CF_IRQ, GPIO_FALLING_EDGE );
/* There's only one slot, but it's "Slot 1": */
return 2;
/* Register interrupts */
irq = ASSABET_IRQ_GPIO_CF_CD;
res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_CD", NULL );
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;
irq_err:
printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
__FUNCTION__, irqs[i].irq, res);
/* There's only one slot, but it's "Slot 1": */
return 2;
while (i--)
free_irq(irqs[i].irq, NULL);
irq_err:
printk( KERN_ERR "%s: Request for IRQ %u failed\n", __FUNCTION__, irq );
return -1;
return res;
}
/*
* Release all resources.
*/
static int assabet_pcmcia_shutdown(void)
{
/* disable IRQs */
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);
int i;
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
*state_array){
unsigned long levels;
static int
assabet_pcmcia_socket_state(struct pcmcia_state_array *state_array)
{
unsigned long levels;
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[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)
info->irq=ASSABET_IRQ_GPIO_CF_IRQ;
default:
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
*configure)
{
unsigned long value, flags;
if (configure->reset)
mask |= ASSABET_BCR_CF_RST;
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){
case 0:
value &= ~ASSABET_BCR_CF_PWR;
break;
if (sock == 1) {
/*
* Enable CF bus
*/
ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF);
case 50:
printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
__FUNCTION__);
for (i = 0; i < ARRAY_SIZE(irqs); i++)
set_irq_type(irqs[i].irq, IRQT_BOTHEDGE);
}
case 33: /* Can only apply 3.3V to the CF slot. */
value |= ASSABET_BCR_CF_PWR;
break;
return 0;
}
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc);
restore_flags(flags);
return -1;
}
/*
* Disable card status IRQs on suspend.
*/
static int assabet_pcmcia_socket_suspend(int sock)
{
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 = {
assabet_pcmcia_init,
assabet_pcmcia_shutdown,
assabet_pcmcia_socket_state,
assabet_pcmcia_get_irq_info,
assabet_pcmcia_configure_socket
};
void __exit pcmcia_assabet_exit(void)
{
sa1100_unregister_pcmcia(&assabet_pcmcia_ops);
}
/*
* 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 @@
* Based off the Assabet.
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <asm/hardware.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){
int irq, res;
static struct irqs {
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);
GPDR |= (GPIO_CF_RESET);
static int cerf_pcmcia_init(struct pcmcia_init *init)
{
int i, res;
set_GPIO_IRQ_edge( GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1, GPIO_BOTH_EDGES );
set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE );
set_irq_type(IRQ_GPIO_CF_IRQ, IRQT_FALLING);
irq = IRQ_GPIO_CF_CD;
res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_CD", NULL );
if( res < 0 ) goto irq_err;
irq = IRQ_GPIO_CF_BVD2;
res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD2", NULL );
if( res < 0 ) 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;
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 %lu failed\n", __FUNCTION__, irq );
return -1;
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 cerf_pcmcia_shutdown(void)
{
free_irq( IRQ_GPIO_CF_CD, NULL );
free_irq( IRQ_GPIO_CF_BVD2, NULL );
free_irq( IRQ_GPIO_CF_BVD1, NULL );
int i;
for (i = 0; i < ARRAY_SIZE(irqs); i++)
free_irq(irqs[i].irq, NULL);
return 0;
}
......@@ -51,31 +68,18 @@ static int cerf_pcmcia_shutdown(void)
static int cerf_pcmcia_socket_state(struct pcmcia_state_array
*state_array){
unsigned long levels;
#ifdef CONFIG_SA1100_CERF_CPLD
int i = 0;
#else
int i = 1;
#endif
int i = CERF_SOCKET;
if(state_array->size<2) return -1;
memset(state_array->state, 0,
(state_array->size)*sizeof(struct pcmcia_state));
levels=GPLR;
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].bvd1=(levels & GPIO_CF_BVD1)?1:0;
state_array->state[i].bvd2=(levels & GPIO_CF_BVD2)?1:0;
state_array->state[i].wrprot=0;
state_array->state[i].vs_3v=1;
state_array->state[i].vs_Xv=0;
return 1;
......@@ -85,11 +89,7 @@ static int cerf_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
if(info->sock>1) return -1;
#ifdef CONFIG_SA1100_CERF_CPLD
if(info->sock==0)
#else
if(info->sock==1)
#endif
if (info->sock == CERF_SOCKET)
info->irq=IRQ_GPIO_CF_IRQ;
return 0;
......@@ -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
*configure)
{
unsigned long flags;
if(configure->sock>1)
return -1;
#ifdef CONFIG_SA1100_CERF_CPLD
if(configure->sock==1)
#else
if(configure->sock==0)
#endif
if (configure->sock != CERF_SOCKET)
return 0;
save_flags_cli(flags);
switch(configure->vcc){
case 0:
break;
......@@ -119,43 +111,76 @@ static int cerf_pcmcia_configure_socket(const struct pcmcia_configure
case 50:
case 33:
#ifdef CONFIG_SA1100_CERF_CPLD
GPDR |= GPIO_PWR_SHUTDOWN;
GPCR |= GPIO_PWR_SHUTDOWN;
GPCR = GPIO_PWR_SHUTDOWN;
#endif
break;
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc);
restore_flags(flags);
return -1;
}
if(configure->reset)
{
#ifdef CONFIG_SA1100_CERF_CPLD
GPDR |= GPIO_CF_RESET;
GPSR |= GPIO_CF_RESET;
GPSR = GPIO_CF_RESET;
#endif
}
else
{
#ifdef CONFIG_SA1100_CERF_CPLD
GPDR |= GPIO_CF_RESET;
GPCR |= GPIO_CF_RESET;
GPCR = GPIO_CF_RESET;
#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;
}
struct pcmcia_low_level cerf_pcmcia_ops = {
cerf_pcmcia_init,
cerf_pcmcia_shutdown,
cerf_pcmcia_socket_state,
cerf_pcmcia_get_irq_info,
cerf_pcmcia_configure_socket
static int cerf_pcmcia_socket_suspend(int sock)
{
int i;
if (sock == CERF_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 @@
* PCMCIA implementation routines for Flexanet.
* by Jordi Colomer, 09/05/2001
*
* Yet to be defined.
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <asm/hardware.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.
......@@ -22,9 +31,37 @@
* Must return the number of slots.
*
*/
static int flexanet_pcmcia_init(struct pcmcia_init *init){
return 0;
static int flexanet_pcmcia_init(struct pcmcia_init *init)
{
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){
*/
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;
}
......@@ -46,7 +89,33 @@ static int flexanet_pcmcia_shutdown(void)
*/
static int flexanet_pcmcia_socket_state(struct pcmcia_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
*/
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){
static int flexanet_pcmcia_configure_socket(const struct pcmcia_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
*
*/
struct pcmcia_low_level flexanet_pcmcia_ops = {
flexanet_pcmcia_init,
flexanet_pcmcia_shutdown,
flexanet_pcmcia_socket_state,
flexanet_pcmcia_get_irq_info,
flexanet_pcmcia_configure_socket
static struct pcmcia_low_level flexanet_pcmcia_ops = {
init: flexanet_pcmcia_init,
shutdown: flexanet_pcmcia_shutdown,
socket_state: flexanet_pcmcia_socket_state,
get_irq_info: flexanet_pcmcia_get_irq_info,
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 @@
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <asm/hardware.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){
int irq, res;
int i, res;
/* Enable Linkup CF card */
LINKUP_PRC = 0xc0;
......@@ -26,37 +34,38 @@ static int freebird_pcmcia_init(struct pcmcia_init *init){
mdelay(100);
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_GPIO_IRQ_edge( GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1, GPIO_BOTH_EDGES );
//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);
set_irq_type(IRQ_GPIO_FREEBIRD_CF_IRQ, IRQT_FALLING);
/* Register interrupts */
irq = IRQ_GPIO_FREEBIRD_CF_CD;
res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_CD", NULL );
if( res < 0 ) goto irq_err;
irq = IRQ_GPIO_FREEBIRD_CF_BVD;
res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD1", NULL );
if( res < 0 ) goto irq_err;
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;
}
/* There's only one slot, but it's "Slot 1": */
return 2;
irq_err:
printk( KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq );
return -1;
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 freebird_pcmcia_shutdown(void)
{
int i;
/* disable IRQs */
free_irq( IRQ_GPIO_FREEBIRD_CF_CD, NULL );
free_irq( IRQ_GPIO_FREEBIRD_CF_BVD, NULL );
for (i = 0; i < ARRAY_SIZE(irqs); i++)
free_irq(irqs[i].irq, NULL);
/* Disable CF card */
LINKUP_PRC = 0x40; /* SSP=1 SOE=0 */
......@@ -75,7 +84,7 @@ static int freebird_pcmcia_socket_state(struct pcmcia_state_array
(state_array->size)*sizeof(struct pcmcia_state));
levels = LINKUP_PRS;
//printk("LINKUP_PRS=%x \n",levels);
//printk("LINKUP_PRS=%x\n",levels);
state_array->state[0].detect=
((levels & (LINKUP_CD1 | LINKUP_CD2))==0)?1:0;
......@@ -114,7 +123,7 @@ static int freebird_pcmcia_configure_socket(const struct pcmcia_configure
if(configure->sock==1) return 0;
save_flags_cli(flags);
local_irq_save(flags);
value = 0xc0; /* SSP=1 SOE=1 CFE=1 */
......@@ -134,7 +143,7 @@ static int freebird_pcmcia_configure_socket(const struct pcmcia_configure
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc);
restore_flags(flags);
local_irq_restore(flags);
return -1;
}
......@@ -145,16 +154,51 @@ static int freebird_pcmcia_configure_socket(const struct pcmcia_configure
LINKUP_PRC = value;
//printk("LINKUP_PRC=%x\n",value);
restore_flags(flags);
local_irq_restore(flags);
return 0;
}
struct pcmcia_low_level freebird_pcmcia_ops = {
freebird_pcmcia_init,
freebird_pcmcia_shutdown,
freebird_pcmcia_socket_state,
freebird_pcmcia_get_irq_info,
freebird_pcmcia_configure_socket
static int freebird_pcmcia_socket_init(int sock)
{
if (sock == 1) {
set_irq_type(IRQ_GPIO_FREEBIRD_CF_CD, IRQT_BOTHEDGE);
set_irq_type(IRQ_GPIO_FREEBIRD_CF_BVD, IRQT_BOTHEDGE);
}
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 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <asm/hardware.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_STS_IRQ 55 // Socket 0 PCMCIA IRQ
......@@ -47,8 +50,9 @@ static int gcplus_pcmcia_init(struct pcmcia_init *init)
irq = S0_CD_IRQ;
res = request_irq(irq, init->handler, SA_INTERRUPT, "PCMCIA 0 CD", NULL);
if (res < 0) {
printk(KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq);
return -1;
printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
__FUNCTION__, irq, res);
return res;
}
return 1; // 1 PCMCIA Slot
......@@ -106,7 +110,7 @@ static int gcplus_pcmcia_configure_socket(const struct pcmcia_configure
if(configure->sock>1) return -1;
save_flags_cli(flags);
local_irq_save(flags);
switch (configure->vcc) {
case 0:
......@@ -126,7 +130,7 @@ static int gcplus_pcmcia_configure_socket(const struct pcmcia_configure
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc);
restore_flags(flags);
local_irq_restore(flags);
return -1;
}
......@@ -139,16 +143,44 @@ static int gcplus_pcmcia_configure_socket(const struct pcmcia_configure
*PCMCIA_Power |= ADS_CS_PR_A_RESET;
mdelay(30);
restore_flags(flags);
local_irq_restore(flags);
return 0;
}
struct pcmcia_low_level gcplus_pcmcia_ops = {
gcplus_pcmcia_init,
gcplus_pcmcia_shutdown,
gcplus_pcmcia_socket_state,
gcplus_pcmcia_get_irq_info,
gcplus_pcmcia_configure_socket
static int gcplus_pcmcia_socket_init(int sock)
{
return 0;
}
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 @@
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <asm/delay.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)
{
......@@ -26,190 +27,82 @@ static int graphicsmaster_pcmcia_init(struct pcmcia_init *init)
/* Disable Power 3.3V/5V for PCMCIA/CF */
PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3;
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,
"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);
/* why? */
MECR = 0x09430943;
return (return_val<0) ? -1 : 2;
}
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;
return sa1111_pcmcia_init(init);
}
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:
pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
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:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc);
return -1;
case 0: pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1; break;
case 33: pa_dwr_set = GPIO_GPIO1; break;
case 50: pa_dwr_set = GPIO_GPIO0; break;
}
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_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;
pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3;
switch (conf->vcc) {
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;
case 0: pa_dwr_set = GPIO_GPIO2 | GPIO_GPIO3; break;
case 33: pa_dwr_set = GPIO_GPIO3; break;
case 50: pa_dwr_set = GPIO_GPIO2; break;
}
}
pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
break;
default:
if (conf->vpp != conf->vcc && conf->vpp != 0) {
printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
conf->vpp);
return -1;
}
PCCR = pccr;
PA_DWR = gpio;
ret = sa1111_pcmcia_configure_socket(conf);
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 = {
graphicsmaster_pcmcia_init,
graphicsmaster_pcmcia_shutdown,
graphicsmaster_pcmcia_socket_state,
graphicsmaster_pcmcia_get_irq_info,
graphicsmaster_pcmcia_configure_socket
static struct pcmcia_low_level graphicsmaster_pcmcia_ops = {
init: graphicsmaster_pcmcia_init,
shutdown: sa1111_pcmcia_shutdown,
socket_state: sa1111_pcmcia_socket_state,
get_irq_info: sa1111_pcmcia_get_irq_info,
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 @@
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/arch/pcmcia.h>
static int h3600_pcmcia_init(struct pcmcia_init *init){
int irq, res;
/* Enable CF bus: */
set_h3600_egpio(EGPIO_H3600_OPT_NVRAM_ON);
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;
#include "sa1100_generic.h"
static struct irqs {
int irq;
const char *str;
} irqs[] = {
{ IRQ_GPIO_H3600_PCMCIA_CD0, "PCMCIA CD0" },
{ IRQ_GPIO_H3600_PCMCIA_CD1, "PCMCIA CD1" }
};
irq_err:
printk( KERN_ERR __FUNCTION__ ": Request for IRQ %u failed\n", irq );
return -1;
static int h3600_pcmcia_init(struct pcmcia_init *init)
{
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)
{
/* disable IRQs */
free_irq( IRQ_GPIO_H3600_PCMCIA_CD0, NULL );
free_irq( IRQ_GPIO_H3600_PCMCIA_CD1, NULL );
int i;
/*
* disable IRQs
*/
for (i = 0; i < ARRAY_SIZE(irqs); i++)
free_irq(irqs[i].irq, NULL);
/* Disable CF bus: */
clr_h3600_egpio(EGPIO_H3600_OPT_NVRAM_ON|EGPIO_H3600_OPT_ON);
set_h3600_egpio(EGPIO_H3600_OPT_RESET);
/* Disable CF bus: */
clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
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
*state_array){
unsigned long levels;
if(state_array->size<2) return -1;
memset(state_array->state, 0,
(state_array->size)*sizeof(struct pcmcia_state));
levels=GPLR;
state_array->state[0].detect=((levels & GPIO_H3600_PCMCIA_CD0)==0)?1:0;
state_array->state[0].ready=(levels & GPIO_H3600_PCMCIA_IRQ0)?1:0;
state_array->state[0].bvd1= 0;
state_array->state[0].bvd2= 0;
state_array->state[0].wrprot=0; /* Not available on H3600. */
state_array->state[0].vs_3v=0;
state_array->state[0].vs_Xv=0;
state_array->state[1].detect=((levels & GPIO_H3600_PCMCIA_CD1)==0)?1:0;
state_array->state[1].ready=(levels & GPIO_H3600_PCMCIA_IRQ1)?1:0;
state_array->state[1].bvd1=0;
state_array->state[1].bvd2=0;
state_array->state[1].wrprot=0; /* Not available on H3600. */
state_array->state[1].vs_3v=0;
state_array->state[1].vs_Xv=0;
return 1;
static int
h3600_pcmcia_socket_state(struct pcmcia_state_array *state)
{
unsigned long levels;
if (state->size < 2)
return -1;
levels = GPLR;
state->state[0].detect = levels & GPIO_H3600_PCMCIA_CD0 ? 0 : 1;
state->state[0].ready = levels & GPIO_H3600_PCMCIA_IRQ0 ? 1 : 0;
state->state[0].bvd1 = 0;
state->state[0].bvd2 = 0;
state->state[0].wrprot = 0; /* Not available on H3600. */
state->state[0].vs_3v = 0;
state->state[0].vs_Xv = 0;
state->state[1].detect = levels & GPIO_H3600_PCMCIA_CD1 ? 0 : 1;
state->state[1].ready = levels & GPIO_H3600_PCMCIA_IRQ1 ? 1 : 0;
state->state[1].bvd1 = 0;
state->state[1].bvd2 = 0;
state->state[1].wrprot = 0; /* Not available on H3600. */
state->state[1].vs_3v = 0;
state->state[1].vs_Xv = 0;
return 1;
}
static int h3600_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
switch (info->sock) {
case 0:
info->irq=IRQ_GPIO_H3600_PCMCIA_IRQ0;
break;
case 1:
info->irq=IRQ_GPIO_H3600_PCMCIA_IRQ1;
break;
default:
return -1;
}
return 0;
static int h3600_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
{
switch (info->sock) {
case 0:
info->irq = IRQ_GPIO_H3600_PCMCIA_IRQ0;
break;
case 1:
info->irq = IRQ_GPIO_H3600_PCMCIA_IRQ1;
break;
default:
return -1;
}
return 0;
}
static int h3600_pcmcia_configure_socket(const struct pcmcia_configure
*configure)
static int
h3600_pcmcia_configure_socket(const struct pcmcia_configure *conf)
{
unsigned long flags;
if(configure->sock>1) return -1;
if (conf->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) {
case 0:
clr_h3600_egpio(EGPIO_H3600_OPT_ON);
break;
if (conf->reset)
set_h3600_egpio(IPAQ_EGPIO_CARD_RESET);
else
clr_h3600_egpio(IPAQ_EGPIO_CARD_RESET);
case 33:
case 50:
set_h3600_egpio(EGPIO_H3600_OPT_ON);
break;
/* Silently ignore Vpp, output enable, speaker enable. */
default:
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. */
return 0;
}
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 = {
h3600_pcmcia_init,
h3600_pcmcia_shutdown,
h3600_pcmcia_socket_state,
h3600_pcmcia_get_irq_info,
h3600_pcmcia_configure_socket
init: h3600_pcmcia_init,
shutdown: h3600_pcmcia_shutdown,
socket_state: h3600_pcmcia_socket_state,
get_irq_info: h3600_pcmcia_get_irq_info,
configure_socket: h3600_pcmcia_configure_socket,
socket_init: h3600_pcmcia_socket_init,
socket_suspend: h3600_pcmcia_socket_suspend,
};
......@@ -6,21 +6,24 @@
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <asm/delay.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_3V GPIO_GPIO2
#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)
{
int return_val=0;
/*
* What is all this crap for?
*/
GRER |= 0x00000002;
/* Set GPIO_A<3:1> to be outputs for PCMCIA/CF power controller: */
PA_DDR = 0;
......@@ -38,178 +41,82 @@ static int jornada720_pcmcia_init(struct pcmcia_init *init)
PC_SDR = 0;
PC_SSR = 0;
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,
"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;
return sa1111_pcmcia_init(init);
}
static int jornada720_pcmcia_configure_socket(const struct pcmcia_configure
*configure)
static int
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__,
configure->sock, configure->vcc, configure->vpp);
switch(configure->sock){
conf->sock, conf->vcc, conf->vpp);
switch (conf->sock) {
case 0:
switch(configure->vcc){
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;
pa_dwr_mask = SOCKET0_POWER | SOCKET0_3V;
switch (conf->vcc) {
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc);
return -1;
}
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;
case 0: pa_dwr_set = 0; break;
case 33: pa_dwr_set = SOCKET0_POWER | SOCKET0_3V; break;
case 50: pa_dwr_set = SOCKET0_POWER; break;
}
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 &= ~(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;
pa_dwr_mask = SOCKET1_POWER;
switch (conf->vcc) {
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc);
return -1;
case 0: pa_dwr_set = 0; break;
case 33: pa_dwr_set = SOCKET1_POWER; break;
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;
default:
}
if (conf->vpp != conf->vcc && conf->vpp != 0) {
printk(KERN_ERR "%s(): slot cannot support VPP %u\n",
__FUNCTION__, conf->vpp);
return -1;
}
PCCR = pccr;
PA_DWR = gpio;
return 0;
ret = sa1111_pcmcia_configure_socket(conf);
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 = {
jornada720_pcmcia_init,
jornada720_pcmcia_shutdown,
jornada720_pcmcia_socket_state,
jornada720_pcmcia_get_irq_info,
jornada720_pcmcia_configure_socket
static struct pcmcia_low_level jornada720_pcmcia_ops = {
init: jornada720_pcmcia_init,
shutdown: sa1111_pcmcia_shutdown,
socket_state: sa1111_pcmcia_socket_state,
get_irq_info: sa1111_pcmcia_get_irq_info,
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
*
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <asm/delay.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/arch/pcmcia.h>
#include <asm/arch/assabet.h>
#include <asm/hardware/sa1111.h>
static int neponset_pcmcia_init(struct pcmcia_init *init){
int return_val=0;
/* 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){
#include "sa1100_generic.h"
#include "sa1111_generic.h"
free_irq(S0_CD_VALID, NULL);
free_irq(S1_CD_VALID, NULL);
free_irq(S0_BVD1_STSCHG, NULL);
free_irq(S1_BVD1_STSCHG, NULL);
static int neponset_pcmcia_init(struct pcmcia_init *init)
{
/* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
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))));
/* MAX1600 to standby mode: */
PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP);
return 0;
return sa1111_pcmcia_init(init);
}
static int neponset_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
neponset_pcmcia_configure_socket(const struct pcmcia_configure *conf)
{
unsigned int ncr_mask, pa_dwr_mask;
unsigned int ncr_set, pa_dwr_set;
int ret;
/* 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 (conf->sock) {
case 0:
pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
ncr_mask = NCR_A0VPP | NCR_A1VPP;
switch (conf->vcc) {
default:
case 0: pa_dwr_set = 0; break;
case 33: pa_dwr_set = GPIO_GPIO1; break;
case 50: pa_dwr_set = GPIO_GPIO0; break;
}
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){
case 0:
info->irq=S0_READY_NINT;
break;
socket_init: sa1111_pcmcia_socket_init,
socket_suspend: sa1111_pcmcia_socket_suspend,
};
case 1:
info->irq=S1_READY_NINT;
break;
int __init pcmcia_neponset_init(void)
{
int ret = -ENODEV;
default:
return -1;
}
if (machine_is_assabet() && machine_has_neponset())
ret = sa1100_register_pcmcia(&neponset_pcmcia_ops);
return 0;
return ret;
}
static int neponset_pcmcia_configure_socket(const struct pcmcia_configure
*configure){
unsigned long pccr=PCCR, ncr=NCR_0, gpio=PA_DWR;
/* 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;
void __exit pcmcia_neponset_exit(void)
{
sa1100_unregister_pcmcia(&neponset_pcmcia_ops);
}
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 @@
* PCMCIA implementation routines for Pangolin
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/arch/pcmcia.h>
#include "sa1100_generic.h"
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
/* set GPIO pins GPIO_PCMCIA_BUS_ON & GPIO_PCMCIA_RESET as output */
GPDR |= (GPIO_PCMCIA_BUS_ON|GPIO_PCMCIA_RESET);
/* Enable PCMCIA bus: */
GPCR = GPIO_PCMCIA_BUS_ON;
#else
/* set GPIO pin GPIO_PCMCIA_RESET as output */
GPDR |= GPIO_PCMCIA_RESET;
#endif
/* Set transition detect */
set_GPIO_IRQ_edge( GPIO_PCMCIA_CD, GPIO_BOTH_EDGES );
set_GPIO_IRQ_edge( GPIO_PCMCIA_IRQ, GPIO_FALLING_EDGE );
set_irq_type(IRQ_PCMCIA_CD, IRQT_NOEDGE);
set_irq_type(IRQ_PCMCIA_IRQ, IRQT_FALLING);
/* Register interrupts */
irq = IRQ_PCMCIA_CD;
res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD", NULL );
if( res < 0 ) goto irq_err;
/* There's only one slot, but it's "Slot 1": */
return 2;
res = request_irq(IRQ_PCMCIA_CD, init->handler, SA_INTERRUPT,
"PCMCIA_CD", NULL);
if (res >= 0)
/* There's only one slot, but it's "Slot 1": */
return 2;
irq_err:
printk( KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq );
return -1;
printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
__FUNCTION__, IRQ_PCMCIA_CD, res);
return res;
}
static int pangolin_pcmcia_shutdown(void)
{
/* disable IRQs */
free_irq( IRQ_PCMCIA_CD, NULL );
free_irq(IRQ_PCMCIA_CD, NULL);
#ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
/* Disable PCMCIA bus: */
GPSR = GPIO_PCMCIA_BUS_ON;
......@@ -105,7 +102,7 @@ static int pangolin_pcmcia_configure_socket(const struct pcmcia_configure
#ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
if(configure->sock==0) return 0;
#endif
save_flags_cli(flags);
local_irq_save(flags);
/* Murphy: BUS_ON different from POWER ? */
......@@ -129,7 +126,7 @@ static int pangolin_pcmcia_configure_socket(const struct pcmcia_configure
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc);
restore_flags(flags);
local_irq_restore(flags);
return -1;
}
#ifdef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
......@@ -143,15 +140,47 @@ static int pangolin_pcmcia_configure_socket(const struct pcmcia_configure
}
#endif
/* Silently ignore Vpp, output enable, speaker enable. */
restore_flags(flags);
local_irq_restore(flags);
return 0;
}
struct pcmcia_low_level pangolin_pcmcia_ops = {
pangolin_pcmcia_init,
pangolin_pcmcia_shutdown,
pangolin_pcmcia_socket_state,
pangolin_pcmcia_get_irq_info,
pangolin_pcmcia_configure_socket
static int pangolin_pcmcia_socket_init(int sock)
{
if (sock == 1)
set_irq_type(IRQ_PCmCIA_CD, IRQT_BOTHEDGE);
return 0;
}
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