2011-05-09 20:56:46 +04:00
/*
* Broadcom specific AMBA
* Bus subsystem
*
* Licensed under the GNU / GPL . See COPYING for details .
*/
# include "bcma_private.h"
2011-07-02 00:06:37 +04:00
# include <linux/module.h>
2012-08-10 23:23:53 +04:00
# include <linux/platform_device.h>
2011-05-09 20:56:46 +04:00
# include <linux/bcma/bcma.h>
2011-06-26 12:19:44 +04:00
# include <linux/slab.h>
2014-09-26 02:09:19 +04:00
# include <linux/of_address.h>
2014-11-01 18:54:56 +03:00
# include <linux/of_irq.h>
2011-05-09 20:56:46 +04:00
MODULE_DESCRIPTION ( " Broadcom's specific AMBA driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
2012-01-31 03:03:36 +04:00
/* contains the number the next bus should get. */
static unsigned int bcma_bus_next_num = 0 ;
/* bcma_buses_mutex locks the bcma_bus_next_num */
static DEFINE_MUTEX ( bcma_buses_mutex ) ;
2011-05-09 20:56:46 +04:00
static int bcma_bus_match ( struct device * dev , struct device_driver * drv ) ;
static int bcma_device_probe ( struct device * dev ) ;
static int bcma_device_remove ( struct device * dev ) ;
2011-08-20 00:14:47 +04:00
static int bcma_device_uevent ( struct device * dev , struct kobj_uevent_env * env ) ;
2011-05-09 20:56:46 +04:00
static ssize_t manuf_show ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct bcma_device * core = container_of ( dev , struct bcma_device , dev ) ;
return sprintf ( buf , " 0x%03X \n " , core - > id . manuf ) ;
}
2013-10-07 10:55:45 +04:00
static DEVICE_ATTR_RO ( manuf ) ;
2011-05-09 20:56:46 +04:00
static ssize_t id_show ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct bcma_device * core = container_of ( dev , struct bcma_device , dev ) ;
return sprintf ( buf , " 0x%03X \n " , core - > id . id ) ;
}
2013-10-07 10:55:45 +04:00
static DEVICE_ATTR_RO ( id ) ;
2011-05-09 20:56:46 +04:00
static ssize_t rev_show ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct bcma_device * core = container_of ( dev , struct bcma_device , dev ) ;
return sprintf ( buf , " 0x%02X \n " , core - > id . rev ) ;
}
2013-10-07 10:55:45 +04:00
static DEVICE_ATTR_RO ( rev ) ;
2011-05-09 20:56:46 +04:00
static ssize_t class_show ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct bcma_device * core = container_of ( dev , struct bcma_device , dev ) ;
return sprintf ( buf , " 0x%X \n " , core - > id . class ) ;
}
2013-10-07 10:55:45 +04:00
static DEVICE_ATTR_RO ( class ) ;
static struct attribute * bcma_device_attrs [ ] = {
& dev_attr_manuf . attr ,
& dev_attr_id . attr ,
& dev_attr_rev . attr ,
& dev_attr_class . attr ,
NULL ,
2011-05-09 20:56:46 +04:00
} ;
2013-10-07 10:55:45 +04:00
ATTRIBUTE_GROUPS ( bcma_device ) ;
2011-05-09 20:56:46 +04:00
static struct bus_type bcma_bus_type = {
. name = " bcma " ,
. match = bcma_bus_match ,
. probe = bcma_device_probe ,
. remove = bcma_device_remove ,
2011-08-20 00:14:47 +04:00
. uevent = bcma_device_uevent ,
2013-10-07 10:55:45 +04:00
. dev_groups = bcma_device_groups ,
2011-05-09 20:56:46 +04:00
} ;
2012-07-11 01:45:49 +04:00
static u16 bcma_cc_core_id ( struct bcma_bus * bus )
{
if ( bus - > chipinfo . id = = BCMA_CHIP_ID_BCM4706 )
return BCMA_CORE_4706_CHIPCOMMON ;
return BCMA_CORE_CHIPCOMMON ;
}
2013-01-04 03:51:20 +04:00
struct bcma_device * bcma_find_core_unit ( struct bcma_bus * bus , u16 coreid ,
u8 unit )
2012-09-29 22:40:18 +04:00
{
struct bcma_device * core ;
list_for_each_entry ( core , & bus - > cores , list ) {
if ( core - > id . id = = coreid & & core - > core_unit = = unit )
return core ;
}
return NULL ;
}
2014-01-05 04:10:43 +04:00
EXPORT_SYMBOL_GPL ( bcma_find_core_unit ) ;
2012-09-29 22:40:18 +04:00
2013-06-26 12:02:11 +04:00
bool bcma_wait_value ( struct bcma_device * core , u16 reg , u32 mask , u32 value ,
int timeout )
{
unsigned long deadline = jiffies + timeout ;
u32 val ;
do {
val = bcma_read32 ( core , reg ) ;
if ( ( val & mask ) = = value )
return true ;
cpu_relax ( ) ;
udelay ( 10 ) ;
} while ( ! time_after_eq ( jiffies , deadline ) ) ;
bcma_warn ( core - > bus , " Timeout waiting for register 0x%04X! \n " , reg ) ;
return false ;
}
2011-05-09 20:56:46 +04:00
static void bcma_release_core_dev ( struct device * dev )
{
struct bcma_device * core = container_of ( dev , struct bcma_device , dev ) ;
2011-07-23 03:20:08 +04:00
if ( core - > io_addr )
iounmap ( core - > io_addr ) ;
if ( core - > io_wrap )
iounmap ( core - > io_wrap ) ;
2011-05-09 20:56:46 +04:00
kfree ( core ) ;
}
2014-09-05 02:18:49 +04:00
static bool bcma_is_core_needed_early ( u16 core_id )
{
switch ( core_id ) {
case BCMA_CORE_NS_NAND :
case BCMA_CORE_NS_QSPI :
return true ;
}
return false ;
}
2014-10-10 01:39:41 +04:00
# if defined(CONFIG_OF) && defined(CONFIG_OF_ADDRESS)
2014-09-26 02:09:19 +04:00
static struct device_node * bcma_of_find_child_device ( struct platform_device * parent ,
struct bcma_device * core )
{
struct device_node * node ;
u64 size ;
const __be32 * reg ;
if ( ! parent | | ! parent - > dev . of_node )
return NULL ;
for_each_child_of_node ( parent - > dev . of_node , node ) {
reg = of_get_address ( node , 0 , & size , NULL ) ;
if ( ! reg )
continue ;
if ( of_translate_address ( node , reg ) = = core - > addr )
return node ;
}
return NULL ;
}
2014-11-01 18:54:56 +03:00
static int bcma_of_irq_parse ( struct platform_device * parent ,
struct bcma_device * core ,
struct of_phandle_args * out_irq , int num )
{
__be32 laddr [ 1 ] ;
int rc ;
if ( core - > dev . of_node ) {
rc = of_irq_parse_one ( core - > dev . of_node , num , out_irq ) ;
if ( ! rc )
return rc ;
}
out_irq - > np = parent - > dev . of_node ;
out_irq - > args_count = 1 ;
out_irq - > args [ 0 ] = num ;
laddr [ 0 ] = cpu_to_be32 ( core - > addr ) ;
return of_irq_parse_raw ( laddr , out_irq ) ;
}
static unsigned int bcma_of_get_irq ( struct platform_device * parent ,
struct bcma_device * core , int num )
{
struct of_phandle_args out_irq ;
int ret ;
if ( ! parent | | ! parent - > dev . of_node )
return 0 ;
ret = bcma_of_irq_parse ( parent , core , & out_irq , num ) ;
if ( ret ) {
bcma_debug ( core - > bus , " bcma_of_get_irq() failed with rc=%d \n " ,
ret ) ;
return 0 ;
}
return irq_create_of_mapping ( & out_irq ) ;
}
2014-09-26 02:09:19 +04:00
static void bcma_of_fill_device ( struct platform_device * parent ,
struct bcma_device * core )
{
struct device_node * node ;
node = bcma_of_find_child_device ( parent , core ) ;
if ( node )
core - > dev . of_node = node ;
2014-11-01 18:54:56 +03:00
core - > irq = bcma_of_get_irq ( parent , core , 0 ) ;
2014-09-26 02:09:19 +04:00
}
# else
static void bcma_of_fill_device ( struct platform_device * parent ,
struct bcma_device * core )
{
}
2014-11-01 18:54:56 +03:00
static inline unsigned int bcma_of_get_irq ( struct platform_device * parent ,
struct bcma_device * core , int num )
{
return 0 ;
}
2014-09-26 02:09:19 +04:00
# endif /* CONFIG_OF */
2014-11-01 18:54:55 +03:00
unsigned int bcma_core_irq ( struct bcma_device * core , int num )
{
struct bcma_bus * bus = core - > bus ;
unsigned int mips_irq ;
switch ( bus - > hosttype ) {
case BCMA_HOSTTYPE_PCI :
return bus - > host_pci - > irq ;
case BCMA_HOSTTYPE_SOC :
if ( bus - > drv_mips . core & & num = = 0 ) {
mips_irq = bcma_core_mips_irq ( core ) ;
return mips_irq < = 4 ? mips_irq + 2 : 0 ;
}
2014-11-01 18:54:56 +03:00
if ( bus - > host_pdev )
return bcma_of_get_irq ( bus - > host_pdev , core , num ) ;
return 0 ;
2014-11-01 18:54:55 +03:00
case BCMA_HOSTTYPE_SDIO :
return 0 ;
}
return 0 ;
}
EXPORT_SYMBOL ( bcma_core_irq ) ;
2014-10-03 19:00:24 +04:00
void bcma_prepare_core ( struct bcma_bus * bus , struct bcma_device * core )
2014-09-05 02:18:48 +04:00
{
core - > dev . release = bcma_release_core_dev ;
core - > dev . bus = & bcma_bus_type ;
dev_set_name ( & core - > dev , " bcma%d:%d " , bus - > num , core - > core_index ) ;
switch ( bus - > hosttype ) {
case BCMA_HOSTTYPE_PCI :
core - > dev . parent = & bus - > host_pci - > dev ;
core - > dma_dev = & bus - > host_pci - > dev ;
core - > irq = bus - > host_pci - > irq ;
break ;
case BCMA_HOSTTYPE_SOC :
core - > dev . dma_mask = & core - > dev . coherent_dma_mask ;
2014-09-26 02:09:19 +04:00
if ( bus - > host_pdev ) {
core - > dma_dev = & bus - > host_pdev - > dev ;
core - > dev . parent = & bus - > host_pdev - > dev ;
bcma_of_fill_device ( bus - > host_pdev , core ) ;
} else {
core - > dma_dev = & core - > dev ;
}
2014-09-05 02:18:48 +04:00
break ;
case BCMA_HOSTTYPE_SDIO :
break ;
}
2014-10-03 19:00:24 +04:00
}
2015-01-16 22:59:39 +03:00
void bcma_init_bus ( struct bcma_bus * bus )
{
mutex_lock ( & bcma_buses_mutex ) ;
bus - > num = bcma_bus_next_num + + ;
mutex_unlock ( & bcma_buses_mutex ) ;
INIT_LIST_HEAD ( & bus - > cores ) ;
bus - > nr_cores = 0 ;
bcma_detect_chip ( bus ) ;
}
2014-10-03 19:00:24 +04:00
static void bcma_register_core ( struct bcma_bus * bus , struct bcma_device * core )
{
int err ;
2014-09-05 02:18:48 +04:00
err = device_register ( & core - > dev ) ;
if ( err ) {
bcma_err ( bus , " Could not register dev for core 0x%03X \n " ,
core - > id . id ) ;
put_device ( & core - > dev ) ;
return ;
}
core - > dev_registered = true ;
}
static int bcma_register_devices ( struct bcma_bus * bus )
2011-05-09 20:56:46 +04:00
{
struct bcma_device * core ;
2014-09-05 02:18:48 +04:00
int err ;
2011-05-09 20:56:46 +04:00
list_for_each_entry ( core , & bus - > cores , list ) {
/* We support that cores ourself */
switch ( core - > id . id ) {
2012-07-11 01:45:49 +04:00
case BCMA_CORE_4706_CHIPCOMMON :
2011-05-09 20:56:46 +04:00
case BCMA_CORE_CHIPCOMMON :
2014-09-09 00:53:36 +04:00
case BCMA_CORE_NS_CHIPCOMMON_B :
2011-05-09 20:56:46 +04:00
case BCMA_CORE_PCI :
case BCMA_CORE_PCIE :
2014-07-05 03:10:41 +04:00
case BCMA_CORE_PCIE2 :
2011-07-23 03:20:09 +04:00
case BCMA_CORE_MIPS_74K :
2012-07-11 11:23:43 +04:00
case BCMA_CORE_4706_MAC_GBIT_COMMON :
2011-05-09 20:56:46 +04:00
continue ;
}
2014-09-05 02:18:49 +04:00
/* Early cores were already registered */
if ( bcma_is_core_needed_early ( core - > id . id ) )
continue ;
2013-02-19 22:41:42 +04:00
/* Only first GMAC core on BCM4706 is connected and working */
if ( core - > id . id = = BCMA_CORE_4706_MAC_GBIT & &
core - > core_unit > 0 )
continue ;
2014-09-05 02:18:48 +04:00
bcma_register_core ( bus , core ) ;
2011-05-09 20:56:46 +04:00
}
2013-01-25 14:37:26 +04:00
# ifdef CONFIG_BCMA_DRIVER_MIPS
if ( bus - > drv_cc . pflash . present ) {
err = platform_device_register ( & bcma_pflash_dev ) ;
if ( err )
bcma_err ( bus , " Error registering parallel flash \n " ) ;
}
# endif
2012-08-10 23:23:53 +04:00
# ifdef CONFIG_BCMA_SFLASH
if ( bus - > drv_cc . sflash . present ) {
err = platform_device_register ( & bcma_sflash_dev ) ;
if ( err )
bcma_err ( bus , " Error registering serial flash \n " ) ;
}
# endif
2012-08-12 15:08:05 +04:00
# ifdef CONFIG_BCMA_NFLASH
if ( bus - > drv_cc . nflash . present ) {
err = platform_device_register ( & bcma_nflash_dev ) ;
if ( err )
bcma_err ( bus , " Error registering NAND flash \n " ) ;
}
# endif
2012-11-21 02:24:30 +04:00
err = bcma_gpio_init ( & bus - > drv_cc ) ;
if ( err = = - ENOTSUPP )
bcma_debug ( bus , " GPIO driver not activated \n " ) ;
else if ( err )
bcma_err ( bus , " Error registering GPIO driver: %i \n " , err ) ;
2012-08-12 15:08:05 +04:00
2012-12-05 21:46:02 +04:00
if ( bus - > hosttype = = BCMA_HOSTTYPE_SOC ) {
err = bcma_chipco_watchdog_register ( & bus - > drv_cc ) ;
if ( err )
bcma_err ( bus , " Error registering watchdog driver \n " ) ;
}
2011-05-09 20:56:46 +04:00
return 0 ;
}
static void bcma_unregister_cores ( struct bcma_bus * bus )
{
2012-10-11 16:05:15 +04:00
struct bcma_device * core , * tmp ;
2011-05-09 20:56:46 +04:00
2012-10-11 16:05:15 +04:00
list_for_each_entry_safe ( core , tmp , & bus - > cores , list ) {
2015-01-24 20:47:19 +03:00
if ( ! core - > dev_registered )
continue ;
2012-10-11 16:05:15 +04:00
list_del ( & core - > list ) ;
2015-01-24 20:47:19 +03:00
device_unregister ( & core - > dev ) ;
2011-05-09 20:56:46 +04:00
}
2012-12-05 21:46:02 +04:00
if ( bus - > hosttype = = BCMA_HOSTTYPE_SOC )
platform_device_unregister ( bus - > drv_cc . watchdog ) ;
2015-01-24 20:47:19 +03:00
/* Now noone uses internally-handled cores, we can free them */
list_for_each_entry_safe ( core , tmp , & bus - > cores , list ) {
list_del ( & core - > list ) ;
kfree ( core ) ;
}
2011-05-09 20:56:46 +04:00
}
2012-12-22 03:12:59 +04:00
int bcma_bus_register ( struct bcma_bus * bus )
2011-05-09 20:56:46 +04:00
{
int err ;
struct bcma_device * core ;
/* Scan for devices (cores) */
err = bcma_bus_scan ( bus ) ;
if ( err ) {
2012-07-06 00:07:32 +04:00
bcma_err ( bus , " Failed to scan: %d \n " , err ) ;
2013-07-15 15:15:07 +04:00
return err ;
2011-05-09 20:56:46 +04:00
}
2012-09-29 22:29:50 +04:00
/* Early init CC core */
core = bcma_find_core ( bus , bcma_cc_core_id ( bus ) ) ;
if ( core ) {
bus - > drv_cc . core = core ;
bcma_core_chipcommon_early_init ( & bus - > drv_cc ) ;
}
2015-01-25 13:11:14 +03:00
/* Early init PCIE core */
core = bcma_find_core ( bus , BCMA_CORE_PCIE ) ;
if ( core ) {
bus - > drv_pci [ 0 ] . core = core ;
bcma_core_pci_early_init ( & bus - > drv_pci [ 0 ] ) ;
}
2012-09-29 22:29:50 +04:00
2014-09-05 02:18:49 +04:00
/* Cores providing flash access go before SPROM init */
list_for_each_entry ( core , & bus - > cores , list ) {
if ( bcma_is_core_needed_early ( core - > id . id ) )
bcma_register_core ( bus , core ) ;
}
2012-09-29 22:29:50 +04:00
/* Try to get SPROM */
err = bcma_sprom_get ( bus ) ;
if ( err = = - ENOENT ) {
bcma_err ( bus , " No SPROM available \n " ) ;
} else if ( err )
bcma_err ( bus , " Failed to get SPROM: %d \n " , err ) ;
2011-05-09 20:56:46 +04:00
/* Init CC core */
2012-07-11 01:45:49 +04:00
core = bcma_find_core ( bus , bcma_cc_core_id ( bus ) ) ;
2011-05-09 20:56:46 +04:00
if ( core ) {
bus - > drv_cc . core = core ;
bcma_core_chipcommon_init ( & bus - > drv_cc ) ;
}
2014-09-09 00:53:36 +04:00
/* Init CC core */
core = bcma_find_core ( bus , BCMA_CORE_NS_CHIPCOMMON_B ) ;
if ( core ) {
bus - > drv_cc_b . core = core ;
bcma_core_chipcommon_b_init ( & bus - > drv_cc_b ) ;
}
2011-07-23 03:20:09 +04:00
/* Init MIPS core */
core = bcma_find_core ( bus , BCMA_CORE_MIPS_74K ) ;
if ( core ) {
bus - > drv_mips . core = core ;
bcma_core_mips_init ( & bus - > drv_mips ) ;
}
2011-05-09 20:56:46 +04:00
/* Init PCIE core */
2012-09-29 22:40:18 +04:00
core = bcma_find_core_unit ( bus , BCMA_CORE_PCIE , 0 ) ;
if ( core ) {
bus - > drv_pci [ 0 ] . core = core ;
bcma_core_pci_init ( & bus - > drv_pci [ 0 ] ) ;
}
/* Init PCIE core */
core = bcma_find_core_unit ( bus , BCMA_CORE_PCIE , 1 ) ;
2011-05-09 20:56:46 +04:00
if ( core ) {
2012-09-29 22:40:18 +04:00
bus - > drv_pci [ 1 ] . core = core ;
bcma_core_pci_init ( & bus - > drv_pci [ 1 ] ) ;
2011-05-09 20:56:46 +04:00
}
2014-07-05 03:10:41 +04:00
/* Init PCIe Gen 2 core */
core = bcma_find_core_unit ( bus , BCMA_CORE_PCIE2 , 0 ) ;
if ( core ) {
bus - > drv_pcie2 . core = core ;
bcma_core_pcie2_init ( & bus - > drv_pcie2 ) ;
}
2012-07-11 11:23:43 +04:00
/* Init GBIT MAC COMMON core */
core = bcma_find_core ( bus , BCMA_CORE_4706_MAC_GBIT_COMMON ) ;
if ( core ) {
bus - > drv_gmac_cmn . core = core ;
bcma_core_gmac_cmn_init ( & bus - > drv_gmac_cmn ) ;
}
2011-05-09 20:56:46 +04:00
/* Register found cores */
2014-09-05 02:18:48 +04:00
bcma_register_devices ( bus ) ;
2011-05-09 20:56:46 +04:00
2012-07-06 00:07:32 +04:00
bcma_info ( bus , " Bus registered \n " ) ;
2011-05-09 20:56:46 +04:00
return 0 ;
}
void bcma_bus_unregister ( struct bcma_bus * bus )
{
2013-02-04 02:25:33 +04:00
int err ;
err = bcma_gpio_unregister ( & bus - > drv_cc ) ;
if ( err = = - EBUSY )
bcma_err ( bus , " Some GPIOs are still in use. \n " ) ;
else if ( err )
bcma_err ( bus , " Can not unregister GPIO driver: %i \n " , err ) ;
2012-08-17 00:42:30 +04:00
2014-09-09 00:53:36 +04:00
bcma_core_chipcommon_b_free ( & bus - > drv_cc_b ) ;
2011-05-09 20:56:46 +04:00
bcma_unregister_cores ( bus ) ;
}
2015-01-19 10:30:30 +03:00
/*
* This is a special version of bus registration function designed for SoCs .
* It scans bus and performs basic initialization of main cores only .
* Please note it requires memory allocation , however it won ' t try to sleep .
*/
int __init bcma_bus_early_register ( struct bcma_bus * bus )
2011-07-23 03:20:07 +04:00
{
int err ;
struct bcma_device * core ;
2015-01-19 10:30:30 +03:00
/* Scan for devices (cores) */
err = bcma_bus_scan ( bus ) ;
2011-07-23 03:20:07 +04:00
if ( err ) {
2015-01-19 10:30:30 +03:00
bcma_err ( bus , " Failed to scan bus: %d \n " , err ) ;
2011-07-23 03:20:07 +04:00
return - 1 ;
}
2012-09-29 22:29:49 +04:00
/* Early init CC core */
2012-07-11 01:45:49 +04:00
core = bcma_find_core ( bus , bcma_cc_core_id ( bus ) ) ;
2011-07-23 03:20:07 +04:00
if ( core ) {
bus - > drv_cc . core = core ;
2012-09-29 22:29:49 +04:00
bcma_core_chipcommon_early_init ( & bus - > drv_cc ) ;
2011-07-23 03:20:07 +04:00
}
2012-09-29 22:29:49 +04:00
/* Early init MIPS core */
2011-07-23 03:20:09 +04:00
core = bcma_find_core ( bus , BCMA_CORE_MIPS_74K ) ;
if ( core ) {
bus - > drv_mips . core = core ;
2012-09-29 22:29:49 +04:00
bcma_core_mips_early_init ( & bus - > drv_mips ) ;
2011-07-23 03:20:09 +04:00
}
2012-07-06 00:07:32 +04:00
bcma_info ( bus , " Early bus registered \n " ) ;
2011-07-23 03:20:07 +04:00
return 0 ;
}
2011-12-10 01:16:07 +04:00
# ifdef CONFIG_PM
2012-01-14 02:58:40 +04:00
int bcma_bus_suspend ( struct bcma_bus * bus )
{
2012-01-14 02:58:41 +04:00
struct bcma_device * core ;
list_for_each_entry ( core , & bus - > cores , list ) {
struct device_driver * drv = core - > dev . driver ;
if ( drv ) {
struct bcma_driver * adrv = container_of ( drv , struct bcma_driver , drv ) ;
if ( adrv - > suspend )
adrv - > suspend ( core ) ;
}
}
2012-01-14 02:58:40 +04:00
return 0 ;
}
2011-12-10 01:16:07 +04:00
int bcma_bus_resume ( struct bcma_bus * bus )
{
struct bcma_device * core ;
/* Init CC core */
2012-07-11 01:45:49 +04:00
if ( bus - > drv_cc . core ) {
2011-12-10 01:16:07 +04:00
bus - > drv_cc . setup_done = false ;
bcma_core_chipcommon_init ( & bus - > drv_cc ) ;
}
2012-01-14 02:58:41 +04:00
list_for_each_entry ( core , & bus - > cores , list ) {
struct device_driver * drv = core - > dev . driver ;
if ( drv ) {
struct bcma_driver * adrv = container_of ( drv , struct bcma_driver , drv ) ;
if ( adrv - > resume )
adrv - > resume ( core ) ;
}
}
2011-12-10 01:16:07 +04:00
return 0 ;
}
# endif
2011-05-09 20:56:46 +04:00
int __bcma_driver_register ( struct bcma_driver * drv , struct module * owner )
{
drv - > drv . name = drv - > name ;
drv - > drv . bus = & bcma_bus_type ;
drv - > drv . owner = owner ;
return driver_register ( & drv - > drv ) ;
}
EXPORT_SYMBOL_GPL ( __bcma_driver_register ) ;
void bcma_driver_unregister ( struct bcma_driver * drv )
{
driver_unregister ( & drv - > drv ) ;
}
EXPORT_SYMBOL_GPL ( bcma_driver_unregister ) ;
static int bcma_bus_match ( struct device * dev , struct device_driver * drv )
{
struct bcma_device * core = container_of ( dev , struct bcma_device , dev ) ;
struct bcma_driver * adrv = container_of ( drv , struct bcma_driver , drv ) ;
const struct bcma_device_id * cid = & core - > id ;
const struct bcma_device_id * did ;
for ( did = adrv - > id_table ; did - > manuf | | did - > id | | did - > rev ; did + + ) {
if ( ( did - > manuf = = cid - > manuf | | did - > manuf = = BCMA_ANY_MANUF ) & &
( did - > id = = cid - > id | | did - > id = = BCMA_ANY_ID ) & &
( did - > rev = = cid - > rev | | did - > rev = = BCMA_ANY_REV ) & &
( did - > class = = cid - > class | | did - > class = = BCMA_ANY_CLASS ) )
return 1 ;
}
return 0 ;
}
static int bcma_device_probe ( struct device * dev )
{
struct bcma_device * core = container_of ( dev , struct bcma_device , dev ) ;
struct bcma_driver * adrv = container_of ( dev - > driver , struct bcma_driver ,
drv ) ;
int err = 0 ;
if ( adrv - > probe )
err = adrv - > probe ( core ) ;
return err ;
}
static int bcma_device_remove ( struct device * dev )
{
struct bcma_device * core = container_of ( dev , struct bcma_device , dev ) ;
struct bcma_driver * adrv = container_of ( dev - > driver , struct bcma_driver ,
drv ) ;
if ( adrv - > remove )
adrv - > remove ( core ) ;
return 0 ;
}
2011-08-20 00:14:47 +04:00
static int bcma_device_uevent ( struct device * dev , struct kobj_uevent_env * env )
{
struct bcma_device * core = container_of ( dev , struct bcma_device , dev ) ;
return add_uevent_var ( env ,
" MODALIAS=bcma:m%04Xid%04Xrev%02Xcl%02X " ,
core - > id . manuf , core - > id . id ,
core - > id . rev , core - > id . class ) ;
}
2011-05-09 20:56:46 +04:00
static int __init bcma_modinit ( void )
{
int err ;
err = bus_register ( & bcma_bus_type ) ;
if ( err )
return err ;
2014-09-26 02:09:19 +04:00
err = bcma_host_soc_register_driver ( ) ;
if ( err ) {
pr_err ( " SoC host initialization failed \n " ) ;
err = 0 ;
}
2011-05-09 20:56:46 +04:00
# ifdef CONFIG_BCMA_HOST_PCI
err = bcma_host_pci_init ( ) ;
if ( err ) {
pr_err ( " PCI host initialization failed \n " ) ;
err = 0 ;
}
# endif
return err ;
}
fs_initcall ( bcma_modinit ) ;
static void __exit bcma_modexit ( void )
{
# ifdef CONFIG_BCMA_HOST_PCI
bcma_host_pci_exit ( ) ;
# endif
2014-09-26 02:09:19 +04:00
bcma_host_soc_unregister_driver ( ) ;
2011-05-09 20:56:46 +04:00
bus_unregister ( & bcma_bus_type ) ;
}
module_exit ( bcma_modexit )