blob: 9d7299d536a88742e019a509fd024e63f30c48ff [file] [log] [blame]
Kuninori Morimoto9afe58f2018-07-02 06:30:58 +00001// SPDX-License-Identifier: GPL-2.0
2//
3// ASoC simple SCU sound card support
4//
5// Copyright (C) 2015 Renesas Solutions Corp.
6// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
7//
8// based on ${LINUX}/sound/soc/generic/simple-card.c
9
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +000010#include <linux/clk.h>
11#include <linux/device.h>
12#include <linux/module.h>
13#include <linux/of.h>
14#include <linux/of_device.h>
15#include <linux/platform_device.h>
16#include <linux/string.h>
17#include <sound/jack.h>
18#include <sound/soc.h>
19#include <sound/soc-dai.h>
Kuninori Morimotod6a4a9a42016-06-30 06:03:13 +000020#include <sound/simple_card_utils.h>
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +000021
Kuninori Morimoto6910e862016-10-28 03:37:44 +000022struct simple_card_data {
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +000023 struct snd_soc_card snd_card;
Kuninori Morimoto5ece10a2018-08-31 03:08:38 +000024 struct simple_dai_props {
Kuninori Morimotoe6a3ff22018-12-11 03:25:27 +000025 struct asoc_simple_dai *cpu_dai;
26 struct asoc_simple_dai *codec_dai;
Kuninori Morimoto2289cc12018-08-31 03:08:51 +000027 struct snd_soc_dai_link_component codecs;
Kuninori Morimoto24f3bea2018-08-31 03:10:46 +000028 struct snd_soc_dai_link_component platform;
Kuninori Morimoto09ee8332018-12-11 03:25:18 +000029 struct asoc_simple_card_data adata;
Kuninori Morimoto0a26d6d2018-12-11 03:25:37 +000030 struct snd_soc_codec_conf *codec_conf;
Kuninori Morimoto5ece10a2018-08-31 03:08:38 +000031 } *dai_props;
Kuninori Morimoto3433bf02015-06-15 06:22:30 +000032 struct snd_soc_dai_link *dai_link;
Kuninori Morimotoe6a3ff22018-12-11 03:25:27 +000033 struct asoc_simple_dai *dais;
Kuninori Morimotocd8957f2017-06-15 00:24:28 +000034 struct asoc_simple_card_data adata;
Kuninori Morimoto0a26d6d2018-12-11 03:25:37 +000035 struct snd_soc_codec_conf *codec_conf;
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +000036};
37
Kuninori Morimotod27f3b42017-03-15 04:44:16 +000038#define simple_priv_to_card(priv) (&(priv)->snd_card)
Kuninori Morimoto53e682b2016-08-23 01:34:17 +000039#define simple_priv_to_props(priv, i) ((priv)->dai_props + (i))
Kuninori Morimotod27f3b42017-03-15 04:44:16 +000040#define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev)
41#define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i))
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +000042
Kuninori Morimoto5bbf38662016-08-08 06:02:31 +000043#define DAI "sound-dai"
44#define CELL "#sound-dai-cells"
Kuninori Morimoto64df0e62016-08-23 01:34:43 +000045#define PREFIX "simple-audio-card,"
Kuninori Morimoto5bbf38662016-08-08 06:02:31 +000046
Kuninori Morimoto53e682b2016-08-23 01:34:17 +000047static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +000048{
49 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimoto6910e862016-10-28 03:37:44 +000050 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
Kuninori Morimoto5ece10a2018-08-31 03:08:38 +000051 struct simple_dai_props *dai_props =
Kuninori Morimoto53e682b2016-08-23 01:34:17 +000052 simple_priv_to_props(priv, rtd->num);
Kuninori Morimotoe6a3ff22018-12-11 03:25:27 +000053 int ret;
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +000054
Kuninori Morimotoe6a3ff22018-12-11 03:25:27 +000055 ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
56 if (ret)
57 return ret;
58
59 ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
60 if (ret)
61 asoc_simple_card_clk_disable(dai_props->cpu_dai);
62
63 return ret;
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +000064}
65
Kuninori Morimoto53e682b2016-08-23 01:34:17 +000066static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +000067{
68 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimoto6910e862016-10-28 03:37:44 +000069 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
Kuninori Morimoto5ece10a2018-08-31 03:08:38 +000070 struct simple_dai_props *dai_props =
Kuninori Morimoto53e682b2016-08-23 01:34:17 +000071 simple_priv_to_props(priv, rtd->num);
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +000072
Kuninori Morimotoe6a3ff22018-12-11 03:25:27 +000073 asoc_simple_card_clk_disable(dai_props->cpu_dai);
74
75 asoc_simple_card_clk_disable(dai_props->codec_dai);
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +000076}
77
Julia Lawall9b6fdef2016-10-15 16:55:49 +020078static const struct snd_soc_ops asoc_simple_card_ops = {
Kuninori Morimoto53e682b2016-08-23 01:34:17 +000079 .startup = asoc_simple_card_startup,
80 .shutdown = asoc_simple_card_shutdown,
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +000081};
82
Kuninori Morimoto53e682b2016-08-23 01:34:17 +000083static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +000084{
Kuninori Morimotoe6a3ff22018-12-11 03:25:27 +000085 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
86 struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
87 int ret;
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +000088
Kuninori Morimotoe6a3ff22018-12-11 03:25:27 +000089 ret = asoc_simple_card_init_dai(rtd->codec_dai,
90 dai_props->codec_dai);
91 if (ret < 0)
92 return ret;
Kuninori Morimoto04700022015-06-15 06:24:15 +000093
Kuninori Morimotoe6a3ff22018-12-11 03:25:27 +000094 ret = asoc_simple_card_init_dai(rtd->cpu_dai,
95 dai_props->cpu_dai);
96 if (ret < 0)
97 return ret;
98
99 return 0;
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000100}
101
Kuninori Morimoto53e682b2016-08-23 01:34:17 +0000102static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
Kuninori Morimotoaf7e2be2015-03-26 04:01:46 +0000103 struct snd_pcm_hw_params *params)
104{
Kuninori Morimoto6910e862016-10-28 03:37:44 +0000105 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
Kuninori Morimoto09ee8332018-12-11 03:25:18 +0000106 struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
Kuninori Morimotoaf7e2be2015-03-26 04:01:46 +0000107
Kuninori Morimoto09ee8332018-12-11 03:25:18 +0000108 asoc_simple_card_convert_fixup(&dai_props->adata, params);
109
110 /* overwrite by top level adata if exist */
Kuninori Morimotocd8957f2017-06-15 00:24:28 +0000111 asoc_simple_card_convert_fixup(&priv->adata, params);
Kuninori Morimotoaf7e2be2015-03-26 04:01:46 +0000112
113 return 0;
114}
115
Kuninori Morimotodbd08fe2018-12-04 08:20:13 +0000116static int asoc_simple_card_dai_link_of(struct device_node *link,
117 struct device_node *np,
118 struct device_node *codec,
Kuninori Morimoto6910e862016-10-28 03:37:44 +0000119 struct simple_card_data *priv,
Kuninori Morimoto0a26d6d2018-12-11 03:25:37 +0000120 int *dai_idx, int link_idx,
121 int *conf_idx, int is_fe,
Kuninori Morimotodbd08fe2018-12-04 08:20:13 +0000122 bool is_top_level_node)
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000123{
Kuninori Morimoto53e682b2016-08-23 01:34:17 +0000124 struct device *dev = simple_priv_to_dev(priv);
Kuninori Morimotoe6a3ff22018-12-11 03:25:27 +0000125 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
126 struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
Kuninori Morimotod27f3b42017-03-15 04:44:16 +0000127 struct snd_soc_card *card = simple_priv_to_card(priv);
Kuninori Morimotoe6a3ff22018-12-11 03:25:27 +0000128 struct asoc_simple_dai *dai;
Kuninori Morimotodbd08fe2018-12-04 08:20:13 +0000129 char *prefix = "";
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000130 int ret;
131
Kuninori Morimotodbd08fe2018-12-04 08:20:13 +0000132 /* For single DAI link & old style of DT node */
133 if (is_top_level_node)
134 prefix = PREFIX;
135
Kuninori Morimoto04700022015-06-15 06:24:15 +0000136 if (is_fe) {
Kuninori Morimoto27b01082016-08-10 02:21:03 +0000137 int is_single_links = 0;
Kuninori Morimoto2289cc12018-08-31 03:08:51 +0000138 struct snd_soc_dai_link_component *codecs;
Kuninori Morimoto27b01082016-08-10 02:21:03 +0000139
Kuninori Morimoto04700022015-06-15 06:24:15 +0000140 /* BE is dummy */
Kuninori Morimoto2289cc12018-08-31 03:08:51 +0000141 codecs = dai_link->codecs;
142 codecs->of_node = NULL;
143 codecs->dai_name = "snd-soc-dummy-dai";
144 codecs->name = "snd-soc-dummy";
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000145
Kuninori Morimoto04700022015-06-15 06:24:15 +0000146 /* FE settings */
147 dai_link->dynamic = 1;
148 dai_link->dpcm_merged_format = 1;
Kuninori Morimoto5bbf38662016-08-08 06:02:31 +0000149
Kuninori Morimotoe6a3ff22018-12-11 03:25:27 +0000150 dai =
151 dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
152
Kuninori Morimoto5bbf38662016-08-08 06:02:31 +0000153 ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL,
154 &is_single_links);
155 if (ret)
Kuninori Morimoto575f1f92015-12-01 08:33:23 +0000156 return ret;
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000157
Kuninori Morimotoe6a3ff22018-12-11 03:25:27 +0000158 ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai);
Kuninori Morimotoc9a235d2016-07-19 02:53:32 +0000159 if (ret < 0)
160 return ret;
161
Kuninori Morimoto8a99a6b2016-07-11 23:58:25 +0000162 ret = asoc_simple_card_set_dailink_name(dev, dai_link,
163 "fe.%s",
164 dai_link->cpu_dai_name);
165 if (ret < 0)
166 return ret;
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000167
Kuninori Morimoto27b01082016-08-10 02:21:03 +0000168 asoc_simple_card_canonicalize_cpu(dai_link, is_single_links);
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000169 } else {
Kuninori Morimoto0a26d6d2018-12-11 03:25:37 +0000170 struct snd_soc_codec_conf *cconf;
171
Kuninori Morimoto04700022015-06-15 06:24:15 +0000172 /* FE is dummy */
173 dai_link->cpu_of_node = NULL;
174 dai_link->cpu_dai_name = "snd-soc-dummy-dai";
175 dai_link->cpu_name = "snd-soc-dummy";
176
177 /* BE settings */
178 dai_link->no_pcm = 1;
Kuninori Morimoto53e682b2016-08-23 01:34:17 +0000179 dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup;
Kuninori Morimoto5bbf38662016-08-08 06:02:31 +0000180
Kuninori Morimotoe6a3ff22018-12-11 03:25:27 +0000181 dai =
182 dai_props->codec_dai = &priv->dais[(*dai_idx)++];
183
Kuninori Morimoto0a26d6d2018-12-11 03:25:37 +0000184 cconf =
185 dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++];
186
Kuninori Morimoto5bbf38662016-08-08 06:02:31 +0000187 ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL);
Kuninori Morimoto575f1f92015-12-01 08:33:23 +0000188 if (ret < 0)
189 return ret;
Kuninori Morimoto04700022015-06-15 06:24:15 +0000190
Kuninori Morimotoe6a3ff22018-12-11 03:25:27 +0000191 ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai);
Kuninori Morimotoc9a235d2016-07-19 02:53:32 +0000192 if (ret < 0)
193 return ret;
194
Kuninori Morimoto8a99a6b2016-07-11 23:58:25 +0000195 ret = asoc_simple_card_set_dailink_name(dev, dai_link,
196 "be.%s",
Kuninori Morimoto2289cc12018-08-31 03:08:51 +0000197 dai_link->codecs->dai_name);
Kuninori Morimoto8a99a6b2016-07-11 23:58:25 +0000198 if (ret < 0)
199 return ret;
200
Kuninori Morimotoca8d95c2018-11-22 00:55:40 +0000201 /* check "prefix" from top node */
Kuninori Morimoto0a26d6d2018-12-11 03:25:37 +0000202 snd_soc_of_parse_audio_prefix(card, cconf,
Kuninori Morimoto2289cc12018-08-31 03:08:51 +0000203 dai_link->codecs->of_node,
Kuninori Morimoto64df0e62016-08-23 01:34:43 +0000204 PREFIX "prefix");
Kuninori Morimotoca8d95c2018-11-22 00:55:40 +0000205 /* check "prefix" from each node if top doesn't have */
Kuninori Morimoto0a26d6d2018-12-11 03:25:37 +0000206 if (!cconf->of_node)
207 snd_soc_of_parse_node_prefix(np, cconf,
Kuninori Morimotoca8d95c2018-11-22 00:55:40 +0000208 dai_link->codecs->of_node,
209 "prefix");
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000210 }
211
Kuninori Morimoto09ee8332018-12-11 03:25:18 +0000212 asoc_simple_card_parse_convert(dev, link, prefix, &dai_props->adata);
213
Kuninori Morimotoe6a3ff22018-12-11 03:25:27 +0000214 ret = asoc_simple_card_of_parse_tdm(np, dai);
Kuninori Morimoto9f645422016-08-25 01:58:55 +0000215 if (ret)
216 return ret;
217
Kuninori Morimotoa09f3832016-08-09 05:50:19 +0000218 ret = asoc_simple_card_canonicalize_dailink(dai_link);
219 if (ret < 0)
220 return ret;
221
Kuninori Morimotodbd08fe2018-12-04 08:20:13 +0000222 ret = asoc_simple_card_parse_daifmt(dev, link, codec,
223 prefix, &dai_link->dai_fmt);
224 if (ret < 0)
225 return ret;
226
Kuninori Morimoto04700022015-06-15 06:24:15 +0000227 dai_link->dpcm_playback = 1;
228 dai_link->dpcm_capture = 1;
Kuninori Morimoto53e682b2016-08-23 01:34:17 +0000229 dai_link->ops = &asoc_simple_card_ops;
230 dai_link->init = asoc_simple_card_dai_init;
Kuninori Morimoto04700022015-06-15 06:24:15 +0000231
Kuninori Morimotoc9a235d2016-07-19 02:53:32 +0000232 return 0;
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000233}
234
Kuninori Morimoto0d6b3522017-06-07 00:37:30 +0000235static int asoc_simple_card_parse_of(struct simple_card_data *priv)
Kuninori Morimoto15a190ff2016-10-28 03:37:26 +0000236
Kuninori Morimotoaf998f82015-12-17 02:49:43 +0000237{
Kuninori Morimoto53e682b2016-08-23 01:34:17 +0000238 struct device *dev = simple_priv_to_dev(priv);
Kuninori Morimotoda32d652018-12-11 03:24:57 +0000239 struct device_node *top = dev->of_node;
240 struct device_node *node;
Kuninori Morimotodbd08fe2018-12-04 08:20:13 +0000241 struct device_node *np;
242 struct device_node *codec;
243 struct snd_soc_card *card = simple_priv_to_card(priv);
Kuninori Morimotoaf998f82015-12-17 02:49:43 +0000244 bool is_fe;
Kuninori Morimotoe6a3ff22018-12-11 03:25:27 +0000245 int ret, loop;
Kuninori Morimoto0a26d6d2018-12-11 03:25:37 +0000246 int dai_idx, link_idx, conf_idx;
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000247
Kuninori Morimotoda32d652018-12-11 03:24:57 +0000248 if (!top)
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000249 return -EINVAL;
250
Daniel Balutad0148eb2017-08-11 17:12:19 +0300251 ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
252 if (ret < 0)
253 return ret;
254
Kuninori Morimoto33404f32018-11-21 02:11:13 +0000255 ret = asoc_simple_card_of_parse_routing(card, PREFIX);
Kuninori Morimoto64df0e62016-08-23 01:34:43 +0000256 if (ret < 0)
257 return ret;
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000258
Kuninori Morimotoda32d652018-12-11 03:24:57 +0000259 asoc_simple_card_parse_convert(dev, top, PREFIX, &priv->adata);
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000260
Kuninori Morimotoda32d652018-12-11 03:24:57 +0000261 loop = 1;
Kuninori Morimotoe6a3ff22018-12-11 03:25:27 +0000262 link_idx = 0;
263 dai_idx = 0;
Kuninori Morimoto0a26d6d2018-12-11 03:25:37 +0000264 conf_idx = 0;
Kuninori Morimotoda32d652018-12-11 03:24:57 +0000265 node = of_get_child_by_name(top, PREFIX "dai-link");
266 if (!node) {
267 node = dev->of_node;
268 loop = 0;
Kuninori Morimoto15a190ff2016-10-28 03:37:26 +0000269 }
270
Kuninori Morimotoda32d652018-12-11 03:24:57 +0000271 do {
272 codec = of_get_child_by_name(node,
273 loop ? "codec" : PREFIX "codec");
274 if (!codec)
275 return -ENODEV;
276
277 for_each_child_of_node(node, np) {
278 is_fe = (np != codec);
279
280 ret = asoc_simple_card_dai_link_of(node, np, codec, priv,
Kuninori Morimotoe6a3ff22018-12-11 03:25:27 +0000281 &dai_idx, link_idx++,
Kuninori Morimoto0a26d6d2018-12-11 03:25:37 +0000282 &conf_idx,
Kuninori Morimotoe6a3ff22018-12-11 03:25:27 +0000283 is_fe, !loop);
Kuninori Morimotoda32d652018-12-11 03:24:57 +0000284 if (ret < 0)
285 return ret;
Kuninori Morimotoda32d652018-12-11 03:24:57 +0000286 }
287 node = of_get_next_child(top, node);
288 } while (loop && node);
289
Kuninori Morimotod27f3b42017-03-15 04:44:16 +0000290 ret = asoc_simple_card_parse_card_name(card, PREFIX);
Kuninori Morimoto53ae9182016-07-12 00:00:00 +0000291 if (ret < 0)
292 return ret;
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000293
294 return 0;
295}
296
Kuninori Morimotob8d8f9a2018-12-11 03:25:08 +0000297static void asoc_simple_card_get_dais_count(struct device *dev,
298 int *link_num,
299 int *dais_num,
300 int *ccnf_num)
301{
302 struct device_node *top = dev->of_node;
303 struct device_node *node;
304 int loop;
305 int num;
306
307 /*
308 * link_num : number of links.
309 * CPU-Codec / CPU-dummy / dummy-Codec
310 * dais_num : number of DAIs
311 * ccnf_num : number of codec_conf
312 * same number for "dummy-Codec"
313 *
314 * ex1)
315 * CPU0 --- Codec0 link : 5
316 * CPU1 --- Codec1 dais : 7
317 * CPU2 -/ ccnf : 1
318 * CPU3 --- Codec2
319 *
320 * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
321 * => 7 DAIs = 4xCPU + 3xCodec
322 * => 1 ccnf = 1xdummy-Codec
323 *
324 * ex2)
325 * CPU0 --- Codec0 link : 5
326 * CPU1 --- Codec1 dais : 6
327 * CPU2 -/ ccnf : 1
328 * CPU3 -/
329 *
330 * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
331 * => 6 DAIs = 4xCPU + 2xCodec
332 * => 1 ccnf = 1xdummy-Codec
333 *
334 * ex3)
335 * CPU0 --- Codec0 link : 6
336 * CPU1 -/ dais : 6
337 * CPU2 --- Codec1 ccnf : 2
338 * CPU3 -/
339 *
340 * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
341 * => 6 DAIs = 4xCPU + 2xCodec
342 * => 2 ccnf = 2xdummy-Codec
343 */
344 if (!top) {
345 (*link_num) = 1;
346 (*dais_num) = 2;
347 (*ccnf_num) = 0;
348 return;
349 }
350
351 loop = 1;
352 node = of_get_child_by_name(top, PREFIX "dai-link");
353 if (!node) {
354 node = top;
355 loop = 0;
356 }
357
358 do {
359 num = of_get_child_count(node);
360 (*dais_num) += num;
361 if (num > 2) {
362 (*link_num) += num;
363 (*ccnf_num)++;
364 } else {
365 (*link_num)++;
366 }
367 node = of_get_next_child(top, node);
368 } while (loop && node);
369}
370
Kuninori Morimoto53e682b2016-08-23 01:34:17 +0000371static int asoc_simple_card_probe(struct platform_device *pdev)
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000372{
Kuninori Morimoto6910e862016-10-28 03:37:44 +0000373 struct simple_card_data *priv;
Kuninori Morimoto19359922016-10-28 03:38:00 +0000374 struct snd_soc_dai_link *dai_link;
Kuninori Morimoto5ece10a2018-08-31 03:08:38 +0000375 struct simple_dai_props *dai_props;
Kuninori Morimotoe6a3ff22018-12-11 03:25:27 +0000376 struct asoc_simple_dai *dais;
Kuninori Morimotod27f3b42017-03-15 04:44:16 +0000377 struct snd_soc_card *card;
Kuninori Morimoto0a26d6d2018-12-11 03:25:37 +0000378 struct snd_soc_codec_conf *cconf;
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000379 struct device *dev = &pdev->dev;
Kuninori Morimotob8d8f9a2018-12-11 03:25:08 +0000380 int ret, i;
381 int lnum = 0, dnum = 0, cnum = 0;
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000382
383 /* Allocate the private data */
384 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
385 if (!priv)
386 return -ENOMEM;
387
Kuninori Morimotob8d8f9a2018-12-11 03:25:08 +0000388 asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum);
389 if (!lnum || !dnum)
390 return -EINVAL;
Kuninori Morimoto15a190ff2016-10-28 03:37:26 +0000391
Kuninori Morimotob8d8f9a2018-12-11 03:25:08 +0000392 dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
393 dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL);
Kuninori Morimotoe6a3ff22018-12-11 03:25:27 +0000394 dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL);
Kuninori Morimoto0a26d6d2018-12-11 03:25:37 +0000395 cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL);
Kuninori Morimotoe6a3ff22018-12-11 03:25:27 +0000396 if (!dai_props || !dai_link || !dais)
Kuninori Morimoto15a190ff2016-10-28 03:37:26 +0000397 return -ENOMEM;
398
Kuninori Morimoto2289cc12018-08-31 03:08:51 +0000399 /*
400 * Use snd_soc_dai_link_component instead of legacy style
401 * It is codec only. but cpu/platform will be supported in the future.
402 * see
403 * soc-core.c :: snd_soc_init_multicodec()
404 */
Kuninori Morimotob8d8f9a2018-12-11 03:25:08 +0000405 for (i = 0; i < lnum; i++) {
Kuninori Morimoto2289cc12018-08-31 03:08:51 +0000406 dai_link[i].codecs = &dai_props[i].codecs;
407 dai_link[i].num_codecs = 1;
Kuninori Morimoto24f3bea2018-08-31 03:10:46 +0000408 dai_link[i].platform = &dai_props[i].platform;
Kuninori Morimoto2289cc12018-08-31 03:08:51 +0000409 }
410
Kuninori Morimoto19359922016-10-28 03:38:00 +0000411 priv->dai_props = dai_props;
412 priv->dai_link = dai_link;
Kuninori Morimotoe6a3ff22018-12-11 03:25:27 +0000413 priv->dais = dais;
Kuninori Morimoto0a26d6d2018-12-11 03:25:37 +0000414 priv->codec_conf = cconf;
Kuninori Morimoto15a190ff2016-10-28 03:37:26 +0000415
416 /* Init snd_soc_card */
Kuninori Morimotod27f3b42017-03-15 04:44:16 +0000417 card = simple_priv_to_card(priv);
418 card->owner = THIS_MODULE;
419 card->dev = dev;
420 card->dai_link = priv->dai_link;
Kuninori Morimotob8d8f9a2018-12-11 03:25:08 +0000421 card->num_links = lnum;
Kuninori Morimoto0a26d6d2018-12-11 03:25:37 +0000422 card->codec_conf = cconf;
423 card->num_configs = cnum;
Kuninori Morimoto15a190ff2016-10-28 03:37:26 +0000424
Kuninori Morimoto0d6b3522017-06-07 00:37:30 +0000425 ret = asoc_simple_card_parse_of(priv);
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000426 if (ret < 0) {
427 if (ret != -EPROBE_DEFER)
428 dev_err(dev, "parse error %d\n", ret);
429 goto err;
430 }
431
Kuninori Morimotod27f3b42017-03-15 04:44:16 +0000432 snd_soc_card_set_drvdata(card, priv);
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000433
Kuninori Morimotod27f3b42017-03-15 04:44:16 +0000434 ret = devm_snd_soc_register_card(dev, card);
Kuninori Morimotoc73df772017-05-19 00:57:44 +0000435 if (ret < 0)
436 goto err;
437
438 return 0;
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000439err:
Kuninori Morimotod27f3b42017-03-15 04:44:16 +0000440 asoc_simple_card_clean_reference(card);
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000441
442 return ret;
443}
444
Kuninori Morimoto53e682b2016-08-23 01:34:17 +0000445static int asoc_simple_card_remove(struct platform_device *pdev)
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000446{
447 struct snd_soc_card *card = platform_get_drvdata(pdev);
448
Kuninori Morimoto239486b2016-08-10 02:22:01 +0000449 return asoc_simple_card_clean_reference(card);
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000450}
451
Kuninori Morimotof4d707092016-08-25 01:58:31 +0000452static const struct of_device_id asoc_simple_of_match[] = {
453 { .compatible = "renesas,rsrc-card", },
454 { .compatible = "simple-scu-audio-card", },
455 {},
456};
457MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
458
Kuninori Morimoto53e682b2016-08-23 01:34:17 +0000459static struct platform_driver asoc_simple_card = {
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000460 .driver = {
Kuninori Morimoto64df0e62016-08-23 01:34:43 +0000461 .name = "simple-scu-audio-card",
Kuninori Morimotob4e01802017-08-22 04:56:06 +0000462 .pm = &snd_soc_pm_ops,
Kuninori Morimotof4d707092016-08-25 01:58:31 +0000463 .of_match_table = asoc_simple_of_match,
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000464 },
Kuninori Morimoto53e682b2016-08-23 01:34:17 +0000465 .probe = asoc_simple_card_probe,
466 .remove = asoc_simple_card_remove,
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000467};
468
Kuninori Morimoto53e682b2016-08-23 01:34:17 +0000469module_platform_driver(asoc_simple_card);
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000470
Kuninori Morimoto53e682b2016-08-23 01:34:17 +0000471MODULE_ALIAS("platform:asoc-simple-scu-card");
Kuninori Morimoto93bc0472016-08-25 01:56:38 +0000472MODULE_LICENSE("GPL v2");
Kuninori Morimoto53e682b2016-08-23 01:34:17 +0000473MODULE_DESCRIPTION("ASoC Simple SCU Sound Card");
Kuninori Morimoto415f1cb2015-03-26 04:01:27 +0000474MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");