aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Hanselmann <linux-kernel@hansmi.ch>2006-06-25 08:47:08 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-25 13:00:59 -0400
commit5474c120aafe78ca54bf272f7a01107c42da2b21 (patch)
treec1b002a27703ce92c816bfb9844752186e33d403
parent17660bdd5c1f1a165273c1a59cb5b87670a81cc4 (diff)
[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>
-rw-r--r--arch/powerpc/kernel/traps.c15
-rw-r--r--arch/powerpc/platforms/powermac/backlight.c270
-rw-r--r--arch/powerpc/xmon/xmon.c3
-rw-r--r--drivers/macintosh/Kconfig19
-rw-r--r--drivers/macintosh/Makefile1
-rw-r--r--drivers/macintosh/adbhid.c28
-rw-r--r--drivers/macintosh/via-pmu-backlight.c150
-rw-r--r--drivers/macintosh/via-pmu.c120
-rw-r--r--drivers/video/Kconfig56
-rw-r--r--drivers/video/aty/Makefile1
-rw-r--r--drivers/video/aty/aty128fb.c322
-rw-r--r--drivers/video/aty/atyfb.h1
-rw-r--r--drivers/video/aty/atyfb_base.c178
-rw-r--r--drivers/video/aty/radeon_backlight.c247
-rw-r--r--drivers/video/aty/radeon_base.c140
-rw-r--r--drivers/video/aty/radeonfb.h9
-rw-r--r--drivers/video/chipsfb.c30
-rw-r--r--drivers/video/fbsysfs.c88
-rw-r--r--drivers/video/nvidia/Makefile3
-rw-r--r--drivers/video/nvidia/nv_backlight.c175
-rw-r--r--drivers/video/nvidia/nv_proto.h10
-rw-r--r--drivers/video/nvidia/nvidia.c95
-rw-r--r--drivers/video/riva/fbdev.c222
-rw-r--r--include/asm-powerpc/backlight.h30
-rw-r--r--include/linux/fb.h23
-rw-r--r--include/linux/pmu.h4
26 files changed, 1529 insertions, 711 deletions
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 91a6e04d9741..52f5659534f4 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -32,6 +32,7 @@
32#include <linux/delay.h> 32#include <linux/delay.h>
33#include <linux/kprobes.h> 33#include <linux/kprobes.h>
34#include <linux/kexec.h> 34#include <linux/kexec.h>
35#include <linux/backlight.h>
35 36
36#include <asm/kdebug.h> 37#include <asm/kdebug.h>
37#include <asm/pgtable.h> 38#include <asm/pgtable.h>
@@ -105,10 +106,18 @@ int die(const char *str, struct pt_regs *regs, long err)
105 spin_lock_irq(&die_lock); 106 spin_lock_irq(&die_lock);
106 bust_spinlocks(1); 107 bust_spinlocks(1);
107#ifdef CONFIG_PMAC_BACKLIGHT 108#ifdef CONFIG_PMAC_BACKLIGHT
108 if (machine_is(powermac)) { 109 mutex_lock(&pmac_backlight_mutex);
109 set_backlight_enable(1); 110 if (machine_is(powermac) && pmac_backlight) {
110 set_backlight_level(BACKLIGHT_MAX); 111 struct backlight_properties *props;
112
113 down(&pmac_backlight->sem);
114 props = pmac_backlight->props;
115 props->brightness = props->max_brightness;
116 props->power = FB_BLANK_UNBLANK;
117 props->update_status(pmac_backlight);
118 up(&pmac_backlight->sem);
111 } 119 }
120 mutex_unlock(&pmac_backlight_mutex);
112#endif 121#endif
113 printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter); 122 printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
114#ifdef CONFIG_PREEMPT 123#ifdef CONFIG_PREEMPT
diff --git a/arch/powerpc/platforms/powermac/backlight.c b/arch/powerpc/platforms/powermac/backlight.c
index 8be2f7d071f0..498b042e1837 100644
--- a/arch/powerpc/platforms/powermac/backlight.c
+++ b/arch/powerpc/platforms/powermac/backlight.c
@@ -3,200 +3,148 @@
3 * Contains support for the backlight. 3 * Contains support for the backlight.
4 * 4 *
5 * Copyright (C) 2000 Benjamin Herrenschmidt 5 * Copyright (C) 2000 Benjamin Herrenschmidt
6 * Copyright (C) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
6 * 7 *
7 */ 8 */
8 9
9#include <linux/config.h> 10#include <linux/config.h>
10#include <linux/kernel.h> 11#include <linux/kernel.h>
11#include <linux/module.h> 12#include <linux/fb.h>
12#include <linux/stddef.h> 13#include <linux/backlight.h>
13#include <linux/reboot.h>
14#include <linux/nvram.h>
15#include <linux/console.h>
16#include <asm/sections.h>
17#include <asm/ptrace.h>
18#include <asm/io.h>
19#include <asm/pgtable.h>
20#include <asm/system.h>
21#include <asm/prom.h> 14#include <asm/prom.h>
22#include <asm/machdep.h>
23#include <asm/nvram.h>
24#include <asm/backlight.h> 15#include <asm/backlight.h>
25 16
26#include <linux/adb.h> 17#define OLD_BACKLIGHT_MAX 15
27#include <linux/pmu.h>
28 18
29static struct backlight_controller *backlighter; 19/* Protect the pmac_backlight variable */
30static void* backlighter_data; 20DEFINE_MUTEX(pmac_backlight_mutex);
31static int backlight_autosave;
32static int backlight_level = BACKLIGHT_MAX;
33static int backlight_enabled = 1;
34static int backlight_req_level = -1;
35static int backlight_req_enable = -1;
36 21
37static void backlight_callback(void *); 22/* Main backlight storage
38static DECLARE_WORK(backlight_work, backlight_callback, NULL); 23 *
24 * Backlight drivers in this variable are required to have the "props"
25 * attribute set and to have an update_status function.
26 *
27 * We can only store one backlight here, but since Apple laptops have only one
28 * internal display, it doesn't matter. Other backlight drivers can be used
29 * independently.
30 *
31 * Lock ordering:
32 * pmac_backlight_mutex (global, main backlight)
33 * pmac_backlight->sem (backlight class)
34 */
35struct backlight_device *pmac_backlight;
39 36
40void register_backlight_controller(struct backlight_controller *ctrler, 37int pmac_has_backlight_type(const char *type)
41 void *data, char *type)
42{ 38{
43 struct device_node* bk_node; 39 struct device_node* bk_node = find_devices("backlight");
44 char *prop; 40
45 int valid = 0;
46
47 /* There's already a matching controller, bail out */
48 if (backlighter != NULL)
49 return;
50
51 bk_node = find_devices("backlight");
52
53#ifdef CONFIG_ADB_PMU
54 /* Special case for the old PowerBook since I can't test on it */
55 backlight_autosave = machine_is_compatible("AAPL,3400/2400")
56 || machine_is_compatible("AAPL,3500");
57 if ((backlight_autosave
58 || machine_is_compatible("AAPL,PowerBook1998")
59 || machine_is_compatible("PowerBook1,1"))
60 && !strcmp(type, "pmu"))
61 valid = 1;
62#endif
63 if (bk_node) { 41 if (bk_node) {
64 prop = get_property(bk_node, "backlight-control", NULL); 42 char *prop = get_property(bk_node, "backlight-control", NULL);
65 if (prop && !strncmp(prop, type, strlen(type))) 43 if (prop && strncmp(prop, type, strlen(type)) == 0)
66 valid = 1; 44 return 1;
67 }
68 if (!valid)
69 return;
70 backlighter = ctrler;
71 backlighter_data = data;
72
73 if (bk_node && !backlight_autosave)
74 prop = get_property(bk_node, "bklt", NULL);
75 else
76 prop = NULL;
77 if (prop) {
78 backlight_level = ((*prop)+1) >> 1;
79 if (backlight_level > BACKLIGHT_MAX)
80 backlight_level = BACKLIGHT_MAX;
81 } 45 }
82 46
83#ifdef CONFIG_ADB_PMU 47 return 0;
84 if (backlight_autosave) {
85 struct adb_request req;
86 pmu_request(&req, NULL, 2, 0xd9, 0);
87 while (!req.complete)
88 pmu_poll();
89 backlight_level = req.reply[0] >> 4;
90 }
91#endif
92 acquire_console_sem();
93 if (!backlighter->set_enable(1, backlight_level, data))
94 backlight_enabled = 1;
95 release_console_sem();
96
97 printk(KERN_INFO "Registered \"%s\" backlight controller,"
98 "level: %d/15\n", type, backlight_level);
99} 48}
100EXPORT_SYMBOL(register_backlight_controller);
101 49
102void unregister_backlight_controller(struct backlight_controller 50int pmac_backlight_curve_lookup(struct fb_info *info, int value)
103 *ctrler, void *data)
104{ 51{
105 /* We keep the current backlight level (for now) */ 52 int level = (FB_BACKLIGHT_LEVELS - 1);
106 if (ctrler == backlighter && data == backlighter_data) 53
107 backlighter = NULL; 54 if (info && info->bl_dev) {
55 int i, max = 0;
56
57 /* Look for biggest value */
58 for (i = 0; i < FB_BACKLIGHT_LEVELS; i++)
59 max = max((int)info->bl_curve[i], max);
60
61 /* Look for nearest value */
62 for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) {
63 int diff = abs(info->bl_curve[i] - value);
64 if (diff < max) {
65 max = diff;
66 level = i;
67 }
68 }
69
70 }
71
72 return level;
108} 73}
109EXPORT_SYMBOL(unregister_backlight_controller);
110 74
111static int __set_backlight_enable(int enable) 75static void pmac_backlight_key(int direction)
112{ 76{
113 int rc; 77 mutex_lock(&pmac_backlight_mutex);
114 78 if (pmac_backlight) {
115 if (!backlighter) 79 struct backlight_properties *props;
116 return -ENODEV; 80 int brightness;
117 acquire_console_sem(); 81
118 rc = backlighter->set_enable(enable, backlight_level, 82 down(&pmac_backlight->sem);
119 backlighter_data); 83 props = pmac_backlight->props;
120 if (!rc) 84
121 backlight_enabled = enable; 85 brightness = props->brightness +
122 release_console_sem(); 86 ((direction?-1:1) * (props->max_brightness / 15));
123 return rc; 87
88 if (brightness < 0)
89 brightness = 0;
90 else if (brightness > props->max_brightness)
91 brightness = props->max_brightness;
92
93 props->brightness = brightness;
94 props->update_status(pmac_backlight);
95
96 up(&pmac_backlight->sem);
97 }
98 mutex_unlock(&pmac_backlight_mutex);
124} 99}
125int set_backlight_enable(int enable) 100
101void pmac_backlight_key_up()
126{ 102{
127 if (!backlighter) 103 pmac_backlight_key(0);
128 return -ENODEV;
129 backlight_req_enable = enable;
130 schedule_work(&backlight_work);
131 return 0;
132} 104}
133 105
134EXPORT_SYMBOL(set_backlight_enable); 106void pmac_backlight_key_down()
135
136int get_backlight_enable(void)
137{ 107{
138 if (!backlighter) 108 pmac_backlight_key(1);
139 return -ENODEV;
140 return backlight_enabled;
141} 109}
142EXPORT_SYMBOL(get_backlight_enable);
143 110
144static int __set_backlight_level(int level) 111int pmac_backlight_set_legacy_brightness(int brightness)
145{ 112{
146 int rc = 0; 113 int error = -ENXIO;
147 114
148 if (!backlighter) 115 mutex_lock(&pmac_backlight_mutex);
149 return -ENODEV; 116 if (pmac_backlight) {
150 if (level < BACKLIGHT_MIN) 117 struct backlight_properties *props;
151 level = BACKLIGHT_OFF; 118
152 if (level > BACKLIGHT_MAX) 119 down(&pmac_backlight->sem);
153 level = BACKLIGHT_MAX; 120 props = pmac_backlight->props;
154 acquire_console_sem(); 121 props->brightness = brightness *
155 if (backlight_enabled) 122 props->max_brightness / OLD_BACKLIGHT_MAX;
156 rc = backlighter->set_level(level, backlighter_data); 123 props->update_status(pmac_backlight);
157 if (!rc) 124 up(&pmac_backlight->sem);
158 backlight_level = level; 125
159 release_console_sem(); 126 error = 0;
160 if (!rc && !backlight_autosave) {
161 level <<=1;
162 if (level & 0x10)
163 level |= 0x01;
164 // -- todo: save to property "bklt"
165 } 127 }
166 return rc; 128 mutex_unlock(&pmac_backlight_mutex);
129
130 return error;
167} 131}
168int set_backlight_level(int level) 132
133int pmac_backlight_get_legacy_brightness()
169{ 134{
170 if (!backlighter) 135 int result = -ENXIO;
171 return -ENODEV;
172 backlight_req_level = level;
173 schedule_work(&backlight_work);
174 return 0;
175}
176 136
177EXPORT_SYMBOL(set_backlight_level); 137 mutex_lock(&pmac_backlight_mutex);
138 if (pmac_backlight) {
139 struct backlight_properties *props;
178 140
179int get_backlight_level(void) 141 down(&pmac_backlight->sem);
180{ 142 props = pmac_backlight->props;
181 if (!backlighter) 143 result = props->brightness *
182 return -ENODEV; 144 OLD_BACKLIGHT_MAX / props->max_brightness;
183 return backlight_level; 145 up(&pmac_backlight->sem);
184} 146 }
185EXPORT_SYMBOL(get_backlight_level); 147 mutex_unlock(&pmac_backlight_mutex);
186 148
187static void backlight_callback(void *dummy) 149 return result;
188{
189 int level, enable;
190
191 do {
192 level = backlight_req_level;
193 enable = backlight_req_enable;
194 mb();
195
196 if (level >= 0)
197 __set_backlight_level(level);
198 if (enable >= 0)
199 __set_backlight_enable(enable);
200 } while(cmpxchg(&backlight_req_level, level, -1) != level ||
201 cmpxchg(&backlight_req_enable, enable, -1) != enable);
202} 150}
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 4735b41c113c..0741df8c41b7 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -26,9 +26,6 @@
26#include <asm/prom.h> 26#include <asm/prom.h>
27#include <asm/machdep.h> 27#include <asm/machdep.h>
28#include <asm/xmon.h> 28#include <asm/xmon.h>
29#ifdef CONFIG_PMAC_BACKLIGHT
30#include <asm/backlight.h>
31#endif
32#include <asm/processor.h> 29#include <asm/processor.h>
33#include <asm/pgtable.h> 30#include <asm/pgtable.h>
34#include <asm/mmu.h> 31#include <asm/mmu.h>
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index ccf5df44cde4..37cd6ee4586b 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -99,17 +99,22 @@ config PMAC_MEDIABAY
99 devices are not fully supported in the bay as I never had one to 99 devices are not fully supported in the bay as I never had one to
100 try with 100 try with
101 101
102# made a separate option since backlight may end up beeing used
103# on non-powerbook machines (but only on PMU based ones AFAIK)
104config PMAC_BACKLIGHT 102config PMAC_BACKLIGHT
105 bool "Backlight control for LCD screens" 103 bool "Backlight control for LCD screens"
106 depends on ADB_PMU && (BROKEN || !PPC64) 104 depends on ADB_PMU && (BROKEN || !PPC64)
107 help 105 help
108 Say Y here to build in code to manage the LCD backlight on a 106 Say Y here to enable Macintosh specific extensions of the generic
109 Macintosh PowerBook. With this code, the backlight will be turned 107 backlight code. With this enabled, the brightness keys on older
110 on and off appropriately on power-management and lid-open/lid-closed 108 PowerBooks will be enabled so you can change the screen brightness.
111 events; also, the PowerBook button device will be enabled so you can 109 Newer models should use an userspace daemon like pbbuttonsd.
112 change the screen brightness. 110
111config PMAC_BACKLIGHT_LEGACY
112 bool "Provide legacy ioctl's on /dev/pmu for the backlight"
113 depends on PMAC_BACKLIGHT && (BROKEN || !PPC64)
114 help
115 Say Y if you want to enable legacy ioctl's on /dev/pmu. This is for
116 programs which use this old interface. New and updated programs
117 should use the backlight classes in sysfs.
113 118
114config ADB_MACIO 119config ADB_MACIO
115 bool "Include MacIO (CHRP) ADB driver" 120 bool "Include MacIO (CHRP) ADB driver"
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
index 6081acdea404..8972e53d2dcb 100644
--- a/drivers/macintosh/Makefile
+++ b/drivers/macintosh/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_INPUT_ADBHID) += adbhid.o
12obj-$(CONFIG_ANSLCD) += ans-lcd.o 12obj-$(CONFIG_ANSLCD) += ans-lcd.o
13 13
14obj-$(CONFIG_ADB_PMU) += via-pmu.o 14obj-$(CONFIG_ADB_PMU) += via-pmu.o
15obj-$(CONFIG_PMAC_BACKLIGHT) += via-pmu-backlight.o
15obj-$(CONFIG_ADB_CUDA) += via-cuda.o 16obj-$(CONFIG_ADB_CUDA) += via-cuda.o
16obj-$(CONFIG_PMAC_APM_EMU) += apm_emu.o 17obj-$(CONFIG_PMAC_APM_EMU) += apm_emu.o
17obj-$(CONFIG_PMAC_SMU) += smu.o 18obj-$(CONFIG_PMAC_SMU) += smu.o
diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
index 394334ec5765..c26e1236b275 100644
--- a/drivers/macintosh/adbhid.c
+++ b/drivers/macintosh/adbhid.c
@@ -503,9 +503,7 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto
503 case 0x1f: /* Powerbook button device */ 503 case 0x1f: /* Powerbook button device */
504 { 504 {
505 int down = (data[1] == (data[1] & 0xf)); 505 int down = (data[1] == (data[1] & 0xf));
506#ifdef CONFIG_PMAC_BACKLIGHT 506
507 int backlight = get_backlight_level();
508#endif
509 /* 507 /*
510 * XXX: Where is the contrast control for the passive? 508 * XXX: Where is the contrast control for the passive?
511 * -- Cort 509 * -- Cort
@@ -530,29 +528,17 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto
530 528
531 case 0xa: /* brightness decrease */ 529 case 0xa: /* brightness decrease */
532#ifdef CONFIG_PMAC_BACKLIGHT 530#ifdef CONFIG_PMAC_BACKLIGHT
533 if (!disable_kernel_backlight) { 531 if (!disable_kernel_backlight && down)
534 if (down && backlight >= 0) { 532 pmac_backlight_key_down();
535 if (backlight > BACKLIGHT_OFF) 533#endif
536 set_backlight_level(backlight-1);
537 else
538 set_backlight_level(BACKLIGHT_OFF);
539 }
540 }
541#endif /* CONFIG_PMAC_BACKLIGHT */
542 input_report_key(adbhid[id]->input, KEY_BRIGHTNESSDOWN, down); 534 input_report_key(adbhid[id]->input, KEY_BRIGHTNESSDOWN, down);
543 break; 535 break;
544 536
545 case 0x9: /* brightness increase */ 537 case 0x9: /* brightness increase */
546#ifdef CONFIG_PMAC_BACKLIGHT 538#ifdef CONFIG_PMAC_BACKLIGHT
547 if (!disable_kernel_backlight) { 539 if (!disable_kernel_backlight && down)
548 if (down && backlight >= 0) { 540 pmac_backlight_key_up();
549 if (backlight < BACKLIGHT_MAX) 541#endif
550 set_backlight_level(backlight+1);
551 else
552 set_backlight_level(BACKLIGHT_MAX);
553 }
554 }
555#endif /* CONFIG_PMAC_BACKLIGHT */
556 input_report_key(adbhid[id]->input, KEY_BRIGHTNESSUP, down); 542 input_report_key(adbhid[id]->input, KEY_BRIGHTNESSUP, down);
557 break; 543 break;
558 544
diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c
new file mode 100644
index 000000000000..b42d05f2aaff
--- /dev/null
+++ b/drivers/macintosh/via-pmu-backlight.c
@@ -0,0 +1,150 @@
1/*
2 * Backlight code for via-pmu
3 *
4 * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
5 * Copyright (C) 2001-2002 Benjamin Herrenschmidt
6 * Copyright (C) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
7 *
8 */
9
10#include <asm/ptrace.h>
11#include <linux/adb.h>
12#include <linux/pmu.h>
13#include <asm/backlight.h>
14#include <asm/prom.h>
15
16#define MAX_PMU_LEVEL 0xFF
17
18static struct device_node *vias;
19static struct backlight_properties pmu_backlight_data;
20
21static int pmu_backlight_get_level_brightness(struct fb_info *info,
22 int level)
23{
24 int pmulevel;
25
26 /* Get and convert the value */
27 mutex_lock(&info->bl_mutex);
28 pmulevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_PMU_LEVEL;
29 mutex_unlock(&info->bl_mutex);
30
31 if (pmulevel < 0)
32 pmulevel = 0;
33 else if (pmulevel > MAX_PMU_LEVEL)
34 pmulevel = MAX_PMU_LEVEL;
35
36 return pmulevel;
37}
38
39static int pmu_backlight_update_status(struct backlight_device *bd)
40{
41 struct fb_info *info = class_get_devdata(&bd->class_dev);
42 struct adb_request req;
43 int pmulevel, level = bd->props->brightness;
44
45 if (vias == NULL)
46 return -ENODEV;
47
48 if (bd->props->power != FB_BLANK_UNBLANK ||
49 bd->props->fb_blank != FB_BLANK_UNBLANK)
50 level = 0;
51
52 pmulevel = pmu_backlight_get_level_brightness(info, level);
53
54 pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel);
55 pmu_wait_complete(&req);
56
57 pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
58 PMU_POW_BACKLIGHT | (level > 0 ? PMU_POW_ON : PMU_POW_OFF));
59 pmu_wait_complete(&req);
60
61 return 0;
62}
63
64static int pmu_backlight_get_brightness(struct backlight_device *bd)
65{
66 return bd->props->brightness;
67}
68
69static struct backlight_properties pmu_backlight_data = {
70 .owner = THIS_MODULE,
71 .get_brightness = pmu_backlight_get_brightness,
72 .update_status = pmu_backlight_update_status,
73 .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
74};
75
76void __init pmu_backlight_init(struct device_node *in_vias)
77{
78 struct backlight_device *bd;
79 struct fb_info *info;
80 char name[10];
81 int level, autosave;
82
83 vias = in_vias;
84
85 /* Special case for the old PowerBook since I can't test on it */
86 autosave =
87 machine_is_compatible("AAPL,3400/2400") ||
88 machine_is_compatible("AAPL,3500");
89
90 if (!autosave &&
91 !pmac_has_backlight_type("pmu") &&
92 !machine_is_compatible("AAPL,PowerBook1998") &&
93 !machine_is_compatible("PowerBook1,1"))
94 return;
95
96 /* Actually, this is a hack, but I don't know of a better way
97 * to get the first framebuffer device.
98 */
99 info = registered_fb[0];
100 if (!info) {
101 printk("pmubl: No framebuffer found\n");
102 goto error;
103 }
104
105 snprintf(name, sizeof(name), "pmubl%d", info->node);
106
107 bd = backlight_device_register(name, info, &pmu_backlight_data);
108 if (IS_ERR(bd)) {
109 printk("pmubl: Backlight registration failed\n");
110 goto error;
111 }
112
113 mutex_lock(&info->bl_mutex);
114 info->bl_dev = bd;
115 fb_bl_default_curve(info, 0x7F, 0x46, 0x0E);
116 mutex_unlock(&info->bl_mutex);
117
118 level = pmu_backlight_data.max_brightness;
119
120 if (autosave) {
121 /* read autosaved value if available */
122 struct adb_request req;
123 pmu_request(&req, NULL, 2, 0xd9, 0);
124 pmu_wait_complete(&req);
125
126 mutex_lock(&info->bl_mutex);
127 level = pmac_backlight_curve_lookup(info,
128 (req.reply[0] >> 4) *
129 pmu_backlight_data.max_brightness / 15);
130 mutex_unlock(&info->bl_mutex);
131 }
132
133 up(&bd->sem);
134 bd->props->brightness = level;
135 bd->props->power = FB_BLANK_UNBLANK;
136 bd->props->update_status(bd);
137 down(&bd->sem);
138
139 mutex_lock(&pmac_backlight_mutex);
140 if (!pmac_backlight)
141 pmac_backlight = bd;
142 mutex_unlock(&pmac_backlight_mutex);
143
144 printk("pmubl: Backlight initialized (%s)\n", name);
145
146 return;
147
148error:
149 return;
150}
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index c63d4e7984be..2a355ae59562 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -144,7 +144,6 @@ static int data_index;
144static int data_len; 144static int data_len;
145static volatile int adb_int_pending; 145static volatile int adb_int_pending;
146static volatile int disable_poll; 146static volatile int disable_poll;
147static struct adb_request bright_req_1, bright_req_2;
148static struct device_node *vias; 147static struct device_node *vias;
149static int pmu_kind = PMU_UNKNOWN; 148static int pmu_kind = PMU_UNKNOWN;
150static int pmu_fully_inited = 0; 149static int pmu_fully_inited = 0;
@@ -161,7 +160,7 @@ static int drop_interrupts;
161#if defined(CONFIG_PM) && defined(CONFIG_PPC32) 160#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
162static int option_lid_wakeup = 1; 161static int option_lid_wakeup = 1;
163#endif /* CONFIG_PM && CONFIG_PPC32 */ 162#endif /* CONFIG_PM && CONFIG_PPC32 */
164#if (defined(CONFIG_PM)&&defined(CONFIG_PPC32))||defined(CONFIG_PMAC_BACKLIGHT) 163#if (defined(CONFIG_PM)&&defined(CONFIG_PPC32))||defined(CONFIG_PMAC_BACKLIGHT_LEGACY)
165static int sleep_in_progress; 164static int sleep_in_progress;
166#endif 165#endif
167static unsigned long async_req_locks; 166static unsigned long async_req_locks;
@@ -208,10 +207,6 @@ static int proc_get_info(char *page, char **start, off_t off,
208 int count, int *eof, void *data); 207 int count, int *eof, void *data);
209static int proc_get_irqstats(char *page, char **start, off_t off, 208static int proc_get_irqstats(char *page, char **start, off_t off,
210 int count, int *eof, void *data); 209 int count, int *eof, void *data);
211#ifdef CONFIG_PMAC_BACKLIGHT
212static int pmu_set_backlight_level(int level, void* data);
213static int pmu_set_backlight_enable(int on, int level, void* data);
214#endif /* CONFIG_PMAC_BACKLIGHT */
215static void pmu_pass_intr(unsigned char *data, int len); 210static void pmu_pass_intr(unsigned char *data, int len);
216static int proc_get_batt(char *page, char **start, off_t off, 211static int proc_get_batt(char *page, char **start, off_t off,
217 int count, int *eof, void *data); 212 int count, int *eof, void *data);
@@ -292,13 +287,6 @@ static char *pbook_type[] = {
292 "Core99" 287 "Core99"
293}; 288};
294 289
295#ifdef CONFIG_PMAC_BACKLIGHT
296static struct backlight_controller pmu_backlight_controller = {
297 pmu_set_backlight_enable,
298 pmu_set_backlight_level
299};
300#endif /* CONFIG_PMAC_BACKLIGHT */
301
302int __init find_via_pmu(void) 290int __init find_via_pmu(void)
303{ 291{
304 u64 taddr; 292 u64 taddr;
@@ -417,8 +405,6 @@ static int __init via_pmu_start(void)
417 if (vias == NULL) 405 if (vias == NULL)
418 return -ENODEV; 406 return -ENODEV;
419 407
420 bright_req_1.complete = 1;
421 bright_req_2.complete = 1;
422 batt_req.complete = 1; 408 batt_req.complete = 1;
423 409
424#ifndef CONFIG_PPC_MERGE 410#ifndef CONFIG_PPC_MERGE
@@ -483,9 +469,9 @@ static int __init via_pmu_dev_init(void)
483 return -ENODEV; 469 return -ENODEV;
484 470
485#ifdef CONFIG_PMAC_BACKLIGHT 471#ifdef CONFIG_PMAC_BACKLIGHT
486 /* Enable backlight */ 472 /* Initialize backlight */
487 register_backlight_controller(&pmu_backlight_controller, NULL, "pmu"); 473 pmu_backlight_init(vias);
488#endif /* CONFIG_PMAC_BACKLIGHT */ 474#endif
489 475
490#ifdef CONFIG_PPC32 476#ifdef CONFIG_PPC32
491 if (machine_is_compatible("AAPL,3400/2400") || 477 if (machine_is_compatible("AAPL,3400/2400") ||
@@ -1424,7 +1410,7 @@ next:
1424#ifdef CONFIG_INPUT_ADBHID 1410#ifdef CONFIG_INPUT_ADBHID
1425 if (!disable_kernel_backlight) 1411 if (!disable_kernel_backlight)
1426#endif /* CONFIG_INPUT_ADBHID */ 1412#endif /* CONFIG_INPUT_ADBHID */
1427 set_backlight_level(data[1] >> 4); 1413 pmac_backlight_set_legacy_brightness(data[1] >> 4);
1428#endif /* CONFIG_PMAC_BACKLIGHT */ 1414#endif /* CONFIG_PMAC_BACKLIGHT */
1429 } 1415 }
1430 /* Tick interrupt */ 1416 /* Tick interrupt */
@@ -1674,61 +1660,6 @@ gpio1_interrupt(int irq, void *arg, struct pt_regs *regs)
1674 return IRQ_NONE; 1660 return IRQ_NONE;
1675} 1661}
1676 1662
1677#ifdef CONFIG_PMAC_BACKLIGHT
1678static int backlight_to_bright[] = {
1679 0x7f, 0x46, 0x42, 0x3e, 0x3a, 0x36, 0x32, 0x2e,
1680 0x2a, 0x26, 0x22, 0x1e, 0x1a, 0x16, 0x12, 0x0e
1681};
1682
1683static int
1684pmu_set_backlight_enable(int on, int level, void* data)
1685{
1686 struct adb_request req;
1687
1688 if (vias == NULL)
1689 return -ENODEV;
1690
1691 if (on) {
1692 pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT,
1693 backlight_to_bright[level]);
1694 pmu_wait_complete(&req);
1695 }
1696 pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
1697 PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF));
1698 pmu_wait_complete(&req);
1699
1700 return 0;
1701}
1702
1703static void
1704pmu_bright_complete(struct adb_request *req)
1705{
1706 if (req == &bright_req_1)
1707 clear_bit(1, &async_req_locks);
1708 if (req == &bright_req_2)
1709 clear_bit(2, &async_req_locks);
1710}
1711
1712static int
1713pmu_set_backlight_level(int level, void* data)
1714{
1715 if (vias == NULL)
1716 return -ENODEV;
1717
1718 if (test_and_set_bit(1, &async_req_locks))
1719 return -EAGAIN;
1720 pmu_request(&bright_req_1, pmu_bright_complete, 2, PMU_BACKLIGHT_BRIGHT,
1721 backlight_to_bright[level]);
1722 if (test_and_set_bit(2, &async_req_locks))
1723 return -EAGAIN;
1724 pmu_request(&bright_req_2, pmu_bright_complete, 2, PMU_POWER_CTRL,
1725 PMU_POW_BACKLIGHT | (level > BACKLIGHT_OFF ?
1726 PMU_POW_ON : PMU_POW_OFF));
1727
1728 return 0;
1729}
1730#endif /* CONFIG_PMAC_BACKLIGHT */
1731
1732void 1663void
1733pmu_enable_irled(int on) 1664pmu_enable_irled(int on)
1734{ 1665{
@@ -2145,9 +2076,8 @@ pmac_suspend_devices(void)
2145 return -EBUSY; 2076 return -EBUSY;
2146 } 2077 }
2147 2078
2148 /* Wait for completion of async backlight requests */ 2079 /* Wait for completion of async requests */
2149 while (!bright_req_1.complete || !bright_req_2.complete || 2080 while (!batt_req.complete)
2150 !batt_req.complete)
2151 pmu_poll(); 2081 pmu_poll();
2152 2082
2153 /* Giveup the lazy FPU & vec so we don't have to back them 2083 /* 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,
2678 return put_user(1, argp); 2608 return put_user(1, argp);
2679#endif /* CONFIG_PM && CONFIG_PPC32 */ 2609#endif /* CONFIG_PM && CONFIG_PPC32 */
2680 2610
2681#ifdef CONFIG_PMAC_BACKLIGHT 2611#ifdef CONFIG_PMAC_BACKLIGHT_LEGACY
2682 /* Backlight should have its own device or go via 2612 /* Compatibility ioctl's for backlight */
2683 * the fbdev
2684 */
2685 case PMU_IOC_GET_BACKLIGHT: 2613 case PMU_IOC_GET_BACKLIGHT:
2614 {
2615 int brightness;
2616
2686 if (sleep_in_progress) 2617 if (sleep_in_progress)
2687 return -EBUSY; 2618 return -EBUSY;
2688 error = get_backlight_level(); 2619
2689 if (error < 0) 2620 brightness = pmac_backlight_get_legacy_brightness();
2690 return error; 2621 if (brightness < 0)
2691 return put_user(error, argp); 2622 return brightness;
2623 else
2624 return put_user(brightness, argp);
2625
2626 }
2692 case PMU_IOC_SET_BACKLIGHT: 2627 case PMU_IOC_SET_BACKLIGHT:
2693 { 2628 {
2694 __u32 value; 2629 int brightness;
2630
2695 if (sleep_in_progress) 2631 if (sleep_in_progress)
2696 return -EBUSY; 2632 return -EBUSY;
2697 error = get_user(value, argp); 2633
2698 if (!error) 2634 error = get_user(brightness, argp);
2699 error = set_backlight_level(value); 2635 if (error)
2700 break; 2636 return error;
2637
2638 return pmac_backlight_set_legacy_brightness(brightness);
2701 } 2639 }
2702#ifdef CONFIG_INPUT_ADBHID 2640#ifdef CONFIG_INPUT_ADBHID
2703 case PMU_IOC_GRAB_BACKLIGHT: { 2641 case PMU_IOC_GRAB_BACKLIGHT: {
@@ -2713,7 +2651,7 @@ pmu_ioctl(struct inode * inode, struct file *filp,
2713 return 0; 2651 return 0;
2714 } 2652 }
2715#endif /* CONFIG_INPUT_ADBHID */ 2653#endif /* CONFIG_INPUT_ADBHID */
2716#endif /* CONFIG_PMAC_BACKLIGHT */ 2654#endif /* CONFIG_PMAC_BACKLIGHT_LEGACY */
2717 case PMU_IOC_GET_MODEL: 2655 case PMU_IOC_GET_MODEL:
2718 return put_user(pmu_kind, argp); 2656 return put_user(pmu_kind, argp);
2719 case PMU_IOC_HAS_ADB: 2657 case PMU_IOC_HAS_ADB:
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 5a2840aeb547..168ede7902bd 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -86,6 +86,11 @@ config FB_FIRMWARE_EDID
86 combination with certain motherboards and monitors are known to 86 combination with certain motherboards and monitors are known to
87 suffer from this problem. 87 suffer from this problem.
88 88
89config FB_BACKLIGHT
90 bool
91 depends on FB
92 default n
93
89config FB_MODE_HELPERS 94config FB_MODE_HELPERS
90 bool "Enable Video Mode Handling Helpers" 95 bool "Enable Video Mode Handling Helpers"
91 depends on FB 96 depends on FB
@@ -717,6 +722,16 @@ config FB_NVIDIA_I2C
717 independently validate video mode parameters, you should say Y 722 independently validate video mode parameters, you should say Y
718 here. 723 here.
719 724
725config FB_NVIDIA_BACKLIGHT
726 bool "Support for backlight control"
727 depends on FB_NVIDIA && PPC_PMAC
728 select FB_BACKLIGHT
729 select BACKLIGHT_LCD_SUPPORT
730 select BACKLIGHT_CLASS_DEVICE
731 default y
732 help
733 Say Y here if you want to control the backlight of your display.
734
720config FB_RIVA 735config FB_RIVA
721 tristate "nVidia Riva support" 736 tristate "nVidia Riva support"
722 depends on FB && PCI 737 depends on FB && PCI
@@ -755,6 +770,16 @@ config FB_RIVA_DEBUG
755 of debugging informations to provide to the maintainer when 770 of debugging informations to provide to the maintainer when
756 something goes wrong. 771 something goes wrong.
757 772
773config FB_RIVA_BACKLIGHT
774 bool "Support for backlight control"
775 depends on FB_RIVA && PPC_PMAC
776 select FB_BACKLIGHT
777 select BACKLIGHT_LCD_SUPPORT
778 select BACKLIGHT_CLASS_DEVICE
779 default y
780 help
781 Say Y here if you want to control the backlight of your display.
782
758config FB_I810 783config FB_I810
759 tristate "Intel 810/815 support (EXPERIMENTAL)" 784 tristate "Intel 810/815 support (EXPERIMENTAL)"
760 depends on FB && EXPERIMENTAL && PCI && X86_32 785 depends on FB && EXPERIMENTAL && PCI && X86_32
@@ -993,6 +1018,7 @@ config FB_RADEON
993 1018
994 There is a product page at 1019 There is a product page at
995 http://apps.ati.com/ATIcompare/ 1020 http://apps.ati.com/ATIcompare/
1021
996config FB_RADEON_I2C 1022config FB_RADEON_I2C
997 bool "DDC/I2C for ATI Radeon support" 1023 bool "DDC/I2C for ATI Radeon support"
998 depends on FB_RADEON 1024 depends on FB_RADEON
@@ -1000,6 +1026,16 @@ config FB_RADEON_I2C
1000 help 1026 help
1001 Say Y here if you want DDC/I2C support for your Radeon board. 1027 Say Y here if you want DDC/I2C support for your Radeon board.
1002 1028
1029config FB_RADEON_BACKLIGHT
1030 bool "Support for backlight control"
1031 depends on FB_RADEON && PPC_PMAC
1032 select FB_BACKLIGHT
1033 select BACKLIGHT_LCD_SUPPORT
1034 select BACKLIGHT_CLASS_DEVICE
1035 default y
1036 help
1037 Say Y here if you want to control the backlight of your display.
1038
1003config FB_RADEON_DEBUG 1039config FB_RADEON_DEBUG
1004 bool "Lots of debug output from Radeon driver" 1040 bool "Lots of debug output from Radeon driver"
1005 depends on FB_RADEON 1041 depends on FB_RADEON
@@ -1024,6 +1060,16 @@ config FB_ATY128
1024 To compile this driver as a module, choose M here: the 1060 To compile this driver as a module, choose M here: the
1025 module will be called aty128fb. 1061 module will be called aty128fb.
1026 1062
1063config FB_ATY128_BACKLIGHT
1064 bool "Support for backlight control"
1065 depends on FB_ATY128 && PPC_PMAC
1066 select FB_BACKLIGHT
1067 select BACKLIGHT_LCD_SUPPORT
1068 select BACKLIGHT_CLASS_DEVICE
1069 default y
1070 help
1071 Say Y here if you want to control the backlight of your display.
1072
1027config FB_ATY 1073config FB_ATY
1028 tristate "ATI Mach64 display support" if PCI || ATARI 1074 tristate "ATI Mach64 display support" if PCI || ATARI
1029 depends on FB && !SPARC32 1075 depends on FB && !SPARC32
@@ -1066,6 +1112,16 @@ config FB_ATY_GX
1066 is at 1112 is at
1067 <http://support.ati.com/products/pc/mach64/graphics_xpression.html>. 1113 <http://support.ati.com/products/pc/mach64/graphics_xpression.html>.
1068 1114
1115config FB_ATY_BACKLIGHT
1116 bool "Support for backlight control"
1117 depends on FB_ATY && PPC_PMAC
1118 select FB_BACKLIGHT
1119 select BACKLIGHT_LCD_SUPPORT
1120 select BACKLIGHT_CLASS_DEVICE
1121 default y
1122 help
1123 Say Y here if you want to control the backlight of your display.
1124
1069config FB_S3TRIO 1125config FB_S3TRIO
1070 bool "S3 Trio display support" 1126 bool "S3 Trio display support"
1071 depends on (FB = y) && PPC && BROKEN 1127 depends on (FB = y) && PPC && BROKEN
diff --git a/drivers/video/aty/Makefile b/drivers/video/aty/Makefile
index 18521397a6e3..a6cc0e9ec790 100644
--- a/drivers/video/aty/Makefile
+++ b/drivers/video/aty/Makefile
@@ -10,5 +10,6 @@ atyfb-objs := $(atyfb-y)
10 10
11radeonfb-y := radeon_base.o radeon_pm.o radeon_monitor.o radeon_accel.o 11radeonfb-y := radeon_base.o radeon_pm.o radeon_monitor.o radeon_accel.o
12radeonfb-$(CONFIG_FB_RADEON_I2C) += radeon_i2c.o 12radeonfb-$(CONFIG_FB_RADEON_I2C) += radeon_i2c.o
13radeonfb-$(CONFIG_FB_RADEON_BACKLIGHT) += radeon_backlight.o
13radeonfb-objs := $(radeonfb-y) 14radeonfb-objs := $(radeonfb-y)
14 15
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index f7bbff4ddc6a..db878fd55fb2 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -64,6 +64,7 @@
64#include <linux/pci.h> 64#include <linux/pci.h>
65#include <linux/ioport.h> 65#include <linux/ioport.h>
66#include <linux/console.h> 66#include <linux/console.h>
67#include <linux/backlight.h>
67#include <asm/io.h> 68#include <asm/io.h>
68 69
69#ifdef CONFIG_PPC_PMAC 70#ifdef CONFIG_PPC_PMAC
@@ -480,16 +481,6 @@ static struct fb_ops aty128fb_ops = {
480 .fb_imageblit = cfb_imageblit, 481 .fb_imageblit = cfb_imageblit,
481}; 482};
482 483
483#ifdef CONFIG_PMAC_BACKLIGHT
484static int aty128_set_backlight_enable(int on, int level, void* data);
485static int aty128_set_backlight_level(int level, void* data);
486
487static struct backlight_controller aty128_backlight_controller = {
488 aty128_set_backlight_enable,
489 aty128_set_backlight_level
490};
491#endif /* CONFIG_PMAC_BACKLIGHT */
492
493 /* 484 /*
494 * Functions to read from/write to the mmio registers 485 * Functions to read from/write to the mmio registers
495 * - endian conversions may possibly be avoided by 486 * - endian conversions may possibly be avoided by
@@ -1258,19 +1249,35 @@ static void aty128_set_crt_enable(struct aty128fb_par *par, int on)
1258static void aty128_set_lcd_enable(struct aty128fb_par *par, int on) 1249static void aty128_set_lcd_enable(struct aty128fb_par *par, int on)
1259{ 1250{
1260 u32 reg; 1251 u32 reg;
1252#ifdef CONFIG_FB_ATY128_BACKLIGHT
1253 struct fb_info *info = pci_get_drvdata(par->pdev);
1254#endif
1261 1255
1262 if (on) { 1256 if (on) {
1263 reg = aty_ld_le32(LVDS_GEN_CNTL); 1257 reg = aty_ld_le32(LVDS_GEN_CNTL);
1264 reg |= LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION; 1258 reg |= LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION;
1265 reg &= ~LVDS_DISPLAY_DIS; 1259 reg &= ~LVDS_DISPLAY_DIS;
1266 aty_st_le32(LVDS_GEN_CNTL, reg); 1260 aty_st_le32(LVDS_GEN_CNTL, reg);
1267#ifdef CONFIG_PMAC_BACKLIGHT 1261#ifdef CONFIG_FB_ATY128_BACKLIGHT
1268 aty128_set_backlight_enable(get_backlight_enable(), 1262 mutex_lock(&info->bl_mutex);
1269 get_backlight_level(), par); 1263 if (info->bl_dev) {
1264 down(&info->bl_dev->sem);
1265 info->bl_dev->props->update_status(info->bl_dev);
1266 up(&info->bl_dev->sem);
1267 }
1268 mutex_unlock(&info->bl_mutex);
1270#endif 1269#endif
1271 } else { 1270 } else {
1272#ifdef CONFIG_PMAC_BACKLIGHT 1271#ifdef CONFIG_FB_ATY128_BACKLIGHT
1273 aty128_set_backlight_enable(0, 0, par); 1272 mutex_lock(&info->bl_mutex);
1273 if (info->bl_dev) {
1274 down(&info->bl_dev->sem);
1275 info->bl_dev->props->brightness = 0;
1276 info->bl_dev->props->power = FB_BLANK_POWERDOWN;
1277 info->bl_dev->props->update_status(info->bl_dev);
1278 up(&info->bl_dev->sem);
1279 }
1280 mutex_unlock(&info->bl_mutex);
1274#endif 1281#endif
1275 reg = aty_ld_le32(LVDS_GEN_CNTL); 1282 reg = aty_ld_le32(LVDS_GEN_CNTL);
1276 reg |= LVDS_DISPLAY_DIS; 1283 reg |= LVDS_DISPLAY_DIS;
@@ -1691,6 +1698,184 @@ static int __init aty128fb_setup(char *options)
1691} 1698}
1692#endif /* MODULE */ 1699#endif /* MODULE */
1693 1700
1701/* Backlight */
1702#ifdef CONFIG_FB_ATY128_BACKLIGHT
1703#define MAX_LEVEL 0xFF
1704
1705static struct backlight_properties aty128_bl_data;
1706
1707static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
1708 int level)
1709{
1710 struct fb_info *info = pci_get_drvdata(par->pdev);
1711 int atylevel;
1712
1713 /* Get and convert the value */
1714 mutex_lock(&info->bl_mutex);
1715 atylevel = MAX_LEVEL -
1716 (info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL);
1717 mutex_unlock(&info->bl_mutex);
1718
1719 if (atylevel < 0)
1720 atylevel = 0;
1721 else if (atylevel > MAX_LEVEL)
1722 atylevel = MAX_LEVEL;
1723
1724 return atylevel;
1725}
1726
1727/* We turn off the LCD completely instead of just dimming the backlight.
1728 * This provides greater power saving and the display is useless without
1729 * backlight anyway
1730 */
1731#define BACKLIGHT_LVDS_OFF
1732/* That one prevents proper CRT output with LCD off */
1733#undef BACKLIGHT_DAC_OFF
1734
1735static int aty128_bl_update_status(struct backlight_device *bd)
1736{
1737 struct aty128fb_par *par = class_get_devdata(&bd->class_dev);
1738 unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
1739 int level;
1740
1741 if (bd->props->power != FB_BLANK_UNBLANK ||
1742 bd->props->fb_blank != FB_BLANK_UNBLANK ||
1743 !par->lcd_on)
1744 level = 0;
1745 else
1746 level = bd->props->brightness;
1747
1748 reg |= LVDS_BL_MOD_EN | LVDS_BLON;
1749 if (level > 0) {
1750 reg |= LVDS_DIGION;
1751 if (!(reg & LVDS_ON)) {
1752 reg &= ~LVDS_BLON;
1753 aty_st_le32(LVDS_GEN_CNTL, reg);
1754 aty_ld_le32(LVDS_GEN_CNTL);
1755 mdelay(10);
1756 reg |= LVDS_BLON;
1757 aty_st_le32(LVDS_GEN_CNTL, reg);
1758 }
1759 reg &= ~LVDS_BL_MOD_LEVEL_MASK;
1760 reg |= (aty128_bl_get_level_brightness(par, level) << LVDS_BL_MOD_LEVEL_SHIFT);
1761#ifdef BACKLIGHT_LVDS_OFF
1762 reg |= LVDS_ON | LVDS_EN;
1763 reg &= ~LVDS_DISPLAY_DIS;
1764#endif
1765 aty_st_le32(LVDS_GEN_CNTL, reg);
1766#ifdef BACKLIGHT_DAC_OFF
1767 aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN));
1768#endif
1769 } else {
1770 reg &= ~LVDS_BL_MOD_LEVEL_MASK;
1771 reg |= (aty128_bl_get_level_brightness(par, 0) << LVDS_BL_MOD_LEVEL_SHIFT);
1772#ifdef BACKLIGHT_LVDS_OFF
1773 reg |= LVDS_DISPLAY_DIS;
1774 aty_st_le32(LVDS_GEN_CNTL, reg);
1775 aty_ld_le32(LVDS_GEN_CNTL);
1776 udelay(10);
1777 reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION);
1778#endif
1779 aty_st_le32(LVDS_GEN_CNTL, reg);
1780#ifdef BACKLIGHT_DAC_OFF
1781 aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN);
1782#endif
1783 }
1784
1785 return 0;
1786}
1787
1788static int aty128_bl_get_brightness(struct backlight_device *bd)
1789{
1790 return bd->props->brightness;
1791}
1792
1793static struct backlight_properties aty128_bl_data = {
1794 .owner = THIS_MODULE,
1795 .get_brightness = aty128_bl_get_brightness,
1796 .update_status = aty128_bl_update_status,
1797 .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
1798};
1799
1800static void aty128_bl_init(struct aty128fb_par *par)
1801{
1802 struct fb_info *info = pci_get_drvdata(par->pdev);
1803 struct backlight_device *bd;
1804 char name[12];
1805
1806 /* Could be extended to Rage128Pro LVDS output too */
1807 if (par->chip_gen != rage_M3)
1808 return;
1809
1810#ifdef CONFIG_PMAC_BACKLIGHT
1811 if (!pmac_has_backlight_type("ati"))
1812 return;
1813#endif
1814
1815 snprintf(name, sizeof(name), "aty128bl%d", info->node);
1816
1817 bd = backlight_device_register(name, par, &aty128_bl_data);
1818 if (IS_ERR(bd)) {
1819 info->bl_dev = NULL;
1820 printk("aty128: Backlight registration failed\n");
1821 goto error;
1822 }
1823
1824 mutex_lock(&info->bl_mutex);
1825 info->bl_dev = bd;
1826 fb_bl_default_curve(info, 0,
1827 63 * FB_BACKLIGHT_MAX / MAX_LEVEL,
1828 219 * FB_BACKLIGHT_MAX / MAX_LEVEL);
1829 mutex_unlock(&info->bl_mutex);
1830
1831 up(&bd->sem);
1832 bd->props->brightness = aty128_bl_data.max_brightness;
1833 bd->props->power = FB_BLANK_UNBLANK;
1834 bd->props->update_status(bd);
1835 down(&bd->sem);
1836
1837#ifdef CONFIG_PMAC_BACKLIGHT
1838 mutex_lock(&pmac_backlight_mutex);
1839 if (!pmac_backlight)
1840 pmac_backlight = bd;
1841 mutex_unlock(&pmac_backlight_mutex);
1842#endif
1843
1844 printk("aty128: Backlight initialized (%s)\n", name);
1845
1846 return;
1847
1848error:
1849 return;
1850}
1851
1852static void aty128_bl_exit(struct aty128fb_par *par)
1853{
1854 struct fb_info *info = pci_get_drvdata(par->pdev);
1855
1856#ifdef CONFIG_PMAC_BACKLIGHT
1857 mutex_lock(&pmac_backlight_mutex);
1858#endif
1859
1860 mutex_lock(&info->bl_mutex);
1861 if (info->bl_dev) {
1862#ifdef CONFIG_PMAC_BACKLIGHT
1863 if (pmac_backlight == info->bl_dev)
1864 pmac_backlight = NULL;
1865#endif
1866
1867 backlight_device_unregister(info->bl_dev);
1868 info->bl_dev = NULL;
1869
1870 printk("aty128: Backlight unloaded\n");
1871 }
1872 mutex_unlock(&info->bl_mutex);
1873
1874#ifdef CONFIG_PMAC_BACKLIGHT
1875 mutex_unlock(&pmac_backlight_mutex);
1876#endif
1877}
1878#endif /* CONFIG_FB_ATY128_BACKLIGHT */
1694 1879
1695/* 1880/*
1696 * Initialisation 1881 * Initialisation
@@ -1835,17 +2020,15 @@ static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id *
1835 if (register_framebuffer(info) < 0) 2020 if (register_framebuffer(info) < 0)
1836 return 0; 2021 return 0;
1837 2022
1838#ifdef CONFIG_PMAC_BACKLIGHT
1839 /* Could be extended to Rage128Pro LVDS output too */
1840 if (par->chip_gen == rage_M3)
1841 register_backlight_controller(&aty128_backlight_controller, par, "ati");
1842#endif /* CONFIG_PMAC_BACKLIGHT */
1843
1844 par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM); 2023 par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM);
1845 par->pdev = pdev; 2024 par->pdev = pdev;
1846 par->asleep = 0; 2025 par->asleep = 0;
1847 par->lock_blank = 0; 2026 par->lock_blank = 0;
1848 2027
2028#ifdef CONFIG_FB_ATY128_BACKLIGHT
2029 aty128_bl_init(par);
2030#endif
2031
1849 printk(KERN_INFO "fb%d: %s frame buffer device on %s\n", 2032 printk(KERN_INFO "fb%d: %s frame buffer device on %s\n",
1850 info->node, info->fix.id, video_card); 2033 info->node, info->fix.id, video_card);
1851 2034
@@ -1981,6 +2164,10 @@ static void __devexit aty128_remove(struct pci_dev *pdev)
1981 2164
1982 par = info->par; 2165 par = info->par;
1983 2166
2167#ifdef CONFIG_FB_ATY128_BACKLIGHT
2168 aty128_bl_exit(par);
2169#endif
2170
1984 unregister_framebuffer(info); 2171 unregister_framebuffer(info);
1985#ifdef CONFIG_MTRR 2172#ifdef CONFIG_MTRR
1986 if (par->mtrr.vram_valid) 2173 if (par->mtrr.vram_valid)
@@ -2011,10 +2198,14 @@ static int aty128fb_blank(int blank, struct fb_info *fb)
2011 if (par->lock_blank || par->asleep) 2198 if (par->lock_blank || par->asleep)
2012 return 0; 2199 return 0;
2013 2200
2014#ifdef CONFIG_PMAC_BACKLIGHT 2201#ifdef CONFIG_FB_ATY128_BACKLIGHT
2015 if (machine_is(powermac) && blank) 2202 if (machine_is(powermac) && blank) {
2016 set_backlight_enable(0); 2203 down(&fb->bl_dev->sem);
2017#endif /* CONFIG_PMAC_BACKLIGHT */ 2204 fb->bl_dev->props->power = FB_BLANK_POWERDOWN;
2205 fb->bl_dev->props->update_status(fb->bl_dev);
2206 up(&fb->bl_dev->sem);
2207 }
2208#endif
2018 2209
2019 if (blank & FB_BLANK_VSYNC_SUSPEND) 2210 if (blank & FB_BLANK_VSYNC_SUSPEND)
2020 state |= 2; 2211 state |= 2;
@@ -2029,10 +2220,14 @@ static int aty128fb_blank(int blank, struct fb_info *fb)
2029 aty128_set_crt_enable(par, par->crt_on && !blank); 2220 aty128_set_crt_enable(par, par->crt_on && !blank);
2030 aty128_set_lcd_enable(par, par->lcd_on && !blank); 2221 aty128_set_lcd_enable(par, par->lcd_on && !blank);
2031 } 2222 }
2032#ifdef CONFIG_PMAC_BACKLIGHT 2223#ifdef CONFIG_FB_ATY128_BACKLIGHT
2033 if (machine_is(powermac) && !blank) 2224 if (machine_is(powermac) && !blank) {
2034 set_backlight_enable(1); 2225 down(&fb->bl_dev->sem);
2035#endif /* CONFIG_PMAC_BACKLIGHT */ 2226 fb->bl_dev->props->power = FB_BLANK_UNBLANK;
2227 fb->bl_dev->props->update_status(fb->bl_dev);
2228 up(&fb->bl_dev->sem);
2229 }
2230#endif
2036 return 0; 2231 return 0;
2037} 2232}
2038 2233
@@ -2138,73 +2333,6 @@ static int aty128fb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
2138 return -EINVAL; 2333 return -EINVAL;
2139} 2334}
2140 2335
2141#ifdef CONFIG_PMAC_BACKLIGHT
2142static int backlight_conv[] = {
2143 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
2144 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
2145};
2146
2147/* We turn off the LCD completely instead of just dimming the backlight.
2148 * This provides greater power saving and the display is useless without
2149 * backlight anyway
2150 */
2151#define BACKLIGHT_LVDS_OFF
2152/* That one prevents proper CRT output with LCD off */
2153#undef BACKLIGHT_DAC_OFF
2154
2155static int aty128_set_backlight_enable(int on, int level, void *data)
2156{
2157 struct aty128fb_par *par = data;
2158 unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
2159
2160 if (!par->lcd_on)
2161 on = 0;
2162 reg |= LVDS_BL_MOD_EN | LVDS_BLON;
2163 if (on && level > BACKLIGHT_OFF) {
2164 reg |= LVDS_DIGION;
2165 if (!(reg & LVDS_ON)) {
2166 reg &= ~LVDS_BLON;
2167 aty_st_le32(LVDS_GEN_CNTL, reg);
2168 (void)aty_ld_le32(LVDS_GEN_CNTL);
2169 mdelay(10);
2170 reg |= LVDS_BLON;
2171 aty_st_le32(LVDS_GEN_CNTL, reg);
2172 }
2173 reg &= ~LVDS_BL_MOD_LEVEL_MASK;
2174 reg |= (backlight_conv[level] << LVDS_BL_MOD_LEVEL_SHIFT);
2175#ifdef BACKLIGHT_LVDS_OFF
2176 reg |= LVDS_ON | LVDS_EN;
2177 reg &= ~LVDS_DISPLAY_DIS;
2178#endif
2179 aty_st_le32(LVDS_GEN_CNTL, reg);
2180#ifdef BACKLIGHT_DAC_OFF
2181 aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN));
2182#endif
2183 } else {
2184 reg &= ~LVDS_BL_MOD_LEVEL_MASK;
2185 reg |= (backlight_conv[0] << LVDS_BL_MOD_LEVEL_SHIFT);
2186#ifdef BACKLIGHT_LVDS_OFF
2187 reg |= LVDS_DISPLAY_DIS;
2188 aty_st_le32(LVDS_GEN_CNTL, reg);
2189 (void)aty_ld_le32(LVDS_GEN_CNTL);
2190 udelay(10);
2191 reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION);
2192#endif
2193 aty_st_le32(LVDS_GEN_CNTL, reg);
2194#ifdef BACKLIGHT_DAC_OFF
2195 aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN);
2196#endif
2197 }
2198
2199 return 0;
2200}
2201
2202static int aty128_set_backlight_level(int level, void* data)
2203{
2204 return aty128_set_backlight_enable(1, level, data);
2205}
2206#endif /* CONFIG_PMAC_BACKLIGHT */
2207
2208#if 0 2336#if 0
2209 /* 2337 /*
2210 * Accelerated functions 2338 * Accelerated functions
diff --git a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h
index e9b7a64c1ac4..43d2cb58af87 100644
--- a/drivers/video/aty/atyfb.h
+++ b/drivers/video/aty/atyfb.h
@@ -151,6 +151,7 @@ struct atyfb_par {
151 int lock_blank; 151 int lock_blank;
152 unsigned long res_start; 152 unsigned long res_start;
153 unsigned long res_size; 153 unsigned long res_size;
154 struct pci_dev *pdev;
154#ifdef __sparc__ 155#ifdef __sparc__
155 struct pci_mmap_map *mmap_map; 156 struct pci_mmap_map *mmap_map;
156 u8 mmaped; 157 u8 mmaped;
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index c054bb28b1c4..c5185f7cf4ba 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -66,6 +66,7 @@
66#include <linux/interrupt.h> 66#include <linux/interrupt.h>
67#include <linux/spinlock.h> 67#include <linux/spinlock.h>
68#include <linux/wait.h> 68#include <linux/wait.h>
69#include <linux/backlight.h>
69 70
70#include <asm/io.h> 71#include <asm/io.h>
71#include <asm/uaccess.h> 72#include <asm/uaccess.h>
@@ -2115,45 +2116,142 @@ static int atyfb_pci_resume(struct pci_dev *pdev)
2115 2116
2116#endif /* defined(CONFIG_PM) && defined(CONFIG_PCI) */ 2117#endif /* defined(CONFIG_PM) && defined(CONFIG_PCI) */
2117 2118
2118#ifdef CONFIG_PMAC_BACKLIGHT 2119/* Backlight */
2120#ifdef CONFIG_FB_ATY_BACKLIGHT
2121#define MAX_LEVEL 0xFF
2119 2122
2120 /* 2123static struct backlight_properties aty_bl_data;
2121 * LCD backlight control
2122 */
2123 2124
2124static int backlight_conv[] = { 2125static int aty_bl_get_level_brightness(struct atyfb_par *par, int level)
2125 0x00, 0x3f, 0x4c, 0x59, 0x66, 0x73, 0x80, 0x8d, 2126{
2126 0x9a, 0xa7, 0xb4, 0xc1, 0xcf, 0xdc, 0xe9, 0xff 2127 struct fb_info *info = pci_get_drvdata(par->pdev);
2127}; 2128 int atylevel;
2129
2130 /* Get and convert the value */
2131 mutex_lock(&info->bl_mutex);
2132 atylevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
2133 mutex_unlock(&info->bl_mutex);
2134
2135 if (atylevel < 0)
2136 atylevel = 0;
2137 else if (atylevel > MAX_LEVEL)
2138 atylevel = MAX_LEVEL;
2128 2139
2129static int aty_set_backlight_enable(int on, int level, void *data) 2140 return atylevel;
2141}
2142
2143static int aty_bl_update_status(struct backlight_device *bd)
2130{ 2144{
2131 struct fb_info *info = (struct fb_info *) data; 2145 struct atyfb_par *par = class_get_devdata(&bd->class_dev);
2132 struct atyfb_par *par = (struct atyfb_par *) info->par;
2133 unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par); 2146 unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par);
2147 int level;
2148
2149 if (bd->props->power != FB_BLANK_UNBLANK ||
2150 bd->props->fb_blank != FB_BLANK_UNBLANK)
2151 level = 0;
2152 else
2153 level = bd->props->brightness;
2134 2154
2135 reg |= (BLMOD_EN | BIASMOD_EN); 2155 reg |= (BLMOD_EN | BIASMOD_EN);
2136 if (on && level > BACKLIGHT_OFF) { 2156 if (level > 0) {
2137 reg &= ~BIAS_MOD_LEVEL_MASK; 2157 reg &= ~BIAS_MOD_LEVEL_MASK;
2138 reg |= (backlight_conv[level] << BIAS_MOD_LEVEL_SHIFT); 2158 reg |= (aty_bl_get_level_brightness(par, level) << BIAS_MOD_LEVEL_SHIFT);
2139 } else { 2159 } else {
2140 reg &= ~BIAS_MOD_LEVEL_MASK; 2160 reg &= ~BIAS_MOD_LEVEL_MASK;
2141 reg |= (backlight_conv[0] << BIAS_MOD_LEVEL_SHIFT); 2161 reg |= (aty_bl_get_level_brightness(par, 0) << BIAS_MOD_LEVEL_SHIFT);
2142 } 2162 }
2143 aty_st_lcd(LCD_MISC_CNTL, reg, par); 2163 aty_st_lcd(LCD_MISC_CNTL, reg, par);
2164
2144 return 0; 2165 return 0;
2145} 2166}
2146 2167
2147static int aty_set_backlight_level(int level, void *data) 2168static int aty_bl_get_brightness(struct backlight_device *bd)
2148{ 2169{
2149 return aty_set_backlight_enable(1, level, data); 2170 return bd->props->brightness;
2150} 2171}
2151 2172
2152static struct backlight_controller aty_backlight_controller = { 2173static struct backlight_properties aty_bl_data = {
2153 aty_set_backlight_enable, 2174 .owner = THIS_MODULE,
2154 aty_set_backlight_level 2175 .get_brightness = aty_bl_get_brightness,
2176 .update_status = aty_bl_update_status,
2177 .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
2155}; 2178};
2156#endif /* CONFIG_PMAC_BACKLIGHT */ 2179
2180static void aty_bl_init(struct atyfb_par *par)
2181{
2182 struct fb_info *info = pci_get_drvdata(par->pdev);
2183 struct backlight_device *bd;
2184 char name[12];
2185
2186#ifdef CONFIG_PMAC_BACKLIGHT
2187 if (!pmac_has_backlight_type("ati"))
2188 return;
2189#endif
2190
2191 snprintf(name, sizeof(name), "atybl%d", info->node);
2192
2193 bd = backlight_device_register(name, par, &aty_bl_data);
2194 if (IS_ERR(bd)) {
2195 info->bl_dev = NULL;
2196 printk("aty: Backlight registration failed\n");
2197 goto error;
2198 }
2199
2200 mutex_lock(&info->bl_mutex);
2201 info->bl_dev = bd;
2202 fb_bl_default_curve(info, 0,
2203 0x3F * FB_BACKLIGHT_MAX / MAX_LEVEL,
2204 0xFF * FB_BACKLIGHT_MAX / MAX_LEVEL);
2205 mutex_unlock(&info->bl_mutex);
2206
2207 up(&bd->sem);
2208 bd->props->brightness = aty_bl_data.max_brightness;
2209 bd->props->power = FB_BLANK_UNBLANK;
2210 bd->props->update_status(bd);
2211 down(&bd->sem);
2212
2213#ifdef CONFIG_PMAC_BACKLIGHT
2214 mutex_lock(&pmac_backlight_mutex);
2215 if (!pmac_backlight)
2216 pmac_backlight = bd;
2217 mutex_unlock(&pmac_backlight_mutex);
2218#endif
2219
2220 printk("aty: Backlight initialized (%s)\n", name);
2221
2222 return;
2223
2224error:
2225 return;
2226}
2227
2228static void aty_bl_exit(struct atyfb_par *par)
2229{
2230 struct fb_info *info = pci_get_drvdata(par->pdev);
2231
2232#ifdef CONFIG_PMAC_BACKLIGHT
2233 mutex_lock(&pmac_backlight_mutex);
2234#endif
2235
2236 mutex_lock(&info->bl_mutex);
2237 if (info->bl_dev) {
2238#ifdef CONFIG_PMAC_BACKLIGHT
2239 if (pmac_backlight == info->bl_dev)
2240 pmac_backlight = NULL;
2241#endif
2242
2243 backlight_device_unregister(info->bl_dev);
2244
2245 printk("aty: Backlight unloaded\n");
2246 }
2247 mutex_unlock(&info->bl_mutex);
2248
2249#ifdef CONFIG_PMAC_BACKLIGHT
2250 mutex_unlock(&pmac_backlight_mutex);
2251#endif
2252}
2253
2254#endif /* CONFIG_FB_ATY_BACKLIGHT */
2157 2255
2158static void __init aty_calc_mem_refresh(struct atyfb_par *par, int xclk) 2256static void __init aty_calc_mem_refresh(struct atyfb_par *par, int xclk)
2159{ 2257{
@@ -2513,9 +2611,13 @@ static int __init aty_init(struct fb_info *info, const char *name)
2513 /* these bits let the 101 powerbook wake up from sleep -- paulus */ 2611 /* these bits let the 101 powerbook wake up from sleep -- paulus */
2514 aty_st_lcd(POWER_MANAGEMENT, aty_ld_lcd(POWER_MANAGEMENT, par) 2612 aty_st_lcd(POWER_MANAGEMENT, aty_ld_lcd(POWER_MANAGEMENT, par)
2515 | (USE_F32KHZ | TRISTATE_MEM_EN), par); 2613 | (USE_F32KHZ | TRISTATE_MEM_EN), par);
2516 } else if (M64_HAS(MOBIL_BUS)) 2614 } else
2517 register_backlight_controller(&aty_backlight_controller, info, "ati"); 2615#endif
2518#endif /* CONFIG_PMAC_BACKLIGHT */ 2616 if (M64_HAS(MOBIL_BUS)) {
2617#ifdef CONFIG_FB_ATY_BACKLIGHT
2618 aty_bl_init (par);
2619#endif
2620 }
2519 2621
2520 memset(&var, 0, sizeof(var)); 2622 memset(&var, 0, sizeof(var));
2521#ifdef CONFIG_PPC 2623#ifdef CONFIG_PPC
@@ -2674,8 +2776,16 @@ static int atyfb_blank(int blank, struct fb_info *info)
2674 return 0; 2776 return 0;
2675 2777
2676#ifdef CONFIG_PMAC_BACKLIGHT 2778#ifdef CONFIG_PMAC_BACKLIGHT
2677 if (machine_is(powermac) && blank > FB_BLANK_NORMAL) 2779 if (machine_is(powermac) && blank > FB_BLANK_NORMAL) {
2678 set_backlight_enable(0); 2780 mutex_lock(&info->bl_mutex);
2781 if (info->bl_dev) {
2782 down(&info->bl_dev->sem);
2783 info->bl_dev->props->power = FB_BLANK_POWERDOWN;
2784 info->bl_dev->props->update_status(info->bl_dev);
2785 up(&info->bl_dev->sem);
2786 }
2787 mutex_unlock(&info->bl_mutex);
2788 }
2679#elif defined(CONFIG_FB_ATY_GENERIC_LCD) 2789#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
2680 if (par->lcd_table && blank > FB_BLANK_NORMAL && 2790 if (par->lcd_table && blank > FB_BLANK_NORMAL &&
2681 (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) { 2791 (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
@@ -2706,8 +2816,16 @@ static int atyfb_blank(int blank, struct fb_info *info)
2706 aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par); 2816 aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par);
2707 2817
2708#ifdef CONFIG_PMAC_BACKLIGHT 2818#ifdef CONFIG_PMAC_BACKLIGHT
2709 if (machine_is(powermac) && blank <= FB_BLANK_NORMAL) 2819 if (machine_is(powermac) && blank <= FB_BLANK_NORMAL) {
2710 set_backlight_enable(1); 2820 mutex_lock(&info->bl_mutex);
2821 if (info->bl_dev) {
2822 down(&info->bl_dev->sem);
2823 info->bl_dev->props->power = FB_BLANK_UNBLANK;
2824 info->bl_dev->props->update_status(info->bl_dev);
2825 up(&info->bl_dev->sem);
2826 }
2827 mutex_unlock(&info->bl_mutex);
2828 }
2711#elif defined(CONFIG_FB_ATY_GENERIC_LCD) 2829#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
2712 if (par->lcd_table && blank <= FB_BLANK_NORMAL && 2830 if (par->lcd_table && blank <= FB_BLANK_NORMAL &&
2713 (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) { 2831 (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
3440 par->res_start = res_start; 3558 par->res_start = res_start;
3441 par->res_size = res_size; 3559 par->res_size = res_size;
3442 par->irq = pdev->irq; 3560 par->irq = pdev->irq;
3561 par->pdev = pdev;
3443 3562
3444 /* Setup "info" structure */ 3563 /* Setup "info" structure */
3445#ifdef __sparc__ 3564#ifdef __sparc__
@@ -3571,6 +3690,11 @@ static void __devexit atyfb_remove(struct fb_info *info)
3571 aty_set_crtc(par, &saved_crtc); 3690 aty_set_crtc(par, &saved_crtc);
3572 par->pll_ops->set_pll(info, &saved_pll); 3691 par->pll_ops->set_pll(info, &saved_pll);
3573 3692
3693#ifdef CONFIG_FB_ATY_BACKLIGHT
3694 if (M64_HAS(MOBIL_BUS))
3695 aty_bl_exit(par);
3696#endif
3697
3574 unregister_framebuffer(info); 3698 unregister_framebuffer(info);
3575 3699
3576#ifdef CONFIG_MTRR 3700#ifdef CONFIG_MTRR
diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c
new file mode 100644
index 000000000000..7de66b855d4e
--- /dev/null
+++ b/drivers/video/aty/radeon_backlight.c
@@ -0,0 +1,247 @@
1/*
2 * Backlight code for ATI Radeon based graphic cards
3 *
4 * Copyright (c) 2000 Ani Joshi <ajoshi@kernel.crashing.org>
5 * Copyright (c) 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org>
6 * Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include "radeonfb.h"
14#include <linux/backlight.h>
15
16#ifdef CONFIG_PMAC_BACKLIGHT
17#include <asm/backlight.h>
18#endif
19
20#define MAX_RADEON_LEVEL 0xFF
21
22static struct backlight_properties radeon_bl_data;
23
24struct radeon_bl_privdata {
25 struct radeonfb_info *rinfo;
26 uint8_t negative;
27};
28
29static int radeon_bl_get_level_brightness(struct radeon_bl_privdata *pdata,
30 int level)
31{
32 struct fb_info *info = pdata->rinfo->info;
33 int rlevel;
34
35 mutex_lock(&info->bl_mutex);
36
37 /* Get and convert the value */
38 rlevel = pdata->rinfo->info->bl_curve[level] *
39 FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL;
40
41 mutex_unlock(&info->bl_mutex);
42
43 if (pdata->negative)
44 rlevel = MAX_RADEON_LEVEL - rlevel;
45
46 if (rlevel < 0)
47 rlevel = 0;
48 else if (rlevel > MAX_RADEON_LEVEL)
49 rlevel = MAX_RADEON_LEVEL;
50
51 return rlevel;
52}
53
54static int radeon_bl_update_status(struct backlight_device *bd)
55{
56 struct radeon_bl_privdata *pdata = class_get_devdata(&bd->class_dev);
57 struct radeonfb_info *rinfo = pdata->rinfo;
58 u32 lvds_gen_cntl, tmpPixclksCntl;
59 int level;
60
61 if (rinfo->mon1_type != MT_LCD)
62 return 0;
63
64 /* We turn off the LCD completely instead of just dimming the
65 * backlight. This provides some greater power saving and the display
66 * is useless without backlight anyway.
67 */
68 if (bd->props->power != FB_BLANK_UNBLANK ||
69 bd->props->fb_blank != FB_BLANK_UNBLANK)
70 level = 0;
71 else
72 level = bd->props->brightness;
73
74 del_timer_sync(&rinfo->lvds_timer);
75 radeon_engine_idle();
76
77 lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
78 if (level > 0) {
79 lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
80 if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) {
81 lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON);
82 lvds_gen_cntl |= LVDS_BLON | LVDS_EN;
83 OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
84 lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
85 lvds_gen_cntl |=
86 (radeon_bl_get_level_brightness(pdata, level) <<
87 LVDS_BL_MOD_LEVEL_SHIFT);
88 lvds_gen_cntl |= LVDS_ON;
89 lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN);
90 rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
91 mod_timer(&rinfo->lvds_timer,
92 jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
93 } else {
94 lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
95 lvds_gen_cntl |=
96 (radeon_bl_get_level_brightness(pdata, level) <<
97 LVDS_BL_MOD_LEVEL_SHIFT);
98 OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
99 }
100 rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
101 rinfo->init_state.lvds_gen_cntl |= rinfo->pending_lvds_gen_cntl
102 & LVDS_STATE_MASK;
103 } else {
104 /* Asic bug, when turning off LVDS_ON, we have to make sure
105 RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
106 */
107 tmpPixclksCntl = INPLL(PIXCLKS_CNTL);
108 if (rinfo->is_mobility || rinfo->is_IGP)
109 OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
110 lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN);
111 lvds_gen_cntl |= (radeon_bl_get_level_brightness(pdata, 0) <<
112 LVDS_BL_MOD_LEVEL_SHIFT);
113 lvds_gen_cntl |= LVDS_DISPLAY_DIS;
114 OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
115 udelay(100);
116 lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN);
117 OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
118 lvds_gen_cntl &= ~(LVDS_DIGON);
119 rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
120 mod_timer(&rinfo->lvds_timer,
121 jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
122 if (rinfo->is_mobility || rinfo->is_IGP)
123 OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl);
124 }
125 rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
126 rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK);
127
128 return 0;
129}
130
131static int radeon_bl_get_brightness(struct backlight_device *bd)
132{
133 return bd->props->brightness;
134}
135
136static struct backlight_properties radeon_bl_data = {
137 .owner = THIS_MODULE,
138 .get_brightness = radeon_bl_get_brightness,
139 .update_status = radeon_bl_update_status,
140 .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
141};
142
143void radeonfb_bl_init(struct radeonfb_info *rinfo)
144{
145 struct backlight_device *bd;
146 struct radeon_bl_privdata *pdata;
147 char name[12];
148
149 if (rinfo->mon1_type != MT_LCD)
150 return;
151
152#ifdef CONFIG_PMAC_BACKLIGHT
153 if (!pmac_has_backlight_type("ati") &&
154 !pmac_has_backlight_type("mnca"))
155 return;
156#endif
157
158 pdata = kmalloc(sizeof(struct radeon_bl_privdata), GFP_KERNEL);
159 if (!pdata) {
160 printk("radeonfb: Memory allocation failed\n");
161 goto error;
162 }
163
164 snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node);
165
166 bd = backlight_device_register(name, pdata, &radeon_bl_data);
167 if (IS_ERR(bd)) {
168 rinfo->info->bl_dev = NULL;
169 printk("radeonfb: Backlight registration failed\n");
170 goto error;
171 }
172
173 pdata->rinfo = rinfo;
174
175 /* Pardon me for that hack... maybe some day we can figure out in what
176 * direction backlight should work on a given panel?
177 */
178 pdata->negative =
179 (rinfo->family != CHIP_FAMILY_RV200 &&
180 rinfo->family != CHIP_FAMILY_RV250 &&
181 rinfo->family != CHIP_FAMILY_RV280 &&
182 rinfo->family != CHIP_FAMILY_RV350);
183
184#ifdef CONFIG_PMAC_BACKLIGHT
185 pdata->negative = pdata->negative ||
186 machine_is_compatible("PowerBook4,3") ||
187 machine_is_compatible("PowerBook6,3") ||
188 machine_is_compatible("PowerBook6,5");
189#endif
190
191 mutex_lock(&rinfo->info->bl_mutex);
192 rinfo->info->bl_dev = bd;
193 fb_bl_default_curve(rinfo->info, 0,
194 63 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL,
195 217 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL);
196 mutex_unlock(&rinfo->info->bl_mutex);
197
198 up(&bd->sem);
199 bd->props->brightness = radeon_bl_data.max_brightness;
200 bd->props->power = FB_BLANK_UNBLANK;
201 bd->props->update_status(bd);
202 down(&bd->sem);
203
204#ifdef CONFIG_PMAC_BACKLIGHT
205 mutex_lock(&pmac_backlight_mutex);
206 if (!pmac_backlight)
207 pmac_backlight = bd;
208 mutex_unlock(&pmac_backlight_mutex);
209#endif
210
211 printk("radeonfb: Backlight initialized (%s)\n", name);
212
213 return;
214
215error:
216 kfree(pdata);
217 return;
218}
219
220void radeonfb_bl_exit(struct radeonfb_info *rinfo)
221{
222#ifdef CONFIG_PMAC_BACKLIGHT
223 mutex_lock(&pmac_backlight_mutex);
224#endif
225
226 mutex_lock(&rinfo->info->bl_mutex);
227 if (rinfo->info->bl_dev) {
228 struct radeon_bl_privdata *pdata;
229
230#ifdef CONFIG_PMAC_BACKLIGHT
231 if (pmac_backlight == rinfo->info->bl_dev)
232 pmac_backlight = NULL;
233#endif
234
235 pdata = class_get_devdata(&rinfo->info->bl_dev->class_dev);
236 backlight_device_unregister(rinfo->info->bl_dev);
237 kfree(pdata);
238 rinfo->info->bl_dev = NULL;
239
240 printk("radeonfb: Backlight unloaded\n");
241 }
242 mutex_unlock(&rinfo->info->bl_mutex);
243
244#ifdef CONFIG_PMAC_BACKLIGHT
245 mutex_unlock(&pmac_backlight_mutex);
246#endif
247}
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 387a18a47ac2..c5ecbb02e01d 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -78,10 +78,6 @@
78#include <asm/pci-bridge.h> 78#include <asm/pci-bridge.h>
79#include "../macmodes.h" 79#include "../macmodes.h"
80 80
81#ifdef CONFIG_PMAC_BACKLIGHT
82#include <asm/backlight.h>
83#endif
84
85#ifdef CONFIG_BOOTX_TEXT 81#ifdef CONFIG_BOOTX_TEXT
86#include <asm/btext.h> 82#include <asm/btext.h>
87#endif 83#endif
@@ -277,20 +273,6 @@ static int nomtrr = 0;
277 * prototypes 273 * prototypes
278 */ 274 */
279 275
280
281#ifdef CONFIG_PPC_OF
282
283#ifdef CONFIG_PMAC_BACKLIGHT
284static int radeon_set_backlight_enable(int on, int level, void *data);
285static int radeon_set_backlight_level(int level, void *data);
286static struct backlight_controller radeon_backlight_controller = {
287 radeon_set_backlight_enable,
288 radeon_set_backlight_level
289};
290#endif /* CONFIG_PMAC_BACKLIGHT */
291
292#endif /* CONFIG_PPC_OF */
293
294static void radeon_unmap_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev) 276static void radeon_unmap_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev)
295{ 277{
296 if (!rinfo->bios_seg) 278 if (!rinfo->bios_seg)
@@ -1913,116 +1895,6 @@ static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo)
1913 return 0; 1895 return 0;
1914} 1896}
1915 1897
1916
1917#ifdef CONFIG_PMAC_BACKLIGHT
1918
1919/* TODO: Dbl check these tables, we don't go up to full ON backlight
1920 * in these, possibly because we noticed MacOS doesn't, but I'd prefer
1921 * having some more official numbers from ATI
1922 */
1923static int backlight_conv_m6[] = {
1924 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
1925 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
1926};
1927static int backlight_conv_m7[] = {
1928 0x00, 0x3f, 0x4a, 0x55, 0x60, 0x6b, 0x76, 0x81,
1929 0x8c, 0x97, 0xa2, 0xad, 0xb8, 0xc3, 0xce, 0xd9
1930};
1931
1932#define BACKLIGHT_LVDS_OFF
1933#undef BACKLIGHT_DAC_OFF
1934
1935/* We turn off the LCD completely instead of just dimming the backlight.
1936 * This provides some greater power saving and the display is useless
1937 * without backlight anyway.
1938 */
1939static int radeon_set_backlight_enable(int on, int level, void *data)
1940{
1941 struct radeonfb_info *rinfo = (struct radeonfb_info *)data;
1942 u32 lvds_gen_cntl, tmpPixclksCntl;
1943 int* conv_table;
1944
1945 if (rinfo->mon1_type != MT_LCD)
1946 return 0;
1947
1948 /* Pardon me for that hack... maybe some day we can figure
1949 * out in what direction backlight should work on a given
1950 * panel ?
1951 */
1952 if ((rinfo->family == CHIP_FAMILY_RV200 ||
1953 rinfo->family == CHIP_FAMILY_RV250 ||
1954 rinfo->family == CHIP_FAMILY_RV280 ||
1955 rinfo->family == CHIP_FAMILY_RV350) &&
1956 !machine_is_compatible("PowerBook4,3") &&
1957 !machine_is_compatible("PowerBook6,3") &&
1958 !machine_is_compatible("PowerBook6,5"))
1959 conv_table = backlight_conv_m7;
1960 else
1961 conv_table = backlight_conv_m6;
1962
1963 del_timer_sync(&rinfo->lvds_timer);
1964 radeon_engine_idle();
1965
1966 lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
1967 if (on && (level > BACKLIGHT_OFF)) {
1968 lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
1969 if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) {
1970 lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON);
1971 lvds_gen_cntl |= LVDS_BLON | LVDS_EN;
1972 OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
1973 lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
1974 lvds_gen_cntl |= (conv_table[level] <<
1975 LVDS_BL_MOD_LEVEL_SHIFT);
1976 lvds_gen_cntl |= LVDS_ON;
1977 lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN);
1978 rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
1979 mod_timer(&rinfo->lvds_timer,
1980 jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
1981 } else {
1982 lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
1983 lvds_gen_cntl |= (conv_table[level] <<
1984 LVDS_BL_MOD_LEVEL_SHIFT);
1985 OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
1986 }
1987 rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
1988 rinfo->init_state.lvds_gen_cntl |= rinfo->pending_lvds_gen_cntl
1989 & LVDS_STATE_MASK;
1990 } else {
1991 /* Asic bug, when turning off LVDS_ON, we have to make sure
1992 RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
1993 */
1994 tmpPixclksCntl = INPLL(PIXCLKS_CNTL);
1995 if (rinfo->is_mobility || rinfo->is_IGP)
1996 OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
1997 lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN);
1998 lvds_gen_cntl |= (conv_table[0] <<
1999 LVDS_BL_MOD_LEVEL_SHIFT);
2000 lvds_gen_cntl |= LVDS_DISPLAY_DIS;
2001 OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
2002 udelay(100);
2003 lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN);
2004 OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
2005 lvds_gen_cntl &= ~(LVDS_DIGON);
2006 rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
2007 mod_timer(&rinfo->lvds_timer,
2008 jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
2009 if (rinfo->is_mobility || rinfo->is_IGP)
2010 OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl);
2011 }
2012 rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
2013 rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK);
2014
2015 return 0;
2016}
2017
2018
2019static int radeon_set_backlight_level(int level, void *data)
2020{
2021 return radeon_set_backlight_enable(1, level, data);
2022}
2023#endif /* CONFIG_PMAC_BACKLIGHT */
2024
2025
2026/* 1898/*
2027 * This reconfigure the card's internal memory map. In theory, we'd like 1899 * This reconfigure the card's internal memory map. In theory, we'd like
2028 * to setup the card's memory at the same address as it's PCI bus address, 1900 * 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,
2477 MTRR_TYPE_WRCOMB, 1); 2349 MTRR_TYPE_WRCOMB, 1);
2478#endif 2350#endif
2479 2351
2480#ifdef CONFIG_PMAC_BACKLIGHT 2352 radeonfb_bl_init(rinfo);
2481 if (rinfo->mon1_type == MT_LCD) {
2482 register_backlight_controller(&radeon_backlight_controller,
2483 rinfo, "ati");
2484 register_backlight_controller(&radeon_backlight_controller,
2485 rinfo, "mnca");
2486 }
2487#endif
2488 2353
2489 printk ("radeonfb (%s): %s\n", pci_name(rinfo->pdev), rinfo->name); 2354 printk ("radeonfb (%s): %s\n", pci_name(rinfo->pdev), rinfo->name);
2490 2355
@@ -2528,7 +2393,8 @@ static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev)
2528 2393
2529 if (!rinfo) 2394 if (!rinfo)
2530 return; 2395 return;
2531 2396
2397 radeonfb_bl_exit(rinfo);
2532 radeonfb_pm_exit(rinfo); 2398 radeonfb_pm_exit(rinfo);
2533 2399
2534 if (rinfo->mon1_EDID) 2400 if (rinfo->mon1_EDID)
diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h
index 217e00ab4a2d..1645943b1123 100644
--- a/drivers/video/aty/radeonfb.h
+++ b/drivers/video/aty/radeonfb.h
@@ -625,4 +625,13 @@ extern int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_
625extern void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode, 625extern void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode,
626 int reg_only); 626 int reg_only);
627 627
628/* Backlight functions */
629#ifdef CONFIG_FB_RADEON_BACKLIGHT
630extern void radeonfb_bl_init(struct radeonfb_info *rinfo);
631extern void radeonfb_bl_exit(struct radeonfb_info *rinfo);
632#else
633static inline void radeonfb_bl_init(struct radeonfb_info *rinfo) {}
634static inline void radeonfb_bl_exit(struct radeonfb_info *rinfo) {}
635#endif
636
628#endif /* __RADEONFB_H__ */ 637#endif /* __RADEONFB_H__ */
diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c
index 72ff6bf75e5e..d76bbfac92cc 100644
--- a/drivers/video/chipsfb.c
+++ b/drivers/video/chipsfb.c
@@ -148,9 +148,24 @@ static int chipsfb_set_par(struct fb_info *info)
148static int chipsfb_blank(int blank, struct fb_info *info) 148static int chipsfb_blank(int blank, struct fb_info *info)
149{ 149{
150#ifdef CONFIG_PMAC_BACKLIGHT 150#ifdef CONFIG_PMAC_BACKLIGHT
151 // used to disable backlight only for blank > 1, but it seems 151 mutex_lock(&pmac_backlight_mutex);
152 // useful at blank = 1 too (saves battery, extends backlight life) 152
153 set_backlight_enable(!blank); 153 if (pmac_backlight) {
154 down(&pmac_backlight->sem);
155
156 /* used to disable backlight only for blank > 1, but it seems
157 * useful at blank = 1 too (saves battery, extends backlight
158 * life)
159 */
160 if (blank)
161 pmac_backlight->props->power = FB_BLANK_POWERDOWN;
162 else
163 pmac_backlight->props->power = FB_BLANK_UNBLANK;
164 pmac_backlight->props->update_status(pmac_backlight);
165 up(&pmac_backlight->sem);
166 }
167
168 mutex_unlock(&pmac_backlight_mutex);
154#endif /* CONFIG_PMAC_BACKLIGHT */ 169#endif /* CONFIG_PMAC_BACKLIGHT */
155 170
156 return 1; /* get fb_blank to set the colormap to all black */ 171 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)
401 416
402#ifdef CONFIG_PMAC_BACKLIGHT 417#ifdef CONFIG_PMAC_BACKLIGHT
403 /* turn on the backlight */ 418 /* turn on the backlight */
404 set_backlight_enable(1); 419 mutex_lock(&pmac_backlight_mutex);
420 if (pmac_backlight) {
421 down(&pmac_backlight->sem);
422 pmac_backlight->props->power = FB_BLANK_UNBLANK;
423 pmac_backlight->props->update_status(pmac_backlight);
424 up(&pmac_backlight->sem);
425 }
426 mutex_unlock(&pmac_backlight_mutex);
405#endif /* CONFIG_PMAC_BACKLIGHT */ 427#endif /* CONFIG_PMAC_BACKLIGHT */
406 428
407#ifdef CONFIG_PPC 429#ifdef CONFIG_PPC
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
index 34e07399756b..3ceb8c1b392e 100644
--- a/drivers/video/fbsysfs.c
+++ b/drivers/video/fbsysfs.c
@@ -18,6 +18,7 @@
18#include <linux/kernel.h> 18#include <linux/kernel.h>
19#include <linux/fb.h> 19#include <linux/fb.h>
20#include <linux/console.h> 20#include <linux/console.h>
21#include <linux/module.h>
21 22
22/** 23/**
23 * framebuffer_alloc - creates a new frame buffer info structure 24 * framebuffer_alloc - creates a new frame buffer info structure
@@ -55,6 +56,10 @@ struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
55 56
56 info->device = dev; 57 info->device = dev;
57 58
59#ifdef CONFIG_FB_BACKLIGHT
60 mutex_init(&info->bl_mutex);
61#endif
62
58 return info; 63 return info;
59#undef PADDING 64#undef PADDING
60#undef BYTES_PER_LONG 65#undef BYTES_PER_LONG
@@ -414,6 +419,65 @@ static ssize_t show_fbstate(struct class_device *class_device, char *buf)
414 return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->state); 419 return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->state);
415} 420}
416 421
422#ifdef CONFIG_FB_BACKLIGHT
423static ssize_t store_bl_curve(struct class_device *class_device,
424 const char *buf, size_t count)
425{
426 struct fb_info *fb_info = class_get_devdata(class_device);
427 u8 tmp_curve[FB_BACKLIGHT_LEVELS];
428 unsigned int i;
429
430 if (count != (FB_BACKLIGHT_LEVELS / 8 * 24))
431 return -EINVAL;
432
433 for (i = 0; i < (FB_BACKLIGHT_LEVELS / 8); ++i)
434 if (sscanf(&buf[i * 24],
435 "%2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx\n",
436 &tmp_curve[i * 8 + 0],
437 &tmp_curve[i * 8 + 1],
438 &tmp_curve[i * 8 + 2],
439 &tmp_curve[i * 8 + 3],
440 &tmp_curve[i * 8 + 4],
441 &tmp_curve[i * 8 + 5],
442 &tmp_curve[i * 8 + 6],
443 &tmp_curve[i * 8 + 7]) != 8)
444 return -EINVAL;
445
446 /* If there has been an error in the input data, we won't
447 * reach this loop.
448 */
449 mutex_lock(&fb_info->bl_mutex);
450 for (i = 0; i < FB_BACKLIGHT_LEVELS; ++i)
451 fb_info->bl_curve[i] = tmp_curve[i];
452 mutex_unlock(&fb_info->bl_mutex);
453
454 return count;
455}
456
457static ssize_t show_bl_curve(struct class_device *class_device, char *buf)
458{
459 struct fb_info *fb_info = class_get_devdata(class_device);
460 ssize_t len = 0;
461 unsigned int i;
462
463 mutex_lock(&fb_info->bl_mutex);
464 for (i = 0; i < FB_BACKLIGHT_LEVELS; i += 8)
465 len += snprintf(&buf[len], PAGE_SIZE,
466 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
467 fb_info->bl_curve[i + 0],
468 fb_info->bl_curve[i + 1],
469 fb_info->bl_curve[i + 2],
470 fb_info->bl_curve[i + 3],
471 fb_info->bl_curve[i + 4],
472 fb_info->bl_curve[i + 5],
473 fb_info->bl_curve[i + 6],
474 fb_info->bl_curve[i + 7]);
475 mutex_unlock(&fb_info->bl_mutex);
476
477 return len;
478}
479#endif
480
417/* When cmap is added back in it should be a binary attribute 481/* When cmap is added back in it should be a binary attribute
418 * not a text one. Consideration should also be given to converting 482 * not a text one. Consideration should also be given to converting
419 * fbdev to use configfs instead of sysfs */ 483 * fbdev to use configfs instead of sysfs */
@@ -432,6 +496,9 @@ static struct class_device_attribute class_device_attrs[] = {
432 __ATTR(con_rotate, S_IRUGO|S_IWUSR, show_con_rotate, store_con_rotate), 496 __ATTR(con_rotate, S_IRUGO|S_IWUSR, show_con_rotate, store_con_rotate),
433 __ATTR(con_rotate_all, S_IWUSR, NULL, store_con_rotate_all), 497 __ATTR(con_rotate_all, S_IWUSR, NULL, store_con_rotate_all),
434 __ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate), 498 __ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate),
499#ifdef CONFIG_FB_BACKLIGHT
500 __ATTR(bl_curve, S_IRUGO|S_IWUSR, show_bl_curve, store_bl_curve),
501#endif
435}; 502};
436 503
437int fb_init_class_device(struct fb_info *fb_info) 504int fb_init_class_device(struct fb_info *fb_info)
@@ -454,4 +521,25 @@ void fb_cleanup_class_device(struct fb_info *fb_info)
454 &class_device_attrs[i]); 521 &class_device_attrs[i]);
455} 522}
456 523
524#ifdef CONFIG_FB_BACKLIGHT
525/* This function generates a linear backlight curve
526 *
527 * 0: off
528 * 1-7: min
529 * 8-127: linear from min to max
530 */
531void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max)
532{
533 unsigned int i, flat, count, range = (max - min);
534
535 fb_info->bl_curve[0] = off;
457 536
537 for (flat = 1; flat < (FB_BACKLIGHT_LEVELS / 16); ++flat)
538 fb_info->bl_curve[flat] = min;
539
540 count = FB_BACKLIGHT_LEVELS * 15 / 16;
541 for (i = 0; i < count; ++i)
542 fb_info->bl_curve[flat + i] = min + (range * (i + 1) / count);
543}
544EXPORT_SYMBOL_GPL(fb_bl_default_curve);
545#endif
diff --git a/drivers/video/nvidia/Makefile b/drivers/video/nvidia/Makefile
index 690d37e8de5b..ca47432113e0 100644
--- a/drivers/video/nvidia/Makefile
+++ b/drivers/video/nvidia/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_FB_NVIDIA) += nvidiafb.o
7nvidiafb-y := nvidia.o nv_hw.o nv_setup.o \ 7nvidiafb-y := nvidia.o nv_hw.o nv_setup.o \
8 nv_accel.o 8 nv_accel.o
9nvidiafb-$(CONFIG_FB_NVIDIA_I2C) += nv_i2c.o 9nvidiafb-$(CONFIG_FB_NVIDIA_I2C) += nv_i2c.o
10nvidiafb-$(CONFIG_FB_NVIDIA_BACKLIGHT) += nv_backlight.o
10nvidiafb-$(CONFIG_PPC_OF) += nv_of.o 11nvidiafb-$(CONFIG_PPC_OF) += nv_of.o
11 12
12nvidiafb-objs := $(nvidiafb-y) \ No newline at end of file 13nvidiafb-objs := $(nvidiafb-y)
diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c
new file mode 100644
index 000000000000..1c1c10c699c5
--- /dev/null
+++ b/drivers/video/nvidia/nv_backlight.c
@@ -0,0 +1,175 @@
1/*
2 * Backlight code for nVidia based graphic cards
3 *
4 * Copyright 2004 Antonino Daplas <adaplas@pol.net>
5 * Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/backlight.h>
13#include <linux/fb.h>
14#include <linux/pci.h>
15#include "nv_local.h"
16#include "nv_type.h"
17#include "nv_proto.h"
18
19#ifdef CONFIG_PMAC_BACKLIGHT
20#include <asm/backlight.h>
21#include <asm/machdep.h>
22#endif
23
24/* We do not have any information about which values are allowed, thus
25 * we used safe values.
26 */
27#define MIN_LEVEL 0x158
28#define MAX_LEVEL 0x534
29
30static struct backlight_properties nvidia_bl_data;
31
32static int nvidia_bl_get_level_brightness(struct nvidia_par *par,
33 int level)
34{
35 struct fb_info *info = pci_get_drvdata(par->pci_dev);
36 int nlevel;
37
38 /* Get and convert the value */
39 mutex_lock(&info->bl_mutex);
40 nlevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
41 mutex_unlock(&info->bl_mutex);
42
43 if (nlevel < 0)
44 nlevel = 0;
45 else if (nlevel < MIN_LEVEL)
46 nlevel = MIN_LEVEL;
47 else if (nlevel > MAX_LEVEL)
48 nlevel = MAX_LEVEL;
49
50 return nlevel;
51}
52
53static int nvidia_bl_update_status(struct backlight_device *bd)
54{
55 struct nvidia_par *par = class_get_devdata(&bd->class_dev);
56 u32 tmp_pcrt, tmp_pmc, fpcontrol;
57 int level;
58
59 if (!par->FlatPanel)
60 return 0;
61
62 if (bd->props->power != FB_BLANK_UNBLANK ||
63 bd->props->fb_blank != FB_BLANK_UNBLANK)
64 level = 0;
65 else
66 level = bd->props->brightness;
67
68 tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF;
69 tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC;
70 fpcontrol = NV_RD32(par->PRAMDAC, 0x0848) & 0xCFFFFFCC;
71
72 if (level > 0) {
73 tmp_pcrt |= 0x1;
74 tmp_pmc |= (1 << 31); /* backlight bit */
75 tmp_pmc |= nvidia_bl_get_level_brightness(par, level) << 16;
76 fpcontrol |= par->fpSyncs;
77 } else
78 fpcontrol |= 0x20000022;
79
80 NV_WR32(par->PCRTC0, 0x081C, tmp_pcrt);
81 NV_WR32(par->PMC, 0x10F0, tmp_pmc);
82 NV_WR32(par->PRAMDAC, 0x848, fpcontrol);
83
84 return 0;
85}
86
87static int nvidia_bl_get_brightness(struct backlight_device *bd)
88{
89 return bd->props->brightness;
90}
91
92static struct backlight_properties nvidia_bl_data = {
93 .owner = THIS_MODULE,
94 .get_brightness = nvidia_bl_get_brightness,
95 .update_status = nvidia_bl_update_status,
96 .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
97};
98
99void nvidia_bl_init(struct nvidia_par *par)
100{
101 struct fb_info *info = pci_get_drvdata(par->pci_dev);
102 struct backlight_device *bd;
103 char name[12];
104
105 if (!par->FlatPanel)
106 return;
107
108#ifdef CONFIG_PMAC_BACKLIGHT
109 if (!machine_is(powermac) ||
110 !pmac_has_backlight_type("mnca"))
111 return;
112#endif
113
114 snprintf(name, sizeof(name), "nvidiabl%d", info->node);
115
116 bd = backlight_device_register(name, par, &nvidia_bl_data);
117 if (IS_ERR(bd)) {
118 info->bl_dev = NULL;
119 printk("nvidia: Backlight registration failed\n");
120 goto error;
121 }
122
123 mutex_lock(&info->bl_mutex);
124 info->bl_dev = bd;
125 fb_bl_default_curve(info, 0,
126 0x158 * FB_BACKLIGHT_MAX / MAX_LEVEL,
127 0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL);
128 mutex_unlock(&info->bl_mutex);
129
130 up(&bd->sem);
131 bd->props->brightness = nvidia_bl_data.max_brightness;
132 bd->props->power = FB_BLANK_UNBLANK;
133 bd->props->update_status(bd);
134 down(&bd->sem);
135
136#ifdef CONFIG_PMAC_BACKLIGHT
137 mutex_lock(&pmac_backlight_mutex);
138 if (!pmac_backlight)
139 pmac_backlight = bd;
140 mutex_unlock(&pmac_backlight_mutex);
141#endif
142
143 printk("nvidia: Backlight initialized (%s)\n", name);
144
145 return;
146
147error:
148 return;
149}
150
151void nvidia_bl_exit(struct nvidia_par *par)
152{
153 struct fb_info *info = pci_get_drvdata(par->pci_dev);
154
155#ifdef CONFIG_PMAC_BACKLIGHT
156 mutex_lock(&pmac_backlight_mutex);
157#endif
158
159 mutex_lock(&info->bl_mutex);
160 if (info->bl_dev) {
161#ifdef CONFIG_PMAC_BACKLIGHT
162 if (pmac_backlight == info->bl_dev)
163 pmac_backlight = NULL;
164#endif
165
166 backlight_device_unregister(info->bl_dev);
167
168 printk("nvidia: Backlight unloaded\n");
169 }
170 mutex_unlock(&info->bl_mutex);
171
172#ifdef CONFIG_PMAC_BACKLIGHT
173 mutex_unlock(&pmac_backlight_mutex);
174#endif
175}
diff --git a/drivers/video/nvidia/nv_proto.h b/drivers/video/nvidia/nv_proto.h
index b149a690ee0f..6fba656cd56b 100644
--- a/drivers/video/nvidia/nv_proto.h
+++ b/drivers/video/nvidia/nv_proto.h
@@ -63,4 +63,14 @@ extern void nvidiafb_imageblit(struct fb_info *info,
63 const struct fb_image *image); 63 const struct fb_image *image);
64extern int nvidiafb_sync(struct fb_info *info); 64extern int nvidiafb_sync(struct fb_info *info);
65extern u8 byte_rev[256]; 65extern u8 byte_rev[256];
66
67/* in nv_backlight.h */
68#ifdef CONFIG_FB_NVIDIA_BACKLIGHT
69extern void nvidia_bl_init(struct nvidia_par *par);
70extern void nvidia_bl_exit(struct nvidia_par *par);
71#else
72static inline void nvidia_bl_init(struct nvidia_par *par) {}
73static inline void nvidia_bl_exit(struct nvidia_par *par) {}
74#endif
75
66#endif /* __NV_PROTO_H__ */ 76#endif /* __NV_PROTO_H__ */
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index 093ab9977c7c..03a7c1e9ce38 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -22,6 +22,7 @@
22#include <linux/init.h> 22#include <linux/init.h>
23#include <linux/pci.h> 23#include <linux/pci.h>
24#include <linux/console.h> 24#include <linux/console.h>
25#include <linux/backlight.h>
25#ifdef CONFIG_MTRR 26#ifdef CONFIG_MTRR
26#include <asm/mtrr.h> 27#include <asm/mtrr.h>
27#endif 28#endif
@@ -29,10 +30,6 @@
29#include <asm/prom.h> 30#include <asm/prom.h>
30#include <asm/pci-bridge.h> 31#include <asm/pci-bridge.h>
31#endif 32#endif
32#ifdef CONFIG_PMAC_BACKLIGHT
33#include <asm/machdep.h>
34#include <asm/backlight.h>
35#endif
36 33
37#include "nv_local.h" 34#include "nv_local.h"
38#include "nv_type.h" 35#include "nv_type.h"
@@ -470,75 +467,6 @@ static struct fb_var_screeninfo __devinitdata nvidiafb_default_var = {
470 .vmode = FB_VMODE_NONINTERLACED 467 .vmode = FB_VMODE_NONINTERLACED
471}; 468};
472 469
473/*
474 * Backlight control
475 */
476#ifdef CONFIG_PMAC_BACKLIGHT
477
478static int nvidia_backlight_levels[] = {
479 0x158,
480 0x192,
481 0x1c6,
482 0x200,
483 0x234,
484 0x268,
485 0x2a2,
486 0x2d6,
487 0x310,
488 0x344,
489 0x378,
490 0x3b2,
491 0x3e6,
492 0x41a,
493 0x454,
494 0x534,
495};
496
497/* ------------------------------------------------------------------------- *
498 *
499 * Backlight operations
500 *
501 * ------------------------------------------------------------------------- */
502
503static int nvidia_set_backlight_enable(int on, int level, void *data)
504{
505 struct nvidia_par *par = data;
506 u32 tmp_pcrt, tmp_pmc, fpcontrol;
507
508 tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF;
509 tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC;
510 fpcontrol = NV_RD32(par->PRAMDAC, 0x0848) & 0xCFFFFFCC;
511
512 if (on && (level > BACKLIGHT_OFF)) {
513 tmp_pcrt |= 0x1;
514 tmp_pmc |= (1 << 31); // backlight bit
515 tmp_pmc |= nvidia_backlight_levels[level - 1] << 16;
516 }
517
518 if (on)
519 fpcontrol |= par->fpSyncs;
520 else
521 fpcontrol |= 0x20000022;
522
523 NV_WR32(par->PCRTC0, 0x081C, tmp_pcrt);
524 NV_WR32(par->PMC, 0x10F0, tmp_pmc);
525 NV_WR32(par->PRAMDAC, 0x848, fpcontrol);
526
527 return 0;
528}
529
530static int nvidia_set_backlight_level(int level, void *data)
531{
532 return nvidia_set_backlight_enable(1, level, data);
533}
534
535static struct backlight_controller nvidia_backlight_controller = {
536 nvidia_set_backlight_enable,
537 nvidia_set_backlight_level
538};
539
540#endif /* CONFIG_PMAC_BACKLIGHT */
541
542static void nvidiafb_load_cursor_image(struct nvidia_par *par, u8 * data8, 470static void nvidiafb_load_cursor_image(struct nvidia_par *par, u8 * data8,
543 u16 bg, u16 fg, u32 w, u32 h) 471 u16 bg, u16 fg, u32 w, u32 h)
544{ 472{
@@ -1355,10 +1283,15 @@ static int nvidiafb_blank(int blank, struct fb_info *info)
1355 NVWriteSeq(par, 0x01, tmp); 1283 NVWriteSeq(par, 0x01, tmp);
1356 NVWriteCrtc(par, 0x1a, vesa); 1284 NVWriteCrtc(par, 0x1a, vesa);
1357 1285
1358#ifdef CONFIG_PMAC_BACKLIGHT 1286#ifdef CONFIG_FB_NVIDIA_BACKLIGHT
1359 if (par->FlatPanel && machine_is(powermac)) { 1287 mutex_lock(&info->bl_mutex);
1360 set_backlight_enable(!blank); 1288 if (info->bl_dev) {
1289 down(&info->bl_dev->sem);
1290 info->bl_dev->props->power = blank;
1291 info->bl_dev->props->update_status(info->bl_dev);
1292 up(&info->bl_dev->sem);
1361 } 1293 }
1294 mutex_unlock(&info->bl_mutex);
1362#endif 1295#endif
1363 1296
1364 NVTRACE_LEAVE(); 1297 NVTRACE_LEAVE();
@@ -1741,11 +1674,9 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd,
1741 "PCI nVidia %s framebuffer (%dMB @ 0x%lX)\n", 1674 "PCI nVidia %s framebuffer (%dMB @ 0x%lX)\n",
1742 info->fix.id, 1675 info->fix.id,
1743 par->FbMapSize / (1024 * 1024), info->fix.smem_start); 1676 par->FbMapSize / (1024 * 1024), info->fix.smem_start);
1744#ifdef CONFIG_PMAC_BACKLIGHT 1677
1745 if (par->FlatPanel && machine_is(powermac)) 1678 nvidia_bl_init(par);
1746 register_backlight_controller(&nvidia_backlight_controller, 1679
1747 par, "mnca");
1748#endif
1749 NVTRACE_LEAVE(); 1680 NVTRACE_LEAVE();
1750 return 0; 1681 return 0;
1751 1682
@@ -1775,6 +1706,8 @@ static void __exit nvidiafb_remove(struct pci_dev *pd)
1775 1706
1776 NVTRACE_ENTER(); 1707 NVTRACE_ENTER();
1777 1708
1709 nvidia_bl_exit(par);
1710
1778 unregister_framebuffer(info); 1711 unregister_framebuffer(info);
1779#ifdef CONFIG_MTRR 1712#ifdef CONFIG_MTRR
1780 if (par->mtrr.vram_valid) 1713 if (par->mtrr.vram_valid)
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index 3e9308f0f165..d4384ab1df65 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -41,6 +41,7 @@
41#include <linux/fb.h> 41#include <linux/fb.h>
42#include <linux/init.h> 42#include <linux/init.h>
43#include <linux/pci.h> 43#include <linux/pci.h>
44#include <linux/backlight.h>
44#ifdef CONFIG_MTRR 45#ifdef CONFIG_MTRR
45#include <asm/mtrr.h> 46#include <asm/mtrr.h>
46#endif 47#endif
@@ -272,34 +273,154 @@ static const struct riva_regs reg_template = {
272/* 273/*
273 * Backlight control 274 * Backlight control
274 */ 275 */
275#ifdef CONFIG_PMAC_BACKLIGHT 276#ifdef CONFIG_FB_RIVA_BACKLIGHT
277/* We do not have any information about which values are allowed, thus
278 * we used safe values.
279 */
280#define MIN_LEVEL 0x158
281#define MAX_LEVEL 0x534
276 282
277static int riva_backlight_levels[] = { 283static struct backlight_properties riva_bl_data;
278 0x158, 284
279 0x192, 285static int riva_bl_get_level_brightness(struct riva_par *par,
280 0x1c6, 286 int level)
281 0x200, 287{
282 0x234, 288 struct fb_info *info = pci_get_drvdata(par->pdev);
283 0x268, 289 int nlevel;
284 0x2a2, 290
285 0x2d6, 291 /* Get and convert the value */
286 0x310, 292 mutex_lock(&info->bl_mutex);
287 0x344, 293 nlevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
288 0x378, 294 mutex_unlock(&info->bl_mutex);
289 0x3b2, 295
290 0x3e6, 296 if (nlevel < 0)
291 0x41a, 297 nlevel = 0;
292 0x454, 298 else if (nlevel < MIN_LEVEL)
293 0x534, 299 nlevel = MIN_LEVEL;
294}; 300 else if (nlevel > MAX_LEVEL)
301 nlevel = MAX_LEVEL;
302
303 return nlevel;
304}
305
306static int riva_bl_update_status(struct backlight_device *bd)
307{
308 struct riva_par *par = class_get_devdata(&bd->class_dev);
309 U032 tmp_pcrt, tmp_pmc;
310 int level;
311
312 if (bd->props->power != FB_BLANK_UNBLANK ||
313 bd->props->fb_blank != FB_BLANK_UNBLANK)
314 level = 0;
315 else
316 level = bd->props->brightness;
317
318 tmp_pmc = par->riva.PMC[0x10F0/4] & 0x0000FFFF;
319 tmp_pcrt = par->riva.PCRTC0[0x081C/4] & 0xFFFFFFFC;
320 if(level > 0) {
321 tmp_pcrt |= 0x1;
322 tmp_pmc |= (1 << 31); /* backlight bit */
323 tmp_pmc |= riva_bl_get_level_brightness(par, level) << 16; /* level */
324 }
325 par->riva.PCRTC0[0x081C/4] = tmp_pcrt;
326 par->riva.PMC[0x10F0/4] = tmp_pmc;
327
328 return 0;
329}
330
331static int riva_bl_get_brightness(struct backlight_device *bd)
332{
333 return bd->props->brightness;
334}
295 335
296static int riva_set_backlight_enable(int on, int level, void *data); 336static struct backlight_properties riva_bl_data = {
297static int riva_set_backlight_level(int level, void *data); 337 .owner = THIS_MODULE,
298static struct backlight_controller riva_backlight_controller = { 338 .get_brightness = riva_bl_get_brightness,
299 riva_set_backlight_enable, 339 .update_status = riva_bl_update_status,
300 riva_set_backlight_level 340 .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
301}; 341};
302#endif /* CONFIG_PMAC_BACKLIGHT */ 342
343static void riva_bl_init(struct riva_par *par)
344{
345 struct fb_info *info = pci_get_drvdata(par->pdev);
346 struct backlight_device *bd;
347 char name[12];
348
349 if (!par->FlatPanel)
350 return;
351
352#ifdef CONFIG_PMAC_BACKLIGHT
353 if (!machine_is(powermac) ||
354 !pmac_has_backlight_type("mnca"))
355 return;
356#endif
357
358 snprintf(name, sizeof(name), "rivabl%d", info->node);
359
360 bd = backlight_device_register(name, par, &riva_bl_data);
361 if (IS_ERR(bd)) {
362 info->bl_dev = NULL;
363 printk("riva: Backlight registration failed\n");
364 goto error;
365 }
366
367 mutex_lock(&info->bl_mutex);
368 info->bl_dev = bd;
369 fb_bl_default_curve(info, 0,
370 0x158 * FB_BACKLIGHT_MAX / MAX_LEVEL,
371 0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL);
372 mutex_unlock(&info->bl_mutex);
373
374 up(&bd->sem);
375 bd->props->brightness = riva_bl_data.max_brightness;
376 bd->props->power = FB_BLANK_UNBLANK;
377 bd->props->update_status(bd);
378 down(&bd->sem);
379
380#ifdef CONFIG_PMAC_BACKLIGHT
381 mutex_lock(&pmac_backlight_mutex);
382 if (!pmac_backlight)
383 pmac_backlight = bd;
384 mutex_unlock(&pmac_backlight_mutex);
385#endif
386
387 printk("riva: Backlight initialized (%s)\n", name);
388
389 return;
390
391error:
392 return;
393}
394
395static void riva_bl_exit(struct riva_par *par)
396{
397 struct fb_info *info = pci_get_drvdata(par->pdev);
398
399#ifdef CONFIG_PMAC_BACKLIGHT
400 mutex_lock(&pmac_backlight_mutex);
401#endif
402
403 mutex_lock(&info->bl_mutex);
404 if (info->bl_dev) {
405#ifdef CONFIG_PMAC_BACKLIGHT
406 if (pmac_backlight == info->bl_dev)
407 pmac_backlight = NULL;
408#endif
409
410 backlight_device_unregister(info->bl_dev);
411
412 printk("riva: Backlight unloaded\n");
413 }
414 mutex_unlock(&info->bl_mutex);
415
416#ifdef CONFIG_PMAC_BACKLIGHT
417 mutex_unlock(&pmac_backlight_mutex);
418#endif
419}
420#else
421static inline void riva_bl_init(struct riva_par *par) {}
422static inline void riva_bl_exit(struct riva_par *par) {}
423#endif /* CONFIG_FB_RIVA_BACKLIGHT */
303 424
304/* ------------------------------------------------------------------------- * 425/* ------------------------------------------------------------------------- *
305 * 426 *
@@ -973,36 +1094,6 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
973 1094
974/* ------------------------------------------------------------------------- * 1095/* ------------------------------------------------------------------------- *
975 * 1096 *
976 * Backlight operations
977 *
978 * ------------------------------------------------------------------------- */
979
980#ifdef CONFIG_PMAC_BACKLIGHT
981static int riva_set_backlight_enable(int on, int level, void *data)
982{
983 struct riva_par *par = data;
984 U032 tmp_pcrt, tmp_pmc;
985
986 tmp_pmc = par->riva.PMC[0x10F0/4] & 0x0000FFFF;
987 tmp_pcrt = par->riva.PCRTC0[0x081C/4] & 0xFFFFFFFC;
988 if(on && (level > BACKLIGHT_OFF)) {
989 tmp_pcrt |= 0x1;
990 tmp_pmc |= (1 << 31); // backlight bit
991 tmp_pmc |= riva_backlight_levels[level-1] << 16; // level
992 }
993 par->riva.PCRTC0[0x081C/4] = tmp_pcrt;
994 par->riva.PMC[0x10F0/4] = tmp_pmc;
995 return 0;
996}
997
998static int riva_set_backlight_level(int level, void *data)
999{
1000 return riva_set_backlight_enable(1, level, data);
1001}
1002#endif /* CONFIG_PMAC_BACKLIGHT */
1003
1004/* ------------------------------------------------------------------------- *
1005 *
1006 * framebuffer operations 1097 * framebuffer operations
1007 * 1098 *
1008 * ------------------------------------------------------------------------- */ 1099 * ------------------------------------------------------------------------- */
@@ -1247,10 +1338,15 @@ static int rivafb_blank(int blank, struct fb_info *info)
1247 SEQout(par, 0x01, tmp); 1338 SEQout(par, 0x01, tmp);
1248 CRTCout(par, 0x1a, vesa); 1339 CRTCout(par, 0x1a, vesa);
1249 1340
1250#ifdef CONFIG_PMAC_BACKLIGHT 1341#ifdef CONFIG_FB_RIVA_BACKLIGHT
1251 if ( par->FlatPanel && machine_is(powermac)) { 1342 mutex_lock(&info->bl_mutex);
1252 set_backlight_enable(!blank); 1343 if (info->bl_dev) {
1344 down(&info->bl_dev->sem);
1345 info->bl_dev->props->power = blank;
1346 info->bl_dev->props->update_status(info->bl_dev);
1347 up(&info->bl_dev->sem);
1253 } 1348 }
1349 mutex_unlock(&info->bl_mutex);
1254#endif 1350#endif
1255 1351
1256 NVTRACE_LEAVE(); 1352 NVTRACE_LEAVE();
@@ -2037,11 +2133,9 @@ static int __devinit rivafb_probe(struct pci_dev *pd,
2037 RIVAFB_VERSION, 2133 RIVAFB_VERSION,
2038 info->fix.smem_len / (1024 * 1024), 2134 info->fix.smem_len / (1024 * 1024),
2039 info->fix.smem_start); 2135 info->fix.smem_start);
2040#ifdef CONFIG_PMAC_BACKLIGHT 2136
2041 if (default_par->FlatPanel && machine_is(powermac)) 2137 riva_bl_init(info->par);
2042 register_backlight_controller(&riva_backlight_controller, 2138
2043 default_par, "mnca");
2044#endif
2045 NVTRACE_LEAVE(); 2139 NVTRACE_LEAVE();
2046 return 0; 2140 return 0;
2047 2141
@@ -2074,6 +2168,8 @@ static void __exit rivafb_remove(struct pci_dev *pd)
2074 2168
2075 NVTRACE_ENTER(); 2169 NVTRACE_ENTER();
2076 2170
2171 riva_bl_exit(par);
2172
2077#ifdef CONFIG_FB_RIVA_I2C 2173#ifdef CONFIG_FB_RIVA_I2C
2078 riva_delete_i2c_busses(par); 2174 riva_delete_i2c_busses(par);
2079 kfree(par->EDID); 2175 kfree(par->EDID);
diff --git a/include/asm-powerpc/backlight.h b/include/asm-powerpc/backlight.h
index 1ba1f27a0b63..a5e9e656e332 100644
--- a/include/asm-powerpc/backlight.h
+++ b/include/asm-powerpc/backlight.h
@@ -2,30 +2,30 @@
2 * Routines for handling backlight control on PowerBooks 2 * Routines for handling backlight control on PowerBooks
3 * 3 *
4 * For now, implementation resides in 4 * For now, implementation resides in
5 * arch/powerpc/platforms/powermac/pmac_support.c 5 * arch/powerpc/platforms/powermac/backlight.c
6 * 6 *
7 */ 7 */
8#ifndef __ASM_POWERPC_BACKLIGHT_H 8#ifndef __ASM_POWERPC_BACKLIGHT_H
9#define __ASM_POWERPC_BACKLIGHT_H 9#define __ASM_POWERPC_BACKLIGHT_H
10#ifdef __KERNEL__ 10#ifdef __KERNEL__
11 11
12/* Abstract values */ 12#include <linux/fb.h>
13#define BACKLIGHT_OFF 0 13#include <linux/mutex.h>
14#define BACKLIGHT_MIN 1
15#define BACKLIGHT_MAX 0xf
16 14
17struct backlight_controller { 15/* For locking instructions, see the implementation file */
18 int (*set_enable)(int enable, int level, void *data); 16extern struct backlight_device *pmac_backlight;
19 int (*set_level)(int level, void *data); 17extern struct mutex pmac_backlight_mutex;
20};
21 18
22extern void register_backlight_controller(struct backlight_controller *ctrler, void *data, char *type); 19extern void pmac_backlight_calc_curve(struct fb_info*);
23extern void unregister_backlight_controller(struct backlight_controller *ctrler, void *data); 20extern int pmac_backlight_curve_lookup(struct fb_info *info, int value);
24 21
25extern int set_backlight_enable(int enable); 22extern int pmac_has_backlight_type(const char *type);
26extern int get_backlight_enable(void); 23
27extern int set_backlight_level(int level); 24extern void pmac_backlight_key_up(void);
28extern int get_backlight_level(void); 25extern void pmac_backlight_key_down(void);
26
27extern int pmac_backlight_set_legacy_brightness(int brightness);
28extern int pmac_backlight_get_legacy_brightness(void);
29 29
30#endif /* __KERNEL__ */ 30#endif /* __KERNEL__ */
31#endif 31#endif
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 315d89740ddf..f1281687e549 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -1,6 +1,7 @@
1#ifndef _LINUX_FB_H 1#ifndef _LINUX_FB_H
2#define _LINUX_FB_H 2#define _LINUX_FB_H
3 3
4#include <linux/backlight.h>
4#include <asm/types.h> 5#include <asm/types.h>
5 6
6/* Definitions of frame buffers */ 7/* Definitions of frame buffers */
@@ -366,6 +367,12 @@ struct fb_cursor {
366 struct fb_image image; /* Cursor image */ 367 struct fb_image image; /* Cursor image */
367}; 368};
368 369
370#ifdef CONFIG_FB_BACKLIGHT
371/* Settings for the generic backlight code */
372#define FB_BACKLIGHT_LEVELS 128
373#define FB_BACKLIGHT_MAX 0xFF
374#endif
375
369#ifdef __KERNEL__ 376#ifdef __KERNEL__
370 377
371#include <linux/fs.h> 378#include <linux/fs.h>
@@ -756,6 +763,21 @@ struct fb_info {
756 struct fb_cmap cmap; /* Current cmap */ 763 struct fb_cmap cmap; /* Current cmap */
757 struct list_head modelist; /* mode list */ 764 struct list_head modelist; /* mode list */
758 struct fb_videomode *mode; /* current mode */ 765 struct fb_videomode *mode; /* current mode */
766
767#ifdef CONFIG_FB_BACKLIGHT
768 /* Lock ordering:
769 * bl_mutex (protects bl_dev and bl_curve)
770 * bl_dev->sem (backlight class)
771 */
772 struct mutex bl_mutex;
773
774 /* assigned backlight device */
775 struct backlight_device *bl_dev;
776
777 /* Backlight level curve */
778 u8 bl_curve[FB_BACKLIGHT_LEVELS];
779#endif
780
759 struct fb_ops *fbops; 781 struct fb_ops *fbops;
760 struct device *device; 782 struct device *device;
761 struct class_device *class_device; /* sysfs per device attrs */ 783 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);
895extern void framebuffer_release(struct fb_info *info); 917extern void framebuffer_release(struct fb_info *info);
896extern int fb_init_class_device(struct fb_info *fb_info); 918extern int fb_init_class_device(struct fb_info *fb_info);
897extern void fb_cleanup_class_device(struct fb_info *head); 919extern void fb_cleanup_class_device(struct fb_info *head);
920extern void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max);
898 921
899/* drivers/video/fbmon.c */ 922/* drivers/video/fbmon.c */
900#define FB_MAXTIMINGS 0 923#define FB_MAXTIMINGS 0
diff --git a/include/linux/pmu.h b/include/linux/pmu.h
index ecce5912f4d6..2ed807ddc08c 100644
--- a/include/linux/pmu.h
+++ b/include/linux/pmu.h
@@ -230,4 +230,8 @@ extern int pmu_battery_count;
230extern struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES]; 230extern struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES];
231extern unsigned int pmu_power_flags; 231extern unsigned int pmu_power_flags;
232 232
233/* Backlight */
234extern int disable_kernel_backlight;
235extern void pmu_backlight_init(struct device_node*);
236
233#endif /* __KERNEL__ */ 237#endif /* __KERNEL__ */