linux/sound/soc/tegra/tegra20_i2s.c
<<
>>
Prefs
   1/*
   2 * tegra20_i2s.c - Tegra20 I2S driver
   3 *
   4 * Author: Stephen Warren <swarren@nvidia.com>
   5 * Copyright (C) 2010,2012 - NVIDIA, Inc.
   6 *
   7 * Based on code copyright/by:
   8 *
   9 * Copyright (c) 2009-2010, NVIDIA Corporation.
  10 * Scott Peterson <speterson@nvidia.com>
  11 *
  12 * Copyright (C) 2010 Google, Inc.
  13 * Iliyan Malchev <malchev@google.com>
  14 *
  15 * This program is free software; you can redistribute it and/or
  16 * modify it under the terms of the GNU General Public License
  17 * version 2 as published by the Free Software Foundation.
  18 *
  19 * This program is distributed in the hope that it will be useful, but
  20 * WITHOUT ANY WARRANTY; without even the implied warranty of
  21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  22 * General Public License for more details.
  23 *
  24 * You should have received a copy of the GNU General Public License
  25 * along with this program; if not, write to the Free Software
  26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  27 * 02110-1301 USA
  28 *
  29 */
  30
  31#include <linux/clk.h>
  32#include <linux/device.h>
  33#include <linux/io.h>
  34#include <linux/module.h>
  35#include <linux/of.h>
  36#include <linux/platform_device.h>
  37#include <linux/pm_runtime.h>
  38#include <linux/regmap.h>
  39#include <linux/slab.h>
  40#include <sound/core.h>
  41#include <sound/pcm.h>
  42#include <sound/pcm_params.h>
  43#include <sound/soc.h>
  44#include <sound/dmaengine_pcm.h>
  45
  46#include "tegra20_i2s.h"
  47
  48#define DRV_NAME "tegra20-i2s"
  49
  50static int tegra20_i2s_runtime_suspend(struct device *dev)
  51{
  52        struct tegra20_i2s *i2s = dev_get_drvdata(dev);
  53
  54        clk_disable_unprepare(i2s->clk_i2s);
  55
  56        return 0;
  57}
  58
  59static int tegra20_i2s_runtime_resume(struct device *dev)
  60{
  61        struct tegra20_i2s *i2s = dev_get_drvdata(dev);
  62        int ret;
  63
  64        ret = clk_prepare_enable(i2s->clk_i2s);
  65        if (ret) {
  66                dev_err(dev, "clk_enable failed: %d\n", ret);
  67                return ret;
  68        }
  69
  70        return 0;
  71}
  72
  73static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai,
  74                                unsigned int fmt)
  75{
  76        struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
  77        unsigned int mask, val;
  78
  79        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
  80        case SND_SOC_DAIFMT_NB_NF:
  81                break;
  82        default:
  83                return -EINVAL;
  84        }
  85
  86        mask = TEGRA20_I2S_CTRL_MASTER_ENABLE;
  87        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
  88        case SND_SOC_DAIFMT_CBS_CFS:
  89                val = TEGRA20_I2S_CTRL_MASTER_ENABLE;
  90                break;
  91        case SND_SOC_DAIFMT_CBM_CFM:
  92                break;
  93        default:
  94                return -EINVAL;
  95        }
  96
  97        mask |= TEGRA20_I2S_CTRL_BIT_FORMAT_MASK |
  98                TEGRA20_I2S_CTRL_LRCK_MASK;
  99        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 100        case SND_SOC_DAIFMT_DSP_A:
 101                val |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
 102                val |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
 103                break;
 104        case SND_SOC_DAIFMT_DSP_B:
 105                val |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
 106                val |= TEGRA20_I2S_CTRL_LRCK_R_LOW;
 107                break;
 108        case SND_SOC_DAIFMT_I2S:
 109                val |= TEGRA20_I2S_CTRL_BIT_FORMAT_I2S;
 110                val |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
 111                break;
 112        case SND_SOC_DAIFMT_RIGHT_J:
 113                val |= TEGRA20_I2S_CTRL_BIT_FORMAT_RJM;
 114                val |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
 115                break;
 116        case SND_SOC_DAIFMT_LEFT_J:
 117                val |= TEGRA20_I2S_CTRL_BIT_FORMAT_LJM;
 118                val |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
 119                break;
 120        default:
 121                return -EINVAL;
 122        }
 123
 124        regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL, mask, val);
 125
 126        return 0;
 127}
 128
 129static int tegra20_i2s_hw_params(struct snd_pcm_substream *substream,
 130                                 struct snd_pcm_hw_params *params,
 131                                 struct snd_soc_dai *dai)
 132{
 133        struct device *dev = dai->dev;
 134        struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 135        unsigned int mask, val;
 136        int ret, sample_size, srate, i2sclock, bitcnt;
 137
 138        mask = TEGRA20_I2S_CTRL_BIT_SIZE_MASK;
 139        switch (params_format(params)) {
 140        case SNDRV_PCM_FORMAT_S16_LE:
 141                val = TEGRA20_I2S_CTRL_BIT_SIZE_16;
 142                sample_size = 16;
 143                break;
 144        case SNDRV_PCM_FORMAT_S24_LE:
 145                val = TEGRA20_I2S_CTRL_BIT_SIZE_24;
 146                sample_size = 24;
 147                break;
 148        case SNDRV_PCM_FORMAT_S32_LE:
 149                val = TEGRA20_I2S_CTRL_BIT_SIZE_32;
 150                sample_size = 32;
 151                break;
 152        default:
 153                return -EINVAL;
 154        }
 155
 156        mask |= TEGRA20_I2S_CTRL_FIFO_FORMAT_MASK;
 157        val |= TEGRA20_I2S_CTRL_FIFO_FORMAT_PACKED;
 158
 159        regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL, mask, val);
 160
 161        srate = params_rate(params);
 162
 163        /* Final "* 2" required by Tegra hardware */
 164        i2sclock = srate * params_channels(params) * sample_size * 2;
 165
 166        ret = clk_set_rate(i2s->clk_i2s, i2sclock);
 167        if (ret) {
 168                dev_err(dev, "Can't set I2S clock rate: %d\n", ret);
 169                return ret;
 170        }
 171
 172        bitcnt = (i2sclock / (2 * srate)) - 1;
 173        if (bitcnt < 0 || bitcnt > TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US)
 174                return -EINVAL;
 175        val = bitcnt << TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
 176
 177        if (i2sclock % (2 * srate))
 178                val |= TEGRA20_I2S_TIMING_NON_SYM_ENABLE;
 179
 180        regmap_write(i2s->regmap, TEGRA20_I2S_TIMING, val);
 181
 182        regmap_write(i2s->regmap, TEGRA20_I2S_FIFO_SCR,
 183                     TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS |
 184                     TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS);
 185
 186        return 0;
 187}
 188
 189static void tegra20_i2s_start_playback(struct tegra20_i2s *i2s)
 190{
 191        regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL,
 192                           TEGRA20_I2S_CTRL_FIFO1_ENABLE,
 193                           TEGRA20_I2S_CTRL_FIFO1_ENABLE);
 194}
 195
 196static void tegra20_i2s_stop_playback(struct tegra20_i2s *i2s)
 197{
 198        regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL,
 199                           TEGRA20_I2S_CTRL_FIFO1_ENABLE, 0);
 200}
 201
 202static void tegra20_i2s_start_capture(struct tegra20_i2s *i2s)
 203{
 204        regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL,
 205                           TEGRA20_I2S_CTRL_FIFO2_ENABLE,
 206                           TEGRA20_I2S_CTRL_FIFO2_ENABLE);
 207}
 208
 209static void tegra20_i2s_stop_capture(struct tegra20_i2s *i2s)
 210{
 211        regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL,
 212                           TEGRA20_I2S_CTRL_FIFO2_ENABLE, 0);
 213}
 214
 215static int tegra20_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
 216                               struct snd_soc_dai *dai)
 217{
 218        struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 219
 220        switch (cmd) {
 221        case SNDRV_PCM_TRIGGER_START:
 222        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 223        case SNDRV_PCM_TRIGGER_RESUME:
 224                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 225                        tegra20_i2s_start_playback(i2s);
 226                else
 227                        tegra20_i2s_start_capture(i2s);
 228                break;
 229        case SNDRV_PCM_TRIGGER_STOP:
 230        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 231        case SNDRV_PCM_TRIGGER_SUSPEND:
 232                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 233                        tegra20_i2s_stop_playback(i2s);
 234                else
 235                        tegra20_i2s_stop_capture(i2s);
 236                break;
 237        default:
 238                return -EINVAL;
 239        }
 240
 241        return 0;
 242}
 243
 244static int tegra20_i2s_probe(struct snd_soc_dai *dai)
 245{
 246        struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 247
 248        dai->capture_dma_data = &i2s->capture_dma_data;
 249        dai->playback_dma_data = &i2s->playback_dma_data;
 250
 251        return 0;
 252}
 253
 254static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = {
 255        .set_fmt        = tegra20_i2s_set_fmt,
 256        .hw_params      = tegra20_i2s_hw_params,
 257        .trigger        = tegra20_i2s_trigger,
 258};
 259
 260static const struct snd_soc_dai_driver tegra20_i2s_dai_template = {
 261        .probe = tegra20_i2s_probe,
 262        .playback = {
 263                .stream_name = "Playback",
 264                .channels_min = 2,
 265                .channels_max = 2,
 266                .rates = SNDRV_PCM_RATE_8000_96000,
 267                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 268        },
 269        .capture = {
 270                .stream_name = "Capture",
 271                .channels_min = 2,
 272                .channels_max = 2,
 273                .rates = SNDRV_PCM_RATE_8000_96000,
 274                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 275        },
 276        .ops = &tegra20_i2s_dai_ops,
 277        .symmetric_rates = 1,
 278};
 279
 280static const struct snd_soc_component_driver tegra20_i2s_component = {
 281        .name           = DRV_NAME,
 282};
 283
 284static bool tegra20_i2s_wr_rd_reg(struct device *dev, unsigned int reg)
 285{
 286        switch (reg) {
 287        case TEGRA20_I2S_CTRL:
 288        case TEGRA20_I2S_STATUS:
 289        case TEGRA20_I2S_TIMING:
 290        case TEGRA20_I2S_FIFO_SCR:
 291        case TEGRA20_I2S_PCM_CTRL:
 292        case TEGRA20_I2S_NW_CTRL:
 293        case TEGRA20_I2S_TDM_CTRL:
 294        case TEGRA20_I2S_TDM_TX_RX_CTRL:
 295        case TEGRA20_I2S_FIFO1:
 296        case TEGRA20_I2S_FIFO2:
 297                return true;
 298        default:
 299                return false;
 300        };
 301}
 302
 303static bool tegra20_i2s_volatile_reg(struct device *dev, unsigned int reg)
 304{
 305        switch (reg) {
 306        case TEGRA20_I2S_STATUS:
 307        case TEGRA20_I2S_FIFO_SCR:
 308        case TEGRA20_I2S_FIFO1:
 309        case TEGRA20_I2S_FIFO2:
 310                return true;
 311        default:
 312                return false;
 313        };
 314}
 315
 316static bool tegra20_i2s_precious_reg(struct device *dev, unsigned int reg)
 317{
 318        switch (reg) {
 319        case TEGRA20_I2S_FIFO1:
 320        case TEGRA20_I2S_FIFO2:
 321                return true;
 322        default:
 323                return false;
 324        };
 325}
 326
 327static const struct regmap_config tegra20_i2s_regmap_config = {
 328        .reg_bits = 32,
 329        .reg_stride = 4,
 330        .val_bits = 32,
 331        .max_register = TEGRA20_I2S_FIFO2,
 332        .writeable_reg = tegra20_i2s_wr_rd_reg,
 333        .readable_reg = tegra20_i2s_wr_rd_reg,
 334        .volatile_reg = tegra20_i2s_volatile_reg,
 335        .precious_reg = tegra20_i2s_precious_reg,
 336        .cache_type = REGCACHE_RBTREE,
 337};
 338
 339static int tegra20_i2s_platform_probe(struct platform_device *pdev)
 340{
 341        struct tegra20_i2s *i2s;
 342        struct resource *mem, *memregion, *dmareq;
 343        u32 of_dma[2];
 344        u32 dma_ch;
 345        void __iomem *regs;
 346        int ret;
 347
 348        i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_i2s), GFP_KERNEL);
 349        if (!i2s) {
 350                dev_err(&pdev->dev, "Can't allocate tegra20_i2s\n");
 351                ret = -ENOMEM;
 352                goto err;
 353        }
 354        dev_set_drvdata(&pdev->dev, i2s);
 355
 356        i2s->dai = tegra20_i2s_dai_template;
 357        i2s->dai.name = dev_name(&pdev->dev);
 358
 359        i2s->clk_i2s = clk_get(&pdev->dev, NULL);
 360        if (IS_ERR(i2s->clk_i2s)) {
 361                dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
 362                ret = PTR_ERR(i2s->clk_i2s);
 363                goto err;
 364        }
 365
 366        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 367        if (!mem) {
 368                dev_err(&pdev->dev, "No memory resource\n");
 369                ret = -ENODEV;
 370                goto err_clk_put;
 371        }
 372
 373        dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
 374        if (!dmareq) {
 375                if (of_property_read_u32_array(pdev->dev.of_node,
 376                                        "nvidia,dma-request-selector",
 377                                        of_dma, 2) < 0) {
 378                        dev_err(&pdev->dev, "No DMA resource\n");
 379                        ret = -ENODEV;
 380                        goto err_clk_put;
 381                }
 382                dma_ch = of_dma[1];
 383        } else {
 384                dma_ch = dmareq->start;
 385        }
 386
 387        memregion = devm_request_mem_region(&pdev->dev, mem->start,
 388                                            resource_size(mem), DRV_NAME);
 389        if (!memregion) {
 390                dev_err(&pdev->dev, "Memory region already claimed\n");
 391                ret = -EBUSY;
 392                goto err_clk_put;
 393        }
 394
 395        regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
 396        if (!regs) {
 397                dev_err(&pdev->dev, "ioremap failed\n");
 398                ret = -ENOMEM;
 399                goto err_clk_put;
 400        }
 401
 402        i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
 403                                            &tegra20_i2s_regmap_config);
 404        if (IS_ERR(i2s->regmap)) {
 405                dev_err(&pdev->dev, "regmap init failed\n");
 406                ret = PTR_ERR(i2s->regmap);
 407                goto err_clk_put;
 408        }
 409
 410        i2s->capture_dma_data.addr = mem->start + TEGRA20_I2S_FIFO2;
 411        i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 412        i2s->capture_dma_data.maxburst = 4;
 413        i2s->capture_dma_data.slave_id = dma_ch;
 414
 415        i2s->playback_dma_data.addr = mem->start + TEGRA20_I2S_FIFO1;
 416        i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 417        i2s->playback_dma_data.maxburst = 4;
 418        i2s->playback_dma_data.slave_id = dma_ch;
 419
 420        pm_runtime_enable(&pdev->dev);
 421        if (!pm_runtime_enabled(&pdev->dev)) {
 422                ret = tegra20_i2s_runtime_resume(&pdev->dev);
 423                if (ret)
 424                        goto err_pm_disable;
 425        }
 426
 427        ret = snd_soc_register_component(&pdev->dev, &tegra20_i2s_component,
 428                                         &i2s->dai, 1);
 429        if (ret) {
 430                dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
 431                ret = -ENOMEM;
 432                goto err_suspend;
 433        }
 434
 435        ret = tegra_pcm_platform_register(&pdev->dev);
 436        if (ret) {
 437                dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
 438                goto err_unregister_component;
 439        }
 440
 441        return 0;
 442
 443err_unregister_component:
 444        snd_soc_unregister_component(&pdev->dev);
 445err_suspend:
 446        if (!pm_runtime_status_suspended(&pdev->dev))
 447                tegra20_i2s_runtime_suspend(&pdev->dev);
 448err_pm_disable:
 449        pm_runtime_disable(&pdev->dev);
 450err_clk_put:
 451        clk_put(i2s->clk_i2s);
 452err:
 453        return ret;
 454}
 455
 456static int tegra20_i2s_platform_remove(struct platform_device *pdev)
 457{
 458        struct tegra20_i2s *i2s = dev_get_drvdata(&pdev->dev);
 459
 460        pm_runtime_disable(&pdev->dev);
 461        if (!pm_runtime_status_suspended(&pdev->dev))
 462                tegra20_i2s_runtime_suspend(&pdev->dev);
 463
 464        tegra_pcm_platform_unregister(&pdev->dev);
 465        snd_soc_unregister_component(&pdev->dev);
 466
 467        clk_put(i2s->clk_i2s);
 468
 469        return 0;
 470}
 471
 472static const struct of_device_id tegra20_i2s_of_match[] = {
 473        { .compatible = "nvidia,tegra20-i2s", },
 474        {},
 475};
 476
 477static const struct dev_pm_ops tegra20_i2s_pm_ops = {
 478        SET_RUNTIME_PM_OPS(tegra20_i2s_runtime_suspend,
 479                           tegra20_i2s_runtime_resume, NULL)
 480};
 481
 482static struct platform_driver tegra20_i2s_driver = {
 483        .driver = {
 484                .name = DRV_NAME,
 485                .owner = THIS_MODULE,
 486                .of_match_table = tegra20_i2s_of_match,
 487                .pm = &tegra20_i2s_pm_ops,
 488        },
 489        .probe = tegra20_i2s_platform_probe,
 490        .remove = tegra20_i2s_platform_remove,
 491};
 492module_platform_driver(tegra20_i2s_driver);
 493
 494MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
 495MODULE_DESCRIPTION("Tegra20 I2S ASoC driver");
 496MODULE_LICENSE("GPL");
 497MODULE_ALIAS("platform:" DRV_NAME);
 498MODULE_DEVICE_TABLE(of, tegra20_i2s_of_match);
 499