1 // SPDX-License-Identifier: GPL-2.0 2 // 3 // Copyright (c) 2020 BayLibre, SAS. 4 // Author: Jerome Brunet <jbrunet@baylibre.com> 5 6 #include <linux/module.h> 7 #include <linux/of_platform.h> 8 #include <sound/soc.h> 9 10 #include "meson-card.h" 11 12 int meson_card_i2s_set_sysclk(struct snd_pcm_substream *substream, 13 struct snd_pcm_hw_params *params, 14 unsigned int mclk_fs) 15 { 16 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 17 struct snd_soc_dai *codec_dai; 18 unsigned int mclk; 19 int ret, i; 20 21 if (!mclk_fs) 22 return 0; 23 24 mclk = params_rate(params) * mclk_fs; 25 26 for_each_rtd_codec_dais(rtd, i, codec_dai) { 27 ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, 28 SND_SOC_CLOCK_IN); 29 if (ret && ret != -ENOTSUPP) 30 return ret; 31 } 32 33 ret = snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0), 0, mclk, 34 SND_SOC_CLOCK_OUT); 35 if (ret && ret != -ENOTSUPP) 36 return ret; 37 38 return 0; 39 } 40 EXPORT_SYMBOL_GPL(meson_card_i2s_set_sysclk); 41 42 int meson_card_reallocate_links(struct snd_soc_card *card, 43 unsigned int num_links) 44 { 45 struct meson_card *priv = snd_soc_card_get_drvdata(card); 46 struct snd_soc_dai_link *links; 47 void **ldata; 48 49 links = krealloc(priv->card.dai_link, 50 num_links * sizeof(*priv->card.dai_link), 51 GFP_KERNEL | __GFP_ZERO); 52 if (!links) 53 goto err_links; 54 55 ldata = krealloc(priv->link_data, 56 num_links * sizeof(*priv->link_data), 57 GFP_KERNEL | __GFP_ZERO); 58 if (!ldata) 59 goto err_ldata; 60 61 priv->card.dai_link = links; 62 priv->link_data = ldata; 63 priv->card.num_links = num_links; 64 return 0; 65 66 err_ldata: 67 kfree(links); 68 err_links: 69 dev_err(priv->card.dev, "failed to allocate links\n"); 70 return -ENOMEM; 71 72 } 73 EXPORT_SYMBOL_GPL(meson_card_reallocate_links); 74 75 int meson_card_parse_dai(struct snd_soc_card *card, 76 struct device_node *node, 77 struct device_node **dai_of_node, 78 const char **dai_name) 79 { 80 struct of_phandle_args args; 81 int ret; 82 83 if (!dai_name || !dai_of_node || !node) 84 return -EINVAL; 85 86 ret = of_parse_phandle_with_args(node, "sound-dai", 87 "#sound-dai-cells", 0, &args); 88 if (ret) 89 return dev_err_probe(card->dev, ret, "can't parse dai\n"); 90 91 *dai_of_node = args.np; 92 93 return snd_soc_get_dai_name(&args, dai_name); 94 } 95 EXPORT_SYMBOL_GPL(meson_card_parse_dai); 96 97 static int meson_card_set_link_name(struct snd_soc_card *card, 98 struct snd_soc_dai_link *link, 99 struct device_node *node, 100 const char *prefix) 101 { 102 char *name = devm_kasprintf(card->dev, GFP_KERNEL, "%s.%s", 103 prefix, node->full_name); 104 if (!name) 105 return -ENOMEM; 106 107 link->name = name; 108 link->stream_name = name; 109 110 return 0; 111 } 112 113 unsigned int meson_card_parse_daifmt(struct device_node *node, 114 struct device_node *cpu_node) 115 { 116 struct device_node *bitclkmaster = NULL; 117 struct device_node *framemaster = NULL; 118 unsigned int daifmt; 119 120 daifmt = snd_soc_daifmt_parse_format(node, NULL); 121 122 snd_soc_daifmt_parse_clock_provider_as_phandle(node, NULL, &bitclkmaster, &framemaster); 123 124 /* If no master is provided, default to cpu master */ 125 if (!bitclkmaster || bitclkmaster == cpu_node) { 126 daifmt |= (!framemaster || framemaster == cpu_node) ? 127 SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBS_CFM; 128 } else { 129 daifmt |= (!framemaster || framemaster == cpu_node) ? 130 SND_SOC_DAIFMT_CBM_CFS : SND_SOC_DAIFMT_CBM_CFM; 131 } 132 133 of_node_put(bitclkmaster); 134 of_node_put(framemaster); 135 136 return daifmt; 137 } 138 EXPORT_SYMBOL_GPL(meson_card_parse_daifmt); 139 140 int meson_card_set_be_link(struct snd_soc_card *card, 141 struct snd_soc_dai_link *link, 142 struct device_node *node) 143 { 144 struct snd_soc_dai_link_component *codec; 145 struct device_node *np; 146 int ret, num_codecs; 147 148 num_codecs = of_get_child_count(node); 149 if (!num_codecs) { 150 dev_err(card->dev, "be link %s has no codec\n", 151 node->full_name); 152 return -EINVAL; 153 } 154 155 codec = devm_kcalloc(card->dev, num_codecs, sizeof(*codec), GFP_KERNEL); 156 if (!codec) 157 return -ENOMEM; 158 159 link->codecs = codec; 160 link->num_codecs = num_codecs; 161 162 for_each_child_of_node(node, np) { 163 ret = meson_card_parse_dai(card, np, &codec->of_node, 164 &codec->dai_name); 165 if (ret) { 166 of_node_put(np); 167 return ret; 168 } 169 170 codec++; 171 } 172 173 ret = meson_card_set_link_name(card, link, node, "be"); 174 if (ret) 175 dev_err(card->dev, "error setting %pOFn link name\n", np); 176 177 return ret; 178 } 179 EXPORT_SYMBOL_GPL(meson_card_set_be_link); 180 181 int meson_card_set_fe_link(struct snd_soc_card *card, 182 struct snd_soc_dai_link *link, 183 struct device_node *node, 184 bool is_playback) 185 { 186 link->codecs = &asoc_dummy_dlc; 187 link->num_codecs = 1; 188 189 link->dynamic = 1; 190 link->dpcm_merged_format = 1; 191 link->dpcm_merged_chan = 1; 192 link->dpcm_merged_rate = 1; 193 194 if (is_playback) 195 link->dpcm_playback = 1; 196 else 197 link->dpcm_capture = 1; 198 199 return meson_card_set_link_name(card, link, node, "fe"); 200 } 201 EXPORT_SYMBOL_GPL(meson_card_set_fe_link); 202 203 static int meson_card_add_links(struct snd_soc_card *card) 204 { 205 struct meson_card *priv = snd_soc_card_get_drvdata(card); 206 struct device_node *node = card->dev->of_node; 207 struct device_node *np; 208 int num, i, ret; 209 210 num = of_get_child_count(node); 211 if (!num) { 212 dev_err(card->dev, "card has no links\n"); 213 return -EINVAL; 214 } 215 216 ret = meson_card_reallocate_links(card, num); 217 if (ret) 218 return ret; 219 220 i = 0; 221 for_each_child_of_node(node, np) { 222 ret = priv->match_data->add_link(card, np, &i); 223 if (ret) { 224 of_node_put(np); 225 return ret; 226 } 227 228 i++; 229 } 230 231 return 0; 232 } 233 234 static int meson_card_parse_of_optional(struct snd_soc_card *card, 235 const char *propname, 236 int (*func)(struct snd_soc_card *c, 237 const char *p)) 238 { 239 /* If property is not provided, don't fail ... */ 240 if (!of_property_read_bool(card->dev->of_node, propname)) 241 return 0; 242 243 /* ... but do fail if it is provided and the parsing fails */ 244 return func(card, propname); 245 } 246 247 static void meson_card_clean_references(struct meson_card *priv) 248 { 249 struct snd_soc_card *card = &priv->card; 250 struct snd_soc_dai_link *link; 251 struct snd_soc_dai_link_component *codec; 252 struct snd_soc_aux_dev *aux; 253 int i, j; 254 255 if (card->dai_link) { 256 for_each_card_prelinks(card, i, link) { 257 if (link->cpus) 258 of_node_put(link->cpus->of_node); 259 for_each_link_codecs(link, j, codec) 260 of_node_put(codec->of_node); 261 } 262 } 263 264 if (card->aux_dev) { 265 for_each_card_pre_auxs(card, i, aux) 266 of_node_put(aux->dlc.of_node); 267 } 268 269 kfree(card->dai_link); 270 kfree(priv->link_data); 271 } 272 273 int meson_card_probe(struct platform_device *pdev) 274 { 275 const struct meson_card_match_data *data; 276 struct device *dev = &pdev->dev; 277 struct meson_card *priv; 278 int ret; 279 280 data = of_device_get_match_data(dev); 281 if (!data) { 282 dev_err(dev, "failed to match device\n"); 283 return -ENODEV; 284 } 285 286 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 287 if (!priv) 288 return -ENOMEM; 289 290 platform_set_drvdata(pdev, priv); 291 snd_soc_card_set_drvdata(&priv->card, priv); 292 293 priv->card.owner = THIS_MODULE; 294 priv->card.dev = dev; 295 priv->card.driver_name = dev->driver->name; 296 priv->match_data = data; 297 298 ret = snd_soc_of_parse_card_name(&priv->card, "model"); 299 if (ret < 0) 300 return ret; 301 302 ret = meson_card_parse_of_optional(&priv->card, "audio-routing", 303 snd_soc_of_parse_audio_routing); 304 if (ret) { 305 dev_err(dev, "error while parsing routing\n"); 306 return ret; 307 } 308 309 ret = meson_card_parse_of_optional(&priv->card, "audio-widgets", 310 snd_soc_of_parse_audio_simple_widgets); 311 if (ret) { 312 dev_err(dev, "error while parsing widgets\n"); 313 return ret; 314 } 315 316 ret = meson_card_add_links(&priv->card); 317 if (ret) 318 goto out_err; 319 320 ret = snd_soc_of_parse_aux_devs(&priv->card, "audio-aux-devs"); 321 if (ret) 322 goto out_err; 323 324 ret = devm_snd_soc_register_card(dev, &priv->card); 325 if (ret) 326 goto out_err; 327 328 return 0; 329 330 out_err: 331 meson_card_clean_references(priv); 332 return ret; 333 } 334 EXPORT_SYMBOL_GPL(meson_card_probe); 335 336 int meson_card_remove(struct platform_device *pdev) 337 { 338 struct meson_card *priv = platform_get_drvdata(pdev); 339 340 meson_card_clean_references(priv); 341 342 return 0; 343 } 344 EXPORT_SYMBOL_GPL(meson_card_remove); 345 346 MODULE_DESCRIPTION("Amlogic Sound Card Utils"); 347 MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); 348 MODULE_LICENSE("GPL v2"); 349