diff options
Diffstat (limited to 'drivers/spi/spi-sun4i.c')
-rw-r--r-- | drivers/spi/spi-sun4i.c | 75 |
1 files changed, 67 insertions, 8 deletions
diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c index 4969dc10684a..c5cd635c28f3 100644 --- a/drivers/spi/spi-sun4i.c +++ b/drivers/spi/spi-sun4i.c | |||
@@ -46,6 +46,8 @@ | |||
46 | #define SUN4I_CTL_TP BIT(18) | 46 | #define SUN4I_CTL_TP BIT(18) |
47 | 47 | ||
48 | #define SUN4I_INT_CTL_REG 0x0c | 48 | #define SUN4I_INT_CTL_REG 0x0c |
49 | #define SUN4I_INT_CTL_RF_F34 BIT(4) | ||
50 | #define SUN4I_INT_CTL_TF_E34 BIT(12) | ||
49 | #define SUN4I_INT_CTL_TC BIT(16) | 51 | #define SUN4I_INT_CTL_TC BIT(16) |
50 | 52 | ||
51 | #define SUN4I_INT_STA_REG 0x10 | 53 | #define SUN4I_INT_STA_REG 0x10 |
@@ -61,11 +63,14 @@ | |||
61 | #define SUN4I_CLK_CTL_CDR1(div) (((div) & SUN4I_CLK_CTL_CDR1_MASK) << 8) | 63 | #define SUN4I_CLK_CTL_CDR1(div) (((div) & SUN4I_CLK_CTL_CDR1_MASK) << 8) |
62 | #define SUN4I_CLK_CTL_DRS BIT(12) | 64 | #define SUN4I_CLK_CTL_DRS BIT(12) |
63 | 65 | ||
66 | #define SUN4I_MAX_XFER_SIZE 0xffffff | ||
67 | |||
64 | #define SUN4I_BURST_CNT_REG 0x20 | 68 | #define SUN4I_BURST_CNT_REG 0x20 |
65 | #define SUN4I_BURST_CNT(cnt) ((cnt) & 0xffffff) | 69 | #define SUN4I_BURST_CNT(cnt) ((cnt) & SUN4I_MAX_XFER_SIZE) |
66 | 70 | ||
67 | #define SUN4I_XMIT_CNT_REG 0x24 | 71 | #define SUN4I_XMIT_CNT_REG 0x24 |
68 | #define SUN4I_XMIT_CNT(cnt) ((cnt) & 0xffffff) | 72 | #define SUN4I_XMIT_CNT(cnt) ((cnt) & SUN4I_MAX_XFER_SIZE) |
73 | |||
69 | 74 | ||
70 | #define SUN4I_FIFO_STA_REG 0x28 | 75 | #define SUN4I_FIFO_STA_REG 0x28 |
71 | #define SUN4I_FIFO_STA_RF_CNT_MASK 0x7f | 76 | #define SUN4I_FIFO_STA_RF_CNT_MASK 0x7f |
@@ -96,6 +101,31 @@ static inline void sun4i_spi_write(struct sun4i_spi *sspi, u32 reg, u32 value) | |||
96 | writel(value, sspi->base_addr + reg); | 101 | writel(value, sspi->base_addr + reg); |
97 | } | 102 | } |
98 | 103 | ||
104 | static inline u32 sun4i_spi_get_tx_fifo_count(struct sun4i_spi *sspi) | ||
105 | { | ||
106 | u32 reg = sun4i_spi_read(sspi, SUN4I_FIFO_STA_REG); | ||
107 | |||
108 | reg >>= SUN4I_FIFO_STA_TF_CNT_BITS; | ||
109 | |||
110 | return reg & SUN4I_FIFO_STA_TF_CNT_MASK; | ||
111 | } | ||
112 | |||
113 | static inline void sun4i_spi_enable_interrupt(struct sun4i_spi *sspi, u32 mask) | ||
114 | { | ||
115 | u32 reg = sun4i_spi_read(sspi, SUN4I_INT_CTL_REG); | ||
116 | |||
117 | reg |= mask; | ||
118 | sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, reg); | ||
119 | } | ||
120 | |||
121 | static inline void sun4i_spi_disable_interrupt(struct sun4i_spi *sspi, u32 mask) | ||
122 | { | ||
123 | u32 reg = sun4i_spi_read(sspi, SUN4I_INT_CTL_REG); | ||
124 | |||
125 | reg &= ~mask; | ||
126 | sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, reg); | ||
127 | } | ||
128 | |||
99 | static inline void sun4i_spi_drain_fifo(struct sun4i_spi *sspi, int len) | 129 | static inline void sun4i_spi_drain_fifo(struct sun4i_spi *sspi, int len) |
100 | { | 130 | { |
101 | u32 reg, cnt; | 131 | u32 reg, cnt; |
@@ -118,10 +148,13 @@ static inline void sun4i_spi_drain_fifo(struct sun4i_spi *sspi, int len) | |||
118 | 148 | ||
119 | static inline void sun4i_spi_fill_fifo(struct sun4i_spi *sspi, int len) | 149 | static inline void sun4i_spi_fill_fifo(struct sun4i_spi *sspi, int len) |
120 | { | 150 | { |
151 | u32 cnt; | ||
121 | u8 byte; | 152 | u8 byte; |
122 | 153 | ||
123 | if (len > sspi->len) | 154 | /* See how much data we can fit */ |
124 | len = sspi->len; | 155 | cnt = SUN4I_FIFO_DEPTH - sun4i_spi_get_tx_fifo_count(sspi); |
156 | |||
157 | len = min3(len, (int)cnt, sspi->len); | ||
125 | 158 | ||
126 | while (len--) { | 159 | while (len--) { |
127 | byte = sspi->tx_buf ? *sspi->tx_buf++ : 0; | 160 | byte = sspi->tx_buf ? *sspi->tx_buf++ : 0; |
@@ -184,10 +217,10 @@ static int sun4i_spi_transfer_one(struct spi_master *master, | |||
184 | u32 reg; | 217 | u32 reg; |
185 | 218 | ||
186 | /* We don't support transfer larger than the FIFO */ | 219 | /* We don't support transfer larger than the FIFO */ |
187 | if (tfr->len > SUN4I_FIFO_DEPTH) | 220 | if (tfr->len > SUN4I_MAX_XFER_SIZE) |
188 | return -EMSGSIZE; | 221 | return -EMSGSIZE; |
189 | 222 | ||
190 | if (tfr->tx_buf && tfr->len >= SUN4I_FIFO_DEPTH) | 223 | if (tfr->tx_buf && tfr->len >= SUN4I_MAX_XFER_SIZE) |
191 | return -EMSGSIZE; | 224 | return -EMSGSIZE; |
192 | 225 | ||
193 | reinit_completion(&sspi->done); | 226 | reinit_completion(&sspi->done); |
@@ -286,7 +319,11 @@ static int sun4i_spi_transfer_one(struct spi_master *master, | |||
286 | sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH - 1); | 319 | sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH - 1); |
287 | 320 | ||
288 | /* Enable the interrupts */ | 321 | /* Enable the interrupts */ |
289 | sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, SUN4I_INT_CTL_TC); | 322 | sun4i_spi_enable_interrupt(sspi, SUN4I_INT_CTL_TC | |
323 | SUN4I_INT_CTL_RF_F34); | ||
324 | /* Only enable Tx FIFO interrupt if we really need it */ | ||
325 | if (tx_len > SUN4I_FIFO_DEPTH) | ||
326 | sun4i_spi_enable_interrupt(sspi, SUN4I_INT_CTL_TF_E34); | ||
290 | 327 | ||
291 | /* Start the transfer */ | 328 | /* Start the transfer */ |
292 | reg = sun4i_spi_read(sspi, SUN4I_CTL_REG); | 329 | reg = sun4i_spi_read(sspi, SUN4I_CTL_REG); |
@@ -306,7 +343,6 @@ static int sun4i_spi_transfer_one(struct spi_master *master, | |||
306 | goto out; | 343 | goto out; |
307 | } | 344 | } |
308 | 345 | ||
309 | sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH); | ||
310 | 346 | ||
311 | out: | 347 | out: |
312 | sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, 0); | 348 | sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, 0); |
@@ -322,10 +358,33 @@ static irqreturn_t sun4i_spi_handler(int irq, void *dev_id) | |||
322 | /* Transfer complete */ | 358 | /* Transfer complete */ |
323 | if (status & SUN4I_INT_CTL_TC) { | 359 | if (status & SUN4I_INT_CTL_TC) { |
324 | sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_TC); | 360 | sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_TC); |
361 | sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH); | ||
325 | complete(&sspi->done); | 362 | complete(&sspi->done); |
326 | return IRQ_HANDLED; | 363 | return IRQ_HANDLED; |
327 | } | 364 | } |
328 | 365 | ||
366 | /* Receive FIFO 3/4 full */ | ||
367 | if (status & SUN4I_INT_CTL_RF_F34) { | ||
368 | sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH); | ||
369 | /* Only clear the interrupt _after_ draining the FIFO */ | ||
370 | sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_RF_F34); | ||
371 | return IRQ_HANDLED; | ||
372 | } | ||
373 | |||
374 | /* Transmit FIFO 3/4 empty */ | ||
375 | if (status & SUN4I_INT_CTL_TF_E34) { | ||
376 | sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH); | ||
377 | |||
378 | if (!sspi->len) | ||
379 | /* nothing left to transmit */ | ||
380 | sun4i_spi_disable_interrupt(sspi, SUN4I_INT_CTL_TF_E34); | ||
381 | |||
382 | /* Only clear the interrupt _after_ re-seeding the FIFO */ | ||
383 | sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_TF_E34); | ||
384 | |||
385 | return IRQ_HANDLED; | ||
386 | } | ||
387 | |||
329 | return IRQ_NONE; | 388 | return IRQ_NONE; |
330 | } | 389 | } |
331 | 390 | ||