summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Osipenko <digetx@gmail.com>2021-12-01 00:23:36 +0100
committerThierry Reding <treding@nvidia.com>2021-12-16 14:03:38 +0100
commit88724b78a84c85350c21ac8d4432f2cf5a77a10a (patch)
tree4e53004adcadf48a472f8a8df7ae6f1e74a36fdc
parentsoc/tegra: fuse: Reset hardware (diff)
downloadlinux-88724b78a84c85350c21ac8d4432f2cf5a77a10a.tar.xz
linux-88724b78a84c85350c21ac8d4432f2cf5a77a10a.zip
soc/tegra: fuse: Use resource-managed helpers
Use resource-managed helpers to make code cleaner and more correct, properly releasing all resources in case of driver probe error. Signed-off-by: Dmitry Osipenko <digetx@gmail.com> Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r--drivers/soc/tegra/fuse/fuse-tegra.c32
-rw-r--r--drivers/soc/tegra/fuse/fuse-tegra20.c33
2 files changed, 48 insertions, 17 deletions
diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c
index cc032729a143..fe4f935ce73a 100644
--- a/drivers/soc/tegra/fuse/fuse-tegra.c
+++ b/drivers/soc/tegra/fuse/fuse-tegra.c
@@ -182,6 +182,12 @@ static const struct nvmem_cell_info tegra_fuse_cells[] = {
},
};
+static void tegra_fuse_restore(void *base)
+{
+ fuse->clk = NULL;
+ fuse->base = base;
+}
+
static int tegra_fuse_probe(struct platform_device *pdev)
{
void __iomem *base = fuse->base;
@@ -189,13 +195,16 @@ static int tegra_fuse_probe(struct platform_device *pdev)
struct resource *res;
int err;
+ err = devm_add_action(&pdev->dev, tegra_fuse_restore, base);
+ if (err)
+ return err;
+
/* take over the memory region from the early initialization */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
fuse->phys = res->start;
fuse->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(fuse->base)) {
err = PTR_ERR(fuse->base);
- fuse->base = base;
return err;
}
@@ -205,19 +214,20 @@ static int tegra_fuse_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to get FUSE clock: %ld",
PTR_ERR(fuse->clk));
- fuse->base = base;
return PTR_ERR(fuse->clk);
}
platform_set_drvdata(pdev, fuse);
fuse->dev = &pdev->dev;
- pm_runtime_enable(&pdev->dev);
+ err = devm_pm_runtime_enable(&pdev->dev);
+ if (err)
+ return err;
if (fuse->soc->probe) {
err = fuse->soc->probe(fuse);
if (err < 0)
- goto restore;
+ return err;
}
memset(&nvmem, 0, sizeof(nvmem));
@@ -241,7 +251,7 @@ static int tegra_fuse_probe(struct platform_device *pdev)
err = PTR_ERR(fuse->nvmem);
dev_err(&pdev->dev, "failed to register NVMEM device: %d\n",
err);
- goto restore;
+ return err;
}
fuse->rst = devm_reset_control_get_optional(&pdev->dev, "fuse");
@@ -249,7 +259,7 @@ static int tegra_fuse_probe(struct platform_device *pdev)
err = PTR_ERR(fuse->rst);
dev_err(&pdev->dev, "failed to get FUSE reset: %pe\n",
fuse->rst);
- goto restore;
+ return err;
}
/*
@@ -258,26 +268,20 @@ static int tegra_fuse_probe(struct platform_device *pdev)
*/
err = pm_runtime_resume_and_get(&pdev->dev);
if (err)
- goto restore;
+ return err;
err = reset_control_reset(fuse->rst);
pm_runtime_put(&pdev->dev);
if (err < 0) {
dev_err(&pdev->dev, "failed to reset FUSE: %d\n", err);
- goto restore;
+ return err;
}
/* release the early I/O memory mapping */
iounmap(base);
return 0;
-
-restore:
- fuse->clk = NULL;
- fuse->base = base;
- pm_runtime_disable(&pdev->dev);
- return err;
}
static int __maybe_unused tegra_fuse_runtime_resume(struct device *dev)
diff --git a/drivers/soc/tegra/fuse/fuse-tegra20.c b/drivers/soc/tegra/fuse/fuse-tegra20.c
index 8ec9fc5e5e4b..12503f563e36 100644
--- a/drivers/soc/tegra/fuse/fuse-tegra20.c
+++ b/drivers/soc/tegra/fuse/fuse-tegra20.c
@@ -94,9 +94,28 @@ static bool dma_filter(struct dma_chan *chan, void *filter_param)
return of_device_is_compatible(np, "nvidia,tegra20-apbdma");
}
+static void tegra20_fuse_release_channel(void *data)
+{
+ struct tegra_fuse *fuse = data;
+
+ dma_release_channel(fuse->apbdma.chan);
+ fuse->apbdma.chan = NULL;
+}
+
+static void tegra20_fuse_free_coherent(void *data)
+{
+ struct tegra_fuse *fuse = data;
+
+ dma_free_coherent(fuse->dev, sizeof(u32), fuse->apbdma.virt,
+ fuse->apbdma.phys);
+ fuse->apbdma.virt = NULL;
+ fuse->apbdma.phys = 0x0;
+}
+
static int tegra20_fuse_probe(struct tegra_fuse *fuse)
{
dma_cap_mask_t mask;
+ int err;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
@@ -105,13 +124,21 @@ static int tegra20_fuse_probe(struct tegra_fuse *fuse)
if (!fuse->apbdma.chan)
return -EPROBE_DEFER;
+ err = devm_add_action_or_reset(fuse->dev, tegra20_fuse_release_channel,
+ fuse);
+ if (err)
+ return err;
+
fuse->apbdma.virt = dma_alloc_coherent(fuse->dev, sizeof(u32),
&fuse->apbdma.phys,
GFP_KERNEL);
- if (!fuse->apbdma.virt) {
- dma_release_channel(fuse->apbdma.chan);
+ if (!fuse->apbdma.virt)
return -ENOMEM;
- }
+
+ err = devm_add_action_or_reset(fuse->dev, tegra20_fuse_free_coherent,
+ fuse);
+ if (err)
+ return err;
fuse->apbdma.config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
fuse->apbdma.config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;