]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/misc/sti/sdti.c
Merge branch 'omap-fixes'
[linux-2.6-omap-h63xx.git] / drivers / misc / sti / sdti.c
1 /*
2  * Support functions for OMAP3 SDTI (Serial Debug Tracing Interface)
3  *
4  * Copyright (C) 2008 Nokia Corporation
5  * Written by: Roman Tereshonkov <roman.tereshonkov@nokia.com>
6  *
7  * This file is subject to the terms and conditions of the GNU General Public
8  * License.  See the file "COPYING" in the main directory of this archive
9  * for more details.
10  */
11 #include <linux/init.h>
12 #include <linux/err.h>
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/spinlock.h>
16 #include <linux/interrupt.h>
17 #include <linux/platform_device.h>
18 #include <linux/clk.h>
19 #include <mach/sti.h>
20 #include <asm/byteorder.h>
21 #include <asm/io.h>
22
23 #define SDTI_REVISION           0x000
24 #define SDTI_SYSCONFIG          0x010
25 #define SDTI_SYSSTATUS          0x014
26 #define SDTI_WINCTRL            0x024
27 #define SDTI_SCONFIG            0x028
28 #define SDTI_TESTCTRL           0x02C
29 #define SDTI_LOCK_ACCESS        0xFB0
30
31 #define CPU1_TRACE_EN           0x01
32 #define CPU2_TRACE_EN           0x02
33
34 #define SDTI_SYSCONFIG_SOFTRESET        (1 << 1)
35 #define SDTI_SYSCONFIG_AUTOIDLE         (1 << 0)
36
37 static struct clk *sdti_fck, *sdti_ick;
38 void __iomem *sti_base, *sti_channel_base;
39 static DEFINE_SPINLOCK(sdti_lock);
40 static int sdti_initialized;
41
42 void sti_channel_write_trace(int len, int id, void *data,
43                                 unsigned int channel)
44 {
45         const u8 *tpntr = data;
46         unsigned long flags;
47
48         spin_lock_irqsave(&sdti_lock, flags);
49
50         if (unlikely(!sdti_initialized))
51                 goto skip;
52
53         sti_channel_writeb(id, channel);
54         while (len--)
55                 sti_channel_writeb(*tpntr++, channel);
56         sti_channel_flush(channel);
57  skip:
58         spin_unlock_irqrestore(&sdti_lock, flags);
59 }
60 EXPORT_SYMBOL(sti_channel_write_trace);
61
62 static void omap_sdti_reset(void)
63 {
64         int i;
65
66         sti_writel(SDTI_SYSCONFIG_SOFTRESET, SDTI_SYSCONFIG);
67
68         for (i = 0; i < 10000; i++)
69                 if (sti_readl(SDTI_SYSSTATUS) & 1)
70                         break;
71         if (i == 10000)
72                 printk(KERN_WARNING "XTI: no real reset\n");
73 }
74
75 static int __init omap_sdti_init(void)
76 {
77         char buf[64];
78         int i, ret = 0;
79
80         sdti_fck = clk_get(NULL, "pclk_fck");
81         if (IS_ERR(sdti_fck)) {
82                 printk(KERN_ERR "Cannot get clk pclk_fck\n");
83                 ret = PTR_ERR(sdti_fck);
84                 goto err0;
85         }
86         sdti_ick = clk_get(NULL, "pclkx2_fck");
87         if (IS_ERR(sdti_ick)) {
88                 printk(KERN_ERR "Cannot get clk pclkx2_fck\n");
89                 ret = PTR_ERR(sdti_ick);
90                 goto err1;
91         }
92         ret = clk_enable(sdti_fck);
93         if (ret) {
94                 printk(KERN_ERR "Cannot enable sdti_fck\n");
95                 goto err2;
96         }
97         ret = clk_enable(sdti_ick);
98         if (ret) {
99                 printk(KERN_ERR "Cannot enable sdti_ick\n");
100                 goto err3;
101         }
102
103         omap_sdti_reset();
104         sti_writel(0xC5ACCE55, SDTI_LOCK_ACCESS);
105
106         /* Autoidle */
107         sti_writel(SDTI_SYSCONFIG_AUTOIDLE, SDTI_SYSCONFIG);
108
109         /* Claim SDTI */
110         sti_writel(1 << 30, SDTI_WINCTRL);
111         i = sti_readl(SDTI_WINCTRL);
112         if (!(i & (1 << 30)))
113                 printk(KERN_WARNING "SDTI: cannot claim SDTI\n");
114
115         /* 4 bits dual, fclk/3 */
116         sti_writel(0x43, SDTI_SCONFIG);
117
118         /* CPU2 trace enable */
119         sti_writel(i | CPU2_TRACE_EN, SDTI_WINCTRL);
120         i = sti_readl(SDTI_WINCTRL);
121
122         /* Enable SDTI */
123         sti_writel((1 << 31) | (i & 0x3FFFFFFF), SDTI_WINCTRL);
124
125         spin_lock_irq(&sdti_lock);
126         sdti_initialized = 1;
127         spin_unlock_irq(&sdti_lock);
128
129         i = sti_readl(SDTI_REVISION);
130         snprintf(buf, sizeof(buf), "OMAP SDTI support loaded (HW v%u.%u)\n",
131                 (i >> 4) & 0x0f, i & 0x0f);
132         printk(KERN_INFO "%s", buf);
133         sti_channel_write_trace(strlen(buf), 0xc3, buf, 239);
134
135         return ret;
136
137 err3:
138         clk_disable(sdti_fck);
139 err2:
140         clk_put(sdti_ick);
141 err1:
142         clk_put(sdti_fck);
143 err0:
144         return ret;
145 }
146
147 static void omap_sdti_exit(void)
148 {
149         sti_writel(0, SDTI_WINCTRL);
150         clk_disable(sdti_fck);
151         clk_disable(sdti_ick);
152         clk_put(sdti_fck);
153         clk_put(sdti_ick);
154 }
155
156 static int __devinit omap_sdti_probe(struct platform_device *pdev)
157 {
158         struct resource *res, *cres;
159         unsigned int size;
160
161         if (pdev->num_resources != 2) {
162                 dev_err(&pdev->dev, "invalid number of resources: %d\n",
163                         pdev->num_resources);
164                 return -ENODEV;
165         }
166
167         /* SDTI base */
168         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
169         if (unlikely(!res)) {
170                 dev_err(&pdev->dev, "invalid mem resource\n");
171                 return -ENODEV;
172         }
173
174         /* Channel base */
175         cres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
176         if (unlikely(!cres)) {
177                 dev_err(&pdev->dev, "invalid channel mem resource\n");
178                 return -ENODEV;
179         }
180
181         size = res->end - res->start;
182         sti_base = ioremap(res->start, size);
183         if (unlikely(!sti_base))
184                 return -ENODEV;
185
186         size = cres->end - cres->start;
187         sti_channel_base = ioremap(cres->start, size);
188         if (unlikely(!sti_channel_base)) {
189                 iounmap(sti_base);
190                 return -ENODEV;
191         }
192
193         return omap_sdti_init();
194 }
195
196 static int __devexit omap_sdti_remove(struct platform_device *pdev)
197 {
198         iounmap(sti_channel_base);
199         iounmap(sti_base);
200         omap_sdti_exit();
201
202         return 0;
203 }
204
205 static struct platform_driver omap_sdti_driver = {
206         .probe          = omap_sdti_probe,
207         .remove         = __devexit_p(omap_sdti_remove),
208         .driver         = {
209                 .name   = "sti",
210                 .owner  = THIS_MODULE,
211         },
212 };
213
214 static int __init omap_sdti_module_init(void)
215 {
216         return platform_driver_register(&omap_sdti_driver);
217 }
218
219 static void __exit omap_sdti_module_exit(void)
220 {
221         platform_driver_unregister(&omap_sdti_driver);
222 }
223 subsys_initcall(omap_sdti_module_init);
224 module_exit(omap_sdti_module_exit);
225
226 MODULE_AUTHOR("Roman Tereshonkov");
227 MODULE_LICENSE("GPL");