Commit 1cf02bbd authored by Russell King's avatar Russell King

Merge branch 'samsung-irq' of...

Merge branch 'samsung-irq' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/misc-2.6 into devel-stable
parents 805499a6 bd7e3880
...@@ -58,12 +58,7 @@ void __init s3c64xx_init_irq(u32 vic0_valid, u32 vic1_valid) ...@@ -58,12 +58,7 @@ void __init s3c64xx_init_irq(u32 vic0_valid, u32 vic1_valid)
vic_init(VA_VIC1, IRQ_VIC1_BASE, vic1_valid, 0); vic_init(VA_VIC1, IRQ_VIC1_BASE, vic1_valid, 0);
/* add the timer sub-irqs */ /* add the timer sub-irqs */
s3c_init_vic_timer_irq(5, IRQ_TIMER0);
s3c_init_vic_timer_irq(IRQ_TIMER0_VIC, IRQ_TIMER0);
s3c_init_vic_timer_irq(IRQ_TIMER1_VIC, IRQ_TIMER1);
s3c_init_vic_timer_irq(IRQ_TIMER2_VIC, IRQ_TIMER2);
s3c_init_vic_timer_irq(IRQ_TIMER3_VIC, IRQ_TIMER3);
s3c_init_vic_timer_irq(IRQ_TIMER4_VIC, IRQ_TIMER4);
s3c_init_uart_irqs(uart_irqs, ARRAY_SIZE(uart_irqs)); s3c_init_uart_irqs(uart_irqs, ARRAY_SIZE(uart_irqs));
} }
...@@ -41,72 +41,11 @@ struct s5p_gpioint_bank { ...@@ -41,72 +41,11 @@ struct s5p_gpioint_bank {
LIST_HEAD(banks); LIST_HEAD(banks);
static int s5p_gpioint_get_offset(struct irq_data *data) static int s5p_gpioint_set_type(struct irq_data *d, unsigned int type)
{ {
struct s3c_gpio_chip *chip = irq_data_get_irq_handler_data(data); struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
return data->irq - chip->irq_base; struct irq_chip_type *ct = gc->chip_types;
} unsigned int shift = (d->irq - gc->irq_base) << 2;
static void s5p_gpioint_ack(struct irq_data *data)
{
struct s3c_gpio_chip *chip = irq_data_get_irq_handler_data(data);
int group, offset, pend_offset;
unsigned int value;
group = chip->group;
offset = s5p_gpioint_get_offset(data);
pend_offset = REG_OFFSET(group);
value = __raw_readl(GPIO_BASE(chip) + PEND_OFFSET + pend_offset);
value |= BIT(offset);
__raw_writel(value, GPIO_BASE(chip) + PEND_OFFSET + pend_offset);
}
static void s5p_gpioint_mask(struct irq_data *data)
{
struct s3c_gpio_chip *chip = irq_data_get_irq_handler_data(data);
int group, offset, mask_offset;
unsigned int value;
group = chip->group;
offset = s5p_gpioint_get_offset(data);
mask_offset = REG_OFFSET(group);
value = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
value |= BIT(offset);
__raw_writel(value, GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
}
static void s5p_gpioint_unmask(struct irq_data *data)
{
struct s3c_gpio_chip *chip = irq_data_get_irq_handler_data(data);
int group, offset, mask_offset;
unsigned int value;
group = chip->group;
offset = s5p_gpioint_get_offset(data);
mask_offset = REG_OFFSET(group);
value = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
value &= ~BIT(offset);
__raw_writel(value, GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
}
static void s5p_gpioint_mask_ack(struct irq_data *data)
{
s5p_gpioint_mask(data);
s5p_gpioint_ack(data);
}
static int s5p_gpioint_set_type(struct irq_data *data, unsigned int type)
{
struct s3c_gpio_chip *chip = irq_data_get_irq_handler_data(data);
int group, offset, con_offset;
unsigned int value;
group = chip->group;
offset = s5p_gpioint_get_offset(data);
con_offset = REG_OFFSET(group);
switch (type) { switch (type) {
case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_EDGE_RISING:
...@@ -130,23 +69,12 @@ static int s5p_gpioint_set_type(struct irq_data *data, unsigned int type) ...@@ -130,23 +69,12 @@ static int s5p_gpioint_set_type(struct irq_data *data, unsigned int type)
return -EINVAL; return -EINVAL;
} }
value = __raw_readl(GPIO_BASE(chip) + CON_OFFSET + con_offset); gc->type_cache &= ~(0x7 << shift);
value &= ~(0x7 << (offset * 0x4)); gc->type_cache |= type << shift;
value |= (type << (offset * 0x4)); writel(gc->type_cache, gc->reg_base + ct->regs.type);
__raw_writel(value, GPIO_BASE(chip) + CON_OFFSET + con_offset);
return 0; return 0;
} }
static struct irq_chip s5p_gpioint = {
.name = "s5p_gpioint",
.irq_ack = s5p_gpioint_ack,
.irq_mask = s5p_gpioint_mask,
.irq_mask_ack = s5p_gpioint_mask_ack,
.irq_unmask = s5p_gpioint_unmask,
.irq_set_type = s5p_gpioint_set_type,
};
static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc) static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc)
{ {
struct s5p_gpioint_bank *bank = irq_get_handler_data(irq); struct s5p_gpioint_bank *bank = irq_get_handler_data(irq);
...@@ -179,9 +107,10 @@ static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc) ...@@ -179,9 +107,10 @@ static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc)
static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip) static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip)
{ {
static int used_gpioint_groups = 0; static int used_gpioint_groups = 0;
int irq, group = chip->group; int group = chip->group;
int i;
struct s5p_gpioint_bank *bank = NULL; struct s5p_gpioint_bank *bank = NULL;
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
if (used_gpioint_groups >= S5P_GPIOINT_GROUP_COUNT) if (used_gpioint_groups >= S5P_GPIOINT_GROUP_COUNT)
return -ENOMEM; return -ENOMEM;
...@@ -211,19 +140,28 @@ static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip) ...@@ -211,19 +140,28 @@ static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip)
* chained GPIO irq has been successfully registered, allocate new gpio * chained GPIO irq has been successfully registered, allocate new gpio
* int group and assign irq nubmers * int group and assign irq nubmers
*/ */
chip->irq_base = S5P_GPIOINT_BASE + chip->irq_base = S5P_GPIOINT_BASE +
used_gpioint_groups * S5P_GPIOINT_GROUP_SIZE; used_gpioint_groups * S5P_GPIOINT_GROUP_SIZE;
used_gpioint_groups++; used_gpioint_groups++;
bank->chips[group - bank->start] = chip; bank->chips[group - bank->start] = chip;
for (i = 0; i < chip->chip.ngpio; i++) {
irq = chip->irq_base + i; gc = irq_alloc_generic_chip("s5p_gpioint", 1, chip->irq_base,
irq_set_chip(irq, &s5p_gpioint); (void __iomem *)GPIO_BASE(chip),
irq_set_handler_data(irq, chip); handle_level_irq);
irq_set_handler(irq, handle_level_irq); if (!gc)
set_irq_flags(irq, IRQF_VALID); return -ENOMEM;
} ct = gc->chip_types;
ct->chip.irq_ack = irq_gc_ack;
ct->chip.irq_mask = irq_gc_mask_set_bit;
ct->chip.irq_unmask = irq_gc_mask_clr_bit;
ct->chip.irq_set_type = s5p_gpioint_set_type,
ct->regs.ack = PEND_OFFSET + REG_OFFSET(chip->group);
ct->regs.mask = MASK_OFFSET + REG_OFFSET(chip->group);
ct->regs.type = CON_OFFSET + REG_OFFSET(chip->group);
irq_setup_generic_chip(gc, IRQ_MSK(chip->chip.ngpio),
IRQ_GC_INIT_MASK_CACHE,
IRQ_NOREQUEST | IRQ_NOPROBE, 0);
return 0; return 0;
} }
......
...@@ -64,11 +64,7 @@ void __init s5p_init_irq(u32 *vic, u32 num_vic) ...@@ -64,11 +64,7 @@ void __init s5p_init_irq(u32 *vic, u32 num_vic)
vic_init(VA_VIC(irq), VIC_BASE(irq), vic[irq], 0); vic_init(VA_VIC(irq), VIC_BASE(irq), vic[irq], 0);
#endif #endif
s3c_init_vic_timer_irq(IRQ_TIMER0_VIC, IRQ_TIMER0); s3c_init_vic_timer_irq(5, IRQ_TIMER0);
s3c_init_vic_timer_irq(IRQ_TIMER1_VIC, IRQ_TIMER1);
s3c_init_vic_timer_irq(IRQ_TIMER2_VIC, IRQ_TIMER2);
s3c_init_vic_timer_irq(IRQ_TIMER3_VIC, IRQ_TIMER3);
s3c_init_vic_timer_irq(IRQ_TIMER4_VIC, IRQ_TIMER4);
s3c_init_uart_irqs(uart_irqs, ARRAY_SIZE(uart_irqs)); s3c_init_uart_irqs(uart_irqs, ARRAY_SIZE(uart_irqs));
} }
...@@ -10,4 +10,4 @@ ...@@ -10,4 +10,4 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
extern void s3c_init_vic_timer_irq(unsigned int vic, unsigned int timer); extern void s3c_init_vic_timer_irq(unsigned int num, unsigned int timer_irq);
...@@ -27,60 +27,6 @@ ...@@ -27,60 +27,6 @@
/* Note, we make use of the fact that the parent IRQs, IRQ_UART[0..3] /* Note, we make use of the fact that the parent IRQs, IRQ_UART[0..3]
* are consecutive when looking up the interrupt in the demux routines. * are consecutive when looking up the interrupt in the demux routines.
*/ */
static inline void __iomem *s3c_irq_uart_base(struct irq_data *data)
{
struct s3c_uart_irq *uirq = irq_data_get_irq_chip_data(data);
return uirq->regs;
}
static inline unsigned int s3c_irq_uart_bit(unsigned int irq)
{
return irq & 3;
}
static void s3c_irq_uart_mask(struct irq_data *data)
{
void __iomem *regs = s3c_irq_uart_base(data);
unsigned int bit = s3c_irq_uart_bit(data->irq);
u32 reg;
reg = __raw_readl(regs + S3C64XX_UINTM);
reg |= (1 << bit);
__raw_writel(reg, regs + S3C64XX_UINTM);
}
static void s3c_irq_uart_maskack(struct irq_data *data)
{
void __iomem *regs = s3c_irq_uart_base(data);
unsigned int bit = s3c_irq_uart_bit(data->irq);
u32 reg;
reg = __raw_readl(regs + S3C64XX_UINTM);
reg |= (1 << bit);
__raw_writel(reg, regs + S3C64XX_UINTM);
__raw_writel(1 << bit, regs + S3C64XX_UINTP);
}
static void s3c_irq_uart_unmask(struct irq_data *data)
{
void __iomem *regs = s3c_irq_uart_base(data);
unsigned int bit = s3c_irq_uart_bit(data->irq);
u32 reg;
reg = __raw_readl(regs + S3C64XX_UINTM);
reg &= ~(1 << bit);
__raw_writel(reg, regs + S3C64XX_UINTM);
}
static void s3c_irq_uart_ack(struct irq_data *data)
{
void __iomem *regs = s3c_irq_uart_base(data);
unsigned int bit = s3c_irq_uart_bit(data->irq);
__raw_writel(1 << bit, regs + S3C64XX_UINTP);
}
static void s3c_irq_demux_uart(unsigned int irq, struct irq_desc *desc) static void s3c_irq_demux_uart(unsigned int irq, struct irq_desc *desc)
{ {
struct s3c_uart_irq *uirq = desc->irq_data.handler_data; struct s3c_uart_irq *uirq = desc->irq_data.handler_data;
...@@ -97,30 +43,25 @@ static void s3c_irq_demux_uart(unsigned int irq, struct irq_desc *desc) ...@@ -97,30 +43,25 @@ static void s3c_irq_demux_uart(unsigned int irq, struct irq_desc *desc)
generic_handle_irq(base + 3); generic_handle_irq(base + 3);
} }
static struct irq_chip s3c_irq_uart = {
.name = "s3c-uart",
.irq_mask = s3c_irq_uart_mask,
.irq_unmask = s3c_irq_uart_unmask,
.irq_mask_ack = s3c_irq_uart_maskack,
.irq_ack = s3c_irq_uart_ack,
};
static void __init s3c_init_uart_irq(struct s3c_uart_irq *uirq) static void __init s3c_init_uart_irq(struct s3c_uart_irq *uirq)
{ {
void __iomem *reg_base = uirq->regs; void __iomem *reg_base = uirq->regs;
unsigned int irq; struct irq_chip_generic *gc;
int offs; struct irq_chip_type *ct;
/* mask all interrupts at the start. */ /* mask all interrupts at the start. */
__raw_writel(0xf, reg_base + S3C64XX_UINTM); __raw_writel(0xf, reg_base + S3C64XX_UINTM);
for (offs = 0; offs < 3; offs++) { gc = irq_alloc_generic_chip("s3c-uart", 1, uirq->base_irq, reg_base,
irq = uirq->base_irq + offs; handle_level_irq);
ct = gc->chip_types;
irq_set_chip_and_handler(irq, &s3c_irq_uart, handle_level_irq); ct->chip.irq_ack = irq_gc_ack;
irq_set_chip_data(irq, uirq); ct->chip.irq_mask = irq_gc_mask_set_bit;
set_irq_flags(irq, IRQF_VALID); ct->chip.irq_unmask = irq_gc_mask_clr_bit;
} ct->regs.ack = S3C64XX_UINTP;
ct->regs.mask = S3C64XX_UINTM;
irq_setup_generic_chip(gc, IRQ_MSK(4), IRQ_GC_INIT_MASK_CACHE,
IRQ_NOREQUEST | IRQ_NOPROBE, 0);
irq_set_handler_data(uirq->parent_irq, uirq); irq_set_handler_data(uirq->parent_irq, uirq);
irq_set_chained_handler(uirq->parent_irq, s3c_irq_demux_uart); irq_set_chained_handler(uirq->parent_irq, s3c_irq_demux_uart);
......
...@@ -28,60 +28,43 @@ static void s3c_irq_demux_vic_timer(unsigned int irq, struct irq_desc *desc) ...@@ -28,60 +28,43 @@ static void s3c_irq_demux_vic_timer(unsigned int irq, struct irq_desc *desc)
} }
/* We assume the IRQ_TIMER0..IRQ_TIMER4 range is continuous. */ /* We assume the IRQ_TIMER0..IRQ_TIMER4 range is continuous. */
static void s3c_irq_timer_ack(struct irq_data *d)
static void s3c_irq_timer_mask(struct irq_data *data)
{
u32 reg = __raw_readl(S3C64XX_TINT_CSTAT);
u32 mask = (u32)data->chip_data;
reg &= 0x1f; /* mask out pending interrupts */
reg &= ~mask;
__raw_writel(reg, S3C64XX_TINT_CSTAT);
}
static void s3c_irq_timer_unmask(struct irq_data *data)
{ {
u32 reg = __raw_readl(S3C64XX_TINT_CSTAT); struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
u32 mask = (u32)data->chip_data; u32 mask = (1 << 5) << (d->irq - gc->irq_base);
reg &= 0x1f; /* mask out pending interrupts */ irq_reg_writel(mask | gc->mask_cache, gc->reg_base);
reg |= mask;
__raw_writel(reg, S3C64XX_TINT_CSTAT);
} }
static void s3c_irq_timer_ack(struct irq_data *data)
{
u32 reg = __raw_readl(S3C64XX_TINT_CSTAT);
u32 mask = (u32)data->chip_data;
reg &= 0x1f;
reg |= mask << 5;
__raw_writel(reg, S3C64XX_TINT_CSTAT);
}
static struct irq_chip s3c_irq_timer = {
.name = "s3c-timer",
.irq_mask = s3c_irq_timer_mask,
.irq_unmask = s3c_irq_timer_unmask,
.irq_ack = s3c_irq_timer_ack,
};
/** /**
* s3c_init_vic_timer_irq() - initialise timer irq chanined off VIC.\ * s3c_init_vic_timer_irq() - initialise timer irq chanined off VIC.\
* @parent_irq: The parent IRQ on the VIC for the timer. * @num: Number of timers to initialize
* @timer_irq: The IRQ to be used for the timer. * @timer_irq: Base IRQ number to be used for the timers.
* *
* Register the necessary IRQ chaining and support for the timer IRQs * Register the necessary IRQ chaining and support for the timer IRQs
* chained of the VIC. * chained of the VIC.
*/ */
void __init s3c_init_vic_timer_irq(unsigned int parent_irq, void __init s3c_init_vic_timer_irq(unsigned int num, unsigned int timer_irq)
unsigned int timer_irq)
{ {
unsigned int pirq[5] = { IRQ_TIMER0_VIC, IRQ_TIMER1_VIC, IRQ_TIMER2_VIC,
IRQ_TIMER3_VIC, IRQ_TIMER4_VIC };
struct irq_chip_generic *s3c_tgc;
struct irq_chip_type *ct;
unsigned int i;
irq_set_chained_handler(parent_irq, s3c_irq_demux_vic_timer); s3c_tgc = irq_alloc_generic_chip("s3c-timer", 1, timer_irq,
irq_set_handler_data(parent_irq, (void *)timer_irq); S3C64XX_TINT_CSTAT, handle_level_irq);
ct = s3c_tgc->chip_types;
ct->chip.irq_mask = irq_gc_mask_clr_bit;
ct->chip.irq_unmask = irq_gc_mask_set_bit;
ct->chip.irq_ack = s3c_irq_timer_ack;
irq_setup_generic_chip(s3c_tgc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
IRQ_NOREQUEST | IRQ_NOPROBE, 0);
/* Clear the upper bits of the mask_cache*/
s3c_tgc->mask_cache &= 0x1f;
irq_set_chip_and_handler(timer_irq, &s3c_irq_timer, handle_level_irq); for (i = 0; i < num; i++, timer_irq++) {
irq_set_chip_data(timer_irq, (void *)(1 << (timer_irq - IRQ_TIMER0))); irq_set_chained_handler(pirq[i], s3c_irq_demux_vic_timer);
set_irq_flags(timer_irq, IRQF_VALID); irq_set_handler_data(pirq[i], (void *)timer_irq);
}
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment