diff options
author | Bryan Wu <bryan.wu@analog.com> | 2007-12-05 02:45:14 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-12-05 12:21:19 -0500 |
commit | fad91c890909aabab0d9858d50f3c8394ee16b21 (patch) | |
tree | ff3a82c58e5fbd5c91756ad0846ef31555c08054 /drivers | |
parent | 5fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736 (diff) |
spi: spi_bfin handles spi_transfer.cs_change
Respect per-transfer cs_change field (protocol tweaking support) by
adding and using cs_active/cs_deactive functions.
Signed-off-by: Bryan Wu <bryan.wu@analog.com>
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/spi/spi_bfin5xx.c | 76 |
1 files changed, 54 insertions, 22 deletions
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 803c5b25db50..c2d51cf3c639 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c | |||
@@ -115,6 +115,7 @@ struct driver_data { | |||
115 | size_t rx_map_len; | 115 | size_t rx_map_len; |
116 | size_t tx_map_len; | 116 | size_t tx_map_len; |
117 | u8 n_bytes; | 117 | u8 n_bytes; |
118 | int cs_change; | ||
118 | void (*write) (struct driver_data *); | 119 | void (*write) (struct driver_data *); |
119 | void (*read) (struct driver_data *); | 120 | void (*read) (struct driver_data *); |
120 | void (*duplex) (struct driver_data *); | 121 | void (*duplex) (struct driver_data *); |
@@ -179,6 +180,26 @@ static int flush(struct driver_data *drv_data) | |||
179 | return limit; | 180 | return limit; |
180 | } | 181 | } |
181 | 182 | ||
183 | /* Chip select operation functions for cs_change flag */ | ||
184 | static void cs_active(struct chip_data *chip) | ||
185 | { | ||
186 | u16 flag = read_FLAG(); | ||
187 | |||
188 | flag |= chip->flag; | ||
189 | flag &= ~(chip->flag << 8); | ||
190 | |||
191 | write_FLAG(flag); | ||
192 | } | ||
193 | |||
194 | static void cs_deactive(struct chip_data *chip) | ||
195 | { | ||
196 | u16 flag = read_FLAG(); | ||
197 | |||
198 | flag |= (chip->flag << 8); | ||
199 | |||
200 | write_FLAG(flag); | ||
201 | } | ||
202 | |||
182 | #define MAX_SPI0_SSEL 7 | 203 | #define MAX_SPI0_SSEL 7 |
183 | 204 | ||
184 | /* stop controller and re-config current chip*/ | 205 | /* stop controller and re-config current chip*/ |
@@ -198,7 +219,7 @@ static int restore_state(struct driver_data *drv_data) | |||
198 | /* Load the registers */ | 219 | /* Load the registers */ |
199 | write_CTRL(chip->ctl_reg); | 220 | write_CTRL(chip->ctl_reg); |
200 | write_BAUD(chip->baud); | 221 | write_BAUD(chip->baud); |
201 | write_FLAG(chip->flag); | 222 | cs_active(chip); |
202 | 223 | ||
203 | if (!chip->chip_select_requested) { | 224 | if (!chip->chip_select_requested) { |
204 | int i = chip->chip_select_num; | 225 | int i = chip->chip_select_num; |
@@ -273,20 +294,20 @@ static void u8_cs_chg_writer(struct driver_data *drv_data) | |||
273 | struct chip_data *chip = drv_data->cur_chip; | 294 | struct chip_data *chip = drv_data->cur_chip; |
274 | 295 | ||
275 | while (drv_data->tx < drv_data->tx_end) { | 296 | while (drv_data->tx < drv_data->tx_end) { |
276 | write_FLAG(chip->flag); | 297 | cs_active(chip); |
277 | 298 | ||
278 | write_TDBR(*(u8 *) (drv_data->tx)); | 299 | write_TDBR(*(u8 *) (drv_data->tx)); |
279 | while (read_STAT() & BIT_STAT_TXS) | 300 | while (read_STAT() & BIT_STAT_TXS) |
280 | continue; | 301 | continue; |
281 | while (!(read_STAT() & BIT_STAT_SPIF)) | 302 | while (!(read_STAT() & BIT_STAT_SPIF)) |
282 | continue; | 303 | continue; |
283 | write_FLAG(0xFF00 | chip->flag); | 304 | cs_deactive(chip); |
284 | 305 | ||
285 | if (chip->cs_chg_udelay) | 306 | if (chip->cs_chg_udelay) |
286 | udelay(chip->cs_chg_udelay); | 307 | udelay(chip->cs_chg_udelay); |
287 | ++drv_data->tx; | 308 | ++drv_data->tx; |
288 | } | 309 | } |
289 | write_FLAG(0xFF00); | 310 | cs_deactive(chip); |
290 | 311 | ||
291 | } | 312 | } |
292 | 313 | ||
@@ -318,7 +339,7 @@ static void u8_cs_chg_reader(struct driver_data *drv_data) | |||
318 | struct chip_data *chip = drv_data->cur_chip; | 339 | struct chip_data *chip = drv_data->cur_chip; |
319 | 340 | ||
320 | while (drv_data->rx < drv_data->rx_end) { | 341 | while (drv_data->rx < drv_data->rx_end) { |
321 | write_FLAG(chip->flag); | 342 | cs_active(chip); |
322 | 343 | ||
323 | read_RDBR(); /* kick off */ | 344 | read_RDBR(); /* kick off */ |
324 | while (!(read_STAT() & BIT_STAT_RXS)) | 345 | while (!(read_STAT() & BIT_STAT_RXS)) |
@@ -326,13 +347,13 @@ static void u8_cs_chg_reader(struct driver_data *drv_data) | |||
326 | while (!(read_STAT() & BIT_STAT_SPIF)) | 347 | while (!(read_STAT() & BIT_STAT_SPIF)) |
327 | continue; | 348 | continue; |
328 | *(u8 *) (drv_data->rx) = read_SHAW(); | 349 | *(u8 *) (drv_data->rx) = read_SHAW(); |
329 | write_FLAG(0xFF00 | chip->flag); | 350 | cs_deactive(chip); |
330 | 351 | ||
331 | if (chip->cs_chg_udelay) | 352 | if (chip->cs_chg_udelay) |
332 | udelay(chip->cs_chg_udelay); | 353 | udelay(chip->cs_chg_udelay); |
333 | ++drv_data->rx; | 354 | ++drv_data->rx; |
334 | } | 355 | } |
335 | write_FLAG(0xFF00); | 356 | cs_deactive(chip); |
336 | 357 | ||
337 | } | 358 | } |
338 | 359 | ||
@@ -356,7 +377,7 @@ static void u8_cs_chg_duplex(struct driver_data *drv_data) | |||
356 | struct chip_data *chip = drv_data->cur_chip; | 377 | struct chip_data *chip = drv_data->cur_chip; |
357 | 378 | ||
358 | while (drv_data->rx < drv_data->rx_end) { | 379 | while (drv_data->rx < drv_data->rx_end) { |
359 | write_FLAG(chip->flag); | 380 | cs_active(chip); |
360 | 381 | ||
361 | 382 | ||
362 | write_TDBR(*(u8 *) (drv_data->tx)); | 383 | write_TDBR(*(u8 *) (drv_data->tx)); |
@@ -365,15 +386,14 @@ static void u8_cs_chg_duplex(struct driver_data *drv_data) | |||
365 | while (!(read_STAT() & BIT_STAT_RXS)) | 386 | while (!(read_STAT() & BIT_STAT_RXS)) |
366 | continue; | 387 | continue; |
367 | *(u8 *) (drv_data->rx) = read_RDBR(); | 388 | *(u8 *) (drv_data->rx) = read_RDBR(); |
368 | write_FLAG(0xFF00 | chip->flag); | 389 | cs_deactive(chip); |
369 | 390 | ||
370 | if (chip->cs_chg_udelay) | 391 | if (chip->cs_chg_udelay) |
371 | udelay(chip->cs_chg_udelay); | 392 | udelay(chip->cs_chg_udelay); |
372 | ++drv_data->rx; | 393 | ++drv_data->rx; |
373 | ++drv_data->tx; | 394 | ++drv_data->tx; |
374 | } | 395 | } |
375 | write_FLAG(0xFF00); | 396 | cs_deactive(chip); |
376 | |||
377 | } | 397 | } |
378 | 398 | ||
379 | static void u16_writer(struct driver_data *drv_data) | 399 | static void u16_writer(struct driver_data *drv_data) |
@@ -398,20 +418,20 @@ static void u16_cs_chg_writer(struct driver_data *drv_data) | |||
398 | struct chip_data *chip = drv_data->cur_chip; | 418 | struct chip_data *chip = drv_data->cur_chip; |
399 | 419 | ||
400 | while (drv_data->tx < drv_data->tx_end) { | 420 | while (drv_data->tx < drv_data->tx_end) { |
401 | write_FLAG(chip->flag); | 421 | cs_active(chip); |
402 | 422 | ||
403 | write_TDBR(*(u16 *) (drv_data->tx)); | 423 | write_TDBR(*(u16 *) (drv_data->tx)); |
404 | while ((read_STAT() & BIT_STAT_TXS)) | 424 | while ((read_STAT() & BIT_STAT_TXS)) |
405 | continue; | 425 | continue; |
406 | while (!(read_STAT() & BIT_STAT_SPIF)) | 426 | while (!(read_STAT() & BIT_STAT_SPIF)) |
407 | continue; | 427 | continue; |
408 | write_FLAG(0xFF00 | chip->flag); | 428 | cs_deactive(chip); |
409 | 429 | ||
410 | if (chip->cs_chg_udelay) | 430 | if (chip->cs_chg_udelay) |
411 | udelay(chip->cs_chg_udelay); | 431 | udelay(chip->cs_chg_udelay); |
412 | drv_data->tx += 2; | 432 | drv_data->tx += 2; |
413 | } | 433 | } |
414 | write_FLAG(0xFF00); | 434 | cs_deactive(chip); |
415 | } | 435 | } |
416 | 436 | ||
417 | static void u16_reader(struct driver_data *drv_data) | 437 | static void u16_reader(struct driver_data *drv_data) |
@@ -438,7 +458,7 @@ static void u16_cs_chg_reader(struct driver_data *drv_data) | |||
438 | struct chip_data *chip = drv_data->cur_chip; | 458 | struct chip_data *chip = drv_data->cur_chip; |
439 | 459 | ||
440 | while (drv_data->rx < drv_data->rx_end) { | 460 | while (drv_data->rx < drv_data->rx_end) { |
441 | write_FLAG(chip->flag); | 461 | cs_active(chip); |
442 | 462 | ||
443 | read_RDBR(); /* kick off */ | 463 | read_RDBR(); /* kick off */ |
444 | while (!(read_STAT() & BIT_STAT_RXS)) | 464 | while (!(read_STAT() & BIT_STAT_RXS)) |
@@ -446,13 +466,13 @@ static void u16_cs_chg_reader(struct driver_data *drv_data) | |||
446 | while (!(read_STAT() & BIT_STAT_SPIF)) | 466 | while (!(read_STAT() & BIT_STAT_SPIF)) |
447 | continue; | 467 | continue; |
448 | *(u16 *) (drv_data->rx) = read_SHAW(); | 468 | *(u16 *) (drv_data->rx) = read_SHAW(); |
449 | write_FLAG(0xFF00 | chip->flag); | 469 | cs_deactive(chip); |
450 | 470 | ||
451 | if (chip->cs_chg_udelay) | 471 | if (chip->cs_chg_udelay) |
452 | udelay(chip->cs_chg_udelay); | 472 | udelay(chip->cs_chg_udelay); |
453 | drv_data->rx += 2; | 473 | drv_data->rx += 2; |
454 | } | 474 | } |
455 | write_FLAG(0xFF00); | 475 | cs_deactive(chip); |
456 | } | 476 | } |
457 | 477 | ||
458 | static void u16_duplex(struct driver_data *drv_data) | 478 | static void u16_duplex(struct driver_data *drv_data) |
@@ -475,7 +495,7 @@ static void u16_cs_chg_duplex(struct driver_data *drv_data) | |||
475 | struct chip_data *chip = drv_data->cur_chip; | 495 | struct chip_data *chip = drv_data->cur_chip; |
476 | 496 | ||
477 | while (drv_data->tx < drv_data->tx_end) { | 497 | while (drv_data->tx < drv_data->tx_end) { |
478 | write_FLAG(chip->flag); | 498 | cs_active(chip); |
479 | 499 | ||
480 | write_TDBR(*(u16 *) (drv_data->tx)); | 500 | write_TDBR(*(u16 *) (drv_data->tx)); |
481 | while (!(read_STAT() & BIT_STAT_SPIF)) | 501 | while (!(read_STAT() & BIT_STAT_SPIF)) |
@@ -483,14 +503,14 @@ static void u16_cs_chg_duplex(struct driver_data *drv_data) | |||
483 | while (!(read_STAT() & BIT_STAT_RXS)) | 503 | while (!(read_STAT() & BIT_STAT_RXS)) |
484 | continue; | 504 | continue; |
485 | *(u16 *) (drv_data->rx) = read_RDBR(); | 505 | *(u16 *) (drv_data->rx) = read_RDBR(); |
486 | write_FLAG(0xFF00 | chip->flag); | 506 | cs_deactive(chip); |
487 | 507 | ||
488 | if (chip->cs_chg_udelay) | 508 | if (chip->cs_chg_udelay) |
489 | udelay(chip->cs_chg_udelay); | 509 | udelay(chip->cs_chg_udelay); |
490 | drv_data->rx += 2; | 510 | drv_data->rx += 2; |
491 | drv_data->tx += 2; | 511 | drv_data->tx += 2; |
492 | } | 512 | } |
493 | write_FLAG(0xFF00); | 513 | cs_deactive(chip); |
494 | } | 514 | } |
495 | 515 | ||
496 | /* test if ther is more transfer to be done */ | 516 | /* test if ther is more transfer to be done */ |
@@ -515,6 +535,7 @@ static void *next_transfer(struct driver_data *drv_data) | |||
515 | */ | 535 | */ |
516 | static void giveback(struct driver_data *drv_data) | 536 | static void giveback(struct driver_data *drv_data) |
517 | { | 537 | { |
538 | struct chip_data *chip = drv_data->cur_chip; | ||
518 | struct spi_transfer *last_transfer; | 539 | struct spi_transfer *last_transfer; |
519 | unsigned long flags; | 540 | unsigned long flags; |
520 | struct spi_message *msg; | 541 | struct spi_message *msg; |
@@ -534,10 +555,13 @@ static void giveback(struct driver_data *drv_data) | |||
534 | 555 | ||
535 | /* disable chip select signal. And not stop spi in autobuffer mode */ | 556 | /* disable chip select signal. And not stop spi in autobuffer mode */ |
536 | if (drv_data->tx_dma != 0xFFFF) { | 557 | if (drv_data->tx_dma != 0xFFFF) { |
537 | write_FLAG(0xFF00); | 558 | cs_deactive(chip); |
538 | bfin_spi_disable(drv_data); | 559 | bfin_spi_disable(drv_data); |
539 | } | 560 | } |
540 | 561 | ||
562 | if (!drv_data->cs_change) | ||
563 | cs_deactive(chip); | ||
564 | |||
541 | if (msg->complete) | 565 | if (msg->complete) |
542 | msg->complete(msg->context); | 566 | msg->complete(msg->context); |
543 | } | 567 | } |
@@ -546,6 +570,7 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id) | |||
546 | { | 570 | { |
547 | struct driver_data *drv_data = (struct driver_data *)dev_id; | 571 | struct driver_data *drv_data = (struct driver_data *)dev_id; |
548 | struct spi_message *msg = drv_data->cur_msg; | 572 | struct spi_message *msg = drv_data->cur_msg; |
573 | struct chip_data *chip = drv_data->cur_chip; | ||
549 | 574 | ||
550 | dev_dbg(&drv_data->pdev->dev, "in dma_irq_handler\n"); | 575 | dev_dbg(&drv_data->pdev->dev, "in dma_irq_handler\n"); |
551 | clear_dma_irqstat(CH_SPI); | 576 | clear_dma_irqstat(CH_SPI); |
@@ -573,6 +598,9 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id) | |||
573 | 598 | ||
574 | msg->actual_length += drv_data->len_in_bytes; | 599 | msg->actual_length += drv_data->len_in_bytes; |
575 | 600 | ||
601 | if (drv_data->cs_change) | ||
602 | cs_deactive(chip); | ||
603 | |||
576 | /* Move to next transfer */ | 604 | /* Move to next transfer */ |
577 | msg->state = next_transfer(drv_data); | 605 | msg->state = next_transfer(drv_data); |
578 | 606 | ||
@@ -659,6 +687,7 @@ static void pump_transfers(unsigned long data) | |||
659 | drv_data->rx_dma = transfer->rx_dma; | 687 | drv_data->rx_dma = transfer->rx_dma; |
660 | drv_data->tx_dma = transfer->tx_dma; | 688 | drv_data->tx_dma = transfer->tx_dma; |
661 | drv_data->len_in_bytes = transfer->len; | 689 | drv_data->len_in_bytes = transfer->len; |
690 | drv_data->cs_change = transfer->cs_change; | ||
662 | 691 | ||
663 | width = chip->width; | 692 | width = chip->width; |
664 | if (width == CFG_SPI_WORDSIZE16) { | 693 | if (width == CFG_SPI_WORDSIZE16) { |
@@ -683,7 +712,7 @@ static void pump_transfers(unsigned long data) | |||
683 | } else { | 712 | } else { |
684 | write_BAUD(chip->baud); | 713 | write_BAUD(chip->baud); |
685 | } | 714 | } |
686 | write_FLAG(chip->flag); | 715 | cs_active(chip); |
687 | 716 | ||
688 | dev_dbg(&drv_data->pdev->dev, | 717 | dev_dbg(&drv_data->pdev->dev, |
689 | "now pumping a transfer: width is %d, len is %d\n", | 718 | "now pumping a transfer: width is %d, len is %d\n", |
@@ -834,6 +863,9 @@ static void pump_transfers(unsigned long data) | |||
834 | /* Update total byte transfered */ | 863 | /* Update total byte transfered */ |
835 | message->actual_length += drv_data->len; | 864 | message->actual_length += drv_data->len; |
836 | 865 | ||
866 | if (drv_data->cs_change) | ||
867 | cs_deactive(chip); | ||
868 | |||
837 | /* Move to next transfer of this msg */ | 869 | /* Move to next transfer of this msg */ |
838 | message->state = next_transfer(drv_data); | 870 | message->state = next_transfer(drv_data); |
839 | } | 871 | } |