2 * Backlight code for ATI Radeon based graphic cards
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>
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.
14 #include <linux/backlight.h>
16 #ifdef CONFIG_PMAC_BACKLIGHT
17 #include <asm/backlight.h>
20 #define MAX_RADEON_LEVEL 0xFF
22 static struct backlight_properties radeon_bl_data
;
24 struct radeon_bl_privdata
{
25 struct radeonfb_info
*rinfo
;
29 static int radeon_bl_get_level_brightness(struct radeon_bl_privdata
*pdata
,
32 struct fb_info
*info
= pdata
->rinfo
->info
;
35 mutex_lock(&info
->bl_mutex
);
37 /* Get and convert the value */
38 rlevel
= pdata
->rinfo
->info
->bl_curve
[level
] *
39 FB_BACKLIGHT_MAX
/ MAX_RADEON_LEVEL
;
41 mutex_unlock(&info
->bl_mutex
);
45 else if (rlevel
> MAX_RADEON_LEVEL
)
46 rlevel
= MAX_RADEON_LEVEL
;
49 rlevel
= MAX_RADEON_LEVEL
- rlevel
;
54 static int radeon_bl_update_status(struct backlight_device
*bd
)
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
;
61 if (rinfo
->mon1_type
!= MT_LCD
)
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.
68 if (bd
->props
->power
!= FB_BLANK_UNBLANK
||
69 bd
->props
->fb_blank
!= FB_BLANK_UNBLANK
)
72 level
= bd
->props
->brightness
;
74 del_timer_sync(&rinfo
->lvds_timer
);
77 lvds_gen_cntl
= INREG(LVDS_GEN_CNTL
);
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
;
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
));
94 lvds_gen_cntl
&= ~LVDS_BL_MOD_LEVEL_MASK
;
96 (radeon_bl_get_level_brightness(pdata
, level
) <<
97 LVDS_BL_MOD_LEVEL_SHIFT
);
98 OUTREG(LVDS_GEN_CNTL
, lvds_gen_cntl
);
100 rinfo
->init_state
.lvds_gen_cntl
&= ~LVDS_STATE_MASK
;
101 rinfo
->init_state
.lvds_gen_cntl
|= rinfo
->pending_lvds_gen_cntl
104 /* Asic bug, when turning off LVDS_ON, we have to make sure
105 RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
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
);
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
);
125 rinfo
->init_state
.lvds_gen_cntl
&= ~LVDS_STATE_MASK
;
126 rinfo
->init_state
.lvds_gen_cntl
|= (lvds_gen_cntl
& LVDS_STATE_MASK
);
131 static int radeon_bl_get_brightness(struct backlight_device
*bd
)
133 return bd
->props
->brightness
;
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),
143 void radeonfb_bl_init(struct radeonfb_info
*rinfo
)
145 struct backlight_device
*bd
;
146 struct radeon_bl_privdata
*pdata
;
149 if (rinfo
->mon1_type
!= MT_LCD
)
152 #ifdef CONFIG_PMAC_BACKLIGHT
153 if (!pmac_has_backlight_type("ati") &&
154 !pmac_has_backlight_type("mnca"))
158 pdata
= kmalloc(sizeof(struct radeon_bl_privdata
), GFP_KERNEL
);
160 printk("radeonfb: Memory allocation failed\n");
164 snprintf(name
, sizeof(name
), "radeonbl%d", rinfo
->info
->node
);
166 bd
= backlight_device_register(name
, pdata
, &radeon_bl_data
);
168 rinfo
->info
->bl_dev
= NULL
;
169 printk("radeonfb: Backlight registration failed\n");
173 pdata
->rinfo
= rinfo
;
175 /* Pardon me for that hack... maybe some day we can figure out in what
176 * direction backlight should work on a given panel?
179 (rinfo
->family
!= CHIP_FAMILY_RV200
&&
180 rinfo
->family
!= CHIP_FAMILY_RV250
&&
181 rinfo
->family
!= CHIP_FAMILY_RV280
&&
182 rinfo
->family
!= CHIP_FAMILY_RV350
);
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");
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
);
199 bd
->props
->brightness
= radeon_bl_data
.max_brightness
;
200 bd
->props
->power
= FB_BLANK_UNBLANK
;
201 bd
->props
->update_status(bd
);
204 #ifdef CONFIG_PMAC_BACKLIGHT
205 mutex_lock(&pmac_backlight_mutex
);
208 mutex_unlock(&pmac_backlight_mutex
);
211 printk("radeonfb: Backlight initialized (%s)\n", name
);
220 void radeonfb_bl_exit(struct radeonfb_info
*rinfo
)
222 #ifdef CONFIG_PMAC_BACKLIGHT
223 mutex_lock(&pmac_backlight_mutex
);
226 mutex_lock(&rinfo
->info
->bl_mutex
);
227 if (rinfo
->info
->bl_dev
) {
228 struct radeon_bl_privdata
*pdata
;
230 #ifdef CONFIG_PMAC_BACKLIGHT
231 if (pmac_backlight
== rinfo
->info
->bl_dev
)
232 pmac_backlight
= NULL
;
235 pdata
= class_get_devdata(&rinfo
->info
->bl_dev
->class_dev
);
236 backlight_device_unregister(rinfo
->info
->bl_dev
);
238 rinfo
->info
->bl_dev
= NULL
;
240 printk("radeonfb: Backlight unloaded\n");
242 mutex_unlock(&rinfo
->info
->bl_mutex
);
244 #ifdef CONFIG_PMAC_BACKLIGHT
245 mutex_unlock(&pmac_backlight_mutex
);