Blame view

drivers/video/aty/radeon_backlight.c 5.95 KB
5474c120a   Michael Hanselmann   [PATCH] Rewritten...
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   Michael Hanselmann   [PATCH] Rewritten...
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   Michael Hanselmann   [PATCH] Rewritten...
29
  	int rlevel;
5474c120a   Michael Hanselmann   [PATCH] Rewritten...
30
  	/* Get and convert the value */
37ce69a57   Richard Purdie   backlight: Rework...
31
  	/* No locking of bl_curve since we read a single value */
5474c120a   Michael Hanselmann   [PATCH] Rewritten...
32
33
  	rlevel = pdata->rinfo->info->bl_curve[level] *
  		 FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL;
5474c120a   Michael Hanselmann   [PATCH] Rewritten...
34
35
36
37
  	if (rlevel < 0)
  		rlevel = 0;
  	else if (rlevel > MAX_RADEON_LEVEL)
  		rlevel = MAX_RADEON_LEVEL;
cab267c65   Michael Hanselmann   [PATCH] powermac ...
38
39
  	if (pdata->negative)
  		rlevel = MAX_RADEON_LEVEL - rlevel;
5474c120a   Michael Hanselmann   [PATCH] Rewritten...
40
41
42
43
44
  	return rlevel;
  }
  
  static int radeon_bl_update_status(struct backlight_device *bd)
  {
655bfd7ae   Richard Purdie   backlight: Conver...
45
  	struct radeon_bl_privdata *pdata = bl_get_data(bd);
5474c120a   Michael Hanselmann   [PATCH] Rewritten...
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   Richard Purdie   backlight: Separa...
57
58
          if (bd->props.power != FB_BLANK_UNBLANK ||
  	    bd->props.fb_blank != FB_BLANK_UNBLANK)
5474c120a   Michael Hanselmann   [PATCH] Rewritten...
59
60
  		level = 0;
  	else
599a52d12   Richard Purdie   backlight: Separa...
61
  		level = bd->props.brightness;
5474c120a   Michael Hanselmann   [PATCH] Rewritten...
62
63
  
  	del_timer_sync(&rinfo->lvds_timer);
b1ee26bab   Benjamin Herrenschmidt   radeonfb: acceler...
64
  	radeon_engine_idle(rinfo);
5474c120a   Michael Hanselmann   [PATCH] Rewritten...
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   Richard Purdie   backlight: Separa...
122
  	return bd->props.brightness;
5474c120a   Michael Hanselmann   [PATCH] Rewritten...
123
  }
599a52d12   Richard Purdie   backlight: Separa...
124
  static struct backlight_ops radeon_bl_data = {
5474c120a   Michael Hanselmann   [PATCH] Rewritten...
125
126
  	.get_brightness = radeon_bl_get_brightness,
  	.update_status	= radeon_bl_update_status,
5474c120a   Michael Hanselmann   [PATCH] Rewritten...
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   James Simmons   fbdev: update aft...
152
  	bd = backlight_device_register(name, rinfo->info->dev, pdata, &radeon_bl_data);
5474c120a   Michael Hanselmann   [PATCH] Rewritten...
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   Michael Hanselmann   [PATCH] Rewritten...
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   Michael Hanselmann   [PATCH] Rewritten...
181

599a52d12   Richard Purdie   backlight: Separa...
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   Richard Purdie   backlight: Fix ex...
185
  	backlight_update_status(bd);
5474c120a   Michael Hanselmann   [PATCH] Rewritten...
186

5474c120a   Michael Hanselmann   [PATCH] Rewritten...
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   Richard Purdie   backlight: Rework...
199
  	struct backlight_device *bd = rinfo->info->bl_dev;
5474c120a   Michael Hanselmann   [PATCH] Rewritten...
200

37ce69a57   Richard Purdie   backlight: Rework...
201
  	if (bd) {
5474c120a   Michael Hanselmann   [PATCH] Rewritten...
202
  		struct radeon_bl_privdata *pdata;
655bfd7ae   Richard Purdie   backlight: Conver...
203
  		pdata = bl_get_data(bd);
37ce69a57   Richard Purdie   backlight: Rework...
204
  		backlight_device_unregister(bd);
5474c120a   Michael Hanselmann   [PATCH] Rewritten...
205
206
207
208
209
210
  		kfree(pdata);
  		rinfo->info->bl_dev = NULL;
  
  		printk("radeonfb: Backlight unloaded
  ");
  	}
5474c120a   Michael Hanselmann   [PATCH] Rewritten...
211
  }