dwc_otg_cil_intr.c

Go to the documentation of this file.
00001 /* ==========================================================================
00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil_intr.c $
00003  * $Revision: #15 $
00004  * $Date: 2009/04/15 $
00005  * $Change: 1234129 $
00006  *
00007  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
00008  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
00009  * otherwise expressly agreed to in writing between Synopsys and you.
00010  *
00011  * The Software IS NOT an item of Licensed Software or Licensed Product under
00012  * any End User Software License Agreement or Agreement for Licensed Product
00013  * with Synopsys or any supplement thereto. You are permitted to use and
00014  * redistribute this Software in source and binary forms, with or without
00015  * modification, provided that redistributions of source code must retain this
00016  * notice. You may not view, use, disclose, copy or distribute this file or
00017  * any information contained herein except pursuant to this license grant from
00018  * Synopsys. If you do not agree with this notice, including the disclaimer
00019  * below, then you are not authorized to use the Software.
00020  *
00021  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00024  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
00025  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00027  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00028  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00031  * DAMAGE.
00032  * ========================================================================== */
00033 
00042 #include "dwc_os.h"
00043 #include "dwc_otg_regs.h"
00044 #include "dwc_otg_cil.h"
00045 
00046 #ifdef DEBUG
00047 inline const char *op_state_str(dwc_otg_core_if_t * core_if)
00048 {
00049         return (core_if->op_state == A_HOST ? "a_host" :
00050                 (core_if->op_state == A_SUSPEND ? "a_suspend" :
00051                  (core_if->op_state == A_PERIPHERAL ? "a_peripheral" :
00052                   (core_if->op_state == B_PERIPHERAL ? "b_peripheral" :
00053                    (core_if->op_state == B_HOST ? "b_host" : "unknown")))));
00054 }
00055 #endif
00056 
00061 int32_t dwc_otg_handle_mode_mismatch_intr(dwc_otg_core_if_t * core_if)
00062 {
00063         gintsts_data_t gintsts;
00064         DWC_WARN("Mode Mismatch Interrupt: currently in %s mode\n",
00065                  dwc_otg_mode(core_if) ? "Host" : "Device");
00066 
00067         /* Clear interrupt */
00068         gintsts.d32 = 0;
00069         gintsts.b.modemismatch = 1;
00070         dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
00071         return 1;
00072 }
00073 
00078 static inline void hcd_start(dwc_otg_core_if_t * core_if)
00079 {
00080         if (core_if->hcd_cb && core_if->hcd_cb->start) {
00081                 core_if->hcd_cb->start(core_if->hcd_cb->p);
00082         }
00083 }
00084 
00089 static inline void hcd_stop(dwc_otg_core_if_t * core_if)
00090 {
00091         if (core_if->hcd_cb && core_if->hcd_cb->stop) {
00092                 core_if->hcd_cb->stop(core_if->hcd_cb->p);
00093         }
00094 }
00095 
00100 static inline void hcd_disconnect(dwc_otg_core_if_t * core_if)
00101 {
00102         if (core_if->hcd_cb && core_if->hcd_cb->disconnect) {
00103                 core_if->hcd_cb->disconnect(core_if->hcd_cb->p);
00104         }
00105 }
00106 
00112 static inline void hcd_session_start(dwc_otg_core_if_t * core_if)
00113 {
00114         if (core_if->hcd_cb && core_if->hcd_cb->session_start) {
00115                 core_if->hcd_cb->session_start(core_if->hcd_cb->p);
00116         }
00117 }
00118 
00119 #ifdef CONFIG_USB_DWC_OTG_LPM
00120 
00126 static inline void hcd_sleep(dwc_otg_core_if_t * core_if)
00127 {
00128         if (core_if->hcd_cb && core_if->hcd_cb->sleep) {
00129                 core_if->hcd_cb->sleep(core_if->hcd_cb->p);
00130         }
00131 }
00132 #endif
00133 
00138 static inline void hcd_resume(dwc_otg_core_if_t * core_if)
00139 {
00140         if (core_if->hcd_cb && core_if->hcd_cb->resume_wakeup) {
00141                 core_if->hcd_cb->resume_wakeup(core_if->hcd_cb->p);
00142         }
00143 }
00144 
00149 static inline void pcd_start(dwc_otg_core_if_t * core_if)
00150 {
00151         if (core_if->pcd_cb && core_if->pcd_cb->start) {
00152                 core_if->pcd_cb->start(core_if->pcd_cb->p);
00153         }
00154 }
00155 
00160 static inline void pcd_stop(dwc_otg_core_if_t * core_if)
00161 {
00162         if (core_if->pcd_cb && core_if->pcd_cb->stop) {
00163                 core_if->pcd_cb->stop(core_if->pcd_cb->p);
00164         }
00165 }
00166 
00171 static inline void pcd_suspend(dwc_otg_core_if_t * core_if)
00172 {
00173         if (core_if->pcd_cb && core_if->pcd_cb->suspend) {
00174                 core_if->pcd_cb->suspend(core_if->pcd_cb->p);
00175         }
00176 }
00177 
00182 static inline void pcd_resume(dwc_otg_core_if_t * core_if)
00183 {
00184         if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
00185                 core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
00186         }
00187 }
00188 
00196 int32_t dwc_otg_handle_otg_intr(dwc_otg_core_if_t * core_if)
00197 {
00198         dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
00199         gotgint_data_t gotgint;
00200         gotgctl_data_t gotgctl;
00201         gintmsk_data_t gintmsk;
00202 
00203         gotgint.d32 = dwc_read_reg32(&global_regs->gotgint);
00204         gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);
00205         DWC_DEBUGPL(DBG_CIL, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint.d32,
00206                     op_state_str(core_if));
00207 
00208         if (gotgint.b.sesenddet) {
00209                 DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
00210                             "Session End Detected++ (%s)\n",
00211                             op_state_str(core_if));
00212                 gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);
00213 
00214                 if (core_if->op_state == B_HOST) {
00215                         pcd_start(core_if);
00216                         core_if->op_state = B_PERIPHERAL;
00217                 } else {
00218                         /* If not B_HOST and Device HNP still set. HNP
00219                          * Did not succeed!*/
00220                         if (gotgctl.b.devhnpen) {
00221                                 DWC_DEBUGPL(DBG_ANY, "Session End Detected\n");
00222                                 __DWC_ERROR("Device Not Connected/Responding!\n");
00223                         }
00224 
00225                         /* If Session End Detected the B-Cable has
00226                          * been disconnected. */
00227                         /* Reset PCD and Gadget driver to a
00228                          * clean state. */
00229                         core_if->lx_state = DWC_OTG_L0;
00230                         pcd_stop(core_if);
00231                 }
00232                 gotgctl.d32 = 0;
00233                 gotgctl.b.devhnpen = 1;
00234                 dwc_modify_reg32(&global_regs->gotgctl, gotgctl.d32, 0);
00235         }
00236         if (gotgint.b.sesreqsucstschng) {
00237                 DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
00238                             "Session Reqeust Success Status Change++\n");
00239                 gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);
00240                 if (gotgctl.b.sesreqscs) {
00241                         if ((core_if->core_params->phy_type ==
00242                              DWC_PHY_TYPE_PARAM_FS) && (core_if->core_params->i2c_enable)) {
00243                                 core_if->srp_success = 1;
00244                         } else {
00245                                 pcd_resume(core_if);
00246                                 /* Clear Session Request */
00247                                 gotgctl.d32 = 0;
00248                                 gotgctl.b.sesreq = 1;
00249                                 dwc_modify_reg32(&global_regs->gotgctl,
00250                                                  gotgctl.d32, 0);
00251                         }
00252                 }
00253         }
00254         if (gotgint.b.hstnegsucstschng) {
00255                 /* Print statements during the HNP interrupt handling
00256                  * can cause it to fail.*/
00257                 gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);
00258                 if (gotgctl.b.hstnegscs) {
00259                         if (dwc_otg_is_host_mode(core_if)) {
00260                                 core_if->op_state = B_HOST;
00261                                 /*
00262                                  * Need to disable SOF interrupt immediately.
00263                                  * When switching from device to host, the PCD
00264                                  * interrupt handler won't handle the
00265                                  * interrupt if host mode is already set. The
00266                                  * HCD interrupt handler won't get called if
00267                                  * the HCD state is HALT. This means that the
00268                                  * interrupt does not get handled and Linux
00269                                  * complains loudly.
00270                                  */
00271                                 gintmsk.d32 = 0;
00272                                 gintmsk.b.sofintr = 1;
00273                                 dwc_modify_reg32(&global_regs->gintmsk,
00274                                                  gintmsk.d32, 0);
00275                                 pcd_stop(core_if);
00276                                 /*
00277                                  * Initialize the Core for Host mode.
00278                                  */
00279                                 hcd_start(core_if);
00280                                 core_if->op_state = B_HOST;
00281                         }
00282                 } else {
00283                         gotgctl.d32 = 0;
00284                         gotgctl.b.hnpreq = 1;
00285                         gotgctl.b.devhnpen = 1;
00286                         dwc_modify_reg32(&global_regs->gotgctl, gotgctl.d32, 0);
00287                         DWC_DEBUGPL(DBG_ANY, "HNP Failed\n");
00288                         __DWC_ERROR("Device Not Connected/Responding\n");
00289                 }
00290         }
00291         if (gotgint.b.hstnegdet) {
00292                 /* The disconnect interrupt is set at the same time as
00293                  * Host Negotiation Detected.  During the mode
00294                  * switch all interrupts are cleared so the disconnect
00295                  * interrupt handler will not get executed.
00296                  */
00297                 DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
00298                             "Host Negotiation Detected++ (%s)\n",
00299                             (dwc_otg_is_host_mode(core_if) ? "Host" :
00300                              "Device"));
00301                 if (dwc_otg_is_device_mode(core_if)) {
00302                         DWC_DEBUGPL(DBG_ANY, "a_suspend->a_peripheral (%d)\n",
00303                                     core_if->op_state);
00304                         hcd_disconnect(core_if);
00305                         pcd_start(core_if);
00306                         core_if->op_state = A_PERIPHERAL;
00307                 } else {
00308                         /*
00309                          * Need to disable SOF interrupt immediately. When
00310                          * switching from device to host, the PCD interrupt
00311                          * handler won't handle the interrupt if host mode is
00312                          * already set. The HCD interrupt handler won't get
00313                          * called if the HCD state is HALT. This means that
00314                          * the interrupt does not get handled and Linux
00315                          * complains loudly.
00316                          */
00317                         gintmsk.d32 = 0;
00318                         gintmsk.b.sofintr = 1;
00319                         dwc_modify_reg32(&global_regs->gintmsk, gintmsk.d32, 0);
00320                         pcd_stop(core_if);
00321                         hcd_start(core_if);
00322                         core_if->op_state = A_HOST;
00323                 }
00324         }
00325         if (gotgint.b.adevtoutchng) {
00326                 DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
00327                             "A-Device Timeout Change++\n");
00328         }
00329         if (gotgint.b.debdone) {
00330                 DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " "Debounce Done++\n");
00331         }
00332 
00333         /* Clear GOTGINT */
00334         dwc_write_reg32(&core_if->core_global_regs->gotgint, gotgint.d32);
00335 
00336         return 1;
00337 }
00338 
00339 void w_conn_id_status_change(void *p)
00340 {
00341         dwc_otg_core_if_t *core_if = p;
00342         uint32_t count = 0;
00343         gotgctl_data_t gotgctl = {.d32 = 0 };
00344 
00345         gotgctl.d32 = dwc_read_reg32(&core_if->core_global_regs->gotgctl);
00346         DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32);
00347         DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts);
00348 
00349         /* B-Device connector (Device Mode) */
00350         if (gotgctl.b.conidsts) {
00351                 /* Wait for switch to device mode. */
00352                 while (!dwc_otg_is_device_mode(core_if)) {
00353                         DWC_PRINTF("Waiting for Peripheral Mode, Mode=%s\n",
00354                                    (dwc_otg_is_host_mode(core_if) ? "Host" :
00355                                     "Peripheral"));
00356                         dwc_mdelay(100);
00357                         if (++count > 10000)
00358                                 break;
00359                 }
00360                 DWC_ASSERT(++count < 10000,
00361                            "Connection id status change timed out");
00362                 core_if->op_state = B_PERIPHERAL;
00363                 dwc_otg_core_init(core_if);
00364                 dwc_otg_enable_global_interrupts(core_if);
00365                 pcd_start(core_if);
00366         } else {
00367                 /* A-Device connector (Host Mode) */
00368                 while (!dwc_otg_is_host_mode(core_if)) {
00369                         DWC_PRINTF("Waiting for Host Mode, Mode=%s\n",
00370                                    (dwc_otg_is_host_mode(core_if) ? "Host" :
00371                                     "Peripheral"));
00372                         dwc_mdelay(100);
00373                         if (++count > 10000)
00374                                 break;
00375                 }
00376                 DWC_ASSERT(++count < 10000,
00377                            "Connection id status change timed out");
00378                 core_if->op_state = A_HOST;
00379                 /*
00380                  * Initialize the Core for Host mode.
00381                  */
00382                 dwc_otg_core_init(core_if);
00383                 dwc_otg_enable_global_interrupts(core_if);
00384                 hcd_start(core_if);
00385         }
00386 }
00387 
00399 int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t * core_if)
00400 {
00401 
00402         /*
00403          * Need to disable SOF interrupt immediately. If switching from device
00404          * to host, the PCD interrupt handler won't handle the interrupt if
00405          * host mode is already set. The HCD interrupt handler won't get
00406          * called if the HCD state is HALT. This means that the interrupt does
00407          * not get handled and Linux complains loudly.
00408          */
00409         gintmsk_data_t gintmsk = {.d32 = 0 };
00410         gintsts_data_t gintsts = {.d32 = 0 };
00411 
00412         gintmsk.b.sofintr = 1;
00413         dwc_modify_reg32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
00414 
00415         DWC_DEBUGPL(DBG_CIL,
00416                     " ++Connector ID Status Change Interrupt++  (%s)\n",
00417                     (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"));
00418 
00419         /*
00420          * Need to schedule a work, as there are possible DELAY function calls
00421          */
00422         DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_conn_id_status_change,
00423                            core_if, "connection id status change");
00424 
00425         /* Set flag and clear interrupt */
00426         gintsts.b.conidstschng = 1;
00427         dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
00428 
00429         return 1;
00430 }
00431 
00441 int32_t dwc_otg_handle_session_req_intr(dwc_otg_core_if_t * core_if)
00442 {
00443         hprt0_data_t hprt0;
00444         gintsts_data_t gintsts;
00445 
00446 #ifndef DWC_HOST_ONLY
00447         DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n");
00448 
00449         if (dwc_otg_is_device_mode(core_if)) {
00450                 DWC_PRINTF("SRP: Device mode\n");
00451         } else {
00452                 DWC_PRINTF("SRP: Host mode\n");
00453 
00454                 /* Turn on the port power bit. */
00455                 hprt0.d32 = dwc_otg_read_hprt0(core_if);
00456                 hprt0.b.prtpwr = 1;
00457                 dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
00458 
00459                 /* Start the Connection timer. So a message can be displayed
00460                  * if connect does not occur within 10 seconds. */
00461                 hcd_session_start(core_if);
00462         }
00463 #endif
00464 
00465         /* Clear interrupt */
00466         gintsts.d32 = 0;
00467         gintsts.b.sessreqintr = 1;
00468         dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
00469 
00470         return 1;
00471 }
00472 
00473 void w_wakeup_detected(void *p)
00474 {
00475         dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) p;
00476         /*
00477          * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
00478          * so that OPT tests pass with all PHYs).
00479          */
00480         hprt0_data_t hprt0 = {.d32 = 0 };
00481 #if 0
00482         pcgcctl_data_t pcgcctl = {.d32 = 0 };
00483         /* Restart the Phy Clock */
00484         pcgcctl.b.stoppclk = 1;
00485         dwc_modify_reg32(core_if->pcgcctl, pcgcctl.d32, 0);
00486         dwc_udelay(10);
00487 #endif                          //0
00488         hprt0.d32 = dwc_otg_read_hprt0(core_if);
00489         DWC_DEBUGPL(DBG_ANY, "Resume: HPRT0=%0x\n", hprt0.d32);
00490 //      dwc_mdelay(70);
00491         hprt0.b.prtres = 0;     /* Resume */
00492         dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
00493         DWC_DEBUGPL(DBG_ANY, "Clear Resume: HPRT0=%0x\n",
00494                     dwc_read_reg32(core_if->host_if->hprt0));
00495 
00496         hcd_resume(core_if);
00497 
00499         core_if->lx_state = DWC_OTG_L0;
00500 
00501 }
00502 
00510 int32_t dwc_otg_handle_wakeup_detected_intr(dwc_otg_core_if_t * core_if)
00511 {
00512         gintsts_data_t gintsts;
00513 
00514         DWC_DEBUGPL(DBG_ANY,
00515                     "++Resume and Remote Wakeup Detected Interrupt++\n");
00516 
00517         DWC_PRINTF("%s lxstate = %d\n", __func__, core_if->lx_state);
00518 
00519         if (dwc_otg_is_device_mode(core_if)) {
00520                 dctl_data_t dctl = {.d32 = 0 };
00521                 DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n",
00522                             dwc_read_reg32(&core_if->dev_if->dev_global_regs->
00523                                            dsts));
00524                 if (core_if->lx_state == DWC_OTG_L2) {
00525 #ifdef PARTIAL_POWER_DOWN
00526                         if (core_if->hwcfg4.b.power_optimiz) {
00527                                 pcgcctl_data_t power = {.d32 = 0 };
00528 
00529                                 power.d32 = dwc_read_reg32(core_if->pcgcctl);
00530                                 DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n",
00531                                             power.d32);
00532 
00533                                 power.b.stoppclk = 0;
00534                                 dwc_write_reg32(core_if->pcgcctl, power.d32);
00535 
00536                                 power.b.pwrclmp = 0;
00537                                 dwc_write_reg32(core_if->pcgcctl, power.d32);
00538 
00539                                 power.b.rstpdwnmodule = 0;
00540                                 dwc_write_reg32(core_if->pcgcctl, power.d32);
00541                         }
00542 #endif
00543                         /* Clear the Remote Wakeup Signalling */
00544                         dctl.b.rmtwkupsig = 1;
00545                         dwc_modify_reg32(&core_if->dev_if->dev_global_regs->
00546                                          dctl, dctl.d32, 0);
00547 
00548                         if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
00549                                 core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->
00550                                                                p);
00551                         }
00552                 } else {
00553                         glpmcfg_data_t lpmcfg;
00554                         lpmcfg.d32 =
00555                             dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
00556                         lpmcfg.b.hird_thres &= (~(1 << 4));
00557                         dwc_write_reg32(&core_if->core_global_regs->glpmcfg,
00558                                         lpmcfg.d32);
00559                 }
00561                 core_if->lx_state = DWC_OTG_L0;
00562         } else {
00563                 if (core_if->lx_state != DWC_OTG_L1) {
00564                         pcgcctl_data_t pcgcctl = {.d32 = 0 };
00565 
00566                         /* Restart the Phy Clock */
00567                         pcgcctl.b.stoppclk = 1;
00568                         dwc_modify_reg32(core_if->pcgcctl, pcgcctl.d32, 0);
00569 
00570                         DWC_TIMER_SCHEDULE(core_if->wkp_timer, 71);
00571                 } else {
00573                         core_if->lx_state = DWC_OTG_L0;
00574                 }
00575         }
00576 
00577         /* Clear interrupt */
00578         gintsts.d32 = 0;
00579         gintsts.b.wkupintr = 1;
00580         dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
00581 
00582         return 1;
00583 }
00584 
00589 int32_t dwc_otg_handle_disconnect_intr(dwc_otg_core_if_t * core_if)
00590 {
00591         gintsts_data_t gintsts;
00592 
00593         DWC_DEBUGPL(DBG_ANY, "++Disconnect Detected Interrupt++ (%s) %s\n",
00594                     (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"),
00595                     op_state_str(core_if));
00596 
00598 #ifndef DWC_HOST_ONLY
00599         if (core_if->op_state == B_HOST) {
00600                 /* If in device mode Disconnect and stop the HCD, then
00601                  * start the PCD. */
00602                 hcd_disconnect(core_if);
00603                 pcd_start(core_if);
00604                 core_if->op_state = B_PERIPHERAL;
00605         } else if (dwc_otg_is_device_mode(core_if)) {
00606                 gotgctl_data_t gotgctl = {.d32 = 0 };
00607                 gotgctl.d32 =
00608                     dwc_read_reg32(&core_if->core_global_regs->gotgctl);
00609                 if (gotgctl.b.hstsethnpen == 1) {
00610                         /* Do nothing, if HNP in process the OTG
00611                          * interrupt "Host Negotiation Detected"
00612                          * interrupt will do the mode switch.
00613                          */
00614                 } else if (gotgctl.b.devhnpen == 0) {
00615                         /* If in device mode Disconnect and stop the HCD, then
00616                          * start the PCD. */
00617                         hcd_disconnect(core_if);
00618                         pcd_start(core_if);
00619                         core_if->op_state = B_PERIPHERAL;
00620                 } else {
00621                         DWC_DEBUGPL(DBG_ANY, "!a_peripheral && !devhnpen\n");
00622                 }
00623         } else {
00624                 if (core_if->op_state == A_HOST) {
00625                         /* A-Cable still connected but device disconnected. */
00626                         hcd_disconnect(core_if);
00627                 }
00628         }
00629 #endif
00630         /* Change to L3(OFF) state */
00631         core_if->lx_state = DWC_OTG_L3;
00632 
00633         gintsts.d32 = 0;
00634         gintsts.b.disconnect = 1;
00635         dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
00636         return 1;
00637 }
00638 
00649 int32_t dwc_otg_handle_usb_suspend_intr(dwc_otg_core_if_t * core_if)
00650 {
00651         dsts_data_t dsts;
00652         gintsts_data_t gintsts;
00653 
00654         DWC_DEBUGPL(DBG_ANY, "USB SUSPEND\n");
00655 
00656         if (dwc_otg_is_device_mode(core_if)) {
00657                 /* Check the Device status register to determine if the Suspend
00658                  * state is active. */
00659                 dsts.d32 =
00660                     dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts);
00661                 DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", dsts.d32);
00662                 DWC_DEBUGPL(DBG_PCD, "DSTS.Suspend Status=%d "
00663                             "HWCFG4.power Optimize=%d\n",
00664                             dsts.b.suspsts, core_if->hwcfg4.b.power_optimiz);
00665 
00666 #ifdef PARTIAL_POWER_DOWN
00667 
00669                 if (dsts.b.suspsts && core_if->hwcfg4.b.power_optimiz) {
00670                         pcgcctl_data_t power = {.d32 = 0 };
00671                         DWC_DEBUGPL(DBG_CIL, "suspend\n");
00672 
00673                         power.b.pwrclmp = 1;
00674                         dwc_write_reg32(core_if->pcgcctl, power.d32);
00675 
00676                         power.b.rstpdwnmodule = 1;
00677                         dwc_modify_reg32(core_if->pcgcctl, 0, power.d32);
00678 
00679                         power.b.stoppclk = 1;
00680                         dwc_modify_reg32(core_if->pcgcctl, 0, power.d32);
00681 
00682                 } else {
00683                         DWC_DEBUGPL(DBG_ANY, "disconnect?\n");
00684                 }
00685 #endif
00686                 /* PCD callback for suspend. */
00687                 pcd_suspend(core_if);
00688         } else {
00689                 if (core_if->op_state == A_PERIPHERAL) {
00690                         DWC_DEBUGPL(DBG_ANY, "a_peripheral->a_host\n");
00691                         /* Clear the a_peripheral flag, back to a_host. */
00692                         pcd_stop(core_if);
00693                         hcd_start(core_if);
00694                         core_if->op_state = A_HOST;
00695                 }
00696         }
00697 
00698         /* Change to L2(suspend) state */
00699         core_if->lx_state = DWC_OTG_L2;
00700 
00701         /* Clear interrupt */
00702         gintsts.d32 = 0;
00703         gintsts.b.usbsuspend = 1;
00704         dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
00705 
00706         return 1;
00707 }
00708 
00709 #ifdef CONFIG_USB_DWC_OTG_LPM
00710 
00713 static int32_t dwc_otg_handle_lpm_intr(dwc_otg_core_if_t * core_if)
00714 {
00715         glpmcfg_data_t lpmcfg;
00716         gintsts_data_t gintsts;
00717 
00718         if (!core_if->core_params->lpm_enable) {
00719                 DWC_PRINTF("Unexpected LPM interrupt\n");
00720         }
00721 
00722         lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
00723         DWC_PRINTF("LPM config register = 0x%08x\n", lpmcfg.d32);
00724 
00725         if (dwc_otg_is_host_mode(core_if)) {
00726                 hcd_sleep(core_if);
00727         } else {
00728                 lpmcfg.b.hird_thres |= (1 << 4);
00729                 dwc_write_reg32(&core_if->core_global_regs->glpmcfg,
00730                                 lpmcfg.d32);
00731         }
00732 
00733         /* Examine prt_sleep_sts after TL1TokenTetry period max (10 us) */      
00734         dwc_udelay(10);
00735         lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
00736         if (lpmcfg.b.prt_sleep_sts) {
00737                 /* Save the current state */
00738                 core_if->lx_state = DWC_OTG_L1;
00739         }
00740 
00741         /* Clear interrupt  */
00742         gintsts.d32 = 0;
00743         gintsts.b.lpmtranrcvd = 1;
00744         dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
00745         return 1;
00746 }
00747 #endif                          /* CONFIG_USB_DWC_OTG_LPM */
00748 
00752 static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if)
00753 {
00754         gintsts_data_t gintsts;
00755         gintmsk_data_t gintmsk;
00756         gintmsk_data_t gintmsk_common = {.d32 = 0 };
00757         gintmsk_common.b.wkupintr = 1;
00758         gintmsk_common.b.sessreqintr = 1;
00759         gintmsk_common.b.conidstschng = 1;
00760         gintmsk_common.b.otgintr = 1;
00761         gintmsk_common.b.modemismatch = 1;
00762         gintmsk_common.b.disconnect = 1;
00763         gintmsk_common.b.usbsuspend = 1;
00764 #ifdef CONFIG_USB_DWC_OTG_LPM
00765         gintmsk_common.b.lpmtranrcvd = 1;
00766 #endif
00767 
00770         gintmsk_common.b.portintr = 1;
00771 
00772         gintsts.d32 = dwc_read_reg32(&core_if->core_global_regs->gintsts);
00773         gintmsk.d32 = dwc_read_reg32(&core_if->core_global_regs->gintmsk);
00774 #ifdef DEBUG
00775         /* if any common interrupts set */
00776         if (gintsts.d32 & gintmsk_common.d32) {
00777                 DWC_DEBUGPL(DBG_ANY, "gintsts=%08x  gintmsk=%08x\n",
00778                             gintsts.d32, gintmsk.d32);
00779         }
00780 #endif
00781 
00782         return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32);
00783 
00784 }
00785 
00800 int32_t dwc_otg_handle_common_intr(dwc_otg_core_if_t * core_if)
00801 {
00802         int retval = 0;
00803         gintsts_data_t gintsts;
00804 
00805         gintsts.d32 = dwc_otg_read_common_intr(core_if);
00806 
00807         if (gintsts.b.modemismatch) {
00808                 retval |= dwc_otg_handle_mode_mismatch_intr(core_if);
00809         }
00810         if (gintsts.b.otgintr) {
00811                 retval |= dwc_otg_handle_otg_intr(core_if);
00812         }
00813         if (gintsts.b.conidstschng) {
00814                 retval |= dwc_otg_handle_conn_id_status_change_intr(core_if);
00815         }
00816         if (gintsts.b.disconnect) {
00817                 retval |= dwc_otg_handle_disconnect_intr(core_if);
00818         }
00819         if (gintsts.b.sessreqintr) {
00820                 retval |= dwc_otg_handle_session_req_intr(core_if);
00821         }
00822         if (gintsts.b.wkupintr) {
00823                 retval |= dwc_otg_handle_wakeup_detected_intr(core_if);
00824         }
00825         if (gintsts.b.usbsuspend) {
00826                 retval |= dwc_otg_handle_usb_suspend_intr(core_if);
00827         }
00828 #ifdef CONFIG_USB_DWC_OTG_LPM
00829         if (gintsts.b.lpmtranrcvd) {
00830                 retval |= dwc_otg_handle_lpm_intr(core_if);
00831         }
00832 #endif
00833 
00834         if (gintsts.b.portintr && dwc_otg_is_device_mode(core_if)) {
00835                 /* The port interrupt occurs while in device mode with HPRT0
00836                  * Port Enable/Disable.
00837                  */
00838                 gintsts.d32 = 0;
00839                 gintsts.b.portintr = 1;
00840                 dwc_write_reg32(&core_if->core_global_regs->gintsts,
00841                                 gintsts.d32);
00842                 retval |= 1;
00843 
00844         }
00845         return retval;
00846 }

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  doxygen 1.4.7