| .. | .. |
|---|
| 15 | 15 | #include <linux/kernel.h> |
|---|
| 16 | 16 | #include <linux/slab.h> |
|---|
| 17 | 17 | #include <linux/pm_runtime.h> |
|---|
| 18 | +#include <linux/pinctrl/consumer.h> |
|---|
| 18 | 19 | #include <linux/usb/ch9.h> |
|---|
| 19 | 20 | #include <linux/usb/gadget.h> |
|---|
| 20 | 21 | #include <linux/usb/otg-fsm.h> |
|---|
| .. | .. |
|---|
| 71 | 72 | |
|---|
| 72 | 73 | /** |
|---|
| 73 | 74 | * hw_device_state: enables/disables interrupts (execute without interruption) |
|---|
| 75 | + * @ci: the controller |
|---|
| 74 | 76 | * @dma: 0 => disable, !0 => enable and set dma engine |
|---|
| 75 | 77 | * |
|---|
| 76 | 78 | * This function returns an error code |
|---|
| .. | .. |
|---|
| 90 | 92 | |
|---|
| 91 | 93 | /** |
|---|
| 92 | 94 | * hw_ep_flush: flush endpoint fifo (execute without interruption) |
|---|
| 95 | + * @ci: the controller |
|---|
| 93 | 96 | * @num: endpoint number |
|---|
| 94 | 97 | * @dir: endpoint direction |
|---|
| 95 | 98 | * |
|---|
| .. | .. |
|---|
| 111 | 114 | |
|---|
| 112 | 115 | /** |
|---|
| 113 | 116 | * hw_ep_disable: disables endpoint (execute without interruption) |
|---|
| 117 | + * @ci: the controller |
|---|
| 114 | 118 | * @num: endpoint number |
|---|
| 115 | 119 | * @dir: endpoint direction |
|---|
| 116 | 120 | * |
|---|
| .. | .. |
|---|
| 125 | 129 | |
|---|
| 126 | 130 | /** |
|---|
| 127 | 131 | * hw_ep_enable: enables endpoint (execute without interruption) |
|---|
| 132 | + * @ci: the controller |
|---|
| 128 | 133 | * @num: endpoint number |
|---|
| 129 | 134 | * @dir: endpoint direction |
|---|
| 130 | 135 | * @type: endpoint type |
|---|
| .. | .. |
|---|
| 160 | 165 | |
|---|
| 161 | 166 | /** |
|---|
| 162 | 167 | * hw_ep_get_halt: return endpoint halt status |
|---|
| 168 | + * @ci: the controller |
|---|
| 163 | 169 | * @num: endpoint number |
|---|
| 164 | 170 | * @dir: endpoint direction |
|---|
| 165 | 171 | * |
|---|
| .. | .. |
|---|
| 174 | 180 | |
|---|
| 175 | 181 | /** |
|---|
| 176 | 182 | * hw_ep_prime: primes endpoint (execute without interruption) |
|---|
| 183 | + * @ci: the controller |
|---|
| 177 | 184 | * @num: endpoint number |
|---|
| 178 | 185 | * @dir: endpoint direction |
|---|
| 179 | 186 | * @is_ctrl: true if control endpoint |
|---|
| .. | .. |
|---|
| 204 | 211 | /** |
|---|
| 205 | 212 | * hw_ep_set_halt: configures ep halt & resets data toggle after clear (execute |
|---|
| 206 | 213 | * without interruption) |
|---|
| 214 | + * @ci: the controller |
|---|
| 207 | 215 | * @num: endpoint number |
|---|
| 208 | 216 | * @dir: endpoint direction |
|---|
| 209 | 217 | * @value: true => stall, false => unstall |
|---|
| .. | .. |
|---|
| 230 | 238 | |
|---|
| 231 | 239 | /** |
|---|
| 232 | 240 | * hw_is_port_high_speed: test if port is high speed |
|---|
| 241 | + * @ci: the controller |
|---|
| 233 | 242 | * |
|---|
| 234 | 243 | * This function returns true if high speed port |
|---|
| 235 | 244 | */ |
|---|
| .. | .. |
|---|
| 242 | 251 | /** |
|---|
| 243 | 252 | * hw_test_and_clear_complete: test & clear complete status (execute without |
|---|
| 244 | 253 | * interruption) |
|---|
| 254 | + * @ci: the controller |
|---|
| 245 | 255 | * @n: endpoint number |
|---|
| 246 | 256 | * |
|---|
| 247 | 257 | * This function returns complete status |
|---|
| .. | .. |
|---|
| 255 | 265 | /** |
|---|
| 256 | 266 | * hw_test_and_clear_intr_active: test & clear active interrupts (execute |
|---|
| 257 | 267 | * without interruption) |
|---|
| 268 | + * @ci: the controller |
|---|
| 258 | 269 | * |
|---|
| 259 | 270 | * This function returns active interrutps |
|---|
| 260 | 271 | */ |
|---|
| .. | .. |
|---|
| 269 | 280 | /** |
|---|
| 270 | 281 | * hw_test_and_clear_setup_guard: test & clear setup guard (execute without |
|---|
| 271 | 282 | * interruption) |
|---|
| 283 | + * @ci: the controller |
|---|
| 272 | 284 | * |
|---|
| 273 | 285 | * This function returns guard value |
|---|
| 274 | 286 | */ |
|---|
| .. | .. |
|---|
| 280 | 292 | /** |
|---|
| 281 | 293 | * hw_test_and_set_setup_guard: test & set setup guard (execute without |
|---|
| 282 | 294 | * interruption) |
|---|
| 295 | + * @ci: the controller |
|---|
| 283 | 296 | * |
|---|
| 284 | 297 | * This function returns guard value |
|---|
| 285 | 298 | */ |
|---|
| .. | .. |
|---|
| 290 | 303 | |
|---|
| 291 | 304 | /** |
|---|
| 292 | 305 | * hw_usb_set_address: configures USB address (execute without interruption) |
|---|
| 306 | + * @ci: the controller |
|---|
| 293 | 307 | * @value: new USB address |
|---|
| 294 | 308 | * |
|---|
| 295 | 309 | * This function explicitly sets the address, without the "USBADRA" (advance) |
|---|
| .. | .. |
|---|
| 304 | 318 | /** |
|---|
| 305 | 319 | * hw_usb_reset: restart device after a bus reset (execute without |
|---|
| 306 | 320 | * interruption) |
|---|
| 321 | + * @ci: the controller |
|---|
| 307 | 322 | * |
|---|
| 308 | 323 | * This function returns an error code |
|---|
| 309 | 324 | */ |
|---|
| .. | .. |
|---|
| 337 | 352 | *****************************************************************************/ |
|---|
| 338 | 353 | |
|---|
| 339 | 354 | static int add_td_to_list(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq, |
|---|
| 340 | | - unsigned length) |
|---|
| 355 | + unsigned int length, struct scatterlist *s) |
|---|
| 341 | 356 | { |
|---|
| 342 | 357 | int i; |
|---|
| 343 | 358 | u32 temp; |
|---|
| .. | .. |
|---|
| 365 | 380 | node->ptr->token |= cpu_to_le32(mul << __ffs(TD_MULTO)); |
|---|
| 366 | 381 | } |
|---|
| 367 | 382 | |
|---|
| 368 | | - temp = (u32) (hwreq->req.dma + hwreq->req.actual); |
|---|
| 383 | + if (s) { |
|---|
| 384 | + temp = (u32) (sg_dma_address(s) + hwreq->req.actual); |
|---|
| 385 | + node->td_remaining_size = CI_MAX_BUF_SIZE - length; |
|---|
| 386 | + } else { |
|---|
| 387 | + temp = (u32) (hwreq->req.dma + hwreq->req.actual); |
|---|
| 388 | + } |
|---|
| 389 | + |
|---|
| 369 | 390 | if (length) { |
|---|
| 370 | 391 | node->ptr->page[0] = cpu_to_le32(temp); |
|---|
| 371 | 392 | for (i = 1; i < TD_PAGE_COUNT; i++) { |
|---|
| .. | .. |
|---|
| 399 | 420 | return ((ep->dir == TX) ? USB_ENDPOINT_DIR_MASK : 0) | ep->num; |
|---|
| 400 | 421 | } |
|---|
| 401 | 422 | |
|---|
| 423 | +static int prepare_td_for_non_sg(struct ci_hw_ep *hwep, |
|---|
| 424 | + struct ci_hw_req *hwreq) |
|---|
| 425 | +{ |
|---|
| 426 | + unsigned int rest = hwreq->req.length; |
|---|
| 427 | + int pages = TD_PAGE_COUNT; |
|---|
| 428 | + int ret = 0; |
|---|
| 429 | + |
|---|
| 430 | + if (rest == 0) { |
|---|
| 431 | + ret = add_td_to_list(hwep, hwreq, 0, NULL); |
|---|
| 432 | + if (ret < 0) |
|---|
| 433 | + return ret; |
|---|
| 434 | + } |
|---|
| 435 | + |
|---|
| 436 | + /* |
|---|
| 437 | + * The first buffer could be not page aligned. |
|---|
| 438 | + * In that case we have to span into one extra td. |
|---|
| 439 | + */ |
|---|
| 440 | + if (hwreq->req.dma % PAGE_SIZE) |
|---|
| 441 | + pages--; |
|---|
| 442 | + |
|---|
| 443 | + while (rest > 0) { |
|---|
| 444 | + unsigned int count = min(hwreq->req.length - hwreq->req.actual, |
|---|
| 445 | + (unsigned int)(pages * CI_HDRC_PAGE_SIZE)); |
|---|
| 446 | + |
|---|
| 447 | + ret = add_td_to_list(hwep, hwreq, count, NULL); |
|---|
| 448 | + if (ret < 0) |
|---|
| 449 | + return ret; |
|---|
| 450 | + |
|---|
| 451 | + rest -= count; |
|---|
| 452 | + } |
|---|
| 453 | + |
|---|
| 454 | + if (hwreq->req.zero && hwreq->req.length && hwep->dir == TX |
|---|
| 455 | + && (hwreq->req.length % hwep->ep.maxpacket == 0)) { |
|---|
| 456 | + ret = add_td_to_list(hwep, hwreq, 0, NULL); |
|---|
| 457 | + if (ret < 0) |
|---|
| 458 | + return ret; |
|---|
| 459 | + } |
|---|
| 460 | + |
|---|
| 461 | + return ret; |
|---|
| 462 | +} |
|---|
| 463 | + |
|---|
| 464 | +static int prepare_td_per_sg(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq, |
|---|
| 465 | + struct scatterlist *s) |
|---|
| 466 | +{ |
|---|
| 467 | + unsigned int rest = sg_dma_len(s); |
|---|
| 468 | + int ret = 0; |
|---|
| 469 | + |
|---|
| 470 | + hwreq->req.actual = 0; |
|---|
| 471 | + while (rest > 0) { |
|---|
| 472 | + unsigned int count = min_t(unsigned int, rest, |
|---|
| 473 | + CI_MAX_BUF_SIZE); |
|---|
| 474 | + |
|---|
| 475 | + ret = add_td_to_list(hwep, hwreq, count, s); |
|---|
| 476 | + if (ret < 0) |
|---|
| 477 | + return ret; |
|---|
| 478 | + |
|---|
| 479 | + rest -= count; |
|---|
| 480 | + } |
|---|
| 481 | + |
|---|
| 482 | + return ret; |
|---|
| 483 | +} |
|---|
| 484 | + |
|---|
| 485 | +static void ci_add_buffer_entry(struct td_node *node, struct scatterlist *s) |
|---|
| 486 | +{ |
|---|
| 487 | + int empty_td_slot_index = (CI_MAX_BUF_SIZE - node->td_remaining_size) |
|---|
| 488 | + / CI_HDRC_PAGE_SIZE; |
|---|
| 489 | + int i; |
|---|
| 490 | + u32 token; |
|---|
| 491 | + |
|---|
| 492 | + token = le32_to_cpu(node->ptr->token) + (sg_dma_len(s) << __ffs(TD_TOTAL_BYTES)); |
|---|
| 493 | + node->ptr->token = cpu_to_le32(token); |
|---|
| 494 | + |
|---|
| 495 | + for (i = empty_td_slot_index; i < TD_PAGE_COUNT; i++) { |
|---|
| 496 | + u32 page = (u32) sg_dma_address(s) + |
|---|
| 497 | + (i - empty_td_slot_index) * CI_HDRC_PAGE_SIZE; |
|---|
| 498 | + |
|---|
| 499 | + page &= ~TD_RESERVED_MASK; |
|---|
| 500 | + node->ptr->page[i] = cpu_to_le32(page); |
|---|
| 501 | + } |
|---|
| 502 | +} |
|---|
| 503 | + |
|---|
| 504 | +static int prepare_td_for_sg(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq) |
|---|
| 505 | +{ |
|---|
| 506 | + struct usb_request *req = &hwreq->req; |
|---|
| 507 | + struct scatterlist *s = req->sg; |
|---|
| 508 | + int ret = 0, i = 0; |
|---|
| 509 | + struct td_node *node = NULL; |
|---|
| 510 | + |
|---|
| 511 | + if (!s || req->zero || req->length == 0) { |
|---|
| 512 | + dev_err(hwep->ci->dev, "not supported operation for sg\n"); |
|---|
| 513 | + return -EINVAL; |
|---|
| 514 | + } |
|---|
| 515 | + |
|---|
| 516 | + while (i++ < req->num_mapped_sgs) { |
|---|
| 517 | + if (sg_dma_address(s) % PAGE_SIZE) { |
|---|
| 518 | + dev_err(hwep->ci->dev, "not page aligned sg buffer\n"); |
|---|
| 519 | + return -EINVAL; |
|---|
| 520 | + } |
|---|
| 521 | + |
|---|
| 522 | + if (node && (node->td_remaining_size >= sg_dma_len(s))) { |
|---|
| 523 | + ci_add_buffer_entry(node, s); |
|---|
| 524 | + node->td_remaining_size -= sg_dma_len(s); |
|---|
| 525 | + } else { |
|---|
| 526 | + ret = prepare_td_per_sg(hwep, hwreq, s); |
|---|
| 527 | + if (ret) |
|---|
| 528 | + return ret; |
|---|
| 529 | + |
|---|
| 530 | + node = list_entry(hwreq->tds.prev, |
|---|
| 531 | + struct td_node, td); |
|---|
| 532 | + } |
|---|
| 533 | + |
|---|
| 534 | + s = sg_next(s); |
|---|
| 535 | + } |
|---|
| 536 | + |
|---|
| 537 | + return ret; |
|---|
| 538 | +} |
|---|
| 539 | + |
|---|
| 402 | 540 | /** |
|---|
| 403 | 541 | * _hardware_enqueue: configures a request at hardware level |
|---|
| 404 | 542 | * @hwep: endpoint |
|---|
| .. | .. |
|---|
| 410 | 548 | { |
|---|
| 411 | 549 | struct ci_hdrc *ci = hwep->ci; |
|---|
| 412 | 550 | int ret = 0; |
|---|
| 413 | | - unsigned rest = hwreq->req.length; |
|---|
| 414 | | - int pages = TD_PAGE_COUNT; |
|---|
| 415 | 551 | struct td_node *firstnode, *lastnode; |
|---|
| 416 | 552 | |
|---|
| 417 | 553 | /* don't queue twice */ |
|---|
| .. | .. |
|---|
| 425 | 561 | if (ret) |
|---|
| 426 | 562 | return ret; |
|---|
| 427 | 563 | |
|---|
| 428 | | - /* |
|---|
| 429 | | - * The first buffer could be not page aligned. |
|---|
| 430 | | - * In that case we have to span into one extra td. |
|---|
| 431 | | - */ |
|---|
| 432 | | - if (hwreq->req.dma % PAGE_SIZE) |
|---|
| 433 | | - pages--; |
|---|
| 564 | + if (hwreq->req.num_mapped_sgs) |
|---|
| 565 | + ret = prepare_td_for_sg(hwep, hwreq); |
|---|
| 566 | + else |
|---|
| 567 | + ret = prepare_td_for_non_sg(hwep, hwreq); |
|---|
| 434 | 568 | |
|---|
| 435 | | - if (rest == 0) { |
|---|
| 436 | | - ret = add_td_to_list(hwep, hwreq, 0); |
|---|
| 437 | | - if (ret < 0) |
|---|
| 438 | | - goto done; |
|---|
| 439 | | - } |
|---|
| 440 | | - |
|---|
| 441 | | - while (rest > 0) { |
|---|
| 442 | | - unsigned count = min(hwreq->req.length - hwreq->req.actual, |
|---|
| 443 | | - (unsigned)(pages * CI_HDRC_PAGE_SIZE)); |
|---|
| 444 | | - ret = add_td_to_list(hwep, hwreq, count); |
|---|
| 445 | | - if (ret < 0) |
|---|
| 446 | | - goto done; |
|---|
| 447 | | - |
|---|
| 448 | | - rest -= count; |
|---|
| 449 | | - } |
|---|
| 450 | | - |
|---|
| 451 | | - if (hwreq->req.zero && hwreq->req.length && hwep->dir == TX |
|---|
| 452 | | - && (hwreq->req.length % hwep->ep.maxpacket == 0)) { |
|---|
| 453 | | - ret = add_td_to_list(hwep, hwreq, 0); |
|---|
| 454 | | - if (ret < 0) |
|---|
| 455 | | - goto done; |
|---|
| 456 | | - } |
|---|
| 569 | + if (ret) |
|---|
| 570 | + return ret; |
|---|
| 457 | 571 | |
|---|
| 458 | 572 | firstnode = list_first_entry(&hwreq->tds, struct td_node, td); |
|---|
| 459 | 573 | |
|---|
| .. | .. |
|---|
| 511 | 625 | return ret; |
|---|
| 512 | 626 | } |
|---|
| 513 | 627 | |
|---|
| 514 | | -/* |
|---|
| 628 | +/** |
|---|
| 515 | 629 | * free_pending_td: remove a pending request for the endpoint |
|---|
| 516 | 630 | * @hwep: endpoint |
|---|
| 517 | 631 | */ |
|---|
| .. | .. |
|---|
| 537 | 651 | |
|---|
| 538 | 652 | /** |
|---|
| 539 | 653 | * _hardware_dequeue: handles a request at hardware level |
|---|
| 540 | | - * @gadget: gadget |
|---|
| 541 | | - * @hwep: endpoint |
|---|
| 654 | + * @hwep: endpoint |
|---|
| 655 | + * @hwreq: request |
|---|
| 542 | 656 | * |
|---|
| 543 | 657 | * This function returns an error code |
|---|
| 544 | 658 | */ |
|---|
| .. | .. |
|---|
| 920 | 1034 | struct ci_hdrc *ci = req->context; |
|---|
| 921 | 1035 | unsigned long flags; |
|---|
| 922 | 1036 | |
|---|
| 1037 | + if (req->status < 0) |
|---|
| 1038 | + return; |
|---|
| 1039 | + |
|---|
| 923 | 1040 | if (ci->setaddr) { |
|---|
| 924 | 1041 | hw_usb_set_address(ci, ci->address); |
|---|
| 925 | 1042 | ci->setaddr = false; |
|---|
| .. | .. |
|---|
| 1116 | 1233 | case USB_DEVICE_TEST_MODE: |
|---|
| 1117 | 1234 | tmode = le16_to_cpu(req.wIndex) >> 8; |
|---|
| 1118 | 1235 | switch (tmode) { |
|---|
| 1119 | | - case TEST_J: |
|---|
| 1120 | | - case TEST_K: |
|---|
| 1121 | | - case TEST_SE0_NAK: |
|---|
| 1122 | | - case TEST_PACKET: |
|---|
| 1123 | | - case TEST_FORCE_EN: |
|---|
| 1236 | + case USB_TEST_J: |
|---|
| 1237 | + case USB_TEST_K: |
|---|
| 1238 | + case USB_TEST_SE0_NAK: |
|---|
| 1239 | + case USB_TEST_PACKET: |
|---|
| 1240 | + case USB_TEST_FORCE_ENABLE: |
|---|
| 1124 | 1241 | ci->test_mode = tmode; |
|---|
| 1125 | 1242 | err = isr_setup_status_phase( |
|---|
| 1126 | 1243 | ci); |
|---|
| .. | .. |
|---|
| 1217 | 1334 | /****************************************************************************** |
|---|
| 1218 | 1335 | * ENDPT block |
|---|
| 1219 | 1336 | *****************************************************************************/ |
|---|
| 1220 | | -/** |
|---|
| 1337 | +/* |
|---|
| 1221 | 1338 | * ep_enable: configure endpoint, making it usable |
|---|
| 1222 | 1339 | * |
|---|
| 1223 | 1340 | * Check usb_ep_enable() at "usb_gadget.h" for details |
|---|
| .. | .. |
|---|
| 1285 | 1402 | return retval; |
|---|
| 1286 | 1403 | } |
|---|
| 1287 | 1404 | |
|---|
| 1288 | | -/** |
|---|
| 1405 | +/* |
|---|
| 1289 | 1406 | * ep_disable: endpoint is no longer usable |
|---|
| 1290 | 1407 | * |
|---|
| 1291 | 1408 | * Check usb_ep_disable() at "usb_gadget.h" for details |
|---|
| .. | .. |
|---|
| 1325 | 1442 | return retval; |
|---|
| 1326 | 1443 | } |
|---|
| 1327 | 1444 | |
|---|
| 1328 | | -/** |
|---|
| 1445 | +/* |
|---|
| 1329 | 1446 | * ep_alloc_request: allocate a request object to use with this endpoint |
|---|
| 1330 | 1447 | * |
|---|
| 1331 | 1448 | * Check usb_ep_alloc_request() at "usb_gadget.h" for details |
|---|
| .. | .. |
|---|
| 1346 | 1463 | return (hwreq == NULL) ? NULL : &hwreq->req; |
|---|
| 1347 | 1464 | } |
|---|
| 1348 | 1465 | |
|---|
| 1349 | | -/** |
|---|
| 1466 | +/* |
|---|
| 1350 | 1467 | * ep_free_request: frees a request object |
|---|
| 1351 | 1468 | * |
|---|
| 1352 | 1469 | * Check usb_ep_free_request() at "usb_gadget.h" for details |
|---|
| .. | .. |
|---|
| 1379 | 1496 | spin_unlock_irqrestore(hwep->lock, flags); |
|---|
| 1380 | 1497 | } |
|---|
| 1381 | 1498 | |
|---|
| 1382 | | -/** |
|---|
| 1499 | +/* |
|---|
| 1383 | 1500 | * ep_queue: queues (submits) an I/O request to an endpoint |
|---|
| 1384 | 1501 | * |
|---|
| 1385 | 1502 | * Check usb_ep_queue()* at usb_gadget.h" for details |
|---|
| .. | .. |
|---|
| 1404 | 1521 | return retval; |
|---|
| 1405 | 1522 | } |
|---|
| 1406 | 1523 | |
|---|
| 1407 | | -/** |
|---|
| 1524 | +/* |
|---|
| 1408 | 1525 | * ep_dequeue: dequeues (cancels, unlinks) an I/O request from an endpoint |
|---|
| 1409 | 1526 | * |
|---|
| 1410 | 1527 | * Check usb_ep_dequeue() at "usb_gadget.h" for details |
|---|
| .. | .. |
|---|
| 1448 | 1565 | return 0; |
|---|
| 1449 | 1566 | } |
|---|
| 1450 | 1567 | |
|---|
| 1451 | | -/** |
|---|
| 1568 | +/* |
|---|
| 1452 | 1569 | * ep_set_halt: sets the endpoint halt feature |
|---|
| 1453 | 1570 | * |
|---|
| 1454 | 1571 | * Check usb_ep_set_halt() at "usb_gadget.h" for details |
|---|
| .. | .. |
|---|
| 1458 | 1575 | return _ep_set_halt(ep, value, true); |
|---|
| 1459 | 1576 | } |
|---|
| 1460 | 1577 | |
|---|
| 1461 | | -/** |
|---|
| 1578 | +/* |
|---|
| 1462 | 1579 | * ep_set_wedge: sets the halt feature and ignores clear requests |
|---|
| 1463 | 1580 | * |
|---|
| 1464 | 1581 | * Check usb_ep_set_wedge() at "usb_gadget.h" for details |
|---|
| .. | .. |
|---|
| 1478 | 1595 | return usb_ep_set_halt(ep); |
|---|
| 1479 | 1596 | } |
|---|
| 1480 | 1597 | |
|---|
| 1481 | | -/** |
|---|
| 1598 | +/* |
|---|
| 1482 | 1599 | * ep_fifo_flush: flushes contents of a fifo |
|---|
| 1483 | 1600 | * |
|---|
| 1484 | 1601 | * Check usb_ep_fifo_flush() at "usb_gadget.h" for details |
|---|
| .. | .. |
|---|
| 1504 | 1621 | spin_unlock_irqrestore(hwep->lock, flags); |
|---|
| 1505 | 1622 | } |
|---|
| 1506 | 1623 | |
|---|
| 1507 | | -/** |
|---|
| 1624 | +/* |
|---|
| 1508 | 1625 | * Endpoint-specific part of the API to the USB controller hardware |
|---|
| 1509 | 1626 | * Check "usb_gadget.h" for details |
|---|
| 1510 | 1627 | */ |
|---|
| .. | .. |
|---|
| 1523 | 1640 | /****************************************************************************** |
|---|
| 1524 | 1641 | * GADGET block |
|---|
| 1525 | 1642 | *****************************************************************************/ |
|---|
| 1643 | +/* |
|---|
| 1644 | + * ci_hdrc_gadget_connect: caller makes sure gadget driver is binded |
|---|
| 1645 | + */ |
|---|
| 1646 | +static void ci_hdrc_gadget_connect(struct usb_gadget *_gadget, int is_active) |
|---|
| 1647 | +{ |
|---|
| 1648 | + struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget); |
|---|
| 1649 | + |
|---|
| 1650 | + if (is_active) { |
|---|
| 1651 | + pm_runtime_get_sync(ci->dev); |
|---|
| 1652 | + hw_device_reset(ci); |
|---|
| 1653 | + spin_lock_irq(&ci->lock); |
|---|
| 1654 | + if (ci->driver) { |
|---|
| 1655 | + hw_device_state(ci, ci->ep0out->qh.dma); |
|---|
| 1656 | + usb_gadget_set_state(_gadget, USB_STATE_POWERED); |
|---|
| 1657 | + spin_unlock_irq(&ci->lock); |
|---|
| 1658 | + usb_udc_vbus_handler(_gadget, true); |
|---|
| 1659 | + } else { |
|---|
| 1660 | + spin_unlock_irq(&ci->lock); |
|---|
| 1661 | + } |
|---|
| 1662 | + } else { |
|---|
| 1663 | + usb_udc_vbus_handler(_gadget, false); |
|---|
| 1664 | + if (ci->driver) |
|---|
| 1665 | + ci->driver->disconnect(&ci->gadget); |
|---|
| 1666 | + hw_device_state(ci, 0); |
|---|
| 1667 | + if (ci->platdata->notify_event) |
|---|
| 1668 | + ci->platdata->notify_event(ci, |
|---|
| 1669 | + CI_HDRC_CONTROLLER_STOPPED_EVENT); |
|---|
| 1670 | + _gadget_stop_activity(&ci->gadget); |
|---|
| 1671 | + pm_runtime_put_sync(ci->dev); |
|---|
| 1672 | + usb_gadget_set_state(_gadget, USB_STATE_NOTATTACHED); |
|---|
| 1673 | + } |
|---|
| 1674 | +} |
|---|
| 1675 | + |
|---|
| 1526 | 1676 | static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active) |
|---|
| 1527 | 1677 | { |
|---|
| 1528 | 1678 | struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget); |
|---|
| 1529 | 1679 | unsigned long flags; |
|---|
| 1530 | | - int gadget_ready = 0; |
|---|
| 1680 | + int ret = 0; |
|---|
| 1531 | 1681 | |
|---|
| 1532 | 1682 | spin_lock_irqsave(&ci->lock, flags); |
|---|
| 1533 | 1683 | ci->vbus_active = is_active; |
|---|
| 1534 | | - if (ci->driver) |
|---|
| 1535 | | - gadget_ready = 1; |
|---|
| 1536 | 1684 | spin_unlock_irqrestore(&ci->lock, flags); |
|---|
| 1537 | 1685 | |
|---|
| 1538 | 1686 | if (ci->usb_phy) |
|---|
| 1539 | 1687 | usb_phy_set_charger_state(ci->usb_phy, is_active ? |
|---|
| 1540 | 1688 | USB_CHARGER_PRESENT : USB_CHARGER_ABSENT); |
|---|
| 1541 | 1689 | |
|---|
| 1542 | | - if (gadget_ready) { |
|---|
| 1543 | | - if (is_active) { |
|---|
| 1544 | | - pm_runtime_get_sync(&_gadget->dev); |
|---|
| 1545 | | - hw_device_reset(ci); |
|---|
| 1546 | | - hw_device_state(ci, ci->ep0out->qh.dma); |
|---|
| 1547 | | - usb_gadget_set_state(_gadget, USB_STATE_POWERED); |
|---|
| 1548 | | - usb_udc_vbus_handler(_gadget, true); |
|---|
| 1549 | | - } else { |
|---|
| 1550 | | - usb_udc_vbus_handler(_gadget, false); |
|---|
| 1551 | | - if (ci->driver) |
|---|
| 1552 | | - ci->driver->disconnect(&ci->gadget); |
|---|
| 1553 | | - hw_device_state(ci, 0); |
|---|
| 1554 | | - if (ci->platdata->notify_event) |
|---|
| 1555 | | - ci->platdata->notify_event(ci, |
|---|
| 1556 | | - CI_HDRC_CONTROLLER_STOPPED_EVENT); |
|---|
| 1557 | | - _gadget_stop_activity(&ci->gadget); |
|---|
| 1558 | | - pm_runtime_put_sync(&_gadget->dev); |
|---|
| 1559 | | - usb_gadget_set_state(_gadget, USB_STATE_NOTATTACHED); |
|---|
| 1560 | | - } |
|---|
| 1561 | | - } |
|---|
| 1690 | + if (ci->platdata->notify_event) |
|---|
| 1691 | + ret = ci->platdata->notify_event(ci, |
|---|
| 1692 | + CI_HDRC_CONTROLLER_VBUS_EVENT); |
|---|
| 1562 | 1693 | |
|---|
| 1563 | | - return 0; |
|---|
| 1694 | + if (ci->driver) |
|---|
| 1695 | + ci_hdrc_gadget_connect(_gadget, is_active); |
|---|
| 1696 | + |
|---|
| 1697 | + return ret; |
|---|
| 1564 | 1698 | } |
|---|
| 1565 | 1699 | |
|---|
| 1566 | 1700 | static int ci_udc_wakeup(struct usb_gadget *_gadget) |
|---|
| .. | .. |
|---|
| 1611 | 1745 | } |
|---|
| 1612 | 1746 | |
|---|
| 1613 | 1747 | /* Change Data+ pullup status |
|---|
| 1614 | | - * this func is used by usb_gadget_connect/disconnet |
|---|
| 1748 | + * this func is used by usb_gadget_connect/disconnect |
|---|
| 1615 | 1749 | */ |
|---|
| 1616 | 1750 | static int ci_udc_pullup(struct usb_gadget *_gadget, int is_on) |
|---|
| 1617 | 1751 | { |
|---|
| .. | .. |
|---|
| 1624 | 1758 | if (ci_otg_is_fsm_mode(ci) || ci->role == CI_ROLE_HOST) |
|---|
| 1625 | 1759 | return 0; |
|---|
| 1626 | 1760 | |
|---|
| 1627 | | - pm_runtime_get_sync(&ci->gadget.dev); |
|---|
| 1761 | + pm_runtime_get_sync(ci->dev); |
|---|
| 1628 | 1762 | if (is_on) |
|---|
| 1629 | 1763 | hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS); |
|---|
| 1630 | 1764 | else |
|---|
| 1631 | 1765 | hw_write(ci, OP_USBCMD, USBCMD_RS, 0); |
|---|
| 1632 | | - pm_runtime_put_sync(&ci->gadget.dev); |
|---|
| 1766 | + pm_runtime_put_sync(ci->dev); |
|---|
| 1633 | 1767 | |
|---|
| 1634 | 1768 | return 0; |
|---|
| 1635 | 1769 | } |
|---|
| .. | .. |
|---|
| 1656 | 1790 | return NULL; |
|---|
| 1657 | 1791 | } |
|---|
| 1658 | 1792 | |
|---|
| 1659 | | -/** |
|---|
| 1793 | +/* |
|---|
| 1660 | 1794 | * Device operations part of the API to the USB controller hardware, |
|---|
| 1661 | 1795 | * which don't involve endpoints (or i/o) |
|---|
| 1662 | 1796 | * Check "usb_gadget.h" for details |
|---|
| .. | .. |
|---|
| 1761 | 1895 | struct usb_gadget_driver *driver) |
|---|
| 1762 | 1896 | { |
|---|
| 1763 | 1897 | struct ci_hdrc *ci = container_of(gadget, struct ci_hdrc, gadget); |
|---|
| 1764 | | - int retval = -ENOMEM; |
|---|
| 1898 | + int retval; |
|---|
| 1765 | 1899 | |
|---|
| 1766 | 1900 | if (driver->disconnect == NULL) |
|---|
| 1767 | 1901 | return -EINVAL; |
|---|
| 1768 | | - |
|---|
| 1769 | 1902 | |
|---|
| 1770 | 1903 | ci->ep0out->ep.desc = &ctrl_endpt_out_desc; |
|---|
| 1771 | 1904 | retval = usb_ep_enable(&ci->ep0out->ep); |
|---|
| .. | .. |
|---|
| 1785 | 1918 | return retval; |
|---|
| 1786 | 1919 | } |
|---|
| 1787 | 1920 | |
|---|
| 1788 | | - pm_runtime_get_sync(&ci->gadget.dev); |
|---|
| 1789 | | - if (ci->vbus_active) { |
|---|
| 1790 | | - hw_device_reset(ci); |
|---|
| 1791 | | - } else { |
|---|
| 1921 | + if (ci->vbus_active) |
|---|
| 1922 | + ci_hdrc_gadget_connect(gadget, 1); |
|---|
| 1923 | + else |
|---|
| 1792 | 1924 | usb_udc_vbus_handler(&ci->gadget, false); |
|---|
| 1793 | | - pm_runtime_put_sync(&ci->gadget.dev); |
|---|
| 1794 | | - return retval; |
|---|
| 1795 | | - } |
|---|
| 1796 | | - |
|---|
| 1797 | | - retval = hw_device_state(ci, ci->ep0out->qh.dma); |
|---|
| 1798 | | - if (retval) |
|---|
| 1799 | | - pm_runtime_put_sync(&ci->gadget.dev); |
|---|
| 1800 | 1925 | |
|---|
| 1801 | 1926 | return retval; |
|---|
| 1802 | 1927 | } |
|---|
| .. | .. |
|---|
| 1817 | 1942 | mutex_unlock(&ci->fsm.lock); |
|---|
| 1818 | 1943 | } |
|---|
| 1819 | 1944 | |
|---|
| 1820 | | -/** |
|---|
| 1945 | +/* |
|---|
| 1821 | 1946 | * ci_udc_stop: unregister a gadget driver |
|---|
| 1822 | 1947 | */ |
|---|
| 1823 | 1948 | static int ci_udc_stop(struct usb_gadget *gadget) |
|---|
| .. | .. |
|---|
| 1826 | 1951 | unsigned long flags; |
|---|
| 1827 | 1952 | |
|---|
| 1828 | 1953 | spin_lock_irqsave(&ci->lock, flags); |
|---|
| 1954 | + ci->driver = NULL; |
|---|
| 1829 | 1955 | |
|---|
| 1830 | 1956 | if (ci->vbus_active) { |
|---|
| 1831 | 1957 | hw_device_state(ci, 0); |
|---|
| .. | .. |
|---|
| 1835 | 1961 | CI_HDRC_CONTROLLER_STOPPED_EVENT); |
|---|
| 1836 | 1962 | _gadget_stop_activity(&ci->gadget); |
|---|
| 1837 | 1963 | spin_lock_irqsave(&ci->lock, flags); |
|---|
| 1838 | | - pm_runtime_put(&ci->gadget.dev); |
|---|
| 1964 | + pm_runtime_put(ci->dev); |
|---|
| 1839 | 1965 | } |
|---|
| 1840 | 1966 | |
|---|
| 1841 | | - ci->driver = NULL; |
|---|
| 1842 | 1967 | spin_unlock_irqrestore(&ci->lock, flags); |
|---|
| 1843 | 1968 | |
|---|
| 1844 | 1969 | ci_udc_stop_for_otg_fsm(ci); |
|---|
| .. | .. |
|---|
| 1848 | 1973 | /****************************************************************************** |
|---|
| 1849 | 1974 | * BUS block |
|---|
| 1850 | 1975 | *****************************************************************************/ |
|---|
| 1851 | | -/** |
|---|
| 1976 | +/* |
|---|
| 1852 | 1977 | * udc_irq: ci interrupt handler |
|---|
| 1853 | 1978 | * |
|---|
| 1854 | 1979 | * This function returns IRQ_HANDLED if the IRQ has been handled |
|---|
| .. | .. |
|---|
| 1932 | 2057 | ci->gadget.max_speed = USB_SPEED_HIGH; |
|---|
| 1933 | 2058 | ci->gadget.name = ci->platdata->name; |
|---|
| 1934 | 2059 | ci->gadget.otg_caps = otg_caps; |
|---|
| 2060 | + ci->gadget.sg_supported = 1; |
|---|
| 2061 | + ci->gadget.irq = ci->irq; |
|---|
| 1935 | 2062 | |
|---|
| 1936 | 2063 | if (ci->platdata->flags & CI_HDRC_REQUIRES_ALIGNED_DMA) |
|---|
| 1937 | 2064 | ci->gadget.quirk_avoids_skb_reserve = 1; |
|---|
| .. | .. |
|---|
| 1967 | 2094 | if (retval) |
|---|
| 1968 | 2095 | goto destroy_eps; |
|---|
| 1969 | 2096 | |
|---|
| 1970 | | - pm_runtime_no_callbacks(&ci->gadget.dev); |
|---|
| 1971 | | - pm_runtime_enable(&ci->gadget.dev); |
|---|
| 1972 | | - |
|---|
| 1973 | 2097 | return retval; |
|---|
| 1974 | 2098 | |
|---|
| 1975 | 2099 | destroy_eps: |
|---|
| .. | .. |
|---|
| 1981 | 2105 | return retval; |
|---|
| 1982 | 2106 | } |
|---|
| 1983 | 2107 | |
|---|
| 1984 | | -/** |
|---|
| 2108 | +/* |
|---|
| 1985 | 2109 | * ci_hdrc_gadget_destroy: parent remove must call this to remove UDC |
|---|
| 1986 | 2110 | * |
|---|
| 1987 | 2111 | * No interrupts active, the IRQ has been released |
|---|
| .. | .. |
|---|
| 2001 | 2125 | |
|---|
| 2002 | 2126 | static int udc_id_switch_for_device(struct ci_hdrc *ci) |
|---|
| 2003 | 2127 | { |
|---|
| 2128 | + if (ci->platdata->pins_device) |
|---|
| 2129 | + pinctrl_select_state(ci->platdata->pctl, |
|---|
| 2130 | + ci->platdata->pins_device); |
|---|
| 2131 | + |
|---|
| 2004 | 2132 | if (ci->is_otg) |
|---|
| 2005 | 2133 | /* Clear and enable BSV irq */ |
|---|
| 2006 | 2134 | hw_write_otgsc(ci, OTGSC_BSVIS | OTGSC_BSVIE, |
|---|
| .. | .. |
|---|
| 2019 | 2147 | hw_write_otgsc(ci, OTGSC_BSVIE | OTGSC_BSVIS, OTGSC_BSVIS); |
|---|
| 2020 | 2148 | |
|---|
| 2021 | 2149 | ci->vbus_active = 0; |
|---|
| 2150 | + |
|---|
| 2151 | + if (ci->platdata->pins_device && ci->platdata->pins_default) |
|---|
| 2152 | + pinctrl_select_state(ci->platdata->pctl, |
|---|
| 2153 | + ci->platdata->pins_default); |
|---|
| 2022 | 2154 | } |
|---|
| 2023 | 2155 | |
|---|
| 2024 | 2156 | /** |
|---|
| 2025 | 2157 | * ci_hdrc_gadget_init - initialize device related bits |
|---|
| 2026 | | - * ci: the controller |
|---|
| 2158 | + * @ci: the controller |
|---|
| 2027 | 2159 | * |
|---|
| 2028 | 2160 | * This function initializes the gadget, if the device is "device capable". |
|---|
| 2029 | 2161 | */ |
|---|