xref: /openbmc/linux/drivers/char/xillybus/xillybus_of.c (revision 7051924f771722c6dd235e693742cda6488ac700)
1*7051924fSEli Billauer /*
2*7051924fSEli Billauer  * linux/drivers/misc/xillybus_of.c
3*7051924fSEli Billauer  *
4*7051924fSEli Billauer  * Copyright 2011 Xillybus Ltd, http://xillybus.com
5*7051924fSEli Billauer  *
6*7051924fSEli Billauer  * Driver for the Xillybus FPGA/host framework using Open Firmware.
7*7051924fSEli Billauer  *
8*7051924fSEli Billauer  * This program is free software; you can redistribute it and/or modify
9*7051924fSEli Billauer  * it under the smems of the GNU General Public License as published by
10*7051924fSEli Billauer  * the Free Software Foundation; version 2 of the License.
11*7051924fSEli Billauer  */
12*7051924fSEli Billauer 
13*7051924fSEli Billauer #include <linux/module.h>
14*7051924fSEli Billauer #include <linux/device.h>
15*7051924fSEli Billauer #include <linux/slab.h>
16*7051924fSEli Billauer #include <linux/platform_device.h>
17*7051924fSEli Billauer #include <linux/of.h>
18*7051924fSEli Billauer #include <linux/of_irq.h>
19*7051924fSEli Billauer #include <linux/of_address.h>
20*7051924fSEli Billauer #include <linux/of_device.h>
21*7051924fSEli Billauer #include <linux/of_platform.h>
22*7051924fSEli Billauer #include <linux/err.h>
23*7051924fSEli Billauer #include "xillybus.h"
24*7051924fSEli Billauer 
25*7051924fSEli Billauer MODULE_DESCRIPTION("Xillybus driver for Open Firmware");
26*7051924fSEli Billauer MODULE_AUTHOR("Eli Billauer, Xillybus Ltd.");
27*7051924fSEli Billauer MODULE_VERSION("1.06");
28*7051924fSEli Billauer MODULE_ALIAS("xillybus_of");
29*7051924fSEli Billauer MODULE_LICENSE("GPL v2");
30*7051924fSEli Billauer 
31*7051924fSEli Billauer static const char xillyname[] = "xillybus_of";
32*7051924fSEli Billauer 
33*7051924fSEli Billauer /* Match table for of_platform binding */
34*7051924fSEli Billauer static struct of_device_id xillybus_of_match[] = {
35*7051924fSEli Billauer 	{ .compatible = "xillybus,xillybus-1.00.a", },
36*7051924fSEli Billauer 	{ .compatible = "xlnx,xillybus-1.00.a", }, /* Deprecated */
37*7051924fSEli Billauer 	{}
38*7051924fSEli Billauer };
39*7051924fSEli Billauer 
40*7051924fSEli Billauer MODULE_DEVICE_TABLE(of, xillybus_of_match);
41*7051924fSEli Billauer 
42*7051924fSEli Billauer static void xilly_dma_sync_single_for_cpu_of(struct xilly_endpoint *ep,
43*7051924fSEli Billauer 					     dma_addr_t dma_handle,
44*7051924fSEli Billauer 					     size_t size,
45*7051924fSEli Billauer 					     int direction)
46*7051924fSEli Billauer {
47*7051924fSEli Billauer 	dma_sync_single_for_cpu(ep->dev, dma_handle, size, direction);
48*7051924fSEli Billauer }
49*7051924fSEli Billauer 
50*7051924fSEli Billauer static void xilly_dma_sync_single_for_device_of(struct xilly_endpoint *ep,
51*7051924fSEli Billauer 						dma_addr_t dma_handle,
52*7051924fSEli Billauer 						size_t size,
53*7051924fSEli Billauer 						int direction)
54*7051924fSEli Billauer {
55*7051924fSEli Billauer 	dma_sync_single_for_device(ep->dev, dma_handle, size, direction);
56*7051924fSEli Billauer }
57*7051924fSEli Billauer 
58*7051924fSEli Billauer static void xilly_dma_sync_single_nop(struct xilly_endpoint *ep,
59*7051924fSEli Billauer 				      dma_addr_t dma_handle,
60*7051924fSEli Billauer 				      size_t size,
61*7051924fSEli Billauer 				      int direction)
62*7051924fSEli Billauer {
63*7051924fSEli Billauer }
64*7051924fSEli Billauer 
65*7051924fSEli Billauer static void xilly_of_unmap(void *ptr)
66*7051924fSEli Billauer {
67*7051924fSEli Billauer 	struct xilly_mapping *data = ptr;
68*7051924fSEli Billauer 
69*7051924fSEli Billauer 	dma_unmap_single(data->device, data->dma_addr,
70*7051924fSEli Billauer 			 data->size, data->direction);
71*7051924fSEli Billauer 
72*7051924fSEli Billauer 	kfree(ptr);
73*7051924fSEli Billauer }
74*7051924fSEli Billauer 
75*7051924fSEli Billauer static int xilly_map_single_of(struct xilly_endpoint *ep,
76*7051924fSEli Billauer 			       void *ptr,
77*7051924fSEli Billauer 			       size_t size,
78*7051924fSEli Billauer 			       int direction,
79*7051924fSEli Billauer 			       dma_addr_t *ret_dma_handle
80*7051924fSEli Billauer 	)
81*7051924fSEli Billauer {
82*7051924fSEli Billauer 	dma_addr_t addr;
83*7051924fSEli Billauer 	struct xilly_mapping *this;
84*7051924fSEli Billauer 	int rc;
85*7051924fSEli Billauer 
86*7051924fSEli Billauer 	this = kzalloc(sizeof(*this), GFP_KERNEL);
87*7051924fSEli Billauer 	if (!this)
88*7051924fSEli Billauer 		return -ENOMEM;
89*7051924fSEli Billauer 
90*7051924fSEli Billauer 	addr = dma_map_single(ep->dev, ptr, size, direction);
91*7051924fSEli Billauer 
92*7051924fSEli Billauer 	if (dma_mapping_error(ep->dev, addr)) {
93*7051924fSEli Billauer 		kfree(this);
94*7051924fSEli Billauer 		return -ENODEV;
95*7051924fSEli Billauer 	}
96*7051924fSEli Billauer 
97*7051924fSEli Billauer 	this->device = ep->dev;
98*7051924fSEli Billauer 	this->dma_addr = addr;
99*7051924fSEli Billauer 	this->size = size;
100*7051924fSEli Billauer 	this->direction = direction;
101*7051924fSEli Billauer 
102*7051924fSEli Billauer 	*ret_dma_handle = addr;
103*7051924fSEli Billauer 
104*7051924fSEli Billauer 	rc = devm_add_action(ep->dev, xilly_of_unmap, this);
105*7051924fSEli Billauer 
106*7051924fSEli Billauer 	if (rc) {
107*7051924fSEli Billauer 		dma_unmap_single(ep->dev, addr, size, direction);
108*7051924fSEli Billauer 		kfree(this);
109*7051924fSEli Billauer 		return rc;
110*7051924fSEli Billauer 	}
111*7051924fSEli Billauer 
112*7051924fSEli Billauer 	return 0;
113*7051924fSEli Billauer }
114*7051924fSEli Billauer 
115*7051924fSEli Billauer static struct xilly_endpoint_hardware of_hw = {
116*7051924fSEli Billauer 	.owner = THIS_MODULE,
117*7051924fSEli Billauer 	.hw_sync_sgl_for_cpu = xilly_dma_sync_single_for_cpu_of,
118*7051924fSEli Billauer 	.hw_sync_sgl_for_device = xilly_dma_sync_single_for_device_of,
119*7051924fSEli Billauer 	.map_single = xilly_map_single_of,
120*7051924fSEli Billauer };
121*7051924fSEli Billauer 
122*7051924fSEli Billauer static struct xilly_endpoint_hardware of_hw_coherent = {
123*7051924fSEli Billauer 	.owner = THIS_MODULE,
124*7051924fSEli Billauer 	.hw_sync_sgl_for_cpu = xilly_dma_sync_single_nop,
125*7051924fSEli Billauer 	.hw_sync_sgl_for_device = xilly_dma_sync_single_nop,
126*7051924fSEli Billauer 	.map_single = xilly_map_single_of,
127*7051924fSEli Billauer };
128*7051924fSEli Billauer 
129*7051924fSEli Billauer static int xilly_drv_probe(struct platform_device *op)
130*7051924fSEli Billauer {
131*7051924fSEli Billauer 	struct device *dev = &op->dev;
132*7051924fSEli Billauer 	struct xilly_endpoint *endpoint;
133*7051924fSEli Billauer 	int rc;
134*7051924fSEli Billauer 	int irq;
135*7051924fSEli Billauer 	struct resource res;
136*7051924fSEli Billauer 	struct xilly_endpoint_hardware *ephw = &of_hw;
137*7051924fSEli Billauer 
138*7051924fSEli Billauer 	if (of_property_read_bool(dev->of_node, "dma-coherent"))
139*7051924fSEli Billauer 		ephw = &of_hw_coherent;
140*7051924fSEli Billauer 
141*7051924fSEli Billauer 	endpoint = xillybus_init_endpoint(NULL, dev, ephw);
142*7051924fSEli Billauer 
143*7051924fSEli Billauer 	if (!endpoint)
144*7051924fSEli Billauer 		return -ENOMEM;
145*7051924fSEli Billauer 
146*7051924fSEli Billauer 	dev_set_drvdata(dev, endpoint);
147*7051924fSEli Billauer 
148*7051924fSEli Billauer 	rc = of_address_to_resource(dev->of_node, 0, &res);
149*7051924fSEli Billauer 	endpoint->registers = devm_ioremap_resource(dev, &res);
150*7051924fSEli Billauer 
151*7051924fSEli Billauer 	if (IS_ERR(endpoint->registers))
152*7051924fSEli Billauer 		return PTR_ERR(endpoint->registers);
153*7051924fSEli Billauer 
154*7051924fSEli Billauer 	irq = irq_of_parse_and_map(dev->of_node, 0);
155*7051924fSEli Billauer 
156*7051924fSEli Billauer 	rc = devm_request_irq(dev, irq, xillybus_isr, 0, xillyname, endpoint);
157*7051924fSEli Billauer 
158*7051924fSEli Billauer 	if (rc) {
159*7051924fSEli Billauer 		dev_err(endpoint->dev,
160*7051924fSEli Billauer 			"Failed to register IRQ handler. Aborting.\n");
161*7051924fSEli Billauer 		return -ENODEV;
162*7051924fSEli Billauer 	}
163*7051924fSEli Billauer 
164*7051924fSEli Billauer 	return xillybus_endpoint_discovery(endpoint);
165*7051924fSEli Billauer }
166*7051924fSEli Billauer 
167*7051924fSEli Billauer static int xilly_drv_remove(struct platform_device *op)
168*7051924fSEli Billauer {
169*7051924fSEli Billauer 	struct device *dev = &op->dev;
170*7051924fSEli Billauer 	struct xilly_endpoint *endpoint = dev_get_drvdata(dev);
171*7051924fSEli Billauer 
172*7051924fSEli Billauer 	xillybus_endpoint_remove(endpoint);
173*7051924fSEli Billauer 
174*7051924fSEli Billauer 	return 0;
175*7051924fSEli Billauer }
176*7051924fSEli Billauer 
177*7051924fSEli Billauer static struct platform_driver xillybus_platform_driver = {
178*7051924fSEli Billauer 	.probe = xilly_drv_probe,
179*7051924fSEli Billauer 	.remove = xilly_drv_remove,
180*7051924fSEli Billauer 	.driver = {
181*7051924fSEli Billauer 		.name = xillyname,
182*7051924fSEli Billauer 		.owner = THIS_MODULE,
183*7051924fSEli Billauer 		.of_match_table = xillybus_of_match,
184*7051924fSEli Billauer 	},
185*7051924fSEli Billauer };
186*7051924fSEli Billauer 
187*7051924fSEli Billauer module_platform_driver(xillybus_platform_driver);
188