remove ioremap_nocache and devm_ioremap_nocache
[sfrench/cifs-2.6.git] / drivers / staging / kpc2000 / kpc_dma / kpc_dma_driver.c
1 /* SPDX-License-Identifier: GPL-2.0+ */
2 #include <linux/init.h>
3 #include <linux/module.h>
4 #include <linux/types.h>
5 #include <asm/io.h>
6 #include <linux/export.h>
7 #include <linux/slab.h>
8 #include <linux/platform_device.h>
9 #include <linux/fs.h>
10 #include <linux/rwsem.h>
11 #include "kpc_dma_driver.h"
12
13 MODULE_LICENSE("GPL");
14 MODULE_AUTHOR("Matt.Sickler@daktronics.com");
15
16 #define KPC_DMA_CHAR_MAJOR    UNNAMED_MAJOR
17 #define KPC_DMA_NUM_MINORS    BIT(MINORBITS)
18 static DEFINE_MUTEX(kpc_dma_mtx);
19 static int assigned_major_num;
20 static LIST_HEAD(kpc_dma_list);
21
22 /**********  kpc_dma_list list management  **********/
23 struct kpc_dma_device *kpc_dma_lookup_device(int minor)
24 {
25         struct kpc_dma_device *c;
26
27         mutex_lock(&kpc_dma_mtx);
28         list_for_each_entry(c, &kpc_dma_list, list) {
29                 if (c->pldev->id == minor) {
30                         goto out;
31                 }
32         }
33         c = NULL; // not-found case
34 out:
35         mutex_unlock(&kpc_dma_mtx);
36         return c;
37 }
38
39 static void kpc_dma_add_device(struct kpc_dma_device *ldev)
40 {
41         mutex_lock(&kpc_dma_mtx);
42         list_add(&ldev->list, &kpc_dma_list);
43         mutex_unlock(&kpc_dma_mtx);
44 }
45
46 static void kpc_dma_del_device(struct kpc_dma_device *ldev)
47 {
48         mutex_lock(&kpc_dma_mtx);
49         list_del(&ldev->list);
50         mutex_unlock(&kpc_dma_mtx);
51 }
52
53 /**********  SysFS Attributes **********/
54 static ssize_t  show_engine_regs(struct device *dev, struct device_attribute *attr, char *buf)
55 {
56         struct kpc_dma_device *ldev;
57         struct platform_device *pldev = to_platform_device(dev);
58
59         if (!pldev)
60                 return 0;
61         ldev = platform_get_drvdata(pldev);
62         if (!ldev)
63                 return 0;
64
65         return scnprintf(buf, PAGE_SIZE,
66                 "EngineControlStatus      = 0x%08x\n"
67                 "RegNextDescPtr           = 0x%08x\n"
68                 "RegSWDescPtr             = 0x%08x\n"
69                 "RegCompletedDescPtr      = 0x%08x\n"
70                 "desc_pool_first          = %p\n"
71                 "desc_pool_last           = %p\n"
72                 "desc_next                = %p\n"
73                 "desc_completed           = %p\n",
74                 readl(ldev->eng_regs + 1),
75                 readl(ldev->eng_regs + 2),
76                 readl(ldev->eng_regs + 3),
77                 readl(ldev->eng_regs + 4),
78                 ldev->desc_pool_first,
79                 ldev->desc_pool_last,
80                 ldev->desc_next,
81                 ldev->desc_completed
82         );
83 }
84 static DEVICE_ATTR(engine_regs, 0444, show_engine_regs, NULL);
85
86 static const struct attribute *ndd_attr_list[] = {
87         &dev_attr_engine_regs.attr,
88         NULL,
89 };
90
91 static struct class *kpc_dma_class;
92
93 /**********  Platform Driver Functions  **********/
94 static
95 int  kpc_dma_probe(struct platform_device *pldev)
96 {
97         struct resource *r = NULL;
98         int rv = 0;
99         dev_t dev;
100
101         struct kpc_dma_device *ldev = kzalloc(sizeof(struct kpc_dma_device), GFP_KERNEL);
102
103         if (!ldev) {
104                 dev_err(&pldev->dev, "%s: unable to kzalloc space for kpc_dma_device\n", __func__);
105                 rv = -ENOMEM;
106                 goto err_rv;
107         }
108
109         INIT_LIST_HEAD(&ldev->list);
110
111         ldev->pldev = pldev;
112         platform_set_drvdata(pldev, ldev);
113         atomic_set(&ldev->open_count, 1);
114
115         mutex_init(&ldev->sem);
116         lock_engine(ldev);
117
118         // Get Engine regs resource
119         r = platform_get_resource(pldev, IORESOURCE_MEM, 0);
120         if (!r) {
121                 dev_err(&ldev->pldev->dev, "%s: didn't get the engine regs resource!\n", __func__);
122                 rv = -ENXIO;
123                 goto err_kfree;
124         }
125         ldev->eng_regs = ioremap(r->start, resource_size(r));
126         if (!ldev->eng_regs) {
127                 dev_err(&ldev->pldev->dev, "%s: failed to ioremap engine regs!\n", __func__);
128                 rv = -ENXIO;
129                 goto err_kfree;
130         }
131
132         r = platform_get_resource(pldev, IORESOURCE_IRQ, 0);
133         if (!r) {
134                 dev_err(&ldev->pldev->dev, "%s: didn't get the IRQ resource!\n", __func__);
135                 rv = -ENXIO;
136                 goto err_kfree;
137         }
138         ldev->irq = r->start;
139
140         // Setup miscdev struct
141         dev = MKDEV(assigned_major_num, pldev->id);
142         ldev->kpc_dma_dev = device_create(kpc_dma_class, &pldev->dev, dev, ldev, "kpc_dma%d", pldev->id);
143         if (IS_ERR(ldev->kpc_dma_dev)) {
144                 dev_err(&ldev->pldev->dev, "%s: device_create failed: %d\n", __func__, rv);
145                 goto err_kfree;
146         }
147
148         // Setup the DMA engine
149         rv = setup_dma_engine(ldev, 30);
150         if (rv) {
151                 dev_err(&ldev->pldev->dev, "%s: failed to setup_dma_engine: %d\n", __func__, rv);
152                 goto err_misc_dereg;
153         }
154
155         // Setup the sysfs files
156         rv = sysfs_create_files(&(ldev->pldev->dev.kobj), ndd_attr_list);
157         if (rv) {
158                 dev_err(&ldev->pldev->dev, "%s: Failed to add sysfs files: %d\n", __func__, rv);
159                 goto err_destroy_eng;
160         }
161
162         kpc_dma_add_device(ldev);
163
164         return 0;
165
166  err_destroy_eng:
167         destroy_dma_engine(ldev);
168  err_misc_dereg:
169         device_destroy(kpc_dma_class, dev);
170  err_kfree:
171         kfree(ldev);
172  err_rv:
173         return rv;
174 }
175
176 static
177 int  kpc_dma_remove(struct platform_device *pldev)
178 {
179         struct kpc_dma_device *ldev = platform_get_drvdata(pldev);
180
181         if (!ldev)
182                 return -ENXIO;
183
184         lock_engine(ldev);
185         sysfs_remove_files(&(ldev->pldev->dev.kobj), ndd_attr_list);
186         destroy_dma_engine(ldev);
187         kpc_dma_del_device(ldev);
188         device_destroy(kpc_dma_class, MKDEV(assigned_major_num, ldev->pldev->id));
189         kfree(ldev);
190
191         return 0;
192 }
193
194 /**********  Driver Functions  **********/
195 static struct platform_driver kpc_dma_plat_driver_i = {
196         .probe        = kpc_dma_probe,
197         .remove       = kpc_dma_remove,
198         .driver = {
199                 .name   = KP_DRIVER_NAME_DMA_CONTROLLER,
200         },
201 };
202
203 static
204 int __init kpc_dma_driver_init(void)
205 {
206         int err;
207
208         err = __register_chrdev(KPC_DMA_CHAR_MAJOR, 0, KPC_DMA_NUM_MINORS, "kpc_dma", &kpc_dma_fops);
209         if (err < 0) {
210                 pr_err("Can't allocate a major number (%d) for kpc_dma (err = %d)\n", KPC_DMA_CHAR_MAJOR, err);
211                 goto fail_chrdev_register;
212         }
213         assigned_major_num = err;
214
215         kpc_dma_class = class_create(THIS_MODULE, "kpc_dma");
216         err = PTR_ERR(kpc_dma_class);
217         if (IS_ERR(kpc_dma_class)) {
218                 pr_err("Can't create class kpc_dma (err = %d)\n", err);
219                 goto fail_class_create;
220         }
221
222         err = platform_driver_register(&kpc_dma_plat_driver_i);
223         if (err) {
224                 pr_err("Can't register platform driver for kpc_dma (err = %d)\n", err);
225                 goto fail_platdriver_register;
226         }
227
228         return err;
229
230 fail_platdriver_register:
231         class_destroy(kpc_dma_class);
232 fail_class_create:
233         __unregister_chrdev(KPC_DMA_CHAR_MAJOR, 0, KPC_DMA_NUM_MINORS, "kpc_dma");
234 fail_chrdev_register:
235         return err;
236 }
237 module_init(kpc_dma_driver_init);
238
239 static
240 void __exit kpc_dma_driver_exit(void)
241 {
242         platform_driver_unregister(&kpc_dma_plat_driver_i);
243         class_destroy(kpc_dma_class);
244         __unregister_chrdev(KPC_DMA_CHAR_MAJOR, 0, KPC_DMA_NUM_MINORS, "kpc_dma");
245 }
246 module_exit(kpc_dma_driver_exit);