Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
usb-tusb6010.c
Go to the documentation of this file.
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 }
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
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;
264  | GPMC_CONFIG1_WAIT_PIN_SEL(waitpin)
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;
290  | GPMC_CONFIG1_WAIT_PIN_SEL(waitpin)
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 = gpio_to_irq(irq);
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 }