aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorYoshihiro Shimoda <shimoda.yoshihiro@renesas.com>2009-03-19 01:18:15 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-03-24 19:20:45 -0400
commite1e609be49c9d345e8b67a122a7cdae48ad27c7e (patch)
treec1cfc523469741bffc3400f5c3d81bda5db1fb8a /drivers/usb
parent71d2718f2507dc17501d04e2bdca7b8e694ce365 (diff)
USB: r8a66597-hcd: suspend/resume support
Fix the problem that system cannot suspend. Signed-off-by: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/r8a66597-hcd.c101
-rw-r--r--drivers/usb/host/r8a66597.h2
2 files changed, 102 insertions, 1 deletions
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 713f4cf0b0dd..f1626e58c141 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -1013,6 +1013,9 @@ static void r8a66597_check_syssts(struct r8a66597 *r8a66597, int port,
1013 1013
1014 r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port)); 1014 r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port));
1015 r8a66597_bset(r8a66597, DTCHE, get_intenb_reg(port)); 1015 r8a66597_bset(r8a66597, DTCHE, get_intenb_reg(port));
1016
1017 if (r8a66597->bus_suspended)
1018 usb_hcd_resume_root_hub(r8a66597_to_hcd(r8a66597));
1016} 1019}
1017 1020
1018/* this function must be called with interrupt disabled */ 1021/* this function must be called with interrupt disabled */
@@ -1614,6 +1617,11 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
1614 r8a66597_bclr(r8a66597, DTCHE, INTENB2); 1617 r8a66597_bclr(r8a66597, DTCHE, INTENB2);
1615 r8a66597_usb_disconnect(r8a66597, 1); 1618 r8a66597_usb_disconnect(r8a66597, 1);
1616 } 1619 }
1620 if (mask2 & BCHG) {
1621 r8a66597_write(r8a66597, ~BCHG, INTSTS2);
1622 r8a66597_bclr(r8a66597, BCHGE, INTENB2);
1623 usb_hcd_resume_root_hub(r8a66597_to_hcd(r8a66597));
1624 }
1617 } 1625 }
1618 1626
1619 if (mask1) { 1627 if (mask1) {
@@ -1629,6 +1637,12 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
1629 r8a66597_bclr(r8a66597, DTCHE, INTENB1); 1637 r8a66597_bclr(r8a66597, DTCHE, INTENB1);
1630 r8a66597_usb_disconnect(r8a66597, 0); 1638 r8a66597_usb_disconnect(r8a66597, 0);
1631 } 1639 }
1640 if (mask1 & BCHG) {
1641 r8a66597_write(r8a66597, ~BCHG, INTSTS1);
1642 r8a66597_bclr(r8a66597, BCHGE, INTENB1);
1643 usb_hcd_resume_root_hub(r8a66597_to_hcd(r8a66597));
1644 }
1645
1632 if (mask1 & SIGN) { 1646 if (mask1 & SIGN) {
1633 r8a66597_write(r8a66597, ~SIGN, INTSTS1); 1647 r8a66597_write(r8a66597, ~SIGN, INTSTS1);
1634 status = get_urb_error(r8a66597, 0); 1648 status = get_urb_error(r8a66597, 0);
@@ -2140,7 +2154,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
2140 2154
2141 switch (wValue) { 2155 switch (wValue) {
2142 case USB_PORT_FEAT_ENABLE: 2156 case USB_PORT_FEAT_ENABLE:
2143 rh->port &= (1 << USB_PORT_FEAT_POWER); 2157 rh->port &= ~(1 << USB_PORT_FEAT_POWER);
2144 break; 2158 break;
2145 case USB_PORT_FEAT_SUSPEND: 2159 case USB_PORT_FEAT_SUSPEND:
2146 break; 2160 break;
@@ -2212,6 +2226,68 @@ error:
2212 return ret; 2226 return ret;
2213} 2227}
2214 2228
2229#if defined(CONFIG_PM)
2230static int r8a66597_bus_suspend(struct usb_hcd *hcd)
2231{
2232 struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
2233 int port;
2234
2235 dbg("%s", __func__);
2236
2237 for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) {
2238 struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
2239 unsigned long dvstctr_reg = get_dvstctr_reg(port);
2240
2241 if (!(rh->port & (1 << USB_PORT_FEAT_ENABLE)))
2242 continue;
2243
2244 dbg("suspend port = %d", port);
2245 r8a66597_bclr(r8a66597, UACT, dvstctr_reg); /* suspend */
2246 rh->port |= 1 << USB_PORT_FEAT_SUSPEND;
2247
2248 if (rh->dev->udev->do_remote_wakeup) {
2249 msleep(3); /* waiting last SOF */
2250 r8a66597_bset(r8a66597, RWUPE, dvstctr_reg);
2251 r8a66597_write(r8a66597, ~BCHG, get_intsts_reg(port));
2252 r8a66597_bset(r8a66597, BCHGE, get_intenb_reg(port));
2253 }
2254 }
2255
2256 r8a66597->bus_suspended = 1;
2257
2258 return 0;
2259}
2260
2261static int r8a66597_bus_resume(struct usb_hcd *hcd)
2262{
2263 struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
2264 int port;
2265
2266 dbg("%s", __func__);
2267
2268 for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) {
2269 struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
2270 unsigned long dvstctr_reg = get_dvstctr_reg(port);
2271
2272 if (!(rh->port & (1 << USB_PORT_FEAT_SUSPEND)))
2273 continue;
2274
2275 dbg("resume port = %d", port);
2276 rh->port &= ~(1 << USB_PORT_FEAT_SUSPEND);
2277 rh->port |= 1 << USB_PORT_FEAT_C_SUSPEND;
2278 r8a66597_mdfy(r8a66597, RESUME, RESUME | UACT, dvstctr_reg);
2279 msleep(50);
2280 r8a66597_mdfy(r8a66597, UACT, RESUME | UACT, dvstctr_reg);
2281 }
2282
2283 return 0;
2284
2285}
2286#else
2287#define r8a66597_bus_suspend NULL
2288#define r8a66597_bus_resume NULL
2289#endif
2290
2215static struct hc_driver r8a66597_hc_driver = { 2291static struct hc_driver r8a66597_hc_driver = {
2216 .description = hcd_name, 2292 .description = hcd_name,
2217 .hcd_priv_size = sizeof(struct r8a66597), 2293 .hcd_priv_size = sizeof(struct r8a66597),
@@ -2242,16 +2318,39 @@ static struct hc_driver r8a66597_hc_driver = {
2242 */ 2318 */
2243 .hub_status_data = r8a66597_hub_status_data, 2319 .hub_status_data = r8a66597_hub_status_data,
2244 .hub_control = r8a66597_hub_control, 2320 .hub_control = r8a66597_hub_control,
2321 .bus_suspend = r8a66597_bus_suspend,
2322 .bus_resume = r8a66597_bus_resume,
2245}; 2323};
2246 2324
2247#if defined(CONFIG_PM) 2325#if defined(CONFIG_PM)
2248static int r8a66597_suspend(struct platform_device *pdev, pm_message_t state) 2326static int r8a66597_suspend(struct platform_device *pdev, pm_message_t state)
2249{ 2327{
2328 struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev);
2329 int port;
2330
2331 dbg("%s", __func__);
2332
2333 disable_controller(r8a66597);
2334
2335 for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) {
2336 struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
2337
2338 rh->port = 0x00000000;
2339 }
2340
2250 return 0; 2341 return 0;
2251} 2342}
2252 2343
2253static int r8a66597_resume(struct platform_device *pdev) 2344static int r8a66597_resume(struct platform_device *pdev)
2254{ 2345{
2346 struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev);
2347 struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
2348
2349 dbg("%s", __func__);
2350
2351 enable_controller(r8a66597);
2352 usb_root_hub_lost_power(hcd->self.root_hub);
2353
2255 return 0; 2354 return 0;
2256} 2355}
2257#else /* if defined(CONFIG_PM) */ 2356#else /* if defined(CONFIG_PM) */
diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h
index ecacde4d69b0..f49208f1bb74 100644
--- a/drivers/usb/host/r8a66597.h
+++ b/drivers/usb/host/r8a66597.h
@@ -504,6 +504,8 @@ struct r8a66597 {
504 504
505 struct list_head child_device; 505 struct list_head child_device;
506 unsigned long child_connect_map[4]; 506 unsigned long child_connect_map[4];
507
508 unsigned bus_suspended:1;
507}; 509};
508 510
509static inline struct r8a66597 *hcd_to_r8a66597(struct usb_hcd *hcd) 511static inline struct r8a66597 *hcd_to_r8a66597(struct usb_hcd *hcd)