.. | .. |
---|
29 | 29 | #define S3C64XX_SPI_CH_CFG 0x00 |
---|
30 | 30 | #define S3C64XX_SPI_CLK_CFG 0x04 |
---|
31 | 31 | #define S3C64XX_SPI_MODE_CFG 0x08 |
---|
32 | | -#define S3C64XX_SPI_SLAVE_SEL 0x0C |
---|
| 32 | +#define S3C64XX_SPI_CS_REG 0x0C |
---|
33 | 33 | #define S3C64XX_SPI_INT_EN 0x10 |
---|
34 | 34 | #define S3C64XX_SPI_STATUS 0x14 |
---|
35 | 35 | #define S3C64XX_SPI_TX_DATA 0x18 |
---|
.. | .. |
---|
64 | 64 | #define S3C64XX_SPI_MODE_TXDMA_ON (1<<1) |
---|
65 | 65 | #define S3C64XX_SPI_MODE_4BURST (1<<0) |
---|
66 | 66 | |
---|
67 | | -#define S3C64XX_SPI_SLAVE_AUTO (1<<1) |
---|
68 | | -#define S3C64XX_SPI_SLAVE_SIG_INACT (1<<0) |
---|
69 | | -#define S3C64XX_SPI_SLAVE_NSC_CNT_2 (2<<4) |
---|
| 67 | +#define S3C64XX_SPI_CS_NSC_CNT_2 (2<<4) |
---|
| 68 | +#define S3C64XX_SPI_CS_AUTO (1<<1) |
---|
| 69 | +#define S3C64XX_SPI_CS_SIG_INACT (1<<0) |
---|
70 | 70 | |
---|
71 | 71 | #define S3C64XX_SPI_INT_TRAILING_EN (1<<6) |
---|
72 | 72 | #define S3C64XX_SPI_INT_RX_OVERRUN_EN (1<<5) |
---|
.. | .. |
---|
84 | 84 | #define S3C64XX_SPI_ST_TX_FIFORDY (1<<0) |
---|
85 | 85 | |
---|
86 | 86 | #define S3C64XX_SPI_PACKET_CNT_EN (1<<16) |
---|
| 87 | +#define S3C64XX_SPI_PACKET_CNT_MASK GENMASK(15, 0) |
---|
87 | 88 | |
---|
88 | 89 | #define S3C64XX_SPI_PND_TX_UNDERRUN_CLR (1<<4) |
---|
89 | 90 | #define S3C64XX_SPI_PND_TX_OVERRUN_CLR (1<<3) |
---|
.. | .. |
---|
131 | 132 | * @fifo_lvl_mask: Bit-mask for {TX|RX}_FIFO_LVL bits in SPI_STATUS register. |
---|
132 | 133 | * @rx_lvl_offset: Bit offset of RX_FIFO_LVL bits in SPI_STATUS regiter. |
---|
133 | 134 | * @tx_st_done: Bit offset of TX_DONE bit in SPI_STATUS regiter. |
---|
| 135 | + * @quirks: Bitmask of known quirks |
---|
134 | 136 | * @high_speed: True, if the controller supports HIGH_SPEED_EN bit. |
---|
135 | 137 | * @clk_from_cmu: True, if the controller does not include a clock mux and |
---|
136 | 138 | * prescaler unit. |
---|
| 139 | + * @clk_ioclk: True if clock is present on this device |
---|
137 | 140 | * |
---|
138 | 141 | * The Samsung s3c64xx SPI controller are used on various Samsung SoC's but |
---|
139 | 142 | * differ in some aspects such as the size of the fifo and spi bus clock |
---|
.. | .. |
---|
155 | 158 | * @clk: Pointer to the spi clock. |
---|
156 | 159 | * @src_clk: Pointer to the clock used to generate SPI signals. |
---|
157 | 160 | * @ioclk: Pointer to the i/o clock between master and slave |
---|
| 161 | + * @pdev: Pointer to device's platform device data |
---|
158 | 162 | * @master: Pointer to the SPI Protocol master. |
---|
159 | 163 | * @cntrlr_info: Platform specific data for the controller this driver manages. |
---|
160 | 164 | * @lock: Controller specific lock. |
---|
161 | 165 | * @state: Set of FLAGS to indicate status. |
---|
162 | | - * @rx_dmach: Controller's DMA channel for Rx. |
---|
163 | | - * @tx_dmach: Controller's DMA channel for Tx. |
---|
164 | 166 | * @sfr_start: BUS address of SPI controller regs. |
---|
165 | 167 | * @regs: Pointer to ioremap'ed controller registers. |
---|
166 | | - * @irq: interrupt |
---|
167 | 168 | * @xfer_completion: To indicate completion of xfer task. |
---|
168 | 169 | * @cur_mode: Stores the active configuration of the controller. |
---|
169 | 170 | * @cur_bpw: Stores the active bits per word settings. |
---|
170 | | - * @cur_speed: Stores the active xfer clock speed. |
---|
| 171 | + * @cur_speed: Current clock speed |
---|
| 172 | + * @rx_dma: Local receive DMA data (e.g. chan and direction) |
---|
| 173 | + * @tx_dma: Local transmit DMA data (e.g. chan and direction) |
---|
| 174 | + * @port_conf: Local SPI port configuartion data |
---|
| 175 | + * @port_id: Port identification number |
---|
171 | 176 | */ |
---|
172 | 177 | struct s3c64xx_spi_driver_data { |
---|
173 | 178 | void __iomem *regs; |
---|
.. | .. |
---|
176 | 181 | struct clk *ioclk; |
---|
177 | 182 | struct platform_device *pdev; |
---|
178 | 183 | struct spi_master *master; |
---|
179 | | - struct s3c64xx_spi_info *cntrlr_info; |
---|
| 184 | + struct s3c64xx_spi_info *cntrlr_info; |
---|
180 | 185 | spinlock_t lock; |
---|
181 | 186 | unsigned long sfr_start; |
---|
182 | 187 | struct completion xfer_completion; |
---|
.. | .. |
---|
325 | 330 | |
---|
326 | 331 | if (enable) { |
---|
327 | 332 | if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO)) { |
---|
328 | | - writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); |
---|
| 333 | + writel(0, sdd->regs + S3C64XX_SPI_CS_REG); |
---|
329 | 334 | } else { |
---|
330 | | - u32 ssel = readl(sdd->regs + S3C64XX_SPI_SLAVE_SEL); |
---|
| 335 | + u32 ssel = readl(sdd->regs + S3C64XX_SPI_CS_REG); |
---|
331 | 336 | |
---|
332 | | - ssel |= (S3C64XX_SPI_SLAVE_AUTO | |
---|
333 | | - S3C64XX_SPI_SLAVE_NSC_CNT_2); |
---|
334 | | - writel(ssel, sdd->regs + S3C64XX_SPI_SLAVE_SEL); |
---|
| 337 | + ssel |= (S3C64XX_SPI_CS_AUTO | |
---|
| 338 | + S3C64XX_SPI_CS_NSC_CNT_2); |
---|
| 339 | + writel(ssel, sdd->regs + S3C64XX_SPI_CS_REG); |
---|
335 | 340 | } |
---|
336 | 341 | } else { |
---|
337 | 342 | if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO)) |
---|
338 | | - writel(S3C64XX_SPI_SLAVE_SIG_INACT, |
---|
339 | | - sdd->regs + S3C64XX_SPI_SLAVE_SEL); |
---|
| 343 | + writel(S3C64XX_SPI_CS_SIG_INACT, |
---|
| 344 | + sdd->regs + S3C64XX_SPI_CS_REG); |
---|
340 | 345 | } |
---|
341 | 346 | } |
---|
342 | 347 | |
---|
.. | .. |
---|
469 | 474 | |
---|
470 | 475 | /* millisecs to xfer 'len' bytes @ 'cur_speed' */ |
---|
471 | 476 | ms = xfer->len * 8 * 1000 / sdd->cur_speed; |
---|
472 | | - ms += 10; /* some tolerance */ |
---|
| 477 | + ms += 30; /* some tolerance */ |
---|
| 478 | + ms = max(ms, 100); /* minimum timeout */ |
---|
473 | 479 | |
---|
474 | 480 | val = msecs_to_jiffies(ms) + 10; |
---|
475 | 481 | val = wait_for_completion_timeout(&sdd->xfer_completion, val); |
---|
.. | .. |
---|
622 | 628 | ret = clk_set_rate(sdd->src_clk, sdd->cur_speed * 2); |
---|
623 | 629 | if (ret) |
---|
624 | 630 | return ret; |
---|
| 631 | + sdd->cur_speed = clk_get_rate(sdd->src_clk) / 2; |
---|
625 | 632 | } else { |
---|
626 | 633 | /* Configure Clock */ |
---|
627 | 634 | val = readl(regs + S3C64XX_SPI_CLK_CFG); |
---|
.. | .. |
---|
652 | 659 | writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK); |
---|
653 | 660 | |
---|
654 | 661 | return 0; |
---|
| 662 | +} |
---|
| 663 | + |
---|
| 664 | +static size_t s3c64xx_spi_max_transfer_size(struct spi_device *spi) |
---|
| 665 | +{ |
---|
| 666 | + struct spi_controller *ctlr = spi->controller; |
---|
| 667 | + |
---|
| 668 | + return ctlr->can_dma ? S3C64XX_SPI_PACKET_CNT_MASK : SIZE_MAX; |
---|
655 | 669 | } |
---|
656 | 670 | |
---|
657 | 671 | static int s3c64xx_spi_transfer_one(struct spi_master *master, |
---|
.. | .. |
---|
724 | 738 | |
---|
725 | 739 | if (status) { |
---|
726 | 740 | dev_err(&spi->dev, |
---|
727 | | - "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n", |
---|
| 741 | + "I/O Error: rx-%d tx-%d rx-%c tx-%c len-%d dma-%d res-(%d)\n", |
---|
728 | 742 | xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0, |
---|
729 | 743 | (sdd->state & RXBUSY) ? 'f' : 'p', |
---|
730 | 744 | (sdd->state & TXBUSY) ? 'f' : 'p', |
---|
731 | | - xfer->len); |
---|
| 745 | + xfer->len, use_dma ? 1 : 0, status); |
---|
732 | 746 | |
---|
733 | 747 | if (use_dma) { |
---|
734 | | - if (xfer->tx_buf && (sdd->state & TXBUSY)) |
---|
| 748 | + struct dma_tx_state s; |
---|
| 749 | + |
---|
| 750 | + if (xfer->tx_buf && (sdd->state & TXBUSY)) { |
---|
| 751 | + dmaengine_pause(sdd->tx_dma.ch); |
---|
| 752 | + dmaengine_tx_status(sdd->tx_dma.ch, sdd->tx_dma.cookie, &s); |
---|
735 | 753 | dmaengine_terminate_all(sdd->tx_dma.ch); |
---|
736 | | - if (xfer->rx_buf && (sdd->state & RXBUSY)) |
---|
| 754 | + dev_err(&spi->dev, "TX residue: %d\n", s.residue); |
---|
| 755 | + |
---|
| 756 | + } |
---|
| 757 | + if (xfer->rx_buf && (sdd->state & RXBUSY)) { |
---|
| 758 | + dmaengine_pause(sdd->rx_dma.ch); |
---|
| 759 | + dmaengine_tx_status(sdd->rx_dma.ch, sdd->rx_dma.cookie, &s); |
---|
737 | 760 | dmaengine_terminate_all(sdd->rx_dma.ch); |
---|
| 761 | + dev_err(&spi->dev, "RX residue: %d\n", s.residue); |
---|
| 762 | + } |
---|
738 | 763 | } |
---|
739 | 764 | } else { |
---|
740 | 765 | s3c64xx_flush_fifo(sdd); |
---|
.. | .. |
---|
964 | 989 | sdd->cur_speed = 0; |
---|
965 | 990 | |
---|
966 | 991 | if (sci->no_cs) |
---|
967 | | - writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); |
---|
| 992 | + writel(0, sdd->regs + S3C64XX_SPI_CS_REG); |
---|
968 | 993 | else if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO)) |
---|
969 | | - writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); |
---|
| 994 | + writel(S3C64XX_SPI_CS_SIG_INACT, sdd->regs + S3C64XX_SPI_CS_REG); |
---|
970 | 995 | |
---|
971 | 996 | /* Disable Interrupts - we use Polling if not DMA mode */ |
---|
972 | 997 | writel(0, regs + S3C64XX_SPI_INT_EN); |
---|
.. | .. |
---|
1118 | 1143 | master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer; |
---|
1119 | 1144 | master->prepare_message = s3c64xx_spi_prepare_message; |
---|
1120 | 1145 | master->transfer_one = s3c64xx_spi_transfer_one; |
---|
| 1146 | + master->max_transfer_size = s3c64xx_spi_max_transfer_size; |
---|
1121 | 1147 | master->num_chipselect = sci->num_cs; |
---|
1122 | 1148 | master->dma_alignment = 8; |
---|
1123 | 1149 | master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | |
---|
.. | .. |
---|
1186 | 1212 | |
---|
1187 | 1213 | if (!is_polling(sdd)) { |
---|
1188 | 1214 | /* Acquire DMA channels */ |
---|
1189 | | - sdd->rx_dma.ch = dma_request_slave_channel_reason(&pdev->dev, |
---|
1190 | | - "rx"); |
---|
| 1215 | + sdd->rx_dma.ch = dma_request_chan(&pdev->dev, "rx"); |
---|
1191 | 1216 | if (IS_ERR(sdd->rx_dma.ch)) { |
---|
1192 | 1217 | dev_err(&pdev->dev, "Failed to get RX DMA channel\n"); |
---|
1193 | 1218 | ret = PTR_ERR(sdd->rx_dma.ch); |
---|
1194 | 1219 | goto err_disable_io_clk; |
---|
1195 | 1220 | } |
---|
1196 | | - sdd->tx_dma.ch = dma_request_slave_channel_reason(&pdev->dev, |
---|
1197 | | - "tx"); |
---|
| 1221 | + sdd->tx_dma.ch = dma_request_chan(&pdev->dev, "tx"); |
---|
1198 | 1222 | if (IS_ERR(sdd->tx_dma.ch)) { |
---|
1199 | 1223 | dev_err(&pdev->dev, "Failed to get TX DMA channel\n"); |
---|
1200 | 1224 | ret = PTR_ERR(sdd->tx_dma.ch); |
---|
.. | .. |
---|
1363 | 1387 | |
---|
1364 | 1388 | s3c64xx_spi_hwinit(sdd); |
---|
1365 | 1389 | |
---|
| 1390 | + writel(S3C64XX_SPI_INT_RX_OVERRUN_EN | S3C64XX_SPI_INT_RX_UNDERRUN_EN | |
---|
| 1391 | + S3C64XX_SPI_INT_TX_OVERRUN_EN | S3C64XX_SPI_INT_TX_UNDERRUN_EN, |
---|
| 1392 | + sdd->regs + S3C64XX_SPI_INT_EN); |
---|
| 1393 | + |
---|
1366 | 1394 | return 0; |
---|
1367 | 1395 | |
---|
1368 | 1396 | err_disable_src_clk: |
---|
.. | .. |
---|
1406 | 1434 | .tx_st_done = 25, |
---|
1407 | 1435 | .high_speed = true, |
---|
1408 | 1436 | .clk_from_cmu = true, |
---|
| 1437 | + .quirks = S3C64XX_SPI_QUIRK_CS_AUTO, |
---|
1409 | 1438 | }; |
---|
1410 | 1439 | |
---|
1411 | 1440 | static struct s3c64xx_spi_port_config exynos7_spi_port_config = { |
---|