2008-07-29 11:42:28 +01:00
/*
* OF helpers for ALSA SoC Layer
*
* Copyright ( C ) 2008 , Secret Lab Technologies Ltd .
*/
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/init.h>
# include <linux/delay.h>
# include <linux/pm.h>
# include <linux/bitops.h>
# include <linux/platform_device.h>
# include <linux/of.h>
# include <sound/core.h>
# include <sound/pcm.h>
# include <sound/pcm_params.h>
# include <sound/soc.h>
# include <sound/soc-of-simple.h>
# include <sound/initval.h>
MODULE_AUTHOR ( " Grant Likely <grant.likely@secretlab.ca> " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " ALSA SoC OpenFirmware bindings " ) ;
static DEFINE_MUTEX ( of_snd_soc_mutex ) ;
static LIST_HEAD ( of_snd_soc_device_list ) ;
static int of_snd_soc_next_index ;
struct of_snd_soc_device {
int id ;
struct list_head list ;
struct snd_soc_device device ;
2008-11-18 20:50:34 +00:00
struct snd_soc_card card ;
2008-07-29 11:42:28 +01:00
struct snd_soc_dai_link dai_link ;
struct platform_device * pdev ;
struct device_node * platform_node ;
struct device_node * codec_node ;
} ;
static struct snd_soc_ops of_snd_soc_ops = {
} ;
static struct of_snd_soc_device *
of_snd_soc_get_device ( struct device_node * codec_node )
{
struct of_snd_soc_device * of_soc ;
list_for_each_entry ( of_soc , & of_snd_soc_device_list , list ) {
if ( of_soc - > codec_node = = codec_node )
return of_soc ;
}
of_soc = kzalloc ( sizeof ( struct of_snd_soc_device ) , GFP_KERNEL ) ;
if ( ! of_soc )
return NULL ;
/* Initialize the structure and add it to the global list */
of_soc - > codec_node = codec_node ;
of_soc - > id = of_snd_soc_next_index + + ;
2008-11-18 20:50:34 +00:00
of_soc - > card . dai_link = & of_soc - > dai_link ;
of_soc - > card . num_links = 1 ;
of_soc - > device . card = & of_soc - > card ;
2008-07-29 11:42:28 +01:00
of_soc - > dai_link . ops = & of_snd_soc_ops ;
list_add ( & of_soc - > list , & of_snd_soc_device_list ) ;
return of_soc ;
}
static void of_snd_soc_register_device ( struct of_snd_soc_device * of_soc )
{
struct platform_device * pdev ;
int rc ;
/* Only register the device if both the codec and platform have
* been registered */
if ( ( ! of_soc - > device . codec_data ) | | ( ! of_soc - > platform_node ) )
return ;
pr_info ( " platform<-->codec match achieved; registering machine \n " ) ;
pdev = platform_device_alloc ( " soc-audio " , of_soc - > id ) ;
if ( ! pdev ) {
pr_err ( " of_soc: platform_device_alloc() failed \n " ) ;
return ;
}
pdev - > dev . platform_data = of_soc ;
platform_set_drvdata ( pdev , & of_soc - > device ) ;
of_soc - > device . dev = & pdev - > dev ;
/* The ASoC device is complete; register it */
rc = platform_device_add ( pdev ) ;
if ( rc ) {
pr_err ( " of_soc: platform_device_add() failed \n " ) ;
return ;
}
}
int of_snd_soc_register_codec ( struct snd_soc_codec_device * codec_dev ,
void * codec_data , struct snd_soc_dai * dai ,
struct device_node * node )
{
struct of_snd_soc_device * of_soc ;
int rc = 0 ;
pr_info ( " registering ASoC codec driver: %s \n " , node - > full_name ) ;
mutex_lock ( & of_snd_soc_mutex ) ;
of_soc = of_snd_soc_get_device ( node ) ;
if ( ! of_soc ) {
rc = - ENOMEM ;
goto out ;
}
/* Store the codec data */
of_soc - > device . codec_data = codec_data ;
of_soc - > device . codec_dev = codec_dev ;
of_soc - > dai_link . name = ( char * ) node - > name ;
of_soc - > dai_link . stream_name = ( char * ) node - > name ;
of_soc - > dai_link . codec_dai = dai ;
/* Now try to register the SoC device */
of_snd_soc_register_device ( of_soc ) ;
out :
mutex_unlock ( & of_snd_soc_mutex ) ;
return rc ;
}
EXPORT_SYMBOL_GPL ( of_snd_soc_register_codec ) ;
int of_snd_soc_register_platform ( struct snd_soc_platform * platform ,
struct device_node * node ,
struct snd_soc_dai * cpu_dai )
{
struct of_snd_soc_device * of_soc ;
struct device_node * codec_node ;
const phandle * handle ;
int len , rc = 0 ;
pr_info ( " registering ASoC platform driver: %s \n " , node - > full_name ) ;
handle = of_get_property ( node , " codec-handle " , & len ) ;
if ( ! handle | | len < sizeof ( handle ) )
return - ENODEV ;
codec_node = of_find_node_by_phandle ( * handle ) ;
if ( ! codec_node )
return - ENODEV ;
pr_info ( " looking for codec: %s \n " , codec_node - > full_name ) ;
mutex_lock ( & of_snd_soc_mutex ) ;
of_soc = of_snd_soc_get_device ( codec_node ) ;
if ( ! of_soc ) {
rc = - ENOMEM ;
goto out ;
}
of_soc - > platform_node = node ;
of_soc - > dai_link . cpu_dai = cpu_dai ;
2008-12-02 16:01:14 +00:00
of_soc - > card . platform = platform ;
2008-11-18 20:50:34 +00:00
of_soc - > card . name = of_soc - > dai_link . cpu_dai - > name ;
2008-07-29 11:42:28 +01:00
/* Now try to register the SoC device */
of_snd_soc_register_device ( of_soc ) ;
out :
mutex_unlock ( & of_snd_soc_mutex ) ;
return rc ;
}
EXPORT_SYMBOL_GPL ( of_snd_soc_register_platform ) ;