[glsdk/meta-ti-glsdk.git] / recipes-kernel / linux / linux-davinci / omapl138 / 0001-uio_pruss1-Core-driver-addition.patch
1 From: Melissa Watkins <m-watkins@ti.com>
2 Date: Wed, 24 Nov 2010 02:59:34 -0600
3 Subject: [PATCH 1/3] uio_pruss1: Core driver addition
5 This patch adds the uio_pru driver and updates the uio Makefile
6 and Kconfig files to support this driver. The uio_pru driver provides
7 a framework for handling the PRU in the user space and is responsible
8 for the device setup and the primary interrupt handling.
10 Signed-off-by: Amit Chatterjee <amit.chatterjee@ti.com>
11 Signed-off-by: Melissa Watkins <m-watkins@ti.com>
12 ---
13 drivers/uio/Kconfig | 10 ++
14 drivers/uio/Makefile | 1 +
15 drivers/uio/uio_pru.c | 279 +++++++++++++++++++++++++++++++++++++++++++++++++
16 3 files changed, 290 insertions(+), 0 deletions(-)
17 create mode 100644 drivers/uio/uio_pru.c
19 diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
20 index 8aa1955..8ae8280 100644
21 --- a/drivers/uio/Kconfig
22 +++ b/drivers/uio/Kconfig
23 @@ -94,4 +94,14 @@ config UIO_PCI_GENERIC
24 primarily, for virtualization scenarios.
25 If you compile this as a module, it will be called uio_pci_generic.
27 +config UIO_PRUSS
28 + tristate "Texas Instruments PRUSS driver"
29 + depends on ARCH_DAVINCI_DA850
30 + default n
31 + help
32 + PRUSS driver for OMAPL13X/DA8XX/AM17XX/AM18XX devices
33 + PRUSS driver requires user space components
34 + To compile this driver as a module, choose M here: the module
35 + will be called uio_pruss.
36 +
37 endif
38 diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile
39 index 73b2e75..e6d8adb 100644
40 --- a/drivers/uio/Makefile
41 +++ b/drivers/uio/Makefile
42 @@ -6,3 +6,4 @@ obj-$(CONFIG_UIO_SMX) += uio_smx.o
43 obj-$(CONFIG_UIO_AEC) += uio_aec.o
44 obj-$(CONFIG_UIO_SERCOS3) += uio_sercos3.o
45 obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o
46 +obj-$(CONFIG_UIO_PRUSS) += uio_pru.o
47 diff --git a/drivers/uio/uio_pru.c b/drivers/uio/uio_pru.c
48 new file mode 100644
49 index 0000000..82dc35e
50 --- /dev/null
51 +++ b/drivers/uio/uio_pru.c
52 @@ -0,0 +1,279 @@
53 +/*
54 + * UIO TI Programmable Real-Time Unit (PRU) driver.
55 + *
56 + * (C) 2010 Amit Chatterjee <amit.chatterjee@ti.com>
57 + *
58 + * Copyright (C) {YEAR} Texas Instruments Incorporated - http://www.ti.com/
59 + *
60 + * This program is free software; you can redistribute it and/or
61 + * modify it under the terms of the GNU General Public License as
62 + * published by the Free Software Foundation version 2.
63 + *
64 + * This program is distributed .as is. WITHOUT ANY WARRANTY of any
65 + * kind, whether express or implied; without even the implied warranty
66 + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
67 + * GNU General Public License for more details.
68 + */
69 +
70 +#include <linux/device.h>
71 +#include <linux/module.h>
72 +#include <linux/platform_device.h>
73 +#include <linux/uio_driver.h>
74 +#include <linux/io.h>
75 +#include <linux/clk.h>
76 +#include <linux/dma-mapping.h>
77 +
78 +#define DRV_NAME "pruss"
79 +#define DRV_VERSION "0.01"
80 +
81 +/*
82 +0x01C30000 - 0x01C301FF Data RAM 0
83 +0x01C30200 - 0x01C31FFF Reserved
84 +0x01C32000 - 0x01C321FF Data RAM 1
85 +0x01C32200 - 0x01C33FFF Reserved
86 +0x01C34000 - 0x01C36FFF INTC Registers
87 +0x01C37000 - 0x01C373FF PRU0 Control Registers
88 +0x01C37400 - 0x01C377FF PRU0 Debug Registers
89 +0x01C37800 - 0x01C37BFF PRU1 Control Registers
90 +0x01C37C00 - 0x01C37FFF PRU1 Debug Registers
91 +0x01C38000 - 0x01C38FFF PRU0 Instruction RAM
92 +0x01C39000 - 0x01C3BFFF Reserved
93 +0x01C3C000 - 0x01C3CFFF PRU1 Instruction RAM
94 +0x01C3D000 - 0x01C3FFFF Reserved
95 +*/
96 +/*
97 + * 3 PRU_EVTOUT0 PRUSS Interrupt
98 + * 4 PRU_EVTOUT1 PRUSS Interrupt
99 + * 5 PRU_EVTOUT2 PRUSS Interrupt
100 + * 6 PRU_EVTOUT3 PRUSS Interrupt
101 + * 7 PRU_EVTOUT4 PRUSS Interrupt
102 + * 8 PRU_EVTOUT5 PRUSS Interrupt
103 + * 9 PRU_EVTOUT6 PRUSS Interrupt
104 + * 10 PRU_EVTOUT7 PRUSS Interrupt
105 +*/
106 +
107 +#define PRUSS_INSTANCE (8)
108 +
109 +static struct clk *pruss_clk = NULL, *ecap0_clk = NULL;
110 +static struct uio_info *info[PRUSS_INSTANCE];
111 +static void *ddr_virt_addr;
112 +static dma_addr_t ddr_phy_addr;
113 +
114 +
115 +
116 +static irqreturn_t pruss_handler(int irq, struct uio_info *dev_info)
117 +{
118 + return IRQ_HANDLED;
119 +}
120 +
121 +static int __devinit pruss_probe(struct platform_device *dev)
122 +{
123 + int ret = -ENODEV;
124 + int count = 0;
125 + struct resource *regs_pruram, *regs_l3ram, *regs_ddr;
126 + char *string;
127 +
128 + /* Power on PRU in case its not done as part of boot-loader */
129 + pruss_clk = clk_get(&dev->dev, "pruss");
130 + if (IS_ERR(pruss_clk)) {
131 + dev_err(&dev->dev, "no pruss clock available\n");
132 + ret = PTR_ERR(pruss_clk);
133 + pruss_clk = NULL;
134 + return ret;
135 + } else {
136 + clk_enable (pruss_clk);
137 + }
138 +
139 + ecap0_clk = clk_get(&dev->dev, "ecap0");
140 + if (IS_ERR(ecap0_clk)) {
141 + dev_err(&dev->dev, "no ecap0 clock available\n");
142 + ret = PTR_ERR(ecap0_clk);
143 + ecap0_clk = NULL;
144 + return ret;
145 + } else {
146 + clk_enable(ecap0_clk);
147 + }
148 +
149 +
150 +
151 + for (count = 0; count < PRUSS_INSTANCE; count++) {
152 + info[count] = (struct uio_info *)kzalloc(sizeof(struct uio_info), GFP_KERNEL);
153 + if (!info[count])
154 + return -ENOMEM;
155 +
156 + }
157 +
158 + regs_pruram = platform_get_resource(dev, IORESOURCE_MEM, 0);
159 + if (!regs_pruram) {
160 + dev_err(&dev->dev, "No memory resource specified\n");
161 + goto out_free;
162 + }
163 +
164 + regs_l3ram = platform_get_resource(dev, IORESOURCE_MEM, 1);
165 + if (!regs_l3ram) {
166 + dev_err(&dev->dev, "No memory resource specified\n");
167 + goto out_free;
168 + }
169 +
170 + regs_ddr = platform_get_resource(dev, IORESOURCE_MEM, 2);
171 + if (!regs_ddr) {
172 + dev_err(&dev->dev, "No memory resource specified\n");
173 + goto out_free;
174 + }
175 + ddr_virt_addr = dma_alloc_coherent(&dev->dev, regs_ddr->end-regs_ddr->start+1, &ddr_phy_addr, GFP_KERNEL|GFP_DMA);
176 +
177 +
178 + for (count = 0; count < PRUSS_INSTANCE; count++) {
179 + info[count]->mem[0].addr = regs_pruram->start;
180 + if (!info[count]->mem[0].addr) {
181 + dev_err(&dev->dev, "Invalid memory resource\n");
182 + break;
183 + }
184 +
185 + info[count]->mem[0].size = regs_pruram->end - regs_pruram->start + 1;
186 + info[count]->mem[0].internal_addr = ioremap(regs_pruram->start, info[count]->mem[0].size);
187 +
188 + if (!info[count]->mem[0].internal_addr) {
189 + dev_err(&dev->dev, "Can't remap memory address range\n");
190 + break;
191 + }
192 + info[count]->mem[0].memtype = UIO_MEM_PHYS;
193 +
194 +
195 + info[count]->mem[1].addr = regs_l3ram->start;
196 + if (!info[count]->mem[1].addr) {
197 + dev_err(&dev->dev, "Invalid memory resource\n");
198 + break;
199 + }
200 +
201 + info[count]->mem[1].size = regs_l3ram->end - regs_l3ram->start + 1;
202 + info[count]->mem[1].internal_addr = ioremap(regs_l3ram->start, info[count]->mem[1].size);
203 +
204 + if (!info[count]->mem[1].internal_addr) {
205 + dev_err(&dev->dev, "Can't remap memory address range\n");
206 + break;
207 + }
208 + info[count]->mem[1].memtype = UIO_MEM_PHYS;
209 +
210 +
211 + info[count]->mem[2].size = regs_ddr->end - regs_ddr->start + 1;
212 + if (!(info[count]->mem[2].size-1)) {
213 + dev_err(&dev->dev, "Invalid memory resource\n");
214 + break;
215 + }
216 +
217 +
218 + info[count]->mem[2].internal_addr = ddr_virt_addr;
219 +
220 + if (!info[count]->mem[2].internal_addr) {
221 + dev_err(&dev->dev, "Can't remap memory address range\n");
222 + break;
223 + }
224 + info[count]->mem[2].addr = ddr_phy_addr;
225 + info[count]->mem[2].memtype = UIO_MEM_PHYS;
226 +
227 +
228 + string = kzalloc(20, GFP_KERNEL);
229 + sprintf(string, "pruss_evt%d", count);
230 + info[count]->name = string;
231 + info[count]->version = "0.01";
232 +
233 + /* Register PRUSS IRQ lines */
234 + info[count]->irq = IRQ_DA8XX_EVTOUT0+count;
235 +
236 + info[count]->irq_flags = IRQF_SHARED;
237 + info[count]->handler = pruss_handler;
238 +
239 + ret = uio_register_device(&dev->dev, info[count]);
240 +
241 + if (ret < 0)
242 + break;
243 + }
244 +
245 + platform_set_drvdata(dev, info);
246 +
247 + if (ret < 0) {
248 + if (ddr_virt_addr)
249 + dma_free_coherent(&dev->dev, regs_ddr->end - regs_ddr->start + 1, ddr_virt_addr, ddr_phy_addr);
250 + while (count--) {
251 + uio_unregister_device(info[count]);
252 + if (info[count]->name)
253 + kfree(info[count]->name);
254 + iounmap(info[count]->mem[0].internal_addr);
255 + }
256 + } else {
257 + return 0;
258 + }
259 +
260 +out_free:
261 + for (count = 0; count < PRUSS_INSTANCE; count++) {
262 + if (info[count])
263 + kfree(info[count]);
264 + }
265 +
266 + if (pruss_clk != NULL)
267 + clk_put(pruss_clk);
268 + if (ecap0_clk != NULL)
269 + clk_put(ecap0_clk);
270 +
271 + return ret;
272 +}
273 +
274 +static int __devexit pruss_remove(struct platform_device *dev)
275 +{
276 + int count = 0;
277 + struct uio_info **info;
278 +
279 + info = (struct uio_info **)platform_get_drvdata(dev);
280 +
281 + for (count = 0; count < PRUSS_INSTANCE; count++) {
282 + uio_unregister_device(info[count]);
283 + if (info[count]->name)
284 + kfree(info[count]->name);
285 +
286 + }
287 + iounmap(info[0]->mem[0].internal_addr);
288 + iounmap(info[0]->mem[1].internal_addr);
289 + if (ddr_virt_addr)
290 + dma_free_coherent(&dev->dev, info[0]->mem[2].size, info[0]->mem[2].internal_addr, info[0]->mem[2].addr);
291 +
292 + for (count = 0; count < PRUSS_INSTANCE; count++) {
293 + if (info[count])
294 + kfree(info[count]);
295 + }
296 +
297 + platform_set_drvdata(dev, NULL);
298 +
299 + if (pruss_clk != NULL)
300 + clk_put(pruss_clk);
301 + if (ecap0_clk != NULL)
302 + clk_put(ecap0_clk);
303 +
304 +
305 + return 0;
306 +}
307 +
308 +static struct platform_driver pruss_driver = {
309 + .probe = pruss_probe,
310 + .remove = __devexit_p(pruss_remove),
311 + .driver = {
312 + .name = DRV_NAME,
313 + .owner = THIS_MODULE,
314 + },
315 +};
316 +
317 +static int __init pruss_init_module(void)
318 +{
319 + return platform_driver_register(&pruss_driver);
320 +}
321 +module_init(pruss_init_module);
322 +
323 +static void __exit pruss_exit_module(void)
324 +{
325 + platform_driver_unregister(&pruss_driver);
326 +}
327 +module_exit(pruss_exit_module);
328 +
329 +MODULE_LICENSE("GPL v2");
330 +MODULE_VERSION(DRV_VERSION);
331 +MODULE_AUTHOR("Amit Chatterjee <amit.chatterjee@ti.com>");
332 --
333 1.7.0.4