--- zzzz-none-000/linux-2.4.17/drivers/pcmcia/sa1100_h3600.c 2001-10-11 16:43:29.000000000 +0000 +++ sangam-fb-322/linux-2.4.17/drivers/pcmcia/sa1100_h3600.c 2004-11-24 13:23:45.000000000 +0000 @@ -2,146 +2,203 @@ * drivers/pcmcia/sa1100_h3600.c * * PCMCIA implementation routines for H3600 - * + * All true functionality is shuttled off to the + * pcmcia implementation for the current sleeve */ +#include +#include +#include #include #include +#include #include #include +#include #include +#include + +static struct pcmcia_init sa1100_h3600_pcmcia_init; // Store the interrupt handler +struct pcmcia_low_level *sa1100_h3600_pcmcia_ops = NULL; // Initialize with no sleeve + +/* Forward declaractions */ +int sa1100_h3600_common_pcmcia_get_irq_info( struct pcmcia_irq_info *info ); + +/***********************************************/ +/* Stub routines called by the PCMCIA device. */ +/***********************************************/ +static int h3600_pcmcia_init(struct pcmcia_init *init) +{ + sa1100_h3600_pcmcia_init = *init; -static int h3600_pcmcia_init(struct pcmcia_init *init){ - int irq, res; + if ( sa1100_h3600_pcmcia_ops != NULL + && sa1100_h3600_pcmcia_ops->init != NULL + && init->handler != NULL ) + return sa1100_h3600_pcmcia_ops->init( init ); - /* 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; - -irq_err: - printk( KERN_ERR __FUNCTION__ ": Request for IRQ %u failed\n", irq ); - return -1; + return 2; /* Return by default */ } static int h3600_pcmcia_shutdown(void) { - /* disable IRQs */ - free_irq( IRQ_GPIO_H3600_PCMCIA_CD0, NULL ); - free_irq( IRQ_GPIO_H3600_PCMCIA_CD1, NULL ); - - /* Disable CF bus: */ - clr_h3600_egpio(EGPIO_H3600_OPT_NVRAM_ON|EGPIO_H3600_OPT_ON); - set_h3600_egpio(EGPIO_H3600_OPT_RESET); + if ( sa1100_h3600_pcmcia_ops != NULL + && sa1100_h3600_pcmcia_ops->shutdown != NULL ) + sa1100_h3600_pcmcia_ops->shutdown(); - return 0; + return 0; /* Not examined */ } -static int h3600_pcmcia_socket_state(struct pcmcia_state_array - *state_array){ - unsigned long levels; - - if(state_array->size<2) return -1; +static int h3600_pcmcia_socket_state(struct pcmcia_state_array *state_array) +{ + if ( sa1100_h3600_pcmcia_ops != NULL + && sa1100_h3600_pcmcia_ops->socket_state != NULL ) + return sa1100_h3600_pcmcia_ops->socket_state( state_array ); + + /* Default actions */ + if ( state_array->size < 2 ) + return -1; - memset(state_array->state, 0, - (state_array->size)*sizeof(struct pcmcia_state)); + memset(state_array->state, 0, (state_array->size)*sizeof(struct pcmcia_state)); + return 0; +} - levels=GPLR; +static int h3600_pcmcia_get_irq_info(struct pcmcia_irq_info *info) +{ + if ( sa1100_h3600_pcmcia_ops != NULL + && sa1100_h3600_pcmcia_ops->get_irq_info != NULL ) + return sa1100_h3600_pcmcia_ops->get_irq_info( info ); - 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; + return + sa1100_h3600_common_pcmcia_get_irq_info( info ); +} - 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; +static int h3600_pcmcia_configure_socket(const struct pcmcia_configure *configure) +{ + if ( sa1100_h3600_pcmcia_ops != NULL + && sa1100_h3600_pcmcia_ops->configure_socket != NULL ) + return sa1100_h3600_pcmcia_ops->configure_socket( configure ); - return 1; + return 0; } -static int h3600_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ +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 +}; - 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; +/****************************************************/ +/* Swapping functions for PCMCIA operations */ +/****************************************************/ + +void sa1100_h3600_pcmcia_change_sleeves(struct pcmcia_low_level *ops) +{ + if ( ops != sa1100_h3600_pcmcia_ops ) { + h3600_pcmcia_shutdown(); + sa1100_h3600_pcmcia_ops = ops; + h3600_pcmcia_init( &sa1100_h3600_pcmcia_init ); + } } -static int h3600_pcmcia_configure_socket(const struct pcmcia_configure - *configure) +void sa1100_h3600_pcmcia_remove_sleeve( void ) { - unsigned long flags; + if ( sa1100_h3600_pcmcia_ops != NULL ) { + h3600_pcmcia_shutdown(); + sa1100_h3600_pcmcia_ops = NULL; + } +} + +EXPORT_SYMBOL(sa1100_h3600_pcmcia_change_sleeves); +EXPORT_SYMBOL(sa1100_h3600_pcmcia_remove_sleeve); - if(configure->sock>1) return -1; - save_flags_cli(flags); +/****************************************************/ +/* Common functions used by the different sleeves */ +/****************************************************/ - switch (configure->vcc) { - case 0: - clr_h3600_egpio(EGPIO_H3600_OPT_ON); - break; +int sa1100_h3600_common_pcmcia_init( struct pcmcia_init *init ) +{ + int irq, res; - case 33: - case 50: - set_h3600_egpio(EGPIO_H3600_OPT_ON); - break; + /* Enable PCMCIA/CF bus: */ + set_h3600_egpio(IPAQ_EGPIO_OPT_ON); + clr_h3600_egpio(IPAQ_EGPIO_OPT_RESET); + clr_h3600_egpio(IPAQ_EGPIO_CARD_RESET); + + /* 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 ) { + printk( KERN_ERR __FUNCTION__ ": Request for IRQ %u failed\n", irq ); + return -1; + } + + irq = IRQ_GPIO_H3600_PCMCIA_CD1; + res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD1", NULL ); + if( res < 0 ) { + printk( KERN_ERR __FUNCTION__ ": Request for IRQ %u failed\n", irq ); + return -1; + } - default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - restore_flags(flags); - return -1; - } + return 2; /* Always allow for two PCMCIA devices */ +} - if (configure->reset) - set_h3600_egpio(EGPIO_H3600_CARD_RESET); - else - clr_h3600_egpio(EGPIO_H3600_CARD_RESET); +int sa1100_h3600_common_pcmcia_shutdown( void ) +{ + /* disable IRQs */ + free_irq( IRQ_GPIO_H3600_PCMCIA_CD0, NULL ); + free_irq( IRQ_GPIO_H3600_PCMCIA_CD1, NULL ); + + /* Disable CF bus: */ + clr_h3600_egpio(IPAQ_EGPIO_OPT_ON); + set_h3600_egpio(IPAQ_EGPIO_OPT_RESET); + return 0; +} - /* Silently ignore Vpp, output enable, speaker enable. */ +int sa1100_h3600_common_pcmcia_socket_state( struct pcmcia_state_array *state_array ) +{ + unsigned long levels; - restore_flags(flags); + if (state_array->size < 2) + return -1; - return 0; + 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[1].detect=((levels & GPIO_H3600_PCMCIA_CD1)==0)?1:0; + state_array->state[1].ready=(levels & GPIO_H3600_PCMCIA_IRQ1)?1:0; + + 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 -}; +int sa1100_h3600_common_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; +} + +EXPORT_SYMBOL(sa1100_h3600_common_pcmcia_init); +EXPORT_SYMBOL(sa1100_h3600_common_pcmcia_shutdown); +EXPORT_SYMBOL(sa1100_h3600_common_pcmcia_socket_state); +EXPORT_SYMBOL(sa1100_h3600_common_pcmcia_get_irq_info); +