0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include "radeonfb.h"
0011 #include <linux/backlight.h>
0012 #include <linux/slab.h>
0013
0014 #ifdef CONFIG_PMAC_BACKLIGHT
0015 #include <asm/backlight.h>
0016 #endif
0017
0018 #define MAX_RADEON_LEVEL 0xFF
0019
0020 struct radeon_bl_privdata {
0021 struct radeonfb_info *rinfo;
0022 uint8_t negative;
0023 };
0024
0025 static int radeon_bl_get_level_brightness(struct radeon_bl_privdata *pdata,
0026 int level)
0027 {
0028 int rlevel;
0029
0030
0031
0032 rlevel = pdata->rinfo->info->bl_curve[level] *
0033 FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL;
0034
0035 if (rlevel < 0)
0036 rlevel = 0;
0037 else if (rlevel > MAX_RADEON_LEVEL)
0038 rlevel = MAX_RADEON_LEVEL;
0039
0040 if (pdata->negative)
0041 rlevel = MAX_RADEON_LEVEL - rlevel;
0042
0043 return rlevel;
0044 }
0045
0046 static int radeon_bl_update_status(struct backlight_device *bd)
0047 {
0048 struct radeon_bl_privdata *pdata = bl_get_data(bd);
0049 struct radeonfb_info *rinfo = pdata->rinfo;
0050 u32 lvds_gen_cntl, tmpPixclksCntl;
0051 int level;
0052
0053 if (rinfo->mon1_type != MT_LCD)
0054 return 0;
0055
0056
0057
0058
0059
0060 if (bd->props.power != FB_BLANK_UNBLANK ||
0061 bd->props.fb_blank != FB_BLANK_UNBLANK)
0062 level = 0;
0063 else
0064 level = bd->props.brightness;
0065
0066 del_timer_sync(&rinfo->lvds_timer);
0067 radeon_engine_idle();
0068
0069 lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
0070 if (level > 0) {
0071 lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
0072 if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) {
0073 lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON);
0074 lvds_gen_cntl |= LVDS_BLON | LVDS_EN;
0075 OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
0076 lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
0077 lvds_gen_cntl |=
0078 (radeon_bl_get_level_brightness(pdata, level) <<
0079 LVDS_BL_MOD_LEVEL_SHIFT);
0080 lvds_gen_cntl |= LVDS_ON;
0081 lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN);
0082 rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
0083 mod_timer(&rinfo->lvds_timer,
0084 jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
0085 } else {
0086 lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
0087 lvds_gen_cntl |=
0088 (radeon_bl_get_level_brightness(pdata, level) <<
0089 LVDS_BL_MOD_LEVEL_SHIFT);
0090 OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
0091 }
0092 rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
0093 rinfo->init_state.lvds_gen_cntl |= rinfo->pending_lvds_gen_cntl
0094 & LVDS_STATE_MASK;
0095 } else {
0096
0097
0098
0099 tmpPixclksCntl = INPLL(PIXCLKS_CNTL);
0100 if (rinfo->is_mobility || rinfo->is_IGP)
0101 OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
0102 lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN);
0103 lvds_gen_cntl |= (radeon_bl_get_level_brightness(pdata, 0) <<
0104 LVDS_BL_MOD_LEVEL_SHIFT);
0105 lvds_gen_cntl |= LVDS_DISPLAY_DIS;
0106 OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
0107 udelay(100);
0108 lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN);
0109 OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
0110 lvds_gen_cntl &= ~(LVDS_DIGON);
0111 rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
0112 mod_timer(&rinfo->lvds_timer,
0113 jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
0114 if (rinfo->is_mobility || rinfo->is_IGP)
0115 OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl);
0116 }
0117 rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
0118 rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK);
0119
0120 return 0;
0121 }
0122
0123 static const struct backlight_ops radeon_bl_data = {
0124 .update_status = radeon_bl_update_status,
0125 };
0126
0127 void radeonfb_bl_init(struct radeonfb_info *rinfo)
0128 {
0129 struct backlight_properties props;
0130 struct backlight_device *bd;
0131 struct radeon_bl_privdata *pdata;
0132 char name[12];
0133
0134 if (rinfo->mon1_type != MT_LCD)
0135 return;
0136
0137 #ifdef CONFIG_PMAC_BACKLIGHT
0138 if (!pmac_has_backlight_type("ati") &&
0139 !pmac_has_backlight_type("mnca"))
0140 return;
0141 #endif
0142
0143 pdata = kmalloc(sizeof(struct radeon_bl_privdata), GFP_KERNEL);
0144 if (!pdata) {
0145 printk("radeonfb: Memory allocation failed\n");
0146 goto error;
0147 }
0148
0149 snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node);
0150
0151 memset(&props, 0, sizeof(struct backlight_properties));
0152 props.type = BACKLIGHT_RAW;
0153 props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
0154 bd = backlight_device_register(name, rinfo->info->dev, pdata,
0155 &radeon_bl_data, &props);
0156 if (IS_ERR(bd)) {
0157 rinfo->info->bl_dev = NULL;
0158 printk("radeonfb: Backlight registration failed\n");
0159 goto error;
0160 }
0161
0162 pdata->rinfo = rinfo;
0163
0164
0165
0166
0167 pdata->negative =
0168 (rinfo->family != CHIP_FAMILY_RV200 &&
0169 rinfo->family != CHIP_FAMILY_RV250 &&
0170 rinfo->family != CHIP_FAMILY_RV280 &&
0171 rinfo->family != CHIP_FAMILY_RV350);
0172
0173 #ifdef CONFIG_PMAC_BACKLIGHT
0174 pdata->negative = pdata->negative ||
0175 of_machine_is_compatible("PowerBook4,3") ||
0176 of_machine_is_compatible("PowerBook6,3") ||
0177 of_machine_is_compatible("PowerBook6,5");
0178 #endif
0179
0180 rinfo->info->bl_dev = bd;
0181 fb_bl_default_curve(rinfo->info, 0,
0182 63 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL,
0183 217 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL);
0184
0185 bd->props.brightness = bd->props.max_brightness;
0186 bd->props.power = FB_BLANK_UNBLANK;
0187 backlight_update_status(bd);
0188
0189 printk("radeonfb: Backlight initialized (%s)\n", name);
0190
0191 return;
0192
0193 error:
0194 kfree(pdata);
0195 return;
0196 }
0197
0198 void radeonfb_bl_exit(struct radeonfb_info *rinfo)
0199 {
0200 struct backlight_device *bd = rinfo->info->bl_dev;
0201
0202 if (bd) {
0203 struct radeon_bl_privdata *pdata;
0204
0205 pdata = bl_get_data(bd);
0206 backlight_device_unregister(bd);
0207 kfree(pdata);
0208 rinfo->info->bl_dev = NULL;
0209
0210 printk("radeonfb: Backlight unloaded\n");
0211 }
0212 }