diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-02 09:03:55 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-02 09:03:55 -0700 | 
| commit | a7726350e06401929eac0aa0677a5467106565fc (patch) | |
| tree | e189513e5014bdfccd73a3af731a6b57733743fa /drivers/irqchip/irq-sun4i.c | |
| parent | 4d26aa305414dbb33b3c32fb205b68004cda8ffc (diff) | |
| parent | afcf7924ecab726dab0227188783c4a40d9f0eec (diff) | |
| download | olio-linux-3.10-a7726350e06401929eac0aa0677a5467106565fc.tar.xz olio-linux-3.10-a7726350e06401929eac0aa0677a5467106565fc.zip  | |
Merge tag 'cleanup-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC cleanup from Olof Johansson:
 "Here is a collection of cleanup patches.  Among the pieces that stand
  out are:
   - The deletion of h720x platforms
   - Split of at91 non-dt platforms to their own Kconfig file to keep
     them separate
   - General cleanups and refactoring of i.MX and MXS platforms
   - Some restructuring of clock tables for OMAP
   - Convertion of PMC driver for Tegra to dt-only
   - Some renames of sunxi -> sun4i (Allwinner A10)
   - ... plus a bunch of other stuff that I haven't mentioned"
* tag 'cleanup-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (119 commits)
  ARM: i.MX: remove unused ARCH_* configs
  ARM i.MX53: remove platform ahci support
  ARM: sunxi: Rework the restart code
  irqchip: sunxi: Rename sunxi to sun4i
  irqchip: sunxi: Make use of the IRQCHIP_DECLARE macro
  clocksource: sunxi: Rename sunxi to sun4i
  clocksource: sunxi: make use of CLKSRC_OF
  clocksource: sunxi: Cleanup the timer code
  ARM: at91: remove trailing semicolon from macros
  ARM: at91/setup: fix trivial typos
  ARM: EXYNOS: remove "config EXYNOS_DEV_DRM"
  ARM: EXYNOS: change the name of USB ohci header
  ARM: SAMSUNG: Remove unnecessary code for dma
  ARM: S3C24XX: Remove unused GPIO drive strength register definitions
  ARM: OMAP4+: PM: Restore CPU power state to ON with clockdomain force wakeup method
  ARM: S3C24XX: Removed unneeded dependency on CPU_S3C2412
  ARM: S3C24XX: Removed unneeded dependency on CPU_S3C2410
  ARM: S3C24XX: Removed unneeded dependency on ARCH_S3C24XX for boards
  ARM: SAMSUNG: Fix typo "CONFIG_SAMSUNG_DEV_RTC"
  ARM: S5P64X0: Fix typo "CONFIG_S5P64X0_SETUP_SDHCI"
  ...
Diffstat (limited to 'drivers/irqchip/irq-sun4i.c')
| -rw-r--r-- | drivers/irqchip/irq-sun4i.c | 149 | 
1 files changed, 149 insertions, 0 deletions
diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c new file mode 100644 index 00000000000..b66d4ae0689 --- /dev/null +++ b/drivers/irqchip/irq-sun4i.c @@ -0,0 +1,149 @@ +/* + * Allwinner A1X SoCs IRQ chip driver. + * + * Copyright (C) 2012 Maxime Ripard + * + * Maxime Ripard <maxime.ripard@free-electrons.com> + * + * Based on code from + * Allwinner Technology Co., Ltd. <www.allwinnertech.com> + * Benn Huang <benn@allwinnertech.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2.  This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> + +#include <asm/exception.h> +#include <asm/mach/irq.h> + +#include "irqchip.h" + +#define SUN4I_IRQ_VECTOR_REG		0x00 +#define SUN4I_IRQ_PROTECTION_REG	0x08 +#define SUN4I_IRQ_NMI_CTRL_REG		0x0c +#define SUN4I_IRQ_PENDING_REG(x)	(0x10 + 0x4 * x) +#define SUN4I_IRQ_FIQ_PENDING_REG(x)	(0x20 + 0x4 * x) +#define SUN4I_IRQ_ENABLE_REG(x)		(0x40 + 0x4 * x) +#define SUN4I_IRQ_MASK_REG(x)		(0x50 + 0x4 * x) + +static void __iomem *sun4i_irq_base; +static struct irq_domain *sun4i_irq_domain; + +static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs); + +void sun4i_irq_ack(struct irq_data *irqd) +{ +	unsigned int irq = irqd_to_hwirq(irqd); +	unsigned int irq_off = irq % 32; +	int reg = irq / 32; +	u32 val; + +	val = readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg)); +	writel(val | (1 << irq_off), +	       sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg)); +} + +static void sun4i_irq_mask(struct irq_data *irqd) +{ +	unsigned int irq = irqd_to_hwirq(irqd); +	unsigned int irq_off = irq % 32; +	int reg = irq / 32; +	u32 val; + +	val = readl(sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(reg)); +	writel(val & ~(1 << irq_off), +	       sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(reg)); +} + +static void sun4i_irq_unmask(struct irq_data *irqd) +{ +	unsigned int irq = irqd_to_hwirq(irqd); +	unsigned int irq_off = irq % 32; +	int reg = irq / 32; +	u32 val; + +	val = readl(sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(reg)); +	writel(val | (1 << irq_off), +	       sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(reg)); +} + +static struct irq_chip sun4i_irq_chip = { +	.name		= "sun4i_irq", +	.irq_ack	= sun4i_irq_ack, +	.irq_mask	= sun4i_irq_mask, +	.irq_unmask	= sun4i_irq_unmask, +}; + +static int sun4i_irq_map(struct irq_domain *d, unsigned int virq, +			 irq_hw_number_t hw) +{ +	irq_set_chip_and_handler(virq, &sun4i_irq_chip, +				 handle_level_irq); +	set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); + +	return 0; +} + +static struct irq_domain_ops sun4i_irq_ops = { +	.map = sun4i_irq_map, +	.xlate = irq_domain_xlate_onecell, +}; + +static int __init sun4i_of_init(struct device_node *node, +				struct device_node *parent) +{ +	sun4i_irq_base = of_iomap(node, 0); +	if (!sun4i_irq_base) +		panic("%s: unable to map IC registers\n", +			node->full_name); + +	/* Disable all interrupts */ +	writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(0)); +	writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(1)); +	writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(2)); + +	/* Mask all the interrupts */ +	writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(0)); +	writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(1)); +	writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(2)); + +	/* Clear all the pending interrupts */ +	writel(0xffffffff, sun4i_irq_base + SUN4I_IRQ_PENDING_REG(0)); +	writel(0xffffffff, sun4i_irq_base + SUN4I_IRQ_PENDING_REG(1)); +	writel(0xffffffff, sun4i_irq_base + SUN4I_IRQ_PENDING_REG(2)); + +	/* Enable protection mode */ +	writel(0x01, sun4i_irq_base + SUN4I_IRQ_PROTECTION_REG); + +	/* Configure the external interrupt source type */ +	writel(0x00, sun4i_irq_base + SUN4I_IRQ_NMI_CTRL_REG); + +	sun4i_irq_domain = irq_domain_add_linear(node, 3 * 32, +						 &sun4i_irq_ops, NULL); +	if (!sun4i_irq_domain) +		panic("%s: unable to create IRQ domain\n", node->full_name); + +	set_handle_irq(sun4i_handle_irq); + +	return 0; +} +IRQCHIP_DECLARE(allwinner_sun4i_ic, "allwinner,sun4i-ic", sun4i_of_init); + +static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs) +{ +	u32 irq, hwirq; + +	hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2; +	while (hwirq != 0) { +		irq = irq_find_mapping(sun4i_irq_domain, hwirq); +		handle_IRQ(irq, regs); +		hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2; +	} +}  |