UIO: Add of_platform_driver to uio_pdrv_genirq
PATCH 1/1 UIO: Add of_platform_driver to uio_pdrv_genirq
Make the uio-driver with generic irq handling also accessible for of_devices.
Signed-off-by Wolfram Sang <[email protected]>
---
I hope the compatible-tag "generic-uio" is apropriate. Please CC me when replying.
drivers/uio/uio_pdrv_genirq.c | 178 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 154 insertions(+), 24 deletions(-)
drivers/uio/uio_pdrv_genirq.c +154 -24
@@ -1,13 +1,15 @@/* * drivers/uio/uio_pdrv_genirq.c * -* Userspace I/O platform driver with generic IRQ handling code. +* Userspace I/O platform & of driver with generic IRQ handling code. * * Copyright (C) 2008 Magnus Damm +* Copyright (C) 2008 Wolfram Sang, Pengutronix * * Based on uio_pdrv.c by Uwe Kleine-Koenig, * Copyright (C) 2008 by Digi International Inc. * All rights reserved. +* Adding of_platform_driver based on xilinxfb.c by Grant Likely. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by
@@ -20,6 +22,10 @@#include <linux/bitops.h> #include <linux/interrupt.h> #include <linux/stringify.h> +#if defined(CONFIG_OF ) +#include <linux/of_device.h> +#include <linux/of_platform.h> +#endif #define DRIVER_NAME "uio_pdrv_genirq"
@@ -68,28 +74,18 @@return 0 ; } -static int uio_pdrv_genirq_probe (struct platform_device *pdev) +static int uio_pdrv_genirq_setup (struct device *dev,struct uio_info *uioinfo, +struct resource *resources,unsigned int num_resources) { -struct uio_info *uioinfo = pdev->dev.platform_data;struct uio_pdrv_genirq_platdata *priv;struct uio_mem *uiomem; -int ret = -EINVAL ; -int i; - -if (!uioinfo || !uioinfo->name || !uioinfo->version) { -dev_err (&pdev->dev,"missing platform_data\n" ); - goto bad0; - } - -if (uioinfo->handler || uioinfo->irqcontrol || uioinfo->irq_flags) { -dev_err (&pdev->dev,"interrupt configuration error\n" ); - goto bad0; - } +unsigned int i; +int ret; priv =kzalloc (sizeof (*priv),GFP_KERNEL );if (!priv) { ret = -ENOMEM ; -dev_err (&pdev->dev,"unable to kmalloc\n" ); +dev_err (dev,"unable to kmalloc\n" ); goto bad0; }
@@ -99,14 +95,15 @@ uiomem = &uioinfo->mem[0 ]; -for (i =0 ; i < pdev->num_resources; ++i) { -struct resource *r = &pdev->resource[i]; +for (i =0 ; i < num_resources; ++i) { + +struct resource *r = resources + i;if (r->flags !=IORESOURCE_MEM )continue ;if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS ]) { - dev_warn(&pdev->dev, "device has more than " + dev_warn(dev, "device has more than " __stringify(MAX_UIO_MAPS)" I/O memory resources.\n" );break ;
@@ -137,13 +134,13 @@ uioinfo->irqcontrol = uio_pdrv_genirq_irqcontrol; uioinfo->priv = priv; - ret =uio_register_device (&pdev->dev, priv->uioinfo); + ret =uio_register_device (dev, priv->uioinfo);if (ret) { -dev_err (&pdev->dev,"unable to register uio device\n" ); +dev_err (dev,"unable to register uio device\n" ); goto bad1; } -platform_set_drvdata (pdev, priv); +dev_set_drvdata (dev, priv);return 0 ; bad1:kfree (priv);
@@ -151,6 +148,24 @@return ret; } +static int uio_pdrv_genirq_probe (struct platform_device *pdev) +{ +struct uio_info *uioinfo = pdev->dev.platform_data; + +if (!uioinfo || !uioinfo->name || !uioinfo->version) { +dev_err (&pdev->dev,"missing platform_data\n" ); +return -EINVAL ; + } + +if (uioinfo->handler || uioinfo->irqcontrol || uioinfo->irq_flags) { +dev_err (&pdev->dev,"interrupt configuration error\n" ); +return -EINVAL ; + } + +return uio_pdrv_genirq_setup (&pdev->dev, uioinfo, pdev->resource, + pdev->num_resources); +} +static int uio_pdrv_genirq_remove (struct platform_device *pdev) {struct uio_pdrv_genirq_platdata *priv =platform_get_drvdata (pdev);
@@ -169,20 +184,135 @@ }, }; +/* --------------------------------------------------------------------- +* OF bus binding +*/ + +#if defined(CONFIG_OF ) + +#define OF_DRIVER_NAME "uio_of_genirq" +#define OF_DRIVER_VERSION "1" + +static int uio_of_genirq_probe (struct of_device *op, +const struct of_device_id *match) +{ +struct uio_info *uioinfo; +struct resource *resources; +int i, ret = -ENOMEM ; + + uioinfo =kzalloc (sizeof (*uioinfo),GFP_KERNEL ); +if (!uioinfo) + goto bad0; + + uioinfo->name = (char *)of_get_property (op->node,"name" ,NULL ); +if (!uioinfo->name) { + ret = -ENODEV ; +dev_err (&op->dev,"could not get node name\n" ); + goto bad1; + } + + uioinfo->version =OF_DRIVER_VERSION ; + uioinfo->irq =irq_of_parse_and_map (op->node,0 ); +if (!uioinfo->irq) + uioinfo->irq =UIO_IRQ_NONE ; + + resources =kzalloc (MAX_UIO_MAPS *sizeof (struct resource ),GFP_KERNEL ); +if (!resources) + goto bad2; + +for (i =0 ; i <MAX_UIO_MAPS ; ++i) +if (of_address_to_resource (op->node, i, resources + i)) +break ; + + ret =uio_pdrv_genirq_setup (&op->dev, uioinfo, resources, i); +kfree (resources); +if (ret) + goto bad2; + +return 0 ; + + bad2: +if (uioinfo->irq !=UIO_IRQ_NONE ) +irq_dispose_mapping (uioinfo->irq); + bad1: +kfree (uioinfo); + bad0: +return ret; +} + +static int uio_of_genirq_remove (struct of_device *op) +{ +struct uio_pdrv_genirq_platdata *priv =dev_get_drvdata (&op->dev); + +uio_unregister_device (priv->uioinfo); + +if (priv->uioinfo->irq !=UIO_IRQ_NONE ) +irq_dispose_mapping (priv->uioinfo->irq); + +kfree (priv->uioinfo); +kfree (priv); +return 0 ; +} + +/* Match table for of_platform binding */ +static struct of_device_id uio_of_genirq_match[] = { + { .compatible ="generic-uio" , }, + {}, +}; +MODULE_DEVICE_TABLE (of, uio_of_genirq_match); + +static struct of_platform_driver uio_of_genirq_driver = { + .owner =THIS_MODULE , + .name =OF_DRIVER_NAME , + .match_table = uio_of_genirq_match, + .probe = uio_of_genirq_probe, + .remove = uio_of_genirq_remove, +}; + +/* Registration helpers to keep the number of #ifdefs to a minimum */ +static inline int __init uio_of_genirq_register (void ) +{ +return of_register_platform_driver (&uio_of_genirq_driver); +} + +static inline void __exit uio_of_genirq_unregister(void) +{ +of_unregister_platform_driver (&uio_of_genirq_driver); +} +#else /* CONFIG_OF */ +/* CONFIG_OF not enabled; do nothing helpers */ +static inline int __init uio_of_genirq_register (void ) {return 0 ; } +static inline void __exit uio_of_genirq_unregister(void) { } +#endif /* CONFIG_OF */ + +/* --------------------------------------------------------------------- */ +static int __init uio_pdrv_genirq_init (void ) { -return platform_driver_register (&uio_pdrv_genirq); +int retval; + + retval =uio_of_genirq_register (); +if (retval) +return retval; + + retval =platform_driver_register (&uio_pdrv_genirq); +if (retval) +uio_of_genirq_unregister (); + +return retval; } static void __exit uio_pdrv_genirq_exit(void) {platform_driver_unregister (&uio_pdrv_genirq); +uio_of_genirq_unregister (); }module_init (uio_pdrv_genirq_init);module_exit (uio_pdrv_genirq_exit);MODULE_AUTHOR ("Magnus Damm" ); -MODULE_DESCRIPTION ("Userspace I/O platform driver with generic IRQ handling" ); +MODULE_DESCRIPTION ("Userspace I/O platform & of driver with generic" +"IRQ handling" );MODULE_LICENSE ("GPL v2" );MODULE_ALIAS ("platform:" DRIVER_NAME );
Signature · 2 lines
Dipl.-Ing. Wolfram Sang | http://www.pengutronix.de Pengutronix - Linux Solutions for Science and Industry