1.5.5 USB驱动修改

初始化结束后,插上USB就报如下错误:

      / # usb 1-1: new full speed USB device using s3c2410-ohci and address 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: 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

解决方法:

问题就在ohci-s3c2410.c中,时钟设置出了问题,原来是USB Host的48MHz时钟没有起来。

s3c2410支持3个PLL,分别是APLL、MPLL和EPLL。APLL为ARM提供时钟,产生ARMCLK;MPLL为所有和AXI/AHB/APB相连的模块提供时钟,产生HCLK和PCLK;EPLL为特殊的外设提供时钟,产生SCLK。

如图1.7所示为EPLL_CON的M、P和S的取值。

图1.7 EPLL_CON的M、P和S的取值

图1.8描述的是用于IrDA和USB Host的时钟发生器,通常USB接口需要48MHz的操作时钟。

图1.8 USB原理图

从图1.8中可以看出,HCLK_GATE、PCLK_GATE和SCL_GATE控制时钟操作。如果设置一个位,则通过每个时钟分频器相应的时钟将会被提供,否则,将被屏蔽。

HCLK_GATE 控制HCLK,用于每个Ips。每个IP的AHB接口逻辑被独立地屏蔽,以减少动态电力消耗。PCLK_GATE控制PCLK,通过SCLK_GATE时钟被控制。

根据图1.8中的EPLL通道写出以下程序:

      #define EPLL_CON00   ((1<<31)|(0x20<<16)|(1<<8)|(3<<0))
      #define EPLL_CON01      0
      #define UPLL_SRC_MASK     ((1<<2)|(3<<5))
      #define UPLL_SRC     ((1<<2)|(1<<5))
      #define UPLL_DIV1_MASK    (0xf<<20)
      #define UPLL_DIV1    (0<<20)
      #define UPLL_GATE_MASK    (1<<30)
      #define UPLL_GATE       (1<<30)
      void set_upll(void)
      {
      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_MASK)!=UPLL_SRC)
          __raw_writel((tmp&UPLL_SRC_MASK)|UPLL_SRC,S3C_CLK_SRC);
      while(((tmp=__raw_readl(S3C_CLK_DIV1))&UPLL_DIV1_MASK)!=UPLL_DIV1)
          __raw_writel((tmp&UPLL_DIV1_MASK)|UPLL_DIV1,S3C_CLK_DIV1);
      while(((tmp=__raw_readl(S3C_SCLK_GATE))&UPLL_GATE_MASK)!=UPLL_GATE)
          __raw_writel((tmp&UPLL_GATE_MASK)|UPLL_GATE,S3C_SCLK_GATE);
      }

在probe中加入上面的函数,修改USB Host的时钟:

      set_upll();

然后编译内核。

USB不能识别的错误就解决了。