diff options
author | Hisashi Nakamura <hisashi.nakamura.ak@renesas.com> | 2017-05-22 09:11:43 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2017-05-26 08:11:54 -0400 |
commit | cf9e4784f3bde3e4749163384f27450ddffe746c (patch) | |
tree | a4047eb127979d77db50eea2930faf6cff4f78e0 | |
parent | aa2ea9115bc3f0735aa65b833076cc5fe3da1489 (diff) |
spi: sh-msiof: Add slave mode support
Add slave mode support to the MSIOF driver, in both PIO and DMA mode.
For now this only supports the transmission of messages with a size
that is known in advance.
Signed-off-by: Hisashi Nakamura <hisashi.nakamura.ak@renesas.com>
Signed-off-by: Hiromitsu Yamasaki <hiromitsu.yamasaki.ym@renesas.com>
[geert: Timeout handling cleanup, spi core integration, cancellation,
rewording]
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | Documentation/devicetree/bindings/spi/sh-msiof.txt | 2 | ||||
-rw-r--r-- | drivers/spi/spi-sh-msiof.c | 111 | ||||
-rw-r--r-- | include/linux/spi/sh_msiof.h | 6 |
3 files changed, 86 insertions, 33 deletions
diff --git a/Documentation/devicetree/bindings/spi/sh-msiof.txt b/Documentation/devicetree/bindings/spi/sh-msiof.txt index dc975064fa27..64ee489571c4 100644 --- a/Documentation/devicetree/bindings/spi/sh-msiof.txt +++ b/Documentation/devicetree/bindings/spi/sh-msiof.txt | |||
@@ -38,6 +38,8 @@ Optional properties: | |||
38 | specifiers, one for transmission, and one for | 38 | specifiers, one for transmission, and one for |
39 | reception. | 39 | reception. |
40 | - dma-names : Must contain a list of two DMA names, "tx" and "rx". | 40 | - dma-names : Must contain a list of two DMA names, "tx" and "rx". |
41 | - spi-slave : Empty property indicating the SPI controller is used | ||
42 | in slave mode. | ||
41 | - renesas,dtdl : delay sync signal (setup) in transmit mode. | 43 | - renesas,dtdl : delay sync signal (setup) in transmit mode. |
42 | Must contain one of the following values: | 44 | Must contain one of the following values: |
43 | 0 (no bit delay) | 45 | 0 (no bit delay) |
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 2ce15ca97782..c304c7167866 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c | |||
@@ -2,7 +2,8 @@ | |||
2 | * SuperH MSIOF SPI Master Interface | 2 | * SuperH MSIOF SPI Master Interface |
3 | * | 3 | * |
4 | * Copyright (c) 2009 Magnus Damm | 4 | * Copyright (c) 2009 Magnus Damm |
5 | * Copyright (C) 2014 Glider bvba | 5 | * Copyright (C) 2014 Renesas Electronics Corporation |
6 | * Copyright (C) 2014-2017 Glider bvba | ||
6 | * | 7 | * |
7 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
@@ -33,7 +34,6 @@ | |||
33 | 34 | ||
34 | #include <asm/unaligned.h> | 35 | #include <asm/unaligned.h> |
35 | 36 | ||
36 | |||
37 | struct sh_msiof_chipdata { | 37 | struct sh_msiof_chipdata { |
38 | u16 tx_fifo_size; | 38 | u16 tx_fifo_size; |
39 | u16 rx_fifo_size; | 39 | u16 rx_fifo_size; |
@@ -53,6 +53,7 @@ struct sh_msiof_spi_priv { | |||
53 | void *rx_dma_page; | 53 | void *rx_dma_page; |
54 | dma_addr_t tx_dma_addr; | 54 | dma_addr_t tx_dma_addr; |
55 | dma_addr_t rx_dma_addr; | 55 | dma_addr_t rx_dma_addr; |
56 | bool slave_aborted; | ||
56 | }; | 57 | }; |
57 | 58 | ||
58 | #define TMDR1 0x00 /* Transmit Mode Register 1 */ | 59 | #define TMDR1 0x00 /* Transmit Mode Register 1 */ |
@@ -337,7 +338,10 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, | |||
337 | tmp |= !cs_high << MDR1_SYNCAC_SHIFT; | 338 | tmp |= !cs_high << MDR1_SYNCAC_SHIFT; |
338 | tmp |= lsb_first << MDR1_BITLSB_SHIFT; | 339 | tmp |= lsb_first << MDR1_BITLSB_SHIFT; |
339 | tmp |= sh_msiof_spi_get_dtdl_and_syncdl(p); | 340 | tmp |= sh_msiof_spi_get_dtdl_and_syncdl(p); |
340 | sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON); | 341 | if (spi_controller_is_slave(p->master)) |
342 | sh_msiof_write(p, TMDR1, tmp | TMDR1_PCON); | ||
343 | else | ||
344 | sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON); | ||
341 | if (p->master->flags & SPI_MASTER_MUST_TX) { | 345 | if (p->master->flags & SPI_MASTER_MUST_TX) { |
342 | /* These bits are reserved if RX needs TX */ | 346 | /* These bits are reserved if RX needs TX */ |
343 | tmp &= ~0x0000ffff; | 347 | tmp &= ~0x0000ffff; |
@@ -564,17 +568,19 @@ static int sh_msiof_prepare_message(struct spi_master *master, | |||
564 | 568 | ||
565 | static int sh_msiof_spi_start(struct sh_msiof_spi_priv *p, void *rx_buf) | 569 | static int sh_msiof_spi_start(struct sh_msiof_spi_priv *p, void *rx_buf) |
566 | { | 570 | { |
567 | int ret; | 571 | bool slave = spi_controller_is_slave(p->master); |
572 | int ret = 0; | ||
568 | 573 | ||
569 | /* setup clock and rx/tx signals */ | 574 | /* setup clock and rx/tx signals */ |
570 | ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TSCKE); | 575 | if (!slave) |
576 | ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TSCKE); | ||
571 | if (rx_buf && !ret) | 577 | if (rx_buf && !ret) |
572 | ret = sh_msiof_modify_ctr_wait(p, 0, CTR_RXE); | 578 | ret = sh_msiof_modify_ctr_wait(p, 0, CTR_RXE); |
573 | if (!ret) | 579 | if (!ret) |
574 | ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TXE); | 580 | ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TXE); |
575 | 581 | ||
576 | /* start by setting frame bit */ | 582 | /* start by setting frame bit */ |
577 | if (!ret) | 583 | if (!ret && !slave) |
578 | ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TFSE); | 584 | ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TFSE); |
579 | 585 | ||
580 | return ret; | 586 | return ret; |
@@ -582,20 +588,49 @@ static int sh_msiof_spi_start(struct sh_msiof_spi_priv *p, void *rx_buf) | |||
582 | 588 | ||
583 | static int sh_msiof_spi_stop(struct sh_msiof_spi_priv *p, void *rx_buf) | 589 | static int sh_msiof_spi_stop(struct sh_msiof_spi_priv *p, void *rx_buf) |
584 | { | 590 | { |
585 | int ret; | 591 | bool slave = spi_controller_is_slave(p->master); |
592 | int ret = 0; | ||
586 | 593 | ||
587 | /* shut down frame, rx/tx and clock signals */ | 594 | /* shut down frame, rx/tx and clock signals */ |
588 | ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0); | 595 | if (!slave) |
596 | ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0); | ||
589 | if (!ret) | 597 | if (!ret) |
590 | ret = sh_msiof_modify_ctr_wait(p, CTR_TXE, 0); | 598 | ret = sh_msiof_modify_ctr_wait(p, CTR_TXE, 0); |
591 | if (rx_buf && !ret) | 599 | if (rx_buf && !ret) |
592 | ret = sh_msiof_modify_ctr_wait(p, CTR_RXE, 0); | 600 | ret = sh_msiof_modify_ctr_wait(p, CTR_RXE, 0); |
593 | if (!ret) | 601 | if (!ret && !slave) |
594 | ret = sh_msiof_modify_ctr_wait(p, CTR_TSCKE, 0); | 602 | ret = sh_msiof_modify_ctr_wait(p, CTR_TSCKE, 0); |
595 | 603 | ||
596 | return ret; | 604 | return ret; |
597 | } | 605 | } |
598 | 606 | ||
607 | static int sh_msiof_slave_abort(struct spi_master *master) | ||
608 | { | ||
609 | struct sh_msiof_spi_priv *p = spi_master_get_devdata(master); | ||
610 | |||
611 | p->slave_aborted = true; | ||
612 | complete(&p->done); | ||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | static int sh_msiof_wait_for_completion(struct sh_msiof_spi_priv *p) | ||
617 | { | ||
618 | if (spi_controller_is_slave(p->master)) { | ||
619 | if (wait_for_completion_interruptible(&p->done) || | ||
620 | p->slave_aborted) { | ||
621 | dev_dbg(&p->pdev->dev, "interrupted\n"); | ||
622 | return -EINTR; | ||
623 | } | ||
624 | } else { | ||
625 | if (!wait_for_completion_timeout(&p->done, HZ)) { | ||
626 | dev_err(&p->pdev->dev, "timeout\n"); | ||
627 | return -ETIMEDOUT; | ||
628 | } | ||
629 | } | ||
630 | |||
631 | return 0; | ||
632 | } | ||
633 | |||
599 | static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, | 634 | static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, |
600 | void (*tx_fifo)(struct sh_msiof_spi_priv *, | 635 | void (*tx_fifo)(struct sh_msiof_spi_priv *, |
601 | const void *, int, int), | 636 | const void *, int, int), |
@@ -628,6 +663,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, | |||
628 | tx_fifo(p, tx_buf, words, fifo_shift); | 663 | tx_fifo(p, tx_buf, words, fifo_shift); |
629 | 664 | ||
630 | reinit_completion(&p->done); | 665 | reinit_completion(&p->done); |
666 | p->slave_aborted = false; | ||
631 | 667 | ||
632 | ret = sh_msiof_spi_start(p, rx_buf); | 668 | ret = sh_msiof_spi_start(p, rx_buf); |
633 | if (ret) { | 669 | if (ret) { |
@@ -636,11 +672,9 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, | |||
636 | } | 672 | } |
637 | 673 | ||
638 | /* wait for tx fifo to be emptied / rx fifo to be filled */ | 674 | /* wait for tx fifo to be emptied / rx fifo to be filled */ |
639 | if (!wait_for_completion_timeout(&p->done, HZ)) { | 675 | ret = sh_msiof_wait_for_completion(p); |
640 | dev_err(&p->pdev->dev, "PIO timeout\n"); | 676 | if (ret) |
641 | ret = -ETIMEDOUT; | ||
642 | goto stop_reset; | 677 | goto stop_reset; |
643 | } | ||
644 | 678 | ||
645 | /* read rx fifo */ | 679 | /* read rx fifo */ |
646 | if (rx_buf) | 680 | if (rx_buf) |
@@ -732,6 +766,7 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, | |||
732 | sh_msiof_write(p, IER, ier_bits); | 766 | sh_msiof_write(p, IER, ier_bits); |
733 | 767 | ||
734 | reinit_completion(&p->done); | 768 | reinit_completion(&p->done); |
769 | p->slave_aborted = false; | ||
735 | 770 | ||
736 | /* Now start DMA */ | 771 | /* Now start DMA */ |
737 | if (rx) | 772 | if (rx) |
@@ -746,11 +781,9 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, | |||
746 | } | 781 | } |
747 | 782 | ||
748 | /* wait for tx fifo to be emptied / rx fifo to be filled */ | 783 | /* wait for tx fifo to be emptied / rx fifo to be filled */ |
749 | if (!wait_for_completion_timeout(&p->done, HZ)) { | 784 | ret = sh_msiof_wait_for_completion(p); |
750 | dev_err(&p->pdev->dev, "DMA timeout\n"); | 785 | if (ret) |
751 | ret = -ETIMEDOUT; | ||
752 | goto stop_reset; | 786 | goto stop_reset; |
753 | } | ||
754 | 787 | ||
755 | /* clear status bits */ | 788 | /* clear status bits */ |
756 | sh_msiof_reset_str(p); | 789 | sh_msiof_reset_str(p); |
@@ -843,7 +876,8 @@ static int sh_msiof_transfer_one(struct spi_master *master, | |||
843 | int ret; | 876 | int ret; |
844 | 877 | ||
845 | /* setup clocks (clock already enabled in chipselect()) */ | 878 | /* setup clocks (clock already enabled in chipselect()) */ |
846 | sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), t->speed_hz); | 879 | if (!spi_controller_is_slave(p->master)) |
880 | sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), t->speed_hz); | ||
847 | 881 | ||
848 | while (master->dma_tx && len > 15) { | 882 | while (master->dma_tx && len > 15) { |
849 | /* | 883 | /* |
@@ -998,8 +1032,12 @@ static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev) | |||
998 | if (!info) | 1032 | if (!info) |
999 | return NULL; | 1033 | return NULL; |
1000 | 1034 | ||
1035 | info->mode = of_property_read_bool(np, "spi-slave") ? MSIOF_SPI_SLAVE | ||
1036 | : MSIOF_SPI_MASTER; | ||
1037 | |||
1001 | /* Parse the MSIOF properties */ | 1038 | /* Parse the MSIOF properties */ |
1002 | of_property_read_u32(np, "num-cs", &num_cs); | 1039 | if (info->mode == MSIOF_SPI_MASTER) |
1040 | of_property_read_u32(np, "num-cs", &num_cs); | ||
1003 | of_property_read_u32(np, "renesas,tx-fifo-size", | 1041 | of_property_read_u32(np, "renesas,tx-fifo-size", |
1004 | &info->tx_fifo_override); | 1042 | &info->tx_fifo_override); |
1005 | of_property_read_u32(np, "renesas,rx-fifo-size", | 1043 | of_property_read_u32(np, "renesas,rx-fifo-size", |
@@ -1159,34 +1197,40 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) | |||
1159 | struct spi_master *master; | 1197 | struct spi_master *master; |
1160 | const struct sh_msiof_chipdata *chipdata; | 1198 | const struct sh_msiof_chipdata *chipdata; |
1161 | const struct of_device_id *of_id; | 1199 | const struct of_device_id *of_id; |
1200 | struct sh_msiof_spi_info *info; | ||
1162 | struct sh_msiof_spi_priv *p; | 1201 | struct sh_msiof_spi_priv *p; |
1163 | int i; | 1202 | int i; |
1164 | int ret; | 1203 | int ret; |
1165 | 1204 | ||
1166 | master = spi_alloc_master(&pdev->dev, sizeof(struct sh_msiof_spi_priv)); | ||
1167 | if (master == NULL) | ||
1168 | return -ENOMEM; | ||
1169 | |||
1170 | p = spi_master_get_devdata(master); | ||
1171 | |||
1172 | platform_set_drvdata(pdev, p); | ||
1173 | p->master = master; | ||
1174 | |||
1175 | of_id = of_match_device(sh_msiof_match, &pdev->dev); | 1205 | of_id = of_match_device(sh_msiof_match, &pdev->dev); |
1176 | if (of_id) { | 1206 | if (of_id) { |
1177 | chipdata = of_id->data; | 1207 | chipdata = of_id->data; |
1178 | p->info = sh_msiof_spi_parse_dt(&pdev->dev); | 1208 | info = sh_msiof_spi_parse_dt(&pdev->dev); |
1179 | } else { | 1209 | } else { |
1180 | chipdata = (const void *)pdev->id_entry->driver_data; | 1210 | chipdata = (const void *)pdev->id_entry->driver_data; |
1181 | p->info = dev_get_platdata(&pdev->dev); | 1211 | info = dev_get_platdata(&pdev->dev); |
1182 | } | 1212 | } |
1183 | 1213 | ||
1184 | if (!p->info) { | 1214 | if (!info) { |
1185 | dev_err(&pdev->dev, "failed to obtain device info\n"); | 1215 | dev_err(&pdev->dev, "failed to obtain device info\n"); |
1186 | ret = -ENXIO; | 1216 | return -ENXIO; |
1187 | goto err1; | ||
1188 | } | 1217 | } |
1189 | 1218 | ||
1219 | if (info->mode == MSIOF_SPI_SLAVE) | ||
1220 | master = spi_alloc_slave(&pdev->dev, | ||
1221 | sizeof(struct sh_msiof_spi_priv)); | ||
1222 | else | ||
1223 | master = spi_alloc_master(&pdev->dev, | ||
1224 | sizeof(struct sh_msiof_spi_priv)); | ||
1225 | if (master == NULL) | ||
1226 | return -ENOMEM; | ||
1227 | |||
1228 | p = spi_master_get_devdata(master); | ||
1229 | |||
1230 | platform_set_drvdata(pdev, p); | ||
1231 | p->master = master; | ||
1232 | p->info = info; | ||
1233 | |||
1190 | init_completion(&p->done); | 1234 | init_completion(&p->done); |
1191 | 1235 | ||
1192 | p->clk = devm_clk_get(&pdev->dev, NULL); | 1236 | p->clk = devm_clk_get(&pdev->dev, NULL); |
@@ -1237,6 +1281,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) | |||
1237 | master->num_chipselect = p->info->num_chipselect; | 1281 | master->num_chipselect = p->info->num_chipselect; |
1238 | master->setup = sh_msiof_spi_setup; | 1282 | master->setup = sh_msiof_spi_setup; |
1239 | master->prepare_message = sh_msiof_prepare_message; | 1283 | master->prepare_message = sh_msiof_prepare_message; |
1284 | master->slave_abort = sh_msiof_slave_abort; | ||
1240 | master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32); | 1285 | master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32); |
1241 | master->auto_runtime_pm = true; | 1286 | master->auto_runtime_pm = true; |
1242 | master->transfer_one = sh_msiof_transfer_one; | 1287 | master->transfer_one = sh_msiof_transfer_one; |
diff --git a/include/linux/spi/sh_msiof.h b/include/linux/spi/sh_msiof.h index b087a85f5f72..f74b581f242f 100644 --- a/include/linux/spi/sh_msiof.h +++ b/include/linux/spi/sh_msiof.h | |||
@@ -1,10 +1,16 @@ | |||
1 | #ifndef __SPI_SH_MSIOF_H__ | 1 | #ifndef __SPI_SH_MSIOF_H__ |
2 | #define __SPI_SH_MSIOF_H__ | 2 | #define __SPI_SH_MSIOF_H__ |
3 | 3 | ||
4 | enum { | ||
5 | MSIOF_SPI_MASTER, | ||
6 | MSIOF_SPI_SLAVE, | ||
7 | }; | ||
8 | |||
4 | struct sh_msiof_spi_info { | 9 | struct sh_msiof_spi_info { |
5 | int tx_fifo_override; | 10 | int tx_fifo_override; |
6 | int rx_fifo_override; | 11 | int rx_fifo_override; |
7 | u16 num_chipselect; | 12 | u16 num_chipselect; |
13 | int mode; | ||
8 | unsigned int dma_tx_id; | 14 | unsigned int dma_tx_id; |
9 | unsigned int dma_rx_id; | 15 | unsigned int dma_rx_id; |
10 | u32 dtdl; | 16 | u32 dtdl; |