2019-04-19 13:21:56 +03:00
// SPDX-License-Identifier: GPL-2.0+
//
// Copyright (c) 2009 Samsung Electronics Co. Ltd
// Author: Jaswinder Singh <jassisinghbrar@gmail.com>
2009-09-19 04:46:06 +04:00
2011-07-15 20:38:28 +04:00
# include <linux/module.h>
2009-09-19 04:46:06 +04:00
# include <sound/soc.h>
2011-01-11 01:26:06 +03:00
# include <sound/pcm_params.h>
2009-09-19 04:46:06 +04:00
# include "../codecs/wm8580.h"
2010-11-22 09:37:07 +03:00
# include "i2s.h"
2009-09-19 04:46:06 +04:00
2010-08-06 20:57:45 +04:00
/*
* Default CFG switch settings to use this driver :
*
* SMDK6410 : Set CFG1 1 - 3 Off , CFG2 1 - 4 On
*/
2010-11-22 09:37:16 +03:00
/* SMDK has a 12MHZ crystal attached to WM8580 */
# define SMDK_WM8580_FREQ 12000000
2009-09-19 04:46:06 +04:00
2010-11-22 09:37:16 +03:00
static int smdk_hw_params ( struct snd_pcm_substream * substream ,
2009-09-19 04:46:06 +04:00
struct snd_pcm_hw_params * params )
{
2020-07-20 04:18:14 +03:00
struct snd_soc_pcm_runtime * rtd = asoc_substream_to_rtd ( substream ) ;
2020-03-23 08:20:20 +03:00
struct snd_soc_dai * codec_dai = asoc_rtd_to_codec ( rtd , 0 ) ;
2009-09-19 04:46:06 +04:00
unsigned int pll_out ;
2016-12-08 20:31:36 +03:00
int rfs , ret ;
2009-09-19 04:46:06 +04:00
2014-05-23 16:05:39 +04:00
switch ( params_width ( params ) ) {
case 8 :
case 16 :
2009-09-19 04:46:06 +04:00
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 ;
2009-10-28 18:47:48 +03:00
/* Set WM8580 to drive MCLK from its PLLA */
2009-09-19 04:46:06 +04:00
ret = snd_soc_dai_set_clkdiv ( codec_dai , WM8580_MCLK ,
WM8580_CLKSRC_PLLA ) ;
if ( ret < 0 )
return ret ;
2010-08-13 22:05:04 +04:00
ret = snd_soc_dai_set_pll ( codec_dai , WM8580_PLLA , 0 ,
2010-11-22 09:37:16 +03:00
SMDK_WM8580_FREQ , pll_out ) ;
2009-09-19 04:46:06 +04:00
if ( ret < 0 )
return ret ;
2010-08-13 22:05:04 +04:00
ret = snd_soc_dai_set_sysclk ( codec_dai , WM8580_CLKSRC_PLLA ,
pll_out , SND_SOC_CLOCK_IN ) ;
2009-09-19 04:46:06 +04:00
if ( ret < 0 )
return ret ;
return 0 ;
}
/*
2010-11-22 09:37:16 +03:00
* SMDK WM8580 DAI operations .
2009-09-19 04:46:06 +04:00
*/
2021-07-28 20:25:48 +03:00
static const struct snd_soc_ops smdk_ops = {
2010-11-22 09:37:16 +03:00
. hw_params = smdk_hw_params ,
2009-09-19 04:46:06 +04:00
} ;
2010-11-22 09:37:16 +03:00
/* SMDK Playback widgets */
2011-10-08 16:31:18 +04:00
static const struct snd_soc_dapm_widget smdk_wm8580_dapm_widgets [ ] = {
2010-08-06 20:23:02 +04:00
SND_SOC_DAPM_HP ( " Front " , NULL ) ,
SND_SOC_DAPM_HP ( " Center+Sub " , NULL ) ,
SND_SOC_DAPM_HP ( " Rear " , NULL ) ,
2009-09-19 04:46:06 +04:00
SND_SOC_DAPM_MIC ( " MicIn " , NULL ) ,
SND_SOC_DAPM_LINE ( " LineIn " , NULL ) ,
} ;
/* SMDK-PAIFTX connections */
2011-10-08 16:31:18 +04:00
static const struct snd_soc_dapm_route smdk_wm8580_audio_map [ ] = {
2009-09-19 04:46:06 +04: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 20:23:02 +04:00
{ " Front " , NULL , " VOUT1L " } ,
{ " Front " , NULL , " VOUT1R " } ,
2009-09-19 04:46:06 +04:00
/* Center/Sub are fed VOUT2L/R */
2010-08-06 20:23:02 +04:00
{ " Center+Sub " , NULL , " VOUT2L " } ,
{ " Center+Sub " , NULL , " VOUT2R " } ,
2009-09-19 04:46:06 +04:00
/* Rear Left/Right are fed VOUT3L/R */
2010-08-06 20:23:02 +04:00
{ " Rear " , NULL , " VOUT3L " } ,
{ " Rear " , NULL , " VOUT3R " } ,
2009-09-19 04:46:06 +04:00
} ;
2010-11-22 09:37:16 +03:00
static int smdk_wm8580_init_paiftx ( struct snd_soc_pcm_runtime * rtd )
2009-09-19 04:46:06 +04:00
{
2009-10-28 18:47:48 +03:00
/* Enabling the microphone requires the fitting of a 0R
* resistor to connect the line from the microphone jack .
*/
2015-01-16 16:34:53 +03:00
snd_soc_dapm_disable_pin ( & rtd - > card - > dapm , " MicIn " ) ;
2009-09-19 04:46:06 +04:00
return 0 ;
}
2010-11-22 09:37:19 +03:00
enum {
PRI_PLAYBACK = 0 ,
PRI_CAPTURE ,
} ;
2015-01-01 19:16:27 +03:00
# define SMDK_DAI_FMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \
SND_SOC_DAIFMT_CBM_CFM )
2019-06-06 07:09:01 +03:00
SND_SOC_DAILINK_DEFS ( paif_rx ,
DAILINK_COMP_ARRAY ( COMP_CPU ( " samsung-i2s.2 " ) ) ,
DAILINK_COMP_ARRAY ( COMP_CODEC ( " wm8580.0-001b " , " wm8580-hifi-playback " ) ) ,
DAILINK_COMP_ARRAY ( COMP_PLATFORM ( " samsung-i2s.0 " ) ) ) ;
SND_SOC_DAILINK_DEFS ( paif_tx ,
DAILINK_COMP_ARRAY ( COMP_CPU ( " samsung-i2s.2 " ) ) ,
DAILINK_COMP_ARRAY ( COMP_CODEC ( " wm8580.0-001b " , " wm8580-hifi-capture " ) ) ,
DAILINK_COMP_ARRAY ( COMP_PLATFORM ( " samsung-i2s.0 " ) ) ) ;
2010-11-22 09:37:16 +03:00
static struct snd_soc_dai_link smdk_dai [ ] = {
2010-11-22 09:37:19 +03:00
[ PRI_PLAYBACK ] = { /* Primary Playback i/f */
. name = " WM8580 PAIF RX " ,
. stream_name = " Playback " ,
2015-01-01 19:16:27 +03:00
. dai_fmt = SMDK_DAI_FMT ,
2010-11-22 09:37:19 +03:00
. ops = & smdk_ops ,
2019-06-06 07:09:01 +03:00
SND_SOC_DAILINK_REG ( paif_rx ) ,
2010-11-22 09:37:19 +03:00
} ,
[ PRI_CAPTURE ] = { /* Primary Capture i/f */
. name = " WM8580 PAIF TX " ,
. stream_name = " Capture " ,
2015-01-01 19:16:27 +03:00
. dai_fmt = SMDK_DAI_FMT ,
2010-11-22 09:37:19 +03:00
. init = smdk_wm8580_init_paiftx ,
. ops = & smdk_ops ,
2019-06-06 07:09:01 +03:00
SND_SOC_DAILINK_REG ( paif_tx ) ,
2010-11-22 09:37:19 +03:00
} ,
2009-09-19 04:46:06 +04:00
} ;
2010-11-22 09:37:16 +03:00
static struct snd_soc_card smdk = {
. name = " SMDK-I2S " ,
2011-12-22 06:53:15 +04:00
. owner = THIS_MODULE ,
2010-11-22 09:37:16 +03:00
. dai_link = smdk_dai ,
2016-11-20 22:24:52 +03:00
. num_links = ARRAY_SIZE ( smdk_dai ) ,
2011-10-08 16:31:18 +04: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 04:46:06 +04:00
} ;
2010-11-22 09:37:16 +03:00
static struct platform_device * smdk_snd_device ;
2009-09-19 04:46:06 +04:00
2010-11-22 09:37:16 +03:00
static int __init smdk_audio_init ( void )
2009-09-19 04:46:06 +04:00
{
int ret ;
2010-11-22 09:37:16 +03:00
smdk_snd_device = platform_device_alloc ( " soc-audio " , - 1 ) ;
if ( ! smdk_snd_device )
2009-09-19 04:46:06 +04:00
return - ENOMEM ;
2010-11-22 09:37:16 +03:00
platform_set_drvdata ( smdk_snd_device , & smdk ) ;
ret = platform_device_add ( smdk_snd_device ) ;
2009-09-19 04:46:06 +04:00
if ( ret )
2010-11-22 09:37:16 +03:00
platform_device_put ( smdk_snd_device ) ;
2009-09-19 04:46:06 +04:00
return ret ;
}
2010-11-22 09:37:16 +03:00
module_init ( smdk_audio_init ) ;
2009-09-19 04:46:06 +04:00
2010-11-24 20:18:45 +03:00
static void __exit smdk_audio_exit ( void )
{
platform_device_unregister ( smdk_snd_device ) ;
}
module_exit ( smdk_audio_exit ) ;
2012-02-25 14:54:36 +04:00
MODULE_AUTHOR ( " Jaswinder Singh, jassisinghbrar@gmail.com " ) ;
2010-11-22 09:37:16 +03:00
MODULE_DESCRIPTION ( " ALSA SoC SMDK WM8580 " ) ;
2009-09-19 04:46:06 +04:00
MODULE_LICENSE ( " GPL " ) ;