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; |
+ } |
+} |