blob: df7760a16356be49221284204c31afcfecd5ca10 [file] [log] [blame]
Fred Ohde9438a2013-04-04 11:29:12 -07001/*
Gopikrishnaiah Anandan11e633b2014-01-20 16:01:24 -08002 * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
Fred Ohde9438a2013-04-04 11:29:12 -07003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/init.h>
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/err.h>
18#include <linux/delay.h>
19#include <linux/platform_device.h>
20#include <mach/subsystem_restart.h>
21#include <mach/qdsp6v2/apr.h>
22#include <linux/of_device.h>
23#include <linux/msm_audio_ion.h>
24
Fred Ohc274a7a2013-03-25 13:59:17 -070025#include <linux/iommu.h>
26#include <mach/iommu_domains.h>
27
Fred Ohde9438a2013-04-04 11:29:12 -070028struct msm_audio_ion_private {
29 bool smmu_enabled;
Fred Ohc274a7a2013-03-25 13:59:17 -070030 bool audioheap_enabled;
31 struct iommu_group *group;
32 u32 domain_id;
33 struct iommu_domain *domain;
Fred Ohde9438a2013-04-04 11:29:12 -070034};
35
36static struct msm_audio_ion_private msm_audio_ion_data = {0,};
37
38
39static int msm_audio_ion_get_phys(struct ion_client *client,
40 struct ion_handle *handle,
41 ion_phys_addr_t *addr, size_t *len);
42
43
44
45int msm_audio_ion_alloc(const char *name, struct ion_client **client,
46 struct ion_handle **handle, size_t bufsz,
47 ion_phys_addr_t *paddr, size_t *pa_len, void **vaddr)
48{
49 int rc = 0;
50
Fred Oh7d0ed032013-06-21 10:34:12 -070051 if ((msm_audio_ion_data.smmu_enabled == true) &&
52 (msm_audio_ion_data.group == NULL)) {
53 pr_debug("%s:probe is not done, deferred\n", __func__);
54 return -EPROBE_DEFER;
55 }
Gopikrishnaiah Anandan6eb6d182013-08-16 17:34:21 -040056 if (!name || !client || !handle || !paddr || !vaddr
57 || !bufsz || !pa_len) {
58 pr_err("%s: Invalid params\n", __func__);
59 return -EINVAL;
60 }
Fred Ohde9438a2013-04-04 11:29:12 -070061 *client = msm_audio_ion_client_create(UINT_MAX, name);
62 if (IS_ERR_OR_NULL((void *)(*client))) {
63 pr_err("%s: ION create client for AUDIO failed\n", __func__);
64 goto err;
65 }
66
Fred Ohc274a7a2013-03-25 13:59:17 -070067 *handle = ion_alloc(*client, bufsz, SZ_4K,
68 ION_HEAP(ION_AUDIO_HEAP_ID), 0);
Fred Ohde9438a2013-04-04 11:29:12 -070069 if (IS_ERR_OR_NULL((void *) (*handle))) {
Fred Ohc274a7a2013-03-25 13:59:17 -070070 pr_debug("system heap is used");
71 msm_audio_ion_data.audioheap_enabled = 0;
72 *handle = ion_alloc(*client, bufsz, SZ_4K,
73 ION_HEAP(ION_SYSTEM_HEAP_ID), 0);
74
75 } else {
76 pr_debug("audio heap is used");
77 msm_audio_ion_data.audioheap_enabled = 1;
78 }
79
80 if (IS_ERR_OR_NULL((void *) (*handle))) {
81 pr_err("%s: ION memory allocation for AUDIO failed rc=%d, smmu_enabled=%d\n",
82 __func__, rc, msm_audio_ion_data.smmu_enabled);
Fred Ohde9438a2013-04-04 11:29:12 -070083 goto err_ion_client;
84 }
85
86 rc = msm_audio_ion_get_phys(*client, *handle, paddr, pa_len);
87 if (rc) {
88 pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
89 __func__, rc);
90 goto err_ion_handle;
91 }
92
Fred Ohde9438a2013-04-04 11:29:12 -070093 *vaddr = ion_map_kernel(*client, *handle);
94 if (IS_ERR_OR_NULL((void *)*vaddr)) {
95 pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
96 goto err_ion_handle;
97 }
Fred Ohc274a7a2013-03-25 13:59:17 -070098 pr_debug("%s: mapped address = %p, size=%d\n", __func__, *vaddr, bufsz);
Fred Ohde9438a2013-04-04 11:29:12 -070099
Fred Ohc274a7a2013-03-25 13:59:17 -0700100 if (bufsz != 0) {
101 pr_debug("%s: memset to 0 %p %d\n", __func__, *vaddr, bufsz);
Fred Ohde9438a2013-04-04 11:29:12 -0700102 memset((void *)*vaddr, 0, bufsz);
Fred Ohc274a7a2013-03-25 13:59:17 -0700103 }
Fred Ohde9438a2013-04-04 11:29:12 -0700104
105 return 0;
106
107err_ion_handle:
108 ion_free(*client, *handle);
109err_ion_client:
110 msm_audio_ion_client_destroy(*client);
Gopikrishnaiah Anandan6eb6d182013-08-16 17:34:21 -0400111 *handle = NULL;
Fred Oh7d0ed032013-06-21 10:34:12 -0700112 *client = NULL;
Fred Ohde9438a2013-04-04 11:29:12 -0700113err:
114 return -EINVAL;
Fred Ohde9438a2013-04-04 11:29:12 -0700115}
116
117int msm_audio_ion_import(const char *name, struct ion_client **client,
118 struct ion_handle **handle, int fd,
119 unsigned long *ionflag, size_t bufsz,
120 ion_phys_addr_t *paddr, size_t *pa_len, void **vaddr)
121{
122 int rc = 0;
Gopikrishnaiah Anandan6eb6d182013-08-16 17:34:21 -0400123 if (!name || !client || !handle || !paddr || !vaddr || !pa_len) {
124 pr_err("%s: Invalid params\n", __func__);
125 rc = -EINVAL;
126 goto err;
127 }
Fred Ohde9438a2013-04-04 11:29:12 -0700128
129 *client = msm_audio_ion_client_create(UINT_MAX, name);
130 if (IS_ERR_OR_NULL((void *)(*client))) {
131 pr_err("%s: ION create client for AUDIO failed\n", __func__);
Gopikrishnaiah Anandan6eb6d182013-08-16 17:34:21 -0400132 rc = -EINVAL;
Fred Ohde9438a2013-04-04 11:29:12 -0700133 goto err;
134 }
135
136 /* name should be audio_acdb_client or Audio_Dec_Client,
137 bufsz should be 0 and fd shouldn't be 0 as of now
138 */
139 *handle = ion_import_dma_buf(*client, fd);
140 pr_err("%s: DMA Buf name=%s, fd=%d handle=%p\n", __func__,
141 name, fd, *handle);
142 if (IS_ERR_OR_NULL((void *) (*handle))) {
143 pr_err("%s: ion import dma buffer failed\n",
144 __func__);
Gopikrishnaiah Anandan6eb6d182013-08-16 17:34:21 -0400145 rc = -EINVAL;
146 goto err_destroy_client;
147 }
Fred Ohde9438a2013-04-04 11:29:12 -0700148
149 if (ionflag != NULL) {
150 rc = ion_handle_get_flags(*client, *handle, ionflag);
151 if (rc) {
152 pr_err("%s: could not get flags for the handle\n",
153 __func__);
154 goto err_ion_handle;
155 }
156 }
157
158 rc = msm_audio_ion_get_phys(*client, *handle, paddr, pa_len);
159 if (rc) {
160 pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
161 __func__, rc);
162 goto err_ion_handle;
163 }
164
Fred Oh13039072013-06-18 19:11:48 -0700165 *vaddr = ion_map_kernel(*client, *handle);
166 if (IS_ERR_OR_NULL((void *)*vaddr)) {
167 pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
Gopikrishnaiah Anandan6eb6d182013-08-16 17:34:21 -0400168 rc = -ENOMEM;
Fred Oh13039072013-06-18 19:11:48 -0700169 goto err_ion_handle;
170 }
171 pr_debug("%s: mapped address = %p, size=%d\n", __func__, *vaddr, bufsz);
Fred Ohde9438a2013-04-04 11:29:12 -0700172
173 return 0;
174
175err_ion_handle:
176 ion_free(*client, *handle);
Gopikrishnaiah Anandan6eb6d182013-08-16 17:34:21 -0400177err_destroy_client:
Fred Ohde9438a2013-04-04 11:29:12 -0700178 msm_audio_ion_client_destroy(*client);
Gopikrishnaiah Anandan6eb6d182013-08-16 17:34:21 -0400179 *client = NULL;
180 *handle = NULL;
Fred Ohde9438a2013-04-04 11:29:12 -0700181err:
Gopikrishnaiah Anandan6eb6d182013-08-16 17:34:21 -0400182 return rc;
Fred Ohde9438a2013-04-04 11:29:12 -0700183}
184
185int msm_audio_ion_free(struct ion_client *client, struct ion_handle *handle)
186{
Gopikrishnaiah Anandan6eb6d182013-08-16 17:34:21 -0400187 if (!client || !handle) {
188 pr_err("%s Invalid params\n", __func__);
189 return -EINVAL;
190 }
Fred Ohc274a7a2013-03-25 13:59:17 -0700191 if (msm_audio_ion_data.smmu_enabled) {
192 /* Need to populate book kept infomation */
193 pr_debug("client=%p, domain=%p, domain_id=%d, group=%p",
194 client, msm_audio_ion_data.domain,
195 msm_audio_ion_data.domain_id, msm_audio_ion_data.group);
196
197 ion_unmap_iommu(client, handle,
198 msm_audio_ion_data.domain_id, 0);
199 }
200
Fred Ohde9438a2013-04-04 11:29:12 -0700201 ion_unmap_kernel(client, handle);
202
203 ion_free(client, handle);
204 msm_audio_ion_client_destroy(client);
205 return 0;
206}
207
Fred Ohc274a7a2013-03-25 13:59:17 -0700208int msm_audio_ion_mmap(struct audio_buffer *ab,
209 struct vm_area_struct *vma)
210{
211 struct sg_table *table;
212 unsigned long addr = vma->vm_start;
213 unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
214 struct scatterlist *sg;
215 unsigned int i;
216 struct page *page;
217 int ret;
218
219 pr_debug("%s\n", __func__);
220
221 table = ion_sg_table(ab->client, ab->handle);
222
223 if (IS_ERR(table)) {
224 pr_err("%s: Unable to get sg_table from ion: %ld\n",
225 __func__, PTR_ERR(table));
226 return PTR_ERR(table);
227 } else if (!table) {
228 pr_err("%s: sg_list is NULL\n", __func__);
229 return -EINVAL;
230 }
231
232 /* uncached */
233 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
234
235 /* We need to check if a page is associated with this sg list because:
236 * If the allocation came from a carveout we currently don't have
237 * pages associated with carved out memory. This might change in the
238 * future and we can remove this check and the else statement.
239 */
240 page = sg_page(table->sgl);
241 if (page) {
242 pr_debug("%s: page is NOT null\n", __func__);
243 for_each_sg(table->sgl, sg, table->nents, i) {
244 unsigned long remainder = vma->vm_end - addr;
245 unsigned long len = sg_dma_len(sg);
246
247 page = sg_page(sg);
248
249 if (offset >= sg_dma_len(sg)) {
250 offset -= sg_dma_len(sg);
251 continue;
252 } else if (offset) {
253 page += offset / PAGE_SIZE;
254 len = sg_dma_len(sg) - offset;
255 offset = 0;
256 }
257 len = min(len, remainder);
258 pr_debug("vma=%p, addr=%x len=%ld vm_start=%x vm_end=%x vm_page_prot=%ld\n",
259 vma, (unsigned int)addr, len,
260 (unsigned int)vma->vm_start,
261 (unsigned int)vma->vm_end,
262 (unsigned long int)vma->vm_page_prot);
263 remap_pfn_range(vma, addr, page_to_pfn(page), len,
264 vma->vm_page_prot);
265 addr += len;
266 if (addr >= vma->vm_end)
267 return 0;
268 }
269 } else {
270 ion_phys_addr_t phys_addr;
271 size_t phys_len;
Fred Oh0b5f49b2013-10-11 15:07:45 -0700272 size_t va_len = 0;
Fred Ohc274a7a2013-03-25 13:59:17 -0700273 pr_debug("%s: page is NULL\n", __func__);
274
275 ret = ion_phys(ab->client, ab->handle, &phys_addr, &phys_len);
276 if (ret) {
277 pr_err("%s: Unable to get phys address from ION buffer: %d\n"
278 , __func__ , ret);
279 return ret;
280 }
281 pr_debug("phys=%x len=%d\n", (unsigned int)phys_addr, phys_len);
282 pr_debug("vma=%p, vm_start=%x vm_end=%x vm_pgoff=%ld vm_page_prot=%ld\n",
283 vma, (unsigned int)vma->vm_start,
284 (unsigned int)vma->vm_end, vma->vm_pgoff,
285 (unsigned long int)vma->vm_page_prot);
Fred Oh0b5f49b2013-10-11 15:07:45 -0700286 va_len = vma->vm_end - vma->vm_start;
287 if ((offset > phys_len) || (va_len > phys_len-offset)) {
288 pr_err("wrong offset size %ld, lens= %d, va_len=%d\n",
289 offset, phys_len, va_len);
290 return -EINVAL;
291 }
Fred Ohc274a7a2013-03-25 13:59:17 -0700292 ret = remap_pfn_range(vma, vma->vm_start,
293 __phys_to_pfn(phys_addr) + vma->vm_pgoff,
294 vma->vm_end - vma->vm_start,
295 vma->vm_page_prot);
296 }
297 return 0;
298}
299
Fred Ohde9438a2013-04-04 11:29:12 -0700300
301bool msm_audio_ion_is_smmu_available(void)
302{
303 return msm_audio_ion_data.smmu_enabled;
304}
305
306/* move to static section again */
307struct ion_client *msm_audio_ion_client_create(unsigned int heap_mask,
308 const char *name)
309{
Fred Ohc274a7a2013-03-25 13:59:17 -0700310 struct ion_client *pclient = NULL;
311 /*IOMMU group and domain are moved to probe()*/
312 pclient = msm_ion_client_create(heap_mask, name);
313 return pclient;
Fred Ohde9438a2013-04-04 11:29:12 -0700314}
315
316
317void msm_audio_ion_client_destroy(struct ion_client *client)
318{
Fred Ohc274a7a2013-03-25 13:59:17 -0700319 pr_debug("%s: client = %p smmu_enabled = %d\n", __func__,
320 client, msm_audio_ion_data.smmu_enabled);
Fred Ohde9438a2013-04-04 11:29:12 -0700321
322 ion_client_destroy(client);
323}
324
325int msm_audio_ion_import_legacy(const char *name, struct ion_client *client,
326 struct ion_handle **handle, int fd,
327 unsigned long *ionflag, size_t bufsz,
328 ion_phys_addr_t *paddr, size_t *pa_len, void **vaddr)
329{
330 int rc = 0;
Gopikrishnaiah Anandan61dcd662013-11-07 20:20:39 -0800331 if (!name || !client || !handle || !paddr || !vaddr || !pa_len) {
332 pr_err("%s: Invalid params\n", __func__);
333 rc = -EINVAL;
334 goto err;
335 }
Fred Ohde9438a2013-04-04 11:29:12 -0700336 /* client is already created for legacy and given*/
337 /* name should be audio_acdb_client or Audio_Dec_Client,
338 bufsz should be 0 and fd shouldn't be 0 as of now
339 */
340 *handle = ion_import_dma_buf(client, fd);
Fred Ohc274a7a2013-03-25 13:59:17 -0700341 pr_debug("%s: DMA Buf name=%s, fd=%d handle=%p\n", __func__,
Fred Ohde9438a2013-04-04 11:29:12 -0700342 name, fd, *handle);
Fred Ohc274a7a2013-03-25 13:59:17 -0700343 if (IS_ERR_OR_NULL((void *)(*handle))) {
Fred Ohde9438a2013-04-04 11:29:12 -0700344 pr_err("%s: ion import dma buffer failed\n",
345 __func__);
Gopikrishnaiah Anandan61dcd662013-11-07 20:20:39 -0800346 rc = -EINVAL;
Anish Kumarc0149b82014-03-10 11:48:07 +0530347 goto err;
Gopikrishnaiah Anandan61dcd662013-11-07 20:20:39 -0800348 }
Fred Ohde9438a2013-04-04 11:29:12 -0700349
350 if (ionflag != NULL) {
351 rc = ion_handle_get_flags(client, *handle, ionflag);
352 if (rc) {
353 pr_err("%s: could not get flags for the handle\n",
354 __func__);
Gopikrishnaiah Anandan61dcd662013-11-07 20:20:39 -0800355 rc = -EINVAL;
Fred Ohde9438a2013-04-04 11:29:12 -0700356 goto err_ion_handle;
357 }
358 }
359
360 rc = msm_audio_ion_get_phys(client, *handle, paddr, pa_len);
361 if (rc) {
362 pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
363 __func__, rc);
Gopikrishnaiah Anandan61dcd662013-11-07 20:20:39 -0800364 rc = -EINVAL;
Fred Ohde9438a2013-04-04 11:29:12 -0700365 goto err_ion_handle;
366 }
367
368 /*Need to add condition SMMU enable or not */
369 *vaddr = ion_map_kernel(client, *handle);
370 if (IS_ERR_OR_NULL((void *)*vaddr)) {
371 pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
Gopikrishnaiah Anandan61dcd662013-11-07 20:20:39 -0800372 rc = -EINVAL;
Fred Ohde9438a2013-04-04 11:29:12 -0700373 goto err_ion_handle;
374 }
375
376 if (bufsz != 0)
377 memset((void *)*vaddr, 0, bufsz);
378
379 return 0;
380
381err_ion_handle:
382 ion_free(client, *handle);
Gopikrishnaiah Anandan61dcd662013-11-07 20:20:39 -0800383err:
384 return rc;
Fred Ohde9438a2013-04-04 11:29:12 -0700385}
386
387int msm_audio_ion_free_legacy(struct ion_client *client,
388 struct ion_handle *handle)
389{
Gopikrishnaiah Anandan11e633b2014-01-20 16:01:24 -0800390 if (msm_audio_ion_data.smmu_enabled)
391 ion_unmap_iommu(client, handle,
392 msm_audio_ion_data.domain_id, 0);
Fred Ohde9438a2013-04-04 11:29:12 -0700393 ion_unmap_kernel(client, handle);
394
395 ion_free(client, handle);
396 /* no client_destrody in legacy*/
397 return 0;
398}
399
Fred Ohc274a7a2013-03-25 13:59:17 -0700400int msm_audio_ion_cache_operations(struct audio_buffer *abuff, int cache_op)
401{
402 unsigned long ionflag = 0;
403 int rc = 0;
404 int msm_cache_ops = 0;
405
406 if (!abuff) {
407 pr_err("Invalid params: %p, %p\n", __func__, abuff);
408 return -EINVAL;
409 }
410 rc = ion_handle_get_flags(abuff->client, abuff->handle,
411 &ionflag);
412 if (rc) {
413 pr_err("ion_handle_get_flags failed: %d\n", rc);
414 goto cache_op_failed;
415 }
416
417 /* has to be CACHED */
418 if (ION_IS_CACHED(ionflag)) {
419 /* ION_IOC_INV_CACHES or ION_IOC_CLEAN_CACHES */
420 msm_cache_ops = cache_op;
421 rc = msm_ion_do_cache_op(abuff->client,
422 abuff->handle,
423 (unsigned long *) abuff->data,
424 (unsigned long)abuff->size,
425 msm_cache_ops);
426 if (rc) {
427 pr_err("cache operation failed %d\n", rc);
428 goto cache_op_failed;
429 }
430 }
431cache_op_failed:
432 return rc;
433}
434
Fred Ohde9438a2013-04-04 11:29:12 -0700435
436static int msm_audio_ion_get_phys(struct ion_client *client,
437 struct ion_handle *handle,
438 ion_phys_addr_t *addr, size_t *len)
439{
440 int rc = 0;
441 pr_debug("%s: smmu_enabled = %d\n", __func__,
442 msm_audio_ion_data.smmu_enabled);
443
444 if (msm_audio_ion_data.smmu_enabled) {
Fred Ohc274a7a2013-03-25 13:59:17 -0700445 rc = ion_map_iommu(client, handle, msm_audio_ion_data.domain_id,
446 0 /*partition_num*/, SZ_4K /*align*/, 0/*iova_length*/,
447 addr, (unsigned long *)len,
448 0, 0);
449 if (rc) {
450 pr_err("%s: ION map iommu failed %d\n", __func__, rc);
451 return rc;
452 }
453 pr_debug("client=%p, domain=%p, domain_id=%d, group=%p",
454 client, msm_audio_ion_data.domain,
455 msm_audio_ion_data.domain_id, msm_audio_ion_data.group);
Fred Ohde9438a2013-04-04 11:29:12 -0700456 } else {
457 /* SMMU is disabled*/
458 rc = ion_phys(client, handle, addr, len);
459 }
Fred Ohc274a7a2013-03-25 13:59:17 -0700460 pr_debug("phys=%x, len=%d, rc=%d\n", (unsigned int)*addr, *len, rc);
Fred Ohde9438a2013-04-04 11:29:12 -0700461 return rc;
462}
463
Fred Ohde9438a2013-04-04 11:29:12 -0700464static int msm_audio_ion_probe(struct platform_device *pdev)
465{
466 int rc = 0;
467 const char *msm_audio_ion_dt = "qcom,smmu-enabled";
468 bool smmu_enabled;
469
470 if (pdev->dev.of_node == NULL) {
471 pr_err("%s: device tree is not found\n", __func__);
472 msm_audio_ion_data.smmu_enabled = 0;
473 return 0;
474 }
475
476 smmu_enabled = of_property_read_bool(pdev->dev.of_node,
477 msm_audio_ion_dt);
478 msm_audio_ion_data.smmu_enabled = smmu_enabled;
479
Fred Ohc274a7a2013-03-25 13:59:17 -0700480 if (smmu_enabled) {
481 msm_audio_ion_data.group = iommu_group_find("lpass_audio");
482 if (!msm_audio_ion_data.group) {
483 pr_debug("Failed to find group lpass_audio deferred\n");
484 goto fail_group;
485 }
486 msm_audio_ion_data.domain =
487 iommu_group_get_iommudata(msm_audio_ion_data.group);
488 if (IS_ERR_OR_NULL(msm_audio_ion_data.domain)) {
489 pr_err("Failed to get domain data for group %p",
490 msm_audio_ion_data.group);
491 goto fail_group;
492 }
493 msm_audio_ion_data.domain_id =
494 msm_find_domain_no(msm_audio_ion_data.domain);
495 if (msm_audio_ion_data.domain_id < 0) {
496 pr_err("Failed to get domain index for domain %p",
497 msm_audio_ion_data.domain);
498 goto fail_group;
499 }
500 pr_debug("domain=%p, domain_id=%d, group=%p",
501 msm_audio_ion_data.domain,
502 msm_audio_ion_data.domain_id, msm_audio_ion_data.group);
503
504 /* iommu_attach_group() will make AXI clock ON. For future PL
505 this will require to be called in once per session */
506 rc = iommu_attach_group(msm_audio_ion_data.domain,
507 msm_audio_ion_data.group);
508 if (rc) {
509 pr_err("%s:ION attach group failed %d\n", __func__, rc);
510 return rc;
511 }
512
513 }
514
Fred Ohde9438a2013-04-04 11:29:12 -0700515 pr_debug("%s: SMMU-Enabled = %d\n", __func__, smmu_enabled);
516 return rc;
Fred Ohc274a7a2013-03-25 13:59:17 -0700517
518fail_group:
519 return -EPROBE_DEFER;
Fred Ohde9438a2013-04-04 11:29:12 -0700520}
521
522static int msm_audio_ion_remove(struct platform_device *pdev)
523{
Fred Ohc274a7a2013-03-25 13:59:17 -0700524 pr_debug("%s: msm audio ion is unloaded, domain=%p, group=%p\n",
525 __func__, msm_audio_ion_data.domain, msm_audio_ion_data.group);
526 iommu_detach_group(msm_audio_ion_data.domain, msm_audio_ion_data.group);
Fred Ohde9438a2013-04-04 11:29:12 -0700527
528 return 0;
529}
530
531static const struct of_device_id msm_audio_ion_dt_match[] = {
532 { .compatible = "qcom,msm-audio-ion" },
533 { }
534};
535MODULE_DEVICE_TABLE(of, msm_audio_ion_dt_match);
536
537static struct platform_driver msm_audio_ion_driver = {
538 .driver = {
539 .name = "msm-audio-ion",
540 .owner = THIS_MODULE,
541 .of_match_table = msm_audio_ion_dt_match,
542 },
543 .probe = msm_audio_ion_probe,
544 .remove = __devexit_p(msm_audio_ion_remove),
545};
546
547static int __init msm_audio_ion_init(void)
548{
549 return platform_driver_register(&msm_audio_ion_driver);
550}
551module_init(msm_audio_ion_init);
552
553static void __exit msm_audio_ion_exit(void)
554{
555 platform_driver_unregister(&msm_audio_ion_driver);
556}
557module_exit(msm_audio_ion_exit);
558
559MODULE_DESCRIPTION("MSM Audio ION module");
560MODULE_LICENSE("GPL v2");