2010-11-24 12:17:14 +03:00
/*
* CE4100 ' s SPI device is more or less the same one as found on PXA
*
*/
# include <linux/pci.h>
# include <linux/platform_device.h>
# include <linux/of_device.h>
# include <linux/spi/pxa2xx_spi.h>
2011-02-02 22:01:21 +03:00
struct ce4100_info {
2010-11-24 12:17:14 +03:00
struct ssp_device ssp ;
2011-02-02 22:01:21 +03:00
struct platform_device * spi_pdev ;
2010-11-24 12:17:14 +03:00
} ;
static DEFINE_MUTEX ( ssp_lock ) ;
static LIST_HEAD ( ssp_list ) ;
struct ssp_device * pxa_ssp_request ( int port , const char * label )
{
struct ssp_device * ssp = NULL ;
mutex_lock ( & ssp_lock ) ;
list_for_each_entry ( ssp , & ssp_list , node ) {
if ( ssp - > port_id = = port & & ssp - > use_count = = 0 ) {
ssp - > use_count + + ;
ssp - > label = label ;
break ;
}
}
mutex_unlock ( & ssp_lock ) ;
if ( & ssp - > node = = & ssp_list )
return NULL ;
return ssp ;
}
EXPORT_SYMBOL_GPL ( pxa_ssp_request ) ;
void pxa_ssp_free ( struct ssp_device * ssp )
{
mutex_lock ( & ssp_lock ) ;
if ( ssp - > use_count ) {
ssp - > use_count - - ;
ssp - > label = NULL ;
} else
dev_err ( & ssp - > pdev - > dev , " device already free \n " ) ;
mutex_unlock ( & ssp_lock ) ;
}
EXPORT_SYMBOL_GPL ( pxa_ssp_free ) ;
static int __devinit ce4100_spi_probe ( struct pci_dev * dev ,
const struct pci_device_id * ent )
{
int ret ;
resource_size_t phys_beg ;
resource_size_t phys_len ;
2011-02-02 22:01:21 +03:00
struct ce4100_info * spi_info ;
2010-11-24 12:17:14 +03:00
struct platform_device * pdev ;
2011-02-02 22:01:21 +03:00
struct pxa2xx_spi_master spi_pdata ;
2010-11-24 12:17:14 +03:00
struct ssp_device * ssp ;
ret = pci_enable_device ( dev ) ;
if ( ret )
return ret ;
phys_beg = pci_resource_start ( dev , 0 ) ;
phys_len = pci_resource_len ( dev , 0 ) ;
if ( ! request_mem_region ( phys_beg , phys_len ,
" CE4100 SPI " ) ) {
dev_err ( & dev - > dev , " Can't request register space. \n " ) ;
ret = - EBUSY ;
return ret ;
}
2011-02-02 22:01:21 +03:00
pdev = platform_device_alloc ( " pxa2xx-spi " , dev - > devfn ) ;
2010-11-24 12:17:14 +03:00
spi_info = kzalloc ( sizeof ( * spi_info ) , GFP_KERNEL ) ;
2011-02-02 22:01:21 +03:00
if ( ! pdev | | ! spi_info ) {
2010-11-24 12:17:14 +03:00
ret = - ENOMEM ;
2011-02-02 22:01:21 +03:00
goto err_nomem ;
2010-11-24 12:17:14 +03:00
}
2011-02-02 22:01:21 +03:00
memset ( & spi_pdata , 0 , sizeof ( spi_pdata ) ) ;
spi_pdata . num_chipselect = dev - > devfn ;
2010-11-24 12:17:14 +03:00
2011-02-02 22:01:21 +03:00
ret = platform_device_add_data ( pdev , & spi_pdata , sizeof ( spi_pdata ) ) ;
if ( ret )
goto err_nomem ;
2010-11-24 12:17:14 +03:00
2011-02-02 22:01:21 +03:00
pdev - > dev . parent = & dev - > dev ;
2010-11-24 12:17:14 +03:00
pdev - > dev . of_node = dev - > dev . of_node ;
2011-02-02 22:01:21 +03:00
ssp = & spi_info - > ssp ;
2010-11-24 12:17:14 +03:00
ssp - > phys_base = pci_resource_start ( dev , 0 ) ;
ssp - > mmio_base = ioremap ( phys_beg , phys_len ) ;
if ( ! ssp - > mmio_base ) {
dev_err ( & pdev - > dev , " failed to ioremap() registers \n " ) ;
ret = - EIO ;
2011-02-02 22:01:21 +03:00
goto err_nomem ;
2010-11-24 12:17:14 +03:00
}
ssp - > irq = dev - > irq ;
ssp - > port_id = pdev - > id ;
ssp - > type = PXA25x_SSP ;
mutex_lock ( & ssp_lock ) ;
list_add ( & ssp - > node , & ssp_list ) ;
mutex_unlock ( & ssp_lock ) ;
pci_set_drvdata ( dev , spi_info ) ;
2011-02-02 22:01:21 +03:00
ret = platform_device_add ( pdev ) ;
2010-11-24 12:17:14 +03:00
if ( ret )
goto err_dev_add ;
return ret ;
err_dev_add :
pci_set_drvdata ( dev , NULL ) ;
mutex_lock ( & ssp_lock ) ;
list_del ( & ssp - > node ) ;
mutex_unlock ( & ssp_lock ) ;
iounmap ( ssp - > mmio_base ) ;
2011-02-02 22:01:21 +03:00
err_nomem :
2010-11-24 12:17:14 +03:00
release_mem_region ( phys_beg , phys_len ) ;
2011-02-02 22:01:21 +03:00
platform_device_put ( pdev ) ;
kfree ( spi_info ) ;
2010-11-24 12:17:14 +03:00
return ret ;
}
static void __devexit ce4100_spi_remove ( struct pci_dev * dev )
{
2011-02-02 22:01:21 +03:00
struct ce4100_info * spi_info ;
2010-11-24 12:17:14 +03:00
struct ssp_device * ssp ;
spi_info = pci_get_drvdata ( dev ) ;
ssp = & spi_info - > ssp ;
2011-02-02 22:01:21 +03:00
platform_device_unregister ( spi_info - > spi_pdev ) ;
2010-11-24 12:17:14 +03:00
iounmap ( ssp - > mmio_base ) ;
release_mem_region ( pci_resource_start ( dev , 0 ) ,
pci_resource_len ( dev , 0 ) ) ;
mutex_lock ( & ssp_lock ) ;
list_del ( & ssp - > node ) ;
mutex_unlock ( & ssp_lock ) ;
pci_set_drvdata ( dev , NULL ) ;
pci_disable_device ( dev ) ;
kfree ( spi_info ) ;
}
static struct pci_device_id ce4100_spi_devices [ ] __devinitdata = {
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , 0x2e6a ) } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( pci , ce4100_spi_devices ) ;
static struct pci_driver ce4100_spi_driver = {
. name = " ce4100_spi " ,
. id_table = ce4100_spi_devices ,
. probe = ce4100_spi_probe ,
. remove = __devexit_p ( ce4100_spi_remove ) ,
} ;
static int __init ce4100_spi_init ( void )
{
return pci_register_driver ( & ce4100_spi_driver ) ;
}
module_init ( ce4100_spi_init ) ;
static void __exit ce4100_spi_exit ( void )
{
pci_unregister_driver ( & ce4100_spi_driver ) ;
}
module_exit ( ce4100_spi_exit ) ;
MODULE_DESCRIPTION ( " CE4100 PCI-SPI glue code for PXA's driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_AUTHOR ( " Sebastian Andrzej Siewior <bigeasy@linutronix.de> " ) ;