root/sound/soc/sunxi/sun4i-spdif.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sun4i_spdif_configure
  2. sun4i_snd_txctrl_on
  3. sun4i_snd_txctrl_off
  4. sun4i_spdif_startup
  5. sun4i_spdif_hw_params
  6. sun4i_spdif_trigger
  7. sun4i_spdif_soc_dai_probe
  8. sun4i_spdif_runtime_suspend
  9. sun4i_spdif_runtime_resume
  10. sun4i_spdif_probe
  11. sun4i_spdif_remove

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * ALSA SoC SPDIF Audio Layer
   4  *
   5  * Copyright 2015 Andrea Venturi <be17068@iperbole.bo.it>
   6  * Copyright 2015 Marcus Cooper <codekipper@gmail.com>
   7  *
   8  * Based on the Allwinner SDK driver, released under the GPL.
   9  */
  10 
  11 #include <linux/clk.h>
  12 #include <linux/delay.h>
  13 #include <linux/device.h>
  14 #include <linux/kernel.h>
  15 #include <linux/init.h>
  16 #include <linux/regmap.h>
  17 #include <linux/of_address.h>
  18 #include <linux/of_device.h>
  19 #include <linux/ioport.h>
  20 #include <linux/module.h>
  21 #include <linux/platform_device.h>
  22 #include <linux/pm_runtime.h>
  23 #include <linux/reset.h>
  24 #include <sound/dmaengine_pcm.h>
  25 #include <sound/pcm_params.h>
  26 #include <sound/soc.h>
  27 
  28 #define SUN4I_SPDIF_CTL         (0x00)
  29         #define SUN4I_SPDIF_CTL_MCLKDIV(v)              ((v) << 4) /* v even */
  30         #define SUN4I_SPDIF_CTL_MCLKOUTEN               BIT(2)
  31         #define SUN4I_SPDIF_CTL_GEN                     BIT(1)
  32         #define SUN4I_SPDIF_CTL_RESET                   BIT(0)
  33 
  34 #define SUN4I_SPDIF_TXCFG       (0x04)
  35         #define SUN4I_SPDIF_TXCFG_SINGLEMOD             BIT(31)
  36         #define SUN4I_SPDIF_TXCFG_ASS                   BIT(17)
  37         #define SUN4I_SPDIF_TXCFG_NONAUDIO              BIT(16)
  38         #define SUN4I_SPDIF_TXCFG_TXRATIO(v)            ((v) << 4)
  39         #define SUN4I_SPDIF_TXCFG_TXRATIO_MASK          GENMASK(8, 4)
  40         #define SUN4I_SPDIF_TXCFG_FMTRVD                GENMASK(3, 2)
  41         #define SUN4I_SPDIF_TXCFG_FMT16BIT              (0 << 2)
  42         #define SUN4I_SPDIF_TXCFG_FMT20BIT              (1 << 2)
  43         #define SUN4I_SPDIF_TXCFG_FMT24BIT              (2 << 2)
  44         #define SUN4I_SPDIF_TXCFG_CHSTMODE              BIT(1)
  45         #define SUN4I_SPDIF_TXCFG_TXEN                  BIT(0)
  46 
  47 #define SUN4I_SPDIF_RXCFG       (0x08)
  48         #define SUN4I_SPDIF_RXCFG_LOCKFLAG              BIT(4)
  49         #define SUN4I_SPDIF_RXCFG_CHSTSRC               BIT(3)
  50         #define SUN4I_SPDIF_RXCFG_CHSTCP                BIT(1)
  51         #define SUN4I_SPDIF_RXCFG_RXEN                  BIT(0)
  52 
  53 #define SUN4I_SPDIF_TXFIFO      (0x0C)
  54 
  55 #define SUN4I_SPDIF_RXFIFO      (0x10)
  56 
  57 #define SUN4I_SPDIF_FCTL        (0x14)
  58         #define SUN4I_SPDIF_FCTL_FIFOSRC                BIT(31)
  59         #define SUN4I_SPDIF_FCTL_FTX                    BIT(17)
  60         #define SUN4I_SPDIF_FCTL_FRX                    BIT(16)
  61         #define SUN4I_SPDIF_FCTL_TXTL(v)                ((v) << 8)
  62         #define SUN4I_SPDIF_FCTL_TXTL_MASK              GENMASK(12, 8)
  63         #define SUN4I_SPDIF_FCTL_RXTL(v)                ((v) << 3)
  64         #define SUN4I_SPDIF_FCTL_RXTL_MASK              GENMASK(7, 3)
  65         #define SUN4I_SPDIF_FCTL_TXIM                   BIT(2)
  66         #define SUN4I_SPDIF_FCTL_RXOM(v)                ((v) << 0)
  67         #define SUN4I_SPDIF_FCTL_RXOM_MASK              GENMASK(1, 0)
  68 
  69 #define SUN50I_H6_SPDIF_FCTL (0x14)
  70         #define SUN50I_H6_SPDIF_FCTL_HUB_EN             BIT(31)
  71         #define SUN50I_H6_SPDIF_FCTL_FTX                BIT(30)
  72         #define SUN50I_H6_SPDIF_FCTL_FRX                BIT(29)
  73         #define SUN50I_H6_SPDIF_FCTL_TXTL(v)            ((v) << 12)
  74         #define SUN50I_H6_SPDIF_FCTL_TXTL_MASK          GENMASK(19, 12)
  75         #define SUN50I_H6_SPDIF_FCTL_RXTL(v)            ((v) << 4)
  76         #define SUN50I_H6_SPDIF_FCTL_RXTL_MASK          GENMASK(10, 4)
  77         #define SUN50I_H6_SPDIF_FCTL_TXIM               BIT(2)
  78         #define SUN50I_H6_SPDIF_FCTL_RXOM(v)            ((v) << 0)
  79         #define SUN50I_H6_SPDIF_FCTL_RXOM_MASK          GENMASK(1, 0)
  80 
  81 #define SUN4I_SPDIF_FSTA        (0x18)
  82         #define SUN4I_SPDIF_FSTA_TXE                    BIT(14)
  83         #define SUN4I_SPDIF_FSTA_TXECNTSHT              (8)
  84         #define SUN4I_SPDIF_FSTA_RXA                    BIT(6)
  85         #define SUN4I_SPDIF_FSTA_RXACNTSHT              (0)
  86 
  87 #define SUN4I_SPDIF_INT         (0x1C)
  88         #define SUN4I_SPDIF_INT_RXLOCKEN                BIT(18)
  89         #define SUN4I_SPDIF_INT_RXUNLOCKEN              BIT(17)
  90         #define SUN4I_SPDIF_INT_RXPARERREN              BIT(16)
  91         #define SUN4I_SPDIF_INT_TXDRQEN                 BIT(7)
  92         #define SUN4I_SPDIF_INT_TXUIEN                  BIT(6)
  93         #define SUN4I_SPDIF_INT_TXOIEN                  BIT(5)
  94         #define SUN4I_SPDIF_INT_TXEIEN                  BIT(4)
  95         #define SUN4I_SPDIF_INT_RXDRQEN                 BIT(2)
  96         #define SUN4I_SPDIF_INT_RXOIEN                  BIT(1)
  97         #define SUN4I_SPDIF_INT_RXAIEN                  BIT(0)
  98 
  99 #define SUN4I_SPDIF_ISTA        (0x20)
 100         #define SUN4I_SPDIF_ISTA_RXLOCKSTA              BIT(18)
 101         #define SUN4I_SPDIF_ISTA_RXUNLOCKSTA            BIT(17)
 102         #define SUN4I_SPDIF_ISTA_RXPARERRSTA            BIT(16)
 103         #define SUN4I_SPDIF_ISTA_TXUSTA                 BIT(6)
 104         #define SUN4I_SPDIF_ISTA_TXOSTA                 BIT(5)
 105         #define SUN4I_SPDIF_ISTA_TXESTA                 BIT(4)
 106         #define SUN4I_SPDIF_ISTA_RXOSTA                 BIT(1)
 107         #define SUN4I_SPDIF_ISTA_RXASTA                 BIT(0)
 108 
 109 #define SUN8I_SPDIF_TXFIFO      (0x20)
 110 
 111 #define SUN4I_SPDIF_TXCNT       (0x24)
 112 
 113 #define SUN4I_SPDIF_RXCNT       (0x28)
 114 
 115 #define SUN4I_SPDIF_TXCHSTA0    (0x2C)
 116         #define SUN4I_SPDIF_TXCHSTA0_CLK(v)             ((v) << 28)
 117         #define SUN4I_SPDIF_TXCHSTA0_SAMFREQ(v)         ((v) << 24)
 118         #define SUN4I_SPDIF_TXCHSTA0_SAMFREQ_MASK       GENMASK(27, 24)
 119         #define SUN4I_SPDIF_TXCHSTA0_CHNUM(v)           ((v) << 20)
 120         #define SUN4I_SPDIF_TXCHSTA0_CHNUM_MASK         GENMASK(23, 20)
 121         #define SUN4I_SPDIF_TXCHSTA0_SRCNUM(v)          ((v) << 16)
 122         #define SUN4I_SPDIF_TXCHSTA0_CATACOD(v)         ((v) << 8)
 123         #define SUN4I_SPDIF_TXCHSTA0_MODE(v)            ((v) << 6)
 124         #define SUN4I_SPDIF_TXCHSTA0_EMPHASIS(v)        ((v) << 3)
 125         #define SUN4I_SPDIF_TXCHSTA0_CP                 BIT(2)
 126         #define SUN4I_SPDIF_TXCHSTA0_AUDIO              BIT(1)
 127         #define SUN4I_SPDIF_TXCHSTA0_PRO                BIT(0)
 128 
 129 #define SUN4I_SPDIF_TXCHSTA1    (0x30)
 130         #define SUN4I_SPDIF_TXCHSTA1_CGMSA(v)           ((v) << 8)
 131         #define SUN4I_SPDIF_TXCHSTA1_ORISAMFREQ(v)      ((v) << 4)
 132         #define SUN4I_SPDIF_TXCHSTA1_ORISAMFREQ_MASK    GENMASK(7, 4)
 133         #define SUN4I_SPDIF_TXCHSTA1_SAMWORDLEN(v)      ((v) << 1)
 134         #define SUN4I_SPDIF_TXCHSTA1_MAXWORDLEN         BIT(0)
 135 
 136 #define SUN4I_SPDIF_RXCHSTA0    (0x34)
 137         #define SUN4I_SPDIF_RXCHSTA0_CLK(v)             ((v) << 28)
 138         #define SUN4I_SPDIF_RXCHSTA0_SAMFREQ(v)         ((v) << 24)
 139         #define SUN4I_SPDIF_RXCHSTA0_CHNUM(v)           ((v) << 20)
 140         #define SUN4I_SPDIF_RXCHSTA0_SRCNUM(v)          ((v) << 16)
 141         #define SUN4I_SPDIF_RXCHSTA0_CATACOD(v)         ((v) << 8)
 142         #define SUN4I_SPDIF_RXCHSTA0_MODE(v)            ((v) << 6)
 143         #define SUN4I_SPDIF_RXCHSTA0_EMPHASIS(v)        ((v) << 3)
 144         #define SUN4I_SPDIF_RXCHSTA0_CP                 BIT(2)
 145         #define SUN4I_SPDIF_RXCHSTA0_AUDIO              BIT(1)
 146         #define SUN4I_SPDIF_RXCHSTA0_PRO                BIT(0)
 147 
 148 #define SUN4I_SPDIF_RXCHSTA1    (0x38)
 149         #define SUN4I_SPDIF_RXCHSTA1_CGMSA(v)           ((v) << 8)
 150         #define SUN4I_SPDIF_RXCHSTA1_ORISAMFREQ(v)      ((v) << 4)
 151         #define SUN4I_SPDIF_RXCHSTA1_SAMWORDLEN(v)      ((v) << 1)
 152         #define SUN4I_SPDIF_RXCHSTA1_MAXWORDLEN         BIT(0)
 153 
 154 /* Defines for Sampling Frequency */
 155 #define SUN4I_SPDIF_SAMFREQ_44_1KHZ             0x0
 156 #define SUN4I_SPDIF_SAMFREQ_NOT_INDICATED       0x1
 157 #define SUN4I_SPDIF_SAMFREQ_48KHZ               0x2
 158 #define SUN4I_SPDIF_SAMFREQ_32KHZ               0x3
 159 #define SUN4I_SPDIF_SAMFREQ_22_05KHZ            0x4
 160 #define SUN4I_SPDIF_SAMFREQ_24KHZ               0x6
 161 #define SUN4I_SPDIF_SAMFREQ_88_2KHZ             0x8
 162 #define SUN4I_SPDIF_SAMFREQ_76_8KHZ             0x9
 163 #define SUN4I_SPDIF_SAMFREQ_96KHZ               0xa
 164 #define SUN4I_SPDIF_SAMFREQ_176_4KHZ            0xc
 165 #define SUN4I_SPDIF_SAMFREQ_192KHZ              0xe
 166 
 167 /**
 168  * struct sun4i_spdif_quirks - Differences between SoC variants.
 169  *
 170  * @reg_dac_tx_data: TX FIFO offset for DMA config.
 171  * @has_reset: SoC needs reset deasserted.
 172  * @val_fctl_ftx: TX FIFO flush bitmask.
 173  */
 174 struct sun4i_spdif_quirks {
 175         unsigned int reg_dac_txdata;
 176         bool has_reset;
 177         unsigned int val_fctl_ftx;
 178 };
 179 
 180 struct sun4i_spdif_dev {
 181         struct platform_device *pdev;
 182         struct clk *spdif_clk;
 183         struct clk *apb_clk;
 184         struct reset_control *rst;
 185         struct snd_soc_dai_driver cpu_dai_drv;
 186         struct regmap *regmap;
 187         struct snd_dmaengine_dai_dma_data dma_params_tx;
 188         const struct sun4i_spdif_quirks *quirks;
 189 };
 190 
 191 static void sun4i_spdif_configure(struct sun4i_spdif_dev *host)
 192 {
 193         const struct sun4i_spdif_quirks *quirks = host->quirks;
 194 
 195         /* soft reset SPDIF */
 196         regmap_write(host->regmap, SUN4I_SPDIF_CTL, SUN4I_SPDIF_CTL_RESET);
 197 
 198         /* flush TX FIFO */
 199         regmap_update_bits(host->regmap, SUN4I_SPDIF_FCTL,
 200                            quirks->val_fctl_ftx, quirks->val_fctl_ftx);
 201 
 202         /* clear TX counter */
 203         regmap_write(host->regmap, SUN4I_SPDIF_TXCNT, 0);
 204 }
 205 
 206 static void sun4i_snd_txctrl_on(struct snd_pcm_substream *substream,
 207                                 struct sun4i_spdif_dev *host)
 208 {
 209         if (substream->runtime->channels == 1)
 210                 regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
 211                                    SUN4I_SPDIF_TXCFG_SINGLEMOD,
 212                                    SUN4I_SPDIF_TXCFG_SINGLEMOD);
 213 
 214         /* SPDIF TX ENABLE */
 215         regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
 216                            SUN4I_SPDIF_TXCFG_TXEN, SUN4I_SPDIF_TXCFG_TXEN);
 217 
 218         /* DRQ ENABLE */
 219         regmap_update_bits(host->regmap, SUN4I_SPDIF_INT,
 220                            SUN4I_SPDIF_INT_TXDRQEN, SUN4I_SPDIF_INT_TXDRQEN);
 221 
 222         /* Global enable */
 223         regmap_update_bits(host->regmap, SUN4I_SPDIF_CTL,
 224                            SUN4I_SPDIF_CTL_GEN, SUN4I_SPDIF_CTL_GEN);
 225 }
 226 
 227 static void sun4i_snd_txctrl_off(struct snd_pcm_substream *substream,
 228                                  struct sun4i_spdif_dev *host)
 229 {
 230         /* SPDIF TX DISABLE */
 231         regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
 232                            SUN4I_SPDIF_TXCFG_TXEN, 0);
 233 
 234         /* DRQ DISABLE */
 235         regmap_update_bits(host->regmap, SUN4I_SPDIF_INT,
 236                            SUN4I_SPDIF_INT_TXDRQEN, 0);
 237 
 238         /* Global disable */
 239         regmap_update_bits(host->regmap, SUN4I_SPDIF_CTL,
 240                            SUN4I_SPDIF_CTL_GEN, 0);
 241 }
 242 
 243 static int sun4i_spdif_startup(struct snd_pcm_substream *substream,
 244                                struct snd_soc_dai *cpu_dai)
 245 {
 246         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 247         struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(rtd->cpu_dai);
 248 
 249         if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
 250                 return -EINVAL;
 251 
 252         sun4i_spdif_configure(host);
 253 
 254         return 0;
 255 }
 256 
 257 static int sun4i_spdif_hw_params(struct snd_pcm_substream *substream,
 258                                  struct snd_pcm_hw_params *params,
 259                                  struct snd_soc_dai *cpu_dai)
 260 {
 261         int ret = 0;
 262         int fmt;
 263         unsigned long rate = params_rate(params);
 264         u32 mclk_div = 0;
 265         unsigned int mclk = 0;
 266         u32 reg_val;
 267         struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
 268         struct platform_device *pdev = host->pdev;
 269 
 270         /* Add the PCM and raw data select interface */
 271         switch (params_channels(params)) {
 272         case 1: /* PCM mode */
 273         case 2:
 274                 fmt = 0;
 275                 break;
 276         case 4: /* raw data mode */
 277                 fmt = SUN4I_SPDIF_TXCFG_NONAUDIO;
 278                 break;
 279         default:
 280                 return -EINVAL;
 281         }
 282 
 283         switch (params_format(params)) {
 284         case SNDRV_PCM_FORMAT_S16_LE:
 285                 fmt |= SUN4I_SPDIF_TXCFG_FMT16BIT;
 286                 break;
 287         case SNDRV_PCM_FORMAT_S20_3LE:
 288                 fmt |= SUN4I_SPDIF_TXCFG_FMT20BIT;
 289                 break;
 290         case SNDRV_PCM_FORMAT_S24_LE:
 291                 fmt |= SUN4I_SPDIF_TXCFG_FMT24BIT;
 292                 break;
 293         default:
 294                 return -EINVAL;
 295         }
 296 
 297         switch (rate) {
 298         case 22050:
 299         case 44100:
 300         case 88200:
 301         case 176400:
 302                 mclk = 22579200;
 303                 break;
 304         case 24000:
 305         case 32000:
 306         case 48000:
 307         case 96000:
 308         case 192000:
 309                 mclk = 24576000;
 310                 break;
 311         default:
 312                 return -EINVAL;
 313         }
 314 
 315         ret = clk_set_rate(host->spdif_clk, mclk);
 316         if (ret < 0) {
 317                 dev_err(&pdev->dev,
 318                         "Setting SPDIF clock rate for %d Hz failed!\n", mclk);
 319                 return ret;
 320         }
 321 
 322         regmap_update_bits(host->regmap, SUN4I_SPDIF_FCTL,
 323                            SUN4I_SPDIF_FCTL_TXIM, SUN4I_SPDIF_FCTL_TXIM);
 324 
 325         switch (rate) {
 326         case 22050:
 327         case 24000:
 328                 mclk_div = 8;
 329                 break;
 330         case 32000:
 331                 mclk_div = 6;
 332                 break;
 333         case 44100:
 334         case 48000:
 335                 mclk_div = 4;
 336                 break;
 337         case 88200:
 338         case 96000:
 339                 mclk_div = 2;
 340                 break;
 341         case 176400:
 342         case 192000:
 343                 mclk_div = 1;
 344                 break;
 345         default:
 346                 return -EINVAL;
 347         }
 348 
 349         reg_val = 0;
 350         reg_val |= SUN4I_SPDIF_TXCFG_ASS;
 351         reg_val |= fmt; /* set non audio and bit depth */
 352         reg_val |= SUN4I_SPDIF_TXCFG_CHSTMODE;
 353         reg_val |= SUN4I_SPDIF_TXCFG_TXRATIO(mclk_div - 1);
 354         regmap_write(host->regmap, SUN4I_SPDIF_TXCFG, reg_val);
 355 
 356         return 0;
 357 }
 358 
 359 static int sun4i_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
 360                                struct snd_soc_dai *dai)
 361 {
 362         int ret = 0;
 363         struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(dai);
 364 
 365         if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
 366                 return -EINVAL;
 367 
 368         switch (cmd) {
 369         case SNDRV_PCM_TRIGGER_START:
 370         case SNDRV_PCM_TRIGGER_RESUME:
 371         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 372                 sun4i_snd_txctrl_on(substream, host);
 373                 break;
 374 
 375         case SNDRV_PCM_TRIGGER_STOP:
 376         case SNDRV_PCM_TRIGGER_SUSPEND:
 377         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 378                 sun4i_snd_txctrl_off(substream, host);
 379                 break;
 380 
 381         default:
 382                 ret = -EINVAL;
 383                 break;
 384         }
 385         return ret;
 386 }
 387 
 388 static int sun4i_spdif_soc_dai_probe(struct snd_soc_dai *dai)
 389 {
 390         struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(dai);
 391 
 392         snd_soc_dai_init_dma_data(dai, &host->dma_params_tx, NULL);
 393         return 0;
 394 }
 395 
 396 static const struct snd_soc_dai_ops sun4i_spdif_dai_ops = {
 397         .startup        = sun4i_spdif_startup,
 398         .trigger        = sun4i_spdif_trigger,
 399         .hw_params      = sun4i_spdif_hw_params,
 400 };
 401 
 402 static const struct regmap_config sun4i_spdif_regmap_config = {
 403         .reg_bits = 32,
 404         .reg_stride = 4,
 405         .val_bits = 32,
 406         .max_register = SUN4I_SPDIF_RXCHSTA1,
 407 };
 408 
 409 #define SUN4I_RATES     SNDRV_PCM_RATE_8000_192000
 410 
 411 #define SUN4I_FORMATS   (SNDRV_PCM_FORMAT_S16_LE | \
 412                                 SNDRV_PCM_FORMAT_S20_3LE | \
 413                                 SNDRV_PCM_FORMAT_S24_LE)
 414 
 415 static struct snd_soc_dai_driver sun4i_spdif_dai = {
 416         .playback = {
 417                 .channels_min = 1,
 418                 .channels_max = 2,
 419                 .rates = SUN4I_RATES,
 420                 .formats = SUN4I_FORMATS,
 421         },
 422         .probe = sun4i_spdif_soc_dai_probe,
 423         .ops = &sun4i_spdif_dai_ops,
 424         .name = "spdif",
 425 };
 426 
 427 static const struct sun4i_spdif_quirks sun4i_a10_spdif_quirks = {
 428         .reg_dac_txdata = SUN4I_SPDIF_TXFIFO,
 429         .val_fctl_ftx   = SUN4I_SPDIF_FCTL_FTX,
 430 };
 431 
 432 static const struct sun4i_spdif_quirks sun6i_a31_spdif_quirks = {
 433         .reg_dac_txdata = SUN4I_SPDIF_TXFIFO,
 434         .val_fctl_ftx   = SUN4I_SPDIF_FCTL_FTX,
 435         .has_reset      = true,
 436 };
 437 
 438 static const struct sun4i_spdif_quirks sun8i_h3_spdif_quirks = {
 439         .reg_dac_txdata = SUN8I_SPDIF_TXFIFO,
 440         .val_fctl_ftx   = SUN4I_SPDIF_FCTL_FTX,
 441         .has_reset      = true,
 442 };
 443 
 444 static const struct sun4i_spdif_quirks sun50i_h6_spdif_quirks = {
 445         .reg_dac_txdata = SUN8I_SPDIF_TXFIFO,
 446         .val_fctl_ftx   = SUN50I_H6_SPDIF_FCTL_FTX,
 447         .has_reset      = true,
 448 };
 449 
 450 static const struct of_device_id sun4i_spdif_of_match[] = {
 451         {
 452                 .compatible = "allwinner,sun4i-a10-spdif",
 453                 .data = &sun4i_a10_spdif_quirks,
 454         },
 455         {
 456                 .compatible = "allwinner,sun6i-a31-spdif",
 457                 .data = &sun6i_a31_spdif_quirks,
 458         },
 459         {
 460                 .compatible = "allwinner,sun8i-h3-spdif",
 461                 .data = &sun8i_h3_spdif_quirks,
 462         },
 463         {
 464                 .compatible = "allwinner,sun50i-h6-spdif",
 465                 .data = &sun50i_h6_spdif_quirks,
 466         },
 467         { /* sentinel */ }
 468 };
 469 MODULE_DEVICE_TABLE(of, sun4i_spdif_of_match);
 470 
 471 static const struct snd_soc_component_driver sun4i_spdif_component = {
 472         .name           = "sun4i-spdif",
 473 };
 474 
 475 static int sun4i_spdif_runtime_suspend(struct device *dev)
 476 {
 477         struct sun4i_spdif_dev *host  = dev_get_drvdata(dev);
 478 
 479         clk_disable_unprepare(host->spdif_clk);
 480         clk_disable_unprepare(host->apb_clk);
 481 
 482         return 0;
 483 }
 484 
 485 static int sun4i_spdif_runtime_resume(struct device *dev)
 486 {
 487         struct sun4i_spdif_dev *host  = dev_get_drvdata(dev);
 488         int ret;
 489 
 490         ret = clk_prepare_enable(host->spdif_clk);
 491         if (ret)
 492                 return ret;
 493         ret = clk_prepare_enable(host->apb_clk);
 494         if (ret)
 495                 clk_disable_unprepare(host->spdif_clk);
 496 
 497         return ret;
 498 }
 499 
 500 static int sun4i_spdif_probe(struct platform_device *pdev)
 501 {
 502         struct sun4i_spdif_dev *host;
 503         struct resource *res;
 504         const struct sun4i_spdif_quirks *quirks;
 505         int ret;
 506         void __iomem *base;
 507 
 508         dev_dbg(&pdev->dev, "Entered %s\n", __func__);
 509 
 510         host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
 511         if (!host)
 512                 return -ENOMEM;
 513 
 514         host->pdev = pdev;
 515 
 516         /* Initialize this copy of the CPU DAI driver structure */
 517         memcpy(&host->cpu_dai_drv, &sun4i_spdif_dai, sizeof(sun4i_spdif_dai));
 518         host->cpu_dai_drv.name = dev_name(&pdev->dev);
 519 
 520         /* Get the addresses */
 521         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 522         base = devm_ioremap_resource(&pdev->dev, res);
 523         if (IS_ERR(base))
 524                 return PTR_ERR(base);
 525 
 526         quirks = of_device_get_match_data(&pdev->dev);
 527         if (quirks == NULL) {
 528                 dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
 529                 return -ENODEV;
 530         }
 531         host->quirks = quirks;
 532 
 533         host->regmap = devm_regmap_init_mmio(&pdev->dev, base,
 534                                                 &sun4i_spdif_regmap_config);
 535 
 536         /* Clocks */
 537         host->apb_clk = devm_clk_get(&pdev->dev, "apb");
 538         if (IS_ERR(host->apb_clk)) {
 539                 dev_err(&pdev->dev, "failed to get a apb clock.\n");
 540                 return PTR_ERR(host->apb_clk);
 541         }
 542 
 543         host->spdif_clk = devm_clk_get(&pdev->dev, "spdif");
 544         if (IS_ERR(host->spdif_clk)) {
 545                 dev_err(&pdev->dev, "failed to get a spdif clock.\n");
 546                 return PTR_ERR(host->spdif_clk);
 547         }
 548 
 549         host->dma_params_tx.addr = res->start + quirks->reg_dac_txdata;
 550         host->dma_params_tx.maxburst = 8;
 551         host->dma_params_tx.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
 552 
 553         platform_set_drvdata(pdev, host);
 554 
 555         if (quirks->has_reset) {
 556                 host->rst = devm_reset_control_get_optional_exclusive(&pdev->dev,
 557                                                                       NULL);
 558                 if (IS_ERR(host->rst) && PTR_ERR(host->rst) == -EPROBE_DEFER) {
 559                         ret = -EPROBE_DEFER;
 560                         dev_err(&pdev->dev, "Failed to get reset: %d\n", ret);
 561                         return ret;
 562                 }
 563                 if (!IS_ERR(host->rst))
 564                         reset_control_deassert(host->rst);
 565         }
 566 
 567         ret = devm_snd_soc_register_component(&pdev->dev,
 568                                 &sun4i_spdif_component, &sun4i_spdif_dai, 1);
 569         if (ret)
 570                 return ret;
 571 
 572         pm_runtime_enable(&pdev->dev);
 573         if (!pm_runtime_enabled(&pdev->dev)) {
 574                 ret = sun4i_spdif_runtime_resume(&pdev->dev);
 575                 if (ret)
 576                         goto err_unregister;
 577         }
 578 
 579         ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
 580         if (ret)
 581                 goto err_suspend;
 582         return 0;
 583 err_suspend:
 584         if (!pm_runtime_status_suspended(&pdev->dev))
 585                 sun4i_spdif_runtime_suspend(&pdev->dev);
 586 err_unregister:
 587         pm_runtime_disable(&pdev->dev);
 588         return ret;
 589 }
 590 
 591 static int sun4i_spdif_remove(struct platform_device *pdev)
 592 {
 593         pm_runtime_disable(&pdev->dev);
 594         if (!pm_runtime_status_suspended(&pdev->dev))
 595                 sun4i_spdif_runtime_suspend(&pdev->dev);
 596 
 597         return 0;
 598 }
 599 
 600 static const struct dev_pm_ops sun4i_spdif_pm = {
 601         SET_RUNTIME_PM_OPS(sun4i_spdif_runtime_suspend,
 602                            sun4i_spdif_runtime_resume, NULL)
 603 };
 604 
 605 static struct platform_driver sun4i_spdif_driver = {
 606         .driver         = {
 607                 .name   = "sun4i-spdif",
 608                 .of_match_table = of_match_ptr(sun4i_spdif_of_match),
 609                 .pm     = &sun4i_spdif_pm,
 610         },
 611         .probe          = sun4i_spdif_probe,
 612         .remove         = sun4i_spdif_remove,
 613 };
 614 
 615 module_platform_driver(sun4i_spdif_driver);
 616 
 617 MODULE_AUTHOR("Marcus Cooper <codekipper@gmail.com>");
 618 MODULE_AUTHOR("Andrea Venturi <be17068@iperbole.bo.it>");
 619 MODULE_DESCRIPTION("Allwinner sun4i SPDIF SoC Interface");
 620 MODULE_LICENSE("GPL");
 621 MODULE_ALIAS("platform:sun4i-spdif");

/* [<][>][^][v][top][bottom][index][help] */