1/* sound/soc/s3c24xx/s3c-ac97.c 2 * 3 * ALSA SoC Audio Layer - S3C AC97 Controller driver 4 * Evolved from s3c2443-ac97.c 5 * 6 * Copyright (c) 2010 Samsung Electronics Co. Ltd 7 * Author: Jaswinder Singh <jassi.brar@samsung.com> 8 * Credits: Graeme Gregory, Sean Choi 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 */ 14 15#include <linux/init.h> 16#include <linux/module.h> 17#include <linux/io.h> 18#include <linux/delay.h> 19#include <linux/clk.h> 20 21#include <sound/soc.h> 22 23#include <plat/regs-ac97.h> 24#include <mach/dma.h> 25#include <plat/audio.h> 26 27#include "s3c-dma.h" 28#include "s3c-ac97.h" 29 30#define AC_CMD_ADDR(x) (x << 16) 31#define AC_CMD_DATA(x) (x & 0xffff) 32 33struct s3c_ac97_info { 34 struct clk *ac97_clk; 35 void __iomem *regs; 36 struct mutex lock; 37 struct completion done; 38}; 39static struct s3c_ac97_info s3c_ac97; 40 41static struct s3c2410_dma_client s3c_dma_client_out = { 42 .name = "AC97 PCMOut" 43}; 44 45static struct s3c2410_dma_client s3c_dma_client_in = { 46 .name = "AC97 PCMIn" 47}; 48 49static struct s3c2410_dma_client s3c_dma_client_micin = { 50 .name = "AC97 MicIn" 51}; 52 53static struct s3c_dma_params s3c_ac97_pcm_out = { 54 .client = &s3c_dma_client_out, 55 .dma_size = 4, 56}; 57 58static struct s3c_dma_params s3c_ac97_pcm_in = { 59 .client = &s3c_dma_client_in, 60 .dma_size = 4, 61}; 62 63static struct s3c_dma_params s3c_ac97_mic_in = { 64 .client = &s3c_dma_client_micin, 65 .dma_size = 4, 66}; 67 68static void s3c_ac97_activate(struct snd_ac97 *ac97) 69{ 70 u32 ac_glbctrl, stat; 71 72 stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7; 73 if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE) 74 return; /* Return if already active */ 75 76 INIT_COMPLETION(s3c_ac97.done); 77 78 ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); 79 ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON; 80 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); 81 msleep(1); 82 83 ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE; 84 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); 85 msleep(1); 86 87 ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); 88 ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE; 89 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); 90 91 if (!wait_for_completion_timeout(&s3c_ac97.done, HZ)) 92 printk(KERN_ERR "AC97: Unable to activate!"); 93} 94 95static unsigned short s3c_ac97_read(struct snd_ac97 *ac97, 96 unsigned short reg) 97{ 98 u32 ac_glbctrl, ac_codec_cmd; 99 u32 stat, addr, data; 100 101 mutex_lock(&s3c_ac97.lock); 102 103 s3c_ac97_activate(ac97); 104 105 INIT_COMPLETION(s3c_ac97.done); 106 107 ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD); 108 ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg); 109 writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD); 110 111 udelay(50); 112 113 ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); 114 ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE; 115 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); 116 117 if (!wait_for_completion_timeout(&s3c_ac97.done, HZ)) 118 printk(KERN_ERR "AC97: Unable to read!"); 119 120 stat = readl(s3c_ac97.regs + S3C_AC97_STAT); 121 addr = (stat >> 16) & 0x7f; 122 data = (stat & 0xffff); 123 124 if (addr != reg) 125 printk(KERN_ERR "s3c-ac97: req addr = %02x, rep addr = %02x\n", reg, addr); 126 127 mutex_unlock(&s3c_ac97.lock); 128 129 return (unsigned short)data; 130} 131 132static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg, 133 unsigned short val) 134{ 135 u32 ac_glbctrl, ac_codec_cmd; 136 137 mutex_lock(&s3c_ac97.lock); 138 139 s3c_ac97_activate(ac97); 140 141 INIT_COMPLETION(s3c_ac97.done); 142 143 ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD); 144 ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val); 145 writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD); 146 147 udelay(50); 148 149 ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); 150 ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE; 151 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); 152 153 if (!wait_for_completion_timeout(&s3c_ac97.done, HZ)) 154 printk(KERN_ERR "AC97: Unable to write!"); 155 156 ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD); 157 ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ; 158 writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD); 159 160 mutex_unlock(&s3c_ac97.lock); 161} 162 163static void s3c_ac97_cold_reset(struct snd_ac97 *ac97) 164{ 165 writel(S3C_AC97_GLBCTRL_COLDRESET, 166 s3c_ac97.regs + S3C_AC97_GLBCTRL); 167 msleep(1); 168 169 writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL); 170 msleep(1); 171} 172 173static void s3c_ac97_warm_reset(struct snd_ac97 *ac97) 174{ 175 u32 stat; 176 177 stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7; 178 if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE) 179 return; /* Return if already active */ 180 181 writel(S3C_AC97_GLBCTRL_WARMRESET, s3c_ac97.regs + S3C_AC97_GLBCTRL); 182 msleep(1); 183 184 writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL); 185 msleep(1); 186 187 s3c_ac97_activate(ac97); 188} 189 190static irqreturn_t s3c_ac97_irq(int irq, void *dev_id) 191{ 192 u32 ac_glbctrl, ac_glbstat; 193 194 ac_glbstat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT); 195 196 if (ac_glbstat & S3C_AC97_GLBSTAT_CODECREADY) { 197 198 ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); 199 ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE; 200 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); 201 202 complete(&s3c_ac97.done); 203 } 204 205 ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); 206 ac_glbctrl |= (1<<30); /* Clear interrupt */ 207 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); 208 209 return IRQ_HANDLED; 210} 211 212struct snd_ac97_bus_ops soc_ac97_ops = { 213 .read = s3c_ac97_read, 214 .write = s3c_ac97_write, 215 .warm_reset = s3c_ac97_warm_reset, 216 .reset = s3c_ac97_cold_reset, 217}; 218EXPORT_SYMBOL_GPL(soc_ac97_ops); 219 220static int s3c_ac97_hw_params(struct snd_pcm_substream *substream, 221 struct snd_pcm_hw_params *params, 222 struct snd_soc_dai *dai) 223{ 224 struct snd_soc_pcm_runtime *rtd = substream->private_data; 225 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 226 struct s3c_dma_params *dma_data; 227 228 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 229 dma_data = &s3c_ac97_pcm_out; 230 else 231 dma_data = &s3c_ac97_pcm_in; 232 233 snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data); 234 235 return 0; 236} 237 238static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd, 239 struct snd_soc_dai *dai) 240{ 241 u32 ac_glbctrl; 242 struct snd_soc_pcm_runtime *rtd = substream->private_data; 243 struct s3c_dma_params *dma_data = 244 snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream); 245 246 ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); 247 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 248 ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK; 249 else 250 ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMOUTTM_MASK; 251 252 switch (cmd) { 253 case SNDRV_PCM_TRIGGER_START: 254 case SNDRV_PCM_TRIGGER_RESUME: 255 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 256 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 257 ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA; 258 else 259 ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA; 260 break; 261 262 case SNDRV_PCM_TRIGGER_STOP: 263 case SNDRV_PCM_TRIGGER_SUSPEND: 264 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 265 break; 266 } 267 268 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); 269 270 s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED); 271 272 return 0; 273} 274 275static int s3c_ac97_hw_mic_params(struct snd_pcm_substream *substream, 276 struct snd_pcm_hw_params *params, 277 struct snd_soc_dai *dai) 278{ 279 struct snd_soc_pcm_runtime *rtd = substream->private_data; 280 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 281 282 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 283 return -ENODEV; 284 else 285 snd_soc_dai_set_dma_data(cpu_dai, substream, &s3c_ac97_mic_in); 286 287 return 0; 288} 289 290static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream, 291 int cmd, struct snd_soc_dai *dai) 292{ 293 u32 ac_glbctrl; 294 struct snd_soc_pcm_runtime *rtd = substream->private_data; 295 struct s3c_dma_params *dma_data = 296 snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream); 297 298 ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); 299 ac_glbctrl &= ~S3C_AC97_GLBCTRL_MICINTM_MASK; 300 301 switch (cmd) { 302 case SNDRV_PCM_TRIGGER_START: 303 case SNDRV_PCM_TRIGGER_RESUME: 304 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 305 ac_glbctrl |= S3C_AC97_GLBCTRL_MICINTM_DMA; 306 break; 307 308 case SNDRV_PCM_TRIGGER_STOP: 309 case SNDRV_PCM_TRIGGER_SUSPEND: 310 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 311 break; 312 } 313 314 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); 315 316 s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED); 317 318 return 0; 319} 320 321static struct snd_soc_dai_ops s3c_ac97_dai_ops = { 322 .hw_params = s3c_ac97_hw_params, 323 .trigger = s3c_ac97_trigger, 324}; 325 326static struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = { 327 .hw_params = s3c_ac97_hw_mic_params, 328 .trigger = s3c_ac97_mic_trigger, 329}; 330 331struct snd_soc_dai s3c_ac97_dai[] = { 332 [S3C_AC97_DAI_PCM] = { 333 .name = "s3c-ac97", 334 .id = S3C_AC97_DAI_PCM, 335 .ac97_control = 1, 336 .playback = { 337 .stream_name = "AC97 Playback", 338 .channels_min = 2, 339 .channels_max = 2, 340 .rates = SNDRV_PCM_RATE_8000_48000, 341 .formats = SNDRV_PCM_FMTBIT_S16_LE,}, 342 .capture = { 343 .stream_name = "AC97 Capture", 344 .channels_min = 2, 345 .channels_max = 2, 346 .rates = SNDRV_PCM_RATE_8000_48000, 347 .formats = SNDRV_PCM_FMTBIT_S16_LE,}, 348 .ops = &s3c_ac97_dai_ops, 349 }, 350 [S3C_AC97_DAI_MIC] = { 351 .name = "s3c-ac97-mic", 352 .id = S3C_AC97_DAI_MIC, 353 .ac97_control = 1, 354 .capture = { 355 .stream_name = "AC97 Mic Capture", 356 .channels_min = 1, 357 .channels_max = 1, 358 .rates = SNDRV_PCM_RATE_8000_48000, 359 .formats = SNDRV_PCM_FMTBIT_S16_LE,}, 360 .ops = &s3c_ac97_mic_dai_ops, 361 }, 362}; 363EXPORT_SYMBOL_GPL(s3c_ac97_dai); 364 365static __devinit int s3c_ac97_probe(struct platform_device *pdev) 366{ 367 struct resource *mem_res, *dmatx_res, *dmarx_res, *dmamic_res, *irq_res; 368 struct s3c_audio_pdata *ac97_pdata; 369 int ret; 370 371 ac97_pdata = pdev->dev.platform_data; 372 if (!ac97_pdata || !ac97_pdata->cfg_gpio) { 373 dev_err(&pdev->dev, "cfg_gpio callback not provided!\n"); 374 return -EINVAL; 375 } 376 377 /* Check for availability of necessary resource */ 378 dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0); 379 if (!dmatx_res) { 380 dev_err(&pdev->dev, "Unable to get AC97-TX dma resource\n"); 381 return -ENXIO; 382 } 383 384 dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1); 385 if (!dmarx_res) { 386 dev_err(&pdev->dev, "Unable to get AC97-RX dma resource\n"); 387 return -ENXIO; 388 } 389 390 dmamic_res = platform_get_resource(pdev, IORESOURCE_DMA, 2); 391 if (!dmamic_res) { 392 dev_err(&pdev->dev, "Unable to get AC97-MIC dma resource\n"); 393 return -ENXIO; 394 } 395 396 mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 397 if (!mem_res) { 398 dev_err(&pdev->dev, "Unable to get register resource\n"); 399 return -ENXIO; 400 } 401 402 irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 403 if (!irq_res) { 404 dev_err(&pdev->dev, "AC97 IRQ not provided!\n"); 405 return -ENXIO; 406 } 407 408 if (!request_mem_region(mem_res->start, 409 resource_size(mem_res), "s3c-ac97")) { 410 dev_err(&pdev->dev, "Unable to request register region\n"); 411 return -EBUSY; 412 } 413 414 s3c_ac97_pcm_out.channel = dmatx_res->start; 415 s3c_ac97_pcm_out.dma_addr = mem_res->start + S3C_AC97_PCM_DATA; 416 s3c_ac97_pcm_in.channel = dmarx_res->start; 417 s3c_ac97_pcm_in.dma_addr = mem_res->start + S3C_AC97_PCM_DATA; 418 s3c_ac97_mic_in.channel = dmamic_res->start; 419 s3c_ac97_mic_in.dma_addr = mem_res->start + S3C_AC97_MIC_DATA; 420 421 init_completion(&s3c_ac97.done); 422 mutex_init(&s3c_ac97.lock); 423 424 s3c_ac97.regs = ioremap(mem_res->start, resource_size(mem_res)); 425 if (s3c_ac97.regs == NULL) { 426 dev_err(&pdev->dev, "Unable to ioremap register region\n"); 427 ret = -ENXIO; 428 goto err1; 429 } 430 431 s3c_ac97.ac97_clk = clk_get(&pdev->dev, "ac97"); 432 if (IS_ERR(s3c_ac97.ac97_clk)) { 433 dev_err(&pdev->dev, "s3c-ac97 failed to get ac97_clock\n"); 434 ret = -ENODEV; 435 goto err2; 436 } 437 clk_enable(s3c_ac97.ac97_clk); 438 439 if (ac97_pdata->cfg_gpio(pdev)) { 440 dev_err(&pdev->dev, "Unable to configure gpio\n"); 441 ret = -EINVAL; 442 goto err3; 443 } 444 445 ret = request_irq(irq_res->start, s3c_ac97_irq, 446 IRQF_DISABLED, "AC97", NULL); 447 if (ret < 0) { 448 printk(KERN_ERR "s3c-ac97: interrupt request failed.\n"); 449 goto err4; 450 } 451 452 s3c_ac97_dai[S3C_AC97_DAI_PCM].dev = &pdev->dev; 453 s3c_ac97_dai[S3C_AC97_DAI_MIC].dev = &pdev->dev; 454 455 ret = snd_soc_register_dais(s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai)); 456 if (ret) 457 goto err5; 458 459 return 0; 460 461err5: 462 free_irq(irq_res->start, NULL); 463err4: 464err3: 465 clk_disable(s3c_ac97.ac97_clk); 466 clk_put(s3c_ac97.ac97_clk); 467err2: 468 iounmap(s3c_ac97.regs); 469err1: 470 release_mem_region(mem_res->start, resource_size(mem_res)); 471 472 return ret; 473} 474 475static __devexit int s3c_ac97_remove(struct platform_device *pdev) 476{ 477 struct resource *mem_res, *irq_res; 478 479 snd_soc_unregister_dais(s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai)); 480 481 irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 482 if (irq_res) 483 free_irq(irq_res->start, NULL); 484 485 clk_disable(s3c_ac97.ac97_clk); 486 clk_put(s3c_ac97.ac97_clk); 487 488 iounmap(s3c_ac97.regs); 489 490 mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 491 if (mem_res) 492 release_mem_region(mem_res->start, resource_size(mem_res)); 493 494 return 0; 495} 496 497static struct platform_driver s3c_ac97_driver = { 498 .probe = s3c_ac97_probe, 499 .remove = s3c_ac97_remove, 500 .driver = { 501 .name = "s3c-ac97", 502 .owner = THIS_MODULE, 503 }, 504}; 505 506static int __init s3c_ac97_init(void) 507{ 508 return platform_driver_register(&s3c_ac97_driver); 509} 510module_init(s3c_ac97_init); 511 512static void __exit s3c_ac97_exit(void) 513{ 514 platform_driver_unregister(&s3c_ac97_driver); 515} 516module_exit(s3c_ac97_exit); 517 518MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>"); 519MODULE_DESCRIPTION("AC97 driver for the Samsung SoC"); 520MODULE_LICENSE("GPL"); 521