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