0001
0002
0003
0004
0005
0006 #include <linux/device.h>
0007 #include <linux/io.h>
0008 #include <linux/ioport.h>
0009 #include <linux/module.h>
0010 #include <linux/of.h>
0011 #include <linux/of_address.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/slab.h>
0014
0015 #include "spi-bcm-qspi.h"
0016
0017 #define INTR_BASE_BIT_SHIFT 0x02
0018 #define INTR_COUNT 0x07
0019
0020 struct bcm_iproc_intc {
0021 struct bcm_qspi_soc_intc soc_intc;
0022 struct platform_device *pdev;
0023 void __iomem *int_reg;
0024 void __iomem *int_status_reg;
0025 spinlock_t soclock;
0026 bool big_endian;
0027 };
0028
0029 static u32 bcm_iproc_qspi_get_l2_int_status(struct bcm_qspi_soc_intc *soc_intc)
0030 {
0031 struct bcm_iproc_intc *priv =
0032 container_of(soc_intc, struct bcm_iproc_intc, soc_intc);
0033 void __iomem *mmio = priv->int_status_reg;
0034 int i;
0035 u32 val = 0, sts = 0;
0036
0037 for (i = 0; i < INTR_COUNT; i++) {
0038 if (bcm_qspi_readl(priv->big_endian, mmio + (i * 4)))
0039 val |= 1UL << i;
0040 }
0041
0042 if (val & INTR_MSPI_DONE_MASK)
0043 sts |= MSPI_DONE;
0044
0045 if (val & BSPI_LR_INTERRUPTS_ALL)
0046 sts |= BSPI_DONE;
0047
0048 if (val & BSPI_LR_INTERRUPTS_ERROR)
0049 sts |= BSPI_ERR;
0050
0051 return sts;
0052 }
0053
0054 static void bcm_iproc_qspi_int_ack(struct bcm_qspi_soc_intc *soc_intc, int type)
0055 {
0056 struct bcm_iproc_intc *priv =
0057 container_of(soc_intc, struct bcm_iproc_intc, soc_intc);
0058 void __iomem *mmio = priv->int_status_reg;
0059 u32 mask = get_qspi_mask(type);
0060 int i;
0061
0062 for (i = 0; i < INTR_COUNT; i++) {
0063 if (mask & (1UL << i))
0064 bcm_qspi_writel(priv->big_endian, 1, mmio + (i * 4));
0065 }
0066 }
0067
0068 static void bcm_iproc_qspi_int_set(struct bcm_qspi_soc_intc *soc_intc, int type,
0069 bool en)
0070 {
0071 struct bcm_iproc_intc *priv =
0072 container_of(soc_intc, struct bcm_iproc_intc, soc_intc);
0073 void __iomem *mmio = priv->int_reg;
0074 u32 mask = get_qspi_mask(type);
0075 u32 val;
0076 unsigned long flags;
0077
0078 spin_lock_irqsave(&priv->soclock, flags);
0079
0080 val = bcm_qspi_readl(priv->big_endian, mmio);
0081
0082 if (en)
0083 val = val | (mask << INTR_BASE_BIT_SHIFT);
0084 else
0085 val = val & ~(mask << INTR_BASE_BIT_SHIFT);
0086
0087 bcm_qspi_writel(priv->big_endian, val, mmio);
0088
0089 spin_unlock_irqrestore(&priv->soclock, flags);
0090 }
0091
0092 static int bcm_iproc_probe(struct platform_device *pdev)
0093 {
0094 struct device *dev = &pdev->dev;
0095 struct bcm_iproc_intc *priv;
0096 struct bcm_qspi_soc_intc *soc_intc;
0097 struct resource *res;
0098
0099 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0100 if (!priv)
0101 return -ENOMEM;
0102 soc_intc = &priv->soc_intc;
0103 priv->pdev = pdev;
0104
0105 spin_lock_init(&priv->soclock);
0106
0107 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr_regs");
0108 priv->int_reg = devm_ioremap_resource(dev, res);
0109 if (IS_ERR(priv->int_reg))
0110 return PTR_ERR(priv->int_reg);
0111
0112 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
0113 "intr_status_reg");
0114 priv->int_status_reg = devm_ioremap_resource(dev, res);
0115 if (IS_ERR(priv->int_status_reg))
0116 return PTR_ERR(priv->int_status_reg);
0117
0118 priv->big_endian = of_device_is_big_endian(dev->of_node);
0119
0120 bcm_iproc_qspi_int_ack(soc_intc, MSPI_BSPI_DONE);
0121 bcm_iproc_qspi_int_set(soc_intc, MSPI_BSPI_DONE, false);
0122
0123 soc_intc->bcm_qspi_int_ack = bcm_iproc_qspi_int_ack;
0124 soc_intc->bcm_qspi_int_set = bcm_iproc_qspi_int_set;
0125 soc_intc->bcm_qspi_get_int_status = bcm_iproc_qspi_get_l2_int_status;
0126
0127 return bcm_qspi_probe(pdev, soc_intc);
0128 }
0129
0130 static int bcm_iproc_remove(struct platform_device *pdev)
0131 {
0132 return bcm_qspi_remove(pdev);
0133 }
0134
0135 static const struct of_device_id bcm_iproc_of_match[] = {
0136 { .compatible = "brcm,spi-nsp-qspi" },
0137 { .compatible = "brcm,spi-ns2-qspi" },
0138 {},
0139 };
0140 MODULE_DEVICE_TABLE(of, bcm_iproc_of_match);
0141
0142 static struct platform_driver bcm_iproc_driver = {
0143 .probe = bcm_iproc_probe,
0144 .remove = bcm_iproc_remove,
0145 .driver = {
0146 .name = "bcm_iproc",
0147 .pm = &bcm_qspi_pm_ops,
0148 .of_match_table = bcm_iproc_of_match,
0149 }
0150 };
0151 module_platform_driver(bcm_iproc_driver);
0152
0153 MODULE_LICENSE("GPL v2");
0154 MODULE_AUTHOR("Kamal Dasu");
0155 MODULE_DESCRIPTION("SPI flash driver for Broadcom iProc SoCs");