在目录 kernel26_h/drivers/usb/host/ohci-s3c2410.c 文件中将下面函数的内同修改为
static void s3c2410_start_hc(struct platform_device *dev, struct usb_hcd *hcd)
{
struct s3c2410_hcd_info *info = dev->dev.platform_data;
//======
unsigned long upllvalue = (0x38<<12)|(0x02<<4)|(0x01);
unsigned long upllvalue1 = (0x38<<12)|(0x02<<4)|(0x02);
dev_dbg(&dev->dev, "s3c2410_start_hc:\n");
//=====
__raw_writel(upllvalue,S3C2410_UPLLCON);
mdelay(20);
__raw_writel(upllvalue1,S3C2410_UPLLCON);
mdelay(20);
//=====
clk_enable(clk);
mdelay(10);
if (info != NULL) {
info->hcd
= hcd;
info->report_oc = s3c2410_hcd_oc;
if (info->enable_oc != NULL) {
(info->enable_oc)(info, 1);
}
}
}
主要功能是在 USB 寄存器初始化的之前给它较高的频率,等初始化完成后在将频率恢复为正常
的 48MHZ。
linux-2.6.28 系统移植 s3c6410 开发板 USB 不能识别的处理
初始化 OK,一插上 usb 就报如下错误:
/ # usb 1-1: new full speed USB device using s3c2410-ohci and addr
ess 2
usb 1-1: device descriptor read/64, error -62
usb 1-1: device descriptor read/64, error -62
usb 1-1: new full speed USB device using s3c2410-ohci and address
3
usb 1-1: device descriptor read/64, error -62
usb 1-1: device descriptor read/64, error -62
usb 1-1: new full speed USB device using s3c2410-ohci and address
4
usb 1-1: device not accepting address 4, error -62
usb 1-1: new full speed USB device using s3c2410-ohci and address
5
usb 1-1: device not accepting address 5, error -62
hub 1-0:1.0: unable to enumerate USB device on port 1
解决方法:
根据终端打印的错误
cd
include/asm-generic/errno.h
u-boot/include/asm-arm/errno.H
找到:
#define
ETIME
62
/*timer
expired*/
再由:
error-codes.txt 去找 usb
error
code
http://ftp.gnu.org/tmp/linux-libre-fsf2_2.6.28/linux-2.6.28/D
ocumentation/usb/error-codes.txt
-ETIME
(**)
No
response
packet
received
withi
n
the
prescribed
may
instead
be
bus
turn-around
time.
This
error
reported
as
-EPROTO
or
-EILSEQ.
由此可以判断,这个错误与 USB 设备超时有关。报告这个错误的地方在
drivers/usb/core/hub.c 中的 hub_port_init 部分,由于
usb_get_device_descriptor 获取 usb 设备资讯的时候产生了超时,这
样基本可以确定三种情况,1.USB 设备及介面有问题,2、usbcore 有问
题 3、usb
driver 有问题。
我们可以很容易的派出 1.2 的可能性,问题应该在
usb
driverimplement 部分造成。2.6 的内核 usb
driver 把 usb 规范
中对 usb 的操作集中到了 core 里面,针对不同设备的 implement 分别
归为 host、gadget、storage 等。基本确定问题就在 ohci-s3c2410.c
中。
原来是 USB Host 的 48MHz 时钟没有起来。
s3c6410 支持三个 PLL 分别是 APLL,MPLL 和 EPLL。APLL 为 ARM
提供时钟,产生 ARMCLK,MPLL 为所有和 AXI/AHB/APB 相连的模块
提供时钟,产生 HCLK 和 PCLK,EPLL 为特殊的外设提供时钟,产生
SCLK。
如图所示为 EPLL_CON 的 M、 P 和 S 的取值。
根据 s3c6410 的数据手册:
如图所示,描述的是用于 IrDA 和 USB host 的时钟发生器,通常 USB
借口需要 48M 的操作时钟。
从图中可也以说明,HCLK_GATE,PCLK_GATE 和 SCL_GATE 控制时
钟操作。如果一个位设置,则通过每个时钟分频器相应的时钟将会被提
供,否则,将被屏蔽。
HCLK_GATE 控制 HCLK,用于每个 Ips。每个 IP 的 AHB 接口逻辑被
独立地屏蔽,以减少动态电力消耗。PCLK_GATE 控制 PCLK。通过
SCLK_GATE 时钟被控制。
根据上图 EPLL 通道写出一下程序。
0
(0<<20)
(1<<30)
((1<<2)|(1<<5))
58 #define EPLL_CON01
359
360 #define UPLL_SRC_MASK ((1<<2)|(3<<5))
361 #define UPLL_SRC
362 #define UPLL_DIV1_MASK (0xf<<20)
363 #define UPLL_DIV1
364 #define UPLL_GATE_MASK (1<<30)
365 #define UPLL_GATE
void set_upll(void)
368 {
369
370
371
372
373
374
375
376
unsigned int tmp;
while(__raw_readl(S3C_EPLL_CON0)!=EPLL_CON00)
__raw_writel(EPLL_CON00,S3C_EPLL_CON0);
while(__raw_readl(S3C_EPLL_CON1)!=EPLL_CON01)
__raw_writel(EPLL_CON01,S3C_EPLL_CON1);
while(((tmp= __raw_readl(S3C_CLK_SRC))&UPLL_SRC_
__raw_writel((tmp&UPLL_SRC_MASK)|UPLL_SRC,S
while(((tmp=__raw_readl(S3C_CLK_DIV1))&UPLL_DIV1_
377
MASK)!=UPLL_SRC)
378
3C_CLK_SRC);
379
MASK)!=UPLL_DIV1)
380
3C_CLK_DIV1);
381
E_MASK)!=UPLL_GATE)
382
S3C_SCLK_GATE);
383 }
在 probe 中加入上面的函数修改 USB host 的时钟:
__raw_writel((tmp&UPLL_DIV1_MASK)|UPLL_DIV1,S
while(((tmp=__raw_readl(S3C_SCLK_GATE))&UPLL_GAT
__raw_writel((tmp&UPLL_GATE_MASK)|UPLL_GATE,
struct platform_device *dev)
struct usb_hcd *hcd = NULL;
int retval;
386 static int usb_hcd_s3c2410_probe (const struct hc_driver *driver,
387
388 {
389
390
391
392 #if !defined(CONFIG_ARCH_2410)
393
394 #endif
395
396
然后编译内核。
usb_host_clk_en();
set_upll();
USB 的不能识别的错误就解决了