Lines Matching +full:zynqmp +full:- +full:dpsub +full:- +full:1

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 <hyun.kwon@xilinx.com>
9 * - Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
54 * - enabled_streams
55 * - volumes
56 * - current_rate
83 struct snd_pcm_runtime *runtime = substream->runtime; in zynqmp_dp_startup()
98 writel(val, audio->base + reg); in zynqmp_dp_audio_write()
106 struct zynqmp_dpsub *dpsub = in dp_dai_hw_params() local
108 struct zynqmp_dpsub_audio *audio = dpsub->audio; in dp_dai_hw_params()
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()
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()
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()
180 (iec.status[(i * 4) + 1] << 8) | 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()
198 struct zynqmp_dpsub *dpsub = in dp_dai_hw_free() local
200 struct zynqmp_dpsub_audio *audio = dpsub->audio; in dp_dai_hw_free()
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()
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),
250 SOC_SINGLE_TLV("Input1 Playback Volume", 1,
255 * Note: these read & write functions only support two "registers", 0 and 1,
256 * for volume 0 and 1. In other words, these are not real register read/write
260 * hardware is not enabled, and also to support locking as volumes 0 and 1
266 struct zynqmp_dpsub *dpsub = dev_get_drvdata(component->dev); in zynqmp_dp_dai_read() local
267 struct zynqmp_dpsub_audio *audio = dpsub->audio; in zynqmp_dp_dai_read()
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() local
276 struct zynqmp_dpsub_audio *audio = dpsub->audio; in zynqmp_dp_dai_write()
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()
284 audio->volumes[0] | in zynqmp_dp_dai_write()
285 (audio->volumes[1] << 16)); in zynqmp_dp_dai_write()
291 .idle_bias_on = 1,
292 .use_pmdown_time = 1,
293 .endianness = 1,
300 int zynqmp_audio_init(struct zynqmp_dpsub *dpsub) in zynqmp_audio_init() argument
302 struct platform_device *pdev = to_platform_device(dpsub->dev); in zynqmp_audio_init()
303 struct device *dev = dpsub->dev; in zynqmp_audio_init()
309 if (!dpsub->aud_clk) 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()
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()
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()
432 dpsub->audio = NULL; in zynqmp_audio_init()
440 void zynqmp_audio_uninit(struct zynqmp_dpsub *dpsub) in zynqmp_audio_uninit() argument
442 struct zynqmp_dpsub_audio *audio = dpsub->audio; in zynqmp_audio_uninit()
447 if (!dpsub->aud_clk) in zynqmp_audio_uninit()
450 mutex_destroy(&audio->enable_lock); in zynqmp_audio_uninit()