1 /* 2 * tegra20_spdif.c - Tegra20 SPDIF driver 3 * 4 * Author: Stephen Warren <swarren@nvidia.com> 5 * Copyright (C) 2011-2012 - NVIDIA, Inc. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * version 2 as published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 19 * 02110-1301 USA 20 * 21 */ 22 23 #include <linux/clk.h> 24 #include <linux/device.h> 25 #include <linux/io.h> 26 #include <linux/module.h> 27 #include <linux/platform_device.h> 28 #include <linux/pm_runtime.h> 29 #include <linux/regmap.h> 30 #include <linux/slab.h> 31 #include <sound/core.h> 32 #include <sound/pcm.h> 33 #include <sound/pcm_params.h> 34 #include <sound/soc.h> 35 36 #include "tegra20_spdif.h" 37 38 #define DRV_NAME "tegra20-spdif" 39 40 static int tegra20_spdif_runtime_suspend(struct device *dev) 41 { 42 struct tegra20_spdif *spdif = dev_get_drvdata(dev); 43 44 clk_disable_unprepare(spdif->clk_spdif_out); 45 46 return 0; 47 } 48 49 static int tegra20_spdif_runtime_resume(struct device *dev) 50 { 51 struct tegra20_spdif *spdif = dev_get_drvdata(dev); 52 int ret; 53 54 ret = clk_prepare_enable(spdif->clk_spdif_out); 55 if (ret) { 56 dev_err(dev, "clk_enable failed: %d\n", ret); 57 return ret; 58 } 59 60 return 0; 61 } 62 63 static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream, 64 struct snd_pcm_hw_params *params, 65 struct snd_soc_dai *dai) 66 { 67 struct device *dev = dai->dev; 68 struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai); 69 unsigned int mask, val; 70 int ret, spdifclock; 71 72 mask = TEGRA20_SPDIF_CTRL_PACK | 73 TEGRA20_SPDIF_CTRL_BIT_MODE_MASK; 74 switch (params_format(params)) { 75 case SNDRV_PCM_FORMAT_S16_LE: 76 val = TEGRA20_SPDIF_CTRL_PACK | 77 TEGRA20_SPDIF_CTRL_BIT_MODE_16BIT; 78 break; 79 default: 80 return -EINVAL; 81 } 82 83 regmap_update_bits(spdif->regmap, TEGRA20_SPDIF_CTRL, mask, val); 84 85 switch (params_rate(params)) { 86 case 32000: 87 spdifclock = 4096000; 88 break; 89 case 44100: 90 spdifclock = 5644800; 91 break; 92 case 48000: 93 spdifclock = 6144000; 94 break; 95 case 88200: 96 spdifclock = 11289600; 97 break; 98 case 96000: 99 spdifclock = 12288000; 100 break; 101 case 176400: 102 spdifclock = 22579200; 103 break; 104 case 192000: 105 spdifclock = 24576000; 106 break; 107 default: 108 return -EINVAL; 109 } 110 111 ret = clk_set_rate(spdif->clk_spdif_out, spdifclock); 112 if (ret) { 113 dev_err(dev, "Can't set SPDIF clock rate: %d\n", ret); 114 return ret; 115 } 116 117 return 0; 118 } 119 120 static void tegra20_spdif_start_playback(struct tegra20_spdif *spdif) 121 { 122 regmap_update_bits(spdif->regmap, TEGRA20_SPDIF_CTRL, 123 TEGRA20_SPDIF_CTRL_TX_EN, 124 TEGRA20_SPDIF_CTRL_TX_EN); 125 } 126 127 static void tegra20_spdif_stop_playback(struct tegra20_spdif *spdif) 128 { 129 regmap_update_bits(spdif->regmap, TEGRA20_SPDIF_CTRL, 130 TEGRA20_SPDIF_CTRL_TX_EN, 0); 131 } 132 133 static int tegra20_spdif_trigger(struct snd_pcm_substream *substream, int cmd, 134 struct snd_soc_dai *dai) 135 { 136 struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai); 137 138 switch (cmd) { 139 case SNDRV_PCM_TRIGGER_START: 140 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 141 case SNDRV_PCM_TRIGGER_RESUME: 142 tegra20_spdif_start_playback(spdif); 143 break; 144 case SNDRV_PCM_TRIGGER_STOP: 145 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 146 case SNDRV_PCM_TRIGGER_SUSPEND: 147 tegra20_spdif_stop_playback(spdif); 148 break; 149 default: 150 return -EINVAL; 151 } 152 153 return 0; 154 } 155 156 static int tegra20_spdif_probe(struct snd_soc_dai *dai) 157 { 158 struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai); 159 160 dai->capture_dma_data = NULL; 161 dai->playback_dma_data = &spdif->playback_dma_data; 162 163 return 0; 164 } 165 166 static const struct snd_soc_dai_ops tegra20_spdif_dai_ops = { 167 .hw_params = tegra20_spdif_hw_params, 168 .trigger = tegra20_spdif_trigger, 169 }; 170 171 static struct snd_soc_dai_driver tegra20_spdif_dai = { 172 .name = DRV_NAME, 173 .probe = tegra20_spdif_probe, 174 .playback = { 175 .stream_name = "Playback", 176 .channels_min = 2, 177 .channels_max = 2, 178 .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | 179 SNDRV_PCM_RATE_48000, 180 .formats = SNDRV_PCM_FMTBIT_S16_LE, 181 }, 182 .ops = &tegra20_spdif_dai_ops, 183 }; 184 185 static bool tegra20_spdif_wr_rd_reg(struct device *dev, unsigned int reg) 186 { 187 switch (reg) { 188 case TEGRA20_SPDIF_CTRL: 189 case TEGRA20_SPDIF_STATUS: 190 case TEGRA20_SPDIF_STROBE_CTRL: 191 case TEGRA20_SPDIF_DATA_FIFO_CSR: 192 case TEGRA20_SPDIF_DATA_OUT: 193 case TEGRA20_SPDIF_DATA_IN: 194 case TEGRA20_SPDIF_CH_STA_RX_A: 195 case TEGRA20_SPDIF_CH_STA_RX_B: 196 case TEGRA20_SPDIF_CH_STA_RX_C: 197 case TEGRA20_SPDIF_CH_STA_RX_D: 198 case TEGRA20_SPDIF_CH_STA_RX_E: 199 case TEGRA20_SPDIF_CH_STA_RX_F: 200 case TEGRA20_SPDIF_CH_STA_TX_A: 201 case TEGRA20_SPDIF_CH_STA_TX_B: 202 case TEGRA20_SPDIF_CH_STA_TX_C: 203 case TEGRA20_SPDIF_CH_STA_TX_D: 204 case TEGRA20_SPDIF_CH_STA_TX_E: 205 case TEGRA20_SPDIF_CH_STA_TX_F: 206 case TEGRA20_SPDIF_USR_STA_RX_A: 207 case TEGRA20_SPDIF_USR_DAT_TX_A: 208 return true; 209 default: 210 return false; 211 }; 212 } 213 214 static bool tegra20_spdif_volatile_reg(struct device *dev, unsigned int reg) 215 { 216 switch (reg) { 217 case TEGRA20_SPDIF_STATUS: 218 case TEGRA20_SPDIF_DATA_FIFO_CSR: 219 case TEGRA20_SPDIF_DATA_OUT: 220 case TEGRA20_SPDIF_DATA_IN: 221 case TEGRA20_SPDIF_CH_STA_RX_A: 222 case TEGRA20_SPDIF_CH_STA_RX_B: 223 case TEGRA20_SPDIF_CH_STA_RX_C: 224 case TEGRA20_SPDIF_CH_STA_RX_D: 225 case TEGRA20_SPDIF_CH_STA_RX_E: 226 case TEGRA20_SPDIF_CH_STA_RX_F: 227 case TEGRA20_SPDIF_USR_STA_RX_A: 228 case TEGRA20_SPDIF_USR_DAT_TX_A: 229 return true; 230 default: 231 return false; 232 }; 233 } 234 235 static bool tegra20_spdif_precious_reg(struct device *dev, unsigned int reg) 236 { 237 switch (reg) { 238 case TEGRA20_SPDIF_DATA_OUT: 239 case TEGRA20_SPDIF_DATA_IN: 240 case TEGRA20_SPDIF_USR_STA_RX_A: 241 case TEGRA20_SPDIF_USR_DAT_TX_A: 242 return true; 243 default: 244 return false; 245 }; 246 } 247 248 static const struct regmap_config tegra20_spdif_regmap_config = { 249 .reg_bits = 32, 250 .reg_stride = 4, 251 .val_bits = 32, 252 .max_register = TEGRA20_SPDIF_USR_DAT_TX_A, 253 .writeable_reg = tegra20_spdif_wr_rd_reg, 254 .readable_reg = tegra20_spdif_wr_rd_reg, 255 .volatile_reg = tegra20_spdif_volatile_reg, 256 .precious_reg = tegra20_spdif_precious_reg, 257 .cache_type = REGCACHE_RBTREE, 258 }; 259 260 static __devinit int tegra20_spdif_platform_probe(struct platform_device *pdev) 261 { 262 struct tegra20_spdif *spdif; 263 struct resource *mem, *memregion, *dmareq; 264 void __iomem *regs; 265 int ret; 266 267 spdif = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_spdif), 268 GFP_KERNEL); 269 if (!spdif) { 270 dev_err(&pdev->dev, "Can't allocate tegra20_spdif\n"); 271 ret = -ENOMEM; 272 goto err; 273 } 274 dev_set_drvdata(&pdev->dev, spdif); 275 276 spdif->clk_spdif_out = clk_get(&pdev->dev, "spdif_out"); 277 if (IS_ERR(spdif->clk_spdif_out)) { 278 pr_err("Can't retrieve spdif clock\n"); 279 ret = PTR_ERR(spdif->clk_spdif_out); 280 goto err; 281 } 282 283 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 284 if (!mem) { 285 dev_err(&pdev->dev, "No memory resource\n"); 286 ret = -ENODEV; 287 goto err_clk_put; 288 } 289 290 dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0); 291 if (!dmareq) { 292 dev_err(&pdev->dev, "No DMA resource\n"); 293 ret = -ENODEV; 294 goto err_clk_put; 295 } 296 297 memregion = devm_request_mem_region(&pdev->dev, mem->start, 298 resource_size(mem), DRV_NAME); 299 if (!memregion) { 300 dev_err(&pdev->dev, "Memory region already claimed\n"); 301 ret = -EBUSY; 302 goto err_clk_put; 303 } 304 305 regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); 306 if (!regs) { 307 dev_err(&pdev->dev, "ioremap failed\n"); 308 ret = -ENOMEM; 309 goto err_clk_put; 310 } 311 312 spdif->regmap = devm_regmap_init_mmio(&pdev->dev, regs, 313 &tegra20_spdif_regmap_config); 314 if (IS_ERR(spdif->regmap)) { 315 dev_err(&pdev->dev, "regmap init failed\n"); 316 ret = PTR_ERR(spdif->regmap); 317 goto err_clk_put; 318 } 319 320 spdif->playback_dma_data.addr = mem->start + TEGRA20_SPDIF_DATA_OUT; 321 spdif->playback_dma_data.wrap = 4; 322 spdif->playback_dma_data.width = 32; 323 spdif->playback_dma_data.req_sel = dmareq->start; 324 325 pm_runtime_enable(&pdev->dev); 326 if (!pm_runtime_enabled(&pdev->dev)) { 327 ret = tegra20_spdif_runtime_resume(&pdev->dev); 328 if (ret) 329 goto err_pm_disable; 330 } 331 332 ret = snd_soc_register_dai(&pdev->dev, &tegra20_spdif_dai); 333 if (ret) { 334 dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); 335 ret = -ENOMEM; 336 goto err_suspend; 337 } 338 339 ret = tegra_pcm_platform_register(&pdev->dev); 340 if (ret) { 341 dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); 342 goto err_unregister_dai; 343 } 344 345 return 0; 346 347 err_unregister_dai: 348 snd_soc_unregister_dai(&pdev->dev); 349 err_suspend: 350 if (!pm_runtime_status_suspended(&pdev->dev)) 351 tegra20_spdif_runtime_suspend(&pdev->dev); 352 err_pm_disable: 353 pm_runtime_disable(&pdev->dev); 354 err_clk_put: 355 clk_put(spdif->clk_spdif_out); 356 err: 357 return ret; 358 } 359 360 static int __devexit tegra20_spdif_platform_remove(struct platform_device *pdev) 361 { 362 struct tegra20_spdif *spdif = dev_get_drvdata(&pdev->dev); 363 364 pm_runtime_disable(&pdev->dev); 365 if (!pm_runtime_status_suspended(&pdev->dev)) 366 tegra20_spdif_runtime_suspend(&pdev->dev); 367 368 tegra_pcm_platform_unregister(&pdev->dev); 369 snd_soc_unregister_dai(&pdev->dev); 370 371 clk_put(spdif->clk_spdif_out); 372 373 return 0; 374 } 375 376 static const struct dev_pm_ops tegra20_spdif_pm_ops __devinitconst = { 377 SET_RUNTIME_PM_OPS(tegra20_spdif_runtime_suspend, 378 tegra20_spdif_runtime_resume, NULL) 379 }; 380 381 static struct platform_driver tegra20_spdif_driver = { 382 .driver = { 383 .name = DRV_NAME, 384 .owner = THIS_MODULE, 385 .pm = &tegra20_spdif_pm_ops, 386 }, 387 .probe = tegra20_spdif_platform_probe, 388 .remove = __devexit_p(tegra20_spdif_platform_remove), 389 }; 390 391 module_platform_driver(tegra20_spdif_driver); 392 393 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); 394 MODULE_DESCRIPTION("Tegra20 SPDIF ASoC driver"); 395 MODULE_LICENSE("GPL"); 396 MODULE_ALIAS("platform:" DRV_NAME); 397