summary refs log tree commit diff
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/kernel/traps.c15
-rw-r--r--arch/powerpc/platforms/powermac/backlight.c270
-rw-r--r--arch/powerpc/xmon/xmon.c3
3 files changed, 121 insertions, 167 deletions
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 91a6e04d9741..52f5659534f4 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -32,6 +32,7 @@
 #include <linux/delay.h>
 #include <linux/kprobes.h>
 #include <linux/kexec.h>
+#include <linux/backlight.h>
 
 #include <asm/kdebug.h>
 #include <asm/pgtable.h>
@@ -105,10 +106,18 @@ int die(const char *str, struct pt_regs *regs, long err)
 	spin_lock_irq(&die_lock);
 	bust_spinlocks(1);
 #ifdef CONFIG_PMAC_BACKLIGHT
-	if (machine_is(powermac)) {
-		set_backlight_enable(1);
-		set_backlight_level(BACKLIGHT_MAX);
+	mutex_lock(&pmac_backlight_mutex);
+	if (machine_is(powermac) && pmac_backlight) {
+		struct backlight_properties *props;
+
+		down(&pmac_backlight->sem);
+		props = pmac_backlight->props;
+		props->brightness = props->max_brightness;
+		props->power = FB_BLANK_UNBLANK;
+		props->update_status(pmac_backlight);
+		up(&pmac_backlight->sem);
 	}
+	mutex_unlock(&pmac_backlight_mutex);
 #endif
 	printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
 #ifdef CONFIG_PREEMPT
diff --git a/arch/powerpc/platforms/powermac/backlight.c b/arch/powerpc/platforms/powermac/backlight.c
index 8be2f7d071f0..498b042e1837 100644
--- a/arch/powerpc/platforms/powermac/backlight.c
+++ b/arch/powerpc/platforms/powermac/backlight.c
@@ -3,200 +3,148 @@
  * Contains support for the backlight.
  *
  *   Copyright (C) 2000 Benjamin Herrenschmidt
+ *   Copyright (C) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
  *
  */
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/stddef.h>
-#include <linux/reboot.h>
-#include <linux/nvram.h>
-#include <linux/console.h>
-#include <asm/sections.h>
-#include <asm/ptrace.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
 #include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/nvram.h>
 #include <asm/backlight.h>
 
-#include <linux/adb.h>
-#include <linux/pmu.h>
+#define OLD_BACKLIGHT_MAX 15
 
-static struct backlight_controller *backlighter;
-static void* backlighter_data;
-static int backlight_autosave;
-static int backlight_level = BACKLIGHT_MAX;
-static int backlight_enabled = 1;
-static int backlight_req_level = -1;
-static int backlight_req_enable = -1;
+/* Protect the pmac_backlight variable */
+DEFINE_MUTEX(pmac_backlight_mutex);
 
-static void backlight_callback(void *);
-static DECLARE_WORK(backlight_work, backlight_callback, NULL);
+/* Main backlight storage
+ *
+ * Backlight drivers in this variable are required to have the "props"
+ * attribute set and to have an update_status function.
+ *
+ * We can only store one backlight here, but since Apple laptops have only one
+ * internal display, it doesn't matter. Other backlight drivers can be used
+ * independently.
+ *
+ * Lock ordering:
+ * pmac_backlight_mutex (global, main backlight)
+ *   pmac_backlight->sem (backlight class)
+ */
+struct backlight_device *pmac_backlight;
 
-void register_backlight_controller(struct backlight_controller *ctrler,
-					  void *data, char *type)
+int pmac_has_backlight_type(const char *type)
 {
-	struct device_node* bk_node;
-	char *prop;
-	int valid = 0;
-
-	/* There's already a matching controller, bail out */
-	if (backlighter != NULL)
-		return;
-
-	bk_node = find_devices("backlight");
-
-#ifdef CONFIG_ADB_PMU
-	/* Special case for the old PowerBook since I can't test on it */
-	backlight_autosave = machine_is_compatible("AAPL,3400/2400")
-		|| machine_is_compatible("AAPL,3500");
-	if ((backlight_autosave
-	     || machine_is_compatible("AAPL,PowerBook1998")
-	     || machine_is_compatible("PowerBook1,1"))
-	    && !strcmp(type, "pmu"))
-		valid = 1;
-#endif
+	struct device_node* bk_node = find_devices("backlight");
+
 	if (bk_node) {
-		prop = get_property(bk_node, "backlight-control", NULL);
-		if (prop && !strncmp(prop, type, strlen(type)))
-			valid = 1;
-	}
-	if (!valid)
-		return;
-	backlighter = ctrler;
-	backlighter_data = data;
-
-	if (bk_node && !backlight_autosave)
-		prop = get_property(bk_node, "bklt", NULL);
-	else
-		prop = NULL;
-	if (prop) {
-		backlight_level = ((*prop)+1) >> 1;
-		if (backlight_level > BACKLIGHT_MAX)
-			backlight_level = BACKLIGHT_MAX;
+		char *prop = get_property(bk_node, "backlight-control", NULL);
+		if (prop && strncmp(prop, type, strlen(type)) == 0)
+			return 1;
 	}
 
-#ifdef CONFIG_ADB_PMU
-	if (backlight_autosave) {
-		struct adb_request req;
-		pmu_request(&req, NULL, 2, 0xd9, 0);
-		while (!req.complete)
-			pmu_poll();
-		backlight_level = req.reply[0] >> 4;
-	}
-#endif
-	acquire_console_sem();
-	if (!backlighter->set_enable(1, backlight_level, data))
-		backlight_enabled = 1;
-	release_console_sem();
-
-	printk(KERN_INFO "Registered \"%s\" backlight controller,"
-	       "level: %d/15\n", type, backlight_level);
+	return 0;
 }
-EXPORT_SYMBOL(register_backlight_controller);
 
-void unregister_backlight_controller(struct backlight_controller
-					    *ctrler, void *data)
+int pmac_backlight_curve_lookup(struct fb_info *info, int value)
 {
-	/* We keep the current backlight level (for now) */
-	if (ctrler == backlighter && data == backlighter_data)
-		backlighter = NULL;
+	int level = (FB_BACKLIGHT_LEVELS - 1);
+
+	if (info && info->bl_dev) {
+		int i, max = 0;
+
+		/* Look for biggest value */
+		for (i = 0; i < FB_BACKLIGHT_LEVELS; i++)
+			max = max((int)info->bl_curve[i], max);
+
+		/* Look for nearest value */
+		for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) {
+			int diff = abs(info->bl_curve[i] - value);
+			if (diff < max) {
+				max = diff;
+				level = i;
+			}
+		}
+
+	}
+
+	return level;
 }
-EXPORT_SYMBOL(unregister_backlight_controller);
 
-static int __set_backlight_enable(int enable)
+static void pmac_backlight_key(int direction)
 {
-	int rc;
-
-	if (!backlighter)
-		return -ENODEV;
-	acquire_console_sem();
-	rc = backlighter->set_enable(enable, backlight_level,
-				     backlighter_data);
-	if (!rc)
-		backlight_enabled = enable;
-	release_console_sem();
-	return rc;
+	mutex_lock(&pmac_backlight_mutex);
+	if (pmac_backlight) {
+		struct backlight_properties *props;
+		int brightness;
+
+		down(&pmac_backlight->sem);
+		props = pmac_backlight->props;
+
+		brightness = props->brightness +
+			((direction?-1:1) * (props->max_brightness / 15));
+
+		if (brightness < 0)
+			brightness = 0;
+		else if (brightness > props->max_brightness)
+			brightness = props->max_brightness;
+
+		props->brightness = brightness;
+		props->update_status(pmac_backlight);
+
+		up(&pmac_backlight->sem);
+	}
+	mutex_unlock(&pmac_backlight_mutex);
 }
-int set_backlight_enable(int enable)
+
+void pmac_backlight_key_up()
 {
-	if (!backlighter)
-		return -ENODEV;
-	backlight_req_enable = enable;
-	schedule_work(&backlight_work);
-	return 0;
+	pmac_backlight_key(0);
 }
 
-EXPORT_SYMBOL(set_backlight_enable);
-
-int get_backlight_enable(void)
+void pmac_backlight_key_down()
 {
-	if (!backlighter)
-		return -ENODEV;
-	return backlight_enabled;
+	pmac_backlight_key(1);
 }
-EXPORT_SYMBOL(get_backlight_enable);
 
-static int __set_backlight_level(int level)
+int pmac_backlight_set_legacy_brightness(int brightness)
 {
-	int rc = 0;
-
-	if (!backlighter)
-		return -ENODEV;
-	if (level < BACKLIGHT_MIN)
-		level = BACKLIGHT_OFF;
-	if (level > BACKLIGHT_MAX)
-		level = BACKLIGHT_MAX;
-	acquire_console_sem();
-	if (backlight_enabled)
-		rc = backlighter->set_level(level, backlighter_data);
-	if (!rc)
-		backlight_level = level;
-	release_console_sem();
-	if (!rc && !backlight_autosave) {
-		level <<=1;
-		if (level & 0x10)
-			level |= 0x01;
-		// -- todo: save to property "bklt"
+	int error = -ENXIO;
+
+	mutex_lock(&pmac_backlight_mutex);
+	if (pmac_backlight) {
+		struct backlight_properties *props;
+
+		down(&pmac_backlight->sem);
+		props = pmac_backlight->props;
+		props->brightness = brightness *
+			props->max_brightness / OLD_BACKLIGHT_MAX;
+		props->update_status(pmac_backlight);
+		up(&pmac_backlight->sem);
+
+		error = 0;
 	}
-	return rc;
+	mutex_unlock(&pmac_backlight_mutex);
+
+	return error;
 }
-int set_backlight_level(int level)
+
+int pmac_backlight_get_legacy_brightness()
 {
-	if (!backlighter)
-		return -ENODEV;
-	backlight_req_level = level;
-	schedule_work(&backlight_work);
-	return 0;
-}
+	int result = -ENXIO;
 
-EXPORT_SYMBOL(set_backlight_level);
+	mutex_lock(&pmac_backlight_mutex);
+	if (pmac_backlight) {
+		struct backlight_properties *props;
 
-int get_backlight_level(void)
-{
-	if (!backlighter)
-		return -ENODEV;
-	return backlight_level;
-}
-EXPORT_SYMBOL(get_backlight_level);
+		down(&pmac_backlight->sem);
+		props = pmac_backlight->props;
+		result = props->brightness *
+			OLD_BACKLIGHT_MAX / props->max_brightness;
+		up(&pmac_backlight->sem);
+	}
+	mutex_unlock(&pmac_backlight_mutex);
 
-static void backlight_callback(void *dummy)
-{
-	int level, enable;
-
-	do {
-		level = backlight_req_level;
-		enable = backlight_req_enable;
-		mb();
-
-		if (level >= 0)
-			__set_backlight_level(level);
-		if (enable >= 0)
-			__set_backlight_enable(enable);
-	} while(cmpxchg(&backlight_req_level, level, -1) != level ||
-		cmpxchg(&backlight_req_enable, enable, -1) != enable);
+	return result;
 }
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 4735b41c113c..0741df8c41b7 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -26,9 +26,6 @@
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/xmon.h>
-#ifdef CONFIG_PMAC_BACKLIGHT
-#include <asm/backlight.h>
-#endif
 #include <asm/processor.h>
 #include <asm/pgtable.h>
 #include <asm/mmu.h>