diff options
author | Kamal Dasu <kdasu.kdev@gmail.com> | 2016-08-24 18:04:29 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2016-09-24 15:03:25 -0400 |
commit | cc20a38612dbc87dc7396affc9758e3bfbe92340 (patch) | |
tree | 3c8764494d7345d8ba1ef847a42000392727e135 | |
parent | 71b8f350a4f03730f3024bfa7dc2414904a21bcb (diff) |
spi: iproc-qspi: Add Broadcom iProc SoCs support
This spi driver uses the common spi-bcm-qspi driver and implements iProc
SoCs specific interrupt controller. The common driver now calls the SoC
handlers when present. Adding support for both muxed l1 and unmuxed interrupt
sources.
Signed-off-by: Kamal Dasu <kdasu.kdev@gmail.com>
Signed-off-by: Yendapally Reddy Dhananjaya Reddy <yendapally.reddy@broadcom.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | drivers/spi/Makefile | 2 | ||||
-rw-r--r-- | drivers/spi/spi-bcm-qspi.c | 97 | ||||
-rw-r--r-- | drivers/spi/spi-bcm-qspi.h | 34 | ||||
-rw-r--r-- | drivers/spi/spi-iproc-qspi.c | 163 |
4 files changed, 291 insertions, 5 deletions
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 3e753db484d4..2dc1b71706f9 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile | |||
@@ -21,7 +21,7 @@ obj-$(CONFIG_SPI_BCM2835AUX) += spi-bcm2835aux.o | |||
21 | obj-$(CONFIG_SPI_BCM53XX) += spi-bcm53xx.o | 21 | obj-$(CONFIG_SPI_BCM53XX) += spi-bcm53xx.o |
22 | obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o | 22 | obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o |
23 | obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o | 23 | obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o |
24 | obj-$(CONFIG_SPI_BCM_QSPI) += spi-brcmstb-qspi.o spi-bcm-qspi.o | 24 | obj-$(CONFIG_SPI_BCM_QSPI) += spi-iproc-qspi.o spi-brcmstb-qspi.o spi-bcm-qspi.o |
25 | obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o | 25 | obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o |
26 | obj-$(CONFIG_SPI_ADI_V3) += spi-adi-v3.o | 26 | obj-$(CONFIG_SPI_ADI_V3) += spi-adi-v3.o |
27 | obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o | 27 | obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o |
diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c index 2c121ba8f0cb..14f9dea3173f 100644 --- a/drivers/spi/spi-bcm-qspi.c +++ b/drivers/spi/spi-bcm-qspi.c | |||
@@ -175,9 +175,15 @@ enum base_type { | |||
175 | BASEMAX, | 175 | BASEMAX, |
176 | }; | 176 | }; |
177 | 177 | ||
178 | enum irq_source { | ||
179 | SINGLE_L2, | ||
180 | MUXED_L1, | ||
181 | }; | ||
182 | |||
178 | struct bcm_qspi_irq { | 183 | struct bcm_qspi_irq { |
179 | const char *irq_name; | 184 | const char *irq_name; |
180 | const irq_handler_t irq_handler; | 185 | const irq_handler_t irq_handler; |
186 | int irq_source; | ||
181 | u32 mask; | 187 | u32 mask; |
182 | }; | 188 | }; |
183 | 189 | ||
@@ -198,6 +204,10 @@ struct bcm_qspi { | |||
198 | u32 base_clk; | 204 | u32 base_clk; |
199 | u32 max_speed_hz; | 205 | u32 max_speed_hz; |
200 | void __iomem *base[BASEMAX]; | 206 | void __iomem *base[BASEMAX]; |
207 | |||
208 | /* Some SoCs provide custom interrupt status register(s) */ | ||
209 | struct bcm_qspi_soc_intc *soc_intc; | ||
210 | |||
201 | struct bcm_qspi_parms last_parms; | 211 | struct bcm_qspi_parms last_parms; |
202 | struct qspi_trans trans_pos; | 212 | struct qspi_trans trans_pos; |
203 | int curr_cs; | 213 | int curr_cs; |
@@ -806,6 +816,7 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi, | |||
806 | u32 addr = 0, len, len_words; | 816 | u32 addr = 0, len, len_words; |
807 | int ret = 0; | 817 | int ret = 0; |
808 | unsigned long timeo = msecs_to_jiffies(100); | 818 | unsigned long timeo = msecs_to_jiffies(100); |
819 | struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc; | ||
809 | 820 | ||
810 | if (bcm_qspi_bspi_ver_three(qspi)) | 821 | if (bcm_qspi_bspi_ver_three(qspi)) |
811 | if (msg->addr_width == BSPI_ADDRLEN_4BYTES) | 822 | if (msg->addr_width == BSPI_ADDRLEN_4BYTES) |
@@ -850,6 +861,15 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi, | |||
850 | bcm_qspi_write(qspi, BSPI, BSPI_RAF_NUM_WORDS, len_words); | 861 | bcm_qspi_write(qspi, BSPI, BSPI_RAF_NUM_WORDS, len_words); |
851 | bcm_qspi_write(qspi, BSPI, BSPI_RAF_WATERMARK, 0); | 862 | bcm_qspi_write(qspi, BSPI, BSPI_RAF_WATERMARK, 0); |
852 | 863 | ||
864 | if (qspi->soc_intc) { | ||
865 | /* | ||
866 | * clear soc MSPI and BSPI interrupts and enable | ||
867 | * BSPI interrupts. | ||
868 | */ | ||
869 | soc_intc->bcm_qspi_int_ack(soc_intc, MSPI_BSPI_DONE); | ||
870 | soc_intc->bcm_qspi_int_set(soc_intc, BSPI_DONE, true); | ||
871 | } | ||
872 | |||
853 | /* Must flush previous writes before starting BSPI operation */ | 873 | /* Must flush previous writes before starting BSPI operation */ |
854 | mb(); | 874 | mb(); |
855 | 875 | ||
@@ -952,9 +972,12 @@ static irqreturn_t bcm_qspi_mspi_l2_isr(int irq, void *dev_id) | |||
952 | u32 status = bcm_qspi_read(qspi, MSPI, MSPI_MSPI_STATUS); | 972 | u32 status = bcm_qspi_read(qspi, MSPI, MSPI_MSPI_STATUS); |
953 | 973 | ||
954 | if (status & MSPI_MSPI_STATUS_SPIF) { | 974 | if (status & MSPI_MSPI_STATUS_SPIF) { |
975 | struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc; | ||
955 | /* clear interrupt */ | 976 | /* clear interrupt */ |
956 | status &= ~MSPI_MSPI_STATUS_SPIF; | 977 | status &= ~MSPI_MSPI_STATUS_SPIF; |
957 | bcm_qspi_write(qspi, MSPI, MSPI_MSPI_STATUS, status); | 978 | bcm_qspi_write(qspi, MSPI, MSPI_MSPI_STATUS, status); |
979 | if (qspi->soc_intc) | ||
980 | soc_intc->bcm_qspi_int_ack(soc_intc, MSPI_DONE); | ||
958 | complete(&qspi->mspi_done); | 981 | complete(&qspi->mspi_done); |
959 | return IRQ_HANDLED; | 982 | return IRQ_HANDLED; |
960 | } | 983 | } |
@@ -966,20 +989,33 @@ static irqreturn_t bcm_qspi_bspi_lr_l2_isr(int irq, void *dev_id) | |||
966 | { | 989 | { |
967 | struct bcm_qspi_dev_id *qspi_dev_id = dev_id; | 990 | struct bcm_qspi_dev_id *qspi_dev_id = dev_id; |
968 | struct bcm_qspi *qspi = qspi_dev_id->dev; | 991 | struct bcm_qspi *qspi = qspi_dev_id->dev; |
969 | u32 status; | 992 | struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc; |
993 | u32 status = qspi_dev_id->irqp->mask; | ||
970 | 994 | ||
971 | if (qspi->bspi_enabled && qspi->bspi_rf_msg) { | 995 | if (qspi->bspi_enabled && qspi->bspi_rf_msg) { |
972 | bcm_qspi_bspi_lr_data_read(qspi); | 996 | bcm_qspi_bspi_lr_data_read(qspi); |
973 | if (qspi->bspi_rf_msg_len == 0) { | 997 | if (qspi->bspi_rf_msg_len == 0) { |
974 | qspi->bspi_rf_msg = NULL; | 998 | qspi->bspi_rf_msg = NULL; |
999 | if (qspi->soc_intc) { | ||
1000 | /* disable soc BSPI interrupt */ | ||
1001 | soc_intc->bcm_qspi_int_set(soc_intc, BSPI_DONE, | ||
1002 | false); | ||
1003 | /* indicate done */ | ||
1004 | status = INTR_BSPI_LR_SESSION_DONE_MASK; | ||
1005 | } | ||
1006 | |||
975 | if (qspi->bspi_rf_msg_status) | 1007 | if (qspi->bspi_rf_msg_status) |
976 | bcm_qspi_bspi_lr_clear(qspi); | 1008 | bcm_qspi_bspi_lr_clear(qspi); |
977 | else | 1009 | else |
978 | bcm_qspi_bspi_flush_prefetch_buffers(qspi); | 1010 | bcm_qspi_bspi_flush_prefetch_buffers(qspi); |
979 | } | 1011 | } |
1012 | |||
1013 | if (qspi->soc_intc) | ||
1014 | /* clear soc BSPI interrupt */ | ||
1015 | soc_intc->bcm_qspi_int_ack(soc_intc, BSPI_DONE); | ||
980 | } | 1016 | } |
981 | 1017 | ||
982 | status = (qspi_dev_id->irqp->mask & INTR_BSPI_LR_SESSION_DONE_MASK); | 1018 | status &= INTR_BSPI_LR_SESSION_DONE_MASK; |
983 | if (qspi->bspi_enabled && status && qspi->bspi_rf_msg_len == 0) | 1019 | if (qspi->bspi_enabled && status && qspi->bspi_rf_msg_len == 0) |
984 | complete(&qspi->bspi_done); | 1020 | complete(&qspi->bspi_done); |
985 | 1021 | ||
@@ -990,13 +1026,39 @@ static irqreturn_t bcm_qspi_bspi_lr_err_l2_isr(int irq, void *dev_id) | |||
990 | { | 1026 | { |
991 | struct bcm_qspi_dev_id *qspi_dev_id = dev_id; | 1027 | struct bcm_qspi_dev_id *qspi_dev_id = dev_id; |
992 | struct bcm_qspi *qspi = qspi_dev_id->dev; | 1028 | struct bcm_qspi *qspi = qspi_dev_id->dev; |
1029 | struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc; | ||
993 | 1030 | ||
994 | dev_err(&qspi->pdev->dev, "BSPI INT error\n"); | 1031 | dev_err(&qspi->pdev->dev, "BSPI INT error\n"); |
995 | qspi->bspi_rf_msg_status = -EIO; | 1032 | qspi->bspi_rf_msg_status = -EIO; |
1033 | if (qspi->soc_intc) | ||
1034 | /* clear soc interrupt */ | ||
1035 | soc_intc->bcm_qspi_int_ack(soc_intc, BSPI_ERR); | ||
1036 | |||
996 | complete(&qspi->bspi_done); | 1037 | complete(&qspi->bspi_done); |
997 | return IRQ_HANDLED; | 1038 | return IRQ_HANDLED; |
998 | } | 1039 | } |
999 | 1040 | ||
1041 | static irqreturn_t bcm_qspi_l1_isr(int irq, void *dev_id) | ||
1042 | { | ||
1043 | struct bcm_qspi_dev_id *qspi_dev_id = dev_id; | ||
1044 | struct bcm_qspi *qspi = qspi_dev_id->dev; | ||
1045 | struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc; | ||
1046 | irqreturn_t ret = IRQ_NONE; | ||
1047 | |||
1048 | if (soc_intc) { | ||
1049 | u32 status = soc_intc->bcm_qspi_get_int_status(soc_intc); | ||
1050 | |||
1051 | if (status & MSPI_DONE) | ||
1052 | ret = bcm_qspi_mspi_l2_isr(irq, dev_id); | ||
1053 | else if (status & BSPI_DONE) | ||
1054 | ret = bcm_qspi_bspi_lr_l2_isr(irq, dev_id); | ||
1055 | else if (status & BSPI_ERR) | ||
1056 | ret = bcm_qspi_bspi_lr_err_l2_isr(irq, dev_id); | ||
1057 | } | ||
1058 | |||
1059 | return ret; | ||
1060 | } | ||
1061 | |||
1000 | static const struct bcm_qspi_irq qspi_irq_tab[] = { | 1062 | static const struct bcm_qspi_irq qspi_irq_tab[] = { |
1001 | { | 1063 | { |
1002 | .irq_name = "spi_lr_fullness_reached", | 1064 | .irq_name = "spi_lr_fullness_reached", |
@@ -1036,6 +1098,13 @@ static const struct bcm_qspi_irq qspi_irq_tab[] = { | |||
1036 | .irq_handler = bcm_qspi_mspi_l2_isr, | 1098 | .irq_handler = bcm_qspi_mspi_l2_isr, |
1037 | .mask = INTR_MSPI_HALTED_MASK, | 1099 | .mask = INTR_MSPI_HALTED_MASK, |
1038 | }, | 1100 | }, |
1101 | { | ||
1102 | /* single muxed L1 interrupt source */ | ||
1103 | .irq_name = "spi_l1_intr", | ||
1104 | .irq_handler = bcm_qspi_l1_isr, | ||
1105 | .irq_source = MUXED_L1, | ||
1106 | .mask = QSPI_INTERRUPTS_ALL, | ||
1107 | }, | ||
1039 | }; | 1108 | }; |
1040 | 1109 | ||
1041 | static void bcm_qspi_bspi_init(struct bcm_qspi *qspi) | 1110 | static void bcm_qspi_bspi_init(struct bcm_qspi *qspi) |
@@ -1182,7 +1251,13 @@ int bcm_qspi_probe(struct platform_device *pdev, | |||
1182 | for (val = 0; val < num_irqs; val++) { | 1251 | for (val = 0; val < num_irqs; val++) { |
1183 | irq = -1; | 1252 | irq = -1; |
1184 | name = qspi_irq_tab[val].irq_name; | 1253 | name = qspi_irq_tab[val].irq_name; |
1185 | irq = platform_get_irq_byname(pdev, name); | 1254 | if (qspi_irq_tab[val].irq_source == SINGLE_L2) { |
1255 | /* get the l2 interrupts */ | ||
1256 | irq = platform_get_irq_byname(pdev, name); | ||
1257 | } else if (!num_ints && soc_intc) { | ||
1258 | /* all mspi, bspi intrs muxed to one L1 intr */ | ||
1259 | irq = platform_get_irq(pdev, 0); | ||
1260 | } | ||
1186 | 1261 | ||
1187 | if (irq >= 0) { | 1262 | if (irq >= 0) { |
1188 | ret = devm_request_irq(&pdev->dev, irq, | 1263 | ret = devm_request_irq(&pdev->dev, irq, |
@@ -1209,6 +1284,17 @@ int bcm_qspi_probe(struct platform_device *pdev, | |||
1209 | goto qspi_probe_err; | 1284 | goto qspi_probe_err; |
1210 | } | 1285 | } |
1211 | 1286 | ||
1287 | /* | ||
1288 | * Some SoCs integrate spi controller (e.g., its interrupt bits) | ||
1289 | * in specific ways | ||
1290 | */ | ||
1291 | if (soc_intc) { | ||
1292 | qspi->soc_intc = soc_intc; | ||
1293 | soc_intc->bcm_qspi_int_set(soc_intc, MSPI_DONE, true); | ||
1294 | } else { | ||
1295 | qspi->soc_intc = NULL; | ||
1296 | } | ||
1297 | |||
1212 | qspi->clk = devm_clk_get(&pdev->dev, NULL); | 1298 | qspi->clk = devm_clk_get(&pdev->dev, NULL); |
1213 | if (IS_ERR(qspi->clk)) { | 1299 | if (IS_ERR(qspi->clk)) { |
1214 | dev_warn(dev, "unable to get clock\n"); | 1300 | dev_warn(dev, "unable to get clock\n"); |
@@ -1288,6 +1374,11 @@ static int __maybe_unused bcm_qspi_resume(struct device *dev) | |||
1288 | 1374 | ||
1289 | bcm_qspi_hw_init(qspi); | 1375 | bcm_qspi_hw_init(qspi); |
1290 | bcm_qspi_chip_select(qspi, qspi->curr_cs); | 1376 | bcm_qspi_chip_select(qspi, qspi->curr_cs); |
1377 | if (qspi->soc_intc) | ||
1378 | /* enable MSPI interrupt */ | ||
1379 | qspi->soc_intc->bcm_qspi_int_set(qspi->soc_intc, MSPI_DONE, | ||
1380 | true); | ||
1381 | |||
1291 | ret = clk_enable(qspi->clk); | 1382 | ret = clk_enable(qspi->clk); |
1292 | if (!ret) | 1383 | if (!ret) |
1293 | spi_master_resume(qspi->master); | 1384 | spi_master_resume(qspi->master); |
diff --git a/drivers/spi/spi-bcm-qspi.h b/drivers/spi/spi-bcm-qspi.h index 65c363b6b7b7..7abfc75a3860 100644 --- a/drivers/spi/spi-bcm-qspi.h +++ b/drivers/spi/spi-bcm-qspi.h | |||
@@ -48,10 +48,26 @@ | |||
48 | (INTR_MSPI_DONE_MASK | \ | 48 | (INTR_MSPI_DONE_MASK | \ |
49 | INTR_MSPI_HALTED_MASK) | 49 | INTR_MSPI_HALTED_MASK) |
50 | 50 | ||
51 | #define QSPI_INTERRUPTS_ALL \ | ||
52 | (MSPI_INTERRUPTS_ALL | \ | ||
53 | BSPI_LR_INTERRUPTS_ALL) | ||
54 | |||
51 | struct platform_device; | 55 | struct platform_device; |
52 | struct dev_pm_ops; | 56 | struct dev_pm_ops; |
53 | 57 | ||
54 | struct bcm_qspi_soc_intc; | 58 | enum { |
59 | MSPI_DONE = 0x1, | ||
60 | BSPI_DONE = 0x2, | ||
61 | BSPI_ERR = 0x4, | ||
62 | MSPI_BSPI_DONE = 0x7 | ||
63 | }; | ||
64 | |||
65 | struct bcm_qspi_soc_intc { | ||
66 | void (*bcm_qspi_int_ack)(struct bcm_qspi_soc_intc *soc_intc, int type); | ||
67 | void (*bcm_qspi_int_set)(struct bcm_qspi_soc_intc *soc_intc, int type, | ||
68 | bool en); | ||
69 | u32 (*bcm_qspi_get_int_status)(struct bcm_qspi_soc_intc *soc_intc); | ||
70 | }; | ||
55 | 71 | ||
56 | /* Read controller register*/ | 72 | /* Read controller register*/ |
57 | static inline u32 bcm_qspi_readl(bool be, void __iomem *addr) | 73 | static inline u32 bcm_qspi_readl(bool be, void __iomem *addr) |
@@ -72,6 +88,22 @@ static inline void bcm_qspi_writel(bool be, | |||
72 | writel_relaxed(data, addr); | 88 | writel_relaxed(data, addr); |
73 | } | 89 | } |
74 | 90 | ||
91 | static inline u32 get_qspi_mask(int type) | ||
92 | { | ||
93 | switch (type) { | ||
94 | case MSPI_DONE: | ||
95 | return INTR_MSPI_DONE_MASK; | ||
96 | case BSPI_DONE: | ||
97 | return BSPI_LR_INTERRUPTS_ALL; | ||
98 | case MSPI_BSPI_DONE: | ||
99 | return QSPI_INTERRUPTS_ALL; | ||
100 | case BSPI_ERR: | ||
101 | return BSPI_LR_INTERRUPTS_ERROR; | ||
102 | } | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
75 | /* The common driver functions to be called by the SoC platform driver */ | 107 | /* The common driver functions to be called by the SoC platform driver */ |
76 | int bcm_qspi_probe(struct platform_device *pdev, | 108 | int bcm_qspi_probe(struct platform_device *pdev, |
77 | struct bcm_qspi_soc_intc *soc_intc); | 109 | struct bcm_qspi_soc_intc *soc_intc); |
diff --git a/drivers/spi/spi-iproc-qspi.c b/drivers/spi/spi-iproc-qspi.c new file mode 100644 index 000000000000..be6ccb204a66 --- /dev/null +++ b/drivers/spi/spi-iproc-qspi.c | |||
@@ -0,0 +1,163 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Broadcom Limited | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | */ | ||
13 | |||
14 | #include <linux/device.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/ioport.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/of.h> | ||
19 | #include <linux/of_address.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/slab.h> | ||
22 | |||
23 | #include "spi-bcm-qspi.h" | ||
24 | |||
25 | #define INTR_BASE_BIT_SHIFT 0x02 | ||
26 | #define INTR_COUNT 0x07 | ||
27 | |||
28 | struct bcm_iproc_intc { | ||
29 | struct bcm_qspi_soc_intc soc_intc; | ||
30 | struct platform_device *pdev; | ||
31 | void __iomem *int_reg; | ||
32 | void __iomem *int_status_reg; | ||
33 | spinlock_t soclock; | ||
34 | bool big_endian; | ||
35 | }; | ||
36 | |||
37 | static u32 bcm_iproc_qspi_get_l2_int_status(struct bcm_qspi_soc_intc *soc_intc) | ||
38 | { | ||
39 | struct bcm_iproc_intc *priv = | ||
40 | container_of(soc_intc, struct bcm_iproc_intc, soc_intc); | ||
41 | void __iomem *mmio = priv->int_status_reg; | ||
42 | int i; | ||
43 | u32 val = 0, sts = 0; | ||
44 | |||
45 | for (i = 0; i < INTR_COUNT; i++) { | ||
46 | if (bcm_qspi_readl(priv->big_endian, mmio + (i * 4))) | ||
47 | val |= 1UL << i; | ||
48 | } | ||
49 | |||
50 | if (val & INTR_MSPI_DONE_MASK) | ||
51 | sts |= MSPI_DONE; | ||
52 | |||
53 | if (val & BSPI_LR_INTERRUPTS_ALL) | ||
54 | sts |= BSPI_DONE; | ||
55 | |||
56 | if (val & BSPI_LR_INTERRUPTS_ERROR) | ||
57 | sts |= BSPI_ERR; | ||
58 | |||
59 | return sts; | ||
60 | } | ||
61 | |||
62 | static void bcm_iproc_qspi_int_ack(struct bcm_qspi_soc_intc *soc_intc, int type) | ||
63 | { | ||
64 | struct bcm_iproc_intc *priv = | ||
65 | container_of(soc_intc, struct bcm_iproc_intc, soc_intc); | ||
66 | void __iomem *mmio = priv->int_status_reg; | ||
67 | u32 mask = get_qspi_mask(type); | ||
68 | int i; | ||
69 | |||
70 | for (i = 0; i < INTR_COUNT; i++) { | ||
71 | if (mask & (1UL << i)) | ||
72 | bcm_qspi_writel(priv->big_endian, 1, mmio + (i * 4)); | ||
73 | } | ||
74 | } | ||
75 | |||
76 | static void bcm_iproc_qspi_int_set(struct bcm_qspi_soc_intc *soc_intc, int type, | ||
77 | bool en) | ||
78 | { | ||
79 | struct bcm_iproc_intc *priv = | ||
80 | container_of(soc_intc, struct bcm_iproc_intc, soc_intc); | ||
81 | void __iomem *mmio = priv->int_reg; | ||
82 | u32 mask = get_qspi_mask(type); | ||
83 | u32 val; | ||
84 | unsigned long flags; | ||
85 | |||
86 | spin_lock_irqsave(&priv->soclock, flags); | ||
87 | |||
88 | val = bcm_qspi_readl(priv->big_endian, mmio); | ||
89 | |||
90 | if (en) | ||
91 | val = val | (mask << INTR_BASE_BIT_SHIFT); | ||
92 | else | ||
93 | val = val & ~(mask << INTR_BASE_BIT_SHIFT); | ||
94 | |||
95 | bcm_qspi_writel(priv->big_endian, val, mmio); | ||
96 | |||
97 | spin_unlock_irqrestore(&priv->soclock, flags); | ||
98 | } | ||
99 | |||
100 | static int bcm_iproc_probe(struct platform_device *pdev) | ||
101 | { | ||
102 | struct device *dev = &pdev->dev; | ||
103 | struct bcm_iproc_intc *priv; | ||
104 | struct bcm_qspi_soc_intc *soc_intc; | ||
105 | struct resource *res; | ||
106 | |||
107 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
108 | if (!priv) | ||
109 | return -ENOMEM; | ||
110 | soc_intc = &priv->soc_intc; | ||
111 | priv->pdev = pdev; | ||
112 | |||
113 | spin_lock_init(&priv->soclock); | ||
114 | |||
115 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr_regs"); | ||
116 | priv->int_reg = devm_ioremap_resource(dev, res); | ||
117 | if (IS_ERR(priv->int_reg)) | ||
118 | return PTR_ERR(priv->int_reg); | ||
119 | |||
120 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | ||
121 | "intr_status_reg"); | ||
122 | priv->int_status_reg = devm_ioremap_resource(dev, res); | ||
123 | if (IS_ERR(priv->int_status_reg)) | ||
124 | return PTR_ERR(priv->int_status_reg); | ||
125 | |||
126 | priv->big_endian = of_device_is_big_endian(dev->of_node); | ||
127 | |||
128 | bcm_iproc_qspi_int_ack(soc_intc, MSPI_BSPI_DONE); | ||
129 | bcm_iproc_qspi_int_set(soc_intc, MSPI_BSPI_DONE, false); | ||
130 | |||
131 | soc_intc->bcm_qspi_int_ack = bcm_iproc_qspi_int_ack; | ||
132 | soc_intc->bcm_qspi_int_set = bcm_iproc_qspi_int_set; | ||
133 | soc_intc->bcm_qspi_get_int_status = bcm_iproc_qspi_get_l2_int_status; | ||
134 | |||
135 | return bcm_qspi_probe(pdev, soc_intc); | ||
136 | } | ||
137 | |||
138 | static int bcm_iproc_remove(struct platform_device *pdev) | ||
139 | { | ||
140 | return bcm_qspi_remove(pdev); | ||
141 | } | ||
142 | |||
143 | static const struct of_device_id bcm_iproc_of_match[] = { | ||
144 | { .compatible = "brcm,spi-nsp-qspi" }, | ||
145 | { .compatible = "brcm,spi-ns2-qspi" }, | ||
146 | {}, | ||
147 | }; | ||
148 | MODULE_DEVICE_TABLE(of, bcm_iproc_of_match); | ||
149 | |||
150 | static struct platform_driver bcm_iproc_driver = { | ||
151 | .probe = bcm_iproc_probe, | ||
152 | .remove = bcm_iproc_remove, | ||
153 | .driver = { | ||
154 | .name = "bcm_iproc", | ||
155 | .pm = &bcm_qspi_pm_ops, | ||
156 | .of_match_table = bcm_iproc_of_match, | ||
157 | } | ||
158 | }; | ||
159 | module_platform_driver(bcm_iproc_driver); | ||
160 | |||
161 | MODULE_LICENSE("GPL v2"); | ||
162 | MODULE_AUTHOR("Kamal Dasu"); | ||
163 | MODULE_DESCRIPTION("SPI flash driver for Broadcom iProc SoCs"); | ||