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