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