From c609818850807a1ae5fa17e165f2b66b914188b4 Mon Sep 17 00:00:00 2001
From: "xingyu.wu" <xingyu.wu@starfivetech.com>
Date: Tue, 28 Jun 2022 22:48:15 +0800
Subject: [PATCH 101/116] spi-pl022:starfive:Add platform bus register to adapt
 overlay

Add platform bus register to adapt dtbo overlay.

Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com>
Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
---
 drivers/spi/spi-pl022.c | 137 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 131 insertions(+), 6 deletions(-)

--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -34,6 +34,7 @@
 #include <linux/of.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/reset.h>
+#include <linux/platform_device.h>
 
 /*
  * This macro is used to define some register default values.
@@ -2088,7 +2089,10 @@ pl022_platform_data_dt_get(struct device
 		return NULL;
 	}
 
-	pd = devm_kzalloc(dev, sizeof(struct pl022_ssp_controller), GFP_KERNEL);
+	if (strncmp(dev->bus->name, "platform", strlen("platform")))
+		pd = devm_kzalloc(dev, sizeof(struct pl022_ssp_controller), GFP_KERNEL);
+	else
+		pd = kzalloc(sizeof(struct pl022_ssp_controller), GFP_KERNEL);
 	if (!pd)
 		return NULL;
 
@@ -2108,6 +2112,14 @@ 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);
@@ -2161,7 +2173,11 @@ static int pl022_probe(struct amba_devic
 		goto err_no_ioregion;
 
 	pl022->phybase = adev->res.start;
-	pl022->virtbase = devm_ioremap(dev, 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,
 				       resource_size(&adev->res));
 	if (pl022->virtbase == NULL) {
 		status = -ENOMEM;
@@ -2170,7 +2186,10 @@ static int pl022_probe(struct amba_devic
 	dev_info(&adev->dev, "mapped registers from %pa to %p\n",
 		&adev->res.start, pl022->virtbase);
 
-	pl022->clk = devm_clk_get(&adev->dev, NULL);
+	if (platform_flag)
+		pl022->clk = clk_get(&adev->dev, NULL);
+	else
+		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");
@@ -2183,7 +2202,10 @@ static int pl022_probe(struct amba_devic
 		goto err_no_clk_en;
 	}
 
-	pl022->rst = devm_reset_control_get(&adev->dev, NULL);
+	if (platform_flag)
+		pl022->rst = reset_control_get_exclusive(&adev->dev, NULL);
+	else
+		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");
@@ -2205,7 +2227,11 @@ static int pl022_probe(struct amba_devic
 	       SSP_CR1(pl022->virtbase));
 	load_ssp_default_config(pl022);
 
-	status = devm_request_irq(dev, adev->irq[0], pl022_interrupt_handler,
+	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,
 				  0, "pl022", pl022);
 	if (status < 0) {
 		dev_err(&adev->dev, "probe - cannot get IRQ (%d)\n", status);
@@ -2230,7 +2256,10 @@ static int pl022_probe(struct amba_devic
 
 	/* Register with the SPI framework */
 	amba_set_drvdata(adev, pl022);
-	status = devm_spi_register_controller(&adev->dev, host);
+	if (platform_flag)
+		status = spi_register_controller(host);
+	else
+		status = devm_spi_register_controller(&adev->dev, host);
 	if (status != 0) {
 		dev_err_probe(&adev->dev, status,
 			      "problem registering spi host\n");
@@ -2255,15 +2284,26 @@ 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;
 }
 
@@ -2464,6 +2504,91 @@ static void __exit pl022_exit(void)
 }
 module_exit(pl022_exit);
 
+/*
+ * Register PL022 in platform bus to accommodate overlay use.
+ * Because overlay only trigger response from the platform bus
+ * not amba bus.
+ */
+static int starfive_of_pl022_probe(struct platform_device *pdev)
+{
+	int ret;
+	const struct amba_id id = {
+		.id = 0x00041022,
+		.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 = pl022_probe(pcdev, &id);
+
+	return ret;
+}
+
+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_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);
+	return 0;
+}
+
+static const struct of_device_id starfive_of_pl022_match[] = {
+	{ .compatible = "starfive,jh7110-spi-pl022" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, starfive_of_pl022_match);
+
+static struct platform_driver starfive_of_pl022_driver = {
+	.driver = {
+		.name = "starfive-spi-pl022",
+		.of_match_table = starfive_of_pl022_match,
+		.pm	= &pl022_dev_pm_ops,
+	},
+	.probe = starfive_of_pl022_probe,
+	.remove = starfive_of_pl022_remove,
+};
+
+module_platform_driver(starfive_of_pl022_driver);
+/* platform register end */
+
+MODULE_AUTHOR("xingyu.wu <xingyu.wu@starfivetech.com>");
 MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
 MODULE_DESCRIPTION("PL022 SSP Controller Driver");
 MODULE_LICENSE("GPL");
