2009-09-19 09:46:06 +09:00
/*
2010-11-22 15:37:16 +09:00
* smdk_wm8580 . c
2009-09-19 09:46:06 +09:00
*
* Copyright ( c ) 2009 Samsung Electronics Co . Ltd
* Author : Jaswinder Singh < jassi . brar @ samsung . com >
*
* 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 .
*/
# include <sound/soc.h>
2011-01-11 07:26:06 +09:00
# include <sound/pcm_params.h>
2009-09-19 09:46:06 +09:00
2010-11-22 15:37:19 +09:00
# include <asm/mach-types.h>
2009-09-19 09:46:06 +09:00
# include "../codecs/wm8580.h"
2010-11-22 15:37:07 +09:00
# include "i2s.h"
2009-09-19 09:46:06 +09:00
2010-08-06 17:57:45 +01:00
/*
* Default CFG switch settings to use this driver :
*
* SMDK6410 : Set CFG1 1 - 3 Off , CFG2 1 - 4 On
*/
2010-11-22 15:37:16 +09:00
/* SMDK has a 12MHZ crystal attached to WM8580 */
# define SMDK_WM8580_FREQ 12000000
2009-09-19 09:46:06 +09:00
2010-11-22 15:37:16 +09:00
static int smdk_hw_params ( struct snd_pcm_substream * substream ,
2009-09-19 09:46:06 +09:00
struct snd_pcm_hw_params * params )
{
struct snd_soc_pcm_runtime * rtd = substream - > private_data ;
2010-03-17 20:15:21 +00:00
struct snd_soc_dai * cpu_dai = rtd - > cpu_dai ;
struct snd_soc_dai * codec_dai = rtd - > codec_dai ;
2009-09-19 09:46:06 +09:00
unsigned int pll_out ;
int bfs , rfs , ret ;
switch ( params_format ( params ) ) {
case SNDRV_PCM_FORMAT_U8 :
case SNDRV_PCM_FORMAT_S8 :
bfs = 16 ;
break ;
case SNDRV_PCM_FORMAT_U16_LE :
case SNDRV_PCM_FORMAT_S16_LE :
bfs = 32 ;
break ;
default :
return - EINVAL ;
}
/* The Fvco for WM8580 PLLs must fall within [90,100]MHz.
* This criterion can ' t be met if we request PLL output
* as { 8000 x256 , 64000 x256 , 11025 x256 } Hz .
* As a wayout , we rather change rfs to a minimum value that
* results in ( params_rate ( params ) * rfs ) , and itself , acceptable
* to both - the CODEC and the CPU .
*/
switch ( params_rate ( params ) ) {
case 16000 :
case 22050 :
case 32000 :
case 44100 :
case 48000 :
case 88200 :
case 96000 :
rfs = 256 ;
break ;
case 64000 :
rfs = 384 ;
break ;
case 8000 :
case 11025 :
rfs = 512 ;
break ;
default :
return - EINVAL ;
}
pll_out = params_rate ( params ) * rfs ;
/* Set the Codec DAI configuration */
ret = snd_soc_dai_set_fmt ( codec_dai , SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBM_CFM ) ;
if ( ret < 0 )
return ret ;
/* Set the AP DAI configuration */
ret = snd_soc_dai_set_fmt ( cpu_dai , SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBM_CFM ) ;
if ( ret < 0 )
return ret ;
2009-10-28 15:47:48 +00:00
/* Set WM8580 to drive MCLK from its PLLA */
2009-09-19 09:46:06 +09:00
ret = snd_soc_dai_set_clkdiv ( codec_dai , WM8580_MCLK ,
WM8580_CLKSRC_PLLA ) ;
if ( ret < 0 )
return ret ;
2010-08-13 19:05:04 +01:00
ret = snd_soc_dai_set_pll ( codec_dai , WM8580_PLLA , 0 ,
2010-11-22 15:37:16 +09:00
SMDK_WM8580_FREQ , pll_out ) ;
2009-09-19 09:46:06 +09:00
if ( ret < 0 )
return ret ;
2010-08-13 19:05:04 +01:00
ret = snd_soc_dai_set_sysclk ( codec_dai , WM8580_CLKSRC_PLLA ,
pll_out , SND_SOC_CLOCK_IN ) ;
2009-09-19 09:46:06 +09:00
if ( ret < 0 )
return ret ;
return 0 ;
}
/*
2010-11-22 15:37:16 +09:00
* SMDK WM8580 DAI operations .
2009-09-19 09:46:06 +09:00
*/
2010-11-22 15:37:16 +09:00
static struct snd_soc_ops smdk_ops = {
. hw_params = smdk_hw_params ,
2009-09-19 09:46:06 +09:00
} ;
2010-11-22 15:37:16 +09:00
/* SMDK Playback widgets */
2011-10-08 13:31:18 +01:00
static const struct snd_soc_dapm_widget smdk_wm8580_dapm_widgets [ ] = {
2010-08-06 17:23:02 +01:00
SND_SOC_DAPM_HP ( " Front " , NULL ) ,
SND_SOC_DAPM_HP ( " Center+Sub " , NULL ) ,
SND_SOC_DAPM_HP ( " Rear " , NULL ) ,
2009-09-19 09:46:06 +09:00
SND_SOC_DAPM_MIC ( " MicIn " , NULL ) ,
SND_SOC_DAPM_LINE ( " LineIn " , NULL ) ,
} ;
/* SMDK-PAIFTX connections */
2011-10-08 13:31:18 +01:00
static const struct snd_soc_dapm_route smdk_wm8580_audio_map [ ] = {
2009-09-19 09:46:06 +09:00
/* MicIn feeds AINL */
{ " AINL " , NULL , " MicIn " } ,
/* LineIn feeds AINL/R */
{ " AINL " , NULL , " LineIn " } ,
{ " AINR " , NULL , " LineIn " } ,
/* Front Left/Right are fed VOUT1L/R */
2010-08-06 17:23:02 +01:00
{ " Front " , NULL , " VOUT1L " } ,
{ " Front " , NULL , " VOUT1R " } ,
2009-09-19 09:46:06 +09:00
/* Center/Sub are fed VOUT2L/R */
2010-08-06 17:23:02 +01:00
{ " Center+Sub " , NULL , " VOUT2L " } ,
{ " Center+Sub " , NULL , " VOUT2R " } ,
2009-09-19 09:46:06 +09:00
/* Rear Left/Right are fed VOUT3L/R */
2010-08-06 17:23:02 +01:00
{ " Rear " , NULL , " VOUT3L " } ,
{ " Rear " , NULL , " VOUT3R " } ,
2009-09-19 09:46:06 +09:00
} ;
2010-11-22 15:37:16 +09:00
static int smdk_wm8580_init_paiftx ( struct snd_soc_pcm_runtime * rtd )
2009-09-19 09:46:06 +09:00
{
2010-03-17 20:15:21 +00:00
struct snd_soc_codec * codec = rtd - > codec ;
2010-11-05 15:53:46 +02:00
struct snd_soc_dapm_context * dapm = & codec - > dapm ;
2010-03-17 20:15:21 +00:00
2009-10-28 15:47:48 +00:00
/* Enabling the microphone requires the fitting of a 0R
* resistor to connect the line from the microphone jack .
*/
2010-11-05 15:53:46 +02:00
snd_soc_dapm_disable_pin ( dapm , " MicIn " ) ;
2009-09-19 09:46:06 +09:00
return 0 ;
}
2010-11-22 15:37:19 +09:00
enum {
PRI_PLAYBACK = 0 ,
PRI_CAPTURE ,
SEC_PLAYBACK ,
} ;
2010-11-22 15:37:16 +09:00
static struct snd_soc_dai_link smdk_dai [ ] = {
2010-11-22 15:37:19 +09:00
[ PRI_PLAYBACK ] = { /* Primary Playback i/f */
. name = " WM8580 PAIF RX " ,
. stream_name = " Playback " ,
2010-12-20 11:05:48 +09:00
. cpu_dai_name = " samsung-i2s.0 " ,
2010-11-22 15:37:19 +09:00
. codec_dai_name = " wm8580-hifi-playback " ,
. platform_name = " samsung-audio " ,
2011-08-03 17:34:41 +09:00
. codec_name = " wm8580.0-001b " ,
2010-11-22 15:37:19 +09:00
. ops = & smdk_ops ,
} ,
[ PRI_CAPTURE ] = { /* Primary Capture i/f */
. name = " WM8580 PAIF TX " ,
. stream_name = " Capture " ,
2010-12-20 11:05:48 +09:00
. cpu_dai_name = " samsung-i2s.0 " ,
2010-11-22 15:37:19 +09:00
. codec_dai_name = " wm8580-hifi-capture " ,
. platform_name = " samsung-audio " ,
2011-08-03 17:34:41 +09:00
. codec_name = " wm8580.0-001b " ,
2010-11-22 15:37:19 +09:00
. init = smdk_wm8580_init_paiftx ,
. ops = & smdk_ops ,
} ,
[ SEC_PLAYBACK ] = { /* Sec_Fifo Playback i/f */
. name = " Sec_FIFO TX " ,
. stream_name = " Playback " ,
. cpu_dai_name = " samsung-i2s.x " ,
. codec_dai_name = " wm8580-hifi-playback " ,
. platform_name = " samsung-audio " ,
2011-08-03 17:34:41 +09:00
. codec_name = " wm8580.0-001b " ,
2010-11-22 15:37:19 +09:00
. ops = & smdk_ops ,
} ,
2009-09-19 09:46:06 +09:00
} ;
2010-11-22 15:37:16 +09:00
static struct snd_soc_card smdk = {
. name = " SMDK-I2S " ,
. dai_link = smdk_dai ,
2010-11-22 15:37:19 +09:00
. num_links = 2 ,
2011-10-08 13:31:18 +01:00
. dapm_widgets = smdk_wm8580_dapm_widgets ,
. num_dapm_widgets = ARRAY_SIZE ( smdk_wm8580_dapm_widgets ) ,
. dapm_routes = smdk_wm8580_audio_map ,
. num_dapm_routes = ARRAY_SIZE ( smdk_wm8580_audio_map ) ,
2009-09-19 09:46:06 +09:00
} ;
2010-11-22 15:37:16 +09:00
static struct platform_device * smdk_snd_device ;
2009-09-19 09:46:06 +09:00
2010-11-22 15:37:16 +09:00
static int __init smdk_audio_init ( void )
2009-09-19 09:46:06 +09:00
{
int ret ;
2010-11-22 15:37:19 +09:00
char * str ;
2011-05-11 16:28:45 +09:00
if ( machine_is_smdkc100 ( )
2010-12-20 11:05:55 +09:00
| | machine_is_smdkv210 ( ) | | machine_is_smdkc110 ( ) ) {
2010-11-22 15:37:19 +09:00
smdk . num_links = 3 ;
/* Secondary is at offset SAMSUNG_I2S_SECOFF from Primary */
str = ( char * ) smdk_dai [ SEC_PLAYBACK ] . cpu_dai_name ;
str [ strlen ( str ) - 1 ] = ' 0 ' + SAMSUNG_I2S_SECOFF ;
2010-12-20 11:05:48 +09:00
} else if ( machine_is_smdk6410 ( ) ) {
str = ( char * ) smdk_dai [ PRI_PLAYBACK ] . cpu_dai_name ;
str [ strlen ( str ) - 1 ] = ' 2 ' ;
str = ( char * ) smdk_dai [ PRI_CAPTURE ] . cpu_dai_name ;
str [ strlen ( str ) - 1 ] = ' 2 ' ;
2010-11-22 15:37:19 +09:00
}
2009-09-19 09:46:06 +09:00
2010-11-22 15:37:16 +09:00
smdk_snd_device = platform_device_alloc ( " soc-audio " , - 1 ) ;
if ( ! smdk_snd_device )
2009-09-19 09:46:06 +09:00
return - ENOMEM ;
2010-11-22 15:37:16 +09:00
platform_set_drvdata ( smdk_snd_device , & smdk ) ;
ret = platform_device_add ( smdk_snd_device ) ;
2009-09-19 09:46:06 +09:00
if ( ret )
2010-11-22 15:37:16 +09:00
platform_device_put ( smdk_snd_device ) ;
2009-09-19 09:46:06 +09:00
return ret ;
}
2010-11-22 15:37:16 +09:00
module_init ( smdk_audio_init ) ;
2009-09-19 09:46:06 +09:00
2010-11-24 17:18:45 +00:00
static void __exit smdk_audio_exit ( void )
{
platform_device_unregister ( smdk_snd_device ) ;
}
module_exit ( smdk_audio_exit ) ;
2009-09-19 09:46:06 +09:00
MODULE_AUTHOR ( " Jaswinder Singh, jassi.brar@samsung.com " ) ;
2010-11-22 15:37:16 +09:00
MODULE_DESCRIPTION ( " ALSA SoC SMDK WM8580 " ) ;
2009-09-19 09:46:06 +09:00
MODULE_LICENSE ( " GPL " ) ;