static int __devinit ocore_irq_mng_probe(struct platform_device *pdev) { unsigned int irq; u16 data; int ret = 0; struct fpga_irq_mng_platform_data *pdata; pr_debug("Initializing FPGA IRQs\n"); /* check if ID is correct */ data = ioread16(ARMADEUS_FPGA_BASE_ADDR_VIRT + IRQ_MNGR_BASE + ID_OFFSET); if (data != ID) { printk(KERN_WARNING "For irq_mngr id:%d doesn't match with id" "read %d,\n is device present ?\n", ID, data); // return -ENODEV; } pdata = pdev->dev.platform_data; if (!pdata) { dev_err(&pdev->dev,"No platform_data available\n"); return -ENOMEM; } /* Mask all interrupts initially */ writew(0, FPGA_IMR); if (pdata->init) { ret = pdata->init(pdev); if (ret) goto failed_platform_init; } for (irq = IRQ_FPGA(0); irq < IRQ_FPGA(NB_IT); irq++) { pr_debug("IRQ %d\n", irq); set_irq_chip_and_handler(irq, &imx_fpga_chip, handle_edge_irq); set_irq_flags(irq, IRQF_VALID); /* clear pending interrrupts */ imx_fpga_ack_irq(irq); } set_irq_chained_handler(ARMADEUS_FPGA_IRQ, imx_fpga_demux_handler); pr_debug("FPGA IRQs initialized (Parent=%d)\n", ARMADEUS_FPGA_IRQ); return 0; failed_platform_init: return ret; }
static int __devexit ocore_irq_mng_remove(struct platform_device *pdev) { unsigned int irq; struct fpga_irq_mng_platform_data *pdata = pdev->dev.platform_data; for (irq = IRQ_FPGA(0); irq < IRQ_FPGA(NB_IT); irq++) { set_irq_chip(irq, NULL); set_irq_handler(irq,NULL); set_irq_flags(irq, 0); } set_irq_chained_handler(ARMADEUS_FPGA_IRQ, NULL); if (pdata && pdata->exit) { pdata->exit(pdev); } pr_debug("%s\n", __FUNCTION__); return 0; }
* */ #include <linux/version.h> #include <linux/init.h> #include <linux/module.h> #include <linux/interrupt.h> #include <asm/irq.h> #ifndef CONFIG_MACH_APF9328 #include <mach/fpga.h> /* To remove when MX1 platform is merged*/ #endif /* Module's parameters: */ static int interrupt = IRQ_FPGA(3); module_param(interrupt, int, 0000); MODULE_PARM_DESC(interrupt, "IT to request"); #define DRIVER_NAME "IRQ test module" static irqreturn_t fpga_interrupt(int irq,void *dev_id,struct pt_regs *reg) { printk(KERN_ERR "FPGA IT n°%d\n", irq); return IRQ_HANDLED; } unsigned int data;
static void imx_fpga_ack_irq(struct irq_data *data) { struct irq_mng *mng = irq_data_get_irq_chip_data(data); unsigned int irq = data->irq; #else static void imx_fpga_ack_irq(unsigned int irq) { struct irq_mng *mng = &global_mng; #endif int shadow; shadow = 1 << ((irq - IRQ_FPGA_START) % NB_IT); pr_debug("%s: irq %d ack:0x%x\n", __FUNCTION__, irq, shadow); writew(shadow, mng->membase + FPGA_ISR); } #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36) static void imx_fpga_mask_irq(struct irq_data *data) { struct irq_mng *mng = irq_data_get_irq_chip_data(data); unsigned int irq = data->irq; #else static void imx_fpga_mask_irq(unsigned int irq) { struct irq_mng *mng = &global_mng; #endif int shadow; shadow = readw(mng->membase + FPGA_IMR); shadow &= ~( 1 << ((irq - IRQ_FPGA_START) % NB_IT)); pr_debug("%s: irq %d mask:0x%x\n", __FUNCTION__, irq, shadow); writew(shadow, mng->membase + FPGA_IMR); } #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36) static void imx_fpga_unmask_irq(struct irq_data *data) { struct irq_mng *mng = irq_data_get_irq_chip_data(data); unsigned int irq = data->irq; #else static void imx_fpga_unmask_irq(unsigned int irq) { struct irq_mng *mng = &global_mng; #endif int shadow; shadow = readw(mng->membase + FPGA_IMR); shadow |= 1 << ((irq - IRQ_FPGA_START) % NB_IT); pr_debug("%s: irq %d mask:0x%x\n", __FUNCTION__, irq, shadow); writew(shadow, mng->membase + FPGA_IMR); } static irqreturn_t ocore_irq_mng_interrupt(int irq, void *data) { struct irq_mng *mng = data; struct irq_desc *desc; unsigned int mask; mask = readw(mng->membase + FPGA_ISR); pr_debug("%s: mask:0x%04x\n", __FUNCTION__, mask); do { irq = IRQ_FPGA_START; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29) desc = irq_to_desc(irq); #else desc = irq_desc + irq; #endif /* handle irqs */ while (mask) { if (mask & 1) { pr_debug("handling irq %d 0x%08x\n", irq, (unsigned int)desc); #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,39) desc->handle_irq(irq, desc); #else desc_handle_irq(irq, desc); #endif } irq++; desc++; mask >>= 1; } mask = readw(mng->membase + FPGA_ISR); } while (mask != 0); return IRQ_HANDLED; } static struct irq_chip imx_fpga_chip = { .name = "FPGA", #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36) .irq_ack = imx_fpga_ack_irq, .irq_mask = imx_fpga_mask_irq, .irq_unmask = imx_fpga_unmask_irq, #else .ack = imx_fpga_ack_irq, .mask = imx_fpga_mask_irq, .unmask = imx_fpga_unmask_irq, #endif #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,39) .irq_set_type = imx_fpga_irq_type, #else .set_type = imx_fpga_irq_type, #endif }; #ifdef CONFIG_PM static int ocore_irq_mng_suspend(struct platform_device *pdev, pm_message_t state) { dev_dbg(&pdev->dev, "suspended\n"); return 0; } static int ocore_irq_mng_resume(struct platform_device *pdev) { dev_dbg(&pdev->dev, "resumed\n"); return 0; } #else # define ocore_irq_mng_suspend NULL # define ocore_irq_mng_resume NULL #endif /* CONFIG_PM */ #if LINUX_VERSION_CODE > KERNEL_VERSION(3,8,0) /* __dev* stuff is removed from Linux since 30/11/2012 */ #define __devinit #define __devexit #endif static int __devinit ocore_irq_mng_probe(struct platform_device *pdev) { struct ocore_irq_mng_pdata *pdata = pdev->dev.platform_data; unsigned int irq; u16 id; int ret = 0; struct resource *mem_res; struct resource *irq_res; struct irq_mng *mng; if (!pdata) { dev_err(&pdev->dev, "Platform data required !\n"); return -ENODEV; } /* get resources */ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem_res) { dev_err(&pdev->dev, "can't find mem resource\n"); return -EINVAL; } irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!irq_res) { dev_err(&pdev->dev, "can't find irq resource\n"); return -EINVAL; } mem_res = request_mem_region(mem_res->start, resource_size(mem_res), pdev->name); if (!mem_res) { dev_err(&pdev->dev, "iomem already in use\n"); return -EBUSY; } /* allocate memory for private structure */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36) mng = kmalloc(sizeof(struct irq_mng), GFP_KERNEL); #else mng = &global_mng; #endif if (!mng) { ret = -ENOMEM; goto out_release_mem; } pdata->mng = mng; mng->membase = ioremap(mem_res->start, resource_size(mem_res)); if (!mng->membase) { dev_err(&pdev->dev, "ioremap failed\n"); ret = -ENOMEM; goto out_dev_free; } mng->mem_res = mem_res; mng->irq_res = irq_res; /* check if ID is correct */ id = readw(mng->membase + ID_OFFSET); if (id != pdata->idnum) { printk(KERN_WARNING "For irq_mngr id:%d doesn't match with id" "read %d,\n is device present ?\n", pdata->idnum, id); ret = -ENODEV; goto out_iounmap; } /* Mask all interrupts initially */ writew(0, mng->membase + FPGA_IMR); for (irq = IRQ_FPGA(0); irq < IRQ_FPGA(NB_IT); irq++) { #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,39) irq_set_chip_data(irq, mng); irq_set_chip_and_handler_name(irq, &imx_fpga_chip, handle_edge_irq, NULL); #else set_irq_chip_data(irq, mng); set_irq_chip_and_handler(irq, &imx_fpga_chip, handle_edge_irq); #endif set_irq_flags(irq, IRQF_VALID); } /* clear pending interrupts */ writew(0xffff, mng->membase + FPGA_ISR); ret = request_irq(mng->irq_res->start, ocore_irq_mng_interrupt, #if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) IRQF_SAMPLE_RANDOM, #else 0, #endif "ocore_irq_mng", mng); if (ret < 0) { printk(KERN_ERR "Can't register irq %d\n", mng->irq_res->start); goto request_irq_error; } pr_debug("FPGA IRQs initialized (Parent=%d)\n", mng->irq_res->start); return 0; request_irq_error: out_iounmap: iounmap(mng->membase); out_dev_free: #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36) kfree(mng); #endif out_release_mem: release_mem_region(mem_res->start, resource_size(mem_res)); return ret; } static int __devexit ocore_irq_mng_remove(struct platform_device *pdev) { struct ocore_irq_mng_pdata *pdata = pdev->dev.platform_data; struct irq_mng *mng = pdata->mng; unsigned int irq; for (irq = IRQ_FPGA(0); irq < IRQ_FPGA(NB_IT); irq++) { #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,39) irq_set_chip(irq, NULL); irq_set_handler(irq, NULL); #else set_irq_chip(irq, NULL); set_irq_handler(irq, NULL); #endif set_irq_flags(irq, 0); } free_irq(mng->irq_res->start, mng); release_mem_region(mng->mem_res->start, resource_size(mng->mem_res)); iounmap(mng->membase); kfree(mng); return 0; } static struct platform_driver ocore_irq_mng_driver = { .probe = ocore_irq_mng_probe, .remove = ocore_irq_mng_remove, .suspend = ocore_irq_mng_suspend, .resume = ocore_irq_mng_resume, .driver = { .name = DRIVER_NAME, }, }; static int __init ocore_irq_mng_init(void) { return platform_driver_register(&ocore_irq_mng_driver); } static void __exit ocore_irq_mng_exit(void) { platform_driver_unregister(&ocore_irq_mng_driver); } module_init(ocore_irq_mng_init); module_exit(ocore_irq_mng_exit); MODULE_AUTHOR("Julien Boibessot, <*****@*****.**>"); MODULE_DESCRIPTION("Armadeus OpenCore IRQ manager"); MODULE_LICENSE("GPL");