Skip to content

Commit

Permalink
USB: r8a66597-hcd: suspend/resume support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Yoshihiro Shimoda authored and Greg Kroah-Hartman committed Mar 24, 2009
1 parent 71d2718 commit e1e609b
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 1 deletion.
101 changes: 100 additions & 1 deletion drivers/usb/host/r8a66597-hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1013,6 +1013,9 @@ static void r8a66597_check_syssts(struct r8a66597 *r8a66597, int port,

r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port));
r8a66597_bset(r8a66597, DTCHE, get_intenb_reg(port));

if (r8a66597->bus_suspended)
usb_hcd_resume_root_hub(r8a66597_to_hcd(r8a66597));
}

/* this function must be called with interrupt disabled */
Expand Down Expand Up @@ -1614,6 +1617,11 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
r8a66597_bclr(r8a66597, DTCHE, INTENB2);
r8a66597_usb_disconnect(r8a66597, 1);
}
if (mask2 & BCHG) {
r8a66597_write(r8a66597, ~BCHG, INTSTS2);
r8a66597_bclr(r8a66597, BCHGE, INTENB2);
usb_hcd_resume_root_hub(r8a66597_to_hcd(r8a66597));
}
}

if (mask1) {
Expand All @@ -1629,6 +1637,12 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
r8a66597_bclr(r8a66597, DTCHE, INTENB1);
r8a66597_usb_disconnect(r8a66597, 0);
}
if (mask1 & BCHG) {
r8a66597_write(r8a66597, ~BCHG, INTSTS1);
r8a66597_bclr(r8a66597, BCHGE, INTENB1);
usb_hcd_resume_root_hub(r8a66597_to_hcd(r8a66597));
}

if (mask1 & SIGN) {
r8a66597_write(r8a66597, ~SIGN, INTSTS1);
status = get_urb_error(r8a66597, 0);
Expand Down Expand Up @@ -2140,7 +2154,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,

switch (wValue) {
case USB_PORT_FEAT_ENABLE:
rh->port &= (1 << USB_PORT_FEAT_POWER);
rh->port &= ~(1 << USB_PORT_FEAT_POWER);
break;
case USB_PORT_FEAT_SUSPEND:
break;
Expand Down Expand Up @@ -2212,6 +2226,68 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
return ret;
}

#if defined(CONFIG_PM)
static int r8a66597_bus_suspend(struct usb_hcd *hcd)
{
struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
int port;

dbg("%s", __func__);

for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) {
struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
unsigned long dvstctr_reg = get_dvstctr_reg(port);

if (!(rh->port & (1 << USB_PORT_FEAT_ENABLE)))
continue;

dbg("suspend port = %d", port);
r8a66597_bclr(r8a66597, UACT, dvstctr_reg); /* suspend */
rh->port |= 1 << USB_PORT_FEAT_SUSPEND;

if (rh->dev->udev->do_remote_wakeup) {
msleep(3); /* waiting last SOF */
r8a66597_bset(r8a66597, RWUPE, dvstctr_reg);
r8a66597_write(r8a66597, ~BCHG, get_intsts_reg(port));
r8a66597_bset(r8a66597, BCHGE, get_intenb_reg(port));
}
}

r8a66597->bus_suspended = 1;

return 0;
}

static int r8a66597_bus_resume(struct usb_hcd *hcd)
{
struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
int port;

dbg("%s", __func__);

for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) {
struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
unsigned long dvstctr_reg = get_dvstctr_reg(port);

if (!(rh->port & (1 << USB_PORT_FEAT_SUSPEND)))
continue;

dbg("resume port = %d", port);
rh->port &= ~(1 << USB_PORT_FEAT_SUSPEND);
rh->port |= 1 << USB_PORT_FEAT_C_SUSPEND;
r8a66597_mdfy(r8a66597, RESUME, RESUME | UACT, dvstctr_reg);
msleep(50);
r8a66597_mdfy(r8a66597, UACT, RESUME | UACT, dvstctr_reg);
}

return 0;

}
#else
#define r8a66597_bus_suspend NULL
#define r8a66597_bus_resume NULL
#endif

static struct hc_driver r8a66597_hc_driver = {
.description = hcd_name,
.hcd_priv_size = sizeof(struct r8a66597),
Expand Down Expand Up @@ -2242,16 +2318,39 @@ static struct hc_driver r8a66597_hc_driver = {
*/
.hub_status_data = r8a66597_hub_status_data,
.hub_control = r8a66597_hub_control,
.bus_suspend = r8a66597_bus_suspend,
.bus_resume = r8a66597_bus_resume,
};

#if defined(CONFIG_PM)
static int r8a66597_suspend(struct platform_device *pdev, pm_message_t state)
{
struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev);
int port;

dbg("%s", __func__);

disable_controller(r8a66597);

for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) {
struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];

rh->port = 0x00000000;
}

return 0;
}

static int r8a66597_resume(struct platform_device *pdev)
{
struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev);
struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);

dbg("%s", __func__);

enable_controller(r8a66597);
usb_root_hub_lost_power(hcd->self.root_hub);

return 0;
}
#else /* if defined(CONFIG_PM) */
Expand Down
2 changes: 2 additions & 0 deletions drivers/usb/host/r8a66597.h
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,8 @@ struct r8a66597 {

struct list_head child_device;
unsigned long child_connect_map[4];

unsigned bus_suspended:1;
};

static inline struct r8a66597 *hcd_to_r8a66597(struct usb_hcd *hcd)
Expand Down

0 comments on commit e1e609b

Please sign in to comment.