aboutsummaryrefslogtreecommitdiffstats
path: root/recipes/linux/linux-openmoko-2.6.34/0004-JBT6k74-work-for-KMS.patch
diff options
context:
space:
mode:
Diffstat (limited to 'recipes/linux/linux-openmoko-2.6.34/0004-JBT6k74-work-for-KMS.patch')
-rw-r--r--recipes/linux/linux-openmoko-2.6.34/0004-JBT6k74-work-for-KMS.patch540
1 files changed, 540 insertions, 0 deletions
diff --git a/recipes/linux/linux-openmoko-2.6.34/0004-JBT6k74-work-for-KMS.patch b/recipes/linux/linux-openmoko-2.6.34/0004-JBT6k74-work-for-KMS.patch
new file mode 100644
index 0000000000..692896f957
--- /dev/null
+++ b/recipes/linux/linux-openmoko-2.6.34/0004-JBT6k74-work-for-KMS.patch
@@ -0,0 +1,540 @@
+From 2042106d96a13c2a15f1425fe9133257b1e0fbed Mon Sep 17 00:00:00 2001
+From: Thomas White <taw@bitwiz.org.uk>
+Date: Sat, 21 Nov 2009 21:42:16 +0100
+Subject: [PATCH 04/13] JBT6k74 work for KMS
+
+This simplifies the JBT6k74 driver, and adds hooks for the Glamo driver to cooperate
+more closely with it.
+
+Signed-off-by: Thomas White <taw@bitwiz.org.uk>
+---
+ drivers/video/backlight/jbt6k74.c | 252 ++++++++++++++++++------------------
+ include/linux/jbt6k74.h | 17 +++-
+ 2 files changed, 142 insertions(+), 127 deletions(-)
+
+diff --git a/drivers/video/backlight/jbt6k74.c b/drivers/video/backlight/jbt6k74.c
+index 8450904..91651e7 100644
+--- a/drivers/video/backlight/jbt6k74.c
++++ b/drivers/video/backlight/jbt6k74.c
+@@ -101,20 +101,10 @@ enum jbt_register {
+ JBT_REG_HCLOCK_QVGA = 0xed,
+ };
+
+-enum jbt_resolution {
+- JBT_RESOLUTION_VGA,
+- JBT_RESOLUTION_QVGA,
+-};
+-
+-enum jbt_power_mode {
+- JBT_POWER_MODE_DEEP_STANDBY,
+- JBT_POWER_MODE_SLEEP,
+- JBT_POWER_MODE_NORMAL,
+-};
+
+ static const char *jbt_power_mode_names[] = {
+- [JBT_POWER_MODE_DEEP_STANDBY] = "deep-standby",
+- [JBT_POWER_MODE_SLEEP] = "sleep",
++ [JBT_POWER_MODE_OFF] = "off",
++ [JBT_POWER_MODE_STANDBY] = "standby",
+ [JBT_POWER_MODE_NORMAL] = "normal",
+ };
+
+@@ -123,6 +113,7 @@ static const char *jbt_resolution_names[] = {
+ [JBT_RESOLUTION_QVGA] = "qvga",
+ };
+
++
+ struct jbt_info {
+ struct mutex lock; /* protects this structure */
+ enum jbt_resolution resolution;
+@@ -141,6 +132,8 @@ struct jbt_info {
+ uint16_t reg_cache[0xEE];
+ };
+
++struct jbt_info *jbt_global;
++
+ #define JBT_COMMAND 0x000
+ #define JBT_DATA 0x100
+
+@@ -156,6 +149,8 @@ static int jbt_reg_write_nodata(struct jbt_info *jbt, uint8_t reg)
+ else
+ dev_err(&jbt->spi->dev, "Write failed: %d\n", ret);
+
++ mdelay(1);
++
+ return ret;
+ }
+
+@@ -173,6 +168,8 @@ static int jbt_reg_write(struct jbt_info *jbt, uint8_t reg, uint8_t data)
+ else
+ dev_err(&jbt->spi->dev, "Write failed: %d\n", ret);
+
++ mdelay(1);
++
+ return ret;
+ }
+
+@@ -191,6 +188,8 @@ static int jbt_reg_write16(struct jbt_info *jbt, uint8_t reg, uint16_t data)
+ else
+ dev_err(&jbt->spi->dev, "Write failed: %d\n", ret);
+
++ mdelay(1);
++
+ return ret;
+ }
+
+@@ -218,7 +217,7 @@ static int jbt_init_regs(struct jbt_info *jbt)
+ * to avoid red / blue flicker
+ */
+ ret |= jbt_reg_write(jbt, JBT_REG_ASW_SLEW, 0x00 | (1 << 5));
+- ret |= jbt_reg_write(jbt, JBT_REG_DUMMY_DISPLAY, 0x00);
++ ret |= jbt_reg_write(jbt, JBT_REG_DUMMY_DISPLAY, 0xff);
+
+ ret |= jbt_reg_write(jbt, JBT_REG_SLEEP_OUT_FR_A, 0x11);
+ ret |= jbt_reg_write(jbt, JBT_REG_SLEEP_OUT_FR_B, 0x11);
+@@ -260,14 +259,18 @@ static int jbt_init_regs(struct jbt_info *jbt)
+ return ret ? -EIO : 0;
+ }
+
+-static int jbt_standby_to_sleep(struct jbt_info *jbt)
++
++static int jbt_off_to_normal(struct jbt_info *jbt)
+ {
+ int ret;
++
+ struct jbt6k74_platform_data *pdata = jbt->spi->dev.platform_data;
+
+ gpio_set_value_cansleep(pdata->gpio_reset, 1);
+ ret = regulator_bulk_enable(ARRAY_SIZE(jbt->supplies), jbt->supplies);
+
++ mdelay(120);
++
+ /* three times command zero */
+ ret |= jbt_reg_write_nodata(jbt, 0x00);
+ mdelay(1);
+@@ -279,18 +282,11 @@ static int jbt_standby_to_sleep(struct jbt_info *jbt)
+ /* deep standby out */
+ ret |= jbt_reg_write(jbt, JBT_REG_POWER_ON_OFF, 0x11);
+ mdelay(1);
+- ret = jbt_reg_write(jbt, JBT_REG_DISPLAY_MODE, 0x28);
++ ret |= jbt_reg_write(jbt, JBT_REG_DISPLAY_MODE, 0x28);
+
+ /* (re)initialize register set */
+ ret |= jbt_init_regs(jbt);
+
+- return ret ? -EIO : 0;
+-}
+-
+-static int jbt_sleep_to_normal(struct jbt_info *jbt)
+-{
+- int ret;
+-
+ /* Make sure we are 120 ms after SLEEP_OUT */
+ if (time_before(jiffies, jbt->next_sleep))
+ mdelay(jiffies_to_msecs(jbt->next_sleep - jiffies));
+@@ -320,6 +316,7 @@ static int jbt_sleep_to_normal(struct jbt_info *jbt)
+
+ /* Sleep mode off */
+ ret |= jbt_reg_write_nodata(jbt, JBT_REG_SLEEP_OUT);
++
+ jbt->next_sleep = jiffies + msecs_to_jiffies(120);
+
+ /* Allow the booster and display controller to restart stably */
+@@ -328,45 +325,68 @@ static int jbt_sleep_to_normal(struct jbt_info *jbt)
+ return ret ? -EIO : 0;
+ }
+
+-static int jbt_normal_to_sleep(struct jbt_info *jbt)
++static int jbt_normal_to_off(struct jbt_info *jbt)
+ {
+ int ret;
++ struct jbt6k74_platform_data *pdata = jbt->spi->dev.platform_data;
+
+- /* Make sure we are 120 ms after SLEEP_OUT */
+- while (time_before(jiffies, jbt->next_sleep))
+- cpu_relax();
++ /* Pull the plug! */
++ ret = regulator_bulk_disable(ARRAY_SIZE(jbt->supplies),
++ jbt->supplies);
+
++ if (!ret)
++ gpio_set_value_cansleep(pdata->gpio_reset, 0);
++
++ return ret ? -EIO : 0;
++}
++
++
++static int jbt_normal_to_standby(struct jbt_info *jbt)
++{
++ int ret;
++
++ if ( jbt->power_mode != JBT_POWER_MODE_NORMAL ) return 0;
++
++ /* Make sure we are 120 ms after SLEEP_{IN,OUT} */
++ while (time_before(jiffies, jbt->next_sleep)) cpu_relax();
++
++ /* Sleep mode on */
+ ret = jbt_reg_write_nodata(jbt, JBT_REG_DISPLAY_OFF);
+ ret |= jbt_reg_write16(jbt, JBT_REG_OUTPUT_CONTROL, 0x8000 | 1 << 3);
++
+ ret |= jbt_reg_write_nodata(jbt, JBT_REG_SLEEP_IN);
+- jbt->next_sleep = jiffies + msecs_to_jiffies(120);
++ jbt->next_sleep = jiffies + msecs_to_jiffies(150);
+
+- /* Allow the internal circuits to stop automatically */
+- mdelay(5);
++ jbt->power_mode = JBT_POWER_MODE_STANDBY;
+
+ return ret ? -EIO : 0;
+ }
+
+-static int jbt_sleep_to_standby(struct jbt_info *jbt)
++
++static int jbt_standby_to_normal(struct jbt_info *jbt)
+ {
+ int ret;
+- struct jbt6k74_platform_data *pdata = jbt->spi->dev.platform_data;
+
+- ret = jbt_reg_write(jbt, JBT_REG_POWER_ON_OFF, 0x00);
++ if ( jbt->power_mode != JBT_POWER_MODE_STANDBY ) return 0;
+
+- if (!ret)
+- ret = regulator_bulk_disable(ARRAY_SIZE(jbt->supplies), jbt->supplies);
++ /* Make sure we are 120 ms after SLEEP_{IN,OUT} */
++ while (time_before(jiffies, jbt->next_sleep)) cpu_relax();
+
+- if (!ret)
+- gpio_set_value_cansleep(pdata->gpio_reset, 0);
++ ret = jbt_reg_write_nodata(jbt, JBT_REG_SLEEP_OUT);
++ jbt->next_sleep = jiffies + msecs_to_jiffies(150);
+
+- return ret;
++ ret |= jbt_reg_write_nodata(jbt, JBT_REG_DISPLAY_ON);
++ ret |= jbt_reg_write16(jbt, JBT_REG_OUTPUT_CONTROL, 0xdff9);
++
++ jbt->power_mode = JBT_POWER_MODE_NORMAL;
++
++ return ret ? -EIO : 0;
+ }
+
++
+ static int jbt6k74_enter_power_mode(struct jbt_info *jbt,
+ enum jbt_power_mode new_mode)
+ {
+- struct jbt6k74_platform_data *pdata = jbt->spi->dev.platform_data;
+ int ret = -EINVAL;
+
+ dev_dbg(&jbt->spi->dev, "entering (old_state=%s, new_state=%s)\n",
+@@ -375,49 +395,17 @@ static int jbt6k74_enter_power_mode(struct jbt_info *jbt,
+
+ mutex_lock(&jbt->lock);
+
+- if (jbt->suspended) {
+- switch (new_mode) {
+- case JBT_POWER_MODE_DEEP_STANDBY:
+- case JBT_POWER_MODE_SLEEP:
+- case JBT_POWER_MODE_NORMAL:
+- ret = 0;
+- jbt->suspend_mode = new_mode;
+- break;
+- default:
+- break;
+- }
+- } else if (new_mode == JBT_POWER_MODE_NORMAL &&
+- pdata->enable_pixel_clock) {
+- pdata->enable_pixel_clock(&jbt->spi->dev, 1);
+- }
+-
+ switch (jbt->power_mode) {
+- case JBT_POWER_MODE_DEEP_STANDBY:
++ case JBT_POWER_MODE_OFF:
+ switch (new_mode) {
+- case JBT_POWER_MODE_DEEP_STANDBY:
++ case JBT_POWER_MODE_OFF:
+ ret = 0;
+ break;
+- case JBT_POWER_MODE_SLEEP:
+- ret = jbt_standby_to_sleep(jbt);
+- break;
+ case JBT_POWER_MODE_NORMAL:
+- /* first transition into sleep */
+- ret = jbt_standby_to_sleep(jbt);
+- /* then transition into normal */
+- ret |= jbt_sleep_to_normal(jbt);
++ ret = jbt_off_to_normal(jbt);
+ break;
+- }
+- break;
+- case JBT_POWER_MODE_SLEEP:
+- switch (new_mode) {
+- case JBT_POWER_MODE_SLEEP:
+- ret = 0;
+- break;
+- case JBT_POWER_MODE_DEEP_STANDBY:
+- ret = jbt_sleep_to_standby(jbt);
+- break;
+- case JBT_POWER_MODE_NORMAL:
+- ret = jbt_sleep_to_normal(jbt);
++ case JBT_POWER_MODE_STANDBY:
++ ret = -EINVAL;
+ break;
+ }
+ break;
+@@ -426,25 +414,23 @@ static int jbt6k74_enter_power_mode(struct jbt_info *jbt,
+ case JBT_POWER_MODE_NORMAL:
+ ret = 0;
+ break;
+- case JBT_POWER_MODE_DEEP_STANDBY:
+- /* first transition into sleep */
+- ret = jbt_normal_to_sleep(jbt);
+- /* then transition into deep standby */
+- ret |= jbt_sleep_to_standby(jbt);
++ case JBT_POWER_MODE_OFF:
++ ret = jbt_normal_to_off(jbt);
+ break;
+- case JBT_POWER_MODE_SLEEP:
+- ret = jbt_normal_to_sleep(jbt);
++ case JBT_POWER_MODE_STANDBY:
++ ret = -EINVAL;
+ break;
+ }
++ break;
++ case JBT_POWER_MODE_STANDBY:
++ ret = -EINVAL;
++ break;
+ }
+
+ if (ret == 0) {
+ jbt->power_mode = new_mode;
+- if (new_mode != JBT_POWER_MODE_NORMAL &&
+- pdata->enable_pixel_clock)
+- pdata->enable_pixel_clock(&jbt->spi->dev, 0);
+ } else {
+- dev_err(&jbt->spi->dev, "Failed enter state '%s': %d\n",
++ dev_err(&jbt->spi->dev, "Failed to enter state '%s': %d\n",
+ jbt_power_mode_names[new_mode], ret);
+ }
+
+@@ -456,28 +442,46 @@ static int jbt6k74_enter_power_mode(struct jbt_info *jbt,
+ static int jbt6k74_set_resolution(struct jbt_info *jbt,
+ enum jbt_resolution new_resolution)
+ {
++ int old_resolution;
+ int ret = 0;
+- enum jbt_resolution old_resolution;
++
++ if ( !jbt ) return -1;
+
+ mutex_lock(&jbt->lock);
+
+- if (jbt->resolution == new_resolution)
+- goto out_unlock;
++ if ( jbt->resolution == new_resolution ) goto out_unlock;
++ if ( jbt->power_mode == JBT_POWER_MODE_OFF ) goto out_unlock;
+
+ old_resolution = jbt->resolution;
+ jbt->resolution = new_resolution;
+
+- if (jbt->power_mode == JBT_POWER_MODE_NORMAL) {
++ if ( jbt->power_mode == JBT_POWER_MODE_NORMAL ) {
++
++ ret = jbt_normal_to_standby(jbt);
++
++ mdelay(25);
+
+- /* first transition into sleep */
+- ret = jbt_normal_to_sleep(jbt);
+- ret |= jbt_sleep_to_normal(jbt);
++ if (jbt->resolution == JBT_RESOLUTION_VGA) {
++ /* Quad mode off */
++ ret |= jbt_reg_write(jbt, JBT_REG_QUAD_RATE, 0x00);
++ ret = jbt_reg_write(jbt, JBT_REG_DISPLAY_MODE, 0x80);
++ } else {
++ /* Quad mode on */
++ ret |= jbt_reg_write(jbt, JBT_REG_QUAD_RATE, 0x22);
++ ret = jbt_reg_write(jbt, JBT_REG_DISPLAY_MODE, 0x81);
++ }
++
++ mdelay(25);
++
++ ret |= jbt_standby_to_normal(jbt);
+
+ if (ret) {
+ jbt->resolution = old_resolution;
+- dev_err(&jbt->spi->dev, "Failed to set resolution '%s')\n",
++ dev_err(&jbt->spi->dev,
++ "Failed to set resolution '%s')\n",
+ jbt_resolution_names[new_resolution]);
+ }
++
+ }
+
+ out_unlock:
+@@ -589,7 +593,7 @@ static ssize_t reset_write(struct device *dev, struct device_attribute *attr,
+
+ mutex_unlock(&jbt->lock);
+
+- jbt->power_mode = JBT_POWER_MODE_DEEP_STANDBY;
++ jbt->power_mode = JBT_POWER_MODE_OFF;
+ jbt6k74_enter_power_mode(jbt, old_power_mode);
+
+ return count;
+@@ -616,27 +620,6 @@ static struct attribute_group jbt_attr_group = {
+ .attrs = jbt_sysfs_entries,
+ };
+
+-/* FIXME: This in an ugly hack to delay display blanking.
+- When the jbt is in sleep mode it displays an all white screen and thus one
+- will a see a short flash.
+- By delaying the blanking we will give the backlight a chance to turn off and
+- thus avoid getting the flash */
+-static void jbt_blank_worker(struct work_struct *work)
+-{
+- struct jbt_info *jbt = container_of(work, struct jbt_info,
+- blank_work.work);
+-
+- switch (jbt->blank_mode) {
+- case FB_BLANK_NORMAL:
+- jbt6k74_enter_power_mode(jbt, JBT_POWER_MODE_SLEEP);
+- break;
+- case FB_BLANK_POWERDOWN:
+- jbt6k74_enter_power_mode(jbt, JBT_POWER_MODE_DEEP_STANDBY);
+- break;
+- default:
+- break;
+- }
+-}
+
+ static int jbt6k74_set_mode(struct lcd_device *ld, struct fb_videomode *m)
+ {
+@@ -649,7 +632,7 @@ static int jbt6k74_set_mode(struct lcd_device *ld, struct fb_videomode *m)
+ ret = jbt6k74_set_resolution(jbt, JBT_RESOLUTION_VGA);
+ } else {
+ dev_err(&jbt->spi->dev, "Unknown resolution.\n");
+- jbt6k74_enter_power_mode(jbt, JBT_POWER_MODE_SLEEP);
++ jbt6k74_enter_power_mode(jbt, JBT_POWER_MODE_OFF);
+ }
+
+ return ret;
+@@ -671,11 +654,11 @@ static int jbt6k74_set_power(struct lcd_device *ld, int power)
+ break;
+ case FB_BLANK_NORMAL:
+ dev_dbg(&jbt->spi->dev, "blank\n");
+- ret = schedule_delayed_work(&jbt->blank_work, HZ);
++ ret = jbt6k74_enter_power_mode(jbt, JBT_POWER_MODE_OFF);
+ break;
+ case FB_BLANK_POWERDOWN:
+ dev_dbg(&jbt->spi->dev, "powerdown\n");
+- ret = schedule_delayed_work(&jbt->blank_work, HZ);
++ ret = jbt6k74_enter_power_mode(jbt, JBT_POWER_MODE_OFF);
+ break;
+ default:
+ break;
+@@ -691,10 +674,10 @@ static int jbt6k74_get_power(struct lcd_device *ld)
+ switch (jbt->power_mode) {
+ case JBT_POWER_MODE_NORMAL:
+ return FB_BLANK_UNBLANK;
+- case JBT_POWER_MODE_SLEEP:
++ case JBT_POWER_MODE_OFF:
+ return FB_BLANK_NORMAL;
+ default:
+- return JBT_POWER_MODE_DEEP_STANDBY;
++ return JBT_POWER_MODE_OFF;
+ }
+ }
+
+@@ -728,6 +711,8 @@ static int __devinit jbt_probe(struct spi_device *spi)
+ if (!jbt)
+ return -ENOMEM;
+
++ jbt_global = jbt;
++
+ jbt->spi = spi;
+
+ jbt->lcd_dev = lcd_device_register("jbt6k74-lcd", &spi->dev, jbt,
+@@ -738,11 +723,9 @@ static int __devinit jbt_probe(struct spi_device *spi)
+ goto err_free_drvdata;
+ }
+
+- INIT_DELAYED_WORK(&jbt->blank_work, jbt_blank_worker);
+-
+ jbt->resolution = JBT_RESOLUTION_VGA;
+- jbt->power_mode = JBT_POWER_MODE_DEEP_STANDBY;
+ jbt->next_sleep = jiffies + msecs_to_jiffies(120);
++ jbt->power_mode = JBT_POWER_MODE_OFF;
+ mutex_init(&jbt->lock);
+
+ dev_set_drvdata(&spi->dev, jbt);
+@@ -831,6 +814,24 @@ static int __devexit jbt_remove(struct spi_device *spi)
+ return 0;
+ }
+
++/* Begin horrible layering violations in the interest of making stuff work */
++
++int jbt6k74_finish_resolutionchange(enum jbt_resolution new_resolution)
++{
++ if ( !jbt_global ) return 0;
++ return jbt6k74_set_resolution(jbt_global, new_resolution);
++}
++EXPORT_SYMBOL_GPL(jbt6k74_finish_resolutionchange);
++
++void jbt6k74_setpower(enum jbt_power_mode new_power)
++{
++ if ( !jbt_global ) return;
++ jbt6k74_enter_power_mode(jbt_global, new_power);
++}
++EXPORT_SYMBOL_GPL(jbt6k74_setpower);
++
++/* End horrible layering violations */
++
+ #ifdef CONFIG_PM
+ static int jbt_suspend(struct spi_device *spi, pm_message_t state)
+ {
+@@ -838,8 +839,7 @@ static int jbt_suspend(struct spi_device *spi, pm_message_t state)
+
+ jbt->suspend_mode = jbt->power_mode;
+
+- jbt6k74_enter_power_mode(jbt, JBT_POWER_MODE_DEEP_STANDBY);
+- jbt->suspended = 1;
++ jbt6k74_enter_power_mode(jbt, JBT_POWER_MODE_OFF);
+
+ dev_info(&spi->dev, "suspended\n");
+
+diff --git a/include/linux/jbt6k74.h b/include/linux/jbt6k74.h
+index 75488c4..2010bdc 100644
+--- a/include/linux/jbt6k74.h
++++ b/include/linux/jbt6k74.h
+@@ -3,6 +3,22 @@
+
+ #include <linux/spi/spi.h>
+
++enum jbt_resolution {
++ JBT_RESOLUTION_VGA,
++ JBT_RESOLUTION_QVGA,
++};
++
++enum jbt_power_mode {
++ JBT_POWER_MODE_OFF,
++ JBT_POWER_MODE_STANDBY,
++ JBT_POWER_MODE_NORMAL,
++};
++
++extern void jbt6k74_setpower(enum jbt_power_mode new_power);
++extern int jbt6k74_prepare_resolutionchange(enum jbt_resolution new_resolution);
++extern int jbt6k74_finish_resolutionchange(enum jbt_resolution new_resolution);
++
++
+ /*
+ * struct jbt6k74_platform_data - Platform data for jbt6k74 driver
+ * @probe_completed: Callback to be called when the driver has been
+@@ -13,7 +29,6 @@
+ */
+ struct jbt6k74_platform_data {
+ void (*probe_completed)(struct device *dev);
+- void (*enable_pixel_clock)(struct device *dev, int enable);
+
+ int gpio_reset;
+ };
+--
+1.7.1
+