blob: 52048069b25a37b96ce774d5fffe970bcc02a171 [file] [log] [blame]
Kuninori Morimotod5734542018-07-02 06:30:28 +00001// SPDX-License-Identifier: GPL-2.0
2//
3// ASoC simple sound card support
4//
5// Copyright (C) 2012 Renesas Solutions Corp.
6// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
7
Kuninori Morimotofa558c22013-11-20 15:25:02 +09008#include <linux/clk.h>
Xiubo Li6ff62ee2014-02-14 09:34:36 +08009#include <linux/device.h>
Kuninori Morimotof2390882012-04-08 21:17:50 -070010#include <linux/module.h>
Kuninori Morimotofa558c22013-11-20 15:25:02 +090011#include <linux/of.h>
Kuninori Morimotof2390882012-04-08 21:17:50 -070012#include <linux/platform_device.h>
Xiubo Lica919fe2014-01-14 12:35:32 +080013#include <linux/string.h>
Kuninori Morimotof2390882012-04-08 21:17:50 -070014#include <sound/simple_card.h>
Xiubo Li6ff62ee2014-02-14 09:34:36 +080015#include <sound/soc-dai.h>
16#include <sound/soc.h>
Kuninori Morimotof2390882012-04-08 21:17:50 -070017
Jean-Francois Moine45fce592014-01-15 16:51:56 +010018struct simple_card_data {
19 struct snd_soc_card snd_card;
Jean-Francois Moinecf7dc232014-03-20 10:52:41 +010020 struct simple_dai_props {
Kuninori Morimoto4fb7f4d2018-12-04 08:19:43 +000021 struct asoc_simple_dai *cpu_dai;
22 struct asoc_simple_dai *codec_dai;
Kuninori Morimoto710af912018-08-31 03:08:24 +000023 struct snd_soc_dai_link_component codecs; /* single codec */
Kuninori Morimotoe58f41e2018-08-31 03:10:33 +000024 struct snd_soc_dai_link_component platform;
Kuninori Morimotoda215352018-12-14 11:35:10 +090025 struct asoc_simple_card_data adata;
26 struct snd_soc_codec_conf *codec_conf;
Arnaud Pouliquen85a4bfd2015-06-05 10:19:05 +020027 unsigned int mclk_fs;
Jean-Francois Moinecf7dc232014-03-20 10:52:41 +010028 } *dai_props;
Kuninori Morimoto9eac3612016-05-31 08:59:46 +000029 struct asoc_simple_jack hp_jack;
30 struct asoc_simple_jack mic_jack;
Kuninori Morimotob0133d92016-08-26 03:10:25 +000031 struct snd_soc_dai_link *dai_link;
Kuninori Morimoto4fb7f4d2018-12-04 08:19:43 +000032 struct asoc_simple_dai *dais;
Kuninori Morimotoda215352018-12-14 11:35:10 +090033 struct snd_soc_codec_conf *codec_conf;
Jean-Francois Moine45fce592014-01-15 16:51:56 +010034};
35
Kuninori Morimoto5be50952017-03-15 04:44:00 +000036#define simple_priv_to_card(priv) (&(priv)->snd_card)
Kuninori Morimoto7e3353d2016-08-26 03:06:23 +000037#define simple_priv_to_props(priv, i) ((priv)->dai_props + (i))
Kuninori Morimoto5be50952017-03-15 04:44:00 +000038#define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev)
39#define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i))
Kuninori Morimotof531913f2014-09-09 21:37:57 -070040
Kuninori Morimoto44c16af2016-08-08 06:02:07 +000041#define DAI "sound-dai"
42#define CELL "#sound-dai-cells"
Kuninori Morimoto548563f2016-05-31 08:59:01 +000043#define PREFIX "simple-audio-card,"
44
Jyri Sarhaf9911802015-01-13 21:16:34 +020045static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
46{
47 struct snd_soc_pcm_runtime *rtd = substream->private_data;
48 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
49 struct simple_dai_props *dai_props =
Kuninori Morimotoc9a23ea2016-08-26 03:06:51 +000050 simple_priv_to_props(priv, rtd->num);
Jyri Sarhaf9911802015-01-13 21:16:34 +020051 int ret;
52
Kuninori Morimoto4fb7f4d2018-12-04 08:19:43 +000053 ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
Jyri Sarhaf9911802015-01-13 21:16:34 +020054 if (ret)
55 return ret;
Kuninori Morimoto387f5822016-08-26 03:07:59 +000056
Kuninori Morimoto4fb7f4d2018-12-04 08:19:43 +000057 ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
Jyri Sarhaf9911802015-01-13 21:16:34 +020058 if (ret)
Kuninori Morimoto4fb7f4d2018-12-04 08:19:43 +000059 asoc_simple_card_clk_disable(dai_props->cpu_dai);
Jyri Sarhaf9911802015-01-13 21:16:34 +020060
61 return ret;
62}
63
64static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
65{
66 struct snd_soc_pcm_runtime *rtd = substream->private_data;
67 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
68 struct simple_dai_props *dai_props =
Kuninori Morimotoc9a23ea2016-08-26 03:06:51 +000069 simple_priv_to_props(priv, rtd->num);
Jyri Sarhaf9911802015-01-13 21:16:34 +020070
Kuninori Morimoto4fb7f4d2018-12-04 08:19:43 +000071 asoc_simple_card_clk_disable(dai_props->cpu_dai);
Jyri Sarhaf9911802015-01-13 21:16:34 +020072
Kuninori Morimoto4fb7f4d2018-12-04 08:19:43 +000073 asoc_simple_card_clk_disable(dai_props->codec_dai);
Jyri Sarhaf9911802015-01-13 21:16:34 +020074}
75
Daniel Macke9be4ff2018-05-30 21:45:56 +020076static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai,
77 unsigned long rate)
78{
Kuninori Morimotoda215352018-12-14 11:35:10 +090079 if (!simple_dai)
80 return 0;
81
Daniel Macke9be4ff2018-05-30 21:45:56 +020082 if (!simple_dai->clk)
83 return 0;
84
85 if (clk_get_rate(simple_dai->clk) == rate)
86 return 0;
87
88 return clk_set_rate(simple_dai->clk, rate);
89}
90
Andrew Lunn2942a0e2014-05-22 17:31:49 +020091static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
92 struct snd_pcm_hw_params *params)
93{
94 struct snd_soc_pcm_runtime *rtd = substream->private_data;
95 struct snd_soc_dai *codec_dai = rtd->codec_dai;
Arnaud Pouliquene2257972015-06-05 10:19:06 +020096 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Andrew Lunn2942a0e2014-05-22 17:31:49 +020097 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
Kuninori Morimotoc9a23ea2016-08-26 03:06:51 +000098 struct simple_dai_props *dai_props =
99 simple_priv_to_props(priv, rtd->num);
Arnaud Pouliquen85a4bfd2015-06-05 10:19:05 +0200100 unsigned int mclk, mclk_fs = 0;
Andrew Lunn2942a0e2014-05-22 17:31:49 +0200101 int ret = 0;
102
Kuninori Morimoto79e83492018-12-14 11:35:15 +0900103 if (dai_props->mclk_fs)
Arnaud Pouliquen85a4bfd2015-06-05 10:19:05 +0200104 mclk_fs = dai_props->mclk_fs;
105
106 if (mclk_fs) {
107 mclk = params_rate(params) * mclk_fs;
Daniel Macke9be4ff2018-05-30 21:45:56 +0200108
Kuninori Morimoto4fb7f4d2018-12-04 08:19:43 +0000109 ret = asoc_simple_set_clk_rate(dai_props->codec_dai, mclk);
Daniel Macke9be4ff2018-05-30 21:45:56 +0200110 if (ret < 0)
111 return ret;
112
Kuninori Morimoto4fb7f4d2018-12-04 08:19:43 +0000113 ret = asoc_simple_set_clk_rate(dai_props->cpu_dai, mclk);
Daniel Macke9be4ff2018-05-30 21:45:56 +0200114 if (ret < 0)
115 return ret;
116
Andrew Lunn2942a0e2014-05-22 17:31:49 +0200117 ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
118 SND_SOC_CLOCK_IN);
Arnaud Pouliquene2257972015-06-05 10:19:06 +0200119 if (ret && ret != -ENOTSUPP)
120 goto err;
121
122 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
123 SND_SOC_CLOCK_OUT);
124 if (ret && ret != -ENOTSUPP)
125 goto err;
Andrew Lunn2942a0e2014-05-22 17:31:49 +0200126 }
Aaro Koskinenee43a1a2016-01-24 00:36:40 +0200127 return 0;
Arnaud Pouliquene2257972015-06-05 10:19:06 +0200128err:
Andrew Lunn2942a0e2014-05-22 17:31:49 +0200129 return ret;
130}
131
Julia Lawall9b6fdef2016-10-15 16:55:49 +0200132static const struct snd_soc_ops asoc_simple_card_ops = {
Jyri Sarhaf9911802015-01-13 21:16:34 +0200133 .startup = asoc_simple_card_startup,
134 .shutdown = asoc_simple_card_shutdown,
Andrew Lunn2942a0e2014-05-22 17:31:49 +0200135 .hw_params = asoc_simple_card_hw_params,
136};
137
Kuninori Morimotof2390882012-04-08 21:17:50 -0700138static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
139{
Nicolin Chen781cbeb2014-04-24 19:14:00 +0800140 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
Kuninori Morimoto4fb7f4d2018-12-04 08:19:43 +0000141 struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
Mengdong Lin1a497982015-11-18 02:34:11 -0500142 int ret;
Kuninori Morimotof2390882012-04-08 21:17:50 -0700143
Kuninori Morimoto4fb7f4d2018-12-04 08:19:43 +0000144 ret = asoc_simple_card_init_dai(rtd->codec_dai,
145 dai_props->codec_dai);
Kuninori Morimotoa4a29922013-01-10 16:49:11 -0800146 if (ret < 0)
147 return ret;
Kuninori Morimotof2390882012-04-08 21:17:50 -0700148
Kuninori Morimoto4fb7f4d2018-12-04 08:19:43 +0000149 ret = asoc_simple_card_init_dai(rtd->cpu_dai,
150 dai_props->cpu_dai);
Kuninori Morimotoa4a29922013-01-10 16:49:11 -0800151 if (ret < 0)
152 return ret;
Kuninori Morimotof2390882012-04-08 21:17:50 -0700153
154 return 0;
155}
156
Kuninori Morimotoda215352018-12-14 11:35:10 +0900157static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
158 struct snd_pcm_hw_params *params)
159{
160 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
161 struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
162
163 asoc_simple_card_convert_fixup(&dai_props->adata, params);
164
Kuninori Morimotoda215352018-12-14 11:35:10 +0900165 return 0;
166}
167
Kuninori Morimoto7e5e1f82018-12-20 10:46:42 +0900168static void asoc_simple_card_get_conversion(struct device *dev,
169 struct device_node *np,
170 struct asoc_simple_card_data *adata)
171{
172 struct device_node *top = dev->of_node;
173 struct device_node *node = of_get_parent(np);
174
175 asoc_simple_card_parse_convert(dev, top, PREFIX, adata);
176 asoc_simple_card_parse_convert(dev, node, PREFIX, adata);
177 asoc_simple_card_parse_convert(dev, node, NULL, adata);
178 asoc_simple_card_parse_convert(dev, np, NULL, adata);
179
180 of_node_put(node);
181}
182
Kuninori Morimoto79e83492018-12-14 11:35:15 +0900183static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top,
184 struct device_node *node,
Kuninori Morimotoda215352018-12-14 11:35:10 +0900185 struct device_node *np,
186 struct device_node *codec,
187 struct simple_card_data *priv,
188 int *dai_idx, int link_idx,
189 int *conf_idx, int is_fe,
190 bool is_top_level_node)
191{
192 struct device *dev = simple_priv_to_dev(priv);
193 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
194 struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
Kuninori Morimotoda215352018-12-14 11:35:10 +0900195 struct asoc_simple_dai *dai;
Kuninori Morimotocfc652a2018-12-14 11:35:24 +0900196 struct snd_soc_dai_link_component *codecs = dai_link->codecs;
197
Kuninori Morimoto79e83492018-12-14 11:35:15 +0900198 char prop[128];
Kuninori Morimotoda215352018-12-14 11:35:10 +0900199 char *prefix = "";
200 int ret;
201
202 /* For single DAI link & old style of DT node */
203 if (is_top_level_node)
204 prefix = PREFIX;
205
206 if (is_fe) {
207 int is_single_links = 0;
Kuninori Morimotoda215352018-12-14 11:35:10 +0900208
209 /* BE is dummy */
Kuninori Morimotoda215352018-12-14 11:35:10 +0900210 codecs->of_node = NULL;
211 codecs->dai_name = "snd-soc-dummy-dai";
212 codecs->name = "snd-soc-dummy";
213
214 /* FE settings */
215 dai_link->dynamic = 1;
216 dai_link->dpcm_merged_format = 1;
217
218 dai =
219 dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
220
221 ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL,
222 &is_single_links);
223 if (ret)
224 return ret;
225
226 ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai);
227 if (ret < 0)
228 return ret;
229
230 ret = asoc_simple_card_set_dailink_name(dev, dai_link,
231 "fe.%s",
232 dai_link->cpu_dai_name);
233 if (ret < 0)
234 return ret;
235
236 asoc_simple_card_canonicalize_cpu(dai_link, is_single_links);
237 } else {
238 struct snd_soc_codec_conf *cconf;
239
240 /* FE is dummy */
241 dai_link->cpu_of_node = NULL;
242 dai_link->cpu_dai_name = "snd-soc-dummy-dai";
243 dai_link->cpu_name = "snd-soc-dummy";
244
245 /* BE settings */
246 dai_link->no_pcm = 1;
247 dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup;
248
249 dai =
250 dai_props->codec_dai = &priv->dais[(*dai_idx)++];
251
252 cconf =
253 dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++];
254
255 ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL);
256 if (ret < 0)
257 return ret;
258
259 ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai);
260 if (ret < 0)
261 return ret;
262
263 ret = asoc_simple_card_set_dailink_name(dev, dai_link,
264 "be.%s",
Kuninori Morimotocfc652a2018-12-14 11:35:24 +0900265 codecs->dai_name);
Kuninori Morimotoda215352018-12-14 11:35:10 +0900266 if (ret < 0)
267 return ret;
268
269 /* check "prefix" from top node */
Kuninori Morimotocfc652a2018-12-14 11:35:24 +0900270 snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
Kuninori Morimotoda215352018-12-14 11:35:10 +0900271 PREFIX "prefix");
Kuninori Morimotocfc652a2018-12-14 11:35:24 +0900272 snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node,
273 "prefix");
274 snd_soc_of_parse_node_prefix(np, cconf, codecs->of_node,
275 "prefix");
Kuninori Morimotoda215352018-12-14 11:35:10 +0900276 }
277
Kuninori Morimoto7e5e1f82018-12-20 10:46:42 +0900278 asoc_simple_card_get_conversion(dev, np, &dai_props->adata);
Kuninori Morimotoda215352018-12-14 11:35:10 +0900279
280 ret = asoc_simple_card_of_parse_tdm(np, dai);
281 if (ret)
282 return ret;
283
284 ret = asoc_simple_card_canonicalize_dailink(dai_link);
285 if (ret < 0)
286 return ret;
287
Kuninori Morimoto79e83492018-12-14 11:35:15 +0900288 snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
289 of_property_read_u32(top, PREFIX "mclk-fs", &dai_props->mclk_fs);
290 of_property_read_u32(node, prop, &dai_props->mclk_fs);
291 of_property_read_u32(np, prop, &dai_props->mclk_fs);
Kuninori Morimotoda215352018-12-14 11:35:10 +0900292
293 ret = asoc_simple_card_parse_daifmt(dev, node, codec,
294 prefix, &dai_link->dai_fmt);
295 if (ret < 0)
296 return ret;
297
298 dai_link->dpcm_playback = 1;
299 dai_link->dpcm_capture = 1;
300 dai_link->ops = &asoc_simple_card_ops;
301 dai_link->init = asoc_simple_card_dai_init;
302
303 return 0;
304}
305
Kuninori Morimoto79e83492018-12-14 11:35:15 +0900306static int asoc_simple_card_dai_link_of(struct device_node *top,
307 struct device_node *node,
Kuninori Morimotof531913f2014-09-09 21:37:57 -0700308 struct simple_card_data *priv,
Kuninori Morimoto4fb7f4d2018-12-04 08:19:43 +0000309 int *dai_idx, int link_idx,
Kuninori Morimoto2d82eeb2014-08-27 20:07:46 -0700310 bool is_top_level_node)
Jean-Francois Moine6a91a17bd2014-03-20 11:49:55 +0100311{
Kuninori Morimotof531913f2014-09-09 21:37:57 -0700312 struct device *dev = simple_priv_to_dev(priv);
Kuninori Morimoto4fb7f4d2018-12-04 08:19:43 +0000313 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
314 struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
315 struct asoc_simple_dai *cpu_dai;
316 struct asoc_simple_dai *codec_dai;
Kuninori Morimoto1b5721b2014-10-27 18:04:52 -0700317 struct device_node *cpu = NULL;
Jun Niee0ae2252015-04-29 18:11:07 +0800318 struct device_node *plat = NULL;
Kuninori Morimoto1b5721b2014-10-27 18:04:52 -0700319 struct device_node *codec = NULL;
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200320 char prop[128];
321 char *prefix = "";
Kuninori Morimoto44c16af2016-08-08 06:02:07 +0000322 int ret, single_cpu;
Jean-Francois Moine6a91a17bd2014-03-20 11:49:55 +0100323
Xiubo Li20804372014-09-03 10:23:39 +0800324 /* For single DAI link & old style of DT node */
Jyri Sarha64872212014-04-24 19:42:00 +0300325 if (is_top_level_node)
Kuninori Morimoto548563f2016-05-31 08:59:01 +0000326 prefix = PREFIX;
Jean-Francois Moine6a91a17bd2014-03-20 11:49:55 +0100327
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200328 snprintf(prop, sizeof(prop), "%scpu", prefix);
Kuninori Morimoto1b5721b2014-10-27 18:04:52 -0700329 cpu = of_get_child_by_name(node, prop);
330
Julian Scheel7ac45d12017-05-24 12:28:23 +0200331 if (!cpu) {
332 ret = -EINVAL;
333 dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
334 goto dai_link_of_err;
335 }
336
Jun Niee0ae2252015-04-29 18:11:07 +0800337 snprintf(prop, sizeof(prop), "%splat", prefix);
338 plat = of_get_child_by_name(node, prop);
339
Kuninori Morimoto1b5721b2014-10-27 18:04:52 -0700340 snprintf(prop, sizeof(prop), "%scodec", prefix);
341 codec = of_get_child_by_name(node, prop);
342
Julian Scheel7ac45d12017-05-24 12:28:23 +0200343 if (!codec) {
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200344 ret = -EINVAL;
Nicolin Chen966b8062014-04-24 19:13:59 +0800345 dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200346 goto dai_link_of_err;
Jean-Francois Moine6a91a17bd2014-03-20 11:49:55 +0100347 }
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200348
Kuninori Morimoto4fb7f4d2018-12-04 08:19:43 +0000349 cpu_dai =
350 dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
351 codec_dai =
352 dai_props->codec_dai = &priv->dais[(*dai_idx)++];
353
Kuninori Morimotocecdef32016-06-30 06:02:46 +0000354 ret = asoc_simple_card_parse_daifmt(dev, node, codec,
355 prefix, &dai_link->dai_fmt);
Kuninori Morimoto1b5721b2014-10-27 18:04:52 -0700356 if (ret < 0)
357 goto dai_link_of_err;
358
Kuninori Morimoto79e83492018-12-14 11:35:15 +0900359 snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
360 of_property_read_u32(top, PREFIX "mclk-fs", &dai_props->mclk_fs);
361 of_property_read_u32(node, prop, &dai_props->mclk_fs);
362 of_property_read_u32(cpu, prop, &dai_props->mclk_fs);
363 of_property_read_u32(codec, prop, &dai_props->mclk_fs);
Arnaud Pouliquen85a4bfd2015-06-05 10:19:05 +0200364
Kuninori Morimoto44c16af2016-08-08 06:02:07 +0000365 ret = asoc_simple_card_parse_cpu(cpu, dai_link,
366 DAI, CELL, &single_cpu);
367 if (ret < 0)
368 goto dai_link_of_err;
369
370 ret = asoc_simple_card_parse_codec(codec, dai_link, DAI, CELL);
371 if (ret < 0)
372 goto dai_link_of_err;
373
374 ret = asoc_simple_card_parse_platform(plat, dai_link, DAI, CELL);
375 if (ret < 0)
376 goto dai_link_of_err;
377
Kuninori Morimotob93d2cf2017-06-14 00:34:53 +0000378 ret = asoc_simple_card_of_parse_tdm(cpu, cpu_dai);
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200379 if (ret < 0)
380 goto dai_link_of_err;
381
Kuninori Morimotob93d2cf2017-06-14 00:34:53 +0000382 ret = asoc_simple_card_of_parse_tdm(codec, codec_dai);
Kuninori Morimoto5fb9cb12016-05-20 09:40:41 +0000383 if (ret < 0)
384 goto dai_link_of_err;
385
Kuninori Morimotoe984fd62017-01-23 07:29:42 +0000386 ret = asoc_simple_card_parse_clk_cpu(dev, cpu, dai_link, cpu_dai);
Kuninori Morimoto28abd992016-07-19 02:53:13 +0000387 if (ret < 0)
388 goto dai_link_of_err;
389
Kuninori Morimotoe984fd62017-01-23 07:29:42 +0000390 ret = asoc_simple_card_parse_clk_codec(dev, codec, dai_link, codec_dai);
Kuninori Morimoto28abd992016-07-19 02:53:13 +0000391 if (ret < 0)
392 goto dai_link_of_err;
393
Kuninori Morimotoc9583742016-08-09 05:50:02 +0000394 ret = asoc_simple_card_canonicalize_dailink(dai_link);
395 if (ret < 0)
Nicolin Chen781cbeb2014-04-24 19:14:00 +0800396 goto dai_link_of_err;
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200397
Kuninori Morimoto2e8d1c72016-07-11 23:57:34 +0000398 ret = asoc_simple_card_set_dailink_name(dev, dai_link,
399 "%s-%s",
400 dai_link->cpu_dai_name,
Kuninori Morimoto710af912018-08-31 03:08:24 +0000401 dai_link->codecs->dai_name);
Kuninori Morimoto2e8d1c72016-07-11 23:57:34 +0000402 if (ret < 0)
Vishal Thanki31f30322015-03-03 18:59:00 +0530403 goto dai_link_of_err;
Vishal Thanki31f30322015-03-03 18:59:00 +0530404
Andrew Lunn2942a0e2014-05-22 17:31:49 +0200405 dai_link->ops = &asoc_simple_card_ops;
Kuninori Morimotoa5960bd2014-08-27 20:08:27 -0700406 dai_link->init = asoc_simple_card_dai_init;
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200407
Kuninori Morimoto16f1de62016-08-10 02:20:43 +0000408 asoc_simple_card_canonicalize_cpu(dai_link, single_cpu);
Kuninori Morimoto179949b2014-08-27 20:08:06 -0700409
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200410dai_link_of_err:
Kuninori Morimoto1b5721b2014-10-27 18:04:52 -0700411 of_node_put(cpu);
412 of_node_put(codec);
413
Jean-Francois Moine6a91a17bd2014-03-20 11:49:55 +0100414 return ret;
415}
416
Nikita Yushchenko899a2472016-09-26 12:56:51 +0300417static int asoc_simple_card_parse_aux_devs(struct device_node *node,
418 struct simple_card_data *priv)
419{
420 struct device *dev = simple_priv_to_dev(priv);
421 struct device_node *aux_node;
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000422 struct snd_soc_card *card = simple_priv_to_card(priv);
Nikita Yushchenko899a2472016-09-26 12:56:51 +0300423 int i, n, len;
424
425 if (!of_find_property(node, PREFIX "aux-devs", &len))
426 return 0; /* Ok to have no aux-devs */
427
428 n = len / sizeof(__be32);
429 if (n <= 0)
430 return -EINVAL;
431
Kees Cooka86854d2018-06-12 14:07:58 -0700432 card->aux_dev = devm_kcalloc(dev,
433 n, sizeof(*card->aux_dev), GFP_KERNEL);
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000434 if (!card->aux_dev)
Nikita Yushchenko899a2472016-09-26 12:56:51 +0300435 return -ENOMEM;
436
437 for (i = 0; i < n; i++) {
438 aux_node = of_parse_phandle(node, PREFIX "aux-devs", i);
439 if (!aux_node)
440 return -EINVAL;
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000441 card->aux_dev[i].codec_of_node = aux_node;
Nikita Yushchenko899a2472016-09-26 12:56:51 +0300442 }
443
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000444 card->num_aux_devs = n;
Nikita Yushchenko899a2472016-09-26 12:56:51 +0300445 return 0;
446}
447
Kuninori Morimotod2fdcc22017-06-07 00:37:05 +0000448static int asoc_simple_card_parse_of(struct simple_card_data *priv)
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900449{
Kuninori Morimotof531913f2014-09-09 21:37:57 -0700450 struct device *dev = simple_priv_to_dev(priv);
Kuninori Morimotoda215352018-12-14 11:35:10 +0900451 struct device_node *top = dev->of_node;
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000452 struct snd_soc_card *card = simple_priv_to_card(priv);
Kuninori Morimotoda215352018-12-14 11:35:10 +0900453 struct device_node *node;
454 struct device_node *np;
455 struct device_node *codec;
456 bool is_fe;
457 int ret, loop;
458 int dai_idx, link_idx, conf_idx;
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900459
Kuninori Morimotoda215352018-12-14 11:35:10 +0900460 if (!top)
Xiubo Li20804372014-09-03 10:23:39 +0800461 return -EINVAL;
462
Kuninori Morimotofa2760dd2017-06-16 01:39:11 +0000463 ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
464 if (ret < 0)
Kuninori Morimotoda215352018-12-14 11:35:10 +0900465 return ret;
Xiubo Li9d681f52014-02-08 15:59:53 +0800466
Kuninori Morimoto33404f32018-11-21 02:11:13 +0000467 ret = asoc_simple_card_of_parse_routing(card, PREFIX);
Kuninori Morimoto1fdb5d22017-06-15 00:25:17 +0000468 if (ret < 0)
Kuninori Morimotoda215352018-12-14 11:35:10 +0900469 return ret;
Xiubo Lid4c22092013-12-23 12:57:01 +0800470
Xiubo Li20804372014-09-03 10:23:39 +0800471 /* Single/Muti DAI link(s) & New style of DT node */
Kuninori Morimotoda215352018-12-14 11:35:10 +0900472 loop = 1;
473 link_idx = 0;
474 dai_idx = 0;
475 conf_idx = 0;
476 node = of_get_child_by_name(top, PREFIX "dai-link");
477 if (!node) {
478 node = dev->of_node;
479 loop = 0;
Jean-Francois Moinee512e002014-03-11 10:03:40 +0100480 }
Xiubo Lidd41e0c2013-12-20 14:39:50 +0800481
Kuninori Morimotoda215352018-12-14 11:35:10 +0900482 do {
483 /* DPCM */
484 if (of_get_child_count(node) > 2) {
485 for_each_child_of_node(node, np) {
486 codec = of_get_child_by_name(node,
487 loop ? "codec" :
488 PREFIX "codec");
489 if (!codec)
490 return -ENODEV;
491
492 is_fe = (np != codec);
493
494 ret = asoc_simple_card_dai_link_of_dpcm(
Kuninori Morimoto79e83492018-12-14 11:35:15 +0900495 top, node, np, codec, priv,
Kuninori Morimotoda215352018-12-14 11:35:10 +0900496 &dai_idx, link_idx++, &conf_idx,
497 is_fe, !loop);
498 }
499 } else {
500 ret = asoc_simple_card_dai_link_of(
Kuninori Morimoto79e83492018-12-14 11:35:15 +0900501 top, node, priv,
Kuninori Morimotoda215352018-12-14 11:35:10 +0900502 &dai_idx, link_idx++, !loop);
503 }
504 if (ret < 0)
505 return ret;
506
507 node = of_get_next_child(top, node);
508 } while (loop && node);
509
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000510 ret = asoc_simple_card_parse_card_name(card, PREFIX);
Nikita Yushchenko899a2472016-09-26 12:56:51 +0300511 if (ret < 0)
Kuninori Morimotoda215352018-12-14 11:35:10 +0900512 return ret;
Nikita Yushchenko899a2472016-09-26 12:56:51 +0300513
Kuninori Morimotoda215352018-12-14 11:35:10 +0900514 ret = asoc_simple_card_parse_aux_devs(top, priv);
Kuninori Morimotoa03b0542016-08-26 03:05:16 +0000515
516 return ret;
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900517}
518
Kuninori Morimotoda215352018-12-14 11:35:10 +0900519static void asoc_simple_card_get_dais_count(struct device *dev,
520 int *link_num,
521 int *dais_num,
522 int *ccnf_num)
523{
524 struct device_node *top = dev->of_node;
525 struct device_node *node;
526 int loop;
527 int num;
528
529 /*
530 * link_num : number of links.
531 * CPU-Codec / CPU-dummy / dummy-Codec
532 * dais_num : number of DAIs
533 * ccnf_num : number of codec_conf
534 * same number for "dummy-Codec"
535 *
536 * ex1)
537 * CPU0 --- Codec0 link : 5
538 * CPU1 --- Codec1 dais : 7
539 * CPU2 -/ ccnf : 1
540 * CPU3 --- Codec2
541 *
542 * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
543 * => 7 DAIs = 4xCPU + 3xCodec
544 * => 1 ccnf = 1xdummy-Codec
545 *
546 * ex2)
547 * CPU0 --- Codec0 link : 5
548 * CPU1 --- Codec1 dais : 6
549 * CPU2 -/ ccnf : 1
550 * CPU3 -/
551 *
552 * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
553 * => 6 DAIs = 4xCPU + 2xCodec
554 * => 1 ccnf = 1xdummy-Codec
555 *
556 * ex3)
557 * CPU0 --- Codec0 link : 6
558 * CPU1 -/ dais : 6
559 * CPU2 --- Codec1 ccnf : 2
560 * CPU3 -/
561 *
562 * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
563 * => 6 DAIs = 4xCPU + 2xCodec
564 * => 2 ccnf = 2xdummy-Codec
565 */
566 if (!top) {
567 (*link_num) = 1;
568 (*dais_num) = 2;
569 (*ccnf_num) = 0;
570 return;
571 }
572
573 loop = 1;
574 node = of_get_child_by_name(top, PREFIX "dai-link");
575 if (!node) {
576 node = top;
577 loop = 0;
578 }
579
580 do {
581 num = of_get_child_count(node);
582 (*dais_num) += num;
583 if (num > 2) {
584 (*link_num) += num;
585 (*ccnf_num)++;
586 } else {
587 (*link_num)++;
588 }
589 node = of_get_next_child(top, node);
590 } while (loop && node);
591}
592
Katsuhiro Suzuki8d1bd112018-06-11 17:32:13 +0900593static int asoc_simple_soc_card_probe(struct snd_soc_card *card)
594{
595 struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
596 int ret;
597
598 ret = asoc_simple_card_init_hp(card, &priv->hp_jack, PREFIX);
599 if (ret < 0)
600 return ret;
601
602 ret = asoc_simple_card_init_mic(card, &priv->mic_jack, PREFIX);
603 if (ret < 0)
604 return ret;
605
606 return 0;
607}
608
Kuninori Morimotof2390882012-04-08 21:17:50 -0700609static int asoc_simple_card_probe(struct platform_device *pdev)
610{
Jean-Francois Moine45fce592014-01-15 16:51:56 +0100611 struct simple_card_data *priv;
Jean-Francois Moine5ca8ba42014-01-15 16:51:45 +0100612 struct snd_soc_dai_link *dai_link;
Kuninori Morimotob0133d92016-08-26 03:10:25 +0000613 struct simple_dai_props *dai_props;
Kuninori Morimoto4fb7f4d2018-12-04 08:19:43 +0000614 struct asoc_simple_dai *dais;
Kuninori Morimotof89983e2012-12-25 22:52:33 -0800615 struct device *dev = &pdev->dev;
Kuninori Morimotodcee9bfe2017-03-15 04:43:21 +0000616 struct device_node *np = dev->of_node;
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000617 struct snd_soc_card *card;
Kuninori Morimotoda215352018-12-14 11:35:10 +0900618 struct snd_soc_codec_conf *cconf;
619 int lnum = 0, dnum = 0, cnum = 0;
620 int ret, i;
Kuninori Morimotof2390882012-04-08 21:17:50 -0700621
Xiubo Li0dd4fc32014-09-10 09:59:55 +0800622 /* Allocate the private data and the DAI link array */
Kuninori Morimotob0133d92016-08-26 03:10:25 +0000623 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
Jean-Francois Moineca65b492014-01-15 16:51:52 +0100624 if (!priv)
Xiubo Lica919fe2014-01-14 12:35:32 +0800625 return -ENOMEM;
626
Kuninori Morimotoda215352018-12-14 11:35:10 +0900627 asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum);
628 if (!lnum || !dnum)
629 return -EINVAL;
630
631 dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
632 dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL);
633 dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL);
634 cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL);
Kuninori Morimoto4fb7f4d2018-12-04 08:19:43 +0000635 if (!dai_props || !dai_link || !dais)
Kuninori Morimotob0133d92016-08-26 03:10:25 +0000636 return -ENOMEM;
637
Kuninori Morimoto710af912018-08-31 03:08:24 +0000638 /*
639 * Use snd_soc_dai_link_component instead of legacy style
640 * It is codec only. but cpu/platform will be supported in the future.
641 * see
642 * soc-core.c :: snd_soc_init_multicodec()
643 */
Kuninori Morimotoda215352018-12-14 11:35:10 +0900644 for (i = 0; i < lnum; i++) {
Kuninori Morimoto710af912018-08-31 03:08:24 +0000645 dai_link[i].codecs = &dai_props[i].codecs;
646 dai_link[i].num_codecs = 1;
Kuninori Morimotoe58f41e2018-08-31 03:10:33 +0000647 dai_link[i].platform = &dai_props[i].platform;
Kuninori Morimoto710af912018-08-31 03:08:24 +0000648 }
649
Kuninori Morimotob0133d92016-08-26 03:10:25 +0000650 priv->dai_props = dai_props;
651 priv->dai_link = dai_link;
Kuninori Morimoto4fb7f4d2018-12-04 08:19:43 +0000652 priv->dais = dais;
Kuninori Morimotoda215352018-12-14 11:35:10 +0900653 priv->codec_conf = cconf;
Kuninori Morimotob0133d92016-08-26 03:10:25 +0000654
Xiubo Li0dd4fc32014-09-10 09:59:55 +0800655 /* Init snd_soc_card */
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000656 card = simple_priv_to_card(priv);
657 card->owner = THIS_MODULE;
658 card->dev = dev;
659 card->dai_link = priv->dai_link;
Kuninori Morimotoda215352018-12-14 11:35:10 +0900660 card->num_links = lnum;
661 card->codec_conf = cconf;
662 card->num_configs = cnum;
Katsuhiro Suzuki8d1bd112018-06-11 17:32:13 +0900663 card->probe = asoc_simple_soc_card_probe;
Xiubo Lica919fe2014-01-14 12:35:32 +0800664
Jean-Francois Moine201a0ea2014-01-15 16:51:41 +0100665 if (np && of_device_is_available(np)) {
666
Kuninori Morimotod2fdcc22017-06-07 00:37:05 +0000667 ret = asoc_simple_card_parse_of(priv);
Xiubo Lica919fe2014-01-14 12:35:32 +0800668 if (ret < 0) {
669 if (ret != -EPROBE_DEFER)
670 dev_err(dev, "parse error %d\n", ret);
Jean-Francois Moinee512e002014-03-11 10:03:40 +0100671 goto err;
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900672 }
Jean-Francois Moine6a91a17bd2014-03-20 11:49:55 +0100673
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900674 } else {
Jean-Francois Moineca65b492014-01-15 16:51:52 +0100675 struct asoc_simple_card_info *cinfo;
Kuninori Morimoto710af912018-08-31 03:08:24 +0000676 struct snd_soc_dai_link_component *codecs;
Kuninori Morimotoe58f41e2018-08-31 03:10:33 +0000677 struct snd_soc_dai_link_component *platform;
Nathan Chancellor869858f2018-12-13 14:15:20 +0900678 int dai_idx = 0;
Jean-Francois Moineca65b492014-01-15 16:51:52 +0100679
680 cinfo = dev->platform_data;
681 if (!cinfo) {
Xiubo Li34787d0a2014-01-09 17:49:40 +0800682 dev_err(dev, "no info for asoc-simple-card\n");
683 return -EINVAL;
684 }
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900685
Nicolin Chen781cbeb2014-04-24 19:14:00 +0800686 if (!cinfo->name ||
687 !cinfo->codec_dai.name ||
688 !cinfo->codec ||
689 !cinfo->platform ||
Jean-Francois Moine7722f832014-01-15 16:51:33 +0100690 !cinfo->cpu_dai.name) {
691 dev_err(dev, "insufficient asoc_simple_card_info settings\n");
692 return -EINVAL;
693 }
Jean-Francois Moine2bee9912014-01-15 16:51:37 +0100694
Nathan Chancellor869858f2018-12-13 14:15:20 +0900695 dai_props->cpu_dai = &priv->dais[dai_idx++];
696 dai_props->codec_dai = &priv->dais[dai_idx++];
697
Kuninori Morimoto710af912018-08-31 03:08:24 +0000698 codecs = dai_link->codecs;
699 codecs->name = cinfo->codec;
700 codecs->dai_name = cinfo->codec_dai.name;
701
Kuninori Morimotoe58f41e2018-08-31 03:10:33 +0000702 platform = dai_link->platform;
703 platform->name = cinfo->platform;
704
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000705 card->name = (cinfo->card) ? cinfo->card : cinfo->name;
Jean-Francois Moine5ca8ba42014-01-15 16:51:45 +0100706 dai_link->name = cinfo->name;
707 dai_link->stream_name = cinfo->name;
Jean-Francois Moine52008472014-01-15 16:51:48 +0100708 dai_link->cpu_dai_name = cinfo->cpu_dai.name;
Lars-Peter Clausen1efb53a2015-03-24 01:07:08 +0000709 dai_link->dai_fmt = cinfo->daifmt;
Kuninori Morimotoa5960bd2014-08-27 20:08:27 -0700710 dai_link->init = asoc_simple_card_dai_init;
Nathan Chancellor869858f2018-12-13 14:15:20 +0900711 memcpy(priv->dai_props->cpu_dai, &cinfo->cpu_dai,
712 sizeof(*priv->dai_props->cpu_dai));
713 memcpy(priv->dai_props->codec_dai, &cinfo->codec_dai,
714 sizeof(*priv->dai_props->codec_dai));
Kuninori Morimotof2390882012-04-08 21:17:50 -0700715 }
716
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000717 snd_soc_card_set_drvdata(card, priv);
Xiubo Liba194a42014-01-13 17:08:08 +0800718
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000719 ret = devm_snd_soc_register_card(dev, card);
Kuninori Morimotoc6d112e2017-05-19 00:57:21 +0000720 if (ret < 0)
721 goto err;
722
723 return 0;
Jean-Francois Moinee512e002014-03-11 10:03:40 +0100724err:
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000725 asoc_simple_card_clean_reference(card);
Kuninori Morimoto387f5822016-08-26 03:07:59 +0000726
Jean-Francois Moinee512e002014-03-11 10:03:40 +0100727 return ret;
Kuninori Morimotof2390882012-04-08 21:17:50 -0700728}
729
Xiubo Lie3c4a282014-09-01 14:46:52 +0800730static int asoc_simple_card_remove(struct platform_device *pdev)
731{
Dylan Reid3fe24032014-10-01 14:25:20 -0700732 struct snd_soc_card *card = platform_get_drvdata(pdev);
Dylan Reid3fe24032014-10-01 14:25:20 -0700733
Kuninori Morimoto885fc052016-08-10 02:21:42 +0000734 return asoc_simple_card_clean_reference(card);
Xiubo Lie3c4a282014-09-01 14:46:52 +0800735}
736
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900737static const struct of_device_id asoc_simple_of_match[] = {
738 { .compatible = "simple-audio-card", },
Kuninori Morimotoda215352018-12-14 11:35:10 +0900739 { .compatible = "simple-scu-audio-card", },
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900740 {},
741};
742MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
743
Kuninori Morimotof2390882012-04-08 21:17:50 -0700744static struct platform_driver asoc_simple_card = {
745 .driver = {
Nicolin Chen781cbeb2014-04-24 19:14:00 +0800746 .name = "asoc-simple-card",
Peter Ujfalusi7c376712016-05-09 13:38:10 +0300747 .pm = &snd_soc_pm_ops,
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900748 .of_match_table = asoc_simple_of_match,
Kuninori Morimotof2390882012-04-08 21:17:50 -0700749 },
Nicolin Chen781cbeb2014-04-24 19:14:00 +0800750 .probe = asoc_simple_card_probe,
Xiubo Lie3c4a282014-09-01 14:46:52 +0800751 .remove = asoc_simple_card_remove,
Kuninori Morimotof2390882012-04-08 21:17:50 -0700752};
753
754module_platform_driver(asoc_simple_card);
755
Fabio Estevamc445be32013-08-23 14:35:17 -0300756MODULE_ALIAS("platform:asoc-simple-card");
Kuninori Morimotoa1dbfd02016-08-26 03:07:28 +0000757MODULE_LICENSE("GPL v2");
Kuninori Morimotof2390882012-04-08 21:17:50 -0700758MODULE_DESCRIPTION("ASoC Simple Sound Card");
759MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");