No subject


Fri Nov 6 13:01:15 EST 2009


leave this comment for now.

> >> +#define eint_irq_to_bit(irq)         (1 << (eint_offset(irq) & 0x7))
> >> +
> >> +#define eint_conf_reg(irq)           ((eint_offset(irq)) >> 3)
> >> +#define eint_mask_reg(irq)           ((eint_offset(irq)) >> 3)
> >> +#define eint_pend_reg(irq)           ((eint_offset(irq)) >> 3)
> >> +
> >> +/* values for S5P_EXTINT0 */
> >> +#define S5P_EXTINT_LOWLEV            (0x00)
> >> +#define S5P_EXTINT_HILEV             (0x01)
> >> +#define S5P_EXTINT_FALLEDGE          (0x02)
> >> +#define S5P_EXTINT_RISEEDGE          (0x03)
> >> +#define S5P_EXTINT_BOTHEDGE          (0x04)
> >> +
> >> +#endif /* __ASM_ARCH_REGS_GPIO_H */
> >> diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
> >> index d400a6a..7d1fc40 100644
> >> --- a/arch/arm/plat-s5p/Kconfig
> >> +++ b/arch/arm/plat-s5p/Kconfig
> >> @@ -23,3 +23,8 @@ config PLAT_S5P
> >>       select SAMSUNG_IRQ_UART
> >>       help
> >>         Base platform code for Samsung's S5P series SoC.
> >> +
> >> +config S5P_EXT_INT
> >> +     bool
> >> +     help
> >> +       Use the external interrupts (other than GPIO interrupts.)
> >> diff --git a/arch/arm/plat-s5p/Makefile b/arch/arm/plat-s5p/Makefile
> >> index a7c54b3..25941a5 100644
> >> --- a/arch/arm/plat-s5p/Makefile
> >> +++ b/arch/arm/plat-s5p/Makefile
> >> @@ -16,4 +16,5 @@ obj-y                               += dev-uart.o
> >>  obj-y                                += cpu.o
> >>  obj-y                                += clock.o
> >>  obj-y                                += irq.o
> >> +obj-$(CONFIG_S5P_EXT_INT)    += irq-eint.o
> >>  obj-y                                += setup-i2c0.o
> >> diff --git a/arch/arm/plat-s5p/irq-eint.c b/arch/arm/plat-s5p/irq-eint.c
> >> new file mode 100644
> >> index 0000000..484a8fe
> >> --- /dev/null
> >> +++ b/arch/arm/plat-s5p/irq-eint.c
> >> @@ -0,0 +1,216 @@
> >> +/* linux/arch/arm/plat-s5p/irq-eint.c
> >> + *
> >> + * Copyright (c) 2010 Samsung Electronics Co., Ltd.
> >> + *           http://www.samsung.com
> >> + *
> >> + * S5P - IRQ EINT support
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License version 2 as
> >> + * published by the Free Software Foundation.
> >> +*/
> >> +
> >> +#include <linux/kernel.h>
> >> +#include <linux/interrupt.h>
> >> +#include <linux/irq.h>
> >> +#include <linux/io.h>
> >> +#include <linux/sysdev.h>
> >> +#include <linux/gpio.h>
> >> +
> >> +#include <asm/bitops.h>
> >> +#include <asm/hardware/vic.h>
> >> +
> >> +#include <plat/regs-irqtype.h>
> >> +
> >> +#include <mach/map.h>
> >> +#include <plat/cpu.h>
> >> +#include <plat/pm.h>
> >> +
> >> +#include <plat/gpio-cfg.h>
> >> +#include <mach/regs-gpio.h>
> >> +
> >> +static inline void s5p_irq_eint_mask(unsigned int irq)
> >> +{
> >> +     u32 mask;
> >> +
> >> +     mask = __raw_readl(S5P_EINT_MASK(eint_mask_reg(irq)));
> >> +     mask |= eint_irq_to_bit(irq);
> >> +     __raw_writel(mask, S5P_EINT_MASK(eint_mask_reg(irq)));
> >> +}
> >> +
> >> +static void s5p_irq_eint_unmask(unsigned int irq)
> >> +{
> >> +     u32 mask;
> >> +
> >> +     mask = __raw_readl(S5P_EINT_MASK(eint_mask_reg(irq)));
> >> +     mask &= ~(eint_irq_to_bit(irq));
> >> +     __raw_writel(mask, S5P_EINT_MASK(eint_mask_reg(irq)));
> >> +}
> >> +
> >> +static inline void s5p_irq_eint_ack(unsigned int irq)
> >> +{
> >> +     __raw_writel(eint_irq_to_bit(irq), S5P_EINT_PEND(eint_pend_reg(irq)));
> >> +}
> >> +
> >> +static void s5p_irq_eint_maskack(unsigned int irq)
> >> +{
> >> +     /* compiler should in-line these */
> >> +     s5p_irq_eint_mask(irq);
> >> +     s5p_irq_eint_ack(irq);
> >> +}
> >> +
> >> +static int s5p_irq_eint_set_type(unsigned int irq, unsigned int type)
> >> +{
> >> +     int offs = eint_offset(irq);
> >> +     int shift;
> >> +     u32 ctrl, mask;
> >> +     u32 newvalue = 0;
> >> +
> >> +     switch (type) {
> >> +     case IRQ_TYPE_NONE:
> >> +             printk(KERN_WARNING "No edge setting!\n");
> >> +             break;
> >> +
> >> +     case IRQ_TYPE_EDGE_RISING:
> >> +             newvalue = S5P_EXTINT_RISEEDGE;
> >> +             break;
> >> +
> >> +     case IRQ_TYPE_EDGE_FALLING:
> >> +             newvalue = S5P_EXTINT_RISEEDGE;
> >> +             break;
> >> +
> >> +     case IRQ_TYPE_EDGE_BOTH:
> >> +             newvalue = S5P_EXTINT_BOTHEDGE;
> >> +             break;
> >> +
> >> +     case IRQ_TYPE_LEVEL_LOW:
> >> +             newvalue = S5P_EXTINT_LOWLEV;
> >> +             break;
> >> +
> >> +     case IRQ_TYPE_LEVEL_HIGH:
> >> +             newvalue = S5P_EXTINT_HILEV;
> >> +             break;
> >> +
> >> +     default:
> >> +             printk(KERN_ERR "No such irq type %d", type);
> >> +             return -EINVAL;
> >> +     }
> >> +
> >> +     shift = (offs & 0x7) * 4;
> >> +     mask = 0x7 << shift;
> >> +
> >> +     ctrl = __raw_readl(S5P_EINT_CON(eint_conf_reg(irq)));
> >> +     ctrl &= ~mask;
> >> +     ctrl |= newvalue << shift;
> >> +     __raw_writel(ctrl, S5P_EINT_CON(eint_conf_reg(irq)));
> >> +
> >> +     if ((0 <= offs) && (offs < 8))
> >> +             s3c_gpio_cfgpin(EINT_GPIO_REG0(offs & 0x7), EINT_MODE);
> >> +
> >> +     else if ((8 <= offs) && (offs < 16))
> >> +             s3c_gpio_cfgpin(EINT_GPIO_REG1(offs & 0x7), EINT_MODE);
> >> +
> >> +     else if ((16 <= offs) && (offs < 24))
> >> +             s3c_gpio_cfgpin(EINT_GPIO_REG2(offs & 0x7), EINT_MODE);
> >> +
> >> +     else if ((24 <= offs) && (offs < 32))
> >> +             s3c_gpio_cfgpin(EINT_GPIO_REG3(offs & 0x7), EINT_MODE);
> >> +
> >> +     else
> >> +             printk(KERN_ERR "No such irq number %d", offs);
> >> +
> >> +     return 0;
> >> +}
> >> +
> >> +static struct irq_chip s5p_irq_eint = {
> >> +     .name           = "s5p-eint",
> >> +     .mask           = s5p_irq_eint_mask,
> >> +     .unmask         = s5p_irq_eint_unmask,
> >> +     .mask_ack       = s5p_irq_eint_maskack,
> >> +     .ack            = s5p_irq_eint_ack,
> >> +     .set_type       = s5p_irq_eint_set_type,
> >> +#ifdef CONFIG_PM
> >> +     .set_wake       = s3c_irqext_wake,
> >> +#endif
> >> +};
> >> +
> >> +/* s5p_irq_demux_eint
> >> + *
> >> + * This function demuxes the IRQ from the group0 external interrupts,
> >> + * from IRQ_EINT(16) to IRQ_EINT(31). It is designed to be inlined into
> >> + * the specific handlers s5p_irq_demux_eintX_Y.
> >> + */
> >> +static inline void s5p_irq_demux_eint(unsigned int start, unsigned int end)
> >> +{
> >> +     u32 status;
> >> +     u32 mask = __raw_readl(S5P_EINT_MASK((start >> 3)));
> >> +     unsigned int irq;
> >> +
> >> +     status = __raw_readl(S5P_EINT_PEND((start >> 3)));
> >> +     status &= ~mask;
> >> +     status &= (1 << (end - start + 1)) - 1;
> >
> > We don't need to do any masking here as we'll always be processing all
> > interrupts from the controller. In fact, we probably don't need the end
> > argument here at-all.
> >
> >> +     while (status) {
> >> +             irq = fls(status);
> >> +             generic_handle_irq(irq - 1 + IRQ_EINT(start));
> >> +             status &= ~(1 << irq);
> >> +     }
> >> +}
> >> +
> >> +static void s5p_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
> >> +{
> >> +     s5p_irq_demux_eint(16, 23);
> >> +     s5p_irq_demux_eint(24, 31);

We can remove the end parameters, both interrupt banks are 8 IRQs and
this we can also make the bit clearing post mask a constant if it is
even needed.

> >> +}
> >> +
> >> +static inline void s5p_irq_vic_eint_mask(unsigned int irq)
> >> +{
> >> +     s5p_irq_eint_mask(irq);
> >> +}
> >> +
> >> +static void s5p_irq_vic_eint_unmask(unsigned int irq)
> >> +{
> >> +     s5p_irq_eint_unmask(irq);
> >> +}
> >> +
> >> +static inline void s5p_irq_vic_eint_ack(unsigned int irq)
> >> +{
> >> +     __raw_writel(eint_irq_to_bit(irq), S5P_EINT_PEND(eint_pend_reg(irq)));
> >> +}
> >> +
> >> +static void s5p_irq_vic_eint_maskack(unsigned int irq)
> >> +{
> >> +     s5p_irq_vic_eint_mask(irq);
> >> +     s5p_irq_vic_eint_ack(irq);
> >> +}
> >> +
> >> +static struct irq_chip s5p_irq_vic_eint = {
> >> +     .name           = "s5p_vic_eint",
> >> +     .mask           = s5p_irq_vic_eint_mask,
> >> +     .unmask         = s5p_irq_vic_eint_unmask,
> >> +     .mask_ack       = s5p_irq_vic_eint_maskack,
> >> +     .ack            = s5p_irq_vic_eint_ack,
> >> +     .set_type       = s5p_irq_eint_set_type,
> >> +#ifdef CONFIG_PM
> >> +     .set_wake       = s3c_irqext_wake,
> >> +#endif
> >> +};
> >> +
> >> +int __init s5p_init_irq_eint(void)
> >> +{
> >> +     int irq;
> >> +
> >> +     for (irq = IRQ_EINT(0); irq <= IRQ_EINT(15); irq++)
> >> +             set_irq_chip(irq, &s5p_irq_vic_eint);
> >> +
> >> +     for (irq = IRQ_EINT_GRP(16); irq <= IRQ_EINT_GRP(31); irq++) {
> >> +             set_irq_chip(irq, &s5p_irq_eint);
> >> +             set_irq_handler(irq, handle_level_irq);
> >> +             set_irq_flags(irq, IRQF_VALID);
> >> +     }
> >> +
> >> +     set_irq_chained_handler(IRQ_EINT16_31, s5p_irq_demux_eint16_31);
> >> +     return 0;
> >> +}
> >> +
> >> +arch_initcall(s5p_init_irq_eint);

-- 
Ben

Q:      What's a light-year?
A:      One-third less calories than a regular year.




More information about the linux-arm-kernel mailing list