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 /drivers/video/aty/atyfb_base.c | |
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>
Diffstat (limited to 'drivers/video/aty/atyfb_base.c')
-rw-r--r-- | drivers/video/aty/atyfb_base.c | 178 |
1 files changed, 151 insertions, 27 deletions
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 |