From 733e7bd23a1efad15a724fbdbce8d9f06aa6813a Mon Sep 17 00:00:00 2001 From: "ziv.xu" Date: Wed, 23 Nov 2022 14:53:58 +0800 Subject: [PATCH 103/116] spi-pl022-starfive:fix the problem of spi overlay reload fix the problem of spi overlay reload Signed-off-by: ziv.xu Signed-off-by: Hal Feng --- drivers/spi/spi-pl022.c | 270 ++++++++++++++++++++++++++++------------ 1 file changed, 188 insertions(+), 82 deletions(-) --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -2106,6 +2106,172 @@ pl022_platform_data_dt_get(struct device return pd; } +static int pl022_platform_probe(struct platform_device *pdev, const struct amba_id *id) +{ + struct device *dev = &pdev->dev; + struct spi_controller *host; + struct pl022_ssp_controller *platform_info; + struct amba_device *adev; + struct pl022 *pl022 = NULL; + struct resource *res; + int status = 0; + int irq; + + dev_info(dev, + "ARM PL022 driver for StarFive SoC platform, device ID: 0x%08x\n", + id->id); + + adev = devm_kzalloc(dev, sizeof(*adev), GFP_KERNEL); + adev->dev = pdev->dev; + platform_info = pl022_platform_data_dt_get(dev); + if (!platform_info) { + dev_err(dev, "probe: no platform data defined\n"); + return -ENODEV; + } + /* Allocate host with space for data */ + host = spi_alloc_host(dev, sizeof(struct pl022)); + if (host == NULL) { + dev_err(dev, "probe - cannot alloc SPI host\n"); + return -ENOMEM; + } + + pl022 = spi_controller_get_devdata(host); + pl022->host = host; + pl022->host_info = platform_info; + pl022->adev = adev; + pl022->vendor = id->data; + pl022->host->dev.parent = &pdev->dev; + /* + * Bus Number Which has been Assigned to this SSP controller + * on this board + */ + host->bus_num = platform_info->bus_id; + host->cleanup = pl022_cleanup; + host->setup = pl022_setup; + /* If open CONFIG_PM, auto_runtime_pm should be false when of-platform.*/ + host->auto_runtime_pm = true; + host->transfer_one_message = pl022_transfer_one_message; + host->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware; + host->rt = platform_info->rt; + host->dev.of_node = dev->of_node; + host->use_gpio_descriptors = true; + + /* + * Supports mode 0-3, loopback, and active low CS. Transfers are + * always MS bit first on the original pl022. + */ + host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; + if (pl022->vendor->extended_cr) + host->mode_bits |= SPI_LSB_FIRST; + + dev_dbg(dev, "BUSNO: %d\n", host->bus_num); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pl022->phybase = res->start; + pl022->virtbase = devm_ioremap_resource(dev, res); + if (pl022->virtbase == NULL) { + status = -ENOMEM; + goto err_no_ioremap; + } + dev_info(dev, "mapped registers from %llx to %llx\n", + pdev->resource->start, pdev->resource->end); + + pl022->clk = devm_clk_get(dev, NULL); + if (IS_ERR(pl022->clk)) { + status = PTR_ERR(pl022->clk); + dev_err(dev, "could not retrieve SSP/SPI bus clock\n"); + goto err_no_clk; + } + status = clk_prepare_enable(pl022->clk); + if (status) { + dev_err(dev, "could not enable SSP/SPI bus clock\n"); + goto err_no_clk_en; + } + + pl022->rst = devm_reset_control_get_exclusive(dev, NULL); + if (!IS_ERR(pl022->rst)) { + status = reset_control_deassert(pl022->rst); + if (status) { + dev_err(dev, "could not deassert SSP/SPI bus reset\n"); + goto err_no_rst_clr; + } + } else { + status = PTR_ERR(pl022->rst); + dev_err(dev, "could not retrieve SSP/SPI bus reset\n"); + goto err_no_rst; + } + + /* Initialize transfer pump */ + tasklet_init(&pl022->pump_transfers, pump_transfers, + (unsigned long)pl022); + + /* Disable SSP */ + writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)), + SSP_CR1(pl022->virtbase)); + load_ssp_default_config(pl022); + + /* Obtain IRQ line. */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + status = -ENXIO; + goto err_no_irq; + } + status = devm_request_irq(dev, irq, pl022_interrupt_handler, + 0, "pl022", pl022); + if (status < 0) { + dev_err(dev, "probe - cannot get IRQ (%d)\n", status); + goto err_no_irq; + } + + /* Get DMA channels, try autoconfiguration first */ + status = pl022_dma_autoprobe(pl022); + if (status == -EPROBE_DEFER) { + dev_dbg(dev, "deferring probe to get DMA channel\n"); + goto err_no_irq; + } + + /* dma is not used unless configured in the device tree */ + platform_info->enable_dma = 0; + + /* If that failed, use channels from platform_info */ + if (status == 0) + platform_info->enable_dma = 1; + else if (platform_info->enable_dma) { + status = pl022_dma_probe(pl022); + if (status != 0) + platform_info->enable_dma = 0; + } + + /* Register with the SPI framework */ + dev_set_drvdata(dev, pl022); + + status = devm_spi_register_controller(dev, host); + if (status != 0) { + dev_err(dev, + "probe - problem registering spi host\n"); + goto err_spi_register; + } + dev_dbg(dev, "probe succeeded\n"); + + clk_disable_unprepare(pl022->clk); + + return 0; + err_spi_register: + if (platform_info->enable_dma) + pl022_dma_remove(pl022); + err_no_irq: + reset_control_assert(pl022->rst); + err_no_rst_clr: + err_no_rst: + clk_disable_unprepare(pl022->clk); + err_no_clk_en: + err_no_clk: + err_no_ioremap: + release_mem_region(pdev->resource->start, resource_size(pdev->resource)); + spi_controller_put(host); + return status; +} + static int pl022_probe(struct amba_device *adev, const struct amba_id *id) { struct device *dev = &adev->dev; @@ -2114,14 +2280,6 @@ static int pl022_probe(struct amba_devic struct spi_controller *host; struct pl022 *pl022 = NULL; /*Data for this driver */ int status = 0; - int platform_flag = 0; - - if (strncmp(dev->bus->name, "platform", strlen("platform"))) - platform_flag = 0; - else - platform_flag = 1; - dev_dbg(&adev->dev, "bus name:%s platform flag:%d", - dev->bus->name, platform_flag); dev_info(&adev->dev, "ARM PL022 driver, device ID: 0x%08x\n", adev->periphid); @@ -2175,11 +2333,7 @@ static int pl022_probe(struct amba_devic goto err_no_ioregion; pl022->phybase = adev->res.start; - if (platform_flag) - pl022->virtbase = ioremap(adev->res.start, - resource_size(&adev->res)); - else - pl022->virtbase = devm_ioremap(dev, adev->res.start, + pl022->virtbase = devm_ioremap(dev, adev->res.start, resource_size(&adev->res)); if (pl022->virtbase == NULL) { status = -ENOMEM; @@ -2188,10 +2342,7 @@ static int pl022_probe(struct amba_devic dev_info(&adev->dev, "mapped registers from %pa to %p\n", &adev->res.start, pl022->virtbase); - if (platform_flag) - pl022->clk = clk_get(&adev->dev, NULL); - else - pl022->clk = devm_clk_get(&adev->dev, NULL); + pl022->clk = devm_clk_get(&adev->dev, NULL); if (IS_ERR(pl022->clk)) { status = PTR_ERR(pl022->clk); dev_err(&adev->dev, "could not retrieve SSP/SPI bus clock\n"); @@ -2204,10 +2355,7 @@ static int pl022_probe(struct amba_devic goto err_no_clk_en; } - if (platform_flag) - pl022->rst = reset_control_get_exclusive(&adev->dev, NULL); - else - pl022->rst = devm_reset_control_get(&adev->dev, NULL); + pl022->rst = devm_reset_control_get(&adev->dev, NULL); if (IS_ERR(pl022->rst)) { status = PTR_ERR(pl022->rst); dev_err(&adev->dev, "could not retrieve SSP/SPI bus reset\n"); @@ -2229,11 +2377,7 @@ static int pl022_probe(struct amba_devic SSP_CR1(pl022->virtbase)); load_ssp_default_config(pl022); - if (platform_flag) - status = request_irq(adev->irq[0], pl022_interrupt_handler, - 0, "pl022", pl022); - else - status = devm_request_irq(dev, adev->irq[0], pl022_interrupt_handler, + status = devm_request_irq(dev, adev->irq[0], pl022_interrupt_handler, 0, "pl022", pl022); if (status < 0) { dev_err(&adev->dev, "probe - cannot get IRQ (%d)\n", status); @@ -2258,18 +2402,16 @@ static int pl022_probe(struct amba_devic /* Register with the SPI framework */ amba_set_drvdata(adev, pl022); - if (platform_flag) - status = spi_register_controller(host); - else - status = devm_spi_register_controller(&adev->dev, host); + + status = devm_spi_register_controller(&adev->dev, host); if (status != 0) { dev_err_probe(&adev->dev, status, "problem registering spi host\n"); goto err_spi_register; } dev_dbg(dev, "probe succeeded\n"); - if (!platform_flag) - platform_info->autosuspend_delay = 100; + + platform_info->autosuspend_delay = 100; /* let runtime pm put suspend */ if (platform_info->autosuspend_delay > 0) { dev_info(&adev->dev, @@ -2279,10 +2421,8 @@ static int pl022_probe(struct amba_devic platform_info->autosuspend_delay); pm_runtime_use_autosuspend(dev); } - if (platform_flag) - clk_disable_unprepare(pl022->clk); - else - pm_runtime_put(dev); + + pm_runtime_put(dev); return 0; @@ -2290,26 +2430,17 @@ static int pl022_probe(struct amba_devic if (platform_info->enable_dma) pl022_dma_remove(pl022); err_no_irq: - if (platform_flag) - free_irq(adev->irq[0], pl022); reset_control_assert(pl022->rst); err_no_rst_de: - if (platform_flag) - reset_control_put(pl022->rst); err_no_rst: clk_disable_unprepare(pl022->clk); err_no_clk_en: - if (platform_flag) - clk_put(pl022->clk); err_no_clk: - if (platform_flag) - iounmap(pl022->virtbase); err_no_ioremap: amba_release_regions(adev); err_no_ioregion: spi_controller_put(host); - if (platform_flag) - kfree(platform_info); + return status; } @@ -2523,23 +2654,8 @@ static int starfive_of_pl022_probe(struc .mask = 0x000fffff, .data = &vendor_arm }; - struct amba_device *pcdev; struct device *dev = &pdev->dev; - pcdev = devm_kzalloc(&pdev->dev, sizeof(*pcdev), GFP_KERNEL); - if (!pcdev) - return -ENOMEM; - - pcdev->dev = pdev->dev; - pcdev->periphid = id.id; - pcdev->res = *(pdev->resource); - - pcdev->irq[0] = platform_get_irq(pdev, 0); - if (pcdev->irq[0] < 0) { - dev_err(dev, "failed to get irq\n"); - ret = -EINVAL; - } - ret = of_clk_set_defaults(dev->of_node, false); if (ret < 0) goto err_probe; @@ -2548,16 +2664,11 @@ static int starfive_of_pl022_probe(struc if (ret) goto err_probe; - ret = pl022_probe(pcdev, &id); + ret = pl022_platform_probe(pdev, &id); - struct pl022 *pl022 = amba_get_drvdata(pcdev); - - pl022->host->dev.parent = &pdev->dev; - platform_set_drvdata(pdev, pl022); - - pm_runtime_enable(&pdev->dev); - pm_runtime_set_autosuspend_delay(&pdev->dev, 100); - pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(dev); + pm_runtime_set_autosuspend_delay(dev, 100); + pm_runtime_use_autosuspend(dev); if (ret) { pm_runtime_disable(dev); @@ -2572,32 +2683,27 @@ err_probe: static int starfive_of_pl022_remove(struct platform_device *pdev) { - u32 size; - int irq; struct pl022 *pl022 = dev_get_drvdata(&pdev->dev); if (!pl022) return 0; + pm_runtime_get_sync(&pdev->dev); pm_runtime_get_noresume(&pdev->dev); load_ssp_default_config(pl022); if (pl022->host_info->enable_dma) pl022_dma_remove(pl022); - irq = platform_get_irq(pdev, 0); - free_irq(irq, pl022); - reset_control_assert(pl022->rst); - reset_control_put(pl022->rst); clk_disable_unprepare(pl022->clk); - clk_put(pl022->clk); - iounmap(pl022->virtbase); - kfree(pl022->host_info); - - size = resource_size(pdev->resource); - release_mem_region(pdev->resource->start, size); tasklet_disable(&pl022->pump_transfers); + + pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + dev_pm_domain_detach(&pdev->dev, true); + return 0; }