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 25MODULE_DESCRIPTION("Xillybus driver for Open Firmware"); 26MODULE_AUTHOR("Eli Billauer, Xillybus Ltd."); 27MODULE_VERSION("1.06"); 28MODULE_ALIAS("xillybus_of"); 29MODULE_LICENSE("GPL v2"); 30 31static const char xillyname[] = "xillybus_of"; 32 33/* Match table for of_platform binding */ 34static 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 40MODULE_DEVICE_TABLE(of, xillybus_of_match); 41 42static 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 50static 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 58static 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 65static 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 75static 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 int rc; 85 86 this = kzalloc(sizeof(*this), GFP_KERNEL); 87 if (!this) 88 return -ENOMEM; 89 90 addr = dma_map_single(ep->dev, ptr, size, direction); 91 92 if (dma_mapping_error(ep->dev, addr)) { 93 kfree(this); 94 return -ENODEV; 95 } 96 97 this->device = ep->dev; 98 this->dma_addr = addr; 99 this->size = size; 100 this->direction = direction; 101 102 *ret_dma_handle = addr; 103 104 rc = devm_add_action(ep->dev, xilly_of_unmap, this); 105 106 if (rc) { 107 dma_unmap_single(ep->dev, addr, size, direction); 108 kfree(this); 109 return rc; 110 } 111 112 return 0; 113} 114 115static struct xilly_endpoint_hardware of_hw = { 116 .owner = THIS_MODULE, 117 .hw_sync_sgl_for_cpu = xilly_dma_sync_single_for_cpu_of, 118 .hw_sync_sgl_for_device = xilly_dma_sync_single_for_device_of, 119 .map_single = xilly_map_single_of, 120}; 121 122static struct xilly_endpoint_hardware of_hw_coherent = { 123 .owner = THIS_MODULE, 124 .hw_sync_sgl_for_cpu = xilly_dma_sync_single_nop, 125 .hw_sync_sgl_for_device = xilly_dma_sync_single_nop, 126 .map_single = xilly_map_single_of, 127}; 128 129static int xilly_drv_probe(struct platform_device *op) 130{ 131 struct device *dev = &op->dev; 132 struct xilly_endpoint *endpoint; 133 int rc; 134 int irq; 135 struct resource res; 136 struct xilly_endpoint_hardware *ephw = &of_hw; 137 138 if (of_property_read_bool(dev->of_node, "dma-coherent")) 139 ephw = &of_hw_coherent; 140 141 endpoint = xillybus_init_endpoint(NULL, dev, ephw); 142 143 if (!endpoint) 144 return -ENOMEM; 145 146 dev_set_drvdata(dev, endpoint); 147 148 rc = of_address_to_resource(dev->of_node, 0, &res); 149 endpoint->registers = devm_ioremap_resource(dev, &res); 150 151 if (IS_ERR(endpoint->registers)) 152 return PTR_ERR(endpoint->registers); 153 154 irq = irq_of_parse_and_map(dev->of_node, 0); 155 156 rc = devm_request_irq(dev, irq, xillybus_isr, 0, xillyname, endpoint); 157 158 if (rc) { 159 dev_err(endpoint->dev, 160 "Failed to register IRQ handler. Aborting.\n"); 161 return -ENODEV; 162 } 163 164 return xillybus_endpoint_discovery(endpoint); 165} 166 167static int xilly_drv_remove(struct platform_device *op) 168{ 169 struct device *dev = &op->dev; 170 struct xilly_endpoint *endpoint = dev_get_drvdata(dev); 171 172 xillybus_endpoint_remove(endpoint); 173 174 return 0; 175} 176 177static struct platform_driver xillybus_platform_driver = { 178 .probe = xilly_drv_probe, 179 .remove = xilly_drv_remove, 180 .driver = { 181 .name = xillyname, 182 .of_match_table = xillybus_of_match, 183 }, 184}; 185 186module_platform_driver(xillybus_platform_driver); 187