2006-10-06 20:38:03 +04:00
/*
* ac97 . c - - ALSA Soc AC97 codec support
*
* Copyright 2005 Wolfson Microelectronics PLC .
2008-10-12 16:17:36 +04:00
* Author : Liam Girdwood < lrg @ slimlogic . co . uk >
2006-10-06 20:38:03 +04:00
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*
* Generic AC97 support .
*/
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/device.h>
# include <sound/core.h>
# include <sound/pcm.h>
# include <sound/ac97_codec.h>
# include <sound/initval.h>
# include <sound/soc.h>
2008-06-11 16:47:09 +04:00
# include "ac97.h"
2006-10-06 20:38:03 +04:00
2007-02-02 19:16:41 +03:00
# define AC97_VERSION "0.6"
2006-10-06 20:38:03 +04:00
2008-11-19 01:11:38 +03:00
static int ac97_prepare ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
2006-10-06 20:38:03 +04:00
{
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct snd_soc_pcm_runtime * rtd = substream - > private_data ;
struct snd_soc_device * socdev = rtd - > socdev ;
struct snd_soc_codec * codec = socdev - > codec ;
int reg = ( substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK ) ?
AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE ;
return snd_ac97_set_rate ( codec - > ac97 , reg , runtime - > rate ) ;
}
2007-02-02 19:16:41 +03:00
# define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
2008-04-23 17:26:45 +04:00
SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000 )
2007-02-02 19:16:41 +03:00
2008-07-07 19:07:52 +04:00
struct snd_soc_dai ac97_dai = {
2006-10-06 20:38:03 +04:00
. name = " AC97 HiFi " ,
2008-11-24 21:01:05 +03:00
. ac97_control = 1 ,
2006-10-06 20:38:03 +04:00
. playback = {
. stream_name = " AC97 Playback " ,
. channels_min = 1 ,
2007-02-02 19:16:41 +03:00
. channels_max = 2 ,
. rates = STD_AC97_RATES ,
. formats = SNDRV_PCM_FMTBIT_S16_LE , } ,
2006-10-06 20:38:03 +04:00
. capture = {
. stream_name = " AC97 Capture " ,
. channels_min = 1 ,
2007-02-02 19:16:41 +03:00
. channels_max = 2 ,
. rates = STD_AC97_RATES ,
. formats = SNDRV_PCM_FMTBIT_S16_LE , } ,
2006-10-06 20:38:03 +04:00
. ops = {
. prepare = ac97_prepare , } ,
} ;
2007-04-16 21:20:17 +04:00
EXPORT_SYMBOL_GPL ( ac97_dai ) ;
2006-10-06 20:38:03 +04:00
static unsigned int ac97_read ( struct snd_soc_codec * codec ,
unsigned int reg )
{
return soc_ac97_ops . read ( codec - > ac97 , reg ) ;
}
static int ac97_write ( struct snd_soc_codec * codec , unsigned int reg ,
unsigned int val )
{
soc_ac97_ops . write ( codec - > ac97 , reg , val ) ;
return 0 ;
}
static int ac97_soc_probe ( struct platform_device * pdev )
{
struct snd_soc_device * socdev = platform_get_drvdata ( pdev ) ;
struct snd_soc_codec * codec ;
struct snd_ac97_bus * ac97_bus ;
struct snd_ac97_template ac97_template ;
int ret = 0 ;
printk ( KERN_INFO " AC97 SoC Audio Codec %s \n " , AC97_VERSION ) ;
socdev - > codec = kzalloc ( sizeof ( struct snd_soc_codec ) , GFP_KERNEL ) ;
2008-04-23 17:26:45 +04:00
if ( ! socdev - > codec )
2006-10-06 20:38:03 +04:00
return - ENOMEM ;
codec = socdev - > codec ;
mutex_init ( & codec - > mutex ) ;
codec - > name = " AC97 " ;
codec - > owner = THIS_MODULE ;
codec - > dai = & ac97_dai ;
codec - > num_dai = 1 ;
codec - > write = ac97_write ;
codec - > read = ac97_read ;
INIT_LIST_HEAD ( & codec - > dapm_widgets ) ;
INIT_LIST_HEAD ( & codec - > dapm_paths ) ;
/* register pcms */
ret = snd_soc_new_pcms ( socdev , SNDRV_DEFAULT_IDX1 , SNDRV_DEFAULT_STR1 ) ;
2008-04-23 17:26:45 +04:00
if ( ret < 0 )
2006-10-06 20:38:03 +04:00
goto err ;
/* add codec as bus device for standard ac97 */
ret = snd_ac97_bus ( codec - > card , 0 , & soc_ac97_ops , NULL , & ac97_bus ) ;
2008-04-23 17:26:45 +04:00
if ( ret < 0 )
2006-10-06 20:38:03 +04:00
goto bus_err ;
memset ( & ac97_template , 0 , sizeof ( struct snd_ac97_template ) ) ;
ret = snd_ac97_mixer ( ac97_bus , & ac97_template , & codec - > ac97 ) ;
2008-04-23 17:26:45 +04:00
if ( ret < 0 )
2006-10-06 20:38:03 +04:00
goto bus_err ;
2008-11-28 14:49:07 +03:00
ret = snd_soc_init_card ( socdev ) ;
2006-10-06 20:38:03 +04:00
if ( ret < 0 )
goto bus_err ;
return 0 ;
bus_err :
snd_soc_free_pcms ( socdev ) ;
err :
kfree ( socdev - > codec - > reg_cache ) ;
kfree ( socdev - > codec ) ;
socdev - > codec = NULL ;
return ret ;
}
static int ac97_soc_remove ( struct platform_device * pdev )
{
struct snd_soc_device * socdev = platform_get_drvdata ( pdev ) ;
struct snd_soc_codec * codec = socdev - > codec ;
2008-04-23 17:26:45 +04:00
if ( ! codec )
2006-10-06 20:38:03 +04:00
return 0 ;
snd_soc_free_pcms ( socdev ) ;
kfree ( socdev - > codec - > reg_cache ) ;
kfree ( socdev - > codec ) ;
return 0 ;
}
2008-07-03 11:33:10 +04:00
# ifdef CONFIG_PM
static int ac97_soc_suspend ( struct platform_device * pdev , pm_message_t msg )
{
struct snd_soc_device * socdev = platform_get_drvdata ( pdev ) ;
snd_ac97_suspend ( socdev - > codec - > ac97 ) ;
return 0 ;
}
static int ac97_soc_resume ( struct platform_device * pdev )
{
struct snd_soc_device * socdev = platform_get_drvdata ( pdev ) ;
snd_ac97_resume ( socdev - > codec - > ac97 ) ;
return 0 ;
}
# else
# define ac97_soc_suspend NULL
# define ac97_soc_resume NULL
# endif
2008-04-23 17:26:45 +04:00
struct snd_soc_codec_device soc_codec_dev_ac97 = {
2006-10-06 20:38:03 +04:00
. probe = ac97_soc_probe ,
. remove = ac97_soc_remove ,
2008-07-03 11:33:10 +04:00
. suspend = ac97_soc_suspend ,
. resume = ac97_soc_resume ,
2006-10-06 20:38:03 +04:00
} ;
EXPORT_SYMBOL_GPL ( soc_codec_dev_ac97 ) ;
MODULE_DESCRIPTION ( " Soc Generic AC97 driver " ) ;
MODULE_AUTHOR ( " Liam Girdwood " ) ;
MODULE_LICENSE ( " GPL " ) ;