diff options
Diffstat (limited to 'sound/soc/intel/boards')
69 files changed, 9524 insertions, 14163 deletions
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index d96fc1313434..2df7afa2f469 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -26,10 +26,28 @@ config SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES interface. If unsure select N. -if SND_SOC_INTEL_HASWELL +config SND_SOC_INTEL_HDA_DSP_COMMON + tristate + +config SND_SOC_INTEL_SOF_MAXIM_COMMON + tristate + +config SND_SOC_INTEL_SOF_REALTEK_COMMON + tristate + +config SND_SOC_INTEL_SOF_CIRRUS_COMMON + tristate + +config SND_SOC_INTEL_SOF_NUVOTON_COMMON + tristate + +config SND_SOC_INTEL_SOF_BOARD_HELPERS + tristate + +if SND_SOC_INTEL_CATPT config SND_SOC_INTEL_HASWELL_MACH - tristate "Haswell Lynxpoint" + tristate "Haswell with RT5640 I2S codec" depends on I2C depends on I2C_DESIGNWARE_PLATFORM || COMPILE_TEST depends on X86_INTEL_LPSS || COMPILE_TEST @@ -40,9 +58,9 @@ config SND_SOC_INTEL_HASWELL_MACH Say Y or m if you have such a device. If unsure select "N". -endif ## SND_SOC_INTEL_HASWELL +endif ## SND_SOC_INTEL_CATPT -if SND_SOC_INTEL_HASWELL || SND_SOC_SOF_BROADWELL +if SND_SOC_INTEL_CATPT || SND_SOC_SOF_BROADWELL config SND_SOC_INTEL_BDW_RT5650_MACH tristate "Broadwell with RT5650 codec" @@ -73,7 +91,7 @@ config SND_SOC_INTEL_BDW_RT5677_MACH If unsure select "N". config SND_SOC_INTEL_BROADWELL_MACH - tristate "Broadwell Wildcatpoint" + tristate "Broadwell with RT286 I2S codec" depends on I2C depends on I2C_DESIGNWARE_PLATFORM || COMPILE_TEST depends on X86_INTEL_LPSS || COMPILE_TEST @@ -83,32 +101,7 @@ config SND_SOC_INTEL_BROADWELL_MACH Ultrabook platforms. Say Y or m if you have such a device. This is a recommended option. If unsure select "N". -endif ## SND_SOC_INTEL_HASWELL || SND_SOC_SOF_BROADWELL - -if SND_SOC_INTEL_BAYTRAIL - -config SND_SOC_INTEL_BYT_MAX98090_MACH - tristate "Baytrail with MAX98090 codec" - depends on I2C - depends on X86_INTEL_LPSS || COMPILE_TEST - select SND_SOC_MAX98090 - help - This adds audio driver for Intel Baytrail platform based boards - with the MAX98090 audio codec. This driver is deprecated, use - SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH instead for better - functionality. - -config SND_SOC_INTEL_BYT_RT5640_MACH - tristate "Baytrail with RT5640 codec" - depends on I2C - depends on X86_INTEL_LPSS || COMPILE_TEST - select SND_SOC_RT5640 - help - This adds audio driver for Intel Baytrail platform based boards - with the RT5640 audio codec. This driver is deprecated, use - SND_SOC_INTEL_BYTCR_RT5640_MACH instead for better functionality. - -endif ## SND_SOC_INTEL_BAYTRAIL +endif ## SND_SOC_INTEL_CATPT || SND_SOC_SOF_BROADWELL if SND_SST_ATOM_HIFI2_PLATFORM || SND_SOC_SOF_BAYTRAIL @@ -116,6 +109,7 @@ config SND_SOC_INTEL_BYTCR_RT5640_MACH tristate "Baytrail and Baytrail-CR with RT5640 codec" depends on I2C && ACPI depends on X86_INTEL_LPSS || COMPILE_TEST + depends on GPIOLIB || COMPILE_TEST select SND_SOC_ACPI select SND_SOC_RT5640 help @@ -128,6 +122,7 @@ config SND_SOC_INTEL_BYTCR_RT5651_MACH tristate "Baytrail and Baytrail-CR with RT5651 codec" depends on I2C && ACPI depends on X86_INTEL_LPSS || COMPILE_TEST + depends on GPIOLIB || COMPILE_TEST select SND_SOC_ACPI select SND_SOC_RT5651 help @@ -136,10 +131,24 @@ config SND_SOC_INTEL_BYTCR_RT5651_MACH Say Y or m if you have such a device. This is a recommended option. If unsure select "N". +config SND_SOC_INTEL_BYTCR_WM5102_MACH + tristate "Baytrail and Baytrail-CR with WM5102 codec" + depends on MFD_ARIZONA && MFD_WM5102 && SPI_MASTER && ACPI + depends on X86_INTEL_LPSS || COMPILE_TEST + depends on GPIOLIB || COMPILE_TEST + select SND_SOC_ACPI + select SND_SOC_WM5102 + help + This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR + platforms with WM5102 audio codec. + Say Y if you have such a device. + If unsure select "N". + config SND_SOC_INTEL_CHT_BSW_RT5672_MACH tristate "Cherrytrail & Braswell with RT5672 codec" depends on I2C && ACPI depends on X86_INTEL_LPSS || COMPILE_TEST + depends on GPIOLIB || COMPILE_TEST select SND_SOC_ACPI select SND_SOC_RT5670 help @@ -164,6 +173,7 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH tristate "Cherrytrail & Braswell with MAX98090 & TI codec" depends on I2C && ACPI depends on X86_INTEL_LPSS || COMPILE_TEST + depends on GPIOLIB || COMPILE_TEST select SND_SOC_MAX98090 select SND_SOC_TS3A227E help @@ -188,6 +198,7 @@ config SND_SOC_INTEL_BYT_CHT_CX2072X_MACH tristate "Baytrail & Cherrytrail with CX2072X codec" depends on I2C && ACPI depends on X86_INTEL_LPSS || COMPILE_TEST + depends on GPIOLIB || COMPILE_TEST select SND_SOC_ACPI select SND_SOC_CX2072X help @@ -212,8 +223,10 @@ config SND_SOC_INTEL_BYT_CHT_ES8316_MACH tristate "Baytrail & Cherrytrail with ES8316 codec" depends on I2C && ACPI depends on X86_INTEL_LPSS || COMPILE_TEST + depends on GPIOLIB || COMPILE_TEST select SND_SOC_ACPI select SND_SOC_ES8316 + select SND_SOC_ES83XX_DSM_COMMON help This adds support for ASoC machine driver for Intel(R) Baytrail & Cherrytrail platforms with ES8316 audio codec. @@ -239,98 +252,13 @@ config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH endif ## SND_SST_ATOM_HIFI2_PLATFORM -if SND_SOC_INTEL_SKL - -config SND_SOC_INTEL_SKL_RT286_MACH - tristate "SKL with RT286 I2S mode" - depends on I2C && ACPI && GPIOLIB - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_RT286 - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - help - This adds support for ASoC machine driver for Skylake platforms - with RT286 I2S audio codec. - Say Y or m if you have such a device. - If unsure select "N". - -config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH - tristate "SKL with NAU88L25 and SSM4567 in I2S Mode" - depends on I2C && ACPI && GPIOLIB - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_NAU8825 - select SND_SOC_SSM4567 - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - help - This adds support for ASoC Onboard Codec I2S machine driver. This will - create an alsa sound card for NAU88L25 + SSM4567. - Say Y or m if you have such a device. This is a recommended option. - If unsure select "N". - -config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH - tristate "SKL with NAU88L25 and MAX98357A in I2S Mode" - depends on I2C && ACPI && GPIOLIB - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_NAU8825 - select SND_SOC_MAX98357A - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - help - This adds support for ASoC Onboard Codec I2S machine driver. This will - create an alsa sound card for NAU88L25 + MAX98357A. - Say Y or m if you have such a device. This is a recommended option. - If unsure select "N". - -endif ## SND_SOC_INTEL_SKL - -config SND_SOC_INTEL_DA7219_MAX98357A_GENERIC - tristate - select SND_SOC_DA7219 - select SND_SOC_MAX98357A - select SND_SOC_MAX98390 - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - -config SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON - tristate - select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC - -if SND_SOC_INTEL_APL - -config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH - tristate "Broxton with DA7219 and MAX98357A/MAX98390 in I2S Mode" - depends on I2C && ACPI && GPIOLIB - depends on MFD_INTEL_LPSS || COMPILE_TEST - depends on SND_HDA_CODEC_HDMI - select SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON - help - This adds support for ASoC machine driver for Broxton-P platforms - with DA7219 + MAX98357A/MAX98390 I2S audio codec. - Say Y or m if you have such a device. This is a recommended option. - If unsure select "N". - -config SND_SOC_INTEL_BXT_RT298_MACH - tristate "Broxton with RT298 I2S mode" - depends on I2C && ACPI && GPIOLIB - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_RT298 - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - help - This adds support for ASoC machine driver for Broxton platforms - with RT286 I2S audio codec. - Say Y or m if you have such a device. This is a recommended option. - If unsure select "N". - -endif ## SND_SOC_INTEL_APL - if SND_SOC_SOF_APOLLOLAKE config SND_SOC_INTEL_SOF_WM8804_MACH tristate "SOF with Wolfson/Cirrus WM8804 codec" depends on I2C && ACPI depends on MFD_INTEL_LPSS || COMPILE_TEST + depends on GPIOLIB || COMPILE_TEST select SND_SOC_WM8804_I2C help This adds support for ASoC machine driver for Intel platforms @@ -340,141 +268,91 @@ config SND_SOC_INTEL_SOF_WM8804_MACH endif ## SND_SOC_SOF_APOLLOLAKE -if SND_SOC_INTEL_KBL - -config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH - tristate "KBL with RT5663 and MAX98927 in I2S Mode" - depends on I2C && ACPI && GPIOLIB - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_RT5663 - select SND_SOC_MAX98927 - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - select SND_SOC_INTEL_SKYLAKE_SSP_CLK - help - This adds support for ASoC Onboard Codec I2S machine driver. This will - create an alsa sound card for RT5663 + MAX98927. - Say Y or m if you have such a device. This is a recommended option. - If unsure select "N". - -config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH - tristate "KBL with RT5663, RT5514 and MAX98927 in I2S Mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - depends on SPI - select SND_SOC_RT5663 - select SND_SOC_RT5514 - select SND_SOC_RT5514_SPI - select SND_SOC_MAX98927 - select SND_SOC_HDAC_HDMI - select SND_SOC_INTEL_SKYLAKE_SSP_CLK - help - This adds support for ASoC Onboard Codec I2S machine driver. This will - create an alsa sound card for RT5663 + RT5514 + MAX98927. - Say Y or m if you have such a device. This is a recommended option. - If unsure select "N". - -config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH - tristate "KBL with DA7219 and MAX98357A in I2S Mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC - help - This adds support for ASoC Onboard Codec I2S machine driver. This will - create an alsa sound card for DA7219 + MAX98357A I2S audio codec. - Say Y if you have such a device. - -config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH - tristate "KBL with DA7219 and MAX98927 in I2S Mode" - depends on I2C && ACPI && GPIOLIB - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_DA7219 - select SND_SOC_MAX98927 - select SND_SOC_MAX98373_I2C - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - help - This adds support for ASoC Onboard Codec I2S machine driver. This will - create an alsa sound card for DA7219 + MAX98927 I2S audio codec. - Say Y if you have such a device. - If unsure select "N". - -config SND_SOC_INTEL_KBL_RT5660_MACH - tristate "KBL with RT5660 in I2S Mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_RT5660 - select SND_SOC_HDAC_HDMI - help - This adds support for ASoC Onboard Codec I2S machine driver. This will - create an alsa sound card for RT5660 I2S audio codec. - Say Y if you have such a device. - -endif ## SND_SOC_INTEL_KBL - if SND_SOC_SOF_GEMINILAKE config SND_SOC_INTEL_GLK_DA7219_MAX98357A_MACH tristate "GLK with DA7219 and MAX98357A in I2S Mode" - depends on I2C && ACPI && GPIOLIB - depends on MFD_INTEL_LPSS || COMPILE_TEST - depends on SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC - select SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON + imply SND_SOC_INTEL_SOF_DA7219_MACH help This adds support for ASoC machine driver for Geminilake platforms - with DA7219 + MAX98357A I2S audio codec. + with DA7219 + MAX98357A I2S audio codec. This option is deprecated + and please use SND_SOC_INTEL_SOF_DA7219_MACH instead. Say Y or m if you have such a device. This is a recommended option. If unsure select "N". config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH tristate "GLK with RT5682 and MAX98357A in I2S Mode" - depends on I2C && ACPI && GPIOLIB - depends on MFD_INTEL_LPSS || COMPILE_TEST - depends on SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC - select SND_SOC_RT5682_I2C - select SND_SOC_MAX98357A - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI + imply SND_SOC_INTEL_SOF_RT5682_MACH help This adds support for ASoC machine driver for Geminilake platforms - with RT5682 + MAX98357A I2S audio codec. + with RT5682 + MAX98357A I2S audio codec. This option is deprecated + and please use SND_SOC_INTEL_SOF_RT5682_MACH instead. Say Y if you have such a device. If unsure select "N". endif ## SND_SOC_SOF_GEMINILAKE -if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC +if SND_SOC_SOF_HDA_AUDIO_CODEC config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH - tristate "SKL/KBL/BXT/APL with HDA Codecs" + tristate "Skylake+ with HDA Codecs" depends on SND_HDA_CODEC_HDMI - depends on GPIOLIB - select SND_SOC_HDAC_HDMI + select SND_SOC_INTEL_HDA_DSP_COMMON + select SND_SOC_INTEL_SOF_BOARD_HELPERS select SND_SOC_DMIC # SND_SOC_HDAC_HDA is already selected help - This adds support for ASoC machine driver for Intel platforms - SKL/KBL/BXT/APL with iDisp, HDA audio codecs. + This adds support for ASoC machine driver for Intel Skylake+ + platforms with display (HDMI/DP) and HDA audio codecs, and + Smart Sound Technology (SST) integrated audio DSP. Say Y or m if you have such a device. This is a recommended option. If unsure select "N". -endif ## SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC +endif ## SND_SOC_SOF_HDA_AUDIO_CODEC if SND_SOC_SOF_HDA_LINK || SND_SOC_SOF_BAYTRAIL config SND_SOC_INTEL_SOF_RT5682_MACH - tristate "SOF with rt5682 codec in I2S Mode" - depends on I2C && ACPI && GPIOLIB + tristate "SOF with rt5650/rt5682 codec in I2S Mode" + depends on I2C && ACPI depends on ((SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC) &&\ (MFD_INTEL_LPSS || COMPILE_TEST)) ||\ (SND_SOC_SOF_BAYTRAIL && (X86_INTEL_LPSS || COMPILE_TEST)) + select SND_SOC_MAX98357A select SND_SOC_MAX98373_I2C + select SND_SOC_MAX98390 + select SND_SOC_RT1011 select SND_SOC_RT1015 + select SND_SOC_RT1015P + select SND_SOC_RT5645 select SND_SOC_RT5682_I2C + select SND_SOC_RT5682S select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI + select SND_SOC_INTEL_HDA_DSP_COMMON + select SND_SOC_INTEL_SOF_BOARD_HELPERS + select SND_SOC_INTEL_SOF_MAXIM_COMMON + select SND_SOC_INTEL_SOF_REALTEK_COMMON + select SND_SOC_ACPI_INTEL_MATCH help This adds support for ASoC machine driver for SOF platforms - with rt5682 codec. + with rt5650 or rt5682 codec. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_INTEL_SOF_CS42L42_MACH + tristate "SOF with cs42l42 codec in I2S Mode" + depends on I2C && ACPI + depends on ((SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC) &&\ + (MFD_INTEL_LPSS || COMPILE_TEST)) + select SND_SOC_CS42L42 + select SND_SOC_MAX98357A + select SND_SOC_DMIC + select SND_SOC_INTEL_HDA_DSP_COMMON + select SND_SOC_INTEL_SOF_BOARD_HELPERS + select SND_SOC_INTEL_SOF_MAXIM_COMMON + select SND_SOC_ACPI_INTEL_MATCH + help + This adds support for ASoC machine driver for SOF platforms + with cs42l42 codec. Say Y if you have such a device. If unsure select "N". @@ -484,6 +362,7 @@ config SND_SOC_INTEL_SOF_PCM512x_MACH depends on (SND_SOC_SOF_HDA_AUDIO_CODEC && (MFD_INTEL_LPSS || COMPILE_TEST)) ||\ (SND_SOC_SOF_BAYTRAIL && (X86_INTEL_LPSS || COMPILE_TEST)) depends on SND_HDA_CODEC_HDMI + select SND_SOC_INTEL_HDA_DSP_COMMON select SND_SOC_PCM512x_I2C help This adds support for ASoC machine driver for SOF platforms @@ -491,65 +370,122 @@ config SND_SOC_INTEL_SOF_PCM512x_MACH Say Y or m if you have such a device. If unsure select "N". +config SND_SOC_INTEL_SOF_ES8336_MACH + tristate "SOF with ES8336 or ES8326 codec in I2S mode" + depends on I2C && ACPI + depends on MFD_INTEL_LPSS || COMPILE_TEST + depends on GPIOLIB || COMPILE_TEST + depends on SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC + select SND_SOC_ES8316 + select SND_SOC_ES8326 + select SND_SOC_DMIC + select SND_SOC_INTEL_HDA_DSP_COMMON + help + This adds support for ASoC machine driver for SOF platforms + with es8336 codec. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_INTEL_SOF_NAU8825_MACH + tristate "SOF with nau8825 codec in I2S Mode" + depends on I2C && ACPI + depends on ((SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC) &&\ + (MFD_INTEL_LPSS || COMPILE_TEST)) + select SND_SOC_NAU8825 + select SND_SOC_RT1015P + select SND_SOC_MAX98373_I2C + select SND_SOC_MAX98357A + select SND_SOC_NAU8315 + select SND_SOC_DMIC + select SND_SOC_INTEL_HDA_DSP_COMMON + select SND_SOC_INTEL_SOF_BOARD_HELPERS + select SND_SOC_INTEL_SOF_MAXIM_COMMON + select SND_SOC_INTEL_SOF_NUVOTON_COMMON + select SND_SOC_INTEL_SOF_REALTEK_COMMON + select SND_SOC_ACPI_INTEL_MATCH + help + This adds support for ASoC machine driver for SOF platforms + with nau8825 codec. + Say Y if you have such a device. + If unsure select "N". + endif ## SND_SOC_SOF_HDA_LINK || SND_SOC_SOF_BAYTRAIL if (SND_SOC_SOF_COMETLAKE && SND_SOC_SOF_HDA_LINK) config SND_SOC_INTEL_CML_LP_DA7219_MAX98357A_MACH tristate "CML_LP with DA7219 and MAX98357A in I2S Mode" - depends on I2C && ACPI && GPIOLIB - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON + imply SND_SOC_INTEL_SOF_DA7219_MACH help This adds support for ASoC machine driver for Cometlake platforms - with DA7219 + MAX98357A I2S audio codec. + with DA7219 + MAX98357A I2S audio codec. This option is deprecated + and please use SND_SOC_INTEL_SOF_DA7219_MACH instead. Say Y or m if you have such a device. This is a recommended option. If unsure select "N". config SND_SOC_INTEL_SOF_CML_RT1011_RT5682_MACH tristate "CML with RT1011 and RT5682 in I2S Mode" - depends on I2C && ACPI && GPIOLIB - depends on MFD_INTEL_LPSS || COMPILE_TEST - depends on SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC - select SND_SOC_RT1011 - select SND_SOC_RT5682_I2C - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI + imply SND_SOC_INTEL_SOF_RT5682_MACH help This adds support for ASoC machine driver for SOF platform with - RT1011 + RT5682 I2S codec. + RT1011 + RT5682 I2S codec. This option is deprecated and please used + SND_SOC_INTEL_SOF_RT5682_MACH instead. Say Y if you have such a device. If unsure select "N". endif ## SND_SOC_SOF_COMETLAKE && SND_SOC_SOF_HDA_LINK -if SND_SOC_SOF_JASPERLAKE - -config SND_SOC_INTEL_SOF_DA7219_MAX98373_MACH - tristate "SOF with DA7219 and MAX98373/MAX98360A in I2S Mode" - depends on I2C && ACPI && GPIOLIB +config SND_SOC_INTEL_SOF_DA7219_MACH + tristate "SOF with DA7219 codec in I2S Mode" + depends on I2C && ACPI depends on MFD_INTEL_LPSS || COMPILE_TEST depends on SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC + select SND_SOC_INTEL_HDA_DSP_COMMON select SND_SOC_DA7219 + select SND_SOC_MAX98357A select SND_SOC_MAX98373_I2C + select SND_SOC_MAX98390 select SND_SOC_DMIC + select SND_SOC_INTEL_SOF_BOARD_HELPERS + select SND_SOC_INTEL_SOF_MAXIM_COMMON + select SND_SOC_ACPI_INTEL_MATCH help This adds support for ASoC machine driver for SOF platforms - with DA7219 + MAX98373/MAX98360A I2S audio codec. + with Dialog DA7219 I2S audio codec. Say Y if you have such a device. If unsure select "N". -endif ## SND_SOC_SOF_JASPERLAKE +if SND_SOC_SOF_HDA_LINK + +config SND_SOC_INTEL_SOF_SSP_AMP_MACH + tristate "SOF with amplifiers in I2S Mode" + depends on I2C && ACPI + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_RT1308 + select SND_SOC_CS35L41_I2C + select SND_SOC_DMIC + select SND_SOC_INTEL_HDA_DSP_COMMON + select SND_SOC_INTEL_SOF_BOARD_HELPERS + select SND_SOC_INTEL_SOF_REALTEK_COMMON + select SND_SOC_INTEL_SOF_CIRRUS_COMMON + select SND_SOC_ACPI_INTEL_MATCH + help + This adds support for ASoC machine driver for SOF platforms + with RT1308/CS35L41 I2S audio codec. + Say Y if you have such a device. + If unsure select "N". +endif ## SND_SOC_SOF_HDA_LINK if SND_SOC_SOF_ELKHARTLAKE config SND_SOC_INTEL_EHL_RT5660_MACH tristate "EHL with RT5660 in I2S mode" - depends on I2C && ACPI && GPIOLIB + depends on I2C && ACPI depends on MFD_INTEL_LPSS || COMPILE_TEST depends on SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC select SND_SOC_RT5660 select SND_SOC_DMIC + select SND_SOC_INTEL_HDA_DSP_COMMON help This adds support for ASoC machine driver for Elkhart Lake platform with RT5660 I2S audio codec. @@ -560,26 +496,46 @@ if SND_SOC_SOF_INTEL_SOUNDWIRE config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH tristate "SoundWire generic machine driver" - depends on I2C && ACPI && GPIOLIB + depends on I2C && SPI_MASTER && ACPI depends on MFD_INTEL_LPSS || COMPILE_TEST depends on SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES || COMPILE_TEST depends on SOUNDWIRE - depends on SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC + select SND_SOC_SDW_UTILS + select SND_SOC_MAX98363 select SND_SOC_MAX98373_I2C select SND_SOC_MAX98373_SDW select SND_SOC_RT700_SDW select SND_SOC_RT711_SDW + select SND_SOC_RT711_SDCA_SDW + select SND_SOC_RT712_SDCA_SDW + select SND_SOC_RT712_SDCA_DMIC_SDW + select SND_SOC_RT715_SDW + select SND_SOC_RT715_SDCA_SDW + select SND_SOC_RT721_SDCA_SDW + select SND_SOC_RT722_SDCA_SDW select SND_SOC_RT1308_SDW select SND_SOC_RT1308 - select SND_SOC_RT715_SDW + select SND_SOC_RT1316_SDW + select SND_SOC_RT1318_SDW + select SND_SOC_RT1320_SDW select SND_SOC_RT5682_SDW + select SND_SOC_CS42L42_SDW + select SND_SOC_CS42L43 + select SND_SOC_CS42L43_SDW + select MFD_CS42L43 + select MFD_CS42L43_SDW + select PINCTRL_CS42L43 + select SPI_CS42L43 + select SND_SOC_CS35L56_SPI + select SND_SOC_CS35L56_SDW select SND_SOC_DMIC - help + select SND_SOC_INTEL_HDA_DSP_COMMON + imply SND_SOC_SDW_MOCKUP + help Add support for Intel SoundWire-based platforms connected to MAX98373, RT700, RT711, RT1308 and RT715 If unsure select "N". endif - endif ## SND_SOC_INTEL_MACH diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index dc04acb911b6..fcd517d6c279 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -1,59 +1,45 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-soc-sst-haswell-objs := haswell.o -snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o -snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o -snd-soc-sst-bdw-rt5650-mach-objs := bdw-rt5650.o -snd-soc-sst-bdw-rt5677-mach-objs := bdw-rt5677.o -snd-soc-sst-broadwell-objs := broadwell.o -snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o hda_dsp_common.o -snd-soc-sst-bxt-rt298-objs := bxt_rt298.o hda_dsp_common.o -snd-soc-sst-sof-pcm512x-objs := sof_pcm512x.o hda_dsp_common.o -snd-soc-sst-sof-wm8804-objs := sof_wm8804.o -snd-soc-sst-glk-rt5682_max98357a-objs := glk_rt5682_max98357a.o hda_dsp_common.o -snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o -snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o -snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o -snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o -snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o -snd-soc-sst-cht-bsw-nau8824-objs := cht_bsw_nau8824.o -snd-soc-sst-byt-cht-cx2072x-objs := bytcht_cx2072x.o -snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o -snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o -snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o -snd-soc-sof_rt5682-objs := sof_rt5682.o hda_dsp_common.o sof_maxim_common.o -snd-soc-cml_rt1011_rt5682-objs := cml_rt1011_rt5682.o hda_dsp_common.o -snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o -snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o -snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o -snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o -snd-soc-kbl_rt5660-objs := kbl_rt5660.o -snd-soc-skl_rt286-objs := skl_rt286.o -snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o hda_dsp_common.o -snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o -snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o -snd-soc-sof_da7219_max98373-objs := sof_da7219_max98373.o hda_dsp_common.o -snd-soc-ehl-rt5660-objs := ehl_rt5660.o hda_dsp_common.o -snd-soc-sof-sdw-objs += sof_sdw.o \ - sof_sdw_max98373.o \ - sof_sdw_rt711.o sof_sdw_rt700.o \ - sof_sdw_rt1308.o sof_sdw_rt715.o \ - sof_sdw_rt5682.o \ - sof_maxim_common.o \ - sof_sdw_dmic.o sof_sdw_hdmi.o hda_dsp_common.o +snd-soc-hsw-rt5640-y := hsw_rt5640.o +snd-soc-sst-bdw-rt5650-mach-y := bdw-rt5650.o +snd-soc-sst-bdw-rt5677-mach-y := bdw-rt5677.o +snd-soc-bdw-rt286-y := bdw_rt286.o +snd-soc-sst-sof-pcm512x-y := sof_pcm512x.o +snd-soc-sst-sof-wm8804-y := sof_wm8804.o +snd-soc-sst-bytcr-rt5640-y := bytcr_rt5640.o +snd-soc-sst-bytcr-rt5651-y := bytcr_rt5651.o +snd-soc-sst-bytcr-wm5102-y := bytcr_wm5102.o +snd-soc-sst-cht-bsw-rt5672-y := cht_bsw_rt5672.o +snd-soc-sst-cht-bsw-rt5645-y := cht_bsw_rt5645.o +snd-soc-sst-cht-bsw-max98090_ti-y := cht_bsw_max98090_ti.o +snd-soc-sst-cht-bsw-nau8824-y := cht_bsw_nau8824.o +snd-soc-sst-byt-cht-cx2072x-y := bytcht_cx2072x.o +snd-soc-sst-byt-cht-da7213-y := bytcht_da7213.o +snd-soc-sst-byt-cht-es8316-y := bytcht_es8316.o +snd-soc-sst-byt-cht-nocodec-y := bytcht_nocodec.o +snd-soc-sof_rt5682-y := sof_rt5682.o +snd-soc-sof_cs42l42-y := sof_cs42l42.o +snd-soc-sof_es8336-y := sof_es8336.o +snd-soc-sof_nau8825-y := sof_nau8825.o +snd-soc-sof_da7219-y := sof_da7219.o +snd-soc-skl_hda_dsp-y := skl_hda_dsp_generic.o +snd-soc-ehl-rt5660-y := ehl_rt5660.o +snd-soc-sof-ssp-amp-y := sof_ssp_amp.o +snd-soc-sof-sdw-y += sof_sdw.o \ + sof_sdw_hdmi.o obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o -obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o -obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o -obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o -obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON) += snd-soc-sst-bxt-da7219_max98357a.o -obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o +obj-$(CONFIG_SND_SOC_INTEL_SOF_CS42L42_MACH) += snd-soc-sof_cs42l42.o +obj-$(CONFIG_SND_SOC_INTEL_SOF_ES8336_MACH) += snd-soc-sof_es8336.o +obj-$(CONFIG_SND_SOC_INTEL_SOF_NAU8825_MACH) += snd-soc-sof_nau8825.o +obj-$(CONFIG_SND_SOC_INTEL_SOF_DA7219_MACH) += snd-soc-sof_da7219.o +obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-hsw-rt5640.o obj-$(CONFIG_SND_SOC_INTEL_SOF_PCM512x_MACH) += snd-soc-sst-sof-pcm512x.o obj-$(CONFIG_SND_SOC_INTEL_SOF_WM8804_MACH) += snd-soc-sst-sof-wm8804.o -obj-$(CONFIG_SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH) += snd-soc-sst-glk-rt5682_max98357a.o -obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o +obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-bdw-rt286.o obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5650_MACH) += snd-soc-sst-bdw-rt5650-mach.o obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH) += snd-soc-sst-bdw-rt5677-mach.o obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH) += snd-soc-sst-bytcr-rt5651.o +obj-$(CONFIG_SND_SOC_INTEL_BYTCR_WM5102_MACH) += snd-soc-sst-bytcr-wm5102.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.o @@ -62,16 +48,26 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_CX2072X_MACH) += snd-soc-sst-byt-cht-cx2072x. obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH) += snd-soc-sst-byt-cht-da7213.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH) += snd-soc-sst-byt-cht-es8316.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) += snd-soc-sst-byt-cht-nocodec.o -obj-$(CONFIG_SND_SOC_INTEL_SOF_CML_RT1011_RT5682_MACH) += snd-soc-cml_rt1011_rt5682.o -obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH) += snd-soc-kbl_da7219_max98357a.o -obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH) += snd-soc-kbl_da7219_max98927.o -obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o -obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt5663_rt5514_max98927.o -obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5660_MACH) += snd-soc-kbl_rt5660.o -obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o -obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o -obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o obj-$(CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH) += snd-soc-skl_hda_dsp.o -obj-$(CONFIG_SND_SOC_INTEL_SOF_DA7219_MAX98373_MACH) += snd-soc-sof_da7219_max98373.o obj-$(CONFIG_SND_SOC_INTEL_EHL_RT5660_MACH) += snd-soc-ehl-rt5660.o obj-$(CONFIG_SND_SOC_INTEL_SOUNDWIRE_SOF_MACH) += snd-soc-sof-sdw.o +obj-$(CONFIG_SND_SOC_INTEL_SOF_SSP_AMP_MACH) += snd-soc-sof-ssp-amp.o + +# common modules +snd-soc-intel-hda-dsp-common-y := hda_dsp_common.o +obj-$(CONFIG_SND_SOC_INTEL_HDA_DSP_COMMON) += snd-soc-intel-hda-dsp-common.o + +snd-soc-intel-sof-maxim-common-y += sof_maxim_common.o +obj-$(CONFIG_SND_SOC_INTEL_SOF_MAXIM_COMMON) += snd-soc-intel-sof-maxim-common.o + +snd-soc-intel-sof-realtek-common-y += sof_realtek_common.o +obj-$(CONFIG_SND_SOC_INTEL_SOF_REALTEK_COMMON) += snd-soc-intel-sof-realtek-common.o + +snd-soc-intel-sof-cirrus-common-y += sof_cirrus_common.o +obj-$(CONFIG_SND_SOC_INTEL_SOF_CIRRUS_COMMON) += snd-soc-intel-sof-cirrus-common.o + +snd-soc-intel-sof-nuvoton-common-y += sof_nuvoton_common.o +obj-$(CONFIG_SND_SOC_INTEL_SOF_NUVOTON_COMMON) += snd-soc-intel-sof-nuvoton-common.o + +snd-soc-intel-sof-board-helpers-y += sof_board_helpers.o +obj-$(CONFIG_SND_SOC_INTEL_SOF_BOARD_HELPERS) += snd-soc-intel-sof-board-helpers.o diff --git a/sound/soc/intel/boards/bdw-rt5650.c b/sound/soc/intel/boards/bdw-rt5650.c index ce7320916b22..d25a7188f603 100644 --- a/sound/soc/intel/boards/bdw-rt5650.c +++ b/sound/soc/intel/boards/bdw-rt5650.c @@ -16,9 +16,6 @@ #include <sound/soc.h> #include <sound/soc-acpi.h> -#include "../common/sst-dsp.h" -#include "../haswell/sst-haswell-ipc.h" - #include "../../codecs/rt5645.h" struct bdw_rt5650_priv { @@ -87,14 +84,14 @@ static int broadwell_ssp0_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); - struct snd_interval *channels = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *chan = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); - /* The ADSP will covert the FE rate to 48k, max 4-channels */ + /* The ADSP will convert the FE rate to 48k, max 4-channels */ rate->min = rate->max = 48000; - channels->min = 2; - channels->max = 4; + chan->min = 2; + chan->max = 4; /* set SSP0 to 24 bit */ snd_mask_set_format(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), @@ -106,8 +103,8 @@ static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, static int bdw_rt5650_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); int ret; /* Workaround: set codec PLL to 19.2MHz that PLL source is @@ -134,34 +131,10 @@ static int bdw_rt5650_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops bdw_rt5650_ops = { +static const struct snd_soc_ops bdw_rt5650_ops = { .hw_params = bdw_rt5650_hw_params, }; -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) -static int bdw_rt5650_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); - struct sst_pdata *pdata = dev_get_platdata(component->dev); - struct sst_hsw *broadwell = pdata->dsp; - int ret; - - /* Set ADSP SSP port settings - * clock_divider = 4 means BCLK = MCLK/5 = 24MHz/5 = 4.8MHz - */ - ret = sst_hsw_device_set_config(broadwell, SST_HSW_DEVICE_SSP_0, - SST_HSW_DEVICE_MCLK_FREQ_24_MHZ, - SST_HSW_DEVICE_TDM_CLOCK_MASTER, 4); - if (ret < 0) { - dev_err(rtd->dev, "error: failed to set device config\n"); - return ret; - } - - return 0; -} -#endif - static const unsigned int channels[] = { 2, 4, }; @@ -194,7 +167,7 @@ static int bdw_rt5650_init(struct snd_soc_pcm_runtime *rtd) { struct bdw_rt5650_priv *bdw_rt5650 = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); struct snd_soc_component *component = codec_dai->component; int ret; @@ -219,15 +192,15 @@ static int bdw_rt5650_init(struct snd_soc_pcm_runtime *rtd) } /* Create and initialize headphone jack */ - if (snd_soc_card_jack_new(rtd->card, "Headphone Jack", + if (snd_soc_card_jack_new_pins(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE, &headphone_jack, &headphone_jack_pin, 1)) { dev_err(component->dev, "Can't create headphone jack\n"); } /* Create and initialize mic jack */ - if (snd_soc_card_jack_new(rtd->card, "Mic Jack", SND_JACK_MICROPHONE, - &mic_jack, &mic_jack_pin, 1)) { + if (snd_soc_card_jack_new_pins(rtd->card, "Mic Jack", + SND_JACK_MICROPHONE, &mic_jack, &mic_jack_pin, 1)) { dev_err(component->dev, "Can't create mic jack\n"); } @@ -251,27 +224,21 @@ SND_SOC_DAILINK_DEF(platform, SND_SOC_DAILINK_DEF(be, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5650:00", "rt5645-aif1"))); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) SND_SOC_DAILINK_DEF(ssp0_port, DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port"))); -#endif static struct snd_soc_dai_link bdw_rt5650_dais[] = { /* Front End DAI links */ { .name = "System PCM", .stream_name = "System Playback", + .nonatomic = 1, .dynamic = 1, .ops = &bdw_rt5650_fe_ops, -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) - .init = bdw_rt5650_rtd_init, -#endif .trigger = { SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST }, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(fe, dummy, platform), }, @@ -280,31 +247,24 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = { /* SSP0 - Codec */ .name = "Codec", .id = 0, + .nonatomic = 1, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, .be_hw_params_fixup = broadwell_ssp0_fixup, .ops = &bdw_rt5650_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, .init = bdw_rt5650_init, -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) - SND_SOC_DAILINK_REG(dummy, be, dummy), -#else SND_SOC_DAILINK_REG(ssp0_port, be, platform), -#endif }, }; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) /* use space before codec name to simplify card ID, and simplify driver name */ -#define CARD_NAME "bdw rt5650" /* card name will be 'sof-bdw rt5650' */ -#define DRIVER_NAME "SOF" -#else +#define SOF_CARD_NAME "bdw rt5650" /* card name will be 'sof-bdw rt5650' */ +#define SOF_DRIVER_NAME "SOF" + #define CARD_NAME "bdw-rt5650" #define DRIVER_NAME NULL /* card name will be used for driver name */ -#endif /* ASoC machine driver for Broadwell DSP + RT5650 */ static struct snd_soc_card bdw_rt5650_card = { @@ -336,7 +296,7 @@ static int bdw_rt5650_probe(struct platform_device *pdev) if (!bdw_rt5650) return -ENOMEM; - /* override plaform name, if required */ + /* override platform name, if required */ mach = pdev->dev.platform_data; ret = snd_soc_fixup_dai_links_platform_name(&bdw_rt5650_card, mach->mach_params.platform); @@ -344,6 +304,15 @@ static int bdw_rt5650_probe(struct platform_device *pdev) if (ret) return ret; + /* set card and driver name */ + if (snd_soc_acpi_sof_parent(&pdev->dev)) { + bdw_rt5650_card.name = SOF_CARD_NAME; + bdw_rt5650_card.driver_name = SOF_DRIVER_NAME; + } else { + bdw_rt5650_card.name = CARD_NAME; + bdw_rt5650_card.driver_name = DRIVER_NAME; + } + snd_soc_card_set_drvdata(&bdw_rt5650_card, bdw_rt5650); return devm_snd_soc_register_card(&pdev->dev, &bdw_rt5650_card); diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index 86e427e3822f..9484f3410787 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -17,9 +17,6 @@ #include <sound/jack.h> #include <sound/soc-acpi.h> -#include "../common/sst-dsp.h" -#include "../haswell/sst-haswell-ipc.h" - #include "../../codecs/rt5677.h" struct bdw_rt5677_priv { @@ -140,13 +137,13 @@ static int broadwell_ssp0_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); - struct snd_interval *channels = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *chan = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); - /* The ADSP will covert the FE rate to 48k, stereo */ + /* The ADSP will convert the FE rate to 48k, stereo */ rate->min = rate->max = 48000; - channels->min = channels->max = 2; + chan->min = chan->max = 2; /* set SSP0 to 16 bit */ params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); @@ -156,8 +153,8 @@ static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, static int bdw_rt5677_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); int ret; ret = snd_soc_dai_set_sysclk(codec_dai, RT5677_SCLK_S_MCLK, 24576000, @@ -173,8 +170,8 @@ static int bdw_rt5677_hw_params(struct snd_pcm_substream *substream, static int bdw_rt5677_dsp_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); int ret; ret = snd_soc_dai_set_sysclk(codec_dai, RT5677_SCLK_S_PLL1, 24576000, @@ -201,27 +198,6 @@ static const struct snd_soc_ops bdw_rt5677_dsp_ops = { .hw_params = bdw_rt5677_dsp_hw_params, }; -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) -static int bdw_rt5677_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); - struct sst_pdata *pdata = dev_get_platdata(component->dev); - struct sst_hsw *broadwell = pdata->dsp; - int ret; - - /* Set ADSP SSP port settings */ - ret = sst_hsw_device_set_config(broadwell, SST_HSW_DEVICE_SSP_0, - SST_HSW_DEVICE_MCLK_FREQ_24_MHZ, - SST_HSW_DEVICE_CLOCK_MASTER, 9); - if (ret < 0) { - dev_err(rtd->dev, "error: failed to set device config\n"); - return ret; - } - - return 0; -} -#endif - static const unsigned int channels[] = { 2, }; @@ -251,7 +227,7 @@ static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd) { struct bdw_rt5677_priv *bdw_rt5677 = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); int ret; @@ -280,7 +256,7 @@ static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd) } /* Create and initialize headphone jack */ - if (!snd_soc_card_jack_new(rtd->card, "Headphone Jack", + if (!snd_soc_card_jack_new_pins(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE, &headphone_jack, &headphone_jack_pin, 1)) { headphone_jack_gpio.gpiod_dev = component->dev; @@ -292,7 +268,7 @@ static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd) } /* Create and initialize mic jack */ - if (!snd_soc_card_jack_new(rtd->card, "Mic Jack", + if (!snd_soc_card_jack_new_pins(rtd->card, "Mic Jack", SND_JACK_MICROPHONE, &mic_jack, &mic_jack_pin, 1)) { mic_jack_gpio.gpiod_dev = component->dev; @@ -333,10 +309,8 @@ SND_SOC_DAILINK_DEF(platform, SND_SOC_DAILINK_DEF(be, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-RT5677CE:00", "rt5677-aif1"))); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) SND_SOC_DAILINK_DEF(ssp0_port, DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port"))); -#endif /* Wake on voice interface */ SND_SOC_DAILINK_DEFS(dsp, @@ -349,16 +323,12 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = { { .name = "System PCM", .stream_name = "System Playback/Capture", + .nonatomic = 1, .dynamic = 1, -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) - .init = bdw_rt5677_rtd_init, -#endif .trigger = { SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST }, - .dpcm_capture = 1, - .dpcm_playback = 1, .ops = &bdw_rt5677_fe_ops, SND_SOC_DAILINK_REG(fe, dummy, platform), }, @@ -377,21 +347,16 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = { /* SSP0 - Codec */ .name = "Codec", .id = 0, + .nonatomic = 1, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, .be_hw_params_fixup = broadwell_ssp0_fixup, .ops = &bdw_rt5677_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, .init = bdw_rt5677_init, .exit = bdw_rt5677_exit, -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) - SND_SOC_DAILINK_REG(dummy, be, dummy), -#else SND_SOC_DAILINK_REG(ssp0_port, be, platform), -#endif }, }; @@ -419,14 +384,12 @@ static int bdw_rt5677_resume_post(struct snd_soc_card *card) return 0; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) /* use space before codec name to simplify card ID, and simplify driver name */ -#define CARD_NAME "bdw rt5677" /* card name will be 'sof-bdw rt5677' */ -#define DRIVER_NAME "SOF" -#else +#define SOF_CARD_NAME "bdw rt5677" /* card name will be 'sof-bdw rt5677' */ +#define SOF_DRIVER_NAME "SOF" + #define CARD_NAME "bdw-rt5677" #define DRIVER_NAME NULL /* card name will be used for driver name */ -#endif /* ASoC machine driver for Broadwell DSP + RT5677 */ static struct snd_soc_card bdw_rt5677_card = { @@ -457,18 +420,25 @@ static int bdw_rt5677_probe(struct platform_device *pdev) /* Allocate driver private struct */ bdw_rt5677 = devm_kzalloc(&pdev->dev, sizeof(struct bdw_rt5677_priv), GFP_KERNEL); - if (!bdw_rt5677) { - dev_err(&pdev->dev, "Can't allocate bdw_rt5677\n"); + if (!bdw_rt5677) return -ENOMEM; - } - /* override plaform name, if required */ + /* override platform name, if required */ mach = pdev->dev.platform_data; ret = snd_soc_fixup_dai_links_platform_name(&bdw_rt5677_card, mach->mach_params.platform); if (ret) return ret; + /* set card and driver name */ + if (snd_soc_acpi_sof_parent(&pdev->dev)) { + bdw_rt5677_card.name = SOF_CARD_NAME; + bdw_rt5677_card.driver_name = SOF_DRIVER_NAME; + } else { + bdw_rt5677_card.name = CARD_NAME; + bdw_rt5677_card.driver_name = DRIVER_NAME; + } + snd_soc_card_set_drvdata(&bdw_rt5677_card, bdw_rt5677); return devm_snd_soc_register_card(&pdev->dev, &bdw_rt5677_card); @@ -478,6 +448,7 @@ static struct platform_driver bdw_rt5677_audio = { .probe = bdw_rt5677_probe, .driver = { .name = "bdw-rt5677", + .pm = &snd_soc_pm_ops }, }; diff --git a/sound/soc/intel/boards/bdw_rt286.c b/sound/soc/intel/boards/bdw_rt286.c new file mode 100644 index 000000000000..523ade9f31ab --- /dev/null +++ b/sound/soc/intel/boards/bdw_rt286.c @@ -0,0 +1,259 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Sound card driver for Intel Broadwell Wildcat Point with Realtek 286 + * + * Copyright (C) 2013, Intel Corporation + */ + +#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> +#include <sound/soc-acpi.h> +#include "../../codecs/rt286.h" + +static struct snd_soc_jack card_headset; + +static struct snd_soc_jack_pin card_headset_pins[] = { + { + .pin = "Mic Jack", + .mask = SND_JACK_MICROPHONE, + }, + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, +}; + +static const struct snd_kcontrol_new card_controls[] = { + SOC_DAPM_PIN_SWITCH("Speaker"), + SOC_DAPM_PIN_SWITCH("Headphone Jack"), +}; + +static const struct snd_soc_dapm_widget card_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_MIC("DMIC1", NULL), + SND_SOC_DAPM_MIC("DMIC2", NULL), + SND_SOC_DAPM_LINE("Line Jack", NULL), +}; + +static const struct snd_soc_dapm_route card_routes[] = { + {"Speaker", NULL, "SPOR"}, + {"Speaker", NULL, "SPOL"}, + + {"Headphone Jack", NULL, "HPO Pin"}, + + {"MIC1", NULL, "Mic Jack"}, + {"LINE1", NULL, "Line Jack"}, + + {"DMIC1 Pin", NULL, "DMIC1"}, + {"DMIC2 Pin", NULL, "DMIC2"}, + + /* CODEC BE connections */ + {"SSP0 CODEC IN", NULL, "AIF1 Capture"}, + {"AIF1 Playback", NULL, "SSP0 CODEC OUT"}, +}; + +static int codec_link_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *codec = snd_soc_rtd_to_codec(rtd, 0)->component; + int ret; + + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0, + &card_headset, card_headset_pins, + ARRAY_SIZE(card_headset_pins)); + if (ret) + return ret; + + return snd_soc_component_set_jack(codec, &card_headset, NULL); +} + +static void codec_link_exit(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *codec = snd_soc_rtd_to_codec(rtd, 0)->component; + + snd_soc_component_set_jack(codec, NULL, NULL); +} + +static int codec_link_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + + /* The ADSP will convert the FE rate to 48kHz, stereo. */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + /* Set SSP0 to 16 bit. */ + params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); + + return 0; +} + +static int codec_link_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + int ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(rtd->dev, "set codec sysclk failed: %d\n", ret); + return ret; + } + + return ret; +} + +static const struct snd_soc_ops codec_link_ops = { + .hw_params = codec_link_hw_params, +}; + +SND_SOC_DAILINK_DEF(system, DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); +SND_SOC_DAILINK_DEF(offload0, DAILINK_COMP_ARRAY(COMP_CPU("Offload0 Pin"))); +SND_SOC_DAILINK_DEF(offload1, DAILINK_COMP_ARRAY(COMP_CPU("Offload1 Pin"))); +SND_SOC_DAILINK_DEF(loopback, DAILINK_COMP_ARRAY(COMP_CPU("Loopback Pin"))); + +SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY())); +SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("haswell-pcm-audio"))); +SND_SOC_DAILINK_DEF(codec, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT343A:00", "rt286-aif1"))); +SND_SOC_DAILINK_DEF(ssp0_port, DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port"))); + +static struct snd_soc_dai_link card_dai_links[] = { + /* Front End DAI links */ + { + .name = "System PCM", + .stream_name = "System Playback/Capture", + .nonatomic = 1, + .dynamic = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + SND_SOC_DAILINK_REG(system, dummy, platform), + }, + { + .name = "Offload0", + .stream_name = "Offload0 Playback", + .nonatomic = 1, + .dynamic = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .playback_only = 1, + SND_SOC_DAILINK_REG(offload0, dummy, platform), + }, + { + .name = "Offload1", + .stream_name = "Offload1 Playback", + .nonatomic = 1, + .dynamic = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .playback_only = 1, + SND_SOC_DAILINK_REG(offload1, dummy, platform), + }, + { + .name = "Loopback PCM", + .stream_name = "Loopback", + .nonatomic = 1, + .dynamic = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .capture_only = 1, + SND_SOC_DAILINK_REG(loopback, dummy, platform), + }, + /* Back End DAI links */ + { + /* SSP0 - Codec */ + .name = "Codec", + .id = 0, + .nonatomic = 1, + .no_pcm = 1, + .init = codec_link_init, + .exit = codec_link_exit, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = codec_link_hw_params_fixup, + .ops = &codec_link_ops, + SND_SOC_DAILINK_REG(ssp0_port, codec, platform), + }, +}; + +static int card_suspend_pre(struct snd_soc_card *card) +{ + struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, "rt286-aif1"); + + if (!codec_dai) + return 0; + + return snd_soc_component_set_jack(codec_dai->component, NULL, NULL); +} + +static int card_resume_post(struct snd_soc_card *card) +{ + struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, "rt286-aif1"); + + if (!codec_dai) + return 0; + + return snd_soc_component_set_jack(codec_dai->component, &card_headset, NULL); +} + +static struct snd_soc_card bdw_rt286_card = { + .owner = THIS_MODULE, + .suspend_pre = card_suspend_pre, + .resume_post = card_resume_post, + .dai_link = card_dai_links, + .num_links = ARRAY_SIZE(card_dai_links), + .controls = card_controls, + .num_controls = ARRAY_SIZE(card_controls), + .dapm_widgets = card_widgets, + .num_dapm_widgets = ARRAY_SIZE(card_widgets), + .dapm_routes = card_routes, + .num_dapm_routes = ARRAY_SIZE(card_routes), + .fully_routed = true, +}; + +/* Use space before codec name to simplify card ID, and simplify driver name. */ +#define SOF_CARD_NAME "bdw rt286" /* card name will be 'sof-bdw rt286' */ +#define SOF_DRIVER_NAME "SOF" + +#define CARD_NAME "broadwell-rt286" + +static int bdw_rt286_probe(struct platform_device *pdev) +{ + struct snd_soc_acpi_mach *mach; + struct device *dev = &pdev->dev; + int ret; + + bdw_rt286_card.dev = dev; + mach = dev_get_platdata(dev); + + ret = snd_soc_fixup_dai_links_platform_name(&bdw_rt286_card, mach->mach_params.platform); + if (ret) + return ret; + + if (snd_soc_acpi_sof_parent(dev)) { + bdw_rt286_card.name = SOF_CARD_NAME; + bdw_rt286_card.driver_name = SOF_DRIVER_NAME; + } else { + bdw_rt286_card.name = CARD_NAME; + } + + return devm_snd_soc_register_card(dev, &bdw_rt286_card); +} + +static struct platform_driver bdw_rt286_driver = { + .probe = bdw_rt286_probe, + .driver = { + .name = "bdw_rt286", + .pm = &snd_soc_pm_ops + }, +}; + +module_platform_driver(bdw_rt286_driver) + +MODULE_AUTHOR("Liam Girdwood, Xingchao Wang"); +MODULE_DESCRIPTION("Sound card driver for Intel Broadwell Wildcat Point with Realtek 286"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:bdw_rt286"); diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c deleted file mode 100644 index f6399077d291..000000000000 --- a/sound/soc/intel/boards/broadwell.c +++ /dev/null @@ -1,359 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Broadwell Wildcatpoint SST Audio - * - * Copyright (C) 2013, Intel Corporation. All rights reserved. - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/jack.h> -#include <sound/pcm_params.h> -#include <sound/soc-acpi.h> - -#include "../common/sst-dsp.h" -#include "../haswell/sst-haswell-ipc.h" - -#include "../../codecs/rt286.h" - -static struct snd_soc_jack broadwell_headset; -/* Headset jack detection DAPM pins */ -static struct snd_soc_jack_pin broadwell_headset_pins[] = { - { - .pin = "Mic Jack", - .mask = SND_JACK_MICROPHONE, - }, - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, -}; - -static const struct snd_kcontrol_new broadwell_controls[] = { - SOC_DAPM_PIN_SWITCH("Speaker"), - SOC_DAPM_PIN_SWITCH("Headphone Jack"), -}; - -static const struct snd_soc_dapm_widget broadwell_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_SPK("Speaker", NULL), - SND_SOC_DAPM_MIC("Mic Jack", NULL), - SND_SOC_DAPM_MIC("DMIC1", NULL), - SND_SOC_DAPM_MIC("DMIC2", NULL), - SND_SOC_DAPM_LINE("Line Jack", NULL), -}; - -static const struct snd_soc_dapm_route broadwell_rt286_map[] = { - - /* speaker */ - {"Speaker", NULL, "SPOR"}, - {"Speaker", NULL, "SPOL"}, - - /* HP jack connectors - unknown if we have jack deteck */ - {"Headphone Jack", NULL, "HPO Pin"}, - - /* other jacks */ - {"MIC1", NULL, "Mic Jack"}, - {"LINE1", NULL, "Line Jack"}, - - /* digital mics */ - {"DMIC1 Pin", NULL, "DMIC1"}, - {"DMIC2 Pin", NULL, "DMIC2"}, - - /* CODEC BE connections */ - {"SSP0 CODEC IN", NULL, "AIF1 Capture"}, - {"AIF1 Playback", NULL, "SSP0 CODEC OUT"}, -}; - -static int broadwell_rt286_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; - int ret = 0; - ret = snd_soc_card_jack_new(rtd->card, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0, &broadwell_headset, - broadwell_headset_pins, ARRAY_SIZE(broadwell_headset_pins)); - if (ret) - return ret; - - rt286_mic_detect(component, &broadwell_headset); - return 0; -} - - -static int broadwell_ssp0_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); - struct snd_interval *channels = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - - /* The ADSP will covert the FE rate to 48k, stereo */ - rate->min = rate->max = 48000; - channels->min = channels->max = 2; - - /* set SSP0 to 16 bit */ - params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); - return 0; -} - -static int broadwell_rt286_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - int ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000, - SND_SOC_CLOCK_IN); - - if (ret < 0) { - dev_err(rtd->dev, "can't set codec sysclk configuration\n"); - return ret; - } - - return ret; -} - -static const struct snd_soc_ops broadwell_rt286_ops = { - .hw_params = broadwell_rt286_hw_params, -}; - -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) -static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); - struct sst_pdata *pdata = dev_get_platdata(component->dev); - struct sst_hsw *broadwell = pdata->dsp; - int ret; - - /* Set ADSP SSP port settings */ - ret = sst_hsw_device_set_config(broadwell, SST_HSW_DEVICE_SSP_0, - SST_HSW_DEVICE_MCLK_FREQ_24_MHZ, - SST_HSW_DEVICE_CLOCK_MASTER, 9); - if (ret < 0) { - dev_err(rtd->dev, "error: failed to set device config\n"); - return ret; - } - - return 0; -} -#endif - -static const unsigned int channels[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static int broadwell_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* Board supports stereo configuration only */ - runtime->hw.channels_max = 2; - return snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); -} - -static const struct snd_soc_ops broadwell_fe_ops = { - .startup = broadwell_fe_startup, -}; - -SND_SOC_DAILINK_DEF(system, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); - -SND_SOC_DAILINK_DEF(offload0, - DAILINK_COMP_ARRAY(COMP_CPU("Offload0 Pin"))); - -SND_SOC_DAILINK_DEF(offload1, - DAILINK_COMP_ARRAY(COMP_CPU("Offload1 Pin"))); - -SND_SOC_DAILINK_DEF(loopback, - DAILINK_COMP_ARRAY(COMP_CPU("Loopback Pin"))); - -SND_SOC_DAILINK_DEF(dummy, - DAILINK_COMP_ARRAY(COMP_DUMMY())); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("haswell-pcm-audio"))); - -SND_SOC_DAILINK_DEF(codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT343A:00", "rt286-aif1"))); - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) -SND_SOC_DAILINK_DEF(ssp0_port, - DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port"))); -#endif - -/* broadwell digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link broadwell_rt286_dais[] = { - /* Front End DAI links */ - { - .name = "System PCM", - .stream_name = "System Playback/Capture", - .dynamic = 1, -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) - .init = broadwell_rtd_init, -#endif - .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .ops = &broadwell_fe_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - { - .name = "Offload0", - .stream_name = "Offload0 Playback", - .dynamic = 1, - .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - SND_SOC_DAILINK_REG(offload0, dummy, platform), - }, - { - .name = "Offload1", - .stream_name = "Offload1 Playback", - .dynamic = 1, - .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - SND_SOC_DAILINK_REG(offload1, dummy, platform), - }, - { - .name = "Loopback PCM", - .stream_name = "Loopback", - .dynamic = 1, - .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(loopback, dummy, platform), - }, - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "Codec", - .id = 0, - .no_pcm = 1, - .init = broadwell_rt286_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 = broadwell_ssp0_fixup, - .ops = &broadwell_rt286_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) - SND_SOC_DAILINK_REG(dummy, codec, dummy), -#else - SND_SOC_DAILINK_REG(ssp0_port, codec, platform), -#endif - }, -}; - -static int broadwell_disable_jack(struct snd_soc_card *card) -{ - struct snd_soc_component *component; - - for_each_card_components(card, component) { - if (!strcmp(component->name, "i2c-INT343A:00")) { - - dev_dbg(component->dev, "disabling jack detect before going to suspend.\n"); - rt286_mic_detect(component, NULL); - break; - } - } - - return 0; -} - -static int broadwell_suspend(struct snd_soc_card *card) -{ - return broadwell_disable_jack(card); -} - -static int broadwell_resume(struct snd_soc_card *card){ - struct snd_soc_component *component; - - for_each_card_components(card, component) { - if (!strcmp(component->name, "i2c-INT343A:00")) { - - dev_dbg(component->dev, "enabling jack detect for resume.\n"); - rt286_mic_detect(component, &broadwell_headset); - break; - } - } - return 0; -} - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) -/* use space before codec name to simplify card ID, and simplify driver name */ -#define CARD_NAME "bdw rt286" /* card name will be 'sof-bdw rt286' */ -#define DRIVER_NAME "SOF" -#else -#define CARD_NAME "broadwell-rt286" -#define DRIVER_NAME NULL /* card name will be used for driver name */ -#endif - -/* broadwell audio machine driver for WPT + RT286S */ -static struct snd_soc_card broadwell_rt286 = { - .name = CARD_NAME, - .driver_name = DRIVER_NAME, - .owner = THIS_MODULE, - .dai_link = broadwell_rt286_dais, - .num_links = ARRAY_SIZE(broadwell_rt286_dais), - .controls = broadwell_controls, - .num_controls = ARRAY_SIZE(broadwell_controls), - .dapm_widgets = broadwell_widgets, - .num_dapm_widgets = ARRAY_SIZE(broadwell_widgets), - .dapm_routes = broadwell_rt286_map, - .num_dapm_routes = ARRAY_SIZE(broadwell_rt286_map), - .fully_routed = true, - .suspend_pre = broadwell_suspend, - .resume_post = broadwell_resume, -}; - -static int broadwell_audio_probe(struct platform_device *pdev) -{ - struct snd_soc_acpi_mach *mach; - int ret; - - broadwell_rt286.dev = &pdev->dev; - - /* override plaform name, if required */ - mach = pdev->dev.platform_data; - ret = snd_soc_fixup_dai_links_platform_name(&broadwell_rt286, - mach->mach_params.platform); - if (ret) - return ret; - - return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286); -} - -static int broadwell_audio_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - - return broadwell_disable_jack(card); -} - -static struct platform_driver broadwell_audio = { - .probe = broadwell_audio_probe, - .remove = broadwell_audio_remove, - .driver = { - .name = "broadwell-audio", - }, -}; - -module_platform_driver(broadwell_audio) - -/* Module information */ -MODULE_AUTHOR("Liam Girdwood, Xingchao Wang"); -MODULE_DESCRIPTION("Intel SST Audio for WPT/Broadwell"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:broadwell-audio"); diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c deleted file mode 100644 index 0c0a717823c4..000000000000 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ /dev/null @@ -1,870 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Broxton-P I2S Machine Driver - * - * Copyright (C) 2016, Intel Corporation. All rights reserved. - * - * Modified from: - * Intel Skylake I2S Machine driver - */ - -#include <linux/input.h> -#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> -#include <sound/soc-acpi.h> -#include "../../codecs/hdac_hdmi.h" -#include "../../codecs/da7219.h" -#include "../../codecs/da7219-aad.h" -#include "../common/soc-intel-quirks.h" -#include "hda_dsp_common.h" - -#define BXT_DIALOG_CODEC_DAI "da7219-hifi" -#define BXT_MAXIM_CODEC_DAI "HiFi" -#define MAX98390_DEV0_NAME "i2c-MX98390:00" -#define MAX98390_DEV1_NAME "i2c-MX98390:01" -#define DUAL_CHANNEL 2 -#define QUAD_CHANNEL 4 - -#define SPKAMP_MAX98357A 1 -#define SPKAMP_MAX98390 2 - -static struct snd_soc_jack broxton_headset; -static struct snd_soc_jack broxton_hdmi[3]; - -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; - bool common_hdmi_codec_drv; - int spkamp; -}; - -enum { - BXT_DPCM_AUDIO_PB = 0, - BXT_DPCM_AUDIO_CP, - BXT_DPCM_AUDIO_HS_PB, - BXT_DPCM_AUDIO_REF_CP, - BXT_DPCM_AUDIO_DMIC_CP, - BXT_DPCM_AUDIO_HDMI1_PB, - BXT_DPCM_AUDIO_HDMI2_PB, - BXT_DPCM_AUDIO_HDMI3_PB, -}; - -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; - - codec_dai = snd_soc_card_get_codec_dai(card, BXT_DIALOG_CODEC_DAI); - 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; -} - -static const struct snd_kcontrol_new broxton_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), -}; - -static const struct snd_kcontrol_new max98357a_controls[] = { - SOC_DAPM_PIN_SWITCH("Spk"), -}; - -static const struct snd_kcontrol_new max98390_controls[] = { - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), -}; - -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), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_POST_PMD|SND_SOC_DAPM_PRE_PMU), -}; - -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), -}; - -static const struct snd_soc_dapm_route audio_map[] = { - /* 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 */ - {"HDMI1", NULL, "hif5-0 Output"}, - {"HDMI2", NULL, "hif6-0 Output"}, - {"HDMI2", NULL, "hif7-0 Output"}, - - {"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"}, - - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headset Mic", NULL, "Platform Clock" }, -}; - -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"}, -}; - -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"}, -}; - -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); - struct snd_interval *chan = hw_param_interval(params, - 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; - chan->min = chan->max = DUAL_CHANNEL; - - /* set SSP to 24 bit */ - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - - return 0; -} - -static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; - int clk_freq; - - /* Configure sysclk for codec */ - 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, - SND_SOC_CLOCK_IN); - - if (ret) { - dev_err(rtd->dev, "can't set codec sysclk configuration\n"); - return ret; - } - - /* - * 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 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, - &broxton_headset, NULL, 0); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); - return ret; - } - - 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); - - da7219_aad_jack_det(component, &broxton_headset); - - snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - - return ret; -} - -static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd) -{ - struct bxt_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); - struct bxt_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = BXT_DPCM_AUDIO_HDMI1_PB + dai->id; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int broxton_da7219_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = asoc_rtd_to_cpu(rtd, 0)->component; - - dapm = snd_soc_component_get_dapm(component); - snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - - return 0; -} - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static const unsigned int channels[] = { - DUAL_CHANNEL, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static const unsigned int channels_quad[] = { - QUAD_CHANNEL, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels_quad = { - .count = ARRAY_SIZE(channels_quad), - .list = channels_quad, - .mask = 0, -}; - -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, - * 48Khz - * 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, -}; - -static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - if (params_channels(params) == 2) - chan->min = chan->max = 2; - else - chan->min = chan->max = 4; - - return 0; -} - -static int broxton_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels_quad); - - 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, -}; - -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, -}; - -static int broxton_refcap_startup(struct snd_pcm_substream *substream) -{ - substream->runtime->hw.channels_max = 1; - snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_refcap); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_16000); -}; - -static const struct snd_soc_ops broxton_refcap_ops = { - .startup = broxton_refcap_startup, -}; - -/* broxton digital audio interface glue - connects codec <--> CPU */ -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))); -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"))); - -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"))); - -SND_SOC_DAILINK_DEF(dmic16k_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin"))); - -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"))); - -static struct snd_soc_dai_link broxton_dais[] = { - /* Front End DAI links */ - [BXT_DPCM_AUDIO_PB] = - { - .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, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [BXT_DPCM_AUDIO_CP] = - { - .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, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [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, - SND_SOC_DAILINK_REG(system2, dummy, platform), - }, - [BXT_DPCM_AUDIO_REF_CP] = - { - .name = "Bxt Audio Reference cap", - .stream_name = "Refcap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &broxton_refcap_ops, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [BXT_DPCM_AUDIO_DMIC_CP] = - { - .name = "Bxt Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &broxton_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [BXT_DPCM_AUDIO_HDMI1_PB] = - { - .name = "Bxt HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [BXT_DPCM_AUDIO_HDMI2_PB] = - { - .name = "Bxt HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [BXT_DPCM_AUDIO_HDMI3_PB] = - { - .name = "Bxt HDMI Port3", - .stream_name = "Hdmi3", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - /* 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, - SND_SOC_DAILINK_REG(ssp5_pin, ssp5_codec, platform), - }, - { - /* 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, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - .name = "dmic01", - .id = 2, - .ignore_suspend = 1, - .be_hw_params_fixup = broxton_dmic_fixup, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .init = broxton_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = broxton_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = broxton_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, - { - .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), - }, -}; - -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", - }, -}; - -#define NAME_SIZE 32 -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; - struct snd_soc_component *component = NULL; - 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; - char jack_name[NAME_SIZE]; - - 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); - return -EINVAL; - } - - 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; - } - - if (soc_intel_is_glk()) - 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)); - - if (list_empty(&ctx->hdmi_pcm_list)) - return -EINVAL; - - if (ctx->common_hdmi_codec_drv) { - pcm = list_first_entry(&ctx->hdmi_pcm_list, struct bxt_hdmi_pcm, - head); - component = pcm->codec_dai->component; - return hda_dsp_hdmi_build_controls(card, component); - } - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - 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]); - if (err < 0) - return err; - - i++; - } - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* 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), - .dapm_routes = audio_map, - .num_dapm_routes = ARRAY_SIZE(audio_map), - .fully_routed = true, - .late_probe = bxt_card_late_probe, -}; - -static int broxton_audio_probe(struct platform_device *pdev) -{ - struct bxt_card_private *ctx; - struct snd_soc_acpi_mach *mach; - const char *platform_name; - int ret; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - if (acpi_dev_present("MX98390", NULL, -1)) - ctx->spkamp = SPKAMP_MAX98390; - else - ctx->spkamp = SPKAMP_MAX98357A; - - broxton_audio_card.dev = &pdev->dev; - snd_soc_card_set_drvdata(&broxton_audio_card, ctx); - if (soc_intel_is_glk()) { - 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. */ - 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"; - } - /* DIALOG_CODE is connected to SSP2 */ - else if (!strcmp(broxton_dais[i].codecs->dai_name, - BXT_DIALOG_CODEC_DAI)) { - broxton_dais[i].name = "SSP2-Codec"; - broxton_dais[i].cpus->dai_name = "SSP2 Pin"; - } - } - } else if (soc_intel_is_cml()) { - unsigned int i; - - 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"; - - 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"; - - if (ctx->spkamp == SPKAMP_MAX98390) { - broxton_dais[i].codecs = max98390_codec; - broxton_dais[i].num_codecs = ARRAY_SIZE(max98390_codec); - } - } - /* 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"; - } - } - } - - /* override plaform name, if required */ - mach = pdev->dev.platform_data; - platform_name = mach->mach_params.platform; - - ret = snd_soc_fixup_dai_links_platform_name(&broxton_audio_card, - platform_name); - if (ret) - return ret; - - ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; - - return devm_snd_soc_register_card(&pdev->dev, &broxton_audio_card); -} - -static const struct platform_device_id bxt_board_ids[] = { - { .name = "bxt_da7219_max98357a" }, - { .name = "glk_da7219_max98357a" }, - { .name = "cml_da7219_max98357a" }, - { } -}; - -static struct platform_driver broxton_audio = { - .probe = broxton_audio_probe, - .driver = { - .name = "bxt_da7219_max98357a", - .pm = &snd_soc_pm_ops, - }, - .id_table = bxt_board_ids, -}; -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>"); -MODULE_AUTHOR("Naveen Manohar <naveen.m@intel.com>"); -MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>"); -MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:bxt_da7219_max98357a"); -MODULE_ALIAS("platform:glk_da7219_max98357a"); -MODULE_ALIAS("platform:cml_da7219_max98357a"); diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c deleted file mode 100644 index 0f3157dfa838..000000000000 --- a/sound/soc/intel/boards/bxt_rt298.c +++ /dev/null @@ -1,669 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Broxton-P I2S Machine Driver - * - * Copyright (C) 2014-2016, Intel Corporation. All rights reserved. - * - * Modified from: - * Intel Skylake I2S Machine driver - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include <sound/jack.h> -#include <sound/pcm_params.h> -#include "../../codecs/hdac_hdmi.h" -#include "../../codecs/rt298.h" -#include "hda_dsp_common.h" - -/* Headset jack detection DAPM pins */ -static struct snd_soc_jack broxton_headset; -static struct snd_soc_jack broxton_hdmi[3]; - -struct bxt_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct bxt_rt286_private { - struct list_head hdmi_pcm_list; - bool common_hdmi_codec_drv; -}; - -enum { - BXT_DPCM_AUDIO_PB = 0, - BXT_DPCM_AUDIO_CP, - BXT_DPCM_AUDIO_REF_CP, - BXT_DPCM_AUDIO_DMIC_CP, - BXT_DPCM_AUDIO_HDMI1_PB, - BXT_DPCM_AUDIO_HDMI2_PB, - BXT_DPCM_AUDIO_HDMI3_PB, -}; - -static struct snd_soc_jack_pin broxton_headset_pins[] = { - { - .pin = "Mic Jack", - .mask = SND_JACK_MICROPHONE, - }, - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, -}; - -static const struct snd_kcontrol_new broxton_controls[] = { - SOC_DAPM_PIN_SWITCH("Speaker"), - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Mic Jack"), -}; - -static const struct snd_soc_dapm_widget broxton_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_SPK("Speaker", NULL), - SND_SOC_DAPM_MIC("Mic Jack", NULL), - SND_SOC_DAPM_MIC("DMIC2", 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), -}; - -static const struct snd_soc_dapm_route broxton_rt298_map[] = { - /* speaker */ - {"Speaker", NULL, "SPOR"}, - {"Speaker", NULL, "SPOL"}, - - /* HP jack connectors - unknown if we have jack detect */ - {"Headphone Jack", NULL, "HPO Pin"}, - - /* other jacks */ - {"MIC1", NULL, "Mic Jack"}, - - /* digital mics */ - {"DMIC1 Pin", NULL, "DMIC2"}, - {"DMic", NULL, "SoC DMIC"}, - - {"HDMI1", NULL, "hif5-0 Output"}, - {"HDMI2", NULL, "hif6-0 Output"}, - {"HDMI2", NULL, "hif7-0 Output"}, - - /* CODEC BE connections */ - { "AIF1 Playback", NULL, "ssp5 Tx"}, - { "ssp5 Tx", NULL, "codec0_out"}, - { "ssp5 Tx", NULL, "codec1_out"}, - - { "codec0_in", NULL, "ssp5 Rx" }, - { "ssp5 Rx", NULL, "AIF1 Capture" }, - - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "Capture" }, - - { "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"}, -}; - -static const struct snd_soc_dapm_route geminilake_rt298_map[] = { - /* speaker */ - {"Speaker", NULL, "SPOR"}, - {"Speaker", NULL, "SPOL"}, - - /* HP jack connectors - unknown if we have jack detect */ - {"Headphone Jack", NULL, "HPO Pin"}, - - /* other jacks */ - {"MIC1", NULL, "Mic Jack"}, - - /* digital mics */ - {"DMIC1 Pin", NULL, "DMIC2"}, - {"DMic", NULL, "SoC DMIC"}, - - {"HDMI1", NULL, "hif5-0 Output"}, - {"HDMI2", NULL, "hif6-0 Output"}, - {"HDMI2", NULL, "hif7-0 Output"}, - - /* CODEC BE connections */ - { "AIF1 Playback", NULL, "ssp2 Tx"}, - { "ssp2 Tx", NULL, "codec0_out"}, - { "ssp2 Tx", NULL, "codec1_out"}, - - { "codec0_in", NULL, "ssp2 Rx" }, - { "ssp2 Rx", NULL, "AIF1 Capture" }, - - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "Capture" }, - - { "dmic_voice", NULL, "DMIC16k Rx" }, - { "DMIC16k Rx", NULL, "Capture" }, - - { "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"}, -}; - -static int broxton_rt298_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = asoc_rtd_to_cpu(rtd, 0)->component; - - dapm = snd_soc_component_get_dapm(component); - snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - - return 0; -} - -static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; - int ret = 0; - - ret = snd_soc_card_jack_new(rtd->card, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0, - &broxton_headset, - broxton_headset_pins, ARRAY_SIZE(broxton_headset_pins)); - - if (ret) - return ret; - - rt298_mic_detect(component, &broxton_headset); - - snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - - return 0; -} - -static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd) -{ - struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); - struct bxt_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = BXT_DPCM_AUDIO_HDMI1_PB + dai->id; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int broxton_ssp5_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); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - - /* The ADSP will covert the FE rate to 48k, stereo */ - rate->min = rate->max = 48000; - chan->min = chan->max = 2; - - /* set SSP5 to 24 bit */ - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - - return 0; -} - -static int broxton_rt298_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - int ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, RT298_SCLK_S_PLL, - 19200000, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(rtd->dev, "can't set codec sysclk configuration\n"); - return ret; - } - - return ret; -} - -static const struct snd_soc_ops broxton_rt298_ops = { - .hw_params = broxton_rt298_hw_params, -}; - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - chan->min = chan->max = 4; - - return 0; -} - -static const unsigned int channels_dmic[] = { - 1, 2, 3, 4, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { - .count = ARRAY_SIZE(channels_dmic), - .list = channels_dmic, - .mask = 0, -}; - -static int broxton_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_max = 4; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_dmic_channels); - - 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 channels[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -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: - * 48Khz - * stereo - * 16-bit audio - */ - - runtime->hw.channels_max = 2; - 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_rt286_fe_ops = { - .startup = bxt_fe_startup, -}; - -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(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"))); - -SND_SOC_DAILINK_DEF(ssp5_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP5 Pin"))); -SND_SOC_DAILINK_DEF(ssp5_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT343A:00", - "rt298-aif1"))); - -SND_SOC_DAILINK_DEF(dmic_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); - -SND_SOC_DAILINK_DEF(dmic_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", - "dmic-hifi"))); - -SND_SOC_DAILINK_DEF(dmic16k, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin"))); - -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"))); - -/* broxton digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link broxton_rt298_dais[] = { - /* Front End DAI links */ - [BXT_DPCM_AUDIO_PB] = - { - .name = "Bxt Audio Port", - .stream_name = "Audio", - .nonatomic = 1, - .dynamic = 1, - .init = broxton_rt298_fe_init, - .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &broxton_rt286_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [BXT_DPCM_AUDIO_CP] = - { - .name = "Bxt Audio Capture Port", - .stream_name = "Audio Record", - .nonatomic = 1, - .dynamic = 1, - .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - .ops = &broxton_rt286_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [BXT_DPCM_AUDIO_REF_CP] = - { - .name = "Bxt Audio Reference cap", - .stream_name = "refcap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [BXT_DPCM_AUDIO_DMIC_CP] = - { - .name = "Bxt Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &broxton_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [BXT_DPCM_AUDIO_HDMI1_PB] = - { - .name = "Bxt HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [BXT_DPCM_AUDIO_HDMI2_PB] = - { - .name = "Bxt HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [BXT_DPCM_AUDIO_HDMI3_PB] = - { - .name = "Bxt HDMI Port3", - .stream_name = "Hdmi3", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - /* Back End DAI links */ - { - /* SSP5 - Codec */ - .name = "SSP5-Codec", - .id = 0, - .no_pcm = 1, - .init = broxton_rt298_codec_init, - .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = broxton_ssp5_fixup, - .ops = &broxton_rt298_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp5_pin, ssp5_codec, platform), - }, - { - .name = "dmic01", - .id = 1, - .be_hw_params_fixup = broxton_dmic_fixup, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "dmic16k", - .id = 2, - .be_hw_params_fixup = broxton_dmic_fixup, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic16k, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .init = broxton_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = broxton_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = broxton_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -#define NAME_SIZE 32 -static int bxt_card_late_probe(struct snd_soc_card *card) -{ - struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(card); - struct bxt_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - if (list_empty(&ctx->hdmi_pcm_list)) - return -EINVAL; - - if (ctx->common_hdmi_codec_drv) { - pcm = list_first_entry(&ctx->hdmi_pcm_list, struct bxt_hdmi_pcm, - head); - component = pcm->codec_dai->component; - return hda_dsp_hdmi_build_controls(card, component); - } - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - 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]); - if (err < 0) - return err; - - i++; - } - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - - -/* broxton audio machine driver for SPT + RT298S */ -static struct snd_soc_card broxton_rt298 = { - .name = "broxton-rt298", - .owner = THIS_MODULE, - .dai_link = broxton_rt298_dais, - .num_links = ARRAY_SIZE(broxton_rt298_dais), - .controls = broxton_controls, - .num_controls = ARRAY_SIZE(broxton_controls), - .dapm_widgets = broxton_widgets, - .num_dapm_widgets = ARRAY_SIZE(broxton_widgets), - .dapm_routes = broxton_rt298_map, - .num_dapm_routes = ARRAY_SIZE(broxton_rt298_map), - .fully_routed = true, - .late_probe = bxt_card_late_probe, - -}; - -static struct snd_soc_card geminilake_rt298 = { - .name = "geminilake-rt298", - .owner = THIS_MODULE, - .dai_link = broxton_rt298_dais, - .num_links = ARRAY_SIZE(broxton_rt298_dais), - .controls = broxton_controls, - .num_controls = ARRAY_SIZE(broxton_controls), - .dapm_widgets = broxton_widgets, - .num_dapm_widgets = ARRAY_SIZE(broxton_widgets), - .dapm_routes = geminilake_rt298_map, - .num_dapm_routes = ARRAY_SIZE(geminilake_rt298_map), - .fully_routed = true, - .late_probe = bxt_card_late_probe, -}; - -static int broxton_audio_probe(struct platform_device *pdev) -{ - struct bxt_rt286_private *ctx; - struct snd_soc_card *card = - (struct snd_soc_card *)pdev->id_entry->driver_data; - struct snd_soc_acpi_mach *mach; - const char *platform_name; - int ret; - int i; - - for (i = 0; i < ARRAY_SIZE(broxton_rt298_dais); i++) { - if (!strncmp(card->dai_link[i].codecs->name, "i2c-INT343A:00", - I2C_NAME_SIZE)) { - if (!strncmp(card->name, "broxton-rt298", - PLATFORM_NAME_SIZE)) { - card->dai_link[i].name = "SSP5-Codec"; - card->dai_link[i].cpus->dai_name = "SSP5 Pin"; - } else if (!strncmp(card->name, "geminilake-rt298", - PLATFORM_NAME_SIZE)) { - card->dai_link[i].name = "SSP2-Codec"; - card->dai_link[i].cpus->dai_name = "SSP2 Pin"; - } - } - } - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - card->dev = &pdev->dev; - snd_soc_card_set_drvdata(card, ctx); - - /* override plaform name, if required */ - mach = pdev->dev.platform_data; - platform_name = mach->mach_params.platform; - - ret = snd_soc_fixup_dai_links_platform_name(card, - platform_name); - if (ret) - return ret; - - ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; - - return devm_snd_soc_register_card(&pdev->dev, card); -} - -static const struct platform_device_id bxt_board_ids[] = { - { .name = "bxt_alc298s_i2s", .driver_data = - (unsigned long)&broxton_rt298 }, - { .name = "glk_alc298s_i2s", .driver_data = - (unsigned long)&geminilake_rt298 }, - {} -}; - -static struct platform_driver broxton_audio = { - .probe = broxton_audio_probe, - .driver = { - .name = "bxt_alc298s_i2s", - .pm = &snd_soc_pm_ops, - }, - .id_table = bxt_board_ids, -}; -module_platform_driver(broxton_audio) - -/* Module information */ -MODULE_AUTHOR("Ramesh Babu <Ramesh.Babu@intel.com>"); -MODULE_AUTHOR("Senthilnathan Veppur <senthilnathanx.veppur@intel.com>"); -MODULE_DESCRIPTION("Intel SST Audio for Broxton"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:bxt_alc298s_i2s"); -MODULE_ALIAS("platform:glk_alc298s_i2s"); diff --git a/sound/soc/intel/boards/byt-max98090.c b/sound/soc/intel/boards/byt-max98090.c deleted file mode 100644 index f5097da28828..000000000000 --- a/sound/soc/intel/boards/byt-max98090.c +++ /dev/null @@ -1,182 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Baytrail SST MAX98090 machine driver - * Copyright (c) 2014, Intel Corporation. - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/acpi.h> -#include <linux/device.h> -#include <linux/gpio.h> -#include <linux/gpio/consumer.h> -#include <linux/slab.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/jack.h> -#include "../../codecs/max98090.h" - -struct byt_max98090_private { - struct snd_soc_jack jack; -}; - -static const struct snd_soc_dapm_widget byt_max98090_widgets[] = { - SND_SOC_DAPM_HP("Headphone", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_MIC("Int Mic", NULL), - SND_SOC_DAPM_SPK("Ext Spk", NULL), -}; - -static const struct snd_soc_dapm_route byt_max98090_audio_map[] = { - {"IN34", NULL, "Headset Mic"}, - {"Headset Mic", NULL, "MICBIAS"}, - {"DMICL", NULL, "Int Mic"}, - {"Headphone", NULL, "HPL"}, - {"Headphone", NULL, "HPR"}, - {"Ext Spk", NULL, "SPKL"}, - {"Ext Spk", NULL, "SPKR"}, -}; - -static const struct snd_kcontrol_new byt_max98090_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Int Mic"), - SOC_DAPM_PIN_SWITCH("Ext Spk"), -}; - -static struct snd_soc_jack_pin hs_jack_pins[] = { - { - .pin = "Headphone", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static struct snd_soc_jack_gpio hs_jack_gpios[] = { - { - .name = "hp", - .report = SND_JACK_HEADPHONE | SND_JACK_LINEOUT, - .debounce_time = 200, - }, - { - .name = "mic", - .invert = 1, - .report = SND_JACK_MICROPHONE, - .debounce_time = 200, - }, -}; - -static const struct acpi_gpio_params hp_gpios = { 0, 0, false }; -static const struct acpi_gpio_params mic_gpios = { 1, 0, false }; - -static const struct acpi_gpio_mapping acpi_byt_max98090_gpios[] = { - { "hp-gpios", &hp_gpios, 1 }, - { "mic-gpios", &mic_gpios, 1 }, - {}, -}; - -static int byt_max98090_init(struct snd_soc_pcm_runtime *runtime) -{ - int ret; - struct snd_soc_card *card = runtime->card; - struct byt_max98090_private *drv = snd_soc_card_get_drvdata(card); - struct snd_soc_jack *jack = &drv->jack; - - card->dapm.idle_bias_off = true; - - ret = snd_soc_dai_set_sysclk(asoc_rtd_to_codec(runtime, 0), - M98090_REG_SYSTEM_CLOCK, - 25000000, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(card->dev, "Can't set codec clock %d\n", ret); - return ret; - } - - /* Enable jack detection */ - ret = snd_soc_card_jack_new(runtime->card, "Headset", - SND_JACK_LINEOUT | SND_JACK_HEADSET, jack, - hs_jack_pins, ARRAY_SIZE(hs_jack_pins)); - if (ret) - return ret; - - return snd_soc_jack_add_gpiods(card->dev->parent, jack, - ARRAY_SIZE(hs_jack_gpios), - hs_jack_gpios); -} - -SND_SOC_DAILINK_DEFS(baytrail, - DAILINK_COMP_ARRAY(COMP_CPU("baytrail-pcm-audio")), - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-193C9890:00", "HiFi")), - DAILINK_COMP_ARRAY(COMP_PLATFORM("baytrail-pcm-audio"))); - -static struct snd_soc_dai_link byt_max98090_dais[] = { - { - .name = "Baytrail Audio", - .stream_name = "Audio", - .init = byt_max98090_init, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, - SND_SOC_DAILINK_REG(baytrail), - }, -}; - -static struct snd_soc_card byt_max98090_card = { - .name = "byt-max98090", - .owner = THIS_MODULE, - .dai_link = byt_max98090_dais, - .num_links = ARRAY_SIZE(byt_max98090_dais), - .dapm_widgets = byt_max98090_widgets, - .num_dapm_widgets = ARRAY_SIZE(byt_max98090_widgets), - .dapm_routes = byt_max98090_audio_map, - .num_dapm_routes = ARRAY_SIZE(byt_max98090_audio_map), - .controls = byt_max98090_controls, - .num_controls = ARRAY_SIZE(byt_max98090_controls), - .fully_routed = true, -}; - -static int byt_max98090_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct byt_max98090_private *priv; - int ret_val; - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(&pdev->dev, "allocation failed\n"); - return -ENOMEM; - } - - ret_val = devm_acpi_dev_add_driver_gpios(dev->parent, acpi_byt_max98090_gpios); - if (ret_val) - dev_dbg(dev, "Unable to add GPIO mapping table\n"); - - byt_max98090_card.dev = &pdev->dev; - snd_soc_card_set_drvdata(&byt_max98090_card, priv); - ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_max98090_card); - if (ret_val) { - dev_err(&pdev->dev, - "snd_soc_register_card failed %d\n", ret_val); - return ret_val; - } - - return 0; -} - -static struct platform_driver byt_max98090_driver = { - .probe = byt_max98090_probe, - .driver = { - .name = "byt-max98090", - .pm = &snd_soc_pm_ops, - }, -}; -module_platform_driver(byt_max98090_driver) - -MODULE_DESCRIPTION("ASoC Intel(R) Baytrail Machine driver"); -MODULE_AUTHOR("Omair Md Abdullah, Jarkko Nikula"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:byt-max98090"); diff --git a/sound/soc/intel/boards/byt-rt5640.c b/sound/soc/intel/boards/byt-rt5640.c deleted file mode 100644 index 8851949f38e2..000000000000 --- a/sound/soc/intel/boards/byt-rt5640.c +++ /dev/null @@ -1,224 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Baytrail SST RT5640 machine driver - * Copyright (c) 2014, Intel Corporation. - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/acpi.h> -#include <linux/device.h> -#include <linux/dmi.h> -#include <linux/slab.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/jack.h> -#include "../../codecs/rt5640.h" - -#include "../common/sst-dsp.h" - -static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = { - SND_SOC_DAPM_HP("Headphone", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_MIC("Internal Mic", NULL), - SND_SOC_DAPM_SPK("Speaker", NULL), -}; - -static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { - {"Headset Mic", NULL, "MICBIAS1"}, - {"IN2P", NULL, "Headset Mic"}, - {"Headphone", NULL, "HPOL"}, - {"Headphone", NULL, "HPOR"}, - {"Speaker", NULL, "SPOLP"}, - {"Speaker", NULL, "SPOLN"}, - {"Speaker", NULL, "SPORP"}, - {"Speaker", NULL, "SPORN"}, -}; - -static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = { - {"DMIC1", NULL, "Internal Mic"}, -}; - -static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic2_map[] = { - {"DMIC2", NULL, "Internal Mic"}, -}; - -static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = { - {"Internal Mic", NULL, "MICBIAS1"}, - {"IN1P", NULL, "Internal Mic"}, -}; - -enum { - BYT_RT5640_DMIC1_MAP, - BYT_RT5640_DMIC2_MAP, - BYT_RT5640_IN1_MAP, -}; - -#define BYT_RT5640_MAP(quirk) ((quirk) & 0xff) -#define BYT_RT5640_DMIC_EN BIT(16) - -static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP | - BYT_RT5640_DMIC_EN; - -static const struct snd_kcontrol_new byt_rt5640_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Internal Mic"), - SOC_DAPM_PIN_SWITCH("Speaker"), -}; - -static int byt_rt5640_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - int ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, - params_rate(params) * 256, - SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(codec_dai->dev, "can't set codec clock %d\n", ret); - return ret; - } - ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_BCLK1, - params_rate(params) * 64, - params_rate(params) * 256); - if (ret < 0) { - dev_err(codec_dai->dev, "can't set codec pll: %d\n", ret); - return ret; - } - return 0; -} - -static int byt_rt5640_quirk_cb(const struct dmi_system_id *id) -{ - byt_rt5640_quirk = (unsigned long)id->driver_data; - return 1; -} - -static const struct dmi_system_id byt_rt5640_quirk_table[] = { - { - .callback = byt_rt5640_quirk_cb, - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"), - }, - .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP, - }, - { - .callback = byt_rt5640_quirk_cb, - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "DellInc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"), - }, - .driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP | - BYT_RT5640_DMIC_EN), - }, - {} -}; - -static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) -{ - int ret; - struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component; - struct snd_soc_card *card = runtime->card; - const struct snd_soc_dapm_route *custom_map; - int num_routes; - - card->dapm.idle_bias_off = true; - - ret = snd_soc_add_card_controls(card, byt_rt5640_controls, - ARRAY_SIZE(byt_rt5640_controls)); - if (ret) { - dev_err(card->dev, "unable to add card controls\n"); - return ret; - } - - dmi_check_system(byt_rt5640_quirk_table); - switch (BYT_RT5640_MAP(byt_rt5640_quirk)) { - case BYT_RT5640_IN1_MAP: - custom_map = byt_rt5640_intmic_in1_map; - num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map); - break; - case BYT_RT5640_DMIC2_MAP: - custom_map = byt_rt5640_intmic_dmic2_map; - num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic2_map); - break; - default: - custom_map = byt_rt5640_intmic_dmic1_map; - num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map); - } - - ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); - if (ret) - return ret; - - if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) { - ret = rt5640_dmic_enable(component, 0, 0); - if (ret) - return ret; - } - - snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone"); - snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker"); - - return ret; -} - -static struct snd_soc_ops byt_rt5640_ops = { - .hw_params = byt_rt5640_hw_params, -}; - -SND_SOC_DAILINK_DEFS(audio, - DAILINK_COMP_ARRAY(COMP_CPU("baytrail-pcm-audio")), - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5640:00", "rt5640-aif1")), - DAILINK_COMP_ARRAY(COMP_PLATFORM("baytrail-pcm-audio"))); - -static struct snd_soc_dai_link byt_rt5640_dais[] = { - { - .name = "Baytrail Audio", - .stream_name = "Audio", - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, - .init = byt_rt5640_init, - .ops = &byt_rt5640_ops, - SND_SOC_DAILINK_REG(audio), - }, -}; - -static struct snd_soc_card byt_rt5640_card = { - .name = "byt-rt5640", - .owner = THIS_MODULE, - .dai_link = byt_rt5640_dais, - .num_links = ARRAY_SIZE(byt_rt5640_dais), - .dapm_widgets = byt_rt5640_widgets, - .num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets), - .dapm_routes = byt_rt5640_audio_map, - .num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map), - .fully_routed = true, -}; - -static int byt_rt5640_probe(struct platform_device *pdev) -{ - struct snd_soc_card *card = &byt_rt5640_card; - - card->dev = &pdev->dev; - return devm_snd_soc_register_card(&pdev->dev, card); -} - -static struct platform_driver byt_rt5640_audio = { - .probe = byt_rt5640_probe, - .driver = { - .name = "byt-rt5640", - .pm = &snd_soc_pm_ops, - }, -}; -module_platform_driver(byt_rt5640_audio) - -MODULE_DESCRIPTION("ASoC Intel(R) Baytrail Machine driver"); -MODULE_AUTHOR("Omair Md Abdullah, Jarkko Nikula"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:byt-rt5640"); diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c index 9cb42ba40c07..68a3d345dc25 100644 --- a/sound/soc/intel/boards/bytcht_cx2072x.c +++ b/sound/soc/intel/boards/bytcht_cx2072x.c @@ -70,7 +70,7 @@ static const struct acpi_gpio_mapping byt_cht_cx2072x_acpi_gpios[] = { static int byt_cht_cx2072x_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; - struct snd_soc_component *codec = asoc_rtd_to_codec(rtd, 0)->component; + struct snd_soc_component *codec = snd_soc_rtd_to_codec(rtd, 0)->component; int ret; if (devm_acpi_dev_add_driver_gpios(codec->dev, @@ -80,26 +80,26 @@ static int byt_cht_cx2072x_init(struct snd_soc_pcm_runtime *rtd) card->dapm.idle_bias_off = true; /* set the default PLL rate, the clock is handled by the codec driver */ - ret = snd_soc_dai_set_sysclk(asoc_rtd_to_codec(rtd, 0), CX2072X_MCLK_EXTERNAL_PLL, + ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(rtd, 0), CX2072X_MCLK_EXTERNAL_PLL, 19200000, SND_SOC_CLOCK_IN); if (ret) { dev_err(rtd->dev, "Could not set sysclk\n"); return ret; } - ret = snd_soc_card_jack_new(card, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0, - &byt_cht_cx2072x_headset, - byt_cht_cx2072x_headset_pins, - ARRAY_SIZE(byt_cht_cx2072x_headset_pins)); + ret = snd_soc_card_jack_new_pins(card, "Headset", + SND_JACK_HEADSET | SND_JACK_BTN_0, + &byt_cht_cx2072x_headset, + byt_cht_cx2072x_headset_pins, + ARRAY_SIZE(byt_cht_cx2072x_headset_pins)); if (ret) return ret; snd_soc_component_set_jack(codec, &byt_cht_cx2072x_headset, NULL); - snd_soc_dai_set_bclk_ratio(asoc_rtd_to_codec(rtd, 0), 50); + snd_soc_dai_set_bclk_ratio(snd_soc_rtd_to_codec(rtd, 0), 50); - return ret; + return 0; } static int byt_cht_cx2072x_fixup(struct snd_soc_pcm_runtime *rtd, @@ -111,7 +111,7 @@ static int byt_cht_cx2072x_fixup(struct snd_soc_pcm_runtime *rtd, hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); int ret; - /* The DSP will covert the FE rate to 48k, stereo, 24bits */ + /* The DSP will convert the FE rate to 48k, stereo, 24bits */ rate->min = rate->max = 48000; channels->min = channels->max = 2; @@ -123,16 +123,16 @@ static int byt_cht_cx2072x_fixup(struct snd_soc_pcm_runtime *rtd, * with explicit setting to I2S 2ch 24-bit. The word length is set with * dai_set_tdm_slot() since there is no other API exposed */ - ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), + ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_BP_FP); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); return ret; } - ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 24); + ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 24); if (ret < 0) { dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); return ret; @@ -147,7 +147,7 @@ static int byt_cht_cx2072x_aif1_startup(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_RATE, 48000); } -static struct snd_soc_ops byt_cht_cx2072x_aif1_ops = { +static const struct snd_soc_ops byt_cht_cx2072x_aif1_ops = { .startup = byt_cht_cx2072x_aif1_startup, }; @@ -175,8 +175,6 @@ static struct snd_soc_dai_link byt_cht_cx2072x_dais[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &byt_cht_cx2072x_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -185,7 +183,7 @@ static struct snd_soc_dai_link byt_cht_cx2072x_dais[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &byt_cht_cx2072x_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -195,24 +193,19 @@ static struct snd_soc_dai_link byt_cht_cx2072x_dais[] = { .id = 0, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS, + | SND_SOC_DAIFMT_CBC_CFC, .init = byt_cht_cx2072x_init, .be_hw_params_fixup = byt_cht_cx2072x_fixup, - .nonatomic = true, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(ssp2, cx2072x, platform), }, }; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) /* use space before codec name to simplify card ID, and simplify driver name */ -#define CARD_NAME "bytcht cx2072x" /* card name will be 'sof-bytcht cx2072x' */ -#define DRIVER_NAME "SOF" -#else +#define SOF_CARD_NAME "bytcht cx2072x" /* card name will be 'sof-bytcht cx2072x' */ +#define SOF_DRIVER_NAME "SOF" + #define CARD_NAME "bytcht-cx2072x" #define DRIVER_NAME NULL /* card name will be used for driver name */ -#endif /* SoC card */ static struct snd_soc_card byt_cht_cx2072x_card = { @@ -236,6 +229,7 @@ static int snd_byt_cht_cx2072x_probe(struct platform_device *pdev) struct snd_soc_acpi_mach *mach; struct acpi_device *adev; int dai_index = 0; + bool sof_parent; int i, ret; byt_cht_cx2072x_card.dev = &pdev->dev; @@ -243,7 +237,8 @@ static int snd_byt_cht_cx2072x_probe(struct platform_device *pdev) /* fix index of codec dai */ for (i = 0; i < ARRAY_SIZE(byt_cht_cx2072x_dais); i++) { - if (!strcmp(byt_cht_cx2072x_dais[i].codecs->name, + if (byt_cht_cx2072x_dais[i].num_codecs && + !strcmp(byt_cht_cx2072x_dais[i].codecs->name, "i2c-14F10720:00")) { dai_index = i; break; @@ -255,25 +250,41 @@ static int snd_byt_cht_cx2072x_probe(struct platform_device *pdev) if (adev) { snprintf(codec_name, sizeof(codec_name), "i2c-%s", acpi_dev_name(adev)); - put_device(&adev->dev); byt_cht_cx2072x_dais[dai_index].codecs->name = codec_name; + } else { + dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); + return -ENOENT; } - /* override plaform name, if required */ + acpi_dev_put(adev); + + /* override platform name, if required */ ret = snd_soc_fixup_dai_links_platform_name(&byt_cht_cx2072x_card, mach->mach_params.platform); if (ret) return ret; + sof_parent = snd_soc_acpi_sof_parent(&pdev->dev); + + /* set card and driver name */ + if (sof_parent) { + byt_cht_cx2072x_card.name = SOF_CARD_NAME; + byt_cht_cx2072x_card.driver_name = SOF_DRIVER_NAME; + } else { + byt_cht_cx2072x_card.name = CARD_NAME; + byt_cht_cx2072x_card.driver_name = DRIVER_NAME; + } + + /* set pm ops */ + if (sof_parent) + pdev->dev.driver->pm = &snd_soc_pm_ops; + return devm_snd_soc_register_card(&pdev->dev, &byt_cht_cx2072x_card); } static struct platform_driver snd_byt_cht_cx2072x_driver = { .driver = { .name = "bytcht_cx2072x", -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - .pm = &snd_soc_pm_ops, -#endif }, .probe = snd_byt_cht_cx2072x_probe, }; diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c index e1e46b4bbac5..31141d4b6b25 100644 --- a/sound/soc/intel/boards/bytcht_da7213.c +++ b/sound/soc/intel/boards/bytcht_da7213.c @@ -78,16 +78,16 @@ static int codec_fixup(struct snd_soc_pcm_runtime *rtd, * with explicit setting to I2S 2ch 24-bit. The word length is set with * dai_set_tdm_slot() since there is no other API exposed */ - ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), + ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_BP_FP); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); return ret; } - ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 24); + ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 24); if (ret < 0) { dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); return ret; @@ -105,8 +105,8 @@ static int aif1_startup(struct snd_pcm_substream *substream) static int aif1_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); int ret; ret = snd_soc_dai_set_sysclk(codec_dai, DA7213_CLKSRC_MCLK, @@ -126,8 +126,8 @@ static int aif1_hw_params(struct snd_pcm_substream *substream, static int aif1_hw_free(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); int ret; ret = snd_soc_dai_set_pll(codec_dai, 0, @@ -174,8 +174,6 @@ static struct snd_soc_dai_link dailink[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -184,7 +182,7 @@ static struct snd_soc_dai_link dailink[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -195,24 +193,19 @@ static struct snd_soc_dai_link dailink[] = { .id = 0, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS, + | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = codec_fixup, - .nonatomic = true, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, }; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) /* use space before codec name to simplify card ID, and simplify driver name */ -#define CARD_NAME "bytcht da7213" /* card name will be 'sof-bytcht da7213' */ -#define DRIVER_NAME "SOF" -#else +#define SOF_CARD_NAME "bytcht da7213" /* card name will be 'sof-bytcht da7213' */ +#define SOF_DRIVER_NAME "SOF" + #define CARD_NAME "bytcht-da7213" #define DRIVER_NAME NULL /* card name will be used for driver name */ -#endif /* SoC card */ static struct snd_soc_card bytcht_da7213_card = { @@ -237,6 +230,7 @@ static int bytcht_da7213_probe(struct platform_device *pdev) struct snd_soc_acpi_mach *mach; const char *platform_name; struct acpi_device *adev; + bool sof_parent; int dai_index = 0; int ret_val = 0; int i; @@ -247,7 +241,8 @@ static int bytcht_da7213_probe(struct platform_device *pdev) /* fix index of codec dai */ for (i = 0; i < ARRAY_SIZE(dailink); i++) { - if (!strcmp(dailink[i].codecs->name, "i2c-DLGS7213:00")) { + if (dailink[i].num_codecs && + !strcmp(dailink[i].codecs->name, "i2c-DLGS7213:00")) { dai_index = i; break; } @@ -258,17 +253,36 @@ static int bytcht_da7213_probe(struct platform_device *pdev) if (adev) { snprintf(codec_name, sizeof(codec_name), "i2c-%s", acpi_dev_name(adev)); - put_device(&adev->dev); dailink[dai_index].codecs->name = codec_name; + } else { + dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); + return -ENOENT; } - /* override plaform name, if required */ + acpi_dev_put(adev); + + /* override platform name, if required */ platform_name = mach->mach_params.platform; ret_val = snd_soc_fixup_dai_links_platform_name(card, platform_name); if (ret_val) return ret_val; + sof_parent = snd_soc_acpi_sof_parent(&pdev->dev); + + /* set card and driver name */ + if (sof_parent) { + bytcht_da7213_card.name = SOF_CARD_NAME; + bytcht_da7213_card.driver_name = SOF_DRIVER_NAME; + } else { + bytcht_da7213_card.name = CARD_NAME; + bytcht_da7213_card.driver_name = DRIVER_NAME; + } + + /* set pm ops */ + if (sof_parent) + pdev->dev.driver->pm = &snd_soc_pm_ops; + ret_val = devm_snd_soc_register_card(&pdev->dev, card); if (ret_val) { dev_err(&pdev->dev, @@ -282,9 +296,6 @@ static int bytcht_da7213_probe(struct platform_device *pdev) static struct platform_driver bytcht_da7213_driver = { .driver = { .name = "bytcht_da7213", -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - .pm = &snd_soc_pm_ops, -#endif }, .probe = bytcht_da7213_probe, }; diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 7ae34b49815c..62594e7966ab 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -27,8 +27,8 @@ #include <sound/pcm_params.h> #include <sound/soc.h> #include <sound/soc-acpi.h> +#include "../../codecs/es83xx-dsm-common.h" #include "../atom/sst-atom-controls.h" -#include "../common/sst-dsp.h" #include "../common/soc-intel-quirks.h" /* jd-inv + terminating entry */ @@ -38,6 +38,7 @@ struct byt_cht_es8316_private { struct clk *mclk; struct snd_soc_jack jack; struct gpio_desc *speaker_en_gpio; + struct device *codec_dev; bool speaker_en; }; @@ -157,7 +158,7 @@ static struct snd_soc_jack_pin byt_cht_es8316_jack_pins[] = { static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) { - struct snd_soc_component *codec = asoc_rtd_to_codec(runtime, 0)->component; + struct snd_soc_component *codec = snd_soc_rtd_to_codec(runtime, 0)->component; struct snd_soc_card *card = runtime->card; struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); const struct snd_soc_dapm_route *custom_map; @@ -212,17 +213,17 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) if (ret) dev_err(card->dev, "unable to enable MCLK\n"); - ret = snd_soc_dai_set_sysclk(asoc_rtd_to_codec(runtime, 0), 0, 19200000, + ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(runtime, 0), 0, 19200000, SND_SOC_CLOCK_IN); if (ret < 0) { dev_err(card->dev, "can't set codec clock %d\n", ret); return ret; } - ret = snd_soc_card_jack_new(card, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0, - &priv->jack, byt_cht_es8316_jack_pins, - ARRAY_SIZE(byt_cht_es8316_jack_pins)); + ret = snd_soc_card_jack_new_pins(card, "Headset", + SND_JACK_HEADSET | SND_JACK_BTN_0, + &priv->jack, byt_cht_es8316_jack_pins, + ARRAY_SIZE(byt_cht_es8316_jack_pins)); if (ret) { dev_err(card->dev, "jack creation failed %d\n", ret); return ret; @@ -243,7 +244,7 @@ static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd, SNDRV_PCM_HW_PARAM_CHANNELS); int ret, bits; - /* The DSP will covert the FE rate to 48k, stereo */ + /* The DSP will convert the FE rate to 48k, stereo */ rate->min = rate->max = 48000; channels->min = channels->max = 2; @@ -262,17 +263,17 @@ static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd, * with explicit setting to I2S 2ch 24-bit. The word length is set with * dai_set_tdm_slot() since there is no other API exposed */ - ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), + ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS + SND_SOC_DAIFMT_BP_FP ); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); return ret; } - ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, bits); + ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, bits); if (ret < 0) { dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); return ret; @@ -314,8 +315,6 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &byt_cht_es8316_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -325,25 +324,19 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &byt_cht_es8316_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, /* back ends */ { - /* Only SSP2 has been tested here, so BYT-CR platforms that - * require SSP0 will not work. - */ .name = "SSP2-Codec", .id = 0, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS, + | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = byt_cht_es8316_codec_fixup, - .nonatomic = true, - .dpcm_playback = 1, - .dpcm_capture = 1, .init = byt_cht_es8316_init, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, @@ -407,18 +400,14 @@ static int byt_cht_es8316_resume(struct snd_soc_card *card) return 0; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) /* use space before codec name to simplify card ID, and simplify driver name */ -#define CARD_NAME "bytcht es8316" /* card name will be 'sof-bytcht es8316' */ -#define DRIVER_NAME "SOF" -#else +#define SOF_CARD_NAME "bytcht es8316" /* card name will be 'sof-bytcht es8316' */ +#define SOF_DRIVER_NAME "SOF" + #define CARD_NAME "bytcht-es8316" #define DRIVER_NAME NULL /* card name will be used for driver name */ -#endif static struct snd_soc_card byt_cht_es8316_card = { - .name = CARD_NAME, - .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = byt_cht_es8316_dais, .num_links = ARRAY_SIZE(byt_cht_es8316_dais), @@ -451,6 +440,13 @@ static const struct dmi_system_id byt_cht_es8316_quirk_table[] = { | BYT_CHT_ES8316_INTMIC_IN2_MAP | BYT_CHT_ES8316_JD_INVERTED), }, + { /* Nanote UMPC-01 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "RWC CO.,LTD"), + DMI_MATCH(DMI_PRODUCT_NAME, "UMPC-01"), + }, + .driver_data = (void *)BYT_CHT_ES8316_INTMIC_IN1_MAP, + }, { /* Teclast X98 Plus II */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"), @@ -462,14 +458,76 @@ static const struct dmi_system_id byt_cht_es8316_quirk_table[] = { {} }; +static int byt_cht_es8316_get_quirks_from_dsm(struct byt_cht_es8316_private *priv, + bool is_bytcr) +{ + int ret, val1, val2, dsm_quirk = 0; + + if (is_bytcr) + dsm_quirk |= BYT_CHT_ES8316_SSP0; + + ret = es83xx_dsm(priv->codec_dev, PLATFORM_MAINMIC_TYPE_ARG, &val1); + if (ret < 0) + return ret; + + ret = es83xx_dsm(priv->codec_dev, PLATFORM_HPMIC_TYPE_ARG, &val2); + if (ret < 0) + return ret; + + if (val1 == PLATFORM_MIC_AMIC_LIN1RIN1 && val2 == PLATFORM_MIC_AMIC_LIN2RIN2) { + dsm_quirk |= BYT_CHT_ES8316_INTMIC_IN1_MAP; + } else if (val1 == PLATFORM_MIC_AMIC_LIN2RIN2 && val2 == PLATFORM_MIC_AMIC_LIN1RIN1) { + dsm_quirk |= BYT_CHT_ES8316_INTMIC_IN2_MAP; + } else { + dev_warn(priv->codec_dev, "Unknown mic settings mainmic 0x%02x hpmic 0x%02x\n", + val1, val2); + return -EINVAL; + } + + ret = es83xx_dsm(priv->codec_dev, PLATFORM_SPK_TYPE_ARG, &val1); + if (ret < 0) + return ret; + + switch (val1) { + case PLATFORM_SPK_MONO: + dsm_quirk |= BYT_CHT_ES8316_MONO_SPEAKER; + break; + case PLATFORM_SPK_STEREO: + break; + default: + dev_warn(priv->codec_dev, "Unknown speaker setting 0x%02x\n", val1); + return -EINVAL; + } + + ret = es83xx_dsm(priv->codec_dev, PLATFORM_HPDET_INV_ARG, &val1); + if (ret < 0) + return ret; + + switch (val1) { + case PLATFORM_HPDET_NORMAL: + break; + case PLATFORM_HPDET_INVERTED: + dsm_quirk |= BYT_CHT_ES8316_JD_INVERTED; + break; + default: + dev_warn(priv->codec_dev, "Unknown hpdet-inv setting 0x%02x\n", val1); + return -EINVAL; + } + + quirk = dsm_quirk; + return 0; +} + static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; static const char * const mic_name[] = { "in1", "in2" }; + struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); struct property_entry props[MAX_NO_PROPS] = {}; struct byt_cht_es8316_private *priv; const struct dmi_system_id *dmi_id; - struct device *dev = &pdev->dev; - struct snd_soc_acpi_mach *mach; + struct fwnode_handle *fwnode; + bool sof_parent, is_bytcr; const char *platform_name; struct acpi_device *adev; struct device *codec_dev; @@ -482,10 +540,10 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - mach = dev->platform_data; /* fix index of codec dai */ for (i = 0; i < ARRAY_SIZE(byt_cht_es8316_dais); i++) { - if (!strcmp(byt_cht_es8316_dais[i].codecs->name, + if (byt_cht_es8316_dais[i].num_codecs && + !strcmp(byt_cht_es8316_dais[i].codecs->name, "i2c-ESSX8316:00")) { dai_index = i; break; @@ -497,25 +555,39 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) if (adev) { snprintf(codec_name, sizeof(codec_name), "i2c-%s", acpi_dev_name(adev)); - put_device(&adev->dev); byt_cht_es8316_dais[dai_index].codecs->name = codec_name; + } else { + dev_err(dev, "Error cannot find '%s' dev\n", mach->id); + return -ENOENT; } - /* override plaform name, if required */ + codec_dev = acpi_get_first_physical_node(adev); + acpi_dev_put(adev); + if (!codec_dev) + return -EPROBE_DEFER; + priv->codec_dev = get_device(codec_dev); + + /* override platform name, if required */ byt_cht_es8316_card.dev = dev; platform_name = mach->mach_params.platform; ret = snd_soc_fixup_dai_links_platform_name(&byt_cht_es8316_card, platform_name); - if (ret) + if (ret) { + put_device(codec_dev); return ret; + } + + es83xx_dsm_dump(priv->codec_dev); /* Check for BYTCR or other platform and setup quirks */ + is_bytcr = soc_intel_is_byt() && mach->mach_params.acpi_ipc_irq_index == 0; dmi_id = dmi_first_match(byt_cht_es8316_quirk_table); if (dmi_id) { quirk = (unsigned long)dmi_id->driver_data; - } else if (soc_intel_is_byt() && - mach->mach_params.acpi_ipc_irq_index == 0) { + } else if (!byt_cht_es8316_get_quirks_from_dsm(priv, is_bytcr)) { + dev_info(dev, "Using ACPI DSM info for quirks\n"); + } else if (is_bytcr) { /* On BYTCR default to SSP0, internal-mic-in2-map, mono-spk */ quirk = BYT_CHT_ES8316_SSP0 | BYT_CHT_ES8316_INTMIC_IN2_MAP | BYT_CHT_ES8316_MONO_SPEAKER; @@ -537,46 +609,40 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) /* get the clock */ priv->mclk = devm_clk_get(dev, "pmc_plt_clk_3"); if (IS_ERR(priv->mclk)) { - ret = PTR_ERR(priv->mclk); - dev_err(dev, "clk_get pmc_plt_clk_3 failed: %d\n", ret); - return ret; + put_device(codec_dev); + return dev_err_probe(dev, PTR_ERR(priv->mclk), "clk_get pmc_plt_clk_3 failed\n"); } - /* get speaker enable GPIO */ - codec_dev = bus_find_device_by_name(&i2c_bus_type, NULL, codec_name); - if (!codec_dev) - return -EPROBE_DEFER; - if (quirk & BYT_CHT_ES8316_JD_INVERTED) props[cnt++] = PROPERTY_ENTRY_BOOL("everest,jack-detect-inverted"); if (cnt) { - ret = device_add_properties(codec_dev, props); + fwnode = fwnode_create_software_node(props, NULL); + if (IS_ERR(fwnode)) { + put_device(codec_dev); + return PTR_ERR(fwnode); + } + + ret = device_add_software_node(codec_dev, to_software_node(fwnode)); + + fwnode_handle_put(fwnode); + if (ret) { put_device(codec_dev); return ret; } } + /* get speaker enable GPIO */ devm_acpi_dev_add_driver_gpios(codec_dev, byt_cht_es8316_gpios); priv->speaker_en_gpio = - gpiod_get_index(codec_dev, "speaker-enable", 0, - /* see comment in byt_cht_es8316_resume */ - GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); - put_device(codec_dev); - + gpiod_get_optional(codec_dev, "speaker-enable", + /* see comment in byt_cht_es8316_resume() */ + GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); if (IS_ERR(priv->speaker_en_gpio)) { - ret = PTR_ERR(priv->speaker_en_gpio); - switch (ret) { - case -ENOENT: - priv->speaker_en_gpio = NULL; - break; - default: - dev_err(dev, "get speaker GPIO failed: %d\n", ret); - fallthrough; - case -EPROBE_DEFER: - return ret; - } + ret = dev_err_probe(dev, PTR_ERR(priv->speaker_en_gpio), + "get speaker GPIO failed\n"); + goto err_put_codec; } snprintf(components_string, sizeof(components_string), @@ -591,6 +657,21 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) byt_cht_es8316_card.long_name = long_name; #endif + sof_parent = snd_soc_acpi_sof_parent(dev); + + /* set card and driver name */ + if (sof_parent) { + byt_cht_es8316_card.name = SOF_CARD_NAME; + byt_cht_es8316_card.driver_name = SOF_DRIVER_NAME; + } else { + byt_cht_es8316_card.name = CARD_NAME; + byt_cht_es8316_card.driver_name = DRIVER_NAME; + } + + /* set pm ops */ + if (sof_parent) + dev->driver->pm = &snd_soc_pm_ops; + /* register the soc card */ snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); @@ -598,27 +679,30 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) if (ret) { gpiod_put(priv->speaker_en_gpio); dev_err(dev, "snd_soc_register_card failed: %d\n", ret); - return ret; + goto err_put_codec; } platform_set_drvdata(pdev, &byt_cht_es8316_card); return 0; + +err_put_codec: + device_remove_software_node(priv->codec_dev); + put_device(priv->codec_dev); + return ret; } -static int snd_byt_cht_es8316_mc_remove(struct platform_device *pdev) +static void snd_byt_cht_es8316_mc_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); gpiod_put(priv->speaker_en_gpio); - return 0; + device_remove_software_node(priv->codec_dev); + put_device(priv->codec_dev); } static struct platform_driver snd_byt_cht_es8316_mc_driver = { .driver = { .name = "bytcht_es8316", -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - .pm = &snd_soc_pm_ops, -#endif }, .probe = snd_byt_cht_es8316_mc_probe, .remove = snd_byt_cht_es8316_mc_remove, diff --git a/sound/soc/intel/boards/bytcht_nocodec.c b/sound/soc/intel/boards/bytcht_nocodec.c index 8c0dab1f4030..fec23bda9e64 100644 --- a/sound/soc/intel/boards/bytcht_nocodec.c +++ b/sound/soc/intel/boards/bytcht_nocodec.c @@ -58,17 +58,17 @@ static int codec_fixup(struct snd_soc_pcm_runtime *rtd, * with explicit setting to I2S 2ch 24-bit. The word length is set with * dai_set_tdm_slot() since there is no other API exposed */ - ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), + ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_BP_FP); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); return ret; } - ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 24); + ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 24); if (ret < 0) { dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); return ret; @@ -93,7 +93,7 @@ static int aif1_startup(struct snd_pcm_substream *substream) &constraints_48000); } -static struct snd_soc_ops aif1_ops = { +static const struct snd_soc_ops aif1_ops = { .startup = aif1_startup, }; @@ -119,8 +119,6 @@ static struct snd_soc_dai_link dais[] = { .ignore_suspend = 1, .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -130,7 +128,7 @@ static struct snd_soc_dai_link dais[] = { .ignore_suspend = 1, .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -141,12 +139,9 @@ static struct snd_soc_dai_link dais[] = { .id = 0, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS, + | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = codec_fixup, .ignore_suspend = 1, - .nonatomic = true, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(ssp2_port, dummy, platform), }, }; diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index fc202747ba83..0f3b8f44e701 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -17,7 +17,10 @@ #include <linux/acpi.h> #include <linux/clk.h> #include <linux/device.h> +#include <linux/device/bus.h> #include <linux/dmi.h> +#include <linux/gpio/consumer.h> +#include <linux/gpio/machine.h> #include <linux/input.h> #include <linux/slab.h> #include <sound/pcm.h> @@ -28,16 +31,20 @@ #include <dt-bindings/sound/rt5640.h> #include "../../codecs/rt5640.h" #include "../atom/sst-atom-controls.h" -#include "../common/sst-dsp.h" #include "../common/soc-intel-quirks.h" +#define BYT_RT5640_FALLBACK_CODEC_DEV_NAME "i2c-rt5640" + enum { BYT_RT5640_DMIC1_MAP, BYT_RT5640_DMIC2_MAP, BYT_RT5640_IN1_MAP, BYT_RT5640_IN3_MAP, + BYT_RT5640_NO_INTERNAL_MIC_MAP, }; +#define RT5640_JD_SRC_EXT_GPIO 0x0f + enum { BYT_RT5640_JD_SRC_GPIO1 = (RT5640_JD_SRC_GPIO1 << 4), BYT_RT5640_JD_SRC_JD1_IN4P = (RT5640_JD_SRC_JD1_IN4P << 4), @@ -45,6 +52,7 @@ enum { BYT_RT5640_JD_SRC_GPIO2 = (RT5640_JD_SRC_GPIO2 << 4), BYT_RT5640_JD_SRC_GPIO3 = (RT5640_JD_SRC_GPIO3 << 4), BYT_RT5640_JD_SRC_GPIO4 = (RT5640_JD_SRC_GPIO4 << 4), + BYT_RT5640_JD_SRC_EXT_GPIO = (RT5640_JD_SRC_EXT_GPIO << 4) }; enum { @@ -72,6 +80,13 @@ enum { #define BYT_RT5640_SSP0_AIF2 BIT(21) #define BYT_RT5640_MCLK_EN BIT(22) #define BYT_RT5640_MCLK_25MHZ BIT(23) +#define BYT_RT5640_NO_SPEAKERS BIT(24) +#define BYT_RT5640_LINEOUT BIT(25) +#define BYT_RT5640_LINEOUT_AS_HP2 BIT(26) +#define BYT_RT5640_HSMIC2_ON_IN1 BIT(27) +#define BYT_RT5640_JD_HP_ELITEP_1000G2 BIT(28) +#define BYT_RT5640_USE_AMCR0F28 BIT(29) +#define BYT_RT5640_SWAPPED_SPEAKERS BIT(30) #define BYTCR_INPUT_DEFAULTS \ (BYT_RT5640_IN3_MAP | \ @@ -85,7 +100,11 @@ enum { struct byt_rt5640_private { struct snd_soc_jack jack; + struct snd_soc_jack jack2; + struct rt5640_set_jack_data jack_data; + struct gpio_desc *hsmic_detect; struct clk *mclk; + struct device *codec_dev; }; static bool is_bytcr; @@ -117,10 +136,15 @@ static void log_quirks(struct device *dev) case BYT_RT5640_IN3_MAP: dev_info(dev, "quirk IN3_MAP enabled\n"); break; + case BYT_RT5640_NO_INTERNAL_MIC_MAP: + dev_info(dev, "quirk NO_INTERNAL_MIC_MAP enabled\n"); + break; default: dev_err(dev, "quirk map 0x%x is not supported, microphone input will not work\n", map); break; } + if (byt_rt5640_quirk & BYT_RT5640_HSMIC2_ON_IN1) + dev_info(dev, "quirk HSMIC2_ON_IN1 enabled\n"); if (BYT_RT5640_JDSRC(byt_rt5640_quirk)) { dev_info(dev, "quirk realtek,jack-detect-source %ld\n", BYT_RT5640_JDSRC(byt_rt5640_quirk)); @@ -131,8 +155,18 @@ static void log_quirks(struct device *dev) } if (byt_rt5640_quirk & BYT_RT5640_JD_NOT_INV) dev_info(dev, "quirk JD_NOT_INV enabled\n"); + if (byt_rt5640_quirk & BYT_RT5640_JD_HP_ELITEP_1000G2) + dev_info(dev, "quirk JD_HP_ELITEPAD_1000G2 enabled\n"); if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) dev_info(dev, "quirk MONO_SPEAKER enabled\n"); + if (byt_rt5640_quirk & BYT_RT5640_NO_SPEAKERS) + dev_info(dev, "quirk NO_SPEAKERS enabled\n"); + if (byt_rt5640_quirk & BYT_RT5640_SWAPPED_SPEAKERS) + dev_info(dev, "quirk SWAPPED_SPEAKERS enabled\n"); + if (byt_rt5640_quirk & BYT_RT5640_LINEOUT) + dev_info(dev, "quirk LINEOUT enabled\n"); + if (byt_rt5640_quirk & BYT_RT5640_LINEOUT_AS_HP2) + dev_info(dev, "quirk LINEOUT_AS_HP2 enabled\n"); if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) dev_info(dev, "quirk DIFF_MIC enabled\n"); if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) { @@ -218,6 +252,20 @@ static int byt_rt5640_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai, #define BYT_CODEC_DAI1 "rt5640-aif1" #define BYT_CODEC_DAI2 "rt5640-aif2" +static struct snd_soc_dai *byt_rt5640_get_codec_dai(struct snd_soc_dapm_context *dapm) +{ + struct snd_soc_card *card = dapm->card; + struct snd_soc_dai *codec_dai; + + codec_dai = snd_soc_card_get_codec_dai(card, BYT_CODEC_DAI1); + if (!codec_dai) + codec_dai = snd_soc_card_get_codec_dai(card, BYT_CODEC_DAI2); + if (!codec_dai) + dev_err(card->dev, "Error codec dai not found\n"); + + return codec_dai; +} + static int platform_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { @@ -227,24 +275,15 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card); int ret; - codec_dai = snd_soc_card_get_codec_dai(card, BYT_CODEC_DAI1); + codec_dai = byt_rt5640_get_codec_dai(dapm); if (!codec_dai) - codec_dai = snd_soc_card_get_codec_dai(card, BYT_CODEC_DAI2); - - if (!codec_dai) { - dev_err(card->dev, - "Codec dai not found; Unable to set platform clock\n"); return -EIO; - } if (SND_SOC_DAPM_EVENT_ON(event)) { - if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN) { - ret = clk_prepare_enable(priv->mclk); - if (ret < 0) { - dev_err(card->dev, - "could not configure MCLK state\n"); - return ret; - } + ret = clk_prepare_enable(priv->mclk); + if (ret < 0) { + dev_err(card->dev, "could not configure MCLK state\n"); + return ret; } ret = byt_rt5640_prepare_and_enable_pll1(codec_dai, 48000); } else { @@ -256,10 +295,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_RCCLK, 48000 * 512, SND_SOC_CLOCK_IN); - if (!ret) { - if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN) - clk_disable_unprepare(priv->mclk); - } + if (!ret) + clk_disable_unprepare(priv->mclk); } if (ret < 0) { @@ -270,23 +307,48 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, return 0; } +static int byt_rt5640_event_lineout(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + unsigned int gpio_ctrl3_val = RT5640_GP1_PF_OUT; + struct snd_soc_dai *codec_dai; + + if (!(byt_rt5640_quirk & BYT_RT5640_LINEOUT_AS_HP2)) + return 0; + + /* + * On devices which use line-out as a second headphones output, + * the codec's GPIO1 pin is used to enable an external HP-amp. + */ + + codec_dai = byt_rt5640_get_codec_dai(w->dapm); + if (!codec_dai) + return -EIO; + + if (SND_SOC_DAPM_EVENT_ON(event)) + gpio_ctrl3_val |= RT5640_GP1_OUT_HI; + + snd_soc_component_update_bits(codec_dai->component, RT5640_GPIO_CTRL3, + RT5640_GP1_PF_MASK | RT5640_GP1_OUT_MASK, gpio_ctrl3_val); + + return 0; +} + static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Headset Mic 2", NULL), SND_SOC_DAPM_MIC("Internal Mic", NULL), SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_LINE("Line Out", byt_rt5640_event_lineout), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - }; static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { {"Headphone", NULL, "Platform Clock"}, {"Headset Mic", NULL, "Platform Clock"}, - {"Internal Mic", NULL, "Platform Clock"}, - {"Speaker", NULL, "Platform Clock"}, - {"Headset Mic", NULL, "MICBIAS1"}, {"IN2P", NULL, "Headset Mic"}, {"Headphone", NULL, "HPOL"}, @@ -294,23 +356,33 @@ static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { }; static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = { + {"Internal Mic", NULL, "Platform Clock"}, {"DMIC1", NULL, "Internal Mic"}, }; static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic2_map[] = { + {"Internal Mic", NULL, "Platform Clock"}, {"DMIC2", NULL, "Internal Mic"}, }; static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = { + {"Internal Mic", NULL, "Platform Clock"}, {"Internal Mic", NULL, "MICBIAS1"}, {"IN1P", NULL, "Internal Mic"}, }; static const struct snd_soc_dapm_route byt_rt5640_intmic_in3_map[] = { + {"Internal Mic", NULL, "Platform Clock"}, {"Internal Mic", NULL, "MICBIAS1"}, {"IN3P", NULL, "Internal Mic"}, }; +static const struct snd_soc_dapm_route byt_rt5640_hsmic2_in1_map[] = { + {"Headset Mic 2", NULL, "Platform Clock"}, + {"Headset Mic 2", NULL, "MICBIAS1"}, + {"IN1P", NULL, "Headset Mic 2"}, +}; + static const struct snd_soc_dapm_route byt_rt5640_ssp2_aif1_map[] = { {"ssp2 Tx", NULL, "codec_out0"}, {"ssp2 Tx", NULL, "codec_out1"}, @@ -348,6 +420,7 @@ static const struct snd_soc_dapm_route byt_rt5640_ssp0_aif2_map[] = { }; static const struct snd_soc_dapm_route byt_rt5640_stereo_spk_map[] = { + {"Speaker", NULL, "Platform Clock"}, {"Speaker", NULL, "SPOLP"}, {"Speaker", NULL, "SPOLN"}, {"Speaker", NULL, "SPORP"}, @@ -355,15 +428,24 @@ static const struct snd_soc_dapm_route byt_rt5640_stereo_spk_map[] = { }; static const struct snd_soc_dapm_route byt_rt5640_mono_spk_map[] = { + {"Speaker", NULL, "Platform Clock"}, {"Speaker", NULL, "SPOLP"}, {"Speaker", NULL, "SPOLN"}, }; +static const struct snd_soc_dapm_route byt_rt5640_lineout_map[] = { + {"Line Out", NULL, "Platform Clock"}, + {"Line Out", NULL, "LOUTR"}, + {"Line Out", NULL, "LOUTL"}, +}; + static const struct snd_kcontrol_new byt_rt5640_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Headset Mic 2"), SOC_DAPM_PIN_SWITCH("Internal Mic"), SOC_DAPM_PIN_SWITCH("Speaker"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static struct snd_soc_jack_pin rt5640_pins[] = { @@ -377,17 +459,98 @@ static struct snd_soc_jack_pin rt5640_pins[] = { }, }; +static struct snd_soc_jack_pin rt5640_pins2[] = { + { + /* The 2nd headset jack uses lineout with an external HP-amp */ + .pin = "Line Out", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic 2", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static struct snd_soc_jack_gpio rt5640_jack_gpio = { + .name = "hp-detect", + .report = SND_JACK_HEADSET, + .invert = true, + .debounce_time = 200, +}; + +static struct snd_soc_jack_gpio rt5640_jack2_gpio = { + .name = "hp2-detect", + .report = SND_JACK_HEADSET, + .invert = true, + .debounce_time = 200, +}; + +static const struct acpi_gpio_params acpi_gpio0 = { 0, 0, false }; +static const struct acpi_gpio_params acpi_gpio1 = { 1, 0, false }; +static const struct acpi_gpio_params acpi_gpio2 = { 2, 0, false }; + +static const struct acpi_gpio_mapping byt_rt5640_hp_elitepad_1000g2_gpios[] = { + { "hp-detect-gpios", &acpi_gpio0, 1, }, + { "headset-mic-detect-gpios", &acpi_gpio1, 1, }, + { "hp2-detect-gpios", &acpi_gpio2, 1, }, + { }, +}; + +static int byt_rt5640_hp_elitepad_1000g2_jack1_check(void *data) +{ + struct byt_rt5640_private *priv = data; + int jack_status, mic_status; + + jack_status = gpiod_get_value_cansleep(rt5640_jack_gpio.desc); + if (jack_status) + return 0; + + mic_status = gpiod_get_value_cansleep(priv->hsmic_detect); + if (mic_status) + return SND_JACK_HEADPHONE; + else + return SND_JACK_HEADSET; +} + +static int byt_rt5640_hp_elitepad_1000g2_jack2_check(void *data) +{ + struct snd_soc_component *component = data; + int jack_status, report; + + jack_status = gpiod_get_value_cansleep(rt5640_jack2_gpio.desc); + if (jack_status) + return 0; + + rt5640_enable_micbias1_for_ovcd(component); + report = rt5640_detect_headset(component, rt5640_jack2_gpio.desc); + rt5640_disable_micbias1_for_ovcd(component); + + return report; +} + static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); return byt_rt5640_prepare_and_enable_pll1(dai, params_rate(params)); } /* Please keep this list alphabetically sorted */ static const struct dmi_system_id byt_rt5640_quirk_table[] = { + { /* Acer Iconia One 7 B1-750 */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "VESPA2"), + }, + .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | + BYT_RT5640_JD_SRC_JD1_IN4P | + BYT_RT5640_OVCD_TH_1500UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { /* Acer Iconia Tab 8 W1-810 */ .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer"), @@ -400,6 +563,32 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF1 | BYT_RT5640_MCLK_EN), }, + { /* Acer One 10 S1002 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "One S1002"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_DIFF_MIC | + BYT_RT5640_SSP0_AIF2 | + BYT_RT5640_MCLK_EN), + }, + { /* Acer Aspire SW3-013 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW3-013"), + }, + .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_DIFF_MIC | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), @@ -413,6 +602,21 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_MCLK_EN), }, { + /* Advantech MICA-071 */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Advantech"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "MICA-071"), + }, + /* OVCD Th = 1500uA to reliable detect head-phones vs -set */ + .driver_data = (void *)(BYT_RT5640_IN3_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_1500UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_MONO_SPEAKER | + BYT_RT5640_DIFF_MIC | + BYT_RT5640_MCLK_EN), + }, + { .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ARCHOS"), DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ARCHOS 80 Cesium"), @@ -424,8 +628,19 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { }, { .matches = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ME176C"), + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ARCHOS"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ARCHOS 101 CESIUM"), + }, + .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | + BYT_RT5640_JD_NOT_INV | + BYT_RT5640_DIFF_MIC | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, + { + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ARCHOS"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ARCHOS 140 CESIUM"), }, .driver_data = (void *)(BYT_RT5640_IN1_MAP | BYT_RT5640_JD_SRC_JD2_IN4N | @@ -437,25 +652,56 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { { .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ME176C"), }, .driver_data = (void *)(BYT_RT5640_IN1_MAP | BYT_RT5640_JD_SRC_JD2_IN4N | BYT_RT5640_OVCD_TH_2000UA | BYT_RT5640_OVCD_SF_0P75 | - BYT_RT5640_MCLK_EN), + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN | + BYT_RT5640_USE_AMCR0F28), }, { + /* Asus T100TAF, unlike other T100TA* models this one has a mono speaker */ .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TAF"), }, .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | BYT_RT5640_MONO_SPEAKER | BYT_RT5640_DIFF_MIC | BYT_RT5640_SSP0_AIF2 | BYT_RT5640_MCLK_EN), }, + { + /* Asus T100TA and T100TAM, must come after T100TAF (mono spk) match */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_MCLK_EN), + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "TF103C"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_EXT_GPIO | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN | + BYT_RT5640_USE_AMCR0F28), + }, { /* Chuwi Vi8 (CWI506) */ .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Insyde"), @@ -468,6 +714,18 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF1 | BYT_RT5640_MCLK_EN), }, + { /* Chuwi Vi8 dual-boot (CWI506) */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "i86"), + /* The above are too generic, also match BIOS info */ + DMI_MATCH(DMI_BIOS_VERSION, "CHUWI2.D86JHBNR02"), + }, + .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | + BYT_RT5640_MONO_SPEAKER | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { /* Chuwi Vi10 (CWI505) */ .matches = { @@ -485,6 +743,23 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_MCLK_EN), }, { + /* Chuwi Hi8 (CWI509) */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Hampoo"), + DMI_MATCH(DMI_BOARD_NAME, "BYT-PA03C"), + DMI_MATCH(DMI_SYS_VENDOR, "ilife"), + DMI_MATCH(DMI_PRODUCT_NAME, "S806"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_MONO_SPEAKER | + BYT_RT5640_DIFF_MIC | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, + { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"), @@ -513,18 +788,66 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_MONO_SPEAKER | BYT_RT5640_MCLK_EN), }, + { /* Estar Beauty HD MID 7316R */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Estar"), + DMI_MATCH(DMI_PRODUCT_NAME, "eSTAR BEAUTY HD Intel Quad core"), + }, + .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | + BYT_RT5640_MONO_SPEAKER | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, + { /* Glavey TM800A550L */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), + /* Above strings are too generic, also match on BIOS version */ + DMI_MATCH(DMI_BIOS_VERSION, "ZY-8-BI-PX4S70VTR400-X423B-005-D"), + }, + .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP ElitePad 1000 G2"), }, - .driver_data = (void *)(BYT_RT5640_IN1_MAP | + .driver_data = (void *)(BYT_RT5640_DMIC2_MAP | + BYT_RT5640_MCLK_EN | + BYT_RT5640_LINEOUT | + BYT_RT5640_LINEOUT_AS_HP2 | + BYT_RT5640_HSMIC2_ON_IN1 | + BYT_RT5640_JD_HP_ELITEP_1000G2), + }, + { /* HP Pavilion x2 10-k0XX, 10-n0XX */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"), + }, + .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_1500UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_SSP0_AIF1 | BYT_RT5640_MCLK_EN), }, - { /* HP Pavilion x2 10-n000nd */ + { /* HP Pavilion x2 10-p0XX */ .matches = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"), + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP x2 Detachable 10-p0XX"), + }, + .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | + BYT_RT5640_JD_SRC_JD1_IN4P | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_MCLK_EN), + }, + { /* HP Pro Tablet 408 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pro Tablet 408"), }, .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | BYT_RT5640_JD_SRC_JD2_IN4N | @@ -544,6 +867,16 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF1 | BYT_RT5640_MCLK_EN), }, + { /* HP Stream 8 */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP Stream 8 Tablet"), + }, + .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | + BYT_RT5640_JD_NOT_INV | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { /* I.T.Works TW891 */ .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."), @@ -580,6 +913,20 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_MONO_SPEAKER | BYT_RT5640_MCLK_EN), }, + { /* Lenovo Miix 3-830 */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 3-830"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_MONO_SPEAKER | + BYT_RT5640_DIFF_MIC | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { /* Linx Linx7 tablet */ .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LINX"), @@ -591,6 +938,28 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF1 | BYT_RT5640_MCLK_EN), }, + { + /* Medion Lifetab S10346 */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), + /* Above strings are much too generic, also match on BIOS date */ + DMI_MATCH(DMI_BIOS_DATE, "10/22/2015"), + }, + .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | + BYT_RT5640_SWAPPED_SPEAKERS | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, + { /* Mele PCG03 Mini PC */ + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Mini PC"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "Mini PC"), + }, + .driver_data = (void *)(BYT_RT5640_NO_INTERNAL_MIC_MAP | + BYT_RT5640_NO_SPEAKERS | + BYT_RT5640_SSP0_AIF1), + }, { /* MPMAN Converter 9, similar hw as the I.T.Works TW891 2-in-1 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MPMAN"), @@ -776,6 +1145,50 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF2 | BYT_RT5640_MCLK_EN), }, + { + /* Vexia Edu Atla 10 tablet 5V version */ + .matches = { + /* Having all 3 of these not set is somewhat unique */ + DMI_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."), + DMI_MATCH(DMI_PRODUCT_NAME, "To be filled by O.E.M."), + DMI_MATCH(DMI_BOARD_NAME, "To be filled by O.E.M."), + /* Above strings are too generic, also match on BIOS date */ + DMI_MATCH(DMI_BIOS_DATE, "05/14/2015"), + }, + .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | + BYT_RT5640_JD_NOT_INV | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, + { /* Vexia Edu Atla 10 tablet 9V version */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), + /* Above strings are too generic, also match on BIOS date */ + DMI_MATCH(DMI_BIOS_DATE, "08/25/2014"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_DIFF_MIC | + BYT_RT5640_SSP0_AIF2 | + BYT_RT5640_MCLK_EN), + }, + { /* Voyo Winpad A15 */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), + /* Above strings are too generic, also match on BIOS date */ + DMI_MATCH(DMI_BIOS_DATE, "11/20/2014"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_DIFF_MIC | + BYT_RT5640_MCLK_EN), + }, { /* Catch-all for generic Insyde tablets, must be last */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), @@ -792,15 +1205,13 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { * Note this MUST be called before snd_soc_register_card(), so that the props * are in place before the codec component driver's probe function parses them. */ -static int byt_rt5640_add_codec_device_props(const char *i2c_dev_name) +static int byt_rt5640_add_codec_device_props(struct device *i2c_dev, + struct byt_rt5640_private *priv) { struct property_entry props[MAX_NO_PROPS] = {}; - struct device *i2c_dev; - int ret, cnt = 0; - - i2c_dev = bus_find_device_by_name(&i2c_bus_type, NULL, i2c_dev_name); - if (!i2c_dev) - return -EPROBE_DEFER; + struct fwnode_handle *fwnode; + int cnt = 0; + int ret; switch (BYT_RT5640_MAP(byt_rt5640_quirk)) { case BYT_RT5640_DMIC1_MAP: @@ -824,9 +1235,11 @@ static int byt_rt5640_add_codec_device_props(const char *i2c_dev_name) } if (BYT_RT5640_JDSRC(byt_rt5640_quirk)) { - props[cnt++] = PROPERTY_ENTRY_U32( - "realtek,jack-detect-source", - BYT_RT5640_JDSRC(byt_rt5640_quirk)); + if (BYT_RT5640_JDSRC(byt_rt5640_quirk) != RT5640_JD_SRC_EXT_GPIO) { + props[cnt++] = PROPERTY_ENTRY_U32( + "realtek,jack-detect-source", + BYT_RT5640_JDSRC(byt_rt5640_quirk)); + } props[cnt++] = PROPERTY_ENTRY_U32( "realtek,over-current-threshold-microamp", @@ -840,9 +1253,61 @@ static int byt_rt5640_add_codec_device_props(const char *i2c_dev_name) if (byt_rt5640_quirk & BYT_RT5640_JD_NOT_INV) props[cnt++] = PROPERTY_ENTRY_BOOL("realtek,jack-detect-not-inverted"); - ret = device_add_properties(i2c_dev, props); - put_device(i2c_dev); + fwnode = fwnode_create_software_node(props, NULL); + if (IS_ERR(fwnode)) { + /* put_device() is handled in caller */ + return PTR_ERR(fwnode); + } + + ret = device_add_software_node(i2c_dev, to_software_node(fwnode)); + + fwnode_handle_put(fwnode); + + return ret; +} + +/* Some Android devs specify IRQs/GPIOS in a special AMCR0F28 ACPI device */ +static const struct acpi_gpio_params amcr0f28_jd_gpio = { 1, 0, false }; + +static const struct acpi_gpio_mapping amcr0f28_gpios[] = { + { "rt5640-jd-gpios", &amcr0f28_jd_gpio, 1 }, + { } +}; + +static int byt_rt5640_get_amcr0f28_settings(struct snd_soc_card *card) +{ + struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card); + struct rt5640_set_jack_data *data = &priv->jack_data; + struct acpi_device *adev; + int ret = 0; + + adev = acpi_dev_get_first_match_dev("AMCR0F28", "1", -1); + if (!adev) { + dev_err(card->dev, "error cannot find AMCR0F28 adev\n"); + return -ENOENT; + } + + data->codec_irq_override = acpi_dev_gpio_irq_get(adev, 0); + if (data->codec_irq_override < 0) { + ret = data->codec_irq_override; + dev_err(card->dev, "error %d getting codec IRQ\n", ret); + goto put_adev; + } + + if (BYT_RT5640_JDSRC(byt_rt5640_quirk) == RT5640_JD_SRC_EXT_GPIO) { + acpi_dev_add_driver_gpios(adev, amcr0f28_gpios); + data->jd_gpio = devm_fwnode_gpiod_get(card->dev, acpi_fwnode_handle(adev), + "rt5640-jd", GPIOD_IN, "rt5640-jd"); + acpi_dev_remove_driver_gpios(adev); + if (IS_ERR(data->jd_gpio)) { + ret = PTR_ERR(data->jd_gpio); + dev_err(card->dev, "error %d getting jd GPIO\n", ret); + } + } + +put_adev: + acpi_dev_put(adev); return ret; } @@ -850,12 +1315,14 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) { struct snd_soc_card *card = runtime->card; struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card); - struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component; - const struct snd_soc_dapm_route *custom_map; - int num_routes; + struct rt5640_set_jack_data *jack_data = &priv->jack_data; + struct snd_soc_component *component = snd_soc_rtd_to_codec(runtime, 0)->component; + const struct snd_soc_dapm_route *custom_map = NULL; + int num_routes = 0; int ret; card->dapm.idle_bias_off = true; + jack_data->use_platform_clock = true; /* Start with RC clk for jack-detect (we disable MCLK below) */ if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN) @@ -887,19 +1354,28 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) custom_map = byt_rt5640_intmic_in3_map; num_routes = ARRAY_SIZE(byt_rt5640_intmic_in3_map); break; + case BYT_RT5640_DMIC1_MAP: + custom_map = byt_rt5640_intmic_dmic1_map; + num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map); + break; case BYT_RT5640_DMIC2_MAP: custom_map = byt_rt5640_intmic_dmic2_map; num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic2_map); break; - default: - custom_map = byt_rt5640_intmic_dmic1_map; - num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map); } ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); if (ret) return ret; + if (byt_rt5640_quirk & BYT_RT5640_HSMIC2_ON_IN1) { + ret = snd_soc_dapm_add_routes(&card->dapm, + byt_rt5640_hsmic2_in1_map, + ARRAY_SIZE(byt_rt5640_hsmic2_in1_map)); + if (ret) + return ret; + } + if (byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) { ret = snd_soc_dapm_add_routes(&card->dapm, byt_rt5640_ssp2_aif2_map, @@ -924,7 +1400,7 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) ret = snd_soc_dapm_add_routes(&card->dapm, byt_rt5640_mono_spk_map, ARRAY_SIZE(byt_rt5640_mono_spk_map)); - } else { + } else if (!(byt_rt5640_quirk & BYT_RT5640_NO_SPEAKERS)) { ret = snd_soc_dapm_add_routes(&card->dapm, byt_rt5640_stereo_spk_map, ARRAY_SIZE(byt_rt5640_stereo_spk_map)); @@ -932,49 +1408,103 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) if (ret) return ret; - if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN) { - /* - * The firmware might enable the clock at - * boot (this information may or may not - * be reflected in the enable clock register). - * To change the rate we must disable the clock - * first to cover these cases. Due to common - * clock framework restrictions that do not allow - * to disable a clock that has not been enabled, - * we need to enable the clock first. - */ - ret = clk_prepare_enable(priv->mclk); - if (!ret) - clk_disable_unprepare(priv->mclk); - - if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) - ret = clk_set_rate(priv->mclk, 25000000); - else - ret = clk_set_rate(priv->mclk, 19200000); - - if (ret) { - dev_err(card->dev, "unable to set MCLK rate\n"); + if (byt_rt5640_quirk & BYT_RT5640_LINEOUT) { + ret = snd_soc_dapm_add_routes(&card->dapm, + byt_rt5640_lineout_map, + ARRAY_SIZE(byt_rt5640_lineout_map)); + if (ret) return ret; - } + } + + /* + * The firmware might enable the clock at boot (this information + * may or may not be reflected in the enable clock register). + * To change the rate we must disable the clock first to cover + * these cases. Due to common clock framework restrictions that + * do not allow to disable a clock that has not been enabled, + * we need to enable the clock first. + */ + ret = clk_prepare_enable(priv->mclk); + if (!ret) + clk_disable_unprepare(priv->mclk); + + if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) + ret = clk_set_rate(priv->mclk, 25000000); + else + ret = clk_set_rate(priv->mclk, 19200000); + if (ret) { + dev_err(card->dev, "unable to set MCLK rate\n"); + return ret; } if (BYT_RT5640_JDSRC(byt_rt5640_quirk)) { - ret = snd_soc_card_jack_new(card, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0, - &priv->jack, rt5640_pins, - ARRAY_SIZE(rt5640_pins)); + ret = snd_soc_card_jack_new_pins(card, "Headset", + SND_JACK_HEADSET | SND_JACK_BTN_0, + &priv->jack, rt5640_pins, + ARRAY_SIZE(rt5640_pins)); if (ret) { dev_err(card->dev, "Jack creation failed %d\n", ret); return ret; } snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_soc_component_set_jack(component, &priv->jack, NULL); + + if (byt_rt5640_quirk & BYT_RT5640_USE_AMCR0F28) { + ret = byt_rt5640_get_amcr0f28_settings(card); + if (ret) + return ret; + } + + snd_soc_component_set_jack(component, &priv->jack, &priv->jack_data); + } + + if (byt_rt5640_quirk & BYT_RT5640_JD_HP_ELITEP_1000G2) { + ret = snd_soc_card_jack_new_pins(card, "Headset", + SND_JACK_HEADSET, + &priv->jack, rt5640_pins, + ARRAY_SIZE(rt5640_pins)); + if (ret) + return ret; + + ret = snd_soc_card_jack_new_pins(card, "Headset 2", + SND_JACK_HEADSET, + &priv->jack2, rt5640_pins2, + ARRAY_SIZE(rt5640_pins2)); + if (ret) + return ret; + + rt5640_jack_gpio.data = priv; + rt5640_jack_gpio.gpiod_dev = priv->codec_dev; + rt5640_jack_gpio.jack_status_check = byt_rt5640_hp_elitepad_1000g2_jack1_check; + ret = snd_soc_jack_add_gpios(&priv->jack, 1, &rt5640_jack_gpio); + if (ret) + return ret; + + rt5640_set_ovcd_params(component); + rt5640_jack2_gpio.data = component; + rt5640_jack2_gpio.gpiod_dev = priv->codec_dev; + rt5640_jack2_gpio.jack_status_check = byt_rt5640_hp_elitepad_1000g2_jack2_check; + ret = snd_soc_jack_add_gpios(&priv->jack2, 1, &rt5640_jack2_gpio); + if (ret) { + snd_soc_jack_free_gpios(&priv->jack, 1, &rt5640_jack_gpio); + return ret; + } } return 0; } +static void byt_rt5640_exit(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_card *card = runtime->card; + struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card); + + if (byt_rt5640_quirk & BYT_RT5640_JD_HP_ELITEP_1000G2) { + snd_soc_jack_free_gpios(&priv->jack2, 1, &rt5640_jack2_gpio); + snd_soc_jack_free_gpios(&priv->jack, 1, &rt5640_jack_gpio); + } +} + static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -984,7 +1514,7 @@ static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd, SNDRV_PCM_HW_PARAM_CHANNELS); int ret, bits; - /* The DSP will covert the FE rate to 48k, stereo */ + /* The DSP will convert the FE rate to 48k, stereo */ rate->min = rate->max = 48000; channels->min = channels->max = 2; @@ -1004,16 +1534,16 @@ static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd, * with explicit setting to I2S 2ch. The word length is set with * dai_set_tdm_slot() since there is no other API exposed */ - ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), + ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_BP_FP); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); return ret; } - ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, bits); + ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, bits); if (ret < 0) { dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); return ret; @@ -1062,8 +1592,6 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { .stream_name = "Baytrail Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &byt_rt5640_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -1072,7 +1600,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &byt_rt5640_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -1082,12 +1610,10 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { .id = 0, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS, + | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = byt_rt5640_codec_fixup, - .nonatomic = true, - .dpcm_playback = 1, - .dpcm_capture = 1, .init = byt_rt5640_init, + .exit = byt_rt5640_exit, .ops = &byt_rt5640_be_ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, @@ -1098,7 +1624,7 @@ static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN]; #if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES) static char byt_rt5640_long_name[40]; /* = "bytcr-rt5640-*-spk-*-mic" */ #endif -static char byt_rt5640_components[32]; /* = "cfg-spk:* cfg-mic:*" */ +static char byt_rt5640_components[64]; /* = "cfg-spk:* cfg-mic:* ..." */ static int byt_rt5640_suspend(struct snd_soc_card *card) { @@ -1129,7 +1655,8 @@ static int byt_rt5640_resume(struct snd_soc_card *card) for_each_card_components(card, component) { if (!strcmp(component->name, byt_rt5640_codec_name)) { dev_dbg(component->dev, "re-enabling jack detect after resume\n"); - snd_soc_component_set_jack(component, &priv->jack, NULL); + snd_soc_component_set_jack(component, &priv->jack, + &priv->jack_data); break; } } @@ -1137,18 +1664,14 @@ static int byt_rt5640_resume(struct snd_soc_card *card) return 0; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) /* use space before codec name to simplify card ID, and simplify driver name */ -#define CARD_NAME "bytcht rt5640" /* card name will be 'sof-bytcht rt5640' */ -#define DRIVER_NAME "SOF" -#else +#define SOF_CARD_NAME "bytcht rt5640" /* card name will be 'sof-bytcht rt5640' */ +#define SOF_DRIVER_NAME "SOF" + #define CARD_NAME "bytcr-rt5640" #define DRIVER_NAME NULL /* card name will be used for driver name */ -#endif static struct snd_soc_card byt_rt5640_card = { - .name = CARD_NAME, - .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = byt_rt5640_dais, .num_links = ARRAY_SIZE(byt_rt5640_dais), @@ -1168,29 +1691,36 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) { - static const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" }; + struct device *dev = &pdev->dev; + static const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3", "none" }; + struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); + __maybe_unused const char *spk_type; const struct dmi_system_id *dmi_id; + const char *headset2_string = ""; + const char *lineout_string = ""; struct byt_rt5640_private *priv; - struct snd_soc_acpi_mach *mach; const char *platform_name; struct acpi_device *adev; + struct device *codec_dev; + const char *cfg_spk; + bool sof_parent; int ret_val = 0; int dai_index = 0; - int i; + int i, aif; is_bytcr = false; - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; /* register the soc card */ - byt_rt5640_card.dev = &pdev->dev; - mach = byt_rt5640_card.dev->platform_data; + byt_rt5640_card.dev = dev; snd_soc_card_set_drvdata(&byt_rt5640_card, priv); /* fix index of codec dai */ for (i = 0; i < ARRAY_SIZE(byt_rt5640_dais); i++) { - if (!strcmp(byt_rt5640_dais[i].codecs->name, + if (byt_rt5640_dais[i].num_codecs && + !strcmp(byt_rt5640_dais[i].codecs->name, "i2c-10EC5640:00")) { dai_index = i; break; @@ -1202,8 +1732,40 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) if (adev) { snprintf(byt_rt5640_codec_name, sizeof(byt_rt5640_codec_name), "i2c-%s", acpi_dev_name(adev)); - put_device(&adev->dev); byt_rt5640_dais[dai_index].codecs->name = byt_rt5640_codec_name; + } else { + dev_err(dev, "Error cannot find '%s' dev\n", mach->id); + return -ENOENT; + } + + codec_dev = acpi_get_first_physical_node(adev); + acpi_dev_put(adev); + + if (codec_dev) { + priv->codec_dev = get_device(codec_dev); + } else { + /* + * Special case for Android tablets where the codec i2c_client + * has been manually instantiated by x86_android_tablets.ko due + * to a broken DSDT. + */ + codec_dev = bus_find_device_by_name(&i2c_bus_type, NULL, + BYT_RT5640_FALLBACK_CODEC_DEV_NAME); + if (!codec_dev) + return -EPROBE_DEFER; + + if (!i2c_verify_client(codec_dev)) { + dev_err(dev, "Error '%s' is not an i2c_client\n", + BYT_RT5640_FALLBACK_CODEC_DEV_NAME); + put_device(codec_dev); + } + + /* fixup codec name */ + strscpy(byt_rt5640_codec_name, BYT_RT5640_FALLBACK_CODEC_DEV_NAME, + sizeof(byt_rt5640_codec_name)); + + /* bus_find_device() returns a reference no need to get() */ + priv->codec_dev = codec_dev; } /* @@ -1224,7 +1786,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) * with the codec driver/pdata are non-existent */ - struct acpi_chan_package chan_package; + struct acpi_chan_package chan_package = { 0 }; /* format specified: 2 64-bit integers */ struct acpi_buffer format = {sizeof("NN"), "NN"}; @@ -1245,13 +1807,13 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) &pkg_ctx); if (pkg_found) { if (chan_package.aif_value == 1) { - dev_info(&pdev->dev, "BIOS Routing: AIF1 connected\n"); + dev_info(dev, "BIOS Routing: AIF1 connected\n"); byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF1; } else if (chan_package.aif_value == 2) { - dev_info(&pdev->dev, "BIOS Routing: AIF2 connected\n"); + dev_info(dev, "BIOS Routing: AIF2 connected\n"); byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF2; } else { - dev_info(&pdev->dev, "BIOS Routing isn't valid, ignored\n"); + dev_info(dev, "BIOS Routing isn't valid, ignored\n"); pkg_found = false; } } @@ -1275,87 +1837,154 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) if (dmi_id) byt_rt5640_quirk = (unsigned long)dmi_id->driver_data; if (quirk_override != -1) { - dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n", + dev_info(dev, "Overriding quirk 0x%lx => 0x%x\n", byt_rt5640_quirk, quirk_override); byt_rt5640_quirk = quirk_override; } + if (byt_rt5640_quirk & BYT_RT5640_JD_HP_ELITEP_1000G2) { + acpi_dev_add_driver_gpios(ACPI_COMPANION(priv->codec_dev), + byt_rt5640_hp_elitepad_1000g2_gpios); + + priv->hsmic_detect = devm_fwnode_gpiod_get(dev, codec_dev->fwnode, + "headset-mic-detect", GPIOD_IN, + "headset-mic-detect"); + if (IS_ERR(priv->hsmic_detect)) { + ret_val = dev_err_probe(dev, PTR_ERR(priv->hsmic_detect), + "getting hsmic-detect GPIO\n"); + goto err_device; + } + } + /* Must be called before register_card, also see declaration comment. */ - ret_val = byt_rt5640_add_codec_device_props(byt_rt5640_codec_name); + ret_val = byt_rt5640_add_codec_device_props(codec_dev, priv); if (ret_val) - return ret_val; + goto err_remove_gpios; - log_quirks(&pdev->dev); + log_quirks(dev); if ((byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) || - (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) + (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) { byt_rt5640_dais[dai_index].codecs->dai_name = "rt5640-aif2"; + aif = 2; + } else { + aif = 1; + } if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) || (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) byt_rt5640_dais[dai_index].cpus->dai_name = "ssp0-port"; if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN) { - priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); + priv->mclk = devm_clk_get_optional(dev, "pmc_plt_clk_3"); if (IS_ERR(priv->mclk)) { - ret_val = PTR_ERR(priv->mclk); - - dev_err(&pdev->dev, - "Failed to get MCLK from pmc_plt_clk_3: %d\n", - ret_val); - - /* - * Fall back to bit clock usage for -ENOENT (clock not - * available likely due to missing dependencies), bail - * for all other errors, including -EPROBE_DEFER - */ - if (ret_val != -ENOENT) - return ret_val; - byt_rt5640_quirk &= ~BYT_RT5640_MCLK_EN; + ret_val = dev_err_probe(dev, PTR_ERR(priv->mclk), + "Failed to get MCLK from pmc_plt_clk_3\n"); + goto err; } + /* + * Fall back to bit clock usage when clock is not + * available likely due to missing dependencies. + */ + if (!priv->mclk) + byt_rt5640_quirk &= ~BYT_RT5640_MCLK_EN; + } + + if (byt_rt5640_quirk & BYT_RT5640_NO_SPEAKERS) { + cfg_spk = "0"; + spk_type = "none"; + } else if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) { + cfg_spk = "1"; + spk_type = "mono"; + } else if (byt_rt5640_quirk & BYT_RT5640_SWAPPED_SPEAKERS) { + cfg_spk = "swapped"; + spk_type = "swapped"; + } else { + cfg_spk = "2"; + spk_type = "stereo"; } + if (byt_rt5640_quirk & BYT_RT5640_LINEOUT) { + if (byt_rt5640_quirk & BYT_RT5640_LINEOUT_AS_HP2) + lineout_string = " cfg-hp2:lineout"; + else + lineout_string = " cfg-lineout:2"; + } + + if (byt_rt5640_quirk & BYT_RT5640_HSMIC2_ON_IN1) + headset2_string = " cfg-hs2:in1"; + snprintf(byt_rt5640_components, sizeof(byt_rt5640_components), - "cfg-spk:%s cfg-mic:%s", - (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) ? "1" : "2", - map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]); + "cfg-spk:%s cfg-mic:%s aif:%d%s%s", cfg_spk, + map_name[BYT_RT5640_MAP(byt_rt5640_quirk)], aif, + lineout_string, headset2_string); byt_rt5640_card.components = byt_rt5640_components; #if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES) snprintf(byt_rt5640_long_name, sizeof(byt_rt5640_long_name), - "bytcr-rt5640-%s-spk-%s-mic", - (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) ? - "mono" : "stereo", + "bytcr-rt5640-%s-spk-%s-mic", spk_type, map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]); byt_rt5640_card.long_name = byt_rt5640_long_name; #endif - /* override plaform name, if required */ + /* override platform name, if required */ platform_name = mach->mach_params.platform; ret_val = snd_soc_fixup_dai_links_platform_name(&byt_rt5640_card, platform_name); if (ret_val) - return ret_val; + goto err; - ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card); + sof_parent = snd_soc_acpi_sof_parent(dev); + /* set card and driver name */ + if (sof_parent) { + byt_rt5640_card.name = SOF_CARD_NAME; + byt_rt5640_card.driver_name = SOF_DRIVER_NAME; + } else { + byt_rt5640_card.name = CARD_NAME; + byt_rt5640_card.driver_name = DRIVER_NAME; + } + + /* set pm ops */ + if (sof_parent) + dev->driver->pm = &snd_soc_pm_ops; + + ret_val = devm_snd_soc_register_card(dev, &byt_rt5640_card); if (ret_val) { - dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n", - ret_val); - return ret_val; + dev_err(dev, "devm_snd_soc_register_card failed %d\n", ret_val); + goto err; } platform_set_drvdata(pdev, &byt_rt5640_card); return ret_val; + +err: + device_remove_software_node(priv->codec_dev); +err_remove_gpios: + if (byt_rt5640_quirk & BYT_RT5640_JD_HP_ELITEP_1000G2) + acpi_dev_remove_driver_gpios(ACPI_COMPANION(priv->codec_dev)); +err_device: + put_device(priv->codec_dev); + return ret_val; +} + +static void snd_byt_rt5640_mc_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card); + + if (byt_rt5640_quirk & BYT_RT5640_JD_HP_ELITEP_1000G2) + acpi_dev_remove_driver_gpios(ACPI_COMPANION(priv->codec_dev)); + + device_remove_software_node(priv->codec_dev); + put_device(priv->codec_dev); } static struct platform_driver snd_byt_rt5640_mc_driver = { .driver = { .name = "bytcr_rt5640", -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - .pm = &snd_soc_pm_ops, -#endif }, .probe = snd_byt_rt5640_mc_probe, + .remove = snd_byt_rt5640_mc_remove, }; module_platform_driver(snd_byt_rt5640_mc_driver); diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 688b5e0a49e3..67c62844ca2a 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -85,6 +85,7 @@ struct byt_rt5651_private { struct gpio_desc *ext_amp_gpio; struct gpio_desc *hp_detect; struct snd_soc_jack jack; + struct device *codec_dev; }; static const struct acpi_gpio_mapping *byt_rt5651_gpios; @@ -143,7 +144,7 @@ static int byt_rt5651_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai, /* Configure the PLL before selecting it */ if (!(byt_rt5651_quirk & BYT_RT5651_MCLK_EN)) { - clk_id = RT5651_PLL1_S_BCLK1, + clk_id = RT5651_PLL1_S_BCLK1; clk_freq = rate * bclk_ratio; } else { clk_id = RT5651_PLL1_S_MCLK; @@ -187,13 +188,10 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, } if (SND_SOC_DAPM_EVENT_ON(event)) { - if (byt_rt5651_quirk & BYT_RT5651_MCLK_EN) { - ret = clk_prepare_enable(priv->mclk); - if (ret < 0) { - dev_err(card->dev, - "could not configure MCLK state"); - return ret; - } + ret = clk_prepare_enable(priv->mclk); + if (ret < 0) { + dev_err(card->dev, "could not configure MCLK state"); + return ret; } ret = byt_rt5651_prepare_and_enable_pll1(codec_dai, 48000, 50); } else { @@ -206,8 +204,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, 48000 * 512, SND_SOC_CLOCK_IN); if (!ret) - if (byt_rt5651_quirk & BYT_RT5651_MCLK_EN) - clk_disable_unprepare(priv->mclk); + clk_disable_unprepare(priv->mclk); } if (ret < 0) { @@ -347,8 +344,8 @@ static struct snd_soc_jack_pin bytcr_jack_pins[] = { static int byt_rt5651_aif1_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); snd_pcm_format_t format = params_format(params); int rate = params_rate(params); int bclk_ratio; @@ -436,6 +433,19 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = { BYT_RT5651_MONO_SPEAKER), }, { + /* Jumper EZpad 7 */ + .callback = byt_rt5651_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Jumper"), + DMI_MATCH(DMI_PRODUCT_NAME, "EZpad"), + /* Jumper12x.WJ2012.bsBKRCP05 with the version dropped */ + DMI_MATCH(DMI_BIOS_VERSION, "Jumper12x.WJ2012.bsBKRCP"), + }, + .driver_data = (void *)(BYT_RT5651_DEFAULT_QUIRKS | + BYT_RT5651_IN2_MAP | + BYT_RT5651_JD_NOT_INV), + }, + { /* KIANO SlimNote 14.2 */ .callback = byt_rt5651_quirk_cb, .matches = { @@ -514,10 +524,13 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = { * Note this MUST be called before snd_soc_register_card(), so that the props * are in place before the codec component driver's probe function parses them. */ -static int byt_rt5651_add_codec_device_props(struct device *i2c_dev) +static int byt_rt5651_add_codec_device_props(struct device *i2c_dev, + struct byt_rt5651_private *priv) { struct property_entry props[MAX_NO_PROPS] = {}; + struct fwnode_handle *fwnode; int cnt = 0; + int ret; props[cnt++] = PROPERTY_ENTRY_U32("realtek,jack-detect-source", BYT_RT5651_JDSRC(byt_rt5651_quirk)); @@ -534,13 +547,23 @@ static int byt_rt5651_add_codec_device_props(struct device *i2c_dev) if (byt_rt5651_quirk & BYT_RT5651_JD_NOT_INV) props[cnt++] = PROPERTY_ENTRY_BOOL("realtek,jack-detect-not-inverted"); - return device_add_properties(i2c_dev, props); + fwnode = fwnode_create_software_node(props, NULL); + if (IS_ERR(fwnode)) { + /* put_device(i2c_dev) is handled in caller */ + return PTR_ERR(fwnode); + } + + ret = device_add_software_node(i2c_dev, to_software_node(fwnode)); + + fwnode_handle_put(fwnode); + + return ret; } static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) { struct snd_soc_card *card = runtime->card; - struct snd_soc_component *codec = asoc_rtd_to_codec(runtime, 0)->component; + struct snd_soc_component *codec = snd_soc_rtd_to_codec(runtime, 0)->component; struct byt_rt5651_private *priv = snd_soc_card_get_drvdata(card); const struct snd_soc_dapm_route *custom_map; int num_routes; @@ -602,29 +625,25 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) return ret; } - if (byt_rt5651_quirk & BYT_RT5651_MCLK_EN) { - /* - * The firmware might enable the clock at - * boot (this information may or may not - * be reflected in the enable clock register). - * To change the rate we must disable the clock - * first to cover these cases. Due to common - * clock framework restrictions that do not allow - * to disable a clock that has not been enabled, - * we need to enable the clock first. - */ - ret = clk_prepare_enable(priv->mclk); - if (!ret) - clk_disable_unprepare(priv->mclk); + /* + * The firmware might enable the clock at boot (this information + * may or may not be reflected in the enable clock register). + * To change the rate we must disable the clock first to cover + * these cases. Due to common clock framework restrictions that + * do not allow to disable a clock that has not been enabled, + * we need to enable the clock first. + */ + ret = clk_prepare_enable(priv->mclk); + if (!ret) + clk_disable_unprepare(priv->mclk); - if (byt_rt5651_quirk & BYT_RT5651_MCLK_25MHZ) - ret = clk_set_rate(priv->mclk, 25000000); - else - ret = clk_set_rate(priv->mclk, 19200000); + if (byt_rt5651_quirk & BYT_RT5651_MCLK_25MHZ) + ret = clk_set_rate(priv->mclk, 25000000); + else + ret = clk_set_rate(priv->mclk, 19200000); - if (ret) - dev_err(card->dev, "unable to set MCLK rate\n"); - } + if (ret) + dev_err(card->dev, "unable to set MCLK rate\n"); report = 0; if (BYT_RT5651_JDSRC(byt_rt5651_quirk)) @@ -633,9 +652,10 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) report = SND_JACK_HEADSET; if (report) { - ret = snd_soc_card_jack_new(runtime->card, "Headset", - report, &priv->jack, bytcr_jack_pins, - ARRAY_SIZE(bytcr_jack_pins)); + ret = snd_soc_card_jack_new_pins(runtime->card, "Headset", + report, &priv->jack, + bytcr_jack_pins, + ARRAY_SIZE(bytcr_jack_pins)); if (ret) { dev_err(runtime->dev, "jack creation failed %d\n", ret); return ret; @@ -663,7 +683,7 @@ static int byt_rt5651_codec_fixup(struct snd_soc_pcm_runtime *rtd, SNDRV_PCM_HW_PARAM_CHANNELS); int ret, bits; - /* The DSP will covert the FE rate to 48k, stereo */ + /* The DSP will convert the FE rate to 48k, stereo */ rate->min = rate->max = 48000; channels->min = channels->max = 2; @@ -683,10 +703,10 @@ static int byt_rt5651_codec_fixup(struct snd_soc_pcm_runtime *rtd, * with explicit setting to I2S 2ch. The word length is set with * dai_set_tdm_slot() since there is no other API exposed */ - ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), + ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS + SND_SOC_DAIFMT_BP_FP ); if (ret < 0) { @@ -694,7 +714,7 @@ static int byt_rt5651_codec_fixup(struct snd_soc_pcm_runtime *rtd, return ret; } - ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, bits); + ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, bits); if (ret < 0) { dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); return ret; @@ -750,8 +770,6 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &byt_rt5651_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -760,7 +778,7 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &byt_rt5651_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -771,11 +789,8 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = { .id = 0, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS, + | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = byt_rt5651_codec_fixup, - .nonatomic = true, - .dpcm_playback = 1, - .dpcm_capture = 1, .init = byt_rt5651_init, .ops = &byt_rt5651_be_ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), @@ -827,14 +842,12 @@ static int byt_rt5651_resume(struct snd_soc_card *card) return 0; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) /* use space before codec name to simplify card ID, and simplify driver name */ -#define CARD_NAME "bytcht rt5651" /* card name will be 'sof-bytcht rt5651' */ -#define DRIVER_NAME "SOF" -#else +#define SOF_CARD_NAME "bytcht rt5651" /* card name will be 'sof-bytcht rt5651' */ +#define SOF_DRIVER_NAME "SOF" + #define CARD_NAME "bytcr-rt5651" #define DRIVER_NAME NULL /* card name will be used for driver name */ -#endif static struct snd_soc_card byt_rt5651_card = { .name = CARD_NAME, @@ -870,30 +883,31 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; static const char * const mic_name[] = { "dmic", "in1", "in2", "in12" }; + struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); struct byt_rt5651_private *priv; - struct snd_soc_acpi_mach *mach; const char *platform_name; struct acpi_device *adev; struct device *codec_dev; + bool sof_parent; bool is_bytcr = false; int ret_val = 0; int dai_index = 0; int i; - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; /* register the soc card */ - byt_rt5651_card.dev = &pdev->dev; - - mach = byt_rt5651_card.dev->platform_data; + byt_rt5651_card.dev = dev; snd_soc_card_set_drvdata(&byt_rt5651_card, priv); /* fix index of codec dai */ for (i = 0; i < ARRAY_SIZE(byt_rt5651_dais); i++) { - if (!strcmp(byt_rt5651_dais[i].codecs->name, + if (byt_rt5651_dais[i].num_codecs && + !strcmp(byt_rt5651_dais[i].codecs->name, "i2c-10EC5651:00")) { dai_index = i; break; @@ -905,17 +919,17 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) if (adev) { snprintf(byt_rt5651_codec_name, sizeof(byt_rt5651_codec_name), "i2c-%s", acpi_dev_name(adev)); - put_device(&adev->dev); byt_rt5651_dais[dai_index].codecs->name = byt_rt5651_codec_name; } else { - dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); - return -ENODEV; + dev_err(dev, "Error cannot find '%s' dev\n", mach->id); + return -ENOENT; } - codec_dev = bus_find_device_by_name(&i2c_bus_type, NULL, - byt_rt5651_codec_name); + codec_dev = acpi_get_first_physical_node(adev); + acpi_dev_put(adev); if (!codec_dev) return -EPROBE_DEFER; + priv->codec_dev = get_device(codec_dev); /* * swap SSP0 if bytcr is detected @@ -935,7 +949,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) * with the codec driver/pdata are non-existent */ - struct acpi_chan_package chan_package; + struct acpi_chan_package chan_package = { 0 }; /* format specified: 2 64-bit integers */ struct acpi_buffer format = {sizeof("NN"), "NN"}; @@ -956,13 +970,13 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) &pkg_ctx); if (pkg_found) { if (chan_package.aif_value == 1) { - dev_info(&pdev->dev, "BIOS Routing: AIF1 connected\n"); + dev_info(dev, "BIOS Routing: AIF1 connected\n"); byt_rt5651_quirk |= BYT_RT5651_SSP0_AIF1; } else if (chan_package.aif_value == 2) { - dev_info(&pdev->dev, "BIOS Routing: AIF2 connected\n"); + dev_info(dev, "BIOS Routing: AIF2 connected\n"); byt_rt5651_quirk |= BYT_RT5651_SSP0_AIF2; } else { - dev_info(&pdev->dev, "BIOS Routing isn't valid, ignored\n"); + dev_info(dev, "BIOS Routing isn't valid, ignored\n"); pkg_found = false; } } @@ -977,17 +991,15 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) dmi_check_system(byt_rt5651_quirk_table); if (quirk_override != -1) { - dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n", + dev_info(dev, "Overriding quirk 0x%lx => 0x%x\n", byt_rt5651_quirk, quirk_override); byt_rt5651_quirk = quirk_override; } /* Must be called before register_card, also see declaration comment. */ - ret_val = byt_rt5651_add_codec_device_props(codec_dev); - if (ret_val) { - put_device(codec_dev); - return ret_val; - } + ret_val = byt_rt5651_add_codec_device_props(codec_dev, priv); + if (ret_val) + goto err_device; /* Cherry Trail devices use an external amplifier enable gpio */ if (soc_intel_is_cht() && !byt_rt5651_gpios) @@ -995,8 +1007,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) if (byt_rt5651_gpios) { devm_acpi_dev_add_driver_gpios(codec_dev, byt_rt5651_gpios); - priv->ext_amp_gpio = devm_fwnode_gpiod_get(&pdev->dev, - codec_dev->fwnode, + priv->ext_amp_gpio = devm_fwnode_gpiod_get(dev, codec_dev->fwnode, "ext-amp-enable", GPIOD_OUT_LOW, "speaker-amp"); @@ -1007,16 +1018,13 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) priv->ext_amp_gpio = NULL; break; default: - dev_err(&pdev->dev, "Failed to get ext-amp-enable GPIO: %d\n", - ret_val); + dev_err(dev, "Failed to get ext-amp-enable GPIO: %d\n", ret_val); fallthrough; case -EPROBE_DEFER: - put_device(codec_dev); - return ret_val; + goto err; } } - priv->hp_detect = devm_fwnode_gpiod_get(&pdev->dev, - codec_dev->fwnode, + priv->hp_detect = devm_fwnode_gpiod_get(dev, codec_dev->fwnode, "hp-detect", GPIOD_IN, "hp-detect"); @@ -1027,19 +1035,15 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) priv->hp_detect = NULL; break; default: - dev_err(&pdev->dev, "Failed to get hp-detect GPIO: %d\n", - ret_val); + dev_err(dev, "Failed to get hp-detect GPIO: %d\n", ret_val); fallthrough; case -EPROBE_DEFER: - put_device(codec_dev); - return ret_val; + goto err; } } } - put_device(codec_dev); - - log_quirks(&pdev->dev); + log_quirks(dev); if ((byt_rt5651_quirk & BYT_RT5651_SSP2_AIF2) || (byt_rt5651_quirk & BYT_RT5651_SSP0_AIF2)) @@ -1050,21 +1054,18 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) byt_rt5651_dais[dai_index].cpus->dai_name = "ssp0-port"; if (byt_rt5651_quirk & BYT_RT5651_MCLK_EN) { - priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); + priv->mclk = devm_clk_get_optional(dev, "pmc_plt_clk_3"); if (IS_ERR(priv->mclk)) { - ret_val = PTR_ERR(priv->mclk); - dev_err(&pdev->dev, - "Failed to get MCLK from pmc_plt_clk_3: %d\n", - ret_val); - /* - * Fall back to bit clock usage for -ENOENT (clock not - * available likely due to missing dependencies), bail - * for all other errors, including -EPROBE_DEFER - */ - if (ret_val != -ENOENT) - return ret_val; - byt_rt5651_quirk &= ~BYT_RT5651_MCLK_EN; + ret_val = dev_err_probe(dev, PTR_ERR(priv->mclk), + "Failed to get MCLK from pmc_plt_clk_3\n"); + goto err; } + /* + * Fall back to bit clock usage when clock is not + * available likely due to missing dependencies. + */ + if (!priv->mclk) + byt_rt5651_quirk &= ~BYT_RT5651_MCLK_EN; } snprintf(byt_rt5651_components, sizeof(byt_rt5651_components), @@ -1085,33 +1086,59 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) byt_rt5651_card.long_name = byt_rt5651_long_name; #endif - /* override plaform name, if required */ + /* override platform name, if required */ platform_name = mach->mach_params.platform; ret_val = snd_soc_fixup_dai_links_platform_name(&byt_rt5651_card, platform_name); if (ret_val) - return ret_val; + goto err; - ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5651_card); + sof_parent = snd_soc_acpi_sof_parent(dev); + /* set card and driver name */ + if (sof_parent) { + byt_rt5651_card.name = SOF_CARD_NAME; + byt_rt5651_card.driver_name = SOF_DRIVER_NAME; + } else { + byt_rt5651_card.name = CARD_NAME; + byt_rt5651_card.driver_name = DRIVER_NAME; + } + + /* set pm ops */ + if (sof_parent) + dev->driver->pm = &snd_soc_pm_ops; + + ret_val = devm_snd_soc_register_card(dev, &byt_rt5651_card); if (ret_val) { - dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n", - ret_val); - return ret_val; + dev_err(dev, "devm_snd_soc_register_card failed %d\n", ret_val); + goto err; } platform_set_drvdata(pdev, &byt_rt5651_card); return ret_val; + +err: + device_remove_software_node(priv->codec_dev); +err_device: + put_device(priv->codec_dev); + return ret_val; +} + +static void snd_byt_rt5651_mc_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct byt_rt5651_private *priv = snd_soc_card_get_drvdata(card); + + device_remove_software_node(priv->codec_dev); + put_device(priv->codec_dev); } static struct platform_driver snd_byt_rt5651_mc_driver = { .driver = { .name = "bytcr_rt5651", -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - .pm = &snd_soc_pm_ops, -#endif }, .probe = snd_byt_rt5651_mc_probe, + .remove = snd_byt_rt5651_mc_remove, }; module_platform_driver(snd_byt_rt5651_mc_driver); diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c new file mode 100644 index 000000000000..a6dfbcfdf74e --- /dev/null +++ b/sound/soc/intel/boards/bytcr_wm5102.c @@ -0,0 +1,670 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * bytcr_wm5102.c - ASoc Machine driver for Intel Baytrail platforms with a + * Wolfson Microelectronics WM5102 codec + * + * Copyright (C) 2020 Hans de Goede <hdegoede@redhat.com> + * Loosely based on bytcr_rt5640.c which is: + * Copyright (C) 2014-2020 Intel Corp + * Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com> + */ + +#include <linux/acpi.h> +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/platform_data/x86/soc.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include "../../codecs/wm5102.h" +#include "../atom/sst-atom-controls.h" + +#define WM5102_MAX_SYSCLK_4K 49152000 /* max sysclk for 4K family */ +#define WM5102_MAX_SYSCLK_11025 45158400 /* max sysclk for 11.025K family */ + +struct byt_wm5102_private { + struct snd_soc_jack jack; + struct clk *mclk; + struct gpio_desc *spkvdd_en_gpio; + int mclk_freq; +}; + +#define BYT_WM5102_IN_MAP GENMASK(3, 0) +#define BYT_WM5102_OUT_MAP GENMASK(7, 4) +#define BYT_WM5102_SSP2 BIT(16) +#define BYT_WM5102_MCLK_19_2MHZ BIT(17) + +enum { + BYT_WM5102_INTMIC_IN3L_HSMIC_IN1L, + BYT_WM5102_INTMIC_IN1L_HSMIC_IN2L, +}; + +/* Note these values are pre-shifted for easy use of setting quirks */ +enum { + BYT_WM5102_SPK_SPK_MAP = FIELD_PREP_CONST(BYT_WM5102_OUT_MAP, 0), + BYT_WM5102_SPK_HPOUT2_MAP = FIELD_PREP_CONST(BYT_WM5102_OUT_MAP, 1), +}; + +static unsigned long quirk; + +static int quirk_override = -1; +module_param_named(quirk, quirk_override, int, 0444); +MODULE_PARM_DESC(quirk, "Board-specific quirk override"); + +static void log_quirks(struct device *dev) +{ + switch (quirk & BYT_WM5102_IN_MAP) { + case BYT_WM5102_INTMIC_IN3L_HSMIC_IN1L: + dev_info_once(dev, "quirk INTMIC_IN3L_HSMIC_IN1L enabled\n"); + break; + case BYT_WM5102_INTMIC_IN1L_HSMIC_IN2L: + dev_info_once(dev, "quirk INTMIC_IN1L_HSMIC_IN2L enabled\n"); + break; + default: + dev_warn_once(dev, "quirk sets invalid input map: 0x%lx, defaulting to INTMIC_IN3L_HSMIC_IN1L\n", + quirk & BYT_WM5102_IN_MAP); + quirk &= ~BYT_WM5102_IN_MAP; + quirk |= BYT_WM5102_INTMIC_IN3L_HSMIC_IN1L; + break; + } + switch (quirk & BYT_WM5102_OUT_MAP) { + case BYT_WM5102_SPK_SPK_MAP: + dev_info_once(dev, "quirk SPK_SPK_MAP enabled\n"); + break; + case BYT_WM5102_SPK_HPOUT2_MAP: + dev_info_once(dev, "quirk SPK_HPOUT2_MAP enabled\n"); + break; + default: + dev_warn_once(dev, "quirk sets invalid output map: 0x%lx, defaulting to SPK_SPK_MAP\n", + quirk & BYT_WM5102_OUT_MAP); + quirk &= ~BYT_WM5102_OUT_MAP; + quirk |= BYT_WM5102_SPK_SPK_MAP; + break; + } + if (quirk & BYT_WM5102_SSP2) + dev_info_once(dev, "quirk SSP2 enabled"); + if (quirk & BYT_WM5102_MCLK_19_2MHZ) + dev_info_once(dev, "quirk MCLK 19.2MHz enabled"); +} + +static int byt_wm5102_spkvdd_power_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_card *card = w->dapm->card; + struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card); + + gpiod_set_value_cansleep(priv->spkvdd_en_gpio, + !!SND_SOC_DAPM_EVENT_ON(event)); + + return 0; +} + +static int byt_wm5102_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai, int rate) +{ + struct snd_soc_component *codec_component = codec_dai->component; + struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(codec_component->card); + int sr_mult = ((rate % 4000) == 0) ? + (WM5102_MAX_SYSCLK_4K / rate) : + (WM5102_MAX_SYSCLK_11025 / rate); + int ret; + + /* Reset FLL1 */ + snd_soc_dai_set_pll(codec_dai, WM5102_FLL1_REFCLK, ARIZONA_FLL_SRC_NONE, 0, 0); + snd_soc_dai_set_pll(codec_dai, WM5102_FLL1, ARIZONA_FLL_SRC_NONE, 0, 0); + + /* Configure the FLL1 PLL before selecting it */ + ret = snd_soc_dai_set_pll(codec_dai, WM5102_FLL1, ARIZONA_CLK_SRC_MCLK1, + priv->mclk_freq, rate * sr_mult); + if (ret) { + dev_err(codec_component->dev, "Error setting PLL: %d\n", ret); + return ret; + } + + ret = snd_soc_component_set_sysclk(codec_component, ARIZONA_CLK_SYSCLK, + ARIZONA_CLK_SRC_FLL1, rate * sr_mult, + SND_SOC_CLOCK_IN); + if (ret) { + dev_err(codec_component->dev, "Error setting SYSCLK: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, ARIZONA_CLK_SYSCLK, + rate * 512, SND_SOC_CLOCK_IN); + if (ret) { + dev_err(codec_component->dev, "Error setting clock: %d\n", ret); + return ret; + } + + return 0; +} + +static int platform_clock_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct snd_soc_dai *codec_dai; + struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card); + int ret; + + codec_dai = snd_soc_card_get_codec_dai(card, "wm5102-aif1"); + if (!codec_dai) { + dev_err(card->dev, "Error codec DAI not found\n"); + return -EIO; + } + + if (SND_SOC_DAPM_EVENT_ON(event)) { + ret = clk_prepare_enable(priv->mclk); + if (ret) { + dev_err(card->dev, "Error enabling MCLK: %d\n", ret); + return ret; + } + ret = byt_wm5102_prepare_and_enable_pll1(codec_dai, 48000); + if (ret) { + dev_err(card->dev, "Error setting codec sysclk: %d\n", ret); + return ret; + } + } else { + /* + * The WM5102 has a separate 32KHz clock for jack-detect + * so we can disable the PLL, followed by disabling the + * platform clock which is the source-clock for the PLL. + */ + snd_soc_dai_set_pll(codec_dai, WM5102_FLL1, ARIZONA_FLL_SRC_NONE, 0, 0); + clk_disable_unprepare(priv->mclk); + } + + return 0; +} + +static const struct snd_soc_dapm_widget byt_wm5102_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Internal Mic", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, + platform_clock_control, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("Speaker VDD", SND_SOC_NOPM, 0, 0, + byt_wm5102_spkvdd_power_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), +}; + +static const struct snd_soc_dapm_route byt_wm5102_audio_map[] = { + {"Headphone", NULL, "Platform Clock"}, + {"Headset Mic", NULL, "Platform Clock"}, + {"Internal Mic", NULL, "Platform Clock"}, + {"Speaker", NULL, "Platform Clock"}, + {"Speaker", NULL, "Speaker VDD"}, + + {"Headphone", NULL, "HPOUT1L"}, + {"Headphone", NULL, "HPOUT1R"}, + + /* + * The Headset Mix uses MICBIAS1 or 2 depending on if a CTIA/OMTP Headset + * is connected, as the MICBIAS is applied after the CTIA/OMTP cross-switch. + */ + {"Headset Mic", NULL, "MICBIAS1"}, + {"Headset Mic", NULL, "MICBIAS2"}, + {"Internal Mic", NULL, "MICBIAS3"}, +}; + +static const struct snd_soc_dapm_route bytcr_wm5102_ssp0_map[] = { + {"AIF1 Playback", NULL, "ssp0 Tx"}, + {"ssp0 Tx", NULL, "modem_out"}, + {"modem_in", NULL, "ssp0 Rx"}, + {"ssp0 Rx", NULL, "AIF1 Capture"}, +}; + +static const struct snd_soc_dapm_route bytcr_wm5102_ssp2_map[] = { + {"AIF1 Playback", NULL, "ssp2 Tx"}, + {"ssp2 Tx", NULL, "codec_out0"}, + {"ssp2 Tx", NULL, "codec_out1"}, + {"codec_in0", NULL, "ssp2 Rx"}, + {"codec_in1", NULL, "ssp2 Rx"}, + {"ssp2 Rx", NULL, "AIF1 Capture"}, +}; + +static const struct snd_soc_dapm_route byt_wm5102_spk_spk_map[] = { + {"Speaker", NULL, "SPKOUTLP"}, + {"Speaker", NULL, "SPKOUTLN"}, + {"Speaker", NULL, "SPKOUTRP"}, + {"Speaker", NULL, "SPKOUTRN"}, +}; + +static const struct snd_soc_dapm_route byt_wm5102_spk_hpout2_map[] = { + {"Speaker", NULL, "HPOUT2L"}, + {"Speaker", NULL, "HPOUT2R"}, +}; + +static const struct snd_soc_dapm_route byt_wm5102_intmic_in3l_hsmic_in1l_map[] = { + {"IN3L", NULL, "Internal Mic"}, + {"IN1L", NULL, "Headset Mic"}, +}; + +static const struct snd_soc_dapm_route byt_wm5102_intmic_in1l_hsmic_in2l_map[] = { + {"IN1L", NULL, "Internal Mic"}, + {"IN2L", NULL, "Headset Mic"}, +}; + +static const struct snd_kcontrol_new byt_wm5102_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Internal Mic"), + SOC_DAPM_PIN_SWITCH("Speaker"), + SOC_DAPM_PIN_SWITCH("Line Out"), +}; + +static struct snd_soc_jack_pin byt_wm5102_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, +}; + +static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_card *card = runtime->card; + struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card); + struct snd_soc_component *component = snd_soc_rtd_to_codec(runtime, 0)->component; + const struct snd_soc_dapm_route *custom_map = NULL; + int ret, jack_type, num_routes = 0; + + card->dapm.idle_bias_off = true; + + ret = snd_soc_add_card_controls(card, byt_wm5102_controls, + ARRAY_SIZE(byt_wm5102_controls)); + if (ret) { + dev_err(card->dev, "Error adding card controls: %d\n", ret); + return ret; + } + + switch (quirk & BYT_WM5102_IN_MAP) { + case BYT_WM5102_INTMIC_IN3L_HSMIC_IN1L: + custom_map = byt_wm5102_intmic_in3l_hsmic_in1l_map; + num_routes = ARRAY_SIZE(byt_wm5102_intmic_in3l_hsmic_in1l_map); + break; + case BYT_WM5102_INTMIC_IN1L_HSMIC_IN2L: + custom_map = byt_wm5102_intmic_in1l_hsmic_in2l_map; + num_routes = ARRAY_SIZE(byt_wm5102_intmic_in1l_hsmic_in2l_map); + break; + } + ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); + if (ret) + return ret; + + switch (quirk & BYT_WM5102_OUT_MAP) { + case BYT_WM5102_SPK_SPK_MAP: + custom_map = byt_wm5102_spk_spk_map; + num_routes = ARRAY_SIZE(byt_wm5102_spk_spk_map); + break; + case BYT_WM5102_SPK_HPOUT2_MAP: + custom_map = byt_wm5102_spk_hpout2_map; + num_routes = ARRAY_SIZE(byt_wm5102_spk_hpout2_map); + break; + } + ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); + if (ret) + return ret; + + if (quirk & BYT_WM5102_SSP2) { + custom_map = bytcr_wm5102_ssp2_map; + num_routes = ARRAY_SIZE(bytcr_wm5102_ssp2_map); + } else { + custom_map = bytcr_wm5102_ssp0_map; + num_routes = ARRAY_SIZE(bytcr_wm5102_ssp0_map); + } + ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); + if (ret) + return ret; + + if (quirk & BYT_WM5102_MCLK_19_2MHZ) + priv->mclk_freq = 19200000; + else + priv->mclk_freq = 25000000; + + /* + * The firmware might enable the clock at boot (this information + * may or may not be reflected in the enable clock register). + * To change the rate we must disable the clock first to cover these + * cases. Due to common clock framework restrictions that do not allow + * to disable a clock that has not been enabled, we need to enable + * the clock first. + */ + ret = clk_prepare_enable(priv->mclk); + if (!ret) + clk_disable_unprepare(priv->mclk); + + ret = clk_set_rate(priv->mclk, priv->mclk_freq); + if (ret) { + dev_err(card->dev, "Error setting MCLK rate: %d\n", ret); + return ret; + } + + jack_type = ARIZONA_JACK_MASK | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3; + ret = snd_soc_card_jack_new_pins(card, "Headset", jack_type, + &priv->jack, byt_wm5102_pins, + ARRAY_SIZE(byt_wm5102_pins)); + if (ret) { + dev_err(card->dev, "Error creating jack: %d\n", ret); + return ret; + } + + snd_soc_component_set_jack(component, &priv->jack, NULL); + + return 0; +} + +static int byt_wm5102_codec_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); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + int ret, bits; + + /* The DSP will convert the FE rate to 48k, stereo */ + rate->min = 48000; + rate->max = 48000; + channels->min = 2; + channels->max = 2; + + if (quirk & BYT_WM5102_SSP2) { + /* set SSP2 to 24-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + bits = 24; + } else { + /* set SSP0 to 16-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); + bits = 16; + } + + /* + * Default mode for SSP configuration is TDM 4 slot, override config + * with explicit setting to I2S 2ch 16-bit. The word length is set with + * dai_set_tdm_slot() since there is no other API exposed + */ + ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0), + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_BP_FP); + if (ret) { + dev_err(rtd->dev, "Error setting format to I2S: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, bits); + if (ret) { + dev_err(rtd->dev, "Error setting I2S config: %d\n", ret); + return ret; + } + + return 0; +} + +static int byt_wm5102_aif1_startup(struct snd_pcm_substream *substream) +{ + return snd_pcm_hw_constraint_single(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, 48000); +} + +static const struct snd_soc_ops byt_wm5102_aif1_ops = { + .startup = byt_wm5102_aif1_startup, +}; + +SND_SOC_DAILINK_DEF(dummy, + DAILINK_COMP_ARRAY(COMP_DUMMY())); + +SND_SOC_DAILINK_DEF(media, + DAILINK_COMP_ARRAY(COMP_CPU("media-cpu-dai"))); + +SND_SOC_DAILINK_DEF(deepbuffer, + DAILINK_COMP_ARRAY(COMP_CPU("deepbuffer-cpu-dai"))); + +SND_SOC_DAILINK_DEF(ssp0_port, + DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port"))); + +SND_SOC_DAILINK_DEF(ssp0_codec, + DAILINK_COMP_ARRAY(COMP_CODEC( + /* + * Note there is no need to overwrite the codec-name as is done in + * other bytcr machine drivers, because the codec is a MFD child-dev. + */ + "wm5102-codec", + "wm5102-aif1"))); + +SND_SOC_DAILINK_DEF(platform, + DAILINK_COMP_ARRAY(COMP_PLATFORM("sst-mfld-platform"))); + +static struct snd_soc_dai_link byt_wm5102_dais[] = { + [MERR_DPCM_AUDIO] = { + .name = "Baytrail Audio Port", + .stream_name = "Baytrail Audio", + .nonatomic = true, + .dynamic = 1, + .ops = &byt_wm5102_aif1_ops, + SND_SOC_DAILINK_REG(media, dummy, platform), + + }, + [MERR_DPCM_DEEP_BUFFER] = { + .name = "Deep-Buffer Audio Port", + .stream_name = "Deep-Buffer Audio", + .nonatomic = true, + .dynamic = 1, + .playback_only = 1, + .ops = &byt_wm5102_aif1_ops, + SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), + }, + /* back ends */ + { + /* + * This dailink is updated dynamically to point to SSP0 or SSP2. + * Yet its name is always kept as "SSP2-Codec" because the SOF + * tplg files hardcode "SSP2-Codec" even in byt-foo-ssp0.tplg. + */ + .name = "SSP2-Codec", + .id = 0, + .no_pcm = 1, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBC_CFC, + .be_hw_params_fixup = byt_wm5102_codec_fixup, + .init = byt_wm5102_init, + SND_SOC_DAILINK_REG(ssp0_port, ssp0_codec, platform), + }, +}; + +/* use space before codec name to simplify card ID, and simplify driver name */ +#define SOF_CARD_NAME "bytcht wm5102" /* card name will be 'sof-bytcht wm5102' */ +#define SOF_DRIVER_NAME "SOF" + +#define CARD_NAME "bytcr-wm5102" +#define DRIVER_NAME NULL /* card name will be used for driver name */ + +/* SoC card */ +static struct snd_soc_card byt_wm5102_card = { + .owner = THIS_MODULE, + .dai_link = byt_wm5102_dais, + .num_links = ARRAY_SIZE(byt_wm5102_dais), + .dapm_widgets = byt_wm5102_widgets, + .num_dapm_widgets = ARRAY_SIZE(byt_wm5102_widgets), + .dapm_routes = byt_wm5102_audio_map, + .num_dapm_routes = ARRAY_SIZE(byt_wm5102_audio_map), + .fully_routed = true, +}; + +static char byt_wm5102_components[64]; /* = "cfg-spk:* cfg-int-mic:* cfg-hs-mic:* ..." */ + +static int snd_byt_wm5102_mc_probe(struct platform_device *pdev) +{ + static const char * const out_map_name[] = { "spk", "hpout2" }; + static const char * const intmic_map_name[] = { "in3l", "in1l" }; + static const char * const hsmic_map_name[] = { "in1l", "in2l" }; + char codec_name[SND_ACPI_I2C_ID_LEN]; + struct device *dev = &pdev->dev; + struct byt_wm5102_private *priv; + struct snd_soc_acpi_mach *mach; + const char *platform_name; + struct acpi_device *adev; + struct device *codec_dev; + int dai_index = 0; + bool sof_parent; + int i, ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + /* Get MCLK */ + priv->mclk = devm_clk_get(dev, "pmc_plt_clk_3"); + if (IS_ERR(priv->mclk)) + return dev_err_probe(dev, PTR_ERR(priv->mclk), "getting pmc_plt_clk_3\n"); + + /* + * Get speaker VDD enable GPIO: + * 1. Get codec-device-name + * 2. Get codec-device + * 3. Get GPIO from codec-device + */ + mach = dev->platform_data; + adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1); + if (adev) { + snprintf(codec_name, sizeof(codec_name), "spi-%s", acpi_dev_name(adev)); + acpi_dev_put(adev); + } else { + /* Special case for when the codec is missing from the DSTD */ + strscpy(codec_name, "spi1.0", sizeof(codec_name)); + } + + codec_dev = bus_find_device_by_name(&spi_bus_type, NULL, codec_name); + if (!codec_dev) + return -EPROBE_DEFER; + + /* Note no devm_ here since we call gpiod_get on codec_dev rather then dev */ + priv->spkvdd_en_gpio = gpiod_get(codec_dev, "wlf,spkvdd-ena", GPIOD_OUT_LOW); + put_device(codec_dev); + + if (IS_ERR(priv->spkvdd_en_gpio)) { + ret = PTR_ERR(priv->spkvdd_en_gpio); + /* + * The spkvdd gpio-lookup is registered by: drivers/mfd/arizona-spi.c, + * so -ENOENT means that arizona-spi hasn't probed yet. + */ + if (ret == -ENOENT) + ret = -EPROBE_DEFER; + + return dev_err_probe(dev, ret, "getting spkvdd-GPIO\n"); + } + + if (soc_intel_is_cht()) { + /* + * CHT always uses SSP2 and 19.2 MHz; and + * the one currently supported CHT design uses HPOUT2 as + * speaker output and has the intmic on IN1L + hsmic on IN2L. + */ + quirk = BYT_WM5102_SSP2 | BYT_WM5102_MCLK_19_2MHZ | + BYT_WM5102_INTMIC_IN1L_HSMIC_IN2L | + BYT_WM5102_SPK_HPOUT2_MAP; + } + if (quirk_override != -1) { + dev_info_once(dev, "Overriding quirk 0x%lx => 0x%x\n", + quirk, quirk_override); + quirk = quirk_override; + } + log_quirks(dev); + + snprintf(byt_wm5102_components, sizeof(byt_wm5102_components), + "cfg-spk:%s cfg-intmic:%s cfg-hsmic:%s", + out_map_name[FIELD_GET(BYT_WM5102_OUT_MAP, quirk)], + intmic_map_name[FIELD_GET(BYT_WM5102_IN_MAP, quirk)], + hsmic_map_name[FIELD_GET(BYT_WM5102_IN_MAP, quirk)]); + byt_wm5102_card.components = byt_wm5102_components; + + /* find index of codec dai */ + for (i = 0; i < ARRAY_SIZE(byt_wm5102_dais); i++) { + if (byt_wm5102_dais[i].num_codecs && + !strcmp(byt_wm5102_dais[i].codecs->name, + "wm5102-codec")) { + dai_index = i; + break; + } + } + + /* override platform name, if required */ + byt_wm5102_card.dev = dev; + platform_name = mach->mach_params.platform; + ret = snd_soc_fixup_dai_links_platform_name(&byt_wm5102_card, platform_name); + if (ret) + goto out_put_gpio; + + /* override SSP port, if required */ + if (quirk & BYT_WM5102_SSP2) + byt_wm5102_dais[dai_index].cpus->dai_name = "ssp2-port"; + + /* set card and driver name and pm-ops */ + sof_parent = snd_soc_acpi_sof_parent(dev); + if (sof_parent) { + byt_wm5102_card.name = SOF_CARD_NAME; + byt_wm5102_card.driver_name = SOF_DRIVER_NAME; + dev->driver->pm = &snd_soc_pm_ops; + } else { + byt_wm5102_card.name = CARD_NAME; + byt_wm5102_card.driver_name = DRIVER_NAME; + } + + snd_soc_card_set_drvdata(&byt_wm5102_card, priv); + ret = devm_snd_soc_register_card(dev, &byt_wm5102_card); + if (ret) { + dev_err_probe(dev, ret, "registering card\n"); + goto out_put_gpio; + } + + platform_set_drvdata(pdev, &byt_wm5102_card); + return 0; + +out_put_gpio: + gpiod_put(priv->spkvdd_en_gpio); + return ret; +} + +static void snd_byt_wm5102_mc_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card); + + gpiod_put(priv->spkvdd_en_gpio); +} + +static struct platform_driver snd_byt_wm5102_mc_driver = { + .driver = { + .name = "bytcr_wm5102", + }, + .probe = snd_byt_wm5102_mc_probe, + .remove = snd_byt_wm5102_mc_remove, +}; + +module_platform_driver(snd_byt_wm5102_mc_driver); + +MODULE_DESCRIPTION("ASoC Baytrail with WM5102 codec machine driver"); +MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:bytcr_wm5102"); diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index 835e9bd6b52d..36984de8a067 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -112,8 +112,8 @@ static const struct snd_kcontrol_new cht_mc_controls[] = { static int cht_aif1_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); int ret; ret = snd_soc_dai_set_sysclk(codec_dai, M98090_REG_SYSTEM_CLOCK, @@ -201,9 +201,10 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE; - ret = snd_soc_card_jack_new(runtime->card, "Headset Jack", - jack_type, jack, - hs_jack_pins, ARRAY_SIZE(hs_jack_pins)); + ret = snd_soc_card_jack_new_pins(runtime->card, "Headset Jack", + jack_type, jack, + hs_jack_pins, + ARRAY_SIZE(hs_jack_pins)); if (ret) { dev_err(runtime->dev, "Headset Jack creation failed %d\n", ret); return ret; @@ -257,22 +258,21 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, int ret = 0; unsigned int fmt = 0; - ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 16); + ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 16); if (ret < 0) { dev_err(rtd->dev, "can't set cpu_dai slot fmt: %d\n", ret); return ret; } - fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS; + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_BP_FP; - ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), fmt); + ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0), fmt); if (ret < 0) { dev_err(rtd->dev, "can't set cpu_dai set fmt: %d\n", ret); return ret; } - /* The DSP will covert the FE rate to 48k, stereo, 24bits */ + /* The DSP will convert the FE rate to 48k, stereo, 24bits */ rate->min = rate->max = 48000; channels->min = channels->max = 2; @@ -296,7 +296,7 @@ static int cht_max98090_headset_init(struct snd_soc_component *component) int ret; /* - * TI supports 4 butons headset detection + * TI supports 4 buttons headset detection * KEY_MEDIA * KEY_VOICECOMMAND * KEY_VOLUMEUP @@ -306,8 +306,7 @@ static int cht_max98090_headset_init(struct snd_soc_component *component) SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3; - ret = snd_soc_card_jack_new(card, "Headset Jack", jack_type, - jack, NULL, 0); + ret = snd_soc_card_jack_new(card, "Headset Jack", jack_type, jack); if (ret) { dev_err(card->dev, "Headset Jack creation failed %d\n", ret); return ret; @@ -352,8 +351,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -362,7 +359,7 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -372,29 +369,23 @@ static struct snd_soc_dai_link cht_dailink[] = { .id = 0, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS, + | SND_SOC_DAIFMT_CBC_CFC, .init = cht_codec_init, .be_hw_params_fixup = cht_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_be_ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, }; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) /* use space before codec name to simplify card ID, and simplify driver name */ -#define CARD_NAME "bytcht max98090" /* card name will be 'sof-bytcht max98090 */ -#define DRIVER_NAME "SOF" -#else +#define SOF_CARD_NAME "bytcht max98090" /* card name will be 'sof-bytcht max98090 */ +#define SOF_DRIVER_NAME "SOF" + #define CARD_NAME "chtmax98090" #define DRIVER_NAME NULL /* card name will be used for driver name */ -#endif /* SoC card */ static struct snd_soc_card snd_soc_card_cht = { - .name = CARD_NAME, - .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = cht_dailink, .num_links = ARRAY_SIZE(cht_dailink), @@ -540,8 +531,9 @@ static int snd_cht_mc_probe(struct platform_device *pdev) const char *mclk_name; struct snd_soc_acpi_mach *mach; const char *platform_name; + bool sof_parent; - drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); + drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL); if (!drv) return -ENOMEM; @@ -561,9 +553,9 @@ static int snd_cht_mc_probe(struct platform_device *pdev) dev_dbg(dev, "Unable to add GPIO mapping table\n"); } - /* override plaform name, if required */ - snd_soc_card_cht.dev = &pdev->dev; - mach = pdev->dev.platform_data; + /* override platform name, if required */ + snd_soc_card_cht.dev = dev; + mach = dev->platform_data; platform_name = mach->mach_params.platform; ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht, @@ -579,9 +571,9 @@ static int snd_cht_mc_probe(struct platform_device *pdev) else mclk_name = "pmc_plt_clk_3"; - drv->mclk = devm_clk_get(&pdev->dev, mclk_name); + drv->mclk = devm_clk_get(dev, mclk_name); if (IS_ERR(drv->mclk)) { - dev_err(&pdev->dev, + dev_err(dev, "Failed to get MCLK from %s: %ld\n", mclk_name, PTR_ERR(drv->mclk)); return PTR_ERR(drv->mclk); @@ -597,14 +589,29 @@ static int snd_cht_mc_probe(struct platform_device *pdev) if (drv->quirks & QUIRK_PMC_PLT_CLK_0) { ret_val = clk_prepare_enable(drv->mclk); if (ret_val < 0) { - dev_err(&pdev->dev, "MCLK enable error: %d\n", ret_val); + dev_err(dev, "MCLK enable error: %d\n", ret_val); return ret_val; } } - ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); + sof_parent = snd_soc_acpi_sof_parent(dev); + + /* set card and driver name */ + if (sof_parent) { + snd_soc_card_cht.name = SOF_CARD_NAME; + snd_soc_card_cht.driver_name = SOF_DRIVER_NAME; + } else { + snd_soc_card_cht.name = CARD_NAME; + snd_soc_card_cht.driver_name = DRIVER_NAME; + } + + /* set pm ops */ + if (sof_parent) + dev->driver->pm = &snd_soc_pm_ops; + + ret_val = devm_snd_soc_register_card(dev, &snd_soc_card_cht); if (ret_val) { - dev_err(&pdev->dev, + dev_err(dev, "snd_soc_register_card failed %d\n", ret_val); return ret_val; } @@ -612,23 +619,18 @@ static int snd_cht_mc_probe(struct platform_device *pdev) return ret_val; } -static int snd_cht_mc_remove(struct platform_device *pdev) +static void snd_cht_mc_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card); if (ctx->quirks & QUIRK_PMC_PLT_CLK_0) clk_disable_unprepare(ctx->mclk); - - return 0; } static struct platform_driver snd_cht_mc_driver = { .driver = { .name = "cht-bsw-max98090", -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - .pm = &snd_soc_pm_ops, -#endif }, .probe = snd_cht_mc_probe, .remove = snd_cht_mc_remove, diff --git a/sound/soc/intel/boards/cht_bsw_nau8824.c b/sound/soc/intel/boards/cht_bsw_nau8824.c index 3e12bff15fed..4afb292d4f13 100644 --- a/sound/soc/intel/boards/cht_bsw_nau8824.c +++ b/sound/soc/intel/boards/cht_bsw_nau8824.c @@ -72,8 +72,8 @@ static const struct snd_kcontrol_new cht_mc_controls[] = { static int cht_aif1_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); int ret; ret = snd_soc_dai_set_sysclk(codec_dai, NAU8824_CLK_FLL_FS, 0, @@ -96,18 +96,11 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) { struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card); struct snd_soc_jack *jack = &ctx->jack; - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0); struct snd_soc_component *component = codec_dai->component; int ret, jack_type; - /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xf, 0x1, 4, 24); - if (ret < 0) { - dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret); - return ret; - } - - /* NAU88L24 supports 4 butons headset detection + /* NAU88L24 supports 4 buttons headset detection * KEY_PLAYPAUSE * KEY_VOICECOMMAND * KEY_VOLUMEUP @@ -115,8 +108,8 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) */ jack_type = SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3; - ret = snd_soc_card_jack_new(runtime->card, "Headset", jack_type, jack, - cht_bsw_jack_pins, ARRAY_SIZE(cht_bsw_jack_pins)); + ret = snd_soc_card_jack_new_pins(runtime->card, "Headset", jack_type, + jack, cht_bsw_jack_pins, ARRAY_SIZE(cht_bsw_jack_pins)); if (ret) { dev_err(runtime->dev, "Headset Jack creation failed %d\n", ret); @@ -141,8 +134,9 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, SNDRV_PCM_HW_PARAM_CHANNELS); struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + int ret; - /* The DSP will covert the FE rate to 48k, stereo, 24bits */ + /* The DSP will convert the FE rate to 48k, stereo, 24bits */ rate->min = rate->max = 48000; channels->min = channels->max = 2; @@ -150,6 +144,13 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, snd_mask_none(fmt); params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ + ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_codec(rtd, 0), 0xf, 0x1, 4, 24); + if (ret < 0) { + dev_err(rtd->dev, "can't set codec TDM slot %d\n", ret); + return ret; + } + return 0; } @@ -176,9 +177,6 @@ SND_SOC_DAILINK_DEF(media, SND_SOC_DAILINK_DEF(deepbuffer, DAILINK_COMP_ARRAY(COMP_CPU("deepbuffer-cpu-dai"))); -SND_SOC_DAILINK_DEF(compress, - DAILINK_COMP_ARRAY(COMP_CPU("compress-cpu-dai"))); - SND_SOC_DAILINK_DEF(ssp2_port, DAILINK_COMP_ARRAY(COMP_CPU("ssp2-port"))); SND_SOC_DAILINK_DEF(ssp2_codec, @@ -195,8 +193,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -205,45 +201,34 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, - [MERR_DPCM_COMPR] = { - .name = "Compressed Port", - .stream_name = "Compress", - SND_SOC_DAILINK_REG(compress, dummy, platform), - }, /* Back End DAI links */ { /* SSP2 - Codec */ .name = "SSP2-Codec", - .id = 1, + .id = 0, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF - | SND_SOC_DAIFMT_CBS_CFS, + | SND_SOC_DAIFMT_CBC_CFC, .init = cht_codec_init, .be_hw_params_fixup = cht_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_be_ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, }; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) /* use space before codec name to simplify card ID, and simplify driver name */ -#define CARD_NAME "bytcht nau8824" /* card name will be 'sof-bytcht nau8824 */ -#define DRIVER_NAME "SOF" -#else +#define SOF_CARD_NAME "bytcht nau8824" /* card name will be 'sof-bytcht nau8824 */ +#define SOF_DRIVER_NAME "SOF" + #define CARD_NAME "chtnau8824" #define DRIVER_NAME NULL /* card name will be used for driver name */ -#endif /* SoC card */ static struct snd_soc_card snd_soc_card_cht = { - .name = CARD_NAME, - .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = cht_dailink, .num_links = ARRAY_SIZE(cht_dailink), @@ -260,6 +245,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) struct cht_mc_private *drv; struct snd_soc_acpi_mach *mach; const char *platform_name; + bool sof_parent; int ret_val; drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); @@ -267,7 +253,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) return -ENOMEM; snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); - /* override plaform name, if required */ + /* override platform name, if required */ snd_soc_card_cht.dev = &pdev->dev; mach = pdev->dev.platform_data; platform_name = mach->mach_params.platform; @@ -277,6 +263,23 @@ static int snd_cht_mc_probe(struct platform_device *pdev) if (ret_val) return ret_val; + sof_parent = snd_soc_acpi_sof_parent(&pdev->dev); + + /* set card and driver name */ + if (sof_parent) { + snd_soc_card_cht.name = SOF_CARD_NAME; + snd_soc_card_cht.driver_name = SOF_DRIVER_NAME; + } else { + snd_soc_card_cht.name = CARD_NAME; + snd_soc_card_cht.driver_name = DRIVER_NAME; + } + + snd_soc_card_cht.components = nau8824_components(); + + /* set pm ops */ + if (sof_parent) + pdev->dev.driver->pm = &snd_soc_pm_ops; + /* register the soc card */ ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); if (ret_val) { @@ -292,9 +295,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev) static struct platform_driver snd_cht_mc_driver = { .driver = { .name = "cht-bsw-nau8824", -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - .pm = &snd_soc_pm_ops, -#endif }, .probe = snd_cht_mc_probe, }; diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index b53c02481749..b977a2db73a3 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -40,7 +40,6 @@ struct cht_acpi_card { struct cht_mc_private { struct snd_soc_jack jack; struct cht_acpi_card *acpi_card; - char codec_name[SND_ACPI_I2C_ID_LEN]; struct clk *mclk; }; @@ -207,8 +206,8 @@ static struct snd_soc_jack_pin cht_bsw_jack_pins[] = { static int cht_aif1_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); int ret; /* set codec PLL source to the 19.2MHz platform clock (MCLK) */ @@ -252,7 +251,7 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) { struct snd_soc_card *card = runtime->card; struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card); - struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component; + struct snd_soc_component *component = snd_soc_rtd_to_codec(runtime, 0)->component; int jack_type; int ret; @@ -302,9 +301,9 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) else jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE; - ret = snd_soc_card_jack_new(runtime->card, "Headset", - jack_type, &ctx->jack, - cht_bsw_jack_pins, ARRAY_SIZE(cht_bsw_jack_pins)); + ret = snd_soc_card_jack_new_pins(runtime->card, "Headset", jack_type, + &ctx->jack, cht_bsw_jack_pins, + ARRAY_SIZE(cht_bsw_jack_pins)); if (ret) { dev_err(runtime->dev, "Headset jack creation failed %d\n", ret); return ret; @@ -344,7 +343,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - /* The DSP will covert the FE rate to 48k, stereo, 24bits */ + /* The DSP will convert the FE rate to 48k, stereo, 24bits */ rate->min = rate->max = 48000; channels->min = channels->max = 2; @@ -359,27 +358,27 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, * with explicit setting to I2S 2ch 16-bit. The word length is set with * dai_set_tdm_slot() since there is no other API exposed */ - ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), + ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS + SND_SOC_DAIFMT_BP_FP ); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); return ret; } - ret = snd_soc_dai_set_fmt(asoc_rtd_to_codec(rtd, 0), + ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_codec(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS + SND_SOC_DAIFMT_BC_FC ); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); return ret; } - ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 16); + ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 16); if (ret < 0) { dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); return ret; @@ -393,17 +392,17 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, /* * Default mode for SSP configuration is TDM 4 slot */ - ret = snd_soc_dai_set_fmt(asoc_rtd_to_codec(rtd, 0), + ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_codec(rtd, 0), SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_BC_FC); if (ret < 0) { dev_err(rtd->dev, "can't set format to TDM %d\n", ret); return ret; } /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ - ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(rtd, 0), 0xF, 0xF, 4, 24); + ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_codec(rtd, 0), 0xF, 0xF, 4, 24); if (ret < 0) { dev_err(rtd->dev, "can't set codec TDM slot %d\n", ret); return ret; @@ -449,8 +448,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -459,7 +456,7 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -471,29 +468,22 @@ static struct snd_soc_dai_link cht_dailink[] = { .no_pcm = 1, .init = cht_codec_init, .be_hw_params_fixup = cht_codec_fixup, - .nonatomic = true, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_be_ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, }; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) /* use space before codec name to simplify card ID, and simplify driver name */ -#define CARD_RT5645_NAME "bytcht rt5645" /* card name 'sof-bytcht rt5645' */ -#define CARD_RT5650_NAME "bytcht rt5650" /* card name 'sof-bytcht rt5650' */ -#define DRIVER_NAME "SOF" -#else +#define SOF_CARD_RT5645_NAME "bytcht rt5645" /* card name 'sof-bytcht rt5645' */ +#define SOF_CARD_RT5650_NAME "bytcht rt5650" /* card name 'sof-bytcht rt5650' */ +#define SOF_DRIVER_NAME "SOF" + #define CARD_RT5645_NAME "chtrt5645" #define CARD_RT5650_NAME "chtrt5650" #define DRIVER_NAME NULL /* card name will be used for driver name */ -#endif /* SoC card */ static struct snd_soc_card snd_soc_card_chtrt5645 = { - .name = CARD_RT5645_NAME, - .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = cht_dailink, .num_links = ARRAY_SIZE(cht_dailink), @@ -506,8 +496,6 @@ static struct snd_soc_card snd_soc_card_chtrt5645 = { }; static struct snd_soc_card snd_soc_card_chtrt5650 = { - .name = CARD_RT5650_NAME, - .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = cht_dailink, .num_links = ARRAY_SIZE(cht_dailink), @@ -541,6 +529,8 @@ static int snd_cht_mc_probe(struct platform_device *pdev) const char *platform_name; struct cht_mc_private *drv; struct acpi_device *adev; + struct device *codec_dev; + bool sof_parent; bool found = false; bool is_bytcr = false; int dai_index = 0; @@ -572,14 +562,14 @@ static int snd_cht_mc_probe(struct platform_device *pdev) } card->dev = &pdev->dev; - sprintf(drv->codec_name, "i2c-%s:00", drv->acpi_card->codec_id); /* set correct codec name */ for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) - if (!strcmp(card->dai_link[i].codecs->name, + if (cht_dailink[i].num_codecs && + !strcmp(cht_dailink[i].codecs->name, "i2c-10EC5645:00")) { - card->dai_link[i].codecs->name = drv->codec_name; dai_index = i; + break; } /* fixup codec name based on HID */ @@ -587,10 +577,21 @@ static int snd_cht_mc_probe(struct platform_device *pdev) if (adev) { snprintf(cht_rt5645_codec_name, sizeof(cht_rt5645_codec_name), "i2c-%s", acpi_dev_name(adev)); - put_device(&adev->dev); cht_dailink[dai_index].codecs->name = cht_rt5645_codec_name; + } else { + dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); + return -ENOENT; } + /* acpi_get_first_physical_node() returns a borrowed ref, no need to deref */ + codec_dev = acpi_get_first_physical_node(adev); + acpi_dev_put(adev); + if (!codec_dev) + return -EPROBE_DEFER; + + snd_soc_card_chtrt5645.components = rt5645_components(codec_dev); + snd_soc_card_chtrt5650.components = rt5645_components(codec_dev); + /* * swap SSP0 if bytcr is detected * (will be overridden if DMI quirk is detected) @@ -609,7 +610,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) * with the codec driver/pdata are non-existent */ - struct acpi_chan_package chan_package; + struct acpi_chan_package chan_package = { 0 }; /* format specified: 2 64-bit integers */ struct acpi_buffer format = {sizeof("NN"), "NN"}; @@ -659,7 +660,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2)) cht_dailink[dai_index].cpus->dai_name = "ssp0-port"; - /* override plaform name, if required */ + /* override platform name, if required */ platform_name = mach->mach_params.platform; ret_val = snd_soc_fixup_dai_links_platform_name(card, @@ -680,6 +681,26 @@ static int snd_cht_mc_probe(struct platform_device *pdev) } snd_soc_card_set_drvdata(card, drv); + + sof_parent = snd_soc_acpi_sof_parent(&pdev->dev); + + /* set card and driver name */ + if (sof_parent) { + snd_soc_card_chtrt5645.name = SOF_CARD_RT5645_NAME; + snd_soc_card_chtrt5645.driver_name = SOF_DRIVER_NAME; + snd_soc_card_chtrt5650.name = SOF_CARD_RT5650_NAME; + snd_soc_card_chtrt5650.driver_name = SOF_DRIVER_NAME; + } else { + snd_soc_card_chtrt5645.name = CARD_RT5645_NAME; + snd_soc_card_chtrt5645.driver_name = DRIVER_NAME; + snd_soc_card_chtrt5650.name = CARD_RT5650_NAME; + snd_soc_card_chtrt5650.driver_name = DRIVER_NAME; + } + + /* set pm ops */ + if (sof_parent) + pdev->dev.driver->pm = &snd_soc_pm_ops; + ret_val = devm_snd_soc_register_card(&pdev->dev, card); if (ret_val) { dev_err(&pdev->dev, @@ -693,9 +714,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev) static struct platform_driver snd_cht_mc_driver = { .driver = { .name = "cht-bsw-rt5645", -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - .pm = &snd_soc_pm_ops, -#endif }, .probe = snd_cht_mc_probe, }; diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 8442be93eb1c..aaef212cf44e 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -21,6 +21,7 @@ #include <sound/soc-acpi.h> #include "../../codecs/rt5670.h" #include "../atom/sst-atom-controls.h" +#include "../common/soc-intel-quirks.h" /* The platform clock #3 outputs 19.2Mhz clock to codec as I2S MCLK */ @@ -31,6 +32,7 @@ struct cht_mc_private { struct snd_soc_jack headset; char codec_name[SND_ACPI_I2C_ID_LEN]; struct clk *mclk; + bool use_ssp0; }; /* Headset jack detection DAPM pins */ @@ -91,8 +93,12 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, * when codec is runtime suspended. Codec needs clock for jack * detection and button press. */ - snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK, - 48000 * 512, SND_SOC_CLOCK_IN); + ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK, + 48000 * 512, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "failed to set codec sysclk: %d\n", ret); + return ret; + } if (ctx->mclk) clk_disable_unprepare(ctx->mclk); @@ -121,16 +127,26 @@ static const struct snd_soc_dapm_route cht_audio_map[] = { {"Ext Spk", NULL, "SPOLN"}, {"Ext Spk", NULL, "SPORP"}, {"Ext Spk", NULL, "SPORN"}, + {"Headphone", NULL, "Platform Clock"}, + {"Headset Mic", NULL, "Platform Clock"}, + {"Int Mic", NULL, "Platform Clock"}, + {"Ext Spk", NULL, "Platform Clock"}, +}; + +static const struct snd_soc_dapm_route cht_audio_ssp0_map[] = { + {"AIF1 Playback", NULL, "ssp0 Tx"}, + {"ssp0 Tx", NULL, "modem_out"}, + {"modem_in", NULL, "ssp0 Rx"}, + {"ssp0 Rx", NULL, "AIF1 Capture"}, +}; + +static const struct snd_soc_dapm_route cht_audio_ssp2_map[] = { {"AIF1 Playback", NULL, "ssp2 Tx"}, {"ssp2 Tx", NULL, "codec_out0"}, {"ssp2 Tx", NULL, "codec_out1"}, {"codec_in0", NULL, "ssp2 Rx"}, {"codec_in1", NULL, "ssp2 Rx"}, {"ssp2 Rx", NULL, "AIF1 Capture"}, - {"Headphone", NULL, "Platform Clock"}, - {"Headset Mic", NULL, "Platform Clock"}, - {"Int Mic", NULL, "Platform Clock"}, - {"Ext Spk", NULL, "Platform Clock"}, }; static const struct snd_kcontrol_new cht_mc_controls[] = { @@ -143,8 +159,8 @@ static const struct snd_kcontrol_new cht_mc_controls[] = { static int cht_aif1_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); int ret; /* set codec PLL source to the 19.2MHz platform clock (MCLK) */ @@ -176,7 +192,7 @@ static const struct acpi_gpio_mapping cht_rt5672_gpios[] = { static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) { int ret; - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0); struct snd_soc_component *component = codec_dai->component; struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card); @@ -197,12 +213,24 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) | RT5670_AD_MONO_R_FILTER, RT5670_CLK_SEL_I2S1_ASRC); - ret = snd_soc_card_jack_new(runtime->card, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2, - &ctx->headset, - cht_bsw_headset_pins, - ARRAY_SIZE(cht_bsw_headset_pins)); + if (ctx->use_ssp0) { + ret = snd_soc_dapm_add_routes(&runtime->card->dapm, + cht_audio_ssp0_map, + ARRAY_SIZE(cht_audio_ssp0_map)); + } else { + ret = snd_soc_dapm_add_routes(&runtime->card->dapm, + cht_audio_ssp2_map, + ARRAY_SIZE(cht_audio_ssp2_map)); + } + if (ret) + return ret; + + ret = snd_soc_card_jack_new_pins(runtime->card, "Headset", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2, + &ctx->headset, + cht_bsw_headset_pins, + ARRAY_SIZE(cht_bsw_headset_pins)); if (ret) return ret; @@ -239,18 +267,26 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { + struct cht_mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - int ret; + int ret, bits; - /* The DSP will covert the FE rate to 48k, stereo, 24bits */ + /* The DSP will convert the FE rate to 48k, stereo, 24bits */ rate->min = rate->max = 48000; channels->min = channels->max = 2; - /* set SSP2 to 24-bit */ - params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + if (ctx->use_ssp0) { + /* set SSP0 to 16-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); + bits = 16; + } else { + /* set SSP2 to 24-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + bits = 24; + } /* * The default mode for the cpu-dai is TDM 4 slot. The default mode @@ -265,15 +301,21 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, * board. Since we only support 2 channels anyways, there is no need * for TDM on any cht-bsw-rt5672 designs. So we use I2S 2ch everywhere. */ - ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), + ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_BP_FP); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); return ret; } + ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, bits); + if (ret < 0) { + dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); + return ret; + } + return 0; } @@ -316,8 +358,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -326,7 +366,7 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -337,11 +377,8 @@ static struct snd_soc_dai_link cht_dailink[] = { .name = "SSP2-Codec", .id = 0, .no_pcm = 1, - .nonatomic = true, .init = cht_codec_init, .be_hw_params_fixup = cht_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_be_ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, @@ -382,19 +419,15 @@ static int cht_resume_post(struct snd_soc_card *card) return 0; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) /* use space before codec name to simplify card ID, and simplify driver name */ -#define CARD_NAME "bytcht rt5672" /* card name will be 'sof-bytcht rt5672' */ -#define DRIVER_NAME "SOF" -#else +#define SOF_CARD_NAME "bytcht rt5672" /* card name will be 'sof-bytcht rt5672' */ +#define SOF_DRIVER_NAME "SOF" + #define CARD_NAME "cht-bsw-rt5672" #define DRIVER_NAME NULL /* card name will be used for driver name */ -#endif /* SoC card */ static struct snd_soc_card snd_soc_card_cht = { - .name = CARD_NAME, - .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = cht_dailink, .num_links = ARRAY_SIZE(cht_dailink), @@ -417,6 +450,8 @@ static int snd_cht_mc_probe(struct platform_device *pdev) struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; const char *platform_name; struct acpi_device *adev; + bool sof_parent; + int dai_index = 0; int i; drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); @@ -425,22 +460,35 @@ static int snd_cht_mc_probe(struct platform_device *pdev) strcpy(drv->codec_name, RT5672_I2C_DEFAULT); + /* find index of codec dai */ + for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { + if (cht_dailink[i].num_codecs && + !strcmp(cht_dailink[i].codecs->name, RT5672_I2C_DEFAULT)) { + dai_index = i; + break; + } + } + /* fixup codec name based on HID */ adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1); if (adev) { snprintf(drv->codec_name, sizeof(drv->codec_name), "i2c-%s", acpi_dev_name(adev)); - put_device(&adev->dev); - for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { - if (!strcmp(cht_dailink[i].codecs->name, - RT5672_I2C_DEFAULT)) { - cht_dailink[i].codecs->name = drv->codec_name; - break; - } - } + cht_dailink[dai_index].codecs->name = drv->codec_name; + } else { + dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); + return -ENOENT; } - /* override plaform name, if required */ + acpi_dev_put(adev); + + /* Use SSP0 on Bay Trail CR devices */ + if (soc_intel_is_byt() && mach->mach_params.acpi_ipc_irq_index == 0) { + cht_dailink[dai_index].cpus->dai_name = "ssp0-port"; + drv->use_ssp0 = true; + } + + /* override platform name, if required */ snd_soc_card_cht.dev = &pdev->dev; platform_name = mach->mach_params.platform; @@ -449,6 +497,8 @@ static int snd_cht_mc_probe(struct platform_device *pdev) if (ret_val) return ret_val; + snd_soc_card_cht.components = rt5670_components(); + drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); if (IS_ERR(drv->mclk)) { dev_err(&pdev->dev, @@ -458,6 +508,21 @@ static int snd_cht_mc_probe(struct platform_device *pdev) } snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); + sof_parent = snd_soc_acpi_sof_parent(&pdev->dev); + + /* set card and driver name */ + if (sof_parent) { + snd_soc_card_cht.name = SOF_CARD_NAME; + snd_soc_card_cht.driver_name = SOF_DRIVER_NAME; + } else { + snd_soc_card_cht.name = CARD_NAME; + snd_soc_card_cht.driver_name = DRIVER_NAME; + } + + /* set pm ops */ + if (sof_parent) + pdev->dev.driver->pm = &snd_soc_pm_ops; + /* register the soc card */ ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); if (ret_val) { @@ -472,9 +537,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev) static struct platform_driver snd_cht_mc_driver = { .driver = { .name = "cht-bsw-rt5672", -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - .pm = &snd_soc_pm_ops, -#endif }, .probe = snd_cht_mc_probe, }; diff --git a/sound/soc/intel/boards/cml_rt1011_rt5682.c b/sound/soc/intel/boards/cml_rt1011_rt5682.c deleted file mode 100644 index 14813beb33d1..000000000000 --- a/sound/soc/intel/boards/cml_rt1011_rt5682.c +++ /dev/null @@ -1,596 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright(c) 2019 Intel Corporation. - -/* - * Intel Cometlake I2S Machine driver for RT1011 + RT5682 codec - */ - -#include <linux/input.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/dmi.h> -#include <linux/slab.h> -#include <linux/acpi.h> -#include <sound/core.h> -#include <sound/jack.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/rt5682.h> -#include <sound/soc-acpi.h> -#include "../../codecs/rt1011.h" -#include "../../codecs/rt5682.h" -#include "../../codecs/hdac_hdmi.h" -#include "hda_dsp_common.h" - -/* The platform clock outputs 24Mhz clock to codec as I2S MCLK */ -#define CML_PLAT_CLK 24000000 -#define CML_RT1011_CODEC_DAI "rt1011-aif" -#define CML_RT5682_CODEC_DAI "rt5682-aif1" -#define NAME_SIZE 32 - -#define SOF_RT1011_SPEAKER_WL BIT(0) -#define SOF_RT1011_SPEAKER_WR BIT(1) -#define SOF_RT1011_SPEAKER_TL BIT(2) -#define SOF_RT1011_SPEAKER_TR BIT(3) - -/* Default: Woofer speakers */ -static unsigned long sof_rt1011_quirk = SOF_RT1011_SPEAKER_WL | - SOF_RT1011_SPEAKER_WR; - -static int sof_rt1011_quirk_cb(const struct dmi_system_id *id) -{ - sof_rt1011_quirk = (unsigned long)id->driver_data; - return 1; -} - -static const struct dmi_system_id sof_rt1011_quirk_table[] = { - { - .callback = sof_rt1011_quirk_cb, - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Google"), - DMI_MATCH(DMI_PRODUCT_NAME, "Helios"), - }, - .driver_data = (void *)(SOF_RT1011_SPEAKER_WL | SOF_RT1011_SPEAKER_WR | - SOF_RT1011_SPEAKER_TL | SOF_RT1011_SPEAKER_TR), - }, - { - } -}; - -static struct snd_soc_jack hdmi_jack[3]; - -struct hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct card_private { - char codec_name[SND_ACPI_I2C_ID_LEN]; - struct snd_soc_jack headset; - struct list_head hdmi_pcm_list; - bool common_hdmi_codec_drv; -}; - -static const struct snd_kcontrol_new cml_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("WL Ext Spk"), - SOC_DAPM_PIN_SWITCH("WR Ext Spk"), -}; - -static const struct snd_kcontrol_new cml_rt1011_tt_controls[] = { - SOC_DAPM_PIN_SWITCH("TL Ext Spk"), - SOC_DAPM_PIN_SWITCH("TR Ext Spk"), -}; - -static const struct snd_soc_dapm_widget cml_rt1011_rt5682_widgets[] = { - SND_SOC_DAPM_SPK("WL Ext Spk", NULL), - SND_SOC_DAPM_SPK("WR Ext Spk", NULL), - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), -}; - -static const struct snd_soc_dapm_widget cml_rt1011_tt_widgets[] = { - SND_SOC_DAPM_SPK("TL Ext Spk", NULL), - SND_SOC_DAPM_SPK("TR Ext Spk", NULL), -}; - -static const struct snd_soc_dapm_route cml_rt1011_rt5682_map[] = { - /*WL/WR speaker*/ - {"WL Ext Spk", NULL, "WL SPO"}, - {"WR Ext Spk", NULL, "WR SPO"}, - - /* HP jack connectors - unknown if we have jack detection */ - { "Headphone Jack", NULL, "HPOL" }, - { "Headphone Jack", NULL, "HPOR" }, - - /* other jacks */ - { "IN1P", NULL, "Headset Mic" }, - - /* DMIC */ - {"DMic", NULL, "SoC DMIC"}, -}; - -static const struct snd_soc_dapm_route cml_rt1011_tt_map[] = { - /*TL/TR speaker*/ - {"TL Ext Spk", NULL, "TL SPO" }, - {"TR Ext Spk", NULL, "TR SPO" }, -}; - -static int cml_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; - struct snd_soc_jack *jack; - int ret; - - /* need to enable ASRC function for 24MHz mclk rate */ - rt5682_sel_asrc_clk_src(component, RT5682_DA_STEREO1_FILTER | - RT5682_AD_STEREO1_FILTER, - RT5682_CLK_SEL_I2S1_ASRC); - - /* - * 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 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - &ctx->headset, NULL, 0); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); - return ret; - } - - jack = &ctx->headset; - - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - ret = snd_soc_component_set_jack(component, jack, NULL); - if (ret) - dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); - - return ret; -}; - -static void cml_rt5682_codec_exit(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; - - snd_soc_component_set_jack(component, NULL, NULL); -} - -static int cml_rt1011_spk_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret = 0; - struct snd_soc_card *card = rtd->card; - - if (sof_rt1011_quirk & (SOF_RT1011_SPEAKER_TL | - SOF_RT1011_SPEAKER_TR)) { - - ret = snd_soc_add_card_controls(card, cml_rt1011_tt_controls, - ARRAY_SIZE(cml_rt1011_tt_controls)); - if (ret) - return ret; - - ret = snd_soc_dapm_new_controls(&card->dapm, - cml_rt1011_tt_widgets, - ARRAY_SIZE(cml_rt1011_tt_widgets)); - if (ret) - return ret; - - ret = snd_soc_dapm_add_routes(&card->dapm, cml_rt1011_tt_map, - ARRAY_SIZE(cml_rt1011_tt_map)); - - if (ret) - return ret; - } - - return ret; -} - -static int cml_rt5682_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - int clk_id, clk_freq, pll_out, ret; - - clk_id = RT5682_PLL1_S_MCLK; - clk_freq = CML_PLAT_CLK; - - pll_out = params_rate(params) * 512; - - ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out); - if (ret < 0) - dev_warn(rtd->dev, "snd_soc_dai_set_pll err = %d\n", ret); - - /* Configure sysclk for codec */ - ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, - pll_out, SND_SOC_CLOCK_IN); - if (ret < 0) - dev_warn(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); - - /* - * slot_width should be equal or large than data length, set them - * be the same - */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2, - params_width(params)); - if (ret < 0) - dev_warn(rtd->dev, "set TDM slot err:%d\n", ret); - return ret; -} - -static int cml_rt1011_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai; - struct snd_soc_card *card = rtd->card; - int srate, i, ret = 0; - - srate = params_rate(params); - - for_each_rtd_codec_dais(rtd, i, codec_dai) { - - /* 100 Fs to drive 24 bit data */ - ret = snd_soc_dai_set_pll(codec_dai, 0, RT1011_PLL1_S_BCLK, - 100 * srate, 256 * srate); - if (ret < 0) { - dev_err(card->dev, "codec_dai clock not set\n"); - return ret; - } - - ret = snd_soc_dai_set_sysclk(codec_dai, - RT1011_FS_SYS_PRE_S_PLL1, - 256 * srate, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(card->dev, "codec_dai clock not set\n"); - return ret; - } - - /* - * Codec TDM is configured as 24 bit capture/ playback. - * 2 CH PB is done over 4 codecs - 2 Woofers and 2 Tweeters. - * The Left woofer and tweeter plays the Left playback data - * and similar by the Right. - * Hence 2 codecs (1 T and 1 W pair) share same Rx slot. - * The feedback is captured for each codec individually. - * Hence all 4 codecs use 1 Tx slot each for feedback. - */ - if (sof_rt1011_quirk & (SOF_RT1011_SPEAKER_WL | - SOF_RT1011_SPEAKER_WR)) { - if (!strcmp(codec_dai->component->name, "i2c-10EC1011:00")) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, - 0x4, 0x1, 4, 24); - if (ret < 0) - break; - } - - if (!strcmp(codec_dai->component->name, "i2c-10EC1011:01")) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, - 0x8, 0x2, 4, 24); - if (ret < 0) - break; - } - } - - if (sof_rt1011_quirk & (SOF_RT1011_SPEAKER_TL | - SOF_RT1011_SPEAKER_TR)) { - if (!strcmp(codec_dai->component->name, "i2c-10EC1011:02")) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, - 0x1, 0x1, 4, 24); - if (ret < 0) - break; - } - - if (!strcmp(codec_dai->component->name, "i2c-10EC1011:03")) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, - 0x2, 0x2, 4, 24); - if (ret < 0) - break; - } - } - } - if (ret < 0) - dev_err(rtd->dev, - "set codec TDM slot for %s failed with error %d\n", - codec_dai->component->name, ret); - return ret; -} - -static struct snd_soc_ops cml_rt5682_ops = { - .hw_params = cml_rt5682_hw_params, -}; - -static const struct snd_soc_ops cml_rt1011_ops = { - .hw_params = cml_rt1011_hw_params, -}; - -static int sof_card_late_probe(struct snd_soc_card *card) -{ - struct card_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_component *component = NULL; - char jack_name[NAME_SIZE]; - struct hdmi_pcm *pcm; - int ret, i = 0; - - if (list_empty(&ctx->hdmi_pcm_list)) - return -EINVAL; - - if (ctx->common_hdmi_codec_drv) { - pcm = list_first_entry(&ctx->hdmi_pcm_list, struct hdmi_pcm, - head); - component = pcm->codec_dai->component; - return hda_dsp_hdmi_build_controls(card, component); - } - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - ret = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &hdmi_jack[i], - NULL, 0); - if (ret) - return ret; - - ret = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &hdmi_jack[i]); - if (ret < 0) - return ret; - - i++; - } - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -static int hdmi_init(struct snd_soc_pcm_runtime *rtd) -{ - struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); - struct hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = dai->id; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -/* Cometlake digital audio interface glue - connects codec <--> CPU */ - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00", - CML_RT5682_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(ssp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); -SND_SOC_DAILINK_DEF(ssp1_codec_2spk, - DAILINK_COMP_ARRAY( - /* WL */ COMP_CODEC("i2c-10EC1011:00", CML_RT1011_CODEC_DAI), - /* WR */ COMP_CODEC("i2c-10EC1011:01", CML_RT1011_CODEC_DAI))); -SND_SOC_DAILINK_DEF(ssp1_codec_4spk, - DAILINK_COMP_ARRAY( - /* WL */ COMP_CODEC("i2c-10EC1011:00", CML_RT1011_CODEC_DAI), - /* WR */ COMP_CODEC("i2c-10EC1011:01", CML_RT1011_CODEC_DAI), - /* TL */ COMP_CODEC("i2c-10EC1011:02", CML_RT1011_CODEC_DAI), - /* TR */ COMP_CODEC("i2c-10EC1011:03", CML_RT1011_CODEC_DAI))); - - -SND_SOC_DAILINK_DEF(dmic_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); - -SND_SOC_DAILINK_DEF(dmic16k_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin"))); - -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:1f.3"))); - -static struct snd_soc_dai_link cml_rt1011_rt5682_dailink[] = { - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .init = cml_rt5682_codec_init, - .exit = cml_rt5682_codec_exit, - .ignore_pmdown_time = 1, - .ops = &cml_rt5682_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - .name = "dmic01", - .id = 1, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "dmic16k", - .id = 2, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic16k_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .init = hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, - { - /* - * SSP1 - Codec : added to end of list ensuring - * reuse of common topologies for other end points - * and changing only SSP1's codec - */ - .name = "SSP1-Codec", - .id = 6, - .dpcm_playback = 1, - .dpcm_capture = 1, /* Capture stream provides Feedback */ - .no_pcm = 1, - .init = cml_rt1011_spk_init, - .ops = &cml_rt1011_ops, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec_2spk, platform), - }, -}; - -static struct snd_soc_codec_conf rt1011_conf[] = { - { - .dlc = COMP_CODEC_CONF("i2c-10EC1011:00"), - .name_prefix = "WL", - }, - { - .dlc = COMP_CODEC_CONF("i2c-10EC1011:01"), - .name_prefix = "WR", - }, - /* single configuration structure for 2 and 4 channels */ - { - .dlc = COMP_CODEC_CONF("i2c-10EC1011:02"), - .name_prefix = "TL", - }, - { - .dlc = COMP_CODEC_CONF("i2c-10EC1011:03"), - .name_prefix = "TR", - }, -}; - -/* Cometlake audio machine driver for RT1011 and RT5682 */ -static struct snd_soc_card snd_soc_card_cml = { - .name = "cml_rt1011_rt5682", - .owner = THIS_MODULE, - .dai_link = cml_rt1011_rt5682_dailink, - .num_links = ARRAY_SIZE(cml_rt1011_rt5682_dailink), - .codec_conf = rt1011_conf, - .num_configs = ARRAY_SIZE(rt1011_conf), - .dapm_widgets = cml_rt1011_rt5682_widgets, - .num_dapm_widgets = ARRAY_SIZE(cml_rt1011_rt5682_widgets), - .dapm_routes = cml_rt1011_rt5682_map, - .num_dapm_routes = ARRAY_SIZE(cml_rt1011_rt5682_map), - .controls = cml_controls, - .num_controls = ARRAY_SIZE(cml_controls), - .fully_routed = true, - .late_probe = sof_card_late_probe, -}; - -static int snd_cml_rt1011_probe(struct platform_device *pdev) -{ - struct snd_soc_dai_link *dai_link; - struct card_private *ctx; - struct snd_soc_acpi_mach *mach; - const char *platform_name; - int ret, i; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - mach = pdev->dev.platform_data; - snd_soc_card_cml.dev = &pdev->dev; - platform_name = mach->mach_params.platform; - - dmi_check_system(sof_rt1011_quirk_table); - - dev_dbg(&pdev->dev, "sof_rt1011_quirk = %lx\n", sof_rt1011_quirk); - - /* when 4 speaker is available, update codec config */ - if (sof_rt1011_quirk & (SOF_RT1011_SPEAKER_TL | - SOF_RT1011_SPEAKER_TR)) { - for_each_card_prelinks(&snd_soc_card_cml, i, dai_link) { - if (!strcmp(dai_link->codecs[0].dai_name, - CML_RT1011_CODEC_DAI)) { - dai_link->codecs = ssp1_codec_4spk; - dai_link->num_codecs = ARRAY_SIZE(ssp1_codec_4spk); - } - } - } - - /* set platform name for each dailink */ - ret = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cml, - platform_name); - if (ret) - return ret; - - ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; - - snd_soc_card_set_drvdata(&snd_soc_card_cml, ctx); - - return devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cml); -} - -static struct platform_driver snd_cml_rt1011_rt5682_driver = { - .probe = snd_cml_rt1011_probe, - .driver = { - .name = "cml_rt1011_rt5682", - .pm = &snd_soc_pm_ops, - }, -}; -module_platform_driver(snd_cml_rt1011_rt5682_driver); - -/* Module information */ -MODULE_DESCRIPTION("Cometlake Audio Machine driver - RT1011 and RT5682 in I2S mode"); -MODULE_AUTHOR("Naveen Manohar <naveen.m@intel.com>"); -MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>"); -MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>"); -MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:cml_rt1011_rt5682"); diff --git a/sound/soc/intel/boards/ehl_rt5660.c b/sound/soc/intel/boards/ehl_rt5660.c index 7c0d4e915406..5c7b218f22b7 100644 --- a/sound/soc/intel/boards/ehl_rt5660.c +++ b/sound/soc/intel/boards/ehl_rt5660.c @@ -74,7 +74,7 @@ struct sof_hdmi_pcm { static int hdmi_init(struct snd_soc_pcm_runtime *rtd) { struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); struct sof_hdmi_pcm *pcm; pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); @@ -109,8 +109,8 @@ static int card_late_probe(struct snd_soc_card *card) static int rt5660_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); int ret; ret = snd_soc_dai_set_sysclk(codec_dai, @@ -132,7 +132,7 @@ static int rt5660_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops rt5660_ops = { +static const struct snd_soc_ops rt5660_ops = { .hw_params = rt5660_hw_params, }; @@ -178,17 +178,14 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "SSP0-Codec", .id = 0, .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &rt5660_ops, - .nonatomic = true, SND_SOC_DAILINK_REG(ssp0_pin, rt5660_codec, platform), }, { .name = "dmic48k", .id = 1, .ignore_suspend = 1, - .dpcm_capture = 1, + .capture_only = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), }, @@ -196,7 +193,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "dmic16k", .id = 2, .ignore_suspend = 1, - .dpcm_capture = 1, + .capture_only = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(dmic16k, dmic_codec, platform), }, @@ -204,7 +201,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "iDisp1", .id = 5, .init = hdmi_init, - .dpcm_playback = 1, + .playback_only = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), }, @@ -212,7 +209,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "iDisp2", .id = 6, .init = hdmi_init, - .dpcm_playback = 1, + .playback_only = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), }, @@ -220,7 +217,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "iDisp3", .id = 7, .init = hdmi_init, - .dpcm_playback = 1, + .playback_only = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), }, @@ -228,7 +225,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "iDisp4", .id = 8, .init = hdmi_init, - .dpcm_playback = 1, + .playback_only = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(idisp4_pin, idisp4_codec, platform), }, @@ -255,11 +252,9 @@ static void hdmi_link_init(struct snd_soc_card *card, struct sof_card_private *ctx, struct snd_soc_acpi_mach *mach) { - struct snd_soc_dai_link *link; int i; - if (mach->mach_params.common_hdmi_codec_drv && - (mach->mach_params.codec_mask & IDISP_CODEC_MASK)) { + if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) { ctx->idisp_codec = true; return; } @@ -268,11 +263,8 @@ static void hdmi_link_init(struct snd_soc_card *card, * if HDMI is not enabled in kernel config, or * hdmi codec is not supported */ - for (i = HDMI_LINK_START; i <= HDMI_LINE_END; i++) { - link = &card->dai_link[i]; - link->codecs[0].name = "snd-soc-dummy"; - link->codecs[0].dai_name = "snd-soc-dummy-dai"; - } + for (i = HDMI_LINK_START; i <= HDMI_LINE_END; i++) + card->dai_link[i].codecs[0] = snd_soc_dummy_dlc; } static int snd_ehl_rt5660_probe(struct platform_device *pdev) @@ -305,6 +297,7 @@ static const struct platform_device_id ehl_board_ids[] = { { .name = "ehl_rt5660" }, { } }; +MODULE_DEVICE_TABLE(platform, ehl_board_ids); static struct platform_driver snd_ehl_rt5660_driver = { .driver = { @@ -320,4 +313,4 @@ module_platform_driver(snd_ehl_rt5660_driver); MODULE_DESCRIPTION("ASoC Intel(R) Elkhartlake + rt5660 Machine driver"); MODULE_AUTHOR("libin.yang@intel.com"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:ehl_rt5660"); +MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON"); diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c deleted file mode 100644 index 62cca511522e..000000000000 --- a/sound/soc/intel/boards/glk_rt5682_max98357a.c +++ /dev/null @@ -1,644 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright(c) 2018 Intel Corporation. - -/* - * Intel Geminilake I2S Machine Driver with MAX98357A & RT5682 Codecs - * - * Modified from: - * Intel Apollolake I2S Machine driver - */ - -#include <linux/input.h> -#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> -#include <sound/soc-acpi.h> -#include "../../codecs/rt5682.h" -#include "../../codecs/hdac_hdmi.h" -#include "hda_dsp_common.h" - -/* The platform clock outputs 19.2Mhz clock to codec as I2S MCLK */ -#define GLK_PLAT_CLK_FREQ 19200000 -#define RT5682_PLL_FREQ (48000 * 512) -#define GLK_REALTEK_CODEC_DAI "rt5682-aif1" -#define GLK_MAXIM_CODEC_DAI "HiFi" -#define MAXIM_DEV0_NAME "MX98357A:00" -#define DUAL_CHANNEL 2 -#define QUAD_CHANNEL 4 -#define NAME_SIZE 32 - -static struct snd_soc_jack geminilake_hdmi[3]; - -struct glk_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct glk_card_private { - struct snd_soc_jack geminilake_headset; - struct list_head hdmi_pcm_list; - bool common_hdmi_codec_drv; -}; - -enum { - GLK_DPCM_AUDIO_PB = 0, - GLK_DPCM_AUDIO_CP, - GLK_DPCM_AUDIO_HS_PB, - GLK_DPCM_AUDIO_ECHO_REF_CP, - GLK_DPCM_AUDIO_REF_CP, - GLK_DPCM_AUDIO_DMIC_CP, - GLK_DPCM_AUDIO_HDMI1_PB, - GLK_DPCM_AUDIO_HDMI2_PB, - GLK_DPCM_AUDIO_HDMI3_PB, -}; - -static const struct snd_kcontrol_new geminilake_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Spk"), -}; - -static const struct snd_soc_dapm_widget geminilake_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Spk", 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), -}; - -static const struct snd_soc_dapm_route geminilake_map[] = { - /* HP jack connectors - unknown if we have jack detection */ - { "Headphone Jack", NULL, "HPOL" }, - { "Headphone Jack", NULL, "HPOR" }, - - /* speaker */ - { "Spk", NULL, "Speaker" }, - - /* other jacks */ - { "IN1P", NULL, "Headset Mic" }, - - /* digital mics */ - { "DMic", NULL, "SoC DMIC" }, - - /* CODEC BE connections */ - { "HiFi Playback", NULL, "ssp1 Tx" }, - { "ssp1 Tx", NULL, "codec0_out" }, - - { "AIF1 Playback", NULL, "ssp2 Tx" }, - { "ssp2 Tx", NULL, "codec1_out" }, - - { "codec0_in", NULL, "ssp2 Rx" }, - { "ssp2 Rx", NULL, "AIF1 Capture" }, - - { "HDMI1", NULL, "hif5-0 Output" }, - { "HDMI2", NULL, "hif6-0 Output" }, - { "HDMI2", NULL, "hif7-0 Output" }, - - { "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" }, -}; - -static int geminilake_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); - struct snd_interval *chan = hw_param_interval(params, - 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; - chan->min = chan->max = DUAL_CHANNEL; - - /* set SSP to 24 bit */ - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - - return 0; -} - -static int geminilake_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - struct glk_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - struct snd_soc_jack *jack; - int ret; - - ret = snd_soc_dai_set_pll(codec_dai, 0, RT5682_PLL1_S_MCLK, - GLK_PLAT_CLK_FREQ, RT5682_PLL_FREQ); - if (ret < 0) { - dev_err(rtd->dev, "can't set codec pll: %d\n", ret); - return ret; - } - - /* Configure sysclk for codec */ - ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, - RT5682_PLL_FREQ, SND_SOC_CLOCK_IN); - if (ret < 0) - dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); - - /* - * 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 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, - &ctx->geminilake_headset, NULL, 0); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); - return ret; - } - - jack = &ctx->geminilake_headset; - - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - - ret = snd_soc_component_set_jack(component, jack, NULL); - - if (ret) { - dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); - return ret; - } - - return ret; -}; - -static int geminilake_rt5682_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - int ret; - - /* Set valid bitmask & configuration for I2S in 24 bit */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2, 24); - if (ret < 0) { - dev_err(rtd->dev, "set TDM slot err:%d\n", ret); - return ret; - } - - return ret; -} - -static struct snd_soc_ops geminilake_rt5682_ops = { - .hw_params = geminilake_rt5682_hw_params, -}; - -static int geminilake_hdmi_init(struct snd_soc_pcm_runtime *rtd) -{ - struct glk_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); - struct glk_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = GLK_DPCM_AUDIO_HDMI1_PB + dai->id; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int geminilake_rt5682_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_component *component = asoc_rtd_to_cpu(rtd, 0)->component; - struct snd_soc_dapm_context *dapm; - int ret; - - dapm = snd_soc_component_get_dapm(component); - ret = snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - if (ret) { - dev_err(rtd->dev, "Ref Cap ignore suspend failed %d\n", ret); - return ret; - } - - return ret; -} - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static unsigned int channels_quad[] = { - QUAD_CHANNEL, -}; - -static struct snd_pcm_hw_constraint_list constraints_channels_quad = { - .count = ARRAY_SIZE(channels_quad), - .list = channels_quad, - .mask = 0, -}; - -static int geminilake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - - /* - * set BE channel constraint as user FE channels - */ - chan->min = chan->max = 4; - - return 0; -} - -static int geminilake_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels_quad); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static const struct snd_soc_ops geminilake_dmic_ops = { - .startup = geminilake_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, -}; - -static int geminilake_refcap_startup(struct snd_pcm_substream *substream) -{ - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_16000); -}; - -static const struct snd_soc_ops geminilake_refcap_ops = { - .startup = geminilake_refcap_startup, -}; - -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(echoref, - DAILINK_COMP_ARRAY(COMP_CPU("Echoref Pin"))); - -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"))); - -SND_SOC_DAILINK_DEF(ssp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); -SND_SOC_DAILINK_DEF(ssp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC(MAXIM_DEV0_NAME, - GLK_MAXIM_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(ssp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP2 Pin"))); -SND_SOC_DAILINK_DEF(ssp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00", - GLK_REALTEK_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(dmic_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); -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"))); - -/* geminilake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link geminilake_dais[] = { - /* Front End DAI links */ - [GLK_DPCM_AUDIO_PB] = { - .name = "Glk Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = geminilake_rt5682_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [GLK_DPCM_AUDIO_CP] = { - .name = "Glk 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, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [GLK_DPCM_AUDIO_HS_PB] = { - .name = "Glk Audio Headset Playback", - .stream_name = "Headset Audio", - .dpcm_playback = 1, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(system2, dummy, platform), - }, - [GLK_DPCM_AUDIO_ECHO_REF_CP] = { - .name = "Glk Audio Echo Reference cap", - .stream_name = "Echoreference Capture", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(echoref, dummy, platform), - }, - [GLK_DPCM_AUDIO_REF_CP] = { - .name = "Glk Audio Reference cap", - .stream_name = "Refcap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &geminilake_refcap_ops, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [GLK_DPCM_AUDIO_DMIC_CP] = { - .name = "Glk Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &geminilake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [GLK_DPCM_AUDIO_HDMI1_PB] = { - .name = "Glk HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [GLK_DPCM_AUDIO_HDMI2_PB] = { - .name = "Glk HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [GLK_DPCM_AUDIO_HDMI3_PB] = { - .name = "Glk HDMI Port3", - .stream_name = "Hdmi3", - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - /* Back End DAI links */ - { - /* SSP1 - Codec */ - .name = "SSP1-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 = geminilake_ssp_fixup, - .dpcm_playback = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - /* SSP2 - Codec */ - .name = "SSP2-Codec", - .id = 1, - .no_pcm = 1, - .init = geminilake_rt5682_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 = geminilake_ssp_fixup, - .ops = &geminilake_rt5682_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp2_pin, ssp2_codec, platform), - }, - { - .name = "dmic01", - .id = 2, - .ignore_suspend = 1, - .be_hw_params_fixup = geminilake_dmic_fixup, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .init = geminilake_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = geminilake_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = geminilake_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -static int glk_card_late_probe(struct snd_soc_card *card) -{ - struct glk_card_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_component *component = NULL; - char jack_name[NAME_SIZE]; - struct glk_hdmi_pcm *pcm; - int err; - int i = 0; - - if (list_empty(&ctx->hdmi_pcm_list)) - return -EINVAL; - - if (ctx->common_hdmi_codec_drv) { - pcm = list_first_entry(&ctx->hdmi_pcm_list, struct glk_hdmi_pcm, - head); - component = pcm->codec_dai->component; - return hda_dsp_hdmi_build_controls(card, component); - } - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - 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, &geminilake_hdmi[i], - NULL, 0); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &geminilake_hdmi[i]); - if (err < 0) - return err; - - i++; - } - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* geminilake audio machine driver for SPT + RT5682 */ -static struct snd_soc_card glk_audio_card_rt5682_m98357a = { - .name = "glkrt5682max", - .owner = THIS_MODULE, - .dai_link = geminilake_dais, - .num_links = ARRAY_SIZE(geminilake_dais), - .controls = geminilake_controls, - .num_controls = ARRAY_SIZE(geminilake_controls), - .dapm_widgets = geminilake_widgets, - .num_dapm_widgets = ARRAY_SIZE(geminilake_widgets), - .dapm_routes = geminilake_map, - .num_dapm_routes = ARRAY_SIZE(geminilake_map), - .fully_routed = true, - .late_probe = glk_card_late_probe, -}; - -static int geminilake_audio_probe(struct platform_device *pdev) -{ - struct glk_card_private *ctx; - struct snd_soc_acpi_mach *mach; - const char *platform_name; - struct snd_soc_card *card; - int ret; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - card = &glk_audio_card_rt5682_m98357a; - card->dev = &pdev->dev; - snd_soc_card_set_drvdata(card, ctx); - - /* override plaform name, if required */ - mach = pdev->dev.platform_data; - platform_name = mach->mach_params.platform; - - ret = snd_soc_fixup_dai_links_platform_name(card, platform_name); - if (ret) - return ret; - - ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; - - return devm_snd_soc_register_card(&pdev->dev, card); -} - -static const struct platform_device_id glk_board_ids[] = { - { - .name = "glk_rt5682_max98357a", - .driver_data = - (kernel_ulong_t)&glk_audio_card_rt5682_m98357a, - }, - { } -}; - -static struct platform_driver geminilake_audio = { - .probe = geminilake_audio_probe, - .driver = { - .name = "glk_rt5682_max98357a", - .pm = &snd_soc_pm_ops, - }, - .id_table = glk_board_ids, -}; -module_platform_driver(geminilake_audio) - -/* Module information */ -MODULE_DESCRIPTION("Geminilake Audio Machine driver-RT5682 & MAX98357A in I2S mode"); -MODULE_AUTHOR("Naveen Manohar <naveen.m@intel.com>"); -MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:glk_rt5682_max98357a"); diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c deleted file mode 100644 index 744b7b5b8106..000000000000 --- a/sound/soc/intel/boards/haswell.c +++ /dev/null @@ -1,217 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Haswell Lynxpoint SST Audio - * - * Copyright (C) 2013, Intel Corporation. All rights reserved. - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include <sound/pcm_params.h> - -#include "../common/sst-dsp.h" -#include "../haswell/sst-haswell-ipc.h" - -#include "../../codecs/rt5640.h" - -/* Haswell ULT platforms have a Headphone and Mic jack */ -static const struct snd_soc_dapm_widget haswell_widgets[] = { - SND_SOC_DAPM_HP("Headphones", NULL), - SND_SOC_DAPM_MIC("Mic", NULL), -}; - -static const struct snd_soc_dapm_route haswell_rt5640_map[] = { - - {"Headphones", NULL, "HPOR"}, - {"Headphones", NULL, "HPOL"}, - {"IN2P", NULL, "Mic"}, - - /* CODEC BE connections */ - {"SSP0 CODEC IN", NULL, "AIF1 Capture"}, - {"AIF1 Playback", NULL, "SSP0 CODEC OUT"}, -}; - -static int haswell_ssp0_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); - struct snd_interval *channels = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - - /* The ADSP will covert the FE rate to 48k, stereo */ - rate->min = rate->max = 48000; - channels->min = channels->max = 2; - - /* set SSP0 to 16 bit */ - params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); - return 0; -} - -static int haswell_rt5640_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - int ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_MCLK, 12288000, - SND_SOC_CLOCK_IN); - - if (ret < 0) { - dev_err(rtd->dev, "can't set codec sysclk configuration\n"); - return ret; - } - - /* set correct codec filter for DAI format and clock config */ - snd_soc_component_update_bits(codec_dai->component, 0x83, 0xffff, 0x8000); - - return ret; -} - -static const struct snd_soc_ops haswell_rt5640_ops = { - .hw_params = haswell_rt5640_hw_params, -}; - -static int haswell_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); - struct sst_pdata *pdata = dev_get_platdata(component->dev); - struct sst_hsw *haswell = pdata->dsp; - int ret; - - /* Set ADSP SSP port settings */ - ret = sst_hsw_device_set_config(haswell, SST_HSW_DEVICE_SSP_0, - SST_HSW_DEVICE_MCLK_FREQ_24_MHZ, - SST_HSW_DEVICE_CLOCK_MASTER, 9); - if (ret < 0) { - dev_err(rtd->dev, "failed to set device config\n"); - return ret; - } - - return 0; -} - -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(offload0, - DAILINK_COMP_ARRAY(COMP_CPU("Offload0 Pin"))); - -SND_SOC_DAILINK_DEF(offload1, - DAILINK_COMP_ARRAY(COMP_CPU("Offload1 Pin"))); - -SND_SOC_DAILINK_DEF(loopback, - DAILINK_COMP_ARRAY(COMP_CPU("Loopback Pin"))); - -SND_SOC_DAILINK_DEF(codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT33CA:00", "rt5640-aif1"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("haswell-pcm-audio"))); - -static struct snd_soc_dai_link haswell_rt5640_dais[] = { - /* Front End DAI links */ - { - .name = "System", - .stream_name = "System Playback/Capture", - .dynamic = 1, - .init = haswell_rtd_init, - .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - { - .name = "Offload0", - .stream_name = "Offload0 Playback", - .dynamic = 1, - .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - SND_SOC_DAILINK_REG(offload0, dummy, platform), - }, - { - .name = "Offload1", - .stream_name = "Offload1 Playback", - .dynamic = 1, - .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - SND_SOC_DAILINK_REG(offload1, dummy, platform), - }, - { - .name = "Loopback", - .stream_name = "Loopback", - .dynamic = 1, - .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(loopback, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "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 = haswell_ssp0_fixup, - .ops = &haswell_rt5640_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(dummy, codec, dummy), - }, -}; - -/* audio machine driver for Haswell Lynxpoint DSP + RT5640 */ -static struct snd_soc_card haswell_rt5640 = { - .name = "haswell-rt5640", - .owner = THIS_MODULE, - .dai_link = haswell_rt5640_dais, - .num_links = ARRAY_SIZE(haswell_rt5640_dais), - .dapm_widgets = haswell_widgets, - .num_dapm_widgets = ARRAY_SIZE(haswell_widgets), - .dapm_routes = haswell_rt5640_map, - .num_dapm_routes = ARRAY_SIZE(haswell_rt5640_map), - .fully_routed = true, -}; - -static int haswell_audio_probe(struct platform_device *pdev) -{ - struct snd_soc_acpi_mach *mach; - int ret; - - haswell_rt5640.dev = &pdev->dev; - - /* override plaform name, if required */ - mach = pdev->dev.platform_data; - ret = snd_soc_fixup_dai_links_platform_name(&haswell_rt5640, - mach->mach_params.platform); - if (ret) - return ret; - - return devm_snd_soc_register_card(&pdev->dev, &haswell_rt5640); -} - -static struct platform_driver haswell_audio = { - .probe = haswell_audio_probe, - .driver = { - .name = "haswell-audio", - }, -}; - -module_platform_driver(haswell_audio) - -/* Module information */ -MODULE_AUTHOR("Liam Girdwood, Xingchao Wang"); -MODULE_DESCRIPTION("Intel SST Audio for Haswell Lynxpoint"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:haswell-audio"); diff --git a/sound/soc/intel/boards/hda_dsp_common.c b/sound/soc/intel/boards/hda_dsp_common.c index 244b57fba64c..86e541a2c204 100644 --- a/sound/soc/intel/boards/hda_dsp_common.c +++ b/sound/soc/intel/boards/hda_dsp_common.c @@ -1,7 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2019 Intel Corporation. All rights reserved. +// Copyright(c) 2019 Intel Corporation +#include <linux/module.h> #include <sound/pcm.h> #include <sound/soc.h> #include <sound/hda_codec.h> @@ -10,12 +11,14 @@ #include "hda_dsp_common.h" +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) + /* * Search card topology and return PCM device number * matching Nth HDMI device (zero-based index). */ -struct snd_pcm *hda_dsp_hdmi_pcm_handle(struct snd_soc_card *card, - int hdmi_idx) +static struct snd_pcm *hda_dsp_hdmi_pcm_handle(struct snd_soc_card *card, + int hdmi_idx) { struct snd_soc_pcm_runtime *rtd; struct snd_pcm *spcm; @@ -34,7 +37,6 @@ struct snd_pcm *hda_dsp_hdmi_pcm_handle(struct snd_soc_card *card, return NULL; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) /* * Search card topology and register HDMI PCM related controls * to codec driver. @@ -52,7 +54,7 @@ int hda_dsp_hdmi_build_controls(struct snd_soc_card *card, return -EINVAL; hda_pvt = snd_soc_component_get_drvdata(comp); - hcodec = &hda_pvt->codec; + hcodec = hda_pvt->codec; list_for_each_entry(hpcm, &hcodec->pcm_list_head, list) { spcm = hda_dsp_hdmi_pcm_handle(card, i); @@ -60,13 +62,13 @@ int hda_dsp_hdmi_build_controls(struct snd_soc_card *card, hpcm->pcm = spcm; hpcm->device = spcm->device; dev_dbg(card->dev, - "%s: mapping HDMI converter %d to PCM %d (%p)\n", - __func__, i, hpcm->device, spcm); + "mapping HDMI converter %d to PCM %d (%p)\n", + i, hpcm->device, spcm); } else { hpcm->pcm = NULL; hpcm->device = SNDRV_PCM_INVALID_DEVICE; dev_warn(card->dev, - "%s: no PCM in topology for HDMI converter %d\n\n", + "%s: no PCM in topology for HDMI converter %d\n", __func__, i); } i++; @@ -81,5 +83,9 @@ int hda_dsp_hdmi_build_controls(struct snd_soc_card *card, return err; } +EXPORT_SYMBOL_NS(hda_dsp_hdmi_build_controls, "SND_SOC_INTEL_HDA_DSP_COMMON"); #endif + +MODULE_DESCRIPTION("ASoC Intel HDMI helpers"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/boards/hda_dsp_common.h b/sound/soc/intel/boards/hda_dsp_common.h index 727edd256962..ea4ae9285cf0 100644 --- a/sound/soc/intel/boards/hda_dsp_common.h +++ b/sound/soc/intel/boards/hda_dsp_common.h @@ -15,9 +15,6 @@ #include <sound/hda_i915.h> #include "../../codecs/hdac_hda.h" -struct snd_pcm *hda_dsp_hdmi_pcm_handle(struct snd_soc_card *card, - int hdmi_idx); - #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) int hda_dsp_hdmi_build_controls(struct snd_soc_card *card, struct snd_soc_component *comp); diff --git a/sound/soc/intel/boards/hsw_rt5640.c b/sound/soc/intel/boards/hsw_rt5640.c new file mode 100644 index 000000000000..9bb2822ba63e --- /dev/null +++ b/sound/soc/intel/boards/hsw_rt5640.c @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Sound card driver for Intel Haswell Lynx Point with Realtek 5640 + * + * Copyright (C) 2013, Intel Corporation + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include "../../codecs/rt5640.h" + +static const struct snd_soc_dapm_widget card_widgets[] = { + SND_SOC_DAPM_HP("Headphones", NULL), + SND_SOC_DAPM_MIC("Mic", NULL), +}; + +static const struct snd_soc_dapm_route card_routes[] = { + {"Headphones", NULL, "HPOR"}, + {"Headphones", NULL, "HPOL"}, + {"IN2P", NULL, "Mic"}, + + /* CODEC BE connections */ + {"SSP0 CODEC IN", NULL, "AIF1 Capture"}, + {"AIF1 Playback", NULL, "SSP0 CODEC OUT"}, +}; + +static int codec_link_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + + /* The ADSP will convert the FE rate to 48k, stereo. */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + /* Set SSP0 to 16 bit. */ + params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); + + return 0; +} + +static int codec_link_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + int ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_MCLK, 12288000, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(rtd->dev, "set codec sysclk failed: %d\n", ret); + return ret; + } + + /* Set correct codec filter for DAI format and clock config. */ + snd_soc_component_update_bits(codec_dai->component, 0x83, 0xffff, 0x8000); + + return ret; +} + +static const struct snd_soc_ops codec_link_ops = { + .hw_params = codec_link_hw_params, +}; + +SND_SOC_DAILINK_DEF(system, DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); +SND_SOC_DAILINK_DEF(offload0, DAILINK_COMP_ARRAY(COMP_CPU("Offload0 Pin"))); +SND_SOC_DAILINK_DEF(offload1, DAILINK_COMP_ARRAY(COMP_CPU("Offload1 Pin"))); +SND_SOC_DAILINK_DEF(loopback, DAILINK_COMP_ARRAY(COMP_CPU("Loopback Pin"))); + +SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY())); +SND_SOC_DAILINK_DEF(codec, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT33CA:00", "rt5640-aif1"))); +SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("haswell-pcm-audio"))); +SND_SOC_DAILINK_DEF(ssp0_port, DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port"))); + +static struct snd_soc_dai_link card_dai_links[] = { + /* Front End DAI links */ + { + .name = "System", + .stream_name = "System Playback/Capture", + .nonatomic = 1, + .dynamic = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + SND_SOC_DAILINK_REG(system, dummy, platform), + }, + { + .name = "Offload0", + .stream_name = "Offload0 Playback", + .nonatomic = 1, + .dynamic = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .playback_only = 1, + SND_SOC_DAILINK_REG(offload0, dummy, platform), + }, + { + .name = "Offload1", + .stream_name = "Offload1 Playback", + .nonatomic = 1, + .dynamic = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .playback_only = 1, + SND_SOC_DAILINK_REG(offload1, dummy, platform), + }, + { + .name = "Loopback", + .stream_name = "Loopback", + .nonatomic = 1, + .dynamic = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .capture_only = 1, + SND_SOC_DAILINK_REG(loopback, dummy, platform), + }, + /* Back End DAI links */ + { + /* SSP0 - Codec */ + .name = "Codec", + .id = 0, + .nonatomic = 1, + .no_pcm = 1, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = codec_link_hw_params_fixup, + .ops = &codec_link_ops, + SND_SOC_DAILINK_REG(ssp0_port, codec, platform), + }, +}; + +static struct snd_soc_card hsw_rt5640_card = { + .name = "haswell-rt5640", + .owner = THIS_MODULE, + .dai_link = card_dai_links, + .num_links = ARRAY_SIZE(card_dai_links), + .dapm_widgets = card_widgets, + .num_dapm_widgets = ARRAY_SIZE(card_widgets), + .dapm_routes = card_routes, + .num_dapm_routes = ARRAY_SIZE(card_routes), + .fully_routed = true, +}; + +static int hsw_rt5640_probe(struct platform_device *pdev) +{ + struct snd_soc_acpi_mach *mach; + struct device *dev = &pdev->dev; + int ret; + + hsw_rt5640_card.dev = dev; + mach = dev_get_platdata(dev); + + ret = snd_soc_fixup_dai_links_platform_name(&hsw_rt5640_card, mach->mach_params.platform); + if (ret) + return ret; + + return devm_snd_soc_register_card(dev, &hsw_rt5640_card); +} + +static struct platform_driver hsw_rt5640_driver = { + .probe = hsw_rt5640_probe, + .driver = { + .name = "hsw_rt5640", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(hsw_rt5640_driver) + +MODULE_AUTHOR("Liam Girdwood, Xingchao Wang"); +MODULE_DESCRIPTION("Sound card driver for Intel Haswell Lynx Point with Realtek 5640"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:hsw_rt5640"); diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c deleted file mode 100644 index dc3d897ad280..000000000000 --- a/sound/soc/intel/boards/kbl_da7219_max98357a.c +++ /dev/null @@ -1,619 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright(c) 2017-18 Intel Corporation. - -/* - * Intel Kabylake I2S Machine Driver with MAX98357A & DA7219 Codecs - * - * Modified from: - * Intel Kabylake I2S Machine driver supporting MAXIM98927 and - * RT5663 codecs - */ - -#include <linux/input.h> -#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> -#include "../../codecs/da7219.h" -#include "../../codecs/hdac_hdmi.h" -#include "../../codecs/da7219-aad.h" - -#define KBL_DIALOG_CODEC_DAI "da7219-hifi" -#define KBL_MAXIM_CODEC_DAI "HiFi" -#define MAXIM_DEV0_NAME "MX98357A:00" -#define DUAL_CHANNEL 2 -#define QUAD_CHANNEL 4 - -static struct snd_soc_card *kabylake_audio_card; -static struct snd_soc_jack skylake_hdmi[3]; - -struct kbl_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct kbl_codec_private { - struct snd_soc_jack kabylake_headset; - struct list_head hdmi_pcm_list; -}; - -enum { - KBL_DPCM_AUDIO_PB = 0, - KBL_DPCM_AUDIO_CP, - KBL_DPCM_AUDIO_DMIC_CP, - KBL_DPCM_AUDIO_HDMI1_PB, - KBL_DPCM_AUDIO_HDMI2_PB, - KBL_DPCM_AUDIO_HDMI3_PB, -}; - -static int platform_clock_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct snd_soc_dai *codec_dai; - int ret = 0; - - codec_dai = snd_soc_card_get_codec_dai(card, KBL_DIALOG_CODEC_DAI); - 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; -} - -static const struct snd_kcontrol_new kabylake_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Spk"), -}; - -static const struct snd_soc_dapm_widget kabylake_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Spk", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("DP", NULL), - SND_SOC_DAPM_SPK("HDMI", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD), -}; - -static const struct snd_soc_dapm_route kabylake_map[] = { - { "Headphone Jack", NULL, "HPL" }, - { "Headphone Jack", NULL, "HPR" }, - - /* speaker */ - { "Spk", NULL, "Speaker" }, - - /* other jacks */ - { "MIC", NULL, "Headset Mic" }, - { "DMic", NULL, "SoC DMIC" }, - - { "HDMI", NULL, "hif5 Output" }, - { "DP", NULL, "hif6 Output" }, - - /* CODEC BE connections */ - { "HiFi Playback", NULL, "ssp0 Tx" }, - { "ssp0 Tx", NULL, "codec0_out" }, - - { "Playback", NULL, "ssp1 Tx" }, - { "ssp1 Tx", NULL, "codec1_out" }, - - { "codec0_in", NULL, "ssp1 Rx" }, - { "ssp1 Rx", NULL, "Capture" }, - - /* DMIC */ - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "DMIC AIF" }, - - { "hifi1", NULL, "iDisp1 Tx" }, - { "iDisp1 Tx", NULL, "iDisp1_out" }, - { "hifi2", NULL, "iDisp2 Tx" }, - { "iDisp2 Tx", NULL, "iDisp2_out" }, - { "hifi3", NULL, "iDisp3 Tx"}, - { "iDisp3 Tx", NULL, "iDisp3_out"}, - - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headset Mic", NULL, "Platform Clock" }, -}; - -static int kabylake_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); - struct snd_interval *chan = hw_param_interval(params, - 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; - chan->min = chan->max = DUAL_CHANNEL; - - /* set SSP to 24 bit */ - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - - return 0; -} - -static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - struct snd_soc_jack *jack; - int ret; - - /* Configure sysclk for codec */ - ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 24576000, - SND_SOC_CLOCK_IN); - if (ret) { - dev_err(rtd->dev, "can't set codec sysclk configuration\n"); - return ret; - } - - /* - * Headset buttons map to the google Reference headset. - * These can be configured by userspace. - */ - ret = snd_soc_card_jack_new(kabylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, - &ctx->kabylake_headset, NULL, 0); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); - return ret; - } - - jack = &ctx->kabylake_headset; - - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); - da7219_aad_jack_det(component, &ctx->kabylake_headset); - - ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - if (ret) - dev_err(rtd->dev, "SoC DMIC - Ignore suspend failed %d\n", ret); - - return ret; -} - -static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); - struct kbl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = device; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB); -} - -static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB); -} - -static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB); -} - -static int kabylake_da7219_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = asoc_rtd_to_cpu(rtd, 0)->component; - - dapm = snd_soc_component_get_dapm(component); - snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - - return 0; -} - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static const unsigned int channels[] = { - DUAL_CHANNEL, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static unsigned int channels_quad[] = { - QUAD_CHANNEL, -}; - -static struct snd_pcm_hw_constraint_list constraints_channels_quad = { - .count = ARRAY_SIZE(channels_quad), - .list = channels_quad, - .mask = 0, -}; - -static int kbl_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * On this platform for PCM device we support, - * 48Khz - * 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 kabylake_da7219_fe_ops = { - .startup = kbl_fe_startup, -}; - -static int kabylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - - /* - * set BE channel constraint as user FE channels - */ - - if (params_channels(params) == 2) - chan->min = chan->max = 2; - else - chan->min = chan->max = 4; - - return 0; -} - -static int kabylake_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels_quad); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static struct snd_soc_ops kabylake_dmic_ops = { - .startup = kabylake_dmic_startup, -}; - -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(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"))); - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY(COMP_CODEC(MAXIM_DEV0_NAME, - KBL_MAXIM_CODEC_DAI))); - -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", - KBL_DIALOG_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(dmic_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); -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:1f.3"))); - -/* kabylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link kabylake_dais[] = { - /* Front End DAI links */ - [KBL_DPCM_AUDIO_PB] = { - .name = "Kbl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = kabylake_da7219_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &kabylake_da7219_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_CP] = { - .name = "Kbl 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 = &kabylake_da7219_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_DMIC_CP] = { - .name = "Kbl Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &kabylake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Kbl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Kbl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI3_PB] = { - .name = "Kbl HDMI Port3", - .stream_name = "Hdmi3", - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-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 = kabylake_ssp_fixup, - .dpcm_playback = 1, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - /* SSP1 - Codec */ - .name = "SSP1-Codec", - .id = 1, - .no_pcm = 1, - .init = kabylake_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 = kabylake_ssp_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - .name = "dmic01", - .id = 2, - .be_hw_params_fixup = kabylake_dmic_fixup, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .dpcm_playback = 1, - .init = kabylake_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = kabylake_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = kabylake_hdmi3_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -#define NAME_SIZE 32 -static int kabylake_card_late_probe(struct snd_soc_card *card) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card); - struct kbl_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - 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, &skylake_hdmi[i], - NULL, 0); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &skylake_hdmi[i]); - if (err < 0) - return err; - - i++; - - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* kabylake audio machine driver for SPT + DA7219 */ -static struct snd_soc_card kabylake_audio_card_da7219_m98357a = { - .name = "kblda7219max", - .owner = THIS_MODULE, - .dai_link = kabylake_dais, - .num_links = ARRAY_SIZE(kabylake_dais), - .controls = kabylake_controls, - .num_controls = ARRAY_SIZE(kabylake_controls), - .dapm_widgets = kabylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), - .dapm_routes = kabylake_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_map), - .fully_routed = true, - .late_probe = kabylake_card_late_probe, -}; - -static int kabylake_audio_probe(struct platform_device *pdev) -{ - struct kbl_codec_private *ctx; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - kabylake_audio_card = - (struct snd_soc_card *)pdev->id_entry->driver_data; - - kabylake_audio_card->dev = &pdev->dev; - snd_soc_card_set_drvdata(kabylake_audio_card, ctx); - return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card); -} - -static const struct platform_device_id kbl_board_ids[] = { - { - .name = "kbl_da7219_max98357a", - .driver_data = - (kernel_ulong_t)&kabylake_audio_card_da7219_m98357a, - }, - { } -}; - -static struct platform_driver kabylake_audio = { - .probe = kabylake_audio_probe, - .driver = { - .name = "kbl_da7219_max98357a", - .pm = &snd_soc_pm_ops, - }, - .id_table = kbl_board_ids, -}; - -module_platform_driver(kabylake_audio) - -/* Module information */ -MODULE_DESCRIPTION("Audio Machine driver-DA7219 & MAX98357A in I2S mode"); -MODULE_AUTHOR("Naveen Manohar <naveen.m@intel.com>"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:kbl_da7219_max98357a"); diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c deleted file mode 100644 index cc9a2509ace2..000000000000 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ /dev/null @@ -1,1173 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright(c) 2018 Intel Corporation. - -/* - * Intel Kabylake I2S Machine Driver with MAX98927, MAX98373 & DA7219 Codecs - * - * Modified from: - * Intel Kabylake I2S Machine driver supporting MAX98927 and - * RT5663 codecs - */ - -#include <linux/input.h> -#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> -#include "../../codecs/da7219.h" -#include "../../codecs/hdac_hdmi.h" -#include "../../codecs/da7219-aad.h" - -#define KBL_DIALOG_CODEC_DAI "da7219-hifi" -#define MAX98927_CODEC_DAI "max98927-aif1" -#define MAX98927_DEV0_NAME "i2c-MX98927:00" -#define MAX98927_DEV1_NAME "i2c-MX98927:01" - -#define MAX98373_CODEC_DAI "max98373-aif1" -#define MAX98373_DEV0_NAME "i2c-MX98373:00" -#define MAX98373_DEV1_NAME "i2c-MX98373:01" - - -#define DUAL_CHANNEL 2 -#define QUAD_CHANNEL 4 -#define NAME_SIZE 32 - -static struct snd_soc_card *kabylake_audio_card; -static struct snd_soc_jack kabylake_hdmi[3]; - -struct kbl_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct kbl_codec_private { - struct snd_soc_jack kabylake_headset; - struct list_head hdmi_pcm_list; -}; - -enum { - KBL_DPCM_AUDIO_PB = 0, - KBL_DPCM_AUDIO_ECHO_REF_CP, - KBL_DPCM_AUDIO_REF_CP, - KBL_DPCM_AUDIO_DMIC_CP, - KBL_DPCM_AUDIO_HDMI1_PB, - KBL_DPCM_AUDIO_HDMI2_PB, - KBL_DPCM_AUDIO_HDMI3_PB, - KBL_DPCM_AUDIO_HS_PB, - KBL_DPCM_AUDIO_CP, -}; - -static int platform_clock_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct snd_soc_dai *codec_dai; - int ret = 0; - - codec_dai = snd_soc_card_get_codec_dai(card, KBL_DIALOG_CODEC_DAI); - if (!codec_dai) { - dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n"); - return -EIO; - } - - /* Configure sysclk for codec */ - ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 24576000, - SND_SOC_CLOCK_IN); - if (ret) { - dev_err(card->dev, "can't set codec sysclk configuration\n"); - return ret; - } - - 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; -} - -static const struct snd_kcontrol_new kabylake_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), -}; - -static const struct snd_soc_dapm_widget kabylake_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("DP", NULL), - SND_SOC_DAPM_SPK("HDMI", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD), -}; - -static const struct snd_soc_dapm_route kabylake_map[] = { - /* speaker */ - { "Left Spk", NULL, "Left BE_OUT" }, - { "Right Spk", NULL, "Right BE_OUT" }, - - /* other jacks */ - { "DMic", NULL, "SoC DMIC" }, - - { "HDMI", NULL, "hif5 Output" }, - { "DP", NULL, "hif6 Output" }, - - /* CODEC BE connections */ - { "Left HiFi Playback", NULL, "ssp0 Tx" }, - { "Right HiFi Playback", NULL, "ssp0 Tx" }, - { "ssp0 Tx", NULL, "spk_out" }, - - /* IV feedback path */ - { "codec0_fb_in", NULL, "ssp0 Rx"}, - { "ssp0 Rx", NULL, "Left HiFi Capture" }, - { "ssp0 Rx", NULL, "Right HiFi Capture" }, - - /* AEC capture path */ - { "echo_ref_out", NULL, "ssp0 Rx" }, - - /* DMIC */ - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "DMIC AIF" }, - - { "hifi1", NULL, "iDisp1 Tx" }, - { "iDisp1 Tx", NULL, "iDisp1_out" }, - { "hifi2", NULL, "iDisp2 Tx" }, - { "iDisp2 Tx", NULL, "iDisp2_out" }, - { "hifi3", NULL, "iDisp3 Tx"}, - { "iDisp3 Tx", NULL, "iDisp3_out"}, -}; - -static const struct snd_soc_dapm_route kabylake_ssp1_map[] = { - { "Headphone Jack", NULL, "HPL" }, - { "Headphone Jack", NULL, "HPR" }, - - /* other jacks */ - { "MIC", NULL, "Headset Mic" }, - - /* CODEC BE connections */ - { "Playback", NULL, "ssp1 Tx" }, - { "ssp1 Tx", NULL, "codec1_out" }, - - { "hs_in", NULL, "ssp1 Rx" }, - { "ssp1 Rx", NULL, "Capture" }, - - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headset Mic", NULL, "Platform Clock" }, -}; - -static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai; - int ret, j; - - for_each_rtd_codec_dais(runtime, j, codec_dai) { - - if (!strcmp(codec_dai->component->name, MAX98927_DEV0_NAME)) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16); - if (ret < 0) { - dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret); - return ret; - } - } - if (!strcmp(codec_dai->component->name, MAX98927_DEV1_NAME)) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16); - if (ret < 0) { - dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret); - return ret; - } - } - if (!strcmp(codec_dai->component->name, MAX98373_DEV0_NAME)) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, - 0x03, 3, 8, 24); - if (ret < 0) { - dev_err(runtime->dev, - "DEV0 TDM slot err:%d\n", ret); - return ret; - } - } - if (!strcmp(codec_dai->component->name, MAX98373_DEV1_NAME)) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, - 0x0C, 3, 8, 24); - if (ret < 0) { - dev_err(runtime->dev, - "DEV0 TDM slot err:%d\n", ret); - return ret; - } - } - } - - return 0; -} - -static int kabylake_ssp0_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai; - int j, ret; - - for_each_rtd_codec_dais(rtd, j, codec_dai) { - const char *name = codec_dai->component->name; - struct snd_soc_component *component = codec_dai->component; - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - char pin_name[20]; - - if (strcmp(name, MAX98927_DEV0_NAME) && - strcmp(name, MAX98927_DEV1_NAME) && - strcmp(name, MAX98373_DEV0_NAME) && - strcmp(name, MAX98373_DEV1_NAME)) - continue; - - snprintf(pin_name, ARRAY_SIZE(pin_name), "%s Spk", - codec_dai->component->name_prefix); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ret = snd_soc_dapm_enable_pin(dapm, pin_name); - if (ret) { - dev_err(rtd->dev, "failed to enable %s: %d\n", - pin_name, ret); - return ret; - } - snd_soc_dapm_sync(dapm); - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ret = snd_soc_dapm_disable_pin(dapm, pin_name); - if (ret) { - dev_err(rtd->dev, "failed to disable %s: %d\n", - pin_name, ret); - return ret; - } - snd_soc_dapm_sync(dapm); - break; - } - } - - return 0; -} - -static struct snd_soc_ops kabylake_ssp0_ops = { - .hw_params = kabylake_ssp0_hw_params, - .trigger = kabylake_ssp0_trigger, -}; - -static int kabylake_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); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - struct snd_soc_dpcm *dpcm = container_of( - params, struct snd_soc_dpcm, hw_params); - struct snd_soc_dai_link *fe_dai_link = dpcm->fe->dai_link; - struct snd_soc_dai_link *be_dai_link = dpcm->be->dai_link; - - /* - * Topology for kblda7219m98373 & kblmax98373 supports only S24_LE, - * where as kblda7219m98927 & kblmax98927 supports S16_LE by default. - * Skipping the port wise FE and BE configuration for kblda7219m98373 & - * kblmax98373 as the topology (FE & BE) supports S24_LE only. - */ - - if (!strcmp(rtd->card->name, "kblda7219m98373") || - !strcmp(rtd->card->name, "kblmax98373")) { - /* The ADSP will convert the FE rate to 48k, stereo */ - rate->min = rate->max = 48000; - chan->min = chan->max = DUAL_CHANNEL; - - /* set SSP to 24 bit */ - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - return 0; - } - - /* - * The ADSP will convert the FE rate to 48k, stereo, 24 bit - */ - if (!strcmp(fe_dai_link->name, "Kbl Audio Port") || - !strcmp(fe_dai_link->name, "Kbl Audio Headset Playback") || - !strcmp(fe_dai_link->name, "Kbl Audio Capture Port")) { - rate->min = rate->max = 48000; - chan->min = chan->max = 2; - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - } - - /* - * The speaker on the SSP0 supports S16_LE and not S24_LE. - * thus changing the mask here - */ - if (!strcmp(be_dai_link->name, "SSP0-Codec")) - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); - - return 0; -} - -static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; - struct snd_soc_jack *jack; - struct snd_soc_card *card = rtd->card; - int ret; - - - ret = snd_soc_dapm_add_routes(&card->dapm, - kabylake_ssp1_map, - ARRAY_SIZE(kabylake_ssp1_map)); - - if (ret) - return ret; - - /* - * Headset buttons map to the google Reference headset. - * These can be configured by userspace. - */ - ret = snd_soc_card_jack_new(kabylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, - &ctx->kabylake_headset, NULL, 0); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); - return ret; - } - - jack = &ctx->kabylake_headset; - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); - - da7219_aad_jack_det(component, &ctx->kabylake_headset); - - return 0; -} - -static int kabylake_dmic_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - if (ret) - dev_err(rtd->dev, "SoC DMIC - Ignore suspend failed %d\n", ret); - - return ret; -} - -static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); - struct kbl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = device; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB); -} - -static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB); -} - -static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB); -} - -static int kabylake_da7219_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = asoc_rtd_to_cpu(rtd, 0)->component; - - dapm = snd_soc_component_get_dapm(component); - snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - - return 0; -} - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static const unsigned int channels[] = { - DUAL_CHANNEL, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static unsigned int channels_quad[] = { - QUAD_CHANNEL, -}; - -static struct snd_pcm_hw_constraint_list constraints_channels_quad = { - .count = ARRAY_SIZE(channels_quad), - .list = channels_quad, - .mask = 0, -}; - -static int kbl_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *soc_rt = asoc_substream_to_rtd(substream); - - /* - * On this platform for PCM device we support, - * 48Khz - * stereo - */ - - runtime->hw.channels_max = DUAL_CHANNEL; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); - /* - * Setup S24_LE (32 bit container and 24 bit valid data) for - * kblda7219m98373 & kblmax98373. For kblda7219m98927 & - * kblmax98927 keeping it as 16/16 due to topology FW dependency. - */ - if (!strcmp(soc_rt->card->name, "kblda7219m98373") || - !strcmp(soc_rt->card->name, "kblmax98373")) { - runtime->hw.formats = SNDRV_PCM_FMTBIT_S24_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); - - } else { - 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 kabylake_da7219_fe_ops = { - .startup = kbl_fe_startup, -}; - -static int kabylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - - /* - * set BE channel constraint as user FE channels - */ - - if (params_channels(params) == 2) - chan->min = chan->max = 2; - else - chan->min = chan->max = 4; - - return 0; -} - -static int kabylake_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *soc_rt = asoc_substream_to_rtd(substream); - - runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels_quad); - - /* - * Topology for kblda7219m98373 & kblmax98373 supports only S24_LE. - * The DMIC also configured for S24_LE. Forcing the DMIC format to - * S24_LE due to the topology FW dependency. - */ - if (!strcmp(soc_rt->card->name, "kblda7219m98373") || - !strcmp(soc_rt->card->name, "kblmax98373")) { - runtime->hw.formats = SNDRV_PCM_FMTBIT_S24_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); - } - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static struct snd_soc_ops kabylake_dmic_ops = { - .startup = kabylake_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, -}; - -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, -}; - -static int kabylake_refcap_startup(struct snd_pcm_substream *substream) -{ - substream->runtime->hw.channels_max = 1; - snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_refcap); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_16000); -} - - -static struct snd_soc_ops skylake_refcap_ops = { - .startup = kabylake_refcap_startup, -}; - -static struct snd_soc_codec_conf max98927_codec_conf[] = { - - { - .dlc = COMP_CODEC_CONF(MAX98927_DEV0_NAME), - .name_prefix = "Right", - }, - - { - .dlc = COMP_CODEC_CONF(MAX98927_DEV1_NAME), - .name_prefix = "Left", - }, -}; - -static struct snd_soc_codec_conf max98373_codec_conf[] = { - - { - .dlc = COMP_CODEC_CONF(MAX98373_DEV0_NAME), - .name_prefix = "Right", - }, - - { - .dlc = COMP_CODEC_CONF(MAX98373_DEV1_NAME), - .name_prefix = "Left", - }, -}; - -static struct snd_soc_dai_link_component max98373_ssp0_codec_components[] = { - { /* Left */ - .name = MAX98373_DEV0_NAME, - .dai_name = MAX98373_CODEC_DAI, - }, - - { /* For Right */ - .name = MAX98373_DEV1_NAME, - .dai_name = MAX98373_CODEC_DAI, - }, - -}; - -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(echoref, - DAILINK_COMP_ARRAY(COMP_CPU("Echoref Pin"))); - -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"))); - -SND_SOC_DAILINK_DEF(system2, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin2"))); - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY( - /* Left */ COMP_CODEC(MAX98927_DEV0_NAME, MAX98927_CODEC_DAI), - /* For Right */ COMP_CODEC(MAX98927_DEV1_NAME, MAX98927_CODEC_DAI))); - -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", - KBL_DIALOG_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(dmic_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); -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:1f.3"))); - -/* kabylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link kabylake_dais[] = { - /* Front End DAI links */ - [KBL_DPCM_AUDIO_PB] = { - .name = "Kbl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = kabylake_da7219_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &kabylake_da7219_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_ECHO_REF_CP] = { - .name = "Kbl Audio Echo Reference cap", - .stream_name = "Echoreference Capture", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - SND_SOC_DAILINK_REG(echoref, dummy, platform), - }, - [KBL_DPCM_AUDIO_REF_CP] = { - .name = "Kbl Audio Reference cap", - .stream_name = "Wake on Voice", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_refcap_ops, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [KBL_DPCM_AUDIO_DMIC_CP] = { - .name = "Kbl Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &kabylake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Kbl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Kbl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI3_PB] = { - .name = "Kbl HDMI Port3", - .stream_name = "Hdmi3", - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - [KBL_DPCM_AUDIO_HS_PB] = { - .name = "Kbl Audio Headset Playback", - .stream_name = "Headset Audio", - .dpcm_playback = 1, - .nonatomic = 1, - .dynamic = 1, - .init = kabylake_da7219_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .ops = &kabylake_da7219_fe_ops, - SND_SOC_DAILINK_REG(system2, dummy, platform), - }, - [KBL_DPCM_AUDIO_CP] = { - .name = "Kbl 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 = &kabylake_da7219_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_DSP_B | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, - .dpcm_playback = 1, - .dpcm_capture = 1, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp_fixup, - .ops = &kabylake_ssp0_ops, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - /* SSP1 - Codec */ - .name = "SSP1-Codec", - .id = 1, - .no_pcm = 1, - .init = kabylake_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 = kabylake_ssp_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - .name = "dmic01", - .id = 2, - .init = kabylake_dmic_init, - .be_hw_params_fixup = kabylake_dmic_fixup, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .dpcm_playback = 1, - .init = kabylake_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = kabylake_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = kabylake_hdmi3_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -/* kabylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link kabylake_max98_927_373_dais[] = { - /* Front End DAI links */ - [KBL_DPCM_AUDIO_PB] = { - .name = "Kbl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = kabylake_da7219_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &kabylake_da7219_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_ECHO_REF_CP] = { - .name = "Kbl Audio Echo Reference cap", - .stream_name = "Echoreference Capture", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - SND_SOC_DAILINK_REG(echoref, dummy, platform), - }, - [KBL_DPCM_AUDIO_REF_CP] = { - .name = "Kbl Audio Reference cap", - .stream_name = "Wake on Voice", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_refcap_ops, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [KBL_DPCM_AUDIO_DMIC_CP] = { - .name = "Kbl Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &kabylake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Kbl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Kbl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI3_PB] = { - .name = "Kbl HDMI Port3", - .stream_name = "Hdmi3", - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_DSP_B | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, - .dpcm_playback = 1, - .dpcm_capture = 1, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp_fixup, - .ops = &kabylake_ssp0_ops, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec), - }, - { - .name = "dmic01", - .id = 1, - .init = kabylake_dmic_init, - .be_hw_params_fixup = kabylake_dmic_fixup, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 2, - .dpcm_playback = 1, - .init = kabylake_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 3, - .init = kabylake_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 4, - .init = kabylake_hdmi3_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -static int kabylake_card_late_probe(struct snd_soc_card *card) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card); - struct kbl_hdmi_pcm *pcm; - struct snd_soc_dapm_context *dapm = &card->dapm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - 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, &kabylake_hdmi[i], - NULL, 0); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &kabylake_hdmi[i]); - if (err < 0) - return err; - - i++; - } - - if (!component) - return -EINVAL; - - - err = hdac_hdmi_jack_port_init(component, &card->dapm); - - if (err < 0) - return err; - - err = snd_soc_dapm_disable_pin(dapm, "Left Spk"); - if (err) { - dev_err(card->dev, "failed to disable Left Spk: %d\n", err); - return err; - } - - err = snd_soc_dapm_disable_pin(dapm, "Right Spk"); - if (err) { - dev_err(card->dev, "failed to disable Right Spk: %d\n", err); - return err; - } - - return snd_soc_dapm_sync(dapm); -} - -/* kabylake audio machine driver for SPT + DA7219 */ -static struct snd_soc_card kbl_audio_card_da7219_m98927 = { - .name = "kblda7219m98927", - .owner = THIS_MODULE, - .dai_link = kabylake_dais, - .num_links = ARRAY_SIZE(kabylake_dais), - .controls = kabylake_controls, - .num_controls = ARRAY_SIZE(kabylake_controls), - .dapm_widgets = kabylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), - .dapm_routes = kabylake_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_map), - .codec_conf = max98927_codec_conf, - .num_configs = ARRAY_SIZE(max98927_codec_conf), - .fully_routed = true, - .late_probe = kabylake_card_late_probe, -}; - -/* kabylake audio machine driver for Maxim98927 */ -static struct snd_soc_card kbl_audio_card_max98927 = { - .name = "kblmax98927", - .owner = THIS_MODULE, - .dai_link = kabylake_max98_927_373_dais, - .num_links = ARRAY_SIZE(kabylake_max98_927_373_dais), - .controls = kabylake_controls, - .num_controls = ARRAY_SIZE(kabylake_controls), - .dapm_widgets = kabylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), - .dapm_routes = kabylake_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_map), - .codec_conf = max98927_codec_conf, - .num_configs = ARRAY_SIZE(max98927_codec_conf), - .fully_routed = true, - .late_probe = kabylake_card_late_probe, -}; - -static struct snd_soc_card kbl_audio_card_da7219_m98373 = { - .name = "kblda7219m98373", - .owner = THIS_MODULE, - .dai_link = kabylake_dais, - .num_links = ARRAY_SIZE(kabylake_dais), - .controls = kabylake_controls, - .num_controls = ARRAY_SIZE(kabylake_controls), - .dapm_widgets = kabylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), - .dapm_routes = kabylake_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_map), - .codec_conf = max98373_codec_conf, - .num_configs = ARRAY_SIZE(max98373_codec_conf), - .fully_routed = true, - .late_probe = kabylake_card_late_probe, -}; - -static struct snd_soc_card kbl_audio_card_max98373 = { - .name = "kblmax98373", - .owner = THIS_MODULE, - .dai_link = kabylake_max98_927_373_dais, - .num_links = ARRAY_SIZE(kabylake_max98_927_373_dais), - .controls = kabylake_controls, - .num_controls = ARRAY_SIZE(kabylake_controls), - .dapm_widgets = kabylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), - .dapm_routes = kabylake_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_map), - .codec_conf = max98373_codec_conf, - .num_configs = ARRAY_SIZE(max98373_codec_conf), - .fully_routed = true, - .late_probe = kabylake_card_late_probe, -}; - -static int kabylake_audio_probe(struct platform_device *pdev) -{ - struct kbl_codec_private *ctx; - struct snd_soc_dai_link *kbl_dai_link; - struct snd_soc_dai_link_component **codecs; - int i; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - kabylake_audio_card = - (struct snd_soc_card *)pdev->id_entry->driver_data; - - kbl_dai_link = kabylake_audio_card->dai_link; - - /* Update codecs for SSP0 with max98373 codec info */ - if (!strcmp(pdev->name, "kbl_da7219_max98373") || - (!strcmp(pdev->name, "kbl_max98373"))) { - for (i = 0; i < kabylake_audio_card->num_links; ++i) { - if (strcmp(kbl_dai_link[i].name, "SSP0-Codec")) - continue; - - codecs = &(kbl_dai_link[i].codecs); - *codecs = max98373_ssp0_codec_components; - kbl_dai_link[i].num_codecs = - ARRAY_SIZE(max98373_ssp0_codec_components); - break; - } - } - kabylake_audio_card->dev = &pdev->dev; - snd_soc_card_set_drvdata(kabylake_audio_card, ctx); - - return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card); -} - -static const struct platform_device_id kbl_board_ids[] = { - { - .name = "kbl_da7219_max98927", - .driver_data = - (kernel_ulong_t)&kbl_audio_card_da7219_m98927, - }, - { - .name = "kbl_max98927", - .driver_data = - (kernel_ulong_t)&kbl_audio_card_max98927, - }, - { - .name = "kbl_da7219_max98373", - .driver_data = - (kernel_ulong_t)&kbl_audio_card_da7219_m98373, - }, - { - .name = "kbl_max98373", - .driver_data = - (kernel_ulong_t)&kbl_audio_card_max98373, - }, - { } -}; - -static struct platform_driver kabylake_audio = { - .probe = kabylake_audio_probe, - .driver = { - .name = "kbl_da7219_max98_927_373", - .pm = &snd_soc_pm_ops, - }, - .id_table = kbl_board_ids, -}; - -module_platform_driver(kabylake_audio) - -/* Module information */ -MODULE_DESCRIPTION("Audio KabyLake Machine driver for MAX98927/MAX98373 & DA7219"); -MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:kbl_da7219_max98927"); -MODULE_ALIAS("platform:kbl_max98927"); -MODULE_ALIAS("platform:kbl_da7219_max98373"); -MODULE_ALIAS("platform:kbl_max98373"); diff --git a/sound/soc/intel/boards/kbl_rt5660.c b/sound/soc/intel/boards/kbl_rt5660.c deleted file mode 100644 index 3a9f91b58e11..000000000000 --- a/sound/soc/intel/boards/kbl_rt5660.c +++ /dev/null @@ -1,567 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright(c) 2018-19 Canonical Corporation. - -/* - * Intel Kabylake I2S Machine Driver with RT5660 Codec - * - * Modified from: - * Intel Kabylake I2S Machine driver supporting MAXIM98357a and - * DA7219 codecs - * Also referred to: - * Intel Broadwell I2S Machine driver supporting RT5677 codec - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/gpio/consumer.h> -#include <linux/acpi.h> -#include <sound/core.h> -#include <sound/jack.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> - -#include "../../codecs/hdac_hdmi.h" -#include "../../codecs/rt5660.h" - -#define KBL_RT5660_CODEC_DAI "rt5660-aif1" -#define DUAL_CHANNEL 2 - -static struct snd_soc_card *kabylake_audio_card; -static struct snd_soc_jack skylake_hdmi[3]; -static struct snd_soc_jack lineout_jack; -static struct snd_soc_jack mic_jack; - -struct kbl_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct kbl_codec_private { - struct gpio_desc *gpio_lo_mute; - struct list_head hdmi_pcm_list; -}; - -enum { - KBL_DPCM_AUDIO_PB = 0, - KBL_DPCM_AUDIO_CP, - KBL_DPCM_AUDIO_HDMI1_PB, - KBL_DPCM_AUDIO_HDMI2_PB, - KBL_DPCM_AUDIO_HDMI3_PB, -}; - -#define GPIO_LINEOUT_MUTE_INDEX 0 -#define GPIO_LINEOUT_DET_INDEX 3 -#define GPIO_LINEIN_DET_INDEX 4 - -static const struct acpi_gpio_params lineout_mute_gpio = { GPIO_LINEOUT_MUTE_INDEX, 0, true }; -static const struct acpi_gpio_params lineout_det_gpio = { GPIO_LINEOUT_DET_INDEX, 0, false }; -static const struct acpi_gpio_params mic_det_gpio = { GPIO_LINEIN_DET_INDEX, 0, false }; - - -static const struct acpi_gpio_mapping acpi_rt5660_gpios[] = { - { "lineout-mute-gpios", &lineout_mute_gpio, 1 }, - { "lineout-det-gpios", &lineout_det_gpio, 1 }, - { "mic-det-gpios", &mic_det_gpio, 1 }, - { NULL }, -}; - -static struct snd_soc_jack_pin lineout_jack_pin = { - .pin = "Line Out", - .mask = SND_JACK_LINEOUT, -}; - -static struct snd_soc_jack_pin mic_jack_pin = { - .pin = "Line In", - .mask = SND_JACK_MICROPHONE, -}; - -static struct snd_soc_jack_gpio lineout_jack_gpio = { - .name = "lineout-det", - .report = SND_JACK_LINEOUT, - .debounce_time = 200, -}; - -static struct snd_soc_jack_gpio mic_jack_gpio = { - .name = "mic-det", - .report = SND_JACK_MICROPHONE, - .debounce_time = 200, -}; - -static int kabylake_5660_event_lineout(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct kbl_codec_private *priv = snd_soc_card_get_drvdata(dapm->card); - - gpiod_set_value_cansleep(priv->gpio_lo_mute, - !(SND_SOC_DAPM_EVENT_ON(event))); - - return 0; -} - -static const struct snd_kcontrol_new kabylake_rt5660_controls[] = { - SOC_DAPM_PIN_SWITCH("Line In"), - SOC_DAPM_PIN_SWITCH("Line Out"), -}; - -static const struct snd_soc_dapm_widget kabylake_rt5660_widgets[] = { - SND_SOC_DAPM_MIC("Line In", NULL), - SND_SOC_DAPM_LINE("Line Out", kabylake_5660_event_lineout), -}; - -static const struct snd_soc_dapm_route kabylake_rt5660_map[] = { - /* other jacks */ - {"IN1P", NULL, "Line In"}, - {"IN2P", NULL, "Line In"}, - {"Line Out", NULL, "LOUTR"}, - {"Line Out", NULL, "LOUTL"}, - - /* CODEC BE connections */ - { "AIF1 Playback", NULL, "ssp0 Tx"}, - { "ssp0 Tx", NULL, "codec0_out"}, - - { "codec0_in", NULL, "ssp0 Rx" }, - { "ssp0 Rx", NULL, "AIF1 Capture" }, - - { "hifi1", NULL, "iDisp1 Tx"}, - { "iDisp1 Tx", NULL, "iDisp1_out"}, - { "hifi2", NULL, "iDisp2 Tx"}, - { "iDisp2 Tx", NULL, "iDisp2_out"}, - { "hifi3", NULL, "iDisp3 Tx"}, - { "iDisp3 Tx", NULL, "iDisp3_out"}, -}; - -static int kabylake_ssp0_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); - struct snd_interval *chan = hw_param_interval(params, - 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; - chan->min = chan->max = DUAL_CHANNEL; - - /* set SSP0 to 24 bit */ - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - - return 0; -} - -static int kabylake_rt5660_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; - struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); - - ret = devm_acpi_dev_add_driver_gpios(component->dev, acpi_rt5660_gpios); - if (ret) - dev_warn(component->dev, "Failed to add driver gpios\n"); - - /* Request rt5660 GPIO for lineout mute control, return if fails */ - ctx->gpio_lo_mute = gpiod_get(component->dev, "lineout-mute", - GPIOD_OUT_HIGH); - if (IS_ERR(ctx->gpio_lo_mute)) { - dev_err(component->dev, "Can't find GPIO_MUTE# gpio\n"); - return PTR_ERR(ctx->gpio_lo_mute); - } - - /* Create and initialize headphone jack, this jack is not mandatory, don't return if fails */ - ret = snd_soc_card_jack_new(rtd->card, "Lineout Jack", - SND_JACK_LINEOUT, &lineout_jack, - &lineout_jack_pin, 1); - if (ret) - dev_warn(component->dev, "Can't create Lineout jack\n"); - else { - lineout_jack_gpio.gpiod_dev = component->dev; - ret = snd_soc_jack_add_gpios(&lineout_jack, 1, - &lineout_jack_gpio); - if (ret) - dev_warn(component->dev, "Can't add Lineout jack gpio\n"); - } - - /* Create and initialize mic jack, this jack is not mandatory, don't return if fails */ - ret = snd_soc_card_jack_new(rtd->card, "Mic Jack", - SND_JACK_MICROPHONE, &mic_jack, - &mic_jack_pin, 1); - if (ret) - dev_warn(component->dev, "Can't create mic jack\n"); - else { - mic_jack_gpio.gpiod_dev = component->dev; - ret = snd_soc_jack_add_gpios(&mic_jack, 1, &mic_jack_gpio); - if (ret) - dev_warn(component->dev, "Can't add mic jack gpio\n"); - } - - /* Here we enable some dapms in advance to reduce the pop noise for recording via line-in */ - snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); - snd_soc_dapm_force_enable_pin(dapm, "BST1"); - snd_soc_dapm_force_enable_pin(dapm, "BST2"); - - return 0; -} - -static void kabylake_rt5660_codec_exit(struct snd_soc_pcm_runtime *rtd) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - - /* - * The .exit() can be reached without going through the .init() - * so explicitly test if the gpiod is valid - */ - if (!IS_ERR_OR_NULL(ctx->gpio_lo_mute)) - gpiod_put(ctx->gpio_lo_mute); -} - -static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); - struct kbl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = device; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB); -} - -static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB); -} - -static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB); -} - -static int kabylake_rt5660_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - int ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, - RT5660_SCLK_S_PLL1, params_rate(params) * 512, - SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); - return ret; - } - - ret = snd_soc_dai_set_pll(codec_dai, 0, - RT5660_PLL1_S_BCLK, - params_rate(params) * 50, - params_rate(params) * 512); - if (ret < 0) - dev_err(codec_dai->dev, "can't set codec pll: %d\n", ret); - - return ret; -} - -static struct snd_soc_ops kabylake_rt5660_ops = { - .hw_params = kabylake_rt5660_hw_params, -}; - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static const unsigned int channels[] = { - DUAL_CHANNEL, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static int kbl_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * On this platform for PCM device we support, - * 48Khz - * 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 kabylake_rt5660_fe_ops = { - .startup = kbl_fe_startup, -}; - -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(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"))); - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC3277:00", KBL_RT5660_CODEC_DAI))); - -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:1f.3"))); - -/* kabylake digital audio interface glue - connects rt5660 codec <--> CPU */ -static struct snd_soc_dai_link kabylake_rt5660_dais[] = { - /* Front End DAI links */ - [KBL_DPCM_AUDIO_PB] = { - .name = "Kbl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &kabylake_rt5660_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_CP] = { - .name = "Kbl 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 = &kabylake_rt5660_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Kbl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Kbl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI3_PB] = { - .name = "Kbl HDMI Port3", - .stream_name = "Hdmi3", - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .init = kabylake_rt5660_codec_init, - .exit = kabylake_rt5660_codec_exit, - .dai_fmt = SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp0_fixup, - .ops = &kabylake_rt5660_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - .name = "iDisp1", - .id = 1, - .dpcm_playback = 1, - .init = kabylake_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 2, - .init = kabylake_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 3, - .init = kabylake_hdmi3_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - - -#define NAME_SIZE 32 -static int kabylake_card_late_probe(struct snd_soc_card *card) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card); - struct kbl_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - 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, &skylake_hdmi[i], - NULL, 0); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &skylake_hdmi[i]); - if (err < 0) - return err; - - i++; - - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* kabylake audio machine driver for rt5660 */ -static struct snd_soc_card kabylake_audio_card_rt5660 = { - .name = "kblrt5660", - .owner = THIS_MODULE, - .dai_link = kabylake_rt5660_dais, - .num_links = ARRAY_SIZE(kabylake_rt5660_dais), - .controls = kabylake_rt5660_controls, - .num_controls = ARRAY_SIZE(kabylake_rt5660_controls), - .dapm_widgets = kabylake_rt5660_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_rt5660_widgets), - .dapm_routes = kabylake_rt5660_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_rt5660_map), - .fully_routed = true, - .late_probe = kabylake_card_late_probe, -}; - -static int kabylake_audio_probe(struct platform_device *pdev) -{ - struct kbl_codec_private *ctx; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - kabylake_audio_card = - (struct snd_soc_card *)pdev->id_entry->driver_data; - - kabylake_audio_card->dev = &pdev->dev; - snd_soc_card_set_drvdata(kabylake_audio_card, ctx); - return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card); -} - -static const struct platform_device_id kbl_board_ids[] = { - { - .name = "kbl_rt5660", - .driver_data = - (kernel_ulong_t)&kabylake_audio_card_rt5660, - }, - { } -}; - -static struct platform_driver kabylake_audio = { - .probe = kabylake_audio_probe, - .driver = { - .name = "kbl_rt5660", - .pm = &snd_soc_pm_ops, - }, - .id_table = kbl_board_ids, -}; - -module_platform_driver(kabylake_audio) - -/* Module information */ -MODULE_DESCRIPTION("Audio Machine driver-RT5660 in I2S mode"); -MODULE_AUTHOR("Hui Wang <hui.wang@canonical.com>"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:kbl_rt5660"); diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c deleted file mode 100644 index 3ea4602dfb3e..000000000000 --- a/sound/soc/intel/boards/kbl_rt5663_max98927.c +++ /dev/null @@ -1,1031 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Kabylake I2S Machine Driver with MAXIM98927 - * and RT5663 Codecs - * - * Copyright (C) 2017, Intel Corporation. All rights reserved. - * - * Modified from: - * Intel Skylake I2S Machine driver - */ - -#include <linux/input.h> -#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> -#include <sound/soc-acpi.h> -#include "../../codecs/rt5663.h" -#include "../../codecs/hdac_hdmi.h" -#include <linux/clk.h> -#include <linux/clk-provider.h> -#include <linux/clkdev.h> - -#define KBL_REALTEK_CODEC_DAI "rt5663-aif" -#define KBL_MAXIM_CODEC_DAI "max98927-aif1" -#define DMIC_CH(p) p->list[p->count-1] -#define MAXIM_DEV0_NAME "i2c-MX98927:00" -#define MAXIM_DEV1_NAME "i2c-MX98927:01" - -static struct snd_soc_card *kabylake_audio_card; -static const struct snd_pcm_hw_constraint_list *dmic_constraints; -static struct snd_soc_jack skylake_hdmi[3]; - -struct kbl_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct kbl_rt5663_private { - struct snd_soc_jack kabylake_headset; - struct list_head hdmi_pcm_list; - struct clk *mclk; - struct clk *sclk; -}; - -enum { - KBL_DPCM_AUDIO_PB = 0, - KBL_DPCM_AUDIO_CP, - KBL_DPCM_AUDIO_HS_PB, - KBL_DPCM_AUDIO_ECHO_REF_CP, - KBL_DPCM_AUDIO_REF_CP, - KBL_DPCM_AUDIO_DMIC_CP, - KBL_DPCM_AUDIO_HDMI1_PB, - KBL_DPCM_AUDIO_HDMI2_PB, - KBL_DPCM_AUDIO_HDMI3_PB, -}; - -static const struct snd_kcontrol_new kabylake_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), -}; - -static int platform_clock_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct kbl_rt5663_private *priv = snd_soc_card_get_drvdata(card); - int ret = 0; - - /* - * MCLK/SCLK need to be ON early for a successful synchronization of - * codec internal clock. And the clocks are turned off during - * POST_PMD after the stream is stopped. - */ - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - /* Enable MCLK */ - ret = clk_set_rate(priv->mclk, 24000000); - if (ret < 0) { - dev_err(card->dev, "Can't set rate for mclk, err: %d\n", - ret); - return ret; - } - - ret = clk_prepare_enable(priv->mclk); - if (ret < 0) { - dev_err(card->dev, "Can't enable mclk, err: %d\n", ret); - return ret; - } - - /* Enable SCLK */ - ret = clk_set_rate(priv->sclk, 3072000); - if (ret < 0) { - dev_err(card->dev, "Can't set rate for sclk, err: %d\n", - ret); - clk_disable_unprepare(priv->mclk); - return ret; - } - - ret = clk_prepare_enable(priv->sclk); - if (ret < 0) { - dev_err(card->dev, "Can't enable sclk, err: %d\n", ret); - clk_disable_unprepare(priv->mclk); - } - break; - case SND_SOC_DAPM_POST_PMD: - clk_disable_unprepare(priv->mclk); - clk_disable_unprepare(priv->sclk); - break; - default: - return 0; - } - - return 0; -} - -static const struct snd_soc_dapm_widget kabylake_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", 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), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD), -}; - -static const struct snd_soc_dapm_route kabylake_map[] = { - /* HP jack connectors - unknown if we have jack detection */ - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headphone Jack", NULL, "HPOL" }, - { "Headphone Jack", NULL, "HPOR" }, - - /* speaker */ - { "Left Spk", NULL, "Left BE_OUT" }, - { "Right Spk", NULL, "Right BE_OUT" }, - - /* other jacks */ - { "Headset Mic", NULL, "Platform Clock" }, - { "IN1P", NULL, "Headset Mic" }, - { "IN1N", NULL, "Headset Mic" }, - { "DMic", NULL, "SoC DMIC" }, - - /* CODEC BE connections */ - { "Left HiFi Playback", NULL, "ssp0 Tx" }, - { "Right HiFi Playback", NULL, "ssp0 Tx" }, - { "ssp0 Tx", NULL, "spk_out" }, - - { "AIF Playback", NULL, "ssp1 Tx" }, - { "ssp1 Tx", NULL, "codec1_out" }, - - { "hs_in", NULL, "ssp1 Rx" }, - { "ssp1 Rx", NULL, "AIF Capture" }, - - /* IV feedback path */ - { "codec0_fb_in", NULL, "ssp0 Rx"}, - { "ssp0 Rx", NULL, "Left HiFi Capture" }, - { "ssp0 Rx", NULL, "Right HiFi Capture" }, - - /* DMIC */ - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "DMIC AIF" }, - - { "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"}, -}; - -enum { - KBL_DPCM_AUDIO_5663_PB = 0, - KBL_DPCM_AUDIO_5663_CP, - KBL_DPCM_AUDIO_5663_HDMI1_PB, - KBL_DPCM_AUDIO_5663_HDMI2_PB, -}; - -static const struct snd_kcontrol_new kabylake_5663_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), -}; - -static const struct snd_soc_dapm_widget kabylake_5663_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("DP", NULL), - SND_SOC_DAPM_SPK("HDMI", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD), -}; - -static const struct snd_soc_dapm_route kabylake_5663_map[] = { - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headphone Jack", NULL, "HPOL" }, - { "Headphone Jack", NULL, "HPOR" }, - - /* other jacks */ - { "Headset Mic", NULL, "Platform Clock" }, - { "IN1P", NULL, "Headset Mic" }, - { "IN1N", NULL, "Headset Mic" }, - - { "HDMI", NULL, "hif5 Output" }, - { "DP", NULL, "hif6 Output" }, - - /* CODEC BE connections */ - { "AIF Playback", NULL, "ssp1 Tx" }, - { "ssp1 Tx", NULL, "codec1_out" }, - - { "codec0_in", NULL, "ssp1 Rx" }, - { "ssp1 Rx", NULL, "AIF Capture" }, - - { "hifi2", NULL, "iDisp2 Tx"}, - { "iDisp2 Tx", NULL, "iDisp2_out"}, - { "hifi1", NULL, "iDisp1 Tx"}, - { "iDisp1 Tx", NULL, "iDisp1_out"}, -}; - -static struct snd_soc_codec_conf max98927_codec_conf[] = { - { - .dlc = COMP_CODEC_CONF(MAXIM_DEV0_NAME), - .name_prefix = "Right", - }, - { - .dlc = COMP_CODEC_CONF(MAXIM_DEV1_NAME), - .name_prefix = "Left", - }, -}; - -static int kabylake_rt5663_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = asoc_rtd_to_cpu(rtd, 0)->component; - - dapm = snd_soc_component_get_dapm(component); - ret = snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - if (ret) { - dev_err(rtd->dev, "Ref Cap ignore suspend failed %d\n", ret); - return ret; - } - - return ret; -} - -static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; - struct snd_soc_jack *jack; - - /* - * Headset buttons map to the google Reference headset. - * These can be configured by userspace. - */ - ret = snd_soc_card_jack_new(kabylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, &ctx->kabylake_headset, - NULL, 0); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); - return ret; - } - - jack = &ctx->kabylake_headset; - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - - snd_soc_component_set_jack(component, &ctx->kabylake_headset, NULL); - - return ret; -} - -static int kabylake_rt5663_max98927_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - - ret = kabylake_rt5663_codec_init(rtd); - if (ret) - return ret; - - ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - if (ret) { - dev_err(rtd->dev, "SoC DMIC ignore suspend failed %d\n", ret); - return ret; - } - - return ret; -} - -static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device) -{ - struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); - struct kbl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = device; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB); -} - -static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB); -} - -static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB); -} - -static int kabylake_5663_hdmi1_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_5663_HDMI1_PB); -} - -static int kabylake_5663_hdmi2_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_5663_HDMI2_PB); -} - -static unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static unsigned int channels[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static int kbl_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * On this platform for PCM device we support, - * 48Khz - * stereo - * 16 bit audio - */ - - runtime->hw.channels_max = 2; - 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 kabylake_rt5663_fe_ops = { - .startup = kbl_fe_startup, -}; - -static int kabylake_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); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - struct snd_soc_dpcm *dpcm = container_of( - params, struct snd_soc_dpcm, hw_params); - struct snd_soc_dai_link *fe_dai_link = dpcm->fe->dai_link; - struct snd_soc_dai_link *be_dai_link = dpcm->be->dai_link; - - /* - * The ADSP will convert the FE rate to 48k, stereo, 24 bit - */ - if (!strcmp(fe_dai_link->name, "Kbl Audio Port") || - !strcmp(fe_dai_link->name, "Kbl Audio Headset Playback") || - !strcmp(fe_dai_link->name, "Kbl Audio Capture Port")) { - rate->min = rate->max = 48000; - chan->min = chan->max = 2; - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - } - /* - * The speaker on the SSP0 supports S16_LE and not S24_LE. - * thus changing the mask here - */ - if (!strcmp(be_dai_link->name, "SSP0-Codec")) - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); - - return 0; -} - -static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - int ret; - - /* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */ - rt5663_sel_asrc_clk_src(codec_dai->component, - RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER, - RT5663_CLK_SEL_I2S1_ASRC); - - ret = snd_soc_dai_set_sysclk(codec_dai, - RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN); - if (ret < 0) - dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); - - return ret; -} - -static struct snd_soc_ops kabylake_rt5663_ops = { - .hw_params = kabylake_rt5663_hw_params, -}; - -static int kabylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - - if (params_channels(params) == 2 || DMIC_CH(dmic_constraints) == 2) - chan->min = chan->max = 2; - else - chan->min = chan->max = 4; - - return 0; -} - -static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai; - int ret = 0, j; - - for_each_rtd_codec_dais(rtd, j, codec_dai) { - if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) { - /* - * Use channel 4 and 5 for the first amp - */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16); - if (ret < 0) { - dev_err(rtd->dev, "set TDM slot err:%d\n", ret); - return ret; - } - } - if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) { - /* - * Use channel 6 and 7 for the second amp - */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16); - if (ret < 0) { - dev_err(rtd->dev, "set TDM slot err:%d\n", ret); - return ret; - } - } - } - return ret; -} - -static struct snd_soc_ops kabylake_ssp0_ops = { - .hw_params = kabylake_ssp0_hw_params, -}; - -static unsigned int channels_dmic[] = { - 2, 4, -}; - -static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { - .count = ARRAY_SIZE(channels_dmic), - .list = channels_dmic, - .mask = 0, -}; - -static const unsigned int dmic_2ch[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = { - .count = ARRAY_SIZE(dmic_2ch), - .list = dmic_2ch, - .mask = 0, -}; - -static int kabylake_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_max = DMIC_CH(dmic_constraints); - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - dmic_constraints); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static struct snd_soc_ops kabylake_dmic_ops = { - .startup = kabylake_dmic_startup, -}; - -static unsigned int rates_16000[] = { - 16000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_16000 = { - .count = ARRAY_SIZE(rates_16000), - .list = rates_16000, -}; - -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, -}; - -static int kabylake_refcap_startup(struct snd_pcm_substream *substream) -{ - substream->runtime->hw.channels_max = 1; - snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_refcap); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_16000); -} - -static struct snd_soc_ops skylake_refcap_ops = { - .startup = kabylake_refcap_startup, -}; - -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(echoref, - DAILINK_COMP_ARRAY(COMP_CPU("Echoref Pin"))); - -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"))); - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY( - /* Left */ COMP_CODEC(MAXIM_DEV0_NAME, KBL_MAXIM_CODEC_DAI), - /* Right */ COMP_CODEC(MAXIM_DEV1_NAME, KBL_MAXIM_CODEC_DAI))); - -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-10EC5663:00", - KBL_REALTEK_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(dmic01_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); -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:1f.3"))); - -/* kabylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link kabylake_dais[] = { - /* Front End DAI links */ - [KBL_DPCM_AUDIO_PB] = { - .name = "Kbl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = kabylake_rt5663_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &kabylake_rt5663_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_CP] = { - .name = "Kbl 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 = &kabylake_rt5663_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_HS_PB] = { - .name = "Kbl Audio Headset Playback", - .stream_name = "Headset Audio", - .dpcm_playback = 1, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(system2, dummy, platform), - }, - [KBL_DPCM_AUDIO_ECHO_REF_CP] = { - .name = "Kbl Audio Echo Reference cap", - .stream_name = "Echoreference Capture", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - SND_SOC_DAILINK_REG(echoref, dummy, platform), - }, - [KBL_DPCM_AUDIO_REF_CP] = { - .name = "Kbl Audio Reference cap", - .stream_name = "Wake on Voice", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_refcap_ops, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [KBL_DPCM_AUDIO_DMIC_CP] = { - .name = "Kbl Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &kabylake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Kbl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Kbl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI3_PB] = { - .name = "Kbl HDMI Port3", - .stream_name = "Hdmi3", - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_DSP_B | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp_fixup, - .dpcm_playback = 1, - .ops = &kabylake_ssp0_ops, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - /* SSP1 - Codec */ - .name = "SSP1-Codec", - .id = 1, - .no_pcm = 1, - .init = kabylake_rt5663_max98927_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 = kabylake_ssp_fixup, - .ops = &kabylake_rt5663_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - .name = "dmic01", - .id = 2, - .be_hw_params_fixup = kabylake_dmic_fixup, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic01_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .dpcm_playback = 1, - .init = kabylake_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = kabylake_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = kabylake_hdmi3_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -static struct snd_soc_dai_link kabylake_5663_dais[] = { - /* Front End DAI links */ - [KBL_DPCM_AUDIO_5663_PB] = { - .name = "Kbl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &kabylake_rt5663_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_5663_CP] = { - .name = "Kbl 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 = &kabylake_rt5663_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_5663_HDMI1_PB] = { - .name = "Kbl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [KBL_DPCM_AUDIO_5663_HDMI2_PB] = { - .name = "Kbl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP1 - Codec */ - .name = "SSP1-Codec", - .id = 0, - .no_pcm = 1, - .init = kabylake_rt5663_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 = kabylake_ssp_fixup, - .ops = &kabylake_rt5663_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - .name = "iDisp1", - .id = 1, - .dpcm_playback = 1, - .init = kabylake_5663_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 2, - .init = kabylake_5663_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, -}; - -#define NAME_SIZE 32 -static int kabylake_card_late_probe(struct snd_soc_card *card) -{ - struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(card); - struct kbl_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - 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, &skylake_hdmi[i], - NULL, 0); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &skylake_hdmi[i]); - if (err < 0) - return err; - - i++; - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* kabylake audio machine driver for SPT + RT5663 */ -static struct snd_soc_card kabylake_audio_card_rt5663_m98927 = { - .name = "kblrt5663max", - .owner = THIS_MODULE, - .dai_link = kabylake_dais, - .num_links = ARRAY_SIZE(kabylake_dais), - .controls = kabylake_controls, - .num_controls = ARRAY_SIZE(kabylake_controls), - .dapm_widgets = kabylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), - .dapm_routes = kabylake_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_map), - .codec_conf = max98927_codec_conf, - .num_configs = ARRAY_SIZE(max98927_codec_conf), - .fully_routed = true, - .late_probe = kabylake_card_late_probe, -}; - -/* kabylake audio machine driver for RT5663 */ -static struct snd_soc_card kabylake_audio_card_rt5663 = { - .name = "kblrt5663", - .owner = THIS_MODULE, - .dai_link = kabylake_5663_dais, - .num_links = ARRAY_SIZE(kabylake_5663_dais), - .controls = kabylake_5663_controls, - .num_controls = ARRAY_SIZE(kabylake_5663_controls), - .dapm_widgets = kabylake_5663_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_5663_widgets), - .dapm_routes = kabylake_5663_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_5663_map), - .fully_routed = true, - .late_probe = kabylake_card_late_probe, -}; - -static int kabylake_audio_probe(struct platform_device *pdev) -{ - struct kbl_rt5663_private *ctx; - struct snd_soc_acpi_mach *mach; - int ret; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - kabylake_audio_card = - (struct snd_soc_card *)pdev->id_entry->driver_data; - - kabylake_audio_card->dev = &pdev->dev; - snd_soc_card_set_drvdata(kabylake_audio_card, ctx); - - mach = pdev->dev.platform_data; - if (mach) - dmic_constraints = mach->mach_params.dmic_num == 2 ? - &constraints_dmic_2ch : &constraints_dmic_channels; - - ctx->mclk = devm_clk_get(&pdev->dev, "ssp1_mclk"); - if (IS_ERR(ctx->mclk)) { - ret = PTR_ERR(ctx->mclk); - if (ret == -ENOENT) { - dev_info(&pdev->dev, - "Failed to get ssp1_sclk, defer probe\n"); - return -EPROBE_DEFER; - } - - dev_err(&pdev->dev, "Failed to get ssp1_mclk with err:%d\n", - ret); - return ret; - } - - ctx->sclk = devm_clk_get(&pdev->dev, "ssp1_sclk"); - if (IS_ERR(ctx->sclk)) { - ret = PTR_ERR(ctx->sclk); - if (ret == -ENOENT) { - dev_info(&pdev->dev, - "Failed to get ssp1_sclk, defer probe\n"); - return -EPROBE_DEFER; - } - - dev_err(&pdev->dev, "Failed to get ssp1_sclk with err:%d\n", - ret); - return ret; - } - - return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card); -} - -static const struct platform_device_id kbl_board_ids[] = { - { - .name = "kbl_rt5663", - .driver_data = (kernel_ulong_t)&kabylake_audio_card_rt5663, - }, - { - .name = "kbl_rt5663_m98927", - .driver_data = - (kernel_ulong_t)&kabylake_audio_card_rt5663_m98927, - }, - { } -}; - -static struct platform_driver kabylake_audio = { - .probe = kabylake_audio_probe, - .driver = { - .name = "kbl_rt5663_m98927", - .pm = &snd_soc_pm_ops, - }, - .id_table = kbl_board_ids, -}; - -module_platform_driver(kabylake_audio) - -/* Module information */ -MODULE_DESCRIPTION("Audio Machine driver-RT5663 & MAX98927 in I2S mode"); -MODULE_AUTHOR("Naveen M <naveen.m@intel.com>"); -MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:kbl_rt5663"); -MODULE_ALIAS("platform:kbl_rt5663_m98927"); diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c deleted file mode 100644 index 922cd0176e1f..000000000000 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ /dev/null @@ -1,854 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Kabylake I2S Machine Driver with MAXIM98927 - * RT5514 and RT5663 Codecs - * - * Copyright (C) 2017, Intel Corporation. All rights reserved. - * - * Modified from: - * Intel Kabylake I2S Machine driver supporting MAXIM98927 and - * RT5663 codecs - */ - -#include <linux/input.h> -#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> -#include <sound/soc-acpi.h> -#include "../../codecs/rt5514.h" -#include "../../codecs/rt5663.h" -#include "../../codecs/hdac_hdmi.h" -#include <linux/clk.h> -#include <linux/clk-provider.h> -#include <linux/clkdev.h> - -#define KBL_REALTEK_CODEC_DAI "rt5663-aif" -#define KBL_REALTEK_DMIC_CODEC_DAI "rt5514-aif1" -#define KBL_MAXIM_CODEC_DAI "max98927-aif1" -#define MAXIM_DEV0_NAME "i2c-MX98927:00" -#define MAXIM_DEV1_NAME "i2c-MX98927:01" -#define RT5514_DEV_NAME "i2c-10EC5514:00" -#define RT5663_DEV_NAME "i2c-10EC5663:00" -#define RT5514_AIF1_BCLK_FREQ (48000 * 8 * 16) -#define RT5514_AIF1_SYSCLK_FREQ 12288000 -#define NAME_SIZE 32 - -#define DMIC_CH(p) p->list[p->count-1] - - -static struct snd_soc_card kabylake_audio_card; -static const struct snd_pcm_hw_constraint_list *dmic_constraints; - -struct kbl_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct kbl_codec_private { - struct snd_soc_jack kabylake_headset; - struct list_head hdmi_pcm_list; - struct snd_soc_jack kabylake_hdmi[2]; - struct clk *mclk; - struct clk *sclk; -}; - -enum { - KBL_DPCM_AUDIO_PB = 0, - KBL_DPCM_AUDIO_CP, - KBL_DPCM_AUDIO_HS_PB, - KBL_DPCM_AUDIO_ECHO_REF_CP, - KBL_DPCM_AUDIO_DMIC_CP, - KBL_DPCM_AUDIO_RT5514_DSP, - KBL_DPCM_AUDIO_HDMI1_PB, - KBL_DPCM_AUDIO_HDMI2_PB, -}; - -static const struct snd_kcontrol_new kabylake_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), - SOC_DAPM_PIN_SWITCH("DMIC"), -}; - -static int platform_clock_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct kbl_codec_private *priv = snd_soc_card_get_drvdata(card); - int ret = 0; - - /* - * MCLK/SCLK need to be ON early for a successful synchronization of - * codec internal clock. And the clocks are turned off during - * POST_PMD after the stream is stopped. - */ - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - /* Enable MCLK */ - ret = clk_set_rate(priv->mclk, 24000000); - if (ret < 0) { - dev_err(card->dev, "Can't set rate for mclk, err: %d\n", - ret); - return ret; - } - - ret = clk_prepare_enable(priv->mclk); - if (ret < 0) { - dev_err(card->dev, "Can't enable mclk, err: %d\n", ret); - return ret; - } - - /* Enable SCLK */ - ret = clk_set_rate(priv->sclk, 3072000); - if (ret < 0) { - dev_err(card->dev, "Can't set rate for sclk, err: %d\n", - ret); - clk_disable_unprepare(priv->mclk); - return ret; - } - - ret = clk_prepare_enable(priv->sclk); - if (ret < 0) { - dev_err(card->dev, "Can't enable sclk, err: %d\n", ret); - clk_disable_unprepare(priv->mclk); - } - break; - case SND_SOC_DAPM_POST_PMD: - clk_disable_unprepare(priv->mclk); - clk_disable_unprepare(priv->sclk); - break; - default: - return 0; - } - - return 0; -} - -static const struct snd_soc_dapm_widget kabylake_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), - SND_SOC_DAPM_MIC("DMIC", NULL), - SND_SOC_DAPM_SPK("HDMI1", NULL), - SND_SOC_DAPM_SPK("HDMI2", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD), - -}; - -static const struct snd_soc_dapm_route kabylake_map[] = { - /* Headphones */ - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headphone Jack", NULL, "HPOL" }, - { "Headphone Jack", NULL, "HPOR" }, - - /* speaker */ - { "Left Spk", NULL, "Left BE_OUT" }, - { "Right Spk", NULL, "Right BE_OUT" }, - - /* other jacks */ - { "Headset Mic", NULL, "Platform Clock" }, - { "IN1P", NULL, "Headset Mic" }, - { "IN1N", NULL, "Headset Mic" }, - - /* CODEC BE connections */ - { "Left HiFi Playback", NULL, "ssp0 Tx" }, - { "Right HiFi Playback", NULL, "ssp0 Tx" }, - { "ssp0 Tx", NULL, "spk_out" }, - - { "AIF Playback", NULL, "ssp1 Tx" }, - { "ssp1 Tx", NULL, "codec1_out" }, - - { "hs_in", NULL, "ssp1 Rx" }, - { "ssp1 Rx", NULL, "AIF Capture" }, - - { "codec1_in", NULL, "ssp0 Rx" }, - { "ssp0 Rx", NULL, "AIF1 Capture" }, - - /* IV feedback path */ - { "codec0_fb_in", NULL, "ssp0 Rx"}, - { "ssp0 Rx", NULL, "Left HiFi Capture" }, - { "ssp0 Rx", NULL, "Right HiFi Capture" }, - - /* DMIC */ - { "DMIC1L", NULL, "DMIC" }, - { "DMIC1R", NULL, "DMIC" }, - { "DMIC2L", NULL, "DMIC" }, - { "DMIC2R", NULL, "DMIC" }, - - { "hifi2", NULL, "iDisp2 Tx" }, - { "iDisp2 Tx", NULL, "iDisp2_out" }, - { "hifi1", NULL, "iDisp1 Tx" }, - { "iDisp1 Tx", NULL, "iDisp1_out" }, -}; - -static struct snd_soc_codec_conf max98927_codec_conf[] = { - { - .dlc = COMP_CODEC_CONF(MAXIM_DEV0_NAME), - .name_prefix = "Right", - }, - { - .dlc = COMP_CODEC_CONF(MAXIM_DEV1_NAME), - .name_prefix = "Left", - }, -}; - - -static int kabylake_rt5663_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = asoc_rtd_to_cpu(rtd, 0)->component; - int ret; - - dapm = snd_soc_component_get_dapm(component); - ret = snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - if (ret) - dev_err(rtd->dev, "Ref Cap -Ignore suspend failed = %d\n", ret); - - return ret; -} - -static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; - struct snd_soc_jack *jack; - - /* - * Headset buttons map to the google Reference headset. - * These can be configured by userspace. - */ - ret = snd_soc_card_jack_new(&kabylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, &ctx->kabylake_headset, - NULL, 0); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); - return ret; - } - - jack = &ctx->kabylake_headset; - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - - snd_soc_component_set_jack(component, &ctx->kabylake_headset, NULL); - - ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "DMIC"); - if (ret) - dev_err(rtd->dev, "DMIC - Ignore suspend failed = %d\n", ret); - - return ret; -} - -static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); - struct kbl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = device; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB); -} - -static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB); -} - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static const unsigned int channels[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static int kbl_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * On this platform for PCM device we support, - * 48Khz - * stereo - * 16 bit audio - */ - - runtime->hw.channels_max = 2; - 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 kabylake_rt5663_fe_ops = { - .startup = kbl_fe_startup, -}; - -static int kabylake_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); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - struct snd_soc_dpcm *dpcm, *rtd_dpcm = NULL; - - /* - * The following loop will be called only for playback stream - * In this platform, there is only one playback device on every SSP - */ - for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_PLAYBACK, dpcm) { - rtd_dpcm = dpcm; - break; - } - - /* - * This following loop will be called only for capture stream - * In this platform, there is only one capture device on every SSP - */ - for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_CAPTURE, dpcm) { - rtd_dpcm = dpcm; - break; - } - - if (!rtd_dpcm) - return -EINVAL; - - /* - * The above 2 loops are mutually exclusive based on the stream direction, - * thus rtd_dpcm variable will never be overwritten - */ - - /* - * The ADSP will convert the FE rate to 48k, stereo, 24 bit - */ - if (!strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Port") || - !strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Headset Playback") || - !strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Capture Port")) { - rate->min = rate->max = 48000; - chan->min = chan->max = 2; - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - } else if (!strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio DMIC cap")) { - if (params_channels(params) == 2 || - DMIC_CH(dmic_constraints) == 2) - chan->min = chan->max = 2; - else - chan->min = chan->max = 4; - } - /* - * The speaker on the SSP0 supports S16_LE and not S24_LE. - * thus changing the mask here - */ - if (!strcmp(rtd_dpcm->be->dai_link->name, "SSP0-Codec")) - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); - - return 0; -} - -static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - int ret; - - /* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */ - rt5663_sel_asrc_clk_src(codec_dai->component, - RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER, - RT5663_CLK_SEL_I2S1_ASRC); - - ret = snd_soc_dai_set_sysclk(codec_dai, - RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN); - if (ret < 0) - dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); - - return ret; -} - -static struct snd_soc_ops kabylake_rt5663_ops = { - .hw_params = kabylake_rt5663_hw_params, -}; - -static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai; - int ret = 0, j; - - for_each_rtd_codec_dais(rtd, j, codec_dai) { - if (!strcmp(codec_dai->component->name, RT5514_DEV_NAME)) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0, 8, 16); - if (ret < 0) { - dev_err(rtd->dev, "set TDM slot err:%d\n", ret); - return ret; - } - - ret = snd_soc_dai_set_sysclk(codec_dai, - RT5514_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(rtd->dev, "set sysclk err: %d\n", ret); - return ret; - } - } - if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16); - if (ret < 0) { - dev_err(rtd->dev, "DEV0 TDM slot err:%d\n", ret); - return ret; - } - } - - if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16); - if (ret < 0) { - dev_err(rtd->dev, "DEV1 TDM slot err:%d\n", ret); - return ret; - } - } - } - return ret; -} - -static struct snd_soc_ops kabylake_ssp0_ops = { - .hw_params = kabylake_ssp0_hw_params, -}; - -static const unsigned int channels_dmic[] = { - 4, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { - .count = ARRAY_SIZE(channels_dmic), - .list = channels_dmic, - .mask = 0, -}; - -static const unsigned int dmic_2ch[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = { - .count = ARRAY_SIZE(dmic_2ch), - .list = dmic_2ch, - .mask = 0, -}; - -static int kabylake_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_max = DMIC_CH(dmic_constraints); - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - dmic_constraints); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static struct snd_soc_ops kabylake_dmic_ops = { - .startup = kabylake_dmic_startup, -}; - -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(echoref, - DAILINK_COMP_ARRAY(COMP_CPU("Echoref Pin"))); - -SND_SOC_DAILINK_DEF(spi_cpu, - DAILINK_COMP_ARRAY(COMP_CPU("spi-PRP0001:00"))); -SND_SOC_DAILINK_DEF(spi_platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("spi-PRP0001:00"))); - -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(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY( - /* Left */ COMP_CODEC(MAXIM_DEV0_NAME, KBL_MAXIM_CODEC_DAI), - /* Right */COMP_CODEC(MAXIM_DEV1_NAME, KBL_MAXIM_CODEC_DAI), - /* dmic */ COMP_CODEC(RT5514_DEV_NAME, KBL_REALTEK_DMIC_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(ssp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); -SND_SOC_DAILINK_DEF(ssp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC(RT5663_DEV_NAME, KBL_REALTEK_CODEC_DAI))); - -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(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); - -/* kabylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link kabylake_dais[] = { - /* Front End DAI links */ - [KBL_DPCM_AUDIO_PB] = { - .name = "Kbl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = kabylake_rt5663_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &kabylake_rt5663_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_CP] = { - .name = "Kbl 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 = &kabylake_rt5663_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_HS_PB] = { - .name = "Kbl Audio Headset Playback", - .stream_name = "Headset Audio", - .dpcm_playback = 1, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(system2, dummy, platform), - }, - [KBL_DPCM_AUDIO_ECHO_REF_CP] = { - .name = "Kbl Audio Echo Reference cap", - .stream_name = "Echoreference Capture", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - SND_SOC_DAILINK_REG(echoref, dummy, platform), - }, - [KBL_DPCM_AUDIO_RT5514_DSP] = { - .name = "rt5514 dsp", - .stream_name = "Wake on Voice", - SND_SOC_DAILINK_REG(spi_cpu, dummy, spi_platform), - }, - [KBL_DPCM_AUDIO_DMIC_CP] = { - .name = "Kbl Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &kabylake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Kbl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Kbl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - /* Back End DAI links */ - /* single Back end dai for both max speakers and dmic */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_DSP_B | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, - .ops = &kabylake_ssp0_ops, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - .name = "SSP1-Codec", - .id = 1, - .no_pcm = 1, - .init = kabylake_rt5663_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 = kabylake_ssp_fixup, - .ops = &kabylake_rt5663_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .dpcm_playback = 1, - .init = kabylake_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = kabylake_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, -}; - -static int kabylake_set_bias_level(struct snd_soc_card *card, - struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) -{ - struct snd_soc_component *component = dapm->component; - struct kbl_codec_private *priv = snd_soc_card_get_drvdata(card); - int ret = 0; - - if (!component || strcmp(component->name, RT5514_DEV_NAME)) - return 0; - - if (IS_ERR(priv->mclk)) - return 0; - - /* - * It's required to control mclk directly in the set_bias_level - * function for rt5514 codec or the recording function could - * break. - */ - switch (level) { - case SND_SOC_BIAS_PREPARE: - if (dapm->bias_level == SND_SOC_BIAS_ON) { - dev_dbg(card->dev, "Disable mclk"); - clk_disable_unprepare(priv->mclk); - } else { - dev_dbg(card->dev, "Enable mclk"); - ret = clk_set_rate(priv->mclk, 24000000); - if (ret) { - dev_err(card->dev, "Can't set rate for mclk, err: %d\n", - ret); - return ret; - } - - ret = clk_prepare_enable(priv->mclk); - if (ret) { - dev_err(card->dev, "Can't enable mclk, err: %d\n", - ret); - - /* mclk is already enabled in FW */ - ret = 0; - } - } - break; - default: - break; - } - - return ret; -} - -static int kabylake_card_late_probe(struct snd_soc_card *card) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card); - struct kbl_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - 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, &ctx->kabylake_hdmi[i], - NULL, 0); - - if (err) - return err; - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &ctx->kabylake_hdmi[i]); - if (err < 0) - return err; - i++; - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* - * kabylake audio machine driver for MAX98927 + RT5514 + RT5663 - */ -static struct snd_soc_card kabylake_audio_card = { - .name = "kbl-r5514-5663-max", - .owner = THIS_MODULE, - .dai_link = kabylake_dais, - .num_links = ARRAY_SIZE(kabylake_dais), - .set_bias_level = kabylake_set_bias_level, - .controls = kabylake_controls, - .num_controls = ARRAY_SIZE(kabylake_controls), - .dapm_widgets = kabylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), - .dapm_routes = kabylake_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_map), - .codec_conf = max98927_codec_conf, - .num_configs = ARRAY_SIZE(max98927_codec_conf), - .fully_routed = true, - .late_probe = kabylake_card_late_probe, -}; - -static int kabylake_audio_probe(struct platform_device *pdev) -{ - struct kbl_codec_private *ctx; - struct snd_soc_acpi_mach *mach; - int ret; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - kabylake_audio_card.dev = &pdev->dev; - snd_soc_card_set_drvdata(&kabylake_audio_card, ctx); - - mach = pdev->dev.platform_data; - if (mach) - dmic_constraints = mach->mach_params.dmic_num == 2 ? - &constraints_dmic_2ch : &constraints_dmic_channels; - - ctx->mclk = devm_clk_get(&pdev->dev, "ssp1_mclk"); - if (IS_ERR(ctx->mclk)) { - ret = PTR_ERR(ctx->mclk); - if (ret == -ENOENT) { - dev_info(&pdev->dev, - "Failed to get ssp1_mclk, defer probe\n"); - return -EPROBE_DEFER; - } - - dev_err(&pdev->dev, "Failed to get ssp1_mclk with err:%d\n", - ret); - return ret; - } - - ctx->sclk = devm_clk_get(&pdev->dev, "ssp1_sclk"); - if (IS_ERR(ctx->sclk)) { - ret = PTR_ERR(ctx->sclk); - if (ret == -ENOENT) { - dev_info(&pdev->dev, - "Failed to get ssp1_sclk, defer probe\n"); - return -EPROBE_DEFER; - } - - dev_err(&pdev->dev, "Failed to get ssp1_sclk with err:%d\n", - ret); - return ret; - } - - return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card); -} - -static const struct platform_device_id kbl_board_ids[] = { - { .name = "kbl_r5514_5663_max" }, - { } -}; - -static struct platform_driver kabylake_audio = { - .probe = kabylake_audio_probe, - .driver = { - .name = "kbl_r5514_5663_max", - .pm = &snd_soc_pm_ops, - }, - .id_table = kbl_board_ids, -}; - -module_platform_driver(kabylake_audio) - -/* Module information */ -MODULE_DESCRIPTION("Audio Machine driver-RT5663 RT5514 & MAX98927"); -MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:kbl_r5514_5663_max"); diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.c b/sound/soc/intel/boards/skl_hda_dsp_common.c deleted file mode 100644 index 07bfb2e64b3b..000000000000 --- a/sound/soc/intel/boards/skl_hda_dsp_common.c +++ /dev/null @@ -1,174 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright(c) 2015-18 Intel Corporation. - -/* - * Common functions used in different Intel machine drivers - */ -#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> -#include "../../codecs/hdac_hdmi.h" -#include "skl_hda_dsp_common.h" - -#include <sound/hda_codec.h> -#include "../../codecs/hdac_hda.h" - -#define NAME_SIZE 32 - -int skl_hda_hdmi_add_pcm(struct snd_soc_card *card, int device) -{ - struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); - struct skl_hda_hdmi_pcm *pcm; - char dai_name[NAME_SIZE]; - - pcm = devm_kzalloc(card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - snprintf(dai_name, sizeof(dai_name), "intel-hdmi-hifi%d", - ctx->dai_index); - pcm->codec_dai = snd_soc_card_get_codec_dai(card, dai_name); - if (!pcm->codec_dai) - return -EINVAL; - - pcm->device = device; - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -SND_SOC_DAILINK_DEF(idisp1_cpu, - 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_cpu, - 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_cpu, - 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(analog_cpu, - DAILINK_COMP_ARRAY(COMP_CPU("Analog CPU DAI"))); -SND_SOC_DAILINK_DEF(analog_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D0", "Analog Codec DAI"))); - -SND_SOC_DAILINK_DEF(digital_cpu, - DAILINK_COMP_ARRAY(COMP_CPU("Digital CPU DAI"))); -SND_SOC_DAILINK_DEF(digital_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D0", "Digital Codec DAI"))); - -SND_SOC_DAILINK_DEF(dmic_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); - -SND_SOC_DAILINK_DEF(dmic_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); - -SND_SOC_DAILINK_DEF(dmic16k, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); - -/* skl_hda_digital audio interface glue - connects codec <--> CPU */ -struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS] = { - /* Back End DAI links */ - { - .name = "iDisp1", - .id = 1, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_cpu, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 2, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_cpu, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 3, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_cpu, idisp3_codec, platform), - }, - { - .name = "Analog Playback and Capture", - .id = 4, - .dpcm_playback = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(analog_cpu, analog_codec, platform), - }, - { - .name = "Digital Playback and Capture", - .id = 5, - .dpcm_playback = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(digital_cpu, digital_codec, platform), - }, - { - .name = "dmic01", - .id = 6, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "dmic16k", - .id = 7, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic16k, dmic_codec, platform), - }, -}; - -int skl_hda_hdmi_jack_init(struct snd_soc_card *card) -{ - struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_component *component = NULL; - struct skl_hda_hdmi_pcm *pcm; - char jack_name[NAME_SIZE]; - int err; - - if (ctx->common_hdmi_codec_drv) - return skl_hda_hdmi_build_controls(card); - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - 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, &pcm->hdmi_jack, - NULL, 0); - - if (err) - return err; - - err = snd_jack_add_new_kctl(pcm->hdmi_jack.jack, - jack_name, SND_JACK_AVOUT); - if (err) - dev_warn(component->dev, "failed creating Jack kctl\n"); - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &pcm->hdmi_jack); - if (err < 0) - return err; - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.h b/sound/soc/intel/boards/skl_hda_dsp_common.h deleted file mode 100644 index 4b0b3959182e..000000000000 --- a/sound/soc/intel/boards/skl_hda_dsp_common.h +++ /dev/null @@ -1,66 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright(c) 2015-18 Intel Corporation. - */ - -/* - * This file defines data structures used in Machine Driver for Intel - * platforms with HDA Codecs. - */ - -#ifndef __SKL_HDA_DSP_COMMON_H -#define __SKL_HDA_DSP_COMMON_H -#include <linux/module.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/jack.h> -#include <sound/hda_codec.h> -#include "../../codecs/hdac_hda.h" -#include "hda_dsp_common.h" - -#define HDA_DSP_MAX_BE_DAI_LINKS 7 - -struct skl_hda_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - struct snd_soc_jack hdmi_jack; - int device; -}; - -struct skl_hda_private { - struct list_head hdmi_pcm_list; - int pcm_count; - int dai_index; - const char *platform_name; - bool common_hdmi_codec_drv; - bool idisp_codec; -}; - -extern struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS]; -int skl_hda_hdmi_jack_init(struct snd_soc_card *card); -int skl_hda_hdmi_add_pcm(struct snd_soc_card *card, int device); - -/* - * Search card topology and register HDMI PCM related controls - * to codec driver. - */ -static inline int skl_hda_hdmi_build_controls(struct snd_soc_card *card) -{ - struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_component *component; - struct skl_hda_hdmi_pcm *pcm; - - /* HDMI disabled, do not create controls */ - if (list_empty(&ctx->hdmi_pcm_list)) - return 0; - - pcm = list_first_entry(&ctx->hdmi_pcm_list, struct skl_hda_hdmi_pcm, - head); - component = pcm->codec_dai->component; - if (!component) - return -EINVAL; - - return hda_dsp_hdmi_build_controls(card, component); -} - -#endif /* __SOUND_SOC_HDA_DSP_COMMON_H */ diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index bc50eda297ab..0554c7e2cb34 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -8,172 +8,23 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <sound/core.h> +#include <sound/hda_codec.h> #include <sound/jack.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> #include <sound/soc-acpi.h> -#include "../../codecs/hdac_hdmi.h" -#include "skl_hda_dsp_common.h" - -static const struct snd_soc_dapm_widget skl_hda_widgets[] = { - SND_SOC_DAPM_HP("Analog Out", NULL), - SND_SOC_DAPM_MIC("Analog In", NULL), - SND_SOC_DAPM_HP("Alt Analog Out", NULL), - SND_SOC_DAPM_MIC("Alt Analog In", NULL), - SND_SOC_DAPM_SPK("Digital Out", NULL), - SND_SOC_DAPM_MIC("Digital In", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), -}; - -static const struct snd_soc_dapm_route skl_hda_map[] = { - { "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"}, - - { "Analog Out", NULL, "Codec Output Pin1" }, - { "Digital Out", NULL, "Codec Output Pin2" }, - { "Alt Analog Out", NULL, "Codec Output Pin3" }, - - { "Codec Input Pin1", NULL, "Analog In" }, - { "Codec Input Pin2", NULL, "Digital In" }, - { "Codec Input Pin3", NULL, "Alt Analog In" }, - - /* digital mics */ - {"DMic", NULL, "SoC DMIC"}, - - /* CODEC BE connections */ - { "Analog Codec Playback", NULL, "Analog CPU Playback" }, - { "Analog CPU Playback", NULL, "codec0_out" }, - { "Digital Codec Playback", NULL, "Digital CPU Playback" }, - { "Digital CPU Playback", NULL, "codec1_out" }, - { "Alt Analog Codec Playback", NULL, "Alt Analog CPU Playback" }, - { "Alt Analog CPU Playback", NULL, "codec2_out" }, - - { "codec0_in", NULL, "Analog CPU Capture" }, - { "Analog CPU Capture", NULL, "Analog Codec Capture" }, - { "codec1_in", NULL, "Digital CPU Capture" }, - { "Digital CPU Capture", NULL, "Digital Codec Capture" }, - { "codec2_in", NULL, "Alt Analog CPU Capture" }, - { "Alt Analog CPU Capture", NULL, "Alt Analog Codec Capture" }, -}; - -SND_SOC_DAILINK_DEF(dummy_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai"))); +#include "../../codecs/hdac_hda.h" +#include "../../sof/intel/hda.h" +#include "sof_board_helpers.h" static int skl_hda_card_late_probe(struct snd_soc_card *card) { - return skl_hda_hdmi_jack_init(card); + return sof_intel_board_card_late_probe(card); } -static int -skl_hda_add_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link) -{ - struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); - int ret = 0; - - dev_dbg(card->dev, "%s: dai link name - %s\n", __func__, link->name); - link->platforms->name = ctx->platform_name; - link->nonatomic = 1; - - if (!ctx->idisp_codec) - return 0; - - if (strstr(link->name, "HDMI")) { - ret = skl_hda_hdmi_add_pcm(card, ctx->pcm_count); - - if (ret < 0) - return ret; - - ctx->dai_index++; - } - - ctx->pcm_count++; - return ret; -} - -static struct snd_soc_card hda_soc_card = { - .name = "hda-dsp", - .owner = THIS_MODULE, - .dai_link = skl_hda_be_dai_links, - .dapm_widgets = skl_hda_widgets, - .dapm_routes = skl_hda_map, - .add_dai_link = skl_hda_add_dai_link, - .fully_routed = true, - .late_probe = skl_hda_card_late_probe, -}; - -static char hda_soc_components[30]; - -#define IDISP_DAI_COUNT 3 -#define HDAC_DAI_COUNT 2 -#define DMIC_DAI_COUNT 2 - -/* there are two routes per iDisp output */ -#define IDISP_ROUTE_COUNT (IDISP_DAI_COUNT * 2) -#define IDISP_CODEC_MASK 0x4 - #define HDA_CODEC_AUTOSUSPEND_DELAY_MS 1000 -static int skl_hda_fill_card_info(struct snd_soc_acpi_mach_params *mach_params) -{ - struct snd_soc_card *card = &hda_soc_card; - struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_dai_link *dai_link; - u32 codec_count, codec_mask; - int i, num_links, num_route; - - codec_mask = mach_params->codec_mask; - codec_count = hweight_long(codec_mask); - ctx->idisp_codec = !!(codec_mask & IDISP_CODEC_MASK); - - if (!codec_count || codec_count > 2 || - (codec_count == 2 && !ctx->idisp_codec)) - return -EINVAL; - - if (codec_mask == IDISP_CODEC_MASK) { - /* topology with iDisp as the only HDA codec */ - num_links = IDISP_DAI_COUNT + DMIC_DAI_COUNT; - num_route = IDISP_ROUTE_COUNT; - - /* - * rearrange the dai link array and make the - * dmic dai links follow idsp dai links for only - * num_links of dai links need to be registered - * to ASoC. - */ - for (i = 0; i < DMIC_DAI_COUNT; i++) { - skl_hda_be_dai_links[IDISP_DAI_COUNT + i] = - skl_hda_be_dai_links[IDISP_DAI_COUNT + - HDAC_DAI_COUNT + i]; - } - } else { - /* topology with external and iDisp HDA codecs */ - num_links = ARRAY_SIZE(skl_hda_be_dai_links); - num_route = ARRAY_SIZE(skl_hda_map); - card->dapm_widgets = skl_hda_widgets; - card->num_dapm_widgets = ARRAY_SIZE(skl_hda_widgets); - if (!ctx->idisp_codec) { - for (i = 0; i < IDISP_DAI_COUNT; i++) { - skl_hda_be_dai_links[i].codecs = dummy_codec; - skl_hda_be_dai_links[i].num_codecs = - ARRAY_SIZE(dummy_codec); - } - } - } - - card->num_links = num_links; - card->num_dapm_routes = num_route; - - for_each_card_prelinks(card, i, dai_link) - dai_link->platforms->name = mach_params->platform; - - return 0; -} - static void skl_set_hda_codec_autosuspend_delay(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; @@ -183,62 +34,115 @@ static void skl_set_hda_codec_autosuspend_delay(struct snd_soc_card *card) for_each_card_rtds(card, rtd) { if (!strstr(rtd->dai_link->codecs->name, "ehdaudio0D0")) continue; - dai = asoc_rtd_to_codec(rtd, 0); + dai = snd_soc_rtd_to_codec(rtd, 0); hda_pvt = snd_soc_component_get_drvdata(dai->component); if (hda_pvt) { /* * all codecs are on the same bus, so it's sufficient * to look up only the first one */ - snd_hda_set_power_save(hda_pvt->codec.bus, + snd_hda_set_power_save(hda_pvt->codec->bus, HDA_CODEC_AUTOSUSPEND_DELAY_MS); break; } } } +#define IDISP_HDMI_BE_ID 1 +#define HDA_BE_ID 4 +#define DMIC01_BE_ID 6 +#define DMIC16K_BE_ID 7 +#define BT_OFFLOAD_BE_ID 8 + +#define HDA_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_IDISP_HDMI, \ + SOF_LINK_HDA, \ + SOF_LINK_DMIC01, \ + SOF_LINK_DMIC16K, \ + SOF_LINK_BT_OFFLOAD, \ + SOF_LINK_NONE, \ + SOF_LINK_NONE) + +#define HDA_LINK_IDS SOF_LINK_ORDER(IDISP_HDMI_BE_ID, \ + HDA_BE_ID, \ + DMIC01_BE_ID, \ + DMIC16K_BE_ID, \ + BT_OFFLOAD_BE_ID, \ + 0, \ + 0) + +static unsigned long +skl_hda_get_board_quirk(struct snd_soc_acpi_mach_params *mach_params) +{ + unsigned long board_quirk = 0; + int ssp_bt; + + if (hweight_long(mach_params->bt_link_mask) == 1) { + ssp_bt = fls(mach_params->bt_link_mask) - 1; + board_quirk |= SOF_SSP_PORT_BT_OFFLOAD(ssp_bt) | + SOF_BT_OFFLOAD_PRESENT; + } + + return board_quirk; +} + static int skl_hda_audio_probe(struct platform_device *pdev) { - struct snd_soc_acpi_mach *mach; - struct skl_hda_private *ctx; + struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; + struct sof_card_private *ctx; + struct snd_soc_card *card; + unsigned long board_quirk = skl_hda_get_board_quirk(&mach->mach_params); int ret; - dev_dbg(&pdev->dev, "%s: entry\n", __func__); + card = devm_kzalloc(&pdev->dev, sizeof(struct snd_soc_card), GFP_KERNEL); + if (!card) + return -ENOMEM; + + card->name = "hda-dsp"; + card->owner = THIS_MODULE; + card->fully_routed = true; + card->late_probe = skl_hda_card_late_probe; - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + dev_dbg(&pdev->dev, "board_quirk = %lx\n", board_quirk); + + /* initialize ctx with board quirk */ + ctx = sof_intel_board_get_ctx(&pdev->dev, board_quirk); if (!ctx) return -ENOMEM; - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + if (HDA_EXT_CODEC(mach->mach_params.codec_mask)) + ctx->hda_codec_present = true; - mach = pdev->dev.platform_data; - if (!mach) - return -EINVAL; + if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) + ctx->hdmi.idisp_codec = true; - snd_soc_card_set_drvdata(&hda_soc_card, ctx); + ctx->link_order_overwrite = HDA_LINK_ORDER; + ctx->link_id_overwrite = HDA_LINK_IDS; - ret = skl_hda_fill_card_info(&mach->mach_params); - if (ret < 0) { - dev_err(&pdev->dev, "Unsupported HDAudio/iDisp configuration found\n"); + /* update dai_link */ + ret = sof_intel_board_set_dai_link(&pdev->dev, card, ctx); + if (ret) return ret; - } - - ctx->pcm_count = hda_soc_card.num_links; - ctx->dai_index = 1; /* hdmi codec dai name starts from index 1 */ - ctx->platform_name = mach->mach_params.platform; - ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; - hda_soc_card.dev = &pdev->dev; + card->dev = &pdev->dev; if (mach->mach_params.dmic_num > 0) { - snprintf(hda_soc_components, sizeof(hda_soc_components), - "cfg-dmics:%d", mach->mach_params.dmic_num); - hda_soc_card.components = hda_soc_components; + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + "cfg-dmics:%d", + mach->mach_params.dmic_num); + if (!card->components) + return -ENOMEM; } - ret = devm_snd_soc_register_card(&pdev->dev, &hda_soc_card); + ret = snd_soc_fixup_dai_links_platform_name(card, + mach->mach_params.platform); + if (ret) + return ret; + + snd_soc_card_set_drvdata(card, ctx); + + ret = devm_snd_soc_register_card(&pdev->dev, card); if (!ret) - skl_set_hda_codec_autosuspend_delay(&hda_soc_card); + skl_set_hda_codec_autosuspend_delay(card); return ret; } @@ -258,3 +162,4 @@ MODULE_DESCRIPTION("SKL/KBL/BXT/APL HDA Generic Machine driver"); MODULE_AUTHOR("Rakesh Ughreja <rakesh.a.ughreja@intel.com>"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:skl_hda_dsp_generic"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS"); diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c deleted file mode 100644 index 55802900069a..000000000000 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ /dev/null @@ -1,693 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Skylake I2S Machine Driver with MAXIM98357A - * and NAU88L25 - * - * Copyright (C) 2015, Intel Corporation. All rights reserved. - */ - -#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> -#include <sound/soc-acpi.h> -#include "../../codecs/nau8825.h" -#include "../../codecs/hdac_hdmi.h" - -#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" -#define SKL_MAXIM_CODEC_DAI "HiFi" -#define DMIC_CH(p) p->list[p->count-1] - -static struct snd_soc_jack skylake_headset; -static struct snd_soc_card skylake_audio_card; -static const struct snd_pcm_hw_constraint_list *dmic_constraints; -static struct snd_soc_jack skylake_hdmi[3]; - -struct skl_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct skl_nau8825_private { - struct list_head hdmi_pcm_list; -}; - -enum { - SKL_DPCM_AUDIO_PB = 0, - SKL_DPCM_AUDIO_CP, - SKL_DPCM_AUDIO_REF_CP, - SKL_DPCM_AUDIO_DMIC_CP, - SKL_DPCM_AUDIO_HDMI1_PB, - SKL_DPCM_AUDIO_HDMI2_PB, - SKL_DPCM_AUDIO_HDMI3_PB, -}; - -static int platform_clock_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct snd_soc_dai *codec_dai; - int ret; - - codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI); - if (!codec_dai) { - dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n"); - return -EIO; - } - - if (SND_SOC_DAPM_EVENT_ON(event)) { - ret = snd_soc_dai_set_sysclk(codec_dai, - NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(card->dev, "set sysclk err = %d\n", ret); - return -EIO; - } - } else { - ret = snd_soc_dai_set_sysclk(codec_dai, - NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(card->dev, "set sysclk err = %d\n", ret); - return -EIO; - } - } - - return ret; -} - -static const struct snd_kcontrol_new skylake_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Spk"), -}; - -static const struct snd_soc_dapm_widget skylake_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Spk", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("DP1", NULL), - SND_SOC_DAPM_SPK("DP2", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD), -}; - -static const struct snd_soc_dapm_route skylake_map[] = { - /* HP jack connectors - unknown if we have jack detection */ - { "Headphone Jack", NULL, "HPOL" }, - { "Headphone Jack", NULL, "HPOR" }, - - /* speaker */ - { "Spk", NULL, "Speaker" }, - - /* other jacks */ - { "MIC", NULL, "Headset Mic" }, - { "DMic", NULL, "SoC DMIC" }, - - /* CODEC BE connections */ - { "HiFi Playback", NULL, "ssp0 Tx" }, - { "ssp0 Tx", NULL, "codec0_out" }, - - { "Playback", NULL, "ssp1 Tx" }, - { "ssp1 Tx", NULL, "codec1_out" }, - - { "codec0_in", NULL, "ssp1 Rx" }, - { "ssp1 Rx", NULL, "Capture" }, - - /* DMIC */ - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "DMIC AIF" }, - - { "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"}, - - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headset Mic", NULL, "Platform Clock" }, -}; - -static int skylake_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); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - - /* The ADSP will covert the FE rate to 48k, stereo */ - rate->min = rate->max = 48000; - chan->min = chan->max = 2; - - /* set SSP0 to 24 bit */ - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - - return 0; -} - -static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; - - /* - * Headset buttons map to the google Reference headset. - * These can be configured by userspace. - */ - ret = snd_soc_card_jack_new(&skylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset, - NULL, 0); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); - return ret; - } - - nau8825_enable_jack_detect(component, &skylake_headset); - - snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - - return ret; -} - -static int skylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) -{ - struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); - struct skl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = SKL_DPCM_AUDIO_HDMI1_PB; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int skylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) -{ - struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); - struct skl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = SKL_DPCM_AUDIO_HDMI2_PB; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int skylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) -{ - struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); - struct skl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = SKL_DPCM_AUDIO_HDMI3_PB; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = asoc_rtd_to_cpu(rtd, 0)->component; - - dapm = snd_soc_component_get_dapm(component); - snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - - return 0; -} - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static const unsigned int channels[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static int skl_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * On this platform for PCM device we support, - * 48Khz - * stereo - * 16 bit audio - */ - - runtime->hw.channels_max = 2; - 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 skylake_nau8825_fe_ops = { - .startup = skl_fe_startup, -}; - -static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - int ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, - NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN); - - if (ret < 0) - dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); - - return ret; -} - -static const struct snd_soc_ops skylake_nau8825_ops = { - .hw_params = skylake_nau8825_hw_params, -}; - -static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - - if (params_channels(params) == 2 || DMIC_CH(dmic_constraints) == 2) - chan->min = chan->max = 2; - else - chan->min = chan->max = 4; - - return 0; -} - -static const unsigned int channels_dmic[] = { - 2, 4, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { - .count = ARRAY_SIZE(channels_dmic), - .list = channels_dmic, - .mask = 0, -}; - -static const unsigned int dmic_2ch[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = { - .count = ARRAY_SIZE(dmic_2ch), - .list = dmic_2ch, - .mask = 0, -}; - -static int skylake_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_max = DMIC_CH(dmic_constraints); - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - dmic_constraints); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static const struct snd_soc_ops skylake_dmic_ops = { - .startup = skylake_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, -}; - -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, -}; - -static int skylake_refcap_startup(struct snd_pcm_substream *substream) -{ - substream->runtime->hw.channels_max = 1; - snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_refcap); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_16000); -} - -static const struct snd_soc_ops skylake_refcap_ops = { - .startup = skylake_refcap_startup, -}; - -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(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"))); - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("MX98357A:00", SKL_MAXIM_CODEC_DAI))); - -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-10508825:00", - SKL_NUVOTON_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(dmic_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); -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:1f.3"))); - -/* skylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link skylake_dais[] = { - /* Front End DAI links */ - [SKL_DPCM_AUDIO_PB] = { - .name = "Skl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = skylake_nau8825_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &skylake_nau8825_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [SKL_DPCM_AUDIO_CP] = { - .name = "Skl 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 = &skylake_nau8825_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [SKL_DPCM_AUDIO_REF_CP] = { - .name = "Skl Audio Reference cap", - .stream_name = "Wake on Voice", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_refcap_ops, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [SKL_DPCM_AUDIO_DMIC_CP] = { - .name = "Skl Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Skl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Skl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI3_PB] = { - .name = "Skl HDMI Port3", - .stream_name = "Hdmi3", - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-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 = skylake_ssp_fixup, - .dpcm_playback = 1, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - /* SSP1 - Codec */ - .name = "SSP1-Codec", - .id = 1, - .no_pcm = 1, - .init = skylake_nau8825_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 = skylake_ssp_fixup, - .ops = &skylake_nau8825_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - .name = "dmic01", - .id = 2, - .be_hw_params_fixup = skylake_dmic_fixup, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .dpcm_playback = 1, - .init = skylake_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = skylake_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = skylake_hdmi3_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -#define NAME_SIZE 32 -static int skylake_card_late_probe(struct snd_soc_card *card) -{ - struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(card); - struct skl_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - 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, - &skylake_hdmi[i], - NULL, 0); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &skylake_hdmi[i]); - if (err < 0) - return err; - - i++; - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* skylake audio machine driver for SPT + NAU88L25 */ -static struct snd_soc_card skylake_audio_card = { - .name = "sklnau8825max", - .owner = THIS_MODULE, - .dai_link = skylake_dais, - .num_links = ARRAY_SIZE(skylake_dais), - .controls = skylake_controls, - .num_controls = ARRAY_SIZE(skylake_controls), - .dapm_widgets = skylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(skylake_widgets), - .dapm_routes = skylake_map, - .num_dapm_routes = ARRAY_SIZE(skylake_map), - .fully_routed = true, - .late_probe = skylake_card_late_probe, -}; - -static int skylake_audio_probe(struct platform_device *pdev) -{ - struct skl_nau8825_private *ctx; - struct snd_soc_acpi_mach *mach; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - skylake_audio_card.dev = &pdev->dev; - snd_soc_card_set_drvdata(&skylake_audio_card, ctx); - - mach = pdev->dev.platform_data; - if (mach) - dmic_constraints = mach->mach_params.dmic_num == 2 ? - &constraints_dmic_2ch : &constraints_dmic_channels; - - return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); -} - -static const struct platform_device_id skl_board_ids[] = { - { .name = "skl_n88l25_m98357a" }, - { .name = "kbl_n88l25_m98357a" }, - { } -}; - -static struct platform_driver skylake_audio = { - .probe = skylake_audio_probe, - .driver = { - .name = "skl_n88l25_m98357a", - .pm = &snd_soc_pm_ops, - }, - .id_table = skl_board_ids, -}; - -module_platform_driver(skylake_audio) - -/* Module information */ -MODULE_DESCRIPTION("Audio Machine driver-NAU88L25 & MAX98357A in I2S mode"); -MODULE_AUTHOR("Rohit Ainapure <rohit.m.ainapure@intel.com"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:skl_n88l25_m98357a"); -MODULE_ALIAS("platform:kbl_n88l25_m98357a"); diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c deleted file mode 100644 index 0c734f3a9364..000000000000 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ /dev/null @@ -1,741 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Skylake I2S Machine Driver for NAU88L25+SSM4567 - * - * Copyright (C) 2015, Intel Corporation. All rights reserved. - * - * Modified from: - * Intel Skylake I2S Machine Driver for NAU88L25 and SSM4567 - * - * Copyright (C) 2015, Intel Corporation. All rights reserved. - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include <sound/jack.h> -#include <sound/pcm_params.h> -#include "../../codecs/nau8825.h" -#include "../../codecs/hdac_hdmi.h" - -#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" -#define SKL_SSM_CODEC_DAI "ssm4567-hifi" -#define DMIC_CH(p) p->list[p->count-1] - -static struct snd_soc_jack skylake_headset; -static struct snd_soc_card skylake_audio_card; -static const struct snd_pcm_hw_constraint_list *dmic_constraints; -static struct snd_soc_jack skylake_hdmi[3]; - -struct skl_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct skl_nau88125_private { - struct list_head hdmi_pcm_list; -}; -enum { - SKL_DPCM_AUDIO_PB = 0, - SKL_DPCM_AUDIO_CP, - SKL_DPCM_AUDIO_REF_CP, - SKL_DPCM_AUDIO_DMIC_CP, - SKL_DPCM_AUDIO_HDMI1_PB, - SKL_DPCM_AUDIO_HDMI2_PB, - SKL_DPCM_AUDIO_HDMI3_PB, -}; - -static const struct snd_kcontrol_new skylake_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Left Speaker"), - SOC_DAPM_PIN_SWITCH("Right Speaker"), -}; - -static int platform_clock_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct snd_soc_dai *codec_dai; - int ret; - - codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI); - if (!codec_dai) { - dev_err(card->dev, "Codec dai not found\n"); - return -EIO; - } - - if (SND_SOC_DAPM_EVENT_ON(event)) { - ret = snd_soc_dai_set_sysclk(codec_dai, - NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(card->dev, "set sysclk err = %d\n", ret); - return -EIO; - } - } else { - ret = snd_soc_dai_set_sysclk(codec_dai, - NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(card->dev, "set sysclk err = %d\n", ret); - return -EIO; - } - } - return ret; -} - -static const struct snd_soc_dapm_widget skylake_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Left Speaker", NULL), - SND_SOC_DAPM_SPK("Right Speaker", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("DP1", NULL), - SND_SOC_DAPM_SPK("DP2", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD), -}; - -static const struct snd_soc_dapm_route skylake_map[] = { - /* HP jack connectors - unknown if we have jack detection */ - {"Headphone Jack", NULL, "HPOL"}, - {"Headphone Jack", NULL, "HPOR"}, - - /* speaker */ - {"Left Speaker", NULL, "Left OUT"}, - {"Right Speaker", NULL, "Right OUT"}, - - /* other jacks */ - {"MIC", NULL, "Headset Mic"}, - {"DMic", NULL, "SoC DMIC"}, - - /* CODEC BE connections */ - { "Left Playback", NULL, "ssp0 Tx"}, - { "Right Playback", NULL, "ssp0 Tx"}, - { "ssp0 Tx", NULL, "codec0_out"}, - - /* IV feedback path */ - { "codec0_lp_in", NULL, "ssp0 Rx"}, - { "ssp0 Rx", NULL, "Left Capture Sense" }, - { "ssp0 Rx", NULL, "Right Capture Sense" }, - - { "Playback", NULL, "ssp1 Tx"}, - { "ssp1 Tx", NULL, "codec1_out"}, - - { "codec0_in", NULL, "ssp1 Rx" }, - { "ssp1 Rx", NULL, "Capture" }, - - /* DMIC */ - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "DMIC AIF" }, - - { "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"}, - - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headset Mic", NULL, "Platform Clock" }, -}; - -static struct snd_soc_codec_conf ssm4567_codec_conf[] = { - { - .dlc = COMP_CODEC_CONF("i2c-INT343B:00"), - .name_prefix = "Left", - }, - { - .dlc = COMP_CODEC_CONF("i2c-INT343B:01"), - .name_prefix = "Right", - }, -}; - -static int skylake_ssm4567_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - - /* Slot 1 for left */ - ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(rtd, 0), 0x01, 0x01, 2, 48); - if (ret < 0) - return ret; - - /* Slot 2 for right */ - ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(rtd, 1), 0x02, 0x02, 2, 48); - if (ret < 0) - return ret; - - return ret; -} - -static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; - - /* - * 4 buttons here map to the google Reference headset - * The use of these buttons can be decided by the user space. - */ - ret = snd_soc_card_jack_new(&skylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset, - NULL, 0); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); - return ret; - } - - nau8825_enable_jack_detect(component, &skylake_headset); - - snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - - return ret; -} - -static int skylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) -{ - struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); - struct skl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = SKL_DPCM_AUDIO_HDMI1_PB; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int skylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) -{ - struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); - struct skl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = SKL_DPCM_AUDIO_HDMI2_PB; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - - -static int skylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) -{ - struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); - struct skl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = SKL_DPCM_AUDIO_HDMI3_PB; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = asoc_rtd_to_cpu(rtd, 0)->component; - - dapm = snd_soc_component_get_dapm(component); - snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - - return 0; -} - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static const unsigned int channels[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static int skl_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * on this platform for PCM device we support, - * 48Khz - * stereo - * 16 bit audio - */ - - runtime->hw.channels_max = 2; - 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 skylake_nau8825_fe_ops = { - .startup = skl_fe_startup, -}; - -static int skylake_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); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - - /* The ADSP will covert the FE rate to 48k, stereo */ - rate->min = rate->max = 48000; - chan->min = chan->max = 2; - - /* set SSP0 to 24 bit */ - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - return 0; -} - -static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - if (params_channels(params) == 2 || DMIC_CH(dmic_constraints) == 2) - chan->min = chan->max = 2; - else - chan->min = chan->max = 4; - - return 0; -} - -static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - int ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, - NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN); - - if (ret < 0) - dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); - - return ret; -} - -static const struct snd_soc_ops skylake_nau8825_ops = { - .hw_params = skylake_nau8825_hw_params, -}; - -static const unsigned int channels_dmic[] = { - 2, 4, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { - .count = ARRAY_SIZE(channels_dmic), - .list = channels_dmic, - .mask = 0, -}; - -static const unsigned int dmic_2ch[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = { - .count = ARRAY_SIZE(dmic_2ch), - .list = dmic_2ch, - .mask = 0, -}; - -static int skylake_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_max = DMIC_CH(dmic_constraints); - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - dmic_constraints); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static const struct snd_soc_ops skylake_dmic_ops = { - .startup = skylake_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, -}; - -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, -}; - -static int skylake_refcap_startup(struct snd_pcm_substream *substream) -{ - substream->runtime->hw.channels_max = 1; - snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_refcap); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_16000); -} - -static const struct snd_soc_ops skylake_refcap_ops = { - .startup = skylake_refcap_startup, -}; - -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(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"))); - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY( - /* Left */ COMP_CODEC("i2c-INT343B:00", SKL_SSM_CODEC_DAI), - /* Right */ COMP_CODEC("i2c-INT343B:01", SKL_SSM_CODEC_DAI))); - -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-10508825:00", SKL_NUVOTON_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(dmic01_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); -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:1f.3"))); - -/* skylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link skylake_dais[] = { - /* Front End DAI links */ - [SKL_DPCM_AUDIO_PB] = { - .name = "Skl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = skylake_nau8825_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &skylake_nau8825_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [SKL_DPCM_AUDIO_CP] = { - .name = "Skl 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 = &skylake_nau8825_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [SKL_DPCM_AUDIO_REF_CP] = { - .name = "Skl Audio Reference cap", - .stream_name = "Wake on Voice", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_refcap_ops, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [SKL_DPCM_AUDIO_DMIC_CP] = { - .name = "Skl Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Skl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Skl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI3_PB] = { - .name = "Skl HDMI Port3", - .stream_name = "Hdmi3", - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBS_CFS, - .init = skylake_ssm4567_codec_init, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = skylake_ssp_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - /* SSP1 - Codec */ - .name = "SSP1-Codec", - .id = 1, - .no_pcm = 1, - .init = skylake_nau8825_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 = skylake_ssp_fixup, - .ops = &skylake_nau8825_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - .name = "dmic01", - .id = 2, - .ignore_suspend = 1, - .be_hw_params_fixup = skylake_dmic_fixup, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic01_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .dpcm_playback = 1, - .init = skylake_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = skylake_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = skylake_hdmi3_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -#define NAME_SIZE 32 -static int skylake_card_late_probe(struct snd_soc_card *card) -{ - struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(card); - struct skl_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - 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, - &skylake_hdmi[i], - NULL, 0); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &skylake_hdmi[i]); - if (err < 0) - return err; - - i++; - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* skylake audio machine driver for SPT + NAU88L25 */ -static struct snd_soc_card skylake_audio_card = { - .name = "sklnau8825adi", - .owner = THIS_MODULE, - .dai_link = skylake_dais, - .num_links = ARRAY_SIZE(skylake_dais), - .controls = skylake_controls, - .num_controls = ARRAY_SIZE(skylake_controls), - .dapm_widgets = skylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(skylake_widgets), - .dapm_routes = skylake_map, - .num_dapm_routes = ARRAY_SIZE(skylake_map), - .codec_conf = ssm4567_codec_conf, - .num_configs = ARRAY_SIZE(ssm4567_codec_conf), - .fully_routed = true, - .disable_route_checks = true, - .late_probe = skylake_card_late_probe, -}; - -static int skylake_audio_probe(struct platform_device *pdev) -{ - struct skl_nau88125_private *ctx; - struct snd_soc_acpi_mach *mach; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - skylake_audio_card.dev = &pdev->dev; - snd_soc_card_set_drvdata(&skylake_audio_card, ctx); - - mach = pdev->dev.platform_data; - if (mach) - dmic_constraints = mach->mach_params.dmic_num == 2 ? - &constraints_dmic_2ch : &constraints_dmic_channels; - - return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); -} - -static const struct platform_device_id skl_board_ids[] = { - { .name = "skl_n88l25_s4567" }, - { .name = "kbl_n88l25_s4567" }, - { } -}; - -static struct platform_driver skylake_audio = { - .probe = skylake_audio_probe, - .driver = { - .name = "skl_n88l25_s4567", - .pm = &snd_soc_pm_ops, - }, - .id_table = skl_board_ids, -}; - -module_platform_driver(skylake_audio) - -/* Module information */ -MODULE_AUTHOR("Conrad Cooke <conrad.cooke@intel.com>"); -MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>"); -MODULE_AUTHOR("Naveen M <naveen.m@intel.com>"); -MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>"); -MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>"); -MODULE_DESCRIPTION("Intel Audio Machine driver for SKL with NAU88L25 and SSM4567 in I2S Mode"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:skl_n88l25_s4567"); -MODULE_ALIAS("platform:kbl_n88l25_s4567"); diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c deleted file mode 100644 index 5a0c64a83146..000000000000 --- a/sound/soc/intel/boards/skl_rt286.c +++ /dev/null @@ -1,569 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Skylake I2S Machine Driver - * - * Copyright (C) 2014-2015, Intel Corporation. All rights reserved. - * - * Modified from: - * Intel Broadwell Wildcatpoint SST Audio - * - * Copyright (C) 2013, Intel Corporation. All rights reserved. - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/jack.h> -#include <sound/pcm_params.h> -#include "../../codecs/rt286.h" -#include "../../codecs/hdac_hdmi.h" - -static struct snd_soc_jack skylake_headset; -static struct snd_soc_jack skylake_hdmi[3]; - -struct skl_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct skl_rt286_private { - struct list_head hdmi_pcm_list; -}; - -enum { - SKL_DPCM_AUDIO_PB = 0, - SKL_DPCM_AUDIO_DB_PB, - SKL_DPCM_AUDIO_CP, - SKL_DPCM_AUDIO_REF_CP, - SKL_DPCM_AUDIO_DMIC_CP, - SKL_DPCM_AUDIO_HDMI1_PB, - SKL_DPCM_AUDIO_HDMI2_PB, - SKL_DPCM_AUDIO_HDMI3_PB, -}; - -/* Headset jack detection DAPM pins */ -static struct snd_soc_jack_pin skylake_headset_pins[] = { - { - .pin = "Mic Jack", - .mask = SND_JACK_MICROPHONE, - }, - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, -}; - -static const struct snd_kcontrol_new skylake_controls[] = { - SOC_DAPM_PIN_SWITCH("Speaker"), - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Mic Jack"), -}; - -static const struct snd_soc_dapm_widget skylake_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_SPK("Speaker", NULL), - SND_SOC_DAPM_MIC("Mic Jack", NULL), - SND_SOC_DAPM_MIC("DMIC2", 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), -}; - -static const struct snd_soc_dapm_route skylake_rt286_map[] = { - /* speaker */ - {"Speaker", NULL, "SPOR"}, - {"Speaker", NULL, "SPOL"}, - - /* HP jack connectors - unknown if we have jack deteck */ - {"Headphone Jack", NULL, "HPO Pin"}, - - /* other jacks */ - {"MIC1", NULL, "Mic Jack"}, - - /* digital mics */ - {"DMIC1 Pin", NULL, "DMIC2"}, - {"DMic", NULL, "SoC DMIC"}, - - /* CODEC BE connections */ - { "AIF1 Playback", NULL, "ssp0 Tx"}, - { "ssp0 Tx", NULL, "codec0_out"}, - { "ssp0 Tx", NULL, "codec1_out"}, - - { "codec0_in", NULL, "ssp0 Rx" }, - { "codec1_in", NULL, "ssp0 Rx" }, - { "ssp0 Rx", NULL, "AIF1 Capture" }, - - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "DMIC AIF" }, - - { "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"}, - -}; - -static int skylake_rt286_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = asoc_rtd_to_cpu(rtd, 0)->component; - - dapm = snd_soc_component_get_dapm(component); - snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - - return 0; -} - -static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; - int ret; - - ret = snd_soc_card_jack_new(rtd->card, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0, - &skylake_headset, - skylake_headset_pins, ARRAY_SIZE(skylake_headset_pins)); - - if (ret) - return ret; - - rt286_mic_detect(component, &skylake_headset); - - snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - - return 0; -} - -static int skylake_hdmi_init(struct snd_soc_pcm_runtime *rtd) -{ - struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); - struct skl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = SKL_DPCM_AUDIO_HDMI1_PB + dai->id; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static const unsigned int channels[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static int skl_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * on this platform for PCM device we support, - * 48Khz - * stereo - * 16 bit audio - */ - - runtime->hw.channels_max = 2; - 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 skylake_rt286_fe_ops = { - .startup = skl_fe_startup, -}; - -static int skylake_ssp0_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); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - - /* The output is 48KHz, stereo, 16bits */ - rate->min = rate->max = 48000; - chan->min = chan->max = 2; - - /* set SSP0 to 24 bit */ - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - return 0; -} - -static int skylake_rt286_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - int ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000, - SND_SOC_CLOCK_IN); - if (ret < 0) - dev_err(rtd->dev, "set codec sysclk failed: %d\n", ret); - - return ret; -} - -static const struct snd_soc_ops skylake_rt286_ops = { - .hw_params = skylake_rt286_hw_params, -}; - -static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - if (params_channels(params) == 2) - chan->min = chan->max = 2; - else - chan->min = chan->max = 4; - - return 0; -} - -static const unsigned int channels_dmic[] = { - 2, 4, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { - .count = ARRAY_SIZE(channels_dmic), - .list = channels_dmic, - .mask = 0, -}; - -static int skylake_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_max = 4; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_dmic_channels); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static const struct snd_soc_ops skylake_dmic_ops = { - .startup = skylake_dmic_startup, -}; - -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(deepbuffer, - DAILINK_COMP_ARRAY(COMP_CPU("Deepbuffer Pin"))); - -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"))); - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT343A:00", "rt286-aif1"))); - -SND_SOC_DAILINK_DEF(dmic01_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); -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:1f.3"))); - -/* skylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link skylake_rt286_dais[] = { - /* Front End DAI links */ - [SKL_DPCM_AUDIO_PB] = { - .name = "Skl Audio Port", - .stream_name = "Audio", - .nonatomic = 1, - .dynamic = 1, - .init = skylake_rt286_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST - }, - .dpcm_playback = 1, - .ops = &skylake_rt286_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [SKL_DPCM_AUDIO_DB_PB] = { - .name = "Skl Deepbuffer Port", - .stream_name = "Deep Buffer Audio", - .nonatomic = 1, - .dynamic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST - }, - .dpcm_playback = 1, - .ops = &skylake_rt286_fe_ops, - SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), - }, - [SKL_DPCM_AUDIO_CP] = { - .name = "Skl Audio Capture Port", - .stream_name = "Audio Record", - .nonatomic = 1, - .dynamic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST - }, - .dpcm_capture = 1, - .ops = &skylake_rt286_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [SKL_DPCM_AUDIO_REF_CP] = { - .name = "Skl Audio Reference cap", - .stream_name = "refcap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [SKL_DPCM_AUDIO_DMIC_CP] = { - .name = "Skl Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Skl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Skl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI3_PB] = { - .name = "Skl HDMI Port3", - .stream_name = "Hdmi3", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .init = skylake_rt286_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 = skylake_ssp0_fixup, - .ops = &skylake_rt286_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - .name = "dmic01", - .id = 1, - .be_hw_params_fixup = skylake_dmic_fixup, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic01_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 2, - .init = skylake_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 3, - .init = skylake_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 4, - .init = skylake_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -#define NAME_SIZE 32 -static int skylake_card_late_probe(struct snd_soc_card *card) -{ - struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(card); - struct skl_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - 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, &skylake_hdmi[i], - NULL, 0); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &skylake_hdmi[i]); - if (err < 0) - return err; - - i++; - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* skylake audio machine driver for SPT + RT286S */ -static struct snd_soc_card skylake_rt286 = { - .name = "skylake-rt286", - .owner = THIS_MODULE, - .dai_link = skylake_rt286_dais, - .num_links = ARRAY_SIZE(skylake_rt286_dais), - .controls = skylake_controls, - .num_controls = ARRAY_SIZE(skylake_controls), - .dapm_widgets = skylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(skylake_widgets), - .dapm_routes = skylake_rt286_map, - .num_dapm_routes = ARRAY_SIZE(skylake_rt286_map), - .fully_routed = true, - .late_probe = skylake_card_late_probe, -}; - -static int skylake_audio_probe(struct platform_device *pdev) -{ - struct skl_rt286_private *ctx; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - skylake_rt286.dev = &pdev->dev; - snd_soc_card_set_drvdata(&skylake_rt286, ctx); - - return devm_snd_soc_register_card(&pdev->dev, &skylake_rt286); -} - -static const struct platform_device_id skl_board_ids[] = { - { .name = "skl_alc286s_i2s" }, - { .name = "kbl_alc286s_i2s" }, - { } -}; - -static struct platform_driver skylake_audio = { - .probe = skylake_audio_probe, - .driver = { - .name = "skl_alc286s_i2s", - .pm = &snd_soc_pm_ops, - }, - .id_table = skl_board_ids, - -}; - -module_platform_driver(skylake_audio) - -/* Module information */ -MODULE_AUTHOR("Omair Mohammed Abdullah <omair.m.abdullah@intel.com>"); -MODULE_DESCRIPTION("Intel SST Audio for Skylake"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:skl_alc286s_i2s"); -MODULE_ALIAS("platform:kbl_alc286s_i2s"); diff --git a/sound/soc/intel/boards/sof_board_helpers.c b/sound/soc/intel/boards/sof_board_helpers.c new file mode 100644 index 000000000000..2ea1dda446ec --- /dev/null +++ b/sound/soc/intel/boards/sof_board_helpers.c @@ -0,0 +1,783 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2023 Intel Corporation + +#include <sound/soc.h> +#include "../common/soc-intel-quirks.h" +#include "hda_dsp_common.h" +#include "sof_board_helpers.h" + +/* + * Intel HDMI DAI Link + */ +static int hdmi_init(struct snd_soc_pcm_runtime *rtd) +{ + struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); + + ctx->hdmi.hdmi_comp = dai->component; + + return 0; +} + +int sof_intel_board_card_late_probe(struct snd_soc_card *card) +{ + struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); + + if (!ctx->hdmi_num) + return 0; + + if (!ctx->hdmi.idisp_codec) + return 0; + + if (!ctx->hdmi.hdmi_comp) + return -EINVAL; + + return hda_dsp_hdmi_build_controls(card, ctx->hdmi.hdmi_comp); +} +EXPORT_SYMBOL_NS(sof_intel_board_card_late_probe, "SND_SOC_INTEL_SOF_BOARD_HELPERS"); + +/* + * DMIC DAI Link + */ +static const struct snd_soc_dapm_widget dmic_widgets[] = { + SND_SOC_DAPM_MIC("SoC DMIC", NULL), +}; + +static const struct snd_soc_dapm_route dmic_routes[] = { + {"DMic", NULL, "SoC DMIC"}, +}; + +static int dmic_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets, + ARRAY_SIZE(dmic_widgets)); + if (ret) { + dev_err(rtd->dev, "fail to add dmic widgets, ret %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, dmic_routes, + ARRAY_SIZE(dmic_routes)); + if (ret) { + dev_err(rtd->dev, "fail to add dmic routes, ret %d\n", ret); + return ret; + } + + return 0; +} + +/* + * HDA External Codec DAI Link + */ +static const struct snd_soc_dapm_widget hda_widgets[] = { + SND_SOC_DAPM_MIC("Analog In", NULL), + SND_SOC_DAPM_MIC("Digital In", NULL), + SND_SOC_DAPM_MIC("Alt Analog In", NULL), + + SND_SOC_DAPM_HP("Analog Out", NULL), + SND_SOC_DAPM_SPK("Digital Out", NULL), + SND_SOC_DAPM_HP("Alt Analog Out", NULL), +}; + +static const struct snd_soc_dapm_route hda_routes[] = { + { "Codec Input Pin1", NULL, "Analog In" }, + { "Codec Input Pin2", NULL, "Digital In" }, + { "Codec Input Pin3", NULL, "Alt Analog In" }, + + { "Analog Out", NULL, "Codec Output Pin1" }, + { "Digital Out", NULL, "Codec Output Pin2" }, + { "Alt Analog Out", NULL, "Codec Output Pin3" }, + + /* CODEC BE connections */ + { "codec0_in", NULL, "Analog CPU Capture" }, + { "Analog CPU Capture", NULL, "Analog Codec Capture" }, + { "codec1_in", NULL, "Digital CPU Capture" }, + { "Digital CPU Capture", NULL, "Digital Codec Capture" }, + { "codec2_in", NULL, "Alt Analog CPU Capture" }, + { "Alt Analog CPU Capture", NULL, "Alt Analog Codec Capture" }, + + { "Analog Codec Playback", NULL, "Analog CPU Playback" }, + { "Analog CPU Playback", NULL, "codec0_out" }, + { "Digital Codec Playback", NULL, "Digital CPU Playback" }, + { "Digital CPU Playback", NULL, "codec1_out" }, + { "Alt Analog Codec Playback", NULL, "Alt Analog CPU Playback" }, + { "Alt Analog CPU Playback", NULL, "codec2_out" }, +}; + +static int hda_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_dapm_new_controls(&card->dapm, hda_widgets, + ARRAY_SIZE(hda_widgets)); + if (ret) { + dev_err(rtd->dev, "fail to add hda widgets, ret %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, hda_routes, + ARRAY_SIZE(hda_routes)); + if (ret) + dev_err(rtd->dev, "fail to add hda routes, ret %d\n", ret); + + return ret; +} + +/* + * DAI Link Helpers + */ + +enum sof_dmic_be_type { + SOF_DMIC_01, + SOF_DMIC_16K, +}; + +enum sof_hda_be_type { + SOF_HDA_ANALOG, + SOF_HDA_DIGITAL, +}; + +/* DEFAULT_LINK_ORDER: the order used in sof_rt5682 */ +#define DEFAULT_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_CODEC, \ + SOF_LINK_DMIC01, \ + SOF_LINK_DMIC16K, \ + SOF_LINK_IDISP_HDMI, \ + SOF_LINK_AMP, \ + SOF_LINK_BT_OFFLOAD, \ + SOF_LINK_HDMI_IN) + +static struct snd_soc_dai_link_component dmic_component[] = { + { + .name = "dmic-codec", + .dai_name = "dmic-hifi", + } +}; + +SND_SOC_DAILINK_DEF(hda_analog_cpus, + DAILINK_COMP_ARRAY(COMP_CPU("Analog CPU DAI"))); +SND_SOC_DAILINK_DEF(hda_analog_codecs, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D0", "Analog Codec DAI"))); + +SND_SOC_DAILINK_DEF(hda_digital_cpus, + DAILINK_COMP_ARRAY(COMP_CPU("Digital CPU DAI"))); +SND_SOC_DAILINK_DEF(hda_digital_codecs, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D0", "Digital Codec DAI"))); + +static struct snd_soc_dai_link_component platform_component[] = { + { + /* name might be overridden during probe */ + .name = "0000:00:1f.3" + } +}; + +static int set_ssp_codec_link(struct device *dev, struct snd_soc_dai_link *link, + int be_id, enum snd_soc_acpi_intel_codec codec_type, + int ssp_codec) +{ + struct snd_soc_dai_link_component *cpus; + + dev_dbg(dev, "link %d: ssp codec %s, ssp %d\n", be_id, + snd_soc_acpi_intel_get_codec_name(codec_type), ssp_codec); + + /* link name */ + link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_codec); + if (!link->name) + return -ENOMEM; + + /* cpus */ + cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); + if (!cpus) + return -ENOMEM; + + if (soc_intel_is_byt() || soc_intel_is_cht()) { + /* backward-compatibility for BYT/CHT boards */ + cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "ssp%d-port", + ssp_codec); + } else { + cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", + ssp_codec); + } + if (!cpus->dai_name) + return -ENOMEM; + + link->cpus = cpus; + link->num_cpus = 1; + + /* codecs - caller to handle */ + + /* platforms */ + link->platforms = platform_component; + link->num_platforms = ARRAY_SIZE(platform_component); + + link->id = be_id; + link->no_pcm = 1; + + return 0; +} + +static int set_dmic_link(struct device *dev, struct snd_soc_dai_link *link, + int be_id, enum sof_dmic_be_type be_type) +{ + struct snd_soc_dai_link_component *cpus; + + /* cpus */ + cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); + if (!cpus) + return -ENOMEM; + + switch (be_type) { + case SOF_DMIC_01: + dev_dbg(dev, "link %d: dmic01\n", be_id); + + link->name = "dmic01"; + cpus->dai_name = "DMIC01 Pin"; + break; + case SOF_DMIC_16K: + dev_dbg(dev, "link %d: dmic16k\n", be_id); + + link->name = "dmic16k"; + cpus->dai_name = "DMIC16k Pin"; + break; + default: + dev_err(dev, "invalid be type %d\n", be_type); + return -EINVAL; + } + + link->cpus = cpus; + link->num_cpus = 1; + + /* codecs */ + link->codecs = dmic_component; + link->num_codecs = ARRAY_SIZE(dmic_component); + + /* platforms */ + link->platforms = platform_component; + link->num_platforms = ARRAY_SIZE(platform_component); + + link->id = be_id; + if (be_type == SOF_DMIC_01) + link->init = dmic_init; + link->ignore_suspend = 1; + link->no_pcm = 1; + link->capture_only = 1; + + return 0; +} + +static int set_idisp_hdmi_link(struct device *dev, struct snd_soc_dai_link *link, + int be_id, int hdmi_id, bool idisp_codec) +{ + struct snd_soc_dai_link_component *cpus, *codecs; + + dev_dbg(dev, "link %d: idisp hdmi %d, idisp codec %d\n", be_id, hdmi_id, + idisp_codec); + + /* link name */ + link->name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", hdmi_id); + if (!link->name) + return -ENOMEM; + + /* cpus */ + cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); + if (!cpus) + return -ENOMEM; + + cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", hdmi_id); + if (!cpus->dai_name) + return -ENOMEM; + + link->cpus = cpus; + link->num_cpus = 1; + + /* codecs */ + if (idisp_codec) { + codecs = devm_kzalloc(dev, + sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); + if (!codecs) + return -ENOMEM; + + codecs->name = "ehdaudio0D2"; + codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "intel-hdmi-hifi%d", hdmi_id); + if (!codecs->dai_name) + return -ENOMEM; + + link->codecs = codecs; + } else { + link->codecs = &snd_soc_dummy_dlc; + } + link->num_codecs = 1; + + /* platforms */ + link->platforms = platform_component; + link->num_platforms = ARRAY_SIZE(platform_component); + + link->id = be_id; + link->init = (hdmi_id == 1) ? hdmi_init : NULL; + link->no_pcm = 1; + link->playback_only = 1; + + return 0; +} + +static int set_ssp_amp_link(struct device *dev, struct snd_soc_dai_link *link, + int be_id, enum snd_soc_acpi_intel_codec amp_type, + int ssp_amp) +{ + struct snd_soc_dai_link_component *cpus; + + dev_dbg(dev, "link %d: ssp amp %s, ssp %d\n", be_id, + snd_soc_acpi_intel_get_codec_name(amp_type), ssp_amp); + + /* link name */ + link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_amp); + if (!link->name) + return -ENOMEM; + + /* cpus */ + cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); + if (!cpus) + return -ENOMEM; + + cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_amp); + if (!cpus->dai_name) + return -ENOMEM; + + link->cpus = cpus; + link->num_cpus = 1; + + /* codecs - caller to handle */ + + /* platforms */ + /* feedback stream or firmware-generated echo reference */ + link->platforms = platform_component; + link->num_platforms = ARRAY_SIZE(platform_component); + + link->id = be_id; + link->no_pcm = 1; + + return 0; +} + +static int set_bt_offload_link(struct device *dev, struct snd_soc_dai_link *link, + int be_id, int ssp_bt) +{ + struct snd_soc_dai_link_component *cpus; + + dev_dbg(dev, "link %d: bt offload, ssp %d\n", be_id, ssp_bt); + + /* link name */ + link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", ssp_bt); + if (!link->name) + return -ENOMEM; + + /* cpus */ + cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); + if (!cpus) + return -ENOMEM; + + cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_bt); + if (!cpus->dai_name) + return -ENOMEM; + + link->cpus = cpus; + link->num_cpus = 1; + + /* codecs */ + link->codecs = &snd_soc_dummy_dlc; + link->num_codecs = 1; + + /* platforms */ + link->platforms = platform_component; + link->num_platforms = ARRAY_SIZE(platform_component); + + link->id = be_id; + link->no_pcm = 1; + + return 0; +} + +static int set_hdmi_in_link(struct device *dev, struct snd_soc_dai_link *link, + int be_id, int ssp_hdmi) +{ + struct snd_soc_dai_link_component *cpus; + + dev_dbg(dev, "link %d: hdmi-in, ssp %d\n", be_id, ssp_hdmi); + + /* link name */ + link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", ssp_hdmi); + if (!link->name) + return -ENOMEM; + + /* cpus */ + cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); + if (!cpus) + return -ENOMEM; + + cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_hdmi); + if (!cpus->dai_name) + return -ENOMEM; + + link->cpus = cpus; + link->num_cpus = 1; + + /* codecs */ + link->codecs = &snd_soc_dummy_dlc; + link->num_codecs = 1; + + /* platforms */ + link->platforms = platform_component; + link->num_platforms = ARRAY_SIZE(platform_component); + + link->id = be_id; + link->no_pcm = 1; + link->capture_only = 1; + + return 0; +} + +static int set_hda_codec_link(struct device *dev, struct snd_soc_dai_link *link, + int be_id, enum sof_hda_be_type be_type) +{ + switch (be_type) { + case SOF_HDA_ANALOG: + dev_dbg(dev, "link %d: hda analog\n", be_id); + + link->name = "Analog Playback and Capture"; + + /* cpus */ + link->cpus = hda_analog_cpus; + link->num_cpus = ARRAY_SIZE(hda_analog_cpus); + + /* codecs */ + link->codecs = hda_analog_codecs; + link->num_codecs = ARRAY_SIZE(hda_analog_codecs); + break; + case SOF_HDA_DIGITAL: + dev_dbg(dev, "link %d: hda digital\n", be_id); + + link->name = "Digital Playback and Capture"; + + /* cpus */ + link->cpus = hda_digital_cpus; + link->num_cpus = ARRAY_SIZE(hda_digital_cpus); + + /* codecs */ + link->codecs = hda_digital_codecs; + link->num_codecs = ARRAY_SIZE(hda_digital_codecs); + break; + default: + dev_err(dev, "invalid be type %d\n", be_type); + return -EINVAL; + } + + /* platforms */ + link->platforms = platform_component; + link->num_platforms = ARRAY_SIZE(platform_component); + + link->id = be_id; + if (be_type == SOF_HDA_ANALOG) + link->init = hda_init; + link->no_pcm = 1; + + return 0; +} + +static int calculate_num_links(struct sof_card_private *ctx) +{ + int num_links = 0; + + /* headphone codec */ + if (ctx->codec_type != CODEC_NONE) + num_links++; + + /* dmic01 and dmic16k */ + if (ctx->dmic_be_num > 0) + num_links++; + + if (ctx->dmic_be_num > 1) + num_links++; + + /* idisp HDMI */ + num_links += ctx->hdmi_num; + + /* speaker amp */ + if (ctx->amp_type != CODEC_NONE) + num_links++; + + /* BT audio offload */ + if (ctx->bt_offload_present) + num_links++; + + /* HDMI-In */ + num_links += hweight32(ctx->ssp_mask_hdmi_in); + + /* HDA external codec */ + if (ctx->hda_codec_present) + num_links += 2; + + return num_links; +} + +int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, + struct sof_card_private *ctx) +{ + struct snd_soc_dai_link *links; + int num_links; + int i; + int idx = 0; + int ret; + int ssp_hdmi_in = 0; + unsigned long link_order, link; + unsigned long link_ids, be_id; + + num_links = calculate_num_links(ctx); + + links = devm_kcalloc(dev, num_links, sizeof(struct snd_soc_dai_link), + GFP_KERNEL); + if (!links) + return -ENOMEM; + + if (ctx->link_order_overwrite) + link_order = ctx->link_order_overwrite; + else + link_order = DEFAULT_LINK_ORDER; + + if (ctx->link_id_overwrite) + link_ids = ctx->link_id_overwrite; + else + link_ids = 0; + + dev_dbg(dev, "create dai links, link_order 0x%lx, id_overwrite 0x%lx\n", + link_order, link_ids); + + while (link_order) { + link = link_order & SOF_LINK_ORDER_MASK; + link_order >>= SOF_LINK_ORDER_SHIFT; + + if (ctx->link_id_overwrite) { + be_id = link_ids & SOF_LINK_IDS_MASK; + link_ids >>= SOF_LINK_IDS_SHIFT; + } else { + /* use array index as link id */ + be_id = idx; + } + + switch (link) { + case SOF_LINK_CODEC: + /* headphone codec */ + if (ctx->codec_type == CODEC_NONE) + continue; + + ret = set_ssp_codec_link(dev, &links[idx], be_id, + ctx->codec_type, ctx->ssp_codec); + if (ret) { + dev_err(dev, "fail to set codec link, ret %d\n", + ret); + return ret; + } + + ctx->codec_link = &links[idx]; + idx++; + break; + case SOF_LINK_DMIC01: + /* dmic01 */ + if (ctx->dmic_be_num == 0) + continue; + + /* at least we have dmic01 */ + ret = set_dmic_link(dev, &links[idx], be_id, SOF_DMIC_01); + if (ret) { + dev_err(dev, "fail to set dmic01 link, ret %d\n", + ret); + return ret; + } + + idx++; + break; + case SOF_LINK_DMIC16K: + /* dmic16k */ + if (ctx->dmic_be_num <= 1) + continue; + + /* set up 2 BE links at most */ + ret = set_dmic_link(dev, &links[idx], be_id, + SOF_DMIC_16K); + if (ret) { + dev_err(dev, "fail to set dmic16k link, ret %d\n", + ret); + return ret; + } + + idx++; + break; + case SOF_LINK_IDISP_HDMI: + /* idisp HDMI */ + for (i = 1; i <= ctx->hdmi_num; i++) { + ret = set_idisp_hdmi_link(dev, &links[idx], + be_id, i, + ctx->hdmi.idisp_codec); + if (ret) { + dev_err(dev, "fail to set hdmi link, ret %d\n", + ret); + return ret; + } + + idx++; + be_id++; + } + break; + case SOF_LINK_AMP: + /* speaker amp */ + if (ctx->amp_type == CODEC_NONE) + continue; + + ret = set_ssp_amp_link(dev, &links[idx], be_id, + ctx->amp_type, ctx->ssp_amp); + if (ret) { + dev_err(dev, "fail to set amp link, ret %d\n", + ret); + return ret; + } + + ctx->amp_link = &links[idx]; + idx++; + break; + case SOF_LINK_BT_OFFLOAD: + /* BT audio offload */ + if (!ctx->bt_offload_present) + continue; + + ret = set_bt_offload_link(dev, &links[idx], be_id, + ctx->ssp_bt); + if (ret) { + dev_err(dev, "fail to set bt link, ret %d\n", + ret); + return ret; + } + + idx++; + break; + case SOF_LINK_HDMI_IN: + /* HDMI-In */ + for_each_set_bit(ssp_hdmi_in, &ctx->ssp_mask_hdmi_in, 32) { + ret = set_hdmi_in_link(dev, &links[idx], be_id, + ssp_hdmi_in); + if (ret) { + dev_err(dev, "fail to set hdmi-in link, ret %d\n", + ret); + return ret; + } + + idx++; + be_id++; + } + break; + case SOF_LINK_HDA: + /* HDA external codec */ + if (!ctx->hda_codec_present) + continue; + + ret = set_hda_codec_link(dev, &links[idx], be_id, + SOF_HDA_ANALOG); + if (ret) { + dev_err(dev, "fail to set hda analog link, ret %d\n", + ret); + return ret; + } + + idx++; + be_id++; + + ret = set_hda_codec_link(dev, &links[idx], be_id, + SOF_HDA_DIGITAL); + if (ret) { + dev_err(dev, "fail to set hda digital link, ret %d\n", + ret); + return ret; + } + + idx++; + break; + case SOF_LINK_NONE: + /* caught here if it's not used as terminator in macro */ + fallthrough; + default: + dev_err(dev, "invalid link type %ld\n", link); + return -EINVAL; + } + } + + if (idx != num_links) { + dev_err(dev, "link number mismatch, idx %d, num_links %d\n", idx, + num_links); + return -EINVAL; + } + + card->dai_link = links; + card->num_links = num_links; + + return 0; +} +EXPORT_SYMBOL_NS(sof_intel_board_set_dai_link, "SND_SOC_INTEL_SOF_BOARD_HELPERS"); + +struct sof_card_private * +sof_intel_board_get_ctx(struct device *dev, unsigned long board_quirk) +{ + struct sof_card_private *ctx; + + dev_dbg(dev, "create ctx, board_quirk 0x%lx\n", board_quirk); + + ctx = devm_kzalloc(dev, sizeof(struct sof_card_private), GFP_KERNEL); + if (!ctx) + return NULL; + + ctx->codec_type = snd_soc_acpi_intel_detect_codec_type(dev); + ctx->amp_type = snd_soc_acpi_intel_detect_amp_type(dev); + + ctx->dmic_be_num = 2; + ctx->hdmi_num = (board_quirk & SOF_NUM_IDISP_HDMI_MASK) >> + SOF_NUM_IDISP_HDMI_SHIFT; + /* default number of HDMI DAI's */ + if (!ctx->hdmi_num) + ctx->hdmi_num = 3; + + /* port number/mask of peripherals attached to ssp interface */ + if (ctx->codec_type != CODEC_NONE) + ctx->ssp_codec = (board_quirk & SOF_SSP_PORT_CODEC_MASK) >> + SOF_SSP_PORT_CODEC_SHIFT; + + if (ctx->amp_type != CODEC_NONE) + ctx->ssp_amp = (board_quirk & SOF_SSP_PORT_AMP_MASK) >> + SOF_SSP_PORT_AMP_SHIFT; + + if (board_quirk & SOF_BT_OFFLOAD_PRESENT) { + ctx->bt_offload_present = true; + ctx->ssp_bt = (board_quirk & SOF_SSP_PORT_BT_OFFLOAD_MASK) >> + SOF_SSP_PORT_BT_OFFLOAD_SHIFT; + } + + ctx->ssp_mask_hdmi_in = (board_quirk & SOF_SSP_MASK_HDMI_CAPTURE_MASK) >> + SOF_SSP_MASK_HDMI_CAPTURE_SHIFT; + + return ctx; +} +EXPORT_SYMBOL_NS(sof_intel_board_get_ctx, "SND_SOC_INTEL_SOF_BOARD_HELPERS"); + +MODULE_DESCRIPTION("ASoC Intel SOF Machine Driver Board Helpers"); +MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON"); +MODULE_IMPORT_NS("SND_SOC_ACPI_INTEL_MATCH"); diff --git a/sound/soc/intel/boards/sof_board_helpers.h b/sound/soc/intel/boards/sof_board_helpers.h new file mode 100644 index 000000000000..33a9601b770c --- /dev/null +++ b/sound/soc/intel/boards/sof_board_helpers.h @@ -0,0 +1,173 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright(c) 2023 Intel Corporation. + */ + +#ifndef __SOF_INTEL_BOARD_HELPERS_H +#define __SOF_INTEL_BOARD_HELPERS_H + +#include <sound/soc.h> +#include <sound/soc-acpi-intel-ssp-common.h> +#include "sof_hdmi_common.h" + +/* + * Common board quirks: from bit 8 to 31, LSB 8 bits reserved for machine + * drivers + */ + +/* SSP port number for headphone codec: 3 bits */ +#define SOF_SSP_PORT_CODEC_SHIFT 8 +#define SOF_SSP_PORT_CODEC_MASK (GENMASK(10, 8)) +#define SOF_SSP_PORT_CODEC(quirk) \ + (((quirk) << SOF_SSP_PORT_CODEC_SHIFT) & SOF_SSP_PORT_CODEC_MASK) + +/* SSP port number for speaker amplifier: 3 bits */ +#define SOF_SSP_PORT_AMP_SHIFT 11 +#define SOF_SSP_PORT_AMP_MASK (GENMASK(13, 11)) +#define SOF_SSP_PORT_AMP(quirk) \ + (((quirk) << SOF_SSP_PORT_AMP_SHIFT) & SOF_SSP_PORT_AMP_MASK) + +/* SSP port number for BT audio offload: 3 bits */ +#define SOF_SSP_PORT_BT_OFFLOAD_SHIFT 14 +#define SOF_SSP_PORT_BT_OFFLOAD_MASK (GENMASK(16, 14)) +#define SOF_SSP_PORT_BT_OFFLOAD(quirk) \ + (((quirk) << SOF_SSP_PORT_BT_OFFLOAD_SHIFT) & SOF_SSP_PORT_BT_OFFLOAD_MASK) + +/* SSP port mask for HDMI capture: 6 bits */ +#define SOF_SSP_MASK_HDMI_CAPTURE_SHIFT 17 +#define SOF_SSP_MASK_HDMI_CAPTURE_MASK (GENMASK(22, 17)) +#define SOF_SSP_MASK_HDMI_CAPTURE(quirk) \ + (((quirk) << SOF_SSP_MASK_HDMI_CAPTURE_SHIFT) & SOF_SSP_MASK_HDMI_CAPTURE_MASK) + +/* Number of idisp HDMI BE link: 3 bits */ +#define SOF_NUM_IDISP_HDMI_SHIFT 23 +#define SOF_NUM_IDISP_HDMI_MASK (GENMASK(25, 23)) +#define SOF_NUM_IDISP_HDMI(quirk) \ + (((quirk) << SOF_NUM_IDISP_HDMI_SHIFT) & SOF_NUM_IDISP_HDMI_MASK) + +/* Board uses BT audio offload */ +#define SOF_BT_OFFLOAD_PRESENT BIT(26) + +enum { + SOF_LINK_NONE = 0, + SOF_LINK_CODEC, + SOF_LINK_DMIC01, + SOF_LINK_DMIC16K, + SOF_LINK_IDISP_HDMI, + SOF_LINK_AMP, + SOF_LINK_BT_OFFLOAD, + SOF_LINK_HDMI_IN, + SOF_LINK_HDA, +}; + +#define SOF_LINK_ORDER_MASK (0xF) +#define SOF_LINK_ORDER_SHIFT (4) + +#define SOF_LINK_ORDER(k1, k2, k3, k4, k5, k6, k7) \ + ((((k1) & SOF_LINK_ORDER_MASK) << (SOF_LINK_ORDER_SHIFT * 0)) | \ + (((k2) & SOF_LINK_ORDER_MASK) << (SOF_LINK_ORDER_SHIFT * 1)) | \ + (((k3) & SOF_LINK_ORDER_MASK) << (SOF_LINK_ORDER_SHIFT * 2)) | \ + (((k4) & SOF_LINK_ORDER_MASK) << (SOF_LINK_ORDER_SHIFT * 3)) | \ + (((k5) & SOF_LINK_ORDER_MASK) << (SOF_LINK_ORDER_SHIFT * 4)) | \ + (((k6) & SOF_LINK_ORDER_MASK) << (SOF_LINK_ORDER_SHIFT * 5)) | \ + (((k7) & SOF_LINK_ORDER_MASK) << (SOF_LINK_ORDER_SHIFT * 6))) + +#define SOF_LINK_IDS_MASK (0xF) +#define SOF_LINK_IDS_SHIFT (4) + +#define SOF_LINK_IDS(k1, k2, k3, k4, k5, k6, k7) \ + ((((k1) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 0)) | \ + (((k2) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 1)) | \ + (((k3) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 2)) | \ + (((k4) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 3)) | \ + (((k5) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 4)) | \ + (((k6) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 5)) | \ + (((k7) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 6))) + +/* + * sof_da7219_private: private data for da7219 machine driver + * + * @mclk_en: true for mclk pin is connected + * @pll_bypass: true for PLL bypass mode + */ +struct sof_da7219_private { + bool mclk_en; + bool pll_bypass; +}; + +/* + * sof_rt5682_private: private data for rt5682 machine driver + * + * @mclk: mclk clock data + * @is_legacy_cpu: true for BYT/CHT boards + * @mclk_en: true for mclk pin is connected + */ +struct sof_rt5682_private { + struct clk *mclk; + bool is_legacy_cpu; + bool mclk_en; +}; + +/* + * sof_card_private: common data for machine drivers + * + * @headset_jack: headset jack data + * @hdmi: init data for hdmi dai link + * @codec_type: type of headset codec + * @amp_type: type of speaker amplifier + * @dmic_be_num: number of Intel PCH DMIC BE link + * @hdmi_num: number of Intel HDMI BE link + * @ssp_codec: ssp port number of headphone BE link + * @ssp_amp: ssp port number of speaker BE link + * @ssp_bt: ssp port number of BT offload BE link + * @ssp_mask_hdmi_in: ssp port mask of HDMI-IN BE link + * @bt_offload_present: true to create BT offload BE link + * @hda_codec_present: true to create HDA codec BE links + * @codec_link: pointer to headset codec dai link + * @amp_link: pointer to speaker amplifier dai link + * @link_order_overwrite: custom DAI link order + * @link_id_overwrite: custom DAI link ID + * @da7219: private data for da7219 machine driver + * @rt5682: private data for rt5682 machine driver + */ +struct sof_card_private { + struct snd_soc_jack headset_jack; + struct sof_hdmi_private hdmi; + + enum snd_soc_acpi_intel_codec codec_type; + enum snd_soc_acpi_intel_codec amp_type; + + int dmic_be_num; + int hdmi_num; + + int ssp_codec; + int ssp_amp; + int ssp_bt; + unsigned long ssp_mask_hdmi_in; + + bool bt_offload_present; + bool hda_codec_present; + + struct snd_soc_dai_link *codec_link; + struct snd_soc_dai_link *amp_link; + + unsigned long link_order_overwrite; + /* + * A variable stores id for all BE DAI links, use SOF_LINK_IDS macro to + * build the value; use DAI link array index as id if zero. + */ + unsigned long link_id_overwrite; + + union { + struct sof_da7219_private da7219; + struct sof_rt5682_private rt5682; + }; +}; + +int sof_intel_board_card_late_probe(struct snd_soc_card *card); +int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, + struct sof_card_private *ctx); +struct sof_card_private * +sof_intel_board_get_ctx(struct device *dev, unsigned long board_quirk); + +#endif /* __SOF_INTEL_BOARD_HELPERS_H */ diff --git a/sound/soc/intel/boards/sof_cirrus_common.c b/sound/soc/intel/boards/sof_cirrus_common.c new file mode 100644 index 000000000000..8db7695b9747 --- /dev/null +++ b/sound/soc/intel/boards/sof_cirrus_common.c @@ -0,0 +1,206 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * This file defines data structures and functions used in Machine + * Driver for Intel platforms with Cirrus Logic Codecs. + * + * Copyright 2022 Intel Corporation. + */ +#include <linux/module.h> +#include <sound/sof.h> +#include "../../codecs/cs35l41.h" +#include "sof_cirrus_common.h" + +#define CS35L41_HID "CSC3541" +#define CS35L41_MAX_AMPS 4 + +/* + * Cirrus Logic CS35L41/CS35L53 + */ +static const struct snd_kcontrol_new cs35l41_kcontrols[] = { + SOC_DAPM_PIN_SWITCH("WL Spk"), + SOC_DAPM_PIN_SWITCH("WR Spk"), + SOC_DAPM_PIN_SWITCH("TL Spk"), + SOC_DAPM_PIN_SWITCH("TR Spk"), +}; + +static const struct snd_soc_dapm_widget cs35l41_dapm_widgets[] = { + SND_SOC_DAPM_SPK("WL Spk", NULL), + SND_SOC_DAPM_SPK("WR Spk", NULL), + SND_SOC_DAPM_SPK("TL Spk", NULL), + SND_SOC_DAPM_SPK("TR Spk", NULL), +}; + +static const struct snd_soc_dapm_route cs35l41_dapm_routes[] = { + /* speaker */ + {"WL Spk", NULL, "WL SPK"}, + {"WR Spk", NULL, "WR SPK"}, + {"TL Spk", NULL, "TL SPK"}, + {"TR Spk", NULL, "TR SPK"}, +}; + +static struct snd_soc_dai_link_component cs35l41_components[CS35L41_MAX_AMPS]; + +/* + * Mapping between ACPI instance id and speaker position. + */ +static struct snd_soc_codec_conf cs35l41_codec_conf[CS35L41_MAX_AMPS]; + +static int cs35l41_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_dapm_new_controls(&card->dapm, cs35l41_dapm_widgets, + ARRAY_SIZE(cs35l41_dapm_widgets)); + if (ret) { + dev_err(rtd->dev, "fail to add dapm controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, cs35l41_kcontrols, + ARRAY_SIZE(cs35l41_kcontrols)); + if (ret) { + dev_err(rtd->dev, "fail to add card controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, cs35l41_dapm_routes, + ARRAY_SIZE(cs35l41_dapm_routes)); + + if (ret) + dev_err(rtd->dev, "fail to add dapm routes, ret %d\n", ret); + + return ret; +} + +/* + * Channel map: + * + * TL/WL: ASPRX1 on slot 0, ASPRX2 on slot 1 (default) + * TR/WR: ASPRX1 on slot 1, ASPRX2 on slot 0 + */ +static const struct { + unsigned int rx[2]; +} cs35l41_channel_map[] = { + {.rx = {0, 1}}, /* WL */ + {.rx = {1, 0}}, /* WR */ + {.rx = {0, 1}}, /* TL */ + {.rx = {1, 0}}, /* TR */ +}; + +static int cs35l41_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai; + int clk_freq, i, ret; + + clk_freq = sof_dai_get_bclk(rtd); /* BCLK freq */ + + if (clk_freq <= 0) { + dev_err(rtd->dev, "fail to get bclk freq, ret %d\n", clk_freq); + return -EINVAL; + } + + for_each_rtd_codec_dais(rtd, i, codec_dai) { + /* call dai driver's set_sysclk() callback */ + ret = snd_soc_dai_set_sysclk(codec_dai, CS35L41_CLKID_SCLK, + clk_freq, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec_dai->dev, "fail to set sysclk, ret %d\n", + ret); + return ret; + } + + /* call component driver's set_sysclk() callback */ + ret = snd_soc_component_set_sysclk(codec_dai->component, + CS35L41_CLKID_SCLK, 0, + clk_freq, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec_dai->dev, "fail to set component sysclk, ret %d\n", + ret); + return ret; + } + + /* setup channel map */ + ret = snd_soc_dai_set_channel_map(codec_dai, 0, NULL, + ARRAY_SIZE(cs35l41_channel_map[i].rx), + (unsigned int *)cs35l41_channel_map[i].rx); + if (ret < 0) { + dev_err(codec_dai->dev, "fail to set channel map, ret %d\n", + ret); + return ret; + } + } + + return 0; +} + +static const struct snd_soc_ops cs35l41_ops = { + .hw_params = cs35l41_hw_params, +}; + +static const char * const cs35l41_name_prefixes[] = { "WL", "WR", "TL", "TR" }; + +/* + * Expected UIDs are integers (stored as strings). + * UID Mapping is fixed: + * UID 0x0 -> WL + * UID 0x1 -> WR + * UID 0x2 -> TL + * UID 0x3 -> TR + * Note: If there are less than 4 Amps, UIDs still map to WL/WR/TL/TR. Dynamic code will only create + * dai links for UIDs which exist, and ignore non-existant ones. Only 2 or 4 amps are expected. + * Return number of codecs found. + */ +static int cs35l41_compute_codec_conf(void) +{ + static const char * const uid_strings[] = { "0", "1", "2", "3" }; + unsigned int uid, sz = 0; + struct acpi_device *adev; + struct device *physdev; + + for (uid = 0; uid < CS35L41_MAX_AMPS; uid++) { + adev = acpi_dev_get_first_match_dev(CS35L41_HID, uid_strings[uid], -1); + if (!adev) { + pr_devel("Cannot find match for HID %s UID %u (%s)\n", CS35L41_HID, uid, + cs35l41_name_prefixes[uid]); + continue; + } + physdev = get_device(acpi_get_first_physical_node(adev)); + acpi_dev_put(adev); + if (!physdev) { + pr_devel("Cannot find physical node for HID %s UID %u (%s)\n", CS35L41_HID, + uid, cs35l41_name_prefixes[uid]); + return 0; + } + cs35l41_components[sz].name = dev_name(physdev); + cs35l41_components[sz].dai_name = CS35L41_CODEC_DAI; + cs35l41_codec_conf[sz].dlc.name = dev_name(physdev); + cs35l41_codec_conf[sz].name_prefix = cs35l41_name_prefixes[uid]; + sz++; + } + + if (sz != 2 && sz != 4) + pr_warn("Invalid number of cs35l41 amps found: %d, expected 2 or 4\n", sz); + return sz; +} + +void cs35l41_set_dai_link(struct snd_soc_dai_link *link) +{ + link->num_codecs = cs35l41_compute_codec_conf(); + link->codecs = cs35l41_components; + link->init = cs35l41_init; + link->ops = &cs35l41_ops; +} +EXPORT_SYMBOL_NS(cs35l41_set_dai_link, "SND_SOC_INTEL_SOF_CIRRUS_COMMON"); + +void cs35l41_set_codec_conf(struct snd_soc_card *card) +{ + card->codec_conf = cs35l41_codec_conf; + card->num_configs = ARRAY_SIZE(cs35l41_codec_conf); +} +EXPORT_SYMBOL_NS(cs35l41_set_codec_conf, "SND_SOC_INTEL_SOF_CIRRUS_COMMON"); + +MODULE_DESCRIPTION("ASoC Intel SOF Cirrus Logic helpers"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/boards/sof_cirrus_common.h b/sound/soc/intel/boards/sof_cirrus_common.h new file mode 100644 index 000000000000..1c87637b9ef7 --- /dev/null +++ b/sound/soc/intel/boards/sof_cirrus_common.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * This file defines data structures used in Machine Driver for Intel + * platforms with Cirrus Logic Codecs. + * + * Copyright 2022 Intel Corporation. + */ +#ifndef __SOF_CIRRUS_COMMON_H +#define __SOF_CIRRUS_COMMON_H + +#include <sound/soc.h> +#include <sound/soc-acpi-intel-ssp-common.h> + +/* + * Cirrus Logic CS35L41/CS35L53 + */ +#define CS35L41_CODEC_DAI "cs35l41-pcm" +#define CS35L41_DEV0_NAME "i2c-" CS35L41_ACPI_HID ":00" +#define CS35L41_DEV1_NAME "i2c-" CS35L41_ACPI_HID ":01" +#define CS35L41_DEV2_NAME "i2c-" CS35L41_ACPI_HID ":02" +#define CS35L41_DEV3_NAME "i2c-" CS35L41_ACPI_HID ":03" + +void cs35l41_set_dai_link(struct snd_soc_dai_link *link); +void cs35l41_set_codec_conf(struct snd_soc_card *card); + +#endif /* __SOF_CIRRUS_COMMON_H */ diff --git a/sound/soc/intel/boards/sof_cs42l42.c b/sound/soc/intel/boards/sof_cs42l42.c new file mode 100644 index 000000000000..455c5bc8c634 --- /dev/null +++ b/sound/soc/intel/boards/sof_cs42l42.c @@ -0,0 +1,307 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright(c) 2021 Intel Corporation. + +/* + * Intel SOF Machine Driver with Cirrus Logic CS42L42 Codec + * and speaker codec MAX98357A + */ +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/dmi.h> +#include <sound/core.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/sof.h> +#include <sound/soc-acpi.h> +#include <dt-bindings/sound/cs42l42.h> +#include "../common/soc-intel-quirks.h" +#include "sof_board_helpers.h" +#include "sof_maxim_common.h" + +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +/* Default: SSP2 */ +static unsigned long sof_cs42l42_quirk = SOF_SSP_PORT_CODEC(2); + +static int sof_cs42l42_init(struct snd_soc_pcm_runtime *rtd) +{ + struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; + struct snd_soc_jack *jack = &ctx->headset_jack; + int ret; + + /* + * Headset buttons map to the google Reference headset. + * These can be configured by userspace. + */ + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + jack, + jack_pins, + ARRAY_SIZE(jack_pins)); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); + return ret; + } + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); + + ret = snd_soc_component_set_jack(component, jack, NULL); + if (ret) { + dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); + return ret; + } + + return ret; +}; + +static void sof_cs42l42_exit(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; + + snd_soc_component_set_jack(component, NULL, NULL); +} + +static int sof_cs42l42_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + int clk_freq, ret; + + clk_freq = sof_dai_get_bclk(rtd); /* BCLK freq */ + + if (clk_freq <= 0) { + dev_err(rtd->dev, "get bclk freq failed: %d\n", clk_freq); + return -EINVAL; + } + + /* Configure sysclk for codec */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, + clk_freq, SND_SOC_CLOCK_IN); + if (ret < 0) + dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); + + return ret; +} + +static const struct snd_soc_ops sof_cs42l42_ops = { + .hw_params = sof_cs42l42_hw_params, +}; + +static int sof_card_late_probe(struct snd_soc_card *card) +{ + return sof_intel_board_card_late_probe(card); +} + +static const struct snd_kcontrol_new sof_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const struct snd_soc_dapm_widget sof_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + +static const struct snd_soc_dapm_route sof_map[] = { + /* HP jack connectors - unknown if we have jack detection */ + {"Headphone Jack", NULL, "HP"}, + + /* other jacks */ + {"HS", NULL, "Headset Mic"}, +}; + +/* sof audio machine driver for cs42l42 codec */ +static struct snd_soc_card sof_audio_card_cs42l42 = { + .name = "cs42l42", /* the sof- prefix is added by the core */ + .owner = THIS_MODULE, + .controls = sof_controls, + .num_controls = ARRAY_SIZE(sof_controls), + .dapm_widgets = sof_widgets, + .num_dapm_widgets = ARRAY_SIZE(sof_widgets), + .dapm_routes = sof_map, + .num_dapm_routes = ARRAY_SIZE(sof_map), + .fully_routed = true, + .late_probe = sof_card_late_probe, +}; + +static struct snd_soc_dai_link_component cs42l42_component[] = { + { + .name = "i2c-10134242:00", + .dai_name = "cs42l42", + } +}; + +static int +sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card, + struct sof_card_private *ctx) +{ + int ret; + + ret = sof_intel_board_set_dai_link(dev, card, ctx); + if (ret) + return ret; + + if (!ctx->codec_link) { + dev_err(dev, "codec link not available"); + return -EINVAL; + } + + /* codec-specific fields for headphone codec */ + ctx->codec_link->codecs = cs42l42_component; + ctx->codec_link->num_codecs = ARRAY_SIZE(cs42l42_component); + ctx->codec_link->init = sof_cs42l42_init; + ctx->codec_link->exit = sof_cs42l42_exit; + ctx->codec_link->ops = &sof_cs42l42_ops; + + if (ctx->amp_type == CODEC_NONE) + return 0; + + if (!ctx->amp_link) { + dev_err(dev, "amp link not available"); + return -EINVAL; + } + + /* codec-specific fields for speaker amplifier */ + switch (ctx->amp_type) { + case CODEC_MAX98357A: + max_98357a_dai_link(ctx->amp_link); + break; + case CODEC_MAX98360A: + max_98360a_dai_link(ctx->amp_link); + break; + default: + dev_err(dev, "invalid amp type %d\n", ctx->amp_type); + return -EINVAL; + } + + return 0; +} + +#define GLK_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \ + SOF_LINK_CODEC, \ + SOF_LINK_DMIC01, \ + SOF_LINK_IDISP_HDMI, \ + SOF_LINK_NONE, \ + SOF_LINK_NONE, \ + SOF_LINK_NONE) + +static int sof_audio_probe(struct platform_device *pdev) +{ + struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; + struct sof_card_private *ctx; + int ret; + + if (pdev->id_entry && pdev->id_entry->driver_data) + sof_cs42l42_quirk = (unsigned long)pdev->id_entry->driver_data; + + dev_dbg(&pdev->dev, "sof_cs42l42_quirk = %lx\n", sof_cs42l42_quirk); + + /* initialize ctx with board quirk */ + ctx = sof_intel_board_get_ctx(&pdev->dev, sof_cs42l42_quirk); + if (!ctx) + return -ENOMEM; + + if (soc_intel_is_glk()) { + ctx->dmic_be_num = 1; + + /* overwrite the DAI link order for GLK boards */ + ctx->link_order_overwrite = GLK_LINK_ORDER; + } + + if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) + ctx->hdmi.idisp_codec = true; + + /* update dai_link */ + ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_cs42l42, ctx); + if (ret) + return ret; + + sof_audio_card_cs42l42.dev = &pdev->dev; + + /* set platform name for each dailink */ + ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_cs42l42, + mach->mach_params.platform); + if (ret) + return ret; + + snd_soc_card_set_drvdata(&sof_audio_card_cs42l42, ctx); + + return devm_snd_soc_register_card(&pdev->dev, + &sof_audio_card_cs42l42); +} + +static const struct platform_device_id board_ids[] = { + { + .name = "glk_cs4242_mx98357a", + .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(2) | + SOF_SSP_PORT_AMP(1)), + }, + { + .name = "jsl_cs4242_mx98360a", + .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1)), + }, + { + .name = "adl_cs42l42_def", + .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1) | + SOF_NUM_IDISP_HDMI(4) | + SOF_BT_OFFLOAD_PRESENT | + SOF_SSP_PORT_BT_OFFLOAD(2)), + }, + { + .name = "rpl_cs42l42_def", + .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1) | + SOF_NUM_IDISP_HDMI(4) | + SOF_BT_OFFLOAD_PRESENT | + SOF_SSP_PORT_BT_OFFLOAD(2)), + }, + { + .name = "mtl_cs42l42_def", + .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(2) | + SOF_SSP_PORT_AMP(0) | + SOF_BT_OFFLOAD_PRESENT | + SOF_SSP_PORT_BT_OFFLOAD(1)), + }, + { } +}; +MODULE_DEVICE_TABLE(platform, board_ids); + +static struct platform_driver sof_audio = { + .probe = sof_audio_probe, + .driver = { + .name = "sof_cs42l42", + .pm = &snd_soc_pm_ops, + }, + .id_table = board_ids, +}; +module_platform_driver(sof_audio) + +/* Module information */ +MODULE_DESCRIPTION("SOF Audio Machine driver for CS42L42"); +MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_MAXIM_COMMON"); diff --git a/sound/soc/intel/boards/sof_da7219.c b/sound/soc/intel/boards/sof_da7219.c new file mode 100644 index 000000000000..9b7082b239c1 --- /dev/null +++ b/sound/soc/intel/boards/sof_da7219.c @@ -0,0 +1,491 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright(c) 2019 Intel Corporation. + +/* + * Intel SOF Machine driver for Dialog headphone codec + */ + +#include <linux/input.h> +#include <linux/module.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <linux/platform_device.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include <sound/sof.h> +#include "../../codecs/da7219.h" +#include "sof_board_helpers.h" +#include "sof_maxim_common.h" + +/* Driver-specific board quirks: from bit 0 to 7 */ +#define SOF_DA7219_GLK_BOARD BIT(0) +#define SOF_DA7219_CML_BOARD BIT(1) +#define SOF_DA7219_JSL_BOARD BIT(2) +#define SOF_DA7219_MCLK_EN BIT(3) + +#define DIALOG_CODEC_DAI "da7219-hifi" + +static int platform_clock_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *codec_dai; + int ret = 0; + + if (ctx->da7219.pll_bypass) + return ret; + + /* PLL SRM mode */ + codec_dai = snd_soc_card_get_codec_dai(card, DIALOG_CODEC_DAI); + 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)) { + dev_dbg(card->dev, "pll srm mode\n"); + + 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; +} + +static const struct snd_kcontrol_new controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Line Out"), +}; + +static const struct snd_soc_dapm_widget widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), + + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, + platform_clock_control, SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU), +}; + +static const struct snd_soc_dapm_route audio_map[] = { + { "Headphone Jack", NULL, "HPL" }, + { "Headphone Jack", NULL, "HPR" }, + + { "MIC", NULL, "Headset Mic" }, + + { "Headphone Jack", NULL, "Platform Clock" }, + { "Headset Mic", NULL, "Platform Clock" }, + { "Line Out", NULL, "Platform Clock" }, +}; + +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, +}; + +static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + struct snd_soc_component *component = codec_dai->component; + struct snd_soc_jack *jack = &ctx->headset_jack; + int mclk_rate, ret; + + mclk_rate = sof_dai_get_mclk(rtd); + if (mclk_rate <= 0) { + dev_err(rtd->dev, "invalid mclk freq %d\n", mclk_rate); + return -EINVAL; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, mclk_rate, + SND_SOC_CLOCK_IN); + if (ret) { + dev_err(rtd->dev, "fail to set sysclk, ret %d\n", ret); + return ret; + } + + /* + * Use PLL bypass mode if MCLK is available, be sure to set the + * frequency of MCLK to 12.288 or 24.576MHz on topology side. + */ + if (ctx->da7219.mclk_en && + (mclk_rate == 12288000 || mclk_rate == 24576000)) { + /* PLL bypass mode */ + dev_dbg(rtd->dev, "pll bypass mode, mclk rate %d\n", mclk_rate); + + ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0); + if (ret) { + dev_err(rtd->dev, "fail to set pll, ret %d\n", ret); + return ret; + } + + ctx->da7219.pll_bypass = true; + } + + /* + * Headset buttons map to the google Reference headset. + * These can be configured by userspace. + */ + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3 | SND_JACK_LINEOUT, + jack, jack_pins, ARRAY_SIZE(jack_pins)); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); + return ret; + } + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); + + ret = snd_soc_component_set_jack(component, jack, NULL); + if (ret) { + dev_err(rtd->dev, "fail to set component jack, ret %d\n", ret); + return ret; + } + + return ret; +} + +static void da7219_codec_exit(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; + + snd_soc_component_set_jack(component, NULL, NULL); +} + +static int card_late_probe(struct snd_soc_card *card) +{ + struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_dapm_context *dapm = &card->dapm; + int err; + + if (ctx->amp_type == CODEC_MAX98373) { + /* Disable Left and Right Spk pin after boot */ + snd_soc_dapm_disable_pin(dapm, "Left Spk"); + snd_soc_dapm_disable_pin(dapm, "Right Spk"); + err = snd_soc_dapm_sync(dapm); + if (err < 0) + return err; + } + + return sof_intel_board_card_late_probe(card); +} + +static struct snd_soc_card card_da7219 = { + .name = "da7219", /* the sof- prefix is added by the core */ + .owner = THIS_MODULE, + .controls = controls, + .num_controls = ARRAY_SIZE(controls), + .dapm_widgets = widgets, + .num_dapm_widgets = ARRAY_SIZE(widgets), + .dapm_routes = audio_map, + .num_dapm_routes = ARRAY_SIZE(audio_map), + .fully_routed = true, + .late_probe = card_late_probe, +}; + +static struct snd_soc_dai_link_component da7219_component[] = { + { + .name = "i2c-DLGS7219:00", + .dai_name = DIALOG_CODEC_DAI, + } +}; + +static int +sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card, + struct sof_card_private *ctx) +{ + int ret; + + ret = sof_intel_board_set_dai_link(dev, card, ctx); + if (ret) + return ret; + + if (!ctx->codec_link) { + dev_err(dev, "codec link not available"); + return -EINVAL; + } + + /* codec-specific fields for headphone codec */ + ctx->codec_link->codecs = da7219_component; + ctx->codec_link->num_codecs = ARRAY_SIZE(da7219_component); + ctx->codec_link->init = da7219_codec_init; + ctx->codec_link->exit = da7219_codec_exit; + + if (ctx->amp_type == CODEC_NONE) + return 0; + + if (!ctx->amp_link) { + dev_err(dev, "amp link not available"); + return -EINVAL; + } + + /* codec-specific fields for speaker amplifier */ + switch (ctx->amp_type) { + case CODEC_MAX98357A: + max_98357a_dai_link(ctx->amp_link); + break; + case CODEC_MAX98360A: + max_98360a_dai_link(ctx->amp_link); + break; + case CODEC_MAX98373: + max_98373_dai_link(dev, ctx->amp_link); + break; + case CODEC_MAX98390: + max_98390_dai_link(dev, ctx->amp_link); + break; + default: + dev_err(dev, "invalid amp type %d\n", ctx->amp_type); + return -EINVAL; + } + + return 0; +} + +#define GLK_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \ + SOF_LINK_CODEC, \ + SOF_LINK_DMIC01, \ + SOF_LINK_IDISP_HDMI, \ + SOF_LINK_NONE, \ + SOF_LINK_NONE, \ + SOF_LINK_NONE) + +#define CML_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \ + SOF_LINK_CODEC, \ + SOF_LINK_DMIC01, \ + SOF_LINK_IDISP_HDMI, \ + SOF_LINK_DMIC16K, \ + SOF_LINK_NONE, \ + SOF_LINK_NONE) + +#define JSL_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \ + SOF_LINK_CODEC, \ + SOF_LINK_DMIC01, \ + SOF_LINK_IDISP_HDMI, \ + SOF_LINK_DMIC16K, \ + SOF_LINK_NONE, \ + SOF_LINK_NONE) + +static int audio_probe(struct platform_device *pdev) +{ + struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; + struct sof_card_private *ctx; + char *card_name; + unsigned long board_quirk = 0; + int ret; + + if (pdev->id_entry && pdev->id_entry->driver_data) + board_quirk = (unsigned long)pdev->id_entry->driver_data; + + dev_dbg(&pdev->dev, "board_quirk = %lx\n", board_quirk); + + /* initialize ctx with board quirk */ + ctx = sof_intel_board_get_ctx(&pdev->dev, board_quirk); + if (!ctx) + return -ENOMEM; + + if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) + ctx->hdmi.idisp_codec = true; + + if (board_quirk & SOF_DA7219_GLK_BOARD) { + /* dmic16k not support */ + ctx->dmic_be_num = 1; + + /* overwrite the DAI link order for GLK boards */ + ctx->link_order_overwrite = GLK_LINK_ORDER; + + /* backward-compatible with existing devices */ + switch (ctx->amp_type) { + case CODEC_MAX98357A: + card_name = devm_kstrdup(&pdev->dev, "glkda7219max", + GFP_KERNEL); + if (!card_name) + return -ENOMEM; + + card_da7219.name = card_name; + break; + default: + break; + } + } else if (board_quirk & SOF_DA7219_CML_BOARD) { + /* overwrite the DAI link order for CML boards */ + ctx->link_order_overwrite = CML_LINK_ORDER; + + /* backward-compatible with existing devices */ + switch (ctx->amp_type) { + case CODEC_MAX98357A: + card_name = devm_kstrdup(&pdev->dev, "cmlda7219max", + GFP_KERNEL); + if (!card_name) + return -ENOMEM; + + card_da7219.name = card_name; + break; + case CODEC_MAX98390: + card_name = devm_kstrdup(&pdev->dev, + "cml_max98390_da7219", + GFP_KERNEL); + if (!card_name) + return -ENOMEM; + + card_da7219.name = card_name; + break; + default: + break; + } + } else if (board_quirk & SOF_DA7219_JSL_BOARD) { + /* overwrite the DAI link order for JSL boards */ + ctx->link_order_overwrite = JSL_LINK_ORDER; + + /* backward-compatible with existing devices */ + switch (ctx->amp_type) { + case CODEC_MAX98360A: + card_name = devm_kstrdup(&pdev->dev, "da7219max98360a", + GFP_KERNEL); + if (!card_name) + return -ENOMEM; + + card_da7219.name = card_name; + break; + case CODEC_MAX98373: + card_name = devm_kstrdup(&pdev->dev, "da7219max", + GFP_KERNEL); + if (!card_name) + return -ENOMEM; + + card_da7219.name = card_name; + break; + default: + break; + } + } + + if (board_quirk & SOF_DA7219_MCLK_EN) + ctx->da7219.mclk_en = true; + + /* update dai_link */ + ret = sof_card_dai_links_create(&pdev->dev, &card_da7219, ctx); + if (ret) + return ret; + + /* update codec_conf */ + switch (ctx->amp_type) { + case CODEC_MAX98373: + max_98373_set_codec_conf(&card_da7219); + break; + case CODEC_MAX98390: + max_98390_set_codec_conf(&pdev->dev, &card_da7219); + break; + case CODEC_MAX98357A: + case CODEC_MAX98360A: + case CODEC_NONE: + /* no codec conf required */ + break; + default: + dev_err(&pdev->dev, "invalid amp type %d\n", ctx->amp_type); + return -EINVAL; + } + + card_da7219.dev = &pdev->dev; + + ret = snd_soc_fixup_dai_links_platform_name(&card_da7219, + mach->mach_params.platform); + if (ret) + return ret; + + snd_soc_card_set_drvdata(&card_da7219, ctx); + + return devm_snd_soc_register_card(&pdev->dev, &card_da7219); +} + +static const struct platform_device_id board_ids[] = { + { + .name = "glk_da7219_def", + .driver_data = (kernel_ulong_t)(SOF_DA7219_GLK_BOARD | + SOF_SSP_PORT_CODEC(2) | + SOF_SSP_PORT_AMP(1)), + }, + { + .name = "cml_da7219_def", + .driver_data = (kernel_ulong_t)(SOF_DA7219_CML_BOARD | + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1)), + }, + { + .name = "jsl_da7219_def", + .driver_data = (kernel_ulong_t)(SOF_DA7219_JSL_BOARD | + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1)), + }, + { + .name = "adl_da7219_def", + .driver_data = (kernel_ulong_t)(SOF_DA7219_MCLK_EN | + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1) | + SOF_NUM_IDISP_HDMI(4) | + SOF_SSP_PORT_BT_OFFLOAD(2) | + SOF_BT_OFFLOAD_PRESENT), + }, + { + .name = "rpl_da7219_def", + .driver_data = (kernel_ulong_t)(SOF_DA7219_MCLK_EN | + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1) | + SOF_NUM_IDISP_HDMI(4) | + SOF_SSP_PORT_BT_OFFLOAD(2) | + SOF_BT_OFFLOAD_PRESENT), + }, + { + .name = "mtl_da7219_def", + .driver_data = (kernel_ulong_t)(SOF_DA7219_MCLK_EN | + SOF_SSP_PORT_CODEC(2) | + SOF_SSP_PORT_AMP(0) | + SOF_SSP_PORT_BT_OFFLOAD(1) | + SOF_BT_OFFLOAD_PRESENT), + }, + { } +}; +MODULE_DEVICE_TABLE(platform, board_ids); + +static struct platform_driver audio = { + .probe = audio_probe, + .driver = { + .name = "sof_da7219", + .pm = &snd_soc_pm_ops, + }, + .id_table = board_ids, +}; +module_platform_driver(audio) + +/* Module information */ +MODULE_DESCRIPTION("ASoC Intel(R) SOF Machine driver for Dialog codec"); +MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>"); +MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_MAXIM_COMMON"); diff --git a/sound/soc/intel/boards/sof_da7219_max98373.c b/sound/soc/intel/boards/sof_da7219_max98373.c deleted file mode 100644 index f3cb0773e70e..000000000000 --- a/sound/soc/intel/boards/sof_da7219_max98373.c +++ /dev/null @@ -1,459 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright(c) 2019 Intel Corporation. - -/* - * Intel SOF Machine driver for DA7219 + MAX98373/MAX98360A codec - */ - -#include <linux/input.h> -#include <linux/module.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <linux/platform_device.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include "../../codecs/da7219.h" -#include "../../codecs/da7219-aad.h" -#include "hda_dsp_common.h" - -#define DIALOG_CODEC_DAI "da7219-hifi" -#define MAX98373_CODEC_DAI "max98373-aif1" -#define MAXIM_DEV0_NAME "i2c-MX98373:00" -#define MAXIM_DEV1_NAME "i2c-MX98373:01" - -struct hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct card_private { - struct snd_soc_jack headset; - struct list_head hdmi_pcm_list; - struct snd_soc_jack hdmi[3]; -}; - -static int platform_clock_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct snd_soc_dai *codec_dai; - int ret = 0; - - codec_dai = snd_soc_card_get_codec_dai(card, DIALOG_CODEC_DAI); - 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; -} - -static const struct snd_kcontrol_new controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), -}; - -static const struct snd_kcontrol_new m98360a_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Spk"), -}; - -/* For MAX98373 amp */ -static const struct snd_soc_dapm_widget widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), - - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_POST_PMD | - SND_SOC_DAPM_PRE_PMU), - - SND_SOC_DAPM_MIC("SoC DMIC", NULL), -}; - -static const struct snd_soc_dapm_route audio_map[] = { - { "Headphone Jack", NULL, "HPL" }, - { "Headphone Jack", NULL, "HPR" }, - - { "MIC", NULL, "Headset Mic" }, - - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headset Mic", NULL, "Platform Clock" }, - - { "Left Spk", NULL, "Left BE_OUT" }, - { "Right Spk", NULL, "Right BE_OUT" }, - - /* digital mics */ - {"DMic", NULL, "SoC DMIC"}, -}; - -/* For MAX98360A amp */ -static const struct snd_soc_dapm_widget max98360a_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - - SND_SOC_DAPM_SPK("Spk", NULL), - - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_POST_PMD | - SND_SOC_DAPM_PRE_PMU), - - SND_SOC_DAPM_MIC("SoC DMIC", NULL), -}; - -static const struct snd_soc_dapm_route max98360a_map[] = { - { "Headphone Jack", NULL, "HPL" }, - { "Headphone Jack", NULL, "HPR" }, - - { "MIC", NULL, "Headset Mic" }, - - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headset Mic", NULL, "Platform Clock" }, - - {"Spk", NULL, "Speaker"}, - - /* digital mics */ - {"DMic", NULL, "SoC DMIC"}, -}; - -static struct snd_soc_jack headset; - -static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - struct snd_soc_component *component = codec_dai->component; - struct snd_soc_jack *jack; - int ret; - - /* Configure sysclk for codec */ - ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 24000000, - SND_SOC_CLOCK_IN); - if (ret) { - dev_err(rtd->dev, "can't set codec sysclk configuration\n"); - return ret; - } - - /* - * 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 | SND_JACK_BTN_2 | - SND_JACK_BTN_3 | SND_JACK_LINEOUT, - &headset, NULL, 0); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); - return ret; - } - - jack = &headset; - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); - da7219_aad_jack_det(component, jack); - - return ret; -} - -static int ssp1_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream); - int ret, j; - - for (j = 0; j < runtime->num_codecs; j++) { - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, j); - - if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) { - /* vmon_slot_no = 0 imon_slot_no = 1 for TX slots */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 3, 4, 16); - if (ret < 0) { - dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret); - return ret; - } - } - if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) { - /* vmon_slot_no = 2 imon_slot_no = 3 for TX slots */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC, 3, 4, 16); - if (ret < 0) { - dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret); - return ret; - } - } - } - - return 0; -} - -static struct snd_soc_ops ssp1_ops = { - .hw_params = ssp1_hw_params, -}; - -static struct snd_soc_codec_conf max98373_codec_conf[] = { - { - .dlc = COMP_CODEC_CONF(MAXIM_DEV0_NAME), - .name_prefix = "Right", - }, - { - .dlc = COMP_CODEC_CONF(MAXIM_DEV1_NAME), - .name_prefix = "Left", - }, -}; - -static int hdmi_init(struct snd_soc_pcm_runtime *rtd) -{ - struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); - struct hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = dai->id; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int card_late_probe(struct snd_soc_card *card) -{ - struct card_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_acpi_mach *mach = (card->dev)->platform_data; - struct hdmi_pcm *pcm; - - if (mach->mach_params.common_hdmi_codec_drv) { - pcm = list_first_entry(&ctx->hdmi_pcm_list, struct hdmi_pcm, - head); - return hda_dsp_hdmi_build_controls(card, - pcm->codec_dai->component); - } - - return -EINVAL; -} - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7219:00", DIALOG_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(ssp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); -SND_SOC_DAILINK_DEF(ssp1_amps, - DAILINK_COMP_ARRAY( - /* Left */ COMP_CODEC(MAXIM_DEV0_NAME, MAX98373_CODEC_DAI), - /* Right */ COMP_CODEC(MAXIM_DEV1_NAME, MAX98373_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(ssp1_m98360a, - DAILINK_COMP_ARRAY(COMP_CODEC("MX98360A:00", "HiFi"))); - -SND_SOC_DAILINK_DEF(dmic_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); -SND_SOC_DAILINK_DEF(dmic_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); - -SND_SOC_DAILINK_DEF(dmic16k_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin"))); - -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, /* subject to be overridden during probe */ - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); - -static struct snd_soc_dai_link dais[] = { - /* Back End DAI links */ - { - .name = "SSP1-Codec", - .id = 0, - .ignore_pmdown_time = 1, - .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, /* IV feedback */ - .ops = &ssp1_ops, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_amps, platform), - }, - { - .name = "SSP0-Codec", - .id = 1, - .no_pcm = 1, - .init = da7219_codec_init, - .ignore_pmdown_time = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - .name = "dmic01", - .id = 2, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .init = hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, - { - .name = "dmic16k", - .id = 6, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic16k_pin, dmic_codec, platform), - } -}; - -static struct snd_soc_card card_da7219_m98373 = { - .name = "da7219max", - .owner = THIS_MODULE, - .dai_link = dais, - .num_links = ARRAY_SIZE(dais), - .controls = controls, - .num_controls = ARRAY_SIZE(controls), - .dapm_widgets = widgets, - .num_dapm_widgets = ARRAY_SIZE(widgets), - .dapm_routes = audio_map, - .num_dapm_routes = ARRAY_SIZE(audio_map), - .codec_conf = max98373_codec_conf, - .num_configs = ARRAY_SIZE(max98373_codec_conf), - .fully_routed = true, - .late_probe = card_late_probe, -}; - -static struct snd_soc_card card_da7219_m98360a = { - .name = "da7219max98360a", - .owner = THIS_MODULE, - .dai_link = dais, - .num_links = ARRAY_SIZE(dais), - .controls = m98360a_controls, - .num_controls = ARRAY_SIZE(m98360a_controls), - .dapm_widgets = max98360a_widgets, - .num_dapm_widgets = ARRAY_SIZE(max98360a_widgets), - .dapm_routes = max98360a_map, - .num_dapm_routes = ARRAY_SIZE(max98360a_map), - .fully_routed = true, - .late_probe = card_late_probe, -}; - -static int audio_probe(struct platform_device *pdev) -{ - static struct snd_soc_card *card; - struct snd_soc_acpi_mach *mach; - struct card_private *ctx; - int ret; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - /* By default dais[0] is configured for max98373 */ - if (!strcmp(pdev->name, "sof_da7219_max98360a")) { - dais[0] = (struct snd_soc_dai_link) { - .name = "SSP1-Codec", - .id = 0, - .no_pcm = 1, - .dpcm_playback = 1, - .ignore_pmdown_time = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_m98360a, platform) }; - } - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - card = (struct snd_soc_card *)pdev->id_entry->driver_data; - card->dev = &pdev->dev; - - mach = pdev->dev.platform_data; - ret = snd_soc_fixup_dai_links_platform_name(card, - mach->mach_params.platform); - if (ret) - return ret; - - snd_soc_card_set_drvdata(card, ctx); - - return devm_snd_soc_register_card(&pdev->dev, card); -} - -static const struct platform_device_id board_ids[] = { - { - .name = "sof_da7219_max98373", - .driver_data = (kernel_ulong_t)&card_da7219_m98373, - }, - { - .name = "sof_da7219_max98360a", - .driver_data = (kernel_ulong_t)&card_da7219_m98360a, - }, - { } -}; - -static struct platform_driver audio = { - .probe = audio_probe, - .driver = { - .name = "sof_da7219_max98_360a_373", - .pm = &snd_soc_pm_ops, - }, - .id_table = board_ids, -}; -module_platform_driver(audio) - -/* Module information */ -MODULE_DESCRIPTION("ASoC Intel(R) SOF Machine driver"); -MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:sof_da7219_max98360a"); -MODULE_ALIAS("platform:sof_da7219_max98373"); diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c new file mode 100644 index 000000000000..a0b3679b17b4 --- /dev/null +++ b/sound/soc/intel/boards/sof_es8336.c @@ -0,0 +1,846 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright(c) 2021 Intel Corporation. + +/* + * Intel SOF Machine Driver with es8336 Codec + */ + +#include <linux/device.h> +#include <linux/dmi.h> +#include <linux/gpio/consumer.h> +#include <linux/gpio/machine.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include "hda_dsp_common.h" + +/* jd-inv + terminating entry */ +#define MAX_NO_PROPS 2 + +#define SOF_ES8336_SSP_CODEC(quirk) ((quirk) & GENMASK(3, 0)) +#define SOF_ES8336_SSP_CODEC_MASK (GENMASK(3, 0)) + +#define SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK BIT(4) + +/* HDMI capture*/ +#define SOF_SSP_HDMI_CAPTURE_PRESENT BIT(14) +#define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT 15 +#define SOF_NO_OF_HDMI_CAPTURE_SSP_MASK (GENMASK(16, 15)) +#define SOF_NO_OF_HDMI_CAPTURE_SSP(quirk) \ + (((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) + +#define SOF_HDMI_CAPTURE_1_SSP_SHIFT 7 +#define SOF_HDMI_CAPTURE_1_SSP_MASK (GENMASK(9, 7)) +#define SOF_HDMI_CAPTURE_1_SSP(quirk) \ + (((quirk) << SOF_HDMI_CAPTURE_1_SSP_SHIFT) & SOF_HDMI_CAPTURE_1_SSP_MASK) + +#define SOF_HDMI_CAPTURE_2_SSP_SHIFT 10 +#define SOF_HDMI_CAPTURE_2_SSP_MASK (GENMASK(12, 10)) +#define SOF_HDMI_CAPTURE_2_SSP(quirk) \ + (((quirk) << SOF_HDMI_CAPTURE_2_SSP_SHIFT) & SOF_HDMI_CAPTURE_2_SSP_MASK) + +#define SOF_ES8336_ENABLE_DMIC BIT(5) +#define SOF_ES8336_JD_INVERTED BIT(6) +#define SOF_ES8336_HEADPHONE_GPIO BIT(7) +#define SOC_ES8336_HEADSET_MIC1 BIT(8) + +static unsigned long quirk; + +static int quirk_override = -1; +module_param_named(quirk, quirk_override, int, 0444); +MODULE_PARM_DESC(quirk, "Board-specific quirk override"); + +struct sof_es8336_private { + struct device *codec_dev; + struct gpio_desc *gpio_speakers, *gpio_headphone; + struct snd_soc_jack jack; + struct list_head hdmi_pcm_list; + bool speaker_en; + struct delayed_work pcm_pop_work; +}; + +struct sof_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +static const struct acpi_gpio_params enable_gpio0 = { 0, 0, true }; +static const struct acpi_gpio_params enable_gpio1 = { 1, 0, true }; + +static const struct acpi_gpio_mapping acpi_speakers_enable_gpio0[] = { + { "speakers-enable-gpios", &enable_gpio0, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, + { } +}; + +static const struct acpi_gpio_mapping acpi_speakers_enable_gpio1[] = { + { "speakers-enable-gpios", &enable_gpio1, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, +}; + +static const struct acpi_gpio_mapping acpi_enable_both_gpios[] = { + { "speakers-enable-gpios", &enable_gpio0, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, + { "headphone-enable-gpios", &enable_gpio1, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, + { } +}; + +static const struct acpi_gpio_mapping acpi_enable_both_gpios_rev_order[] = { + { "speakers-enable-gpios", &enable_gpio1, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, + { "headphone-enable-gpios", &enable_gpio0, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, + { } +}; + +static void log_quirks(struct device *dev) +{ + dev_info(dev, "quirk mask %#lx\n", quirk); + dev_info(dev, "quirk SSP%ld\n", SOF_ES8336_SSP_CODEC(quirk)); + if (quirk & SOF_ES8336_ENABLE_DMIC) + dev_info(dev, "quirk DMIC enabled\n"); + if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) + dev_info(dev, "Speakers GPIO1 quirk enabled\n"); + if (quirk & SOF_ES8336_HEADPHONE_GPIO) + dev_info(dev, "quirk headphone GPIO enabled\n"); + if (quirk & SOF_ES8336_JD_INVERTED) + dev_info(dev, "quirk JD inverted enabled\n"); + if (quirk & SOC_ES8336_HEADSET_MIC1) + dev_info(dev, "quirk headset at mic1 port enabled\n"); +} + +static void pcm_pop_work_events(struct work_struct *work) +{ + struct sof_es8336_private *priv = + container_of(work, struct sof_es8336_private, pcm_pop_work.work); + + gpiod_set_value_cansleep(priv->gpio_speakers, priv->speaker_en); + + if (quirk & SOF_ES8336_HEADPHONE_GPIO) + gpiod_set_value_cansleep(priv->gpio_headphone, priv->speaker_en); + +} + +static int sof_8336_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_card *card = rtd->card; + struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + if (priv->speaker_en == false) + if (substream->stream == 0) { + cancel_delayed_work(&priv->pcm_pop_work); + gpiod_set_value_cansleep(priv->gpio_speakers, true); + } + break; + default: + return -EINVAL; + } + + return 0; +} + +static int sof_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_card *card = w->dapm->card; + struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card); + + if (priv->speaker_en == !SND_SOC_DAPM_EVENT_ON(event)) + return 0; + + priv->speaker_en = !SND_SOC_DAPM_EVENT_ON(event); + + queue_delayed_work(system_wq, &priv->pcm_pop_work, msecs_to_jiffies(70)); + return 0; +} + +static const struct snd_soc_dapm_widget sof_es8316_widgets[] = { + SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Internal Mic", NULL), + + SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0, + sof_es8316_speaker_power_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), +}; + +static const struct snd_soc_dapm_widget dmic_widgets[] = { + SND_SOC_DAPM_MIC("SoC DMIC", NULL), +}; + +static const struct snd_soc_dapm_route sof_es8316_audio_map[] = { + {"Headphone", NULL, "HPOL"}, + {"Headphone", NULL, "HPOR"}, + + /* + * There is no separate speaker output instead the speakers are muxed to + * the HP outputs. The mux is controlled Speaker and/or headphone switch. + */ + {"Speaker", NULL, "HPOL"}, + {"Speaker", NULL, "HPOR"}, + {"Speaker", NULL, "Speaker Power"}, +}; + +static const struct snd_soc_dapm_route sof_es8316_headset_mic2_map[] = { + {"MIC1", NULL, "Internal Mic"}, + {"MIC2", NULL, "Headset Mic"}, +}; + +static const struct snd_soc_dapm_route sof_es8316_headset_mic1_map[] = { + {"MIC2", NULL, "Internal Mic"}, + {"MIC1", NULL, "Headset Mic"}, +}; + +static const struct snd_soc_dapm_route dmic_map[] = { + /* digital mics */ + {"DMic", NULL, "SoC DMIC"}, +}; + +static const struct snd_kcontrol_new sof_es8316_controls[] = { + SOC_DAPM_PIN_SWITCH("Speaker"), + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Internal Mic"), +}; + +static struct snd_soc_jack_pin sof_es8316_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static int dmic_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_card *card = runtime->card; + int ret; + + ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets, + ARRAY_SIZE(dmic_widgets)); + if (ret) { + dev_err(card->dev, "DMic widget addition failed: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map, + ARRAY_SIZE(dmic_map)); + if (ret) + dev_err(card->dev, "DMic map addition failed: %d\n", ret); + + return ret; +} + +static int sof_hdmi_init(struct snd_soc_pcm_runtime *runtime) +{ + struct sof_es8336_private *priv = snd_soc_card_get_drvdata(runtime->card); + struct snd_soc_dai *dai = snd_soc_rtd_to_codec(runtime, 0); + struct sof_hdmi_pcm *pcm; + + pcm = devm_kzalloc(runtime->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + /* dai_link id is 1:1 mapped to the PCM device */ + pcm->device = runtime->dai_link->id; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &priv->hdmi_pcm_list); + + return 0; +} + +static int sof_es8316_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_component *codec = snd_soc_rtd_to_codec(runtime, 0)->component; + struct snd_soc_card *card = runtime->card; + struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card); + const struct snd_soc_dapm_route *custom_map; + int num_routes; + int ret; + + card->dapm.idle_bias_off = true; + + if (quirk & SOC_ES8336_HEADSET_MIC1) { + custom_map = sof_es8316_headset_mic1_map; + num_routes = ARRAY_SIZE(sof_es8316_headset_mic1_map); + } else { + custom_map = sof_es8316_headset_mic2_map; + num_routes = ARRAY_SIZE(sof_es8316_headset_mic2_map); + } + + ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); + if (ret) + return ret; + + ret = snd_soc_card_jack_new_pins(card, "Headset", + SND_JACK_HEADSET | SND_JACK_BTN_0, + &priv->jack, sof_es8316_jack_pins, + ARRAY_SIZE(sof_es8316_jack_pins)); + if (ret) { + dev_err(card->dev, "jack creation failed %d\n", ret); + return ret; + } + + snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + + snd_soc_component_set_jack(codec, &priv->jack, NULL); + + return 0; +} + +static void sof_es8316_exit(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; + + snd_soc_component_set_jack(component, NULL, NULL); +} + +static int sof_es8336_quirk_cb(const struct dmi_system_id *id) +{ + quirk = (unsigned long)id->driver_data; + + return 1; +} + +/* + * this table should only be used to add GPIO or jack-detection quirks + * that cannot be detected from ACPI tables. The SSP and DMIC + * information are providing by the platform driver and are aligned + * with the topology used. + * + * If the GPIO support is missing, the quirk parameter can be used to + * enable speakers. In that case it's recommended to keep the SSP and DMIC + * information consistent, overriding the SSP and DMIC can only be done + * if the topology file is modified as well. + */ +static const struct dmi_system_id sof_es8336_quirk_table[] = { + { + .callback = sof_es8336_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "IP3 tech"), + DMI_MATCH(DMI_BOARD_NAME, "WN1"), + }, + .driver_data = (void *)(SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) + }, + { + .callback = sof_es8336_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HUAWEI"), + DMI_MATCH(DMI_BOARD_NAME, "BOHB-WAX9-PCB-B2"), + }, + .driver_data = (void *)(SOF_ES8336_HEADPHONE_GPIO | + SOC_ES8336_HEADSET_MIC1) + }, + {} +}; + +static int sof_es8336_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + const int sysclk = 19200000; + int ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, 1, sysclk, SND_SOC_CLOCK_OUT); + if (ret < 0) { + dev_err(rtd->dev, "%s, Failed to set ES8336 SYSCLK: %d\n", + __func__, ret); + return ret; + } + + return 0; +} + +/* machine stream operations */ +static const struct snd_soc_ops sof_es8336_ops = { + .hw_params = sof_es8336_hw_params, + .trigger = sof_8336_trigger, +}; + +static struct snd_soc_dai_link_component platform_component[] = { + { + /* name might be overridden during probe */ + .name = "0000:00:1f.3" + } +}; + +SND_SOC_DAILINK_DEF(es8336_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ESSX8336:00", "ES8316 HiFi"))); + +static struct snd_soc_dai_link_component dmic_component[] = { + { + .name = "dmic-codec", + .dai_name = "dmic-hifi", + } +}; + +static int sof_es8336_late_probe(struct snd_soc_card *card) +{ + struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card); + struct sof_hdmi_pcm *pcm; + + if (list_empty(&priv->hdmi_pcm_list)) + return -ENOENT; + + pcm = list_first_entry(&priv->hdmi_pcm_list, struct sof_hdmi_pcm, head); + + return hda_dsp_hdmi_build_controls(card, pcm->codec_dai->component); +} + +/* SoC card */ +static struct snd_soc_card sof_es8336_card = { + .name = "essx8336", /* sof- prefix added automatically */ + .owner = THIS_MODULE, + .dapm_widgets = sof_es8316_widgets, + .num_dapm_widgets = ARRAY_SIZE(sof_es8316_widgets), + .dapm_routes = sof_es8316_audio_map, + .num_dapm_routes = ARRAY_SIZE(sof_es8316_audio_map), + .controls = sof_es8316_controls, + .num_controls = ARRAY_SIZE(sof_es8316_controls), + .fully_routed = true, + .late_probe = sof_es8336_late_probe, + .num_links = 1, +}; + +static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, + int ssp_codec, + int dmic_be_num, + int hdmi_num) +{ + struct snd_soc_dai_link_component *cpus; + struct snd_soc_dai_link *links; + struct snd_soc_dai_link_component *idisp_components; + int hdmi_id_offset = 0; + int id = 0; + int i; + + links = devm_kcalloc(dev, sof_es8336_card.num_links, + sizeof(struct snd_soc_dai_link), GFP_KERNEL); + cpus = devm_kcalloc(dev, sof_es8336_card.num_links, + sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); + if (!links || !cpus) + goto devm_err; + + /* codec SSP */ + links[id].name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d-Codec", ssp_codec); + if (!links[id].name) + goto devm_err; + + links[id].id = id; + links[id].codecs = es8336_codec; + links[id].num_codecs = ARRAY_SIZE(es8336_codec); + links[id].platforms = platform_component; + links[id].num_platforms = ARRAY_SIZE(platform_component); + links[id].init = sof_es8316_init; + links[id].exit = sof_es8316_exit; + links[id].ops = &sof_es8336_ops; + links[id].nonatomic = true; + links[id].no_pcm = 1; + links[id].cpus = &cpus[id]; + links[id].num_cpus = 1; + + links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d Pin", + ssp_codec); + if (!links[id].cpus->dai_name) + goto devm_err; + + id++; + + /* dmic */ + if (dmic_be_num > 0) { + /* at least we have dmic01 */ + links[id].name = "dmic01"; + links[id].cpus = &cpus[id]; + links[id].cpus->dai_name = "DMIC01 Pin"; + links[id].init = dmic_init; + if (dmic_be_num > 1) { + /* set up 2 BE links at most */ + links[id + 1].name = "dmic16k"; + links[id + 1].cpus = &cpus[id + 1]; + links[id + 1].cpus->dai_name = "DMIC16k Pin"; + dmic_be_num = 2; + } + } else { + /* HDMI dai link starts at 3 according to current topology settings */ + hdmi_id_offset = 2; + } + + for (i = 0; i < dmic_be_num; i++) { + links[id].id = id; + links[id].num_cpus = 1; + links[id].codecs = dmic_component; + links[id].num_codecs = ARRAY_SIZE(dmic_component); + links[id].platforms = platform_component; + links[id].num_platforms = ARRAY_SIZE(platform_component); + links[id].ignore_suspend = 1; + links[id].capture_only = 1; + links[id].no_pcm = 1; + + id++; + } + + /* HDMI */ + if (hdmi_num > 0) { + idisp_components = devm_kcalloc(dev, + hdmi_num, + sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); + if (!idisp_components) + goto devm_err; + } + + for (i = 1; i <= hdmi_num; i++) { + links[id].name = devm_kasprintf(dev, GFP_KERNEL, + "iDisp%d", i); + if (!links[id].name) + goto devm_err; + + links[id].id = id + hdmi_id_offset; + links[id].cpus = &cpus[id]; + links[id].num_cpus = 1; + links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "iDisp%d Pin", i); + if (!links[id].cpus->dai_name) + goto devm_err; + + idisp_components[i - 1].name = "ehdaudio0D2"; + idisp_components[i - 1].dai_name = devm_kasprintf(dev, + GFP_KERNEL, + "intel-hdmi-hifi%d", + i); + if (!idisp_components[i - 1].dai_name) + goto devm_err; + + links[id].codecs = &idisp_components[i - 1]; + links[id].num_codecs = 1; + links[id].platforms = platform_component; + links[id].num_platforms = ARRAY_SIZE(platform_component); + links[id].init = sof_hdmi_init; + links[id].playback_only = 1; + links[id].no_pcm = 1; + + id++; + } + + /* HDMI-In SSP */ + if (quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) { + int num_of_hdmi_ssp = (quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >> + SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; + + for (i = 1; i <= num_of_hdmi_ssp; i++) { + int port = (i == 1 ? (quirk & SOF_HDMI_CAPTURE_1_SSP_MASK) >> + SOF_HDMI_CAPTURE_1_SSP_SHIFT : + (quirk & SOF_HDMI_CAPTURE_2_SSP_MASK) >> + SOF_HDMI_CAPTURE_2_SSP_SHIFT); + + links[id].cpus = &cpus[id]; + links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d Pin", port); + if (!links[id].cpus->dai_name) + return NULL; + links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port); + if (!links[id].name) + return NULL; + links[id].id = id + hdmi_id_offset; + links[id].codecs = &snd_soc_dummy_dlc; + links[id].num_codecs = 1; + links[id].platforms = platform_component; + links[id].num_platforms = ARRAY_SIZE(platform_component); + links[id].capture_only = 1; + links[id].no_pcm = 1; + links[id].num_cpus = 1; + id++; + } + } + + return links; + +devm_err: + return NULL; +} + +static char soc_components[30]; + + /* i2c-<HID>:00 with HID being 8 chars */ +static char codec_name[SND_ACPI_I2C_ID_LEN]; + +static int sof_es8336_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct snd_soc_card *card; + struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; + struct property_entry props[MAX_NO_PROPS] = {}; + struct sof_es8336_private *priv; + struct fwnode_handle *fwnode; + struct acpi_device *adev; + struct snd_soc_dai_link *dai_links; + struct device *codec_dev; + const struct acpi_gpio_mapping *gpio_mapping; + unsigned int cnt = 0; + int dmic_be_num = 0; + int hdmi_num = 3; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + card = &sof_es8336_card; + card->dev = dev; + + if (pdev->id_entry && pdev->id_entry->driver_data) + quirk = (unsigned long)pdev->id_entry->driver_data; + + /* check GPIO DMI quirks */ + dmi_check_system(sof_es8336_quirk_table); + + /* Use NHLT configuration only for Non-HDMI capture use case. + * Because more than one SSP will be enabled for HDMI capture hence wrong codec + * SSP will be set. + */ + if (mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER) { + if (!mach->mach_params.i2s_link_mask) { + dev_warn(dev, "No I2S link information provided, using SSP0. This may need to be modified with the quirk module parameter\n"); + } else { + /* + * Set configuration based on platform NHLT. + * In this machine driver, we can only support one SSP for the + * ES8336 link. + * In some cases multiple SSPs can be reported by NHLT, starting MSB-first + * seems to pick the right connection. + */ + unsigned long ssp; + + /* fls returns 1-based results, SSPs indices are 0-based */ + ssp = fls(mach->mach_params.i2s_link_mask) - 1; + + quirk |= ssp; + } + } + + if (mach->mach_params.dmic_num) + quirk |= SOF_ES8336_ENABLE_DMIC; + + if (quirk_override != -1) { + dev_info(dev, "Overriding quirk 0x%lx => 0x%x\n", + quirk, quirk_override); + quirk = quirk_override; + } + log_quirks(dev); + + if (quirk & SOF_ES8336_ENABLE_DMIC) + dmic_be_num = 2; + + /* compute number of dai links */ + sof_es8336_card.num_links = 1 + dmic_be_num + hdmi_num; + + if (quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) + sof_es8336_card.num_links += (quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >> + SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; + + dai_links = sof_card_dai_links_create(dev, + SOF_ES8336_SSP_CODEC(quirk), + dmic_be_num, hdmi_num); + if (!dai_links) + return -ENOMEM; + + sof_es8336_card.dai_link = dai_links; + + /* fixup codec name based on HID */ + adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1); + if (adev) { + snprintf(codec_name, sizeof(codec_name), + "i2c-%s", acpi_dev_name(adev)); + dai_links[0].codecs->name = codec_name; + + /* also fixup codec dai name if relevant */ + if (!strncmp(mach->id, "ESSX8326", SND_ACPI_I2C_ID_LEN)) + dai_links[0].codecs->dai_name = "ES8326 HiFi"; + } else { + dev_err(dev, "Error cannot find '%s' dev\n", mach->id); + return -ENOENT; + } + + codec_dev = acpi_get_first_physical_node(adev); + acpi_dev_put(adev); + if (!codec_dev) + return -EPROBE_DEFER; + priv->codec_dev = get_device(codec_dev); + + ret = snd_soc_fixup_dai_links_platform_name(&sof_es8336_card, + mach->mach_params.platform); + if (ret) { + put_device(codec_dev); + return ret; + } + + if (quirk & SOF_ES8336_JD_INVERTED) + props[cnt++] = PROPERTY_ENTRY_BOOL("everest,jack-detect-inverted"); + + if (cnt) { + fwnode = fwnode_create_software_node(props, NULL); + if (IS_ERR(fwnode)) { + put_device(codec_dev); + return PTR_ERR(fwnode); + } + + ret = device_add_software_node(codec_dev, to_software_node(fwnode)); + + fwnode_handle_put(fwnode); + + if (ret) { + put_device(codec_dev); + return ret; + } + } + + /* get speaker enable GPIO */ + if (quirk & SOF_ES8336_HEADPHONE_GPIO) { + if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) + gpio_mapping = acpi_enable_both_gpios; + else + gpio_mapping = acpi_enable_both_gpios_rev_order; + } else if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) { + gpio_mapping = acpi_speakers_enable_gpio1; + } else { + gpio_mapping = acpi_speakers_enable_gpio0; + } + + ret = devm_acpi_dev_add_driver_gpios(codec_dev, gpio_mapping); + if (ret) + dev_warn(codec_dev, "unable to add GPIO mapping table\n"); + + priv->gpio_speakers = gpiod_get_optional(codec_dev, "speakers-enable", GPIOD_OUT_LOW); + if (IS_ERR(priv->gpio_speakers)) { + ret = dev_err_probe(dev, PTR_ERR(priv->gpio_speakers), + "could not get speakers-enable GPIO\n"); + goto err_put_codec; + } + + priv->gpio_headphone = gpiod_get_optional(codec_dev, "headphone-enable", GPIOD_OUT_LOW); + if (IS_ERR(priv->gpio_headphone)) { + ret = dev_err_probe(dev, PTR_ERR(priv->gpio_headphone), + "could not get headphone-enable GPIO\n"); + goto err_put_codec; + } + + INIT_LIST_HEAD(&priv->hdmi_pcm_list); + INIT_DELAYED_WORK(&priv->pcm_pop_work, + pcm_pop_work_events); + snd_soc_card_set_drvdata(card, priv); + + if (mach->mach_params.dmic_num > 0) { + snprintf(soc_components, sizeof(soc_components), + "cfg-dmics:%d", mach->mach_params.dmic_num); + card->components = soc_components; + } + + ret = devm_snd_soc_register_card(dev, card); + if (ret) { + gpiod_put(priv->gpio_speakers); + dev_err(dev, "snd_soc_register_card failed: %d\n", ret); + goto err_put_codec; + } + platform_set_drvdata(pdev, &sof_es8336_card); + return 0; + +err_put_codec: + device_remove_software_node(priv->codec_dev); + put_device(codec_dev); + return ret; +} + +static void sof_es8336_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card); + + cancel_delayed_work_sync(&priv->pcm_pop_work); + gpiod_put(priv->gpio_speakers); + device_remove_software_node(priv->codec_dev); + put_device(priv->codec_dev); +} + +static const struct platform_device_id board_ids[] = { + { + .name = "sof-essx8336", /* default quirk == 0 */ + }, + { + .name = "adl_es83x6_c1_h02", + .driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) | + SOF_NO_OF_HDMI_CAPTURE_SSP(2) | + SOF_HDMI_CAPTURE_1_SSP(0) | + SOF_HDMI_CAPTURE_2_SSP(2) | + SOF_SSP_HDMI_CAPTURE_PRESENT | + SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | + SOF_ES8336_JD_INVERTED), + }, + { + .name = "rpl_es83x6_c1_h02", + .driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) | + SOF_NO_OF_HDMI_CAPTURE_SSP(2) | + SOF_HDMI_CAPTURE_1_SSP(0) | + SOF_HDMI_CAPTURE_2_SSP(2) | + SOF_SSP_HDMI_CAPTURE_PRESENT | + SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | + SOF_ES8336_JD_INVERTED), + }, + { + .name = "mtl_es83x6_c1_h02", + .driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) | + SOF_NO_OF_HDMI_CAPTURE_SSP(2) | + SOF_HDMI_CAPTURE_1_SSP(0) | + SOF_HDMI_CAPTURE_2_SSP(2) | + SOF_SSP_HDMI_CAPTURE_PRESENT | + SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | + SOF_ES8336_JD_INVERTED), + }, + { + .name = "arl_es83x6_c1_h02", + .driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) | + SOF_NO_OF_HDMI_CAPTURE_SSP(2) | + SOF_HDMI_CAPTURE_1_SSP(0) | + SOF_HDMI_CAPTURE_2_SSP(2) | + SOF_SSP_HDMI_CAPTURE_PRESENT | + SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | + SOF_ES8336_JD_INVERTED), + }, + { } +}; +MODULE_DEVICE_TABLE(platform, board_ids); + +static struct platform_driver sof_es8336_driver = { + .driver = { + .name = "sof-essx8336", + .pm = &snd_soc_pm_ops, + }, + .probe = sof_es8336_probe, + .remove = sof_es8336_remove, + .id_table = board_ids, +}; +module_platform_driver(sof_es8336_driver); + +MODULE_DESCRIPTION("ASoC Intel(R) SOF + ES8336 Machine driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON"); diff --git a/sound/soc/intel/boards/sof_hdmi_common.h b/sound/soc/intel/boards/sof_hdmi_common.h new file mode 100644 index 000000000000..1573e089c0e5 --- /dev/null +++ b/sound/soc/intel/boards/sof_hdmi_common.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright(c) 2023 Intel Corporation. + */ + +#ifndef __SOF_HDMI_COMMON_H +#define __SOF_HDMI_COMMON_H + +#include <sound/soc.h> + +#define IDISP_CODEC_MASK 0x4 + +/* + * sof_hdmi_private: data for Intel HDMI dai link (idisp) initialization + * + * @hdmi_comp: ASoC component of idisp codec + * @idisp_codec: true to indicate idisp codec is present + */ +struct sof_hdmi_private { + struct snd_soc_component *hdmi_comp; + bool idisp_codec; +}; + +#endif /* __SOF_HDMI_COMMON_H */ diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c index b6e63ea13d64..c98a67ae5e66 100644 --- a/sound/soc/intel/boards/sof_maxim_common.c +++ b/sound/soc/intel/boards/sof_maxim_common.c @@ -1,17 +1,51 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2020 Intel Corporation. All rights reserved. +// Copyright(c) 2020 Intel Corporation +#include <linux/module.h> #include <linux/string.h> #include <sound/pcm.h> +#include <sound/pcm_params.h> #include <sound/soc.h> +#include <sound/soc-acpi.h> #include <sound/soc-dai.h> #include <sound/soc-dapm.h> +#include <sound/sof.h> #include <uapi/sound/asound.h> +#include "../common/soc-intel-quirks.h" #include "sof_maxim_common.h" +/* + * Common structures and functions + */ +static const struct snd_kcontrol_new maxim_2spk_kcontrols[] = { + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), + +}; + +static const struct snd_soc_dapm_widget maxim_2spk_widgets[] = { + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), +}; + +/* helper function to get the number of specific codec */ +static unsigned int get_num_codecs(const char *hid) +{ + struct acpi_device *adev; + unsigned int dev_num = 0; + + for_each_acpi_dev_match(adev, hid, NULL, -1) + dev_num++; + + return dev_num; +} + +/* + * Maxim MAX98373 + */ #define MAX_98373_PIN_NAME 16 -const struct snd_soc_dapm_route max_98373_dapm_routes[] = { +static const struct snd_soc_dapm_route max_98373_dapm_routes[] = { /* speaker */ { "Left Spk", NULL, "Left BE_OUT" }, { "Right Spk", NULL, "Right BE_OUT" }, @@ -28,7 +62,7 @@ static struct snd_soc_codec_conf max_98373_codec_conf[] = { }, }; -struct snd_soc_dai_link_component max_98373_components[] = { +static struct snd_soc_dai_link_component max_98373_components[] = { { /* For Right */ .name = MAX_98373_DEV0_NAME, .dai_name = MAX_98373_CODEC_DAI, @@ -39,30 +73,125 @@ struct snd_soc_dai_link_component max_98373_components[] = { }, }; -static int max98373_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +/* + * According to the definition of 'DAI Sel Mux' mixer in max98373.c, rx mask + * should choose two channels from TDM slots, the LSB of rx mask is left channel + * and the other one is right channel. + */ +static const struct { + unsigned int rx; +} max_98373_tdm_mask[] = { + {.rx = 0x3}, + {.rx = 0x3}, +}; + +/* + * The tx mask indicates which channel(s) contains output IV-sense data and + * others should set to Hi-Z. Here we get the channel number from codec's ACPI + * device property "maxim,vmon-slot-no" and "maxim,imon-slot-no" to generate the + * mask. Refer to the max98373_slot_config() function in max98373.c codec driver. + */ +static unsigned int max_98373_get_tx_mask(struct device *dev) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + int vmon_slot; + int imon_slot; + + if (device_property_read_u32(dev, "maxim,vmon-slot-no", &vmon_slot)) + vmon_slot = 0; + + if (device_property_read_u32(dev, "maxim,imon-slot-no", &imon_slot)) + imon_slot = 1; + + dev_dbg(dev, "vmon_slot %d imon_slot %d\n", vmon_slot, imon_slot); + + return (0x1 << vmon_slot) | (0x1 << imon_slot); +} + +static int max_98373_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai_link *dai_link = rtd->dai_link; struct snd_soc_dai *codec_dai; - int j; + int i; + int tdm_slots; + unsigned int tx_mask; + unsigned int tx_mask_used = 0x0; + int ret = 0; - for_each_rtd_codec_dais(rtd, j, codec_dai) { - if (!strcmp(codec_dai->component->name, MAX_98373_DEV0_NAME)) { - /* DEV0 tdm slot configuration */ - snd_soc_dai_set_tdm_slot(codec_dai, 0x03, 3, 8, 24); + for_each_rtd_codec_dais(rtd, i, codec_dai) { + if (i >= ARRAY_SIZE(max_98373_tdm_mask)) { + dev_err(codec_dai->dev, "only 2 amps are supported\n"); + return -EINVAL; } - if (!strcmp(codec_dai->component->name, MAX_98373_DEV1_NAME)) { - /* DEV1 tdm slot configuration */ - snd_soc_dai_set_tdm_slot(codec_dai, 0x0C, 3, 8, 24); + + switch (dai_link->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + /* get the tplg configured tdm slot number */ + tdm_slots = sof_dai_get_tdm_slots(rtd); + if (tdm_slots <= 0) { + dev_err(rtd->dev, "invalid tdm slots %d\n", + tdm_slots); + return -EINVAL; + } + + /* get the tx mask from ACPI device properties */ + tx_mask = max_98373_get_tx_mask(codec_dai->dev); + if (!tx_mask) + return -EINVAL; + + if (tx_mask & tx_mask_used) { + dev_err(codec_dai->dev, "invalid tx mask 0x%x, used 0x%x\n", + tx_mask, tx_mask_used); + return -EINVAL; + } + + tx_mask_used |= tx_mask; + + /* + * check if tdm slot number is too small for channel + * allocation + */ + if (fls(tx_mask) > tdm_slots) { + dev_err(codec_dai->dev, "slot mismatch, tx %d slots %d\n", + fls(tx_mask), tdm_slots); + return -EINVAL; + } + + if (fls(max_98373_tdm_mask[i].rx) > tdm_slots) { + dev_err(codec_dai->dev, "slot mismatch, rx %d slots %d\n", + fls(max_98373_tdm_mask[i].rx), tdm_slots); + return -EINVAL; + } + + dev_dbg(codec_dai->dev, "set tdm slot: tx 0x%x rx 0x%x slots %d width %d\n", + tx_mask, max_98373_tdm_mask[i].rx, + tdm_slots, params_width(params)); + + ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_mask, + max_98373_tdm_mask[i].rx, + tdm_slots, + params_width(params)); + if (ret < 0) { + dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n", + ret); + return ret; + } + break; + default: + dev_dbg(codec_dai->dev, "codec is in I2S mode\n"); + break; } } return 0; } -int max98373_trigger(struct snd_pcm_substream *substream, int cmd) +static int max_98373_trigger(struct snd_pcm_substream *substream, int cmd) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai; + struct snd_soc_dai *cpu_dai; int j; int ret = 0; @@ -70,10 +199,10 @@ int max98373_trigger(struct snd_pcm_substream *substream, int cmd) if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) return 0; + cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); for_each_rtd_codec_dais(rtd, j, codec_dai) { - struct snd_soc_component *component = codec_dai->component; struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); + snd_soc_component_get_dapm(cpu_dai->component); char pin_name[MAX_98373_PIN_NAME]; snprintf(pin_name, ARRAY_SIZE(pin_name), "%s Spk", @@ -102,25 +231,380 @@ int max98373_trigger(struct snd_pcm_substream *substream, int cmd) return ret; } -struct snd_soc_ops max_98373_ops = { - .hw_params = max98373_hw_params, - .trigger = max98373_trigger, +static const struct snd_soc_ops max_98373_ops = { + .hw_params = max_98373_hw_params, + .trigger = max_98373_trigger, }; -int max98373_spk_codec_init(struct snd_soc_pcm_runtime *rtd) +static int max_98373_spk_codec_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; + unsigned int num_codecs = get_num_codecs(MAX_98373_ACPI_HID); int ret; - ret = snd_soc_dapm_add_routes(&card->dapm, max_98373_dapm_routes, - ARRAY_SIZE(max_98373_dapm_routes)); - if (ret) - dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); + switch (num_codecs) { + case 2: + ret = snd_soc_dapm_new_controls(&card->dapm, maxim_2spk_widgets, + ARRAY_SIZE(maxim_2spk_widgets)); + if (ret) { + dev_err(rtd->dev, "fail to add max98373 widgets, ret %d\n", + ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, maxim_2spk_kcontrols, + ARRAY_SIZE(maxim_2spk_kcontrols)); + if (ret) { + dev_err(rtd->dev, "fail to add max98373 kcontrols, ret %d\n", + ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, max_98373_dapm_routes, + ARRAY_SIZE(max_98373_dapm_routes)); + if (ret) { + dev_err(rtd->dev, "fail to add max98373 routes, ret %d\n", + ret); + return ret; + } + break; + default: + dev_err(rtd->dev, "max98373: invalid num_codecs %d\n", num_codecs); + return -EINVAL; + } + return ret; } -void sof_max98373_codec_conf(struct snd_soc_card *card) +void max_98373_dai_link(struct device *dev, struct snd_soc_dai_link *link) +{ + link->codecs = max_98373_components; + link->num_codecs = ARRAY_SIZE(max_98373_components); + link->init = max_98373_spk_codec_init; + link->ops = &max_98373_ops; +} +EXPORT_SYMBOL_NS(max_98373_dai_link, "SND_SOC_INTEL_SOF_MAXIM_COMMON"); + +void max_98373_set_codec_conf(struct snd_soc_card *card) { card->codec_conf = max_98373_codec_conf; card->num_configs = ARRAY_SIZE(max_98373_codec_conf); } +EXPORT_SYMBOL_NS(max_98373_set_codec_conf, "SND_SOC_INTEL_SOF_MAXIM_COMMON"); + +/* + * Maxim MAX98390 + */ +static const struct snd_soc_dapm_route max_98390_dapm_routes[] = { + /* speaker */ + { "Left Spk", NULL, "Left BE_OUT" }, + { "Right Spk", NULL, "Right BE_OUT" }, +}; + +static const struct snd_kcontrol_new max_98390_tt_kcontrols[] = { + SOC_DAPM_PIN_SWITCH("TL Spk"), + SOC_DAPM_PIN_SWITCH("TR Spk"), +}; + +static const struct snd_soc_dapm_widget max_98390_tt_dapm_widgets[] = { + SND_SOC_DAPM_SPK("TL Spk", NULL), + SND_SOC_DAPM_SPK("TR Spk", NULL), +}; + +static const struct snd_soc_dapm_route max_98390_tt_dapm_routes[] = { + /* Tweeter speaker */ + { "TL Spk", NULL, "Tweeter Left BE_OUT" }, + { "TR Spk", NULL, "Tweeter Right BE_OUT" }, +}; + +static struct snd_soc_codec_conf max_98390_cml_codec_conf[] = { + { + .dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME), + .name_prefix = "Left", + }, + { + .dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME), + .name_prefix = "Right", + }, +}; + +static struct snd_soc_codec_conf max_98390_codec_conf[] = { + { + .dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME), + .name_prefix = "Right", + }, + { + .dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME), + .name_prefix = "Left", + }, + { + .dlc = COMP_CODEC_CONF(MAX_98390_DEV2_NAME), + .name_prefix = "Tweeter Right", + }, + { + .dlc = COMP_CODEC_CONF(MAX_98390_DEV3_NAME), + .name_prefix = "Tweeter Left", + }, +}; + +static struct snd_soc_dai_link_component max_98390_components[] = { + { + .name = MAX_98390_DEV0_NAME, + .dai_name = MAX_98390_CODEC_DAI, + }, + { + .name = MAX_98390_DEV1_NAME, + .dai_name = MAX_98390_CODEC_DAI, + }, + { + .name = MAX_98390_DEV2_NAME, + .dai_name = MAX_98390_CODEC_DAI, + }, + { + .name = MAX_98390_DEV3_NAME, + .dai_name = MAX_98390_CODEC_DAI, + }, +}; + +static const struct { + unsigned int tx; + unsigned int rx; +} max_98390_tdm_mask[] = { + {.tx = 0x01, .rx = 0x3}, + {.tx = 0x02, .rx = 0x3}, + {.tx = 0x04, .rx = 0x3}, + {.tx = 0x08, .rx = 0x3}, +}; + +static int max_98390_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai_link *dai_link = rtd->dai_link; + struct snd_soc_dai *codec_dai; + int i, ret; + + for_each_rtd_codec_dais(rtd, i, codec_dai) { + if (i >= ARRAY_SIZE(max_98390_tdm_mask)) { + dev_err(codec_dai->dev, "invalid codec index %d\n", i); + return -ENODEV; + } + + switch (dai_link->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + /* 4-slot TDM */ + ret = snd_soc_dai_set_tdm_slot(codec_dai, + max_98390_tdm_mask[i].tx, + max_98390_tdm_mask[i].rx, + 4, + params_width(params)); + if (ret < 0) { + dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n", + ret); + return ret; + } + break; + default: + dev_dbg(codec_dai->dev, "codec is in I2S mode\n"); + break; + } + } + return 0; +} + +static int max_98390_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID); + int ret; + + switch (num_codecs) { + case 4: + /* add widgets/controls/dapm for tweeter speakers */ + ret = snd_soc_dapm_new_controls(&card->dapm, max_98390_tt_dapm_widgets, + ARRAY_SIZE(max_98390_tt_dapm_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add tweeter dapm widgets, ret %d\n", + ret); + /* Don't need to add routes if widget addition failed */ + return ret; + } + + ret = snd_soc_add_card_controls(card, max_98390_tt_kcontrols, + ARRAY_SIZE(max_98390_tt_kcontrols)); + if (ret) { + dev_err(rtd->dev, "unable to add tweeter controls, ret %d\n", + ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_tt_dapm_routes, + ARRAY_SIZE(max_98390_tt_dapm_routes)); + if (ret) { + dev_err(rtd->dev, "unable to add tweeter dapm routes, ret %d\n", + ret); + return ret; + } + + fallthrough; + case 2: + /* add regular speakers dapm route */ + ret = snd_soc_dapm_new_controls(&card->dapm, maxim_2spk_widgets, + ARRAY_SIZE(maxim_2spk_widgets)); + if (ret) { + dev_err(rtd->dev, "fail to add max98390 woofer widgets, ret %d\n", + ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, maxim_2spk_kcontrols, + ARRAY_SIZE(maxim_2spk_kcontrols)); + if (ret) { + dev_err(rtd->dev, "fail to add max98390 woofer kcontrols, ret %d\n", + ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_dapm_routes, + ARRAY_SIZE(max_98390_dapm_routes)); + if (ret) { + dev_err(rtd->dev, "unable to add dapm routes, ret %d\n", + ret); + return ret; + } + break; + default: + dev_err(rtd->dev, "invalid codec number %d\n", num_codecs); + return -EINVAL; + } + + return ret; +} + +static const struct snd_soc_ops max_98390_ops = { + .hw_params = max_98390_hw_params, +}; + +void max_98390_dai_link(struct device *dev, struct snd_soc_dai_link *link) +{ + unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID); + + link->codecs = max_98390_components; + + switch (num_codecs) { + case 2: + case 4: + link->num_codecs = num_codecs; + break; + default: + dev_err(dev, "invalid codec number %d for %s\n", num_codecs, + MAX_98390_ACPI_HID); + break; + } + + link->init = max_98390_init; + link->ops = &max_98390_ops; +} +EXPORT_SYMBOL_NS(max_98390_dai_link, "SND_SOC_INTEL_SOF_MAXIM_COMMON"); + +void max_98390_set_codec_conf(struct device *dev, struct snd_soc_card *card) +{ + unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID); + + card->codec_conf = max_98390_codec_conf; + + switch (num_codecs) { + case 2: + if (soc_intel_is_cml()) + card->codec_conf = max_98390_cml_codec_conf; + + fallthrough; + case 4: + card->num_configs = num_codecs; + break; + default: + dev_err(dev, "invalid codec number %d for %s\n", num_codecs, + MAX_98390_ACPI_HID); + break; + } +} +EXPORT_SYMBOL_NS(max_98390_set_codec_conf, "SND_SOC_INTEL_SOF_MAXIM_COMMON"); + +/* + * Maxim MAX98357A/MAX98360A + */ +static const struct snd_kcontrol_new max_98357a_kcontrols[] = { + SOC_DAPM_PIN_SWITCH("Spk"), +}; + +static const struct snd_soc_dapm_widget max_98357a_dapm_widgets[] = { + SND_SOC_DAPM_SPK("Spk", NULL), +}; + +static const struct snd_soc_dapm_route max_98357a_dapm_routes[] = { + /* speaker */ + {"Spk", NULL, "Speaker"}, +}; + +static struct snd_soc_dai_link_component max_98357a_components[] = { + { + .name = MAX_98357A_DEV0_NAME, + .dai_name = MAX_98357A_CODEC_DAI, + } +}; + +static struct snd_soc_dai_link_component max_98360a_components[] = { + { + .name = MAX_98360A_DEV0_NAME, + .dai_name = MAX_98357A_CODEC_DAI, + } +}; + +static int max_98357a_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_dapm_new_controls(&card->dapm, max_98357a_dapm_widgets, + ARRAY_SIZE(max_98357a_dapm_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add dapm controls, ret %d\n", ret); + /* Don't need to add routes if widget addition failed */ + return ret; + } + + ret = snd_soc_add_card_controls(card, max_98357a_kcontrols, + ARRAY_SIZE(max_98357a_kcontrols)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, max_98357a_dapm_routes, + ARRAY_SIZE(max_98357a_dapm_routes)); + + if (ret) + dev_err(rtd->dev, "unable to add dapm routes, ret %d\n", ret); + + return ret; +} + +void max_98357a_dai_link(struct snd_soc_dai_link *link) +{ + link->codecs = max_98357a_components; + link->num_codecs = ARRAY_SIZE(max_98357a_components); + link->init = max_98357a_init; +} +EXPORT_SYMBOL_NS(max_98357a_dai_link, "SND_SOC_INTEL_SOF_MAXIM_COMMON"); + +void max_98360a_dai_link(struct snd_soc_dai_link *link) +{ + link->codecs = max_98360a_components; + link->num_codecs = ARRAY_SIZE(max_98360a_components); + link->init = max_98357a_init; +} +EXPORT_SYMBOL_NS(max_98360a_dai_link, "SND_SOC_INTEL_SOF_MAXIM_COMMON"); + +MODULE_DESCRIPTION("ASoC Intel SOF Maxim helpers"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/boards/sof_maxim_common.h b/sound/soc/intel/boards/sof_maxim_common.h index 5240b1c9d379..3d34c7dae6f5 100644 --- a/sound/soc/intel/boards/sof_maxim_common.h +++ b/sound/soc/intel/boards/sof_maxim_common.h @@ -11,17 +11,38 @@ #define __SOF_MAXIM_COMMON_H #include <sound/soc.h> +#include <sound/soc-acpi-intel-ssp-common.h> +/* + * Maxim MAX98373 + */ #define MAX_98373_CODEC_DAI "max98373-aif1" -#define MAX_98373_DEV0_NAME "i2c-MX98373:00" -#define MAX_98373_DEV1_NAME "i2c-MX98373:01" +#define MAX_98373_DEV0_NAME "i2c-" MAX_98373_ACPI_HID ":00" +#define MAX_98373_DEV1_NAME "i2c-" MAX_98373_ACPI_HID ":01" + +void max_98373_dai_link(struct device *dev, struct snd_soc_dai_link *link); +void max_98373_set_codec_conf(struct snd_soc_card *card); -extern struct snd_soc_dai_link_component max_98373_components[2]; -extern struct snd_soc_ops max_98373_ops; -extern const struct snd_soc_dapm_route max_98373_dapm_routes[]; +/* + * Maxim MAX98390 + */ +#define MAX_98390_CODEC_DAI "max98390-aif1" +#define MAX_98390_DEV0_NAME "i2c-" MAX_98390_ACPI_HID ":00" +#define MAX_98390_DEV1_NAME "i2c-" MAX_98390_ACPI_HID ":01" +#define MAX_98390_DEV2_NAME "i2c-" MAX_98390_ACPI_HID ":02" +#define MAX_98390_DEV3_NAME "i2c-" MAX_98390_ACPI_HID ":03" + +void max_98390_dai_link(struct device *dev, struct snd_soc_dai_link *link); +void max_98390_set_codec_conf(struct device *dev, struct snd_soc_card *card); + +/* + * Maxim MAX98357A/MAX98360A + */ +#define MAX_98357A_CODEC_DAI "HiFi" +#define MAX_98357A_DEV0_NAME MAX_98357A_ACPI_HID ":00" +#define MAX_98360A_DEV0_NAME MAX_98360A_ACPI_HID ":00" -int max98373_spk_codec_init(struct snd_soc_pcm_runtime *rtd); -void sof_max98373_codec_conf(struct snd_soc_card *card); -int max98373_trigger(struct snd_pcm_substream *substream, int cmd); +void max_98357a_dai_link(struct snd_soc_dai_link *link); +void max_98360a_dai_link(struct snd_soc_dai_link *link); #endif /* __SOF_MAXIM_COMMON_H */ diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c new file mode 100644 index 000000000000..72ce32e2cd57 --- /dev/null +++ b/sound/soc/intel/boards/sof_nau8825.c @@ -0,0 +1,345 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright(c) 2021 Intel Corporation. +// Copyright(c) 2021 Nuvoton Corporation. + +/* + * Intel SOF Machine Driver with Nuvoton headphone codec NAU8825 + * and speaker codec RT1019P MAX98360a or MAX98373 + */ +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/dmi.h> +#include <sound/core.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/sof.h> +#include <sound/soc-acpi.h> +#include "../../codecs/nau8825.h" +#include "../common/soc-intel-quirks.h" +#include "sof_board_helpers.h" +#include "sof_realtek_common.h" +#include "sof_maxim_common.h" +#include "sof_nuvoton_common.h" + +static unsigned long sof_nau8825_quirk = SOF_SSP_PORT_CODEC(0); + +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static int sof_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; + struct snd_soc_jack *jack = &ctx->headset_jack; + int ret; + + /* + * Headset buttons map to the google Reference headset. + * These can be configured by userspace. + */ + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + jack, + jack_pins, + ARRAY_SIZE(jack_pins)); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); + return ret; + } + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + + ret = snd_soc_component_set_jack(component, jack, NULL); + if (ret) { + dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); + return ret; + } + + return ret; +}; + +static void sof_nau8825_codec_exit(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; + + snd_soc_component_set_jack(component, NULL, NULL); +} + +static int sof_nau8825_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + int clk_freq, ret; + + clk_freq = sof_dai_get_bclk(rtd); /* BCLK freq */ + + if (clk_freq <= 0) { + dev_err(rtd->dev, "get bclk freq failed: %d\n", clk_freq); + return -EINVAL; + } + + /* Configure clock for codec */ + ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_BLK, 0, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec_dai->dev, "can't set BCLK clock %d\n", ret); + return ret; + } + + /* Configure pll for codec */ + ret = snd_soc_dai_set_pll(codec_dai, 0, 0, clk_freq, + params_rate(params) * 256); + if (ret < 0) { + dev_err(codec_dai->dev, "can't set BCLK: %d\n", ret); + return ret; + } + + return ret; +} + +static const struct snd_soc_ops sof_nau8825_ops = { + .hw_params = sof_nau8825_hw_params, +}; + +static int sof_card_late_probe(struct snd_soc_card *card) +{ + struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_dapm_context *dapm = &card->dapm; + int err; + + if (ctx->amp_type == CODEC_MAX98373) { + /* Disable Left and Right Spk pin after boot */ + snd_soc_dapm_disable_pin(dapm, "Left Spk"); + snd_soc_dapm_disable_pin(dapm, "Right Spk"); + err = snd_soc_dapm_sync(dapm); + if (err < 0) + return err; + } + + return sof_intel_board_card_late_probe(card); +} + +static const struct snd_kcontrol_new sof_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const struct snd_soc_dapm_widget sof_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + +static const struct snd_soc_dapm_route sof_map[] = { + /* HP jack connectors - unknown if we have jack detection */ + { "Headphone Jack", NULL, "HPOL" }, + { "Headphone Jack", NULL, "HPOR" }, + + /* other jacks */ + { "MIC", NULL, "Headset Mic" }, +}; + +/* sof audio machine driver for nau8825 codec */ +static struct snd_soc_card sof_audio_card_nau8825 = { + .name = "nau8825", /* the sof- prefix is added by the core */ + .owner = THIS_MODULE, + .controls = sof_controls, + .num_controls = ARRAY_SIZE(sof_controls), + .dapm_widgets = sof_widgets, + .num_dapm_widgets = ARRAY_SIZE(sof_widgets), + .dapm_routes = sof_map, + .num_dapm_routes = ARRAY_SIZE(sof_map), + .fully_routed = true, + .late_probe = sof_card_late_probe, +}; + +static struct snd_soc_dai_link_component nau8825_component[] = { + { + .name = "i2c-10508825:00", + .dai_name = "nau8825-hifi", + } +}; + +static int +sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card, + struct sof_card_private *ctx) +{ + int ret; + + ret = sof_intel_board_set_dai_link(dev, card, ctx); + if (ret) + return ret; + + if (!ctx->codec_link) { + dev_err(dev, "codec link not available"); + return -EINVAL; + } + + /* codec-specific fields for headphone codec */ + ctx->codec_link->codecs = nau8825_component; + ctx->codec_link->num_codecs = ARRAY_SIZE(nau8825_component); + ctx->codec_link->init = sof_nau8825_codec_init; + ctx->codec_link->exit = sof_nau8825_codec_exit; + ctx->codec_link->ops = &sof_nau8825_ops; + + if (ctx->amp_type == CODEC_NONE) + return 0; + + if (!ctx->amp_link) { + dev_err(dev, "amp link not available"); + return -EINVAL; + } + + /* codec-specific fields for speaker amplifier */ + switch (ctx->amp_type) { + case CODEC_MAX98360A: + max_98360a_dai_link(ctx->amp_link); + break; + case CODEC_MAX98373: + max_98373_dai_link(dev, ctx->amp_link); + break; + case CODEC_NAU8318: + nau8318_set_dai_link(ctx->amp_link); + break; + case CODEC_RT1015P: + sof_rt1015p_dai_link(ctx->amp_link); + break; + case CODEC_RT1019P: + sof_rt1019p_dai_link(ctx->amp_link); + break; + default: + dev_err(dev, "invalid amp type %d\n", ctx->amp_type); + return -EINVAL; + } + + return 0; +} + +static int sof_audio_probe(struct platform_device *pdev) +{ + struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; + struct sof_card_private *ctx; + int ret; + + if (pdev->id_entry && pdev->id_entry->driver_data) + sof_nau8825_quirk = (unsigned long)pdev->id_entry->driver_data; + + dev_dbg(&pdev->dev, "sof_nau8825_quirk = %lx\n", sof_nau8825_quirk); + + /* initialize ctx with board quirk */ + ctx = sof_intel_board_get_ctx(&pdev->dev, sof_nau8825_quirk); + if (!ctx) + return -ENOMEM; + + if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) + ctx->hdmi.idisp_codec = true; + + /* update dai_link */ + ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_nau8825, ctx); + if (ret) + return ret; + + /* update codec_conf */ + switch (ctx->amp_type) { + case CODEC_MAX98373: + max_98373_set_codec_conf(&sof_audio_card_nau8825); + break; + case CODEC_RT1015P: + sof_rt1015p_codec_conf(&sof_audio_card_nau8825); + break; + case CODEC_MAX98360A: + case CODEC_NAU8318: + case CODEC_RT1019P: + case CODEC_NONE: + /* no codec conf required */ + break; + default: + dev_err(&pdev->dev, "invalid amp type %d\n", ctx->amp_type); + return -EINVAL; + } + + sof_audio_card_nau8825.dev = &pdev->dev; + + /* set platform name for each dailink */ + ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_nau8825, + mach->mach_params.platform); + if (ret) + return ret; + + snd_soc_card_set_drvdata(&sof_audio_card_nau8825, ctx); + + return devm_snd_soc_register_card(&pdev->dev, + &sof_audio_card_nau8825); +} + +static const struct platform_device_id board_ids[] = { + { + .name = "adl_rt1019p_8825", + .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(2) | + SOF_NUM_IDISP_HDMI(4)), + }, + { + .name = "adl_nau8825_def", + .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1) | + SOF_NUM_IDISP_HDMI(4) | + SOF_SSP_PORT_BT_OFFLOAD(2) | + SOF_BT_OFFLOAD_PRESENT), + }, + { + .name = "rpl_nau8825_def", + .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1) | + SOF_NUM_IDISP_HDMI(4) | + SOF_SSP_PORT_BT_OFFLOAD(2) | + SOF_BT_OFFLOAD_PRESENT), + }, + { + .name = "mtl_nau8825_def", + .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(2) | + SOF_SSP_PORT_AMP(0) | + SOF_SSP_PORT_BT_OFFLOAD(1) | + SOF_BT_OFFLOAD_PRESENT), + }, + { } +}; +MODULE_DEVICE_TABLE(platform, board_ids); + +static struct platform_driver sof_audio = { + .probe = sof_audio_probe, + .driver = { + .name = "sof_nau8825", + .pm = &snd_soc_pm_ops, + }, + .id_table = board_ids, +}; +module_platform_driver(sof_audio) + +/* Module information */ +MODULE_DESCRIPTION("SOF Audio Machine driver for NAU8825"); +MODULE_AUTHOR("David Lin <ctlin0@nuvoton.com>"); +MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>"); +MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_MAXIM_COMMON"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_NUVOTON_COMMON"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_REALTEK_COMMON"); diff --git a/sound/soc/intel/boards/sof_nuvoton_common.c b/sound/soc/intel/boards/sof_nuvoton_common.c new file mode 100644 index 000000000000..ed41cb6f7fa5 --- /dev/null +++ b/sound/soc/intel/boards/sof_nuvoton_common.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * This file defines data structures and functions used in Machine + * Driver for Intel platforms with Nuvoton Codecs. + * + * Copyright 2023 Intel Corporation. + */ +#include <linux/module.h> +#include <sound/sof.h> +#include "sof_nuvoton_common.h" + +/* + * Nuvoton NAU8318 + */ +static const struct snd_kcontrol_new nau8318_kcontrols[] = { + SOC_DAPM_PIN_SWITCH("Spk"), +}; + +static const struct snd_soc_dapm_widget nau8318_widgets[] = { + SND_SOC_DAPM_SPK("Spk", NULL), +}; + +static const struct snd_soc_dapm_route nau8318_routes[] = { + { "Spk", NULL, "Speaker" }, +}; + +static struct snd_soc_dai_link_component nau8318_components[] = { + { + .name = NAU8318_DEV0_NAME, + .dai_name = NAU8318_CODEC_DAI, + } +}; + +static int nau8318_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_dapm_new_controls(&card->dapm, nau8318_widgets, + ARRAY_SIZE(nau8318_widgets)); + if (ret) { + dev_err(rtd->dev, "fail to add nau8318 widgets, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, nau8318_kcontrols, + ARRAY_SIZE(nau8318_kcontrols)); + if (ret) { + dev_err(rtd->dev, "fail to add nau8318 kcontrols, ret %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, nau8318_routes, + ARRAY_SIZE(nau8318_routes)); + + if (ret) { + dev_err(rtd->dev, "fail to add nau8318 routes, ret %d\n", ret); + return ret; + } + + return ret; +} + +void nau8318_set_dai_link(struct snd_soc_dai_link *link) +{ + link->codecs = nau8318_components; + link->num_codecs = ARRAY_SIZE(nau8318_components); + link->init = nau8318_init; +} +EXPORT_SYMBOL_NS(nau8318_set_dai_link, "SND_SOC_INTEL_SOF_NUVOTON_COMMON"); + +MODULE_DESCRIPTION("ASoC Intel SOF Nuvoton helpers"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/boards/sof_nuvoton_common.h b/sound/soc/intel/boards/sof_nuvoton_common.h new file mode 100644 index 000000000000..8a0f283260e7 --- /dev/null +++ b/sound/soc/intel/boards/sof_nuvoton_common.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * This file defines data structures used in Machine Driver for Intel + * platforms with Nuvoton Codecs. + * + * Copyright 2023 Intel Corporation. + */ +#ifndef __SOF_NUVOTON_COMMON_H +#define __SOF_NUVOTON_COMMON_H + +#include <sound/soc.h> +#include <sound/soc-acpi-intel-ssp-common.h> + +/* + * Nuvoton NAU8318 + */ +#define NAU8318_CODEC_DAI "nau8315-hifi" +#define NAU8318_DEV0_NAME "i2c-" NAU8318_ACPI_HID ":00" + +void nau8318_set_dai_link(struct snd_soc_dai_link *link); + +#endif /* __SOF_NUVOTON_COMMON_H */ diff --git a/sound/soc/intel/boards/sof_pcm512x.c b/sound/soc/intel/boards/sof_pcm512x.c index d2b0456236c7..2f43710c1bae 100644 --- a/sound/soc/intel/boards/sof_pcm512x.c +++ b/sound/soc/intel/boards/sof_pcm512x.c @@ -26,11 +26,16 @@ #define SOF_PCM512X_SSP_CODEC(quirk) ((quirk) & GENMASK(3, 0)) #define SOF_PCM512X_SSP_CODEC_MASK (GENMASK(3, 0)) +#define SOF_PCM512X_ENABLE_SSP_CAPTURE BIT(4) +#define SOF_PCM512X_ENABLE_DMIC BIT(5) #define IDISP_CODEC_MASK 0x4 /* Default: SSP5 */ -static unsigned long sof_pcm512x_quirk = SOF_PCM512X_SSP_CODEC(5); +static unsigned long sof_pcm512x_quirk = + SOF_PCM512X_SSP_CODEC(5) | + SOF_PCM512X_ENABLE_SSP_CAPTURE | + SOF_PCM512X_ENABLE_DMIC; static bool is_legacy_cpu; @@ -66,7 +71,7 @@ static const struct dmi_system_id sof_pcm512x_quirk_table[] = { static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd) { struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); struct sof_hdmi_pcm *pcm; pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); @@ -84,7 +89,7 @@ static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd) static int sof_pcm512x_codec_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_component *codec = asoc_rtd_to_codec(rtd, 0)->component; + struct snd_soc_component *codec = snd_soc_rtd_to_codec(rtd, 0)->component; snd_soc_component_update_bits(codec, PCM512x_GPIO_EN, 0x08, 0x08); snd_soc_component_update_bits(codec, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02); @@ -96,8 +101,8 @@ static int sof_pcm512x_codec_init(struct snd_soc_pcm_runtime *rtd) static int aif1_startup(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_component *codec = asoc_rtd_to_codec(rtd, 0)->component; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_component *codec = snd_soc_rtd_to_codec(rtd, 0)->component; snd_soc_component_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); @@ -107,8 +112,8 @@ static int aif1_startup(struct snd_pcm_substream *substream) static void aif1_shutdown(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_component *codec = asoc_rtd_to_codec(rtd, 0)->component; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_component *codec = snd_soc_rtd_to_codec(rtd, 0)->component; snd_soc_component_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08, 0x00); @@ -241,12 +246,11 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].init = sof_pcm512x_codec_init; links[id].ops = &sof_pcm512x_ops; - links[id].nonatomic = true; - links[id].dpcm_playback = 1; /* * capture only supported with specific versions of the Hifiberry DAC+ - * links[id].dpcm_capture = 1; */ + if (!(sof_pcm512x_quirk & SOF_PCM512X_ENABLE_SSP_CAPTURE)) + links[id].playback_only = 1; links[id].no_pcm = 1; links[id].cpus = &cpus[id]; links[id].num_cpus = 1; @@ -289,7 +293,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].ignore_suspend = 1; - links[id].dpcm_capture = 1; + links[id].capture_only = 1; links[id].no_pcm = 1; id++; } @@ -326,8 +330,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, devm_kasprintf(dev, GFP_KERNEL, "intel-hdmi-hifi%d", i); } else { - idisp_components[i - 1].name = "snd-soc-dummy"; - idisp_components[i - 1].dai_name = "snd-soc-dummy-dai"; + idisp_components[i - 1] = snd_soc_dummy_dlc; } if (!idisp_components[i - 1].dai_name) goto devm_err; @@ -337,7 +340,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].init = sof_hdmi_init; - links[id].dpcm_playback = 1; + links[id].playback_only = 1; links[id].no_pcm = 1; id++; } @@ -367,8 +370,7 @@ static int sof_audio_probe(struct platform_device *pdev) sof_pcm512x_quirk = SOF_PCM512X_SSP_CODEC(2); } else { dmic_be_num = 2; - if (mach->mach_params.common_hdmi_codec_drv && - (mach->mach_params.codec_mask & IDISP_CODEC_MASK)) + if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) ctx->idisp_codec = true; /* links are always present in topology */ @@ -381,6 +383,9 @@ static int sof_audio_probe(struct platform_device *pdev) ssp_codec = sof_pcm512x_quirk & SOF_PCM512X_SSP_CODEC_MASK; + if (!(sof_pcm512x_quirk & SOF_PCM512X_ENABLE_DMIC)) + dmic_be_num = 0; + /* compute number of dai links */ sof_audio_card_pcm512x.num_links = 1 + dmic_be_num + hdmi_num; @@ -408,10 +413,10 @@ static int sof_audio_probe(struct platform_device *pdev) &sof_audio_card_pcm512x); } -static int sof_pcm512x_remove(struct platform_device *pdev) +static void sof_pcm512x_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); - struct snd_soc_component *component = NULL; + struct snd_soc_component *component; for_each_card_components(card, component) { if (!strcmp(component->name, pcm512x_component[0].name)) { @@ -419,8 +424,6 @@ static int sof_pcm512x_remove(struct platform_device *pdev) break; } } - - return 0; } static struct platform_driver sof_audio = { @@ -437,3 +440,4 @@ MODULE_DESCRIPTION("ASoC Intel(R) SOF + PCM512x Machine driver"); MODULE_AUTHOR("Pierre-Louis Bossart"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:sof_pcm512x"); +MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON"); diff --git a/sound/soc/intel/boards/sof_realtek_common.c b/sound/soc/intel/boards/sof_realtek_common.c new file mode 100644 index 000000000000..600707d403b9 --- /dev/null +++ b/sound/soc/intel/boards/sof_realtek_common.c @@ -0,0 +1,687 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2020 Intel Corporation + +#include <linux/device.h> +#include <linux/kernel.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include <sound/soc-dai.h> +#include <sound/soc-dapm.h> +#include <sound/sof.h> +#include <uapi/sound/asound.h> +#include "../../codecs/rt1011.h" +#include "../../codecs/rt1015.h" +#include "../../codecs/rt1308.h" +#include "../common/soc-intel-quirks.h" +#include "sof_realtek_common.h" + +/* + * Common structures and functions + */ +static const struct snd_kcontrol_new realtek_2spk_kcontrols[] = { + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), + +}; + +static const struct snd_soc_dapm_widget realtek_2spk_widgets[] = { + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), +}; + +static const struct snd_kcontrol_new realtek_4spk_kcontrols[] = { + SOC_DAPM_PIN_SWITCH("WL Ext Spk"), + SOC_DAPM_PIN_SWITCH("WR Ext Spk"), + SOC_DAPM_PIN_SWITCH("TL Ext Spk"), + SOC_DAPM_PIN_SWITCH("TR Ext Spk"), +}; + +static const struct snd_soc_dapm_widget realtek_4spk_widgets[] = { + SND_SOC_DAPM_SPK("WL Ext Spk", NULL), + SND_SOC_DAPM_SPK("WR Ext Spk", NULL), + SND_SOC_DAPM_SPK("TL Ext Spk", NULL), + SND_SOC_DAPM_SPK("TR Ext Spk", NULL), +}; + +/* helper function to get the number of specific codec */ +static unsigned int get_num_codecs(const char *hid) +{ + struct acpi_device *adev; + unsigned int dev_num = 0; + + for_each_acpi_dev_match(adev, hid, NULL, -1) + dev_num++; + + return dev_num; +} + +/* + * Realtek ALC1011 + */ +static const struct snd_soc_dapm_route speaker_map_lr[] = { + /* speaker */ + { "Left Spk", NULL, "Left SPO" }, + { "Right Spk", NULL, "Right SPO" }, +}; + +static const struct snd_soc_dapm_route rt1011_4spk_routes[] = { + {"WL Ext Spk", NULL, "WL SPO" }, + {"WR Ext Spk", NULL, "WR SPO" }, + {"TL Ext Spk", NULL, "TL SPO" }, + {"TR Ext Spk", NULL, "TR SPO" }, +}; + +static struct snd_soc_codec_conf rt1011_2spk_codec_confs[] = { + { + .dlc = COMP_CODEC_CONF(RT1011_DEV0_NAME), + .name_prefix = "Left", + }, + { + .dlc = COMP_CODEC_CONF(RT1011_DEV1_NAME), + .name_prefix = "Right", + }, +}; + +static struct snd_soc_codec_conf rt1011_4spk_codec_confs[] = { + { + .dlc = COMP_CODEC_CONF(RT1011_DEV0_NAME), + .name_prefix = "WL", + }, + { + .dlc = COMP_CODEC_CONF(RT1011_DEV1_NAME), + .name_prefix = "WR", + }, + { + .dlc = COMP_CODEC_CONF(RT1011_DEV2_NAME), + .name_prefix = "TL", + }, + { + .dlc = COMP_CODEC_CONF(RT1011_DEV3_NAME), + .name_prefix = "TR", + }, +}; + +static struct snd_soc_dai_link_component rt1011_dai_link_components[] = { + { + .name = RT1011_DEV0_NAME, + .dai_name = RT1011_CODEC_DAI, + }, + { + .name = RT1011_DEV1_NAME, + .dai_name = RT1011_CODEC_DAI, + }, + { + .name = RT1011_DEV2_NAME, + .dai_name = RT1011_CODEC_DAI, + }, + { + .name = RT1011_DEV3_NAME, + .dai_name = RT1011_CODEC_DAI, + }, +}; + +static const struct { + unsigned int tx; + unsigned int rx; +} rt1011_tdm_mask[] = { + {.tx = 0x4, .rx = 0x1}, + {.tx = 0x8, .rx = 0x2}, + {.tx = 0x1, .rx = 0x1}, + {.tx = 0x2, .rx = 0x2}, +}; + +static int rt1011_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai; + int srate, i, ret = 0; + + srate = params_rate(params); + + for_each_rtd_codec_dais(rtd, i, codec_dai) { + /* 100 Fs to drive 24 bit data */ + ret = snd_soc_dai_set_pll(codec_dai, 0, RT1011_PLL1_S_BCLK, + 100 * srate, 256 * srate); + if (ret < 0) { + dev_err(codec_dai->dev, "fail to set pll, ret %d\n", + ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, RT1011_FS_SYS_PRE_S_PLL1, + 256 * srate, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec_dai->dev, "fail to set sysclk, ret %d\n", + ret); + return ret; + } + + if (i >= ARRAY_SIZE(rt1011_tdm_mask)) { + dev_err(codec_dai->dev, "invalid codec index %d\n", + i); + return -ENODEV; + } + + ret = snd_soc_dai_set_tdm_slot(codec_dai, rt1011_tdm_mask[i].tx, + rt1011_tdm_mask[i].rx, 4, + params_width(params)); + if (ret < 0) { + dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n", + ret); + return ret; + } + } + + return 0; +} + +static const struct snd_soc_ops rt1011_ops = { + .hw_params = rt1011_hw_params, +}; + +static int rt1011_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + unsigned int num_codecs = get_num_codecs(RT1011_ACPI_HID); + int ret; + + switch (num_codecs) { + case 2: + if (!soc_intel_is_cml()) { + ret = snd_soc_dapm_new_controls(&card->dapm, realtek_2spk_widgets, + ARRAY_SIZE(realtek_2spk_widgets)); + if (ret) { + dev_err(rtd->dev, "fail to add rt1011 widgets, ret %d\n", + ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, realtek_2spk_kcontrols, + ARRAY_SIZE(realtek_2spk_kcontrols)); + if (ret) { + dev_err(rtd->dev, "fail to add rt1011 kcontrols, ret %d\n", + ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, speaker_map_lr, + ARRAY_SIZE(speaker_map_lr)); + if (ret) { + dev_err(rtd->dev, "fail to add rt1011 routes, ret %d\n", + ret); + return ret; + } + + break; + } + + /* + * register speaker widgets "WL Ext Spk" and "WR Ext Spk" to + * keep backward compatible with cml devices + */ + fallthrough; + case 4: + ret = snd_soc_dapm_new_controls(&card->dapm, realtek_4spk_widgets, + num_codecs); + if (ret) { + dev_err(rtd->dev, "fail to add rt1011 widgets, ret %d\n", + ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, realtek_4spk_kcontrols, + num_codecs); + if (ret) { + dev_err(rtd->dev, "fail to add rt1011 controls, ret %d\n", + ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, rt1011_4spk_routes, + num_codecs); + if (ret) { + dev_err(rtd->dev, "fail to add rt1011 routes, ret %d\n", + ret); + return ret; + } + break; + default: + dev_err(rtd->dev, "rt1011: invalid num_codecs %d\n", num_codecs); + return -EINVAL; + } + + return ret; +} + +void sof_rt1011_dai_link(struct device *dev, struct snd_soc_dai_link *link) +{ + unsigned int num_codecs = get_num_codecs(RT1011_ACPI_HID); + + link->codecs = rt1011_dai_link_components; + + switch (num_codecs) { + case 2: + case 4: + link->num_codecs = num_codecs; + break; + default: + dev_err(dev, "rt1011: invalid num_codecs %d\n", num_codecs); + break; + } + + link->init = rt1011_init; + link->ops = &rt1011_ops; +} +EXPORT_SYMBOL_NS(sof_rt1011_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON"); + +void sof_rt1011_codec_conf(struct device *dev, struct snd_soc_card *card) +{ + unsigned int num_codecs = get_num_codecs(RT1011_ACPI_HID); + + switch (num_codecs) { + case 2: + if (soc_intel_is_cml()) { + /* + * use name prefix 'WL' and 'WR' for speaker widgets to + * keep backward compatible with cml devices + */ + card->codec_conf = rt1011_4spk_codec_confs; + } else { + card->codec_conf = rt1011_2spk_codec_confs; + } + + card->num_configs = num_codecs; + break; + case 4: + card->codec_conf = rt1011_4spk_codec_confs; + card->num_configs = ARRAY_SIZE(rt1011_4spk_codec_confs); + break; + default: + dev_err(dev, "rt1011: invalid num_codecs %d\n", num_codecs); + break; + } + +} +EXPORT_SYMBOL_NS(sof_rt1011_codec_conf, "SND_SOC_INTEL_SOF_REALTEK_COMMON"); + +/* + * rt1015: i2c mode driver for ALC1015 and ALC1015Q + * rt1015p: auto-mode driver for ALC1015, ALC1015Q, and ALC1015Q-VB + * + * For stereo output, there are always two amplifiers on the board. + * However, the ACPI implements only one device instance (UID=0) if they + * are sharing the same enable pin. This is the case of rt1015p. + */ +static const struct snd_soc_dapm_route rt1015p_dapm_routes[] = { + /* speaker */ + { "Left Spk", NULL, "Speaker" }, + { "Right Spk", NULL, "Speaker" }, +}; + +static struct snd_soc_dai_link_component rt1015p_dai_link_components[] = { + { + .name = RT1015P_DEV0_NAME, + .dai_name = RT1015P_CODEC_DAI, + }, +}; + +static int rt1015p_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + /* reserved for debugging purpose */ + + return 0; +} + +static const struct snd_soc_ops rt1015p_ops = { + .hw_params = rt1015p_hw_params, +}; + +static int rt1015p_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_dapm_new_controls(&card->dapm, realtek_2spk_widgets, + ARRAY_SIZE(realtek_2spk_widgets)); + if (ret) { + dev_err(rtd->dev, "fail to add rt1015p widgets, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, realtek_2spk_kcontrols, + ARRAY_SIZE(realtek_2spk_kcontrols)); + if (ret) { + dev_err(rtd->dev, "fail to add rt1015p kcontrols, ret %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, rt1015p_dapm_routes, + ARRAY_SIZE(rt1015p_dapm_routes)); + if (ret) + dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); + return ret; +} + +void sof_rt1015p_dai_link(struct snd_soc_dai_link *link) +{ + link->codecs = rt1015p_dai_link_components; + link->num_codecs = ARRAY_SIZE(rt1015p_dai_link_components); + link->init = rt1015p_init; + link->ops = &rt1015p_ops; +} +EXPORT_SYMBOL_NS(sof_rt1015p_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON"); + +void sof_rt1015p_codec_conf(struct snd_soc_card *card) +{ +} +EXPORT_SYMBOL_NS(sof_rt1015p_codec_conf, "SND_SOC_INTEL_SOF_REALTEK_COMMON"); + +/* + * RT1015 audio amplifier + */ + +static const struct { + unsigned int tx; + unsigned int rx; +} rt1015_tdm_mask[] = { + {.tx = 0x0, .rx = 0x1}, + {.tx = 0x0, .rx = 0x2}, +}; + +static int rt1015_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai_link *dai_link = rtd->dai_link; + struct snd_soc_dai *codec_dai; + int i, clk_freq; + int ret = 0; + + clk_freq = sof_dai_get_bclk(rtd); + + if (clk_freq <= 0) { + dev_err(rtd->dev, "fail to get bclk freq, ret %d\n", clk_freq); + return -EINVAL; + } + + for_each_rtd_codec_dais(rtd, i, codec_dai) { + ret = snd_soc_dai_set_pll(codec_dai, 0, RT1015_PLL_S_BCLK, + clk_freq, + params_rate(params) * 256); + if (ret) { + dev_err(codec_dai->dev, "fail to set pll, ret %d\n", + ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, RT1015_SCLK_S_PLL, + params_rate(params) * 256, + SND_SOC_CLOCK_IN); + if (ret) { + dev_err(codec_dai->dev, "fail to set sysclk, ret %d\n", + ret); + return ret; + } + + switch (dai_link->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + /* 4-slot TDM */ + ret = snd_soc_dai_set_tdm_slot(codec_dai, + rt1015_tdm_mask[i].tx, + rt1015_tdm_mask[i].rx, + 4, + params_width(params)); + if (ret < 0) { + dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n", + ret); + return ret; + } + break; + default: + dev_dbg(codec_dai->dev, "codec is in I2S mode\n"); + break; + } + } + + return ret; +} + +static const struct snd_soc_ops rt1015_ops = { + .hw_params = rt1015_hw_params, +}; + +static struct snd_soc_codec_conf rt1015_amp_conf[] = { + { + .dlc = COMP_CODEC_CONF(RT1015_DEV0_NAME), + .name_prefix = "Left", + }, + { + .dlc = COMP_CODEC_CONF(RT1015_DEV1_NAME), + .name_prefix = "Right", + }, +}; + +static struct snd_soc_dai_link_component rt1015_components[] = { + { + .name = RT1015_DEV0_NAME, + .dai_name = RT1015_CODEC_DAI, + }, + { + .name = RT1015_DEV1_NAME, + .dai_name = RT1015_CODEC_DAI, + }, +}; + +static int speaker_codec_init_lr(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + unsigned int num_codecs = get_num_codecs(RT1015_ACPI_HID); + int ret; + + switch (num_codecs) { + case 2: + ret = snd_soc_dapm_new_controls(&card->dapm, realtek_2spk_widgets, + ARRAY_SIZE(realtek_2spk_widgets)); + if (ret) { + dev_err(rtd->dev, "fail to add rt1015 widgets, ret %d\n", + ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, realtek_2spk_kcontrols, + ARRAY_SIZE(realtek_2spk_kcontrols)); + if (ret) { + dev_err(rtd->dev, "fail to add rt1015 kcontrols, ret %d\n", + ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&rtd->card->dapm, speaker_map_lr, + ARRAY_SIZE(speaker_map_lr)); + if (ret) { + dev_err(rtd->dev, "fail to add rt1015 routes, ret %d\n", + ret); + return ret; + } + break; + default: + dev_err(rtd->dev, "rt1015: invalid num_codecs %d\n", num_codecs); + return -EINVAL; + } + + return ret; +} + +void sof_rt1015_codec_conf(struct snd_soc_card *card) +{ + card->codec_conf = rt1015_amp_conf; + card->num_configs = ARRAY_SIZE(rt1015_amp_conf); +} +EXPORT_SYMBOL_NS(sof_rt1015_codec_conf, "SND_SOC_INTEL_SOF_REALTEK_COMMON"); + +void sof_rt1015_dai_link(struct snd_soc_dai_link *link) +{ + link->codecs = rt1015_components; + link->num_codecs = ARRAY_SIZE(rt1015_components); + link->init = speaker_codec_init_lr; + link->ops = &rt1015_ops; +} +EXPORT_SYMBOL_NS(sof_rt1015_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON"); + +/* + * RT1308 audio amplifier + */ +static const struct snd_kcontrol_new rt1308_kcontrols[] = { + SOC_DAPM_PIN_SWITCH("Speakers"), +}; + +static const struct snd_soc_dapm_widget rt1308_dapm_widgets[] = { + SND_SOC_DAPM_SPK("Speakers", NULL), +}; + +static const struct snd_soc_dapm_route rt1308_dapm_routes[] = { + /* speaker */ + {"Speakers", NULL, "SPOL"}, + {"Speakers", NULL, "SPOR"}, +}; + +static struct snd_soc_dai_link_component rt1308_components[] = { + { + .name = RT1308_DEV0_NAME, + .dai_name = RT1308_CODEC_DAI, + } +}; + +static int rt1308_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_dapm_new_controls(&card->dapm, rt1308_dapm_widgets, + ARRAY_SIZE(rt1308_dapm_widgets)); + if (ret) { + dev_err(rtd->dev, "fail to add dapm controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, rt1308_kcontrols, + ARRAY_SIZE(rt1308_kcontrols)); + if (ret) { + dev_err(rtd->dev, "fail to add card controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_dapm_routes, + ARRAY_SIZE(rt1308_dapm_routes)); + + if (ret) + dev_err(rtd->dev, "fail to add dapm routes, ret %d\n", ret); + + return ret; +} + +static int rt1308_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_card *card = rtd->card; + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + int clk_id, clk_freq, pll_out; + int ret; + + clk_id = RT1308_PLL_S_MCLK; + /* get the tplg configured mclk. */ + clk_freq = sof_dai_get_mclk(rtd); + + pll_out = params_rate(params) * 512; + + /* Set rt1308 pll */ + ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out); + if (ret < 0) { + dev_err(card->dev, "Failed to set RT1308 PLL: %d\n", ret); + return ret; + } + + /* Set rt1308 sysclk */ + ret = snd_soc_dai_set_sysclk(codec_dai, RT1308_FS_SYS_S_PLL, pll_out, + SND_SOC_CLOCK_IN); + if (ret < 0) + dev_err(card->dev, "Failed to set RT1308 SYSCLK: %d\n", ret); + + return ret; +} + +static const struct snd_soc_ops rt1308_ops = { + .hw_params = rt1308_hw_params, +}; + +void sof_rt1308_dai_link(struct snd_soc_dai_link *link) +{ + link->codecs = rt1308_components; + link->num_codecs = ARRAY_SIZE(rt1308_components); + link->init = rt1308_init; + link->ops = &rt1308_ops; +} +EXPORT_SYMBOL_NS(sof_rt1308_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON"); + +/* + * 2-amp Configuration for RT1019 + */ + +static const struct snd_soc_dapm_route rt1019p_dapm_routes[] = { + /* speaker */ + { "Left Spk", NULL, "Speaker" }, + { "Right Spk", NULL, "Speaker" }, +}; + +static struct snd_soc_dai_link_component rt1019p_components[] = { + { + .name = RT1019P_DEV0_NAME, + .dai_name = RT1019P_CODEC_DAI, + }, +}; + +static int rt1019p_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_dapm_new_controls(&card->dapm, realtek_2spk_widgets, + ARRAY_SIZE(realtek_2spk_widgets)); + if (ret) { + dev_err(rtd->dev, "fail to add rt1019p widgets, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, realtek_2spk_kcontrols, + ARRAY_SIZE(realtek_2spk_kcontrols)); + if (ret) { + dev_err(rtd->dev, "fail to add rt1019p kcontrols, ret %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, rt1019p_dapm_routes, + ARRAY_SIZE(rt1019p_dapm_routes)); + if (ret) { + dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); + return ret; + } + return ret; +} + +void sof_rt1019p_dai_link(struct snd_soc_dai_link *link) +{ + link->codecs = rt1019p_components; + link->num_codecs = ARRAY_SIZE(rt1019p_components); + link->init = rt1019p_init; +} +EXPORT_SYMBOL_NS(sof_rt1019p_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON"); + +MODULE_DESCRIPTION("ASoC Intel SOF Realtek helpers"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/boards/sof_realtek_common.h b/sound/soc/intel/boards/sof_realtek_common.h new file mode 100644 index 000000000000..876290555c22 --- /dev/null +++ b/sound/soc/intel/boards/sof_realtek_common.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright(c) 2020 Intel Corporation. + */ + +/* + * This file defines data structures used in Machine Driver for Intel + * platforms with Realtek Codecs. + */ +#ifndef __SOF_REALTEK_COMMON_H +#define __SOF_REALTEK_COMMON_H + +#include <sound/soc.h> +#include <sound/soc-acpi-intel-ssp-common.h> + +/* + * Realtek ALC1011 + */ + +#define RT1011_CODEC_DAI "rt1011-aif" +#define RT1011_DEV0_NAME "i2c-" RT1011_ACPI_HID ":00" +#define RT1011_DEV1_NAME "i2c-" RT1011_ACPI_HID ":01" +#define RT1011_DEV2_NAME "i2c-" RT1011_ACPI_HID ":02" +#define RT1011_DEV3_NAME "i2c-" RT1011_ACPI_HID ":03" + +void sof_rt1011_dai_link(struct device *dev, struct snd_soc_dai_link *link); +void sof_rt1011_codec_conf(struct device *dev, struct snd_soc_card *card); + +/* + * Realtek ALC1015 (AUTO) + */ +#define RT1015P_CODEC_DAI "HiFi" +#define RT1015P_DEV0_NAME RT1015P_ACPI_HID ":00" + +void sof_rt1015p_dai_link(struct snd_soc_dai_link *link); +void sof_rt1015p_codec_conf(struct snd_soc_card *card); + +/* + * Realtek ALC1015 (I2C) + */ +#define RT1015_CODEC_DAI "rt1015-aif" +#define RT1015_DEV0_NAME "i2c-" RT1015_ACPI_HID ":00" +#define RT1015_DEV1_NAME "i2c-" RT1015_ACPI_HID ":01" + +void sof_rt1015_dai_link(struct snd_soc_dai_link *link); +void sof_rt1015_codec_conf(struct snd_soc_card *card); + +/* + * Realtek ALC1308 + */ +#define RT1308_CODEC_DAI "rt1308-aif" +#define RT1308_DEV0_NAME "i2c-" RT1308_ACPI_HID ":00" +void sof_rt1308_dai_link(struct snd_soc_dai_link *link); + +/* + * Realtek ALC1019 + */ +#define RT1019P_CODEC_DAI "HiFi" +#define RT1019P_DEV0_NAME RT1019P_ACPI_HID ":00" + +void sof_rt1019p_dai_link(struct snd_soc_dai_link *link); + +#endif /* __SOF_REALTEK_COMMON_H */ diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 0129d23694ed..f5925bd0a3fc 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -16,55 +16,24 @@ #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> +#include <sound/sof.h> #include <sound/rt5682.h> +#include <sound/rt5682s.h> #include <sound/soc-acpi.h> -#include "../../codecs/rt1015.h" #include "../../codecs/rt5682.h" -#include "../../codecs/hdac_hdmi.h" +#include "../../codecs/rt5682s.h" +#include "../../codecs/rt5645.h" #include "../common/soc-intel-quirks.h" -#include "hda_dsp_common.h" +#include "sof_board_helpers.h" #include "sof_maxim_common.h" +#include "sof_realtek_common.h" -#define NAME_SIZE 32 - -#define SOF_RT5682_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0)) -#define SOF_RT5682_SSP_CODEC_MASK (GENMASK(2, 0)) -#define SOF_RT5682_MCLK_EN BIT(3) -#define SOF_RT5682_MCLK_24MHZ BIT(4) -#define SOF_SPEAKER_AMP_PRESENT BIT(5) -#define SOF_RT5682_SSP_AMP_SHIFT 6 -#define SOF_RT5682_SSP_AMP_MASK (GENMASK(8, 6)) -#define SOF_RT5682_SSP_AMP(quirk) \ - (((quirk) << SOF_RT5682_SSP_AMP_SHIFT) & SOF_RT5682_SSP_AMP_MASK) -#define SOF_RT5682_MCLK_BYTCHT_EN BIT(9) -#define SOF_RT5682_NUM_HDMIDEV_SHIFT 10 -#define SOF_RT5682_NUM_HDMIDEV_MASK (GENMASK(12, 10)) -#define SOF_RT5682_NUM_HDMIDEV(quirk) \ - ((quirk << SOF_RT5682_NUM_HDMIDEV_SHIFT) & SOF_RT5682_NUM_HDMIDEV_MASK) -#define SOF_RT1015_SPEAKER_AMP_PRESENT BIT(13) -#define SOF_MAX98373_SPEAKER_AMP_PRESENT BIT(14) -#define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(15) +/* Driver-specific board quirks: from bit 0 to 7 */ +#define SOF_RT5682_MCLK_EN BIT(0) /* Default: MCLK on, MCLK 19.2M, SSP0 */ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0); - -static int is_legacy_cpu; - -static struct snd_soc_jack sof_hdmi[3]; - -struct sof_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct sof_card_private { - struct clk *mclk; - struct snd_soc_jack sof_headset; - struct list_head hdmi_pcm_list; - bool common_hdmi_codec_drv; -}; + SOF_SSP_PORT_CODEC(0); static int sof_rt5682_quirk_cb(const struct dmi_system_id *id) { @@ -79,7 +48,7 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max"), }, - .driver_data = (void *)(SOF_RT5682_SSP_CODEC(2)), + .driver_data = (void *)(SOF_SSP_PORT_CODEC(2)), }, { .callback = sof_rt5682_quirk_cb, @@ -87,7 +56,7 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), DMI_MATCH(DMI_PRODUCT_NAME, "UP-CHT01"), }, - .driver_data = (void *)(SOF_RT5682_SSP_CODEC(2)), + .driver_data = (void *)(SOF_SSP_PORT_CODEC(2)), }, { .callback = sof_rt5682_quirk_cb, @@ -96,108 +65,176 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "WhiskeyLake Client"), }, .driver_data = (void *)(SOF_RT5682_MCLK_EN | - SOF_RT5682_MCLK_24MHZ | - SOF_RT5682_SSP_CODEC(1)), + SOF_SSP_PORT_CODEC(1)), }, { .callback = sof_rt5682_quirk_cb, .matches = { - DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Hatch"), + DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Volteer"), + DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98373_ALC5682I_I2S_UP4"), }, .driver_data = (void *)(SOF_RT5682_MCLK_EN | - SOF_RT5682_MCLK_24MHZ | - SOF_RT5682_SSP_CODEC(0) | - SOF_SPEAKER_AMP_PRESENT | - SOF_RT5682_SSP_AMP(1)), + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(2) | + SOF_NUM_IDISP_HDMI(4)), }, { .callback = sof_rt5682_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alder Lake Client Platform"), + DMI_MATCH(DMI_OEM_STRING, "AUDIO-ADL_MAX98373_ALC5682I_I2S"), + }, + .driver_data = (void *)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(2) | + SOF_NUM_IDISP_HDMI(4)), + }, + { + .callback = sof_rt5682_quirk_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"), + DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98390_ALC5682I_I2S"), + }, + .driver_data = (void *)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(2) | + SOF_NUM_IDISP_HDMI(4)), + }, + { + .callback = sof_rt5682_quirk_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"), + DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98360_ALC5682I_I2S_AMP_SSP2"), }, .driver_data = (void *)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0)), + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(2) | + SOF_NUM_IDISP_HDMI(4)), + }, + { + .callback = sof_rt5682_quirk_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Rex"), + }, + .driver_data = (void *)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(2) | + SOF_SSP_PORT_AMP(0) | + SOF_SSP_PORT_BT_OFFLOAD(1) | + SOF_BT_OFFLOAD_PRESENT + ), }, {} }; -static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd) -{ - struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); - struct sof_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - /* dai_link id is 1:1 mapped to the PCM device */ - pcm->device = rtd->dai_link->id; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) { struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; - struct snd_soc_jack *jack; - int ret; - - /* need to enable ASRC function for 24MHz mclk rate */ - if ((sof_rt5682_quirk & SOF_RT5682_MCLK_EN) && - (sof_rt5682_quirk & SOF_RT5682_MCLK_24MHZ)) { - rt5682_sel_asrc_clk_src(component, RT5682_DA_STEREO1_FILTER | - RT5682_AD_STEREO1_FILTER, - RT5682_CLK_SEL_I2S1_ASRC); - } - - if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) { - /* - * The firmware might enable the clock at - * boot (this information may or may not - * be reflected in the enable clock register). - * To change the rate we must disable the clock - * first to cover these cases. Due to common - * clock framework restrictions that do not allow - * to disable a clock that has not been enabled, - * we need to enable the clock first. - */ - ret = clk_prepare_enable(ctx->mclk); - if (!ret) - clk_disable_unprepare(ctx->mclk); + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; + struct snd_soc_jack *jack = &ctx->headset_jack; + int extra_jack_data; + int ret, mclk_freq; + + if (ctx->rt5682.mclk_en) { + mclk_freq = sof_dai_get_mclk(rtd); + if (mclk_freq <= 0) { + dev_err(rtd->dev, "invalid mclk freq %d\n", mclk_freq); + return -EINVAL; + } - ret = clk_set_rate(ctx->mclk, 19200000); + /* need to enable ASRC function for 24MHz mclk rate */ + if (mclk_freq == 24000000) { + dev_info(rtd->dev, "enable ASRC\n"); + + switch (ctx->codec_type) { + case CODEC_RT5650: + rt5645_sel_asrc_clk_src(component, + RT5645_DA_STEREO_FILTER | + RT5645_AD_STEREO_FILTER, + RT5645_CLK_SEL_I2S1_ASRC); + rt5645_sel_asrc_clk_src(component, + RT5645_DA_MONO_L_FILTER | + RT5645_DA_MONO_R_FILTER, + RT5645_CLK_SEL_I2S2_ASRC); + break; + case CODEC_RT5682: + rt5682_sel_asrc_clk_src(component, + RT5682_DA_STEREO1_FILTER | + RT5682_AD_STEREO1_FILTER, + RT5682_CLK_SEL_I2S1_ASRC); + break; + case CODEC_RT5682S: + rt5682s_sel_asrc_clk_src(component, + RT5682S_DA_STEREO1_FILTER | + RT5682S_AD_STEREO1_FILTER, + RT5682S_CLK_SEL_I2S1_ASRC); + break; + default: + dev_err(rtd->dev, "invalid codec type %d\n", + ctx->codec_type); + return -EINVAL; + } + } - if (ret) - dev_err(rtd->dev, "unable to set MCLK rate\n"); + if (ctx->rt5682.is_legacy_cpu) { + /* + * The firmware might enable the clock at + * boot (this information may or may not + * be reflected in the enable clock register). + * To change the rate we must disable the clock + * first to cover these cases. Due to common + * clock framework restrictions that do not allow + * to disable a clock that has not been enabled, + * we need to enable the clock first. + */ + ret = clk_prepare_enable(ctx->rt5682.mclk); + if (!ret) + clk_disable_unprepare(ctx->rt5682.mclk); + + ret = clk_set_rate(ctx->rt5682.mclk, 19200000); + + if (ret) + dev_err(rtd->dev, "unable to set MCLK rate\n"); + } } /* * 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 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - &ctx->sof_headset, NULL, 0); + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + jack, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; } - jack = &ctx->sof_headset; - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - ret = snd_soc_component_set_jack(component, jack, NULL); + + if (ctx->codec_type == CODEC_RT5650) { + extra_jack_data = SND_JACK_MICROPHONE | SND_JACK_BTN_0; + ret = snd_soc_component_set_jack(component, jack, &extra_jack_data); + } else + ret = snd_soc_component_set_jack(component, jack, NULL); if (ret) { dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); @@ -209,7 +246,7 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) static void sof_rt5682_codec_exit(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; snd_soc_component_set_jack(component, NULL, NULL); } @@ -217,14 +254,14 @@ static void sof_rt5682_codec_exit(struct snd_soc_pcm_runtime *rtd) static int sof_rt5682_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - int clk_id, clk_freq, pll_out, ret; + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + int pll_id, pll_source, pll_in, pll_out, clk_id, ret; - if (sof_rt5682_quirk & SOF_RT5682_MCLK_EN) { - if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) { - ret = clk_prepare_enable(ctx->mclk); + if (ctx->rt5682.mclk_en) { + if (ctx->rt5682.is_legacy_cpu) { + ret = clk_prepare_enable(ctx->rt5682.mclk); if (ret < 0) { dev_err(rtd->dev, "could not configure MCLK state"); @@ -232,24 +269,116 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream, } } - clk_id = RT5682_PLL1_S_MCLK; - if (sof_rt5682_quirk & SOF_RT5682_MCLK_24MHZ) - clk_freq = 24000000; - else - clk_freq = 19200000; + switch (ctx->codec_type) { + case CODEC_RT5650: + pll_source = RT5645_PLL1_S_MCLK; + break; + case CODEC_RT5682: + pll_source = RT5682_PLL1_S_MCLK; + break; + case CODEC_RT5682S: + pll_source = RT5682S_PLL_S_MCLK; + break; + default: + dev_err(rtd->dev, "invalid codec type %d\n", + ctx->codec_type); + return -EINVAL; + } + + /* get the tplg configured mclk. */ + pll_in = sof_dai_get_mclk(rtd); + if (pll_in <= 0) { + dev_err(rtd->dev, "invalid mclk freq %d\n", pll_in); + return -EINVAL; + } } else { - clk_id = RT5682_PLL1_S_BCLK1; - clk_freq = params_rate(params) * 50; + switch (ctx->codec_type) { + case CODEC_RT5650: + pll_source = RT5645_PLL1_S_BCLK1; + break; + case CODEC_RT5682: + pll_source = RT5682_PLL1_S_BCLK1; + break; + case CODEC_RT5682S: + pll_source = RT5682S_PLL_S_BCLK1; + break; + default: + dev_err(rtd->dev, "invalid codec type %d\n", + ctx->codec_type); + return -EINVAL; + } + + /* get the tplg configured bclk. */ + pll_in = sof_dai_get_bclk(rtd); + if (pll_in <= 0) { + dev_err(rtd->dev, "invalid bclk freq %d\n", pll_in); + return -EINVAL; + } } pll_out = params_rate(params) * 512; - ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out); - if (ret < 0) - dev_err(rtd->dev, "snd_soc_dai_set_pll err = %d\n", ret); + /* when MCLK is 512FS, no need to set PLL configuration additionally. */ + if (pll_in == pll_out) { + switch (ctx->codec_type) { + case CODEC_RT5650: + clk_id = RT5645_SCLK_S_MCLK; + break; + case CODEC_RT5682: + clk_id = RT5682_SCLK_S_MCLK; + break; + case CODEC_RT5682S: + clk_id = RT5682S_SCLK_S_MCLK; + break; + default: + dev_err(rtd->dev, "invalid codec type %d\n", + ctx->codec_type); + return -EINVAL; + } + } else { + switch (ctx->codec_type) { + case CODEC_RT5650: + pll_id = 0; /* not used in codec driver */ + clk_id = RT5645_SCLK_S_PLL1; + break; + case CODEC_RT5682: + pll_id = RT5682_PLL1; + clk_id = RT5682_SCLK_S_PLL1; + break; + case CODEC_RT5682S: + /* check plla_table and pllb_table in rt5682s.c */ + switch (pll_in) { + case 3072000: + case 24576000: + /* + * For MCLK = 24.576MHz and sample rate = 96KHz case, use PLL1 We don't test + * pll_out or params_rate() here since rt5682s PLL2 doesn't support 24.576MHz + * input, so we have no choice but to use PLL1. Besides, we will not use PLL at + * all if pll_in == pll_out. ex, MCLK = 24.576Mhz and sample rate = 48KHz + */ + pll_id = RT5682S_PLL1; + clk_id = RT5682S_SCLK_S_PLL1; + break; + default: + pll_id = RT5682S_PLL2; + clk_id = RT5682S_SCLK_S_PLL2; + break; + } + break; + default: + dev_err(rtd->dev, "invalid codec type %d\n", ctx->codec_type); + return -EINVAL; + } + + /* Configure pll for codec */ + ret = snd_soc_dai_set_pll(codec_dai, pll_id, pll_source, pll_in, + pll_out); + if (ret < 0) + dev_err(rtd->dev, "snd_soc_dai_set_pll err = %d\n", ret); + } /* Configure sysclk for codec */ - ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, + ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, pll_out, SND_SOC_CLOCK_IN); if (ret < 0) dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); @@ -268,104 +397,17 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops sof_rt5682_ops = { +static const struct snd_soc_ops sof_rt5682_ops = { .hw_params = sof_rt5682_hw_params, }; -static int sof_rt1015_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_card *card = rtd->card; - struct snd_soc_dai *codec_dai; - int i, ret; - - if (!snd_soc_card_get_codec_dai(card, "rt1015-aif")) - return 0; - - for_each_rtd_codec_dais(rtd, i, codec_dai) { - /* Set tdm/i2s1 master bclk ratio */ - ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64); - if (ret < 0) { - dev_err(card->dev, "failed to set bclk ratio\n"); - return ret; - } - - ret = snd_soc_dai_set_pll(codec_dai, 0, RT1015_PLL_S_BCLK, - params_rate(params) * 64, - params_rate(params) * 256); - if (ret < 0) { - dev_err(card->dev, "failed to set pll\n"); - return ret; - } - /* Configure sysclk for codec */ - ret = snd_soc_dai_set_sysclk(codec_dai, RT1015_SCLK_S_PLL, - params_rate(params) * 256, - SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(card->dev, "failed to set sysclk\n"); - return ret; - } - } - - return 0; -} - -static struct snd_soc_ops sof_rt1015_ops = { - .hw_params = sof_rt1015_hw_params, -}; - -static struct snd_soc_dai_link_component platform_component[] = { - { - /* name might be overridden during probe */ - .name = "0000:00:1f.3" - } -}; - static int sof_card_late_probe(struct snd_soc_card *card) { struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_component *component = NULL; struct snd_soc_dapm_context *dapm = &card->dapm; - char jack_name[NAME_SIZE]; - struct sof_hdmi_pcm *pcm; int err; - int i = 0; - - /* HDMI is not supported by SOF on Baytrail/CherryTrail */ - if (is_legacy_cpu) - return 0; - - if (list_empty(&ctx->hdmi_pcm_list)) - return -EINVAL; - - if (ctx->common_hdmi_codec_drv) { - pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, - head); - component = pcm->codec_dai->component; - return hda_dsp_hdmi_build_controls(card, component); - } - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - 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, &sof_hdmi[i], - NULL, 0); - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &sof_hdmi[i]); - if (err < 0) - return err; - - i++; - } - - if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) { + if (ctx->amp_type == CODEC_MAX98373) { /* Disable Left and Right Spk pin after boot */ snd_soc_dapm_disable_pin(dapm, "Left Spk"); snd_soc_dapm_disable_pin(dapm, "Right Spk"); @@ -373,28 +415,18 @@ static int sof_card_late_probe(struct snd_soc_card *card) if (err < 0) return err; } - return hdac_hdmi_jack_port_init(component, &card->dapm); + + return sof_intel_board_card_late_probe(card); } static const struct snd_kcontrol_new sof_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Spk"), - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), - }; static const struct snd_soc_dapm_widget sof_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Spk", NULL), - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), -}; - -static const struct snd_soc_dapm_widget dmic_widgets[] = { - SND_SOC_DAPM_MIC("SoC DMIC", NULL), }; static const struct snd_soc_dapm_route sof_map[] = { @@ -406,73 +438,52 @@ static const struct snd_soc_dapm_route sof_map[] = { { "IN1P", NULL, "Headset Mic" }, }; -static const struct snd_soc_dapm_route speaker_map[] = { - /* speaker */ - { "Spk", NULL, "Speaker" }, -}; +static const struct snd_kcontrol_new rt5650_spk_kcontrols[] = { + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), -static const struct snd_soc_dapm_route speaker_map_lr[] = { - { "Left Spk", NULL, "Left SPO" }, - { "Right Spk", NULL, "Right SPO" }, }; -static const struct snd_soc_dapm_route dmic_map[] = { - /* digital mics */ - {"DMic", NULL, "SoC DMIC"}, +static const struct snd_soc_dapm_widget rt5650_spk_widgets[] = { + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), }; -static int speaker_codec_init_lr(struct snd_soc_pcm_runtime *rtd) -{ - return snd_soc_dapm_add_routes(&rtd->card->dapm, speaker_map_lr, - ARRAY_SIZE(speaker_map_lr)); -} - -static int speaker_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - int ret; - - ret = snd_soc_dapm_add_routes(&card->dapm, speaker_map, - ARRAY_SIZE(speaker_map)); - - if (ret) - dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); - return ret; -} +static const struct snd_soc_dapm_route rt5650_spk_dapm_routes[] = { + /* speaker */ + { "Left Spk", NULL, "SPOL" }, + { "Right Spk", NULL, "SPOR" }, +}; -static int dmic_init(struct snd_soc_pcm_runtime *rtd) +static int rt5650_spk_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; int ret; - ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets, - ARRAY_SIZE(dmic_widgets)); + ret = snd_soc_dapm_new_controls(&card->dapm, rt5650_spk_widgets, + ARRAY_SIZE(rt5650_spk_widgets)); if (ret) { - dev_err(card->dev, "DMic widget addition failed: %d\n", ret); - /* Don't need to add routes if widget addition failed */ + dev_err(rtd->dev, "fail to add rt5650 spk widgets, ret %d\n", + ret); return ret; } - ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map, - ARRAY_SIZE(dmic_map)); + ret = snd_soc_add_card_controls(card, rt5650_spk_kcontrols, + ARRAY_SIZE(rt5650_spk_kcontrols)); + if (ret) { + dev_err(rtd->dev, "fail to add rt5650 spk kcontrols, ret %d\n", + ret); + return ret; + } + ret = snd_soc_dapm_add_routes(&card->dapm, rt5650_spk_dapm_routes, + ARRAY_SIZE(rt5650_spk_dapm_routes)); if (ret) - dev_err(card->dev, "DMic map addition failed: %d\n", ret); + dev_err(rtd->dev, "fail to add dapm routes, ret=%d\n", ret); return ret; } -static struct snd_soc_codec_conf rt1015_amp_conf[] = { - { - .dlc = COMP_CODEC_CONF("i2c-10EC1015:00"), - .name_prefix = "Left", - }, - { - .dlc = COMP_CODEC_CONF("i2c-10EC1015:01"), - .name_prefix = "Right", - }, -}; - /* sof audio machine driver for rt5682 codec */ static struct snd_soc_card sof_audio_card_rt5682 = { .name = "rt5682", /* the sof- prefix is added by the core */ @@ -494,83 +505,63 @@ static struct snd_soc_dai_link_component rt5682_component[] = { } }; -static struct snd_soc_dai_link_component dmic_component[] = { +static struct snd_soc_dai_link_component rt5682s_component[] = { { - .name = "dmic-codec", - .dai_name = "dmic-hifi", + .name = "i2c-RTL5682:00", + .dai_name = "rt5682s-aif1", } }; -static struct snd_soc_dai_link_component max98357a_component[] = { +static struct snd_soc_dai_link_component rt5650_components[] = { + { + .name = "i2c-10EC5650:00", + .dai_name = "rt5645-aif1", + }, { - .name = "MX98357A:00", - .dai_name = "HiFi", + .name = "i2c-10EC5650:00", + .dai_name = "rt5645-aif2", } }; -static struct snd_soc_dai_link_component max98360a_component[] = { - { - .name = "MX98360A:00", - .dai_name = "HiFi", +static int +sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card, + struct sof_card_private *ctx) +{ + int ret; + + ret = sof_intel_board_set_dai_link(dev, card, ctx); + if (ret) + return ret; + + if (!ctx->codec_link) { + dev_err(dev, "codec link not available"); + return -EINVAL; } -}; -static struct snd_soc_dai_link_component rt1015_components[] = { - { - .name = "i2c-10EC1015:00", - .dai_name = "rt1015-aif", - }, - { - .name = "i2c-10EC1015:01", - .dai_name = "rt1015-aif", - }, -}; + /* codec-specific fields for headphone codec */ + switch (ctx->codec_type) { + case CODEC_RT5650: + ctx->codec_link->codecs = &rt5650_components[0]; + ctx->codec_link->num_codecs = 1; + break; + case CODEC_RT5682: + ctx->codec_link->codecs = rt5682_component; + ctx->codec_link->num_codecs = ARRAY_SIZE(rt5682_component); + break; + case CODEC_RT5682S: + ctx->codec_link->codecs = rt5682s_component; + ctx->codec_link->num_codecs = ARRAY_SIZE(rt5682s_component); + break; + default: + dev_err(dev, "invalid codec type %d\n", ctx->codec_type); + return -EINVAL; + } -static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, - int ssp_codec, - int ssp_amp, - int dmic_be_num, - int hdmi_num) -{ - struct snd_soc_dai_link_component *idisp_components; - struct snd_soc_dai_link_component *cpus; - struct snd_soc_dai_link *links; - int i, id = 0; - - links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * - sof_audio_card_rt5682.num_links, GFP_KERNEL); - cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) * - sof_audio_card_rt5682.num_links, GFP_KERNEL); - if (!links || !cpus) - goto devm_err; - - /* codec SSP */ - links[id].name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d-Codec", ssp_codec); - if (!links[id].name) - goto devm_err; - - links[id].id = id; - links[id].codecs = rt5682_component; - links[id].num_codecs = ARRAY_SIZE(rt5682_component); - links[id].platforms = platform_component; - links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].init = sof_rt5682_codec_init; - links[id].exit = sof_rt5682_codec_exit; - links[id].ops = &sof_rt5682_ops; - links[id].nonatomic = true; - links[id].dpcm_playback = 1; - links[id].dpcm_capture = 1; - links[id].no_pcm = 1; - links[id].cpus = &cpus[id]; - links[id].num_cpus = 1; - if (is_legacy_cpu) { - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "ssp%d-port", - ssp_codec); - if (!links[id].cpus->dai_name) - goto devm_err; - } else { + ctx->codec_link->init = sof_rt5682_codec_init; + ctx->codec_link->exit = sof_rt5682_codec_exit; + ctx->codec_link->ops = &sof_rt5682_ops; + + if (!ctx->rt5682.is_legacy_cpu) { /* * Currently, On SKL+ platforms MCLK will be turned off in sof * runtime suspended, and it will go into runtime suspended @@ -580,233 +571,199 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, * avoid the noise. * It can be removed once we can control MCLK by driver. */ - links[id].ignore_pmdown_time = 1; - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", - ssp_codec); - if (!links[id].cpus->dai_name) - goto devm_err; - } - id++; - - /* dmic */ - if (dmic_be_num > 0) { - /* at least we have dmic01 */ - links[id].name = "dmic01"; - links[id].cpus = &cpus[id]; - links[id].cpus->dai_name = "DMIC01 Pin"; - links[id].init = dmic_init; - if (dmic_be_num > 1) { - /* set up 2 BE links at most */ - links[id + 1].name = "dmic16k"; - links[id + 1].cpus = &cpus[id + 1]; - links[id + 1].cpus->dai_name = "DMIC16k Pin"; - dmic_be_num = 2; - } + ctx->codec_link->ignore_pmdown_time = 1; } - for (i = 0; i < dmic_be_num; i++) { - links[id].id = id; - links[id].num_cpus = 1; - links[id].codecs = dmic_component; - links[id].num_codecs = ARRAY_SIZE(dmic_component); - links[id].platforms = platform_component; - links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].ignore_suspend = 1; - links[id].dpcm_capture = 1; - links[id].no_pcm = 1; - id++; - } + if (ctx->amp_type == CODEC_NONE) + return 0; - /* HDMI */ - if (hdmi_num > 0) { - idisp_components = devm_kzalloc(dev, - sizeof(struct snd_soc_dai_link_component) * - hdmi_num, GFP_KERNEL); - if (!idisp_components) - goto devm_err; - } - for (i = 1; i <= hdmi_num; i++) { - links[id].name = devm_kasprintf(dev, GFP_KERNEL, - "iDisp%d", i); - if (!links[id].name) - goto devm_err; - - links[id].id = id; - links[id].cpus = &cpus[id]; - links[id].num_cpus = 1; - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "iDisp%d Pin", i); - if (!links[id].cpus->dai_name) - goto devm_err; - - idisp_components[i - 1].name = "ehdaudio0D2"; - idisp_components[i - 1].dai_name = devm_kasprintf(dev, - GFP_KERNEL, - "intel-hdmi-hifi%d", - i); - if (!idisp_components[i - 1].dai_name) - goto devm_err; - - links[id].codecs = &idisp_components[i - 1]; - links[id].num_codecs = 1; - links[id].platforms = platform_component; - links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].init = sof_hdmi_init; - links[id].dpcm_playback = 1; - links[id].no_pcm = 1; - id++; + if (!ctx->amp_link) { + dev_err(dev, "amp link not available"); + return -EINVAL; } - /* speaker amp */ - if (sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT) { - links[id].name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d-Codec", ssp_amp); - if (!links[id].name) - goto devm_err; - - links[id].id = id; - if (sof_rt5682_quirk & SOF_RT1015_SPEAKER_AMP_PRESENT) { - links[id].codecs = rt1015_components; - links[id].num_codecs = ARRAY_SIZE(rt1015_components); - links[id].init = speaker_codec_init_lr; - links[id].ops = &sof_rt1015_ops; - } else if (sof_rt5682_quirk & - SOF_MAX98373_SPEAKER_AMP_PRESENT) { - links[id].codecs = max_98373_components; - links[id].num_codecs = ARRAY_SIZE(max_98373_components); - links[id].init = max98373_spk_codec_init; - links[id].ops = &max_98373_ops; - } else if (sof_rt5682_quirk & - SOF_MAX98360A_SPEAKER_AMP_PRESENT) { - links[id].codecs = max98360a_component; - links[id].num_codecs = ARRAY_SIZE(max98360a_component); - links[id].init = speaker_codec_init; - } else { - links[id].codecs = max98357a_component; - links[id].num_codecs = ARRAY_SIZE(max98357a_component); - links[id].init = speaker_codec_init; - } - links[id].platforms = platform_component; - links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].nonatomic = true; - links[id].dpcm_playback = 1; - links[id].no_pcm = 1; - links[id].cpus = &cpus[id]; - links[id].num_cpus = 1; - if (is_legacy_cpu) { - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "ssp%d-port", - ssp_amp); - if (!links[id].cpus->dai_name) - goto devm_err; - - } else { - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", - ssp_amp); - if (!links[id].cpus->dai_name) - goto devm_err; - } + /* codec-specific fields for speaker amplifier */ + switch (ctx->amp_type) { + case CODEC_MAX98357A: + max_98357a_dai_link(ctx->amp_link); + break; + case CODEC_MAX98360A: + max_98360a_dai_link(ctx->amp_link); + break; + case CODEC_MAX98373: + max_98373_dai_link(dev, ctx->amp_link); + break; + case CODEC_MAX98390: + max_98390_dai_link(dev, ctx->amp_link); + break; + case CODEC_RT1011: + sof_rt1011_dai_link(dev, ctx->amp_link); + break; + case CODEC_RT1015: + sof_rt1015_dai_link(ctx->amp_link); + break; + case CODEC_RT1015P: + sof_rt1015p_dai_link(ctx->amp_link); + break; + case CODEC_RT1019P: + sof_rt1019p_dai_link(ctx->amp_link); + break; + case CODEC_RT5650: + /* use AIF2 to support speaker pipeline */ + ctx->amp_link->codecs = &rt5650_components[1]; + ctx->amp_link->num_codecs = 1; + ctx->amp_link->init = rt5650_spk_init; + ctx->amp_link->ops = &sof_rt5682_ops; + break; + default: + dev_err(dev, "invalid amp type %d\n", ctx->amp_type); + return -EINVAL; } - return links; -devm_err: - return NULL; + return 0; } +#define GLK_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \ + SOF_LINK_CODEC, \ + SOF_LINK_DMIC01, \ + SOF_LINK_IDISP_HDMI, \ + SOF_LINK_NONE, \ + SOF_LINK_NONE, \ + SOF_LINK_NONE) + static int sof_audio_probe(struct platform_device *pdev) { - struct snd_soc_dai_link *dai_links; - struct snd_soc_acpi_mach *mach; + struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; struct sof_card_private *ctx; - int dmic_be_num, hdmi_num; - int ret, ssp_amp, ssp_codec; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + char *card_name; + int ret; if (pdev->id_entry && pdev->id_entry->driver_data) sof_rt5682_quirk = (unsigned long)pdev->id_entry->driver_data; dmi_check_system(sof_rt5682_quirk_table); - mach = pdev->dev.platform_data; + dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", sof_rt5682_quirk); - /* A speaker amp might not be present when the quirk claims one is. - * Detect this via whether the machine driver match includes quirk_data. - */ - if ((sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT) && !mach->quirk_data) - sof_rt5682_quirk &= ~SOF_SPEAKER_AMP_PRESENT; + /* initialize ctx with board quirk */ + ctx = sof_intel_board_get_ctx(&pdev->dev, sof_rt5682_quirk); + if (!ctx) + return -ENOMEM; - if (soc_intel_is_byt() || soc_intel_is_cht()) { - is_legacy_cpu = 1; - dmic_be_num = 0; - hdmi_num = 0; - /* default quirk for legacy cpu */ - sof_rt5682_quirk = SOF_RT5682_MCLK_EN | - SOF_RT5682_MCLK_BYTCHT_EN | - SOF_RT5682_SSP_CODEC(2); - } else { - dmic_be_num = 2; - hdmi_num = (sof_rt5682_quirk & SOF_RT5682_NUM_HDMIDEV_MASK) >> - SOF_RT5682_NUM_HDMIDEV_SHIFT; - /* default number of HDMI DAI's */ - if (!hdmi_num) - hdmi_num = 3; + if (ctx->codec_type == CODEC_RT5650) { + card_name = devm_kstrdup(&pdev->dev, "rt5650", GFP_KERNEL); + if (!card_name) + return -ENOMEM; + + sof_audio_card_rt5682.name = card_name; + + /* create speaker dai link also */ + if (ctx->amp_type == CODEC_NONE) + ctx->amp_type = CODEC_RT5650; } - /* need to get main clock from pmc */ - if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) { - ctx->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); - if (IS_ERR(ctx->mclk)) { - ret = PTR_ERR(ctx->mclk); + if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) + ctx->hdmi.idisp_codec = true; - dev_err(&pdev->dev, - "Failed to get MCLK from pmc_plt_clk_3: %d\n", - ret); - return ret; + if (soc_intel_is_byt() || soc_intel_is_cht()) { + ctx->rt5682.is_legacy_cpu = true; + ctx->dmic_be_num = 0; + /* HDMI is not supported by SOF on Baytrail/CherryTrail */ + ctx->hdmi_num = 0; + } else if (soc_intel_is_glk()) { + /* dmic16k not support */ + ctx->dmic_be_num = 1; + + /* overwrite the DAI link order for GLK boards */ + ctx->link_order_overwrite = GLK_LINK_ORDER; + + /* backward-compatible with existing devices */ + switch (ctx->amp_type) { + case CODEC_MAX98357A: + card_name = devm_kstrdup(&pdev->dev, "glkrt5682max", + GFP_KERNEL); + if (!card_name) + return -ENOMEM; + + sof_audio_card_rt5682.name = card_name; + break; + default: + break; } - - ret = clk_prepare_enable(ctx->mclk); - if (ret < 0) { - dev_err(&pdev->dev, - "could not configure MCLK state"); - return ret; + } else if (soc_intel_is_cml()) { + /* backward-compatible with existing devices */ + switch (ctx->amp_type) { + case CODEC_RT1011: + card_name = devm_kstrdup(&pdev->dev, "cml_rt1011_rt5682", + GFP_KERNEL); + if (!card_name) + return -ENOMEM; + + sof_audio_card_rt5682.name = card_name; + break; + default: + break; } } - dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", sof_rt5682_quirk); - - ssp_amp = (sof_rt5682_quirk & SOF_RT5682_SSP_AMP_MASK) >> - SOF_RT5682_SSP_AMP_SHIFT; - - ssp_codec = sof_rt5682_quirk & SOF_RT5682_SSP_CODEC_MASK; - - /* compute number of dai links */ - sof_audio_card_rt5682.num_links = 1 + dmic_be_num + hdmi_num; + if (sof_rt5682_quirk & SOF_RT5682_MCLK_EN) { + ctx->rt5682.mclk_en = true; - if (sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT) - sof_audio_card_rt5682.num_links++; + /* need to get main clock from pmc */ + if (ctx->rt5682.is_legacy_cpu) { + ctx->rt5682.mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); + if (IS_ERR(ctx->rt5682.mclk)) { + ret = PTR_ERR(ctx->rt5682.mclk); - if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) - sof_max98373_codec_conf(&sof_audio_card_rt5682); + dev_err(&pdev->dev, + "Failed to get MCLK from pmc_plt_clk_3: %d\n", + ret); + return ret; + } - dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp, - dmic_be_num, hdmi_num); - if (!dai_links) - return -ENOMEM; + ret = clk_prepare_enable(ctx->rt5682.mclk); + if (ret < 0) { + dev_err(&pdev->dev, + "could not configure MCLK state"); + return ret; + } + } + } - sof_audio_card_rt5682.dai_link = dai_links; + /* update dai_link */ + ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_rt5682, ctx); + if (ret) + return ret; - if (sof_rt5682_quirk & SOF_RT1015_SPEAKER_AMP_PRESENT) { - sof_audio_card_rt5682.codec_conf = rt1015_amp_conf; - sof_audio_card_rt5682.num_configs = ARRAY_SIZE(rt1015_amp_conf); + /* update codec_conf */ + switch (ctx->amp_type) { + case CODEC_MAX98373: + max_98373_set_codec_conf(&sof_audio_card_rt5682); + break; + case CODEC_MAX98390: + max_98390_set_codec_conf(&pdev->dev, &sof_audio_card_rt5682); + break; + case CODEC_RT1011: + sof_rt1011_codec_conf(&pdev->dev, &sof_audio_card_rt5682); + break; + case CODEC_RT1015: + sof_rt1015_codec_conf(&sof_audio_card_rt5682); + break; + case CODEC_RT1015P: + sof_rt1015p_codec_conf(&sof_audio_card_rt5682); + break; + case CODEC_MAX98357A: + case CODEC_MAX98360A: + case CODEC_RT1019P: + case CODEC_RT5650: + case CODEC_NONE: + /* no codec conf required */ + break; + default: + dev_err(&pdev->dev, "invalid amp type %d\n", ctx->amp_type); + return -EINVAL; } - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - sof_audio_card_rt5682.dev = &pdev->dev; /* set platform name for each dailink */ @@ -815,8 +772,6 @@ static int sof_audio_probe(struct platform_device *pdev) if (ret) return ret; - ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; - snd_soc_card_set_drvdata(&sof_audio_card_rt5682, ctx); return devm_snd_soc_register_card(&pdev->dev, @@ -826,44 +781,120 @@ static int sof_audio_probe(struct platform_device *pdev) static const struct platform_device_id board_ids[] = { { .name = "sof_rt5682", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(2)), + }, + { + .name = "glk_rt5682_def", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(2) | + SOF_SSP_PORT_AMP(1)), + }, + { + .name = "icl_rt5682_def", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(0)), + }, + { + .name = "cml_rt5682_def", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1)), + }, + { + .name = "jsl_rt5682_def", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1)), + }, + { + .name = "tgl_rt5682_def", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1) | + SOF_NUM_IDISP_HDMI(4) | + SOF_SSP_PORT_BT_OFFLOAD(2) | + SOF_BT_OFFLOAD_PRESENT), + }, + { + .name = "adl_rt5682_def", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1) | + SOF_NUM_IDISP_HDMI(4) | + SOF_SSP_PORT_BT_OFFLOAD(2) | + SOF_BT_OFFLOAD_PRESENT), + }, + { + .name = "adl_mx98357_rt5682", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(2) | + SOF_NUM_IDISP_HDMI(4)), + }, + { + .name = "adl_rt5682_c1_h02", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(1) | + /* SSP 0 and SSP 2 are used for HDMI IN */ + SOF_SSP_MASK_HDMI_CAPTURE(0x5)), + }, + { + .name = "rpl_mx98357_rt5682", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(2) | + SOF_NUM_IDISP_HDMI(4)), + }, + { + .name = "rpl_rt5682_def", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1) | + SOF_NUM_IDISP_HDMI(4) | + SOF_SSP_PORT_BT_OFFLOAD(2) | + SOF_BT_OFFLOAD_PRESENT), + }, + { + .name = "rpl_rt5682_c1_h02", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(1) | + /* SSP 0 and SSP 2 are used for HDMI IN */ + SOF_SSP_MASK_HDMI_CAPTURE(0x5)), }, { - .name = "tgl_max98357a_rt5682", + .name = "mtl_rt5682_def", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - SOF_SPEAKER_AMP_PRESENT | - SOF_RT5682_SSP_AMP(1) | - SOF_RT5682_NUM_HDMIDEV(4)), + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1) | + SOF_SSP_PORT_BT_OFFLOAD(2) | + SOF_BT_OFFLOAD_PRESENT), }, { - .name = "jsl_rt5682_rt1015", + .name = "mtl_rt5682_c1_h02", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_MCLK_24MHZ | - SOF_RT5682_SSP_CODEC(0) | - SOF_SPEAKER_AMP_PRESENT | - SOF_RT1015_SPEAKER_AMP_PRESENT | - SOF_RT5682_SSP_AMP(1)), + SOF_SSP_PORT_CODEC(1) | + /* SSP 0 and SSP 2 are used for HDMI IN */ + SOF_SSP_MASK_HDMI_CAPTURE(0x5)), }, { - .name = "tgl_max98373_rt5682", + .name = "arl_rt5682_c1_h02", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - SOF_SPEAKER_AMP_PRESENT | - SOF_MAX98373_SPEAKER_AMP_PRESENT | - SOF_RT5682_SSP_AMP(1) | - SOF_RT5682_NUM_HDMIDEV(4)), + SOF_SSP_PORT_CODEC(1) | + /* SSP 0 and SSP 2 are used for HDMI IN */ + SOF_SSP_MASK_HDMI_CAPTURE(0x5)), }, { - .name = "jsl_rt5682_max98360a", + .name = "ptl_rt5682_def", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_MCLK_24MHZ | - SOF_RT5682_SSP_CODEC(0) | - SOF_SPEAKER_AMP_PRESENT | - SOF_MAX98360A_SPEAKER_AMP_PRESENT | - SOF_RT5682_SSP_AMP(1)), + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1) | + SOF_SSP_PORT_BT_OFFLOAD(2) | + SOF_BT_OFFLOAD_PRESENT), }, { } }; +MODULE_DEVICE_TABLE(platform, board_ids); static struct platform_driver sof_audio = { .probe = sof_audio_probe, @@ -879,9 +910,9 @@ module_platform_driver(sof_audio) MODULE_DESCRIPTION("SOF Audio Machine driver"); MODULE_AUTHOR("Bard Liao <bard.liao@intel.com>"); MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>"); +MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); +MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:sof_rt5682"); -MODULE_ALIAS("platform:tgl_max98357a_rt5682"); -MODULE_ALIAS("platform:jsl_rt5682_rt1015"); -MODULE_ALIAS("platform:tgl_max98373_rt5682"); -MODULE_ALIAS("platform:jsl_rt5682_max98360a"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_MAXIM_COMMON"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_REALTEK_COMMON"); diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 2463d432bf4d..81a914bd7ec2 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -5,40 +5,48 @@ * sof_sdw - ASOC Machine driver for Intel SoundWire platforms */ +#include <linux/acpi.h> +#include <linux/bitmap.h> #include <linux/device.h> #include <linux/dmi.h> #include <linux/module.h> #include <linux/soundwire/sdw.h> #include <linux/soundwire/sdw_type.h> -#include <sound/soc.h> +#include <linux/soundwire/sdw_intel.h> +#include <sound/core.h> #include <sound/soc-acpi.h> #include "sof_sdw_common.h" +#include "../../codecs/rt711.h" -unsigned long sof_sdw_quirk = SOF_RT711_JD_SRC_JD1; +static unsigned long sof_sdw_quirk = RT711_JD1; static int quirk_override = -1; module_param_named(quirk, quirk_override, int, 0444); MODULE_PARM_DESC(quirk, "Board-specific quirk override"); -#define INC_ID(BE, CPU, LINK) do { (BE)++; (CPU)++; (LINK)++; } while (0) +#define DMIC_DEFAULT_CHANNELS 2 static void log_quirks(struct device *dev) { - if (SOF_RT711_JDSRC(sof_sdw_quirk)) + if (SOC_SDW_JACK_JDSRC(sof_sdw_quirk)) dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n", - SOF_RT711_JDSRC(sof_sdw_quirk)); - if (sof_sdw_quirk & SOF_SDW_FOUR_SPK) - dev_dbg(dev, "quirk SOF_SDW_FOUR_SPK enabled\n"); + SOC_SDW_JACK_JDSRC(sof_sdw_quirk)); + if (sof_sdw_quirk & SOC_SDW_FOUR_SPK) + dev_err(dev, "quirk SOC_SDW_FOUR_SPK enabled but no longer supported\n"); if (sof_sdw_quirk & SOF_SDW_TGL_HDMI) dev_dbg(dev, "quirk SOF_SDW_TGL_HDMI enabled\n"); - if (sof_sdw_quirk & SOF_SDW_PCH_DMIC) - dev_dbg(dev, "quirk SOF_SDW_PCH_DMIC enabled\n"); + if (sof_sdw_quirk & SOC_SDW_PCH_DMIC) + dev_dbg(dev, "quirk SOC_SDW_PCH_DMIC enabled\n"); if (SOF_SSP_GET_PORT(sof_sdw_quirk)) dev_dbg(dev, "SSP port %ld\n", SOF_SSP_GET_PORT(sof_sdw_quirk)); - if (sof_sdw_quirk & SOF_RT715_DAI_ID_FIX) - dev_dbg(dev, "quirk SOF_RT715_DAI_ID_FIX enabled\n"); - if (sof_sdw_quirk & SOF_SDW_NO_AGGREGATION) - dev_dbg(dev, "quirk SOF_SDW_NO_AGGREGATION enabled\n"); + if (sof_sdw_quirk & SOC_SDW_NO_AGGREGATION) + dev_err(dev, "quirk SOC_SDW_NO_AGGREGATION enabled but no longer supported\n"); + if (sof_sdw_quirk & SOC_SDW_CODEC_SPKR) + dev_dbg(dev, "quirk SOC_SDW_CODEC_SPKR enabled\n"); + if (sof_sdw_quirk & SOC_SDW_SIDECAR_AMPS) + dev_dbg(dev, "quirk SOC_SDW_SIDECAR_AMPS enabled\n"); + if (sof_sdw_quirk & SOC_SDW_CODEC_MIC) + dev_dbg(dev, "quirk SOC_SDW_CODEC_MIC enabled\n"); } static int sof_sdw_quirk_cb(const struct dmi_system_id *id) @@ -48,14 +56,22 @@ static int sof_sdw_quirk_cb(const struct dmi_system_id *id) } static const struct dmi_system_id sof_sdw_quirk_table[] = { + /* CometLake devices */ + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "CometLake Client"), + }, + .driver_data = (void *)SOC_SDW_PCH_DMIC, + }, { .callback = sof_sdw_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6") }, - .driver_data = (void *)(SOF_RT711_JD_SRC_JD2 | - SOF_RT715_DAI_ID_FIX), + .driver_data = (void *)RT711_JD2, }, { /* early version of SKU 09C6 */ @@ -64,8 +80,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983") }, - .driver_data = (void *)(SOF_RT711_JD_SRC_JD2 | - SOF_RT715_DAI_ID_FIX), + .driver_data = (void *)RT711_JD2, }, { .callback = sof_sdw_quirk_cb, @@ -73,20 +88,26 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"), }, - .driver_data = (void *)(SOF_RT711_JD_SRC_JD2 | - SOF_RT715_DAI_ID_FIX | - SOF_SDW_FOUR_SPK), + .driver_data = (void *)(RT711_JD2), }, - { + { .callback = sof_sdw_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"), }, - .driver_data = (void *)(SOF_RT711_JD_SRC_JD2 | - SOF_RT715_DAI_ID_FIX | - SOF_SDW_FOUR_SPK), + .driver_data = (void *)(RT711_JD2), }, + /* IceLake devices */ + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"), + }, + .driver_data = (void *)SOC_SDW_PCH_DMIC, + }, + /* TigerLake devices */ { .callback = sof_sdw_quirk_cb, .matches = { @@ -94,25 +115,48 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Tiger Lake Client Platform"), }, - .driver_data = (void *)(SOF_RT711_JD_SRC_JD1 | - SOF_SDW_TGL_HDMI | SOF_SDW_PCH_DMIC | - SOF_SSP_PORT(SOF_I2S_SSP2)), + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD1 | + SOC_SDW_PCH_DMIC | + SOF_SSP_PORT(SOF_I2S_SSP2)), }, { .callback = sof_sdw_quirk_cb, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"), + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3E") }, - .driver_data = (void *)SOF_SDW_PCH_DMIC, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), }, { + /* another SKU of Dell Latitude 9520 */ .callback = sof_sdw_quirk_cb, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "CometLake Client"), + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3F") }, - .driver_data = (void *)SOF_SDW_PCH_DMIC, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), + }, + { + /* Dell XPS 9710 */ + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5D") + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5E") + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), }, { .callback = sof_sdw_quirk_cb, @@ -120,910 +164,1219 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Google"), DMI_MATCH(DMI_PRODUCT_NAME, "Volteer"), }, - .driver_data = (void *)(SOF_SDW_TGL_HDMI | SOF_SDW_PCH_DMIC | - SOF_SDW_FOUR_SPK), + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + SOC_SDW_PCH_DMIC | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), }, - - {} -}; - -static struct snd_soc_codec_conf codec_conf[] = { { - .dlc = COMP_CODEC_CONF("sdw:0:25d:711:0"), - .name_prefix = "rt711", + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_PRODUCT_NAME, "Ripto"), + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + SOC_SDW_PCH_DMIC), }, - /* rt1308 w/ I2S connection */ { - .dlc = COMP_CODEC_CONF("i2c-10EC1308:00"), - .name_prefix = "rt1308-1", + /* + * this entry covers multiple HP SKUs. The family name + * does not seem robust enough, so we use a partial + * match that ignores the product name suffix + * (e.g. 15-eb1xxx, 14t-ea000 or 13-aw2xxx) + */ + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Conv"), + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + SOC_SDW_PCH_DMIC | + RT711_JD1), }, - /* rt1308 left on link 1 */ { - .dlc = COMP_CODEC_CONF("sdw:1:25d:1308:0"), - .name_prefix = "rt1308-1", + /* + * this entry covers HP Spectre x360 where the DMI information + * changed somehow + */ + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_BOARD_NAME, "8709"), + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + SOC_SDW_PCH_DMIC | + RT711_JD1), }, - /* two 1308s on link1 with different unique id */ { - .dlc = COMP_CODEC_CONF("sdw:1:25d:1308:0:0"), - .name_prefix = "rt1308-1", + /* NUC15 'Bishop County' LAPBC510 and LAPBC710 skews */ + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"), + DMI_MATCH(DMI_PRODUCT_NAME, "LAPBC"), + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + SOC_SDW_PCH_DMIC | + RT711_JD1), }, { - .dlc = COMP_CODEC_CONF("sdw:1:25d:1308:0:2"), - .name_prefix = "rt1308-2", + /* NUC15 LAPBC710 skews */ + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "LAPBC710"), + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + SOC_SDW_PCH_DMIC | + RT711_JD1), }, - /* rt1308 right on link 2 */ { - .dlc = COMP_CODEC_CONF("sdw:2:25d:1308:0"), - .name_prefix = "rt1308-2", + /* NUC15 'Rooks County' LAPRC510 and LAPRC710 skews */ + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"), + DMI_MATCH(DMI_PRODUCT_NAME, "LAPRC"), + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + SOC_SDW_PCH_DMIC | + RT711_JD2_100K), }, { - .dlc = COMP_CODEC_CONF("sdw:3:25d:715:0"), - .name_prefix = "rt715", + /* NUC15 LAPRC710 skews */ + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "LAPRC710"), + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + SOC_SDW_PCH_DMIC | + RT711_JD2_100K), }, - /* two MAX98373s on link1 with different unique id */ + /* TigerLake-SDCA devices */ { - .dlc = COMP_CODEC_CONF("sdw:1:19f:8373:0:3"), - .name_prefix = "Right", + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A32") + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), }, { - .dlc = COMP_CODEC_CONF("sdw:1:19f:8373:0:7"), - .name_prefix = "Left", + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A45") + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), }, + /* AlderLake devices */ { - .dlc = COMP_CODEC_CONF("sdw:0:25d:5682:0"), - .name_prefix = "rt5682", + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alder Lake Client Platform"), + }, + .driver_data = (void *)(RT711_JD2_100K | + SOF_SDW_TGL_HDMI | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), }, -}; - -static struct snd_soc_dai_link_component dmic_component[] = { { - .name = "dmic-codec", - .dai_name = "dmic-hifi", - } -}; - -static struct snd_soc_dai_link_component platform_component[] = { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_PRODUCT_SKU, "0000000000070000"), + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2_100K), + }, { - /* name might be overridden during probe */ - .name = "0000:00:1f.3" - } -}; - -/* these wrappers are only needed to avoid typecast compilation errors */ -int sdw_startup(struct snd_pcm_substream *substream) -{ - return sdw_startup_stream(substream); -} + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_PRODUCT_NAME, "Brya"), + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + SOC_SDW_PCH_DMIC | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF0") + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF3"), + }, + /* No Jack */ + .driver_data = (void *)(SOF_SDW_TGL_HDMI), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE") + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF") + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00") + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01") + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B11") + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B12") + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B13"), + }, + /* No Jack */ + .driver_data = (void *)SOF_SDW_TGL_HDMI, + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B14"), + }, + /* No Jack */ + .driver_data = (void *)SOF_SDW_TGL_HDMI, + }, -void sdw_shutdown(struct snd_pcm_substream *substream) -{ - sdw_shutdown_stream(substream); -} + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B29"), + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B34"), + }, + /* No Jack */ + .driver_data = (void *)SOF_SDW_TGL_HDMI, + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B8C"), + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16"), + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), + }, + /* RaptorLake devices */ + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0BDA") + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C0F") + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C10"), + }, + /* No Jack */ + .driver_data = (void *)(SOF_SDW_TGL_HDMI), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C11") + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C40") + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C4F") + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF6") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF9") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CFA") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + /* MeteorLake devices */ + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_mtlrvp"), + }, + .driver_data = (void *)(RT711_JD1), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "Meteor Lake Client Platform"), + }, + .driver_data = (void *)(RT711_JD2_100K), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_PRODUCT_NAME, "Rex"), + }, + .driver_data = (void *)(SOC_SDW_PCH_DMIC | + SOF_BT_OFFLOAD_SSP(1) | + SOF_SSP_BT_OFFLOAD_PRESENT), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "OMEN Transcend Gaming Laptop"), + }, + .driver_data = (void *)(RT711_JD2), + }, -static const struct snd_soc_ops sdw_ops = { - .startup = sdw_startup, - .shutdown = sdw_shutdown, -}; + /* LunarLake devices */ + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "Lunar Lake Client Platform"), + }, + .driver_data = (void *)(RT711_JD2), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE3") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE4") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDB") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDC") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDD") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0D36") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF8") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "83JX") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "83LC") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "83MC") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC), + }, { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "83NM") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "83HM") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | + SOC_SDW_CODEC_MIC), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "21QB") + }, + /* Note this quirk excludes the CODEC mic */ + .driver_data = (void *)(SOC_SDW_CODEC_MIC), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "21QA") + }, + /* Note this quirk excludes the CODEC mic */ + .driver_data = (void *)(SOC_SDW_CODEC_MIC), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "21Q6") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "21Q7") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC), + }, -static struct sof_sdw_codec_info codec_info_list[] = { + /* ArrowLake devices */ { - .id = 0x700, - .direction = {true, true}, - .dai_name = "rt700-aif1", - .init = sof_sdw_rt700_init, + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE8") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), }, { - .id = 0x711, - .direction = {true, true}, - .dai_name = "rt711-aif1", - .init = sof_sdw_rt711_init, - .exit = sof_sdw_rt711_exit, + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF1") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), }, { - .id = 0x1308, - .acpi_id = "10EC1308", - .direction = {true, false}, - .dai_name = "rt1308-aif", - .ops = &sof_sdw_rt1308_i2s_ops, - .init = sof_sdw_rt1308_init, + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF7") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), }, { - .id = 0x715, - .direction = {false, true}, - .dai_name = "rt715-aif2", - .init = sof_sdw_rt715_init, + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF0") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), }, { - .id = 0x8373, - .direction = {true, true}, - .dai_name = "max98373-aif1", - .init = sof_sdw_mx8373_init, - .codec_card_late_probe = sof_sdw_mx8373_late_probe, + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF3") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF4") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF5") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + /* Pantherlake devices*/ + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_ptlrvp"), + }, + .driver_data = (void *)(SOC_SDW_PCH_DMIC), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_PRODUCT_NAME, "Fatcat"), + }, + .driver_data = (void *)(SOC_SDW_PCH_DMIC | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), + }, + /* Wildcatlake devices*/ + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_wclrvp"), + }, + .driver_data = (void *)(SOC_SDW_PCH_DMIC), }, { - .id = 0x5682, - .direction = {true, true}, - .dai_name = "rt5682-sdw", - .init = sof_sdw_rt5682_init, + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_PRODUCT_NAME, "Ocelot"), + }, + .driver_data = (void *)(SOC_SDW_PCH_DMIC | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), }, + {} }; -static inline int find_codec_info_part(unsigned int part_id) -{ - int i; +static const struct snd_pci_quirk sof_sdw_ssid_quirk_table[] = { + SND_PCI_QUIRK(0x1043, 0x1e13, "ASUS Zenbook S14", SOC_SDW_CODEC_MIC), + SND_PCI_QUIRK(0x1043, 0x1f43, "ASUS Zenbook S16", SOC_SDW_CODEC_MIC), + {} +}; - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) - if (part_id == codec_info_list[i].id) - break; +static void sof_sdw_check_ssid_quirk(const struct snd_soc_acpi_mach *mach) +{ + const struct snd_pci_quirk *quirk_entry; - if (i == ARRAY_SIZE(codec_info_list)) - return -EINVAL; + quirk_entry = snd_pci_quirk_lookup_id(mach->mach_params.subsystem_vendor, + mach->mach_params.subsystem_device, + sof_sdw_ssid_quirk_table); - return i; + if (quirk_entry) + sof_sdw_quirk = quirk_entry->value; } -static inline int find_codec_info_acpi(const u8 *acpi_id) -{ - int i; +static const struct snd_soc_ops sdw_ops = { + .startup = asoc_sdw_startup, + .prepare = asoc_sdw_prepare, + .trigger = asoc_sdw_trigger, + .hw_params = asoc_sdw_hw_params, + .hw_free = asoc_sdw_hw_free, + .shutdown = asoc_sdw_shutdown, +}; - if (!acpi_id[0]) - return -EINVAL; +static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) - if (!memcmp(codec_info_list[i].acpi_id, acpi_id, - ACPI_ID_LEN)) - break; +static int create_sdw_dailink(struct snd_soc_card *card, + struct asoc_sdw_dailink *sof_dai, + struct snd_soc_dai_link **dai_links, + int *be_id, struct snd_soc_codec_conf **codec_conf) +{ + struct device *dev = card->dev; + struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; + struct asoc_sdw_endpoint *sof_end; + int stream; + int ret; - if (i == ARRAY_SIZE(codec_info_list)) - return -EINVAL; + list_for_each_entry(sof_end, &sof_dai->endpoints, list) { + if (sof_end->name_prefix) { + (*codec_conf)->dlc.name = sof_end->codec_name; + (*codec_conf)->name_prefix = sof_end->name_prefix; + (*codec_conf)++; + } - return i; -} + if (sof_end->include_sidecar) { + ret = sof_end->codec_info->add_sidecar(card, dai_links, codec_conf); + if (ret) + return ret; + } + } -/* - * get BE dailink number and CPU DAI number based on sdw link adr. - * Since some sdw slaves may be aggregated, the CPU DAI number - * may be larger than the number of BE dailinks. - */ -static int get_sdw_dailink_info(const struct snd_soc_acpi_link_adr *links, - int *sdw_be_num, int *sdw_cpu_dai_num) -{ - const struct snd_soc_acpi_link_adr *link; - bool group_visited[SDW_MAX_GROUPS]; - bool no_aggregation; - int i; - - no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION; - *sdw_cpu_dai_num = 0; - *sdw_be_num = 0; - - if (!links) - return -EINVAL; - - for (i = 0; i < SDW_MAX_GROUPS; i++) - group_visited[i] = false; - - for (link = links; link->num_adr; link++) { - const struct snd_soc_acpi_endpoint *endpoint; - int part_id, codec_index; - int stream; - u64 adr; - - adr = link->adr_d->adr; - part_id = SDW_PART_ID(adr); - codec_index = find_codec_info_part(part_id); - if (codec_index < 0) - return codec_index; - - endpoint = link->adr_d->endpoints; - - /* count DAI number for playback and capture */ - for_each_pcm_streams(stream) { - if (!codec_info_list[codec_index].direction[stream]) - continue; + for_each_pcm_streams(stream) { + static const char * const sdw_stream_name[] = { + "SDW%d-Playback", + "SDW%d-Capture", + "SDW%d-Playback-%s", + "SDW%d-Capture-%s", + }; + struct snd_soc_dai_link_ch_map *codec_maps; + struct snd_soc_dai_link_component *codecs; + struct snd_soc_dai_link_component *cpus; + struct snd_soc_dai_link_component *platform; + int num_cpus = hweight32(sof_dai->link_mask[stream]); + int num_codecs = sof_dai->num_devs[stream]; + int playback, capture; + int cur_link = 0; + int i = 0, j = 0; + char *name; - (*sdw_cpu_dai_num)++; + if (!sof_dai->num_devs[stream]) + continue; + + sof_end = list_first_entry(&sof_dai->endpoints, + struct asoc_sdw_endpoint, list); - /* count BE for each non-aggregated slave or group */ - if (!endpoint->aggregated || no_aggregation || - !group_visited[endpoint->group_id]) - (*sdw_be_num)++; + *be_id = sof_end->dai_info->dailink[stream]; + if (*be_id < 0) { + dev_err(dev, "Invalid dailink id %d\n", *be_id); + return -EINVAL; } - if (endpoint->aggregated) - group_visited[endpoint->group_id] = true; - } + /* create stream name according to first link id */ + if (ctx->append_dai_type) + name = devm_kasprintf(dev, GFP_KERNEL, + sdw_stream_name[stream + 2], + ffs(sof_end->link_mask) - 1, + type_strings[sof_end->dai_info->dai_type]); + else + name = devm_kasprintf(dev, GFP_KERNEL, + sdw_stream_name[stream], + ffs(sof_end->link_mask) - 1); + if (!name) + return -ENOMEM; - return 0; -} + cpus = devm_kcalloc(dev, num_cpus, sizeof(*cpus), GFP_KERNEL); + if (!cpus) + return -ENOMEM; -static void init_dai_link(struct snd_soc_dai_link *dai_links, int be_id, - char *name, int playback, int capture, - struct snd_soc_dai_link_component *cpus, - int cpus_num, - struct snd_soc_dai_link_component *codecs, - int codecs_num, - int (*init)(struct snd_soc_pcm_runtime *rtd), - const struct snd_soc_ops *ops) -{ - dai_links->id = be_id; - dai_links->name = name; - dai_links->platforms = platform_component; - dai_links->num_platforms = ARRAY_SIZE(platform_component); - dai_links->nonatomic = true; - dai_links->no_pcm = 1; - dai_links->cpus = cpus; - dai_links->num_cpus = cpus_num; - dai_links->codecs = codecs; - dai_links->num_codecs = codecs_num; - dai_links->dpcm_playback = playback; - dai_links->dpcm_capture = capture; - dai_links->init = init; - dai_links->ops = ops; -} + codecs = devm_kcalloc(dev, num_codecs, sizeof(*codecs), GFP_KERNEL); + if (!codecs) + return -ENOMEM; -static bool is_unique_device(const struct snd_soc_acpi_link_adr *link, - unsigned int sdw_version, - unsigned int mfg_id, - unsigned int part_id, - unsigned int class_id, - int index_in_link - ) -{ - int i; + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!platform) + return -ENOMEM; - for (i = 0; i < link->num_adr; i++) { - unsigned int sdw1_version, mfg1_id, part1_id, class1_id; - u64 adr; + codec_maps = devm_kcalloc(dev, num_codecs, sizeof(*codec_maps), GFP_KERNEL); + if (!codec_maps) + return -ENOMEM; - /* skip itself */ - if (i == index_in_link) - continue; + list_for_each_entry(sof_end, &sof_dai->endpoints, list) { + if (!sof_end->dai_info->direction[stream]) + continue; - adr = link->adr_d[i].adr; + if (cur_link != sof_end->link_mask) { + int link_num = ffs(sof_end->link_mask) - 1; + int pin_num = intel_ctx->sdw_pin_index[link_num]++; - sdw1_version = SDW_VERSION(adr); - mfg1_id = SDW_MFG_ID(adr); - part1_id = SDW_PART_ID(adr); - class1_id = SDW_CLASS_ID(adr); + cur_link = sof_end->link_mask; - if (sdw_version == sdw1_version && - mfg_id == mfg1_id && - part_id == part1_id && - class_id == class1_id) - return false; - } + cpus[i].dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SDW%d Pin%d", + link_num, pin_num); + if (!cpus[i].dai_name) + return -ENOMEM; + i++; + } - return true; -} + codec_maps[j].cpu = i - 1; + codec_maps[j].codec = j; -static int create_codec_dai_name(struct device *dev, - const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link_component *codec, - int offset) -{ - int i; - - for (i = 0; i < link->num_adr; i++) { - unsigned int sdw_version, unique_id, mfg_id; - unsigned int link_id, part_id, class_id; - int codec_index, comp_index; - char *codec_str; - u64 adr; - - adr = link->adr_d[i].adr; - - sdw_version = SDW_VERSION(adr); - link_id = SDW_DISCO_LINK_ID(adr); - unique_id = SDW_UNIQUE_ID(adr); - mfg_id = SDW_MFG_ID(adr); - part_id = SDW_PART_ID(adr); - class_id = SDW_CLASS_ID(adr); - - comp_index = i + offset; - if (is_unique_device(link, sdw_version, mfg_id, part_id, - class_id, i)) { - codec_str = "sdw:%x:%x:%x:%x"; - codec[comp_index].name = - devm_kasprintf(dev, GFP_KERNEL, codec_str, - link_id, mfg_id, part_id, - class_id); - } else { - codec_str = "sdw:%x:%x:%x:%x:%x"; - codec[comp_index].name = - devm_kasprintf(dev, GFP_KERNEL, codec_str, - link_id, mfg_id, part_id, - class_id, unique_id); + codecs[j].name = sof_end->codec_name; + codecs[j].dai_name = sof_end->dai_info->dai_name; + if (sof_end->dai_info->dai_type == SOC_SDW_DAI_TYPE_MIC && + mach_params->dmic_num > 0) { + dev_warn(dev, + "Both SDW DMIC and PCH DMIC are present, if incorrect, please set kernel params snd_sof_intel_hda_generic dmic_num=0 to disable PCH DMIC\n"); + } + j++; } - if (!codec[comp_index].name) - return -ENOMEM; + WARN_ON(i != num_cpus || j != num_codecs); - codec_index = find_codec_info_part(part_id); - if (codec_index < 0) - return codec_index; + playback = (stream == SNDRV_PCM_STREAM_PLAYBACK); + capture = (stream == SNDRV_PCM_STREAM_CAPTURE); + + asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, playback, capture, + cpus, num_cpus, platform, 1, codecs, num_codecs, + 1, asoc_sdw_rtd_init, &sdw_ops); + + /* + * SoundWire DAILINKs use 'stream' functions and Bank Switch operations + * based on wait_for_completion(), tag them as 'nonatomic'. + */ + (*dai_links)->nonatomic = true; + (*dai_links)->ch_maps = codec_maps; + + list_for_each_entry(sof_end, &sof_dai->endpoints, list) { + if (sof_end->dai_info->init) + sof_end->dai_info->init(card, *dai_links, + sof_end->codec_info, + playback); + } - codec[comp_index].dai_name = - codec_info_list[codec_index].dai_name; + (*dai_links)++; } return 0; } -static int set_codec_init_func(const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - bool playback, int group_id) +static int create_sdw_dailinks(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, int *be_id, + struct asoc_sdw_dailink *sof_dais, + struct snd_soc_codec_conf **codec_conf) { - int i; + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; + int ret, i; - do { - /* - * Initialize the codec. If codec is part of an aggregated - * group (group_id>0), initialize all codecs belonging to - * same group. - */ - for (i = 0; i < link->num_adr; i++) { - unsigned int part_id; - int codec_index; + for (i = 0; i < SDW_INTEL_MAX_LINKS; i++) + intel_ctx->sdw_pin_index[i] = SOC_SDW_INTEL_BIDIR_PDI_BASE; + + /* generate DAI links by each sdw link */ + while (sof_dais->initialised) { + int current_be_id = 0; - part_id = SDW_PART_ID(link->adr_d[i].adr); - codec_index = find_codec_info_part(part_id); + ret = create_sdw_dailink(card, sof_dais, dai_links, + ¤t_be_id, codec_conf); + if (ret) + return ret; - if (codec_index < 0) - return codec_index; - /* The group_id is > 0 iff the codec is aggregated */ - if (link->adr_d[i].endpoints->group_id != group_id) - continue; - if (codec_info_list[codec_index].init) - codec_info_list[codec_index].init(link, - dai_links, - &codec_info_list[codec_index], - playback); - } - link++; - } while (link->mask && group_id); + /* Update the be_id to match the highest ID used for SDW link */ + if (*be_id < current_be_id) + *be_id = current_be_id; + + sof_dais++; + } return 0; } -/* - * check endpoint status in slaves and gather link ID for all slaves in - * the same group to generate different CPU DAI. Now only support - * one sdw link with all slaves set with only single group id. - * - * one slave on one sdw link with aggregated = 0 - * one sdw BE DAI <---> one-cpu DAI <---> one-codec DAI - * - * two or more slaves on one sdw link with aggregated = 0 - * one sdw BE DAI <---> one-cpu DAI <---> multi-codec DAIs - * - * multiple links with multiple slaves with aggregated = 1 - * one sdw BE DAI <---> 1 .. N CPU DAIs <----> 1 .. N codec DAIs - */ -static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, - struct device *dev, int *cpu_dai_id, int *cpu_dai_num, - int *codec_num, int *group_id, - bool *group_generated) +static int create_ssp_dailinks(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, int *be_id, + struct asoc_sdw_codec_info *ssp_info, + unsigned long ssp_mask) { - const struct snd_soc_acpi_adr_device *adr_d; - const struct snd_soc_acpi_link_adr *adr_next; - bool no_aggregation; - int index = 0; - - no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION; - *codec_num = adr_link->num_adr; - adr_d = adr_link->adr_d; - - /* make sure the link mask has a single bit set */ - if (!is_power_of_2(adr_link->mask)) - return -EINVAL; - - cpu_dai_id[index++] = ffs(adr_link->mask) - 1; - if (!adr_d->endpoints->aggregated || no_aggregation) { - *cpu_dai_num = 1; - *group_id = 0; - return 0; - } - - *group_id = adr_d->endpoints->group_id; + struct device *dev = card->dev; + int i, j = 0; + int ret; - /* gather other link ID of slaves in the same group */ - for (adr_next = adr_link + 1; adr_next && adr_next->num_adr; - adr_next++) { - const struct snd_soc_acpi_endpoint *endpoint; + for_each_set_bit(i, &ssp_mask, BITS_PER_TYPE(ssp_mask)) { + char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", i); + char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i); + char *codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d", + ssp_info->acpi_id, j++); + if (!name || !cpu_dai_name || !codec_name) + return -ENOMEM; - endpoint = adr_next->adr_d->endpoints; - if (!endpoint->aggregated || - endpoint->group_id != *group_id) - continue; + int playback = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK]; + int capture = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE]; - /* make sure the link mask has a single bit set */ - if (!is_power_of_2(adr_next->mask)) - return -EINVAL; + ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, + playback, capture, cpu_dai_name, + "dummy", codec_name, + ssp_info->dais[0].dai_name, 1, NULL, + ssp_info->ops); + if (ret) + return ret; - if (index >= SDW_MAX_CPU_DAIS) { - dev_err(dev, " cpu_dai_id array overflows"); - return -EINVAL; - } + ret = ssp_info->dais[0].init(card, *dai_links, ssp_info, 0); + if (ret < 0) + return ret; - cpu_dai_id[index++] = ffs(adr_next->mask) - 1; - *codec_num += adr_next->num_adr; + (*dai_links)++; } - /* - * indicate CPU DAIs for this group have been generated - * to avoid generating CPU DAIs for this group again. - */ - group_generated[*group_id] = true; - *cpu_dai_num = index; - return 0; } -static int create_sdw_dailink(struct device *dev, int *be_index, - struct snd_soc_dai_link *dai_links, - int sdw_be_num, int sdw_cpu_dai_num, - struct snd_soc_dai_link_component *cpus, - const struct snd_soc_acpi_link_adr *link, - int *cpu_id, bool *group_generated) +static int create_dmic_dailinks(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, int *be_id) { - const struct snd_soc_acpi_link_adr *link_next; - struct snd_soc_dai_link_component *codecs; - int cpu_dai_id[SDW_MAX_CPU_DAIS]; - int cpu_dai_num, cpu_dai_index; - unsigned int part_id, group_id; - int codec_idx = 0; - int i = 0, j = 0; - int codec_index; - int codec_num; - int stream; + struct device *dev = card->dev; int ret; - int k; - ret = get_slave_info(link, dev, cpu_dai_id, &cpu_dai_num, &codec_num, - &group_id, group_generated); + ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic01", + 0, 1, // DMIC only supports capture + "DMIC01 Pin", "dummy", + "dmic-codec", "dmic-hifi", 1, + asoc_sdw_dmic_init, NULL); if (ret) return ret; - codecs = devm_kcalloc(dev, codec_num, sizeof(*codecs), GFP_KERNEL); - if (!codecs) - return -ENOMEM; - - /* generate codec name on different links in the same group */ - for (link_next = link; link_next && link_next->num_adr && - i < cpu_dai_num; link_next++) { - const struct snd_soc_acpi_endpoint *endpoints; + (*dai_links)++; - endpoints = link_next->adr_d->endpoints; - if (group_id && (!endpoints->aggregated || - endpoints->group_id != group_id)) - continue; - - /* skip the link excluded by this processed group */ - if (cpu_dai_id[i] != ffs(link_next->mask) - 1) - continue; - - ret = create_codec_dai_name(dev, link_next, codecs, codec_idx); - if (ret < 0) - return ret; - - /* check next link to create codec dai in the processed group */ - i++; - codec_idx += link_next->num_adr; - } + ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic16k", + 0, 1, // DMIC only supports capture + "DMIC16k Pin", "dummy", + "dmic-codec", "dmic-hifi", 1, + /* don't call asoc_sdw_dmic_init() twice */ + NULL, NULL); + if (ret) + return ret; - /* find codec info to create BE DAI */ - part_id = SDW_PART_ID(link->adr_d[0].adr); - codec_index = find_codec_info_part(part_id); - if (codec_index < 0) - return codec_index; + (*dai_links)++; - cpu_dai_index = *cpu_id; - for_each_pcm_streams(stream) { - char *name, *cpu_name; - int playback, capture; - static const char * const sdw_stream_name[] = { - "SDW%d-Playback", - "SDW%d-Capture", - }; + return 0; +} - if (!codec_info_list[codec_index].direction[stream]) - continue; +static int create_hdmi_dailinks(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, int *be_id, + int hdmi_num) +{ + struct device *dev = card->dev; + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; + int i, ret; - /* create stream name according to first link id */ - name = devm_kasprintf(dev, GFP_KERNEL, - sdw_stream_name[stream], cpu_dai_id[0]); - if (!name) + for (i = 0; i < hdmi_num; i++) { + char *name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", i + 1); + char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", i + 1); + if (!name || !cpu_dai_name) return -ENOMEM; - /* - * generate CPU DAI name base on the sdw link ID and - * PIN ID with offset of 2 according to sdw dai driver. - */ - for (k = 0; k < cpu_dai_num; k++) { - cpu_name = devm_kasprintf(dev, GFP_KERNEL, - "SDW%d Pin%d", cpu_dai_id[k], - j + SDW_INTEL_BIDIR_PDI_BASE); - if (!cpu_name) - return -ENOMEM; - - if (cpu_dai_index >= sdw_cpu_dai_num) { - dev_err(dev, "invalid cpu dai index %d", - cpu_dai_index); - return -EINVAL; - } - - cpus[cpu_dai_index++].dai_name = cpu_name; - } + char *codec_name, *codec_dai_name; - if (*be_index >= sdw_be_num) { - dev_err(dev, " invalid be dai index %d", *be_index); - return -EINVAL; + if (intel_ctx->hdmi.idisp_codec) { + codec_name = "ehdaudio0D2"; + codec_dai_name = devm_kasprintf(dev, GFP_KERNEL, + "intel-hdmi-hifi%d", i + 1); + } else { + codec_name = "snd-soc-dummy"; + codec_dai_name = "snd-soc-dummy-dai"; } - if (*cpu_id >= sdw_cpu_dai_num) { - dev_err(dev, " invalid cpu dai index %d", *cpu_id); - return -EINVAL; - } + if (!codec_dai_name) + return -ENOMEM; - playback = (stream == SNDRV_PCM_STREAM_PLAYBACK); - capture = (stream == SNDRV_PCM_STREAM_CAPTURE); - init_dai_link(dai_links + *be_index, *be_index, name, - playback, capture, - cpus + *cpu_id, cpu_dai_num, - codecs, codec_num, - NULL, &sdw_ops); - - ret = set_codec_init_func(link, dai_links + (*be_index)++, - playback, group_id); - if (ret < 0) { - dev_err(dev, "failed to init codec %d", codec_index); + ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, + 1, 0, // HDMI only supports playback + cpu_dai_name, "dummy", + codec_name, codec_dai_name, 1, + i == 0 ? sof_sdw_hdmi_init : NULL, NULL); + if (ret) return ret; - } - *cpu_id += cpu_dai_num; - j++; + (*dai_links)++; } return 0; } -/* - * DAI link ID of SSP & DMIC & HDMI are based on last - * link ID used by sdw link. Since be_id may be changed - * in init func of sdw codec, it is not equal to be_id - */ -static inline int get_next_be_id(struct snd_soc_dai_link *links, - int be_id) +static int create_bt_dailinks(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, int *be_id) { - return links[be_id - 1].id + 1; -} - -#define IDISP_CODEC_MASK 0x4 + struct device *dev = card->dev; + int port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> + SOF_BT_OFFLOAD_SSP_SHIFT; + char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); + char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port); + if (!name || !cpu_dai_name) + return -ENOMEM; -static int sof_card_dai_links_create(struct device *dev, - struct snd_soc_acpi_mach *mach, - struct snd_soc_card *card) -{ - int ssp_num, sdw_be_num = 0, hdmi_num = 0, dmic_num; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_dai_link_component *idisp_components; - struct snd_soc_dai_link_component *ssp_components; - struct snd_soc_acpi_mach_params *mach_params; - const struct snd_soc_acpi_link_adr *adr_link; - struct snd_soc_dai_link_component *cpus; - bool group_generated[SDW_MAX_GROUPS]; - int ssp_codec_index, ssp_mask; - struct snd_soc_dai_link *links; - int num_links, link_id = 0; - char *name, *cpu_name; - int total_cpu_dai_num; - int sdw_cpu_dai_num; - int i, j, be_id = 0; - int cpu_id = 0; - int comp_num; int ret; - /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) - codec_info_list[i].amp_num = 0; + ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, + 1, 1, cpu_dai_name, "dummy", + snd_soc_dummy_dlc.name, snd_soc_dummy_dlc.dai_name, + 1, NULL, NULL); + if (ret) + return ret; - hdmi_num = sof_sdw_quirk & SOF_SDW_TGL_HDMI ? - SOF_TGL_HDMI_COUNT : SOF_PRE_TGL_HDMI_COUNT; + (*dai_links)++; - ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk); - /* - * on generic tgl platform, I2S or sdw mode is supported - * based on board rework. A ACPI device is registered in - * system only when I2S mode is supported, not sdw mode. - * Here check ACPI ID to confirm I2S is supported. - */ - ssp_codec_index = find_codec_info_acpi(mach->id); - ssp_num = ssp_codec_index >= 0 ? hweight_long(ssp_mask) : 0; - comp_num = hdmi_num + ssp_num; + return 0; +} + +static int sof_card_dai_links_create(struct snd_soc_card *card) +{ + struct device *dev = card->dev; + struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); + int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, bt_num = 0; + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; + struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; + struct snd_soc_codec_conf *codec_conf; + struct asoc_sdw_codec_info *ssp_info; + struct asoc_sdw_endpoint *sof_ends; + struct asoc_sdw_dailink *sof_dais; + int num_devs = 0; + int num_ends = 0; + struct snd_soc_dai_link *dai_links; + int num_links; + int be_id = 0; + int hdmi_num; + unsigned long ssp_mask; + int ret; - mach_params = &mach->mach_params; - ret = get_sdw_dailink_info(mach_params->links, - &sdw_be_num, &sdw_cpu_dai_num); + ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends); if (ret < 0) { - dev_err(dev, "failed to get sdw link info %d", ret); + dev_err(dev, "failed to count devices/endpoints: %d\n", ret); return ret; } - if (mach_params->codec_mask & IDISP_CODEC_MASK) - ctx->idisp_codec = true; - - /* enable dmic01 & dmic16k */ - dmic_num = (sof_sdw_quirk & SOF_SDW_PCH_DMIC) ? 2 : 0; - comp_num += dmic_num; - - dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d", sdw_be_num, ssp_num, - dmic_num, ctx->idisp_codec ? hdmi_num : 0); - - /* allocate BE dailinks */ - num_links = comp_num + sdw_be_num; - links = devm_kcalloc(dev, num_links, sizeof(*links), GFP_KERNEL); - - /* allocated CPU DAIs */ - total_cpu_dai_num = comp_num + sdw_cpu_dai_num; - cpus = devm_kcalloc(dev, total_cpu_dai_num, sizeof(*cpus), - GFP_KERNEL); - - if (!links || !cpus) - return -ENOMEM; - - /* SDW */ - if (!sdw_be_num) - goto SSP; - - adr_link = mach_params->links; - if (!adr_link) - return -EINVAL; - /* - * SoundWire Slaves aggregated in the same group may be - * located on different hardware links. Clear array to indicate - * CPU DAIs for this group have not been generated. + * One per DAI link, worst case is a DAI link for every endpoint, also + * add one additional to act as a terminator such that code can iterate + * until it hits an uninitialised DAI. */ - for (i = 0; i < SDW_MAX_GROUPS; i++) - group_generated[i] = false; - - /* generate DAI links by each sdw link */ - for (; adr_link->num_adr; adr_link++) { - const struct snd_soc_acpi_endpoint *endpoint; - - endpoint = adr_link->adr_d->endpoints; - if (endpoint->aggregated && !endpoint->group_id) { - dev_err(dev, "invalid group id on link %x", - adr_link->mask); - continue; - } - - /* this group has been generated */ - if (endpoint->aggregated && - group_generated[endpoint->group_id]) - continue; + sof_dais = kcalloc(num_ends + 1, sizeof(*sof_dais), GFP_KERNEL); + if (!sof_dais) + return -ENOMEM; - ret = create_sdw_dailink(dev, &be_id, links, sdw_be_num, - sdw_cpu_dai_num, cpus, adr_link, - &cpu_id, group_generated); - if (ret < 0) { - dev_err(dev, "failed to create dai link %d", be_id); - return -ENOMEM; - } + /* One per endpoint, ie. each DAI on each codec/amp */ + sof_ends = kcalloc(num_ends, sizeof(*sof_ends), GFP_KERNEL); + if (!sof_ends) { + ret = -ENOMEM; + goto err_dai; } - /* non-sdw DAI follows sdw DAI */ - link_id = be_id; + ret = asoc_sdw_parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs); + if (ret < 0) + goto err_end; - /* get BE ID for non-sdw DAI */ - be_id = get_next_be_id(links, be_id); + sdw_be_num = ret; -SSP: - /* SSP */ - if (!ssp_num) - goto DMIC; + /* + * on generic tgl platform, I2S or sdw mode is supported + * based on board rework. A ACPI device is registered in + * system only when I2S mode is supported, not sdw mode. + * Here check ACPI ID to confirm I2S is supported. + */ + ssp_info = asoc_sdw_find_codec_info_acpi(mach->id); + if (ssp_info) { + ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk); + ssp_num = hweight_long(ssp_mask); + } - for (i = 0, j = 0; ssp_mask; i++, ssp_mask >>= 1) { - struct sof_sdw_codec_info *info; - int playback, capture; - char *codec_name; + if (mach_params->codec_mask & IDISP_CODEC_MASK) + intel_ctx->hdmi.idisp_codec = true; - if (!(ssp_mask & 0x1)) - continue; + if (sof_sdw_quirk & SOF_SDW_TGL_HDMI) + hdmi_num = SOF_TGL_HDMI_COUNT; + else + hdmi_num = SOF_PRE_TGL_HDMI_COUNT; - name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d-Codec", i); - if (!name) - return -ENOMEM; + /* enable dmic01 & dmic16k */ + if (ctx->ignore_internal_dmic) { + dev_dbg(dev, "SoundWire DMIC is used, ignoring internal DMIC\n"); + mach_params->dmic_num = 0; + } else if (mach_params->dmic_num) { + dmic_num = 2; + } else if (sof_sdw_quirk & SOC_SDW_PCH_DMIC) { + dmic_num = 2; + /* + * mach_params->dmic_num will be used to set the cfg-mics value of + * card->components string. Set it to the default value. + */ + mach_params->dmic_num = DMIC_DEFAULT_CHANNELS; + } - cpu_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i); - if (!cpu_name) - return -ENOMEM; + if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) + bt_num = 1; - ssp_components = devm_kzalloc(dev, sizeof(*ssp_components), - GFP_KERNEL); - if (!ssp_components) - return -ENOMEM; + dev_dbg(dev, "DAI link numbers: sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n", + sdw_be_num, ssp_num, dmic_num, + intel_ctx->hdmi.idisp_codec ? hdmi_num : 0, bt_num); - info = &codec_info_list[ssp_codec_index]; - codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d", - info->acpi_id, j++); - if (!codec_name) - return -ENOMEM; + codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL); + if (!codec_conf) { + ret = -ENOMEM; + goto err_end; + } - ssp_components->name = codec_name; - ssp_components->dai_name = info->dai_name; - cpus[cpu_id].dai_name = cpu_name; + /* allocate BE dailinks */ + num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num; + dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL); + if (!dai_links) { + ret = -ENOMEM; + goto err_end; + } - playback = info->direction[SNDRV_PCM_STREAM_PLAYBACK]; - capture = info->direction[SNDRV_PCM_STREAM_CAPTURE]; - init_dai_link(links + link_id, be_id, name, - playback, capture, - cpus + cpu_id, 1, - ssp_components, 1, - NULL, info->ops); + card->codec_conf = codec_conf; + card->num_configs = num_devs; + card->dai_link = dai_links; + card->num_links = num_links; - ret = info->init(NULL, links + link_id, info, 0); - if (ret < 0) - return ret; + /* SDW */ + if (sdw_be_num) { + ret = create_sdw_dailinks(card, &dai_links, &be_id, + sof_dais, &codec_conf); + if (ret) + goto err_end; + } - INC_ID(be_id, cpu_id, link_id); + /* SSP */ + if (ssp_num) { + ret = create_ssp_dailinks(card, &dai_links, &be_id, + ssp_info, ssp_mask); + if (ret) + goto err_end; } -DMIC: /* dmic */ - if (dmic_num > 0) { - cpus[cpu_id].dai_name = "DMIC01 Pin"; - init_dai_link(links + link_id, be_id, "dmic01", - 0, 1, // DMIC only supports capture - cpus + cpu_id, 1, - dmic_component, 1, - sof_sdw_dmic_init, NULL); - INC_ID(be_id, cpu_id, link_id); - - cpus[cpu_id].dai_name = "DMIC16k Pin"; - init_dai_link(links + link_id, be_id, "dmic16k", - 0, 1, // DMIC only supports capture - cpus + cpu_id, 1, - dmic_component, 1, - /* don't call sof_sdw_dmic_init() twice */ - NULL, NULL); - INC_ID(be_id, cpu_id, link_id); + if (dmic_num) { + ret = create_dmic_dailinks(card, &dai_links, &be_id); + if (ret) + goto err_end; } /* HDMI */ - if (hdmi_num > 0) { - idisp_components = devm_kcalloc(dev, hdmi_num, - sizeof(*idisp_components), - GFP_KERNEL); - if (!idisp_components) - return -ENOMEM; - } - - for (i = 0; i < hdmi_num; i++) { - name = devm_kasprintf(dev, GFP_KERNEL, - "iDisp%d", i + 1); - if (!name) - return -ENOMEM; - - if (ctx->idisp_codec) { - idisp_components[i].name = "ehdaudio0D2"; - idisp_components[i].dai_name = devm_kasprintf(dev, - GFP_KERNEL, - "intel-hdmi-hifi%d", - i + 1); - if (!idisp_components[i].dai_name) - return -ENOMEM; - } else { - idisp_components[i].name = "snd-soc-dummy"; - idisp_components[i].dai_name = "snd-soc-dummy-dai"; - } - - cpu_name = devm_kasprintf(dev, GFP_KERNEL, - "iDisp%d Pin", i + 1); - if (!cpu_name) - return -ENOMEM; + ret = create_hdmi_dailinks(card, &dai_links, &be_id, hdmi_num); + if (ret) + goto err_end; - cpus[cpu_id].dai_name = cpu_name; - init_dai_link(links + link_id, be_id, name, - 1, 0, // HDMI only supports playback - cpus + cpu_id, 1, - idisp_components + i, 1, - sof_sdw_hdmi_init, NULL); - INC_ID(be_id, cpu_id, link_id); + /* BT */ + if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { + ret = create_bt_dailinks(card, &dai_links, &be_id); + if (ret) + goto err_end; } - card->dai_link = links; - card->num_links = num_links; + WARN_ON(codec_conf != card->codec_conf + card->num_configs); + WARN_ON(dai_links != card->dai_link + card->num_links); - return 0; +err_end: + kfree(sof_ends); +err_dai: + kfree(sof_dais); + + return ret; } static int sof_sdw_card_late_probe(struct snd_soc_card *card) { - int i, ret; + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; + int ret = 0; - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { - if (!codec_info_list[i].late_probe) - continue; + ret = asoc_sdw_card_late_probe(card); + if (ret < 0) + return ret; - ret = codec_info_list[i].codec_card_late_probe(card); - if (ret < 0) - return ret; - } + if (intel_ctx->hdmi.idisp_codec) + ret = sof_sdw_hdmi_card_late_probe(card); - return sof_sdw_hdmi_card_late_probe(card); + return ret; } -/* SoC card */ -static const char sdw_card_long_name[] = "Intel Soundwire SOF"; - -static struct snd_soc_card card_sof_sdw = { - .name = "soundwire", - .owner = THIS_MODULE, - .late_probe = sof_sdw_card_late_probe, - .codec_conf = codec_conf, - .num_configs = ARRAY_SIZE(codec_conf), -}; - static int mc_probe(struct platform_device *pdev) { - struct snd_soc_card *card = &card_sof_sdw; - struct snd_soc_acpi_mach *mach; - struct mc_private *ctx; + struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev); + struct snd_soc_card *card; + struct asoc_sdw_mc_private *ctx; + struct intel_mc_ctx *intel_ctx; int amp_num = 0, i; int ret; - dev_dbg(&pdev->dev, "Entry %s\n", __func__); + dev_dbg(&pdev->dev, "Entry\n"); + + intel_ctx = devm_kzalloc(&pdev->dev, sizeof(*intel_ctx), GFP_KERNEL); + if (!intel_ctx) + return -ENOMEM; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; + ctx->private = intel_ctx; + ctx->codec_info_list_count = asoc_sdw_get_codec_info_list_count(); + card = &ctx->card; + card->dev = &pdev->dev; + card->name = "soundwire"; + card->owner = THIS_MODULE; + card->late_probe = sof_sdw_card_late_probe; + + snd_soc_card_set_drvdata(card, ctx); + + if (mach->mach_params.subsystem_id_set) { + snd_soc_card_set_pci_ssid(card, + mach->mach_params.subsystem_vendor, + mach->mach_params.subsystem_device); + sof_sdw_check_ssid_quirk(mach); + } + dmi_check_system(sof_sdw_quirk_table); if (quirk_override != -1) { - dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n", + dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n", sof_sdw_quirk, quirk_override); sof_sdw_quirk = quirk_override; } - log_quirks(&pdev->dev); - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + log_quirks(card->dev); - card->dev = &pdev->dev; - snd_soc_card_set_drvdata(card, ctx); + ctx->mc_quirk = sof_sdw_quirk; + /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ + for (i = 0; i < ctx->codec_info_list_count; i++) + codec_info_list[i].amp_num = 0; - mach = pdev->dev.platform_data; - ret = sof_card_dai_links_create(&pdev->dev, mach, - card); + ret = sof_card_dai_links_create(card); if (ret < 0) return ret; - ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; - /* * the default amp_num is zero for each codec and * amp_num will only be increased for active amp * codecs on used platform */ - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) + for (i = 0; i < ctx->codec_info_list_count; i++) amp_num += codec_info_list[i].amp_num; card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "cfg-spk:%d cfg-amp:%d", - (sof_sdw_quirk & SOF_SDW_FOUR_SPK) - ? 4 : 2, amp_num); + " cfg-amp:%d", amp_num); if (!card->components) return -ENOMEM; - card->long_name = sdw_card_long_name; + if (mach->mach_params.dmic_num) { + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + "%s mic:dmic cfg-mics:%d", + card->components, + mach->mach_params.dmic_num); + if (!card->components) + return -ENOMEM; + } /* Register the card */ - ret = devm_snd_soc_register_card(&pdev->dev, card); + ret = devm_snd_soc_register_card(card->dev, card); if (ret) { - dev_err(card->dev, "snd_soc_register_card failed %d\n", ret); + dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret); + asoc_sdw_mc_dailink_exit_loop(card); return ret; } @@ -1032,12 +1385,27 @@ static int mc_probe(struct platform_device *pdev) return ret; } +static void mc_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + + asoc_sdw_mc_dailink_exit_loop(card); +} + +static const struct platform_device_id mc_id_table[] = { + { "sof_sdw", }, + {} +}; +MODULE_DEVICE_TABLE(platform, mc_id_table); + static struct platform_driver sof_sdw_driver = { .driver = { .name = "sof_sdw", .pm = &snd_soc_pm_ops, }, .probe = mc_probe, + .remove = mc_remove, + .id_table = mc_id_table, }; module_platform_driver(sof_sdw_driver); @@ -1047,4 +1415,5 @@ MODULE_AUTHOR("Bard Liao <yung-chuan.liao@linux.intel.com>"); MODULE_AUTHOR("Rander Wang <rander.wang@linux.intel.com>"); MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:sof_sdw"); +MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON"); +MODULE_IMPORT_NS("SND_SOC_SDW_UTILS"); diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h index 12e32439ba46..3aa1dcec5172 100644 --- a/sound/soc/intel/boards/sof_sdw_common.h +++ b/sound/soc/intel/boards/sof_sdw_common.h @@ -12,22 +12,17 @@ #include <linux/bits.h> #include <linux/types.h> #include <sound/soc.h> +#include <sound/soc_sdw_utils.h> +#include "sof_hdmi_common.h" -#define MAX_NO_PROPS 2 #define MAX_HDMI_NUM 4 -#define SDW_DMIC_DAI_ID 4 -#define SDW_MAX_CPU_DAIS 16 -#define SDW_INTEL_BIDIR_PDI_BASE 2 +#define SOC_SDW_MAX_CPU_DAIS 16 +#define SOC_SDW_INTEL_BIDIR_PDI_BASE 2 /* 8 combinations with 4 links + unused group 0 */ #define SDW_MAX_GROUPS 9 enum { - SOF_RT711_JD_SRC_JD1 = 1, - SOF_RT711_JD_SRC_JD2 = 2, -}; - -enum { SOF_PRE_TGL_HDMI_COUNT = 3, SOF_TGL_HDMI_COUNT = 4, }; @@ -41,91 +36,31 @@ enum { SOF_I2S_SSP5 = BIT(5), }; -#define SOF_RT711_JDSRC(quirk) ((quirk) & GENMASK(1, 0)) -#define SOF_SDW_FOUR_SPK BIT(2) -#define SOF_SDW_TGL_HDMI BIT(3) -#define SOF_SDW_PCH_DMIC BIT(4) -#define SOF_SSP_PORT(x) (((x) & GENMASK(5, 0)) << 5) -#define SOF_SSP_GET_PORT(quirk) (((quirk) >> 5) & GENMASK(5, 0)) -#define SOF_RT715_DAI_ID_FIX BIT(11) -#define SOF_SDW_NO_AGGREGATION BIT(12) - -struct sof_sdw_codec_info { - const int id; - int amp_num; - const u8 acpi_id[ACPI_ID_LEN]; - const bool direction[2]; // playback & capture support - const char *dai_name; - const struct snd_soc_ops *ops; - - int (*init)(const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); - - bool late_probe; - int (*codec_card_late_probe)(struct snd_soc_card *card); -}; - -struct mc_private { - struct list_head hdmi_pcm_list; - bool common_hdmi_codec_drv; - bool idisp_codec; - struct snd_soc_jack sdw_headset; +/* Deprecated and no longer supported by the code */ +#define SOC_SDW_FOUR_SPK BIT(4) +#define SOF_SDW_TGL_HDMI BIT(5) +#define SOC_SDW_PCH_DMIC BIT(6) +#define SOF_SSP_PORT(x) (((x) & GENMASK(5, 0)) << 7) +#define SOF_SSP_GET_PORT(quirk) (((quirk) >> 7) & GENMASK(5, 0)) +/* Deprecated and no longer supported by the code */ +#define SOC_SDW_NO_AGGREGATION BIT(14) + +/* BT audio offload: reserve 3 bits for future */ +#define SOF_BT_OFFLOAD_SSP_SHIFT 15 +#define SOF_BT_OFFLOAD_SSP_MASK (GENMASK(17, 15)) +#define SOF_BT_OFFLOAD_SSP(quirk) \ + (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK) +#define SOF_SSP_BT_OFFLOAD_PRESENT BIT(18) + +struct intel_mc_ctx { + struct sof_hdmi_private hdmi; + /* To store SDW Pin index for each SoundWire link */ + unsigned int sdw_pin_index[SDW_INTEL_MAX_LINKS]; }; -extern unsigned long sof_sdw_quirk; - -int sdw_startup(struct snd_pcm_substream *substream); -void sdw_shutdown(struct snd_pcm_substream *substream); - /* generic HDMI support */ int sof_sdw_hdmi_init(struct snd_soc_pcm_runtime *rtd); int sof_sdw_hdmi_card_late_probe(struct snd_soc_card *card); -/* DMIC support */ -int sof_sdw_dmic_init(struct snd_soc_pcm_runtime *rtd); - -/* RT711 support */ -int sof_sdw_rt711_init(const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); -int sof_sdw_rt711_exit(struct device *dev, struct snd_soc_dai_link *dai_link); - -/* RT700 support */ -int sof_sdw_rt700_init(const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); - -/* RT1308 support */ -extern struct snd_soc_ops sof_sdw_rt1308_i2s_ops; - -int sof_sdw_rt1308_init(const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); - -/* RT715 support */ -int sof_sdw_rt715_init(const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); - -/* MAX98373 support */ -int sof_sdw_mx8373_init(const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); - -int sof_sdw_mx8373_late_probe(struct snd_soc_card *card); - -/* RT5682 support */ -int sof_sdw_rt5682_init(const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); - #endif diff --git a/sound/soc/intel/boards/sof_sdw_dmic.c b/sound/soc/intel/boards/sof_sdw_dmic.c deleted file mode 100644 index 89b0824b2381..000000000000 --- a/sound/soc/intel/boards/sof_sdw_dmic.c +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright (c) 2020 Intel Corporation - -/* - * sof_sdw_dmic - Helpers to handle dmic from generic machine driver - */ - -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include "sof_sdw_common.h" - -static const struct snd_soc_dapm_widget dmic_widgets[] = { - SND_SOC_DAPM_MIC("SoC DMIC", NULL), -}; - -static const struct snd_soc_dapm_route dmic_map[] = { - /* digital mics */ - {"DMic", NULL, "SoC DMIC"}, -}; - -int sof_sdw_dmic_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - int ret; - - ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets, - ARRAY_SIZE(dmic_widgets)); - if (ret) { - dev_err(card->dev, "DMic widget addition failed: %d\n", ret); - /* Don't need to add routes if widget addition failed */ - return ret; - } - - ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map, - ARRAY_SIZE(dmic_map)); - - if (ret) - dev_err(card->dev, "DMic map addition failed: %d\n", ret); - - return ret; -} - diff --git a/sound/soc/intel/boards/sof_sdw_hdmi.c b/sound/soc/intel/boards/sof_sdw_hdmi.c index 99b04bb2f3a0..f92867deb029 100644 --- a/sound/soc/intel/boards/sof_sdw_hdmi.c +++ b/sound/soc/intel/boards/sof_sdw_hdmi.c @@ -5,92 +5,39 @@ * sof_sdw_hdmi - Helpers to handle HDMI from generic machine driver */ +#include <linux/acpi.h> #include <linux/device.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/list.h> +#include <linux/soundwire/sdw_intel.h> #include <sound/soc.h> #include <sound/soc-acpi.h> #include <sound/jack.h> #include "sof_sdw_common.h" -#include "../../codecs/hdac_hdmi.h" #include "hda_dsp_common.h" -static struct snd_soc_jack hdmi[MAX_HDMI_NUM]; - -struct hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - int sof_sdw_hdmi_init(struct snd_soc_pcm_runtime *rtd) { - struct mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); - struct hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - /* dai_link id is 1:1 mapped to the PCM device */ - pcm->device = rtd->dai_link->id; - pcm->codec_dai = dai; + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; + struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + intel_ctx->hdmi.hdmi_comp = dai->component; return 0; } -#define NAME_SIZE 32 int sof_sdw_hdmi_card_late_probe(struct snd_soc_card *card) { - struct mc_private *ctx = snd_soc_card_get_drvdata(card); - struct hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; - if (!ctx->idisp_codec) + if (!intel_ctx->hdmi.idisp_codec) return 0; - if (list_empty(&ctx->hdmi_pcm_list)) - return -EINVAL; - - pcm = list_first_entry(&ctx->hdmi_pcm_list, struct hdmi_pcm, - head); - component = pcm->codec_dai->component; - - if (ctx->common_hdmi_codec_drv) - return hda_dsp_hdmi_build_controls(card, component); - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - 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, &hdmi[i], - NULL, 0); - - if (err) - return err; - - err = snd_jack_add_new_kctl(hdmi[i].jack, - jack_name, SND_JACK_AVOUT); - if (err) - dev_warn(component->dev, "failed creating Jack kctl\n"); - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &hdmi[i]); - if (err < 0) - return err; - - i++; - } - - if (!component) + if (!intel_ctx->hdmi.hdmi_comp) return -EINVAL; - return hdac_hdmi_jack_port_init(component, &card->dapm); + return hda_dsp_hdmi_build_controls(card, intel_ctx->hdmi.hdmi_comp); } diff --git a/sound/soc/intel/boards/sof_sdw_max98373.c b/sound/soc/intel/boards/sof_sdw_max98373.c deleted file mode 100644 index 6437872a9b3d..000000000000 --- a/sound/soc/intel/boards/sof_sdw_max98373.c +++ /dev/null @@ -1,86 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright (c) 2020 Intel Corporation -// -// sof_sdw_max98373 - Helpers to handle 2x MAX98373 -// codec devices from generic machine driver - -#include <linux/device.h> -#include <linux/errno.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include "sof_sdw_common.h" -#include "sof_maxim_common.h" - -static const struct snd_soc_dapm_widget mx8373_widgets[] = { - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), -}; - -static const struct snd_kcontrol_new mx8373_controls[] = { - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), -}; - -static int spk_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - int ret; - - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s spk:mx8373", - card->components); - if (!card->components) - return -ENOMEM; - - ret = snd_soc_add_card_controls(card, mx8373_controls, - ARRAY_SIZE(mx8373_controls)); - if (ret) { - dev_err(card->dev, "mx8373 ctrls addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_new_controls(&card->dapm, mx8373_widgets, - ARRAY_SIZE(mx8373_widgets)); - if (ret) { - dev_err(card->dev, "mx8373 widgets addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_add_routes(&card->dapm, max_98373_dapm_routes, 2); - if (ret) - dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret); - - return ret; -} - -static const struct snd_soc_ops max_98373_sdw_ops = { - .startup = sdw_startup, - .trigger = max98373_trigger, - .shutdown = sdw_shutdown, -}; - -int sof_sdw_mx8373_init(const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) -{ - info->amp_num++; - if (info->amp_num == 2) - dai_links->init = spk_init; - - info->late_probe = true; - - dai_links->ops = &max_98373_sdw_ops; - - return 0; -} - -int sof_sdw_mx8373_late_probe(struct snd_soc_card *card) -{ - struct snd_soc_dapm_context *dapm = &card->dapm; - - /* Disable Left and Right Spk pin after boot */ - snd_soc_dapm_disable_pin(dapm, "Left Spk"); - snd_soc_dapm_disable_pin(dapm, "Right Spk"); - return snd_soc_dapm_sync(dapm); -} diff --git a/sound/soc/intel/boards/sof_sdw_rt1308.c b/sound/soc/intel/boards/sof_sdw_rt1308.c deleted file mode 100644 index 3655e890acec..000000000000 --- a/sound/soc/intel/boards/sof_sdw_rt1308.c +++ /dev/null @@ -1,151 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright (c) 2020 Intel Corporation - -/* - * sof_sdw_rt1308 - Helpers to handle RT1308 from generic machine driver - */ - -#include <linux/device.h> -#include <linux/errno.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include "sof_sdw_common.h" -#include "../../codecs/rt1308.h" - -static const struct snd_soc_dapm_widget rt1308_widgets[] = { - SND_SOC_DAPM_SPK("Speaker", NULL), -}; - -/* - * dapm routes for rt1308 will be registered dynamically according - * to the number of rt1308 used. The first two entries will be registered - * for one codec case, and the last two entries are also registered - * if two 1308s are used. - */ -static const struct snd_soc_dapm_route rt1308_map[] = { - { "Speaker", NULL, "rt1308-1 SPOL" }, - { "Speaker", NULL, "rt1308-1 SPOR" }, - { "Speaker", NULL, "rt1308-2 SPOL" }, - { "Speaker", NULL, "rt1308-2 SPOR" }, -}; - -static const struct snd_kcontrol_new rt1308_controls[] = { - SOC_DAPM_PIN_SWITCH("Speaker"), -}; - -static int first_spk_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - int ret; - - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s spk:rt1308", - card->components); - if (!card->components) - return -ENOMEM; - - ret = snd_soc_add_card_controls(card, rt1308_controls, - ARRAY_SIZE(rt1308_controls)); - if (ret) { - dev_err(card->dev, "rt1308 controls addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_new_controls(&card->dapm, rt1308_widgets, - ARRAY_SIZE(rt1308_widgets)); - if (ret) { - dev_err(card->dev, "rt1308 widgets addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_map, 2); - if (ret) - dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret); - - return ret; -} - -static int second_spk_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - int ret; - - ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_map + 2, 2); - if (ret) - dev_err(rtd->dev, "failed to add second SPK map: %d\n", ret); - - return ret; -} - -static int all_spk_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - - ret = first_spk_init(rtd); - if (ret) - return ret; - - return second_spk_init(rtd); -} - -static int rt1308_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_card *card = rtd->card; - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - int clk_id, clk_freq, pll_out; - int err; - - clk_id = RT1308_PLL_S_MCLK; - clk_freq = 38400000; - - pll_out = params_rate(params) * 512; - - /* Set rt1308 pll */ - err = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out); - if (err < 0) { - dev_err(card->dev, "Failed to set RT1308 PLL: %d\n", err); - return err; - } - - /* Set rt1308 sysclk */ - err = snd_soc_dai_set_sysclk(codec_dai, RT1308_FS_SYS_S_PLL, pll_out, - SND_SOC_CLOCK_IN); - if (err < 0) { - dev_err(card->dev, "Failed to set RT1308 SYSCLK: %d\n", err); - return err; - } - - return 0; -} - -/* machine stream operations */ -struct snd_soc_ops sof_sdw_rt1308_i2s_ops = { - .hw_params = rt1308_i2s_hw_params, -}; - -int sof_sdw_rt1308_init(const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) -{ - info->amp_num++; - if (info->amp_num == 1) - dai_links->init = first_spk_init; - - if (info->amp_num == 2) { - /* - * if two 1308s are in one dai link, the init function - * in this dai link will be first set for the first speaker, - * and it should be reset to initialize all speakers when - * the second speaker is found. - */ - if (dai_links->init) - dai_links->init = all_spk_init; - else - dai_links->init = second_spk_init; - } - - return 0; -} diff --git a/sound/soc/intel/boards/sof_sdw_rt5682.c b/sound/soc/intel/boards/sof_sdw_rt5682.c deleted file mode 100644 index da354ba83939..000000000000 --- a/sound/soc/intel/boards/sof_sdw_rt5682.c +++ /dev/null @@ -1,127 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright (c) 2020 Intel Corporation - -/* - * sof_sdw_rt5682 - Helpers to handle RT5682 from generic machine driver - */ - -#include <linux/device.h> -#include <linux/errno.h> -#include <linux/input.h> -#include <linux/soundwire/sdw.h> -#include <linux/soundwire/sdw_type.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include <sound/jack.h> -#include "sof_sdw_common.h" - -static const struct snd_soc_dapm_widget rt5682_widgets[] = { - SND_SOC_DAPM_HP("Headphone", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), -}; - -static const struct snd_soc_dapm_route rt5682_map[] = { - /*Headphones*/ - { "Headphone", NULL, "rt5682 HPOL" }, - { "Headphone", NULL, "rt5682 HPOR" }, - { "rt5682 IN1P", NULL, "Headset Mic" }, -}; - -static const struct snd_kcontrol_new rt5682_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), -}; - -static struct snd_soc_jack_pin rt5682_jack_pins[] = { - { - .pin = "Headphone", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static int rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - struct snd_soc_component *component = codec_dai->component; - struct snd_soc_jack *jack; - int ret; - - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s hs:rt5682", - card->components); - if (!card->components) - return -ENOMEM; - - ret = snd_soc_add_card_controls(card, rt5682_controls, - ARRAY_SIZE(rt5682_controls)); - if (ret) { - dev_err(card->dev, "rt5682 control addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_new_controls(&card->dapm, rt5682_widgets, - ARRAY_SIZE(rt5682_widgets)); - if (ret) { - dev_err(card->dev, "rt5682 widgets addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_add_routes(&card->dapm, rt5682_map, - ARRAY_SIZE(rt5682_map)); - - if (ret) { - dev_err(card->dev, "rt5682 map addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - &ctx->sdw_headset, - rt5682_jack_pins, - ARRAY_SIZE(rt5682_jack_pins)); - if (ret) { - dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n", - ret); - return ret; - } - - jack = &ctx->sdw_headset; - - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - - ret = snd_soc_component_set_jack(component, jack, NULL); - - if (ret) - dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n", - ret); - - return ret; -} - -int sof_sdw_rt5682_init(const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) -{ - /* - * headset should be initialized once. - * Do it with dai link for playback. - */ - if (!playback) - return 0; - - dai_links->init = rt5682_rtd_init; - - return 0; -} diff --git a/sound/soc/intel/boards/sof_sdw_rt700.c b/sound/soc/intel/boards/sof_sdw_rt700.c deleted file mode 100644 index 5f50491ba5ee..000000000000 --- a/sound/soc/intel/boards/sof_sdw_rt700.c +++ /dev/null @@ -1,126 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright (c) 2020 Intel Corporation - -/* - * sof_sdw_rt700 - Helpers to handle RT700 from generic machine driver - */ - -#include <linux/device.h> -#include <linux/errno.h> -#include <linux/input.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include <sound/jack.h> -#include "sof_sdw_common.h" - -static const struct snd_soc_dapm_widget rt700_widgets[] = { - SND_SOC_DAPM_HP("Headphones", NULL), - SND_SOC_DAPM_MIC("AMIC", NULL), - SND_SOC_DAPM_SPK("Speaker", NULL), -}; - -static const struct snd_soc_dapm_route rt700_map[] = { - /* Headphones */ - { "Headphones", NULL, "HP" }, - { "Speaker", NULL, "SPK" }, - { "MIC2", NULL, "AMIC" }, -}; - -static const struct snd_kcontrol_new rt700_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphones"), - SOC_DAPM_PIN_SWITCH("AMIC"), - SOC_DAPM_PIN_SWITCH("Speaker"), -}; - -static struct snd_soc_jack_pin rt700_jack_pins[] = { - { - .pin = "Headphones", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "AMIC", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static int rt700_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - struct snd_soc_component *component = codec_dai->component; - struct snd_soc_jack *jack; - int ret; - - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s hs:rt700", - card->components); - if (!card->components) - return -ENOMEM; - - ret = snd_soc_add_card_controls(card, rt700_controls, - ARRAY_SIZE(rt700_controls)); - if (ret) { - dev_err(card->dev, "rt700 controls addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_new_controls(&card->dapm, rt700_widgets, - ARRAY_SIZE(rt700_widgets)); - if (ret) { - dev_err(card->dev, "rt700 widgets addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_add_routes(&card->dapm, rt700_map, - ARRAY_SIZE(rt700_map)); - - if (ret) { - dev_err(card->dev, "rt700 map addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - &ctx->sdw_headset, - rt700_jack_pins, - ARRAY_SIZE(rt700_jack_pins)); - if (ret) { - dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n", - ret); - return ret; - } - - jack = &ctx->sdw_headset; - - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - - ret = snd_soc_component_set_jack(component, jack, NULL); - if (ret) - dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n", - ret); - - return ret; -} - -int sof_sdw_rt700_init(const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) -{ - /* - * headset should be initialized once. - * Do it with dai link for playback. - */ - if (!playback) - return 0; - - dai_links->init = rt700_rtd_init; - - return 0; -} diff --git a/sound/soc/intel/boards/sof_sdw_rt711.c b/sound/soc/intel/boards/sof_sdw_rt711.c deleted file mode 100644 index 606009fa3901..000000000000 --- a/sound/soc/intel/boards/sof_sdw_rt711.c +++ /dev/null @@ -1,172 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright (c) 2020 Intel Corporation - -/* - * sof_sdw_rt711 - Helpers to handle RT711 from generic machine driver - */ - -#include <linux/device.h> -#include <linux/errno.h> -#include <linux/input.h> -#include <linux/soundwire/sdw.h> -#include <linux/soundwire/sdw_type.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include <sound/jack.h> -#include "sof_sdw_common.h" - -/* - * Note this MUST be called before snd_soc_register_card(), so that the props - * are in place before the codec component driver's probe function parses them. - */ -static int rt711_add_codec_device_props(const char *sdw_dev_name) -{ - struct property_entry props[MAX_NO_PROPS] = {}; - struct device *sdw_dev; - int ret; - - sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, sdw_dev_name); - if (!sdw_dev) - return -EPROBE_DEFER; - - if (SOF_RT711_JDSRC(sof_sdw_quirk)) { - props[0] = PROPERTY_ENTRY_U32("realtek,jd-src", - SOF_RT711_JDSRC(sof_sdw_quirk)); - } - - ret = device_add_properties(sdw_dev, props); - put_device(sdw_dev); - - return ret; -} - -static const struct snd_soc_dapm_widget rt711_widgets[] = { - SND_SOC_DAPM_HP("Headphone", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), -}; - -static const struct snd_soc_dapm_route rt711_map[] = { - /* Headphones */ - { "Headphone", NULL, "rt711 HP" }, - { "rt711 MIC2", NULL, "Headset Mic" }, -}; - -static const struct snd_kcontrol_new rt711_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), -}; - -static struct snd_soc_jack_pin rt711_jack_pins[] = { - { - .pin = "Headphone", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static int rt711_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - struct snd_soc_component *component = codec_dai->component; - struct snd_soc_jack *jack; - int ret; - - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s hs:rt711", - card->components); - if (!card->components) - return -ENOMEM; - - ret = snd_soc_add_card_controls(card, rt711_controls, - ARRAY_SIZE(rt711_controls)); - if (ret) { - dev_err(card->dev, "rt711 controls addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_new_controls(&card->dapm, rt711_widgets, - ARRAY_SIZE(rt711_widgets)); - if (ret) { - dev_err(card->dev, "rt711 widgets addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_add_routes(&card->dapm, rt711_map, - ARRAY_SIZE(rt711_map)); - - if (ret) { - dev_err(card->dev, "rt711 map addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - &ctx->sdw_headset, - rt711_jack_pins, - ARRAY_SIZE(rt711_jack_pins)); - if (ret) { - dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n", - ret); - return ret; - } - - jack = &ctx->sdw_headset; - - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - - ret = snd_soc_component_set_jack(component, jack, NULL); - - if (ret) - dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n", - ret); - - return ret; -} - -int sof_sdw_rt711_exit(struct device *dev, struct snd_soc_dai_link *dai_link) -{ - struct device *sdw_dev; - - sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, - dai_link->codecs[0].name); - if (!sdw_dev) - return -EINVAL; - - device_remove_properties(sdw_dev); - put_device(sdw_dev); - - return 0; -} - -int sof_sdw_rt711_init(const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) -{ - int ret; - - /* - * headset should be initialized once. - * Do it with dai link for playback. - */ - if (!playback) - return 0; - - ret = rt711_add_codec_device_props(dai_links->codecs[0].name); - if (ret < 0) - return ret; - - dai_links->init = rt711_rtd_init; - - return 0; -} diff --git a/sound/soc/intel/boards/sof_sdw_rt715.c b/sound/soc/intel/boards/sof_sdw_rt715.c deleted file mode 100644 index 9b298f79e784..000000000000 --- a/sound/soc/intel/boards/sof_sdw_rt715.c +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright (c) 2020 Intel Corporation - -/* - * sof_sdw_rt715 - Helpers to handle RT715 from generic machine driver - */ - -#include <linux/device.h> -#include <linux/errno.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include "sof_sdw_common.h" - -static int rt715_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s mic:rt715", - card->components); - if (!card->components) - return -ENOMEM; - - return 0; -} - -int sof_sdw_rt715_init(const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) -{ - /* - * DAI ID is fixed at SDW_DMIC_DAI_ID for 715 to - * keep sdw DMIC and HDMI setting static in UCM - */ - if (sof_sdw_quirk & SOF_RT715_DAI_ID_FIX) - dai_links->id = SDW_DMIC_DAI_ID; - - dai_links->init = rt715_rtd_init; - - return 0; -} diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c new file mode 100644 index 000000000000..48ee5353bdf1 --- /dev/null +++ b/sound/soc/intel/boards/sof_ssp_amp.c @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2022 Intel Corporation + +/* + * sof_ssp_amp.c - ASoc Machine driver for Intel platforms + * with RT1308/CS35L41 codec. + */ + +#include <linux/acpi.h> +#include <linux/delay.h> +#include <linux/dmi.h> +#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/sof.h> +#include "sof_board_helpers.h" +#include "sof_realtek_common.h" +#include "sof_cirrus_common.h" + +/* Driver-specific board quirks: from bit 0 to 7 */ +#define SOF_HDMI_PLAYBACK_PRESENT BIT(0) + +/* Default: SSP2 */ +static unsigned long sof_ssp_amp_quirk = SOF_SSP_PORT_AMP(2); + +static const struct dmi_system_id chromebook_platforms[] = { + { + .ident = "Google Chromebooks", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + } + }, + {}, +}; + +static int sof_card_late_probe(struct snd_soc_card *card) +{ + return sof_intel_board_card_late_probe(card); +} + +static struct snd_soc_card sof_ssp_amp_card = { + .name = "ssp_amp", + .owner = THIS_MODULE, + .fully_routed = true, + .late_probe = sof_card_late_probe, +}; + +/* BE ID defined in sof-tgl-rt1308-hdmi-ssp.m4 */ +#define HDMI_IN_BE_ID 0 +#define SPK_BE_ID 2 +#define DMIC01_BE_ID 3 +#define INTEL_HDMI_BE_ID 5 +/* extra BE links to support no-hdmi-in boards */ +#define DMIC16K_BE_ID 4 +#define BT_OFFLOAD_BE_ID 8 + +#define SSP_AMP_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_HDMI_IN, \ + SOF_LINK_AMP, \ + SOF_LINK_DMIC01, \ + SOF_LINK_DMIC16K, \ + SOF_LINK_IDISP_HDMI, \ + SOF_LINK_BT_OFFLOAD, \ + SOF_LINK_NONE) + +#define SSP_AMP_LINK_IDS SOF_LINK_ORDER(HDMI_IN_BE_ID, \ + SPK_BE_ID, \ + DMIC01_BE_ID, \ + DMIC16K_BE_ID, \ + INTEL_HDMI_BE_ID, \ + BT_OFFLOAD_BE_ID, \ + 0) + +static int +sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card, + struct sof_card_private *ctx) +{ + int ret; + + ret = sof_intel_board_set_dai_link(dev, card, ctx); + if (ret) + return ret; + + if (ctx->amp_type == CODEC_NONE) + return 0; + + if (!ctx->amp_link) { + dev_err(dev, "amp link not available"); + return -EINVAL; + } + + /* codec-specific fields for speaker amplifier */ + switch (ctx->amp_type) { + case CODEC_CS35L41: + cs35l41_set_dai_link(ctx->amp_link); + break; + case CODEC_RT1308: + sof_rt1308_dai_link(ctx->amp_link); + break; + default: + dev_err(dev, "invalid amp type %d\n", ctx->amp_type); + return -EINVAL; + } + + return 0; +} + +static int sof_ssp_amp_probe(struct platform_device *pdev) +{ + struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; + struct sof_card_private *ctx; + int ret; + + if (pdev->id_entry && pdev->id_entry->driver_data) + sof_ssp_amp_quirk = (unsigned long)pdev->id_entry->driver_data; + + dev_dbg(&pdev->dev, "sof_ssp_amp_quirk = %lx\n", sof_ssp_amp_quirk); + + /* initialize ctx with board quirk */ + ctx = sof_intel_board_get_ctx(&pdev->dev, sof_ssp_amp_quirk); + if (!ctx) + return -ENOMEM; + + if (!dmi_check_system(chromebook_platforms) && + (mach->mach_params.dmic_num == 0)) + ctx->dmic_be_num = 0; + + if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) { + if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) + ctx->hdmi.idisp_codec = true; + } else { + ctx->hdmi_num = 0; + } + + ctx->link_order_overwrite = SSP_AMP_LINK_ORDER; + + if (ctx->ssp_mask_hdmi_in) { + /* the topology supports HDMI-IN uses fixed BE ID for DAI links */ + ctx->link_id_overwrite = SSP_AMP_LINK_IDS; + } + + /* update dai_link */ + ret = sof_card_dai_links_create(&pdev->dev, &sof_ssp_amp_card, ctx); + if (ret) + return ret; + + /* update codec_conf */ + switch (ctx->amp_type) { + case CODEC_CS35L41: + cs35l41_set_codec_conf(&sof_ssp_amp_card); + break; + case CODEC_RT1308: + case CODEC_NONE: + /* no codec conf required */ + break; + default: + dev_err(&pdev->dev, "invalid amp type %d\n", ctx->amp_type); + return -EINVAL; + } + + sof_ssp_amp_card.dev = &pdev->dev; + + /* set platform name for each dailink */ + ret = snd_soc_fixup_dai_links_platform_name(&sof_ssp_amp_card, + mach->mach_params.platform); + if (ret) + return ret; + + snd_soc_card_set_drvdata(&sof_ssp_amp_card, ctx); + + return devm_snd_soc_register_card(&pdev->dev, &sof_ssp_amp_card); +} + +static const struct platform_device_id board_ids[] = { + { + .name = "sof_ssp_amp", + }, + { + .name = "tgl_rt1308_hdmi_ssp", + .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_AMP(2) | + SOF_SSP_MASK_HDMI_CAPTURE(0x22)), + /* SSP 1 and SSP 5 are used for HDMI IN */ + }, + { + .name = "adl_cs35l41", + .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_AMP(1) | + SOF_NUM_IDISP_HDMI(4) | + SOF_HDMI_PLAYBACK_PRESENT | + SOF_SSP_PORT_BT_OFFLOAD(2) | + SOF_BT_OFFLOAD_PRESENT), + }, + { + .name = "adl_lt6911_hdmi_ssp", + .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) | + /* SSP 0 and SSP 2 are used for HDMI IN */ + SOF_HDMI_PLAYBACK_PRESENT), + }, + { + .name = "rpl_lt6911_hdmi_ssp", + .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) | + /* SSP 0 and SSP 2 are used for HDMI IN */ + SOF_HDMI_PLAYBACK_PRESENT), + }, + { + .name = "mtl_lt6911_hdmi_ssp", + .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) | + /* SSP 0 and SSP 2 are used for HDMI IN */ + SOF_HDMI_PLAYBACK_PRESENT), + }, + { + .name = "arl_lt6911_hdmi_ssp", + .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) | + /* SSP 0 and SSP 2 are used for HDMI IN */ + SOF_HDMI_PLAYBACK_PRESENT), + }, + { } +}; +MODULE_DEVICE_TABLE(platform, board_ids); + +static struct platform_driver sof_ssp_amp_driver = { + .probe = sof_ssp_amp_probe, + .driver = { + .name = "sof_ssp_amp", + .pm = &snd_soc_pm_ops, + }, + .id_table = board_ids, +}; +module_platform_driver(sof_ssp_amp_driver); + +MODULE_DESCRIPTION("ASoC Intel(R) SOF Amplifier Machine driver"); +MODULE_AUTHOR("Balamurugan C <balamurugan.c@intel.com>"); +MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_REALTEK_COMMON"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_CIRRUS_COMMON"); diff --git a/sound/soc/intel/boards/sof_wm8804.c b/sound/soc/intel/boards/sof_wm8804.c index a46ba13e8eb0..51922347409f 100644 --- a/sound/soc/intel/boards/sof_wm8804.c +++ b/sound/soc/intel/boards/sof_wm8804.c @@ -49,9 +49,9 @@ static const struct dmi_system_id sof_wm8804_quirk_table[] = { static int sof_wm8804_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); struct snd_soc_component *codec = codec_dai->component; const int sysclk = 27000000; /* This is fixed on this board */ int samplerate; @@ -124,7 +124,11 @@ static int sof_wm8804_hw_params(struct snd_pcm_substream *substream, } snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, mclk_div); - snd_soc_dai_set_pll(codec_dai, 0, 0, sysclk, mclk_freq); + ret = snd_soc_dai_set_pll(codec_dai, 0, 0, sysclk, mclk_freq); + if (ret < 0) { + dev_err(rtd->card->dev, "Failed to set WM8804 PLL\n"); + return ret; + } ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL, sysclk, SND_SOC_CLOCK_OUT); @@ -144,7 +148,7 @@ static int sof_wm8804_hw_params(struct snd_pcm_substream *substream, } /* machine stream operations */ -static struct snd_soc_ops sof_wm8804_ops = { +static const struct snd_soc_ops sof_wm8804_ops = { .hw_params = sof_wm8804_hw_params, }; @@ -163,9 +167,6 @@ static struct snd_soc_dai_link dailink[] = { .name = "SSP5-Codec", .id = 0, .no_pcm = 1, - .nonatomic = true, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &sof_wm8804_ops, SND_SOC_DAILINK_REG(ssp5_pin, ssp5_codec, platform), }, @@ -266,20 +267,23 @@ static int sof_wm8804_probe(struct platform_device *pdev) if (adev) { snprintf(codec_name, sizeof(codec_name), "%s%s", "i2c-", acpi_dev_name(adev)); - put_device(&adev->dev); dailink[dai_index].codecs->name = codec_name; + } else { + dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); + return -ENOENT; } + acpi_dev_put(adev); + snd_soc_card_set_drvdata(card, ctx); return devm_snd_soc_register_card(&pdev->dev, card); } -static int sof_wm8804_remove(struct platform_device *pdev) +static void sof_wm8804_remove(struct platform_device *pdev) { if (sof_wm8804_quirk & SOF_WM8804_UP2_QUIRK) gpiod_remove_lookup_table(&up2_gpios_table); - return 0; } static struct platform_driver sof_wm8804_driver = { |