Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * otg.c - ChipIdea USB IP core OTG driver
0004  *
0005  * Copyright (C) 2013 Freescale Semiconductor, Inc.
0006  *
0007  * Author: Peter Chen
0008  */
0009 
0010 /*
0011  * This file mainly handles otgsc register, OTG fsm operations for HNP and SRP
0012  * are also included.
0013  */
0014 
0015 #include <linux/usb/otg.h>
0016 #include <linux/usb/gadget.h>
0017 #include <linux/usb/chipidea.h>
0018 
0019 #include "ci.h"
0020 #include "bits.h"
0021 #include "otg.h"
0022 #include "otg_fsm.h"
0023 
0024 /**
0025  * hw_read_otgsc - returns otgsc register bits value.
0026  * @ci: the controller
0027  * @mask: bitfield mask
0028  */
0029 u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask)
0030 {
0031     struct ci_hdrc_cable *cable;
0032     u32 val = hw_read(ci, OP_OTGSC, mask);
0033 
0034     /*
0035      * If using extcon framework for VBUS and/or ID signal
0036      * detection overwrite OTGSC register value
0037      */
0038     cable = &ci->platdata->vbus_extcon;
0039     if (!IS_ERR(cable->edev) || ci->role_switch) {
0040         if (cable->changed)
0041             val |= OTGSC_BSVIS;
0042         else
0043             val &= ~OTGSC_BSVIS;
0044 
0045         if (cable->connected)
0046             val |= OTGSC_BSV;
0047         else
0048             val &= ~OTGSC_BSV;
0049 
0050         if (cable->enabled)
0051             val |= OTGSC_BSVIE;
0052         else
0053             val &= ~OTGSC_BSVIE;
0054     }
0055 
0056     cable = &ci->platdata->id_extcon;
0057     if (!IS_ERR(cable->edev) || ci->role_switch) {
0058         if (cable->changed)
0059             val |= OTGSC_IDIS;
0060         else
0061             val &= ~OTGSC_IDIS;
0062 
0063         if (cable->connected)
0064             val &= ~OTGSC_ID; /* host */
0065         else
0066             val |= OTGSC_ID; /* device */
0067 
0068         if (cable->enabled)
0069             val |= OTGSC_IDIE;
0070         else
0071             val &= ~OTGSC_IDIE;
0072     }
0073 
0074     return val & mask;
0075 }
0076 
0077 /**
0078  * hw_write_otgsc - updates target bits of OTGSC register.
0079  * @ci: the controller
0080  * @mask: bitfield mask
0081  * @data: to be written
0082  */
0083 void hw_write_otgsc(struct ci_hdrc *ci, u32 mask, u32 data)
0084 {
0085     struct ci_hdrc_cable *cable;
0086 
0087     cable = &ci->platdata->vbus_extcon;
0088     if (!IS_ERR(cable->edev) || ci->role_switch) {
0089         if (data & mask & OTGSC_BSVIS)
0090             cable->changed = false;
0091 
0092         /* Don't enable vbus interrupt if using external notifier */
0093         if (data & mask & OTGSC_BSVIE) {
0094             cable->enabled = true;
0095             data &= ~OTGSC_BSVIE;
0096         } else if (mask & OTGSC_BSVIE) {
0097             cable->enabled = false;
0098         }
0099     }
0100 
0101     cable = &ci->platdata->id_extcon;
0102     if (!IS_ERR(cable->edev) || ci->role_switch) {
0103         if (data & mask & OTGSC_IDIS)
0104             cable->changed = false;
0105 
0106         /* Don't enable id interrupt if using external notifier */
0107         if (data & mask & OTGSC_IDIE) {
0108             cable->enabled = true;
0109             data &= ~OTGSC_IDIE;
0110         } else if (mask & OTGSC_IDIE) {
0111             cable->enabled = false;
0112         }
0113     }
0114 
0115     hw_write(ci, OP_OTGSC, mask | OTGSC_INT_STATUS_BITS, data);
0116 }
0117 
0118 /**
0119  * ci_otg_role - pick role based on ID pin state
0120  * @ci: the controller
0121  */
0122 enum ci_role ci_otg_role(struct ci_hdrc *ci)
0123 {
0124     enum ci_role role = hw_read_otgsc(ci, OTGSC_ID)
0125         ? CI_ROLE_GADGET
0126         : CI_ROLE_HOST;
0127 
0128     return role;
0129 }
0130 
0131 void ci_handle_vbus_change(struct ci_hdrc *ci)
0132 {
0133     if (!ci->is_otg)
0134         return;
0135 
0136     if (hw_read_otgsc(ci, OTGSC_BSV) && !ci->vbus_active)
0137         usb_gadget_vbus_connect(&ci->gadget);
0138     else if (!hw_read_otgsc(ci, OTGSC_BSV) && ci->vbus_active)
0139         usb_gadget_vbus_disconnect(&ci->gadget);
0140 }
0141 
0142 /**
0143  * hw_wait_vbus_lower_bsv - When we switch to device mode, the vbus value
0144  *                          should be lower than OTGSC_BSV before connecting
0145  *                          to host.
0146  *
0147  * @ci: the controller
0148  *
0149  * This function returns an error code if timeout
0150  */
0151 static int hw_wait_vbus_lower_bsv(struct ci_hdrc *ci)
0152 {
0153     unsigned long elapse = jiffies + msecs_to_jiffies(5000);
0154     u32 mask = OTGSC_BSV;
0155 
0156     while (hw_read_otgsc(ci, mask)) {
0157         if (time_after(jiffies, elapse)) {
0158             dev_err(ci->dev, "timeout waiting for %08x in OTGSC\n",
0159                     mask);
0160             return -ETIMEDOUT;
0161         }
0162         msleep(20);
0163     }
0164 
0165     return 0;
0166 }
0167 
0168 static void ci_handle_id_switch(struct ci_hdrc *ci)
0169 {
0170     enum ci_role role = ci_otg_role(ci);
0171 
0172     if (role != ci->role) {
0173         dev_dbg(ci->dev, "switching from %s to %s\n",
0174             ci_role(ci)->name, ci->roles[role]->name);
0175 
0176         if (ci->vbus_active && ci->role == CI_ROLE_GADGET)
0177             /*
0178              * vbus disconnect event is lost due to role
0179              * switch occurs during system suspend.
0180              */
0181             usb_gadget_vbus_disconnect(&ci->gadget);
0182 
0183         ci_role_stop(ci);
0184 
0185         if (role == CI_ROLE_GADGET &&
0186                 IS_ERR(ci->platdata->vbus_extcon.edev))
0187             /*
0188              * Wait vbus lower than OTGSC_BSV before connecting
0189              * to host. If connecting status is from an external
0190              * connector instead of register, we don't need to
0191              * care vbus on the board, since it will not affect
0192              * external connector status.
0193              */
0194             hw_wait_vbus_lower_bsv(ci);
0195 
0196         ci_role_start(ci, role);
0197         /* vbus change may have already occurred */
0198         if (role == CI_ROLE_GADGET)
0199             ci_handle_vbus_change(ci);
0200     }
0201 }
0202 /**
0203  * ci_otg_work - perform otg (vbus/id) event handle
0204  * @work: work struct
0205  */
0206 static void ci_otg_work(struct work_struct *work)
0207 {
0208     struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work);
0209 
0210     if (ci_otg_is_fsm_mode(ci) && !ci_otg_fsm_work(ci)) {
0211         enable_irq(ci->irq);
0212         return;
0213     }
0214 
0215     pm_runtime_get_sync(ci->dev);
0216 
0217     if (ci->id_event) {
0218         ci->id_event = false;
0219         ci_handle_id_switch(ci);
0220     }
0221 
0222     if (ci->b_sess_valid_event) {
0223         ci->b_sess_valid_event = false;
0224         ci_handle_vbus_change(ci);
0225     }
0226 
0227     pm_runtime_put_sync(ci->dev);
0228 
0229     enable_irq(ci->irq);
0230 }
0231 
0232 
0233 /**
0234  * ci_hdrc_otg_init - initialize otg struct
0235  * @ci: the controller
0236  */
0237 int ci_hdrc_otg_init(struct ci_hdrc *ci)
0238 {
0239     INIT_WORK(&ci->work, ci_otg_work);
0240     ci->wq = create_freezable_workqueue("ci_otg");
0241     if (!ci->wq) {
0242         dev_err(ci->dev, "can't create workqueue\n");
0243         return -ENODEV;
0244     }
0245 
0246     if (ci_otg_is_fsm_mode(ci))
0247         return ci_hdrc_otg_fsm_init(ci);
0248 
0249     return 0;
0250 }
0251 
0252 /**
0253  * ci_hdrc_otg_destroy - destroy otg struct
0254  * @ci: the controller
0255  */
0256 void ci_hdrc_otg_destroy(struct ci_hdrc *ci)
0257 {
0258     if (ci->wq)
0259         destroy_workqueue(ci->wq);
0260 
0261     /* Disable all OTG irq and clear status */
0262     hw_write_otgsc(ci, OTGSC_INT_EN_BITS | OTGSC_INT_STATUS_BITS,
0263                         OTGSC_INT_STATUS_BITS);
0264     if (ci_otg_is_fsm_mode(ci))
0265         ci_hdrc_otg_fsm_remove(ci);
0266 }