From: Russell King Date: Fri, 12 Jun 2015 20:18:13 +0000 (+0100) Subject: Merge branch 'sa1100' into for-next X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=c62af70ff3015a4412c6655de602fdf7f1ecdaa6;p=deliverable%2Flinux.git Merge branch 'sa1100' into for-next --- c62af70ff3015a4412c6655de602fdf7f1ecdaa6 diff --cc drivers/irqchip/irq-sa11x0.c index 000000000000,97d257bd8b12..46df2875dc1c mode 000000,100644..100644 --- a/drivers/irqchip/irq-sa11x0.c +++ b/drivers/irqchip/irq-sa11x0.c @@@ -1,0 -1,175 +1,175 @@@ + /* + * Copyright (C) 2015 Dmitry Eremin-Solenikov + * Copyright (C) 1999-2001 Nicolas Pitre + * + * Generic IRQ handling for the SA11x0. + * + * 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 + #include + #include + #include + #include + #include + #include + #include + + #include + + #include + + #define ICIP 0x00 /* IC IRQ Pending reg. */ + #define ICMR 0x04 /* IC Mask Reg. */ + #define ICLR 0x08 /* IC Level Reg. */ + #define ICCR 0x0C /* IC Control Reg. */ + #define ICFP 0x10 /* IC FIQ Pending reg. */ + #define ICPR 0x20 /* IC Pending Reg. */ + + static void __iomem *iobase; + + /* + * We don't need to ACK IRQs on the SA1100 unless they're GPIOs + * this is for internal IRQs i.e. from IRQ LCD to RTCAlrm. + */ + static void sa1100_mask_irq(struct irq_data *d) + { + u32 reg; + + reg = readl_relaxed(iobase + ICMR); + reg &= ~BIT(d->hwirq); + writel_relaxed(reg, iobase + ICMR); + } + + static void sa1100_unmask_irq(struct irq_data *d) + { + u32 reg; + + reg = readl_relaxed(iobase + ICMR); + reg |= BIT(d->hwirq); + writel_relaxed(reg, iobase + ICMR); + } + + static int sa1100_set_wake(struct irq_data *d, unsigned int on) + { + return sa11x0_sc_set_wake(d->hwirq, on); + } + + static struct irq_chip sa1100_normal_chip = { + .name = "SC", + .irq_ack = sa1100_mask_irq, + .irq_mask = sa1100_mask_irq, + .irq_unmask = sa1100_unmask_irq, + .irq_set_wake = sa1100_set_wake, + }; + + static int sa1100_normal_irqdomain_map(struct irq_domain *d, + unsigned int irq, irq_hw_number_t hwirq) + { + irq_set_chip_and_handler(irq, &sa1100_normal_chip, + handle_level_irq); + set_irq_flags(irq, IRQF_VALID); + + return 0; + } + -static struct irq_domain_ops sa1100_normal_irqdomain_ops = { ++static const struct irq_domain_ops sa1100_normal_irqdomain_ops = { + .map = sa1100_normal_irqdomain_map, + .xlate = irq_domain_xlate_onetwocell, + }; + + static struct irq_domain *sa1100_normal_irqdomain; + + static struct sa1100irq_state { + unsigned int saved; + unsigned int icmr; + unsigned int iclr; + unsigned int iccr; + } sa1100irq_state; + + static int sa1100irq_suspend(void) + { + struct sa1100irq_state *st = &sa1100irq_state; + + st->saved = 1; + st->icmr = readl_relaxed(iobase + ICMR); + st->iclr = readl_relaxed(iobase + ICLR); + st->iccr = readl_relaxed(iobase + ICCR); + + /* + * Disable all GPIO-based interrupts. + */ + writel_relaxed(st->icmr & 0xfffff000, iobase + ICMR); + + return 0; + } + + static void sa1100irq_resume(void) + { + struct sa1100irq_state *st = &sa1100irq_state; + + if (st->saved) { + writel_relaxed(st->iccr, iobase + ICCR); + writel_relaxed(st->iclr, iobase + ICLR); + + writel_relaxed(st->icmr, iobase + ICMR); + } + } + + static struct syscore_ops sa1100irq_syscore_ops = { + .suspend = sa1100irq_suspend, + .resume = sa1100irq_resume, + }; + + static int __init sa1100irq_init_devicefs(void) + { + register_syscore_ops(&sa1100irq_syscore_ops); + return 0; + } + + device_initcall(sa1100irq_init_devicefs); + + static asmlinkage void __exception_irq_entry + sa1100_handle_irq(struct pt_regs *regs) + { + uint32_t icip, icmr, mask; + + do { + icip = readl_relaxed(iobase + ICIP); + icmr = readl_relaxed(iobase + ICMR); + mask = icip & icmr; + + if (mask == 0) + break; + + handle_domain_irq(sa1100_normal_irqdomain, + ffs(mask) - 1, regs); + } while (1); + } + + void __init sa11x0_init_irq_nodt(int irq_start, resource_size_t io_start) + { + iobase = ioremap(io_start, SZ_64K); + if (WARN_ON(!iobase)) + return; + + /* disable all IRQs */ + writel_relaxed(0, iobase + ICMR); + + /* all IRQs are IRQ, not FIQ */ + writel_relaxed(0, iobase + ICLR); + + /* + * Whatever the doc says, this has to be set for the wait-on-irq + * instruction to work... on a SA1100 rev 9 at least. + */ + writel_relaxed(1, iobase + ICCR); + + sa1100_normal_irqdomain = irq_domain_add_simple(NULL, + 32, irq_start, + &sa1100_normal_irqdomain_ops, NULL); + + set_handle_irq(sa1100_handle_irq); + }