Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * IMG SPDIF input controller driver
0004  *
0005  * Copyright (C) 2015 Imagination Technologies Ltd.
0006  *
0007  * Author: Damien Horsley <Damien.Horsley@imgtec.com>
0008  */
0009 
0010 #include <linux/clk.h>
0011 #include <linux/init.h>
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/of.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/pm_runtime.h>
0017 #include <linux/reset.h>
0018 
0019 #include <sound/core.h>
0020 #include <sound/dmaengine_pcm.h>
0021 #include <sound/initval.h>
0022 #include <sound/pcm.h>
0023 #include <sound/pcm_params.h>
0024 #include <sound/soc.h>
0025 
0026 #define IMG_SPDIF_IN_RX_FIFO_OFFSET     0
0027 
0028 #define IMG_SPDIF_IN_CTL            0x4
0029 #define IMG_SPDIF_IN_CTL_LOCKLO_MASK        0xff
0030 #define IMG_SPDIF_IN_CTL_LOCKLO_SHIFT       0
0031 #define IMG_SPDIF_IN_CTL_LOCKHI_MASK        0xff00
0032 #define IMG_SPDIF_IN_CTL_LOCKHI_SHIFT       8
0033 #define IMG_SPDIF_IN_CTL_TRK_MASK       0xff0000
0034 #define IMG_SPDIF_IN_CTL_TRK_SHIFT      16
0035 #define IMG_SPDIF_IN_CTL_SRD_MASK       0x70000000
0036 #define IMG_SPDIF_IN_CTL_SRD_SHIFT      28
0037 #define IMG_SPDIF_IN_CTL_SRT_MASK       BIT(31)
0038 
0039 #define IMG_SPDIF_IN_STATUS         0x8
0040 #define IMG_SPDIF_IN_STATUS_SAM_MASK        0x7000
0041 #define IMG_SPDIF_IN_STATUS_SAM_SHIFT       12
0042 #define IMG_SPDIF_IN_STATUS_LOCK_MASK       BIT(15)
0043 #define IMG_SPDIF_IN_STATUS_LOCK_SHIFT      15
0044 
0045 #define IMG_SPDIF_IN_CLKGEN         0x1c
0046 #define IMG_SPDIF_IN_CLKGEN_NOM_MASK        0x3ff
0047 #define IMG_SPDIF_IN_CLKGEN_NOM_SHIFT       0
0048 #define IMG_SPDIF_IN_CLKGEN_HLD_MASK        0x3ff0000
0049 #define IMG_SPDIF_IN_CLKGEN_HLD_SHIFT       16
0050 
0051 #define IMG_SPDIF_IN_CSL            0x20
0052 
0053 #define IMG_SPDIF_IN_CSH            0x24
0054 #define IMG_SPDIF_IN_CSH_MASK           0xff
0055 #define IMG_SPDIF_IN_CSH_SHIFT          0
0056 
0057 #define IMG_SPDIF_IN_SOFT_RESET         0x28
0058 #define IMG_SPDIF_IN_SOFT_RESET_MASK        BIT(0)
0059 
0060 #define IMG_SPDIF_IN_ACLKGEN_START      0x2c
0061 #define IMG_SPDIF_IN_ACLKGEN_NOM_MASK       0x3ff
0062 #define IMG_SPDIF_IN_ACLKGEN_NOM_SHIFT      0
0063 #define IMG_SPDIF_IN_ACLKGEN_HLD_MASK       0xffc00
0064 #define IMG_SPDIF_IN_ACLKGEN_HLD_SHIFT      10
0065 #define IMG_SPDIF_IN_ACLKGEN_TRK_MASK       0xff00000
0066 #define IMG_SPDIF_IN_ACLKGEN_TRK_SHIFT      20
0067 
0068 #define IMG_SPDIF_IN_NUM_ACLKGEN        4
0069 
0070 struct img_spdif_in {
0071     spinlock_t lock;
0072     void __iomem *base;
0073     struct clk *clk_sys;
0074     struct snd_dmaengine_dai_dma_data dma_data;
0075     struct device *dev;
0076     unsigned int trk;
0077     bool multi_freq;
0078     int lock_acquire;
0079     int lock_release;
0080     unsigned int single_freq;
0081     unsigned int multi_freqs[IMG_SPDIF_IN_NUM_ACLKGEN];
0082     bool active;
0083     u32 suspend_clkgen;
0084     u32 suspend_ctl;
0085 
0086     /* Write-only registers */
0087     unsigned int aclkgen_regs[IMG_SPDIF_IN_NUM_ACLKGEN];
0088 };
0089 
0090 static int img_spdif_in_runtime_suspend(struct device *dev)
0091 {
0092     struct img_spdif_in *spdif = dev_get_drvdata(dev);
0093 
0094     clk_disable_unprepare(spdif->clk_sys);
0095 
0096     return 0;
0097 }
0098 
0099 static int img_spdif_in_runtime_resume(struct device *dev)
0100 {
0101     struct img_spdif_in *spdif = dev_get_drvdata(dev);
0102     int ret;
0103 
0104     ret = clk_prepare_enable(spdif->clk_sys);
0105     if (ret) {
0106         dev_err(dev, "Unable to enable sys clock\n");
0107         return ret;
0108     }
0109 
0110     return 0;
0111 }
0112 
0113 static inline void img_spdif_in_writel(struct img_spdif_in *spdif,
0114                     u32 val, u32 reg)
0115 {
0116     writel(val, spdif->base + reg);
0117 }
0118 
0119 static inline u32 img_spdif_in_readl(struct img_spdif_in *spdif, u32 reg)
0120 {
0121     return readl(spdif->base + reg);
0122 }
0123 
0124 static inline void img_spdif_in_aclkgen_writel(struct img_spdif_in *spdif,
0125                         u32 index)
0126 {
0127     img_spdif_in_writel(spdif, spdif->aclkgen_regs[index],
0128             IMG_SPDIF_IN_ACLKGEN_START + (index * 0x4));
0129 }
0130 
0131 static int img_spdif_in_check_max_rate(struct img_spdif_in *spdif,
0132         unsigned int sample_rate, unsigned long *actual_freq)
0133 {
0134     unsigned long min_freq, freq_t;
0135 
0136     /* Clock rate must be at least 24x the bit rate */
0137     min_freq = sample_rate * 2 * 32 * 24;
0138 
0139     freq_t = clk_get_rate(spdif->clk_sys);
0140 
0141     if (freq_t < min_freq)
0142         return -EINVAL;
0143 
0144     *actual_freq = freq_t;
0145 
0146     return 0;
0147 }
0148 
0149 static int img_spdif_in_do_clkgen_calc(unsigned int rate, unsigned int *pnom,
0150         unsigned int *phld, unsigned long clk_rate)
0151 {
0152     unsigned int ori, nom, hld;
0153 
0154     /*
0155      * Calculate oversampling ratio, nominal phase increment and hold
0156      * increment for the given rate / frequency
0157      */
0158 
0159     if (!rate)
0160         return -EINVAL;
0161 
0162     ori = clk_rate / (rate * 64);
0163 
0164     if (!ori)
0165         return -EINVAL;
0166 
0167     nom = (4096 / ori) + 1;
0168     do
0169         hld = 4096 - (--nom * (ori - 1));
0170     while (hld < 120);
0171 
0172     *pnom = nom;
0173     *phld = hld;
0174 
0175     return 0;
0176 }
0177 
0178 static int img_spdif_in_do_clkgen_single(struct img_spdif_in *spdif,
0179         unsigned int rate)
0180 {
0181     unsigned int nom, hld;
0182     unsigned long flags, clk_rate;
0183     int ret = 0;
0184     u32 reg;
0185 
0186     ret = img_spdif_in_check_max_rate(spdif, rate, &clk_rate);
0187     if (ret)
0188         return ret;
0189 
0190     ret = img_spdif_in_do_clkgen_calc(rate, &nom, &hld, clk_rate);
0191     if (ret)
0192         return ret;
0193 
0194     reg = (nom << IMG_SPDIF_IN_CLKGEN_NOM_SHIFT) &
0195         IMG_SPDIF_IN_CLKGEN_NOM_MASK;
0196     reg |= (hld << IMG_SPDIF_IN_CLKGEN_HLD_SHIFT) &
0197         IMG_SPDIF_IN_CLKGEN_HLD_MASK;
0198 
0199     spin_lock_irqsave(&spdif->lock, flags);
0200 
0201     if (spdif->active) {
0202         spin_unlock_irqrestore(&spdif->lock, flags);
0203         return -EBUSY;
0204     }
0205 
0206     img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CLKGEN);
0207 
0208     spdif->single_freq = rate;
0209 
0210     spin_unlock_irqrestore(&spdif->lock, flags);
0211 
0212     return 0;
0213 }
0214 
0215 static int img_spdif_in_do_clkgen_multi(struct img_spdif_in *spdif,
0216         unsigned int multi_freqs[])
0217 {
0218     unsigned int nom, hld, rate, max_rate = 0;
0219     unsigned long flags, clk_rate;
0220     int i, ret = 0;
0221     u32 reg, trk_reg, temp_regs[IMG_SPDIF_IN_NUM_ACLKGEN];
0222 
0223     for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++)
0224         if (multi_freqs[i] > max_rate)
0225             max_rate = multi_freqs[i];
0226 
0227     ret = img_spdif_in_check_max_rate(spdif, max_rate, &clk_rate);
0228     if (ret)
0229         return ret;
0230 
0231     for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) {
0232         rate = multi_freqs[i];
0233 
0234         ret = img_spdif_in_do_clkgen_calc(rate, &nom, &hld, clk_rate);
0235         if (ret)
0236             return ret;
0237 
0238         reg = (nom << IMG_SPDIF_IN_ACLKGEN_NOM_SHIFT) &
0239             IMG_SPDIF_IN_ACLKGEN_NOM_MASK;
0240         reg |= (hld << IMG_SPDIF_IN_ACLKGEN_HLD_SHIFT) &
0241             IMG_SPDIF_IN_ACLKGEN_HLD_MASK;
0242         temp_regs[i] = reg;
0243     }
0244 
0245     spin_lock_irqsave(&spdif->lock, flags);
0246 
0247     if (spdif->active) {
0248         spin_unlock_irqrestore(&spdif->lock, flags);
0249         return -EBUSY;
0250     }
0251 
0252     trk_reg = spdif->trk << IMG_SPDIF_IN_ACLKGEN_TRK_SHIFT;
0253 
0254     for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) {
0255         spdif->aclkgen_regs[i] = temp_regs[i] | trk_reg;
0256         img_spdif_in_aclkgen_writel(spdif, i);
0257     }
0258 
0259     spdif->multi_freq = true;
0260     spdif->multi_freqs[0] = multi_freqs[0];
0261     spdif->multi_freqs[1] = multi_freqs[1];
0262     spdif->multi_freqs[2] = multi_freqs[2];
0263     spdif->multi_freqs[3] = multi_freqs[3];
0264 
0265     spin_unlock_irqrestore(&spdif->lock, flags);
0266 
0267     return 0;
0268 }
0269 
0270 static int img_spdif_in_iec958_info(struct snd_kcontrol *kcontrol,
0271         struct snd_ctl_elem_info *uinfo)
0272 {
0273     uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
0274     uinfo->count = 1;
0275 
0276     return 0;
0277 }
0278 
0279 static int img_spdif_in_get_status_mask(struct snd_kcontrol *kcontrol,
0280                        struct snd_ctl_elem_value *ucontrol)
0281 {
0282     ucontrol->value.iec958.status[0] = 0xff;
0283     ucontrol->value.iec958.status[1] = 0xff;
0284     ucontrol->value.iec958.status[2] = 0xff;
0285     ucontrol->value.iec958.status[3] = 0xff;
0286     ucontrol->value.iec958.status[4] = 0xff;
0287 
0288     return 0;
0289 }
0290 
0291 static int img_spdif_in_get_status(struct snd_kcontrol *kcontrol,
0292                   struct snd_ctl_elem_value *ucontrol)
0293 {
0294     struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
0295     struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
0296     u32 reg;
0297 
0298     reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CSL);
0299     ucontrol->value.iec958.status[0] = reg & 0xff;
0300     ucontrol->value.iec958.status[1] = (reg >> 8) & 0xff;
0301     ucontrol->value.iec958.status[2] = (reg >> 16) & 0xff;
0302     ucontrol->value.iec958.status[3] = (reg >> 24) & 0xff;
0303     reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CSH);
0304     ucontrol->value.iec958.status[4] = (reg & IMG_SPDIF_IN_CSH_MASK)
0305         >> IMG_SPDIF_IN_CSH_SHIFT;
0306 
0307     return 0;
0308 }
0309 
0310 static int img_spdif_in_info_multi_freq(struct snd_kcontrol *kcontrol,
0311         struct snd_ctl_elem_info *uinfo)
0312 {
0313     uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
0314     uinfo->count = IMG_SPDIF_IN_NUM_ACLKGEN;
0315     uinfo->value.integer.min = 0;
0316     uinfo->value.integer.max = LONG_MAX;
0317 
0318     return 0;
0319 }
0320 
0321 static int img_spdif_in_get_multi_freq(struct snd_kcontrol *kcontrol,
0322                   struct snd_ctl_elem_value *ucontrol)
0323 {
0324     struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
0325     struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
0326     unsigned long flags;
0327 
0328     spin_lock_irqsave(&spdif->lock, flags);
0329     if (spdif->multi_freq) {
0330         ucontrol->value.integer.value[0] = spdif->multi_freqs[0];
0331         ucontrol->value.integer.value[1] = spdif->multi_freqs[1];
0332         ucontrol->value.integer.value[2] = spdif->multi_freqs[2];
0333         ucontrol->value.integer.value[3] = spdif->multi_freqs[3];
0334     } else {
0335         ucontrol->value.integer.value[0] = 0;
0336         ucontrol->value.integer.value[1] = 0;
0337         ucontrol->value.integer.value[2] = 0;
0338         ucontrol->value.integer.value[3] = 0;
0339     }
0340     spin_unlock_irqrestore(&spdif->lock, flags);
0341 
0342     return 0;
0343 }
0344 
0345 static int img_spdif_in_set_multi_freq(struct snd_kcontrol *kcontrol,
0346                   struct snd_ctl_elem_value *ucontrol)
0347 {
0348     struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
0349     struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
0350     unsigned int multi_freqs[IMG_SPDIF_IN_NUM_ACLKGEN];
0351     bool multi_freq;
0352     unsigned long flags;
0353 
0354     if ((ucontrol->value.integer.value[0] == 0) &&
0355             (ucontrol->value.integer.value[1] == 0) &&
0356             (ucontrol->value.integer.value[2] == 0) &&
0357             (ucontrol->value.integer.value[3] == 0)) {
0358         multi_freq = false;
0359     } else {
0360         multi_freqs[0] = ucontrol->value.integer.value[0];
0361         multi_freqs[1] = ucontrol->value.integer.value[1];
0362         multi_freqs[2] = ucontrol->value.integer.value[2];
0363         multi_freqs[3] = ucontrol->value.integer.value[3];
0364         multi_freq = true;
0365     }
0366 
0367     if (multi_freq)
0368         return img_spdif_in_do_clkgen_multi(spdif, multi_freqs);
0369 
0370     spin_lock_irqsave(&spdif->lock, flags);
0371 
0372     if (spdif->active) {
0373         spin_unlock_irqrestore(&spdif->lock, flags);
0374         return -EBUSY;
0375     }
0376 
0377     spdif->multi_freq = false;
0378 
0379     spin_unlock_irqrestore(&spdif->lock, flags);
0380 
0381     return 0;
0382 }
0383 
0384 static int img_spdif_in_info_lock_freq(struct snd_kcontrol *kcontrol,
0385         struct snd_ctl_elem_info *uinfo)
0386 {
0387     uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
0388     uinfo->count = 1;
0389     uinfo->value.integer.min = 0;
0390     uinfo->value.integer.max = LONG_MAX;
0391 
0392     return 0;
0393 }
0394 
0395 static int img_spdif_in_get_lock_freq(struct snd_kcontrol *kcontrol,
0396                   struct snd_ctl_elem_value *uc)
0397 {
0398     struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
0399     struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
0400     u32 reg;
0401     int i;
0402     unsigned long flags;
0403 
0404     spin_lock_irqsave(&spdif->lock, flags);
0405 
0406     reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_STATUS);
0407     if (reg & IMG_SPDIF_IN_STATUS_LOCK_MASK) {
0408         if (spdif->multi_freq) {
0409             i = ((reg & IMG_SPDIF_IN_STATUS_SAM_MASK) >>
0410                     IMG_SPDIF_IN_STATUS_SAM_SHIFT) - 1;
0411             uc->value.integer.value[0] = spdif->multi_freqs[i];
0412         } else {
0413             uc->value.integer.value[0] = spdif->single_freq;
0414         }
0415     } else {
0416         uc->value.integer.value[0] = 0;
0417     }
0418 
0419     spin_unlock_irqrestore(&spdif->lock, flags);
0420 
0421     return 0;
0422 }
0423 
0424 static int img_spdif_in_info_trk(struct snd_kcontrol *kcontrol,
0425         struct snd_ctl_elem_info *uinfo)
0426 {
0427     uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
0428     uinfo->count = 1;
0429     uinfo->value.integer.min = 0;
0430     uinfo->value.integer.max = 255;
0431 
0432     return 0;
0433 }
0434 
0435 static int img_spdif_in_get_trk(struct snd_kcontrol *kcontrol,
0436                   struct snd_ctl_elem_value *ucontrol)
0437 {
0438     struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
0439     struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
0440 
0441     ucontrol->value.integer.value[0] = spdif->trk;
0442 
0443     return 0;
0444 }
0445 
0446 static int img_spdif_in_set_trk(struct snd_kcontrol *kcontrol,
0447                   struct snd_ctl_elem_value *ucontrol)
0448 {
0449     struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
0450     struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
0451     unsigned long flags;
0452     int i;
0453     u32 reg;
0454 
0455     spin_lock_irqsave(&spdif->lock, flags);
0456 
0457     if (spdif->active) {
0458         spin_unlock_irqrestore(&spdif->lock, flags);
0459         return -EBUSY;
0460     }
0461 
0462     spdif->trk = ucontrol->value.integer.value[0];
0463 
0464     reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
0465     reg &= ~IMG_SPDIF_IN_CTL_TRK_MASK;
0466     reg |= spdif->trk << IMG_SPDIF_IN_CTL_TRK_SHIFT;
0467     img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
0468 
0469     for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) {
0470         spdif->aclkgen_regs[i] = (spdif->aclkgen_regs[i] &
0471             ~IMG_SPDIF_IN_ACLKGEN_TRK_MASK) |
0472             (spdif->trk << IMG_SPDIF_IN_ACLKGEN_TRK_SHIFT);
0473 
0474         img_spdif_in_aclkgen_writel(spdif, i);
0475     }
0476 
0477     spin_unlock_irqrestore(&spdif->lock, flags);
0478 
0479     return 0;
0480 }
0481 
0482 static int img_spdif_in_info_lock(struct snd_kcontrol *kcontrol,
0483         struct snd_ctl_elem_info *uinfo)
0484 {
0485     uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
0486     uinfo->count = 1;
0487     uinfo->value.integer.min = -128;
0488     uinfo->value.integer.max = 127;
0489 
0490     return 0;
0491 }
0492 
0493 static int img_spdif_in_get_lock_acquire(struct snd_kcontrol *kcontrol,
0494                   struct snd_ctl_elem_value *ucontrol)
0495 {
0496     struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
0497     struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
0498 
0499     ucontrol->value.integer.value[0] = spdif->lock_acquire;
0500 
0501     return 0;
0502 }
0503 
0504 static int img_spdif_in_set_lock_acquire(struct snd_kcontrol *kcontrol,
0505                   struct snd_ctl_elem_value *ucontrol)
0506 {
0507     struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
0508     struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
0509     unsigned long flags;
0510     u32 reg;
0511 
0512     spin_lock_irqsave(&spdif->lock, flags);
0513 
0514     if (spdif->active) {
0515         spin_unlock_irqrestore(&spdif->lock, flags);
0516         return -EBUSY;
0517     }
0518 
0519     spdif->lock_acquire = ucontrol->value.integer.value[0];
0520 
0521     reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
0522     reg &= ~IMG_SPDIF_IN_CTL_LOCKHI_MASK;
0523     reg |= (spdif->lock_acquire << IMG_SPDIF_IN_CTL_LOCKHI_SHIFT) &
0524         IMG_SPDIF_IN_CTL_LOCKHI_MASK;
0525     img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
0526 
0527     spin_unlock_irqrestore(&spdif->lock, flags);
0528 
0529     return 0;
0530 }
0531 
0532 static int img_spdif_in_get_lock_release(struct snd_kcontrol *kcontrol,
0533                   struct snd_ctl_elem_value *ucontrol)
0534 {
0535     struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
0536     struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
0537 
0538     ucontrol->value.integer.value[0] = spdif->lock_release;
0539 
0540     return 0;
0541 }
0542 
0543 static int img_spdif_in_set_lock_release(struct snd_kcontrol *kcontrol,
0544                   struct snd_ctl_elem_value *ucontrol)
0545 {
0546     struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
0547     struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
0548     unsigned long flags;
0549     u32 reg;
0550 
0551     spin_lock_irqsave(&spdif->lock, flags);
0552 
0553     if (spdif->active) {
0554         spin_unlock_irqrestore(&spdif->lock, flags);
0555         return -EBUSY;
0556     }
0557 
0558     spdif->lock_release = ucontrol->value.integer.value[0];
0559 
0560     reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
0561     reg &= ~IMG_SPDIF_IN_CTL_LOCKLO_MASK;
0562     reg |= (spdif->lock_release << IMG_SPDIF_IN_CTL_LOCKLO_SHIFT) &
0563         IMG_SPDIF_IN_CTL_LOCKLO_MASK;
0564     img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
0565 
0566     spin_unlock_irqrestore(&spdif->lock, flags);
0567 
0568     return 0;
0569 }
0570 
0571 static struct snd_kcontrol_new img_spdif_in_controls[] = {
0572     {
0573         .access = SNDRV_CTL_ELEM_ACCESS_READ,
0574         .iface = SNDRV_CTL_ELEM_IFACE_PCM,
0575         .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK),
0576         .info = img_spdif_in_iec958_info,
0577         .get = img_spdif_in_get_status_mask
0578     },
0579     {
0580         .access = SNDRV_CTL_ELEM_ACCESS_READ |
0581             SNDRV_CTL_ELEM_ACCESS_VOLATILE,
0582         .iface = SNDRV_CTL_ELEM_IFACE_PCM,
0583         .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
0584         .info = img_spdif_in_iec958_info,
0585         .get = img_spdif_in_get_status
0586     },
0587     {
0588         .iface = SNDRV_CTL_ELEM_IFACE_PCM,
0589         .name = "SPDIF In Multi Frequency Acquire",
0590         .info = img_spdif_in_info_multi_freq,
0591         .get = img_spdif_in_get_multi_freq,
0592         .put = img_spdif_in_set_multi_freq
0593     },
0594     {
0595         .access = SNDRV_CTL_ELEM_ACCESS_READ |
0596             SNDRV_CTL_ELEM_ACCESS_VOLATILE,
0597         .iface = SNDRV_CTL_ELEM_IFACE_PCM,
0598         .name = "SPDIF In Lock Frequency",
0599         .info = img_spdif_in_info_lock_freq,
0600         .get = img_spdif_in_get_lock_freq
0601     },
0602     {
0603         .iface = SNDRV_CTL_ELEM_IFACE_PCM,
0604         .name = "SPDIF In Lock TRK",
0605         .info = img_spdif_in_info_trk,
0606         .get = img_spdif_in_get_trk,
0607         .put = img_spdif_in_set_trk
0608     },
0609     {
0610         .iface = SNDRV_CTL_ELEM_IFACE_PCM,
0611         .name = "SPDIF In Lock Acquire Threshold",
0612         .info = img_spdif_in_info_lock,
0613         .get = img_spdif_in_get_lock_acquire,
0614         .put = img_spdif_in_set_lock_acquire
0615     },
0616     {
0617         .iface = SNDRV_CTL_ELEM_IFACE_PCM,
0618         .name = "SPDIF In Lock Release Threshold",
0619         .info = img_spdif_in_info_lock,
0620         .get = img_spdif_in_get_lock_release,
0621         .put = img_spdif_in_set_lock_release
0622     }
0623 };
0624 
0625 static int img_spdif_in_trigger(struct snd_pcm_substream *substream, int cmd,
0626     struct snd_soc_dai *dai)
0627 {
0628     unsigned long flags;
0629     struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai);
0630     int ret = 0;
0631     u32 reg;
0632 
0633     spin_lock_irqsave(&spdif->lock, flags);
0634 
0635     switch (cmd) {
0636     case SNDRV_PCM_TRIGGER_START:
0637     case SNDRV_PCM_TRIGGER_RESUME:
0638     case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0639         reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
0640         if (spdif->multi_freq)
0641             reg &= ~IMG_SPDIF_IN_CTL_SRD_MASK;
0642         else
0643             reg |= (1UL << IMG_SPDIF_IN_CTL_SRD_SHIFT);
0644         reg |= IMG_SPDIF_IN_CTL_SRT_MASK;
0645         img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
0646         spdif->active = true;
0647         break;
0648     case SNDRV_PCM_TRIGGER_STOP:
0649     case SNDRV_PCM_TRIGGER_SUSPEND:
0650     case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0651         reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
0652         reg &= ~IMG_SPDIF_IN_CTL_SRT_MASK;
0653         img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
0654         spdif->active = false;
0655         break;
0656     default:
0657         ret = -EINVAL;
0658     }
0659 
0660     spin_unlock_irqrestore(&spdif->lock, flags);
0661 
0662     return ret;
0663 }
0664 
0665 static int img_spdif_in_hw_params(struct snd_pcm_substream *substream,
0666     struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
0667 {
0668     struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai);
0669     unsigned int rate, channels;
0670     snd_pcm_format_t format;
0671 
0672     rate = params_rate(params);
0673     channels = params_channels(params);
0674     format = params_format(params);
0675 
0676     if (format != SNDRV_PCM_FORMAT_S32_LE)
0677         return -EINVAL;
0678 
0679     if (channels != 2)
0680         return -EINVAL;
0681 
0682     return img_spdif_in_do_clkgen_single(spdif, rate);
0683 }
0684 
0685 static const struct snd_soc_dai_ops img_spdif_in_dai_ops = {
0686     .trigger = img_spdif_in_trigger,
0687     .hw_params = img_spdif_in_hw_params
0688 };
0689 
0690 static int img_spdif_in_dai_probe(struct snd_soc_dai *dai)
0691 {
0692     struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai);
0693 
0694     snd_soc_dai_init_dma_data(dai, NULL, &spdif->dma_data);
0695 
0696     snd_soc_add_dai_controls(dai, img_spdif_in_controls,
0697             ARRAY_SIZE(img_spdif_in_controls));
0698 
0699     return 0;
0700 }
0701 
0702 static struct snd_soc_dai_driver img_spdif_in_dai = {
0703     .probe = img_spdif_in_dai_probe,
0704     .capture = {
0705         .channels_min = 2,
0706         .channels_max = 2,
0707         .rates = SNDRV_PCM_RATE_8000_192000,
0708         .formats = SNDRV_PCM_FMTBIT_S32_LE
0709     },
0710     .ops = &img_spdif_in_dai_ops
0711 };
0712 
0713 static const struct snd_soc_component_driver img_spdif_in_component = {
0714     .name = "img-spdif-in",
0715     .legacy_dai_naming = 1,
0716 };
0717 
0718 static int img_spdif_in_probe(struct platform_device *pdev)
0719 {
0720     struct img_spdif_in *spdif;
0721     struct resource *res;
0722     void __iomem *base;
0723     int ret;
0724     struct reset_control *rst;
0725     u32 reg;
0726     struct device *dev = &pdev->dev;
0727 
0728     spdif = devm_kzalloc(&pdev->dev, sizeof(*spdif), GFP_KERNEL);
0729     if (!spdif)
0730         return -ENOMEM;
0731 
0732     platform_set_drvdata(pdev, spdif);
0733 
0734     spdif->dev = &pdev->dev;
0735 
0736     base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
0737     if (IS_ERR(base))
0738         return PTR_ERR(base);
0739 
0740     spdif->base = base;
0741 
0742     spdif->clk_sys = devm_clk_get(dev, "sys");
0743     if (IS_ERR(spdif->clk_sys))
0744         return dev_err_probe(dev, PTR_ERR(spdif->clk_sys),
0745                      "Failed to acquire clock 'sys'\n");
0746 
0747     pm_runtime_enable(&pdev->dev);
0748     if (!pm_runtime_enabled(&pdev->dev)) {
0749         ret = img_spdif_in_runtime_resume(&pdev->dev);
0750         if (ret)
0751             goto err_pm_disable;
0752     }
0753     ret = pm_runtime_resume_and_get(&pdev->dev);
0754     if (ret < 0)
0755         goto err_suspend;
0756 
0757     rst = devm_reset_control_get_exclusive(&pdev->dev, "rst");
0758     if (IS_ERR(rst)) {
0759         if (PTR_ERR(rst) == -EPROBE_DEFER) {
0760             ret = -EPROBE_DEFER;
0761             goto err_pm_put;
0762         }
0763         dev_dbg(dev, "No top level reset found\n");
0764         img_spdif_in_writel(spdif, IMG_SPDIF_IN_SOFT_RESET_MASK,
0765                 IMG_SPDIF_IN_SOFT_RESET);
0766         img_spdif_in_writel(spdif, 0, IMG_SPDIF_IN_SOFT_RESET);
0767     } else {
0768         reset_control_assert(rst);
0769         reset_control_deassert(rst);
0770     }
0771 
0772     spin_lock_init(&spdif->lock);
0773 
0774     spdif->dma_data.addr = res->start + IMG_SPDIF_IN_RX_FIFO_OFFSET;
0775     spdif->dma_data.addr_width = 4;
0776     spdif->dma_data.maxburst = 4;
0777     spdif->trk = 0x80;
0778     spdif->lock_acquire = 4;
0779     spdif->lock_release = -128;
0780 
0781     reg = (spdif->lock_acquire << IMG_SPDIF_IN_CTL_LOCKHI_SHIFT) &
0782         IMG_SPDIF_IN_CTL_LOCKHI_MASK;
0783     reg |= (spdif->lock_release << IMG_SPDIF_IN_CTL_LOCKLO_SHIFT) &
0784         IMG_SPDIF_IN_CTL_LOCKLO_MASK;
0785     reg |= (spdif->trk << IMG_SPDIF_IN_CTL_TRK_SHIFT) &
0786         IMG_SPDIF_IN_CTL_TRK_MASK;
0787     img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
0788 
0789     pm_runtime_put(&pdev->dev);
0790 
0791     ret = devm_snd_soc_register_component(&pdev->dev,
0792             &img_spdif_in_component, &img_spdif_in_dai, 1);
0793     if (ret)
0794         goto err_suspend;
0795 
0796     ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
0797     if (ret)
0798         goto err_suspend;
0799 
0800     return 0;
0801 
0802 err_pm_put:
0803     pm_runtime_put(&pdev->dev);
0804 err_suspend:
0805     if (!pm_runtime_enabled(&pdev->dev))
0806         img_spdif_in_runtime_suspend(&pdev->dev);
0807 err_pm_disable:
0808     pm_runtime_disable(&pdev->dev);
0809 
0810     return ret;
0811 }
0812 
0813 static int img_spdif_in_dev_remove(struct platform_device *pdev)
0814 {
0815     pm_runtime_disable(&pdev->dev);
0816     if (!pm_runtime_status_suspended(&pdev->dev))
0817         img_spdif_in_runtime_suspend(&pdev->dev);
0818 
0819     return 0;
0820 }
0821 
0822 #ifdef CONFIG_PM_SLEEP
0823 static int img_spdif_in_suspend(struct device *dev)
0824 {
0825     struct img_spdif_in *spdif = dev_get_drvdata(dev);
0826     int ret;
0827 
0828     if (pm_runtime_status_suspended(dev)) {
0829         ret = img_spdif_in_runtime_resume(dev);
0830         if (ret)
0831             return ret;
0832     }
0833 
0834     spdif->suspend_clkgen = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CLKGEN);
0835     spdif->suspend_ctl = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
0836 
0837     img_spdif_in_runtime_suspend(dev);
0838 
0839     return 0;
0840 }
0841 
0842 static int img_spdif_in_resume(struct device *dev)
0843 {
0844     struct img_spdif_in *spdif = dev_get_drvdata(dev);
0845     int i, ret;
0846 
0847     ret = img_spdif_in_runtime_resume(dev);
0848     if (ret)
0849         return ret;
0850 
0851     for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++)
0852         img_spdif_in_aclkgen_writel(spdif, i);
0853 
0854     img_spdif_in_writel(spdif, spdif->suspend_clkgen, IMG_SPDIF_IN_CLKGEN);
0855     img_spdif_in_writel(spdif, spdif->suspend_ctl, IMG_SPDIF_IN_CTL);
0856 
0857     if (pm_runtime_status_suspended(dev))
0858         img_spdif_in_runtime_suspend(dev);
0859 
0860     return 0;
0861 }
0862 #endif
0863 
0864 static const struct of_device_id img_spdif_in_of_match[] = {
0865     { .compatible = "img,spdif-in" },
0866     {}
0867 };
0868 MODULE_DEVICE_TABLE(of, img_spdif_in_of_match);
0869 
0870 static const struct dev_pm_ops img_spdif_in_pm_ops = {
0871     SET_RUNTIME_PM_OPS(img_spdif_in_runtime_suspend,
0872                img_spdif_in_runtime_resume, NULL)
0873     SET_SYSTEM_SLEEP_PM_OPS(img_spdif_in_suspend, img_spdif_in_resume)
0874 };
0875 
0876 static struct platform_driver img_spdif_in_driver = {
0877     .driver = {
0878         .name = "img-spdif-in",
0879         .of_match_table = img_spdif_in_of_match,
0880         .pm = &img_spdif_in_pm_ops
0881     },
0882     .probe = img_spdif_in_probe,
0883     .remove = img_spdif_in_dev_remove
0884 };
0885 module_platform_driver(img_spdif_in_driver);
0886 
0887 MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
0888 MODULE_DESCRIPTION("IMG SPDIF Input driver");
0889 MODULE_LICENSE("GPL v2");