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
next_clk(unsigned t1_NS,unsigned t2_ps,unsigned fclk_ps)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 
tusb_set_async_mode(unsigned sysclk_ps,unsigned fclk_ps)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 
tusb_set_sync_mode(unsigned sysclk_ps,unsigned fclk_ps)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 */
tusb6010_platform_retime(unsigned is_refclk)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
tusb6010_setup_interface(struct musb_hdrc_platform_data * data,unsigned ps_refclk,unsigned waitpin,unsigned async,unsigned sync,unsigned irq,unsigned dmachan)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 }
351