diff options
Diffstat (limited to 'sound/soc/intel')
60 files changed, 1724 insertions, 272 deletions
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 36f547939f0a..82805a8681e5 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -240,6 +240,13 @@ config SND_SOC_ACPI_INTEL_MATCH endif ## SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL +config SND_SOC_INTEL_KEEMBAY + tristate "Keembay Platforms" + depends on ARM64 || COMPILE_TEST + depends on COMMON_CLK + help + If you have a Intel Keembay platform then enable this option + by saying Y or m. # ASoC codec drivers source "sound/soc/intel/boards/Kconfig" diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index e16d6dc4d4e6..04ee48204fc9 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/ obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += baytrail/ obj-$(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM) += atom/ obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += skylake/ +obj-$(CONFIG_SND_SOC_INTEL_KEEMBAY) += keembay/ # Machine support obj-$(CONFIG_SND_SOC) += boards/ diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 69f3af4524ab..ff42f629b035 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -61,8 +61,13 @@ static int sst_fill_and_send_cmd_unlocked(struct sst_data *drv, /** * sst_fill_and_send_cmd - generate the IPC message and send it to the FW - * @ipc_msg: type of IPC (CMD, SET_PARAMS, GET_PARAMS) - * @cmd_data: the IPC payload + * @drv: sst_data + * @ipc_msg: type of IPC (CMD, SET_PARAMS, GET_PARAMS) + * @block: block index + * @task_id: task index + * @pipe_id: pipe index + * @cmd_data: the IPC payload + * @len: length of data to be sent */ static int sst_fill_and_send_cmd(struct sst_data *drv, u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id, @@ -78,7 +83,7 @@ static int sst_fill_and_send_cmd(struct sst_data *drv, return ret; } -/** +/* * tx map value is a bitfield where each bit represents a FW channel * * 3 2 1 0 # 0 = codec0, 1 = codec1 @@ -90,7 +95,7 @@ static u8 sst_ssp_tx_map[SST_MAX_TDM_SLOTS] = { 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, /* default rx map */ }; -/** +/* * rx map value is a bitfield where each bit represents a slot * * 76543210 # 0 = slot 0, 1 = slot 1 @@ -101,7 +106,7 @@ static u8 sst_ssp_rx_map[SST_MAX_TDM_SLOTS] = { 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, /* default tx map */ }; -/** +/* * NOTE: this is invoked with lock held */ static int sst_send_slot_map(struct sst_data *drv) @@ -145,7 +150,8 @@ static int sst_slot_enum_info(struct snd_kcontrol *kcontrol, /** * sst_slot_get - get the status of the interleaver/deinterleaver control - * + * @kcontrol: control pointer + * @ucontrol: User data * Searches the map where the control status is stored, and gets the * channel/slot which is currently set for this enumerated control. Since it is * an enumerated control, there is only one possible value. @@ -197,7 +203,8 @@ static int sst_check_and_send_slot_map(struct sst_data *drv, struct snd_kcontrol /** * sst_slot_put - set the status of interleaver/deinterleaver control - * + * @kcontrol: control pointer + * @ucontrol: User data * (de)interleaver controls are defined in opposite sense to be user-friendly * * Instead of the enum value being the value written to the register, it is the @@ -280,7 +287,9 @@ static int sst_send_algo_cmd(struct sst_data *drv, /** * sst_find_and_send_pipe_algo - send all the algo parameters for a pipe - * + * @drv: sst_data + * @pipe: string identifier + * @ids: list of algorithms * The algos which are in each pipeline are sent to the firmware one by one * * Called with lock held @@ -379,11 +388,15 @@ static int sst_gain_ctl_info(struct snd_kcontrol *kcontrol, /** * sst_send_gain_cmd - send the gain algorithm IPC to the FW - * @gv: the stored value of gain (also contains rampduration) - * @mute: flag that indicates whether this was called from the - * digital_mute callback or directly. If called from the - * digital_mute callback, module will be muted/unmuted based on this - * flag. The flag is always 0 if called directly. + * @drv: sst_data + * @gv:the stored value of gain (also contains rampduration) + * @task_id: task index + * @loc_id: location/position index + * @module_id: module index + * @mute: flag that indicates whether this was called from the + * digital_mute callback or directly. If called from the + * digital_mute callback, module will be muted/unmuted based on this + * flag. The flag is always 0 if called directly. * * Called with sst_data.lock held * @@ -544,9 +557,12 @@ static const uint swm_mixer_input_ids[SST_SWM_INPUT_COUNT] = { /** * fill_swm_input - fill in the SWM input ids given the register + * @cmpnt: ASoC component + * @swm_input: array of swm_input_ids + * @reg: the register value is a bit-field inicated which mixer inputs are ON. * - * The register value is a bit-field inicated which mixer inputs are ON. Use the - * lookup table to get the input-id and fill it in the structure. + * Use the lookup table to get the input-id and fill it in the + * structure. */ static int fill_swm_input(struct snd_soc_component *cmpnt, struct swm_input_ids *swm_input, unsigned int reg) @@ -577,7 +593,7 @@ static int fill_swm_input(struct snd_soc_component *cmpnt, } -/** +/* * called with lock held */ static int sst_set_pipe_gain(struct sst_ids *ids, @@ -707,7 +723,7 @@ SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm2_controls); SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_sprot_l0_controls); SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_media_l1_controls); SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_media_l2_controls); -SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_voip_controls); +SST_SBA_DECLARE_MIX_CONTROLS(__maybe_unused sst_mix_voip_controls); SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec0_controls); SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec1_controls); SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_modem_controls); @@ -881,7 +897,7 @@ int sst_fill_ssp_config(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -/** +/* * sst_ssp_config - contains SSP configuration for media UC * this can be overwritten by set_dai_xxx APIs */ @@ -1300,6 +1316,9 @@ static bool is_sst_dapm_widget(struct snd_soc_dapm_widget *w) /** * sst_send_pipe_gains - send gains for the front-end DAIs + * @dai: front-end dai + * @stream: direction + * @mute: boolean indicating mute status * * The gains in the pipes connected to the front-ends are muted/unmuted * automatically via the digital_mute() DAPM callback. This function sends the @@ -1357,7 +1376,9 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute) /** * sst_fill_module_list - populate the list of modules/gains for a pipe - * + * @kctl: kcontrol pointer + * @w: dapm widget + * @type: widget type * * Fills the widget pointer in the kcontrol private data, and also fills the * kcontrol pointer in the widget private data. @@ -1403,7 +1424,8 @@ static int sst_fill_module_list(struct snd_kcontrol *kctl, /** * sst_fill_widget_module_info - fill list of gains/algos for the pipe - * @widget: pipe modelled as a DAPM widget + * @w: pipe modeled as a DAPM widget + * @component: ASoC component * * Fill the list of gains/algos for the widget by looking at all the card * controls and comparing the name of the widget with the first part of control @@ -1463,6 +1485,8 @@ static int sst_fill_widget_module_info(struct snd_soc_dapm_widget *w, /** * sst_fill_linked_widgets - fill the parent pointer for the linked widget + * @component: ASoC component + * @ids: sst_ids array */ static void sst_fill_linked_widgets(struct snd_soc_component *component, struct sst_ids *ids) @@ -1480,6 +1504,7 @@ static void sst_fill_linked_widgets(struct snd_soc_component *component, /** * sst_map_modules_to_pipe - fill algo/gains list for all pipes + * @component: ASoC component */ static int sst_map_modules_to_pipe(struct snd_soc_component *component) { diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 8817eaae6bb7..49b9f18472bc 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -274,7 +274,7 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream) { struct sst_runtime_stream *stream = substream->runtime->private_data; - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); int ret_val; dev_dbg(rtd->dev, "setting buffer ptr param\n"); @@ -582,7 +582,7 @@ static int sst_soc_trigger(struct snd_soc_component *component, int ret_val = 0, str_id; struct sst_runtime_stream *stream; int status; - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); dev_dbg(rtd->dev, "%s called\n", __func__); if (substream->pcm->internal) @@ -630,7 +630,7 @@ static snd_pcm_uframes_t sst_soc_pointer(struct snd_soc_component *component, struct sst_runtime_stream *stream; int ret_val, status; struct pcm_stream_info *str_info; - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); stream = substream->runtime->private_data; status = sst_get_stream_status(stream); diff --git a/sound/soc/intel/atom/sst/sst_loader.c b/sound/soc/intel/atom/sst/sst_loader.c index 9b0e3739c738..fc91a304256b 100644 --- a/sound/soc/intel/atom/sst/sst_loader.c +++ b/sound/soc/intel/atom/sst/sst_loader.c @@ -49,6 +49,7 @@ void memcpy32_fromio(void *dst, const void __iomem *src, int count) /** * intel_sst_reset_dsp_mrfld - Resetting SST DSP + * @sst_drv_ctx: intel_sst_drv context pointer * * This resets DSP in case of MRFLD platfroms */ @@ -77,6 +78,7 @@ int intel_sst_reset_dsp_mrfld(struct intel_sst_drv *sst_drv_ctx) /** * sst_start_merrifield - Start the SST DSP processor + * @sst_drv_ctx: intel_sst_drv context pointer * * This starts the DSP in MERRIFIELD platfroms */ @@ -274,12 +276,10 @@ void sst_memcpy_free_resources(struct intel_sst_drv *sst_drv_ctx) struct sst_memcpy_list *listnode, *tmplistnode; /* Free the list */ - if (!list_empty(&sst_drv_ctx->memcpy_list)) { - list_for_each_entry_safe(listnode, tmplistnode, - &sst_drv_ctx->memcpy_list, memcpylist) { - list_del(&listnode->memcpylist); - kfree(listnode); - } + list_for_each_entry_safe(listnode, tmplistnode, + &sst_drv_ctx->memcpy_list, memcpylist) { + list_del(&listnode->memcpylist); + kfree(listnode); } } @@ -387,6 +387,8 @@ void sst_post_download_mrfld(struct intel_sst_drv *ctx) /** * sst_load_fw - function to load FW into DSP + * @sst_drv_ctx: intel_sst_drv context pointer + * * Transfers the FW to DSP using dma/memcpy */ int sst_load_fw(struct intel_sst_drv *sst_drv_ctx) diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c index ea09f4170201..c0221e103e79 100644 --- a/sound/soc/intel/atom/sst/sst_stream.c +++ b/sound/soc/intel/atom/sst/sst_stream.c @@ -92,8 +92,8 @@ int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params) /** * sst_realloc_stream - Send msg for (re-)allocating a stream using the - * @sst_drv_ctx intel_sst_drv context pointer - * @str_id: stream ID + * @sst_drv_ctx: intel_sst_drv context pointer + * @str_id: stream ID * * Send a msg for (re-)allocating a stream using the parameters previously * passed to sst_alloc_stream_mrfld() for the same stream ID. @@ -142,12 +142,13 @@ out: } /** -* sst_start_stream - Send msg for a starting stream -* @str_id: stream ID -* -* This function is called by any function which wants to start -* a stream. -*/ + * sst_start_stream - Send msg for a starting stream + * @sst_drv_ctx: intel_sst_drv context pointer + * @str_id: stream ID + * + * This function is called by any function which wants to start + * a stream. + */ int sst_start_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) { int retval = 0; @@ -234,7 +235,8 @@ out: /** * sst_pause_stream - Send msg for a pausing stream - * @str_id: stream ID + * @sst_drv_ctx: intel_sst_drv context pointer + * @str_id: stream ID * * This function is called by any function which wants to pause * an already running stream. @@ -278,7 +280,8 @@ int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) /** * sst_resume_stream - Send msg for resuming stream - * @str_id: stream ID + * @sst_drv_ctx: intel_sst_drv context pointer + * @str_id: stream ID * * This function is called by any function which wants to resume * an already paused stream. @@ -345,7 +348,8 @@ int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) /** * sst_drop_stream - Send msg for stopping stream - * @str_id: stream ID + * @sst_drv_ctx: intel_sst_drv context pointer + * @str_id: stream ID * * This function is called by any function which wants to stop * a stream. @@ -377,12 +381,14 @@ int sst_drop_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) } /** -* sst_drain_stream - Send msg for draining stream -* @str_id: stream ID -* -* This function is called by any function which wants to drain -* a stream. -*/ + * sst_drain_stream - Send msg for draining stream + * @sst_drv_ctx: intel_sst_drv context pointer + * @str_id: stream ID + * @partial_drain: boolean indicating if a gapless transition is taking place + * + * This function is called by any function which wants to drain + * a stream. + */ int sst_drain_stream(struct intel_sst_drv *sst_drv_ctx, int str_id, bool partial_drain) { @@ -415,7 +421,8 @@ int sst_drain_stream(struct intel_sst_drv *sst_drv_ctx, /** * sst_free_stream - Frees a stream - * @str_id: stream ID + * @sst_drv_ctx: intel_sst_drv context pointer + * @str_id: stream ID * * This function is called by any function which wants to free * a stream. diff --git a/sound/soc/intel/baytrail/sst-baytrail-pcm.c b/sound/soc/intel/baytrail/sst-baytrail-pcm.c index 53383055c8dc..54a66cc6db89 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-pcm.c +++ b/sound/soc/intel/baytrail/sst-baytrail-pcm.c @@ -62,7 +62,7 @@ static int sst_byt_pcm_hw_params(struct snd_soc_component *component, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct sst_byt_priv_data *pdata = snd_soc_component_get_drvdata(component); struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream]; struct sst_byt *byt = pdata->byt; @@ -121,7 +121,7 @@ static int sst_byt_pcm_hw_params(struct snd_soc_component *component, static int sst_byt_pcm_restore_stream_context(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct sst_byt_priv_data *pdata = snd_soc_component_get_drvdata(component); struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream]; @@ -155,7 +155,7 @@ static void sst_byt_pcm_work(struct work_struct *work) static int sst_byt_pcm_trigger(struct snd_soc_component *component, struct snd_pcm_substream *substream, int cmd) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct sst_byt_priv_data *pdata = snd_soc_component_get_drvdata(component); struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream]; struct sst_byt *byt = pdata->byt; @@ -197,7 +197,7 @@ static u32 byt_notify_pointer(struct sst_byt_stream *stream, void *data) struct sst_byt_pcm_data *pcm_data = data; struct snd_pcm_substream *substream = pcm_data->substream; struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct sst_byt_priv_data *pdata = snd_soc_component_get_drvdata(component); struct sst_byt *byt = pdata->byt; @@ -219,7 +219,7 @@ static u32 byt_notify_pointer(struct sst_byt_stream *stream, void *data) static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct sst_byt_priv_data *pdata = snd_soc_component_get_drvdata(component); struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream]; @@ -232,7 +232,7 @@ static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_soc_component *component static int sst_byt_pcm_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct sst_byt_priv_data *pdata = snd_soc_component_get_drvdata(component); struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream]; struct sst_byt *byt = pdata->byt; @@ -260,7 +260,7 @@ static int sst_byt_pcm_open(struct snd_soc_component *component, static int sst_byt_pcm_close(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct sst_byt_priv_data *pdata = snd_soc_component_get_drvdata(component); struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream]; struct sst_byt *byt = pdata->byt; @@ -286,7 +286,7 @@ static int sst_byt_pcm_mmap(struct snd_soc_component *component, struct snd_pcm_substream *substream, struct vm_area_struct *vma) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); dev_dbg(rtd->dev, "PCM: mmap\n"); return snd_pcm_lib_default_mmap(substream, vma); diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 5dc489a79454..d96fc1313434 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -288,6 +288,7 @@ 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 @@ -298,14 +299,14 @@ config SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON if SND_SOC_INTEL_APL config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH - tristate "Broxton with DA7219 and MAX98357A in I2S Mode" + 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 I2S audio codec. + 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". @@ -389,7 +390,7 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH depends on MFD_INTEL_LPSS || COMPILE_TEST select SND_SOC_DA7219 select SND_SOC_MAX98927 - select SND_SOC_MAX98373 + select SND_SOC_MAX98373_I2C select SND_SOC_DMIC select SND_SOC_HDAC_HDMI help @@ -466,7 +467,7 @@ config SND_SOC_INTEL_SOF_RT5682_MACH 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_MAX98373 + select SND_SOC_MAX98373_I2C select SND_SOC_RT1015 select SND_SOC_RT5682_I2C select SND_SOC_DMIC @@ -530,7 +531,7 @@ config SND_SOC_INTEL_SOF_DA7219_MAX98373_MACH depends on MFD_INTEL_LPSS || COMPILE_TEST depends on SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC select SND_SOC_DA7219 - select SND_SOC_MAX98373 + select SND_SOC_MAX98373_I2C select SND_SOC_DMIC help This adds support for ASoC machine driver for SOF platforms @@ -564,6 +565,8 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH 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_MAX98373_I2C + select SND_SOC_MAX98373_SDW select SND_SOC_RT700_SDW select SND_SOC_RT711_SDW select SND_SOC_RT1308_SDW @@ -573,7 +576,7 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH select SND_SOC_DMIC help Add support for Intel SoundWire-based platforms connected to - RT700, RT711, RT1308 and RT715 + MAX98373, RT700, RT711, RT1308 and RT715 If unsure select "N". endif diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 15684610f8c6..dc04acb911b6 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -34,9 +34,11 @@ 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 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 diff --git a/sound/soc/intel/boards/bdw-rt5650.c b/sound/soc/intel/boards/bdw-rt5650.c index a97e912adf4b..ce7320916b22 100644 --- a/sound/soc/intel/boards/bdw-rt5650.c +++ b/sound/soc/intel/boards/bdw-rt5650.c @@ -106,7 +106,7 @@ 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 = substream->private_data; + 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; @@ -297,9 +297,19 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = { }, }; +#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 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 = { - .name = "bdw-rt5650", + .name = CARD_NAME, + .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = bdw_rt5650_dais, .num_links = ARRAY_SIZE(bdw_rt5650_dais), diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index bed4d5f73d9c..86e427e3822f 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -156,7 +156,7 @@ 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 = substream->private_data; + 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; @@ -173,7 +173,7 @@ 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 = substream->private_data; + 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; @@ -272,8 +272,8 @@ static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd) RT5677_CLK_SEL_SYS2); /* Request rt5677 GPIO for headphone amp control */ - bdw_rt5677->gpio_hp_en = devm_gpiod_get(component->dev, "headphone-enable", - GPIOD_OUT_LOW); + bdw_rt5677->gpio_hp_en = gpiod_get(component->dev, "headphone-enable", + GPIOD_OUT_LOW); if (IS_ERR(bdw_rt5677->gpio_hp_en)) { dev_err(component->dev, "Can't find HP_AMP_SHDN_L gpio\n"); return PTR_ERR(bdw_rt5677->gpio_hp_en); @@ -307,6 +307,19 @@ static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd) return 0; } +static void bdw_rt5677_exit(struct snd_soc_pcm_runtime *rtd) +{ + struct bdw_rt5677_priv *bdw_rt5677 = + 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(bdw_rt5677->gpio_hp_en)) + gpiod_put(bdw_rt5677->gpio_hp_en); +} + /* broadwell digital audio interface glue - connects codec <--> CPU */ SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY())); @@ -373,6 +386,7 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = { .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 @@ -405,9 +419,19 @@ 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 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 = { - .name = "bdw-rt5677", + .name = CARD_NAME, + .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = bdw_rt5677_dais, .num_links = ARRAY_SIZE(bdw_rt5677_dais), diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 42f8723beef2..f6399077d291 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -103,7 +103,7 @@ static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, static int broadwell_rt286_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + 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; @@ -291,9 +291,19 @@ static int broadwell_resume(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 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 = "broadwell-rt286", + .name = CARD_NAME, + .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = broadwell_rt286_dais, .num_links = ARRAY_SIZE(broadwell_rt286_dais), diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 44016c16f25e..0c0a717823c4 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -25,9 +25,14 @@ #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]; @@ -40,6 +45,7 @@ struct bxt_hdmi_pcm { struct bxt_card_private { struct list_head hdmi_pcm_list; bool common_hdmi_codec_drv; + int spkamp; }; enum { @@ -85,13 +91,20 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, 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_SPK("Spk", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), SND_SOC_DAPM_SPK("HDMI1", NULL), SND_SOC_DAPM_SPK("HDMI2", NULL), @@ -100,14 +113,20 @@ static const struct snd_soc_dapm_widget broxton_widgets[] = { 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"}, - /* speaker */ - {"Spk", NULL, "Speaker"}, - /* other jacks */ {"MIC", NULL, "Headset Mic"}, @@ -134,6 +153,17 @@ static const struct snd_soc_dapm_route audio_map[] = { { "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"}, @@ -404,6 +434,10 @@ SND_SOC_DAILINK_DEF(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"))); @@ -601,15 +635,69 @@ static struct snd_soc_dai_link broxton_dais[] = { }, }; +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; - int err, i = 0; + 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)); @@ -678,6 +766,11 @@ static int broxton_audio_probe(struct platform_device *pdev) 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()) { @@ -702,7 +795,13 @@ static int broxton_audio_probe(struct platform_device *pdev) } else if (soc_intel_is_cml()) { unsigned int i; - broxton_audio_card.name = "cmlda7219max"; + 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. */ @@ -710,6 +809,11 @@ static int broxton_audio_probe(struct platform_device *pdev) 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, @@ -759,6 +863,7 @@ 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"); diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index 7a4decf34191..0f3157dfa838 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -224,7 +224,7 @@ static int broxton_ssp5_fixup(struct snd_soc_pcm_runtime *rtd, static int broxton_rt298_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + 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; @@ -565,6 +565,7 @@ static int bxt_card_late_probe(struct snd_soc_card *card) /* 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, @@ -580,6 +581,7 @@ static struct snd_soc_card broxton_rt298 = { 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, diff --git a/sound/soc/intel/boards/byt-rt5640.c b/sound/soc/intel/boards/byt-rt5640.c index ace232f8aed6..8851949f38e2 100644 --- a/sound/soc/intel/boards/byt-rt5640.c +++ b/sound/soc/intel/boards/byt-rt5640.c @@ -72,7 +72,7 @@ static const struct snd_kcontrol_new byt_rt5640_controls[] = { static int byt_rt5640_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + 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; diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c index fad937610494..9cb42ba40c07 100644 --- a/sound/soc/intel/boards/bytcht_cx2072x.c +++ b/sound/soc/intel/boards/bytcht_cx2072x.c @@ -205,9 +205,19 @@ static struct snd_soc_dai_link byt_cht_cx2072x_dais[] = { }, }; +#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 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 = { - .name = "bytcht-cx2072x", + .name = CARD_NAME, + .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = byt_cht_cx2072x_dais, .num_links = ARRAY_SIZE(byt_cht_cx2072x_dais), diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c index f3791ff2bad1..e1e46b4bbac5 100644 --- a/sound/soc/intel/boards/bytcht_da7213.c +++ b/sound/soc/intel/boards/bytcht_da7213.c @@ -105,7 +105,7 @@ 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 = substream->private_data; + 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; @@ -126,7 +126,7 @@ 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 = substream->private_data; + 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; @@ -205,9 +205,19 @@ static struct snd_soc_dai_link dailink[] = { }, }; +#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 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 = { - .name = "bytcht-da7213", + .name = CARD_NAME, + .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = dailink, .num_links = ARRAY_SIZE(dailink), diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index ecbc58e8a37f..414ae4bb5224 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -407,8 +407,18 @@ 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 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 = "bytcht-es8316", + .name = CARD_NAME, + .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = byt_cht_es8316_dais, .num_links = ARRAY_SIZE(byt_cht_es8316_dais), @@ -515,9 +525,8 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) BYT_CHT_ES8316_MONO_SPEAKER; } if (quirk_override != -1) { - dev_info(dev, "Overriding quirk 0x%x => 0x%x\n", - (unsigned int)quirk, - quirk_override); + dev_info(dev, "Overriding quirk 0x%lx => 0x%x\n", + quirk, quirk_override); quirk = quirk_override; } log_quirks(dev); diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 1fdb70b9e478..479992f4e97a 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -380,7 +380,7 @@ static struct snd_soc_jack_pin rt5640_pins[] = { static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); return byt_rt5640_prepare_and_enable_pll1(dai, params_rate(params)); @@ -1127,8 +1127,18 @@ 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 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 = "bytcr-rt5640", + .name = CARD_NAME, + .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = byt_rt5640_dais, .num_links = ARRAY_SIZE(byt_rt5640_dais), @@ -1255,8 +1265,8 @@ 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%x => 0x%x\n", - (unsigned int)byt_rt5640_quirk, quirk_override); + dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n", + byt_rt5640_quirk, quirk_override); byt_rt5640_quirk = quirk_override; } diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 520e916e329c..4e2897596cea 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -347,7 +347,7 @@ 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 = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); snd_pcm_format_t format = params_format(params); int rate = params_rate(params); @@ -827,8 +827,18 @@ 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 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 = "bytcr-rt5651", + .name = CARD_NAME, + .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = byt_rt5651_dais, .num_links = ARRAY_SIZE(byt_rt5651_dais), @@ -967,8 +977,8 @@ 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%x => 0x%x\n", - (unsigned int)byt_rt5651_quirk, quirk_override); + dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n", + byt_rt5651_quirk, quirk_override); byt_rt5651_quirk = quirk_override; } diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index 767ac2ae03e2..835e9bd6b52d 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -112,7 +112,7 @@ 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 = substream->private_data; + 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; @@ -382,9 +382,19 @@ static struct snd_soc_dai_link cht_dailink[] = { }, }; +#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 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 = "chtmax98090", + .name = CARD_NAME, + .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = cht_dailink, .num_links = ARRAY_SIZE(cht_dailink), diff --git a/sound/soc/intel/boards/cht_bsw_nau8824.c b/sound/soc/intel/boards/cht_bsw_nau8824.c index 2f7c94d335c1..3e12bff15fed 100644 --- a/sound/soc/intel/boards/cht_bsw_nau8824.c +++ b/sound/soc/intel/boards/cht_bsw_nau8824.c @@ -72,7 +72,7 @@ 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 = substream->private_data; + 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; @@ -231,9 +231,19 @@ static struct snd_soc_dai_link cht_dailink[] = { }, }; +#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 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 = "chtnau8824", + .name = CARD_NAME, + .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = cht_dailink, .num_links = ARRAY_SIZE(cht_dailink), diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 22de138ffa33..b53c02481749 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -207,7 +207,7 @@ 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 = substream->private_data; + 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; @@ -479,9 +479,21 @@ static struct snd_soc_dai_link cht_dailink[] = { }, }; +#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 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 = "chtrt5645", + .name = CARD_RT5645_NAME, + .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = cht_dailink, .num_links = ARRAY_SIZE(cht_dailink), @@ -494,7 +506,8 @@ static struct snd_soc_card snd_soc_card_chtrt5645 = { }; static struct snd_soc_card snd_soc_card_chtrt5650 = { - .name = "chtrt5650", + .name = CARD_RT5650_NAME, + .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = cht_dailink, .num_links = ARRAY_SIZE(cht_dailink), diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 22e432768edb..8442be93eb1c 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -143,7 +143,7 @@ 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 = substream->private_data; + 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; @@ -253,13 +253,17 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); /* - * Default mode for SSP configuration is TDM 4 slot. One board/design, - * the Lenovo Miix 2 10 uses not 1 but 2 codecs connected to SSP2. The - * second piggy-backed, output-only codec is inside the keyboard-dock - * (which has extra speakers). Unlike the main rt5672 codec, we cannot - * configure this codec, it is hard coded to use 2 channel 24 bit I2S. - * Since we only support 2 channels anyways, there is no need for TDM - * on any cht-bsw-rt5672 designs. So we simply use I2S 2ch everywhere. + * The default mode for the cpu-dai is TDM 4 slot. The default mode + * for the codec-dai is I2S. So we need to either set the cpu-dai to + * I2S mode to match the codec-dai, or set the codec-dai to TDM 4 slot + * (or program both to yet another mode). + * One board, the Lenovo Miix 2 10, uses not 1 but 2 codecs connected + * to SSP2. The second piggy-backed, output-only codec is inside the + * keyboard-dock (which has extra speakers). Unlike the main rt5672 + * codec, we cannot configure this codec, it is hard coded to use + * 2 channel 24 bit I2S. For this to work we must use I2S mode on this + * 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), SND_SOC_DAIFMT_I2S | @@ -378,9 +382,19 @@ 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 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 = "cht-bsw-rt5672", + .name = CARD_NAME, + .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = cht_dailink, .num_links = ARRAY_SIZE(cht_dailink), diff --git a/sound/soc/intel/boards/cml_rt1011_rt5682.c b/sound/soc/intel/boards/cml_rt1011_rt5682.c index 68eff29daf8f..14813beb33d1 100644 --- a/sound/soc/intel/boards/cml_rt1011_rt5682.c +++ b/sound/soc/intel/boards/cml_rt1011_rt5682.c @@ -34,7 +34,6 @@ #define SOF_RT1011_SPEAKER_WR BIT(1) #define SOF_RT1011_SPEAKER_TL BIT(2) #define SOF_RT1011_SPEAKER_TR BIT(3) -#define SPK_CH 4 /* Default: Woofer speakers */ static unsigned long sof_rt1011_quirk = SOF_RT1011_SPEAKER_WL | @@ -161,6 +160,13 @@ static int cml_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) 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; @@ -193,7 +199,7 @@ static int cml_rt1011_spk_init(struct snd_soc_pcm_runtime *rtd) static int cml_rt5682_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + 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; @@ -226,7 +232,7 @@ static int cml_rt5682_hw_params(struct snd_pcm_substream *substream, static int cml_rt1011_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + 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; @@ -376,10 +382,17 @@ SND_SOC_DAILINK_DEF(ssp0_codec, SND_SOC_DAILINK_DEF(ssp1_pin, DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); -SND_SOC_DAILINK_DEF(ssp1_codec, +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"))); @@ -415,6 +428,7 @@ static struct snd_soc_dai_link cml_rt1011_rt5682_dailink[] = { .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, @@ -475,7 +489,7 @@ static struct snd_soc_dai_link cml_rt1011_rt5682_dailink[] = { .no_pcm = 1, .init = cml_rt1011_spk_init, .ops = &cml_rt1011_ops, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), + SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec_2spk, platform), }, }; @@ -488,11 +502,21 @@ static struct snd_soc_codec_conf rt1011_conf[] = { .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, @@ -509,8 +533,7 @@ static struct snd_soc_card snd_soc_card_cml = { static int snd_cml_rt1011_probe(struct platform_device *pdev) { - struct snd_soc_dai_link_component *rt1011_dais_components; - struct snd_soc_codec_conf *rt1011_dais_confs; + struct snd_soc_dai_link *dai_link; struct card_private *ctx; struct snd_soc_acpi_mach *mach; const char *platform_name; @@ -527,67 +550,16 @@ static int snd_cml_rt1011_probe(struct platform_device *pdev) dmi_check_system(sof_rt1011_quirk_table); - dev_info(&pdev->dev, "sof_rt1011_quirk = %lx\n", sof_rt1011_quirk); + 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)) { - rt1011_dais_confs = devm_kzalloc(&pdev->dev, - sizeof(struct snd_soc_codec_conf) * - SPK_CH, GFP_KERNEL); - - if (!rt1011_dais_confs) - return -ENOMEM; - - rt1011_dais_components = devm_kzalloc(&pdev->dev, - sizeof(struct snd_soc_dai_link_component) * - SPK_CH, GFP_KERNEL); - - if (!rt1011_dais_components) - return -ENOMEM; - - for (i = 0; i < SPK_CH; i++) { - rt1011_dais_confs[i].dlc.name = devm_kasprintf(&pdev->dev, - GFP_KERNEL, - "i2c-10EC1011:0%d", - i); - - if (!rt1011_dais_confs[i].dlc.name) - return -ENOMEM; - - switch (i) { - case 0: - rt1011_dais_confs[i].name_prefix = "WL"; - break; - case 1: - rt1011_dais_confs[i].name_prefix = "WR"; - break; - case 2: - rt1011_dais_confs[i].name_prefix = "TL"; - break; - case 3: - rt1011_dais_confs[i].name_prefix = "TR"; - break; - default: - return -EINVAL; - } - rt1011_dais_components[i].name = devm_kasprintf(&pdev->dev, - GFP_KERNEL, - "i2c-10EC1011:0%d", - i); - if (!rt1011_dais_components[i].name) - return -ENOMEM; - - rt1011_dais_components[i].dai_name = CML_RT1011_CODEC_DAI; - } - - snd_soc_card_cml.codec_conf = rt1011_dais_confs; - snd_soc_card_cml.num_configs = SPK_CH; - - for (i = 0; i < ARRAY_SIZE(cml_rt1011_rt5682_dailink); i++) { - if (!strcmp(cml_rt1011_rt5682_dailink[i].codecs->dai_name, - CML_RT1011_CODEC_DAI)) { - cml_rt1011_rt5682_dailink[i].codecs = rt1011_dais_components; - cml_rt1011_rt5682_dailink[i].num_codecs = SPK_CH; + 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); } } } diff --git a/sound/soc/intel/boards/ehl_rt5660.c b/sound/soc/intel/boards/ehl_rt5660.c index 78160e3b1615..7c0d4e915406 100644 --- a/sound/soc/intel/boards/ehl_rt5660.c +++ b/sound/soc/intel/boards/ehl_rt5660.c @@ -109,7 +109,7 @@ 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 = substream->private_data; + 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; diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c index 954ab01f695b..62cca511522e 100644 --- a/sound/soc/intel/boards/glk_rt5682_max98357a.c +++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c @@ -187,7 +187,7 @@ static int geminilake_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) static int geminilake_rt5682_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + 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; diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c index 74af090f2657..744b7b5b8106 100644 --- a/sound/soc/intel/boards/haswell.c +++ b/sound/soc/intel/boards/haswell.c @@ -55,7 +55,7 @@ static int haswell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, static int haswell_rt5640_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + 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; diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index e29c31ffd241..cc9a2509ace2 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -175,7 +175,7 @@ static const struct snd_soc_dapm_route kabylake_ssp1_map[] = { static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *runtime = substream->private_data; + struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai; int ret, j; @@ -220,7 +220,7 @@ static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, static int kabylake_ssp0_trigger(struct snd_pcm_substream *substream, int cmd) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai; int j, ret; @@ -455,7 +455,7 @@ static struct snd_pcm_hw_constraint_list constraints_channels_quad = { static int kbl_fe_startup(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *soc_rt = substream->private_data; + struct snd_soc_pcm_runtime *soc_rt = asoc_substream_to_rtd(substream); /* * On this platform for PCM device we support, @@ -512,7 +512,7 @@ static int kabylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, static int kabylake_dmic_startup(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *soc_rt = substream->private_data; + 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, diff --git a/sound/soc/intel/boards/kbl_rt5660.c b/sound/soc/intel/boards/kbl_rt5660.c index d2a078454784..3a9f91b58e11 100644 --- a/sound/soc/intel/boards/kbl_rt5660.c +++ b/sound/soc/intel/boards/kbl_rt5660.c @@ -165,8 +165,8 @@ static int kabylake_rt5660_codec_init(struct snd_soc_pcm_runtime *rtd) dev_warn(component->dev, "Failed to add driver gpios\n"); /* Request rt5660 GPIO for lineout mute control, return if fails */ - ctx->gpio_lo_mute = devm_gpiod_get(component->dev, "lineout-mute", - GPIOD_OUT_HIGH); + 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); @@ -207,6 +207,18 @@ static int kabylake_rt5660_codec_init(struct snd_soc_pcm_runtime *rtd) 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); @@ -243,7 +255,7 @@ static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) static int kabylake_rt5660_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + 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; @@ -421,6 +433,7 @@ static struct snd_soc_dai_link kabylake_rt5660_dais[] = { .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, diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c index 09ba55fc36d5..3ea4602dfb3e 100644 --- a/sound/soc/intel/boards/kbl_rt5663_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c @@ -430,7 +430,7 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + 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; @@ -468,7 +468,7 @@ static int kabylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai; int ret = 0, j; diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index b34cf6cf1139..922cd0176e1f 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -336,22 +336,45 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, 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; + 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(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")) { + 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(fe_dai_link->name, "Kbl Audio DMIC cap")) { + } 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; @@ -362,7 +385,7 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, * 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")) + if (!strcmp(rtd_dpcm->be->dai_link->name, "SSP0-Codec")) snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); return 0; @@ -371,7 +394,7 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + 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; @@ -395,7 +418,7 @@ static struct snd_soc_ops kabylake_rt5663_ops = { static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai; int ret = 0, j; diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.h b/sound/soc/intel/boards/skl_hda_dsp_common.h index 507750ef67f3..4b0b3959182e 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_common.h +++ b/sound/soc/intel/boards/skl_hda_dsp_common.h @@ -33,6 +33,7 @@ struct skl_hda_private { 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]; diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index 79c8947f840b..ca4900036ead 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -79,6 +79,9 @@ skl_hda_add_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link) 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); @@ -118,19 +121,20 @@ static char hda_soc_components[30]; 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, idisp_mask; + u32 codec_count, codec_mask; int i, num_links, num_route; codec_mask = mach_params->codec_mask; codec_count = hweight_long(codec_mask); - idisp_mask = codec_mask & IDISP_CODEC_MASK; + ctx->idisp_codec = !!(codec_mask & IDISP_CODEC_MASK); if (!codec_count || codec_count > 2 || - (codec_count == 2 && !idisp_mask)) + (codec_count == 2 && !ctx->idisp_codec)) return -EINVAL; - if (codec_mask == idisp_mask) { + 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; @@ -152,7 +156,7 @@ static int skl_hda_fill_card_info(struct snd_soc_acpi_mach_params *mach_params) num_route = ARRAY_SIZE(skl_hda_map); card->dapm_widgets = skl_hda_widgets; card->num_dapm_widgets = ARRAY_SIZE(skl_hda_widgets); - if (!idisp_mask) { + 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 = @@ -211,6 +215,8 @@ static int skl_hda_audio_probe(struct platform_device *pdev) if (!mach) return -EINVAL; + snd_soc_card_set_drvdata(&hda_soc_card, ctx); + ret = skl_hda_fill_card_info(&mach->mach_params); if (ret < 0) { dev_err(&pdev->dev, "Unsupported HDAudio/iDisp configuration found\n"); @@ -223,7 +229,6 @@ static int skl_hda_audio_probe(struct platform_device *pdev) ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; hda_soc_card.dev = &pdev->dev; - snd_soc_card_set_drvdata(&hda_soc_card, ctx); if (mach->mach_params.dmic_num > 0) { snprintf(hda_soc_components, sizeof(hda_soc_components), diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index d7b8154c43a4..55802900069a 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -295,7 +295,7 @@ static const struct snd_soc_ops skylake_nau8825_fe_ops = { static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + 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; diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 4b317bcf6ea0..0c734f3a9364 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -347,7 +347,7 @@ static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + 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; diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index 903ae1b28ec9..5a0c64a83146 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -228,7 +228,7 @@ static int skylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, static int skylake_rt286_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + 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; diff --git a/sound/soc/intel/boards/sof_da7219_max98373.c b/sound/soc/intel/boards/sof_da7219_max98373.c index 703703858595..f3cb0773e70e 100644 --- a/sound/soc/intel/boards/sof_da7219_max98373.c +++ b/sound/soc/intel/boards/sof_da7219_max98373.c @@ -179,7 +179,7 @@ static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd) static int ssp1_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *runtime = substream->private_data; + struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream); int ret, j; for (j = 0; j < runtime->num_codecs; j++) { diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c index 1a549b32d1c9..1a6961592029 100644 --- a/sound/soc/intel/boards/sof_maxim_common.c +++ b/sound/soc/intel/boards/sof_maxim_common.c @@ -9,7 +9,9 @@ #include <uapi/sound/asound.h> #include "sof_maxim_common.h" -static const struct snd_soc_dapm_route max_98373_dapm_routes[] = { +#define MAX_98373_PIN_NAME 16 + +const struct snd_soc_dapm_route max_98373_dapm_routes[] = { /* speaker */ { "Left Spk", NULL, "Left BE_OUT" }, { "Right Spk", NULL, "Right BE_OUT" }, @@ -27,11 +29,11 @@ static struct snd_soc_codec_conf max_98373_codec_conf[] = { }; struct snd_soc_dai_link_component max_98373_components[] = { - { /* For Left */ + { /* For Right */ .name = MAX_98373_DEV0_NAME, .dai_name = MAX_98373_CODEC_DAI, }, - { /* For Right */ + { /* For Left */ .name = MAX_98373_DEV1_NAME, .dai_name = MAX_98373_CODEC_DAI, }, @@ -40,25 +42,68 @@ 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) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai; int j; 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, 0x30, 3, 8, 16); + snd_soc_dai_set_tdm_slot(codec_dai, 0x03, 3, 8, 24); } if (!strcmp(codec_dai->component->name, MAX_98373_DEV1_NAME)) { /* DEV1 tdm slot configuration */ - snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16); + snd_soc_dai_set_tdm_slot(codec_dai, 0x0C, 3, 8, 24); } } return 0; } +int max98373_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; + int ret = 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); + char pin_name[MAX_98373_PIN_NAME]; + + 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) + snd_soc_dapm_sync(dapm); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + /* Make sure no streams are active before disable pin */ + if (snd_soc_dai_active(codec_dai) != 1) + break; + ret = snd_soc_dapm_disable_pin(dapm, pin_name); + if (!ret) + snd_soc_dapm_sync(dapm); + break; + default: + break; + } + } + + return ret; +} + struct snd_soc_ops max_98373_ops = { .hw_params = max98373_hw_params, + .trigger = max98373_trigger, }; int max98373_spk_codec_init(struct snd_soc_pcm_runtime *rtd) diff --git a/sound/soc/intel/boards/sof_maxim_common.h b/sound/soc/intel/boards/sof_maxim_common.h index 785b34335368..5240b1c9d379 100644 --- a/sound/soc/intel/boards/sof_maxim_common.h +++ b/sound/soc/intel/boards/sof_maxim_common.h @@ -18,7 +18,10 @@ 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[]; 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); + #endif /* __SOF_MAXIM_COMMON_H */ diff --git a/sound/soc/intel/boards/sof_pcm512x.c b/sound/soc/intel/boards/sof_pcm512x.c index 9fa8a4911276..d2b0456236c7 100644 --- a/sound/soc/intel/boards/sof_pcm512x.c +++ b/sound/soc/intel/boards/sof_pcm512x.c @@ -96,7 +96,7 @@ 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 = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_component *codec = asoc_rtd_to_codec(rtd, 0)->component; snd_soc_component_update_bits(codec, PCM512x_GPIO_CONTROL_1, @@ -107,7 +107,7 @@ static int aif1_startup(struct snd_pcm_substream *substream) static void aif1_shutdown(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_component *codec = asoc_rtd_to_codec(rtd, 0)->component; snd_soc_component_update_bits(codec, PCM512x_GPIO_CONTROL_1, diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 13a48b0c35ae..0129d23694ed 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -43,6 +43,7 @@ ((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) /* Default: MCLK on, MCLK 19.2M, SSP0 */ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | @@ -206,10 +207,17 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) return ret; }; +static void sof_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 sof_rt5682_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_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; @@ -267,7 +275,7 @@ static struct snd_soc_ops sof_rt5682_ops = { static int sof_rt1015_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + 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; @@ -276,8 +284,15 @@ static int sof_rt1015_hw_params(struct snd_pcm_substream *substream, 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) * 50, + params_rate(params) * 64, params_rate(params) * 256); if (ret < 0) { dev_err(card->dev, "failed to set pll\n"); @@ -311,6 +326,7 @@ 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; @@ -349,6 +365,14 @@ static int sof_card_late_probe(struct snd_soc_card *card) i++; } + if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) { + /* 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 hdac_hdmi_jack_port_init(component, &card->dapm); } @@ -484,6 +508,13 @@ static struct snd_soc_dai_link_component max98357a_component[] = { } }; +static struct snd_soc_dai_link_component max98360a_component[] = { + { + .name = "MX98360A:00", + .dai_name = "HiFi", + } +}; + static struct snd_soc_dai_link_component rt1015_components[] = { { .name = "i2c-10EC1015:00", @@ -525,6 +556,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_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; @@ -645,6 +677,11 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, 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); @@ -786,21 +823,6 @@ static int sof_audio_probe(struct platform_device *pdev) &sof_audio_card_rt5682); } -static int sof_rt5682_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - struct snd_soc_component *component = NULL; - - for_each_card_components(card, component) { - if (!strcmp(component->name, rt5682_component[0].name)) { - snd_soc_component_set_jack(component, NULL, NULL); - break; - } - } - - return 0; -} - static const struct platform_device_id board_ids[] = { { .name = "sof_rt5682", @@ -831,12 +853,20 @@ static const struct platform_device_id board_ids[] = { SOF_RT5682_SSP_AMP(1) | SOF_RT5682_NUM_HDMIDEV(4)), }, + { + .name = "jsl_rt5682_max98360a", + .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)), + }, { } }; static struct platform_driver sof_audio = { .probe = sof_audio_probe, - .remove = sof_rt5682_remove, .driver = { .name = "sof_rt5682", .pm = &snd_soc_pm_ops, @@ -854,3 +884,4 @@ 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"); diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index e1c1a8ba78e6..2463d432bf4d 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -15,9 +15,32 @@ #include "sof_sdw_common.h" unsigned long sof_sdw_quirk = SOF_RT711_JD_SRC_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) +static void log_quirks(struct device *dev) +{ + if (SOF_RT711_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"); + 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_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"); +} + static int sof_sdw_quirk_cb(const struct dmi_system_id *id) { sof_sdw_quirk = (unsigned long)id->driver_data; @@ -97,7 +120,8 @@ 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), + .driver_data = (void *)(SOF_SDW_TGL_HDMI | SOF_SDW_PCH_DMIC | + SOF_SDW_FOUR_SPK), }, {} @@ -136,6 +160,15 @@ static struct snd_soc_codec_conf codec_conf[] = { .dlc = COMP_CODEC_CONF("sdw:3:25d:715:0"), .name_prefix = "rt715", }, + /* two MAX98373s on link1 with different unique id */ + { + .dlc = COMP_CODEC_CONF("sdw:1:19f:8373:0:3"), + .name_prefix = "Right", + }, + { + .dlc = COMP_CODEC_CONF("sdw:1:19f:8373:0:7"), + .name_prefix = "Left", + }, { .dlc = COMP_CODEC_CONF("sdw:0:25d:5682:0"), .name_prefix = "rt5682", @@ -157,12 +190,12 @@ static struct snd_soc_dai_link_component platform_component[] = { }; /* these wrappers are only needed to avoid typecast compilation errors */ -static int sdw_startup(struct snd_pcm_substream *substream) +int sdw_startup(struct snd_pcm_substream *substream) { return sdw_startup_stream(substream); } -static void sdw_shutdown(struct snd_pcm_substream *substream) +void sdw_shutdown(struct snd_pcm_substream *substream) { sdw_shutdown_stream(substream); } @@ -184,6 +217,7 @@ static struct sof_sdw_codec_info codec_info_list[] = { .direction = {true, true}, .dai_name = "rt711-aif1", .init = sof_sdw_rt711_init, + .exit = sof_sdw_rt711_exit, }, { .id = 0x1308, @@ -200,6 +234,13 @@ static struct sof_sdw_codec_info codec_info_list[] = { .init = sof_sdw_rt715_init, }, { + .id = 0x8373, + .direction = {true, true}, + .dai_name = "max98373-aif1", + .init = sof_sdw_mx8373_init, + .codec_card_late_probe = sof_sdw_mx8373_late_probe, + }, + { .id = 0x5682, .direction = {true, true}, .dai_name = "rt5682-sdw", @@ -658,11 +699,14 @@ static inline int get_next_be_id(struct snd_soc_dai_link *links, return links[be_id - 1].id + 1; } +#define IDISP_CODEC_MASK 0x4 + 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; @@ -706,12 +750,15 @@ static int sof_card_dai_links_create(struct device *dev, 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, hdmi_num); + dmic_num, ctx->idisp_codec ? hdmi_num : 0); /* allocate BE dailinks */ num_links = comp_num + sdw_be_num; @@ -860,13 +907,18 @@ DMIC: if (!name) return -ENOMEM; - 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; + 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); @@ -888,12 +940,29 @@ DMIC: return 0; } +static int sof_sdw_card_late_probe(struct snd_soc_card *card) +{ + int i, ret; + + for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { + if (!codec_info_list[i].late_probe) + continue; + + ret = codec_info_list[i].codec_card_late_probe(card); + if (ret < 0) + return ret; + } + + return sof_sdw_hdmi_card_late_probe(card); +} + /* SoC card */ static const char sdw_card_long_name[] = "Intel Soundwire SOF"; static struct snd_soc_card card_sof_sdw = { .name = "soundwire", - .late_probe = sof_sdw_hdmi_card_late_probe, + .owner = THIS_MODULE, + .late_probe = sof_sdw_card_late_probe, .codec_conf = codec_conf, .num_configs = ARRAY_SIZE(codec_conf), }; @@ -914,9 +983,17 @@ static int mc_probe(struct platform_device *pdev) dmi_check_system(sof_sdw_quirk_table); + if (quirk_override != -1) { + dev_info(&pdev->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); card->dev = &pdev->dev; + snd_soc_card_set_drvdata(card, ctx); mach = pdev->dev.platform_data; ret = sof_card_dai_links_create(&pdev->dev, mach, @@ -926,8 +1003,6 @@ static int mc_probe(struct platform_device *pdev) ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; - snd_soc_card_set_drvdata(card, ctx); - /* * the default amp_num is zero for each codec and * amp_num will only be increased for active amp diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h index 69b363b8a686..12e32439ba46 100644 --- a/sound/soc/intel/boards/sof_sdw_common.h +++ b/sound/soc/intel/boards/sof_sdw_common.h @@ -11,6 +11,7 @@ #include <linux/bits.h> #include <linux/types.h> +#include <sound/soc.h> #define MAX_NO_PROPS 2 #define MAX_HDMI_NUM 4 @@ -61,16 +62,23 @@ struct sof_sdw_codec_info { 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; }; 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); @@ -84,6 +92,7 @@ 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, @@ -105,6 +114,14 @@ int sof_sdw_rt715_init(const struct snd_soc_acpi_link_adr *link, 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, diff --git a/sound/soc/intel/boards/sof_sdw_hdmi.c b/sound/soc/intel/boards/sof_sdw_hdmi.c index 0654b38a7e0d..99b04bb2f3a0 100644 --- a/sound/soc/intel/boards/sof_sdw_hdmi.c +++ b/sound/soc/intel/boards/sof_sdw_hdmi.c @@ -52,6 +52,12 @@ int sof_sdw_hdmi_card_late_probe(struct snd_soc_card *card) int err, i = 0; char jack_name[NAME_SIZE]; + if (!ctx->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; diff --git a/sound/soc/intel/boards/sof_sdw_max98373.c b/sound/soc/intel/boards/sof_sdw_max98373.c new file mode 100644 index 000000000000..6437872a9b3d --- /dev/null +++ b/sound/soc/intel/boards/sof_sdw_max98373.c @@ -0,0 +1,86 @@ +// 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 index 177cc781ada6..3655e890acec 100644 --- a/sound/soc/intel/boards/sof_sdw_rt1308.c +++ b/sound/soc/intel/boards/sof_sdw_rt1308.c @@ -91,7 +91,7 @@ static int all_spk_init(struct snd_soc_pcm_runtime *rtd) static int rt1308_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + 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; diff --git a/sound/soc/intel/boards/sof_sdw_rt711.c b/sound/soc/intel/boards/sof_sdw_rt711.c index d4d75c8dc6b7..606009fa3901 100644 --- a/sound/soc/intel/boards/sof_sdw_rt711.c +++ b/sound/soc/intel/boards/sof_sdw_rt711.c @@ -133,6 +133,21 @@ static int rt711_rtd_init(struct snd_soc_pcm_runtime *rtd) 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, @@ -147,7 +162,7 @@ int sof_sdw_rt711_init(const struct snd_soc_acpi_link_adr *link, if (!playback) return 0; - ret = rt711_add_codec_device_props("sdw:0:25d:711:0"); + ret = rt711_add_codec_device_props(dai_links->codecs[0].name); if (ret < 0) return ret; diff --git a/sound/soc/intel/boards/sof_wm8804.c b/sound/soc/intel/boards/sof_wm8804.c index c13fd20da559..a46ba13e8eb0 100644 --- a/sound/soc/intel/boards/sof_wm8804.c +++ b/sound/soc/intel/boards/sof_wm8804.c @@ -49,7 +49,7 @@ 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 = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_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_component *codec = codec_dai->component; diff --git a/sound/soc/intel/common/soc-acpi-intel-cml-match.c b/sound/soc/intel/common/soc-acpi-intel-cml-match.c index cdea0c09fe0a..dee1f0fa998b 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cml-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cml-match.c @@ -19,6 +19,11 @@ static struct snd_soc_acpi_codecs max98357a_spk_codecs = { .codecs = {"MX98357A"} }; +static struct snd_soc_acpi_codecs max98390_spk_codecs = { + .num_codecs = 1, + .codecs = {"MX98390"} +}; + /* * The order of the three entries with .id = "10EC5682" matters * here, because DSDT tables expose an ACPI HID for the MAX98357A @@ -55,6 +60,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_machines[] = { .sof_fw_filename = "sof-cml.ri", .sof_tplg_filename = "sof-cml-da7219-max98357a.tplg", }, + { + .id = "DLGS7219", + .drv_name = "cml_da7219_max98357a", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &max98390_spk_codecs, + .sof_fw_filename = "sof-cml.ri", + .sof_tplg_filename = "sof-cml-da7219-max98357a.tplg", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cml_machines); diff --git a/sound/soc/intel/common/soc-acpi-intel-ehl-match.c b/sound/soc/intel/common/soc-acpi-intel-ehl-match.c index 45e07d886013..badafc1d54d2 100644 --- a/sound/soc/intel/common/soc-acpi-intel-ehl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-ehl-match.c @@ -12,7 +12,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[] = { { - .id = "INTC1027", + .id = "10EC5660", .drv_name = "ehl_rt5660", .sof_fw_filename = "sof-ehl.ri", .sof_tplg_filename = "sof-ehl-rt5660.tplg", diff --git a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c index 859f8a1bd914..34f5fcad5701 100644 --- a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c @@ -19,6 +19,11 @@ static struct snd_soc_acpi_codecs rt1015_spk = { .codecs = {"10EC1015"} }; +static struct snd_soc_acpi_codecs mx98360a_spk = { + .num_codecs = 1, + .codecs = {"MX98360A"} +}; + /* * When adding new entry to the snd_soc_acpi_intel_jsl_machines array, * use .quirk_data member to distinguish different machine driver, @@ -47,6 +52,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = { .quirk_data = &rt1015_spk, .sof_tplg_filename = "sof-jsl-rt5682-rt1015.tplg", }, + { + .id = "10EC5682", + .drv_name = "jsl_rt5682_max98360a", + .sof_fw_filename = "sof-jsl.ri", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &mx98360a_spk, + .sof_tplg_filename = "sof-jsl-rt5682-mx98360a.tplg", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_jsl_machines); diff --git a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c index 5a56f4359479..2ffa608d987d 100644 --- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c @@ -56,6 +56,19 @@ static const struct snd_soc_acpi_adr_device rt1308_1_adr[] = { } }; +static const struct snd_soc_acpi_adr_device mx8373_1_adr[] = { + { + .adr = 0x000123019F837300, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + }, + { + .adr = 0x000127019F837300, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + } +}; + static const struct snd_soc_acpi_adr_device rt5682_0_adr[] = { { .adr = 0x000021025D568200, @@ -93,6 +106,11 @@ static const struct snd_soc_acpi_link_adr tgl_chromebook_base[] = { .num_adr = ARRAY_SIZE(rt5682_0_adr), .adr_d = rt5682_0_adr, }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(mx8373_1_adr), + .adr_d = mx8373_1_adr, + }, {} }; @@ -140,6 +158,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[] = { .sof_tplg_filename = "sof-tgl-rt711-rt1308.tplg", }, { + .link_mask = 0x3, /* rt5682 on link0 & 2xmax98373 on link 1 */ + .links = tgl_chromebook_base, + .drv_name = "sof_sdw", + .sof_fw_filename = "sof-tgl.ri", + .sof_tplg_filename = "sof-tgl-sdw-max98373-rt5682.tplg", + }, + { .link_mask = 0x1, /* this will only enable rt5682 for now */ .links = tgl_chromebook_base, .drv_name = "sof_sdw", diff --git a/sound/soc/intel/haswell/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c index 16ac16f5a641..b8d86c74c53d 100644 --- a/sound/soc/intel/haswell/sst-haswell-pcm.c +++ b/sound/soc/intel/haswell/sst-haswell-pcm.c @@ -462,7 +462,7 @@ static int hsw_pcm_hw_params(struct snd_soc_component *component, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component); struct hsw_pcm_data *pcm_data; @@ -652,7 +652,7 @@ static int hsw_pcm_hw_params(struct snd_soc_component *component, static int hsw_pcm_trigger(struct snd_soc_component *component, struct snd_pcm_substream *substream, int cmd) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component); struct hsw_pcm_data *pcm_data; struct sst_hsw_stream *sst_stream; @@ -695,7 +695,7 @@ static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data) struct hsw_pcm_data *pcm_data = data; struct snd_pcm_substream *substream = pcm_data->substream; struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component); struct sst_hsw *hsw = pdata->hsw; @@ -760,7 +760,7 @@ static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data) static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component); struct hsw_pcm_data *pcm_data; @@ -785,7 +785,7 @@ static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_soc_component *component, static int hsw_pcm_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component); struct hsw_pcm_data *pcm_data; struct sst_hsw *hsw = pdata->hsw; @@ -818,7 +818,7 @@ static int hsw_pcm_open(struct snd_soc_component *component, static int hsw_pcm_close(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component); struct hsw_pcm_data *pcm_data; struct sst_hsw *hsw = pdata->hsw; diff --git a/sound/soc/intel/keembay/Makefile b/sound/soc/intel/keembay/Makefile new file mode 100644 index 000000000000..9084e8c63854 --- /dev/null +++ b/sound/soc/intel/keembay/Makefile @@ -0,0 +1,4 @@ +snd-soc-kmb_platform-objs := \ + kmb_platform.o + +obj-$(CONFIG_SND_SOC_INTEL_KEEMBAY) += snd-soc-kmb_platform.o diff --git a/sound/soc/intel/keembay/kmb_platform.c b/sound/soc/intel/keembay/kmb_platform.c new file mode 100644 index 000000000000..16f9fc4c663d --- /dev/null +++ b/sound/soc/intel/keembay/kmb_platform.c @@ -0,0 +1,668 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright (C) 2020 Intel Corporation. +// +// Intel KeemBay Platform driver. +// + +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/module.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include "kmb_platform.h" + +#define PERIODS_MIN 2 +#define PERIODS_MAX 48 +#define PERIOD_BYTES_MIN 4096 +#define BUFFER_BYTES_MAX (PERIODS_MAX * PERIOD_BYTES_MIN) +#define TDM_OPERATION 1 +#define I2S_OPERATION 0 +#define DATA_WIDTH_CONFIG_BIT 6 +#define TDM_CHANNEL_CONFIG_BIT 3 + +static const struct snd_pcm_hardware kmb_pcm_hardware = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_BLOCK_TRANSFER, + .rates = SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000, + .rate_min = 8000, + .rate_max = 48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = BUFFER_BYTES_MAX, + .period_bytes_min = PERIOD_BYTES_MIN, + .period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN, + .periods_min = PERIODS_MIN, + .periods_max = PERIODS_MAX, + .fifo_size = 16, +}; + +static unsigned int kmb_pcm_tx_fn(struct kmb_i2s_info *kmb_i2s, + struct snd_pcm_runtime *runtime, + unsigned int tx_ptr, bool *period_elapsed) +{ + unsigned int period_pos = tx_ptr % runtime->period_size; + void __iomem *i2s_base = kmb_i2s->i2s_base; + void *buf = runtime->dma_area; + int i; + + /* KMB i2s uses two separate L/R FIFO */ + for (i = 0; i < kmb_i2s->fifo_th; i++) { + if (kmb_i2s->config.data_width == 16) { + writel(((u16(*)[2])buf)[tx_ptr][0], i2s_base + LRBR_LTHR(0)); + writel(((u16(*)[2])buf)[tx_ptr][1], i2s_base + RRBR_RTHR(0)); + } else { + writel(((u32(*)[2])buf)[tx_ptr][0], i2s_base + LRBR_LTHR(0)); + writel(((u32(*)[2])buf)[tx_ptr][1], i2s_base + RRBR_RTHR(0)); + } + + period_pos++; + + if (++tx_ptr >= runtime->buffer_size) + tx_ptr = 0; + } + + *period_elapsed = period_pos >= runtime->period_size; + + return tx_ptr; +} + +static unsigned int kmb_pcm_rx_fn(struct kmb_i2s_info *kmb_i2s, + struct snd_pcm_runtime *runtime, + unsigned int rx_ptr, bool *period_elapsed) +{ + unsigned int period_pos = rx_ptr % runtime->period_size; + void __iomem *i2s_base = kmb_i2s->i2s_base; + void *buf = runtime->dma_area; + int i; + + /* KMB i2s uses two separate L/R FIFO */ + for (i = 0; i < kmb_i2s->fifo_th; i++) { + if (kmb_i2s->config.data_width == 16) { + ((u16(*)[2])buf)[rx_ptr][0] = readl(i2s_base + LRBR_LTHR(0)); + ((u16(*)[2])buf)[rx_ptr][1] = readl(i2s_base + RRBR_RTHR(0)); + } else { + ((u32(*)[2])buf)[rx_ptr][0] = readl(i2s_base + LRBR_LTHR(0)); + ((u32(*)[2])buf)[rx_ptr][1] = readl(i2s_base + RRBR_RTHR(0)); + } + + period_pos++; + + if (++rx_ptr >= runtime->buffer_size) + rx_ptr = 0; + } + + *period_elapsed = period_pos >= runtime->period_size; + + return rx_ptr; +} + +static inline void kmb_i2s_disable_channels(struct kmb_i2s_info *kmb_i2s, + u32 stream) +{ + u32 i; + + /* Disable all channels regardless of configuration*/ + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + for (i = 0; i < MAX_ISR; i++) + writel(0, kmb_i2s->i2s_base + TER(i)); + } else { + for (i = 0; i < MAX_ISR; i++) + writel(0, kmb_i2s->i2s_base + RER(i)); + } +} + +static inline void kmb_i2s_clear_irqs(struct kmb_i2s_info *kmb_i2s, u32 stream) +{ + struct i2s_clk_config_data *config = &kmb_i2s->config; + u32 i; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + for (i = 0; i < config->chan_nr / 2; i++) + readl(kmb_i2s->i2s_base + TOR(i)); + } else { + for (i = 0; i < config->chan_nr / 2; i++) + readl(kmb_i2s->i2s_base + ROR(i)); + } +} + +static inline void kmb_i2s_irq_trigger(struct kmb_i2s_info *kmb_i2s, + u32 stream, int chan_nr, bool trigger) +{ + u32 i, irq; + u32 flag; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + flag = TX_INT_FLAG; + else + flag = RX_INT_FLAG; + + for (i = 0; i < chan_nr / 2; i++) { + irq = readl(kmb_i2s->i2s_base + IMR(i)); + + if (trigger) + irq = irq & ~flag; + else + irq = irq | flag; + + writel(irq, kmb_i2s->i2s_base + IMR(i)); + } +} + +static void kmb_pcm_operation(struct kmb_i2s_info *kmb_i2s, bool playback) +{ + struct snd_pcm_substream *substream; + bool period_elapsed; + unsigned int new_ptr; + unsigned int ptr; + + if (playback) + substream = kmb_i2s->tx_substream; + else + substream = kmb_i2s->rx_substream; + + if (!substream || !snd_pcm_running(substream)) + return; + + if (playback) { + ptr = kmb_i2s->tx_ptr; + new_ptr = kmb_pcm_tx_fn(kmb_i2s, substream->runtime, + ptr, &period_elapsed); + cmpxchg(&kmb_i2s->tx_ptr, ptr, new_ptr); + } else { + ptr = kmb_i2s->rx_ptr; + new_ptr = kmb_pcm_rx_fn(kmb_i2s, substream->runtime, + ptr, &period_elapsed); + cmpxchg(&kmb_i2s->rx_ptr, ptr, new_ptr); + } + + if (period_elapsed) + snd_pcm_period_elapsed(substream); +} + +static int kmb_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct kmb_i2s_info *kmb_i2s; + + kmb_i2s = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); + snd_soc_set_runtime_hwparams(substream, &kmb_pcm_hardware); + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + runtime->private_data = kmb_i2s; + + return 0; +} + +static int kmb_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct kmb_i2s_info *kmb_i2s = runtime->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + kmb_i2s->tx_ptr = 0; + kmb_i2s->tx_substream = substream; + } else { + kmb_i2s->rx_ptr = 0; + kmb_i2s->rx_substream = substream; + } + break; + case SNDRV_PCM_TRIGGER_STOP: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + kmb_i2s->tx_substream = NULL; + else + kmb_i2s->rx_substream = NULL; + break; + default: + return -EINVAL; + } + + return 0; +} + +static irqreturn_t kmb_i2s_irq_handler(int irq, void *dev_id) +{ + struct kmb_i2s_info *kmb_i2s = dev_id; + struct i2s_clk_config_data *config = &kmb_i2s->config; + irqreturn_t ret = IRQ_NONE; + u32 isr[4]; + int i; + + for (i = 0; i < config->chan_nr / 2; i++) + isr[i] = readl(kmb_i2s->i2s_base + ISR(i)); + + kmb_i2s_clear_irqs(kmb_i2s, SNDRV_PCM_STREAM_PLAYBACK); + kmb_i2s_clear_irqs(kmb_i2s, SNDRV_PCM_STREAM_CAPTURE); + + for (i = 0; i < config->chan_nr / 2; i++) { + /* + * Check if TX fifo is empty. If empty fill FIFO with samples + */ + if ((isr[i] & ISR_TXFE)) { + kmb_pcm_operation(kmb_i2s, true); + ret = IRQ_HANDLED; + } + /* + * Data available. Retrieve samples from FIFO + */ + if ((isr[i] & ISR_RXDA)) { + kmb_pcm_operation(kmb_i2s, false); + ret = IRQ_HANDLED; + } + /* Error Handling: TX */ + if (isr[i] & ISR_TXFO) { + dev_dbg(kmb_i2s->dev, "TX overrun (ch_id=%d)\n", i); + ret = IRQ_HANDLED; + } + /* Error Handling: RX */ + if (isr[i] & ISR_RXFO) { + dev_dbg(kmb_i2s->dev, "RX overrun (ch_id=%d)\n", i); + ret = IRQ_HANDLED; + } + } + + return ret; +} + +static int kmb_platform_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *soc_runtime) +{ + size_t size = kmb_pcm_hardware.buffer_bytes_max; + /* Use SNDRV_DMA_TYPE_CONTINUOUS as KMB doesn't use PCI sg buffer */ + snd_pcm_set_managed_buffer_all(soc_runtime->pcm, + SNDRV_DMA_TYPE_CONTINUOUS, + NULL, size, size); + return 0; +} + +static snd_pcm_uframes_t kmb_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct kmb_i2s_info *kmb_i2s = runtime->private_data; + snd_pcm_uframes_t pos; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + pos = kmb_i2s->tx_ptr; + else + pos = kmb_i2s->rx_ptr; + + return pos < runtime->buffer_size ? pos : 0; +} + +static const struct snd_soc_component_driver kmb_component = { + .name = "kmb", + .pcm_construct = kmb_platform_pcm_new, + .open = kmb_pcm_open, + .trigger = kmb_pcm_trigger, + .pointer = kmb_pcm_pointer, +}; + +static void kmb_i2s_start(struct kmb_i2s_info *kmb_i2s, + struct snd_pcm_substream *substream) +{ + struct i2s_clk_config_data *config = &kmb_i2s->config; + + /* I2S Programming sequence in Keem_Bay_VPU_DB_v1.1 */ + writel(1, kmb_i2s->i2s_base + IER); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + writel(1, kmb_i2s->i2s_base + ITER); + else + writel(1, kmb_i2s->i2s_base + IRER); + + kmb_i2s_irq_trigger(kmb_i2s, substream->stream, config->chan_nr, true); + + if (kmb_i2s->master) + writel(1, kmb_i2s->i2s_base + CER); + else + writel(0, kmb_i2s->i2s_base + CER); +} + +static void kmb_i2s_stop(struct kmb_i2s_info *kmb_i2s, + struct snd_pcm_substream *substream) +{ + /* I2S Programming sequence in Keem_Bay_VPU_DB_v1.1 */ + kmb_i2s_clear_irqs(kmb_i2s, substream->stream); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + writel(0, kmb_i2s->i2s_base + ITER); + else + writel(0, kmb_i2s->i2s_base + IRER); + + kmb_i2s_irq_trigger(kmb_i2s, substream->stream, 8, false); + + if (!kmb_i2s->active) { + writel(0, kmb_i2s->i2s_base + CER); + writel(0, kmb_i2s->i2s_base + IER); + } +} + +static void kmb_disable_clk(void *clk) +{ + clk_disable_unprepare(clk); +} + +static int kmb_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) +{ + struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai); + int ret; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + kmb_i2s->master = false; + ret = 0; + break; + case SND_SOC_DAIFMT_CBS_CFS: + writel(MASTER_MODE, kmb_i2s->pss_base + I2S_GEN_CFG_0); + + ret = clk_prepare_enable(kmb_i2s->clk_i2s); + if (ret < 0) + return ret; + + ret = devm_add_action_or_reset(kmb_i2s->dev, kmb_disable_clk, + kmb_i2s->clk_i2s); + if (ret) + return ret; + + kmb_i2s->master = true; + break; + default: + return -EINVAL; + } + + return ret; +} + +static int kmb_dai_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *cpu_dai) +{ + struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + /* Keep track of i2s activity before turn off + * the i2s interface + */ + kmb_i2s->active++; + kmb_i2s_start(kmb_i2s, substream); + break; + case SNDRV_PCM_TRIGGER_STOP: + kmb_i2s->active--; + kmb_i2s_stop(kmb_i2s, substream); + break; + default: + return -EINVAL; + } + + return 0; +} + +static void kmb_i2s_config(struct kmb_i2s_info *kmb_i2s, int stream) +{ + struct i2s_clk_config_data *config = &kmb_i2s->config; + u32 ch_reg; + + kmb_i2s_disable_channels(kmb_i2s, stream); + + for (ch_reg = 0; ch_reg < config->chan_nr / 2; ch_reg++) { + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + writel(kmb_i2s->xfer_resolution, + kmb_i2s->i2s_base + TCR(ch_reg)); + + writel(kmb_i2s->fifo_th - 1, + kmb_i2s->i2s_base + TFCR(ch_reg)); + + writel(1, kmb_i2s->i2s_base + TER(ch_reg)); + } else { + writel(kmb_i2s->xfer_resolution, + kmb_i2s->i2s_base + RCR(ch_reg)); + + writel(kmb_i2s->fifo_th - 1, + kmb_i2s->i2s_base + RFCR(ch_reg)); + + writel(1, kmb_i2s->i2s_base + RER(ch_reg)); + } + } +} + +static int kmb_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params, + struct snd_soc_dai *cpu_dai) +{ + struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai); + struct i2s_clk_config_data *config = &kmb_i2s->config; + u32 register_val, write_val; + int ret; + + switch (params_format(hw_params)) { + case SNDRV_PCM_FORMAT_S16_LE: + config->data_width = 16; + kmb_i2s->ccr = 0x00; + kmb_i2s->xfer_resolution = 0x02; + break; + case SNDRV_PCM_FORMAT_S24_LE: + config->data_width = 24; + kmb_i2s->ccr = 0x08; + kmb_i2s->xfer_resolution = 0x04; + break; + case SNDRV_PCM_FORMAT_S32_LE: + config->data_width = 32; + kmb_i2s->ccr = 0x10; + kmb_i2s->xfer_resolution = 0x05; + break; + default: + dev_err(kmb_i2s->dev, "kmb: unsupported PCM fmt"); + return -EINVAL; + } + + config->chan_nr = params_channels(hw_params); + + switch (config->chan_nr) { + /* TODO: This switch case will handle up to TDM8 in the near future */ + case TWO_CHANNEL_SUPPORT: + write_val = ((config->chan_nr / 2) << TDM_CHANNEL_CONFIG_BIT) | + (config->data_width << DATA_WIDTH_CONFIG_BIT) | + MASTER_MODE | I2S_OPERATION; + + writel(write_val, kmb_i2s->pss_base + I2S_GEN_CFG_0); + + register_val = readl(kmb_i2s->pss_base + I2S_GEN_CFG_0); + dev_dbg(kmb_i2s->dev, "pss register = 0x%X", register_val); + break; + default: + dev_dbg(kmb_i2s->dev, "channel not supported\n"); + return -EINVAL; + } + + kmb_i2s_config(kmb_i2s, substream->stream); + + writel(kmb_i2s->ccr, kmb_i2s->i2s_base + CCR); + + config->sample_rate = params_rate(hw_params); + + if (kmb_i2s->master) { + /* Only 2 ch supported in Master mode */ + u32 bitclk = config->sample_rate * config->data_width * 2; + + ret = clk_set_rate(kmb_i2s->clk_i2s, bitclk); + if (ret) { + dev_err(kmb_i2s->dev, + "Can't set I2S clock rate: %d\n", ret); + return ret; + } + } + + return 0; +} + +static int kmb_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + writel(1, kmb_i2s->i2s_base + TXFFR); + else + writel(1, kmb_i2s->i2s_base + RXFFR); + + return 0; +} + +static struct snd_soc_dai_ops kmb_dai_ops = { + .trigger = kmb_dai_trigger, + .hw_params = kmb_dai_hw_params, + .prepare = kmb_dai_prepare, + .set_fmt = kmb_set_dai_fmt, +}; + +static struct snd_soc_dai_driver intel_kmb_platform_dai[] = { + { + .name = "kmb-plat-dai", + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000, + .rate_min = 8000, + .rate_max = 48000, + .formats = (SNDRV_PCM_FMTBIT_S32_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S16_LE), + }, + .capture = { + .channels_min = 2, + .channels_max = 2, + /* + * .channels_max will be overwritten + * if provided by Device Tree + */ + .rates = SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000, + .rate_min = 8000, + .rate_max = 48000, + .formats = (SNDRV_PCM_FMTBIT_S32_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S16_LE), + }, + .ops = &kmb_dai_ops, + }, +}; + +static int kmb_plat_dai_probe(struct platform_device *pdev) +{ + struct snd_soc_dai_driver *kmb_i2s_dai; + struct device *dev = &pdev->dev; + struct kmb_i2s_info *kmb_i2s; + int ret, irq; + u32 comp1_reg; + + kmb_i2s = devm_kzalloc(dev, sizeof(*kmb_i2s), GFP_KERNEL); + if (!kmb_i2s) + return -ENOMEM; + + kmb_i2s_dai = devm_kzalloc(dev, sizeof(*kmb_i2s_dai), GFP_KERNEL); + if (!kmb_i2s_dai) + return -ENOMEM; + + kmb_i2s_dai->ops = &kmb_dai_ops; + + /* Prepare the related clocks */ + kmb_i2s->clk_apb = devm_clk_get(dev, "apb_clk"); + if (IS_ERR(kmb_i2s->clk_apb)) { + dev_err(dev, "Failed to get apb clock\n"); + return PTR_ERR(kmb_i2s->clk_apb); + } + + ret = clk_prepare_enable(kmb_i2s->clk_apb); + if (ret < 0) + return ret; + + ret = devm_add_action_or_reset(dev, kmb_disable_clk, kmb_i2s->clk_apb); + if (ret) { + dev_err(dev, "Failed to add clk_apb reset action\n"); + return ret; + } + + kmb_i2s->clk_i2s = devm_clk_get(dev, "osc"); + if (IS_ERR(kmb_i2s->clk_i2s)) { + dev_err(dev, "Failed to get osc clock\n"); + return PTR_ERR(kmb_i2s->clk_i2s); + } + + kmb_i2s->i2s_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(kmb_i2s->i2s_base)) + return PTR_ERR(kmb_i2s->i2s_base); + + kmb_i2s->pss_base = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(kmb_i2s->pss_base)) + return PTR_ERR(kmb_i2s->pss_base); + + kmb_i2s->dev = &pdev->dev; + + irq = platform_get_irq_optional(pdev, 0); + if (irq > 0) { + ret = devm_request_irq(dev, irq, kmb_i2s_irq_handler, 0, + pdev->name, kmb_i2s); + if (ret < 0) { + dev_err(dev, "failed to request irq\n"); + return ret; + } + } + + comp1_reg = readl(kmb_i2s->i2s_base + I2S_COMP_PARAM_1); + + kmb_i2s->fifo_th = (1 << COMP1_FIFO_DEPTH(comp1_reg)) / 2; + + ret = devm_snd_soc_register_component(dev, &kmb_component, + intel_kmb_platform_dai, + ARRAY_SIZE(intel_kmb_platform_dai)); + if (ret) { + dev_err(dev, "not able to register dai\n"); + return ret; + } + + /* To ensure none of the channels are enabled at boot up */ + kmb_i2s_disable_channels(kmb_i2s, SNDRV_PCM_STREAM_PLAYBACK); + kmb_i2s_disable_channels(kmb_i2s, SNDRV_PCM_STREAM_CAPTURE); + + dev_set_drvdata(dev, kmb_i2s); + + return ret; +} + +static const struct of_device_id kmb_plat_of_match[] = { + { .compatible = "intel,keembay-i2s", }, + {} +}; + +static struct platform_driver kmb_plat_dai_driver = { + .driver = { + .name = "kmb-plat-dai", + .of_match_table = kmb_plat_of_match, + }, + .probe = kmb_plat_dai_probe, +}; + +module_platform_driver(kmb_plat_dai_driver); + +MODULE_DESCRIPTION("ASoC Intel KeemBay Platform driver"); +MODULE_AUTHOR("Sia Jee Heng <jee.heng.sia@intel.com>"); +MODULE_AUTHOR("Sit, Michael Wei Hong <michael.wei.hong.sit@intel.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:kmb_platform"); diff --git a/sound/soc/intel/keembay/kmb_platform.h b/sound/soc/intel/keembay/kmb_platform.h new file mode 100644 index 000000000000..9756b132c12f --- /dev/null +++ b/sound/soc/intel/keembay/kmb_platform.h @@ -0,0 +1,146 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Intel KeemBay Platform driver + * + * Copyright (C) 2020 Intel Corporation. + * + */ + +#ifndef KMB_PLATFORM_H_ +#define KMB_PLATFORM_H_ + +#include <linux/bits.h> +#include <linux/bitfield.h> +#include <linux/types.h> + +/* Register values with reference to KMB databook v1.1 */ +/* common register for all channel */ +#define IER 0x000 +#define IRER 0x004 +#define ITER 0x008 +#define CER 0x00C +#define CCR 0x010 +#define RXFFR 0x014 +#define TXFFR 0x018 + +/* Interrupt status register fields */ +#define ISR_TXFO BIT(5) +#define ISR_TXFE BIT(4) +#define ISR_RXFO BIT(1) +#define ISR_RXDA BIT(0) + +/* I2S Tx Rx Registers for all channels */ +#define LRBR_LTHR(x) (0x40 * (x) + 0x020) +#define RRBR_RTHR(x) (0x40 * (x) + 0x024) +#define RER(x) (0x40 * (x) + 0x028) +#define TER(x) (0x40 * (x) + 0x02C) +#define RCR(x) (0x40 * (x) + 0x030) +#define TCR(x) (0x40 * (x) + 0x034) +#define ISR(x) (0x40 * (x) + 0x038) +#define IMR(x) (0x40 * (x) + 0x03C) +#define ROR(x) (0x40 * (x) + 0x040) +#define TOR(x) (0x40 * (x) + 0x044) +#define RFCR(x) (0x40 * (x) + 0x048) +#define TFCR(x) (0x40 * (x) + 0x04C) +#define RFF(x) (0x40 * (x) + 0x050) +#define TFF(x) (0x40 * (x) + 0x054) + +/* I2S COMP Registers */ +#define I2S_COMP_PARAM_2 0x01F0 +#define I2S_COMP_PARAM_1 0x01F4 +#define I2S_COMP_VERSION 0x01F8 +#define I2S_COMP_TYPE 0x01FC + +/* PSS_GEN_CTRL_I2S_GEN_CFG_0 Registers */ +#define I2S_GEN_CFG_0 0x000 +#define PSS_CPR_RST_EN 0x010 +#define PSS_CPR_RST_SET 0x014 +#define PSS_CPR_CLK_CLR 0x000 +#define PSS_CPR_AUX_RST_EN 0x070 + +#define MASTER_MODE BIT(13) + +/* Interrupt Flag */ +#define TX_INT_FLAG GENMASK(5, 4) +#define RX_INT_FLAG GENMASK(1, 0) +/* + * Component parameter register fields - define the I2S block's + * configuration. + */ +#define COMP1_TX_WORDSIZE_3(r) FIELD_GET(GENMASK(27, 25), (r)) +#define COMP1_TX_WORDSIZE_2(r) FIELD_GET(GENMASK(24, 22), (r)) +#define COMP1_TX_WORDSIZE_1(r) FIELD_GET(GENMASK(21, 19), (r)) +#define COMP1_TX_WORDSIZE_0(r) FIELD_GET(GENMASK(18, 16), (r)) +#define COMP1_RX_ENABLED(r) FIELD_GET(BIT(6), (r)) +#define COMP1_TX_ENABLED(r) FIELD_GET(BIT(5), (r)) +#define COMP1_MODE_EN(r) FIELD_GET(BIT(4), (r)) +#define COMP1_APB_DATA_WIDTH(r) FIELD_GET(GENMASK(1, 0), (r)) +#define COMP2_RX_WORDSIZE_3(r) FIELD_GET(GENMASK(12, 10), (r)) +#define COMP2_RX_WORDSIZE_2(r) FIELD_GET(GENMASK(9, 7), (r)) +#define COMP2_RX_WORDSIZE_1(r) FIELD_GET(GENMASK(5, 3), (r)) +#define COMP2_RX_WORDSIZE_0(r) FIELD_GET(GENMASK(2, 0), (r)) + +/* Add 1 to the below registers to indicate the actual size */ +#define COMP1_TX_CHANNELS(r) (FIELD_GET(GENMASK(10, 9), (r)) + 1) +#define COMP1_RX_CHANNELS(r) (FIELD_GET(GENMASK(8, 7), (r)) + 1) +#define COMP1_FIFO_DEPTH(r) (FIELD_GET(GENMASK(3, 2), (r)) + 1) + +/* Number of entries in WORDSIZE and DATA_WIDTH parameter registers */ +#define COMP_MAX_WORDSIZE 8 /* 3 bits register width */ + +#define MAX_CHANNEL_NUM 8 +#define MIN_CHANNEL_NUM 2 +#define MAX_ISR 4 + +#define TWO_CHANNEL_SUPPORT 2 /* up to 2.0 */ +#define FOUR_CHANNEL_SUPPORT 4 /* up to 3.1 */ +#define SIX_CHANNEL_SUPPORT 6 /* up to 5.1 */ +#define EIGHT_CHANNEL_SUPPORT 8 /* up to 7.1 */ + +#define DWC_I2S_PLAY BIT(0) +#define DWC_I2S_RECORD BIT(1) +#define DW_I2S_SLAVE BIT(2) +#define DW_I2S_MASTER BIT(3) + +#define I2S_RXDMA 0x01C0 +#define I2S_TXDMA 0x01C8 + +/* + * struct i2s_clk_config_data - represent i2s clk configuration data + * @chan_nr: number of channel + * @data_width: number of bits per sample (8/16/24/32 bit) + * @sample_rate: sampling frequency (8Khz, 16Khz, 48Khz) + */ +struct i2s_clk_config_data { + int chan_nr; + u32 data_width; + u32 sample_rate; +}; + +struct kmb_i2s_info { + void __iomem *i2s_base; + void __iomem *pss_base; + struct clk *clk_i2s; + struct clk *clk_apb; + int active; + unsigned int capability; + unsigned int i2s_reg_comp1; + unsigned int i2s_reg_comp2; + struct device *dev; + u32 ccr; + u32 xfer_resolution; + u32 fifo_th; + bool master; + + struct i2s_clk_config_data config; + int (*i2s_clk_cfg)(struct i2s_clk_config_data *config); + + /* data related to PIO transfers */ + bool use_pio; + struct snd_pcm_substream *tx_substream; + struct snd_pcm_substream *rx_substream; + unsigned int tx_ptr; + unsigned int rx_ptr; +}; + +#endif /* KMB_PLATFORM_H_ */ diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 89dcccdfb1cd..5dee55e9546b 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -544,7 +544,7 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, { struct hdac_bus *bus = dev_get_drvdata(dai->dev); struct hdac_ext_stream *link_dev; - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(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 skl_pipe_params p_params = {0}; struct hdac_ext_link *link; @@ -634,7 +634,7 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct hdac_bus *bus = dev_get_drvdata(dai->dev); - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct hdac_ext_stream *link_dev = snd_soc_dai_get_dma_data(dai, substream); struct hdac_ext_link *link; @@ -1071,7 +1071,7 @@ int skl_dai_load(struct snd_soc_component *cmp, int index, static int skl_platform_soc_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai_link *dai_link = rtd->dai_link; dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "In %s:%s\n", __func__, @@ -1225,7 +1225,7 @@ static int skl_platform_soc_mmap(struct snd_soc_component *component, static u64 skl_adjust_codec_delay(struct snd_pcm_substream *substream, u64 nsec) { - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); u64 codec_frames, codec_nsecs; @@ -1509,11 +1509,9 @@ int skl_platform_unregister(struct device *dev) struct skl_dev *skl = bus_to_skl(bus); struct skl_module_deferred_bind *modules, *tmp; - if (!list_empty(&skl->bind_list)) { - list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) { - list_del(&modules->node); - kfree(modules); - } + list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) { + list_del(&modules->node); + kfree(modules); } kfree(skl->dais); diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index b9aab47d1202..b7d2d97d12a7 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -3773,9 +3773,8 @@ void skl_tplg_exit(struct snd_soc_component *component, struct hdac_bus *bus) struct skl_dev *skl = bus_to_skl(bus); struct skl_pipeline *ppl, *tmp; - if (!list_empty(&skl->ppl_list)) - list_for_each_entry_safe(ppl, tmp, &skl->ppl_list, node) - list_del(&ppl->node); + list_for_each_entry_safe(ppl, tmp, &skl->ppl_list, node) + list_del(&ppl->node); /* clean up topology */ snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL); diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 9889f728752c..5e93ad85e06d 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -97,7 +97,7 @@ struct skl_audio_data_format { u8 number_of_channels; u8 valid_bit_depth; u8 sample_type; - u8 reserved[1]; + u8 reserved; } __packed; struct skl_base_cfg { |