Merge branch 'next/timer' of git://git.linaro.org/people/arnd/arm-soc
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 2 Nov 2011 03:18:05 +0000 (20:18 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 2 Nov 2011 03:18:05 +0000 (20:18 -0700)
* 'next/timer' of git://git.linaro.org/people/arnd/arm-soc:
  clocksource: fixup ux500 build problems
  ARM: omap: use __devexit_p in dmtimer driver
  ARM: ux500: Reprogram timers upon resume
  ARM: plat-nomadik: timer: Export reset functions
  ARM: plat-nomadik: timer: Add support for periodic timers
  ARM: ux500: Move timer code to separate file
  ARM: ux500: add support for clocksource DBX500 PRCMU
  clocksource: add DBX500 PRCMU Timer support
  ARM: plat-nomadik: MTU sched_clock as an option
  ARM: OMAP: dmtimer: add error handling to export APIs
  ARM: OMAP: dmtimer: low-power mode support
  ARM: OMAP: dmtimer: skip reserved timers
  ARM: OMAP: dmtimer: pm_runtime support
  ARM: OMAP: dmtimer: switch-over to platform device driver
  ARM: OMAP: dmtimer: platform driver
  ARM: OMAP2+: dmtimer: convert to platform devices
  ARM: OMAP1: dmtimer: conversion to platform devices
  ARM: OMAP2+: dmtimer: add device names to flck nodes
  ARM: OMAP: Add support for dmtimer v2 ip

25 files changed:
arch/arm/mach-omap1/Makefile
arch/arm/mach-omap1/timer.c [new file with mode: 0644]
arch/arm/mach-omap2/clock2420_data.c
arch/arm/mach-omap2/clock2430_data.c
arch/arm/mach-omap2/clock3xxx_data.c
arch/arm/mach-omap2/clock44xx_data.c
arch/arm/mach-omap2/omap_hwmod_2420_data.c
arch/arm/mach-omap2/omap_hwmod_2430_data.c
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
arch/arm/mach-omap2/omap_hwmod_44xx_data.c
arch/arm/mach-omap2/timer.c
arch/arm/mach-ux500/Makefile
arch/arm/mach-ux500/cpu.c
arch/arm/mach-ux500/include/mach/db5500-regs.h
arch/arm/mach-ux500/include/mach/db8500-regs.h
arch/arm/mach-ux500/timer.c [new file with mode: 0644]
arch/arm/plat-nomadik/Kconfig
arch/arm/plat-nomadik/include/plat/mtu.h
arch/arm/plat-nomadik/timer.c
arch/arm/plat-omap/dmtimer.c
arch/arm/plat-omap/include/plat/dmtimer.h
drivers/clocksource/Kconfig
drivers/clocksource/Makefile
drivers/clocksource/clksrc-dbx500-prcmu.c [new file with mode: 0644]
include/linux/clksrc-dbx500-prcmu.h [new file with mode: 0644]

index 5b114d1..11c85cd 100644 (file)
@@ -4,7 +4,7 @@
 
 # Common support
 obj-y := io.o id.o sram.o time.o irq.o mux.o flash.o serial.o devices.o dma.o
-obj-y += clock.o clock_data.o opp_data.o reset.o pm_bus.o
+obj-y += clock.o clock_data.o opp_data.o reset.o pm_bus.o timer.o
 
 obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
 
diff --git a/arch/arm/mach-omap1/timer.c b/arch/arm/mach-omap1/timer.c
new file mode 100644 (file)
index 0000000..6e90665
--- /dev/null
@@ -0,0 +1,173 @@
+/**
+ * OMAP1 Dual-Mode Timers - platform device registration
+ *
+ * Contains first level initialization routines which internally
+ * generates timer device information and registers with linux
+ * device model. It also has low level function to chnage the timer
+ * input clock source.
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Tarun Kanti DebBarma <tarun.kanti@ti.com>
+ * Thara Gopinath <thara@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include <mach/irqs.h>
+
+#include <plat/dmtimer.h>
+
+#define OMAP1610_GPTIMER1_BASE         0xfffb1400
+#define OMAP1610_GPTIMER2_BASE         0xfffb1c00
+#define OMAP1610_GPTIMER3_BASE         0xfffb2400
+#define OMAP1610_GPTIMER4_BASE         0xfffb2c00
+#define OMAP1610_GPTIMER5_BASE         0xfffb3400
+#define OMAP1610_GPTIMER6_BASE         0xfffb3c00
+#define OMAP1610_GPTIMER7_BASE         0xfffb7400
+#define OMAP1610_GPTIMER8_BASE         0xfffbd400
+
+#define OMAP1_DM_TIMER_COUNT           8
+
+static int omap1_dm_timer_set_src(struct platform_device *pdev,
+                               int source)
+{
+       int n = (pdev->id - 1) << 1;
+       u32 l;
+
+       l = __raw_readl(MOD_CONF_CTRL_1) & ~(0x03 << n);
+       l |= source << n;
+       __raw_writel(l, MOD_CONF_CTRL_1);
+
+       return 0;
+}
+
+
+int __init omap1_dm_timer_init(void)
+{
+       int i;
+       int ret;
+       struct dmtimer_platform_data *pdata;
+       struct platform_device *pdev;
+
+       if (!cpu_is_omap16xx())
+               return 0;
+
+       for (i = 1; i <= OMAP1_DM_TIMER_COUNT; i++) {
+               struct resource res[2];
+               u32 base, irq;
+
+               switch (i) {
+               case 1:
+                       base = OMAP1610_GPTIMER1_BASE;
+                       irq = INT_1610_GPTIMER1;
+                       break;
+               case 2:
+                       base = OMAP1610_GPTIMER2_BASE;
+                       irq = INT_1610_GPTIMER2;
+                       break;
+               case 3:
+                       base = OMAP1610_GPTIMER3_BASE;
+                       irq = INT_1610_GPTIMER3;
+                       break;
+               case 4:
+                       base = OMAP1610_GPTIMER4_BASE;
+                       irq = INT_1610_GPTIMER4;
+                       break;
+               case 5:
+                       base = OMAP1610_GPTIMER5_BASE;
+                       irq = INT_1610_GPTIMER5;
+                       break;
+               case 6:
+                       base = OMAP1610_GPTIMER6_BASE;
+                       irq = INT_1610_GPTIMER6;
+                       break;
+               case 7:
+                       base = OMAP1610_GPTIMER7_BASE;
+                       irq = INT_1610_GPTIMER7;
+                       break;
+               case 8:
+                       base = OMAP1610_GPTIMER8_BASE;
+                       irq = INT_1610_GPTIMER8;
+                       break;
+               default:
+                       /*
+                        * not supposed to reach here.
+                        * this is to remove warning.
+                        */
+                       return -EINVAL;
+               }
+
+               pdev = platform_device_alloc("omap_timer", i);
+               if (!pdev) {
+                       pr_err("%s: Failed to device alloc for dmtimer%d\n",
+                               __func__, i);
+                       return -ENOMEM;
+               }
+
+               memset(res, 0, 2 * sizeof(struct resource));
+               res[0].start = base;
+               res[0].end = base + 0x46;
+               res[0].flags = IORESOURCE_MEM;
+               res[1].start = irq;
+               res[1].end = irq;
+               res[1].flags = IORESOURCE_IRQ;
+               ret = platform_device_add_resources(pdev, res,
+                               ARRAY_SIZE(res));
+               if (ret) {
+                       dev_err(&pdev->dev, "%s: Failed to add resources.\n",
+                               __func__);
+                       goto err_free_pdev;
+               }
+
+               pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+               if (!pdata) {
+                       dev_err(&pdev->dev, "%s: Failed to allocate pdata.\n",
+                               __func__);
+                       ret = -ENOMEM;
+                       goto err_free_pdata;
+               }
+
+               pdata->set_timer_src = omap1_dm_timer_set_src;
+               pdata->needs_manual_reset = 1;
+
+               ret = platform_device_add_data(pdev, pdata, sizeof(*pdata));
+               if (ret) {
+                       dev_err(&pdev->dev, "%s: Failed to add platform data.\n",
+                               __func__);
+                       goto err_free_pdata;
+               }
+
+               ret = platform_device_add(pdev);
+               if (ret) {
+                       dev_err(&pdev->dev, "%s: Failed to add platform device.\n",
+                               __func__);
+                       goto err_free_pdata;
+               }
+
+               dev_dbg(&pdev->dev, " Registered.\n");
+       }
+
+       return 0;
+
+err_free_pdata:
+       kfree(pdata);
+
+err_free_pdev:
+       platform_device_unregister(pdev);
+
+       return ret;
+}
+arch_initcall(omap1_dm_timer_init);
index debc040..14a6277 100644 (file)
@@ -1898,6 +1898,54 @@ static struct omap_clk omap2420_clks[] = {
        CLK(NULL,       "pka_ick",      &pka_ick,       CK_242X),
        CLK(NULL,       "usb_fck",      &usb_fck,       CK_242X),
        CLK("musb-hdrc",        "fck",  &osc_ck,        CK_242X),
+       CLK("omap_timer.1",     "fck",  &gpt1_fck,      CK_242X),
+       CLK("omap_timer.2",     "fck",  &gpt2_fck,      CK_242X),
+       CLK("omap_timer.3",     "fck",  &gpt3_fck,      CK_242X),
+       CLK("omap_timer.4",     "fck",  &gpt4_fck,      CK_242X),
+       CLK("omap_timer.5",     "fck",  &gpt5_fck,      CK_242X),
+       CLK("omap_timer.6",     "fck",  &gpt6_fck,      CK_242X),
+       CLK("omap_timer.7",     "fck",  &gpt7_fck,      CK_242X),
+       CLK("omap_timer.8",     "fck",  &gpt8_fck,      CK_242X),
+       CLK("omap_timer.9",     "fck",  &gpt9_fck,      CK_242X),
+       CLK("omap_timer.10",    "fck",  &gpt10_fck,     CK_242X),
+       CLK("omap_timer.11",    "fck",  &gpt11_fck,     CK_242X),
+       CLK("omap_timer.12",    "fck",  &gpt12_fck,     CK_242X),
+       CLK("omap_timer.1",     "32k_ck",       &func_32k_ck,   CK_243X),
+       CLK("omap_timer.2",     "32k_ck",       &func_32k_ck,   CK_243X),
+       CLK("omap_timer.3",     "32k_ck",       &func_32k_ck,   CK_243X),
+       CLK("omap_timer.4",     "32k_ck",       &func_32k_ck,   CK_243X),
+       CLK("omap_timer.5",     "32k_ck",       &func_32k_ck,   CK_243X),
+       CLK("omap_timer.6",     "32k_ck",       &func_32k_ck,   CK_243X),
+       CLK("omap_timer.7",     "32k_ck",       &func_32k_ck,   CK_243X),
+       CLK("omap_timer.8",     "32k_ck",       &func_32k_ck,   CK_243X),
+       CLK("omap_timer.9",     "32k_ck",       &func_32k_ck,   CK_243X),
+       CLK("omap_timer.10",    "32k_ck",       &func_32k_ck,   CK_243X),
+       CLK("omap_timer.11",    "32k_ck",       &func_32k_ck,   CK_243X),
+       CLK("omap_timer.12",    "32k_ck",       &func_32k_ck,   CK_243X),
+       CLK("omap_timer.1",     "sys_ck",       &sys_ck,        CK_243X),
+       CLK("omap_timer.2",     "sys_ck",       &sys_ck,        CK_243X),
+       CLK("omap_timer.3",     "sys_ck",       &sys_ck,        CK_243X),
+       CLK("omap_timer.4",     "sys_ck",       &sys_ck,        CK_243X),
+       CLK("omap_timer.5",     "sys_ck",       &sys_ck,        CK_243X),
+       CLK("omap_timer.6",     "sys_ck",       &sys_ck,        CK_243X),
+       CLK("omap_timer.7",     "sys_ck",       &sys_ck,        CK_243X),
+       CLK("omap_timer.8",     "sys_ck",       &sys_ck,        CK_243X),
+       CLK("omap_timer.9",     "sys_ck",       &sys_ck,        CK_243X),
+       CLK("omap_timer.10",    "sys_ck",       &sys_ck,        CK_243X),
+       CLK("omap_timer.11",    "sys_ck",       &sys_ck,        CK_243X),
+       CLK("omap_timer.12",    "sys_ck",       &sys_ck,        CK_243X),
+       CLK("omap_timer.1",     "alt_ck",       &alt_ck,        CK_243X),
+       CLK("omap_timer.2",     "alt_ck",       &alt_ck,        CK_243X),
+       CLK("omap_timer.3",     "alt_ck",       &alt_ck,        CK_243X),
+       CLK("omap_timer.4",     "alt_ck",       &alt_ck,        CK_243X),
+       CLK("omap_timer.5",     "alt_ck",       &alt_ck,        CK_243X),
+       CLK("omap_timer.6",     "alt_ck",       &alt_ck,        CK_243X),
+       CLK("omap_timer.7",     "alt_ck",       &alt_ck,        CK_243X),
+       CLK("omap_timer.8",     "alt_ck",       &alt_ck,        CK_243X),
+       CLK("omap_timer.9",     "alt_ck",       &alt_ck,        CK_243X),
+       CLK("omap_timer.10",    "alt_ck",       &alt_ck,        CK_243X),
+       CLK("omap_timer.11",    "alt_ck",       &alt_ck,        CK_243X),
+       CLK("omap_timer.12",    "alt_ck",       &alt_ck,        CK_243X),
 };
 
 /*
index 96a942e..ea6717c 100644 (file)
@@ -1998,6 +1998,54 @@ static struct omap_clk omap2430_clks[] = {
        CLK(NULL,       "mdm_intc_ick", &mdm_intc_ick,  CK_243X),
        CLK("omap_hsmmc.0", "mmchsdb_fck",      &mmchsdb1_fck,  CK_243X),
        CLK("omap_hsmmc.1", "mmchsdb_fck",      &mmchsdb2_fck,  CK_243X),
+       CLK("omap_timer.1",     "fck",  &gpt1_fck,      CK_243X),
+       CLK("omap_timer.2",     "fck",  &gpt2_fck,      CK_243X),
+       CLK("omap_timer.3",     "fck",  &gpt3_fck,      CK_243X),
+       CLK("omap_timer.4",     "fck",  &gpt4_fck,      CK_243X),
+       CLK("omap_timer.5",     "fck",  &gpt5_fck,      CK_243X),
+       CLK("omap_timer.6",     "fck",  &gpt6_fck,      CK_243X),
+       CLK("omap_timer.7",     "fck",  &gpt7_fck,      CK_243X),
+       CLK("omap_timer.8",     "fck",  &gpt8_fck,      CK_243X),
+       CLK("omap_timer.9",     "fck",  &gpt9_fck,      CK_243X),
+       CLK("omap_timer.10",    "fck",  &gpt10_fck,     CK_243X),
+       CLK("omap_timer.11",    "fck",  &gpt11_fck,     CK_243X),
+       CLK("omap_timer.12",    "fck",  &gpt12_fck,     CK_243X),
+       CLK("omap_timer.1",     "32k_ck",  &func_32k_ck,   CK_243X),
+       CLK("omap_timer.2",     "32k_ck",  &func_32k_ck,   CK_243X),
+       CLK("omap_timer.3",     "32k_ck",  &func_32k_ck,   CK_243X),
+       CLK("omap_timer.4",     "32k_ck",  &func_32k_ck,   CK_243X),
+       CLK("omap_timer.5",     "32k_ck",  &func_32k_ck,   CK_243X),
+       CLK("omap_timer.6",     "32k_ck",  &func_32k_ck,   CK_243X),
+       CLK("omap_timer.7",     "32k_ck",  &func_32k_ck,   CK_243X),
+       CLK("omap_timer.8",     "32k_ck",  &func_32k_ck,   CK_243X),
+       CLK("omap_timer.9",     "32k_ck",  &func_32k_ck,   CK_243X),
+       CLK("omap_timer.10",    "32k_ck",  &func_32k_ck,   CK_243X),
+       CLK("omap_timer.11",    "32k_ck",  &func_32k_ck,   CK_243X),
+       CLK("omap_timer.12",    "32k_ck",  &func_32k_ck,   CK_243X),
+       CLK("omap_timer.1",     "sys_ck",       &sys_ck,        CK_243X),
+       CLK("omap_timer.2",     "sys_ck",       &sys_ck,        CK_243X),
+       CLK("omap_timer.3",     "sys_ck",       &sys_ck,        CK_243X),
+       CLK("omap_timer.4",     "sys_ck",       &sys_ck,        CK_243X),
+       CLK("omap_timer.5",     "sys_ck",       &sys_ck,        CK_243X),
+       CLK("omap_timer.6",     "sys_ck",       &sys_ck,        CK_243X),
+       CLK("omap_timer.7",     "sys_ck",       &sys_ck,        CK_243X),
+       CLK("omap_timer.8",     "sys_ck",       &sys_ck,        CK_243X),
+       CLK("omap_timer.9",     "sys_ck",       &sys_ck,        CK_243X),
+       CLK("omap_timer.10",    "sys_ck",       &sys_ck,        CK_243X),
+       CLK("omap_timer.11",    "sys_ck",       &sys_ck,        CK_243X),
+       CLK("omap_timer.12",    "sys_ck",       &sys_ck,        CK_243X),
+       CLK("omap_timer.1",     "alt_ck",       &alt_ck,        CK_243X),
+       CLK("omap_timer.2",     "alt_ck",       &alt_ck,        CK_243X),
+       CLK("omap_timer.3",     "alt_ck",       &alt_ck,        CK_243X),
+       CLK("omap_timer.4",     "alt_ck",       &alt_ck,        CK_243X),
+       CLK("omap_timer.5",     "alt_ck",       &alt_ck,        CK_243X),
+       CLK("omap_timer.6",     "alt_ck",       &alt_ck,        CK_243X),
+       CLK("omap_timer.7",     "alt_ck",       &alt_ck,        CK_243X),
+       CLK("omap_timer.8",     "alt_ck",       &alt_ck,        CK_243X),
+       CLK("omap_timer.9",     "alt_ck",       &alt_ck,        CK_243X),
+       CLK("omap_timer.10",    "alt_ck",       &alt_ck,        CK_243X),
+       CLK("omap_timer.11",    "alt_ck",       &alt_ck,        CK_243X),
+       CLK("omap_timer.12",    "alt_ck",       &alt_ck,        CK_243X),
 };
 
 /*
index dadb8c6..65dd363 100644 (file)
@@ -3464,6 +3464,42 @@ static struct omap_clk omap3xxx_clks[] = {
        CLK("musb-am35x",       "fck",          &hsotgusb_fck_am35xx,   CK_AM35XX),
        CLK(NULL,       "hecc_ck",      &hecc_ck,       CK_AM35XX),
        CLK(NULL,       "uart4_ick",    &uart4_ick_am35xx,      CK_AM35XX),
+       CLK("omap_timer.1",     "fck",  &gpt1_fck,      CK_3XXX),
+       CLK("omap_timer.2",     "fck",  &gpt2_fck,      CK_3XXX),
+       CLK("omap_timer.3",     "fck",  &gpt3_fck,      CK_3XXX),
+       CLK("omap_timer.4",     "fck",  &gpt4_fck,      CK_3XXX),
+       CLK("omap_timer.5",     "fck",  &gpt5_fck,      CK_3XXX),
+       CLK("omap_timer.6",     "fck",  &gpt6_fck,      CK_3XXX),
+       CLK("omap_timer.7",     "fck",  &gpt7_fck,      CK_3XXX),
+       CLK("omap_timer.8",     "fck",  &gpt8_fck,      CK_3XXX),
+       CLK("omap_timer.9",     "fck",  &gpt9_fck,      CK_3XXX),
+       CLK("omap_timer.10",    "fck",  &gpt10_fck,     CK_3XXX),
+       CLK("omap_timer.11",    "fck",  &gpt11_fck,     CK_3XXX),
+       CLK("omap_timer.12",    "fck",  &gpt12_fck,     CK_3XXX),
+       CLK("omap_timer.1",     "32k_ck",       &omap_32k_fck,  CK_3XXX),
+       CLK("omap_timer.2",     "32k_ck",       &omap_32k_fck,  CK_3XXX),
+       CLK("omap_timer.3",     "32k_ck",       &omap_32k_fck,  CK_3XXX),
+       CLK("omap_timer.4",     "32k_ck",       &omap_32k_fck,  CK_3XXX),
+       CLK("omap_timer.5",     "32k_ck",       &omap_32k_fck,  CK_3XXX),
+       CLK("omap_timer.6",     "32k_ck",       &omap_32k_fck,  CK_3XXX),
+       CLK("omap_timer.7",     "32k_ck",       &omap_32k_fck,  CK_3XXX),
+       CLK("omap_timer.8",     "32k_ck",       &omap_32k_fck,  CK_3XXX),
+       CLK("omap_timer.9",     "32k_ck",       &omap_32k_fck,  CK_3XXX),
+       CLK("omap_timer.10",    "32k_ck",       &omap_32k_fck,  CK_3XXX),
+       CLK("omap_timer.11",    "32k_ck",       &omap_32k_fck,  CK_3XXX),
+       CLK("omap_timer.12",    "32k_ck",       &omap_32k_fck,  CK_3XXX),
+       CLK("omap_timer.1",     "sys_ck",       &sys_ck,        CK_3XXX),
+       CLK("omap_timer.2",     "sys_ck",       &sys_ck,        CK_3XXX),
+       CLK("omap_timer.3",     "sys_ck",       &sys_ck,        CK_3XXX),
+       CLK("omap_timer.4",     "sys_ck",       &sys_ck,        CK_3XXX),
+       CLK("omap_timer.5",     "sys_ck",       &sys_ck,        CK_3XXX),
+       CLK("omap_timer.6",     "sys_ck",       &sys_ck,        CK_3XXX),
+       CLK("omap_timer.7",     "sys_ck",       &sys_ck,        CK_3XXX),
+       CLK("omap_timer.8",     "sys_ck",       &sys_ck,        CK_3XXX),
+       CLK("omap_timer.9",     "sys_ck",       &sys_ck,        CK_3XXX),
+       CLK("omap_timer.10",    "sys_ck",       &sys_ck,        CK_3XXX),
+       CLK("omap_timer.11",    "sys_ck",       &sys_ck,        CK_3XXX),
+       CLK("omap_timer.12",    "sys_ck",       &sys_ck,        CK_3XXX),
 };
 
 
index c0b6fbd..946bf04 100644 (file)
@@ -3363,6 +3363,39 @@ static struct omap_clk omap44xx_clks[] = {
        CLK("usbhs-omap.0",     "usbhost_ick",          &dummy_ck,              CK_443X),
        CLK("usbhs-omap.0",     "usbtll_fck",           &dummy_ck,      CK_443X),
        CLK("omap_wdt", "ick",                          &dummy_ck,      CK_443X),
+       CLK("omap_timer.1",     "fck",                  &timer1_fck,    CK_443X),
+       CLK("omap_timer.2",     "fck",                  &timer2_fck,    CK_443X),
+       CLK("omap_timer.3",     "fck",                  &timer3_fck,    CK_443X),
+       CLK("omap_timer.4",     "fck",                  &timer4_fck,    CK_443X),
+       CLK("omap_timer.5",     "fck",                  &timer5_fck,    CK_443X),
+       CLK("omap_timer.6",     "fck",                  &timer6_fck,    CK_443X),
+       CLK("omap_timer.7",     "fck",                  &timer7_fck,    CK_443X),
+       CLK("omap_timer.8",     "fck",                  &timer8_fck,    CK_443X),
+       CLK("omap_timer.9",     "fck",                  &timer9_fck,    CK_443X),
+       CLK("omap_timer.10",    "fck",                  &timer10_fck,   CK_443X),
+       CLK("omap_timer.11",    "fck",                  &timer11_fck,   CK_443X),
+       CLK("omap_timer.1",     "32k_ck",       &sys_32k_ck,    CK_443X),
+       CLK("omap_timer.2",     "32k_ck",       &sys_32k_ck,    CK_443X),
+       CLK("omap_timer.3",     "32k_ck",       &sys_32k_ck,    CK_443X),
+       CLK("omap_timer.4",     "32k_ck",       &sys_32k_ck,    CK_443X),
+       CLK("omap_timer.5",     "32k_ck",       &sys_32k_ck,    CK_443X),
+       CLK("omap_timer.6",     "32k_ck",       &sys_32k_ck,    CK_443X),
+       CLK("omap_timer.7",     "32k_ck",       &sys_32k_ck,    CK_443X),
+       CLK("omap_timer.8",     "32k_ck",       &sys_32k_ck,    CK_443X),
+       CLK("omap_timer.9",     "32k_ck",       &sys_32k_ck,    CK_443X),
+       CLK("omap_timer.10",    "32k_ck",       &sys_32k_ck,    CK_443X),
+       CLK("omap_timer.11",    "32k_ck",       &sys_32k_ck,    CK_443X),
+       CLK("omap_timer.1",     "sys_ck",       &sys_clkin_ck,  CK_443X),
+       CLK("omap_timer.2",     "sys_ck",       &sys_clkin_ck,  CK_443X),
+       CLK("omap_timer.3",     "sys_ck",       &sys_clkin_ck,  CK_443X),
+       CLK("omap_timer.4",     "sys_ck",       &sys_clkin_ck,  CK_443X),
+       CLK("omap_timer.9",     "sys_ck",       &sys_clkin_ck,  CK_443X),
+       CLK("omap_timer.10",    "sys_ck",       &sys_clkin_ck,  CK_443X),
+       CLK("omap_timer.11",    "sys_ck",       &sys_clkin_ck,  CK_443X),
+       CLK("omap_timer.5",     "sys_ck",       &syc_clk_div_ck,        CK_443X),
+       CLK("omap_timer.6",     "sys_ck",       &syc_clk_div_ck,        CK_443X),
+       CLK("omap_timer.7",     "sys_ck",       &syc_clk_div_ck,        CK_443X),
+       CLK("omap_timer.8",     "sys_ck",       &syc_clk_div_ck,        CK_443X),
 };
 
 int __init omap4xxx_clk_init(void)
index b6ea69a..6d72062 100644 (file)
@@ -269,6 +269,16 @@ static struct omap_hwmod omap2420_iva_hwmod = {
        .masters_cnt    = ARRAY_SIZE(omap2420_iva_masters),
 };
 
+/* always-on timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
+       .timer_capability       = OMAP_TIMER_ALWON,
+};
+
+/* pwm timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_pwm_dev_attr = {
+       .timer_capability       = OMAP_TIMER_HAS_PWM,
+};
+
 /* timer1 */
 static struct omap_hwmod omap2420_timer1_hwmod;
 
@@ -309,6 +319,7 @@ static struct omap_hwmod omap2420_timer1_hwmod = {
                        .idlest_idle_bit = OMAP24XX_ST_GPT1_SHIFT,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap2420_timer1_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap2420_timer1_slaves),
        .class          = &omap2xxx_timer_hwmod_class,
@@ -345,6 +356,7 @@ static struct omap_hwmod omap2420_timer2_hwmod = {
                        .idlest_idle_bit = OMAP24XX_ST_GPT2_SHIFT,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap2420_timer2_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap2420_timer2_slaves),
        .class          = &omap2xxx_timer_hwmod_class,
@@ -381,6 +393,7 @@ static struct omap_hwmod omap2420_timer3_hwmod = {
                        .idlest_idle_bit = OMAP24XX_ST_GPT3_SHIFT,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap2420_timer3_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap2420_timer3_slaves),
        .class          = &omap2xxx_timer_hwmod_class,
@@ -417,6 +430,7 @@ static struct omap_hwmod omap2420_timer4_hwmod = {
                        .idlest_idle_bit = OMAP24XX_ST_GPT4_SHIFT,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap2420_timer4_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap2420_timer4_slaves),
        .class          = &omap2xxx_timer_hwmod_class,
@@ -453,6 +467,7 @@ static struct omap_hwmod omap2420_timer5_hwmod = {
                        .idlest_idle_bit = OMAP24XX_ST_GPT5_SHIFT,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap2420_timer5_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap2420_timer5_slaves),
        .class          = &omap2xxx_timer_hwmod_class,
@@ -490,6 +505,7 @@ static struct omap_hwmod omap2420_timer6_hwmod = {
                        .idlest_idle_bit = OMAP24XX_ST_GPT6_SHIFT,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap2420_timer6_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap2420_timer6_slaves),
        .class          = &omap2xxx_timer_hwmod_class,
@@ -526,6 +542,7 @@ static struct omap_hwmod omap2420_timer7_hwmod = {
                        .idlest_idle_bit = OMAP24XX_ST_GPT7_SHIFT,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap2420_timer7_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap2420_timer7_slaves),
        .class          = &omap2xxx_timer_hwmod_class,
@@ -562,6 +579,7 @@ static struct omap_hwmod omap2420_timer8_hwmod = {
                        .idlest_idle_bit = OMAP24XX_ST_GPT8_SHIFT,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap2420_timer8_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap2420_timer8_slaves),
        .class          = &omap2xxx_timer_hwmod_class,
@@ -598,6 +616,7 @@ static struct omap_hwmod omap2420_timer9_hwmod = {
                        .idlest_idle_bit = OMAP24XX_ST_GPT9_SHIFT,
                },
        },
+       .dev_attr       = &capability_pwm_dev_attr,
        .slaves         = omap2420_timer9_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap2420_timer9_slaves),
        .class          = &omap2xxx_timer_hwmod_class,
@@ -634,6 +653,7 @@ static struct omap_hwmod omap2420_timer10_hwmod = {
                        .idlest_idle_bit = OMAP24XX_ST_GPT10_SHIFT,
                },
        },
+       .dev_attr       = &capability_pwm_dev_attr,
        .slaves         = omap2420_timer10_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap2420_timer10_slaves),
        .class          = &omap2xxx_timer_hwmod_class,
@@ -670,6 +690,7 @@ static struct omap_hwmod omap2420_timer11_hwmod = {
                        .idlest_idle_bit = OMAP24XX_ST_GPT11_SHIFT,
                },
        },
+       .dev_attr       = &capability_pwm_dev_attr,
        .slaves         = omap2420_timer11_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap2420_timer11_slaves),
        .class          = &omap2xxx_timer_hwmod_class,
@@ -706,6 +727,7 @@ static struct omap_hwmod omap2420_timer12_hwmod = {
                        .idlest_idle_bit = OMAP24XX_ST_GPT12_SHIFT,
                },
        },
+       .dev_attr       = &capability_pwm_dev_attr,
        .slaves         = omap2420_timer12_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap2420_timer12_slaves),
        .class          = &omap2xxx_timer_hwmod_class,
index 56de8d6..a2580d0 100644 (file)
@@ -343,6 +343,16 @@ static struct omap_hwmod omap2430_iva_hwmod = {
        .masters_cnt    = ARRAY_SIZE(omap2430_iva_masters),
 };
 
+/* always-on timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
+       .timer_capability       = OMAP_TIMER_ALWON,
+};
+
+/* pwm timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_pwm_dev_attr = {
+       .timer_capability       = OMAP_TIMER_HAS_PWM,
+};
+
 /* timer1 */
 static struct omap_hwmod omap2430_timer1_hwmod;
 
@@ -383,6 +393,7 @@ static struct omap_hwmod omap2430_timer1_hwmod = {
                        .idlest_idle_bit = OMAP24XX_ST_GPT1_SHIFT,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap2430_timer1_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap2430_timer1_slaves),
        .class          = &omap2xxx_timer_hwmod_class,
@@ -419,6 +430,7 @@ static struct omap_hwmod omap2430_timer2_hwmod = {
                        .idlest_idle_bit = OMAP24XX_ST_GPT2_SHIFT,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap2430_timer2_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap2430_timer2_slaves),
        .class          = &omap2xxx_timer_hwmod_class,
@@ -455,6 +467,7 @@ static struct omap_hwmod omap2430_timer3_hwmod = {
                        .idlest_idle_bit = OMAP24XX_ST_GPT3_SHIFT,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap2430_timer3_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap2430_timer3_slaves),
        .class          = &omap2xxx_timer_hwmod_class,
@@ -491,6 +504,7 @@ static struct omap_hwmod omap2430_timer4_hwmod = {
                        .idlest_idle_bit = OMAP24XX_ST_GPT4_SHIFT,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap2430_timer4_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap2430_timer4_slaves),
        .class          = &omap2xxx_timer_hwmod_class,
@@ -527,6 +541,7 @@ static struct omap_hwmod omap2430_timer5_hwmod = {
                        .idlest_idle_bit = OMAP24XX_ST_GPT5_SHIFT,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap2430_timer5_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap2430_timer5_slaves),
        .class          = &omap2xxx_timer_hwmod_class,
@@ -563,6 +578,7 @@ static struct omap_hwmod omap2430_timer6_hwmod = {
                        .idlest_idle_bit = OMAP24XX_ST_GPT6_SHIFT,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap2430_timer6_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap2430_timer6_slaves),
        .class          = &omap2xxx_timer_hwmod_class,
@@ -599,6 +615,7 @@ static struct omap_hwmod omap2430_timer7_hwmod = {
                        .idlest_idle_bit = OMAP24XX_ST_GPT7_SHIFT,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap2430_timer7_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap2430_timer7_slaves),
        .class          = &omap2xxx_timer_hwmod_class,
@@ -635,6 +652,7 @@ static struct omap_hwmod omap2430_timer8_hwmod = {
                        .idlest_idle_bit = OMAP24XX_ST_GPT8_SHIFT,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap2430_timer8_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap2430_timer8_slaves),
        .class          = &omap2xxx_timer_hwmod_class,
@@ -671,6 +689,7 @@ static struct omap_hwmod omap2430_timer9_hwmod = {
                        .idlest_idle_bit = OMAP24XX_ST_GPT9_SHIFT,
                },
        },
+       .dev_attr       = &capability_pwm_dev_attr,
        .slaves         = omap2430_timer9_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap2430_timer9_slaves),
        .class          = &omap2xxx_timer_hwmod_class,
@@ -707,6 +726,7 @@ static struct omap_hwmod omap2430_timer10_hwmod = {
                        .idlest_idle_bit = OMAP24XX_ST_GPT10_SHIFT,
                },
        },
+       .dev_attr       = &capability_pwm_dev_attr,
        .slaves         = omap2430_timer10_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap2430_timer10_slaves),
        .class          = &omap2xxx_timer_hwmod_class,
@@ -743,6 +763,7 @@ static struct omap_hwmod omap2430_timer11_hwmod = {
                        .idlest_idle_bit = OMAP24XX_ST_GPT11_SHIFT,
                },
        },
+       .dev_attr       = &capability_pwm_dev_attr,
        .slaves         = omap2430_timer11_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap2430_timer11_slaves),
        .class          = &omap2xxx_timer_hwmod_class,
@@ -779,6 +800,7 @@ static struct omap_hwmod omap2430_timer12_hwmod = {
                        .idlest_idle_bit = OMAP24XX_ST_GPT12_SHIFT,
                },
        },
+       .dev_attr       = &capability_pwm_dev_attr,
        .slaves         = omap2430_timer12_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap2430_timer12_slaves),
        .class          = &omap2xxx_timer_hwmod_class,
index ab35acb..2e4852d 100644 (file)
@@ -564,6 +564,21 @@ static struct omap_hwmod_class omap3xxx_timer_hwmod_class = {
        .rev =  OMAP_TIMER_IP_VERSION_1,
 };
 
+/* secure timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_secure_dev_attr = {
+       .timer_capability       = OMAP_TIMER_SECURE,
+};
+
+/* always-on timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
+       .timer_capability       = OMAP_TIMER_ALWON,
+};
+
+/* pwm timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_pwm_dev_attr = {
+       .timer_capability       = OMAP_TIMER_HAS_PWM,
+};
+
 /* timer1 */
 static struct omap_hwmod omap3xxx_timer1_hwmod;
 
@@ -604,6 +619,7 @@ static struct omap_hwmod omap3xxx_timer1_hwmod = {
                        .idlest_idle_bit = OMAP3430_ST_GPT1_SHIFT,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap3xxx_timer1_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap3xxx_timer1_slaves),
        .class          = &omap3xxx_timer_1ms_hwmod_class,
@@ -649,6 +665,7 @@ static struct omap_hwmod omap3xxx_timer2_hwmod = {
                        .idlest_idle_bit = OMAP3430_ST_GPT2_SHIFT,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap3xxx_timer2_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap3xxx_timer2_slaves),
        .class          = &omap3xxx_timer_1ms_hwmod_class,
@@ -694,6 +711,7 @@ static struct omap_hwmod omap3xxx_timer3_hwmod = {
                        .idlest_idle_bit = OMAP3430_ST_GPT3_SHIFT,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap3xxx_timer3_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap3xxx_timer3_slaves),
        .class          = &omap3xxx_timer_hwmod_class,
@@ -739,6 +757,7 @@ static struct omap_hwmod omap3xxx_timer4_hwmod = {
                        .idlest_idle_bit = OMAP3430_ST_GPT4_SHIFT,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap3xxx_timer4_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap3xxx_timer4_slaves),
        .class          = &omap3xxx_timer_hwmod_class,
@@ -784,6 +803,7 @@ static struct omap_hwmod omap3xxx_timer5_hwmod = {
                        .idlest_idle_bit = OMAP3430_ST_GPT5_SHIFT,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap3xxx_timer5_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap3xxx_timer5_slaves),
        .class          = &omap3xxx_timer_hwmod_class,
@@ -829,6 +849,7 @@ static struct omap_hwmod omap3xxx_timer6_hwmod = {
                        .idlest_idle_bit = OMAP3430_ST_GPT6_SHIFT,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap3xxx_timer6_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap3xxx_timer6_slaves),
        .class          = &omap3xxx_timer_hwmod_class,
@@ -874,6 +895,7 @@ static struct omap_hwmod omap3xxx_timer7_hwmod = {
                        .idlest_idle_bit = OMAP3430_ST_GPT7_SHIFT,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap3xxx_timer7_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap3xxx_timer7_slaves),
        .class          = &omap3xxx_timer_hwmod_class,
@@ -919,6 +941,7 @@ static struct omap_hwmod omap3xxx_timer8_hwmod = {
                        .idlest_idle_bit = OMAP3430_ST_GPT8_SHIFT,
                },
        },
+       .dev_attr       = &capability_pwm_dev_attr,
        .slaves         = omap3xxx_timer8_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap3xxx_timer8_slaves),
        .class          = &omap3xxx_timer_hwmod_class,
@@ -964,6 +987,7 @@ static struct omap_hwmod omap3xxx_timer9_hwmod = {
                        .idlest_idle_bit = OMAP3430_ST_GPT9_SHIFT,
                },
        },
+       .dev_attr       = &capability_pwm_dev_attr,
        .slaves         = omap3xxx_timer9_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap3xxx_timer9_slaves),
        .class          = &omap3xxx_timer_hwmod_class,
@@ -1000,6 +1024,7 @@ static struct omap_hwmod omap3xxx_timer10_hwmod = {
                        .idlest_idle_bit = OMAP3430_ST_GPT10_SHIFT,
                },
        },
+       .dev_attr       = &capability_pwm_dev_attr,
        .slaves         = omap3xxx_timer10_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap3xxx_timer10_slaves),
        .class          = &omap3xxx_timer_1ms_hwmod_class,
@@ -1036,6 +1061,7 @@ static struct omap_hwmod omap3xxx_timer11_hwmod = {
                        .idlest_idle_bit = OMAP3430_ST_GPT11_SHIFT,
                },
        },
+       .dev_attr       = &capability_pwm_dev_attr,
        .slaves         = omap3xxx_timer11_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap3xxx_timer11_slaves),
        .class          = &omap3xxx_timer_hwmod_class,
@@ -1085,6 +1111,7 @@ static struct omap_hwmod omap3xxx_timer12_hwmod = {
                        .idlest_idle_bit = OMAP3430_ST_GPT12_SHIFT,
                },
        },
+       .dev_attr       = &capability_secure_dev_attr,
        .slaves         = omap3xxx_timer12_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap3xxx_timer12_slaves),
        .class          = &omap3xxx_timer_hwmod_class,
index fd1074a..7695e5d 100644 (file)
@@ -29,6 +29,7 @@
 #include <plat/mcbsp.h>
 #include <plat/mmc.h>
 #include <plat/i2c.h>
+#include <plat/dmtimer.h>
 
 #include "omap_hwmod_common_data.h"
 
@@ -4201,6 +4202,16 @@ static struct omap_hwmod_class omap44xx_timer_hwmod_class = {
        .sysc   = &omap44xx_timer_sysc,
 };
 
+/* always-on timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
+       .timer_capability       = OMAP_TIMER_ALWON,
+};
+
+/* pwm timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_pwm_dev_attr = {
+       .timer_capability       = OMAP_TIMER_HAS_PWM,
+};
+
 /* timer1 */
 static struct omap_hwmod omap44xx_timer1_hwmod;
 static struct omap_hwmod_irq_info omap44xx_timer1_irqs[] = {
@@ -4244,6 +4255,7 @@ static struct omap_hwmod omap44xx_timer1_hwmod = {
                        .modulemode   = MODULEMODE_SWCTRL,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap44xx_timer1_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_timer1_slaves),
 };
@@ -4291,6 +4303,7 @@ static struct omap_hwmod omap44xx_timer2_hwmod = {
                        .modulemode   = MODULEMODE_SWCTRL,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap44xx_timer2_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_timer2_slaves),
 };
@@ -4338,6 +4351,7 @@ static struct omap_hwmod omap44xx_timer3_hwmod = {
                        .modulemode   = MODULEMODE_SWCTRL,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap44xx_timer3_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_timer3_slaves),
 };
@@ -4385,6 +4399,7 @@ static struct omap_hwmod omap44xx_timer4_hwmod = {
                        .modulemode   = MODULEMODE_SWCTRL,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap44xx_timer4_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_timer4_slaves),
 };
@@ -4451,6 +4466,7 @@ static struct omap_hwmod omap44xx_timer5_hwmod = {
                        .modulemode   = MODULEMODE_SWCTRL,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap44xx_timer5_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_timer5_slaves),
 };
@@ -4518,6 +4534,7 @@ static struct omap_hwmod omap44xx_timer6_hwmod = {
                        .modulemode   = MODULEMODE_SWCTRL,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap44xx_timer6_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_timer6_slaves),
 };
@@ -4584,6 +4601,7 @@ static struct omap_hwmod omap44xx_timer7_hwmod = {
                        .modulemode   = MODULEMODE_SWCTRL,
                },
        },
+       .dev_attr       = &capability_alwon_dev_attr,
        .slaves         = omap44xx_timer7_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_timer7_slaves),
 };
@@ -4650,6 +4668,7 @@ static struct omap_hwmod omap44xx_timer8_hwmod = {
                        .modulemode   = MODULEMODE_SWCTRL,
                },
        },
+       .dev_attr       = &capability_pwm_dev_attr,
        .slaves         = omap44xx_timer8_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_timer8_slaves),
 };
@@ -4697,6 +4716,7 @@ static struct omap_hwmod omap44xx_timer9_hwmod = {
                        .modulemode   = MODULEMODE_SWCTRL,
                },
        },
+       .dev_attr       = &capability_pwm_dev_attr,
        .slaves         = omap44xx_timer9_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_timer9_slaves),
 };
@@ -4744,6 +4764,7 @@ static struct omap_hwmod omap44xx_timer10_hwmod = {
                        .modulemode   = MODULEMODE_SWCTRL,
                },
        },
+       .dev_attr       = &capability_pwm_dev_attr,
        .slaves         = omap44xx_timer10_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_timer10_slaves),
 };
@@ -4791,6 +4812,7 @@ static struct omap_hwmod omap44xx_timer11_hwmod = {
                        .modulemode   = MODULEMODE_SWCTRL,
                },
        },
+       .dev_attr       = &capability_pwm_dev_attr,
        .slaves         = omap44xx_timer11_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_timer11_slaves),
 };
index cf1de7d..1140e98 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/irq.h>
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
+#include <linux/slab.h>
 
 #include <asm/mach/time.h>
 #include <plat/dmtimer.h>
 #include <asm/sched_clock.h>
 #include <plat/common.h>
 #include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
+#include <plat/omap-pm.h>
+
+#include "powerdomain.h"
 
 /* Parent clocks, eventually these will come from the clock framework */
 
@@ -67,7 +72,7 @@
 /* MAX_GPTIMER_ID: number of GPTIMERs on the chip */
 #define MAX_GPTIMER_ID         12
 
-u32 sys_timer_reserved;
+static u32 sys_timer_reserved;
 
 /* Clockevent code */
 
@@ -78,7 +83,7 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
 {
        struct clock_event_device *evt = &clockevent_gpt;
 
-       __omap_dm_timer_write_status(clkev.io_base, OMAP_TIMER_INT_OVERFLOW);
+       __omap_dm_timer_write_status(&clkev, OMAP_TIMER_INT_OVERFLOW);
 
        evt->event_handler(evt);
        return IRQ_HANDLED;
@@ -93,7 +98,7 @@ static struct irqaction omap2_gp_timer_irq = {
 static int omap2_gp_timer_set_next_event(unsigned long cycles,
                                         struct clock_event_device *evt)
 {
-       __omap_dm_timer_load_start(clkev.io_base, OMAP_TIMER_CTRL_ST,
+       __omap_dm_timer_load_start(&clkev, OMAP_TIMER_CTRL_ST,
                                                0xffffffff - cycles, 1);
 
        return 0;
@@ -104,16 +109,16 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
 {
        u32 period;
 
-       __omap_dm_timer_stop(clkev.io_base, 1, clkev.rate);
+       __omap_dm_timer_stop(&clkev, 1, clkev.rate);
 
        switch (mode) {
        case CLOCK_EVT_MODE_PERIODIC:
                period = clkev.rate / HZ;
                period -= 1;
                /* Looks like we need to first set the load value separately */
-               __omap_dm_timer_write(clkev.io_base, OMAP_TIMER_LOAD_REG,
+               __omap_dm_timer_write(&clkev, OMAP_TIMER_LOAD_REG,
                                        0xffffffff - period, 1);
-               __omap_dm_timer_load_start(clkev.io_base,
+               __omap_dm_timer_load_start(&clkev,
                                        OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST,
                                                0xffffffff - period, 1);
                break;
@@ -189,7 +194,8 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
                        clk_put(src);
                }
        }
-       __omap_dm_timer_reset(timer->io_base, 1, 1);
+       __omap_dm_timer_init_regs(timer);
+       __omap_dm_timer_reset(timer, 1, 1);
        timer->posted = 1;
 
        timer->rate = clk_get_rate(timer->fclk);
@@ -210,7 +216,7 @@ static void __init omap2_gp_clockevent_init(int gptimer_id,
        omap2_gp_timer_irq.dev_id = (void *)&clkev;
        setup_irq(clkev.irq, &omap2_gp_timer_irq);
 
-       __omap_dm_timer_int_enable(clkev.io_base, OMAP_TIMER_INT_OVERFLOW);
+       __omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW);
 
        clockevent_gpt.mult = div_sc(clkev.rate, NSEC_PER_SEC,
                                     clockevent_gpt.shift);
@@ -251,7 +257,7 @@ static struct omap_dm_timer clksrc;
 static DEFINE_CLOCK_DATA(cd);
 static cycle_t clocksource_read_cycles(struct clocksource *cs)
 {
-       return (cycle_t)__omap_dm_timer_read_counter(clksrc.io_base, 1);
+       return (cycle_t)__omap_dm_timer_read_counter(&clksrc, 1);
 }
 
 static struct clocksource clocksource_gpt = {
@@ -266,7 +272,7 @@ static void notrace dmtimer_update_sched_clock(void)
 {
        u32 cyc;
 
-       cyc = __omap_dm_timer_read_counter(clksrc.io_base, 1);
+       cyc = __omap_dm_timer_read_counter(&clksrc, 1);
 
        update_sched_clock(&cd, cyc, (u32)~0);
 }
@@ -276,7 +282,7 @@ unsigned long long notrace sched_clock(void)
        u32 cyc = 0;
 
        if (clksrc.reserved)
-               cyc = __omap_dm_timer_read_counter(clksrc.io_base, 1);
+               cyc = __omap_dm_timer_read_counter(&clksrc, 1);
 
        return cyc_to_sched_clock(&cd, cyc, (u32)~0);
 }
@@ -293,7 +299,7 @@ static void __init omap2_gp_clocksource_init(int gptimer_id,
        pr_info("OMAP clocksource: GPTIMER%d at %lu Hz\n",
                gptimer_id, clksrc.rate);
 
-       __omap_dm_timer_load_start(clksrc.io_base,
+       __omap_dm_timer_load_start(&clksrc,
                        OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1);
        init_sched_clock(&cd, dmtimer_update_sched_clock, 32, clksrc.rate);
 
@@ -341,3 +347,167 @@ static void __init omap4_timer_init(void)
 }
 OMAP_SYS_TIMER(4)
 #endif
+
+/**
+ * omap2_dm_timer_set_src - change the timer input clock source
+ * @pdev:      timer platform device pointer
+ * @source:    array index of parent clock source
+ */
+static int omap2_dm_timer_set_src(struct platform_device *pdev, int source)
+{
+       int ret;
+       struct dmtimer_platform_data *pdata = pdev->dev.platform_data;
+       struct clk *fclk, *parent;
+       char *parent_name = NULL;
+
+       fclk = clk_get(&pdev->dev, "fck");
+       if (IS_ERR_OR_NULL(fclk)) {
+               dev_err(&pdev->dev, "%s: %d: clk_get() FAILED\n",
+                               __func__, __LINE__);
+               return -EINVAL;
+       }
+
+       switch (source) {
+       case OMAP_TIMER_SRC_SYS_CLK:
+               parent_name = "sys_ck";
+               break;
+
+       case OMAP_TIMER_SRC_32_KHZ:
+               parent_name = "32k_ck";
+               break;
+
+       case OMAP_TIMER_SRC_EXT_CLK:
+               if (pdata->timer_ip_version == OMAP_TIMER_IP_VERSION_1) {
+                       parent_name = "alt_ck";
+                       break;
+               }
+               dev_err(&pdev->dev, "%s: %d: invalid clk src.\n",
+                       __func__, __LINE__);
+               clk_put(fclk);
+               return -EINVAL;
+       }
+
+       parent = clk_get(&pdev->dev, parent_name);
+       if (IS_ERR_OR_NULL(parent)) {
+               dev_err(&pdev->dev, "%s: %d: clk_get() %s FAILED\n",
+                       __func__, __LINE__, parent_name);
+               clk_put(fclk);
+               return -EINVAL;
+       }
+
+       ret = clk_set_parent(fclk, parent);
+       if (IS_ERR_VALUE(ret)) {
+               dev_err(&pdev->dev, "%s: clk_set_parent() to %s FAILED\n",
+                       __func__, parent_name);
+               ret = -EINVAL;
+       }
+
+       clk_put(parent);
+       clk_put(fclk);
+
+       return ret;
+}
+
+struct omap_device_pm_latency omap2_dmtimer_latency[] = {
+       {
+               .deactivate_func = omap_device_idle_hwmods,
+               .activate_func   = omap_device_enable_hwmods,
+               .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+       },
+};
+
+/**
+ * omap_timer_init - build and register timer device with an
+ * associated timer hwmod
+ * @oh:        timer hwmod pointer to be used to build timer device
+ * @user:      parameter that can be passed from calling hwmod API
+ *
+ * Called by omap_hwmod_for_each_by_class to register each of the timer
+ * devices present in the system. The number of timer devices is known
+ * by parsing through the hwmod database for a given class name. At the
+ * end of function call memory is allocated for timer device and it is
+ * registered to the framework ready to be proved by the driver.
+ */
+static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
+{
+       int id;
+       int ret = 0;
+       char *name = "omap_timer";
+       struct dmtimer_platform_data *pdata;
+       struct omap_device *od;
+       struct omap_timer_capability_dev_attr *timer_dev_attr;
+       struct powerdomain *pwrdm;
+
+       pr_debug("%s: %s\n", __func__, oh->name);
+
+       /* on secure device, do not register secure timer */
+       timer_dev_attr = oh->dev_attr;
+       if (omap_type() != OMAP2_DEVICE_TYPE_GP && timer_dev_attr)
+               if (timer_dev_attr->timer_capability == OMAP_TIMER_SECURE)
+                       return ret;
+
+       pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+       if (!pdata) {
+               pr_err("%s: No memory for [%s]\n", __func__, oh->name);
+               return -ENOMEM;
+       }
+
+       /*
+        * Extract the IDs from name field in hwmod database
+        * and use the same for constructing ids' for the
+        * timer devices. In a way, we are avoiding usage of
+        * static variable witin the function to do the same.
+        * CAUTION: We have to be careful and make sure the
+        * name in hwmod database does not change in which case
+        * we might either make corresponding change here or
+        * switch back static variable mechanism.
+        */
+       sscanf(oh->name, "timer%2d", &id);
+
+       pdata->set_timer_src = omap2_dm_timer_set_src;
+       pdata->timer_ip_version = oh->class->rev;
+
+       /* Mark clocksource and clockevent timers as reserved */
+       if ((sys_timer_reserved >> (id - 1)) & 0x1)
+               pdata->reserved = 1;
+
+       pwrdm = omap_hwmod_get_pwrdm(oh);
+       pdata->loses_context = pwrdm_can_ever_lose_context(pwrdm);
+#ifdef CONFIG_PM
+       pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count;
+#endif
+       od = omap_device_build(name, id, oh, pdata, sizeof(*pdata),
+                       omap2_dmtimer_latency,
+                       ARRAY_SIZE(omap2_dmtimer_latency),
+                       0);
+
+       if (IS_ERR(od)) {
+               pr_err("%s: Can't build omap_device for %s: %s.\n",
+                       __func__, name, oh->name);
+               ret = -EINVAL;
+       }
+
+       kfree(pdata);
+
+       return ret;
+}
+
+/**
+ * omap2_dm_timer_init - top level regular device initialization
+ *
+ * Uses dedicated hwmod api to parse through hwmod database for
+ * given class name and then build and register the timer device.
+ */
+static int __init omap2_dm_timer_init(void)
+{
+       int ret;
+
+       ret = omap_hwmod_for_each_by_class("timer", omap_timer_init, NULL);
+       if (unlikely(ret)) {
+               pr_err("%s: device registration failed.\n", __func__);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+arch_initcall(omap2_dm_timer_init);
index 9fd00a6..6bd2f45 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 obj-y                          := clock.o cpu.o devices.o devices-common.o \
-                                  id.o usb.o
+                                  id.o usb.o timer.o
 obj-$(CONFIG_CACHE_L2X0)       += cache-l2x0.o
 obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o dma-db5500.o
 obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o
index 252e8b3..1405d0e 100644 (file)
 #include <linux/clk.h>
 #include <linux/mfd/db8500-prcmu.h>
 #include <linux/mfd/db5500-prcmu.h>
+#include <linux/clksrc-dbx500-prcmu.h>
 
 #include <asm/hardware/gic.h>
 #include <asm/mach/map.h>
 #include <asm/localtimer.h>
 
-#include <plat/mtu.h>
 #include <mach/hardware.h>
 #include <mach/setup.h>
 #include <mach/devices.h>
@@ -50,30 +50,3 @@ void __init ux500_init_irq(void)
                prcmu_early_init();
        clk_init();
 }
-
-static void __init ux500_timer_init(void)
-{
-#ifdef CONFIG_LOCAL_TIMERS
-       /* Setup the local timer base */
-       if (cpu_is_u5500())
-               twd_base = __io_address(U5500_TWD_BASE);
-       else if (cpu_is_u8500())
-               twd_base = __io_address(U8500_TWD_BASE);
-       else
-               ux500_unknown_soc();
-#endif
-       if (cpu_is_u5500())
-               mtu_base = __io_address(U5500_MTU0_BASE);
-       else if (cpu_is_u8500ed())
-               mtu_base = __io_address(U8500_MTU0_BASE_ED);
-       else if (cpu_is_u8500())
-               mtu_base = __io_address(U8500_MTU0_BASE);
-       else
-               ux500_unknown_soc();
-
-       nmdk_timer_init();
-}
-
-struct sys_timer ux500_timer = {
-       .init   = ux500_timer_init,
-};
index 6ad9832..994b5fe 100644 (file)
@@ -61,6 +61,8 @@
 #define U5500_SCR_BASE         (U5500_PER4_BASE + 0x5000)
 #define U5500_DMC_BASE         (U5500_PER4_BASE + 0x6000)
 #define U5500_PRCMU_BASE       (U5500_PER4_BASE + 0x7000)
+#define U5500_PRCMU_TIMER_3_BASE (U5500_PER4_BASE + 0x07338)
+#define U5500_PRCMU_TIMER_4_BASE (U5500_PER4_BASE + 0x07450)
 #define U5500_MSP1_BASE                (U5500_PER4_BASE + 0x9000)
 #define U5500_GPIO2_BASE       (U5500_PER4_BASE + 0xA000)
 #define U5500_CDETECT_BASE     (U5500_PER4_BASE + 0xF000)
index 0499971..751b0e6 100644 (file)
 #define U8500_SCR_BASE         (U8500_PER4_BASE + 0x05000)
 #define U8500_DMC_BASE         (U8500_PER4_BASE + 0x06000)
 #define U8500_PRCMU_BASE       (U8500_PER4_BASE + 0x07000)
+#define U8500_PRCMU_TIMER_3_BASE (U8500_PER4_BASE + 0x07338)
+#define U8500_PRCMU_TIMER_4_BASE (U8500_PER4_BASE + 0x07450)
 #define U8500_PRCMU_TCDM_BASE_V1 (U8500_PER4_BASE + 0x0f000)
 #define U8500_PRCMU_TCDM_BASE  (U8500_PER4_BASE + 0x68000)
 #define U8500_PRCMU_TCPM_BASE   (U8500_PER4_BASE + 0x60000)
 
+
 /* per3 base addresses */
 #define U8500_FSMC_BASE                (U8500_PER3_BASE + 0x0000)
 #define U8500_SSP0_BASE                (U8500_PER3_BASE + 0x2000)
diff --git a/arch/arm/mach-ux500/timer.c b/arch/arm/mach-ux500/timer.c
new file mode 100644 (file)
index 0000000..aea467d
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson
+ */
+#include <linux/io.h>
+#include <linux/errno.h>
+#include <linux/clksrc-dbx500-prcmu.h>
+
+#include <asm/localtimer.h>
+
+#include <plat/mtu.h>
+
+#include <mach/setup.h>
+#include <mach/hardware.h>
+
+static void __init ux500_timer_init(void)
+{
+       void __iomem *prcmu_timer_base;
+
+       if (cpu_is_u5500()) {
+#ifdef CONFIG_LOCAL_TIMERS
+               twd_base = __io_address(U5500_TWD_BASE);
+#endif
+               mtu_base = __io_address(U5500_MTU0_BASE);
+               prcmu_timer_base = __io_address(U5500_PRCMU_TIMER_3_BASE);
+       } else if (cpu_is_u8500()) {
+#ifdef CONFIG_LOCAL_TIMERS
+               twd_base = __io_address(U8500_TWD_BASE);
+#endif
+               mtu_base = __io_address(U8500_MTU0_BASE);
+               prcmu_timer_base = __io_address(U8500_PRCMU_TIMER_4_BASE);
+       } else {
+               ux500_unknown_soc();
+       }
+
+       /*
+        * Here we register the timerblocks active in the system.
+        * Localtimers (twd) is started when both cpu is up and running.
+        * MTU register a clocksource, clockevent and sched_clock.
+        * Since the MTU is located in the VAPE power domain
+        * it will be cleared in sleep which makes it unsuitable.
+        * We however need it as a timer tick (clockevent)
+        * during boot to calibrate delay until twd is started.
+        * RTC-RTT have problems as timer tick during boot since it is
+        * depending on delay which is not yet calibrated. RTC-RTT is in the
+        * always-on powerdomain and is used as clockevent instead of twd when
+        * sleeping.
+        * The PRCMU timer 4(3 for DB5500) register a clocksource and
+        * sched_clock with higher rating then MTU since is always-on.
+        *
+        */
+
+       nmdk_timer_init();
+       clksrc_dbx500_prcmu_init(prcmu_timer_base);
+}
+
+static void ux500_timer_reset(void)
+{
+       nmdk_clkevt_reset();
+       nmdk_clksrc_reset();
+}
+
+struct sys_timer ux500_timer = {
+       .init           = ux500_timer_init,
+       .resume         = ux500_timer_reset,
+};
index ce65901..bca4914 100644 (file)
@@ -15,10 +15,16 @@ if PLAT_NOMADIK
 
 config HAS_MTU
        bool
-       select HAVE_SCHED_CLOCK
        help
          Support for Multi Timer Unit. MTU provides access
          to multiple interrupt generating programmable
          32-bit free running decrementing counters.
 
+config NOMADIK_MTU_SCHED_CLOCK
+       bool
+       depends on HAS_MTU
+       select HAVE_SCHED_CLOCK
+       help
+         Use the Multi Timer Unit as the sched_clock.
+
 endif
index 65704a3..6508e76 100644 (file)
@@ -1,54 +1,11 @@
 #ifndef __PLAT_MTU_H
 #define __PLAT_MTU_H
 
-/*
- * Guaranteed runtime conversion range in seconds for
- * the clocksource and clockevent.
- */
-#define MTU_MIN_RANGE 4
-
 /* should be set by the platform code */
 extern void __iomem *mtu_base;
 
-/*
- * The MTU device hosts four different counters, with 4 set of
- * registers. These are register names.
- */
-
-#define MTU_IMSC       0x00    /* Interrupt mask set/clear */
-#define MTU_RIS                0x04    /* Raw interrupt status */
-#define MTU_MIS                0x08    /* Masked interrupt status */
-#define MTU_ICR                0x0C    /* Interrupt clear register */
-
-/* per-timer registers take 0..3 as argument */
-#define MTU_LR(x)      (0x10 + 0x10 * (x) + 0x00)      /* Load value */
-#define MTU_VAL(x)     (0x10 + 0x10 * (x) + 0x04)      /* Current value */
-#define MTU_CR(x)      (0x10 + 0x10 * (x) + 0x08)      /* Control reg */
-#define MTU_BGLR(x)    (0x10 + 0x10 * (x) + 0x0c)      /* At next overflow */
-
-/* bits for the control register */
-#define MTU_CRn_ENA            0x80
-#define MTU_CRn_PERIODIC       0x40    /* if 0 = free-running */
-#define MTU_CRn_PRESCALE_MASK  0x0c
-#define MTU_CRn_PRESCALE_1             0x00
-#define MTU_CRn_PRESCALE_16            0x04
-#define MTU_CRn_PRESCALE_256           0x08
-#define MTU_CRn_32BITS         0x02
-#define MTU_CRn_ONESHOT                0x01    /* if 0 = wraps reloading from BGLR*/
-
-/* Other registers are usual amba/primecell registers, currently not used */
-#define MTU_ITCR       0xff0
-#define MTU_ITOP       0xff4
-
-#define MTU_PERIPH_ID0 0xfe0
-#define MTU_PERIPH_ID1 0xfe4
-#define MTU_PERIPH_ID2 0xfe8
-#define MTU_PERIPH_ID3 0xfeC
-
-#define MTU_PCELL0     0xff0
-#define MTU_PCELL1     0xff4
-#define MTU_PCELL2     0xff8
-#define MTU_PCELL3     0xffC
+void nmdk_clkevt_reset(void);
+void nmdk_clksrc_reset(void);
 
 #endif /* __PLAT_MTU_H */
 
index ef74e15..30b6433 100644 (file)
 #include <asm/mach/time.h>
 #include <asm/sched_clock.h>
 
-#include <plat/mtu.h>
+/*
+ * Guaranteed runtime conversion range in seconds for
+ * the clocksource and clockevent.
+ */
+#define MTU_MIN_RANGE 4
+
+/*
+ * The MTU device hosts four different counters, with 4 set of
+ * registers. These are register names.
+ */
+
+#define MTU_IMSC       0x00    /* Interrupt mask set/clear */
+#define MTU_RIS                0x04    /* Raw interrupt status */
+#define MTU_MIS                0x08    /* Masked interrupt status */
+#define MTU_ICR                0x0C    /* Interrupt clear register */
+
+/* per-timer registers take 0..3 as argument */
+#define MTU_LR(x)      (0x10 + 0x10 * (x) + 0x00)      /* Load value */
+#define MTU_VAL(x)     (0x10 + 0x10 * (x) + 0x04)      /* Current value */
+#define MTU_CR(x)      (0x10 + 0x10 * (x) + 0x08)      /* Control reg */
+#define MTU_BGLR(x)    (0x10 + 0x10 * (x) + 0x0c)      /* At next overflow */
+
+/* bits for the control register */
+#define MTU_CRn_ENA            0x80
+#define MTU_CRn_PERIODIC       0x40    /* if 0 = free-running */
+#define MTU_CRn_PRESCALE_MASK  0x0c
+#define MTU_CRn_PRESCALE_1             0x00
+#define MTU_CRn_PRESCALE_16            0x04
+#define MTU_CRn_PRESCALE_256           0x08
+#define MTU_CRn_32BITS         0x02
+#define MTU_CRn_ONESHOT                0x01    /* if 0 = wraps reloading from BGLR*/
+
+/* Other registers are usual amba/primecell registers, currently not used */
+#define MTU_ITCR       0xff0
+#define MTU_ITOP       0xff4
+
+#define MTU_PERIPH_ID0 0xfe0
+#define MTU_PERIPH_ID1 0xfe4
+#define MTU_PERIPH_ID2 0xfe8
+#define MTU_PERIPH_ID3 0xfeC
+
+#define MTU_PCELL0     0xff0
+#define MTU_PCELL1     0xff4
+#define MTU_PCELL2     0xff8
+#define MTU_PCELL3     0xffC
+
+static bool clkevt_periodic;
+static u32 clk_prescale;
+static u32 nmdk_cycle;         /* write-once */
 
 void __iomem *mtu_base; /* Assigned by machine code */
 
+#ifdef CONFIG_NOMADIK_MTU_SCHED_CLOCK
 /*
  * Override the global weak sched_clock symbol with this
  * local implementation which uses the clocksource to get some
@@ -48,32 +97,56 @@ static void notrace nomadik_update_sched_clock(void)
        u32 cyc = -readl(mtu_base + MTU_VAL(0));
        update_sched_clock(&cd, cyc, (u32)~0);
 }
+#endif
 
 /* Clockevent device: use one-shot mode */
+static int nmdk_clkevt_next(unsigned long evt, struct clock_event_device *ev)
+{
+       writel(1 << 1, mtu_base + MTU_IMSC);
+       writel(evt, mtu_base + MTU_LR(1));
+       /* Load highest value, enable device, enable interrupts */
+       writel(MTU_CRn_ONESHOT | clk_prescale |
+              MTU_CRn_32BITS | MTU_CRn_ENA,
+              mtu_base + MTU_CR(1));
+
+       return 0;
+}
+
+void nmdk_clkevt_reset(void)
+{
+       if (clkevt_periodic) {
+
+               /* Timer: configure load and background-load, and fire it up */
+               writel(nmdk_cycle, mtu_base + MTU_LR(1));
+               writel(nmdk_cycle, mtu_base + MTU_BGLR(1));
+
+               writel(MTU_CRn_PERIODIC | clk_prescale |
+                      MTU_CRn_32BITS | MTU_CRn_ENA,
+                      mtu_base + MTU_CR(1));
+               writel(1 << 1, mtu_base + MTU_IMSC);
+       } else {
+               /* Generate an interrupt to start the clockevent again */
+               (void) nmdk_clkevt_next(nmdk_cycle, NULL);
+       }
+}
+
 static void nmdk_clkevt_mode(enum clock_event_mode mode,
                             struct clock_event_device *dev)
 {
-       u32 cr;
 
        switch (mode) {
        case CLOCK_EVT_MODE_PERIODIC:
-               pr_err("%s: periodic mode not supported\n", __func__);
+               clkevt_periodic = true;
+               nmdk_clkevt_reset();
                break;
        case CLOCK_EVT_MODE_ONESHOT:
-               /* Load highest value, enable device, enable interrupts */
-               cr = readl(mtu_base + MTU_CR(1));
-               writel(0, mtu_base + MTU_LR(1));
-               writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(1));
-               writel(1 << 1, mtu_base + MTU_IMSC);
+               clkevt_periodic = false;
                break;
        case CLOCK_EVT_MODE_SHUTDOWN:
        case CLOCK_EVT_MODE_UNUSED:
-               /* disable irq */
                writel(0, mtu_base + MTU_IMSC);
                /* disable timer */
-               cr = readl(mtu_base + MTU_CR(1));
-               cr &= ~MTU_CRn_ENA;
-               writel(cr, mtu_base + MTU_CR(1));
+               writel(0, mtu_base + MTU_CR(1));
                /* load some high default value */
                writel(0xffffffff, mtu_base + MTU_LR(1));
                break;
@@ -82,16 +155,9 @@ static void nmdk_clkevt_mode(enum clock_event_mode mode,
        }
 }
 
-static int nmdk_clkevt_next(unsigned long evt, struct clock_event_device *ev)
-{
-       /* writing the value has immediate effect */
-       writel(evt, mtu_base + MTU_LR(1));
-       return 0;
-}
-
 static struct clock_event_device nmdk_clkevt = {
        .name           = "mtu_1",
-       .features       = CLOCK_EVT_FEAT_ONESHOT,
+       .features       = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
        .rating         = 200,
        .set_mode       = nmdk_clkevt_mode,
        .set_next_event = nmdk_clkevt_next,
@@ -116,11 +182,23 @@ static struct irqaction nmdk_timer_irq = {
        .dev_id         = &nmdk_clkevt,
 };
 
+void nmdk_clksrc_reset(void)
+{
+       /* Disable */
+       writel(0, mtu_base + MTU_CR(0));
+
+       /* ClockSource: configure load and background-load, and fire it up */
+       writel(nmdk_cycle, mtu_base + MTU_LR(0));
+       writel(nmdk_cycle, mtu_base + MTU_BGLR(0));
+
+       writel(clk_prescale | MTU_CRn_32BITS | MTU_CRn_ENA,
+              mtu_base + MTU_CR(0));
+}
+
 void __init nmdk_timer_init(void)
 {
        unsigned long rate;
        struct clk *clk0;
-       u32 cr = MTU_CRn_32BITS;
 
        clk0 = clk_get_sys("mtu0", NULL);
        BUG_ON(IS_ERR(clk0));
@@ -138,30 +216,28 @@ void __init nmdk_timer_init(void)
        rate = clk_get_rate(clk0);
        if (rate > 32000000) {
                rate /= 16;
-               cr |= MTU_CRn_PRESCALE_16;
+               clk_prescale = MTU_CRn_PRESCALE_16;
        } else {
-               cr |= MTU_CRn_PRESCALE_1;
+               clk_prescale = MTU_CRn_PRESCALE_1;
        }
 
+       nmdk_cycle = (rate + HZ/2) / HZ;
+
+
        /* Timer 0 is the free running clocksource */
-       writel(cr, mtu_base + MTU_CR(0));
-       writel(0, mtu_base + MTU_LR(0));
-       writel(0, mtu_base + MTU_BGLR(0));
-       writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(0));
+       nmdk_clksrc_reset();
 
        if (clocksource_mmio_init(mtu_base + MTU_VAL(0), "mtu_0",
                        rate, 200, 32, clocksource_mmio_readl_down))
                pr_err("timer: failed to initialize clock source %s\n",
                       "mtu_0");
-
+#ifdef CONFIG_NOMADIK_MTU_SCHED_CLOCK
        init_sched_clock(&cd, nomadik_update_sched_clock, 32, rate);
-
+#endif
        /* Timer 1 is used for events */
 
        clockevents_calc_mult_shift(&nmdk_clkevt, rate, MTU_MIN_RANGE);
 
-       writel(cr | MTU_CRn_ONESHOT, mtu_base + MTU_CR(1)); /* off, currently */
-
        nmdk_clkevt.max_delta_ns =
                clockevent_delta2ns(0xffffffff, &nmdk_clkevt);
        nmdk_clkevt.min_delta_ns =
index 75a847d..2def4e1 100644 (file)
@@ -3,6 +3,12 @@
  *
  * OMAP Dual-Mode Timers
  *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ * Tarun Kanti DebBarma <tarun.kanti@ti.com>
+ * Thara Gopinath <thara@ti.com>
+ *
+ * dmtimer adaptation to platform_driver.
+ *
  * Copyright (C) 2005 Nokia Corporation
  * OMAP2 support by Juha Yrjola
  * API improvements and OMAP2 clock framework support by Timo Teras
  * 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-#include <linux/list.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
 #include <linux/io.h>
-#include <linux/module.h>
-#include <mach/hardware.h>
-#include <plat/dmtimer.h>
-#include <mach/irqs.h>
-
-static int dm_timer_count;
-
-#ifdef CONFIG_ARCH_OMAP1
-static struct omap_dm_timer omap1_dm_timers[] = {
-       { .phys_base = 0xfffb1400, .irq = INT_1610_GPTIMER1 },
-       { .phys_base = 0xfffb1c00, .irq = INT_1610_GPTIMER2 },
-       { .phys_base = 0xfffb2400, .irq = INT_1610_GPTIMER3 },
-       { .phys_base = 0xfffb2c00, .irq = INT_1610_GPTIMER4 },
-       { .phys_base = 0xfffb3400, .irq = INT_1610_GPTIMER5 },
-       { .phys_base = 0xfffb3c00, .irq = INT_1610_GPTIMER6 },
-       { .phys_base = 0xfffb7400, .irq = INT_1610_GPTIMER7 },
-       { .phys_base = 0xfffbd400, .irq = INT_1610_GPTIMER8 },
-};
-
-static const int omap1_dm_timer_count = ARRAY_SIZE(omap1_dm_timers);
-
-#else
-#define omap1_dm_timers                        NULL
-#define omap1_dm_timer_count           0
-#endif /* CONFIG_ARCH_OMAP1 */
-
-#ifdef CONFIG_ARCH_OMAP2
-static struct omap_dm_timer omap2_dm_timers[] = {
-       { .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 },
-       { .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 },
-       { .phys_base = 0x48078000, .irq = INT_24XX_GPTIMER3 },
-       { .phys_base = 0x4807a000, .irq = INT_24XX_GPTIMER4 },
-       { .phys_base = 0x4807c000, .irq = INT_24XX_GPTIMER5 },
-       { .phys_base = 0x4807e000, .irq = INT_24XX_GPTIMER6 },
-       { .phys_base = 0x48080000, .irq = INT_24XX_GPTIMER7 },
-       { .phys_base = 0x48082000, .irq = INT_24XX_GPTIMER8 },
-       { .phys_base = 0x48084000, .irq = INT_24XX_GPTIMER9 },
-       { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
-       { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
-       { .phys_base = 0x4808a000, .irq = INT_24XX_GPTIMER12 },
-};
-
-static const char *omap2_dm_source_names[] __initdata = {
-       "sys_ck",
-       "func_32k_ck",
-       "alt_ck",
-       NULL
-};
-
-static struct clk *omap2_dm_source_clocks[3];
-static const int omap2_dm_timer_count = ARRAY_SIZE(omap2_dm_timers);
-
-#else
-#define omap2_dm_timers                        NULL
-#define omap2_dm_timer_count           0
-#define omap2_dm_source_names          NULL
-#define omap2_dm_source_clocks         NULL
-#endif /* CONFIG_ARCH_OMAP2 */
-
-#ifdef CONFIG_ARCH_OMAP3
-static struct omap_dm_timer omap3_dm_timers[] = {
-       { .phys_base = 0x48318000, .irq = INT_24XX_GPTIMER1 },
-       { .phys_base = 0x49032000, .irq = INT_24XX_GPTIMER2 },
-       { .phys_base = 0x49034000, .irq = INT_24XX_GPTIMER3 },
-       { .phys_base = 0x49036000, .irq = INT_24XX_GPTIMER4 },
-       { .phys_base = 0x49038000, .irq = INT_24XX_GPTIMER5 },
-       { .phys_base = 0x4903A000, .irq = INT_24XX_GPTIMER6 },
-       { .phys_base = 0x4903C000, .irq = INT_24XX_GPTIMER7 },
-       { .phys_base = 0x4903E000, .irq = INT_24XX_GPTIMER8 },
-       { .phys_base = 0x49040000, .irq = INT_24XX_GPTIMER9 },
-       { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
-       { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
-       { .phys_base = 0x48304000, .irq = INT_34XX_GPT12_IRQ },
-};
-
-static const char *omap3_dm_source_names[] __initdata = {
-       "sys_ck",
-       "omap_32k_fck",
-       NULL
-};
-
-static struct clk *omap3_dm_source_clocks[2];
-static const int omap3_dm_timer_count = ARRAY_SIZE(omap3_dm_timers);
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/pm_runtime.h>
 
-#else
-#define omap3_dm_timers                        NULL
-#define omap3_dm_timer_count           0
-#define omap3_dm_source_names          NULL
-#define omap3_dm_source_clocks         NULL
-#endif /* CONFIG_ARCH_OMAP3 */
-
-#ifdef CONFIG_ARCH_OMAP4
-static struct omap_dm_timer omap4_dm_timers[] = {
-       { .phys_base = 0x4a318000, .irq = OMAP44XX_IRQ_GPT1 },
-       { .phys_base = 0x48032000, .irq = OMAP44XX_IRQ_GPT2 },
-       { .phys_base = 0x48034000, .irq = OMAP44XX_IRQ_GPT3 },
-       { .phys_base = 0x48036000, .irq = OMAP44XX_IRQ_GPT4 },
-       { .phys_base = 0x40138000, .irq = OMAP44XX_IRQ_GPT5 },
-       { .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT6 },
-       { .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT7 },
-       { .phys_base = 0x4013e000, .irq = OMAP44XX_IRQ_GPT8 },
-       { .phys_base = 0x4803e000, .irq = OMAP44XX_IRQ_GPT9 },
-       { .phys_base = 0x48086000, .irq = OMAP44XX_IRQ_GPT10 },
-       { .phys_base = 0x48088000, .irq = OMAP44XX_IRQ_GPT11 },
-       { .phys_base = 0x4a320000, .irq = OMAP44XX_IRQ_GPT12 },
-};
-static const char *omap4_dm_source_names[] __initdata = {
-       "sys_clkin_ck",
-       "sys_32k_ck",
-       NULL
-};
-static struct clk *omap4_dm_source_clocks[2];
-static const int omap4_dm_timer_count = ARRAY_SIZE(omap4_dm_timers);
-
-#else
-#define omap4_dm_timers                        NULL
-#define omap4_dm_timer_count           0
-#define omap4_dm_source_names          NULL
-#define omap4_dm_source_clocks         NULL
-#endif /* CONFIG_ARCH_OMAP4 */
-
-static struct omap_dm_timer *dm_timers;
-static const char **dm_source_names;
-static struct clk **dm_source_clocks;
+#include <plat/dmtimer.h>
 
-static spinlock_t dm_timer_lock;
+static LIST_HEAD(omap_timer_list);
+static DEFINE_SPINLOCK(dm_timer_lock);
 
-/*
- * Reads timer registers in posted and non-posted mode. The posted mode bit
- * is encoded in reg. Note that in posted mode write pending bit must be
- * checked. Otherwise a read of a non completed write will produce an error.
+/**
+ * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode
+ * @timer:      timer pointer over which read operation to perform
+ * @reg:        lowest byte holds the register offset
+ *
+ * The posted mode bit is encoded in reg. Note that in posted mode write
+ * pending bit must be checked. Otherwise a read of a non completed write
+ * will produce an error.
  */
 static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
 {
-       return __omap_dm_timer_read(timer->io_base, reg, timer->posted);
+       WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
+       return __omap_dm_timer_read(timer, reg, timer->posted);
 }
 
-/*
- * Writes timer registers in posted and non-posted mode. The posted mode bit
- * is encoded in reg. Note that in posted mode the write pending bit must be
- * checked. Otherwise a write on a register which has a pending write will be
- * lost.
+/**
+ * omap_dm_timer_write_reg - write timer registers in posted and non-posted mode
+ * @timer:      timer pointer over which write operation is to perform
+ * @reg:        lowest byte holds the register offset
+ * @value:      data to write into the register
+ *
+ * The posted mode bit is encoded in reg. Note that in posted mode the write
+ * pending bit must be checked. Otherwise a write on a register which has a
+ * pending write will be lost.
  */
 static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
                                                u32 value)
 {
-       __omap_dm_timer_write(timer->io_base, reg, value, timer->posted);
+       WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
+       __omap_dm_timer_write(timer, reg, value, timer->posted);
+}
+
+static void omap_timer_restore_context(struct omap_dm_timer *timer)
+{
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_OFFSET,
+                               timer->context.tiocp_cfg);
+       if (timer->revision > 1)
+               __raw_writel(timer->context.tistat, timer->sys_stat);
+
+       __raw_writel(timer->context.tisr, timer->irq_stat);
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
+                               timer->context.twer);
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
+                               timer->context.tcrr);
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG,
+                               timer->context.tldr);
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG,
+                               timer->context.tmar);
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
+                               timer->context.tsicr);
+       __raw_writel(timer->context.tier, timer->irq_ena);
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG,
+                               timer->context.tclr);
 }
 
 static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
 {
        int c;
 
+       if (!timer->sys_stat)
+               return;
+
        c = 0;
-       while (!(omap_dm_timer_read_reg(timer, OMAP_TIMER_SYS_STAT_REG) & 1)) {
+       while (!(__raw_readl(timer->sys_stat) & 1)) {
                c++;
                if (c > 100000) {
                        printk(KERN_ERR "Timer failed to reset\n");
@@ -201,53 +119,65 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
 
 static void omap_dm_timer_reset(struct omap_dm_timer *timer)
 {
-       int autoidle = 0, wakeup = 0;
-
-       if (!cpu_class_is_omap2() || timer != &dm_timers[0]) {
+       omap_dm_timer_enable(timer);
+       if (timer->pdev->id != 1) {
                omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
                omap_dm_timer_wait_for_reset(timer);
        }
-       omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
-
-       /* Enable autoidle on OMAP2+ */
-       if (cpu_class_is_omap2())
-               autoidle = 1;
-
-       /*
-        * Enable wake-up on OMAP2 CPUs.
-        */
-       if (cpu_class_is_omap2())
-               wakeup = 1;
 
-       __omap_dm_timer_reset(timer->io_base, autoidle, wakeup);
+       __omap_dm_timer_reset(timer, 0, 0);
+       omap_dm_timer_disable(timer);
        timer->posted = 1;
 }
 
-void omap_dm_timer_prepare(struct omap_dm_timer *timer)
+int omap_dm_timer_prepare(struct omap_dm_timer *timer)
 {
-       omap_dm_timer_enable(timer);
-       omap_dm_timer_reset(timer);
+       struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
+       int ret;
+
+       timer->fclk = clk_get(&timer->pdev->dev, "fck");
+       if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) {
+               timer->fclk = NULL;
+               dev_err(&timer->pdev->dev, ": No fclk handle.\n");
+               return -EINVAL;
+       }
+
+       if (pdata->needs_manual_reset)
+               omap_dm_timer_reset(timer);
+
+       ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
+
+       timer->posted = 1;
+       return ret;
 }
 
 struct omap_dm_timer *omap_dm_timer_request(void)
 {
-       struct omap_dm_timer *timer = NULL;
+       struct omap_dm_timer *timer = NULL, *t;
        unsigned long flags;
-       int i;
+       int ret = 0;
 
        spin_lock_irqsave(&dm_timer_lock, flags);
-       for (i = 0; i < dm_timer_count; i++) {
-               if (dm_timers[i].reserved)
+       list_for_each_entry(t, &omap_timer_list, node) {
+               if (t->reserved)
                        continue;
 
-               timer = &dm_timers[i];
+               timer = t;
                timer->reserved = 1;
                break;
        }
+
+       if (timer) {
+               ret = omap_dm_timer_prepare(timer);
+               if (ret) {
+                       timer->reserved = 0;
+                       timer = NULL;
+               }
+       }
        spin_unlock_irqrestore(&dm_timer_lock, flags);
 
-       if (timer != NULL)
-               omap_dm_timer_prepare(timer);
+       if (!timer)
+               pr_debug("%s: timer request failed!\n", __func__);
 
        return timer;
 }
@@ -255,74 +185,65 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request);
 
 struct omap_dm_timer *omap_dm_timer_request_specific(int id)
 {
-       struct omap_dm_timer *timer;
+       struct omap_dm_timer *timer = NULL, *t;
        unsigned long flags;
+       int ret = 0;
 
        spin_lock_irqsave(&dm_timer_lock, flags);
-       if (id <= 0 || id > dm_timer_count || dm_timers[id-1].reserved) {
-               spin_unlock_irqrestore(&dm_timer_lock, flags);
-               printk("BUG: warning at %s:%d/%s(): unable to get timer %d\n",
-                      __FILE__, __LINE__, __func__, id);
-               dump_stack();
-               return NULL;
+       list_for_each_entry(t, &omap_timer_list, node) {
+               if (t->pdev->id == id && !t->reserved) {
+                       timer = t;
+                       timer->reserved = 1;
+                       break;
+               }
        }
 
-       timer = &dm_timers[id-1];
-       timer->reserved = 1;
+       if (timer) {
+               ret = omap_dm_timer_prepare(timer);
+               if (ret) {
+                       timer->reserved = 0;
+                       timer = NULL;
+               }
+       }
        spin_unlock_irqrestore(&dm_timer_lock, flags);
 
-       omap_dm_timer_prepare(timer);
+       if (!timer)
+               pr_debug("%s: timer%d request failed!\n", __func__, id);
 
        return timer;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
 
-void omap_dm_timer_free(struct omap_dm_timer *timer)
+int omap_dm_timer_free(struct omap_dm_timer *timer)
 {
-       omap_dm_timer_enable(timer);
-       omap_dm_timer_reset(timer);
-       omap_dm_timer_disable(timer);
+       if (unlikely(!timer))
+               return -EINVAL;
+
+       clk_put(timer->fclk);
 
        WARN_ON(!timer->reserved);
        timer->reserved = 0;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_free);
 
 void omap_dm_timer_enable(struct omap_dm_timer *timer)
 {
-       if (timer->enabled)
-               return;
-
-#ifdef CONFIG_ARCH_OMAP2PLUS
-       if (cpu_class_is_omap2()) {
-               clk_enable(timer->fclk);
-               clk_enable(timer->iclk);
-       }
-#endif
-
-       timer->enabled = 1;
+       pm_runtime_get_sync(&timer->pdev->dev);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
 
 void omap_dm_timer_disable(struct omap_dm_timer *timer)
 {
-       if (!timer->enabled)
-               return;
-
-#ifdef CONFIG_ARCH_OMAP2PLUS
-       if (cpu_class_is_omap2()) {
-               clk_disable(timer->iclk);
-               clk_disable(timer->fclk);
-       }
-#endif
-
-       timer->enabled = 0;
+       pm_runtime_put(&timer->pdev->dev);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
 
 int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
 {
-       return timer->irq;
+       if (timer)
+               return timer->irq;
+       return -EINVAL;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
 
@@ -334,24 +255,29 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
  */
 __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
 {
-       int i;
+       int i = 0;
+       struct omap_dm_timer *timer = NULL;
+       unsigned long flags;
 
        /* If ARMXOR cannot be idled this function call is unnecessary */
        if (!(inputmask & (1 << 1)))
                return inputmask;
 
        /* If any active timer is using ARMXOR return modified mask */
-       for (i = 0; i < dm_timer_count; i++) {
+       spin_lock_irqsave(&dm_timer_lock, flags);
+       list_for_each_entry(timer, &omap_timer_list, node) {
                u32 l;
 
-               l = omap_dm_timer_read_reg(&dm_timers[i], OMAP_TIMER_CTRL_REG);
+               l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
                if (l & OMAP_TIMER_CTRL_ST) {
                        if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
                                inputmask &= ~(1 << 1);
                        else
                                inputmask &= ~(1 << 2);
                }
+               i++;
        }
+       spin_unlock_irqrestore(&dm_timer_lock, flags);
 
        return inputmask;
 }
@@ -361,7 +287,9 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
 
 struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
 {
-       return timer->fclk;
+       if (timer)
+               return timer->fclk;
+       return NULL;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk);
 
@@ -375,70 +303,91 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
 
 #endif
 
-void omap_dm_timer_trigger(struct omap_dm_timer *timer)
+int omap_dm_timer_trigger(struct omap_dm_timer *timer)
 {
+       if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
+               pr_err("%s: timer not available or enabled.\n", __func__);
+               return -EINVAL;
+       }
+
        omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
 
-void omap_dm_timer_start(struct omap_dm_timer *timer)
+int omap_dm_timer_start(struct omap_dm_timer *timer)
 {
        u32 l;
 
+       if (unlikely(!timer))
+               return -EINVAL;
+
+       omap_dm_timer_enable(timer);
+
+       if (timer->loses_context) {
+               u32 ctx_loss_cnt_after =
+                       timer->get_context_loss_count(&timer->pdev->dev);
+               if (ctx_loss_cnt_after != timer->ctx_loss_count)
+                       omap_timer_restore_context(timer);
+       }
+
        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
        if (!(l & OMAP_TIMER_CTRL_ST)) {
                l |= OMAP_TIMER_CTRL_ST;
                omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
        }
+
+       /* Save the context */
+       timer->context.tclr = l;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_start);
 
-void omap_dm_timer_stop(struct omap_dm_timer *timer)
+int omap_dm_timer_stop(struct omap_dm_timer *timer)
 {
        unsigned long rate = 0;
+       struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
-       rate = clk_get_rate(timer->fclk);
-#endif
+       if (unlikely(!timer))
+               return -EINVAL;
 
-       __omap_dm_timer_stop(timer->io_base, timer->posted, rate);
+       if (!pdata->needs_manual_reset)
+               rate = clk_get_rate(timer->fclk);
+
+       __omap_dm_timer_stop(timer, timer->posted, rate);
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
 
-#ifdef CONFIG_ARCH_OMAP1
-
 int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
 {
-       int n = (timer - dm_timers) << 1;
-       u32 l;
-
-       l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n);
-       l |= source << n;
-       omap_writel(l, MOD_CONF_CTRL_1);
+       int ret;
+       struct dmtimer_platform_data *pdata;
 
-       return 0;
-}
-EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
+       if (unlikely(!timer))
+               return -EINVAL;
 
-#else
+       pdata = timer->pdev->dev.platform_data;
 
-int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
-{
        if (source < 0 || source >= 3)
                return -EINVAL;
 
-       return __omap_dm_timer_set_source(timer->fclk,
-                                               dm_source_clocks[source]);
+       ret = pdata->set_timer_src(timer->pdev, source);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
 
-#endif
-
-void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
+int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
                            unsigned int load)
 {
        u32 l;
 
+       if (unlikely(!timer))
+               return -EINVAL;
+
+       omap_dm_timer_enable(timer);
        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
        if (autoreload)
                l |= OMAP_TIMER_CTRL_AR;
@@ -448,15 +397,32 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
        omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
 
        omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
+       /* Save the context */
+       timer->context.tclr = l;
+       timer->context.tldr = load;
+       omap_dm_timer_disable(timer);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
 
 /* Optimized set_load which removes costly spin wait in timer_start */
-void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
+int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
                             unsigned int load)
 {
        u32 l;
 
+       if (unlikely(!timer))
+               return -EINVAL;
+
+       omap_dm_timer_enable(timer);
+
+       if (timer->loses_context) {
+               u32 ctx_loss_cnt_after =
+                       timer->get_context_loss_count(&timer->pdev->dev);
+               if (ctx_loss_cnt_after != timer->ctx_loss_count)
+                       omap_timer_restore_context(timer);
+       }
+
        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
        if (autoreload) {
                l |= OMAP_TIMER_CTRL_AR;
@@ -466,15 +432,25 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
        }
        l |= OMAP_TIMER_CTRL_ST;
 
-       __omap_dm_timer_load_start(timer->io_base, l, load, timer->posted);
+       __omap_dm_timer_load_start(timer, l, load, timer->posted);
+
+       /* Save the context */
+       timer->context.tclr = l;
+       timer->context.tldr = load;
+       timer->context.tcrr = load;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
 
-void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
+int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
                             unsigned int match)
 {
        u32 l;
 
+       if (unlikely(!timer))
+               return -EINVAL;
+
+       omap_dm_timer_enable(timer);
        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
        if (enable)
                l |= OMAP_TIMER_CTRL_CE;
@@ -482,14 +458,24 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
                l &= ~OMAP_TIMER_CTRL_CE;
        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
        omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
+
+       /* Save the context */
+       timer->context.tclr = l;
+       timer->context.tmar = match;
+       omap_dm_timer_disable(timer);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
 
-void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
+int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
                           int toggle, int trigger)
 {
        u32 l;
 
+       if (unlikely(!timer))
+               return -EINVAL;
+
+       omap_dm_timer_enable(timer);
        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
        l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
               OMAP_TIMER_CTRL_PT | (0x03 << 10));
@@ -499,13 +485,22 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
                l |= OMAP_TIMER_CTRL_PT;
        l |= trigger << 10;
        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+
+       /* Save the context */
+       timer->context.tclr = l;
+       omap_dm_timer_disable(timer);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
 
-void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
+int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
 {
        u32 l;
 
+       if (unlikely(!timer))
+               return -EINVAL;
+
+       omap_dm_timer_enable(timer);
        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
        l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
        if (prescaler >= 0x00 && prescaler <= 0x07) {
@@ -513,13 +508,28 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
                l |= prescaler << 2;
        }
        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+
+       /* Save the context */
+       timer->context.tclr = l;
+       omap_dm_timer_disable(timer);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
 
-void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
+int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
                                  unsigned int value)
 {
-       __omap_dm_timer_int_enable(timer->io_base, value);
+       if (unlikely(!timer))
+               return -EINVAL;
+
+       omap_dm_timer_enable(timer);
+       __omap_dm_timer_int_enable(timer, value);
+
+       /* Save the context */
+       timer->context.tier = value;
+       timer->context.twer = value;
+       omap_dm_timer_disable(timer);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
 
@@ -527,40 +537,61 @@ unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
 {
        unsigned int l;
 
-       l = omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
+       if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
+               pr_err("%s: timer not available or enabled.\n", __func__);
+               return 0;
+       }
+
+       l = __raw_readl(timer->irq_stat);
 
        return l;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
 
-void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
+int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
 {
-       __omap_dm_timer_write_status(timer->io_base, value);
+       if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev)))
+               return -EINVAL;
+
+       __omap_dm_timer_write_status(timer, value);
+       /* Save the context */
+       timer->context.tisr = value;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
 
 unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
 {
-       return __omap_dm_timer_read_counter(timer->io_base, timer->posted);
+       if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
+               pr_err("%s: timer not iavailable or enabled.\n", __func__);
+               return 0;
+       }
+
+       return __omap_dm_timer_read_counter(timer, timer->posted);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
 
-void omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
+int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
 {
+       if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
+               pr_err("%s: timer not available or enabled.\n", __func__);
+               return -EINVAL;
+       }
+
        omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
+
+       /* Save the context */
+       timer->context.tcrr = value;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
 
 int omap_dm_timers_active(void)
 {
-       int i;
-
-       for (i = 0; i < dm_timer_count; i++) {
-               struct omap_dm_timer *timer;
-
-               timer = &dm_timers[i];
+       struct omap_dm_timer *timer;
 
-               if (!timer->enabled)
+       list_for_each_entry(timer, &omap_timer_list, node) {
+               if (!timer->reserved)
                        continue;
 
                if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
@@ -572,69 +603,147 @@ int omap_dm_timers_active(void)
 }
 EXPORT_SYMBOL_GPL(omap_dm_timers_active);
 
-static int __init omap_dm_timer_init(void)
+/**
+ * omap_dm_timer_probe - probe function called for every registered device
+ * @pdev:      pointer to current timer platform device
+ *
+ * Called by driver framework at the end of device registration for all
+ * timer devices.
+ */
+static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
 {
+       int ret;
+       unsigned long flags;
        struct omap_dm_timer *timer;
-       int i, map_size = SZ_8K;        /* Module 4KB + L4 4KB except on omap1 */
+       struct resource *mem, *irq, *ioarea;
+       struct dmtimer_platform_data *pdata = pdev->dev.platform_data;
 
-       if (!(cpu_is_omap16xx() || cpu_class_is_omap2()))
+       if (!pdata) {
+               dev_err(&pdev->dev, "%s: no platform data.\n", __func__);
                return -ENODEV;
+       }
 
-       spin_lock_init(&dm_timer_lock);
-
-       if (cpu_class_is_omap1()) {
-               dm_timers = omap1_dm_timers;
-               dm_timer_count = omap1_dm_timer_count;
-               map_size = SZ_2K;
-       } else if (cpu_is_omap24xx()) {
-               dm_timers = omap2_dm_timers;
-               dm_timer_count = omap2_dm_timer_count;
-               dm_source_names = omap2_dm_source_names;
-               dm_source_clocks = omap2_dm_source_clocks;
-       } else if (cpu_is_omap34xx()) {
-               dm_timers = omap3_dm_timers;
-               dm_timer_count = omap3_dm_timer_count;
-               dm_source_names = omap3_dm_source_names;
-               dm_source_clocks = omap3_dm_source_clocks;
-       } else if (cpu_is_omap44xx()) {
-               dm_timers = omap4_dm_timers;
-               dm_timer_count = omap4_dm_timer_count;
-               dm_source_names = omap4_dm_source_names;
-               dm_source_clocks = omap4_dm_source_clocks;
+       irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (unlikely(!irq)) {
+               dev_err(&pdev->dev, "%s: no IRQ resource.\n", __func__);
+               return -ENODEV;
        }
 
-       if (cpu_class_is_omap2())
-               for (i = 0; dm_source_names[i] != NULL; i++)
-                       dm_source_clocks[i] = clk_get(NULL, dm_source_names[i]);
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (unlikely(!mem)) {
+               dev_err(&pdev->dev, "%s: no memory resource.\n", __func__);
+               return -ENODEV;
+       }
 
-       if (cpu_is_omap243x())
-               dm_timers[0].phys_base = 0x49018000;
+       ioarea = request_mem_region(mem->start, resource_size(mem),
+                       pdev->name);
+       if (!ioarea) {
+               dev_err(&pdev->dev, "%s: region already claimed.\n", __func__);
+               return -EBUSY;
+       }
 
-       for (i = 0; i < dm_timer_count; i++) {
-               timer = &dm_timers[i];
+       timer = kzalloc(sizeof(struct omap_dm_timer), GFP_KERNEL);
+       if (!timer) {
+               dev_err(&pdev->dev, "%s: no memory for omap_dm_timer.\n",
+                       __func__);
+               ret = -ENOMEM;
+               goto err_free_ioregion;
+       }
 
-               /* Static mapping, never released */
-               timer->io_base = ioremap(timer->phys_base, map_size);
-               BUG_ON(!timer->io_base);
+       timer->io_base = ioremap(mem->start, resource_size(mem));
+       if (!timer->io_base) {
+               dev_err(&pdev->dev, "%s: ioremap failed.\n", __func__);
+               ret = -ENOMEM;
+               goto err_free_mem;
+       }
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
-               if (cpu_class_is_omap2()) {
-                       char clk_name[16];
-                       sprintf(clk_name, "gpt%d_ick", i + 1);
-                       timer->iclk = clk_get(NULL, clk_name);
-                       sprintf(clk_name, "gpt%d_fck", i + 1);
-                       timer->fclk = clk_get(NULL, clk_name);
-               }
+       timer->id = pdev->id;
+       timer->irq = irq->start;
+       timer->reserved = pdata->reserved;
+       timer->pdev = pdev;
+       timer->loses_context = pdata->loses_context;
+       timer->get_context_loss_count = pdata->get_context_loss_count;
+
+       /* Skip pm_runtime_enable for OMAP1 */
+       if (!pdata->needs_manual_reset) {
+               pm_runtime_enable(&pdev->dev);
+               pm_runtime_irq_safe(&pdev->dev);
+       }
 
-               /* One or two timers may be set up early for sys_timer */
-               if (sys_timer_reserved & (1  << i)) {
-                       timer->reserved = 1;
-                       timer->posted = 1;
-               }
-#endif
+       if (!timer->reserved) {
+               pm_runtime_get_sync(&pdev->dev);
+               __omap_dm_timer_init_regs(timer);
+               pm_runtime_put(&pdev->dev);
        }
 
+       /* add the timer element to the list */
+       spin_lock_irqsave(&dm_timer_lock, flags);
+       list_add_tail(&timer->node, &omap_timer_list);
+       spin_unlock_irqrestore(&dm_timer_lock, flags);
+
+       dev_dbg(&pdev->dev, "Device Probed.\n");
+
        return 0;
+
+err_free_mem:
+       kfree(timer);
+
+err_free_ioregion:
+       release_mem_region(mem->start, resource_size(mem));
+
+       return ret;
 }
 
-arch_initcall(omap_dm_timer_init);
+/**
+ * omap_dm_timer_remove - cleanup a registered timer device
+ * @pdev:      pointer to current timer platform device
+ *
+ * Called by driver framework whenever a timer device is unregistered.
+ * In addition to freeing platform resources it also deletes the timer
+ * entry from the local list.
+ */
+static int __devexit omap_dm_timer_remove(struct platform_device *pdev)
+{
+       struct omap_dm_timer *timer;
+       unsigned long flags;
+       int ret = -EINVAL;
+
+       spin_lock_irqsave(&dm_timer_lock, flags);
+       list_for_each_entry(timer, &omap_timer_list, node)
+               if (timer->pdev->id == pdev->id) {
+                       list_del(&timer->node);
+                       kfree(timer);
+                       ret = 0;
+                       break;
+               }
+       spin_unlock_irqrestore(&dm_timer_lock, flags);
+
+       return ret;
+}
+
+static struct platform_driver omap_dm_timer_driver = {
+       .probe  = omap_dm_timer_probe,
+       .remove = __devexit_p(omap_dm_timer_remove),
+       .driver = {
+               .name   = "omap_timer",
+       },
+};
+
+static int __init omap_dm_timer_driver_init(void)
+{
+       return platform_driver_register(&omap_dm_timer_driver);
+}
+
+static void __exit omap_dm_timer_driver_exit(void)
+{
+       platform_driver_unregister(&omap_dm_timer_driver);
+}
+
+early_platform_init("earlytimer", &omap_dm_timer_driver);
+module_init(omap_dm_timer_driver_init);
+module_exit(omap_dm_timer_driver_exit);
+
+MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_AUTHOR("Texas Instruments Inc");
index eb5d16c..d11025e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/arm/plat-omap/include/mach/dmtimer.h
+ * arch/arm/plat-omap/include/plat/dmtimer.h
  *
  * OMAP Dual-Mode Timers
  *
@@ -35,6 +35,7 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/io.h>
+#include <linux/platform_device.h>
 
 #ifndef __ASM_ARCH_DMTIMER_H
 #define __ASM_ARCH_DMTIMER_H
  * in OMAP4 can be distinguished.
  */
 #define OMAP_TIMER_IP_VERSION_1                        0x1
+
+/* timer capabilities used in hwmod database */
+#define OMAP_TIMER_SECURE                              0x80000000
+#define OMAP_TIMER_ALWON                               0x40000000
+#define OMAP_TIMER_HAS_PWM                             0x20000000
+
+struct omap_timer_capability_dev_attr {
+       u32 timer_capability;
+};
+
 struct omap_dm_timer;
 struct clk;
 
+struct timer_regs {
+       u32 tidr;
+       u32 tiocp_cfg;
+       u32 tistat;
+       u32 tisr;
+       u32 tier;
+       u32 twer;
+       u32 tclr;
+       u32 tcrr;
+       u32 tldr;
+       u32 ttrg;
+       u32 twps;
+       u32 tmar;
+       u32 tcar1;
+       u32 tsicr;
+       u32 tcar2;
+       u32 tpir;
+       u32 tnir;
+       u32 tcvr;
+       u32 tocr;
+       u32 towr;
+};
+
+struct dmtimer_platform_data {
+       int (*set_timer_src)(struct platform_device *pdev, int source);
+       int timer_ip_version;
+       u32 needs_manual_reset:1;
+       bool reserved;
+
+       bool loses_context;
+
+       u32 (*get_context_loss_count)(struct device *dev);
+};
+
 struct omap_dm_timer *omap_dm_timer_request(void);
 struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id);
-void omap_dm_timer_free(struct omap_dm_timer *timer);
+int omap_dm_timer_free(struct omap_dm_timer *timer);
 void omap_dm_timer_enable(struct omap_dm_timer *timer);
 void omap_dm_timer_disable(struct omap_dm_timer *timer);
 
@@ -73,23 +118,23 @@ int omap_dm_timer_get_irq(struct omap_dm_timer *timer);
 u32 omap_dm_timer_modify_idlect_mask(u32 inputmask);
 struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer);
 
-void omap_dm_timer_trigger(struct omap_dm_timer *timer);
-void omap_dm_timer_start(struct omap_dm_timer *timer);
-void omap_dm_timer_stop(struct omap_dm_timer *timer);
+int omap_dm_timer_trigger(struct omap_dm_timer *timer);
+int omap_dm_timer_start(struct omap_dm_timer *timer);
+int omap_dm_timer_stop(struct omap_dm_timer *timer);
 
 int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source);
-void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, unsigned int value);
-void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, unsigned int value);
-void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, unsigned int match);
-void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, int toggle, int trigger);
-void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler);
+int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, unsigned int value);
+int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, unsigned int value);
+int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, unsigned int match);
+int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, int toggle, int trigger);
+int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler);
 
-void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value);
+int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value);
 
 unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer);
-void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value);
+int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value);
 unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer);
-void omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value);
+int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value);
 
 int omap_dm_timers_active(void);
 
@@ -98,12 +143,30 @@ int omap_dm_timers_active(void);
  * used by dmtimer.c and sys_timer related code.
  */
 
-/* register offsets */
-#define _OMAP_TIMER_ID_OFFSET          0x00
-#define _OMAP_TIMER_OCP_CFG_OFFSET     0x10
-#define _OMAP_TIMER_SYS_STAT_OFFSET    0x14
-#define _OMAP_TIMER_STAT_OFFSET                0x18
-#define _OMAP_TIMER_INT_EN_OFFSET      0x1c
+/*
+ * The interrupt registers are different between v1 and v2 ip.
+ * These registers are offsets from timer->iobase.
+ */
+#define OMAP_TIMER_ID_OFFSET           0x00
+#define OMAP_TIMER_OCP_CFG_OFFSET      0x10
+
+#define OMAP_TIMER_V1_SYS_STAT_OFFSET  0x14
+#define OMAP_TIMER_V1_STAT_OFFSET      0x18
+#define OMAP_TIMER_V1_INT_EN_OFFSET    0x1c
+
+#define OMAP_TIMER_V2_IRQSTATUS_RAW    0x24
+#define OMAP_TIMER_V2_IRQSTATUS                0x28
+#define OMAP_TIMER_V2_IRQENABLE_SET    0x2c
+#define OMAP_TIMER_V2_IRQENABLE_CLR    0x30
+
+/*
+ * The functional registers have a different base on v1 and v2 ip.
+ * These registers are offsets from timer->func_base. The func_base
+ * is samae as io_base for v1 and io_base + 0x14 for v2 ip.
+ *
+ */
+#define OMAP_TIMER_V2_FUNC_OFFSET              0x14
+
 #define _OMAP_TIMER_WAKEUP_EN_OFFSET   0x20
 #define _OMAP_TIMER_CTRL_OFFSET                0x24
 #define                OMAP_TIMER_CTRL_GPOCFG          (1 << 14)
@@ -147,21 +210,6 @@ int omap_dm_timers_active(void);
 /* register offsets with the write pending bit encoded */
 #define        WPSHIFT                                 16
 
-#define OMAP_TIMER_ID_REG                      (_OMAP_TIMER_ID_OFFSET \
-                                                       | (WP_NONE << WPSHIFT))
-
-#define OMAP_TIMER_OCP_CFG_REG                 (_OMAP_TIMER_OCP_CFG_OFFSET \
-                                                       | (WP_NONE << WPSHIFT))
-
-#define OMAP_TIMER_SYS_STAT_REG                        (_OMAP_TIMER_SYS_STAT_OFFSET \
-                                                       | (WP_NONE << WPSHIFT))
-
-#define OMAP_TIMER_STAT_REG                    (_OMAP_TIMER_STAT_OFFSET \
-                                                       | (WP_NONE << WPSHIFT))
-
-#define OMAP_TIMER_INT_EN_REG                  (_OMAP_TIMER_INT_EN_OFFSET \
-                                                       | (WP_NONE << WPSHIFT))
-
 #define OMAP_TIMER_WAKEUP_EN_REG               (_OMAP_TIMER_WAKEUP_EN_OFFSET \
                                                        | (WP_NONE << WPSHIFT))
 
@@ -209,49 +257,88 @@ int omap_dm_timers_active(void);
 
 struct omap_dm_timer {
        unsigned long phys_base;
+       int id;
        int irq;
-#ifdef CONFIG_ARCH_OMAP2PLUS
        struct clk *iclk, *fclk;
-#endif
-       void __iomem *io_base;
+
+       void __iomem    *io_base;
+       void __iomem    *sys_stat;      /* TISTAT timer status */
+       void __iomem    *irq_stat;      /* TISR/IRQSTATUS interrupt status */
+       void __iomem    *irq_ena;       /* irq enable */
+       void __iomem    *irq_dis;       /* irq disable, only on v2 ip */
+       void __iomem    *pend;          /* write pending */
+       void __iomem    *func_base;     /* function register base */
+
        unsigned long rate;
        unsigned reserved:1;
-       unsigned enabled:1;
        unsigned posted:1;
+       struct timer_regs context;
+       bool loses_context;
+       int ctx_loss_count;
+       int revision;
+       struct platform_device *pdev;
+       struct list_head node;
+
+       u32 (*get_context_loss_count)(struct device *dev);
 };
 
-extern u32 sys_timer_reserved;
-void omap_dm_timer_prepare(struct omap_dm_timer *timer);
+int omap_dm_timer_prepare(struct omap_dm_timer *timer);
 
-static inline u32 __omap_dm_timer_read(void __iomem *base, u32 reg,
+static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
                                                int posted)
 {
        if (posted)
-               while (__raw_readl(base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))
-                               & (reg >> WPSHIFT))
+               while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
                        cpu_relax();
 
-       return __raw_readl(base + (reg & 0xff));
+       return __raw_readl(timer->func_base + (reg & 0xff));
 }
 
-static inline void __omap_dm_timer_write(void __iomem *base, u32 reg, u32 val,
-                                               int posted)
+static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
+                                       u32 reg, u32 val, int posted)
 {
        if (posted)
-               while (__raw_readl(base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))
-                               & (reg >> WPSHIFT))
+               while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
                        cpu_relax();
 
-       __raw_writel(val, base + (reg & 0xff));
+       __raw_writel(val, timer->func_base + (reg & 0xff));
+}
+
+static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
+{
+       u32 tidr;
+
+       /* Assume v1 ip if bits [31:16] are zero */
+       tidr = __raw_readl(timer->io_base);
+       if (!(tidr >> 16)) {
+               timer->revision = 1;
+               timer->sys_stat = timer->io_base +
+                               OMAP_TIMER_V1_SYS_STAT_OFFSET;
+               timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET;
+               timer->irq_ena = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET;
+               timer->irq_dis = 0;
+               timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET;
+               timer->func_base = timer->io_base;
+       } else {
+               timer->revision = 2;
+               timer->sys_stat = 0;
+               timer->irq_stat = timer->io_base + OMAP_TIMER_V2_IRQSTATUS;
+               timer->irq_ena = timer->io_base + OMAP_TIMER_V2_IRQENABLE_SET;
+               timer->irq_dis = timer->io_base + OMAP_TIMER_V2_IRQENABLE_CLR;
+               timer->pend = timer->io_base +
+                       _OMAP_TIMER_WRITE_PEND_OFFSET +
+                               OMAP_TIMER_V2_FUNC_OFFSET;
+               timer->func_base = timer->io_base + OMAP_TIMER_V2_FUNC_OFFSET;
+       }
 }
 
 /* Assumes the source clock has been set by caller */
-static inline void __omap_dm_timer_reset(void __iomem *base, int autoidle,
-                                               int wakeup)
+static inline void __omap_dm_timer_reset(struct omap_dm_timer *timer,
+                                       int autoidle, int wakeup)
 {
        u32 l;
 
-       l = __omap_dm_timer_read(base, OMAP_TIMER_OCP_CFG_REG, 0);
+       l = __raw_readl(timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET);
        l |= 0x02 << 3;  /* Set to smart-idle mode */
        l |= 0x2 << 8;   /* Set clock activity to perserve f-clock on idle */
 
@@ -261,10 +348,10 @@ static inline void __omap_dm_timer_reset(void __iomem *base, int autoidle,
        if (wakeup)
                l |= 1 << 2;
 
-       __omap_dm_timer_write(base, OMAP_TIMER_OCP_CFG_REG, l, 0);
+       __raw_writel(l, timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET);
 
        /* Match hardware reset default of posted mode */
-       __omap_dm_timer_write(base, OMAP_TIMER_IF_CTRL_REG,
+       __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG,
                                        OMAP_TIMER_CTRL_POSTED, 0);
 }
 
@@ -286,18 +373,18 @@ static inline int __omap_dm_timer_set_source(struct clk *timer_fck,
        return ret;
 }
 
-static inline void __omap_dm_timer_stop(void __iomem *base, int posted,
-                                               unsigned long rate)
+static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer,
+                                       int posted, unsigned long rate)
 {
        u32 l;
 
-       l = __omap_dm_timer_read(base, OMAP_TIMER_CTRL_REG, posted);
+       l = __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted);
        if (l & OMAP_TIMER_CTRL_ST) {
                l &= ~0x1;
-               __omap_dm_timer_write(base, OMAP_TIMER_CTRL_REG, l, posted);
+               __omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, l, posted);
 #ifdef CONFIG_ARCH_OMAP2PLUS
                /* Readback to make sure write has completed */
-               __omap_dm_timer_read(base, OMAP_TIMER_CTRL_REG, posted);
+               __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted);
                /*
                 * Wait for functional clock period x 3.5 to make sure that
                 * timer is stopped
@@ -307,34 +394,34 @@ static inline void __omap_dm_timer_stop(void __iomem *base, int posted,
        }
 
        /* Ack possibly pending interrupt */
-       __omap_dm_timer_write(base, OMAP_TIMER_STAT_REG,
-                                       OMAP_TIMER_INT_OVERFLOW, 0);
+       __raw_writel(OMAP_TIMER_INT_OVERFLOW, timer->irq_stat);
 }
 
-static inline void __omap_dm_timer_load_start(void __iomem *base, u32 ctrl,
-                                               unsigned int load, int posted)
+static inline void __omap_dm_timer_load_start(struct omap_dm_timer *timer,
+                                               u32 ctrl, unsigned int load,
+                                               int posted)
 {
-       __omap_dm_timer_write(base, OMAP_TIMER_COUNTER_REG, load, posted);
-       __omap_dm_timer_write(base, OMAP_TIMER_CTRL_REG, ctrl, posted);
+       __omap_dm_timer_write(timer, OMAP_TIMER_COUNTER_REG, load, posted);
+       __omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, ctrl, posted);
 }
 
-static inline void __omap_dm_timer_int_enable(void __iomem *base,
+static inline void __omap_dm_timer_int_enable(struct omap_dm_timer *timer,
                                                unsigned int value)
 {
-       __omap_dm_timer_write(base, OMAP_TIMER_INT_EN_REG, value, 0);
-       __omap_dm_timer_write(base, OMAP_TIMER_WAKEUP_EN_REG, value, 0);
+       __raw_writel(value, timer->irq_ena);
+       __omap_dm_timer_write(timer, OMAP_TIMER_WAKEUP_EN_REG, value, 0);
 }
 
-static inline unsigned int __omap_dm_timer_read_counter(void __iomem *base,
-                                                       int posted)
+static inline unsigned int
+__omap_dm_timer_read_counter(struct omap_dm_timer *timer, int posted)
 {
-       return __omap_dm_timer_read(base, OMAP_TIMER_COUNTER_REG, posted);
+       return __omap_dm_timer_read(timer, OMAP_TIMER_COUNTER_REG, posted);
 }
 
-static inline void __omap_dm_timer_write_status(void __iomem *base,
+static inline void __omap_dm_timer_write_status(struct omap_dm_timer *timer,
                                                unsigned int value)
 {
-       __omap_dm_timer_write(base, OMAP_TIMER_STAT_REG, value, 0);
+       __raw_writel(value, timer->irq_stat);
 }
 
 #endif /* __ASM_ARCH_DMTIMER_H */
index 34e9c4f..999d6a0 100644 (file)
@@ -15,3 +15,18 @@ config CLKSRC_MMIO
 
 config DW_APB_TIMER
        bool
+
+config CLKSRC_DBX500_PRCMU
+       bool "Clocksource PRCMU Timer"
+       depends on UX500_SOC_DB5500 || UX500_SOC_DB8500
+       default y
+       help
+         Use the always on PRCMU Timer as clocksource
+
+config CLKSRC_DBX500_PRCMU_SCHED_CLOCK
+       bool "Clocksource PRCMU Timer sched_clock"
+       depends on (CLKSRC_DBX500_PRCMU && !NOMADIK_MTU_SCHED_CLOCK)
+       select HAVE_SCHED_CLOCK
+       default y
+       help
+         Use the always on PRCMU Timer as sched_clock
index 85ad164..8d81a1d 100644 (file)
@@ -9,3 +9,4 @@ obj-$(CONFIG_SH_TIMER_TMU)      += sh_tmu.o
 obj-$(CONFIG_CLKBLD_I8253)     += i8253.o
 obj-$(CONFIG_CLKSRC_MMIO)      += mmio.o
 obj-$(CONFIG_DW_APB_TIMER)     += dw_apb_timer.o
+obj-$(CONFIG_CLKSRC_DBX500_PRCMU)      += clksrc-dbx500-prcmu.o
\ No newline at end of file
diff --git a/drivers/clocksource/clksrc-dbx500-prcmu.c b/drivers/clocksource/clksrc-dbx500-prcmu.c
new file mode 100644 (file)
index 0000000..59feefe
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson
+ * Author: Sundar Iyer for ST-Ericsson
+ * sched_clock implementation is based on:
+ * plat-nomadik/timer.c Linus Walleij <linus.walleij@stericsson.com>
+ *
+ * DBx500-PRCMU Timer
+ * The PRCMU has 5 timers which are available in a always-on
+ * power domain.  We use the Timer 4 for our always-on clock
+ * source on DB8500 and Timer 3 on DB5500.
+ */
+#include <linux/clockchips.h>
+#include <linux/clksrc-dbx500-prcmu.h>
+
+#include <asm/sched_clock.h>
+
+#include <mach/setup.h>
+#include <mach/hardware.h>
+
+#define RATE_32K               32768
+
+#define TIMER_MODE_CONTINOUS   0x1
+#define TIMER_DOWNCOUNT_VAL    0xffffffff
+
+#define PRCMU_TIMER_REF                0
+#define PRCMU_TIMER_DOWNCOUNT  0x4
+#define PRCMU_TIMER_MODE       0x8
+
+#define SCHED_CLOCK_MIN_WRAP 131072 /* 2^32 / 32768 */
+
+static void __iomem *clksrc_dbx500_timer_base;
+
+static cycle_t clksrc_dbx500_prcmu_read(struct clocksource *cs)
+{
+       u32 count, count2;
+
+       do {
+               count = readl(clksrc_dbx500_timer_base +
+                             PRCMU_TIMER_DOWNCOUNT);
+               count2 = readl(clksrc_dbx500_timer_base +
+                              PRCMU_TIMER_DOWNCOUNT);
+       } while (count2 != count);
+
+       /* Negate because the timer is a decrementing counter */
+       return ~count;
+}
+
+static struct clocksource clocksource_dbx500_prcmu = {
+       .name           = "dbx500-prcmu-timer",
+       .rating         = 300,
+       .read           = clksrc_dbx500_prcmu_read,
+       .shift          = 10,
+       .mask           = CLOCKSOURCE_MASK(32),
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+#ifdef CONFIG_CLKSRC_DBX500_PRCMU_SCHED_CLOCK
+static DEFINE_CLOCK_DATA(cd);
+
+unsigned long long notrace sched_clock(void)
+{
+       u32 cyc;
+
+       if (unlikely(!clksrc_dbx500_timer_base))
+               return 0;
+
+       cyc = clksrc_dbx500_prcmu_read(&clocksource_dbx500_prcmu);
+
+       return cyc_to_sched_clock(&cd, cyc, (u32)~0);
+}
+
+static void notrace clksrc_dbx500_prcmu_update_sched_clock(void)
+{
+       u32 cyc = clksrc_dbx500_prcmu_read(&clocksource_dbx500_prcmu);
+       update_sched_clock(&cd, cyc, (u32)~0);
+}
+#endif
+
+void __init clksrc_dbx500_prcmu_init(void __iomem *base)
+{
+       clksrc_dbx500_timer_base = base;
+
+       /*
+        * The A9 sub system expects the timer to be configured as
+        * a continous looping timer.
+        * The PRCMU should configure it but if it for some reason
+        * don't we do it here.
+        */
+       if (readl(clksrc_dbx500_timer_base + PRCMU_TIMER_MODE) !=
+           TIMER_MODE_CONTINOUS) {
+               writel(TIMER_MODE_CONTINOUS,
+                      clksrc_dbx500_timer_base + PRCMU_TIMER_MODE);
+               writel(TIMER_DOWNCOUNT_VAL,
+                      clksrc_dbx500_timer_base + PRCMU_TIMER_REF);
+       }
+#ifdef CONFIG_CLKSRC_DBX500_PRCMU_SCHED_CLOCK
+       init_sched_clock(&cd, clksrc_dbx500_prcmu_update_sched_clock,
+                        32, RATE_32K);
+#endif
+       clocksource_calc_mult_shift(&clocksource_dbx500_prcmu,
+                                   RATE_32K, SCHED_CLOCK_MIN_WRAP);
+       clocksource_register(&clocksource_dbx500_prcmu);
+}
diff --git a/include/linux/clksrc-dbx500-prcmu.h b/include/linux/clksrc-dbx500-prcmu.h
new file mode 100644 (file)
index 0000000..4fb8119
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Mattias Wallin <mattias.wallin@stericsson.com>
+ *
+ */
+#ifndef __CLKSRC_DBX500_PRCMU_H
+#define __CLKSRC_DBX500_PRCMU_H
+
+#include <linux/init.h>
+#include <linux/io.h>
+
+#ifdef CONFIG_CLKSRC_DBX500_PRCMU
+void __init clksrc_dbx500_prcmu_init(void __iomem *base);
+#else
+static inline void __init clksrc_dbx500_prcmu_init(void __iomem *base) {}
+#endif
+
+#endif