blob: bb12351330e8c0f307b0237ee2e2f1b6b2f9aeec [file] [log] [blame]
Kuninori Morimotodecd8962018-07-02 06:31:16 +00001// SPDX-License-Identifier: GPL-2.0
2//
3// ASoC audio graph sound card support
4//
5// Copyright (C) 2016 Renesas Solutions Corp.
6// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
7//
8// based on ${LINUX}/sound/soc/generic/simple-card.c
9
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +000010#include <linux/clk.h>
11#include <linux/device.h>
12#include <linux/gpio.h>
Shawn Guof9869072017-06-29 21:26:38 +080013#include <linux/gpio/consumer.h>
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +000014#include <linux/module.h>
15#include <linux/of.h>
16#include <linux/of_device.h>
17#include <linux/of_gpio.h>
18#include <linux/of_graph.h>
19#include <linux/platform_device.h>
20#include <linux/string.h>
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +000021#include <sound/simple_card_utils.h>
22
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +090023struct graph_priv {
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +000024 struct snd_soc_card snd_card;
25 struct graph_dai_props {
Kuninori Morimoto0e3460b2018-11-30 02:07:48 +000026 struct asoc_simple_dai *cpu_dai;
27 struct asoc_simple_dai *codec_dai;
Kuninori Morimoto8e6746d2018-08-31 03:09:05 +000028 struct snd_soc_dai_link_component codecs; /* single codec */
Kuninori Morimoto910fdca2019-01-21 09:32:32 +090029 struct snd_soc_dai_link_component platforms;
Kuninori Morimotoae3cb572018-12-14 11:32:25 +090030 struct asoc_simple_card_data adata;
31 struct snd_soc_codec_conf *codec_conf;
Olivier Moysan757652d2017-11-09 15:07:58 +010032 unsigned int mclk_fs;
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +000033 } *dai_props;
Katsuhiro Suzukif6de35c2018-06-11 17:32:14 +090034 struct asoc_simple_jack hp_jack;
35 struct asoc_simple_jack mic_jack;
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +000036 struct snd_soc_dai_link *dai_link;
Kuninori Morimoto0e3460b2018-11-30 02:07:48 +000037 struct asoc_simple_dai *dais;
Kuninori Morimotoae3cb572018-12-14 11:32:25 +090038 struct snd_soc_codec_conf *codec_conf;
Shawn Guof9869072017-06-29 21:26:38 +080039 struct gpio_desc *pa_gpio;
40};
41
Kuninori Morimoto1e4771a2018-12-20 10:45:59 +090042struct link_info {
43 int dais; /* number of dai */
44 int link; /* number of link */
45 int conf; /* number of codec_conf */
46 int cpu; /* turn for CPU / Codec */
47};
48
Kuninori Morimoto64ef0812018-11-22 00:57:40 +000049#define graph_priv_to_card(priv) (&(priv)->snd_card)
50#define graph_priv_to_props(priv, i) ((priv)->dai_props + (i))
51#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev)
52#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i))
53
Kuninori Morimotoae3cb572018-12-14 11:32:25 +090054#define PREFIX "audio-graph-card,"
55
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +090056static int graph_outdrv_event(struct snd_soc_dapm_widget *w,
57 struct snd_kcontrol *kcontrol,
58 int event)
Shawn Guof9869072017-06-29 21:26:38 +080059{
60 struct snd_soc_dapm_context *dapm = w->dapm;
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +090061 struct graph_priv *priv = snd_soc_card_get_drvdata(dapm->card);
Shawn Guof9869072017-06-29 21:26:38 +080062
63 switch (event) {
64 case SND_SOC_DAPM_POST_PMU:
65 gpiod_set_value_cansleep(priv->pa_gpio, 1);
66 break;
67 case SND_SOC_DAPM_PRE_PMD:
68 gpiod_set_value_cansleep(priv->pa_gpio, 0);
69 break;
70 default:
71 return -EINVAL;
72 }
73
74 return 0;
75}
76
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +090077static const struct snd_soc_dapm_widget graph_dapm_widgets[] = {
Shawn Guof9869072017-06-29 21:26:38 +080078 SND_SOC_DAPM_OUT_DRV_E("Amplifier", SND_SOC_NOPM,
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +090079 0, 0, NULL, 0, graph_outdrv_event,
Shawn Guof9869072017-06-29 21:26:38 +080080 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +000081};
82
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +090083static int graph_startup(struct snd_pcm_substream *substream)
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +000084{
85 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +090086 struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card);
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +000087 struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
88 int ret;
89
Kuninori Morimoto0e3460b2018-11-30 02:07:48 +000090 ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +000091 if (ret)
92 return ret;
93
Kuninori Morimoto0e3460b2018-11-30 02:07:48 +000094 ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +000095 if (ret)
Kuninori Morimoto0e3460b2018-11-30 02:07:48 +000096 asoc_simple_card_clk_disable(dai_props->cpu_dai);
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +000097
98 return ret;
99}
100
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900101static void graph_shutdown(struct snd_pcm_substream *substream)
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000102{
103 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900104 struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card);
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000105 struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
106
Kuninori Morimoto0e3460b2018-11-30 02:07:48 +0000107 asoc_simple_card_clk_disable(dai_props->cpu_dai);
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000108
Kuninori Morimoto0e3460b2018-11-30 02:07:48 +0000109 asoc_simple_card_clk_disable(dai_props->codec_dai);
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000110}
111
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900112static int graph_hw_params(struct snd_pcm_substream *substream,
113 struct snd_pcm_hw_params *params)
Olivier Moysan757652d2017-11-09 15:07:58 +0100114{
115 struct snd_soc_pcm_runtime *rtd = substream->private_data;
116 struct snd_soc_dai *codec_dai = rtd->codec_dai;
117 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900118 struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card);
Olivier Moysan757652d2017-11-09 15:07:58 +0100119 struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
120 unsigned int mclk, mclk_fs = 0;
121 int ret = 0;
122
Kuninori Morimoto56eb8182018-12-14 11:32:30 +0900123 if (dai_props->mclk_fs)
Olivier Moysan757652d2017-11-09 15:07:58 +0100124 mclk_fs = dai_props->mclk_fs;
125
126 if (mclk_fs) {
127 mclk = params_rate(params) * mclk_fs;
128 ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
129 SND_SOC_CLOCK_IN);
130 if (ret && ret != -ENOTSUPP)
131 goto err;
132
133 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
134 SND_SOC_CLOCK_OUT);
135 if (ret && ret != -ENOTSUPP)
136 goto err;
137 }
138 return 0;
139err:
140 return ret;
141}
142
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900143static const struct snd_soc_ops graph_ops = {
144 .startup = graph_startup,
145 .shutdown = graph_shutdown,
146 .hw_params = graph_hw_params,
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000147};
148
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900149static int graph_dai_init(struct snd_soc_pcm_runtime *rtd)
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000150{
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900151 struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card);
Kuninori Morimoto0e3460b2018-11-30 02:07:48 +0000152 struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
153 int ret = 0;
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000154
Kuninori Morimoto0e3460b2018-11-30 02:07:48 +0000155 ret = asoc_simple_card_init_dai(rtd->codec_dai,
156 dai_props->codec_dai);
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000157 if (ret < 0)
158 return ret;
159
Kuninori Morimoto0e3460b2018-11-30 02:07:48 +0000160 ret = asoc_simple_card_init_dai(rtd->cpu_dai,
161 dai_props->cpu_dai);
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000162 if (ret < 0)
163 return ret;
164
165 return 0;
166}
167
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900168static int graph_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
169 struct snd_pcm_hw_params *params)
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900170{
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900171 struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card);
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900172 struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
173
174 asoc_simple_card_convert_fixup(&dai_props->adata, params);
175
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900176 return 0;
177}
178
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900179static void graph_get_conversion(struct device *dev,
180 struct device_node *ep,
181 struct asoc_simple_card_data *adata)
Kuninori Morimoto40dfae12018-12-20 10:45:48 +0900182{
183 struct device_node *top = dev->of_node;
184 struct device_node *port = of_get_parent(ep);
185 struct device_node *ports = of_get_parent(port);
186 struct device_node *node = of_graph_get_port_parent(ep);
187
188 asoc_simple_card_parse_convert(dev, top, NULL, adata);
189 asoc_simple_card_parse_convert(dev, node, PREFIX, adata);
190 asoc_simple_card_parse_convert(dev, ports, NULL, adata);
191 asoc_simple_card_parse_convert(dev, port, NULL, adata);
192 asoc_simple_card_parse_convert(dev, ep, NULL, adata);
193}
194
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900195static int graph_dai_link_of_dpcm(struct graph_priv *priv,
196 struct device_node *cpu_ep,
197 struct device_node *codec_ep,
198 struct link_info *li,
199 int dup_codec)
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900200{
201 struct device *dev = graph_priv_to_dev(priv);
Kuninori Morimoto1e4771a2018-12-20 10:45:59 +0900202 struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, li->link);
203 struct graph_dai_props *dai_props = graph_priv_to_props(priv, li->link);
Kuninori Morimotodd98fbc2018-12-20 10:46:05 +0900204 struct device_node *top = dev->of_node;
Kuninori Morimoto1e4771a2018-12-20 10:45:59 +0900205 struct device_node *ep = li->cpu ? cpu_ep : codec_ep;
Kuninori Morimotodd98fbc2018-12-20 10:46:05 +0900206 struct device_node *port;
207 struct device_node *ports;
208 struct device_node *node;
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900209 struct asoc_simple_dai *dai;
Kuninori Morimoto66164a42018-12-14 11:32:43 +0900210 struct snd_soc_dai_link_component *codecs = dai_link->codecs;
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900211 int ret;
212
Kuninori Morimotodd98fbc2018-12-20 10:46:05 +0900213 /* Do it all CPU endpoint, and 1st Codec endpoint */
214 if (!li->cpu && dup_codec)
215 return 0;
216
217 port = of_get_parent(ep);
218 ports = of_get_parent(port);
219 node = of_graph_get_port_parent(ep);
220
Kuninori Morimoto1e4771a2018-12-20 10:45:59 +0900221 li->link++;
222
223 dev_dbg(dev, "link_of DPCM (%pOF)\n", ep);
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900224
Kuninori Morimoto56eb8182018-12-14 11:32:30 +0900225 of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs);
226 of_property_read_u32(ports, "mclk-fs", &dai_props->mclk_fs);
227 of_property_read_u32(port, "mclk-fs", &dai_props->mclk_fs);
228 of_property_read_u32(ep, "mclk-fs", &dai_props->mclk_fs);
Kuninori Morimoto7ced65f2018-12-14 11:32:36 +0900229
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900230 graph_get_conversion(dev, ep, &dai_props->adata);
Kuninori Morimoto7ced65f2018-12-14 11:32:36 +0900231
Kuninori Morimoto56eb8182018-12-14 11:32:30 +0900232 of_node_put(ports);
233 of_node_put(port);
Kuninori Morimotodd98fbc2018-12-20 10:46:05 +0900234 of_node_put(node);
Kuninori Morimoto56eb8182018-12-14 11:32:30 +0900235
Kuninori Morimoto1e4771a2018-12-20 10:45:59 +0900236 if (li->cpu) {
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900237
238 /* BE is dummy */
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900239 codecs->of_node = NULL;
240 codecs->dai_name = "snd-soc-dummy-dai";
241 codecs->name = "snd-soc-dummy";
242
243 /* FE settings */
244 dai_link->dynamic = 1;
245 dai_link->dpcm_merged_format = 1;
246
247 dai =
Kuninori Morimoto1e4771a2018-12-20 10:45:59 +0900248 dai_props->cpu_dai = &priv->dais[li->dais++];
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900249
250 ret = asoc_simple_card_parse_graph_cpu(ep, dai_link);
251 if (ret)
252 return ret;
253
254 ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, dai);
255 if (ret < 0)
256 return ret;
257
258 ret = asoc_simple_card_set_dailink_name(dev, dai_link,
259 "fe.%s",
260 dai_link->cpu_dai_name);
261 if (ret < 0)
262 return ret;
263
264 /* card->num_links includes Codec */
265 asoc_simple_card_canonicalize_cpu(dai_link,
266 of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
267 } else {
268 struct snd_soc_codec_conf *cconf;
269
270 /* FE is dummy */
271 dai_link->cpu_of_node = NULL;
272 dai_link->cpu_dai_name = "snd-soc-dummy-dai";
273 dai_link->cpu_name = "snd-soc-dummy";
274
275 /* BE settings */
276 dai_link->no_pcm = 1;
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900277 dai_link->be_hw_params_fixup = graph_be_hw_params_fixup;
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900278
279 dai =
Kuninori Morimoto1e4771a2018-12-20 10:45:59 +0900280 dai_props->codec_dai = &priv->dais[li->dais++];
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900281
282 cconf =
Kuninori Morimoto1e4771a2018-12-20 10:45:59 +0900283 dai_props->codec_conf = &priv->codec_conf[li->conf++];
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900284
285 ret = asoc_simple_card_parse_graph_codec(ep, dai_link);
286 if (ret < 0)
287 return ret;
288
289 ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, dai);
290 if (ret < 0)
291 return ret;
292
293 ret = asoc_simple_card_set_dailink_name(dev, dai_link,
294 "be.%s",
Kuninori Morimoto66164a42018-12-14 11:32:43 +0900295 codecs->dai_name);
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900296 if (ret < 0)
297 return ret;
298
299 /* check "prefix" from top node */
Kuninori Morimoto66164a42018-12-14 11:32:43 +0900300 snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900301 "prefix");
Kuninori Morimoto66164a42018-12-14 11:32:43 +0900302 snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node,
303 PREFIX "prefix");
304 snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node,
305 "prefix");
306 snd_soc_of_parse_node_prefix(port, cconf, codecs->of_node,
307 "prefix");
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900308 }
309
Kuninori Morimotofe7ed4d2019-01-21 16:40:59 +0900310 asoc_simple_card_canonicalize_platform(dai_link);
311
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900312 ret = asoc_simple_card_of_parse_tdm(ep, dai);
313 if (ret)
314 return ret;
315
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900316 ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
317 NULL, &dai_link->dai_fmt);
318 if (ret < 0)
319 return ret;
320
321 dai_link->dpcm_playback = 1;
322 dai_link->dpcm_capture = 1;
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900323 dai_link->ops = &graph_ops;
324 dai_link->init = graph_dai_init;
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900325
326 return 0;
327}
328
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900329static int graph_dai_link_of(struct graph_priv *priv,
330 struct device_node *cpu_ep,
331 struct device_node *codec_ep,
332 struct link_info *li)
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000333{
334 struct device *dev = graph_priv_to_dev(priv);
Kuninori Morimoto1e4771a2018-12-20 10:45:59 +0900335 struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, li->link);
336 struct graph_dai_props *dai_props = graph_priv_to_props(priv, li->link);
Kuninori Morimotodd98fbc2018-12-20 10:46:05 +0900337 struct device_node *top = dev->of_node;
338 struct device_node *cpu_port;
Kuninori Morimotodd98fbc2018-12-20 10:46:05 +0900339 struct device_node *cpu_ports;
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900340 struct device_node *codec_port;
Kuninori Morimotodd98fbc2018-12-20 10:46:05 +0900341 struct device_node *codec_ports;
Kuninori Morimoto0e3460b2018-11-30 02:07:48 +0000342 struct asoc_simple_dai *cpu_dai;
343 struct asoc_simple_dai *codec_dai;
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000344 int ret;
345
Kuninori Morimotodd98fbc2018-12-20 10:46:05 +0900346 /* Do it only CPU turn */
347 if (!li->cpu)
348 return 0;
349
350 cpu_port = of_get_parent(cpu_ep);
351 cpu_ports = of_get_parent(cpu_port);
352 codec_port = of_get_parent(codec_ep);
353 codec_ports = of_get_parent(codec_port);
354
Kuninori Morimoto1e4771a2018-12-20 10:45:59 +0900355 dev_dbg(dev, "link_of (%pOF)\n", cpu_ep);
356
357 li->link++;
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900358
Kuninori Morimoto0e3460b2018-11-30 02:07:48 +0000359 cpu_dai =
Kuninori Morimoto1e4771a2018-12-20 10:45:59 +0900360 dai_props->cpu_dai = &priv->dais[li->dais++];
Kuninori Morimoto0e3460b2018-11-30 02:07:48 +0000361 codec_dai =
Kuninori Morimoto1e4771a2018-12-20 10:45:59 +0900362 dai_props->codec_dai = &priv->dais[li->dais++];
Kuninori Morimoto0e3460b2018-11-30 02:07:48 +0000363
Kuninori Morimoto56eb8182018-12-14 11:32:30 +0900364 /* Factor to mclk, used in hw_params() */
365 of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs);
366 of_property_read_u32(cpu_ports, "mclk-fs", &dai_props->mclk_fs);
367 of_property_read_u32(codec_ports, "mclk-fs", &dai_props->mclk_fs);
368 of_property_read_u32(cpu_port, "mclk-fs", &dai_props->mclk_fs);
369 of_property_read_u32(codec_port, "mclk-fs", &dai_props->mclk_fs);
370 of_property_read_u32(cpu_ep, "mclk-fs", &dai_props->mclk_fs);
371 of_property_read_u32(codec_ep, "mclk-fs", &dai_props->mclk_fs);
372 of_node_put(cpu_port);
373 of_node_put(cpu_ports);
374 of_node_put(codec_port);
375 of_node_put(codec_ports);
376
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000377 ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
378 NULL, &dai_link->dai_fmt);
379 if (ret < 0)
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900380 return ret;
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000381
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000382 ret = asoc_simple_card_parse_graph_cpu(cpu_ep, dai_link);
383 if (ret < 0)
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900384 return ret;
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000385
386 ret = asoc_simple_card_parse_graph_codec(codec_ep, dai_link);
387 if (ret < 0)
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900388 return ret;
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000389
Kuninori Morimotoc98907d2017-06-14 00:35:30 +0000390 ret = asoc_simple_card_of_parse_tdm(cpu_ep, cpu_dai);
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000391 if (ret < 0)
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900392 return ret;
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000393
Kuninori Morimotoc98907d2017-06-14 00:35:30 +0000394 ret = asoc_simple_card_of_parse_tdm(codec_ep, codec_dai);
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000395 if (ret < 0)
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900396 return ret;
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000397
398 ret = asoc_simple_card_parse_clk_cpu(dev, cpu_ep, dai_link, cpu_dai);
399 if (ret < 0)
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900400 return ret;
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000401
402 ret = asoc_simple_card_parse_clk_codec(dev, codec_ep, dai_link, codec_dai);
403 if (ret < 0)
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900404 return ret;
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000405
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000406 ret = asoc_simple_card_set_dailink_name(dev, dai_link,
407 "%s-%s",
408 dai_link->cpu_dai_name,
Kuninori Morimoto8e6746d2018-08-31 03:09:05 +0000409 dai_link->codecs->dai_name);
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000410 if (ret < 0)
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900411 return ret;
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000412
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900413 dai_link->ops = &graph_ops;
414 dai_link->init = graph_dai_init;
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000415
Kuninori Morimotofe7ed4d2019-01-21 16:40:59 +0900416 asoc_simple_card_canonicalize_platform(dai_link);
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000417 asoc_simple_card_canonicalize_cpu(dai_link,
Kuninori Morimoto47ca9592017-06-22 06:21:49 +0000418 of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000419
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900420 return 0;
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000421}
422
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900423static int graph_for_each_link(struct graph_priv *priv,
Kuninori Morimotofce9b902018-12-20 10:46:20 +0900424 struct link_info *li,
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900425 int (*func_noml)(struct graph_priv *priv,
Kuninori Morimotofce9b902018-12-20 10:46:20 +0900426 struct device_node *cpu_ep,
427 struct device_node *codec_ep,
428 struct link_info *li),
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900429 int (*func_dpcm)(struct graph_priv *priv,
Kuninori Morimotofce9b902018-12-20 10:46:20 +0900430 struct device_node *cpu_ep,
431 struct device_node *codec_ep,
432 struct link_info *li, int dup_codec))
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000433{
434 struct of_phandle_iterator it;
435 struct device *dev = graph_priv_to_dev(priv);
Kuninori Morimotofce9b902018-12-20 10:46:20 +0900436 struct device_node *node = dev->of_node;
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900437 struct device_node *cpu_port;
Kuninori Morimotofce9b902018-12-20 10:46:20 +0900438 struct device_node *cpu_ep;
439 struct device_node *codec_ep;
440 struct device_node *codec_port;
441 struct device_node *codec_port_old = NULL;
Kuninori Morimotode2949f2018-12-20 10:45:54 +0900442 struct asoc_simple_card_data adata;
Kuninori Morimoto0e3460b2018-11-30 02:07:48 +0000443 int rc, ret;
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000444
Kuninori Morimotofce9b902018-12-20 10:46:20 +0900445 /* loop for all listed CPU port */
446 of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
447 cpu_port = it.node;
448 cpu_ep = NULL;
449
450 /* loop for all CPU endpoint */
451 while (1) {
452 cpu_ep = of_get_next_child(cpu_port, cpu_ep);
453 if (!cpu_ep)
454 break;
455
456 /* get codec */
457 codec_ep = of_graph_get_remote_endpoint(cpu_ep);
458 codec_port = of_get_parent(codec_ep);
459
460 of_node_put(codec_ep);
461 of_node_put(codec_port);
462
463 /* get convert-xxx property */
464 memset(&adata, 0, sizeof(adata));
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900465 graph_get_conversion(dev, codec_ep, &adata);
466 graph_get_conversion(dev, cpu_ep, &adata);
Kuninori Morimotofce9b902018-12-20 10:46:20 +0900467
468 /*
469 * It is DPCM
470 * if Codec port has many endpoints,
471 * or has convert-xxx property
472 */
473 if ((of_get_child_count(codec_port) > 1) ||
474 adata.convert_rate || adata.convert_channels)
475 ret = func_dpcm(priv, cpu_ep, codec_ep, li,
476 (codec_port_old == codec_port));
477 /* else normal sound */
478 else
479 ret = func_noml(priv, cpu_ep, codec_ep, li);
480
481 if (ret < 0)
482 return ret;
483
484 codec_port_old = codec_port;
485 }
486 }
487
488 return 0;
489}
490
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900491static int graph_parse_of(struct graph_priv *priv)
Kuninori Morimotofce9b902018-12-20 10:46:20 +0900492{
493 struct snd_soc_card *card = graph_priv_to_card(priv);
494 struct link_info li;
495 int ret;
496
Shawn Guof9869072017-06-29 21:26:38 +0800497 ret = asoc_simple_card_of_parse_widgets(card, NULL);
498 if (ret < 0)
499 return ret;
500
Kuninori Morimoto33404f32018-11-21 02:11:13 +0000501 ret = asoc_simple_card_of_parse_routing(card, NULL);
Shawn Guof9869072017-06-29 21:26:38 +0800502 if (ret < 0)
503 return ret;
504
Kuninori Morimoto1e4771a2018-12-20 10:45:59 +0900505 memset(&li, 0, sizeof(li));
Kuninori Morimoto1e4771a2018-12-20 10:45:59 +0900506 for (li.cpu = 1; li.cpu >= 0; li.cpu--) {
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900507 /*
508 * Detect all CPU first, and Detect all Codec 2nd.
509 *
510 * In Normal sound case, all DAIs are detected
511 * as "CPU-Codec".
512 *
513 * In DPCM sound case,
514 * all CPUs are detected as "CPU-dummy", and
515 * all Codecs are detected as "dummy-Codec".
516 * To avoid random sub-device numbering,
517 * detect "dummy-Codec" in last;
518 */
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900519 ret = graph_for_each_link(priv, &li,
520 graph_dai_link_of,
521 graph_dai_link_of_dpcm);
Kuninori Morimotofce9b902018-12-20 10:46:20 +0900522 if (ret < 0)
523 return ret;
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000524 }
525
526 return asoc_simple_card_parse_card_name(card, NULL);
527}
528
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900529static int graph_count_noml(struct graph_priv *priv,
530 struct device_node *cpu_ep,
531 struct device_node *codec_ep,
532 struct link_info *li)
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000533{
Kuninori Morimotodd98fbc2018-12-20 10:46:05 +0900534 struct device *dev = graph_priv_to_dev(priv);
535
536 li->link += 1; /* 1xCPU-Codec */
537 li->dais += 2; /* 1xCPU + 1xCodec */
538
539 dev_dbg(dev, "Count As Normal\n");
540
541 return 0;
542}
543
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900544static int graph_count_dpcm(struct graph_priv *priv,
545 struct device_node *cpu_ep,
546 struct device_node *codec_ep,
547 struct link_info *li,
548 int dup_codec)
Kuninori Morimotodd98fbc2018-12-20 10:46:05 +0900549{
550 struct device *dev = graph_priv_to_dev(priv);
551
552 li->link++; /* 1xCPU-dummy */
553 li->dais++; /* 1xCPU */
554
555 if (!dup_codec) {
556 li->link++; /* 1xdummy-Codec */
557 li->conf++; /* 1xdummy-Codec */
558 li->dais++; /* 1xCodec */
559 }
560
561 dev_dbg(dev, "Count As DPCM\n");
562
563 return 0;
564}
565
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900566static void graph_get_dais_count(struct graph_priv *priv,
567 struct link_info *li)
Kuninori Morimotodd98fbc2018-12-20 10:46:05 +0900568{
569 struct device *dev = graph_priv_to_dev(priv);
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000570
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900571 /*
572 * link_num : number of links.
573 * CPU-Codec / CPU-dummy / dummy-Codec
574 * dais_num : number of DAIs
575 * ccnf_num : number of codec_conf
576 * same number for "dummy-Codec"
577 *
578 * ex1)
579 * CPU0 --- Codec0 link : 5
580 * CPU1 --- Codec1 dais : 7
581 * CPU2 -/ ccnf : 1
582 * CPU3 --- Codec2
583 *
584 * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
585 * => 7 DAIs = 4xCPU + 3xCodec
586 * => 1 ccnf = 1xdummy-Codec
587 *
588 * ex2)
589 * CPU0 --- Codec0 link : 5
590 * CPU1 --- Codec1 dais : 6
591 * CPU2 -/ ccnf : 1
592 * CPU3 -/
593 *
594 * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
595 * => 6 DAIs = 4xCPU + 2xCodec
596 * => 1 ccnf = 1xdummy-Codec
597 *
598 * ex3)
599 * CPU0 --- Codec0 link : 6
600 * CPU1 -/ dais : 6
601 * CPU2 --- Codec1 ccnf : 2
602 * CPU3 -/
603 *
604 * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
605 * => 6 DAIs = 4xCPU + 2xCodec
606 * => 2 ccnf = 2xdummy-Codec
Kuninori Morimotode2949f2018-12-20 10:45:54 +0900607 *
608 * ex4)
609 * CPU0 --- Codec0 (convert-rate) link : 3
610 * CPU1 --- Codec1 dais : 4
611 * ccnf : 1
612 *
613 * => 3 links = 1xCPU-Codec + 1xCPU-dummy + 1xdummy-Codec
614 * => 4 DAIs = 2xCPU + 2xCodec
615 * => 1 ccnf = 1xdummy-Codec
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900616 */
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900617 graph_for_each_link(priv, li,
618 graph_count_noml,
619 graph_count_dpcm);
Kuninori Morimotofce9b902018-12-20 10:46:20 +0900620 dev_dbg(dev, "link %d, dais %d, ccnf %d\n",
621 li->link, li->dais, li->conf);
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000622}
623
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900624static int graph_card_probe(struct snd_soc_card *card)
Katsuhiro Suzukif6de35c2018-06-11 17:32:14 +0900625{
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900626 struct graph_priv *priv = snd_soc_card_get_drvdata(card);
Katsuhiro Suzukif6de35c2018-06-11 17:32:14 +0900627 int ret;
628
629 ret = asoc_simple_card_init_hp(card, &priv->hp_jack, NULL);
630 if (ret < 0)
631 return ret;
632
633 ret = asoc_simple_card_init_mic(card, &priv->mic_jack, NULL);
634 if (ret < 0)
635 return ret;
636
637 return 0;
638}
639
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900640static int graph_probe(struct platform_device *pdev)
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000641{
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900642 struct graph_priv *priv;
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000643 struct snd_soc_dai_link *dai_link;
644 struct graph_dai_props *dai_props;
Kuninori Morimoto0e3460b2018-11-30 02:07:48 +0000645 struct asoc_simple_dai *dais;
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000646 struct device *dev = &pdev->dev;
647 struct snd_soc_card *card;
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900648 struct snd_soc_codec_conf *cconf;
Kuninori Morimoto1e4771a2018-12-20 10:45:59 +0900649 struct link_info li;
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900650 int ret, i;
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000651
652 /* Allocate the private data and the DAI link array */
653 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
654 if (!priv)
655 return -ENOMEM;
656
Kuninori Morimotodd98fbc2018-12-20 10:46:05 +0900657 card = graph_priv_to_card(priv);
658 card->owner = THIS_MODULE;
659 card->dev = dev;
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900660 card->dapm_widgets = graph_dapm_widgets;
661 card->num_dapm_widgets = ARRAY_SIZE(graph_dapm_widgets);
662 card->probe = graph_card_probe;
Kuninori Morimotodd98fbc2018-12-20 10:46:05 +0900663
Kuninori Morimoto1e4771a2018-12-20 10:45:59 +0900664 memset(&li, 0, sizeof(li));
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900665 graph_get_dais_count(priv, &li);
Kuninori Morimoto1e4771a2018-12-20 10:45:59 +0900666 if (!li.link || !li.dais)
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000667 return -EINVAL;
668
Kuninori Morimoto1e4771a2018-12-20 10:45:59 +0900669 dai_props = devm_kcalloc(dev, li.link, sizeof(*dai_props), GFP_KERNEL);
670 dai_link = devm_kcalloc(dev, li.link, sizeof(*dai_link), GFP_KERNEL);
671 dais = devm_kcalloc(dev, li.dais, sizeof(*dais), GFP_KERNEL);
672 cconf = devm_kcalloc(dev, li.conf, sizeof(*cconf), GFP_KERNEL);
Kuninori Morimoto0e3460b2018-11-30 02:07:48 +0000673 if (!dai_props || !dai_link || !dais)
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000674 return -ENOMEM;
675
Kuninori Morimoto8e6746d2018-08-31 03:09:05 +0000676 /*
677 * Use snd_soc_dai_link_component instead of legacy style
678 * It is codec only. but cpu/platform will be supported in the future.
679 * see
680 * soc-core.c :: snd_soc_init_multicodec()
681 */
Kuninori Morimoto1e4771a2018-12-20 10:45:59 +0900682 for (i = 0; i < li.link; i++) {
Kuninori Morimoto8e6746d2018-08-31 03:09:05 +0000683 dai_link[i].codecs = &dai_props[i].codecs;
684 dai_link[i].num_codecs = 1;
Kuninori Morimoto910fdca2019-01-21 09:32:32 +0900685 dai_link[i].platforms = &dai_props[i].platforms;
686 dai_link[i].num_platforms = 1;
Kuninori Morimoto8e6746d2018-08-31 03:09:05 +0000687 }
688
Shawn Guof9869072017-06-29 21:26:38 +0800689 priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW);
690 if (IS_ERR(priv->pa_gpio)) {
691 ret = PTR_ERR(priv->pa_gpio);
692 dev_err(dev, "failed to get amplifier gpio: %d\n", ret);
693 return ret;
694 }
695
Kuninori Morimotodd98fbc2018-12-20 10:46:05 +0900696 priv->dai_props = dai_props;
697 priv->dai_link = dai_link;
698 priv->dais = dais;
699 priv->codec_conf = cconf;
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000700
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900701 card->dai_link = dai_link;
Kuninori Morimoto1e4771a2018-12-20 10:45:59 +0900702 card->num_links = li.link;
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900703 card->codec_conf = cconf;
Kuninori Morimoto1e4771a2018-12-20 10:45:59 +0900704 card->num_configs = li.conf;
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000705
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900706 ret = graph_parse_of(priv);
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000707 if (ret < 0) {
708 if (ret != -EPROBE_DEFER)
709 dev_err(dev, "parse error %d\n", ret);
710 goto err;
711 }
712
713 snd_soc_card_set_drvdata(card, priv);
714
715 ret = devm_snd_soc_register_card(dev, card);
Kuninori Morimotoecea9312017-05-19 00:58:00 +0000716 if (ret < 0)
717 goto err;
718
719 return 0;
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000720err:
721 asoc_simple_card_clean_reference(card);
722
723 return ret;
724}
725
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900726static int graph_remove(struct platform_device *pdev)
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000727{
728 struct snd_soc_card *card = platform_get_drvdata(pdev);
729
730 return asoc_simple_card_clean_reference(card);
731}
732
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900733static const struct of_device_id graph_of_match[] = {
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000734 { .compatible = "audio-graph-card", },
Kuninori Morimotoae3cb572018-12-14 11:32:25 +0900735 { .compatible = "audio-graph-scu-card", },
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000736 {},
737};
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900738MODULE_DEVICE_TABLE(of, graph_of_match);
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000739
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900740static struct platform_driver graph_card = {
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000741 .driver = {
742 .name = "asoc-audio-graph-card",
Kuninori Morimoto7b828a32017-08-22 04:56:44 +0000743 .pm = &snd_soc_pm_ops,
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900744 .of_match_table = graph_of_match,
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000745 },
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900746 .probe = graph_probe,
747 .remove = graph_remove,
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000748};
Kuninori Morimoto97fe6ca2018-12-20 10:46:33 +0900749module_platform_driver(graph_card);
Kuninori Morimoto2692c1c2017-04-20 01:36:08 +0000750
751MODULE_ALIAS("platform:asoc-audio-graph-card");
752MODULE_LICENSE("GPL v2");
753MODULE_DESCRIPTION("ASoC Audio Graph Sound Card");
754MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");