Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * ALSA SoC SPDIF Audio Layer
0004  *
0005  * Copyright 2015 Andrea Venturi <be17068@iperbole.bo.it>
0006  * Copyright 2015 Marcus Cooper <codekipper@gmail.com>
0007  *
0008  * Based on the Allwinner SDK driver, released under the GPL.
0009  */
0010 
0011 #include <linux/clk.h>
0012 #include <linux/delay.h>
0013 #include <linux/device.h>
0014 #include <linux/kernel.h>
0015 #include <linux/init.h>
0016 #include <linux/regmap.h>
0017 #include <linux/of_address.h>
0018 #include <linux/of_device.h>
0019 #include <linux/ioport.h>
0020 #include <linux/module.h>
0021 #include <linux/platform_device.h>
0022 #include <linux/pm_runtime.h>
0023 #include <linux/reset.h>
0024 #include <linux/spinlock.h>
0025 #include <sound/asoundef.h>
0026 #include <sound/dmaengine_pcm.h>
0027 #include <sound/pcm_params.h>
0028 #include <sound/soc.h>
0029 
0030 #define SUN4I_SPDIF_CTL     (0x00)
0031     #define SUN4I_SPDIF_CTL_MCLKDIV(v)      ((v) << 4) /* v even */
0032     #define SUN4I_SPDIF_CTL_MCLKOUTEN       BIT(2)
0033     #define SUN4I_SPDIF_CTL_GEN         BIT(1)
0034     #define SUN4I_SPDIF_CTL_RESET           BIT(0)
0035 
0036 #define SUN4I_SPDIF_TXCFG   (0x04)
0037     #define SUN4I_SPDIF_TXCFG_SINGLEMOD     BIT(31)
0038     #define SUN4I_SPDIF_TXCFG_ASS           BIT(17)
0039     #define SUN4I_SPDIF_TXCFG_NONAUDIO      BIT(16)
0040     #define SUN4I_SPDIF_TXCFG_TXRATIO(v)        ((v) << 4)
0041     #define SUN4I_SPDIF_TXCFG_TXRATIO_MASK      GENMASK(8, 4)
0042     #define SUN4I_SPDIF_TXCFG_FMTRVD        GENMASK(3, 2)
0043     #define SUN4I_SPDIF_TXCFG_FMT16BIT      (0 << 2)
0044     #define SUN4I_SPDIF_TXCFG_FMT20BIT      (1 << 2)
0045     #define SUN4I_SPDIF_TXCFG_FMT24BIT      (2 << 2)
0046     #define SUN4I_SPDIF_TXCFG_CHSTMODE      BIT(1)
0047     #define SUN4I_SPDIF_TXCFG_TXEN          BIT(0)
0048 
0049 #define SUN4I_SPDIF_RXCFG   (0x08)
0050     #define SUN4I_SPDIF_RXCFG_LOCKFLAG      BIT(4)
0051     #define SUN4I_SPDIF_RXCFG_CHSTSRC       BIT(3)
0052     #define SUN4I_SPDIF_RXCFG_CHSTCP        BIT(1)
0053     #define SUN4I_SPDIF_RXCFG_RXEN          BIT(0)
0054 
0055 #define SUN4I_SPDIF_TXFIFO  (0x0C)
0056 
0057 #define SUN4I_SPDIF_RXFIFO  (0x10)
0058 
0059 #define SUN4I_SPDIF_FCTL    (0x14)
0060     #define SUN4I_SPDIF_FCTL_FIFOSRC        BIT(31)
0061     #define SUN4I_SPDIF_FCTL_FTX            BIT(17)
0062     #define SUN4I_SPDIF_FCTL_FRX            BIT(16)
0063     #define SUN4I_SPDIF_FCTL_TXTL(v)        ((v) << 8)
0064     #define SUN4I_SPDIF_FCTL_TXTL_MASK      GENMASK(12, 8)
0065     #define SUN4I_SPDIF_FCTL_RXTL(v)        ((v) << 3)
0066     #define SUN4I_SPDIF_FCTL_RXTL_MASK      GENMASK(7, 3)
0067     #define SUN4I_SPDIF_FCTL_TXIM           BIT(2)
0068     #define SUN4I_SPDIF_FCTL_RXOM(v)        ((v) << 0)
0069     #define SUN4I_SPDIF_FCTL_RXOM_MASK      GENMASK(1, 0)
0070 
0071 #define SUN50I_H6_SPDIF_FCTL (0x14)
0072     #define SUN50I_H6_SPDIF_FCTL_HUB_EN     BIT(31)
0073     #define SUN50I_H6_SPDIF_FCTL_FTX        BIT(30)
0074     #define SUN50I_H6_SPDIF_FCTL_FRX        BIT(29)
0075     #define SUN50I_H6_SPDIF_FCTL_TXTL(v)        ((v) << 12)
0076     #define SUN50I_H6_SPDIF_FCTL_TXTL_MASK      GENMASK(19, 12)
0077     #define SUN50I_H6_SPDIF_FCTL_RXTL(v)        ((v) << 4)
0078     #define SUN50I_H6_SPDIF_FCTL_RXTL_MASK      GENMASK(10, 4)
0079     #define SUN50I_H6_SPDIF_FCTL_TXIM       BIT(2)
0080     #define SUN50I_H6_SPDIF_FCTL_RXOM(v)        ((v) << 0)
0081     #define SUN50I_H6_SPDIF_FCTL_RXOM_MASK      GENMASK(1, 0)
0082 
0083 #define SUN4I_SPDIF_FSTA    (0x18)
0084     #define SUN4I_SPDIF_FSTA_TXE            BIT(14)
0085     #define SUN4I_SPDIF_FSTA_TXECNTSHT      (8)
0086     #define SUN4I_SPDIF_FSTA_RXA            BIT(6)
0087     #define SUN4I_SPDIF_FSTA_RXACNTSHT      (0)
0088 
0089 #define SUN4I_SPDIF_INT     (0x1C)
0090     #define SUN4I_SPDIF_INT_RXLOCKEN        BIT(18)
0091     #define SUN4I_SPDIF_INT_RXUNLOCKEN      BIT(17)
0092     #define SUN4I_SPDIF_INT_RXPARERREN      BIT(16)
0093     #define SUN4I_SPDIF_INT_TXDRQEN         BIT(7)
0094     #define SUN4I_SPDIF_INT_TXUIEN          BIT(6)
0095     #define SUN4I_SPDIF_INT_TXOIEN          BIT(5)
0096     #define SUN4I_SPDIF_INT_TXEIEN          BIT(4)
0097     #define SUN4I_SPDIF_INT_RXDRQEN         BIT(2)
0098     #define SUN4I_SPDIF_INT_RXOIEN          BIT(1)
0099     #define SUN4I_SPDIF_INT_RXAIEN          BIT(0)
0100 
0101 #define SUN4I_SPDIF_ISTA    (0x20)
0102     #define SUN4I_SPDIF_ISTA_RXLOCKSTA      BIT(18)
0103     #define SUN4I_SPDIF_ISTA_RXUNLOCKSTA        BIT(17)
0104     #define SUN4I_SPDIF_ISTA_RXPARERRSTA        BIT(16)
0105     #define SUN4I_SPDIF_ISTA_TXUSTA         BIT(6)
0106     #define SUN4I_SPDIF_ISTA_TXOSTA         BIT(5)
0107     #define SUN4I_SPDIF_ISTA_TXESTA         BIT(4)
0108     #define SUN4I_SPDIF_ISTA_RXOSTA         BIT(1)
0109     #define SUN4I_SPDIF_ISTA_RXASTA         BIT(0)
0110 
0111 #define SUN8I_SPDIF_TXFIFO  (0x20)
0112 
0113 #define SUN4I_SPDIF_TXCNT   (0x24)
0114 
0115 #define SUN4I_SPDIF_RXCNT   (0x28)
0116 
0117 #define SUN4I_SPDIF_TXCHSTA0    (0x2C)
0118     #define SUN4I_SPDIF_TXCHSTA0_CLK(v)     ((v) << 28)
0119     #define SUN4I_SPDIF_TXCHSTA0_SAMFREQ(v)     ((v) << 24)
0120     #define SUN4I_SPDIF_TXCHSTA0_SAMFREQ_MASK   GENMASK(27, 24)
0121     #define SUN4I_SPDIF_TXCHSTA0_CHNUM(v)       ((v) << 20)
0122     #define SUN4I_SPDIF_TXCHSTA0_CHNUM_MASK     GENMASK(23, 20)
0123     #define SUN4I_SPDIF_TXCHSTA0_SRCNUM(v)      ((v) << 16)
0124     #define SUN4I_SPDIF_TXCHSTA0_CATACOD(v)     ((v) << 8)
0125     #define SUN4I_SPDIF_TXCHSTA0_MODE(v)        ((v) << 6)
0126     #define SUN4I_SPDIF_TXCHSTA0_EMPHASIS(v)    ((v) << 3)
0127     #define SUN4I_SPDIF_TXCHSTA0_CP         BIT(2)
0128     #define SUN4I_SPDIF_TXCHSTA0_AUDIO      BIT(1)
0129     #define SUN4I_SPDIF_TXCHSTA0_PRO        BIT(0)
0130 
0131 #define SUN4I_SPDIF_TXCHSTA1    (0x30)
0132     #define SUN4I_SPDIF_TXCHSTA1_CGMSA(v)       ((v) << 8)
0133     #define SUN4I_SPDIF_TXCHSTA1_ORISAMFREQ(v)  ((v) << 4)
0134     #define SUN4I_SPDIF_TXCHSTA1_ORISAMFREQ_MASK    GENMASK(7, 4)
0135     #define SUN4I_SPDIF_TXCHSTA1_SAMWORDLEN(v)  ((v) << 1)
0136     #define SUN4I_SPDIF_TXCHSTA1_MAXWORDLEN     BIT(0)
0137 
0138 #define SUN4I_SPDIF_RXCHSTA0    (0x34)
0139     #define SUN4I_SPDIF_RXCHSTA0_CLK(v)     ((v) << 28)
0140     #define SUN4I_SPDIF_RXCHSTA0_SAMFREQ(v)     ((v) << 24)
0141     #define SUN4I_SPDIF_RXCHSTA0_CHNUM(v)       ((v) << 20)
0142     #define SUN4I_SPDIF_RXCHSTA0_SRCNUM(v)      ((v) << 16)
0143     #define SUN4I_SPDIF_RXCHSTA0_CATACOD(v)     ((v) << 8)
0144     #define SUN4I_SPDIF_RXCHSTA0_MODE(v)        ((v) << 6)
0145     #define SUN4I_SPDIF_RXCHSTA0_EMPHASIS(v)    ((v) << 3)
0146     #define SUN4I_SPDIF_RXCHSTA0_CP         BIT(2)
0147     #define SUN4I_SPDIF_RXCHSTA0_AUDIO      BIT(1)
0148     #define SUN4I_SPDIF_RXCHSTA0_PRO        BIT(0)
0149 
0150 #define SUN4I_SPDIF_RXCHSTA1    (0x38)
0151     #define SUN4I_SPDIF_RXCHSTA1_CGMSA(v)       ((v) << 8)
0152     #define SUN4I_SPDIF_RXCHSTA1_ORISAMFREQ(v)  ((v) << 4)
0153     #define SUN4I_SPDIF_RXCHSTA1_SAMWORDLEN(v)  ((v) << 1)
0154     #define SUN4I_SPDIF_RXCHSTA1_MAXWORDLEN     BIT(0)
0155 
0156 /* Defines for Sampling Frequency */
0157 #define SUN4I_SPDIF_SAMFREQ_44_1KHZ     0x0
0158 #define SUN4I_SPDIF_SAMFREQ_NOT_INDICATED   0x1
0159 #define SUN4I_SPDIF_SAMFREQ_48KHZ       0x2
0160 #define SUN4I_SPDIF_SAMFREQ_32KHZ       0x3
0161 #define SUN4I_SPDIF_SAMFREQ_22_05KHZ        0x4
0162 #define SUN4I_SPDIF_SAMFREQ_24KHZ       0x6
0163 #define SUN4I_SPDIF_SAMFREQ_88_2KHZ     0x8
0164 #define SUN4I_SPDIF_SAMFREQ_76_8KHZ     0x9
0165 #define SUN4I_SPDIF_SAMFREQ_96KHZ       0xa
0166 #define SUN4I_SPDIF_SAMFREQ_176_4KHZ        0xc
0167 #define SUN4I_SPDIF_SAMFREQ_192KHZ      0xe
0168 
0169 /**
0170  * struct sun4i_spdif_quirks - Differences between SoC variants.
0171  *
0172  * @reg_dac_txdata: TX FIFO offset for DMA config.
0173  * @has_reset: SoC needs reset deasserted.
0174  * @val_fctl_ftx: TX FIFO flush bitmask.
0175  */
0176 struct sun4i_spdif_quirks {
0177     unsigned int reg_dac_txdata;
0178     bool has_reset;
0179     unsigned int val_fctl_ftx;
0180 };
0181 
0182 struct sun4i_spdif_dev {
0183     struct platform_device *pdev;
0184     struct clk *spdif_clk;
0185     struct clk *apb_clk;
0186     struct reset_control *rst;
0187     struct snd_soc_dai_driver cpu_dai_drv;
0188     struct regmap *regmap;
0189     struct snd_dmaengine_dai_dma_data dma_params_tx;
0190     const struct sun4i_spdif_quirks *quirks;
0191     spinlock_t lock;
0192 };
0193 
0194 static void sun4i_spdif_configure(struct sun4i_spdif_dev *host)
0195 {
0196     const struct sun4i_spdif_quirks *quirks = host->quirks;
0197 
0198     /* soft reset SPDIF */
0199     regmap_write(host->regmap, SUN4I_SPDIF_CTL, SUN4I_SPDIF_CTL_RESET);
0200 
0201     /* flush TX FIFO */
0202     regmap_update_bits(host->regmap, SUN4I_SPDIF_FCTL,
0203                quirks->val_fctl_ftx, quirks->val_fctl_ftx);
0204 
0205     /* clear TX counter */
0206     regmap_write(host->regmap, SUN4I_SPDIF_TXCNT, 0);
0207 }
0208 
0209 static void sun4i_snd_txctrl_on(struct snd_pcm_substream *substream,
0210                 struct sun4i_spdif_dev *host)
0211 {
0212     if (substream->runtime->channels == 1)
0213         regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
0214                    SUN4I_SPDIF_TXCFG_SINGLEMOD,
0215                    SUN4I_SPDIF_TXCFG_SINGLEMOD);
0216 
0217     /* SPDIF TX ENABLE */
0218     regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
0219                SUN4I_SPDIF_TXCFG_TXEN, SUN4I_SPDIF_TXCFG_TXEN);
0220 
0221     /* DRQ ENABLE */
0222     regmap_update_bits(host->regmap, SUN4I_SPDIF_INT,
0223                SUN4I_SPDIF_INT_TXDRQEN, SUN4I_SPDIF_INT_TXDRQEN);
0224 
0225     /* Global enable */
0226     regmap_update_bits(host->regmap, SUN4I_SPDIF_CTL,
0227                SUN4I_SPDIF_CTL_GEN, SUN4I_SPDIF_CTL_GEN);
0228 }
0229 
0230 static void sun4i_snd_txctrl_off(struct snd_pcm_substream *substream,
0231                  struct sun4i_spdif_dev *host)
0232 {
0233     /* SPDIF TX DISABLE */
0234     regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
0235                SUN4I_SPDIF_TXCFG_TXEN, 0);
0236 
0237     /* DRQ DISABLE */
0238     regmap_update_bits(host->regmap, SUN4I_SPDIF_INT,
0239                SUN4I_SPDIF_INT_TXDRQEN, 0);
0240 
0241     /* Global disable */
0242     regmap_update_bits(host->regmap, SUN4I_SPDIF_CTL,
0243                SUN4I_SPDIF_CTL_GEN, 0);
0244 }
0245 
0246 static int sun4i_spdif_startup(struct snd_pcm_substream *substream,
0247                    struct snd_soc_dai *cpu_dai)
0248 {
0249     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0250     struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
0251 
0252     if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
0253         return -EINVAL;
0254 
0255     sun4i_spdif_configure(host);
0256 
0257     return 0;
0258 }
0259 
0260 static int sun4i_spdif_hw_params(struct snd_pcm_substream *substream,
0261                  struct snd_pcm_hw_params *params,
0262                  struct snd_soc_dai *cpu_dai)
0263 {
0264     int ret = 0;
0265     int fmt;
0266     unsigned long rate = params_rate(params);
0267     u32 mclk_div = 0;
0268     unsigned int mclk = 0;
0269     u32 reg_val;
0270     struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
0271     struct platform_device *pdev = host->pdev;
0272 
0273     /* Add the PCM and raw data select interface */
0274     switch (params_channels(params)) {
0275     case 1: /* PCM mode */
0276     case 2:
0277         fmt = 0;
0278         break;
0279     case 4: /* raw data mode */
0280         fmt = SUN4I_SPDIF_TXCFG_NONAUDIO;
0281         break;
0282     default:
0283         return -EINVAL;
0284     }
0285 
0286     switch (params_format(params)) {
0287     case SNDRV_PCM_FORMAT_S16_LE:
0288         fmt |= SUN4I_SPDIF_TXCFG_FMT16BIT;
0289         break;
0290     case SNDRV_PCM_FORMAT_S20_3LE:
0291         fmt |= SUN4I_SPDIF_TXCFG_FMT20BIT;
0292         break;
0293     case SNDRV_PCM_FORMAT_S24_LE:
0294         fmt |= SUN4I_SPDIF_TXCFG_FMT24BIT;
0295         break;
0296     default:
0297         return -EINVAL;
0298     }
0299 
0300     switch (rate) {
0301     case 22050:
0302     case 44100:
0303     case 88200:
0304     case 176400:
0305         mclk = 22579200;
0306         break;
0307     case 24000:
0308     case 32000:
0309     case 48000:
0310     case 96000:
0311     case 192000:
0312         mclk = 24576000;
0313         break;
0314     default:
0315         return -EINVAL;
0316     }
0317 
0318     ret = clk_set_rate(host->spdif_clk, mclk);
0319     if (ret < 0) {
0320         dev_err(&pdev->dev,
0321             "Setting SPDIF clock rate for %d Hz failed!\n", mclk);
0322         return ret;
0323     }
0324 
0325     regmap_update_bits(host->regmap, SUN4I_SPDIF_FCTL,
0326                SUN4I_SPDIF_FCTL_TXIM, SUN4I_SPDIF_FCTL_TXIM);
0327 
0328     switch (rate) {
0329     case 22050:
0330     case 24000:
0331         mclk_div = 8;
0332         break;
0333     case 32000:
0334         mclk_div = 6;
0335         break;
0336     case 44100:
0337     case 48000:
0338         mclk_div = 4;
0339         break;
0340     case 88200:
0341     case 96000:
0342         mclk_div = 2;
0343         break;
0344     case 176400:
0345     case 192000:
0346         mclk_div = 1;
0347         break;
0348     default:
0349         return -EINVAL;
0350     }
0351 
0352     reg_val = 0;
0353     reg_val |= SUN4I_SPDIF_TXCFG_ASS;
0354     reg_val |= fmt; /* set non audio and bit depth */
0355     reg_val |= SUN4I_SPDIF_TXCFG_CHSTMODE;
0356     reg_val |= SUN4I_SPDIF_TXCFG_TXRATIO(mclk_div - 1);
0357     regmap_write(host->regmap, SUN4I_SPDIF_TXCFG, reg_val);
0358 
0359     return 0;
0360 }
0361 
0362 static int sun4i_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
0363                    struct snd_soc_dai *dai)
0364 {
0365     int ret = 0;
0366     struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(dai);
0367 
0368     if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
0369         return -EINVAL;
0370 
0371     switch (cmd) {
0372     case SNDRV_PCM_TRIGGER_START:
0373     case SNDRV_PCM_TRIGGER_RESUME:
0374     case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0375         sun4i_snd_txctrl_on(substream, host);
0376         break;
0377 
0378     case SNDRV_PCM_TRIGGER_STOP:
0379     case SNDRV_PCM_TRIGGER_SUSPEND:
0380     case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0381         sun4i_snd_txctrl_off(substream, host);
0382         break;
0383 
0384     default:
0385         ret = -EINVAL;
0386         break;
0387     }
0388     return ret;
0389 }
0390 
0391 static int sun4i_spdif_info(struct snd_kcontrol *kcontrol,
0392                 struct snd_ctl_elem_info *uinfo)
0393 {
0394     uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
0395     uinfo->count = 1;
0396 
0397     return 0;
0398 }
0399 
0400 static int sun4i_spdif_get_status_mask(struct snd_kcontrol *kcontrol,
0401                        struct snd_ctl_elem_value *ucontrol)
0402 {
0403     u8 *status = ucontrol->value.iec958.status;
0404 
0405     status[0] = 0xff;
0406     status[1] = 0xff;
0407     status[2] = 0xff;
0408     status[3] = 0xff;
0409     status[4] = 0xff;
0410     status[5] = 0x03;
0411 
0412     return 0;
0413 }
0414 
0415 static int sun4i_spdif_get_status(struct snd_kcontrol *kcontrol,
0416                   struct snd_ctl_elem_value *ucontrol)
0417 {
0418     struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
0419     struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
0420     u8 *status = ucontrol->value.iec958.status;
0421     unsigned long flags;
0422     unsigned int reg;
0423 
0424     spin_lock_irqsave(&host->lock, flags);
0425 
0426     regmap_read(host->regmap, SUN4I_SPDIF_TXCHSTA0, &reg);
0427 
0428     status[0] = reg & 0xff;
0429     status[1] = (reg >> 8) & 0xff;
0430     status[2] = (reg >> 16) & 0xff;
0431     status[3] = (reg >> 24) & 0xff;
0432 
0433     regmap_read(host->regmap, SUN4I_SPDIF_TXCHSTA1, &reg);
0434 
0435     status[4] = reg & 0xff;
0436     status[5] = (reg >> 8) & 0x3;
0437 
0438     spin_unlock_irqrestore(&host->lock, flags);
0439 
0440     return 0;
0441 }
0442 
0443 static int sun4i_spdif_set_status(struct snd_kcontrol *kcontrol,
0444                   struct snd_ctl_elem_value *ucontrol)
0445 {
0446     struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
0447     struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
0448     u8 *status = ucontrol->value.iec958.status;
0449     unsigned long flags;
0450     unsigned int reg;
0451     bool chg0, chg1;
0452 
0453     spin_lock_irqsave(&host->lock, flags);
0454 
0455     reg = (u32)status[3] << 24;
0456     reg |= (u32)status[2] << 16;
0457     reg |= (u32)status[1] << 8;
0458     reg |= (u32)status[0];
0459 
0460     regmap_update_bits_check(host->regmap, SUN4I_SPDIF_TXCHSTA0,
0461                  GENMASK(31,0), reg, &chg0);
0462 
0463     reg = (u32)status[5] << 8;
0464     reg |= (u32)status[4];
0465 
0466     regmap_update_bits_check(host->regmap, SUN4I_SPDIF_TXCHSTA1,
0467                  GENMASK(9,0), reg, &chg1);
0468 
0469     reg = SUN4I_SPDIF_TXCFG_CHSTMODE;
0470     if (status[0] & IEC958_AES0_NONAUDIO)
0471         reg |= SUN4I_SPDIF_TXCFG_NONAUDIO;
0472 
0473     regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
0474                SUN4I_SPDIF_TXCFG_CHSTMODE |
0475                SUN4I_SPDIF_TXCFG_NONAUDIO, reg);
0476 
0477     spin_unlock_irqrestore(&host->lock, flags);
0478 
0479     return chg0 || chg1;
0480 }
0481 
0482 static struct snd_kcontrol_new sun4i_spdif_controls[] = {
0483     {
0484         .access = SNDRV_CTL_ELEM_ACCESS_READ,
0485         .iface = SNDRV_CTL_ELEM_IFACE_PCM,
0486         .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
0487         .info = sun4i_spdif_info,
0488         .get = sun4i_spdif_get_status_mask
0489     },
0490     {
0491         .iface = SNDRV_CTL_ELEM_IFACE_PCM,
0492         .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
0493         .info = sun4i_spdif_info,
0494         .get = sun4i_spdif_get_status,
0495         .put = sun4i_spdif_set_status
0496     }
0497 };
0498 
0499 static int sun4i_spdif_soc_dai_probe(struct snd_soc_dai *dai)
0500 {
0501     struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(dai);
0502 
0503     snd_soc_dai_init_dma_data(dai, &host->dma_params_tx, NULL);
0504     snd_soc_add_dai_controls(dai, sun4i_spdif_controls,
0505                  ARRAY_SIZE(sun4i_spdif_controls));
0506 
0507     return 0;
0508 }
0509 
0510 static const struct snd_soc_dai_ops sun4i_spdif_dai_ops = {
0511     .startup    = sun4i_spdif_startup,
0512     .trigger    = sun4i_spdif_trigger,
0513     .hw_params  = sun4i_spdif_hw_params,
0514 };
0515 
0516 static const struct regmap_config sun4i_spdif_regmap_config = {
0517     .reg_bits = 32,
0518     .reg_stride = 4,
0519     .val_bits = 32,
0520     .max_register = SUN4I_SPDIF_RXCHSTA1,
0521 };
0522 
0523 #define SUN4I_RATES SNDRV_PCM_RATE_8000_192000
0524 
0525 #define SUN4I_FORMATS   (SNDRV_PCM_FORMAT_S16_LE | \
0526                 SNDRV_PCM_FORMAT_S20_3LE | \
0527                 SNDRV_PCM_FORMAT_S24_LE)
0528 
0529 static struct snd_soc_dai_driver sun4i_spdif_dai = {
0530     .playback = {
0531         .channels_min = 1,
0532         .channels_max = 2,
0533         .rates = SUN4I_RATES,
0534         .formats = SUN4I_FORMATS,
0535     },
0536     .probe = sun4i_spdif_soc_dai_probe,
0537     .ops = &sun4i_spdif_dai_ops,
0538     .name = "spdif",
0539 };
0540 
0541 static const struct sun4i_spdif_quirks sun4i_a10_spdif_quirks = {
0542     .reg_dac_txdata = SUN4I_SPDIF_TXFIFO,
0543     .val_fctl_ftx   = SUN4I_SPDIF_FCTL_FTX,
0544 };
0545 
0546 static const struct sun4i_spdif_quirks sun6i_a31_spdif_quirks = {
0547     .reg_dac_txdata = SUN4I_SPDIF_TXFIFO,
0548     .val_fctl_ftx   = SUN4I_SPDIF_FCTL_FTX,
0549     .has_reset  = true,
0550 };
0551 
0552 static const struct sun4i_spdif_quirks sun8i_h3_spdif_quirks = {
0553     .reg_dac_txdata = SUN8I_SPDIF_TXFIFO,
0554     .val_fctl_ftx   = SUN4I_SPDIF_FCTL_FTX,
0555     .has_reset  = true,
0556 };
0557 
0558 static const struct sun4i_spdif_quirks sun50i_h6_spdif_quirks = {
0559     .reg_dac_txdata = SUN8I_SPDIF_TXFIFO,
0560     .val_fctl_ftx   = SUN50I_H6_SPDIF_FCTL_FTX,
0561     .has_reset      = true,
0562 };
0563 
0564 static const struct of_device_id sun4i_spdif_of_match[] = {
0565     {
0566         .compatible = "allwinner,sun4i-a10-spdif",
0567         .data = &sun4i_a10_spdif_quirks,
0568     },
0569     {
0570         .compatible = "allwinner,sun6i-a31-spdif",
0571         .data = &sun6i_a31_spdif_quirks,
0572     },
0573     {
0574         .compatible = "allwinner,sun8i-h3-spdif",
0575         .data = &sun8i_h3_spdif_quirks,
0576     },
0577     {
0578         .compatible = "allwinner,sun50i-h6-spdif",
0579         .data = &sun50i_h6_spdif_quirks,
0580     },
0581     { /* sentinel */ }
0582 };
0583 MODULE_DEVICE_TABLE(of, sun4i_spdif_of_match);
0584 
0585 static const struct snd_soc_component_driver sun4i_spdif_component = {
0586     .name           = "sun4i-spdif",
0587     .legacy_dai_naming  = 1,
0588 };
0589 
0590 static int sun4i_spdif_runtime_suspend(struct device *dev)
0591 {
0592     struct sun4i_spdif_dev *host  = dev_get_drvdata(dev);
0593 
0594     clk_disable_unprepare(host->spdif_clk);
0595     clk_disable_unprepare(host->apb_clk);
0596 
0597     return 0;
0598 }
0599 
0600 static int sun4i_spdif_runtime_resume(struct device *dev)
0601 {
0602     struct sun4i_spdif_dev *host  = dev_get_drvdata(dev);
0603     int ret;
0604 
0605     ret = clk_prepare_enable(host->spdif_clk);
0606     if (ret)
0607         return ret;
0608     ret = clk_prepare_enable(host->apb_clk);
0609     if (ret)
0610         clk_disable_unprepare(host->spdif_clk);
0611 
0612     return ret;
0613 }
0614 
0615 static int sun4i_spdif_probe(struct platform_device *pdev)
0616 {
0617     struct sun4i_spdif_dev *host;
0618     struct resource *res;
0619     const struct sun4i_spdif_quirks *quirks;
0620     int ret;
0621     void __iomem *base;
0622 
0623     dev_dbg(&pdev->dev, "Entered %s\n", __func__);
0624 
0625     host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
0626     if (!host)
0627         return -ENOMEM;
0628 
0629     host->pdev = pdev;
0630     spin_lock_init(&host->lock);
0631 
0632     /* Initialize this copy of the CPU DAI driver structure */
0633     memcpy(&host->cpu_dai_drv, &sun4i_spdif_dai, sizeof(sun4i_spdif_dai));
0634     host->cpu_dai_drv.name = dev_name(&pdev->dev);
0635 
0636     /* Get the addresses */
0637     base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
0638     if (IS_ERR(base))
0639         return PTR_ERR(base);
0640 
0641     quirks = of_device_get_match_data(&pdev->dev);
0642     if (quirks == NULL) {
0643         dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
0644         return -ENODEV;
0645     }
0646     host->quirks = quirks;
0647 
0648     host->regmap = devm_regmap_init_mmio(&pdev->dev, base,
0649                         &sun4i_spdif_regmap_config);
0650 
0651     /* Clocks */
0652     host->apb_clk = devm_clk_get(&pdev->dev, "apb");
0653     if (IS_ERR(host->apb_clk)) {
0654         dev_err(&pdev->dev, "failed to get a apb clock.\n");
0655         return PTR_ERR(host->apb_clk);
0656     }
0657 
0658     host->spdif_clk = devm_clk_get(&pdev->dev, "spdif");
0659     if (IS_ERR(host->spdif_clk)) {
0660         dev_err(&pdev->dev, "failed to get a spdif clock.\n");
0661         return PTR_ERR(host->spdif_clk);
0662     }
0663 
0664     host->dma_params_tx.addr = res->start + quirks->reg_dac_txdata;
0665     host->dma_params_tx.maxburst = 8;
0666     host->dma_params_tx.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
0667 
0668     platform_set_drvdata(pdev, host);
0669 
0670     if (quirks->has_reset) {
0671         host->rst = devm_reset_control_get_optional_exclusive(&pdev->dev,
0672                                       NULL);
0673         if (PTR_ERR(host->rst) == -EPROBE_DEFER) {
0674             ret = -EPROBE_DEFER;
0675             dev_err(&pdev->dev, "Failed to get reset: %d\n", ret);
0676             return ret;
0677         }
0678         if (!IS_ERR(host->rst))
0679             reset_control_deassert(host->rst);
0680     }
0681 
0682     ret = devm_snd_soc_register_component(&pdev->dev,
0683                 &sun4i_spdif_component, &sun4i_spdif_dai, 1);
0684     if (ret)
0685         return ret;
0686 
0687     pm_runtime_enable(&pdev->dev);
0688     if (!pm_runtime_enabled(&pdev->dev)) {
0689         ret = sun4i_spdif_runtime_resume(&pdev->dev);
0690         if (ret)
0691             goto err_unregister;
0692     }
0693 
0694     ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
0695     if (ret)
0696         goto err_suspend;
0697     return 0;
0698 err_suspend:
0699     if (!pm_runtime_status_suspended(&pdev->dev))
0700         sun4i_spdif_runtime_suspend(&pdev->dev);
0701 err_unregister:
0702     pm_runtime_disable(&pdev->dev);
0703     return ret;
0704 }
0705 
0706 static int sun4i_spdif_remove(struct platform_device *pdev)
0707 {
0708     pm_runtime_disable(&pdev->dev);
0709     if (!pm_runtime_status_suspended(&pdev->dev))
0710         sun4i_spdif_runtime_suspend(&pdev->dev);
0711 
0712     return 0;
0713 }
0714 
0715 static const struct dev_pm_ops sun4i_spdif_pm = {
0716     SET_RUNTIME_PM_OPS(sun4i_spdif_runtime_suspend,
0717                sun4i_spdif_runtime_resume, NULL)
0718 };
0719 
0720 static struct platform_driver sun4i_spdif_driver = {
0721     .driver     = {
0722         .name   = "sun4i-spdif",
0723         .of_match_table = of_match_ptr(sun4i_spdif_of_match),
0724         .pm = &sun4i_spdif_pm,
0725     },
0726     .probe      = sun4i_spdif_probe,
0727     .remove     = sun4i_spdif_remove,
0728 };
0729 
0730 module_platform_driver(sun4i_spdif_driver);
0731 
0732 MODULE_AUTHOR("Marcus Cooper <codekipper@gmail.com>");
0733 MODULE_AUTHOR("Andrea Venturi <be17068@iperbole.bo.it>");
0734 MODULE_DESCRIPTION("Allwinner sun4i SPDIF SoC Interface");
0735 MODULE_LICENSE("GPL");
0736 MODULE_ALIAS("platform:sun4i-spdif");