2008-08-19 14:15:53 +04:00
/*
2009-11-14 15:39:13 +03:00
* Viper / Zeus PCMCIA support
2008-08-19 14:15:53 +04:00
* Copyright 2004 Arcom Control Systems
*
* Maintained by Marc Zyngier < maz @ misterjones . org >
*
* Based on :
* iPAQ h2200 PCMCIA support
* Copyright 2004 Koen Kooi < koen @ vestingbar . nl >
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file COPYING in the main directory of this archive for
* more details .
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/interrupt.h>
# include <linux/platform_device.h>
# include <linux/gpio.h>
# include <pcmcia/ss.h>
# include <asm/irq.h>
2012-08-24 17:16:48 +04:00
# include <linux/platform_data/pcmcia-pxa2xx_viper.h>
2008-08-19 14:15:53 +04:00
# include "soc_common.h"
# include "pxa2xx_base.h"
2009-11-14 15:39:13 +03:00
static struct platform_device * arcom_pcmcia_dev ;
static inline struct arcom_pcmcia_pdata * viper_get_pdata ( void )
{
return arcom_pcmcia_dev - > dev . platform_data ;
}
2008-08-19 14:15:53 +04:00
static int viper_pcmcia_hw_init ( struct soc_pcmcia_socket * skt )
{
2009-11-14 15:39:13 +03:00
struct arcom_pcmcia_pdata * pdata = viper_get_pdata ( ) ;
2008-08-19 14:15:53 +04:00
unsigned long flags ;
2012-01-14 02:56:32 +04:00
skt - > stat [ SOC_STAT_CD ] . gpio = pdata - > cd_gpio ;
skt - > stat [ SOC_STAT_CD ] . name = " PCMCIA_CD " ;
skt - > stat [ SOC_STAT_RDY ] . gpio = pdata - > rdy_gpio ;
skt - > stat [ SOC_STAT_RDY ] . name = " CF ready " ;
2008-08-19 14:15:53 +04:00
2009-11-14 15:39:13 +03:00
if ( gpio_request ( pdata - > pwr_gpio , " CF power " ) )
2008-08-19 14:15:53 +04:00
goto err_request_pwr ;
local_irq_save ( flags ) ;
2012-01-14 02:56:32 +04:00
if ( gpio_direction_output ( pdata - > pwr_gpio , 0 ) ) {
2008-08-19 14:15:53 +04:00
local_irq_restore ( flags ) ;
goto err_dir ;
}
local_irq_restore ( flags ) ;
2012-01-14 02:56:32 +04:00
return 0 ;
2008-08-19 14:15:53 +04:00
err_dir :
2009-11-14 15:39:13 +03:00
gpio_free ( pdata - > pwr_gpio ) ;
2008-08-19 14:15:53 +04:00
err_request_pwr :
2009-11-14 15:39:13 +03:00
dev_err ( & arcom_pcmcia_dev - > dev , " Failed to setup PCMCIA GPIOs \n " ) ;
2008-08-19 14:15:53 +04:00
return - 1 ;
}
/*
* Release all resources .
*/
static void viper_pcmcia_hw_shutdown ( struct soc_pcmcia_socket * skt )
{
2009-11-14 15:39:13 +03:00
struct arcom_pcmcia_pdata * pdata = viper_get_pdata ( ) ;
gpio_free ( pdata - > pwr_gpio ) ;
2008-08-19 14:15:53 +04:00
}
static void viper_pcmcia_socket_state ( struct soc_pcmcia_socket * skt ,
struct pcmcia_state * state )
{
state - > vs_3v = 1 ; /* Can only apply 3.3V */
state - > vs_Xv = 0 ;
}
static int viper_pcmcia_configure_socket ( struct soc_pcmcia_socket * skt ,
const socket_state_t * state )
{
2009-11-14 15:39:13 +03:00
struct arcom_pcmcia_pdata * pdata = viper_get_pdata ( ) ;
2008-08-19 14:15:53 +04:00
/* Silently ignore Vpp, output enable, speaker enable. */
2009-11-14 15:39:13 +03:00
pdata - > reset ( state - > flags & SS_RESET ) ;
2008-08-19 14:15:53 +04:00
/* Apply socket voltage */
switch ( state - > Vcc ) {
case 0 :
2009-11-14 15:39:13 +03:00
gpio_set_value ( pdata - > pwr_gpio , 0 ) ;
2008-08-19 14:15:53 +04:00
break ;
case 33 :
2009-11-14 15:39:13 +03:00
gpio_set_value ( pdata - > pwr_gpio , 1 ) ;
2008-08-19 14:15:53 +04:00
break ;
default :
2009-11-14 15:39:13 +03:00
dev_err ( & arcom_pcmcia_dev - > dev , " Unsupported Vcc:%d \n " , state - > Vcc ) ;
2008-08-19 14:15:53 +04:00
return - 1 ;
}
return 0 ;
}
2009-11-14 15:39:13 +03:00
static struct pcmcia_low_level viper_pcmcia_ops = {
2008-08-19 14:15:53 +04:00
. owner = THIS_MODULE ,
. hw_init = viper_pcmcia_hw_init ,
. hw_shutdown = viper_pcmcia_hw_shutdown ,
. socket_state = viper_pcmcia_socket_state ,
. configure_socket = viper_pcmcia_configure_socket ,
. nr = 1 ,
} ;
static struct platform_device * viper_pcmcia_device ;
2009-11-14 15:39:13 +03:00
static int viper_pcmcia_probe ( struct platform_device * pdev )
2008-08-19 14:15:53 +04:00
{
int ret ;
2009-11-14 15:39:13 +03:00
/* I can't imagine more than one device, but you never know... */
if ( arcom_pcmcia_dev )
return - EEXIST ;
if ( ! pdev - > dev . platform_data )
return - EINVAL ;
2008-08-19 14:15:53 +04:00
viper_pcmcia_device = platform_device_alloc ( " pxa2xx-pcmcia " , - 1 ) ;
if ( ! viper_pcmcia_device )
return - ENOMEM ;
2009-11-14 15:39:13 +03:00
arcom_pcmcia_dev = pdev ;
viper_pcmcia_device - > dev . parent = & pdev - > dev ;
2008-08-19 14:15:53 +04:00
ret = platform_device_add_data ( viper_pcmcia_device ,
& viper_pcmcia_ops ,
sizeof ( viper_pcmcia_ops ) ) ;
if ( ! ret )
ret = platform_device_add ( viper_pcmcia_device ) ;
2009-11-14 15:39:13 +03:00
if ( ret ) {
2008-08-19 14:15:53 +04:00
platform_device_put ( viper_pcmcia_device ) ;
2009-11-14 15:39:13 +03:00
arcom_pcmcia_dev = NULL ;
}
2008-08-19 14:15:53 +04:00
return ret ;
}
2009-11-14 15:39:13 +03:00
static int viper_pcmcia_remove ( struct platform_device * pdev )
2008-08-19 14:15:53 +04:00
{
platform_device_unregister ( viper_pcmcia_device ) ;
2009-11-14 15:39:13 +03:00
arcom_pcmcia_dev = NULL ;
return 0 ;
}
static struct platform_device_id viper_pcmcia_id_table [ ] = {
{ . name = " viper-pcmcia " , } ,
{ . name = " zeus-pcmcia " , } ,
{ } ,
} ;
static struct platform_driver viper_pcmcia_driver = {
. probe = viper_pcmcia_probe ,
. remove = viper_pcmcia_remove ,
. driver = {
. name = " arcom-pcmcia " ,
} ,
. id_table = viper_pcmcia_id_table ,
} ;
2011-11-27 08:53:06 +04:00
module_platform_driver ( viper_pcmcia_driver ) ;
2008-08-19 14:15:53 +04:00
2009-11-14 15:39:13 +03:00
MODULE_DEVICE_TABLE ( platform , viper_pcmcia_id_table ) ;
2008-08-19 14:15:53 +04:00
MODULE_LICENSE ( " GPL " ) ;