Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | /*
* drivers/pcmcia/sa1100_yopy.c
*
* PCMCIA implementation routines for Yopy
*
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/arch/pcmcia.h>
static inline void pcmcia_power(int on) {
/* high for power up */
yopy_gpio_set(GPIO_CF_POWER, on);
}
static inline void pcmcia_reset(int reset)
{
/* high for reset */
yopy_gpio_set(GPIO_CF_RESET, reset);
}
static int yopy_pcmcia_init(struct pcmcia_init *init)
{
int irq, res;
pcmcia_power(0);
pcmcia_reset(1);
/* All those are inputs */
GPDR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IREQ);
GAFR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IREQ);
/* 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_IREQ, GPIO_FALLING_EDGE );
/* Register interrupts */
irq = IRQ_CF_CD;
res = request_irq(irq, init->handler, SA_INTERRUPT, "CF_CD", NULL);
if (res < 0) goto irq_err;
irq = IRQ_CF_BVD2;
res = request_irq(irq, init->handler, SA_INTERRUPT, "CF_BVD2", NULL);
if (res < 0) goto irq_err;
irq = IRQ_CF_BVD1;
res = request_irq(irq, init->handler, SA_INTERRUPT, "CF_BVD1", NULL);
if (res < 0) goto irq_err;
return 1;
irq_err:
printk(KERN_ERR "%s: Request for IRQ %d failed\n", __FUNCTION__, irq);
return -1;
}
static int yopy_pcmcia_shutdown(void)
{
/* disable IRQs */
free_irq( IRQ_CF_CD, NULL );
free_irq( IRQ_CF_BVD2, NULL );
free_irq( IRQ_CF_BVD1, NULL );
/* Disable CF */
pcmcia_reset(1);
pcmcia_power(0);
return 0;
}
static int yopy_pcmcia_socket_state(struct pcmcia_state_array *state_array)
{
unsigned long levels;
if (state_array->size != 1)
return -1;
memset(state_array->state, 0,
state_array->size * sizeof(struct pcmcia_state));
levels = GPLR;
state_array->state[0].detect = (levels & GPIO_CF_CD) ? 0 : 1;
state_array->state[0].ready = (levels & GPIO_CF_READY) ? 1 : 0;
state_array->state[0].bvd1 = (levels & GPIO_CF_BVD1) ? 1 : 0;
state_array->state[0].bvd2 = (levels & GPIO_CF_BVD2) ? 1 : 0;
state_array->state[0].wrprot = 0; /* Not available on Yopy. */
state_array->state[0].vs_3v = 0; /* FIXME Can only apply 3.3V on Yopy. */
state_array->state[0].vs_Xv = 0;
return 1;
}
static int yopy_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
{
if (info->sock != 0)
return -1;
info->irq = IRQ_CF_IREQ;
return 0;
}
static int yopy_pcmcia_configure_socket(const struct pcmcia_configure *configure)
{
if (configure->sock != 0)
return -1;
switch (configure->vcc) {
case 0: /* power off */;
pcmcia_power(0);
break;
case 50:
printk(KERN_WARNING __FUNCTION__"(): CS asked for 5V, applying 3.3V..\n");
case 33:
pcmcia_power(1);
break;
default:
printk(KERN_ERR __FUNCTION__"(): unrecognized Vcc %u\n",
configure->vcc);
return -1;
}
pcmcia_reset(configure->reset);
/* Silently ignore Vpp, output enable, speaker enable. */
return 0;
}
struct pcmcia_low_level yopy_pcmcia_ops = {
yopy_pcmcia_init,
yopy_pcmcia_shutdown,
yopy_pcmcia_socket_state,
yopy_pcmcia_get_irq_info,
yopy_pcmcia_configure_socket
};
|