2008-06-27 13:37:19 +04:00
/*
* drivers / mfd / mfd - core . c
*
* core MFD support
* Copyright ( c ) 2006 Ian Molton
* Copyright ( c ) 2007 , 2008 Dmitry Baryshkov
*
* 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 .
*
*/
# include <linux/kernel.h>
# include <linux/platform_device.h>
# include <linux/mfd/core.h>
2008-07-29 03:30:26 +04:00
static int mfd_add_device ( struct device * parent , int id ,
2008-07-28 20:29:09 +04:00
const struct mfd_cell * cell ,
struct resource * mem_base ,
int irq_base )
2008-06-27 13:37:19 +04:00
{
2008-07-26 01:59:29 +04:00
struct resource * res ;
2008-06-27 13:37:19 +04:00
struct platform_device * pdev ;
int ret = - ENOMEM ;
int r ;
2009-07-27 17:45:51 +04:00
pdev = platform_device_alloc ( cell - > name , id + cell - > id ) ;
2008-06-27 13:37:19 +04:00
if ( ! pdev )
goto fail_alloc ;
2008-07-26 01:59:29 +04:00
res = kzalloc ( sizeof ( * res ) * cell - > num_resources , GFP_KERNEL ) ;
if ( ! res )
goto fail_device ;
2008-07-29 03:30:26 +04:00
pdev - > dev . parent = parent ;
2008-12-18 12:54:12 +03:00
platform_set_drvdata ( pdev , cell - > driver_data ) ;
2008-06-27 13:37:19 +04:00
ret = platform_device_add_data ( pdev ,
2008-07-29 03:23:32 +04:00
cell - > platform_data , cell - > data_size ) ;
2008-06-27 13:37:19 +04:00
if ( ret )
2008-07-26 01:59:29 +04:00
goto fail_res ;
2008-06-27 13:37:19 +04:00
for ( r = 0 ; r < cell - > num_resources ; r + + ) {
res [ r ] . name = cell - > resources [ r ] . name ;
res [ r ] . flags = cell - > resources [ r ] . flags ;
/* Find out base to use */
if ( cell - > resources [ r ] . flags & IORESOURCE_MEM ) {
res [ r ] . parent = mem_base ;
res [ r ] . start = mem_base - > start +
cell - > resources [ r ] . start ;
res [ r ] . end = mem_base - > start +
cell - > resources [ r ] . end ;
} else if ( cell - > resources [ r ] . flags & IORESOURCE_IRQ ) {
res [ r ] . start = irq_base +
cell - > resources [ r ] . start ;
res [ r ] . end = irq_base +
cell - > resources [ r ] . end ;
} else {
res [ r ] . parent = cell - > resources [ r ] . parent ;
res [ r ] . start = cell - > resources [ r ] . start ;
res [ r ] . end = cell - > resources [ r ] . end ;
}
}
platform_device_add_resources ( pdev , res , cell - > num_resources ) ;
ret = platform_device_add ( pdev ) ;
if ( ret )
2008-07-26 01:59:29 +04:00
goto fail_res ;
kfree ( res ) ;
2008-06-27 13:37:19 +04:00
return 0 ;
/* platform_device_del(pdev); */
2008-07-26 01:59:29 +04:00
fail_res :
kfree ( res ) ;
2008-06-27 13:37:19 +04:00
fail_device :
platform_device_put ( pdev ) ;
fail_alloc :
return ret ;
}
2008-07-29 03:30:26 +04:00
int mfd_add_devices ( struct device * parent , int id ,
2008-07-28 20:29:09 +04:00
const struct mfd_cell * cells , int n_devs ,
struct resource * mem_base ,
int irq_base )
2008-06-27 13:37:19 +04:00
{
int i ;
int ret = 0 ;
for ( i = 0 ; i < n_devs ; i + + ) {
2008-07-29 03:30:26 +04:00
ret = mfd_add_device ( parent , id , cells + i , mem_base , irq_base ) ;
2008-06-27 13:37:19 +04:00
if ( ret )
break ;
}
if ( ret )
mfd_remove_devices ( parent ) ;
return ret ;
}
EXPORT_SYMBOL ( mfd_add_devices ) ;
static int mfd_remove_devices_fn ( struct device * dev , void * unused )
{
2008-07-28 20:26:42 +04:00
platform_device_unregister ( to_platform_device ( dev ) ) ;
2008-06-27 13:37:19 +04:00
return 0 ;
}
2008-07-29 03:30:26 +04:00
void mfd_remove_devices ( struct device * parent )
2008-06-27 13:37:19 +04:00
{
2008-07-29 03:30:26 +04:00
device_for_each_child ( parent , NULL , mfd_remove_devices_fn ) ;
2008-06-27 13:37:19 +04:00
}
EXPORT_SYMBOL ( mfd_remove_devices ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Ian Molton, Dmitry Baryshkov " ) ;