162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci// Copyright (c) 2020 Intel Corporation 362306a36Sopenharmony_ci// 462306a36Sopenharmony_ci// sof_sdw_maxim - Helpers to handle maxim codecs 562306a36Sopenharmony_ci// codec devices from generic machine driver 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/device.h> 862306a36Sopenharmony_ci#include <linux/errno.h> 962306a36Sopenharmony_ci#include <sound/control.h> 1062306a36Sopenharmony_ci#include <sound/soc.h> 1162306a36Sopenharmony_ci#include <sound/soc-acpi.h> 1262306a36Sopenharmony_ci#include <sound/soc-dapm.h> 1362306a36Sopenharmony_ci#include "sof_sdw_common.h" 1462306a36Sopenharmony_ci#include "sof_maxim_common.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic int maxim_part_id; 1762306a36Sopenharmony_ci#define SOF_SDW_PART_ID_MAX98363 0x8363 1862306a36Sopenharmony_ci#define SOF_SDW_PART_ID_MAX98373 0x8373 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget maxim_widgets[] = { 2162306a36Sopenharmony_ci SND_SOC_DAPM_SPK("Left Spk", NULL), 2262306a36Sopenharmony_ci SND_SOC_DAPM_SPK("Right Spk", NULL), 2362306a36Sopenharmony_ci}; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic const struct snd_kcontrol_new maxim_controls[] = { 2662306a36Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Left Spk"), 2762306a36Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Right Spk"), 2862306a36Sopenharmony_ci}; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic int spk_init(struct snd_soc_pcm_runtime *rtd) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci struct snd_soc_card *card = rtd->card; 3362306a36Sopenharmony_ci int ret; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci card->components = devm_kasprintf(card->dev, GFP_KERNEL, 3662306a36Sopenharmony_ci "%s spk:mx%04x", 3762306a36Sopenharmony_ci card->components, maxim_part_id); 3862306a36Sopenharmony_ci if (!card->components) 3962306a36Sopenharmony_ci return -ENOMEM; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci dev_dbg(card->dev, "soundwire maxim card components assigned : %s\n", 4262306a36Sopenharmony_ci card->components); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci ret = snd_soc_add_card_controls(card, maxim_controls, 4562306a36Sopenharmony_ci ARRAY_SIZE(maxim_controls)); 4662306a36Sopenharmony_ci if (ret) { 4762306a36Sopenharmony_ci dev_err(card->dev, "mx%04x ctrls addition failed: %d\n", maxim_part_id, ret); 4862306a36Sopenharmony_ci return ret; 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci ret = snd_soc_dapm_new_controls(&card->dapm, maxim_widgets, 5262306a36Sopenharmony_ci ARRAY_SIZE(maxim_widgets)); 5362306a36Sopenharmony_ci if (ret) { 5462306a36Sopenharmony_ci dev_err(card->dev, "mx%04x widgets addition failed: %d\n", maxim_part_id, ret); 5562306a36Sopenharmony_ci return ret; 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci ret = snd_soc_dapm_add_routes(&card->dapm, max_98373_dapm_routes, 2); 5962306a36Sopenharmony_ci if (ret) 6062306a36Sopenharmony_ci dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci return ret; 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic int mx8373_enable_spk_pin(struct snd_pcm_substream *substream, bool enable) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 6862306a36Sopenharmony_ci struct snd_soc_dai *codec_dai; 6962306a36Sopenharmony_ci struct snd_soc_dai *cpu_dai; 7062306a36Sopenharmony_ci int ret; 7162306a36Sopenharmony_ci int j; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci /* set spk pin by playback only */ 7462306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 7562306a36Sopenharmony_ci return 0; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci cpu_dai = asoc_rtd_to_cpu(rtd, 0); 7862306a36Sopenharmony_ci for_each_rtd_codec_dais(rtd, j, codec_dai) { 7962306a36Sopenharmony_ci struct snd_soc_dapm_context *dapm = 8062306a36Sopenharmony_ci snd_soc_component_get_dapm(cpu_dai->component); 8162306a36Sopenharmony_ci char pin_name[16]; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci snprintf(pin_name, ARRAY_SIZE(pin_name), "%s Spk", 8462306a36Sopenharmony_ci codec_dai->component->name_prefix); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (enable) 8762306a36Sopenharmony_ci ret = snd_soc_dapm_enable_pin(dapm, pin_name); 8862306a36Sopenharmony_ci else 8962306a36Sopenharmony_ci ret = snd_soc_dapm_disable_pin(dapm, pin_name); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (!ret) 9262306a36Sopenharmony_ci snd_soc_dapm_sync(dapm); 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci return 0; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic int mx8373_sdw_prepare(struct snd_pcm_substream *substream) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci int ret; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci /* according to soc_pcm_prepare dai link prepare is called first */ 10362306a36Sopenharmony_ci ret = sdw_prepare(substream); 10462306a36Sopenharmony_ci if (ret < 0) 10562306a36Sopenharmony_ci return ret; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci return mx8373_enable_spk_pin(substream, true); 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic int mx8373_sdw_hw_free(struct snd_pcm_substream *substream) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci int ret; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci /* according to soc_pcm_hw_free dai link free is called first */ 11562306a36Sopenharmony_ci ret = sdw_hw_free(substream); 11662306a36Sopenharmony_ci if (ret < 0) 11762306a36Sopenharmony_ci return ret; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci return mx8373_enable_spk_pin(substream, false); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic const struct snd_soc_ops max_98373_sdw_ops = { 12362306a36Sopenharmony_ci .startup = sdw_startup, 12462306a36Sopenharmony_ci .prepare = mx8373_sdw_prepare, 12562306a36Sopenharmony_ci .trigger = sdw_trigger, 12662306a36Sopenharmony_ci .hw_params = sdw_hw_params, 12762306a36Sopenharmony_ci .hw_free = mx8373_sdw_hw_free, 12862306a36Sopenharmony_ci .shutdown = sdw_shutdown, 12962306a36Sopenharmony_ci}; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic int mx8373_sdw_late_probe(struct snd_soc_card *card) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci struct snd_soc_dapm_context *dapm = &card->dapm; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci /* Disable Left and Right Spk pin after boot */ 13662306a36Sopenharmony_ci snd_soc_dapm_disable_pin(dapm, "Left Spk"); 13762306a36Sopenharmony_ci snd_soc_dapm_disable_pin(dapm, "Right Spk"); 13862306a36Sopenharmony_ci return snd_soc_dapm_sync(dapm); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ciint sof_sdw_maxim_init(struct snd_soc_card *card, 14262306a36Sopenharmony_ci const struct snd_soc_acpi_link_adr *link, 14362306a36Sopenharmony_ci struct snd_soc_dai_link *dai_links, 14462306a36Sopenharmony_ci struct sof_sdw_codec_info *info, 14562306a36Sopenharmony_ci bool playback) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci info->amp_num++; 14862306a36Sopenharmony_ci if (info->amp_num == 2) 14962306a36Sopenharmony_ci dai_links->init = spk_init; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci maxim_part_id = info->part_id; 15262306a36Sopenharmony_ci switch (maxim_part_id) { 15362306a36Sopenharmony_ci case SOF_SDW_PART_ID_MAX98363: 15462306a36Sopenharmony_ci /* Default ops are set in function init_dai_link. 15562306a36Sopenharmony_ci * called as part of function create_sdw_dailink 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_ci break; 15862306a36Sopenharmony_ci case SOF_SDW_PART_ID_MAX98373: 15962306a36Sopenharmony_ci info->codec_card_late_probe = mx8373_sdw_late_probe; 16062306a36Sopenharmony_ci dai_links->ops = &max_98373_sdw_ops; 16162306a36Sopenharmony_ci break; 16262306a36Sopenharmony_ci default: 16362306a36Sopenharmony_ci dev_err(card->dev, "Invalid maxim_part_id %#x\n", maxim_part_id); 16462306a36Sopenharmony_ci return -EINVAL; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci return 0; 16762306a36Sopenharmony_ci} 168