OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * i915_backlight.c - ChromeOS specific backlight support for pineview |
| 3 * |
| 4 * |
| 5 * Copyright (C) 2010 ChromeOS contributors |
| 6 * |
| 7 * This program is free software; you can redistribute it and/or modify |
| 8 * it under the terms of the GNU General Public License as published by |
| 9 * the Free Software Foundation; either version 2 of the License, or |
| 10 * (at your option) any later version. |
| 11 * |
| 12 * This program is distributed in the hope that it will be useful, |
| 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 * GNU General Public License for more details. |
| 16 * |
| 17 * You should have received a copy of the GNU General Public License |
| 18 * along with this program; if not, write to the Free Software |
| 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 20 */ |
| 21 |
| 22 #include <linux/backlight.h> |
| 23 |
| 24 #include "drmP.h" |
| 25 #include "i915_drm.h" |
| 26 #include "i915_drv.h" |
| 27 |
| 28 /* |
| 29 * Somewhat arbitrarily choose a max brightness level of 256 (as full "on") |
| 30 * and a PWM frequency of 0x1000. The frequency can be as high as 0x7fff, |
| 31 * but we do not need that level of flexibility. |
| 32 */ |
| 33 #define MAX_BRIGHTNESS 256 |
| 34 #define PWM_FREQUENCY 0x1000 |
| 35 |
| 36 /* |
| 37 * The Pineview LVDS Backlight PWM Control register is a 32 bit word split |
| 38 * into two unsigned 16 bit words: the high order short is the cycle frequency, |
| 39 * and the low order word is the duty cycle. According to i915_opregion.c, |
| 40 * the low order bit of each short is unused. |
| 41 * |
| 42 * While the frequency is hardcoded, these macros provide masking and shifting |
| 43 * for the duty cycle. |
| 44 */ |
| 45 #define CTL_TO_PWM(ctl) ((ctl & BACKLIGHT_DUTY_CYCLE_MASK) >> 1) |
| 46 #define PWM_TO_CTL(pwm) ((pwm << 1) & BACKLIGHT_DUTY_CYCLE_MASK) |
| 47 |
| 48 static int i915_get_intensity(struct backlight_device *bd) |
| 49 { |
| 50 struct drm_device *dev = bl_get_data(bd); |
| 51 struct drm_i915_private *dev_priv = dev->dev_private; |
| 52 u32 blc_pwm_ctl; |
| 53 int level, pwm_val; |
| 54 |
| 55 blc_pwm_ctl = I915_READ(BLC_PWM_CTL); |
| 56 pwm_val = CTL_TO_PWM(blc_pwm_ctl); |
| 57 level = (pwm_val * MAX_BRIGHTNESS) / PWM_FREQUENCY; |
| 58 |
| 59 return level; |
| 60 } |
| 61 |
| 62 static int i915_set_intensity(struct backlight_device *bd) |
| 63 { |
| 64 struct drm_device *dev = bl_get_data(bd); |
| 65 struct drm_i915_private *dev_priv = dev->dev_private; |
| 66 int level, pwm_val; |
| 67 u32 blc_pwm_ctl; |
| 68 |
| 69 level = bd->props.brightness; |
| 70 if (level > MAX_BRIGHTNESS) |
| 71 level = MAX_BRIGHTNESS; |
| 72 |
| 73 pwm_val = (level * PWM_FREQUENCY) / MAX_BRIGHTNESS; |
| 74 blc_pwm_ctl = (PWM_FREQUENCY << BACKLIGHT_MODULATION_FREQ_SHIFT) | |
| 75 PWM_TO_CTL(pwm_val); |
| 76 I915_WRITE(BLC_PWM_CTL, blc_pwm_ctl); |
| 77 |
| 78 return 0; |
| 79 } |
| 80 |
| 81 static struct backlight_ops i915_bl_ops = { |
| 82 .get_brightness = i915_get_intensity, |
| 83 .update_status = i915_set_intensity, |
| 84 }; |
| 85 |
| 86 void i915_backlight_init(struct drm_device *dev) |
| 87 { |
| 88 struct drm_i915_private *dev_priv = dev->dev_private; |
| 89 struct backlight_device *bd; |
| 90 |
| 91 if (!IS_PINEVIEW(dev)) { |
| 92 dev_printk(KERN_WARNING, &dev->pdev->dev, |
| 93 "i915_backlight_init only supports the pineview version\n"); |
| 94 return; |
| 95 } |
| 96 |
| 97 bd = backlight_device_register("i915_backlight", |
| 98 &dev->pdev->dev, dev, &i915_bl_ops); |
| 99 if (IS_ERR(bd)) { |
| 100 dev_printk(KERN_WARNING, &dev->pdev->dev, |
| 101 "Unable to register i915 backlight.\n"); |
| 102 return; |
| 103 } |
| 104 |
| 105 dev_priv->backlight = bd; |
| 106 bd->props.max_brightness = MAX_BRIGHTNESS; |
| 107 bd->props.brightness = 0; |
| 108 backlight_update_status(bd); |
| 109 return; |
| 110 } |
| 111 |
| 112 void i915_backlight_exit(struct drm_device *dev) |
| 113 { |
| 114 struct drm_i915_private *dev_priv = dev->dev_private; |
| 115 |
| 116 if (dev_priv->backlight) { |
| 117 backlight_device_unregister(dev_priv->backlight); |
| 118 dev_priv->backlight = NULL; |
| 119 } |
| 120 } |
OLD | NEW |