static void uv_domain_free(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs) { struct irq_data *irq_data = irq_domain_get_irq_data(domain, virq); BUG_ON(nr_irqs != 1); kfree(irq_data->chip_data); irq_clear_status_flags(virq, IRQ_MOVE_PCNTXT); irq_clear_status_flags(virq, IRQ_NO_BALANCING); irq_domain_free_irqs_top(domain, virq, nr_irqs); }
static void ep93xx_gpio_init_irq(void) { int gpio_irq; for (gpio_irq = gpio_to_irq(0); gpio_irq <= gpio_to_irq(EP93XX_GPIO_LINE_MAX_IRQ); ++gpio_irq) { irq_set_chip_and_handler(gpio_irq, &ep93xx_gpio_irq_chip, handle_level_irq); irq_clear_status_flags(gpio_irq, IRQ_NOREQUEST); } irq_set_chained_handler(IRQ_EP93XX_GPIO_AB, ep93xx_gpio_ab_irq_handler); irq_set_chained_handler(IRQ_EP93XX_GPIO0MUX, ep93xx_gpio_f_irq_handler); irq_set_chained_handler(IRQ_EP93XX_GPIO1MUX, ep93xx_gpio_f_irq_handler); irq_set_chained_handler(IRQ_EP93XX_GPIO2MUX, ep93xx_gpio_f_irq_handler); irq_set_chained_handler(IRQ_EP93XX_GPIO3MUX, ep93xx_gpio_f_irq_handler); irq_set_chained_handler(IRQ_EP93XX_GPIO4MUX, ep93xx_gpio_f_irq_handler); irq_set_chained_handler(IRQ_EP93XX_GPIO5MUX, ep93xx_gpio_f_irq_handler); irq_set_chained_handler(IRQ_EP93XX_GPIO6MUX, ep93xx_gpio_f_irq_handler); irq_set_chained_handler(IRQ_EP93XX_GPIO7MUX, ep93xx_gpio_f_irq_handler); }
static int __init scalewayc1gpio_init(void) { unsigned int gpio; int ret; printk(KERN_DEBUG "Scaleway C1 SoC IRQ: initializing\n"); /* create reboot thread */ task = kthread_create(scalewayc1_reboot_thread, NULL, "scaleway-c1-soc-irq"); if (IS_ERR(task)) { printk(KERN_ALERT "Scaleway C1 SoC IRQ: kthread_create error\n"); return -1; } wake_up_process(task); /* setup an irq that watch the reset gpio state */ gpio = SCALEWAYC1_GPIO_SWRESET; gpio_request(gpio, "softreset"); gpio_direction_input(gpio); g_irq = gpio_to_irq(gpio); irq_clear_status_flags(g_irq, IRQ_LEVEL); ret = request_any_context_irq(g_irq, scalewayc1_irq_resethandler, IRQF_TRIGGER_FALLING, "scaleway-c1", NULL); /* enable console, switch the booted gpio */ gpio = SCALEWAYC1_GPIO_BOOTED; gpio_request(gpio, "booted"); gpio_direction_output(gpio, 0); printk(KERN_INFO "Scaleway C1 SoC IRQ: initialized\n"); return 0; }
static __init int bast_irq_init(void) { unsigned int i; if (machine_is_bast()) { printk(KERN_INFO "BAST PC104 IRQ routing, Copyright 2005 Simtec Electronics\n"); /* zap all the IRQs */ __raw_writeb(0x0, BAST_VA_PC104_IRQMASK); irq_set_chained_handler(BAST_IRQ_ISA, bast_irq_pc104_demux); /* register our IRQs */ for (i = 0; i < 4; i++) { unsigned int irqno = bast_pc104_irqs[i]; irq_set_chip_and_handler(irqno, &bast_pc104_chip, handle_level_irq); irq_clear_status_flags(irqno, IRQ_NOREQUEST); } } return 0; }
static void __init zeus_init_irq(void) { int level; int isa_irq; pxa27x_init_irq(); /* Peripheral IRQs. It would be nice to move those inside driver configuration, but it is not supported at the moment. */ irq_set_irq_type(gpio_to_irq(ZEUS_AC97_GPIO), IRQ_TYPE_EDGE_RISING); irq_set_irq_type(gpio_to_irq(ZEUS_WAKEUP_GPIO), IRQ_TYPE_EDGE_RISING); irq_set_irq_type(gpio_to_irq(ZEUS_PTT_GPIO), IRQ_TYPE_EDGE_RISING); irq_set_irq_type(gpio_to_irq(ZEUS_EXTGPIO_GPIO), IRQ_TYPE_EDGE_FALLING); irq_set_irq_type(gpio_to_irq(ZEUS_CAN_GPIO), IRQ_TYPE_EDGE_FALLING); /* Setup ISA IRQs */ for (level = 0; level < ARRAY_SIZE(zeus_isa_irqs); level++) { isa_irq = zeus_bit_to_irq(level); irq_set_chip_and_handler(isa_irq, &zeus_irq_chip, handle_edge_irq); irq_clear_status_flags(isa_irq, IRQ_NOREQUEST | IRQ_NOPROBE); } irq_set_irq_type(gpio_to_irq(ZEUS_ISA_GPIO), IRQ_TYPE_EDGE_RISING); irq_set_chained_handler(gpio_to_irq(ZEUS_ISA_GPIO), zeus_irq_handler); }
static irqreturn_t scalewayc1_irq_resethandler(int irq, void *dev_id) { /* handled when reset gpio state changed */ if (irq == g_irq) { need_reboot = 1; atomic_inc(&probe_count); wake_up(&probe_waitqueue); irq_clear_status_flags(irq, IRQ_LEVEL); } return IRQ_HANDLED; }
int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { u32 intr_mask = (u32)d->host_data; if (intr_mask & (1 << hw)) { irq_set_chip_and_handler_name(irq, &intc_dev, handle_edge_irq, "edge"); irq_clear_status_flags(irq, IRQ_LEVEL); } else { irq_set_chip_and_handler_name(irq, &intc_dev, handle_level_irq, "level"); irq_set_status_flags(irq, IRQ_LEVEL); } return 0; }
/* * All of the FPGA interrupt request inputs except for the touchscreen are * edge-sensitive; the touchscreen is level-sensitive. The edge-sensitive * interrupts are acknowledged as a side-effect of reading the interrupt * status register from the FPGA. The edge-sensitive interrupt inputs * cause a problem with level interrupt requests, such as Ethernet. The * problem occurs when a level interrupt request is asserted while its * interrupt input is masked in the FPGA, which results in a missed * interrupt. * * In an attempt to workaround the problem with missed interrupts, the * mask_ack routine for all of the FPGA interrupts has been changed from * fpga_mask_ack_irq() to fpga_ack_irq() so that the specific FPGA interrupt * being serviced is left unmasked. We can do this because the FPGA cascade * interrupt is run with all interrupts masked. * * Limited testing indicates that this workaround appears to be effective * for the smc9194 Ethernet driver used on the Innovator. It should work * on other FPGA interrupts as well, but any drivers that explicitly mask * interrupts at the interrupt controller via disable_irq/enable_irq * could pose a problem. */ void omap1510_fpga_init_irq(void) { int i, res; __raw_writeb(0, OMAP1510_FPGA_IMR_LO); __raw_writeb(0, OMAP1510_FPGA_IMR_HI); __raw_writeb(0, INNOVATOR_FPGA_IMR2); for (i = OMAP_FPGA_IRQ_BASE; i < OMAP_FPGA_IRQ_END; i++) { if (i == OMAP1510_INT_FPGA_TS) { /* * The touchscreen interrupt is level-sensitive, so * we'll use the regular mask_ack routine for it. */ irq_set_chip(i, &omap_fpga_irq_ack); } else { /* * All FPGA interrupts except the touchscreen are * edge-sensitive, so we won't mask them. */ irq_set_chip(i, &omap_fpga_irq); } irq_set_handler(i, handle_edge_irq); irq_clear_status_flags(i, IRQ_NOREQUEST); } /* * The FPGA interrupt line is connected to GPIO13. Claim this pin for * the ARM. * * NOTE: For general GPIO/MPUIO access and interrupts, please see * gpio.[ch] */ res = gpio_request(13, "FPGA irq"); if (res) { pr_err("%s failed to get gpio\n", __func__); return; } gpio_direction_input(13); irq_set_irq_type(gpio_to_irq(13), IRQ_TYPE_EDGE_RISING); irq_set_chained_handler(OMAP1510_INT_FPGA, innovator_fpga_IRQ_demux); }
static void __init balloon3_init_irq(void) { int irq; pxa27x_init_irq(); /* setup extra Balloon3 irqs */ for (irq = BALLOON3_IRQ(0); irq <= BALLOON3_IRQ(7); irq++) { irq_set_chip_and_handler(irq, &balloon3_irq_chip, handle_level_irq); irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); } irq_set_chained_handler(BALLOON3_AUX_NIRQ, balloon3_irq_handler); irq_set_irq_type(BALLOON3_AUX_NIRQ, IRQ_TYPE_EDGE_FALLING); pr_debug("%s: chained handler installed - irq %d automatically " "enabled\n", __func__, BALLOON3_AUX_NIRQ); }
static void __init pcm990_init_irq(void) { int irq; /* setup extra PCM990 irqs */ for (irq = PCM027_IRQ(0); irq <= PCM027_IRQ(3); irq++) { irq_set_chip_and_handler(irq, &pcm990_irq_chip, handle_level_irq); irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); } /* disable all Interrupts */ pcm990_cpld_writeb(0x0, PCM990_CTRL_INTMSKENA); pcm990_cpld_writeb(0xff, PCM990_CTRL_INTSETCLR); irq_set_chained_handler(PCM990_CTRL_INT_IRQ, pcm990_irq_handler); irq_set_irq_type(PCM990_CTRL_INT_IRQ, PCM990_CTRL_INT_IRQ_EDGE); }
/** * irq_alloc_hwirqs - Allocate an irq descriptor and initialize the hardware * @cnt: number of interrupts to allocate * @node: node on which to allocate * * Returns an interrupt number > 0 or 0, if the allocation fails. */ unsigned int irq_alloc_hwirqs(int cnt, int node) { int i, irq = __irq_alloc_descs(-1, 0, cnt, node, NULL, NULL); if (irq < 0) return 0; for (i = irq; cnt > 0; i++, cnt--) { if (arch_setup_hwirq(i, node)) goto err; irq_clear_status_flags(i, _IRQ_NOREQUEST); } return irq; err: for (i--; i >= irq; i--) { irq_set_status_flags(i, _IRQ_NOREQUEST | _IRQ_NOPROBE); arch_teardown_hwirq(i); } irq_free_descs(irq, cnt); return 0; }
static void hpet_msi_free(struct irq_domain *domain, struct msi_domain_info *info, unsigned int virq) { irq_clear_status_flags(virq, IRQ_MOVE_PCNTXT); }
int its_unmap_vlpi(int irq) { irq_clear_status_flags(irq, IRQ_DISABLE_UNLAZY); return irq_set_vcpu_affinity(irq, NULL); }
/** * xgpiops_probe - Initialization method for a xgpiops device * @pdev: platform device instance * * This function allocates memory resources for the gpio device and registers * all the banks of the device. It will also set up interrupts for the gpio * pins. * Note: Interrupts are disabled for all the banks during initialization. * Returns 0 on success, negative error otherwise. */ static int __devinit xgpiops_probe(struct platform_device *pdev) { int ret; unsigned int irq_num; struct xgpiops *gpio; struct gpio_chip *chip; resource_size_t remap_size; struct resource *mem_res = NULL; int pin_num, bank_num, gpio_irq; gpio = kzalloc(sizeof(struct xgpiops), GFP_KERNEL); if (!gpio) { dev_err(&pdev->dev, "couldn't allocate memory for gpio private data\n"); return -ENOMEM; } spin_lock_init(&gpio->gpio_lock); platform_set_drvdata(pdev, gpio); mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem_res) { dev_err(&pdev->dev, "No memory resource\n"); ret = -ENODEV; goto err_free_gpio; } remap_size = mem_res->end - mem_res->start + 1; if (!request_mem_region(mem_res->start, remap_size, pdev->name)) { dev_err(&pdev->dev, "Cannot request IO\n"); ret = -ENXIO; goto err_free_gpio; } gpio->base_addr = ioremap(mem_res->start, remap_size); if (gpio->base_addr == NULL) { dev_err(&pdev->dev, "Couldn't ioremap memory at 0x%08lx\n", (unsigned long)mem_res->start); ret = -ENOMEM; goto err_release_region; } irq_num = platform_get_irq(pdev, 0); gpio->irq = irq_num; /* configure the gpio chip */ chip = &gpio->chip; chip->label = "xgpiops"; chip->owner = THIS_MODULE; chip->dev = &pdev->dev; chip->get = xgpiops_get_value; chip->set = xgpiops_set_value; chip->request = xgpiops_request; chip->free = xgpiops_free; chip->direction_input = xgpiops_dir_in; chip->direction_output = xgpiops_dir_out; chip->to_irq = xgpiops_to_irq; chip->dbg_show = NULL; chip->base = 0; /* default pin base */ chip->ngpio = XGPIOPS_NR_GPIOS; chip->can_sleep = 0; /* report a bug if gpio chip registration fails */ ret = gpiochip_add(chip); if (ret < 0) { dev_err(&pdev->dev, "gpio chip registration failed\n"); goto err_iounmap; } else { dev_info(&pdev->dev, "gpio at 0x%08lx mapped to 0x%08lx\n", (unsigned long)mem_res->start, (unsigned long)gpio->base_addr); } /* Enable GPIO clock */ gpio->clk = clk_get_sys("GPIO_APER", NULL); if (IS_ERR(gpio->clk)) { dev_err(&pdev->dev, "Clock not found.\n"); ret = PTR_ERR(gpio->clk); goto err_chip_remove; } ret = clk_prepare_enable(gpio->clk); if (ret) { dev_err(&pdev->dev, "Unable to enable clock.\n"); goto err_clk_put; } /* disable interrupts for all banks */ for (bank_num = 0; bank_num < 4; bank_num++) { xgpiops_writereg(0xffffffff, gpio->base_addr + XGPIOPS_INTDIS_OFFSET(bank_num)); } /* * set the irq chip, handler and irq chip data for callbacks for * each pin */ gpio_irq = XGPIOPS_IRQBASE; for (pin_num = 0; pin_num < XGPIOPS_NR_GPIOS; pin_num++, gpio_irq++) { irq_set_chip(gpio_irq, &xgpiops_irqchip); irq_set_chip_data(gpio_irq, (void *)gpio); irq_set_handler(gpio_irq, handle_simple_irq); irq_set_status_flags(gpio_irq, IRQF_VALID); irq_clear_status_flags(gpio_irq, IRQ_NOREQUEST); } irq_set_handler_data(irq_num, (void *)(XGPIOPS_IRQBASE)); irq_set_chained_handler(irq_num, xgpiops_irqhandler); xgpiops_pm_runtime_init(pdev); device_set_wakeup_capable(&pdev->dev, 1); return 0; err_clk_put: clk_put(gpio->clk); err_chip_remove: gpiochip_remove(chip); err_iounmap: iounmap(gpio->base_addr); err_release_region: release_mem_region(mem_res->start, remap_size); err_free_gpio: platform_set_drvdata(pdev, NULL); kfree(gpio); return ret; }
static int __init CoreServicesInit(void) { int ret_val = 0; int result = 0; uint32_t currentSettings = 0; struct resource* r = request_mem_region(ALLOY_RAM_BASE, ALLOY_DEDICATED_RAM_SIZE, "AlloyRAM"); if(r == NULL) { printk("request_mem_region failed.\n"); } else { printk("request_mem_region ok.\n"); } r = request_mem_region(0x40000000, 4096, "AlloyPeripherals"); if(r == NULL) { printk("request_mem_region failed.\n"); } else { printk("request_mem_region ok.\n"); } /* * Register the character device (atleast try) */ ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &Fops); /* * Negative values signify an error */ if (ret_val < 0) { printk(KERN_ALERT "%s failed with %d\n", "Sorry, registering the character device ", ret_val); return ret_val; } set_irq_flags(IRQ_ARM_LOCAL_MAILBOX2, IRQF_VALID); irq_clear_status_flags(IRQ_ARM_LOCAL_MAILBOX2, IRQ_PER_CPU); irq_clear_status_flags(IRQ_ARM_LOCAL_MAILBOX2, IRQ_LEVEL); irq_modify_status(IRQ_ARM_LOCAL_MAILBOX0,0xffffffff,0x00000000); irq_modify_status(IRQ_ARM_LOCAL_MAILBOX1,0xffffffff,0x00000000); irq_modify_status(IRQ_ARM_LOCAL_MAILBOX2,0xffffffff,0x00000000); irq_modify_status(IRQ_ARM_LOCAL_MAILBOX3,0xffffffff,0x00000000); // // Register the interrupt handler for mailbox IRQs. // set_irq_flags(IRQ_ARM_LOCAL_MAILBOX2, IRQF_VALID); result = request_threaded_irq( IRQ_ARM_LOCAL_MAILBOX0, // The interrupt number requested (irq_handler_t) MailboxIRQHandler0, // The pointer to the handler function (above) NULL, IRQF_SHARED, // Interrupt is on rising edge (button press in Fig.1) "MailboxIRQHandler", // Used in /proc/interrupts to identify the owner DEVICE_NAME); // The *dev_id for shared interrupt lines, NULL here result = request_threaded_irq( IRQ_ARM_LOCAL_MAILBOX1, // The interrupt number requested (irq_handler_t) MailboxIRQHandler1, // The pointer to the handler function (above) NULL, IRQF_SHARED, // Interrupt is on rising edge (button press in Fig.1) "MailboxIRQHandler", // Used in /proc/interrupts to identify the owner DEVICE_NAME); // The *dev_id for shared interrupt lines, NULL here result = request_threaded_irq( IRQ_ARM_LOCAL_MAILBOX2, // The interrupt number requested (irq_handler_t) MailboxIRQHandler2, // The pointer to the handler function (above) NULL, IRQF_SHARED, // Interrupt is on rising edge (button press in Fig.1) "MailboxIRQHandler", // Used in /proc/interrupts to identify the owner DEVICE_NAME); // The *dev_id for shared interrupt lines, NULL here result = request_threaded_irq( IRQ_ARM_LOCAL_MAILBOX3, // The interrupt number requested (irq_handler_t) MailboxIRQHandler3, // The pointer to the handler function (above) NULL, IRQF_SHARED, // Interrupt is on rising edge (button press in Fig.1) "MailboxIRQHandler", // Used in /proc/interrupts to identify the owner DEVICE_NAME); // The *dev_id for shared interrupt lines, NULL here if(result == 0) { printk(KERN_INFO "Mailbox ISR registered ok.\n"); } else { printk(KERN_INFO "Mailbox ISR registration failed (%d).\n", result); } // // Enable the interupt. // We're on Core0 and we want to enable the Mailbox 1 interrupt. // currentSettings = readl( __io_address(ARM_LOCAL_MAILBOX_INT_CONTROL0) ); currentSettings |= 0x0000000f; writel( currentSettings, __io_address(ARM_LOCAL_MAILBOX_INT_CONTROL0) ); // // // alloyRam = ioremap_nocache( ALLOY_RAM_BASE, ALLOY_DEDICATED_RAM_SIZE ); printk(KERN_INFO "%s The major device number is %d.\n", "Registeration is a success", MAJOR_NUM); printk(KERN_INFO "If you want to talk to the device driver,\n"); printk(KERN_INFO "you'll have to create a device file. \n"); printk(KERN_INFO "We suggest you use:\n"); printk(KERN_INFO "mknod %s c %d 0\n", DEVICE_FILE_NAME, MAJOR_NUM); printk(KERN_INFO "The device file name is important, because\n"); printk(KERN_INFO "the ioctl program assumes that's the\n"); printk(KERN_INFO "file you'll use.\n"); return 0; }
void __init init_IRQ(void) { u32 i, j, intr_type; struct device_node *intc = NULL; #ifdef CONFIG_SELFMOD_INTC unsigned int intc_baseaddr = 0; static int arr_func[] = { (int)&get_irq, (int)&intc_enable_or_unmask, (int)&intc_disable_or_mask, (int)&intc_mask_ack, (int)&intc_ack, (int)&intc_end, 0 }; #endif const char * const intc_list[] = { "xlnx,xps-intc-1.00.a", NULL }; for (j = 0; intc_list[j] != NULL; j++) { intc = of_find_compatible_node(NULL, NULL, intc_list[j]); if (intc) break; } BUG_ON(!intc); intc_baseaddr = be32_to_cpup(of_get_property(intc, "reg", NULL)); intc_baseaddr = (unsigned long) ioremap(intc_baseaddr, PAGE_SIZE); nr_irq = be32_to_cpup(of_get_property(intc, "xlnx,num-intr-inputs", NULL)); intr_type = be32_to_cpup(of_get_property(intc, "xlnx,kind-of-intr", NULL)); if (intr_type > (u32)((1ULL << nr_irq) - 1)) printk(KERN_INFO " ERROR: Mismatch in kind-of-intr param\n"); #ifdef CONFIG_SELFMOD_INTC selfmod_function((int *) arr_func, intc_baseaddr); #endif printk(KERN_INFO "%s #0 at 0x%08x, num_irq=%d, edge=0x%x\n", intc_list[j], intc_baseaddr, nr_irq, intr_type); /* * Disable all external interrupts until they are * explicity requested. */ out_be32(intc_baseaddr + IER, 0); /* Acknowledge any pending interrupts just in case. */ out_be32(intc_baseaddr + IAR, 0xffffffff); /* Turn on the Master Enable. */ out_be32(intc_baseaddr + MER, MER_HIE | MER_ME); for (i = 0; i < nr_irq; ++i) { if (intr_type & (0x00000001 << i)) { irq_set_chip_and_handler_name(i, &intc_dev, handle_edge_irq, "edge"); irq_clear_status_flags(i, IRQ_LEVEL); } else { irq_set_chip_and_handler_name(i, &intc_dev, handle_level_irq, "level"); irq_set_status_flags(i, IRQ_LEVEL); } } }
static int ezx_pcap_probe(struct spi_device *spi) { struct pcap_platform_data *pdata = dev_get_platdata(&spi->dev); struct pcap_chip *pcap; int i, adc_irq; int ret = -ENODEV; /* platform data is required */ if (!pdata) goto ret; pcap = devm_kzalloc(&spi->dev, sizeof(*pcap), GFP_KERNEL); if (!pcap) { ret = -ENOMEM; goto ret; } mutex_init(&pcap->io_mutex); mutex_init(&pcap->adc_mutex); INIT_WORK(&pcap->isr_work, pcap_isr_work); INIT_WORK(&pcap->msr_work, pcap_msr_work); spi_set_drvdata(spi, pcap); /* setup spi */ spi->bits_per_word = 32; spi->mode = SPI_MODE_0 | (pdata->config & PCAP_CS_AH ? SPI_CS_HIGH : 0); ret = spi_setup(spi); if (ret) goto ret; pcap->spi = spi; /* setup irq */ pcap->irq_base = pdata->irq_base; pcap->workqueue = create_singlethread_workqueue("pcapd"); if (!pcap->workqueue) { ret = -ENOMEM; dev_err(&spi->dev, "can't create pcap thread\n"); goto ret; } /* redirect interrupts to AP, except adcdone2 */ if (!(pdata->config & PCAP_SECOND_PORT)) ezx_pcap_write(pcap, PCAP_REG_INT_SEL, (1 << PCAP_IRQ_ADCDONE2)); /* setup irq chip */ for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) { irq_set_chip_and_handler(i, &pcap_irq_chip, handle_simple_irq); irq_set_chip_data(i, pcap); irq_clear_status_flags(i, IRQ_NOREQUEST | IRQ_NOPROBE); } /* mask/ack all PCAP interrupts */ ezx_pcap_write(pcap, PCAP_REG_MSR, PCAP_MASK_ALL_INTERRUPT); ezx_pcap_write(pcap, PCAP_REG_ISR, PCAP_CLEAR_INTERRUPT_REGISTER); pcap->msr = PCAP_MASK_ALL_INTERRUPT; irq_set_irq_type(spi->irq, IRQ_TYPE_EDGE_RISING); irq_set_chained_handler_and_data(spi->irq, pcap_irq_handler, pcap); irq_set_irq_wake(spi->irq, 1); /* ADC */ adc_irq = pcap_to_irq(pcap, (pdata->config & PCAP_SECOND_PORT) ? PCAP_IRQ_ADCDONE2 : PCAP_IRQ_ADCDONE); ret = devm_request_irq(&spi->dev, adc_irq, pcap_adc_irq, 0, "ADC", pcap); if (ret) goto free_irqchip; /* setup subdevs */ for (i = 0; i < pdata->num_subdevs; i++) { ret = pcap_add_subdev(pcap, &pdata->subdevs[i]); if (ret) goto remove_subdevs; } /* board specific quirks */ if (pdata->init) pdata->init(pcap); return 0; remove_subdevs: device_for_each_child(&spi->dev, NULL, pcap_remove_subdev); free_irqchip: for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) irq_set_chip_and_handler(i, NULL, NULL); /* destroy_workqueue: */ destroy_workqueue(pcap->workqueue); ret: return ret; }