Blame view
drivers/video/aty/radeon_backlight.c
5.95 KB
5474c120a
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
/* * Backlight code for ATI Radeon based graphic cards * * Copyright (c) 2000 Ani Joshi <ajoshi@kernel.crashing.org> * Copyright (c) 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org> * Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include "radeonfb.h" #include <linux/backlight.h> #ifdef CONFIG_PMAC_BACKLIGHT #include <asm/backlight.h> #endif #define MAX_RADEON_LEVEL 0xFF |
5474c120a
|
21 22 23 24 25 26 27 28 |
struct radeon_bl_privdata { struct radeonfb_info *rinfo; uint8_t negative; }; static int radeon_bl_get_level_brightness(struct radeon_bl_privdata *pdata, int level) { |
5474c120a
|
29 |
int rlevel; |
5474c120a
|
30 |
/* Get and convert the value */ |
37ce69a57
|
31 |
/* No locking of bl_curve since we read a single value */ |
5474c120a
|
32 33 |
rlevel = pdata->rinfo->info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL; |
5474c120a
|
34 35 36 37 |
if (rlevel < 0) rlevel = 0; else if (rlevel > MAX_RADEON_LEVEL) rlevel = MAX_RADEON_LEVEL; |
cab267c65
|
38 39 |
if (pdata->negative) rlevel = MAX_RADEON_LEVEL - rlevel; |
5474c120a
|
40 41 42 43 44 |
return rlevel; } static int radeon_bl_update_status(struct backlight_device *bd) { |
655bfd7ae
|
45 |
struct radeon_bl_privdata *pdata = bl_get_data(bd); |
5474c120a
|
46 47 48 49 50 51 52 53 54 55 56 |
struct radeonfb_info *rinfo = pdata->rinfo; u32 lvds_gen_cntl, tmpPixclksCntl; int level; if (rinfo->mon1_type != MT_LCD) return 0; /* We turn off the LCD completely instead of just dimming the * backlight. This provides some greater power saving and the display * is useless without backlight anyway. */ |
599a52d12
|
57 58 |
if (bd->props.power != FB_BLANK_UNBLANK || bd->props.fb_blank != FB_BLANK_UNBLANK) |
5474c120a
|
59 60 |
level = 0; else |
599a52d12
|
61 |
level = bd->props.brightness; |
5474c120a
|
62 63 |
del_timer_sync(&rinfo->lvds_timer); |
b1ee26bab
|
64 |
radeon_engine_idle(rinfo); |
5474c120a
|
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
lvds_gen_cntl = INREG(LVDS_GEN_CNTL); if (level > 0) { lvds_gen_cntl &= ~LVDS_DISPLAY_DIS; if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) { lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON); lvds_gen_cntl |= LVDS_BLON | LVDS_EN; OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK; lvds_gen_cntl |= (radeon_bl_get_level_brightness(pdata, level) << LVDS_BL_MOD_LEVEL_SHIFT); lvds_gen_cntl |= LVDS_ON; lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN); rinfo->pending_lvds_gen_cntl = lvds_gen_cntl; mod_timer(&rinfo->lvds_timer, jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay)); } else { lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK; lvds_gen_cntl |= (radeon_bl_get_level_brightness(pdata, level) << LVDS_BL_MOD_LEVEL_SHIFT); OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); } rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK; rinfo->init_state.lvds_gen_cntl |= rinfo->pending_lvds_gen_cntl & LVDS_STATE_MASK; } else { /* Asic bug, when turning off LVDS_ON, we have to make sure RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off */ tmpPixclksCntl = INPLL(PIXCLKS_CNTL); if (rinfo->is_mobility || rinfo->is_IGP) OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb); lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN); lvds_gen_cntl |= (radeon_bl_get_level_brightness(pdata, 0) << LVDS_BL_MOD_LEVEL_SHIFT); lvds_gen_cntl |= LVDS_DISPLAY_DIS; OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); udelay(100); lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN); OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); lvds_gen_cntl &= ~(LVDS_DIGON); rinfo->pending_lvds_gen_cntl = lvds_gen_cntl; mod_timer(&rinfo->lvds_timer, jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay)); if (rinfo->is_mobility || rinfo->is_IGP) OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl); } rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK; rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK); return 0; } static int radeon_bl_get_brightness(struct backlight_device *bd) { |
599a52d12
|
122 |
return bd->props.brightness; |
5474c120a
|
123 |
} |
599a52d12
|
124 |
static struct backlight_ops radeon_bl_data = { |
5474c120a
|
125 126 |
.get_brightness = radeon_bl_get_brightness, .update_status = radeon_bl_update_status, |
5474c120a
|
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
}; void radeonfb_bl_init(struct radeonfb_info *rinfo) { struct backlight_device *bd; struct radeon_bl_privdata *pdata; char name[12]; if (rinfo->mon1_type != MT_LCD) return; #ifdef CONFIG_PMAC_BACKLIGHT if (!pmac_has_backlight_type("ati") && !pmac_has_backlight_type("mnca")) return; #endif pdata = kmalloc(sizeof(struct radeon_bl_privdata), GFP_KERNEL); if (!pdata) { printk("radeonfb: Memory allocation failed "); goto error; } snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node); |
a8274d57a
|
152 |
bd = backlight_device_register(name, rinfo->info->dev, pdata, &radeon_bl_data); |
5474c120a
|
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
if (IS_ERR(bd)) { rinfo->info->bl_dev = NULL; printk("radeonfb: Backlight registration failed "); goto error; } pdata->rinfo = rinfo; /* Pardon me for that hack... maybe some day we can figure out in what * direction backlight should work on a given panel? */ pdata->negative = (rinfo->family != CHIP_FAMILY_RV200 && rinfo->family != CHIP_FAMILY_RV250 && rinfo->family != CHIP_FAMILY_RV280 && rinfo->family != CHIP_FAMILY_RV350); #ifdef CONFIG_PMAC_BACKLIGHT pdata->negative = pdata->negative || machine_is_compatible("PowerBook4,3") || machine_is_compatible("PowerBook6,3") || machine_is_compatible("PowerBook6,5"); #endif |
5474c120a
|
177 178 179 180 |
rinfo->info->bl_dev = bd; fb_bl_default_curve(rinfo->info, 0, 63 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL, 217 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL); |
5474c120a
|
181 |
|
599a52d12
|
182 183 184 |
bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1; bd->props.brightness = bd->props.max_brightness; bd->props.power = FB_BLANK_UNBLANK; |
28ee086d5
|
185 |
backlight_update_status(bd); |
5474c120a
|
186 |
|
5474c120a
|
187 188 189 190 191 192 193 194 195 196 197 198 |
printk("radeonfb: Backlight initialized (%s) ", name); return; error: kfree(pdata); return; } void radeonfb_bl_exit(struct radeonfb_info *rinfo) { |
37ce69a57
|
199 |
struct backlight_device *bd = rinfo->info->bl_dev; |
5474c120a
|
200 |
|
37ce69a57
|
201 |
if (bd) { |
5474c120a
|
202 |
struct radeon_bl_privdata *pdata; |
655bfd7ae
|
203 |
pdata = bl_get_data(bd); |
37ce69a57
|
204 |
backlight_device_unregister(bd); |
5474c120a
|
205 206 207 208 209 210 |
kfree(pdata); rinfo->info->bl_dev = NULL; printk("radeonfb: Backlight unloaded "); } |
5474c120a
|
211 |
} |