summaryrefslogtreecommitdiff
path: root/drivers/staging/gma500/mrst_device.c
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2011-07-05 15:38:40 +0100
committerGreg Kroah-Hartman <gregkh@suse.de>2011-07-05 08:20:40 -0700
commit6a7afe3acc4bfa54b1433b7f6b5b467ec05ee15b (patch)
tree86e369afb6494bf0819e5869c0b1acd64a96051b /drivers/staging/gma500/mrst_device.c
parent92367fe1bca91efa7f689127ba45080d4303d609 (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.c137
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,