From 714c99f993097e5c16822e73ba0a7945b86a20ea Mon Sep 17 00:00:00 2001 From: "xingyu.wu" Date: Tue, 28 Jun 2022 22:48:15 +0800 Subject: [PATCH 20/55] spi-pl022:starfive:Add platform bus register to adapt overlay Add platform bus register to adapt dtbo overlay. Signed-off-by: Xingyu Wu Signed-off-by: Hal Feng --- drivers/spi/spi-pl022.c | 143 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 137 insertions(+), 6 deletions(-) --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -34,6 +34,7 @@ #include #include #include +#include /* * This macro is used to define some register default values. @@ -1841,7 +1842,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; @@ -1861,6 +1865,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); @@ -1916,7 +1928,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; @@ -1925,14 +1941,28 @@ 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_enabled(&adev->dev, NULL); + if (platform_flag) + pl022->clk = clk_get(&adev->dev, NULL); + else + 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; } - pl022->rst = devm_reset_control_get(&adev->dev, NULL); + 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); if (IS_ERR(pl022->rst)) { status = PTR_ERR(pl022->rst); dev_err(&adev->dev, "could not retrieve SSP/SPI bus reset\n"); @@ -1950,7 +1980,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); @@ -2000,13 +2034,24 @@ 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; } @@ -2211,6 +2256,89 @@ 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 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_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); +} + +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 "); MODULE_AUTHOR("Linus Walleij "); MODULE_DESCRIPTION("PL022 SSP Controller Driver"); MODULE_LICENSE("GPL");