17051924fSEli Billauer /* 27051924fSEli Billauer * linux/drivers/misc/xillybus_of.c 37051924fSEli Billauer * 47051924fSEli Billauer * Copyright 2011 Xillybus Ltd, http://xillybus.com 57051924fSEli Billauer * 67051924fSEli Billauer * Driver for the Xillybus FPGA/host framework using Open Firmware. 77051924fSEli Billauer * 87051924fSEli Billauer * This program is free software; you can redistribute it and/or modify 97051924fSEli Billauer * it under the smems of the GNU General Public License as published by 107051924fSEli Billauer * the Free Software Foundation; version 2 of the License. 117051924fSEli Billauer */ 127051924fSEli Billauer 137051924fSEli Billauer #include <linux/module.h> 147051924fSEli Billauer #include <linux/device.h> 157051924fSEli Billauer #include <linux/slab.h> 167051924fSEli Billauer #include <linux/platform_device.h> 177051924fSEli Billauer #include <linux/of.h> 187051924fSEli Billauer #include <linux/of_irq.h> 197051924fSEli Billauer #include <linux/of_address.h> 207051924fSEli Billauer #include <linux/of_device.h> 217051924fSEli Billauer #include <linux/of_platform.h> 227051924fSEli Billauer #include <linux/err.h> 237051924fSEli Billauer #include "xillybus.h" 247051924fSEli Billauer 257051924fSEli Billauer MODULE_DESCRIPTION("Xillybus driver for Open Firmware"); 267051924fSEli Billauer MODULE_AUTHOR("Eli Billauer, Xillybus Ltd."); 277051924fSEli Billauer MODULE_VERSION("1.06"); 287051924fSEli Billauer MODULE_ALIAS("xillybus_of"); 297051924fSEli Billauer MODULE_LICENSE("GPL v2"); 307051924fSEli Billauer 317051924fSEli Billauer static const char xillyname[] = "xillybus_of"; 327051924fSEli Billauer 337051924fSEli Billauer /* Match table for of_platform binding */ 34*da2ff527SFabian Frederick static const struct of_device_id xillybus_of_match[] = { 357051924fSEli Billauer { .compatible = "xillybus,xillybus-1.00.a", }, 367051924fSEli Billauer { .compatible = "xlnx,xillybus-1.00.a", }, /* Deprecated */ 377051924fSEli Billauer {} 387051924fSEli Billauer }; 397051924fSEli Billauer 407051924fSEli Billauer MODULE_DEVICE_TABLE(of, xillybus_of_match); 417051924fSEli Billauer 427051924fSEli Billauer static void xilly_dma_sync_single_for_cpu_of(struct xilly_endpoint *ep, 437051924fSEli Billauer dma_addr_t dma_handle, 447051924fSEli Billauer size_t size, 457051924fSEli Billauer int direction) 467051924fSEli Billauer { 477051924fSEli Billauer dma_sync_single_for_cpu(ep->dev, dma_handle, size, direction); 487051924fSEli Billauer } 497051924fSEli Billauer 507051924fSEli Billauer static void xilly_dma_sync_single_for_device_of(struct xilly_endpoint *ep, 517051924fSEli Billauer dma_addr_t dma_handle, 527051924fSEli Billauer size_t size, 537051924fSEli Billauer int direction) 547051924fSEli Billauer { 557051924fSEli Billauer dma_sync_single_for_device(ep->dev, dma_handle, size, direction); 567051924fSEli Billauer } 577051924fSEli Billauer 587051924fSEli Billauer static void xilly_dma_sync_single_nop(struct xilly_endpoint *ep, 597051924fSEli Billauer dma_addr_t dma_handle, 607051924fSEli Billauer size_t size, 617051924fSEli Billauer int direction) 627051924fSEli Billauer { 637051924fSEli Billauer } 647051924fSEli Billauer 657051924fSEli Billauer static void xilly_of_unmap(void *ptr) 667051924fSEli Billauer { 677051924fSEli Billauer struct xilly_mapping *data = ptr; 687051924fSEli Billauer 697051924fSEli Billauer dma_unmap_single(data->device, data->dma_addr, 707051924fSEli Billauer data->size, data->direction); 717051924fSEli Billauer 727051924fSEli Billauer kfree(ptr); 737051924fSEli Billauer } 747051924fSEli Billauer 757051924fSEli Billauer static int xilly_map_single_of(struct xilly_endpoint *ep, 767051924fSEli Billauer void *ptr, 777051924fSEli Billauer size_t size, 787051924fSEli Billauer int direction, 797051924fSEli Billauer dma_addr_t *ret_dma_handle 807051924fSEli Billauer ) 817051924fSEli Billauer { 827051924fSEli Billauer dma_addr_t addr; 837051924fSEli Billauer struct xilly_mapping *this; 847051924fSEli Billauer int rc; 857051924fSEli Billauer 867051924fSEli Billauer this = kzalloc(sizeof(*this), GFP_KERNEL); 877051924fSEli Billauer if (!this) 887051924fSEli Billauer return -ENOMEM; 897051924fSEli Billauer 907051924fSEli Billauer addr = dma_map_single(ep->dev, ptr, size, direction); 917051924fSEli Billauer 927051924fSEli Billauer if (dma_mapping_error(ep->dev, addr)) { 937051924fSEli Billauer kfree(this); 947051924fSEli Billauer return -ENODEV; 957051924fSEli Billauer } 967051924fSEli Billauer 977051924fSEli Billauer this->device = ep->dev; 987051924fSEli Billauer this->dma_addr = addr; 997051924fSEli Billauer this->size = size; 1007051924fSEli Billauer this->direction = direction; 1017051924fSEli Billauer 1027051924fSEli Billauer *ret_dma_handle = addr; 1037051924fSEli Billauer 1047051924fSEli Billauer rc = devm_add_action(ep->dev, xilly_of_unmap, this); 1057051924fSEli Billauer 1067051924fSEli Billauer if (rc) { 1077051924fSEli Billauer dma_unmap_single(ep->dev, addr, size, direction); 1087051924fSEli Billauer kfree(this); 1097051924fSEli Billauer return rc; 1107051924fSEli Billauer } 1117051924fSEli Billauer 1127051924fSEli Billauer return 0; 1137051924fSEli Billauer } 1147051924fSEli Billauer 1157051924fSEli Billauer static struct xilly_endpoint_hardware of_hw = { 1167051924fSEli Billauer .owner = THIS_MODULE, 1177051924fSEli Billauer .hw_sync_sgl_for_cpu = xilly_dma_sync_single_for_cpu_of, 1187051924fSEli Billauer .hw_sync_sgl_for_device = xilly_dma_sync_single_for_device_of, 1197051924fSEli Billauer .map_single = xilly_map_single_of, 1207051924fSEli Billauer }; 1217051924fSEli Billauer 1227051924fSEli Billauer static struct xilly_endpoint_hardware of_hw_coherent = { 1237051924fSEli Billauer .owner = THIS_MODULE, 1247051924fSEli Billauer .hw_sync_sgl_for_cpu = xilly_dma_sync_single_nop, 1257051924fSEli Billauer .hw_sync_sgl_for_device = xilly_dma_sync_single_nop, 1267051924fSEli Billauer .map_single = xilly_map_single_of, 1277051924fSEli Billauer }; 1287051924fSEli Billauer 1297051924fSEli Billauer static int xilly_drv_probe(struct platform_device *op) 1307051924fSEli Billauer { 1317051924fSEli Billauer struct device *dev = &op->dev; 1327051924fSEli Billauer struct xilly_endpoint *endpoint; 1337051924fSEli Billauer int rc; 1347051924fSEli Billauer int irq; 1357051924fSEli Billauer struct resource res; 1367051924fSEli Billauer struct xilly_endpoint_hardware *ephw = &of_hw; 1377051924fSEli Billauer 1387051924fSEli Billauer if (of_property_read_bool(dev->of_node, "dma-coherent")) 1397051924fSEli Billauer ephw = &of_hw_coherent; 1407051924fSEli Billauer 1417051924fSEli Billauer endpoint = xillybus_init_endpoint(NULL, dev, ephw); 1427051924fSEli Billauer 1437051924fSEli Billauer if (!endpoint) 1447051924fSEli Billauer return -ENOMEM; 1457051924fSEli Billauer 1467051924fSEli Billauer dev_set_drvdata(dev, endpoint); 1477051924fSEli Billauer 1487051924fSEli Billauer rc = of_address_to_resource(dev->of_node, 0, &res); 1497051924fSEli Billauer endpoint->registers = devm_ioremap_resource(dev, &res); 1507051924fSEli Billauer 1517051924fSEli Billauer if (IS_ERR(endpoint->registers)) 1527051924fSEli Billauer return PTR_ERR(endpoint->registers); 1537051924fSEli Billauer 1547051924fSEli Billauer irq = irq_of_parse_and_map(dev->of_node, 0); 1557051924fSEli Billauer 1567051924fSEli Billauer rc = devm_request_irq(dev, irq, xillybus_isr, 0, xillyname, endpoint); 1577051924fSEli Billauer 1587051924fSEli Billauer if (rc) { 1597051924fSEli Billauer dev_err(endpoint->dev, 1607051924fSEli Billauer "Failed to register IRQ handler. Aborting.\n"); 1617051924fSEli Billauer return -ENODEV; 1627051924fSEli Billauer } 1637051924fSEli Billauer 1647051924fSEli Billauer return xillybus_endpoint_discovery(endpoint); 1657051924fSEli Billauer } 1667051924fSEli Billauer 1677051924fSEli Billauer static int xilly_drv_remove(struct platform_device *op) 1687051924fSEli Billauer { 1697051924fSEli Billauer struct device *dev = &op->dev; 1707051924fSEli Billauer struct xilly_endpoint *endpoint = dev_get_drvdata(dev); 1717051924fSEli Billauer 1727051924fSEli Billauer xillybus_endpoint_remove(endpoint); 1737051924fSEli Billauer 1747051924fSEli Billauer return 0; 1757051924fSEli Billauer } 1767051924fSEli Billauer 1777051924fSEli Billauer static struct platform_driver xillybus_platform_driver = { 1787051924fSEli Billauer .probe = xilly_drv_probe, 1797051924fSEli Billauer .remove = xilly_drv_remove, 1807051924fSEli Billauer .driver = { 1817051924fSEli Billauer .name = xillyname, 1827051924fSEli Billauer .of_match_table = xillybus_of_match, 1837051924fSEli Billauer }, 1847051924fSEli Billauer }; 1857051924fSEli Billauer 1867051924fSEli Billauer module_platform_driver(xillybus_platform_driver); 187