1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright 2016 Broadcom Limited
6 #include <linux/device.h>
8 #include <linux/ioport.h>
9 #include <linux/module.h>
11 #include <linux/of_address.h>
12 #include <linux/platform_device.h>
13 #include <linux/slab.h>
15 #include "spi-bcm-qspi.h"
17 #define INTR_BASE_BIT_SHIFT 0x02
18 #define INTR_COUNT 0x07
20 struct bcm_iproc_intc
{
21 struct bcm_qspi_soc_intc soc_intc
;
22 struct platform_device
*pdev
;
23 void __iomem
*int_reg
;
24 void __iomem
*int_status_reg
;
29 static u32
bcm_iproc_qspi_get_l2_int_status(struct bcm_qspi_soc_intc
*soc_intc
)
31 struct bcm_iproc_intc
*priv
=
32 container_of(soc_intc
, struct bcm_iproc_intc
, soc_intc
);
33 void __iomem
*mmio
= priv
->int_status_reg
;
37 for (i
= 0; i
< INTR_COUNT
; i
++) {
38 if (bcm_qspi_readl(priv
->big_endian
, mmio
+ (i
* 4)))
42 if (val
& INTR_MSPI_DONE_MASK
)
45 if (val
& BSPI_LR_INTERRUPTS_ALL
)
48 if (val
& BSPI_LR_INTERRUPTS_ERROR
)
54 static void bcm_iproc_qspi_int_ack(struct bcm_qspi_soc_intc
*soc_intc
, int type
)
56 struct bcm_iproc_intc
*priv
=
57 container_of(soc_intc
, struct bcm_iproc_intc
, soc_intc
);
58 void __iomem
*mmio
= priv
->int_status_reg
;
59 u32 mask
= get_qspi_mask(type
);
62 for (i
= 0; i
< INTR_COUNT
; i
++) {
63 if (mask
& (1UL << i
))
64 bcm_qspi_writel(priv
->big_endian
, 1, mmio
+ (i
* 4));
68 static void bcm_iproc_qspi_int_set(struct bcm_qspi_soc_intc
*soc_intc
, int type
,
71 struct bcm_iproc_intc
*priv
=
72 container_of(soc_intc
, struct bcm_iproc_intc
, soc_intc
);
73 void __iomem
*mmio
= priv
->int_reg
;
74 u32 mask
= get_qspi_mask(type
);
78 spin_lock_irqsave(&priv
->soclock
, flags
);
80 val
= bcm_qspi_readl(priv
->big_endian
, mmio
);
83 val
= val
| (mask
<< INTR_BASE_BIT_SHIFT
);
85 val
= val
& ~(mask
<< INTR_BASE_BIT_SHIFT
);
87 bcm_qspi_writel(priv
->big_endian
, val
, mmio
);
89 spin_unlock_irqrestore(&priv
->soclock
, flags
);
92 static int bcm_iproc_probe(struct platform_device
*pdev
)
94 struct device
*dev
= &pdev
->dev
;
95 struct bcm_iproc_intc
*priv
;
96 struct bcm_qspi_soc_intc
*soc_intc
;
98 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
101 soc_intc
= &priv
->soc_intc
;
104 spin_lock_init(&priv
->soclock
);
106 priv
->int_reg
= devm_platform_ioremap_resource_byname(pdev
, "intr_regs");
107 if (IS_ERR(priv
->int_reg
))
108 return PTR_ERR(priv
->int_reg
);
110 priv
->int_status_reg
= devm_platform_ioremap_resource_byname(pdev
,
112 if (IS_ERR(priv
->int_status_reg
))
113 return PTR_ERR(priv
->int_status_reg
);
115 priv
->big_endian
= of_device_is_big_endian(dev
->of_node
);
117 bcm_iproc_qspi_int_ack(soc_intc
, MSPI_BSPI_DONE
);
118 bcm_iproc_qspi_int_set(soc_intc
, MSPI_BSPI_DONE
, false);
120 soc_intc
->bcm_qspi_int_ack
= bcm_iproc_qspi_int_ack
;
121 soc_intc
->bcm_qspi_int_set
= bcm_iproc_qspi_int_set
;
122 soc_intc
->bcm_qspi_get_int_status
= bcm_iproc_qspi_get_l2_int_status
;
124 return bcm_qspi_probe(pdev
, soc_intc
);
127 static void bcm_iproc_remove(struct platform_device
*pdev
)
129 bcm_qspi_remove(pdev
);
132 static const struct of_device_id bcm_iproc_of_match
[] = {
133 { .compatible
= "brcm,spi-nsp-qspi" },
134 { .compatible
= "brcm,spi-ns2-qspi" },
137 MODULE_DEVICE_TABLE(of
, bcm_iproc_of_match
);
139 static struct platform_driver bcm_iproc_driver
= {
140 .probe
= bcm_iproc_probe
,
141 .remove
= bcm_iproc_remove
,
144 .pm
= &bcm_qspi_pm_ops
,
145 .of_match_table
= bcm_iproc_of_match
,
148 module_platform_driver(bcm_iproc_driver
);
150 MODULE_LICENSE("GPL v2");
151 MODULE_AUTHOR("Kamal Dasu");
152 MODULE_DESCRIPTION("SPI flash driver for Broadcom iProc SoCs");