diff options
author | Haikun Wang <haikun.wang@freescale.com> | 2015-06-09 07:45:27 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-06-09 13:35:54 -0400 |
commit | d1f4a38c8139cf87316b16f28b206fd1fd2b31db (patch) | |
tree | 145245902e3a21587dd943a78ef9798437409a7b /drivers/spi/spi-fsl-dspi.c | |
parent | 6724af486903df57338c14424e02599e371cf563 (diff) |
spi: spi-fsl-dspi: Enable TCF interrupt mode support
DSPI module has two optional interrupts when complete data transfer.
One is EOQ interrupt, the other one is TCF interrupt.
EOQ indicates a queue of data frame has been transmitted.
TCF indicates a frame has been transmitted.
This patch enable support TCF mode.
Driver binds a correct interrupt mode to every compatible string.
User should use the correct compatible string in the dts node.
Signed-off-by: Haikun Wang <haikun.wang@freescale.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/spi/spi-fsl-dspi.c')
-rw-r--r-- | drivers/spi/spi-fsl-dspi.c | 245 |
1 files changed, 169 insertions, 76 deletions
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index c184f21c1ffa..7d7f8035f25b 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c | |||
@@ -67,9 +67,11 @@ | |||
67 | 67 | ||
68 | #define SPI_SR 0x2c | 68 | #define SPI_SR 0x2c |
69 | #define SPI_SR_EOQF 0x10000000 | 69 | #define SPI_SR_EOQF 0x10000000 |
70 | #define SPI_SR_TCFQF 0x80000000 | ||
70 | 71 | ||
71 | #define SPI_RSER 0x30 | 72 | #define SPI_RSER 0x30 |
72 | #define SPI_RSER_EOQFE 0x10000000 | 73 | #define SPI_RSER_EOQFE 0x10000000 |
74 | #define SPI_RSER_TCFQE 0x80000000 | ||
73 | 75 | ||
74 | #define SPI_PUSHR 0x34 | 76 | #define SPI_PUSHR 0x34 |
75 | #define SPI_PUSHR_CONT (1 << 31) | 77 | #define SPI_PUSHR_CONT (1 << 31) |
@@ -108,6 +110,27 @@ struct chip_data { | |||
108 | u16 void_write_data; | 110 | u16 void_write_data; |
109 | }; | 111 | }; |
110 | 112 | ||
113 | enum dspi_trans_mode { | ||
114 | DSPI_EOQ_MODE = 0, | ||
115 | DSPI_TCFQ_MODE, | ||
116 | }; | ||
117 | |||
118 | struct fsl_dspi_devtype_data { | ||
119 | enum dspi_trans_mode trans_mode; | ||
120 | }; | ||
121 | |||
122 | static const struct fsl_dspi_devtype_data vf610_data = { | ||
123 | .trans_mode = DSPI_EOQ_MODE, | ||
124 | }; | ||
125 | |||
126 | static const struct fsl_dspi_devtype_data ls1021a_v1_data = { | ||
127 | .trans_mode = DSPI_TCFQ_MODE, | ||
128 | }; | ||
129 | |||
130 | static const struct fsl_dspi_devtype_data ls2085a_data = { | ||
131 | .trans_mode = DSPI_TCFQ_MODE, | ||
132 | }; | ||
133 | |||
111 | struct fsl_dspi { | 134 | struct fsl_dspi { |
112 | struct spi_master *master; | 135 | struct spi_master *master; |
113 | struct platform_device *pdev; | 136 | struct platform_device *pdev; |
@@ -128,6 +151,7 @@ struct fsl_dspi { | |||
128 | u8 cs; | 151 | u8 cs; |
129 | u16 void_write_data; | 152 | u16 void_write_data; |
130 | u32 cs_change; | 153 | u32 cs_change; |
154 | struct fsl_dspi_devtype_data *devtype_data; | ||
131 | 155 | ||
132 | wait_queue_head_t waitq; | 156 | wait_queue_head_t waitq; |
133 | u32 waitflags; | 157 | u32 waitflags; |
@@ -213,63 +237,61 @@ static void ns_delay_scale(char *psc, char *sc, int delay_ns, | |||
213 | } | 237 | } |
214 | } | 238 | } |
215 | 239 | ||
216 | static int dspi_transfer_write(struct fsl_dspi *dspi) | 240 | static u32 dspi_data_to_pushr(struct fsl_dspi *dspi, int tx_word) |
217 | { | 241 | { |
218 | int tx_count = 0; | ||
219 | int tx_word; | ||
220 | u16 d16; | 242 | u16 d16; |
221 | u8 d8; | ||
222 | u32 dspi_pushr = 0; | ||
223 | int first = 1; | ||
224 | 243 | ||
225 | tx_word = is_double_byte_mode(dspi); | 244 | if (!(dspi->dataflags & TRAN_STATE_TX_VOID)) |
245 | d16 = tx_word ? *(u16 *)dspi->tx : *(u8 *)dspi->tx; | ||
246 | else | ||
247 | d16 = dspi->void_write_data; | ||
226 | 248 | ||
227 | /* If we are in word mode, but only have a single byte to transfer | 249 | dspi->tx += tx_word + 1; |
228 | * then switch to byte mode temporarily. Will switch back at the | 250 | dspi->len -= tx_word + 1; |
229 | * end of the transfer. | ||
230 | */ | ||
231 | if (tx_word && (dspi->len == 1)) { | ||
232 | dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM; | ||
233 | regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs), | ||
234 | SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8)); | ||
235 | tx_word = 0; | ||
236 | } | ||
237 | 251 | ||
238 | while (dspi->len && (tx_count < DSPI_FIFO_SIZE)) { | 252 | return SPI_PUSHR_TXDATA(d16) | |
239 | if (tx_word) { | 253 | SPI_PUSHR_PCS(dspi->cs) | |
240 | if (dspi->len == 1) | 254 | SPI_PUSHR_CTAS(dspi->cs) | |
241 | break; | 255 | SPI_PUSHR_CONT; |
256 | } | ||
242 | 257 | ||
243 | if (!(dspi->dataflags & TRAN_STATE_TX_VOID)) { | 258 | static void dspi_data_from_popr(struct fsl_dspi *dspi, int rx_word) |
244 | d16 = *(u16 *)dspi->tx; | 259 | { |
245 | dspi->tx += 2; | 260 | u16 d; |
246 | } else { | 261 | unsigned int val; |
247 | d16 = dspi->void_write_data; | ||
248 | } | ||
249 | 262 | ||
250 | dspi_pushr = SPI_PUSHR_TXDATA(d16) | | 263 | regmap_read(dspi->regmap, SPI_POPR, &val); |
251 | SPI_PUSHR_PCS(dspi->cs) | | 264 | d = SPI_POPR_RXDATA(val); |
252 | SPI_PUSHR_CTAS(dspi->cs) | | ||
253 | SPI_PUSHR_CONT; | ||
254 | 265 | ||
255 | dspi->len -= 2; | 266 | if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) |
256 | } else { | 267 | rx_word ? (*(u16 *)dspi->rx = d) : (*(u8 *)dspi->rx = d); |
257 | if (!(dspi->dataflags & TRAN_STATE_TX_VOID)) { | ||
258 | 268 | ||
259 | d8 = *(u8 *)dspi->tx; | 269 | dspi->rx += rx_word + 1; |
260 | dspi->tx++; | 270 | } |
261 | } else { | ||
262 | d8 = (u8)dspi->void_write_data; | ||
263 | } | ||
264 | 271 | ||
265 | dspi_pushr = SPI_PUSHR_TXDATA(d8) | | 272 | static int dspi_eoq_write(struct fsl_dspi *dspi) |
266 | SPI_PUSHR_PCS(dspi->cs) | | 273 | { |
267 | SPI_PUSHR_CTAS(dspi->cs) | | 274 | int tx_count = 0; |
268 | SPI_PUSHR_CONT; | 275 | int tx_word; |
276 | u32 dspi_pushr = 0; | ||
277 | int first = 1; | ||
269 | 278 | ||
270 | dspi->len--; | 279 | tx_word = is_double_byte_mode(dspi); |
280 | |||
281 | while (dspi->len && (tx_count < DSPI_FIFO_SIZE)) { | ||
282 | /* If we are in word mode, only have a single byte to transfer | ||
283 | * switch to byte mode temporarily. Will switch back at the | ||
284 | * end of the transfer. | ||
285 | */ | ||
286 | if (tx_word && (dspi->len == 1)) { | ||
287 | dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM; | ||
288 | regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs), | ||
289 | SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8)); | ||
290 | tx_word = 0; | ||
271 | } | 291 | } |
272 | 292 | ||
293 | dspi_pushr = dspi_data_to_pushr(dspi, tx_word); | ||
294 | |||
273 | if (dspi->len == 0 || tx_count == DSPI_FIFO_SIZE - 1) { | 295 | if (dspi->len == 0 || tx_count == DSPI_FIFO_SIZE - 1) { |
274 | /* last transfer in the transfer */ | 296 | /* last transfer in the transfer */ |
275 | dspi_pushr |= SPI_PUSHR_EOQ; | 297 | dspi_pushr |= SPI_PUSHR_EOQ; |
@@ -291,40 +313,55 @@ static int dspi_transfer_write(struct fsl_dspi *dspi) | |||
291 | return tx_count * (tx_word + 1); | 313 | return tx_count * (tx_word + 1); |
292 | } | 314 | } |
293 | 315 | ||
294 | static int dspi_transfer_read(struct fsl_dspi *dspi) | 316 | static int dspi_eoq_read(struct fsl_dspi *dspi) |
295 | { | 317 | { |
296 | int rx_count = 0; | 318 | int rx_count = 0; |
297 | int rx_word = is_double_byte_mode(dspi); | 319 | int rx_word = is_double_byte_mode(dspi); |
298 | u16 d; | ||
299 | 320 | ||
300 | while ((dspi->rx < dspi->rx_end) | 321 | while ((dspi->rx < dspi->rx_end) |
301 | && (rx_count < DSPI_FIFO_SIZE)) { | 322 | && (rx_count < DSPI_FIFO_SIZE)) { |
302 | if (rx_word) { | 323 | if (rx_word && (dspi->rx_end - dspi->rx) == 1) |
303 | unsigned int val; | 324 | rx_word = 0; |
304 | 325 | ||
305 | if ((dspi->rx_end - dspi->rx) == 1) | 326 | dspi_data_from_popr(dspi, rx_word); |
306 | break; | 327 | rx_count++; |
328 | } | ||
307 | 329 | ||
308 | regmap_read(dspi->regmap, SPI_POPR, &val); | 330 | return rx_count; |
309 | d = SPI_POPR_RXDATA(val); | 331 | } |
310 | 332 | ||
311 | if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) | 333 | static int dspi_tcfq_write(struct fsl_dspi *dspi) |
312 | *(u16 *)dspi->rx = d; | 334 | { |
313 | dspi->rx += 2; | 335 | int tx_word; |
336 | u32 dspi_pushr = 0; | ||
314 | 337 | ||
315 | } else { | 338 | tx_word = is_double_byte_mode(dspi); |
316 | unsigned int val; | ||
317 | 339 | ||
318 | regmap_read(dspi->regmap, SPI_POPR, &val); | 340 | if (tx_word && (dspi->len == 1)) { |
319 | d = SPI_POPR_RXDATA(val); | 341 | dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM; |
320 | if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) | 342 | regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs), |
321 | *(u8 *)dspi->rx = d; | 343 | SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8)); |
322 | dspi->rx++; | 344 | tx_word = 0; |
323 | } | ||
324 | rx_count++; | ||
325 | } | 345 | } |
326 | 346 | ||
327 | return rx_count; | 347 | dspi_pushr = dspi_data_to_pushr(dspi, tx_word); |
348 | |||
349 | if ((dspi->cs_change) && (!dspi->len)) | ||
350 | dspi_pushr &= ~SPI_PUSHR_CONT; | ||
351 | |||
352 | regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr); | ||
353 | |||
354 | return tx_word + 1; | ||
355 | } | ||
356 | |||
357 | static void dspi_tcfq_read(struct fsl_dspi *dspi) | ||
358 | { | ||
359 | int rx_word = is_double_byte_mode(dspi); | ||
360 | |||
361 | if (rx_word && (dspi->rx_end - dspi->rx) == 1) | ||
362 | rx_word = 0; | ||
363 | |||
364 | dspi_data_from_popr(dspi, rx_word); | ||
328 | } | 365 | } |
329 | 366 | ||
330 | static int dspi_transfer_one_message(struct spi_master *master, | 367 | static int dspi_transfer_one_message(struct spi_master *master, |
@@ -334,6 +371,8 @@ static int dspi_transfer_one_message(struct spi_master *master, | |||
334 | struct spi_device *spi = message->spi; | 371 | struct spi_device *spi = message->spi; |
335 | struct spi_transfer *transfer; | 372 | struct spi_transfer *transfer; |
336 | int status = 0; | 373 | int status = 0; |
374 | enum dspi_trans_mode trans_mode; | ||
375 | |||
337 | message->actual_length = 0; | 376 | message->actual_length = 0; |
338 | 377 | ||
339 | list_for_each_entry(transfer, &message->transfers, transfer_list) { | 378 | list_for_each_entry(transfer, &message->transfers, transfer_list) { |
@@ -370,8 +409,22 @@ static int dspi_transfer_one_message(struct spi_master *master, | |||
370 | regmap_write(dspi->regmap, SPI_CTAR(dspi->cs), | 409 | regmap_write(dspi->regmap, SPI_CTAR(dspi->cs), |
371 | dspi->cur_chip->ctar_val); | 410 | dspi->cur_chip->ctar_val); |
372 | 411 | ||
373 | regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_EOQFE); | 412 | trans_mode = dspi->devtype_data->trans_mode; |
374 | message->actual_length += dspi_transfer_write(dspi); | 413 | switch (trans_mode) { |
414 | case DSPI_EOQ_MODE: | ||
415 | regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_EOQFE); | ||
416 | message->actual_length += dspi_eoq_write(dspi); | ||
417 | break; | ||
418 | case DSPI_TCFQ_MODE: | ||
419 | regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_TCFQE); | ||
420 | message->actual_length += dspi_tcfq_write(dspi); | ||
421 | break; | ||
422 | default: | ||
423 | dev_err(&dspi->pdev->dev, "unsupported trans_mode %u\n", | ||
424 | trans_mode); | ||
425 | status = -EINVAL; | ||
426 | goto out; | ||
427 | } | ||
375 | 428 | ||
376 | if (wait_event_interruptible(dspi->waitq, dspi->waitflags)) | 429 | if (wait_event_interruptible(dspi->waitq, dspi->waitflags)) |
377 | dev_err(&dspi->pdev->dev, "wait transfer complete fail!\n"); | 430 | dev_err(&dspi->pdev->dev, "wait transfer complete fail!\n"); |
@@ -381,6 +434,7 @@ static int dspi_transfer_one_message(struct spi_master *master, | |||
381 | udelay(transfer->delay_usecs); | 434 | udelay(transfer->delay_usecs); |
382 | } | 435 | } |
383 | 436 | ||
437 | out: | ||
384 | message->status = status; | 438 | message->status = status; |
385 | spi_finalize_current_message(master); | 439 | spi_finalize_current_message(master); |
386 | 440 | ||
@@ -460,27 +514,57 @@ static void dspi_cleanup(struct spi_device *spi) | |||
460 | static irqreturn_t dspi_interrupt(int irq, void *dev_id) | 514 | static irqreturn_t dspi_interrupt(int irq, void *dev_id) |
461 | { | 515 | { |
462 | struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id; | 516 | struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id; |
463 | |||
464 | struct spi_message *msg = dspi->cur_msg; | 517 | struct spi_message *msg = dspi->cur_msg; |
465 | 518 | enum dspi_trans_mode trans_mode; | |
466 | regmap_write(dspi->regmap, SPI_SR, SPI_SR_EOQF); | 519 | u32 spi_sr; |
467 | dspi_transfer_read(dspi); | 520 | |
521 | regmap_read(dspi->regmap, SPI_SR, &spi_sr); | ||
522 | regmap_write(dspi->regmap, SPI_SR, spi_sr); | ||
523 | |||
524 | trans_mode = dspi->devtype_data->trans_mode; | ||
525 | switch (trans_mode) { | ||
526 | case DSPI_EOQ_MODE: | ||
527 | dspi_eoq_read(dspi); | ||
528 | break; | ||
529 | case DSPI_TCFQ_MODE: | ||
530 | dspi_tcfq_read(dspi); | ||
531 | break; | ||
532 | default: | ||
533 | dev_err(&dspi->pdev->dev, "unsupported trans_mode %u\n", | ||
534 | trans_mode); | ||
535 | return IRQ_HANDLED; | ||
536 | } | ||
468 | 537 | ||
469 | if (!dspi->len) { | 538 | if (!dspi->len) { |
470 | if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM) | 539 | if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM) { |
471 | regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs), | 540 | regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs), |
472 | SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(16)); | 541 | SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(16)); |
542 | dspi->dataflags &= ~TRAN_STATE_WORD_ODD_NUM; | ||
543 | } | ||
473 | 544 | ||
474 | dspi->waitflags = 1; | 545 | dspi->waitflags = 1; |
475 | wake_up_interruptible(&dspi->waitq); | 546 | wake_up_interruptible(&dspi->waitq); |
476 | } else | 547 | } else { |
477 | msg->actual_length += dspi_transfer_write(dspi); | 548 | switch (trans_mode) { |
478 | 549 | case DSPI_EOQ_MODE: | |
550 | msg->actual_length += dspi_eoq_write(dspi); | ||
551 | break; | ||
552 | case DSPI_TCFQ_MODE: | ||
553 | msg->actual_length += dspi_tcfq_write(dspi); | ||
554 | break; | ||
555 | default: | ||
556 | dev_err(&dspi->pdev->dev, "unsupported trans_mode %u\n", | ||
557 | trans_mode); | ||
558 | } | ||
559 | } | ||
479 | return IRQ_HANDLED; | 560 | return IRQ_HANDLED; |
480 | } | 561 | } |
481 | 562 | ||
482 | static const struct of_device_id fsl_dspi_dt_ids[] = { | 563 | static const struct of_device_id fsl_dspi_dt_ids[] = { |
483 | { .compatible = "fsl,vf610-dspi", .data = NULL, }, | 564 | { .compatible = "fsl,vf610-dspi", .data = (void *)&vf610_data, }, |
565 | { .compatible = "fsl,ls1021a-v1.0-dspi", | ||
566 | .data = (void *)&ls1021a_v1_data, }, | ||
567 | { .compatible = "fsl,ls2085a-dspi", .data = (void *)&ls2085a_data, }, | ||
484 | { /* sentinel */ } | 568 | { /* sentinel */ } |
485 | }; | 569 | }; |
486 | MODULE_DEVICE_TABLE(of, fsl_dspi_dt_ids); | 570 | MODULE_DEVICE_TABLE(of, fsl_dspi_dt_ids); |
@@ -526,6 +610,8 @@ static int dspi_probe(struct platform_device *pdev) | |||
526 | struct resource *res; | 610 | struct resource *res; |
527 | void __iomem *base; | 611 | void __iomem *base; |
528 | int ret = 0, cs_num, bus_num; | 612 | int ret = 0, cs_num, bus_num; |
613 | const struct of_device_id *of_id = | ||
614 | of_match_device(fsl_dspi_dt_ids, &pdev->dev); | ||
529 | 615 | ||
530 | master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi)); | 616 | master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi)); |
531 | if (!master) | 617 | if (!master) |
@@ -559,6 +645,13 @@ static int dspi_probe(struct platform_device *pdev) | |||
559 | } | 645 | } |
560 | master->bus_num = bus_num; | 646 | master->bus_num = bus_num; |
561 | 647 | ||
648 | dspi->devtype_data = (struct fsl_dspi_devtype_data *)of_id->data; | ||
649 | if (!dspi->devtype_data) { | ||
650 | dev_err(&pdev->dev, "can't get devtype_data\n"); | ||
651 | ret = -EFAULT; | ||
652 | goto out_master_put; | ||
653 | } | ||
654 | |||
562 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 655 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
563 | base = devm_ioremap_resource(&pdev->dev, res); | 656 | base = devm_ioremap_resource(&pdev->dev, res); |
564 | if (IS_ERR(base)) { | 657 | if (IS_ERR(base)) { |