From 7a98fafdc544b85694db5d99cdf933a4640058f9 Mon Sep 17 00:00:00 2001
From: "ziv.xu" <ziv.xu@starfive.com>
Date: Wed, 23 Nov 2022 14:53:58 +0800
Subject: [PATCH 22/55] spi-pl022-starfive:fix the problem of spi overlay
 reload

fix the problem of spi overlay reload

Signed-off-by: ziv.xu <ziv.xu@starfive.com>
Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
---
 drivers/spi/spi-pl022.c | 266 ++++++++++++++++++++++++++--------------
 1 file changed, 177 insertions(+), 89 deletions(-)

--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -1859,6 +1859,163 @@ 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 = pl022_transfer_one;
+	host->set_cs = pl022_cs_control;
+	host->handle_err = pl022_handle_err;
+	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_enabled(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;
+	}
+
+	pl022->rst = devm_reset_control_get_exclusive(dev, NULL);
+	if (IS_ERR(pl022->rst)) {
+		status = PTR_ERR(pl022->rst);
+		dev_err(dev, "could not retrieve SSP/SPI bus reset\n");
+		goto err_no_rst;
+	}
+
+	status = reset_control_deassert(pl022->rst);
+	if (status) {
+		dev_err(dev, "could not deassert SSP/SPI bus reset\n");
+		goto err_no_rst_de;
+	}
+
+	/* 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_de:
+ err_no_rst:
+ 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;
@@ -1867,14 +2024,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);
@@ -1930,11 +2079,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;
@@ -1943,28 +2088,14 @@ 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_enabled(&adev->dev, NULL);
+	pl022->clk = devm_clk_get_enabled(&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");
 		goto err_no_clk;
 	}
 
-	if (platform_flag) {
-		status = clk_prepare_enable(pl022->clk);
-		if (status) {
-			dev_err(&adev->dev, "could not enable SSP/SPI bus clock\n");
-			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");
@@ -1982,11 +2113,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);
@@ -2011,18 +2138,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,
@@ -2032,10 +2157,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;
 
@@ -2043,24 +2166,15 @@ 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:
-	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;
 }
 
@@ -2272,23 +2386,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;
@@ -2297,16 +2396,11 @@ static int starfive_of_pl022_probe(struc
 	if (ret)
 		goto err_probe;
 
-	ret = pl022_probe(pcdev, &id);
-
-	struct pl022 *pl022 = amba_get_drvdata(pcdev);
-
-	pl022->host->dev.parent = &pdev->dev;
-	platform_set_drvdata(pdev, pl022);
+	ret = pl022_platform_probe(pdev, &id);
 
-	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);
@@ -2321,31 +2415,25 @@ err_probe:
 
 static void starfive_of_pl022_remove(struct platform_device *pdev)
 {
-	u32 size;
-	int irq;
 	struct pl022 *pl022 = dev_get_drvdata(&pdev->dev);
 
 	if (!pl022)
 		return;
 
+	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);
+	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);
 }
 
 static const struct of_device_id starfive_of_pl022_match[] = {
