voice_mhi.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2019, The Linux Foundation. All rights reserved.
  4. */
  5. #include <linux/dma-mapping.h>
  6. #include <linux/platform_device.h>
  7. #include <linux/of.h>
  8. #include <linux/of_address.h>
  9. #include <linux/list.h>
  10. #include <linux/slab.h>
  11. #include <linux/module.h>
  12. #include <linux/mhi.h>
  13. #include <linux/mutex.h>
  14. #include <dsp/voice_mhi.h>
  15. #include <dsp/msm_audio_ion.h>
  16. #include <dsp/audio_notifier.h>
  17. #include <dsp/q6core.h>
  18. #include <dsp/audio_notifier.h>
  19. #include <ipc/apr.h>
  20. #include "adsp_err.h"
  21. #define VSS_IPKTEXG_CMD_SET_MAILBOX_MEMORY_CONFIG 0x0001333B
  22. #define VOICE_MHI_STATE_SET(a, b) ((a) |= (1UL<<(b)))
  23. #define VOICE_MHI_STATE_RESET(a, b) ((a) &= ~(1UL<<(b)))
  24. #define VOICE_MHI_STATE_CHECK(a, b) (1UL & (a >> b))
  25. #define CMD_STATUS_SUCCESS 0
  26. #define CMD_STATUS_FAIL 1
  27. #define TIMEOUT_MS 500
  28. #define PORT_NUM 0x01
  29. #define PORT_MASK 0x03
  30. #define CONVERT_PORT_APR(x, y) (x << 8 | y)
  31. enum voice_states {
  32. VOICE_MHI_INIT = 0,
  33. VOICE_MHI_PROBED = VOICE_MHI_INIT,
  34. VOICE_MHI_ADSP_UP,
  35. VOICE_MHI_SDX_UP,
  36. VOICE_MHI_INCALL
  37. };
  38. struct voice_mhi_addr {
  39. dma_addr_t base;
  40. uint32_t size;
  41. };
  42. struct voice_mhi_dev_info {
  43. struct platform_device *pdev;
  44. struct voice_mhi_addr phys_addr;
  45. struct voice_mhi_addr iova_pcie;
  46. struct voice_mhi_addr iova_adsp;
  47. };
  48. struct voice_mhi {
  49. struct voice_mhi_dev_info dev_info;
  50. struct mhi_device *mhi_dev;
  51. uint32_t vote_count;
  52. struct mutex mutex;
  53. enum voice_states voice_mhi_state;
  54. bool vote_enable;
  55. bool pcie_enabled;
  56. void *apr_mvm_handle;
  57. struct work_struct voice_mhi_work_pcie;
  58. struct work_struct voice_mhi_work_adsp;
  59. wait_queue_head_t voice_mhi_wait;
  60. u32 mvm_state;
  61. u32 async_err;
  62. };
  63. struct vss_ipktexg_cmd_set_mailbox_memory_config_t {
  64. struct apr_hdr hdr;
  65. uint64_t mailbox_mem_address_adsp;
  66. /*
  67. * IOVA of mailbox memory for ADSP access
  68. */
  69. uint64_t mailbox_mem_address_pcie;
  70. /*
  71. * IOVA of mailbox memory for PCIe access
  72. */
  73. uint32_t mem_size;
  74. /*
  75. * Size of mailbox memory allocated
  76. */
  77. } __packed;
  78. static struct voice_mhi voice_mhi_lcl;
  79. static int voice_mhi_pcie_up_callback(struct mhi_device *,
  80. const struct mhi_device_id *);
  81. static void voice_mhi_pcie_down_callback(struct mhi_device *);
  82. static void voice_mhi_pcie_status_callback(struct mhi_device *, enum MHI_CB);
  83. static int32_t voice_mhi_apr_callback(struct apr_client_data *data, void *priv);
  84. static int voice_mhi_notifier_service_cb(struct notifier_block *nb,
  85. unsigned long opcode, void *ptr);
  86. static int voice_mhi_apr_register(void);
  87. static struct notifier_block voice_mhi_service_nb = {
  88. .notifier_call = voice_mhi_notifier_service_cb,
  89. .priority = -INT_MAX,
  90. };
  91. static const struct mhi_device_id voice_mhi_match_table[] = {
  92. { .chan = "AUDIO_VOICE_0", .driver_data = 0 },
  93. {},
  94. };
  95. static struct mhi_driver voice_mhi_driver = {
  96. .id_table = voice_mhi_match_table,
  97. .probe = voice_mhi_pcie_up_callback,
  98. .remove = voice_mhi_pcie_down_callback,
  99. .status_cb = voice_mhi_pcie_status_callback,
  100. .driver = {
  101. .name = "voice_mhi_audio",
  102. .owner = THIS_MODULE,
  103. },
  104. };
  105. static int voice_mhi_notifier_service_cb(struct notifier_block *nb,
  106. unsigned long opcode, void *ptr)
  107. {
  108. pr_debug("%s: opcode 0x%lx\n", __func__, opcode);
  109. switch (opcode) {
  110. case AUDIO_NOTIFIER_SERVICE_DOWN:
  111. if (voice_mhi_lcl.apr_mvm_handle) {
  112. apr_reset(voice_mhi_lcl.apr_mvm_handle);
  113. voice_mhi_lcl.apr_mvm_handle = NULL;
  114. VOICE_MHI_STATE_RESET(voice_mhi_lcl.voice_mhi_state,
  115. VOICE_MHI_ADSP_UP);
  116. }
  117. break;
  118. case AUDIO_NOTIFIER_SERVICE_UP:
  119. if (!VOICE_MHI_STATE_CHECK(voice_mhi_lcl.voice_mhi_state,
  120. VOICE_MHI_ADSP_UP)) {
  121. VOICE_MHI_STATE_SET(voice_mhi_lcl.voice_mhi_state,
  122. VOICE_MHI_ADSP_UP);
  123. schedule_work(&voice_mhi_lcl.voice_mhi_work_adsp);
  124. }
  125. break;
  126. default:
  127. break;
  128. }
  129. return NOTIFY_OK;
  130. }
  131. static int32_t voice_mhi_apr_callback(struct apr_client_data *data, void *priv)
  132. {
  133. uint32_t *ptr1;
  134. if (data == NULL) {
  135. pr_err("%s: data is NULL\n", __func__);
  136. return -EINVAL;
  137. }
  138. pr_debug("%s: Payload Length = %d, opcode=%x\n", __func__,
  139. data->payload_size, data->opcode);
  140. switch (data->opcode) {
  141. case APR_BASIC_RSP_RESULT:
  142. if (data->payload_size < 2 * sizeof(uint32_t)) {
  143. pr_err("%s: APR_BASIC_RSP_RESULT payload less than expected\n",
  144. __func__);
  145. return 0;
  146. }
  147. ptr1 = data->payload;
  148. switch (ptr1[0]) {
  149. case VSS_IPKTEXG_CMD_SET_MAILBOX_MEMORY_CONFIG:
  150. pr_debug("%s: cmd VSS_IPKTEXG_CMD_SET_MAILBOX_MEMORY_CONFIG\n",
  151. __func__);
  152. voice_mhi_lcl.mvm_state = CMD_STATUS_SUCCESS;
  153. voice_mhi_lcl.async_err = ptr1[1];
  154. wake_up(&voice_mhi_lcl.voice_mhi_wait);
  155. break;
  156. default:
  157. pr_err("%s: Invalid cmd response 0x%x 0x%x\n", __func__,
  158. ptr1[0], ptr1[1]);
  159. break;
  160. }
  161. break;
  162. case APR_RSP_ACCEPTED:
  163. if (data->payload_size < sizeof(uint32_t)) {
  164. pr_err("%s: APR_RSP_ACCEPTED payload less than expected\n",
  165. __func__);
  166. return 0;
  167. }
  168. ptr1 = data->payload;
  169. if (ptr1[0])
  170. pr_debug("%s: APR_RSP_ACCEPTED for 0x%x:\n",
  171. __func__, ptr1[0]);
  172. break;
  173. case RESET_EVENTS:
  174. /* Should we handle here or audio notifier down? */
  175. if (voice_mhi_lcl.apr_mvm_handle) {
  176. apr_reset(voice_mhi_lcl.apr_mvm_handle);
  177. voice_mhi_lcl.apr_mvm_handle = NULL;
  178. VOICE_MHI_STATE_RESET(voice_mhi_lcl.voice_mhi_state,
  179. VOICE_MHI_ADSP_UP);
  180. }
  181. break;
  182. default:
  183. pr_err("%s: Invalid opcode %d\n", __func__,
  184. data->opcode);
  185. break;
  186. }
  187. return 0;
  188. }
  189. /**
  190. * voice_mhi_start -
  191. * Start vote for MHI/PCIe clock
  192. *
  193. * Returns 0 on success or error on failure
  194. */
  195. int voice_mhi_start(void)
  196. {
  197. int ret = 0;
  198. mutex_lock(&voice_mhi_lcl.mutex);
  199. if (voice_mhi_lcl.pcie_enabled) {
  200. if (!voice_mhi_lcl.mhi_dev) {
  201. pr_err("%s: NULL device found\n", __func__);
  202. ret = -EINVAL;
  203. goto done;
  204. }
  205. if (voice_mhi_lcl.vote_count == 0) {
  206. ret = mhi_device_get_sync(voice_mhi_lcl.mhi_dev);
  207. if (ret) {
  208. pr_err("%s: mhi_device_get_sync failed\n",
  209. __func__);
  210. ret = -EINVAL;
  211. goto done;
  212. }
  213. pr_debug("%s: mhi_device_get_sync success\n", __func__);
  214. } else {
  215. /* For DSDA, no additional voting is needed */
  216. pr_debug("%s: mhi is already voted\n", __func__);
  217. }
  218. voice_mhi_lcl.vote_count++;
  219. } else {
  220. /* PCIe not supported - return success*/
  221. goto done;
  222. }
  223. done:
  224. mutex_unlock(&voice_mhi_lcl.mutex);
  225. return ret;
  226. }
  227. EXPORT_SYMBOL(voice_mhi_start);
  228. /**
  229. * voice_mhi_end -
  230. * End vote for MHI/PCIe clock
  231. *
  232. * Returns 0 on success or error on failure
  233. */
  234. int voice_mhi_end(void)
  235. {
  236. mutex_lock(&voice_mhi_lcl.mutex);
  237. if (voice_mhi_lcl.pcie_enabled) {
  238. if (!voice_mhi_lcl.mhi_dev || voice_mhi_lcl.vote_count == 0) {
  239. pr_err("%s: NULL device found\n", __func__);
  240. mutex_unlock(&voice_mhi_lcl.mutex);
  241. return -EINVAL;
  242. }
  243. if (voice_mhi_lcl.vote_count == 1)
  244. mhi_device_put(voice_mhi_lcl.mhi_dev);
  245. voice_mhi_lcl.vote_count--;
  246. }
  247. mutex_unlock(&voice_mhi_lcl.mutex);
  248. return 0;
  249. }
  250. EXPORT_SYMBOL(voice_mhi_end);
  251. static int voice_mhi_set_mailbox_memory_config(void)
  252. {
  253. struct vss_ipktexg_cmd_set_mailbox_memory_config_t mb_memory_config;
  254. int ret = 0;
  255. void *apr_mvm;
  256. if (!voice_mhi_lcl.apr_mvm_handle) {
  257. pr_err("%s: APR handle is NULL\n", __func__);
  258. return -EINVAL;
  259. }
  260. memset(&mb_memory_config, 0, sizeof(mb_memory_config));
  261. mb_memory_config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
  262. APR_HDR_LEN(APR_HDR_SIZE),
  263. APR_PKT_VER);
  264. mb_memory_config.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
  265. sizeof(mb_memory_config) - APR_HDR_SIZE);
  266. pr_debug("%s: pkt size = %d\n", __func__,
  267. mb_memory_config.hdr.pkt_size);
  268. mutex_lock(&voice_mhi_lcl.mutex);
  269. apr_mvm = voice_mhi_lcl.apr_mvm_handle;
  270. /*
  271. * Handle can be NULL as it is not tied to any session
  272. */
  273. mb_memory_config.hdr.src_port = CONVERT_PORT_APR(PORT_NUM, PORT_MASK);
  274. mb_memory_config.hdr.dest_port = 0;
  275. mb_memory_config.hdr.token = 0;
  276. mb_memory_config.hdr.opcode = VSS_IPKTEXG_CMD_SET_MAILBOX_MEMORY_CONFIG;
  277. mb_memory_config.mailbox_mem_address_pcie =
  278. voice_mhi_lcl.dev_info.iova_pcie.base;
  279. mb_memory_config.mailbox_mem_address_adsp =
  280. voice_mhi_lcl.dev_info.iova_adsp.base;
  281. mb_memory_config.mem_size = voice_mhi_lcl.dev_info.iova_adsp.size;
  282. voice_mhi_lcl.mvm_state = CMD_STATUS_FAIL;
  283. voice_mhi_lcl.async_err = 0;
  284. ret = apr_send_pkt(apr_mvm, (uint32_t *) &mb_memory_config);
  285. if (ret < 0) {
  286. pr_err("%s: Set mailbox memory config failed ret = %d\n",
  287. __func__, ret);
  288. goto unlock;
  289. }
  290. ret = wait_event_timeout(voice_mhi_lcl.voice_mhi_wait,
  291. (voice_mhi_lcl.mvm_state ==
  292. CMD_STATUS_SUCCESS),
  293. msecs_to_jiffies(TIMEOUT_MS));
  294. if (!ret) {
  295. pr_err("%s: wait_event timeout\n", __func__);
  296. ret = -ETIME;
  297. goto unlock;
  298. }
  299. if (voice_mhi_lcl.async_err > 0) {
  300. pr_err("%s: DSP returned error[%d]\n",
  301. __func__, voice_mhi_lcl.async_err);
  302. ret = voice_mhi_lcl.async_err;
  303. goto unlock;
  304. }
  305. ret = 0;
  306. unlock:
  307. mutex_unlock(&voice_mhi_lcl.mutex);
  308. return ret;
  309. }
  310. static void voice_mhi_map_pcie_and_send(struct work_struct *work)
  311. {
  312. dma_addr_t iova, phys_addr;
  313. uint32_t mem_size;
  314. struct device *md;
  315. mutex_lock(&voice_mhi_lcl.mutex);
  316. if (voice_mhi_lcl.mhi_dev) {
  317. md = &voice_mhi_lcl.mhi_dev->dev;
  318. } else {
  319. pr_err("%s: MHI device handle is NULL\n", __func__);
  320. goto err;
  321. }
  322. phys_addr = voice_mhi_lcl.dev_info.phys_addr.base;
  323. mem_size = voice_mhi_lcl.dev_info.iova_pcie.size;
  324. if (md) {
  325. iova = dma_map_resource(md->parent, phys_addr, mem_size,
  326. DMA_BIDIRECTIONAL, 0);
  327. if (dma_mapping_error(md->parent, iova)) {
  328. pr_err("%s: dma_mapping_error\n", __func__);
  329. goto err;
  330. }
  331. pr_debug("%s: dma_mapping_success iova:0x%lx\n",
  332. __func__, (unsigned long)iova);
  333. voice_mhi_lcl.dev_info.iova_pcie.base = iova;
  334. if (q6core_is_adsp_ready()) {
  335. if (VOICE_MHI_STATE_CHECK(voice_mhi_lcl.voice_mhi_state,
  336. VOICE_MHI_SDX_UP)) {
  337. mutex_unlock(&voice_mhi_lcl.mutex);
  338. voice_mhi_set_mailbox_memory_config();
  339. return;
  340. }
  341. }
  342. }
  343. err:
  344. mutex_unlock(&voice_mhi_lcl.mutex);
  345. }
  346. static void voice_mhi_register_apr_and_send(struct work_struct *work)
  347. {
  348. int ret = 0;
  349. ret = voice_mhi_apr_register();
  350. if (ret) {
  351. pr_err("%s: APR registration failed %d\n", __func__, ret);
  352. return;
  353. }
  354. mutex_lock(&voice_mhi_lcl.mutex);
  355. if (q6core_is_adsp_ready()) {
  356. if (VOICE_MHI_STATE_CHECK(voice_mhi_lcl.voice_mhi_state,
  357. VOICE_MHI_SDX_UP)) {
  358. mutex_unlock(&voice_mhi_lcl.mutex);
  359. voice_mhi_set_mailbox_memory_config();
  360. return;
  361. }
  362. }
  363. mutex_unlock(&voice_mhi_lcl.mutex);
  364. }
  365. static int voice_mhi_pcie_up_callback(struct mhi_device *voice_mhi_dev,
  366. const struct mhi_device_id *id)
  367. {
  368. if ((!voice_mhi_dev) || (id != &voice_mhi_match_table[0])) {
  369. pr_err("%s: Invalid device or table received\n", __func__);
  370. return -EINVAL;
  371. }
  372. pr_debug("%s: MHI PCIe UP callback\n", __func__);
  373. mutex_lock(&voice_mhi_lcl.mutex);
  374. voice_mhi_lcl.mhi_dev = voice_mhi_dev;
  375. VOICE_MHI_STATE_SET(voice_mhi_lcl.voice_mhi_state, VOICE_MHI_SDX_UP);
  376. mutex_unlock(&voice_mhi_lcl.mutex);
  377. schedule_work(&voice_mhi_lcl.voice_mhi_work_pcie);
  378. return 0;
  379. }
  380. static void voice_mhi_pcie_down_callback(struct mhi_device *voice_mhi_dev)
  381. {
  382. dma_addr_t iova;
  383. struct device *md;
  384. mutex_lock(&voice_mhi_lcl.mutex);
  385. if (voice_mhi_lcl.mhi_dev)
  386. md = &voice_mhi_lcl.mhi_dev->dev;
  387. VOICE_MHI_STATE_RESET(voice_mhi_lcl.voice_mhi_state, VOICE_MHI_SDX_UP);
  388. iova = voice_mhi_lcl.dev_info.iova_pcie.base;
  389. if (md)
  390. dma_unmap_resource(md->parent, iova, PAGE_SIZE,
  391. DMA_BIDIRECTIONAL, 0);
  392. voice_mhi_lcl.mhi_dev = NULL;
  393. voice_mhi_lcl.vote_count = 0;
  394. mutex_unlock(&voice_mhi_lcl.mutex);
  395. }
  396. static void voice_mhi_pcie_status_callback(struct mhi_device *voice_mhi_dev,
  397. enum MHI_CB mhi_cb)
  398. {
  399. }
  400. static int voice_mhi_apr_register(void)
  401. {
  402. int ret = 0;
  403. mutex_lock(&voice_mhi_lcl.mutex);
  404. voice_mhi_lcl.apr_mvm_handle = apr_register("ADSP", "MVM",
  405. (apr_fn)voice_mhi_apr_callback,
  406. CONVERT_PORT_APR(PORT_NUM,
  407. PORT_MASK),
  408. &voice_mhi_lcl);
  409. if (voice_mhi_lcl.apr_mvm_handle == NULL) {
  410. pr_err("%s: error in APR register\n", __func__);
  411. ret = -ENODEV;
  412. }
  413. mutex_unlock(&voice_mhi_lcl.mutex);
  414. return ret;
  415. }
  416. static int voice_mhi_probe(struct platform_device *pdev)
  417. {
  418. int ret = 0;
  419. struct device_node *node;
  420. uint32_t mem_size = 0;
  421. void *ptr;
  422. dma_addr_t phys_addr, iova;
  423. const __be32 *cell;
  424. pr_debug("%s:\n", __func__);
  425. INIT_WORK(&voice_mhi_lcl.voice_mhi_work_pcie,
  426. voice_mhi_map_pcie_and_send);
  427. INIT_WORK(&voice_mhi_lcl.voice_mhi_work_adsp,
  428. voice_mhi_register_apr_and_send);
  429. init_waitqueue_head(&voice_mhi_lcl.voice_mhi_wait);
  430. node = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
  431. if (node) {
  432. cell = of_get_property(node, "size", NULL);
  433. if (cell)
  434. mem_size = of_read_number(cell, 2);
  435. else {
  436. pr_err("%s: cell not found\n", __func__);
  437. ret = -EINVAL;
  438. goto done;
  439. }
  440. } else {
  441. pr_err("%s: Node read failed\n", __func__);
  442. ret = -EINVAL;
  443. goto done;
  444. }
  445. pr_debug("%s: mem_size = %d\n", __func__, mem_size);
  446. if (mem_size) {
  447. ptr = dma_alloc_attrs(&pdev->dev, mem_size, &phys_addr,
  448. GFP_KERNEL, DMA_ATTR_NO_KERNEL_MAPPING);
  449. if (IS_ERR_OR_NULL(ptr)) {
  450. pr_err("%s: Memory alloc failed\n", __func__);
  451. ret = -ENOMEM;
  452. goto done;
  453. } else {
  454. pr_debug("%s: Memory alloc success phys_addr:0x%lx\n",
  455. __func__, (unsigned long)phys_addr);
  456. }
  457. ret = msm_audio_ion_dma_map(&phys_addr, &iova, mem_size,
  458. DMA_BIDIRECTIONAL);
  459. if (ret) {
  460. pr_err("%s: dma mapping failed %d\n", __func__, ret);
  461. goto err_free;
  462. }
  463. pr_debug("%s: dma_mapping_success iova:0x%lx\n",
  464. __func__, (unsigned long)iova);
  465. voice_mhi_lcl.dev_info.phys_addr.base = phys_addr;
  466. voice_mhi_lcl.dev_info.iova_adsp.base = iova;
  467. voice_mhi_lcl.dev_info.iova_adsp.size = mem_size;
  468. voice_mhi_lcl.dev_info.iova_pcie.size = mem_size;
  469. VOICE_MHI_STATE_SET(voice_mhi_lcl.voice_mhi_state,
  470. VOICE_MHI_ADSP_UP);
  471. ret = voice_mhi_apr_register();
  472. /* If fails register during audio notifier UP event */
  473. if (ret)
  474. pr_err("%s: APR register failed %d\n", __func__, ret);
  475. ret = mhi_driver_register(&voice_mhi_driver);
  476. if (ret) {
  477. pr_err("%s: mhi register failed %d\n", __func__, ret);
  478. goto done;
  479. }
  480. ret = audio_notifier_register("voice_mhi",
  481. AUDIO_NOTIFIER_ADSP_DOMAIN,
  482. &voice_mhi_service_nb);
  483. if (ret < 0)
  484. pr_err("%s: Audio notifier register failed ret = %d\n",
  485. __func__, ret);
  486. mutex_lock(&voice_mhi_lcl.mutex);
  487. voice_mhi_lcl.dev_info.pdev = pdev;
  488. voice_mhi_lcl.pcie_enabled = true;
  489. VOICE_MHI_STATE_SET(voice_mhi_lcl.voice_mhi_state,
  490. VOICE_MHI_PROBED);
  491. mutex_unlock(&voice_mhi_lcl.mutex);
  492. } else {
  493. pr_err("%s: Memory size can't be zero\n", __func__);
  494. ret = -ENOMEM;
  495. goto done;
  496. }
  497. done:
  498. return ret;
  499. err_free:
  500. dma_free_attrs(&pdev->dev, mem_size, ptr, phys_addr,
  501. DMA_ATTR_NO_KERNEL_MAPPING);
  502. return ret;
  503. }
  504. static int voice_mhi_remove(struct platform_device *pdev)
  505. {
  506. if (voice_mhi_lcl.apr_mvm_handle)
  507. apr_reset(voice_mhi_lcl.apr_mvm_handle);
  508. mhi_driver_unregister(&voice_mhi_driver);
  509. memset(&voice_mhi_lcl, 0, sizeof(voice_mhi_lcl));
  510. return 0;
  511. }
  512. static const struct of_device_id voice_mhi_of_match[] = {
  513. { .compatible = "qcom,voice-mhi-audio", },
  514. {},
  515. };
  516. static struct platform_driver voice_mhi_platform_driver = {
  517. .probe = voice_mhi_probe,
  518. .remove = voice_mhi_remove,
  519. .driver = {
  520. .name = "voice_mhi_audio",
  521. .owner = THIS_MODULE,
  522. .of_match_table = voice_mhi_of_match,
  523. }
  524. };
  525. int __init voice_mhi_init(void)
  526. {
  527. int ret = 0;
  528. memset(&voice_mhi_lcl, 0, sizeof(voice_mhi_lcl));
  529. mutex_init(&voice_mhi_lcl.mutex);
  530. /* Add remaining init here */
  531. voice_mhi_lcl.pcie_enabled = false;
  532. voice_mhi_lcl.voice_mhi_state = VOICE_MHI_INIT;
  533. voice_mhi_lcl.vote_count = 0;
  534. voice_mhi_lcl.apr_mvm_handle = NULL;
  535. ret = platform_driver_register(&voice_mhi_platform_driver);
  536. return ret;
  537. }
  538. void __exit voice_mhi_exit(void)
  539. {
  540. mutex_destroy(&voice_mhi_lcl.mutex);
  541. platform_driver_unregister(&voice_mhi_platform_driver);
  542. }
  543. MODULE_DESCRIPTION("Voice MHI module");
  544. MODULE_LICENSE("GPL v2");