diff options
author | Alan Cox <alan@linux.intel.com> | 2011-07-05 15:38:40 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-07-05 08:20:40 -0700 |
commit | 6a7afe3acc4bfa54b1433b7f6b5b467ec05ee15b (patch) | |
tree | 86e369afb6494bf0819e5869c0b1acd64a96051b /drivers/staging/gma500/mrst_device.c | |
parent | 92367fe1bca91efa7f689127ba45080d4303d609 (diff) |
gma500: continue abstracting platform specific code
Next obvious target - backlight support
Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/gma500/mrst_device.c')
-rw-r--r-- | drivers/staging/gma500/mrst_device.c | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/drivers/staging/gma500/mrst_device.c b/drivers/staging/gma500/mrst_device.c index 5cd82838a052..daeeb18d9273 100644 --- a/drivers/staging/gma500/mrst_device.c +++ b/drivers/staging/gma500/mrst_device.c @@ -17,6 +17,7 @@ * **************************************************************************/ +#include <linux/backlight.h> #include <drm/drmP.h> #include <drm/drm.h> #include "psb_drm.h" @@ -42,7 +43,138 @@ static int mrst_output_init(struct drm_device *dev) } /* + * Provide the low level interfaces for the Moorestown backlight + */ + +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + +#define MRST_BLC_MAX_PWM_REG_FREQ 0xFFFF +#define BLC_PWM_PRECISION_FACTOR 100 /* 10000000 */ +#define BLC_PWM_FREQ_CALC_CONSTANT 32 +#define MHz 1000000 +#define BLC_ADJUSTMENT_MAX 100 + +static struct backlight_device *mrst_backlight_device; +static int mrst_brightness; + +static int mrst_set_brightness(struct backlight_device *bd) +{ + struct drm_device *dev = bl_get_data(mrst_backlight_device); + struct drm_psb_private *dev_priv = dev->dev_private; + int level = bd->props.brightness; + u32 blc_pwm_ctl; + u32 max_pwm_blc; + + /* Percentage 1-100% being valid */ + if (level < 1) + level = 1; + + if (gma_power_begin(dev, 0)) { + /* Calculate and set the brightness value */ + max_pwm_blc = REG_READ(BLC_PWM_CTL) >> 16; + blc_pwm_ctl = level * max_pwm_blc / 100; + + /* Adjust the backlight level with the percent in + * dev_priv->blc_adj1; + */ + blc_pwm_ctl = blc_pwm_ctl * dev_priv->blc_adj1; + blc_pwm_ctl = blc_pwm_ctl / 100; + + /* Adjust the backlight level with the percent in + * dev_priv->blc_adj2; + */ + blc_pwm_ctl = blc_pwm_ctl * dev_priv->blc_adj2; + blc_pwm_ctl = blc_pwm_ctl / 100; + + /* force PWM bit on */ + REG_WRITE(BLC_PWM_CTL2, (0x80000000 | REG_READ(BLC_PWM_CTL2))); + REG_WRITE(BLC_PWM_CTL, (max_pwm_blc << 16) | blc_pwm_ctl); + gma_power_end(dev); + } + mrst_brightness = level; + return 0; +} + +static int mrst_get_brightness(struct backlight_device *bd) +{ + /* return locally cached var instead of HW read (due to DPST etc.) */ + /* FIXME: ideally return actual value in case firmware fiddled with + it */ + return mrst_brightness; +} + +static int device_backlight_init(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + unsigned long core_clock; + u16 bl_max_freq; + uint32_t value; + uint32_t blc_pwm_precision_factor; + + dev_priv->blc_adj1 = BLC_ADJUSTMENT_MAX; + dev_priv->blc_adj2 = BLC_ADJUSTMENT_MAX; + bl_max_freq = 256; + /* this needs to be set elsewhere */ + blc_pwm_precision_factor = BLC_PWM_PRECISION_FACTOR; + + core_clock = dev_priv->core_freq; + + value = (core_clock * MHz) / BLC_PWM_FREQ_CALC_CONSTANT; + value *= blc_pwm_precision_factor; + value /= bl_max_freq; + value /= blc_pwm_precision_factor; + + if (gma_power_begin(dev, false)) { + if (value > (unsigned long long)MRST_BLC_MAX_PWM_REG_FREQ) + return -ERANGE; + else { + REG_WRITE(BLC_PWM_CTL2, + (0x80000000 | REG_READ(BLC_PWM_CTL2))); + REG_WRITE(BLC_PWM_CTL, value | (value << 16)); + } + gma_power_end(dev); + } + return 0; +} + +static const struct backlight_ops mrst_ops = { + .get_brightness = mrst_get_brightness, + .update_status = mrst_set_brightness, +}; + +int mrst_backlight_init(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + int ret; + struct backlight_properties props; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.max_brightness = 100; + props.type = BACKLIGHT_PLATFORM; + + mrst_backlight_device = backlight_device_register("mrst-bl", + NULL, (void *)dev, &mrst_ops, &props); + + if (IS_ERR(mrst_backlight_device)) + return PTR_ERR(mrst_backlight_device); + + ret = device_backlight_init(dev); + if (ret < 0) { + backlight_device_unregister(mrst_backlight_device); + return ret; + } + mrst_backlight_device->props.brightness = 100; + mrst_backlight_device->props.max_brightness = 100; + backlight_update_status(mrst_backlight_device); + dev_priv->backlight_device = mrst_backlight_device; + return 0; +} + +#endif + +/* * Provide the Moorestown specific chip logic and low level methods + * for power management */ static void mrst_init_pm(struct drm_device *dev) @@ -221,6 +353,11 @@ static int mrst_power_up(struct drm_device *dev) const struct psb_ops mrst_chip_ops = { .output_init = mrst_output_init, + +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + .backlight_init = mrst_backlight_init, +#endif + .init_pm = mrst_init_pm, .save_regs = mrst_save_display_registers, .restore_regs = mrst_restore_display_registers, |