| OLD | NEW |
| 1 /* sound/soc/s3c24xx/s3c-ac97.c | 1 /* sound/soc/samsung/ac97.c |
| 2 * | 2 * |
| 3 * ALSA SoC Audio Layer - S3C AC97 Controller driver | 3 * ALSA SoC Audio Layer - S3C AC97 Controller driver |
| 4 * Evolved from s3c2443-ac97.c | 4 * Evolved from s3c2443-ac97.c |
| 5 * | 5 * |
| 6 * Copyright (c) 2010 Samsung Electronics Co. Ltd | 6 * Copyright (c) 2010 Samsung Electronics Co. Ltd |
| 7 * Author: Jaswinder Singh <jassi.brar@samsung.com> | 7 * Author: Jaswinder Singh <jassi.brar@samsung.com> |
| 8 * Credits: Graeme Gregory, Sean Choi | 8 * Credits: Graeme Gregory, Sean Choi |
| 9 * | 9 * |
| 10 * This program is free software; you can redistribute it and/or modify | 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 | 11 * it under the terms of the GNU General Public License version 2 as |
| 12 * published by the Free Software Foundation. | 12 * published by the Free Software Foundation. |
| 13 */ | 13 */ |
| 14 | 14 |
| 15 #include <linux/init.h> | |
| 16 #include <linux/module.h> | |
| 17 #include <linux/io.h> | 15 #include <linux/io.h> |
| 18 #include <linux/delay.h> | 16 #include <linux/delay.h> |
| 19 #include <linux/clk.h> | 17 #include <linux/clk.h> |
| 20 | 18 |
| 21 #include <sound/soc.h> | 19 #include <sound/soc.h> |
| 22 | 20 |
| 21 #include <mach/dma.h> |
| 23 #include <plat/regs-ac97.h> | 22 #include <plat/regs-ac97.h> |
| 24 #include <mach/dma.h> | |
| 25 #include <plat/audio.h> | 23 #include <plat/audio.h> |
| 26 | 24 |
| 27 #include "s3c-dma.h" | 25 #include "dma.h" |
| 28 #include "s3c-ac97.h" | |
| 29 | 26 |
| 30 #define AC_CMD_ADDR(x) (x << 16) | 27 #define AC_CMD_ADDR(x) (x << 16) |
| 31 #define AC_CMD_DATA(x) (x & 0xffff) | 28 #define AC_CMD_DATA(x) (x & 0xffff) |
| 32 | 29 |
| 30 #define S3C_AC97_DAI_PCM 0 |
| 31 #define S3C_AC97_DAI_MIC 1 |
| 32 |
| 33 struct s3c_ac97_info { | 33 struct s3c_ac97_info { |
| 34 struct clk *ac97_clk; | 34 struct clk *ac97_clk; |
| 35 void __iomem *regs; | 35 void __iomem *regs; |
| 36 struct mutex lock; | 36 struct mutex lock; |
| 37 struct completion done; | 37 struct completion done; |
| 38 }; | 38 }; |
| 39 static struct s3c_ac97_info s3c_ac97; | 39 static struct s3c_ac97_info s3c_ac97; |
| 40 | 40 |
| 41 static struct s3c2410_dma_client s3c_dma_client_out = { | 41 static struct s3c2410_dma_client s3c_dma_client_out = { |
| 42 .name = "AC97 PCMOut" | 42 .name = "AC97 PCMOut" |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 115 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); | 115 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); |
| 116 | 116 |
| 117 if (!wait_for_completion_timeout(&s3c_ac97.done, HZ)) | 117 if (!wait_for_completion_timeout(&s3c_ac97.done, HZ)) |
| 118 pr_err("AC97: Unable to read!"); | 118 pr_err("AC97: Unable to read!"); |
| 119 | 119 |
| 120 stat = readl(s3c_ac97.regs + S3C_AC97_STAT); | 120 stat = readl(s3c_ac97.regs + S3C_AC97_STAT); |
| 121 addr = (stat >> 16) & 0x7f; | 121 addr = (stat >> 16) & 0x7f; |
| 122 data = (stat & 0xffff); | 122 data = (stat & 0xffff); |
| 123 | 123 |
| 124 if (addr != reg) | 124 if (addr != reg) |
| 125 » » pr_err("s3c-ac97: req addr = %02x, rep addr = %02x\n", | 125 » » pr_err("ac97: req addr = %02x, rep addr = %02x\n", |
| 126 reg, addr); | 126 reg, addr); |
| 127 | 127 |
| 128 mutex_unlock(&s3c_ac97.lock); | 128 mutex_unlock(&s3c_ac97.lock); |
| 129 | 129 |
| 130 return (unsigned short)data; | 130 return (unsigned short)data; |
| 131 } | 131 } |
| 132 | 132 |
| 133 static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg, | 133 static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg, |
| 134 unsigned short val) | 134 unsigned short val) |
| 135 { | 135 { |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 327 .trigger = s3c_ac97_trigger, | 327 .trigger = s3c_ac97_trigger, |
| 328 }; | 328 }; |
| 329 | 329 |
| 330 static struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = { | 330 static struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = { |
| 331 .hw_params = s3c_ac97_hw_mic_params, | 331 .hw_params = s3c_ac97_hw_mic_params, |
| 332 .trigger = s3c_ac97_mic_trigger, | 332 .trigger = s3c_ac97_mic_trigger, |
| 333 }; | 333 }; |
| 334 | 334 |
| 335 static struct snd_soc_dai_driver s3c_ac97_dai[] = { | 335 static struct snd_soc_dai_driver s3c_ac97_dai[] = { |
| 336 [S3C_AC97_DAI_PCM] = { | 336 [S3C_AC97_DAI_PCM] = { |
| 337 » » .name =»"s3c-ac97", | 337 » » .name =»"samsung-ac97", |
| 338 .ac97_control = 1, | 338 .ac97_control = 1, |
| 339 .playback = { | 339 .playback = { |
| 340 .stream_name = "AC97 Playback", | 340 .stream_name = "AC97 Playback", |
| 341 .channels_min = 2, | 341 .channels_min = 2, |
| 342 .channels_max = 2, | 342 .channels_max = 2, |
| 343 .rates = SNDRV_PCM_RATE_8000_48000, | 343 .rates = SNDRV_PCM_RATE_8000_48000, |
| 344 .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 344 .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
| 345 .capture = { | 345 .capture = { |
| 346 .stream_name = "AC97 Capture", | 346 .stream_name = "AC97 Capture", |
| 347 .channels_min = 2, | 347 .channels_min = 2, |
| 348 .channels_max = 2, | 348 .channels_max = 2, |
| 349 .rates = SNDRV_PCM_RATE_8000_48000, | 349 .rates = SNDRV_PCM_RATE_8000_48000, |
| 350 .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 350 .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
| 351 .ops = &s3c_ac97_dai_ops, | 351 .ops = &s3c_ac97_dai_ops, |
| 352 }, | 352 }, |
| 353 [S3C_AC97_DAI_MIC] = { | 353 [S3C_AC97_DAI_MIC] = { |
| 354 » » .name = "s3c-ac97-mic", | 354 » » .name = "samsung-ac97-mic", |
| 355 .ac97_control = 1, | 355 .ac97_control = 1, |
| 356 .capture = { | 356 .capture = { |
| 357 .stream_name = "AC97 Mic Capture", | 357 .stream_name = "AC97 Mic Capture", |
| 358 .channels_min = 1, | 358 .channels_min = 1, |
| 359 .channels_max = 1, | 359 .channels_max = 1, |
| 360 .rates = SNDRV_PCM_RATE_8000_48000, | 360 .rates = SNDRV_PCM_RATE_8000_48000, |
| 361 .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 361 .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
| 362 .ops = &s3c_ac97_mic_dai_ops, | 362 .ops = &s3c_ac97_mic_dai_ops, |
| 363 }, | 363 }, |
| 364 }; | 364 }; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 400 return -ENXIO; | 400 return -ENXIO; |
| 401 } | 401 } |
| 402 | 402 |
| 403 irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 403 irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
| 404 if (!irq_res) { | 404 if (!irq_res) { |
| 405 dev_err(&pdev->dev, "AC97 IRQ not provided!\n"); | 405 dev_err(&pdev->dev, "AC97 IRQ not provided!\n"); |
| 406 return -ENXIO; | 406 return -ENXIO; |
| 407 } | 407 } |
| 408 | 408 |
| 409 if (!request_mem_region(mem_res->start, | 409 if (!request_mem_region(mem_res->start, |
| 410 » » » » resource_size(mem_res), "s3c-ac97")) { | 410 » » » » resource_size(mem_res), "ac97")) { |
| 411 dev_err(&pdev->dev, "Unable to request register region\n"); | 411 dev_err(&pdev->dev, "Unable to request register region\n"); |
| 412 return -EBUSY; | 412 return -EBUSY; |
| 413 } | 413 } |
| 414 | 414 |
| 415 s3c_ac97_pcm_out.channel = dmatx_res->start; | 415 s3c_ac97_pcm_out.channel = dmatx_res->start; |
| 416 s3c_ac97_pcm_out.dma_addr = mem_res->start + S3C_AC97_PCM_DATA; | 416 s3c_ac97_pcm_out.dma_addr = mem_res->start + S3C_AC97_PCM_DATA; |
| 417 s3c_ac97_pcm_in.channel = dmarx_res->start; | 417 s3c_ac97_pcm_in.channel = dmarx_res->start; |
| 418 s3c_ac97_pcm_in.dma_addr = mem_res->start + S3C_AC97_PCM_DATA; | 418 s3c_ac97_pcm_in.dma_addr = mem_res->start + S3C_AC97_PCM_DATA; |
| 419 s3c_ac97_mic_in.channel = dmamic_res->start; | 419 s3c_ac97_mic_in.channel = dmamic_res->start; |
| 420 s3c_ac97_mic_in.dma_addr = mem_res->start + S3C_AC97_MIC_DATA; | 420 s3c_ac97_mic_in.dma_addr = mem_res->start + S3C_AC97_MIC_DATA; |
| 421 | 421 |
| 422 init_completion(&s3c_ac97.done); | 422 init_completion(&s3c_ac97.done); |
| 423 mutex_init(&s3c_ac97.lock); | 423 mutex_init(&s3c_ac97.lock); |
| 424 | 424 |
| 425 s3c_ac97.regs = ioremap(mem_res->start, resource_size(mem_res)); | 425 s3c_ac97.regs = ioremap(mem_res->start, resource_size(mem_res)); |
| 426 if (s3c_ac97.regs == NULL) { | 426 if (s3c_ac97.regs == NULL) { |
| 427 dev_err(&pdev->dev, "Unable to ioremap register region\n"); | 427 dev_err(&pdev->dev, "Unable to ioremap register region\n"); |
| 428 ret = -ENXIO; | 428 ret = -ENXIO; |
| 429 goto err1; | 429 goto err1; |
| 430 } | 430 } |
| 431 | 431 |
| 432 s3c_ac97.ac97_clk = clk_get(&pdev->dev, "ac97"); | 432 s3c_ac97.ac97_clk = clk_get(&pdev->dev, "ac97"); |
| 433 if (IS_ERR(s3c_ac97.ac97_clk)) { | 433 if (IS_ERR(s3c_ac97.ac97_clk)) { |
| 434 » » dev_err(&pdev->dev, "s3c-ac97 failed to get ac97_clock\n"); | 434 » » dev_err(&pdev->dev, "ac97 failed to get ac97_clock\n"); |
| 435 ret = -ENODEV; | 435 ret = -ENODEV; |
| 436 goto err2; | 436 goto err2; |
| 437 } | 437 } |
| 438 clk_enable(s3c_ac97.ac97_clk); | 438 clk_enable(s3c_ac97.ac97_clk); |
| 439 | 439 |
| 440 if (ac97_pdata->cfg_gpio(pdev)) { | 440 if (ac97_pdata->cfg_gpio(pdev)) { |
| 441 dev_err(&pdev->dev, "Unable to configure gpio\n"); | 441 dev_err(&pdev->dev, "Unable to configure gpio\n"); |
| 442 ret = -EINVAL; | 442 ret = -EINVAL; |
| 443 goto err3; | 443 goto err3; |
| 444 } | 444 } |
| 445 | 445 |
| 446 ret = request_irq(irq_res->start, s3c_ac97_irq, | 446 ret = request_irq(irq_res->start, s3c_ac97_irq, |
| 447 IRQF_DISABLED, "AC97", NULL); | 447 IRQF_DISABLED, "AC97", NULL); |
| 448 if (ret < 0) { | 448 if (ret < 0) { |
| 449 » » dev_err(&pdev->dev, "s3c-ac97: interrupt request failed.\n"); | 449 » » dev_err(&pdev->dev, "ac97: interrupt request failed.\n"); |
| 450 goto err4; | 450 goto err4; |
| 451 } | 451 } |
| 452 | 452 |
| 453 ret = snd_soc_register_dais(&pdev->dev, s3c_ac97_dai, | 453 ret = snd_soc_register_dais(&pdev->dev, s3c_ac97_dai, |
| 454 ARRAY_SIZE(s3c_ac97_dai)); | 454 ARRAY_SIZE(s3c_ac97_dai)); |
| 455 if (ret) | 455 if (ret) |
| 456 goto err5; | 456 goto err5; |
| 457 | 457 |
| 458 return 0; | 458 return 0; |
| 459 | 459 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 490 if (mem_res) | 490 if (mem_res) |
| 491 release_mem_region(mem_res->start, resource_size(mem_res)); | 491 release_mem_region(mem_res->start, resource_size(mem_res)); |
| 492 | 492 |
| 493 return 0; | 493 return 0; |
| 494 } | 494 } |
| 495 | 495 |
| 496 static struct platform_driver s3c_ac97_driver = { | 496 static struct platform_driver s3c_ac97_driver = { |
| 497 .probe = s3c_ac97_probe, | 497 .probe = s3c_ac97_probe, |
| 498 .remove = s3c_ac97_remove, | 498 .remove = s3c_ac97_remove, |
| 499 .driver = { | 499 .driver = { |
| 500 » » .name = "s3c-ac97", | 500 » » .name = "samsung-ac97", |
| 501 .owner = THIS_MODULE, | 501 .owner = THIS_MODULE, |
| 502 }, | 502 }, |
| 503 }; | 503 }; |
| 504 | 504 |
| 505 static int __init s3c_ac97_init(void) | 505 static int __init s3c_ac97_init(void) |
| 506 { | 506 { |
| 507 return platform_driver_register(&s3c_ac97_driver); | 507 return platform_driver_register(&s3c_ac97_driver); |
| 508 } | 508 } |
| 509 module_init(s3c_ac97_init); | 509 module_init(s3c_ac97_init); |
| 510 | 510 |
| 511 static void __exit s3c_ac97_exit(void) | 511 static void __exit s3c_ac97_exit(void) |
| 512 { | 512 { |
| 513 platform_driver_unregister(&s3c_ac97_driver); | 513 platform_driver_unregister(&s3c_ac97_driver); |
| 514 } | 514 } |
| 515 module_exit(s3c_ac97_exit); | 515 module_exit(s3c_ac97_exit); |
| 516 | 516 |
| 517 MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>"); | 517 MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>"); |
| 518 MODULE_DESCRIPTION("AC97 driver for the Samsung SoC"); | 518 MODULE_DESCRIPTION("AC97 driver for the Samsung SoC"); |
| 519 MODULE_LICENSE("GPL"); | 519 MODULE_LICENSE("GPL"); |
| 520 MODULE_ALIAS("platform:s3c-ac97"); | 520 MODULE_ALIAS("platform:samsung-ac97"); |
| OLD | NEW |