mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 09:19:51 +00:00
ARM: soc: soc-specific updates, take 2
This branch converts the MXS Freescale platform to use irqdomains and sparse IRQ, in preparation for DT probing and multiplatform kernels. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJQaiKwAAoJEIwa5zzehBx32FQP/0wZ5YZ4XMsCZRlXkzixc+/K uJa8+1vj4M861/4Q5/QXxbW/lOamxM5djvbG8/zLyl05RmQ5zV8UggDFIRSy9Yrr UlCwQK2co30HGlNK9NsbSiMadEaDVw9KitW4hssaqIPVDKR0KAOY0P4lDHDDFxUr /ES6Hl9GL5pGnAKrnxgU/amdHNTWkeW3YD30l00+v+EJd+65nXecN+iSZWleiZyC tV9cxwBgSZIwYAy7rJoNyOaZyEO8xPpewUGFgGFLUYEUggan9MKtMH7FQZstQ/YY hVSsqc05FYecdviuaoGJmmzWddihMBo2hNLUZTt5b+VDdw/mOGl0WV9aAiYOSlOY z/npwgWA8TP74MvtTuoy6BRQgNL7a2B4/h35ZeQ37bQG6AuQmcFvSxg4oiuyWQJL OL40FGANx7e2KK2gVEzpA7CVA69v/lh8CGD/xYdxsO+/o/F48j2cdPdtsQrCh3Gq MUV4e89avp1UVt5t5186snGmP990y/5rxOfbF+z7n1iU4zt2Dc2+k0H65UAiNpeG xHwJP20pRmroBRQiuwQABasSUNO6HL98/ZDQvFRdDj/xBQQt1/uGetDKLGk+i+tW T6HQIHT70iy7Xds0ANbd1K1uurUoYD33pB2KwgHjib9C0fy0ChEYs5NGemkUew22 1iB6u0nTSrPnMXVg0M0e =wVa3 -----END PGP SIGNATURE----- Merge tag 'soc2' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc Pull ARM soc-specific updates, take 2 from Olof Johansson: "This branch converts the MXS Freescale platform to use irqdomains and sparse IRQ, in preparation for DT probing and multiplatform kernels." * tag 'soc2' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: ARM: mxs: remove mach/irqs.h ARM: mxs: select SPARSE_IRQ ARM: mxs: adopt irq_domain support for icoll driver ARM: mxs: select MULTI_IRQ_HANDLER ARM: mxs: retrieve timer irq from device tree gpio/mxs: adopt irq_domain support for mxs gpio driver
This commit is contained in:
commit
84be4ae2c0
12 changed files with 112 additions and 137 deletions
|
@ -485,7 +485,9 @@ config ARCH_MXS
|
|||
select CLKSRC_MMIO
|
||||
select COMMON_CLK
|
||||
select HAVE_CLK_PREPARE
|
||||
select MULTI_IRQ_HANDLER
|
||||
select PINCTRL
|
||||
select SPARSE_IRQ
|
||||
select USE_OF
|
||||
help
|
||||
Support for Freescale MXS-based family of processors
|
||||
|
|
|
@ -43,7 +43,7 @@ apbh@80000000 {
|
|||
ranges;
|
||||
|
||||
icoll: interrupt-controller@80000000 {
|
||||
compatible = "fsl,imx23-icoll", "fsl,mxs-icoll";
|
||||
compatible = "fsl,imx23-icoll", "fsl,icoll";
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
reg = <0x80000000 0x2000>;
|
||||
|
@ -407,8 +407,9 @@ pwm: pwm@80064000 {
|
|||
};
|
||||
|
||||
timrot@80068000 {
|
||||
compatible = "fsl,imx23-timrot", "fsl,timrot";
|
||||
reg = <0x80068000 0x2000>;
|
||||
status = "disabled";
|
||||
interrupts = <28 29 30 31>;
|
||||
};
|
||||
|
||||
auart0: serial@8006c000 {
|
||||
|
|
|
@ -52,7 +52,7 @@ apbh@80000000 {
|
|||
ranges;
|
||||
|
||||
icoll: interrupt-controller@80000000 {
|
||||
compatible = "fsl,imx28-icoll", "fsl,mxs-icoll";
|
||||
compatible = "fsl,imx28-icoll", "fsl,icoll";
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
reg = <0x80000000 0x2000>;
|
||||
|
@ -787,8 +787,9 @@ pwm: pwm@80064000 {
|
|||
};
|
||||
|
||||
timrot@80068000 {
|
||||
compatible = "fsl,imx28-timrot", "fsl,timrot";
|
||||
reg = <0x80068000 0x2000>;
|
||||
status = "disabled";
|
||||
interrupts = <48 49 50 51>;
|
||||
};
|
||||
|
||||
auart0: serial@8006a000 {
|
||||
|
|
|
@ -19,20 +19,27 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <asm/exception.h>
|
||||
#include <mach/mxs.h>
|
||||
#include <mach/common.h>
|
||||
|
||||
#define HW_ICOLL_VECTOR 0x0000
|
||||
#define HW_ICOLL_LEVELACK 0x0010
|
||||
#define HW_ICOLL_CTRL 0x0020
|
||||
#define HW_ICOLL_STAT_OFFSET 0x0070
|
||||
#define HW_ICOLL_INTERRUPTn_SET(n) (0x0124 + (n) * 0x10)
|
||||
#define HW_ICOLL_INTERRUPTn_CLR(n) (0x0128 + (n) * 0x10)
|
||||
#define BM_ICOLL_INTERRUPTn_ENABLE 0x00000004
|
||||
#define BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0 0x1
|
||||
|
||||
#define ICOLL_NUM_IRQS 128
|
||||
|
||||
static void __iomem *icoll_base = MXS_IO_ADDRESS(MXS_ICOLL_BASE_ADDR);
|
||||
static struct irq_domain *icoll_domain;
|
||||
|
||||
static void icoll_ack_irq(struct irq_data *d)
|
||||
{
|
||||
|
@ -48,13 +55,13 @@ static void icoll_ack_irq(struct irq_data *d)
|
|||
static void icoll_mask_irq(struct irq_data *d)
|
||||
{
|
||||
__raw_writel(BM_ICOLL_INTERRUPTn_ENABLE,
|
||||
icoll_base + HW_ICOLL_INTERRUPTn_CLR(d->irq));
|
||||
icoll_base + HW_ICOLL_INTERRUPTn_CLR(d->hwirq));
|
||||
}
|
||||
|
||||
static void icoll_unmask_irq(struct irq_data *d)
|
||||
{
|
||||
__raw_writel(BM_ICOLL_INTERRUPTn_ENABLE,
|
||||
icoll_base + HW_ICOLL_INTERRUPTn_SET(d->irq));
|
||||
icoll_base + HW_ICOLL_INTERRUPTn_SET(d->hwirq));
|
||||
}
|
||||
|
||||
static struct irq_chip mxs_icoll_chip = {
|
||||
|
@ -63,18 +70,56 @@ static struct irq_chip mxs_icoll_chip = {
|
|||
.irq_unmask = icoll_unmask_irq,
|
||||
};
|
||||
|
||||
void __init icoll_init_irq(void)
|
||||
asmlinkage void __exception_irq_entry icoll_handle_irq(struct pt_regs *regs)
|
||||
{
|
||||
int i;
|
||||
u32 irqnr;
|
||||
|
||||
do {
|
||||
irqnr = __raw_readl(icoll_base + HW_ICOLL_STAT_OFFSET);
|
||||
if (irqnr != 0x7f) {
|
||||
__raw_writel(irqnr, icoll_base + HW_ICOLL_VECTOR);
|
||||
irqnr = irq_find_mapping(icoll_domain, irqnr);
|
||||
handle_IRQ(irqnr, regs);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
} while (1);
|
||||
}
|
||||
|
||||
static int icoll_irq_domain_map(struct irq_domain *d, unsigned int virq,
|
||||
irq_hw_number_t hw)
|
||||
{
|
||||
irq_set_chip_and_handler(virq, &mxs_icoll_chip, handle_level_irq);
|
||||
set_irq_flags(virq, IRQF_VALID);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_domain_ops icoll_irq_domain_ops = {
|
||||
.map = icoll_irq_domain_map,
|
||||
.xlate = irq_domain_xlate_onecell,
|
||||
};
|
||||
|
||||
void __init icoll_of_init(struct device_node *np,
|
||||
struct device_node *interrupt_parent)
|
||||
{
|
||||
/*
|
||||
* Interrupt Collector reset, which initializes the priority
|
||||
* for each irq to level 0.
|
||||
*/
|
||||
mxs_reset_block(icoll_base + HW_ICOLL_CTRL);
|
||||
|
||||
for (i = 0; i < MXS_INTERNAL_IRQS; i++) {
|
||||
irq_set_chip_and_handler(i, &mxs_icoll_chip, handle_level_irq);
|
||||
set_irq_flags(i, IRQF_VALID);
|
||||
}
|
||||
icoll_domain = irq_domain_add_linear(np, ICOLL_NUM_IRQS,
|
||||
&icoll_irq_domain_ops, NULL);
|
||||
WARN_ON(!icoll_domain);
|
||||
}
|
||||
|
||||
static const struct of_device_id icoll_of_match[] __initconst = {
|
||||
{.compatible = "fsl,icoll", .data = icoll_of_init},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
void __init icoll_init_irq(void)
|
||||
{
|
||||
of_irq_init(icoll_of_match);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
extern const u32 *mxs_get_ocotp(void);
|
||||
extern int mxs_reset_block(void __iomem *);
|
||||
extern void mxs_timer_init(int);
|
||||
extern void mxs_timer_init(void);
|
||||
extern void mxs_restart(char, const char *);
|
||||
extern int mxs_saif_clkmux_select(unsigned int clkmux);
|
||||
|
||||
|
@ -24,5 +24,6 @@ extern int mx28_clocks_init(void);
|
|||
extern void mx28_map_io(void);
|
||||
|
||||
extern void icoll_init_irq(void);
|
||||
extern void icoll_handle_irq(struct pt_regs *);
|
||||
|
||||
#endif /* __MACH_MXS_COMMON_H__ */
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* Low-level IRQ helper macros for Freescale MXS-based
|
||||
*
|
||||
* Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <mach/mxs.h>
|
||||
|
||||
#define MXS_ICOLL_VBASE MXS_IO_ADDRESS(MXS_ICOLL_BASE_ADDR)
|
||||
#define HW_ICOLL_STAT_OFFSET 0x70
|
||||
|
||||
.macro get_irqnr_and_base, irqnr, irqstat, base, tmp
|
||||
ldr \irqnr, [\base, #HW_ICOLL_STAT_OFFSET]
|
||||
cmp \irqnr, #0x7F
|
||||
strne \irqnr, [\base]
|
||||
moveqs \irqnr, #0
|
||||
.endm
|
||||
|
||||
.macro get_irqnr_preamble, base, tmp
|
||||
ldr \base, =MXS_ICOLL_VBASE
|
||||
.endm
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __MACH_MXS_IRQS_H__
|
||||
#define __MACH_MXS_IRQS_H__
|
||||
|
||||
#define MXS_INTERNAL_IRQS 128
|
||||
|
||||
#define MXS_GPIO_IRQ_START MXS_INTERNAL_IRQS
|
||||
|
||||
/* the maximum for MXS-based */
|
||||
#define MXS_GPIO_IRQS (32 * 5)
|
||||
|
||||
/*
|
||||
* The next 16 interrupts are for board specific purposes. Since
|
||||
* the kernel can only run on one machine at a time, we can re-use
|
||||
* these. If you need more, increase MXS_BOARD_IRQS, but keep it
|
||||
* within sensible limits.
|
||||
*/
|
||||
#define MXS_BOARD_IRQ_START (MXS_GPIO_IRQ_START + MXS_GPIO_IRQS)
|
||||
#define MXS_BOARD_IRQS 16
|
||||
|
||||
#define NR_IRQS (MXS_BOARD_IRQ_START + MXS_BOARD_IRQS)
|
||||
|
||||
#endif /* __MACH_MXS_IRQS_H__ */
|
|
@ -17,10 +17,8 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/micrel_phy.h>
|
||||
#include <linux/mxsfb.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
|
@ -141,37 +139,6 @@ static struct of_dev_auxdata mxs_auxdata_lookup[] __initdata = {
|
|||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static int __init mxs_icoll_add_irq_domain(struct device_node *np,
|
||||
struct device_node *interrupt_parent)
|
||||
{
|
||||
irq_domain_add_legacy(np, 128, 0, 0, &irq_domain_simple_ops, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init mxs_gpio_add_irq_domain(struct device_node *np,
|
||||
struct device_node *interrupt_parent)
|
||||
{
|
||||
static int gpio_irq_base = MXS_GPIO_IRQ_START;
|
||||
|
||||
irq_domain_add_legacy(np, 32, gpio_irq_base, 0, &irq_domain_simple_ops, NULL);
|
||||
gpio_irq_base += 32;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id mxs_irq_match[] __initconst = {
|
||||
{ .compatible = "fsl,mxs-icoll", .data = mxs_icoll_add_irq_domain, },
|
||||
{ .compatible = "fsl,mxs-gpio", .data = mxs_gpio_add_irq_domain, },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static void __init mxs_dt_init_irq(void)
|
||||
{
|
||||
icoll_init_irq();
|
||||
of_irq_init(mxs_irq_match);
|
||||
}
|
||||
|
||||
static void __init imx23_timer_init(void)
|
||||
{
|
||||
mx23_clocks_init();
|
||||
|
@ -421,7 +388,8 @@ static const char *imx28_dt_compat[] __initdata = {
|
|||
|
||||
DT_MACHINE_START(IMX23, "Freescale i.MX23 (Device Tree)")
|
||||
.map_io = mx23_map_io,
|
||||
.init_irq = mxs_dt_init_irq,
|
||||
.init_irq = icoll_init_irq,
|
||||
.handle_irq = icoll_handle_irq,
|
||||
.timer = &imx23_timer,
|
||||
.init_machine = mxs_machine_init,
|
||||
.dt_compat = imx23_dt_compat,
|
||||
|
@ -430,7 +398,8 @@ MACHINE_END
|
|||
|
||||
DT_MACHINE_START(IMX28, "Freescale i.MX28 (Device Tree)")
|
||||
.map_io = mx28_map_io,
|
||||
.init_irq = mxs_dt_init_irq,
|
||||
.init_irq = icoll_init_irq,
|
||||
.handle_irq = icoll_handle_irq,
|
||||
.timer = &imx28_timer,
|
||||
.init_machine = mxs_machine_init,
|
||||
.dt_compat = imx28_dt_compat,
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#include <linux/irq.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
||||
#include <asm/mach/time.h>
|
||||
#include <mach/mxs.h>
|
||||
|
@ -244,9 +246,17 @@ static int __init mxs_clocksource_init(struct clk *timer_clk)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void __init mxs_timer_init(int irq)
|
||||
void __init mxs_timer_init(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
struct clk *timer_clk;
|
||||
int irq;
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "fsl,timrot");
|
||||
if (!np) {
|
||||
pr_err("%s: failed find timrot node\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
timer_clk = clk_get_sys("timrot", NULL);
|
||||
if (IS_ERR(timer_clk)) {
|
||||
|
@ -295,5 +305,6 @@ void __init mxs_timer_init(int irq)
|
|||
mxs_clockevent_init(timer_clk);
|
||||
|
||||
/* Make irqs happen */
|
||||
irq = irq_of_parse_and_map(np, 0);
|
||||
setup_irq(irq, &mxs_timer_irq);
|
||||
}
|
||||
|
|
|
@ -165,7 +165,7 @@ int __init mx23_clocks_init(void)
|
|||
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
|
||||
clk_prepare_enable(clks[clks_init_on[i]]);
|
||||
|
||||
mxs_timer_init(MX23_INT_TIMER0);
|
||||
mxs_timer_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -244,7 +244,7 @@ int __init mx28_clocks_init(void)
|
|||
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
|
||||
clk_prepare_enable(clks[clks_init_on[i]]);
|
||||
|
||||
mxs_timer_init(MX28_INT_TIMER0);
|
||||
mxs_timer_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
|
@ -52,8 +53,6 @@
|
|||
#define GPIO_INT_LEV_MASK (1 << 0)
|
||||
#define GPIO_INT_POL_MASK (1 << 1)
|
||||
|
||||
#define irq_to_gpio(irq) ((irq) - MXS_GPIO_IRQ_START)
|
||||
|
||||
enum mxs_gpio_id {
|
||||
IMX23_GPIO,
|
||||
IMX28_GPIO,
|
||||
|
@ -63,7 +62,7 @@ struct mxs_gpio_port {
|
|||
void __iomem *base;
|
||||
int id;
|
||||
int irq;
|
||||
int virtual_irq_start;
|
||||
struct irq_domain *domain;
|
||||
struct bgpio_chip bgc;
|
||||
enum mxs_gpio_id devid;
|
||||
};
|
||||
|
@ -82,8 +81,7 @@ static inline int is_imx28_gpio(struct mxs_gpio_port *port)
|
|||
|
||||
static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
u32 gpio = irq_to_gpio(d->irq);
|
||||
u32 pin_mask = 1 << (gpio & 31);
|
||||
u32 pin_mask = 1 << d->hwirq;
|
||||
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
|
||||
struct mxs_gpio_port *port = gc->private;
|
||||
void __iomem *pin_addr;
|
||||
|
@ -120,7 +118,7 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
|
|||
else
|
||||
writel(pin_mask, pin_addr + MXS_CLR);
|
||||
|
||||
writel(1 << (gpio & 0x1f),
|
||||
writel(pin_mask,
|
||||
port->base + PINCTRL_IRQSTAT(port) + MXS_CLR);
|
||||
|
||||
return 0;
|
||||
|
@ -131,7 +129,6 @@ static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc)
|
|||
{
|
||||
u32 irq_stat;
|
||||
struct mxs_gpio_port *port = irq_get_handler_data(irq);
|
||||
u32 gpio_irq_no_base = port->virtual_irq_start;
|
||||
|
||||
desc->irq_data.chip->irq_ack(&desc->irq_data);
|
||||
|
||||
|
@ -140,7 +137,7 @@ static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc)
|
|||
|
||||
while (irq_stat != 0) {
|
||||
int irqoffset = fls(irq_stat) - 1;
|
||||
generic_handle_irq(gpio_irq_no_base + irqoffset);
|
||||
generic_handle_irq(irq_find_mapping(port->domain, irqoffset));
|
||||
irq_stat &= ~(1 << irqoffset);
|
||||
}
|
||||
}
|
||||
|
@ -167,12 +164,12 @@ static int mxs_gpio_set_wake_irq(struct irq_data *d, unsigned int enable)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void __init mxs_gpio_init_gc(struct mxs_gpio_port *port)
|
||||
static void __init mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base)
|
||||
{
|
||||
struct irq_chip_generic *gc;
|
||||
struct irq_chip_type *ct;
|
||||
|
||||
gc = irq_alloc_generic_chip("gpio-mxs", 1, port->virtual_irq_start,
|
||||
gc = irq_alloc_generic_chip("gpio-mxs", 1, irq_base,
|
||||
port->base, handle_level_irq);
|
||||
gc->private = port;
|
||||
|
||||
|
@ -194,7 +191,7 @@ static int mxs_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
|
|||
struct mxs_gpio_port *port =
|
||||
container_of(bgc, struct mxs_gpio_port, bgc);
|
||||
|
||||
return port->virtual_irq_start + offset;
|
||||
return irq_find_mapping(port->domain, offset);
|
||||
}
|
||||
|
||||
static struct platform_device_id mxs_gpio_ids[] = {
|
||||
|
@ -226,6 +223,7 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev)
|
|||
static void __iomem *base;
|
||||
struct mxs_gpio_port *port;
|
||||
struct resource *iores = NULL;
|
||||
int irq_base;
|
||||
int err;
|
||||
|
||||
port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
|
||||
|
@ -241,7 +239,6 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev)
|
|||
port->id = pdev->id;
|
||||
port->devid = pdev->id_entry->driver_data;
|
||||
}
|
||||
port->virtual_irq_start = MXS_GPIO_IRQ_START + port->id * 32;
|
||||
|
||||
port->irq = platform_get_irq(pdev, 0);
|
||||
if (port->irq < 0)
|
||||
|
@ -275,8 +272,19 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev)
|
|||
/* clear address has to be used to clear IRQSTAT bits */
|
||||
writel(~0U, port->base + PINCTRL_IRQSTAT(port) + MXS_CLR);
|
||||
|
||||
irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id());
|
||||
if (irq_base < 0)
|
||||
return irq_base;
|
||||
|
||||
port->domain = irq_domain_add_legacy(np, 32, irq_base, 0,
|
||||
&irq_domain_simple_ops, NULL);
|
||||
if (!port->domain) {
|
||||
err = -ENODEV;
|
||||
goto out_irqdesc_free;
|
||||
}
|
||||
|
||||
/* gpio-mxs can be a generic irq chip */
|
||||
mxs_gpio_init_gc(port);
|
||||
mxs_gpio_init_gc(port, irq_base);
|
||||
|
||||
/* setup one handler for each entry */
|
||||
irq_set_chained_handler(port->irq, mxs_gpio_irq_handler);
|
||||
|
@ -287,18 +295,22 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev)
|
|||
port->base + PINCTRL_DOUT(port), NULL,
|
||||
port->base + PINCTRL_DOE(port), NULL, 0);
|
||||
if (err)
|
||||
return err;
|
||||
goto out_irqdesc_free;
|
||||
|
||||
port->bgc.gc.to_irq = mxs_gpio_to_irq;
|
||||
port->bgc.gc.base = port->id * 32;
|
||||
|
||||
err = gpiochip_add(&port->bgc.gc);
|
||||
if (err) {
|
||||
bgpio_remove(&port->bgc);
|
||||
return err;
|
||||
}
|
||||
if (err)
|
||||
goto out_bgpio_remove;
|
||||
|
||||
return 0;
|
||||
|
||||
out_bgpio_remove:
|
||||
bgpio_remove(&port->bgc);
|
||||
out_irqdesc_free:
|
||||
irq_free_descs(irq_base, 32);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct platform_driver mxs_gpio_driver = {
|
||||
|
|
Loading…
Reference in a new issue