diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index cb07f4a034834a4621ea3be0f84055888bf1296a..488d9bd68d2c1652407fbdb6abf4bffb64ed882d 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c @@ -615,310 +615,3 @@ static void __init exynos4_init_uarts(struct s3c2410_uartcfg *cfg, int no) s3c24xx_init_uartdevs("exynos4210-uart", exynos4_uart_resources, cfg, no); } - -static void __iomem *exynos_eint_base; - -static DEFINE_SPINLOCK(eint_lock); - -static unsigned int eint0_15_data[16]; - -static inline int exynos4_irq_to_gpio(unsigned int irq) -{ - if (irq < IRQ_EINT(0)) - return -EINVAL; - - irq -= IRQ_EINT(0); - if (irq < 8) - return EXYNOS4_GPX0(irq); - - irq -= 8; - if (irq < 8) - return EXYNOS4_GPX1(irq); - - irq -= 8; - if (irq < 8) - return EXYNOS4_GPX2(irq); - - irq -= 8; - if (irq < 8) - return EXYNOS4_GPX3(irq); - - return -EINVAL; -} - -static inline int exynos5_irq_to_gpio(unsigned int irq) -{ - if (irq < IRQ_EINT(0)) - return -EINVAL; - - irq -= IRQ_EINT(0); - if (irq < 8) - return EXYNOS5_GPX0(irq); - - irq -= 8; - if (irq < 8) - return EXYNOS5_GPX1(irq); - - irq -= 8; - if (irq < 8) - return EXYNOS5_GPX2(irq); - - irq -= 8; - if (irq < 8) - return EXYNOS5_GPX3(irq); - - return -EINVAL; -} - -static unsigned int exynos4_eint0_15_src_int[16] = { - EXYNOS4_IRQ_EINT0, - EXYNOS4_IRQ_EINT1, - EXYNOS4_IRQ_EINT2, - EXYNOS4_IRQ_EINT3, - EXYNOS4_IRQ_EINT4, - EXYNOS4_IRQ_EINT5, - EXYNOS4_IRQ_EINT6, - EXYNOS4_IRQ_EINT7, - EXYNOS4_IRQ_EINT8, - EXYNOS4_IRQ_EINT9, - EXYNOS4_IRQ_EINT10, - EXYNOS4_IRQ_EINT11, - EXYNOS4_IRQ_EINT12, - EXYNOS4_IRQ_EINT13, - EXYNOS4_IRQ_EINT14, - EXYNOS4_IRQ_EINT15, -}; - -static unsigned int exynos5_eint0_15_src_int[16] = { - EXYNOS5_IRQ_EINT0, - EXYNOS5_IRQ_EINT1, - EXYNOS5_IRQ_EINT2, - EXYNOS5_IRQ_EINT3, - EXYNOS5_IRQ_EINT4, - EXYNOS5_IRQ_EINT5, - EXYNOS5_IRQ_EINT6, - EXYNOS5_IRQ_EINT7, - EXYNOS5_IRQ_EINT8, - EXYNOS5_IRQ_EINT9, - EXYNOS5_IRQ_EINT10, - EXYNOS5_IRQ_EINT11, - EXYNOS5_IRQ_EINT12, - EXYNOS5_IRQ_EINT13, - EXYNOS5_IRQ_EINT14, - EXYNOS5_IRQ_EINT15, -}; -static inline void exynos_irq_eint_mask(struct irq_data *data) -{ - u32 mask; - - spin_lock(&eint_lock); - mask = __raw_readl(EINT_MASK(exynos_eint_base, data->irq)); - mask |= EINT_OFFSET_BIT(data->irq); - __raw_writel(mask, EINT_MASK(exynos_eint_base, data->irq)); - spin_unlock(&eint_lock); -} - -static void exynos_irq_eint_unmask(struct irq_data *data) -{ - u32 mask; - - spin_lock(&eint_lock); - mask = __raw_readl(EINT_MASK(exynos_eint_base, data->irq)); - mask &= ~(EINT_OFFSET_BIT(data->irq)); - __raw_writel(mask, EINT_MASK(exynos_eint_base, data->irq)); - spin_unlock(&eint_lock); -} - -static inline void exynos_irq_eint_ack(struct irq_data *data) -{ - __raw_writel(EINT_OFFSET_BIT(data->irq), - EINT_PEND(exynos_eint_base, data->irq)); -} - -static void exynos_irq_eint_maskack(struct irq_data *data) -{ - exynos_irq_eint_mask(data); - exynos_irq_eint_ack(data); -} - -static int exynos_irq_eint_set_type(struct irq_data *data, unsigned int type) -{ - int offs = EINT_OFFSET(data->irq); - int shift; - u32 ctrl, mask; - u32 newvalue = 0; - - switch (type) { - case IRQ_TYPE_EDGE_RISING: - newvalue = S5P_IRQ_TYPE_EDGE_RISING; - break; - - case IRQ_TYPE_EDGE_FALLING: - newvalue = S5P_IRQ_TYPE_EDGE_FALLING; - break; - - case IRQ_TYPE_EDGE_BOTH: - newvalue = S5P_IRQ_TYPE_EDGE_BOTH; - break; - - case IRQ_TYPE_LEVEL_LOW: - newvalue = S5P_IRQ_TYPE_LEVEL_LOW; - break; - - case IRQ_TYPE_LEVEL_HIGH: - newvalue = S5P_IRQ_TYPE_LEVEL_HIGH; - break; - - default: - printk(KERN_ERR "No such irq type %d", type); - return -EINVAL; - } - - shift = (offs & 0x7) * 4; - mask = 0x7 << shift; - - spin_lock(&eint_lock); - ctrl = __raw_readl(EINT_CON(exynos_eint_base, data->irq)); - ctrl &= ~mask; - ctrl |= newvalue << shift; - __raw_writel(ctrl, EINT_CON(exynos_eint_base, data->irq)); - spin_unlock(&eint_lock); - - if (soc_is_exynos5250()) - s3c_gpio_cfgpin(exynos5_irq_to_gpio(data->irq), S3C_GPIO_SFN(0xf)); - else - s3c_gpio_cfgpin(exynos4_irq_to_gpio(data->irq), S3C_GPIO_SFN(0xf)); - - return 0; -} - -static struct irq_chip exynos_irq_eint = { - .name = "exynos-eint", - .irq_mask = exynos_irq_eint_mask, - .irq_unmask = exynos_irq_eint_unmask, - .irq_mask_ack = exynos_irq_eint_maskack, - .irq_ack = exynos_irq_eint_ack, - .irq_set_type = exynos_irq_eint_set_type, -#ifdef CONFIG_PM - .irq_set_wake = s3c_irqext_wake, -#endif -}; - -/* - * exynos4_irq_demux_eint - * - * This function demuxes the IRQ from from EINTs 16 to 31. - * It is designed to be inlined into the specific handler - * s5p_irq_demux_eintX_Y. - * - * Each EINT pend/mask registers handle eight of them. - */ -static inline void exynos_irq_demux_eint(unsigned int start) -{ - unsigned int irq; - - u32 status = __raw_readl(EINT_PEND(exynos_eint_base, start)); - u32 mask = __raw_readl(EINT_MASK(exynos_eint_base, start)); - - status &= ~mask; - status &= 0xff; - - while (status) { - irq = fls(status) - 1; - generic_handle_irq(irq + start); - status &= ~(1 << irq); - } -} - -static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc) -{ - struct irq_chip *chip = irq_get_chip(irq); - chained_irq_enter(chip, desc); - exynos_irq_demux_eint(IRQ_EINT(16)); - exynos_irq_demux_eint(IRQ_EINT(24)); - chained_irq_exit(chip, desc); -} - -static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc) -{ - u32 *irq_data = irq_get_handler_data(irq); - struct irq_chip *chip = irq_get_chip(irq); - - chained_irq_enter(chip, desc); - generic_handle_irq(*irq_data); - chained_irq_exit(chip, desc); -} - -static int __init exynos_init_irq_eint(void) -{ - int irq; - -#ifdef CONFIG_PINCTRL_SAMSUNG - /* - * The Samsung pinctrl driver provides an integrated gpio/pinmux/pinconf - * functionality along with support for external gpio and wakeup - * interrupts. If the samsung pinctrl driver is enabled and includes - * the wakeup interrupt support, then the setting up external wakeup - * interrupts here can be skipped. This check here is temporary to - * allow exynos4 platforms that do not use Samsung pinctrl driver to - * co-exist with platforms that do. When all of the Samsung Exynos4 - * platforms switch over to using the pinctrl driver, the wakeup - * interrupt support code here can be completely removed. - */ - static const struct of_device_id exynos_pinctrl_ids[] = { - { .compatible = "samsung,exynos4210-pinctrl", }, - { .compatible = "samsung,exynos4x12-pinctrl", }, - { .compatible = "samsung,exynos5250-pinctrl", }, - }; - struct device_node *pctrl_np, *wkup_np; - const char *wkup_compat = "samsung,exynos4210-wakeup-eint"; - - for_each_matching_node(pctrl_np, exynos_pinctrl_ids) { - if (of_device_is_available(pctrl_np)) { - wkup_np = of_find_compatible_node(pctrl_np, NULL, - wkup_compat); - if (wkup_np) - return -ENODEV; - } - } -#endif - if (soc_is_exynos5440()) - return 0; - - if (soc_is_exynos5250()) - exynos_eint_base = ioremap(EXYNOS5_PA_GPIO1, SZ_4K); - else - exynos_eint_base = ioremap(EXYNOS4_PA_GPIO2, SZ_4K); - - if (exynos_eint_base == NULL) { - pr_err("unable to ioremap for EINT base address\n"); - return -ENOMEM; - } - - for (irq = 0 ; irq <= 31 ; irq++) { - irq_set_chip_and_handler(IRQ_EINT(irq), &exynos_irq_eint, - handle_level_irq); - set_irq_flags(IRQ_EINT(irq), IRQF_VALID); - } - - irq_set_chained_handler(EXYNOS_IRQ_EINT16_31, exynos_irq_demux_eint16_31); - - for (irq = 0 ; irq <= 15 ; irq++) { - eint0_15_data[irq] = IRQ_EINT(irq); - - if (soc_is_exynos5250()) { - irq_set_handler_data(exynos5_eint0_15_src_int[irq], - &eint0_15_data[irq]); - irq_set_chained_handler(exynos5_eint0_15_src_int[irq], - exynos_irq_eint0_15); - } else { - irq_set_handler_data(exynos4_eint0_15_src_int[irq], - &eint0_15_data[irq]); - irq_set_chained_handler(exynos4_eint0_15_src_int[irq], - exynos_irq_eint0_15); - } - } - - return 0; -} -arch_initcall(exynos_init_irq_eint);