GNU Linux-libre 4.9-gnu1
[releases.git] / drivers / staging / android / ion / hisilicon / hi6220_ion.c
1 /*
2  * Hisilicon Hi6220 ION Driver
3  *
4  * Copyright (c) 2015 Hisilicon Limited.
5  *
6  * Author: Chen Feng <puck.chen@hisilicon.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #define pr_fmt(fmt) "Ion: " fmt
14
15 #include <linux/err.h>
16 #include <linux/platform_device.h>
17 #include <linux/slab.h>
18 #include <linux/of.h>
19 #include <linux/mm.h>
20 #include "../ion_priv.h"
21 #include "../ion.h"
22 #include "../ion_of.h"
23
24 struct hisi_ion_dev {
25         struct ion_heap **heaps;
26         struct ion_device *idev;
27         struct ion_platform_data *data;
28 };
29
30 static struct ion_of_heap hisi_heaps[] = {
31         PLATFORM_HEAP("hisilicon,sys_user", 0,
32                       ION_HEAP_TYPE_SYSTEM, "sys_user"),
33         PLATFORM_HEAP("hisilicon,sys_contig", 1,
34                       ION_HEAP_TYPE_SYSTEM_CONTIG, "sys_contig"),
35         PLATFORM_HEAP("hisilicon,cma", ION_HEAP_TYPE_DMA, ION_HEAP_TYPE_DMA,
36                       "cma"),
37         {}
38 };
39
40 static int hi6220_ion_probe(struct platform_device *pdev)
41 {
42         struct hisi_ion_dev *ipdev;
43         int i;
44
45         ipdev = devm_kzalloc(&pdev->dev, sizeof(*ipdev), GFP_KERNEL);
46         if (!ipdev)
47                 return -ENOMEM;
48
49         platform_set_drvdata(pdev, ipdev);
50
51         ipdev->idev = ion_device_create(NULL);
52         if (IS_ERR(ipdev->idev))
53                 return PTR_ERR(ipdev->idev);
54
55         ipdev->data = ion_parse_dt(pdev, hisi_heaps);
56         if (IS_ERR(ipdev->data))
57                 return PTR_ERR(ipdev->data);
58
59         ipdev->heaps = devm_kzalloc(&pdev->dev,
60                                 sizeof(struct ion_heap) * ipdev->data->nr,
61                                 GFP_KERNEL);
62         if (!ipdev->heaps) {
63                 ion_destroy_platform_data(ipdev->data);
64                 return -ENOMEM;
65         }
66
67         for (i = 0; i < ipdev->data->nr; i++) {
68                 ipdev->heaps[i] = ion_heap_create(&ipdev->data->heaps[i]);
69                 if (!ipdev->heaps) {
70                         ion_destroy_platform_data(ipdev->data);
71                         return -ENOMEM;
72                 }
73                 ion_device_add_heap(ipdev->idev, ipdev->heaps[i]);
74         }
75         return 0;
76 }
77
78 static int hi6220_ion_remove(struct platform_device *pdev)
79 {
80         struct hisi_ion_dev *ipdev;
81         int i;
82
83         ipdev = platform_get_drvdata(pdev);
84
85         for (i = 0; i < ipdev->data->nr; i++)
86                 ion_heap_destroy(ipdev->heaps[i]);
87
88         ion_destroy_platform_data(ipdev->data);
89         ion_device_destroy(ipdev->idev);
90
91         return 0;
92 }
93
94 static const struct of_device_id hi6220_ion_match_table[] = {
95         {.compatible = "hisilicon,hi6220-ion"},
96         {},
97 };
98
99 static struct platform_driver hi6220_ion_driver = {
100         .probe = hi6220_ion_probe,
101         .remove = hi6220_ion_remove,
102         .driver = {
103                 .name = "ion-hi6220",
104                 .of_match_table = hi6220_ion_match_table,
105         },
106 };
107
108 static int __init hi6220_ion_init(void)
109 {
110         return platform_driver_register(&hi6220_ion_driver);
111 }
112
113 subsys_initcall(hi6220_ion_init);