axg-tdm-interface.c (13898B)
1// SPDX-License-Identifier: (GPL-2.0 OR MIT) 2// 3// Copyright (c) 2018 BayLibre, SAS. 4// Author: Jerome Brunet <jbrunet@baylibre.com> 5 6#include <linux/clk.h> 7#include <linux/module.h> 8#include <linux/of_platform.h> 9#include <sound/pcm_params.h> 10#include <sound/soc.h> 11#include <sound/soc-dai.h> 12 13#include "axg-tdm.h" 14 15enum { 16 TDM_IFACE_PAD, 17 TDM_IFACE_LOOPBACK, 18}; 19 20static unsigned int axg_tdm_slots_total(u32 *mask) 21{ 22 unsigned int slots = 0; 23 int i; 24 25 if (!mask) 26 return 0; 27 28 /* Count the total number of slots provided by all 4 lanes */ 29 for (i = 0; i < AXG_TDM_NUM_LANES; i++) 30 slots += hweight32(mask[i]); 31 32 return slots; 33} 34 35int axg_tdm_set_tdm_slots(struct snd_soc_dai *dai, u32 *tx_mask, 36 u32 *rx_mask, unsigned int slots, 37 unsigned int slot_width) 38{ 39 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai); 40 struct axg_tdm_stream *tx = (struct axg_tdm_stream *) 41 dai->playback_dma_data; 42 struct axg_tdm_stream *rx = (struct axg_tdm_stream *) 43 dai->capture_dma_data; 44 unsigned int tx_slots, rx_slots; 45 unsigned int fmt = 0; 46 47 tx_slots = axg_tdm_slots_total(tx_mask); 48 rx_slots = axg_tdm_slots_total(rx_mask); 49 50 /* We should at least have a slot for a valid interface */ 51 if (!tx_slots && !rx_slots) { 52 dev_err(dai->dev, "interface has no slot\n"); 53 return -EINVAL; 54 } 55 56 iface->slots = slots; 57 58 switch (slot_width) { 59 case 0: 60 slot_width = 32; 61 fallthrough; 62 case 32: 63 fmt |= SNDRV_PCM_FMTBIT_S32_LE; 64 fallthrough; 65 case 24: 66 fmt |= SNDRV_PCM_FMTBIT_S24_LE; 67 fmt |= SNDRV_PCM_FMTBIT_S20_LE; 68 fallthrough; 69 case 16: 70 fmt |= SNDRV_PCM_FMTBIT_S16_LE; 71 fallthrough; 72 case 8: 73 fmt |= SNDRV_PCM_FMTBIT_S8; 74 break; 75 default: 76 dev_err(dai->dev, "unsupported slot width: %d\n", slot_width); 77 return -EINVAL; 78 } 79 80 iface->slot_width = slot_width; 81 82 /* Amend the dai driver and let dpcm merge do its job */ 83 if (tx) { 84 tx->mask = tx_mask; 85 dai->driver->playback.channels_max = tx_slots; 86 dai->driver->playback.formats = fmt; 87 } 88 89 if (rx) { 90 rx->mask = rx_mask; 91 dai->driver->capture.channels_max = rx_slots; 92 dai->driver->capture.formats = fmt; 93 } 94 95 return 0; 96} 97EXPORT_SYMBOL_GPL(axg_tdm_set_tdm_slots); 98 99static int axg_tdm_iface_set_sysclk(struct snd_soc_dai *dai, int clk_id, 100 unsigned int freq, int dir) 101{ 102 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai); 103 int ret = -ENOTSUPP; 104 105 if (dir == SND_SOC_CLOCK_OUT && clk_id == 0) { 106 if (!iface->mclk) { 107 dev_warn(dai->dev, "master clock not provided\n"); 108 } else { 109 ret = clk_set_rate(iface->mclk, freq); 110 if (!ret) 111 iface->mclk_rate = freq; 112 } 113 } 114 115 return ret; 116} 117 118static int axg_tdm_iface_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 119{ 120 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai); 121 122 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 123 case SND_SOC_DAIFMT_CBS_CFS: 124 if (!iface->mclk) { 125 dev_err(dai->dev, "cpu clock master: mclk missing\n"); 126 return -ENODEV; 127 } 128 break; 129 130 case SND_SOC_DAIFMT_CBM_CFM: 131 break; 132 133 case SND_SOC_DAIFMT_CBS_CFM: 134 case SND_SOC_DAIFMT_CBM_CFS: 135 dev_err(dai->dev, "only CBS_CFS and CBM_CFM are supported\n"); 136 fallthrough; 137 default: 138 return -EINVAL; 139 } 140 141 iface->fmt = fmt; 142 return 0; 143} 144 145static int axg_tdm_iface_startup(struct snd_pcm_substream *substream, 146 struct snd_soc_dai *dai) 147{ 148 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai); 149 struct axg_tdm_stream *ts = 150 snd_soc_dai_get_dma_data(dai, substream); 151 int ret; 152 153 if (!axg_tdm_slots_total(ts->mask)) { 154 dev_err(dai->dev, "interface has not slots\n"); 155 return -EINVAL; 156 } 157 158 /* Apply component wide rate symmetry */ 159 if (snd_soc_component_active(dai->component)) { 160 ret = snd_pcm_hw_constraint_single(substream->runtime, 161 SNDRV_PCM_HW_PARAM_RATE, 162 iface->rate); 163 if (ret < 0) { 164 dev_err(dai->dev, 165 "can't set iface rate constraint\n"); 166 return ret; 167 } 168 } 169 170 return 0; 171} 172 173static int axg_tdm_iface_set_stream(struct snd_pcm_substream *substream, 174 struct snd_pcm_hw_params *params, 175 struct snd_soc_dai *dai) 176{ 177 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai); 178 struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream); 179 unsigned int channels = params_channels(params); 180 unsigned int width = params_width(params); 181 182 /* Save rate and sample_bits for component symmetry */ 183 iface->rate = params_rate(params); 184 185 /* Make sure this interface can cope with the stream */ 186 if (axg_tdm_slots_total(ts->mask) < channels) { 187 dev_err(dai->dev, "not enough slots for channels\n"); 188 return -EINVAL; 189 } 190 191 if (iface->slot_width < width) { 192 dev_err(dai->dev, "incompatible slots width for stream\n"); 193 return -EINVAL; 194 } 195 196 /* Save the parameter for tdmout/tdmin widgets */ 197 ts->physical_width = params_physical_width(params); 198 ts->width = params_width(params); 199 ts->channels = params_channels(params); 200 201 return 0; 202} 203 204static int axg_tdm_iface_set_lrclk(struct snd_soc_dai *dai, 205 struct snd_pcm_hw_params *params) 206{ 207 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai); 208 unsigned int ratio_num; 209 int ret; 210 211 ret = clk_set_rate(iface->lrclk, params_rate(params)); 212 if (ret) { 213 dev_err(dai->dev, "setting sample clock failed: %d\n", ret); 214 return ret; 215 } 216 217 switch (iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 218 case SND_SOC_DAIFMT_I2S: 219 case SND_SOC_DAIFMT_LEFT_J: 220 case SND_SOC_DAIFMT_RIGHT_J: 221 /* 50% duty cycle ratio */ 222 ratio_num = 1; 223 break; 224 225 case SND_SOC_DAIFMT_DSP_A: 226 case SND_SOC_DAIFMT_DSP_B: 227 /* 228 * A zero duty cycle ratio will result in setting the mininum 229 * ratio possible which, for this clock, is 1 cycle of the 230 * parent bclk clock high and the rest low, This is exactly 231 * what we want here. 232 */ 233 ratio_num = 0; 234 break; 235 236 default: 237 return -EINVAL; 238 } 239 240 ret = clk_set_duty_cycle(iface->lrclk, ratio_num, 2); 241 if (ret) { 242 dev_err(dai->dev, 243 "setting sample clock duty cycle failed: %d\n", ret); 244 return ret; 245 } 246 247 /* Set sample clock inversion */ 248 ret = clk_set_phase(iface->lrclk, 249 axg_tdm_lrclk_invert(iface->fmt) ? 180 : 0); 250 if (ret) { 251 dev_err(dai->dev, 252 "setting sample clock phase failed: %d\n", ret); 253 return ret; 254 } 255 256 return 0; 257} 258 259static int axg_tdm_iface_set_sclk(struct snd_soc_dai *dai, 260 struct snd_pcm_hw_params *params) 261{ 262 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai); 263 unsigned long srate; 264 int ret; 265 266 srate = iface->slots * iface->slot_width * params_rate(params); 267 268 if (!iface->mclk_rate) { 269 /* If no specific mclk is requested, default to bit clock * 4 */ 270 clk_set_rate(iface->mclk, 4 * srate); 271 } else { 272 /* Check if we can actually get the bit clock from mclk */ 273 if (iface->mclk_rate % srate) { 274 dev_err(dai->dev, 275 "can't derive sclk %lu from mclk %lu\n", 276 srate, iface->mclk_rate); 277 return -EINVAL; 278 } 279 } 280 281 ret = clk_set_rate(iface->sclk, srate); 282 if (ret) { 283 dev_err(dai->dev, "setting bit clock failed: %d\n", ret); 284 return ret; 285 } 286 287 /* Set the bit clock inversion */ 288 ret = clk_set_phase(iface->sclk, 289 axg_tdm_sclk_invert(iface->fmt) ? 0 : 180); 290 if (ret) { 291 dev_err(dai->dev, "setting bit clock phase failed: %d\n", ret); 292 return ret; 293 } 294 295 return ret; 296} 297 298static int axg_tdm_iface_hw_params(struct snd_pcm_substream *substream, 299 struct snd_pcm_hw_params *params, 300 struct snd_soc_dai *dai) 301{ 302 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai); 303 int ret; 304 305 switch (iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 306 case SND_SOC_DAIFMT_I2S: 307 case SND_SOC_DAIFMT_LEFT_J: 308 case SND_SOC_DAIFMT_RIGHT_J: 309 if (iface->slots > 2) { 310 dev_err(dai->dev, "bad slot number for format: %d\n", 311 iface->slots); 312 return -EINVAL; 313 } 314 break; 315 316 case SND_SOC_DAIFMT_DSP_A: 317 case SND_SOC_DAIFMT_DSP_B: 318 break; 319 320 default: 321 dev_err(dai->dev, "unsupported dai format\n"); 322 return -EINVAL; 323 } 324 325 ret = axg_tdm_iface_set_stream(substream, params, dai); 326 if (ret) 327 return ret; 328 329 if ((iface->fmt & SND_SOC_DAIFMT_MASTER_MASK) == 330 SND_SOC_DAIFMT_CBS_CFS) { 331 ret = axg_tdm_iface_set_sclk(dai, params); 332 if (ret) 333 return ret; 334 335 ret = axg_tdm_iface_set_lrclk(dai, params); 336 if (ret) 337 return ret; 338 } 339 340 return 0; 341} 342 343static int axg_tdm_iface_hw_free(struct snd_pcm_substream *substream, 344 struct snd_soc_dai *dai) 345{ 346 struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream); 347 348 /* Stop all attached formatters */ 349 axg_tdm_stream_stop(ts); 350 351 return 0; 352} 353 354static int axg_tdm_iface_prepare(struct snd_pcm_substream *substream, 355 struct snd_soc_dai *dai) 356{ 357 struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream); 358 359 /* Force all attached formatters to update */ 360 return axg_tdm_stream_reset(ts); 361} 362 363static int axg_tdm_iface_remove_dai(struct snd_soc_dai *dai) 364{ 365 if (dai->capture_dma_data) 366 axg_tdm_stream_free(dai->capture_dma_data); 367 368 if (dai->playback_dma_data) 369 axg_tdm_stream_free(dai->playback_dma_data); 370 371 return 0; 372} 373 374static int axg_tdm_iface_probe_dai(struct snd_soc_dai *dai) 375{ 376 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai); 377 378 if (dai->capture_widget) { 379 dai->capture_dma_data = axg_tdm_stream_alloc(iface); 380 if (!dai->capture_dma_data) 381 return -ENOMEM; 382 } 383 384 if (dai->playback_widget) { 385 dai->playback_dma_data = axg_tdm_stream_alloc(iface); 386 if (!dai->playback_dma_data) { 387 axg_tdm_iface_remove_dai(dai); 388 return -ENOMEM; 389 } 390 } 391 392 return 0; 393} 394 395static const struct snd_soc_dai_ops axg_tdm_iface_ops = { 396 .set_sysclk = axg_tdm_iface_set_sysclk, 397 .set_fmt = axg_tdm_iface_set_fmt, 398 .startup = axg_tdm_iface_startup, 399 .hw_params = axg_tdm_iface_hw_params, 400 .prepare = axg_tdm_iface_prepare, 401 .hw_free = axg_tdm_iface_hw_free, 402}; 403 404/* TDM Backend DAIs */ 405static const struct snd_soc_dai_driver axg_tdm_iface_dai_drv[] = { 406 [TDM_IFACE_PAD] = { 407 .name = "TDM Pad", 408 .playback = { 409 .stream_name = "Playback", 410 .channels_min = 1, 411 .channels_max = AXG_TDM_CHANNEL_MAX, 412 .rates = AXG_TDM_RATES, 413 .formats = AXG_TDM_FORMATS, 414 }, 415 .capture = { 416 .stream_name = "Capture", 417 .channels_min = 1, 418 .channels_max = AXG_TDM_CHANNEL_MAX, 419 .rates = AXG_TDM_RATES, 420 .formats = AXG_TDM_FORMATS, 421 }, 422 .id = TDM_IFACE_PAD, 423 .ops = &axg_tdm_iface_ops, 424 .probe = axg_tdm_iface_probe_dai, 425 .remove = axg_tdm_iface_remove_dai, 426 }, 427 [TDM_IFACE_LOOPBACK] = { 428 .name = "TDM Loopback", 429 .capture = { 430 .stream_name = "Loopback", 431 .channels_min = 1, 432 .channels_max = AXG_TDM_CHANNEL_MAX, 433 .rates = AXG_TDM_RATES, 434 .formats = AXG_TDM_FORMATS, 435 }, 436 .id = TDM_IFACE_LOOPBACK, 437 .ops = &axg_tdm_iface_ops, 438 .probe = axg_tdm_iface_probe_dai, 439 .remove = axg_tdm_iface_remove_dai, 440 }, 441}; 442 443static int axg_tdm_iface_set_bias_level(struct snd_soc_component *component, 444 enum snd_soc_bias_level level) 445{ 446 struct axg_tdm_iface *iface = snd_soc_component_get_drvdata(component); 447 enum snd_soc_bias_level now = 448 snd_soc_component_get_bias_level(component); 449 int ret = 0; 450 451 switch (level) { 452 case SND_SOC_BIAS_PREPARE: 453 if (now == SND_SOC_BIAS_STANDBY) 454 ret = clk_prepare_enable(iface->mclk); 455 break; 456 457 case SND_SOC_BIAS_STANDBY: 458 if (now == SND_SOC_BIAS_PREPARE) 459 clk_disable_unprepare(iface->mclk); 460 break; 461 462 case SND_SOC_BIAS_OFF: 463 case SND_SOC_BIAS_ON: 464 break; 465 } 466 467 return ret; 468} 469 470static const struct snd_soc_dapm_widget axg_tdm_iface_dapm_widgets[] = { 471 SND_SOC_DAPM_SIGGEN("Playback Signal"), 472}; 473 474static const struct snd_soc_dapm_route axg_tdm_iface_dapm_routes[] = { 475 { "Loopback", NULL, "Playback Signal" }, 476}; 477 478static const struct snd_soc_component_driver axg_tdm_iface_component_drv = { 479 .dapm_widgets = axg_tdm_iface_dapm_widgets, 480 .num_dapm_widgets = ARRAY_SIZE(axg_tdm_iface_dapm_widgets), 481 .dapm_routes = axg_tdm_iface_dapm_routes, 482 .num_dapm_routes = ARRAY_SIZE(axg_tdm_iface_dapm_routes), 483 .set_bias_level = axg_tdm_iface_set_bias_level, 484}; 485 486static const struct of_device_id axg_tdm_iface_of_match[] = { 487 { .compatible = "amlogic,axg-tdm-iface", }, 488 {} 489}; 490MODULE_DEVICE_TABLE(of, axg_tdm_iface_of_match); 491 492static int axg_tdm_iface_probe(struct platform_device *pdev) 493{ 494 struct device *dev = &pdev->dev; 495 struct snd_soc_dai_driver *dai_drv; 496 struct axg_tdm_iface *iface; 497 int ret, i; 498 499 iface = devm_kzalloc(dev, sizeof(*iface), GFP_KERNEL); 500 if (!iface) 501 return -ENOMEM; 502 platform_set_drvdata(pdev, iface); 503 504 /* 505 * Duplicate dai driver: depending on the slot masks configuration 506 * We'll change the number of channel provided by DAI stream, so dpcm 507 * channel merge can be done properly 508 */ 509 dai_drv = devm_kcalloc(dev, ARRAY_SIZE(axg_tdm_iface_dai_drv), 510 sizeof(*dai_drv), GFP_KERNEL); 511 if (!dai_drv) 512 return -ENOMEM; 513 514 for (i = 0; i < ARRAY_SIZE(axg_tdm_iface_dai_drv); i++) 515 memcpy(&dai_drv[i], &axg_tdm_iface_dai_drv[i], 516 sizeof(*dai_drv)); 517 518 /* Bit clock provided on the pad */ 519 iface->sclk = devm_clk_get(dev, "sclk"); 520 if (IS_ERR(iface->sclk)) 521 return dev_err_probe(dev, PTR_ERR(iface->sclk), "failed to get sclk\n"); 522 523 /* Sample clock provided on the pad */ 524 iface->lrclk = devm_clk_get(dev, "lrclk"); 525 if (IS_ERR(iface->lrclk)) 526 return dev_err_probe(dev, PTR_ERR(iface->lrclk), "failed to get lrclk\n"); 527 528 /* 529 * mclk maybe be missing when the cpu dai is in slave mode and 530 * the codec does not require it to provide a master clock. 531 * At this point, ignore the error if mclk is missing. We'll 532 * throw an error if the cpu dai is master and mclk is missing 533 */ 534 iface->mclk = devm_clk_get(dev, "mclk"); 535 if (IS_ERR(iface->mclk)) { 536 ret = PTR_ERR(iface->mclk); 537 if (ret == -ENOENT) 538 iface->mclk = NULL; 539 else 540 return dev_err_probe(dev, ret, "failed to get mclk\n"); 541 } 542 543 return devm_snd_soc_register_component(dev, 544 &axg_tdm_iface_component_drv, dai_drv, 545 ARRAY_SIZE(axg_tdm_iface_dai_drv)); 546} 547 548static struct platform_driver axg_tdm_iface_pdrv = { 549 .probe = axg_tdm_iface_probe, 550 .driver = { 551 .name = "axg-tdm-iface", 552 .of_match_table = axg_tdm_iface_of_match, 553 }, 554}; 555module_platform_driver(axg_tdm_iface_pdrv); 556 557MODULE_DESCRIPTION("Amlogic AXG TDM interface driver"); 558MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); 559MODULE_LICENSE("GPL v2");