Lines Matching +full:audio +full:- +full:cpu

1 // SPDX-License-Identifier: GPL-2.0
3 * ZynqMP DisplayPort Subsystem Driver - Audio support
5 * Copyright (C) 2015 - 2024 Xilinx, Inc.
8 * - Hyun Woo Kwon <[email protected]>
9 * - Tomi Valkeinen <[email protected]>
47 struct snd_soc_dai_link_component cpu; member
54 * - enabled_streams
55 * - volumes
56 * - current_rate
83 struct snd_pcm_runtime *runtime = substream->runtime; in zynqmp_dp_startup()
95 static void zynqmp_dp_audio_write(struct zynqmp_dpsub_audio *audio, int reg, in zynqmp_dp_audio_write() argument
98 writel(val, audio->base + reg); in zynqmp_dp_audio_write()
108 struct zynqmp_dpsub_audio *audio = dpsub->audio; in dp_dai_hw_params() local
117 return -EINVAL; in dp_dai_hw_params()
119 guard(mutex)(&audio->enable_lock); in dp_dai_hw_params()
121 if (audio->enabled_streams && audio->current_rate != sample_rate) { in dp_dai_hw_params()
122 dev_err(dpsub->dev, in dp_dai_hw_params()
124 return -EINVAL; in dp_dai_hw_params()
127 if (audio->enabled_streams > 0) { in dp_dai_hw_params()
129 audio->enabled_streams++; in dp_dai_hw_params()
133 audio->current_rate = sample_rate; in dp_dai_hw_params()
136 ret = clk_set_rate(dpsub->aud_clk, in dp_dai_hw_params()
139 dev_err(dpsub->dev, "can't set aud_clk to %u err:%d\n", in dp_dai_hw_params()
144 clk_prepare_enable(dpsub->aud_clk); in dp_dai_hw_params()
146 rate = clk_get_rate(dpsub->aud_clk); in dp_dai_hw_params()
148 /* Ignore some offset +- 10 */ in dp_dai_hw_params()
149 if (abs(sample_rate * ZYNQMP_DISP_AUD_SMPL_RATE_TO_CLK - rate) > 10) { in dp_dai_hw_params()
150 dev_err(dpsub->dev, "aud_clk offset is higher: %ld\n", in dp_dai_hw_params()
151 sample_rate * ZYNQMP_DISP_AUD_SMPL_RATE_TO_CLK - rate); in dp_dai_hw_params()
152 clk_disable_unprepare(dpsub->aud_clk); in dp_dai_hw_params()
153 return -EINVAL; in dp_dai_hw_params()
156 pm_runtime_get_sync(dpsub->dev); in dp_dai_hw_params()
158 zynqmp_dp_audio_write(audio, ZYNQMP_DISP_AUD_MIXER_VOLUME, in dp_dai_hw_params()
159 audio->volumes[0] | (audio->volumes[1] << 16)); in dp_dai_hw_params()
161 /* Clear the audio soft reset register as it's an non-reset flop. */ in dp_dai_hw_params()
162 zynqmp_dp_audio_write(audio, ZYNQMP_DISP_AUD_SOFT_RESET, 0); in dp_dai_hw_params()
164 /* Only 2 channel audio is supported now */ in dp_dai_hw_params()
165 zynqmp_dp_audio_set_channels(dpsub->dp, 2); in dp_dai_hw_params()
167 zynqmp_dp_audio_write_n_m(dpsub->dp); in dp_dai_hw_params()
184 zynqmp_dp_audio_write(audio, ZYNQMP_DISP_AUD_CH_STATUS(i), v); in dp_dai_hw_params()
187 zynqmp_dp_audio_enable(dpsub->dp); in dp_dai_hw_params()
189 audio->enabled_streams++; in dp_dai_hw_params()
200 struct zynqmp_dpsub_audio *audio = dpsub->audio; in dp_dai_hw_free() local
202 guard(mutex)(&audio->enable_lock); in dp_dai_hw_free()
205 if (audio->enabled_streams > 1) { in dp_dai_hw_free()
206 audio->enabled_streams--; in dp_dai_hw_free()
210 pm_runtime_put(dpsub->dev); in dp_dai_hw_free()
212 zynqmp_dp_audio_disable(dpsub->dp); in dp_dai_hw_free()
215 * Reset doesn't work. If we assert reset between audio stop and start, in dp_dai_hw_free()
216 * the audio won't start anymore. Probably we are missing writing in dp_dai_hw_free()
217 * some audio related registers. A/B buf? in dp_dai_hw_free()
220 zynqmp_disp_audio_write(audio, ZYNQMP_DISP_AUD_SOFT_RESET, in dp_dai_hw_free()
224 clk_disable_unprepare(dpsub->aud_clk); in dp_dai_hw_free()
226 audio->current_rate = 0; in dp_dai_hw_free()
227 audio->enabled_streams--; in dp_dai_hw_free()
238 * Min = 10 * log10(0x1 / 0x2000) = -39.13
242 0x0, 0x0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, -3913, 1),
243 0x1, 0x2000, TLV_DB_LINEAR_ITEM(-3913, 0),
266 struct zynqmp_dpsub *dpsub = dev_get_drvdata(component->dev); in zynqmp_dp_dai_read()
267 struct zynqmp_dpsub_audio *audio = dpsub->audio; in zynqmp_dp_dai_read() local
269 return audio->volumes[reg]; in zynqmp_dp_dai_read()
275 struct zynqmp_dpsub *dpsub = dev_get_drvdata(component->dev); in zynqmp_dp_dai_write()
276 struct zynqmp_dpsub_audio *audio = dpsub->audio; in zynqmp_dp_dai_write() local
278 guard(mutex)(&audio->enable_lock); in zynqmp_dp_dai_write()
280 audio->volumes[reg] = val; in zynqmp_dp_dai_write()
282 if (audio->enabled_streams) in zynqmp_dp_dai_write()
283 zynqmp_dp_audio_write(audio, ZYNQMP_DISP_AUD_MIXER_VOLUME, in zynqmp_dp_dai_write()
284 audio->volumes[0] | in zynqmp_dp_dai_write()
285 (audio->volumes[1] << 16)); in zynqmp_dp_dai_write()
302 struct platform_device *pdev = to_platform_device(dpsub->dev); in zynqmp_audio_init()
303 struct device *dev = dpsub->dev; in zynqmp_audio_init()
304 struct zynqmp_dpsub_audio *audio; in zynqmp_audio_init() local
309 if (!dpsub->aud_clk) in zynqmp_audio_init()
312 audio = devm_kzalloc(dev, sizeof(*audio), GFP_KERNEL); in zynqmp_audio_init()
313 if (!audio) in zynqmp_audio_init()
314 return -ENOMEM; in zynqmp_audio_init()
316 dpsub->audio = audio; in zynqmp_audio_init()
318 mutex_init(&audio->enable_lock); in zynqmp_audio_init()
321 audio->volumes[0] = 0x2000; in zynqmp_audio_init()
322 audio->volumes[1] = 0x2000; in zynqmp_audio_init()
324 audio->dai_name = devm_kasprintf(dev, GFP_KERNEL, in zynqmp_audio_init()
325 "%s-dai", dev_name(dev)); in zynqmp_audio_init()
326 if (!audio->dai_name) in zynqmp_audio_init()
327 return -ENOMEM; in zynqmp_audio_init()
330 audio->link_names[i] = devm_kasprintf(dev, GFP_KERNEL, in zynqmp_audio_init()
331 "%s-dp-%u", dev_name(dev), i); in zynqmp_audio_init()
332 audio->pcm_names[i] = devm_kasprintf(dev, GFP_KERNEL, in zynqmp_audio_init()
333 "%s-pcm-%u", dev_name(dev), i); in zynqmp_audio_init()
334 if (!audio->link_names[i] || !audio->pcm_names[i]) in zynqmp_audio_init()
335 return -ENOMEM; in zynqmp_audio_init()
338 audio->base = devm_platform_ioremap_resource_byname(pdev, "aud"); in zynqmp_audio_init()
339 if (IS_ERR(audio->base)) in zynqmp_audio_init()
340 return PTR_ERR(audio->base); in zynqmp_audio_init()
342 /* Create CPU DAI */ in zynqmp_audio_init()
344 audio->dai_driver = (struct snd_soc_dai_driver) { in zynqmp_audio_init()
345 .name = audio->dai_name, in zynqmp_audio_init()
356 &audio->dai_driver, 1); in zynqmp_audio_init()
358 dev_err(dev, "Failed to register CPU DAI\n"); in zynqmp_audio_init()
366 &audio->pcm_configs[i]; in zynqmp_audio_init()
369 .name = audio->pcm_names[i], in zynqmp_audio_init()
385 card = &audio->card; in zynqmp_audio_init()
386 card->name = "DisplayPort"; in zynqmp_audio_init()
387 card->long_name = "DisplayPort Monitor"; in zynqmp_audio_init()
388 card->driver_name = "zynqmp_dpsub"; in zynqmp_audio_init()
389 card->dev = dev; in zynqmp_audio_init()
390 card->owner = THIS_MODULE; in zynqmp_audio_init()
391 card->num_links = ZYNQMP_NUM_PCMS; in zynqmp_audio_init()
392 card->dai_link = audio->links; in zynqmp_audio_init()
395 struct snd_soc_dai_link *link = &card->dai_link[i]; in zynqmp_audio_init()
397 link->ops = &zynqmp_dp_ops; in zynqmp_audio_init()
399 link->name = audio->link_names[i]; in zynqmp_audio_init()
400 link->stream_name = audio->link_names[i]; in zynqmp_audio_init()
402 link->cpus = &audio->components[i].cpu; in zynqmp_audio_init()
403 link->num_cpus = 1; in zynqmp_audio_init()
404 link->cpus[0].dai_name = audio->dai_name; in zynqmp_audio_init()
406 link->codecs = &audio->components[i].codec; in zynqmp_audio_init()
407 link->num_codecs = 1; in zynqmp_audio_init()
408 link->codecs[0].name = "snd-soc-dummy"; in zynqmp_audio_init()
409 link->codecs[0].dai_name = "snd-soc-dummy-dai"; in zynqmp_audio_init()
411 link->platforms = &audio->components[i].platform; in zynqmp_audio_init()
412 link->num_platforms = 1; in zynqmp_audio_init()
413 link->platforms[0].name = audio->pcm_names[i]; in zynqmp_audio_init()
425 * As older dtbs may not have the audio channel dmas defined, in zynqmp_audio_init()
427 * mark the audio as disabled. in zynqmp_audio_init()
429 dev_err(dev, "Failed to register sound card, disabling audio support\n"); in zynqmp_audio_init()
431 devm_kfree(dev, audio); in zynqmp_audio_init()
432 dpsub->audio = NULL; in zynqmp_audio_init()
442 struct zynqmp_dpsub_audio *audio = dpsub->audio; in zynqmp_audio_uninit() local
444 if (!audio) in zynqmp_audio_uninit()
447 if (!dpsub->aud_clk) in zynqmp_audio_uninit()
450 mutex_destroy(&audio->enable_lock); in zynqmp_audio_uninit()