/arch/arm/mach-msm/qdsp5v2/audio_fm.c

https://bitbucket.org/sammyz/iscream_thunderc-2.6.35-rebase · C · 358 lines · 284 code · 38 blank · 36 comment · 37 complexity · 5089e040ef95cd8eafe1647d19829c17 MD5 · raw file

  1. /* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
  2. *
  3. * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5v2/audio_mp3.c
  4. *
  5. * Copyright (C) 2008 Google, Inc.
  6. * Copyright (C) 2008 HTC Corporation
  7. *
  8. * All source code in this file is licensed under the following license except
  9. * where indicated.
  10. *
  11. * This program is free software; you can redistribute it and/or modify it
  12. * under the terms of the GNU General Public License version 2 as published
  13. * by the Free Software Foundation.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  18. *
  19. * See the GNU General Public License for more details.
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, you can find it at http://www.fsf.org
  22. */
  23. #include <linux/module.h>
  24. #include <linux/fs.h>
  25. #include <linux/miscdevice.h>
  26. #include <linux/uaccess.h>
  27. #include <linux/kthread.h>
  28. #include <linux/wait.h>
  29. #include <linux/dma-mapping.h>
  30. #include <linux/delay.h>
  31. #include <linux/android_pmem.h>
  32. #include <linux/msm_audio.h>
  33. #include <asm/atomic.h>
  34. #include <asm/ioctls.h>
  35. #include <mach/msm_adsp.h>
  36. #include <mach/debug_mm.h>
  37. #include <mach/qdsp5v2/audio_dev_ctl.h>
  38. #include <mach/qdsp5v2/afe.h>
  39. #include <mach/qdsp5v2/acdb_commands.h>
  40. #include <mach/qdsp5v2/audio_acdbi.h>
  41. #include <mach/qdsp5v2/audio_acdb_def.h>
  42. #define SESSION_ID_FM 6
  43. #define FM_ENABLE 0xFFFF
  44. #define FM_DISABLE 0x0
  45. #define FM_COPP 0x2
  46. /* Macro specifies maximum FM routing
  47. possible */
  48. #define FM_MAX_RX_ROUTE 0x2
  49. struct fm_rx_calib_gain {
  50. uint16_t device_id;
  51. struct auddev_evt_devinfo dev_details;
  52. struct acdb_calib_gain_rx calib_rx;
  53. };
  54. struct audio {
  55. struct mutex lock;
  56. int opened;
  57. int enabled;
  58. int running;
  59. uint16_t dec_id;
  60. uint16_t source;
  61. uint16_t fm_source;
  62. uint16_t fm_mask;
  63. uint32_t device_events;
  64. uint16_t volume;
  65. struct fm_rx_calib_gain fm_calibration_rx[FM_MAX_RX_ROUTE];
  66. };
  67. static struct audio fm_audio;
  68. /* must be called with audio->lock held */
  69. static int audio_enable(struct audio *audio)
  70. {
  71. int rc = 0;
  72. if (audio->enabled)
  73. return 0;
  74. MM_DBG("fm mask= %08x fm_source = %08x\n",
  75. audio->fm_mask, audio->fm_source);
  76. if (audio->fm_mask && audio->fm_source) {
  77. rc = afe_config_fm_codec(FM_ENABLE, audio->fm_mask);
  78. if (!rc)
  79. audio->running = 1;
  80. /* Routed to icodec rx path */
  81. if ((audio->fm_mask & AFE_HW_PATH_CODEC_RX) ==
  82. AFE_HW_PATH_CODEC_RX) {
  83. afe_config_fm_calibration_gain(
  84. audio->fm_calibration_rx[0].device_id,
  85. audio->fm_calibration_rx[0].calib_rx.audppcalgain);
  86. }
  87. /* Routed to aux codec rx path */
  88. if ((audio->fm_mask & AFE_HW_PATH_AUXPCM_RX) ==
  89. AFE_HW_PATH_AUXPCM_RX){
  90. afe_config_fm_calibration_gain(
  91. audio->fm_calibration_rx[1].device_id,
  92. audio->fm_calibration_rx[1].calib_rx.audppcalgain);
  93. }
  94. }
  95. audio->enabled = 1;
  96. return rc;
  97. }
  98. static void fm_listner(u32 evt_id, union auddev_evt_data *evt_payload,
  99. void *private_data)
  100. {
  101. struct audio *audio = (struct audio *) private_data;
  102. struct auddev_evt_devinfo *devinfo =
  103. (struct auddev_evt_devinfo *)evt_payload;
  104. switch (evt_id) {
  105. case AUDDEV_EVT_DEV_RDY:
  106. MM_DBG(":AUDDEV_EVT_DEV_RDY\n");
  107. if (evt_payload->routing_id == FM_COPP)
  108. audio->fm_source = 1;
  109. else
  110. audio->source = (0x1 << evt_payload->routing_id);
  111. if (audio->source & 0x1)
  112. audio->fm_mask = 0x1;
  113. else if (audio->source & 0x2)
  114. audio->fm_mask = 0x3;
  115. else
  116. audio->fm_mask = 0x0;
  117. if (!audio->enabled
  118. || !audio->fm_mask
  119. || !audio->fm_source)
  120. break;
  121. else {
  122. afe_config_fm_codec(FM_ENABLE, audio->fm_mask);
  123. audio->running = 1;
  124. }
  125. break;
  126. case AUDDEV_EVT_DEV_RLS:
  127. MM_DBG(":AUDDEV_EVT_DEV_RLS\n");
  128. if (evt_payload->routing_id == FM_COPP)
  129. audio->fm_source = 0;
  130. else
  131. audio->source &= ~(0x1 << evt_payload->routing_id);
  132. if (audio->source & 0x1)
  133. audio->fm_mask = 0x1;
  134. else if (audio->source & 0x2)
  135. audio->fm_mask = 0x3;
  136. else
  137. audio->fm_mask = 0x0;
  138. if (audio->running
  139. && (!audio->fm_mask || !audio->fm_source)) {
  140. afe_config_fm_codec(FM_DISABLE, audio->fm_mask);
  141. audio->running = 0;
  142. }
  143. break;
  144. case AUDDEV_EVT_STREAM_VOL_CHG:
  145. MM_DBG(":AUDDEV_EVT_STREAM_VOL_CHG, stream vol \n");
  146. audio->volume = evt_payload->session_vol;
  147. afe_config_fm_volume(audio->volume);
  148. break;
  149. case AUDDEV_EVT_DEVICE_INFO:{
  150. struct acdb_get_block get_block;
  151. int rc = 0;
  152. MM_DBG(":AUDDEV_EVT_DEVICE_INFO\n");
  153. MM_DBG("sample_rate = %d\n", devinfo->sample_rate);
  154. MM_DBG("acdb_id = %d\n", devinfo->acdb_id);
  155. /* Applucable only for icodec rx and aux codec rx path
  156. and fm stream routed to it */
  157. if (((devinfo->dev_id == 0x00) || (devinfo->dev_id == 0x01)) &&
  158. (devinfo->sessions && (1 << audio->dec_id))) {
  159. /* Query ACDB driver for calib gain, only if difference
  160. in device */
  161. if ((audio->fm_calibration_rx[devinfo->dev_id].
  162. dev_details.acdb_id != devinfo->acdb_id) ||
  163. (audio->fm_calibration_rx[devinfo->dev_id].
  164. dev_details.sample_rate !=
  165. devinfo->sample_rate)) {
  166. audio->fm_calibration_rx[devinfo->dev_id].
  167. dev_details.dev_id = devinfo->dev_id;
  168. audio->fm_calibration_rx[devinfo->dev_id].
  169. dev_details.sample_rate =
  170. devinfo->sample_rate;
  171. audio->fm_calibration_rx[devinfo->dev_id].
  172. dev_details.dev_type =
  173. devinfo->dev_type;
  174. audio->fm_calibration_rx[devinfo->dev_id].
  175. dev_details.sessions =
  176. devinfo->sessions;
  177. /* Query ACDB driver for calibration gain */
  178. get_block.acdb_id = devinfo->acdb_id;
  179. get_block.sample_rate_id = devinfo->sample_rate;
  180. get_block.interface_id =
  181. IID_AUDIO_CALIBRATION_GAIN_RX;
  182. get_block.algorithm_block_id =
  183. ABID_AUDIO_CALIBRATION_GAIN_RX;
  184. get_block.total_bytes =
  185. sizeof(struct acdb_calib_gain_rx);
  186. get_block.buf_ptr = (u32 *)
  187. &audio->fm_calibration_rx[devinfo->dev_id].
  188. calib_rx;
  189. rc = acdb_get_calibration_data(&get_block);
  190. if (rc < 0) {
  191. MM_ERR("Unable to get calibration"\
  192. "gain\n");
  193. /* Set to unity incase of error */
  194. audio->\
  195. fm_calibration_rx[devinfo->dev_id].
  196. calib_rx.audppcalgain = 0x2000;
  197. } else
  198. MM_DBG("calibration gain = 0x%8x\n",
  199. *(get_block.buf_ptr));
  200. }
  201. if (audio->running) {
  202. afe_config_fm_calibration_gain(
  203. audio->fm_calibration_rx[devinfo->dev_id].
  204. device_id,
  205. audio->fm_calibration_rx[devinfo->dev_id].
  206. calib_rx.audppcalgain);
  207. }
  208. }
  209. break;
  210. }
  211. default:
  212. MM_DBG(":ERROR:wrong event\n");
  213. break;
  214. }
  215. }
  216. /* must be called with audio->lock held */
  217. static int audio_disable(struct audio *audio)
  218. {
  219. MM_DBG("\n"); /* Macro prints the file name and function */
  220. return afe_config_fm_codec(FM_DISABLE, audio->source);
  221. }
  222. static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  223. {
  224. struct audio *audio = file->private_data;
  225. int rc = -EINVAL;
  226. MM_DBG("cmd = %d\n", cmd);
  227. mutex_lock(&audio->lock);
  228. switch (cmd) {
  229. case AUDIO_START:
  230. MM_DBG("AUDIO_START\n");
  231. rc = audio_enable(audio);
  232. break;
  233. case AUDIO_STOP:
  234. MM_DBG("AUDIO_STOP\n");
  235. rc = audio_disable(audio);
  236. audio->running = 0;
  237. audio->enabled = 0;
  238. break;
  239. case AUDIO_GET_SESSION_ID:
  240. if (copy_to_user((void *) arg, &audio->dec_id,
  241. sizeof(unsigned short)))
  242. rc = -EFAULT;
  243. else
  244. rc = 0;
  245. break;
  246. default:
  247. rc = -EINVAL;
  248. }
  249. mutex_unlock(&audio->lock);
  250. return rc;
  251. }
  252. static int audio_release(struct inode *inode, struct file *file)
  253. {
  254. struct audio *audio = file->private_data;
  255. MM_DBG("audio instance 0x%08x freeing\n", (int)audio);
  256. mutex_lock(&audio->lock);
  257. auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->dec_id);
  258. audio_disable(audio);
  259. audio->running = 0;
  260. audio->enabled = 0;
  261. audio->opened = 0;
  262. mutex_unlock(&audio->lock);
  263. return 0;
  264. }
  265. static int audio_open(struct inode *inode, struct file *file)
  266. {
  267. struct audio *audio = &fm_audio;
  268. int rc = 0;
  269. if (audio->opened)
  270. return -EPERM;
  271. /* Allocate the decoder */
  272. audio->dec_id = SESSION_ID_FM;
  273. audio->running = 0;
  274. audio->fm_source = 0;
  275. audio->fm_mask = 0;
  276. /* Initialize the calibration gain structure */
  277. audio->fm_calibration_rx[0].device_id = AFE_HW_PATH_CODEC_RX;
  278. audio->fm_calibration_rx[1].device_id = AFE_HW_PATH_AUXPCM_RX;
  279. audio->fm_calibration_rx[0].calib_rx.audppcalgain = 0x2000;
  280. audio->fm_calibration_rx[1].calib_rx.audppcalgain = 0x2000;
  281. audio->fm_calibration_rx[0].dev_details.acdb_id = PSEUDO_ACDB_ID;
  282. audio->fm_calibration_rx[1].dev_details.acdb_id = PSEUDO_ACDB_ID;
  283. audio->device_events = AUDDEV_EVT_DEV_RDY
  284. |AUDDEV_EVT_DEV_RLS|
  285. AUDDEV_EVT_STREAM_VOL_CHG|
  286. AUDDEV_EVT_DEVICE_INFO;
  287. rc = auddev_register_evt_listner(audio->device_events,
  288. AUDDEV_CLNT_DEC,
  289. audio->dec_id,
  290. fm_listner,
  291. (void *)audio);
  292. if (rc) {
  293. MM_ERR("%s: failed to register listnet\n", __func__);
  294. goto event_err;
  295. }
  296. audio->opened = 1;
  297. file->private_data = audio;
  298. event_err:
  299. return rc;
  300. }
  301. static const struct file_operations audio_fm_fops = {
  302. .owner = THIS_MODULE,
  303. .open = audio_open,
  304. .release = audio_release,
  305. .unlocked_ioctl = audio_ioctl,
  306. };
  307. struct miscdevice audio_fm_misc = {
  308. .minor = MISC_DYNAMIC_MINOR,
  309. .name = "msm_fm",
  310. .fops = &audio_fm_fops,
  311. };
  312. static int __init audio_init(void)
  313. {
  314. struct audio *audio = &fm_audio;
  315. mutex_init(&audio->lock);
  316. return misc_register(&audio_fm_misc);
  317. }
  318. device_initcall(audio_init);
  319. MODULE_DESCRIPTION("MSM FM driver");
  320. MODULE_LICENSE("GPL v2");