ASoC: Intel: sof_sdw: add max98373 dapm routes
[linux-2.6-block.git] / sound / soc / intel / boards / sof_sdw_maxim.c
CommitLineData
be82e888
NM
1// SPDX-License-Identifier: GPL-2.0-only
2// Copyright (c) 2020 Intel Corporation
3//
fcb3f0fb 4// sof_sdw_maxim - Helpers to handle maxim codecs
be82e888
NM
5// codec devices from generic machine driver
6
7#include <linux/device.h>
8#include <linux/errno.h>
3f2c6564 9#include <sound/control.h>
be82e888
NM
10#include <sound/soc.h>
11#include <sound/soc-acpi.h>
3f2c6564 12#include <sound/soc-dapm.h>
be82e888 13#include "sof_sdw_common.h"
be82e888 14
fcb3f0fb 15static int maxim_part_id;
dea4138d 16#define SOF_SDW_PART_ID_MAX98363 0x8363
fcb3f0fb
UB
17#define SOF_SDW_PART_ID_MAX98373 0x8373
18
19static const struct snd_soc_dapm_widget maxim_widgets[] = {
be82e888
NM
20 SND_SOC_DAPM_SPK("Left Spk", NULL),
21 SND_SOC_DAPM_SPK("Right Spk", NULL),
22};
23
fcb3f0fb 24static const struct snd_kcontrol_new maxim_controls[] = {
be82e888
NM
25 SOC_DAPM_PIN_SWITCH("Left Spk"),
26 SOC_DAPM_PIN_SWITCH("Right Spk"),
27};
28
15ce635f
BL
29static const struct snd_soc_dapm_route max_98373_dapm_routes[] = {
30 { "Left Spk", NULL, "Left BE_OUT" },
31 { "Right Spk", NULL, "Right BE_OUT" },
32};
33
8266c731 34int maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd)
be82e888
NM
35{
36 struct snd_soc_card *card = rtd->card;
37 int ret;
38
39 card->components = devm_kasprintf(card->dev, GFP_KERNEL,
fcb3f0fb
UB
40 "%s spk:mx%04x",
41 card->components, maxim_part_id);
be82e888
NM
42 if (!card->components)
43 return -ENOMEM;
44
fcb3f0fb
UB
45 dev_dbg(card->dev, "soundwire maxim card components assigned : %s\n",
46 card->components);
47
48 ret = snd_soc_add_card_controls(card, maxim_controls,
49 ARRAY_SIZE(maxim_controls));
be82e888 50 if (ret) {
fcb3f0fb 51 dev_err(card->dev, "mx%04x ctrls addition failed: %d\n", maxim_part_id, ret);
be82e888
NM
52 return ret;
53 }
54
fcb3f0fb
UB
55 ret = snd_soc_dapm_new_controls(&card->dapm, maxim_widgets,
56 ARRAY_SIZE(maxim_widgets));
be82e888 57 if (ret) {
fcb3f0fb 58 dev_err(card->dev, "mx%04x widgets addition failed: %d\n", maxim_part_id, ret);
be82e888
NM
59 return ret;
60 }
61
62 ret = snd_soc_dapm_add_routes(&card->dapm, max_98373_dapm_routes, 2);
63 if (ret)
64 dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret);
65
66 return ret;
67}
68
33c85168 69static int mx8373_enable_spk_pin(struct snd_pcm_substream *substream, bool enable)
7cc3b56f 70{
a2c1125e 71 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
33c85168
RW
72 struct snd_soc_dai *codec_dai;
73 struct snd_soc_dai *cpu_dai;
7cc3b56f 74 int ret;
33c85168 75 int j;
7cc3b56f 76
33c85168
RW
77 /* set spk pin by playback only */
78 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
79 return 0;
80
a2c1125e 81 cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
33c85168
RW
82 for_each_rtd_codec_dais(rtd, j, codec_dai) {
83 struct snd_soc_dapm_context *dapm =
84 snd_soc_component_get_dapm(cpu_dai->component);
85 char pin_name[16];
86
87 snprintf(pin_name, ARRAY_SIZE(pin_name), "%s Spk",
88 codec_dai->component->name_prefix);
89
90 if (enable)
91 ret = snd_soc_dapm_enable_pin(dapm, pin_name);
92 else
93 ret = snd_soc_dapm_disable_pin(dapm, pin_name);
94
95 if (!ret)
96 snd_soc_dapm_sync(dapm);
7cc3b56f
RW
97 }
98
33c85168
RW
99 return 0;
100}
101
102static int mx8373_sdw_prepare(struct snd_pcm_substream *substream)
103{
d4321277 104 int ret;
33c85168
RW
105
106 /* according to soc_pcm_prepare dai link prepare is called first */
107 ret = sdw_prepare(substream);
108 if (ret < 0)
109 return ret;
110
111 return mx8373_enable_spk_pin(substream, true);
112}
113
114static int mx8373_sdw_hw_free(struct snd_pcm_substream *substream)
115{
d4321277 116 int ret;
33c85168
RW
117
118 /* according to soc_pcm_hw_free dai link free is called first */
119 ret = sdw_hw_free(substream);
120 if (ret < 0)
121 return ret;
122
123 return mx8373_enable_spk_pin(substream, false);
7cc3b56f
RW
124}
125
be82e888
NM
126static const struct snd_soc_ops max_98373_sdw_ops = {
127 .startup = sdw_startup,
33c85168
RW
128 .prepare = mx8373_sdw_prepare,
129 .trigger = sdw_trigger,
0281b02e 130 .hw_params = sdw_hw_params,
33c85168 131 .hw_free = mx8373_sdw_hw_free,
be82e888
NM
132 .shutdown = sdw_shutdown,
133};
134
e9fcbaff
YZ
135static int mx8373_sdw_late_probe(struct snd_soc_card *card)
136{
137 struct snd_soc_dapm_context *dapm = &card->dapm;
138
139 /* Disable Left and Right Spk pin after boot */
140 snd_soc_dapm_disable_pin(dapm, "Left Spk");
141 snd_soc_dapm_disable_pin(dapm, "Right Spk");
142 return snd_soc_dapm_sync(dapm);
143}
144
fcb3f0fb 145int sof_sdw_maxim_init(struct snd_soc_card *card,
fcb3f0fb
UB
146 struct snd_soc_dai_link *dai_links,
147 struct sof_sdw_codec_info *info,
148 bool playback)
be82e888
NM
149{
150 info->amp_num++;
be82e888 151
fcb3f0fb
UB
152 maxim_part_id = info->part_id;
153 switch (maxim_part_id) {
dea4138d
UB
154 case SOF_SDW_PART_ID_MAX98363:
155 /* Default ops are set in function init_dai_link.
156 * called as part of function create_sdw_dailink
157 */
158 break;
fcb3f0fb
UB
159 case SOF_SDW_PART_ID_MAX98373:
160 info->codec_card_late_probe = mx8373_sdw_late_probe;
161 dai_links->ops = &max_98373_sdw_ops;
162 break;
163 default:
164 dev_err(card->dev, "Invalid maxim_part_id %#x\n", maxim_part_id);
165 return -EINVAL;
166 }
be82e888
NM
167 return 0;
168}