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