backlight: Rework backlight/fb interaction simplifying, lots

fb_info->bl_mutex is badly thought out and the backlight class doesn't
need it if the framebuffer/backlight register/unregister order is
consistent, particularly after the backlight locking fixes.

Fix the drivers to use the order:

backlight_device_register()
register_framebuffer()
unregister_framebuffer()
backlight_device_unregister()

and turn bl_mutex into a lock for the bl_curve data only.

Signed-off-by: Richard Purdie <rpurdie@rpsys.net>
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index 1c77cfb..ef3e786 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -1697,7 +1697,6 @@
 
 static struct backlight_properties aty128_bl_data;
 
-/* Call with fb_info->bl_mutex held */
 static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
 		int level)
 {
@@ -1705,6 +1704,7 @@
 	int atylevel;
 
 	/* Get and convert the value */
+	/* No locking of bl_curve since we read a single value */
 	atylevel = MAX_LEVEL -
 		(info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL);
 
@@ -1724,8 +1724,7 @@
 /* That one prevents proper CRT output with LCD off */
 #undef BACKLIGHT_DAC_OFF
 
-/* Call with fb_info->bl_mutex held */
-static int __aty128_bl_update_status(struct backlight_device *bd)
+static int aty128_bl_update_status(struct backlight_device *bd)
 {
 	struct aty128fb_par *par = class_get_devdata(&bd->class_dev);
 	unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
@@ -1778,19 +1777,6 @@
 	return 0;
 }
 
-static int aty128_bl_update_status(struct backlight_device *bd)
-{
-	struct aty128fb_par *par = class_get_devdata(&bd->class_dev);
-	struct fb_info *info = pci_get_drvdata(par->pdev);
-	int ret;
-
-	mutex_lock(&info->bl_mutex);
-	ret = __aty128_bl_update_status(bd);
-	mutex_unlock(&info->bl_mutex);
-
-	return ret;
-}
-
 static int aty128_bl_get_brightness(struct backlight_device *bd)
 {
 	return bd->props->brightness;
@@ -1804,14 +1790,10 @@
 
 static void aty128_bl_set_power(struct fb_info *info, int power)
 {
-	mutex_lock(&info->bl_mutex);
-
 	if (info->bl_dev) {
 		info->bl_dev->props->power = power;
-		__aty128_bl_update_status(info->bl_dev);
+		backlight_update_status(info->bl_dev);
 	}
-
-	mutex_unlock(&info->bl_mutex);
 }
 
 static void aty128_bl_init(struct aty128fb_par *par)
@@ -1838,12 +1820,10 @@
 		goto error;
 	}
 
-	mutex_lock(&info->bl_mutex);
 	info->bl_dev = bd;
 	fb_bl_default_curve(info, 0,
 		 63 * FB_BACKLIGHT_MAX / MAX_LEVEL,
 		219 * FB_BACKLIGHT_MAX / MAX_LEVEL);
-	mutex_unlock(&info->bl_mutex);
 
 	bd->props->brightness = aty128_bl_data.max_brightness;
 	bd->props->power = FB_BLANK_UNBLANK;
@@ -1864,31 +1844,19 @@
 	return;
 }
 
-static void aty128_bl_exit(struct aty128fb_par *par)
+static void aty128_bl_exit(struct backlight_device *bd)
 {
-	struct fb_info *info = pci_get_drvdata(par->pdev);
-
+	if (bd) {
 #ifdef CONFIG_PMAC_BACKLIGHT
-	mutex_lock(&pmac_backlight_mutex);
-#endif
-
-	mutex_lock(&info->bl_mutex);
-	if (info->bl_dev) {
-#ifdef CONFIG_PMAC_BACKLIGHT
-		if (pmac_backlight == info->bl_dev)
+		mutex_lock(&pmac_backlight_mutex);
+		if (pmac_backlight == bd)
 			pmac_backlight = NULL;
+		mutex_unlock(&pmac_backlight_mutex);
 #endif
-
-		backlight_device_unregister(info->bl_dev);
-		info->bl_dev = NULL;
+		backlight_device_unregister(bd);
 
 		printk("aty128: Backlight unloaded\n");
 	}
-	mutex_unlock(&info->bl_mutex);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-	mutex_unlock(&pmac_backlight_mutex);
-#endif
 }
 #endif /* CONFIG_FB_ATY128_BACKLIGHT */
 
@@ -2175,11 +2143,12 @@
 
 	par = info->par;
 
+	unregister_framebuffer(info);
+
 #ifdef CONFIG_FB_ATY128_BACKLIGHT
-	aty128_bl_exit(par);
+	aty128_bl_exit(info->bl_dev);
 #endif
 
-	unregister_framebuffer(info);
 #ifdef CONFIG_MTRR
 	if (par->mtrr.vram_valid)
 		mtrr_del(par->mtrr.vram, info->fix.smem_start,
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index 3b65293..6646228 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -2116,13 +2116,13 @@
 
 static struct backlight_properties aty_bl_data;
 
-/* Call with fb_info->bl_mutex held */
 static int aty_bl_get_level_brightness(struct atyfb_par *par, int level)
 {
 	struct fb_info *info = pci_get_drvdata(par->pdev);
 	int atylevel;
 
 	/* Get and convert the value */
+	/* No locking of bl_curve since we read a single value */
 	atylevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
 
 	if (atylevel < 0)
@@ -2133,8 +2133,7 @@
 	return atylevel;
 }
 
-/* Call with fb_info->bl_mutex held */
-static int __aty_bl_update_status(struct backlight_device *bd)
+static int aty_bl_update_status(struct backlight_device *bd)
 {
 	struct atyfb_par *par = class_get_devdata(&bd->class_dev);
 	unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par);
@@ -2159,19 +2158,6 @@
 	return 0;
 }
 
-static int aty_bl_update_status(struct backlight_device *bd)
-{
-	struct atyfb_par *par = class_get_devdata(&bd->class_dev);
-	struct fb_info *info = pci_get_drvdata(par->pdev);
-	int ret;
-
-	mutex_lock(&info->bl_mutex);
-	ret = __aty_bl_update_status(bd);
-	mutex_unlock(&info->bl_mutex);
-
-	return ret;
-}
-
 static int aty_bl_get_brightness(struct backlight_device *bd)
 {
 	return bd->props->brightness;
@@ -2203,12 +2189,10 @@
 		goto error;
 	}
 
-	mutex_lock(&info->bl_mutex);
 	info->bl_dev = bd;
 	fb_bl_default_curve(info, 0,
 		0x3F * FB_BACKLIGHT_MAX / MAX_LEVEL,
 		0xFF * FB_BACKLIGHT_MAX / MAX_LEVEL);
-	mutex_unlock(&info->bl_mutex);
 
 	bd->props->brightness = aty_bl_data.max_brightness;
 	bd->props->power = FB_BLANK_UNBLANK;
@@ -2229,30 +2213,19 @@
 	return;
 }
 
-static void aty_bl_exit(struct atyfb_par *par)
+static void aty_bl_exit(struct backlight_device *bd)
 {
-	struct fb_info *info = pci_get_drvdata(par->pdev);
-
+	if (bd) {
 #ifdef CONFIG_PMAC_BACKLIGHT
-	mutex_lock(&pmac_backlight_mutex);
-#endif
-
-	mutex_lock(&info->bl_mutex);
-	if (info->bl_dev) {
-#ifdef CONFIG_PMAC_BACKLIGHT
-		if (pmac_backlight == info->bl_dev)
+		mutex_lock(&pmac_backlight_mutex);
+		if (pmac_backlight == bd)
 			pmac_backlight = NULL;
+		mutex_unlock(&pmac_backlight_mutex);
 #endif
-
-		backlight_device_unregister(info->bl_dev);
+		backlight_device_unregister(bd);
 
 		printk("aty: Backlight unloaded\n");
 	}
-	mutex_unlock(&info->bl_mutex);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-	mutex_unlock(&pmac_backlight_mutex);
-#endif
 }
 
 #endif /* CONFIG_FB_ATY_BACKLIGHT */
@@ -3705,13 +3678,13 @@
 	aty_set_crtc(par, &saved_crtc);
 	par->pll_ops->set_pll(info, &saved_pll);
 
+	unregister_framebuffer(info);
+
 #ifdef CONFIG_FB_ATY_BACKLIGHT
 	if (M64_HAS(MOBIL_BUS))
-		aty_bl_exit(par);
+		aty_bl_exit(info->bl_dev);
 #endif
 
-	unregister_framebuffer(info);
-
 #ifdef CONFIG_MTRR
 	if (par->mtrr_reg >= 0) {
 	    mtrr_del(par->mtrr_reg, 0, 0);
diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c
index 9cfceca..f94e461 100644
--- a/drivers/video/aty/radeon_backlight.c
+++ b/drivers/video/aty/radeon_backlight.c
@@ -29,17 +29,13 @@
 static int radeon_bl_get_level_brightness(struct radeon_bl_privdata *pdata,
 		int level)
 {
-	struct fb_info *info = pdata->rinfo->info;
 	int rlevel;
 
-	mutex_lock(&info->bl_mutex);
-
 	/* Get and convert the value */
+	/* No locking of bl_curve since we read a single value */
 	rlevel = pdata->rinfo->info->bl_curve[level] *
 		 FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL;
 
-	mutex_unlock(&info->bl_mutex);
-
 	if (rlevel < 0)
 		rlevel = 0;
 	else if (rlevel > MAX_RADEON_LEVEL)
@@ -187,12 +183,10 @@
 		machine_is_compatible("PowerBook6,5");
 #endif
 
-	mutex_lock(&rinfo->info->bl_mutex);
 	rinfo->info->bl_dev = bd;
 	fb_bl_default_curve(rinfo->info, 0,
 		 63 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL,
 		217 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL);
-	mutex_unlock(&rinfo->info->bl_mutex);
 
 	bd->props->brightness = radeon_bl_data.max_brightness;
 	bd->props->power = FB_BLANK_UNBLANK;
@@ -216,29 +210,22 @@
 
 void radeonfb_bl_exit(struct radeonfb_info *rinfo)
 {
-#ifdef CONFIG_PMAC_BACKLIGHT
-	mutex_lock(&pmac_backlight_mutex);
-#endif
+	struct backlight_device *bd = rinfo->info->bl_dev;
 
-	mutex_lock(&rinfo->info->bl_mutex);
-	if (rinfo->info->bl_dev) {
+	if (bd) {
 		struct radeon_bl_privdata *pdata;
 
 #ifdef CONFIG_PMAC_BACKLIGHT
-		if (pmac_backlight == rinfo->info->bl_dev)
+		mutex_lock(&pmac_backlight_mutex);
+		if (pmac_backlight == bd)
 			pmac_backlight = NULL;
+		mutex_unlock(&pmac_backlight_mutex);
 #endif
-
-		pdata = class_get_devdata(&rinfo->info->bl_dev->class_dev);
-		backlight_device_unregister(rinfo->info->bl_dev);
+		pdata = class_get_devdata(&bd->class_dev);
+		backlight_device_unregister(bd);
 		kfree(pdata);
 		rinfo->info->bl_dev = NULL;
 
 		printk("radeonfb: Backlight unloaded\n");
 	}
-	mutex_unlock(&rinfo->info->bl_mutex);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-	mutex_unlock(&pmac_backlight_mutex);
-#endif
 }
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 0ed577e..7e228ad 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -2393,7 +2393,6 @@
         if (!rinfo)
                 return;
 
-	radeonfb_bl_exit(rinfo);
 	radeonfb_pm_exit(rinfo);
 
 	if (rinfo->mon1_EDID)
@@ -2420,6 +2419,8 @@
 
         unregister_framebuffer(info);
 
+        radeonfb_bl_exit(rinfo);
+
         iounmap(rinfo->mmio_base);
         iounmap(rinfo->fb_base);