diff options
author | Michael Hanselmann <linux-kernel@hansmi.ch> | 2006-06-25 08:47:08 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-25 13:00:59 -0400 |
commit | 5474c120aafe78ca54bf272f7a01107c42da2b21 (patch) | |
tree | c1b002a27703ce92c816bfb9844752186e33d403 | |
parent | 17660bdd5c1f1a165273c1a59cb5b87670a81cc4 (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>
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 | ||
29 | static struct backlight_controller *backlighter; | 19 | /* Protect the pmac_backlight variable */ |
30 | static void* backlighter_data; | 20 | DEFINE_MUTEX(pmac_backlight_mutex); |
31 | static int backlight_autosave; | ||
32 | static int backlight_level = BACKLIGHT_MAX; | ||
33 | static int backlight_enabled = 1; | ||
34 | static int backlight_req_level = -1; | ||
35 | static int backlight_req_enable = -1; | ||
36 | 21 | ||
37 | static void backlight_callback(void *); | 22 | /* Main backlight storage |
38 | static 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 | */ | ||
35 | struct backlight_device *pmac_backlight; | ||
39 | 36 | ||
40 | void register_backlight_controller(struct backlight_controller *ctrler, | 37 | int 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 | } |
100 | EXPORT_SYMBOL(register_backlight_controller); | ||
101 | 49 | ||
102 | void unregister_backlight_controller(struct backlight_controller | 50 | int 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 | } |
109 | EXPORT_SYMBOL(unregister_backlight_controller); | ||
110 | 74 | ||
111 | static int __set_backlight_enable(int enable) | 75 | static 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 | } |
125 | int set_backlight_enable(int enable) | 100 | |
101 | void 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 | ||
134 | EXPORT_SYMBOL(set_backlight_enable); | 106 | void pmac_backlight_key_down() |
135 | |||
136 | int get_backlight_enable(void) | ||
137 | { | 107 | { |
138 | if (!backlighter) | 108 | pmac_backlight_key(1); |
139 | return -ENODEV; | ||
140 | return backlight_enabled; | ||
141 | } | 109 | } |
142 | EXPORT_SYMBOL(get_backlight_enable); | ||
143 | 110 | ||
144 | static int __set_backlight_level(int level) | 111 | int 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 | } |
168 | int set_backlight_level(int level) | 132 | |
133 | int 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 | ||
177 | EXPORT_SYMBOL(set_backlight_level); | 137 | mutex_lock(&pmac_backlight_mutex); |
138 | if (pmac_backlight) { | ||
139 | struct backlight_properties *props; | ||
178 | 140 | ||
179 | int 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 | } |
185 | EXPORT_SYMBOL(get_backlight_level); | 147 | mutex_unlock(&pmac_backlight_mutex); |
186 | 148 | ||
187 | static 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) | ||
104 | config PMAC_BACKLIGHT | 102 | config 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 | |
111 | config 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 | ||
114 | config ADB_MACIO | 119 | config 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 | |||
12 | obj-$(CONFIG_ANSLCD) += ans-lcd.o | 12 | obj-$(CONFIG_ANSLCD) += ans-lcd.o |
13 | 13 | ||
14 | obj-$(CONFIG_ADB_PMU) += via-pmu.o | 14 | obj-$(CONFIG_ADB_PMU) += via-pmu.o |
15 | obj-$(CONFIG_PMAC_BACKLIGHT) += via-pmu-backlight.o | ||
15 | obj-$(CONFIG_ADB_CUDA) += via-cuda.o | 16 | obj-$(CONFIG_ADB_CUDA) += via-cuda.o |
16 | obj-$(CONFIG_PMAC_APM_EMU) += apm_emu.o | 17 | obj-$(CONFIG_PMAC_APM_EMU) += apm_emu.o |
17 | obj-$(CONFIG_PMAC_SMU) += smu.o | 18 | obj-$(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 | |||
18 | static struct device_node *vias; | ||
19 | static struct backlight_properties pmu_backlight_data; | ||
20 | |||
21 | static 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 | |||
39 | static 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 | |||
64 | static int pmu_backlight_get_brightness(struct backlight_device *bd) | ||
65 | { | ||
66 | return bd->props->brightness; | ||
67 | } | ||
68 | |||
69 | static 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 | |||
76 | void __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 | |||
148 | error: | ||
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; | |||
144 | static int data_len; | 144 | static int data_len; |
145 | static volatile int adb_int_pending; | 145 | static volatile int adb_int_pending; |
146 | static volatile int disable_poll; | 146 | static volatile int disable_poll; |
147 | static struct adb_request bright_req_1, bright_req_2; | ||
148 | static struct device_node *vias; | 147 | static struct device_node *vias; |
149 | static int pmu_kind = PMU_UNKNOWN; | 148 | static int pmu_kind = PMU_UNKNOWN; |
150 | static int pmu_fully_inited = 0; | 149 | static 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) |
162 | static int option_lid_wakeup = 1; | 161 | static 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) |
165 | static int sleep_in_progress; | 164 | static int sleep_in_progress; |
166 | #endif | 165 | #endif |
167 | static unsigned long async_req_locks; | 166 | static 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); |
209 | static int proc_get_irqstats(char *page, char **start, off_t off, | 208 | static 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 | ||
212 | static int pmu_set_backlight_level(int level, void* data); | ||
213 | static int pmu_set_backlight_enable(int on, int level, void* data); | ||
214 | #endif /* CONFIG_PMAC_BACKLIGHT */ | ||
215 | static void pmu_pass_intr(unsigned char *data, int len); | 210 | static void pmu_pass_intr(unsigned char *data, int len); |
216 | static int proc_get_batt(char *page, char **start, off_t off, | 211 | static 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 | ||
296 | static struct backlight_controller pmu_backlight_controller = { | ||
297 | pmu_set_backlight_enable, | ||
298 | pmu_set_backlight_level | ||
299 | }; | ||
300 | #endif /* CONFIG_PMAC_BACKLIGHT */ | ||
301 | |||
302 | int __init find_via_pmu(void) | 290 | int __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 | ||
1678 | static int backlight_to_bright[] = { | ||
1679 | 0x7f, 0x46, 0x42, 0x3e, 0x3a, 0x36, 0x32, 0x2e, | ||
1680 | 0x2a, 0x26, 0x22, 0x1e, 0x1a, 0x16, 0x12, 0x0e | ||
1681 | }; | ||
1682 | |||
1683 | static int | ||
1684 | pmu_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 | |||
1703 | static void | ||
1704 | pmu_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 | |||
1712 | static int | ||
1713 | pmu_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 | |||
1732 | void | 1663 | void |
1733 | pmu_enable_irled(int on) | 1664 | pmu_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 | ||
89 | config FB_BACKLIGHT | ||
90 | bool | ||
91 | depends on FB | ||
92 | default n | ||
93 | |||
89 | config FB_MODE_HELPERS | 94 | config 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 | ||
725 | config 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 | |||
720 | config FB_RIVA | 735 | config 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 | ||
773 | config 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 | |||
758 | config FB_I810 | 783 | config 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 | |||
996 | config FB_RADEON_I2C | 1022 | config 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 | ||
1029 | config 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 | |||
1003 | config FB_RADEON_DEBUG | 1039 | config 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 | ||
1063 | config 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 | |||
1027 | config FB_ATY | 1073 | config 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 | ||
1115 | config 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 | |||
1069 | config FB_S3TRIO | 1125 | config 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 | ||
11 | radeonfb-y := radeon_base.o radeon_pm.o radeon_monitor.o radeon_accel.o | 11 | radeonfb-y := radeon_base.o radeon_pm.o radeon_monitor.o radeon_accel.o |
12 | radeonfb-$(CONFIG_FB_RADEON_I2C) += radeon_i2c.o | 12 | radeonfb-$(CONFIG_FB_RADEON_I2C) += radeon_i2c.o |
13 | radeonfb-$(CONFIG_FB_RADEON_BACKLIGHT) += radeon_backlight.o | ||
13 | radeonfb-objs := $(radeonfb-y) | 14 | radeonfb-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 | ||
484 | static int aty128_set_backlight_enable(int on, int level, void* data); | ||
485 | static int aty128_set_backlight_level(int level, void* data); | ||
486 | |||
487 | static 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) | |||
1258 | static void aty128_set_lcd_enable(struct aty128fb_par *par, int on) | 1249 | static 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 | |||
1705 | static struct backlight_properties aty128_bl_data; | ||
1706 | |||
1707 | static 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 | |||
1735 | static 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 | |||
1788 | static int aty128_bl_get_brightness(struct backlight_device *bd) | ||
1789 | { | ||
1790 | return bd->props->brightness; | ||
1791 | } | ||
1792 | |||
1793 | static 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 | |||
1800 | static 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 | |||
1848 | error: | ||
1849 | return; | ||
1850 | } | ||
1851 | |||
1852 | static 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 | ||
2142 | static 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 | |||
2155 | static 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 | |||
2202 | static 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 | /* | 2123 | static struct backlight_properties aty_bl_data; |
2121 | * LCD backlight control | ||
2122 | */ | ||
2123 | 2124 | ||
2124 | static int backlight_conv[] = { | 2125 | static 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 | ||
2129 | static int aty_set_backlight_enable(int on, int level, void *data) | 2140 | return atylevel; |
2141 | } | ||
2142 | |||
2143 | static 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 | ||
2147 | static int aty_set_backlight_level(int level, void *data) | 2168 | static 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 | ||
2152 | static struct backlight_controller aty_backlight_controller = { | 2173 | static 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 | |
2180 | static 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 | |||
2224 | error: | ||
2225 | return; | ||
2226 | } | ||
2227 | |||
2228 | static 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 | ||
2158 | static void __init aty_calc_mem_refresh(struct atyfb_par *par, int xclk) | 2256 | static 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 | |||
22 | static struct backlight_properties radeon_bl_data; | ||
23 | |||
24 | struct radeon_bl_privdata { | ||
25 | struct radeonfb_info *rinfo; | ||
26 | uint8_t negative; | ||
27 | }; | ||
28 | |||
29 | static 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 | |||
54 | static 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 | |||
131 | static int radeon_bl_get_brightness(struct backlight_device *bd) | ||
132 | { | ||
133 | return bd->props->brightness; | ||
134 | } | ||
135 | |||
136 | static 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 | |||
143 | void 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 | |||
215 | error: | ||
216 | kfree(pdata); | ||
217 | return; | ||
218 | } | ||
219 | |||
220 | void 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 | ||
284 | static int radeon_set_backlight_enable(int on, int level, void *data); | ||
285 | static int radeon_set_backlight_level(int level, void *data); | ||
286 | static 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 | |||
294 | static void radeon_unmap_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev) | 276 | static 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 | */ | ||
1923 | static int backlight_conv_m6[] = { | ||
1924 | 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e, | ||
1925 | 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24 | ||
1926 | }; | ||
1927 | static 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 | */ | ||
1939 | static 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 | |||
2019 | static 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_ | |||
625 | extern void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode, | 625 | extern 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 | ||
630 | extern void radeonfb_bl_init(struct radeonfb_info *rinfo); | ||
631 | extern void radeonfb_bl_exit(struct radeonfb_info *rinfo); | ||
632 | #else | ||
633 | static inline void radeonfb_bl_init(struct radeonfb_info *rinfo) {} | ||
634 | static 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) | |||
148 | static int chipsfb_blank(int blank, struct fb_info *info) | 148 | static 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 | ||
423 | static 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 | |||
457 | static 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 | ||
437 | int fb_init_class_device(struct fb_info *fb_info) | 504 | int 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 | */ | ||
531 | void 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 | } | ||
544 | EXPORT_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 | |||
7 | nvidiafb-y := nvidia.o nv_hw.o nv_setup.o \ | 7 | nvidiafb-y := nvidia.o nv_hw.o nv_setup.o \ |
8 | nv_accel.o | 8 | nv_accel.o |
9 | nvidiafb-$(CONFIG_FB_NVIDIA_I2C) += nv_i2c.o | 9 | nvidiafb-$(CONFIG_FB_NVIDIA_I2C) += nv_i2c.o |
10 | nvidiafb-$(CONFIG_FB_NVIDIA_BACKLIGHT) += nv_backlight.o | ||
10 | nvidiafb-$(CONFIG_PPC_OF) += nv_of.o | 11 | nvidiafb-$(CONFIG_PPC_OF) += nv_of.o |
11 | 12 | ||
12 | nvidiafb-objs := $(nvidiafb-y) \ No newline at end of file | 13 | nvidiafb-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 | |||
30 | static struct backlight_properties nvidia_bl_data; | ||
31 | |||
32 | static 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 | |||
53 | static 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 | |||
87 | static int nvidia_bl_get_brightness(struct backlight_device *bd) | ||
88 | { | ||
89 | return bd->props->brightness; | ||
90 | } | ||
91 | |||
92 | static 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 | |||
99 | void 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 | |||
147 | error: | ||
148 | return; | ||
149 | } | ||
150 | |||
151 | void 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); |
64 | extern int nvidiafb_sync(struct fb_info *info); | 64 | extern int nvidiafb_sync(struct fb_info *info); |
65 | extern u8 byte_rev[256]; | 65 | extern u8 byte_rev[256]; |
66 | |||
67 | /* in nv_backlight.h */ | ||
68 | #ifdef CONFIG_FB_NVIDIA_BACKLIGHT | ||
69 | extern void nvidia_bl_init(struct nvidia_par *par); | ||
70 | extern void nvidia_bl_exit(struct nvidia_par *par); | ||
71 | #else | ||
72 | static inline void nvidia_bl_init(struct nvidia_par *par) {} | ||
73 | static 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 | |||
478 | static 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 | |||
503 | static 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 | |||
530 | static int nvidia_set_backlight_level(int level, void *data) | ||
531 | { | ||
532 | return nvidia_set_backlight_enable(1, level, data); | ||
533 | } | ||
534 | |||
535 | static struct backlight_controller nvidia_backlight_controller = { | ||
536 | nvidia_set_backlight_enable, | ||
537 | nvidia_set_backlight_level | ||
538 | }; | ||
539 | |||
540 | #endif /* CONFIG_PMAC_BACKLIGHT */ | ||
541 | |||
542 | static void nvidiafb_load_cursor_image(struct nvidia_par *par, u8 * data8, | 470 | static 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 | ||
277 | static int riva_backlight_levels[] = { | 283 | static struct backlight_properties riva_bl_data; |
278 | 0x158, | 284 | |
279 | 0x192, | 285 | static 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 | |||
306 | static 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 | |||
331 | static int riva_bl_get_brightness(struct backlight_device *bd) | ||
332 | { | ||
333 | return bd->props->brightness; | ||
334 | } | ||
295 | 335 | ||
296 | static int riva_set_backlight_enable(int on, int level, void *data); | 336 | static struct backlight_properties riva_bl_data = { |
297 | static int riva_set_backlight_level(int level, void *data); | 337 | .owner = THIS_MODULE, |
298 | static 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 | |
343 | static 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 | |||
391 | error: | ||
392 | return; | ||
393 | } | ||
394 | |||
395 | static 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 | ||
421 | static inline void riva_bl_init(struct riva_par *par) {} | ||
422 | static 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 | ||
981 | static 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 | |||
998 | static 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 | ||
17 | struct backlight_controller { | 15 | /* For locking instructions, see the implementation file */ |
18 | int (*set_enable)(int enable, int level, void *data); | 16 | extern struct backlight_device *pmac_backlight; |
19 | int (*set_level)(int level, void *data); | 17 | extern struct mutex pmac_backlight_mutex; |
20 | }; | ||
21 | 18 | ||
22 | extern void register_backlight_controller(struct backlight_controller *ctrler, void *data, char *type); | 19 | extern void pmac_backlight_calc_curve(struct fb_info*); |
23 | extern void unregister_backlight_controller(struct backlight_controller *ctrler, void *data); | 20 | extern int pmac_backlight_curve_lookup(struct fb_info *info, int value); |
24 | 21 | ||
25 | extern int set_backlight_enable(int enable); | 22 | extern int pmac_has_backlight_type(const char *type); |
26 | extern int get_backlight_enable(void); | 23 | |
27 | extern int set_backlight_level(int level); | 24 | extern void pmac_backlight_key_up(void); |
28 | extern int get_backlight_level(void); | 25 | extern void pmac_backlight_key_down(void); |
26 | |||
27 | extern int pmac_backlight_set_legacy_brightness(int brightness); | ||
28 | extern 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); | |||
895 | extern void framebuffer_release(struct fb_info *info); | 917 | extern void framebuffer_release(struct fb_info *info); |
896 | extern int fb_init_class_device(struct fb_info *fb_info); | 918 | extern int fb_init_class_device(struct fb_info *fb_info); |
897 | extern void fb_cleanup_class_device(struct fb_info *head); | 919 | extern void fb_cleanup_class_device(struct fb_info *head); |
920 | extern 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; | |||
230 | extern struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES]; | 230 | extern struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES]; |
231 | extern unsigned int pmu_power_flags; | 231 | extern unsigned int pmu_power_flags; |
232 | 232 | ||
233 | /* Backlight */ | ||
234 | extern int disable_kernel_backlight; | ||
235 | extern void pmu_backlight_init(struct device_node*); | ||
236 | |||
233 | #endif /* __KERNEL__ */ | 237 | #endif /* __KERNEL__ */ |