| Index: drivers/gpu/drm/i915/i915_backlight.c | 
| diff --git a/drivers/gpu/drm/i915/i915_backlight.c b/drivers/gpu/drm/i915/i915_backlight.c | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..18e33e73dd1c41d45dc176e717810193ef11b37d | 
| --- /dev/null | 
| +++ b/drivers/gpu/drm/i915/i915_backlight.c | 
| @@ -0,0 +1,120 @@ | 
| +/* | 
| + *  i915_backlight.c - ChromeOS specific backlight support for pineview | 
| + * | 
| + * | 
| + *  Copyright (C) 2010 ChromeOS contributors | 
| + * | 
| + *  This program is free software; you can redistribute it and/or modify | 
| + *  it under the terms of the GNU General Public License as published by | 
| + *  the Free Software Foundation; either version 2 of the License, or | 
| + *  (at your option) any later version. | 
| + * | 
| + *  This program is distributed in the hope that it will be useful, | 
| + *  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
| + *  GNU General Public License for more details. | 
| + * | 
| + *  You should have received a copy of the GNU General Public License | 
| + *  along with this program; if not, write to the Free Software | 
| + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
| + */ | 
| + | 
| +#include <linux/backlight.h> | 
| + | 
| +#include "drmP.h" | 
| +#include "i915_drm.h" | 
| +#include "i915_drv.h" | 
| + | 
| +/* | 
| + * Somewhat arbitrarily choose a max brightness level of 256 (as full "on") | 
| + * and a PWM frequency of 0x1000.  The frequency can be as high as 0x7fff, | 
| + * but we do not need that level of flexibility. | 
| + */ | 
| +#define MAX_BRIGHTNESS 256 | 
| +#define PWM_FREQUENCY 0x1000 | 
| + | 
| +/* | 
| + * The Pineview LVDS Backlight PWM Control register is a 32 bit word split | 
| + * into two unsigned 16 bit words: the high order short is the cycle frequency, | 
| + * and the low order word is the duty cycle.  According to i915_opregion.c, | 
| + * the low order bit of each short is unused. | 
| + * | 
| + * While the frequency is hardcoded, these macros provide masking and shifting | 
| + * for the duty cycle. | 
| + */ | 
| +#define CTL_TO_PWM(ctl) ((ctl & BACKLIGHT_DUTY_CYCLE_MASK) >> 1) | 
| +#define PWM_TO_CTL(pwm) ((pwm << 1) & BACKLIGHT_DUTY_CYCLE_MASK) | 
| + | 
| +static int i915_get_intensity(struct backlight_device *bd) | 
| +{ | 
| +	struct drm_device *dev = bl_get_data(bd); | 
| +	struct drm_i915_private *dev_priv = dev->dev_private; | 
| +	u32 blc_pwm_ctl; | 
| +	int level, pwm_val; | 
| + | 
| +	blc_pwm_ctl = I915_READ(BLC_PWM_CTL); | 
| +	pwm_val = CTL_TO_PWM(blc_pwm_ctl); | 
| +	level = (pwm_val * MAX_BRIGHTNESS) / PWM_FREQUENCY; | 
| + | 
| +	return level; | 
| +} | 
| + | 
| +static int i915_set_intensity(struct backlight_device *bd) | 
| +{ | 
| +	struct drm_device *dev = bl_get_data(bd); | 
| +	struct drm_i915_private *dev_priv = dev->dev_private; | 
| +	int level, pwm_val; | 
| +	u32 blc_pwm_ctl; | 
| + | 
| +	level = bd->props.brightness; | 
| +	if (level > MAX_BRIGHTNESS) | 
| +		level = MAX_BRIGHTNESS; | 
| + | 
| +	pwm_val = (level * PWM_FREQUENCY) / MAX_BRIGHTNESS; | 
| +	blc_pwm_ctl = (PWM_FREQUENCY << BACKLIGHT_MODULATION_FREQ_SHIFT) | | 
| +		PWM_TO_CTL(pwm_val); | 
| +	I915_WRITE(BLC_PWM_CTL, blc_pwm_ctl); | 
| + | 
| +	return 0; | 
| +} | 
| + | 
| +static struct backlight_ops i915_bl_ops = { | 
| +	.get_brightness = i915_get_intensity, | 
| +	.update_status = i915_set_intensity, | 
| +}; | 
| + | 
| +void i915_backlight_init(struct drm_device *dev) | 
| +{ | 
| +	struct drm_i915_private *dev_priv = dev->dev_private; | 
| +	struct backlight_device *bd; | 
| + | 
| +	if (!IS_PINEVIEW(dev)) { | 
| +		dev_printk(KERN_WARNING, &dev->pdev->dev, | 
| +		"i915_backlight_init only supports the pineview version\n"); | 
| +		return; | 
| +	} | 
| + | 
| +	bd = backlight_device_register("i915_backlight", | 
| +		&dev->pdev->dev, dev, &i915_bl_ops); | 
| +	if (IS_ERR(bd)) { | 
| +		dev_printk(KERN_WARNING, &dev->pdev->dev, | 
| +			"Unable to register i915 backlight.\n"); | 
| +		return; | 
| +	} | 
| + | 
| +	dev_priv->backlight = bd; | 
| +	bd->props.max_brightness = MAX_BRIGHTNESS; | 
| +	bd->props.brightness = 0; | 
| +	backlight_update_status(bd); | 
| +	return; | 
| +} | 
| + | 
| +void i915_backlight_exit(struct drm_device *dev) | 
| +{ | 
| +	struct drm_i915_private *dev_priv = dev->dev_private; | 
| + | 
| +	if (dev_priv->backlight) { | 
| +		backlight_device_unregister(dev_priv->backlight); | 
| +		dev_priv->backlight = NULL; | 
| +	} | 
| +} | 
|  |