odroid.c (9114B)
1// SPDX-License-Identifier: GPL-2.0 2// 3// Copyright (C) 2017 Samsung Electronics Co., Ltd. 4 5#include <linux/clk.h> 6#include <linux/clk-provider.h> 7#include <linux/of.h> 8#include <linux/of_device.h> 9#include <linux/module.h> 10#include <sound/soc.h> 11#include <sound/pcm_params.h> 12#include "i2s.h" 13#include "i2s-regs.h" 14 15struct odroid_priv { 16 struct snd_soc_card card; 17 struct clk *clk_i2s_bus; 18 struct clk *sclk_i2s; 19 20 /* Spinlock protecting fields below */ 21 spinlock_t lock; 22 unsigned int be_sample_rate; 23 bool be_active; 24}; 25 26static int odroid_card_fe_startup(struct snd_pcm_substream *substream) 27{ 28 struct snd_pcm_runtime *runtime = substream->runtime; 29 30 snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2); 31 32 return 0; 33} 34 35static int odroid_card_fe_hw_params(struct snd_pcm_substream *substream, 36 struct snd_pcm_hw_params *params) 37{ 38 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 39 struct odroid_priv *priv = snd_soc_card_get_drvdata(rtd->card); 40 unsigned long flags; 41 int ret = 0; 42 43 spin_lock_irqsave(&priv->lock, flags); 44 if (priv->be_active && priv->be_sample_rate != params_rate(params)) 45 ret = -EINVAL; 46 spin_unlock_irqrestore(&priv->lock, flags); 47 48 return ret; 49} 50 51static const struct snd_soc_ops odroid_card_fe_ops = { 52 .startup = odroid_card_fe_startup, 53 .hw_params = odroid_card_fe_hw_params, 54}; 55 56static int odroid_card_be_hw_params(struct snd_pcm_substream *substream, 57 struct snd_pcm_hw_params *params) 58{ 59 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 60 struct odroid_priv *priv = snd_soc_card_get_drvdata(rtd->card); 61 unsigned int pll_freq, rclk_freq, rfs; 62 unsigned long flags; 63 int ret; 64 65 switch (params_rate(params)) { 66 case 64000: 67 pll_freq = 196608001U; 68 rfs = 384; 69 break; 70 case 44100: 71 case 88200: 72 pll_freq = 180633609U; 73 rfs = 512; 74 break; 75 case 32000: 76 case 48000: 77 case 96000: 78 pll_freq = 196608001U; 79 rfs = 512; 80 break; 81 default: 82 return -EINVAL; 83 } 84 85 ret = clk_set_rate(priv->clk_i2s_bus, pll_freq / 2 + 1); 86 if (ret < 0) 87 return ret; 88 89 /* 90 * We add 2 to the rclk_freq value in order to avoid too low clock 91 * frequency values due to the EPLL output frequency not being exact 92 * multiple of the audio sampling rate. 93 */ 94 rclk_freq = params_rate(params) * rfs + 2; 95 96 ret = clk_set_rate(priv->sclk_i2s, rclk_freq); 97 if (ret < 0) 98 return ret; 99 100 if (rtd->num_codecs > 1) { 101 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 1); 102 103 ret = snd_soc_dai_set_sysclk(codec_dai, 0, rclk_freq, 104 SND_SOC_CLOCK_IN); 105 if (ret < 0) 106 return ret; 107 } 108 109 spin_lock_irqsave(&priv->lock, flags); 110 priv->be_sample_rate = params_rate(params); 111 spin_unlock_irqrestore(&priv->lock, flags); 112 113 return 0; 114} 115 116static int odroid_card_be_trigger(struct snd_pcm_substream *substream, int cmd) 117{ 118 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 119 struct odroid_priv *priv = snd_soc_card_get_drvdata(rtd->card); 120 unsigned long flags; 121 122 spin_lock_irqsave(&priv->lock, flags); 123 124 switch (cmd) { 125 case SNDRV_PCM_TRIGGER_START: 126 case SNDRV_PCM_TRIGGER_RESUME: 127 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 128 priv->be_active = true; 129 break; 130 131 case SNDRV_PCM_TRIGGER_STOP: 132 case SNDRV_PCM_TRIGGER_SUSPEND: 133 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 134 priv->be_active = false; 135 break; 136 } 137 138 spin_unlock_irqrestore(&priv->lock, flags); 139 140 return 0; 141} 142 143static const struct snd_soc_ops odroid_card_be_ops = { 144 .hw_params = odroid_card_be_hw_params, 145 .trigger = odroid_card_be_trigger, 146}; 147 148/* DAPM routes for backward compatibility with old DTS */ 149static const struct snd_soc_dapm_route odroid_dapm_routes[] = { 150 { "I2S Playback", NULL, "Mixer DAI TX" }, 151 { "HiFi Playback", NULL, "Mixer DAI TX" }, 152}; 153 154SND_SOC_DAILINK_DEFS(primary, 155 DAILINK_COMP_ARRAY(COMP_EMPTY()), 156 DAILINK_COMP_ARRAY(COMP_DUMMY()), 157 DAILINK_COMP_ARRAY(COMP_PLATFORM("3830000.i2s"))); 158 159SND_SOC_DAILINK_DEFS(mixer, 160 DAILINK_COMP_ARRAY(COMP_DUMMY()), 161 DAILINK_COMP_ARRAY(COMP_EMPTY()), 162 DAILINK_COMP_ARRAY(COMP_DUMMY())); 163 164SND_SOC_DAILINK_DEFS(secondary, 165 DAILINK_COMP_ARRAY(COMP_EMPTY()), 166 DAILINK_COMP_ARRAY(COMP_DUMMY()), 167 DAILINK_COMP_ARRAY(COMP_PLATFORM("3830000.i2s-sec"))); 168 169static struct snd_soc_dai_link odroid_card_dais[] = { 170 { 171 /* Primary FE <-> BE link */ 172 .ops = &odroid_card_fe_ops, 173 .name = "Primary", 174 .stream_name = "Primary", 175 .dynamic = 1, 176 .dpcm_playback = 1, 177 SND_SOC_DAILINK_REG(primary), 178 }, { 179 /* BE <-> CODECs link */ 180 .name = "I2S Mixer", 181 .ops = &odroid_card_be_ops, 182 .no_pcm = 1, 183 .dpcm_playback = 1, 184 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 185 SND_SOC_DAIFMT_CBS_CFS, 186 SND_SOC_DAILINK_REG(mixer), 187 }, { 188 /* Secondary FE <-> BE link */ 189 .playback_only = 1, 190 .ops = &odroid_card_fe_ops, 191 .name = "Secondary", 192 .stream_name = "Secondary", 193 .dynamic = 1, 194 .dpcm_playback = 1, 195 SND_SOC_DAILINK_REG(secondary), 196 } 197}; 198 199static int odroid_audio_probe(struct platform_device *pdev) 200{ 201 struct device *dev = &pdev->dev; 202 struct device_node *cpu_dai = NULL; 203 struct device_node *cpu, *codec; 204 struct odroid_priv *priv; 205 struct snd_soc_card *card; 206 struct snd_soc_dai_link *link, *codec_link; 207 int num_pcms, ret, i; 208 struct of_phandle_args args = {}; 209 210 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 211 if (!priv) 212 return -ENOMEM; 213 214 card = &priv->card; 215 card->dev = dev; 216 217 card->owner = THIS_MODULE; 218 card->fully_routed = true; 219 220 spin_lock_init(&priv->lock); 221 snd_soc_card_set_drvdata(card, priv); 222 223 ret = snd_soc_of_parse_card_name(card, "model"); 224 if (ret < 0) 225 return ret; 226 227 if (of_property_read_bool(dev->of_node, "samsung,audio-widgets")) { 228 ret = snd_soc_of_parse_audio_simple_widgets(card, 229 "samsung,audio-widgets"); 230 if (ret < 0) 231 return ret; 232 } 233 234 if (of_property_read_bool(dev->of_node, "samsung,audio-routing")) { 235 ret = snd_soc_of_parse_audio_routing(card, 236 "samsung,audio-routing"); 237 if (ret < 0) 238 return ret; 239 } 240 241 card->dai_link = odroid_card_dais; 242 card->num_links = ARRAY_SIZE(odroid_card_dais); 243 244 cpu = of_get_child_by_name(dev->of_node, "cpu"); 245 codec = of_get_child_by_name(dev->of_node, "codec"); 246 link = card->dai_link; 247 codec_link = &card->dai_link[1]; 248 249 /* 250 * For backwards compatibility create the secondary CPU DAI link only 251 * if there are 2 CPU DAI entries in the cpu sound-dai property in DT. 252 * Also add required DAPM routes not available in old DTS. 253 */ 254 num_pcms = of_count_phandle_with_args(cpu, "sound-dai", 255 "#sound-dai-cells"); 256 if (num_pcms == 1) { 257 card->dapm_routes = odroid_dapm_routes; 258 card->num_dapm_routes = ARRAY_SIZE(odroid_dapm_routes); 259 card->num_links--; 260 } 261 262 for (i = 0; i < num_pcms; i++, link += 2) { 263 ret = of_parse_phandle_with_args(cpu, "sound-dai", 264 "#sound-dai-cells", i, &args); 265 if (ret < 0) 266 break; 267 268 if (!args.np) { 269 dev_err(dev, "sound-dai property parse error: %d\n", ret); 270 ret = -EINVAL; 271 break; 272 } 273 274 ret = snd_soc_get_dai_name(&args, &link->cpus->dai_name); 275 of_node_put(args.np); 276 277 if (ret < 0) 278 break; 279 } 280 if (ret == 0) { 281 cpu_dai = of_parse_phandle(cpu, "sound-dai", 0); 282 if (!cpu_dai) 283 ret = -EINVAL; 284 } 285 286 of_node_put(cpu); 287 if (ret < 0) 288 goto err_put_node; 289 290 ret = snd_soc_of_get_dai_link_codecs(dev, codec, codec_link); 291 if (ret < 0) 292 goto err_put_cpu_dai; 293 294 /* Set capture capability only for boards with the MAX98090 CODEC */ 295 if (codec_link->num_codecs > 1) { 296 card->dai_link[0].dpcm_capture = 1; 297 card->dai_link[1].dpcm_capture = 1; 298 } 299 300 priv->sclk_i2s = of_clk_get_by_name(cpu_dai, "i2s_opclk1"); 301 if (IS_ERR(priv->sclk_i2s)) { 302 ret = PTR_ERR(priv->sclk_i2s); 303 goto err_put_cpu_dai; 304 } 305 306 priv->clk_i2s_bus = of_clk_get_by_name(cpu_dai, "iis"); 307 if (IS_ERR(priv->clk_i2s_bus)) { 308 ret = PTR_ERR(priv->clk_i2s_bus); 309 goto err_put_sclk; 310 } 311 312 ret = devm_snd_soc_register_card(dev, card); 313 if (ret < 0) { 314 dev_err_probe(dev, ret, "snd_soc_register_card() failed\n"); 315 goto err_put_clk_i2s; 316 } 317 318 of_node_put(cpu_dai); 319 of_node_put(codec); 320 return 0; 321 322err_put_clk_i2s: 323 clk_put(priv->clk_i2s_bus); 324err_put_sclk: 325 clk_put(priv->sclk_i2s); 326err_put_cpu_dai: 327 of_node_put(cpu_dai); 328 snd_soc_of_put_dai_link_codecs(codec_link); 329err_put_node: 330 of_node_put(codec); 331 return ret; 332} 333 334static int odroid_audio_remove(struct platform_device *pdev) 335{ 336 struct odroid_priv *priv = platform_get_drvdata(pdev); 337 338 snd_soc_of_put_dai_link_codecs(&priv->card.dai_link[1]); 339 clk_put(priv->sclk_i2s); 340 clk_put(priv->clk_i2s_bus); 341 342 return 0; 343} 344 345static const struct of_device_id odroid_audio_of_match[] = { 346 { .compatible = "hardkernel,odroid-xu3-audio" }, 347 { .compatible = "hardkernel,odroid-xu4-audio" }, 348 { .compatible = "samsung,odroid-xu3-audio" }, 349 { .compatible = "samsung,odroid-xu4-audio" }, 350 { }, 351}; 352MODULE_DEVICE_TABLE(of, odroid_audio_of_match); 353 354static struct platform_driver odroid_audio_driver = { 355 .driver = { 356 .name = "odroid-audio", 357 .of_match_table = odroid_audio_of_match, 358 .pm = &snd_soc_pm_ops, 359 }, 360 .probe = odroid_audio_probe, 361 .remove = odroid_audio_remove, 362}; 363module_platform_driver(odroid_audio_driver); 364 365MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>"); 366MODULE_DESCRIPTION("Odroid XU3/XU4 audio support"); 367MODULE_LICENSE("GPL v2");