1 /* 2 * tegra20_ac97.c - Tegra20 AC97 platform driver 3 * 4 * Copyright (c) 2012 Lucas Stach <dev@lynxeye.de> 5 * 6 * Partly based on code copyright/by: 7 * 8 * Copyright (c) 2011,2012 Toradex Inc. 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License 12 * version 2 as published by the Free Software Foundation. 13 * 14 * This program is distributed in the hope that it will be useful, but 15 * WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * General Public License for more details. 18 * 19 */ 20 21 #include <linux/clk.h> 22 #include <linux/delay.h> 23 #include <linux/device.h> 24 #include <linux/gpio.h> 25 #include <linux/io.h> 26 #include <linux/jiffies.h> 27 #include <linux/module.h> 28 #include <linux/of.h> 29 #include <linux/of_gpio.h> 30 #include <linux/platform_device.h> 31 #include <linux/pm_runtime.h> 32 #include <linux/regmap.h> 33 #include <linux/slab.h> 34 #include <sound/core.h> 35 #include <sound/pcm.h> 36 #include <sound/pcm_params.h> 37 #include <sound/soc.h> 38 #include <sound/dmaengine_pcm.h> 39 40 #include "tegra20_ac97.h" 41 42 #define DRV_NAME "tegra20-ac97" 43 44 static struct tegra20_ac97 *workdata; 45 46 static void tegra20_ac97_codec_reset(struct snd_ac97 *ac97) 47 { 48 u32 readback; 49 unsigned long timeout; 50 51 /* reset line is not driven by DAC pad group, have to toggle GPIO */ 52 gpio_set_value(workdata->reset_gpio, 0); 53 udelay(2); 54 55 gpio_set_value(workdata->reset_gpio, 1); 56 udelay(2); 57 58 timeout = jiffies + msecs_to_jiffies(100); 59 60 do { 61 regmap_read(workdata->regmap, TEGRA20_AC97_STATUS1, &readback); 62 if (readback & TEGRA20_AC97_STATUS1_CODEC1_RDY) 63 break; 64 usleep_range(1000, 2000); 65 } while (!time_after(jiffies, timeout)); 66 } 67 68 static void tegra20_ac97_codec_warm_reset(struct snd_ac97 *ac97) 69 { 70 u32 readback; 71 unsigned long timeout; 72 73 /* 74 * although sync line is driven by the DAC pad group warm reset using 75 * the controller cmd is not working, have to toggle sync line 76 * manually. 77 */ 78 gpio_request(workdata->sync_gpio, "codec-sync"); 79 80 gpio_direction_output(workdata->sync_gpio, 1); 81 82 udelay(2); 83 gpio_set_value(workdata->sync_gpio, 0); 84 udelay(2); 85 gpio_free(workdata->sync_gpio); 86 87 timeout = jiffies + msecs_to_jiffies(100); 88 89 do { 90 regmap_read(workdata->regmap, TEGRA20_AC97_STATUS1, &readback); 91 if (readback & TEGRA20_AC97_STATUS1_CODEC1_RDY) 92 break; 93 usleep_range(1000, 2000); 94 } while (!time_after(jiffies, timeout)); 95 } 96 97 static unsigned short tegra20_ac97_codec_read(struct snd_ac97 *ac97_snd, 98 unsigned short reg) 99 { 100 u32 readback; 101 unsigned long timeout; 102 103 regmap_write(workdata->regmap, TEGRA20_AC97_CMD, 104 (((reg | 0x80) << TEGRA20_AC97_CMD_CMD_ADDR_SHIFT) & 105 TEGRA20_AC97_CMD_CMD_ADDR_MASK) | 106 TEGRA20_AC97_CMD_BUSY); 107 108 timeout = jiffies + msecs_to_jiffies(100); 109 110 do { 111 regmap_read(workdata->regmap, TEGRA20_AC97_STATUS1, &readback); 112 if (readback & TEGRA20_AC97_STATUS1_STA_VALID1) 113 break; 114 usleep_range(1000, 2000); 115 } while (!time_after(jiffies, timeout)); 116 117 return ((readback & TEGRA20_AC97_STATUS1_STA_DATA1_MASK) >> 118 TEGRA20_AC97_STATUS1_STA_DATA1_SHIFT); 119 } 120 121 static void tegra20_ac97_codec_write(struct snd_ac97 *ac97_snd, 122 unsigned short reg, unsigned short val) 123 { 124 u32 readback; 125 unsigned long timeout; 126 127 regmap_write(workdata->regmap, TEGRA20_AC97_CMD, 128 ((reg << TEGRA20_AC97_CMD_CMD_ADDR_SHIFT) & 129 TEGRA20_AC97_CMD_CMD_ADDR_MASK) | 130 ((val << TEGRA20_AC97_CMD_CMD_DATA_SHIFT) & 131 TEGRA20_AC97_CMD_CMD_DATA_MASK) | 132 TEGRA20_AC97_CMD_BUSY); 133 134 timeout = jiffies + msecs_to_jiffies(100); 135 136 do { 137 regmap_read(workdata->regmap, TEGRA20_AC97_CMD, &readback); 138 if (!(readback & TEGRA20_AC97_CMD_BUSY)) 139 break; 140 usleep_range(1000, 2000); 141 } while (!time_after(jiffies, timeout)); 142 } 143 144 static struct snd_ac97_bus_ops tegra20_ac97_ops = { 145 .read = tegra20_ac97_codec_read, 146 .write = tegra20_ac97_codec_write, 147 .reset = tegra20_ac97_codec_reset, 148 .warm_reset = tegra20_ac97_codec_warm_reset, 149 }; 150 151 static inline void tegra20_ac97_start_playback(struct tegra20_ac97 *ac97) 152 { 153 regmap_update_bits(ac97->regmap, TEGRA20_AC97_FIFO1_SCR, 154 TEGRA20_AC97_FIFO_SCR_PB_QRT_MT_EN, 155 TEGRA20_AC97_FIFO_SCR_PB_QRT_MT_EN); 156 157 regmap_update_bits(ac97->regmap, TEGRA20_AC97_CTRL, 158 TEGRA20_AC97_CTRL_PCM_DAC_EN | 159 TEGRA20_AC97_CTRL_STM_EN, 160 TEGRA20_AC97_CTRL_PCM_DAC_EN | 161 TEGRA20_AC97_CTRL_STM_EN); 162 } 163 164 static inline void tegra20_ac97_stop_playback(struct tegra20_ac97 *ac97) 165 { 166 regmap_update_bits(ac97->regmap, TEGRA20_AC97_FIFO1_SCR, 167 TEGRA20_AC97_FIFO_SCR_PB_QRT_MT_EN, 0); 168 169 regmap_update_bits(ac97->regmap, TEGRA20_AC97_CTRL, 170 TEGRA20_AC97_CTRL_PCM_DAC_EN, 0); 171 } 172 173 static inline void tegra20_ac97_start_capture(struct tegra20_ac97 *ac97) 174 { 175 regmap_update_bits(ac97->regmap, TEGRA20_AC97_FIFO1_SCR, 176 TEGRA20_AC97_FIFO_SCR_REC_FULL_EN, 177 TEGRA20_AC97_FIFO_SCR_REC_FULL_EN); 178 } 179 180 static inline void tegra20_ac97_stop_capture(struct tegra20_ac97 *ac97) 181 { 182 regmap_update_bits(ac97->regmap, TEGRA20_AC97_FIFO1_SCR, 183 TEGRA20_AC97_FIFO_SCR_REC_FULL_EN, 0); 184 } 185 186 static int tegra20_ac97_trigger(struct snd_pcm_substream *substream, int cmd, 187 struct snd_soc_dai *dai) 188 { 189 struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(dai); 190 191 switch (cmd) { 192 case SNDRV_PCM_TRIGGER_START: 193 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 194 case SNDRV_PCM_TRIGGER_RESUME: 195 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 196 tegra20_ac97_start_playback(ac97); 197 else 198 tegra20_ac97_start_capture(ac97); 199 break; 200 case SNDRV_PCM_TRIGGER_STOP: 201 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 202 case SNDRV_PCM_TRIGGER_SUSPEND: 203 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 204 tegra20_ac97_stop_playback(ac97); 205 else 206 tegra20_ac97_stop_capture(ac97); 207 break; 208 default: 209 return -EINVAL; 210 } 211 212 return 0; 213 } 214 215 static const struct snd_soc_dai_ops tegra20_ac97_dai_ops = { 216 .trigger = tegra20_ac97_trigger, 217 }; 218 219 static int tegra20_ac97_probe(struct snd_soc_dai *dai) 220 { 221 struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(dai); 222 223 dai->capture_dma_data = &ac97->capture_dma_data; 224 dai->playback_dma_data = &ac97->playback_dma_data; 225 226 return 0; 227 } 228 229 static struct snd_soc_dai_driver tegra20_ac97_dai = { 230 .name = "tegra-ac97-pcm", 231 .bus_control = true, 232 .probe = tegra20_ac97_probe, 233 .playback = { 234 .stream_name = "PCM Playback", 235 .channels_min = 2, 236 .channels_max = 2, 237 .rates = SNDRV_PCM_RATE_8000_48000, 238 .formats = SNDRV_PCM_FMTBIT_S16_LE, 239 }, 240 .capture = { 241 .stream_name = "PCM Capture", 242 .channels_min = 2, 243 .channels_max = 2, 244 .rates = SNDRV_PCM_RATE_8000_48000, 245 .formats = SNDRV_PCM_FMTBIT_S16_LE, 246 }, 247 .ops = &tegra20_ac97_dai_ops, 248 }; 249 250 static const struct snd_soc_component_driver tegra20_ac97_component = { 251 .name = DRV_NAME, 252 }; 253 254 static bool tegra20_ac97_wr_rd_reg(struct device *dev, unsigned int reg) 255 { 256 switch (reg) { 257 case TEGRA20_AC97_CTRL: 258 case TEGRA20_AC97_CMD: 259 case TEGRA20_AC97_STATUS1: 260 case TEGRA20_AC97_FIFO1_SCR: 261 case TEGRA20_AC97_FIFO_TX1: 262 case TEGRA20_AC97_FIFO_RX1: 263 return true; 264 default: 265 break; 266 } 267 268 return false; 269 } 270 271 static bool tegra20_ac97_volatile_reg(struct device *dev, unsigned int reg) 272 { 273 switch (reg) { 274 case TEGRA20_AC97_STATUS1: 275 case TEGRA20_AC97_FIFO1_SCR: 276 case TEGRA20_AC97_FIFO_TX1: 277 case TEGRA20_AC97_FIFO_RX1: 278 return true; 279 default: 280 break; 281 } 282 283 return false; 284 } 285 286 static bool tegra20_ac97_precious_reg(struct device *dev, unsigned int reg) 287 { 288 switch (reg) { 289 case TEGRA20_AC97_FIFO_TX1: 290 case TEGRA20_AC97_FIFO_RX1: 291 return true; 292 default: 293 break; 294 } 295 296 return false; 297 } 298 299 static const struct regmap_config tegra20_ac97_regmap_config = { 300 .reg_bits = 32, 301 .reg_stride = 4, 302 .val_bits = 32, 303 .max_register = TEGRA20_AC97_FIFO_RX1, 304 .writeable_reg = tegra20_ac97_wr_rd_reg, 305 .readable_reg = tegra20_ac97_wr_rd_reg, 306 .volatile_reg = tegra20_ac97_volatile_reg, 307 .precious_reg = tegra20_ac97_precious_reg, 308 .cache_type = REGCACHE_FLAT, 309 }; 310 311 static int tegra20_ac97_platform_probe(struct platform_device *pdev) 312 { 313 struct tegra20_ac97 *ac97; 314 struct resource *mem; 315 void __iomem *regs; 316 int ret = 0; 317 318 ac97 = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_ac97), 319 GFP_KERNEL); 320 if (!ac97) { 321 ret = -ENOMEM; 322 goto err; 323 } 324 dev_set_drvdata(&pdev->dev, ac97); 325 326 ac97->clk_ac97 = devm_clk_get(&pdev->dev, NULL); 327 if (IS_ERR(ac97->clk_ac97)) { 328 dev_err(&pdev->dev, "Can't retrieve ac97 clock\n"); 329 ret = PTR_ERR(ac97->clk_ac97); 330 goto err; 331 } 332 333 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 334 regs = devm_ioremap_resource(&pdev->dev, mem); 335 if (IS_ERR(regs)) { 336 ret = PTR_ERR(regs); 337 goto err_clk_put; 338 } 339 340 ac97->regmap = devm_regmap_init_mmio(&pdev->dev, regs, 341 &tegra20_ac97_regmap_config); 342 if (IS_ERR(ac97->regmap)) { 343 dev_err(&pdev->dev, "regmap init failed\n"); 344 ret = PTR_ERR(ac97->regmap); 345 goto err_clk_put; 346 } 347 348 ac97->reset_gpio = of_get_named_gpio(pdev->dev.of_node, 349 "nvidia,codec-reset-gpio", 0); 350 if (gpio_is_valid(ac97->reset_gpio)) { 351 ret = devm_gpio_request_one(&pdev->dev, ac97->reset_gpio, 352 GPIOF_OUT_INIT_HIGH, "codec-reset"); 353 if (ret) { 354 dev_err(&pdev->dev, "could not get codec-reset GPIO\n"); 355 goto err_clk_put; 356 } 357 } else { 358 dev_err(&pdev->dev, "no codec-reset GPIO supplied\n"); 359 goto err_clk_put; 360 } 361 362 ac97->sync_gpio = of_get_named_gpio(pdev->dev.of_node, 363 "nvidia,codec-sync-gpio", 0); 364 if (!gpio_is_valid(ac97->sync_gpio)) { 365 dev_err(&pdev->dev, "no codec-sync GPIO supplied\n"); 366 goto err_clk_put; 367 } 368 369 ac97->capture_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_RX1; 370 ac97->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 371 ac97->capture_dma_data.maxburst = 4; 372 373 ac97->playback_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_TX1; 374 ac97->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 375 ac97->playback_dma_data.maxburst = 4; 376 377 ret = clk_prepare_enable(ac97->clk_ac97); 378 if (ret) { 379 dev_err(&pdev->dev, "clk_enable failed: %d\n", ret); 380 goto err_clk_put; 381 } 382 383 ret = snd_soc_set_ac97_ops(&tegra20_ac97_ops); 384 if (ret) { 385 dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret); 386 goto err_clk_disable_unprepare; 387 } 388 389 ret = snd_soc_register_component(&pdev->dev, &tegra20_ac97_component, 390 &tegra20_ac97_dai, 1); 391 if (ret) { 392 dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); 393 ret = -ENOMEM; 394 goto err_clk_disable_unprepare; 395 } 396 397 ret = tegra_pcm_platform_register(&pdev->dev); 398 if (ret) { 399 dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); 400 goto err_unregister_component; 401 } 402 403 /* XXX: crufty ASoC AC97 API - only one AC97 codec allowed */ 404 workdata = ac97; 405 406 return 0; 407 408 err_unregister_component: 409 snd_soc_unregister_component(&pdev->dev); 410 err_clk_disable_unprepare: 411 clk_disable_unprepare(ac97->clk_ac97); 412 err_clk_put: 413 err: 414 snd_soc_set_ac97_ops(NULL); 415 return ret; 416 } 417 418 static int tegra20_ac97_platform_remove(struct platform_device *pdev) 419 { 420 struct tegra20_ac97 *ac97 = dev_get_drvdata(&pdev->dev); 421 422 tegra_pcm_platform_unregister(&pdev->dev); 423 snd_soc_unregister_component(&pdev->dev); 424 425 clk_disable_unprepare(ac97->clk_ac97); 426 427 snd_soc_set_ac97_ops(NULL); 428 429 return 0; 430 } 431 432 static const struct of_device_id tegra20_ac97_of_match[] = { 433 { .compatible = "nvidia,tegra20-ac97", }, 434 {}, 435 }; 436 437 static struct platform_driver tegra20_ac97_driver = { 438 .driver = { 439 .name = DRV_NAME, 440 .of_match_table = tegra20_ac97_of_match, 441 }, 442 .probe = tegra20_ac97_platform_probe, 443 .remove = tegra20_ac97_platform_remove, 444 }; 445 module_platform_driver(tegra20_ac97_driver); 446 447 MODULE_AUTHOR("Lucas Stach"); 448 MODULE_DESCRIPTION("Tegra20 AC97 ASoC driver"); 449 MODULE_LICENSE("GPL v2"); 450 MODULE_ALIAS("platform:" DRV_NAME); 451 MODULE_DEVICE_TABLE(of, tegra20_ac97_of_match); 452