diff options
Diffstat (limited to 'drivers')
35 files changed, 972 insertions, 430 deletions
| diff --git a/drivers/clk/mxs/clk-imx23.c b/drivers/clk/mxs/clk-imx23.c index b5c06f9766f..f6a74872f14 100644 --- a/drivers/clk/mxs/clk-imx23.c +++ b/drivers/clk/mxs/clk-imx23.c @@ -15,12 +15,15 @@  #include <linux/init.h>  #include <linux/io.h>  #include <linux/of.h> -#include <mach/common.h> -#include <mach/mx23.h> +#include <linux/of_address.h>  #include "clk.h" -#define DIGCTRL			MX23_IO_ADDRESS(MX23_DIGCTL_BASE_ADDR) -#define CLKCTRL			MX23_IO_ADDRESS(MX23_CLKCTRL_BASE_ADDR) +static void __iomem *clkctrl; +static void __iomem *digctrl; + +#define CLKCTRL clkctrl +#define DIGCTRL digctrl +  #define PLLCTRL0		(CLKCTRL + 0x0000)  #define CPU			(CLKCTRL + 0x0020)  #define HBUS			(CLKCTRL + 0x0030) @@ -48,10 +51,10 @@ static void __init clk_misc_init(void)  	u32 val;  	/* Gate off cpu clock in WFI for power saving */ -	__mxs_setl(1 << BP_CPU_INTERRUPT_WAIT, CPU); +	writel_relaxed(1 << BP_CPU_INTERRUPT_WAIT, CPU + SET);  	/* Clear BYPASS for SAIF */ -	__mxs_clrl(1 << BP_CLKSEQ_BYPASS_SAIF, CLKSEQ); +	writel_relaxed(1 << BP_CLKSEQ_BYPASS_SAIF, CLKSEQ + CLR);  	/* SAIF has to use frac div for functional operation */  	val = readl_relaxed(SAIF); @@ -62,14 +65,14 @@ static void __init clk_misc_init(void)  	 * Source ssp clock from ref_io than ref_xtal,  	 * as ref_xtal only provides 24 MHz as maximum.  	 */ -	__mxs_clrl(1 << BP_CLKSEQ_BYPASS_SSP, CLKSEQ); +	writel_relaxed(1 << BP_CLKSEQ_BYPASS_SSP, CLKSEQ + CLR);  	/*  	 * 480 MHz seems too high to be ssp clock source directly,  	 * so set frac to get a 288 MHz ref_io.  	 */ -	__mxs_clrl(0x3f << BP_FRAC_IOFRAC, FRAC); -	__mxs_setl(30 << BP_FRAC_IOFRAC, FRAC); +	writel_relaxed(0x3f << BP_FRAC_IOFRAC, FRAC + CLR); +	writel_relaxed(30 << BP_FRAC_IOFRAC, FRAC + SET);  }  static const char *sel_pll[]  __initconst = { "pll", "ref_xtal", }; @@ -101,6 +104,14 @@ int __init mx23_clocks_init(void)  	struct device_node *np;  	u32 i; +	np = of_find_compatible_node(NULL, NULL, "fsl,imx23-digctl"); +	digctrl = of_iomap(np, 0); +	WARN_ON(!digctrl); + +	np = of_find_compatible_node(NULL, NULL, "fsl,imx23-clkctrl"); +	clkctrl = of_iomap(np, 0); +	WARN_ON(!clkctrl); +  	clk_misc_init();  	clks[ref_xtal] = mxs_clk_fixed("ref_xtal", 24000000); @@ -153,19 +164,12 @@ int __init mx23_clocks_init(void)  			return PTR_ERR(clks[i]);  		} -	np = of_find_compatible_node(NULL, NULL, "fsl,imx23-clkctrl"); -	if (np) { -		clk_data.clks = clks; -		clk_data.clk_num = ARRAY_SIZE(clks); -		of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); -	} - -	clk_register_clkdev(clks[clk32k], NULL, "timrot"); +	clk_data.clks = clks; +	clk_data.clk_num = ARRAY_SIZE(clks); +	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);  	for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)  		clk_prepare_enable(clks[clks_init_on[i]]); -	mxs_timer_init(); -  	return 0;  } diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c index 76ce6c6d111..d0e5eed146d 100644 --- a/drivers/clk/mxs/clk-imx28.c +++ b/drivers/clk/mxs/clk-imx28.c @@ -15,11 +15,12 @@  #include <linux/init.h>  #include <linux/io.h>  #include <linux/of.h> -#include <mach/common.h> -#include <mach/mx28.h> +#include <linux/of_address.h>  #include "clk.h" -#define CLKCTRL			MX28_IO_ADDRESS(MX28_CLKCTRL_BASE_ADDR) +static void __iomem *clkctrl; +#define CLKCTRL clkctrl +  #define PLL0CTRL0		(CLKCTRL + 0x0000)  #define PLL1CTRL0		(CLKCTRL + 0x0020)  #define PLL2CTRL0		(CLKCTRL + 0x0040) @@ -53,7 +54,8 @@  #define BP_FRAC0_IO1FRAC	16  #define BP_FRAC0_IO0FRAC	24 -#define DIGCTRL			MX28_IO_ADDRESS(MX28_DIGCTL_BASE_ADDR) +static void __iomem *digctrl; +#define DIGCTRL digctrl  #define BP_SAIF_CLKMUX		10  /* @@ -72,8 +74,8 @@ int mxs_saif_clkmux_select(unsigned int clkmux)  	if (clkmux > 0x3)  		return -EINVAL; -	__mxs_clrl(0x3 << BP_SAIF_CLKMUX, DIGCTRL); -	__mxs_setl(clkmux << BP_SAIF_CLKMUX, DIGCTRL); +	writel_relaxed(0x3 << BP_SAIF_CLKMUX, DIGCTRL + CLR); +	writel_relaxed(clkmux << BP_SAIF_CLKMUX, DIGCTRL + SET);  	return 0;  } @@ -83,13 +85,13 @@ static void __init clk_misc_init(void)  	u32 val;  	/* Gate off cpu clock in WFI for power saving */ -	__mxs_setl(1 << BP_CPU_INTERRUPT_WAIT, CPU); +	writel_relaxed(1 << BP_CPU_INTERRUPT_WAIT, CPU + SET);  	/* 0 is a bad default value for a divider */ -	__mxs_setl(1 << BP_ENET_DIV_TIME, ENET); +	writel_relaxed(1 << BP_ENET_DIV_TIME, ENET + SET);  	/* Clear BYPASS for SAIF */ -	__mxs_clrl(0x3 << BP_CLKSEQ_BYPASS_SAIF0, CLKSEQ); +	writel_relaxed(0x3 << BP_CLKSEQ_BYPASS_SAIF0, CLKSEQ + CLR);  	/* SAIF has to use frac div for functional operation */  	val = readl_relaxed(SAIF0); @@ -109,7 +111,7 @@ static void __init clk_misc_init(void)  	 * Source ssp clock from ref_io than ref_xtal,  	 * as ref_xtal only provides 24 MHz as maximum.  	 */ -	__mxs_clrl(0xf << BP_CLKSEQ_BYPASS_SSP0, CLKSEQ); +	writel_relaxed(0xf << BP_CLKSEQ_BYPASS_SSP0, CLKSEQ + CLR);  	/*  	 * 480 MHz seems too high to be ssp clock source directly, @@ -156,6 +158,14 @@ int __init mx28_clocks_init(void)  	struct device_node *np;  	u32 i; +	np = of_find_compatible_node(NULL, NULL, "fsl,imx28-digctl"); +	digctrl = of_iomap(np, 0); +	WARN_ON(!digctrl); + +	np = of_find_compatible_node(NULL, NULL, "fsl,imx28-clkctrl"); +	clkctrl = of_iomap(np, 0); +	WARN_ON(!clkctrl); +  	clk_misc_init();  	clks[ref_xtal] = mxs_clk_fixed("ref_xtal", 24000000); @@ -231,20 +241,14 @@ int __init mx28_clocks_init(void)  			return PTR_ERR(clks[i]);  		} -	np = of_find_compatible_node(NULL, NULL, "fsl,imx28-clkctrl"); -	if (np) { -		clk_data.clks = clks; -		clk_data.clk_num = ARRAY_SIZE(clks); -		of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); -	} +	clk_data.clks = clks; +	clk_data.clk_num = ARRAY_SIZE(clks); +	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); -	clk_register_clkdev(clks[xbus], NULL, "timrot");  	clk_register_clkdev(clks[enet_out], NULL, "enet_out");  	for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)  		clk_prepare_enable(clks[clks_init_on[i]]); -	mxs_timer_init(); -  	return 0;  } diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index e507ab7df60..9002185a0a1 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -25,7 +25,7 @@ config DW_APB_TIMER_OF  config ARMADA_370_XP_TIMER  	bool -config SUNXI_TIMER +config SUN4I_TIMER  	bool  config VT8500_TIMER diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 96e25319659..4897f243a00 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -16,7 +16,8 @@ obj-$(CONFIG_CLKSRC_NOMADIK_MTU)	+= nomadik-mtu.o  obj-$(CONFIG_CLKSRC_DBX500_PRCMU)	+= clksrc-dbx500-prcmu.o  obj-$(CONFIG_ARMADA_370_XP_TIMER)	+= time-armada-370-xp.o  obj-$(CONFIG_ARCH_BCM2835)	+= bcm2835_timer.o -obj-$(CONFIG_SUNXI_TIMER)	+= sunxi_timer.o +obj-$(CONFIG_ARCH_MXS)		+= mxs_timer.o +obj-$(CONFIG_SUN4I_TIMER)	+= sun4i_timer.o  obj-$(CONFIG_ARCH_TEGRA)	+= tegra20_timer.o  obj-$(CONFIG_VT8500_TIMER)	+= vt8500_timer.o  obj-$(CONFIG_ARCH_BCM)		+= bcm_kona_timer.o diff --git a/drivers/clocksource/bcm2835_timer.c b/drivers/clocksource/bcm2835_timer.c index 50c68fef944..766611d2994 100644 --- a/drivers/clocksource/bcm2835_timer.c +++ b/drivers/clocksource/bcm2835_timer.c @@ -95,23 +95,13 @@ static irqreturn_t bcm2835_time_interrupt(int irq, void *dev_id)  	}  } -static struct of_device_id bcm2835_time_match[] __initconst = { -	{ .compatible = "brcm,bcm2835-system-timer" }, -	{} -}; - -static void __init bcm2835_timer_init(void) +static void __init bcm2835_timer_init(struct device_node *node)  { -	struct device_node *node;  	void __iomem *base;  	u32 freq;  	int irq;  	struct bcm2835_timer *timer; -	node = of_find_matching_node(NULL, bcm2835_time_match); -	if (!node) -		panic("No bcm2835 timer node"); -  	base = of_iomap(node, 0);  	if (!base)  		panic("Can't remap registers"); diff --git a/drivers/clocksource/clksrc-of.c b/drivers/clocksource/clksrc-of.c index bdabdaa8d00..37f5325bec9 100644 --- a/drivers/clocksource/clksrc-of.c +++ b/drivers/clocksource/clksrc-of.c @@ -16,6 +16,7 @@  #include <linux/init.h>  #include <linux/of.h> +#include <linux/clocksource.h>  extern struct of_device_id __clksrc_of_table[]; @@ -26,10 +27,10 @@ void __init clocksource_of_init(void)  {  	struct device_node *np;  	const struct of_device_id *match; -	void (*init_func)(void); +	clocksource_of_init_fn init_func;  	for_each_matching_node_and_match(np, __clksrc_of_table, &match) {  		init_func = match->data; -		init_func(); +		init_func(np);  	}  } diff --git a/drivers/clocksource/mxs_timer.c b/drivers/clocksource/mxs_timer.c new file mode 100644 index 00000000000..02af4204af8 --- /dev/null +++ b/drivers/clocksource/mxs_timer.c @@ -0,0 +1,304 @@ +/* + *  Copyright (C) 2000-2001 Deep Blue Solutions + *  Copyright (C) 2002 Shane Nay (shane@minirl.com) + *  Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.com) + *  Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) + *  Copyright (C) 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 <linux/err.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/clockchips.h> +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/stmp_device.h> + +#include <asm/mach/time.h> +#include <asm/sched_clock.h> + +/* + * There are 2 versions of the timrot on Freescale MXS-based SoCs. + * The v1 on MX23 only gets 16 bits counter, while v2 on MX28 + * extends the counter to 32 bits. + * + * The implementation uses two timers, one for clock_event and + * another for clocksource. MX28 uses timrot 0 and 1, while MX23 + * uses 0 and 2. + */ + +#define MX23_TIMROT_VERSION_OFFSET	0x0a0 +#define MX28_TIMROT_VERSION_OFFSET	0x120 +#define BP_TIMROT_MAJOR_VERSION		24 +#define BV_TIMROT_VERSION_1		0x01 +#define BV_TIMROT_VERSION_2		0x02 +#define timrot_is_v1()	(timrot_major_version == BV_TIMROT_VERSION_1) + +/* + * There are 4 registers for each timrotv2 instance, and 2 registers + * for each timrotv1. So address step 0x40 in macros below strides + * one instance of timrotv2 while two instances of timrotv1. + * + * As the result, HW_TIMROT_XXXn(1) defines the address of timrot1 + * on MX28 while timrot2 on MX23. + */ +/* common between v1 and v2 */ +#define HW_TIMROT_ROTCTRL		0x00 +#define HW_TIMROT_TIMCTRLn(n)		(0x20 + (n) * 0x40) +/* v1 only */ +#define HW_TIMROT_TIMCOUNTn(n)		(0x30 + (n) * 0x40) +/* v2 only */ +#define HW_TIMROT_RUNNING_COUNTn(n)	(0x30 + (n) * 0x40) +#define HW_TIMROT_FIXED_COUNTn(n)	(0x40 + (n) * 0x40) + +#define BM_TIMROT_TIMCTRLn_RELOAD	(1 << 6) +#define BM_TIMROT_TIMCTRLn_UPDATE	(1 << 7) +#define BM_TIMROT_TIMCTRLn_IRQ_EN	(1 << 14) +#define BM_TIMROT_TIMCTRLn_IRQ		(1 << 15) +#define BP_TIMROT_TIMCTRLn_SELECT	0 +#define BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL		0x8 +#define BV_TIMROTv2_TIMCTRLn_SELECT__32KHZ_XTAL		0xb +#define BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS	0xf + +static struct clock_event_device mxs_clockevent_device; +static enum clock_event_mode mxs_clockevent_mode = CLOCK_EVT_MODE_UNUSED; + +static void __iomem *mxs_timrot_base; +static u32 timrot_major_version; + +static inline void timrot_irq_disable(void) +{ +	__raw_writel(BM_TIMROT_TIMCTRLn_IRQ_EN, mxs_timrot_base + +		     HW_TIMROT_TIMCTRLn(0) + STMP_OFFSET_REG_CLR); +} + +static inline void timrot_irq_enable(void) +{ +	__raw_writel(BM_TIMROT_TIMCTRLn_IRQ_EN, mxs_timrot_base + +		     HW_TIMROT_TIMCTRLn(0) + STMP_OFFSET_REG_SET); +} + +static void timrot_irq_acknowledge(void) +{ +	__raw_writel(BM_TIMROT_TIMCTRLn_IRQ, mxs_timrot_base + +		     HW_TIMROT_TIMCTRLn(0) + STMP_OFFSET_REG_CLR); +} + +static cycle_t timrotv1_get_cycles(struct clocksource *cs) +{ +	return ~((__raw_readl(mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1)) +			& 0xffff0000) >> 16); +} + +static int timrotv1_set_next_event(unsigned long evt, +					struct clock_event_device *dev) +{ +	/* timrot decrements the count */ +	__raw_writel(evt, mxs_timrot_base + HW_TIMROT_TIMCOUNTn(0)); + +	return 0; +} + +static int timrotv2_set_next_event(unsigned long evt, +					struct clock_event_device *dev) +{ +	/* timrot decrements the count */ +	__raw_writel(evt, mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(0)); + +	return 0; +} + +static irqreturn_t mxs_timer_interrupt(int irq, void *dev_id) +{ +	struct clock_event_device *evt = dev_id; + +	timrot_irq_acknowledge(); +	evt->event_handler(evt); + +	return IRQ_HANDLED; +} + +static struct irqaction mxs_timer_irq = { +	.name		= "MXS Timer Tick", +	.dev_id		= &mxs_clockevent_device, +	.flags		= IRQF_TIMER | IRQF_IRQPOLL, +	.handler	= mxs_timer_interrupt, +}; + +#ifdef DEBUG +static const char *clock_event_mode_label[] const = { +	[CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC", +	[CLOCK_EVT_MODE_ONESHOT]  = "CLOCK_EVT_MODE_ONESHOT", +	[CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN", +	[CLOCK_EVT_MODE_UNUSED]   = "CLOCK_EVT_MODE_UNUSED" +}; +#endif /* DEBUG */ + +static void mxs_set_mode(enum clock_event_mode mode, +				struct clock_event_device *evt) +{ +	/* Disable interrupt in timer module */ +	timrot_irq_disable(); + +	if (mode != mxs_clockevent_mode) { +		/* Set event time into the furthest future */ +		if (timrot_is_v1()) +			__raw_writel(0xffff, +				mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1)); +		else +			__raw_writel(0xffffffff, +				mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(1)); + +		/* Clear pending interrupt */ +		timrot_irq_acknowledge(); +	} + +#ifdef DEBUG +	pr_info("%s: changing mode from %s to %s\n", __func__, +		clock_event_mode_label[mxs_clockevent_mode], +		clock_event_mode_label[mode]); +#endif /* DEBUG */ + +	/* Remember timer mode */ +	mxs_clockevent_mode = mode; + +	switch (mode) { +	case CLOCK_EVT_MODE_PERIODIC: +		pr_err("%s: Periodic mode is not implemented\n", __func__); +		break; +	case CLOCK_EVT_MODE_ONESHOT: +		timrot_irq_enable(); +		break; +	case CLOCK_EVT_MODE_SHUTDOWN: +	case CLOCK_EVT_MODE_UNUSED: +	case CLOCK_EVT_MODE_RESUME: +		/* Left event sources disabled, no more interrupts appear */ +		break; +	} +} + +static struct clock_event_device mxs_clockevent_device = { +	.name		= "mxs_timrot", +	.features	= CLOCK_EVT_FEAT_ONESHOT, +	.set_mode	= mxs_set_mode, +	.set_next_event	= timrotv2_set_next_event, +	.rating		= 200, +}; + +static int __init mxs_clockevent_init(struct clk *timer_clk) +{ +	if (timrot_is_v1()) +		mxs_clockevent_device.set_next_event = timrotv1_set_next_event; +	mxs_clockevent_device.cpumask = cpumask_of(0); +	clockevents_config_and_register(&mxs_clockevent_device, +					clk_get_rate(timer_clk), +					timrot_is_v1() ? 0xf : 0x2, +					timrot_is_v1() ? 0xfffe : 0xfffffffe); + +	return 0; +} + +static struct clocksource clocksource_mxs = { +	.name		= "mxs_timer", +	.rating		= 200, +	.read		= timrotv1_get_cycles, +	.mask		= CLOCKSOURCE_MASK(16), +	.flags		= CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static u32 notrace mxs_read_sched_clock_v2(void) +{ +	return ~readl_relaxed(mxs_timrot_base + HW_TIMROT_RUNNING_COUNTn(1)); +} + +static int __init mxs_clocksource_init(struct clk *timer_clk) +{ +	unsigned int c = clk_get_rate(timer_clk); + +	if (timrot_is_v1()) +		clocksource_register_hz(&clocksource_mxs, c); +	else { +		clocksource_mmio_init(mxs_timrot_base + HW_TIMROT_RUNNING_COUNTn(1), +			"mxs_timer", c, 200, 32, clocksource_mmio_readl_down); +		setup_sched_clock(mxs_read_sched_clock_v2, 32, c); +	} + +	return 0; +} + +static void __init mxs_timer_init(struct device_node *np) +{ +	struct clk *timer_clk; +	int irq; + +	mxs_timrot_base = of_iomap(np, 0); +	WARN_ON(!mxs_timrot_base); + +	timer_clk = of_clk_get(np, 0); +	if (IS_ERR(timer_clk)) { +		pr_err("%s: failed to get clk\n", __func__); +		return; +	} + +	clk_prepare_enable(timer_clk); + +	/* +	 * Initialize timers to a known state +	 */ +	stmp_reset_block(mxs_timrot_base + HW_TIMROT_ROTCTRL); + +	/* get timrot version */ +	timrot_major_version = __raw_readl(mxs_timrot_base + +			(of_device_is_compatible(np, "fsl,imx23-timrot") ? +						MX23_TIMROT_VERSION_OFFSET : +						MX28_TIMROT_VERSION_OFFSET)); +	timrot_major_version >>= BP_TIMROT_MAJOR_VERSION; + +	/* one for clock_event */ +	__raw_writel((timrot_is_v1() ? +			BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL : +			BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS) | +			BM_TIMROT_TIMCTRLn_UPDATE | +			BM_TIMROT_TIMCTRLn_IRQ_EN, +			mxs_timrot_base + HW_TIMROT_TIMCTRLn(0)); + +	/* another for clocksource */ +	__raw_writel((timrot_is_v1() ? +			BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL : +			BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS) | +			BM_TIMROT_TIMCTRLn_RELOAD, +			mxs_timrot_base + HW_TIMROT_TIMCTRLn(1)); + +	/* set clocksource timer fixed count to the maximum */ +	if (timrot_is_v1()) +		__raw_writel(0xffff, +			mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1)); +	else +		__raw_writel(0xffffffff, +			mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(1)); + +	/* init and register the timer to the framework */ +	mxs_clocksource_init(timer_clk); +	mxs_clockevent_init(timer_clk); + +	/* Make irqs happen */ +	irq = irq_of_parse_and_map(np, 0); +	setup_irq(irq, &mxs_timer_irq); +} +CLOCKSOURCE_OF_DECLARE(mxs, "fsl,timrot", mxs_timer_init); diff --git a/drivers/clocksource/sunxi_timer.c b/drivers/clocksource/sun4i_timer.c index 0ce85e29769..d4674e78ef3 100644 --- a/drivers/clocksource/sunxi_timer.c +++ b/drivers/clocksource/sun4i_timer.c @@ -22,66 +22,64 @@  #include <linux/of.h>  #include <linux/of_address.h>  #include <linux/of_irq.h> -#include <linux/sunxi_timer.h> -#include <linux/clk/sunxi.h> -#define TIMER_CTL_REG		0x00 -#define TIMER_CTL_ENABLE		(1 << 0) +#define TIMER_IRQ_EN_REG	0x00 +#define TIMER_IRQ_EN(val)		(1 << val)  #define TIMER_IRQ_ST_REG	0x04 -#define TIMER0_CTL_REG		0x10 -#define TIMER0_CTL_ENABLE		(1 << 0) -#define TIMER0_CTL_AUTORELOAD		(1 << 1) -#define TIMER0_CTL_ONESHOT		(1 << 7) -#define TIMER0_INTVAL_REG	0x14 -#define TIMER0_CNTVAL_REG	0x18 +#define TIMER_CTL_REG(val)	(0x10 * val + 0x10) +#define TIMER_CTL_ENABLE		(1 << 0) +#define TIMER_CTL_AUTORELOAD		(1 << 1) +#define TIMER_CTL_ONESHOT		(1 << 7) +#define TIMER_INTVAL_REG(val)	(0x10 * val + 0x14) +#define TIMER_CNTVAL_REG(val)	(0x10 * val + 0x18)  #define TIMER_SCAL		16  static void __iomem *timer_base; -static void sunxi_clkevt_mode(enum clock_event_mode mode, +static void sun4i_clkevt_mode(enum clock_event_mode mode,  			      struct clock_event_device *clk)  { -	u32 u = readl(timer_base + TIMER0_CTL_REG); +	u32 u = readl(timer_base + TIMER_CTL_REG(0));  	switch (mode) {  	case CLOCK_EVT_MODE_PERIODIC: -		u &= ~(TIMER0_CTL_ONESHOT); -		writel(u | TIMER0_CTL_ENABLE, timer_base + TIMER0_CTL_REG); +		u &= ~(TIMER_CTL_ONESHOT); +		writel(u | TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(0));  		break;  	case CLOCK_EVT_MODE_ONESHOT: -		writel(u | TIMER0_CTL_ONESHOT, timer_base + TIMER0_CTL_REG); +		writel(u | TIMER_CTL_ONESHOT, timer_base + TIMER_CTL_REG(0));  		break;  	case CLOCK_EVT_MODE_UNUSED:  	case CLOCK_EVT_MODE_SHUTDOWN:  	default: -		writel(u & ~(TIMER0_CTL_ENABLE), timer_base + TIMER0_CTL_REG); +		writel(u & ~(TIMER_CTL_ENABLE), timer_base + TIMER_CTL_REG(0));  		break;  	}  } -static int sunxi_clkevt_next_event(unsigned long evt, +static int sun4i_clkevt_next_event(unsigned long evt,  				   struct clock_event_device *unused)  { -	u32 u = readl(timer_base + TIMER0_CTL_REG); -	writel(evt, timer_base + TIMER0_CNTVAL_REG); -	writel(u | TIMER0_CTL_ENABLE | TIMER0_CTL_AUTORELOAD, -	       timer_base + TIMER0_CTL_REG); +	u32 u = readl(timer_base + TIMER_CTL_REG(0)); +	writel(evt, timer_base + TIMER_CNTVAL_REG(0)); +	writel(u | TIMER_CTL_ENABLE | TIMER_CTL_AUTORELOAD, +	       timer_base + TIMER_CTL_REG(0));  	return 0;  } -static struct clock_event_device sunxi_clockevent = { -	.name = "sunxi_tick", +static struct clock_event_device sun4i_clockevent = { +	.name = "sun4i_tick",  	.rating = 300,  	.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, -	.set_mode = sunxi_clkevt_mode, -	.set_next_event = sunxi_clkevt_next_event, +	.set_mode = sun4i_clkevt_mode, +	.set_next_event = sun4i_clkevt_next_event,  }; -static irqreturn_t sunxi_timer_interrupt(int irq, void *dev_id) +static irqreturn_t sun4i_timer_interrupt(int irq, void *dev_id)  {  	struct clock_event_device *evt = (struct clock_event_device *)dev_id; @@ -91,30 +89,20 @@ static irqreturn_t sunxi_timer_interrupt(int irq, void *dev_id)  	return IRQ_HANDLED;  } -static struct irqaction sunxi_timer_irq = { -	.name = "sunxi_timer0", +static struct irqaction sun4i_timer_irq = { +	.name = "sun4i_timer0",  	.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, -	.handler = sunxi_timer_interrupt, -	.dev_id = &sunxi_clockevent, -}; - -static struct of_device_id sunxi_timer_dt_ids[] = { -	{ .compatible = "allwinner,sunxi-timer" }, -	{ } +	.handler = sun4i_timer_interrupt, +	.dev_id = &sun4i_clockevent,  }; -void __init sunxi_timer_init(void) +static void __init sun4i_timer_init(struct device_node *node)  { -	struct device_node *node;  	unsigned long rate = 0;  	struct clk *clk;  	int ret, irq;  	u32 val; -	node = of_find_matching_node(NULL, sunxi_timer_dt_ids); -	if (!node) -		panic("No sunxi timer node"); -  	timer_base = of_iomap(node, 0);  	if (!timer_base)  		panic("Can't map registers"); @@ -123,8 +111,6 @@ void __init sunxi_timer_init(void)  	if (irq <= 0)  		panic("Can't parse IRQ"); -	sunxi_init_clocks(); -  	clk = of_clk_get(node, 0);  	if (IS_ERR(clk))  		panic("Can't get timer clock"); @@ -132,29 +118,31 @@ void __init sunxi_timer_init(void)  	rate = clk_get_rate(clk);  	writel(rate / (TIMER_SCAL * HZ), -	       timer_base + TIMER0_INTVAL_REG); +	       timer_base + TIMER_INTVAL_REG(0));  	/* set clock source to HOSC, 16 pre-division */ -	val = readl(timer_base + TIMER0_CTL_REG); +	val = readl(timer_base + TIMER_CTL_REG(0));  	val &= ~(0x07 << 4);  	val &= ~(0x03 << 2);  	val |= (4 << 4) | (1 << 2); -	writel(val, timer_base + TIMER0_CTL_REG); +	writel(val, timer_base + TIMER_CTL_REG(0));  	/* set mode to auto reload */ -	val = readl(timer_base + TIMER0_CTL_REG); -	writel(val | TIMER0_CTL_AUTORELOAD, timer_base + TIMER0_CTL_REG); +	val = readl(timer_base + TIMER_CTL_REG(0)); +	writel(val | TIMER_CTL_AUTORELOAD, timer_base + TIMER_CTL_REG(0)); -	ret = setup_irq(irq, &sunxi_timer_irq); +	ret = setup_irq(irq, &sun4i_timer_irq);  	if (ret)  		pr_warn("failed to setup irq %d\n", irq);  	/* Enable timer0 interrupt */ -	val = readl(timer_base + TIMER_CTL_REG); -	writel(val | TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG); +	val = readl(timer_base + TIMER_IRQ_EN_REG); +	writel(val | TIMER_IRQ_EN(0), timer_base + TIMER_IRQ_EN_REG); -	sunxi_clockevent.cpumask = cpumask_of(0); +	sun4i_clockevent.cpumask = cpumask_of(0); -	clockevents_config_and_register(&sunxi_clockevent, rate / TIMER_SCAL, +	clockevents_config_and_register(&sun4i_clockevent, rate / TIMER_SCAL,  					0x1, 0xff);  } +CLOCKSOURCE_OF_DECLARE(sun4i, "allwinner,sun4i-timer", +		       sun4i_timer_init); diff --git a/drivers/clocksource/tegra20_timer.c b/drivers/clocksource/tegra20_timer.c index 0bde03feb09..ae877b021b5 100644 --- a/drivers/clocksource/tegra20_timer.c +++ b/drivers/clocksource/tegra20_timer.c @@ -154,29 +154,12 @@ static struct irqaction tegra_timer_irq = {  	.dev_id		= &tegra_clockevent,  }; -static const struct of_device_id timer_match[] __initconst = { -	{ .compatible = "nvidia,tegra20-timer" }, -	{} -}; - -static const struct of_device_id rtc_match[] __initconst = { -	{ .compatible = "nvidia,tegra20-rtc" }, -	{} -}; - -static void __init tegra20_init_timer(void) +static void __init tegra20_init_timer(struct device_node *np)  { -	struct device_node *np;  	struct clk *clk;  	unsigned long rate;  	int ret; -	np = of_find_matching_node(NULL, timer_match); -	if (!np) { -		pr_err("Failed to find timer DT node\n"); -		BUG(); -	} -  	timer_reg_base = of_iomap(np, 0);  	if (!timer_reg_base) {  		pr_err("Can't map timer registers\n"); @@ -189,7 +172,7 @@ static void __init tegra20_init_timer(void)  		BUG();  	} -	clk = clk_get_sys("timer", NULL); +	clk = of_clk_get(np, 0);  	if (IS_ERR(clk)) {  		pr_warn("Unable to get timer clock. Assuming 12Mhz input clock.\n");  		rate = 12000000; @@ -200,30 +183,6 @@ static void __init tegra20_init_timer(void)  	of_node_put(np); -	np = of_find_matching_node(NULL, rtc_match); -	if (!np) { -		pr_err("Failed to find RTC DT node\n"); -		BUG(); -	} - -	rtc_base = of_iomap(np, 0); -	if (!rtc_base) { -		pr_err("Can't map RTC registers"); -		BUG(); -	} - -	/* -	 * rtc registers are used by read_persistent_clock, keep the rtc clock -	 * enabled -	 */ -	clk = clk_get_sys("rtc-tegra", NULL); -	if (IS_ERR(clk)) -		pr_warn("Unable to get rtc-tegra clock\n"); -	else -		clk_prepare_enable(clk); - -	of_node_put(np); -  	switch (rate) {  	case 12000000:  		timer_writel(0x000b, TIMERUS_USEC_CFG); @@ -259,12 +218,34 @@ static void __init tegra20_init_timer(void)  	tegra_clockevent.irq = tegra_timer_irq.irq;  	clockevents_config_and_register(&tegra_clockevent, 1000000,  					0x1, 0x1fffffff); -#ifdef CONFIG_HAVE_ARM_TWD -	twd_local_timer_of_register(); -#endif +} +CLOCKSOURCE_OF_DECLARE(tegra20_timer, "nvidia,tegra20-timer", tegra20_init_timer); + +static void __init tegra20_init_rtc(struct device_node *np) +{ +	struct clk *clk; + +	rtc_base = of_iomap(np, 0); +	if (!rtc_base) { +		pr_err("Can't map RTC registers"); +		BUG(); +	} + +	/* +	 * rtc registers are used by read_persistent_clock, keep the rtc clock +	 * enabled +	 */ +	clk = of_clk_get(np, 0); +	if (IS_ERR(clk)) +		pr_warn("Unable to get rtc-tegra clock\n"); +	else +		clk_prepare_enable(clk); + +	of_node_put(np); +  	register_persistent_clock(NULL, tegra_read_persistent_clock);  } -CLOCKSOURCE_OF_DECLARE(tegra20, "nvidia,tegra20-timer", tegra20_init_timer); +CLOCKSOURCE_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc);  #ifdef CONFIG_PM  static u32 usec_config; diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/vt8500_timer.c index 8efc86b5b5d..64f553f04fa 100644 --- a/drivers/clocksource/vt8500_timer.c +++ b/drivers/clocksource/vt8500_timer.c @@ -129,22 +129,10 @@ static struct irqaction irq = {  	.dev_id  = &clockevent,  }; -static struct of_device_id vt8500_timer_ids[] = { -	{ .compatible = "via,vt8500-timer" }, -	{ } -}; - -static void __init vt8500_timer_init(void) +static void __init vt8500_timer_init(struct device_node *np)  { -	struct device_node *np;  	int timer_irq; -	np = of_find_matching_node(NULL, vt8500_timer_ids); -	if (!np) { -		pr_err("%s: Timer description missing from Device Tree\n", -								__func__); -		return; -	}  	regbase = of_iomap(np, 0);  	if (!regbase) {  		pr_err("%s: Missing iobase description in Device Tree\n", @@ -177,4 +165,4 @@ static void __init vt8500_timer_init(void)  					4, 0xf0000000);  } -CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init) +CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init); diff --git a/drivers/gpio/gpio-msm-v1.c b/drivers/gpio/gpio-msm-v1.c index 52a4d4286eb..c798585a3fe 100644 --- a/drivers/gpio/gpio-msm-v1.c +++ b/drivers/gpio/gpio-msm-v1.c @@ -1,6 +1,6 @@  /*   * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.   *   * This software is licensed under the terms of the GNU General Public   * License version 2, as published by the Free Software Foundation, and @@ -19,9 +19,10 @@  #include <linux/io.h>  #include <linux/irq.h>  #include <linux/module.h> -#include <mach/cpu.h> +#include <linux/device.h> +#include <linux/platform_device.h> +  #include <mach/msm_gpiomux.h> -#include <mach/msm_iomap.h>  /* see 80-VA736-2 Rev C pp 695-751  ** @@ -34,10 +35,10 @@  ** macros.  */ -#define MSM_GPIO1_REG(off) (MSM_GPIO1_BASE + (off)) -#define MSM_GPIO2_REG(off) (MSM_GPIO2_BASE + 0x400 + (off)) -#define MSM_GPIO1_SHADOW_REG(off) (MSM_GPIO1_BASE + 0x800 + (off)) -#define MSM_GPIO2_SHADOW_REG(off) (MSM_GPIO2_BASE + 0xC00 + (off)) +#define MSM_GPIO1_REG(off) (off) +#define MSM_GPIO2_REG(off) (off) +#define MSM_GPIO1_SHADOW_REG(off) (off) +#define MSM_GPIO2_SHADOW_REG(off) (off)  /*   * MSM7X00 registers @@ -276,16 +277,14 @@  #define MSM_GPIO_BANK(soc, bank, first, last)				\  	{								\ -		.regs = {						\ -			.out =         soc##_GPIO_OUT_##bank,		\ -			.in =          soc##_GPIO_IN_##bank,		\ -			.int_status =  soc##_GPIO_INT_STATUS_##bank,	\ -			.int_clear =   soc##_GPIO_INT_CLEAR_##bank,	\ -			.int_en =      soc##_GPIO_INT_EN_##bank,	\ -			.int_edge =    soc##_GPIO_INT_EDGE_##bank,	\ -			.int_pos =     soc##_GPIO_INT_POS_##bank,	\ -			.oe =          soc##_GPIO_OE_##bank,		\ -		},							\ +		.regs[MSM_GPIO_OUT] =         soc##_GPIO_OUT_##bank,	\ +		.regs[MSM_GPIO_IN] =          soc##_GPIO_IN_##bank,	\ +		.regs[MSM_GPIO_INT_STATUS] =  soc##_GPIO_INT_STATUS_##bank, \ +		.regs[MSM_GPIO_INT_CLEAR] =   soc##_GPIO_INT_CLEAR_##bank, \ +		.regs[MSM_GPIO_INT_EN] =      soc##_GPIO_INT_EN_##bank,	\ +		.regs[MSM_GPIO_INT_EDGE] =    soc##_GPIO_INT_EDGE_##bank, \ +		.regs[MSM_GPIO_INT_POS] =     soc##_GPIO_INT_POS_##bank, \ +		.regs[MSM_GPIO_OE] =          soc##_GPIO_OE_##bank,	\  		.chip = {						\  			.base = (first),				\  			.ngpio = (last) - (first) + 1,			\ @@ -301,39 +300,57 @@  #define MSM_GPIO_BROKEN_INT_CLEAR 1 -struct msm_gpio_regs { -	void __iomem *out; -	void __iomem *in; -	void __iomem *int_status; -	void __iomem *int_clear; -	void __iomem *int_en; -	void __iomem *int_edge; -	void __iomem *int_pos; -	void __iomem *oe; +enum msm_gpio_reg { +	MSM_GPIO_IN, +	MSM_GPIO_OUT, +	MSM_GPIO_INT_STATUS, +	MSM_GPIO_INT_CLEAR, +	MSM_GPIO_INT_EN, +	MSM_GPIO_INT_EDGE, +	MSM_GPIO_INT_POS, +	MSM_GPIO_OE, +	MSM_GPIO_REG_NR  };  struct msm_gpio_chip {  	spinlock_t		lock;  	struct gpio_chip	chip; -	struct msm_gpio_regs	regs; +	unsigned long		regs[MSM_GPIO_REG_NR];  #if MSM_GPIO_BROKEN_INT_CLEAR  	unsigned                int_status_copy;  #endif  	unsigned int            both_edge_detect;  	unsigned int            int_enable[2]; /* 0: awake, 1: sleep */ +	void __iomem		*base; +}; + +struct msm_gpio_initdata { +	struct msm_gpio_chip *chips; +	int count;  }; +static void msm_gpio_writel(struct msm_gpio_chip *chip, u32 val, +			    enum msm_gpio_reg reg) +{ +	writel(val, chip->base + chip->regs[reg]); +} + +static u32 msm_gpio_readl(struct msm_gpio_chip *chip, enum msm_gpio_reg reg) +{ +	return readl(chip->base + chip->regs[reg]); +} +  static int msm_gpio_write(struct msm_gpio_chip *msm_chip,  			  unsigned offset, unsigned on)  {  	unsigned mask = BIT(offset);  	unsigned val; -	val = readl(msm_chip->regs.out); +	val = msm_gpio_readl(msm_chip, MSM_GPIO_OUT);  	if (on) -		writel(val | mask, msm_chip->regs.out); +		msm_gpio_writel(msm_chip, val | mask, MSM_GPIO_OUT);  	else -		writel(val & ~mask, msm_chip->regs.out); +		msm_gpio_writel(msm_chip, val & ~mask, MSM_GPIO_OUT);  	return 0;  } @@ -342,13 +359,13 @@ static void msm_gpio_update_both_edge_detect(struct msm_gpio_chip *msm_chip)  	int loop_limit = 100;  	unsigned pol, val, val2, intstat;  	do { -		val = readl(msm_chip->regs.in); -		pol = readl(msm_chip->regs.int_pos); +		val = msm_gpio_readl(msm_chip, MSM_GPIO_IN); +		pol = msm_gpio_readl(msm_chip, MSM_GPIO_INT_POS);  		pol = (pol & ~msm_chip->both_edge_detect) |  		      (~val & msm_chip->both_edge_detect); -		writel(pol, msm_chip->regs.int_pos); -		intstat = readl(msm_chip->regs.int_status); -		val2 = readl(msm_chip->regs.in); +		msm_gpio_writel(msm_chip, pol, MSM_GPIO_INT_POS); +		intstat = msm_gpio_readl(msm_chip, MSM_GPIO_INT_STATUS); +		val2 = msm_gpio_readl(msm_chip, MSM_GPIO_IN);  		if (((val ^ val2) & msm_chip->both_edge_detect & ~intstat) == 0)  			return;  	} while (loop_limit-- > 0); @@ -365,10 +382,11 @@ static int msm_gpio_clear_detect_status(struct msm_gpio_chip *msm_chip,  	/* Save interrupts that already triggered before we loose them. */  	/* Any interrupt that triggers between the read of int_status */  	/* and the write to int_clear will still be lost though. */ -	msm_chip->int_status_copy |= readl(msm_chip->regs.int_status); +	msm_chip->int_status_copy |= +		msm_gpio_readl(msm_chip, MSM_GPIO_INT_STATUS);  	msm_chip->int_status_copy &= ~bit;  #endif -	writel(bit, msm_chip->regs.int_clear); +	msm_gpio_writel(msm_chip, bit, MSM_GPIO_INT_CLEAR);  	msm_gpio_update_both_edge_detect(msm_chip);  	return 0;  } @@ -377,10 +395,12 @@ static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)  {  	struct msm_gpio_chip *msm_chip;  	unsigned long irq_flags; +	u32 val;  	msm_chip = container_of(chip, struct msm_gpio_chip, chip);  	spin_lock_irqsave(&msm_chip->lock, irq_flags); -	writel(readl(msm_chip->regs.oe) & ~BIT(offset), msm_chip->regs.oe); +	val = msm_gpio_readl(msm_chip, MSM_GPIO_OE) & ~BIT(offset); +	msm_gpio_writel(msm_chip, val, MSM_GPIO_OE);  	spin_unlock_irqrestore(&msm_chip->lock, irq_flags);  	return 0;  } @@ -390,11 +410,13 @@ msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)  {  	struct msm_gpio_chip *msm_chip;  	unsigned long irq_flags; +	u32 val;  	msm_chip = container_of(chip, struct msm_gpio_chip, chip);  	spin_lock_irqsave(&msm_chip->lock, irq_flags);  	msm_gpio_write(msm_chip, offset, value); -	writel(readl(msm_chip->regs.oe) | BIT(offset), msm_chip->regs.oe); +	val = msm_gpio_readl(msm_chip, MSM_GPIO_OE) | BIT(offset); +	msm_gpio_writel(msm_chip, val, MSM_GPIO_OE);  	spin_unlock_irqrestore(&msm_chip->lock, irq_flags);  	return 0;  } @@ -404,7 +426,7 @@ static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)  	struct msm_gpio_chip *msm_chip;  	msm_chip = container_of(chip, struct msm_gpio_chip, chip); -	return (readl(msm_chip->regs.in) & (1U << offset)) ? 1 : 0; +	return (msm_gpio_readl(msm_chip, MSM_GPIO_IN) & (1U << offset)) ? 1 : 0;  }  static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value) @@ -450,6 +472,11 @@ static struct msm_gpio_chip msm_gpio_chips_msm7x01[] = {  	MSM_GPIO_BANK(MSM7X00, 5, 107, 121),  }; +static struct msm_gpio_initdata msm_gpio_7x01_init = { +	.chips = msm_gpio_chips_msm7x01, +	.count = ARRAY_SIZE(msm_gpio_chips_msm7x01), +}; +  static struct msm_gpio_chip msm_gpio_chips_msm7x30[] = {  	MSM_GPIO_BANK(MSM7X30, 0,   0,  15),  	MSM_GPIO_BANK(MSM7X30, 1,  16,  43), @@ -461,6 +488,11 @@ static struct msm_gpio_chip msm_gpio_chips_msm7x30[] = {  	MSM_GPIO_BANK(MSM7X30, 7, 151, 181),  }; +static struct msm_gpio_initdata msm_gpio_7x30_init = { +	.chips = msm_gpio_chips_msm7x30, +	.count = ARRAY_SIZE(msm_gpio_chips_msm7x30), +}; +  static struct msm_gpio_chip msm_gpio_chips_qsd8x50[] = {  	MSM_GPIO_BANK(QSD8X50, 0,   0,  15),  	MSM_GPIO_BANK(QSD8X50, 1,  16,  42), @@ -472,6 +504,11 @@ static struct msm_gpio_chip msm_gpio_chips_qsd8x50[] = {  	MSM_GPIO_BANK(QSD8X50, 7, 153, 164),  }; +static struct msm_gpio_initdata msm_gpio_8x50_init = { +	.chips = msm_gpio_chips_qsd8x50, +	.count = ARRAY_SIZE(msm_gpio_chips_qsd8x50), +}; +  static void msm_gpio_irq_ack(struct irq_data *d)  {  	unsigned long irq_flags; @@ -490,10 +527,10 @@ static void msm_gpio_irq_mask(struct irq_data *d)  	spin_lock_irqsave(&msm_chip->lock, irq_flags);  	/* level triggered interrupts are also latched */ -	if (!(readl(msm_chip->regs.int_edge) & BIT(offset))) +	if (!(msm_gpio_readl(msm_chip, MSM_GPIO_INT_EDGE) & BIT(offset)))  		msm_gpio_clear_detect_status(msm_chip, offset);  	msm_chip->int_enable[0] &= ~BIT(offset); -	writel(msm_chip->int_enable[0], msm_chip->regs.int_en); +	msm_gpio_writel(msm_chip, msm_chip->int_enable[0], MSM_GPIO_INT_EN);  	spin_unlock_irqrestore(&msm_chip->lock, irq_flags);  } @@ -505,10 +542,10 @@ static void msm_gpio_irq_unmask(struct irq_data *d)  	spin_lock_irqsave(&msm_chip->lock, irq_flags);  	/* level triggered interrupts are also latched */ -	if (!(readl(msm_chip->regs.int_edge) & BIT(offset))) +	if (!(msm_gpio_readl(msm_chip, MSM_GPIO_INT_EDGE) & BIT(offset)))  		msm_gpio_clear_detect_status(msm_chip, offset);  	msm_chip->int_enable[0] |= BIT(offset); -	writel(msm_chip->int_enable[0], msm_chip->regs.int_en); +	msm_gpio_writel(msm_chip, msm_chip->int_enable[0], MSM_GPIO_INT_EN);  	spin_unlock_irqrestore(&msm_chip->lock, irq_flags);  } @@ -537,12 +574,12 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)  	unsigned val, mask = BIT(offset);  	spin_lock_irqsave(&msm_chip->lock, irq_flags); -	val = readl(msm_chip->regs.int_edge); +	val = msm_gpio_readl(msm_chip, MSM_GPIO_INT_EDGE);  	if (flow_type & IRQ_TYPE_EDGE_BOTH) { -		writel(val | mask, msm_chip->regs.int_edge); +		msm_gpio_writel(msm_chip, val | mask, MSM_GPIO_INT_EDGE);  		__irq_set_handler_locked(d->irq, handle_edge_irq);  	} else { -		writel(val & ~mask, msm_chip->regs.int_edge); +		msm_gpio_writel(msm_chip, val & ~mask, MSM_GPIO_INT_EDGE);  		__irq_set_handler_locked(d->irq, handle_level_irq);  	}  	if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) { @@ -550,11 +587,12 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)  		msm_gpio_update_both_edge_detect(msm_chip);  	} else {  		msm_chip->both_edge_detect &= ~mask; -		val = readl(msm_chip->regs.int_pos); +		val = msm_gpio_readl(msm_chip, MSM_GPIO_INT_POS);  		if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH)) -			writel(val | mask, msm_chip->regs.int_pos); +			val |= mask;  		else -			writel(val & ~mask, msm_chip->regs.int_pos); +			val &= ~mask; +		msm_gpio_writel(msm_chip, val, MSM_GPIO_INT_POS);  	}  	spin_unlock_irqrestore(&msm_chip->lock, irq_flags);  	return 0; @@ -567,7 +605,7 @@ static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)  	for (i = 0; i < msm_gpio_count; i++) {  		struct msm_gpio_chip *msm_chip = &msm_gpio_chips[i]; -		val = readl(msm_chip->regs.int_status); +		val = msm_gpio_readl(msm_chip, MSM_GPIO_INT_STATUS);  		val &= msm_chip->int_enable[0];  		while (val) {  			mask = val & -val; @@ -592,22 +630,36 @@ static struct irq_chip msm_gpio_irq_chip = {  	.irq_set_type  = msm_gpio_irq_set_type,  }; -static int __init msm_init_gpio(void) +static int __devinit gpio_msm_v1_probe(struct platform_device *pdev)  {  	int i, j = 0; +	const struct platform_device_id *dev_id = platform_get_device_id(pdev); +	struct msm_gpio_initdata *data; +	int irq1, irq2; +	struct resource *res; +	void __iomem *base1, __iomem *base2; -	if (cpu_is_msm7x01()) { -		msm_gpio_chips = msm_gpio_chips_msm7x01; -		msm_gpio_count = ARRAY_SIZE(msm_gpio_chips_msm7x01); -	} else if (cpu_is_msm7x30()) { -		msm_gpio_chips = msm_gpio_chips_msm7x30; -		msm_gpio_count = ARRAY_SIZE(msm_gpio_chips_msm7x30); -	} else if (cpu_is_qsd8x50()) { -		msm_gpio_chips = msm_gpio_chips_qsd8x50; -		msm_gpio_count = ARRAY_SIZE(msm_gpio_chips_qsd8x50); -	} else { -		return 0; -	} +	data = (struct msm_gpio_initdata *)dev_id->driver_data; +	msm_gpio_chips = data->chips; +	msm_gpio_count = data->count; + +	irq1 = platform_get_irq(pdev, 0); +	if (irq1 < 0) +		return irq1; + +	irq2 = platform_get_irq(pdev, 1); +	if (irq2 < 0) +		return irq2; + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	base1 = devm_request_and_ioremap(&pdev->dev, res); +	if (!base1) +		return -EADDRNOTAVAIL; + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 1); +	base2 = devm_request_and_ioremap(&pdev->dev, res); +	if (!base2) +		return -EADDRNOTAVAIL;  	for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {  		if (i - FIRST_GPIO_IRQ >= @@ -621,16 +673,42 @@ static int __init msm_init_gpio(void)  	}  	for (i = 0; i < msm_gpio_count; i++) { +		if (i == 1) +			msm_gpio_chips[i].base = base2; +		else +			msm_gpio_chips[i].base = base1;  		spin_lock_init(&msm_gpio_chips[i].lock); -		writel(0, msm_gpio_chips[i].regs.int_en); +		msm_gpio_writel(&msm_gpio_chips[i], 0, MSM_GPIO_INT_EN);  		gpiochip_add(&msm_gpio_chips[i].chip);  	} -	irq_set_chained_handler(INT_GPIO_GROUP1, msm_gpio_irq_handler); -	irq_set_chained_handler(INT_GPIO_GROUP2, msm_gpio_irq_handler); -	irq_set_irq_wake(INT_GPIO_GROUP1, 1); -	irq_set_irq_wake(INT_GPIO_GROUP2, 2); +	irq_set_chained_handler(irq1, msm_gpio_irq_handler); +	irq_set_chained_handler(irq2, msm_gpio_irq_handler); +	irq_set_irq_wake(irq1, 1); +	irq_set_irq_wake(irq2, 2);  	return 0;  } -postcore_initcall(msm_init_gpio); +static struct platform_device_id gpio_msm_v1_device_ids[] = { +	{ "gpio-msm-7201", (unsigned long)&msm_gpio_7x01_init }, +	{ "gpio-msm-7x30", (unsigned long)&msm_gpio_7x30_init }, +	{ "gpio-msm-8x50", (unsigned long)&msm_gpio_8x50_init }, +	{ } +}; +MODULE_DEVICE_TABLE(platform, gpio_msm_v1_device_ids); + +static struct platform_driver gpio_msm_v1_driver = { +	.driver = { +		.name = "gpio-msm-v1", +		.owner = THIS_MODULE, +	}, +	.probe = gpio_msm_v1_probe, +	.id_table = gpio_msm_v1_device_ids, +}; + +static int __init gpio_msm_v1_init(void) +{ +	return platform_driver_register(&gpio_msm_v1_driver); +} +postcore_initcall(gpio_msm_v1_init); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c index 55a7e7769af..dd2eddeb1e0 100644 --- a/drivers/gpio/gpio-msm-v2.c +++ b/drivers/gpio/gpio-msm-v2.c @@ -23,13 +23,12 @@  #include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/io.h> +#include <linux/irqchip/chained_irq.h>  #include <linux/irq.h>  #include <linux/module.h>  #include <linux/platform_device.h>  #include <linux/spinlock.h> -#include <asm/mach/irq.h> -  #include <mach/msm_gpiomux.h>  #include <mach/msm_iomap.h> diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index 7877335c4cc..7176743915d 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -24,6 +24,7 @@  #include <linux/io.h>  #include <linux/irq.h>  #include <linux/irqdomain.h> +#include <linux/irqchip/chained_irq.h>  #include <linux/gpio.h>  #include <linux/platform_device.h>  #include <linux/slab.h> @@ -32,7 +33,6 @@  #include <linux/of_device.h>  #include <linux/module.h>  #include <asm-generic/bug.h> -#include <asm/mach/irq.h>  enum mxc_gpio_hwtype {  	IMX1_GPIO,	/* runs on i.mx1 */ diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 159f5c57eb4..a612ea1c53c 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -25,11 +25,10 @@  #include <linux/of.h>  #include <linux/of_device.h>  #include <linux/irqdomain.h> +#include <linux/irqchip/chained_irq.h>  #include <linux/gpio.h>  #include <linux/platform_data/gpio-omap.h> -#include <asm/mach/irq.h> -  #define OFF_MODE	1  static LIST_HEAD(omap_gpio_list); diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index d7008dfdd6f..6a4bd0dae0c 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -16,6 +16,7 @@  #include <linux/ioport.h>  #include <linux/irq.h>  #include <linux/irqdomain.h> +#include <linux/irqchip/chained_irq.h>  #include <linux/bitops.h>  #include <linux/workqueue.h>  #include <linux/gpio.h> @@ -25,7 +26,6 @@  #include <linux/slab.h>  #include <linux/pinctrl/consumer.h>  #include <linux/pm.h> -#include <asm/mach/irq.h>  #define GPIODIR 0x400  #define GPIOIS  0x404 diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 8325f580c0f..2d3af981641 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -19,6 +19,7 @@  #include <linux/init.h>  #include <linux/irq.h>  #include <linux/irqdomain.h> +#include <linux/irqchip/chained_irq.h>  #include <linux/io.h>  #include <linux/of.h>  #include <linux/of_device.h> @@ -26,8 +27,6 @@  #include <linux/syscore_ops.h>  #include <linux/slab.h> -#include <asm/mach/irq.h> -  #include <mach/irqs.h>  /* diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 414ad912232..8e215554888 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -27,11 +27,10 @@  #include <linux/platform_device.h>  #include <linux/module.h>  #include <linux/irqdomain.h> +#include <linux/irqchip/chained_irq.h>  #include <linux/pinctrl/consumer.h>  #include <linux/pm.h> -#include <asm/mach/irq.h> -  #define GPIO_BANK(x)		((x) >> 5)  #define GPIO_PORT(x)		(((x) >> 3) & 0x3)  #define GPIO_BIT(x)		((x) & 0x7) diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 98e3b87bdf1..d5e119ca942 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -2,9 +2,10 @@ obj-$(CONFIG_IRQCHIP)			+= irqchip.o  obj-$(CONFIG_ARCH_BCM2835)		+= irq-bcm2835.o  obj-$(CONFIG_ARCH_EXYNOS)		+= exynos-combiner.o +obj-$(CONFIG_ARCH_MXS)			+= irq-mxs.o  obj-$(CONFIG_METAG)			+= irq-metag-ext.o  obj-$(CONFIG_METAG_PERFCOUNTER_IRQS)	+= irq-metag.o -obj-$(CONFIG_ARCH_SUNXI)		+= irq-sunxi.o +obj-$(CONFIG_ARCH_SUNXI)		+= irq-sun4i.o  obj-$(CONFIG_ARCH_SPEAR3XX)		+= spear-shirq.o  obj-$(CONFIG_ARM_GIC)			+= irq-gic.o  obj-$(CONFIG_ARM_VIC)			+= irq-vic.o diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c index 04d86a9803f..6a520135150 100644 --- a/drivers/irqchip/exynos-combiner.c +++ b/drivers/irqchip/exynos-combiner.c @@ -13,6 +13,7 @@  #include <linux/init.h>  #include <linux/io.h>  #include <linux/irqdomain.h> +#include <linux/irqchip/chained_irq.h>  #include <linux/of_address.h>  #include <linux/of_irq.h>  #include <asm/mach/irq.h> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index fc6aebf1e4b..1760ceb68b7 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -28,6 +28,7 @@  #include <linux/module.h>  #include <linux/list.h>  #include <linux/smp.h> +#include <linux/cpu.h>  #include <linux/cpu_pm.h>  #include <linux/cpumask.h>  #include <linux/io.h> @@ -38,12 +39,12 @@  #include <linux/interrupt.h>  #include <linux/percpu.h>  #include <linux/slab.h> +#include <linux/irqchip/chained_irq.h>  #include <linux/irqchip/arm-gic.h>  #include <asm/irq.h>  #include <asm/exception.h>  #include <asm/smp_plat.h> -#include <asm/mach/irq.h>  #include "irqchip.h" @@ -127,7 +128,7 @@ static inline void gic_set_base_accessor(struct gic_chip_data *data,  #else  #define gic_data_dist_base(d)	((d)->dist_base.common_base)  #define gic_data_cpu_base(d)	((d)->cpu_base.common_base) -#define gic_set_base_accessor(d,f) +#define gic_set_base_accessor(d, f)  #endif  static inline void __iomem *gic_dist_base(struct irq_data *d) @@ -324,7 +325,7 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)  	cascade_irq = irq_find_mapping(chip_data->domain, gic_irq);  	if (unlikely(gic_irq < 32 || gic_irq > 1020)) -		do_bad_IRQ(cascade_irq, desc); +		handle_bad_irq(cascade_irq, desc);  	else  		generic_handle_irq(cascade_irq); @@ -700,6 +701,25 @@ static int gic_irq_domain_xlate(struct irq_domain *d,  	return 0;  } +#ifdef CONFIG_SMP +static int __cpuinit gic_secondary_init(struct notifier_block *nfb, +					unsigned long action, void *hcpu) +{ +	if (action == CPU_STARTING) +		gic_cpu_init(&gic_data[0]); +	return NOTIFY_OK; +} + +/* + * Notifier for enabling the GIC CPU interface. Set an arbitrarily high + * priority because the GIC needs to be up before the ARM generic timers. + */ +static struct notifier_block __cpuinitdata gic_cpu_notifier = { +	.notifier_call = gic_secondary_init, +	.priority = 100, +}; +#endif +  const struct irq_domain_ops gic_irq_domain_ops = {  	.map = gic_irq_domain_map,  	.xlate = gic_irq_domain_xlate, @@ -790,6 +810,7 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,  #ifdef CONFIG_SMP  	set_smp_cross_call(gic_raise_softirq); +	register_cpu_notifier(&gic_cpu_notifier);  #endif  	set_handle_irq(gic_handle_irq); @@ -800,15 +821,8 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,  	gic_pm_init(gic);  } -void __cpuinit gic_secondary_init(unsigned int gic_nr) -{ -	BUG_ON(gic_nr >= MAX_GIC_NR); - -	gic_cpu_init(&gic_data[gic_nr]); -} -  #ifdef CONFIG_OF -static int gic_cnt __initdata = 0; +static int gic_cnt __initdata;  int __init gic_of_init(struct device_node *node, struct device_node *parent)  { diff --git a/drivers/irqchip/irq-mxs.c b/drivers/irqchip/irq-mxs.c new file mode 100644 index 00000000000..29889bbdcc6 --- /dev/null +++ b/drivers/irqchip/irq-mxs.c @@ -0,0 +1,121 @@ +/* + * 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 <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_address.h> +#include <linux/of_irq.h> +#include <linux/stmp_device.h> +#include <asm/exception.h> + +#include "irqchip.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; +static struct irq_domain *icoll_domain; + +static void icoll_ack_irq(struct irq_data *d) +{ +	/* +	 * The Interrupt Collector is able to prioritize irqs. +	 * Currently only level 0 is used. So acking can use +	 * BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0 unconditionally. +	 */ +	__raw_writel(BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0, +			icoll_base + HW_ICOLL_LEVELACK); +} + +static void icoll_mask_irq(struct irq_data *d) +{ +	__raw_writel(BM_ICOLL_INTERRUPTn_ENABLE, +			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->hwirq)); +} + +static struct irq_chip mxs_icoll_chip = { +	.irq_ack = icoll_ack_irq, +	.irq_mask = icoll_mask_irq, +	.irq_unmask = icoll_unmask_irq, +}; + +asmlinkage void __exception_irq_entry icoll_handle_irq(struct pt_regs *regs) +{ +	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, +}; + +static void __init icoll_of_init(struct device_node *np, +			  struct device_node *interrupt_parent) +{ +	icoll_base = of_iomap(np, 0); +	WARN_ON(!icoll_base); + +	/* +	 * Interrupt Collector reset, which initializes the priority +	 * for each irq to level 0. +	 */ +	stmp_reset_block(icoll_base + HW_ICOLL_CTRL); + +	icoll_domain = irq_domain_add_linear(np, ICOLL_NUM_IRQS, +					     &icoll_irq_domain_ops, NULL); +	WARN_ON(!icoll_domain); +} +IRQCHIP_DECLARE(mxs, "fsl,icoll", icoll_of_init); diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c new file mode 100644 index 00000000000..b66d4ae0689 --- /dev/null +++ b/drivers/irqchip/irq-sun4i.c @@ -0,0 +1,149 @@ +/* + * Allwinner A1X SoCs IRQ chip driver. + * + * Copyright (C) 2012 Maxime Ripard + * + * Maxime Ripard <maxime.ripard@free-electrons.com> + * + * Based on code from + * Allwinner Technology Co., Ltd. <www.allwinnertech.com> + * Benn Huang <benn@allwinnertech.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2.  This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> + +#include <asm/exception.h> +#include <asm/mach/irq.h> + +#include "irqchip.h" + +#define SUN4I_IRQ_VECTOR_REG		0x00 +#define SUN4I_IRQ_PROTECTION_REG	0x08 +#define SUN4I_IRQ_NMI_CTRL_REG		0x0c +#define SUN4I_IRQ_PENDING_REG(x)	(0x10 + 0x4 * x) +#define SUN4I_IRQ_FIQ_PENDING_REG(x)	(0x20 + 0x4 * x) +#define SUN4I_IRQ_ENABLE_REG(x)		(0x40 + 0x4 * x) +#define SUN4I_IRQ_MASK_REG(x)		(0x50 + 0x4 * x) + +static void __iomem *sun4i_irq_base; +static struct irq_domain *sun4i_irq_domain; + +static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs); + +void sun4i_irq_ack(struct irq_data *irqd) +{ +	unsigned int irq = irqd_to_hwirq(irqd); +	unsigned int irq_off = irq % 32; +	int reg = irq / 32; +	u32 val; + +	val = readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg)); +	writel(val | (1 << irq_off), +	       sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg)); +} + +static void sun4i_irq_mask(struct irq_data *irqd) +{ +	unsigned int irq = irqd_to_hwirq(irqd); +	unsigned int irq_off = irq % 32; +	int reg = irq / 32; +	u32 val; + +	val = readl(sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(reg)); +	writel(val & ~(1 << irq_off), +	       sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(reg)); +} + +static void sun4i_irq_unmask(struct irq_data *irqd) +{ +	unsigned int irq = irqd_to_hwirq(irqd); +	unsigned int irq_off = irq % 32; +	int reg = irq / 32; +	u32 val; + +	val = readl(sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(reg)); +	writel(val | (1 << irq_off), +	       sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(reg)); +} + +static struct irq_chip sun4i_irq_chip = { +	.name		= "sun4i_irq", +	.irq_ack	= sun4i_irq_ack, +	.irq_mask	= sun4i_irq_mask, +	.irq_unmask	= sun4i_irq_unmask, +}; + +static int sun4i_irq_map(struct irq_domain *d, unsigned int virq, +			 irq_hw_number_t hw) +{ +	irq_set_chip_and_handler(virq, &sun4i_irq_chip, +				 handle_level_irq); +	set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); + +	return 0; +} + +static struct irq_domain_ops sun4i_irq_ops = { +	.map = sun4i_irq_map, +	.xlate = irq_domain_xlate_onecell, +}; + +static int __init sun4i_of_init(struct device_node *node, +				struct device_node *parent) +{ +	sun4i_irq_base = of_iomap(node, 0); +	if (!sun4i_irq_base) +		panic("%s: unable to map IC registers\n", +			node->full_name); + +	/* Disable all interrupts */ +	writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(0)); +	writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(1)); +	writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(2)); + +	/* Mask all the interrupts */ +	writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(0)); +	writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(1)); +	writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(2)); + +	/* Clear all the pending interrupts */ +	writel(0xffffffff, sun4i_irq_base + SUN4I_IRQ_PENDING_REG(0)); +	writel(0xffffffff, sun4i_irq_base + SUN4I_IRQ_PENDING_REG(1)); +	writel(0xffffffff, sun4i_irq_base + SUN4I_IRQ_PENDING_REG(2)); + +	/* Enable protection mode */ +	writel(0x01, sun4i_irq_base + SUN4I_IRQ_PROTECTION_REG); + +	/* Configure the external interrupt source type */ +	writel(0x00, sun4i_irq_base + SUN4I_IRQ_NMI_CTRL_REG); + +	sun4i_irq_domain = irq_domain_add_linear(node, 3 * 32, +						 &sun4i_irq_ops, NULL); +	if (!sun4i_irq_domain) +		panic("%s: unable to create IRQ domain\n", node->full_name); + +	set_handle_irq(sun4i_handle_irq); + +	return 0; +} +IRQCHIP_DECLARE(allwinner_sun4i_ic, "allwinner,sun4i-ic", sun4i_of_init); + +static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs) +{ +	u32 irq, hwirq; + +	hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2; +	while (hwirq != 0) { +		irq = irq_find_mapping(sun4i_irq_domain, hwirq); +		handle_IRQ(irq, regs); +		hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2; +	} +} diff --git a/drivers/irqchip/irq-sunxi.c b/drivers/irqchip/irq-sunxi.c deleted file mode 100644 index 10974fa4265..00000000000 --- a/drivers/irqchip/irq-sunxi.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Allwinner A1X SoCs IRQ chip driver. - * - * Copyright (C) 2012 Maxime Ripard - * - * Maxime Ripard <maxime.ripard@free-electrons.com> - * - * Based on code from - * Allwinner Technology Co., Ltd. <www.allwinnertech.com> - * Benn Huang <benn@allwinnertech.com> - * - * This file is licensed under the terms of the GNU General Public - * License version 2.  This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include <linux/io.h> -#include <linux/irq.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> - -#include <linux/irqchip/sunxi.h> - -#define SUNXI_IRQ_VECTOR_REG		0x00 -#define SUNXI_IRQ_PROTECTION_REG	0x08 -#define SUNXI_IRQ_NMI_CTRL_REG		0x0c -#define SUNXI_IRQ_PENDING_REG(x)	(0x10 + 0x4 * x) -#define SUNXI_IRQ_FIQ_PENDING_REG(x)	(0x20 + 0x4 * x) -#define SUNXI_IRQ_ENABLE_REG(x)		(0x40 + 0x4 * x) -#define SUNXI_IRQ_MASK_REG(x)		(0x50 + 0x4 * x) - -static void __iomem *sunxi_irq_base; -static struct irq_domain *sunxi_irq_domain; - -void sunxi_irq_ack(struct irq_data *irqd) -{ -	unsigned int irq = irqd_to_hwirq(irqd); -	unsigned int irq_off = irq % 32; -	int reg = irq / 32; -	u32 val; - -	val = readl(sunxi_irq_base + SUNXI_IRQ_PENDING_REG(reg)); -	writel(val | (1 << irq_off), -	       sunxi_irq_base + SUNXI_IRQ_PENDING_REG(reg)); -} - -static void sunxi_irq_mask(struct irq_data *irqd) -{ -	unsigned int irq = irqd_to_hwirq(irqd); -	unsigned int irq_off = irq % 32; -	int reg = irq / 32; -	u32 val; - -	val = readl(sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(reg)); -	writel(val & ~(1 << irq_off), -	       sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(reg)); -} - -static void sunxi_irq_unmask(struct irq_data *irqd) -{ -	unsigned int irq = irqd_to_hwirq(irqd); -	unsigned int irq_off = irq % 32; -	int reg = irq / 32; -	u32 val; - -	val = readl(sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(reg)); -	writel(val | (1 << irq_off), -	       sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(reg)); -} - -static struct irq_chip sunxi_irq_chip = { -	.name		= "sunxi_irq", -	.irq_ack	= sunxi_irq_ack, -	.irq_mask	= sunxi_irq_mask, -	.irq_unmask	= sunxi_irq_unmask, -}; - -static int sunxi_irq_map(struct irq_domain *d, unsigned int virq, -			 irq_hw_number_t hw) -{ -	irq_set_chip_and_handler(virq, &sunxi_irq_chip, -				 handle_level_irq); -	set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); - -	return 0; -} - -static struct irq_domain_ops sunxi_irq_ops = { -	.map = sunxi_irq_map, -	.xlate = irq_domain_xlate_onecell, -}; - -static int __init sunxi_of_init(struct device_node *node, -				struct device_node *parent) -{ -	sunxi_irq_base = of_iomap(node, 0); -	if (!sunxi_irq_base) -		panic("%s: unable to map IC registers\n", -			node->full_name); - -	/* Disable all interrupts */ -	writel(0, sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(0)); -	writel(0, sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(1)); -	writel(0, sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(2)); - -	/* Mask all the interrupts */ -	writel(0, sunxi_irq_base + SUNXI_IRQ_MASK_REG(0)); -	writel(0, sunxi_irq_base + SUNXI_IRQ_MASK_REG(1)); -	writel(0, sunxi_irq_base + SUNXI_IRQ_MASK_REG(2)); - -	/* Clear all the pending interrupts */ -	writel(0xffffffff, sunxi_irq_base + SUNXI_IRQ_PENDING_REG(0)); -	writel(0xffffffff, sunxi_irq_base + SUNXI_IRQ_PENDING_REG(1)); -	writel(0xffffffff, sunxi_irq_base + SUNXI_IRQ_PENDING_REG(2)); - -	/* Enable protection mode */ -	writel(0x01, sunxi_irq_base + SUNXI_IRQ_PROTECTION_REG); - -	/* Configure the external interrupt source type */ -	writel(0x00, sunxi_irq_base + SUNXI_IRQ_NMI_CTRL_REG); - -	sunxi_irq_domain = irq_domain_add_linear(node, 3 * 32, -						 &sunxi_irq_ops, NULL); -	if (!sunxi_irq_domain) -		panic("%s: unable to create IRQ domain\n", node->full_name); - -	return 0; -} - -static struct of_device_id sunxi_irq_dt_ids[] __initconst = { -	{ .compatible = "allwinner,sunxi-ic", .data = sunxi_of_init }, -	{ } -}; - -void __init sunxi_init_irq(void) -{ -	of_irq_init(sunxi_irq_dt_ids); -} - -asmlinkage void __exception_irq_entry sunxi_handle_irq(struct pt_regs *regs) -{ -	u32 irq, hwirq; - -	hwirq = readl(sunxi_irq_base + SUNXI_IRQ_VECTOR_REG) >> 2; -	while (hwirq != 0) { -		irq = irq_find_mapping(sunxi_irq_domain, hwirq); -		handle_IRQ(irq, regs); -		hwirq = readl(sunxi_irq_base + SUNXI_IRQ_VECTOR_REG) >> 2; -	} -} diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c index 3cf97aaebe4..884d11c7355 100644 --- a/drivers/irqchip/irq-vic.c +++ b/drivers/irqchip/irq-vic.c @@ -23,6 +23,7 @@  #include <linux/init.h>  #include <linux/list.h>  #include <linux/io.h> +#include <linux/irq.h>  #include <linux/irqdomain.h>  #include <linux/of.h>  #include <linux/of_address.h> @@ -33,7 +34,7 @@  #include <linux/irqchip/arm-vic.h>  #include <asm/exception.h> -#include <asm/mach/irq.h> +#include <asm/irq.h>  #include "irqchip.h" diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 7c0af0e8004..0ee4a57fe6b 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -43,7 +43,6 @@  #include <asm/sizes.h>  #include <linux/platform_data/mmc-msm_sdcc.h> -#include <mach/msm_iomap.h>  #include <mach/dma.h>  #include <mach/clk.h> diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 63fb265e0da..8d6794cdf89 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -25,14 +25,93 @@  #include <mach/dma.h> -#include <mach/regs-sdi.h> -  #include <linux/platform_data/mmc-s3cmci.h>  #include "s3cmci.h"  #define DRIVER_NAME "s3c-mci" +#define S3C2410_SDICON			(0x00) +#define S3C2410_SDIPRE			(0x04) +#define S3C2410_SDICMDARG		(0x08) +#define S3C2410_SDICMDCON		(0x0C) +#define S3C2410_SDICMDSTAT		(0x10) +#define S3C2410_SDIRSP0			(0x14) +#define S3C2410_SDIRSP1			(0x18) +#define S3C2410_SDIRSP2			(0x1C) +#define S3C2410_SDIRSP3			(0x20) +#define S3C2410_SDITIMER		(0x24) +#define S3C2410_SDIBSIZE		(0x28) +#define S3C2410_SDIDCON			(0x2C) +#define S3C2410_SDIDCNT			(0x30) +#define S3C2410_SDIDSTA			(0x34) +#define S3C2410_SDIFSTA			(0x38) + +#define S3C2410_SDIDATA			(0x3C) +#define S3C2410_SDIIMSK			(0x40) + +#define S3C2440_SDIDATA			(0x40) +#define S3C2440_SDIIMSK			(0x3C) + +#define S3C2440_SDICON_SDRESET		(1 << 8) +#define S3C2410_SDICON_SDIOIRQ		(1 << 3) +#define S3C2410_SDICON_FIFORESET	(1 << 1) +#define S3C2410_SDICON_CLOCKTYPE	(1 << 0) + +#define S3C2410_SDICMDCON_LONGRSP	(1 << 10) +#define S3C2410_SDICMDCON_WAITRSP	(1 << 9) +#define S3C2410_SDICMDCON_CMDSTART	(1 << 8) +#define S3C2410_SDICMDCON_SENDERHOST	(1 << 6) +#define S3C2410_SDICMDCON_INDEX		(0x3f) + +#define S3C2410_SDICMDSTAT_CRCFAIL	(1 << 12) +#define S3C2410_SDICMDSTAT_CMDSENT	(1 << 11) +#define S3C2410_SDICMDSTAT_CMDTIMEOUT	(1 << 10) +#define S3C2410_SDICMDSTAT_RSPFIN	(1 << 9) + +#define S3C2440_SDIDCON_DS_WORD		(2 << 22) +#define S3C2410_SDIDCON_TXAFTERRESP	(1 << 20) +#define S3C2410_SDIDCON_RXAFTERCMD	(1 << 19) +#define S3C2410_SDIDCON_BLOCKMODE	(1 << 17) +#define S3C2410_SDIDCON_WIDEBUS		(1 << 16) +#define S3C2410_SDIDCON_DMAEN		(1 << 15) +#define S3C2410_SDIDCON_STOP		(1 << 14) +#define S3C2440_SDIDCON_DATSTART	(1 << 14) + +#define S3C2410_SDIDCON_XFER_RXSTART	(2 << 12) +#define S3C2410_SDIDCON_XFER_TXSTART	(3 << 12) + +#define S3C2410_SDIDCON_BLKNUM_MASK	(0xFFF) + +#define S3C2410_SDIDSTA_SDIOIRQDETECT	(1 << 9) +#define S3C2410_SDIDSTA_FIFOFAIL	(1 << 8) +#define S3C2410_SDIDSTA_CRCFAIL		(1 << 7) +#define S3C2410_SDIDSTA_RXCRCFAIL	(1 << 6) +#define S3C2410_SDIDSTA_DATATIMEOUT	(1 << 5) +#define S3C2410_SDIDSTA_XFERFINISH	(1 << 4) +#define S3C2410_SDIDSTA_TXDATAON	(1 << 1) +#define S3C2410_SDIDSTA_RXDATAON	(1 << 0) + +#define S3C2440_SDIFSTA_FIFORESET	(1 << 16) +#define S3C2440_SDIFSTA_FIFOFAIL	(3 << 14) +#define S3C2410_SDIFSTA_TFDET		(1 << 13) +#define S3C2410_SDIFSTA_RFDET		(1 << 12) +#define S3C2410_SDIFSTA_COUNTMASK	(0x7f) + +#define S3C2410_SDIIMSK_RESPONSECRC	(1 << 17) +#define S3C2410_SDIIMSK_CMDSENT		(1 << 16) +#define S3C2410_SDIIMSK_CMDTIMEOUT	(1 << 15) +#define S3C2410_SDIIMSK_RESPONSEND	(1 << 14) +#define S3C2410_SDIIMSK_SDIOIRQ		(1 << 12) +#define S3C2410_SDIIMSK_FIFOFAIL	(1 << 11) +#define S3C2410_SDIIMSK_CRCSTATUS	(1 << 10) +#define S3C2410_SDIIMSK_DATACRC		(1 << 9) +#define S3C2410_SDIIMSK_DATATIMEOUT	(1 << 8) +#define S3C2410_SDIIMSK_DATAFINISH	(1 << 7) +#define S3C2410_SDIIMSK_TXFIFOHALF	(1 << 4) +#define S3C2410_SDIIMSK_RXFIFOLAST	(1 << 2) +#define S3C2410_SDIIMSK_RXFIFOHALF	(1 << 0) +  enum dbg_channels {  	dbg_err   = (1 << 0),  	dbg_debug = (1 << 1), diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index 4d7f531e945..5d7529ed539 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -18,6 +18,7 @@  #include <linux/interrupt.h>  #include <linux/irq.h>  #include <linux/irqdomain.h> +#include <linux/irqchip/chained_irq.h>  #include <linux/io.h>  #include <linux/gpio.h>  #include <linux/pinctrl/machine.h> @@ -27,8 +28,6 @@  /* Since we request GPIOs from ourself */  #include <linux/pinctrl/consumer.h> -#include <asm/mach/irq.h> -  #include <mach/hardware.h>  #include <mach/at91_pio.h> diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c index 8b10b1ac907..ec1567842a7 100644 --- a/drivers/pinctrl/pinctrl-exynos.c +++ b/drivers/pinctrl/pinctrl-exynos.c @@ -23,14 +23,13 @@  #include <linux/interrupt.h>  #include <linux/irqdomain.h>  #include <linux/irq.h> +#include <linux/irqchip/chained_irq.h>  #include <linux/of_irq.h>  #include <linux/io.h>  #include <linux/slab.h>  #include <linux/spinlock.h>  #include <linux/err.h> -#include <asm/mach/irq.h> -  #include "pinctrl-samsung.h"  #include "pinctrl-exynos.h" diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index 435bf3078d2..34281754b62 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c @@ -23,6 +23,7 @@  #include <linux/interrupt.h>  #include <linux/irq.h>  #include <linux/irqdomain.h> +#include <linux/irqchip/chained_irq.h>  #include <linux/slab.h>  #include <linux/of_device.h>  #include <linux/of_address.h> @@ -33,7 +34,6 @@  /* Since we request GPIOs from ourself */  #include <linux/pinctrl/consumer.h>  #include <linux/platform_data/pinctrl-nomadik.h> -#include <asm/mach/irq.h>  #include "pinctrl-nomadik.h"  #include "core.h" diff --git a/drivers/pinctrl/pinctrl-sirf.c b/drivers/pinctrl/pinctrl-sirf.c index fb906257074..1ed23d02011 100644 --- a/drivers/pinctrl/pinctrl-sirf.c +++ b/drivers/pinctrl/pinctrl-sirf.c @@ -14,6 +14,7 @@  #include <linux/slab.h>  #include <linux/err.h>  #include <linux/irqdomain.h> +#include <linux/irqchip/chained_irq.h>  #include <linux/pinctrl/pinctrl.h>  #include <linux/pinctrl/pinmux.h>  #include <linux/pinctrl/consumer.h> @@ -25,7 +26,6 @@  #include <linux/bitops.h>  #include <linux/gpio.h>  #include <linux/of_gpio.h> -#include <asm/mach/irq.h>  #define DRIVER_NAME "pinmux-sirf" diff --git a/drivers/pinctrl/spear/pinctrl-plgpio.c b/drivers/pinctrl/spear/pinctrl-plgpio.c index 295b349a05c..a4908ecd74f 100644 --- a/drivers/pinctrl/spear/pinctrl-plgpio.c +++ b/drivers/pinctrl/spear/pinctrl-plgpio.c @@ -15,12 +15,12 @@  #include <linux/io.h>  #include <linux/irq.h>  #include <linux/irqdomain.h> +#include <linux/irqchip/chained_irq.h>  #include <linux/module.h>  #include <linux/pinctrl/consumer.h>  #include <linux/platform_device.h>  #include <linux/pm.h>  #include <linux/spinlock.h> -#include <asm/mach/irq.h>  #define MAX_GPIO_PER_REG		32  #define PIN_OFFSET(pin)			(pin % MAX_GPIO_PER_REG) diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index a9cd26a26dc..483ce086990 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -30,8 +30,6 @@  #include <linux/stmp_device.h>  #include <linux/stmp3xxx_rtc_wdt.h> -#include <mach/common.h> -  #define STMP3XXX_RTC_CTRL			0x0  #define STMP3XXX_RTC_CTRL_SET			0x4  #define STMP3XXX_RTC_CTRL_CLR			0x8 @@ -264,7 +262,7 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev)  	platform_set_drvdata(pdev, rtc_data); -	mxs_reset_block(rtc_data->io); +	stmp_reset_block(rtc_data->io);  	writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN |  			STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN |  			STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE, @@ -307,7 +305,7 @@ static int stmp3xxx_rtc_resume(struct device *dev)  {  	struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); -	mxs_reset_block(rtc_data->io); +	stmp_reset_block(rtc_data->io);  	writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN |  			STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN |  			STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE, diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index 6044e1717b2..2856b8fd44a 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -36,9 +36,6 @@  #include <linux/delay.h>  #include <linux/input.h> -#include <mach/mxs.h> -#include <mach/common.h> -  #include <linux/iio/iio.h>  #include <linux/iio/buffer.h>  #include <linux/iio/trigger.h> diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c index 055b99db50f..0880ef1a01b 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c +++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c @@ -25,8 +25,8 @@  #include <linux/clk.h>  #include <linux/list.h>  #include <linux/irq.h> +#include <linux/irqchip/chained_irq.h>  #include <linux/of_device.h> -#include <asm/mach/irq.h>  #include "imx-ipu-v3.h"  #include "ipu-prv.h" diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index 114583a8e92..07592c00af2 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -14,7 +14,7 @@  #include <linux/clk.h>  #include <linux/of.h>  #include <linux/platform_device.h> -#include <linux/platform_data/usb-exynos.h> +#include <linux/platform_data/usb-ohci-exynos.h>  #include <linux/usb/phy.h>  #include <linux/usb/samsung_usb_phy.h> |