linux/sound/soc/rockchip/rockchip_pdm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Rockchip PDM ALSA SoC Digital Audio Interface(DAI)  driver
   4 *
   5 * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd
   6 */
   7
   8#include <linux/module.h>
   9#include <linux/clk.h>
  10#include <linux/of.h>
  11#include <linux/of_device.h>
  12#include <linux/pm_runtime.h>
  13#include <linux/rational.h>
  14#include <linux/regmap.h>
  15#include <linux/reset.h>
  16#include <sound/dmaengine_pcm.h>
  17#include <sound/pcm_params.h>
  18
  19#include "rockchip_pdm.h"
  20
  21#define PDM_DMA_BURST_SIZE      (8) /* size * width: 8*4 = 32 bytes */
  22#define PDM_SIGNOFF_CLK_RATE    (100000000)
  23
  24enum rk_pdm_version {
  25        RK_PDM_RK3229,
  26        RK_PDM_RK3308,
  27};
  28
  29struct rk_pdm_dev {
  30        struct device *dev;
  31        struct clk *clk;
  32        struct clk *hclk;
  33        struct regmap *regmap;
  34        struct snd_dmaengine_dai_dma_data capture_dma_data;
  35        struct reset_control *reset;
  36        enum rk_pdm_version version;
  37};
  38
  39struct rk_pdm_clkref {
  40        unsigned int sr;
  41        unsigned int clk;
  42        unsigned int clk_out;
  43};
  44
  45struct rk_pdm_ds_ratio {
  46        unsigned int ratio;
  47        unsigned int sr;
  48};
  49
  50static struct rk_pdm_clkref clkref[] = {
  51        { 8000, 40960000, 2048000 },
  52        { 11025, 56448000, 2822400 },
  53        { 12000, 61440000, 3072000 },
  54        { 8000, 98304000, 2048000 },
  55        { 12000, 98304000, 3072000 },
  56};
  57
  58static struct rk_pdm_ds_ratio ds_ratio[] = {
  59        { 0, 192000 },
  60        { 0, 176400 },
  61        { 0, 128000 },
  62        { 1, 96000 },
  63        { 1, 88200 },
  64        { 1, 64000 },
  65        { 2, 48000 },
  66        { 2, 44100 },
  67        { 2, 32000 },
  68        { 3, 24000 },
  69        { 3, 22050 },
  70        { 3, 16000 },
  71        { 4, 12000 },
  72        { 4, 11025 },
  73        { 4, 8000 },
  74};
  75
  76static unsigned int get_pdm_clk(struct rk_pdm_dev *pdm, unsigned int sr,
  77                                unsigned int *clk_src, unsigned int *clk_out)
  78{
  79        unsigned int i, count, clk, div, rate;
  80
  81        clk = 0;
  82        if (!sr)
  83                return clk;
  84
  85        count = ARRAY_SIZE(clkref);
  86        for (i = 0; i < count; i++) {
  87                if (sr % clkref[i].sr)
  88                        continue;
  89                div = sr / clkref[i].sr;
  90                if ((div & (div - 1)) == 0) {
  91                        *clk_out = clkref[i].clk_out;
  92                        rate = clk_round_rate(pdm->clk, clkref[i].clk);
  93                        if (rate != clkref[i].clk)
  94                                continue;
  95                        clk = clkref[i].clk;
  96                        *clk_src = clkref[i].clk;
  97                        break;
  98                }
  99        }
 100
 101        if (!clk) {
 102                clk = clk_round_rate(pdm->clk, PDM_SIGNOFF_CLK_RATE);
 103                *clk_src = clk;
 104        }
 105        return clk;
 106}
 107
 108static unsigned int get_pdm_ds_ratio(unsigned int sr)
 109{
 110        unsigned int i, count, ratio;
 111
 112        ratio = 0;
 113        if (!sr)
 114                return ratio;
 115
 116        count = ARRAY_SIZE(ds_ratio);
 117        for (i = 0; i < count; i++) {
 118                if (sr == ds_ratio[i].sr)
 119                        ratio = ds_ratio[i].ratio;
 120        }
 121        return ratio;
 122}
 123
 124static inline struct rk_pdm_dev *to_info(struct snd_soc_dai *dai)
 125{
 126        return snd_soc_dai_get_drvdata(dai);
 127}
 128
 129static void rockchip_pdm_rxctrl(struct rk_pdm_dev *pdm, int on)
 130{
 131        if (on) {
 132                regmap_update_bits(pdm->regmap, PDM_DMA_CTRL,
 133                                   PDM_DMA_RD_MSK, PDM_DMA_RD_EN);
 134                regmap_update_bits(pdm->regmap, PDM_SYSCONFIG,
 135                                   PDM_RX_MASK, PDM_RX_START);
 136        } else {
 137                regmap_update_bits(pdm->regmap, PDM_DMA_CTRL,
 138                                   PDM_DMA_RD_MSK, PDM_DMA_RD_DIS);
 139                regmap_update_bits(pdm->regmap, PDM_SYSCONFIG,
 140                                   PDM_RX_MASK | PDM_RX_CLR_MASK,
 141                                   PDM_RX_STOP | PDM_RX_CLR_WR);
 142        }
 143}
 144
 145static int rockchip_pdm_hw_params(struct snd_pcm_substream *substream,
 146                                  struct snd_pcm_hw_params *params,
 147                                  struct snd_soc_dai *dai)
 148{
 149        struct rk_pdm_dev *pdm = to_info(dai);
 150        unsigned int val = 0;
 151        unsigned int clk_rate, clk_div, samplerate;
 152        unsigned int clk_src, clk_out = 0;
 153        unsigned long m, n;
 154        bool change;
 155        int ret;
 156
 157        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 158                return 0;
 159
 160        samplerate = params_rate(params);
 161        clk_rate = get_pdm_clk(pdm, samplerate, &clk_src, &clk_out);
 162        if (!clk_rate)
 163                return -EINVAL;
 164
 165        ret = clk_set_rate(pdm->clk, clk_src);
 166        if (ret)
 167                return -EINVAL;
 168
 169        if (pdm->version == RK_PDM_RK3308) {
 170                rational_best_approximation(clk_out, clk_src,
 171                                            GENMASK(16 - 1, 0),
 172                                            GENMASK(16 - 1, 0),
 173                                            &m, &n);
 174
 175                val = (m << PDM_FD_NUMERATOR_SFT) |
 176                        (n << PDM_FD_DENOMINATOR_SFT);
 177                regmap_update_bits_check(pdm->regmap, PDM_CTRL1,
 178                                         PDM_FD_NUMERATOR_MSK |
 179                                         PDM_FD_DENOMINATOR_MSK,
 180                                         val, &change);
 181                if (change) {
 182                        reset_control_assert(pdm->reset);
 183                        reset_control_deassert(pdm->reset);
 184                        rockchip_pdm_rxctrl(pdm, 0);
 185                }
 186                clk_div = n / m;
 187                if (clk_div >= 40)
 188                        val = PDM_CLK_FD_RATIO_40;
 189                else if (clk_div <= 35)
 190                        val = PDM_CLK_FD_RATIO_35;
 191                else
 192                        return -EINVAL;
 193                regmap_update_bits(pdm->regmap, PDM_CLK_CTRL,
 194                                   PDM_CLK_FD_RATIO_MSK,
 195                                   val);
 196        }
 197        val = get_pdm_ds_ratio(samplerate);
 198        regmap_update_bits(pdm->regmap, PDM_CLK_CTRL, PDM_DS_RATIO_MSK, val);
 199        regmap_update_bits(pdm->regmap, PDM_HPF_CTRL,
 200                           PDM_HPF_CF_MSK, PDM_HPF_60HZ);
 201        regmap_update_bits(pdm->regmap, PDM_HPF_CTRL,
 202                           PDM_HPF_LE | PDM_HPF_RE, PDM_HPF_LE | PDM_HPF_RE);
 203        regmap_update_bits(pdm->regmap, PDM_CLK_CTRL, PDM_CLK_EN, PDM_CLK_EN);
 204        if (pdm->version != RK_PDM_RK3229)
 205                regmap_update_bits(pdm->regmap, PDM_CTRL0,
 206                                   PDM_MODE_MSK, PDM_MODE_LJ);
 207
 208        val = 0;
 209        switch (params_format(params)) {
 210        case SNDRV_PCM_FORMAT_S8:
 211                val |= PDM_VDW(8);
 212                break;
 213        case SNDRV_PCM_FORMAT_S16_LE:
 214                val |= PDM_VDW(16);
 215                break;
 216        case SNDRV_PCM_FORMAT_S20_3LE:
 217                val |= PDM_VDW(20);
 218                break;
 219        case SNDRV_PCM_FORMAT_S24_LE:
 220                val |= PDM_VDW(24);
 221                break;
 222        case SNDRV_PCM_FORMAT_S32_LE:
 223                val |= PDM_VDW(32);
 224                break;
 225        default:
 226                return -EINVAL;
 227        }
 228
 229        switch (params_channels(params)) {
 230        case 8:
 231                val |= PDM_PATH3_EN;
 232                fallthrough;
 233        case 6:
 234                val |= PDM_PATH2_EN;
 235                fallthrough;
 236        case 4:
 237                val |= PDM_PATH1_EN;
 238                fallthrough;
 239        case 2:
 240                val |= PDM_PATH0_EN;
 241                break;
 242        default:
 243                dev_err(pdm->dev, "invalid channel: %d\n",
 244                        params_channels(params));
 245                return -EINVAL;
 246        }
 247
 248        regmap_update_bits(pdm->regmap, PDM_CTRL0,
 249                           PDM_PATH_MSK | PDM_VDW_MSK,
 250                           val);
 251        /* all channels share the single FIFO */
 252        regmap_update_bits(pdm->regmap, PDM_DMA_CTRL, PDM_DMA_RDL_MSK,
 253                           PDM_DMA_RDL(8 * params_channels(params)));
 254
 255        return 0;
 256}
 257
 258static int rockchip_pdm_set_fmt(struct snd_soc_dai *cpu_dai,
 259                                unsigned int fmt)
 260{
 261        struct rk_pdm_dev *pdm = to_info(cpu_dai);
 262        unsigned int mask = 0, val = 0;
 263
 264        mask = PDM_CKP_MSK;
 265        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 266        case SND_SOC_DAIFMT_NB_NF:
 267                val = PDM_CKP_NORMAL;
 268                break;
 269        case SND_SOC_DAIFMT_IB_NF:
 270                val = PDM_CKP_INVERTED;
 271                break;
 272        default:
 273                return -EINVAL;
 274        }
 275
 276        pm_runtime_get_sync(cpu_dai->dev);
 277        regmap_update_bits(pdm->regmap, PDM_CLK_CTRL, mask, val);
 278        pm_runtime_put(cpu_dai->dev);
 279
 280        return 0;
 281}
 282
 283static int rockchip_pdm_trigger(struct snd_pcm_substream *substream, int cmd,
 284                                struct snd_soc_dai *dai)
 285{
 286        struct rk_pdm_dev *pdm = to_info(dai);
 287        int ret = 0;
 288
 289        switch (cmd) {
 290        case SNDRV_PCM_TRIGGER_START:
 291        case SNDRV_PCM_TRIGGER_RESUME:
 292        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 293                if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
 294                        rockchip_pdm_rxctrl(pdm, 1);
 295                break;
 296        case SNDRV_PCM_TRIGGER_SUSPEND:
 297        case SNDRV_PCM_TRIGGER_STOP:
 298        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 299                if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
 300                        rockchip_pdm_rxctrl(pdm, 0);
 301                break;
 302        default:
 303                ret = -EINVAL;
 304                break;
 305        }
 306
 307        return ret;
 308}
 309
 310static int rockchip_pdm_dai_probe(struct snd_soc_dai *dai)
 311{
 312        struct rk_pdm_dev *pdm = to_info(dai);
 313
 314        dai->capture_dma_data = &pdm->capture_dma_data;
 315
 316        return 0;
 317}
 318
 319static const struct snd_soc_dai_ops rockchip_pdm_dai_ops = {
 320        .set_fmt = rockchip_pdm_set_fmt,
 321        .trigger = rockchip_pdm_trigger,
 322        .hw_params = rockchip_pdm_hw_params,
 323};
 324
 325#define ROCKCHIP_PDM_RATES SNDRV_PCM_RATE_8000_192000
 326#define ROCKCHIP_PDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
 327                              SNDRV_PCM_FMTBIT_S20_3LE | \
 328                              SNDRV_PCM_FMTBIT_S24_LE | \
 329                              SNDRV_PCM_FMTBIT_S32_LE)
 330
 331static struct snd_soc_dai_driver rockchip_pdm_dai = {
 332        .probe = rockchip_pdm_dai_probe,
 333        .capture = {
 334                .stream_name = "Capture",
 335                .channels_min = 2,
 336                .channels_max = 8,
 337                .rates = ROCKCHIP_PDM_RATES,
 338                .formats = ROCKCHIP_PDM_FORMATS,
 339        },
 340        .ops = &rockchip_pdm_dai_ops,
 341        .symmetric_rate = 1,
 342};
 343
 344static const struct snd_soc_component_driver rockchip_pdm_component = {
 345        .name = "rockchip-pdm",
 346};
 347
 348static int rockchip_pdm_runtime_suspend(struct device *dev)
 349{
 350        struct rk_pdm_dev *pdm = dev_get_drvdata(dev);
 351
 352        clk_disable_unprepare(pdm->clk);
 353        clk_disable_unprepare(pdm->hclk);
 354
 355        return 0;
 356}
 357
 358static int rockchip_pdm_runtime_resume(struct device *dev)
 359{
 360        struct rk_pdm_dev *pdm = dev_get_drvdata(dev);
 361        int ret;
 362
 363        ret = clk_prepare_enable(pdm->clk);
 364        if (ret) {
 365                dev_err(pdm->dev, "clock enable failed %d\n", ret);
 366                return ret;
 367        }
 368
 369        ret = clk_prepare_enable(pdm->hclk);
 370        if (ret) {
 371                dev_err(pdm->dev, "hclock enable failed %d\n", ret);
 372                return ret;
 373        }
 374
 375        return 0;
 376}
 377
 378static bool rockchip_pdm_wr_reg(struct device *dev, unsigned int reg)
 379{
 380        switch (reg) {
 381        case PDM_SYSCONFIG:
 382        case PDM_CTRL0:
 383        case PDM_CTRL1:
 384        case PDM_CLK_CTRL:
 385        case PDM_HPF_CTRL:
 386        case PDM_FIFO_CTRL:
 387        case PDM_DMA_CTRL:
 388        case PDM_INT_EN:
 389        case PDM_INT_CLR:
 390        case PDM_DATA_VALID:
 391                return true;
 392        default:
 393                return false;
 394        }
 395}
 396
 397static bool rockchip_pdm_rd_reg(struct device *dev, unsigned int reg)
 398{
 399        switch (reg) {
 400        case PDM_SYSCONFIG:
 401        case PDM_CTRL0:
 402        case PDM_CTRL1:
 403        case PDM_CLK_CTRL:
 404        case PDM_HPF_CTRL:
 405        case PDM_FIFO_CTRL:
 406        case PDM_DMA_CTRL:
 407        case PDM_INT_EN:
 408        case PDM_INT_CLR:
 409        case PDM_INT_ST:
 410        case PDM_DATA_VALID:
 411        case PDM_RXFIFO_DATA:
 412        case PDM_VERSION:
 413                return true;
 414        default:
 415                return false;
 416        }
 417}
 418
 419static bool rockchip_pdm_volatile_reg(struct device *dev, unsigned int reg)
 420{
 421        switch (reg) {
 422        case PDM_SYSCONFIG:
 423        case PDM_FIFO_CTRL:
 424        case PDM_INT_CLR:
 425        case PDM_INT_ST:
 426        case PDM_RXFIFO_DATA:
 427                return true;
 428        default:
 429                return false;
 430        }
 431}
 432
 433static bool rockchip_pdm_precious_reg(struct device *dev, unsigned int reg)
 434{
 435        switch (reg) {
 436        case PDM_RXFIFO_DATA:
 437                return true;
 438        default:
 439                return false;
 440        }
 441}
 442
 443static const struct reg_default rockchip_pdm_reg_defaults[] = {
 444        {0x04, 0x78000017},
 445        {0x08, 0x0bb8ea60},
 446        {0x18, 0x0000001f},
 447};
 448
 449static const struct regmap_config rockchip_pdm_regmap_config = {
 450        .reg_bits = 32,
 451        .reg_stride = 4,
 452        .val_bits = 32,
 453        .max_register = PDM_VERSION,
 454        .reg_defaults = rockchip_pdm_reg_defaults,
 455        .num_reg_defaults = ARRAY_SIZE(rockchip_pdm_reg_defaults),
 456        .writeable_reg = rockchip_pdm_wr_reg,
 457        .readable_reg = rockchip_pdm_rd_reg,
 458        .volatile_reg = rockchip_pdm_volatile_reg,
 459        .precious_reg = rockchip_pdm_precious_reg,
 460        .cache_type = REGCACHE_FLAT,
 461};
 462
 463static const struct of_device_id rockchip_pdm_match[] __maybe_unused = {
 464        { .compatible = "rockchip,pdm",
 465          .data = (void *)RK_PDM_RK3229 },
 466        { .compatible = "rockchip,px30-pdm",
 467          .data = (void *)RK_PDM_RK3308 },
 468        { .compatible = "rockchip,rk1808-pdm",
 469          .data = (void *)RK_PDM_RK3308 },
 470        { .compatible = "rockchip,rk3308-pdm",
 471          .data = (void *)RK_PDM_RK3308 },
 472        {},
 473};
 474MODULE_DEVICE_TABLE(of, rockchip_pdm_match);
 475
 476static int rockchip_pdm_probe(struct platform_device *pdev)
 477{
 478        const struct of_device_id *match;
 479        struct rk_pdm_dev *pdm;
 480        struct resource *res;
 481        void __iomem *regs;
 482        int ret;
 483
 484        pdm = devm_kzalloc(&pdev->dev, sizeof(*pdm), GFP_KERNEL);
 485        if (!pdm)
 486                return -ENOMEM;
 487
 488        match = of_match_device(rockchip_pdm_match, &pdev->dev);
 489        if (match)
 490                pdm->version = (enum rk_pdm_version)match->data;
 491
 492        if (pdm->version == RK_PDM_RK3308) {
 493                pdm->reset = devm_reset_control_get(&pdev->dev, "pdm-m");
 494                if (IS_ERR(pdm->reset))
 495                        return PTR_ERR(pdm->reset);
 496        }
 497
 498        regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
 499        if (IS_ERR(regs))
 500                return PTR_ERR(regs);
 501
 502        pdm->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
 503                                            &rockchip_pdm_regmap_config);
 504        if (IS_ERR(pdm->regmap))
 505                return PTR_ERR(pdm->regmap);
 506
 507        pdm->capture_dma_data.addr = res->start + PDM_RXFIFO_DATA;
 508        pdm->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 509        pdm->capture_dma_data.maxburst = PDM_DMA_BURST_SIZE;
 510
 511        pdm->dev = &pdev->dev;
 512        dev_set_drvdata(&pdev->dev, pdm);
 513
 514        pdm->clk = devm_clk_get(&pdev->dev, "pdm_clk");
 515        if (IS_ERR(pdm->clk))
 516                return PTR_ERR(pdm->clk);
 517
 518        pdm->hclk = devm_clk_get(&pdev->dev, "pdm_hclk");
 519        if (IS_ERR(pdm->hclk))
 520                return PTR_ERR(pdm->hclk);
 521
 522        ret = clk_prepare_enable(pdm->hclk);
 523        if (ret)
 524                return ret;
 525
 526        pm_runtime_enable(&pdev->dev);
 527        if (!pm_runtime_enabled(&pdev->dev)) {
 528                ret = rockchip_pdm_runtime_resume(&pdev->dev);
 529                if (ret)
 530                        goto err_pm_disable;
 531        }
 532
 533        ret = devm_snd_soc_register_component(&pdev->dev,
 534                                              &rockchip_pdm_component,
 535                                              &rockchip_pdm_dai, 1);
 536
 537        if (ret) {
 538                dev_err(&pdev->dev, "could not register dai: %d\n", ret);
 539                goto err_suspend;
 540        }
 541
 542        rockchip_pdm_rxctrl(pdm, 0);
 543        ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
 544        if (ret) {
 545                dev_err(&pdev->dev, "could not register pcm: %d\n", ret);
 546                goto err_suspend;
 547        }
 548
 549        return 0;
 550
 551err_suspend:
 552        if (!pm_runtime_status_suspended(&pdev->dev))
 553                rockchip_pdm_runtime_suspend(&pdev->dev);
 554err_pm_disable:
 555        pm_runtime_disable(&pdev->dev);
 556
 557        clk_disable_unprepare(pdm->hclk);
 558
 559        return ret;
 560}
 561
 562static int rockchip_pdm_remove(struct platform_device *pdev)
 563{
 564        struct rk_pdm_dev *pdm = dev_get_drvdata(&pdev->dev);
 565
 566        pm_runtime_disable(&pdev->dev);
 567        if (!pm_runtime_status_suspended(&pdev->dev))
 568                rockchip_pdm_runtime_suspend(&pdev->dev);
 569
 570        clk_disable_unprepare(pdm->clk);
 571        clk_disable_unprepare(pdm->hclk);
 572
 573        return 0;
 574}
 575
 576#ifdef CONFIG_PM_SLEEP
 577static int rockchip_pdm_suspend(struct device *dev)
 578{
 579        struct rk_pdm_dev *pdm = dev_get_drvdata(dev);
 580
 581        regcache_mark_dirty(pdm->regmap);
 582
 583        return 0;
 584}
 585
 586static int rockchip_pdm_resume(struct device *dev)
 587{
 588        struct rk_pdm_dev *pdm = dev_get_drvdata(dev);
 589        int ret;
 590
 591        ret = pm_runtime_get_sync(dev);
 592        if (ret < 0) {
 593                pm_runtime_put(dev);
 594                return ret;
 595        }
 596
 597        ret = regcache_sync(pdm->regmap);
 598
 599        pm_runtime_put(dev);
 600
 601        return ret;
 602}
 603#endif
 604
 605static const struct dev_pm_ops rockchip_pdm_pm_ops = {
 606        SET_RUNTIME_PM_OPS(rockchip_pdm_runtime_suspend,
 607                           rockchip_pdm_runtime_resume, NULL)
 608        SET_SYSTEM_SLEEP_PM_OPS(rockchip_pdm_suspend, rockchip_pdm_resume)
 609};
 610
 611static struct platform_driver rockchip_pdm_driver = {
 612        .probe  = rockchip_pdm_probe,
 613        .remove = rockchip_pdm_remove,
 614        .driver = {
 615                .name = "rockchip-pdm",
 616                .of_match_table = of_match_ptr(rockchip_pdm_match),
 617                .pm = &rockchip_pdm_pm_ops,
 618        },
 619};
 620
 621module_platform_driver(rockchip_pdm_driver);
 622
 623MODULE_AUTHOR("Sugar <sugar.zhang@rock-chips.com>");
 624MODULE_DESCRIPTION("Rockchip PDM Controller Driver");
 625MODULE_LICENSE("GPL v2");
 626