diff options
Diffstat (limited to 'drivers/usb/gadget/s3c-hsotg.c')
| -rw-r--r-- | drivers/usb/gadget/s3c-hsotg.c | 153 |
1 files changed, 122 insertions, 31 deletions
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 26193eceb323..521ebed0118d 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c | |||
| @@ -12,6 +12,8 @@ | |||
| 12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
| 13 | */ | 13 | */ |
| 14 | 14 | ||
| 15 | #define DEBUG | ||
| 16 | |||
| 15 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
| 16 | #include <linux/module.h> | 18 | #include <linux/module.h> |
| 17 | #include <linux/spinlock.h> | 19 | #include <linux/spinlock.h> |
| @@ -23,6 +25,7 @@ | |||
| 23 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
| 24 | #include <linux/io.h> | 26 | #include <linux/io.h> |
| 25 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
| 28 | #include <linux/clk.h> | ||
| 26 | 29 | ||
| 27 | #include <linux/usb/ch9.h> | 30 | #include <linux/usb/ch9.h> |
| 28 | #include <linux/usb/gadget.h> | 31 | #include <linux/usb/gadget.h> |
| @@ -33,6 +36,7 @@ | |||
| 33 | #include <plat/regs-usb-hsotg.h> | 36 | #include <plat/regs-usb-hsotg.h> |
| 34 | #include <mach/regs-sys.h> | 37 | #include <mach/regs-sys.h> |
| 35 | #include <plat/udc-hs.h> | 38 | #include <plat/udc-hs.h> |
| 39 | #include <plat/cpu.h> | ||
| 36 | 40 | ||
| 37 | #define DMA_ADDR_INVALID (~((dma_addr_t)0)) | 41 | #define DMA_ADDR_INVALID (~((dma_addr_t)0)) |
| 38 | 42 | ||
| @@ -91,7 +95,9 @@ struct s3c_hsotg_req; | |||
| 91 | * For periodic IN endpoints, we have fifo_size and fifo_load to try | 95 | * For periodic IN endpoints, we have fifo_size and fifo_load to try |
| 92 | * and keep track of the amount of data in the periodic FIFO for each | 96 | * and keep track of the amount of data in the periodic FIFO for each |
| 93 | * of these as we don't have a status register that tells us how much | 97 | * of these as we don't have a status register that tells us how much |
| 94 | * is in each of them. | 98 | * is in each of them. (note, this may actually be useless information |
| 99 | * as in shared-fifo mode periodic in acts like a single-frame packet | ||
| 100 | * buffer than a fifo) | ||
| 95 | */ | 101 | */ |
| 96 | struct s3c_hsotg_ep { | 102 | struct s3c_hsotg_ep { |
| 97 | struct usb_ep ep; | 103 | struct usb_ep ep; |
| @@ -128,6 +134,7 @@ struct s3c_hsotg_ep { | |||
| 128 | * @regs: The memory area mapped for accessing registers. | 134 | * @regs: The memory area mapped for accessing registers. |
| 129 | * @regs_res: The resource that was allocated when claiming register space. | 135 | * @regs_res: The resource that was allocated when claiming register space. |
| 130 | * @irq: The IRQ number we are using | 136 | * @irq: The IRQ number we are using |
| 137 | * @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos. | ||
| 131 | * @debug_root: root directrory for debugfs. | 138 | * @debug_root: root directrory for debugfs. |
| 132 | * @debug_file: main status file for debugfs. | 139 | * @debug_file: main status file for debugfs. |
| 133 | * @debug_fifo: FIFO status file for debugfs. | 140 | * @debug_fifo: FIFO status file for debugfs. |
| @@ -145,6 +152,9 @@ struct s3c_hsotg { | |||
| 145 | void __iomem *regs; | 152 | void __iomem *regs; |
| 146 | struct resource *regs_res; | 153 | struct resource *regs_res; |
| 147 | int irq; | 154 | int irq; |
| 155 | struct clk *clk; | ||
| 156 | |||
| 157 | unsigned int dedicated_fifos:1; | ||
| 148 | 158 | ||
| 149 | struct dentry *debug_root; | 159 | struct dentry *debug_root; |
| 150 | struct dentry *debug_file; | 160 | struct dentry *debug_file; |
| @@ -310,11 +320,11 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) | |||
| 310 | hsotg->regs + S3C_GNPTXFSIZ); | 320 | hsotg->regs + S3C_GNPTXFSIZ); |
| 311 | */ | 321 | */ |
| 312 | 322 | ||
| 313 | /* set FIFO sizes to 2048/0x1C0 */ | 323 | /* set FIFO sizes to 2048/1024 */ |
| 314 | 324 | ||
| 315 | writel(2048, hsotg->regs + S3C_GRXFSIZ); | 325 | writel(2048, hsotg->regs + S3C_GRXFSIZ); |
| 316 | writel(S3C_GNPTXFSIZ_NPTxFStAddr(2048) | | 326 | writel(S3C_GNPTXFSIZ_NPTxFStAddr(2048) | |
| 317 | S3C_GNPTXFSIZ_NPTxFDep(0x1C0), | 327 | S3C_GNPTXFSIZ_NPTxFDep(1024), |
| 318 | hsotg->regs + S3C_GNPTXFSIZ); | 328 | hsotg->regs + S3C_GNPTXFSIZ); |
| 319 | 329 | ||
| 320 | /* arange all the rest of the TX FIFOs, as some versions of this | 330 | /* arange all the rest of the TX FIFOs, as some versions of this |
| @@ -464,7 +474,7 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, | |||
| 464 | if (to_write == 0) | 474 | if (to_write == 0) |
| 465 | return 0; | 475 | return 0; |
| 466 | 476 | ||
| 467 | if (periodic) { | 477 | if (periodic && !hsotg->dedicated_fifos) { |
| 468 | u32 epsize = readl(hsotg->regs + S3C_DIEPTSIZ(hs_ep->index)); | 478 | u32 epsize = readl(hsotg->regs + S3C_DIEPTSIZ(hs_ep->index)); |
| 469 | int size_left; | 479 | int size_left; |
| 470 | int size_done; | 480 | int size_done; |
| @@ -474,6 +484,14 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, | |||
| 474 | 484 | ||
| 475 | size_left = S3C_DxEPTSIZ_XferSize_GET(epsize); | 485 | size_left = S3C_DxEPTSIZ_XferSize_GET(epsize); |
| 476 | 486 | ||
| 487 | /* if shared fifo, we cannot write anything until the | ||
| 488 | * previous data has been completely sent. | ||
| 489 | */ | ||
| 490 | if (hs_ep->fifo_load != 0) { | ||
| 491 | s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_PTxFEmp); | ||
| 492 | return -ENOSPC; | ||
| 493 | } | ||
| 494 | |||
| 477 | dev_dbg(hsotg->dev, "%s: left=%d, load=%d, fifo=%d, size %d\n", | 495 | dev_dbg(hsotg->dev, "%s: left=%d, load=%d, fifo=%d, size %d\n", |
| 478 | __func__, size_left, | 496 | __func__, size_left, |
| 479 | hs_ep->size_loaded, hs_ep->fifo_load, hs_ep->fifo_size); | 497 | hs_ep->size_loaded, hs_ep->fifo_load, hs_ep->fifo_size); |
| @@ -494,6 +512,11 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, | |||
| 494 | s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_PTxFEmp); | 512 | s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_PTxFEmp); |
| 495 | return -ENOSPC; | 513 | return -ENOSPC; |
| 496 | } | 514 | } |
| 515 | } else if (hsotg->dedicated_fifos && hs_ep->index != 0) { | ||
| 516 | can_write = readl(hsotg->regs + S3C_DTXFSTS(hs_ep->index)); | ||
| 517 | |||
| 518 | can_write &= 0xffff; | ||
| 519 | can_write *= 4; | ||
| 497 | } else { | 520 | } else { |
| 498 | if (S3C_GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) { | 521 | if (S3C_GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) { |
| 499 | dev_dbg(hsotg->dev, | 522 | dev_dbg(hsotg->dev, |
| @@ -505,6 +528,7 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, | |||
| 505 | } | 528 | } |
| 506 | 529 | ||
| 507 | can_write = S3C_GNPTXSTS_NPTxFSpcAvail_GET(gnptxsts); | 530 | can_write = S3C_GNPTXSTS_NPTxFSpcAvail_GET(gnptxsts); |
| 531 | can_write *= 4; /* fifo size is in 32bit quantities. */ | ||
| 508 | } | 532 | } |
| 509 | 533 | ||
| 510 | dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, mps %d\n", | 534 | dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, mps %d\n", |
| @@ -517,6 +541,17 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, | |||
| 517 | if (can_write > 512) | 541 | if (can_write > 512) |
| 518 | can_write = 512; | 542 | can_write = 512; |
| 519 | 543 | ||
| 544 | /* limit the write to one max-packet size worth of data, but allow | ||
| 545 | * the transfer to return that it did not run out of fifo space | ||
| 546 | * doing it. */ | ||
| 547 | if (to_write > hs_ep->ep.maxpacket) { | ||
| 548 | to_write = hs_ep->ep.maxpacket; | ||
| 549 | |||
| 550 | s3c_hsotg_en_gsint(hsotg, | ||
| 551 | periodic ? S3C_GINTSTS_PTxFEmp : | ||
| 552 | S3C_GINTSTS_NPTxFEmp); | ||
| 553 | } | ||
| 554 | |||
| 520 | /* see if we can write data */ | 555 | /* see if we can write data */ |
| 521 | 556 | ||
| 522 | if (to_write > can_write) { | 557 | if (to_write > can_write) { |
| @@ -579,12 +614,10 @@ static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep) | |||
| 579 | maxsize = S3C_DxEPTSIZ_XferSize_LIMIT + 1; | 614 | maxsize = S3C_DxEPTSIZ_XferSize_LIMIT + 1; |
| 580 | maxpkt = S3C_DxEPTSIZ_PktCnt_LIMIT + 1; | 615 | maxpkt = S3C_DxEPTSIZ_PktCnt_LIMIT + 1; |
| 581 | } else { | 616 | } else { |
| 617 | maxsize = 64+64; | ||
| 582 | if (hs_ep->dir_in) { | 618 | if (hs_ep->dir_in) { |
| 583 | /* maxsize = S3C_DIEPTSIZ0_XferSize_LIMIT + 1; */ | ||
| 584 | maxsize = 64+64+1; | ||
| 585 | maxpkt = S3C_DIEPTSIZ0_PktCnt_LIMIT + 1; | 619 | maxpkt = S3C_DIEPTSIZ0_PktCnt_LIMIT + 1; |
| 586 | } else { | 620 | } else { |
| 587 | maxsize = 0x3f; | ||
| 588 | maxpkt = 2; | 621 | maxpkt = 2; |
| 589 | } | 622 | } |
| 590 | } | 623 | } |
| @@ -1353,6 +1386,9 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size) | |||
| 1353 | read_ptr = hs_req->req.actual; | 1386 | read_ptr = hs_req->req.actual; |
| 1354 | max_req = hs_req->req.length - read_ptr; | 1387 | max_req = hs_req->req.length - read_ptr; |
| 1355 | 1388 | ||
| 1389 | dev_dbg(hsotg->dev, "%s: read %d/%d, done %d/%d\n", | ||
| 1390 | __func__, to_read, max_req, read_ptr, hs_req->req.length); | ||
| 1391 | |||
| 1356 | if (to_read > max_req) { | 1392 | if (to_read > max_req) { |
| 1357 | /* more data appeared than we where willing | 1393 | /* more data appeared than we where willing |
| 1358 | * to deal with in this request. | 1394 | * to deal with in this request. |
| @@ -1362,9 +1398,6 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size) | |||
| 1362 | WARN_ON_ONCE(1); | 1398 | WARN_ON_ONCE(1); |
| 1363 | } | 1399 | } |
| 1364 | 1400 | ||
| 1365 | dev_dbg(hsotg->dev, "%s: read %d/%d, done %d/%d\n", | ||
| 1366 | __func__, to_read, max_req, read_ptr, hs_req->req.length); | ||
| 1367 | |||
| 1368 | hs_ep->total_data += to_read; | 1401 | hs_ep->total_data += to_read; |
| 1369 | hs_req->req.actual += to_read; | 1402 | hs_req->req.actual += to_read; |
| 1370 | to_read = DIV_ROUND_UP(to_read, 4); | 1403 | to_read = DIV_ROUND_UP(to_read, 4); |
| @@ -1433,9 +1466,11 @@ static void s3c_hsotg_send_zlp(struct s3c_hsotg *hsotg, | |||
| 1433 | static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg, | 1466 | static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg, |
| 1434 | int epnum, bool was_setup) | 1467 | int epnum, bool was_setup) |
| 1435 | { | 1468 | { |
| 1469 | u32 epsize = readl(hsotg->regs + S3C_DOEPTSIZ(epnum)); | ||
| 1436 | struct s3c_hsotg_ep *hs_ep = &hsotg->eps[epnum]; | 1470 | struct s3c_hsotg_ep *hs_ep = &hsotg->eps[epnum]; |
| 1437 | struct s3c_hsotg_req *hs_req = hs_ep->req; | 1471 | struct s3c_hsotg_req *hs_req = hs_ep->req; |
| 1438 | struct usb_request *req = &hs_req->req; | 1472 | struct usb_request *req = &hs_req->req; |
| 1473 | unsigned size_left = S3C_DxEPTSIZ_XferSize_GET(epsize); | ||
| 1439 | int result = 0; | 1474 | int result = 0; |
| 1440 | 1475 | ||
| 1441 | if (!hs_req) { | 1476 | if (!hs_req) { |
| @@ -1444,9 +1479,7 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg, | |||
| 1444 | } | 1479 | } |
| 1445 | 1480 | ||
| 1446 | if (using_dma(hsotg)) { | 1481 | if (using_dma(hsotg)) { |
| 1447 | u32 epsize = readl(hsotg->regs + S3C_DOEPTSIZ(epnum)); | ||
| 1448 | unsigned size_done; | 1482 | unsigned size_done; |
| 1449 | unsigned size_left; | ||
| 1450 | 1483 | ||
| 1451 | /* Calculate the size of the transfer by checking how much | 1484 | /* Calculate the size of the transfer by checking how much |
| 1452 | * is left in the endpoint size register and then working it | 1485 | * is left in the endpoint size register and then working it |
| @@ -1456,14 +1489,18 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg, | |||
| 1456 | * so may overshoot/undershoot the transfer. | 1489 | * so may overshoot/undershoot the transfer. |
| 1457 | */ | 1490 | */ |
| 1458 | 1491 | ||
| 1459 | size_left = S3C_DxEPTSIZ_XferSize_GET(epsize); | ||
| 1460 | |||
| 1461 | size_done = hs_ep->size_loaded - size_left; | 1492 | size_done = hs_ep->size_loaded - size_left; |
| 1462 | size_done += hs_ep->last_load; | 1493 | size_done += hs_ep->last_load; |
| 1463 | 1494 | ||
| 1464 | req->actual = size_done; | 1495 | req->actual = size_done; |
| 1465 | } | 1496 | } |
| 1466 | 1497 | ||
| 1498 | /* if there is more request to do, schedule new transfer */ | ||
| 1499 | if (req->actual < req->length && size_left == 0) { | ||
| 1500 | s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true); | ||
| 1501 | return; | ||
| 1502 | } | ||
| 1503 | |||
| 1467 | if (req->actual < req->length && req->short_not_ok) { | 1504 | if (req->actual < req->length && req->short_not_ok) { |
| 1468 | dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n", | 1505 | dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n", |
| 1469 | __func__, req->actual, req->length); | 1506 | __func__, req->actual, req->length); |
| @@ -1758,7 +1795,7 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, | |||
| 1758 | if (dir_in) { | 1795 | if (dir_in) { |
| 1759 | s3c_hsotg_complete_in(hsotg, hs_ep); | 1796 | s3c_hsotg_complete_in(hsotg, hs_ep); |
| 1760 | 1797 | ||
| 1761 | if (idx == 0) | 1798 | if (idx == 0 && !hs_ep->req) |
| 1762 | s3c_hsotg_enqueue_setup(hsotg); | 1799 | s3c_hsotg_enqueue_setup(hsotg); |
| 1763 | } else if (using_dma(hsotg)) { | 1800 | } else if (using_dma(hsotg)) { |
| 1764 | /* We're using DMA, we need to fire an OutDone here | 1801 | /* We're using DMA, we need to fire an OutDone here |
| @@ -1818,6 +1855,15 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, | |||
| 1818 | __func__, idx); | 1855 | __func__, idx); |
| 1819 | clear |= S3C_DIEPMSK_INTknEPMisMsk; | 1856 | clear |= S3C_DIEPMSK_INTknEPMisMsk; |
| 1820 | } | 1857 | } |
| 1858 | |||
| 1859 | /* FIFO has space or is empty (see GAHBCFG) */ | ||
| 1860 | if (hsotg->dedicated_fifos && | ||
| 1861 | ints & S3C_DIEPMSK_TxFIFOEmpty) { | ||
| 1862 | dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n", | ||
| 1863 | __func__, idx); | ||
| 1864 | s3c_hsotg_trytx(hsotg, hs_ep); | ||
| 1865 | clear |= S3C_DIEPMSK_TxFIFOEmpty; | ||
| 1866 | } | ||
| 1821 | } | 1867 | } |
| 1822 | 1868 | ||
| 1823 | writel(clear, hsotg->regs + epint_reg); | 1869 | writel(clear, hsotg->regs + epint_reg); |
| @@ -2071,17 +2117,12 @@ irq_retry: | |||
| 2071 | kill_all_requests(hsotg, &hsotg->eps[0], -ECONNRESET, true); | 2117 | kill_all_requests(hsotg, &hsotg->eps[0], -ECONNRESET, true); |
| 2072 | 2118 | ||
| 2073 | /* it seems after a reset we can end up with a situation | 2119 | /* it seems after a reset we can end up with a situation |
| 2074 | * where the TXFIFO still has data in it... try flushing | 2120 | * where the TXFIFO still has data in it... the docs |
| 2075 | * it to remove anything that may still be in it. | 2121 | * suggest resetting all the fifos, so use the init_fifo |
| 2122 | * code to relayout and flush the fifos. | ||
| 2076 | */ | 2123 | */ |
| 2077 | 2124 | ||
| 2078 | if (1) { | 2125 | s3c_hsotg_init_fifo(hsotg); |
| 2079 | writel(S3C_GRSTCTL_TxFNum(0) | S3C_GRSTCTL_TxFFlsh, | ||
| 2080 | hsotg->regs + S3C_GRSTCTL); | ||
| 2081 | |||
| 2082 | dev_info(hsotg->dev, "GNPTXSTS=%08x\n", | ||
| 2083 | readl(hsotg->regs + S3C_GNPTXSTS)); | ||
| 2084 | } | ||
| 2085 | 2126 | ||
| 2086 | s3c_hsotg_enqueue_setup(hsotg); | 2127 | s3c_hsotg_enqueue_setup(hsotg); |
| 2087 | 2128 | ||
| @@ -2274,6 +2315,12 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, | |||
| 2274 | break; | 2315 | break; |
| 2275 | } | 2316 | } |
| 2276 | 2317 | ||
| 2318 | /* if the hardware has dedicated fifos, we must give each IN EP | ||
| 2319 | * a unique tx-fifo even if it is non-periodic. | ||
| 2320 | */ | ||
| 2321 | if (dir_in && hsotg->dedicated_fifos) | ||
| 2322 | epctrl |= S3C_DxEPCTL_TxFNum(index); | ||
| 2323 | |||
| 2277 | /* for non control endpoints, set PID to D0 */ | 2324 | /* for non control endpoints, set PID to D0 */ |
| 2278 | if (index) | 2325 | if (index) |
| 2279 | epctrl |= S3C_DxEPCTL_SetD0PID; | 2326 | epctrl |= S3C_DxEPCTL_SetD0PID; |
| @@ -2563,7 +2610,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) | |||
| 2563 | 2610 | ||
| 2564 | writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk | | 2611 | writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk | |
| 2565 | S3C_DIEPMSK_INTknEPMisMsk | | 2612 | S3C_DIEPMSK_INTknEPMisMsk | |
| 2566 | S3C_DIEPMSK_EPDisbldMsk | S3C_DIEPMSK_XferComplMsk, | 2613 | S3C_DIEPMSK_EPDisbldMsk | S3C_DIEPMSK_XferComplMsk | |
| 2614 | ((hsotg->dedicated_fifos) ? S3C_DIEPMSK_TxFIFOEmpty : 0), | ||
| 2567 | hsotg->regs + S3C_DIEPMSK); | 2615 | hsotg->regs + S3C_DIEPMSK); |
| 2568 | 2616 | ||
| 2569 | /* don't need XferCompl, we get that from RXFIFO in slave mode. In | 2617 | /* don't need XferCompl, we get that from RXFIFO in slave mode. In |
| @@ -2732,7 +2780,7 @@ static void __devinit s3c_hsotg_initep(struct s3c_hsotg *hsotg, | |||
| 2732 | */ | 2780 | */ |
| 2733 | 2781 | ||
| 2734 | ptxfifo = readl(hsotg->regs + S3C_DPTXFSIZn(epnum)); | 2782 | ptxfifo = readl(hsotg->regs + S3C_DPTXFSIZn(epnum)); |
| 2735 | hs_ep->fifo_size = S3C_DPTXFSIZn_DPTxFSize_GET(ptxfifo); | 2783 | hs_ep->fifo_size = S3C_DPTXFSIZn_DPTxFSize_GET(ptxfifo) * 4; |
| 2736 | 2784 | ||
| 2737 | /* if we're using dma, we need to set the next-endpoint pointer | 2785 | /* if we're using dma, we need to set the next-endpoint pointer |
| 2738 | * to be something valid. | 2786 | * to be something valid. |
| @@ -2753,13 +2801,33 @@ static void __devinit s3c_hsotg_initep(struct s3c_hsotg *hsotg, | |||
| 2753 | */ | 2801 | */ |
| 2754 | static void s3c_hsotg_otgreset(struct s3c_hsotg *hsotg) | 2802 | static void s3c_hsotg_otgreset(struct s3c_hsotg *hsotg) |
| 2755 | { | 2803 | { |
| 2756 | u32 osc; | 2804 | struct clk *xusbxti; |
| 2805 | u32 pwr, osc; | ||
| 2757 | 2806 | ||
| 2758 | writel(0, S3C_PHYPWR); | 2807 | pwr = readl(S3C_PHYPWR); |
| 2808 | pwr &= ~0x19; | ||
| 2809 | writel(pwr, S3C_PHYPWR); | ||
| 2759 | mdelay(1); | 2810 | mdelay(1); |
| 2760 | 2811 | ||
| 2761 | osc = hsotg->plat->is_osc ? S3C_PHYCLK_EXT_OSC : 0; | 2812 | osc = hsotg->plat->is_osc ? S3C_PHYCLK_EXT_OSC : 0; |
| 2762 | 2813 | ||
| 2814 | xusbxti = clk_get(hsotg->dev, "xusbxti"); | ||
| 2815 | if (xusbxti && !IS_ERR(xusbxti)) { | ||
| 2816 | switch (clk_get_rate(xusbxti)) { | ||
| 2817 | case 12*MHZ: | ||
| 2818 | osc |= S3C_PHYCLK_CLKSEL_12M; | ||
| 2819 | break; | ||
| 2820 | case 24*MHZ: | ||
| 2821 | osc |= S3C_PHYCLK_CLKSEL_24M; | ||
| 2822 | break; | ||
| 2823 | default: | ||
| 2824 | case 48*MHZ: | ||
| 2825 | /* default reference clock */ | ||
| 2826 | break; | ||
| 2827 | } | ||
| 2828 | clk_put(xusbxti); | ||
| 2829 | } | ||
| 2830 | |||
| 2763 | writel(osc | 0x10, S3C_PHYCLK); | 2831 | writel(osc | 0x10, S3C_PHYCLK); |
| 2764 | 2832 | ||
| 2765 | /* issue a full set of resets to the otg and core */ | 2833 | /* issue a full set of resets to the otg and core */ |
| @@ -2772,6 +2840,8 @@ static void s3c_hsotg_otgreset(struct s3c_hsotg *hsotg) | |||
| 2772 | 2840 | ||
| 2773 | static void s3c_hsotg_init(struct s3c_hsotg *hsotg) | 2841 | static void s3c_hsotg_init(struct s3c_hsotg *hsotg) |
| 2774 | { | 2842 | { |
| 2843 | u32 cfg4; | ||
| 2844 | |||
| 2775 | /* unmask subset of endpoint interrupts */ | 2845 | /* unmask subset of endpoint interrupts */ |
| 2776 | 2846 | ||
| 2777 | writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk | | 2847 | writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk | |
| @@ -2807,6 +2877,14 @@ static void s3c_hsotg_init(struct s3c_hsotg *hsotg) | |||
| 2807 | 2877 | ||
| 2808 | writel(using_dma(hsotg) ? S3C_GAHBCFG_DMAEn : 0x0, | 2878 | writel(using_dma(hsotg) ? S3C_GAHBCFG_DMAEn : 0x0, |
| 2809 | hsotg->regs + S3C_GAHBCFG); | 2879 | hsotg->regs + S3C_GAHBCFG); |
| 2880 | |||
| 2881 | /* check hardware configuration */ | ||
| 2882 | |||
| 2883 | cfg4 = readl(hsotg->regs + 0x50); | ||
| 2884 | hsotg->dedicated_fifos = (cfg4 >> 25) & 1; | ||
| 2885 | |||
| 2886 | dev_info(hsotg->dev, "%s fifos\n", | ||
| 2887 | hsotg->dedicated_fifos ? "dedicated" : "shared"); | ||
| 2810 | } | 2888 | } |
| 2811 | 2889 | ||
| 2812 | static void s3c_hsotg_dump(struct s3c_hsotg *hsotg) | 2890 | static void s3c_hsotg_dump(struct s3c_hsotg *hsotg) |
| @@ -3181,13 +3259,20 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) | |||
| 3181 | hsotg->dev = dev; | 3259 | hsotg->dev = dev; |
| 3182 | hsotg->plat = plat; | 3260 | hsotg->plat = plat; |
| 3183 | 3261 | ||
| 3262 | hsotg->clk = clk_get(&pdev->dev, "otg"); | ||
| 3263 | if (IS_ERR(hsotg->clk)) { | ||
| 3264 | dev_err(dev, "cannot get otg clock\n"); | ||
| 3265 | ret = -EINVAL; | ||
| 3266 | goto err_mem; | ||
| 3267 | } | ||
| 3268 | |||
| 3184 | platform_set_drvdata(pdev, hsotg); | 3269 | platform_set_drvdata(pdev, hsotg); |
| 3185 | 3270 | ||
| 3186 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 3271 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 3187 | if (!res) { | 3272 | if (!res) { |
| 3188 | dev_err(dev, "cannot find register resource 0\n"); | 3273 | dev_err(dev, "cannot find register resource 0\n"); |
| 3189 | ret = -EINVAL; | 3274 | ret = -EINVAL; |
| 3190 | goto err_mem; | 3275 | goto err_clk; |
| 3191 | } | 3276 | } |
| 3192 | 3277 | ||
| 3193 | hsotg->regs_res = request_mem_region(res->start, resource_size(res), | 3278 | hsotg->regs_res = request_mem_region(res->start, resource_size(res), |
| @@ -3195,7 +3280,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) | |||
| 3195 | if (!hsotg->regs_res) { | 3280 | if (!hsotg->regs_res) { |
| 3196 | dev_err(dev, "cannot reserve registers\n"); | 3281 | dev_err(dev, "cannot reserve registers\n"); |
| 3197 | ret = -ENOENT; | 3282 | ret = -ENOENT; |
| 3198 | goto err_mem; | 3283 | goto err_clk; |
| 3199 | } | 3284 | } |
| 3200 | 3285 | ||
| 3201 | hsotg->regs = ioremap(res->start, resource_size(res)); | 3286 | hsotg->regs = ioremap(res->start, resource_size(res)); |
| @@ -3248,6 +3333,8 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) | |||
| 3248 | 3333 | ||
| 3249 | /* reset the system */ | 3334 | /* reset the system */ |
| 3250 | 3335 | ||
| 3336 | clk_enable(hsotg->clk); | ||
| 3337 | |||
| 3251 | s3c_hsotg_gate(pdev, true); | 3338 | s3c_hsotg_gate(pdev, true); |
| 3252 | 3339 | ||
| 3253 | s3c_hsotg_otgreset(hsotg); | 3340 | s3c_hsotg_otgreset(hsotg); |
| @@ -3271,7 +3358,8 @@ err_regs: | |||
| 3271 | err_regs_res: | 3358 | err_regs_res: |
| 3272 | release_resource(hsotg->regs_res); | 3359 | release_resource(hsotg->regs_res); |
| 3273 | kfree(hsotg->regs_res); | 3360 | kfree(hsotg->regs_res); |
| 3274 | 3361 | err_clk: | |
| 3362 | clk_put(hsotg->clk); | ||
| 3275 | err_mem: | 3363 | err_mem: |
| 3276 | kfree(hsotg); | 3364 | kfree(hsotg); |
| 3277 | return ret; | 3365 | return ret; |
| @@ -3293,6 +3381,9 @@ static int __devexit s3c_hsotg_remove(struct platform_device *pdev) | |||
| 3293 | 3381 | ||
| 3294 | s3c_hsotg_gate(pdev, false); | 3382 | s3c_hsotg_gate(pdev, false); |
| 3295 | 3383 | ||
| 3384 | clk_disable(hsotg->clk); | ||
| 3385 | clk_put(hsotg->clk); | ||
| 3386 | |||
| 3296 | kfree(hsotg); | 3387 | kfree(hsotg); |
| 3297 | return 0; | 3388 | return 0; |
| 3298 | } | 3389 | } |
