Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4b755999 authored by Michael Hanselmann's avatar Michael Hanselmann Committed by Linus Torvalds
Browse files

[PATCH] powermac: More powermac backlight fixes



This patch fixes several problems:
- The legacy backlight value might be set at interrupt time. Introduced
  a worker to prevent it from directly calling the backlight code.
- via-pmu allows the backlight to be grabbed, in which case we need to
  prevent other kernel code from changing the brightness.
- Don't send PMU requests in via-pmu-backlight when the machine is about
  to sleep or waking up.
- More Kconfig fixes.

Signed-off-by: default avatarMichael Hanselmann <linux-kernel@hansmi.ch>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 994aad25
Loading
Loading
Loading
Loading
+55 −3
Original line number Original line Diff line number Diff line
@@ -10,19 +10,32 @@
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/fb.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/backlight.h>
#include <linux/adb.h>
#include <linux/pmu.h>
#include <asm/atomic.h>
#include <asm/prom.h>
#include <asm/prom.h>
#include <asm/backlight.h>
#include <asm/backlight.h>


#define OLD_BACKLIGHT_MAX 15
#define OLD_BACKLIGHT_MAX 15


static void pmac_backlight_key_worker(void *data);
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_key_work, pmac_backlight_key_worker, NULL);
static DECLARE_WORK(pmac_backlight_set_legacy_work, pmac_backlight_set_legacy_worker, NULL);


/* Although this variable is used in interrupt context, it makes no sense to
/* Although these variables are used in interrupt context, it makes no sense to
 * protect it. No user is able to produce enough key events per second and
 * protect them. No user is able to produce enough key events per second and
 * notice the errors that might happen.
 * notice the errors that might happen.
 */
 */
static int pmac_backlight_key_queued;
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 */
/* Protect the pmac_backlight variable */
DEFINE_MUTEX(pmac_backlight_mutex);
DEFINE_MUTEX(pmac_backlight_mutex);
@@ -82,6 +95,9 @@ int pmac_backlight_curve_lookup(struct fb_info *info, int value)


static void pmac_backlight_key_worker(void *data)
static void pmac_backlight_key_worker(void *data)
{
{
	if (atomic_read(&kernel_backlight_disabled))
		return;

	mutex_lock(&pmac_backlight_mutex);
	mutex_lock(&pmac_backlight_mutex);
	if (pmac_backlight) {
	if (pmac_backlight) {
		struct backlight_properties *props;
		struct backlight_properties *props;
@@ -107,8 +123,12 @@ static void pmac_backlight_key_worker(void *data)
	mutex_unlock(&pmac_backlight_mutex);
	mutex_unlock(&pmac_backlight_mutex);
}
}


/* This function is called in interrupt context */
void pmac_backlight_key(int direction)
void pmac_backlight_key(int direction)
{
{
	if (atomic_read(&kernel_backlight_disabled))
		return;

	/* we can receive multiple interrupts here, but the scheduled work
	/* we can receive multiple interrupts here, but the scheduled work
	 * will run only once, with the last value
	 * will run only once, with the last value
	 */
	 */
@@ -116,7 +136,7 @@ void pmac_backlight_key(int direction)
	schedule_work(&pmac_backlight_key_work);
	schedule_work(&pmac_backlight_key_work);
}
}


int pmac_backlight_set_legacy_brightness(int brightness)
static int __pmac_backlight_set_legacy_brightness(int brightness)
{
{
	int error = -ENXIO;
	int error = -ENXIO;


@@ -145,6 +165,28 @@ int pmac_backlight_set_legacy_brightness(int brightness)
	return error;
	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 pmac_backlight_get_legacy_brightness()
{
{
	int result = -ENXIO;
	int result = -ENXIO;
@@ -167,6 +209,16 @@ int pmac_backlight_get_legacy_brightness()
	return result;
	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);
EXPORT_SYMBOL_GPL(pmac_backlight_mutex);
EXPORT_SYMBOL_GPL(pmac_backlight_mutex);
EXPORT_SYMBOL_GPL(pmac_has_backlight_type);
EXPORT_SYMBOL_GPL(pmac_has_backlight_type);
+0 −2
Original line number Original line Diff line number Diff line
@@ -115,8 +115,6 @@ config PMAC_BACKLIGHT
	bool "Backlight control for LCD screens"
	bool "Backlight control for LCD screens"
	depends on ADB_PMU && FB = y && (BROKEN || !PPC64)
	depends on ADB_PMU && FB = y && (BROKEN || !PPC64)
	select FB_BACKLIGHT
	select FB_BACKLIGHT
	select BACKLIGHT_CLASS_DEVICE
	select BACKLIGHT_LCD_SUPPORT
	help
	help
	  Say Y here to enable Macintosh specific extensions of the generic
	  Say Y here to enable Macintosh specific extensions of the generic
	  backlight code. With this enabled, the brightness keys on older
	  backlight code. With this enabled, the brightness keys on older
+3 −11
Original line number Original line Diff line number Diff line
@@ -45,14 +45,11 @@
#include <linux/pmu.h>
#include <linux/pmu.h>


#include <asm/machdep.h>
#include <asm/machdep.h>
#include <asm/backlight.h>
#ifdef CONFIG_PPC_PMAC
#ifdef CONFIG_PPC_PMAC
#include <asm/pmac_feature.h>
#include <asm/pmac_feature.h>
#endif
#endif


#ifdef CONFIG_PMAC_BACKLIGHT
#include <asm/backlight.h>
#endif

MODULE_AUTHOR("Franz Sirl <Franz.Sirl-kernel@lauterbach.com>");
MODULE_AUTHOR("Franz Sirl <Franz.Sirl-kernel@lauterbach.com>");


#define KEYB_KEYREG	0	/* register # for key up/down data */
#define KEYB_KEYREG	0	/* register # for key up/down data */
@@ -237,11 +234,6 @@ static struct adb_ids keyboard_ids;
static struct adb_ids mouse_ids;
static struct adb_ids mouse_ids;
static struct adb_ids buttons_ids;
static struct adb_ids buttons_ids;


#ifdef CONFIG_PMAC_BACKLIGHT
/* Exported to via-pmu.c */
int disable_kernel_backlight = 0;
#endif /* CONFIG_PMAC_BACKLIGHT */

/* Kind of keyboard, see Apple technote 1152  */
/* Kind of keyboard, see Apple technote 1152  */
#define ADB_KEYBOARD_UNKNOWN	0
#define ADB_KEYBOARD_UNKNOWN	0
#define ADB_KEYBOARD_ANSI	0x0100
#define ADB_KEYBOARD_ANSI	0x0100
@@ -527,7 +519,7 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto


		case 0xa:	/* brightness decrease */
		case 0xa:	/* brightness decrease */
#ifdef CONFIG_PMAC_BACKLIGHT
#ifdef CONFIG_PMAC_BACKLIGHT
			if (!disable_kernel_backlight && down)
			if (down)
				pmac_backlight_key_down();
				pmac_backlight_key_down();
#endif
#endif
			input_report_key(adbhid[id]->input, KEY_BRIGHTNESSDOWN, down);
			input_report_key(adbhid[id]->input, KEY_BRIGHTNESSDOWN, down);
@@ -535,7 +527,7 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto


		case 0x9:	/* brightness increase */
		case 0x9:	/* brightness increase */
#ifdef CONFIG_PMAC_BACKLIGHT
#ifdef CONFIG_PMAC_BACKLIGHT
			if (!disable_kernel_backlight && down)
			if (down)
				pmac_backlight_key_up();
				pmac_backlight_key_up();
#endif
#endif
			input_report_key(adbhid[id]->input, KEY_BRIGHTNESSUP, down);
			input_report_key(adbhid[id]->input, KEY_BRIGHTNESSUP, down);
+55 −13
Original line number Original line Diff line number Diff line
@@ -15,8 +15,9 @@


#define MAX_PMU_LEVEL 0xFF
#define MAX_PMU_LEVEL 0xFF


static struct device_node *vias;
static struct backlight_properties pmu_backlight_data;
static struct backlight_properties pmu_backlight_data;
static spinlock_t pmu_backlight_lock;
static int sleeping;


static int pmu_backlight_get_level_brightness(struct fb_info *info,
static int pmu_backlight_get_level_brightness(struct fb_info *info,
		int level)
		int level)
@@ -40,23 +41,36 @@ static int pmu_backlight_update_status(struct backlight_device *bd)
{
{
	struct fb_info *info = class_get_devdata(&bd->class_dev);
	struct fb_info *info = class_get_devdata(&bd->class_dev);
	struct adb_request req;
	struct adb_request req;
	int pmulevel, level = bd->props->brightness;
	unsigned long flags;
	int level = bd->props->brightness;


	if (vias == NULL)
	spin_lock_irqsave(&pmu_backlight_lock, flags);
		return -ENODEV;

	/* Don't update brightness when sleeping */
	if (sleeping)
		goto out;


	if (bd->props->power != FB_BLANK_UNBLANK ||
	if (bd->props->power != FB_BLANK_UNBLANK ||
	    bd->props->fb_blank != FB_BLANK_UNBLANK)
	    bd->props->fb_blank != FB_BLANK_UNBLANK)
		level = 0;
		level = 0;


	pmulevel = pmu_backlight_get_level_brightness(info, level);
	if (level > 0) {
		int pmulevel = pmu_backlight_get_level_brightness(info, level);


		pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel);
		pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel);
		pmu_wait_complete(&req);
		pmu_wait_complete(&req);


		pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
		pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
		PMU_POW_BACKLIGHT | (level > 0 ? PMU_POW_ON : PMU_POW_OFF));
			PMU_POW_BACKLIGHT | PMU_POW_ON);
		pmu_wait_complete(&req);
	} else {
		pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
			PMU_POW_BACKLIGHT | PMU_POW_OFF);
		pmu_wait_complete(&req);
		pmu_wait_complete(&req);
	}

out:
	spin_unlock_irqrestore(&pmu_backlight_lock, flags);


	return 0;
	return 0;
}
}
@@ -73,15 +87,39 @@ static struct backlight_properties pmu_backlight_data = {
	.max_brightness	= (FB_BACKLIGHT_LEVELS - 1),
	.max_brightness	= (FB_BACKLIGHT_LEVELS - 1),
};
};


void __init pmu_backlight_init(struct device_node *in_vias)
#ifdef CONFIG_PM
static int pmu_backlight_sleep_call(struct pmu_sleep_notifier *self, int when)
{
	unsigned long flags;

	spin_lock_irqsave(&pmu_backlight_lock, flags);

	switch (when) {
	case PBOOK_SLEEP_REQUEST:
		sleeping = 1;
		break;
	case PBOOK_WAKE:
		sleeping = 0;
		break;
	}

	spin_unlock_irqrestore(&pmu_backlight_lock, flags);

	return PBOOK_SLEEP_OK;
}

static struct pmu_sleep_notifier pmu_backlight_sleep_notif = {
	.notifier_call = pmu_backlight_sleep_call,
};
#endif

void __init pmu_backlight_init()
{
{
	struct backlight_device *bd;
	struct backlight_device *bd;
	struct fb_info *info;
	struct fb_info *info;
	char name[10];
	char name[10];
	int level, autosave;
	int level, autosave;


	vias = in_vias;

	/* Special case for the old PowerBook since I can't test on it */
	/* Special case for the old PowerBook since I can't test on it */
	autosave =
	autosave =
		machine_is_compatible("AAPL,3400/2400") ||
		machine_is_compatible("AAPL,3400/2400") ||
@@ -141,6 +179,10 @@ void __init pmu_backlight_init(struct device_node *in_vias)
		pmac_backlight = bd;
		pmac_backlight = bd;
	mutex_unlock(&pmac_backlight_mutex);
	mutex_unlock(&pmac_backlight_mutex);


#ifdef CONFIG_PM
	pmu_register_sleep_notifier(&pmu_backlight_sleep_notif);
#endif

	printk("pmubl: Backlight initialized (%s)\n", name);
	printk("pmubl: Backlight initialized (%s)\n", name);


	return;
	return;
+14 −25
Original line number Original line Diff line number Diff line
@@ -16,7 +16,6 @@
 *    a sleep or a freq. switch
 *    a sleep or a freq. switch
 *  - Move sleep code out of here to pmac_pm, merge into new
 *  - Move sleep code out of here to pmac_pm, merge into new
 *    common PM infrastructure
 *    common PM infrastructure
 *  - Move backlight code out as well
 *  - Save/Restore PCI space properly
 *  - Save/Restore PCI space properly
 *
 *
 */
 */
@@ -60,9 +59,7 @@
#include <asm/mmu_context.h>
#include <asm/mmu_context.h>
#include <asm/cputable.h>
#include <asm/cputable.h>
#include <asm/time.h>
#include <asm/time.h>
#ifdef CONFIG_PMAC_BACKLIGHT
#include <asm/backlight.h>
#include <asm/backlight.h>
#endif


#include "via-pmu-event.h"
#include "via-pmu-event.h"


@@ -177,10 +174,6 @@ static int query_batt_timer = BATTERY_POLLING_COUNT;
static struct adb_request batt_req;
static struct adb_request batt_req;
static struct proc_dir_entry *proc_pmu_batt[PMU_MAX_BATTERIES];
static struct proc_dir_entry *proc_pmu_batt[PMU_MAX_BATTERIES];


#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
extern int disable_kernel_backlight;
#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */

int __fake_sleep;
int __fake_sleep;
int asleep;
int asleep;
BLOCKING_NOTIFIER_HEAD(sleep_notifier_list);
BLOCKING_NOTIFIER_HEAD(sleep_notifier_list);
@@ -466,7 +459,7 @@ static int __init via_pmu_dev_init(void)


#ifdef CONFIG_PMAC_BACKLIGHT
#ifdef CONFIG_PMAC_BACKLIGHT
	/* Initialize backlight */
	/* Initialize backlight */
	pmu_backlight_init(vias);
	pmu_backlight_init();
#endif
#endif


#ifdef CONFIG_PPC32
#ifdef CONFIG_PPC32
@@ -1403,11 +1396,8 @@ pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
	else if ((1 << pirq) & PMU_INT_SNDBRT) {
	else if ((1 << pirq) & PMU_INT_SNDBRT) {
#ifdef CONFIG_PMAC_BACKLIGHT
#ifdef CONFIG_PMAC_BACKLIGHT
		if (len == 3)
		if (len == 3)
#ifdef CONFIG_INPUT_ADBHID
			pmac_backlight_set_legacy_brightness_pmu(data[1] >> 4);
			if (!disable_kernel_backlight)
#endif
#endif /* CONFIG_INPUT_ADBHID */
				pmac_backlight_set_legacy_brightness(data[1] >> 4);
#endif /* CONFIG_PMAC_BACKLIGHT */
	}
	}
	/* Tick interrupt */
	/* Tick interrupt */
	else if ((1 << pirq) & PMU_INT_TICK) {
	else if ((1 << pirq) & PMU_INT_TICK) {
@@ -2414,7 +2404,7 @@ struct pmu_private {
	spinlock_t lock;
	spinlock_t lock;
#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
	int	backlight_locker;
	int	backlight_locker;
#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */	
#endif
};
};


static LIST_HEAD(all_pmu_pvt);
static LIST_HEAD(all_pmu_pvt);
@@ -2464,7 +2454,7 @@ pmu_open(struct inode *inode, struct file *file)
	spin_lock_irqsave(&all_pvt_lock, flags);
	spin_lock_irqsave(&all_pvt_lock, flags);
#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
	pp->backlight_locker = 0;
	pp->backlight_locker = 0;
#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */	
#endif
	list_add(&pp->list, &all_pmu_pvt);
	list_add(&pp->list, &all_pmu_pvt);
	spin_unlock_irqrestore(&all_pvt_lock, flags);
	spin_unlock_irqrestore(&all_pvt_lock, flags);
	file->private_data = pp;
	file->private_data = pp;
@@ -2559,13 +2549,12 @@ pmu_release(struct inode *inode, struct file *file)
		spin_lock_irqsave(&all_pvt_lock, flags);
		spin_lock_irqsave(&all_pvt_lock, flags);
		list_del(&pp->list);
		list_del(&pp->list);
		spin_unlock_irqrestore(&all_pvt_lock, flags);
		spin_unlock_irqrestore(&all_pvt_lock, flags);

#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
		if (pp->backlight_locker) {
		if (pp->backlight_locker)
			spin_lock_irqsave(&pmu_lock, flags);
			pmac_backlight_enable();
			disable_kernel_backlight--;
#endif
			spin_unlock_irqrestore(&pmu_lock, flags);

		}
#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */
		kfree(pp);
		kfree(pp);
	}
	}
	unlock_kernel();
	unlock_kernel();
@@ -2642,18 +2631,18 @@ pmu_ioctl(struct inode * inode, struct file *filp,
#ifdef CONFIG_INPUT_ADBHID
#ifdef CONFIG_INPUT_ADBHID
	case PMU_IOC_GRAB_BACKLIGHT: {
	case PMU_IOC_GRAB_BACKLIGHT: {
		struct pmu_private *pp = filp->private_data;
		struct pmu_private *pp = filp->private_data;
		unsigned long flags;


		if (pp->backlight_locker)
		if (pp->backlight_locker)
			return 0;
			return 0;

		pp->backlight_locker = 1;
		pp->backlight_locker = 1;
		spin_lock_irqsave(&pmu_lock, flags);
		pmac_backlight_disable();
		disable_kernel_backlight++;

		spin_unlock_irqrestore(&pmu_lock, flags);
		return 0;
		return 0;
	}
	}
#endif /* CONFIG_INPUT_ADBHID */
#endif /* CONFIG_INPUT_ADBHID */
#endif /* CONFIG_PMAC_BACKLIGHT_LEGACY */
#endif /* CONFIG_PMAC_BACKLIGHT_LEGACY */

	case PMU_IOC_GET_MODEL:
	case PMU_IOC_GET_MODEL:
	    	return put_user(pmu_kind, argp);
	    	return put_user(pmu_kind, argp);
	case PMU_IOC_HAS_ADB:
	case PMU_IOC_HAS_ADB:
Loading