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