diff options
Diffstat (limited to 'drivers/dma/qcom/hidma_mgmt.c')
-rw-r--r-- | drivers/dma/qcom/hidma_mgmt.c | 113 |
1 files changed, 109 insertions, 4 deletions
diff --git a/drivers/dma/qcom/hidma_mgmt.c b/drivers/dma/qcom/hidma_mgmt.c index ef491b893f40..c0e365321310 100644 --- a/drivers/dma/qcom/hidma_mgmt.c +++ b/drivers/dma/qcom/hidma_mgmt.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Qualcomm Technologies HIDMA DMA engine Management interface | 2 | * Qualcomm Technologies HIDMA DMA engine Management interface |
3 | * | 3 | * |
4 | * Copyright (c) 2015, The Linux Foundation. All rights reserved. | 4 | * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License version 2 and | 7 | * it under the terms of the GNU General Public License version 2 and |
@@ -17,13 +17,14 @@ | |||
17 | #include <linux/acpi.h> | 17 | #include <linux/acpi.h> |
18 | #include <linux/of.h> | 18 | #include <linux/of.h> |
19 | #include <linux/property.h> | 19 | #include <linux/property.h> |
20 | #include <linux/interrupt.h> | 20 | #include <linux/of_irq.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/of_platform.h> |
22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
23 | #include <linux/uaccess.h> | 23 | #include <linux/uaccess.h> |
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/pm_runtime.h> | 25 | #include <linux/pm_runtime.h> |
26 | #include <linux/bitops.h> | 26 | #include <linux/bitops.h> |
27 | #include <linux/dma-mapping.h> | ||
27 | 28 | ||
28 | #include "hidma_mgmt.h" | 29 | #include "hidma_mgmt.h" |
29 | 30 | ||
@@ -298,5 +299,109 @@ static struct platform_driver hidma_mgmt_driver = { | |||
298 | }, | 299 | }, |
299 | }; | 300 | }; |
300 | 301 | ||
301 | module_platform_driver(hidma_mgmt_driver); | 302 | #if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) |
303 | static int object_counter; | ||
304 | |||
305 | static int __init hidma_mgmt_of_populate_channels(struct device_node *np) | ||
306 | { | ||
307 | struct platform_device *pdev_parent = of_find_device_by_node(np); | ||
308 | struct platform_device_info pdevinfo; | ||
309 | struct of_phandle_args out_irq; | ||
310 | struct device_node *child; | ||
311 | struct resource *res; | ||
312 | const __be32 *cell; | ||
313 | int ret = 0, size, i, num; | ||
314 | u64 addr, addr_size; | ||
315 | |||
316 | for_each_available_child_of_node(np, child) { | ||
317 | struct resource *res_iter; | ||
318 | struct platform_device *new_pdev; | ||
319 | |||
320 | cell = of_get_property(child, "reg", &size); | ||
321 | if (!cell) { | ||
322 | ret = -EINVAL; | ||
323 | goto out; | ||
324 | } | ||
325 | |||
326 | size /= sizeof(*cell); | ||
327 | num = size / | ||
328 | (of_n_addr_cells(child) + of_n_size_cells(child)) + 1; | ||
329 | |||
330 | /* allocate a resource array */ | ||
331 | res = kcalloc(num, sizeof(*res), GFP_KERNEL); | ||
332 | if (!res) { | ||
333 | ret = -ENOMEM; | ||
334 | goto out; | ||
335 | } | ||
336 | |||
337 | /* read each reg value */ | ||
338 | i = 0; | ||
339 | res_iter = res; | ||
340 | while (i < size) { | ||
341 | addr = of_read_number(&cell[i], | ||
342 | of_n_addr_cells(child)); | ||
343 | i += of_n_addr_cells(child); | ||
344 | |||
345 | addr_size = of_read_number(&cell[i], | ||
346 | of_n_size_cells(child)); | ||
347 | i += of_n_size_cells(child); | ||
348 | |||
349 | res_iter->start = addr; | ||
350 | res_iter->end = res_iter->start + addr_size - 1; | ||
351 | res_iter->flags = IORESOURCE_MEM; | ||
352 | res_iter++; | ||
353 | } | ||
354 | |||
355 | ret = of_irq_parse_one(child, 0, &out_irq); | ||
356 | if (ret) | ||
357 | goto out; | ||
358 | |||
359 | res_iter->start = irq_create_of_mapping(&out_irq); | ||
360 | res_iter->name = "hidma event irq"; | ||
361 | res_iter->flags = IORESOURCE_IRQ; | ||
362 | |||
363 | memset(&pdevinfo, 0, sizeof(pdevinfo)); | ||
364 | pdevinfo.fwnode = &child->fwnode; | ||
365 | pdevinfo.parent = pdev_parent ? &pdev_parent->dev : NULL; | ||
366 | pdevinfo.name = child->name; | ||
367 | pdevinfo.id = object_counter++; | ||
368 | pdevinfo.res = res; | ||
369 | pdevinfo.num_res = num; | ||
370 | pdevinfo.data = NULL; | ||
371 | pdevinfo.size_data = 0; | ||
372 | pdevinfo.dma_mask = DMA_BIT_MASK(64); | ||
373 | new_pdev = platform_device_register_full(&pdevinfo); | ||
374 | if (!new_pdev) { | ||
375 | ret = -ENODEV; | ||
376 | goto out; | ||
377 | } | ||
378 | of_dma_configure(&new_pdev->dev, child); | ||
379 | |||
380 | kfree(res); | ||
381 | res = NULL; | ||
382 | } | ||
383 | out: | ||
384 | kfree(res); | ||
385 | |||
386 | return ret; | ||
387 | } | ||
388 | #endif | ||
389 | |||
390 | static int __init hidma_mgmt_init(void) | ||
391 | { | ||
392 | #if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) | ||
393 | struct device_node *child; | ||
394 | |||
395 | for (child = of_find_matching_node(NULL, hidma_mgmt_match); child; | ||
396 | child = of_find_matching_node(child, hidma_mgmt_match)) { | ||
397 | /* device tree based firmware here */ | ||
398 | hidma_mgmt_of_populate_channels(child); | ||
399 | of_node_put(child); | ||
400 | } | ||
401 | #endif | ||
402 | platform_driver_register(&hidma_mgmt_driver); | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | module_init(hidma_mgmt_init); | ||
302 | MODULE_LICENSE("GPL v2"); | 407 | MODULE_LICENSE("GPL v2"); |