diff options
| author | Jason Cooper <jason@lakedaemon.net> | 2014-09-14 03:53:17 -0400 |
|---|---|---|
| committer | Jason Cooper <jason@lakedaemon.net> | 2014-09-14 03:53:17 -0400 |
| commit | 1fc9d96ec63e7e071f22b89c268145d50720d667 (patch) | |
| tree | fb673039eabc9612e6f6209e88a762dcbf8ca919 | |
| parent | 705bc96c2c15313c0677607f6e81800f4d2b4534 (diff) | |
| parent | 8703ec19c706eb4d9f2848d50e9fc41d73eb4a40 (diff) | |
Merge branch 'irqchip/keystone' into irqchip/core
| -rw-r--r-- | Documentation/devicetree/bindings/interrupt-controller/ti,keystone-irq.txt | 36 | ||||
| -rw-r--r-- | drivers/irqchip/Kconfig | 7 | ||||
| -rw-r--r-- | drivers/irqchip/Makefile | 1 | ||||
| -rw-r--r-- | drivers/irqchip/irq-keystone.c | 232 |
4 files changed, 276 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/interrupt-controller/ti,keystone-irq.txt b/Documentation/devicetree/bindings/interrupt-controller/ti,keystone-irq.txt new file mode 100644 index 000000000000..d9bb106bdd16 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/ti,keystone-irq.txt | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | Keystone 2 IRQ controller IP | ||
| 2 | |||
| 3 | On Keystone SOCs, DSP cores can send interrupts to ARM | ||
| 4 | host using the IRQ controller IP. It provides 28 IRQ signals to ARM. | ||
| 5 | The IRQ handler running on HOST OS can identify DSP signal source by | ||
| 6 | analyzing SRCCx bits in IPCARx registers. This is one of the component | ||
| 7 | used by the IPC mechanism used on Keystone SOCs. | ||
| 8 | |||
| 9 | Required Properties: | ||
| 10 | - compatible: should be "ti,keystone-irq" | ||
| 11 | - ti,syscon-dev : phandle and offset pair. The phandle to syscon used to | ||
| 12 | access device control registers and the offset inside | ||
| 13 | device control registers range. | ||
| 14 | - interrupt-controller : Identifies the node as an interrupt controller | ||
| 15 | - #interrupt-cells : Specifies the number of cells needed to encode interrupt | ||
| 16 | source should be 1. | ||
| 17 | - interrupts: interrupt reference to primary interrupt controller | ||
| 18 | |||
| 19 | Please refer to interrupts.txt in this directory for details of the common | ||
| 20 | Interrupt Controllers bindings used by client devices. | ||
| 21 | |||
| 22 | Example: | ||
| 23 | kirq0: keystone_irq0@026202a0 { | ||
| 24 | compatible = "ti,keystone-irq"; | ||
| 25 | ti,syscon-dev = <&devctrl 0x2a0>; | ||
| 26 | interrupts = <GIC_SPI 4 IRQ_TYPE_EDGE_RISING>; | ||
| 27 | interrupt-controller; | ||
| 28 | #interrupt-cells = <1>; | ||
| 29 | }; | ||
| 30 | |||
| 31 | dsp0: dsp0 { | ||
| 32 | compatible = "linux,rproc-user"; | ||
| 33 | ... | ||
| 34 | interrupt-parent = <&kirq0>; | ||
| 35 | interrupts = <10 2>; | ||
| 36 | }; | ||
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index b8632bf9a7f3..c88896478e70 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig | |||
| @@ -113,3 +113,10 @@ config IRQ_CROSSBAR | |||
| 113 | The primary irqchip invokes the crossbar's callback which inturn allocates | 113 | The primary irqchip invokes the crossbar's callback which inturn allocates |
| 114 | a free irq and configures the IP. Thus the peripheral interrupts are | 114 | a free irq and configures the IP. Thus the peripheral interrupts are |
| 115 | routed to one of the free irqchip interrupt lines. | 115 | routed to one of the free irqchip interrupt lines. |
| 116 | |||
| 117 | config KEYSTONE_IRQ | ||
| 118 | tristate "Keystone 2 IRQ controller IP" | ||
| 119 | depends on ARCH_KEYSTONE | ||
| 120 | help | ||
| 121 | Support for Texas Instruments Keystone 2 IRQ controller IP which | ||
| 122 | is part of the Keystone 2 IPC mechanism | ||
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 73052ba9ca62..69fc7fc8d1bb 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile | |||
| @@ -34,3 +34,4 @@ obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o | |||
| 34 | obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o | 34 | obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o |
| 35 | obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o | 35 | obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o |
| 36 | obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o | 36 | obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o |
| 37 | obj-$(CONFIG_KEYSTONE_IRQ) += irq-keystone.o | ||
diff --git a/drivers/irqchip/irq-keystone.c b/drivers/irqchip/irq-keystone.c new file mode 100644 index 000000000000..608abf9c9283 --- /dev/null +++ b/drivers/irqchip/irq-keystone.c | |||
| @@ -0,0 +1,232 @@ | |||
| 1 | /* | ||
| 2 | * Texas Instruments Keystone IRQ controller IP driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014 Texas Instruments, Inc. | ||
| 5 | * Author: Sajesh Kumar Saran <sajesh@ti.com> | ||
| 6 | * Grygorii Strashko <grygorii.strashko@ti.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or | ||
| 9 | * modify it under the terms of the GNU General Public License as | ||
| 10 | * published by the Free Software Foundation version 2. | ||
| 11 | * | ||
| 12 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
| 13 | * kind, whether express or implied; without even the implied warranty | ||
| 14 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <linux/irq.h> | ||
| 19 | #include <linux/bitops.h> | ||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/moduleparam.h> | ||
| 22 | #include <linux/irqdomain.h> | ||
| 23 | #include <linux/irqchip/chained_irq.h> | ||
| 24 | #include <linux/of.h> | ||
| 25 | #include <linux/of_platform.h> | ||
| 26 | #include <linux/mfd/syscon.h> | ||
| 27 | #include <linux/regmap.h> | ||
| 28 | #include "irqchip.h" | ||
| 29 | |||
| 30 | |||
| 31 | /* The source ID bits start from 4 to 31 (total 28 bits)*/ | ||
| 32 | #define BIT_OFS 4 | ||
| 33 | #define KEYSTONE_N_IRQ (32 - BIT_OFS) | ||
| 34 | |||
| 35 | struct keystone_irq_device { | ||
| 36 | struct device *dev; | ||
| 37 | struct irq_chip chip; | ||
| 38 | u32 mask; | ||
| 39 | int irq; | ||
| 40 | struct irq_domain *irqd; | ||
| 41 | struct regmap *devctrl_regs; | ||
| 42 | u32 devctrl_offset; | ||
| 43 | }; | ||
| 44 | |||
| 45 | static inline u32 keystone_irq_readl(struct keystone_irq_device *kirq) | ||
| 46 | { | ||
| 47 | int ret; | ||
| 48 | u32 val = 0; | ||
| 49 | |||
| 50 | ret = regmap_read(kirq->devctrl_regs, kirq->devctrl_offset, &val); | ||
| 51 | if (ret < 0) | ||
| 52 | dev_dbg(kirq->dev, "irq read failed ret(%d)\n", ret); | ||
| 53 | return val; | ||
| 54 | } | ||
| 55 | |||
| 56 | static inline void | ||
| 57 | keystone_irq_writel(struct keystone_irq_device *kirq, u32 value) | ||
| 58 | { | ||
| 59 | int ret; | ||
| 60 | |||
| 61 | ret = regmap_write(kirq->devctrl_regs, kirq->devctrl_offset, value); | ||
| 62 | if (ret < 0) | ||
| 63 | dev_dbg(kirq->dev, "irq write failed ret(%d)\n", ret); | ||
| 64 | } | ||
| 65 | |||
| 66 | static void keystone_irq_setmask(struct irq_data *d) | ||
| 67 | { | ||
| 68 | struct keystone_irq_device *kirq = irq_data_get_irq_chip_data(d); | ||
| 69 | |||
| 70 | kirq->mask |= BIT(d->hwirq); | ||
| 71 | dev_dbg(kirq->dev, "mask %lu [%x]\n", d->hwirq, kirq->mask); | ||
| 72 | } | ||
| 73 | |||
| 74 | static void keystone_irq_unmask(struct irq_data *d) | ||
| 75 | { | ||
| 76 | struct keystone_irq_device *kirq = irq_data_get_irq_chip_data(d); | ||
| 77 | |||
| 78 | kirq->mask &= ~BIT(d->hwirq); | ||
| 79 | dev_dbg(kirq->dev, "unmask %lu [%x]\n", d->hwirq, kirq->mask); | ||
| 80 | } | ||
| 81 | |||
| 82 | static void keystone_irq_ack(struct irq_data *d) | ||
| 83 | { | ||
| 84 | /* nothing to do here */ | ||
| 85 | } | ||
| 86 | |||
| 87 | static void keystone_irq_handler(unsigned irq, struct irq_desc *desc) | ||
| 88 | { | ||
| 89 | struct keystone_irq_device *kirq = irq_desc_get_handler_data(desc); | ||
| 90 | unsigned long pending; | ||
| 91 | int src, virq; | ||
| 92 | |||
| 93 | dev_dbg(kirq->dev, "start irq %d\n", irq); | ||
| 94 | |||
| 95 | chained_irq_enter(irq_desc_get_chip(desc), desc); | ||
| 96 | |||
| 97 | pending = keystone_irq_readl(kirq); | ||
| 98 | keystone_irq_writel(kirq, pending); | ||
| 99 | |||
| 100 | dev_dbg(kirq->dev, "pending 0x%lx, mask 0x%x\n", pending, kirq->mask); | ||
| 101 | |||
| 102 | pending = (pending >> BIT_OFS) & ~kirq->mask; | ||
| 103 | |||
| 104 | dev_dbg(kirq->dev, "pending after mask 0x%lx\n", pending); | ||
| 105 | |||
| 106 | for (src = 0; src < KEYSTONE_N_IRQ; src++) { | ||
| 107 | if (BIT(src) & pending) { | ||
| 108 | virq = irq_find_mapping(kirq->irqd, src); | ||
| 109 | dev_dbg(kirq->dev, "dispatch bit %d, virq %d\n", | ||
| 110 | src, virq); | ||
| 111 | if (!virq) | ||
| 112 | dev_warn(kirq->dev, "sporious irq detected hwirq %d, virq %d\n", | ||
| 113 | src, virq); | ||
| 114 | generic_handle_irq(virq); | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | chained_irq_exit(irq_desc_get_chip(desc), desc); | ||
| 119 | |||
| 120 | dev_dbg(kirq->dev, "end irq %d\n", irq); | ||
| 121 | } | ||
