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 50 static 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 59 static 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 73 static 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 = 0, val = 0; 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 129 static 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 189 static 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 196 static 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 202 static 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 209 static 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 215 static 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 244 static 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 254 static 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 260 static 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 280 static const struct snd_soc_component_driver tegra20_i2s_component = { 281 .name = DRV_NAME, 282 }; 283 284 static 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 303 static 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 316 static 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 327 static 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_FLAT, 337 }; 338 339 static int tegra20_i2s_platform_probe(struct platform_device *pdev) 340 { 341 struct tegra20_i2s *i2s; 342 struct resource *mem, *memregion; 343 void __iomem *regs; 344 int ret; 345 346 i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_i2s), GFP_KERNEL); 347 if (!i2s) { 348 dev_err(&pdev->dev, "Can't allocate tegra20_i2s\n"); 349 ret = -ENOMEM; 350 goto err; 351 } 352 dev_set_drvdata(&pdev->dev, i2s); 353 354 i2s->dai = tegra20_i2s_dai_template; 355 i2s->dai.name = dev_name(&pdev->dev); 356 357 i2s->clk_i2s = clk_get(&pdev->dev, NULL); 358 if (IS_ERR(i2s->clk_i2s)) { 359 dev_err(&pdev->dev, "Can't retrieve i2s clock\n"); 360 ret = PTR_ERR(i2s->clk_i2s); 361 goto err; 362 } 363 364 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 365 if (!mem) { 366 dev_err(&pdev->dev, "No memory resource\n"); 367 ret = -ENODEV; 368 goto err_clk_put; 369 } 370 371 memregion = devm_request_mem_region(&pdev->dev, mem->start, 372 resource_size(mem), DRV_NAME); 373 if (!memregion) { 374 dev_err(&pdev->dev, "Memory region already claimed\n"); 375 ret = -EBUSY; 376 goto err_clk_put; 377 } 378 379 regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); 380 if (!regs) { 381 dev_err(&pdev->dev, "ioremap failed\n"); 382 ret = -ENOMEM; 383 goto err_clk_put; 384 } 385 386 i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs, 387 &tegra20_i2s_regmap_config); 388 if (IS_ERR(i2s->regmap)) { 389 dev_err(&pdev->dev, "regmap init failed\n"); 390 ret = PTR_ERR(i2s->regmap); 391 goto err_clk_put; 392 } 393 394 i2s->capture_dma_data.addr = mem->start + TEGRA20_I2S_FIFO2; 395 i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 396 i2s->capture_dma_data.maxburst = 4; 397 398 i2s->playback_dma_data.addr = mem->start + TEGRA20_I2S_FIFO1; 399 i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 400 i2s->playback_dma_data.maxburst = 4; 401 402 pm_runtime_enable(&pdev->dev); 403 if (!pm_runtime_enabled(&pdev->dev)) { 404 ret = tegra20_i2s_runtime_resume(&pdev->dev); 405 if (ret) 406 goto err_pm_disable; 407 } 408 409 ret = snd_soc_register_component(&pdev->dev, &tegra20_i2s_component, 410 &i2s->dai, 1); 411 if (ret) { 412 dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); 413 ret = -ENOMEM; 414 goto err_suspend; 415 } 416 417 ret = tegra_pcm_platform_register(&pdev->dev); 418 if (ret) { 419 dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); 420 goto err_unregister_component; 421 } 422 423 return 0; 424 425 err_unregister_component: 426 snd_soc_unregister_component(&pdev->dev); 427 err_suspend: 428 if (!pm_runtime_status_suspended(&pdev->dev)) 429 tegra20_i2s_runtime_suspend(&pdev->dev); 430 err_pm_disable: 431 pm_runtime_disable(&pdev->dev); 432 err_clk_put: 433 clk_put(i2s->clk_i2s); 434 err: 435 return ret; 436 } 437 438 static int tegra20_i2s_platform_remove(struct platform_device *pdev) 439 { 440 struct tegra20_i2s *i2s = dev_get_drvdata(&pdev->dev); 441 442 pm_runtime_disable(&pdev->dev); 443 if (!pm_runtime_status_suspended(&pdev->dev)) 444 tegra20_i2s_runtime_suspend(&pdev->dev); 445 446 tegra_pcm_platform_unregister(&pdev->dev); 447 snd_soc_unregister_component(&pdev->dev); 448 449 clk_put(i2s->clk_i2s); 450 451 return 0; 452 } 453 454 static const struct of_device_id tegra20_i2s_of_match[] = { 455 { .compatible = "nvidia,tegra20-i2s", }, 456 {}, 457 }; 458 459 static const struct dev_pm_ops tegra20_i2s_pm_ops = { 460 SET_RUNTIME_PM_OPS(tegra20_i2s_runtime_suspend, 461 tegra20_i2s_runtime_resume, NULL) 462 }; 463 464 static struct platform_driver tegra20_i2s_driver = { 465 .driver = { 466 .name = DRV_NAME, 467 .owner = THIS_MODULE, 468 .of_match_table = tegra20_i2s_of_match, 469 .pm = &tegra20_i2s_pm_ops, 470 }, 471 .probe = tegra20_i2s_platform_probe, 472 .remove = tegra20_i2s_platform_remove, 473 }; 474 module_platform_driver(tegra20_i2s_driver); 475 476 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); 477 MODULE_DESCRIPTION("Tegra20 I2S ASoC driver"); 478 MODULE_LICENSE("GPL"); 479 MODULE_ALIAS("platform:" DRV_NAME); 480 MODULE_DEVICE_TABLE(of, tegra20_i2s_of_match); 481