Chinaunix首页 | 论坛 | 博客
  • 博客访问: 332643
  • 博文数量: 125
  • 博客积分: 30
  • 博客等级: 民兵
  • 技术积分: 160
  • 用 户 组: 普通用户
  • 注册时间: 2012-12-06 15:18
文章分类

全部博文(125)

文章存档

2014年(29)

2013年(93)

2012年(3)

分类: LINUX

2014-05-19 16:00:20

该系列博文是基于高通8260,android版本为相对较新的Android4.0.4,由于高通的整个android usb子系统是一个整体,所以有一个框架支撑着整个体系结构。下面先大致说下该框架的结构:
该框架有以下三部分组成:
1、otg控制器。
2、主机控制器。
3、设备控制器。
三个控制器中,其中otg控制器是核心,控制着整个的调度过程,决定在某个时候,是启动主机控制器还是设备控制器。
1、当启动主机控制器的时候,就是我们的设备作为主机,例如:我们的手机上面可以接U盘,数码相机等,直接可以读取U盘上面的数据。
2、当启动设备控制器的时候,就是我们的设备作为外设,例如: 我们的手机插入PC上当作U盘用。
下面就要看看,这三个控制器,是怎么配合的,以及设备与驱动的注册过程,首先说明下,三个控制器都是注册为平台设备。
下面通过一幅图看下整体结构:
 
下面先看otg控制器设备以及驱动的注册过程:

//代码路径如下:Devices-msm8x60.c (arch\arm\mach-msm)
//注册otg平台设备
#define IORESOURCE_MEM 0x00000200
#define IORESOURCE_IRQ  0x00000400
static struct resource resources_otg[] = {
 {
  .start = 0x12500000,
  .end = 0x12500000 + SZ_1K - 1,
  .flags = IORESOURCE_MEM,//资源类型io
 },
 {
  .start = USB1_HS_IRQ,//132
  .end = USB1_HS_IRQ,
  .flags = IORESOURCE_IRQ,//资源类型irq
 },
};
/*otg平台设备*/
struct platform_device msm_device_otg = {
 .name = "msm_otg",
 .id  = -1,
 .num_resources = ARRAY_SIZE(resources_otg),
 .resource = resources_otg,
};
//下面的代码路径如下Board-msm8x60.c (arch\arm\mach-msm)
/*otg平台设备的平台数据*/
static struct msm_otg_platform_data msm_otg_pdata = {
 .............
#ifdef CONFIG_USB_EHCI_MSM_72K
 .pmic_id_notif_init = msm_hsusb_pmic_id_notif_init,//usb id引脚处理的回调注册函数
 .phy_id_setup_init = msm_hsusb_phy_id_setup_init,
#endif
#ifdef CONFIG_USB_EHCI_MSM_72K
 .vbus_power = msm_hsusb_vbus_power,//在下面已经被重写,开启otg对外电源,关闭充电功能
#endif
#ifdef CONFIG_BATTERY_MSM8X60
 .pmic_vbus_notif_init = msm_hsusb_pmic_vbus_notif_init,//usb设备的作为client时,处理vbus的回调函数注册
#endif
 .ldo_init   = msm_hsusb_ldo_init,
 .ldo_enable   = msm_hsusb_ldo_enable,
 .config_vddcx    = msm_hsusb_config_vddcx,
 .init_vddcx      = msm_hsusb_init_vddcx,
#ifdef CONFIG_BATTERY_MSM8X60
 .chg_vbus_draw = msm_charger_vbus_draw,
#endif
};
static void __init msm8x60_init_buses(void)
{
 ..................
 
 //继续初始化平台数据
 msm_otg_pdata.pmic_id_irq = PMICID_INT;//#define  PMICID_INT PM8058_GPIO_IRQ(PM8058_IRQ_BASE, 36)
 msm_otg_pdata.phy_can_powercollapse = 1;
 msm_otg_pdata.vbus_power = msm_hsusb_smb137b_vbus_power; //otg功能时对外供电的管理,重写上面的函数
  /*下面是msm_hsusb_smb137b_vbus_power的实现,控制smb137b充电芯片的otg功能*/
  /*************************************************************************/
  static void msm_hsusb_smb137b_vbus_power(unsigned phy_info, int on)
  {
   smb137b_otg_power(on);
    __smb137b_otg_power(on);
     if (on) {
      ret = smb137b_write_reg(usb_smb137b_chg->client,PIN_CTRL_REG, PIN_CTRL_REG_CHG_OFF);
      ret = smb137b_write_reg(usb_smb137b_chg->client,COMMAND_A_REG, COMMAND_A_REG_OTG_MODE);
     } else {
      ret = smb137b_write_reg(usb_smb137b_chg->client,COMMAND_A_REG, COMMAND_A_REG_DEFAULT);
      ret = smb137b_write_reg(usb_smb137b_chg->client,PIN_CTRL_REG, PIN_CTRL_REG_DEFAULT);
     }
  }
  /************************************************************************/
 /*为otg平台设备挂载平台数据*/
 msm_device_otg.dev.platform_data = &msm_otg_pdata;
}
//注册平台设备
static struct platform_device *surf_devices[] __initdata = {
  .............
 #if defined(CONFIG_USB_GADGET_MSM_72K) || defined(CONFIG_USB_EHCI_HCD)
  &msm_device_otg,
 #endif
  ...........
}
static void __init msm8x60_init(struct msm_board_data *board_data)
{
 .....................
 msm8x60_init_buses();
 ....................
 platform_add_devices(surf_devices,ARRAY_SIZE(surf_devices));//把otg平台设备注册进系统
 ..............
}

//下面的代码路径如下:Msm72k_otg.c (drivers\usb\otg) 
//注册MSM_OTG平台驱动
static struct platform_driver msm_otg_driver = {
 .remove = __exit_p(msm_otg_remove),
 .driver = {
  .name = DRIVER_NAME,//#define DRIVER_NAME "msm_otg"
  .owner = THIS_MODULE,
  .pm = &msm_otg_dev_pm_ops,//电源管理函数
 },
};
static int __init msm_otg_init(void)
{
 return platform_driver_probe(&msm_otg_driver, msm_otg_probe);//注册平台驱动
}

/*成功匹配到平台驱动后,调用msm_otg_probe函数,下面先看下msm_otg结构体*/
 //代码路径如下:Msm72k_otg.h (arch\arm\mach-msm\include\mach)
struct msm_otg {
 struct otg_transceiver otg;//收发器结构体,实现在下面列出(1)
 /* usb clocks */
 struct clk  *alt_core_clk; //串行接口引擎SIE的clock
 struct clk  *iface_clk;//protocol engine的clock和AHB bus的clock
 struct clk  *core_clk;
 struct clk  *phy_reset_clk;
 int    irq;//otg设备的中断号
 int    vbus_on_irq;
 int    id_irq;
 void __iomem *regs;//记录iomem映射后的地址
 atomic_t  in_lpm;
 atomic_t   chg_type;/* charger-type is modified by gadget for legacy chargers and OTG modifies it for ACA */
 void (*start_host) (struct usb_bus *bus, int suspend);
 int  (*set_clk)  (struct otg_transceiver *otg, int on);/* Enable/disable the clocks */
 void (*reset)  (struct otg_transceiver *otg, int phy_reset);/* Reset phy and link */
 /* pmic notfications apis */
 u8 pmic_vbus_notif_supp;//是否支持vbus插入通知
 u8 pmic_id_notif_supp;//是否支持id引脚的插入通知
 struct msm_otg_platform_data *pdata;//otg平台设备的平台数据
 spinlock_t lock; /* 改变otg控制器状态机时,要加该自旋锁*/
 struct wake_lock wlock;
 unsigned long b_last_se0_sess; /* SRP initial condition check */
 /*管理otg控制器状态机的位域*/
 unsigned long inputs;
 unsigned long tmouts;
 u8 active_tmout;
 struct hrtimer timer;//处理状态机的超时处理
 struct workqueue_struct *wq;//针对otg work起个专门的线程队列
 struct work_struct sm_work; /* otg状态机的驱动work */
 struct work_struct  otg_resume_work;
 struct notifier_block usbdev_nb;//usb插入拔出时的通知链
 struct msm_xo_voter *xo_handle; /*handle to vote for TCXO D1 buffer*/
};
//接着上面的实现(1)
struct otg_transceiver {
 struct device  *dev;
 const char      *label;
 unsigned int  flags;
 u8              default_a;
 enum usb_otg_state    state;
 enum usb_xceiv_events  last_event;
 struct usb_bus  *host;
 struct usb_gadget *gadget;
 struct otg_io_access_ops *io_ops;
 void __iomem    *io_priv;
 /* for notification of usb_xceiv_events */
 struct atomic_notifier_head notifier;
 /* to pass extra port status to the root hub */
 u16   port_status;
 u16   port_change;
 /* initialize/shutdown the OTG controller */
 int (*init)(struct otg_transceiver *otg);
 void(*shutdown)(struct otg_transceiver *otg);
 /* bind/unbind the host controller */
 int (*set_host)(struct otg_transceiver *otg, struct usb_bus *host);
 /* bind/unbind the peripheral controller */
 int (*set_peripheral)(struct otg_transceiver *otg, struct usb_gadget *gadget);
 /* effective for B devices, ignored for A-peripheral */
 int (*set_power)(struct otg_transceiver *otg, unsigned mA);
 /* effective for A-peripheral, ignored for B devices */
 int (*set_vbus)(struct otg_transceiver *otg, bool enabled);
 /* for non-OTG B devices: set transceiver into suspend mode */
 int (*set_suspend)(struct otg_transceiver *otg, int suspend);
 /* for B devices only:  start session with A-Host */
 int (*start_srp)(struct otg_transceiver *otg);
 /* start or continue HNP role switch */
 int (*start_hnp)(struct otg_transceiver *otg);
 /* send events to user space */
 int (*send_event)(struct otg_transceiver *otg,  enum usb_otg_event event);
};

//下面的代码路径如下:Msm72k_otg.c (drivers\usb\otg) 
struct msm_otg *the_msm_otg;//保存otg信息的全局变量
//下面的probe函数,主要是对msm_otg结构体进行初始化
static int __init msm_otg_probe(struct platform_device *pdev)
{
 int ret = 0;
 struct resource *res;
 struct msm_otg *dev;
 dev = kzalloc(sizeof(struct msm_otg), GFP_KERNEL);//分配otg设备结构体
 the_msm_otg = dev;//保存到全局变量中
 dev->otg.dev = &pdev->dev;//为设备模型中的dev赋值
 dev->pdata = pdev->dev.platform_data;//保存平台设备的平台数据到msm_otg
#ifdef CONFIG_USB_EHCI_MSM_72K
 if (!dev->pdata->vbus_power) {
  ret = -ENODEV;
  goto free_dev;
 } else
  dev->pdata->vbus_power(USB_PHY_INTEGRATED, 0);//先关闭otg对外供电电源
#endif
 //设置usb的clock
 /********************************************************************************************/
 dev->alt_core_clk = clk_get(&pdev->dev, "alt_core_clk");
 clk_set_rate(dev->alt_core_clk, 60000000);//设置alt_core_clk = 60M ,cc_usb_xcvr_fs_clk,串行接口引擎SIE的clock
 /* pm qos request to prevent apps idle power collapse */
 pm_qos_add_request(&dev->pdata->pm_qos_req_dma, PM_QOS_CPU_DMA_LATENCY,PM_QOS_DEFAULT_VALUE);
 dev->core_clk = clk_get(&pdev->dev, "core_clk");
 clk_set_rate(dev->core_clk, INT_MAX);
 clk_enable(dev->core_clk);
 if (!dev->pdata->pclk_is_hw_gated) {
  dev->iface_clk = clk_get(&pdev->dev, "iface_clk");//cc_usb_hs1_hclk,PE和AHB bus的clock
  clk_enable(dev->iface_clk);
 }
 if (!dev->pdata->phy_reset) {
  dev->phy_reset_clk = clk_get(&pdev->dev, "phy_clk");
 }
 /********************************************************************************************/
 //取出otg平台设备的io资源,并映射到用户空间
 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 dev->regs = ioremap(res->start, resource_size(res));
 //取出otg平台设备的irq资源
 dev->irq = platform_get_irq(pdev, 0);
 dev->xo_handle = msm_xo_get(MSM_XO_TCXO_D1, "usb");
 ret = msm_xo_mode_vote(dev->xo_handle, MSM_XO_MODE_ON);
 //处理otg状态迁移的超时定时器
 msm_otg_init_timer(dev);
 //维护otg控制器状态机的work
 INIT_WORK(&dev->sm_work, msm_otg_sm_work);
 //唤醒时执行的work
 INIT_WORK(&dev->otg_resume_work, msm_otg_resume_w);
 //初始化自旋锁,在otg控制器状态机改变时要上锁
 spin_lock_init(&dev->lock);
 //初始化worklock
 wake_lock_init(&dev->wlock, WAKE_LOCK_SUSPEND, "msm_otg");
 //专门起一个工作队列线程,调度otg相关的work
 dev->wq = alloc_workqueue("k_otg", WQ_NON_REENTRANT, 0);
 if (dev->pdata->pmic_vbus_notif_init) {//挂载检测usb作为device是否插入/拔出状态的回调函数
  ret = dev->pdata->pmic_vbus_notif_init(&msm_otg_set_vbus_state, 1);
  if (!ret) {
   dev->pmic_vbus_notif_supp = 1;//如果成功,则pmic_vbus_notif_supp =1
  }
 }
 if (dev->pdata->phy_id_setup_init) {
  ret = dev->pdata->phy_id_setup_init(1);//初始化pm8901的供电状态,为PHY供电
 }
 /* vote for vddcx, as PHY cannot tolerate vddcx below 1.0V */
 if (dev->pdata->init_vddcx) {
  ret = dev->pdata->init_vddcx(1);//配置电压1.0V~1.32V
 }
 //配置并使能usb控制器所需要的电压1.8V,3.3V
 if (dev->pdata->ldo_init) {
  ret = dev->pdata->ldo_init(1);
 }
 //设置电压的工作模式,是工作在low power mode,还是high power mode
 if (dev->pdata->ldo_enable) {
  ret = dev->pdata->ldo_enable(1);
 }
 /* ACk all pending interrupts and clear interrupt enable registers */
 writel((readl(USB_OTGSC) & ~OTGSC_INTR_MASK), USB_OTGSC);//打开中断掩码,屏蔽所有中断
 writel(readl(USB_USBSTS), USB_USBSTS);//清除状态寄存器的值
 writel(0, USB_USBINTR);//清除中断标志寄存器
 /* Ensure that above STOREs are completed before enabling interrupts */
 mb();
 //注册otg中断处理函数,该中断函数的android usb子系统的事件驱动入口
 ret = request_irq(dev->irq, msm_otg_irq, IRQF_SHARED,"msm_otg", dev);
 /*设置dev的otg成员*/
 dev->otg.set_peripheral = msm_otg_set_peripheral;
 dev->otg.set_host  = msm_otg_set_host;
 dev->otg.set_suspend = msm_otg_set_suspend;
 dev->otg.start_hnp      = msm_otg_start_hnp;
 dev->otg.send_event   = msm_otg_send_event;
 dev->otg.set_power   = msm_otg_set_power;
 dev->otg.io_ops      = &msm_otg_io_ops;
 dev->set_clk         = msm_otg_set_clk;
 dev->reset    = otg_reset;
 //保存transceiver,该变量是主机控制器和设备控制器的桥梁,通过该变量可以使用otg核心的资源
 if (otg_set_transceiver(&dev->otg)) {
  goto free_otg_irq;
 }
 atomic_set(&dev->chg_type, USB_CHG_TYPE__INVALID);//初始化charger type为无效
 device_init_wakeup(&pdev->dev, 1);//设置能被唤醒,并且使能
 
 ......................
 
 return 0;
}

//代码路径如下:Otg.c (drivers\usb\otg) 
//下面分析下几个重要的函数
static struct otg_transceiver *xceiv;
/*保存otg_transceiver到全局变量xceiv中*/
int otg_set_transceiver(struct otg_transceiver *x)
{
 if (xceiv && x)
  return -EBUSY;
 xceiv = x;
 return 0;
}
/* 从xcerv中取出otg_transceiver,该函数在udc和host中调用*/
struct otg_transceiver *otg_get_transceiver(void)
{
 if (xceiv)
  get_device(xceiv->dev);
 return xceiv;
}
上面就是otg控制器设备与驱动的注册,其中比较重要的是注册的中断函数
1、msm_otg_irq,该中断时事件驱动入口。
2、全局变量xceiv,是连接三个控制器的桥梁。
3、msm_otg_set_vbus_state,上报usb插入拔出的回调函数。
下一篇继续看usb主机控制器的注册。
阅读(606) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~