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