Guest User

Untitled

a guest
Jul 9th, 2013
917
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.  * drivers/uio/uio_pdrv_genirq.c
  3.  *
  4.  * Userspace I/O platform driver with generic IRQ handling code.
  5.  *
  6.  * Copyright (C) 2008 Magnus Damm
  7.  *
  8.  * Based on uio_pdrv.c by Uwe Kleine-Koenig,
  9.  * Copyright (C) 2008 by Digi International Inc.
  10.  * All rights reserved.
  11.  *
  12.  * This program is free software; you can redistribute it and/or modify it
  13.  * under the terms of the GNU General Public License version 2 as published by
  14.  * the Free Software Foundation.
  15.  */
  16.  
  17. #include <linux/platform_device.h>
  18. #include <linux/uio_driver.h>
  19. #include <linux/spinlock.h>
  20. #include <linux/bitops.h>
  21. #include <linux/interrupt.h>
  22. #include <linux/pm_runtime.h>
  23. #include <linux/slab.h>
  24. #include <asm/io.h>
  25. #include "uioDrv.h"
  26.  
  27. #define MAXIRQ 10000
  28. static struct uio_info *uioinfo;
  29. static unsigned int timerVal[MAXIRQ];
  30. static int irqc;
  31.  
  32. /*
  33.  * Called when associated /dev/uioX device is opened from userspace
  34.  *
  35.  * Does nothing. All required initalization is done in user space part
  36.  */
  37. static int xilAxiTimer_open(struct uio_info *info, struct inode *inode)
  38. {
  39.         return 0;
  40. }
  41.  
  42. /*
  43.  * Called when associated /dev/uioX device is closed from userspace
  44.  *
  45.  * Disable timer.
  46.  */
  47. static int xilAxiTimer_release(struct uio_info *info, struct inode *inode)
  48. {
  49.         volatile unsigned char *iomem = uioinfo->mem[0].internal_addr;
  50.  
  51.         iowrite32(0, iomem + TC0_CS_REG);
  52.         return 0;
  53. }
  54.  
  55. /*
  56.  * Interrupt service routine:
  57.  * Interrupt is cleared in IP core and the timer value is saved(, though
  58.  * I don't know how to make that value accessible from userspace).
  59.  * Any further handling is done in user space part of driver.
  60.  */
  61. static irqreturn_t xilAxiTimer_isr(int irq, struct uio_info *dev_info)
  62. {
  63.         unsigned int tmp;
  64.         volatile unsigned char *iomem = uioinfo->mem[0].internal_addr;
  65.         /* Just disable the interrupt in the interrupt controller, and
  66.          * remember the state so we can allow user space to enable it later.
  67.          */
  68.  
  69. //      if (!test_and_set_bit(0, &uioinfo->irq_flags))
  70. //              disable_irq_nosync(irq);
  71.  
  72.         // save the timer value as soon as we get here
  73.         if (irqc < MAXIRQ)
  74.                 timerVal[irqc++] = ioread32(iomem + TC0_TC_REG);
  75.         // clear the interrupt in ipcore
  76.         tmp = ioread32(iomem + TC0_CS_REG);
  77.         tmp |= TC_T0INT;
  78.         iowrite32(tmp, iomem + TC0_CS_REG);
  79.  
  80.         return IRQ_HANDLED;
  81. }
  82.  
  83. /*
  84.  * Allow user space to enable and disable the interrupt
  85.  * in the interrupt controller, but keep track of the
  86.  * state to prevent per-irq depth damage.
  87.  *
  88.  * Serialize this operation to support multiple tasks.
  89.  * Writing 1/0 to the associated /dev/uioX enables/disables the interrupt.
  90.  */
  91. static int xilAxiTimer_irqcontrol(struct uio_info *dev_info, s32 irq_on)
  92. {
  93.         unsigned int tmp;
  94.         volatile unsigned char *iomem = uioinfo->mem[0].internal_addr;
  95.  
  96.         tmp = ioread32(iomem + TC0_CS_REG);
  97.         if(irq_on)
  98.                 tmp |= TC_ENIT0;
  99.         else
  100.                 tmp &= ~TC_ENIT0;
  101.         iowrite32(tmp, iomem + TC0_CS_REG);
  102.  
  103.         return 0;
  104. }
  105.  
  106. static int xilAxiTimer_probe(struct platform_device *pdev)
  107. {
  108.         int ret = -EINVAL;
  109.  
  110.         if (request_mem_region(TIMERBAR, IOREGIONSIZE, DEVICENAME) == NULL) {
  111.                 printk(KERN_WARNING "Memory region already in use.\n");
  112.                 return -EBUSY;
  113.         }
  114.  
  115.         uioinfo = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
  116.         if (uioinfo == NULL) {
  117.                 printk(KERN_WARNING "Unable to allocate memory.\n");
  118.                 release_mem_region(TIMERBAR, IOREGIONSIZE);
  119.                 return -ENOMEM;
  120.         }
  121.  
  122.         uioinfo->name = DEVICENAME;
  123.         uioinfo->version = DRVVERSION;
  124.         uioinfo->priv = NULL;
  125.         uioinfo->open = xilAxiTimer_open;
  126.         uioinfo->release = xilAxiTimer_release;
  127.         uioinfo->handler = xilAxiTimer_isr;
  128.         uioinfo->irqcontrol = xilAxiTimer_irqcontrol;
  129.         uioinfo->irq = 61;
  130.         uioinfo->irq_flags = IRQF_SHARED;
  131.         uioinfo->mem[0].name = "Registers";
  132.         uioinfo->mem[0].addr = TIMERBAR;
  133.         uioinfo->mem[0].size = IOREGIONSIZE;
  134.         uioinfo->mem[0].memtype = UIO_MEM_PHYS;
  135.         uioinfo->mem[0].internal_addr = ioremap(TIMERBAR, IOREGIONSIZE);
  136.  
  137.         if (uioinfo->mem[0].internal_addr == NULL) {
  138.                 printk(KERN_WARNING "Unable to remap memory.\n");
  139.                 release_mem_region(TIMERBAR, IOREGIONSIZE);
  140.                 return -ENOMEM;
  141.         }
  142.  
  143.         /* Enable Runtime PM for this device:
  144.          * The device starts in suspended state to allow the hardware to be
  145.          * turned off by default. The Runtime PM bus code should power on the
  146.          * hardware and enable clocks at open().
  147.          */
  148. //      pm_runtime_enable(&pdev->dev);
  149.  
  150.         ret = uio_register_device(&pdev->dev, uioinfo);
  151.         if (ret) {
  152.                 dev_err(&pdev->dev, "unable to register uio device\n");
  153.                 goto bad1;
  154.         }
  155.  
  156.         return 0;
  157.  
  158.       bad1:
  159. //      pm_runtime_disable(&pdev->dev);
  160.         iounmap(uioinfo->mem[0].internal_addr);
  161.         kfree(uioinfo);
  162.         release_mem_region(TIMERBAR, IOREGIONSIZE);
  163.         ret = -ENODEV;
  164.         return ret;
  165. }
  166.  
  167. static int xilAxiTimer_remove(struct platform_device *pdev)
  168. {
  169.         int i;
  170. //      pm_runtime_disable(&pdev->dev);
  171.         uio_unregister_device(uioinfo);
  172.         iounmap(uioinfo->mem[0].internal_addr);
  173.         kfree(uioinfo);
  174.         release_mem_region(TIMERBAR, IOREGIONSIZE);
  175.         for (i = 0; i < MAXIRQ; i++)
  176.                 printk(KERN_INFO "IRQ latency kernel(%d): %u\n", i, 0xfffff - timerVal[i]);
  177.         return 0;
  178. }
  179.  
  180. static int uio_pdrv_genirq_runtime_nop(struct device *dev)
  181. {
  182.         /* Runtime PM callback shared between ->runtime_suspend()
  183.          * and ->runtime_resume(). Simply returns success.
  184.          *
  185.          * In this driver pm_runtime_get_sync() and pm_runtime_put_sync()
  186.          * are used at open() and release() time. This allows the
  187.          * Runtime PM code to turn off power to the device while the
  188.          * device is unused, ie before open() and after release().
  189.          *
  190.          * This Runtime PM callback does not need to save or restore
  191.          * any registers since user space is responsbile for hardware
  192.          * register reinitialization after open().
  193.          */
  194.         return 0;
  195. }
  196.  
  197. static const struct dev_pm_ops uio_pdrv_genirq_dev_pm_ops = {
  198.         .runtime_suspend = uio_pdrv_genirq_runtime_nop,
  199.         .runtime_resume = uio_pdrv_genirq_runtime_nop,
  200. };
  201.  
  202. static struct platform_driver xilAxiTimerPdrv = {
  203.         .probe = xilAxiTimer_probe,
  204.         .remove = xilAxiTimer_remove,
  205.         .driver = {
  206.                    .name = "FABRICPARENT",
  207.                    .owner = THIS_MODULE,
  208.                    .pm = &uio_pdrv_genirq_dev_pm_ops,
  209.                    },
  210. };
  211.  
  212. static int __init xilAxiTimer_init(void)
  213. {
  214.         return platform_driver_register(&xilAxiTimerPdrv);
  215. }
  216.  
  217. static void __exit xilAxiTimer_exit(void)
  218. {
  219.         platform_driver_unregister(&xilAxiTimerPdrv);
  220. }
  221.  
  222. module_init(xilAxiTimer_init);
  223. module_exit(xilAxiTimer_exit);
  224.  
  225. MODULE_AUTHOR("Xilinx");
  226. MODULE_DESCRIPTION("Userspace I/O driver for the Xilinx AXI Timer IP core.");
  227. MODULE_LICENSE("GPL v2");
  228. MODULE_ALIAS("uio:xilaxitimer");
RAW Paste Data