/** * int reset_and_enable_port(const u8 port) * * @brief Reset port and make enable status the specific port * * @param [IN] port : port number * * @return USB_ERR_SUCCESS : If success \n * USB_ERR_FAIL : If call fail \n * * @remark * */ int reset_and_enable_port(const u8 port) { hprt_t hprt; u32 count = 0; u32 max_error_count = 1000; mdelay(50); hprt.d32 = read_reg_32(HPRT); if(!hprt.b.prtena) { hprt.b.prtrst = 1; // drive reset write_reg_32(HPRT, hprt.d32); mdelay(80); hprt.b.prtrst = 0; write_reg_32(HPRT, hprt.d32); mdelay(60); do { hprt.d32 = read_reg_32(HPRT); udelay(10); if(count > max_error_count) { otg_dbg(OTG_DBG_ROOTHUB,"Port Reset Fail : HPRT : 0x%x\n",(u16)read_reg_32(HPRT)); return USB_ERR_FAIL; } count++; }while(!hprt.b.prtena); } return USB_ERR_SUCCESS; }
/*Internal function of isr */ static void process_port_intr(struct usb_hcd *hcd) { hprt_t hprt; /* by ss1, clear_hprt; */ struct sec_otghost *otghost = hcd_to_sec_otghost(hcd); hprt.d32 = read_reg_32(HPRT); otg_dbg(OTG_DBG_ISR, "Port Interrupt() : HPRT = 0x%x\n", hprt.d32); if (hprt.b.prtconndet) { otg_dbg(true, "detect connection"); otghost->port_flag.b.port_connect_status_change = 1; if (hprt.b.prtconnsts) otghost->port_flag.b.port_connect_status = 1; /* wake_lock(&otghost->wake_lock); */ } if (hprt.b.prtenchng) { otg_dbg(true, "port enable/disable changed\n"); otghost->port_flag.b.port_enable_change = 1; // kevinh - it seems the hw implicitly disables the interface on unplug, so mark that we are unplugged if(!hprt.b.prtconnsts) { otghost->port_flag.b.port_connect_status_change = 1; otghost->port_flag.b.port_connect_status = 0; } } if (hprt.b.prtovrcurrchng) { otg_dbg(true, "over current condition is changed\n"); if (hprt.b.prtovrcurract) { otg_dbg(true, "port_over_current_change = 1\n"); otghost->port_flag.b.port_over_current_change = 1; } else { otghost->port_flag.b.port_over_current_change = 0; } /* defer otg power control into a kernel thread */ queue_work(otghost->wq, &otghost->work); } hprt.b.prtena = 0; /* prtena를 writeclear시키면 안됨. */ /* hprt.b.prtpwr = 0; */ hprt.b.prtrst = 0; hprt.b.prtconnsts = 0; write_reg_32(HPRT, hprt.d32); }
/** * int root_hub_feature(const u8 port, * const u16 type_req, * const u16 feature, * void* buf) * * @brief Get port change bitmap information * * @param [IN] port : port number * [IN] type_req : request type of hub feature as usb 2.0 spec * [IN] feature : hub feature as usb 2.0 spec * [OUT] status : buffer to store results * * @return USB_ERR_SUCCESS : If success \n * USB_ERR_FAIL : If call fail \n * * @remark * */ __inline__ int root_hub_feature(const u8 port, const u16 type_req, const u16 feature, void *buf) { int retval = USB_ERR_SUCCESS; usb_hub_descriptor_t *desc = NULL; u32 port_status = 0; hprt_t hprt = {.d32 = 0}; switch (type_req) { case ClearHubFeature: otg_dbg(OTG_DBG_ROOTHUB,"case ClearHubFeature\n"); switch (feature) { case C_HUB_LOCAL_POWER: otg_dbg(OTG_DBG_ROOTHUB,"case ClearHubFeature -C_HUB_LOCAL_POWER \n"); break; case C_HUB_OVER_CURRENT: otg_dbg(OTG_DBG_ROOTHUB,"case ClearHubFeature -C_HUB_OVER_CURRENT \n"); /* Nothing required here */ break; default: retval = USB_ERR_FAIL; } break; case ClearPortFeature: otg_dbg(OTG_DBG_ROOTHUB,"case ClearPortFeature\n"); switch (feature) { case USB_PORT_FEAT_ENABLE: otg_dbg(OTG_DBG_ROOTHUB,"case ClearPortFeature -USB_PORT_FEAT_ENABLE \n"); hprt.b.prtena = 1; update_reg_32(HPRT, hprt.d32); break; case USB_PORT_FEAT_SUSPEND: otg_dbg(OTG_DBG_ROOTHUB,"case ClearPortFeature -USB_PORT_FEAT_SUSPEND \n"); bus_resume(); break; case USB_PORT_FEAT_POWER: otg_dbg(OTG_DBG_ROOTHUB,"case ClearPortFeature -USB_PORT_FEAT_POWER \n"); hprt.b.prtpwr = 1; clear_reg_32(HPRT, hprt.d32); break; case USB_PORT_FEAT_INDICATOR: otg_dbg(OTG_DBG_ROOTHUB,"case ClearPortFeature -USB_PORT_FEAT_INDICATOR \n"); /* Port inidicator not supported */ break; case USB_PORT_FEAT_C_CONNECTION: otg_dbg(OTG_DBG_ROOTHUB,"case ClearPortFeature -USB_PORT_FEAT_C_CONNECTION \n"); /* Clears drivers internal connect status change * flag */ port_flag.b.port_connect_status_change = 0; break; case USB_PORT_FEAT_C_RESET: otg_dbg(OTG_DBG_ROOTHUB,"case ClearPortFeature -USB_PORT_FEAT_C_RESET \n"); /* Clears the driver's internal Port Reset Change * flag */ port_flag.b.port_reset_change = 0; break; case USB_PORT_FEAT_C_ENABLE: otg_dbg(OTG_DBG_ROOTHUB,"case ClearPortFeature -USB_PORT_FEAT_C_ENABLE \n"); /* Clears the driver's internal Port * Enable/Disable Change flag */ port_flag.b.port_enable_change = 0; break; case USB_PORT_FEAT_C_SUSPEND: otg_dbg(OTG_DBG_ROOTHUB,"case ClearPortFeature -USB_PORT_FEAT_C_SUSPEND \n"); /* Clears the driver's internal Port Suspend * Change flag, which is set when resume signaling on * the host port is complete */ port_flag.b.port_suspend_change = 0; break; case USB_PORT_FEAT_C_OVER_CURRENT: otg_dbg(OTG_DBG_ROOTHUB,"case ClearPortFeature -USB_PORT_FEAT_C_OVER_CURRENT \n"); port_flag.b.port_over_current_change = 0; break; default: retval = USB_ERR_FAIL; } break; case GetHubDescriptor: otg_dbg(OTG_DBG_ROOTHUB,"case GetHubDescriptor\n"); desc = (usb_hub_descriptor_t *)buf; desc->desc_length = 9; desc->desc_type = 0x29; desc->port_number = 1; desc->hub_characteristics = 0x08; desc->power_on_to_power_good = 1; desc->hub_control_current = 0; desc->bitmap[0] = 0; desc->bitmap[1] = 0xff; break; case GetHubStatus: otg_dbg(OTG_DBG_ROOTHUB,"case GetHubStatus\n"); otg_mem_set(buf, 0, 4); break; case GetPortStatus: //otg_dbg(OTG_DBG_ROOTHUB_KH,"case GetPortStatus\n"); if (port_flag.b.port_connect_status_change) port_status |= (1 << USB_PORT_FEAT_C_CONNECTION); if (port_flag.b.port_enable_change) port_status |= (1 << USB_PORT_FEAT_C_ENABLE); if (port_flag.b.port_suspend_change) port_status |= (1 << USB_PORT_FEAT_C_SUSPEND); if (port_flag.b.port_reset_change) port_status|= (1 << USB_PORT_FEAT_C_RESET); if (port_flag.b.port_over_current_change) port_status |= (1 << USB_PORT_FEAT_C_OVER_CURRENT); if (!port_flag.b.port_connect_status) { // // The port is disconnected, which means the core is // either in device mode or it soon will be. Just // return 0's for the remainder of the port status // since the port register can't be read if the core // is in device mode. *((__le32*)buf) = cpu_to_le32(port_status); break; } hprt.d32 = read_reg_32(HPRT); if (hprt.b.prtconnsts) port_status|= (1 << USB_PORT_FEAT_CONNECTION); if (hprt.b.prtena) port_status |= (1 << USB_PORT_FEAT_ENABLE); if (hprt.b.prtsusp) port_status |= (1 << USB_PORT_FEAT_SUSPEND); if (hprt.b.prtovrcurract) port_status |= (1 << USB_PORT_FEAT_OVER_CURRENT); if (hprt.b.prtrst) port_status |= (1 << USB_PORT_FEAT_RESET); if (hprt.b.prtpwr) port_status |= (1 << USB_PORT_FEAT_POWER); if (hprt.b.prtspd == 0) port_status |= (1 << USB_PORT_FEAT_HIGHSPEED); else if (hprt.b.prtspd == 2) port_status |= (1 << USB_PORT_FEAT_LOWSPEED); if (hprt.b.prttstctl) port_status |= (1 << USB_PORT_FEAT_TEST); *((__le32*)buf) = cpu_to_le32(port_status); break; case SetHubFeature: otg_dbg(OTG_DBG_ROOTHUB,"case SetHubFeature\n"); /* No HUB features supported */ break; case SetPortFeature: otg_dbg(OTG_DBG_ROOTHUB,"case SetPortFeature\n"); if (!port_flag.b.port_connect_status) { /* * The port is disconnected, which means the core is * either in device mode or it soon will be. Just * return without doing anything since the port * register can't be written if the core is in device * mode. */ break; } switch (feature) { case USB_PORT_FEAT_SUSPEND: otg_dbg(OTG_DBG_ROOTHUB,"case SetPortFeature -USB_PORT_FEAT_SUSPEND \n"); bus_suspend(); break; case USB_PORT_FEAT_POWER: otg_dbg(OTG_DBG_ROOTHUB,"case SetPortFeature -USB_PORT_FEAT_POWER \n"); hprt.d32 = read_reg_32(HPRT); if(!hprt.b.prtpwr) { //hprt.d32 = 0; hprt.b.prtpwr = 1; write_reg_32(HPRT, hprt.d32); } break; case USB_PORT_FEAT_RESET: otg_dbg(OTG_DBG_ROOTHUB,"case SetPortFeature -USB_PORT_FEAT_RESET \n"); retval = reset_and_enable_port(port); break; case USB_PORT_FEAT_INDICATOR: otg_dbg(OTG_DBG_ROOTHUB,"case USB_PORT_FEAT_INDICATOR\n"); break; default : retval = USB_ERR_FAIL; break; } break; default: retval = USB_ERR_FAIL; otg_dbg(OTG_DBG_ROOTHUB,"root_hub_feature() Function Error\n"); break; } if(retval != USB_ERR_SUCCESS) retval = USB_ERR_FAIL; return retval; } /** * void bus_suspend(void) * * @brief Make suspend status when this platform support PM Mode * * @param None * * @return None * * @remark * */ void bus_suspend(void) { hprt_t hprt; pcgcctl_t pcgcctl; hprt.d32 = 0; pcgcctl.d32 = 0; hprt.b.prtsusp = 1; update_reg_32(HPRT, hprt.d32); pcgcctl.b.pwrclmp = 1; update_reg_32(PCGCCTL,pcgcctl.d32); udelay(1); pcgcctl.b.rstpdwnmodule = 1; update_reg_32(PCGCCTL,pcgcctl.d32); udelay(1); pcgcctl.b.stoppclk = 1; update_reg_32(PCGCCTL,pcgcctl.d32); udelay(1); }