Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Memory-mapped interface driver for DW SPI Core
0004  *
0005  * Copyright (c) 2010, Octasic semiconductor.
0006  */
0007 
0008 #include <linux/clk.h>
0009 #include <linux/err.h>
0010 #include <linux/platform_device.h>
0011 #include <linux/pm_runtime.h>
0012 #include <linux/slab.h>
0013 #include <linux/spi/spi.h>
0014 #include <linux/scatterlist.h>
0015 #include <linux/mfd/syscon.h>
0016 #include <linux/module.h>
0017 #include <linux/of.h>
0018 #include <linux/of_platform.h>
0019 #include <linux/acpi.h>
0020 #include <linux/property.h>
0021 #include <linux/regmap.h>
0022 #include <linux/reset.h>
0023 
0024 #include "spi-dw.h"
0025 
0026 #define DRIVER_NAME "dw_spi_mmio"
0027 
0028 struct dw_spi_mmio {
0029     struct dw_spi  dws;
0030     struct clk     *clk;
0031     struct clk     *pclk;
0032     void           *priv;
0033     struct reset_control *rstc;
0034 };
0035 
0036 #define MSCC_CPU_SYSTEM_CTRL_GENERAL_CTRL   0x24
0037 #define OCELOT_IF_SI_OWNER_OFFSET       4
0038 #define JAGUAR2_IF_SI_OWNER_OFFSET      6
0039 #define MSCC_IF_SI_OWNER_MASK           GENMASK(1, 0)
0040 #define MSCC_IF_SI_OWNER_SISL           0
0041 #define MSCC_IF_SI_OWNER_SIBM           1
0042 #define MSCC_IF_SI_OWNER_SIMC           2
0043 
0044 #define MSCC_SPI_MST_SW_MODE            0x14
0045 #define MSCC_SPI_MST_SW_MODE_SW_PIN_CTRL_MODE   BIT(13)
0046 #define MSCC_SPI_MST_SW_MODE_SW_SPI_CS(x)   (x << 5)
0047 
0048 #define SPARX5_FORCE_ENA            0xa4
0049 #define SPARX5_FORCE_VAL            0xa8
0050 
0051 struct dw_spi_mscc {
0052     struct regmap       *syscon;
0053     void __iomem        *spi_mst; /* Not sparx5 */
0054 };
0055 
0056 /*
0057  * The Designware SPI controller (referred to as master in the documentation)
0058  * automatically deasserts chip select when the tx fifo is empty. The chip
0059  * selects then needs to be either driven as GPIOs or, for the first 4 using
0060  * the SPI boot controller registers. the final chip select is an OR gate
0061  * between the Designware SPI controller and the SPI boot controller.
0062  */
0063 static void dw_spi_mscc_set_cs(struct spi_device *spi, bool enable)
0064 {
0065     struct dw_spi *dws = spi_master_get_devdata(spi->master);
0066     struct dw_spi_mmio *dwsmmio = container_of(dws, struct dw_spi_mmio, dws);
0067     struct dw_spi_mscc *dwsmscc = dwsmmio->priv;
0068     u32 cs = spi->chip_select;
0069 
0070     if (cs < 4) {
0071         u32 sw_mode = MSCC_SPI_MST_SW_MODE_SW_PIN_CTRL_MODE;
0072 
0073         if (!enable)
0074             sw_mode |= MSCC_SPI_MST_SW_MODE_SW_SPI_CS(BIT(cs));
0075 
0076         writel(sw_mode, dwsmscc->spi_mst + MSCC_SPI_MST_SW_MODE);
0077     }
0078 
0079     dw_spi_set_cs(spi, enable);
0080 }
0081 
0082 static int dw_spi_mscc_init(struct platform_device *pdev,
0083                 struct dw_spi_mmio *dwsmmio,
0084                 const char *cpu_syscon, u32 if_si_owner_offset)
0085 {
0086     struct dw_spi_mscc *dwsmscc;
0087 
0088     dwsmscc = devm_kzalloc(&pdev->dev, sizeof(*dwsmscc), GFP_KERNEL);
0089     if (!dwsmscc)
0090         return -ENOMEM;
0091 
0092     dwsmscc->spi_mst = devm_platform_ioremap_resource(pdev, 1);
0093     if (IS_ERR(dwsmscc->spi_mst)) {
0094         dev_err(&pdev->dev, "SPI_MST region map failed\n");
0095         return PTR_ERR(dwsmscc->spi_mst);
0096     }
0097 
0098     dwsmscc->syscon = syscon_regmap_lookup_by_compatible(cpu_syscon);
0099     if (IS_ERR(dwsmscc->syscon))
0100         return PTR_ERR(dwsmscc->syscon);
0101 
0102     /* Deassert all CS */
0103     writel(0, dwsmscc->spi_mst + MSCC_SPI_MST_SW_MODE);
0104 
0105     /* Select the owner of the SI interface */
0106     regmap_update_bits(dwsmscc->syscon, MSCC_CPU_SYSTEM_CTRL_GENERAL_CTRL,
0107                MSCC_IF_SI_OWNER_MASK << if_si_owner_offset,
0108                MSCC_IF_SI_OWNER_SIMC << if_si_owner_offset);
0109 
0110     dwsmmio->dws.set_cs = dw_spi_mscc_set_cs;
0111     dwsmmio->priv = dwsmscc;
0112 
0113     return 0;
0114 }
0115 
0116 static int dw_spi_mscc_ocelot_init(struct platform_device *pdev,
0117                    struct dw_spi_mmio *dwsmmio)
0118 {
0119     return dw_spi_mscc_init(pdev, dwsmmio, "mscc,ocelot-cpu-syscon",
0120                 OCELOT_IF_SI_OWNER_OFFSET);
0121 }
0122 
0123 static int dw_spi_mscc_jaguar2_init(struct platform_device *pdev,
0124                     struct dw_spi_mmio *dwsmmio)
0125 {
0126     return dw_spi_mscc_init(pdev, dwsmmio, "mscc,jaguar2-cpu-syscon",
0127                 JAGUAR2_IF_SI_OWNER_OFFSET);
0128 }
0129 
0130 /*
0131  * The Designware SPI controller (referred to as master in the
0132  * documentation) automatically deasserts chip select when the tx fifo
0133  * is empty. The chip selects then needs to be driven by a CS override
0134  * register. enable is an active low signal.
0135  */
0136 static void dw_spi_sparx5_set_cs(struct spi_device *spi, bool enable)
0137 {
0138     struct dw_spi *dws = spi_master_get_devdata(spi->master);
0139     struct dw_spi_mmio *dwsmmio = container_of(dws, struct dw_spi_mmio, dws);
0140     struct dw_spi_mscc *dwsmscc = dwsmmio->priv;
0141     u8 cs = spi->chip_select;
0142 
0143     if (!enable) {
0144         /* CS override drive enable */
0145         regmap_write(dwsmscc->syscon, SPARX5_FORCE_ENA, 1);
0146         /* Now set CSx enabled */
0147         regmap_write(dwsmscc->syscon, SPARX5_FORCE_VAL, ~BIT(cs));
0148         /* Allow settle */
0149         usleep_range(1, 5);
0150     } else {
0151         /* CS value */
0152         regmap_write(dwsmscc->syscon, SPARX5_FORCE_VAL, ~0);
0153         /* Allow settle */
0154         usleep_range(1, 5);
0155         /* CS override drive disable */
0156         regmap_write(dwsmscc->syscon, SPARX5_FORCE_ENA, 0);
0157     }
0158 
0159     dw_spi_set_cs(spi, enable);
0160 }
0161 
0162 static int dw_spi_mscc_sparx5_init(struct platform_device *pdev,
0163                    struct dw_spi_mmio *dwsmmio)
0164 {
0165     const char *syscon_name = "microchip,sparx5-cpu-syscon";
0166     struct device *dev = &pdev->dev;
0167     struct dw_spi_mscc *dwsmscc;
0168 
0169     if (!IS_ENABLED(CONFIG_SPI_MUX)) {
0170         dev_err(dev, "This driver needs CONFIG_SPI_MUX\n");
0171         return -EOPNOTSUPP;
0172     }
0173 
0174     dwsmscc = devm_kzalloc(dev, sizeof(*dwsmscc), GFP_KERNEL);
0175     if (!dwsmscc)
0176         return -ENOMEM;
0177 
0178     dwsmscc->syscon =
0179         syscon_regmap_lookup_by_compatible(syscon_name);
0180     if (IS_ERR(dwsmscc->syscon)) {
0181         dev_err(dev, "No syscon map %s\n", syscon_name);
0182         return PTR_ERR(dwsmscc->syscon);
0183     }
0184 
0185     dwsmmio->dws.set_cs = dw_spi_sparx5_set_cs;
0186     dwsmmio->priv = dwsmscc;
0187 
0188     return 0;
0189 }
0190 
0191 static int dw_spi_alpine_init(struct platform_device *pdev,
0192                   struct dw_spi_mmio *dwsmmio)
0193 {
0194     dwsmmio->dws.caps = DW_SPI_CAP_CS_OVERRIDE;
0195 
0196     return 0;
0197 }
0198 
0199 static int dw_spi_pssi_init(struct platform_device *pdev,
0200                 struct dw_spi_mmio *dwsmmio)
0201 {
0202     dw_spi_dma_setup_generic(&dwsmmio->dws);
0203 
0204     return 0;
0205 }
0206 
0207 static int dw_spi_hssi_init(struct platform_device *pdev,
0208                 struct dw_spi_mmio *dwsmmio)
0209 {
0210     dwsmmio->dws.ip = DW_HSSI_ID;
0211 
0212     dw_spi_dma_setup_generic(&dwsmmio->dws);
0213 
0214     return 0;
0215 }
0216 
0217 static int dw_spi_intel_init(struct platform_device *pdev,
0218                  struct dw_spi_mmio *dwsmmio)
0219 {
0220     dwsmmio->dws.ip = DW_HSSI_ID;
0221 
0222     return 0;
0223 }
0224 
0225 static int dw_spi_canaan_k210_init(struct platform_device *pdev,
0226                    struct dw_spi_mmio *dwsmmio)
0227 {
0228     /*
0229      * The Canaan Kendryte K210 SoC DW apb_ssi v4 spi controller is
0230      * documented to have a 32 word deep TX and RX FIFO, which
0231      * spi_hw_init() detects. However, when the RX FIFO is filled up to
0232      * 32 entries (RXFLR = 32), an RX FIFO overrun error occurs. Avoid this
0233      * problem by force setting fifo_len to 31.
0234      */
0235     dwsmmio->dws.fifo_len = 31;
0236 
0237     return 0;
0238 }
0239 
0240 static int dw_spi_mmio_probe(struct platform_device *pdev)
0241 {
0242     int (*init_func)(struct platform_device *pdev,
0243              struct dw_spi_mmio *dwsmmio);
0244     struct dw_spi_mmio *dwsmmio;
0245     struct resource *mem;
0246     struct dw_spi *dws;
0247     int ret;
0248     int num_cs;
0249 
0250     dwsmmio = devm_kzalloc(&pdev->dev, sizeof(struct dw_spi_mmio),
0251             GFP_KERNEL);
0252     if (!dwsmmio)
0253         return -ENOMEM;
0254 
0255     dws = &dwsmmio->dws;
0256 
0257     /* Get basic io resource and map it */
0258     dws->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem);
0259     if (IS_ERR(dws->regs))
0260         return PTR_ERR(dws->regs);
0261 
0262     dws->paddr = mem->start;
0263 
0264     dws->irq = platform_get_irq(pdev, 0);
0265     if (dws->irq < 0)
0266         return dws->irq; /* -ENXIO */
0267 
0268     dwsmmio->clk = devm_clk_get(&pdev->dev, NULL);
0269     if (IS_ERR(dwsmmio->clk))
0270         return PTR_ERR(dwsmmio->clk);
0271     ret = clk_prepare_enable(dwsmmio->clk);
0272     if (ret)
0273         return ret;
0274 
0275     /* Optional clock needed to access the registers */
0276     dwsmmio->pclk = devm_clk_get_optional(&pdev->dev, "pclk");
0277     if (IS_ERR(dwsmmio->pclk)) {
0278         ret = PTR_ERR(dwsmmio->pclk);
0279         goto out_clk;
0280     }
0281     ret = clk_prepare_enable(dwsmmio->pclk);
0282     if (ret)
0283         goto out_clk;
0284 
0285     /* find an optional reset controller */
0286     dwsmmio->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, "spi");
0287     if (IS_ERR(dwsmmio->rstc)) {
0288         ret = PTR_ERR(dwsmmio->rstc);
0289         goto out_clk;
0290     }
0291     reset_control_deassert(dwsmmio->rstc);
0292 
0293     dws->bus_num = pdev->id;
0294 
0295     dws->max_freq = clk_get_rate(dwsmmio->clk);
0296 
0297     device_property_read_u32(&pdev->dev, "reg-io-width", &dws->reg_io_width);
0298 
0299     num_cs = 4;
0300 
0301     device_property_read_u32(&pdev->dev, "num-cs", &num_cs);
0302 
0303     dws->num_cs = num_cs;
0304 
0305     init_func = device_get_match_data(&pdev->dev);
0306     if (init_func) {
0307         ret = init_func(pdev, dwsmmio);
0308         if (ret)
0309             goto out;
0310     }
0311 
0312     pm_runtime_enable(&pdev->dev);
0313 
0314     ret = dw_spi_add_host(&pdev->dev, dws);
0315     if (ret)
0316         goto out;
0317 
0318     platform_set_drvdata(pdev, dwsmmio);
0319     return 0;
0320 
0321 out:
0322     pm_runtime_disable(&pdev->dev);
0323     clk_disable_unprepare(dwsmmio->pclk);
0324 out_clk:
0325     clk_disable_unprepare(dwsmmio->clk);
0326     reset_control_assert(dwsmmio->rstc);
0327 
0328     return ret;
0329 }
0330 
0331 static int dw_spi_mmio_remove(struct platform_device *pdev)
0332 {
0333     struct dw_spi_mmio *dwsmmio = platform_get_drvdata(pdev);
0334 
0335     dw_spi_remove_host(&dwsmmio->dws);
0336     pm_runtime_disable(&pdev->dev);
0337     clk_disable_unprepare(dwsmmio->pclk);
0338     clk_disable_unprepare(dwsmmio->clk);
0339     reset_control_assert(dwsmmio->rstc);
0340 
0341     return 0;
0342 }
0343 
0344 static const struct of_device_id dw_spi_mmio_of_match[] = {
0345     { .compatible = "snps,dw-apb-ssi", .data = dw_spi_pssi_init},
0346     { .compatible = "mscc,ocelot-spi", .data = dw_spi_mscc_ocelot_init},
0347     { .compatible = "mscc,jaguar2-spi", .data = dw_spi_mscc_jaguar2_init},
0348     { .compatible = "amazon,alpine-dw-apb-ssi", .data = dw_spi_alpine_init},
0349     { .compatible = "renesas,rzn1-spi", .data = dw_spi_pssi_init},
0350     { .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_hssi_init},
0351     { .compatible = "intel,keembay-ssi", .data = dw_spi_intel_init},
0352     { .compatible = "intel,thunderbay-ssi", .data = dw_spi_intel_init},
0353     { .compatible = "microchip,sparx5-spi", dw_spi_mscc_sparx5_init},
0354     { .compatible = "canaan,k210-spi", dw_spi_canaan_k210_init},
0355     { /* end of table */}
0356 };
0357 MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match);
0358 
0359 #ifdef CONFIG_ACPI
0360 static const struct acpi_device_id dw_spi_mmio_acpi_match[] = {
0361     {"HISI0173", (kernel_ulong_t)dw_spi_pssi_init},
0362     {},
0363 };
0364 MODULE_DEVICE_TABLE(acpi, dw_spi_mmio_acpi_match);
0365 #endif
0366 
0367 static struct platform_driver dw_spi_mmio_driver = {
0368     .probe      = dw_spi_mmio_probe,
0369     .remove     = dw_spi_mmio_remove,
0370     .driver     = {
0371         .name   = DRIVER_NAME,
0372         .of_match_table = dw_spi_mmio_of_match,
0373         .acpi_match_table = ACPI_PTR(dw_spi_mmio_acpi_match),
0374     },
0375 };
0376 module_platform_driver(dw_spi_mmio_driver);
0377 
0378 MODULE_AUTHOR("Jean-Hugues Deschenes <jean-hugues.deschenes@octasic.com>");
0379 MODULE_DESCRIPTION("Memory-mapped I/O interface driver for DW SPI Core");
0380 MODULE_LICENSE("GPL v2");
0381 MODULE_IMPORT_NS(SPI_DW_CORE);