Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

i2c: sh_mobile: add DMA support

Make it possible to transfer i2c message buffers via DMA.
Start/Stop/Sending_Slave_Address is still handled using the old state
machine, it is sending the actual data that is done via DMA. This is
least intrusive and allows us to work with the message buffers directly
instead of preparing a custom buffer which involves copying the data
around.

Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
[wsa: fixed an uninitialized var problem]
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>

authored by

Wolfram Sang and committed by
Wolfram Sang
2d09581b 5bbe6879

+190 -10
+5
Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt
··· 19 19 20 20 Optional properties: 21 21 - clock-frequency : frequency of bus clock in Hz. Default 100kHz if unset. 22 + - dmas : Must contain a list of two references to DMA 23 + specifiers, one for transmission, and one for 24 + reception. 25 + - dma-names : Must contain a list of two DMA names, "tx" and "rx". 26 + 22 27 23 28 Pinctrl properties might be needed, too. See there. 24 29
+185 -10
drivers/i2c/busses/i2c-sh_mobile.c
··· 1 1 /* 2 2 * SuperH Mobile I2C Controller 3 3 * 4 + * Copyright (C) 2014 Wolfram Sang <wsa@sang-engineering.com> 5 + * 4 6 * Copyright (C) 2008 Magnus Damm 5 7 * 6 8 * Portions of the code based on out-of-tree driver i2c-sh7343.c ··· 20 18 21 19 #include <linux/clk.h> 22 20 #include <linux/delay.h> 21 + #include <linux/dmaengine.h> 22 + #include <linux/dma-mapping.h> 23 23 #include <linux/err.h> 24 24 #include <linux/i2c.h> 25 25 #include <linux/i2c/i2c-sh_mobile.h> ··· 114 110 OP_TX_FIRST, 115 111 OP_TX, 116 112 OP_TX_STOP, 113 + OP_TX_STOP_DATA, 117 114 OP_TX_TO_RX, 118 115 OP_RX, 119 116 OP_RX_STOP, ··· 139 134 int pos; 140 135 int sr; 141 136 bool send_stop; 137 + 138 + struct dma_chan *dma_tx; 139 + struct dma_chan *dma_rx; 140 + struct scatterlist sg; 141 + enum dma_data_direction dma_direction; 142 142 }; 143 143 144 144 struct sh_mobile_dt_config { ··· 181 171 182 172 #define ICIC_ICCLB8 0x80 183 173 #define ICIC_ICCHB8 0x40 174 + #define ICIC_TDMAE 0x20 175 + #define ICIC_RDMAE 0x10 184 176 #define ICIC_ALE 0x08 185 177 #define ICIC_TACKE 0x04 186 178 #define ICIC_WAITE 0x02 ··· 344 332 case OP_TX: /* write data */ 345 333 iic_wr(pd, ICDR, data); 346 334 break; 347 - case OP_TX_STOP: /* write data and issue a stop afterwards */ 335 + case OP_TX_STOP_DATA: /* write data and issue a stop afterwards */ 348 336 iic_wr(pd, ICDR, data); 337 + /* fallthrough */ 338 + case OP_TX_STOP: /* issue a stop */ 349 339 iic_wr(pd, ICCR, pd->send_stop ? ICCR_ICE | ICCR_TRS 350 340 : ICCR_ICE | ICCR_TRS | ICCR_BBSY); 351 341 break; ··· 403 389 { 404 390 unsigned char data; 405 391 406 - if (pd->pos == pd->msg->len) 392 + if (pd->pos == pd->msg->len) { 393 + /* Send stop if we haven't yet (DMA case) */ 394 + if (pd->send_stop && (iic_rd(pd, ICCR) & ICCR_BBSY)) 395 + i2c_op(pd, OP_TX_STOP, 0); 407 396 return 1; 397 + } 408 398 409 399 sh_mobile_i2c_get_data(pd, &data); 410 400 411 401 if (sh_mobile_i2c_is_last_byte(pd)) 412 - i2c_op(pd, OP_TX_STOP, data); 402 + i2c_op(pd, OP_TX_STOP_DATA, data); 413 403 else if (sh_mobile_i2c_is_first_byte(pd)) 414 404 i2c_op(pd, OP_TX_FIRST, data); 415 405 else ··· 468 450 struct platform_device *dev = dev_id; 469 451 struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev); 470 452 unsigned char sr; 471 - int wakeup; 453 + int wakeup = 0; 472 454 473 455 sr = iic_rd(pd, ICSR); 474 456 pd->sr |= sr; /* remember state */ ··· 477 459 (pd->msg->flags & I2C_M_RD) ? "read" : "write", 478 460 pd->pos, pd->msg->len); 479 461 480 - if (sr & (ICSR_AL | ICSR_TACK)) { 462 + /* Kick off TxDMA after preface was done */ 463 + if (pd->dma_direction == DMA_TO_DEVICE && pd->pos == 0) 464 + iic_set_clr(pd, ICIC, ICIC_TDMAE, 0); 465 + else if (sr & (ICSR_AL | ICSR_TACK)) 481 466 /* don't interrupt transaction - continue to issue stop */ 482 467 iic_wr(pd, ICSR, sr & ~(ICSR_AL | ICSR_TACK)); 483 - wakeup = 0; 484 - } else if (pd->msg->flags & I2C_M_RD) 468 + else if (pd->msg->flags & I2C_M_RD) 485 469 wakeup = sh_mobile_i2c_isr_rx(pd); 486 470 else 487 471 wakeup = sh_mobile_i2c_isr_tx(pd); 472 + 473 + /* Kick off RxDMA after preface was done */ 474 + if (pd->dma_direction == DMA_FROM_DEVICE && pd->pos == 1) 475 + iic_set_clr(pd, ICIC, ICIC_RDMAE, 0); 488 476 489 477 if (sr & ICSR_WAIT) /* TODO: add delay here to support slow acks */ 490 478 iic_wr(pd, ICSR, sr & ~ICSR_WAIT); ··· 504 480 iic_rd(pd, ICSR); 505 481 506 482 return IRQ_HANDLED; 483 + } 484 + 485 + static void sh_mobile_i2c_cleanup_dma(struct sh_mobile_i2c_data *pd) 486 + { 487 + if (pd->dma_direction == DMA_NONE) 488 + return; 489 + else if (pd->dma_direction == DMA_FROM_DEVICE) 490 + dmaengine_terminate_all(pd->dma_rx); 491 + else if (pd->dma_direction == DMA_TO_DEVICE) 492 + dmaengine_terminate_all(pd->dma_tx); 493 + 494 + dma_unmap_single(pd->dev, sg_dma_address(&pd->sg), 495 + pd->msg->len, pd->dma_direction); 496 + 497 + pd->dma_direction = DMA_NONE; 498 + } 499 + 500 + static void sh_mobile_i2c_dma_callback(void *data) 501 + { 502 + struct sh_mobile_i2c_data *pd = data; 503 + 504 + dma_unmap_single(pd->dev, sg_dma_address(&pd->sg), 505 + pd->msg->len, pd->dma_direction); 506 + 507 + pd->dma_direction = DMA_NONE; 508 + pd->pos = pd->msg->len; 509 + 510 + iic_set_clr(pd, ICIC, 0, ICIC_TDMAE | ICIC_RDMAE); 511 + } 512 + 513 + static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd) 514 + { 515 + bool read = pd->msg->flags & I2C_M_RD; 516 + enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE; 517 + struct dma_chan *chan = read ? pd->dma_rx : pd->dma_tx; 518 + struct dma_async_tx_descriptor *txdesc; 519 + dma_addr_t dma_addr; 520 + dma_cookie_t cookie; 521 + 522 + if (!chan) 523 + return; 524 + 525 + dma_addr = dma_map_single(pd->dev, pd->msg->buf, pd->msg->len, dir); 526 + if (dma_mapping_error(pd->dev, dma_addr)) { 527 + dev_dbg(pd->dev, "dma map failed, using PIO\n"); 528 + return; 529 + } 530 + 531 + sg_dma_len(&pd->sg) = pd->msg->len; 532 + sg_dma_address(&pd->sg) = dma_addr; 533 + 534 + pd->dma_direction = dir; 535 + 536 + txdesc = dmaengine_prep_slave_sg(chan, &pd->sg, 1, 537 + read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV, 538 + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 539 + if (!txdesc) { 540 + dev_dbg(pd->dev, "dma prep slave sg failed, using PIO\n"); 541 + sh_mobile_i2c_cleanup_dma(pd); 542 + return; 543 + } 544 + 545 + txdesc->callback = sh_mobile_i2c_dma_callback; 546 + txdesc->callback_param = pd; 547 + 548 + cookie = dmaengine_submit(txdesc); 549 + if (dma_submit_error(cookie)) { 550 + dev_dbg(pd->dev, "submitting dma failed, using PIO\n"); 551 + sh_mobile_i2c_cleanup_dma(pd); 552 + return; 553 + } 554 + 555 + dma_async_issue_pending(chan); 507 556 } 508 557 509 558 static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg, ··· 602 505 pd->msg = usr_msg; 603 506 pd->pos = -1; 604 507 pd->sr = 0; 508 + 509 + if (pd->msg->len > 8) 510 + sh_mobile_i2c_xfer_dma(pd); 605 511 606 512 /* Enable all interrupts to begin with */ 607 513 iic_wr(pd, ICIC, ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE); ··· 689 589 5 * HZ); 690 590 if (!k) { 691 591 dev_err(pd->dev, "Transfer request timed out\n"); 592 + if (pd->dma_direction != DMA_NONE) 593 + sh_mobile_i2c_cleanup_dma(pd); 594 + 692 595 err = -ETIMEDOUT; 693 596 break; 694 597 } ··· 741 638 {}, 742 639 }; 743 640 MODULE_DEVICE_TABLE(of, sh_mobile_i2c_dt_ids); 641 + 642 + static int sh_mobile_i2c_request_dma_chan(struct device *dev, enum dma_transfer_direction dir, 643 + dma_addr_t port_addr, struct dma_chan **chan_ptr) 644 + { 645 + dma_cap_mask_t mask; 646 + struct dma_chan *chan; 647 + struct dma_slave_config cfg; 648 + char *chan_name = dir == DMA_MEM_TO_DEV ? "tx" : "rx"; 649 + int ret; 650 + 651 + dma_cap_zero(mask); 652 + dma_cap_set(DMA_SLAVE, mask); 653 + *chan_ptr = NULL; 654 + 655 + chan = dma_request_slave_channel_reason(dev, chan_name); 656 + if (IS_ERR(chan)) { 657 + ret = PTR_ERR(chan); 658 + dev_dbg(dev, "request_channel failed for %s (%d)\n", chan_name, ret); 659 + return ret; 660 + } 661 + 662 + memset(&cfg, 0, sizeof(cfg)); 663 + cfg.direction = dir; 664 + if (dir == DMA_MEM_TO_DEV) { 665 + cfg.dst_addr = port_addr; 666 + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; 667 + } else { 668 + cfg.src_addr = port_addr; 669 + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; 670 + } 671 + 672 + ret = dmaengine_slave_config(chan, &cfg); 673 + if (ret) { 674 + dev_dbg(dev, "slave_config failed for %s (%d)\n", chan_name, ret); 675 + dma_release_channel(chan); 676 + return ret; 677 + } 678 + 679 + *chan_ptr = chan; 680 + 681 + dev_dbg(dev, "got DMA channel for %s\n", chan_name); 682 + return 0; 683 + } 684 + 685 + static void sh_mobile_i2c_release_dma(struct sh_mobile_i2c_data *pd) 686 + { 687 + if (pd->dma_tx) { 688 + dma_release_channel(pd->dma_tx); 689 + pd->dma_tx = NULL; 690 + } 691 + 692 + if (pd->dma_rx) { 693 + dma_release_channel(pd->dma_rx); 694 + pd->dma_rx = NULL; 695 + } 696 + } 744 697 745 698 static int sh_mobile_i2c_hook_irqs(struct platform_device *dev) 746 699 { ··· 884 725 if (ret) 885 726 return ret; 886 727 728 + /* Init DMA */ 729 + sg_init_table(&pd->sg, 1); 730 + pd->dma_direction = DMA_NONE; 731 + ret = sh_mobile_i2c_request_dma_chan(pd->dev, DMA_DEV_TO_MEM, 732 + res->start + ICDR, &pd->dma_rx); 733 + if (ret == -EPROBE_DEFER) 734 + return ret; 735 + 736 + ret = sh_mobile_i2c_request_dma_chan(pd->dev, DMA_MEM_TO_DEV, 737 + res->start + ICDR, &pd->dma_tx); 738 + if (ret == -EPROBE_DEFER) { 739 + sh_mobile_i2c_release_dma(pd); 740 + return ret; 741 + } 742 + 887 743 /* Enable Runtime PM for this device. 888 744 * 889 745 * Also tell the Runtime PM core to ignore children ··· 930 756 931 757 ret = i2c_add_numbered_adapter(adap); 932 758 if (ret < 0) { 759 + sh_mobile_i2c_release_dma(pd); 933 760 dev_err(&dev->dev, "cannot add numbered adapter\n"); 934 761 return ret; 935 762 } ··· 947 772 struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev); 948 773 949 774 i2c_del_adapter(&pd->adap); 775 + sh_mobile_i2c_release_dma(pd); 950 776 pm_runtime_disable(&dev->dev); 951 777 return 0; 952 778 } ··· 984 808 { 985 809 return platform_driver_register(&sh_mobile_i2c_driver); 986 810 } 811 + subsys_initcall(sh_mobile_i2c_adap_init); 987 812 988 813 static void __exit sh_mobile_i2c_adap_exit(void) 989 814 { 990 815 platform_driver_unregister(&sh_mobile_i2c_driver); 991 816 } 992 - 993 - subsys_initcall(sh_mobile_i2c_adap_init); 994 817 module_exit(sh_mobile_i2c_adap_exit); 995 818 996 819 MODULE_DESCRIPTION("SuperH Mobile I2C Bus Controller driver"); 997 - MODULE_AUTHOR("Magnus Damm"); 820 + MODULE_AUTHOR("Magnus Damm and Wolfram Sang"); 998 821 MODULE_LICENSE("GPL v2"); 999 822 MODULE_ALIAS("platform:i2c-sh_mobile");