分享

OTG Transceiver --- ISP1301 的驱动代码分析(一)

 Vin的藏書閣 2013-08-18

 

分类: Linux - USB - OTG1947人阅读评论(0)收藏举报
  1. <pre>OTG Transceiver --- ISP1301 的驱动代码分析 <br>如需引用,请注明出处blog.csdn.net/zkami 作者ZhengKui</pre>  

 

Isp1301是philips的外部收发器, 完全支持USB2.0和OTG1.0a规范。能以12Mbit/s(full-speed)和1.5Mbit/s(low-speed)的速度发送和接收串行数据。支持I2C总线接口。本文分析linux-2.6中isp1301 driver的code (isp1301_omap.c)

 

include/linux/usb/otg.h

/*
   * the otg driver needs to interact with both device side and host side
   * usb controllers.  it decides which controller is active at a given
   * moment, using the transceiver, ID signal, HNP and sometimes static
   * configuration information (including "board isn't wired for otg").
   */
struct otg_transceiver {
          struct device           *dev;
          const char              *label;
          u8                      default_a;
          enum usb_otg_state      state;
          struct usb_bus          *host;
          struct usb_gadget       *gadget;
          /* to pass extra port status to the root hub */
          u16                     port_status;
          u16                     port_change;
          /* 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);
          /* 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);
 
  };


drivers/i2c/chips/isp1301_omap.c

struct isp1301 {
          struct otg_transceiver  otg;        //继承了strcuct otg_transceiver 的所有特性和接口
          struct i2c_client       client;
          void                    (*i2c_release)(struct device *dev);
          int                     irq;
          u32                     last_otg_ctrl;
          unsigned                working:1;
          struct timer_list       timer;
          /* use keventd context to change the state for us */
         struct work_struct      work;   
          unsigned long           todo;
  #               define WORK_UPDATE_ISP  0       /* update ISP from OTG */
  #               define WORK_UPDATE_OTG  1       /* update OTG from ISP */
  #               define WORK_HOST_RESUME 4       /* resume host */
  #               define WORK_TIMER       6       /* timer fired */
  #               define WORK_STOP        7       /* don't resubmit */
  };

在booting的时侯首先调用isp1301_scan_bus ---> i2c_probe(bus, &addr_data, isp1301_probe)探测i2c总线设备,进而调用

/* no error returns, they'd just make bus scanning stop */
static int isp1301_probe(struct i2c_adapter *bus, int address, int kind)
 {
 //分配一个struct isp1301的对象,并初始化其中各项
         struct isp1301 *isp = kzalloc(sizeof *isp, GFP_KERNEL); 
 ...
       
 INIT_WORK(&isp->work, isp1301_work, isp);  //初始化isp1301的工作队列  
 init_timer(&isp->timer);   //初始化isp1301的定时器
        isp->timer.function = isp1301_timer;
        isp->timer.data = (unsigned long) isp;
        isp->irq = -1;
 
 //探测是否是isp1301,如果是进行一些chip的初始化设置
 ...

        status = otg_bind(isp); //注册omap_otg_driver
        isp->otg.set_host = isp1301_set_host,    //将这个设备的角色设为host
        isp->otg.set_peripheral = isp1301_set_peripheral, //将这个设备的角色设为peripheral
        isp->otg.set_power = isp1301_set_power, //设置transceiver的电流
        isp->otg.start_srp = isp1301_start_srp, //发起srp
        isp->otg.start_hnp = isp1301_start_hnp, //发起hnp
        update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE));
        update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS));

        ...
 }

 

static int otg_bind(struct isp1301 *isp)
{
 //注册一个platform_device,在omap_otg_init的时侯会注册一个platform_device
 //platform_device_register(&otg_device),这样在device与driver间进行匹配
 platform_driver_register(&omap_otg_driver);
 ...
 //注册isp1301的中断处理程序
 request_irq(otg_dev->resource[1].start, omap_otg_irq, SA_INTERRUPT, DRIVER_NAME, isp);
 ...
}

 

static int isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
{//将这个设备的角色设为host
 isp->otg.host = host; //用struct usb_bus来抽象这个host设备
 host_suspend(isp); //挂起host
 if (isp->otg.gadget) //如果这个设备角色还是peripheral
 return isp1301_otg_enable(isp); //重新使能这个isp1301,因为一个设备不可能即是host又是peripheral
 return 0;
}


static int isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
{//将这个设备的角色设为peripheral,同isp1301_set_host()
 isp->otg.gadget = gadget;
 /* gadget driver 可以挂起直到 vbus_connect () */
 if (isp->otg.host)
 return isp1301_otg_enable(isp);
 return 0;
}

 

static int isp1301_set_power(struct otg_transceiver *dev, unsigned mA)
{//只有当设备角色是B PERIPHERAL时,才能设置transceiver的电流,大小是第二个参数
 if (dev->state == OTG_STATE_B_PERIPHERAL)
 enable_vbus_draw(the_transceiver, mA);
}

 

static int isp1301_start_srp(struct otg_transceiver *dev)
{
 otg_ctrl = OTG_CTRL_REG;
        otg_ctrl |= OTG_B_BUSREQ;
        otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK;
        OTG_CTRL_REG = otg_ctrl;
        isp->otg.state = OTG_STATE_B_SRP_INIT;
}

 

static int isp1301_start_hnp(struct otg_transceiver *dev)
{
 跟距isp->otg.state判断:
 (1) OTG_STATE_B_HOST: isp->otg.state=OTG_STATE_B_PERIPHERAL 接着挂起
 (2) OTG_STATE_A_HOST: 调用者必须挂起,接着清A_BUSREQ标志
  usb_gadget_vbus_connect(isp->otg.gadget)
  OTG_CTRL_REQ |= OTG_A_SETB_HNPEN
 (3) OTG_STATE_A_PERIPHERAL: 已经由B-HOST挂起初始化
}

 

void isp1301_work(struct work_struct *work)
{//由isp1301_timer定时调用
(1) WORK_UPDATE_ISP: 将state从otg engine传到isp1301
 otg_update_isp(isp);
(2) WORK_UPDATE_ISP: 将state从isp1301传到otg engine
 otg_update_OTG(isp);
(3) WORK_HOST_RESUME: 根距isp->otg.state判断
 host_resume(isp)
}

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多