aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi-dw-mid.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi/spi-dw-mid.c')
-rw-r--r--drivers/spi/spi-dw-mid.c114
1 files changed, 83 insertions, 31 deletions
diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c
index 46c6d58e1fda..7281316a5ecb 100644
--- a/drivers/spi/spi-dw-mid.c
+++ b/drivers/spi/spi-dw-mid.c
@@ -26,6 +26,9 @@
26#include <linux/intel_mid_dma.h> 26#include <linux/intel_mid_dma.h>
27#include <linux/pci.h> 27#include <linux/pci.h>
28 28
29#define RX_BUSY 0
30#define TX_BUSY 1
31
29struct mid_dma { 32struct mid_dma {
30 struct intel_mid_dma_slave dmas_tx; 33 struct intel_mid_dma_slave dmas_tx;
31 struct intel_mid_dma_slave dmas_rx; 34 struct intel_mid_dma_slave dmas_rx;
@@ -98,41 +101,26 @@ static void mid_spi_dma_exit(struct dw_spi *dws)
98} 101}
99 102
100/* 103/*
101 * dws->dma_chan_done is cleared before the dma transfer starts, 104 * dws->dma_chan_busy is set before the dma transfer starts, callback for tx
102 * callback for rx/tx channel will each increment it by 1. 105 * channel will clear a corresponding bit.
103 * Reaching 2 means the whole spi transaction is done.
104 */ 106 */
105static void dw_spi_dma_done(void *arg) 107static void dw_spi_dma_tx_done(void *arg)
106{ 108{
107 struct dw_spi *dws = arg; 109 struct dw_spi *dws = arg;
108 110
109 if (++dws->dma_chan_done != 2) 111 if (test_and_clear_bit(TX_BUSY, &dws->dma_chan_busy) & BIT(RX_BUSY))
110 return; 112 return;
111 dw_spi_xfer_done(dws); 113 dw_spi_xfer_done(dws);
112} 114}
113 115
114static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) 116static struct dma_async_tx_descriptor *dw_spi_dma_prepare_tx(struct dw_spi *dws)
115{ 117{
116 struct dma_async_tx_descriptor *txdesc, *rxdesc; 118 struct dma_slave_config txconf;
117 struct dma_slave_config txconf, rxconf; 119 struct dma_async_tx_descriptor *txdesc;
118 u16 dma_ctrl = 0;
119
120 /* 1. setup DMA related registers */
121 if (cs_change) {
122 spi_enable_chip(dws, 0);
123 dw_writew(dws, DW_SPI_DMARDLR, 0xf);
124 dw_writew(dws, DW_SPI_DMATDLR, 0x10);
125 if (dws->tx_dma)
126 dma_ctrl |= SPI_DMA_TDMAE;
127 if (dws->rx_dma)
128 dma_ctrl |= SPI_DMA_RDMAE;
129 dw_writew(dws, DW_SPI_DMACR, dma_ctrl);
130 spi_enable_chip(dws, 1);
131 }
132 120
133 dws->dma_chan_done = 0; 121 if (!dws->tx_dma)
122 return NULL;
134 123
135 /* 2. Prepare the TX dma transfer */
136 txconf.direction = DMA_MEM_TO_DEV; 124 txconf.direction = DMA_MEM_TO_DEV;
137 txconf.dst_addr = dws->dma_addr; 125 txconf.dst_addr = dws->dma_addr;
138 txconf.dst_maxburst = LNW_DMA_MSIZE_16; 126 txconf.dst_maxburst = LNW_DMA_MSIZE_16;
@@ -151,10 +139,33 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
151 1, 139 1,
152 DMA_MEM_TO_DEV, 140 DMA_MEM_TO_DEV,
153 DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 141 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
154 txdesc->callback = dw_spi_dma_done; 142 txdesc->callback = dw_spi_dma_tx_done;
155 txdesc->callback_param = dws; 143 txdesc->callback_param = dws;
156 144
157 /* 3. Prepare the RX dma transfer */ 145 return txdesc;
146}
147
148/*
149 * dws->dma_chan_busy is set before the dma transfer starts, callback for rx
150 * channel will clear a corresponding bit.
151 */
152static void dw_spi_dma_rx_done(void *arg)
153{
154 struct dw_spi *dws = arg;
155
156 if (test_and_clear_bit(RX_BUSY, &dws->dma_chan_busy) & BIT(TX_BUSY))
157 return;
158 dw_spi_xfer_done(dws);
159}
160
161static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws)
162{
163 struct dma_slave_config rxconf;
164 struct dma_async_tx_descriptor *rxdesc;
165
166 if (!dws->rx_dma)
167 return NULL;
168
158 rxconf.direction = DMA_DEV_TO_MEM; 169 rxconf.direction = DMA_DEV_TO_MEM;
159 rxconf.src_addr = dws->dma_addr; 170 rxconf.src_addr = dws->dma_addr;
160 rxconf.src_maxburst = LNW_DMA_MSIZE_16; 171 rxconf.src_maxburst = LNW_DMA_MSIZE_16;
@@ -173,15 +184,56 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
173 1, 184 1,
174 DMA_DEV_TO_MEM, 185 DMA_DEV_TO_MEM,
175 DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 186 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
176 rxdesc->callback = dw_spi_dma_done; 187 rxdesc->callback = dw_spi_dma_rx_done;
177 rxdesc->callback_param = dws; 188 rxdesc->callback_param = dws;
178 189
190 return rxdesc;
191}
192
193static void dw_spi_dma_setup(struct dw_spi *dws)
194{
195 u16 dma_ctrl = 0;
196
197 spi_enable_chip(dws, 0);
198
199 dw_writew(dws, DW_SPI_DMARDLR, 0xf);
200 dw_writew(dws, DW_SPI_DMATDLR, 0x10);
201
202 if (dws->tx_dma)
203 dma_ctrl |= SPI_DMA_TDMAE;
204 if (dws->rx_dma)
205 dma_ctrl |= SPI_DMA_RDMAE;
206 dw_writew(dws, DW_SPI_DMACR, dma_ctrl);
207
208 spi_enable_chip(dws, 1);
209}
210
211static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
212{
213 struct dma_async_tx_descriptor *txdesc, *rxdesc;
214
215 /* 1. setup DMA related registers */
216 if (cs_change)
217 dw_spi_dma_setup(dws);
218
219 /* 2. Prepare the TX dma transfer */
220 txdesc = dw_spi_dma_prepare_tx(dws);
221
222 /* 3. Prepare the RX dma transfer */
223 rxdesc = dw_spi_dma_prepare_rx(dws);
224
179 /* rx must be started before tx due to spi instinct */ 225 /* rx must be started before tx due to spi instinct */
180 dmaengine_submit(rxdesc); 226 if (rxdesc) {
181 dma_async_issue_pending(dws->rxchan); 227 set_bit(RX_BUSY, &dws->dma_chan_busy);
228 dmaengine_submit(rxdesc);
229 dma_async_issue_pending(dws->rxchan);
230 }
182 231
183 dmaengine_submit(txdesc); 232 if (txdesc) {
184 dma_async_issue_pending(dws->txchan); 233 set_bit(TX_BUSY, &dws->dma_chan_busy);
234 dmaengine_submit(txdesc);
235 dma_async_issue_pending(dws->txchan);
236 }
185 237
186 return 0; 238 return 0;
187} 239}