Chinaunix首页 | 论坛 | 博客
  • 博客访问: 165792
  • 博文数量: 205
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 0
  • 用 户 组: 普通用户
  • 注册时间: 2016-07-21 21:11
文章分类

全部博文(205)

文章存档

2016年(2)

2015年(203)

我的朋友

分类: LINUX

2015-11-17 09:50:49

该系列博文是基于高通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主机控制器的注册。
阅读(439) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~