2019-05-27 08:55:21 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2016-05-31 23:33:15 -07:00
/*
* Intel Broxton - P I2S Machine Driver
*
* Copyright ( C ) 2016 , Intel Corporation . All rights reserved .
*
* Modified from :
* Intel Skylake I2S Machine driver
*/
2019-02-13 17:08:51 -06:00
# include <linux/input.h>
2016-05-31 23:33:15 -07:00
# include <linux/module.h>
# include <linux/platform_device.h>
# include <sound/core.h>
# include <sound/jack.h>
# include <sound/pcm.h>
# include <sound/pcm_params.h>
# include <sound/soc.h>
2019-01-25 14:35:07 -06:00
# include <sound/soc-acpi.h>
2016-05-31 23:33:15 -07:00
# include "../../codecs/hdac_hdmi.h"
# include "../../codecs/da7219.h"
# include "../../codecs/da7219-aad.h"
2019-05-30 06:50:11 -05:00
# include "../common/soc-intel-quirks.h"
2019-10-29 15:40:14 +02:00
# include "hda_dsp_common.h"
2016-05-31 23:33:15 -07:00
# define BXT_DIALOG_CODEC_DAI "da7219-hifi"
# define BXT_MAXIM_CODEC_DAI "HiFi"
2020-07-01 17:36:51 +08:00
# define MAX98390_DEV0_NAME "i2c-MX98390:00"
# define MAX98390_DEV1_NAME "i2c-MX98390:01"
2016-05-31 23:33:15 -07:00
# define DUAL_CHANNEL 2
2016-12-06 07:08:36 -08:00
# define QUAD_CHANNEL 4
2016-05-31 23:33:15 -07:00
2020-07-01 17:36:51 +08:00
# define SPKAMP_MAX98357A 1
# define SPKAMP_MAX98390 2
2016-05-31 23:33:15 -07:00
static struct snd_soc_jack broxton_headset ;
2017-02-07 19:09:54 +05:30
static struct snd_soc_jack broxton_hdmi [ 3 ] ;
2016-05-31 23:33:15 -07:00
2017-01-24 21:49:07 +05:30
struct bxt_hdmi_pcm {
struct list_head head ;
struct snd_soc_dai * codec_dai ;
int device ;
} ;
struct bxt_card_private {
struct list_head hdmi_pcm_list ;
2019-10-29 15:40:14 +02:00
bool common_hdmi_codec_drv ;
2020-07-01 17:36:51 +08:00
int spkamp ;
2017-01-24 21:49:07 +05:30
} ;
2016-05-31 23:33:15 -07:00
enum {
BXT_DPCM_AUDIO_PB = 0 ,
BXT_DPCM_AUDIO_CP ,
2019-02-13 17:08:53 -06:00
BXT_DPCM_AUDIO_HS_PB ,
2016-05-31 23:33:15 -07:00
BXT_DPCM_AUDIO_REF_CP ,
2016-09-26 13:02:29 -07:00
BXT_DPCM_AUDIO_DMIC_CP ,
2016-05-31 23:33:15 -07:00
BXT_DPCM_AUDIO_HDMI1_PB ,
BXT_DPCM_AUDIO_HDMI2_PB ,
BXT_DPCM_AUDIO_HDMI3_PB ,
} ;
2017-03-15 16:28:25 -07:00
static int platform_clock_control ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * k , int event )
{
int ret = 0 ;
struct snd_soc_dapm_context * dapm = w - > dapm ;
struct snd_soc_card * card = dapm - > card ;
struct snd_soc_dai * codec_dai ;
2017-10-12 18:38:03 -05:00
codec_dai = snd_soc_card_get_codec_dai ( card , BXT_DIALOG_CODEC_DAI ) ;
2017-03-15 16:28:25 -07:00
if ( ! codec_dai ) {
dev_err ( card - > dev , " Codec dai not found; Unable to set/unset codec pll \n " ) ;
return - EIO ;
}
if ( SND_SOC_DAPM_EVENT_OFF ( event ) ) {
ret = snd_soc_dai_set_pll ( codec_dai , 0 ,
DA7219_SYSCLK_MCLK , 0 , 0 ) ;
if ( ret )
dev_err ( card - > dev , " failed to stop PLL: %d \n " , ret ) ;
} else if ( SND_SOC_DAPM_EVENT_ON ( event ) ) {
ret = snd_soc_dai_set_pll ( codec_dai , 0 ,
DA7219_SYSCLK_PLL_SRM , 0 , DA7219_PLL_FREQ_OUT_98304 ) ;
if ( ret )
dev_err ( card - > dev , " failed to start PLL: %d \n " , ret ) ;
}
return ret ;
}
2016-05-31 23:33:15 -07:00
static const struct snd_kcontrol_new broxton_controls [ ] = {
SOC_DAPM_PIN_SWITCH ( " Headphone Jack " ) ,
SOC_DAPM_PIN_SWITCH ( " Headset Mic " ) ,
2020-07-01 17:36:51 +08:00
} ;
static const struct snd_kcontrol_new max98357a_controls [ ] = {
2016-05-31 23:33:15 -07:00
SOC_DAPM_PIN_SWITCH ( " Spk " ) ,
} ;
2020-07-01 17:36:51 +08:00
static const struct snd_kcontrol_new max98390_controls [ ] = {
SOC_DAPM_PIN_SWITCH ( " Left Spk " ) ,
SOC_DAPM_PIN_SWITCH ( " Right Spk " ) ,
} ;
2016-05-31 23:33:15 -07:00
static const struct snd_soc_dapm_widget broxton_widgets [ ] = {
SND_SOC_DAPM_HP ( " Headphone Jack " , NULL ) ,
SND_SOC_DAPM_MIC ( " Headset Mic " , NULL ) ,
SND_SOC_DAPM_MIC ( " SoC DMIC " , NULL ) ,
SND_SOC_DAPM_SPK ( " HDMI1 " , NULL ) ,
SND_SOC_DAPM_SPK ( " HDMI2 " , NULL ) ,
SND_SOC_DAPM_SPK ( " HDMI3 " , NULL ) ,
2017-03-15 16:28:25 -07:00
SND_SOC_DAPM_SUPPLY ( " Platform Clock " , SND_SOC_NOPM , 0 , 0 ,
platform_clock_control , SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU ) ,
2016-05-31 23:33:15 -07:00
} ;
2020-07-01 17:36:51 +08:00
static const struct snd_soc_dapm_widget max98357a_widgets [ ] = {
SND_SOC_DAPM_SPK ( " Spk " , NULL ) ,
} ;
static const struct snd_soc_dapm_widget max98390_widgets [ ] = {
SND_SOC_DAPM_SPK ( " Left Spk " , NULL ) ,
SND_SOC_DAPM_SPK ( " Right Spk " , NULL ) ,
} ;
2019-02-13 17:08:52 -06:00
static const struct snd_soc_dapm_route audio_map [ ] = {
2016-05-31 23:33:15 -07:00
/* HP jack connectors - unknown if we have jack detection */
{ " Headphone Jack " , NULL , " HPL " } ,
{ " Headphone Jack " , NULL , " HPR " } ,
/* other jacks */
{ " MIC " , NULL , " Headset Mic " } ,
/* digital mics */
{ " DMic " , NULL , " SoC DMIC " } ,
/* CODEC BE connections */
2017-01-24 21:49:13 +05:30
{ " HDMI1 " , NULL , " hif5-0 Output " } ,
{ " HDMI2 " , NULL , " hif6-0 Output " } ,
{ " HDMI2 " , NULL , " hif7-0 Output " } ,
2016-05-31 23:33:15 -07:00
{ " hifi3 " , NULL , " iDisp3 Tx " } ,
{ " iDisp3 Tx " , NULL , " iDisp3_out " } ,
{ " hifi2 " , NULL , " iDisp2 Tx " } ,
{ " iDisp2 Tx " , NULL , " iDisp2_out " } ,
{ " hifi1 " , NULL , " iDisp1 Tx " } ,
{ " iDisp1 Tx " , NULL , " iDisp1_out " } ,
/* DMIC */
{ " dmic01_hifi " , NULL , " DMIC01 Rx " } ,
{ " DMIC01 Rx " , NULL , " DMIC AIF " } ,
2017-03-15 16:28:25 -07:00
{ " Headphone Jack " , NULL , " Platform Clock " } ,
{ " Headset Mic " , NULL , " Platform Clock " } ,
2016-05-31 23:33:15 -07:00
} ;
2020-07-01 17:36:51 +08:00
static const struct snd_soc_dapm_route max98357a_routes [ ] = {
/* speaker */
{ " Spk " , NULL , " Speaker " } ,
} ;
static const struct snd_soc_dapm_route max98390_routes [ ] = {
/* Speaker */
{ " Left Spk " , NULL , " Left BE_OUT " } ,
{ " Right Spk " , NULL , " Right BE_OUT " } ,
} ;
2019-02-13 17:08:52 -06:00
static const struct snd_soc_dapm_route broxton_map [ ] = {
{ " HiFi Playback " , NULL , " ssp5 Tx " } ,
{ " ssp5 Tx " , NULL , " codec0_out " } ,
{ " Playback " , NULL , " ssp1 Tx " } ,
{ " ssp1 Tx " , NULL , " codec1_out " } ,
{ " codec0_in " , NULL , " ssp1 Rx " } ,
{ " ssp1 Rx " , NULL , " Capture " } ,
} ;
static const struct snd_soc_dapm_route gemini_map [ ] = {
{ " HiFi Playback " , NULL , " ssp1 Tx " } ,
{ " ssp1 Tx " , NULL , " codec0_out " } ,
{ " Playback " , NULL , " ssp2 Tx " } ,
{ " ssp2 Tx " , NULL , " codec1_out " } ,
{ " codec0_in " , NULL , " ssp2 Rx " } ,
{ " ssp2 Rx " , NULL , " Capture " } ,
} ;
2016-05-31 23:33:15 -07:00
static int broxton_ssp_fixup ( struct snd_soc_pcm_runtime * rtd ,
struct snd_pcm_hw_params * params )
{
struct snd_interval * rate = hw_param_interval ( params ,
SNDRV_PCM_HW_PARAM_RATE ) ;
2020-01-13 15:04:11 -06:00
struct snd_interval * chan = hw_param_interval ( params ,
2016-05-31 23:33:15 -07:00
SNDRV_PCM_HW_PARAM_CHANNELS ) ;
struct snd_mask * fmt = hw_param_mask ( params , SNDRV_PCM_HW_PARAM_FORMAT ) ;
/* The ADSP will convert the FE rate to 48k, stereo */
rate - > min = rate - > max = 48000 ;
2020-01-13 15:04:11 -06:00
chan - > min = chan - > max = DUAL_CHANNEL ;
2016-05-31 23:33:15 -07:00
/* set SSP to 24 bit */
snd_mask_none ( fmt ) ;
2018-07-25 23:17:19 +02:00
snd_mask_set_format ( fmt , SNDRV_PCM_FORMAT_S24_LE ) ;
2016-05-31 23:33:15 -07:00
return 0 ;
}
static int broxton_da7219_codec_init ( struct snd_soc_pcm_runtime * rtd )
{
int ret ;
2020-03-23 14:19:05 +09:00
struct snd_soc_dai * codec_dai = asoc_rtd_to_codec ( rtd , 0 ) ;
struct snd_soc_component * component = asoc_rtd_to_codec ( rtd , 0 ) - > component ;
2019-08-15 14:51:49 +08:00
int clk_freq ;
2016-05-31 23:33:15 -07:00
2017-06-19 10:56:34 +01:00
/* Configure sysclk for codec */
2019-08-15 14:51:49 +08:00
if ( soc_intel_is_cml ( ) )
clk_freq = 24000000 ;
else
clk_freq = 19200000 ;
ret = snd_soc_dai_set_sysclk ( codec_dai , DA7219_CLKSRC_MCLK , clk_freq ,
2017-06-19 10:56:34 +01:00
SND_SOC_CLOCK_IN ) ;
2019-08-15 14:51:49 +08:00
2017-06-19 10:56:34 +01:00
if ( ret ) {
dev_err ( rtd - > dev , " can't set codec sysclk configuration \n " ) ;
return ret ;
}
2016-05-31 23:33:15 -07:00
/*
* Headset buttons map to the google Reference headset .
* These can be configured by userspace .
*/
ret = snd_soc_card_jack_new ( rtd - > card , " Headset Jack " ,
SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
2016-10-04 10:33:20 -07:00
SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT ,
& broxton_headset , NULL , 0 ) ;
2016-05-31 23:33:15 -07:00
if ( ret ) {
dev_err ( rtd - > dev , " Headset Jack creation failed: %d \n " , ret ) ;
return ret ;
}
2019-02-13 17:08:51 -06:00
snd_jack_set_key ( broxton_headset . jack , SND_JACK_BTN_0 , KEY_PLAYPAUSE ) ;
snd_jack_set_key ( broxton_headset . jack , SND_JACK_BTN_1 , KEY_VOLUMEUP ) ;
snd_jack_set_key ( broxton_headset . jack , SND_JACK_BTN_2 , KEY_VOLUMEDOWN ) ;
snd_jack_set_key ( broxton_headset . jack , SND_JACK_BTN_3 ,
KEY_VOICECOMMAND ) ;
2018-01-29 04:36:54 +00:00
da7219_aad_jack_det ( component , & broxton_headset ) ;
2016-05-31 23:33:15 -07:00
snd_soc_dapm_ignore_suspend ( & rtd - > card - > dapm , " SoC DMIC " ) ;
return ret ;
}
static int broxton_hdmi_init ( struct snd_soc_pcm_runtime * rtd )
{
2017-01-24 21:49:07 +05:30
struct bxt_card_private * ctx = snd_soc_card_get_drvdata ( rtd - > card ) ;
2020-03-23 14:19:05 +09:00
struct snd_soc_dai * dai = asoc_rtd_to_codec ( rtd , 0 ) ;
2017-01-24 21:49:07 +05:30
struct bxt_hdmi_pcm * pcm ;
pcm = devm_kzalloc ( rtd - > card - > dev , sizeof ( * pcm ) , GFP_KERNEL ) ;
if ( ! pcm )
return - ENOMEM ;
2016-05-31 23:33:15 -07:00
2017-01-24 21:49:07 +05:30
pcm - > device = BXT_DPCM_AUDIO_HDMI1_PB + dai - > id ;
pcm - > codec_dai = dai ;
list_add_tail ( & pcm - > head , & ctx - > hdmi_pcm_list ) ;
return 0 ;
2016-05-31 23:33:15 -07:00
}
static int broxton_da7219_fe_init ( struct snd_soc_pcm_runtime * rtd )
{
struct snd_soc_dapm_context * dapm ;
2020-03-23 14:19:05 +09:00
struct snd_soc_component * component = asoc_rtd_to_cpu ( rtd , 0 ) - > component ;
2016-05-31 23:33:15 -07:00
dapm = snd_soc_component_get_dapm ( component ) ;
snd_soc_dapm_ignore_suspend ( dapm , " Reference Capture " ) ;
return 0 ;
}
2017-06-14 09:33:06 +02:00
static const unsigned int rates [ ] = {
2016-05-31 23:33:15 -07:00
48000 ,
} ;
2017-06-14 09:33:06 +02:00
static const struct snd_pcm_hw_constraint_list constraints_rates = {
2016-05-31 23:33:15 -07:00
. count = ARRAY_SIZE ( rates ) ,
. list = rates ,
. mask = 0 ,
} ;
2017-06-14 09:33:06 +02:00
static const unsigned int channels [ ] = {
2016-05-31 23:33:15 -07:00
DUAL_CHANNEL ,
} ;
2017-06-14 09:33:06 +02:00
static const struct snd_pcm_hw_constraint_list constraints_channels = {
2016-05-31 23:33:15 -07:00
. count = ARRAY_SIZE ( channels ) ,
. list = channels ,
. mask = 0 ,
} ;
2017-06-14 09:33:06 +02:00
static const unsigned int channels_quad [ ] = {
2016-12-06 07:08:36 -08:00
QUAD_CHANNEL ,
} ;
2017-06-14 09:33:06 +02:00
static const struct snd_pcm_hw_constraint_list constraints_channels_quad = {
2016-12-06 07:08:36 -08:00
. count = ARRAY_SIZE ( channels_quad ) ,
. list = channels_quad ,
. mask = 0 ,
} ;
2016-05-31 23:33:15 -07:00
static int bxt_fe_startup ( struct snd_pcm_substream * substream )
{
struct snd_pcm_runtime * runtime = substream - > runtime ;
/*
* On this platform for PCM device we support ,
* 48 Khz
* stereo
* 16 bit audio
*/
runtime - > hw . channels_max = DUAL_CHANNEL ;
snd_pcm_hw_constraint_list ( runtime , 0 , SNDRV_PCM_HW_PARAM_CHANNELS ,
& constraints_channels ) ;
runtime - > hw . formats = SNDRV_PCM_FMTBIT_S16_LE ;
snd_pcm_hw_constraint_msbits ( runtime , 0 , 16 , 16 ) ;
snd_pcm_hw_constraint_list ( runtime , 0 ,
SNDRV_PCM_HW_PARAM_RATE , & constraints_rates ) ;
return 0 ;
}
static const struct snd_soc_ops broxton_da7219_fe_ops = {
. startup = bxt_fe_startup ,
} ;
2016-09-26 13:02:29 -07:00
static int broxton_dmic_fixup ( struct snd_soc_pcm_runtime * rtd ,
struct snd_pcm_hw_params * params )
{
2020-01-13 15:04:11 -06:00
struct snd_interval * chan = hw_param_interval ( params ,
2016-09-26 13:02:29 -07:00
SNDRV_PCM_HW_PARAM_CHANNELS ) ;
2016-12-06 07:08:36 -08:00
if ( params_channels ( params ) = = 2 )
2020-01-13 15:04:11 -06:00
chan - > min = chan - > max = 2 ;
2016-12-06 07:08:36 -08:00
else
2020-01-13 15:04:11 -06:00
chan - > min = chan - > max = 4 ;
2016-09-26 13:02:29 -07:00
return 0 ;
}
static int broxton_dmic_startup ( struct snd_pcm_substream * substream )
{
struct snd_pcm_runtime * runtime = substream - > runtime ;
2016-12-06 07:08:36 -08:00
runtime - > hw . channels_min = runtime - > hw . channels_max = QUAD_CHANNEL ;
2016-09-26 13:02:29 -07:00
snd_pcm_hw_constraint_list ( runtime , 0 , SNDRV_PCM_HW_PARAM_CHANNELS ,
2016-12-06 07:08:36 -08:00
& constraints_channels_quad ) ;
2016-09-26 13:02:29 -07:00
return snd_pcm_hw_constraint_list ( substream - > runtime , 0 ,
SNDRV_PCM_HW_PARAM_RATE , & constraints_rates ) ;
}
static const struct snd_soc_ops broxton_dmic_ops = {
. startup = broxton_dmic_startup ,
} ;
static const unsigned int rates_16000 [ ] = {
16000 ,
} ;
static const struct snd_pcm_hw_constraint_list constraints_16000 = {
. count = ARRAY_SIZE ( rates_16000 ) ,
. list = rates_16000 ,
} ;
2018-08-02 18:21:31 -05:00
static const unsigned int ch_mono [ ] = {
1 ,
} ;
static const struct snd_pcm_hw_constraint_list constraints_refcap = {
. count = ARRAY_SIZE ( ch_mono ) ,
. list = ch_mono ,
} ;
2016-09-26 13:02:29 -07:00
static int broxton_refcap_startup ( struct snd_pcm_substream * substream )
{
2018-08-02 18:21:31 -05:00
substream - > runtime - > hw . channels_max = 1 ;
snd_pcm_hw_constraint_list ( substream - > runtime , 0 ,
SNDRV_PCM_HW_PARAM_CHANNELS ,
& constraints_refcap ) ;
2016-09-26 13:02:29 -07:00
return snd_pcm_hw_constraint_list ( substream - > runtime , 0 ,
SNDRV_PCM_HW_PARAM_RATE ,
& constraints_16000 ) ;
} ;
2016-10-15 16:55:49 +02:00
static const struct snd_soc_ops broxton_refcap_ops = {
2016-09-26 13:02:29 -07:00
. startup = broxton_refcap_startup ,
} ;
2016-05-31 23:33:15 -07:00
/* broxton digital audio interface glue - connects codec <--> CPU */
2019-06-06 13:20:00 +09:00
SND_SOC_DAILINK_DEF ( dummy ,
DAILINK_COMP_ARRAY ( COMP_DUMMY ( ) ) ) ;
SND_SOC_DAILINK_DEF ( system ,
DAILINK_COMP_ARRAY ( COMP_CPU ( " System Pin " ) ) ) ;
SND_SOC_DAILINK_DEF ( system2 ,
DAILINK_COMP_ARRAY ( COMP_CPU ( " System Pin2 " ) ) ) ;
SND_SOC_DAILINK_DEF ( reference ,
DAILINK_COMP_ARRAY ( COMP_CPU ( " Reference Pin " ) ) ) ;
SND_SOC_DAILINK_DEF ( dmic ,
DAILINK_COMP_ARRAY ( COMP_CPU ( " DMIC Pin " ) ) ) ;
SND_SOC_DAILINK_DEF ( hdmi1 ,
DAILINK_COMP_ARRAY ( COMP_CPU ( " HDMI1 Pin " ) ) ) ;
SND_SOC_DAILINK_DEF ( hdmi2 ,
DAILINK_COMP_ARRAY ( COMP_CPU ( " HDMI2 Pin " ) ) ) ;
SND_SOC_DAILINK_DEF ( hdmi3 ,
DAILINK_COMP_ARRAY ( COMP_CPU ( " HDMI3 Pin " ) ) ) ;
/* Back End DAI */
SND_SOC_DAILINK_DEF ( ssp5_pin ,
DAILINK_COMP_ARRAY ( COMP_CPU ( " SSP5 Pin " ) ) ) ;
SND_SOC_DAILINK_DEF ( ssp5_codec ,
DAILINK_COMP_ARRAY ( COMP_CODEC ( " MX98357A:00 " ,
BXT_MAXIM_CODEC_DAI ) ) ) ;
2020-07-01 17:36:51 +08:00
SND_SOC_DAILINK_DEF ( max98390_codec ,
DAILINK_COMP_ARRAY (
/* Left */ COMP_CODEC ( MAX98390_DEV0_NAME , " max98390-aif1 " ) ,
/* Right */ COMP_CODEC ( MAX98390_DEV1_NAME , " max98390-aif1 " ) ) ) ;
2019-06-06 13:20:00 +09:00
SND_SOC_DAILINK_DEF ( ssp1_pin ,
DAILINK_COMP_ARRAY ( COMP_CPU ( " SSP1 Pin " ) ) ) ;
SND_SOC_DAILINK_DEF ( ssp1_codec ,
DAILINK_COMP_ARRAY ( COMP_CODEC ( " i2c-DLGS7219:00 " ,
BXT_DIALOG_CODEC_DAI ) ) ) ;
SND_SOC_DAILINK_DEF ( dmic_pin ,
DAILINK_COMP_ARRAY ( COMP_CPU ( " DMIC01 Pin " ) ) ) ;
2019-06-12 11:39:58 -05:00
SND_SOC_DAILINK_DEF ( dmic16k_pin ,
DAILINK_COMP_ARRAY ( COMP_CPU ( " DMIC16k Pin " ) ) ) ;
2019-06-06 13:20:00 +09:00
SND_SOC_DAILINK_DEF ( dmic_codec ,
DAILINK_COMP_ARRAY ( COMP_CODEC ( " dmic-codec " , " dmic-hifi " ) ) ) ;
SND_SOC_DAILINK_DEF ( idisp1_pin ,
DAILINK_COMP_ARRAY ( COMP_CPU ( " iDisp1 Pin " ) ) ) ;
SND_SOC_DAILINK_DEF ( idisp1_codec ,
DAILINK_COMP_ARRAY ( COMP_CODEC ( " ehdaudio0D2 " , " intel-hdmi-hifi1 " ) ) ) ;
SND_SOC_DAILINK_DEF ( idisp2_pin ,
DAILINK_COMP_ARRAY ( COMP_CPU ( " iDisp2 Pin " ) ) ) ;
SND_SOC_DAILINK_DEF ( idisp2_codec ,
DAILINK_COMP_ARRAY ( COMP_CODEC ( " ehdaudio0D2 " ,
" intel-hdmi-hifi2 " ) ) ) ;
SND_SOC_DAILINK_DEF ( idisp3_pin ,
DAILINK_COMP_ARRAY ( COMP_CPU ( " iDisp3 Pin " ) ) ) ;
SND_SOC_DAILINK_DEF ( idisp3_codec ,
DAILINK_COMP_ARRAY ( COMP_CODEC ( " ehdaudio0D2 " ,
" intel-hdmi-hifi3 " ) ) ) ;
SND_SOC_DAILINK_DEF ( platform ,
DAILINK_COMP_ARRAY ( COMP_PLATFORM ( " 0000:00:0e.0 " ) ) ) ;
2016-05-31 23:33:15 -07:00
static struct snd_soc_dai_link broxton_dais [ ] = {
/* Front End DAI links */
2016-09-27 07:45:09 +09:00
[ BXT_DPCM_AUDIO_PB ] =
2016-05-31 23:33:15 -07:00
{
. name = " Bxt Audio Port " ,
. stream_name = " Audio " ,
. dynamic = 1 ,
. nonatomic = 1 ,
. init = broxton_da7219_fe_init ,
. trigger = {
SND_SOC_DPCM_TRIGGER_POST , SND_SOC_DPCM_TRIGGER_POST } ,
. dpcm_playback = 1 ,
. ops = & broxton_da7219_fe_ops ,
2019-06-06 13:20:00 +09:00
SND_SOC_DAILINK_REG ( system , dummy , platform ) ,
2016-05-31 23:33:15 -07:00
} ,
2016-09-27 07:45:09 +09:00
[ BXT_DPCM_AUDIO_CP ] =
2016-05-31 23:33:15 -07:00
{
. name = " Bxt Audio Capture Port " ,
. stream_name = " Audio Record " ,
. dynamic = 1 ,
. nonatomic = 1 ,
. trigger = {
SND_SOC_DPCM_TRIGGER_POST , SND_SOC_DPCM_TRIGGER_POST } ,
. dpcm_capture = 1 ,
. ops = & broxton_da7219_fe_ops ,
2019-06-06 13:20:00 +09:00
SND_SOC_DAILINK_REG ( system , dummy , platform ) ,
2016-05-31 23:33:15 -07:00
} ,
2019-02-13 17:08:53 -06:00
[ BXT_DPCM_AUDIO_HS_PB ] = {
. name = " Bxt Audio Headset Playback " ,
. stream_name = " Headset Playback " ,
. dynamic = 1 ,
. nonatomic = 1 ,
. trigger = {
SND_SOC_DPCM_TRIGGER_POST , SND_SOC_DPCM_TRIGGER_POST } ,
. dpcm_playback = 1 ,
. ops = & broxton_da7219_fe_ops ,
2019-06-06 13:20:00 +09:00
SND_SOC_DAILINK_REG ( system2 , dummy , platform ) ,
2019-02-13 17:08:53 -06:00
} ,
2016-09-27 07:45:09 +09:00
[ BXT_DPCM_AUDIO_REF_CP ] =
2016-05-31 23:33:15 -07:00
{
. name = " Bxt Audio Reference cap " ,
. stream_name = " Refcap " ,
. init = NULL ,
. dpcm_capture = 1 ,
. nonatomic = 1 ,
. dynamic = 1 ,
2016-09-26 13:02:29 -07:00
. ops = & broxton_refcap_ops ,
2019-06-06 13:20:00 +09:00
SND_SOC_DAILINK_REG ( reference , dummy , platform ) ,
2016-09-26 13:02:29 -07:00
} ,
2016-10-17 23:02:56 +01:00
[ BXT_DPCM_AUDIO_DMIC_CP ] =
2016-09-26 13:02:29 -07:00
{
. name = " Bxt Audio DMIC cap " ,
. stream_name = " dmiccap " ,
. init = NULL ,
. dpcm_capture = 1 ,
. nonatomic = 1 ,
. dynamic = 1 ,
. ops = & broxton_dmic_ops ,
2019-06-06 13:20:00 +09:00
SND_SOC_DAILINK_REG ( dmic , dummy , platform ) ,
2016-05-31 23:33:15 -07:00
} ,
2016-09-27 07:45:09 +09:00
[ BXT_DPCM_AUDIO_HDMI1_PB ] =
2016-05-31 23:33:15 -07:00
{
. name = " Bxt HDMI Port1 " ,
. stream_name = " Hdmi1 " ,
. dpcm_playback = 1 ,
. init = NULL ,
. nonatomic = 1 ,
. dynamic = 1 ,
2019-06-06 13:20:00 +09:00
SND_SOC_DAILINK_REG ( hdmi1 , dummy , platform ) ,
2016-05-31 23:33:15 -07:00
} ,
2016-09-27 07:45:09 +09:00
[ BXT_DPCM_AUDIO_HDMI2_PB ] =
2016-05-31 23:33:15 -07:00
{
. name = " Bxt HDMI Port2 " ,
. stream_name = " Hdmi2 " ,
. dpcm_playback = 1 ,
. init = NULL ,
. nonatomic = 1 ,
. dynamic = 1 ,
2019-06-06 13:20:00 +09:00
SND_SOC_DAILINK_REG ( hdmi2 , dummy , platform ) ,
2016-05-31 23:33:15 -07:00
} ,
2016-09-27 07:45:09 +09:00
[ BXT_DPCM_AUDIO_HDMI3_PB ] =
2016-05-31 23:33:15 -07:00
{
. name = " Bxt HDMI Port3 " ,
. stream_name = " Hdmi3 " ,
. dpcm_playback = 1 ,
. init = NULL ,
. nonatomic = 1 ,
. dynamic = 1 ,
2019-06-06 13:20:00 +09:00
SND_SOC_DAILINK_REG ( hdmi3 , dummy , platform ) ,
2016-05-31 23:33:15 -07:00
} ,
/* Back End DAI links */
{
/* SSP5 - Codec */
. name = " SSP5-Codec " ,
. id = 0 ,
. no_pcm = 1 ,
. dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS ,
. ignore_pmdown_time = 1 ,
. be_hw_params_fixup = broxton_ssp_fixup ,
. dpcm_playback = 1 ,
2019-06-06 13:20:00 +09:00
SND_SOC_DAILINK_REG ( ssp5_pin , ssp5_codec , platform ) ,
2016-05-31 23:33:15 -07:00
} ,
{
/* SSP1 - Codec */
. name = " SSP1-Codec " ,
. id = 1 ,
. no_pcm = 1 ,
. init = broxton_da7219_codec_init ,
. dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS ,
. ignore_pmdown_time = 1 ,
. be_hw_params_fixup = broxton_ssp_fixup ,
. dpcm_playback = 1 ,
. dpcm_capture = 1 ,
2019-06-06 13:20:00 +09:00
SND_SOC_DAILINK_REG ( ssp1_pin , ssp1_codec , platform ) ,
2016-05-31 23:33:15 -07:00
} ,
{
. name = " dmic01 " ,
. id = 2 ,
. ignore_suspend = 1 ,
2016-09-26 13:02:29 -07:00
. be_hw_params_fixup = broxton_dmic_fixup ,
2016-05-31 23:33:15 -07:00
. dpcm_capture = 1 ,
. no_pcm = 1 ,
2019-06-06 13:20:00 +09:00
SND_SOC_DAILINK_REG ( dmic_pin , dmic_codec , platform ) ,
2016-05-31 23:33:15 -07:00
} ,
{
. name = " iDisp1 " ,
. id = 3 ,
. init = broxton_hdmi_init ,
. dpcm_playback = 1 ,
. no_pcm = 1 ,
2019-06-06 13:20:00 +09:00
SND_SOC_DAILINK_REG ( idisp1_pin , idisp1_codec , platform ) ,
2016-05-31 23:33:15 -07:00
} ,
{
. name = " iDisp2 " ,
. id = 4 ,
. init = broxton_hdmi_init ,
. dpcm_playback = 1 ,
. no_pcm = 1 ,
2019-06-06 13:20:00 +09:00
SND_SOC_DAILINK_REG ( idisp2_pin , idisp2_codec , platform ) ,
2016-05-31 23:33:15 -07:00
} ,
{
. name = " iDisp3 " ,
. id = 5 ,
. init = broxton_hdmi_init ,
. dpcm_playback = 1 ,
. no_pcm = 1 ,
2019-06-06 13:20:00 +09:00
SND_SOC_DAILINK_REG ( idisp3_pin , idisp3_codec , platform ) ,
2016-05-31 23:33:15 -07:00
} ,
2019-06-12 11:39:58 -05:00
{
. name = " dmic16k " ,
. id = 6 ,
. be_hw_params_fixup = broxton_dmic_fixup ,
. dpcm_capture = 1 ,
. no_pcm = 1 ,
SND_SOC_DAILINK_REG ( dmic16k_pin , dmic_codec , platform ) ,
} ,
2016-05-31 23:33:15 -07:00
} ;
2020-07-01 17:36:51 +08:00
static struct snd_soc_codec_conf max98390_codec_confs [ ] = {
{
. dlc = COMP_CODEC_CONF ( MAX98390_DEV0_NAME ) ,
. name_prefix = " Left " ,
} ,
{
. dlc = COMP_CODEC_CONF ( MAX98390_DEV1_NAME ) ,
. name_prefix = " Right " ,
} ,
} ;
2017-02-07 19:09:54 +05:30
# define NAME_SIZE 32
2017-01-24 21:49:07 +05:30
static int bxt_card_late_probe ( struct snd_soc_card * card )
{
struct bxt_card_private * ctx = snd_soc_card_get_drvdata ( card ) ;
struct bxt_hdmi_pcm * pcm ;
2018-01-29 04:36:54 +00:00
struct snd_soc_component * component = NULL ;
2020-07-01 17:36:51 +08:00
const struct snd_kcontrol_new * controls ;
const struct snd_soc_dapm_widget * widgets ;
const struct snd_soc_dapm_route * routes ;
int num_controls , num_widgets , num_routes , err , i = 0 ;
2017-02-07 19:09:54 +05:30
char jack_name [ NAME_SIZE ] ;
2017-01-24 21:49:07 +05:30
2020-07-01 17:36:51 +08:00
switch ( ctx - > spkamp ) {
case SPKAMP_MAX98357A :
controls = max98357a_controls ;
num_controls = ARRAY_SIZE ( max98357a_controls ) ;
widgets = max98357a_widgets ;
num_widgets = ARRAY_SIZE ( max98357a_widgets ) ;
routes = max98357a_routes ;
num_routes = ARRAY_SIZE ( max98357a_routes ) ;
break ;
case SPKAMP_MAX98390 :
controls = max98390_controls ;
num_controls = ARRAY_SIZE ( max98390_controls ) ;
widgets = max98390_widgets ;
num_widgets = ARRAY_SIZE ( max98390_widgets ) ;
routes = max98390_routes ;
num_routes = ARRAY_SIZE ( max98390_routes ) ;
break ;
default :
dev_err ( card - > dev , " Invalid speaker amplifier %d \n " , ctx - > spkamp ) ;
2020-07-02 12:48:35 +01:00
return - EINVAL ;
2020-07-01 17:36:51 +08:00
}
err = snd_soc_dapm_new_controls ( & card - > dapm , widgets , num_widgets ) ;
if ( err ) {
dev_err ( card - > dev , " Fail to new widgets \n " ) ;
return err ;
}
err = snd_soc_add_card_controls ( card , controls , num_controls ) ;
if ( err ) {
dev_err ( card - > dev , " Fail to add controls \n " ) ;
return err ;
}
err = snd_soc_dapm_add_routes ( & card - > dapm , routes , num_routes ) ;
if ( err ) {
dev_err ( card - > dev , " Fail to add routes \n " ) ;
return err ;
}
2019-05-30 06:50:11 -05:00
if ( soc_intel_is_glk ( ) )
2019-02-13 17:08:52 -06:00
snd_soc_dapm_add_routes ( & card - > dapm , gemini_map ,
ARRAY_SIZE ( gemini_map ) ) ;
else
snd_soc_dapm_add_routes ( & card - > dapm , broxton_map ,
ARRAY_SIZE ( broxton_map ) ) ;
2020-01-24 15:36:25 -06:00
if ( list_empty ( & ctx - > hdmi_pcm_list ) )
return - EINVAL ;
2019-10-29 15:40:14 +02:00
2020-01-24 15:36:25 -06:00
if ( ctx - > common_hdmi_codec_drv ) {
pcm = list_first_entry ( & ctx - > hdmi_pcm_list , struct bxt_hdmi_pcm ,
head ) ;
component = pcm - > codec_dai - > component ;
2019-10-29 15:40:14 +02:00
return hda_dsp_hdmi_build_controls ( card , component ) ;
2020-01-24 15:36:25 -06:00
}
2019-10-29 15:40:14 +02:00
2017-01-24 21:49:07 +05:30
list_for_each_entry ( pcm , & ctx - > hdmi_pcm_list , head ) {
2018-01-29 04:36:54 +00:00
component = pcm - > codec_dai - > component ;
2017-02-07 19:09:54 +05:30
snprintf ( jack_name , sizeof ( jack_name ) ,
" HDMI/DP, pcm=%d Jack " , pcm - > device ) ;
err = snd_soc_card_jack_new ( card , jack_name ,
SND_JACK_AVOUT , & broxton_hdmi [ i ] ,
NULL , 0 ) ;
if ( err )
return err ;
err = hdac_hdmi_jack_init ( pcm - > codec_dai , pcm - > device ,
& broxton_hdmi [ i ] ) ;
2017-01-24 21:49:07 +05:30
if ( err < 0 )
return err ;
2017-02-07 19:09:54 +05:30
i + + ;
2017-01-24 21:49:07 +05:30
}
2018-01-29 04:36:54 +00:00
return hdac_hdmi_jack_port_init ( component , & card - > dapm ) ;
2017-01-24 21:49:07 +05:30
}
2016-05-31 23:33:15 -07:00
/* broxton audio machine driver for SPT + da7219 */
static struct snd_soc_card broxton_audio_card = {
. name = " bxtda7219max " ,
. owner = THIS_MODULE ,
. dai_link = broxton_dais ,
. num_links = ARRAY_SIZE ( broxton_dais ) ,
. controls = broxton_controls ,
. num_controls = ARRAY_SIZE ( broxton_controls ) ,
. dapm_widgets = broxton_widgets ,
. num_dapm_widgets = ARRAY_SIZE ( broxton_widgets ) ,
2019-02-13 17:08:52 -06:00
. dapm_routes = audio_map ,
. num_dapm_routes = ARRAY_SIZE ( audio_map ) ,
2016-05-31 23:33:15 -07:00
. fully_routed = true ,
2017-01-24 21:49:07 +05:30
. late_probe = bxt_card_late_probe ,
2016-05-31 23:33:15 -07:00
} ;
static int broxton_audio_probe ( struct platform_device * pdev )
{
2017-01-24 21:49:07 +05:30
struct bxt_card_private * ctx ;
2019-01-25 14:35:07 -06:00
struct snd_soc_acpi_mach * mach ;
const char * platform_name ;
int ret ;
2017-01-24 21:49:07 +05:30
2018-04-09 18:46:21 +08:00
ctx = devm_kzalloc ( & pdev - > dev , sizeof ( * ctx ) , GFP_KERNEL ) ;
2017-01-24 21:49:07 +05:30
if ( ! ctx )
return - ENOMEM ;
INIT_LIST_HEAD ( & ctx - > hdmi_pcm_list ) ;
2020-07-01 17:36:51 +08:00
if ( acpi_dev_present ( " MX98390 " , NULL , - 1 ) )
ctx - > spkamp = SPKAMP_MAX98390 ;
else
ctx - > spkamp = SPKAMP_MAX98357A ;
2016-05-31 23:33:15 -07:00
broxton_audio_card . dev = & pdev - > dev ;
2017-01-24 21:49:07 +05:30
snd_soc_card_set_drvdata ( & broxton_audio_card , ctx ) ;
2019-05-30 06:50:11 -05:00
if ( soc_intel_is_glk ( ) ) {
2019-02-13 17:08:52 -06:00
unsigned int i ;
broxton_audio_card . name = " glkda7219max " ;
/* Fixup the SSP entries for geminilake */
for ( i = 0 ; i < ARRAY_SIZE ( broxton_dais ) ; i + + ) {
/* MAXIM_CODEC is connected to SSP1. */
2019-06-06 13:20:00 +09:00
if ( ! strcmp ( broxton_dais [ i ] . codecs - > dai_name ,
2019-02-13 17:08:52 -06:00
BXT_MAXIM_CODEC_DAI ) ) {
broxton_dais [ i ] . name = " SSP1-Codec " ;
2019-06-06 13:20:00 +09:00
broxton_dais [ i ] . cpus - > dai_name = " SSP1 Pin " ;
2019-02-13 17:08:52 -06:00
}
/* DIALOG_CODE is connected to SSP2 */
2019-06-06 13:20:00 +09:00
else if ( ! strcmp ( broxton_dais [ i ] . codecs - > dai_name ,
2019-02-13 17:08:52 -06:00
BXT_DIALOG_CODEC_DAI ) ) {
broxton_dais [ i ] . name = " SSP2-Codec " ;
2019-06-06 13:20:00 +09:00
broxton_dais [ i ] . cpus - > dai_name = " SSP2 Pin " ;
2019-02-13 17:08:52 -06:00
}
}
2019-08-15 14:51:49 +08:00
} else if ( soc_intel_is_cml ( ) ) {
unsigned int i ;
2020-07-01 17:36:51 +08:00
if ( ctx - > spkamp = = SPKAMP_MAX98390 ) {
broxton_audio_card . name = " cml_max98390_da7219 " ;
broxton_audio_card . codec_conf = max98390_codec_confs ;
broxton_audio_card . num_configs = ARRAY_SIZE ( max98390_codec_confs ) ;
} else
broxton_audio_card . name = " cmlda7219max " ;
2019-08-15 14:51:49 +08:00
for ( i = 0 ; i < ARRAY_SIZE ( broxton_dais ) ; i + + ) {
/* MAXIM_CODEC is connected to SSP1. */
if ( ! strcmp ( broxton_dais [ i ] . codecs - > dai_name ,
BXT_MAXIM_CODEC_DAI ) ) {
broxton_dais [ i ] . name = " SSP1-Codec " ;
broxton_dais [ i ] . cpus - > dai_name = " SSP1 Pin " ;
2020-07-01 17:36:51 +08:00
if ( ctx - > spkamp = = SPKAMP_MAX98390 ) {
broxton_dais [ i ] . codecs = max98390_codec ;
broxton_dais [ i ] . num_codecs = ARRAY_SIZE ( max98390_codec ) ;
}
2019-08-15 14:51:49 +08:00
}
/* DIALOG_CODEC is connected to SSP0 */
else if ( ! strcmp ( broxton_dais [ i ] . codecs - > dai_name ,
BXT_DIALOG_CODEC_DAI ) ) {
broxton_dais [ i ] . name = " SSP0-Codec " ;
broxton_dais [ i ] . cpus - > dai_name = " SSP0 Pin " ;
}
}
2019-02-13 17:08:52 -06:00
}
2017-01-24 21:49:07 +05:30
2019-01-25 14:35:07 -06:00
/* override plaform name, if required */
2020-03-12 14:48:56 -05:00
mach = pdev - > dev . platform_data ;
2019-01-25 14:35:07 -06:00
platform_name = mach - > mach_params . platform ;
ret = snd_soc_fixup_dai_links_platform_name ( & broxton_audio_card ,
platform_name ) ;
if ( ret )
return ret ;
2019-10-29 15:40:14 +02:00
ctx - > common_hdmi_codec_drv = mach - > mach_params . common_hdmi_codec_drv ;
2016-05-31 23:33:15 -07:00
return devm_snd_soc_register_card ( & pdev - > dev , & broxton_audio_card ) ;
}
2019-02-13 17:08:52 -06:00
static const struct platform_device_id bxt_board_ids [ ] = {
{ . name = " bxt_da7219_max98357a " } ,
{ . name = " glk_da7219_max98357a " } ,
2019-08-15 14:51:49 +08:00
{ . name = " cml_da7219_max98357a " } ,
2019-02-13 17:08:52 -06:00
{ }
} ;
2016-05-31 23:33:15 -07:00
static struct platform_driver broxton_audio = {
. probe = broxton_audio_probe ,
. driver = {
2018-06-18 13:29:35 -05:00
. name = " bxt_da7219_max98357a " ,
2016-05-31 23:33:15 -07:00
. pm = & snd_soc_pm_ops ,
} ,
2019-02-13 17:08:52 -06:00
. id_table = bxt_board_ids ,
2016-05-31 23:33:15 -07:00
} ;
module_platform_driver ( broxton_audio )
/* Module information */
MODULE_DESCRIPTION ( " Audio Machine driver-DA7219 & MAX98357A in I2S mode " ) ;
MODULE_AUTHOR ( " Sathyanarayana Nujella <sathyanarayana.nujella@intel.com> " ) ;
MODULE_AUTHOR ( " Rohit Ainapure <rohit.m.ainapure@intel.com> " ) ;
MODULE_AUTHOR ( " Harsha Priya <harshapriya.n@intel.com> " ) ;
MODULE_AUTHOR ( " Conrad Cooke <conrad.cooke@intel.com> " ) ;
2019-02-13 17:08:52 -06:00
MODULE_AUTHOR ( " Naveen Manohar <naveen.m@intel.com> " ) ;
2019-08-15 14:51:49 +08:00
MODULE_AUTHOR ( " Mac Chiang <mac.chiang@intel.com> " ) ;
2020-07-01 17:36:51 +08:00
MODULE_AUTHOR ( " Brent Lu <brent.lu@intel.com> " ) ;
2016-05-31 23:33:15 -07:00
MODULE_LICENSE ( " GPL v2 " ) ;
2018-06-18 13:29:35 -05:00
MODULE_ALIAS ( " platform:bxt_da7219_max98357a " ) ;
2019-02-13 17:08:52 -06:00
MODULE_ALIAS ( " platform:glk_da7219_max98357a " ) ;
2019-08-15 14:51:49 +08:00
MODULE_ALIAS ( " platform:cml_da7219_max98357a " ) ;