aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/powermac/backlight.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/powermac/backlight.c')
-rw-r--r--arch/powerpc/platforms/powermac/backlight.c85
1 files changed, 75 insertions, 10 deletions
diff --git a/arch/powerpc/platforms/powermac/backlight.c b/arch/powerpc/platforms/powermac/backlight.c
index 69f65e215a5c8..d664154910552 100644
--- a/arch/powerpc/platforms/powermac/backlight.c
+++ b/arch/powerpc/platforms/powermac/backlight.c
@@ -10,11 +10,33 @@
#include <linux/kernel.h>
#include <linux/fb.h>
#include <linux/backlight.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <asm/atomic.h>
#include <asm/prom.h>
#include <asm/backlight.h>
#define OLD_BACKLIGHT_MAX 15
+static void pmac_backlight_key_worker(void *data);
+static void pmac_backlight_set_legacy_worker(void *data);
+
+static DECLARE_WORK(pmac_backlight_key_work, pmac_backlight_key_worker, NULL);
+static DECLARE_WORK(pmac_backlight_set_legacy_work, pmac_backlight_set_legacy_worker, NULL);
+
+/* Although these variables are used in interrupt context, it makes no sense to
+ * protect them. No user is able to produce enough key events per second and
+ * notice the errors that might happen.
+ */
+static int pmac_backlight_key_queued;
+static int pmac_backlight_set_legacy_queued;
+
+/* The via-pmu code allows the backlight to be grabbed, in which case the
+ * in-kernel control of the brightness needs to be disabled. This should
+ * only be used by really old PowerBooks.
+ */
+static atomic_t kernel_backlight_disabled = ATOMIC_INIT(0);
+
/* Protect the pmac_backlight variable */
DEFINE_MUTEX(pmac_backlight_mutex);
@@ -71,8 +93,11 @@ int pmac_backlight_curve_lookup(struct fb_info *info, int value)
return level;
}
-static void pmac_backlight_key(int direction)
+static void pmac_backlight_key_worker(void *data)
{
+ if (atomic_read(&kernel_backlight_disabled))
+ return;
+
mutex_lock(&pmac_backlight_mutex);
if (pmac_backlight) {
struct backlight_properties *props;
@@ -82,7 +107,8 @@ static void pmac_backlight_key(int direction)
props = pmac_backlight->props;
brightness = props->brightness +
- ((direction?-1:1) * (props->max_brightness / 15));
+ ((pmac_backlight_key_queued?-1:1) *
+ (props->max_brightness / 15));
if (brightness < 0)
brightness = 0;
@@ -97,17 +123,20 @@ static void pmac_backlight_key(int direction)
mutex_unlock(&pmac_backlight_mutex);
}
-void pmac_backlight_key_up()
+/* This function is called in interrupt context */
+void pmac_backlight_key(int direction)
{
- pmac_backlight_key(0);
+ if (atomic_read(&kernel_backlight_disabled))
+ return;
+
+ /* we can receive multiple interrupts here, but the scheduled work
+ * will run only once, with the last value
+ */
+ pmac_backlight_key_queued = direction;
+ schedule_work(&pmac_backlight_key_work);
}
-void pmac_backlight_key_down()
-{
- pmac_backlight_key(1);
-}
-
-int pmac_backlight_set_legacy_brightness(int brightness)
+static int __pmac_backlight_set_legacy_brightness(int brightness)
{
int error = -ENXIO;
@@ -136,6 +165,28 @@ int pmac_backlight_set_legacy_brightness(int brightness)
return error;
}
+static void pmac_backlight_set_legacy_worker(void *data)
+{
+ if (atomic_read(&kernel_backlight_disabled))
+ return;
+
+ __pmac_backlight_set_legacy_brightness(pmac_backlight_set_legacy_queued);
+}
+
+/* This function is called in interrupt context */
+void pmac_backlight_set_legacy_brightness_pmu(int brightness) {
+ if (atomic_read(&kernel_backlight_disabled))
+ return;
+
+ pmac_backlight_set_legacy_queued = brightness;
+ schedule_work(&pmac_backlight_set_legacy_work);
+}
+
+int pmac_backlight_set_legacy_brightness(int brightness)
+{
+ return __pmac_backlight_set_legacy_brightness(brightness);
+}
+
int pmac_backlight_get_legacy_brightness()
{
int result = -ENXIO;
@@ -157,3 +208,17 @@ int pmac_backlight_get_legacy_brightness()
return result;
}
+
+void pmac_backlight_disable()
+{
+ atomic_inc(&kernel_backlight_disabled);
+}
+
+void pmac_backlight_enable()
+{
+ atomic_dec(&kernel_backlight_disabled);
+}
+
+EXPORT_SYMBOL_GPL(pmac_backlight);
+EXPORT_SYMBOL_GPL(pmac_backlight_mutex);
+EXPORT_SYMBOL_GPL(pmac_has_backlight_type);