--- zzzz-none-000/linux-2.4.17/drivers/pcmcia/sa1100_flexanet.c 2001-10-11 16:43:29.000000000 +0000 +++ sangam-fb-322/linux-2.4.17/drivers/pcmcia/sa1100_flexanet.c 2004-11-24 13:23:45.000000000 +0000 @@ -4,7 +4,6 @@ * PCMCIA implementation routines for Flexanet. * by Jordi Colomer, 09/05/2001 * - * Yet to be defined. */ #include @@ -14,6 +13,15 @@ #include #include +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 +30,37 @@ * Must return the number of slots. * */ -static int flexanet_pcmcia_init(struct pcmcia_init *init){ +static int flexanet_pcmcia_init(struct pcmcia_init *init) +{ + int i, res; - return 0; + /* 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_GPIO_IRQ_edge( GPIO_CF1_NCD | GPIO_CF1_BVD1 | + GPIO_CF2_NCD | GPIO_CF2_BVD1, GPIO_BOTH_EDGES ); + set_GPIO_IRQ_edge( GPIO_CF1_IRQ | GPIO_CF2_IRQ, GPIO_FALLING_EDGE ); + + /* Register the socket interrupts (not the card interrupts) */ + for (i = 0; i < ARRAY_SIZE(irqs); i++) { + 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%u failed: %d\n", __FUNCTION__, + irqs[i].irq, res); + for (; i >= 0; i--) + free_irq(irqs[i].irq, NULL); + return -1; + } + + return 2; } @@ -34,6 +70,12 @@ */ static int flexanet_pcmcia_shutdown(void) { + int i; + + /* disable IRQs */ + for (i = ARRAY_SIZE(irqs) - 1; i >= 0; i--) + free_irq(irqs[i].irq, NULL); + return 0; } @@ -46,7 +88,37 @@ */ static int flexanet_pcmcia_socket_state(struct pcmcia_state_array *state_array){ - return -1; + unsigned long levels; + + if (state_array->size < 2) + return -1; + + /* clear the result array */ + memset(state_array->state, 0, + (state_array->size)*sizeof(struct pcmcia_state)); + + /* 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 +128,16 @@ */ 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,7 +147,50 @@ 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; + } + + save_flags_cli(flags); + + value = flexanet_BCR; + value = (configure->reset) ? (value | mask) : (value & ~mask); + FHH_BCR = flexanet_BCR = value; + + restore_flags(flags); + + return 0; }