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"); 164