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