linux/sound/soc/meson/axg-spdifout.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0 OR MIT)
   2//
   3// Copyright (c) 2018 BayLibre, SAS.
   4// Author: Jerome Brunet <jbrunet@baylibre.com>
   5
   6#include <linux/clk.h>
   7#include <linux/module.h>
   8#include <linux/of_platform.h>
   9#include <linux/regmap.h>
  10#include <sound/soc.h>
  11#include <sound/soc-dai.h>
  12#include <sound/pcm_params.h>
  13#include <sound/pcm_iec958.h>
  14
  15/*
  16 * NOTE:
  17 * The meaning of bits SPDIFOUT_CTRL0_XXX_SEL is actually the opposite
  18 * of what the documentation says. Manual control on V, U and C bits is
  19 * applied when the related sel bits are cleared
  20 */
  21
  22#define SPDIFOUT_STAT                   0x00
  23#define SPDIFOUT_GAIN0                  0x04
  24#define SPDIFOUT_GAIN1                  0x08
  25#define SPDIFOUT_CTRL0                  0x0c
  26#define  SPDIFOUT_CTRL0_EN              BIT(31)
  27#define  SPDIFOUT_CTRL0_RST_OUT         BIT(29)
  28#define  SPDIFOUT_CTRL0_RST_IN          BIT(28)
  29#define  SPDIFOUT_CTRL0_USEL            BIT(26)
  30#define  SPDIFOUT_CTRL0_USET            BIT(25)
  31#define  SPDIFOUT_CTRL0_CHSTS_SEL       BIT(24)
  32#define  SPDIFOUT_CTRL0_DATA_SEL        BIT(20)
  33#define  SPDIFOUT_CTRL0_MSB_FIRST       BIT(19)
  34#define  SPDIFOUT_CTRL0_VSEL            BIT(18)
  35#define  SPDIFOUT_CTRL0_VSET            BIT(17)
  36#define  SPDIFOUT_CTRL0_MASK_MASK       GENMASK(11, 4)
  37#define  SPDIFOUT_CTRL0_MASK(x)         ((x) << 4)
  38#define SPDIFOUT_CTRL1                  0x10
  39#define  SPDIFOUT_CTRL1_MSB_POS_MASK    GENMASK(12, 8)
  40#define  SPDIFOUT_CTRL1_MSB_POS(x)      ((x) << 8)
  41#define  SPDIFOUT_CTRL1_TYPE_MASK       GENMASK(6, 4)
  42#define  SPDIFOUT_CTRL1_TYPE(x)         ((x) << 4)
  43#define SPDIFOUT_PREAMB                 0x14
  44#define SPDIFOUT_SWAP                   0x18
  45#define SPDIFOUT_CHSTS0                 0x1c
  46#define SPDIFOUT_CHSTS1                 0x20
  47#define SPDIFOUT_CHSTS2                 0x24
  48#define SPDIFOUT_CHSTS3                 0x28
  49#define SPDIFOUT_CHSTS4                 0x2c
  50#define SPDIFOUT_CHSTS5                 0x30
  51#define SPDIFOUT_CHSTS6                 0x34
  52#define SPDIFOUT_CHSTS7                 0x38
  53#define SPDIFOUT_CHSTS8                 0x3c
  54#define SPDIFOUT_CHSTS9                 0x40
  55#define SPDIFOUT_CHSTSA                 0x44
  56#define SPDIFOUT_CHSTSB                 0x48
  57#define SPDIFOUT_MUTE_VAL               0x4c
  58
  59struct axg_spdifout {
  60        struct regmap *map;
  61        struct clk *mclk;
  62        struct clk *pclk;
  63};
  64
  65static void axg_spdifout_enable(struct regmap *map)
  66{
  67        /* Apply both reset */
  68        regmap_update_bits(map, SPDIFOUT_CTRL0,
  69                           SPDIFOUT_CTRL0_RST_OUT | SPDIFOUT_CTRL0_RST_IN,
  70                           0);
  71
  72        /* Clear out reset before in reset */
  73        regmap_update_bits(map, SPDIFOUT_CTRL0,
  74                           SPDIFOUT_CTRL0_RST_OUT, SPDIFOUT_CTRL0_RST_OUT);
  75        regmap_update_bits(map, SPDIFOUT_CTRL0,
  76                           SPDIFOUT_CTRL0_RST_IN,  SPDIFOUT_CTRL0_RST_IN);
  77
  78        /* Enable spdifout */
  79        regmap_update_bits(map, SPDIFOUT_CTRL0, SPDIFOUT_CTRL0_EN,
  80                           SPDIFOUT_CTRL0_EN);
  81}
  82
  83static void axg_spdifout_disable(struct regmap *map)
  84{
  85        regmap_update_bits(map, SPDIFOUT_CTRL0, SPDIFOUT_CTRL0_EN, 0);
  86}
  87
  88static int axg_spdifout_trigger(struct snd_pcm_substream *substream, int cmd,
  89                                struct snd_soc_dai *dai)
  90{
  91        struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
  92
  93        switch (cmd) {
  94        case SNDRV_PCM_TRIGGER_START:
  95        case SNDRV_PCM_TRIGGER_RESUME:
  96        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  97                axg_spdifout_enable(priv->map);
  98                return 0;
  99
 100        case SNDRV_PCM_TRIGGER_STOP:
 101        case SNDRV_PCM_TRIGGER_SUSPEND:
 102        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 103                axg_spdifout_disable(priv->map);
 104                return 0;
 105
 106        default:
 107                return -EINVAL;
 108        }
 109}
 110
 111static int axg_spdifout_mute(struct snd_soc_dai *dai, int mute, int direction)
 112{
 113        struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
 114
 115        /* Use spdif valid bit to perform digital mute */
 116        regmap_update_bits(priv->map, SPDIFOUT_CTRL0, SPDIFOUT_CTRL0_VSET,
 117                           mute ? SPDIFOUT_CTRL0_VSET : 0);
 118
 119        return 0;
 120}
 121
 122static int axg_spdifout_sample_fmt(struct snd_pcm_hw_params *params,
 123                                   struct snd_soc_dai *dai)
 124{
 125        struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
 126        unsigned int val;
 127
 128        /* Set the samples spdifout will pull from the FIFO */
 129        switch (params_channels(params)) {
 130        case 1:
 131                val = SPDIFOUT_CTRL0_MASK(0x1);
 132                break;
 133        case 2:
 134                val = SPDIFOUT_CTRL0_MASK(0x3);
 135                break;
 136        default:
 137                dev_err(dai->dev, "too many channels for spdif dai: %u\n",
 138                        params_channels(params));
 139                return -EINVAL;
 140        }
 141
 142        regmap_update_bits(priv->map, SPDIFOUT_CTRL0,
 143                           SPDIFOUT_CTRL0_MASK_MASK, val);
 144
 145        /* FIFO data are arranged in chunks of 64bits */
 146        switch (params_physical_width(params)) {
 147        case 8:
 148                /* 8 samples of 8 bits */
 149                val = SPDIFOUT_CTRL1_TYPE(0);
 150                break;
 151        case 16:
 152                /* 4 samples of 16 bits - right justified */
 153                val = SPDIFOUT_CTRL1_TYPE(2);
 154                break;
 155        case 32:
 156                /* 2 samples of 32 bits - right justified */
 157                val = SPDIFOUT_CTRL1_TYPE(4);
 158                break;
 159        default:
 160                dev_err(dai->dev, "Unsupported physical width: %u\n",
 161                        params_physical_width(params));
 162                return -EINVAL;
 163        }
 164
 165        /* Position of the MSB in FIFO samples */
 166        val |= SPDIFOUT_CTRL1_MSB_POS(params_width(params) - 1);
 167
 168        regmap_update_bits(priv->map, SPDIFOUT_CTRL1,
 169                           SPDIFOUT_CTRL1_MSB_POS_MASK |
 170                           SPDIFOUT_CTRL1_TYPE_MASK, val);
 171
 172        regmap_update_bits(priv->map, SPDIFOUT_CTRL0,
 173                           SPDIFOUT_CTRL0_MSB_FIRST | SPDIFOUT_CTRL0_DATA_SEL,
 174                           0);
 175
 176        return 0;
 177}
 178
 179static int axg_spdifout_set_chsts(struct snd_pcm_hw_params *params,
 180                                  struct snd_soc_dai *dai)
 181{
 182        struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
 183        unsigned int offset;
 184        int ret;
 185        u8 cs[4];
 186        u32 val;
 187
 188        ret = snd_pcm_create_iec958_consumer_hw_params(params, cs, 4);
 189        if (ret < 0) {
 190                dev_err(dai->dev, "Creating IEC958 channel status failed %d\n",
 191                        ret);
 192                return ret;
 193        }
 194        val = cs[0] | cs[1] << 8 | cs[2] << 16 | cs[3] << 24;
 195
 196        /* Setup channel status A bits [31 - 0]*/
 197        regmap_write(priv->map, SPDIFOUT_CHSTS0, val);
 198
 199        /* Clear channel status A bits [191 - 32] */
 200        for (offset = SPDIFOUT_CHSTS1; offset <= SPDIFOUT_CHSTS5;
 201             offset += regmap_get_reg_stride(priv->map))
 202                regmap_write(priv->map, offset, 0);
 203
 204        /* Setup channel status B bits [31 - 0]*/
 205        regmap_write(priv->map, SPDIFOUT_CHSTS6, val);
 206
 207        /* Clear channel status B bits [191 - 32] */
 208        for (offset = SPDIFOUT_CHSTS7; offset <= SPDIFOUT_CHSTSB;
 209             offset += regmap_get_reg_stride(priv->map))
 210                regmap_write(priv->map, offset, 0);
 211
 212        return 0;
 213}
 214
 215static int axg_spdifout_hw_params(struct snd_pcm_substream *substream,
 216                                  struct snd_pcm_hw_params *params,
 217                                  struct snd_soc_dai *dai)
 218{
 219        struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
 220        unsigned int rate = params_rate(params);
 221        int ret;
 222
 223        /* 2 * 32bits per subframe * 2 channels = 128 */
 224        ret = clk_set_rate(priv->mclk, rate * 128);
 225        if (ret) {
 226                dev_err(dai->dev, "failed to set spdif clock\n");
 227                return ret;
 228        }
 229
 230        ret = axg_spdifout_sample_fmt(params, dai);
 231        if (ret) {
 232                dev_err(dai->dev, "failed to setup sample format\n");
 233                return ret;
 234        }
 235
 236        ret = axg_spdifout_set_chsts(params, dai);
 237        if (ret) {
 238                dev_err(dai->dev, "failed to setup channel status words\n");
 239                return ret;
 240        }
 241
 242        return 0;
 243}
 244
 245static int axg_spdifout_startup(struct snd_pcm_substream *substream,
 246                                struct snd_soc_dai *dai)
 247{
 248        struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
 249        int ret;
 250
 251        /* Clock the spdif output block */
 252        ret = clk_prepare_enable(priv->pclk);
 253        if (ret) {
 254                dev_err(dai->dev, "failed to enable pclk\n");
 255                return ret;
 256        }
 257
 258        /* Make sure the block is initially stopped */
 259        axg_spdifout_disable(priv->map);
 260
 261        /* Insert data from bit 27 lsb first */
 262        regmap_update_bits(priv->map, SPDIFOUT_CTRL0,
 263                           SPDIFOUT_CTRL0_MSB_FIRST | SPDIFOUT_CTRL0_DATA_SEL,
 264                           0);
 265
 266        /* Manual control of V, C and U, U = 0 */
 267        regmap_update_bits(priv->map, SPDIFOUT_CTRL0,
 268                           SPDIFOUT_CTRL0_CHSTS_SEL | SPDIFOUT_CTRL0_VSEL |
 269                           SPDIFOUT_CTRL0_USEL | SPDIFOUT_CTRL0_USET,
 270                           0);
 271
 272        /* Static SWAP configuration ATM */
 273        regmap_write(priv->map, SPDIFOUT_SWAP, 0x10);
 274
 275        return 0;
 276}
 277
 278static void axg_spdifout_shutdown(struct snd_pcm_substream *substream,
 279                                  struct snd_soc_dai *dai)
 280{
 281        struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
 282
 283        clk_disable_unprepare(priv->pclk);
 284}
 285
 286static const struct snd_soc_dai_ops axg_spdifout_ops = {
 287        .trigger        = axg_spdifout_trigger,
 288        .mute_stream    = axg_spdifout_mute,
 289        .hw_params      = axg_spdifout_hw_params,
 290        .startup        = axg_spdifout_startup,
 291        .shutdown       = axg_spdifout_shutdown,
 292        .no_capture_mute = 1,
 293};
 294
 295static struct snd_soc_dai_driver axg_spdifout_dai_drv[] = {
 296        {
 297                .name = "SPDIF Output",
 298                .playback = {
 299                        .stream_name    = "Playback",
 300                        .channels_min   = 1,
 301                        .channels_max   = 2,
 302                        .rates          = (SNDRV_PCM_RATE_32000  |
 303                                           SNDRV_PCM_RATE_44100  |
 304                                           SNDRV_PCM_RATE_48000  |
 305                                           SNDRV_PCM_RATE_88200  |
 306                                           SNDRV_PCM_RATE_96000  |
 307                                           SNDRV_PCM_RATE_176400 |
 308                                           SNDRV_PCM_RATE_192000),
 309                        .formats        = (SNDRV_PCM_FMTBIT_S8     |
 310                                           SNDRV_PCM_FMTBIT_S16_LE |
 311                                           SNDRV_PCM_FMTBIT_S20_LE |
 312                                           SNDRV_PCM_FMTBIT_S24_LE),
 313                },
 314                .ops = &axg_spdifout_ops,
 315        },
 316};
 317
 318static const char * const spdifout_sel_texts[] = {
 319        "IN 0", "IN 1", "IN 2",
 320};
 321
 322static SOC_ENUM_SINGLE_DECL(axg_spdifout_sel_enum, SPDIFOUT_CTRL1, 24,
 323                            spdifout_sel_texts);
 324
 325static const struct snd_kcontrol_new axg_spdifout_in_mux =
 326        SOC_DAPM_ENUM("Input Source", axg_spdifout_sel_enum);
 327
 328static const struct snd_soc_dapm_widget axg_spdifout_dapm_widgets[] = {
 329        SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0),
 330        SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0),
 331        SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0),
 332        SND_SOC_DAPM_MUX("SRC SEL", SND_SOC_NOPM, 0, 0, &axg_spdifout_in_mux),
 333};
 334
 335static const struct snd_soc_dapm_route axg_spdifout_dapm_routes[] = {
 336        { "SRC SEL", "IN 0", "IN 0" },
 337        { "SRC SEL", "IN 1", "IN 1" },
 338        { "SRC SEL", "IN 2", "IN 2" },
 339        { "Playback", NULL, "SRC SEL" },
 340};
 341
 342static const struct snd_kcontrol_new axg_spdifout_controls[] = {
 343        SOC_DOUBLE("Playback Volume", SPDIFOUT_GAIN0,  0,  8, 255, 0),
 344        SOC_DOUBLE("Playback Switch", SPDIFOUT_CTRL0, 22, 21, 1, 1),
 345        SOC_SINGLE("Playback Gain Enable Switch",
 346                   SPDIFOUT_CTRL1, 26, 1, 0),
 347        SOC_SINGLE("Playback Channels Mix Switch",
 348                   SPDIFOUT_CTRL0, 23, 1, 0),
 349};
 350
 351static int axg_spdifout_set_bias_level(struct snd_soc_component *component,
 352                                       enum snd_soc_bias_level level)
 353{
 354        struct axg_spdifout *priv = snd_soc_component_get_drvdata(component);
 355        enum snd_soc_bias_level now =
 356                snd_soc_component_get_bias_level(component);
 357        int ret = 0;
 358
 359        switch (level) {
 360        case SND_SOC_BIAS_PREPARE:
 361                if (now == SND_SOC_BIAS_STANDBY)
 362                        ret = clk_prepare_enable(priv->mclk);
 363                break;
 364
 365        case SND_SOC_BIAS_STANDBY:
 366                if (now == SND_SOC_BIAS_PREPARE)
 367                        clk_disable_unprepare(priv->mclk);
 368                break;
 369
 370        case SND_SOC_BIAS_OFF:
 371        case SND_SOC_BIAS_ON:
 372                break;
 373        }
 374
 375        return ret;
 376}
 377
 378static const struct snd_soc_component_driver axg_spdifout_component_drv = {
 379        .controls               = axg_spdifout_controls,
 380        .num_controls           = ARRAY_SIZE(axg_spdifout_controls),
 381        .dapm_widgets           = axg_spdifout_dapm_widgets,
 382        .num_dapm_widgets       = ARRAY_SIZE(axg_spdifout_dapm_widgets),
 383        .dapm_routes            = axg_spdifout_dapm_routes,
 384        .num_dapm_routes        = ARRAY_SIZE(axg_spdifout_dapm_routes),
 385        .set_bias_level         = axg_spdifout_set_bias_level,
 386};
 387
 388static const struct regmap_config axg_spdifout_regmap_cfg = {
 389        .reg_bits       = 32,
 390        .val_bits       = 32,
 391        .reg_stride     = 4,
 392        .max_register   = SPDIFOUT_MUTE_VAL,
 393};
 394
 395static const struct of_device_id axg_spdifout_of_match[] = {
 396        { .compatible = "amlogic,axg-spdifout", },
 397        {}
 398};
 399MODULE_DEVICE_TABLE(of, axg_spdifout_of_match);
 400
 401static int axg_spdifout_probe(struct platform_device *pdev)
 402{
 403        struct device *dev = &pdev->dev;
 404        struct axg_spdifout *priv;
 405        void __iomem *regs;
 406        int ret;
 407
 408        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 409        if (!priv)
 410                return -ENOMEM;
 411        platform_set_drvdata(pdev, priv);
 412
 413        regs = devm_platform_ioremap_resource(pdev, 0);
 414        if (IS_ERR(regs))
 415                return PTR_ERR(regs);
 416
 417        priv->map = devm_regmap_init_mmio(dev, regs, &axg_spdifout_regmap_cfg);
 418        if (IS_ERR(priv->map)) {
 419                dev_err(dev, "failed to init regmap: %ld\n",
 420                        PTR_ERR(priv->map));
 421                return PTR_ERR(priv->map);
 422        }
 423
 424        priv->pclk = devm_clk_get(dev, "pclk");
 425        if (IS_ERR(priv->pclk)) {
 426                ret = PTR_ERR(priv->pclk);
 427                if (ret != -EPROBE_DEFER)
 428                        dev_err(dev, "failed to get pclk: %d\n", ret);
 429                return ret;
 430        }
 431
 432        priv->mclk = devm_clk_get(dev, "mclk");
 433        if (IS_ERR(priv->mclk)) {
 434                ret = PTR_ERR(priv->mclk);
 435                if (ret != -EPROBE_DEFER)
 436                        dev_err(dev, "failed to get mclk: %d\n", ret);
 437                return ret;
 438        }
 439
 440        return devm_snd_soc_register_component(dev, &axg_spdifout_component_drv,
 441                        axg_spdifout_dai_drv, ARRAY_SIZE(axg_spdifout_dai_drv));
 442}
 443
 444static struct platform_driver axg_spdifout_pdrv = {
 445        .probe = axg_spdifout_probe,
 446        .driver = {
 447                .name = "axg-spdifout",
 448                .of_match_table = axg_spdifout_of_match,
 449        },
 450};
 451module_platform_driver(axg_spdifout_pdrv);
 452
 453MODULE_DESCRIPTION("Amlogic AXG SPDIF Output driver");
 454MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
 455MODULE_LICENSE("GPL v2");
 456