int usb_otg_start(struct platform_device *pdev) { struct fsl_otg *p_otg;
/*获得otg_transceiver结构*/ struct otg_transceiver *otg_trans = otg_get_transceiver(); struct otg_fsm *fsm; volatile unsigned long *p; int status; struct resource *res; u32 temp;
/*获得设备的私有数据*/ struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; /*使用container_of宏定义能够通过结构中一个变量的指针获得该结构首地址*/ p_otg = container_of(otg_trans, struct fsl_otg, otg); fsm = &p_otg->fsm;
/* Initialize the state machine structure with default values */ SET_OTG_STATE(otg_trans, OTG_STATE_UNDEFINED); fsm->transceiver = &p_otg->otg;
/* We don‘t require predefined MEM/IRQ resource index */
/*获得设备的资源,是在设备注冊时结构体里面的内容*/ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENXIO;
/* We don‘t request_mem_region here to enable resource sharing * with host/device */ /*通过资源中获得的物理地址映射一个能够被驱动訪问的虚拟地址指针*/ usb_dr_regs = ioremap(res->start, sizeof(struct usb_dr_mmap));
/*将该指针保存到p_otg->dr_mem_map中*/ p_otg->dr_mem_map = (struct usb_dr_mmap *)usb_dr_regs; pdata->regs = (void *)usb_dr_regs;
/* request irq */
/*获得设备注冊时候的中断并注冊。在OTG ID发生变化时触发中断。然后调用注冊的中断例程函数,函数后面分析*/ p_otg->irq = platform_get_irq(pdev, 0); status = request_irq(p_otg->irq, fsl_otg_isr, IRQF_SHARED, driver_name, p_otg); if (status) { dev_dbg(p_otg->otg.dev, "can‘t get IRQ %d, error %d\n", p_otg->irq, status); iounmap(p_otg->dr_mem_map); kfree(p_otg); return status; }
if (pdata->platform_init && pdata->platform_init(pdev) != 0) return -EINVAL;
/* Export DR controller resources */
/**************************************************/
int otg_set_resources(struct resource *resources) { otg_resources = resources; return 0; }
和otg_set_transceiver功能相似将设备资源保存到一个全局变量中
/**************************************************/ otg_set_resources(pdev->resource); /*開始配置USB寄存器*/ /* stop the controller */ temp = readl(&p_otg->dr_mem_map->usbcmd); temp &= ~USB_CMD_RUN_STOP; writel(temp, &p_otg->dr_mem_map->usbcmd);
/* reset the controller */ temp = readl(&p_otg->dr_mem_map->usbcmd); temp |= USB_CMD_CTRL_RESET; writel(temp, &p_otg->dr_mem_map->usbcmd);
/* wait reset completed */ while (readl(&p_otg->dr_mem_map->usbcmd) & USB_CMD_CTRL_RESET) ;
/* configure the VBUSHS as IDLE(both host and device) */ temp = USB_MODE_STREAM_DISABLE | (pdata->es ? USB_MODE_ES : 0); writel(temp, &p_otg->dr_mem_map->usbmode);
/* configure PHY interface */ temp = readl(&p_otg->dr_mem_map->portsc); temp &= ~(PORTSC_PHY_TYPE_SEL | PORTSC_PTW); switch (pdata->phy_mode) { case FSL_USB2_PHY_ULPI: temp |= PORTSC_PTS_ULPI; break; case FSL_USB2_PHY_UTMI_WIDE: temp |= PORTSC_PTW_16BIT; /* fall through */ case FSL_USB2_PHY_UTMI: temp |= PORTSC_PTS_UTMI; /* fall through */ default: break; } writel(temp, &p_otg->dr_mem_map->portsc);
if (pdata->have_sysif_regs) { /* configure control enable IO output, big endian register */ p = (volatile unsigned long *)(&p_otg->dr_mem_map->control); temp = *p; temp |= USB_CTRL_IOENB; *p = temp; }
/* disable all interrupt and clear all OTGSC status */ temp = readl(&p_otg->dr_mem_map->otgsc); temp &= ~OTGSC_INTERRUPT_ENABLE_BITS_MASK; temp |= OTGSC_INTERRUPT_STATUS_BITS_MASK | OTGSC_CTRL_VBUS_DISCHARGE; writel(temp, &p_otg->dr_mem_map->otgsc);
/* * The identification (id) input is FALSE when a Mini-A plug is inserted * in the devices Mini-AB receptacle. Otherwise, this input is TRUE. * Also: record initial state of ID pin */ if (le32_to_cpu(p_otg->dr_mem_map->otgsc) & OTGSC_STS_USB_ID) { p_otg->otg.state = OTG_STATE_UNDEFINED; p_otg->fsm.id = 1; } else { p_otg->otg.state = OTG_STATE_A_IDLE; p_otg->fsm.id = 0; }
DBG("initial ID pin=%d\n", p_otg->fsm.id);
/* enable OTG ID pin interrupt */ temp = readl(&p_otg->dr_mem_map->otgsc); temp |= OTGSC_INTR_USB_ID_EN; temp &= ~(OTGSC_CTRL_VBUS_DISCHARGE | OTGSC_INTR_1MS_TIMER_EN); writel(temp, &p_otg->dr_mem_map->otgsc);
return 0; }
|