diff options
Diffstat (limited to 'drivers/usb/host/r8a66597-hcd.c')
| -rw-r--r-- | drivers/usb/host/r8a66597-hcd.c | 118 |
1 files changed, 108 insertions, 10 deletions
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 319041205b57..f1626e58c141 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c | |||
| @@ -660,9 +660,9 @@ static u16 get_empty_pipenum(struct r8a66597 *r8a66597, | |||
| 660 | u16 array[R8A66597_MAX_NUM_PIPE], i = 0, min; | 660 | u16 array[R8A66597_MAX_NUM_PIPE], i = 0, min; |
| 661 | 661 | ||
| 662 | memset(array, 0, sizeof(array)); | 662 | memset(array, 0, sizeof(array)); |
| 663 | switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { | 663 | switch (usb_endpoint_type(ep)) { |
| 664 | case USB_ENDPOINT_XFER_BULK: | 664 | case USB_ENDPOINT_XFER_BULK: |
| 665 | if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) | 665 | if (usb_endpoint_dir_in(ep)) |
| 666 | array[i++] = 4; | 666 | array[i++] = 4; |
| 667 | else { | 667 | else { |
| 668 | array[i++] = 3; | 668 | array[i++] = 3; |
| @@ -670,7 +670,7 @@ static u16 get_empty_pipenum(struct r8a66597 *r8a66597, | |||
| 670 | } | 670 | } |
| 671 | break; | 671 | break; |
| 672 | case USB_ENDPOINT_XFER_INT: | 672 | case USB_ENDPOINT_XFER_INT: |
| 673 | if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) { | 673 | if (usb_endpoint_dir_in(ep)) { |
| 674 | array[i++] = 6; | 674 | array[i++] = 6; |
| 675 | array[i++] = 7; | 675 | array[i++] = 7; |
| 676 | array[i++] = 8; | 676 | array[i++] = 8; |
| @@ -678,7 +678,7 @@ static u16 get_empty_pipenum(struct r8a66597 *r8a66597, | |||
| 678 | array[i++] = 9; | 678 | array[i++] = 9; |
| 679 | break; | 679 | break; |
| 680 | case USB_ENDPOINT_XFER_ISOC: | 680 | case USB_ENDPOINT_XFER_ISOC: |
| 681 | if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) | 681 | if (usb_endpoint_dir_in(ep)) |
| 682 | array[i++] = 2; | 682 | array[i++] = 2; |
| 683 | else | 683 | else |
| 684 | array[i++] = 1; | 684 | array[i++] = 1; |
| @@ -928,10 +928,9 @@ static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb, | |||
| 928 | 928 | ||
| 929 | info.pipenum = get_empty_pipenum(r8a66597, ep); | 929 | info.pipenum = get_empty_pipenum(r8a66597, ep); |
| 930 | info.address = get_urb_to_r8a66597_addr(r8a66597, urb); | 930 | info.address = get_urb_to_r8a66597_addr(r8a66597, urb); |
| 931 | info.epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; | 931 | info.epnum = usb_endpoint_num(ep); |
| 932 | info.maxpacket = le16_to_cpu(ep->wMaxPacketSize); | 932 | info.maxpacket = le16_to_cpu(ep->wMaxPacketSize); |
| 933 | info.type = get_r8a66597_type(ep->bmAttributes | 933 | info.type = get_r8a66597_type(usb_endpoint_type(ep)); |
| 934 | & USB_ENDPOINT_XFERTYPE_MASK); | ||
| 935 | info.bufnum = get_bufnum(info.pipenum); | 934 | info.bufnum = get_bufnum(info.pipenum); |
| 936 | info.buf_bsize = get_buf_bsize(info.pipenum); | 935 | info.buf_bsize = get_buf_bsize(info.pipenum); |
| 937 | if (info.type == R8A66597_BULK) { | 936 | if (info.type == R8A66597_BULK) { |
| @@ -941,7 +940,7 @@ static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb, | |||
| 941 | info.interval = get_interval(urb, ep->bInterval); | 940 | info.interval = get_interval(urb, ep->bInterval); |
| 942 | info.timer_interval = get_timer_interval(urb, ep->bInterval); | 941 | info.timer_interval = get_timer_interval(urb, ep->bInterval); |
| 943 | } | 942 | } |
| 944 | if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) | 943 | if (usb_endpoint_dir_in(ep)) |
| 945 | info.dir_in = 1; | 944 | info.dir_in = 1; |
| 946 | else | 945 | else |
| 947 | info.dir_in = 0; | 946 | info.dir_in = 0; |
| @@ -1014,6 +1013,9 @@ static void r8a66597_check_syssts(struct r8a66597 *r8a66597, int port, | |||
| 1014 | 1013 | ||
| 1015 | r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port)); | 1014 | r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port)); |
| 1016 | 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)); | ||
| 1017 | } | 1019 | } |
| 1018 | 1020 | ||
| 1019 | /* this function must be called with interrupt disabled */ | 1021 | /* this function must be called with interrupt disabled */ |
| @@ -1395,7 +1397,7 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum) | |||
| 1395 | (int)urb->iso_frame_desc[td->iso_cnt].length); | 1397 | (int)urb->iso_frame_desc[td->iso_cnt].length); |
| 1396 | } else { | 1398 | } else { |
| 1397 | buf = (u16 *)(urb->transfer_buffer + urb->actual_length); | 1399 | buf = (u16 *)(urb->transfer_buffer + urb->actual_length); |
| 1398 | size = min((int)bufsize, | 1400 | size = min_t(u32, bufsize, |
| 1399 | urb->transfer_buffer_length - urb->actual_length); | 1401 | urb->transfer_buffer_length - urb->actual_length); |
| 1400 | } | 1402 | } |
| 1401 | 1403 | ||
| @@ -1615,6 +1617,11 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd) | |||
| 1615 | r8a66597_bclr(r8a66597, DTCHE, INTENB2); | 1617 | r8a66597_bclr(r8a66597, DTCHE, INTENB2); |
| 1616 | r8a66597_usb_disconnect(r8a66597, 1); | 1618 | r8a66597_usb_disconnect(r8a66597, 1); |
| 1617 | } | 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 | } | ||
| 1618 | } | 1625 | } |
| 1619 | 1626 | ||
| 1620 | if (mask1) { | 1627 | if (mask1) { |
| @@ -1630,6 +1637,12 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd) | |||
| 1630 | r8a66597_bclr(r8a66597, DTCHE, INTENB1); | 1637 | r8a66597_bclr(r8a66597, DTCHE, INTENB1); |
| 1631 | r8a66597_usb_disconnect(r8a66597, 0); | 1638 | r8a66597_usb_disconnect(r8a66597, 0); |
| 1632 | } | 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 | |||
| 1633 | if (mask1 & SIGN) { | 1646 | if (mask1 & SIGN) { |
| 1634 | r8a66597_write(r8a66597, ~SIGN, INTSTS1); | 1647 | r8a66597_write(r8a66597, ~SIGN, INTSTS1); |
| 1635 | status = get_urb_error(r8a66597, 0); | 1648 | status = get_urb_error(r8a66597, 0); |
| @@ -2141,7 +2154,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
| 2141 | 2154 | ||
| 2142 | switch (wValue) { | 2155 | switch (wValue) { |
| 2143 | case USB_PORT_FEAT_ENABLE: | 2156 | case USB_PORT_FEAT_ENABLE: |
| 2144 | rh->port &= (1 << USB_PORT_FEAT_POWER); | 2157 | rh->port &= ~(1 << USB_PORT_FEAT_POWER); |
| 2145 | break; | 2158 | break; |
| 2146 | case USB_PORT_FEAT_SUSPEND: | 2159 | case USB_PORT_FEAT_SUSPEND: |
| 2147 | break; | 2160 | break; |
| @@ -2213,6 +2226,68 @@ error: | |||
| 2213 | return ret; | 2226 | return ret; |
| 2214 | } | 2227 | } |
| 2215 | 2228 | ||
| 2229 | #if defined(CONFIG_PM) | ||
| 2230 | static 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 | |||
| 2261 | static 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 | |||
| 2216 | static struct hc_driver r8a66597_hc_driver = { | 2291 | static struct hc_driver r8a66597_hc_driver = { |
| 2217 | .description = hcd_name, | 2292 | .description = hcd_name, |
| 2218 | .hcd_priv_size = sizeof(struct r8a66597), | 2293 | .hcd_priv_size = sizeof(struct r8a66597), |
| @@ -2243,16 +2318,39 @@ static struct hc_driver r8a66597_hc_driver = { | |||
| 2243 | */ | 2318 | */ |
| 2244 | .hub_status_data = r8a66597_hub_status_data, | 2319 | .hub_status_data = r8a66597_hub_status_data, |
| 2245 | .hub_control = r8a66597_hub_control, | 2320 | .hub_control = r8a66597_hub_control, |
| 2321 | .bus_suspend = r8a66597_bus_suspend, | ||
| 2322 | .bus_resume = r8a66597_bus_resume, | ||
| 2246 | }; | 2323 | }; |
| 2247 | 2324 | ||
| 2248 | #if defined(CONFIG_PM) | 2325 | #if defined(CONFIG_PM) |
| 2249 | static int r8a66597_suspend(struct platform_device *pdev, pm_message_t state) | 2326 | static int r8a66597_suspend(struct platform_device *pdev, pm_message_t state) |
| 2250 | { | 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 | |||
| 2251 | return 0; | 2341 | return 0; |
| 2252 | } | 2342 | } |
| 2253 | 2343 | ||
| 2254 | static int r8a66597_resume(struct platform_device *pdev) | 2344 | static int r8a66597_resume(struct platform_device *pdev) |
| 2255 | { | 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 | |||
| 2256 | return 0; | 2354 | return 0; |
| 2257 | } | 2355 | } |
| 2258 | #else /* if defined(CONFIG_PM) */ | 2356 | #else /* if defined(CONFIG_PM) */ |
