📄 ucb1x00-core.cbb
字号:
ucb1x00_disable(ucb); spin_unlock_irqrestore(&ucb->lock, flags); }}/** * ucb1x00_free_irq - disable and free the specified UCB1x00 interrupt * @ucb: UCB1x00 structure describing chip * @idx: interrupt index * @devid: device id. * * Disable the interrupt source and remove the handler. devid must * match the devid passed when hooking the interrupt. * * Returns zero on success, or one of the following errors: * -EINVAL if the interrupt index is invalid * -ENOENT if devid does not match */int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid){ struct ucb1x00_irq *irq; int ret; if (idx >= 16) goto bad; irq = ucb->irq_handler + idx; ret = -ENOENT; spin_lock_irq(&ucb->lock); if (irq->devid == devid) { ucb->irq_ris_enbl &= ~(1 << idx); ucb->irq_fal_enbl &= ~(1 << idx); ucb1x00_enable(ucb); ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl); ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl); ucb1x00_disable(ucb); irq->fn = NULL; irq->devid = NULL; ret = 0; } spin_unlock_irq(&ucb->lock); return ret;bad: printk(KERN_ERR "%s: freeing bad irq %d\n", __FUNCTION__, idx); return -EINVAL;}/* * Try to probe our interrupt, rather than relying on lots of * hard-coded machine dependencies. For reference, the expected * IRQ mappings are: * * Machine Default IRQ * adsbitsy IRQ_GPCIN4 * cerf IRQ_GPIO_UCB1200_IRQ * flexanet IRQ_GPIO_GUI * freebird IRQ_GPIO_FREEBIRD_UCB1300_IRQ * graphicsclient ADS_EXT_IRQ(8) * graphicsmaster ADS_EXT_IRQ(8) * lart LART_IRQ_UCB1200 * omnimeter IRQ_GPIO23 * pfs168 IRQ_GPIO_UCB1300_IRQ * simpad IRQ_GPIO_UCB1300_IRQ * shannon SHANNON_IRQ_GPIO_IRQ_CODEC * yopy IRQ_GPIO_UCB1200_IRQ */static int __init ucb1x00_detect_irq(struct ucb1x00 *ucb){ unsigned long mask; mask = probe_irq_on(); if (!mask) return NO_IRQ; printk("ucb1x00_detect_irq \n"); /* * Enable the ADC interrupt. */ ucb1x00_reg_write(ucb, UCB_IE_RIS, UCB_IE_ADC); ucb1x00_reg_write(ucb, UCB_IE_FAL, UCB_IE_ADC); ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0xffff); ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0); /* * Cause an ADC interrupt. */ ucb1x00_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA); ucb1x00_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA | UCB_ADC_START); /* * Wait for the conversion to complete. */ while ((ucb1x00_reg_read(ucb, UCB_ADC_DATA) & UCB_ADC_DAT_VAL) == 0); ucb1x00_reg_write(ucb, UCB_ADC_CR, 0); /* * Disable and clear interrupt. */ ucb1x00_reg_write(ucb, UCB_IE_RIS, 0); ucb1x00_reg_write(ucb, UCB_IE_FAL, 0); ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0xffff); ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0); /* * Read triggered interrupt. */ return probe_irq_off(mask);}/* * This configures the UCB1x00 layer depending on the machine type * we're running on. The UCB1x00 drivers should not contain any * machine dependencies. * * We can get rid of some of these dependencies by using existing * facilities provided by the kernel - namely IRQ probing. The * machine specific files are expected to setup the IRQ levels on * initialisation. With any luck, we'll get rid of all the * machine dependencies here. */static int __init ucb1x00_configure(struct ucb1x00 *ucb){ unsigned int irq_gpio_pin = 0; int irq, default_irq = NO_IRQ; // ucb->irq = UCB1400_IRQ;#ifdef CONFIG_ARCH_SA1100 if (machine_is_adsbitsy()) default_irq = IRQ_GPCIN4;// if (machine_is_assabet())// default_irq = IRQ_GPIO23;#ifdef CONFIG_SA1100_CERF if (machine_is_cerf()) default_irq = IRQ_GPIO_UCB1200_IRQ;#endif#ifdef CONFIG_SA1100_FREEBIRD if (machine_is_freebird()) default_irq = IRQ_GPIO_FREEBIRD_UCB1300_IRQ;#endif#if defined(CONFIG_SA1100_GRAPHICSCLIENT) || defined(CONFIG_SA1100_GRAPICSMASTER) if (machine_is_graphicsclient() || machine_is_graphicsmaster()) default_irq = ADS_EXT_IRQ(8);#endif#ifdef CONFIG_SA1100_LART if (machine_is_lart()) { default_irq = LART_IRQ_UCB1200; irq_gpio_pin = LART_GPIO_UCB1200; }#endif if (machine_is_omnimeter()) default_irq = IRQ_GPIO23;#ifdef CONFIG_SA1100_PFS168 if (machine_is_pfs168()) default_irq = IRQ_GPIO_UCB1300_IRQ;#endif#ifdef CONFIG_SA1100_SIMPAD if (machine_is_simpad()) default_irq = IRQ_GPIO_UCB1300_IRQ;#endif#ifdef CONFIG_SA1100_SIMPUTER if (machine_is_simputer()) { default_irq = IRQ_GPIO_UCB1300_IRQ; irq_gpio_pin = GPIO_UCB1300_IRQ; }#endif if (machine_is_shannon()) default_irq = SHANNON_IRQ_GPIO_IRQ_CODEC;#ifdef CONFIG_SA1100_YOPY if (machine_is_yopy()) default_irq = IRQ_GPIO_UCB1200_IRQ;#endif#ifdef CONFIG_SA1100_ACCELENT if (machine_is_accelent_sa()) { ucb->irq = IRQ_GPIO_UCB1200_IRQ; irq_gpio_pin = GPIO_UCB1200_IRQ; }#endif#endif /* CONFIG_ARCH_SA1100 */#ifdef CONFIG_ARCH_PXA_IDP if (machine_is_pxa_idp()) { default_irq = TOUCH_PANEL_IRQ; irq_gpio_pin = IRQ_TO_GPIO_2_80(TOUCH_PANEL_IRQ); GPDR(irq_gpio_pin) &= ~GPIO_bit(irq_gpio_pin); }#endif#ifdef CONFIG_ARCH_TRIZEPS2 if (machine_is_trizeps2()) { default_irq = TOUCH_PANEL_IRQ; irq_gpio_pin = IRQ_TO_GPIO_2_80(TOUCH_PANEL_IRQ); GPDR(irq_gpio_pin) &= ~GPIO_bit(irq_gpio_pin); }#endif#ifdef CONFIG_ARCH_MAINSTONE if (machine_is_mainstone()) { ucb->irq = MAINSTONE_AC97_IRQ; }#endif#ifdef CONFIG_ARCH_XSBASE270 if (machine_is_xsbase270()) { set_GPIO_IRQ_edge(13,GPIO_RISING_EDGE); enable_irq(IRQ_GPIO(13)); //ucb->irq = UCB1400_IRQ; }#endif#ifdef CONFIG_PXA_CERF_PDA if (machine_is_pxa_cerf()) { irq_gpio_pin = CERF_GPIO_UCB1400_IRQ; }#endif /* * Eventually, this will disappear. */ if (irq_gpio_pin)#ifdef CONFIG_ARCH_PXA_IDP set_GPIO_IRQ_edge(irq_gpio_pin, GPIO_FALLING_EDGE);#else set_GPIO_IRQ_edge(irq_gpio_pin, GPIO_RISING_EDGE);#endif irq = ucb1x00_detect_irq(ucb); if (irq != NO_IRQ) { if (default_irq != NO_IRQ && irq != default_irq) printk(KERN_ERR "UCB1x00: probed IRQ%d != default IRQ%d\n", irq, default_irq); if (irq == default_irq) printk(KERN_ERR "UCB1x00: probed IRQ%d correctly. " "Please remove machine dependencies from " "ucb1x00-core.c\n", irq); ucb->irq = irq; } else { printk(KERN_ERR "UCB1x00: IRQ probe failed, using IRQ%d\n", default_irq); ucb->irq = default_irq; } return ucb->irq == NO_IRQ ? -ENODEV : 0;}struct ucb1x00 *my_ucb;static int ucb1x00_init_helper(void){ struct mcp *mcp; unsigned int id; int ret = -ENODEV; mcp = mcp_get(); if (!mcp) goto no_mcp; mcp_enable(mcp); id = mcp_reg_read(mcp, UCB_ID); if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_1400) { printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id); goto out; } /* distinguish between UCB1400 revs 1B and 2A */ if (id == UCB_ID_1400 && mcp_reg_read(mcp, 0x00) == 0x002a) id = UCB_ID_1400_BUGGY; my_ucb = kmalloc(sizeof(struct ucb1x00), GFP_KERNEL); ret = -ENOMEM; if (!my_ucb) goto out;#ifdef CONFIG_ARCH_SA1100 if (machine_is_shannon()) { /* reset the codec */ GPDR |= SHANNON_GPIO_CODEC_RESET; GPCR = SHANNON_GPIO_CODEC_RESET; GPSR = SHANNON_GPIO_CODEC_RESET; }#endif memset(my_ucb, 0, sizeof(struct ucb1x00)); spin_lock_init(&my_ucb->lock); spin_lock_init(&my_ucb->io_lock); sema_init(&my_ucb->adc_sem, 1); my_ucb->id = id; my_ucb->mcp = mcp; ret = ucb1x00_configure(my_ucb); if (ret) goto out; init_waitqueue_head(&my_ucb->irq_wait); ret = request_irq(my_ucb->irq, ucb1x00_irq, 0, "UCB1x00", my_ucb); if (ret) { printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n", my_ucb->irq, ret); goto irq_err; }#ifdef CONFIG_PM my_ucb->pmdev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ucb1x00_pm); if (my_ucb->pmdev == NULL) printk("ucb1x00: unable to register in PM.\n"); else my_ucb->pmdev->data = my_ucb;#endif init_completion(&my_ucb->complete); ret = kernel_thread(ucb1x00_thread, my_ucb, CLONE_FS | CLONE_FILES); if (ret >= 0) { wait_for_completion(&my_ucb->complete); ret = 0; goto out; } free_irq(my_ucb->irq, my_ucb);irq_err: kfree(my_ucb); my_ucb = NULL;out: mcp_disable(mcp);no_mcp: return ret;}/** * ucb1x00_get - get the UCB1x00 structure describing a chip * @ucb: UCB1x00 structure describing chip * * Return the UCB1x00 structure describing a chip. * * FIXME: Currently very noddy indeed, which currently doesn't * matter since we only support one chip. */struct ucb1x00 *ucb1x00_get(void){ if( !my_ucb) ucb1x00_init_helper(); return my_ucb;}static int __init ucb1x00_init(void){ /* check if driver is already initialized */ if( my_ucb) return 0; return ucb1x00_init_helper();}static void __exit ucb1x00_exit(void){ send_sig(SIGKILL, my_ucb->rtask, 1); wait_for_completion(&my_ucb->complete); free_irq(my_ucb->irq, my_ucb); kfree(my_ucb); my_ucb = 0;}module_init(ucb1x00_init);module_exit(ucb1x00_exit);EXPORT_SYMBOL(ucb1x00_get);EXPORT_SYMBOL(ucb1x00_io_set_dir);EXPORT_SYMBOL(ucb1x00_io_write);EXPORT_SYMBOL(ucb1x00_io_read);EXPORT_SYMBOL(ucb1x00_adc_enable);EXPORT_SYMBOL(ucb1x00_adc_read);EXPORT_SYMBOL(ucb1x00_adc_disable);EXPORT_SYMBOL(ucb1x00_hook_irq);EXPORT_SYMBOL(ucb1x00_free_irq);EXPORT_SYMBOL(ucb1x00_enable_irq);EXPORT_SYMBOL(ucb1x00_disable_irq);MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");MODULE_DESCRIPTION("UCB1x00 core driver");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -