Merge tag 'v3.3-rc7' into gpio/next
authorGrant Likely <grant.likely@secretlab.ca>
Mon, 12 Mar 2012 15:41:28 +0000 (09:41 -0600)
committerGrant Likely <grant.likely@secretlab.ca>
Mon, 12 Mar 2012 15:41:28 +0000 (09:41 -0600)
Linux 3.3-rc7.  Merged into the gpio branch to pick up gpio bugfixes already
in mainline before queueing up move v3.4 patches

109 files changed:
Documentation/IRQ-domain.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio-omap.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/sodaville.txt [new file with mode: 0644]
Documentation/gpio.txt
MAINTAINERS
arch/arm/common/gic.c
arch/arm/common/vic.c
arch/arm/include/asm/hardware/gic.h
arch/arm/include/asm/hardware/vic.h
arch/arm/mach-exynos/common.c
arch/arm/mach-imx/imx51-dt.c
arch/arm/mach-imx/imx53-dt.c
arch/arm/mach-imx/mach-imx6q.c
arch/arm/mach-msm/board-msm8x60.c
arch/arm/mach-omap1/gpio15xx.c
arch/arm/mach-omap1/gpio16xx.c
arch/arm/mach-omap1/gpio7xx.c
arch/arm/mach-omap2/board-generic.c
arch/arm/mach-omap2/gpio.c
arch/arm/mach-omap2/pm34xx.c
arch/arm/mach-prima2/irq.c
arch/arm/mach-versatile/core.c
arch/arm/plat-omap/include/plat/gpio.h
arch/c6x/Kconfig
arch/c6x/include/asm/irq.h
arch/c6x/kernel/irq.c
arch/c6x/platforms/megamod-pic.c
arch/microblaze/Kconfig
arch/microblaze/include/asm/hardirq.h
arch/microblaze/include/asm/irq.h
arch/microblaze/kernel/intc.c
arch/microblaze/kernel/irq.c
arch/microblaze/kernel/setup.c
arch/mips/Kconfig
arch/mips/include/asm/irq.h
arch/mips/kernel/prom.c
arch/openrisc/include/asm/prom.h
arch/powerpc/Kconfig
arch/powerpc/include/asm/ehv_pic.h
arch/powerpc/include/asm/i8259.h
arch/powerpc/include/asm/irq.h
arch/powerpc/include/asm/mpic.h
arch/powerpc/include/asm/xics.h
arch/powerpc/kernel/irq.c
arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
arch/powerpc/platforms/52xx/media5200.c
arch/powerpc/platforms/52xx/mpc52xx_gpt.c
arch/powerpc/platforms/52xx/mpc52xx_pic.c
arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
arch/powerpc/platforms/85xx/socrates_fpga_pic.c
arch/powerpc/platforms/86xx/gef_pic.c
arch/powerpc/platforms/cell/axon_msi.c
arch/powerpc/platforms/cell/beat_interrupt.c
arch/powerpc/platforms/cell/interrupt.c
arch/powerpc/platforms/cell/spider-pic.c
arch/powerpc/platforms/embedded6xx/flipper-pic.c
arch/powerpc/platforms/embedded6xx/hlwd-pic.c
arch/powerpc/platforms/iseries/irq.c
arch/powerpc/platforms/powermac/pic.c
arch/powerpc/platforms/powermac/smp.c
arch/powerpc/platforms/ps3/interrupt.c
arch/powerpc/platforms/wsp/opb_pic.c
arch/powerpc/sysdev/cpm1.c
arch/powerpc/sysdev/cpm2_pic.c
arch/powerpc/sysdev/ehv_pic.c
arch/powerpc/sysdev/fsl_msi.c
arch/powerpc/sysdev/fsl_msi.h
arch/powerpc/sysdev/i8259.c
arch/powerpc/sysdev/ipic.c
arch/powerpc/sysdev/ipic.h
arch/powerpc/sysdev/mpc8xx_pic.c
arch/powerpc/sysdev/mpic.c
arch/powerpc/sysdev/mpic_msi.c
arch/powerpc/sysdev/mv64x60_pic.c
arch/powerpc/sysdev/qe_lib/qe_ic.c
arch/powerpc/sysdev/qe_lib/qe_ic.h
arch/powerpc/sysdev/tsi108_pci.c
arch/powerpc/sysdev/uic.c
arch/powerpc/sysdev/xics/xics-common.c
arch/powerpc/sysdev/xilinx_intc.c
arch/sparc/include/asm/prom.h
arch/x86/Kconfig
arch/x86/include/asm/irq_controller.h [deleted file]
arch/x86/include/asm/prom.h
arch/x86/kernel/devicetree.c
arch/x86/platform/ce4100/falconfalls.dts
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-mc9s08dz60.c [new file with mode: 0644]
drivers/gpio/gpio-mpc8xxx.c
drivers/gpio/gpio-omap.c
drivers/gpio/gpio-pl061.c
drivers/gpio/gpio-sodaville.c [new file with mode: 0644]
drivers/gpio/gpio-tps65910.c
drivers/gpio/gpiolib.c
drivers/mfd/Kconfig
drivers/mfd/twl-core.c
drivers/net/phy/mdio-gpio.c
drivers/of/gpio.c
drivers/of/platform.c
include/asm-generic/gpio.h
include/linux/gpio.h
include/linux/irqdomain.h
include/linux/mfd/tps65910.h
include/linux/of_address.h
include/linux/of_gpio.h
include/linux/of_irq.h
include/linux/of_platform.h
kernel/irq/irqdomain.c

diff --git a/Documentation/IRQ-domain.txt b/Documentation/IRQ-domain.txt
new file mode 100644 (file)
index 0000000..27dcaab
--- /dev/null
@@ -0,0 +1,117 @@
+irq_domain interrupt number mapping library
+
+The current design of the Linux kernel uses a single large number
+space where each separate IRQ source is assigned a different number.
+This is simple when there is only one interrupt controller, but in
+systems with multiple interrupt controllers the kernel must ensure
+that each one gets assigned non-overlapping allocations of Linux
+IRQ numbers.
+
+The irq_alloc_desc*() and irq_free_desc*() APIs provide allocation of
+irq numbers, but they don't provide any support for reverse mapping of
+the controller-local IRQ (hwirq) number into the Linux IRQ number
+space.
+
+The irq_domain library adds mapping between hwirq and IRQ numbers on
+top of the irq_alloc_desc*() API.  An irq_domain to manage mapping is
+preferred over interrupt controller drivers open coding their own
+reverse mapping scheme.
+
+irq_domain also implements translation from Device Tree interrupt
+specifiers to hwirq numbers, and can be easily extended to support
+other IRQ topology data sources.
+
+=== irq_domain usage ===
+An interrupt controller driver creates and registers an irq_domain by
+calling one of the irq_domain_add_*() functions (each mapping method
+has a different allocator function, more on that later).  The function
+will return a pointer to the irq_domain on success.  The caller must
+provide the allocator function with an irq_domain_ops structure with
+the .map callback populated as a minimum.
+
+In most cases, the irq_domain will begin empty without any mappings
+between hwirq and IRQ numbers.  Mappings are added to the irq_domain
+by calling irq_create_mapping() which accepts the irq_domain and a
+hwirq number as arguments.  If a mapping for the hwirq doesn't already
+exist then it will allocate a new Linux irq_desc, associate it with
+the hwirq, and call the .map() callback so the driver can perform any
+required hardware setup.
+
+When an interrupt is received, irq_find_mapping() function should
+be used to find the Linux IRQ number from the hwirq number.
+
+If the driver has the Linux IRQ number or the irq_data pointer, and
+needs to know the associated hwirq number (such as in the irq_chip
+callbacks) then it can be directly obtained from irq_data->hwirq.
+
+=== Types of irq_domain mappings ===
+There are several mechanisms available for reverse mapping from hwirq
+to Linux irq, and each mechanism uses a different allocation function.
+Which reverse map type should be used depends on the use case.  Each
+of the reverse map types are described below:
+
+==== Linear ====
+irq_domain_add_linear()
+
+The linear reverse map maintains a fixed size table indexed by the
+hwirq number.  When a hwirq is mapped, an irq_desc is allocated for
+the hwirq, and the IRQ number is stored in the table.
+
+The Linear map is a good choice when the maximum number of hwirqs is
+fixed and a relatively small number (~ < 256).  The advantages of this
+map are fixed time lookup for IRQ numbers, and irq_descs are only
+allocated for in-use IRQs.  The disadvantage is that the table must be
+as large as the largest possible hwirq number.
+
+The majority of drivers should use the linear map.
+
+==== Tree ====
+irq_domain_add_tree()
+
+The irq_domain maintains a radix tree map from hwirq numbers to Linux
+IRQs.  When an hwirq is mapped, an irq_desc is allocated and the
+hwirq is used as the lookup key for the radix tree.
+
+The tree map is a good choice if the hwirq number can be very large
+since it doesn't need to allocate a table as large as the largest
+hwirq number.  The disadvantage is that hwirq to IRQ number lookup is
+dependent on how many entries are in the table.
+
+Very few drivers should need this mapping.  At the moment, powerpc
+iseries is the only user.
+
+==== No Map ===-
+irq_domain_add_nomap()
+
+The No Map mapping is to be used when the hwirq number is
+programmable in the hardware.  In this case it is best to program the
+Linux IRQ number into the hardware itself so that no mapping is
+required.  Calling irq_create_direct_mapping() will allocate a Linux
+IRQ number and call the .map() callback so that driver can program the
+Linux IRQ number into the hardware.
+
+Most drivers cannot use this mapping.
+
+==== Legacy ====
+irq_domain_add_legacy()
+irq_domain_add_legacy_isa()
+
+The Legacy mapping is a special case for drivers that already have a
+range of irq_descs allocated for the hwirqs.  It is used when the
+driver cannot be immediately converted to use the linear mapping.  For
+example, many embedded system board support files use a set of #defines
+for IRQ numbers that are passed to struct device registrations.  In that
+case the Linux IRQ numbers cannot be dynamically assigned and the legacy
+mapping should be used.
+
+The legacy map assumes a contiguous range of IRQ numbers has already
+been allocated for the controller and that the IRQ number can be
+calculated by adding a fixed offset to the hwirq number, and
+visa-versa.  The disadvantage is that it requires the interrupt
+controller to manage IRQ allocations and it requires an irq_desc to be
+allocated for every hwirq, even if it is unused.
+
+The legacy map should only be used if fixed IRQ mappings must be
+supported.  For example, ISA controllers would use the legacy map for
+mapping Linux IRQs 0-15 so that existing ISA drivers get the correct IRQ
+numbers.
diff --git a/Documentation/devicetree/bindings/gpio/gpio-omap.txt b/Documentation/devicetree/bindings/gpio/gpio-omap.txt
new file mode 100644 (file)
index 0000000..bff51a2
--- /dev/null
@@ -0,0 +1,36 @@
+OMAP GPIO controller bindings
+
+Required properties:
+- compatible:
+  - "ti,omap2-gpio" for OMAP2 controllers
+  - "ti,omap3-gpio" for OMAP3 controllers
+  - "ti,omap4-gpio" for OMAP4 controllers
+- #gpio-cells : Should be two.
+  - first cell is the pin number
+  - second cell is used to specify optional parameters (unused)
+- gpio-controller : Marks the device node as a GPIO controller.
+- #interrupt-cells : Should be 2.
+- interrupt-controller: Mark the device node as an interrupt controller
+  The first cell is the GPIO number.
+  The second cell is used to specify flags:
+    bits[3:0] trigger type and level flags:
+      1 = low-to-high edge triggered.
+      2 = high-to-low edge triggered.
+      4 = active high level-sensitive.
+      8 = active low level-sensitive.
+
+OMAP specific properties:
+- ti,hwmods: Name of the hwmod associated to the GPIO:
+  "gpio<X>", <X> being the 1-based instance number from the HW spec
+
+
+Example:
+
+gpio4: gpio4 {
+    compatible = "ti,omap4-gpio";
+    ti,hwmods = "gpio4";
+    #gpio-cells = <2>;
+    gpio-controller;
+    #interrupt-cells = <2>;
+    interrupt-controller;
+};
diff --git a/Documentation/devicetree/bindings/gpio/sodaville.txt b/Documentation/devicetree/bindings/gpio/sodaville.txt
new file mode 100644 (file)
index 0000000..563eff2
--- /dev/null
@@ -0,0 +1,48 @@
+GPIO controller on CE4100 / Sodaville SoCs
+==========================================
+
+The bindings for CE4100's GPIO controller match the generic description
+which is covered by the gpio.txt file in this folder.
+
+The only additional property is the intel,muxctl property which holds the
+value which is written into the MUXCNTL register.
+
+There is no compatible property for now because the driver is probed via
+PCI id (vendor 0x8086 device 0x2e67).
+
+The interrupt specifier consists of two cells encoded as follows:
+ - <1st cell>: The interrupt-number that identifies the interrupt source.
+ - <2nd cell>: The level-sense information, encoded as follows:
+               4 - active high level-sensitive
+               8 - active low level-sensitive
+
+Example of the GPIO device and one user:
+
+       pcigpio: gpio@b,1 {
+                       /* two cells for GPIO and interrupt */
+                       #gpio-cells = <2>;
+                       #interrupt-cells = <2>;
+                       compatible = "pci8086,2e67.2",
+                                          "pci8086,2e67",
+                                          "pciclassff0000",
+                                          "pciclassff00";
+
+                       reg = <0x15900 0x0 0x0 0x0 0x0>;
+                       /* Interrupt line of the gpio device */
+                       interrupts = <15 1>;
+                       /* It is an interrupt and GPIO controller itself */
+                       interrupt-controller;
+                       gpio-controller;
+                       intel,muxctl = <0>;
+       };
+
+       testuser@20 {
+                       compatible = "example,testuser";
+                       /* User the 11th GPIO line as an active high triggered
+                        * level interrupt
+                        */
+                       interrupts = <11 8>;
+                       interrupt-parent = <&pcigpio>;
+                       /* Use this GPIO also with the gpio functions */
+                       gpios = <&pcigpio 11 0>;
+       };
index 792faa3..f783e7f 100644 (file)
@@ -302,6 +302,8 @@ where 'flags' is currently defined to specify the following properties:
 
        * GPIOF_INIT_LOW        - as output, set initial level to LOW
        * GPIOF_INIT_HIGH       - as output, set initial level to HIGH
+       * GPIOF_OPEN_DRAIN      - gpio pin is open drain type.
+       * GPIOF_OPEN_SOURCE     - gpio pin is open source type.
 
 since GPIOF_INIT_* are only valid when configured as output, so group valid
 combinations as:
@@ -310,8 +312,19 @@ combinations as:
        * GPIOF_OUT_INIT_LOW    - configured as output, initial level LOW
        * GPIOF_OUT_INIT_HIGH   - configured as output, initial level HIGH
 
-In the future, these flags can be extended to support more properties such
-as open-drain status.
+When setting the flag as GPIOF_OPEN_DRAIN then it will assume that pins is
+open drain type. Such pins will not be driven to 1 in output mode. It is
+require to connect pull-up on such pins. By enabling this flag, gpio lib will
+make the direction to input when it is asked to set value of 1 in output mode
+to make the pin HIGH. The pin is make to LOW by driving value 0 in output mode.
+
+When setting the flag as GPIOF_OPEN_SOURCE then it will assume that pins is
+open source type. Such pins will not be driven to 0 in output mode. It is
+require to connect pull-down on such pin. By enabling this flag, gpio lib will
+make the direction to input when it is asked to set value of 0 in output mode
+to make the pin LOW. The pin is make to HIGH by driving value 1 in output mode.
+
+In the future, these flags can be extended to support more properties.
 
 Further more, to ease the claim/release of multiple GPIOs, 'struct gpio' is
 introduced to encapsulate all three fields as:
index 3321d75..24c94d6 100644 (file)
@@ -3638,6 +3638,15 @@ S:       Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core
 F:     kernel/irq/
 
+IRQ DOMAINS (IRQ NUMBER MAPPING LIBRARY)
+M:     Benjamin Herrenschmidt <benh@kernel.crashing.org>
+M:     Grant Likely <grant.likely@secretlab.ca>
+T:     git git://git.secretlab.ca/git/linux-2.6.git irqdomain/next
+S:     Maintained
+F:     Documentation/IRQ-domain.txt
+F:     include/linux/irqdomain.h
+F:     kernel/irq/irqdomain.c
+
 ISAPNP
 M:     Jaroslav Kysela <perex@perex.cz>
 S:     Maintained
index c47d619..f0783be 100644 (file)
@@ -51,7 +51,6 @@ union gic_base {
 };
 
 struct gic_chip_data {
-       unsigned int irq_offset;
        union gic_base dist_base;
        union gic_base cpu_base;
 #ifdef CONFIG_CPU_PM
@@ -61,9 +60,7 @@ struct gic_chip_data {
        u32 __percpu *saved_ppi_enable;
        u32 __percpu *saved_ppi_conf;
 #endif
-#ifdef CONFIG_IRQ_DOMAIN
-       struct irq_domain domain;
-#endif
+       struct irq_domain *domain;
        unsigned int gic_irqs;
 #ifdef CONFIG_GIC_NON_BANKED
        void __iomem *(*get_base)(union gic_base *);
@@ -282,7 +279,7 @@ asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
                irqnr = irqstat & ~0x1c00;
 
                if (likely(irqnr > 15 && irqnr < 1021)) {
-                       irqnr = irq_domain_to_irq(&gic->domain, irqnr);
+                       irqnr = irq_find_mapping(gic->domain, irqnr);
                        handle_IRQ(irqnr, regs);
                        continue;
                }
@@ -314,8 +311,8 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
        if (gic_irq == 1023)
                goto out;
 
-       cascade_irq = irq_domain_to_irq(&chip_data->domain, gic_irq);
-       if (unlikely(gic_irq < 32 || gic_irq > 1020 || cascade_irq >= NR_IRQS))
+       cascade_irq = irq_find_mapping(chip_data->domain, gic_irq);
+       if (unlikely(gic_irq < 32 || gic_irq > 1020))
                do_bad_IRQ(cascade_irq, desc);
        else
                generic_handle_irq(cascade_irq);
@@ -348,10 +345,9 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
 
 static void __init gic_dist_init(struct gic_chip_data *gic)
 {
-       unsigned int i, irq;
+       unsigned int i;
        u32 cpumask;
        unsigned int gic_irqs = gic->gic_irqs;
-       struct irq_domain *domain = &gic->domain;
        void __iomem *base = gic_data_dist_base(gic);
        u32 cpu = cpu_logical_map(smp_processor_id());
 
@@ -386,23 +382,6 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
        for (i = 32; i < gic_irqs; i += 32)
                writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
 
-       /*
-        * Setup the Linux IRQ subsystem.
-        */
-       irq_domain_for_each_irq(domain, i, irq) {
-               if (i < 32) {
-                       irq_set_percpu_devid(irq);
-                       irq_set_chip_and_handler(irq, &gic_chip,
-                                                handle_percpu_devid_irq);
-                       set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
-               } else {
-                       irq_set_chip_and_handler(irq, &gic_chip,
-                                                handle_fasteoi_irq);
-                       set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
-               }
-               irq_set_chip_data(irq, gic);
-       }
-
        writel_relaxed(1, base + GIC_DIST_CTRL);
 }
 
@@ -618,11 +597,27 @@ static void __init gic_pm_init(struct gic_chip_data *gic)
 }
 #endif
 
-#ifdef CONFIG_OF
-static int gic_irq_domain_dt_translate(struct irq_domain *d,
-                                      struct device_node *controller,
-                                      const u32 *intspec, unsigned int intsize,
-                                      unsigned long *out_hwirq, unsigned int *out_type)
+static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
+                               irq_hw_number_t hw)
+{
+       if (hw < 32) {
+               irq_set_percpu_devid(irq);
+               irq_set_chip_and_handler(irq, &gic_chip,
+                                        handle_percpu_devid_irq);
+               set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
+       } else {
+               irq_set_chip_and_handler(irq, &gic_chip,
+                                        handle_fasteoi_irq);
+               set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+       }
+       irq_set_chip_data(irq, d->host_data);
+       return 0;
+}
+
+static int gic_irq_domain_xlate(struct irq_domain *d,
+                               struct device_node *controller,
+                               const u32 *intspec, unsigned int intsize,
+                               unsigned long *out_hwirq, unsigned int *out_type)
 {
        if (d->of_node != controller)
                return -EINVAL;
@@ -639,26 +634,23 @@ static int gic_irq_domain_dt_translate(struct irq_domain *d,
        *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
        return 0;
 }
-#endif
 
 const struct irq_domain_ops gic_irq_domain_ops = {
-#ifdef CONFIG_OF
-       .dt_translate = gic_irq_domain_dt_translate,
-#endif
+       .map = gic_irq_domain_map,
+       .xlate = gic_irq_domain_xlate,
 };
 
 void __init gic_init_bases(unsigned int gic_nr, int irq_start,
                           void __iomem *dist_base, void __iomem *cpu_base,
-                          u32 percpu_offset)
+                          u32 percpu_offset, struct device_node *node)
 {
+       irq_hw_number_t hwirq_base;
        struct gic_chip_data *gic;
-       struct irq_domain *domain;
-       int gic_irqs;
+       int gic_irqs, irq_base;
 
        BUG_ON(gic_nr >= MAX_GIC_NR);
 
        gic = &gic_data[gic_nr];
-       domain = &gic->domain;
 #ifdef CONFIG_GIC_NON_BANKED
        if (percpu_offset) { /* Frankein-GIC without banked registers... */
                unsigned int cpu;
@@ -694,10 +686,10 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
         * For primary GICs, skip over SGIs.
         * For secondary GICs, skip over PPIs, too.
         */
-       domain->hwirq_base = 32;
+       hwirq_base = 32;
        if (gic_nr == 0) {
                if ((irq_start & 31) > 0) {
-                       domain->hwirq_base = 16;
+                       hwirq_base = 16;
                        if (irq_start != -1)
                                irq_start = (irq_start & ~31) + 16;
                }
@@ -713,17 +705,17 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
                gic_irqs = 1020;
        gic->gic_irqs = gic_irqs;
 
-       domain->nr_irq = gic_irqs - domain->hwirq_base;
-       domain->irq_base = irq_alloc_descs(irq_start, 16, domain->nr_irq,
-                                          numa_node_id());
-       if (IS_ERR_VALUE(domain->irq_base)) {
+       gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
+       irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id());
+       if (IS_ERR_VALUE(irq_base)) {
                WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
                     irq_start);
-               domain->irq_base = irq_start;
+               irq_base = irq_start;
        }
-       domain->priv = gic;
-       domain->ops = &gic_irq_domain_ops;
-       irq_domain_add(domain);
+       gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
+                                   hwirq_base, &gic_irq_domain_ops, gic);
+       if (WARN_ON(!gic->domain))
+               return;
 
        gic_chip.flags |= gic_arch_extn.flags;
        gic_dist_init(gic);
@@ -768,7 +760,6 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent)
        void __iomem *dist_base;
        u32 percpu_offset;
        int irq;
-       struct irq_domain *domain = &gic_data[gic_cnt].domain;
 
        if (WARN_ON(!node))
                return -ENODEV;
@@ -782,9 +773,7 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent)
        if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
                percpu_offset = 0;
 
-       domain->of_node = of_node_get(node);
-
-       gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset);
+       gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);
 
        if (parent) {
                irq = irq_of_parse_and_map(node, 0);
index dcb004a..7a66311 100644 (file)
@@ -56,7 +56,7 @@ struct vic_device {
        u32             int_enable;
        u32             soft_int;
        u32             protect;
-       struct irq_domain domain;
+       struct irq_domain *domain;
 };
 
 /* we cannot allocate memory when VICs are initially registered */
@@ -192,14 +192,8 @@ static void __init vic_register(void __iomem *base, unsigned int irq,
        v->resume_sources = resume_sources;
        v->irq = irq;
        vic_id++;
-
-       v->domain.irq_base = irq;
-       v->domain.nr_irq = 32;
-#ifdef CONFIG_OF_IRQ
-       v->domain.of_node = of_node_get(node);
-#endif /* CONFIG_OF */
-       v->domain.ops = &irq_domain_simple_ops;
-       irq_domain_add(&v->domain);
+       v->domain = irq_domain_add_legacy(node, 32, irq, 0,
+                                         &irq_domain_simple_ops, v);
 }
 
 static void vic_ack_irq(struct irq_data *d)
@@ -348,7 +342,7 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
        vic_register(base, irq_start, 0, node);
 }
 
-static void __init __vic_init(void __iomem *base, unsigned int irq_start,
+void __init __vic_init(void __iomem *base, unsigned int irq_start,
                              u32 vic_sources, u32 resume_sources,
                              struct device_node *node)
 {
@@ -444,7 +438,7 @@ static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs)
        stat = readl_relaxed(vic->base + VIC_IRQ_STATUS);
        while (stat) {
                irq = ffs(stat) - 1;
-               handle_IRQ(irq_domain_to_irq(&vic->domain, irq), regs);
+               handle_IRQ(irq_find_mapping(vic->domain, irq), regs);
                stat &= ~(1 << irq);
                handled = 1;
        }
index 4bdfe00..4b1ce6c 100644 (file)
@@ -39,7 +39,7 @@ struct device_node;
 extern struct irq_chip gic_arch_extn;
 
 void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *,
-                   u32 offset);
+                   u32 offset, struct device_node *);
 int gic_of_init(struct device_node *node, struct device_node *parent);
 void gic_secondary_init(unsigned int);
 void gic_handle_irq(struct pt_regs *regs);
@@ -49,7 +49,7 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq);
 static inline void gic_init(unsigned int nr, int start,
                            void __iomem *dist , void __iomem *cpu)
 {
-       gic_init_bases(nr, start, dist, cpu, 0);
+       gic_init_bases(nr, start, dist, cpu, 0, NULL);
 }
 
 #endif
index f42ebd6..e14af1a 100644 (file)
@@ -47,6 +47,8 @@
 struct device_node;
 struct pt_regs;
 
+void __vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources,
+               u32 resume_sources, struct device_node *node);
 void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
 int vic_of_init(struct device_node *node, struct device_node *parent);
 void vic_handle_irq(struct pt_regs *regs);
index c59e188..6de298c 100644 (file)
@@ -402,7 +402,7 @@ void __init exynos4_init_irq(void)
        gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000;
 
        if (!of_have_populated_dt())
-               gic_init_bases(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU, gic_bank_offset);
+               gic_init_bases(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU, gic_bank_offset, NULL);
 #ifdef CONFIG_OF
        else
                of_irq_init(exynos4_dt_irq_match);
index e6bad17..1e03ef4 100644 (file)
@@ -47,7 +47,7 @@ static const struct of_dev_auxdata imx51_auxdata_lookup[] __initconst = {
 static int __init imx51_tzic_add_irq_domain(struct device_node *np,
                                struct device_node *interrupt_parent)
 {
-       irq_domain_add_simple(np, 0);
+       irq_domain_add_legacy(np, 128, 0, 0, &irq_domain_simple_ops, NULL);
        return 0;
 }
 
@@ -57,7 +57,7 @@ static int __init imx51_gpio_add_irq_domain(struct device_node *np,
        static int gpio_irq_base = MXC_GPIO_IRQ_START + ARCH_NR_GPIOS;
 
        gpio_irq_base -= 32;
-       irq_domain_add_simple(np, gpio_irq_base);
+       irq_domain_add_legacy(np, 32, gpio_irq_base, 0, &irq_domain_simple_ops, NULL);
 
        return 0;
 }
index 05ebb3e..fd5be0f 100644 (file)
@@ -51,7 +51,7 @@ static const struct of_dev_auxdata imx53_auxdata_lookup[] __initconst = {
 static int __init imx53_tzic_add_irq_domain(struct device_node *np,
                                struct device_node *interrupt_parent)
 {
-       irq_domain_add_simple(np, 0);
+       irq_domain_add_legacy(np, 128, 0, 0, &irq_domain_simple_ops, NULL);
        return 0;
 }
 
@@ -61,7 +61,7 @@ static int __init imx53_gpio_add_irq_domain(struct device_node *np,
        static int gpio_irq_base = MXC_GPIO_IRQ_START + ARCH_NR_GPIOS;
 
        gpio_irq_base -= 32;
-       irq_domain_add_simple(np, gpio_irq_base);
+       irq_domain_add_legacy(np, 32, gpio_irq_base, 0, &irq_domain_simple_ops, NULL);
 
        return 0;
 }
index c257281..6075d4d 100644 (file)
@@ -97,7 +97,8 @@ static int __init imx6q_gpio_add_irq_domain(struct device_node *np,
        static int gpio_irq_base = MXC_GPIO_IRQ_START + ARCH_NR_GPIOS;
 
        gpio_irq_base -= 32;
-       irq_domain_add_simple(np, gpio_irq_base);
+       irq_domain_add_legacy(np, 32, gpio_irq_base, 0, &irq_domain_simple_ops,
+                             NULL);
 
        return 0;
 }
index 0a11342..962e711 100644 (file)
@@ -80,12 +80,8 @@ static struct of_device_id msm_dt_gic_match[] __initdata = {
 
 static void __init msm8x60_dt_init(void)
 {
-       struct device_node *node;
-
-       node = of_find_matching_node_by_address(NULL, msm_dt_gic_match,
-                       MSM8X60_QGIC_DIST_PHYS);
-       if (node)
-               irq_domain_add_simple(node, GIC_SPI_START);
+       irq_domain_generate_simple(msm_dt_gic_match, MSM8X60_QGIC_DIST_PHYS,
+                               GIC_SPI_START);
 
        if (of_machine_is_compatible("qcom,msm8660-surf")) {
                printk(KERN_INFO "Init surf UART registers\n");
index 399da4c..634903e 100644 (file)
@@ -42,11 +42,12 @@ static struct omap_gpio_reg_offs omap15xx_mpuio_regs = {
        .irqstatus      = OMAP_MPUIO_GPIO_INT,
        .irqenable      = OMAP_MPUIO_GPIO_MASKIT,
        .irqenable_inv  = true,
+       .irqctrl        = OMAP_MPUIO_GPIO_INT_EDGE,
 };
 
 static struct __initdata omap_gpio_platform_data omap15xx_mpu_gpio_config = {
        .virtual_irq_start      = IH_MPUIO_BASE,
-       .bank_type              = METHOD_MPUIO,
+       .is_mpuio               = true,
        .bank_width             = 16,
        .bank_stride            = 1,
        .regs                   = &omap15xx_mpuio_regs,
@@ -83,11 +84,12 @@ static struct omap_gpio_reg_offs omap15xx_gpio_regs = {
        .irqstatus      = OMAP1510_GPIO_INT_STATUS,
        .irqenable      = OMAP1510_GPIO_INT_MASK,
        .irqenable_inv  = true,
+       .irqctrl        = OMAP1510_GPIO_INT_CONTROL,
+       .pinctrl        = OMAP1510_GPIO_PIN_CONTROL,
 };
 
 static struct __initdata omap_gpio_platform_data omap15xx_gpio_config = {
        .virtual_irq_start      = IH_GPIO_BASE,
-       .bank_type              = METHOD_GPIO_1510,
        .bank_width             = 16,
        .regs                   = &omap15xx_gpio_regs,
 };
@@ -115,7 +117,6 @@ static int __init omap15xx_gpio_init(void)
        platform_device_register(&omap15xx_mpu_gpio);
        platform_device_register(&omap15xx_gpio);
 
-       gpio_bank_count = 2;
        return 0;
 }
 postcore_initcall(omap15xx_gpio_init);
index 0f399bd..1c5f90e 100644 (file)
@@ -24,6 +24,9 @@
 #define OMAP1610_GPIO4_BASE            0xfffbbc00
 #define OMAP1_MPUIO_VBASE              OMAP1_MPUIO_BASE
 
+/* smart idle, enable wakeup */
+#define SYSCONFIG_WORD                 0x14
+
 /* mpu gpio */
 static struct __initdata resource omap16xx_mpu_gpio_resources[] = {
        {
@@ -45,11 +48,12 @@ static struct omap_gpio_reg_offs omap16xx_mpuio_regs = {
        .irqstatus      = OMAP_MPUIO_GPIO_INT,
        .irqenable      = OMAP_MPUIO_GPIO_MASKIT,
        .irqenable_inv  = true,
+       .irqctrl        = OMAP_MPUIO_GPIO_INT_EDGE,
 };
 
 static struct __initdata omap_gpio_platform_data omap16xx_mpu_gpio_config = {
        .virtual_irq_start      = IH_MPUIO_BASE,
-       .bank_type              = METHOD_MPUIO,
+       .is_mpuio               = true,
        .bank_width             = 16,
        .bank_stride            = 1,
        .regs                   = &omap16xx_mpuio_regs,
@@ -89,11 +93,13 @@ static struct omap_gpio_reg_offs omap16xx_gpio_regs = {
        .irqenable      = OMAP1610_GPIO_IRQENABLE1,
        .set_irqenable  = OMAP1610_GPIO_SET_IRQENABLE1,
        .clr_irqenable  = OMAP1610_GPIO_CLEAR_IRQENABLE1,
+       .wkup_en        = OMAP1610_GPIO_WAKEUPENABLE,
+       .edgectrl1      = OMAP1610_GPIO_EDGE_CTRL1,
+       .edgectrl2      = OMAP1610_GPIO_EDGE_CTRL2,
 };
 
 static struct __initdata omap_gpio_platform_data omap16xx_gpio1_config = {
        .virtual_irq_start      = IH_GPIO_BASE,
-       .bank_type              = METHOD_GPIO_1610,
        .bank_width             = 16,
        .regs                   = &omap16xx_gpio_regs,
 };
@@ -123,7 +129,6 @@ static struct __initdata resource omap16xx_gpio2_resources[] = {
 
 static struct __initdata omap_gpio_platform_data omap16xx_gpio2_config = {
        .virtual_irq_start      = IH_GPIO_BASE + 16,
-       .bank_type              = METHOD_GPIO_1610,
        .bank_width             = 16,
        .regs                   = &omap16xx_gpio_regs,
 };
@@ -153,7 +158,6 @@ static struct __initdata resource omap16xx_gpio3_resources[] = {
 
 static struct __initdata omap_gpio_platform_data omap16xx_gpio3_config = {
        .virtual_irq_start      = IH_GPIO_BASE + 32,
-       .bank_type              = METHOD_GPIO_1610,
        .bank_width             = 16,
        .regs                   = &omap16xx_gpio_regs,
 };
@@ -183,7 +187,6 @@ static struct __initdata resource omap16xx_gpio4_resources[] = {
 
 static struct __initdata omap_gpio_platform_data omap16xx_gpio4_config = {
        .virtual_irq_start      = IH_GPIO_BASE + 48,
-       .bank_type              = METHOD_GPIO_1610,
        .bank_width             = 16,
        .regs                   = &omap16xx_gpio_regs,
 };
@@ -214,14 +217,42 @@ static struct __initdata platform_device * omap16xx_gpio_dev[] = {
 static int __init omap16xx_gpio_init(void)
 {
        int i;
+       void __iomem *base;
+       struct resource *res;
+       struct platform_device *pdev;
+       struct omap_gpio_platform_data *pdata;
 
        if (!cpu_is_omap16xx())
                return -EINVAL;
 
-       for (i = 0; i < ARRAY_SIZE(omap16xx_gpio_dev); i++)
-               platform_device_register(omap16xx_gpio_dev[i]);
+       for (i = 0; i < ARRAY_SIZE(omap16xx_gpio_dev); i++) {
+               pdev = omap16xx_gpio_dev[i];
+               pdata = pdev->dev.platform_data;
+
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+               if (unlikely(!res)) {
+                       dev_err(&pdev->dev, "Invalid mem resource.\n");
+                       return -ENODEV;
+               }
+
+               base = ioremap(res->start, resource_size(res));
+               if (unlikely(!base)) {
+                       dev_err(&pdev->dev, "ioremap failed.\n");
+                       return -ENOMEM;
+               }
 
-       gpio_bank_count = ARRAY_SIZE(omap16xx_gpio_dev);
+               __raw_writel(SYSCONFIG_WORD, base + OMAP1610_GPIO_SYSCONFIG);
+               iounmap(base);
+
+               /*
+                * Enable system clock for GPIO module.
+                * The CAM_CLK_CTRL *is* really the right place.
+                */
+               omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04,
+                                       ULPD_CAM_CLK_CTRL);
+
+               platform_device_register(omap16xx_gpio_dev[i]);
+       }
 
        return 0;
 }
index 5ab63ea..4771d6b 100644 (file)
@@ -47,12 +47,13 @@ static struct omap_gpio_reg_offs omap7xx_mpuio_regs = {
        .irqstatus      = OMAP_MPUIO_GPIO_INT / 2,
        .irqenable      = OMAP_MPUIO_GPIO_MASKIT / 2,
        .irqenable_inv  = true,
+       .irqctrl        = OMAP_MPUIO_GPIO_INT_EDGE >> 1,
 };
 
 static struct __initdata omap_gpio_platform_data omap7xx_mpu_gpio_config = {
        .virtual_irq_start      = IH_MPUIO_BASE,
-       .bank_type              = METHOD_MPUIO,
-       .bank_width             = 32,
+       .is_mpuio               = true,
+       .bank_width             = 16,
        .bank_stride            = 2,
        .regs                   = &omap7xx_mpuio_regs,
 };
@@ -88,11 +89,11 @@ static struct omap_gpio_reg_offs omap7xx_gpio_regs = {
        .irqstatus      = OMAP7XX_GPIO_INT_STATUS,
        .irqenable      = OMAP7XX_GPIO_INT_MASK,
        .irqenable_inv  = true,
+       .irqctrl        = OMAP7XX_GPIO_INT_CONTROL,
 };
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio1_config = {
        .virtual_irq_start      = IH_GPIO_BASE,
-       .bank_type              = METHOD_GPIO_7XX,
        .bank_width             = 32,
        .regs                   = &omap7xx_gpio_regs,
 };
@@ -122,7 +123,6 @@ static struct __initdata resource omap7xx_gpio2_resources[] = {
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio2_config = {
        .virtual_irq_start      = IH_GPIO_BASE + 32,
-       .bank_type              = METHOD_GPIO_7XX,
        .bank_width             = 32,
        .regs                   = &omap7xx_gpio_regs,
 };
@@ -152,7 +152,6 @@ static struct __initdata resource omap7xx_gpio3_resources[] = {
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio3_config = {
        .virtual_irq_start      = IH_GPIO_BASE + 64,
-       .bank_type              = METHOD_GPIO_7XX,
        .bank_width             = 32,
        .regs                   = &omap7xx_gpio_regs,
 };
@@ -182,7 +181,6 @@ static struct __initdata resource omap7xx_gpio4_resources[] = {
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio4_config = {
        .virtual_irq_start      = IH_GPIO_BASE + 96,
-       .bank_type              = METHOD_GPIO_7XX,
        .bank_width             = 32,
        .regs                   = &omap7xx_gpio_regs,
 };
@@ -212,7 +210,6 @@ static struct __initdata resource omap7xx_gpio5_resources[] = {
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio5_config = {
        .virtual_irq_start      = IH_GPIO_BASE + 128,
-       .bank_type              = METHOD_GPIO_7XX,
        .bank_width             = 32,
        .regs                   = &omap7xx_gpio_regs,
 };
@@ -242,7 +239,6 @@ static struct __initdata resource omap7xx_gpio6_resources[] = {
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio6_config = {
        .virtual_irq_start      = IH_GPIO_BASE + 160,
-       .bank_type              = METHOD_GPIO_7XX,
        .bank_width             = 32,
        .regs                   = &omap7xx_gpio_regs,
 };
@@ -282,8 +278,6 @@ static int __init omap7xx_gpio_init(void)
        for (i = 0; i < ARRAY_SIZE(omap7xx_gpio_dev); i++)
                platform_device_register(omap7xx_gpio_dev[i]);
 
-       gpio_bank_count = ARRAY_SIZE(omap7xx_gpio_dev);
-
        return 0;
 }
 postcore_initcall(omap7xx_gpio_init);
index ad49762..45fdfe2 100644 (file)
@@ -68,7 +68,7 @@ static void __init omap_generic_init(void)
 {
        struct device_node *node = of_find_matching_node(NULL, intc_match);
        if (node)
-               irq_domain_add_simple(node, 0);
+               irq_domain_add_legacy(node, 32, 0, 0, &irq_domain_simple_ops, NULL);
 
        omap_sdrc_init(NULL, NULL);
 
index 8cbfbc2..1e0b750 100644 (file)
@@ -23,6 +23,9 @@
 
 #include <plat/omap_hwmod.h>
 #include <plat/omap_device.h>
+#include <plat/omap-pm.h>
+
+#include "powerdomain.h"
 
 static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
 {
@@ -31,6 +34,7 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
        struct omap_gpio_dev_attr *dev_attr;
        char *name = "omap_gpio";
        int id;
+       struct powerdomain *pwrdm;
 
        /*
         * extract the device id from name field available in the
@@ -52,7 +56,7 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
        pdata->bank_width = dev_attr->bank_width;
        pdata->dbck_flag = dev_attr->dbck_flag;
        pdata->virtual_irq_start = IH_GPIO_BASE + 32 * (id - 1);
-
+       pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count;
        pdata->regs = kzalloc(sizeof(struct omap_gpio_reg_offs), GFP_KERNEL);
        if (!pdata) {
                pr_err("gpio%d: Memory allocation failed\n", id);
@@ -61,8 +65,15 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
 
        switch (oh->class->rev) {
        case 0:
+               if (id == 1)
+                       /* non-wakeup GPIO pins for OMAP2 Bank1 */
+                       pdata->non_wakeup_gpios = 0xe203ffc0;
+               else if (id == 2)
+                       /* non-wakeup GPIO pins for OMAP2 Bank2 */
+                       pdata->non_wakeup_gpios = 0x08700040;
+               /* fall through */
+
        case 1:
-               pdata->bank_type = METHOD_GPIO_24XX;
                pdata->regs->revision = OMAP24XX_GPIO_REVISION;
                pdata->regs->direction = OMAP24XX_GPIO_OE;
                pdata->regs->datain = OMAP24XX_GPIO_DATAIN;
@@ -72,13 +83,19 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
                pdata->regs->irqstatus = OMAP24XX_GPIO_IRQSTATUS1;
                pdata->regs->irqstatus2 = OMAP24XX_GPIO_IRQSTATUS2;
                pdata->regs->irqenable = OMAP24XX_GPIO_IRQENABLE1;
+               pdata->regs->irqenable2 = OMAP24XX_GPIO_IRQENABLE2;
                pdata->regs->set_irqenable = OMAP24XX_GPIO_SETIRQENABLE1;
                pdata->regs->clr_irqenable = OMAP24XX_GPIO_CLEARIRQENABLE1;
                pdata->regs->debounce = OMAP24XX_GPIO_DEBOUNCE_VAL;
                pdata->regs->debounce_en = OMAP24XX_GPIO_DEBOUNCE_EN;
+               pdata->regs->ctrl = OMAP24XX_GPIO_CTRL;
+               pdata->regs->wkup_en = OMAP24XX_GPIO_WAKE_EN;
+               pdata->regs->leveldetect0 = OMAP24XX_GPIO_LEVELDETECT0;
+               pdata->regs->leveldetect1 = OMAP24XX_GPIO_LEVELDETECT1;
+               pdata->regs->risingdetect = OMAP24XX_GPIO_RISINGDETECT;
+               pdata->regs->fallingdetect = OMAP24XX_GPIO_FALLINGDETECT;
                break;
        case 2:
-               pdata->bank_type = METHOD_GPIO_44XX;
                pdata->regs->revision = OMAP4_GPIO_REVISION;
                pdata->regs->direction = OMAP4_GPIO_OE;
                pdata->regs->datain = OMAP4_GPIO_DATAIN;
@@ -88,10 +105,17 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
                pdata->regs->irqstatus = OMAP4_GPIO_IRQSTATUS0;
                pdata->regs->irqstatus2 = OMAP4_GPIO_IRQSTATUS1;
                pdata->regs->irqenable = OMAP4_GPIO_IRQSTATUSSET0;
+               pdata->regs->irqenable2 = OMAP4_GPIO_IRQSTATUSSET1;
                pdata->regs->set_irqenable = OMAP4_GPIO_IRQSTATUSSET0;
                pdata->regs->clr_irqenable = OMAP4_GPIO_IRQSTATUSCLR0;
                pdata->regs->debounce = OMAP4_GPIO_DEBOUNCINGTIME;
                pdata->regs->debounce_en = OMAP4_GPIO_DEBOUNCENABLE;
+               pdata->regs->ctrl = OMAP4_GPIO_CTRL;
+               pdata->regs->wkup_en = OMAP4_GPIO_IRQWAKEN0;
+               pdata->regs->leveldetect0 = OMAP4_GPIO_LEVELDETECT0;
+               pdata->regs->leveldetect1 = OMAP4_GPIO_LEVELDETECT1;
+               pdata->regs->risingdetect = OMAP4_GPIO_RISINGDETECT;
+               pdata->regs->fallingdetect = OMAP4_GPIO_FALLINGDETECT;
                break;
        default:
                WARN(1, "Invalid gpio bank_type\n");
@@ -99,6 +123,9 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
                return -EINVAL;
        }
 
+       pwrdm = omap_hwmod_get_pwrdm(oh);
+       pdata->loses_context = pwrdm_can_ever_lose_context(pwrdm);
+
        pdev = omap_device_build(name, id - 1, oh, pdata,
                                sizeof(*pdata), NULL, 0, false);
        kfree(pdata);
@@ -109,9 +136,6 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
                return PTR_ERR(pdev);
        }
 
-       omap_device_disable_idle_on_suspend(pdev);
-
-       gpio_bank_count++;
        return 0;
 }
 
index fc69875..59c6dc1 100644 (file)
@@ -75,16 +75,6 @@ static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
 static struct powerdomain *core_pwrdm, *per_pwrdm;
 static struct powerdomain *cam_pwrdm;
 
-static inline void omap3_per_save_context(void)
-{
-       omap_gpio_save_context();
-}
-
-static inline void omap3_per_restore_context(void)
-{
-       omap_gpio_restore_context();
-}
-
 static void omap3_enable_io_chain(void)
 {
        int timeout = 0;
@@ -332,8 +322,6 @@ void omap_sram_idle(void)
        if (per_next_state < PWRDM_POWER_ON) {
                per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0;
                omap2_gpio_prepare_for_idle(per_going_off);
-               if (per_next_state == PWRDM_POWER_OFF)
-                               omap3_per_save_context();
        }
 
        /* CORE */
@@ -399,8 +387,6 @@ void omap_sram_idle(void)
        if (per_next_state < PWRDM_POWER_ON) {
                per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm);
                omap2_gpio_resume_after_idle();
-               if (per_prev_state == PWRDM_POWER_OFF)
-                       omap3_per_restore_context();
        }
 
        /* Disable IO-PAD and IO-CHAIN wakeup */
index d93ceef..37c2de9 100644 (file)
@@ -68,7 +68,7 @@ void __init sirfsoc_of_irq_init(void)
        if (!sirfsoc_intc_base)
                panic("unable to map intc cpu registers\n");
 
-       irq_domain_add_simple(np, 0);
+       irq_domain_add_legacy(np, 32, 0, 0, &irq_domain_simple_ops, NULL);
 
        of_node_put(np);
 
index 02b7b93..008ce22 100644 (file)
@@ -98,8 +98,11 @@ static const struct of_device_id sic_of_match[] __initconst = {
 
 void __init versatile_init_irq(void)
 {
-       vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0, 0);
-       irq_domain_generate_simple(vic_of_match, VERSATILE_VIC_BASE, IRQ_VIC_START);
+       struct device_node *np;
+
+       np = of_find_matching_node_by_address(NULL, vic_of_match,
+                                             VERSATILE_VIC_BASE);
+       __vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0, 0, np);
 
        writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
 
index 9e86ee0..b8a96c6 100644 (file)
                                 IH_MPUIO_BASE + ((nr) & 0x0f) : \
                                 IH_GPIO_BASE + (nr))
 
-#define METHOD_MPUIO           0
-#define METHOD_GPIO_1510       1
-#define METHOD_GPIO_1610       2
-#define METHOD_GPIO_7XX                3
-#define METHOD_GPIO_24XX       5
-#define METHOD_GPIO_44XX       6
-
 struct omap_gpio_dev_attr {
        int bank_width;         /* GPIO bank width */
        bool dbck_flag;         /* dbck required or not - True for OMAP3&4 */
@@ -184,10 +177,21 @@ struct omap_gpio_reg_offs {
        u16 irqstatus;
        u16 irqstatus2;
        u16 irqenable;
+       u16 irqenable2;
        u16 set_irqenable;
        u16 clr_irqenable;
        u16 debounce;
        u16 debounce_en;
+       u16 ctrl;
+       u16 wkup_en;
+       u16 leveldetect0;
+       u16 leveldetect1;
+       u16 risingdetect;
+       u16 fallingdetect;
+       u16 irqctrl;
+       u16 edgectrl1;
+       u16 edgectrl2;
+       u16 pinctrl;
 
        bool irqenable_inv;
 };
@@ -198,45 +202,30 @@ struct omap_gpio_platform_data {
        int bank_width;         /* GPIO bank width */
        int bank_stride;        /* Only needed for omap1 MPUIO */
        bool dbck_flag;         /* dbck required or not - True for OMAP3&4 */
+       bool loses_context;     /* whether the bank would ever lose context */
+       bool is_mpuio;          /* whether the bank is of type MPUIO */
+       u32 non_wakeup_gpios;
 
        struct omap_gpio_reg_offs *regs;
-};
 
-/* TODO: Analyze removing gpio_bank_count usage from driver code */
-extern int gpio_bank_count;
+       /* Return context loss count due to PM states changing */
+       int (*get_context_loss_count)(struct device *dev);
+};
 
 extern void omap2_gpio_prepare_for_idle(int off_mode);
 extern void omap2_gpio_resume_after_idle(void);
 extern void omap_set_gpio_debounce(int gpio, int enable);
 extern void omap_set_gpio_debounce_time(int gpio, int enable);
-extern void omap_gpio_save_context(void);
-extern void omap_gpio_restore_context(void);
 /*-------------------------------------------------------------------------*/
 
-/* Wrappers for "new style" GPIO calls, using the new infrastructure
+/*
+ * Wrappers for "new style" GPIO calls, using the new infrastructure
  * which lets us plug in FPGA, I2C, and other implementations.
- * *
+ *
  * The original OMAP-specific calls should eventually be removed.
  */
 
 #include <linux/errno.h>
 #include <asm-generic/gpio.h>
 
-static inline int irq_to_gpio(unsigned irq)
-{
-       int tmp;
-
-       /* omap1 SOC mpuio */
-       if (cpu_class_is_omap1() && (irq < (IH_MPUIO_BASE + 16)))
-               return (irq - IH_MPUIO_BASE) + OMAP_MAX_GPIO_LINES;
-
-       /* SOC gpio */
-       tmp = irq - IH_GPIO_BASE;
-       if (tmp < OMAP_MAX_GPIO_LINES)
-               return tmp;
-
-       /* we don't supply reverse mappings for non-SOC gpios */
-       return -EIO;
-}
-
 #endif
index 26e67f0..3c64b28 100644 (file)
@@ -12,6 +12,7 @@ config TMS320C6X
        select HAVE_GENERIC_HARDIRQS
        select HAVE_MEMBLOCK
        select HAVE_SPARSE_IRQ
+       select IRQ_DOMAIN
        select OF
        select OF_EARLY_FLATTREE
 
index a6ae3c9..f13b78d 100644 (file)
@@ -13,6 +13,7 @@
 #ifndef _ASM_C6X_IRQ_H
 #define _ASM_C6X_IRQ_H
 
+#include <linux/irqdomain.h>
 #include <linux/threads.h>
 #include <linux/list.h>
 #include <linux/radix-tree.h>
 /* This number is used when no interrupt has been assigned */
 #define NO_IRQ         0
 
-/* This type is the placeholder for a hardware interrupt number. It has to
- * be big enough to enclose whatever representation is used by a given
- * platform.
- */
-typedef unsigned long irq_hw_number_t;
-
-/* Interrupt controller "host" data structure. This could be defined as a
- * irq domain controller. That is, it handles the mapping between hardware
- * and virtual interrupt numbers for a given interrupt domain. The host
- * structure is generally created by the PIC code for a given PIC instance
- * (though a host can cover more than one PIC if they have a flat number
- * model). It's the host callbacks that are responsible for setting the
- * irq_chip on a given irq_desc after it's been mapped.
- *
- * The host code and data structures are fairly agnostic to the fact that
- * we use an open firmware device-tree. We do have references to struct
- * device_node in two places: in irq_find_host() to find the host matching
- * a given interrupt controller node, and of course as an argument to its
- * counterpart host->ops->match() callback. However, those are treated as
- * generic pointers by the core and the fact that it's actually a device-node
- * pointer is purely a convention between callers and implementation. This
- * code could thus be used on other architectures by replacing those two
- * by some sort of arch-specific void * "token" used to identify interrupt
- * controllers.
- */
-struct irq_host;
-struct radix_tree_root;
-struct device_node;
-
-/* Functions below are provided by the host and called whenever a new mapping
- * is created or an old mapping is disposed. The host can then proceed to
- * whatever internal data structures management is required. It also needs
- * to setup the irq_desc when returning from map().
- */
-struct irq_host_ops {
-       /* Match an interrupt controller device node to a host, returns
-        * 1 on a match
-        */
-       int (*match)(struct irq_host *h, struct device_node *node);
-
-       /* Create or update a mapping between a virtual irq number and a hw
-        * irq number. This is called only once for a given mapping.
-        */
-       int (*map)(struct irq_host *h, unsigned int virq, irq_hw_number_t hw);
-
-       /* Dispose of such a mapping */
-       void (*unmap)(struct irq_host *h, unsigned int virq);
-
-       /* Translate device-tree interrupt specifier from raw format coming
-        * from the firmware to a irq_hw_number_t (interrupt line number) and
-        * type (sense) that can be passed to set_irq_type(). In the absence
-        * of this callback, irq_create_of_mapping() and irq_of_parse_and_map()
-        * will return the hw number in the first cell and IRQ_TYPE_NONE for
-        * the type (which amount to keeping whatever default value the
-        * interrupt controller has for that line)
-        */
-       int (*xlate)(struct irq_host *h, struct device_node *ctrler,
-                    const u32 *intspec, unsigned int intsize,
-                    irq_hw_number_t *out_hwirq, unsigned int *out_type);
-};
-
-struct irq_host {
-       struct list_head        link;
-
-       /* type of reverse mapping technique */
-       unsigned int            revmap_type;
-#define IRQ_HOST_MAP_PRIORITY   0 /* core priority irqs, get irqs 1..15 */
-#define IRQ_HOST_MAP_NOMAP     1 /* no fast reverse mapping */
-#define IRQ_HOST_MAP_LINEAR    2 /* linear map of interrupts */
-#define IRQ_HOST_MAP_TREE      3 /* radix tree */
-       union {
-               struct {
-                       unsigned int size;
-                       unsigned int *revmap;
-               } linear;
-               struct radix_tree_root tree;
-       } revmap_data;
-       struct irq_host_ops     *ops;
-       void                    *host_data;
-       irq_hw_number_t         inval_irq;
-
-       /* Optional device node pointer */
-       struct device_node      *of_node;
-};
-
 struct irq_data;
 extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d);
 extern irq_hw_number_t virq_to_hw(unsigned int virq);
-extern bool virq_is_host(unsigned int virq, struct irq_host *host);
-
-/**
- * irq_alloc_host - Allocate a new irq_host data structure
- * @of_node: optional device-tree node of the interrupt controller
- * @revmap_type: type of reverse mapping to use
- * @revmap_arg: for IRQ_HOST_MAP_LINEAR linear only: size of the map
- * @ops: map/unmap host callbacks
- * @inval_irq: provide a hw number in that host space that is always invalid
- *
- * Allocates and initialize and irq_host structure. Note that in the case of
- * IRQ_HOST_MAP_LEGACY, the map() callback will be called before this returns
- * for all legacy interrupts except 0 (which is always the invalid irq for
- * a legacy controller). For a IRQ_HOST_MAP_LINEAR, the map is allocated by
- * this call as well. For a IRQ_HOST_MAP_TREE, the radix tree will be allocated
- * later during boot automatically (the reverse mapping will use the slow path
- * until that happens).
- */
-extern struct irq_host *irq_alloc_host(struct device_node *of_node,
-                                      unsigned int revmap_type,
-                                      unsigned int revmap_arg,
-                                      struct irq_host_ops *ops,
-                                      irq_hw_number_t inval_irq);
-
-
-/**
- * irq_find_host - Locates a host for a given device node
- * @node: device-tree node of the interrupt controller
- */
-extern struct irq_host *irq_find_host(struct device_node *node);
-
-
-/**
- * irq_set_default_host - Set a "default" host
- * @host: default host pointer
- *
- * For convenience, it's possible to set a "default" host that will be used
- * whenever NULL is passed to irq_create_mapping(). It makes life easier for
- * platforms that want to manipulate a few hard coded interrupt numbers that
- * aren't properly represented in the device-tree.
- */
-extern void irq_set_default_host(struct irq_host *host);
-
-
-/**
- * irq_set_virq_count - Set the maximum number of virt irqs
- * @count: number of linux virtual irqs, capped with NR_IRQS
- *
- * This is mainly for use by platforms like iSeries who want to program
- * the virtual irq number in the controller to avoid the reverse mapping
- */
-extern void irq_set_virq_count(unsigned int count);
-
-
-/**
- * irq_create_mapping - Map a hardware interrupt into linux virq space
- * @host: host owning this hardware interrupt or NULL for default host
- * @hwirq: hardware irq number in that host space
- *
- * Only one mapping per hardware interrupt is permitted. Returns a linux
- * virq number.
- * If the sense/trigger is to be specified, set_irq_type() should be called
- * on the number returned from that call.
- */
-extern unsigned int irq_create_mapping(struct irq_host *host,
-                                      irq_hw_number_t hwirq);
-
-
-/**
- * irq_dispose_mapping - Unmap an interrupt
- * @virq: linux virq number of the interrupt to unmap
- */
-extern void irq_dispose_mapping(unsigned int virq);
-
-/**
- * irq_find_mapping - Find a linux virq from an hw irq number.
- * @host: host owning this hardware interrupt
- * @hwirq: hardware irq number in that host space
- *
- * This is a slow path, for use by generic code. It's expected that an
- * irq controller implementation directly calls the appropriate low level
- * mapping function.
- */
-extern unsigned int irq_find_mapping(struct irq_host *host,
-                                    irq_hw_number_t hwirq);
-
-/**
- * irq_create_direct_mapping - Allocate a virq for direct mapping
- * @host: host to allocate the virq for or NULL for default host
- *
- * This routine is used for irq controllers which can choose the hardware
- * interrupt numbers they generate. In such a case it's simplest to use
- * the linux virq as the hardware interrupt number.
- */
-extern unsigned int irq_create_direct_mapping(struct irq_host *host);
-
-/**
- * irq_radix_revmap_insert - Insert a hw irq to linux virq number mapping.
- * @host: host owning this hardware interrupt
- * @virq: linux irq number
- * @hwirq: hardware irq number in that host space
- *
- * This is for use by irq controllers that use a radix tree reverse
- * mapping for fast lookup.
- */
-extern void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
-                                   irq_hw_number_t hwirq);
-
-/**
- * irq_radix_revmap_lookup - Find a linux virq from a hw irq number.
- * @host: host owning this hardware interrupt
- * @hwirq: hardware irq number in that host space
- *
- * This is a fast path, for use by irq controller code that uses radix tree
- * revmaps
- */
-extern unsigned int irq_radix_revmap_lookup(struct irq_host *host,
-                                           irq_hw_number_t hwirq);
-
-/**
- * irq_linear_revmap - Find a linux virq from a hw irq number.
- * @host: host owning this hardware interrupt
- * @hwirq: hardware irq number in that host space
- *
- * This is a fast path, for use by irq controller code that uses linear
- * revmaps. It does fallback to the slow path if the revmap doesn't exist
- * yet and will create the revmap entry with appropriate locking
- */
-
-extern unsigned int irq_linear_revmap(struct irq_host *host,
-                                     irq_hw_number_t hwirq);
-
-
-
-/**
- * irq_alloc_virt - Allocate virtual irq numbers
- * @host: host owning these new virtual irqs
- * @count: number of consecutive numbers to allocate
- * @hint: pass a hint number, the allocator will try to use a 1:1 mapping
- *
- * This is a low level function that is used internally by irq_create_mapping()
- * and that can be used by some irq controllers implementations for things
- * like allocating ranges of numbers for MSIs. The revmaps are left untouched.
- */
-extern unsigned int irq_alloc_virt(struct irq_host *host,
-                                  unsigned int count,
-                                  unsigned int hint);
-
-/**
- * irq_free_virt - Free virtual irq numbers
- * @virq: virtual irq number of the first interrupt to free
- * @count: number of interrupts to free
- *
- * This function is the opposite of irq_alloc_virt. It will not clear reverse
- * maps, this should be done previously by unmap'ing the interrupt. In fact,
- * all interrupts covered by the range being freed should have been unmapped
- * prior to calling this.
- */
-extern void irq_free_virt(unsigned int virq, unsigned int count);
 
 extern void __init init_pic_c64xplus(void);
 
index 0929e4b..d77bcfd 100644 (file)
@@ -73,10 +73,10 @@ asmlinkage void c6x_do_IRQ(unsigned int prio, struct pt_regs *regs)
        set_irq_regs(old_regs);
 }
 
-static struct irq_host *core_host;
+static struct irq_domain *core_domain;
 
-static int core_host_map(struct irq_host *h, unsigned int virq,
-                        irq_hw_number_t hw)
+static int core_domain_map(struct irq_domain *h, unsigned int virq,
+                          irq_hw_number_t hw)
 {
        if (hw < 4 || hw >= NR_PRIORITY_IRQS)
                return -EINVAL;
@@ -86,8 +86,9 @@ static int core_host_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static struct irq_host_ops core_host_ops = {
-       .map = core_host_map,
+static const struct irq_domain_ops core_domain_ops = {
+       .map = core_domain_map,
+       .xlate = irq_domain_xlate_onecell,
 };
 
 void __init init_IRQ(void)
@@ -100,10 +101,11 @@ void __init init_IRQ(void)
        np = of_find_compatible_node(NULL, NULL, "ti,c64x+core-pic");
        if (np != NULL) {
                /* create the core host */
-               core_host = irq_alloc_host(np, IRQ_HOST_MAP_PRIORITY, 0,
-                                          &core_host_ops, 0);
-               if (core_host)
-                       irq_set_default_host(core_host);
+               core_domain = irq_domain_add_legacy(np, NR_PRIORITY_IRQS,
+                                                   0, 0, &core_domain_ops,
+                                                   NULL);
+               if (core_domain)
+                       irq_set_default_host(core_domain);
                of_node_put(np);
        }
 
@@ -128,601 +130,15 @@ int arch_show_interrupts(struct seq_file *p, int prec)
        return 0;
 }
 
-/*
- * IRQ controller and virtual interrupts
- */
-
-/* The main irq map itself is an array of NR_IRQ entries containing the
- * associate host and irq number. An entry with a host of NULL is free.
- * An entry can be allocated if it's free, the allocator always then sets
- * hwirq first to the host's invalid irq number and then fills ops.
- */
-struct irq_map_entry {
-       irq_hw_number_t hwirq;
-       struct irq_host *host;
-};
-
-static LIST_HEAD(irq_hosts);
-static DEFINE_RAW_SPINLOCK(irq_big_lock);
-static DEFINE_MUTEX(revmap_trees_mutex);
-static struct irq_map_entry irq_map[NR_IRQS];
-static unsigned int irq_virq_count = NR_IRQS;
-static struct irq_host *irq_default_host;
-
 irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
 {
-       return irq_map[d->irq].hwirq;
+       return d->hwirq;
 }
 EXPORT_SYMBOL_GPL(irqd_to_hwirq);
 
 irq_hw_number_t virq_to_hw(unsigned int virq)
 {
-       return irq_map[virq].hwirq;
+       struct irq_data *irq_data = irq_get_irq_data(virq);
+       return WARN_ON(!irq_data) ? 0 : irq_data->hwirq;
 }
 EXPORT_SYMBOL_GPL(virq_to_hw);
-
-bool virq_is_host(unsigned int virq, struct irq_host *host)
-{
-       return irq_map[virq].host == host;
-}
-EXPORT_SYMBOL_GPL(virq_is_host);
-
-static int default_irq_host_match(struct irq_host *h, struct device_node *np)
-{
-       return h->of_node != NULL && h->of_node == np;
-}
-
-struct irq_host *irq_alloc_host(struct device_node *of_node,
-                               unsigned int revmap_type,
-                               unsigned int revmap_arg,
-                               struct irq_host_ops *ops,
-                               irq_hw_number_t inval_irq)
-{
-       struct irq_host *host;
-       unsigned int size = sizeof(struct irq_host);
-       unsigned int i;
-       unsigned int *rmap;
-       unsigned long flags;
-
-       /* Allocate structure and revmap table if using linear mapping */
-       if (revmap_type == IRQ_HOST_MAP_LINEAR)
-               size += revmap_arg * sizeof(unsigned int);
-       host = kzalloc(size, GFP_KERNEL);
-       if (host == NULL)
-               return NULL;
-
-       /* Fill structure */
-       host->revmap_type = revmap_type;
-       host->inval_irq = inval_irq;
-       host->ops = ops;
-       host->of_node = of_node_get(of_node);
-
-       if (host->ops->match == NULL)
-               host->ops->match = default_irq_host_match;
-
-       raw_spin_lock_irqsave(&irq_big_lock, flags);
-
-       /* Check for the priority controller. */
-       if (revmap_type == IRQ_HOST_MAP_PRIORITY) {
-               if (irq_map[0].host != NULL) {
-                       raw_spin_unlock_irqrestore(&irq_big_lock, flags);
-                       of_node_put(host->of_node);
-                       kfree(host);
-                       return NULL;
-               }
-               irq_map[0].host = host;
-       }
-
-       list_add(&host->link, &irq_hosts);
-       raw_spin_unlock_irqrestore(&irq_big_lock, flags);
-
-       /* Additional setups per revmap type */
-       switch (revmap_type) {
-       case IRQ_HOST_MAP_PRIORITY:
-               /* 0 is always the invalid number for priority */
-               host->inval_irq = 0;
-               /* setup us as the host for all priority interrupts */
-               for (i = 1; i < NR_PRIORITY_IRQS; i++) {
-                       irq_map[i].hwirq = i;
-                       smp_wmb();
-                       irq_map[i].host = host;
-                       smp_wmb();
-
-                       ops->map(host, i, i);
-               }
-               break;
-       case IRQ_HOST_MAP_LINEAR:
-               rmap = (unsigned int *)(host + 1);
-               for (i = 0; i < revmap_arg; i++)
-                       rmap[i] = NO_IRQ;
-               host->revmap_data.linear.size = revmap_arg;
-               smp_wmb();
-               host->revmap_data.linear.revmap = rmap;
-               break;
-       case IRQ_HOST_MAP_TREE:
-               INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL);
-               break;
-       default:
-               break;
-       }
-
-       pr_debug("irq: Allocated host of type %d @0x%p\n", revmap_type, host);
-
-       return host;
-}
-
-struct irq_host *irq_find_host(struct device_node *node)
-{
-       struct irq_host *h, *found = NULL;
-       unsigned long flags;
-
-       /* We might want to match the legacy controller last since
-        * it might potentially be set to match all interrupts in
-        * the absence of a device node. This isn't a problem so far
-        * yet though...
-        */
-       raw_spin_lock_irqsave(&irq_big_lock, flags);
-       list_for_each_entry(h, &irq_hosts, link)
-               if (h->ops->match(h, node)) {
-                       found = h;
-                       break;
-               }
-       raw_spin_unlock_irqrestore(&irq_big_lock, flags);
-       return found;
-}
-EXPORT_SYMBOL_GPL(irq_find_host);
-
-void irq_set_default_host(struct irq_host *host)
-{
-       pr_debug("irq: Default host set to @0x%p\n", host);
-
-       irq_default_host = host;
-}
-
-void irq_set_virq_count(unsigned int count)
-{
-       pr_debug("irq: Trying to set virq count to %d\n", count);
-
-       BUG_ON(count < NR_PRIORITY_IRQS);
-       if (count < NR_IRQS)
-               irq_virq_count = count;
-}
-
-static int irq_setup_virq(struct irq_host *host, unsigned int virq,
-                           irq_hw_number_t hwirq)
-{
-       int res;
-
-       res = irq_alloc_desc_at(virq, 0);
-       if (res != virq) {
-               pr_debug("irq: -> allocating desc failed\n");
-               goto error;
-       }
-
-       /* map it */
-       smp_wmb();
-       irq_map[virq].hwirq = hwirq;
-       smp_mb();
-
-       if (host->ops->map(host, virq, hwirq)) {
-               pr_debug("irq: -> mapping failed, freeing\n");
-               goto errdesc;
-       }
-
-       irq_clear_status_flags(virq, IRQ_NOREQUEST);
-
-       return 0;
-
-errdesc:
-       irq_free_descs(virq, 1);
-error:
-       irq_free_virt(virq, 1);
-       return -1;
-}
-
-unsigned int irq_create_direct_mapping(struct irq_host *host)
-{
-       unsigned int virq;
-
-       if (host == NULL)
-               host = irq_default_host;
-
-       BUG_ON(host == NULL);
-       WARN_ON(host->revmap_type != IRQ_HOST_MAP_NOMAP);
-
-       virq = irq_alloc_virt(host, 1, 0);
-       if (virq == NO_IRQ) {
-               pr_debug("irq: create_direct virq allocation failed\n");
-               return NO_IRQ;
-       }
-
-       pr_debug("irq: create_direct obtained virq %d\n", virq);
-
-       if (irq_setup_virq(host, virq, virq))
-               return NO_IRQ;
-
-       return virq;
-}
-
-unsigned int irq_create_mapping(struct irq_host *host,
-                               irq_hw_number_t hwirq)
-{
-       unsigned int virq, hint;
-
-       pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", host, hwirq);
-
-       /* Look for default host if nececssary */
-       if (host == NULL)
-               host = irq_default_host;
-       if (host == NULL) {
-               printk(KERN_WARNING "irq_create_mapping called for"
-                      " NULL host, hwirq=%lx\n", hwirq);
-               WARN_ON(1);
-               return NO_IRQ;
-       }
-       pr_debug("irq: -> using host @%p\n", host);
-
-       /* Check if mapping already exists */
-       virq = irq_find_mapping(host, hwirq);
-       if (virq != NO_IRQ) {
-               pr_debug("irq: -> existing mapping on virq %d\n", virq);
-               return virq;
-       }
-
-       /* Allocate a virtual interrupt number */
-       hint = hwirq % irq_virq_count;
-       virq = irq_alloc_virt(host, 1, hint);
-       if (virq == NO_IRQ) {
-               pr_debug("irq: -> virq allocation failed\n");
-               return NO_IRQ;
-       }
-
-       if (irq_setup_virq(host, virq, hwirq))
-               return NO_IRQ;
-
-       pr_debug("irq: irq %lu on host %s mapped to virtual irq %u\n",
-               hwirq, host->of_node ? host->of_node->full_name : "null", virq);
-
-       return virq;
-}
-EXPORT_SYMBOL_GPL(irq_create_mapping);
-
-unsigned int irq_create_of_mapping(struct device_node *controller,
-                                  const u32 *intspec, unsigned int intsize)
-{
-       struct irq_host *host;
-       irq_hw_number_t hwirq;
-       unsigned int type = IRQ_TYPE_NONE;
-       unsigned int virq;
-
-       if (controller == NULL)
-               host = irq_default_host;
-       else
-               host = irq_find_host(controller);
-       if (host == NULL) {
-               printk(KERN_WARNING "irq: no irq host found for %s !\n",
-                      controller->full_name);
-               return NO_IRQ;
-       }
-
-       /* If host has no translation, then we assume interrupt line */
-       if (host->ops->xlate == NULL)
-               hwirq = intspec[0];
-       else {
-               if (host->ops->xlate(host, controller, intspec, intsize,
-                                    &hwirq, &type))
-                       return NO_IRQ;
-       }
-
-       /* Create mapping */
-       virq = irq_create_mapping(host, hwirq);
-       if (virq == NO_IRQ)
-               return virq;
-
-       /* Set type if specified and different than the current one */
-       if (type != IRQ_TYPE_NONE &&
-           type != (irqd_get_trigger_type(irq_get_irq_data(virq))))
-               irq_set_irq_type(virq, type);
-       return virq;
-}
-EXPORT_SYMBOL_GPL(irq_create_of_mapping);
-
-void irq_dispose_mapping(unsigned int virq)
-{
-       struct irq_host *host;
-       irq_hw_number_t hwirq;
-
-       if (virq == NO_IRQ)
-               return;
-
-       /* Never unmap priority interrupts */
-       if (virq < NR_PRIORITY_IRQS)
-               return;
-
-       host = irq_map[virq].host;
-       if (WARN_ON(host == NULL))
-               return;
-
-       irq_set_status_flags(virq, IRQ_NOREQUEST);
-
-       /* remove chip and handler */
-       irq_set_chip_and_handler(virq, NULL, NULL);
-
-       /* Make sure it's completed */
-       synchronize_irq(virq);
-
-       /* Tell the PIC about it */
-       if (host->ops->unmap)
-               host->ops->unmap(host, virq);
-       smp_mb();
-
-       /* Clear reverse map */
-       hwirq = irq_map[virq].hwirq;
-       switch (host->revmap_type) {
-       case IRQ_HOST_MAP_LINEAR:
-               if (hwirq < host->revmap_data.linear.size)
-                       host->revmap_data.linear.revmap[hwirq] = NO_IRQ;
-               break;
-       case IRQ_HOST_MAP_TREE:
-               mutex_lock(&revmap_trees_mutex);
-               radix_tree_delete(&host->revmap_data.tree, hwirq);
-               mutex_unlock(&revmap_trees_mutex);
-               break;
-       }
-
-       /* Destroy map */
-       smp_mb();
-       irq_map[virq].hwirq = host->inval_irq;
-
-       irq_free_descs(virq, 1);
-       /* Free it */
-       irq_free_virt(virq, 1);
-}
-EXPORT_SYMBOL_GPL(irq_dispose_mapping);
-
-unsigned int irq_find_mapping(struct irq_host *host,
-                             irq_hw_number_t hwirq)
-{
-       unsigned int i;
-       unsigned int hint = hwirq % irq_virq_count;
-
-       /* Look for default host if nececssary */
-       if (host == NULL)
-               host = irq_default_host;
-       if (host == NULL)
-               return NO_IRQ;
-
-       /* Slow path does a linear search of the map */
-       i = hint;
-       do  {
-               if (irq_map[i].host == host &&
-                   irq_map[i].hwirq == hwirq)
-                       return i;
-               i++;
-               if (i >= irq_virq_count)
-                       i = 4;
-       } while (i != hint);
-       return NO_IRQ;
-}
-EXPORT_SYMBOL_GPL(irq_find_mapping);
-
-unsigned int irq_radix_revmap_lookup(struct irq_host *host,
-                                    irq_hw_number_t hwirq)
-{
-       struct irq_map_entry *ptr;
-       unsigned int virq;
-
-       if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_TREE))
-               return irq_find_mapping(host, hwirq);
-
-       /*
-        * The ptr returned references the static global irq_map.
-        * but freeing an irq can delete nodes along the path to
-        * do the lookup via call_rcu.
-        */
-       rcu_read_lock();
-       ptr = radix_tree_lookup(&host->revmap_data.tree, hwirq);
-       rcu_read_unlock();
-
-       /*
-        * If found in radix tree, then fine.
-        * Else fallback to linear lookup - this should not happen in practice
-        * as it means that we failed to insert the node in the radix tree.
-        */
-       if (ptr)
-               virq = ptr - irq_map;
-       else
-               virq = irq_find_mapping(host, hwirq);
-
-       return virq;
-}
-
-void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
-                            irq_hw_number_t hwirq)
-{
-       if (WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE))
-               return;
-
-       if (virq != NO_IRQ) {
-               mutex_lock(&revmap_trees_mutex);
-               radix_tree_insert(&host->revmap_data.tree, hwirq,
-                                 &irq_map[virq]);
-               mutex_unlock(&revmap_trees_mutex);
-       }
-}
-
-unsigned int irq_linear_revmap(struct irq_host *host,
-                              irq_hw_number_t hwirq)
-{
-       unsigned int *revmap;
-
-       if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_LINEAR))
-               return irq_find_mapping(host, hwirq);
-
-       /* Check revmap bounds */
-       if (unlikely(hwirq >= host->revmap_data.linear.size))
-               return irq_find_mapping(host, hwirq);
-
-       /* Check if revmap was allocated */
-       revmap = host->revmap_data.linear.revmap;
-       if (unlikely(revmap == NULL))
-               return irq_find_mapping(host, hwirq);
-
-       /* Fill up revmap with slow path if no mapping found */
-       if (unlikely(revmap[hwirq] == NO_IRQ))
-               revmap[hwirq] = irq_find_mapping(host, hwirq);
-
-       return revmap[hwirq];
-}
-
-unsigned int irq_alloc_virt(struct irq_host *host,
-                           unsigned int count,
-                           unsigned int hint)
-{
-       unsigned long flags;
-       unsigned int i, j, found = NO_IRQ;
-
-       if (count == 0 || count > (irq_virq_count - NR_PRIORITY_IRQS))
-               return NO_IRQ;
-
-       raw_spin_lock_irqsave(&irq_big_lock, flags);
-
-       /* Use hint for 1 interrupt if any */
-       if (count == 1 && hint >= NR_PRIORITY_IRQS &&
-           hint < irq_virq_count && irq_map[hint].host == NULL) {
-               found = hint;
-               goto hint_found;
-       }
-
-       /* Look for count consecutive numbers in the allocatable
-        * (non-legacy) space
-        */
-       for (i = NR_PRIORITY_IRQS, j = 0; i < irq_virq_count; i++) {
-               if (irq_map[i].host != NULL)
-                       j = 0;
-               else
-                       j++;
-
-               if (j == count) {
-                       found = i - count + 1;
-                       break;
-               }
-       }
-       if (found == NO_IRQ) {
-               raw_spin_unlock_irqrestore(&irq_big_lock, flags);
-               return NO_IRQ;
-       }
- hint_found:
-       for (i = found; i < (found + count); i++) {
-               irq_map[i].hwirq = host->inval_irq;
-               smp_wmb();
-               irq_map[i].host = host;
-       }
-       raw_spin_unlock_irqrestore(&irq_big_lock, flags);
-       return found;
-}
-
-void irq_free_virt(unsigned int virq, unsigned int count)
-{
-       unsigned long flags;
-       unsigned int i;
-
-       WARN_ON(virq < NR_PRIORITY_IRQS);
-       WARN_ON(count == 0 || (virq + count) > irq_virq_count);
-
-       if (virq < NR_PRIORITY_IRQS) {
-               if (virq + count < NR_PRIORITY_IRQS)
-                       return;
-               count  -= NR_PRIORITY_IRQS - virq;
-               virq = NR_PRIORITY_IRQS;
-       }
-
-       if (count > irq_virq_count || virq > irq_virq_count - count) {
-               if (virq > irq_virq_count)
-                       return;
-               count = irq_virq_count - virq;
-       }
-
-       raw_spin_lock_irqsave(&irq_big_lock, flags);
-       for (i = virq; i < (virq + count); i++) {
-               struct irq_host *host;
-
-               host = irq_map[i].host;
-               irq_map[i].hwirq = host->inval_irq;
-               smp_wmb();
-               irq_map[i].host = NULL;
-       }
-       raw_spin_unlock_irqrestore(&irq_big_lock, flags);
-}
-
-#ifdef CONFIG_VIRQ_DEBUG
-static int virq_debug_show(struct seq_file *m, void *private)
-{
-       unsigned long flags;
-       struct irq_desc *desc;
-       const char *p;
-       static const char none[] = "none";
-       void *data;
-       int i;
-
-       seq_printf(m, "%-5s  %-7s  %-15s  %-18s  %s\n", "virq", "hwirq",
-                     "chip name", "chip data", "host name");
-
-       for (i = 1; i < nr_irqs; i++) {
-               desc = irq_to_desc(i);
-               if (!desc)
-                       continue;
-
-               raw_spin_lock_irqsave(&desc->lock, flags);
-
-               if (desc->action && desc->action->handler) {
-                       struct irq_chip *chip;
-
-                       seq_printf(m, "%5d  ", i);
-                       seq_printf(m, "0x%05lx  ", irq_map[i].hwirq);
-
-                       chip = irq_desc_get_chip(desc);
-                       if (chip && chip->name)
-                               p = chip->name;
-                       else
-                               p = none;
-                       seq_printf(m, "%-15s  ", p);
-
-                       data = irq_desc_get_chip_data(desc);
-                       seq_printf(m, "0x%16p  ", data);
-
-                       if (irq_map[i].host && irq_map[i].host->of_node)
-                               p = irq_map[i].host->of_node->full_name;
-                       else
-                               p = none;
-                       seq_printf(m, "%s\n", p);
-               }
-
-               raw_spin_unlock_irqrestore(&desc->lock, flags);
-       }
-
-       return 0;
-}
-
-static int virq_debug_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, virq_debug_show, inode->i_private);
-}
-
-static const struct file_operations virq_debug_fops = {
-       .open = virq_debug_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
-
-static int __init irq_debugfs_init(void)
-{
-       if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root,
-                                NULL, &virq_debug_fops) == NULL)
-               return -ENOMEM;
-
-       return 0;
-}
-device_initcall(irq_debugfs_init);
-#endif /* CONFIG_VIRQ_DEBUG */
index 7c37a94..c1c4e2a 100644 (file)
@@ -48,7 +48,7 @@ struct megamod_regs {
 };
 
 struct megamod_pic {
-       struct irq_host *irqhost;
+       struct irq_domain *irqhost;
        struct megamod_regs __iomem *regs;
        raw_spinlock_t lock;
 
@@ -116,7 +116,7 @@ static void megamod_irq_cascade(unsigned int irq, struct irq_desc *desc)
        }
 }
 
-static int megamod_map(struct irq_host *h, unsigned int virq,
+static int megamod_map(struct irq_domain *h, unsigned int virq,
                       irq_hw_number_t hw)
 {
        struct megamod_pic *pic = h->host_data;
@@ -136,21 +136,9 @@ static int megamod_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static int megamod_xlate(struct irq_host *h, struct device_node *ct,
-                        const u32 *intspec, unsigned int intsize,
-                        irq_hw_number_t *out_hwirq, unsigned int *out_type)
-
-{
-       /* megamod intspecs must have 1 cell */
-       BUG_ON(intsize != 1);
-       *out_hwirq = intspec[0];
-       *out_type = IRQ_TYPE_NONE;
-       return 0;
-}
-
-static struct irq_host_ops megamod_host_ops = {
+static const struct irq_domain_ops megamod_domain_ops = {
        .map    = megamod_map,
-       .xlate  = megamod_xlate,
+       .xlate  = irq_domain_xlate_onecell,
 };
 
 static void __init set_megamod_mux(struct megamod_pic *pic, int src, int output)
@@ -223,9 +211,8 @@ static struct megamod_pic * __init init_megamod_pic(struct device_node *np)
                return NULL;
        }
 
-       pic->irqhost = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
-                                     NR_COMBINERS * 32, &megamod_host_ops,
-                                     IRQ_UNMAPPED);
+       pic->irqhost = irq_domain_add_linear(np, NR_COMBINERS * 32,
+                                            &megamod_domain_ops, pic);
        if (!pic->irqhost) {
                pr_err("%s: Could not alloc host.\n", np->full_name);
                goto error_free;
index c8d6efb..11060fa 100644 (file)
@@ -14,6 +14,7 @@ config MICROBLAZE
        select TRACING_SUPPORT
        select OF
        select OF_EARLY_FLATTREE
+       select IRQ_DOMAIN
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
index cd1ac9a..fb3c05a 100644 (file)
@@ -1,17 +1 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_HARDIRQ_H
-#define _ASM_MICROBLAZE_HARDIRQ_H
-
-/* should be defined in each interrupt controller driver */
-extern unsigned int get_irq(struct pt_regs *regs);
-
 #include <asm-generic/hardirq.h>
-
-#endif /* _ASM_MICROBLAZE_HARDIRQ_H */
index a175132..bab3b13 100644 (file)
@@ -9,49 +9,13 @@
 #ifndef _ASM_MICROBLAZE_IRQ_H
 #define _ASM_MICROBLAZE_IRQ_H
 
-
-/*
- * Linux IRQ# is currently offset by one to map to the hardware
- * irq number. So hardware IRQ0 maps to Linux irq 1.
- */
-#define NO_IRQ_OFFSET  1
-#define IRQ_OFFSET     NO_IRQ_OFFSET
-#define NR_IRQS                (32 + IRQ_OFFSET)
+#define NR_IRQS                (32 + 1)
 #include <asm-generic/irq.h>
 
-/* This type is the placeholder for a hardware interrupt number. It has to
- * be big enough to enclose whatever representation is used by a given
- * platform.
- */
-typedef unsigned long irq_hw_number_t;
-
-extern unsigned int nr_irq;
-
 struct pt_regs;
 extern void do_IRQ(struct pt_regs *regs);
 
-/** FIXME - not implement
- * irq_dispose_mapping - Unmap an interrupt
- * @virq: linux virq number of the interrupt to unmap
- */
-static inline void irq_dispose_mapping(unsigned int virq)
-{
-       return;
-}
-
-struct irq_host;
-
-/**
- * irq_create_mapping - Map a hardware interrupt into linux virq space
- * @host: host owning this hardware interrupt or NULL for default host
- * @hwirq: hardware irq number in that host space
- *
- * Only one mapping per hardware interrupt is permitted. Returns a linux
- * virq number.
- * If the sense/trigger is to be specified, set_irq_type() should be called
- * on the number returned from that call.
- */
-extern unsigned int irq_create_mapping(struct irq_host *host,
-                                       irq_hw_number_t hwirq);
+/* should be defined in each interrupt controller driver */
+extern unsigned int get_irq(void);
 
 #endif /* _ASM_MICROBLAZE_IRQ_H */
index 44b177e..ad12067 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/irqdomain.h>
 #include <linux/irq.h>
 #include <asm/page.h>
 #include <linux/io.h>
@@ -25,8 +26,6 @@ static unsigned int intc_baseaddr;
 #define INTC_BASE      intc_baseaddr
 #endif
 
-unsigned int nr_irq;
-
 /* No one else should require these constants, so define them locally here. */
 #define ISR 0x00                       /* Interrupt Status Register */
 #define IPR 0x04                       /* Interrupt Pending Register */
@@ -84,24 +83,45 @@ static struct irq_chip intc_dev = {
        .irq_mask_ack = intc_mask_ack,
 };
 
-unsigned int get_irq(struct pt_regs *regs)
+static struct irq_domain *root_domain;
+
+unsigned int get_irq(void)
 {
-       int irq;
+       unsigned int hwirq, irq = -1;
 
-       /*
-        * NOTE: This function is the one that needs to be improved in
-        * order to handle multiple interrupt controllers. It currently
-        * is hardcoded to check for interrupts only on the first INTC.
-        */
-       irq = in_be32(INTC_BASE + IVR) + NO_IRQ_OFFSET;
-       pr_debug("get_irq: %d\n", irq);
+       hwirq = in_be32(INTC_BASE + IVR);
+       if (hwirq != -1U)
+               irq = irq_find_mapping(root_domain, hwirq);
+
+       pr_debug("get_irq: hwirq=%d, irq=%d\n", hwirq, irq);
 
        return irq;
 }
 
+int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
+{
+       u32 intr_mask = (u32)d->host_data;
+
+       if (intr_mask & (1 << hw)) {
+               irq_set_chip_and_handler_name(irq, &intc_dev,
+                                               handle_edge_irq, "edge");
+               irq_clear_status_flags(irq, IRQ_LEVEL);
+       } else {
+               irq_set_chip_and_handler_name(irq, &intc_dev,
+                                               handle_level_irq, "level");
+               irq_set_status_flags(irq, IRQ_LEVEL);
+       }
+       return 0;
+}
+
+static const struct irq_domain_ops xintc_irq_domain_ops = {
+       .xlate = irq_domain_xlate_onetwocell,
+       .map = xintc_map,
+};
+
 void __init init_IRQ(void)
 {
-       u32 i, intr_mask;
+       u32 nr_irq, intr_mask;
        struct device_node *intc = NULL;
 #ifdef CONFIG_SELFMOD_INTC
        unsigned int intc_baseaddr = 0;
@@ -146,16 +166,9 @@ void __init init_IRQ(void)
        /* Turn on the Master Enable. */
        out_be32(intc_baseaddr + MER, MER_HIE | MER_ME);
 
-       for (i = IRQ_OFFSET; i < (nr_irq + IRQ_OFFSET); ++i) {
-               if (intr_mask & (0x00000001 << (i - IRQ_OFFSET))) {
-                       irq_set_chip_and_handler_name(i, &intc_dev,
-                               handle_edge_irq, "edge");
-                       irq_clear_status_flags(i, IRQ_LEVEL);
-               } else {
-                       irq_set_chip_and_handler_name(i, &intc_dev,
-                               handle_level_irq, "level");
-                       irq_set_status_flags(i, IRQ_LEVEL);
-               }
-               irq_get_irq_data(i)->hwirq = i - IRQ_OFFSET;
-       }
+       /* Yeah, okay, casting the intr_mask to a void* is butt-ugly, but I'm
+        * lazy and Michal can clean it up to something nicer when he tests
+        * and commits this patch.  ~~gcl */
+       root_domain = irq_domain_add_linear(intc, nr_irq, &xintc_irq_domain_ops,
+                                                       (void *)intr_mask);
 }
index bbebcae..ace700a 100644 (file)
@@ -31,14 +31,13 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
        trace_hardirqs_off();
 
        irq_enter();
-       irq = get_irq(regs);
+       irq = get_irq();
 next_irq:
        BUG_ON(!irq);
-       /* Substract 1 because of get_irq */
-       generic_handle_irq(irq + IRQ_OFFSET - NO_IRQ_OFFSET);
+       generic_handle_irq(irq);
 
-       irq = get_irq(regs);
-       if (irq) {
+       irq = get_irq();
+       if (irq != -1U) {
                pr_debug("next irq: %d\n", irq);
                ++concurrent_irq;
                goto next_irq;
@@ -48,18 +47,3 @@ next_irq:
        set_irq_regs(old_regs);
        trace_hardirqs_on();
 }
-
-/* MS: There is no any advance mapping mechanism. We are using simple 32bit
-  intc without any cascades or any connection that's why mapping is 1:1 */
-unsigned int irq_create_mapping(struct irq_host *host, irq_hw_number_t hwirq)
-{
-       return hwirq + IRQ_OFFSET;
-}
-EXPORT_SYMBOL_GPL(irq_create_mapping);
-
-unsigned int irq_create_of_mapping(struct device_node *controller,
-                                  const u32 *intspec, unsigned int intsize)
-{
-       return intspec[0] + IRQ_OFFSET;
-}
-EXPORT_SYMBOL_GPL(irq_create_of_mapping);
index 604cd9d..70e6d0b 100644 (file)
@@ -51,8 +51,6 @@ void __init setup_arch(char **cmdline_p)
 
        unflatten_device_tree();
 
-       /* NOTE I think that this function is not necessary to call */
-       /* irq_early_init(); */
        setup_cpuinfo();
 
        microblaze_cache_init();
index 5ab6e89..edbbae1 100644 (file)
@@ -2327,6 +2327,7 @@ config USE_OF
        bool "Flattened Device Tree support"
        select OF
        select OF_EARLY_FLATTREE
+       select IRQ_DOMAIN
        help
          Include support for flattened device tree machine descriptions.
 
index 2354c87..fb698dc 100644 (file)
 
 #include <linux/linkage.h>
 #include <linux/smp.h>
+#include <linux/irqdomain.h>
 
 #include <asm/mipsmtregs.h>
 
 #include <irq.h>
 
-static inline void irq_dispose_mapping(unsigned int virq)
-{
-}
-
 #ifdef CONFIG_I8259
 static inline int irq_canonicalize(int irq)
 {
index 6b8b420..558b539 100644 (file)
@@ -60,20 +60,6 @@ void __init early_init_dt_setup_initrd_arch(unsigned long start,
 }
 #endif
 
-/*
- * irq_create_of_mapping - Hook to resolve OF irq specifier into a Linux irq#
- *
- * Currently the mapping mechanism is trivial; simple flat hwirq numbers are
- * mapped 1:1 onto Linux irq numbers.  Cascaded irq controllers are not
- * supported.
- */
-unsigned int irq_create_of_mapping(struct device_node *controller,
-                                  const u32 *intspec, unsigned int intsize)
-{
-       return intspec[0];
-}
-EXPORT_SYMBOL_GPL(irq_create_of_mapping);
-
 void __init early_init_devtree(void *params)
 {
        /* Setup flat device-tree pointer */
index e1f3fe2..bbb34e5 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <linux/types.h>
 #include <asm/irq.h>
+#include <linux/irqdomain.h>
 #include <linux/atomic.h>
 #include <linux/of_irq.h>
 #include <linux/of_fdt.h>
@@ -63,15 +64,6 @@ extern const void *of_get_mac_address(struct device_node *np);
 struct pci_dev;
 extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq);
 
-/* This routine is here to provide compatibility with how powerpc
- * handles IRQ mapping for OF device nodes.  We precompute and permanently
- * register them in the platform_device objects, whereas powerpc computes them
- * on request.
- */
-static inline void irq_dispose_mapping(unsigned int virq)
-{
-}
-
 #endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* _ASM_OPENRISC_PROM_H */
index 1919634..303703d 100644 (file)
@@ -135,6 +135,7 @@ config PPC
        select HAVE_GENERIC_HARDIRQS
        select HAVE_SPARSE_IRQ
        select IRQ_PER_CPU
+       select IRQ_DOMAIN
        select GENERIC_IRQ_SHOW
        select GENERIC_IRQ_SHOW_LEVEL
        select IRQ_FORCED_THREADING
index a9e1f4f..dc7d48e 100644 (file)
@@ -25,7 +25,7 @@
 
 struct ehv_pic {
        /* The remapper for this EHV_PIC */
-       struct irq_host *irqhost;
+       struct irq_domain       *irqhost;
 
        /* The "linux" controller struct */
        struct irq_chip hc_irq;
index 105ade2..c3fdfbd 100644 (file)
@@ -6,7 +6,7 @@
 
 extern void i8259_init(struct device_node *node, unsigned long intack_addr);
 extern unsigned int i8259_irq(void);
-extern struct irq_host *i8259_get_host(void);
+extern struct irq_domain *i8259_get_host(void);
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_I8259_H */
index c0e1bc3..fe0b09d 100644 (file)
@@ -9,6 +9,7 @@
  * 2 of the License, or (at your option) any later version.
  */
 
+#include <linux/irqdomain.h>
 #include <linux/threads.h>
 #include <linux/list.h>
 #include <linux/radix-tree.h>
@@ -35,258 +36,12 @@ extern atomic_t ppc_n_lost_interrupts;
 /* Total number of virq in the platform */
 #define NR_IRQS                CONFIG_NR_IRQS
 
-/* Number of irqs reserved for the legacy controller */
-#define NUM_ISA_INTERRUPTS     16
-
 /* Same thing, used by the generic IRQ code */
 #define NR_IRQS_LEGACY         NUM_ISA_INTERRUPTS
 
-/* This type is the placeholder for a hardware interrupt number. It has to
- * be big enough to enclose whatever representation is used by a given
- * platform.
- */
-typedef unsigned long irq_hw_number_t;
-
-/* Interrupt controller "host" data structure. This could be defined as a
- * irq domain controller. That is, it handles the mapping between hardware
- * and virtual interrupt numbers for a given interrupt domain. The host
- * structure is generally created by the PIC code for a given PIC instance
- * (though a host can cover more than one PIC if they have a flat number
- * model). It's the host callbacks that are responsible for setting the
- * irq_chip on a given irq_desc after it's been mapped.
- *
- * The host code and data structures are fairly agnostic to the fact that
- * we use an open firmware device-tree. We do have references to struct
- * device_node in two places: in irq_find_host() to find the host matching
- * a given interrupt controller node, and of course as an argument to its
- * counterpart host->ops->match() callback. However, those are treated as
- * generic pointers by the core and the fact that it's actually a device-node
- * pointer is purely a convention between callers and implementation. This
- * code could thus be used on other architectures by replacing those two
- * by some sort of arch-specific void * "token" used to identify interrupt
- * controllers.
- */
-struct irq_host;
-struct radix_tree_root;
-
-/* Functions below are provided by the host and called whenever a new mapping
- * is created or an old mapping is disposed. The host can then proceed to
- * whatever internal data structures management is required. It also needs
- * to setup the irq_desc when returning from map().
- */
-struct irq_host_ops {
-       /* Match an interrupt controller device node to a host, returns
-        * 1 on a match
-        */
-       int (*match)(struct irq_host *h, struct device_node *node);
-
-       /* Create or update a mapping between a virtual irq number and a hw
-        * irq number. This is called only once for a given mapping.
-        */
-       int (*map)(struct irq_host *h, unsigned int virq, irq_hw_number_t hw);
-
-       /* Dispose of such a mapping */
-       void (*unmap)(struct irq_host *h, unsigned int virq);
-
-       /* Translate device-tree interrupt specifier from raw format coming
-        * from the firmware to a irq_hw_number_t (interrupt line number) and
-        * type (sense) that can be passed to set_irq_type(). In the absence
-        * of this callback, irq_create_of_mapping() and irq_of_parse_and_map()
-        * will return the hw number in the first cell and IRQ_TYPE_NONE for
-        * the type (which amount to keeping whatever default value the
-        * interrupt controller has for that line)
-        */
-       int (*xlate)(struct irq_host *h, struct device_node *ctrler,
-                    const u32 *intspec, unsigned int intsize,
-                    irq_hw_number_t *out_hwirq, unsigned int *out_type);
-};
-
-struct irq_host {
-       struct list_head        link;
-
-       /* type of reverse mapping technique */
-       unsigned int            revmap_type;
-#define IRQ_HOST_MAP_LEGACY     0 /* legacy 8259, gets irqs 1..15 */
-#define IRQ_HOST_MAP_NOMAP     1 /* no fast reverse mapping */
-#define IRQ_HOST_MAP_LINEAR    2 /* linear map of interrupts */
-#define IRQ_HOST_MAP_TREE      3 /* radix tree */
-       union {
-               struct {
-                       unsigned int size;
-                       unsigned int *revmap;
-               } linear;
-               struct radix_tree_root tree;
-       } revmap_data;
-       struct irq_host_ops     *ops;
-       void                    *host_data;
-       irq_hw_number_t         inval_irq;
-
-       /* Optional device node pointer */
-       struct device_node      *of_node;
-};
-
 struct irq_data;
 extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d);
 extern irq_hw_number_t virq_to_hw(unsigned int virq);
-extern bool virq_is_host(unsigned int virq, struct irq_host *host);
-
-/**
- * irq_alloc_host - Allocate a new irq_host data structure
- * @of_node: optional device-tree node of the interrupt controller
- * @revmap_type: type of reverse mapping to use
- * @revmap_arg: for IRQ_HOST_MAP_LINEAR linear only: size of the map
- * @ops: map/unmap host callbacks
- * @inval_irq: provide a hw number in that host space that is always invalid
- *
- * Allocates and initialize and irq_host structure. Note that in the case of
- * IRQ_HOST_MAP_LEGACY, the map() callback will be called before this returns
- * for all legacy interrupts except 0 (which is always the invalid irq for
- * a legacy controller). For a IRQ_HOST_MAP_LINEAR, the map is allocated by
- * this call as well. For a IRQ_HOST_MAP_TREE, the radix tree will be allocated
- * later during boot automatically (the reverse mapping will use the slow path
- * until that happens).
- */
-extern struct irq_host *irq_alloc_host(struct device_node *of_node,
-                                      unsigned int revmap_type,
-                                      unsigned int revmap_arg,
-                                      struct irq_host_ops *ops,
-                                      irq_hw_number_t inval_irq);
-
-
-/**
- * irq_find_host - Locates a host for a given device node
- * @node: device-tree node of the interrupt controller
- */
-extern struct irq_host *irq_find_host(struct device_node *node);
-
-
-/**
- * irq_set_default_host - Set a "default" host
- * @host: default host pointer
- *
- * For convenience, it's possible to set a "default" host that will be used
- * whenever NULL is passed to irq_create_mapping(). It makes life easier for
- * platforms that want to manipulate a few hard coded interrupt numbers that
- * aren't properly represented in the device-tree.
- */
-extern void irq_set_default_host(struct irq_host *host);
-
-
-/**
- * irq_set_virq_count - Set the maximum number of virt irqs
- * @count: number of linux virtual irqs, capped with NR_IRQS
- *
- * This is mainly for use by platforms like iSeries who want to program
- * the virtual irq number in the controller to avoid the reverse mapping
- */
-extern void irq_set_virq_count(unsigned int count);
-
-
-/**
- * irq_create_mapping - Map a hardware interrupt into linux virq space
- * @host: host owning this hardware interrupt or NULL for default host
- * @hwirq: hardware irq number in that host space
- *
- * Only one mapping per hardware interrupt is permitted. Returns a linux
- * virq number.
- * If the sense/trigger is to be specified, set_irq_type() should be called
- * on the number returned from that call.
- */
-extern unsigned int irq_create_mapping(struct irq_host *host,
-                                      irq_hw_number_t hwirq);
-
-
-/**
- * irq_dispose_mapping - Unmap an interrupt
- * @virq: linux virq number of the interrupt to unmap
- */
-extern void irq_dispose_mapping(unsigned int virq);
-
-/**
- * irq_find_mapping - Find a linux virq from an hw irq number.
- * @host: host owning this hardware interrupt
- * @hwirq: hardware irq number in that host space
- *
- * This is a slow path, for use by generic code. It's expected that an
- * irq controller implementation directly calls the appropriate low level
- * mapping function.
- */
-extern unsigned int irq_find_mapping(struct irq_host *host,
-                                    irq_hw_number_t hwirq);
-
-/**
- * irq_create_direct_mapping - Allocate a virq for direct mapping
- * @host: host to allocate the virq for or NULL for default host
- *
- * This routine is used for irq controllers which can choose the hardware
- * interrupt numbers they generate. In such a case it's simplest to use
- * the linux virq as the hardware interrupt number.
- */
-extern unsigned int irq_create_direct_mapping(struct irq_host *host);
-
-/**
- * irq_radix_revmap_insert - Insert a hw irq to linux virq number mapping.
- * @host: host owning this hardware interrupt
- * @virq: linux irq number
- * @hwirq: hardware irq number in that host space
- *
- * This is for use by irq controllers that use a radix tree reverse
- * mapping for fast lookup.
- */
-extern void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
-                                   irq_hw_number_t hwirq);
-
-/**
- * irq_radix_revmap_lookup - Find a linux virq from a hw irq number.
- * @host: host owning this hardware interrupt
- * @hwirq: hardware irq number in that host space
- *
- * This is a fast path, for use by irq controller code that uses radix tree
- * revmaps
- */
-extern unsigned int irq_radix_revmap_lookup(struct irq_host *host,
-                                           irq_hw_number_t hwirq);
-
-/**
- * irq_linear_revmap - Find a linux virq from a hw irq number.
- * @host: host owning this hardware interrupt
- * @hwirq: hardware irq number in that host space
- *
- * This is a fast path, for use by irq controller code that uses linear
- * revmaps. It does fallback to the slow path if the revmap doesn't exist
- * yet and will create the revmap entry with appropriate locking
- */
-
-extern unsigned int irq_linear_revmap(struct irq_host *host,
-                                     irq_hw_number_t hwirq);
-
-
-
-/**
- * irq_alloc_virt - Allocate virtual irq numbers
- * @host: host owning these new virtual irqs
- * @count: number of consecutive numbers to allocate
- * @hint: pass a hint number, the allocator will try to use a 1:1 mapping
- *
- * This is a low level function that is used internally by irq_create_mapping()
- * and that can be used by some irq controllers implementations for things
- * like allocating ranges of numbers for MSIs. The revmaps are left untouched.
- */
-extern unsigned int irq_alloc_virt(struct irq_host *host,
-                                  unsigned int count,
-                                  unsigned int hint);
-
-/**
- * irq_free_virt - Free virtual irq numbers
- * @virq: virtual irq number of the first interrupt to free
- * @count: number of interrupts to free
- *
- * This function is the opposite of irq_alloc_virt. It will not clear reverse
- * maps, this should be done previously by unmap'ing the interrupt. In fact,
- * all interrupts covered by the range being freed should have been unmapped
- * prior to calling this.
- */
-extern void irq_free_virt(unsigned int virq, unsigned int count);
 
 /**
  * irq_early_init - Init irq remapping subsystem
index 67b4d98..a5b7c56 100644 (file)
@@ -255,7 +255,7 @@ struct mpic
        struct device_node *node;
 
        /* The remapper for this MPIC */
-       struct irq_host         *irqhost;
+       struct irq_domain       *irqhost;
 
        /* The "linux" controller struct */
        struct irq_chip         hc_irq;
index c48de98..4ae9a09 100644 (file)
@@ -86,7 +86,7 @@ struct ics {
 extern unsigned int xics_default_server;
 extern unsigned int xics_default_distrib_server;
 extern unsigned int xics_interrupt_server_size;
-extern struct irq_host *xics_host;
+extern struct irq_domain *xics_host;
 
 struct xics_cppr {
        unsigned char stack[MAX_NUM_PRIORITIES];
index 01e2877..bdfb3ee 100644 (file)
@@ -490,409 +490,19 @@ void do_softirq(void)
        local_irq_restore(flags);
 }
 
-
-/*
- * IRQ controller and virtual interrupts
- */
-
-/* The main irq map itself is an array of NR_IRQ entries containing the
- * associate host and irq number. An entry with a host of NULL is free.
- * An entry can be allocated if it's free, the allocator always then sets
- * hwirq first to the host's invalid irq number and then fills ops.
- */
-struct irq_map_entry {
-       irq_hw_number_t hwirq;
-       struct irq_host *host;
-};
-
-static LIST_HEAD(irq_hosts);
-static DEFINE_RAW_SPINLOCK(irq_big_lock);
-static DEFINE_MUTEX(revmap_trees_mutex);
-static struct irq_map_entry irq_map[NR_IRQS];
-static unsigned int irq_virq_count = NR_IRQS;
-static struct irq_host *irq_default_host;
-
 irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
 {
-       return irq_map[d->irq].hwirq;
+       return d->hwirq;
 }
 EXPORT_SYMBOL_GPL(irqd_to_hwirq);
 
 irq_hw_number_t virq_to_hw(unsigned int virq)
 {
-       return irq_map[virq].hwirq;
+       struct irq_data *irq_data = irq_get_irq_data(virq);
+       return WARN_ON(!irq_data) ? 0 : irq_data->hwirq;
 }
 EXPORT_SYMBOL_GPL(virq_to_hw);
 
-bool virq_is_host(unsigned int virq, struct irq_host *host)
-{
-       return irq_map[virq].host == host;
-}
-EXPORT_SYMBOL_GPL(virq_is_host);
-
-static int default_irq_host_match(struct irq_host *h, struct device_node *np)
-{
-       return h->of_node != NULL && h->of_node == np;
-}
-
-struct irq_host *irq_alloc_host(struct device_node *of_node,
-                               unsigned int revmap_type,
-                               unsigned int revmap_arg,
-                               struct irq_host_ops *ops,
-                               irq_hw_number_t inval_irq)
-{
-       struct irq_host *host;
-       unsigned int size = sizeof(struct irq_host);
-       unsigned int i;
-       unsigned int *rmap;
-       unsigned long flags;
-
-       /* Allocate structure and revmap table if using linear mapping */
-       if (revmap_type == IRQ_HOST_MAP_LINEAR)
-               size += revmap_arg * sizeof(unsigned int);
-       host = kzalloc(size, GFP_KERNEL);
-       if (host == NULL)
-               return NULL;
-
-       /* Fill structure */
-       host->revmap_type = revmap_type;
-       host->inval_irq = inval_irq;
-       host->ops = ops;
-       host->of_node = of_node_get(of_node);
-
-       if (host->ops->match == NULL)
-               host->ops->match = default_irq_host_match;
-
-       raw_spin_lock_irqsave(&irq_big_lock, flags);
-
-       /* If it's a legacy controller, check for duplicates and
-        * mark it as allocated (we use irq 0 host pointer for that
-        */
-       if (revmap_type == IRQ_HOST_MAP_LEGACY) {
-               if (irq_map[0].host != NULL) {
-                       raw_spin_unlock_irqrestore(&irq_big_lock, flags);
-                       of_node_put(host->of_node);
-                       kfree(host);
-                       return NULL;
-               }
-               irq_map[0].host = host;
-       }
-
-       list_add(&host->link, &irq_hosts);
-       raw_spin_unlock_irqrestore(&irq_big_lock, flags);
-
-       /* Additional setups per revmap type */
-       switch(revmap_type) {
-       case IRQ_HOST_MAP_LEGACY:
-               /* 0 is always the invalid number for legacy */
-               host->inval_irq = 0;
-               /* setup us as the host for all legacy interrupts */
-               for (i = 1; i < NUM_ISA_INTERRUPTS; i++) {
-                       irq_map[i].hwirq = i;
-                       smp_wmb();
-                       irq_map[i].host = host;
-                       smp_wmb();
-
-                       /* Legacy flags are left to default at this point,
-                        * one can then use irq_create_mapping() to
-                        * explicitly change them
-                        */
-                       ops->map(host, i, i);
-
-                       /* Clear norequest flags */
-                       irq_clear_status_flags(i, IRQ_NOREQUEST);
-               }
-               break;
-       case IRQ_HOST_MAP_LINEAR:
-               rmap = (unsigned int *)(host + 1);
-               for (i = 0; i < revmap_arg; i++)
-                       rmap[i] = NO_IRQ;
-               host->revmap_data.linear.size = revmap_arg;
-               smp_wmb();
-               host->revmap_data.linear.revmap = rmap;
-               break;
-       case IRQ_HOST_MAP_TREE:
-               INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL);
-               break;
-       default:
-               break;
-       }
-
-       pr_debug("irq: Allocated host of type %d @0x%p\n", revmap_type, host);
-
-       return host;
-}
-
-struct irq_host *irq_find_host(struct device_node *node)
-{
-       struct irq_host *h, *found = NULL;
-       unsigned long flags;
-
-       /* We might want to match the legacy controller last since
-        * it might potentially be set to match all interrupts in
-        * the absence of a device node. This isn't a problem so far
-        * yet though...
-        */
-       raw_spin_lock_irqsave(&irq_big_lock, flags);
-       list_for_each_entry(h, &irq_hosts, link)
-               if (h->ops->match(h, node)) {
-                       found = h;
-                       break;
-               }
-       raw_spin_unlock_irqrestore(&irq_big_lock, flags);
-       return found;
-}
-EXPORT_SYMBOL_GPL(irq_find_host);
-
-void irq_set_default_host(struct irq_host *host)
-{
-       pr_debug("irq: Default host set to @0x%p\n", host);
-
-       irq_default_host = host;
-}
-
-void irq_set_virq_count(unsigned int count)
-{
-       pr_debug("irq: Trying to set virq count to %d\n", count);
-
-       BUG_ON(count < NUM_ISA_INTERRUPTS);
-       if (count < NR_IRQS)
-               irq_virq_count = count;
-}
-
-static int irq_setup_virq(struct irq_host *host, unsigned int virq,
-                           irq_hw_number_t hwirq)
-{
-       int res;
-
-       res = irq_alloc_desc_at(virq, 0);
-       if (res != virq) {
-               pr_debug("irq: -> allocating desc failed\n");
-               goto error;
-       }
-
-       /* map it */
-       smp_wmb();
-       irq_map[virq].hwirq = hwirq;
-       smp_mb();
-
-       if (host->ops->map(host, virq, hwirq)) {
-               pr_debug("irq: -> mapping failed, freeing\n");
-               goto errdesc;
-       }
-
-       irq_clear_status_flags(virq, IRQ_NOREQUEST);
-
-       return 0;
-
-errdesc:
-       irq_free_descs(virq, 1);
-error:
-       irq_free_virt(virq, 1);
-       return -1;
-}
-
-unsigned int irq_create_direct_mapping(struct irq_host *host)
-{
-       unsigned int virq;
-
-       if (host == NULL)
-               host = irq_default_host;
-
-       BUG_ON(host == NULL);
-       WARN_ON(host->revmap_type != IRQ_HOST_MAP_NOMAP);
-
-       virq = irq_alloc_virt(host, 1, 0);
-       if (virq == NO_IRQ) {
-               pr_debug("irq: create_direct virq allocation failed\n");
-               return NO_IRQ;
-       }
-
-       pr_debug("irq: create_direct obtained virq %d\n", virq);
-
-       if (irq_setup_virq(host, virq, virq))
-               return NO_IRQ;
-
-       return virq;
-}
-
-unsigned int irq_create_mapping(struct irq_host *host,
-                               irq_hw_number_t hwirq)
-{
-       unsigned int virq, hint;
-
-       pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", host, hwirq);
-
-       /* Look for default host if nececssary */
-       if (host == NULL)
-               host = irq_default_host;
-       if (host == NULL) {
-               printk(KERN_WARNING "irq_create_mapping called for"
-                      " NULL host, hwirq=%lx\n", hwirq);
-               WARN_ON(1);
-               return NO_IRQ;
-       }
-       pr_debug("irq: -> using host @%p\n", host);
-
-       /* Check if mapping already exists */
-       virq = irq_find_mapping(host, hwirq);
-       if (virq != NO_IRQ) {
-               pr_debug("irq: -> existing mapping on virq %d\n", virq);
-               return virq;
-       }
-
-       /* Get a virtual interrupt number */
-       if (host->revmap_type == IRQ_HOST_MAP_LEGACY) {
-               /* Handle legacy */
-               virq = (unsigned int)hwirq;
-               if (virq == 0 || virq >= NUM_ISA_INTERRUPTS)
-                       return NO_IRQ;
-               return virq;
-       } else {
-               /* Allocate a virtual interrupt number */
-               hint = hwirq % irq_virq_count;
-               virq = irq_alloc_virt(host, 1, hint);
-               if (virq == NO_IRQ) {
-                       pr_debug("irq: -> virq allocation failed\n");
-                       return NO_IRQ;
-               }
-       }
-
-       if (irq_setup_virq(host, virq, hwirq))
-               return NO_IRQ;
-
-       pr_debug("irq: irq %lu on host %s mapped to virtual irq %u\n",
-               hwirq, host->of_node ? host->of_node->full_name : "null", virq);
-
-       return virq;
-}
-EXPORT_SYMBOL_GPL(irq_create_mapping);
-
-unsigned int irq_create_of_mapping(struct device_node *controller,
-                                  const u32 *intspec, unsigned int intsize)
-{
-       struct irq_host *host;
-       irq_hw_number_t hwirq;
-       unsigned int type = IRQ_TYPE_NONE;
-       unsigned int virq;
-
-       if (controller == NULL)
-               host = irq_default_host;
-       else
-               host = irq_find_host(controller);
-       if (host == NULL) {
-               printk(KERN_WARNING "irq: no irq host found for %s !\n",
-                      controller->full_name);
-               return NO_IRQ;
-       }
-
-       /* If host has no translation, then we assume interrupt line */
-       if (host->ops->xlate == NULL)
-               hwirq = intspec[0];
-       else {
-               if (host->ops->xlate(host, controller, intspec, intsize,
-                                    &hwirq, &type))
-                       return NO_IRQ;
-       }
-
-       /* Create mapping */
-       virq = irq_create_mapping(host, hwirq);
-       if (virq == NO_IRQ)
-               return virq;
-
-       /* Set type if specified and different than the current one */
-       if (type != IRQ_TYPE_NONE &&
-           type != (irqd_get_trigger_type(irq_get_irq_data(virq))))
-               irq_set_irq_type(virq, type);
-       return virq;
-}
-EXPORT_SYMBOL_GPL(irq_create_of_mapping);
-
-void irq_dispose_mapping(unsigned int virq)
-{
-       struct irq_host *host;
-       irq_hw_number_t hwirq;
-
-       if (virq == NO_IRQ)
-               return;
-
-       host = irq_map[virq].host;
-       if (WARN_ON(host == NULL))
-               return;
-
-       /* Never unmap legacy interrupts */
-       if (host->revmap_type == IRQ_HOST_MAP_LEGACY)
-               return;
-
-       irq_set_status_flags(virq, IRQ_NOREQUEST);
-
-       /* remove chip and handler */
-       irq_set_chip_and_handler(virq, NULL, NULL);
-
-       /* Make sure it's completed */
-       synchronize_irq(virq);
-
-       /* Tell the PIC about it */
-       if (host->ops->unmap)
-               host->ops->unmap(host, virq);
-       smp_mb();
-
-       /* Clear reverse map */
-       hwirq = irq_map[virq].hwirq;
-       switch(host->revmap_type) {
-       case IRQ_HOST_MAP_LINEAR:
-               if (hwirq < host->revmap_data.linear.size)
-                       host->revmap_data.linear.revmap[hwirq] = NO_IRQ;
-               break;
-       case IRQ_HOST_MAP_TREE:
-               mutex_lock(&revmap_trees_mutex);
-               radix_tree_delete(&host->revmap_data.tree, hwirq);
-               mutex_unlock(&revmap_trees_mutex);
-               break;
-       }
-
-       /* Destroy map */
-       smp_mb();
-       irq_map[virq].hwirq = host->inval_irq;
-
-       irq_free_descs(virq, 1);
-       /* Free it */
-       irq_free_virt(virq, 1);
-}
-EXPORT_SYMBOL_GPL(irq_dispose_mapping);
-
-unsigned int irq_find_mapping(struct irq_host *host,
-                             irq_hw_number_t hwirq)
-{
-       unsigned int i;
-       unsigned int hint = hwirq % irq_virq_count;
-
-       /* Look for default host if nececssary */
-       if (host == NULL)
-               host = irq_default_host;
-       if (host == NULL)
-               return NO_IRQ;
-
-       /* legacy -> bail early */
-       if (host->revmap_type == IRQ_HOST_MAP_LEGACY)
-               return hwirq;
-
-       /* Slow path does a linear search of the map */
-       if (hint < NUM_ISA_INTERRUPTS)
-               hint = NUM_ISA_INTERRUPTS;
-       i = hint;
-       do  {
-               if (irq_map[i].host == host &&
-                   irq_map[i].hwirq == hwirq)
-                       return i;
-               i++;
-               if (i >= irq_virq_count)
-                       i = NUM_ISA_INTERRUPTS;
-       } while(i != hint);
-       return NO_IRQ;
-}
-EXPORT_SYMBOL_GPL(irq_find_mapping);
-
 #ifdef CONFIG_SMP
 int irq_choose_cpu(const struct cpumask *mask)
 {
@@ -929,232 +539,11 @@ int irq_choose_cpu(const struct cpumask *mask)
 }
 #endif
 
-unsigned int irq_radix_revmap_lookup(struct irq_host *host,
-                                    irq_hw_number_t hwirq)
-{
-       struct irq_map_entry *ptr;
-       unsigned int virq;
-
-       if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_TREE))
-               return irq_find_mapping(host, hwirq);
-
-       /*
-        * The ptr returned references the static global irq_map.
-        * but freeing an irq can delete nodes along the path to
-        * do the lookup via call_rcu.
-        */
-       rcu_read_lock();
-       ptr = radix_tree_lookup(&host->revmap_data.tree, hwirq);
-       rcu_read_unlock();
-
-       /*
-        * If found in radix tree, then fine.
-        * Else fallback to linear lookup - this should not happen in practice
-        * as it means that we failed to insert the node in the radix tree.
-        */
-       if (ptr)
-               virq = ptr - irq_map;
-       else
-               virq = irq_find_mapping(host, hwirq);
-
-       return virq;
-}
-
-void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
-                            irq_hw_number_t hwirq)
-{
-       if (WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE))
-               return;
-
-       if (virq != NO_IRQ) {
-               mutex_lock(&revmap_trees_mutex);
-               radix_tree_insert(&host->revmap_data.tree, hwirq,
-                                 &irq_map[virq]);
-               mutex_unlock(&revmap_trees_mutex);
-       }
-}
-
-unsigned int irq_linear_revmap(struct irq_host *host,
-                              irq_hw_number_t hwirq)
-{
-       unsigned int *revmap;
-
-       if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_LINEAR))
-               return irq_find_mapping(host, hwirq);
-
-       /* Check revmap bounds */
-       if (unlikely(hwirq >= host->revmap_data.linear.size))
-               return irq_find_mapping(host, hwirq);
-
-       /* Check if revmap was allocated */
-       revmap = host->revmap_data.linear.revmap;
-       if (unlikely(revmap == NULL))
-               return irq_find_mapping(host, hwirq);
-
-       /* Fill up revmap with slow path if no mapping found */
-       if (unlikely(revmap[hwirq] == NO_IRQ))
-               revmap[hwirq] = irq_find_mapping(host, hwirq);
-
-       return revmap[hwirq];
-}
-
-unsigned int irq_alloc_virt(struct irq_host *host,
-                           unsigned int count,
-                           unsigned int hint)
-{
-       unsigned long flags;
-       unsigned int i, j, found = NO_IRQ;
-
-       if (count == 0 || count > (irq_virq_count - NUM_ISA_INTERRUPTS))
-               return NO_IRQ;
-
-       raw_spin_lock_irqsave(&irq_big_lock, flags);
-
-       /* Use hint for 1 interrupt if any */
-       if (count == 1 && hint >= NUM_ISA_INTERRUPTS &&
-           hint < irq_virq_count && irq_map[hint].host == NULL) {
-               found = hint;
-               goto hint_found;
-       }
-
-       /* Look for count consecutive numbers in the allocatable
-        * (non-legacy) space
-        */
-       for (i = NUM_ISA_INTERRUPTS, j = 0; i < irq_virq_count; i++) {
-               if (irq_map[i].host != NULL)
-                       j = 0;
-               else
-                       j++;
-
-               if (j == count) {
-                       found = i - count + 1;
-                       break;
-               }
-       }
-       if (found == NO_IRQ) {
-               raw_spin_unlock_irqrestore(&irq_big_lock, flags);
-               return NO_IRQ;
-       }
- hint_found:
-       for (i = found; i < (found + count); i++) {
-               irq_map[i].hwirq = host->inval_irq;
-               smp_wmb();
-               irq_map[i].host = host;
-       }
-       raw_spin_unlock_irqrestore(&irq_big_lock, flags);
-       return found;
-}
-
-void irq_free_virt(unsigned int virq, unsigned int count)
-{
-       unsigned long flags;
-       unsigned int i;
-
-       WARN_ON (virq < NUM_ISA_INTERRUPTS);
-       WARN_ON (count == 0 || (virq + count) > irq_virq_count);
-
-       if (virq < NUM_ISA_INTERRUPTS) {
-               if (virq + count < NUM_ISA_INTERRUPTS)
-                       return;
-               count  =- NUM_ISA_INTERRUPTS - virq;
-               virq = NUM_ISA_INTERRUPTS;
-       }
-
-       if (count > irq_virq_count || virq > irq_virq_count - count) {
-               if (virq > irq_virq_count)
-                       return;
-               count = irq_virq_count - virq;
-       }
-
-       raw_spin_lock_irqsave(&irq_big_lock, flags);
-       for (i = virq; i < (virq + count); i++) {
-               struct irq_host *host;
-
-               host = irq_map[i].host;
-               irq_map[i].hwirq = host->inval_irq;
-               smp_wmb();
-               irq_map[i].host = NULL;
-       }
-       raw_spin_unlock_irqrestore(&irq_big_lock, flags);
-}
-
 int arch_early_irq_init(void)
 {
        return 0;
 }
 
-#ifdef CONFIG_VIRQ_DEBUG
-static int virq_debug_show(struct seq_file *m, void *private)
-{
-       unsigned long flags;
-       struct irq_desc *desc;
-       const char *p;
-       static const char none[] = "none";
-       void *data;
-       int i;
-
-       seq_printf(m, "%-5s  %-7s  %-15s  %-18s  %s\n", "virq", "hwirq",
-                     "chip name", "chip data", "host name");
-
-       for (i = 1; i < nr_irqs; i++) {
-               desc = irq_to_desc(i);
-               if (!desc)
-                       continue;
-
-               raw_spin_lock_irqsave(&desc->lock, flags);
-
-               if (desc->action && desc->action->handler) {
-                       struct irq_chip *chip;
-
-                       seq_printf(m, "%5d  ", i);
-                       seq_printf(m, "0x%05lx  ", irq_map[i].hwirq);
-
-                       chip = irq_desc_get_chip(desc);
-                       if (chip && chip->name)
-                               p = chip->name;
-                       else
-                               p = none;
-                       seq_printf(m, "%-15s  ", p);
-
-                       data = irq_desc_get_chip_data(desc);
-                       seq_printf(m, "0x%16p  ", data);
-
-                       if (irq_map[i].host && irq_map[i].host->of_node)
-                               p = irq_map[i].host->of_node->full_name;
-                       else
-                               p = none;
-                       seq_printf(m, "%s\n", p);
-               }
-
-               raw_spin_unlock_irqrestore(&desc->lock, flags);
-       }
-
-       return 0;
-}
-
-static int virq_debug_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, virq_debug_show, inode->i_private);
-}
-
-static const struct file_operations virq_debug_fops = {
-       .open = virq_debug_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
-
-static int __init irq_debugfs_init(void)
-{
-       if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root,
-                                NULL, &virq_debug_fops) == NULL)
-               return -ENOMEM;
-
-       return 0;
-}
-__initcall(irq_debugfs_init);
-#endif /* CONFIG_VIRQ_DEBUG */
-
 #ifdef CONFIG_PPC64
 static int __init setup_noirqdistrib(char *str)
 {
index 9f09319..ca3a062 100644 (file)
@@ -21,7 +21,7 @@
 #include <asm/prom.h>
 
 static struct device_node *cpld_pic_node;
-static struct irq_host *cpld_pic_host;
+static struct irq_domain *cpld_pic_host;
 
 /*
  * Bits to ignore in the misc_status register
@@ -123,13 +123,13 @@ cpld_pic_cascade(unsigned int irq, struct irq_desc *desc)
 }
 
 static int
-cpld_pic_host_match(struct irq_host *h, struct device_node *node)
+cpld_pic_host_match(struct irq_domain *h, struct device_node *node)
 {
        return cpld_pic_node == node;
 }
 
 static int
-cpld_pic_host_map(struct irq_host *h, unsigned int virq,
+cpld_pic_host_map(struct irq_domain *h, unsigned int virq,
                             irq_hw_number_t hw)
 {
        irq_set_status_flags(virq, IRQ_LEVEL);
@@ -137,8 +137,7 @@ cpld_pic_host_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static struct
-irq_host_ops cpld_pic_host_ops = {
+static const struct irq_domain_ops cpld_pic_host_ops = {
        .match = cpld_pic_host_match,
        .map = cpld_pic_host_map,
 };
@@ -191,8 +190,7 @@ mpc5121_ads_cpld_pic_init(void)
 
        cpld_pic_node = of_node_get(np);
 
-       cpld_pic_host =
-           irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, 16, &cpld_pic_host_ops, 16);
+       cpld_pic_host = irq_domain_add_linear(np, 16, &cpld_pic_host_ops, NULL);
        if (!cpld_pic_host) {
                printk(KERN_ERR "CPLD PIC: failed to allocate irq host!\n");
                goto end;
index 96f85e5..17d91b7 100644 (file)
@@ -45,7 +45,7 @@ static struct of_device_id mpc5200_gpio_ids[] __initdata = {
 struct media5200_irq {
        void __iomem *regs;
        spinlock_t lock;
-       struct irq_host *irqhost;
+       struct irq_domain *irqhost;
 };
 struct media5200_irq media5200_irq;
 
@@ -112,7 +112,7 @@ void media5200_irq_cascade(unsigned int virq, struct irq_desc *desc)
        raw_spin_unlock(&desc->lock);
 }
 
-static int media5200_irq_map(struct irq_host *h, unsigned int virq,
+static int media5200_irq_map(struct irq_domain *h, unsigned int virq,
                             irq_hw_number_t hw)
 {
        pr_debug("%s: h=%p, virq=%i, hwirq=%i\n", __func__, h, virq, (int)hw);
@@ -122,7 +122,7 @@ static int media5200_irq_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static int media5200_irq_xlate(struct irq_host *h, struct device_node *ct,
+static int media5200_irq_xlate(struct irq_domain *h, struct device_node *ct,
                                 const u32 *intspec, unsigned int intsize,
                                 irq_hw_number_t *out_hwirq,
                                 unsigned int *out_flags)
@@ -136,7 +136,7 @@ static int media5200_irq_xlate(struct irq_host *h, struct device_node *ct,
        return 0;
 }
 
-static struct irq_host_ops media5200_irq_ops = {
+static const struct irq_domain_ops media5200_irq_ops = {
        .map = media5200_irq_map,
        .xlate = media5200_irq_xlate,
 };
@@ -173,15 +173,12 @@ static void __init media5200_init_irq(void)
 
        spin_lock_init(&media5200_irq.lock);
 
-       media5200_irq.irqhost = irq_alloc_host(fpga_np, IRQ_HOST_MAP_LINEAR,
-                                              MEDIA5200_NUM_IRQS,
-                                              &media5200_irq_ops, -1);
+       media5200_irq.irqhost = irq_domain_add_linear(fpga_np,
+                       MEDIA5200_NUM_IRQS, &media5200_irq_ops, &media5200_irq);
        if (!media5200_irq.irqhost)
                goto out;
        pr_debug("%s: allocated irqhost\n", __func__);
 
-       media5200_irq.irqhost->host_data = &media5200_irq;
-
        irq_set_handler_data(cascade_virq, &media5200_irq);
        irq_set_chained_handler(cascade_virq, media5200_irq_cascade);
 
index f94f06e..028470b 100644 (file)
@@ -81,7 +81,7 @@ MODULE_LICENSE("GPL");
  * @regs: virtual address of GPT registers
  * @lock: spinlock to coordinate between different functions.
  * @gc: gpio_chip instance structure; used when GPIO is enabled
- * @irqhost: Pointer to irq_host instance; used when IRQ mode is supported
+ * @irqhost: Pointer to irq_domain instance; used when IRQ mode is supported
  * @wdt_mode: only relevant for gpt0: bit 0 (MPC52xx_GPT_CAN_WDT) indicates
  *   if the gpt may be used as wdt, bit 1 (MPC52xx_GPT_IS_WDT) indicates
  *   if the timer is actively used as wdt which blocks gpt functions
@@ -91,7 +91,7 @@ struct mpc52xx_gpt_priv {
        struct device *dev;
        struct mpc52xx_gpt __iomem *regs;
        spinlock_t lock;
-       struct irq_host *irqhost;
+       struct irq_domain *irqhost;
        u32 ipb_freq;
        u8 wdt_mode;
 
@@ -204,7 +204,7 @@ void mpc52xx_gpt_irq_cascade(unsigned int virq, struct irq_desc *desc)
        }
 }
 
-static int mpc52xx_gpt_irq_map(struct irq_host *h, unsigned int virq,
+static int mpc52xx_gpt_irq_map(struct irq_domain *h, unsigned int virq,
                               irq_hw_number_t hw)
 {
        struct mpc52xx_gpt_priv *gpt = h->host_data;
@@ -216,7 +216,7 @@ static int mpc52xx_gpt_irq_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static int mpc52xx_gpt_irq_xlate(struct irq_host *h, struct device_node *ct,
+static int mpc52xx_gpt_irq_xlate(struct irq_domain *h, struct device_node *ct,
                                 const u32 *intspec, unsigned int intsize,
                                 irq_hw_number_t *out_hwirq,
                                 unsigned int *out_flags)
@@ -236,7 +236,7 @@ static int mpc52xx_gpt_irq_xlate(struct irq_host *h, struct device_node *ct,
        return 0;
 }
 
-static struct irq_host_ops mpc52xx_gpt_irq_ops = {
+static const struct irq_domain_ops mpc52xx_gpt_irq_ops = {
        .map = mpc52xx_gpt_irq_map,
        .xlate = mpc52xx_gpt_irq_xlate,
 };
@@ -252,14 +252,12 @@ mpc52xx_gpt_irq_setup(struct mpc52xx_gpt_priv *gpt, struct device_node *node)
        if (!cascade_virq)
                return;
 
-       gpt->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, 1,
-                                     &mpc52xx_gpt_irq_ops, -1);
+       gpt->irqhost = irq_domain_add_linear(node, 1, &mpc52xx_gpt_irq_ops, gpt);
        if (!gpt->irqhost) {
-               dev_err(gpt->dev, "irq_alloc_host() failed\n");
+               dev_err(gpt->dev, "irq_domain_add_linear() failed\n");
                return;
        }
 
-       gpt->irqhost->host_data = gpt;
        irq_set_handler_data(cascade_virq, gpt);
        irq_set_chained_handler(cascade_virq, mpc52xx_gpt_irq_cascade);
 
index 1a9a495..8520b58 100644 (file)
@@ -132,7 +132,7 @@ static struct of_device_id mpc52xx_sdma_ids[] __initdata = {
 
 static struct mpc52xx_intr __iomem *intr;
 static struct mpc52xx_sdma __iomem *sdma;
-static struct irq_host *mpc52xx_irqhost = NULL;
+static struct irq_domain *mpc52xx_irqhost = NULL;
 
 static unsigned char mpc52xx_map_senses[4] = {
        IRQ_TYPE_LEVEL_HIGH,
@@ -301,7 +301,7 @@ static int mpc52xx_is_extirq(int l1, int l2)
 /**
  * mpc52xx_irqhost_xlate - translate virq# from device tree interrupts property
  */
-static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct,
+static int mpc52xx_irqhost_xlate(struct irq_domain *h, struct device_node *ct,
                                 const u32 *intspec, unsigned int intsize,
                                 irq_hw_number_t *out_hwirq,
                                 unsigned int *out_flags)
@@ -335,7 +335,7 @@ static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct,
 /**
  * mpc52xx_irqhost_map - Hook to map from virq to an irq_chip structure
  */
-static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq,
+static int mpc52xx_irqhost_map(struct irq_domain *h, unsigned int virq,
                               irq_hw_number_t irq)
 {
        int l1irq;
@@ -384,7 +384,7 @@ static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static struct irq_host_ops mpc52xx_irqhost_ops = {
+static const struct irq_domain_ops mpc52xx_irqhost_ops = {
        .xlate = mpc52xx_irqhost_xlate,
        .map = mpc52xx_irqhost_map,
 };
@@ -444,9 +444,9 @@ void __init mpc52xx_init_irq(void)
         * As last step, add an irq host to translate the real
         * hw irq information provided by the ofw to linux virq
         */
-       mpc52xx_irqhost = irq_alloc_host(picnode, IRQ_HOST_MAP_LINEAR,
+       mpc52xx_irqhost = irq_domain_add_linear(picnode,
                                         MPC52xx_IRQ_HIGHTESTHWIRQ,
-                                        &mpc52xx_irqhost_ops, -1);
+                                        &mpc52xx_irqhost_ops, NULL);
 
        if (!mpc52xx_irqhost)
                panic(__FILE__ ": Cannot allocate the IRQ host\n");
index 8ccf9ed..328d221 100644 (file)
@@ -29,7 +29,7 @@ static DEFINE_RAW_SPINLOCK(pci_pic_lock);
 
 struct pq2ads_pci_pic {
        struct device_node *node;
-       struct irq_host *host;
+       struct irq_domain *host;
 
        struct {
                u32 stat;
@@ -103,7 +103,7 @@ static void pq2ads_pci_irq_demux(unsigned int irq, struct irq_desc *desc)
        }
 }
 
-static int pci_pic_host_map(struct irq_host *h, unsigned int virq,
+static int pci_pic_host_map(struct irq_domain *h, unsigned int virq,
                            irq_hw_number_t hw)
 {
        irq_set_status_flags(virq, IRQ_LEVEL);
@@ -112,14 +112,14 @@ static int pci_pic_host_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static struct irq_host_ops pci_pic_host_ops = {
+static const struct irq_domain_ops pci_pic_host_ops = {
        .map = pci_pic_host_map,
 };
 
 int __init pq2ads_pci_init_irq(void)
 {
        struct pq2ads_pci_pic *priv;
-       struct irq_host *host;
+       struct irq_domain *host;
        struct device_node *np;
        int ret = -ENODEV;
        int irq;
@@ -156,17 +156,13 @@ int __init pq2ads_pci_init_irq(void)
        out_be32(&priv->regs->mask, ~0);
        mb();
 
-       host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, NUM_IRQS,
-                             &pci_pic_host_ops, NUM_IRQS);
+       host = irq_domain_add_linear(np, NUM_IRQS, &pci_pic_host_ops, priv);
        if (!host) {
                ret = -ENOMEM;
                goto out_unmap_regs;
        }
 
-       host->host_data = priv;
-
        priv->host = host;
-       host->host_data = priv;
        irq_set_handler_data(irq, priv);
        irq_set_chained_handler(irq, pq2ads_pci_irq_demux);
 
index 12cb9bb..3bbbf74 100644 (file)
@@ -51,7 +51,7 @@ static struct socrates_fpga_irq_info fpga_irqs[SOCRATES_FPGA_NUM_IRQS] = {
 static DEFINE_RAW_SPINLOCK(socrates_fpga_pic_lock);
 
 static void __iomem *socrates_fpga_pic_iobase;
-static struct irq_host *socrates_fpga_pic_irq_host;
+static struct irq_domain *socrates_fpga_pic_irq_host;
 static unsigned int socrates_fpga_irqs[3];
 
 static inline uint32_t socrates_fpga_pic_read(int reg)
@@ -227,7 +227,7 @@ static struct irq_chip socrates_fpga_pic_chip = {
        .irq_set_type   = socrates_fpga_pic_set_type,
 };
 
-static int socrates_fpga_pic_host_map(struct irq_host *h, unsigned int virq,
+static int socrates_fpga_pic_host_map(struct irq_domain *h, unsigned int virq,
                irq_hw_number_t hwirq)
 {
        /* All interrupts are LEVEL sensitive */
@@ -238,7 +238,7 @@ static int socrates_fpga_pic_host_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static int socrates_fpga_pic_host_xlate(struct irq_host *h,
+static int socrates_fpga_pic_host_xlate(struct irq_domain *h,
                struct device_node *ct, const u32 *intspec, unsigned int intsize,
                irq_hw_number_t *out_hwirq, unsigned int *out_flags)
 {
@@ -269,7 +269,7 @@ static int socrates_fpga_pic_host_xlate(struct irq_host *h,
        return 0;
 }
 
-static struct irq_host_ops socrates_fpga_pic_host_ops = {
+static const struct irq_domain_ops socrates_fpga_pic_host_ops = {
        .map    = socrates_fpga_pic_host_map,
        .xlate  = socrates_fpga_pic_host_xlate,
 };
@@ -279,10 +279,9 @@ void socrates_fpga_pic_init(struct device_node *pic)
        unsigned long flags;
        int i;
 
-       /* Setup an irq_host structure */
-       socrates_fpga_pic_irq_host = irq_alloc_host(pic, IRQ_HOST_MAP_LINEAR,
-                       SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops,
-                       SOCRATES_FPGA_NUM_IRQS);
+       /* Setup an irq_domain structure */
+       socrates_fpga_pic_irq_host = irq_domain_add_linear(pic,
+                   SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops, NULL);
        if (socrates_fpga_pic_irq_host == NULL) {
                pr_err("FPGA PIC: Unable to allocate host\n");
                return;
index 94594e5..af3fd69 100644 (file)
@@ -50,7 +50,7 @@
 static DEFINE_RAW_SPINLOCK(gef_pic_lock);
 
 static void __iomem *gef_pic_irq_reg_base;
-static struct irq_host *gef_pic_irq_host;
+static struct irq_domain *gef_pic_irq_host;
 static int gef_pic_cascade_irq;
 
 /*
@@ -153,7 +153,7 @@ static struct irq_chip gef_pic_chip = {
 /* When an interrupt is being configured, this call allows some flexibilty
  * in deciding which irq_chip structure is used
  */
-static int gef_pic_host_map(struct irq_host *h, unsigned int virq,
+static int gef_pic_host_map(struct irq_domain *h, unsigned int virq,
                          irq_hw_number_t hwirq)
 {
        /* All interrupts are LEVEL sensitive */
@@ -163,7 +163,7 @@ static int gef_pic_host_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static int gef_pic_host_xlate(struct irq_host *h, struct device_node *ct,
+static int gef_pic_host_xlate(struct irq_domain *h, struct device_node *ct,
                            const u32 *intspec, unsigned int intsize,
                            irq_hw_number_t *out_hwirq, unsigned int *out_flags)
 {
@@ -177,7 +177,7 @@ static int gef_pic_host_xlate(struct irq_host *h, struct device_node *ct,
        return 0;
 }
 
-static struct irq_host_ops gef_pic_host_ops = {
+static const struct irq_domain_ops gef_pic_host_ops = {
        .map    = gef_pic_host_map,
        .xlate  = gef_pic_host_xlate,
 };
@@ -211,10 +211,9 @@ void __init gef_pic_init(struct device_node *np)
                return;
        }
 
-       /* Setup an irq_host structure */
-       gef_pic_irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
-                                         GEF_PIC_NUM_IRQS,
-                                         &gef_pic_host_ops, NO_IRQ);
+       /* Setup an irq_domain structure */
+       gef_pic_irq_host = irq_domain_add_linear(np, GEF_PIC_NUM_IRQS,
+                                         &gef_pic_host_ops, NULL);
        if (gef_pic_irq_host == NULL)
                return;
 
index 40a6e34..db360fc 100644 (file)
@@ -67,7 +67,7 @@
 
 
 struct axon_msic {
-       struct irq_host *irq_host;
+       struct irq_domain *irq_domain;
        __le32 *fifo_virt;
        dma_addr_t fifo_phys;
        dcr_host_t dcr_host;
@@ -152,7 +152,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
 
 static struct axon_msic *find_msi_translator(struct pci_dev *dev)
 {
-       struct irq_host *irq_host;
+       struct irq_domain *irq_domain;
        struct device_node *dn, *tmp;
        const phandle *ph;
        struct axon_msic *msic = NULL;
@@ -184,14 +184,14 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev)
                goto out_error;
        }
 
-       irq_host = irq_find_host(dn);
-       if (!irq_host) {
-               dev_dbg(&dev->dev, "axon_msi: no irq_host found for node %s\n",
+       irq_domain = irq_find_host(dn);
+       if (!irq_domain) {
+               dev_dbg(&dev->dev, "axon_msi: no irq_domain found for node %s\n",
                        dn->full_name);
                goto out_error;
        }
 
-       msic = irq_host->host_data;
+       msic = irq_domain->host_data;
 
 out_error:
        of_node_put(dn);
@@ -280,7 +280,7 @@ static int axon_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
        BUILD_BUG_ON(NR_IRQS > 65536);
 
        list_for_each_entry(entry, &dev->msi_list, list) {
-               virq = irq_create_direct_mapping(msic->irq_host);
+               virq = irq_create_direct_mapping(msic->irq_domain);
                if (virq == NO_IRQ) {
                        dev_warn(&dev->dev,
                                 "axon_msi: virq allocation failed!\n");
@@ -318,7 +318,7 @@ static struct irq_chip msic_irq_chip = {
        .name           = "AXON-MSI",
 };
 
-static int msic_host_map(struct irq_host *h, unsigned int virq,
+static int msic_host_map(struct irq_domain *h, unsigned int virq,
                         irq_hw_number_t hw)
 {
        irq_set_chip_data(virq, h->host_data);
@@ -327,7 +327,7 @@ static int msic_host_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static struct irq_host_ops msic_host_ops = {
+static const struct irq_domain_ops msic_host_ops = {
        .map    = msic_host_map,
 };
 
@@ -337,7 +337,7 @@ static void axon_msi_shutdown(struct platform_device *device)
        u32 tmp;
 
        pr_devel("axon_msi: disabling %s\n",
-                 msic->irq_host->of_node->full_name);
+                 msic->irq_domain->of_node->full_name);
        tmp  = dcr_read(msic->dcr_host, MSIC_CTRL_REG);
        tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
        msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
@@ -392,16 +392,13 @@ static int axon_msi_probe(struct platform_device *device)
        }
        memset(msic->fifo_virt, 0xff, MSIC_FIFO_SIZE_BYTES);
 
-       msic->irq_host = irq_alloc_host(dn, IRQ_HOST_MAP_NOMAP,
-                                       NR_IRQS, &msic_host_ops, 0);
-       if (!msic->irq_host) {
-               printk(KERN_ERR "axon_msi: couldn't allocate irq_host for %s\n",
+       msic->irq_domain = irq_domain_add_nomap(dn, &msic_host_ops, msic);
+       if (!msic->irq_domain) {
+               printk(KERN_ERR "axon_msi: couldn't allocate irq_domain for %s\n",
                       dn->full_name);
                goto out_free_fifo;
        }
 
-       msic->irq_host->host_data = msic;
-
        irq_set_handler_data(virq, msic);
        irq_set_chained_handler(virq, axon_msi_cascade);
        pr_devel("axon_msi: irq 0x%x setup for axon_msi\n", virq);
index 55015e1..e5c3a2c 100644 (file)
@@ -34,7 +34,7 @@ static DEFINE_RAW_SPINLOCK(beatic_irq_mask_lock);
 static uint64_t        beatic_irq_mask_enable[(MAX_IRQS+255)/64];
 static uint64_t        beatic_irq_mask_ack[(MAX_IRQS+255)/64];
 
-static struct irq_host *beatic_host;
+static struct irq_domain *beatic_host;
 
 /*
  * In this implementation, "virq" == "IRQ plug number",
@@ -122,7 +122,7 @@ static struct irq_chip beatic_pic = {
  *
  * Note that the number (virq) is already assigned at upper layer.
  */
-static void beatic_pic_host_unmap(struct irq_host *h, unsigned int virq)
+static void beatic_pic_host_unmap(struct irq_domain *h, unsigned int virq)
 {
        beat_destruct_irq_plug(virq);
 }
@@ -133,7 +133,7 @@ static void beatic_pic_host_unmap(struct irq_host *h, unsigned int virq)
  *
  * Note that the number (virq) is already assigned at upper layer.
  */
-static int beatic_pic_host_map(struct irq_host *h, unsigned int virq,
+static int beatic_pic_host_map(struct irq_domain *h, unsigned int virq,
                               irq_hw_number_t hw)
 {
        int64_t err;
@@ -154,7 +154,7 @@ static int beatic_pic_host_map(struct irq_host *h, unsigned int virq,
  * Called from irq_create_of_mapping() only.
  * Note: We have only 1 entry to translate.
  */
-static int beatic_pic_host_xlate(struct irq_host *h, struct device_node *ct,
+static int beatic_pic_host_xlate(struct irq_domain *h, struct device_node *ct,
                                 const u32 *intspec, unsigned int intsize,
                                 irq_hw_number_t *out_hwirq,
                                 unsigned int *out_flags)
@@ -166,13 +166,13 @@ static int beatic_pic_host_xlate(struct irq_host *h, struct device_node *ct,
        return 0;
 }
 
-static int beatic_pic_host_match(struct irq_host *h, struct device_node *np)
+static int beatic_pic_host_match(struct irq_domain *h, struct device_node *np)
 {
        /* Match all */
        return 1;
 }
 
-static struct irq_host_ops beatic_pic_host_ops = {
+static const struct irq_domain_ops beatic_pic_host_ops = {
        .map = beatic_pic_host_map,
        .unmap = beatic_pic_host_unmap,
        .xlate = beatic_pic_host_xlate,
@@ -239,9 +239,7 @@ void __init beatic_init_IRQ(void)
        ppc_md.get_irq = beatic_get_irq;
 
        /* Allocate an irq host */
-       beatic_host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0,
-                                    &beatic_pic_host_ops,
-                                        0);
+       beatic_host = irq_domain_add_nomap(NULL, &beatic_pic_host_ops, NULL);
        BUG_ON(beatic_host == NULL);
        irq_set_default_host(beatic_host);
 }
index 96a433d..2d42f3b 100644 (file)
@@ -56,7 +56,7 @@ struct iic {
 
 static DEFINE_PER_CPU(struct iic, cpu_iic);
 #define IIC_NODE_COUNT 2
-static struct irq_host *iic_host;
+static struct irq_domain *iic_host;
 
 /* Convert between "pending" bits and hw irq number */
 static irq_hw_number_t iic_pending_to_hwnum(struct cbe_iic_pending_bits bits)
@@ -186,7 +186,7 @@ void iic_message_pass(int cpu, int msg)
        out_be64(&per_cpu(cpu_iic, cpu).regs->generate, (0xf - msg) << 4);
 }
 
-struct irq_host *iic_get_irq_host(int node)
+struct irq_domain *iic_get_irq_host(int node)
 {
        return iic_host;
 }
@@ -222,13 +222,13 @@ void iic_request_IPIs(void)
 #endif /* CONFIG_SMP */
 
 
-static int iic_host_match(struct irq_host *h, struct device_node *node)
+static int iic_host_match(struct irq_domain *h, struct device_node *node)
 {
        return of_device_is_compatible(node,
                                    "IBM,CBEA-Internal-Interrupt-Controller");
 }
 
-static int iic_host_map(struct irq_host *h, unsigned int virq,
+static int iic_host_map(struct irq_domain *h, unsigned int virq,
                        irq_hw_number_t hw)
 {
        switch (hw & IIC_IRQ_TYPE_MASK) {
@@ -245,7 +245,7 @@ static int iic_host_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static int iic_host_xlate(struct irq_host *h, struct device_node *ct,
+static int iic_host_xlate(struct irq_domain *h, struct device_node *ct,
                           const u32 *intspec, unsigned int intsize,
                           irq_hw_number_t *out_hwirq, unsigned int *out_flags)
 
@@ -285,7 +285,7 @@ static int iic_host_xlate(struct irq_host *h, struct device_node *ct,
        return 0;
 }
 
-static struct irq_host_ops iic_host_ops = {
+static const struct irq_domain_ops iic_host_ops = {
        .match = iic_host_match,
        .map = iic_host_map,
        .xlate = iic_host_xlate,
@@ -378,8 +378,8 @@ static int __init setup_iic(void)
 void __init iic_init_IRQ(void)
 {
        /* Setup an irq host data structure */
-       iic_host = irq_alloc_host(NULL, IRQ_HOST_MAP_LINEAR, IIC_SOURCE_COUNT,
-                                 &iic_host_ops, IIC_IRQ_INVALID);
+       iic_host = irq_domain_add_linear(NULL, IIC_SOURCE_COUNT, &iic_host_ops,
+                                        NULL);
        BUG_ON(iic_host == NULL);
        irq_set_default_host(iic_host);
 
index 442c28c..d8b7cc8 100644 (file)
@@ -62,7 +62,7 @@ enum {
 #define SPIDER_IRQ_INVALID     63
 
 struct spider_pic {
-       struct irq_host         *host;
+       struct irq_domain               *host;
        void __iomem            *regs;
        unsigned int            node_id;
 };
@@ -168,7 +168,7 @@ static struct irq_chip spider_pic = {
        .irq_set_type = spider_set_irq_type,
 };
 
-static int spider_host_map(struct irq_host *h, unsigned int virq,
+static int spider_host_map(struct irq_domain *h, unsigned int virq,
                        irq_hw_number_t hw)
 {
        irq_set_chip_data(virq, h->host_data);
@@ -180,7 +180,7 @@ static int spider_host_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static int spider_host_xlate(struct irq_host *h, struct device_node *ct,
+static int spider_host_xlate(struct irq_domain *h, struct device_node *ct,
                           const u32 *intspec, unsigned int intsize,
                           irq_hw_number_t *out_hwirq, unsigned int *out_flags)
 
@@ -194,7 +194,7 @@ static int spider_host_xlate(struct irq_host *h, struct device_node *ct,
        return 0;
 }
 
-static struct irq_host_ops spider_host_ops = {
+static const struct irq_domain_ops spider_host_ops = {
        .map = spider_host_map,
        .xlate = spider_host_xlate,
 };
@@ -299,12 +299,10 @@ static void __init spider_init_one(struct device_node *of_node, int chip,
                panic("spider_pic: can't map registers !");
 
        /* Allocate a host */
-       pic->host = irq_alloc_host(of_node, IRQ_HOST_MAP_LINEAR,
-                                  SPIDER_SRC_COUNT, &spider_host_ops,
-                                  SPIDER_IRQ_INVALID);
+       pic->host = irq_domain_add_linear(of_node, SPIDER_SRC_COUNT,
+                                         &spider_host_ops, pic);
        if (pic->host == NULL)
                panic("spider_pic: can't allocate irq host !");
-       pic->host->host_data = pic;
 
        /* Go through all sources and disable them */
        for (i = 0; i < SPIDER_SRC_COUNT; i++) {
index f61a2dd..53d6eee 100644 (file)
@@ -96,9 +96,9 @@ static struct irq_chip flipper_pic = {
  *
  */
 
-static struct irq_host *flipper_irq_host;
+static struct irq_domain *flipper_irq_host;
 
-static int flipper_pic_map(struct irq_host *h, unsigned int virq,
+static int flipper_pic_map(struct irq_domain *h, unsigned int virq,
                           irq_hw_number_t hwirq)
 {
        irq_set_chip_data(virq, h->host_data);
@@ -107,13 +107,13 @@ static int flipper_pic_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static int flipper_pic_match(struct irq_host *h, struct device_node *np)
+static int flipper_pic_match(struct irq_domain *h, struct device_node *np)
 {
        return 1;
 }
 
 
-static struct irq_host_ops flipper_irq_host_ops = {
+static const struct irq_domain_ops flipper_irq_domain_ops = {
        .map = flipper_pic_map,
        .match = flipper_pic_match,
 };
@@ -130,10 +130,10 @@ static void __flipper_quiesce(void __iomem *io_base)
        out_be32(io_base + FLIPPER_ICR, 0xffffffff);
 }
 
-struct irq_host * __init flipper_pic_init(struct device_node *np)
+struct irq_domain * __init flipper_pic_init(struct device_node *np)
 {
        struct device_node *pi;
-       struct irq_host *irq_host = NULL;
+       struct irq_domain *irq_domain = NULL;
        struct resource res;
        void __iomem *io_base;
        int retval;
@@ -159,17 +159,15 @@ struct irq_host * __init flipper_pic_init(struct device_node *np)
 
        __flipper_quiesce(io_base);
 
-       irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, FLIPPER_NR_IRQS,
-                                 &flipper_irq_host_ops, -1);
-       if (!irq_host) {
-               pr_err("failed to allocate irq_host\n");
+       irq_domain = irq_domain_add_linear(np, FLIPPER_NR_IRQS,
+                                 &flipper_irq_domain_ops, io_base);
+       if (!irq_domain) {
+               pr_err("failed to allocate irq_domain\n");
                return NULL;
        }
 
-       irq_host->host_data = io_base;
-
 out:
-       return irq_host;
+       return irq_domain;
 }
 
 unsigned int flipper_pic_get_irq(void)
index e491917..3006b51 100644 (file)
@@ -89,9 +89,9 @@ static struct irq_chip hlwd_pic = {
  *
  */
 
-static struct irq_host *hlwd_irq_host;
+static struct irq_domain *hlwd_irq_host;
 
-static int hlwd_pic_map(struct irq_host *h, unsigned int virq,
+static int hlwd_pic_map(struct irq_domain *h, unsigned int virq,
                           irq_hw_number_t hwirq)
 {
        irq_set_chip_data(virq, h->host_data);
@@ -100,11 +100,11 @@ static int hlwd_pic_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static struct irq_host_ops hlwd_irq_host_ops = {
+static const struct irq_domain_ops hlwd_irq_domain_ops = {
        .map = hlwd_pic_map,
 };
 
-static unsigned int __hlwd_pic_get_irq(struct irq_host *h)
+static unsigned int __hlwd_pic_get_irq(struct irq_domain *h)
 {
        void __iomem *io_base = h->host_data;
        int irq;
@@ -123,14 +123,14 @@ static void hlwd_pic_irq_cascade(unsigned int cascade_virq,
                                      struct irq_desc *desc)
 {
        struct irq_chip *chip = irq_desc_get_chip(desc);
-       struct irq_host *irq_host = irq_get_handler_data(cascade_virq);
+       struct irq_domain *irq_domain = irq_get_handler_data(cascade_virq);
        unsigned int virq;
 
        raw_spin_lock(&desc->lock);
        chip->irq_mask(&desc->irq_data); /* IRQ_LEVEL */
        raw_spin_unlock(&desc->lock);
 
-       virq = __hlwd_pic_get_irq(irq_host);
+       virq = __hlwd_pic_get_irq(irq_domain);
        if (virq != NO_IRQ)
                generic_handle_irq(virq);
        else
@@ -155,9 +155,9 @@ static void __hlwd_quiesce(void __iomem *io_base)
        out_be32(io_base + HW_BROADWAY_ICR, 0xffffffff);
 }
 
-struct irq_host *hlwd_pic_init(struct device_node *np)
+struct irq_domain *hlwd_pic_init(struct device_node *np)
 {
-       struct irq_host *irq_host;
+       struct irq_domain *irq_domain;
        struct resource res;
        void __iomem *io_base;
        int retval;
@@ -177,15 +177,14 @@ struct irq_host *hlwd_pic_init(struct device_node *np)
 
        __hlwd_quiesce(io_base);
 
-       irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, HLWD_NR_IRQS,
-                                 &hlwd_irq_host_ops, -1);
-       if (!irq_host) {
-               pr_err("failed to allocate irq_host\n");
+       irq_domain = irq_domain_add_linear(np, HLWD_NR_IRQS,
+                                          &hlwd_irq_domain_ops, io_base);
+       if (!irq_domain) {
+               pr_err("failed to allocate irq_domain\n");
                return NULL;
        }
-       irq_host->host_data = io_base;
 
-       return irq_host;
+       return irq_domain;
 }
 
 unsigned int hlwd_pic_get_irq(void)
@@ -200,7 +199,7 @@ unsigned int hlwd_pic_get_irq(void)
 
 void hlwd_pic_probe(void)
 {
-       struct irq_host *host;
+       struct irq_domain *host;
        struct device_node *np;
        const u32 *interrupts;
        int cascade_virq;
index b210345..05ce516 100644 (file)
@@ -342,7 +342,7 @@ unsigned int iSeries_get_irq(void)
 
 #ifdef CONFIG_PCI
 
-static int iseries_irq_host_map(struct irq_host *h, unsigned int virq,
+static int iseries_irq_host_map(struct irq_domain *h, unsigned int virq,
                                irq_hw_number_t hw)
 {
        irq_set_chip_and_handler(virq, &iseries_pic, handle_fasteoi_irq);
@@ -350,13 +350,13 @@ static int iseries_irq_host_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static int iseries_irq_host_match(struct irq_host *h, struct device_node *np)
+static int iseries_irq_host_match(struct irq_domain *h, struct device_node *np)
 {
        /* Match all */
        return 1;
 }
 
-static struct irq_host_ops iseries_irq_host_ops = {
+static const struct irq_domain_ops iseries_irq_domain_ops = {
        .map = iseries_irq_host_map,
        .match = iseries_irq_host_match,
 };
@@ -368,7 +368,7 @@ static struct irq_host_ops iseries_irq_host_ops = {
 void __init iSeries_init_IRQ(void)
 {
        /* Register PCI event handler and open an event path */
-       struct irq_host *host;
+       struct irq_domain *host;
        int ret;
 
        /*
@@ -380,8 +380,7 @@ void __init iSeries_init_IRQ(void)
        /* Create irq host. No need for a revmap since HV will give us
         * back our virtual irq number
         */
-       host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0,
-                             &iseries_irq_host_ops, 0);
+       host = irq_domain_add_nomap(NULL, &iseries_irq_domain_ops, NULL);
        BUG_ON(host == NULL);
        irq_set_default_host(host);
 
index 7761aab..92afc38 100644 (file)
@@ -61,7 +61,7 @@ static DEFINE_RAW_SPINLOCK(pmac_pic_lock);
 static unsigned long ppc_lost_interrupts[NR_MASK_WORDS];
 static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
 static int pmac_irq_cascade = -1;
-static struct irq_host *pmac_pic_host;
+static struct irq_domain *pmac_pic_host;
 
 static void __pmac_retrigger(unsigned int irq_nr)
 {
@@ -268,13 +268,13 @@ static struct irqaction gatwick_cascade_action = {
        .name           = "cascade",
 };
 
-static int pmac_pic_host_match(struct irq_host *h, struct device_node *node)
+static int pmac_pic_host_match(struct irq_domain *h, struct device_node *node)
 {
        /* We match all, we don't always have a node anyway */
        return 1;
 }
 
-static int pmac_pic_host_map(struct irq_host *h, unsigned int virq,
+static int pmac_pic_host_map(struct irq_domain *h, unsigned int virq,
                             irq_hw_number_t hw)
 {
        if (hw >= max_irqs)
@@ -288,21 +288,10 @@ static int pmac_pic_host_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static int pmac_pic_host_xlate(struct irq_host *h, struct device_node *ct,
-                              const u32 *intspec, unsigned int intsize,
-                              irq_hw_number_t *out_hwirq,
-                              unsigned int *out_flags)
-
-{
-       *out_flags = IRQ_TYPE_NONE;
-       *out_hwirq = *intspec;
-       return 0;
-}
-
-static struct irq_host_ops pmac_pic_host_ops = {
+static const struct irq_domain_ops pmac_pic_host_ops = {
        .match = pmac_pic_host_match,
        .map = pmac_pic_host_map,
-       .xlate = pmac_pic_host_xlate,
+       .xlate = irq_domain_xlate_onecell,
 };
 
 static void __init pmac_pic_probe_oldstyle(void)
@@ -352,9 +341,8 @@ static void __init pmac_pic_probe_oldstyle(void)
        /*
         * Allocate an irq host
         */
-       pmac_pic_host = irq_alloc_host(master, IRQ_HOST_MAP_LINEAR, max_irqs,
-                                      &pmac_pic_host_ops,
-                                      max_irqs);
+       pmac_pic_host = irq_domain_add_linear(master, max_irqs,
+                                             &pmac_pic_host_ops, NULL);
        BUG_ON(pmac_pic_host == NULL);
        irq_set_default_host(pmac_pic_host);
 
index 44d7692..a81e5a8 100644 (file)
@@ -125,7 +125,7 @@ static volatile u32 __iomem *psurge_start;
 static int psurge_type = PSURGE_NONE;
 
 /* irq for secondary cpus to report */
-static struct irq_host *psurge_host;
+static struct irq_domain *psurge_host;
 int psurge_secondary_virq;
 
 /*
@@ -176,7 +176,7 @@ static void smp_psurge_cause_ipi(int cpu, unsigned long data)
        psurge_set_ipi(cpu);
 }
 
-static int psurge_host_map(struct irq_host *h, unsigned int virq,
+static int psurge_host_map(struct irq_domain *h, unsigned int virq,
                         irq_hw_number_t hw)
 {
        irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_percpu_irq);
@@ -184,7 +184,7 @@ static int psurge_host_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-struct irq_host_ops psurge_host_ops = {
+static const struct irq_domain_ops psurge_host_ops = {
        .map    = psurge_host_map,
 };
 
@@ -192,8 +192,7 @@ static int psurge_secondary_ipi_init(void)
 {
        int rc = -ENOMEM;
 
-       psurge_host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0,
-               &psurge_host_ops, 0);
+       psurge_host = irq_domain_add_nomap(NULL, &psurge_host_ops, NULL);
 
        if (psurge_host)
                psurge_secondary_virq = irq_create_direct_mapping(psurge_host);
index 617efa1..2a4ff86 100644 (file)
@@ -667,7 +667,7 @@ static void __maybe_unused _dump_mask(struct ps3_private *pd,
 static void dump_bmp(struct ps3_private* pd) {};
 #endif /* defined(DEBUG) */
 
-static int ps3_host_map(struct irq_host *h, unsigned int virq,
+static int ps3_host_map(struct irq_domain *h, unsigned int virq,
        irq_hw_number_t hwirq)
 {
        DBG("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq,
@@ -678,13 +678,13 @@ static int ps3_host_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static int ps3_host_match(struct irq_host *h, struct device_node *np)
+static int ps3_host_match(struct irq_domain *h, struct device_node *np)
 {
        /* Match all */
        return 1;
 }
 
-static struct irq_host_ops ps3_host_ops = {
+static const struct irq_domain_ops ps3_host_ops = {
        .map = ps3_host_map,
        .match = ps3_host_match,
 };
@@ -751,10 +751,9 @@ void __init ps3_init_IRQ(void)
 {
        int result;
        unsigned cpu;
-       struct irq_host *host;
+       struct irq_domain *host;
 
-       host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, &ps3_host_ops,
-               PS3_INVALID_OUTLET);
+       host = irq_domain_add_nomap(NULL, &ps3_host_ops, NULL);
        irq_set_default_host(host);
        irq_set_virq_count(PS3_PLUG_MAX + 1);
 
index 19f353d..cb565bf 100644 (file)
@@ -30,7 +30,7 @@
 static int opb_index = 0;
 
 struct opb_pic {
-       struct irq_host *host;
+       struct irq_domain *host;
        void *regs;
        int index;
        spinlock_t lock;
@@ -179,7 +179,7 @@ static struct irq_chip opb_irq_chip = {
        .irq_set_type   = opb_set_irq_type
 };
 
-static int opb_host_map(struct irq_host *host, unsigned int virq,
+static int opb_host_map(struct irq_domain *host, unsigned int virq,
                irq_hw_number_t hwirq)
 {
        struct opb_pic *opb;
@@ -196,20 +196,9 @@ static int opb_host_map(struct irq_host *host, unsigned int virq,
        return 0;
 }
 
-static int opb_host_xlate(struct irq_host *host, struct device_node *dn,
-               const u32 *intspec, unsigned int intsize,
-               irq_hw_number_t *out_hwirq, unsigned int *out_type)
-{
-       /* Interrupt size must == 2 */
-       BUG_ON(intsize != 2);
-       *out_hwirq = intspec[0];
-       *out_type = intspec[1];
-       return 0;
-}
-
-static struct irq_host_ops opb_host_ops = {
+static const struct irq_domain_ops opb_host_ops = {
        .map = opb_host_map,
-       .xlate = opb_host_xlate,
+       .xlate = irq_domain_xlate_twocell,
 };
 
 irqreturn_t opb_irq_handler(int irq, void *private)
@@ -263,13 +252,11 @@ struct opb_pic *opb_pic_init_one(struct device_node *dn)
                goto free_opb;
        }
 
-       /* Allocate an irq host so that Linux knows that despite only
+       /* Allocate an irq domain so that Linux knows that despite only
         * having one interrupt to issue, we're the controller for multiple
         * hardware IRQs, so later we can lookup their virtual IRQs. */
 
-       opb->host = irq_alloc_host(dn, IRQ_HOST_MAP_LINEAR,
-                       OPB_NR_IRQS, &opb_host_ops, -1);
-
+       opb->host = irq_domain_add_linear(dn, OPB_NR_IRQS, &opb_host_ops, opb);
        if (!opb->host) {
                printk(KERN_ERR "opb: Failed to allocate IRQ host!\n");
                goto free_regs;
@@ -277,7 +264,6 @@ struct opb_pic *opb_pic_init_one(struct device_node *dn)
 
        opb->index = opb_index++;
        spin_lock_init(&opb->lock);
-       opb->host->host_data = opb;
 
        /* Disable all interrupts by default */
        opb_out(opb, OPB_MLSASIER, 0);
index 5d7d59a..d4fa03f 100644 (file)
@@ -54,7 +54,7 @@ cpm8xx_t __iomem *cpmp;  /* Pointer to comm processor space */
 immap_t __iomem *mpc8xx_immr;
 static cpic8xx_t __iomem *cpic_reg;
 
-static struct irq_host *cpm_pic_host;
+static struct irq_domain *cpm_pic_host;
 
 static void cpm_mask_irq(struct irq_data *d)
 {
@@ -98,7 +98,7 @@ int cpm_get_irq(void)
        return irq_linear_revmap(cpm_pic_host, cpm_vec);
 }
 
-static int cpm_pic_host_map(struct irq_host *h, unsigned int virq,
+static int cpm_pic_host_map(struct irq_domain *h, unsigned int virq,
                          irq_hw_number_t hw)
 {
        pr_debug("cpm_pic_host_map(%d, 0x%lx)\n", virq, hw);
@@ -123,7 +123,7 @@ static struct irqaction cpm_error_irqaction = {
        .name = "error",
 };
 
-static struct irq_host_ops cpm_pic_host_ops = {
+static const struct irq_domain_ops cpm_pic_host_ops = {
        .map = cpm_pic_host_map,
 };
 
@@ -164,8 +164,7 @@ unsigned int cpm_pic_init(void)
 
        out_be32(&cpic_reg->cpic_cimr, 0);
 
-       cpm_pic_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
-                                     64, &cpm_pic_host_ops, 64);
+       cpm_pic_host = irq_domain_add_linear(np, 64, &cpm_pic_host_ops, NULL);
        if (cpm_pic_host == NULL) {
                printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n");
                sirq = NO_IRQ;
index bcab50e..d3be961 100644 (file)
@@ -50,7 +50,7 @@
 
 static intctl_cpm2_t __iomem *cpm2_intctl;
 
-static struct irq_host *cpm2_pic_host;
+static struct irq_domain *cpm2_pic_host;
 #define NR_MASK_WORDS   ((NR_IRQS + 31) / 32)
 static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
 
@@ -214,7 +214,7 @@ unsigned int cpm2_get_irq(void)
        return irq_linear_revmap(cpm2_pic_host, irq);
 }
 
-static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq,
+static int cpm2_pic_host_map(struct irq_domain *h, unsigned int virq,
                          irq_hw_number_t hw)
 {
        pr_debug("cpm2_pic_host_map(%d, 0x%lx)\n", virq, hw);
@@ -224,21 +224,9 @@ static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static int cpm2_pic_host_xlate(struct irq_host *h, struct device_node *ct,
-                           const u32 *intspec, unsigned int intsize,
-                           irq_hw_number_t *out_hwirq, unsigned int *out_flags)
-{
-       *out_hwirq = intspec[0];
-       if (intsize > 1)
-               *out_flags = intspec[1];
-       else
-               *out_flags = IRQ_TYPE_NONE;
-       return 0;
-}
-
-static struct irq_host_ops cpm2_pic_host_ops = {
+static const struct irq_domain_ops cpm2_pic_host_ops = {
        .map = cpm2_pic_host_map,
-       .xlate = cpm2_pic_host_xlate,
+       .xlate = irq_domain_xlate_onetwocell,
 };
 
 void cpm2_pic_init(struct device_node *node)
@@ -275,8 +263,7 @@ void cpm2_pic_init(struct device_node *node)
        out_be32(&cpm2_intctl->ic_scprrl, 0x05309770);
 
        /* create a legacy host */
-       cpm2_pic_host = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR,
-                                      64, &cpm2_pic_host_ops, 64);
+       cpm2_pic_host = irq_domain_add_linear(node, 64, &cpm2_pic_host_ops, NULL);
        if (cpm2_pic_host == NULL) {
                printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n");
                return;
index b6731e4..6e0e100 100644 (file)
@@ -182,13 +182,13 @@ unsigned int ehv_pic_get_irq(void)
        return irq_linear_revmap(global_ehv_pic->irqhost, irq);
 }
 
-static int ehv_pic_host_match(struct irq_host *h, struct device_node *node)
+static int ehv_pic_host_match(struct irq_domain *h, struct device_node *node)
 {
        /* Exact match, unless ehv_pic node is NULL */
        return h->of_node == NULL || h->of_node == node;
 }
 
-static int ehv_pic_host_map(struct irq_host *h, unsigned int virq,
+static int ehv_pic_host_map(struct irq_domain *h, unsigned int virq,
                         irq_hw_number_t hw)
 {
        struct ehv_pic *ehv_pic = h->host_data;
@@ -217,7 +217,7 @@ static int ehv_pic_host_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static int ehv_pic_host_xlate(struct irq_host *h, struct device_node *ct,
+static int ehv_pic_host_xlate(struct irq_domain *h, struct device_node *ct,
                           const u32 *intspec, unsigned int intsize,
                           irq_hw_number_t *out_hwirq, unsigned int *out_flags)
 
@@ -248,7 +248,7 @@ static int ehv_pic_host_xlate(struct irq_host *h, struct device_node *ct,
        return 0;
 }
 
-static struct irq_host_ops ehv_pic_host_ops = {
+static const struct irq_domain_ops ehv_pic_host_ops = {
        .match = ehv_pic_host_match,
        .map = ehv_pic_host_map,
        .xlate = ehv_pic_host_xlate,
@@ -275,9 +275,8 @@ void __init ehv_pic_init(void)
                return;
        }
 
-       ehv_pic->irqhost = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
-               NR_EHV_PIC_INTS, &ehv_pic_host_ops, 0);
-
+       ehv_pic->irqhost = irq_domain_add_linear(np, NR_EHV_PIC_INTS,
+                                                &ehv_pic_host_ops, ehv_pic);
        if (!ehv_pic->irqhost) {
                of_node_put(np);
                kfree(ehv_pic);
@@ -293,7 +292,6 @@ void __init ehv_pic_init(void)
                of_node_put(np2);
        }
 
-       ehv_pic->irqhost->host_data = ehv_pic;
        ehv_pic->hc_irq = ehv_pic_irq_chip;
        ehv_pic->hc_irq.irq_set_affinity = ehv_pic_set_affinity;
        ehv_pic->coreint_flag = coreint_flag;
index ecb5c19..0c01deb 100644 (file)
@@ -60,7 +60,7 @@ static struct irq_chip fsl_msi_chip = {
        .name           = "FSL-MSI",
 };
 
-static int fsl_msi_host_map(struct irq_host *h, unsigned int virq,
+static int fsl_msi_host_map(struct irq_domain *h, unsigned int virq,
                                irq_hw_number_t hw)
 {
        struct fsl_msi *msi_data = h->host_data;
@@ -74,7 +74,7 @@ static int fsl_msi_host_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static struct irq_host_ops fsl_msi_host_ops = {
+static const struct irq_domain_ops fsl_msi_host_ops = {
        .map = fsl_msi_host_map,
 };
 
@@ -387,8 +387,8 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev)
        }
        platform_set_drvdata(dev, msi);
 
-       msi->irqhost = irq_alloc_host(dev->dev.of_node, IRQ_HOST_MAP_LINEAR,
-                                     NR_MSI_IRQS, &fsl_msi_host_ops, 0);
+       msi->irqhost = irq_domain_add_linear(dev->dev.of_node,
+                                     NR_MSI_IRQS, &fsl_msi_host_ops, msi);
 
        if (msi->irqhost == NULL) {
                dev_err(&dev->dev, "No memory for MSI irqhost\n");
@@ -420,8 +420,6 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev)
 
        msi->feature = features->fsl_pic_ip;
 
-       msi->irqhost->host_data = msi;
-
        /*
         * Remember the phandle, so that we can match with any PCI nodes
         * that have an "fsl,msi" property.
index f6c646a..8225f86 100644 (file)
@@ -26,7 +26,7 @@
 #define FSL_PIC_IP_VMPIC  0x00000003
 
 struct fsl_msi {
-       struct irq_host *irqhost;
+       struct irq_domain *irqhost;
 
        unsigned long cascade_irq;
 
index d18bb27..997df6a 100644 (file)
@@ -25,7 +25,7 @@ static unsigned char cached_8259[2] = { 0xff, 0xff };
 
 static DEFINE_RAW_SPINLOCK(i8259_lock);
 
-static struct irq_host *i8259_host;
+static struct irq_domain *i8259_host;
 
 /*
  * Acknowledge the IRQ using either the PCI host bridge's interrupt
@@ -163,12 +163,12 @@ static struct resource pic_edgectrl_iores = {
        .flags = IORESOURCE_BUSY,
 };
 
-static int i8259_host_match(struct irq_host *h, struct device_node *node)
+static int i8259_host_match(struct irq_domain *h, struct device_node *node)
 {
        return h->of_node == NULL || h->of_node == node;
 }
 
-static int i8259_host_map(struct irq_host *h, unsigned int virq,
+static int i8259_host_map(struct irq_domain *h, unsigned int virq,
                          irq_hw_number_t hw)
 {
        pr_debug("i8259_host_map(%d, 0x%lx)\n", virq, hw);
@@ -185,7 +185,7 @@ static int i8259_host_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static int i8259_host_xlate(struct irq_host *h, struct device_node *ct,
+static int i8259_host_xlate(struct irq_domain *h, struct device_node *ct,
                            const u32 *intspec, unsigned int intsize,
                            irq_hw_number_t *out_hwirq, unsigned int *out_flags)
 {
@@ -205,13 +205,13 @@ static int i8259_host_xlate(struct irq_host *h, struct device_node *ct,
        return 0;
 }
 
-static struct irq_host_ops i8259_host_ops = {
+static struct irq_domain_ops i8259_host_ops = {
        .match = i8259_host_match,
        .map = i8259_host_map,
        .xlate = i8259_host_xlate,
 };
 
-struct irq_host *i8259_get_host(void)
+struct irq_domain *i8259_get_host(void)
 {
        return i8259_host;
 }
@@ -263,8 +263,7 @@ void i8259_init(struct device_node *node, unsigned long intack_addr)
        raw_spin_unlock_irqrestore(&i8259_lock, flags);
 
        /* create a legacy host */
-       i8259_host = irq_alloc_host(node, IRQ_HOST_MAP_LEGACY,
-                                   0, &i8259_host_ops, 0);
+       i8259_host = irq_domain_add_legacy_isa(node, &i8259_host_ops, NULL);
        if (i8259_host == NULL) {
                printk(KERN_ERR "i8259: failed to allocate irq host !\n");
                return;
index 95da897..b50f978 100644 (file)
@@ -672,13 +672,13 @@ static struct irq_chip ipic_edge_irq_chip = {
        .irq_set_type   = ipic_set_irq_type,
 };
 
-static int ipic_host_match(struct irq_host *h, struct device_node *node)
+static int ipic_host_match(struct irq_domain *h, struct device_node *node)
 {
        /* Exact match, unless ipic node is NULL */
        return h->of_node == NULL || h->of_node == node;
 }
 
-static int ipic_host_map(struct irq_host *h, unsigned int virq,
+static int ipic_host_map(struct irq_domain *h, unsigned int virq,
                         irq_hw_number_t hw)
 {
        struct ipic *ipic = h->host_data;
@@ -692,26 +692,10 @@ static int ipic_host_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static int ipic_host_xlate(struct irq_host *h, struct device_node *ct,
-                          const u32 *intspec, unsigned int intsize,
-                          irq_hw_number_t *out_hwirq, unsigned int *out_flags)
-
-{
-       /* interrupt sense values coming from the device tree equal either
-        * LEVEL_LOW (low assertion) or EDGE_FALLING (high-to-low change)
-        */
-       *out_hwirq = intspec[0];
-       if (intsize > 1)
-               *out_flags = intspec[1];
-       else
-               *out_flags = IRQ_TYPE_NONE;
-       return 0;
-}
-
-static struct irq_host_ops ipic_host_ops = {
+static struct irq_domain_ops ipic_host_ops = {
        .match  = ipic_host_match,
        .map    = ipic_host_map,
-       .xlate  = ipic_host_xlate,
+       .xlate  = irq_domain_xlate_onetwocell,
 };
 
 struct ipic * __init ipic_init(struct device_node *node, unsigned int flags)
@@ -728,9 +712,8 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags)
        if (ipic == NULL)
                return NULL;
 
-       ipic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR,
-                                      NR_IPIC_INTS,
-                                      &ipic_host_ops, 0);
+       ipic->irqhost = irq_domain_add_linear(node, NR_IPIC_INTS,
+                                             &ipic_host_ops, ipic);
        if (ipic->irqhost == NULL) {
                kfree(ipic);
                return NULL;
@@ -738,8 +721,6 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags)
 
        ipic->regs = ioremap(res.start, resource_size(&res));
 
-       ipic->irqhost->host_data = ipic;
-
        /* init hw */
        ipic_write(ipic->regs, IPIC_SICNR, 0x0);
 
index 9391c57..90031d1 100644 (file)
@@ -43,7 +43,7 @@ struct ipic {
        volatile u32 __iomem    *regs;
 
        /* The remapper for this IPIC */
-       struct irq_host         *irqhost;
+       struct irq_domain               *irqhost;
 };
 
 struct ipic_info {
index 2ca0a85..d5f5416 100644 (file)
@@ -17,7 +17,7 @@
 
 extern int cpm_get_irq(struct pt_regs *regs);
 
-static struct irq_host *mpc8xx_pic_host;
+static struct irq_domain *mpc8xx_pic_host;
 #define NR_MASK_WORDS   ((NR_IRQS + 31) / 32)
 static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
 static sysconf8xx_t __iomem *siu_reg;
@@ -110,7 +110,7 @@ unsigned int mpc8xx_get_irq(void)
 
 }
 
-static int mpc8xx_pic_host_map(struct irq_host *h, unsigned int virq,
+static int mpc8xx_pic_host_map(struct irq_domain *h, unsigned int virq,
                          irq_hw_number_t hw)
 {
        pr_debug("mpc8xx_pic_host_map(%d, 0x%lx)\n", virq, hw);
@@ -121,7 +121,7 @@ static int mpc8xx_pic_host_map(struct irq_host *h, unsigned int virq,
 }
 
 
-static int mpc8xx_pic_host_xlate(struct irq_host *h, struct device_node *ct,
+static int mpc8xx_pic_host_xlate(struct irq_domain *h, struct device_node *ct,
                            const u32 *intspec, unsigned int intsize,
                            irq_hw_number_t *out_hwirq, unsigned int *out_flags)
 {
@@ -142,7 +142,7 @@ static int mpc8xx_pic_host_xlate(struct irq_host *h, struct device_node *ct,
 }
 
 
-static struct irq_host_ops mpc8xx_pic_host_ops = {
+static struct irq_domain_ops mpc8xx_pic_host_ops = {
        .map = mpc8xx_pic_host_map,
        .xlate = mpc8xx_pic_host_xlate,
 };
@@ -171,8 +171,7 @@ int mpc8xx_pic_init(void)
                goto out;
        }
 
-       mpc8xx_pic_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
-                                        64, &mpc8xx_pic_host_ops, 64);
+       mpc8xx_pic_host = irq_domain_add_linear(np, 64, &mpc8xx_pic_host_ops, NULL);
        if (mpc8xx_pic_host == NULL) {
                printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n");
                ret = -ENOMEM;
index 4e9ccb1..c83a512 100644 (file)
@@ -965,13 +965,13 @@ static struct irq_chip mpic_irq_ht_chip = {
 #endif /* CONFIG_MPIC_U3_HT_IRQS */
 
 
-static int mpic_host_match(struct irq_host *h, struct device_node *node)
+static int mpic_host_match(struct irq_domain *h, struct device_node *node)
 {
        /* Exact match, unless mpic node is NULL */
        return h->of_node == NULL || h->of_node == node;
 }
 
-static int mpic_host_map(struct irq_host *h, unsigned int virq,
+static int mpic_host_map(struct irq_domain *h, unsigned int virq,
                         irq_hw_number_t hw)
 {
        struct mpic *mpic = h->host_data;
@@ -1041,7 +1041,7 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static int mpic_host_xlate(struct irq_host *h, struct device_node *ct,
+static int mpic_host_xlate(struct irq_domain *h, struct device_node *ct,
                           const u32 *intspec, unsigned int intsize,
                           irq_hw_number_t *out_hwirq, unsigned int *out_flags)
 
@@ -1121,13 +1121,13 @@ static void mpic_cascade(unsigned int irq, struct irq_desc *desc)
        BUG_ON(!(mpic->flags & MPIC_SECONDARY));
 
        virq = mpic_get_one_irq(mpic);
-       if (virq != NO_IRQ)
+       if (virq)
                generic_handle_irq(virq);
 
        chip->irq_eoi(&desc->irq_data);
 }
 
-static struct irq_host_ops mpic_host_ops = {
+static struct irq_domain_ops mpic_host_ops = {
        .match = mpic_host_match,
        .map = mpic_host_map,
        .xlate = mpic_host_xlate,
@@ -1345,10 +1345,9 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1);
        mpic->isu_mask = (1 << mpic->isu_shift) - 1;
 
-       mpic->irqhost = irq_alloc_host(mpic->node, IRQ_HOST_MAP_LINEAR,
+       mpic->irqhost = irq_domain_add_linear(mpic->node,
                                       isu_size ? isu_size : mpic->num_sources,
-                                      &mpic_host_ops,
-                                      flags & MPIC_LARGE_VECTORS ? 2048 : 256);
+                                      &mpic_host_ops, mpic);
 
        /*
         * FIXME: The code leaks the MPIC object and mappings here; this
@@ -1357,8 +1356,6 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        if (mpic->irqhost == NULL)
                return NULL;
 
-       mpic->irqhost->host_data = mpic;
-
        /* Display version */
        switch (greg_feature & MPIC_GREG_FEATURE_VERSION_MASK) {
        case 1:
index 0f67cd7..0622aa9 100644 (file)
@@ -32,7 +32,7 @@ void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq)
 static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
 {
        irq_hw_number_t hwirq;
-       struct irq_host_ops *ops = mpic->irqhost->ops;
+       const struct irq_domain_ops *ops = mpic->irqhost->ops;
        struct device_node *np;
        int flags, index, i;
        struct of_irq oirq;
index 14d1302..8848e99 100644 (file)
@@ -70,7 +70,7 @@ static u32 mv64x60_cached_low_mask;
 static u32 mv64x60_cached_high_mask = MV64X60_HIGH_GPP_GROUPS;
 static u32 mv64x60_cached_gpp_mask;
 
-static struct irq_host *mv64x60_irq_host;
+static struct irq_domain *mv64x60_irq_host;
 
 /*
  * mv64x60_chip_low functions
@@ -208,7 +208,7 @@ static struct irq_chip *mv64x60_chips[] = {
        [MV64x60_LEVEL1_GPP]  = &mv64x60_chip_gpp,
 };
 
-static int mv64x60_host_map(struct irq_host *h, unsigned int virq,
+static int mv64x60_host_map(struct irq_domain *h, unsigned int virq,
                          irq_hw_number_t hwirq)
 {
        int level1;
@@ -223,7 +223,7 @@ static int mv64x60_host_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static struct irq_host_ops mv64x60_host_ops = {
+static struct irq_domain_ops mv64x60_host_ops = {
        .map   = mv64x60_host_map,
 };
 
@@ -250,9 +250,8 @@ void __init mv64x60_init_irq(void)
        paddr = of_translate_address(np, reg);
        mv64x60_irq_reg_base = ioremap(paddr, reg[1]);
 
-       mv64x60_irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
-                                         MV64x60_NUM_IRQS,
-                                         &mv64x60_host_ops, MV64x60_NUM_IRQS);
+       mv64x60_irq_host = irq_domain_add_linear(np, MV64x60_NUM_IRQS,
+                                         &mv64x60_host_ops, NULL);
 
        spin_lock_irqsave(&mv64x60_lock, flags);
        out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK,
index 73034bd..2fba6ef 100644 (file)
@@ -245,13 +245,13 @@ static struct irq_chip qe_ic_irq_chip = {
        .irq_mask_ack = qe_ic_mask_irq,
 };
 
-static int qe_ic_host_match(struct irq_host *h, struct device_node *node)
+static int qe_ic_host_match(struct irq_domain *h, struct device_node *node)
 {
        /* Exact match, unless qe_ic node is NULL */
        return h->of_node == NULL || h->of_node == node;
 }
 
-static int qe_ic_host_map(struct irq_host *h, unsigned int virq,
+static int qe_ic_host_map(struct irq_domain *h, unsigned int virq,
                          irq_hw_number_t hw)
 {
        struct qe_ic *qe_ic = h->host_data;
@@ -272,23 +272,10 @@ static int qe_ic_host_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static int qe_ic_host_xlate(struct irq_host *h, struct device_node *ct,
-                           const u32 * intspec, unsigned int intsize,
-                           irq_hw_number_t * out_hwirq,
-                           unsigned int *out_flags)
-{
-       *out_hwirq = intspec[0];
-       if (intsize > 1)
-               *out_flags = intspec[1];
-       else
-               *out_flags = IRQ_TYPE_NONE;
-       return 0;
-}
-
-static struct irq_host_ops qe_ic_host_ops = {
+static struct irq_domain_ops qe_ic_host_ops = {
        .match = qe_ic_host_match,
        .map = qe_ic_host_map,
-       .xlate = qe_ic_host_xlate,
+       .xlate = irq_domain_xlate_onetwocell,
 };
 
 /* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
@@ -339,8 +326,8 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags,
        if (qe_ic == NULL)
                return;
 
-       qe_ic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR,
-                                       NR_QE_IC_INTS, &qe_ic_host_ops, 0);
+       qe_ic->irqhost = irq_domain_add_linear(node, NR_QE_IC_INTS,
+                                              &qe_ic_host_ops, qe_ic);
        if (qe_ic->irqhost == NULL) {
                kfree(qe_ic);
                return;
@@ -348,7 +335,6 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags,
 
        qe_ic->regs = ioremap(res.start, resource_size(&res));
 
-       qe_ic->irqhost->host_data = qe_ic;
        qe_ic->hc_irq = qe_ic_irq_chip;
 
        qe_ic->virq_high = irq_of_parse_and_map(node, 0);
index c1361d0..c327872 100644 (file)
@@ -79,7 +79,7 @@ struct qe_ic {
        volatile u32 __iomem *regs;
 
        /* The remapper for this QEIC */
-       struct irq_host *irqhost;
+       struct irq_domain *irqhost;
 
        /* The "linux" controller struct */
        struct irq_chip hc_irq;
index 4d18658..188012c 100644 (file)
@@ -51,7 +51,7 @@
 u32 tsi108_pci_cfg_base;
 static u32 tsi108_pci_cfg_phys;
 u32 tsi108_csr_vir_base;
-static struct irq_host *pci_irq_host;
+static struct irq_domain *pci_irq_host;
 
 extern u32 get_vir_csrbase(void);
 extern u32 tsi108_read_reg(u32 reg_offset);
@@ -376,7 +376,7 @@ static struct irq_chip tsi108_pci_irq = {
        .irq_unmask = tsi108_pci_irq_unmask,
 };
 
-static int pci_irq_host_xlate(struct irq_host *h, struct device_node *ct,
+static int pci_irq_host_xlate(struct irq_domain *h, struct device_node *ct,
                            const u32 *intspec, unsigned int intsize,
                            irq_hw_number_t *out_hwirq, unsigned int *out_flags)
 {
@@ -385,7 +385,7 @@ static int pci_irq_host_xlate(struct irq_host *h, struct device_node *ct,
        return 0;
 }
 
-static int pci_irq_host_map(struct irq_host *h, unsigned int virq,
+static int pci_irq_host_map(struct irq_domain *h, unsigned int virq,
                          irq_hw_number_t hw)
 {      unsigned int irq;
        DBG("%s(%d, 0x%lx)\n", __func__, virq, hw);
@@ -397,7 +397,7 @@ static int pci_irq_host_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static struct irq_host_ops pci_irq_host_ops = {
+static struct irq_domain_ops pci_irq_domain_ops = {
        .map = pci_irq_host_map,
        .xlate = pci_irq_host_xlate,
 };
@@ -419,10 +419,9 @@ void __init tsi108_pci_int_init(struct device_node *node)
 {
        DBG("Tsi108_pci_int_init: initializing PCI interrupts\n");
 
-       pci_irq_host = irq_alloc_host(node, IRQ_HOST_MAP_LEGACY,
-                                     0, &pci_irq_host_ops, 0);
+       pci_irq_host = irq_domain_add_legacy_isa(node, &pci_irq_domain_ops, NULL);
        if (pci_irq_host == NULL) {
-               printk(KERN_ERR "pci_irq_host: failed to allocate irq host !\n");
+               printk(KERN_ERR "pci_irq_host: failed to allocate irq domain!\n");
                return;
        }
 
index 063c901..9203393 100644 (file)
@@ -49,7 +49,7 @@ struct uic {
        raw_spinlock_t lock;
 
        /* The remapper for this UIC */
-       struct irq_host *irqhost;
+       struct irq_domain       *irqhost;
 };
 
 static void uic_unmask_irq(struct irq_data *d)
@@ -174,7 +174,7 @@ static struct irq_chip uic_irq_chip = {
        .irq_set_type   = uic_set_irq_type,
 };
 
-static int uic_host_map(struct irq_host *h, unsigned int virq,
+static int uic_host_map(struct irq_domain *h, unsigned int virq,
                        irq_hw_number_t hw)
 {
        struct uic *uic = h->host_data;
@@ -190,21 +190,9 @@ static int uic_host_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static int uic_host_xlate(struct irq_host *h, struct device_node *ct,
-                         const u32 *intspec, unsigned int intsize,
-                         irq_hw_number_t *out_hwirq, unsigned int *out_type)
-
-{
-       /* UIC intspecs must have 2 cells */
-       BUG_ON(intsize != 2);
-       *out_hwirq = intspec[0];
-       *out_type = intspec[1];
-       return 0;
-}
-
-static struct irq_host_ops uic_host_ops = {
+static struct irq_domain_ops uic_host_ops = {
        .map    = uic_host_map,
-       .xlate  = uic_host_xlate,
+       .xlate  = irq_domain_xlate_twocell,
 };
 
 void uic_irq_cascade(unsigned int virq, struct irq_desc *desc)
@@ -270,13 +258,11 @@ static struct uic * __init uic_init_one(struct device_node *node)
        }
        uic->dcrbase = *dcrreg;
 
-       uic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR,
-                                     NR_UIC_INTS, &uic_host_ops, -1);
+       uic->irqhost = irq_domain_add_linear(node, NR_UIC_INTS, &uic_host_ops,
+                                            uic);
        if (! uic->irqhost)
                return NULL; /* FIXME: panic? */
 
-       uic->irqhost->host_data = uic;
-
        /* Start with all interrupts disabled, level and non-critical */
        mtdcr(uic->dcrbase + UIC_ER, 0);
        mtdcr(uic->dcrbase + UIC_CR, 0);
index d72eda6..ea5e204 100644 (file)
@@ -40,7 +40,7 @@ unsigned int xics_interrupt_server_size               = 8;
 
 DEFINE_PER_CPU(struct xics_cppr, xics_cppr);
 
-struct irq_host *xics_host;
+struct irq_domain *xics_host;
 
 static LIST_HEAD(ics_list);
 
@@ -212,16 +212,16 @@ void xics_migrate_irqs_away(void)
                /* We can't set affinity on ISA interrupts */
                if (virq < NUM_ISA_INTERRUPTS)
                        continue;
-               if (!virq_is_host(virq, xics_host))
-                       continue;
-               irq = (unsigned int)virq_to_hw(virq);
-               /* We need to get IPIs still. */
-               if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
-                       continue;
                desc = irq_to_desc(virq);
                /* We only need to migrate enabled IRQS */
                if (!desc || !desc->action)
                        continue;
+               if (desc->irq_data.domain != xics_host)
+                       continue;
+               irq = desc->irq_data.hwirq;
+               /* We need to get IPIs still. */
+               if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
+                       continue;
                chip = irq_desc_get_chip(desc);
                if (!chip || !chip->irq_set_affinity)
                        continue;
@@ -301,7 +301,7 @@ int xics_get_irq_server(unsigned int virq, const struct cpumask *cpumask,
 }
 #endif /* CONFIG_SMP */
 
-static int xics_host_match(struct irq_host *h, struct device_node *node)
+static int xics_host_match(struct irq_domain *h, struct device_node *node)
 {
        struct ics *ics;
 
@@ -323,7 +323,7 @@ static struct irq_chip xics_ipi_chip = {
        .irq_unmask = xics_ipi_unmask,
 };
 
-static int xics_host_map(struct irq_host *h, unsigned int virq,
+static int xics_host_map(struct irq_domain *h, unsigned int virq,
                         irq_hw_number_t hw)
 {
        struct ics *ics;
@@ -351,7 +351,7 @@ static int xics_host_map(struct irq_host *h, unsigned int virq,
        return -EINVAL;
 }
 
-static int xics_host_xlate(struct irq_host *h, struct device_node *ct,
+static int xics_host_xlate(struct irq_domain *h, struct device_node *ct,
                           const u32 *intspec, unsigned int intsize,
                           irq_hw_number_t *out_hwirq, unsigned int *out_flags)
 
@@ -366,7 +366,7 @@ static int xics_host_xlate(struct irq_host *h, struct device_node *ct,
        return 0;
 }
 
-static struct irq_host_ops xics_host_ops = {
+static struct irq_domain_ops xics_host_ops = {
        .match = xics_host_match,
        .map = xics_host_map,
        .xlate = xics_host_xlate,
@@ -374,8 +374,7 @@ static struct irq_host_ops xics_host_ops = {
 
 static void __init xics_init_host(void)
 {
-       xics_host = irq_alloc_host(NULL, IRQ_HOST_MAP_TREE, 0, &xics_host_ops,
-                                  XICS_IRQ_SPURIOUS);
+       xics_host = irq_domain_add_tree(NULL, &xics_host_ops, NULL);
        BUG_ON(xics_host == NULL);
        irq_set_default_host(xics_host);
 }
index 6183799..8d73c3c 100644 (file)
@@ -40,7 +40,7 @@
 #define XINTC_IVR      24      /* Interrupt Vector */
 #define XINTC_MER      28      /* Master Enable */
 
-static struct irq_host *master_irqhost;
+static struct irq_domain *master_irqhost;
 
 #define XILINX_INTC_MAXIRQS    (32)
 
@@ -141,7 +141,7 @@ static struct irq_chip xilinx_intc_edge_irqchip = {
 /**
  * xilinx_intc_xlate - translate virq# from device tree interrupts property
  */
-static int xilinx_intc_xlate(struct irq_host *h, struct device_node *ct,
+static int xilinx_intc_xlate(struct irq_domain *h, struct device_node *ct,
                                const u32 *intspec, unsigned int intsize,
                                irq_hw_number_t *out_hwirq,
                                unsigned int *out_flags)
@@ -161,7 +161,7 @@ static int xilinx_intc_xlate(struct irq_host *h, struct device_node *ct,
 
        return 0;
 }
-static int xilinx_intc_map(struct irq_host *h, unsigned int virq,
+static int xilinx_intc_map(struct irq_domain *h, unsigned int virq,
                                  irq_hw_number_t irq)
 {
        irq_set_chip_data(virq, h->host_data);
@@ -177,15 +177,15 @@ static int xilinx_intc_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static struct irq_host_ops xilinx_intc_ops = {
+static struct irq_domain_ops xilinx_intc_ops = {
        .map = xilinx_intc_map,
        .xlate = xilinx_intc_xlate,
 };
 
-struct irq_host * __init
+struct irq_domain * __init
 xilinx_intc_init(struct device_node *np)
 {
-       struct irq_host * irq;
+       struct irq_domain * irq;
        void * regs;
 
        /* Find and map the intc registers */
@@ -200,12 +200,11 @@ xilinx_intc_init(struct device_node *np)
        out_be32(regs + XINTC_IAR, ~(u32) 0); /* Acknowledge pending irqs */
        out_be32(regs + XINTC_MER, 0x3UL); /* Turn on the Master Enable. */
 
-       /* Allocate and initialize an irq_host structure. */
-       irq = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, XILINX_INTC_MAXIRQS,
-                            &xilinx_intc_ops, -1);
+       /* Allocate and initialize an irq_domain structure. */
+       irq = irq_domain_add_linear(np, XILINX_INTC_MAXIRQS, &xilinx_intc_ops,
+                                   regs);
        if (!irq)
                panic(__FILE__ ": Cannot allocate IRQ host\n");
-       irq->host_data = regs;
 
        return irq;
 }
index edd3d3c..c287651 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/proc_fs.h>
 #include <linux/mutex.h>
 #include <linux/atomic.h>
+#include <linux/irqdomain.h>
 
 #define OF_ROOT_NODE_ADDR_CELLS_DEFAULT        2
 #define OF_ROOT_NODE_SIZE_CELLS_DEFAULT        1
@@ -55,15 +56,6 @@ struct resource;
 extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name);
 extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size);
 
-/* These routines are here to provide compatibility with how powerpc
- * handles IRQ mapping for OF device nodes.  We precompute and permanently
- * register them in the platform_device objects, whereas powerpc computes them
- * on request.
- */
-static inline void irq_dispose_mapping(unsigned int virq)
-{
-}
-
 extern struct device_node *of_console_device;
 extern char *of_console_path;
 extern char *of_console_options;
index 5bed94e..e0829a6 100644 (file)
@@ -398,6 +398,7 @@ config X86_INTEL_CE
        select X86_REBOOTFIXUPS
        select OF
        select OF_EARLY_FLATTREE
+       select IRQ_DOMAIN
        ---help---
          Select for the Intel CE media processor (CE4100) SOC.
          This option compiles in support for the CE4100 SOC for settop
@@ -2076,6 +2077,7 @@ config OLPC
        select GPIOLIB
        select OF
        select OF_PROMTREE
+       select IRQ_DOMAIN
        ---help---
          Add support for detecting the unique features of the OLPC
          XO hardware.
diff --git a/arch/x86/include/asm/irq_controller.h b/arch/x86/include/asm/irq_controller.h
deleted file mode 100644 (file)
index 423bbbd..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef __IRQ_CONTROLLER__
-#define __IRQ_CONTROLLER__
-
-struct irq_domain {
-       int (*xlate)(struct irq_domain *h, const u32 *intspec, u32 intsize,
-                       u32 *out_hwirq, u32 *out_type);
-       void *priv;
-       struct device_node *controller;
-       struct list_head l;
-};
-
-#endif
index 644dd88..60bef66 100644 (file)
@@ -21,7 +21,6 @@
 #include <asm/irq.h>
 #include <linux/atomic.h>
 #include <asm/setup.h>
-#include <asm/irq_controller.h>
 
 #ifdef CONFIG_OF
 extern int of_ioapic;
@@ -43,15 +42,6 @@ extern char cmd_line[COMMAND_LINE_SIZE];
 #define pci_address_to_pio pci_address_to_pio
 unsigned long pci_address_to_pio(phys_addr_t addr);
 
-/**
- * irq_dispose_mapping - Unmap an interrupt
- * @virq: linux virq number of the interrupt to unmap
- *
- * FIXME: We really should implement proper virq handling like power,
- * but that's going to be major surgery.
- */
-static inline void irq_dispose_mapping(unsigned int virq) { }
-
 #define HAVE_ARCH_DEVTREE_FIXUPS
 
 #endif /* __ASSEMBLY__ */
index 5282179..3ae2ced 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/bootmem.h>
 #include <linux/export.h>
 #include <linux/io.h>
+#include <linux/irqdomain.h>
 #include <linux/interrupt.h>
 #include <linux/list.h>
 #include <linux/of.h>
 #include <linux/initrd.h>
 
 #include <asm/hpet.h>
-#include <asm/irq_controller.h>
 #include <asm/apic.h>
 #include <asm/pci_x86.h>
 
 __initdata u64 initial_dtb;
 char __initdata cmd_line[COMMAND_LINE_SIZE];
-static LIST_HEAD(irq_domains);
-static DEFINE_RAW_SPINLOCK(big_irq_lock);
 
 int __initdata of_ioapic;
 
-#ifdef CONFIG_X86_IO_APIC
-static void add_interrupt_host(struct irq_domain *ih)
-{
-       unsigned long flags;
-
-       raw_spin_lock_irqsave(&big_irq_lock, flags);
-       list_add(&ih->l, &irq_domains);
-       raw_spin_unlock_irqrestore(&big_irq_lock, flags);
-}
-#endif
-
-static struct irq_domain *get_ih_from_node(struct device_node *controller)
-{
-       struct irq_domain *ih, *found = NULL;
-       unsigned long flags;
-
-       raw_spin_lock_irqsave(&big_irq_lock, flags);
-       list_for_each_entry(ih, &irq_domains, l) {
-               if (ih->controller ==  controller) {
-                       found = ih;
-                       break;
-               }
-       }
-       raw_spin_unlock_irqrestore(&big_irq_lock, flags);
-       return found;
-}
-
-unsigned int irq_create_of_mapping(struct device_node *controller,
-                                  const u32 *intspec, unsigned int intsize)
-{
-       struct irq_domain *ih;
-       u32 virq, type;
-       int ret;
-
-       ih = get_ih_from_node(controller);
-       if (!ih)
-               return 0;
-       ret = ih->xlate(ih, intspec, intsize, &virq, &type);
-       if (ret)
-               return 0;
-       if (type == IRQ_TYPE_NONE)
-               return virq;
-       irq_set_irq_type(virq, type);
-       return virq;
-}
-EXPORT_SYMBOL_GPL(irq_create_of_mapping);
-
 unsigned long pci_address_to_pio(phys_addr_t address)
 {
        /*
@@ -354,36 +305,43 @@ static struct of_ioapic_type of_ioapic_type[] =
        },
 };
 
-static int ioapic_xlate(struct irq_domain *id, const u32 *intspec, u32 intsize,
-                       u32 *out_hwirq, u32 *out_type)
+static int ioapic_xlate(struct irq_domain *domain,
+                       struct device_node *controller,
+                       const u32 *intspec, u32 intsize,
+                       irq_hw_number_t *out_hwirq, u32 *out_type)
 {
-       struct mp_ioapic_gsi *gsi_cfg;
        struct io_apic_irq_attr attr;
        struct of_ioapic_type *it;
-       u32 line, idx, type;
+       u32 line, idx;
+       int rc;
 
-       if (intsize < 2)
+       if (WARN_ON(intsize < 2))
                return -EINVAL;
 
-       line = *intspec;
-       idx = (u32) id->priv;
-       gsi_cfg = mp_ioapic_gsi_routing(idx);
-       *out_hwirq = line + gsi_cfg->gsi_base;
-
-       intspec++;
-       type = *intspec;
+       line = intspec[0];
 
-       if (type >= ARRAY_SIZE(of_ioapic_type))
+       if (intspec[1] >= ARRAY_SIZE(of_ioapic_type))
                return -EINVAL;
 
-       it = of_ioapic_type + type;
-       *out_type = it->out_type;
+       it = &of_ioapic_type[intspec[1]];
 
+       idx = (u32) domain->host_data;
        set_io_apic_irq_attr(&attr, idx, line, it->trigger, it->polarity);
 
-       return io_apic_setup_irq_pin_once(*out_hwirq, cpu_to_node(0), &attr);
+       rc = io_apic_setup_irq_pin_once(irq_find_mapping(domain, line),
+                                       cpu_to_node(0), &attr);
+       if (rc)
+               return rc;
+
+       *out_hwirq = line;
+       *out_type = it->out_type;
+       return 0;
 }
 
+const struct irq_domain_ops ioapic_irq_domain_ops = {
+       .xlate = ioapic_xlate,
+};
+
 static void __init ioapic_add_ofnode(struct device_node *np)
 {
        struct resource r;
@@ -399,13 +357,14 @@ static void __init ioapic_add_ofnode(struct device_node *np)
        for (i = 0; i < nr_ioapics; i++) {
                if (r.start == mpc_ioapic_addr(i)) {
                        struct irq_domain *id;
+                       struct mp_ioapic_gsi *gsi_cfg;
+
+                       gsi_cfg = mp_ioapic_gsi_routing(i);
 
-                       id = kzalloc(sizeof(*id), GFP_KERNEL);
+                       id = irq_domain_add_legacy(np, 32, gsi_cfg->gsi_base, 0,
+                                                  &ioapic_irq_domain_ops,
+                                                  (void*)i);
                        BUG_ON(!id);
-                       id->controller = np;
-                       id->xlate = ioapic_xlate;
-                       id->priv = (void *)i;
-                       add_interrupt_host(id);
                        return;
                }
        }
index e70be38..ce874f8 100644 (file)
                                        interrupts = <14 1>;
                                };
 
-                               gpio@b,1 {
+                               pcigpio: gpio@b,1 {
+                                       #gpio-cells = <2>;
+                                       #interrupt-cells = <2>;
                                        compatible = "pci8086,2e67.2",
                                                   "pci8086,2e67",
                                                   "pciclassff0000",
                                                   "pciclassff00";
 
-                                       #gpio-cells = <2>;
                                        reg = <0x15900 0x0 0x0 0x0 0x0>;
                                        interrupts = <15 1>;
+                                       interrupt-controller;
                                        gpio-controller;
+                                       intel,muxctl = <0>;
                                };
 
                                i2c-controller@b,2 {
index d0c4118..dbb1909 100644 (file)
@@ -225,6 +225,12 @@ config GPIO_MAX732X_IRQ
          Say yes here to enable the max732x to be used as an interrupt
          controller. It requires the driver to be built in the kernel.
 
+config GPIO_MC9S08DZ60
+       bool "MX35 3DS BOARD MC9S08DZ60 GPIO functions"
+       depends on I2C && MACH_MX35_3DS
+       help
+         Select this to enable the MC9S08DZ60 GPIO driver
+
 config GPIO_PCA953X
        tristate "PCA953x, PCA955x, TCA64xx, and MAX7310 I/O ports"
        depends on I2C
@@ -411,6 +417,14 @@ config GPIO_ML_IOH
          Hub) which is for IVI(In-Vehicle Infotainment) use.
          This driver can access the IOH's GPIO device.
 
+config GPIO_SODAVILLE
+       bool "Intel Sodaville GPIO support"
+       depends on X86 && PCI && OF
+       select GPIO_GENERIC
+       select GENERIC_IRQ_CHIP
+       help
+         Say Y here to support Intel Sodaville GPIO.
+
 config GPIO_TIMBERDALE
        bool "Support for timberdale GPIO IP"
        depends on MFD_TIMBERDALE && HAS_IOMEM
index fa10df6..593bdcd 100644 (file)
@@ -26,6 +26,7 @@ obj-$(CONFIG_GPIO_MAX7300)    += gpio-max7300.o
 obj-$(CONFIG_GPIO_MAX7301)     += gpio-max7301.o
 obj-$(CONFIG_GPIO_MAX732X)     += gpio-max732x.o
 obj-$(CONFIG_GPIO_MC33880)     += gpio-mc33880.o
+obj-$(CONFIG_GPIO_MC9S08DZ60)  += gpio-mc9s08dz60.o
 obj-$(CONFIG_GPIO_MCP23S08)    += gpio-mcp23s08.o
 obj-$(CONFIG_GPIO_ML_IOH)      += gpio-ml-ioh.o
 obj-$(CONFIG_GPIO_MPC5200)     += gpio-mpc5200.o
@@ -45,6 +46,7 @@ obj-$(CONFIG_GPIO_RDC321X)    += gpio-rdc321x.o
 obj-$(CONFIG_PLAT_SAMSUNG)     += gpio-samsung.o
 obj-$(CONFIG_ARCH_SA1100)      += gpio-sa1100.o
 obj-$(CONFIG_GPIO_SCH)         += gpio-sch.o
+obj-$(CONFIG_GPIO_SODAVILLE)   += gpio-sodaville.o
 obj-$(CONFIG_GPIO_STMPE)       += gpio-stmpe.o
 obj-$(CONFIG_GPIO_SX150X)      += gpio-sx150x.o
 obj-$(CONFIG_GPIO_TC3589X)     += gpio-tc3589x.o
diff --git a/drivers/gpio/gpio-mc9s08dz60.c b/drivers/gpio/gpio-mc9s08dz60.c
new file mode 100644 (file)
index 0000000..2738cc4
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2009-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Author: Wu Guoxing <b39297@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+
+#define GPIO_GROUP_NUM 2
+#define GPIO_NUM_PER_GROUP 8
+#define GPIO_NUM (GPIO_GROUP_NUM*GPIO_NUM_PER_GROUP)
+
+struct mc9s08dz60 {
+       struct i2c_client *client;
+       struct gpio_chip chip;
+};
+
+static inline struct mc9s08dz60 *to_mc9s08dz60(struct gpio_chip *gc)
+{
+       return container_of(gc, struct mc9s08dz60, chip);
+}
+
+
+static void mc9s_gpio_to_reg_and_bit(int offset, u8 *reg, u8 *bit)
+{
+       *reg = 0x20 + offset / GPIO_NUM_PER_GROUP;
+       *bit = offset % GPIO_NUM_PER_GROUP;
+}
+
+static int mc9s08dz60_get_value(struct gpio_chip *gc, unsigned offset)
+{
+       u8 reg, bit;
+       s32 value;
+       struct mc9s08dz60 *mc9s = to_mc9s08dz60(gc);
+
+       mc9s_gpio_to_reg_and_bit(offset, &reg, &bit);
+       value = i2c_smbus_read_byte_data(mc9s->client, reg);
+
+       return (value >= 0) ? (value >> bit) & 0x1 : 0;
+}
+
+static int mc9s08dz60_set(struct mc9s08dz60 *mc9s, unsigned offset, int val)
+{
+       u8 reg, bit;
+       s32 value;
+
+       mc9s_gpio_to_reg_and_bit(offset, &reg, &bit);
+       value = i2c_smbus_read_byte_data(mc9s->client, reg);
+       if (value >= 0) {
+               if (val)
+                       value |= 1 << bit;
+               else
+                       value &= ~(1 << bit);
+
+               return i2c_smbus_write_byte_data(mc9s->client, reg, value);
+       } else
+               return value;
+
+}
+
+
+static void mc9s08dz60_set_value(struct gpio_chip *gc, unsigned offset, int val)
+{
+       struct mc9s08dz60 *mc9s = to_mc9s08dz60(gc);
+
+       mc9s08dz60_set(mc9s, offset, val);
+}
+
+static int mc9s08dz60_direction_output(struct gpio_chip *gc,
+                                      unsigned offset, int val)
+{
+       struct mc9s08dz60 *mc9s = to_mc9s08dz60(gc);
+
+       return mc9s08dz60_set(mc9s, offset, val);
+}
+
+static int mc9s08dz60_probe(struct i2c_client *client,
+                           const struct i2c_device_id *id)
+{
+       int ret = 0;
+       struct mc9s08dz60 *mc9s;
+
+       mc9s = kzalloc(sizeof(*mc9s), GFP_KERNEL);
+       if (!mc9s)
+               return -ENOMEM;
+
+       mc9s->chip.label = client->name;
+       mc9s->chip.base = -1;
+       mc9s->chip.dev = &client->dev;
+       mc9s->chip.owner = THIS_MODULE;
+       mc9s->chip.ngpio = GPIO_NUM;
+       mc9s->chip.can_sleep = 1;
+       mc9s->chip.get = mc9s08dz60_get_value;
+       mc9s->chip.set = mc9s08dz60_set_value;
+       mc9s->chip.direction_output = mc9s08dz60_direction_output;
+       mc9s->client = client;
+       i2c_set_clientdata(client, mc9s);
+
+       ret = gpiochip_add(&mc9s->chip);
+       if (ret)
+               goto error;
+
+       return 0;
+
+ error:
+       kfree(mc9s);
+       return ret;
+}
+
+static int mc9s08dz60_remove(struct i2c_client *client)
+{
+       struct mc9s08dz60 *mc9s;
+       int ret;
+
+       mc9s = i2c_get_clientdata(client);
+
+       ret = gpiochip_remove(&mc9s->chip);
+       if (!ret)
+               kfree(mc9s);
+
+       return ret;
+
+}
+
+static const struct i2c_device_id mc9s08dz60_id[] = {
+       {"mc9s08dz60", 0},
+       {},
+};
+
+MODULE_DEVICE_TABLE(i2c, mc9s08dz60_id);
+
+static struct i2c_driver mc9s08dz60_i2c_driver = {
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = "mc9s08dz60",
+       },
+       .probe = mc9s08dz60_probe,
+       .remove = mc9s08dz60_remove,
+       .id_table = mc9s08dz60_id,
+};
+
+module_i2c_driver(mc9s08dz60_i2c_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc. "
+               "Wu Guoxing <b39297@freescale.com>");
+MODULE_DESCRIPTION("mc9s08dz60 gpio function on mx35 3ds board");
+MODULE_LICENSE("GPL v2");
index 5cd04b6..e6568c1 100644 (file)
@@ -37,7 +37,7 @@ struct mpc8xxx_gpio_chip {
         * open drain mode safely
         */
        u32 data;
-       struct irq_host *irq;
+       struct irq_domain *irq;
        void *of_dev_id_data;
 };
 
@@ -281,7 +281,7 @@ static struct irq_chip mpc8xxx_irq_chip = {
        .irq_set_type   = mpc8xxx_irq_set_type,
 };
 
-static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq,
+static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int virq,
                                irq_hw_number_t hw)
 {
        struct mpc8xxx_gpio_chip *mpc8xxx_gc = h->host_data;
@@ -296,24 +296,9 @@ static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static int mpc8xxx_gpio_irq_xlate(struct irq_host *h, struct device_node *ct,
-                                 const u32 *intspec, unsigned int intsize,
-                                 irq_hw_number_t *out_hwirq,
-                                 unsigned int *out_flags)
-
-{
-       /* interrupt sense values coming from the device tree equal either
-        * EDGE_FALLING or EDGE_BOTH
-        */
-       *out_hwirq = intspec[0];
-       *out_flags = intspec[1];
-
-       return 0;
-}
-
-static struct irq_host_ops mpc8xxx_gpio_irq_ops = {
+static struct irq_domain_ops mpc8xxx_gpio_irq_ops = {
        .map    = mpc8xxx_gpio_irq_map,
-       .xlate  = mpc8xxx_gpio_irq_xlate,
+       .xlate  = irq_domain_xlate_twocell,
 };
 
 static struct of_device_id mpc8xxx_gpio_ids[] __initdata = {
@@ -364,9 +349,8 @@ static void __init mpc8xxx_add_controller(struct device_node *np)
        if (hwirq == NO_IRQ)
                goto skip_irq;
 
-       mpc8xxx_gc->irq =
-               irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, MPC8XXX_GPIO_PINS,
-                              &mpc8xxx_gpio_irq_ops, MPC8XXX_GPIO_PINS);
+       mpc8xxx_gc->irq = irq_domain_add_linear(np, MPC8XXX_GPIO_PINS,
+                                       &mpc8xxx_gpio_irq_ops, mpc8xxx_gc);
        if (!mpc8xxx_gc->irq)
                goto skip_irq;
 
@@ -374,8 +358,6 @@ static void __init mpc8xxx_add_controller(struct device_node *np)
        if (id)
                mpc8xxx_gc->of_dev_id_data = id->data;
 
-       mpc8xxx_gc->irq->host_data = mpc8xxx_gc;
-
        /* ack and mask all irqs */
        out_be32(mm_gc->regs + GPIO_IER, 0xffffffff);
        out_be32(mm_gc->regs + GPIO_IMR, 0);
index 0b05629..afef0f7 100644 (file)
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/io.h>
-#include <linux/slab.h>
+#include <linux/device.h>
 #include <linux/pm_runtime.h>
+#include <linux/pm.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/irqdomain.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
 #include <asm/gpio.h>
 #include <asm/mach/irq.h>
 
+#define OFF_MODE       1
+
+static LIST_HEAD(omap_gpio_list);
+
+struct gpio_regs {
+       u32 irqenable1;
+       u32 irqenable2;
+       u32 wake_en;
+       u32 ctrl;
+       u32 oe;
+       u32 leveldetect0;
+       u32 leveldetect1;
+       u32 risingdetect;
+       u32 fallingdetect;
+       u32 dataout;
+       u32 debounce;
+       u32 debounce_en;
+};
+
 struct gpio_bank {
-       unsigned long pbase;
+       struct list_head node;
        void __iomem *base;
        u16 irq;
-       u16 virtual_irq_start;
-       int method;
+       int irq_base;
+       struct irq_domain *domain;
        u32 suspend_wakeup;
-#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS)
        u32 saved_wakeup;
-#endif
        u32 non_wakeup_gpios;
        u32 enabled_non_wakeup_gpios;
-
+       struct gpio_regs context;
        u32 saved_datain;
        u32 saved_fallingdetect;
        u32 saved_risingdetect;
@@ -51,44 +72,31 @@ struct gpio_bank {
        struct clk *dbck;
        u32 mod_usage;
        u32 dbck_enable_mask;
+       bool dbck_enabled;
        struct device *dev;
+       bool is_mpuio;
        bool dbck_flag;
+       bool loses_context;
        int stride;
        u32 width;
+       int context_loss_count;
+       int power_mode;
+       bool workaround_enabled;
 
        void (*set_dataout)(struct gpio_bank *bank, int gpio, int enable);
+       int (*get_context_loss_count)(struct device *dev);
 
        struct omap_gpio_reg_offs *regs;
 };
 
-#ifdef CONFIG_ARCH_OMAP3
-struct omap3_gpio_regs {
-       u32 irqenable1;
-       u32 irqenable2;
-       u32 wake_en;
-       u32 ctrl;
-       u32 oe;
-       u32 leveldetect0;
-       u32 leveldetect1;
-       u32 risingdetect;
-       u32 fallingdetect;
-       u32 dataout;
-};
-
-static struct omap3_gpio_regs gpio_context[OMAP34XX_NR_GPIOS];
-#endif
-
-/*
- * TODO: Cleanup gpio_bank usage as it is having information
- * related to all instances of the device
- */
-static struct gpio_bank *gpio_bank;
-
-/* TODO: Analyze removing gpio_bank_count usage from driver code */
-int gpio_bank_count;
-
 #define GPIO_INDEX(bank, gpio) (gpio % bank->width)
 #define GPIO_BIT(bank, gpio) (1 << GPIO_INDEX(bank, gpio))
+#define GPIO_MOD_CTRL_BIT      BIT(0)
+
+static int irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq)
+{
+       return gpio_irq - bank->irq_base + bank->chip.base;
+}
 
 static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
 {
@@ -102,6 +110,7 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
        else
                l &= ~(1 << gpio);
        __raw_writel(l, reg);
+       bank->context.oe = l;
 }
 
 
@@ -132,6 +141,7 @@ static void _set_gpio_dataout_mask(struct gpio_bank *bank, int gpio, int enable)
        else
                l &= ~gpio_bit;
        __raw_writel(l, reg);
+       bank->context.dataout = l;
 }
 
 static int _get_gpio_datain(struct gpio_bank *bank, int gpio)
@@ -152,7 +162,7 @@ static inline void _gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set)
 {
        int l = __raw_readl(base + reg);
 
-       if (set) 
+       if (set)
                l |= mask;
        else
                l &= ~mask;
@@ -160,6 +170,22 @@ static inline void _gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set)
        __raw_writel(l, base + reg);
 }
 
+static inline void _gpio_dbck_enable(struct gpio_bank *bank)
+{
+       if (bank->dbck_enable_mask && !bank->dbck_enabled) {
+               clk_enable(bank->dbck);
+               bank->dbck_enabled = true;
+       }
+}
+
+static inline void _gpio_dbck_disable(struct gpio_bank *bank)
+{
+       if (bank->dbck_enable_mask && bank->dbck_enabled) {
+               clk_disable(bank->dbck);
+               bank->dbck_enabled = false;
+       }
+}
+
 /**
  * _set_gpio_debounce - low level gpio debounce time
  * @bank: the gpio bank we're acting upon
@@ -188,70 +214,74 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
 
        l = GPIO_BIT(bank, gpio);
 
+       clk_enable(bank->dbck);
        reg = bank->base + bank->regs->debounce;
        __raw_writel(debounce, reg);
 
        reg = bank->base + bank->regs->debounce_en;
        val = __raw_readl(reg);
 
-       if (debounce) {
+       if (debounce)
                val |= l;
-               clk_enable(bank->dbck);
-       } else {
+       else
                val &= ~l;
-               clk_disable(bank->dbck);
-       }
        bank->dbck_enable_mask = val;
 
        __raw_writel(val, reg);
+       clk_disable(bank->dbck);
+       /*
+        * Enable debounce clock per module.
+        * This call is mandatory because in omap_gpio_request() when
+        * *_runtime_get_sync() is called,  _gpio_dbck_enable() within
+        * runtime callbck fails to turn on dbck because dbck_enable_mask
+        * used within _gpio_dbck_enable() is still not initialized at
+        * that point. Therefore we have to enable dbck here.
+        */
+       _gpio_dbck_enable(bank);
+       if (bank->dbck_enable_mask) {
+               bank->context.debounce = debounce;
+               bank->context.debounce_en = val;
+       }
 }
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
-static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio,
+static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio,
                                                int trigger)
 {
        void __iomem *base = bank->base;
        u32 gpio_bit = 1 << gpio;
 
-       if (cpu_is_omap44xx()) {
-               _gpio_rmw(base, OMAP4_GPIO_LEVELDETECT0, gpio_bit,
-                         trigger & IRQ_TYPE_LEVEL_LOW);
-               _gpio_rmw(base, OMAP4_GPIO_LEVELDETECT1, gpio_bit,
-                         trigger & IRQ_TYPE_LEVEL_HIGH);
-               _gpio_rmw(base, OMAP4_GPIO_RISINGDETECT, gpio_bit,
-                         trigger & IRQ_TYPE_EDGE_RISING);
-               _gpio_rmw(base, OMAP4_GPIO_FALLINGDETECT, gpio_bit,
-                         trigger & IRQ_TYPE_EDGE_FALLING);
-       } else {
-               _gpio_rmw(base, OMAP24XX_GPIO_LEVELDETECT0, gpio_bit,
-                         trigger & IRQ_TYPE_LEVEL_LOW);
-               _gpio_rmw(base, OMAP24XX_GPIO_LEVELDETECT1, gpio_bit,
-                         trigger & IRQ_TYPE_LEVEL_HIGH);
-               _gpio_rmw(base, OMAP24XX_GPIO_RISINGDETECT, gpio_bit,
-                         trigger & IRQ_TYPE_EDGE_RISING);
-               _gpio_rmw(base, OMAP24XX_GPIO_FALLINGDETECT, gpio_bit,
-                         trigger & IRQ_TYPE_EDGE_FALLING);
-       }
+       _gpio_rmw(base, bank->regs->leveldetect0, gpio_bit,
+                 trigger & IRQ_TYPE_LEVEL_LOW);
+       _gpio_rmw(base, bank->regs->leveldetect1, gpio_bit,
+                 trigger & IRQ_TYPE_LEVEL_HIGH);
+       _gpio_rmw(base, bank->regs->risingdetect, gpio_bit,
+                 trigger & IRQ_TYPE_EDGE_RISING);
+       _gpio_rmw(base, bank->regs->fallingdetect, gpio_bit,
+                 trigger & IRQ_TYPE_EDGE_FALLING);
+
+       bank->context.leveldetect0 =
+                       __raw_readl(bank->base + bank->regs->leveldetect0);
+       bank->context.leveldetect1 =
+                       __raw_readl(bank->base + bank->regs->leveldetect1);
+       bank->context.risingdetect =
+                       __raw_readl(bank->base + bank->regs->risingdetect);
+       bank->context.fallingdetect =
+                       __raw_readl(bank->base + bank->regs->fallingdetect);
+
        if (likely(!(bank->non_wakeup_gpios & gpio_bit))) {
-               if (cpu_is_omap44xx()) {
-                       _gpio_rmw(base, OMAP4_GPIO_IRQWAKEN0, gpio_bit,
-                                 trigger != 0);
-               } else {
-                       /*
-                        * GPIO wakeup request can only be generated on edge
-                        * transitions
-                        */
-                       if (trigger & IRQ_TYPE_EDGE_BOTH)
-                               __raw_writel(1 << gpio, bank->base
-                                       + OMAP24XX_GPIO_SETWKUENA);
-                       else
-                               __raw_writel(1 << gpio, bank->base
-                                       + OMAP24XX_GPIO_CLEARWKUENA);
-               }
+               _gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0);
+               bank->context.wake_en =
+                       __raw_readl(bank->base + bank->regs->wkup_en);
        }
+
        /* This part needs to be executed always for OMAP{34xx, 44xx} */
-       if (cpu_is_omap34xx() || cpu_is_omap44xx() ||
-                       (bank->non_wakeup_gpios & gpio_bit)) {
+       if (!bank->regs->irqctrl) {
+               /* On omap24xx proceed only when valid GPIO bit is set */
+               if (bank->non_wakeup_gpios) {
+                       if (!(bank->non_wakeup_gpios & gpio_bit))
+                               goto exit;
+               }
+
                /*
                 * Log the edge gpio and manually trigger the IRQ
                 * after resume if the input level changes
@@ -264,17 +294,11 @@ static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio,
                        bank->enabled_non_wakeup_gpios &= ~gpio_bit;
        }
 
-       if (cpu_is_omap44xx()) {
-               bank->level_mask =
-                       __raw_readl(bank->base + OMAP4_GPIO_LEVELDETECT0) |
-                       __raw_readl(bank->base + OMAP4_GPIO_LEVELDETECT1);
-       } else {
-               bank->level_mask =
-                       __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0) |
-                       __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1);
-       }
+exit:
+       bank->level_mask =
+               __raw_readl(bank->base + bank->regs->leveldetect0) |
+               __raw_readl(bank->base + bank->regs->leveldetect1);
 }
-#endif
 
 #ifdef CONFIG_ARCH_OMAP1
 /*
@@ -286,23 +310,10 @@ static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio)
        void __iomem *reg = bank->base;
        u32 l = 0;
 
-       switch (bank->method) {
-       case METHOD_MPUIO:
-               reg += OMAP_MPUIO_GPIO_INT_EDGE / bank->stride;
-               break;
-#ifdef CONFIG_ARCH_OMAP15XX
-       case METHOD_GPIO_1510:
-               reg += OMAP1510_GPIO_INT_CONTROL;
-               break;
-#endif
-#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
-       case METHOD_GPIO_7XX:
-               reg += OMAP7XX_GPIO_INT_CONTROL;
-               break;
-#endif
-       default:
+       if (!bank->regs->irqctrl)
                return;
-       }
+
+       reg += bank->regs->irqctrl;
 
        l = __raw_readl(reg);
        if ((l >> gpio) & 1)
@@ -312,31 +323,21 @@ static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio)
 
        __raw_writel(l, reg);
 }
+#else
+static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) {}
 #endif
 
 static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
 {
        void __iomem *reg = bank->base;
+       void __iomem *base = bank->base;
        u32 l = 0;
 
-       switch (bank->method) {
-#ifdef CONFIG_ARCH_OMAP1
-       case METHOD_MPUIO:
-               reg += OMAP_MPUIO_GPIO_INT_EDGE / bank->stride;
-               l = __raw_readl(reg);
-               if ((trigger & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH)
-                       bank->toggle_mask |= 1 << gpio;
-               if (trigger & IRQ_TYPE_EDGE_RISING)
-                       l |= 1 << gpio;
-               else if (trigger & IRQ_TYPE_EDGE_FALLING)
-                       l &= ~(1 << gpio);
-               else
-                       goto bad;
-               break;
-#endif
-#ifdef CONFIG_ARCH_OMAP15XX
-       case METHOD_GPIO_1510:
-               reg += OMAP1510_GPIO_INT_CONTROL;
+       if (bank->regs->leveldetect0 && bank->regs->wkup_en) {
+               set_gpio_trigger(bank, gpio, trigger);
+       } else if (bank->regs->irqctrl) {
+               reg += bank->regs->irqctrl;
+
                l = __raw_readl(reg);
                if ((trigger & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH)
                        bank->toggle_mask |= 1 << gpio;
@@ -345,15 +346,15 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
                else if (trigger & IRQ_TYPE_EDGE_FALLING)
                        l &= ~(1 << gpio);
                else
-                       goto bad;
-               break;
-#endif
-#ifdef CONFIG_ARCH_OMAP16XX
-       case METHOD_GPIO_1610:
+                       return -EINVAL;
+
+               __raw_writel(l, reg);
+       } else if (bank->regs->edgectrl1) {
                if (gpio & 0x08)
-                       reg += OMAP1610_GPIO_EDGE_CTRL2;
+                       reg += bank->regs->edgectrl2;
                else
-                       reg += OMAP1610_GPIO_EDGE_CTRL1;
+                       reg += bank->regs->edgectrl1;
+
                gpio &= 0x07;
                l = __raw_readl(reg);
                l &= ~(3 << (gpio << 1));
@@ -361,45 +362,19 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
                        l |= 2 << (gpio << 1);
                if (trigger & IRQ_TYPE_EDGE_FALLING)
                        l |= 1 << (gpio << 1);
-               if (trigger)
-                       /* Enable wake-up during idle for dynamic tick */
-                       __raw_writel(1 << gpio, bank->base + OMAP1610_GPIO_SET_WAKEUPENA);
-               else
-                       __raw_writel(1 << gpio, bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA);
-               break;
-#endif
-#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
-       case METHOD_GPIO_7XX:
-               reg += OMAP7XX_GPIO_INT_CONTROL;
-               l = __raw_readl(reg);
-               if ((trigger & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH)
-                       bank->toggle_mask |= 1 << gpio;
-               if (trigger & IRQ_TYPE_EDGE_RISING)
-                       l |= 1 << gpio;
-               else if (trigger & IRQ_TYPE_EDGE_FALLING)
-                       l &= ~(1 << gpio);
-               else
-                       goto bad;
-               break;
-#endif
-#ifdef CONFIG_ARCH_OMAP2PLUS
-       case METHOD_GPIO_24XX:
-       case METHOD_GPIO_44XX:
-               set_24xx_gpio_triggering(bank, gpio, trigger);
-               return 0;
-#endif
-       default:
-               goto bad;
+
+               /* Enable wake-up during idle for dynamic tick */
+               _gpio_rmw(base, bank->regs->wkup_en, 1 << gpio, trigger);
+               bank->context.wake_en =
+                       __raw_readl(bank->base + bank->regs->wkup_en);
+               __raw_writel(l, reg);
        }
-       __raw_writel(l, reg);
        return 0;
-bad:
-       return -EINVAL;
 }
 
 static int gpio_irq_type(struct irq_data *d, unsigned type)
 {
-       struct gpio_bank *bank;
+       struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
        unsigned gpio;
        int retval;
        unsigned long flags;
@@ -407,17 +382,15 @@ static int gpio_irq_type(struct irq_data *d, unsigned type)
        if (!cpu_class_is_omap2() && d->irq > IH_MPUIO_BASE)
                gpio = OMAP_MPUIO(d->irq - IH_MPUIO_BASE);
        else
-               gpio = d->irq - IH_GPIO_BASE;
+               gpio = irq_to_gpio(bank, d->irq);
 
        if (type & ~IRQ_TYPE_SENSE_MASK)
                return -EINVAL;
 
-       /* OMAP1 allows only only edge triggering */
-       if (!cpu_class_is_omap2()
-                       && (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)))
+       if (!bank->regs->leveldetect0 &&
+               (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)))
                return -EINVAL;
 
-       bank = irq_data_get_irq_chip_data(d);
        spin_lock_irqsave(&bank->lock, flags);
        retval = _set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), type);
        spin_unlock_irqrestore(&bank->lock, flags);
@@ -484,6 +457,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
        }
 
        __raw_writel(l, reg);
+       bank->context.irqenable1 = l;
 }
 
 static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
@@ -504,6 +478,7 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
        }
 
        __raw_writel(l, reg);
+       bank->context.irqenable1 = l;
 }
 
 static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable)
@@ -525,7 +500,7 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
        unsigned long flags;
 
        if (bank->non_wakeup_gpios & gpio_bit) {
-               dev_err(bank->dev, 
+               dev_err(bank->dev,
                        "Unable to modify wakeup on non-wakeup GPIO%d\n", gpio);
                return -EINVAL;
        }
@@ -552,14 +527,10 @@ static void _reset_gpio(struct gpio_bank *bank, int gpio)
 /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
 static int gpio_wake_enable(struct irq_data *d, unsigned int enable)
 {
-       unsigned int gpio = d->irq - IH_GPIO_BASE;
-       struct gpio_bank *bank;
-       int retval;
-
-       bank = irq_data_get_irq_chip_data(d);
-       retval = _set_gpio_wakeup(bank, gpio, enable);
+       struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
+       unsigned int gpio = irq_to_gpio(bank, d->irq);
 
-       return retval;
+       return _set_gpio_wakeup(bank, gpio, enable);
 }
 
 static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
@@ -567,38 +538,39 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
        struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
        unsigned long flags;
 
-       spin_lock_irqsave(&bank->lock, flags);
+       /*
+        * If this is the first gpio_request for the bank,
+        * enable the bank module.
+        */
+       if (!bank->mod_usage)
+               pm_runtime_get_sync(bank->dev);
 
+       spin_lock_irqsave(&bank->lock, flags);
        /* Set trigger to none. You need to enable the desired trigger with
         * request_irq() or set_irq_type().
         */
        _set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
 
-#ifdef CONFIG_ARCH_OMAP15XX
-       if (bank->method == METHOD_GPIO_1510) {
-               void __iomem *reg;
+       if (bank->regs->pinctrl) {
+               void __iomem *reg = bank->base + bank->regs->pinctrl;
 
                /* Claim the pin for MPU */
-               reg = bank->base + OMAP1510_GPIO_PIN_CONTROL;
                __raw_writel(__raw_readl(reg) | (1 << offset), reg);
        }
-#endif
-       if (!cpu_class_is_omap1()) {
-               if (!bank->mod_usage) {
-                       void __iomem *reg = bank->base;
-                       u32 ctrl;
-
-                       if (cpu_is_omap24xx() || cpu_is_omap34xx())
-                               reg += OMAP24XX_GPIO_CTRL;
-                       else if (cpu_is_omap44xx())
-                               reg += OMAP4_GPIO_CTRL;
-                       ctrl = __raw_readl(reg);
-                       /* Module is enabled, clocks are not gated */
-                       ctrl &= 0xFFFFFFFE;
-                       __raw_writel(ctrl, reg);
-               }
-               bank->mod_usage |= 1 << offset;
+
+       if (bank->regs->ctrl && !bank->mod_usage) {
+               void __iomem *reg = bank->base + bank->regs->ctrl;
+               u32 ctrl;
+
+               ctrl = __raw_readl(reg);
+               /* Module is enabled, clocks are not gated */
+               ctrl &= ~GPIO_MOD_CTRL_BIT;
+               __raw_writel(ctrl, reg);
+               bank->context.ctrl = ctrl;
        }
+
+       bank->mod_usage |= 1 << offset;
+
        spin_unlock_irqrestore(&bank->lock, flags);
 
        return 0;
@@ -607,48 +579,40 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
 static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
        struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
+       void __iomem *base = bank->base;
        unsigned long flags;
 
        spin_lock_irqsave(&bank->lock, flags);
-#ifdef CONFIG_ARCH_OMAP16XX
-       if (bank->method == METHOD_GPIO_1610) {
-               /* Disable wake-up during idle for dynamic tick */
-               void __iomem *reg = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
-               __raw_writel(1 << offset, reg);
-       }
-#endif
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-       if (bank->method == METHOD_GPIO_24XX) {
-               /* Disable wake-up during idle for dynamic tick */
-               void __iomem *reg = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
-               __raw_writel(1 << offset, reg);
-       }
-#endif
-#ifdef CONFIG_ARCH_OMAP4
-       if (bank->method == METHOD_GPIO_44XX) {
+
+       if (bank->regs->wkup_en) {
                /* Disable wake-up during idle for dynamic tick */
-               void __iomem *reg = bank->base + OMAP4_GPIO_IRQWAKEN0;
-               __raw_writel(1 << offset, reg);
+               _gpio_rmw(base, bank->regs->wkup_en, 1 << offset, 0);
+               bank->context.wake_en =
+                       __raw_readl(bank->base + bank->regs->wkup_en);
        }
-#endif
-       if (!cpu_class_is_omap1()) {
-               bank->mod_usage &= ~(1 << offset);
-               if (!bank->mod_usage) {
-                       void __iomem *reg = bank->base;
-                       u32 ctrl;
-
-                       if (cpu_is_omap24xx() || cpu_is_omap34xx())
-                               reg += OMAP24XX_GPIO_CTRL;
-                       else if (cpu_is_omap44xx())
-                               reg += OMAP4_GPIO_CTRL;
-                       ctrl = __raw_readl(reg);
-                       /* Module is disabled, clocks are gated */
-                       ctrl |= 1;
-                       __raw_writel(ctrl, reg);
-               }
+
+       bank->mod_usage &= ~(1 << offset);
+
+       if (bank->regs->ctrl && !bank->mod_usage) {
+               void __iomem *reg = bank->base + bank->regs->ctrl;
+               u32 ctrl;
+
+               ctrl = __raw_readl(reg);
+               /* Module is disabled, clocks are gated */
+               ctrl |= GPIO_MOD_CTRL_BIT;
+               __raw_writel(ctrl, reg);
+               bank->context.ctrl = ctrl;
        }
+
        _reset_gpio(bank, bank->chip.base + offset);
        spin_unlock_irqrestore(&bank->lock, flags);
+
+       /*
+        * If this is the last gpio to be freed in the bank,
+        * disable the bank module.
+        */
+       if (!bank->mod_usage)
+               pm_runtime_put(bank->dev);
 }
 
 /*
@@ -674,6 +638,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 
        bank = irq_get_handler_data(irq);
        isr_reg = bank->base + bank->regs->irqstatus;
+       pm_runtime_get_sync(bank->dev);
 
        if (WARN_ON(!isr_reg))
                goto exit;
@@ -685,12 +650,8 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
                enabled = _get_gpio_irqbank_mask(bank);
                isr_saved = isr = __raw_readl(isr_reg) & enabled;
 
-               if (cpu_is_omap15xx() && (bank->method == METHOD_MPUIO))
-                       isr &= 0x0000ffff;
-
-               if (cpu_class_is_omap2()) {
+               if (bank->level_mask)
                        level_mask = bank->level_mask & enabled;
-               }
 
                /* clear edge sensitive interrupts before handler(s) are
                called so that we don't miss any interrupt occurred while
@@ -711,14 +672,15 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
                if (!isr)
                        break;
 
-               gpio_irq = bank->virtual_irq_start;
+               gpio_irq = bank->irq_base;
                for (; isr != 0; isr >>= 1, gpio_irq++) {
-                       gpio_index = GPIO_INDEX(bank, irq_to_gpio(gpio_irq));
+                       int gpio = irq_to_gpio(bank, gpio_irq);
 
                        if (!(isr & 1))
                                continue;
 
-#ifdef CONFIG_ARCH_OMAP1
+                       gpio_index = GPIO_INDEX(bank, gpio);
+
                        /*
                         * Some chips can't respond to both rising and falling
                         * at the same time.  If this irq was requested with
@@ -728,7 +690,6 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
                         */
                        if (bank->toggle_mask & (1 << gpio_index))
                                _toggle_gpio_edge_triggering(bank, gpio_index);
-#endif
 
                        generic_handle_irq(gpio_irq);
                }
@@ -740,12 +701,13 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 exit:
        if (!unmasked)
                chained_irq_exit(chip, desc);
+       pm_runtime_put(bank->dev);
 }
 
 static void gpio_irq_shutdown(struct irq_data *d)
 {
-       unsigned int gpio = d->irq - IH_GPIO_BASE;
        struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
+       unsigned int gpio = irq_to_gpio(bank, d->irq);
        unsigned long flags;
 
        spin_lock_irqsave(&bank->lock, flags);
@@ -755,16 +717,16 @@ static void gpio_irq_shutdown(struct irq_data *d)
 
 static void gpio_ack_irq(struct irq_data *d)
 {
-       unsigned int gpio = d->irq - IH_GPIO_BASE;
        struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
+       unsigned int gpio = irq_to_gpio(bank, d->irq);
 
        _clear_gpio_irqstatus(bank, gpio);
 }
 
 static void gpio_mask_irq(struct irq_data *d)
 {
-       unsigned int gpio = d->irq - IH_GPIO_BASE;
        struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
+       unsigned int gpio = irq_to_gpio(bank, d->irq);
        unsigned long flags;
 
        spin_lock_irqsave(&bank->lock, flags);
@@ -775,8 +737,8 @@ static void gpio_mask_irq(struct irq_data *d)
 
 static void gpio_unmask_irq(struct irq_data *d)
 {
-       unsigned int gpio = d->irq - IH_GPIO_BASE;
        struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
+       unsigned int gpio = irq_to_gpio(bank, d->irq);
        unsigned int irq_mask = GPIO_BIT(bank, gpio);
        u32 trigger = irqd_get_trigger_type(d);
        unsigned long flags;
@@ -808,14 +770,6 @@ static struct irq_chip gpio_irq_chip = {
 
 /*---------------------------------------------------------------------*/
 
-#ifdef CONFIG_ARCH_OMAP1
-
-#define bank_is_mpuio(bank)    ((bank)->method == METHOD_MPUIO)
-
-#ifdef CONFIG_ARCH_OMAP16XX
-
-#include <linux/platform_device.h>
-
 static int omap_mpuio_suspend_noirq(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -869,32 +823,16 @@ static struct platform_device omap_mpuio_device = {
        /* could list the /proc/iomem resources */
 };
 
-static inline void mpuio_init(void)
+static inline void mpuio_init(struct gpio_bank *bank)
 {
-       struct gpio_bank *bank = &gpio_bank[0];
        platform_set_drvdata(&omap_mpuio_device, bank);
 
        if (platform_driver_register(&omap_mpuio_driver) == 0)
                (void) platform_device_register(&omap_mpuio_device);
 }
 
-#else
-static inline void mpuio_init(void) {}
-#endif /* 16xx */
-
-#else
-
-#define bank_is_mpuio(bank)    0
-static inline void mpuio_init(void) {}
-
-#endif
-
 /*---------------------------------------------------------------------*/
 
-/* REVISIT these are stupid implementations!  replace by ones that
- * don't switch on METHOD_* and which mostly avoid spinlocks
- */
-
 static int gpio_input(struct gpio_chip *chip, unsigned offset)
 {
        struct gpio_bank *bank;
@@ -982,7 +920,7 @@ static int gpio_2irq(struct gpio_chip *chip, unsigned offset)
        struct gpio_bank *bank;
 
        bank = container_of(chip, struct gpio_bank, chip);
-       return bank->virtual_irq_start + offset;
+       return bank->irq_base + offset;
 }
 
 /*---------------------------------------------------------------------*/
@@ -1007,78 +945,32 @@ static void __init omap_gpio_show_rev(struct gpio_bank *bank)
  */
 static struct lock_class_key gpio_lock_class;
 
-static inline int init_gpio_info(struct platform_device *pdev)
+static void omap_gpio_mod_init(struct gpio_bank *bank)
 {
-       /* TODO: Analyze removing gpio_bank_count usage from driver code */
-       gpio_bank = kzalloc(gpio_bank_count * sizeof(struct gpio_bank),
-                               GFP_KERNEL);
-       if (!gpio_bank) {
-               dev_err(&pdev->dev, "Memory alloc failed for gpio_bank\n");
-               return -ENOMEM;
-       }
-       return 0;
-}
+       void __iomem *base = bank->base;
+       u32 l = 0xffffffff;
 
-/* TODO: Cleanup cpu_is_* checks */
-static void omap_gpio_mod_init(struct gpio_bank *bank, int id)
-{
-       if (cpu_class_is_omap2()) {
-               if (cpu_is_omap44xx()) {
-                       __raw_writel(0xffffffff, bank->base +
-                                       OMAP4_GPIO_IRQSTATUSCLR0);
-                       __raw_writel(0x00000000, bank->base +
-                                        OMAP4_GPIO_DEBOUNCENABLE);
-                       /* Initialize interface clk ungated, module enabled */
-                       __raw_writel(0, bank->base + OMAP4_GPIO_CTRL);
-               } else if (cpu_is_omap34xx()) {
-                       __raw_writel(0x00000000, bank->base +
-                                       OMAP24XX_GPIO_IRQENABLE1);
-                       __raw_writel(0xffffffff, bank->base +
-                                       OMAP24XX_GPIO_IRQSTATUS1);
-                       __raw_writel(0x00000000, bank->base +
-                                       OMAP24XX_GPIO_DEBOUNCE_EN);
-
-                       /* Initialize interface clk ungated, module enabled */
-                       __raw_writel(0, bank->base + OMAP24XX_GPIO_CTRL);
-               } else if (cpu_is_omap24xx()) {
-                       static const u32 non_wakeup_gpios[] = {
-                               0xe203ffc0, 0x08700040
-                       };
-                       if (id < ARRAY_SIZE(non_wakeup_gpios))
-                               bank->non_wakeup_gpios = non_wakeup_gpios[id];
-               }
-       } else if (cpu_class_is_omap1()) {
-               if (bank_is_mpuio(bank))
-                       __raw_writew(0xffff, bank->base +
-                               OMAP_MPUIO_GPIO_MASKIT / bank->stride);
-               if (cpu_is_omap15xx() && bank->method == METHOD_GPIO_1510) {
-                       __raw_writew(0xffff, bank->base
-                                               + OMAP1510_GPIO_INT_MASK);
-                       __raw_writew(0x0000, bank->base
-                                               + OMAP1510_GPIO_INT_STATUS);
-               }
-               if (cpu_is_omap16xx() && bank->method == METHOD_GPIO_1610) {
-                       __raw_writew(0x0000, bank->base
-                                               + OMAP1610_GPIO_IRQENABLE1);
-                       __raw_writew(0xffff, bank->base
-                                               + OMAP1610_GPIO_IRQSTATUS1);
-                       __raw_writew(0x0014, bank->base
-                                               + OMAP1610_GPIO_SYSCONFIG);
+       if (bank->width == 16)
+               l = 0xffff;
 
-                       /*
-                        * Enable system clock for GPIO module.
-                        * The CAM_CLK_CTRL *is* really the right place.
-                        */
-                       omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04,
-                                               ULPD_CAM_CLK_CTRL);
-               }
-               if (cpu_is_omap7xx() && bank->method == METHOD_GPIO_7XX) {
-                       __raw_writel(0xffffffff, bank->base
-                                               + OMAP7XX_GPIO_INT_MASK);
-                       __raw_writel(0x00000000, bank->base
-                                               + OMAP7XX_GPIO_INT_STATUS);
-               }
+       if (bank->is_mpuio) {
+               __raw_writel(l, bank->base + bank->regs->irqenable);
+               return;
        }
+
+       _gpio_rmw(base, bank->regs->irqenable, l, bank->regs->irqenable_inv);
+       _gpio_rmw(base, bank->regs->irqstatus, l,
+                                       bank->regs->irqenable_inv == false);
+       _gpio_rmw(base, bank->regs->irqenable, l, bank->regs->debounce_en != 0);
+       _gpio_rmw(base, bank->regs->irqenable, l, bank->regs->ctrl != 0);
+       if (bank->regs->debounce_en)
+               _gpio_rmw(base, bank->regs->debounce_en, 0, 1);
+
+       /* Save OE default value (0xffffffff) in the context */
+       bank->context.oe = __raw_readl(bank->base + bank->regs->direction);
+        /* Initialize interface clk ungated, module enabled */
+       if (bank->regs->ctrl)
+               _gpio_rmw(base, bank->regs->ctrl, 0, 1);
 }
 
 static __init void
@@ -1101,8 +993,8 @@ omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start,
        ct->chip.irq_mask = irq_gc_mask_set_bit;
        ct->chip.irq_unmask = irq_gc_mask_clr_bit;
        ct->chip.irq_set_type = gpio_irq_type;
-       /* REVISIT: assuming only 16xx supports MPUIO wake events */
-       if (cpu_is_omap16xx())
+
+       if (bank->regs->wkup_en)
                ct->chip.irq_set_wake = gpio_wake_enable,
 
        ct->regs.mask = OMAP_MPUIO_GPIO_INT / bank->stride;
@@ -1115,7 +1007,6 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank)
        int j;
        static int gpio;
 
-       bank->mod_usage = 0;
        /*
         * REVISIT eventually switch from OMAP-specific gpio structs
         * over to the generic ones
@@ -1128,11 +1019,10 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank)
        bank->chip.set_debounce = gpio_debounce;
        bank->chip.set = gpio_set;
        bank->chip.to_irq = gpio_2irq;
-       if (bank_is_mpuio(bank)) {
+       if (bank->is_mpuio) {
                bank->chip.label = "mpuio";
-#ifdef CONFIG_ARCH_OMAP16XX
-               bank->chip.dev = &omap_mpuio_device.dev;
-#endif
+               if (bank->regs->wkup_en)
+                       bank->chip.dev = &omap_mpuio_device.dev;
                bank->chip.base = OMAP_MPUIO(0);
        } else {
                bank->chip.label = "gpio";
@@ -1143,11 +1033,10 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank)
 
        gpiochip_add(&bank->chip);
 
-       for (j = bank->virtual_irq_start;
-                    j < bank->virtual_irq_start + bank->width; j++) {
+       for (j = bank->irq_base; j < bank->irq_base + bank->width; j++) {
                irq_set_lockdep_class(j, &gpio_lock_class);
                irq_set_chip_data(j, bank);
-               if (bank_is_mpuio(bank)) {
+               if (bank->is_mpuio) {
                        omap_mpuio_alloc_gc(bank, j, bank->width);
                } else {
                        irq_set_chip(j, &gpio_irq_chip);
@@ -1159,45 +1048,58 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank)
        irq_set_handler_data(bank->irq, bank);
 }
 
+static const struct of_device_id omap_gpio_match[];
+
 static int __devinit omap_gpio_probe(struct platform_device *pdev)
 {
-       static int gpio_init_done;
+       struct device *dev = &pdev->dev;
+       struct device_node *node = dev->of_node;
+       const struct of_device_id *match;
        struct omap_gpio_platform_data *pdata;
        struct resource *res;
-       int id;
        struct gpio_bank *bank;
+       int ret = 0;
 
-       if (!pdev->dev.platform_data)
-               return -EINVAL;
+       match = of_match_device(of_match_ptr(omap_gpio_match), dev);
 
-       pdata = pdev->dev.platform_data;
-
-       if (!gpio_init_done) {
-               int ret;
+       pdata = match ? match->data : dev->platform_data;
+       if (!pdata)
+               return -EINVAL;
 
-               ret = init_gpio_info(pdev);
-               if (ret)
-                       return ret;
+       bank = devm_kzalloc(&pdev->dev, sizeof(struct gpio_bank), GFP_KERNEL);
+       if (!bank) {
+               dev_err(dev, "Memory alloc failed\n");
+               return -ENOMEM;
        }
 
-       id = pdev->id;
-       bank = &gpio_bank[id];
-
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (unlikely(!res)) {
-               dev_err(&pdev->dev, "GPIO Bank %i Invalid IRQ resource\n", id);
+               dev_err(dev, "Invalid IRQ resource\n");
                return -ENODEV;
        }
 
        bank->irq = res->start;
-       bank->virtual_irq_start = pdata->virtual_irq_start;
-       bank->method = pdata->bank_type;
-       bank->dev = &pdev->dev;
+       bank->dev = dev;
        bank->dbck_flag = pdata->dbck_flag;
        bank->stride = pdata->bank_stride;
        bank->width = pdata->bank_width;
-
+       bank->is_mpuio = pdata->is_mpuio;
+       bank->non_wakeup_gpios = pdata->non_wakeup_gpios;
+       bank->loses_context = pdata->loses_context;
+       bank->get_context_loss_count = pdata->get_context_loss_count;
        bank->regs = pdata->regs;
+#ifdef CONFIG_OF_GPIO
+       bank->chip.of_node = of_node_get(node);
+#endif
+
+       bank->irq_base = irq_alloc_descs(-1, 0, bank->width, 0);
+       if (bank->irq_base < 0) {
+               dev_err(dev, "Couldn't allocate IRQ numbers\n");
+               return -ENODEV;
+       }
+
+       bank->domain = irq_domain_add_legacy(node, bank->width, bank->irq_base,
+                                            0, &irq_domain_simple_ops, NULL);
 
        if (bank->regs->set_dataout && bank->regs->clr_dataout)
                bank->set_dataout = _set_gpio_dataout_reg;
@@ -1209,369 +1111,391 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
        /* Static mapping, never released */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (unlikely(!res)) {
-               dev_err(&pdev->dev, "GPIO Bank %i Invalid mem resource\n", id);
+               dev_err(dev, "Invalid mem resource\n");
                return -ENODEV;
        }
 
-       bank->base = ioremap(res->start, resource_size(res));
+       if (!devm_request_mem_region(dev, res->start, resource_size(res),
+                                    pdev->name)) {
+               dev_err(dev, "Region already claimed\n");
+               return -EBUSY;
+       }
+
+       bank->base = devm_ioremap(dev, res->start, resource_size(res));
        if (!bank->base) {
-               dev_err(&pdev->dev, "Could not ioremap gpio bank%i\n", id);
+               dev_err(dev, "Could not ioremap\n");
                return -ENOMEM;
        }
 
+       platform_set_drvdata(pdev, bank);
+
        pm_runtime_enable(bank->dev);
+       pm_runtime_irq_safe(bank->dev);
        pm_runtime_get_sync(bank->dev);
 
-       omap_gpio_mod_init(bank, id);
+       if (bank->is_mpuio)
+               mpuio_init(bank);
+
+       omap_gpio_mod_init(bank);
        omap_gpio_chip_init(bank);
        omap_gpio_show_rev(bank);
 
-       if (!gpio_init_done)
-               gpio_init_done = 1;
+       pm_runtime_put(bank->dev);
 
-       return 0;
+       list_add_tail(&bank->node, &omap_gpio_list);
+
+       return ret;
 }
 
-#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS)
-static int omap_gpio_suspend(void)
+#ifdef CONFIG_ARCH_OMAP2PLUS
+
+#if defined(CONFIG_PM_SLEEP)
+static int omap_gpio_suspend(struct device *dev)
 {
-       int i;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct gpio_bank *bank = platform_get_drvdata(pdev);
+       void __iomem *base = bank->base;
+       void __iomem *wakeup_enable;
+       unsigned long flags;
 
-       if (!cpu_class_is_omap2() && !cpu_is_omap16xx())
+       if (!bank->mod_usage || !bank->loses_context)
                return 0;
 
-       for (i = 0; i < gpio_bank_count; i++) {
-               struct gpio_bank *bank = &gpio_bank[i];
-               void __iomem *wake_status;
-               void __iomem *wake_clear;
-               void __iomem *wake_set;
-               unsigned long flags;
-
-               switch (bank->method) {
-#ifdef CONFIG_ARCH_OMAP16XX
-               case METHOD_GPIO_1610:
-                       wake_status = bank->base + OMAP1610_GPIO_WAKEUPENABLE;
-                       wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
-                       wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
-                       break;
-#endif
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-               case METHOD_GPIO_24XX:
-                       wake_status = bank->base + OMAP24XX_GPIO_WAKE_EN;
-                       wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
-                       wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA;
-                       break;
-#endif
-#ifdef CONFIG_ARCH_OMAP4
-               case METHOD_GPIO_44XX:
-                       wake_status = bank->base + OMAP4_GPIO_IRQWAKEN0;
-                       wake_clear = bank->base + OMAP4_GPIO_IRQWAKEN0;
-                       wake_set = bank->base + OMAP4_GPIO_IRQWAKEN0;
-                       break;
-#endif
-               default:
-                       continue;
-               }
+       if (!bank->regs->wkup_en || !bank->suspend_wakeup)
+               return 0;
 
-               spin_lock_irqsave(&bank->lock, flags);
-               bank->saved_wakeup = __raw_readl(wake_status);
-               __raw_writel(0xffffffff, wake_clear);
-               __raw_writel(bank->suspend_wakeup, wake_set);
-               spin_unlock_irqrestore(&bank->lock, flags);
-       }
+       wakeup_enable = bank->base + bank->regs->wkup_en;
+
+       spin_lock_irqsave(&bank->lock, flags);
+       bank->saved_wakeup = __raw_readl(wakeup_enable);
+       _gpio_rmw(base, bank->regs->wkup_en, 0xffffffff, 0);
+       _gpio_rmw(base, bank->regs->wkup_en, bank->suspend_wakeup, 1);
+       spin_unlock_irqrestore(&bank->lock, flags);
 
        return 0;
 }
 
-static void omap_gpio_resume(void)
+static int omap_gpio_resume(struct device *dev)
 {
-       int i;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct gpio_bank *bank = platform_get_drvdata(pdev);
+       void __iomem *base = bank->base;
+       unsigned long flags;
 
-       if (!cpu_class_is_omap2() && !cpu_is_omap16xx())
-               return;
+       if (!bank->mod_usage || !bank->loses_context)
+               return 0;
 
-       for (i = 0; i < gpio_bank_count; i++) {
-               struct gpio_bank *bank = &gpio_bank[i];
-               void __iomem *wake_clear;
-               void __iomem *wake_set;
-               unsigned long flags;
-
-               switch (bank->method) {
-#ifdef CONFIG_ARCH_OMAP16XX
-               case METHOD_GPIO_1610:
-                       wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
-                       wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
-                       break;
-#endif
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-               case METHOD_GPIO_24XX:
-                       wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
-                       wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA;
-                       break;
-#endif
-#ifdef CONFIG_ARCH_OMAP4
-               case METHOD_GPIO_44XX:
-                       wake_clear = bank->base + OMAP4_GPIO_IRQWAKEN0;
-                       wake_set = bank->base + OMAP4_GPIO_IRQWAKEN0;
-                       break;
-#endif
-               default:
-                       continue;
-               }
+       if (!bank->regs->wkup_en || !bank->saved_wakeup)
+               return 0;
 
-               spin_lock_irqsave(&bank->lock, flags);
-               __raw_writel(0xffffffff, wake_clear);
-               __raw_writel(bank->saved_wakeup, wake_set);
-               spin_unlock_irqrestore(&bank->lock, flags);
-       }
-}
+       spin_lock_irqsave(&bank->lock, flags);
+       _gpio_rmw(base, bank->regs->wkup_en, 0xffffffff, 0);
+       _gpio_rmw(base, bank->regs->wkup_en, bank->saved_wakeup, 1);
+       spin_unlock_irqrestore(&bank->lock, flags);
 
-static struct syscore_ops omap_gpio_syscore_ops = {
-       .suspend        = omap_gpio_suspend,
-       .resume         = omap_gpio_resume,
-};
+       return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
 
-#endif
+#if defined(CONFIG_PM_RUNTIME)
+static void omap_gpio_restore_context(struct gpio_bank *bank);
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
+static int omap_gpio_runtime_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct gpio_bank *bank = platform_get_drvdata(pdev);
+       u32 l1 = 0, l2 = 0;
+       unsigned long flags;
 
-static int workaround_enabled;
+       spin_lock_irqsave(&bank->lock, flags);
+       if (bank->power_mode != OFF_MODE) {
+               bank->power_mode = 0;
+               goto update_gpio_context_count;
+       }
+       /*
+        * If going to OFF, remove triggering for all
+        * non-wakeup GPIOs.  Otherwise spurious IRQs will be
+        * generated.  See OMAP2420 Errata item 1.101.
+        */
+       if (!(bank->enabled_non_wakeup_gpios))
+               goto update_gpio_context_count;
 
-void omap2_gpio_prepare_for_idle(int off_mode)
-{
-       int i, c = 0;
-       int min = 0;
+       bank->saved_datain = __raw_readl(bank->base +
+                                               bank->regs->datain);
+       l1 = __raw_readl(bank->base + bank->regs->fallingdetect);
+       l2 = __raw_readl(bank->base + bank->regs->risingdetect);
 
-       if (cpu_is_omap34xx())
-               min = 1;
+       bank->saved_fallingdetect = l1;
+       bank->saved_risingdetect = l2;
+       l1 &= ~bank->enabled_non_wakeup_gpios;
+       l2 &= ~bank->enabled_non_wakeup_gpios;
 
-       for (i = min; i < gpio_bank_count; i++) {
-               struct gpio_bank *bank = &gpio_bank[i];
-               u32 l1 = 0, l2 = 0;
-               int j;
+       __raw_writel(l1, bank->base + bank->regs->fallingdetect);
+       __raw_writel(l2, bank->base + bank->regs->risingdetect);
 
-               for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
-                       clk_disable(bank->dbck);
+       bank->workaround_enabled = true;
 
-               if (!off_mode)
-                       continue;
+update_gpio_context_count:
+       if (bank->get_context_loss_count)
+               bank->context_loss_count =
+                               bank->get_context_loss_count(bank->dev);
 
-               /* If going to OFF, remove triggering for all
-                * non-wakeup GPIOs.  Otherwise spurious IRQs will be
-                * generated.  See OMAP2420 Errata item 1.101. */
-               if (!(bank->enabled_non_wakeup_gpios))
-                       continue;
+       _gpio_dbck_disable(bank);
+       spin_unlock_irqrestore(&bank->lock, flags);
 
-               if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
-                       bank->saved_datain = __raw_readl(bank->base +
-                                       OMAP24XX_GPIO_DATAIN);
-                       l1 = __raw_readl(bank->base +
-                                       OMAP24XX_GPIO_FALLINGDETECT);
-                       l2 = __raw_readl(bank->base +
-                                       OMAP24XX_GPIO_RISINGDETECT);
-               }
+       return 0;
+}
 
-               if (cpu_is_omap44xx()) {
-                       bank->saved_datain = __raw_readl(bank->base +
-                                               OMAP4_GPIO_DATAIN);
-                       l1 = __raw_readl(bank->base +
-                                               OMAP4_GPIO_FALLINGDETECT);
-                       l2 = __raw_readl(bank->base +
-                                               OMAP4_GPIO_RISINGDETECT);
-               }
+static int omap_gpio_runtime_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct gpio_bank *bank = platform_get_drvdata(pdev);
+       int context_lost_cnt_after;
+       u32 l = 0, gen, gen0, gen1;
+       unsigned long flags;
 
-               bank->saved_fallingdetect = l1;
-               bank->saved_risingdetect = l2;
-               l1 &= ~bank->enabled_non_wakeup_gpios;
-               l2 &= ~bank->enabled_non_wakeup_gpios;
+       spin_lock_irqsave(&bank->lock, flags);
+       _gpio_dbck_enable(bank);
+       if (!bank->enabled_non_wakeup_gpios || !bank->workaround_enabled) {
+               spin_unlock_irqrestore(&bank->lock, flags);
+               return 0;
+       }
 
-               if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
-                       __raw_writel(l1, bank->base +
-                                       OMAP24XX_GPIO_FALLINGDETECT);
-                       __raw_writel(l2, bank->base +
-                                       OMAP24XX_GPIO_RISINGDETECT);
+       if (bank->get_context_loss_count) {
+               context_lost_cnt_after =
+                       bank->get_context_loss_count(bank->dev);
+               if (context_lost_cnt_after != bank->context_loss_count ||
+                                               !context_lost_cnt_after) {
+                       omap_gpio_restore_context(bank);
+               } else {
+                       spin_unlock_irqrestore(&bank->lock, flags);
+                       return 0;
                }
+       }
 
-               if (cpu_is_omap44xx()) {
-                       __raw_writel(l1, bank->base + OMAP4_GPIO_FALLINGDETECT);
-                       __raw_writel(l2, bank->base + OMAP4_GPIO_RISINGDETECT);
-               }
+       __raw_writel(bank->saved_fallingdetect,
+                       bank->base + bank->regs->fallingdetect);
+       __raw_writel(bank->saved_risingdetect,
+                       bank->base + bank->regs->risingdetect);
+       l = __raw_readl(bank->base + bank->regs->datain);
 
-               c++;
-       }
-       if (!c) {
-               workaround_enabled = 0;
-               return;
-       }
-       workaround_enabled = 1;
-}
+       /*
+        * Check if any of the non-wakeup interrupt GPIOs have changed
+        * state.  If so, generate an IRQ by software.  This is
+        * horribly racy, but it's the best we can do to work around
+        * this silicon bug.
+        */
+       l ^= bank->saved_datain;
+       l &= bank->enabled_non_wakeup_gpios;
 
-void omap2_gpio_resume_after_idle(void)
-{
-       int i;
-       int min = 0;
+       /*
+        * No need to generate IRQs for the rising edge for gpio IRQs
+        * configured with falling edge only; and vice versa.
+        */
+       gen0 = l & bank->saved_fallingdetect;
+       gen0 &= bank->saved_datain;
 
-       if (cpu_is_omap34xx())
-               min = 1;
-       for (i = min; i < gpio_bank_count; i++) {
-               struct gpio_bank *bank = &gpio_bank[i];
-               u32 l = 0, gen, gen0, gen1;
-               int j;
+       gen1 = l & bank->saved_risingdetect;
+       gen1 &= ~(bank->saved_datain);
 
-               for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
-                       clk_enable(bank->dbck);
+       /* FIXME: Consider GPIO IRQs with level detections properly! */
+       gen = l & (~(bank->saved_fallingdetect) & ~(bank->saved_risingdetect));
+       /* Consider all GPIO IRQs needed to be updated */
+       gen |= gen0 | gen1;
 
-               if (!workaround_enabled)
-                       continue;
+       if (gen) {
+               u32 old0, old1;
 
-               if (!(bank->enabled_non_wakeup_gpios))
-                       continue;
+               old0 = __raw_readl(bank->base + bank->regs->leveldetect0);
+               old1 = __raw_readl(bank->base + bank->regs->leveldetect1);
 
                if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
-                       __raw_writel(bank->saved_fallingdetect,
-                                bank->base + OMAP24XX_GPIO_FALLINGDETECT);
-                       __raw_writel(bank->saved_risingdetect,
-                                bank->base + OMAP24XX_GPIO_RISINGDETECT);
-                       l = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN);
+                       __raw_writel(old0 | gen, bank->base +
+                                               bank->regs->leveldetect0);
+                       __raw_writel(old1 | gen, bank->base +
+                                               bank->regs->leveldetect1);
                }
 
                if (cpu_is_omap44xx()) {
-                       __raw_writel(bank->saved_fallingdetect,
-                                bank->base + OMAP4_GPIO_FALLINGDETECT);
-                       __raw_writel(bank->saved_risingdetect,
-                                bank->base + OMAP4_GPIO_RISINGDETECT);
-                       l = __raw_readl(bank->base + OMAP4_GPIO_DATAIN);
-               }
-
-               /* Check if any of the non-wakeup interrupt GPIOs have changed
-                * state.  If so, generate an IRQ by software.  This is
-                * horribly racy, but it's the best we can do to work around
-                * this silicon bug. */
-               l ^= bank->saved_datain;
-               l &= bank->enabled_non_wakeup_gpios;
-
-               /*
-                * No need to generate IRQs for the rising edge for gpio IRQs
-                * configured with falling edge only; and vice versa.
-                */
-               gen0 = l & bank->saved_fallingdetect;
-               gen0 &= bank->saved_datain;
-
-               gen1 = l & bank->saved_risingdetect;
-               gen1 &= ~(bank->saved_datain);
-
-               /* FIXME: Consider GPIO IRQs with level detections properly! */
-               gen = l & (~(bank->saved_fallingdetect) &
-                               ~(bank->saved_risingdetect));
-               /* Consider all GPIO IRQs needed to be updated */
-               gen |= gen0 | gen1;
-
-               if (gen) {
-                       u32 old0, old1;
-
-                       if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
-                               old0 = __raw_readl(bank->base +
-                                       OMAP24XX_GPIO_LEVELDETECT0);
-                               old1 = __raw_readl(bank->base +
-                                       OMAP24XX_GPIO_LEVELDETECT1);
-                               __raw_writel(old0 | gen, bank->base +
-                                       OMAP24XX_GPIO_LEVELDETECT0);
-                               __raw_writel(old1 | gen, bank->base +
-                                       OMAP24XX_GPIO_LEVELDETECT1);
-                               __raw_writel(old0, bank->base +
-                                       OMAP24XX_GPIO_LEVELDETECT0);
-                               __raw_writel(old1, bank->base +
-                                       OMAP24XX_GPIO_LEVELDETECT1);
-                       }
-
-                       if (cpu_is_omap44xx()) {
-                               old0 = __raw_readl(bank->base +
-                                               OMAP4_GPIO_LEVELDETECT0);
-                               old1 = __raw_readl(bank->base +
-                                               OMAP4_GPIO_LEVELDETECT1);
-                               __raw_writel(old0 | l, bank->base +
-                                               OMAP4_GPIO_LEVELDETECT0);
-                               __raw_writel(old1 | l, bank->base +
-                                               OMAP4_GPIO_LEVELDETECT1);
-                               __raw_writel(old0, bank->base +
-                                               OMAP4_GPIO_LEVELDETECT0);
-                               __raw_writel(old1, bank->base +
-                                               OMAP4_GPIO_LEVELDETECT1);
-                       }
+                       __raw_writel(old0 | l, bank->base +
+                                               bank->regs->leveldetect0);
+                       __raw_writel(old1 | l, bank->base +
+                                               bank->regs->leveldetect1);
                }
+               __raw_writel(old0, bank->base + bank->regs->leveldetect0);
+               __raw_writel(old1, bank->base + bank->regs->leveldetect1);
        }
 
+       bank->workaround_enabled = false;
+       spin_unlock_irqrestore(&bank->lock, flags);
+
+       return 0;
 }
+#endif /* CONFIG_PM_RUNTIME */
 
-#endif
+void omap2_gpio_prepare_for_idle(int pwr_mode)
+{
+       struct gpio_bank *bank;
 
-#ifdef CONFIG_ARCH_OMAP3
-/* save the registers of bank 2-6 */
-void omap_gpio_save_context(void)
+       list_for_each_entry(bank, &omap_gpio_list, node) {
+               if (!bank->mod_usage || !bank->loses_context)
+                       continue;
+
+               bank->power_mode = pwr_mode;
+
+               pm_runtime_put_sync_suspend(bank->dev);
+       }
+}
+
+void omap2_gpio_resume_after_idle(void)
 {
-       int i;
-
-       /* saving banks from 2-6 only since GPIO1 is in WKUP */
-       for (i = 1; i < gpio_bank_count; i++) {
-               struct gpio_bank *bank = &gpio_bank[i];
-               gpio_context[i].irqenable1 =
-                       __raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE1);
-               gpio_context[i].irqenable2 =
-                       __raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE2);
-               gpio_context[i].wake_en =
-                       __raw_readl(bank->base + OMAP24XX_GPIO_WAKE_EN);
-               gpio_context[i].ctrl =
-                       __raw_readl(bank->base + OMAP24XX_GPIO_CTRL);
-               gpio_context[i].oe =
-                       __raw_readl(bank->base + OMAP24XX_GPIO_OE);
-               gpio_context[i].leveldetect0 =
-                       __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0);
-               gpio_context[i].leveldetect1 =
-                       __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1);
-               gpio_context[i].risingdetect =
-                       __raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT);
-               gpio_context[i].fallingdetect =
-                       __raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT);
-               gpio_context[i].dataout =
-                       __raw_readl(bank->base + OMAP24XX_GPIO_DATAOUT);
+       struct gpio_bank *bank;
+
+       list_for_each_entry(bank, &omap_gpio_list, node) {
+               if (!bank->mod_usage || !bank->loses_context)
+                       continue;
+
+               pm_runtime_get_sync(bank->dev);
        }
 }
 
-/* restore the required registers of bank 2-6 */
-void omap_gpio_restore_context(void)
+#if defined(CONFIG_PM_RUNTIME)
+static void omap_gpio_restore_context(struct gpio_bank *bank)
 {
-       int i;
-
-       for (i = 1; i < gpio_bank_count; i++) {
-               struct gpio_bank *bank = &gpio_bank[i];
-               __raw_writel(gpio_context[i].irqenable1,
-                               bank->base + OMAP24XX_GPIO_IRQENABLE1);
-               __raw_writel(gpio_context[i].irqenable2,
-                               bank->base + OMAP24XX_GPIO_IRQENABLE2);
-               __raw_writel(gpio_context[i].wake_en,
-                               bank->base + OMAP24XX_GPIO_WAKE_EN);
-               __raw_writel(gpio_context[i].ctrl,
-                               bank->base + OMAP24XX_GPIO_CTRL);
-               __raw_writel(gpio_context[i].oe,
-                               bank->base + OMAP24XX_GPIO_OE);
-               __raw_writel(gpio_context[i].leveldetect0,
-                               bank->base + OMAP24XX_GPIO_LEVELDETECT0);
-               __raw_writel(gpio_context[i].leveldetect1,
-                               bank->base + OMAP24XX_GPIO_LEVELDETECT1);
-               __raw_writel(gpio_context[i].risingdetect,
-                               bank->base + OMAP24XX_GPIO_RISINGDETECT);
-               __raw_writel(gpio_context[i].fallingdetect,
-                               bank->base + OMAP24XX_GPIO_FALLINGDETECT);
-               __raw_writel(gpio_context[i].dataout,
-                               bank->base + OMAP24XX_GPIO_DATAOUT);
+       __raw_writel(bank->context.wake_en,
+                               bank->base + bank->regs->wkup_en);
+       __raw_writel(bank->context.ctrl, bank->base + bank->regs->ctrl);
+       __raw_writel(bank->context.leveldetect0,
+                               bank->base + bank->regs->leveldetect0);
+       __raw_writel(bank->context.leveldetect1,
+                               bank->base + bank->regs->leveldetect1);
+       __raw_writel(bank->context.risingdetect,
+                               bank->base + bank->regs->risingdetect);
+       __raw_writel(bank->context.fallingdetect,
+                               bank->base + bank->regs->fallingdetect);
+       if (bank->regs->set_dataout && bank->regs->clr_dataout)
+               __raw_writel(bank->context.dataout,
+                               bank->base + bank->regs->set_dataout);
+       else
+               __raw_writel(bank->context.dataout,
+                               bank->base + bank->regs->dataout);
+       __raw_writel(bank->context.oe, bank->base + bank->regs->direction);
+
+       if (bank->dbck_enable_mask) {
+               __raw_writel(bank->context.debounce, bank->base +
+                                       bank->regs->debounce);
+               __raw_writel(bank->context.debounce_en,
+                                       bank->base + bank->regs->debounce_en);
        }
+
+       __raw_writel(bank->context.irqenable1,
+                               bank->base + bank->regs->irqenable);
+       __raw_writel(bank->context.irqenable2,
+                               bank->base + bank->regs->irqenable2);
 }
+#endif /* CONFIG_PM_RUNTIME */
+#else
+#define omap_gpio_suspend NULL
+#define omap_gpio_resume NULL
+#define omap_gpio_runtime_suspend NULL
+#define omap_gpio_runtime_resume NULL
+#endif
+
+static const struct dev_pm_ops gpio_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(omap_gpio_suspend, omap_gpio_resume)
+       SET_RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume,
+                                                                       NULL)
+};
+
+#if defined(CONFIG_OF)
+static struct omap_gpio_reg_offs omap2_gpio_regs = {
+       .revision =             OMAP24XX_GPIO_REVISION,
+       .direction =            OMAP24XX_GPIO_OE,
+       .datain =               OMAP24XX_GPIO_DATAIN,
+       .dataout =              OMAP24XX_GPIO_DATAOUT,
+       .set_dataout =          OMAP24XX_GPIO_SETDATAOUT,
+       .clr_dataout =          OMAP24XX_GPIO_CLEARDATAOUT,
+       .irqstatus =            OMAP24XX_GPIO_IRQSTATUS1,
+       .irqstatus2 =           OMAP24XX_GPIO_IRQSTATUS2,
+       .irqenable =            OMAP24XX_GPIO_IRQENABLE1,
+       .irqenable2 =           OMAP24XX_GPIO_IRQENABLE2,
+       .set_irqenable =        OMAP24XX_GPIO_SETIRQENABLE1,
+       .clr_irqenable =        OMAP24XX_GPIO_CLEARIRQENABLE1,
+       .debounce =             OMAP24XX_GPIO_DEBOUNCE_VAL,
+       .debounce_en =          OMAP24XX_GPIO_DEBOUNCE_EN,
+       .ctrl =                 OMAP24XX_GPIO_CTRL,
+       .wkup_en =              OMAP24XX_GPIO_WAKE_EN,
+       .leveldetect0 =         OMAP24XX_GPIO_LEVELDETECT0,
+       .leveldetect1 =         OMAP24XX_GPIO_LEVELDETECT1,
+       .risingdetect =         OMAP24XX_GPIO_RISINGDETECT,
+       .fallingdetect =        OMAP24XX_GPIO_FALLINGDETECT,
+};
+
+static struct omap_gpio_reg_offs omap4_gpio_regs = {
+       .revision =             OMAP4_GPIO_REVISION,
+       .direction =            OMAP4_GPIO_OE,
+       .datain =               OMAP4_GPIO_DATAIN,
+       .dataout =              OMAP4_GPIO_DATAOUT,
+       .set_dataout =          OMAP4_GPIO_SETDATAOUT,
+       .clr_dataout =          OMAP4_GPIO_CLEARDATAOUT,
+       .irqstatus =            OMAP4_GPIO_IRQSTATUS0,
+       .irqstatus2 =           OMAP4_GPIO_IRQSTATUS1,
+       .irqenable =            OMAP4_GPIO_IRQSTATUSSET0,
+       .irqenable2 =           OMAP4_GPIO_IRQSTATUSSET1,
+       .set_irqenable =        OMAP4_GPIO_IRQSTATUSSET0,
+       .clr_irqenable =        OMAP4_GPIO_IRQSTATUSCLR0,
+       .debounce =             OMAP4_GPIO_DEBOUNCINGTIME,
+       .debounce_en =          OMAP4_GPIO_DEBOUNCENABLE,
+       .ctrl =                 OMAP4_GPIO_CTRL,
+       .wkup_en =              OMAP4_GPIO_IRQWAKEN0,
+       .leveldetect0 =         OMAP4_GPIO_LEVELDETECT0,
+       .leveldetect1 =         OMAP4_GPIO_LEVELDETECT1,
+       .risingdetect =         OMAP4_GPIO_RISINGDETECT,
+       .fallingdetect =        OMAP4_GPIO_FALLINGDETECT,
+};
+
+static struct omap_gpio_platform_data omap2_pdata = {
+       .regs = &omap2_gpio_regs,
+       .bank_width = 32,
+       .dbck_flag = false,
+};
+
+static struct omap_gpio_platform_data omap3_pdata = {
+       .regs = &omap2_gpio_regs,
+       .bank_width = 32,
+       .dbck_flag = true,
+};
+
+static struct omap_gpio_platform_data omap4_pdata = {
+       .regs = &omap4_gpio_regs,
+       .bank_width = 32,
+       .dbck_flag = true,
+};
+
+static const struct of_device_id omap_gpio_match[] = {
+       {
+               .compatible = "ti,omap4-gpio",
+               .data = &omap4_pdata,
+       },
+       {
+               .compatible = "ti,omap3-gpio",
+               .data = &omap3_pdata,
+       },
+       {
+               .compatible = "ti,omap2-gpio",
+               .data = &omap2_pdata,
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(of, omap_gpio_match);
 #endif
 
 static struct platform_driver omap_gpio_driver = {
        .probe          = omap_gpio_probe,
        .driver         = {
                .name   = "omap_gpio",
+               .pm     = &gpio_pm_ops,
+               .of_match_table = of_match_ptr(omap_gpio_match),
        },
 };
 
@@ -1585,17 +1509,3 @@ static int __init omap_gpio_drv_reg(void)
        return platform_driver_register(&omap_gpio_driver);
 }
 postcore_initcall(omap_gpio_drv_reg);
-
-static int __init omap_gpio_sysinit(void)
-{
-       mpuio_init();
-
-#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS)
-       if (cpu_is_omap16xx() || cpu_class_is_omap2())
-               register_syscore_ops(&omap_gpio_syscore_ops);
-#endif
-
-       return 0;
-}
-
-arch_initcall(omap_gpio_sysinit);
index 77c9cc7..b4b5da4 100644 (file)
@@ -352,7 +352,12 @@ static int pl061_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(pl061_dev_pm_ops, pl061_suspend, pl061_resume);
+static const struct dev_pm_ops pl061_dev_pm_ops = {
+       .suspend = pl061_suspend,
+       .resume = pl061_resume,
+       .freeze = pl061_suspend,
+       .restore = pl061_resume,
+};
 #endif
 
 static struct amba_id pl061_ids[] = {
diff --git a/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c
new file mode 100644 (file)
index 0000000..9ba15d3
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ *  GPIO interface for Intel Sodaville SoCs.
+ *
+ *  Copyright (c) 2010, 2011 Intel Corporation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/of_irq.h>
+#include <linux/basic_mmio_gpio.h>
+
+#define DRV_NAME               "sdv_gpio"
+#define SDV_NUM_PUB_GPIOS      12
+#define PCI_DEVICE_ID_SDV_GPIO 0x2e67
+#define GPIO_BAR               0
+
+#define GPOUTR         0x00
+#define GPOER          0x04
+#define GPINR          0x08
+
+#define GPSTR          0x0c
+#define GPIT1R0                0x10
+#define GPIO_INT       0x14
+#define GPIT1R1                0x18
+
+#define GPMUXCTL       0x1c
+
+struct sdv_gpio_chip_data {
+       int irq_base;
+       void __iomem *gpio_pub_base;
+       struct irq_domain id;
+       struct irq_chip_generic *gc;
+       struct bgpio_chip bgpio;
+};
+
+static int sdv_gpio_pub_set_type(struct irq_data *d, unsigned int type)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       struct sdv_gpio_chip_data *sd = gc->private;
+       void __iomem *type_reg;
+       u32 irq_offs = d->irq - sd->irq_base;
+       u32 reg;
+
+       if (irq_offs < 8)
+               type_reg = sd->gpio_pub_base + GPIT1R0;
+       else
+               type_reg = sd->gpio_pub_base + GPIT1R1;
+
+       reg = readl(type_reg);
+
+       switch (type) {
+       case IRQ_TYPE_LEVEL_HIGH:
+               reg &= ~BIT(4 * (irq_offs % 8));
+               break;
+
+       case IRQ_TYPE_LEVEL_LOW:
+               reg |= BIT(4 * (irq_offs % 8));
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       writel(reg, type_reg);
+       return 0;
+}
+
+static irqreturn_t sdv_gpio_pub_irq_handler(int irq, void *data)
+{
+       struct sdv_gpio_chip_data *sd = data;
+       u32 irq_stat = readl(sd->gpio_pub_base + GPSTR);
+
+       irq_stat &= readl(sd->gpio_pub_base + GPIO_INT);
+       if (!irq_stat)
+               return IRQ_NONE;
+
+       while (irq_stat) {
+               u32 irq_bit = __fls(irq_stat);
+
+               irq_stat &= ~BIT(irq_bit);
+               generic_handle_irq(sd->irq_base + irq_bit);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int sdv_xlate(struct irq_domain *h, struct device_node *node,
+               const u32 *intspec, u32 intsize, irq_hw_number_t *out_hwirq,
+               u32 *out_type)
+{
+       u32 line, type;
+
+       if (node != h->of_node)
+               return -EINVAL;
+
+       if (intsize < 2)
+               return -EINVAL;
+
+       line = *intspec;
+       *out_hwirq = line;
+
+       intspec++;
+       type = *intspec;
+
+       switch (type) {
+       case IRQ_TYPE_LEVEL_LOW:
+       case IRQ_TYPE_LEVEL_HIGH:
+               *out_type = type;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static struct irq_domain_ops irq_domain_sdv_ops = {
+       .dt_translate   = sdv_xlate,
+};
+
+static __devinit int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd,
+               struct pci_dev *pdev)
+{
+       struct irq_chip_type *ct;
+       int ret;
+
+       sd->irq_base = irq_alloc_descs(-1, 0, SDV_NUM_PUB_GPIOS, -1);
+       if (sd->irq_base < 0)
+               return sd->irq_base;
+
+       /* mask + ACK all interrupt sources */
+       writel(0, sd->gpio_pub_base + GPIO_INT);
+       writel((1 << 11) - 1, sd->gpio_pub_base + GPSTR);
+
+       ret = request_irq(pdev->irq, sdv_gpio_pub_irq_handler, IRQF_SHARED,
+                       "sdv_gpio", sd);
+       if (ret)
+               goto out_free_desc;
+
+       sd->id.irq_base = sd->irq_base;
+       sd->id.of_node = of_node_get(pdev->dev.of_node);
+       sd->id.ops = &irq_domain_sdv_ops;
+
+       /*
+        * This gpio irq controller latches level irqs. Testing shows that if
+        * we unmask & ACK the IRQ before the source of the interrupt is gone
+        * then the interrupt is active again.
+        */
+       sd->gc = irq_alloc_generic_chip("sdv-gpio", 1, sd->irq_base,
+                       sd->gpio_pub_base, handle_fasteoi_irq);
+       if (!sd->gc) {
+               ret = -ENOMEM;
+               goto out_free_irq;
+       }
+
+       sd->gc->private = sd;
+       ct = sd->gc->chip_types;
+       ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
+       ct->regs.eoi = GPSTR;
+       ct->regs.mask = GPIO_INT;
+       ct->chip.irq_mask = irq_gc_mask_clr_bit;
+       ct->chip.irq_unmask = irq_gc_mask_set_bit;
+       ct->chip.irq_eoi = irq_gc_eoi;
+       ct->chip.irq_set_type = sdv_gpio_pub_set_type;
+
+       irq_setup_generic_chip(sd->gc, IRQ_MSK(SDV_NUM_PUB_GPIOS),
+                       IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST,
+                       IRQ_LEVEL | IRQ_NOPROBE);
+
+       irq_domain_add(&sd->id);
+       return 0;
+out_free_irq:
+       free_irq(pdev->irq, sd);
+out_free_desc:
+       irq_free_descs(sd->irq_base, SDV_NUM_PUB_GPIOS);
+       return ret;
+}
+
+static int __devinit sdv_gpio_probe(struct pci_dev *pdev,
+                                       const struct pci_device_id *pci_id)
+{
+       struct sdv_gpio_chip_data *sd;
+       unsigned long addr;
+       const void *prop;
+       int len;
+       int ret;
+       u32 mux_val;
+
+       sd = kzalloc(sizeof(struct sdv_gpio_chip_data), GFP_KERNEL);
+       if (!sd)
+               return -ENOMEM;
+       ret = pci_enable_device(pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "can't enable device.\n");
+               goto done;
+       }
+
+       ret = pci_request_region(pdev, GPIO_BAR, DRV_NAME);
+       if (ret) {
+               dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", GPIO_BAR);
+               goto disable_pci;
+       }
+
+       addr = pci_resource_start(pdev, GPIO_BAR);
+       if (!addr)
+               goto release_reg;
+       sd->gpio_pub_base = ioremap(addr, pci_resource_len(pdev, GPIO_BAR));
+
+       prop = of_get_property(pdev->dev.of_node, "intel,muxctl", &len);
+       if (prop && len == 4) {
+               mux_val = of_read_number(prop, 1);
+               writel(mux_val, sd->gpio_pub_base + GPMUXCTL);
+       }
+
+       ret = bgpio_init(&sd->bgpio, &pdev->dev, 4,
+                       sd->gpio_pub_base + GPINR, sd->gpio_pub_base + GPOUTR,
+                       NULL, sd->gpio_pub_base + GPOER, NULL, false);
+       if (ret)
+               goto unmap;
+       sd->bgpio.gc.ngpio = SDV_NUM_PUB_GPIOS;
+
+       ret = gpiochip_add(&sd->bgpio.gc);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "gpiochip_add() failed.\n");
+               goto unmap;
+       }
+
+       ret = sdv_register_irqsupport(sd, pdev);
+       if (ret)
+               goto unmap;
+
+       pci_set_drvdata(pdev, sd);
+       dev_info(&pdev->dev, "Sodaville GPIO driver registered.\n");
+       return 0;
+
+unmap:
+       iounmap(sd->gpio_pub_base);
+release_reg:
+       pci_release_region(pdev, GPIO_BAR);
+disable_pci:
+       pci_disable_device(pdev);
+done:
+       kfree(sd);
+       return ret;
+}
+
+static void sdv_gpio_remove(struct pci_dev *pdev)
+{
+       struct sdv_gpio_chip_data *sd = pci_get_drvdata(pdev);
+
+       irq_domain_del(&sd->id);
+       free_irq(pdev->irq, sd);
+       irq_free_descs(sd->irq_base, SDV_NUM_PUB_GPIOS);
+
+       if (gpiochip_remove(&sd->bgpio.gc))
+               dev_err(&pdev->dev, "gpiochip_remove() failed.\n");
+
+       pci_release_region(pdev, GPIO_BAR);
+       iounmap(sd->gpio_pub_base);
+       pci_disable_device(pdev);
+       kfree(sd);
+}
+
+static struct pci_device_id sdv_gpio_pci_ids[] __devinitdata = {
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_SDV_GPIO) },
+       { 0, },
+};
+
+static struct pci_driver sdv_gpio_driver = {
+       .name = DRV_NAME,
+       .id_table = sdv_gpio_pci_ids,
+       .probe = sdv_gpio_probe,
+       .remove = sdv_gpio_remove,
+};
+
+static int __init sdv_gpio_init(void)
+{
+       return pci_register_driver(&sdv_gpio_driver);
+}
+module_init(sdv_gpio_init);
+
+static void __exit sdv_gpio_exit(void)
+{
+       pci_unregister_driver(&sdv_gpio_driver);
+}
+module_exit(sdv_gpio_exit);
+
+MODULE_AUTHOR("Hans J. Koch <hjk@linutronix.de>");
+MODULE_DESCRIPTION("GPIO interface for Intel Sodaville SoCs");
+MODULE_LICENSE("GPL v2");
index 91f45b9..7eef648 100644 (file)
@@ -69,6 +69,7 @@ static int tps65910_gpio_input(struct gpio_chip *gc, unsigned offset)
 void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base)
 {
        int ret;
+       struct tps65910_board *board_data;
 
        if (!gpio_base)
                return;
@@ -80,10 +81,10 @@ void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base)
 
        switch(tps65910_chip_id(tps65910)) {
        case TPS65910:
-               tps65910->gpio.ngpio    = 6;
+               tps65910->gpio.ngpio    = TPS65910_NUM_GPIO;
                break;
        case TPS65911:
-               tps65910->gpio.ngpio    = 9;
+               tps65910->gpio.ngpio    = TPS65911_NUM_GPIO;
                break;
        default:
                return;
@@ -95,6 +96,21 @@ void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base)
        tps65910->gpio.set              = tps65910_gpio_set;
        tps65910->gpio.get              = tps65910_gpio_get;
 
+       /* Configure sleep control for gpios */
+       board_data = dev_get_platdata(tps65910->dev);
+       if (board_data) {
+               int i;
+               for (i = 0; i < tps65910->gpio.ngpio; ++i) {
+                       if (board_data->en_gpio_sleep[i]) {
+                               ret = tps65910_set_bits(tps65910,
+                                       TPS65910_GPIO0 + i, GPIO_SLEEP_MASK);
+                               if (ret < 0)
+                                       dev_warn(tps65910->dev,
+                                               "GPIO Sleep setting failed\n");
+                       }
+               }
+       }
+
        ret = gpiochip_add(&tps65910->gpio);
 
        if (ret)
index 17fdf4b..5a75510 100644 (file)
@@ -58,6 +58,8 @@ struct gpio_desc {
 #define FLAG_TRIG_FALL 5       /* trigger on falling edge */
 #define FLAG_TRIG_RISE 6       /* trigger on rising edge */
 #define FLAG_ACTIVE_LOW        7       /* sysfs value has active low */
+#define FLAG_OPEN_DRAIN        8       /* Gpio is open drain type */
+#define FLAG_OPEN_SOURCE 9     /* Gpio is open source type */
 
 #define ID_SHIFT       16      /* add new flags before this one */
 
@@ -873,6 +875,7 @@ void gpio_unexport(unsigned gpio)
 {
        struct gpio_desc        *desc;
        int                     status = 0;
+       struct device           *dev = NULL;
 
        if (!gpio_is_valid(gpio)) {
                status = -EINVAL;
@@ -884,19 +887,20 @@ void gpio_unexport(unsigned gpio)
        desc = &gpio_desc[gpio];
 
        if (test_bit(FLAG_EXPORT, &desc->flags)) {
-               struct device   *dev = NULL;
 
                dev = class_find_device(&gpio_class, NULL, desc, match_export);
                if (dev) {
                        gpio_setup_irq(desc, dev, 0);
                        clear_bit(FLAG_EXPORT, &desc->flags);
-                       put_device(dev);
-                       device_unregister(dev);
                } else
                        status = -ENODEV;
        }
 
        mutex_unlock(&sysfs_lock);
+       if (dev) {
+               device_unregister(dev);
+               put_device(dev);
+       }
 done:
        if (status)
                pr_debug("%s: gpio%d status %d\n", __func__, gpio, status);
@@ -1150,8 +1154,9 @@ EXPORT_SYMBOL_GPL(gpiochip_remove);
  * non-zero, this function will return to the caller and not iterate over any
  * more gpio_chips.
  */
-struct gpio_chip *gpiochip_find(void *data,
-                               int (*match)(struct gpio_chip *chip, void *data))
+struct gpio_chip *gpiochip_find(const void *data,
+                               int (*match)(struct gpio_chip *chip,
+                                            const void *data))
 {
        struct gpio_chip *chip = NULL;
        unsigned long flags;
@@ -1261,6 +1266,8 @@ void gpio_free(unsigned gpio)
                module_put(desc->chip->owner);
                clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
                clear_bit(FLAG_REQUESTED, &desc->flags);
+               clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
+               clear_bit(FLAG_OPEN_SOURCE, &desc->flags);
        } else
                WARN_ON(extra_checks);
 
@@ -1282,6 +1289,12 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
        if (err)
                return err;
 
+       if (flags & GPIOF_OPEN_DRAIN)
+               set_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags);
+
+       if (flags & GPIOF_OPEN_SOURCE)
+               set_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags);
+
        if (flags & GPIOF_DIR_IN)
                err = gpio_direction_input(gpio);
        else
@@ -1431,6 +1444,14 @@ int gpio_direction_output(unsigned gpio, int value)
        struct gpio_desc        *desc = &gpio_desc[gpio];
        int                     status = -EINVAL;
 
+       /* Open drain pin should not be driven to 1 */
+       if (value && test_bit(FLAG_OPEN_DRAIN,  &desc->flags))
+               return gpio_direction_input(gpio);
+
+       /* Open source pin should not be driven to 0 */
+       if (!value && test_bit(FLAG_OPEN_SOURCE,  &desc->flags))
+               return gpio_direction_input(gpio);
+
        spin_lock_irqsave(&gpio_lock, flags);
 
        if (!gpio_is_valid(gpio))
@@ -1560,6 +1581,7 @@ int __gpio_get_value(unsigned gpio)
        int value;
 
        chip = gpio_to_chip(gpio);
+       /* Should be using gpio_get_value_cansleep() */
        WARN_ON(chip->can_sleep);
        value = chip->get ? chip->get(chip, gpio - chip->base) : 0;
        trace_gpio_value(gpio, 1, value);
@@ -1567,6 +1589,57 @@ int __gpio_get_value(unsigned gpio)
 }
 EXPORT_SYMBOL_GPL(__gpio_get_value);
 
+/*
+ *  _gpio_set_open_drain_value() - Set the open drain gpio's value.
+ * @gpio: Gpio whose state need to be set.
+ * @chip: Gpio chip.
+ * @value: Non-zero for setting it HIGH otherise it will set to LOW.
+ */
+static void _gpio_set_open_drain_value(unsigned gpio,
+                       struct gpio_chip *chip, int value)
+{
+       int err = 0;
+       if (value) {
+               err = chip->direction_input(chip, gpio - chip->base);
+               if (!err)
+                       clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+       } else {
+               err = chip->direction_output(chip, gpio - chip->base, 0);
+               if (!err)
+                       set_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+       }
+       trace_gpio_direction(gpio, value, err);
+       if (err < 0)
+               pr_err("%s: Error in set_value for open drain gpio%d err %d\n",
+                                       __func__, gpio, err);
+}
+
+/*
+ *  _gpio_set_open_source() - Set the open source gpio's value.
+ * @gpio: Gpio whose state need to be set.
+ * @chip: Gpio chip.
+ * @value: Non-zero for setting it HIGH otherise it will set to LOW.
+ */
+static void _gpio_set_open_source_value(unsigned gpio,
+                       struct gpio_chip *chip, int value)
+{
+       int err = 0;
+       if (value) {
+               err = chip->direction_output(chip, gpio - chip->base, 1);
+               if (!err)
+                       set_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+       } else {
+               err = chip->direction_input(chip, gpio - chip->base);
+               if (!err)
+                       clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+       }
+       trace_gpio_direction(gpio, !value, err);
+       if (err < 0)
+               pr_err("%s: Error in set_value for open source gpio%d err %d\n",
+                                       __func__, gpio, err);
+}
+
+
 /**
  * __gpio_set_value() - assign a gpio's value
  * @gpio: gpio whose value will be assigned
@@ -1581,9 +1654,15 @@ void __gpio_set_value(unsigned gpio, int value)
        struct gpio_chip        *chip;
 
        chip = gpio_to_chip(gpio);
+       /* Should be using gpio_set_value_cansleep() */
        WARN_ON(chip->can_sleep);
        trace_gpio_value(gpio, 0, value);
-       chip->set(chip, gpio - chip->base, value);
+       if (test_bit(FLAG_OPEN_DRAIN,  &gpio_desc[gpio].flags))
+               _gpio_set_open_drain_value(gpio, chip, value);
+       else if (test_bit(FLAG_OPEN_SOURCE,  &gpio_desc[gpio].flags))
+               _gpio_set_open_source_value(gpio, chip, value);
+       else
+               chip->set(chip, gpio - chip->base, value);
 }
 EXPORT_SYMBOL_GPL(__gpio_set_value);
 
@@ -1650,7 +1729,12 @@ void gpio_set_value_cansleep(unsigned gpio, int value)
        might_sleep_if(extra_checks);
        chip = gpio_to_chip(gpio);
        trace_gpio_value(gpio, 0, value);
-       chip->set(chip, gpio - chip->base, value);
+       if (test_bit(FLAG_OPEN_DRAIN,  &gpio_desc[gpio].flags))
+               _gpio_set_open_drain_value(gpio, chip, value);
+       else if (test_bit(FLAG_OPEN_SOURCE,  &gpio_desc[gpio].flags))
+               _gpio_set_open_source_value(gpio, chip, value);
+       else
+               chip->set(chip, gpio - chip->base, value);
 }
 EXPORT_SYMBOL_GPL(gpio_set_value_cansleep);
 
index f147395..1489c35 100644 (file)
@@ -201,6 +201,7 @@ config MENELAUS
 config TWL4030_CORE
        bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support"
        depends on I2C=y && GENERIC_HARDIRQS
+       select IRQ_DOMAIN
        help
          Say yes here if you have TWL4030 / TWL6030 family chip on your board.
          This core driver provides register access and IRQ handling
index 8ce3959..4970d43 100644 (file)
 
 #define TWL_MODULE_LAST TWL4030_MODULE_LAST
 
-#define TWL4030_NR_IRQS    8
+#define TWL4030_NR_IRQS    34 /* core:8, power:8, gpio: 18 */
 #define TWL6030_NR_IRQS    20
 
 /* Base Address defns for twl4030_map[] */
@@ -263,10 +263,6 @@ struct twl_client {
 
 static struct twl_client twl_modules[TWL_NUM_SLAVES];
 
-#ifdef CONFIG_IRQ_DOMAIN
-static struct irq_domain domain;
-#endif
-
 /* mapping the module id to slave id and base address */
 struct twl_mapping {
        unsigned char sid;      /* Slave ID */
@@ -1227,14 +1223,8 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
        pdata->irq_base = status;
        pdata->irq_end = pdata->irq_base + nr_irqs;
-
-#ifdef CONFIG_IRQ_DOMAIN
-       domain.irq_base = pdata->irq_base;
-       domain.nr_irq = nr_irqs;
-       domain.of_node = of_node_get(node);
-       domain.ops = &irq_domain_simple_ops;
-       irq_domain_add(&domain);
-#endif
+       irq_domain_add_legacy(node, nr_irqs, pdata->irq_base, 0,
+                             &irq_domain_simple_ops, NULL);
 
        if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
                dev_dbg(&client->dev, "can't talk I2C?\n");
@@ -1315,11 +1305,10 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
                twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
        }
 
-#ifdef CONFIG_OF_DEVICE
+       status = -ENODEV;
        if (node)
                status = of_platform_populate(node, NULL, NULL, &client->dev);
-       else
-#endif
+       if (status)
                status = add_children(pdata, id->driver_data);
 
 fail:
index 50e8e5e..7189adf 100644 (file)
@@ -255,13 +255,13 @@ static inline int __init mdio_ofgpio_init(void)
        return platform_driver_register(&mdio_ofgpio_driver);
 }
 
-static inline void __exit mdio_ofgpio_exit(void)
+static inline void mdio_ofgpio_exit(void)
 {
        platform_driver_unregister(&mdio_ofgpio_driver);
 }
 #else
 static inline int __init mdio_ofgpio_init(void) { return 0; }
-static inline void __exit mdio_ofgpio_exit(void) { }
+static inline void mdio_ofgpio_exit(void) { }
 #endif /* CONFIG_OF_GPIO */
 
 static struct platform_driver mdio_gpio_driver = {
index 7e62d15..bba8121 100644 (file)
@@ -78,8 +78,9 @@ err0:
 EXPORT_SYMBOL(of_get_named_gpio_flags);
 
 /**
- * of_gpio_count - Count GPIOs for a device
+ * of_gpio_named_count - Count GPIOs for a device
  * @np:                device node to count GPIOs for
+ * @propname:  property name containing gpio specifier(s)
  *
  * The function returns the count of GPIOs specified for a node.
  *
@@ -93,14 +94,14 @@ EXPORT_SYMBOL(of_get_named_gpio_flags);
  * defines four GPIOs (so this function will return 4), two of which
  * are not specified.
  */
-unsigned int of_gpio_count(struct device_node *np)
+unsigned int of_gpio_named_count(struct device_node *np, const char* propname)
 {
        unsigned int cnt = 0;
 
        do {
                int ret;
 
-               ret = of_parse_phandle_with_args(np, "gpios", "#gpio-cells",
+               ret = of_parse_phandle_with_args(np, propname, "#gpio-cells",
                                                 cnt, NULL);
                /* A hole in the gpios = <> counts anyway. */
                if (ret < 0 && ret != -EEXIST)
@@ -109,7 +110,7 @@ unsigned int of_gpio_count(struct device_node *np)
 
        return cnt;
 }
-EXPORT_SYMBOL(of_gpio_count);
+EXPORT_SYMBOL(of_gpio_named_count);
 
 /**
  * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags
@@ -228,7 +229,7 @@ void of_gpiochip_remove(struct gpio_chip *chip)
 }
 
 /* Private function for resolving node pointer to gpio_chip */
-static int of_gpiochip_is_match(struct gpio_chip *chip, void *data)
+static int of_gpiochip_is_match(struct gpio_chip *chip, const void *data)
 {
        return chip->of_node == data;
 }
index 63b3ec4..20fbebd 100644 (file)
@@ -55,7 +55,7 @@ EXPORT_SYMBOL(of_find_device_by_node);
 #include <asm/dcr.h>
 #endif
 
-#if !defined(CONFIG_SPARC)
+#ifdef CONFIG_OF_ADDRESS
 /*
  * The following routines scan a subtree and registers a device for
  * each applicable node.
@@ -462,4 +462,4 @@ int of_platform_populate(struct device_node *root,
        of_node_put(root);
        return rc;
 }
-#endif /* !CONFIG_SPARC */
+#endif /* CONFIG_OF_ADDRESS */
index 1ff4e22..5f52690 100644 (file)
@@ -142,9 +142,9 @@ extern int __must_check gpiochip_reserve(int start, int ngpio);
 /* add/remove chips */
 extern int gpiochip_add(struct gpio_chip *chip);
 extern int __must_check gpiochip_remove(struct gpio_chip *chip);
-extern struct gpio_chip *gpiochip_find(void *data,
+extern struct gpio_chip *gpiochip_find(const void *data,
                                        int (*match)(struct gpio_chip *chip,
-                                                    void *data));
+                                                    const void *data));
 
 
 /* Always use the library code for GPIO management calls,
index 38ac48b..67851bb 100644 (file)
 #define GPIOF_OUT_INIT_LOW     (GPIOF_DIR_OUT | GPIOF_INIT_LOW)
 #define GPIOF_OUT_INIT_HIGH    (GPIOF_DIR_OUT | GPIOF_INIT_HIGH)
 
+/* Gpio pin is open drain */
+#define GPIOF_OPEN_DRAIN       (1 << 2)
+
+/* Gpio pin is open source */
+#define GPIOF_OPEN_SOURCE      (1 << 3)
+
 /**
  * struct gpio - a structure describing a GPIO with configuration
  * @gpio:      the GPIO number
index bd4272b..ead4a42 100644 (file)
  * representation into a hardware irq number that can be mapped back to a
  * Linux irq number without any extra platform support code.
  *
- * irq_domain is expected to be embedded in an interrupt controller's private
- * data structure.
+ * Interrupt controller "domain" data structure. This could be defined as a
+ * irq domain controller. That is, it handles the mapping between hardware
+ * and virtual interrupt numbers for a given interrupt domain. The domain
+ * structure is generally created by the PIC code for a given PIC instance
+ * (though a domain can cover more than one PIC if they have a flat number
+ * model). It's the domain callbacks that are responsible for setting the
+ * irq_chip on a given irq_desc after it's been mapped.
+ *
+ * The host code and data structures are agnostic to whether or not
+ * we use an open firmware device-tree. We do have references to struct
+ * device_node in two places: in irq_find_host() to find the host matching
+ * a given interrupt controller node, and of course as an argument to its
+ * counterpart domain->ops->match() callback. However, those are treated as
+ * generic pointers by the core and the fact that it's actually a device-node
+ * pointer is purely a convention between callers and implementation. This
+ * code could thus be used on other architectures by replacing those two
+ * by some sort of arch-specific void * "token" used to identify interrupt
+ * controllers.
  */
+
 #ifndef _LINUX_IRQDOMAIN_H
 #define _LINUX_IRQDOMAIN_H
 
-#include <linux/irq.h>
-#include <linux/mod_devicetable.h>
+#include <linux/types.h>
+#include <linux/radix-tree.h>
 
-#ifdef CONFIG_IRQ_DOMAIN
 struct device_node;
 struct irq_domain;
+struct of_device_id;
+
+/* Number of irqs reserved for a legacy isa controller */
+#define NUM_ISA_INTERRUPTS     16
+
+/* This type is the placeholder for a hardware interrupt number. It has to
+ * be big enough to enclose whatever representation is used by a given
+ * platform.
+ */
+typedef unsigned long irq_hw_number_t;
 
 /**
  * struct irq_domain_ops - Methods for irq_domain objects
- * @to_irq: (optional) given a local hardware irq number, return the linux
- *          irq number.  If to_irq is not implemented, then the irq_domain
- *          will use this translation: irq = (domain->irq_base + hwirq)
- * @dt_translate: Given a device tree node and interrupt specifier, decode
- *                the hardware irq number and linux irq type value.
+ * @match: Match an interrupt controller device node to a host, returns
+ *         1 on a match
+ * @map: Create or update a mapping between a virtual irq number and a hw
+ *       irq number. This is called only once for a given mapping.
+ * @unmap: Dispose of such a mapping
+ * @xlate: Given a device tree node and interrupt specifier, decode
+ *         the hardware irq number and linux irq type value.
+ *
+ * Functions below are provided by the driver and called whenever a new mapping
+ * is created or an old mapping is disposed. The driver can then proceed to
+ * whatever internal data structures management is required. It also needs
+ * to setup the irq_desc when returning from map().
  */
 struct irq_domain_ops {
-       unsigned int (*to_irq)(struct irq_domain *d, unsigned long hwirq);
-
-#ifdef CONFIG_OF
-       int (*dt_translate)(struct irq_domain *d, struct device_node *node,
-                           const u32 *intspec, unsigned int intsize,
-                           unsigned long *out_hwirq, unsigned int *out_type);
-#endif /* CONFIG_OF */
+       int (*match)(struct irq_domain *d, struct device_node *node);
+       int (*map)(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw);
+       void (*unmap)(struct irq_domain *d, unsigned int virq);
+       int (*xlate)(struct irq_domain *d, struct device_node *node,
+                    const u32 *intspec, unsigned int intsize,
+                    unsigned long *out_hwirq, unsigned int *out_type);
 };
 
 /**
  * struct irq_domain - Hardware interrupt number translation object
- * @list: Element in global irq_domain list.
+ * @link: Element in global irq_domain list.
+ * @revmap_type: Method used for reverse mapping hwirq numbers to linux irq. This
+ *               will be one of the IRQ_DOMAIN_MAP_* values.
+ * @revmap_data: Revmap method specific data.
+ * @ops: pointer to irq_domain methods
+ * @host_data: private data pointer for use by owner.  Not touched by irq_domain
+ *             core code.
  * @irq_base: Start of irq_desc range assigned to the irq_domain.  The creator
  *            of the irq_domain is responsible for allocating the array of
  *            irq_desc structures.
  * @nr_irq: Number of irqs managed by the irq domain
  * @hwirq_base: Starting number for hwirqs managed by the irq domain
- * @ops: pointer to irq_domain methods
- * @priv: private data pointer for use by owner.  Not touched by irq_domain
- *        core code.
  * @of_node: (optional) Pointer to device tree nodes associated with the
  *           irq_domain.  Used when decoding device tree interrupt specifiers.
  */
 struct irq_domain {
-       struct list_head list;
-       unsigned int irq_base;
-       unsigned int nr_irq;
-       unsigned int hwirq_base;
+       struct list_head link;
+
+       /* type of reverse mapping_technique */
+       unsigned int revmap_type;
+       union {
+               struct {
+                       unsigned int size;
+                       unsigned int first_irq;
+                       irq_hw_number_t first_hwirq;
+               } legacy;
+               struct {
+                       unsigned int size;
+                       unsigned int *revmap;
+               } linear;
+               struct radix_tree_root tree;
+       } revmap_data;
        const struct irq_domain_ops *ops;
-       void *priv;
+       void *host_data;
+       irq_hw_number_t inval_irq;
+
+       /* Optional device node pointer */
        struct device_node *of_node;
 };
 
-/**
- * irq_domain_to_irq() - Translate from a hardware irq to a linux irq number
- *
- * Returns the linux irq number associated with a hardware irq.  By default,
- * the mapping is irq == domain->irq_base + hwirq, but this mapping can
- * be overridden if the irq_domain implements a .to_irq() hook.
- */
-static inline unsigned int irq_domain_to_irq(struct irq_domain *d,
-                                            unsigned long hwirq)
+#ifdef CONFIG_IRQ_DOMAIN
+struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
+                                        unsigned int size,
+                                        unsigned int first_irq,
+                                        irq_hw_number_t first_hwirq,
+                                        const struct irq_domain_ops *ops,
+                                        void *host_data);
+struct irq_domain *irq_domain_add_linear(struct device_node *of_node,
+                                        unsigned int size,
+                                        const struct irq_domain_ops *ops,
+                                        void *host_data);
+struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
+                                        const struct irq_domain_ops *ops,
+                                        void *host_data);
+struct irq_domain *irq_domain_add_tree(struct device_node *of_node,
+                                        const struct irq_domain_ops *ops,
+                                        void *host_data);
+
+extern struct irq_domain *irq_find_host(struct device_node *node);
+extern void irq_set_default_host(struct irq_domain *host);
+extern void irq_set_virq_count(unsigned int count);
+
+static inline struct irq_domain *irq_domain_add_legacy_isa(
+                               struct device_node *of_node,
+                               const struct irq_domain_ops *ops,
+                               void *host_data)
 {
-       if (d->ops->to_irq)
-               return d->ops->to_irq(d, hwirq);
-       if (WARN_ON(hwirq < d->hwirq_base))
-               return 0;
-       return d->irq_base + hwirq - d->hwirq_base;
+       return irq_domain_add_legacy(of_node, NUM_ISA_INTERRUPTS, 0, 0, ops,
+                                    host_data);
 }
+extern struct irq_domain *irq_find_host(struct device_node *node);
+extern void irq_set_default_host(struct irq_domain *host);
+extern void irq_set_virq_count(unsigned int count);
 
-#define irq_domain_for_each_hwirq(d, hw) \
-       for (hw = d->hwirq_base; hw < d->hwirq_base + d->nr_irq; hw++)
 
-#define irq_domain_for_each_irq(d, hw, irq) \
-       for (hw = d->hwirq_base, irq = irq_domain_to_irq(d, hw); \
-            hw < d->hwirq_base + d->nr_irq; \
-            hw++, irq = irq_domain_to_irq(d, hw))
+extern unsigned int irq_create_mapping(struct irq_domain *host,
+                                      irq_hw_number_t hwirq);
+extern void irq_dispose_mapping(unsigned int virq);
+extern unsigned int irq_find_mapping(struct irq_domain *host,
+                                    irq_hw_number_t hwirq);
+extern unsigned int irq_create_direct_mapping(struct irq_domain *host);
+extern void irq_radix_revmap_insert(struct irq_domain *host, unsigned int virq,
+                                   irq_hw_number_t hwirq);
+extern unsigned int irq_radix_revmap_lookup(struct irq_domain *host,
+                                           irq_hw_number_t hwirq);
+extern unsigned int irq_linear_revmap(struct irq_domain *host,
+                                     irq_hw_number_t hwirq);
 
-extern void irq_domain_add(struct irq_domain *domain);
-extern void irq_domain_del(struct irq_domain *domain);
+extern const struct irq_domain_ops irq_domain_simple_ops;
 
-extern struct irq_domain_ops irq_domain_simple_ops;
-#endif /* CONFIG_IRQ_DOMAIN */
+/* stock xlate functions */
+int irq_domain_xlate_onecell(struct irq_domain *d, struct device_node *ctrlr,
+                       const u32 *intspec, unsigned int intsize,
+                       irq_hw_number_t *out_hwirq, unsigned int *out_type);
+int irq_domain_xlate_twocell(struct irq_domain *d, struct device_node *ctrlr,
+                       const u32 *intspec, unsigned int intsize,
+                       irq_hw_number_t *out_hwirq, unsigned int *out_type);
+int irq_domain_xlate_onetwocell(struct irq_domain *d, struct device_node *ctrlr,
+                       const u32 *intspec, unsigned int intsize,
+                       irq_hw_number_t *out_hwirq, unsigned int *out_type);
 
-#if defined(CONFIG_IRQ_DOMAIN) && defined(CONFIG_OF_IRQ)
-extern void irq_domain_add_simple(struct device_node *controller, int irq_base);
+#if defined(CONFIG_OF_IRQ)
 extern void irq_domain_generate_simple(const struct of_device_id *match,
                                        u64 phys_base, unsigned int irq_start);
-#else /* CONFIG_IRQ_DOMAIN && CONFIG_OF_IRQ */
+#else /* CONFIG_OF_IRQ */
 static inline void irq_domain_generate_simple(const struct of_device_id *match,
                                        u64 phys_base, unsigned int irq_start) { }
-#endif /* CONFIG_IRQ_DOMAIN && CONFIG_OF_IRQ */
+#endif /* !CONFIG_OF_IRQ */
+
+#else /* CONFIG_IRQ_DOMAIN */
+static inline void irq_dispose_mapping(unsigned int virq) { }
+#endif /* !CONFIG_IRQ_DOMAIN */
 
 #endif /* _LINUX_IRQDOMAIN_H */
index d0cb12e..9071902 100644 (file)
 
 
 /*Register GPIO  (0x80) register.RegisterDescription */
+#define GPIO_SLEEP_MASK                         0x80
+#define GPIO_SLEEP_SHIFT                        7
 #define GPIO_DEB_MASK                           0x10
 #define GPIO_DEB_SHIFT                          4
 #define GPIO_PUEN_MASK                          0x08
 #define TPS65910_GPIO_STS                              BIT(1)
 #define TPS65910_GPIO_SET                              BIT(0)
 
+/* Max number of TPS65910/11 GPIOs */
+#define TPS65910_NUM_GPIO                              6
+#define TPS65911_NUM_GPIO                              9
+#define TPS6591X_MAX_NUM_GPIO                          9
+
 /* Regulator Index Definitions */
 #define TPS65910_REG_VRTC                              0
 #define TPS65910_REG_VIO                               1
@@ -779,6 +786,7 @@ struct tps65910_board {
        int irq_base;
        int vmbch_threshold;
        int vmbch2_threshold;
+       bool en_gpio_sleep[TPS6591X_MAX_NUM_GPIO];
        struct regulator_init_data *tps65910_pmic_init_data[TPS65910_NUM_REGS];
 };
 
index 3118623..01b925a 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/errno.h>
 #include <linux/of.h>
 
+#ifdef CONFIG_OF_ADDRESS
 extern u64 of_translate_address(struct device_node *np, const __be32 *addr);
 extern int of_address_to_resource(struct device_node *dev, int index,
                                  struct resource *r);
@@ -25,12 +26,37 @@ static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; }
 #define pci_address_to_pio pci_address_to_pio
 #endif
 
-#ifdef CONFIG_PCI
+#else /* CONFIG_OF_ADDRESS */
+static inline int of_address_to_resource(struct device_node *dev, int index,
+                                        struct resource *r)
+{
+       return -EINVAL;
+}
+static inline struct device_node *of_find_matching_node_by_address(
+                                       struct device_node *from,
+                                       const struct of_device_id *matches,
+                                       u64 base_address)
+{
+       return NULL;
+}
+static inline void __iomem *of_iomap(struct device_node *device, int index)
+{
+       return NULL;
+}
+static inline const u32 *of_get_address(struct device_node *dev, int index,
+                                       u64 *size, unsigned int *flags)
+{
+       return NULL;
+}
+#endif /* CONFIG_OF_ADDRESS */
+
+
+#if defined(CONFIG_OF_ADDRESS) && defined(CONFIG_PCI)
 extern const __be32 *of_get_pci_address(struct device_node *dev, int bar_no,
                               u64 *size, unsigned int *flags);
 extern int of_pci_address_to_resource(struct device_node *dev, int bar,
                                      struct resource *r);
-#else /* CONFIG_PCI */
+#else /* CONFIG_OF_ADDRESS && CONFIG_PCI */
 static inline int of_pci_address_to_resource(struct device_node *dev, int bar,
                                             struct resource *r)
 {
@@ -42,8 +68,7 @@ static inline const __be32 *of_get_pci_address(struct device_node *dev,
 {
        return NULL;
 }
-#endif /* CONFIG_PCI */
-
+#endif /* CONFIG_OF_ADDRESS && CONFIG_PCI */
 
 #endif /* __OF_ADDRESS_H */
 
index b254052..81733d1 100644 (file)
@@ -50,7 +50,8 @@ static inline struct of_mm_gpio_chip *to_of_mm_gpio_chip(struct gpio_chip *gc)
 extern int of_get_named_gpio_flags(struct device_node *np,
                const char *list_name, int index, enum of_gpio_flags *flags);
 
-extern unsigned int of_gpio_count(struct device_node *np);
+extern unsigned int of_gpio_named_count(struct device_node *np,
+                                       const char* propname);
 
 extern int of_mm_gpiochip_add(struct device_node *np,
                              struct of_mm_gpio_chip *mm_gc);
@@ -71,7 +72,8 @@ static inline int of_get_named_gpio_flags(struct device_node *np,
        return -ENOSYS;
 }
 
-static inline unsigned int of_gpio_count(struct device_node *np)
+static inline unsigned int of_gpio_named_count(struct device_node *np,
+                                       const char* propname)
 {
        return 0;
 }
@@ -89,6 +91,27 @@ static inline void of_gpiochip_remove(struct gpio_chip *gc) { }
 #endif /* CONFIG_OF_GPIO */
 
 /**
+ * of_gpio_count - Count GPIOs for a device
+ * @np:                device node to count GPIOs for
+ *
+ * The function returns the count of GPIOs specified for a node.
+ *
+ * Note that the empty GPIO specifiers counts too. For example,
+ *
+ * gpios = <0
+ *          &pio1 1 2
+ *          0
+ *          &pio2 3 4>;
+ *
+ * defines four GPIOs (so this function will return 4), two of which
+ * are not specified.
+ */
+static inline unsigned int of_gpio_count(struct device_node *np)
+{
+       return of_gpio_named_count(np, "gpios");
+}
+
+/**
  * of_get_gpio_flags() - Get a GPIO number and flags to use with GPIO API
  * @np:                device node to get GPIO from
  * @index:     index of the GPIO
index d0307ee..d229ad3 100644 (file)
@@ -6,6 +6,7 @@ struct of_irq;
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/irq.h>
+#include <linux/irqdomain.h>
 #include <linux/ioport.h>
 #include <linux/of.h>
 
@@ -65,9 +66,6 @@ extern int of_irq_map_one(struct device_node *device, int index,
 extern unsigned int irq_create_of_mapping(struct device_node *controller,
                                          const u32 *intspec,
                                          unsigned int intsize);
-#ifdef CONFIG_IRQ_DOMAIN
-extern void irq_dispose_mapping(unsigned int irq);
-#endif
 extern int of_irq_to_resource(struct device_node *dev, int index,
                              struct resource *r);
 extern int of_irq_count(struct device_node *dev);
index 040ce2f..242fa35 100644 (file)
@@ -81,7 +81,7 @@ extern struct platform_device *of_device_alloc(struct device_node *np,
                                         struct device *parent);
 extern struct platform_device *of_find_device_by_node(struct device_node *np);
 
-#if !defined(CONFIG_SPARC) /* SPARC has its own device registration method */
+#ifdef CONFIG_OF_ADDRESS /* device reg helpers depend on OF_ADDRESS */
 /* Platform devices and busses creation */
 extern struct platform_device *of_platform_device_create(struct device_node *np,
                                                   const char *bus_id,
@@ -94,7 +94,15 @@ extern int of_platform_populate(struct device_node *root,
                                const struct of_device_id *matches,
                                const struct of_dev_auxdata *lookup,
                                struct device *parent);
-#endif /* !CONFIG_SPARC */
+#else
+static inline int of_platform_populate(struct device_node *root,
+                                       const struct of_device_id *matches,
+                                       const struct of_dev_auxdata *lookup,
+                                       struct device *parent)
+{
+       return -ENODEV;
+}
+#endif /* !CONFIG_OF_ADDRESS */
 
 #endif /* CONFIG_OF_DEVICE */
 
index 1f9e265..af48e59 100644 (file)
+#include <linux/debugfs.h>
+#include <linux/hardirq.h>
+#include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/irqdesc.h>
 #include <linux/irqdomain.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/seq_file.h>
 #include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/fs.h>
+
+#define IRQ_DOMAIN_MAP_LEGACY 0 /* driver allocated fixed range of irqs.
+                                * ie. legacy 8259, gets irqs 1..15 */
+#define IRQ_DOMAIN_MAP_NOMAP 1 /* no fast reverse mapping */
+#define IRQ_DOMAIN_MAP_LINEAR 2 /* linear map of interrupts */
+#define IRQ_DOMAIN_MAP_TREE 3 /* radix tree */
 
 static LIST_HEAD(irq_domain_list);
 static DEFINE_MUTEX(irq_domain_mutex);
 
+static DEFINE_MUTEX(revmap_trees_mutex);
+static unsigned int irq_virq_count = NR_IRQS;
+static struct irq_domain *irq_default_domain;
+
 /**
- * irq_domain_add() - Register an irq_domain
- * @domain: ptr to initialized irq_domain structure
+ * irq_domain_alloc() - Allocate a new irq_domain data structure
+ * @of_node: optional device-tree node of the interrupt controller
+ * @revmap_type: type of reverse mapping to use
+ * @ops: map/unmap domain callbacks
+ * @host_data: Controller private data pointer
  *
- * Registers an irq_domain structure.  The irq_domain must at a minimum be
- * initialized with an ops structure pointer, and either a ->to_irq hook or
- * a valid irq_base value.  Everything else is optional.
+ * Allocates and initialize and irq_domain structure.  Caller is expected to
+ * register allocated irq_domain with irq_domain_register().  Returns pointer
+ * to IRQ domain, or NULL on failure.
  */
-void irq_domain_add(struct irq_domain *domain)
+static struct irq_domain *irq_domain_alloc(struct device_node *of_node,
+                                          unsigned int revmap_type,
+                                          const struct irq_domain_ops *ops,
+                                          void *host_data)
 {
-       struct irq_data *d;
-       int hwirq, irq;
+       struct irq_domain *domain;
 
-       /*
-        * This assumes that the irq_domain owner has already allocated
-        * the irq_descs.  This block will be removed when support for dynamic
-        * allocation of irq_descs is added to irq_domain.
-        */
-       irq_domain_for_each_irq(domain, hwirq, irq) {
-               d = irq_get_irq_data(irq);
-               if (!d) {
-                       WARN(1, "error: assigning domain to non existant irq_desc");
-                       return;
-               }
-               if (d->domain) {
-                       /* things are broken; just report, don't clean up */
-                       WARN(1, "error: irq_desc already assigned to a domain");
-                       return;
+       domain = kzalloc(sizeof(*domain), GFP_KERNEL);
+       if (WARN_ON(!domain))
+               return NULL;
+
+       /* Fill structure */
+       domain->revmap_type = revmap_type;
+       domain->ops = ops;
+       domain->host_data = host_data;
+       domain->of_node = of_node_get(of_node);
+
+       return domain;
+}
+
+static void irq_domain_add(struct irq_domain *domain)
+{
+       mutex_lock(&irq_domain_mutex);
+       list_add(&domain->link, &irq_domain_list);
+       mutex_unlock(&irq_domain_mutex);
+       pr_debug("irq: Allocated domain of type %d @0x%p\n",
+                domain->revmap_type, domain);
+}
+
+static unsigned int irq_domain_legacy_revmap(struct irq_domain *domain,
+                                            irq_hw_number_t hwirq)
+{
+       irq_hw_number_t first_hwirq = domain->revmap_data.legacy.first_hwirq;
+       int size = domain->revmap_data.legacy.size;
+
+       if (WARN_ON(hwirq < first_hwirq || hwirq >= first_hwirq + size))
+               return 0;
+       return hwirq - first_hwirq + domain->revmap_data.legacy.first_irq;
+}
+
+/**
+ * irq_domain_add_legacy() - Allocate and register a legacy revmap irq_domain.
+ * @of_node: pointer to interrupt controller's device tree node.
+ * @size: total number of irqs in legacy mapping
+ * @first_irq: first number of irq block assigned to the domain
+ * @first_hwirq: first hwirq number to use for the translation. Should normally
+ *               be '0', but a positive integer can be used if the effective
+ *               hwirqs numbering does not begin at zero.
+ * @ops: map/unmap domain callbacks
+ * @host_data: Controller private data pointer
+ *
+ * Note: the map() callback will be called before this function returns
+ * for all legacy interrupts except 0 (which is always the invalid irq for
+ * a legacy controller).
+ */
+struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
+                                        unsigned int size,
+                                        unsigned int first_irq,
+                                        irq_hw_number_t first_hwirq,
+                                        const struct irq_domain_ops *ops,
+                                        void *host_data)
+{
+       struct irq_domain *domain;
+       unsigned int i;
+
+       domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_LEGACY, ops, host_data);
+       if (!domain)
+               return NULL;
+
+       domain->revmap_data.legacy.first_irq = first_irq;
+       domain->revmap_data.legacy.first_hwirq = first_hwirq;
+       domain->revmap_data.legacy.size = size;
+
+       mutex_lock(&irq_domain_mutex);
+       /* Verify that all the irqs are available */
+       for (i = 0; i < size; i++) {
+               int irq = first_irq + i;
+               struct irq_data *irq_data = irq_get_irq_data(irq);
+
+               if (WARN_ON(!irq_data || irq_data->domain)) {
+                       mutex_unlock(&irq_domain_mutex);
+                       of_node_put(domain->of_node);
+                       kfree(domain);
+                       return NULL;
                }
-               d->domain = domain;
-               d->hwirq = hwirq;
        }
 
-       mutex_lock(&irq_domain_mutex);
-       list_add(&domain->list, &irq_domain_list);
+       /* Claim all of the irqs before registering a legacy domain */
+       for (i = 0; i < size; i++) {
+               struct irq_data *irq_data = irq_get_irq_data(first_irq + i);
+               irq_data->hwirq = first_hwirq + i;
+               irq_data->domain = domain;
+       }
        mutex_unlock(&irq_domain_mutex);
+
+       for (i = 0; i < size; i++) {
+               int irq = first_irq + i;
+               int hwirq = first_hwirq + i;
+
+               /* IRQ0 gets ignored */
+               if (!irq)
+                       continue;
+
+               /* Legacy flags are left to default at this point,
+                * one can then use irq_create_mapping() to
+                * explicitly change them
+                */
+               ops->map(domain, irq, hwirq);
+
+               /* Clear norequest flags */
+               irq_clear_status_flags(irq, IRQ_NOREQUEST);
+       }
+
+       irq_domain_add(domain);
+       return domain;
+}
+
+/**
+ * irq_domain_add_linear() - Allocate and register a legacy revmap irq_domain.
+ * @of_node: pointer to interrupt controller's device tree node.
+ * @ops: map/unmap domain callbacks
+ * @host_data: Controller private data pointer
+ */
+struct irq_domain *irq_domain_add_linear(struct device_node *of_node,
+                                        unsigned int size,
+                                        const struct irq_domain_ops *ops,
+                                        void *host_data)
+{
+       struct irq_domain *domain;
+       unsigned int *revmap;
+
+       revmap = kzalloc(sizeof(*revmap) * size, GFP_KERNEL);
+       if (WARN_ON(!revmap))
+               return NULL;
+
+       domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_LINEAR, ops, host_data);
+       if (!domain) {
+               kfree(revmap);
+               return NULL;
+       }
+       domain->revmap_data.linear.size = size;
+       domain->revmap_data.linear.revmap = revmap;
+       irq_domain_add(domain);
+       return domain;
+}
+
+struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
+                                        const struct irq_domain_ops *ops,
+                                        void *host_data)
+{
+       struct irq_domain *domain = irq_domain_alloc(of_node,
+                                       IRQ_DOMAIN_MAP_NOMAP, ops, host_data);
+       if (domain)
+               irq_domain_add(domain);
+       return domain;
+}
+
+/**
+ * irq_domain_add_tree()
+ * @of_node: pointer to interrupt controller's device tree node.
+ * @ops: map/unmap domain callbacks
+ *
+ * Note: The radix tree will be allocated later during boot automatically
+ * (the reverse mapping will use the slow path until that happens).
+ */
+struct irq_domain *irq_domain_add_tree(struct device_node *of_node,
+                                        const struct irq_domain_ops *ops,
+                                        void *host_data)
+{
+       struct irq_domain *domain = irq_domain_alloc(of_node,
+                                       IRQ_DOMAIN_MAP_TREE, ops, host_data);
+       if (domain) {
+               INIT_RADIX_TREE(&domain->revmap_data.tree, GFP_KERNEL);
+               irq_domain_add(domain);
+       }
+       return domain;
 }
 
 /**
- * irq_domain_del() - Unregister an irq_domain
- * @domain: ptr to registered irq_domain.
+ * irq_find_host() - Locates a domain for a given device node
+ * @node: device-tree node of the interrupt controller
  */
-void irq_domain_del(struct irq_domain *domain)
+struct irq_domain *irq_find_host(struct device_node *node)
 {
-       struct irq_data *d;
-       int hwirq, irq;
+       struct irq_domain *h, *found = NULL;
+       int rc;
 
+       /* We might want to match the legacy controller last since
+        * it might potentially be set to match all interrupts in
+        * the absence of a device node. This isn't a problem so far
+        * yet though...
+        */
        mutex_lock(&irq_domain_mutex);
-       list_del(&domain->list);
+       list_for_each_entry(h, &irq_domain_list, link) {
+               if (h->ops->match)
+                       rc = h->ops->match(h, node);
+               else
+                       rc = (h->of_node != NULL) && (h->of_node == node);
+
+               if (rc) {
+                       found = h;
+                       break;
+               }
+       }
        mutex_unlock(&irq_domain_mutex);
+       return found;
+}
+EXPORT_SYMBOL_GPL(irq_find_host);
+
+/**
+ * irq_set_default_host() - Set a "default" irq domain
+ * @domain: default domain pointer
+ *
+ * For convenience, it's possible to set a "default" domain that will be used
+ * whenever NULL is passed to irq_create_mapping(). It makes life easier for
+ * platforms that want to manipulate a few hard coded interrupt numbers that
+ * aren't properly represented in the device-tree.
+ */
+void irq_set_default_host(struct irq_domain *domain)
+{
+       pr_debug("irq: Default domain set to @0x%p\n", domain);
+
+       irq_default_domain = domain;
+}
+
+/**
+ * irq_set_virq_count() - Set the maximum number of linux irqs
+ * @count: number of linux irqs, capped with NR_IRQS
+ *
+ * This is mainly for use by platforms like iSeries who want to program
+ * the virtual irq number in the controller to avoid the reverse mapping
+ */
+void irq_set_virq_count(unsigned int count)
+{
+       pr_debug("irq: Trying to set virq count to %d\n", count);
 
-       /* Clear the irq_domain assignments */
-       irq_domain_for_each_irq(domain, hwirq, irq) {
-               d = irq_get_irq_data(irq);
-               d->domain = NULL;
+       BUG_ON(count < NUM_ISA_INTERRUPTS);
+       if (count < NR_IRQS)
+               irq_virq_count = count;
+}
+
+static int irq_setup_virq(struct irq_domain *domain, unsigned int virq,
+                           irq_hw_number_t hwirq)
+{
+       struct irq_data *irq_data = irq_get_irq_data(virq);
+
+       irq_data->hwirq = hwirq;
+       irq_data->domain = domain;
+       if (domain->ops->map(domain, virq, hwirq)) {
+               pr_debug("irq: -> mapping failed, freeing\n");
+               irq_data->domain = NULL;
+               irq_data->hwirq = 0;
+               return -1;
        }
+
+       irq_clear_status_flags(virq, IRQ_NOREQUEST);
+
+       return 0;
 }
 
-#if defined(CONFIG_OF_IRQ)
 /**
- * irq_create_of_mapping() - Map a linux irq number from a DT interrupt spec
+ * irq_create_direct_mapping() - Allocate an irq for direct mapping
+ * @domain: domain to allocate the irq for or NULL for default domain
  *
- * Used by the device tree interrupt mapping code to translate a device tree
- * interrupt specifier to a valid linux irq number.  Returns either a valid
- * linux IRQ number or 0.
+ * This routine is used for irq controllers which can choose the hardware
+ * interrupt numbers they generate. In such a case it's simplest to use
+ * the linux irq as the hardware interrupt number.
+ */
+unsigned int irq_create_direct_mapping(struct irq_domain *domain)
+{
+       unsigned int virq;
+
+       if (domain == NULL)
+               domain = irq_default_domain;
+
+       BUG_ON(domain == NULL);
+       WARN_ON(domain->revmap_type != IRQ_DOMAIN_MAP_NOMAP);
+
+       virq = irq_alloc_desc_from(1, 0);
+       if (!virq) {
+               pr_debug("irq: create_direct virq allocation failed\n");
+               return 0;
+       }
+       if (virq >= irq_virq_count) {
+               pr_err("ERROR: no free irqs available below %i maximum\n",
+                       irq_virq_count);
+               irq_free_desc(virq);
+               return 0;
+       }
+
+       pr_debug("irq: create_direct obtained virq %d\n", virq);
+
+       if (irq_setup_virq(domain, virq, virq)) {
+               irq_free_desc(virq);
+               return 0;
+       }
+
+       return virq;
+}
+
+/**
+ * irq_create_mapping() - Map a hardware interrupt into linux irq space
+ * @domain: domain owning this hardware interrupt or NULL for default domain
+ * @hwirq: hardware irq number in that domain space
  *
- * When the caller no longer need the irq number returned by this function it
- * should arrange to call irq_dispose_mapping().
+ * Only one mapping per hardware interrupt is permitted. Returns a linux
+ * irq number.
+ * If the sense/trigger is to be specified, set_irq_type() should be called
+ * on the number returned from that call.
  */
+unsigned int irq_create_mapping(struct irq_domain *domain,
+                               irq_hw_number_t hwirq)
+{
+       unsigned int virq, hint;
+
+       pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);
+
+       /* Look for default domain if nececssary */
+       if (domain == NULL)
+               domain = irq_default_domain;
+       if (domain == NULL) {
+               printk(KERN_WARNING "irq_create_mapping called for"
+                      " NULL domain, hwirq=%lx\n", hwirq);
+               WARN_ON(1);
+               return 0;
+       }
+       pr_debug("irq: -> using domain @%p\n", domain);
+
+       /* Check if mapping already exists */
+       virq = irq_find_mapping(domain, hwirq);
+       if (virq) {
+               pr_debug("irq: -> existing mapping on virq %d\n", virq);
+               return virq;
+       }
+
+       /* Get a virtual interrupt number */
+       if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY)
+               return irq_domain_legacy_revmap(domain, hwirq);
+
+       /* Allocate a virtual interrupt number */
+       hint = hwirq % irq_virq_count;
+       if (hint == 0)
+               hint++;
+       virq = irq_alloc_desc_from(hint, 0);
+       if (!virq)
+               virq = irq_alloc_desc_from(1, 0);
+       if (!virq) {
+               pr_debug("irq: -> virq allocation failed\n");
+               return 0;
+       }
+
+       if (irq_setup_virq(domain, virq, hwirq)) {
+               if (domain->revmap_type != IRQ_DOMAIN_MAP_LEGACY)
+                       irq_free_desc(virq);
+               return 0;
+       }
+
+       pr_debug("irq: irq %lu on domain %s mapped to virtual irq %u\n",
+               hwirq, domain->of_node ? domain->of_node->full_name : "null", virq);
+
+       return virq;
+}
+EXPORT_SYMBOL_GPL(irq_create_mapping);
+
 unsigned int irq_create_of_mapping(struct device_node *controller,
                                   const u32 *intspec, unsigned int intsize)
 {
        struct irq_domain *domain;
-       unsigned long hwirq;
-       unsigned int irq, type;
-       int rc = -EINVAL;
+       irq_hw_number_t hwirq;
+       unsigned int type = IRQ_TYPE_NONE;
+       unsigned int virq;
 
-       /* Find a domain which can translate the irq spec */
-       mutex_lock(&irq_domain_mutex);
-       list_for_each_entry(domain, &irq_domain_list, list) {
-               if (!domain->ops->dt_translate)
-                       continue;
-               rc = domain->ops->dt_translate(domain, controller,
-                                       intspec, intsize, &hwirq, &type);
-               if (rc == 0)
-                       break;
+       domain = controller ? irq_find_host(controller) : irq_default_domain;
+       if (!domain) {
+#ifdef CONFIG_MIPS
+               /*
+                * Workaround to avoid breaking interrupt controller drivers
+                * that don't yet register an irq_domain.  This is temporary
+                * code. ~~~gcl, Feb 24, 2012
+                *
+                * Scheduled for removal in Linux v3.6.  That should be enough
+                * time.
+                */
+               if (intsize > 0)
+                       return intspec[0];
+#endif
+               printk(KERN_WARNING "irq: no irq domain found for %s !\n",
+                      controller->full_name);
+               return 0;
        }
-       mutex_unlock(&irq_domain_mutex);
 
-       if (rc != 0)
-               return 0;
+       /* If domain has no translation, then we assume interrupt line */
+       if (domain->ops->xlate == NULL)
+               hwirq = intspec[0];
+       else {
+               if (domain->ops->xlate(domain, controller, intspec, intsize,
+                                    &hwirq, &type))
+                       return 0;
+       }
+
+       /* Create mapping */
+       virq = irq_create_mapping(domain, hwirq);
+       if (!virq)
+               return virq;
 
-       irq = irq_domain_to_irq(domain, hwirq);
-       if (type != IRQ_TYPE_NONE)
-               irq_set_irq_type(irq, type);
-       pr_debug("%s: mapped hwirq=%i to irq=%i, flags=%x\n",
-                controller->full_name, (int)hwirq, irq, type);
-       return irq;
+       /* Set type if specified and different than the current one */
+       if (type != IRQ_TYPE_NONE &&
+           type != (irqd_get_trigger_type(irq_get_irq_data(virq))))
+               irq_set_irq_type(virq, type);
+       return virq;
 }
 EXPORT_SYMBOL_GPL(irq_create_of_mapping);
 
 /**
- * irq_dispose_mapping() - Discard a mapping created by irq_create_of_mapping()
- * @irq: linux irq number to be discarded
+ * irq_dispose_mapping() - Unmap an interrupt
+ * @virq: linux irq number of the interrupt to unmap
+ */
+void irq_dispose_mapping(unsigned int virq)
+{
+       struct irq_data *irq_data = irq_get_irq_data(virq);
+       struct irq_domain *domain;
+       irq_hw_number_t hwirq;
+
+       if (!virq || !irq_data)
+               return;
+
+       domain = irq_data->domain;
+       if (WARN_ON(domain == NULL))
+               return;
+
+       /* Never unmap legacy interrupts */
+       if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY)
+               return;
+
+       irq_set_status_flags(virq, IRQ_NOREQUEST);
+
+       /* remove chip and handler */
+       irq_set_chip_and_handler(virq, NULL, NULL);
+
+       /* Make sure it's completed */
+       synchronize_irq(virq);
+
+       /* Tell the PIC about it */
+       if (domain->ops->unmap)
+               domain->ops->unmap(domain, virq);
+       smp_mb();
+
+       /* Clear reverse map */
+       hwirq = irq_data->hwirq;
+       switch(domain->revmap_type) {
+       case IRQ_DOMAIN_MAP_LINEAR:
+               if (hwirq < domain->revmap_data.linear.size)
+                       domain->revmap_data.linear.revmap[hwirq] = 0;
+               break;
+       case IRQ_DOMAIN_MAP_TREE:
+               mutex_lock(&revmap_trees_mutex);
+               radix_tree_delete(&domain->revmap_data.tree, hwirq);
+               mutex_unlock(&revmap_trees_mutex);
+               break;
+       }
+
+       irq_free_desc(virq);
+}
+EXPORT_SYMBOL_GPL(irq_dispose_mapping);
+
+/**
+ * irq_find_mapping() - Find a linux irq from an hw irq number.
+ * @domain: domain owning this hardware interrupt
+ * @hwirq: hardware irq number in that domain space
+ *
+ * This is a slow path, for use by generic code. It's expected that an
+ * irq controller implementation directly calls the appropriate low level
+ * mapping function.
+ */
+unsigned int irq_find_mapping(struct irq_domain *domain,
+                             irq_hw_number_t hwirq)
+{
+       unsigned int i;
+       unsigned int hint = hwirq % irq_virq_count;
+
+       /* Look for default domain if nececssary */
+       if (domain == NULL)
+               domain = irq_default_domain;
+       if (domain == NULL)
+               return 0;
+
+       /* legacy -> bail early */
+       if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY)
+               return irq_domain_legacy_revmap(domain, hwirq);
+
+       /* Slow path does a linear search of the map */
+       if (hint == 0)
+               hint = 1;
+       i = hint;
+       do {
+               struct irq_data *data = irq_get_irq_data(i);
+               if (data && (data->domain == domain) && (data->hwirq == hwirq))
+                       return i;
+               i++;
+               if (i >= irq_virq_count)
+                       i = 1;
+       } while(i != hint);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(irq_find_mapping);
+
+/**
+ * irq_radix_revmap_lookup() - Find a linux irq from a hw irq number.
+ * @domain: domain owning this hardware interrupt
+ * @hwirq: hardware irq number in that domain space
  *
- * Calling this function indicates the caller no longer needs a reference to
- * the linux irq number returned by a prior call to irq_create_of_mapping().
+ * This is a fast path, for use by irq controller code that uses radix tree
+ * revmaps
  */
-void irq_dispose_mapping(unsigned int irq)
+unsigned int irq_radix_revmap_lookup(struct irq_domain *domain,
+                                    irq_hw_number_t hwirq)
 {
+       struct irq_data *irq_data;
+
+       if (WARN_ON_ONCE(domain->revmap_type != IRQ_DOMAIN_MAP_TREE))
+               return irq_find_mapping(domain, hwirq);
+
+       /*
+        * Freeing an irq can delete nodes along the path to
+        * do the lookup via call_rcu.
+        */
+       rcu_read_lock();
+       irq_data = radix_tree_lookup(&domain->revmap_data.tree, hwirq);
+       rcu_read_unlock();
+
        /*
-        * nothing yet; will be filled when support for dynamic allocation of
-        * irq_descs is added to irq_domain
+        * If found in radix tree, then fine.
+        * Else fallback to linear lookup - this should not happen in practice
+        * as it means that we failed to insert the node in the radix tree.
         */
+       return irq_data ? irq_data->irq : irq_find_mapping(domain, hwirq);
 }
-EXPORT_SYMBOL_GPL(irq_dispose_mapping);
 
-int irq_domain_simple_dt_translate(struct irq_domain *d,
-                           struct device_node *controller,
-                           const u32 *intspec, unsigned int intsize,
-                           unsigned long *out_hwirq, unsigned int *out_type)
+/**
+ * irq_radix_revmap_insert() - Insert a hw irq to linux irq number mapping.
+ * @domain: domain owning this hardware interrupt
+ * @virq: linux irq number
+ * @hwirq: hardware irq number in that domain space
+ *
+ * This is for use by irq controllers that use a radix tree reverse
+ * mapping for fast lookup.
+ */
+void irq_radix_revmap_insert(struct irq_domain *domain, unsigned int virq,
+                            irq_hw_number_t hwirq)
 {
-       if (d->of_node != controller)
-               return -EINVAL;
-       if (intsize < 1)
-               return -EINVAL;
-       if (d->nr_irq && ((intspec[0] < d->hwirq_base) ||
-           (intspec[0] >= d->hwirq_base + d->nr_irq)))
-               return -EINVAL;
+       struct irq_data *irq_data = irq_get_irq_data(virq);
+
+       if (WARN_ON(domain->revmap_type != IRQ_DOMAIN_MAP_TREE))
+               return;
+
+       if (virq) {
+               mutex_lock(&revmap_trees_mutex);
+               radix_tree_insert(&domain->revmap_data.tree, hwirq, irq_data);
+               mutex_unlock(&revmap_trees_mutex);
+       }
+}
+
+/**
+ * irq_linear_revmap() - Find a linux irq from a hw irq number.
+ * @domain: domain owning this hardware interrupt
+ * @hwirq: hardware irq number in that domain space
+ *
+ * This is a fast path, for use by irq controller code that uses linear
+ * revmaps. It does fallback to the slow path if the revmap doesn't exist
+ * yet and will create the revmap entry with appropriate locking
+ */
+unsigned int irq_linear_revmap(struct irq_domain *domain,
+                              irq_hw_number_t hwirq)
+{
+       unsigned int *revmap;
+
+       if (WARN_ON_ONCE(domain->revmap_type != IRQ_DOMAIN_MAP_LINEAR))
+               return irq_find_mapping(domain, hwirq);
+
+       /* Check revmap bounds */
+       if (unlikely(hwirq >= domain->revmap_data.linear.size))
+               return irq_find_mapping(domain, hwirq);
+
+       /* Check if revmap was allocated */
+       revmap = domain->revmap_data.linear.revmap;
+       if (unlikely(revmap == NULL))
+               return irq_find_mapping(domain, hwirq);
+
+       /* Fill up revmap with slow path if no mapping found */
+       if (unlikely(!revmap[hwirq]))
+               revmap[hwirq] = irq_find_mapping(domain, hwirq);
+
+       return revmap[hwirq];
+}
+
+#ifdef CONFIG_VIRQ_DEBUG
+static int virq_debug_show(struct seq_file *m, void *private)
+{
+       unsigned long flags;
+       struct irq_desc *desc;
+       const char *p;
+       static const char none[] = "none";
+       void *data;
+       int i;
+
+       seq_printf(m, "%-5s  %-7s  %-15s  %-18s  %s\n", "virq", "hwirq",
+                     "chip name", "chip data", "domain name");
+
+       for (i = 1; i < nr_irqs; i++) {
+               desc = irq_to_desc(i);
+               if (!desc)
+                       continue;
+
+               raw_spin_lock_irqsave(&desc->lock, flags);
+
+               if (desc->action && desc->action->handler) {
+                       struct irq_chip *chip;
+
+                       seq_printf(m, "%5d  ", i);
+                       seq_printf(m, "0x%05lx  ", desc->irq_data.hwirq);
+
+                       chip = irq_desc_get_chip(desc);
+                       if (chip && chip->name)
+                               p = chip->name;
+                       else
+                               p = none;
+                       seq_printf(m, "%-15s  ", p);
+
+                       data = irq_desc_get_chip_data(desc);
+                       seq_printf(m, "0x%16p  ", data);
+
+                       if (desc->irq_data.domain->of_node)
+                               p = desc->irq_data.domain->of_node->full_name;
+                       else
+                               p = none;
+                       seq_printf(m, "%s\n", p);
+               }
+
+               raw_spin_unlock_irqrestore(&desc->lock, flags);
+       }
+
+       return 0;
+}
 
+static int virq_debug_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, virq_debug_show, inode->i_private);
+}
+
+static const struct file_operations virq_debug_fops = {
+       .open = virq_debug_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static int __init irq_debugfs_init(void)
+{
+       if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root,
+                                NULL, &virq_debug_fops) == NULL)
+               return -ENOMEM;
+
+       return 0;
+}
+__initcall(irq_debugfs_init);
+#endif /* CONFIG_VIRQ_DEBUG */
+
+int irq_domain_simple_map(struct irq_domain *d, unsigned int irq,
+                         irq_hw_number_t hwirq)
+{
+       return 0;
+}
+
+/**
+ * irq_domain_xlate_onecell() - Generic xlate for direct one cell bindings
+ *
+ * Device Tree IRQ specifier translation function which works with one cell
+ * bindings where the cell value maps directly to the hwirq number.
+ */
+int irq_domain_xlate_onecell(struct irq_domain *d, struct device_node *ctrlr,
+                            const u32 *intspec, unsigned int intsize,
+                            unsigned long *out_hwirq, unsigned int *out_type)
+{
+       if (WARN_ON(intsize < 1))
+               return -EINVAL;
        *out_hwirq = intspec[0];
        *out_type = IRQ_TYPE_NONE;
-       if (intsize > 1)
-               *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
        return 0;
 }
+EXPORT_SYMBOL_GPL(irq_domain_xlate_onecell);
 
 /**
- * irq_domain_create_simple() - Set up a 'simple' translation range
+ * irq_domain_xlate_twocell() - Generic xlate for direct two cell bindings
+ *
+ * Device Tree IRQ specifier translation function which works with two cell
+ * bindings where the cell values map directly to the hwirq number
+ * and linux irq flags.
  */
-void irq_domain_add_simple(struct device_node *controller, int irq_base)
+int irq_domain_xlate_twocell(struct irq_domain *d, struct device_node *ctrlr,
+                       const u32 *intspec, unsigned int intsize,
+                       irq_hw_number_t *out_hwirq, unsigned int *out_type)
 {
-       struct irq_domain *domain;
-
-       domain = kzalloc(sizeof(*domain), GFP_KERNEL);
-       if (!domain) {
-               WARN_ON(1);
-               return;
-       }
+       if (WARN_ON(intsize < 2))
+               return -EINVAL;
+       *out_hwirq = intspec[0];
+       *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(irq_domain_xlate_twocell);
 
-       domain->irq_base = irq_base;
-       domain->of_node = of_node_get(controller);
-       domain->ops = &irq_domain_simple_ops;
-       irq_domain_add(domain);
+/**
+ * irq_domain_xlate_onetwocell() - Generic xlate for one or two cell bindings
+ *
+ * Device Tree IRQ specifier translation function which works with either one
+ * or two cell bindings where the cell values map directly to the hwirq number
+ * and linux irq flags.
+ *
+ * Note: don't use this function unless your interrupt controller explicitly
+ * supports both one and two cell bindings.  For the majority of controllers
+ * the _onecell() or _twocell() variants above should be used.
+ */
+int irq_domain_xlate_onetwocell(struct irq_domain *d,
+                               struct device_node *ctrlr,
+                               const u32 *intspec, unsigned int intsize,
+                               unsigned long *out_hwirq, unsigned int *out_type)
+{
+       if (WARN_ON(intsize < 1))
+               return -EINVAL;
+       *out_hwirq = intspec[0];
+       *out_type = (intsize > 1) ? intspec[1] : IRQ_TYPE_NONE;
+       return 0;
 }
-EXPORT_SYMBOL_GPL(irq_domain_add_simple);
+EXPORT_SYMBOL_GPL(irq_domain_xlate_onetwocell);
 
+const struct irq_domain_ops irq_domain_simple_ops = {
+       .map = irq_domain_simple_map,
+       .xlate = irq_domain_xlate_onetwocell,
+};
+EXPORT_SYMBOL_GPL(irq_domain_simple_ops);
+
+#ifdef CONFIG_OF_IRQ
 void irq_domain_generate_simple(const struct of_device_id *match,
                                u64 phys_base, unsigned int irq_start)
 {
        struct device_node *node;
-       pr_info("looking for phys_base=%llx, irq_start=%i\n",
+       pr_debug("looking for phys_base=%llx, irq_start=%i\n",
                (unsigned long long) phys_base, (int) irq_start);
        node = of_find_matching_node_by_address(NULL, match, phys_base);
        if (node)
-               irq_domain_add_simple(node, irq_start);
-       else
-               pr_info("no node found\n");
+               irq_domain_add_legacy(node, 32, irq_start, 0,
+                                     &irq_domain_simple_ops, NULL);
 }
 EXPORT_SYMBOL_GPL(irq_domain_generate_simple);
-#endif /* CONFIG_OF_IRQ */
-
-struct irq_domain_ops irq_domain_simple_ops = {
-#ifdef CONFIG_OF_IRQ
-       .dt_translate = irq_domain_simple_dt_translate,
-#endif /* CONFIG_OF_IRQ */
-};
-EXPORT_SYMBOL_GPL(irq_domain_simple_ops);
+#endif