linux/sound/soc/zte/zx-tdm.c
<<
>>
Prefs
   1/*
   2 * ZTE's TDM driver
   3 *
   4 * Copyright (C) 2017 ZTE Ltd
   5 *
   6 * Author: Baoyou Xie <baoyou.xie@linaro.org>
   7 *
   8 * License terms: GNU General Public License (GPL) version 2
   9 */
  10
  11#include <linux/clk.h>
  12#include <linux/io.h>
  13#include <linux/mfd/syscon.h>
  14#include <linux/module.h>
  15#include <sound/dmaengine_pcm.h>
  16#include <sound/pcm_params.h>
  17#include <sound/soc.h>
  18#include <sound/soc-dai.h>
  19
  20#define REG_TIMING_CTRL         0x04
  21#define REG_TX_FIFO_CTRL        0x0C
  22#define REG_RX_FIFO_CTRL        0x10
  23#define REG_INT_EN              0x1C
  24#define REG_INT_STATUS          0x20
  25#define REG_DATABUF             0x24
  26#define REG_TS_MASK0            0x44
  27#define REG_PROCESS_CTRL        0x54
  28
  29#define FIFO_CTRL_TX_RST        BIT(0)
  30#define FIFO_CTRL_RX_RST        BIT(0)
  31#define DEAGULT_FIFO_THRES      GENMASK(4, 2)
  32
  33#define FIFO_CTRL_TX_DMA_EN     BIT(1)
  34#define FIFO_CTRL_RX_DMA_EN     BIT(1)
  35
  36#define TX_FIFO_RST_MASK        BIT(0)
  37#define RX_FIFO_RST_MASK        BIT(0)
  38
  39#define FIFOCTRL_TX_FIFO_RST    BIT(0)
  40#define FIFOCTRL_RX_FIFO_RST    BIT(0)
  41
  42#define TXTH_MASK               GENMASK(5, 2)
  43#define RXTH_MASK               GENMASK(5, 2)
  44
  45#define FIFOCTRL_THRESHOLD(x)   ((x) << 2)
  46
  47#define TIMING_MS_MASK          BIT(1)
  48/*
  49 * 00: 8 clk cycles every timeslot
  50 * 01: 16 clk cycles every timeslot
  51 * 10: 32 clk cycles every timeslot
  52 */
  53#define TIMING_SYNC_WIDTH_MASK  GENMASK(6, 5)
  54#define TIMING_WIDTH_SHIFT      5
  55#define TIMING_DEFAULT_WIDTH    0
  56#define TIMING_TS_WIDTH(x)      ((x) << TIMING_WIDTH_SHIFT)
  57#define TIMING_WIDTH_FACTOR     8
  58
  59#define TIMING_MASTER_MODE      BIT(21)
  60#define TIMING_LSB_FIRST        BIT(20)
  61#define TIMING_TS_NUM(x)        (((x) - 1) << 7)
  62#define TIMING_CLK_SEL_MASK     GENMASK(2, 0)
  63#define TIMING_CLK_SEL_DEF      BIT(2)
  64
  65#define PROCESS_TX_EN           BIT(0)
  66#define PROCESS_RX_EN           BIT(1)
  67#define PROCESS_TDM_EN          BIT(2)
  68#define PROCESS_DISABLE_ALL     0
  69
  70#define INT_DISABLE_ALL         0
  71#define INT_STATUS_MASK         GENMASK(6, 0)
  72
  73struct zx_tdm_info {
  74        struct snd_dmaengine_dai_dma_data       dma_playback;
  75        struct snd_dmaengine_dai_dma_data       dma_capture;
  76        resource_size_t                         phy_addr;
  77        void __iomem                            *regbase;
  78        struct clk                              *dai_wclk;
  79        struct clk                              *dai_pclk;
  80        int                                     master;
  81        struct device                           *dev;
  82};
  83
  84static inline u32 zx_tdm_readl(struct zx_tdm_info *tdm, u16 reg)
  85{
  86        return readl_relaxed(tdm->regbase + reg);
  87}
  88
  89static inline void zx_tdm_writel(struct zx_tdm_info *tdm, u16 reg, u32 val)
  90{
  91        writel_relaxed(val, tdm->regbase + reg);
  92}
  93
  94static void zx_tdm_tx_en(struct zx_tdm_info *tdm, bool on)
  95{
  96        unsigned long val;
  97
  98        val = zx_tdm_readl(tdm, REG_PROCESS_CTRL);
  99        if (on)
 100                val |= PROCESS_TX_EN | PROCESS_TDM_EN;
 101        else
 102                val &= ~(PROCESS_TX_EN | PROCESS_TDM_EN);
 103        zx_tdm_writel(tdm, REG_PROCESS_CTRL, val);
 104}
 105
 106static void zx_tdm_rx_en(struct zx_tdm_info *tdm, bool on)
 107{
 108        unsigned long val;
 109
 110        val = zx_tdm_readl(tdm, REG_PROCESS_CTRL);
 111        if (on)
 112                val |= PROCESS_RX_EN | PROCESS_TDM_EN;
 113        else
 114                val &= ~(PROCESS_RX_EN | PROCESS_TDM_EN);
 115        zx_tdm_writel(tdm, REG_PROCESS_CTRL, val);
 116}
 117
 118static void zx_tdm_tx_dma_en(struct zx_tdm_info *tdm, bool on)
 119{
 120        unsigned long val;
 121
 122        val = zx_tdm_readl(tdm, REG_TX_FIFO_CTRL);
 123        val |= FIFO_CTRL_TX_RST | DEAGULT_FIFO_THRES;
 124        if (on)
 125                val |= FIFO_CTRL_TX_DMA_EN;
 126        else
 127                val &= ~FIFO_CTRL_TX_DMA_EN;
 128        zx_tdm_writel(tdm, REG_TX_FIFO_CTRL, val);
 129}
 130
 131static void zx_tdm_rx_dma_en(struct zx_tdm_info *tdm, bool on)
 132{
 133        unsigned long val;
 134
 135        val = zx_tdm_readl(tdm, REG_RX_FIFO_CTRL);
 136        val |= FIFO_CTRL_RX_RST | DEAGULT_FIFO_THRES;
 137        if (on)
 138                val |= FIFO_CTRL_RX_DMA_EN;
 139        else
 140                val &= ~FIFO_CTRL_RX_DMA_EN;
 141        zx_tdm_writel(tdm, REG_RX_FIFO_CTRL, val);
 142}
 143
 144#define ZX_TDM_RATES    (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000)
 145
 146#define ZX_TDM_FMTBIT \
 147        (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_MU_LAW | \
 148        SNDRV_PCM_FORMAT_A_LAW)
 149
 150static int zx_tdm_dai_probe(struct snd_soc_dai *dai)
 151{
 152        struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev);
 153
 154        snd_soc_dai_set_drvdata(dai, zx_tdm);
 155        zx_tdm->dma_playback.addr = zx_tdm->phy_addr + REG_DATABUF;
 156        zx_tdm->dma_playback.maxburst = 16;
 157        zx_tdm->dma_capture.addr = zx_tdm->phy_addr + REG_DATABUF;
 158        zx_tdm->dma_capture.maxburst = 16;
 159        snd_soc_dai_init_dma_data(dai, &zx_tdm->dma_playback,
 160                                  &zx_tdm->dma_capture);
 161        return 0;
 162}
 163
 164static int zx_tdm_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 165{
 166        struct zx_tdm_info *tdm = snd_soc_dai_get_drvdata(cpu_dai);
 167        unsigned long val;
 168
 169        val = zx_tdm_readl(tdm, REG_TIMING_CTRL);
 170        val &= ~(TIMING_SYNC_WIDTH_MASK | TIMING_MS_MASK);
 171        val |= TIMING_DEFAULT_WIDTH << TIMING_WIDTH_SHIFT;
 172
 173        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 174        case SND_SOC_DAIFMT_CBM_CFM:
 175                tdm->master = 1;
 176                val |= TIMING_MASTER_MODE;
 177                break;
 178        case SND_SOC_DAIFMT_CBS_CFS:
 179                tdm->master = 0;
 180                val &= ~TIMING_MASTER_MODE;
 181                break;
 182        default:
 183                dev_err(cpu_dai->dev, "Unknown master/slave format\n");
 184                return -EINVAL;
 185        }
 186
 187
 188        zx_tdm_writel(tdm, REG_TIMING_CTRL, val);
 189
 190        return 0;
 191}
 192
 193static int zx_tdm_hw_params(struct snd_pcm_substream *substream,
 194                            struct snd_pcm_hw_params *params,
 195                            struct snd_soc_dai *socdai)
 196{
 197        struct zx_tdm_info *tdm = snd_soc_dai_get_drvdata(socdai);
 198        struct snd_dmaengine_dai_dma_data *dma_data;
 199        unsigned int ts_width = TIMING_DEFAULT_WIDTH;
 200        unsigned int ch_num = 32;
 201        unsigned int mask = 0;
 202        unsigned int ret = 0;
 203        unsigned long val;
 204
 205        dma_data = snd_soc_dai_get_dma_data(socdai, substream);
 206        dma_data->addr_width = ch_num >> 3;
 207
 208        switch (params_format(params)) {
 209        case SNDRV_PCM_FORMAT_MU_LAW:
 210        case SNDRV_PCM_FORMAT_A_LAW:
 211        case SNDRV_PCM_FORMAT_S16_LE:
 212                ts_width = 1;
 213                break;
 214        default:
 215                ts_width = 0;
 216                dev_err(socdai->dev, "Unknown data format\n");
 217                return -EINVAL;
 218        }
 219
 220        val = zx_tdm_readl(tdm, REG_TIMING_CTRL);
 221        val |= TIMING_TS_WIDTH(ts_width) | TIMING_TS_NUM(1);
 222        zx_tdm_writel(tdm, REG_TIMING_CTRL, val);
 223        zx_tdm_writel(tdm, REG_TS_MASK0, mask);
 224
 225        if (tdm->master)
 226                ret = clk_set_rate(tdm->dai_wclk,
 227                        params_rate(params) * TIMING_WIDTH_FACTOR * ch_num);
 228
 229        return ret;
 230}
 231
 232static int zx_tdm_trigger(struct snd_pcm_substream *substream, int cmd,
 233                          struct snd_soc_dai *dai)
 234{
 235        int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
 236        struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev);
 237        unsigned int val;
 238        int ret = 0;
 239
 240        switch (cmd) {
 241        case SNDRV_PCM_TRIGGER_START:
 242                if (capture) {
 243                        val = zx_tdm_readl(zx_tdm, REG_RX_FIFO_CTRL);
 244                        val |= FIFOCTRL_RX_FIFO_RST;
 245                        zx_tdm_writel(zx_tdm, REG_RX_FIFO_CTRL, val);
 246
 247                        zx_tdm_rx_dma_en(zx_tdm, true);
 248                } else {
 249                        val = zx_tdm_readl(zx_tdm, REG_TX_FIFO_CTRL);
 250                        val |= FIFOCTRL_TX_FIFO_RST;
 251                        zx_tdm_writel(zx_tdm, REG_TX_FIFO_CTRL, val);
 252
 253                        zx_tdm_tx_dma_en(zx_tdm, true);
 254                }
 255                break;
 256        case SNDRV_PCM_TRIGGER_RESUME:
 257        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 258                if (capture)
 259                        zx_tdm_rx_en(zx_tdm, true);
 260                else
 261                        zx_tdm_tx_en(zx_tdm, true);
 262                break;
 263        case SNDRV_PCM_TRIGGER_STOP:
 264                if (capture)
 265                        zx_tdm_rx_dma_en(zx_tdm, false);
 266                else
 267                        zx_tdm_tx_dma_en(zx_tdm, false);
 268                break;
 269        case SNDRV_PCM_TRIGGER_SUSPEND:
 270        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 271                if (capture)
 272                        zx_tdm_rx_en(zx_tdm, false);
 273                else
 274                        zx_tdm_tx_en(zx_tdm, false);
 275                break;
 276        default:
 277                ret = -EINVAL;
 278                break;
 279        }
 280
 281        return ret;
 282}
 283
 284static int zx_tdm_startup(struct snd_pcm_substream *substream,
 285                          struct snd_soc_dai *dai)
 286{
 287        struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev);
 288        int ret;
 289
 290        ret = clk_prepare_enable(zx_tdm->dai_wclk);
 291        if (ret)
 292                return ret;
 293
 294        ret = clk_prepare_enable(zx_tdm->dai_pclk);
 295        if (ret) {
 296                clk_disable_unprepare(zx_tdm->dai_wclk);
 297                return ret;
 298        }
 299
 300        return 0;
 301}
 302
 303static void zx_tdm_shutdown(struct snd_pcm_substream *substream,
 304                            struct snd_soc_dai *dai)
 305{
 306        struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev);
 307
 308        clk_disable_unprepare(zx_tdm->dai_pclk);
 309        clk_disable_unprepare(zx_tdm->dai_wclk);
 310}
 311
 312static const struct snd_soc_dai_ops zx_tdm_dai_ops = {
 313        .trigger        = zx_tdm_trigger,
 314        .hw_params      = zx_tdm_hw_params,
 315        .set_fmt        = zx_tdm_set_fmt,
 316        .startup        = zx_tdm_startup,
 317        .shutdown       = zx_tdm_shutdown,
 318};
 319
 320static const struct snd_soc_component_driver zx_tdm_component = {
 321        .name                   = "zx-tdm",
 322};
 323
 324static void zx_tdm_init_state(struct zx_tdm_info *tdm)
 325{
 326        unsigned int val;
 327
 328        zx_tdm_writel(tdm, REG_PROCESS_CTRL, PROCESS_DISABLE_ALL);
 329
 330        val = zx_tdm_readl(tdm, REG_TIMING_CTRL);
 331        val |= TIMING_LSB_FIRST;
 332        val &= ~TIMING_CLK_SEL_MASK;
 333        val |= TIMING_CLK_SEL_DEF;
 334        zx_tdm_writel(tdm, REG_TIMING_CTRL, val);
 335
 336        zx_tdm_writel(tdm, REG_INT_EN, INT_DISABLE_ALL);
 337        /*
 338         * write INT_STATUS register to clear it.
 339         */
 340        zx_tdm_writel(tdm, REG_INT_STATUS, INT_STATUS_MASK);
 341        zx_tdm_writel(tdm, REG_RX_FIFO_CTRL, FIFOCTRL_RX_FIFO_RST);
 342        zx_tdm_writel(tdm, REG_TX_FIFO_CTRL, FIFOCTRL_TX_FIFO_RST);
 343
 344        val = zx_tdm_readl(tdm, REG_RX_FIFO_CTRL);
 345        val &= ~(RXTH_MASK | RX_FIFO_RST_MASK);
 346        val |= FIFOCTRL_THRESHOLD(8);
 347        zx_tdm_writel(tdm, REG_RX_FIFO_CTRL, val);
 348
 349        val = zx_tdm_readl(tdm, REG_TX_FIFO_CTRL);
 350        val &= ~(TXTH_MASK | TX_FIFO_RST_MASK);
 351        val |= FIFOCTRL_THRESHOLD(8);
 352        zx_tdm_writel(tdm, REG_TX_FIFO_CTRL, val);
 353}
 354
 355static struct snd_soc_dai_driver zx_tdm_dai = {
 356        .name   = "zx-tdm-dai",
 357        .id     = 0,
 358        .probe  = zx_tdm_dai_probe,
 359        .playback   = {
 360                .channels_min   = 1,
 361                .channels_max   = 4,
 362                .rates          = ZX_TDM_RATES,
 363                .formats        = ZX_TDM_FMTBIT,
 364        },
 365        .capture = {
 366                .channels_min   = 1,
 367                .channels_max   = 4,
 368                .rates          = ZX_TDM_RATES,
 369                .formats        = ZX_TDM_FMTBIT,
 370        },
 371        .ops    = &zx_tdm_dai_ops,
 372};
 373
 374static int zx_tdm_probe(struct platform_device *pdev)
 375{
 376        struct device *dev = &pdev->dev;
 377        struct of_phandle_args out_args;
 378        unsigned int dma_reg_offset;
 379        struct zx_tdm_info *zx_tdm;
 380        unsigned int dma_mask;
 381        struct resource *res;
 382        struct regmap *regmap_sysctrl;
 383        int ret;
 384
 385        zx_tdm = devm_kzalloc(&pdev->dev, sizeof(*zx_tdm), GFP_KERNEL);
 386        if (!zx_tdm)
 387                return -ENOMEM;
 388
 389        zx_tdm->dev = dev;
 390
 391        zx_tdm->dai_wclk = devm_clk_get(&pdev->dev, "wclk");
 392        if (IS_ERR(zx_tdm->dai_wclk)) {
 393                dev_err(&pdev->dev, "Fail to get wclk\n");
 394                return PTR_ERR(zx_tdm->dai_wclk);
 395        }
 396
 397        zx_tdm->dai_pclk = devm_clk_get(&pdev->dev, "pclk");
 398        if (IS_ERR(zx_tdm->dai_pclk)) {
 399                dev_err(&pdev->dev, "Fail to get pclk\n");
 400                return PTR_ERR(zx_tdm->dai_pclk);
 401        }
 402
 403        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 404        zx_tdm->phy_addr = res->start;
 405        zx_tdm->regbase = devm_ioremap_resource(&pdev->dev, res);
 406        if (IS_ERR(zx_tdm->regbase))
 407                return PTR_ERR(zx_tdm->regbase);
 408
 409        ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
 410                                "zte,tdm-dma-sysctrl", 2, 0, &out_args);
 411        if (ret) {
 412                dev_err(&pdev->dev, "Fail to get zte,tdm-dma-sysctrl\n");
 413                return ret;
 414        }
 415
 416        dma_reg_offset = out_args.args[0];
 417        dma_mask = out_args.args[1];
 418        regmap_sysctrl = syscon_node_to_regmap(out_args.np);
 419        if (IS_ERR(regmap_sysctrl)) {
 420                of_node_put(out_args.np);
 421                return PTR_ERR(regmap_sysctrl);
 422        }
 423
 424        regmap_update_bits(regmap_sysctrl, dma_reg_offset, dma_mask, dma_mask);
 425        of_node_put(out_args.np);
 426
 427        zx_tdm_init_state(zx_tdm);
 428        platform_set_drvdata(pdev, zx_tdm);
 429
 430        ret = devm_snd_soc_register_component(&pdev->dev, &zx_tdm_component,
 431                                                &zx_tdm_dai, 1);
 432        if (ret) {
 433                dev_err(&pdev->dev, "Register DAI failed: %d\n", ret);
 434                return ret;
 435        }
 436
 437        ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
 438        if (ret)
 439                dev_err(&pdev->dev, "Register platform PCM failed: %d\n", ret);
 440
 441        return ret;
 442}
 443
 444static const struct of_device_id zx_tdm_dt_ids[] = {
 445        { .compatible = "zte,zx296718-tdm", },
 446        {}
 447};
 448MODULE_DEVICE_TABLE(of, zx_tdm_dt_ids);
 449
 450static struct platform_driver tdm_driver = {
 451        .probe = zx_tdm_probe,
 452        .driver = {
 453                .name = "zx-tdm",
 454                .of_match_table = zx_tdm_dt_ids,
 455        },
 456};
 457module_platform_driver(tdm_driver);
 458
 459MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
 460MODULE_DESCRIPTION("ZTE TDM DAI driver");
 461MODULE_LICENSE("GPL v2");
 462