Merge branch 'next/timer' of git://git.linaro.org/people/arnd/arm-soc

* '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
This commit is contained in:
Linus Torvalds 2011-11-01 20:18:05 -07:00
commit ac5761a650
25 changed files with 1525 additions and 501 deletions

View File

@ -4,7 +4,7 @@
# Common support # 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 := 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 obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o

173
arch/arm/mach-omap1/timer.c Normal file
View File

@ -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);

View File

@ -1898,6 +1898,54 @@ static struct omap_clk omap2420_clks[] = {
CLK(NULL, "pka_ick", &pka_ick, CK_242X), CLK(NULL, "pka_ick", &pka_ick, CK_242X),
CLK(NULL, "usb_fck", &usb_fck, CK_242X), CLK(NULL, "usb_fck", &usb_fck, CK_242X),
CLK("musb-hdrc", "fck", &osc_ck, 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),
}; };
/* /*

View File

@ -1998,6 +1998,54 @@ static struct omap_clk omap2430_clks[] = {
CLK(NULL, "mdm_intc_ick", &mdm_intc_ick, CK_243X), CLK(NULL, "mdm_intc_ick", &mdm_intc_ick, CK_243X),
CLK("omap_hsmmc.0", "mmchsdb_fck", &mmchsdb1_fck, CK_243X), CLK("omap_hsmmc.0", "mmchsdb_fck", &mmchsdb1_fck, CK_243X),
CLK("omap_hsmmc.1", "mmchsdb_fck", &mmchsdb2_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),
}; };
/* /*

View File

@ -3464,6 +3464,42 @@ static struct omap_clk omap3xxx_clks[] = {
CLK("musb-am35x", "fck", &hsotgusb_fck_am35xx, CK_AM35XX), CLK("musb-am35x", "fck", &hsotgusb_fck_am35xx, CK_AM35XX),
CLK(NULL, "hecc_ck", &hecc_ck, CK_AM35XX), CLK(NULL, "hecc_ck", &hecc_ck, CK_AM35XX),
CLK(NULL, "uart4_ick", &uart4_ick_am35xx, 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),
}; };

View 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", "usbhost_ick", &dummy_ck, CK_443X),
CLK("usbhs-omap.0", "usbtll_fck", &dummy_ck, CK_443X), CLK("usbhs-omap.0", "usbtll_fck", &dummy_ck, CK_443X),
CLK("omap_wdt", "ick", &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) int __init omap4xxx_clk_init(void)

View File

@ -269,6 +269,16 @@ static struct omap_hwmod omap2420_iva_hwmod = {
.masters_cnt = ARRAY_SIZE(omap2420_iva_masters), .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 */ /* timer1 */
static struct omap_hwmod omap2420_timer1_hwmod; 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, .idlest_idle_bit = OMAP24XX_ST_GPT1_SHIFT,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap2420_timer1_slaves, .slaves = omap2420_timer1_slaves,
.slaves_cnt = ARRAY_SIZE(omap2420_timer1_slaves), .slaves_cnt = ARRAY_SIZE(omap2420_timer1_slaves),
.class = &omap2xxx_timer_hwmod_class, .class = &omap2xxx_timer_hwmod_class,
@ -345,6 +356,7 @@ static struct omap_hwmod omap2420_timer2_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_GPT2_SHIFT, .idlest_idle_bit = OMAP24XX_ST_GPT2_SHIFT,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap2420_timer2_slaves, .slaves = omap2420_timer2_slaves,
.slaves_cnt = ARRAY_SIZE(omap2420_timer2_slaves), .slaves_cnt = ARRAY_SIZE(omap2420_timer2_slaves),
.class = &omap2xxx_timer_hwmod_class, .class = &omap2xxx_timer_hwmod_class,
@ -381,6 +393,7 @@ static struct omap_hwmod omap2420_timer3_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_GPT3_SHIFT, .idlest_idle_bit = OMAP24XX_ST_GPT3_SHIFT,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap2420_timer3_slaves, .slaves = omap2420_timer3_slaves,
.slaves_cnt = ARRAY_SIZE(omap2420_timer3_slaves), .slaves_cnt = ARRAY_SIZE(omap2420_timer3_slaves),
.class = &omap2xxx_timer_hwmod_class, .class = &omap2xxx_timer_hwmod_class,
@ -417,6 +430,7 @@ static struct omap_hwmod omap2420_timer4_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_GPT4_SHIFT, .idlest_idle_bit = OMAP24XX_ST_GPT4_SHIFT,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap2420_timer4_slaves, .slaves = omap2420_timer4_slaves,
.slaves_cnt = ARRAY_SIZE(omap2420_timer4_slaves), .slaves_cnt = ARRAY_SIZE(omap2420_timer4_slaves),
.class = &omap2xxx_timer_hwmod_class, .class = &omap2xxx_timer_hwmod_class,
@ -453,6 +467,7 @@ static struct omap_hwmod omap2420_timer5_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_GPT5_SHIFT, .idlest_idle_bit = OMAP24XX_ST_GPT5_SHIFT,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap2420_timer5_slaves, .slaves = omap2420_timer5_slaves,
.slaves_cnt = ARRAY_SIZE(omap2420_timer5_slaves), .slaves_cnt = ARRAY_SIZE(omap2420_timer5_slaves),
.class = &omap2xxx_timer_hwmod_class, .class = &omap2xxx_timer_hwmod_class,
@ -490,6 +505,7 @@ static struct omap_hwmod omap2420_timer6_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_GPT6_SHIFT, .idlest_idle_bit = OMAP24XX_ST_GPT6_SHIFT,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap2420_timer6_slaves, .slaves = omap2420_timer6_slaves,
.slaves_cnt = ARRAY_SIZE(omap2420_timer6_slaves), .slaves_cnt = ARRAY_SIZE(omap2420_timer6_slaves),
.class = &omap2xxx_timer_hwmod_class, .class = &omap2xxx_timer_hwmod_class,
@ -526,6 +542,7 @@ static struct omap_hwmod omap2420_timer7_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_GPT7_SHIFT, .idlest_idle_bit = OMAP24XX_ST_GPT7_SHIFT,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap2420_timer7_slaves, .slaves = omap2420_timer7_slaves,
.slaves_cnt = ARRAY_SIZE(omap2420_timer7_slaves), .slaves_cnt = ARRAY_SIZE(omap2420_timer7_slaves),
.class = &omap2xxx_timer_hwmod_class, .class = &omap2xxx_timer_hwmod_class,
@ -562,6 +579,7 @@ static struct omap_hwmod omap2420_timer8_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_GPT8_SHIFT, .idlest_idle_bit = OMAP24XX_ST_GPT8_SHIFT,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap2420_timer8_slaves, .slaves = omap2420_timer8_slaves,
.slaves_cnt = ARRAY_SIZE(omap2420_timer8_slaves), .slaves_cnt = ARRAY_SIZE(omap2420_timer8_slaves),
.class = &omap2xxx_timer_hwmod_class, .class = &omap2xxx_timer_hwmod_class,
@ -598,6 +616,7 @@ static struct omap_hwmod omap2420_timer9_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_GPT9_SHIFT, .idlest_idle_bit = OMAP24XX_ST_GPT9_SHIFT,
}, },
}, },
.dev_attr = &capability_pwm_dev_attr,
.slaves = omap2420_timer9_slaves, .slaves = omap2420_timer9_slaves,
.slaves_cnt = ARRAY_SIZE(omap2420_timer9_slaves), .slaves_cnt = ARRAY_SIZE(omap2420_timer9_slaves),
.class = &omap2xxx_timer_hwmod_class, .class = &omap2xxx_timer_hwmod_class,
@ -634,6 +653,7 @@ static struct omap_hwmod omap2420_timer10_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_GPT10_SHIFT, .idlest_idle_bit = OMAP24XX_ST_GPT10_SHIFT,
}, },
}, },
.dev_attr = &capability_pwm_dev_attr,
.slaves = omap2420_timer10_slaves, .slaves = omap2420_timer10_slaves,
.slaves_cnt = ARRAY_SIZE(omap2420_timer10_slaves), .slaves_cnt = ARRAY_SIZE(omap2420_timer10_slaves),
.class = &omap2xxx_timer_hwmod_class, .class = &omap2xxx_timer_hwmod_class,
@ -670,6 +690,7 @@ static struct omap_hwmod omap2420_timer11_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_GPT11_SHIFT, .idlest_idle_bit = OMAP24XX_ST_GPT11_SHIFT,
}, },
}, },
.dev_attr = &capability_pwm_dev_attr,
.slaves = omap2420_timer11_slaves, .slaves = omap2420_timer11_slaves,
.slaves_cnt = ARRAY_SIZE(omap2420_timer11_slaves), .slaves_cnt = ARRAY_SIZE(omap2420_timer11_slaves),
.class = &omap2xxx_timer_hwmod_class, .class = &omap2xxx_timer_hwmod_class,
@ -706,6 +727,7 @@ static struct omap_hwmod omap2420_timer12_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_GPT12_SHIFT, .idlest_idle_bit = OMAP24XX_ST_GPT12_SHIFT,
}, },
}, },
.dev_attr = &capability_pwm_dev_attr,
.slaves = omap2420_timer12_slaves, .slaves = omap2420_timer12_slaves,
.slaves_cnt = ARRAY_SIZE(omap2420_timer12_slaves), .slaves_cnt = ARRAY_SIZE(omap2420_timer12_slaves),
.class = &omap2xxx_timer_hwmod_class, .class = &omap2xxx_timer_hwmod_class,

View File

@ -343,6 +343,16 @@ static struct omap_hwmod omap2430_iva_hwmod = {
.masters_cnt = ARRAY_SIZE(omap2430_iva_masters), .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 */ /* timer1 */
static struct omap_hwmod omap2430_timer1_hwmod; 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, .idlest_idle_bit = OMAP24XX_ST_GPT1_SHIFT,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap2430_timer1_slaves, .slaves = omap2430_timer1_slaves,
.slaves_cnt = ARRAY_SIZE(omap2430_timer1_slaves), .slaves_cnt = ARRAY_SIZE(omap2430_timer1_slaves),
.class = &omap2xxx_timer_hwmod_class, .class = &omap2xxx_timer_hwmod_class,
@ -419,6 +430,7 @@ static struct omap_hwmod omap2430_timer2_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_GPT2_SHIFT, .idlest_idle_bit = OMAP24XX_ST_GPT2_SHIFT,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap2430_timer2_slaves, .slaves = omap2430_timer2_slaves,
.slaves_cnt = ARRAY_SIZE(omap2430_timer2_slaves), .slaves_cnt = ARRAY_SIZE(omap2430_timer2_slaves),
.class = &omap2xxx_timer_hwmod_class, .class = &omap2xxx_timer_hwmod_class,
@ -455,6 +467,7 @@ static struct omap_hwmod omap2430_timer3_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_GPT3_SHIFT, .idlest_idle_bit = OMAP24XX_ST_GPT3_SHIFT,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap2430_timer3_slaves, .slaves = omap2430_timer3_slaves,
.slaves_cnt = ARRAY_SIZE(omap2430_timer3_slaves), .slaves_cnt = ARRAY_SIZE(omap2430_timer3_slaves),
.class = &omap2xxx_timer_hwmod_class, .class = &omap2xxx_timer_hwmod_class,
@ -491,6 +504,7 @@ static struct omap_hwmod omap2430_timer4_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_GPT4_SHIFT, .idlest_idle_bit = OMAP24XX_ST_GPT4_SHIFT,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap2430_timer4_slaves, .slaves = omap2430_timer4_slaves,
.slaves_cnt = ARRAY_SIZE(omap2430_timer4_slaves), .slaves_cnt = ARRAY_SIZE(omap2430_timer4_slaves),
.class = &omap2xxx_timer_hwmod_class, .class = &omap2xxx_timer_hwmod_class,
@ -527,6 +541,7 @@ static struct omap_hwmod omap2430_timer5_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_GPT5_SHIFT, .idlest_idle_bit = OMAP24XX_ST_GPT5_SHIFT,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap2430_timer5_slaves, .slaves = omap2430_timer5_slaves,
.slaves_cnt = ARRAY_SIZE(omap2430_timer5_slaves), .slaves_cnt = ARRAY_SIZE(omap2430_timer5_slaves),
.class = &omap2xxx_timer_hwmod_class, .class = &omap2xxx_timer_hwmod_class,
@ -563,6 +578,7 @@ static struct omap_hwmod omap2430_timer6_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_GPT6_SHIFT, .idlest_idle_bit = OMAP24XX_ST_GPT6_SHIFT,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap2430_timer6_slaves, .slaves = omap2430_timer6_slaves,
.slaves_cnt = ARRAY_SIZE(omap2430_timer6_slaves), .slaves_cnt = ARRAY_SIZE(omap2430_timer6_slaves),
.class = &omap2xxx_timer_hwmod_class, .class = &omap2xxx_timer_hwmod_class,
@ -599,6 +615,7 @@ static struct omap_hwmod omap2430_timer7_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_GPT7_SHIFT, .idlest_idle_bit = OMAP24XX_ST_GPT7_SHIFT,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap2430_timer7_slaves, .slaves = omap2430_timer7_slaves,
.slaves_cnt = ARRAY_SIZE(omap2430_timer7_slaves), .slaves_cnt = ARRAY_SIZE(omap2430_timer7_slaves),
.class = &omap2xxx_timer_hwmod_class, .class = &omap2xxx_timer_hwmod_class,
@ -635,6 +652,7 @@ static struct omap_hwmod omap2430_timer8_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_GPT8_SHIFT, .idlest_idle_bit = OMAP24XX_ST_GPT8_SHIFT,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap2430_timer8_slaves, .slaves = omap2430_timer8_slaves,
.slaves_cnt = ARRAY_SIZE(omap2430_timer8_slaves), .slaves_cnt = ARRAY_SIZE(omap2430_timer8_slaves),
.class = &omap2xxx_timer_hwmod_class, .class = &omap2xxx_timer_hwmod_class,
@ -671,6 +689,7 @@ static struct omap_hwmod omap2430_timer9_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_GPT9_SHIFT, .idlest_idle_bit = OMAP24XX_ST_GPT9_SHIFT,
}, },
}, },
.dev_attr = &capability_pwm_dev_attr,
.slaves = omap2430_timer9_slaves, .slaves = omap2430_timer9_slaves,
.slaves_cnt = ARRAY_SIZE(omap2430_timer9_slaves), .slaves_cnt = ARRAY_SIZE(omap2430_timer9_slaves),
.class = &omap2xxx_timer_hwmod_class, .class = &omap2xxx_timer_hwmod_class,
@ -707,6 +726,7 @@ static struct omap_hwmod omap2430_timer10_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_GPT10_SHIFT, .idlest_idle_bit = OMAP24XX_ST_GPT10_SHIFT,
}, },
}, },
.dev_attr = &capability_pwm_dev_attr,
.slaves = omap2430_timer10_slaves, .slaves = omap2430_timer10_slaves,
.slaves_cnt = ARRAY_SIZE(omap2430_timer10_slaves), .slaves_cnt = ARRAY_SIZE(omap2430_timer10_slaves),
.class = &omap2xxx_timer_hwmod_class, .class = &omap2xxx_timer_hwmod_class,
@ -743,6 +763,7 @@ static struct omap_hwmod omap2430_timer11_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_GPT11_SHIFT, .idlest_idle_bit = OMAP24XX_ST_GPT11_SHIFT,
}, },
}, },
.dev_attr = &capability_pwm_dev_attr,
.slaves = omap2430_timer11_slaves, .slaves = omap2430_timer11_slaves,
.slaves_cnt = ARRAY_SIZE(omap2430_timer11_slaves), .slaves_cnt = ARRAY_SIZE(omap2430_timer11_slaves),
.class = &omap2xxx_timer_hwmod_class, .class = &omap2xxx_timer_hwmod_class,
@ -779,6 +800,7 @@ static struct omap_hwmod omap2430_timer12_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_GPT12_SHIFT, .idlest_idle_bit = OMAP24XX_ST_GPT12_SHIFT,
}, },
}, },
.dev_attr = &capability_pwm_dev_attr,
.slaves = omap2430_timer12_slaves, .slaves = omap2430_timer12_slaves,
.slaves_cnt = ARRAY_SIZE(omap2430_timer12_slaves), .slaves_cnt = ARRAY_SIZE(omap2430_timer12_slaves),
.class = &omap2xxx_timer_hwmod_class, .class = &omap2xxx_timer_hwmod_class,

View File

@ -564,6 +564,21 @@ static struct omap_hwmod_class omap3xxx_timer_hwmod_class = {
.rev = OMAP_TIMER_IP_VERSION_1, .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 */ /* timer1 */
static struct omap_hwmod omap3xxx_timer1_hwmod; 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, .idlest_idle_bit = OMAP3430_ST_GPT1_SHIFT,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap3xxx_timer1_slaves, .slaves = omap3xxx_timer1_slaves,
.slaves_cnt = ARRAY_SIZE(omap3xxx_timer1_slaves), .slaves_cnt = ARRAY_SIZE(omap3xxx_timer1_slaves),
.class = &omap3xxx_timer_1ms_hwmod_class, .class = &omap3xxx_timer_1ms_hwmod_class,
@ -649,6 +665,7 @@ static struct omap_hwmod omap3xxx_timer2_hwmod = {
.idlest_idle_bit = OMAP3430_ST_GPT2_SHIFT, .idlest_idle_bit = OMAP3430_ST_GPT2_SHIFT,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap3xxx_timer2_slaves, .slaves = omap3xxx_timer2_slaves,
.slaves_cnt = ARRAY_SIZE(omap3xxx_timer2_slaves), .slaves_cnt = ARRAY_SIZE(omap3xxx_timer2_slaves),
.class = &omap3xxx_timer_1ms_hwmod_class, .class = &omap3xxx_timer_1ms_hwmod_class,
@ -694,6 +711,7 @@ static struct omap_hwmod omap3xxx_timer3_hwmod = {
.idlest_idle_bit = OMAP3430_ST_GPT3_SHIFT, .idlest_idle_bit = OMAP3430_ST_GPT3_SHIFT,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap3xxx_timer3_slaves, .slaves = omap3xxx_timer3_slaves,
.slaves_cnt = ARRAY_SIZE(omap3xxx_timer3_slaves), .slaves_cnt = ARRAY_SIZE(omap3xxx_timer3_slaves),
.class = &omap3xxx_timer_hwmod_class, .class = &omap3xxx_timer_hwmod_class,
@ -739,6 +757,7 @@ static struct omap_hwmod omap3xxx_timer4_hwmod = {
.idlest_idle_bit = OMAP3430_ST_GPT4_SHIFT, .idlest_idle_bit = OMAP3430_ST_GPT4_SHIFT,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap3xxx_timer4_slaves, .slaves = omap3xxx_timer4_slaves,
.slaves_cnt = ARRAY_SIZE(omap3xxx_timer4_slaves), .slaves_cnt = ARRAY_SIZE(omap3xxx_timer4_slaves),
.class = &omap3xxx_timer_hwmod_class, .class = &omap3xxx_timer_hwmod_class,
@ -784,6 +803,7 @@ static struct omap_hwmod omap3xxx_timer5_hwmod = {
.idlest_idle_bit = OMAP3430_ST_GPT5_SHIFT, .idlest_idle_bit = OMAP3430_ST_GPT5_SHIFT,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap3xxx_timer5_slaves, .slaves = omap3xxx_timer5_slaves,
.slaves_cnt = ARRAY_SIZE(omap3xxx_timer5_slaves), .slaves_cnt = ARRAY_SIZE(omap3xxx_timer5_slaves),
.class = &omap3xxx_timer_hwmod_class, .class = &omap3xxx_timer_hwmod_class,
@ -829,6 +849,7 @@ static struct omap_hwmod omap3xxx_timer6_hwmod = {
.idlest_idle_bit = OMAP3430_ST_GPT6_SHIFT, .idlest_idle_bit = OMAP3430_ST_GPT6_SHIFT,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap3xxx_timer6_slaves, .slaves = omap3xxx_timer6_slaves,
.slaves_cnt = ARRAY_SIZE(omap3xxx_timer6_slaves), .slaves_cnt = ARRAY_SIZE(omap3xxx_timer6_slaves),
.class = &omap3xxx_timer_hwmod_class, .class = &omap3xxx_timer_hwmod_class,
@ -874,6 +895,7 @@ static struct omap_hwmod omap3xxx_timer7_hwmod = {
.idlest_idle_bit = OMAP3430_ST_GPT7_SHIFT, .idlest_idle_bit = OMAP3430_ST_GPT7_SHIFT,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap3xxx_timer7_slaves, .slaves = omap3xxx_timer7_slaves,
.slaves_cnt = ARRAY_SIZE(omap3xxx_timer7_slaves), .slaves_cnt = ARRAY_SIZE(omap3xxx_timer7_slaves),
.class = &omap3xxx_timer_hwmod_class, .class = &omap3xxx_timer_hwmod_class,
@ -919,6 +941,7 @@ static struct omap_hwmod omap3xxx_timer8_hwmod = {
.idlest_idle_bit = OMAP3430_ST_GPT8_SHIFT, .idlest_idle_bit = OMAP3430_ST_GPT8_SHIFT,
}, },
}, },
.dev_attr = &capability_pwm_dev_attr,
.slaves = omap3xxx_timer8_slaves, .slaves = omap3xxx_timer8_slaves,
.slaves_cnt = ARRAY_SIZE(omap3xxx_timer8_slaves), .slaves_cnt = ARRAY_SIZE(omap3xxx_timer8_slaves),
.class = &omap3xxx_timer_hwmod_class, .class = &omap3xxx_timer_hwmod_class,
@ -964,6 +987,7 @@ static struct omap_hwmod omap3xxx_timer9_hwmod = {
.idlest_idle_bit = OMAP3430_ST_GPT9_SHIFT, .idlest_idle_bit = OMAP3430_ST_GPT9_SHIFT,
}, },
}, },
.dev_attr = &capability_pwm_dev_attr,
.slaves = omap3xxx_timer9_slaves, .slaves = omap3xxx_timer9_slaves,
.slaves_cnt = ARRAY_SIZE(omap3xxx_timer9_slaves), .slaves_cnt = ARRAY_SIZE(omap3xxx_timer9_slaves),
.class = &omap3xxx_timer_hwmod_class, .class = &omap3xxx_timer_hwmod_class,
@ -1000,6 +1024,7 @@ static struct omap_hwmod omap3xxx_timer10_hwmod = {
.idlest_idle_bit = OMAP3430_ST_GPT10_SHIFT, .idlest_idle_bit = OMAP3430_ST_GPT10_SHIFT,
}, },
}, },
.dev_attr = &capability_pwm_dev_attr,
.slaves = omap3xxx_timer10_slaves, .slaves = omap3xxx_timer10_slaves,
.slaves_cnt = ARRAY_SIZE(omap3xxx_timer10_slaves), .slaves_cnt = ARRAY_SIZE(omap3xxx_timer10_slaves),
.class = &omap3xxx_timer_1ms_hwmod_class, .class = &omap3xxx_timer_1ms_hwmod_class,
@ -1036,6 +1061,7 @@ static struct omap_hwmod omap3xxx_timer11_hwmod = {
.idlest_idle_bit = OMAP3430_ST_GPT11_SHIFT, .idlest_idle_bit = OMAP3430_ST_GPT11_SHIFT,
}, },
}, },
.dev_attr = &capability_pwm_dev_attr,
.slaves = omap3xxx_timer11_slaves, .slaves = omap3xxx_timer11_slaves,
.slaves_cnt = ARRAY_SIZE(omap3xxx_timer11_slaves), .slaves_cnt = ARRAY_SIZE(omap3xxx_timer11_slaves),
.class = &omap3xxx_timer_hwmod_class, .class = &omap3xxx_timer_hwmod_class,
@ -1085,6 +1111,7 @@ static struct omap_hwmod omap3xxx_timer12_hwmod = {
.idlest_idle_bit = OMAP3430_ST_GPT12_SHIFT, .idlest_idle_bit = OMAP3430_ST_GPT12_SHIFT,
}, },
}, },
.dev_attr = &capability_secure_dev_attr,
.slaves = omap3xxx_timer12_slaves, .slaves = omap3xxx_timer12_slaves,
.slaves_cnt = ARRAY_SIZE(omap3xxx_timer12_slaves), .slaves_cnt = ARRAY_SIZE(omap3xxx_timer12_slaves),
.class = &omap3xxx_timer_hwmod_class, .class = &omap3xxx_timer_hwmod_class,

View File

@ -29,6 +29,7 @@
#include <plat/mcbsp.h> #include <plat/mcbsp.h>
#include <plat/mmc.h> #include <plat/mmc.h>
#include <plat/i2c.h> #include <plat/i2c.h>
#include <plat/dmtimer.h>
#include "omap_hwmod_common_data.h" #include "omap_hwmod_common_data.h"
@ -4201,6 +4202,16 @@ static struct omap_hwmod_class omap44xx_timer_hwmod_class = {
.sysc = &omap44xx_timer_sysc, .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 */ /* timer1 */
static struct omap_hwmod omap44xx_timer1_hwmod; static struct omap_hwmod omap44xx_timer1_hwmod;
static struct omap_hwmod_irq_info omap44xx_timer1_irqs[] = { static struct omap_hwmod_irq_info omap44xx_timer1_irqs[] = {
@ -4244,6 +4255,7 @@ static struct omap_hwmod omap44xx_timer1_hwmod = {
.modulemode = MODULEMODE_SWCTRL, .modulemode = MODULEMODE_SWCTRL,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap44xx_timer1_slaves, .slaves = omap44xx_timer1_slaves,
.slaves_cnt = ARRAY_SIZE(omap44xx_timer1_slaves), .slaves_cnt = ARRAY_SIZE(omap44xx_timer1_slaves),
}; };
@ -4291,6 +4303,7 @@ static struct omap_hwmod omap44xx_timer2_hwmod = {
.modulemode = MODULEMODE_SWCTRL, .modulemode = MODULEMODE_SWCTRL,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap44xx_timer2_slaves, .slaves = omap44xx_timer2_slaves,
.slaves_cnt = ARRAY_SIZE(omap44xx_timer2_slaves), .slaves_cnt = ARRAY_SIZE(omap44xx_timer2_slaves),
}; };
@ -4338,6 +4351,7 @@ static struct omap_hwmod omap44xx_timer3_hwmod = {
.modulemode = MODULEMODE_SWCTRL, .modulemode = MODULEMODE_SWCTRL,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap44xx_timer3_slaves, .slaves = omap44xx_timer3_slaves,
.slaves_cnt = ARRAY_SIZE(omap44xx_timer3_slaves), .slaves_cnt = ARRAY_SIZE(omap44xx_timer3_slaves),
}; };
@ -4385,6 +4399,7 @@ static struct omap_hwmod omap44xx_timer4_hwmod = {
.modulemode = MODULEMODE_SWCTRL, .modulemode = MODULEMODE_SWCTRL,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap44xx_timer4_slaves, .slaves = omap44xx_timer4_slaves,
.slaves_cnt = ARRAY_SIZE(omap44xx_timer4_slaves), .slaves_cnt = ARRAY_SIZE(omap44xx_timer4_slaves),
}; };
@ -4451,6 +4466,7 @@ static struct omap_hwmod omap44xx_timer5_hwmod = {
.modulemode = MODULEMODE_SWCTRL, .modulemode = MODULEMODE_SWCTRL,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap44xx_timer5_slaves, .slaves = omap44xx_timer5_slaves,
.slaves_cnt = ARRAY_SIZE(omap44xx_timer5_slaves), .slaves_cnt = ARRAY_SIZE(omap44xx_timer5_slaves),
}; };
@ -4518,6 +4534,7 @@ static struct omap_hwmod omap44xx_timer6_hwmod = {
.modulemode = MODULEMODE_SWCTRL, .modulemode = MODULEMODE_SWCTRL,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap44xx_timer6_slaves, .slaves = omap44xx_timer6_slaves,
.slaves_cnt = ARRAY_SIZE(omap44xx_timer6_slaves), .slaves_cnt = ARRAY_SIZE(omap44xx_timer6_slaves),
}; };
@ -4584,6 +4601,7 @@ static struct omap_hwmod omap44xx_timer7_hwmod = {
.modulemode = MODULEMODE_SWCTRL, .modulemode = MODULEMODE_SWCTRL,
}, },
}, },
.dev_attr = &capability_alwon_dev_attr,
.slaves = omap44xx_timer7_slaves, .slaves = omap44xx_timer7_slaves,
.slaves_cnt = ARRAY_SIZE(omap44xx_timer7_slaves), .slaves_cnt = ARRAY_SIZE(omap44xx_timer7_slaves),
}; };
@ -4650,6 +4668,7 @@ static struct omap_hwmod omap44xx_timer8_hwmod = {
.modulemode = MODULEMODE_SWCTRL, .modulemode = MODULEMODE_SWCTRL,
}, },
}, },
.dev_attr = &capability_pwm_dev_attr,
.slaves = omap44xx_timer8_slaves, .slaves = omap44xx_timer8_slaves,
.slaves_cnt = ARRAY_SIZE(omap44xx_timer8_slaves), .slaves_cnt = ARRAY_SIZE(omap44xx_timer8_slaves),
}; };
@ -4697,6 +4716,7 @@ static struct omap_hwmod omap44xx_timer9_hwmod = {
.modulemode = MODULEMODE_SWCTRL, .modulemode = MODULEMODE_SWCTRL,
}, },
}, },
.dev_attr = &capability_pwm_dev_attr,
.slaves = omap44xx_timer9_slaves, .slaves = omap44xx_timer9_slaves,
.slaves_cnt = ARRAY_SIZE(omap44xx_timer9_slaves), .slaves_cnt = ARRAY_SIZE(omap44xx_timer9_slaves),
}; };
@ -4744,6 +4764,7 @@ static struct omap_hwmod omap44xx_timer10_hwmod = {
.modulemode = MODULEMODE_SWCTRL, .modulemode = MODULEMODE_SWCTRL,
}, },
}, },
.dev_attr = &capability_pwm_dev_attr,
.slaves = omap44xx_timer10_slaves, .slaves = omap44xx_timer10_slaves,
.slaves_cnt = ARRAY_SIZE(omap44xx_timer10_slaves), .slaves_cnt = ARRAY_SIZE(omap44xx_timer10_slaves),
}; };
@ -4791,6 +4812,7 @@ static struct omap_hwmod omap44xx_timer11_hwmod = {
.modulemode = MODULEMODE_SWCTRL, .modulemode = MODULEMODE_SWCTRL,
}, },
}, },
.dev_attr = &capability_pwm_dev_attr,
.slaves = omap44xx_timer11_slaves, .slaves = omap44xx_timer11_slaves,
.slaves_cnt = ARRAY_SIZE(omap44xx_timer11_slaves), .slaves_cnt = ARRAY_SIZE(omap44xx_timer11_slaves),
}; };

View File

@ -35,6 +35,7 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/clocksource.h> #include <linux/clocksource.h>
#include <linux/clockchips.h> #include <linux/clockchips.h>
#include <linux/slab.h>
#include <asm/mach/time.h> #include <asm/mach/time.h>
#include <plat/dmtimer.h> #include <plat/dmtimer.h>
@ -42,6 +43,10 @@
#include <asm/sched_clock.h> #include <asm/sched_clock.h>
#include <plat/common.h> #include <plat/common.h>
#include <plat/omap_hwmod.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 */ /* Parent clocks, eventually these will come from the clock framework */
@ -67,7 +72,7 @@
/* MAX_GPTIMER_ID: number of GPTIMERs on the chip */ /* MAX_GPTIMER_ID: number of GPTIMERs on the chip */
#define MAX_GPTIMER_ID 12 #define MAX_GPTIMER_ID 12
u32 sys_timer_reserved; static u32 sys_timer_reserved;
/* Clockevent code */ /* 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; 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); evt->event_handler(evt);
return IRQ_HANDLED; 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, static int omap2_gp_timer_set_next_event(unsigned long cycles,
struct clock_event_device *evt) 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); 0xffffffff - cycles, 1);
return 0; return 0;
@ -104,16 +109,16 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
{ {
u32 period; u32 period;
__omap_dm_timer_stop(clkev.io_base, 1, clkev.rate); __omap_dm_timer_stop(&clkev, 1, clkev.rate);
switch (mode) { switch (mode) {
case CLOCK_EVT_MODE_PERIODIC: case CLOCK_EVT_MODE_PERIODIC:
period = clkev.rate / HZ; period = clkev.rate / HZ;
period -= 1; period -= 1;
/* Looks like we need to first set the load value separately */ /* 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); 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, OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST,
0xffffffff - period, 1); 0xffffffff - period, 1);
break; break;
@ -189,7 +194,8 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
clk_put(src); 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->posted = 1;
timer->rate = clk_get_rate(timer->fclk); 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; omap2_gp_timer_irq.dev_id = (void *)&clkev;
setup_irq(clkev.irq, &omap2_gp_timer_irq); 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.mult = div_sc(clkev.rate, NSEC_PER_SEC,
clockevent_gpt.shift); clockevent_gpt.shift);
@ -251,7 +257,7 @@ static struct omap_dm_timer clksrc;
static DEFINE_CLOCK_DATA(cd); static DEFINE_CLOCK_DATA(cd);
static cycle_t clocksource_read_cycles(struct clocksource *cs) 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 = { static struct clocksource clocksource_gpt = {
@ -266,7 +272,7 @@ static void notrace dmtimer_update_sched_clock(void)
{ {
u32 cyc; 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); update_sched_clock(&cd, cyc, (u32)~0);
} }
@ -276,7 +282,7 @@ unsigned long long notrace sched_clock(void)
u32 cyc = 0; u32 cyc = 0;
if (clksrc.reserved) 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); 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", pr_info("OMAP clocksource: GPTIMER%d at %lu Hz\n",
gptimer_id, clksrc.rate); 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); OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1);
init_sched_clock(&cd, dmtimer_update_sched_clock, 32, clksrc.rate); 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) OMAP_SYS_TIMER(4)
#endif #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);

View File

@ -3,7 +3,7 @@
# #
obj-y := clock.o cpu.o devices.o devices-common.o \ 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_CACHE_L2X0) += cache-l2x0.o
obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o dma-db5500.o obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o dma-db5500.o
obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o

View File

@ -10,12 +10,12 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/mfd/db8500-prcmu.h> #include <linux/mfd/db8500-prcmu.h>
#include <linux/mfd/db5500-prcmu.h> #include <linux/mfd/db5500-prcmu.h>
#include <linux/clksrc-dbx500-prcmu.h>
#include <asm/hardware/gic.h> #include <asm/hardware/gic.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include <asm/localtimer.h> #include <asm/localtimer.h>
#include <plat/mtu.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/setup.h> #include <mach/setup.h>
#include <mach/devices.h> #include <mach/devices.h>
@ -50,30 +50,3 @@ void __init ux500_init_irq(void)
prcmu_early_init(); prcmu_early_init();
clk_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,
};

View File

@ -61,6 +61,8 @@
#define U5500_SCR_BASE (U5500_PER4_BASE + 0x5000) #define U5500_SCR_BASE (U5500_PER4_BASE + 0x5000)
#define U5500_DMC_BASE (U5500_PER4_BASE + 0x6000) #define U5500_DMC_BASE (U5500_PER4_BASE + 0x6000)
#define U5500_PRCMU_BASE (U5500_PER4_BASE + 0x7000) #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_MSP1_BASE (U5500_PER4_BASE + 0x9000)
#define U5500_GPIO2_BASE (U5500_PER4_BASE + 0xA000) #define U5500_GPIO2_BASE (U5500_PER4_BASE + 0xA000)
#define U5500_CDETECT_BASE (U5500_PER4_BASE + 0xF000) #define U5500_CDETECT_BASE (U5500_PER4_BASE + 0xF000)

View File

@ -102,10 +102,13 @@
#define U8500_SCR_BASE (U8500_PER4_BASE + 0x05000) #define U8500_SCR_BASE (U8500_PER4_BASE + 0x05000)
#define U8500_DMC_BASE (U8500_PER4_BASE + 0x06000) #define U8500_DMC_BASE (U8500_PER4_BASE + 0x06000)
#define U8500_PRCMU_BASE (U8500_PER4_BASE + 0x07000) #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_V1 (U8500_PER4_BASE + 0x0f000)
#define U8500_PRCMU_TCDM_BASE (U8500_PER4_BASE + 0x68000) #define U8500_PRCMU_TCDM_BASE (U8500_PER4_BASE + 0x68000)
#define U8500_PRCMU_TCPM_BASE (U8500_PER4_BASE + 0x60000) #define U8500_PRCMU_TCPM_BASE (U8500_PER4_BASE + 0x60000)
/* per3 base addresses */ /* per3 base addresses */
#define U8500_FSMC_BASE (U8500_PER3_BASE + 0x0000) #define U8500_FSMC_BASE (U8500_PER3_BASE + 0x0000)
#define U8500_SSP0_BASE (U8500_PER3_BASE + 0x2000) #define U8500_SSP0_BASE (U8500_PER3_BASE + 0x2000)

View File

@ -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,
};

View File

@ -15,10 +15,16 @@ if PLAT_NOMADIK
config HAS_MTU config HAS_MTU
bool bool
select HAVE_SCHED_CLOCK
help help
Support for Multi Timer Unit. MTU provides access Support for Multi Timer Unit. MTU provides access
to multiple interrupt generating programmable to multiple interrupt generating programmable
32-bit free running decrementing counters. 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 endif

View File

@ -1,54 +1,11 @@
#ifndef __PLAT_MTU_H #ifndef __PLAT_MTU_H
#define __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 */ /* should be set by the platform code */
extern void __iomem *mtu_base; extern void __iomem *mtu_base;
/* void nmdk_clkevt_reset(void);
* The MTU device hosts four different counters, with 4 set of void nmdk_clksrc_reset(void);
* 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
#endif /* __PLAT_MTU_H */ #endif /* __PLAT_MTU_H */

View File

@ -21,10 +21,59 @@
#include <asm/mach/time.h> #include <asm/mach/time.h>
#include <asm/sched_clock.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 */ void __iomem *mtu_base; /* Assigned by machine code */
#ifdef CONFIG_NOMADIK_MTU_SCHED_CLOCK
/* /*
* Override the global weak sched_clock symbol with this * Override the global weak sched_clock symbol with this
* local implementation which uses the clocksource to get some * 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)); u32 cyc = -readl(mtu_base + MTU_VAL(0));
update_sched_clock(&cd, cyc, (u32)~0); update_sched_clock(&cd, cyc, (u32)~0);
} }
#endif
/* Clockevent device: use one-shot mode */ /* 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, static void nmdk_clkevt_mode(enum clock_event_mode mode,
struct clock_event_device *dev) struct clock_event_device *dev)
{ {
u32 cr;
switch (mode) { switch (mode) {
case CLOCK_EVT_MODE_PERIODIC: case CLOCK_EVT_MODE_PERIODIC:
pr_err("%s: periodic mode not supported\n", __func__); clkevt_periodic = true;
nmdk_clkevt_reset();
break; break;
case CLOCK_EVT_MODE_ONESHOT: case CLOCK_EVT_MODE_ONESHOT:
/* Load highest value, enable device, enable interrupts */ clkevt_periodic = false;
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);
break; break;
case CLOCK_EVT_MODE_SHUTDOWN: case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_UNUSED: case CLOCK_EVT_MODE_UNUSED:
/* disable irq */
writel(0, mtu_base + MTU_IMSC); writel(0, mtu_base + MTU_IMSC);
/* disable timer */ /* disable timer */
cr = readl(mtu_base + MTU_CR(1)); writel(0, mtu_base + MTU_CR(1));
cr &= ~MTU_CRn_ENA;
writel(cr, mtu_base + MTU_CR(1));
/* load some high default value */ /* load some high default value */
writel(0xffffffff, mtu_base + MTU_LR(1)); writel(0xffffffff, mtu_base + MTU_LR(1));
break; 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 = { static struct clock_event_device nmdk_clkevt = {
.name = "mtu_1", .name = "mtu_1",
.features = CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
.rating = 200, .rating = 200,
.set_mode = nmdk_clkevt_mode, .set_mode = nmdk_clkevt_mode,
.set_next_event = nmdk_clkevt_next, .set_next_event = nmdk_clkevt_next,
@ -116,11 +182,23 @@ static struct irqaction nmdk_timer_irq = {
.dev_id = &nmdk_clkevt, .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) void __init nmdk_timer_init(void)
{ {
unsigned long rate; unsigned long rate;
struct clk *clk0; struct clk *clk0;
u32 cr = MTU_CRn_32BITS;
clk0 = clk_get_sys("mtu0", NULL); clk0 = clk_get_sys("mtu0", NULL);
BUG_ON(IS_ERR(clk0)); BUG_ON(IS_ERR(clk0));
@ -138,30 +216,28 @@ void __init nmdk_timer_init(void)
rate = clk_get_rate(clk0); rate = clk_get_rate(clk0);
if (rate > 32000000) { if (rate > 32000000) {
rate /= 16; rate /= 16;
cr |= MTU_CRn_PRESCALE_16; clk_prescale = MTU_CRn_PRESCALE_16;
} else { } 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 */ /* Timer 0 is the free running clocksource */
writel(cr, mtu_base + MTU_CR(0)); nmdk_clksrc_reset();
writel(0, mtu_base + MTU_LR(0));
writel(0, mtu_base + MTU_BGLR(0));
writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(0));
if (clocksource_mmio_init(mtu_base + MTU_VAL(0), "mtu_0", if (clocksource_mmio_init(mtu_base + MTU_VAL(0), "mtu_0",
rate, 200, 32, clocksource_mmio_readl_down)) rate, 200, 32, clocksource_mmio_readl_down))
pr_err("timer: failed to initialize clock source %s\n", pr_err("timer: failed to initialize clock source %s\n",
"mtu_0"); "mtu_0");
#ifdef CONFIG_NOMADIK_MTU_SCHED_CLOCK
init_sched_clock(&cd, nomadik_update_sched_clock, 32, rate); init_sched_clock(&cd, nomadik_update_sched_clock, 32, rate);
#endif
/* Timer 1 is used for events */ /* Timer 1 is used for events */
clockevents_calc_mult_shift(&nmdk_clkevt, rate, MTU_MIN_RANGE); 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 = nmdk_clkevt.max_delta_ns =
clockevent_delta2ns(0xffffffff, &nmdk_clkevt); clockevent_delta2ns(0xffffffff, &nmdk_clkevt);
nmdk_clkevt.min_delta_ns = nmdk_clkevt.min_delta_ns =

View File

@ -3,6 +3,12 @@
* *
* OMAP Dual-Mode Timers * 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 * Copyright (C) 2005 Nokia Corporation
* OMAP2 support by Juha Yrjola * OMAP2 support by Juha Yrjola
* API improvements and OMAP2 clock framework support by Timo Teras * API improvements and OMAP2 clock framework support by Timo Teras
@ -29,168 +35,80 @@
* 675 Mass Ave, Cambridge, MA 02139, USA. * 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/io.h>
#include <linux/module.h> #include <linux/slab.h>
#include <mach/hardware.h> #include <linux/err.h>
#include <linux/pm_runtime.h>
#include <plat/dmtimer.h> #include <plat/dmtimer.h>
#include <mach/irqs.h>
static int dm_timer_count; static LIST_HEAD(omap_timer_list);
static DEFINE_SPINLOCK(dm_timer_lock);
#ifdef CONFIG_ARCH_OMAP1 /**
static struct omap_dm_timer omap1_dm_timers[] = { * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode
{ .phys_base = 0xfffb1400, .irq = INT_1610_GPTIMER1 }, * @timer: timer pointer over which read operation to perform
{ .phys_base = 0xfffb1c00, .irq = INT_1610_GPTIMER2 }, * @reg: lowest byte holds the register offset
{ .phys_base = 0xfffb2400, .irq = INT_1610_GPTIMER3 }, *
{ .phys_base = 0xfffb2c00, .irq = INT_1610_GPTIMER4 }, * The posted mode bit is encoded in reg. Note that in posted mode write
{ .phys_base = 0xfffb3400, .irq = INT_1610_GPTIMER5 }, * pending bit must be checked. Otherwise a read of a non completed write
{ .phys_base = 0xfffb3c00, .irq = INT_1610_GPTIMER6 }, * will produce an error.
{ .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);
#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;
static spinlock_t 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.
*/ */
static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg) 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 * omap_dm_timer_write_reg - write timer registers in posted and non-posted mode
* is encoded in reg. Note that in posted mode the write pending bit must be * @timer: timer pointer over which write operation is to perform
* checked. Otherwise a write on a register which has a pending write will be * @reg: lowest byte holds the register offset
* lost. * @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, static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
u32 value) 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) static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
{ {
int c; int c;
if (!timer->sys_stat)
return;
c = 0; c = 0;
while (!(omap_dm_timer_read_reg(timer, OMAP_TIMER_SYS_STAT_REG) & 1)) { while (!(__raw_readl(timer->sys_stat) & 1)) {
c++; c++;
if (c > 100000) { if (c > 100000) {
printk(KERN_ERR "Timer failed to reset\n"); 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) static void omap_dm_timer_reset(struct omap_dm_timer *timer)
{ {
int autoidle = 0, wakeup = 0; omap_dm_timer_enable(timer);
if (timer->pdev->id != 1) {
if (!cpu_class_is_omap2() || timer != &dm_timers[0]) {
omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
omap_dm_timer_wait_for_reset(timer); omap_dm_timer_wait_for_reset(timer);
} }
omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
/* Enable autoidle on OMAP2+ */ __omap_dm_timer_reset(timer, 0, 0);
if (cpu_class_is_omap2()) omap_dm_timer_disable(timer);
autoidle = 1;
/*
* Enable wake-up on OMAP2 CPUs.
*/
if (cpu_class_is_omap2())
wakeup = 1;
__omap_dm_timer_reset(timer->io_base, autoidle, wakeup);
timer->posted = 1; 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); struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
omap_dm_timer_reset(timer); 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 *omap_dm_timer_request(void)
{ {
struct omap_dm_timer *timer = NULL; struct omap_dm_timer *timer = NULL, *t;
unsigned long flags; unsigned long flags;
int i; int ret = 0;
spin_lock_irqsave(&dm_timer_lock, flags); spin_lock_irqsave(&dm_timer_lock, flags);
for (i = 0; i < dm_timer_count; i++) { list_for_each_entry(t, &omap_timer_list, node) {
if (dm_timers[i].reserved) if (t->reserved)
continue; continue;
timer = &dm_timers[i]; timer = t;
timer->reserved = 1; timer->reserved = 1;
break; break;
} }
if (timer) {
ret = omap_dm_timer_prepare(timer);
if (ret) {
timer->reserved = 0;
timer = NULL;
}
}
spin_unlock_irqrestore(&dm_timer_lock, flags); spin_unlock_irqrestore(&dm_timer_lock, flags);
if (timer != NULL) if (!timer)
omap_dm_timer_prepare(timer); pr_debug("%s: timer request failed!\n", __func__);
return timer; 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 *omap_dm_timer_request_specific(int id)
{ {
struct omap_dm_timer *timer; struct omap_dm_timer *timer = NULL, *t;
unsigned long flags; unsigned long flags;
int ret = 0;
spin_lock_irqsave(&dm_timer_lock, flags); spin_lock_irqsave(&dm_timer_lock, flags);
if (id <= 0 || id > dm_timer_count || dm_timers[id-1].reserved) { list_for_each_entry(t, &omap_timer_list, node) {
spin_unlock_irqrestore(&dm_timer_lock, flags); if (t->pdev->id == id && !t->reserved) {
printk("BUG: warning at %s:%d/%s(): unable to get timer %d\n", timer = t;
__FILE__, __LINE__, __func__, id); timer->reserved = 1;
dump_stack(); break;
return NULL; }
} }
timer = &dm_timers[id-1]; if (timer) {
timer->reserved = 1; ret = omap_dm_timer_prepare(timer);
if (ret) {
timer->reserved = 0;
timer = NULL;
}
}
spin_unlock_irqrestore(&dm_timer_lock, flags); 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; return timer;
} }
EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific); 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); if (unlikely(!timer))
omap_dm_timer_reset(timer); return -EINVAL;
omap_dm_timer_disable(timer);
clk_put(timer->fclk);
WARN_ON(!timer->reserved); WARN_ON(!timer->reserved);
timer->reserved = 0; timer->reserved = 0;
return 0;
} }
EXPORT_SYMBOL_GPL(omap_dm_timer_free); EXPORT_SYMBOL_GPL(omap_dm_timer_free);
void omap_dm_timer_enable(struct omap_dm_timer *timer) void omap_dm_timer_enable(struct omap_dm_timer *timer)
{ {
if (timer->enabled) pm_runtime_get_sync(&timer->pdev->dev);
return;
#ifdef CONFIG_ARCH_OMAP2PLUS
if (cpu_class_is_omap2()) {
clk_enable(timer->fclk);
clk_enable(timer->iclk);
}
#endif
timer->enabled = 1;
} }
EXPORT_SYMBOL_GPL(omap_dm_timer_enable); EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
void omap_dm_timer_disable(struct omap_dm_timer *timer) void omap_dm_timer_disable(struct omap_dm_timer *timer)
{ {
if (!timer->enabled) pm_runtime_put(&timer->pdev->dev);
return;
#ifdef CONFIG_ARCH_OMAP2PLUS
if (cpu_class_is_omap2()) {
clk_disable(timer->iclk);
clk_disable(timer->fclk);
}
#endif
timer->enabled = 0;
} }
EXPORT_SYMBOL_GPL(omap_dm_timer_disable); EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
int omap_dm_timer_get_irq(struct omap_dm_timer *timer) 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); 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) __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 ARMXOR cannot be idled this function call is unnecessary */
if (!(inputmask & (1 << 1))) if (!(inputmask & (1 << 1)))
return inputmask; return inputmask;
/* If any active timer is using ARMXOR return modified mask */ /* 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; 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 (l & OMAP_TIMER_CTRL_ST) {
if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0) if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
inputmask &= ~(1 << 1); inputmask &= ~(1 << 1);
else else
inputmask &= ~(1 << 2); inputmask &= ~(1 << 2);
} }
i++;
} }
spin_unlock_irqrestore(&dm_timer_lock, flags);
return inputmask; 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) 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); EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk);
@ -375,70 +303,91 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
#endif #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); omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
return 0;
} }
EXPORT_SYMBOL_GPL(omap_dm_timer_trigger); 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; 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); l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
if (!(l & OMAP_TIMER_CTRL_ST)) { if (!(l & OMAP_TIMER_CTRL_ST)) {
l |= OMAP_TIMER_CTRL_ST; l |= OMAP_TIMER_CTRL_ST;
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); 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); 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; unsigned long rate = 0;
struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
#ifdef CONFIG_ARCH_OMAP2PLUS if (unlikely(!timer))
rate = clk_get_rate(timer->fclk); return -EINVAL;
#endif
__omap_dm_timer_stop(timer->io_base, timer->posted, rate); if (!pdata->needs_manual_reset)
} rate = clk_get_rate(timer->fclk);
EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
#ifdef CONFIG_ARCH_OMAP1 __omap_dm_timer_stop(timer, timer->posted, rate);
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);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(omap_dm_timer_set_source); EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
#else
int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
{ {
int ret;
struct dmtimer_platform_data *pdata;
if (unlikely(!timer))
return -EINVAL;
pdata = timer->pdev->dev.platform_data;
if (source < 0 || source >= 3) if (source < 0 || source >= 3)
return -EINVAL; return -EINVAL;
return __omap_dm_timer_set_source(timer->fclk, ret = pdata->set_timer_src(timer->pdev, source);
dm_source_clocks[source]);
return ret;
} }
EXPORT_SYMBOL_GPL(omap_dm_timer_set_source); EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
#endif int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
unsigned int load) unsigned int load)
{ {
u32 l; 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_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
if (autoreload) if (autoreload)
l |= OMAP_TIMER_CTRL_AR; 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_LOAD_REG, load);
omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); 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); EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
/* Optimized set_load which removes costly spin wait in timer_start */ /* 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) unsigned int load)
{ {
u32 l; 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); l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
if (autoreload) { if (autoreload) {
l |= OMAP_TIMER_CTRL_AR; 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; 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); 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) unsigned int match)
{ {
u32 l; 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_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
if (enable) if (enable)
l |= OMAP_TIMER_CTRL_CE; 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; l &= ~OMAP_TIMER_CTRL_CE;
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match); 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); 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) int toggle, int trigger)
{ {
u32 l; 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_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM | l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
OMAP_TIMER_CTRL_PT | (0x03 << 10)); 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 |= OMAP_TIMER_CTRL_PT;
l |= trigger << 10; l |= trigger << 10;
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); 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); 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; 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_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2)); l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
if (prescaler >= 0x00 && prescaler <= 0x07) { 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; l |= prescaler << 2;
} }
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); 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); 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) 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); 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; 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; return l;
} }
EXPORT_SYMBOL_GPL(omap_dm_timer_read_status); 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); EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) 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); 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); 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); EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
int omap_dm_timers_active(void) int omap_dm_timers_active(void)
{ {
int i; struct omap_dm_timer *timer;
for (i = 0; i < dm_timer_count; i++) { list_for_each_entry(timer, &omap_timer_list, node) {
struct omap_dm_timer *timer; if (!timer->reserved)
timer = &dm_timers[i];
if (!timer->enabled)
continue; continue;
if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) & 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); 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; 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; 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;
} }
if (cpu_class_is_omap2()) irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
for (i = 0; dm_source_names[i] != NULL; i++) if (unlikely(!irq)) {
dm_source_clocks[i] = clk_get(NULL, dm_source_names[i]); dev_err(&pdev->dev, "%s: no IRQ resource.\n", __func__);
return -ENODEV;
if (cpu_is_omap243x())
dm_timers[0].phys_base = 0x49018000;
for (i = 0; i < dm_timer_count; i++) {
timer = &dm_timers[i];
/* Static mapping, never released */
timer->io_base = ioremap(timer->phys_base, map_size);
BUG_ON(!timer->io_base);
#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);
}
/* 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
} }
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (unlikely(!mem)) {
dev_err(&pdev->dev, "%s: no memory resource.\n", __func__);
return -ENODEV;
}
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;
}
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;
}
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;
}
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);
}
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; 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");

View 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 * OMAP Dual-Mode Timers
* *
@ -35,6 +35,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/platform_device.h>
#ifndef __ASM_ARCH_DMTIMER_H #ifndef __ASM_ARCH_DMTIMER_H
#define __ASM_ARCH_DMTIMER_H #define __ASM_ARCH_DMTIMER_H
@ -59,12 +60,56 @@
* in OMAP4 can be distinguished. * in OMAP4 can be distinguished.
*/ */
#define OMAP_TIMER_IP_VERSION_1 0x1 #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 omap_dm_timer;
struct clk; 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(void);
struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id); 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_enable(struct omap_dm_timer *timer);
void omap_dm_timer_disable(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); u32 omap_dm_timer_modify_idlect_mask(u32 inputmask);
struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer); struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer);
void omap_dm_timer_trigger(struct omap_dm_timer *timer); int omap_dm_timer_trigger(struct omap_dm_timer *timer);
void omap_dm_timer_start(struct omap_dm_timer *timer); int omap_dm_timer_start(struct omap_dm_timer *timer);
void omap_dm_timer_stop(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); 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); int 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); int 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); int 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); int 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_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); 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); 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); 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. * used by dmtimer.c and sys_timer related code.
*/ */
/* register offsets */ /*
#define _OMAP_TIMER_ID_OFFSET 0x00 * The interrupt registers are different between v1 and v2 ip.
#define _OMAP_TIMER_OCP_CFG_OFFSET 0x10 * These registers are offsets from timer->iobase.
#define _OMAP_TIMER_SYS_STAT_OFFSET 0x14 */
#define _OMAP_TIMER_STAT_OFFSET 0x18 #define OMAP_TIMER_ID_OFFSET 0x00
#define _OMAP_TIMER_INT_EN_OFFSET 0x1c #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_WAKEUP_EN_OFFSET 0x20
#define _OMAP_TIMER_CTRL_OFFSET 0x24 #define _OMAP_TIMER_CTRL_OFFSET 0x24
#define OMAP_TIMER_CTRL_GPOCFG (1 << 14) #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 */ /* register offsets with the write pending bit encoded */
#define WPSHIFT 16 #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 \ #define OMAP_TIMER_WAKEUP_EN_REG (_OMAP_TIMER_WAKEUP_EN_OFFSET \
| (WP_NONE << WPSHIFT)) | (WP_NONE << WPSHIFT))
@ -209,49 +257,88 @@ int omap_dm_timers_active(void);
struct omap_dm_timer { struct omap_dm_timer {
unsigned long phys_base; unsigned long phys_base;
int id;
int irq; int irq;
#ifdef CONFIG_ARCH_OMAP2PLUS
struct clk *iclk, *fclk; 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 long rate;
unsigned reserved:1; unsigned reserved:1;
unsigned enabled:1;
unsigned posted: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; int omap_dm_timer_prepare(struct omap_dm_timer *timer);
void 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) int posted)
{ {
if (posted) if (posted)
while (__raw_readl(base + (OMAP_TIMER_WRITE_PEND_REG & 0xff)) while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
& (reg >> WPSHIFT))
cpu_relax(); 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, static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
int posted) u32 reg, u32 val, int posted)
{ {
if (posted) if (posted)
while (__raw_readl(base + (OMAP_TIMER_WRITE_PEND_REG & 0xff)) while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
& (reg >> WPSHIFT))
cpu_relax(); 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 */ /* Assumes the source clock has been set by caller */
static inline void __omap_dm_timer_reset(void __iomem *base, int autoidle, static inline void __omap_dm_timer_reset(struct omap_dm_timer *timer,
int wakeup) int autoidle, int wakeup)
{ {
u32 l; 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 |= 0x02 << 3; /* Set to smart-idle mode */
l |= 0x2 << 8; /* Set clock activity to perserve f-clock on idle */ 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) if (wakeup)
l |= 1 << 2; 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 */ /* 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); OMAP_TIMER_CTRL_POSTED, 0);
} }
@ -286,18 +373,18 @@ static inline int __omap_dm_timer_set_source(struct clk *timer_fck,
return ret; return ret;
} }
static inline void __omap_dm_timer_stop(void __iomem *base, int posted, static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer,
unsigned long rate) int posted, unsigned long rate)
{ {
u32 l; 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) { if (l & OMAP_TIMER_CTRL_ST) {
l &= ~0x1; 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 #ifdef CONFIG_ARCH_OMAP2PLUS
/* Readback to make sure write has completed */ /* 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 * Wait for functional clock period x 3.5 to make sure that
* timer is stopped * timer is stopped
@ -307,34 +394,34 @@ static inline void __omap_dm_timer_stop(void __iomem *base, int posted,
} }
/* Ack possibly pending interrupt */ /* Ack possibly pending interrupt */
__omap_dm_timer_write(base, OMAP_TIMER_STAT_REG, __raw_writel(OMAP_TIMER_INT_OVERFLOW, timer->irq_stat);
OMAP_TIMER_INT_OVERFLOW, 0);
} }
static inline void __omap_dm_timer_load_start(void __iomem *base, u32 ctrl, static inline void __omap_dm_timer_load_start(struct omap_dm_timer *timer,
unsigned int load, int posted) u32 ctrl, unsigned int load,
int posted)
{ {
__omap_dm_timer_write(base, OMAP_TIMER_COUNTER_REG, load, posted); __omap_dm_timer_write(timer, OMAP_TIMER_COUNTER_REG, load, posted);
__omap_dm_timer_write(base, OMAP_TIMER_CTRL_REG, ctrl, 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) unsigned int value)
{ {
__omap_dm_timer_write(base, OMAP_TIMER_INT_EN_REG, value, 0); __raw_writel(value, timer->irq_ena);
__omap_dm_timer_write(base, OMAP_TIMER_WAKEUP_EN_REG, value, 0); __omap_dm_timer_write(timer, OMAP_TIMER_WAKEUP_EN_REG, value, 0);
} }
static inline unsigned int __omap_dm_timer_read_counter(void __iomem *base, static inline unsigned int
int posted) __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) 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 */ #endif /* __ASM_ARCH_DMTIMER_H */

View File

@ -15,3 +15,18 @@ config CLKSRC_MMIO
config DW_APB_TIMER config DW_APB_TIMER
bool 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

View File

@ -9,3 +9,4 @@ obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o
obj-$(CONFIG_CLKBLD_I8253) += i8253.o obj-$(CONFIG_CLKBLD_I8253) += i8253.o
obj-$(CONFIG_CLKSRC_MMIO) += mmio.o obj-$(CONFIG_CLKSRC_MMIO) += mmio.o
obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o
obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o

View File

@ -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);
}

View File

@ -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