pcm3008.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /*
  2. * ALSA Soc PCM3008 codec support
  3. *
  4. * Author: Hugo Villeneuve
  5. * Copyright (C) 2008 Lyrtech inc
  6. *
  7. * Based on AC97 Soc codec, original copyright follow:
  8. * Copyright 2005 Wolfson Microelectronics PLC.
  9. *
  10. * This program is free software; you can redistribute it and/or modify it
  11. * under the terms of the GNU General Public License as published by the
  12. * Free Software Foundation; either version 2 of the License, or (at your
  13. * option) any later version.
  14. *
  15. * Generic PCM3008 support.
  16. */
  17. #include <linux/init.h>
  18. #include <linux/kernel.h>
  19. #include <linux/device.h>
  20. #include <linux/gpio.h>
  21. #include <linux/slab.h>
  22. #include <linux/module.h>
  23. #include <sound/core.h>
  24. #include <sound/pcm.h>
  25. #include <sound/initval.h>
  26. #include <sound/soc.h>
  27. #include "pcm3008.h"
  28. static const struct snd_soc_dapm_widget pcm3008_dapm_widgets[] = {
  29. SND_SOC_DAPM_INPUT("VINL"),
  30. SND_SOC_DAPM_INPUT("VINR"),
  31. SND_SOC_DAPM_OUTPUT("VOUTL"),
  32. SND_SOC_DAPM_OUTPUT("VOUTR"),
  33. };
  34. static const struct snd_soc_dapm_route pcm3008_dapm_routes[] = {
  35. { "PCM3008 Capture", NULL, "VINL" },
  36. { "PCM3008 Capture", NULL, "VINR" },
  37. { "VOUTL", NULL, "PCM3008 Playback" },
  38. { "VOUTR", NULL, "PCM3008 Playback" },
  39. };
  40. #define PCM3008_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
  41. SNDRV_PCM_RATE_48000)
  42. static struct snd_soc_dai_driver pcm3008_dai = {
  43. .name = "pcm3008-hifi",
  44. .playback = {
  45. .stream_name = "PCM3008 Playback",
  46. .channels_min = 1,
  47. .channels_max = 2,
  48. .rates = PCM3008_RATES,
  49. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  50. },
  51. .capture = {
  52. .stream_name = "PCM3008 Capture",
  53. .channels_min = 1,
  54. .channels_max = 2,
  55. .rates = PCM3008_RATES,
  56. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  57. },
  58. };
  59. #ifdef CONFIG_PM
  60. static int pcm3008_soc_suspend(struct snd_soc_codec *codec)
  61. {
  62. struct pcm3008_setup_data *setup = codec->dev->platform_data;
  63. gpio_set_value_cansleep(setup->pdad_pin, 0);
  64. gpio_set_value_cansleep(setup->pdda_pin, 0);
  65. return 0;
  66. }
  67. static int pcm3008_soc_resume(struct snd_soc_codec *codec)
  68. {
  69. struct pcm3008_setup_data *setup = codec->dev->platform_data;
  70. gpio_set_value_cansleep(setup->pdad_pin, 1);
  71. gpio_set_value_cansleep(setup->pdda_pin, 1);
  72. return 0;
  73. }
  74. #else
  75. #define pcm3008_soc_suspend NULL
  76. #define pcm3008_soc_resume NULL
  77. #endif
  78. static struct snd_soc_codec_driver soc_codec_dev_pcm3008 = {
  79. .suspend = pcm3008_soc_suspend,
  80. .resume = pcm3008_soc_resume,
  81. .dapm_widgets = pcm3008_dapm_widgets,
  82. .num_dapm_widgets = ARRAY_SIZE(pcm3008_dapm_widgets),
  83. .dapm_routes = pcm3008_dapm_routes,
  84. .num_dapm_routes = ARRAY_SIZE(pcm3008_dapm_routes),
  85. };
  86. static int pcm3008_codec_probe(struct platform_device *pdev)
  87. {
  88. struct pcm3008_setup_data *setup = pdev->dev.platform_data;
  89. int ret;
  90. if (!setup)
  91. return -EINVAL;
  92. /* DEM1 DEM0 DE-EMPHASIS_MODE
  93. * Low Low De-emphasis 44.1 kHz ON
  94. * Low High De-emphasis OFF
  95. * High Low De-emphasis 48 kHz ON
  96. * High High De-emphasis 32 kHz ON
  97. */
  98. /* Configure DEM0 GPIO (turning OFF DAC De-emphasis). */
  99. ret = devm_gpio_request_one(&pdev->dev, setup->dem0_pin,
  100. GPIOF_OUT_INIT_HIGH, "codec_dem0");
  101. if (ret != 0)
  102. return ret;
  103. /* Configure DEM1 GPIO (turning OFF DAC De-emphasis). */
  104. ret = devm_gpio_request_one(&pdev->dev, setup->dem1_pin,
  105. GPIOF_OUT_INIT_LOW, "codec_dem1");
  106. if (ret != 0)
  107. return ret;
  108. /* Configure PDAD GPIO. */
  109. ret = devm_gpio_request_one(&pdev->dev, setup->pdad_pin,
  110. GPIOF_OUT_INIT_HIGH, "codec_pdad");
  111. if (ret != 0)
  112. return ret;
  113. /* Configure PDDA GPIO. */
  114. ret = devm_gpio_request_one(&pdev->dev, setup->pdda_pin,
  115. GPIOF_OUT_INIT_HIGH, "codec_pdda");
  116. if (ret != 0)
  117. return ret;
  118. return snd_soc_register_codec(&pdev->dev,
  119. &soc_codec_dev_pcm3008, &pcm3008_dai, 1);
  120. }
  121. static int pcm3008_codec_remove(struct platform_device *pdev)
  122. {
  123. snd_soc_unregister_codec(&pdev->dev);
  124. return 0;
  125. }
  126. MODULE_ALIAS("platform:pcm3008-codec");
  127. static struct platform_driver pcm3008_codec_driver = {
  128. .probe = pcm3008_codec_probe,
  129. .remove = pcm3008_codec_remove,
  130. .driver = {
  131. .name = "pcm3008-codec",
  132. .owner = THIS_MODULE,
  133. },
  134. };
  135. module_platform_driver(pcm3008_codec_driver);
  136. MODULE_DESCRIPTION("Soc PCM3008 driver");
  137. MODULE_AUTHOR("Hugo Villeneuve");
  138. MODULE_LICENSE("GPL");