[PATCH] Rewritten backlight infrastructure for portable Apple computers
This patch contains a total rewrite of the backlight infrastructure for portable Apple computers. Backward compatibility is retained. A sysfs interface allows userland to control the brightness with more steps than before. Userland is allowed to upload a brightness curve for different monitors, similar to Mac OS X. [akpm@osdl.org: add needed exports] Signed-off-by: Michael Hanselmann <linux-kernel@hansmi.ch> Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Richard Purdie <rpurdie@rpsys.net> Cc: "Antonino A. Daplas" <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
Родитель
17660bdd5c
Коммит
5474c120aa
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
struct device_node* bk_node = find_devices("backlight");
|
||||
|
||||
/* 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
|
||||
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);
|
||||
}
|
||||
EXPORT_SYMBOL(register_backlight_controller);
|
||||
|
||||
void unregister_backlight_controller(struct backlight_controller
|
||||
*ctrler, void *data)
|
||||
{
|
||||
/* We keep the current backlight level (for now) */
|
||||
if (ctrler == backlighter && data == backlighter_data)
|
||||
backlighter = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(unregister_backlight_controller);
|
||||
|
||||
static int __set_backlight_enable(int enable)
|
||||
{
|
||||
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;
|
||||
}
|
||||
int set_backlight_enable(int enable)
|
||||
{
|
||||
if (!backlighter)
|
||||
return -ENODEV;
|
||||
backlight_req_enable = enable;
|
||||
schedule_work(&backlight_work);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(set_backlight_enable);
|
||||
|
||||
int get_backlight_enable(void)
|
||||
int pmac_backlight_curve_lookup(struct fb_info *info, int value)
|
||||
{
|
||||
if (!backlighter)
|
||||
return -ENODEV;
|
||||
return backlight_enabled;
|
||||
}
|
||||
EXPORT_SYMBOL(get_backlight_enable);
|
||||
int level = (FB_BACKLIGHT_LEVELS - 1);
|
||||
|
||||
static int __set_backlight_level(int level)
|
||||
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;
|
||||
}
|
||||
|
||||
static void pmac_backlight_key(int direction)
|
||||
{
|
||||
int rc = 0;
|
||||
mutex_lock(&pmac_backlight_mutex);
|
||||
if (pmac_backlight) {
|
||||
struct backlight_properties *props;
|
||||
int brightness;
|
||||
|
||||
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"
|
||||
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);
|
||||
}
|
||||
return rc;
|
||||
mutex_unlock(&pmac_backlight_mutex);
|
||||
}
|
||||
int set_backlight_level(int level)
|
||||
|
||||
void pmac_backlight_key_up()
|
||||
{
|
||||
if (!backlighter)
|
||||
return -ENODEV;
|
||||
backlight_req_level = level;
|
||||
schedule_work(&backlight_work);
|
||||
return 0;
|
||||
pmac_backlight_key(0);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(set_backlight_level);
|
||||
|
||||
int get_backlight_level(void)
|
||||
void pmac_backlight_key_down()
|
||||
{
|
||||
if (!backlighter)
|
||||
return -ENODEV;
|
||||
return backlight_level;
|
||||
pmac_backlight_key(1);
|
||||
}
|
||||
EXPORT_SYMBOL(get_backlight_level);
|
||||
|
||||
static void backlight_callback(void *dummy)
|
||||
int pmac_backlight_set_legacy_brightness(int brightness)
|
||||
{
|
||||
int level, enable;
|
||||
int error = -ENXIO;
|
||||
|
||||
do {
|
||||
level = backlight_req_level;
|
||||
enable = backlight_req_enable;
|
||||
mb();
|
||||
mutex_lock(&pmac_backlight_mutex);
|
||||
if (pmac_backlight) {
|
||||
struct backlight_properties *props;
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
mutex_unlock(&pmac_backlight_mutex);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int pmac_backlight_get_legacy_brightness()
|
||||
{
|
||||
int result = -ENXIO;
|
||||
|
||||
mutex_lock(&pmac_backlight_mutex);
|
||||
if (pmac_backlight) {
|
||||
struct backlight_properties *props;
|
||||
|
||||
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);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -99,17 +99,22 @@ config PMAC_MEDIABAY
|
|||
devices are not fully supported in the bay as I never had one to
|
||||
try with
|
||||
|
||||
# made a separate option since backlight may end up beeing used
|
||||
# on non-powerbook machines (but only on PMU based ones AFAIK)
|
||||
config PMAC_BACKLIGHT
|
||||
bool "Backlight control for LCD screens"
|
||||
depends on ADB_PMU && (BROKEN || !PPC64)
|
||||
help
|
||||
Say Y here to build in code to manage the LCD backlight on a
|
||||
Macintosh PowerBook. With this code, the backlight will be turned
|
||||
on and off appropriately on power-management and lid-open/lid-closed
|
||||
events; also, the PowerBook button device will be enabled so you can
|
||||
change the screen brightness.
|
||||
Say Y here to enable Macintosh specific extensions of the generic
|
||||
backlight code. With this enabled, the brightness keys on older
|
||||
PowerBooks will be enabled so you can change the screen brightness.
|
||||
Newer models should use an userspace daemon like pbbuttonsd.
|
||||
|
||||
config PMAC_BACKLIGHT_LEGACY
|
||||
bool "Provide legacy ioctl's on /dev/pmu for the backlight"
|
||||
depends on PMAC_BACKLIGHT && (BROKEN || !PPC64)
|
||||
help
|
||||
Say Y if you want to enable legacy ioctl's on /dev/pmu. This is for
|
||||
programs which use this old interface. New and updated programs
|
||||
should use the backlight classes in sysfs.
|
||||
|
||||
config ADB_MACIO
|
||||
bool "Include MacIO (CHRP) ADB driver"
|
||||
|
|
|
@ -12,6 +12,7 @@ obj-$(CONFIG_INPUT_ADBHID) += adbhid.o
|
|||
obj-$(CONFIG_ANSLCD) += ans-lcd.o
|
||||
|
||||
obj-$(CONFIG_ADB_PMU) += via-pmu.o
|
||||
obj-$(CONFIG_PMAC_BACKLIGHT) += via-pmu-backlight.o
|
||||
obj-$(CONFIG_ADB_CUDA) += via-cuda.o
|
||||
obj-$(CONFIG_PMAC_APM_EMU) += apm_emu.o
|
||||
obj-$(CONFIG_PMAC_SMU) += smu.o
|
||||
|
|
|
@ -503,9 +503,7 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto
|
|||
case 0x1f: /* Powerbook button device */
|
||||
{
|
||||
int down = (data[1] == (data[1] & 0xf));
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
int backlight = get_backlight_level();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* XXX: Where is the contrast control for the passive?
|
||||
* -- Cort
|
||||
|
@ -530,29 +528,17 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto
|
|||
|
||||
case 0xa: /* brightness decrease */
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
if (!disable_kernel_backlight) {
|
||||
if (down && backlight >= 0) {
|
||||
if (backlight > BACKLIGHT_OFF)
|
||||
set_backlight_level(backlight-1);
|
||||
else
|
||||
set_backlight_level(BACKLIGHT_OFF);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_PMAC_BACKLIGHT */
|
||||
if (!disable_kernel_backlight && down)
|
||||
pmac_backlight_key_down();
|
||||
#endif
|
||||
input_report_key(adbhid[id]->input, KEY_BRIGHTNESSDOWN, down);
|
||||
break;
|
||||
|
||||
case 0x9: /* brightness increase */
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
if (!disable_kernel_backlight) {
|
||||
if (down && backlight >= 0) {
|
||||
if (backlight < BACKLIGHT_MAX)
|
||||
set_backlight_level(backlight+1);
|
||||
else
|
||||
set_backlight_level(BACKLIGHT_MAX);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_PMAC_BACKLIGHT */
|
||||
if (!disable_kernel_backlight && down)
|
||||
pmac_backlight_key_up();
|
||||
#endif
|
||||
input_report_key(adbhid[id]->input, KEY_BRIGHTNESSUP, down);
|
||||
break;
|
||||
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* Backlight code for via-pmu
|
||||
*
|
||||
* Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
|
||||
* Copyright (C) 2001-2002 Benjamin Herrenschmidt
|
||||
* Copyright (C) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <asm/ptrace.h>
|
||||
#include <linux/adb.h>
|
||||
#include <linux/pmu.h>
|
||||
#include <asm/backlight.h>
|
||||
#include <asm/prom.h>
|
||||
|
||||
#define MAX_PMU_LEVEL 0xFF
|
||||
|
||||
static struct device_node *vias;
|
||||
static struct backlight_properties pmu_backlight_data;
|
||||
|
||||
static int pmu_backlight_get_level_brightness(struct fb_info *info,
|
||||
int level)
|
||||
{
|
||||
int pmulevel;
|
||||
|
||||
/* Get and convert the value */
|
||||
mutex_lock(&info->bl_mutex);
|
||||
pmulevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_PMU_LEVEL;
|
||||
mutex_unlock(&info->bl_mutex);
|
||||
|
||||
if (pmulevel < 0)
|
||||
pmulevel = 0;
|
||||
else if (pmulevel > MAX_PMU_LEVEL)
|
||||
pmulevel = MAX_PMU_LEVEL;
|
||||
|
||||
return pmulevel;
|
||||
}
|
||||
|
||||
static int pmu_backlight_update_status(struct backlight_device *bd)
|
||||
{
|
||||
struct fb_info *info = class_get_devdata(&bd->class_dev);
|
||||
struct adb_request req;
|
||||
int pmulevel, level = bd->props->brightness;
|
||||
|
||||
if (vias == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
if (bd->props->power != FB_BLANK_UNBLANK ||
|
||||
bd->props->fb_blank != FB_BLANK_UNBLANK)
|
||||
level = 0;
|
||||
|
||||
pmulevel = pmu_backlight_get_level_brightness(info, level);
|
||||
|
||||
pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel);
|
||||
pmu_wait_complete(&req);
|
||||
|
||||
pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
|
||||
PMU_POW_BACKLIGHT | (level > 0 ? PMU_POW_ON : PMU_POW_OFF));
|
||||
pmu_wait_complete(&req);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pmu_backlight_get_brightness(struct backlight_device *bd)
|
||||
{
|
||||
return bd->props->brightness;
|
||||
}
|
||||
|
||||
static struct backlight_properties pmu_backlight_data = {
|
||||
.owner = THIS_MODULE,
|
||||
.get_brightness = pmu_backlight_get_brightness,
|
||||
.update_status = pmu_backlight_update_status,
|
||||
.max_brightness = (FB_BACKLIGHT_LEVELS - 1),
|
||||
};
|
||||
|
||||
void __init pmu_backlight_init(struct device_node *in_vias)
|
||||
{
|
||||
struct backlight_device *bd;
|
||||
struct fb_info *info;
|
||||
char name[10];
|
||||
int level, autosave;
|
||||
|
||||
vias = in_vias;
|
||||
|
||||
/* Special case for the old PowerBook since I can't test on it */
|
||||
autosave =
|
||||
machine_is_compatible("AAPL,3400/2400") ||
|
||||
machine_is_compatible("AAPL,3500");
|
||||
|
||||
if (!autosave &&
|
||||
!pmac_has_backlight_type("pmu") &&
|
||||
!machine_is_compatible("AAPL,PowerBook1998") &&
|
||||
!machine_is_compatible("PowerBook1,1"))
|
||||
return;
|
||||
|
||||
/* Actually, this is a hack, but I don't know of a better way
|
||||
* to get the first framebuffer device.
|
||||
*/
|
||||
info = registered_fb[0];
|
||||
if (!info) {
|
||||
printk("pmubl: No framebuffer found\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
snprintf(name, sizeof(name), "pmubl%d", info->node);
|
||||
|
||||
bd = backlight_device_register(name, info, &pmu_backlight_data);
|
||||
if (IS_ERR(bd)) {
|
||||
printk("pmubl: Backlight registration failed\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
mutex_lock(&info->bl_mutex);
|
||||
info->bl_dev = bd;
|
||||
fb_bl_default_curve(info, 0x7F, 0x46, 0x0E);
|
||||
mutex_unlock(&info->bl_mutex);
|
||||
|
||||
level = pmu_backlight_data.max_brightness;
|
||||
|
||||
if (autosave) {
|
||||
/* read autosaved value if available */
|
||||
struct adb_request req;
|
||||
pmu_request(&req, NULL, 2, 0xd9, 0);
|
||||
pmu_wait_complete(&req);
|
||||
|
||||
mutex_lock(&info->bl_mutex);
|
||||
level = pmac_backlight_curve_lookup(info,
|
||||
(req.reply[0] >> 4) *
|
||||
pmu_backlight_data.max_brightness / 15);
|
||||
mutex_unlock(&info->bl_mutex);
|
||||
}
|
||||
|
||||
up(&bd->sem);
|
||||
bd->props->brightness = level;
|
||||
bd->props->power = FB_BLANK_UNBLANK;
|
||||
bd->props->update_status(bd);
|
||||
down(&bd->sem);
|
||||
|
||||
mutex_lock(&pmac_backlight_mutex);
|
||||
if (!pmac_backlight)
|
||||
pmac_backlight = bd;
|
||||
mutex_unlock(&pmac_backlight_mutex);
|
||||
|
||||
printk("pmubl: Backlight initialized (%s)\n", name);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
return;
|
||||
}
|
|
@ -144,7 +144,6 @@ static int data_index;
|
|||
static int data_len;
|
||||
static volatile int adb_int_pending;
|
||||
static volatile int disable_poll;
|
||||
static struct adb_request bright_req_1, bright_req_2;
|
||||
static struct device_node *vias;
|
||||
static int pmu_kind = PMU_UNKNOWN;
|
||||
static int pmu_fully_inited = 0;
|
||||
|
@ -161,7 +160,7 @@ static int drop_interrupts;
|
|||
#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
|
||||
static int option_lid_wakeup = 1;
|
||||
#endif /* CONFIG_PM && CONFIG_PPC32 */
|
||||
#if (defined(CONFIG_PM)&&defined(CONFIG_PPC32))||defined(CONFIG_PMAC_BACKLIGHT)
|
||||
#if (defined(CONFIG_PM)&&defined(CONFIG_PPC32))||defined(CONFIG_PMAC_BACKLIGHT_LEGACY)
|
||||
static int sleep_in_progress;
|
||||
#endif
|
||||
static unsigned long async_req_locks;
|
||||
|
@ -208,10 +207,6 @@ static int proc_get_info(char *page, char **start, off_t off,
|
|||
int count, int *eof, void *data);
|
||||
static int proc_get_irqstats(char *page, char **start, off_t off,
|
||||
int count, int *eof, void *data);
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
static int pmu_set_backlight_level(int level, void* data);
|
||||
static int pmu_set_backlight_enable(int on, int level, void* data);
|
||||
#endif /* CONFIG_PMAC_BACKLIGHT */
|
||||
static void pmu_pass_intr(unsigned char *data, int len);
|
||||
static int proc_get_batt(char *page, char **start, off_t off,
|
||||
int count, int *eof, void *data);
|
||||
|
@ -292,13 +287,6 @@ static char *pbook_type[] = {
|
|||
"Core99"
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
static struct backlight_controller pmu_backlight_controller = {
|
||||
pmu_set_backlight_enable,
|
||||
pmu_set_backlight_level
|
||||
};
|
||||
#endif /* CONFIG_PMAC_BACKLIGHT */
|
||||
|
||||
int __init find_via_pmu(void)
|
||||
{
|
||||
u64 taddr;
|
||||
|
@ -417,8 +405,6 @@ static int __init via_pmu_start(void)
|
|||
if (vias == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
bright_req_1.complete = 1;
|
||||
bright_req_2.complete = 1;
|
||||
batt_req.complete = 1;
|
||||
|
||||
#ifndef CONFIG_PPC_MERGE
|
||||
|
@ -483,9 +469,9 @@ static int __init via_pmu_dev_init(void)
|
|||
return -ENODEV;
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
/* Enable backlight */
|
||||
register_backlight_controller(&pmu_backlight_controller, NULL, "pmu");
|
||||
#endif /* CONFIG_PMAC_BACKLIGHT */
|
||||
/* Initialize backlight */
|
||||
pmu_backlight_init(vias);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PPC32
|
||||
if (machine_is_compatible("AAPL,3400/2400") ||
|
||||
|
@ -1424,7 +1410,7 @@ next:
|
|||
#ifdef CONFIG_INPUT_ADBHID
|
||||
if (!disable_kernel_backlight)
|
||||
#endif /* CONFIG_INPUT_ADBHID */
|
||||
set_backlight_level(data[1] >> 4);
|
||||
pmac_backlight_set_legacy_brightness(data[1] >> 4);
|
||||
#endif /* CONFIG_PMAC_BACKLIGHT */
|
||||
}
|
||||
/* Tick interrupt */
|
||||
|
@ -1674,61 +1660,6 @@ gpio1_interrupt(int irq, void *arg, struct pt_regs *regs)
|
|||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
static int backlight_to_bright[] = {
|
||||
0x7f, 0x46, 0x42, 0x3e, 0x3a, 0x36, 0x32, 0x2e,
|
||||
0x2a, 0x26, 0x22, 0x1e, 0x1a, 0x16, 0x12, 0x0e
|
||||
};
|
||||
|
||||
static int
|
||||
pmu_set_backlight_enable(int on, int level, void* data)
|
||||
{
|
||||
struct adb_request req;
|
||||
|
||||
if (vias == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
if (on) {
|
||||
pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT,
|
||||
backlight_to_bright[level]);
|
||||
pmu_wait_complete(&req);
|
||||
}
|
||||
pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
|
||||
PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF));
|
||||
pmu_wait_complete(&req);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
pmu_bright_complete(struct adb_request *req)
|
||||
{
|
||||
if (req == &bright_req_1)
|
||||
clear_bit(1, &async_req_locks);
|
||||
if (req == &bright_req_2)
|
||||
clear_bit(2, &async_req_locks);
|
||||
}
|
||||
|
||||
static int
|
||||
pmu_set_backlight_level(int level, void* data)
|
||||
{
|
||||
if (vias == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
if (test_and_set_bit(1, &async_req_locks))
|
||||
return -EAGAIN;
|
||||
pmu_request(&bright_req_1, pmu_bright_complete, 2, PMU_BACKLIGHT_BRIGHT,
|
||||
backlight_to_bright[level]);
|
||||
if (test_and_set_bit(2, &async_req_locks))
|
||||
return -EAGAIN;
|
||||
pmu_request(&bright_req_2, pmu_bright_complete, 2, PMU_POWER_CTRL,
|
||||
PMU_POW_BACKLIGHT | (level > BACKLIGHT_OFF ?
|
||||
PMU_POW_ON : PMU_POW_OFF));
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PMAC_BACKLIGHT */
|
||||
|
||||
void
|
||||
pmu_enable_irled(int on)
|
||||
{
|
||||
|
@ -2145,9 +2076,8 @@ pmac_suspend_devices(void)
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* Wait for completion of async backlight requests */
|
||||
while (!bright_req_1.complete || !bright_req_2.complete ||
|
||||
!batt_req.complete)
|
||||
/* Wait for completion of async requests */
|
||||
while (!batt_req.complete)
|
||||
pmu_poll();
|
||||
|
||||
/* Giveup the lazy FPU & vec so we don't have to back them
|
||||
|
@ -2678,26 +2608,34 @@ pmu_ioctl(struct inode * inode, struct file *filp,
|
|||
return put_user(1, argp);
|
||||
#endif /* CONFIG_PM && CONFIG_PPC32 */
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
/* Backlight should have its own device or go via
|
||||
* the fbdev
|
||||
*/
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT_LEGACY
|
||||
/* Compatibility ioctl's for backlight */
|
||||
case PMU_IOC_GET_BACKLIGHT:
|
||||
{
|
||||
int brightness;
|
||||
|
||||
if (sleep_in_progress)
|
||||
return -EBUSY;
|
||||
error = get_backlight_level();
|
||||
if (error < 0)
|
||||
return error;
|
||||
return put_user(error, argp);
|
||||
|
||||
brightness = pmac_backlight_get_legacy_brightness();
|
||||
if (brightness < 0)
|
||||
return brightness;
|
||||
else
|
||||
return put_user(brightness, argp);
|
||||
|
||||
}
|
||||
case PMU_IOC_SET_BACKLIGHT:
|
||||
{
|
||||
__u32 value;
|
||||
int brightness;
|
||||
|
||||
if (sleep_in_progress)
|
||||
return -EBUSY;
|
||||
error = get_user(value, argp);
|
||||
if (!error)
|
||||
error = set_backlight_level(value);
|
||||
break;
|
||||
|
||||
error = get_user(brightness, argp);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return pmac_backlight_set_legacy_brightness(brightness);
|
||||
}
|
||||
#ifdef CONFIG_INPUT_ADBHID
|
||||
case PMU_IOC_GRAB_BACKLIGHT: {
|
||||
|
@ -2713,7 +2651,7 @@ pmu_ioctl(struct inode * inode, struct file *filp,
|
|||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_INPUT_ADBHID */
|
||||
#endif /* CONFIG_PMAC_BACKLIGHT */
|
||||
#endif /* CONFIG_PMAC_BACKLIGHT_LEGACY */
|
||||
case PMU_IOC_GET_MODEL:
|
||||
return put_user(pmu_kind, argp);
|
||||
case PMU_IOC_HAS_ADB:
|
||||
|
|
|
@ -86,6 +86,11 @@ config FB_FIRMWARE_EDID
|
|||
combination with certain motherboards and monitors are known to
|
||||
suffer from this problem.
|
||||
|
||||
config FB_BACKLIGHT
|
||||
bool
|
||||
depends on FB
|
||||
default n
|
||||
|
||||
config FB_MODE_HELPERS
|
||||
bool "Enable Video Mode Handling Helpers"
|
||||
depends on FB
|
||||
|
@ -717,6 +722,16 @@ config FB_NVIDIA_I2C
|
|||
independently validate video mode parameters, you should say Y
|
||||
here.
|
||||
|
||||
config FB_NVIDIA_BACKLIGHT
|
||||
bool "Support for backlight control"
|
||||
depends on FB_NVIDIA && PPC_PMAC
|
||||
select FB_BACKLIGHT
|
||||
select BACKLIGHT_LCD_SUPPORT
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
default y
|
||||
help
|
||||
Say Y here if you want to control the backlight of your display.
|
||||
|
||||
config FB_RIVA
|
||||
tristate "nVidia Riva support"
|
||||
depends on FB && PCI
|
||||
|
@ -755,6 +770,16 @@ config FB_RIVA_DEBUG
|
|||
of debugging informations to provide to the maintainer when
|
||||
something goes wrong.
|
||||
|
||||
config FB_RIVA_BACKLIGHT
|
||||
bool "Support for backlight control"
|
||||
depends on FB_RIVA && PPC_PMAC
|
||||
select FB_BACKLIGHT
|
||||
select BACKLIGHT_LCD_SUPPORT
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
default y
|
||||
help
|
||||
Say Y here if you want to control the backlight of your display.
|
||||
|
||||
config FB_I810
|
||||
tristate "Intel 810/815 support (EXPERIMENTAL)"
|
||||
depends on FB && EXPERIMENTAL && PCI && X86_32
|
||||
|
@ -993,6 +1018,7 @@ config FB_RADEON
|
|||
|
||||
There is a product page at
|
||||
http://apps.ati.com/ATIcompare/
|
||||
|
||||
config FB_RADEON_I2C
|
||||
bool "DDC/I2C for ATI Radeon support"
|
||||
depends on FB_RADEON
|
||||
|
@ -1000,6 +1026,16 @@ config FB_RADEON_I2C
|
|||
help
|
||||
Say Y here if you want DDC/I2C support for your Radeon board.
|
||||
|
||||
config FB_RADEON_BACKLIGHT
|
||||
bool "Support for backlight control"
|
||||
depends on FB_RADEON && PPC_PMAC
|
||||
select FB_BACKLIGHT
|
||||
select BACKLIGHT_LCD_SUPPORT
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
default y
|
||||
help
|
||||
Say Y here if you want to control the backlight of your display.
|
||||
|
||||
config FB_RADEON_DEBUG
|
||||
bool "Lots of debug output from Radeon driver"
|
||||
depends on FB_RADEON
|
||||
|
@ -1024,6 +1060,16 @@ config FB_ATY128
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called aty128fb.
|
||||
|
||||
config FB_ATY128_BACKLIGHT
|
||||
bool "Support for backlight control"
|
||||
depends on FB_ATY128 && PPC_PMAC
|
||||
select FB_BACKLIGHT
|
||||
select BACKLIGHT_LCD_SUPPORT
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
default y
|
||||
help
|
||||
Say Y here if you want to control the backlight of your display.
|
||||
|
||||
config FB_ATY
|
||||
tristate "ATI Mach64 display support" if PCI || ATARI
|
||||
depends on FB && !SPARC32
|
||||
|
@ -1066,6 +1112,16 @@ config FB_ATY_GX
|
|||
is at
|
||||
<http://support.ati.com/products/pc/mach64/graphics_xpression.html>.
|
||||
|
||||
config FB_ATY_BACKLIGHT
|
||||
bool "Support for backlight control"
|
||||
depends on FB_ATY && PPC_PMAC
|
||||
select FB_BACKLIGHT
|
||||
select BACKLIGHT_LCD_SUPPORT
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
default y
|
||||
help
|
||||
Say Y here if you want to control the backlight of your display.
|
||||
|
||||
config FB_S3TRIO
|
||||
bool "S3 Trio display support"
|
||||
depends on (FB = y) && PPC && BROKEN
|
||||
|
|
|
@ -10,5 +10,6 @@ atyfb-objs := $(atyfb-y)
|
|||
|
||||
radeonfb-y := radeon_base.o radeon_pm.o radeon_monitor.o radeon_accel.o
|
||||
radeonfb-$(CONFIG_FB_RADEON_I2C) += radeon_i2c.o
|
||||
radeonfb-$(CONFIG_FB_RADEON_BACKLIGHT) += radeon_backlight.o
|
||||
radeonfb-objs := $(radeonfb-y)
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/backlight.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#ifdef CONFIG_PPC_PMAC
|
||||
|
@ -480,16 +481,6 @@ static struct fb_ops aty128fb_ops = {
|
|||
.fb_imageblit = cfb_imageblit,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
static int aty128_set_backlight_enable(int on, int level, void* data);
|
||||
static int aty128_set_backlight_level(int level, void* data);
|
||||
|
||||
static struct backlight_controller aty128_backlight_controller = {
|
||||
aty128_set_backlight_enable,
|
||||
aty128_set_backlight_level
|
||||
};
|
||||
#endif /* CONFIG_PMAC_BACKLIGHT */
|
||||
|
||||
/*
|
||||
* Functions to read from/write to the mmio registers
|
||||
* - endian conversions may possibly be avoided by
|
||||
|
@ -1258,19 +1249,35 @@ static void aty128_set_crt_enable(struct aty128fb_par *par, int on)
|
|||
static void aty128_set_lcd_enable(struct aty128fb_par *par, int on)
|
||||
{
|
||||
u32 reg;
|
||||
#ifdef CONFIG_FB_ATY128_BACKLIGHT
|
||||
struct fb_info *info = pci_get_drvdata(par->pdev);
|
||||
#endif
|
||||
|
||||
if (on) {
|
||||
reg = aty_ld_le32(LVDS_GEN_CNTL);
|
||||
reg |= LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION;
|
||||
reg &= ~LVDS_DISPLAY_DIS;
|
||||
aty_st_le32(LVDS_GEN_CNTL, reg);
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
aty128_set_backlight_enable(get_backlight_enable(),
|
||||
get_backlight_level(), par);
|
||||
#ifdef CONFIG_FB_ATY128_BACKLIGHT
|
||||
mutex_lock(&info->bl_mutex);
|
||||
if (info->bl_dev) {
|
||||
down(&info->bl_dev->sem);
|
||||
info->bl_dev->props->update_status(info->bl_dev);
|
||||
up(&info->bl_dev->sem);
|
||||
}
|
||||
mutex_unlock(&info->bl_mutex);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
aty128_set_backlight_enable(0, 0, par);
|
||||
#ifdef CONFIG_FB_ATY128_BACKLIGHT
|
||||
mutex_lock(&info->bl_mutex);
|
||||
if (info->bl_dev) {
|
||||
down(&info->bl_dev->sem);
|
||||
info->bl_dev->props->brightness = 0;
|
||||
info->bl_dev->props->power = FB_BLANK_POWERDOWN;
|
||||
info->bl_dev->props->update_status(info->bl_dev);
|
||||
up(&info->bl_dev->sem);
|
||||
}
|
||||
mutex_unlock(&info->bl_mutex);
|
||||
#endif
|
||||
reg = aty_ld_le32(LVDS_GEN_CNTL);
|
||||
reg |= LVDS_DISPLAY_DIS;
|
||||
|
@ -1691,6 +1698,184 @@ static int __init aty128fb_setup(char *options)
|
|||
}
|
||||
#endif /* MODULE */
|
||||
|
||||
/* Backlight */
|
||||
#ifdef CONFIG_FB_ATY128_BACKLIGHT
|
||||
#define MAX_LEVEL 0xFF
|
||||
|
||||
static struct backlight_properties aty128_bl_data;
|
||||
|
||||
static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
|
||||
int level)
|
||||
{
|
||||
struct fb_info *info = pci_get_drvdata(par->pdev);
|
||||
int atylevel;
|
||||
|
||||
/* Get and convert the value */
|
||||
mutex_lock(&info->bl_mutex);
|
||||
atylevel = MAX_LEVEL -
|
||||
(info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL);
|
||||
mutex_unlock(&info->bl_mutex);
|
||||
|
||||
if (atylevel < 0)
|
||||
atylevel = 0;
|
||||
else if (atylevel > MAX_LEVEL)
|
||||
atylevel = MAX_LEVEL;
|
||||
|
||||
return atylevel;
|
||||
}
|
||||
|
||||
/* We turn off the LCD completely instead of just dimming the backlight.
|
||||
* This provides greater power saving and the display is useless without
|
||||
* backlight anyway
|
||||
*/
|
||||
#define BACKLIGHT_LVDS_OFF
|
||||
/* That one prevents proper CRT output with LCD off */
|
||||
#undef BACKLIGHT_DAC_OFF
|
||||
|
||||
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);
|
||||
int level;
|
||||
|
||||
if (bd->props->power != FB_BLANK_UNBLANK ||
|
||||
bd->props->fb_blank != FB_BLANK_UNBLANK ||
|
||||
!par->lcd_on)
|
||||
level = 0;
|
||||
else
|
||||
level = bd->props->brightness;
|
||||
|
||||
reg |= LVDS_BL_MOD_EN | LVDS_BLON;
|
||||
if (level > 0) {
|
||||
reg |= LVDS_DIGION;
|
||||
if (!(reg & LVDS_ON)) {
|
||||
reg &= ~LVDS_BLON;
|
||||
aty_st_le32(LVDS_GEN_CNTL, reg);
|
||||
aty_ld_le32(LVDS_GEN_CNTL);
|
||||
mdelay(10);
|
||||
reg |= LVDS_BLON;
|
||||
aty_st_le32(LVDS_GEN_CNTL, reg);
|
||||
}
|
||||
reg &= ~LVDS_BL_MOD_LEVEL_MASK;
|
||||
reg |= (aty128_bl_get_level_brightness(par, level) << LVDS_BL_MOD_LEVEL_SHIFT);
|
||||
#ifdef BACKLIGHT_LVDS_OFF
|
||||
reg |= LVDS_ON | LVDS_EN;
|
||||
reg &= ~LVDS_DISPLAY_DIS;
|
||||
#endif
|
||||
aty_st_le32(LVDS_GEN_CNTL, reg);
|
||||
#ifdef BACKLIGHT_DAC_OFF
|
||||
aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN));
|
||||
#endif
|
||||
} else {
|
||||
reg &= ~LVDS_BL_MOD_LEVEL_MASK;
|
||||
reg |= (aty128_bl_get_level_brightness(par, 0) << LVDS_BL_MOD_LEVEL_SHIFT);
|
||||
#ifdef BACKLIGHT_LVDS_OFF
|
||||
reg |= LVDS_DISPLAY_DIS;
|
||||
aty_st_le32(LVDS_GEN_CNTL, reg);
|
||||
aty_ld_le32(LVDS_GEN_CNTL);
|
||||
udelay(10);
|
||||
reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION);
|
||||
#endif
|
||||
aty_st_le32(LVDS_GEN_CNTL, reg);
|
||||
#ifdef BACKLIGHT_DAC_OFF
|
||||
aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aty128_bl_get_brightness(struct backlight_device *bd)
|
||||
{
|
||||
return bd->props->brightness;
|
||||
}
|
||||
|
||||
static struct backlight_properties aty128_bl_data = {
|
||||
.owner = THIS_MODULE,
|
||||
.get_brightness = aty128_bl_get_brightness,
|
||||
.update_status = aty128_bl_update_status,
|
||||
.max_brightness = (FB_BACKLIGHT_LEVELS - 1),
|
||||
};
|
||||
|
||||
static void aty128_bl_init(struct aty128fb_par *par)
|
||||
{
|
||||
struct fb_info *info = pci_get_drvdata(par->pdev);
|
||||
struct backlight_device *bd;
|
||||
char name[12];
|
||||
|
||||
/* Could be extended to Rage128Pro LVDS output too */
|
||||
if (par->chip_gen != rage_M3)
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
if (!pmac_has_backlight_type("ati"))
|
||||
return;
|
||||
#endif
|
||||
|
||||
snprintf(name, sizeof(name), "aty128bl%d", info->node);
|
||||
|
||||
bd = backlight_device_register(name, par, &aty128_bl_data);
|
||||
if (IS_ERR(bd)) {
|
||||
info->bl_dev = NULL;
|
||||
printk("aty128: Backlight registration failed\n");
|
||||
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);
|
||||
|
||||
up(&bd->sem);
|
||||
bd->props->brightness = aty128_bl_data.max_brightness;
|
||||
bd->props->power = FB_BLANK_UNBLANK;
|
||||
bd->props->update_status(bd);
|
||||
down(&bd->sem);
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
mutex_lock(&pmac_backlight_mutex);
|
||||
if (!pmac_backlight)
|
||||
pmac_backlight = bd;
|
||||
mutex_unlock(&pmac_backlight_mutex);
|
||||
#endif
|
||||
|
||||
printk("aty128: Backlight initialized (%s)\n", name);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
return;
|
||||
}
|
||||
|
||||
static void aty128_bl_exit(struct aty128fb_par *par)
|
||||
{
|
||||
struct fb_info *info = pci_get_drvdata(par->pdev);
|
||||
|
||||
#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)
|
||||
pmac_backlight = NULL;
|
||||
#endif
|
||||
|
||||
backlight_device_unregister(info->bl_dev);
|
||||
info->bl_dev = NULL;
|
||||
|
||||
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 */
|
||||
|
||||
/*
|
||||
* Initialisation
|
||||
|
@ -1835,17 +2020,15 @@ static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id *
|
|||
if (register_framebuffer(info) < 0)
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
/* Could be extended to Rage128Pro LVDS output too */
|
||||
if (par->chip_gen == rage_M3)
|
||||
register_backlight_controller(&aty128_backlight_controller, par, "ati");
|
||||
#endif /* CONFIG_PMAC_BACKLIGHT */
|
||||
|
||||
par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM);
|
||||
par->pdev = pdev;
|
||||
par->asleep = 0;
|
||||
par->lock_blank = 0;
|
||||
|
||||
#ifdef CONFIG_FB_ATY128_BACKLIGHT
|
||||
aty128_bl_init(par);
|
||||
#endif
|
||||
|
||||
printk(KERN_INFO "fb%d: %s frame buffer device on %s\n",
|
||||
info->node, info->fix.id, video_card);
|
||||
|
||||
|
@ -1981,6 +2164,10 @@ static void __devexit aty128_remove(struct pci_dev *pdev)
|
|||
|
||||
par = info->par;
|
||||
|
||||
#ifdef CONFIG_FB_ATY128_BACKLIGHT
|
||||
aty128_bl_exit(par);
|
||||
#endif
|
||||
|
||||
unregister_framebuffer(info);
|
||||
#ifdef CONFIG_MTRR
|
||||
if (par->mtrr.vram_valid)
|
||||
|
@ -2011,10 +2198,14 @@ static int aty128fb_blank(int blank, struct fb_info *fb)
|
|||
if (par->lock_blank || par->asleep)
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
if (machine_is(powermac) && blank)
|
||||
set_backlight_enable(0);
|
||||
#endif /* CONFIG_PMAC_BACKLIGHT */
|
||||
#ifdef CONFIG_FB_ATY128_BACKLIGHT
|
||||
if (machine_is(powermac) && blank) {
|
||||
down(&fb->bl_dev->sem);
|
||||
fb->bl_dev->props->power = FB_BLANK_POWERDOWN;
|
||||
fb->bl_dev->props->update_status(fb->bl_dev);
|
||||
up(&fb->bl_dev->sem);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (blank & FB_BLANK_VSYNC_SUSPEND)
|
||||
state |= 2;
|
||||
|
@ -2029,10 +2220,14 @@ static int aty128fb_blank(int blank, struct fb_info *fb)
|
|||
aty128_set_crt_enable(par, par->crt_on && !blank);
|
||||
aty128_set_lcd_enable(par, par->lcd_on && !blank);
|
||||
}
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
if (machine_is(powermac) && !blank)
|
||||
set_backlight_enable(1);
|
||||
#endif /* CONFIG_PMAC_BACKLIGHT */
|
||||
#ifdef CONFIG_FB_ATY128_BACKLIGHT
|
||||
if (machine_is(powermac) && !blank) {
|
||||
down(&fb->bl_dev->sem);
|
||||
fb->bl_dev->props->power = FB_BLANK_UNBLANK;
|
||||
fb->bl_dev->props->update_status(fb->bl_dev);
|
||||
up(&fb->bl_dev->sem);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2138,73 +2333,6 @@ static int aty128fb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
static int backlight_conv[] = {
|
||||
0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
|
||||
0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
|
||||
};
|
||||
|
||||
/* We turn off the LCD completely instead of just dimming the backlight.
|
||||
* This provides greater power saving and the display is useless without
|
||||
* backlight anyway
|
||||
*/
|
||||
#define BACKLIGHT_LVDS_OFF
|
||||
/* That one prevents proper CRT output with LCD off */
|
||||
#undef BACKLIGHT_DAC_OFF
|
||||
|
||||
static int aty128_set_backlight_enable(int on, int level, void *data)
|
||||
{
|
||||
struct aty128fb_par *par = data;
|
||||
unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
|
||||
|
||||
if (!par->lcd_on)
|
||||
on = 0;
|
||||
reg |= LVDS_BL_MOD_EN | LVDS_BLON;
|
||||
if (on && level > BACKLIGHT_OFF) {
|
||||
reg |= LVDS_DIGION;
|
||||
if (!(reg & LVDS_ON)) {
|
||||
reg &= ~LVDS_BLON;
|
||||
aty_st_le32(LVDS_GEN_CNTL, reg);
|
||||
(void)aty_ld_le32(LVDS_GEN_CNTL);
|
||||
mdelay(10);
|
||||
reg |= LVDS_BLON;
|
||||
aty_st_le32(LVDS_GEN_CNTL, reg);
|
||||
}
|
||||
reg &= ~LVDS_BL_MOD_LEVEL_MASK;
|
||||
reg |= (backlight_conv[level] << LVDS_BL_MOD_LEVEL_SHIFT);
|
||||
#ifdef BACKLIGHT_LVDS_OFF
|
||||
reg |= LVDS_ON | LVDS_EN;
|
||||
reg &= ~LVDS_DISPLAY_DIS;
|
||||
#endif
|
||||
aty_st_le32(LVDS_GEN_CNTL, reg);
|
||||
#ifdef BACKLIGHT_DAC_OFF
|
||||
aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN));
|
||||
#endif
|
||||
} else {
|
||||
reg &= ~LVDS_BL_MOD_LEVEL_MASK;
|
||||
reg |= (backlight_conv[0] << LVDS_BL_MOD_LEVEL_SHIFT);
|
||||
#ifdef BACKLIGHT_LVDS_OFF
|
||||
reg |= LVDS_DISPLAY_DIS;
|
||||
aty_st_le32(LVDS_GEN_CNTL, reg);
|
||||
(void)aty_ld_le32(LVDS_GEN_CNTL);
|
||||
udelay(10);
|
||||
reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION);
|
||||
#endif
|
||||
aty_st_le32(LVDS_GEN_CNTL, reg);
|
||||
#ifdef BACKLIGHT_DAC_OFF
|
||||
aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aty128_set_backlight_level(int level, void* data)
|
||||
{
|
||||
return aty128_set_backlight_enable(1, level, data);
|
||||
}
|
||||
#endif /* CONFIG_PMAC_BACKLIGHT */
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Accelerated functions
|
||||
|
|
|
@ -151,6 +151,7 @@ struct atyfb_par {
|
|||
int lock_blank;
|
||||
unsigned long res_start;
|
||||
unsigned long res_size;
|
||||
struct pci_dev *pdev;
|
||||
#ifdef __sparc__
|
||||
struct pci_mmap_map *mmap_map;
|
||||
u8 mmaped;
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/backlight.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
@ -2115,45 +2116,142 @@ static int atyfb_pci_resume(struct pci_dev *pdev)
|
|||
|
||||
#endif /* defined(CONFIG_PM) && defined(CONFIG_PCI) */
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
/* Backlight */
|
||||
#ifdef CONFIG_FB_ATY_BACKLIGHT
|
||||
#define MAX_LEVEL 0xFF
|
||||
|
||||
/*
|
||||
* LCD backlight control
|
||||
*/
|
||||
static struct backlight_properties aty_bl_data;
|
||||
|
||||
static int backlight_conv[] = {
|
||||
0x00, 0x3f, 0x4c, 0x59, 0x66, 0x73, 0x80, 0x8d,
|
||||
0x9a, 0xa7, 0xb4, 0xc1, 0xcf, 0xdc, 0xe9, 0xff
|
||||
};
|
||||
|
||||
static int aty_set_backlight_enable(int on, int level, void *data)
|
||||
static int aty_bl_get_level_brightness(struct atyfb_par *par, int level)
|
||||
{
|
||||
struct fb_info *info = (struct fb_info *) data;
|
||||
struct atyfb_par *par = (struct atyfb_par *) info->par;
|
||||
struct fb_info *info = pci_get_drvdata(par->pdev);
|
||||
int atylevel;
|
||||
|
||||
/* Get and convert the value */
|
||||
mutex_lock(&info->bl_mutex);
|
||||
atylevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
|
||||
mutex_unlock(&info->bl_mutex);
|
||||
|
||||
if (atylevel < 0)
|
||||
atylevel = 0;
|
||||
else if (atylevel > MAX_LEVEL)
|
||||
atylevel = MAX_LEVEL;
|
||||
|
||||
return atylevel;
|
||||
}
|
||||
|
||||
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);
|
||||
int level;
|
||||
|
||||
if (bd->props->power != FB_BLANK_UNBLANK ||
|
||||
bd->props->fb_blank != FB_BLANK_UNBLANK)
|
||||
level = 0;
|
||||
else
|
||||
level = bd->props->brightness;
|
||||
|
||||
reg |= (BLMOD_EN | BIASMOD_EN);
|
||||
if (on && level > BACKLIGHT_OFF) {
|
||||
if (level > 0) {
|
||||
reg &= ~BIAS_MOD_LEVEL_MASK;
|
||||
reg |= (backlight_conv[level] << BIAS_MOD_LEVEL_SHIFT);
|
||||
reg |= (aty_bl_get_level_brightness(par, level) << BIAS_MOD_LEVEL_SHIFT);
|
||||
} else {
|
||||
reg &= ~BIAS_MOD_LEVEL_MASK;
|
||||
reg |= (backlight_conv[0] << BIAS_MOD_LEVEL_SHIFT);
|
||||
reg |= (aty_bl_get_level_brightness(par, 0) << BIAS_MOD_LEVEL_SHIFT);
|
||||
}
|
||||
aty_st_lcd(LCD_MISC_CNTL, reg, par);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aty_set_backlight_level(int level, void *data)
|
||||
static int aty_bl_get_brightness(struct backlight_device *bd)
|
||||
{
|
||||
return aty_set_backlight_enable(1, level, data);
|
||||
return bd->props->brightness;
|
||||
}
|
||||
|
||||
static struct backlight_controller aty_backlight_controller = {
|
||||
aty_set_backlight_enable,
|
||||
aty_set_backlight_level
|
||||
static struct backlight_properties aty_bl_data = {
|
||||
.owner = THIS_MODULE,
|
||||
.get_brightness = aty_bl_get_brightness,
|
||||
.update_status = aty_bl_update_status,
|
||||
.max_brightness = (FB_BACKLIGHT_LEVELS - 1),
|
||||
};
|
||||
#endif /* CONFIG_PMAC_BACKLIGHT */
|
||||
|
||||
static void aty_bl_init(struct atyfb_par *par)
|
||||
{
|
||||
struct fb_info *info = pci_get_drvdata(par->pdev);
|
||||
struct backlight_device *bd;
|
||||
char name[12];
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
if (!pmac_has_backlight_type("ati"))
|
||||
return;
|
||||
#endif
|
||||
|
||||
snprintf(name, sizeof(name), "atybl%d", info->node);
|
||||
|
||||
bd = backlight_device_register(name, par, &aty_bl_data);
|
||||
if (IS_ERR(bd)) {
|
||||
info->bl_dev = NULL;
|
||||
printk("aty: Backlight registration failed\n");
|
||||
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);
|
||||
|
||||
up(&bd->sem);
|
||||
bd->props->brightness = aty_bl_data.max_brightness;
|
||||
bd->props->power = FB_BLANK_UNBLANK;
|
||||
bd->props->update_status(bd);
|
||||
down(&bd->sem);
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
mutex_lock(&pmac_backlight_mutex);
|
||||
if (!pmac_backlight)
|
||||
pmac_backlight = bd;
|
||||
mutex_unlock(&pmac_backlight_mutex);
|
||||
#endif
|
||||
|
||||
printk("aty: Backlight initialized (%s)\n", name);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
return;
|
||||
}
|
||||
|
||||
static void aty_bl_exit(struct atyfb_par *par)
|
||||
{
|
||||
struct fb_info *info = pci_get_drvdata(par->pdev);
|
||||
|
||||
#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)
|
||||
pmac_backlight = NULL;
|
||||
#endif
|
||||
|
||||
backlight_device_unregister(info->bl_dev);
|
||||
|
||||
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 */
|
||||
|
||||
static void __init aty_calc_mem_refresh(struct atyfb_par *par, int xclk)
|
||||
{
|
||||
|
@ -2513,9 +2611,13 @@ static int __init aty_init(struct fb_info *info, const char *name)
|
|||
/* these bits let the 101 powerbook wake up from sleep -- paulus */
|
||||
aty_st_lcd(POWER_MANAGEMENT, aty_ld_lcd(POWER_MANAGEMENT, par)
|
||||
| (USE_F32KHZ | TRISTATE_MEM_EN), par);
|
||||
} else if (M64_HAS(MOBIL_BUS))
|
||||
register_backlight_controller(&aty_backlight_controller, info, "ati");
|
||||
#endif /* CONFIG_PMAC_BACKLIGHT */
|
||||
} else
|
||||
#endif
|
||||
if (M64_HAS(MOBIL_BUS)) {
|
||||
#ifdef CONFIG_FB_ATY_BACKLIGHT
|
||||
aty_bl_init (par);
|
||||
#endif
|
||||
}
|
||||
|
||||
memset(&var, 0, sizeof(var));
|
||||
#ifdef CONFIG_PPC
|
||||
|
@ -2674,8 +2776,16 @@ static int atyfb_blank(int blank, struct fb_info *info)
|
|||
return 0;
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
if (machine_is(powermac) && blank > FB_BLANK_NORMAL)
|
||||
set_backlight_enable(0);
|
||||
if (machine_is(powermac) && blank > FB_BLANK_NORMAL) {
|
||||
mutex_lock(&info->bl_mutex);
|
||||
if (info->bl_dev) {
|
||||
down(&info->bl_dev->sem);
|
||||
info->bl_dev->props->power = FB_BLANK_POWERDOWN;
|
||||
info->bl_dev->props->update_status(info->bl_dev);
|
||||
up(&info->bl_dev->sem);
|
||||
}
|
||||
mutex_unlock(&info->bl_mutex);
|
||||
}
|
||||
#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
|
||||
if (par->lcd_table && blank > FB_BLANK_NORMAL &&
|
||||
(aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
|
||||
|
@ -2706,8 +2816,16 @@ static int atyfb_blank(int blank, struct fb_info *info)
|
|||
aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par);
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
if (machine_is(powermac) && blank <= FB_BLANK_NORMAL)
|
||||
set_backlight_enable(1);
|
||||
if (machine_is(powermac) && blank <= FB_BLANK_NORMAL) {
|
||||
mutex_lock(&info->bl_mutex);
|
||||
if (info->bl_dev) {
|
||||
down(&info->bl_dev->sem);
|
||||
info->bl_dev->props->power = FB_BLANK_UNBLANK;
|
||||
info->bl_dev->props->update_status(info->bl_dev);
|
||||
up(&info->bl_dev->sem);
|
||||
}
|
||||
mutex_unlock(&info->bl_mutex);
|
||||
}
|
||||
#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
|
||||
if (par->lcd_table && blank <= FB_BLANK_NORMAL &&
|
||||
(aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
|
||||
|
@ -3440,6 +3558,7 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi
|
|||
par->res_start = res_start;
|
||||
par->res_size = res_size;
|
||||
par->irq = pdev->irq;
|
||||
par->pdev = pdev;
|
||||
|
||||
/* Setup "info" structure */
|
||||
#ifdef __sparc__
|
||||
|
@ -3571,6 +3690,11 @@ static void __devexit atyfb_remove(struct fb_info *info)
|
|||
aty_set_crtc(par, &saved_crtc);
|
||||
par->pll_ops->set_pll(info, &saved_pll);
|
||||
|
||||
#ifdef CONFIG_FB_ATY_BACKLIGHT
|
||||
if (M64_HAS(MOBIL_BUS))
|
||||
aty_bl_exit(par);
|
||||
#endif
|
||||
|
||||
unregister_framebuffer(info);
|
||||
|
||||
#ifdef CONFIG_MTRR
|
||||
|
|
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
* Backlight code for ATI Radeon based graphic cards
|
||||
*
|
||||
* Copyright (c) 2000 Ani Joshi <ajoshi@kernel.crashing.org>
|
||||
* Copyright (c) 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org>
|
||||
* Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "radeonfb.h"
|
||||
#include <linux/backlight.h>
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
#include <asm/backlight.h>
|
||||
#endif
|
||||
|
||||
#define MAX_RADEON_LEVEL 0xFF
|
||||
|
||||
static struct backlight_properties radeon_bl_data;
|
||||
|
||||
struct radeon_bl_privdata {
|
||||
struct radeonfb_info *rinfo;
|
||||
uint8_t negative;
|
||||
};
|
||||
|
||||
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 */
|
||||
rlevel = pdata->rinfo->info->bl_curve[level] *
|
||||
FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL;
|
||||
|
||||
mutex_unlock(&info->bl_mutex);
|
||||
|
||||
if (pdata->negative)
|
||||
rlevel = MAX_RADEON_LEVEL - rlevel;
|
||||
|
||||
if (rlevel < 0)
|
||||
rlevel = 0;
|
||||
else if (rlevel > MAX_RADEON_LEVEL)
|
||||
rlevel = MAX_RADEON_LEVEL;
|
||||
|
||||
return rlevel;
|
||||
}
|
||||
|
||||
static int radeon_bl_update_status(struct backlight_device *bd)
|
||||
{
|
||||
struct radeon_bl_privdata *pdata = class_get_devdata(&bd->class_dev);
|
||||
struct radeonfb_info *rinfo = pdata->rinfo;
|
||||
u32 lvds_gen_cntl, tmpPixclksCntl;
|
||||
int level;
|
||||
|
||||
if (rinfo->mon1_type != MT_LCD)
|
||||
return 0;
|
||||
|
||||
/* We turn off the LCD completely instead of just dimming the
|
||||
* backlight. This provides some greater power saving and the display
|
||||
* is useless without backlight anyway.
|
||||
*/
|
||||
if (bd->props->power != FB_BLANK_UNBLANK ||
|
||||
bd->props->fb_blank != FB_BLANK_UNBLANK)
|
||||
level = 0;
|
||||
else
|
||||
level = bd->props->brightness;
|
||||
|
||||
del_timer_sync(&rinfo->lvds_timer);
|
||||
radeon_engine_idle();
|
||||
|
||||
lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
|
||||
if (level > 0) {
|
||||
lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
|
||||
if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) {
|
||||
lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON);
|
||||
lvds_gen_cntl |= LVDS_BLON | LVDS_EN;
|
||||
OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
|
||||
lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
|
||||
lvds_gen_cntl |=
|
||||
(radeon_bl_get_level_brightness(pdata, level) <<
|
||||
LVDS_BL_MOD_LEVEL_SHIFT);
|
||||
lvds_gen_cntl |= LVDS_ON;
|
||||
lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN);
|
||||
rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
|
||||
mod_timer(&rinfo->lvds_timer,
|
||||
jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
|
||||
} else {
|
||||
lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
|
||||
lvds_gen_cntl |=
|
||||
(radeon_bl_get_level_brightness(pdata, level) <<
|
||||
LVDS_BL_MOD_LEVEL_SHIFT);
|
||||
OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
|
||||
}
|
||||
rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
|
||||
rinfo->init_state.lvds_gen_cntl |= rinfo->pending_lvds_gen_cntl
|
||||
& LVDS_STATE_MASK;
|
||||
} else {
|
||||
/* Asic bug, when turning off LVDS_ON, we have to make sure
|
||||
RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
|
||||
*/
|
||||
tmpPixclksCntl = INPLL(PIXCLKS_CNTL);
|
||||
if (rinfo->is_mobility || rinfo->is_IGP)
|
||||
OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
|
||||
lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN);
|
||||
lvds_gen_cntl |= (radeon_bl_get_level_brightness(pdata, 0) <<
|
||||
LVDS_BL_MOD_LEVEL_SHIFT);
|
||||
lvds_gen_cntl |= LVDS_DISPLAY_DIS;
|
||||
OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
|
||||
udelay(100);
|
||||
lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN);
|
||||
OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
|
||||
lvds_gen_cntl &= ~(LVDS_DIGON);
|
||||
rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
|
||||
mod_timer(&rinfo->lvds_timer,
|
||||
jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
|
||||
if (rinfo->is_mobility || rinfo->is_IGP)
|
||||
OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl);
|
||||
}
|
||||
rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
|
||||
rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int radeon_bl_get_brightness(struct backlight_device *bd)
|
||||
{
|
||||
return bd->props->brightness;
|
||||
}
|
||||
|
||||
static struct backlight_properties radeon_bl_data = {
|
||||
.owner = THIS_MODULE,
|
||||
.get_brightness = radeon_bl_get_brightness,
|
||||
.update_status = radeon_bl_update_status,
|
||||
.max_brightness = (FB_BACKLIGHT_LEVELS - 1),
|
||||
};
|
||||
|
||||
void radeonfb_bl_init(struct radeonfb_info *rinfo)
|
||||
{
|
||||
struct backlight_device *bd;
|
||||
struct radeon_bl_privdata *pdata;
|
||||
char name[12];
|
||||
|
||||
if (rinfo->mon1_type != MT_LCD)
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
if (!pmac_has_backlight_type("ati") &&
|
||||
!pmac_has_backlight_type("mnca"))
|
||||
return;
|
||||
#endif
|
||||
|
||||
pdata = kmalloc(sizeof(struct radeon_bl_privdata), GFP_KERNEL);
|
||||
if (!pdata) {
|
||||
printk("radeonfb: Memory allocation failed\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node);
|
||||
|
||||
bd = backlight_device_register(name, pdata, &radeon_bl_data);
|
||||
if (IS_ERR(bd)) {
|
||||
rinfo->info->bl_dev = NULL;
|
||||
printk("radeonfb: Backlight registration failed\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
pdata->rinfo = rinfo;
|
||||
|
||||
/* Pardon me for that hack... maybe some day we can figure out in what
|
||||
* direction backlight should work on a given panel?
|
||||
*/
|
||||
pdata->negative =
|
||||
(rinfo->family != CHIP_FAMILY_RV200 &&
|
||||
rinfo->family != CHIP_FAMILY_RV250 &&
|
||||
rinfo->family != CHIP_FAMILY_RV280 &&
|
||||
rinfo->family != CHIP_FAMILY_RV350);
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
pdata->negative = pdata->negative ||
|
||||
machine_is_compatible("PowerBook4,3") ||
|
||||
machine_is_compatible("PowerBook6,3") ||
|
||||
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);
|
||||
|
||||
up(&bd->sem);
|
||||
bd->props->brightness = radeon_bl_data.max_brightness;
|
||||
bd->props->power = FB_BLANK_UNBLANK;
|
||||
bd->props->update_status(bd);
|
||||
down(&bd->sem);
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
mutex_lock(&pmac_backlight_mutex);
|
||||
if (!pmac_backlight)
|
||||
pmac_backlight = bd;
|
||||
mutex_unlock(&pmac_backlight_mutex);
|
||||
#endif
|
||||
|
||||
printk("radeonfb: Backlight initialized (%s)\n", name);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
kfree(pdata);
|
||||
return;
|
||||
}
|
||||
|
||||
void radeonfb_bl_exit(struct radeonfb_info *rinfo)
|
||||
{
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
mutex_lock(&pmac_backlight_mutex);
|
||||
#endif
|
||||
|
||||
mutex_lock(&rinfo->info->bl_mutex);
|
||||
if (rinfo->info->bl_dev) {
|
||||
struct radeon_bl_privdata *pdata;
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
if (pmac_backlight == rinfo->info->bl_dev)
|
||||
pmac_backlight = NULL;
|
||||
#endif
|
||||
|
||||
pdata = class_get_devdata(&rinfo->info->bl_dev->class_dev);
|
||||
backlight_device_unregister(rinfo->info->bl_dev);
|
||||
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
|
||||
}
|
|
@ -78,10 +78,6 @@
|
|||
#include <asm/pci-bridge.h>
|
||||
#include "../macmodes.h"
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
#include <asm/backlight.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BOOTX_TEXT
|
||||
#include <asm/btext.h>
|
||||
#endif
|
||||
|
@ -277,20 +273,6 @@ static int nomtrr = 0;
|
|||
* prototypes
|
||||
*/
|
||||
|
||||
|
||||
#ifdef CONFIG_PPC_OF
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
static int radeon_set_backlight_enable(int on, int level, void *data);
|
||||
static int radeon_set_backlight_level(int level, void *data);
|
||||
static struct backlight_controller radeon_backlight_controller = {
|
||||
radeon_set_backlight_enable,
|
||||
radeon_set_backlight_level
|
||||
};
|
||||
#endif /* CONFIG_PMAC_BACKLIGHT */
|
||||
|
||||
#endif /* CONFIG_PPC_OF */
|
||||
|
||||
static void radeon_unmap_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev)
|
||||
{
|
||||
if (!rinfo->bios_seg)
|
||||
|
@ -1913,116 +1895,6 @@ static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
|
||||
/* TODO: Dbl check these tables, we don't go up to full ON backlight
|
||||
* in these, possibly because we noticed MacOS doesn't, but I'd prefer
|
||||
* having some more official numbers from ATI
|
||||
*/
|
||||
static int backlight_conv_m6[] = {
|
||||
0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
|
||||
0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
|
||||
};
|
||||
static int backlight_conv_m7[] = {
|
||||
0x00, 0x3f, 0x4a, 0x55, 0x60, 0x6b, 0x76, 0x81,
|
||||
0x8c, 0x97, 0xa2, 0xad, 0xb8, 0xc3, 0xce, 0xd9
|
||||
};
|
||||
|
||||
#define BACKLIGHT_LVDS_OFF
|
||||
#undef BACKLIGHT_DAC_OFF
|
||||
|
||||
/* We turn off the LCD completely instead of just dimming the backlight.
|
||||
* This provides some greater power saving and the display is useless
|
||||
* without backlight anyway.
|
||||
*/
|
||||
static int radeon_set_backlight_enable(int on, int level, void *data)
|
||||
{
|
||||
struct radeonfb_info *rinfo = (struct radeonfb_info *)data;
|
||||
u32 lvds_gen_cntl, tmpPixclksCntl;
|
||||
int* conv_table;
|
||||
|
||||
if (rinfo->mon1_type != MT_LCD)
|
||||
return 0;
|
||||
|
||||
/* Pardon me for that hack... maybe some day we can figure
|
||||
* out in what direction backlight should work on a given
|
||||
* panel ?
|
||||
*/
|
||||
if ((rinfo->family == CHIP_FAMILY_RV200 ||
|
||||
rinfo->family == CHIP_FAMILY_RV250 ||
|
||||
rinfo->family == CHIP_FAMILY_RV280 ||
|
||||
rinfo->family == CHIP_FAMILY_RV350) &&
|
||||
!machine_is_compatible("PowerBook4,3") &&
|
||||
!machine_is_compatible("PowerBook6,3") &&
|
||||
!machine_is_compatible("PowerBook6,5"))
|
||||
conv_table = backlight_conv_m7;
|
||||
else
|
||||
conv_table = backlight_conv_m6;
|
||||
|
||||
del_timer_sync(&rinfo->lvds_timer);
|
||||
radeon_engine_idle();
|
||||
|
||||
lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
|
||||
if (on && (level > BACKLIGHT_OFF)) {
|
||||
lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
|
||||
if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) {
|
||||
lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON);
|
||||
lvds_gen_cntl |= LVDS_BLON | LVDS_EN;
|
||||
OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
|
||||
lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
|
||||
lvds_gen_cntl |= (conv_table[level] <<
|
||||
LVDS_BL_MOD_LEVEL_SHIFT);
|
||||
lvds_gen_cntl |= LVDS_ON;
|
||||
lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN);
|
||||
rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
|
||||
mod_timer(&rinfo->lvds_timer,
|
||||
jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
|
||||
} else {
|
||||
lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
|
||||
lvds_gen_cntl |= (conv_table[level] <<
|
||||
LVDS_BL_MOD_LEVEL_SHIFT);
|
||||
OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
|
||||
}
|
||||
rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
|
||||
rinfo->init_state.lvds_gen_cntl |= rinfo->pending_lvds_gen_cntl
|
||||
& LVDS_STATE_MASK;
|
||||
} else {
|
||||
/* Asic bug, when turning off LVDS_ON, we have to make sure
|
||||
RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
|
||||
*/
|
||||
tmpPixclksCntl = INPLL(PIXCLKS_CNTL);
|
||||
if (rinfo->is_mobility || rinfo->is_IGP)
|
||||
OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
|
||||
lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN);
|
||||
lvds_gen_cntl |= (conv_table[0] <<
|
||||
LVDS_BL_MOD_LEVEL_SHIFT);
|
||||
lvds_gen_cntl |= LVDS_DISPLAY_DIS;
|
||||
OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
|
||||
udelay(100);
|
||||
lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN);
|
||||
OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
|
||||
lvds_gen_cntl &= ~(LVDS_DIGON);
|
||||
rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
|
||||
mod_timer(&rinfo->lvds_timer,
|
||||
jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
|
||||
if (rinfo->is_mobility || rinfo->is_IGP)
|
||||
OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl);
|
||||
}
|
||||
rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
|
||||
rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int radeon_set_backlight_level(int level, void *data)
|
||||
{
|
||||
return radeon_set_backlight_enable(1, level, data);
|
||||
}
|
||||
#endif /* CONFIG_PMAC_BACKLIGHT */
|
||||
|
||||
|
||||
/*
|
||||
* This reconfigure the card's internal memory map. In theory, we'd like
|
||||
* to setup the card's memory at the same address as it's PCI bus address,
|
||||
|
@ -2477,14 +2349,7 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
|
|||
MTRR_TYPE_WRCOMB, 1);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
if (rinfo->mon1_type == MT_LCD) {
|
||||
register_backlight_controller(&radeon_backlight_controller,
|
||||
rinfo, "ati");
|
||||
register_backlight_controller(&radeon_backlight_controller,
|
||||
rinfo, "mnca");
|
||||
}
|
||||
#endif
|
||||
radeonfb_bl_init(rinfo);
|
||||
|
||||
printk ("radeonfb (%s): %s\n", pci_name(rinfo->pdev), rinfo->name);
|
||||
|
||||
|
@ -2529,6 +2394,7 @@ static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev)
|
|||
if (!rinfo)
|
||||
return;
|
||||
|
||||
radeonfb_bl_exit(rinfo);
|
||||
radeonfb_pm_exit(rinfo);
|
||||
|
||||
if (rinfo->mon1_EDID)
|
||||
|
|
|
@ -625,4 +625,13 @@ extern int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_
|
|||
extern void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode,
|
||||
int reg_only);
|
||||
|
||||
/* Backlight functions */
|
||||
#ifdef CONFIG_FB_RADEON_BACKLIGHT
|
||||
extern void radeonfb_bl_init(struct radeonfb_info *rinfo);
|
||||
extern void radeonfb_bl_exit(struct radeonfb_info *rinfo);
|
||||
#else
|
||||
static inline void radeonfb_bl_init(struct radeonfb_info *rinfo) {}
|
||||
static inline void radeonfb_bl_exit(struct radeonfb_info *rinfo) {}
|
||||
#endif
|
||||
|
||||
#endif /* __RADEONFB_H__ */
|
||||
|
|
|
@ -148,9 +148,24 @@ static int chipsfb_set_par(struct fb_info *info)
|
|||
static int chipsfb_blank(int blank, struct fb_info *info)
|
||||
{
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
// used to disable backlight only for blank > 1, but it seems
|
||||
// useful at blank = 1 too (saves battery, extends backlight life)
|
||||
set_backlight_enable(!blank);
|
||||
mutex_lock(&pmac_backlight_mutex);
|
||||
|
||||
if (pmac_backlight) {
|
||||
down(&pmac_backlight->sem);
|
||||
|
||||
/* used to disable backlight only for blank > 1, but it seems
|
||||
* useful at blank = 1 too (saves battery, extends backlight
|
||||
* life)
|
||||
*/
|
||||
if (blank)
|
||||
pmac_backlight->props->power = FB_BLANK_POWERDOWN;
|
||||
else
|
||||
pmac_backlight->props->power = FB_BLANK_UNBLANK;
|
||||
pmac_backlight->props->update_status(pmac_backlight);
|
||||
up(&pmac_backlight->sem);
|
||||
}
|
||||
|
||||
mutex_unlock(&pmac_backlight_mutex);
|
||||
#endif /* CONFIG_PMAC_BACKLIGHT */
|
||||
|
||||
return 1; /* get fb_blank to set the colormap to all black */
|
||||
|
@ -401,7 +416,14 @@ chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
|
|||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
/* turn on the backlight */
|
||||
set_backlight_enable(1);
|
||||
mutex_lock(&pmac_backlight_mutex);
|
||||
if (pmac_backlight) {
|
||||
down(&pmac_backlight->sem);
|
||||
pmac_backlight->props->power = FB_BLANK_UNBLANK;
|
||||
pmac_backlight->props->update_status(pmac_backlight);
|
||||
up(&pmac_backlight->sem);
|
||||
}
|
||||
mutex_unlock(&pmac_backlight_mutex);
|
||||
#endif /* CONFIG_PMAC_BACKLIGHT */
|
||||
|
||||
#ifdef CONFIG_PPC
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
/**
|
||||
* framebuffer_alloc - creates a new frame buffer info structure
|
||||
|
@ -55,6 +56,10 @@ struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
|
|||
|
||||
info->device = dev;
|
||||
|
||||
#ifdef CONFIG_FB_BACKLIGHT
|
||||
mutex_init(&info->bl_mutex);
|
||||
#endif
|
||||
|
||||
return info;
|
||||
#undef PADDING
|
||||
#undef BYTES_PER_LONG
|
||||
|
@ -414,6 +419,65 @@ static ssize_t show_fbstate(struct class_device *class_device, char *buf)
|
|||
return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->state);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FB_BACKLIGHT
|
||||
static ssize_t store_bl_curve(struct class_device *class_device,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct fb_info *fb_info = class_get_devdata(class_device);
|
||||
u8 tmp_curve[FB_BACKLIGHT_LEVELS];
|
||||
unsigned int i;
|
||||
|
||||
if (count != (FB_BACKLIGHT_LEVELS / 8 * 24))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < (FB_BACKLIGHT_LEVELS / 8); ++i)
|
||||
if (sscanf(&buf[i * 24],
|
||||
"%2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx\n",
|
||||
&tmp_curve[i * 8 + 0],
|
||||
&tmp_curve[i * 8 + 1],
|
||||
&tmp_curve[i * 8 + 2],
|
||||
&tmp_curve[i * 8 + 3],
|
||||
&tmp_curve[i * 8 + 4],
|
||||
&tmp_curve[i * 8 + 5],
|
||||
&tmp_curve[i * 8 + 6],
|
||||
&tmp_curve[i * 8 + 7]) != 8)
|
||||
return -EINVAL;
|
||||
|
||||
/* If there has been an error in the input data, we won't
|
||||
* reach this loop.
|
||||
*/
|
||||
mutex_lock(&fb_info->bl_mutex);
|
||||
for (i = 0; i < FB_BACKLIGHT_LEVELS; ++i)
|
||||
fb_info->bl_curve[i] = tmp_curve[i];
|
||||
mutex_unlock(&fb_info->bl_mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_bl_curve(struct class_device *class_device, char *buf)
|
||||
{
|
||||
struct fb_info *fb_info = class_get_devdata(class_device);
|
||||
ssize_t len = 0;
|
||||
unsigned int i;
|
||||
|
||||
mutex_lock(&fb_info->bl_mutex);
|
||||
for (i = 0; i < FB_BACKLIGHT_LEVELS; i += 8)
|
||||
len += snprintf(&buf[len], PAGE_SIZE,
|
||||
"%02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
fb_info->bl_curve[i + 0],
|
||||
fb_info->bl_curve[i + 1],
|
||||
fb_info->bl_curve[i + 2],
|
||||
fb_info->bl_curve[i + 3],
|
||||
fb_info->bl_curve[i + 4],
|
||||
fb_info->bl_curve[i + 5],
|
||||
fb_info->bl_curve[i + 6],
|
||||
fb_info->bl_curve[i + 7]);
|
||||
mutex_unlock(&fb_info->bl_mutex);
|
||||
|
||||
return len;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* When cmap is added back in it should be a binary attribute
|
||||
* not a text one. Consideration should also be given to converting
|
||||
* fbdev to use configfs instead of sysfs */
|
||||
|
@ -432,6 +496,9 @@ static struct class_device_attribute class_device_attrs[] = {
|
|||
__ATTR(con_rotate, S_IRUGO|S_IWUSR, show_con_rotate, store_con_rotate),
|
||||
__ATTR(con_rotate_all, S_IWUSR, NULL, store_con_rotate_all),
|
||||
__ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate),
|
||||
#ifdef CONFIG_FB_BACKLIGHT
|
||||
__ATTR(bl_curve, S_IRUGO|S_IWUSR, show_bl_curve, store_bl_curve),
|
||||
#endif
|
||||
};
|
||||
|
||||
int fb_init_class_device(struct fb_info *fb_info)
|
||||
|
@ -454,4 +521,25 @@ void fb_cleanup_class_device(struct fb_info *fb_info)
|
|||
&class_device_attrs[i]);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FB_BACKLIGHT
|
||||
/* This function generates a linear backlight curve
|
||||
*
|
||||
* 0: off
|
||||
* 1-7: min
|
||||
* 8-127: linear from min to max
|
||||
*/
|
||||
void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max)
|
||||
{
|
||||
unsigned int i, flat, count, range = (max - min);
|
||||
|
||||
fb_info->bl_curve[0] = off;
|
||||
|
||||
for (flat = 1; flat < (FB_BACKLIGHT_LEVELS / 16); ++flat)
|
||||
fb_info->bl_curve[flat] = min;
|
||||
|
||||
count = FB_BACKLIGHT_LEVELS * 15 / 16;
|
||||
for (i = 0; i < count; ++i)
|
||||
fb_info->bl_curve[flat + i] = min + (range * (i + 1) / count);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fb_bl_default_curve);
|
||||
#endif
|
||||
|
|
|
@ -7,6 +7,7 @@ obj-$(CONFIG_FB_NVIDIA) += nvidiafb.o
|
|||
nvidiafb-y := nvidia.o nv_hw.o nv_setup.o \
|
||||
nv_accel.o
|
||||
nvidiafb-$(CONFIG_FB_NVIDIA_I2C) += nv_i2c.o
|
||||
nvidiafb-$(CONFIG_FB_NVIDIA_BACKLIGHT) += nv_backlight.o
|
||||
nvidiafb-$(CONFIG_PPC_OF) += nv_of.o
|
||||
|
||||
nvidiafb-objs := $(nvidiafb-y)
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* Backlight code for nVidia based graphic cards
|
||||
*
|
||||
* Copyright 2004 Antonino Daplas <adaplas@pol.net>
|
||||
* Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/pci.h>
|
||||
#include "nv_local.h"
|
||||
#include "nv_type.h"
|
||||
#include "nv_proto.h"
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
#include <asm/backlight.h>
|
||||
#include <asm/machdep.h>
|
||||
#endif
|
||||
|
||||
/* We do not have any information about which values are allowed, thus
|
||||
* we used safe values.
|
||||
*/
|
||||
#define MIN_LEVEL 0x158
|
||||
#define MAX_LEVEL 0x534
|
||||
|
||||
static struct backlight_properties nvidia_bl_data;
|
||||
|
||||
static int nvidia_bl_get_level_brightness(struct nvidia_par *par,
|
||||
int level)
|
||||
{
|
||||
struct fb_info *info = pci_get_drvdata(par->pci_dev);
|
||||
int nlevel;
|
||||
|
||||
/* Get and convert the value */
|
||||
mutex_lock(&info->bl_mutex);
|
||||
nlevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
|
||||
mutex_unlock(&info->bl_mutex);
|
||||
|
||||
if (nlevel < 0)
|
||||
nlevel = 0;
|
||||
else if (nlevel < MIN_LEVEL)
|
||||
nlevel = MIN_LEVEL;
|
||||
else if (nlevel > MAX_LEVEL)
|
||||
nlevel = MAX_LEVEL;
|
||||
|
||||
return nlevel;
|
||||
}
|
||||
|
||||
static int nvidia_bl_update_status(struct backlight_device *bd)
|
||||
{
|
||||
struct nvidia_par *par = class_get_devdata(&bd->class_dev);
|
||||
u32 tmp_pcrt, tmp_pmc, fpcontrol;
|
||||
int level;
|
||||
|
||||
if (!par->FlatPanel)
|
||||
return 0;
|
||||
|
||||
if (bd->props->power != FB_BLANK_UNBLANK ||
|
||||
bd->props->fb_blank != FB_BLANK_UNBLANK)
|
||||
level = 0;
|
||||
else
|
||||
level = bd->props->brightness;
|
||||
|
||||
tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF;
|
||||
tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC;
|
||||
fpcontrol = NV_RD32(par->PRAMDAC, 0x0848) & 0xCFFFFFCC;
|
||||
|
||||
if (level > 0) {
|
||||
tmp_pcrt |= 0x1;
|
||||
tmp_pmc |= (1 << 31); /* backlight bit */
|
||||
tmp_pmc |= nvidia_bl_get_level_brightness(par, level) << 16;
|
||||
fpcontrol |= par->fpSyncs;
|
||||
} else
|
||||
fpcontrol |= 0x20000022;
|
||||
|
||||
NV_WR32(par->PCRTC0, 0x081C, tmp_pcrt);
|
||||
NV_WR32(par->PMC, 0x10F0, tmp_pmc);
|
||||
NV_WR32(par->PRAMDAC, 0x848, fpcontrol);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nvidia_bl_get_brightness(struct backlight_device *bd)
|
||||
{
|
||||
return bd->props->brightness;
|
||||
}
|
||||
|
||||
static struct backlight_properties nvidia_bl_data = {
|
||||
.owner = THIS_MODULE,
|
||||
.get_brightness = nvidia_bl_get_brightness,
|
||||
.update_status = nvidia_bl_update_status,
|
||||
.max_brightness = (FB_BACKLIGHT_LEVELS - 1),
|
||||
};
|
||||
|
||||
void nvidia_bl_init(struct nvidia_par *par)
|
||||
{
|
||||
struct fb_info *info = pci_get_drvdata(par->pci_dev);
|
||||
struct backlight_device *bd;
|
||||
char name[12];
|
||||
|
||||
if (!par->FlatPanel)
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
if (!machine_is(powermac) ||
|
||||
!pmac_has_backlight_type("mnca"))
|
||||
return;
|
||||
#endif
|
||||
|
||||
snprintf(name, sizeof(name), "nvidiabl%d", info->node);
|
||||
|
||||
bd = backlight_device_register(name, par, &nvidia_bl_data);
|
||||
if (IS_ERR(bd)) {
|
||||
info->bl_dev = NULL;
|
||||
printk("nvidia: Backlight registration failed\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
mutex_lock(&info->bl_mutex);
|
||||
info->bl_dev = bd;
|
||||
fb_bl_default_curve(info, 0,
|
||||
0x158 * FB_BACKLIGHT_MAX / MAX_LEVEL,
|
||||
0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL);
|
||||
mutex_unlock(&info->bl_mutex);
|
||||
|
||||
up(&bd->sem);
|
||||
bd->props->brightness = nvidia_bl_data.max_brightness;
|
||||
bd->props->power = FB_BLANK_UNBLANK;
|
||||
bd->props->update_status(bd);
|
||||
down(&bd->sem);
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
mutex_lock(&pmac_backlight_mutex);
|
||||
if (!pmac_backlight)
|
||||
pmac_backlight = bd;
|
||||
mutex_unlock(&pmac_backlight_mutex);
|
||||
#endif
|
||||
|
||||
printk("nvidia: Backlight initialized (%s)\n", name);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
return;
|
||||
}
|
||||
|
||||
void nvidia_bl_exit(struct nvidia_par *par)
|
||||
{
|
||||
struct fb_info *info = pci_get_drvdata(par->pci_dev);
|
||||
|
||||
#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)
|
||||
pmac_backlight = NULL;
|
||||
#endif
|
||||
|
||||
backlight_device_unregister(info->bl_dev);
|
||||
|
||||
printk("nvidia: Backlight unloaded\n");
|
||||
}
|
||||
mutex_unlock(&info->bl_mutex);
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
mutex_unlock(&pmac_backlight_mutex);
|
||||
#endif
|
||||
}
|
|
@ -63,4 +63,14 @@ extern void nvidiafb_imageblit(struct fb_info *info,
|
|||
const struct fb_image *image);
|
||||
extern int nvidiafb_sync(struct fb_info *info);
|
||||
extern u8 byte_rev[256];
|
||||
|
||||
/* in nv_backlight.h */
|
||||
#ifdef CONFIG_FB_NVIDIA_BACKLIGHT
|
||||
extern void nvidia_bl_init(struct nvidia_par *par);
|
||||
extern void nvidia_bl_exit(struct nvidia_par *par);
|
||||
#else
|
||||
static inline void nvidia_bl_init(struct nvidia_par *par) {}
|
||||
static inline void nvidia_bl_exit(struct nvidia_par *par) {}
|
||||
#endif
|
||||
|
||||
#endif /* __NV_PROTO_H__ */
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/backlight.h>
|
||||
#ifdef CONFIG_MTRR
|
||||
#include <asm/mtrr.h>
|
||||
#endif
|
||||
|
@ -29,10 +30,6 @@
|
|||
#include <asm/prom.h>
|
||||
#include <asm/pci-bridge.h>
|
||||
#endif
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/backlight.h>
|
||||
#endif
|
||||
|
||||
#include "nv_local.h"
|
||||
#include "nv_type.h"
|
||||
|
@ -470,75 +467,6 @@ static struct fb_var_screeninfo __devinitdata nvidiafb_default_var = {
|
|||
.vmode = FB_VMODE_NONINTERLACED
|
||||
};
|
||||
|
||||
/*
|
||||
* Backlight control
|
||||
*/
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
|
||||
static int nvidia_backlight_levels[] = {
|
||||
0x158,
|
||||
0x192,
|
||||
0x1c6,
|
||||
0x200,
|
||||
0x234,
|
||||
0x268,
|
||||
0x2a2,
|
||||
0x2d6,
|
||||
0x310,
|
||||
0x344,
|
||||
0x378,
|
||||
0x3b2,
|
||||
0x3e6,
|
||||
0x41a,
|
||||
0x454,
|
||||
0x534,
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- *
|
||||
*
|
||||
* Backlight operations
|
||||
*
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
static int nvidia_set_backlight_enable(int on, int level, void *data)
|
||||
{
|
||||
struct nvidia_par *par = data;
|
||||
u32 tmp_pcrt, tmp_pmc, fpcontrol;
|
||||
|
||||
tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF;
|
||||
tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC;
|
||||
fpcontrol = NV_RD32(par->PRAMDAC, 0x0848) & 0xCFFFFFCC;
|
||||
|
||||
if (on && (level > BACKLIGHT_OFF)) {
|
||||
tmp_pcrt |= 0x1;
|
||||
tmp_pmc |= (1 << 31); // backlight bit
|
||||
tmp_pmc |= nvidia_backlight_levels[level - 1] << 16;
|
||||
}
|
||||
|
||||
if (on)
|
||||
fpcontrol |= par->fpSyncs;
|
||||
else
|
||||
fpcontrol |= 0x20000022;
|
||||
|
||||
NV_WR32(par->PCRTC0, 0x081C, tmp_pcrt);
|
||||
NV_WR32(par->PMC, 0x10F0, tmp_pmc);
|
||||
NV_WR32(par->PRAMDAC, 0x848, fpcontrol);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nvidia_set_backlight_level(int level, void *data)
|
||||
{
|
||||
return nvidia_set_backlight_enable(1, level, data);
|
||||
}
|
||||
|
||||
static struct backlight_controller nvidia_backlight_controller = {
|
||||
nvidia_set_backlight_enable,
|
||||
nvidia_set_backlight_level
|
||||
};
|
||||
|
||||
#endif /* CONFIG_PMAC_BACKLIGHT */
|
||||
|
||||
static void nvidiafb_load_cursor_image(struct nvidia_par *par, u8 * data8,
|
||||
u16 bg, u16 fg, u32 w, u32 h)
|
||||
{
|
||||
|
@ -1355,10 +1283,15 @@ static int nvidiafb_blank(int blank, struct fb_info *info)
|
|||
NVWriteSeq(par, 0x01, tmp);
|
||||
NVWriteCrtc(par, 0x1a, vesa);
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
if (par->FlatPanel && machine_is(powermac)) {
|
||||
set_backlight_enable(!blank);
|
||||
#ifdef CONFIG_FB_NVIDIA_BACKLIGHT
|
||||
mutex_lock(&info->bl_mutex);
|
||||
if (info->bl_dev) {
|
||||
down(&info->bl_dev->sem);
|
||||
info->bl_dev->props->power = blank;
|
||||
info->bl_dev->props->update_status(info->bl_dev);
|
||||
up(&info->bl_dev->sem);
|
||||
}
|
||||
mutex_unlock(&info->bl_mutex);
|
||||
#endif
|
||||
|
||||
NVTRACE_LEAVE();
|
||||
|
@ -1741,11 +1674,9 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd,
|
|||
"PCI nVidia %s framebuffer (%dMB @ 0x%lX)\n",
|
||||
info->fix.id,
|
||||
par->FbMapSize / (1024 * 1024), info->fix.smem_start);
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
if (par->FlatPanel && machine_is(powermac))
|
||||
register_backlight_controller(&nvidia_backlight_controller,
|
||||
par, "mnca");
|
||||
#endif
|
||||
|
||||
nvidia_bl_init(par);
|
||||
|
||||
NVTRACE_LEAVE();
|
||||
return 0;
|
||||
|
||||
|
@ -1775,6 +1706,8 @@ static void __exit nvidiafb_remove(struct pci_dev *pd)
|
|||
|
||||
NVTRACE_ENTER();
|
||||
|
||||
nvidia_bl_exit(par);
|
||||
|
||||
unregister_framebuffer(info);
|
||||
#ifdef CONFIG_MTRR
|
||||
if (par->mtrr.vram_valid)
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include <linux/fb.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/backlight.h>
|
||||
#ifdef CONFIG_MTRR
|
||||
#include <asm/mtrr.h>
|
||||
#endif
|
||||
|
@ -272,34 +273,154 @@ static const struct riva_regs reg_template = {
|
|||
/*
|
||||
* Backlight control
|
||||
*/
|
||||
#ifdef CONFIG_FB_RIVA_BACKLIGHT
|
||||
/* We do not have any information about which values are allowed, thus
|
||||
* we used safe values.
|
||||
*/
|
||||
#define MIN_LEVEL 0x158
|
||||
#define MAX_LEVEL 0x534
|
||||
|
||||
static struct backlight_properties riva_bl_data;
|
||||
|
||||
static int riva_bl_get_level_brightness(struct riva_par *par,
|
||||
int level)
|
||||
{
|
||||
struct fb_info *info = pci_get_drvdata(par->pdev);
|
||||
int nlevel;
|
||||
|
||||
/* Get and convert the value */
|
||||
mutex_lock(&info->bl_mutex);
|
||||
nlevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
|
||||
mutex_unlock(&info->bl_mutex);
|
||||
|
||||
if (nlevel < 0)
|
||||
nlevel = 0;
|
||||
else if (nlevel < MIN_LEVEL)
|
||||
nlevel = MIN_LEVEL;
|
||||
else if (nlevel > MAX_LEVEL)
|
||||
nlevel = MAX_LEVEL;
|
||||
|
||||
return nlevel;
|
||||
}
|
||||
|
||||
static int riva_bl_update_status(struct backlight_device *bd)
|
||||
{
|
||||
struct riva_par *par = class_get_devdata(&bd->class_dev);
|
||||
U032 tmp_pcrt, tmp_pmc;
|
||||
int level;
|
||||
|
||||
if (bd->props->power != FB_BLANK_UNBLANK ||
|
||||
bd->props->fb_blank != FB_BLANK_UNBLANK)
|
||||
level = 0;
|
||||
else
|
||||
level = bd->props->brightness;
|
||||
|
||||
tmp_pmc = par->riva.PMC[0x10F0/4] & 0x0000FFFF;
|
||||
tmp_pcrt = par->riva.PCRTC0[0x081C/4] & 0xFFFFFFFC;
|
||||
if(level > 0) {
|
||||
tmp_pcrt |= 0x1;
|
||||
tmp_pmc |= (1 << 31); /* backlight bit */
|
||||
tmp_pmc |= riva_bl_get_level_brightness(par, level) << 16; /* level */
|
||||
}
|
||||
par->riva.PCRTC0[0x081C/4] = tmp_pcrt;
|
||||
par->riva.PMC[0x10F0/4] = tmp_pmc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int riva_bl_get_brightness(struct backlight_device *bd)
|
||||
{
|
||||
return bd->props->brightness;
|
||||
}
|
||||
|
||||
static struct backlight_properties riva_bl_data = {
|
||||
.owner = THIS_MODULE,
|
||||
.get_brightness = riva_bl_get_brightness,
|
||||
.update_status = riva_bl_update_status,
|
||||
.max_brightness = (FB_BACKLIGHT_LEVELS - 1),
|
||||
};
|
||||
|
||||
static void riva_bl_init(struct riva_par *par)
|
||||
{
|
||||
struct fb_info *info = pci_get_drvdata(par->pdev);
|
||||
struct backlight_device *bd;
|
||||
char name[12];
|
||||
|
||||
if (!par->FlatPanel)
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
if (!machine_is(powermac) ||
|
||||
!pmac_has_backlight_type("mnca"))
|
||||
return;
|
||||
#endif
|
||||
|
||||
static int riva_backlight_levels[] = {
|
||||
0x158,
|
||||
0x192,
|
||||
0x1c6,
|
||||
0x200,
|
||||
0x234,
|
||||
0x268,
|
||||
0x2a2,
|
||||
0x2d6,
|
||||
0x310,
|
||||
0x344,
|
||||
0x378,
|
||||
0x3b2,
|
||||
0x3e6,
|
||||
0x41a,
|
||||
0x454,
|
||||
0x534,
|
||||
};
|
||||
snprintf(name, sizeof(name), "rivabl%d", info->node);
|
||||
|
||||
static int riva_set_backlight_enable(int on, int level, void *data);
|
||||
static int riva_set_backlight_level(int level, void *data);
|
||||
static struct backlight_controller riva_backlight_controller = {
|
||||
riva_set_backlight_enable,
|
||||
riva_set_backlight_level
|
||||
};
|
||||
#endif /* CONFIG_PMAC_BACKLIGHT */
|
||||
bd = backlight_device_register(name, par, &riva_bl_data);
|
||||
if (IS_ERR(bd)) {
|
||||
info->bl_dev = NULL;
|
||||
printk("riva: Backlight registration failed\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
mutex_lock(&info->bl_mutex);
|
||||
info->bl_dev = bd;
|
||||
fb_bl_default_curve(info, 0,
|
||||
0x158 * FB_BACKLIGHT_MAX / MAX_LEVEL,
|
||||
0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL);
|
||||
mutex_unlock(&info->bl_mutex);
|
||||
|
||||
up(&bd->sem);
|
||||
bd->props->brightness = riva_bl_data.max_brightness;
|
||||
bd->props->power = FB_BLANK_UNBLANK;
|
||||
bd->props->update_status(bd);
|
||||
down(&bd->sem);
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
mutex_lock(&pmac_backlight_mutex);
|
||||
if (!pmac_backlight)
|
||||
pmac_backlight = bd;
|
||||
mutex_unlock(&pmac_backlight_mutex);
|
||||
#endif
|
||||
|
||||
printk("riva: Backlight initialized (%s)\n", name);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
return;
|
||||
}
|
||||
|
||||
static void riva_bl_exit(struct riva_par *par)
|
||||
{
|
||||
struct fb_info *info = pci_get_drvdata(par->pdev);
|
||||
|
||||
#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)
|
||||
pmac_backlight = NULL;
|
||||
#endif
|
||||
|
||||
backlight_device_unregister(info->bl_dev);
|
||||
|
||||
printk("riva: Backlight unloaded\n");
|
||||
}
|
||||
mutex_unlock(&info->bl_mutex);
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
mutex_unlock(&pmac_backlight_mutex);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static inline void riva_bl_init(struct riva_par *par) {}
|
||||
static inline void riva_bl_exit(struct riva_par *par) {}
|
||||
#endif /* CONFIG_FB_RIVA_BACKLIGHT */
|
||||
|
||||
/* ------------------------------------------------------------------------- *
|
||||
*
|
||||
|
@ -971,36 +1092,6 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
|
|||
return rc;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- *
|
||||
*
|
||||
* Backlight operations
|
||||
*
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
static int riva_set_backlight_enable(int on, int level, void *data)
|
||||
{
|
||||
struct riva_par *par = data;
|
||||
U032 tmp_pcrt, tmp_pmc;
|
||||
|
||||
tmp_pmc = par->riva.PMC[0x10F0/4] & 0x0000FFFF;
|
||||
tmp_pcrt = par->riva.PCRTC0[0x081C/4] & 0xFFFFFFFC;
|
||||
if(on && (level > BACKLIGHT_OFF)) {
|
||||
tmp_pcrt |= 0x1;
|
||||
tmp_pmc |= (1 << 31); // backlight bit
|
||||
tmp_pmc |= riva_backlight_levels[level-1] << 16; // level
|
||||
}
|
||||
par->riva.PCRTC0[0x081C/4] = tmp_pcrt;
|
||||
par->riva.PMC[0x10F0/4] = tmp_pmc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int riva_set_backlight_level(int level, void *data)
|
||||
{
|
||||
return riva_set_backlight_enable(1, level, data);
|
||||
}
|
||||
#endif /* CONFIG_PMAC_BACKLIGHT */
|
||||
|
||||
/* ------------------------------------------------------------------------- *
|
||||
*
|
||||
* framebuffer operations
|
||||
|
@ -1247,10 +1338,15 @@ static int rivafb_blank(int blank, struct fb_info *info)
|
|||
SEQout(par, 0x01, tmp);
|
||||
CRTCout(par, 0x1a, vesa);
|
||||
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
if ( par->FlatPanel && machine_is(powermac)) {
|
||||
set_backlight_enable(!blank);
|
||||
#ifdef CONFIG_FB_RIVA_BACKLIGHT
|
||||
mutex_lock(&info->bl_mutex);
|
||||
if (info->bl_dev) {
|
||||
down(&info->bl_dev->sem);
|
||||
info->bl_dev->props->power = blank;
|
||||
info->bl_dev->props->update_status(info->bl_dev);
|
||||
up(&info->bl_dev->sem);
|
||||
}
|
||||
mutex_unlock(&info->bl_mutex);
|
||||
#endif
|
||||
|
||||
NVTRACE_LEAVE();
|
||||
|
@ -2037,11 +2133,9 @@ static int __devinit rivafb_probe(struct pci_dev *pd,
|
|||
RIVAFB_VERSION,
|
||||
info->fix.smem_len / (1024 * 1024),
|
||||
info->fix.smem_start);
|
||||
#ifdef CONFIG_PMAC_BACKLIGHT
|
||||
if (default_par->FlatPanel && machine_is(powermac))
|
||||
register_backlight_controller(&riva_backlight_controller,
|
||||
default_par, "mnca");
|
||||
#endif
|
||||
|
||||
riva_bl_init(info->par);
|
||||
|
||||
NVTRACE_LEAVE();
|
||||
return 0;
|
||||
|
||||
|
@ -2074,6 +2168,8 @@ static void __exit rivafb_remove(struct pci_dev *pd)
|
|||
|
||||
NVTRACE_ENTER();
|
||||
|
||||
riva_bl_exit(par);
|
||||
|
||||
#ifdef CONFIG_FB_RIVA_I2C
|
||||
riva_delete_i2c_busses(par);
|
||||
kfree(par->EDID);
|
||||
|
|
|
@ -2,30 +2,30 @@
|
|||
* Routines for handling backlight control on PowerBooks
|
||||
*
|
||||
* For now, implementation resides in
|
||||
* arch/powerpc/platforms/powermac/pmac_support.c
|
||||
* arch/powerpc/platforms/powermac/backlight.c
|
||||
*
|
||||
*/
|
||||
#ifndef __ASM_POWERPC_BACKLIGHT_H
|
||||
#define __ASM_POWERPC_BACKLIGHT_H
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/* Abstract values */
|
||||
#define BACKLIGHT_OFF 0
|
||||
#define BACKLIGHT_MIN 1
|
||||
#define BACKLIGHT_MAX 0xf
|
||||
#include <linux/fb.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
struct backlight_controller {
|
||||
int (*set_enable)(int enable, int level, void *data);
|
||||
int (*set_level)(int level, void *data);
|
||||
};
|
||||
/* For locking instructions, see the implementation file */
|
||||
extern struct backlight_device *pmac_backlight;
|
||||
extern struct mutex pmac_backlight_mutex;
|
||||
|
||||
extern void register_backlight_controller(struct backlight_controller *ctrler, void *data, char *type);
|
||||
extern void unregister_backlight_controller(struct backlight_controller *ctrler, void *data);
|
||||
extern void pmac_backlight_calc_curve(struct fb_info*);
|
||||
extern int pmac_backlight_curve_lookup(struct fb_info *info, int value);
|
||||
|
||||
extern int set_backlight_enable(int enable);
|
||||
extern int get_backlight_enable(void);
|
||||
extern int set_backlight_level(int level);
|
||||
extern int get_backlight_level(void);
|
||||
extern int pmac_has_backlight_type(const char *type);
|
||||
|
||||
extern void pmac_backlight_key_up(void);
|
||||
extern void pmac_backlight_key_down(void);
|
||||
|
||||
extern int pmac_backlight_set_legacy_brightness(int brightness);
|
||||
extern int pmac_backlight_get_legacy_brightness(void);
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef _LINUX_FB_H
|
||||
#define _LINUX_FB_H
|
||||
|
||||
#include <linux/backlight.h>
|
||||
#include <asm/types.h>
|
||||
|
||||
/* Definitions of frame buffers */
|
||||
|
@ -366,6 +367,12 @@ struct fb_cursor {
|
|||
struct fb_image image; /* Cursor image */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_FB_BACKLIGHT
|
||||
/* Settings for the generic backlight code */
|
||||
#define FB_BACKLIGHT_LEVELS 128
|
||||
#define FB_BACKLIGHT_MAX 0xFF
|
||||
#endif
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/fs.h>
|
||||
|
@ -756,6 +763,21 @@ struct fb_info {
|
|||
struct fb_cmap cmap; /* Current cmap */
|
||||
struct list_head modelist; /* mode list */
|
||||
struct fb_videomode *mode; /* current mode */
|
||||
|
||||
#ifdef CONFIG_FB_BACKLIGHT
|
||||
/* Lock ordering:
|
||||
* bl_mutex (protects bl_dev and bl_curve)
|
||||
* bl_dev->sem (backlight class)
|
||||
*/
|
||||
struct mutex bl_mutex;
|
||||
|
||||
/* assigned backlight device */
|
||||
struct backlight_device *bl_dev;
|
||||
|
||||
/* Backlight level curve */
|
||||
u8 bl_curve[FB_BACKLIGHT_LEVELS];
|
||||
#endif
|
||||
|
||||
struct fb_ops *fbops;
|
||||
struct device *device;
|
||||
struct class_device *class_device; /* sysfs per device attrs */
|
||||
|
@ -895,6 +917,7 @@ extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev);
|
|||
extern void framebuffer_release(struct fb_info *info);
|
||||
extern int fb_init_class_device(struct fb_info *fb_info);
|
||||
extern void fb_cleanup_class_device(struct fb_info *head);
|
||||
extern void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max);
|
||||
|
||||
/* drivers/video/fbmon.c */
|
||||
#define FB_MAXTIMINGS 0
|
||||
|
|
|
@ -230,4 +230,8 @@ extern int pmu_battery_count;
|
|||
extern struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES];
|
||||
extern unsigned int pmu_power_flags;
|
||||
|
||||
/* Backlight */
|
||||
extern int disable_kernel_backlight;
|
||||
extern void pmu_backlight_init(struct device_node*);
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
|
Загрузка…
Ссылка в новой задаче