blob: c5b6e04cd9261d80de4646fdae588c93b87230c7 [file] [log] [blame]
Kuninori Morimotof2390882012-04-08 21:17:50 -07001/*
2 * ASoC simple sound card support
3 *
4 * Copyright (C) 2012 Renesas Solutions Corp.
5 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
Kuninori Morimotofa558c22013-11-20 15:25:02 +090011#include <linux/clk.h>
Xiubo Li6ff62ee2014-02-14 09:34:36 +080012#include <linux/device.h>
Kuninori Morimotof2390882012-04-08 21:17:50 -070013#include <linux/module.h>
Kuninori Morimotofa558c22013-11-20 15:25:02 +090014#include <linux/of.h>
Kuninori Morimotof2390882012-04-08 21:17:50 -070015#include <linux/platform_device.h>
Xiubo Lica919fe2014-01-14 12:35:32 +080016#include <linux/string.h>
Kuninori Morimotof2390882012-04-08 21:17:50 -070017#include <sound/simple_card.h>
Xiubo Li6ff62ee2014-02-14 09:34:36 +080018#include <sound/soc-dai.h>
19#include <sound/soc.h>
Kuninori Morimotof2390882012-04-08 21:17:50 -070020
Jean-Francois Moine45fce592014-01-15 16:51:56 +010021struct simple_card_data {
22 struct snd_soc_card snd_card;
Jean-Francois Moinecf7dc232014-03-20 10:52:41 +010023 struct simple_dai_props {
24 struct asoc_simple_dai cpu_dai;
25 struct asoc_simple_dai codec_dai;
Arnaud Pouliquen85a4bfd2015-06-05 10:19:05 +020026 unsigned int mclk_fs;
Jean-Francois Moinecf7dc232014-03-20 10:52:41 +010027 } *dai_props;
Andrew Lunn2942a0e2014-05-22 17:31:49 +020028 unsigned int mclk_fs;
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;
Jean-Francois Moine45fce592014-01-15 16:51:56 +010032};
33
Kuninori Morimoto5be50952017-03-15 04:44:00 +000034#define simple_priv_to_card(priv) (&(priv)->snd_card)
Kuninori Morimoto7e3353d2016-08-26 03:06:23 +000035#define simple_priv_to_props(priv, i) ((priv)->dai_props + (i))
Kuninori Morimoto5be50952017-03-15 04:44:00 +000036#define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev)
37#define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i))
Kuninori Morimotof531913f2014-09-09 21:37:57 -070038
Kuninori Morimoto44c16af2016-08-08 06:02:07 +000039#define DAI "sound-dai"
40#define CELL "#sound-dai-cells"
Kuninori Morimoto548563f2016-05-31 08:59:01 +000041#define PREFIX "simple-audio-card,"
42
Jyri Sarhaf9911802015-01-13 21:16:34 +020043static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
44{
45 struct snd_soc_pcm_runtime *rtd = substream->private_data;
46 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
47 struct simple_dai_props *dai_props =
Kuninori Morimotoc9a23ea2016-08-26 03:06:51 +000048 simple_priv_to_props(priv, rtd->num);
Jyri Sarhaf9911802015-01-13 21:16:34 +020049 int ret;
50
Kuninori Morimoto3ab50c42017-06-09 00:44:16 +000051 ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai);
Jyri Sarhaf9911802015-01-13 21:16:34 +020052 if (ret)
53 return ret;
Kuninori Morimoto387f5822016-08-26 03:07:59 +000054
Kuninori Morimoto3ab50c42017-06-09 00:44:16 +000055 ret = asoc_simple_card_clk_enable(&dai_props->codec_dai);
Jyri Sarhaf9911802015-01-13 21:16:34 +020056 if (ret)
Kuninori Morimoto3ab50c42017-06-09 00:44:16 +000057 asoc_simple_card_clk_disable(&dai_props->cpu_dai);
Jyri Sarhaf9911802015-01-13 21:16:34 +020058
59 return ret;
60}
61
62static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
63{
64 struct snd_soc_pcm_runtime *rtd = substream->private_data;
65 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
66 struct simple_dai_props *dai_props =
Kuninori Morimotoc9a23ea2016-08-26 03:06:51 +000067 simple_priv_to_props(priv, rtd->num);
Jyri Sarhaf9911802015-01-13 21:16:34 +020068
Kuninori Morimoto3ab50c42017-06-09 00:44:16 +000069 asoc_simple_card_clk_disable(&dai_props->cpu_dai);
Jyri Sarhaf9911802015-01-13 21:16:34 +020070
Kuninori Morimoto3ab50c42017-06-09 00:44:16 +000071 asoc_simple_card_clk_disable(&dai_props->codec_dai);
Jyri Sarhaf9911802015-01-13 21:16:34 +020072}
73
Daniel Macke9be4ff2018-05-30 21:45:56 +020074static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai,
75 unsigned long rate)
76{
77 if (!simple_dai->clk)
78 return 0;
79
80 if (clk_get_rate(simple_dai->clk) == rate)
81 return 0;
82
83 return clk_set_rate(simple_dai->clk, rate);
84}
85
Andrew Lunn2942a0e2014-05-22 17:31:49 +020086static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
87 struct snd_pcm_hw_params *params)
88{
89 struct snd_soc_pcm_runtime *rtd = substream->private_data;
90 struct snd_soc_dai *codec_dai = rtd->codec_dai;
Arnaud Pouliquene2257972015-06-05 10:19:06 +020091 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Andrew Lunn2942a0e2014-05-22 17:31:49 +020092 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
Kuninori Morimotoc9a23ea2016-08-26 03:06:51 +000093 struct simple_dai_props *dai_props =
94 simple_priv_to_props(priv, rtd->num);
Arnaud Pouliquen85a4bfd2015-06-05 10:19:05 +020095 unsigned int mclk, mclk_fs = 0;
Andrew Lunn2942a0e2014-05-22 17:31:49 +020096 int ret = 0;
97
Arnaud Pouliquen85a4bfd2015-06-05 10:19:05 +020098 if (priv->mclk_fs)
99 mclk_fs = priv->mclk_fs;
100 else if (dai_props->mclk_fs)
101 mclk_fs = dai_props->mclk_fs;
102
103 if (mclk_fs) {
104 mclk = params_rate(params) * mclk_fs;
Daniel Macke9be4ff2018-05-30 21:45:56 +0200105
106 ret = asoc_simple_set_clk_rate(&dai_props->codec_dai, mclk);
107 if (ret < 0)
108 return ret;
109
110 ret = asoc_simple_set_clk_rate(&dai_props->cpu_dai, mclk);
111 if (ret < 0)
112 return ret;
113
Andrew Lunn2942a0e2014-05-22 17:31:49 +0200114 ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
115 SND_SOC_CLOCK_IN);
Arnaud Pouliquene2257972015-06-05 10:19:06 +0200116 if (ret && ret != -ENOTSUPP)
117 goto err;
118
119 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
120 SND_SOC_CLOCK_OUT);
121 if (ret && ret != -ENOTSUPP)
122 goto err;
Andrew Lunn2942a0e2014-05-22 17:31:49 +0200123 }
Aaro Koskinenee43a1a2016-01-24 00:36:40 +0200124 return 0;
Arnaud Pouliquene2257972015-06-05 10:19:06 +0200125err:
Andrew Lunn2942a0e2014-05-22 17:31:49 +0200126 return ret;
127}
128
Julia Lawall9b6fdef2016-10-15 16:55:49 +0200129static const struct snd_soc_ops asoc_simple_card_ops = {
Jyri Sarhaf9911802015-01-13 21:16:34 +0200130 .startup = asoc_simple_card_startup,
131 .shutdown = asoc_simple_card_shutdown,
Andrew Lunn2942a0e2014-05-22 17:31:49 +0200132 .hw_params = asoc_simple_card_hw_params,
133};
134
Kuninori Morimotof2390882012-04-08 21:17:50 -0700135static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
136{
Nicolin Chen781cbeb2014-04-24 19:14:00 +0800137 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
Kuninori Morimotof2390882012-04-08 21:17:50 -0700138 struct snd_soc_dai *codec = rtd->codec_dai;
139 struct snd_soc_dai *cpu = rtd->cpu_dai;
Kuninori Morimotoc9a23ea2016-08-26 03:06:51 +0000140 struct simple_dai_props *dai_props =
141 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 Morimotod8cb9352016-08-09 05:48:53 +0000144 ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai);
Kuninori Morimotoa4a29922013-01-10 16:49:11 -0800145 if (ret < 0)
146 return ret;
Kuninori Morimotof2390882012-04-08 21:17:50 -0700147
Kuninori Morimotod8cb9352016-08-09 05:48:53 +0000148 ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai);
Kuninori Morimotoa4a29922013-01-10 16:49:11 -0800149 if (ret < 0)
150 return ret;
Kuninori Morimotof2390882012-04-08 21:17:50 -0700151
152 return 0;
153}
154
Kuninori Morimoto2d82eeb2014-08-27 20:07:46 -0700155static int asoc_simple_card_dai_link_of(struct device_node *node,
Kuninori Morimotof531913f2014-09-09 21:37:57 -0700156 struct simple_card_data *priv,
Kuninori Morimoto9810f532014-09-09 21:38:24 -0700157 int idx,
Kuninori Morimoto2d82eeb2014-08-27 20:07:46 -0700158 bool is_top_level_node)
Jean-Francois Moine6a91a17bd2014-03-20 11:49:55 +0100159{
Kuninori Morimotof531913f2014-09-09 21:37:57 -0700160 struct device *dev = simple_priv_to_dev(priv);
Kuninori Morimoto9810f532014-09-09 21:38:24 -0700161 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
162 struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
Kuninori Morimoto28abd992016-07-19 02:53:13 +0000163 struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
164 struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
Kuninori Morimoto1b5721b2014-10-27 18:04:52 -0700165 struct device_node *cpu = NULL;
Jun Niee0ae2252015-04-29 18:11:07 +0800166 struct device_node *plat = NULL;
Kuninori Morimoto1b5721b2014-10-27 18:04:52 -0700167 struct device_node *codec = NULL;
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200168 char prop[128];
169 char *prefix = "";
Kuninori Morimoto44c16af2016-08-08 06:02:07 +0000170 int ret, single_cpu;
Jean-Francois Moine6a91a17bd2014-03-20 11:49:55 +0100171
Xiubo Li20804372014-09-03 10:23:39 +0800172 /* For single DAI link & old style of DT node */
Jyri Sarha64872212014-04-24 19:42:00 +0300173 if (is_top_level_node)
Kuninori Morimoto548563f2016-05-31 08:59:01 +0000174 prefix = PREFIX;
Jean-Francois Moine6a91a17bd2014-03-20 11:49:55 +0100175
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200176 snprintf(prop, sizeof(prop), "%scpu", prefix);
Kuninori Morimoto1b5721b2014-10-27 18:04:52 -0700177 cpu = of_get_child_by_name(node, prop);
178
Julian Scheel7ac45d12017-05-24 12:28:23 +0200179 if (!cpu) {
180 ret = -EINVAL;
181 dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
182 goto dai_link_of_err;
183 }
184
Jun Niee0ae2252015-04-29 18:11:07 +0800185 snprintf(prop, sizeof(prop), "%splat", prefix);
186 plat = of_get_child_by_name(node, prop);
187
Kuninori Morimoto1b5721b2014-10-27 18:04:52 -0700188 snprintf(prop, sizeof(prop), "%scodec", prefix);
189 codec = of_get_child_by_name(node, prop);
190
Julian Scheel7ac45d12017-05-24 12:28:23 +0200191 if (!codec) {
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200192 ret = -EINVAL;
Nicolin Chen966b8062014-04-24 19:13:59 +0800193 dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200194 goto dai_link_of_err;
Jean-Francois Moine6a91a17bd2014-03-20 11:49:55 +0100195 }
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200196
Kuninori Morimotocecdef32016-06-30 06:02:46 +0000197 ret = asoc_simple_card_parse_daifmt(dev, node, codec,
198 prefix, &dai_link->dai_fmt);
Kuninori Morimoto1b5721b2014-10-27 18:04:52 -0700199 if (ret < 0)
200 goto dai_link_of_err;
201
Kuninori Morimotof93b6462016-08-26 03:05:58 +0000202 of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs);
Arnaud Pouliquen85a4bfd2015-06-05 10:19:05 +0200203
Kuninori Morimoto44c16af2016-08-08 06:02:07 +0000204 ret = asoc_simple_card_parse_cpu(cpu, dai_link,
205 DAI, CELL, &single_cpu);
206 if (ret < 0)
207 goto dai_link_of_err;
208
209 ret = asoc_simple_card_parse_codec(codec, dai_link, DAI, CELL);
210 if (ret < 0)
211 goto dai_link_of_err;
212
213 ret = asoc_simple_card_parse_platform(plat, dai_link, DAI, CELL);
214 if (ret < 0)
215 goto dai_link_of_err;
216
Kuninori Morimotob93d2cf2017-06-14 00:34:53 +0000217 ret = asoc_simple_card_of_parse_tdm(cpu, cpu_dai);
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200218 if (ret < 0)
219 goto dai_link_of_err;
220
Kuninori Morimotob93d2cf2017-06-14 00:34:53 +0000221 ret = asoc_simple_card_of_parse_tdm(codec, codec_dai);
Kuninori Morimoto5fb9cb12016-05-20 09:40:41 +0000222 if (ret < 0)
223 goto dai_link_of_err;
224
Kuninori Morimotoe984fd62017-01-23 07:29:42 +0000225 ret = asoc_simple_card_parse_clk_cpu(dev, cpu, dai_link, cpu_dai);
Kuninori Morimoto28abd992016-07-19 02:53:13 +0000226 if (ret < 0)
227 goto dai_link_of_err;
228
Kuninori Morimotoe984fd62017-01-23 07:29:42 +0000229 ret = asoc_simple_card_parse_clk_codec(dev, codec, dai_link, codec_dai);
Kuninori Morimoto28abd992016-07-19 02:53:13 +0000230 if (ret < 0)
231 goto dai_link_of_err;
232
Kuninori Morimotoc9583742016-08-09 05:50:02 +0000233 ret = asoc_simple_card_canonicalize_dailink(dai_link);
234 if (ret < 0)
Nicolin Chen781cbeb2014-04-24 19:14:00 +0800235 goto dai_link_of_err;
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200236
Kuninori Morimoto2e8d1c72016-07-11 23:57:34 +0000237 ret = asoc_simple_card_set_dailink_name(dev, dai_link,
238 "%s-%s",
239 dai_link->cpu_dai_name,
240 dai_link->codec_dai_name);
241 if (ret < 0)
Vishal Thanki31f30322015-03-03 18:59:00 +0530242 goto dai_link_of_err;
Vishal Thanki31f30322015-03-03 18:59:00 +0530243
Andrew Lunn2942a0e2014-05-22 17:31:49 +0200244 dai_link->ops = &asoc_simple_card_ops;
Kuninori Morimotoa5960bd2014-08-27 20:08:27 -0700245 dai_link->init = asoc_simple_card_dai_init;
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200246
Kuninori Morimoto16f1de62016-08-10 02:20:43 +0000247 asoc_simple_card_canonicalize_cpu(dai_link, single_cpu);
Kuninori Morimoto179949b2014-08-27 20:08:06 -0700248
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200249dai_link_of_err:
Kuninori Morimoto1b5721b2014-10-27 18:04:52 -0700250 of_node_put(cpu);
251 of_node_put(codec);
252
Jean-Francois Moine6a91a17bd2014-03-20 11:49:55 +0100253 return ret;
254}
255
Nikita Yushchenko899a2472016-09-26 12:56:51 +0300256static int asoc_simple_card_parse_aux_devs(struct device_node *node,
257 struct simple_card_data *priv)
258{
259 struct device *dev = simple_priv_to_dev(priv);
260 struct device_node *aux_node;
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000261 struct snd_soc_card *card = simple_priv_to_card(priv);
Nikita Yushchenko899a2472016-09-26 12:56:51 +0300262 int i, n, len;
263
264 if (!of_find_property(node, PREFIX "aux-devs", &len))
265 return 0; /* Ok to have no aux-devs */
266
267 n = len / sizeof(__be32);
268 if (n <= 0)
269 return -EINVAL;
270
Kees Cooka86854d2018-06-12 14:07:58 -0700271 card->aux_dev = devm_kcalloc(dev,
272 n, sizeof(*card->aux_dev), GFP_KERNEL);
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000273 if (!card->aux_dev)
Nikita Yushchenko899a2472016-09-26 12:56:51 +0300274 return -ENOMEM;
275
276 for (i = 0; i < n; i++) {
277 aux_node = of_parse_phandle(node, PREFIX "aux-devs", i);
278 if (!aux_node)
279 return -EINVAL;
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000280 card->aux_dev[i].codec_of_node = aux_node;
Nikita Yushchenko899a2472016-09-26 12:56:51 +0300281 }
282
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000283 card->num_aux_devs = n;
Nikita Yushchenko899a2472016-09-26 12:56:51 +0300284 return 0;
285}
286
Kuninori Morimotod2fdcc22017-06-07 00:37:05 +0000287static int asoc_simple_card_parse_of(struct simple_card_data *priv)
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900288{
Kuninori Morimotof531913f2014-09-09 21:37:57 -0700289 struct device *dev = simple_priv_to_dev(priv);
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000290 struct snd_soc_card *card = simple_priv_to_card(priv);
Kuninori Morimotoa03b0542016-08-26 03:05:16 +0000291 struct device_node *dai_link;
Kuninori Morimotod2fdcc22017-06-07 00:37:05 +0000292 struct device_node *node = dev->of_node;
Xiubo Lid4c22092013-12-23 12:57:01 +0800293 int ret;
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900294
Xiubo Li20804372014-09-03 10:23:39 +0800295 if (!node)
296 return -EINVAL;
297
Kuninori Morimotoa03b0542016-08-26 03:05:16 +0000298 dai_link = of_get_child_by_name(node, PREFIX "dai-link");
299
Kuninori Morimotofa2760dd2017-06-16 01:39:11 +0000300 ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
301 if (ret < 0)
302 goto card_parse_end;
Xiubo Li9d681f52014-02-08 15:59:53 +0800303
Kuninori Morimoto1fdb5d22017-06-15 00:25:17 +0000304 ret = asoc_simple_card_of_parse_routing(card, PREFIX, 1);
305 if (ret < 0)
306 goto card_parse_end;
Xiubo Lid4c22092013-12-23 12:57:01 +0800307
Andrew Lunn2942a0e2014-05-22 17:31:49 +0200308 /* Factor to mclk, used in hw_params() */
Kuninori Morimotof93b6462016-08-26 03:05:58 +0000309 of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs);
Andrew Lunn2942a0e2014-05-22 17:31:49 +0200310
Xiubo Li20804372014-09-03 10:23:39 +0800311 /* Single/Muti DAI link(s) & New style of DT node */
Kuninori Morimotoa03b0542016-08-26 03:05:16 +0000312 if (dai_link) {
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200313 struct device_node *np = NULL;
Kuninori Morimotoa44a7502014-08-27 20:08:47 -0700314 int i = 0;
315
316 for_each_child_of_node(node, np) {
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200317 dev_dbg(dev, "\tlink %d:\n", i);
Kuninori Morimotof531913f2014-09-09 21:37:57 -0700318 ret = asoc_simple_card_dai_link_of(np, priv,
Kuninori Morimoto9810f532014-09-09 21:38:24 -0700319 i, false);
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200320 if (ret < 0) {
321 of_node_put(np);
Kuninori Morimotoa03b0542016-08-26 03:05:16 +0000322 goto card_parse_end;
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200323 }
Kuninori Morimotoa44a7502014-08-27 20:08:47 -0700324 i++;
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200325 }
326 } else {
Xiubo Li20804372014-09-03 10:23:39 +0800327 /* For single DAI link & old style of DT node */
Kuninori Morimoto9810f532014-09-09 21:38:24 -0700328 ret = asoc_simple_card_dai_link_of(node, priv, 0, true);
Jean-Francois Moine6a91a17bd2014-03-20 11:49:55 +0100329 if (ret < 0)
Kuninori Morimotoa03b0542016-08-26 03:05:16 +0000330 goto card_parse_end;
Jean-Francois Moinee512e002014-03-11 10:03:40 +0100331 }
Xiubo Lidd41e0c2013-12-20 14:39:50 +0800332
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000333 ret = asoc_simple_card_parse_card_name(card, PREFIX);
Nikita Yushchenko899a2472016-09-26 12:56:51 +0300334 if (ret < 0)
335 goto card_parse_end;
336
337 ret = asoc_simple_card_parse_aux_devs(node, priv);
Kuninori Morimotof687d902014-02-27 18:25:24 -0800338
Kuninori Morimotoa03b0542016-08-26 03:05:16 +0000339card_parse_end:
340 of_node_put(dai_link);
341
342 return ret;
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900343}
344
Katsuhiro Suzuki8d1bd112018-06-11 17:32:13 +0900345static int asoc_simple_soc_card_probe(struct snd_soc_card *card)
346{
347 struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
348 int ret;
349
350 ret = asoc_simple_card_init_hp(card, &priv->hp_jack, PREFIX);
351 if (ret < 0)
352 return ret;
353
354 ret = asoc_simple_card_init_mic(card, &priv->mic_jack, PREFIX);
355 if (ret < 0)
356 return ret;
357
358 return 0;
359}
360
Kuninori Morimotof2390882012-04-08 21:17:50 -0700361static int asoc_simple_card_probe(struct platform_device *pdev)
362{
Jean-Francois Moine45fce592014-01-15 16:51:56 +0100363 struct simple_card_data *priv;
Jean-Francois Moine5ca8ba42014-01-15 16:51:45 +0100364 struct snd_soc_dai_link *dai_link;
Kuninori Morimotob0133d92016-08-26 03:10:25 +0000365 struct simple_dai_props *dai_props;
Kuninori Morimotof89983e2012-12-25 22:52:33 -0800366 struct device *dev = &pdev->dev;
Kuninori Morimotodcee9bfe2017-03-15 04:43:21 +0000367 struct device_node *np = dev->of_node;
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000368 struct snd_soc_card *card;
Kuninori Morimoto2c86dda2016-08-26 03:09:38 +0000369 int num, ret;
Jean-Francois Moine6a91a17bd2014-03-20 11:49:55 +0100370
Xiubo Li0dd4fc32014-09-10 09:59:55 +0800371 /* Get the number of DAI links */
Kuninori Morimoto548563f2016-05-31 08:59:01 +0000372 if (np && of_get_child_by_name(np, PREFIX "dai-link"))
Kuninori Morimoto2c86dda2016-08-26 03:09:38 +0000373 num = of_get_child_count(np);
Xiubo Li20804372014-09-03 10:23:39 +0800374 else
Kuninori Morimoto2c86dda2016-08-26 03:09:38 +0000375 num = 1;
Kuninori Morimotof2390882012-04-08 21:17:50 -0700376
Xiubo Li0dd4fc32014-09-10 09:59:55 +0800377 /* Allocate the private data and the DAI link array */
Kuninori Morimotob0133d92016-08-26 03:10:25 +0000378 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
Jean-Francois Moineca65b492014-01-15 16:51:52 +0100379 if (!priv)
Xiubo Lica919fe2014-01-14 12:35:32 +0800380 return -ENOMEM;
381
Kees Cooka86854d2018-06-12 14:07:58 -0700382 dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);
383 dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);
Kuninori Morimotob0133d92016-08-26 03:10:25 +0000384 if (!dai_props || !dai_link)
385 return -ENOMEM;
386
387 priv->dai_props = dai_props;
388 priv->dai_link = dai_link;
389
Xiubo Li0dd4fc32014-09-10 09:59:55 +0800390 /* Init snd_soc_card */
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000391 card = simple_priv_to_card(priv);
392 card->owner = THIS_MODULE;
393 card->dev = dev;
394 card->dai_link = priv->dai_link;
395 card->num_links = num;
Katsuhiro Suzuki8d1bd112018-06-11 17:32:13 +0900396 card->probe = asoc_simple_soc_card_probe;
Xiubo Lica919fe2014-01-14 12:35:32 +0800397
Jean-Francois Moine201a0ea2014-01-15 16:51:41 +0100398 if (np && of_device_is_available(np)) {
399
Kuninori Morimotod2fdcc22017-06-07 00:37:05 +0000400 ret = asoc_simple_card_parse_of(priv);
Xiubo Lica919fe2014-01-14 12:35:32 +0800401 if (ret < 0) {
402 if (ret != -EPROBE_DEFER)
403 dev_err(dev, "parse error %d\n", ret);
Jean-Francois Moinee512e002014-03-11 10:03:40 +0100404 goto err;
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900405 }
Jean-Francois Moine6a91a17bd2014-03-20 11:49:55 +0100406
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900407 } else {
Jean-Francois Moineca65b492014-01-15 16:51:52 +0100408 struct asoc_simple_card_info *cinfo;
409
410 cinfo = dev->platform_data;
411 if (!cinfo) {
Xiubo Li34787d0a2014-01-09 17:49:40 +0800412 dev_err(dev, "no info for asoc-simple-card\n");
413 return -EINVAL;
414 }
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900415
Nicolin Chen781cbeb2014-04-24 19:14:00 +0800416 if (!cinfo->name ||
417 !cinfo->codec_dai.name ||
418 !cinfo->codec ||
419 !cinfo->platform ||
Jean-Francois Moine7722f832014-01-15 16:51:33 +0100420 !cinfo->cpu_dai.name) {
421 dev_err(dev, "insufficient asoc_simple_card_info settings\n");
422 return -EINVAL;
423 }
Jean-Francois Moine2bee9912014-01-15 16:51:37 +0100424
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000425 card->name = (cinfo->card) ? cinfo->card : cinfo->name;
Jean-Francois Moine5ca8ba42014-01-15 16:51:45 +0100426 dai_link->name = cinfo->name;
427 dai_link->stream_name = cinfo->name;
428 dai_link->platform_name = cinfo->platform;
429 dai_link->codec_name = cinfo->codec;
Jean-Francois Moine52008472014-01-15 16:51:48 +0100430 dai_link->cpu_dai_name = cinfo->cpu_dai.name;
431 dai_link->codec_dai_name = cinfo->codec_dai.name;
Lars-Peter Clausen1efb53a2015-03-24 01:07:08 +0000432 dai_link->dai_fmt = cinfo->daifmt;
Kuninori Morimotoa5960bd2014-08-27 20:08:27 -0700433 dai_link->init = asoc_simple_card_dai_init;
Jean-Francois Moinecf7dc232014-03-20 10:52:41 +0100434 memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
435 sizeof(priv->dai_props->cpu_dai));
436 memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai,
437 sizeof(priv->dai_props->codec_dai));
Kuninori Morimotof2390882012-04-08 21:17:50 -0700438 }
439
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000440 snd_soc_card_set_drvdata(card, priv);
Xiubo Liba194a42014-01-13 17:08:08 +0800441
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000442 ret = devm_snd_soc_register_card(dev, card);
Kuninori Morimotoc6d112e2017-05-19 00:57:21 +0000443 if (ret < 0)
444 goto err;
445
446 return 0;
Jean-Francois Moinee512e002014-03-11 10:03:40 +0100447err:
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000448 asoc_simple_card_clean_reference(card);
Kuninori Morimoto387f5822016-08-26 03:07:59 +0000449
Jean-Francois Moinee512e002014-03-11 10:03:40 +0100450 return ret;
Kuninori Morimotof2390882012-04-08 21:17:50 -0700451}
452
Xiubo Lie3c4a282014-09-01 14:46:52 +0800453static int asoc_simple_card_remove(struct platform_device *pdev)
454{
Dylan Reid3fe24032014-10-01 14:25:20 -0700455 struct snd_soc_card *card = platform_get_drvdata(pdev);
Dylan Reid3fe24032014-10-01 14:25:20 -0700456
Kuninori Morimoto885fc052016-08-10 02:21:42 +0000457 return asoc_simple_card_clean_reference(card);
Xiubo Lie3c4a282014-09-01 14:46:52 +0800458}
459
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900460static const struct of_device_id asoc_simple_of_match[] = {
461 { .compatible = "simple-audio-card", },
462 {},
463};
464MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
465
Kuninori Morimotof2390882012-04-08 21:17:50 -0700466static struct platform_driver asoc_simple_card = {
467 .driver = {
Nicolin Chen781cbeb2014-04-24 19:14:00 +0800468 .name = "asoc-simple-card",
Peter Ujfalusi7c376712016-05-09 13:38:10 +0300469 .pm = &snd_soc_pm_ops,
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900470 .of_match_table = asoc_simple_of_match,
Kuninori Morimotof2390882012-04-08 21:17:50 -0700471 },
Nicolin Chen781cbeb2014-04-24 19:14:00 +0800472 .probe = asoc_simple_card_probe,
Xiubo Lie3c4a282014-09-01 14:46:52 +0800473 .remove = asoc_simple_card_remove,
Kuninori Morimotof2390882012-04-08 21:17:50 -0700474};
475
476module_platform_driver(asoc_simple_card);
477
Fabio Estevamc445be32013-08-23 14:35:17 -0300478MODULE_ALIAS("platform:asoc-simple-card");
Kuninori Morimotoa1dbfd02016-08-26 03:07:28 +0000479MODULE_LICENSE("GPL v2");
Kuninori Morimotof2390882012-04-08 21:17:50 -0700480MODULE_DESCRIPTION("ASoC Simple Sound Card");
481MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");