msm-pcm-dtmf-v2.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. /* Copyright (c) 2013, The Linux Foundation. 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. #include <linux/init.h>
  13. #include <linux/module.h>
  14. #include <linux/time.h>
  15. #include <linux/wait.h>
  16. #include <linux/platform_device.h>
  17. #include <linux/slab.h>
  18. #include <linux/dma-mapping.h>
  19. #include <sound/core.h>
  20. #include <sound/soc.h>
  21. #include <sound/pcm.h>
  22. #include <sound/q6afe-v2.h>
  23. #include "msm-pcm-q6-v2.h"
  24. #include "msm-pcm-routing-v2.h"
  25. #include "q6voice.h"
  26. enum {
  27. DTMF_IN_RX,
  28. DTMF_IN_TX,
  29. };
  30. enum format {
  31. FORMAT_S16_LE = 2
  32. };
  33. struct dtmf_det_info {
  34. char session[MAX_SESSION_NAME_LEN];
  35. uint8_t dir;
  36. uint16_t high_freq;
  37. uint16_t low_freq;
  38. };
  39. struct dtmf_buf_node {
  40. struct list_head list;
  41. struct dtmf_det_info dtmf_det_pkt;
  42. };
  43. enum dtmf_state {
  44. DTMF_GEN_RX_STOPPED,
  45. DTMF_GEN_RX_STARTED,
  46. };
  47. #define DTMF_MAX_Q_LEN 10
  48. #define DTMF_PKT_SIZE sizeof(struct dtmf_det_info)
  49. struct dtmf_drv_info {
  50. enum dtmf_state state;
  51. struct snd_pcm_substream *capture_substream;
  52. struct list_head out_queue;
  53. struct list_head free_out_queue;
  54. wait_queue_head_t out_wait;
  55. struct mutex lock;
  56. spinlock_t dsp_lock;
  57. uint8_t capture_start;
  58. uint8_t capture_instance;
  59. unsigned int pcm_capture_size;
  60. unsigned int pcm_capture_count;
  61. unsigned int pcm_capture_irq_pos;
  62. unsigned int pcm_capture_buf_pos;
  63. };
  64. static struct snd_pcm_hardware msm_pcm_hardware = {
  65. .info = (SNDRV_PCM_INFO_MMAP |
  66. SNDRV_PCM_INFO_BLOCK_TRANSFER |
  67. SNDRV_PCM_INFO_MMAP_VALID |
  68. SNDRV_PCM_INFO_INTERLEAVED),
  69. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  70. .channels_min = 1,
  71. .channels_max = 1,
  72. .buffer_bytes_max = (sizeof(struct dtmf_buf_node) * DTMF_MAX_Q_LEN),
  73. .period_bytes_min = DTMF_PKT_SIZE,
  74. .period_bytes_max = DTMF_PKT_SIZE,
  75. .periods_min = DTMF_MAX_Q_LEN,
  76. .periods_max = DTMF_MAX_Q_LEN,
  77. .fifo_size = 0,
  78. };
  79. static int msm_dtmf_rx_generate_put(struct snd_kcontrol *kcontrol,
  80. struct snd_ctl_elem_value *ucontrol)
  81. {
  82. uint16_t low_freq = ucontrol->value.integer.value[0];
  83. uint16_t high_freq = ucontrol->value.integer.value[1];
  84. int64_t duration = ucontrol->value.integer.value[2];
  85. uint16_t gain = ucontrol->value.integer.value[3];
  86. pr_debug("%s: low_freq=%d high_freq=%d duration=%d gain=%d\n",
  87. __func__, low_freq, high_freq, (int)duration, gain);
  88. afe_dtmf_generate_rx(duration, high_freq, low_freq, gain);
  89. return 0;
  90. }
  91. static int msm_dtmf_rx_generate_get(struct snd_kcontrol *kcontrol,
  92. struct snd_ctl_elem_value *ucontrol)
  93. {
  94. pr_debug("%s:\n", __func__);
  95. ucontrol->value.integer.value[0] = 0;
  96. return 0;
  97. }
  98. static int msm_dtmf_detect_voice_rx_put(struct snd_kcontrol *kcontrol,
  99. struct snd_ctl_elem_value *ucontrol)
  100. {
  101. int enable = ucontrol->value.integer.value[0];
  102. pr_debug("%s: enable=%d\n", __func__, enable);
  103. voc_enable_dtmf_rx_detection(voc_get_session_id(VOICE_SESSION_NAME),
  104. enable);
  105. return 0;
  106. }
  107. static int msm_dtmf_detect_voice_rx_get(struct snd_kcontrol *kcontrol,
  108. struct snd_ctl_elem_value *ucontrol)
  109. {
  110. ucontrol->value.integer.value[0] = 0;
  111. return 0;
  112. }
  113. static int msm_dtmf_detect_volte_rx_put(struct snd_kcontrol *kcontrol,
  114. struct snd_ctl_elem_value *ucontrol)
  115. {
  116. int enable = ucontrol->value.integer.value[0];
  117. pr_debug("%s: enable=%d\n", __func__, enable);
  118. voc_enable_dtmf_rx_detection(voc_get_session_id(VOLTE_SESSION_NAME),
  119. enable);
  120. return 0;
  121. }
  122. static int msm_dtmf_detect_volte_rx_get(struct snd_kcontrol *kcontrol,
  123. struct snd_ctl_elem_value *ucontrol)
  124. {
  125. ucontrol->value.integer.value[0] = 0;
  126. return 0;
  127. }
  128. static struct snd_kcontrol_new msm_dtmf_controls[] = {
  129. SOC_SINGLE_MULTI_EXT("DTMF_Generate Rx Low High Duration Gain",
  130. SND_SOC_NOPM, 0, 5000, 0, 4,
  131. msm_dtmf_rx_generate_get,
  132. msm_dtmf_rx_generate_put),
  133. SOC_SINGLE_EXT("DTMF_Detect Rx Voice enable", SND_SOC_NOPM, 0, 1, 0,
  134. msm_dtmf_detect_voice_rx_get,
  135. msm_dtmf_detect_voice_rx_put),
  136. SOC_SINGLE_EXT("DTMF_Detect Rx VoLTE enable", SND_SOC_NOPM, 0, 1, 0,
  137. msm_dtmf_detect_volte_rx_get,
  138. msm_dtmf_detect_volte_rx_put),
  139. };
  140. static int msm_pcm_dtmf_probe(struct snd_soc_platform *platform)
  141. {
  142. snd_soc_add_platform_controls(platform, msm_dtmf_controls,
  143. ARRAY_SIZE(msm_dtmf_controls));
  144. return 0;
  145. }
  146. static void dtmf_rx_detected_cb(uint8_t *pkt,
  147. char *session,
  148. void *private_data)
  149. {
  150. struct dtmf_buf_node *buf_node = NULL;
  151. struct vss_istream_evt_rx_dtmf_detected *dtmf_det_pkt =
  152. (struct vss_istream_evt_rx_dtmf_detected *)pkt;
  153. struct dtmf_drv_info *prtd = private_data;
  154. unsigned long dsp_flags;
  155. pr_debug("%s\n", __func__);
  156. if (prtd->capture_substream == NULL)
  157. return;
  158. /* Copy dtmf detected info into out_queue. */
  159. spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
  160. /* discarding dtmf detection info till start is received */
  161. if (!list_empty(&prtd->free_out_queue) && prtd->capture_start) {
  162. buf_node = list_first_entry(&prtd->free_out_queue,
  163. struct dtmf_buf_node, list);
  164. list_del(&buf_node->list);
  165. buf_node->dtmf_det_pkt.high_freq = dtmf_det_pkt->high_freq;
  166. buf_node->dtmf_det_pkt.low_freq = dtmf_det_pkt->low_freq;
  167. if (session != NULL)
  168. strlcpy(buf_node->dtmf_det_pkt.session,
  169. session, MAX_SESSION_NAME_LEN);
  170. buf_node->dtmf_det_pkt.dir = DTMF_IN_RX;
  171. pr_debug("high =%d, low=%d session=%s\n",
  172. buf_node->dtmf_det_pkt.high_freq,
  173. buf_node->dtmf_det_pkt.low_freq,
  174. buf_node->dtmf_det_pkt.session);
  175. list_add_tail(&buf_node->list, &prtd->out_queue);
  176. prtd->pcm_capture_irq_pos += prtd->pcm_capture_count;
  177. spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
  178. snd_pcm_period_elapsed(prtd->capture_substream);
  179. } else {
  180. spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
  181. pr_err("DTMF detection pkt in Rx dropped, no free node available\n");
  182. }
  183. wake_up(&prtd->out_wait);
  184. }
  185. static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
  186. int channel, snd_pcm_uframes_t hwoff,
  187. void __user *buf, snd_pcm_uframes_t frames)
  188. {
  189. int ret = 0;
  190. int count = 0;
  191. struct dtmf_buf_node *buf_node = NULL;
  192. struct snd_pcm_runtime *runtime = substream->runtime;
  193. struct dtmf_drv_info *prtd = runtime->private_data;
  194. unsigned long dsp_flags;
  195. count = frames_to_bytes(runtime, frames);
  196. ret = wait_event_interruptible_timeout(prtd->out_wait,
  197. (!list_empty(&prtd->out_queue)),
  198. 1 * HZ);
  199. if (ret > 0) {
  200. if (count <= DTMF_PKT_SIZE) {
  201. spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
  202. buf_node = list_first_entry(&prtd->out_queue,
  203. struct dtmf_buf_node, list);
  204. list_del(&buf_node->list);
  205. spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
  206. ret = copy_to_user(buf,
  207. &buf_node->dtmf_det_pkt,
  208. count);
  209. if (ret) {
  210. pr_err("%s: Copy to user retuned %d\n",
  211. __func__, ret);
  212. ret = -EFAULT;
  213. }
  214. spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
  215. list_add_tail(&buf_node->list,
  216. &prtd->free_out_queue);
  217. spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
  218. } else {
  219. pr_err("%s: Read count %d > DTMF_PKT_SIZE\n",
  220. __func__, count);
  221. ret = -ENOMEM;
  222. }
  223. } else if (ret == 0) {
  224. pr_err("%s: No UL data available\n", __func__);
  225. ret = -ETIMEDOUT;
  226. } else {
  227. pr_err("%s: Read was interrupted\n", __func__);
  228. ret = -ERESTARTSYS;
  229. }
  230. return ret;
  231. }
  232. static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
  233. snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
  234. {
  235. int ret = 0;
  236. pr_debug("%s() DTMF\n", __func__);
  237. if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
  238. ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
  239. return ret;
  240. }
  241. static int msm_pcm_open(struct snd_pcm_substream *substream)
  242. {
  243. struct snd_pcm_runtime *runtime = substream->runtime;
  244. struct dtmf_drv_info *prtd = NULL;
  245. int ret = 0;
  246. if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
  247. prtd = kzalloc(sizeof(struct dtmf_drv_info), GFP_KERNEL);
  248. if (prtd == NULL) {
  249. pr_err("Failed to allocate memory for msm_audio\n");
  250. ret = -ENOMEM;
  251. goto done;
  252. }
  253. mutex_init(&prtd->lock);
  254. spin_lock_init(&prtd->dsp_lock);
  255. init_waitqueue_head(&prtd->out_wait);
  256. INIT_LIST_HEAD(&prtd->out_queue);
  257. INIT_LIST_HEAD(&prtd->free_out_queue);
  258. runtime->hw = msm_pcm_hardware;
  259. ret = snd_pcm_hw_constraint_integer(runtime,
  260. SNDRV_PCM_HW_PARAM_PERIODS);
  261. if (ret < 0)
  262. pr_info("snd_pcm_hw_constraint_integer failed\n");
  263. prtd->capture_substream = substream;
  264. prtd->capture_instance++;
  265. runtime->private_data = prtd;
  266. }
  267. done:
  268. return ret;
  269. }
  270. static int msm_pcm_close(struct snd_pcm_substream *substream)
  271. {
  272. int ret = 0;
  273. struct list_head *ptr = NULL;
  274. struct list_head *next = NULL;
  275. struct dtmf_buf_node *buf_node = NULL;
  276. struct snd_dma_buffer *c_dma_buf;
  277. struct snd_pcm_substream *c_substream;
  278. struct snd_pcm_runtime *runtime = substream->runtime;
  279. struct dtmf_drv_info *prtd = runtime->private_data;
  280. unsigned long dsp_flags;
  281. pr_debug("%s() DTMF\n", __func__);
  282. if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
  283. mutex_lock(&prtd->lock);
  284. wake_up(&prtd->out_wait);
  285. if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
  286. prtd->capture_instance--;
  287. if (!prtd->capture_instance) {
  288. if (prtd->state == DTMF_GEN_RX_STARTED) {
  289. prtd->state = DTMF_GEN_RX_STOPPED;
  290. voc_disable_dtmf_det_on_active_sessions();
  291. voc_register_dtmf_rx_detection_cb(NULL, NULL);
  292. }
  293. /* release all buffer */
  294. /* release out_queue and free_out_queue */
  295. pr_debug("release all buffer\n");
  296. c_substream = prtd->capture_substream;
  297. if (c_substream == NULL) {
  298. pr_debug("c_substream is NULL\n");
  299. mutex_unlock(&prtd->lock);
  300. return -EINVAL;
  301. }
  302. c_dma_buf = &c_substream->dma_buffer;
  303. if (c_dma_buf == NULL) {
  304. pr_debug("c_dma_buf is NULL.\n");
  305. mutex_unlock(&prtd->lock);
  306. return -EINVAL;
  307. }
  308. if (c_dma_buf->area != NULL) {
  309. spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
  310. list_for_each_safe(ptr, next,
  311. &prtd->out_queue) {
  312. buf_node = list_entry(ptr,
  313. struct dtmf_buf_node, list);
  314. list_del(&buf_node->list);
  315. }
  316. list_for_each_safe(ptr, next,
  317. &prtd->free_out_queue) {
  318. buf_node = list_entry(ptr,
  319. struct dtmf_buf_node, list);
  320. list_del(&buf_node->list);
  321. }
  322. spin_unlock_irqrestore(&prtd->dsp_lock,
  323. dsp_flags);
  324. dma_free_coherent(c_substream->pcm->card->dev,
  325. runtime->hw.buffer_bytes_max,
  326. c_dma_buf->area,
  327. c_dma_buf->addr);
  328. c_dma_buf->area = NULL;
  329. }
  330. }
  331. prtd->capture_substream = NULL;
  332. mutex_unlock(&prtd->lock);
  333. }
  334. return ret;
  335. }
  336. static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
  337. struct snd_pcm_hw_params *params)
  338. {
  339. struct snd_pcm_runtime *runtime = substream->runtime;
  340. struct dtmf_drv_info *prtd = runtime->private_data;
  341. struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
  342. struct dtmf_buf_node *buf_node = NULL;
  343. int i = 0, offset = 0;
  344. int ret = 0;
  345. pr_debug("%s: DTMF\n", __func__);
  346. if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
  347. mutex_lock(&prtd->lock);
  348. dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
  349. dma_buf->dev.dev = substream->pcm->card->dev;
  350. dma_buf->private_data = NULL;
  351. dma_buf->area = dma_alloc_coherent(substream->pcm->card->dev,
  352. runtime->hw.buffer_bytes_max,
  353. &dma_buf->addr, GFP_KERNEL);
  354. if (!dma_buf->area) {
  355. pr_err("%s:MSM DTMF dma_alloc failed\n", __func__);
  356. mutex_unlock(&prtd->lock);
  357. return -ENOMEM;
  358. }
  359. dma_buf->bytes = runtime->hw.buffer_bytes_max;
  360. memset(dma_buf->area, 0, runtime->hw.buffer_bytes_max);
  361. for (i = 0; i < DTMF_MAX_Q_LEN; i++) {
  362. pr_debug("node =%d\n", i);
  363. buf_node = (void *) dma_buf->area + offset;
  364. list_add_tail(&buf_node->list,
  365. &prtd->free_out_queue);
  366. offset = offset + sizeof(struct dtmf_buf_node);
  367. }
  368. snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
  369. mutex_unlock(&prtd->lock);
  370. }
  371. return ret;
  372. }
  373. static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
  374. {
  375. struct snd_pcm_runtime *runtime = substream->runtime;
  376. struct dtmf_drv_info *prtd = runtime->private_data;
  377. pr_debug("%s: DTMF\n", __func__);
  378. prtd->pcm_capture_size = snd_pcm_lib_buffer_bytes(substream);
  379. prtd->pcm_capture_count = snd_pcm_lib_period_bytes(substream);
  380. prtd->pcm_capture_irq_pos = 0;
  381. prtd->pcm_capture_buf_pos = 0;
  382. return 0;
  383. }
  384. static int msm_pcm_prepare(struct snd_pcm_substream *substream)
  385. {
  386. struct snd_pcm_runtime *runtime = substream->runtime;
  387. struct dtmf_drv_info *prtd = runtime->private_data;
  388. pr_debug("%s: DTMF\n", __func__);
  389. if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
  390. mutex_lock(&prtd->lock);
  391. msm_pcm_capture_prepare(substream);
  392. if (runtime->format != FORMAT_S16_LE) {
  393. pr_err("format:%u doesnt match %d\n",
  394. (uint32_t)runtime->format, FORMAT_S16_LE);
  395. mutex_unlock(&prtd->lock);
  396. return -EINVAL;
  397. }
  398. if (prtd->capture_instance &&
  399. (prtd->state != DTMF_GEN_RX_STARTED)) {
  400. voc_register_dtmf_rx_detection_cb(dtmf_rx_detected_cb,
  401. prtd);
  402. prtd->state = DTMF_GEN_RX_STARTED;
  403. }
  404. mutex_unlock(&prtd->lock);
  405. }
  406. return 0;
  407. }
  408. static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
  409. {
  410. int ret = 0;
  411. struct snd_pcm_runtime *runtime = substream->runtime;
  412. struct dtmf_drv_info *prtd = runtime->private_data;
  413. switch (cmd) {
  414. case SNDRV_PCM_TRIGGER_START:
  415. case SNDRV_PCM_TRIGGER_RESUME:
  416. pr_debug("%s: Trigger start\n", __func__);
  417. if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
  418. prtd->capture_start = 1;
  419. break;
  420. case SNDRV_PCM_TRIGGER_STOP:
  421. pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
  422. if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
  423. prtd->capture_start = 0;
  424. break;
  425. default:
  426. ret = -EINVAL;
  427. break;
  428. }
  429. return ret;
  430. }
  431. static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
  432. {
  433. snd_pcm_uframes_t ret = 0;
  434. struct snd_pcm_runtime *runtime = substream->runtime;
  435. struct dtmf_drv_info *prtd = runtime->private_data;
  436. if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
  437. if (prtd->pcm_capture_irq_pos >= prtd->pcm_capture_size)
  438. prtd->pcm_capture_irq_pos = 0;
  439. ret = bytes_to_frames(runtime, (prtd->pcm_capture_irq_pos));
  440. }
  441. return ret;
  442. }
  443. static struct snd_pcm_ops msm_pcm_ops = {
  444. .open = msm_pcm_open,
  445. .copy = msm_pcm_copy,
  446. .hw_params = msm_pcm_hw_params,
  447. .close = msm_pcm_close,
  448. .prepare = msm_pcm_prepare,
  449. .trigger = msm_pcm_trigger,
  450. .pointer = msm_pcm_pointer,
  451. };
  452. static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
  453. {
  454. struct snd_card *card = rtd->card->snd_card;
  455. int ret = 0;
  456. if (!card->dev->coherent_dma_mask)
  457. card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
  458. return ret;
  459. }
  460. static struct snd_soc_platform_driver msm_soc_platform = {
  461. .ops = &msm_pcm_ops,
  462. .pcm_new = msm_asoc_pcm_new,
  463. .probe = msm_pcm_dtmf_probe,
  464. };
  465. static __devinit int msm_pcm_probe(struct platform_device *pdev)
  466. {
  467. if (pdev->dev.of_node)
  468. dev_set_name(&pdev->dev, "%s", "msm-pcm-dtmf");
  469. pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
  470. return snd_soc_register_platform(&pdev->dev,
  471. &msm_soc_platform);
  472. }
  473. static int msm_pcm_remove(struct platform_device *pdev)
  474. {
  475. snd_soc_unregister_platform(&pdev->dev);
  476. return 0;
  477. }
  478. static const struct of_device_id msm_pcm_dtmf_dt_match[] = {
  479. {.compatible = "qcom,msm-pcm-dtmf"},
  480. {}
  481. };
  482. MODULE_DEVICE_TABLE(of, msm_pcm_dtmf_dt_match);
  483. static struct platform_driver msm_pcm_driver = {
  484. .driver = {
  485. .name = "msm-pcm-dtmf",
  486. .owner = THIS_MODULE,
  487. .of_match_table = msm_pcm_dtmf_dt_match,
  488. },
  489. .probe = msm_pcm_probe,
  490. .remove = __devexit_p(msm_pcm_remove),
  491. };
  492. static int __init msm_soc_platform_init(void)
  493. {
  494. return platform_driver_register(&msm_pcm_driver);
  495. }
  496. module_init(msm_soc_platform_init);
  497. static void __exit msm_soc_platform_exit(void)
  498. {
  499. platform_driver_unregister(&msm_pcm_driver);
  500. }
  501. module_exit(msm_soc_platform_exit);
  502. MODULE_DESCRIPTION("DTMF platform driver");
  503. MODULE_LICENSE("GPL v2");