aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc/rtc-omap.c
blob: 7789002bdd5c1af65f7c6bff95649e9e72d89db1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
/*
 * TI OMAP1 Real Time Clock interface for Linux
 *
 * Copyright (C) 2003 MontaVista Software, Inc.
 * Author: George G. Davis <gdavis@mvista.com> or <source@mvista.com>
 *
 * Copyright (C) 2006 David Brownell (new RTC framework)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
#include <linux/platform_device.h>

#include <asm/io.h>


/* The OMAP1 RTC is a year/month/day/hours/minutes/seconds BCD clock
 * with century-range alarm matching, driven by the 32kHz clock.
 *
 * The main user-visible ways it differs from PC RTCs are by omitting
 * "don't care" alarm fields and sub-second periodic IRQs, and having
 * an autoadjust mechanism to calibrate to the true oscillator rate.
 *
 * Board-specific wiring options include using split power mode with
 * RTC_OFF_NOFF used as the reset signal (so the RTC won't be reset),
 * and wiring RTC_WAKE_INT (so the RTC alarm can wake the system from
 * low power modes) for OMAP1 boards (OMAP-L138 has this built into
 * the SoC). See the BOARD-SPECIFIC CUSTOMIZATION comment.
 */

#define OMAP_RTC_BASE			0xfffb4800

/* RTC registers */
#define OMAP_RTC_SECONDS_REG		0x00
#define OMAP_RTC_MINUTES_REG		0x04
#define OMAP_RTC_HOURS_REG		0x08
#define OMAP_RTC_DAYS_REG		0x0C
#define OMAP_RTC_MONTHS_REG		0x10
#define OMAP_RTC_YEARS_REG		0x14
#define OMAP_RTC_WEEKS_REG		0x18

#define OMAP_RTC_ALARM_SECONDS_REG	0x20
#define OMAP_RTC_ALARM_MINUTES_REG	0x24
#define OMAP_RTC_ALARM_HOURS_REG	0x28
#define OMAP_RTC_ALARM_DAYS_REG		0x2c
#define OMAP_RTC_ALARM_MONTHS_REG	0x30
#define OMAP_RTC_ALARM_YEARS_REG	0x34

#define OMAP_RTC_CTRL_REG		0x40
#define OMAP_RTC_STATUS_REG		0x44
#define OMAP_RTC_INTERRUPTS_REG		0x48

#define OMAP_RTC_COMP_LSB_REG		0x4c
#define OMAP_RTC_COMP_MSB_REG		0x50
#define OMAP_RTC_OSC_REG		0x54

/* OMAP_RTC_CTRL_REG bit fields: */
#define OMAP_RTC_CTRL_SPLIT		(1<<7)
#define OMAP_RTC_CTRL_DISABLE		(1<<6)
#define OMAP_RTC_CTRL_SET_32_COUNTER	(1<<5)
#define OMAP_RTC_CTRL_TEST		(1<<4)
#define OMAP_RTC_CTRL_MODE_12_24	(1<<3)
#define OMAP_RTC_CTRL_AUTO_COMP		(1<<2)
#define OMAP_RTC_CTRL_ROUND_30S		(1<<1)
#define OMAP_RTC_CTRL_STOP		(1<<0)

/* OMAP_RTC_STATUS_REG bit fields: */
#define OMAP_RTC_STATUS_POWER_UP        (1<<7)
#define OMAP_RTC_STATUS_ALARM           (1<<6)
#define OMAP_RTC_STATUS_1D_EVENT        (1<<5)
#define OMAP_RTC_STATUS_1H_EVENT        (1<<4)
#define OMAP_RTC_STATUS_1M_EVENT        (1<<3)
#define OMAP_RTC_STATUS_1S_EVENT        (1<<2)
#define OMAP_RTC_STATUS_RUN             (1<<1)
#define OMAP_RTC_STATUS_BUSY            (1<<0)

/* OMAP_RTC_INTERRUPTS_REG bit fields: */
#define OMAP_RTC_INTERRUPTS_IT_ALARM    (1<<3)
#define OMAP_RTC_INTERRUPTS_IT_TIMER    (1<<2)

static void __iomem	*rtc_base;

#define rtc_read(addr)		__raw_readb(rtc_base + (addr))
#define rtc_write(val, addr)	__raw_writeb(val, rtc_base + (addr))


/* we rely on the rtc framework to handle locking (rtc->ops_lock),
 * so the only other requirement is that register accesses which
 * require BUSY to be clear are made with IRQs locally disabled
 */
static void rtc_wait_not_busy(void)
{
	int	count = 0;
	u8	status;

	/* BUSY may stay active for 1/32768 second (~30 usec) */
	for (count = 0; count < 50; count++) {
		status = rtc_read(OMAP_RTC_STATUS_REG);
		if ((status & (u8)OMAP_RTC_STATUS_BUSY) == 0)
			break;
		udelay(1);
	}
	/* now we have ~15 usec to read/write various registers */
}

static irqreturn_t rtc_irq(int irq, void *rtc)
{
	unsigned long		events = 0;
	u8			irq_data;

	irq_data = rtc_read(OMAP_RTC_STATUS_REG);

	/* alarm irq? */
	if (irq_data & OMAP_RTC_STATUS_ALARM) {
		rtc_write(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG);
		events |= RTC_IRQF | RTC_AF;
	}

	/* 1/sec periodic/update irq? */
	if (irq_data & OMAP_RTC_STATUS_1S_EVENT)
		events |= RTC_IRQF | RTC_UF;

	rtc_update_irq(rtc, 1, events);

	return IRQ_HANDLED;
}

static int omap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
	u8 reg;

	local_irq_disable();
	rtc_wait_not_busy();
	reg = rtc_read(OMAP_RTC_INTERRUPTS_REG);
	if (enabled)
		reg |= OMAP_RTC_INTERRUPTS_IT_ALARM;
	else
		reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM;
	rtc_wait_not_busy();
	rtc_write(reg, OMAP_RTC_INTERRUPTS_REG);
	local_irq_enable();

	return 0;
}

/* this hardware doesn't support "don't care" alarm fields */
static int tm2bcd(struct rtc_time *tm)
{
	if (rtc_valid_tm(tm) != 0)
		return -EINVAL;

	tm->tm_sec = bin2bcd(tm->tm_sec);
	tm->tm_min = bin2bcd(tm->tm_min);
	tm->tm_hour = bin2bcd(tm->tm_hour);
	tm->tm_mday = bin2bcd(tm->tm_mday);

	tm->tm_mon = bin2bcd(tm->tm_mon + 1);

	/* epoch == 1900 */
	if (tm->tm_year < 100 || tm->tm_year > 199)
		return -EINVAL;
	tm->tm_year = bin2bcd(tm->tm_year - 100);

	return 0;
}

static void bcd2tm(struct rtc_time *tm)
{
	tm->tm_sec = bcd2bin(tm->tm_sec);
	tm->tm_min = bcd2bin(tm->tm_min);
	tm->tm_hour = bcd2bin(tm->tm_hour);
	tm->tm_mday = bcd2bin(tm->tm_mday);
	tm->tm_mon = bcd2bin(tm->tm_mon) - 1;
	/* epoch == 1900 */
	tm->tm_year = bcd2bin(tm->tm_year) + 100;
}


static int omap_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
	/* we don't report wday/yday/isdst ... */
	local_irq_disable();
	rtc_wait_not_busy();

	tm->tm_sec = rtc_read(OMAP_RTC_SECONDS_REG);
	tm->tm_min = rtc_read(OMAP_RTC_MINUTES_REG);
	tm->tm_hour = rtc_read(OMAP_RTC_HOURS_REG);
	tm->tm_mday = rtc_read(OMAP_RTC_DAYS_REG);
	tm->tm_mon = rtc_read(OMAP_RTC_MONTHS_REG);
	tm->tm_year = rtc_read(OMAP_RTC_YEARS_REG);

	local_irq_enable();

	bcd2tm(tm);
	return 0;
}

static int omap_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
	if (tm2bcd(tm) < 0)
		return -EINVAL;
	local_irq_disable();
	rtc_wait_not_busy();

	rtc_write(tm->tm_year, OMAP_RTC_YEARS_REG);
	rtc_write(tm->tm_mon, OMAP_RTC_MONTHS_REG);
	rtc_write(tm->tm_mday, OMAP_RTC_DAYS_REG);
	rtc_write(tm->tm_hour, OMAP_RTC_HOURS_REG);
	rtc_write(tm->tm_min, OMAP_RTC_MINUTES_REG);
	rtc_write(tm->tm_sec, OMAP_RTC_SECONDS_REG);

	local_irq_enable();

	return 0;
}

static int omap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
	local_irq_disable();
	rtc_wait_not_busy();

	alm->time.tm_sec = rtc_read(OMAP_RTC_ALARM_SECONDS_REG);
	alm->time.tm_min = rtc_read(OMAP_RTC_ALARM_MINUTES_REG);
	alm->time.tm_hour = rtc_read(OMAP_RTC_ALARM_HOURS_REG);
	alm->time.tm_mday = rtc_read(OMAP_RTC_ALARM_DAYS_REG);
	alm->time.tm_mon = rtc_read(OMAP_RTC_ALARM_MONTHS_REG);
	alm->time.tm_year = rtc_read(OMAP_RTC_ALARM_YEARS_REG);

	local_irq_enable();

	bcd2tm(&alm->time);
	alm->enabled = !!(rtc_read(OMAP_RTC_INTERRUPTS_REG)
			& OMAP_RTC_INTERRUPTS_IT_ALARM);

	return 0;
}

static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
	u8 reg;

	if (tm2bcd(&alm->time) < 0)
		return -EINVAL;

	local_irq_disable();
	rtc_wait_not_busy();

	rtc_write(alm->time.tm_year, OMAP_RTC_ALARM_YEARS_REG);
	rtc_write(alm->time.tm_mon, OMAP_RTC_ALARM_MONTHS_REG);
	rtc_write(alm->time.tm_mday, OMAP_RTC_ALARM_DAYS_REG);
	rtc_write(alm->time.tm_hour, OMAP_RTC_ALARM_HOURS_REG);
	rtc_write(alm->time.tm_min, OMAP_RTC_ALARM_MINUTES_REG);
	rtc_write(alm->time.tm_sec, OMAP_RTC_ALARM_SECONDS_REG);

	reg = rtc_read(OMAP_RTC_INTERRUPTS_REG);
	if (alm->enabled)
		reg |= OMAP_RTC_INTERRUPTS_IT_ALARM;
	else
		reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM;
	rtc_write(reg, OMAP_RTC_INTERRUPTS_REG);

	local_irq_enable();

	return 0;
}

static struct rtc_class_ops omap_rtc_ops = {
	.read_time	= omap_rtc_read_time,
	.set_time	= omap_rtc_set_time,
	.read_alarm	= omap_rtc_read_alarm,
	.set_alarm	= omap_rtc_set_alarm,
	.alarm_irq_enable = omap_rtc_alarm_irq_enable,
};

static int omap_rtc_alarm;
static int omap_rtc_timer;

static int __init omap_rtc_probe(struct platform_device *pdev)
{
	struct resource		*res, *mem;
	struct rtc_device	*rtc;
	u8			reg, new_ctrl;

	omap_rtc_timer = platform_get_irq(pdev, 0);
	if (omap_rtc_timer <= 0) {
		pr_debug("%s: no update irq?\n", pdev->name);
		return -ENOENT;
	}

	omap_rtc_alarm = platform_get_irq(pdev, 1);
	if (omap_rtc_alarm <= 0) {
		pr_debug("%s: no alarm irq?\n", pdev->name);
		return -ENOENT;
	}

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		pr_debug("%s: RTC resource data missing\n", pdev->name);
		return -ENOENT;
	}

	mem = request_mem_region(res->start, resource_size(res), pdev->name);
	if (!mem) {
		pr_debug("%s: RTC registers at %08x are not free\n",
			pdev->name, res->start);
		return -EBUSY;
	}

	rtc_base = ioremap(res->start, resource_size(res));
	if (!rtc_base) {
		pr_debug("%s: RTC registers can't be mapped\n", pdev->name);
		goto fail;
	}

	rtc = rtc_device_register(pdev->name, &pdev->dev,
			&omap_rtc_ops, THIS_MODULE);
	if (IS_ERR(rtc)) {
		pr_debug("%s: can't register RTC device, err %ld\n",
			pdev->name, PTR_ERR(rtc));
		goto fail0;
	}
	platform_set_drvdata(pdev, rtc);
	dev_set_drvdata(&rtc->dev, mem);

	/* clear pending irqs, and set 1/second periodic,
	 * which we'll use instead of update irqs
	 */
	rtc_write(0, OMAP_RTC_INTERRUPTS_REG);

	/* clear old status */
	reg = rtc_read(OMAP_RTC_STATUS_REG);
	if (reg & (u8) OMAP_RTC_STATUS_POWER_UP) {
		pr_info("%s: RTC power up reset detected\n",
			pdev->name);
		rtc_write(OMAP_RTC_STATUS_POWER_UP, OMAP_RTC_STATUS_REG);
	}
	if (reg & (u8) OMAP_RTC_STATUS_ALARM)
		rtc_write(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG);

	/* handle periodic and alarm irqs */
	if (request_irq(omap_rtc_timer, rtc_irq, IRQF_DISABLED,
			dev_name(&rtc->dev), rtc)) {
		pr_debug("%s: RTC timer interrupt IRQ%d already claimed\n",
			pdev->name, omap_rtc_timer);
		goto fail1;
	}
	if ((omap_rtc_timer != omap_rtc_alarm) &&
		(request_irq(omap_rtc_alarm, rtc_irq, IRQF_DISABLED,
			dev_name(&rtc->dev), rtc))) {
		pr_debug("%s: RTC alarm interrupt IRQ%d already claimed\n",
			pdev->name, omap_rtc_alarm);
		goto fail2;
	}

	/* On boards with split power, RTC_ON_NOFF won't reset the RTC */
	reg = rtc_read(OMAP_RTC_CTRL_REG);
	if (reg & (u8) OMAP_RTC_CTRL_STOP)
		pr_info("%s: already running\n", pdev->name);

	/* force to 24 hour mode */
	new_ctrl = reg & (OMAP_RTC_CTRL_SPLIT|OMAP_RTC_CTRL_AUTO_COMP);
	new_ctrl |= OMAP_RTC_CTRL_STOP;

	/* BOARD-SPECIFIC CUSTOMIZATION CAN GO HERE:
	 *
	 *  - Device wake-up capability setting should come through chip
	 *    init logic. OMAP1 boards should initialize the "wakeup capable"
	 *    flag in the platform device if the board is wired right for
	 *    being woken up by RTC alarm. For OMAP-L138, this capability
	 *    is built into the SoC by the "Deep Sleep" capability.
	 *
	 *  - Boards wired so RTC_ON_nOFF is used as the reset signal,
	 *    rather than nPWRON_RESET, should forcibly enable split
	 *    power mode.  (Some chip errata report that RTC_CTRL_SPLIT
	 *    is write-only, and always reads as zero...)
	 */

	if (new_ctrl & (u8) OMAP_RTC_CTRL_SPLIT)
		pr_info("%s: split power mode\n", pdev->name);

	if (reg != new_ctrl)
		rtc_write(new_ctrl, OMAP_RTC_CTRL_REG);

	return 0;

fail2:
	free_irq(omap_rtc_timer, rtc);
fail1:
	rtc_device_unregister(rtc);
fail0:
	iounmap(rtc_base);
fail:
	release_mem_region(mem->start, resource_size(mem));
	return -EIO;
}

static int __exit omap_rtc_remove(struct platform_device *pdev)
{
	struct rtc_device	*rtc = platform_get_drvdata(pdev);
	struct resource		*mem = dev_get_drvdata(&rtc->dev);

	device_init_wakeup(&pdev->dev, 0);

	/* leave rtc running, but disable irqs */
	rtc_write(0, OMAP_RTC_INTERRUPTS_REG);

	free_irq(omap_rtc_timer, rtc);

	if (omap_rtc_timer != omap_rtc_alarm)
		free_irq(omap_rtc_alarm, rtc);

	rtc_device_unregister(rtc);
	iounmap(rtc_base);
	release_mem_region(mem->start, resource_size(mem));
	return 0;
}

#ifdef CONFIG_PM

static u8 irqstat;

static int omap_rtc_suspend(struct platform_device *pdev, pm_message_t state)
{
	irqstat = rtc_read(OMAP_RTC_INTERRUPTS_REG);

	/* FIXME the RTC alarm is not currently acting as a wakeup event
	 * source, and in fact this enable() call is just saving a flag
	 * that's never used...
	 */
	if (device_may_wakeup(&pdev->dev))
		enable_irq_wake(omap_rtc_alarm);
	else
		rtc_write(0, OMAP_RTC_INTERRUPTS_REG);

	return 0;
}

static int omap_rtc_resume(struct platform_device *pdev)
{
	if (device_may_wakeup(&pdev->dev))
		disable_irq_wake(omap_rtc_alarm);
	else
		rtc_write(irqstat, OMAP_RTC_INTERRUPTS_REG);
	return 0;
}

#else
#define omap_rtc_suspend NULL
#define omap_rtc_resume  NULL
#endif

static void omap_rtc_shutdown(struct platform_device *pdev)
{
	rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
}

MODULE_ALIAS("platform:omap_rtc");
static struct platform_driver omap_rtc_driver = {
	.remove		= __exit_p(omap_rtc_remove),
	.suspend	= omap_rtc_suspend,
	.resume		= omap_rtc_resume,
	.shutdown	= omap_rtc_shutdown,
	.driver		= {
		.name	= "omap_rtc",
		.owner	= THIS_MODULE,
	},
};

static int __init rtc_init(void)
{
	return platform_driver_probe(&omap_rtc_driver, omap_rtc_probe);
}
module_init(rtc_init);

static void __exit rtc_exit(void)
{
	platform_driver_unregister(&omap_rtc_driver);
}
module_exit(rtc_exit);

MODULE_AUTHOR("George G. Davis (and others)");
MODULE_LICENSE("GPL");
13 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570
/*
 * R8A66597 HCD (Host Controller Driver)
 *
 * Copyright (C) 2006-2007 Renesas Solutions Corp.
 * Portions Copyright (C) 2004 Psion Teklogix (for NetBook PRO)
 * Portions Copyright (C) 2004-2005 David Brownell
 * Portions Copyright (C) 1999 Roman Weissgaerber
 *
 * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/list.h>
#include <linux/interrupt.h>
#include <linux/usb.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/mm.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <asm/cacheflush.h>

#include "../core/hcd.h"
#include "r8a66597.h"

MODULE_DESCRIPTION("R8A66597 USB Host Controller Driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yoshihiro Shimoda");
MODULE_ALIAS("platform:r8a66597_hcd");

#define DRIVER_VERSION	"2009-05-26"

static const char hcd_name[] = "r8a66597_hcd";

static void packet_write(struct r8a66597 *r8a66597, u16 pipenum);
static int r8a66597_get_frame(struct usb_hcd *hcd);

/* this function must be called with interrupt disabled */
static void enable_pipe_irq(struct r8a66597 *r8a66597, u16 pipenum,
			    unsigned long reg)
{
	u16 tmp;

	tmp = r8a66597_read(r8a66597, INTENB0);
	r8a66597_bclr(r8a66597, BEMPE | NRDYE | BRDYE, INTENB0);
	r8a66597_bset(r8a66597, 1 << pipenum, reg);
	r8a66597_write(r8a66597, tmp, INTENB0);
}

/* this function must be called with interrupt disabled */
static void disable_pipe_irq(struct r8a66597 *r8a66597, u16 pipenum,
			     unsigned long reg)
{
	u16 tmp;

	tmp = r8a66597_read(r8a66597, INTENB0);
	r8a66597_bclr(r8a66597, BEMPE | NRDYE | BRDYE, INTENB0);
	r8a66597_bclr(r8a66597, 1 << pipenum, reg);
	r8a66597_write(r8a66597, tmp, INTENB0);
}

static void set_devadd_reg(struct r8a66597 *r8a66597, u8 r8a66597_address,
			   u16 usbspd, u8 upphub, u8 hubport, int port)
{
	u16 val;
	unsigned long devadd_reg = get_devadd_addr(r8a66597_address);

	val = (upphub << 11) | (hubport << 8) | (usbspd << 6) | (port & 0x0001);
	r8a66597_write(r8a66597, val, devadd_reg);
}

static int r8a66597_clock_enable(struct r8a66597 *r8a66597)
{
	u16 tmp;
	int i = 0;

	if (r8a66597->pdata->on_chip) {
#ifdef CONFIG_HAVE_CLK
		clk_enable(r8a66597->clk);
#endif
		do {
			r8a66597_write(r8a66597, SCKE, SYSCFG0);
			tmp = r8a66597_read(r8a66597, SYSCFG0);
			if (i++ > 1000) {
				printk(KERN_ERR "r8a66597: reg access fail.\n");
				return -ENXIO;
			}
		} while ((tmp & SCKE) != SCKE);
		r8a66597_write(r8a66597, 0x04, 0x02);
	} else {
		do {
			r8a66597_write(r8a66597, USBE, SYSCFG0);
			tmp = r8a66597_read(r8a66597, SYSCFG0);
			if (i++ > 1000) {
				printk(KERN_ERR "r8a66597: reg access fail.\n");
				return -ENXIO;
			}
		} while ((tmp & USBE) != USBE);
		r8a66597_bclr(r8a66597, USBE, SYSCFG0);
		r8a66597_mdfy(r8a66597, get_xtal_from_pdata(r8a66597->pdata),
			      XTAL, SYSCFG0);

		i = 0;
		r8a66597_bset(r8a66597, XCKE, SYSCFG0);
		do {
			msleep(1);
			tmp = r8a66597_read(r8a66597, SYSCFG0);
			if (i++ > 500) {
				printk(KERN_ERR "r8a66597: reg access fail.\n");
				return -ENXIO;
			}
		} while ((tmp & SCKE) != SCKE);
	}

	return 0;
}

static void r8a66597_clock_disable(struct r8a66597 *r8a66597)
{
	r8a66597_bclr(r8a66597, SCKE, SYSCFG0);
	udelay(1);

	if (r8a66597->pdata->on_chip) {
#ifdef CONFIG_HAVE_CLK
		clk_disable(r8a66597->clk);
#endif
	} else {
		r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
		r8a66597_bclr(r8a66597, XCKE, SYSCFG0);
		r8a66597_bclr(r8a66597, USBE, SYSCFG0);
	}
}

static void r8a66597_enable_port(struct r8a66597 *r8a66597, int port)
{
	u16 val;

	val = port ? DRPD : DCFM | DRPD;
	r8a66597_bset(r8a66597, val, get_syscfg_reg(port));
	r8a66597_bset(r8a66597, HSE, get_syscfg_reg(port));

	r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR, get_dmacfg_reg(port));
	r8a66597_bclr(r8a66597, DTCHE, get_intenb_reg(port));
	r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port));
}

static void r8a66597_disable_port(struct r8a66597 *r8a66597, int port)
{
	u16 val, tmp;

	r8a66597_write(r8a66597, 0, get_intenb_reg(port));
	r8a66597_write(r8a66597, 0, get_intsts_reg(port));

	r8a66597_port_power(r8a66597, port, 0);

	do {
		tmp = r8a66597_read(r8a66597, SOFCFG) & EDGESTS;
		udelay(640);
	} while (tmp == EDGESTS);

	val = port ? DRPD : DCFM | DRPD;
	r8a66597_bclr(r8a66597, val, get_syscfg_reg(port));
	r8a66597_bclr(r8a66597, HSE, get_syscfg_reg(port));
}

static int enable_controller(struct r8a66597 *r8a66597)
{
	int ret, port;
	u16 vif = r8a66597->pdata->vif ? LDRV : 0;
	u16 irq_sense = r8a66597->irq_sense_low ? INTL : 0;
	u16 endian = r8a66597->pdata->endian ? BIGEND : 0;

	ret = r8a66597_clock_enable(r8a66597);
	if (ret < 0)
		return ret;

	r8a66597_bset(r8a66597, vif & LDRV, PINCFG);
	r8a66597_bset(r8a66597, USBE, SYSCFG0);

	r8a66597_bset(r8a66597, BEMPE | NRDYE | BRDYE, INTENB0);
	r8a66597_bset(r8a66597, irq_sense & INTL, SOFCFG);
	r8a66597_bset(r8a66597, BRDY0, BRDYENB);
	r8a66597_bset(r8a66597, BEMP0, BEMPENB);

	r8a66597_bset(r8a66597, endian & BIGEND, CFIFOSEL);
	r8a66597_bset(r8a66597, endian & BIGEND, D0FIFOSEL);
	r8a66597_bset(r8a66597, endian & BIGEND, D1FIFOSEL);
	r8a66597_bset(r8a66597, TRNENSEL, SOFCFG);

	r8a66597_bset(r8a66597, SIGNE | SACKE, INTENB1);

	for (port = 0; port < r8a66597->max_root_hub; port++)
		r8a66597_enable_port(r8a66597, port);

	return 0;
}

static void disable_controller(struct r8a66597 *r8a66597)
{
	int port;

	/* disable interrupts */
	r8a66597_write(r8a66597, 0, INTENB0);
	r8a66597_write(r8a66597, 0, INTENB1);
	r8a66597_write(r8a66597, 0, BRDYENB);
	r8a66597_write(r8a66597, 0, BEMPENB);
	r8a66597_write(r8a66597, 0, NRDYENB);

	/* clear status */
	r8a66597_write(r8a66597, 0, BRDYSTS);
	r8a66597_write(r8a66597, 0, NRDYSTS);
	r8a66597_write(r8a66597, 0, BEMPSTS);

	for (port = 0; port < r8a66597->max_root_hub; port++)
		r8a66597_disable_port(r8a66597, port);

	r8a66597_clock_disable(r8a66597);
}

static int get_parent_r8a66597_address(struct r8a66597 *r8a66597,
				       struct usb_device *udev)
{
	struct r8a66597_device *dev;

	if (udev->parent && udev->parent->devnum != 1)
		udev = udev->parent;

	dev = dev_get_drvdata(&udev->dev);
	if (dev)
		return dev->address;
	else
		return 0;
}

static int is_child_device(char *devpath)
{
	return (devpath[2] ? 1 : 0);
}

static int is_hub_limit(char *devpath)
{
	return ((strlen(devpath) >= 4) ? 1 : 0);
}

static void get_port_number(struct r8a66597 *r8a66597,
			    char *devpath, u16 *root_port, u16 *hub_port)
{
	if (root_port) {
		*root_port = (devpath[0] & 0x0F) - 1;
		if (*root_port >= r8a66597->max_root_hub)
			printk(KERN_ERR "r8a66597: Illegal root port number.\n");
	}
	if (hub_port)
		*hub_port = devpath[2] & 0x0F;
}

static u16 get_r8a66597_usb_speed(enum usb_device_speed speed)
{
	u16 usbspd = 0;

	switch (speed) {
	case USB_SPEED_LOW:
		usbspd = LSMODE;
		break;
	case USB_SPEED_FULL:
		usbspd = FSMODE;
		break;
	case USB_SPEED_HIGH:
		usbspd = HSMODE;
		break;
	default:
		printk(KERN_ERR "r8a66597: unknown speed\n");
		break;
	}

	return usbspd;
}

static void set_child_connect_map(struct r8a66597 *r8a66597, int address)
{
	int idx;

	idx = address / 32;
	r8a66597->child_connect_map[idx] |= 1 << (address % 32);
}

static void put_child_connect_map(struct r8a66597 *r8a66597, int address)
{
	int idx;

	idx = address / 32;
	r8a66597->child_connect_map[idx] &= ~(1 << (address % 32));
}

static void set_pipe_reg_addr(struct r8a66597_pipe *pipe, u8 dma_ch)
{
	u16 pipenum = pipe->info.pipenum;
	const unsigned long fifoaddr[] = {D0FIFO, D1FIFO, CFIFO};
	const unsigned long fifosel[] = {D0FIFOSEL, D1FIFOSEL, CFIFOSEL};
	const unsigned long fifoctr[] = {D0FIFOCTR, D1FIFOCTR, CFIFOCTR};

	if (dma_ch > R8A66597_PIPE_NO_DMA)	/* dma fifo not use? */
		dma_ch = R8A66597_PIPE_NO_DMA;

	pipe->fifoaddr = fifoaddr[dma_ch];
	pipe->fifosel = fifosel[dma_ch];
	pipe->fifoctr = fifoctr[dma_ch];

	if (pipenum == 0)
		pipe->pipectr = DCPCTR;
	else
		pipe->pipectr = get_pipectr_addr(pipenum);

	if (check_bulk_or_isoc(pipenum)) {
		pipe->pipetre = get_pipetre_addr(pipenum);
		pipe->pipetrn = get_pipetrn_addr(pipenum);
	} else {
		pipe->pipetre = 0;
		pipe->pipetrn = 0;
	}
}

static struct r8a66597_device *
get_urb_to_r8a66597_dev(struct r8a66597 *r8a66597, struct urb *urb)
{
	if (usb_pipedevice(urb->pipe) == 0)
		return &r8a66597->device0;

	return dev_get_drvdata(&urb->dev->dev);
}

static int make_r8a66597_device(struct r8a66597 *r8a66597,
				struct urb *urb, u8 addr)
{
	struct r8a66597_device *dev;
	int usb_address = urb->setup_packet[2];	/* urb->pipe is address 0 */

	dev = kzalloc(sizeof(struct r8a66597_device), GFP_ATOMIC);
	if (dev == NULL)
		return -ENOMEM;

	dev_set_drvdata(&urb->dev->dev, dev);
	dev->udev = urb->dev;
	dev->address = addr;
	dev->usb_address = usb_address;
	dev->state = USB_STATE_ADDRESS;
	dev->ep_in_toggle = 0;
	dev->ep_out_toggle = 0;
	INIT_LIST_HEAD(&dev->device_list);
	list_add_tail(&dev->device_list, &r8a66597->child_device);

	get_port_number(r8a66597, urb->dev->devpath,
			&dev->root_port, &dev->hub_port);
	if (!is_child_device(urb->dev->devpath))
		r8a66597->root_hub[dev->root_port].dev = dev;

	set_devadd_reg(r8a66597, dev->address,
		       get_r8a66597_usb_speed(urb->dev->speed),
		       get_parent_r8a66597_address(r8a66597, urb->dev),
		       dev->hub_port, dev->root_port);

	return 0;
}

/* this function must be called with interrupt disabled */
static u8 alloc_usb_address(struct r8a66597 *r8a66597, struct urb *urb)
{
	u8 addr;	/* R8A66597's address */
	struct r8a66597_device *dev;

	if (is_hub_limit(urb->dev->devpath)) {
		dev_err(&urb->dev->dev, "External hub limit reached.\n");
		return 0;
	}

	dev = get_urb_to_r8a66597_dev(r8a66597, urb);
	if (dev && dev->state >= USB_STATE_ADDRESS)
		return dev->address;

	for (addr = 1; addr <= R8A66597_MAX_DEVICE; addr++) {
		if (r8a66597->address_map & (1 << addr))
			continue;

		dbg("alloc_address: r8a66597_addr=%d", addr);
		r8a66597->address_map |= 1 << addr;

		if (make_r8a66597_device(r8a66597, urb, addr) < 0)
			return 0;

		return addr;
	}

	dev_err(&urb->dev->dev,
		"cannot communicate with a USB device more than 10.(%x)\n",
		r8a66597->address_map);

	return 0;
}

/* this function must be called with interrupt disabled */
static void free_usb_address(struct r8a66597 *r8a66597,
			     struct r8a66597_device *dev, int reset)
{
	int port;

	if (!dev)
		return;

	dbg("free_addr: addr=%d", dev->address);

	dev->state = USB_STATE_DEFAULT;
	r8a66597->address_map &= ~(1 << dev->address);
	dev->address = 0;
	/*
	 * Only when resetting USB, it is necessary to erase drvdata. When
	 * a usb device with usb hub is disconnect, "dev->udev" is already
	 * freed on usb_desconnect(). So we cannot access the data.
	 */
	if (reset)
		dev_set_drvdata(&dev->udev->dev, NULL);
	list_del(&dev->device_list);
	kfree(dev);

	for (port = 0; port < r8a66597->max_root_hub; port++) {
		if (r8a66597->root_hub[port].dev == dev) {
			r8a66597->root_hub[port].dev = NULL;
			break;
		}
	}
}

static void r8a66597_reg_wait(struct r8a66597 *r8a66597, unsigned long reg,
			      u16 mask, u16 loop)
{
	u16 tmp;
	int i = 0;

	do {
		tmp = r8a66597_read(r8a66597, reg);
		if (i++ > 1000000) {
			printk(KERN_ERR "r8a66597: register%lx, loop %x "
			       "is timeout\n", reg, loop);
			break;
		}
		ndelay(1);
	} while ((tmp & mask) != loop);
}

/* this function must be called with interrupt disabled */
static void pipe_start(struct r8a66597 *r8a66597, struct r8a66597_pipe *pipe)
{
	u16 tmp;

	tmp = r8a66597_read(r8a66597, pipe->pipectr) & PID;
	if ((pipe->info.pipenum != 0) & ((tmp & PID_STALL) != 0)) /* stall? */
		r8a66597_mdfy(r8a66597, PID_NAK, PID, pipe->pipectr);
	r8a66597_mdfy(r8a66597, PID_BUF, PID, pipe->pipectr);
}

/* this function must be called with interrupt disabled */
static void pipe_stop(struct r8a66597 *r8a66597, struct r8a66597_pipe *pipe)
{
	u16 tmp;

	tmp = r8a66597_read(r8a66597, pipe->pipectr) & PID;
	if ((tmp & PID_STALL11) != PID_STALL11)	/* force stall? */
		r8a66597_mdfy(r8a66597, PID_STALL, PID, pipe->pipectr);
	r8a66597_mdfy(r8a66597, PID_NAK, PID, pipe->pipectr);
	r8a66597_reg_wait(r8a66597, pipe->pipectr, PBUSY, 0);
}

/* this function must be called with interrupt disabled */
static void clear_all_buffer(struct r8a66597 *r8a66597,
			     struct r8a66597_pipe *pipe)
{
	u16 tmp;

	if (!pipe || pipe->info.pipenum == 0)
		return;

	pipe_stop(r8a66597, pipe);
	r8a66597_bset(r8a66597, ACLRM, pipe->pipectr);
	tmp = r8a66597_read(r8a66597, pipe->pipectr);
	tmp = r8a66597_read(r8a66597, pipe->pipectr);
	tmp = r8a66597_read(r8a66597, pipe->pipectr);
	r8a66597_bclr(r8a66597, ACLRM, pipe->pipectr);
}

/* this function must be called with interrupt disabled */
static void r8a66597_pipe_toggle(struct r8a66597 *r8a66597,
				 struct r8a66597_pipe *pipe, int toggle)
{
	if (toggle)
		r8a66597_bset(r8a66597, SQSET, pipe->pipectr);
	else
		r8a66597_bset(r8a66597, SQCLR, pipe->pipectr);
}

static inline unsigned short mbw_value(struct r8a66597 *r8a66597)
{
	if (r8a66597->pdata->on_chip)
		return MBW_32;
	else
		return MBW_16;
}

/* this function must be called with interrupt disabled */
static inline void cfifo_change(struct r8a66597 *r8a66597, u16 pipenum)
{
	unsigned short mbw = mbw_value(r8a66597);

	r8a66597_mdfy(r8a66597, mbw | pipenum, mbw | CURPIPE, CFIFOSEL);
	r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, pipenum);
}

/* this function must be called with interrupt disabled */
static inline void fifo_change_from_pipe(struct r8a66597 *r8a66597,
					 struct r8a66597_pipe *pipe)
{
	unsigned short mbw = mbw_value(r8a66597);

	cfifo_change(r8a66597, 0);
	r8a66597_mdfy(r8a66597, mbw | 0, mbw | CURPIPE, D0FIFOSEL);
	r8a66597_mdfy(r8a66597, mbw | 0, mbw | CURPIPE, D1FIFOSEL);

	r8a66597_mdfy(r8a66597, mbw | pipe->info.pipenum, mbw | CURPIPE,
		      pipe->fifosel);
	r8a66597_reg_wait(r8a66597, pipe->fifosel, CURPIPE, pipe->info.pipenum);
}

static u16 r8a66597_get_pipenum(struct urb *urb, struct usb_host_endpoint *hep)
{
	struct r8a66597_pipe *pipe = hep->hcpriv;

	if (usb_pipeendpoint(urb->pipe) == 0)
		return 0;
	else
		return pipe->info.pipenum;
}

static u16 get_urb_to_r8a66597_addr(struct r8a66597 *r8a66597, struct urb *urb)
{
	struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb);

	return (usb_pipedevice(urb->pipe) == 0) ? 0 : dev->address;
}

static unsigned short *get_toggle_pointer(struct r8a66597_device *dev,
					  int urb_pipe)
{
	if (!dev)
		return NULL;

	return usb_pipein(urb_pipe) ? &dev->ep_in_toggle : &dev->ep_out_toggle;
}

/* this function must be called with interrupt disabled */
static void pipe_toggle_set(struct r8a66597 *r8a66597,
			    struct r8a66597_pipe *pipe,
			    struct urb *urb, int set)
{
	struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb);
	unsigned char endpoint = usb_pipeendpoint(urb->pipe);
	unsigned short *toggle = get_toggle_pointer(dev, urb->pipe);

	if (!toggle)
		return;

	if (set)
		*toggle |= 1 << endpoint;
	else
		*toggle &= ~(1 << endpoint);
}

/* this function must be called with interrupt disabled */
static void pipe_toggle_save(struct r8a66597 *r8a66597,
			     struct r8a66597_pipe *pipe,
			     struct urb *urb)
{
	if (r8a66597_read(r8a66597, pipe->pipectr) & SQMON)
		pipe_toggle_set(r8a66597, pipe, urb, 1);
	else
		pipe_toggle_set(r8a66597, pipe, urb, 0);
}

/* this function must be called with interrupt disabled */
static void pipe_toggle_restore(struct r8a66597 *r8a66597,
				struct r8a66597_pipe *pipe,
				struct urb *urb)
{
	struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb);
	unsigned char endpoint = usb_pipeendpoint(urb->pipe);
	unsigned short *toggle = get_toggle_pointer(dev, urb->pipe);

	if (!toggle)
		return;

	r8a66597_pipe_toggle(r8a66597, pipe, *toggle & (1 << endpoint));
}

/* this function must be called with interrupt disabled */
static void pipe_buffer_setting(struct r8a66597 *r8a66597,
				struct r8a66597_pipe_info *info)
{
	u16 val = 0;

	if (info->pipenum == 0)
		return;

	r8a66597_bset(r8a66597, ACLRM, get_pipectr_addr(info->pipenum));
	r8a66597_bclr(r8a66597, ACLRM, get_pipectr_addr(info->pipenum));
	r8a66597_write(r8a66597, info->pipenum, PIPESEL);
	if (!info->dir_in)
		val |= R8A66597_DIR;
	if (info->type == R8A66597_BULK && info->dir_in)
		val |= R8A66597_DBLB | R8A66597_SHTNAK;
	val |= info->type | info->epnum;
	r8a66597_write(r8a66597, val, PIPECFG);

	r8a66597_write(r8a66597, (info->buf_bsize << 10) | (info->bufnum),
		       PIPEBUF);
	r8a66597_write(r8a66597, make_devsel(info->address) | info->maxpacket,
		       PIPEMAXP);
	r8a66597_write(r8a66597, info->interval, PIPEPERI);
}

/* this function must be called with interrupt disabled */
static void pipe_setting(struct r8a66597 *r8a66597, struct r8a66597_td *td)
{
	struct r8a66597_pipe_info *info;
	struct urb *urb = td->urb;

	if (td->pipenum > 0) {
		info = &td->pipe->info;
		cfifo_change(r8a66597, 0);
		pipe_buffer_setting(r8a66597, info);

		if (!usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
				   usb_pipeout(urb->pipe)) &&
		    !usb_pipecontrol(urb->pipe)) {
			r8a66597_pipe_toggle(r8a66597, td->pipe, 0);
			pipe_toggle_set(r8a66597, td->pipe, urb, 0);
			clear_all_buffer(r8a66597, td->pipe);
			usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
				      usb_pipeout(urb->pipe), 1);
		}
		pipe_toggle_restore(r8a66597, td->pipe, urb);
	}
}

/* this function must be called with interrupt disabled */
static u16 get_empty_pipenum(struct r8a66597 *r8a66597,
			     struct usb_endpoint_descriptor *ep)
{
	u16 array[R8A66597_MAX_NUM_PIPE], i = 0, min;

	memset(array, 0, sizeof(array));
	switch (usb_endpoint_type(ep)) {
	case USB_ENDPOINT_XFER_BULK:
		if (usb_endpoint_dir_in(ep))
			array[i++] = 4;
		else {
			array[i++] = 3;
			array[i++] = 5;
		}
		break;
	case USB_ENDPOINT_XFER_INT:
		if (usb_endpoint_dir_in(ep)) {
			array[i++] = 6;
			array[i++] = 7;
			array[i++] = 8;
		} else
			array[i++] = 9;
		break;
	case USB_ENDPOINT_XFER_ISOC:
		if (usb_endpoint_dir_in(ep))
			array[i++] = 2;
		else
			array[i++] = 1;
		break;
	default:
		printk(KERN_ERR "r8a66597: Illegal type\n");
		return 0;
	}

	i = 1;
	min = array[0];
	while (array[i] != 0) {
		if (r8a66597->pipe_cnt[min] > r8a66597->pipe_cnt[array[i]])
			min = array[i];
		i++;
	}

	return min;
}

static u16 get_r8a66597_type(__u8 type)
{
	u16 r8a66597_type;

	switch (type) {
	case USB_ENDPOINT_XFER_BULK:
		r8a66597_type = R8A66597_BULK;
		break;
	case USB_ENDPOINT_XFER_INT:
		r8a66597_type = R8A66597_INT;
		break;
	case USB_ENDPOINT_XFER_ISOC:
		r8a66597_type = R8A66597_ISO;
		break;
	default:
		printk(KERN_ERR "r8a66597: Illegal type\n");
		r8a66597_type = 0x0000;
		break;
	}

	return r8a66597_type;
}

static u16 get_bufnum(u16 pipenum)
{
	u16 bufnum = 0;

	if (pipenum == 0)
		bufnum = 0;
	else if (check_bulk_or_isoc(pipenum))
		bufnum = 8 + (pipenum - 1) * R8A66597_BUF_BSIZE*2;
	else if (check_interrupt(pipenum))
		bufnum = 4 + (pipenum - 6);
	else
		printk(KERN_ERR "r8a66597: Illegal pipenum (%d)\n", pipenum);

	return bufnum;
}

static u16 get_buf_bsize(u16 pipenum)
{
	u16 buf_bsize = 0;

	if (pipenum == 0)
		buf_bsize = 3;
	else if (check_bulk_or_isoc(pipenum))
		buf_bsize = R8A66597_BUF_BSIZE - 1;
	else if (check_interrupt(pipenum))
		buf_bsize = 0;
	else
		printk(KERN_ERR "r8a66597: Illegal pipenum (%d)\n", pipenum);

	return buf_bsize;
}

/* this function must be called with interrupt disabled */
static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597,
				     struct r8a66597_device *dev,
				     struct r8a66597_pipe *pipe,
				     struct urb *urb)
{
	int i;
	struct r8a66597_pipe_info *info = &pipe->info;
	unsigned short mbw = mbw_value(r8a66597);

	/* pipe dma is only for external controlles */
	if (r8a66597->pdata->on_chip)
		return;

	if ((pipe->info.pipenum != 0) && (info->type != R8A66597_INT)) {
		for (i = 0; i < R8A66597_MAX_DMA_CHANNEL; i++) {
			if ((r8a66597->dma_map & (1 << i)) != 0)
				continue;

			dev_info(&dev->udev->dev,
				 "address %d, EndpointAddress 0x%02x use "
				 "DMA FIFO\n", usb_pipedevice(urb->pipe),
				 info->dir_in ?
				 	USB_ENDPOINT_DIR_MASK + info->epnum
					: info->epnum);

			r8a66597->dma_map |= 1 << i;
			dev->dma_map |= 1 << i;
			set_pipe_reg_addr(pipe, i);

			cfifo_change(r8a66597, 0);
			r8a66597_mdfy(r8a66597, mbw | pipe->info.pipenum,
				      mbw | CURPIPE, pipe->fifosel);

			r8a66597_reg_wait(r8a66597, pipe->fifosel, CURPIPE,
					  pipe->info.pipenum);
			r8a66597_bset(r8a66597, BCLR, pipe->fifoctr);
			break;
		}
	}
}

/* this function must be called with interrupt disabled */
static void enable_r8a66597_pipe(struct r8a66597 *r8a66597, struct urb *urb,
				 struct usb_host_endpoint *hep,
				 struct r8a66597_pipe_info *info)
{
	struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb);
	struct r8a66597_pipe *pipe = hep->hcpriv;

	dbg("enable_pipe:");

	pipe->info = *info;
	set_pipe_reg_addr(pipe, R8A66597_PIPE_NO_DMA);
	r8a66597->pipe_cnt[pipe->info.pipenum]++;
	dev->pipe_cnt[pipe->info.pipenum]++;

	enable_r8a66597_pipe_dma(r8a66597, dev, pipe, urb);
}

static void r8a66597_urb_done(struct r8a66597 *r8a66597, struct urb *urb,
			      int status)
__releases(r8a66597->lock)
__acquires(r8a66597->lock)
{
	if (usb_pipein(urb->pipe) && usb_pipetype(urb->pipe) != PIPE_CONTROL) {
		void *ptr;

		for (ptr = urb->transfer_buffer;
		     ptr < urb->transfer_buffer + urb->transfer_buffer_length;
		     ptr += PAGE_SIZE)
			flush_dcache_page(virt_to_page(ptr));
	}

	usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb);
	spin_unlock(&r8a66597->lock);
	usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb, status);
	spin_lock(&r8a66597->lock);
}

/* this function must be called with interrupt disabled */
static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address)
{
	struct r8a66597_td *td, *next;
	struct urb *urb;
	struct list_head *list = &r8a66597->pipe_queue[pipenum];

	if (list_empty(list))
		return;

	list_for_each_entry_safe(td, next, list, queue) {
		if (td->address != address)
			continue;

		urb = td->urb;
		list_del(&td->queue);
		kfree(td);

		if (urb)
			r8a66597_urb_done(r8a66597, urb, -ENODEV);

		break;
	}
}

/* this function must be called with interrupt disabled */
static void disable_r8a66597_pipe_all(struct r8a66597 *r8a66597,
				      struct r8a66597_device *dev)
{
	int check_ep0 = 0;
	u16 pipenum;

	if (!dev)
		return;

	for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
		if (!dev->pipe_cnt[pipenum])
			continue;

		if (!check_ep0) {
			check_ep0 = 1;
			force_dequeue(r8a66597, 0, dev->address);
		}

		r8a66597->pipe_cnt[pipenum] -= dev->pipe_cnt[pipenum];
		dev->pipe_cnt[pipenum] = 0;
		force_dequeue(r8a66597, pipenum, dev->address);
	}

	dbg("disable_pipe");

	r8a66597->dma_map &= ~(dev->dma_map);
	dev->dma_map = 0;
}

static u16 get_interval(struct urb *urb, __u8 interval)
{
	u16 time = 1;
	int i;

	if (urb->dev->speed == USB_SPEED_HIGH) {
		if (interval > IITV)
			time = IITV;
		else
			time = interval ? interval - 1 : 0;
	} else {
		if (interval > 128) {
			time = IITV;
		} else {
			/* calculate the nearest value for PIPEPERI */
			for (i = 0; i < 7; i++) {
				if ((1 << i) < interval &&
				    (1 << (i + 1) > interval))
					time = 1 << i;
			}
		}
	}

	return time;
}

static unsigned long get_timer_interval(struct urb *urb, __u8 interval)
{
	__u8 i;
	unsigned long time = 1;

	if (usb_pipeisoc(urb->pipe))
		return 0;

	if (get_r8a66597_usb_speed(urb->dev->speed) == HSMODE) {
		for (i = 0; i < (interval - 1); i++)
			time *= 2;
		time = time * 125 / 1000;	/* uSOF -> msec */
	} else {
		time = interval;
	}

	return time;
}

/* this function must be called with interrupt disabled */
static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb,
			   struct usb_host_endpoint *hep,
			   struct usb_endpoint_descriptor *ep)
{
	struct r8a66597_pipe_info info;

	info.pipenum = get_empty_pipenum(r8a66597, ep);
	info.address = get_urb_to_r8a66597_addr(r8a66597, urb);
	info.epnum = usb_endpoint_num(ep);
	info.maxpacket = le16_to_cpu(ep->wMaxPacketSize);
	info.type = get_r8a66597_type(usb_endpoint_type(ep));
	info.bufnum = get_bufnum(info.pipenum);
	info.buf_bsize = get_buf_bsize(info.pipenum);
	if (info.type == R8A66597_BULK) {
		info.interval = 0;
		info.timer_interval = 0;
	} else {
		info.interval = get_interval(urb, ep->bInterval);
		info.timer_interval = get_timer_interval(urb, ep->bInterval);
	}
	if (usb_endpoint_dir_in(ep))
		info.dir_in = 1;
	else
		info.dir_in = 0;

	enable_r8a66597_pipe(r8a66597, urb, hep, &info);
}

static void init_pipe_config(struct r8a66597 *r8a66597, struct urb *urb)
{
	struct r8a66597_device *dev;

	dev = get_urb_to_r8a66597_dev(r8a66597, urb);
	dev->state = USB_STATE_CONFIGURED;
}

static void pipe_irq_enable(struct r8a66597 *r8a66597, struct urb *urb,
			    u16 pipenum)
{
	if (pipenum == 0 && usb_pipeout(urb->pipe))
		enable_irq_empty(r8a66597, pipenum);
	else
		enable_irq_ready(r8a66597, pipenum);

	if (!usb_pipeisoc(urb->pipe))
		enable_irq_nrdy(r8a66597, pipenum);
}

static void pipe_irq_disable(struct r8a66597 *r8a66597, u16 pipenum)
{
	disable_irq_ready(r8a66597, pipenum);
	disable_irq_nrdy(r8a66597, pipenum);
}

static void r8a66597_root_hub_start_polling(struct r8a66597 *r8a66597)
{
	mod_timer(&r8a66597->rh_timer,
			jiffies + msecs_to_jiffies(R8A66597_RH_POLL_TIME));
}

static void start_root_hub_sampling(struct r8a66597 *r8a66597, int port,
					int connect)
{
	struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];

	rh->old_syssts = r8a66597_read(r8a66597, get_syssts_reg(port)) & LNST;
	rh->scount = R8A66597_MAX_SAMPLING;
	if (connect)
		rh->port |= 1 << USB_PORT_FEAT_CONNECTION;
	else
		rh->port &= ~(1 << USB_PORT_FEAT_CONNECTION);
	rh->port |= 1 << USB_PORT_FEAT_C_CONNECTION;

	r8a66597_root_hub_start_polling(r8a66597);
}

/* this function must be called with interrupt disabled */
static void r8a66597_check_syssts(struct r8a66597 *r8a66597, int port,
					u16 syssts)
__releases(r8a66597->lock)
__acquires(r8a66597->lock)
{
	if (syssts == SE0) {
		r8a66597_write(r8a66597, ~ATTCH, get_intsts_reg(port));
		r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port));
	} else {
		if (syssts == FS_JSTS)
			r8a66597_bset(r8a66597, HSE, get_syscfg_reg(port));
		else if (syssts == LS_JSTS)
			r8a66597_bclr(r8a66597, HSE, get_syscfg_reg(port));

		r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port));
		r8a66597_bset(r8a66597, DTCHE, get_intenb_reg(port));

		if (r8a66597->bus_suspended)
			usb_hcd_resume_root_hub(r8a66597_to_hcd(r8a66597));
	}

	spin_unlock(&r8a66597->lock);
	usb_hcd_poll_rh_status(r8a66597_to_hcd(r8a66597));
	spin_lock(&r8a66597->lock);
}

/* this function must be called with interrupt disabled */
static void r8a66597_usb_connect(struct r8a66597 *r8a66597, int port)
{
	u16 speed = get_rh_usb_speed(r8a66597, port);
	struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];

	rh->port &= ~((1 << USB_PORT_FEAT_HIGHSPEED) |
		      (1 << USB_PORT_FEAT_LOWSPEED));
	if (speed == HSMODE)
		rh->port |= (1 << USB_PORT_FEAT_HIGHSPEED);
	else if (speed == LSMODE)
		rh->port |= (1 << USB_PORT_FEAT_LOWSPEED);

	rh->port &= ~(1 << USB_PORT_FEAT_RESET);
	rh->port |= 1 << USB_PORT_FEAT_ENABLE;
}

/* this function must be called with interrupt disabled */
static void r8a66597_usb_disconnect(struct r8a66597 *r8a66597, int port)
{
	struct r8a66597_device *dev = r8a66597->root_hub[port].dev;

	disable_r8a66597_pipe_all(r8a66597, dev);
	free_usb_address(r8a66597, dev, 0);

	start_root_hub_sampling(r8a66597, port, 0);
}

/* this function must be called with interrupt disabled */
static void prepare_setup_packet(struct r8a66597 *r8a66597,
				 struct r8a66597_td *td)
{
	int i;
	__le16 *p = (__le16 *)td->urb->setup_packet;
	unsigned long setup_addr = USBREQ;

	r8a66597_write(r8a66597, make_devsel(td->address) | td->maxpacket,
		       DCPMAXP);
	r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);

	for (i = 0; i < 4; i++) {
		r8a66597_write(r8a66597, le16_to_cpu(p[i]), setup_addr);
		setup_addr += 2;
	}
	r8a66597_write(r8a66597, SUREQ, DCPCTR);
}

/* this function must be called with interrupt disabled */
static void prepare_packet_read(struct r8a66597 *r8a66597,
				struct r8a66597_td *td)
{
	struct urb *urb = td->urb;

	if (usb_pipecontrol(urb->pipe)) {
		r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
		r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);
		r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
		if (urb->actual_length == 0) {
			r8a66597_pipe_toggle(r8a66597, td->pipe, 1);
			r8a66597_write(r8a66597, BCLR, CFIFOCTR);
		}
		pipe_irq_disable(r8a66597, td->pipenum);
		pipe_start(r8a66597, td->pipe);
		pipe_irq_enable(r8a66597, urb, td->pipenum);
	} else {
		if (urb->actual_length == 0) {
			pipe_irq_disable(r8a66597, td->pipenum);
			pipe_setting(r8a66597, td);
			pipe_stop(r8a66597, td->pipe);
			r8a66597_write(r8a66597, ~(1 << td->pipenum), BRDYSTS);

			if (td->pipe->pipetre) {
				r8a66597_write(r8a66597, TRCLR,
						td->pipe->pipetre);
				r8a66597_write(r8a66597,
						DIV_ROUND_UP
						  (urb->transfer_buffer_length,
						   td->maxpacket),
						td->pipe->pipetrn);
				r8a66597_bset(r8a66597, TRENB,
						td->pipe->pipetre);
			}

			pipe_start(r8a66597, td->pipe);
			pipe_irq_enable(r8a66597, urb, td->pipenum);
		}
	}
}

/* this function must be called with interrupt disabled */
static void prepare_packet_write(struct r8a66597 *r8a66597,
				 struct r8a66597_td *td)
{
	u16 tmp;
	struct urb *urb = td->urb;

	if (usb_pipecontrol(urb->pipe)) {
		pipe_stop(r8a66597, td->pipe);
		r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG);
		r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL);
		r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
		if (urb->actual_length == 0) {
			r8a66597_pipe_toggle(r8a66597, td->pipe, 1);
			r8a66597_write(r8a66597, BCLR, CFIFOCTR);
		}
	} else {
		if (urb->actual_length == 0)
			pipe_setting(r8a66597, td);
		if (td->pipe->pipetre)
			r8a66597_bclr(r8a66597, TRENB, td->pipe->pipetre);
	}
	r8a66597_write(r8a66597, ~(1 << td->pipenum), BRDYSTS);

	fifo_change_from_pipe(r8a66597, td->pipe);
	tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
	if (unlikely((tmp & FRDY) == 0))
		pipe_irq_enable(r8a66597, urb, td->pipenum);
	else
		packet_write(r8a66597, td->pipenum);
	pipe_start(r8a66597, td->pipe);
}

/* this function must be called with interrupt disabled */
static void prepare_status_packet(struct r8a66597 *r8a66597,
				  struct r8a66597_td *td)
{
	struct urb *urb = td->urb;

	r8a66597_pipe_toggle(r8a66597, td->pipe, 1);
	pipe_stop(r8a66597, td->pipe);

	if (urb->setup_packet[0] & USB_ENDPOINT_DIR_MASK) {
		r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG);
		r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL);
		r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
		r8a66597_write(r8a66597, ~BEMP0, BEMPSTS);
		r8a66597_write(r8a66597, BCLR | BVAL, CFIFOCTR);
		enable_irq_empty(r8a66597, 0);
	} else {
		r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
		r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);
		r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
		r8a66597_write(r8a66597, BCLR, CFIFOCTR);
		enable_irq_ready(r8a66597, 0);
	}
	enable_irq_nrdy(r8a66597, 0);
	pipe_start(r8a66597, td->pipe);
}

static int is_set_address(unsigned char *setup_packet)
{
	if (((setup_packet[0] & USB_TYPE_MASK) == USB_TYPE_STANDARD) &&
			setup_packet[1] == USB_REQ_SET_ADDRESS)
		return 1;
	else
		return 0;
}

/* this function must be called with interrupt disabled */
static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
{
	BUG_ON(!td);

	switch (td->type) {
	case USB_PID_SETUP:
		if (is_set_address(td->urb->setup_packet)) {
			td->set_address = 1;
			td->urb->setup_packet[2] = alloc_usb_address(r8a66597,
								     td->urb);
			if (td->urb->setup_packet[2] == 0)
				return -EPIPE;
		}
		prepare_setup_packet(r8a66597, td);
		break;
	case USB_PID_IN:
		prepare_packet_read(r8a66597, td);
		break;
	case USB_PID_OUT:
		prepare_packet_write(r8a66597, td);
		break;
	case USB_PID_ACK:
		prepare_status_packet(r8a66597, td);
		break;
	default:
		printk(KERN_ERR "r8a66597: invalid type.\n");
		break;
	}

	return 0;
}

static int check_transfer_finish(struct r8a66597_td *td, struct urb *urb)
{
	if (usb_pipeisoc(urb->pipe)) {
		if (urb->number_of_packets == td->iso_cnt)
			return 1;
	}

	/* control or bulk or interrupt */
	if ((urb->transfer_buffer_length <= urb->actual_length) ||
	    (td->short_packet) || (td->zero_packet))
		return 1;

	return 0;
}

/* this function must be called with interrupt disabled */
static void set_td_timer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
{
	unsigned long time;

	BUG_ON(!td);

	if (!list_empty(&r8a66597->pipe_queue[td->pipenum]) &&
	    !usb_pipecontrol(td->urb->pipe) && usb_pipein(td->urb->pipe)) {
		r8a66597->timeout_map |= 1 << td->pipenum;
		switch (usb_pipetype(td->urb->pipe)) {
		case PIPE_INTERRUPT:
		case PIPE_ISOCHRONOUS:
			time = 30;
			break;
		default:
			time = 300;
			break;
		}

		mod_timer(&r8a66597->td_timer[td->pipenum],
			  jiffies + msecs_to_jiffies(time));
	}
}

/* this function must be called with interrupt disabled */
static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td,
		u16 pipenum, struct urb *urb, int status)
__releases(r8a66597->lock) __acquires(r8a66597->lock)
{
	int restart = 0;
	struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);

	r8a66597->timeout_map &= ~(1 << pipenum);

	if (likely(td)) {
		if (td->set_address && (status != 0 || urb->unlinked))
			r8a66597->address_map &= ~(1 << urb->setup_packet[2]);

		pipe_toggle_save(r8a66597, td->pipe, urb);
		list_del(&td->queue);
		kfree(td);
	}

	if (!list_empty(&r8a66597->pipe_queue[pipenum]))
		restart = 1;

	if (likely(urb)) {
		if (usb_pipeisoc(urb->pipe))
			urb->start_frame = r8a66597_get_frame(hcd);

		r8a66597_urb_done(r8a66597, urb, status);
	}

	if (restart) {
		td = r8a66597_get_td(r8a66597, pipenum);
		if (unlikely(!td))
			return;

		start_transfer(r8a66597, td);
		set_td_timer(r8a66597, td);
	}
}

static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
{
	u16 tmp;
	int rcv_len, bufsize, urb_len, size;
	u16 *buf;
	struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
	struct urb *urb;
	int finish = 0;
	int status = 0;

	if (unlikely(!td))
		return;
	urb = td->urb;

	fifo_change_from_pipe(r8a66597, td->pipe);
	tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
	if (unlikely((tmp & FRDY) == 0)) {
		pipe_stop(r8a66597, td->pipe);
		pipe_irq_disable(r8a66597, pipenum);
		printk(KERN_ERR "r8a66597: in fifo not ready (%d)\n", pipenum);
		finish_request(r8a66597, td, pipenum, td->urb, -EPIPE);
		return;
	}

	/* prepare parameters */
	rcv_len = tmp & DTLN;
	if (usb_pipeisoc(urb->pipe)) {
		buf = (u16 *)(urb->transfer_buffer +
				urb->iso_frame_desc[td->iso_cnt].offset);
		urb_len = urb->iso_frame_desc[td->iso_cnt].length;
	} else {
		buf = (void *)urb->transfer_buffer + urb->actual_length;
		urb_len = urb->transfer_buffer_length - urb->actual_length;
	}
	bufsize = min(urb_len, (int) td->maxpacket);
	if (rcv_len <= bufsize) {
		size = rcv_len;
	} else {
		size = bufsize;
		status = -EOVERFLOW;
		finish = 1;
	}

	/* update parameters */
	urb->actual_length += size;
	if (rcv_len == 0)
		td->zero_packet = 1;
	if (rcv_len < bufsize) {
		td->short_packet = 1;
	}
	if (usb_pipeisoc(urb->pipe)) {
		urb->iso_frame_desc[td->iso_cnt].actual_length = size;
		urb->iso_frame_desc[td->iso_cnt].status = status;
		td->iso_cnt++;
		finish = 0;
	}

	/* check transfer finish */
	if (finish || check_transfer_finish(td, urb)) {
		pipe_stop(r8a66597, td->pipe);
		pipe_irq_disable(r8a66597, pipenum);
		finish = 1;
	}

	/* read fifo */
	if (urb->transfer_buffer) {
		if (size == 0)
			r8a66597_write(r8a66597, BCLR, td->pipe->fifoctr);
		else
			r8a66597_read_fifo(r8a66597, td->pipe->fifoaddr,
					   buf, size);
	}

	if (finish && pipenum != 0)
		finish_request(r8a66597, td, pipenum, urb, status);
}

static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
{
	u16 tmp;
	int bufsize, size;
	u16 *buf;
	struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
	struct urb *urb;

	if (unlikely(!td))
		return;
	urb = td->urb;

	fifo_change_from_pipe(r8a66597, td->pipe);
	tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
	if (unlikely((tmp & FRDY) == 0)) {
		pipe_stop(r8a66597, td->pipe);
		pipe_irq_disable(r8a66597, pipenum);
		printk(KERN_ERR "r8a66597: out fifo not ready (%d)\n", pipenum);
		finish_request(r8a66597, td, pipenum, urb, -EPIPE);
		return;
	}

	/* prepare parameters */
	bufsize = td->maxpacket;
	if (usb_pipeisoc(urb->pipe)) {
		buf = (u16 *)(urb->transfer_buffer +
				urb->iso_frame_desc[td->iso_cnt].offset);
		size = min(bufsize,
			   (int)urb->iso_frame_desc[td->iso_cnt].length);
	} else {
		buf = (u16 *)(urb->transfer_buffer + urb->actual_length);
		size = min_t(u32, bufsize,
			   urb->transfer_buffer_length - urb->actual_length);
	}

	/* write fifo */
	if (pipenum > 0)
		r8a66597_write(r8a66597, ~(1 << pipenum), BEMPSTS);
	if (urb->transfer_buffer) {
		r8a66597_write_fifo(r8a66597, td->pipe->fifoaddr, buf, size);
		if (!usb_pipebulk(urb->pipe) || td->maxpacket != size)
			r8a66597_write(r8a66597, BVAL, td->pipe->fifoctr);
	}

	/* update parameters */
	urb->actual_length += size;
	if (usb_pipeisoc(urb->pipe)) {
		urb->iso_frame_desc[td->iso_cnt].actual_length = size;
		urb->iso_frame_desc[td->iso_cnt].status = 0;
		td->iso_cnt++;
	}

	/* check transfer finish */
	if (check_transfer_finish(td, urb)) {
		disable_irq_ready(r8a66597, pipenum);
		enable_irq_empty(r8a66597, pipenum);
		if (!usb_pipeisoc(urb->pipe))
			enable_irq_nrdy(r8a66597, pipenum);
	} else
		pipe_irq_enable(r8a66597, urb, pipenum);
}


static void check_next_phase(struct r8a66597 *r8a66597, int status)
{
	struct r8a66597_td *td = r8a66597_get_td(r8a66597, 0);
	struct urb *urb;
	u8 finish = 0;

	if (unlikely(!td))
		return;
	urb = td->urb;

	switch (td->type) {
	case USB_PID_IN:
	case USB_PID_OUT:
		if (check_transfer_finish(td, urb))
			td->type = USB_PID_ACK;
		break;
	case USB_PID_SETUP:
		if (urb->transfer_buffer_length == urb->actual_length)
			td->type = USB_PID_ACK;
		else if (usb_pipeout(urb->pipe))
			td->type = USB_PID_OUT;
		else
			td->type = USB_PID_IN;
		break;
	case USB_PID_ACK:
		finish = 1;
		break;
	}

	if (finish || status != 0 || urb->unlinked)
		finish_request(r8a66597, td, 0, urb, status);
	else
		start_transfer(r8a66597, td);
}

static int get_urb_error(struct r8a66597 *r8a66597, u16 pipenum)
{
	struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);

	if (td) {
		u16 pid = r8a66597_read(r8a66597, td->pipe->pipectr) & PID;

		if (pid == PID_NAK)
			return -ECONNRESET;
		else
			return -EPIPE;
	}
	return 0;
}

static void irq_pipe_ready(struct r8a66597 *r8a66597)
{
	u16 check;
	u16 pipenum;
	u16 mask;
	struct r8a66597_td *td;

	mask = r8a66597_read(r8a66597, BRDYSTS)
	       & r8a66597_read(r8a66597, BRDYENB);
	r8a66597_write(r8a66597, ~mask, BRDYSTS);
	if (mask & BRDY0) {
		td = r8a66597_get_td(r8a66597, 0);
		if (td && td->type == USB_PID_IN)
			packet_read(r8a66597, 0);
		else
			pipe_irq_disable(r8a66597, 0);
		check_next_phase(r8a66597, 0);
	}

	for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
		check = 1 << pipenum;
		if (mask & check) {
			td = r8a66597_get_td(r8a66597, pipenum);
			if (unlikely(!td))
				continue;

			if (td->type == USB_PID_IN)
				packet_read(r8a66597, pipenum);
			else if (td->type == USB_PID_OUT)
				packet_write(r8a66597, pipenum);
		}
	}
}

static void irq_pipe_empty(struct r8a66597 *r8a66597)
{
	u16 tmp;
	u16 check;
	u16 pipenum;
	u16 mask;
	struct r8a66597_td *td;

	mask = r8a66597_read(r8a66597, BEMPSTS)
	       & r8a66597_read(r8a66597, BEMPENB);
	r8a66597_write(r8a66597, ~mask, BEMPSTS);
	if (mask & BEMP0) {
		cfifo_change(r8a66597, 0);
		td = r8a66597_get_td(r8a66597, 0);
		if (td && td->type != USB_PID_OUT)
			disable_irq_empty(r8a66597, 0);
		check_next_phase(r8a66597, 0);
	}

	for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
		check = 1 << pipenum;
		if (mask &  check) {
			struct r8a66597_td *td;
			td = r8a66597_get_td(r8a66597, pipenum);
			if (unlikely(!td))
				continue;

			tmp = r8a66597_read(r8a66597, td->pipe->pipectr);
			if ((tmp & INBUFM) == 0) {
				disable_irq_empty(r8a66597, pipenum);
				pipe_irq_disable(r8a66597, pipenum);
				finish_request(r8a66597, td, pipenum, td->urb,
						0);
			}
		}
	}
}

static void irq_pipe_nrdy(struct r8a66597 *r8a66597)
{
	u16 check;
	u16 pipenum;
	u16 mask;
	int status;

	mask = r8a66597_read(r8a66597, NRDYSTS)
	       & r8a66597_read(r8a66597, NRDYENB);
	r8a66597_write(r8a66597, ~mask, NRDYSTS);
	if (mask & NRDY0) {
		cfifo_change(r8a66597, 0);
		status = get_urb_error(r8a66597, 0);
		pipe_irq_disable(r8a66597, 0);
		check_next_phase(r8a66597, status);
	}

	for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
		check = 1 << pipenum;
		if (mask & check) {
			struct r8a66597_td *td;
			td = r8a66597_get_td(r8a66597, pipenum);
			if (unlikely(!td))
				continue;

			status = get_urb_error(r8a66597, pipenum);
			pipe_irq_disable(r8a66597, pipenum);
			pipe_stop(r8a66597, td->pipe);
			finish_request(r8a66597, td, pipenum, td->urb, status);
		}
	}
}

static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
{
	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
	u16 intsts0, intsts1, intsts2;
	u16 intenb0, intenb1, intenb2;
	u16 mask0, mask1, mask2;
	int status;

	spin_lock(&r8a66597->lock);

	intsts0 = r8a66597_read(r8a66597, INTSTS0);
	intsts1 = r8a66597_read(r8a66597, INTSTS1);
	intsts2 = r8a66597_read(r8a66597, INTSTS2);
	intenb0 = r8a66597_read(r8a66597, INTENB0);
	intenb1 = r8a66597_read(r8a66597, INTENB1);
	intenb2 = r8a66597_read(r8a66597, INTENB2);

	mask2 = intsts2 & intenb2;
	mask1 = intsts1 & intenb1;
	mask0 = intsts0 & intenb0 & (BEMP | NRDY | BRDY);
	if (mask2) {
		if (mask2 & ATTCH) {
			r8a66597_write(r8a66597, ~ATTCH, INTSTS2);
			r8a66597_bclr(r8a66597, ATTCHE, INTENB2);

			/* start usb bus sampling */
			start_root_hub_sampling(r8a66597, 1, 1);
		}
		if (mask2 & DTCH) {
			r8a66597_write(r8a66597, ~DTCH, INTSTS2);
			r8a66597_bclr(r8a66597, DTCHE, INTENB2);
			r8a66597_usb_disconnect(r8a66597, 1);
		}
		if (mask2 & BCHG) {
			r8a66597_write(r8a66597, ~BCHG, INTSTS2);
			r8a66597_bclr(r8a66597, BCHGE, INTENB2);
			usb_hcd_resume_root_hub(r8a66597_to_hcd(r8a66597));
		}
	}

	if (mask1) {
		if (mask1 & ATTCH) {
			r8a66597_write(r8a66597, ~ATTCH, INTSTS1);
			r8a66597_bclr(r8a66597, ATTCHE, INTENB1);

			/* start usb bus sampling */
			start_root_hub_sampling(r8a66597, 0, 1);
		}
		if (mask1 & DTCH) {
			r8a66597_write(r8a66597, ~DTCH, INTSTS1);
			r8a66597_bclr(r8a66597, DTCHE, INTENB1);
			r8a66597_usb_disconnect(r8a66597, 0);
		}
		if (mask1 & BCHG) {
			r8a66597_write(r8a66597, ~BCHG, INTSTS1);
			r8a66597_bclr(r8a66597, BCHGE, INTENB1);
			usb_hcd_resume_root_hub(r8a66597_to_hcd(r8a66597));
		}

		if (mask1 & SIGN) {
			r8a66597_write(r8a66597, ~SIGN, INTSTS1);
			status = get_urb_error(r8a66597, 0);
			check_next_phase(r8a66597, status);
		}
		if (mask1 & SACK) {
			r8a66597_write(r8a66597, ~SACK, INTSTS1);
			check_next_phase(r8a66597, 0);
		}
	}
	if (mask0) {
		if (mask0 & BRDY)
			irq_pipe_ready(r8a66597);
		if (mask0 & BEMP)
			irq_pipe_empty(r8a66597);
		if (mask0 & NRDY)
			irq_pipe_nrdy(r8a66597);
	}

	spin_unlock(&r8a66597->lock);
	return IRQ_HANDLED;
}

/* this function must be called with interrupt disabled */
static void r8a66597_root_hub_control(struct r8a66597 *r8a66597, int port)
{
	u16 tmp;
	struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];

	if (rh->port & (1 << USB_PORT_FEAT_RESET)) {
		unsigned long dvstctr_reg = get_dvstctr_reg(port);

		tmp = r8a66597_read(r8a66597, dvstctr_reg);
		if ((tmp & USBRST) == USBRST) {
			r8a66597_mdfy(r8a66597, UACT, USBRST | UACT,
				      dvstctr_reg);
			r8a66597_root_hub_start_polling(r8a66597);
		} else
			r8a66597_usb_connect(r8a66597, port);
	}

	if (!(rh->port & (1 << USB_PORT_FEAT_CONNECTION))) {
		r8a66597_write(r8a66597, ~ATTCH, get_intsts_reg(port));
		r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port));
	}

	if (rh->scount > 0) {
		tmp = r8a66597_read(r8a66597, get_syssts_reg(port)) & LNST;
		if (tmp == rh->old_syssts) {
			rh->scount--;
			if (rh->scount == 0)
				r8a66597_check_syssts(r8a66597, port, tmp);
			else
				r8a66597_root_hub_start_polling(r8a66597);
		} else {
			rh->scount = R8A66597_MAX_SAMPLING;
			rh->old_syssts = tmp;
			r8a66597_root_hub_start_polling(r8a66597);
		}
	}
}

static void r8a66597_interval_timer(unsigned long _r8a66597)
{
	struct r8a66597 *r8a66597 = (struct r8a66597 *)_r8a66597;
	unsigned long flags;
	u16 pipenum;
	struct r8a66597_td *td;

	spin_lock_irqsave(&r8a66597->lock, flags);

	for (pipenum = 0; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
		if (!(r8a66597->interval_map & (1 << pipenum)))
			continue;
		if (timer_pending(&r8a66597->interval_timer[pipenum]))
			continue;

		td = r8a66597_get_td(r8a66597, pipenum);
		if (td)
			start_transfer(r8a66597, td);
	}

	spin_unlock_irqrestore(&r8a66597->lock, flags);
}

static void r8a66597_td_timer(unsigned long _r8a66597)
{
	struct r8a66597 *r8a66597 = (struct r8a66597 *)_r8a66597;
	unsigned long flags;
	u16 pipenum;
	struct r8a66597_td *td, *new_td = NULL;
	struct r8a66597_pipe *pipe;

	spin_lock_irqsave(&r8a66597->lock, flags);
	for (pipenum = 0; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
		if (!(r8a66597->timeout_map & (1 << pipenum)))
			continue;
		if (timer_pending(&r8a66597->td_timer[pipenum]))
			continue;

		td = r8a66597_get_td(r8a66597, pipenum);
		if (!td) {
			r8a66597->timeout_map &= ~(1 << pipenum);
			continue;
		}

		if (td->urb->actual_length) {
			set_td_timer(r8a66597, td);
			break;
		}

		pipe = td->pipe;
		pipe_stop(r8a66597, pipe);

		new_td = td;
		do {
			list_move_tail(&new_td->queue,
				       &r8a66597->pipe_queue[pipenum]);
			new_td = r8a66597_get_td(r8a66597, pipenum);
			if (!new_td) {
				new_td = td;
				break;
			}
		} while (td != new_td && td->address == new_td->address);

		start_transfer(r8a66597, new_td);

		if (td == new_td)
			r8a66597->timeout_map &= ~(1 << pipenum);
		else
			set_td_timer(r8a66597, new_td);
		break;
	}
	spin_unlock_irqrestore(&r8a66597->lock, flags);
}

static void r8a66597_timer(unsigned long _r8a66597)
{
	struct r8a66597 *r8a66597 = (struct r8a66597 *)_r8a66597;
	unsigned long flags;
	int port;

	spin_lock_irqsave(&r8a66597->lock, flags);

	for (port = 0; port < r8a66597->max_root_hub; port++)
		r8a66597_root_hub_control(r8a66597, port);

	spin_unlock_irqrestore(&r8a66597->lock, flags);
}

static int check_pipe_config(struct r8a66597 *r8a66597, struct urb *urb)
{
	struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb);

	if (dev && dev->address && dev->state != USB_STATE_CONFIGURED &&
	    (urb->dev->state == USB_STATE_CONFIGURED))
		return 1;
	else
		return 0;
}

static int r8a66597_start(struct usb_hcd *hcd)
{
	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);

	hcd->state = HC_STATE_RUNNING;
	return enable_controller(r8a66597);
}

static void r8a66597_stop(struct usb_hcd *hcd)
{
	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);

	disable_controller(r8a66597);
}

static void set_address_zero(struct r8a66597 *r8a66597, struct urb *urb)
{
	unsigned int usb_address = usb_pipedevice(urb->pipe);
	u16 root_port, hub_port;

	if (usb_address == 0) {
		get_port_number(r8a66597, urb->dev->devpath,
				&root_port, &hub_port);
		set_devadd_reg(r8a66597, 0,
			       get_r8a66597_usb_speed(urb->dev->speed),
			       get_parent_r8a66597_address(r8a66597, urb->dev),
			       hub_port, root_port);
	}
}

static struct r8a66597_td *r8a66597_make_td(struct r8a66597 *r8a66597,
					    struct urb *urb,
					    struct usb_host_endpoint *hep)
{
	struct r8a66597_td *td;
	u16 pipenum;

	td = kzalloc(sizeof(struct r8a66597_td), GFP_ATOMIC);
	if (td == NULL)
		return NULL;

	pipenum = r8a66597_get_pipenum(urb, hep);
	td->pipenum = pipenum;
	td->pipe = hep->hcpriv;
	td->urb = urb;
	td->address = get_urb_to_r8a66597_addr(r8a66597, urb);
	td->maxpacket = usb_maxpacket(urb->dev, urb->pipe,
				      !usb_pipein(urb->pipe));
	if (usb_pipecontrol(urb->pipe))
		td->type = USB_PID_SETUP;
	else if (usb_pipein(urb->pipe))
		td->type = USB_PID_IN;
	else
		td->type = USB_PID_OUT;
	INIT_LIST_HEAD(&td->queue);

	return td;
}

static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
				struct urb *urb,
				gfp_t mem_flags)
{
	struct usb_host_endpoint *hep = urb->ep;
	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
	struct r8a66597_td *td = NULL;
	int ret, request = 0;
	unsigned long flags;

	spin_lock_irqsave(&r8a66597->lock, flags);
	if (!get_urb_to_r8a66597_dev(r8a66597, urb)) {
		ret = -ENODEV;
		goto error_not_linked;
	}

	ret = usb_hcd_link_urb_to_ep(hcd, urb);
	if (ret)
		goto error_not_linked;

	if (!hep->hcpriv) {
		hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe),
				GFP_ATOMIC);
		if (!hep->hcpriv) {
			ret = -ENOMEM;
			goto error;
		}
		set_pipe_reg_addr(hep->hcpriv, R8A66597_PIPE_NO_DMA);
		if (usb_pipeendpoint(urb->pipe))
			init_pipe_info(r8a66597, urb, hep, &hep->desc);
	}

	if (unlikely(check_pipe_config(r8a66597, urb)))
		init_pipe_config(r8a66597, urb);

	set_address_zero(r8a66597, urb);
	td = r8a66597_make_td(r8a66597, urb, hep);
	if (td == NULL) {
		ret = -ENOMEM;
		goto error;
	}
	if (list_empty(&r8a66597->pipe_queue[td->pipenum]))
		request = 1;
	list_add_tail(&td->queue, &r8a66597->pipe_queue[td->pipenum]);
	urb->hcpriv = td;

	if (request) {
		if (td->pipe->info.timer_interval) {
			r8a66597->interval_map |= 1 << td->pipenum;
			mod_timer(&r8a66597->interval_timer[td->pipenum],
				  jiffies + msecs_to_jiffies(
					td->pipe->info.timer_interval));
		} else {
			ret = start_transfer(r8a66597, td);
			if (ret < 0) {
				list_del(&td->queue);
				kfree(td);
			}
		}
	} else
		set_td_timer(r8a66597, td);

error:
	if (ret)
		usb_hcd_unlink_urb_from_ep(hcd, urb);
error_not_linked:
	spin_unlock_irqrestore(&r8a66597->lock, flags);
	return ret;
}

static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
		int status)
{
	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
	struct r8a66597_td *td;
	unsigned long flags;
	int rc;

	spin_lock_irqsave(&r8a66597->lock, flags);
	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
	if (rc)
		goto done;

	if (urb->hcpriv) {
		td = urb->hcpriv;
		pipe_stop(r8a66597, td->pipe);
		pipe_irq_disable(r8a66597, td->pipenum);
		disable_irq_empty(r8a66597, td->pipenum);
		finish_request(r8a66597, td, td->pipenum, urb, status);
	}
 done:
	spin_unlock_irqrestore(&r8a66597->lock, flags);
	return rc;
}

static void r8a66597_endpoint_disable(struct usb_hcd *hcd,
				      struct usb_host_endpoint *hep)
{
	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
	struct r8a66597_pipe *pipe = (struct r8a66597_pipe *)hep->hcpriv;
	struct r8a66597_td *td;
	struct urb *urb = NULL;
	u16 pipenum;
	unsigned long flags;

	if (pipe == NULL)
		return;
	pipenum = pipe->info.pipenum;

	if (pipenum == 0) {
		kfree(hep->hcpriv);
		hep->hcpriv = NULL;
		return;
	}

	spin_lock_irqsave(&r8a66597->lock, flags);
	pipe_stop(r8a66597, pipe);
	pipe_irq_disable(r8a66597, pipenum);
	disable_irq_empty(r8a66597, pipenum);
	td = r8a66597_get_td(r8a66597, pipenum);
	if (td)
		urb = td->urb;
	finish_request(r8a66597, td, pipenum, urb, -ESHUTDOWN);
	kfree(hep->hcpriv);
	hep->hcpriv = NULL;
	spin_unlock_irqrestore(&r8a66597->lock, flags);
}

static int r8a66597_get_frame(struct usb_hcd *hcd)
{
	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
	return r8a66597_read(r8a66597, FRMNUM) & 0x03FF;
}

static void collect_usb_address_map(struct usb_device *udev, unsigned long *map)
{
	int chix;

	if (udev->state == USB_STATE_CONFIGURED &&
	    udev->parent && udev->parent->devnum > 1 &&
	    udev->parent->descriptor.bDeviceClass == USB_CLASS_HUB)
		map[udev->devnum/32] |= (1 << (udev->devnum % 32));

	for (chix = 0; chix < udev->maxchild; chix++) {
		struct usb_device *childdev = udev->children[chix];

		if (childdev)
			collect_usb_address_map(childdev, map);
	}
}

/* this function must be called with interrupt disabled */
static struct r8a66597_device *get_r8a66597_device(struct r8a66597 *r8a66597,
						   int addr)
{
	struct r8a66597_device *dev;
	struct list_head *list = &r8a66597->child_device;

	list_for_each_entry(dev, list, device_list) {
		if (dev->usb_address != addr)
			continue;

		return dev;
	}

	printk(KERN_ERR "r8a66597: get_r8a66597_device fail.(%d)\n", addr);
	return NULL;
}

static void update_usb_address_map(struct r8a66597 *r8a66597,
				   struct usb_device *root_hub,
				   unsigned long *map)
{
	int i, j, addr;
	unsigned long diff;
	unsigned long flags;

	for (i = 0; i < 4; i++) {
		diff = r8a66597->child_connect_map[i] ^ map[i];
		if (!diff)
			continue;

		for (j = 0; j < 32; j++) {
			if (!(diff & (1 << j)))
				continue;

			addr = i * 32 + j;
			if (map[i] & (1 << j))
				set_child_connect_map(r8a66597, addr);
			else {
				struct r8a66597_device *dev;

				spin_lock_irqsave(&r8a66597->lock, flags);
				dev = get_r8a66597_device(r8a66597, addr);
				disable_r8a66597_pipe_all(r8a66597, dev);
				free_usb_address(r8a66597, dev, 0);
				put_child_connect_map(r8a66597, addr);
				spin_unlock_irqrestore(&r8a66597->lock, flags);
			}
		}
	}
}

static void r8a66597_check_detect_child(struct r8a66597 *r8a66597,
					struct usb_hcd *hcd)
{
	struct usb_bus *bus;
	unsigned long now_map[4];

	memset(now_map, 0, sizeof(now_map));

	list_for_each_entry(bus, &usb_bus_list, bus_list) {
		if (!bus->root_hub)
			continue;

		if (bus->busnum != hcd->self.busnum)
			continue;

		collect_usb_address_map(bus->root_hub, now_map);
		update_usb_address_map(r8a66597, bus->root_hub, now_map);
	}
}

static int r8a66597_hub_status_data(struct usb_hcd *hcd, char *buf)
{
	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
	unsigned long flags;
	int i;

	r8a66597_check_detect_child(r8a66597, hcd);

	spin_lock_irqsave(&r8a66597->lock, flags);

	*buf = 0;	/* initialize (no change) */

	for (i = 0; i < r8a66597->max_root_hub; i++) {
		if (r8a66597->root_hub[i].port & 0xffff0000)
			*buf |= 1 << (i + 1);
	}

	spin_unlock_irqrestore(&r8a66597->lock, flags);

	return (*buf != 0);
}

static void r8a66597_hub_descriptor(struct r8a66597 *r8a66597,
				    struct usb_hub_descriptor *desc)
{
	desc->bDescriptorType = 0x29;
	desc->bHubContrCurrent = 0;