diff mbox

[06/18] ARM: imx: New timer driver APIs based on IP block

Message ID 1430405073-13106-7-git-send-email-shenwei.wang@freescale.com (mailing list archive)
State New, archived
Headers show

Commit Message

Shenwei Wang April 30, 2015, 2:44 p.m. UTC
Implemented the necessory imx timer driver APIs directly
based on the version of IP block. These APIs are only relating
to the version of the timer block, and are independent of
the SoC.

Signed-off-by: Shenwei Wang <shenwei.wang@freescale.com>
---
 arch/arm/mach-imx/time.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 171 insertions(+)

Comments

Shawn Guo May 15, 2015, 1:44 a.m. UTC | #1
On Thu, Apr 30, 2015 at 09:44:21AM -0500, Shenwei Wang wrote:
> Implemented the necessory imx timer driver APIs directly
> based on the version of IP block. These APIs are only relating
> to the version of the timer block, and are independent of
> the SoC.
> 
> Signed-off-by: Shenwei Wang <shenwei.wang@freescale.com>
> ---
>  arch/arm/mach-imx/time.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 171 insertions(+)
> 
> diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c
> index 4db233f..811d50a 100644
> --- a/arch/arm/mach-imx/time.c
> +++ b/arch/arm/mach-imx/time.c
> @@ -101,6 +101,54 @@ static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
>  
>  static void __iomem *timer_base;
>  
> +static void gpt_irq_disable_v0_v1(struct imx_timer *tm)
> +{
> +	unsigned int tmp;
> +
> +	tmp = __raw_readl(tm->timer_base + MXC_TCTL);
> +	__raw_writel(tmp & ~MX1_2_TCTL_IRQEN, tm->timer_base + MXC_TCTL);
> +
> +}
> +
> +static void gpt_irq_disable_v2_v3(struct imx_timer *tm)
> +{
> +	__raw_writel(0, tm->timer_base + V2_IR);
> +
> +}
> +
> +static void gpt_irq_enable_v0_v1(struct imx_timer *tm)
> +{
> +	__raw_writel(__raw_readl(tm->timer_base + MXC_TCTL) | MX1_2_TCTL_IRQEN,
> +			tm->timer_base + MXC_TCTL);
> +}
> +
> +static void gpt_irq_enable_v2_v3(struct imx_timer *tm)
> +{
> +	__raw_writel(1, tm->timer_base + V2_IR);
> +}
> +
> +static void gpt_irq_acknowledge_v0(struct imx_timer *tm)
> +{
> +	__raw_readl(tm->timer_base + MX1_2_TSTAT);
> +
> +	__raw_writel(0, tm->timer_base + MX1_2_TSTAT);
> +}
> +
> +static void gpt_irq_acknowledge_v1(struct imx_timer *tm)
> +{
> +	__raw_readl(tm->timer_base + MX1_2_TSTAT);
> +
> +	__raw_writel(MX2_TSTAT_CAPT | MX2_TSTAT_COMP,
> +			tm->timer_base + MX1_2_TSTAT);
> +}
> +
> +static void gpt_irq_acknowledge_v2_v3(struct imx_timer *tm)
> +{
> +	__raw_readl(tm->timer_base + V2_TSTAT);
> +
> +	__raw_writel(V2_TSTAT_OF1, tm->timer_base + V2_TSTAT);
> +}
> +
>  static inline void gpt_irq_disable(void)
>  {
>  	unsigned int tmp;
> @@ -314,6 +362,129 @@ static int __init mxc_clockevent_init(struct clk *timer_clk,
>  	return 0;
>  }
>  
> +static void __init _mxc_timer_init_v0_v1(int irq, struct clk *clk_per,
> +		struct clk *clk_ipg, struct imx_timer *tm)
> +{
> +	uint32_t tctl_val;
> +
> +	if (IS_ERR(clk_per)) {
> +		pr_err("i.MX timer: unable to get clk\n");
> +		return;
> +	}
> +
> +	if (!IS_ERR(clk_ipg))
> +		clk_prepare_enable(clk_ipg);
> +
> +	clk_prepare_enable(clk_per);
> +
> +	/*
> +	 * Initialise to a known state (all timers off, and timing reset)
> +	 */
> +
> +	__raw_writel(0, tm->timer_base + MXC_TCTL);
> +	__raw_writel(0, tm->timer_base + MXC_TPRER); /* see datasheet note */
> +
> +	tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;
> +
> +	__raw_writel(tctl_val, tm->timer_base + MXC_TCTL);
> +
> +	/* init and register the timer to the framework */
> +	mxc_clocksource_init(clk_per, tm->timer_base + MX1_2_TCN);
> +
> +	tm->evt.set_next_event = mx1_2_set_next_event;
> +	mxc_clockevent_init(clk_per, tm);
> +
> +	/* Make irqs happen */
> +	setup_irq(irq, &tm->act);
> +}
> +
> +static void __init _mxc_timer_init_v2(int irq, struct clk *clk_per,
> +		struct clk *clk_ipg, struct imx_timer *tm)
> +{
> +	uint32_t tctl_val;
> +
> +	if (IS_ERR(clk_per)) {
> +		pr_err("i.MX timer: unable to get clk\n");
> +		return;
> +	}
> +
> +	if (!IS_ERR(clk_ipg))
> +		clk_prepare_enable(clk_ipg);
> +
> +	clk_prepare_enable(clk_per);
> +
> +	/*
> +	 * Initialise to a known state (all timers off, and timing reset)
> +	 */
> +
> +	__raw_writel(0, tm->timer_base + MXC_TCTL);
> +	__raw_writel(0, tm->timer_base + MXC_TPRER); /* see datasheet note */
> +
> +	tctl_val = V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN;
> +
> +	if (clk_get_rate(clk_per) == V2_TIMER_RATE_OSC_DIV8)
> +		tctl_val |= V2_TCTL_CLK_OSC_DIV8;
> +	else
> +		tctl_val |= V2_TCTL_CLK_PER;
> +
> +	__raw_writel(tctl_val, tm->timer_base + MXC_TCTL);
> +
> +	/* init and register the timer to the framework */
> +	mxc_clocksource_init(clk_per, tm->timer_base + V2_TCN);
> +
> +	tm->evt.set_next_event = v2_set_next_event;
> +	mxc_clockevent_init(clk_per, tm);
> +
> +	/* Make irqs happen */
> +	setup_irq(irq, &tm->act);
> +}
> +
> +static void __init _mxc_timer_init_v3(int irq, struct clk *clk_per,
> +		struct clk *clk_ipg, struct imx_timer *tm)
> +{
> +	uint32_t tctl_val;
> +
> +	if (IS_ERR(clk_per)) {
> +		pr_err("i.MX timer: unable to get clk\n");
> +		return;
> +	}
> +
> +	if (!IS_ERR(clk_ipg))
> +		clk_prepare_enable(clk_ipg);
> +
> +	clk_prepare_enable(clk_per);
> +
> +	/*
> +	 * Initialise to a known state (all timers off, and timing reset)
> +	 */
> +
> +	__raw_writel(0, tm->timer_base + MXC_TCTL);
> +	__raw_writel(0, tm->timer_base + MXC_TPRER); /* see datasheet note */
> +
> +	tctl_val = V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN;
> +
> +	if (clk_get_rate(clk_per) == V2_TIMER_RATE_OSC_DIV8) {
> +		tctl_val |= V2_TCTL_CLK_OSC_DIV8;
> +		/* 24 / 8 = 3 MHz */
> +		__raw_writel(7 << V2_TPRER_PRE24M,
> +					tm->timer_base + MXC_TPRER);
> +		tctl_val |= V2_TCTL_24MEN;
> +	} else {
> +		tctl_val |= V2_TCTL_CLK_PER;
> +	}
> +
> +	__raw_writel(tctl_val, tm->timer_base + MXC_TCTL);
> +
> +	/* init and register the timer to the framework */
> +	mxc_clocksource_init(clk_per, tm->timer_base + V2_TCN);
> +
> +	tm->evt.set_next_event = v2_set_next_event;
> +	mxc_clockevent_init(clk_per, tm);
> +
> +	/* Make irqs happen */
> +	setup_irq(irq, &tm->act);
> +}
> +

Quite some bit of the code is duplicated among these three
_mxc_timer_init_v?() functions.  I'm not sure this makes the most sense.

Shawn

>  static void __init _mxc_timer_init(int irq,
>  				   struct clk *clk_per, struct clk *clk_ipg)
>  {
> -- 
> 1.9.1
> 
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
diff mbox

Patch

diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c
index 4db233f..811d50a 100644
--- a/arch/arm/mach-imx/time.c
+++ b/arch/arm/mach-imx/time.c
@@ -101,6 +101,54 @@  static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
 
 static void __iomem *timer_base;
 
+static void gpt_irq_disable_v0_v1(struct imx_timer *tm)
+{
+	unsigned int tmp;
+
+	tmp = __raw_readl(tm->timer_base + MXC_TCTL);
+	__raw_writel(tmp & ~MX1_2_TCTL_IRQEN, tm->timer_base + MXC_TCTL);
+
+}
+
+static void gpt_irq_disable_v2_v3(struct imx_timer *tm)
+{
+	__raw_writel(0, tm->timer_base + V2_IR);
+
+}
+
+static void gpt_irq_enable_v0_v1(struct imx_timer *tm)
+{
+	__raw_writel(__raw_readl(tm->timer_base + MXC_TCTL) | MX1_2_TCTL_IRQEN,
+			tm->timer_base + MXC_TCTL);
+}
+
+static void gpt_irq_enable_v2_v3(struct imx_timer *tm)
+{
+	__raw_writel(1, tm->timer_base + V2_IR);
+}
+
+static void gpt_irq_acknowledge_v0(struct imx_timer *tm)
+{
+	__raw_readl(tm->timer_base + MX1_2_TSTAT);
+
+	__raw_writel(0, tm->timer_base + MX1_2_TSTAT);
+}
+
+static void gpt_irq_acknowledge_v1(struct imx_timer *tm)
+{
+	__raw_readl(tm->timer_base + MX1_2_TSTAT);
+
+	__raw_writel(MX2_TSTAT_CAPT | MX2_TSTAT_COMP,
+			tm->timer_base + MX1_2_TSTAT);
+}
+
+static void gpt_irq_acknowledge_v2_v3(struct imx_timer *tm)
+{
+	__raw_readl(tm->timer_base + V2_TSTAT);
+
+	__raw_writel(V2_TSTAT_OF1, tm->timer_base + V2_TSTAT);
+}
+
 static inline void gpt_irq_disable(void)
 {
 	unsigned int tmp;
@@ -314,6 +362,129 @@  static int __init mxc_clockevent_init(struct clk *timer_clk,
 	return 0;
 }
 
+static void __init _mxc_timer_init_v0_v1(int irq, struct clk *clk_per,
+		struct clk *clk_ipg, struct imx_timer *tm)
+{
+	uint32_t tctl_val;
+
+	if (IS_ERR(clk_per)) {
+		pr_err("i.MX timer: unable to get clk\n");
+		return;
+	}
+
+	if (!IS_ERR(clk_ipg))
+		clk_prepare_enable(clk_ipg);
+
+	clk_prepare_enable(clk_per);
+
+	/*
+	 * Initialise to a known state (all timers off, and timing reset)
+	 */
+
+	__raw_writel(0, tm->timer_base + MXC_TCTL);
+	__raw_writel(0, tm->timer_base + MXC_TPRER); /* see datasheet note */
+
+	tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;
+
+	__raw_writel(tctl_val, tm->timer_base + MXC_TCTL);
+
+	/* init and register the timer to the framework */
+	mxc_clocksource_init(clk_per, tm->timer_base + MX1_2_TCN);
+
+	tm->evt.set_next_event = mx1_2_set_next_event;
+	mxc_clockevent_init(clk_per, tm);
+
+	/* Make irqs happen */
+	setup_irq(irq, &tm->act);
+}
+
+static void __init _mxc_timer_init_v2(int irq, struct clk *clk_per,
+		struct clk *clk_ipg, struct imx_timer *tm)
+{
+	uint32_t tctl_val;
+
+	if (IS_ERR(clk_per)) {
+		pr_err("i.MX timer: unable to get clk\n");
+		return;
+	}
+
+	if (!IS_ERR(clk_ipg))
+		clk_prepare_enable(clk_ipg);
+
+	clk_prepare_enable(clk_per);
+
+	/*
+	 * Initialise to a known state (all timers off, and timing reset)
+	 */
+
+	__raw_writel(0, tm->timer_base + MXC_TCTL);
+	__raw_writel(0, tm->timer_base + MXC_TPRER); /* see datasheet note */
+
+	tctl_val = V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN;
+
+	if (clk_get_rate(clk_per) == V2_TIMER_RATE_OSC_DIV8)
+		tctl_val |= V2_TCTL_CLK_OSC_DIV8;
+	else
+		tctl_val |= V2_TCTL_CLK_PER;
+
+	__raw_writel(tctl_val, tm->timer_base + MXC_TCTL);
+
+	/* init and register the timer to the framework */
+	mxc_clocksource_init(clk_per, tm->timer_base + V2_TCN);
+
+	tm->evt.set_next_event = v2_set_next_event;
+	mxc_clockevent_init(clk_per, tm);
+
+	/* Make irqs happen */
+	setup_irq(irq, &tm->act);
+}
+
+static void __init _mxc_timer_init_v3(int irq, struct clk *clk_per,
+		struct clk *clk_ipg, struct imx_timer *tm)
+{
+	uint32_t tctl_val;
+
+	if (IS_ERR(clk_per)) {
+		pr_err("i.MX timer: unable to get clk\n");
+		return;
+	}
+
+	if (!IS_ERR(clk_ipg))
+		clk_prepare_enable(clk_ipg);
+
+	clk_prepare_enable(clk_per);
+
+	/*
+	 * Initialise to a known state (all timers off, and timing reset)
+	 */
+
+	__raw_writel(0, tm->timer_base + MXC_TCTL);
+	__raw_writel(0, tm->timer_base + MXC_TPRER); /* see datasheet note */
+
+	tctl_val = V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN;
+
+	if (clk_get_rate(clk_per) == V2_TIMER_RATE_OSC_DIV8) {
+		tctl_val |= V2_TCTL_CLK_OSC_DIV8;
+		/* 24 / 8 = 3 MHz */
+		__raw_writel(7 << V2_TPRER_PRE24M,
+					tm->timer_base + MXC_TPRER);
+		tctl_val |= V2_TCTL_24MEN;
+	} else {
+		tctl_val |= V2_TCTL_CLK_PER;
+	}
+
+	__raw_writel(tctl_val, tm->timer_base + MXC_TCTL);
+
+	/* init and register the timer to the framework */
+	mxc_clocksource_init(clk_per, tm->timer_base + V2_TCN);
+
+	tm->evt.set_next_event = v2_set_next_event;
+	mxc_clockevent_init(clk_per, tm);
+
+	/* Make irqs happen */
+	setup_irq(irq, &tm->act);
+}
+
 static void __init _mxc_timer_init(int irq,
 				   struct clk *clk_per, struct clk *clk_ipg)
 {