xref: /OK3568_Linux_fs/kernel/arch/arm/mach-omap1/timer.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /**
2*4882a593Smuzhiyun  * OMAP1 Dual-Mode Timers - platform device registration
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Contains first level initialization routines which internally
5*4882a593Smuzhiyun  * generates timer device information and registers with linux
6*4882a593Smuzhiyun  * device model. It also has a low level function to change the timer
7*4882a593Smuzhiyun  * input clock source.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/
10*4882a593Smuzhiyun  * Tarun Kanti DebBarma <tarun.kanti@ti.com>
11*4882a593Smuzhiyun  * Thara Gopinath <thara@ti.com>
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or modify
14*4882a593Smuzhiyun  * it under the terms of the GNU General Public License version 2 as
15*4882a593Smuzhiyun  * published by the Free Software Foundation.
16*4882a593Smuzhiyun  *
17*4882a593Smuzhiyun  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
18*4882a593Smuzhiyun  * kind, whether express or implied; without even the implied warranty
19*4882a593Smuzhiyun  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20*4882a593Smuzhiyun  * GNU General Public License for more details.
21*4882a593Smuzhiyun  */
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #include <linux/clk.h>
24*4882a593Smuzhiyun #include <linux/io.h>
25*4882a593Smuzhiyun #include <linux/err.h>
26*4882a593Smuzhiyun #include <linux/slab.h>
27*4882a593Smuzhiyun #include <linux/platform_device.h>
28*4882a593Smuzhiyun #include <linux/platform_data/dmtimer-omap.h>
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun #include <clocksource/timer-ti-dm.h>
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun #include "soc.h"
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #define OMAP1610_GPTIMER1_BASE		0xfffb1400
35*4882a593Smuzhiyun #define OMAP1610_GPTIMER2_BASE		0xfffb1c00
36*4882a593Smuzhiyun #define OMAP1610_GPTIMER3_BASE		0xfffb2400
37*4882a593Smuzhiyun #define OMAP1610_GPTIMER4_BASE		0xfffb2c00
38*4882a593Smuzhiyun #define OMAP1610_GPTIMER5_BASE		0xfffb3400
39*4882a593Smuzhiyun #define OMAP1610_GPTIMER6_BASE		0xfffb3c00
40*4882a593Smuzhiyun #define OMAP1610_GPTIMER7_BASE		0xfffb7400
41*4882a593Smuzhiyun #define OMAP1610_GPTIMER8_BASE		0xfffbd400
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #define OMAP1_DM_TIMER_COUNT		8
44*4882a593Smuzhiyun 
omap1_dm_timer_set_src(struct platform_device * pdev,int source)45*4882a593Smuzhiyun static int omap1_dm_timer_set_src(struct platform_device *pdev,
46*4882a593Smuzhiyun 				int source)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun 	int n = (pdev->id - 1) << 1;
49*4882a593Smuzhiyun 	u32 l;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n);
52*4882a593Smuzhiyun 	l |= source << n;
53*4882a593Smuzhiyun 	omap_writel(l, MOD_CONF_CTRL_1);
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	return 0;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun 
omap1_dm_timer_init(void)58*4882a593Smuzhiyun static int __init omap1_dm_timer_init(void)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun 	int i;
61*4882a593Smuzhiyun 	int ret;
62*4882a593Smuzhiyun 	struct dmtimer_platform_data *pdata;
63*4882a593Smuzhiyun 	struct platform_device *pdev;
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	if (!cpu_is_omap16xx())
66*4882a593Smuzhiyun 		return 0;
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	for (i = 1; i <= OMAP1_DM_TIMER_COUNT; i++) {
69*4882a593Smuzhiyun 		struct resource res[2];
70*4882a593Smuzhiyun 		u32 base, irq;
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 		switch (i) {
73*4882a593Smuzhiyun 		case 1:
74*4882a593Smuzhiyun 			base = OMAP1610_GPTIMER1_BASE;
75*4882a593Smuzhiyun 			irq = INT_1610_GPTIMER1;
76*4882a593Smuzhiyun 			break;
77*4882a593Smuzhiyun 		case 2:
78*4882a593Smuzhiyun 			base = OMAP1610_GPTIMER2_BASE;
79*4882a593Smuzhiyun 			irq = INT_1610_GPTIMER2;
80*4882a593Smuzhiyun 			break;
81*4882a593Smuzhiyun 		case 3:
82*4882a593Smuzhiyun 			base = OMAP1610_GPTIMER3_BASE;
83*4882a593Smuzhiyun 			irq = INT_1610_GPTIMER3;
84*4882a593Smuzhiyun 			break;
85*4882a593Smuzhiyun 		case 4:
86*4882a593Smuzhiyun 			base = OMAP1610_GPTIMER4_BASE;
87*4882a593Smuzhiyun 			irq = INT_1610_GPTIMER4;
88*4882a593Smuzhiyun 			break;
89*4882a593Smuzhiyun 		case 5:
90*4882a593Smuzhiyun 			base = OMAP1610_GPTIMER5_BASE;
91*4882a593Smuzhiyun 			irq = INT_1610_GPTIMER5;
92*4882a593Smuzhiyun 			break;
93*4882a593Smuzhiyun 		case 6:
94*4882a593Smuzhiyun 			base = OMAP1610_GPTIMER6_BASE;
95*4882a593Smuzhiyun 			irq = INT_1610_GPTIMER6;
96*4882a593Smuzhiyun 			break;
97*4882a593Smuzhiyun 		case 7:
98*4882a593Smuzhiyun 			base = OMAP1610_GPTIMER7_BASE;
99*4882a593Smuzhiyun 			irq = INT_1610_GPTIMER7;
100*4882a593Smuzhiyun 			break;
101*4882a593Smuzhiyun 		case 8:
102*4882a593Smuzhiyun 			base = OMAP1610_GPTIMER8_BASE;
103*4882a593Smuzhiyun 			irq = INT_1610_GPTIMER8;
104*4882a593Smuzhiyun 			break;
105*4882a593Smuzhiyun 		default:
106*4882a593Smuzhiyun 			/*
107*4882a593Smuzhiyun 			 * not supposed to reach here.
108*4882a593Smuzhiyun 			 * this is to remove warning.
109*4882a593Smuzhiyun 			 */
110*4882a593Smuzhiyun 			return -EINVAL;
111*4882a593Smuzhiyun 		}
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 		pdev = platform_device_alloc("omap_timer", i);
114*4882a593Smuzhiyun 		if (!pdev) {
115*4882a593Smuzhiyun 			pr_err("%s: Failed to device alloc for dmtimer%d\n",
116*4882a593Smuzhiyun 				__func__, i);
117*4882a593Smuzhiyun 			return -ENOMEM;
118*4882a593Smuzhiyun 		}
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 		memset(res, 0, 2 * sizeof(struct resource));
121*4882a593Smuzhiyun 		res[0].start = base;
122*4882a593Smuzhiyun 		res[0].end = base + 0x46;
123*4882a593Smuzhiyun 		res[0].flags = IORESOURCE_MEM;
124*4882a593Smuzhiyun 		res[1].start = irq;
125*4882a593Smuzhiyun 		res[1].end = irq;
126*4882a593Smuzhiyun 		res[1].flags = IORESOURCE_IRQ;
127*4882a593Smuzhiyun 		ret = platform_device_add_resources(pdev, res,
128*4882a593Smuzhiyun 				ARRAY_SIZE(res));
129*4882a593Smuzhiyun 		if (ret) {
130*4882a593Smuzhiyun 			dev_err(&pdev->dev, "%s: Failed to add resources.\n",
131*4882a593Smuzhiyun 				__func__);
132*4882a593Smuzhiyun 			goto err_free_pdev;
133*4882a593Smuzhiyun 		}
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 		pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
136*4882a593Smuzhiyun 		if (!pdata) {
137*4882a593Smuzhiyun 			ret = -ENOMEM;
138*4882a593Smuzhiyun 			goto err_free_pdata;
139*4882a593Smuzhiyun 		}
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 		pdata->set_timer_src = omap1_dm_timer_set_src;
142*4882a593Smuzhiyun 		pdata->timer_capability = OMAP_TIMER_ALWON |
143*4882a593Smuzhiyun 				OMAP_TIMER_NEEDS_RESET | OMAP_TIMER_HAS_DSP_IRQ;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 		ret = platform_device_add_data(pdev, pdata, sizeof(*pdata));
146*4882a593Smuzhiyun 		if (ret) {
147*4882a593Smuzhiyun 			dev_err(&pdev->dev, "%s: Failed to add platform data.\n",
148*4882a593Smuzhiyun 				__func__);
149*4882a593Smuzhiyun 			goto err_free_pdata;
150*4882a593Smuzhiyun 		}
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 		ret = platform_device_add(pdev);
153*4882a593Smuzhiyun 		if (ret) {
154*4882a593Smuzhiyun 			dev_err(&pdev->dev, "%s: Failed to add platform device.\n",
155*4882a593Smuzhiyun 				__func__);
156*4882a593Smuzhiyun 			goto err_free_pdata;
157*4882a593Smuzhiyun 		}
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 		dev_dbg(&pdev->dev, " Registered.\n");
160*4882a593Smuzhiyun 	}
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	return 0;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun err_free_pdata:
165*4882a593Smuzhiyun 	kfree(pdata);
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun err_free_pdev:
168*4882a593Smuzhiyun 	platform_device_unregister(pdev);
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	return ret;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun arch_initcall(omap1_dm_timer_init);
173