summaryrefslogtreecommitdiff
path: root/drivers/video/fbdev/simplefb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/fbdev/simplefb.c')
-rw-r--r--drivers/video/fbdev/simplefb.c31
1 files changed, 23 insertions, 8 deletions
diff --git a/drivers/video/fbdev/simplefb.c b/drivers/video/fbdev/simplefb.c
index 1893815dc67f..6acf5a00c2ba 100644
--- a/drivers/video/fbdev/simplefb.c
+++ b/drivers/video/fbdev/simplefb.c
@@ -93,6 +93,7 @@ struct simplefb_par {
static void simplefb_clocks_destroy(struct simplefb_par *par);
static void simplefb_regulators_destroy(struct simplefb_par *par);
+static void simplefb_detach_genpds(void *res);
/*
* fb_ops.fb_destroy is called by the last put_fb_info() call at the end
@@ -105,6 +106,7 @@ static void simplefb_destroy(struct fb_info *info)
simplefb_regulators_destroy(info->par);
simplefb_clocks_destroy(info->par);
+ simplefb_detach_genpds(info->par);
if (info->screen_base)
iounmap(info->screen_base);
@@ -445,13 +447,14 @@ static void simplefb_detach_genpds(void *res)
if (!IS_ERR_OR_NULL(par->genpds[i]))
dev_pm_domain_detach(par->genpds[i], true);
}
+ par->num_genpds = 0;
}
static int simplefb_attach_genpds(struct simplefb_par *par,
struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- unsigned int i;
+ unsigned int i, num_genpds;
int err;
err = of_count_phandle_with_args(dev->of_node, "power-domains",
@@ -465,26 +468,35 @@ static int simplefb_attach_genpds(struct simplefb_par *par,
return err;
}
- par->num_genpds = err;
+ num_genpds = err;
/*
* Single power-domain devices are handled by the driver core, so
* nothing to do here.
*/
- if (par->num_genpds <= 1)
+ if (num_genpds <= 1) {
+ par->num_genpds = num_genpds;
return 0;
+ }
- par->genpds = devm_kcalloc(dev, par->num_genpds, sizeof(*par->genpds),
+ par->genpds = devm_kcalloc(dev, num_genpds, sizeof(*par->genpds),
GFP_KERNEL);
if (!par->genpds)
return -ENOMEM;
- par->genpd_links = devm_kcalloc(dev, par->num_genpds,
+ par->genpd_links = devm_kcalloc(dev, num_genpds,
sizeof(*par->genpd_links),
GFP_KERNEL);
if (!par->genpd_links)
return -ENOMEM;
+ /*
+ * Set par->num_genpds only after genpds and genpd_links are allocated
+ * to exit early from simplefb_detach_genpds() without full
+ * initialisation.
+ */
+ par->num_genpds = num_genpds;
+
for (i = 0; i < par->num_genpds; i++) {
par->genpds[i] = dev_pm_domain_attach_by_id(dev, i);
if (IS_ERR(par->genpds[i])) {
@@ -506,9 +518,10 @@ static int simplefb_attach_genpds(struct simplefb_par *par,
dev_warn(dev, "failed to link power-domain %u\n", i);
}
- return devm_add_action_or_reset(dev, simplefb_detach_genpds, par);
+ return 0;
}
#else
+static void simplefb_detach_genpds(void *res) { }
static int simplefb_attach_genpds(struct simplefb_par *par,
struct platform_device *pdev)
{
@@ -622,18 +635,20 @@ static int simplefb_probe(struct platform_device *pdev)
ret = devm_aperture_acquire_for_platform_device(pdev, par->base, par->size);
if (ret) {
dev_err(&pdev->dev, "Unable to acquire aperture: %d\n", ret);
- goto error_regulators;
+ goto error_genpds;
}
ret = register_framebuffer(info);
if (ret < 0) {
dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret);
- goto error_regulators;
+ goto error_genpds;
}
dev_info(&pdev->dev, "fb%d: simplefb registered!\n", info->node);
return 0;
+error_genpds:
+ simplefb_detach_genpds(par);
error_regulators:
simplefb_regulators_destroy(par);
error_clocks: