diff options
Diffstat (limited to 'drivers/spi/spi-fsl-lpspi.c')
-rw-r--r-- | drivers/spi/spi-fsl-lpspi.c | 92 |
1 files changed, 48 insertions, 44 deletions
diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 08dcc3c22e88..391863914043 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c | |||
@@ -48,10 +48,13 @@ | |||
48 | #define CR_RTF BIT(8) | 48 | #define CR_RTF BIT(8) |
49 | #define CR_RST BIT(1) | 49 | #define CR_RST BIT(1) |
50 | #define CR_MEN BIT(0) | 50 | #define CR_MEN BIT(0) |
51 | #define SR_MBF BIT(24) | ||
51 | #define SR_TCF BIT(10) | 52 | #define SR_TCF BIT(10) |
53 | #define SR_FCF BIT(9) | ||
52 | #define SR_RDF BIT(1) | 54 | #define SR_RDF BIT(1) |
53 | #define SR_TDF BIT(0) | 55 | #define SR_TDF BIT(0) |
54 | #define IER_TCIE BIT(10) | 56 | #define IER_TCIE BIT(10) |
57 | #define IER_FCIE BIT(9) | ||
55 | #define IER_RDIE BIT(1) | 58 | #define IER_RDIE BIT(1) |
56 | #define IER_TDIE BIT(0) | 59 | #define IER_TDIE BIT(0) |
57 | #define CFGR1_PCSCFG BIT(27) | 60 | #define CFGR1_PCSCFG BIT(27) |
@@ -59,6 +62,7 @@ | |||
59 | #define CFGR1_PCSPOL BIT(8) | 62 | #define CFGR1_PCSPOL BIT(8) |
60 | #define CFGR1_NOSTALL BIT(3) | 63 | #define CFGR1_NOSTALL BIT(3) |
61 | #define CFGR1_MASTER BIT(0) | 64 | #define CFGR1_MASTER BIT(0) |
65 | #define FSR_RXCOUNT (BIT(16)|BIT(17)|BIT(18)) | ||
62 | #define RSR_RXEMPTY BIT(1) | 66 | #define RSR_RXEMPTY BIT(1) |
63 | #define TCR_CPOL BIT(31) | 67 | #define TCR_CPOL BIT(31) |
64 | #define TCR_CPHA BIT(30) | 68 | #define TCR_CPHA BIT(30) |
@@ -161,28 +165,10 @@ static int lpspi_unprepare_xfer_hardware(struct spi_controller *controller) | |||
161 | return 0; | 165 | return 0; |
162 | } | 166 | } |
163 | 167 | ||
164 | static int fsl_lpspi_txfifo_empty(struct fsl_lpspi_data *fsl_lpspi) | ||
165 | { | ||
166 | u32 txcnt; | ||
167 | unsigned long orig_jiffies = jiffies; | ||
168 | |||
169 | do { | ||
170 | txcnt = readl(fsl_lpspi->base + IMX7ULP_FSR) & 0xff; | ||
171 | |||
172 | if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) { | ||
173 | dev_dbg(fsl_lpspi->dev, "txfifo empty timeout\n"); | ||
174 | return -ETIMEDOUT; | ||
175 | } | ||
176 | cond_resched(); | ||
177 | |||
178 | } while (txcnt); | ||
179 | |||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | static void fsl_lpspi_write_tx_fifo(struct fsl_lpspi_data *fsl_lpspi) | 168 | static void fsl_lpspi_write_tx_fifo(struct fsl_lpspi_data *fsl_lpspi) |
184 | { | 169 | { |
185 | u8 txfifo_cnt; | 170 | u8 txfifo_cnt; |
171 | u32 temp; | ||
186 | 172 | ||
187 | txfifo_cnt = readl(fsl_lpspi->base + IMX7ULP_FSR) & 0xff; | 173 | txfifo_cnt = readl(fsl_lpspi->base + IMX7ULP_FSR) & 0xff; |
188 | 174 | ||
@@ -193,9 +179,15 @@ static void fsl_lpspi_write_tx_fifo(struct fsl_lpspi_data *fsl_lpspi) | |||
193 | txfifo_cnt++; | 179 | txfifo_cnt++; |
194 | } | 180 | } |
195 | 181 | ||
196 | if (!fsl_lpspi->remain && (txfifo_cnt < fsl_lpspi->txfifosize)) | 182 | if (txfifo_cnt < fsl_lpspi->txfifosize) { |
197 | writel(0, fsl_lpspi->base + IMX7ULP_TDR); | 183 | if (!fsl_lpspi->is_slave) { |
198 | else | 184 | temp = readl(fsl_lpspi->base + IMX7ULP_TCR); |
185 | temp &= ~TCR_CONTC; | ||
186 | writel(temp, fsl_lpspi->base + IMX7ULP_TCR); | ||
187 | } | ||
188 | |||
189 | fsl_lpspi_intctrl(fsl_lpspi, IER_FCIE); | ||
190 | } else | ||
199 | fsl_lpspi_intctrl(fsl_lpspi, IER_TDIE); | 191 | fsl_lpspi_intctrl(fsl_lpspi, IER_TDIE); |
200 | } | 192 | } |
201 | 193 | ||
@@ -276,10 +268,6 @@ static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_lpspi) | |||
276 | u32 temp; | 268 | u32 temp; |
277 | int ret; | 269 | int ret; |
278 | 270 | ||
279 | temp = CR_RST; | ||
280 | writel(temp, fsl_lpspi->base + IMX7ULP_CR); | ||
281 | writel(0, fsl_lpspi->base + IMX7ULP_CR); | ||
282 | |||
283 | if (!fsl_lpspi->is_slave) { | 271 | if (!fsl_lpspi->is_slave) { |
284 | ret = fsl_lpspi_set_bitrate(fsl_lpspi); | 272 | ret = fsl_lpspi_set_bitrate(fsl_lpspi); |
285 | if (ret) | 273 | if (ret) |
@@ -370,6 +358,24 @@ static int fsl_lpspi_wait_for_completion(struct spi_controller *controller) | |||
370 | return 0; | 358 | return 0; |
371 | } | 359 | } |
372 | 360 | ||
361 | static int fsl_lpspi_reset(struct fsl_lpspi_data *fsl_lpspi) | ||
362 | { | ||
363 | u32 temp; | ||
364 | |||
365 | /* Disable all interrupt */ | ||
366 | fsl_lpspi_intctrl(fsl_lpspi, 0); | ||
367 | |||
368 | /* W1C for all flags in SR */ | ||
369 | temp = 0x3F << 8; | ||
370 | writel(temp, fsl_lpspi->base + IMX7ULP_SR); | ||
371 | |||
372 | /* Clear FIFO and disable module */ | ||
373 | temp = CR_RRF | CR_RTF; | ||
374 | writel(temp, fsl_lpspi->base + IMX7ULP_CR); | ||
375 | |||
376 | return 0; | ||
377 | } | ||
378 | |||
373 | static int fsl_lpspi_transfer_one(struct spi_controller *controller, | 379 | static int fsl_lpspi_transfer_one(struct spi_controller *controller, |
374 | struct spi_device *spi, | 380 | struct spi_device *spi, |
375 | struct spi_transfer *t) | 381 | struct spi_transfer *t) |
@@ -391,11 +397,7 @@ static int fsl_lpspi_transfer_one(struct spi_controller *controller, | |||
391 | if (ret) | 397 | if (ret) |
392 | return ret; | 398 | return ret; |
393 | 399 | ||
394 | ret = fsl_lpspi_txfifo_empty(fsl_lpspi); | 400 | fsl_lpspi_reset(fsl_lpspi); |
395 | if (ret) | ||
396 | return ret; | ||
397 | |||
398 | fsl_lpspi_read_rx_fifo(fsl_lpspi); | ||
399 | 401 | ||
400 | return 0; | 402 | return 0; |
401 | } | 403 | } |
@@ -408,7 +410,6 @@ static int fsl_lpspi_transfer_one_msg(struct spi_controller *controller, | |||
408 | struct spi_device *spi = msg->spi; | 410 | struct spi_device *spi = msg->spi; |
409 | struct spi_transfer *xfer; | 411 | struct spi_transfer *xfer; |
410 | bool is_first_xfer = true; | 412 | bool is_first_xfer = true; |
411 | u32 temp; | ||
412 | int ret = 0; | 413 | int ret = 0; |
413 | 414 | ||
414 | msg->status = 0; | 415 | msg->status = 0; |
@@ -428,13 +429,6 @@ static int fsl_lpspi_transfer_one_msg(struct spi_controller *controller, | |||
428 | } | 429 | } |
429 | 430 | ||
430 | complete: | 431 | complete: |
431 | if (!fsl_lpspi->is_slave) { | ||
432 | /* de-assert SS, then finalize current message */ | ||
433 | temp = readl(fsl_lpspi->base + IMX7ULP_TCR); | ||
434 | temp &= ~TCR_CONTC; | ||
435 | writel(temp, fsl_lpspi->base + IMX7ULP_TCR); | ||
436 | } | ||
437 | |||
438 | msg->status = ret; | 432 | msg->status = ret; |
439 | spi_finalize_current_message(controller); | 433 | spi_finalize_current_message(controller); |
440 | 434 | ||
@@ -443,20 +437,30 @@ complete: | |||
443 | 437 | ||
444 | static irqreturn_t fsl_lpspi_isr(int irq, void *dev_id) | 438 | static irqreturn_t fsl_lpspi_isr(int irq, void *dev_id) |
445 | { | 439 | { |
440 | u32 temp_SR, temp_IER; | ||
446 | struct fsl_lpspi_data *fsl_lpspi = dev_id; | 441 | struct fsl_lpspi_data *fsl_lpspi = dev_id; |
447 | u32 temp; | ||
448 | 442 | ||
443 | temp_IER = readl(fsl_lpspi->base + IMX7ULP_IER); | ||
449 | fsl_lpspi_intctrl(fsl_lpspi, 0); | 444 | fsl_lpspi_intctrl(fsl_lpspi, 0); |
450 | temp = readl(fsl_lpspi->base + IMX7ULP_SR); | 445 | temp_SR = readl(fsl_lpspi->base + IMX7ULP_SR); |
451 | 446 | ||
452 | fsl_lpspi_read_rx_fifo(fsl_lpspi); | 447 | fsl_lpspi_read_rx_fifo(fsl_lpspi); |
453 | 448 | ||
454 | if (temp & SR_TDF) { | 449 | if ((temp_SR & SR_TDF) && (temp_IER & IER_TDIE)) { |
455 | fsl_lpspi_write_tx_fifo(fsl_lpspi); | 450 | fsl_lpspi_write_tx_fifo(fsl_lpspi); |
451 | return IRQ_HANDLED; | ||
452 | } | ||
456 | 453 | ||
457 | if (!fsl_lpspi->remain) | 454 | if (temp_SR & SR_MBF || |
458 | complete(&fsl_lpspi->xfer_done); | 455 | readl(fsl_lpspi->base + IMX7ULP_FSR) & FSR_RXCOUNT) { |
456 | writel(SR_FCF, fsl_lpspi->base + IMX7ULP_SR); | ||
457 | fsl_lpspi_intctrl(fsl_lpspi, IER_FCIE); | ||
458 | return IRQ_HANDLED; | ||
459 | } | ||
459 | 460 | ||
461 | if (temp_SR & SR_FCF && (temp_IER & IER_FCIE)) { | ||
462 | writel(SR_FCF, fsl_lpspi->base + IMX7ULP_SR); | ||
463 | complete(&fsl_lpspi->xfer_done); | ||
460 | return IRQ_HANDLED; | 464 | return IRQ_HANDLED; |
461 | } | 465 | } |
462 | 466 | ||