Merge branch 'drm-intel-fixes' of git://people.freedesktop.org/~keithp/linux into...
[pandora-kernel.git] / arch / arm / mach-omap2 / usb-tusb6010.c
1 /*
2  * linux/arch/arm/mach-omap2/usb-tusb6010.c
3  *
4  * Copyright (C) 2006 Nokia Corporation
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10
11 #include <linux/string.h>
12 #include <linux/types.h>
13 #include <linux/errno.h>
14 #include <linux/delay.h>
15 #include <linux/platform_device.h>
16 #include <linux/gpio.h>
17 #include <linux/export.h>
18
19 #include <linux/usb/musb.h>
20
21 #include <plat/gpmc.h>
22
23 #include "mux.h"
24
25 static u8               async_cs, sync_cs;
26 static unsigned         refclk_psec;
27
28
29 /* t2_ps, when quantized to fclk units, must happen no earlier than
30  * the clock after after t1_NS.
31  *
32  * Return a possibly updated value of t2_ps, converted to nsec.
33  */
34 static unsigned
35 next_clk(unsigned t1_NS, unsigned t2_ps, unsigned fclk_ps)
36 {
37         unsigned        t1_ps = t1_NS * 1000;
38         unsigned        t1_f, t2_f;
39
40         if ((t1_ps + fclk_ps) < t2_ps)
41                 return t2_ps / 1000;
42
43         t1_f = (t1_ps + fclk_ps - 1) / fclk_ps;
44         t2_f = (t2_ps + fclk_ps - 1) / fclk_ps;
45
46         if (t1_f >= t2_f)
47                 t2_f = t1_f + 1;
48
49         return (t2_f * fclk_ps) / 1000;
50 }
51
52 /* NOTE:  timings are from tusb 6010 datasheet Rev 1.8, 12-Sept 2006 */
53
54 static int tusb_set_async_mode(unsigned sysclk_ps, unsigned fclk_ps)
55 {
56         struct gpmc_timings     t;
57         unsigned                t_acsnh_advnh = sysclk_ps + 3000;
58         unsigned                tmp;
59
60         memset(&t, 0, sizeof(t));
61
62         /* CS_ON = t_acsnh_acsnl */
63         t.cs_on = 8;
64         /* ADV_ON = t_acsnh_advnh - t_advn */
65         t.adv_on = next_clk(t.cs_on, t_acsnh_advnh - 7000, fclk_ps);
66
67         /*
68          * READ ... from omap2420 TRM fig 12-13
69          */
70
71         /* ADV_RD_OFF = t_acsnh_advnh */
72         t.adv_rd_off = next_clk(t.adv_on, t_acsnh_advnh, fclk_ps);
73
74         /* OE_ON = t_acsnh_advnh + t_advn_oen (then wait for nRDY) */
75         t.oe_on = next_clk(t.adv_on, t_acsnh_advnh + 1000, fclk_ps);
76
77         /* ACCESS = counters continue only after nRDY */
78         tmp = t.oe_on * 1000 + 300;
79         t.access = next_clk(t.oe_on, tmp, fclk_ps);
80
81         /* OE_OFF = after data gets sampled */
82         tmp = t.access * 1000;
83         t.oe_off = next_clk(t.access, tmp, fclk_ps);
84
85         t.cs_rd_off = t.oe_off;
86
87         tmp = t.cs_rd_off * 1000 + 7000 /* t_acsn_rdy_z */;
88         t.rd_cycle = next_clk(t.cs_rd_off, tmp, fclk_ps);
89
90         /*
91          * WRITE ... from omap2420 TRM fig 12-15
92          */
93
94         /* ADV_WR_OFF = t_acsnh_advnh */
95         t.adv_wr_off = t.adv_rd_off;
96
97         /* WE_ON = t_acsnh_advnh + t_advn_wen (then wait for nRDY) */
98         t.we_on = next_clk(t.adv_wr_off, t_acsnh_advnh + 1000, fclk_ps);
99
100         /* WE_OFF = after data gets sampled */
101         tmp = t.we_on * 1000 + 300;
102         t.we_off = next_clk(t.we_on, tmp, fclk_ps);
103
104         t.cs_wr_off = t.we_off;
105
106         tmp = t.cs_wr_off * 1000 + 7000 /* t_acsn_rdy_z */;
107         t.wr_cycle = next_clk(t.cs_wr_off, tmp, fclk_ps);
108
109         return gpmc_cs_set_timings(async_cs, &t);
110 }
111
112 static int tusb_set_sync_mode(unsigned sysclk_ps, unsigned fclk_ps)
113 {
114         struct gpmc_timings     t;
115         unsigned                t_scsnh_advnh = sysclk_ps + 3000;
116         unsigned                tmp;
117
118         memset(&t, 0, sizeof(t));
119         t.cs_on = 8;
120
121         /* ADV_ON = t_acsnh_advnh - t_advn */
122         t.adv_on = next_clk(t.cs_on, t_scsnh_advnh - 7000, fclk_ps);
123
124         /* GPMC_CLK rate = fclk rate / div */
125         t.sync_clk = 11100 /* 11.1 nsec */;
126         tmp = (t.sync_clk + fclk_ps - 1) / fclk_ps;
127         if (tmp > 4)
128                 return -ERANGE;
129         if (tmp <= 0)
130                 tmp = 1;
131         t.page_burst_access = (fclk_ps * tmp) / 1000;
132
133         /*
134          * READ ... based on omap2420 TRM fig 12-19, 12-20
135          */
136
137         /* ADV_RD_OFF = t_scsnh_advnh */
138         t.adv_rd_off = next_clk(t.adv_on, t_scsnh_advnh, fclk_ps);
139
140         /* OE_ON = t_scsnh_advnh + t_advn_oen * fclk_ps (then wait for nRDY) */
141         tmp = (t.adv_rd_off * 1000) + (3 * fclk_ps);
142         t.oe_on = next_clk(t.adv_on, tmp, fclk_ps);
143
144         /* ACCESS = number of clock cycles after t_adv_eon */
145         tmp = (t.oe_on * 1000) + (5 * fclk_ps);
146         t.access = next_clk(t.oe_on, tmp, fclk_ps);
147
148         /* OE_OFF = after data gets sampled */
149         tmp = (t.access * 1000) + (1 * fclk_ps);
150         t.oe_off = next_clk(t.access, tmp, fclk_ps);
151
152         t.cs_rd_off = t.oe_off;
153
154         tmp = t.cs_rd_off * 1000 + 7000 /* t_scsn_rdy_z */;
155         t.rd_cycle = next_clk(t.cs_rd_off, tmp, fclk_ps);
156
157         /*
158          * WRITE ... based on omap2420 TRM fig 12-21
159          */
160
161         /* ADV_WR_OFF = t_scsnh_advnh */
162         t.adv_wr_off = t.adv_rd_off;
163
164         /* WE_ON = t_scsnh_advnh + t_advn_wen * fclk_ps (then wait for nRDY) */
165         tmp = (t.adv_wr_off * 1000) + (3 * fclk_ps);
166         t.we_on = next_clk(t.adv_wr_off, tmp, fclk_ps);
167
168         /* WE_OFF = number of clock cycles after t_adv_wen */
169         tmp = (t.we_on * 1000) + (6 * fclk_ps);
170         t.we_off = next_clk(t.we_on, tmp, fclk_ps);
171
172         t.cs_wr_off = t.we_off;
173
174         tmp = t.cs_wr_off * 1000 + 7000 /* t_scsn_rdy_z */;
175         t.wr_cycle = next_clk(t.cs_wr_off, tmp, fclk_ps);
176
177         return gpmc_cs_set_timings(sync_cs, &t);
178 }
179
180 extern unsigned long gpmc_get_fclk_period(void);
181
182 /* tusb driver calls this when it changes the chip's clocking */
183 int tusb6010_platform_retime(unsigned is_refclk)
184 {
185         static const char       error[] =
186                 KERN_ERR "tusb6010 %s retime error %d\n";
187
188         unsigned        fclk_ps = gpmc_get_fclk_period();
189         unsigned        sysclk_ps;
190         int             status;
191
192         if (!refclk_psec || fclk_ps == 0)
193                 return -ENODEV;
194
195         sysclk_ps = is_refclk ? refclk_psec : TUSB6010_OSCCLK_60;
196
197         status = tusb_set_async_mode(sysclk_ps, fclk_ps);
198         if (status < 0) {
199                 printk(error, "async", status);
200                 goto done;
201         }
202         status = tusb_set_sync_mode(sysclk_ps, fclk_ps);
203         if (status < 0)
204                 printk(error, "sync", status);
205 done:
206         return status;
207 }
208 EXPORT_SYMBOL_GPL(tusb6010_platform_retime);
209
210 static struct resource tusb_resources[] = {
211         /* Order is significant!  The start/end fields
212          * are updated during setup..
213          */
214         { /* Asynchronous access */
215                 .flags  = IORESOURCE_MEM,
216         },
217         { /* Synchronous access */
218                 .flags  = IORESOURCE_MEM,
219         },
220         { /* IRQ */
221                 .name   = "mc",
222                 .flags  = IORESOURCE_IRQ,
223         },
224 };
225
226 static u64 tusb_dmamask = ~(u32)0;
227
228 static struct platform_device tusb_device = {
229         .name           = "musb-tusb",
230         .id             = -1,
231         .dev = {
232                 .dma_mask               = &tusb_dmamask,
233                 .coherent_dma_mask      = 0xffffffff,
234         },
235         .num_resources  = ARRAY_SIZE(tusb_resources),
236         .resource       = tusb_resources,
237 };
238
239
240 /* this may be called only from board-*.c setup code */
241 int __init
242 tusb6010_setup_interface(struct musb_hdrc_platform_data *data,
243                 unsigned ps_refclk, unsigned waitpin,
244                 unsigned async, unsigned sync,
245                 unsigned irq, unsigned dmachan)
246 {
247         int             status;
248         static char     error[] __initdata =
249                 KERN_ERR "tusb6010 init error %d, %d\n";
250
251         /* ASYNC region, primarily for PIO */
252         status = gpmc_cs_request(async, SZ_16M, (unsigned long *)
253                                 &tusb_resources[0].start);
254         if (status < 0) {
255                 printk(error, 1, status);
256                 return status;
257         }
258         tusb_resources[0].end = tusb_resources[0].start + 0x9ff;
259         async_cs = async;
260         gpmc_cs_write_reg(async, GPMC_CS_CONFIG1,
261                           GPMC_CONFIG1_PAGE_LEN(2)
262                         | GPMC_CONFIG1_WAIT_READ_MON
263                         | GPMC_CONFIG1_WAIT_WRITE_MON
264                         | GPMC_CONFIG1_WAIT_PIN_SEL(waitpin)
265                         | GPMC_CONFIG1_READTYPE_ASYNC
266                         | GPMC_CONFIG1_WRITETYPE_ASYNC
267                         | GPMC_CONFIG1_DEVICESIZE_16
268                         | GPMC_CONFIG1_DEVICETYPE_NOR
269                         | GPMC_CONFIG1_MUXADDDATA);
270
271
272         /* SYNC region, primarily for DMA */
273         status = gpmc_cs_request(sync, SZ_16M, (unsigned long *)
274                                 &tusb_resources[1].start);
275         if (status < 0) {
276                 printk(error, 2, status);
277                 return status;
278         }
279         tusb_resources[1].end = tusb_resources[1].start + 0x9ff;
280         sync_cs = sync;
281         gpmc_cs_write_reg(sync, GPMC_CS_CONFIG1,
282                           GPMC_CONFIG1_READMULTIPLE_SUPP
283                         | GPMC_CONFIG1_READTYPE_SYNC
284                         | GPMC_CONFIG1_WRITEMULTIPLE_SUPP
285                         | GPMC_CONFIG1_WRITETYPE_SYNC
286                         | GPMC_CONFIG1_CLKACTIVATIONTIME(1)
287                         | GPMC_CONFIG1_PAGE_LEN(2)
288                         | GPMC_CONFIG1_WAIT_READ_MON
289                         | GPMC_CONFIG1_WAIT_WRITE_MON
290                         | GPMC_CONFIG1_WAIT_PIN_SEL(waitpin)
291                         | GPMC_CONFIG1_DEVICESIZE_16
292                         | GPMC_CONFIG1_DEVICETYPE_NOR
293                         | GPMC_CONFIG1_MUXADDDATA
294                         /* fclk divider gets set later */
295                         );
296
297         /* IRQ */
298         status = gpio_request_one(irq, GPIOF_IN, "TUSB6010 irq");
299         if (status < 0) {
300                 printk(error, 3, status);
301                 return status;
302         }
303         tusb_resources[2].start = irq + IH_GPIO_BASE;
304
305         /* set up memory timings ... can speed them up later */
306         if (!ps_refclk) {
307                 printk(error, 4, status);
308                 return -ENODEV;
309         }
310         refclk_psec = ps_refclk;
311         status = tusb6010_platform_retime(1);
312         if (status < 0) {
313                 printk(error, 5, status);
314                 return status;
315         }
316
317         /* finish device setup ... */
318         if (!data) {
319                 printk(error, 6, status);
320                 return -ENODEV;
321         }
322         tusb_device.dev.platform_data = data;
323
324         /* REVISIT let the driver know what DMA channels work */
325         if (!dmachan)
326                 tusb_device.dev.dma_mask = NULL;
327         else {
328                 /* assume OMAP 2420 ES2.0 and later */
329                 if (dmachan & (1 << 0))
330                         omap_mux_init_signal("sys_ndmareq0", 0);
331                 if (dmachan & (1 << 1))
332                         omap_mux_init_signal("sys_ndmareq1", 0);
333                 if (dmachan & (1 << 2))
334                         omap_mux_init_signal("sys_ndmareq2", 0);
335                 if (dmachan & (1 << 3))
336                         omap_mux_init_signal("sys_ndmareq3", 0);
337                 if (dmachan & (1 << 4))
338                         omap_mux_init_signal("sys_ndmareq4", 0);
339                 if (dmachan & (1 << 5))
340                         omap_mux_init_signal("sys_ndmareq5", 0);
341         }
342
343         /* so far so good ... register the device */
344         status = platform_device_register(&tusb_device);
345         if (status < 0) {
346                 printk(error, 7, status);
347                 return status;
348         }
349         return 0;
350 }