From 08c73c0533ec33dba5676d1124634dd1654aef8b Mon Sep 17 00:00:00 2001 From: Nelson Castillo Date: Sun, 19 Apr 2009 14:41:33 -0500 Subject: Revert "Revert "Fixed the LCM driver state transition delay and pixel clock issue"" This reverts commit aa2dbc74bed8cf60e591c654ba1882011b9a8ece. Reverting the revert. Sorry for the noise. Check: http://lists.openmoko.org/pipermail/openmoko-kernel/2009-April/010023.html --- drivers/mfd/glamo/glamo-fb.c | 127 +++++++++++++++++++++---------------- drivers/video/display/jbt6k74.c | 136 ++++++++++++++++++++++------------------ 2 files changed, 149 insertions(+), 114 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/glamo/glamo-fb.c b/drivers/mfd/glamo/glamo-fb.c index 4eb81a508e5..5491dadbf8a 100644 --- a/drivers/mfd/glamo/glamo-fb.c +++ b/drivers/mfd/glamo/glamo-fb.c @@ -37,9 +37,9 @@ #include #include #include +#include +#include -#include -#include #include #ifdef CONFIG_PM @@ -76,6 +76,7 @@ struct glamofb_handle { u_int32_t pseudo_pal[16]; spinlock_t lock_cmd; int angle; /* Current rotation angle */ + int blank_mode; }; /* 'sibling' spi device for lcm init */ @@ -89,7 +90,7 @@ static int reg_read(struct glamofb_handle *glamo, { int i = 0; - for (i = 0; i != 2; i ++) + for (i = 0; i != 2; i++) nop(); return readw(glamo->base + reg); @@ -100,7 +101,7 @@ static void reg_write(struct glamofb_handle *glamo, { int i = 0; - for (i = 0; i != 2; i ++) + for (i = 0; i != 2; i++) nop(); writew(val, glamo->base + reg); @@ -141,7 +142,8 @@ static int glamofb_run_script(struct glamofb_handle *glamo, int i; if (glamo->mach_info->glamo->suspending) { - dev_err(&glamo->mach_info->glamo->pdev->dev, "IGNORING glamofb_run_script while " + dev_err(&glamo->mach_info->glamo->pdev->dev, + "IGNORING glamofb_run_script while " "suspended\n"); return -EBUSY; } @@ -166,7 +168,8 @@ static int glamofb_check_var(struct fb_var_screeninfo *var, struct glamofb_handle *glamo = info->par; if (glamo->mach_info->glamo->suspending) { - dev_err(&glamo->mach_info->glamo->pdev->dev, "IGNORING glamofb_check_var while " + dev_err(&glamo->mach_info->glamo->pdev->dev, + "IGNORING glamofb_check_var while " "suspended\n"); return -EBUSY; } @@ -263,32 +266,33 @@ static void __rotate_lcd(struct glamofb_handle *glamo, __u32 rotation) int glamo_rot; if (glamo->mach_info->glamo->suspending) { - dev_err(&glamo->mach_info->glamo->pdev->dev, "IGNORING rotate_lcd while " + dev_err(&glamo->mach_info->glamo->pdev->dev, + "IGNORING rotate_lcd while " "suspended\n"); return; } switch (rotation) { - case FB_ROTATE_UR: - glamo_rot = GLAMO_LCD_ROT_MODE_0; - glamo->angle = 0; - break; - case FB_ROTATE_CW: - glamo_rot = GLAMO_LCD_ROT_MODE_90; - glamo->angle = 90; - break; - case FB_ROTATE_UD: - glamo_rot = GLAMO_LCD_ROT_MODE_180; - glamo->angle = 180; - break; - case FB_ROTATE_CCW: - glamo_rot = GLAMO_LCD_ROT_MODE_270; - glamo->angle = 270; - break; - default: - glamo->angle = 0; - glamo_rot = GLAMO_LCD_ROT_MODE_0; - break; + case FB_ROTATE_UR: + glamo_rot = GLAMO_LCD_ROT_MODE_0; + glamo->angle = 0; + break; + case FB_ROTATE_CW: + glamo_rot = GLAMO_LCD_ROT_MODE_90; + glamo->angle = 90; + break; + case FB_ROTATE_UD: + glamo_rot = GLAMO_LCD_ROT_MODE_180; + glamo->angle = 180; + break; + case FB_ROTATE_CCW: + glamo_rot = GLAMO_LCD_ROT_MODE_270; + glamo->angle = 270; + break; + default: + glamo->angle = 0; + glamo_rot = GLAMO_LCD_ROT_MODE_0; + break; } reg_set_bit_mask(glamo, @@ -298,7 +302,7 @@ static void __rotate_lcd(struct glamofb_handle *glamo, __u32 rotation) reg_set_bit_mask(glamo, GLAMO_REG_LCD_MODE1, GLAMO_LCD_MODE1_ROTATE_EN, - (glamo_rot != GLAMO_LCD_ROT_MODE_0)? + (glamo_rot != GLAMO_LCD_ROT_MODE_0) ? GLAMO_LCD_MODE1_ROTATE_EN : 0); } @@ -313,7 +317,8 @@ static void glamofb_update_lcd_controller(struct glamofb_handle *glamo, return; if (glamo->mach_info->glamo->suspending) { - dev_err(&glamo->mach_info->glamo->pdev->dev, "IGNORING glamofb_update_lcd_controller while " + dev_err(&glamo->mach_info->glamo->pdev->dev, + "IGNORING glamofb_update_lcd_controller while " "suspended\n"); return; } @@ -331,10 +336,10 @@ static void glamofb_update_lcd_controller(struct glamofb_handle *glamo, var->pixclock); if (glamo->angle == 90 || glamo->angle == 270) { - /* + /* * But if we are going back to portrait mode from here, - * we get inverted values from Xglamo - */ + * we get inverted values from Xglamo + */ if (!(var->rotate == FB_ROTATE_UR || var->rotate == FB_ROTATE_UD)) { width = var->yres; @@ -354,7 +359,8 @@ static void glamofb_update_lcd_controller(struct glamofb_handle *glamo, /* We don't need to set xres and yres in this particular case * because Xglamo does it for us */ if (!(glamo->angle == 90 || glamo->angle == 270)) { - var->xres = width;var->yres = height; + var->xres = width; + var->yres = height; } var->xres_virtual = width; @@ -427,7 +433,8 @@ out_unlock: spin_unlock_irqrestore(&glamo->lock_cmd, flags); } -static int glamofb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +static int glamofb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) { struct glamofb_handle *glamo = info->par; u_int16_t page = var->yoffset / glamo->mach_info->yres.defval; @@ -442,7 +449,8 @@ static int glamofb_set_par(struct fb_info *info) struct fb_var_screeninfo *var = &info->var; if (glamo->mach_info->glamo->suspending) { - dev_err(&glamo->mach_info->glamo->pdev->dev, "IGNORING glamofb_set_par while " + dev_err(&glamo->mach_info->glamo->pdev->dev, + "IGNORING glamofb_set_par while " "suspended\n"); return -EBUSY; } @@ -488,17 +496,29 @@ static int glamofb_blank(int blank_mode, struct fb_info *info) * we should already switch off pixel clock here */ break; case FB_BLANK_POWERDOWN: + /* Simulating FB_BLANK_NORMAL allow turning off backlight */ + if (gfb->blank_mode != FB_BLANK_NORMAL) + notify_blank(info, FB_BLANK_NORMAL); + + /* LCM need notification before pixel clock is stopped */ + notify_blank(info, blank_mode); + /* disable the pixel clock */ glamo_engine_clkreg_set(gcore, GLAMO_ENGINE_LCD, GLAMO_CLOCK_LCD_EN_DCLK, 0); + gfb->blank_mode = blank_mode; break; case FB_BLANK_UNBLANK: case FB_BLANK_NORMAL: - /* enable the pixel clock */ - glamo_engine_clkreg_set(gcore, GLAMO_ENGINE_LCD, + /* enable the pixel clock if off */ + if (gfb->blank_mode == FB_BLANK_POWERDOWN) + glamo_engine_clkreg_set(gcore, + GLAMO_ENGINE_LCD, GLAMO_CLOCK_LCD_EN_DCLK, GLAMO_CLOCK_LCD_EN_DCLK); + notify_blank(info, blank_mode); + gfb->blank_mode = blank_mode; break; } @@ -524,7 +544,8 @@ static int glamofb_setcolreg(unsigned regno, unsigned int val; if (glamo->mach_info->glamo->suspending) { - dev_err(&glamo->mach_info->glamo->pdev->dev, "IGNORING glamofb_set_par while " + dev_err(&glamo->mach_info->glamo->pdev->dev, + "IGNORING glamofb_set_par while " "suspended\n"); return -EBUSY; } @@ -692,7 +713,8 @@ int glamofb_cmd_mode(struct glamofb_handle *gfb, int on) int timeout = 2000000; if (gfb->mach_info->glamo->suspending) { - dev_err(&gfb->mach_info->glamo->pdev->dev, "IGNORING glamofb_cmd_mode while " + dev_err(&gfb->mach_info->glamo->pdev->dev, + "IGNORING glamofb_cmd_mode while " "suspended\n"); return -EBUSY; } @@ -700,7 +722,7 @@ int glamofb_cmd_mode(struct glamofb_handle *gfb, int on) dev_dbg(gfb->dev, "glamofb_cmd_mode(gfb=%p, on=%d)\n", gfb, on); if (on) { dev_dbg(gfb->dev, "%s: waiting for cmdq empty: ", - __FUNCTION__); + __func__); while ((!glamofb_cmdq_empty(gfb)) && (timeout--)) /* yield() */; if (timeout < 0) { @@ -755,12 +777,13 @@ int glamofb_cmd_write(struct glamofb_handle *gfb, u_int16_t val) int timeout = 200000; if (gfb->mach_info->glamo->suspending) { - dev_err(&gfb->mach_info->glamo->pdev->dev, "IGNORING glamofb_cmd_write while " + dev_err(&gfb->mach_info->glamo->pdev->dev, + "IGNORING glamofb_cmd_write while " "suspended\n"); return -EBUSY; } - dev_dbg(gfb->dev, "%s: waiting for cmdq empty\n", __FUNCTION__); + dev_dbg(gfb->dev, "%s: waiting for cmdq empty\n", __func__); while ((!glamofb_cmdq_empty(gfb)) && (timeout--)) yield(); if (timeout < 0) { @@ -822,6 +845,7 @@ static int __init glamofb_probe(struct platform_device *pdev) glamofb->dev = &pdev->dev; glamofb->angle = 0; + glamofb->blank_mode = FB_BLANK_POWERDOWN; strcpy(fbinfo->fix.id, "SMedia Glamo"); @@ -976,38 +1000,35 @@ static int glamofb_suspend(struct platform_device *pdev, pm_message_t state) struct glamofb_handle *gfb = platform_get_drvdata(pdev); /* we need to stop anything touching our framebuffer */ -// fb_blank(gfb->fb, FB_BLANK_NORMAL); fb_set_suspend(gfb->fb, 1); /* seriously -- nobody is allowed to touch glamo memory when we * are suspended or we lock on nWAIT */ -// iounmap(gfb->fb->screen_base); + /* iounmap(gfb->fb->screen_base); */ return 0; } static int glamofb_resume(struct platform_device *pdev) { - struct glamofb_handle *glamofb = platform_get_drvdata(pdev); + struct glamofb_handle *gfb = platform_get_drvdata(pdev); struct glamofb_platform_data *mach_info = pdev->dev.platform_data; /* OK let's allow framebuffer ops again */ -// gfb->fb->screen_base = ioremap(gfb->fb_res->start, -// RESSIZE(gfb->fb_res)); + /* gfb->fb->screen_base = ioremap(gfb->fb_res->start, + RESSIZE(gfb->fb_res)); */ glamo_engine_enable(mach_info->glamo, GLAMO_ENGINE_LCD); glamo_engine_reset(mach_info->glamo, GLAMO_ENGINE_LCD); printk(KERN_ERR"spin_lock_init\n"); - spin_lock_init(&glamofb->lock_cmd); - glamofb_init_regs(glamofb); + spin_lock_init(&gfb->lock_cmd); + glamofb_init_regs(gfb); #ifdef CONFIG_MFD_GLAMO_HWACCEL - glamofb_cursor_onoff(glamofb, 1); + glamofb_cursor_onoff(gfb, 1); #endif - - fb_set_suspend(glamofb->fb, 0); -// fb_blank(gfb->fb, FB_BLANK_UNBLANK); + fb_set_suspend(gfb->fb, 0); return 0; } diff --git a/drivers/video/display/jbt6k74.c b/drivers/video/display/jbt6k74.c index 0307ed5318f..5d7a6519de9 100644 --- a/drivers/video/display/jbt6k74.c +++ b/drivers/video/display/jbt6k74.c @@ -31,6 +31,7 @@ #include #include #include +#include enum jbt_register { JBT_REG_SLEEP_IN = 0x10, @@ -117,12 +118,18 @@ struct jbt_info { struct notifier_block fb_notif; u16 tx_buf[8]; u16 reg_cache[0xEE]; - int have_resumed; + struct timespec last_sleep; }; #define JBT_COMMAND 0x000 #define JBT_DATA 0x100 +static inline unsigned int timespec_sub_ms(struct timespec lhs, + struct timespec rhs) +{ + struct timespec ts = timespec_sub(lhs, rhs); + return (ts.tv_sec * MSEC_PER_SEC) + (ts.tv_nsec / NSEC_PER_MSEC); +} static int jbt_reg_write_nodata(struct jbt_info *jbt, u8 reg) { @@ -179,7 +186,7 @@ static int jbt_init_regs(struct jbt_info *jbt) { int rc; - dev_dbg(&jbt->spi_dev->dev, "entering %cVGA mode\n", + dev_dbg(&jbt->spi_dev->dev, "entering %cVGA mode\n", jbt->normal_state == JBT_STATE_QVGA_NORMAL ? 'Q' : ' '); rc = jbt_reg_write(jbt, JBT_REG_DISPLAY_MODE1, 0x01); @@ -268,36 +275,25 @@ static int sleep_to_normal(struct jbt_info *jbt) { int rc; - /* RGB I/F on, RAM wirte off, QVGA through, SIGCON enable */ - rc = jbt_reg_write(jbt, JBT_REG_DISPLAY_MODE, 0x80); - - /* Quad mode off */ - rc |= jbt_reg_write(jbt, JBT_REG_QUAD_RATE, 0x00); - - /* AVDD on, XVDD on */ - rc |= jbt_reg_write(jbt, JBT_REG_POWER_ON_OFF, 0x16); + /* Make sure we are 120 ms after SLEEP_OUT */ + unsigned int sleep_time = timespec_sub_ms(current_kernel_time(), + jbt->last_sleep); + if (sleep_time < 120) + mdelay(120 - sleep_time); - /* Output control */ - rc |= jbt_reg_write16(jbt, JBT_REG_OUTPUT_CONTROL, 0xfff9); - - /* Turn on display */ - rc |= jbt_reg_write_nodata(jbt, JBT_REG_DISPLAY_ON); + if (jbt->normal_state == JBT_STATE_NORMAL) { + /* RGB I/F on, RAM wirte off, QVGA through, SIGCON enable */ + rc = jbt_reg_write(jbt, JBT_REG_DISPLAY_MODE, 0x80); - /* Sleep mode off */ - rc |= jbt_reg_write_nodata(jbt, JBT_REG_SLEEP_OUT); - - return rc ? -EIO : 0; -} - -static int sleep_to_qvga_normal(struct jbt_info *jbt) -{ - int rc; - - /* RGB I/F on, RAM wirte off, QVGA through, SIGCON enable */ - rc = jbt_reg_write(jbt, JBT_REG_DISPLAY_MODE, 0x81); + /* Quad mode off */ + rc |= jbt_reg_write(jbt, JBT_REG_QUAD_RATE, 0x00); + } else { + /* RGB I/F on, RAM wirte off, QVGA through, SIGCON enable */ + rc = jbt_reg_write(jbt, JBT_REG_DISPLAY_MODE, 0x81); - /* Quad mode on */ - rc |= jbt_reg_write(jbt, JBT_REG_QUAD_RATE, 0x22); + /* Quad mode on */ + rc |= jbt_reg_write(jbt, JBT_REG_QUAD_RATE, 0x22); + } /* AVDD on, XVDD on */ rc |= jbt_reg_write(jbt, JBT_REG_POWER_ON_OFF, 0x16); @@ -310,6 +306,10 @@ static int sleep_to_qvga_normal(struct jbt_info *jbt) /* Sleep mode off */ rc |= jbt_reg_write_nodata(jbt, JBT_REG_SLEEP_OUT); + jbt->last_sleep = current_kernel_time(); + + /* Allow the booster and display controller to restart stably */ + mdelay(5); return rc ? -EIO : 0; } @@ -318,9 +318,19 @@ static int normal_to_sleep(struct jbt_info *jbt) { int rc; + /* Make sure we are 120 ms after SLEEP_OUT */ + unsigned int sleep_time = timespec_sub_ms(current_kernel_time(), + jbt->last_sleep); + if (sleep_time < 120) + mdelay(120 - sleep_time); + rc = jbt_reg_write_nodata(jbt, JBT_REG_DISPLAY_OFF); rc |= jbt_reg_write16(jbt, JBT_REG_OUTPUT_CONTROL, 0x8002); rc |= jbt_reg_write_nodata(jbt, JBT_REG_SLEEP_IN); + jbt->last_sleep = current_kernel_time(); + + /* Allow the internal circuits to stop automatically */ + mdelay(5); return rc ? -EIO : 0; } @@ -335,8 +345,9 @@ int jbt6k74_enter_state(struct jbt_info *jbt, enum jbt_state new_state) { int rc = -EINVAL; - dev_dbg(&jbt->spi_dev->dev, "entering (old_state=%s, " - "new_state=%s)\n", jbt_state_names[jbt->state], jbt_state_names[new_state]); + dev_dbg(&jbt->spi_dev->dev, "entering (old_state=%s, new_state=%s)\n", + jbt_state_names[jbt->state], + jbt_state_names[new_state]); mutex_lock(&jbt->lock); @@ -363,7 +374,7 @@ int jbt6k74_enter_state(struct jbt_info *jbt, enum jbt_state new_state) /* first transition into sleep */ rc = standby_to_sleep(jbt); /* then transition into normal */ - rc |= sleep_to_qvga_normal(jbt); + rc |= sleep_to_normal(jbt); break; } break; @@ -376,10 +387,8 @@ int jbt6k74_enter_state(struct jbt_info *jbt, enum jbt_state new_state) rc = sleep_to_standby(jbt); break; case JBT_STATE_NORMAL: - rc = sleep_to_normal(jbt); - break; case JBT_STATE_QVGA_NORMAL: - rc = sleep_to_qvga_normal(jbt); + rc = sleep_to_normal(jbt); break; } break; @@ -405,7 +414,7 @@ int jbt6k74_enter_state(struct jbt_info *jbt, enum jbt_state new_state) /* third transition into sleep */ rc |= standby_to_sleep(jbt); /* fourth transition into normal */ - rc |= sleep_to_qvga_normal(jbt); + rc |= sleep_to_normal(jbt); break; } break; @@ -436,12 +445,13 @@ int jbt6k74_enter_state(struct jbt_info *jbt, enum jbt_state new_state) } break; } - + if (rc == 0) jbt->state = new_state; else - dev_err(&jbt->spi_dev->dev, "Failed enter state '%s')\n", jbt_state_names[new_state]); - + dev_err(&jbt->spi_dev->dev, "Failed enter state '%s')\n", + jbt_state_names[new_state]); + mutex_unlock(&jbt->lock); return rc; @@ -525,18 +535,27 @@ static ssize_t gamma_write(struct device *dev, struct device_attribute *attr, static ssize_t reset_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + int rc; struct jbt_info *jbt = dev_get_drvdata(dev); - struct jbt6k74_platform_data *jbt6k74_pdata = jbt->spi_dev->dev.platform_data; + struct jbt6k74_platform_data *pdata = jbt->spi_dev->dev.platform_data; dev_info(dev, "reset\n"); - jbt6k74_enter_state(jbt, JBT_STATE_DEEP_STANDBY); + mutex_lock(&jbt->lock); + + jbt->state = JBT_STATE_DEEP_STANDBY; /* hard reset the jbt6k74 */ - mutex_lock(&jbt->lock); - (jbt6k74_pdata->reset)(0, 0); + (pdata->reset)(0, 0); mdelay(1); - (jbt6k74_pdata->reset)(0, 1); + (pdata->reset)(0, 1); + mdelay(120); + + rc = jbt_reg_write_nodata(jbt, 0x01); + if (rc < 0) + dev_err(&jbt->spi_dev->dev, "cannot soft reset\n"); + mdelay(120); + mutex_unlock(&jbt->lock); jbt6k74_enter_state(jbt, jbt->normal_state); @@ -580,26 +599,22 @@ static int fb_notifier_callback(struct notifier_block *self, return 0; fb_blank = *(int *)evdata->data; - switch (fb_blank) { case FB_BLANK_UNBLANK: - dev_info(&jbt->spi_dev->dev, "**** jbt6k74 unblank\n"); + dev_dbg(&jbt->spi_dev->dev, "unblank\n"); jbt6k74_enter_state(jbt, jbt->normal_state); break; case FB_BLANK_NORMAL: - dev_info(&jbt->spi_dev->dev, "**** jbt6k74 normal\n"); + dev_dbg(&jbt->spi_dev->dev, "blank\n"); break; case FB_BLANK_VSYNC_SUSPEND: - dev_info(&jbt->spi_dev->dev, "**** jbt6k74 vsync suspend\n"); + dev_dbg(&jbt->spi_dev->dev, "vsync suspend\n"); break; case FB_BLANK_HSYNC_SUSPEND: - dev_info(&jbt->spi_dev->dev, "**** jbt6k74 hsync suspend\n"); + dev_dbg(&jbt->spi_dev->dev, "hsync suspend\n"); break; case FB_BLANK_POWERDOWN: - dev_info(&jbt->spi_dev->dev, "**** jbt6k74 powerdown\n"); - /* FIXME DEEP STANDBY wihtout suspend causes WSOD at cold - * temperature on certain devices. */ - /*jbt6k74_enter_state(jbt, JBT_STATE_DEEP_STANDBY);*/ + dev_dbg(&jbt->spi_dev->dev, "powerdown\n"); jbt6k74_enter_state(jbt, JBT_STATE_SLEEP); break; } @@ -613,7 +628,7 @@ static int __devinit jbt_probe(struct spi_device *spi) { int rc; struct jbt_info *jbt; - struct jbt6k74_platform_data *jbt6k74_pdata = spi->dev.platform_data; + struct jbt6k74_platform_data *pdata = spi->dev.platform_data; /* the controller doesn't have a MISO pin; we can't do detection */ @@ -634,6 +649,7 @@ static int __devinit jbt_probe(struct spi_device *spi) jbt->spi_dev = spi; jbt->normal_state = JBT_STATE_NORMAL; jbt->state = JBT_STATE_DEEP_STANDBY; + jbt->last_sleep = current_kernel_time(); mutex_init(&jbt->lock); dev_set_drvdata(&spi->dev, jbt); @@ -657,8 +673,8 @@ static int __devinit jbt_probe(struct spi_device *spi) goto err_sysfs; } - if (jbt6k74_pdata->probe_completed) - (jbt6k74_pdata->probe_completed)(&spi->dev); + if (pdata->probe_completed) + (pdata->probe_completed)(&spi->dev); return 0; @@ -696,8 +712,6 @@ static int jbt_suspend(struct spi_device *spi, pm_message_t state) jbt6k74_enter_state(jbt, JBT_STATE_DEEP_STANDBY); - jbt->have_resumed = 0; - dev_info(&spi->dev, "suspended\n"); return 0; @@ -706,12 +720,12 @@ static int jbt_suspend(struct spi_device *spi, pm_message_t state) int jbt6k74_resume(struct spi_device *spi) { struct jbt_info *jbt = dev_get_drvdata(&spi->dev); - struct jbt6k74_platform_data *jbt6k74_pdata = spi->dev.platform_data; + struct jbt6k74_platform_data *pdata = spi->dev.platform_data; jbt6k74_enter_state(jbt, jbt->normal_state); - if (jbt6k74_pdata->resuming) - (jbt6k74_pdata->resuming)(0); + if (pdata->resuming) + (pdata->resuming)(0); dev_info(&spi->dev, "resumed\n"); -- cgit v1.2.3