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
;
99 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
102 soc_intc
= &priv
->soc_intc
;
105 spin_lock_init(&priv
->soclock
);
107 res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, "intr_regs");
108 priv
->int_reg
= devm_ioremap_resource(dev
, res
);
109 if (IS_ERR(priv
->int_reg
))
110 return PTR_ERR(priv
->int_reg
);
112 res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
,
114 priv
->int_status_reg
= devm_ioremap_resource(dev
, res
);
115 if (IS_ERR(priv
->int_status_reg
))
116 return PTR_ERR(priv
->int_status_reg
);
118 priv
->big_endian
= of_device_is_big_endian(dev
->of_node
);
120 bcm_iproc_qspi_int_ack(soc_intc
, MSPI_BSPI_DONE
);
121 bcm_iproc_qspi_int_set(soc_intc
, MSPI_BSPI_DONE
, false);
123 soc_intc
->bcm_qspi_int_ack
= bcm_iproc_qspi_int_ack
;
124 soc_intc
->bcm_qspi_int_set
= bcm_iproc_qspi_int_set
;
125 soc_intc
->bcm_qspi_get_int_status
= bcm_iproc_qspi_get_l2_int_status
;
127 return bcm_qspi_probe(pdev
, soc_intc
);
130 static int bcm_iproc_remove(struct platform_device
*pdev
)
132 return bcm_qspi_remove(pdev
);
135 static const struct of_device_id bcm_iproc_of_match
[] = {
136 { .compatible
= "brcm,spi-nsp-qspi" },
137 { .compatible
= "brcm,spi-ns2-qspi" },
140 MODULE_DEVICE_TABLE(of
, bcm_iproc_of_match
);
142 static struct platform_driver bcm_iproc_driver
= {
143 .probe
= bcm_iproc_probe
,
144 .remove
= bcm_iproc_remove
,
147 .pm
= &bcm_qspi_pm_ops
,
148 .of_match_table
= bcm_iproc_of_match
,
151 module_platform_driver(bcm_iproc_driver
);
153 MODULE_LICENSE("GPL v2");
154 MODULE_AUTHOR("Kamal Dasu");
155 MODULE_DESCRIPTION("SPI flash driver for Broadcom iProc SoCs");