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