[PATCH] powerpc: More via-pmu backlight fixes

The via-pmu backlight code (introduced in 2.6.18) has various design issues
causing crashes on machines using it like the old Wallstreet powerbook
(Michael, the author, never managed to test on these and I just got my hand
on one of those old beasts).

This fixes them by no longer trying to hijack the backlight device of the
frontmost framebuffer (causing that framebuffer to crash) but having it's
own local bits instead. Might look weird but it's better that way on those
old machines, at least as a last-minute fix for 2.6.18. We might rework
the whole thing later. This patch also changes the way it gets notified of
sleep and wakeup in order to properly shut the backlight down on sleep and
bring it back on wakeup.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by Benjamin Herrenschmidt and committed by Linus Torvalds d565dd3b 0b1d647a

+57 -50
+45 -50
drivers/macintosh/via-pmu-backlight.c
··· 18 static struct backlight_properties pmu_backlight_data; 19 static spinlock_t pmu_backlight_lock; 20 static int sleeping; 21 22 - static int pmu_backlight_get_level_brightness(struct fb_info *info, 23 - int level) 24 { 25 int pmulevel; 26 27 /* Get and convert the value */ 28 - mutex_lock(&info->bl_mutex); 29 - pmulevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_PMU_LEVEL; 30 - mutex_unlock(&info->bl_mutex); 31 - 32 if (pmulevel < 0) 33 pmulevel = 0; 34 else if (pmulevel > MAX_PMU_LEVEL) ··· 70 71 static int pmu_backlight_update_status(struct backlight_device *bd) 72 { 73 - struct fb_info *info = class_get_devdata(&bd->class_dev); 74 struct adb_request req; 75 unsigned long flags; 76 int level = bd->props->brightness; ··· 85 level = 0; 86 87 if (level > 0) { 88 - int pmulevel = pmu_backlight_get_level_brightness(info, level); 89 90 pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel); 91 pmu_wait_complete(&req); ··· 118 }; 119 120 #ifdef CONFIG_PM 121 - static int pmu_backlight_sleep_call(struct pmu_sleep_notifier *self, int when) 122 { 123 unsigned long flags; 124 125 spin_lock_irqsave(&pmu_backlight_lock, flags); 126 - 127 - switch (when) { 128 - case PBOOK_SLEEP_REQUEST: 129 - sleeping = 1; 130 - break; 131 - case PBOOK_WAKE: 132 - sleeping = 0; 133 - break; 134 - } 135 - 136 spin_unlock_irqrestore(&pmu_backlight_lock, flags); 137 - 138 - return PBOOK_SLEEP_OK; 139 } 140 - 141 - static struct pmu_sleep_notifier pmu_backlight_sleep_notif = { 142 - .notifier_call = pmu_backlight_sleep_call, 143 - }; 144 - #endif 145 146 void __init pmu_backlight_init() 147 { 148 struct backlight_device *bd; 149 - struct fb_info *info; 150 char name[10]; 151 int level, autosave; 152 ··· 145 !machine_is_compatible("PowerBook1,1")) 146 return; 147 148 - /* Actually, this is a hack, but I don't know of a better way 149 - * to get the first framebuffer device. 150 - */ 151 - info = registered_fb[0]; 152 - if (!info) { 153 - printk("pmubl: No framebuffer found\n"); 154 - goto error; 155 - } 156 157 - snprintf(name, sizeof(name), "pmubl%d", info->node); 158 - 159 - bd = backlight_device_register(name, info, &pmu_backlight_data); 160 if (IS_ERR(bd)) { 161 printk("pmubl: Backlight registration failed\n"); 162 goto error; 163 } 164 - 165 - mutex_lock(&info->bl_mutex); 166 - info->bl_dev = bd; 167 - fb_bl_default_curve(info, 0x7F, 0x46, 0x0E); 168 - mutex_unlock(&info->bl_mutex); 169 170 level = pmu_backlight_data.max_brightness; 171 ··· 162 pmu_request(&req, NULL, 2, 0xd9, 0); 163 pmu_wait_complete(&req); 164 165 - mutex_lock(&info->bl_mutex); 166 - level = pmac_backlight_curve_lookup(info, 167 (req.reply[0] >> 4) * 168 pmu_backlight_data.max_brightness / 15); 169 - mutex_unlock(&info->bl_mutex); 170 } 171 172 up(&bd->sem); ··· 177 if (!pmac_backlight) 178 pmac_backlight = bd; 179 mutex_unlock(&pmac_backlight_mutex); 180 - 181 - #ifdef CONFIG_PM 182 - pmu_register_sleep_notifier(&pmu_backlight_sleep_notif); 183 - #endif 184 185 printk("pmubl: Backlight initialized (%s)\n", name); 186
··· 18 static struct backlight_properties pmu_backlight_data; 19 static spinlock_t pmu_backlight_lock; 20 static int sleeping; 21 + static u8 bl_curve[FB_BACKLIGHT_LEVELS]; 22 23 + static void pmu_backlight_init_curve(u8 off, u8 min, u8 max) 24 + { 25 + unsigned int i, flat, count, range = (max - min); 26 + 27 + bl_curve[0] = off; 28 + 29 + for (flat = 1; flat < (FB_BACKLIGHT_LEVELS / 16); ++flat) 30 + bl_curve[flat] = min; 31 + 32 + count = FB_BACKLIGHT_LEVELS * 15 / 16; 33 + for (i = 0; i < count; ++i) 34 + bl_curve[flat + i] = min + (range * (i + 1) / count); 35 + } 36 + 37 + static int pmu_backlight_curve_lookup(int value) 38 + { 39 + int level = (FB_BACKLIGHT_LEVELS - 1); 40 + int i, max = 0; 41 + 42 + /* Look for biggest value */ 43 + for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) 44 + max = max((int)bl_curve[i], max); 45 + 46 + /* Look for nearest value */ 47 + for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) { 48 + int diff = abs(bl_curve[i] - value); 49 + if (diff < max) { 50 + max = diff; 51 + level = i; 52 + } 53 + } 54 + return level; 55 + } 56 + 57 + static int pmu_backlight_get_level_brightness(int level) 58 { 59 int pmulevel; 60 61 /* Get and convert the value */ 62 + pmulevel = bl_curve[level] * FB_BACKLIGHT_MAX / MAX_PMU_LEVEL; 63 if (pmulevel < 0) 64 pmulevel = 0; 65 else if (pmulevel > MAX_PMU_LEVEL) ··· 39 40 static int pmu_backlight_update_status(struct backlight_device *bd) 41 { 42 struct adb_request req; 43 unsigned long flags; 44 int level = bd->props->brightness; ··· 55 level = 0; 56 57 if (level > 0) { 58 + int pmulevel = pmu_backlight_get_level_brightness(level); 59 60 pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel); 61 pmu_wait_complete(&req); ··· 88 }; 89 90 #ifdef CONFIG_PM 91 + void pmu_backlight_set_sleep(int sleep) 92 { 93 unsigned long flags; 94 95 spin_lock_irqsave(&pmu_backlight_lock, flags); 96 + sleeping = sleep; 97 spin_unlock_irqrestore(&pmu_backlight_lock, flags); 98 } 99 + #endif /* CONFIG_PM */ 100 101 void __init pmu_backlight_init() 102 { 103 struct backlight_device *bd; 104 char name[10]; 105 int level, autosave; 106 ··· 131 !machine_is_compatible("PowerBook1,1")) 132 return; 133 134 + snprintf(name, sizeof(name), "pmubl"); 135 136 + bd = backlight_device_register(name, NULL, &pmu_backlight_data); 137 if (IS_ERR(bd)) { 138 printk("pmubl: Backlight registration failed\n"); 139 goto error; 140 } 141 + pmu_backlight_init_curve(0x7F, 0x46, 0x0E); 142 143 level = pmu_backlight_data.max_brightness; 144 ··· 161 pmu_request(&req, NULL, 2, 0xd9, 0); 162 pmu_wait_complete(&req); 163 164 + level = pmu_backlight_curve_lookup( 165 (req.reply[0] >> 4) * 166 pmu_backlight_data.max_brightness / 15); 167 } 168 169 up(&bd->sem); ··· 178 if (!pmac_backlight) 179 pmac_backlight = bd; 180 mutex_unlock(&pmac_backlight_mutex); 181 182 printk("pmubl: Backlight initialized (%s)\n", name); 183
+12
drivers/macintosh/via-pmu.c
··· 1995 out_8(&via[IER], IER_SET | SR_INT | CB1_INT); 1996 } 1997 1998 static int 1999 pmac_suspend_devices(void) 2000 { ··· 2033 printk(KERN_ERR "Driver sleep failed\n"); 2034 return -EBUSY; 2035 } 2036 2037 /* Call platform functions marked "on sleep" */ 2038 pmac_pfunc_i2c_suspend(); ··· 2096 pmac_wakeup_devices(void) 2097 { 2098 mdelay(100); 2099 2100 /* Power back up system devices (including the PIC) */ 2101 device_power_up();
··· 1995 out_8(&via[IER], IER_SET | SR_INT | CB1_INT); 1996 } 1997 1998 + extern void pmu_backlight_set_sleep(int sleep); 1999 + 2000 static int 2001 pmac_suspend_devices(void) 2002 { ··· 2031 printk(KERN_ERR "Driver sleep failed\n"); 2032 return -EBUSY; 2033 } 2034 + 2035 + #ifdef CONFIG_PMAC_BACKLIGHT 2036 + /* Tell backlight code not to muck around with the chip anymore */ 2037 + pmu_backlight_set_sleep(1); 2038 + #endif 2039 2040 /* Call platform functions marked "on sleep" */ 2041 pmac_pfunc_i2c_suspend(); ··· 2089 pmac_wakeup_devices(void) 2090 { 2091 mdelay(100); 2092 + 2093 + #ifdef CONFIG_PMAC_BACKLIGHT 2094 + /* Tell backlight code it can use the chip again */ 2095 + pmu_backlight_set_sleep(0); 2096 + #endif 2097 2098 /* Power back up system devices (including the PIC) */ 2099 device_power_up();