forked from Minki/linux
Merge branch 'next/soc2' into HEAD
This commit is contained in:
commit
5c008d7029
@ -485,7 +485,9 @@ config ARCH_MXS
|
|||||||
select CLKSRC_MMIO
|
select CLKSRC_MMIO
|
||||||
select COMMON_CLK
|
select COMMON_CLK
|
||||||
select HAVE_CLK_PREPARE
|
select HAVE_CLK_PREPARE
|
||||||
|
select MULTI_IRQ_HANDLER
|
||||||
select PINCTRL
|
select PINCTRL
|
||||||
|
select SPARSE_IRQ
|
||||||
select USE_OF
|
select USE_OF
|
||||||
help
|
help
|
||||||
Support for Freescale MXS-based family of processors
|
Support for Freescale MXS-based family of processors
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
ranges;
|
ranges;
|
||||||
|
|
||||||
icoll: interrupt-controller@80000000 {
|
icoll: interrupt-controller@80000000 {
|
||||||
compatible = "fsl,imx23-icoll", "fsl,mxs-icoll";
|
compatible = "fsl,imx23-icoll", "fsl,icoll";
|
||||||
interrupt-controller;
|
interrupt-controller;
|
||||||
#interrupt-cells = <1>;
|
#interrupt-cells = <1>;
|
||||||
reg = <0x80000000 0x2000>;
|
reg = <0x80000000 0x2000>;
|
||||||
@ -407,8 +407,9 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
timrot@80068000 {
|
timrot@80068000 {
|
||||||
|
compatible = "fsl,imx23-timrot", "fsl,timrot";
|
||||||
reg = <0x80068000 0x2000>;
|
reg = <0x80068000 0x2000>;
|
||||||
status = "disabled";
|
interrupts = <28 29 30 31>;
|
||||||
};
|
};
|
||||||
|
|
||||||
auart0: serial@8006c000 {
|
auart0: serial@8006c000 {
|
||||||
|
@ -52,7 +52,7 @@
|
|||||||
ranges;
|
ranges;
|
||||||
|
|
||||||
icoll: interrupt-controller@80000000 {
|
icoll: interrupt-controller@80000000 {
|
||||||
compatible = "fsl,imx28-icoll", "fsl,mxs-icoll";
|
compatible = "fsl,imx28-icoll", "fsl,icoll";
|
||||||
interrupt-controller;
|
interrupt-controller;
|
||||||
#interrupt-cells = <1>;
|
#interrupt-cells = <1>;
|
||||||
reg = <0x80000000 0x2000>;
|
reg = <0x80000000 0x2000>;
|
||||||
@ -787,8 +787,9 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
timrot@80068000 {
|
timrot@80068000 {
|
||||||
|
compatible = "fsl,imx28-timrot", "fsl,timrot";
|
||||||
reg = <0x80068000 0x2000>;
|
reg = <0x80068000 0x2000>;
|
||||||
status = "disabled";
|
interrupts = <48 49 50 51>;
|
||||||
};
|
};
|
||||||
|
|
||||||
auart0: serial@8006a000 {
|
auart0: serial@8006a000 {
|
||||||
|
@ -19,20 +19,27 @@
|
|||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
|
#include <linux/irqdomain.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_irq.h>
|
||||||
|
#include <asm/exception.h>
|
||||||
#include <mach/mxs.h>
|
#include <mach/mxs.h>
|
||||||
#include <mach/common.h>
|
#include <mach/common.h>
|
||||||
|
|
||||||
#define HW_ICOLL_VECTOR 0x0000
|
#define HW_ICOLL_VECTOR 0x0000
|
||||||
#define HW_ICOLL_LEVELACK 0x0010
|
#define HW_ICOLL_LEVELACK 0x0010
|
||||||
#define HW_ICOLL_CTRL 0x0020
|
#define HW_ICOLL_CTRL 0x0020
|
||||||
|
#define HW_ICOLL_STAT_OFFSET 0x0070
|
||||||
#define HW_ICOLL_INTERRUPTn_SET(n) (0x0124 + (n) * 0x10)
|
#define HW_ICOLL_INTERRUPTn_SET(n) (0x0124 + (n) * 0x10)
|
||||||
#define HW_ICOLL_INTERRUPTn_CLR(n) (0x0128 + (n) * 0x10)
|
#define HW_ICOLL_INTERRUPTn_CLR(n) (0x0128 + (n) * 0x10)
|
||||||
#define BM_ICOLL_INTERRUPTn_ENABLE 0x00000004
|
#define BM_ICOLL_INTERRUPTn_ENABLE 0x00000004
|
||||||
#define BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0 0x1
|
#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 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)
|
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)
|
static void icoll_mask_irq(struct irq_data *d)
|
||||||
{
|
{
|
||||||
__raw_writel(BM_ICOLL_INTERRUPTn_ENABLE,
|
__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)
|
static void icoll_unmask_irq(struct irq_data *d)
|
||||||
{
|
{
|
||||||
__raw_writel(BM_ICOLL_INTERRUPTn_ENABLE,
|
__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 = {
|
static struct irq_chip mxs_icoll_chip = {
|
||||||
@ -63,18 +70,56 @@ static struct irq_chip mxs_icoll_chip = {
|
|||||||
.irq_unmask = icoll_unmask_irq,
|
.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
|
* Interrupt Collector reset, which initializes the priority
|
||||||
* for each irq to level 0.
|
* for each irq to level 0.
|
||||||
*/
|
*/
|
||||||
mxs_reset_block(icoll_base + HW_ICOLL_CTRL);
|
mxs_reset_block(icoll_base + HW_ICOLL_CTRL);
|
||||||
|
|
||||||
for (i = 0; i < MXS_INTERNAL_IRQS; i++) {
|
icoll_domain = irq_domain_add_linear(np, ICOLL_NUM_IRQS,
|
||||||
irq_set_chip_and_handler(i, &mxs_icoll_chip, handle_level_irq);
|
&icoll_irq_domain_ops, NULL);
|
||||||
set_irq_flags(i, IRQF_VALID);
|
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 const u32 *mxs_get_ocotp(void);
|
||||||
extern int mxs_reset_block(void __iomem *);
|
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 void mxs_restart(char, const char *);
|
||||||
extern int mxs_saif_clkmux_select(unsigned int clkmux);
|
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 mx28_map_io(void);
|
||||||
|
|
||||||
extern void icoll_init_irq(void);
|
extern void icoll_init_irq(void);
|
||||||
|
extern void icoll_handle_irq(struct pt_regs *);
|
||||||
|
|
||||||
#endif /* __MACH_MXS_COMMON_H__ */
|
#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/err.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/irqdomain.h>
|
|
||||||
#include <linux/micrel_phy.h>
|
#include <linux/micrel_phy.h>
|
||||||
#include <linux/mxsfb.h>
|
#include <linux/mxsfb.h>
|
||||||
#include <linux/of_irq.h>
|
|
||||||
#include <linux/of_platform.h>
|
#include <linux/of_platform.h>
|
||||||
#include <linux/phy.h>
|
#include <linux/phy.h>
|
||||||
#include <linux/pinctrl/consumer.h>
|
#include <linux/pinctrl/consumer.h>
|
||||||
@ -141,37 +139,6 @@ static struct of_dev_auxdata mxs_auxdata_lookup[] __initdata = {
|
|||||||
{ /* sentinel */ }
|
{ /* 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)
|
static void __init imx23_timer_init(void)
|
||||||
{
|
{
|
||||||
mx23_clocks_init();
|
mx23_clocks_init();
|
||||||
@ -421,7 +388,8 @@ static const char *imx28_dt_compat[] __initdata = {
|
|||||||
|
|
||||||
DT_MACHINE_START(IMX23, "Freescale i.MX23 (Device Tree)")
|
DT_MACHINE_START(IMX23, "Freescale i.MX23 (Device Tree)")
|
||||||
.map_io = mx23_map_io,
|
.map_io = mx23_map_io,
|
||||||
.init_irq = mxs_dt_init_irq,
|
.init_irq = icoll_init_irq,
|
||||||
|
.handle_irq = icoll_handle_irq,
|
||||||
.timer = &imx23_timer,
|
.timer = &imx23_timer,
|
||||||
.init_machine = mxs_machine_init,
|
.init_machine = mxs_machine_init,
|
||||||
.dt_compat = imx23_dt_compat,
|
.dt_compat = imx23_dt_compat,
|
||||||
@ -430,7 +398,8 @@ MACHINE_END
|
|||||||
|
|
||||||
DT_MACHINE_START(IMX28, "Freescale i.MX28 (Device Tree)")
|
DT_MACHINE_START(IMX28, "Freescale i.MX28 (Device Tree)")
|
||||||
.map_io = mx28_map_io,
|
.map_io = mx28_map_io,
|
||||||
.init_irq = mxs_dt_init_irq,
|
.init_irq = icoll_init_irq,
|
||||||
|
.handle_irq = icoll_handle_irq,
|
||||||
.timer = &imx28_timer,
|
.timer = &imx28_timer,
|
||||||
.init_machine = mxs_machine_init,
|
.init_machine = mxs_machine_init,
|
||||||
.dt_compat = imx28_dt_compat,
|
.dt_compat = imx28_dt_compat,
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
#include <linux/clockchips.h>
|
#include <linux/clockchips.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_irq.h>
|
||||||
|
|
||||||
#include <asm/mach/time.h>
|
#include <asm/mach/time.h>
|
||||||
#include <mach/mxs.h>
|
#include <mach/mxs.h>
|
||||||
@ -244,9 +246,17 @@ static int __init mxs_clocksource_init(struct clk *timer_clk)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __init mxs_timer_init(int irq)
|
void __init mxs_timer_init(void)
|
||||||
{
|
{
|
||||||
|
struct device_node *np;
|
||||||
struct clk *timer_clk;
|
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);
|
timer_clk = clk_get_sys("timrot", NULL);
|
||||||
if (IS_ERR(timer_clk)) {
|
if (IS_ERR(timer_clk)) {
|
||||||
@ -295,5 +305,6 @@ void __init mxs_timer_init(int irq)
|
|||||||
mxs_clockevent_init(timer_clk);
|
mxs_clockevent_init(timer_clk);
|
||||||
|
|
||||||
/* Make irqs happen */
|
/* Make irqs happen */
|
||||||
|
irq = irq_of_parse_and_map(np, 0);
|
||||||
setup_irq(irq, &mxs_timer_irq);
|
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++)
|
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
|
||||||
clk_prepare_enable(clks[clks_init_on[i]]);
|
clk_prepare_enable(clks[clks_init_on[i]]);
|
||||||
|
|
||||||
mxs_timer_init(MX23_INT_TIMER0);
|
mxs_timer_init();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -244,7 +244,7 @@ int __init mx28_clocks_init(void)
|
|||||||
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
|
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
|
||||||
clk_prepare_enable(clks[clks_init_on[i]]);
|
clk_prepare_enable(clks[clks_init_on[i]]);
|
||||||
|
|
||||||
mxs_timer_init(MX28_INT_TIMER0);
|
mxs_timer_init();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
|
#include <linux/irqdomain.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
@ -52,8 +53,6 @@
|
|||||||
#define GPIO_INT_LEV_MASK (1 << 0)
|
#define GPIO_INT_LEV_MASK (1 << 0)
|
||||||
#define GPIO_INT_POL_MASK (1 << 1)
|
#define GPIO_INT_POL_MASK (1 << 1)
|
||||||
|
|
||||||
#define irq_to_gpio(irq) ((irq) - MXS_GPIO_IRQ_START)
|
|
||||||
|
|
||||||
enum mxs_gpio_id {
|
enum mxs_gpio_id {
|
||||||
IMX23_GPIO,
|
IMX23_GPIO,
|
||||||
IMX28_GPIO,
|
IMX28_GPIO,
|
||||||
@ -63,7 +62,7 @@ struct mxs_gpio_port {
|
|||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
int id;
|
int id;
|
||||||
int irq;
|
int irq;
|
||||||
int virtual_irq_start;
|
struct irq_domain *domain;
|
||||||
struct bgpio_chip bgc;
|
struct bgpio_chip bgc;
|
||||||
enum mxs_gpio_id devid;
|
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)
|
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 << d->hwirq;
|
||||||
u32 pin_mask = 1 << (gpio & 31);
|
|
||||||
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
|
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
|
||||||
struct mxs_gpio_port *port = gc->private;
|
struct mxs_gpio_port *port = gc->private;
|
||||||
void __iomem *pin_addr;
|
void __iomem *pin_addr;
|
||||||
@ -120,7 +118,7 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
|
|||||||
else
|
else
|
||||||
writel(pin_mask, pin_addr + MXS_CLR);
|
writel(pin_mask, pin_addr + MXS_CLR);
|
||||||
|
|
||||||
writel(1 << (gpio & 0x1f),
|
writel(pin_mask,
|
||||||
port->base + PINCTRL_IRQSTAT(port) + MXS_CLR);
|
port->base + PINCTRL_IRQSTAT(port) + MXS_CLR);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -131,7 +129,6 @@ static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc)
|
|||||||
{
|
{
|
||||||
u32 irq_stat;
|
u32 irq_stat;
|
||||||
struct mxs_gpio_port *port = irq_get_handler_data(irq);
|
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);
|
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) {
|
while (irq_stat != 0) {
|
||||||
int irqoffset = fls(irq_stat) - 1;
|
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);
|
irq_stat &= ~(1 << irqoffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -167,12 +164,12 @@ static int mxs_gpio_set_wake_irq(struct irq_data *d, unsigned int enable)
|
|||||||
return 0;
|
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_generic *gc;
|
||||||
struct irq_chip_type *ct;
|
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);
|
port->base, handle_level_irq);
|
||||||
gc->private = port;
|
gc->private = port;
|
||||||
|
|
||||||
@ -194,7 +191,7 @@ static int mxs_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
|
|||||||
struct mxs_gpio_port *port =
|
struct mxs_gpio_port *port =
|
||||||
container_of(bgc, struct mxs_gpio_port, bgc);
|
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[] = {
|
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;
|
static void __iomem *base;
|
||||||
struct mxs_gpio_port *port;
|
struct mxs_gpio_port *port;
|
||||||
struct resource *iores = NULL;
|
struct resource *iores = NULL;
|
||||||
|
int irq_base;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
|
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->id = pdev->id;
|
||||||
port->devid = pdev->id_entry->driver_data;
|
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);
|
port->irq = platform_get_irq(pdev, 0);
|
||||||
if (port->irq < 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 */
|
/* clear address has to be used to clear IRQSTAT bits */
|
||||||
writel(~0U, port->base + PINCTRL_IRQSTAT(port) + MXS_CLR);
|
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 */
|
/* 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 */
|
/* setup one handler for each entry */
|
||||||
irq_set_chained_handler(port->irq, mxs_gpio_irq_handler);
|
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_DOUT(port), NULL,
|
||||||
port->base + PINCTRL_DOE(port), NULL, 0);
|
port->base + PINCTRL_DOE(port), NULL, 0);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
goto out_irqdesc_free;
|
||||||
|
|
||||||
port->bgc.gc.to_irq = mxs_gpio_to_irq;
|
port->bgc.gc.to_irq = mxs_gpio_to_irq;
|
||||||
port->bgc.gc.base = port->id * 32;
|
port->bgc.gc.base = port->id * 32;
|
||||||
|
|
||||||
err = gpiochip_add(&port->bgc.gc);
|
err = gpiochip_add(&port->bgc.gc);
|
||||||
if (err) {
|
if (err)
|
||||||
bgpio_remove(&port->bgc);
|
goto out_bgpio_remove;
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
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 = {
|
static struct platform_driver mxs_gpio_driver = {
|
||||||
|
Loading…
Reference in New Issue
Block a user