1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Memory-mapped interface driver for DW SPI Core 4 * 5 * Copyright (c) 2010, Octasic semiconductor. 6 */ 7 8 #include <linux/clk.h> 9 #include <linux/err.h> 10 #include <linux/interrupt.h> 11 #include <linux/platform_device.h> 12 #include <linux/pm_runtime.h> 13 #include <linux/slab.h> 14 #include <linux/spi/spi.h> 15 #include <linux/scatterlist.h> 16 #include <linux/mfd/syscon.h> 17 #include <linux/module.h> 18 #include <linux/of.h> 19 #include <linux/of_platform.h> 20 #include <linux/acpi.h> 21 #include <linux/property.h> 22 #include <linux/regmap.h> 23 24 #include "spi-dw.h" 25 26 #define DRIVER_NAME "dw_spi_mmio" 27 28 struct dw_spi_mmio { 29 struct dw_spi dws; 30 struct clk *clk; 31 struct clk *pclk; 32 void *priv; 33 }; 34 35 #define MSCC_CPU_SYSTEM_CTRL_GENERAL_CTRL 0x24 36 #define OCELOT_IF_SI_OWNER_OFFSET 4 37 #define JAGUAR2_IF_SI_OWNER_OFFSET 6 38 #define MSCC_IF_SI_OWNER_MASK GENMASK(1, 0) 39 #define MSCC_IF_SI_OWNER_SISL 0 40 #define MSCC_IF_SI_OWNER_SIBM 1 41 #define MSCC_IF_SI_OWNER_SIMC 2 42 43 #define MSCC_SPI_MST_SW_MODE 0x14 44 #define MSCC_SPI_MST_SW_MODE_SW_PIN_CTRL_MODE BIT(13) 45 #define MSCC_SPI_MST_SW_MODE_SW_SPI_CS(x) (x << 5) 46 47 struct dw_spi_mscc { 48 struct regmap *syscon; 49 void __iomem *spi_mst; 50 }; 51 52 /* 53 * The Designware SPI controller (referred to as master in the documentation) 54 * automatically deasserts chip select when the tx fifo is empty. The chip 55 * selects then needs to be either driven as GPIOs or, for the first 4 using the 56 * the SPI boot controller registers. the final chip select is an OR gate 57 * between the Designware SPI controller and the SPI boot controller. 58 */ 59 static void dw_spi_mscc_set_cs(struct spi_device *spi, bool enable) 60 { 61 struct dw_spi *dws = spi_master_get_devdata(spi->master); 62 struct dw_spi_mmio *dwsmmio = container_of(dws, struct dw_spi_mmio, dws); 63 struct dw_spi_mscc *dwsmscc = dwsmmio->priv; 64 u32 cs = spi->chip_select; 65 66 if (cs < 4) { 67 u32 sw_mode = MSCC_SPI_MST_SW_MODE_SW_PIN_CTRL_MODE; 68 69 if (!enable) 70 sw_mode |= MSCC_SPI_MST_SW_MODE_SW_SPI_CS(BIT(cs)); 71 72 writel(sw_mode, dwsmscc->spi_mst + MSCC_SPI_MST_SW_MODE); 73 } 74 75 dw_spi_set_cs(spi, enable); 76 } 77 78 static int dw_spi_mscc_init(struct platform_device *pdev, 79 struct dw_spi_mmio *dwsmmio, 80 const char *cpu_syscon, u32 if_si_owner_offset) 81 { 82 struct dw_spi_mscc *dwsmscc; 83 84 dwsmscc = devm_kzalloc(&pdev->dev, sizeof(*dwsmscc), GFP_KERNEL); 85 if (!dwsmscc) 86 return -ENOMEM; 87 88 dwsmscc->spi_mst = devm_platform_ioremap_resource(pdev, 1); 89 if (IS_ERR(dwsmscc->spi_mst)) { 90 dev_err(&pdev->dev, "SPI_MST region map failed\n"); 91 return PTR_ERR(dwsmscc->spi_mst); 92 } 93 94 dwsmscc->syscon = syscon_regmap_lookup_by_compatible(cpu_syscon); 95 if (IS_ERR(dwsmscc->syscon)) 96 return PTR_ERR(dwsmscc->syscon); 97 98 /* Deassert all CS */ 99 writel(0, dwsmscc->spi_mst + MSCC_SPI_MST_SW_MODE); 100 101 /* Select the owner of the SI interface */ 102 regmap_update_bits(dwsmscc->syscon, MSCC_CPU_SYSTEM_CTRL_GENERAL_CTRL, 103 MSCC_IF_SI_OWNER_MASK << if_si_owner_offset, 104 MSCC_IF_SI_OWNER_SIMC << if_si_owner_offset); 105 106 dwsmmio->dws.set_cs = dw_spi_mscc_set_cs; 107 dwsmmio->priv = dwsmscc; 108 109 return 0; 110 } 111 112 static int dw_spi_mscc_ocelot_init(struct platform_device *pdev, 113 struct dw_spi_mmio *dwsmmio) 114 { 115 return dw_spi_mscc_init(pdev, dwsmmio, "mscc,ocelot-cpu-syscon", 116 OCELOT_IF_SI_OWNER_OFFSET); 117 } 118 119 static int dw_spi_mscc_jaguar2_init(struct platform_device *pdev, 120 struct dw_spi_mmio *dwsmmio) 121 { 122 return dw_spi_mscc_init(pdev, dwsmmio, "mscc,jaguar2-cpu-syscon", 123 JAGUAR2_IF_SI_OWNER_OFFSET); 124 } 125 126 static int dw_spi_alpine_init(struct platform_device *pdev, 127 struct dw_spi_mmio *dwsmmio) 128 { 129 dwsmmio->dws.cs_override = 1; 130 131 return 0; 132 } 133 134 static int dw_spi_mmio_probe(struct platform_device *pdev) 135 { 136 int (*init_func)(struct platform_device *pdev, 137 struct dw_spi_mmio *dwsmmio); 138 struct dw_spi_mmio *dwsmmio; 139 struct dw_spi *dws; 140 int ret; 141 int num_cs; 142 143 dwsmmio = devm_kzalloc(&pdev->dev, sizeof(struct dw_spi_mmio), 144 GFP_KERNEL); 145 if (!dwsmmio) 146 return -ENOMEM; 147 148 dws = &dwsmmio->dws; 149 150 /* Get basic io resource and map it */ 151 dws->regs = devm_platform_ioremap_resource(pdev, 0); 152 if (IS_ERR(dws->regs)) { 153 dev_err(&pdev->dev, "SPI region map failed\n"); 154 return PTR_ERR(dws->regs); 155 } 156 157 dws->irq = platform_get_irq(pdev, 0); 158 if (dws->irq < 0) 159 return dws->irq; /* -ENXIO */ 160 161 dwsmmio->clk = devm_clk_get(&pdev->dev, NULL); 162 if (IS_ERR(dwsmmio->clk)) 163 return PTR_ERR(dwsmmio->clk); 164 ret = clk_prepare_enable(dwsmmio->clk); 165 if (ret) 166 return ret; 167 168 /* Optional clock needed to access the registers */ 169 dwsmmio->pclk = devm_clk_get_optional(&pdev->dev, "pclk"); 170 if (IS_ERR(dwsmmio->pclk)) { 171 ret = PTR_ERR(dwsmmio->pclk); 172 goto out_clk; 173 } 174 ret = clk_prepare_enable(dwsmmio->pclk); 175 if (ret) 176 goto out_clk; 177 178 dws->bus_num = pdev->id; 179 180 dws->max_freq = clk_get_rate(dwsmmio->clk); 181 182 device_property_read_u32(&pdev->dev, "reg-io-width", &dws->reg_io_width); 183 184 num_cs = 4; 185 186 device_property_read_u32(&pdev->dev, "num-cs", &num_cs); 187 188 dws->num_cs = num_cs; 189 190 init_func = device_get_match_data(&pdev->dev); 191 if (init_func) { 192 ret = init_func(pdev, dwsmmio); 193 if (ret) 194 goto out; 195 } 196 197 pm_runtime_enable(&pdev->dev); 198 199 ret = dw_spi_add_host(&pdev->dev, dws); 200 if (ret) 201 goto out; 202 203 platform_set_drvdata(pdev, dwsmmio); 204 return 0; 205 206 out: 207 pm_runtime_disable(&pdev->dev); 208 clk_disable_unprepare(dwsmmio->pclk); 209 out_clk: 210 clk_disable_unprepare(dwsmmio->clk); 211 return ret; 212 } 213 214 static int dw_spi_mmio_remove(struct platform_device *pdev) 215 { 216 struct dw_spi_mmio *dwsmmio = platform_get_drvdata(pdev); 217 218 dw_spi_remove_host(&dwsmmio->dws); 219 pm_runtime_disable(&pdev->dev); 220 clk_disable_unprepare(dwsmmio->pclk); 221 clk_disable_unprepare(dwsmmio->clk); 222 223 return 0; 224 } 225 226 static const struct of_device_id dw_spi_mmio_of_match[] = { 227 { .compatible = "snps,dw-apb-ssi", }, 228 { .compatible = "mscc,ocelot-spi", .data = dw_spi_mscc_ocelot_init}, 229 { .compatible = "mscc,jaguar2-spi", .data = dw_spi_mscc_jaguar2_init}, 230 { .compatible = "amazon,alpine-dw-apb-ssi", .data = dw_spi_alpine_init}, 231 { .compatible = "renesas,rzn1-spi", }, 232 { /* end of table */} 233 }; 234 MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match); 235 236 static const struct acpi_device_id dw_spi_mmio_acpi_match[] = { 237 {"HISI0173", 0}, 238 {}, 239 }; 240 MODULE_DEVICE_TABLE(acpi, dw_spi_mmio_acpi_match); 241 242 static struct platform_driver dw_spi_mmio_driver = { 243 .probe = dw_spi_mmio_probe, 244 .remove = dw_spi_mmio_remove, 245 .driver = { 246 .name = DRIVER_NAME, 247 .of_match_table = dw_spi_mmio_of_match, 248 .acpi_match_table = ACPI_PTR(dw_spi_mmio_acpi_match), 249 }, 250 }; 251 module_platform_driver(dw_spi_mmio_driver); 252 253 MODULE_AUTHOR("Jean-Hugues Deschenes <jean-hugues.deschenes@octasic.com>"); 254 MODULE_DESCRIPTION("Memory-mapped I/O interface driver for DW SPI Core"); 255 MODULE_LICENSE("GPL v2"); 256