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"); |
