blob: 2c9dedab5184ff74909caf163f7d0697d8b67949 [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>
Dylan Reid3fe24032014-10-01 14:25:20 -070013#include <linux/gpio.h>
Kuninori Morimotof2390882012-04-08 21:17:50 -070014#include <linux/module.h>
Kuninori Morimotofa558c22013-11-20 15:25:02 +090015#include <linux/of.h>
Dylan Reid3fe24032014-10-01 14:25:20 -070016#include <linux/of_gpio.h>
Kuninori Morimotof2390882012-04-08 21:17:50 -070017#include <linux/platform_device.h>
Xiubo Lica919fe2014-01-14 12:35:32 +080018#include <linux/string.h>
Dylan Reid3fe24032014-10-01 14:25:20 -070019#include <sound/jack.h>
Kuninori Morimotof2390882012-04-08 21:17:50 -070020#include <sound/simple_card.h>
Xiubo Li6ff62ee2014-02-14 09:34:36 +080021#include <sound/soc-dai.h>
22#include <sound/soc.h>
Kuninori Morimotof2390882012-04-08 21:17:50 -070023
Kuninori Morimoto9eac3612016-05-31 08:59:46 +000024struct asoc_simple_jack {
25 struct snd_soc_jack jack;
26 struct snd_soc_jack_pin pin;
27 struct snd_soc_jack_gpio gpio;
28};
29
Jean-Francois Moine45fce592014-01-15 16:51:56 +010030struct simple_card_data {
31 struct snd_soc_card snd_card;
Jean-Francois Moinecf7dc232014-03-20 10:52:41 +010032 struct simple_dai_props {
33 struct asoc_simple_dai cpu_dai;
34 struct asoc_simple_dai codec_dai;
Arnaud Pouliquen85a4bfd2015-06-05 10:19:05 +020035 unsigned int mclk_fs;
Jean-Francois Moinecf7dc232014-03-20 10:52:41 +010036 } *dai_props;
Andrew Lunn2942a0e2014-05-22 17:31:49 +020037 unsigned int mclk_fs;
Kuninori Morimoto9eac3612016-05-31 08:59:46 +000038 struct asoc_simple_jack hp_jack;
39 struct asoc_simple_jack mic_jack;
Kuninori Morimotob0133d92016-08-26 03:10:25 +000040 struct snd_soc_dai_link *dai_link;
Jean-Francois Moine45fce592014-01-15 16:51:56 +010041};
42
Kuninori Morimoto5be50952017-03-15 04:44:00 +000043#define simple_priv_to_card(priv) (&(priv)->snd_card)
Kuninori Morimoto7e3353d2016-08-26 03:06:23 +000044#define simple_priv_to_props(priv, i) ((priv)->dai_props + (i))
Kuninori Morimoto5be50952017-03-15 04:44:00 +000045#define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev)
46#define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i))
Kuninori Morimotof531913f2014-09-09 21:37:57 -070047
Kuninori Morimoto44c16af2016-08-08 06:02:07 +000048#define DAI "sound-dai"
49#define CELL "#sound-dai-cells"
Kuninori Morimoto548563f2016-05-31 08:59:01 +000050#define PREFIX "simple-audio-card,"
51
Kuninori Morimoto9eac3612016-05-31 08:59:46 +000052#define asoc_simple_card_init_hp(card, sjack, prefix)\
53 asoc_simple_card_init_jack(card, sjack, 1, prefix)
54#define asoc_simple_card_init_mic(card, sjack, prefix)\
55 asoc_simple_card_init_jack(card, sjack, 0, prefix)
56static int asoc_simple_card_init_jack(struct snd_soc_card *card,
57 struct asoc_simple_jack *sjack,
58 int is_hp, char *prefix)
59{
60 struct device *dev = card->dev;
61 enum of_gpio_flags flags;
62 char prop[128];
63 char *pin_name;
64 char *gpio_name;
65 int mask;
66 int det;
67
68 sjack->gpio.gpio = -ENOENT;
69
70 if (is_hp) {
71 snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix);
72 pin_name = "Headphones";
73 gpio_name = "Headphone detection";
74 mask = SND_JACK_HEADPHONE;
75 } else {
76 snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix);
77 pin_name = "Mic Jack";
78 gpio_name = "Mic detection";
79 mask = SND_JACK_MICROPHONE;
80 }
81
82 det = of_get_named_gpio_flags(dev->of_node, prop, 0, &flags);
83 if (det == -EPROBE_DEFER)
84 return -EPROBE_DEFER;
85
86 if (gpio_is_valid(det)) {
87 sjack->pin.pin = pin_name;
88 sjack->pin.mask = mask;
89
90 sjack->gpio.name = gpio_name;
91 sjack->gpio.report = mask;
92 sjack->gpio.gpio = det;
93 sjack->gpio.invert = !!(flags & OF_GPIO_ACTIVE_LOW);
94 sjack->gpio.debounce_time = 150;
95
96 snd_soc_card_jack_new(card, pin_name, mask,
97 &sjack->jack,
98 &sjack->pin, 1);
99
100 snd_soc_jack_add_gpios(&sjack->jack, 1,
101 &sjack->gpio);
102 }
103
104 return 0;
105}
106
107static void asoc_simple_card_remove_jack(struct asoc_simple_jack *sjack)
108{
109 if (gpio_is_valid(sjack->gpio.gpio))
110 snd_soc_jack_free_gpios(&sjack->jack, 1, &sjack->gpio);
111}
112
Jyri Sarhaf9911802015-01-13 21:16:34 +0200113static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
114{
115 struct snd_soc_pcm_runtime *rtd = substream->private_data;
116 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
117 struct simple_dai_props *dai_props =
Kuninori Morimotoc9a23ea2016-08-26 03:06:51 +0000118 simple_priv_to_props(priv, rtd->num);
Jyri Sarhaf9911802015-01-13 21:16:34 +0200119 int ret;
120
121 ret = clk_prepare_enable(dai_props->cpu_dai.clk);
122 if (ret)
123 return ret;
Kuninori Morimoto387f5822016-08-26 03:07:59 +0000124
Jyri Sarhaf9911802015-01-13 21:16:34 +0200125 ret = clk_prepare_enable(dai_props->codec_dai.clk);
126 if (ret)
127 clk_disable_unprepare(dai_props->cpu_dai.clk);
128
129 return ret;
130}
131
132static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
133{
134 struct snd_soc_pcm_runtime *rtd = substream->private_data;
135 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
136 struct simple_dai_props *dai_props =
Kuninori Morimotoc9a23ea2016-08-26 03:06:51 +0000137 simple_priv_to_props(priv, rtd->num);
Jyri Sarhaf9911802015-01-13 21:16:34 +0200138
139 clk_disable_unprepare(dai_props->cpu_dai.clk);
140
141 clk_disable_unprepare(dai_props->codec_dai.clk);
142}
143
Andrew Lunn2942a0e2014-05-22 17:31:49 +0200144static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
145 struct snd_pcm_hw_params *params)
146{
147 struct snd_soc_pcm_runtime *rtd = substream->private_data;
148 struct snd_soc_dai *codec_dai = rtd->codec_dai;
Arnaud Pouliquene2257972015-06-05 10:19:06 +0200149 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Andrew Lunn2942a0e2014-05-22 17:31:49 +0200150 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
Kuninori Morimotoc9a23ea2016-08-26 03:06:51 +0000151 struct simple_dai_props *dai_props =
152 simple_priv_to_props(priv, rtd->num);
Arnaud Pouliquen85a4bfd2015-06-05 10:19:05 +0200153 unsigned int mclk, mclk_fs = 0;
Andrew Lunn2942a0e2014-05-22 17:31:49 +0200154 int ret = 0;
155
Arnaud Pouliquen85a4bfd2015-06-05 10:19:05 +0200156 if (priv->mclk_fs)
157 mclk_fs = priv->mclk_fs;
158 else if (dai_props->mclk_fs)
159 mclk_fs = dai_props->mclk_fs;
160
161 if (mclk_fs) {
162 mclk = params_rate(params) * mclk_fs;
Andrew Lunn2942a0e2014-05-22 17:31:49 +0200163 ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
164 SND_SOC_CLOCK_IN);
Arnaud Pouliquene2257972015-06-05 10:19:06 +0200165 if (ret && ret != -ENOTSUPP)
166 goto err;
167
168 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
169 SND_SOC_CLOCK_OUT);
170 if (ret && ret != -ENOTSUPP)
171 goto err;
Andrew Lunn2942a0e2014-05-22 17:31:49 +0200172 }
Aaro Koskinenee43a1a2016-01-24 00:36:40 +0200173 return 0;
Arnaud Pouliquene2257972015-06-05 10:19:06 +0200174err:
Andrew Lunn2942a0e2014-05-22 17:31:49 +0200175 return ret;
176}
177
Julia Lawall9b6fdef2016-10-15 16:55:49 +0200178static const struct snd_soc_ops asoc_simple_card_ops = {
Jyri Sarhaf9911802015-01-13 21:16:34 +0200179 .startup = asoc_simple_card_startup,
180 .shutdown = asoc_simple_card_shutdown,
Andrew Lunn2942a0e2014-05-22 17:31:49 +0200181 .hw_params = asoc_simple_card_hw_params,
182};
183
Kuninori Morimotof2390882012-04-08 21:17:50 -0700184static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
185{
Nicolin Chen781cbeb2014-04-24 19:14:00 +0800186 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
Kuninori Morimotof2390882012-04-08 21:17:50 -0700187 struct snd_soc_dai *codec = rtd->codec_dai;
188 struct snd_soc_dai *cpu = rtd->cpu_dai;
Kuninori Morimotoc9a23ea2016-08-26 03:06:51 +0000189 struct simple_dai_props *dai_props =
190 simple_priv_to_props(priv, rtd->num);
Mengdong Lin1a497982015-11-18 02:34:11 -0500191 int ret;
Kuninori Morimotof2390882012-04-08 21:17:50 -0700192
Kuninori Morimotod8cb9352016-08-09 05:48:53 +0000193 ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai);
Kuninori Morimotoa4a29922013-01-10 16:49:11 -0800194 if (ret < 0)
195 return ret;
Kuninori Morimotof2390882012-04-08 21:17:50 -0700196
Kuninori Morimotod8cb9352016-08-09 05:48:53 +0000197 ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai);
Kuninori Morimotoa4a29922013-01-10 16:49:11 -0800198 if (ret < 0)
199 return ret;
Kuninori Morimotof2390882012-04-08 21:17:50 -0700200
Kuninori Morimoto9eac3612016-05-31 08:59:46 +0000201 ret = asoc_simple_card_init_hp(rtd->card, &priv->hp_jack, PREFIX);
202 if (ret < 0)
203 return ret;
Dylan Reid3fe24032014-10-01 14:25:20 -0700204
Kuninori Morimoto9eac3612016-05-31 08:59:46 +0000205 ret = asoc_simple_card_init_mic(rtd->card, &priv->hp_jack, PREFIX);
206 if (ret < 0)
207 return ret;
Dylan Reid3fe24032014-10-01 14:25:20 -0700208
Kuninori Morimotof2390882012-04-08 21:17:50 -0700209 return 0;
210}
211
Kuninori Morimoto2d82eeb2014-08-27 20:07:46 -0700212static int asoc_simple_card_dai_link_of(struct device_node *node,
Kuninori Morimotof531913f2014-09-09 21:37:57 -0700213 struct simple_card_data *priv,
Kuninori Morimoto9810f532014-09-09 21:38:24 -0700214 int idx,
Kuninori Morimoto2d82eeb2014-08-27 20:07:46 -0700215 bool is_top_level_node)
Jean-Francois Moine6a91a17bd2014-03-20 11:49:55 +0100216{
Kuninori Morimotof531913f2014-09-09 21:37:57 -0700217 struct device *dev = simple_priv_to_dev(priv);
Kuninori Morimoto9810f532014-09-09 21:38:24 -0700218 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
219 struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
Kuninori Morimoto28abd992016-07-19 02:53:13 +0000220 struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
221 struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
Kuninori Morimoto1b5721b2014-10-27 18:04:52 -0700222 struct device_node *cpu = NULL;
Jun Niee0ae2252015-04-29 18:11:07 +0800223 struct device_node *plat = NULL;
Kuninori Morimoto1b5721b2014-10-27 18:04:52 -0700224 struct device_node *codec = NULL;
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200225 char prop[128];
226 char *prefix = "";
Kuninori Morimoto44c16af2016-08-08 06:02:07 +0000227 int ret, single_cpu;
Jean-Francois Moine6a91a17bd2014-03-20 11:49:55 +0100228
Xiubo Li20804372014-09-03 10:23:39 +0800229 /* For single DAI link & old style of DT node */
Jyri Sarha64872212014-04-24 19:42:00 +0300230 if (is_top_level_node)
Kuninori Morimoto548563f2016-05-31 08:59:01 +0000231 prefix = PREFIX;
Jean-Francois Moine6a91a17bd2014-03-20 11:49:55 +0100232
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200233 snprintf(prop, sizeof(prop), "%scpu", prefix);
Kuninori Morimoto1b5721b2014-10-27 18:04:52 -0700234 cpu = of_get_child_by_name(node, prop);
235
Jun Niee0ae2252015-04-29 18:11:07 +0800236 snprintf(prop, sizeof(prop), "%splat", prefix);
237 plat = of_get_child_by_name(node, prop);
238
Kuninori Morimoto1b5721b2014-10-27 18:04:52 -0700239 snprintf(prop, sizeof(prop), "%scodec", prefix);
240 codec = of_get_child_by_name(node, prop);
241
242 if (!cpu || !codec) {
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200243 ret = -EINVAL;
Nicolin Chen966b8062014-04-24 19:13:59 +0800244 dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200245 goto dai_link_of_err;
Jean-Francois Moine6a91a17bd2014-03-20 11:49:55 +0100246 }
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200247
Kuninori Morimotocecdef32016-06-30 06:02:46 +0000248 ret = asoc_simple_card_parse_daifmt(dev, node, codec,
249 prefix, &dai_link->dai_fmt);
Kuninori Morimoto1b5721b2014-10-27 18:04:52 -0700250 if (ret < 0)
251 goto dai_link_of_err;
252
Kuninori Morimotof93b6462016-08-26 03:05:58 +0000253 of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs);
Arnaud Pouliquen85a4bfd2015-06-05 10:19:05 +0200254
Kuninori Morimoto44c16af2016-08-08 06:02:07 +0000255 ret = asoc_simple_card_parse_cpu(cpu, dai_link,
256 DAI, CELL, &single_cpu);
257 if (ret < 0)
258 goto dai_link_of_err;
259
260 ret = asoc_simple_card_parse_codec(codec, dai_link, DAI, CELL);
261 if (ret < 0)
262 goto dai_link_of_err;
263
264 ret = asoc_simple_card_parse_platform(plat, dai_link, DAI, CELL);
265 if (ret < 0)
266 goto dai_link_of_err;
267
Kuninori Morimotoc3b19c82016-08-08 06:03:35 +0000268 ret = snd_soc_of_parse_tdm_slot(cpu, &cpu_dai->tx_slot_mask,
269 &cpu_dai->rx_slot_mask,
270 &cpu_dai->slots,
271 &cpu_dai->slot_width);
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200272 if (ret < 0)
273 goto dai_link_of_err;
274
Kuninori Morimotoc3b19c82016-08-08 06:03:35 +0000275 ret = snd_soc_of_parse_tdm_slot(codec, &codec_dai->tx_slot_mask,
276 &codec_dai->rx_slot_mask,
277 &codec_dai->slots,
278 &codec_dai->slot_width);
Kuninori Morimoto5fb9cb12016-05-20 09:40:41 +0000279 if (ret < 0)
280 goto dai_link_of_err;
281
Kuninori Morimotoe984fd62017-01-23 07:29:42 +0000282 ret = asoc_simple_card_parse_clk_cpu(dev, cpu, dai_link, cpu_dai);
Kuninori Morimoto28abd992016-07-19 02:53:13 +0000283 if (ret < 0)
284 goto dai_link_of_err;
285
Kuninori Morimotoe984fd62017-01-23 07:29:42 +0000286 ret = asoc_simple_card_parse_clk_codec(dev, codec, dai_link, codec_dai);
Kuninori Morimoto28abd992016-07-19 02:53:13 +0000287 if (ret < 0)
288 goto dai_link_of_err;
289
Kuninori Morimotoc9583742016-08-09 05:50:02 +0000290 ret = asoc_simple_card_canonicalize_dailink(dai_link);
291 if (ret < 0)
Nicolin Chen781cbeb2014-04-24 19:14:00 +0800292 goto dai_link_of_err;
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200293
Kuninori Morimoto2e8d1c72016-07-11 23:57:34 +0000294 ret = asoc_simple_card_set_dailink_name(dev, dai_link,
295 "%s-%s",
296 dai_link->cpu_dai_name,
297 dai_link->codec_dai_name);
298 if (ret < 0)
Vishal Thanki31f30322015-03-03 18:59:00 +0530299 goto dai_link_of_err;
Vishal Thanki31f30322015-03-03 18:59:00 +0530300
Andrew Lunn2942a0e2014-05-22 17:31:49 +0200301 dai_link->ops = &asoc_simple_card_ops;
Kuninori Morimotoa5960bd2014-08-27 20:08:27 -0700302 dai_link->init = asoc_simple_card_dai_init;
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200303
304 dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
Lars-Peter Clausen1efb53a2015-03-24 01:07:08 +0000305 dev_dbg(dev, "\tformat : %04x\n", dai_link->dai_fmt);
306 dev_dbg(dev, "\tcpu : %s / %d\n",
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200307 dai_link->cpu_dai_name,
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200308 dai_props->cpu_dai.sysclk);
Lars-Peter Clausen1efb53a2015-03-24 01:07:08 +0000309 dev_dbg(dev, "\tcodec : %s / %d\n",
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200310 dai_link->codec_dai_name,
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200311 dai_props->codec_dai.sysclk);
312
Kuninori Morimoto16f1de62016-08-10 02:20:43 +0000313 asoc_simple_card_canonicalize_cpu(dai_link, single_cpu);
Kuninori Morimoto179949b2014-08-27 20:08:06 -0700314
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200315dai_link_of_err:
Kuninori Morimoto1b5721b2014-10-27 18:04:52 -0700316 of_node_put(cpu);
317 of_node_put(codec);
318
Jean-Francois Moine6a91a17bd2014-03-20 11:49:55 +0100319 return ret;
320}
321
Nikita Yushchenko899a2472016-09-26 12:56:51 +0300322static int asoc_simple_card_parse_aux_devs(struct device_node *node,
323 struct simple_card_data *priv)
324{
325 struct device *dev = simple_priv_to_dev(priv);
326 struct device_node *aux_node;
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000327 struct snd_soc_card *card = simple_priv_to_card(priv);
Nikita Yushchenko899a2472016-09-26 12:56:51 +0300328 int i, n, len;
329
330 if (!of_find_property(node, PREFIX "aux-devs", &len))
331 return 0; /* Ok to have no aux-devs */
332
333 n = len / sizeof(__be32);
334 if (n <= 0)
335 return -EINVAL;
336
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000337 card->aux_dev = devm_kzalloc(dev,
338 n * sizeof(*card->aux_dev), GFP_KERNEL);
339 if (!card->aux_dev)
Nikita Yushchenko899a2472016-09-26 12:56:51 +0300340 return -ENOMEM;
341
342 for (i = 0; i < n; i++) {
343 aux_node = of_parse_phandle(node, PREFIX "aux-devs", i);
344 if (!aux_node)
345 return -EINVAL;
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000346 card->aux_dev[i].codec_of_node = aux_node;
Nikita Yushchenko899a2472016-09-26 12:56:51 +0300347 }
348
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000349 card->num_aux_devs = n;
Nikita Yushchenko899a2472016-09-26 12:56:51 +0300350 return 0;
351}
352
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900353static int asoc_simple_card_parse_of(struct device_node *node,
Kuninori Morimotof531913f2014-09-09 21:37:57 -0700354 struct simple_card_data *priv)
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900355{
Kuninori Morimotof531913f2014-09-09 21:37:57 -0700356 struct device *dev = simple_priv_to_dev(priv);
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000357 struct snd_soc_card *card = simple_priv_to_card(priv);
Kuninori Morimotoa03b0542016-08-26 03:05:16 +0000358 struct device_node *dai_link;
Xiubo Lid4c22092013-12-23 12:57:01 +0800359 int ret;
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900360
Xiubo Li20804372014-09-03 10:23:39 +0800361 if (!node)
362 return -EINVAL;
363
Kuninori Morimotoa03b0542016-08-26 03:05:16 +0000364 dai_link = of_get_child_by_name(node, PREFIX "dai-link");
365
Xiubo Li0dd4fc32014-09-10 09:59:55 +0800366 /* The off-codec widgets */
Kuninori Morimoto548563f2016-05-31 08:59:01 +0000367 if (of_property_read_bool(node, PREFIX "widgets")) {
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000368 ret = snd_soc_of_parse_audio_simple_widgets(card,
Kuninori Morimoto548563f2016-05-31 08:59:01 +0000369 PREFIX "widgets");
Xiubo Li9d681f52014-02-08 15:59:53 +0800370 if (ret)
Kuninori Morimotoa03b0542016-08-26 03:05:16 +0000371 goto card_parse_end;
Xiubo Li9d681f52014-02-08 15:59:53 +0800372 }
373
Xiubo Lid4c22092013-12-23 12:57:01 +0800374 /* DAPM routes */
Kuninori Morimoto548563f2016-05-31 08:59:01 +0000375 if (of_property_read_bool(node, PREFIX "routing")) {
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000376 ret = snd_soc_of_parse_audio_routing(card,
Kuninori Morimoto548563f2016-05-31 08:59:01 +0000377 PREFIX "routing");
Xiubo Lif87a3e82014-01-07 09:13:42 +0800378 if (ret)
Kuninori Morimotoa03b0542016-08-26 03:05:16 +0000379 goto card_parse_end;
Xiubo Lif87a3e82014-01-07 09:13:42 +0800380 }
Xiubo Lid4c22092013-12-23 12:57:01 +0800381
Andrew Lunn2942a0e2014-05-22 17:31:49 +0200382 /* Factor to mclk, used in hw_params() */
Kuninori Morimotof93b6462016-08-26 03:05:58 +0000383 of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs);
Andrew Lunn2942a0e2014-05-22 17:31:49 +0200384
Xiubo Li20804372014-09-03 10:23:39 +0800385 /* Single/Muti DAI link(s) & New style of DT node */
Kuninori Morimotoa03b0542016-08-26 03:05:16 +0000386 if (dai_link) {
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200387 struct device_node *np = NULL;
Kuninori Morimotoa44a7502014-08-27 20:08:47 -0700388 int i = 0;
389
390 for_each_child_of_node(node, np) {
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200391 dev_dbg(dev, "\tlink %d:\n", i);
Kuninori Morimotof531913f2014-09-09 21:37:57 -0700392 ret = asoc_simple_card_dai_link_of(np, priv,
Kuninori Morimoto9810f532014-09-09 21:38:24 -0700393 i, false);
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200394 if (ret < 0) {
395 of_node_put(np);
Kuninori Morimotoa03b0542016-08-26 03:05:16 +0000396 goto card_parse_end;
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200397 }
Kuninori Morimotoa44a7502014-08-27 20:08:47 -0700398 i++;
Jyri Sarhab3ca11f2014-03-24 12:15:25 +0200399 }
400 } else {
Xiubo Li20804372014-09-03 10:23:39 +0800401 /* For single DAI link & old style of DT node */
Kuninori Morimoto9810f532014-09-09 21:38:24 -0700402 ret = asoc_simple_card_dai_link_of(node, priv, 0, true);
Jean-Francois Moine6a91a17bd2014-03-20 11:49:55 +0100403 if (ret < 0)
Kuninori Morimotoa03b0542016-08-26 03:05:16 +0000404 goto card_parse_end;
Jean-Francois Moinee512e002014-03-11 10:03:40 +0100405 }
Xiubo Lidd41e0c2013-12-20 14:39:50 +0800406
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000407 ret = asoc_simple_card_parse_card_name(card, PREFIX);
Nikita Yushchenko899a2472016-09-26 12:56:51 +0300408 if (ret < 0)
409 goto card_parse_end;
410
411 ret = asoc_simple_card_parse_aux_devs(node, priv);
Kuninori Morimotof687d902014-02-27 18:25:24 -0800412
Kuninori Morimotoa03b0542016-08-26 03:05:16 +0000413card_parse_end:
414 of_node_put(dai_link);
415
416 return ret;
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900417}
418
Kuninori Morimotof2390882012-04-08 21:17:50 -0700419static int asoc_simple_card_probe(struct platform_device *pdev)
420{
Jean-Francois Moine45fce592014-01-15 16:51:56 +0100421 struct simple_card_data *priv;
Jean-Francois Moine5ca8ba42014-01-15 16:51:45 +0100422 struct snd_soc_dai_link *dai_link;
Kuninori Morimotob0133d92016-08-26 03:10:25 +0000423 struct simple_dai_props *dai_props;
Kuninori Morimotof89983e2012-12-25 22:52:33 -0800424 struct device *dev = &pdev->dev;
Kuninori Morimotodcee9bf2017-03-15 04:43:21 +0000425 struct device_node *np = dev->of_node;
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000426 struct snd_soc_card *card;
Kuninori Morimoto2c86dda2016-08-26 03:09:38 +0000427 int num, ret;
Jean-Francois Moine6a91a17bd2014-03-20 11:49:55 +0100428
Xiubo Li0dd4fc32014-09-10 09:59:55 +0800429 /* Get the number of DAI links */
Kuninori Morimoto548563f2016-05-31 08:59:01 +0000430 if (np && of_get_child_by_name(np, PREFIX "dai-link"))
Kuninori Morimoto2c86dda2016-08-26 03:09:38 +0000431 num = of_get_child_count(np);
Xiubo Li20804372014-09-03 10:23:39 +0800432 else
Kuninori Morimoto2c86dda2016-08-26 03:09:38 +0000433 num = 1;
Kuninori Morimotof2390882012-04-08 21:17:50 -0700434
Xiubo Li0dd4fc32014-09-10 09:59:55 +0800435 /* Allocate the private data and the DAI link array */
Kuninori Morimotob0133d92016-08-26 03:10:25 +0000436 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
Jean-Francois Moineca65b492014-01-15 16:51:52 +0100437 if (!priv)
Xiubo Lica919fe2014-01-14 12:35:32 +0800438 return -ENOMEM;
439
Kuninori Morimotob0133d92016-08-26 03:10:25 +0000440 dai_props = devm_kzalloc(dev, sizeof(*dai_props) * num, GFP_KERNEL);
441 dai_link = devm_kzalloc(dev, sizeof(*dai_link) * num, GFP_KERNEL);
442 if (!dai_props || !dai_link)
443 return -ENOMEM;
444
445 priv->dai_props = dai_props;
446 priv->dai_link = dai_link;
447
Xiubo Li0dd4fc32014-09-10 09:59:55 +0800448 /* Init snd_soc_card */
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000449 card = simple_priv_to_card(priv);
450 card->owner = THIS_MODULE;
451 card->dev = dev;
452 card->dai_link = priv->dai_link;
453 card->num_links = num;
Xiubo Lica919fe2014-01-14 12:35:32 +0800454
Jean-Francois Moine201a0ea2014-01-15 16:51:41 +0100455 if (np && of_device_is_available(np)) {
456
Kuninori Morimotof531913f2014-09-09 21:37:57 -0700457 ret = asoc_simple_card_parse_of(np, priv);
Xiubo Lica919fe2014-01-14 12:35:32 +0800458 if (ret < 0) {
459 if (ret != -EPROBE_DEFER)
460 dev_err(dev, "parse error %d\n", ret);
Jean-Francois Moinee512e002014-03-11 10:03:40 +0100461 goto err;
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900462 }
Jean-Francois Moine6a91a17bd2014-03-20 11:49:55 +0100463
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900464 } else {
Jean-Francois Moineca65b492014-01-15 16:51:52 +0100465 struct asoc_simple_card_info *cinfo;
466
467 cinfo = dev->platform_data;
468 if (!cinfo) {
Xiubo Li34787d0a2014-01-09 17:49:40 +0800469 dev_err(dev, "no info for asoc-simple-card\n");
470 return -EINVAL;
471 }
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900472
Nicolin Chen781cbeb2014-04-24 19:14:00 +0800473 if (!cinfo->name ||
474 !cinfo->codec_dai.name ||
475 !cinfo->codec ||
476 !cinfo->platform ||
Jean-Francois Moine7722f832014-01-15 16:51:33 +0100477 !cinfo->cpu_dai.name) {
478 dev_err(dev, "insufficient asoc_simple_card_info settings\n");
479 return -EINVAL;
480 }
Jean-Francois Moine2bee9912014-01-15 16:51:37 +0100481
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000482 card->name = (cinfo->card) ? cinfo->card : cinfo->name;
Jean-Francois Moine5ca8ba42014-01-15 16:51:45 +0100483 dai_link->name = cinfo->name;
484 dai_link->stream_name = cinfo->name;
485 dai_link->platform_name = cinfo->platform;
486 dai_link->codec_name = cinfo->codec;
Jean-Francois Moine52008472014-01-15 16:51:48 +0100487 dai_link->cpu_dai_name = cinfo->cpu_dai.name;
488 dai_link->codec_dai_name = cinfo->codec_dai.name;
Lars-Peter Clausen1efb53a2015-03-24 01:07:08 +0000489 dai_link->dai_fmt = cinfo->daifmt;
Kuninori Morimotoa5960bd2014-08-27 20:08:27 -0700490 dai_link->init = asoc_simple_card_dai_init;
Jean-Francois Moinecf7dc232014-03-20 10:52:41 +0100491 memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
492 sizeof(priv->dai_props->cpu_dai));
493 memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai,
494 sizeof(priv->dai_props->codec_dai));
Kuninori Morimotof2390882012-04-08 21:17:50 -0700495 }
496
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000497 snd_soc_card_set_drvdata(card, priv);
Xiubo Liba194a42014-01-13 17:08:08 +0800498
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000499 ret = devm_snd_soc_register_card(dev, card);
Xiubo Lie3c4a282014-09-01 14:46:52 +0800500 if (ret >= 0)
501 return ret;
Jean-Francois Moinee512e002014-03-11 10:03:40 +0100502err:
Kuninori Morimoto5be50952017-03-15 04:44:00 +0000503 asoc_simple_card_clean_reference(card);
Kuninori Morimoto387f5822016-08-26 03:07:59 +0000504
Jean-Francois Moinee512e002014-03-11 10:03:40 +0100505 return ret;
Kuninori Morimotof2390882012-04-08 21:17:50 -0700506}
507
Xiubo Lie3c4a282014-09-01 14:46:52 +0800508static int asoc_simple_card_remove(struct platform_device *pdev)
509{
Dylan Reid3fe24032014-10-01 14:25:20 -0700510 struct snd_soc_card *card = platform_get_drvdata(pdev);
511 struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
512
Kuninori Morimoto9eac3612016-05-31 08:59:46 +0000513 asoc_simple_card_remove_jack(&priv->hp_jack);
514 asoc_simple_card_remove_jack(&priv->mic_jack);
Dylan Reid3fe24032014-10-01 14:25:20 -0700515
Kuninori Morimoto885fc052016-08-10 02:21:42 +0000516 return asoc_simple_card_clean_reference(card);
Xiubo Lie3c4a282014-09-01 14:46:52 +0800517}
518
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900519static const struct of_device_id asoc_simple_of_match[] = {
520 { .compatible = "simple-audio-card", },
521 {},
522};
523MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
524
Kuninori Morimotof2390882012-04-08 21:17:50 -0700525static struct platform_driver asoc_simple_card = {
526 .driver = {
Nicolin Chen781cbeb2014-04-24 19:14:00 +0800527 .name = "asoc-simple-card",
Peter Ujfalusi7c376712016-05-09 13:38:10 +0300528 .pm = &snd_soc_pm_ops,
Kuninori Morimotofa558c22013-11-20 15:25:02 +0900529 .of_match_table = asoc_simple_of_match,
Kuninori Morimotof2390882012-04-08 21:17:50 -0700530 },
Nicolin Chen781cbeb2014-04-24 19:14:00 +0800531 .probe = asoc_simple_card_probe,
Xiubo Lie3c4a282014-09-01 14:46:52 +0800532 .remove = asoc_simple_card_remove,
Kuninori Morimotof2390882012-04-08 21:17:50 -0700533};
534
535module_platform_driver(asoc_simple_card);
536
Fabio Estevamc445be32013-08-23 14:35:17 -0300537MODULE_ALIAS("platform:asoc-simple-card");
Kuninori Morimotoa1dbfd02016-08-26 03:07:28 +0000538MODULE_LICENSE("GPL v2");
Kuninori Morimotof2390882012-04-08 21:17:50 -0700539MODULE_DESCRIPTION("ASoC Simple Sound Card");
540MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");