blob: a0c4c42e56b9388dc38071a78111e91321a3cb8e [file] [log] [blame]
Thomas Gleixnerd2912cb2019-06-04 10:11:33 +02001// SPDX-License-Identifier: GPL-2.0-only
David Brownellc1ed6402006-12-07 14:03:49 -08002/*
3 * linux/arch/arm/mach-omap2/usb-tusb6010.c
4 *
5 * Copyright (C) 2006 Nokia Corporation
David Brownellc1ed6402006-12-07 14:03:49 -08006 */
7
Jon Hunter012e3382013-02-21 13:01:47 -06008#include <linux/err.h>
Paul Gortmakerd44b28c2011-07-31 10:52:44 -04009#include <linux/string.h>
David Brownellc1ed6402006-12-07 14:03:49 -080010#include <linux/types.h>
11#include <linux/errno.h>
12#include <linux/delay.h>
13#include <linux/platform_device.h>
Jarkko Nikulaf2d18fe2008-12-10 17:35:30 -080014#include <linux/gpio.h>
Paul Gortmakerdc280942011-07-31 16:17:29 -040015#include <linux/export.h>
Felipe Balbie8c4a7a2012-10-24 14:26:19 -070016#include <linux/platform_data/usb-omap.h>
David Brownellc1ed6402006-12-07 14:03:49 -080017
18#include <linux/usb/musb.h>
19
Afzal Mohammed3ef5d002012-10-05 10:37:27 +053020#include "gpmc.h"
David Brownellc1ed6402006-12-07 14:03:49 -080021
David Brownellc1ed6402006-12-07 14:03:49 -080022static u8 async_cs, sync_cs;
23static unsigned refclk_psec;
24
Jon Hunterc3be5b42013-02-21 13:46:22 -060025static struct gpmc_settings tusb_async = {
Jon Hunter012e3382013-02-21 13:01:47 -060026 .wait_on_read = true,
27 .wait_on_write = true,
28 .device_width = GPMC_DEVWIDTH_16BIT,
Jon Hunterc3be5b42013-02-21 13:46:22 -060029 .mux_add_data = GPMC_MUX_AD,
30};
31
32static struct gpmc_settings tusb_sync = {
Jon Hunter012e3382013-02-21 13:01:47 -060033 .burst_read = true,
34 .burst_write = true,
Jon Hunterc3be5b42013-02-21 13:46:22 -060035 .sync_read = true,
36 .sync_write = true,
Jon Hunter012e3382013-02-21 13:01:47 -060037 .wait_on_read = true,
38 .wait_on_write = true,
39 .burst_len = GPMC_BURST_16,
40 .device_width = GPMC_DEVWIDTH_16BIT,
Jon Hunterc3be5b42013-02-21 13:46:22 -060041 .mux_add_data = GPMC_MUX_AD,
42};
David Brownellc1ed6402006-12-07 14:03:49 -080043
David Brownellc1ed6402006-12-07 14:03:49 -080044/* NOTE: timings are from tusb 6010 datasheet Rev 1.8, 12-Sept 2006 */
45
Afzal Mohammed47acde12012-08-17 12:16:14 +053046static int tusb_set_async_mode(unsigned sysclk_ps)
David Brownellc1ed6402006-12-07 14:03:49 -080047{
Afzal Mohammed47acde12012-08-17 12:16:14 +053048 struct gpmc_device_timings dev_t;
David Brownellc1ed6402006-12-07 14:03:49 -080049 struct gpmc_timings t;
50 unsigned t_acsnh_advnh = sysclk_ps + 3000;
David Brownellc1ed6402006-12-07 14:03:49 -080051
Afzal Mohammed47acde12012-08-17 12:16:14 +053052 memset(&dev_t, 0, sizeof(dev_t));
David Brownellc1ed6402006-12-07 14:03:49 -080053
Afzal Mohammed47acde12012-08-17 12:16:14 +053054 dev_t.t_ceasu = 8 * 1000;
55 dev_t.t_avdasu = t_acsnh_advnh - 7000;
56 dev_t.t_ce_avd = 1000;
57 dev_t.t_avdp_r = t_acsnh_advnh;
58 dev_t.t_oeasu = t_acsnh_advnh + 1000;
59 dev_t.t_oe = 300;
60 dev_t.t_cez_r = 7000;
61 dev_t.t_cez_w = dev_t.t_cez_r;
62 dev_t.t_avdp_w = t_acsnh_advnh;
63 dev_t.t_weasu = t_acsnh_advnh + 1000;
64 dev_t.t_wpl = 300;
65 dev_t.cyc_aavdh_we = 1;
David Brownellc1ed6402006-12-07 14:03:49 -080066
Jon Hunterc3be5b42013-02-21 13:46:22 -060067 gpmc_calc_timings(&t, &tusb_async, &dev_t);
David Brownellc1ed6402006-12-07 14:03:49 -080068
Robert ABEL2e676902015-02-27 16:56:53 +010069 return gpmc_cs_set_timings(async_cs, &t, &tusb_async);
David Brownellc1ed6402006-12-07 14:03:49 -080070}
71
Afzal Mohammed47acde12012-08-17 12:16:14 +053072static int tusb_set_sync_mode(unsigned sysclk_ps)
David Brownellc1ed6402006-12-07 14:03:49 -080073{
Afzal Mohammed47acde12012-08-17 12:16:14 +053074 struct gpmc_device_timings dev_t;
David Brownellc1ed6402006-12-07 14:03:49 -080075 struct gpmc_timings t;
76 unsigned t_scsnh_advnh = sysclk_ps + 3000;
David Brownellc1ed6402006-12-07 14:03:49 -080077
Afzal Mohammed47acde12012-08-17 12:16:14 +053078 memset(&dev_t, 0, sizeof(dev_t));
David Brownellc1ed6402006-12-07 14:03:49 -080079
Afzal Mohammed47acde12012-08-17 12:16:14 +053080 dev_t.clk = 11100;
81 dev_t.t_bacc = 1000;
82 dev_t.t_ces = 1000;
83 dev_t.t_ceasu = 8 * 1000;
84 dev_t.t_avdasu = t_scsnh_advnh - 7000;
85 dev_t.t_ce_avd = 1000;
86 dev_t.t_avdp_r = t_scsnh_advnh;
87 dev_t.cyc_aavdh_oe = 3;
88 dev_t.cyc_oe = 5;
89 dev_t.t_ce_rdyz = 7000;
90 dev_t.t_avdp_w = t_scsnh_advnh;
91 dev_t.cyc_aavdh_we = 3;
92 dev_t.cyc_wpl = 6;
David Brownellc1ed6402006-12-07 14:03:49 -080093
Jon Hunterc3be5b42013-02-21 13:46:22 -060094 gpmc_calc_timings(&t, &tusb_sync, &dev_t);
Afzal Mohammed559d94b2012-05-28 17:51:37 +053095
Robert ABEL2e676902015-02-27 16:56:53 +010096 return gpmc_cs_set_timings(sync_cs, &t, &tusb_sync);
David Brownellc1ed6402006-12-07 14:03:49 -080097}
98
David Brownellc1ed6402006-12-07 14:03:49 -080099/* tusb driver calls this when it changes the chip's clocking */
100int tusb6010_platform_retime(unsigned is_refclk)
101{
102 static const char error[] =
103 KERN_ERR "tusb6010 %s retime error %d\n";
104
David Brownellc1ed6402006-12-07 14:03:49 -0800105 unsigned sysclk_ps;
106 int status;
107
Afzal Mohammed47acde12012-08-17 12:16:14 +0530108 if (!refclk_psec)
David Brownellc1ed6402006-12-07 14:03:49 -0800109 return -ENODEV;
110
111 sysclk_ps = is_refclk ? refclk_psec : TUSB6010_OSCCLK_60;
112
Afzal Mohammed47acde12012-08-17 12:16:14 +0530113 status = tusb_set_async_mode(sysclk_ps);
David Brownellc1ed6402006-12-07 14:03:49 -0800114 if (status < 0) {
115 printk(error, "async", status);
116 goto done;
117 }
Afzal Mohammed47acde12012-08-17 12:16:14 +0530118 status = tusb_set_sync_mode(sysclk_ps);
David Brownellc1ed6402006-12-07 14:03:49 -0800119 if (status < 0)
120 printk(error, "sync", status);
121done:
122 return status;
123}
124EXPORT_SYMBOL_GPL(tusb6010_platform_retime);
125
126static struct resource tusb_resources[] = {
127 /* Order is significant! The start/end fields
128 * are updated during setup..
129 */
130 { /* Asynchronous access */
131 .flags = IORESOURCE_MEM,
132 },
133 { /* Synchronous access */
134 .flags = IORESOURCE_MEM,
135 },
136 { /* IRQ */
Felipe Balbi6ec1e072010-12-23 12:17:49 -0800137 .name = "mc",
David Brownellc1ed6402006-12-07 14:03:49 -0800138 .flags = IORESOURCE_IRQ,
139 },
140};
141
142static u64 tusb_dmamask = ~(u32)0;
143
144static struct platform_device tusb_device = {
Felipe Balbi18688fb2010-12-02 09:13:54 +0200145 .name = "musb-tusb",
David Brownellc1ed6402006-12-07 14:03:49 -0800146 .id = -1,
147 .dev = {
148 .dma_mask = &tusb_dmamask,
149 .coherent_dma_mask = 0xffffffff,
150 },
151 .num_resources = ARRAY_SIZE(tusb_resources),
152 .resource = tusb_resources,
153};
154
155
156/* this may be called only from board-*.c setup code */
157int __init
158tusb6010_setup_interface(struct musb_hdrc_platform_data *data,
159 unsigned ps_refclk, unsigned waitpin,
160 unsigned async, unsigned sync,
161 unsigned irq, unsigned dmachan)
162{
163 int status;
164 static char error[] __initdata =
165 KERN_ERR "tusb6010 init error %d, %d\n";
166
167 /* ASYNC region, primarily for PIO */
168 status = gpmc_cs_request(async, SZ_16M, (unsigned long *)
169 &tusb_resources[0].start);
170 if (status < 0) {
171 printk(error, 1, status);
172 return status;
173 }
174 tusb_resources[0].end = tusb_resources[0].start + 0x9ff;
Jon Hunter012e3382013-02-21 13:01:47 -0600175 tusb_async.wait_pin = waitpin;
David Brownellc1ed6402006-12-07 14:03:49 -0800176 async_cs = async;
David Brownellc1ed6402006-12-07 14:03:49 -0800177
Jon Hunter012e3382013-02-21 13:01:47 -0600178 status = gpmc_cs_program_settings(async_cs, &tusb_async);
179 if (status < 0)
180 return status;
David Brownellc1ed6402006-12-07 14:03:49 -0800181
182 /* SYNC region, primarily for DMA */
183 status = gpmc_cs_request(sync, SZ_16M, (unsigned long *)
184 &tusb_resources[1].start);
185 if (status < 0) {
186 printk(error, 2, status);
187 return status;
188 }
189 tusb_resources[1].end = tusb_resources[1].start + 0x9ff;
Jon Hunter012e3382013-02-21 13:01:47 -0600190 tusb_sync.wait_pin = waitpin;
David Brownellc1ed6402006-12-07 14:03:49 -0800191 sync_cs = sync;
Jon Hunter012e3382013-02-21 13:01:47 -0600192
193 status = gpmc_cs_program_settings(sync_cs, &tusb_sync);
194 if (status < 0)
195 return status;
David Brownellc1ed6402006-12-07 14:03:49 -0800196
197 /* IRQ */
Igor Grinbergbc593f52011-05-03 18:22:09 +0300198 status = gpio_request_one(irq, GPIOF_IN, "TUSB6010 irq");
David Brownellc1ed6402006-12-07 14:03:49 -0800199 if (status < 0) {
200 printk(error, 3, status);
201 return status;
202 }
Tony Lindgren3d09b332012-06-20 07:18:15 -0700203 tusb_resources[2].start = gpio_to_irq(irq);
David Brownellc1ed6402006-12-07 14:03:49 -0800204
205 /* set up memory timings ... can speed them up later */
206 if (!ps_refclk) {
207 printk(error, 4, status);
208 return -ENODEV;
209 }
210 refclk_psec = ps_refclk;
211 status = tusb6010_platform_retime(1);
212 if (status < 0) {
213 printk(error, 5, status);
214 return status;
215 }
216
217 /* finish device setup ... */
218 if (!data) {
219 printk(error, 6, status);
220 return -ENODEV;
221 }
David Brownellc1ed6402006-12-07 14:03:49 -0800222 tusb_device.dev.platform_data = data;
223
David Brownellc1ed6402006-12-07 14:03:49 -0800224 /* so far so good ... register the device */
225 status = platform_device_register(&tusb_device);
226 if (status < 0) {
227 printk(error, 7, status);
228 return status;
229 }
230 return 0;
231}