img-spdif-in.c (22855B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * IMG SPDIF input controller driver 4 * 5 * Copyright (C) 2015 Imagination Technologies Ltd. 6 * 7 * Author: Damien Horsley <Damien.Horsley@imgtec.com> 8 */ 9 10#include <linux/clk.h> 11#include <linux/init.h> 12#include <linux/kernel.h> 13#include <linux/module.h> 14#include <linux/of.h> 15#include <linux/platform_device.h> 16#include <linux/pm_runtime.h> 17#include <linux/reset.h> 18 19#include <sound/core.h> 20#include <sound/dmaengine_pcm.h> 21#include <sound/initval.h> 22#include <sound/pcm.h> 23#include <sound/pcm_params.h> 24#include <sound/soc.h> 25 26#define IMG_SPDIF_IN_RX_FIFO_OFFSET 0 27 28#define IMG_SPDIF_IN_CTL 0x4 29#define IMG_SPDIF_IN_CTL_LOCKLO_MASK 0xff 30#define IMG_SPDIF_IN_CTL_LOCKLO_SHIFT 0 31#define IMG_SPDIF_IN_CTL_LOCKHI_MASK 0xff00 32#define IMG_SPDIF_IN_CTL_LOCKHI_SHIFT 8 33#define IMG_SPDIF_IN_CTL_TRK_MASK 0xff0000 34#define IMG_SPDIF_IN_CTL_TRK_SHIFT 16 35#define IMG_SPDIF_IN_CTL_SRD_MASK 0x70000000 36#define IMG_SPDIF_IN_CTL_SRD_SHIFT 28 37#define IMG_SPDIF_IN_CTL_SRT_MASK BIT(31) 38 39#define IMG_SPDIF_IN_STATUS 0x8 40#define IMG_SPDIF_IN_STATUS_SAM_MASK 0x7000 41#define IMG_SPDIF_IN_STATUS_SAM_SHIFT 12 42#define IMG_SPDIF_IN_STATUS_LOCK_MASK BIT(15) 43#define IMG_SPDIF_IN_STATUS_LOCK_SHIFT 15 44 45#define IMG_SPDIF_IN_CLKGEN 0x1c 46#define IMG_SPDIF_IN_CLKGEN_NOM_MASK 0x3ff 47#define IMG_SPDIF_IN_CLKGEN_NOM_SHIFT 0 48#define IMG_SPDIF_IN_CLKGEN_HLD_MASK 0x3ff0000 49#define IMG_SPDIF_IN_CLKGEN_HLD_SHIFT 16 50 51#define IMG_SPDIF_IN_CSL 0x20 52 53#define IMG_SPDIF_IN_CSH 0x24 54#define IMG_SPDIF_IN_CSH_MASK 0xff 55#define IMG_SPDIF_IN_CSH_SHIFT 0 56 57#define IMG_SPDIF_IN_SOFT_RESET 0x28 58#define IMG_SPDIF_IN_SOFT_RESET_MASK BIT(0) 59 60#define IMG_SPDIF_IN_ACLKGEN_START 0x2c 61#define IMG_SPDIF_IN_ACLKGEN_NOM_MASK 0x3ff 62#define IMG_SPDIF_IN_ACLKGEN_NOM_SHIFT 0 63#define IMG_SPDIF_IN_ACLKGEN_HLD_MASK 0xffc00 64#define IMG_SPDIF_IN_ACLKGEN_HLD_SHIFT 10 65#define IMG_SPDIF_IN_ACLKGEN_TRK_MASK 0xff00000 66#define IMG_SPDIF_IN_ACLKGEN_TRK_SHIFT 20 67 68#define IMG_SPDIF_IN_NUM_ACLKGEN 4 69 70struct img_spdif_in { 71 spinlock_t lock; 72 void __iomem *base; 73 struct clk *clk_sys; 74 struct snd_dmaengine_dai_dma_data dma_data; 75 struct device *dev; 76 unsigned int trk; 77 bool multi_freq; 78 int lock_acquire; 79 int lock_release; 80 unsigned int single_freq; 81 unsigned int multi_freqs[IMG_SPDIF_IN_NUM_ACLKGEN]; 82 bool active; 83 u32 suspend_clkgen; 84 u32 suspend_ctl; 85 86 /* Write-only registers */ 87 unsigned int aclkgen_regs[IMG_SPDIF_IN_NUM_ACLKGEN]; 88}; 89 90static int img_spdif_in_runtime_suspend(struct device *dev) 91{ 92 struct img_spdif_in *spdif = dev_get_drvdata(dev); 93 94 clk_disable_unprepare(spdif->clk_sys); 95 96 return 0; 97} 98 99static int img_spdif_in_runtime_resume(struct device *dev) 100{ 101 struct img_spdif_in *spdif = dev_get_drvdata(dev); 102 int ret; 103 104 ret = clk_prepare_enable(spdif->clk_sys); 105 if (ret) { 106 dev_err(dev, "Unable to enable sys clock\n"); 107 return ret; 108 } 109 110 return 0; 111} 112 113static inline void img_spdif_in_writel(struct img_spdif_in *spdif, 114 u32 val, u32 reg) 115{ 116 writel(val, spdif->base + reg); 117} 118 119static inline u32 img_spdif_in_readl(struct img_spdif_in *spdif, u32 reg) 120{ 121 return readl(spdif->base + reg); 122} 123 124static inline void img_spdif_in_aclkgen_writel(struct img_spdif_in *spdif, 125 u32 index) 126{ 127 img_spdif_in_writel(spdif, spdif->aclkgen_regs[index], 128 IMG_SPDIF_IN_ACLKGEN_START + (index * 0x4)); 129} 130 131static int img_spdif_in_check_max_rate(struct img_spdif_in *spdif, 132 unsigned int sample_rate, unsigned long *actual_freq) 133{ 134 unsigned long min_freq, freq_t; 135 136 /* Clock rate must be at least 24x the bit rate */ 137 min_freq = sample_rate * 2 * 32 * 24; 138 139 freq_t = clk_get_rate(spdif->clk_sys); 140 141 if (freq_t < min_freq) 142 return -EINVAL; 143 144 *actual_freq = freq_t; 145 146 return 0; 147} 148 149static int img_spdif_in_do_clkgen_calc(unsigned int rate, unsigned int *pnom, 150 unsigned int *phld, unsigned long clk_rate) 151{ 152 unsigned int ori, nom, hld; 153 154 /* 155 * Calculate oversampling ratio, nominal phase increment and hold 156 * increment for the given rate / frequency 157 */ 158 159 if (!rate) 160 return -EINVAL; 161 162 ori = clk_rate / (rate * 64); 163 164 if (!ori) 165 return -EINVAL; 166 167 nom = (4096 / ori) + 1; 168 do 169 hld = 4096 - (--nom * (ori - 1)); 170 while (hld < 120); 171 172 *pnom = nom; 173 *phld = hld; 174 175 return 0; 176} 177 178static int img_spdif_in_do_clkgen_single(struct img_spdif_in *spdif, 179 unsigned int rate) 180{ 181 unsigned int nom, hld; 182 unsigned long flags, clk_rate; 183 int ret = 0; 184 u32 reg; 185 186 ret = img_spdif_in_check_max_rate(spdif, rate, &clk_rate); 187 if (ret) 188 return ret; 189 190 ret = img_spdif_in_do_clkgen_calc(rate, &nom, &hld, clk_rate); 191 if (ret) 192 return ret; 193 194 reg = (nom << IMG_SPDIF_IN_CLKGEN_NOM_SHIFT) & 195 IMG_SPDIF_IN_CLKGEN_NOM_MASK; 196 reg |= (hld << IMG_SPDIF_IN_CLKGEN_HLD_SHIFT) & 197 IMG_SPDIF_IN_CLKGEN_HLD_MASK; 198 199 spin_lock_irqsave(&spdif->lock, flags); 200 201 if (spdif->active) { 202 spin_unlock_irqrestore(&spdif->lock, flags); 203 return -EBUSY; 204 } 205 206 img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CLKGEN); 207 208 spdif->single_freq = rate; 209 210 spin_unlock_irqrestore(&spdif->lock, flags); 211 212 return 0; 213} 214 215static int img_spdif_in_do_clkgen_multi(struct img_spdif_in *spdif, 216 unsigned int multi_freqs[]) 217{ 218 unsigned int nom, hld, rate, max_rate = 0; 219 unsigned long flags, clk_rate; 220 int i, ret = 0; 221 u32 reg, trk_reg, temp_regs[IMG_SPDIF_IN_NUM_ACLKGEN]; 222 223 for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) 224 if (multi_freqs[i] > max_rate) 225 max_rate = multi_freqs[i]; 226 227 ret = img_spdif_in_check_max_rate(spdif, max_rate, &clk_rate); 228 if (ret) 229 return ret; 230 231 for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) { 232 rate = multi_freqs[i]; 233 234 ret = img_spdif_in_do_clkgen_calc(rate, &nom, &hld, clk_rate); 235 if (ret) 236 return ret; 237 238 reg = (nom << IMG_SPDIF_IN_ACLKGEN_NOM_SHIFT) & 239 IMG_SPDIF_IN_ACLKGEN_NOM_MASK; 240 reg |= (hld << IMG_SPDIF_IN_ACLKGEN_HLD_SHIFT) & 241 IMG_SPDIF_IN_ACLKGEN_HLD_MASK; 242 temp_regs[i] = reg; 243 } 244 245 spin_lock_irqsave(&spdif->lock, flags); 246 247 if (spdif->active) { 248 spin_unlock_irqrestore(&spdif->lock, flags); 249 return -EBUSY; 250 } 251 252 trk_reg = spdif->trk << IMG_SPDIF_IN_ACLKGEN_TRK_SHIFT; 253 254 for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) { 255 spdif->aclkgen_regs[i] = temp_regs[i] | trk_reg; 256 img_spdif_in_aclkgen_writel(spdif, i); 257 } 258 259 spdif->multi_freq = true; 260 spdif->multi_freqs[0] = multi_freqs[0]; 261 spdif->multi_freqs[1] = multi_freqs[1]; 262 spdif->multi_freqs[2] = multi_freqs[2]; 263 spdif->multi_freqs[3] = multi_freqs[3]; 264 265 spin_unlock_irqrestore(&spdif->lock, flags); 266 267 return 0; 268} 269 270static int img_spdif_in_iec958_info(struct snd_kcontrol *kcontrol, 271 struct snd_ctl_elem_info *uinfo) 272{ 273 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 274 uinfo->count = 1; 275 276 return 0; 277} 278 279static int img_spdif_in_get_status_mask(struct snd_kcontrol *kcontrol, 280 struct snd_ctl_elem_value *ucontrol) 281{ 282 ucontrol->value.iec958.status[0] = 0xff; 283 ucontrol->value.iec958.status[1] = 0xff; 284 ucontrol->value.iec958.status[2] = 0xff; 285 ucontrol->value.iec958.status[3] = 0xff; 286 ucontrol->value.iec958.status[4] = 0xff; 287 288 return 0; 289} 290 291static int img_spdif_in_get_status(struct snd_kcontrol *kcontrol, 292 struct snd_ctl_elem_value *ucontrol) 293{ 294 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 295 struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); 296 u32 reg; 297 298 reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CSL); 299 ucontrol->value.iec958.status[0] = reg & 0xff; 300 ucontrol->value.iec958.status[1] = (reg >> 8) & 0xff; 301 ucontrol->value.iec958.status[2] = (reg >> 16) & 0xff; 302 ucontrol->value.iec958.status[3] = (reg >> 24) & 0xff; 303 reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CSH); 304 ucontrol->value.iec958.status[4] = (reg & IMG_SPDIF_IN_CSH_MASK) 305 >> IMG_SPDIF_IN_CSH_SHIFT; 306 307 return 0; 308} 309 310static int img_spdif_in_info_multi_freq(struct snd_kcontrol *kcontrol, 311 struct snd_ctl_elem_info *uinfo) 312{ 313 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 314 uinfo->count = IMG_SPDIF_IN_NUM_ACLKGEN; 315 uinfo->value.integer.min = 0; 316 uinfo->value.integer.max = LONG_MAX; 317 318 return 0; 319} 320 321static int img_spdif_in_get_multi_freq(struct snd_kcontrol *kcontrol, 322 struct snd_ctl_elem_value *ucontrol) 323{ 324 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 325 struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); 326 unsigned long flags; 327 328 spin_lock_irqsave(&spdif->lock, flags); 329 if (spdif->multi_freq) { 330 ucontrol->value.integer.value[0] = spdif->multi_freqs[0]; 331 ucontrol->value.integer.value[1] = spdif->multi_freqs[1]; 332 ucontrol->value.integer.value[2] = spdif->multi_freqs[2]; 333 ucontrol->value.integer.value[3] = spdif->multi_freqs[3]; 334 } else { 335 ucontrol->value.integer.value[0] = 0; 336 ucontrol->value.integer.value[1] = 0; 337 ucontrol->value.integer.value[2] = 0; 338 ucontrol->value.integer.value[3] = 0; 339 } 340 spin_unlock_irqrestore(&spdif->lock, flags); 341 342 return 0; 343} 344 345static int img_spdif_in_set_multi_freq(struct snd_kcontrol *kcontrol, 346 struct snd_ctl_elem_value *ucontrol) 347{ 348 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 349 struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); 350 unsigned int multi_freqs[IMG_SPDIF_IN_NUM_ACLKGEN]; 351 bool multi_freq; 352 unsigned long flags; 353 354 if ((ucontrol->value.integer.value[0] == 0) && 355 (ucontrol->value.integer.value[1] == 0) && 356 (ucontrol->value.integer.value[2] == 0) && 357 (ucontrol->value.integer.value[3] == 0)) { 358 multi_freq = false; 359 } else { 360 multi_freqs[0] = ucontrol->value.integer.value[0]; 361 multi_freqs[1] = ucontrol->value.integer.value[1]; 362 multi_freqs[2] = ucontrol->value.integer.value[2]; 363 multi_freqs[3] = ucontrol->value.integer.value[3]; 364 multi_freq = true; 365 } 366 367 if (multi_freq) 368 return img_spdif_in_do_clkgen_multi(spdif, multi_freqs); 369 370 spin_lock_irqsave(&spdif->lock, flags); 371 372 if (spdif->active) { 373 spin_unlock_irqrestore(&spdif->lock, flags); 374 return -EBUSY; 375 } 376 377 spdif->multi_freq = false; 378 379 spin_unlock_irqrestore(&spdif->lock, flags); 380 381 return 0; 382} 383 384static int img_spdif_in_info_lock_freq(struct snd_kcontrol *kcontrol, 385 struct snd_ctl_elem_info *uinfo) 386{ 387 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 388 uinfo->count = 1; 389 uinfo->value.integer.min = 0; 390 uinfo->value.integer.max = LONG_MAX; 391 392 return 0; 393} 394 395static int img_spdif_in_get_lock_freq(struct snd_kcontrol *kcontrol, 396 struct snd_ctl_elem_value *uc) 397{ 398 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 399 struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); 400 u32 reg; 401 int i; 402 unsigned long flags; 403 404 spin_lock_irqsave(&spdif->lock, flags); 405 406 reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_STATUS); 407 if (reg & IMG_SPDIF_IN_STATUS_LOCK_MASK) { 408 if (spdif->multi_freq) { 409 i = ((reg & IMG_SPDIF_IN_STATUS_SAM_MASK) >> 410 IMG_SPDIF_IN_STATUS_SAM_SHIFT) - 1; 411 uc->value.integer.value[0] = spdif->multi_freqs[i]; 412 } else { 413 uc->value.integer.value[0] = spdif->single_freq; 414 } 415 } else { 416 uc->value.integer.value[0] = 0; 417 } 418 419 spin_unlock_irqrestore(&spdif->lock, flags); 420 421 return 0; 422} 423 424static int img_spdif_in_info_trk(struct snd_kcontrol *kcontrol, 425 struct snd_ctl_elem_info *uinfo) 426{ 427 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 428 uinfo->count = 1; 429 uinfo->value.integer.min = 0; 430 uinfo->value.integer.max = 255; 431 432 return 0; 433} 434 435static int img_spdif_in_get_trk(struct snd_kcontrol *kcontrol, 436 struct snd_ctl_elem_value *ucontrol) 437{ 438 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 439 struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); 440 441 ucontrol->value.integer.value[0] = spdif->trk; 442 443 return 0; 444} 445 446static int img_spdif_in_set_trk(struct snd_kcontrol *kcontrol, 447 struct snd_ctl_elem_value *ucontrol) 448{ 449 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 450 struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); 451 unsigned long flags; 452 int i; 453 u32 reg; 454 455 spin_lock_irqsave(&spdif->lock, flags); 456 457 if (spdif->active) { 458 spin_unlock_irqrestore(&spdif->lock, flags); 459 return -EBUSY; 460 } 461 462 spdif->trk = ucontrol->value.integer.value[0]; 463 464 reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL); 465 reg &= ~IMG_SPDIF_IN_CTL_TRK_MASK; 466 reg |= spdif->trk << IMG_SPDIF_IN_CTL_TRK_SHIFT; 467 img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL); 468 469 for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) { 470 spdif->aclkgen_regs[i] = (spdif->aclkgen_regs[i] & 471 ~IMG_SPDIF_IN_ACLKGEN_TRK_MASK) | 472 (spdif->trk << IMG_SPDIF_IN_ACLKGEN_TRK_SHIFT); 473 474 img_spdif_in_aclkgen_writel(spdif, i); 475 } 476 477 spin_unlock_irqrestore(&spdif->lock, flags); 478 479 return 0; 480} 481 482static int img_spdif_in_info_lock(struct snd_kcontrol *kcontrol, 483 struct snd_ctl_elem_info *uinfo) 484{ 485 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 486 uinfo->count = 1; 487 uinfo->value.integer.min = -128; 488 uinfo->value.integer.max = 127; 489 490 return 0; 491} 492 493static int img_spdif_in_get_lock_acquire(struct snd_kcontrol *kcontrol, 494 struct snd_ctl_elem_value *ucontrol) 495{ 496 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 497 struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); 498 499 ucontrol->value.integer.value[0] = spdif->lock_acquire; 500 501 return 0; 502} 503 504static int img_spdif_in_set_lock_acquire(struct snd_kcontrol *kcontrol, 505 struct snd_ctl_elem_value *ucontrol) 506{ 507 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 508 struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); 509 unsigned long flags; 510 u32 reg; 511 512 spin_lock_irqsave(&spdif->lock, flags); 513 514 if (spdif->active) { 515 spin_unlock_irqrestore(&spdif->lock, flags); 516 return -EBUSY; 517 } 518 519 spdif->lock_acquire = ucontrol->value.integer.value[0]; 520 521 reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL); 522 reg &= ~IMG_SPDIF_IN_CTL_LOCKHI_MASK; 523 reg |= (spdif->lock_acquire << IMG_SPDIF_IN_CTL_LOCKHI_SHIFT) & 524 IMG_SPDIF_IN_CTL_LOCKHI_MASK; 525 img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL); 526 527 spin_unlock_irqrestore(&spdif->lock, flags); 528 529 return 0; 530} 531 532static int img_spdif_in_get_lock_release(struct snd_kcontrol *kcontrol, 533 struct snd_ctl_elem_value *ucontrol) 534{ 535 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 536 struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); 537 538 ucontrol->value.integer.value[0] = spdif->lock_release; 539 540 return 0; 541} 542 543static int img_spdif_in_set_lock_release(struct snd_kcontrol *kcontrol, 544 struct snd_ctl_elem_value *ucontrol) 545{ 546 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 547 struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); 548 unsigned long flags; 549 u32 reg; 550 551 spin_lock_irqsave(&spdif->lock, flags); 552 553 if (spdif->active) { 554 spin_unlock_irqrestore(&spdif->lock, flags); 555 return -EBUSY; 556 } 557 558 spdif->lock_release = ucontrol->value.integer.value[0]; 559 560 reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL); 561 reg &= ~IMG_SPDIF_IN_CTL_LOCKLO_MASK; 562 reg |= (spdif->lock_release << IMG_SPDIF_IN_CTL_LOCKLO_SHIFT) & 563 IMG_SPDIF_IN_CTL_LOCKLO_MASK; 564 img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL); 565 566 spin_unlock_irqrestore(&spdif->lock, flags); 567 568 return 0; 569} 570 571static struct snd_kcontrol_new img_spdif_in_controls[] = { 572 { 573 .access = SNDRV_CTL_ELEM_ACCESS_READ, 574 .iface = SNDRV_CTL_ELEM_IFACE_PCM, 575 .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK), 576 .info = img_spdif_in_iec958_info, 577 .get = img_spdif_in_get_status_mask 578 }, 579 { 580 .access = SNDRV_CTL_ELEM_ACCESS_READ | 581 SNDRV_CTL_ELEM_ACCESS_VOLATILE, 582 .iface = SNDRV_CTL_ELEM_IFACE_PCM, 583 .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), 584 .info = img_spdif_in_iec958_info, 585 .get = img_spdif_in_get_status 586 }, 587 { 588 .iface = SNDRV_CTL_ELEM_IFACE_PCM, 589 .name = "SPDIF In Multi Frequency Acquire", 590 .info = img_spdif_in_info_multi_freq, 591 .get = img_spdif_in_get_multi_freq, 592 .put = img_spdif_in_set_multi_freq 593 }, 594 { 595 .access = SNDRV_CTL_ELEM_ACCESS_READ | 596 SNDRV_CTL_ELEM_ACCESS_VOLATILE, 597 .iface = SNDRV_CTL_ELEM_IFACE_PCM, 598 .name = "SPDIF In Lock Frequency", 599 .info = img_spdif_in_info_lock_freq, 600 .get = img_spdif_in_get_lock_freq 601 }, 602 { 603 .iface = SNDRV_CTL_ELEM_IFACE_PCM, 604 .name = "SPDIF In Lock TRK", 605 .info = img_spdif_in_info_trk, 606 .get = img_spdif_in_get_trk, 607 .put = img_spdif_in_set_trk 608 }, 609 { 610 .iface = SNDRV_CTL_ELEM_IFACE_PCM, 611 .name = "SPDIF In Lock Acquire Threshold", 612 .info = img_spdif_in_info_lock, 613 .get = img_spdif_in_get_lock_acquire, 614 .put = img_spdif_in_set_lock_acquire 615 }, 616 { 617 .iface = SNDRV_CTL_ELEM_IFACE_PCM, 618 .name = "SPDIF In Lock Release Threshold", 619 .info = img_spdif_in_info_lock, 620 .get = img_spdif_in_get_lock_release, 621 .put = img_spdif_in_set_lock_release 622 } 623}; 624 625static int img_spdif_in_trigger(struct snd_pcm_substream *substream, int cmd, 626 struct snd_soc_dai *dai) 627{ 628 unsigned long flags; 629 struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai); 630 int ret = 0; 631 u32 reg; 632 633 spin_lock_irqsave(&spdif->lock, flags); 634 635 switch (cmd) { 636 case SNDRV_PCM_TRIGGER_START: 637 case SNDRV_PCM_TRIGGER_RESUME: 638 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 639 reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL); 640 if (spdif->multi_freq) 641 reg &= ~IMG_SPDIF_IN_CTL_SRD_MASK; 642 else 643 reg |= (1UL << IMG_SPDIF_IN_CTL_SRD_SHIFT); 644 reg |= IMG_SPDIF_IN_CTL_SRT_MASK; 645 img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL); 646 spdif->active = true; 647 break; 648 case SNDRV_PCM_TRIGGER_STOP: 649 case SNDRV_PCM_TRIGGER_SUSPEND: 650 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 651 reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL); 652 reg &= ~IMG_SPDIF_IN_CTL_SRT_MASK; 653 img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL); 654 spdif->active = false; 655 break; 656 default: 657 ret = -EINVAL; 658 } 659 660 spin_unlock_irqrestore(&spdif->lock, flags); 661 662 return ret; 663} 664 665static int img_spdif_in_hw_params(struct snd_pcm_substream *substream, 666 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) 667{ 668 struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai); 669 unsigned int rate, channels; 670 snd_pcm_format_t format; 671 672 rate = params_rate(params); 673 channels = params_channels(params); 674 format = params_format(params); 675 676 if (format != SNDRV_PCM_FORMAT_S32_LE) 677 return -EINVAL; 678 679 if (channels != 2) 680 return -EINVAL; 681 682 return img_spdif_in_do_clkgen_single(spdif, rate); 683} 684 685static const struct snd_soc_dai_ops img_spdif_in_dai_ops = { 686 .trigger = img_spdif_in_trigger, 687 .hw_params = img_spdif_in_hw_params 688}; 689 690static int img_spdif_in_dai_probe(struct snd_soc_dai *dai) 691{ 692 struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai); 693 694 snd_soc_dai_init_dma_data(dai, NULL, &spdif->dma_data); 695 696 snd_soc_add_dai_controls(dai, img_spdif_in_controls, 697 ARRAY_SIZE(img_spdif_in_controls)); 698 699 return 0; 700} 701 702static struct snd_soc_dai_driver img_spdif_in_dai = { 703 .probe = img_spdif_in_dai_probe, 704 .capture = { 705 .channels_min = 2, 706 .channels_max = 2, 707 .rates = SNDRV_PCM_RATE_8000_192000, 708 .formats = SNDRV_PCM_FMTBIT_S32_LE 709 }, 710 .ops = &img_spdif_in_dai_ops 711}; 712 713static const struct snd_soc_component_driver img_spdif_in_component = { 714 .name = "img-spdif-in" 715}; 716 717static int img_spdif_in_probe(struct platform_device *pdev) 718{ 719 struct img_spdif_in *spdif; 720 struct resource *res; 721 void __iomem *base; 722 int ret; 723 struct reset_control *rst; 724 u32 reg; 725 struct device *dev = &pdev->dev; 726 727 spdif = devm_kzalloc(&pdev->dev, sizeof(*spdif), GFP_KERNEL); 728 if (!spdif) 729 return -ENOMEM; 730 731 platform_set_drvdata(pdev, spdif); 732 733 spdif->dev = &pdev->dev; 734 735 base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 736 if (IS_ERR(base)) 737 return PTR_ERR(base); 738 739 spdif->base = base; 740 741 spdif->clk_sys = devm_clk_get(dev, "sys"); 742 if (IS_ERR(spdif->clk_sys)) 743 return dev_err_probe(dev, PTR_ERR(spdif->clk_sys), 744 "Failed to acquire clock 'sys'\n"); 745 746 pm_runtime_enable(&pdev->dev); 747 if (!pm_runtime_enabled(&pdev->dev)) { 748 ret = img_spdif_in_runtime_resume(&pdev->dev); 749 if (ret) 750 goto err_pm_disable; 751 } 752 ret = pm_runtime_resume_and_get(&pdev->dev); 753 if (ret < 0) 754 goto err_suspend; 755 756 rst = devm_reset_control_get_exclusive(&pdev->dev, "rst"); 757 if (IS_ERR(rst)) { 758 if (PTR_ERR(rst) == -EPROBE_DEFER) { 759 ret = -EPROBE_DEFER; 760 goto err_pm_put; 761 } 762 dev_dbg(dev, "No top level reset found\n"); 763 img_spdif_in_writel(spdif, IMG_SPDIF_IN_SOFT_RESET_MASK, 764 IMG_SPDIF_IN_SOFT_RESET); 765 img_spdif_in_writel(spdif, 0, IMG_SPDIF_IN_SOFT_RESET); 766 } else { 767 reset_control_assert(rst); 768 reset_control_deassert(rst); 769 } 770 771 spin_lock_init(&spdif->lock); 772 773 spdif->dma_data.addr = res->start + IMG_SPDIF_IN_RX_FIFO_OFFSET; 774 spdif->dma_data.addr_width = 4; 775 spdif->dma_data.maxburst = 4; 776 spdif->trk = 0x80; 777 spdif->lock_acquire = 4; 778 spdif->lock_release = -128; 779 780 reg = (spdif->lock_acquire << IMG_SPDIF_IN_CTL_LOCKHI_SHIFT) & 781 IMG_SPDIF_IN_CTL_LOCKHI_MASK; 782 reg |= (spdif->lock_release << IMG_SPDIF_IN_CTL_LOCKLO_SHIFT) & 783 IMG_SPDIF_IN_CTL_LOCKLO_MASK; 784 reg |= (spdif->trk << IMG_SPDIF_IN_CTL_TRK_SHIFT) & 785 IMG_SPDIF_IN_CTL_TRK_MASK; 786 img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL); 787 788 pm_runtime_put(&pdev->dev); 789 790 ret = devm_snd_soc_register_component(&pdev->dev, 791 &img_spdif_in_component, &img_spdif_in_dai, 1); 792 if (ret) 793 goto err_suspend; 794 795 ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); 796 if (ret) 797 goto err_suspend; 798 799 return 0; 800 801err_pm_put: 802 pm_runtime_put(&pdev->dev); 803err_suspend: 804 if (!pm_runtime_enabled(&pdev->dev)) 805 img_spdif_in_runtime_suspend(&pdev->dev); 806err_pm_disable: 807 pm_runtime_disable(&pdev->dev); 808 809 return ret; 810} 811 812static int img_spdif_in_dev_remove(struct platform_device *pdev) 813{ 814 pm_runtime_disable(&pdev->dev); 815 if (!pm_runtime_status_suspended(&pdev->dev)) 816 img_spdif_in_runtime_suspend(&pdev->dev); 817 818 return 0; 819} 820 821#ifdef CONFIG_PM_SLEEP 822static int img_spdif_in_suspend(struct device *dev) 823{ 824 struct img_spdif_in *spdif = dev_get_drvdata(dev); 825 int ret; 826 827 if (pm_runtime_status_suspended(dev)) { 828 ret = img_spdif_in_runtime_resume(dev); 829 if (ret) 830 return ret; 831 } 832 833 spdif->suspend_clkgen = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CLKGEN); 834 spdif->suspend_ctl = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL); 835 836 img_spdif_in_runtime_suspend(dev); 837 838 return 0; 839} 840 841static int img_spdif_in_resume(struct device *dev) 842{ 843 struct img_spdif_in *spdif = dev_get_drvdata(dev); 844 int i, ret; 845 846 ret = img_spdif_in_runtime_resume(dev); 847 if (ret) 848 return ret; 849 850 for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) 851 img_spdif_in_aclkgen_writel(spdif, i); 852 853 img_spdif_in_writel(spdif, spdif->suspend_clkgen, IMG_SPDIF_IN_CLKGEN); 854 img_spdif_in_writel(spdif, spdif->suspend_ctl, IMG_SPDIF_IN_CTL); 855 856 if (pm_runtime_status_suspended(dev)) 857 img_spdif_in_runtime_suspend(dev); 858 859 return 0; 860} 861#endif 862 863static const struct of_device_id img_spdif_in_of_match[] = { 864 { .compatible = "img,spdif-in" }, 865 {} 866}; 867MODULE_DEVICE_TABLE(of, img_spdif_in_of_match); 868 869static const struct dev_pm_ops img_spdif_in_pm_ops = { 870 SET_RUNTIME_PM_OPS(img_spdif_in_runtime_suspend, 871 img_spdif_in_runtime_resume, NULL) 872 SET_SYSTEM_SLEEP_PM_OPS(img_spdif_in_suspend, img_spdif_in_resume) 873}; 874 875static struct platform_driver img_spdif_in_driver = { 876 .driver = { 877 .name = "img-spdif-in", 878 .of_match_table = img_spdif_in_of_match, 879 .pm = &img_spdif_in_pm_ops 880 }, 881 .probe = img_spdif_in_probe, 882 .remove = img_spdif_in_dev_remove 883}; 884module_platform_driver(img_spdif_in_driver); 885 886MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>"); 887MODULE_DESCRIPTION("IMG SPDIF Input driver"); 888MODULE_LICENSE("GPL v2");