diff options
Diffstat (limited to 'target/linux/ubicom32/files/arch/ubicom32/mach-common/ring_tio.c')
-rw-r--r-- | target/linux/ubicom32/files/arch/ubicom32/mach-common/ring_tio.c | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/ring_tio.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/ring_tio.c new file mode 100644 index 000000000..9d0f8cd2a --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/ring_tio.c @@ -0,0 +1,123 @@ +/* + * arch/ubicom32/mach-common/ring_tio.c + * Generic initialization for UIO Ubicom32 Ring + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see <http://www.gnu.org/licenses/>. + */ + +#include <linux/platform_device.h> +#include <linux/types.h> + +#include <asm/devtree.h> +#include <asm/ring_tio.h> + +static const char *ring_tio_driver_name = "uio_ubicom32ring"; + +/* + * The number of ring_tio's currently allocated, used for .id + */ +static int __initdata ring_tio_count; + +/* + * The maximum number of resources that the ring_tio will have. + * Currently 3, a register space, and up to 2 interrupts. + */ +#define RING_TIO_MAX_RESOURCES 3 + +/* + * ring_tio_init + * Checks the device tree and instantiates the driver if found + */ +void __init ring_tio_init(const char *node_name) +{ + struct platform_device *pdev; + struct resource *res; + int resource_idx = 0; + struct ring_tio_node *ring_node; + + /* + * Check the device tree for the ring_tio + */ + ring_node = (struct ring_tio_node *)devtree_find_node(node_name); + if (!ring_node) { + printk(KERN_WARNING "Ring TIO '%s' not found\n", node_name); + return; + } + + if (ring_node->version != RING_TIO_NODE_VERSION) { + printk(KERN_WARNING "ring_tio not compatible\n"); + return; + } + + /* + * Dynamically create the platform_device structure and resources + */ + pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL); + if (!pdev) { + printk(KERN_WARNING "ring_tio could not alloc pdev\n"); + return; + } + + res = kzalloc(sizeof(struct resource) * RING_TIO_MAX_RESOURCES, + GFP_KERNEL); + if (!res) { + kfree(pdev); + printk(KERN_WARNING "ring_tio could not alloc res\n"); + return; + } + + pdev->name = ring_tio_driver_name; + pdev->id = ring_tio_count++; + pdev->resource = res; + + /* + * Fill in the resources and platform data from devtree information + */ + res[resource_idx].start = (u32_t)(ring_node->regs); + res[resource_idx].end = (u32_t)(ring_node->regs); + res[resource_idx].flags = IORESOURCE_MEM; + resource_idx++; + + if (ring_node->dn.sendirq != 0xFF) { + res[resource_idx].start = ring_node->dn.sendirq; + res[resource_idx].flags = IORESOURCE_IRQ; + resource_idx++; + } + + if (ring_node->dn.recvirq != 0xFF) { + res[resource_idx].start = ring_node->dn.recvirq; + res[resource_idx].flags = IORESOURCE_IRQ; + resource_idx++; + } + pdev->num_resources = resource_idx; + + printk(KERN_INFO "RingTIO.%d '%s' found irq=%d/%d regs=%p pdev=%p/%p\n", + ring_tio_count - 1, node_name, ring_node->dn.sendirq, + ring_node->dn.recvirq, ring_node->regs, pdev, res); + + /* + * Try to get the device registered + */ + pdev->dev.platform_data = (void *)node_name; + if (platform_device_register(pdev) < 0) { + printk(KERN_WARNING "Ring failed to register\n"); + kfree(pdev); + kfree(res); + } +} |