0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/module.h>
0011 #include <linux/kernel.h>
0012 #include <linux/sched.h>
0013 #include <linux/errno.h>
0014 #include <linux/time.h>
0015 #include <linux/timer.h>
0016
0017 #include <asm/unaligned.h>
0018
0019 #include "musb_core.h"
0020
0021 void musb_host_finish_resume(struct work_struct *work)
0022 {
0023 struct musb *musb;
0024 unsigned long flags;
0025 u8 power;
0026
0027 musb = container_of(work, struct musb, finish_resume_work.work);
0028
0029 spin_lock_irqsave(&musb->lock, flags);
0030
0031 power = musb_readb(musb->mregs, MUSB_POWER);
0032 power &= ~MUSB_POWER_RESUME;
0033 musb_dbg(musb, "root port resume stopped, power %02x", power);
0034 musb_writeb(musb->mregs, MUSB_POWER, power);
0035
0036
0037
0038
0039
0040
0041 musb->is_active = 1;
0042 musb->port1_status &= ~(USB_PORT_STAT_SUSPEND | MUSB_PORT_STAT_RESUME);
0043 musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
0044 usb_hcd_poll_rh_status(musb->hcd);
0045
0046 musb->xceiv->otg->state = OTG_STATE_A_HOST;
0047
0048 spin_unlock_irqrestore(&musb->lock, flags);
0049 }
0050
0051 int musb_port_suspend(struct musb *musb, bool do_suspend)
0052 {
0053 struct usb_otg *otg = musb->xceiv->otg;
0054 u8 power;
0055 void __iomem *mbase = musb->mregs;
0056
0057 if (!is_host_active(musb))
0058 return 0;
0059
0060
0061
0062
0063
0064
0065 power = musb_readb(mbase, MUSB_POWER);
0066 if (do_suspend) {
0067 int retries = 10000;
0068
0069 if (power & MUSB_POWER_RESUME)
0070 return -EBUSY;
0071
0072 if (!(power & MUSB_POWER_SUSPENDM)) {
0073 power |= MUSB_POWER_SUSPENDM;
0074 musb_writeb(mbase, MUSB_POWER, power);
0075
0076
0077 power = musb_readb(mbase, MUSB_POWER);
0078 while (power & MUSB_POWER_SUSPENDM) {
0079 power = musb_readb(mbase, MUSB_POWER);
0080 if (retries-- < 1)
0081 break;
0082 }
0083 }
0084
0085 musb_dbg(musb, "Root port suspended, power %02x", power);
0086
0087 musb->port1_status |= USB_PORT_STAT_SUSPEND;
0088 switch (musb->xceiv->otg->state) {
0089 case OTG_STATE_A_HOST:
0090 musb->xceiv->otg->state = OTG_STATE_A_SUSPEND;
0091 musb->is_active = otg->host->b_hnp_enable;
0092 if (musb->is_active)
0093 mod_timer(&musb->otg_timer, jiffies
0094 + msecs_to_jiffies(
0095 OTG_TIME_A_AIDL_BDIS));
0096 musb_platform_try_idle(musb, 0);
0097 break;
0098 case OTG_STATE_B_HOST:
0099 musb->xceiv->otg->state = OTG_STATE_B_WAIT_ACON;
0100 musb->is_active = otg->host->b_hnp_enable;
0101 musb_platform_try_idle(musb, 0);
0102 break;
0103 default:
0104 musb_dbg(musb, "bogus rh suspend? %s",
0105 usb_otg_state_string(musb->xceiv->otg->state));
0106 }
0107 } else if (power & MUSB_POWER_SUSPENDM) {
0108 power &= ~MUSB_POWER_SUSPENDM;
0109 power |= MUSB_POWER_RESUME;
0110 musb_writeb(mbase, MUSB_POWER, power);
0111
0112 musb_dbg(musb, "Root port resuming, power %02x", power);
0113
0114 musb->port1_status |= MUSB_PORT_STAT_RESUME;
0115 schedule_delayed_work(&musb->finish_resume_work,
0116 msecs_to_jiffies(USB_RESUME_TIMEOUT));
0117 }
0118 return 0;
0119 }
0120
0121 void musb_port_reset(struct musb *musb, bool do_reset)
0122 {
0123 u8 power;
0124 void __iomem *mbase = musb->mregs;
0125
0126 if (musb->xceiv->otg->state == OTG_STATE_B_IDLE) {
0127 musb_dbg(musb, "HNP: Returning from HNP; no hub reset from b_idle");
0128 musb->port1_status &= ~USB_PORT_STAT_RESET;
0129 return;
0130 }
0131
0132 if (!is_host_active(musb))
0133 return;
0134
0135
0136
0137
0138 power = musb_readb(mbase, MUSB_POWER);
0139 if (do_reset) {
0140
0141
0142
0143
0144
0145
0146
0147 if (power & MUSB_POWER_RESUME) {
0148 long remain = (unsigned long) musb->rh_timer - jiffies;
0149
0150 if (musb->rh_timer > 0 && remain > 0) {
0151
0152 schedule_delayed_work(
0153 &musb->deassert_reset_work, remain);
0154 return;
0155 }
0156
0157 musb_writeb(mbase, MUSB_POWER,
0158 power & ~MUSB_POWER_RESUME);
0159
0160
0161 schedule_delayed_work(&musb->deassert_reset_work,
0162 msecs_to_jiffies(1));
0163 return;
0164 }
0165
0166 power &= 0xf0;
0167 musb_writeb(mbase, MUSB_POWER,
0168 power | MUSB_POWER_RESET);
0169
0170 musb->port1_status |= USB_PORT_STAT_RESET;
0171 musb->port1_status &= ~USB_PORT_STAT_ENABLE;
0172 schedule_delayed_work(&musb->deassert_reset_work,
0173 msecs_to_jiffies(50));
0174 } else {
0175 musb_dbg(musb, "root port reset stopped");
0176 musb_platform_pre_root_reset_end(musb);
0177 musb_writeb(mbase, MUSB_POWER,
0178 power & ~MUSB_POWER_RESET);
0179 musb_platform_post_root_reset_end(musb);
0180
0181 power = musb_readb(mbase, MUSB_POWER);
0182 if (power & MUSB_POWER_HSMODE) {
0183 musb_dbg(musb, "high-speed device connected");
0184 musb->port1_status |= USB_PORT_STAT_HIGH_SPEED;
0185 }
0186
0187 musb->port1_status &= ~USB_PORT_STAT_RESET;
0188 musb->port1_status |= USB_PORT_STAT_ENABLE
0189 | (USB_PORT_STAT_C_RESET << 16)
0190 | (USB_PORT_STAT_C_ENABLE << 16);
0191 usb_hcd_poll_rh_status(musb->hcd);
0192
0193 musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
0194 }
0195 }
0196
0197 void musb_root_disconnect(struct musb *musb)
0198 {
0199 struct usb_otg *otg = musb->xceiv->otg;
0200
0201 musb->port1_status = USB_PORT_STAT_POWER
0202 | (USB_PORT_STAT_C_CONNECTION << 16);
0203
0204 usb_hcd_poll_rh_status(musb->hcd);
0205 musb->is_active = 0;
0206
0207 switch (musb->xceiv->otg->state) {
0208 case OTG_STATE_A_SUSPEND:
0209 if (otg->host->b_hnp_enable) {
0210 musb->xceiv->otg->state = OTG_STATE_A_PERIPHERAL;
0211 musb->g.is_a_peripheral = 1;
0212 break;
0213 }
0214 fallthrough;
0215 case OTG_STATE_A_HOST:
0216 musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON;
0217 musb->is_active = 0;
0218 break;
0219 case OTG_STATE_A_WAIT_VFALL:
0220 musb->xceiv->otg->state = OTG_STATE_B_IDLE;
0221 break;
0222 default:
0223 musb_dbg(musb, "host disconnect (%s)",
0224 usb_otg_state_string(musb->xceiv->otg->state));
0225 }
0226 }
0227 EXPORT_SYMBOL_GPL(musb_root_disconnect);
0228
0229
0230
0231
0232
0233 int musb_hub_status_data(struct usb_hcd *hcd, char *buf)
0234 {
0235 struct musb *musb = hcd_to_musb(hcd);
0236 int retval = 0;
0237
0238
0239 if (musb->port1_status & 0xffff0000) {
0240 *buf = 0x02;
0241 retval = 1;
0242 }
0243 return retval;
0244 }
0245
0246 static int musb_has_gadget(struct musb *musb)
0247 {
0248
0249
0250
0251
0252
0253
0254 #ifdef CONFIG_USB_MUSB_HOST
0255 return 1;
0256 #else
0257 return musb->port_mode == MUSB_HOST;
0258 #endif
0259 }
0260
0261 int musb_hub_control(
0262 struct usb_hcd *hcd,
0263 u16 typeReq,
0264 u16 wValue,
0265 u16 wIndex,
0266 char *buf,
0267 u16 wLength)
0268 {
0269 struct musb *musb = hcd_to_musb(hcd);
0270 u32 temp;
0271 int retval = 0;
0272 unsigned long flags;
0273 bool start_musb = false;
0274
0275 spin_lock_irqsave(&musb->lock, flags);
0276
0277 if (unlikely(!HCD_HW_ACCESSIBLE(hcd))) {
0278 spin_unlock_irqrestore(&musb->lock, flags);
0279 return -ESHUTDOWN;
0280 }
0281
0282
0283
0284
0285
0286 switch (typeReq) {
0287 case ClearHubFeature:
0288 case SetHubFeature:
0289 switch (wValue) {
0290 case C_HUB_OVER_CURRENT:
0291 case C_HUB_LOCAL_POWER:
0292 break;
0293 default:
0294 goto error;
0295 }
0296 break;
0297 case ClearPortFeature:
0298 if ((wIndex & 0xff) != 1)
0299 goto error;
0300
0301 switch (wValue) {
0302 case USB_PORT_FEAT_ENABLE:
0303 break;
0304 case USB_PORT_FEAT_SUSPEND:
0305 musb_port_suspend(musb, false);
0306 break;
0307 case USB_PORT_FEAT_POWER:
0308 if (!hcd->self.is_b_host)
0309 musb_platform_set_vbus(musb, 0);
0310 break;
0311 case USB_PORT_FEAT_C_CONNECTION:
0312 case USB_PORT_FEAT_C_ENABLE:
0313 case USB_PORT_FEAT_C_OVER_CURRENT:
0314 case USB_PORT_FEAT_C_RESET:
0315 case USB_PORT_FEAT_C_SUSPEND:
0316 break;
0317 default:
0318 goto error;
0319 }
0320 musb_dbg(musb, "clear feature %d", wValue);
0321 musb->port1_status &= ~(1 << wValue);
0322 break;
0323 case GetHubDescriptor:
0324 {
0325 struct usb_hub_descriptor *desc = (void *)buf;
0326
0327 desc->bDescLength = 9;
0328 desc->bDescriptorType = USB_DT_HUB;
0329 desc->bNbrPorts = 1;
0330 desc->wHubCharacteristics = cpu_to_le16(
0331 HUB_CHAR_INDV_PORT_LPSM
0332 | HUB_CHAR_NO_OCPM
0333 );
0334 desc->bPwrOn2PwrGood = 5;
0335 desc->bHubContrCurrent = 0;
0336
0337
0338 desc->u.hs.DeviceRemovable[0] = 0x02;
0339 desc->u.hs.DeviceRemovable[1] = 0xff;
0340 }
0341 break;
0342 case GetHubStatus:
0343 temp = 0;
0344 *(__le32 *) buf = cpu_to_le32(temp);
0345 break;
0346 case GetPortStatus:
0347 if (wIndex != 1)
0348 goto error;
0349
0350 put_unaligned(cpu_to_le32(musb->port1_status
0351 & ~MUSB_PORT_STAT_RESUME),
0352 (__le32 *) buf);
0353
0354
0355 musb_dbg(musb, "port status %08x", musb->port1_status);
0356 break;
0357 case SetPortFeature:
0358 if ((wIndex & 0xff) != 1)
0359 goto error;
0360
0361 switch (wValue) {
0362 case USB_PORT_FEAT_POWER:
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372
0373 if (!hcd->self.is_b_host && musb_has_gadget(musb))
0374 start_musb = true;
0375 break;
0376 case USB_PORT_FEAT_RESET:
0377 musb_port_reset(musb, true);
0378 break;
0379 case USB_PORT_FEAT_SUSPEND:
0380 musb_port_suspend(musb, true);
0381 break;
0382 case USB_PORT_FEAT_TEST:
0383 if (unlikely(is_host_active(musb)))
0384 goto error;
0385
0386 wIndex >>= 8;
0387 switch (wIndex) {
0388 case USB_TEST_J:
0389 pr_debug("USB_TEST_J\n");
0390 temp = MUSB_TEST_J;
0391 break;
0392 case USB_TEST_K:
0393 pr_debug("USB_TEST_K\n");
0394 temp = MUSB_TEST_K;
0395 break;
0396 case USB_TEST_SE0_NAK:
0397 pr_debug("USB_TEST_SE0_NAK\n");
0398 temp = MUSB_TEST_SE0_NAK;
0399 break;
0400 case USB_TEST_PACKET:
0401 pr_debug("USB_TEST_PACKET\n");
0402 temp = MUSB_TEST_PACKET;
0403 musb_load_testpacket(musb);
0404 break;
0405 case USB_TEST_FORCE_ENABLE:
0406 pr_debug("USB_TEST_FORCE_ENABLE\n");
0407 temp = MUSB_TEST_FORCE_HOST
0408 | MUSB_TEST_FORCE_HS;
0409
0410 musb_writeb(musb->mregs, MUSB_DEVCTL,
0411 MUSB_DEVCTL_SESSION);
0412 break;
0413 case 6:
0414 pr_debug("TEST_FIFO_ACCESS\n");
0415 temp = MUSB_TEST_FIFO_ACCESS;
0416 break;
0417 default:
0418 goto error;
0419 }
0420 musb_writeb(musb->mregs, MUSB_TESTMODE, temp);
0421 break;
0422 default:
0423 goto error;
0424 }
0425 musb_dbg(musb, "set feature %d", wValue);
0426 musb->port1_status |= 1 << wValue;
0427 break;
0428
0429 default:
0430 error:
0431
0432 retval = -EPIPE;
0433 }
0434 spin_unlock_irqrestore(&musb->lock, flags);
0435
0436 if (start_musb)
0437 musb_start(musb);
0438
0439 return retval;
0440 }