2007-09-23 16:00:20 +01:00
/*
* linux / drivers / pcmcia / pxa / pxa_cm_x270 . c
*
* 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 .
*
* Compulab Ltd . , 2003 , 2007
* Mike Rapoport < mike @ compulab . co . il >
*
*/
# include <linux/kernel.h>
# include <linux/sched.h>
# include <linux/platform_device.h>
# include <linux/irq.h>
# include <linux/delay.h>
# include <pcmcia/ss.h>
# include <asm/hardware.h>
# include <asm/arch/pxa-regs.h>
2008-03-03 09:44:25 +08:00
# include <asm/arch/pxa2xx-gpio.h>
2007-09-23 16:00:20 +01:00
# include <asm/arch/cm-x270.h>
# include "soc_common.h"
static struct pcmcia_irqs irqs [ ] = {
{ 0 , PCMCIA_S0_CD_VALID , " PCMCIA0 CD " } ,
{ 1 , PCMCIA_S1_CD_VALID , " PCMCIA1 CD " } ,
} ;
static int cmx270_pcmcia_hw_init ( struct soc_pcmcia_socket * skt )
{
GPSR ( GPIO48_nPOE ) = GPIO_bit ( GPIO48_nPOE ) |
GPIO_bit ( GPIO49_nPWE ) |
GPIO_bit ( GPIO50_nPIOR ) |
GPIO_bit ( GPIO51_nPIOW ) |
GPIO_bit ( GPIO85_nPCE_1 ) |
GPIO_bit ( GPIO54_nPCE_2 ) ;
pxa_gpio_mode ( GPIO48_nPOE_MD ) ;
pxa_gpio_mode ( GPIO49_nPWE_MD ) ;
pxa_gpio_mode ( GPIO50_nPIOR_MD ) ;
pxa_gpio_mode ( GPIO51_nPIOW_MD ) ;
pxa_gpio_mode ( GPIO85_nPCE_1_MD ) ;
pxa_gpio_mode ( GPIO54_nPCE_2_MD ) ;
pxa_gpio_mode ( GPIO55_nPREG_MD ) ;
pxa_gpio_mode ( GPIO56_nPWAIT_MD ) ;
pxa_gpio_mode ( GPIO57_nIOIS16_MD ) ;
/* Reset signal */
pxa_gpio_mode ( GPIO53_nPCE_2 | GPIO_OUT ) ;
GPCR ( GPIO53_nPCE_2 ) = GPIO_bit ( GPIO53_nPCE_2 ) ;
set_irq_type ( PCMCIA_S0_CD_VALID , IRQ_TYPE_EDGE_BOTH ) ;
set_irq_type ( PCMCIA_S1_CD_VALID , IRQ_TYPE_EDGE_BOTH ) ;
/* irq's for slots: */
set_irq_type ( PCMCIA_S0_RDYINT , IRQ_TYPE_EDGE_FALLING ) ;
set_irq_type ( PCMCIA_S1_RDYINT , IRQ_TYPE_EDGE_FALLING ) ;
skt - > irq = ( skt - > nr = = 0 ) ? PCMCIA_S0_RDYINT : PCMCIA_S1_RDYINT ;
return soc_pcmcia_request_irqs ( skt , irqs , ARRAY_SIZE ( irqs ) ) ;
}
static void cmx270_pcmcia_shutdown ( struct soc_pcmcia_socket * skt )
{
soc_pcmcia_free_irqs ( skt , irqs , ARRAY_SIZE ( irqs ) ) ;
set_irq_type ( IRQ_TO_GPIO ( PCMCIA_S0_CD_VALID ) , IRQ_TYPE_NONE ) ;
set_irq_type ( IRQ_TO_GPIO ( PCMCIA_S1_CD_VALID ) , IRQ_TYPE_NONE ) ;
set_irq_type ( IRQ_TO_GPIO ( PCMCIA_S0_RDYINT ) , IRQ_TYPE_NONE ) ;
set_irq_type ( IRQ_TO_GPIO ( PCMCIA_S1_RDYINT ) , IRQ_TYPE_NONE ) ;
}
static void cmx270_pcmcia_socket_state ( struct soc_pcmcia_socket * skt ,
struct pcmcia_state * state )
{
state - > detect = ( PCC_DETECT ( skt - > nr ) = = 0 ) ? 1 : 0 ;
state - > ready = ( PCC_READY ( skt - > nr ) = = 0 ) ? 0 : 1 ;
state - > bvd1 = 1 ;
state - > bvd2 = 1 ;
state - > vs_3v = 0 ;
state - > vs_Xv = 0 ;
state - > wrprot = 0 ; /* not available */
}
static int cmx270_pcmcia_configure_socket ( struct soc_pcmcia_socket * skt ,
const socket_state_t * state )
{
GPSR ( GPIO49_nPWE ) = GPIO_bit ( GPIO49_nPWE ) ;
pxa_gpio_mode ( GPIO49_nPWE | GPIO_OUT ) ;
switch ( skt - > nr ) {
case 0 :
if ( state - > flags & SS_RESET ) {
GPCR ( GPIO49_nPWE ) = GPIO_bit ( GPIO49_nPWE ) ;
GPSR ( GPIO53_nPCE_2 ) = GPIO_bit ( GPIO53_nPCE_2 ) ;
udelay ( 10 ) ;
GPCR ( GPIO53_nPCE_2 ) = GPIO_bit ( GPIO53_nPCE_2 ) ;
GPSR ( GPIO49_nPWE ) = GPIO_bit ( GPIO49_nPWE ) ;
}
break ;
case 1 :
if ( state - > flags & SS_RESET ) {
GPCR ( GPIO49_nPWE ) = GPIO_bit ( GPIO49_nPWE ) ;
GPSR ( GPIO53_nPCE_2 ) = GPIO_bit ( GPIO53_nPCE_2 ) ;
udelay ( 10 ) ;
GPCR ( GPIO53_nPCE_2 ) = GPIO_bit ( GPIO53_nPCE_2 ) ;
GPSR ( GPIO49_nPWE ) = GPIO_bit ( GPIO49_nPWE ) ;
}
break ;
}
pxa_gpio_mode ( GPIO49_nPWE_MD ) ;
return 0 ;
}
static void cmx270_pcmcia_socket_init ( struct soc_pcmcia_socket * skt )
{
}
static void cmx270_pcmcia_socket_suspend ( struct soc_pcmcia_socket * skt )
{
}
static struct pcmcia_low_level cmx270_pcmcia_ops = {
. owner = THIS_MODULE ,
. hw_init = cmx270_pcmcia_hw_init ,
. hw_shutdown = cmx270_pcmcia_shutdown ,
. socket_state = cmx270_pcmcia_socket_state ,
. configure_socket = cmx270_pcmcia_configure_socket ,
. socket_init = cmx270_pcmcia_socket_init ,
. socket_suspend = cmx270_pcmcia_socket_suspend ,
. nr = 2 ,
} ;
static struct platform_device * cmx270_pcmcia_device ;
static int __init cmx270_pcmcia_init ( void )
{
int ret ;
cmx270_pcmcia_device = platform_device_alloc ( " pxa2xx-pcmcia " , - 1 ) ;
if ( ! cmx270_pcmcia_device )
return - ENOMEM ;
cmx270_pcmcia_device - > dev . platform_data = & cmx270_pcmcia_ops ;
printk ( KERN_INFO " Registering cm-x270 PCMCIA interface. \n " ) ;
ret = platform_device_add ( cmx270_pcmcia_device ) ;
if ( ret )
platform_device_put ( cmx270_pcmcia_device ) ;
return ret ;
}
static void __exit cmx270_pcmcia_exit ( void )
{
platform_device_unregister ( cmx270_pcmcia_device ) ;
}
module_init ( cmx270_pcmcia_init ) ;
module_exit ( cmx270_pcmcia_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Mike Rapoport <mike@compulab.co.il> " ) ;
MODULE_DESCRIPTION ( " CM-x270 PCMCIA driver " ) ;