/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c

https://bitbucket.org/sammyz/iscream_thunderc-2.6.35-rebase · C · 387 lines · 292 code · 75 blank · 20 comment · 27 complexity · 3280911ec1e952b9b49270adefe3cc85 MD5 · raw file

  1. /* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program; if not, write to the Free Software
  14. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  15. * 02110-1301, USA.
  16. *
  17. */
  18. #include <linux/module.h>
  19. #include <linux/platform_device.h>
  20. #include <linux/clk.h>
  21. #include <linux/err.h>
  22. #include <linux/slab.h>
  23. #include <linux/gpio.h>
  24. #include <linux/delay.h>
  25. #include <linux/io.h>
  26. #include <asm/uaccess.h>
  27. #include <asm/io.h>
  28. #include <mach/clk.h>
  29. #include <mach/qdsp6v2/audio_dev_ctl.h>
  30. #include <mach/qdsp6v2/apr_audio.h>
  31. #include "snddev_ecodec.h"
  32. #include <mach/qdsp6v2/q6afe.h>
  33. #define ECODEC_SAMPLE_RATE 8000
  34. /* Context for each external codec device */
  35. struct snddev_ecodec_state {
  36. struct snddev_ecodec_data *data;
  37. u32 sample_rate;
  38. };
  39. /* Global state for the driver */
  40. struct snddev_ecodec_drv_state {
  41. struct mutex dev_lock;
  42. int ref_cnt; /* ensure one rx device at a time */
  43. struct clk *ecodec_clk;
  44. };
  45. static struct snddev_ecodec_drv_state snddev_ecodec_drv;
  46. struct aux_pcm_state {
  47. unsigned int dout;
  48. unsigned int din;
  49. unsigned int syncout;
  50. unsigned int clkin_a;
  51. };
  52. static struct aux_pcm_state the_aux_pcm_state;
  53. static int aux_pcm_gpios_request(void)
  54. {
  55. int rc = 0;
  56. pr_debug("%s\n", __func__);
  57. rc = gpio_request(the_aux_pcm_state.dout, "AUX PCM DOUT");
  58. if (rc < 0) {
  59. pr_err("%s: GPIO request for AUX PCM DOUT failed\n", __func__);
  60. return rc;
  61. }
  62. rc = gpio_request(the_aux_pcm_state.din, "AUX PCM DIN");
  63. if (rc < 0) {
  64. pr_err("%s: GPIO request for AUX PCM DIN failed\n", __func__);
  65. gpio_free(the_aux_pcm_state.dout);
  66. return rc;
  67. }
  68. rc = gpio_request(the_aux_pcm_state.syncout, "AUX PCM SYNC OUT");
  69. if (rc < 0) {
  70. pr_err("%s: GPIO request for AUX PCM SYNC OUT failed\n",
  71. __func__);
  72. gpio_free(the_aux_pcm_state.dout);
  73. gpio_free(the_aux_pcm_state.din);
  74. return rc;
  75. }
  76. rc = gpio_request(the_aux_pcm_state.clkin_a, "AUX PCM CLKIN A");
  77. if (rc < 0) {
  78. pr_err("%s: GPIO request for AUX PCM CLKIN A failed\n",
  79. __func__);
  80. gpio_free(the_aux_pcm_state.dout);
  81. gpio_free(the_aux_pcm_state.din);
  82. gpio_free(the_aux_pcm_state.syncout);
  83. return rc;
  84. }
  85. return rc;
  86. }
  87. static void aux_pcm_gpios_free(void)
  88. {
  89. pr_debug("%s\n", __func__);
  90. gpio_free(the_aux_pcm_state.dout);
  91. gpio_free(the_aux_pcm_state.din);
  92. gpio_free(the_aux_pcm_state.syncout);
  93. gpio_free(the_aux_pcm_state.clkin_a);
  94. }
  95. static int get_aux_pcm_gpios(struct platform_device *pdev)
  96. {
  97. int rc = 0;
  98. struct resource *res;
  99. /* Claim all of the GPIOs. */
  100. res = platform_get_resource_byname(pdev, IORESOURCE_IO, "aux_pcm_dout");
  101. if (!res) {
  102. pr_err("%s: failed to get gpio AUX PCM DOUT\n", __func__);
  103. return -ENODEV;
  104. }
  105. the_aux_pcm_state.dout = res->start;
  106. res = platform_get_resource_byname(pdev, IORESOURCE_IO, "aux_pcm_din");
  107. if (!res) {
  108. pr_err("%s: failed to get gpio AUX PCM DIN\n", __func__);
  109. return -ENODEV;
  110. }
  111. the_aux_pcm_state.din = res->start;
  112. res = platform_get_resource_byname(pdev, IORESOURCE_IO,
  113. "aux_pcm_syncout");
  114. if (!res) {
  115. pr_err("%s: failed to get gpio AUX PCM SYNC OUT\n", __func__);
  116. return -ENODEV;
  117. }
  118. the_aux_pcm_state.syncout = res->start;
  119. res = platform_get_resource_byname(pdev, IORESOURCE_IO,
  120. "aux_pcm_clkin_a");
  121. if (!res) {
  122. pr_err("%s: failed to get gpio AUX PCM CLKIN A\n", __func__);
  123. return -ENODEV;
  124. }
  125. the_aux_pcm_state.clkin_a = res->start;
  126. return rc;
  127. }
  128. static int aux_pcm_probe(struct platform_device *pdev)
  129. {
  130. int rc = 0;
  131. rc = get_aux_pcm_gpios(pdev);
  132. if (rc < 0) {
  133. pr_err("%s: GPIO configuration failed\n", __func__);
  134. return -ENODEV;
  135. }
  136. return rc;
  137. }
  138. static struct platform_driver aux_pcm_driver = {
  139. .probe = aux_pcm_probe,
  140. .driver = { .name = "msm_aux_pcm"}
  141. };
  142. static int snddev_ecodec_open(struct msm_snddev_info *dev_info)
  143. {
  144. int rc;
  145. struct snddev_ecodec_drv_state *drv = &snddev_ecodec_drv;
  146. union afe_port_config afe_config;
  147. pr_debug("%s\n", __func__);
  148. mutex_lock(&drv->dev_lock);
  149. if (dev_info->opened) {
  150. pr_err("%s: ERROR: %s already opened\n", __func__,
  151. dev_info->name);
  152. mutex_unlock(&drv->dev_lock);
  153. return -EBUSY;
  154. }
  155. if (drv->ref_cnt != 0) {
  156. pr_debug("%s: opened %s\n", __func__, dev_info->name);
  157. drv->ref_cnt++;
  158. mutex_unlock(&drv->dev_lock);
  159. return 0;
  160. }
  161. pr_info("%s: opening %s\n", __func__, dev_info->name);
  162. rc = aux_pcm_gpios_request();
  163. if (rc < 0) {
  164. pr_err("%s: GPIO request failed\n", __func__);
  165. return rc;
  166. }
  167. clk_reset(drv->ecodec_clk, CLK_RESET_ASSERT);
  168. afe_config.pcm.mode = AFE_PCM_CFG_MODE_PCM;
  169. afe_config.pcm.sync = AFE_PCM_CFG_SYNC_INT;
  170. afe_config.pcm.frame = AFE_PCM_CFG_FRM_256BPF;
  171. afe_config.pcm.quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD;
  172. afe_config.pcm.slot = 0;
  173. afe_config.pcm.data = AFE_PCM_CFG_CDATAOE_MASTER;
  174. rc = afe_open(PCM_RX, &afe_config, ECODEC_SAMPLE_RATE);
  175. if (rc < 0) {
  176. pr_err("%s: afe open failed for PCM_RX\n", __func__);
  177. goto err_rx_afe;
  178. }
  179. rc = afe_open(PCM_TX, &afe_config, ECODEC_SAMPLE_RATE);
  180. if (rc < 0) {
  181. pr_err("%s: afe open failed for PCM_TX\n", __func__);
  182. goto err_tx_afe;
  183. }
  184. rc = clk_set_rate(drv->ecodec_clk, 2048000);
  185. if (rc < 0) {
  186. pr_err("%s: clk_set_rate failed\n", __func__);
  187. goto err_clk;
  188. }
  189. clk_enable(drv->ecodec_clk);
  190. clk_reset(drv->ecodec_clk, CLK_RESET_DEASSERT);
  191. drv->ref_cnt++;
  192. mutex_unlock(&drv->dev_lock);
  193. return 0;
  194. err_clk:
  195. afe_close(PCM_TX);
  196. err_tx_afe:
  197. afe_close(PCM_RX);
  198. err_rx_afe:
  199. aux_pcm_gpios_free();
  200. mutex_unlock(&drv->dev_lock);
  201. return -ENODEV;
  202. }
  203. int snddev_ecodec_close(struct msm_snddev_info *dev_info)
  204. {
  205. struct snddev_ecodec_drv_state *drv = &snddev_ecodec_drv;
  206. pr_debug("%s: closing %s\n", __func__, dev_info->name);
  207. mutex_lock(&drv->dev_lock);
  208. if (!dev_info->opened) {
  209. pr_err("%s: ERROR: %s is not opened\n", __func__,
  210. dev_info->name);
  211. mutex_unlock(&drv->dev_lock);
  212. return -EPERM;
  213. }
  214. drv->ref_cnt--;
  215. if (drv->ref_cnt == 0) {
  216. pr_info("%s: closing all devices\n", __func__);
  217. clk_disable(drv->ecodec_clk);
  218. aux_pcm_gpios_free();
  219. afe_close(PCM_RX);
  220. afe_close(PCM_TX);
  221. }
  222. mutex_unlock(&drv->dev_lock);
  223. return 0;
  224. }
  225. int snddev_ecodec_set_freq(struct msm_snddev_info *dev_info, u32 rate)
  226. {
  227. int rc = 0;
  228. if (!dev_info) {
  229. rc = -EINVAL;
  230. goto error;
  231. }
  232. return ECODEC_SAMPLE_RATE;
  233. error:
  234. return rc;
  235. }
  236. static int snddev_ecodec_probe(struct platform_device *pdev)
  237. {
  238. int rc = 0;
  239. struct snddev_ecodec_data *pdata;
  240. struct msm_snddev_info *dev_info;
  241. struct snddev_ecodec_state *ecodec;
  242. if (!pdev || !pdev->dev.platform_data) {
  243. printk(KERN_ALERT "Invalid caller\n");
  244. rc = -1;
  245. goto error;
  246. }
  247. pdata = pdev->dev.platform_data;
  248. ecodec = kzalloc(sizeof(struct snddev_ecodec_state), GFP_KERNEL);
  249. if (!ecodec) {
  250. rc = -ENOMEM;
  251. goto error;
  252. }
  253. dev_info = kzalloc(sizeof(struct msm_snddev_info), GFP_KERNEL);
  254. if (!dev_info) {
  255. kfree(ecodec);
  256. rc = -ENOMEM;
  257. goto error;
  258. }
  259. dev_info->name = pdata->name;
  260. dev_info->copp_id = pdata->copp_id;
  261. dev_info->private_data = (void *)ecodec;
  262. dev_info->dev_ops.open = snddev_ecodec_open;
  263. dev_info->dev_ops.close = snddev_ecodec_close;
  264. dev_info->dev_ops.set_freq = snddev_ecodec_set_freq;
  265. dev_info->dev_ops.enable_sidetone = NULL;
  266. dev_info->capability = pdata->capability;
  267. dev_info->opened = 0;
  268. msm_snddev_register(dev_info);
  269. ecodec->data = pdata;
  270. ecodec->sample_rate = ECODEC_SAMPLE_RATE; /* Default to 8KHz */
  271. error:
  272. return rc;
  273. }
  274. struct platform_driver snddev_ecodec_driver = {
  275. .probe = snddev_ecodec_probe,
  276. .driver = {.name = "msm_snddev_ecodec"}
  277. };
  278. int __init snddev_ecodec_init(void)
  279. {
  280. int rc = 0;
  281. struct snddev_ecodec_drv_state *drv = &snddev_ecodec_drv;
  282. mutex_init(&drv->dev_lock);
  283. drv->ref_cnt = 0;
  284. drv->ecodec_clk = clk_get(NULL, "pcm_clk");
  285. if (IS_ERR(drv->ecodec_clk)) {
  286. pr_err("%s: could not get pcm_clk\n", __func__);
  287. return PTR_ERR(drv->ecodec_clk);
  288. }
  289. rc = platform_driver_register(&aux_pcm_driver);
  290. if (IS_ERR_VALUE(rc)) {
  291. pr_err("%s: platform_driver_register for aux pcm failed\n",
  292. __func__);
  293. goto error_aux_pcm_platform_driver;
  294. }
  295. rc = platform_driver_register(&snddev_ecodec_driver);
  296. if (IS_ERR_VALUE(rc)) {
  297. pr_err("%s: platform_driver_register for ecodec failed\n",
  298. __func__);
  299. goto error_ecodec_platform_driver;
  300. }
  301. return 0;
  302. error_ecodec_platform_driver:
  303. platform_driver_unregister(&aux_pcm_driver);
  304. error_aux_pcm_platform_driver:
  305. clk_put(drv->ecodec_clk);
  306. pr_err("%s: encounter error\n", __func__);
  307. return -ENODEV;
  308. }
  309. device_initcall(snddev_ecodec_init);
  310. MODULE_DESCRIPTION("ECodec Sound Device driver");
  311. MODULE_VERSION("1.0");
  312. MODULE_LICENSE("GPL v2");