imx-es8328.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. /*
  2. * Copyright 2012 Freescale Semiconductor, Inc.
  3. * Copyright 2012 Linaro Ltd.
  4. *
  5. * The code contained herein is licensed under the GNU General Public
  6. * License. You may obtain a copy of the GNU General Public License
  7. * Version 2 or later at the following locations:
  8. *
  9. * http://www.opensource.org/licenses/gpl-license.html
  10. * http://www.gnu.org/copyleft/gpl.html
  11. */
  12. #include <linux/gpio.h>
  13. #include <linux/module.h>
  14. #include <linux/of.h>
  15. #include <linux/of_platform.h>
  16. #include <linux/i2c.h>
  17. #include <linux/of_gpio.h>
  18. #include <sound/soc.h>
  19. #include <sound/jack.h>
  20. #include "imx-audmux.h"
  21. #define DAI_NAME_SIZE 32
  22. #define MUX_PORT_MAX 7
  23. struct imx_es8328_data {
  24. struct device *dev;
  25. struct snd_soc_dai_link dai;
  26. struct snd_soc_card card;
  27. char codec_dai_name[DAI_NAME_SIZE];
  28. char platform_name[DAI_NAME_SIZE];
  29. int jack_gpio;
  30. };
  31. static struct snd_soc_jack_gpio headset_jack_gpios[] = {
  32. {
  33. .gpio = -1,
  34. .name = "headset-gpio",
  35. .report = SND_JACK_HEADSET,
  36. .invert = 0,
  37. .debounce_time = 200,
  38. },
  39. };
  40. static struct snd_soc_jack headset_jack;
  41. static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd)
  42. {
  43. struct imx_es8328_data *data = container_of(rtd->card,
  44. struct imx_es8328_data, card);
  45. int ret = 0;
  46. /* Headphone jack detection */
  47. if (gpio_is_valid(data->jack_gpio)) {
  48. ret = snd_soc_card_jack_new(rtd->card, "Headphone",
  49. SND_JACK_HEADPHONE | SND_JACK_BTN_0,
  50. &headset_jack, NULL, 0);
  51. if (ret)
  52. return ret;
  53. headset_jack_gpios[0].gpio = data->jack_gpio;
  54. ret = snd_soc_jack_add_gpios(&headset_jack,
  55. ARRAY_SIZE(headset_jack_gpios),
  56. headset_jack_gpios);
  57. }
  58. return ret;
  59. }
  60. static const struct snd_soc_dapm_widget imx_es8328_dapm_widgets[] = {
  61. SND_SOC_DAPM_MIC("Mic Jack", NULL),
  62. SND_SOC_DAPM_HP("Headphone", NULL),
  63. SND_SOC_DAPM_SPK("Speaker", NULL),
  64. SND_SOC_DAPM_REGULATOR_SUPPLY("audio-amp", 1, 0),
  65. };
  66. static int imx_es8328_probe(struct platform_device *pdev)
  67. {
  68. struct device_node *np = pdev->dev.of_node;
  69. struct device_node *ssi_np = NULL, *codec_np = NULL;
  70. struct platform_device *ssi_pdev;
  71. struct imx_es8328_data *data;
  72. u32 int_port, ext_port;
  73. int ret;
  74. struct device *dev = &pdev->dev;
  75. ret = of_property_read_u32(np, "mux-int-port", &int_port);
  76. if (ret) {
  77. dev_err(dev, "mux-int-port missing or invalid\n");
  78. goto fail;
  79. }
  80. if (int_port > MUX_PORT_MAX || int_port == 0) {
  81. dev_err(dev, "mux-int-port: hardware only has %d mux ports\n",
  82. MUX_PORT_MAX);
  83. goto fail;
  84. }
  85. ret = of_property_read_u32(np, "mux-ext-port", &ext_port);
  86. if (ret) {
  87. dev_err(dev, "mux-ext-port missing or invalid\n");
  88. goto fail;
  89. }
  90. if (ext_port > MUX_PORT_MAX || ext_port == 0) {
  91. dev_err(dev, "mux-ext-port: hardware only has %d mux ports\n",
  92. MUX_PORT_MAX);
  93. ret = -EINVAL;
  94. goto fail;
  95. }
  96. /*
  97. * The port numbering in the hardware manual starts at 1, while
  98. * the audmux API expects it starts at 0.
  99. */
  100. int_port--;
  101. ext_port--;
  102. ret = imx_audmux_v2_configure_port(int_port,
  103. IMX_AUDMUX_V2_PTCR_SYN |
  104. IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
  105. IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
  106. IMX_AUDMUX_V2_PTCR_TFSDIR |
  107. IMX_AUDMUX_V2_PTCR_TCLKDIR,
  108. IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
  109. if (ret) {
  110. dev_err(dev, "audmux internal port setup failed\n");
  111. return ret;
  112. }
  113. ret = imx_audmux_v2_configure_port(ext_port,
  114. IMX_AUDMUX_V2_PTCR_SYN,
  115. IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
  116. if (ret) {
  117. dev_err(dev, "audmux external port setup failed\n");
  118. return ret;
  119. }
  120. ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0);
  121. codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0);
  122. if (!ssi_np || !codec_np) {
  123. dev_err(dev, "phandle missing or invalid\n");
  124. ret = -EINVAL;
  125. goto fail;
  126. }
  127. ssi_pdev = of_find_device_by_node(ssi_np);
  128. if (!ssi_pdev) {
  129. dev_err(dev, "failed to find SSI platform device\n");
  130. ret = -EINVAL;
  131. goto fail;
  132. }
  133. data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
  134. if (!data) {
  135. ret = -ENOMEM;
  136. goto fail;
  137. }
  138. data->dev = dev;
  139. data->jack_gpio = of_get_named_gpio(pdev->dev.of_node, "jack-gpio", 0);
  140. data->dai.name = "hifi";
  141. data->dai.stream_name = "hifi";
  142. data->dai.codec_dai_name = "es8328-hifi-analog";
  143. data->dai.codec_of_node = codec_np;
  144. data->dai.cpu_of_node = ssi_np;
  145. data->dai.platform_of_node = ssi_np;
  146. data->dai.init = &imx_es8328_dai_init;
  147. data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
  148. SND_SOC_DAIFMT_CBM_CFM;
  149. data->card.dev = dev;
  150. data->card.dapm_widgets = imx_es8328_dapm_widgets;
  151. data->card.num_dapm_widgets = ARRAY_SIZE(imx_es8328_dapm_widgets);
  152. ret = snd_soc_of_parse_card_name(&data->card, "model");
  153. if (ret) {
  154. dev_err(dev, "Unable to parse card name\n");
  155. goto fail;
  156. }
  157. ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing");
  158. if (ret) {
  159. dev_err(dev, "Unable to parse routing: %d\n", ret);
  160. goto fail;
  161. }
  162. data->card.num_links = 1;
  163. data->card.owner = THIS_MODULE;
  164. data->card.dai_link = &data->dai;
  165. ret = snd_soc_register_card(&data->card);
  166. if (ret) {
  167. dev_err(dev, "Unable to register: %d\n", ret);
  168. goto fail;
  169. }
  170. platform_set_drvdata(pdev, data);
  171. fail:
  172. of_node_put(ssi_np);
  173. of_node_put(codec_np);
  174. return ret;
  175. }
  176. static int imx_es8328_remove(struct platform_device *pdev)
  177. {
  178. struct imx_es8328_data *data = platform_get_drvdata(pdev);
  179. snd_soc_jack_free_gpios(&headset_jack, ARRAY_SIZE(headset_jack_gpios),
  180. headset_jack_gpios);
  181. snd_soc_unregister_card(&data->card);
  182. return 0;
  183. }
  184. static const struct of_device_id imx_es8328_dt_ids[] = {
  185. { .compatible = "fsl,imx-audio-es8328", },
  186. { /* sentinel */ }
  187. };
  188. MODULE_DEVICE_TABLE(of, imx_es8328_dt_ids);
  189. static struct platform_driver imx_es8328_driver = {
  190. .driver = {
  191. .name = "imx-es8328",
  192. .of_match_table = imx_es8328_dt_ids,
  193. },
  194. .probe = imx_es8328_probe,
  195. .remove = imx_es8328_remove,
  196. };
  197. module_platform_driver(imx_es8328_driver);
  198. MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
  199. MODULE_DESCRIPTION("Kosagi i.MX6 ES8328 ASoC machine driver");
  200. MODULE_LICENSE("GPL v2");
  201. MODULE_ALIAS("platform:imx-audio-es8328");