diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-platform-hidma | 9 | ||||
-rw-r--r-- | drivers/dma/qcom/hidma.c | 39 | ||||
-rw-r--r-- | drivers/dma/qcom/hidma_mgmt.c | 113 |
3 files changed, 156 insertions, 5 deletions
diff --git a/Documentation/ABI/testing/sysfs-platform-hidma b/Documentation/ABI/testing/sysfs-platform-hidma new file mode 100644 index 000000000000..d36441538660 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-platform-hidma | |||
@@ -0,0 +1,9 @@ | |||
1 | What: /sys/devices/platform/hidma-*/chid | ||
2 | /sys/devices/platform/QCOM8061:*/chid | ||
3 | Date: Dec 2015 | ||
4 | KernelVersion: 4.4 | ||
5 | Contact: "Sinan Kaya <okaya@cudeaurora.org>" | ||
6 | Description: | ||
7 | Contains the ID of the channel within the HIDMA instance. | ||
8 | It is used to associate a given HIDMA channel with the | ||
9 | priority and weight calls in the management interface. | ||
diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c index 1ad27c28d00c..41b5c6dee713 100644 --- a/drivers/dma/qcom/hidma.c +++ b/drivers/dma/qcom/hidma.c | |||
@@ -530,6 +530,43 @@ static irqreturn_t hidma_chirq_handler(int chirq, void *arg) | |||
530 | return hidma_ll_inthandler(chirq, lldev); | 530 | return hidma_ll_inthandler(chirq, lldev); |
531 | } | 531 | } |
532 | 532 | ||
533 | static ssize_t hidma_show_values(struct device *dev, | ||
534 | struct device_attribute *attr, char *buf) | ||
535 | { | ||
536 | struct platform_device *pdev = to_platform_device(dev); | ||
537 | struct hidma_dev *mdev = platform_get_drvdata(pdev); | ||
538 | |||
539 | buf[0] = 0; | ||
540 | |||
541 | if (strcmp(attr->attr.name, "chid") == 0) | ||
542 | sprintf(buf, "%d\n", mdev->chidx); | ||
543 | |||
544 | return strlen(buf); | ||
545 | } | ||
546 | |||
547 | static int hidma_create_sysfs_entry(struct hidma_dev *dev, char *name, | ||
548 | int mode) | ||
549 | { | ||
550 | struct device_attribute *attrs; | ||
551 | char *name_copy; | ||
552 | |||
553 | attrs = devm_kmalloc(dev->ddev.dev, sizeof(struct device_attribute), | ||
554 | GFP_KERNEL); | ||
555 | if (!attrs) | ||
556 | return -ENOMEM; | ||
557 | |||
558 | name_copy = devm_kstrdup(dev->ddev.dev, name, GFP_KERNEL); | ||
559 | if (!name_copy) | ||
560 | return -ENOMEM; | ||
561 | |||
562 | attrs->attr.name = name_copy; | ||
563 | attrs->attr.mode = mode; | ||
564 | attrs->show = hidma_show_values; | ||
565 | sysfs_attr_init(&attrs->attr); | ||
566 | |||
567 | return device_create_file(dev->ddev.dev, attrs); | ||
568 | } | ||
569 | |||
533 | static int hidma_probe(struct platform_device *pdev) | 570 | static int hidma_probe(struct platform_device *pdev) |
534 | { | 571 | { |
535 | struct hidma_dev *dmadev; | 572 | struct hidma_dev *dmadev; |
@@ -645,6 +682,7 @@ static int hidma_probe(struct platform_device *pdev) | |||
645 | dmadev->irq = chirq; | 682 | dmadev->irq = chirq; |
646 | tasklet_init(&dmadev->task, hidma_issue_task, (unsigned long)dmadev); | 683 | tasklet_init(&dmadev->task, hidma_issue_task, (unsigned long)dmadev); |
647 | hidma_debug_init(dmadev); | 684 | hidma_debug_init(dmadev); |
685 | hidma_create_sysfs_entry(dmadev, "chid", S_IRUGO); | ||
648 | dev_info(&pdev->dev, "HI-DMA engine driver registration complete\n"); | 686 | dev_info(&pdev->dev, "HI-DMA engine driver registration complete\n"); |
649 | platform_set_drvdata(pdev, dmadev); | 687 | platform_set_drvdata(pdev, dmadev); |
650 | pm_runtime_mark_last_busy(dmadev->ddev.dev); | 688 | pm_runtime_mark_last_busy(dmadev->ddev.dev); |
@@ -692,7 +730,6 @@ static const struct of_device_id hidma_match[] = { | |||
692 | {.compatible = "qcom,hidma-1.0",}, | 730 | {.compatible = "qcom,hidma-1.0",}, |
693 | {}, | 731 | {}, |
694 | }; | 732 | }; |
695 | |||
696 | MODULE_DEVICE_TABLE(of, hidma_match); | 733 | MODULE_DEVICE_TABLE(of, hidma_match); |
697 | 734 | ||
698 | static struct platform_driver hidma_driver = { | 735 | static struct platform_driver hidma_driver = { |
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"); |