X-Git-Url: http://git.rohieb.name/openwrt.git/blobdiff_plain/fb189822fcab111e55d1c7e83c482dc2c144500a..HEAD:/target/linux/s3c24xx/files-2.6.30/drivers/video/display/jbt6k74.c diff --git a/target/linux/s3c24xx/files-2.6.30/drivers/video/display/jbt6k74.c b/target/linux/s3c24xx/files-2.6.30/drivers/video/display/jbt6k74.c index eb4e46d13..87f0d6731 100644 --- a/target/linux/s3c24xx/files-2.6.30/drivers/video/display/jbt6k74.c +++ b/target/linux/s3c24xx/files-2.6.30/drivers/video/display/jbt6k74.c @@ -4,6 +4,7 @@ * Author: Harald Welte , * Stefan Schmidt * Copyright (C) 2008 by Harald Welte + * Copyright (C) 2009 by Lars-Peter Clausen * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -29,8 +30,10 @@ #include #include #include +#include #include #include +#include #include enum jbt_register { @@ -97,51 +100,57 @@ enum jbt_register { }; -enum jbt_state { - JBT_STATE_DEEP_STANDBY, - JBT_STATE_SLEEP, - JBT_STATE_NORMAL, - JBT_STATE_QVGA_NORMAL, +enum jbt_resolution { + JBT_RESOLUTION_VGA, + JBT_RESOLUTION_QVGA, }; -static const char *jbt_state_names[] = { - [JBT_STATE_DEEP_STANDBY] = "deep-standby", - [JBT_STATE_SLEEP] = "sleep", - [JBT_STATE_NORMAL] = "normal", - [JBT_STATE_QVGA_NORMAL] = "qvga-normal", +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_NORMAL] = "normal", +}; + +static const char *jbt_resolution_names[] = { + [JBT_RESOLUTION_VGA] = "vga", + [JBT_RESOLUTION_QVGA] = "qvga", }; struct jbt_info { - enum jbt_state state, normal_state; + struct mutex lock; /* protects this structure */ + enum jbt_resolution resolution; + enum jbt_power_mode power_mode; + enum jbt_power_mode suspend_mode; + int suspended; struct spi_device *spi_dev; - struct mutex lock; /* protects tx_buf and reg_cache */ - struct notifier_block fb_notif; - u16 tx_buf[8]; + struct lcd_device *lcd_dev; + unsigned long last_sleep; + struct delayed_work blank_work; + int blank_mode; + u16 tx_buf[4]; u16 reg_cache[0xEE]; - 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) { int rc; jbt->tx_buf[0] = JBT_COMMAND | reg; rc = spi_write(jbt->spi_dev, (u8 *)jbt->tx_buf, - 1*sizeof(u16)); + 1*sizeof(u16)); if (rc == 0) jbt->reg_cache[reg] = 0; else - printk(KERN_ERR"jbt_reg_write_nodata spi_write ret %d\n", + dev_err(&jbt->spi_dev->dev, "jbt_reg_write_nodata spi_write ret %d\n", rc); return rc; @@ -155,11 +164,11 @@ static int jbt_reg_write(struct jbt_info *jbt, u8 reg, u8 data) jbt->tx_buf[0] = JBT_COMMAND | reg; jbt->tx_buf[1] = JBT_DATA | data; rc = spi_write(jbt->spi_dev, (u8 *)jbt->tx_buf, - 2*sizeof(u16)); + 2*sizeof(u16)); if (rc == 0) jbt->reg_cache[reg] = data; else - printk(KERN_ERR"jbt_reg_write spi_write ret %d\n", rc); + dev_err(&jbt->spi_dev->dev, "jbt_reg_write spi_write ret %d\n", rc); return rc; } @@ -173,11 +182,11 @@ static int jbt_reg_write16(struct jbt_info *jbt, u8 reg, u16 data) jbt->tx_buf[2] = JBT_DATA | (data & 0xff); rc = spi_write(jbt->spi_dev, (u8 *)jbt->tx_buf, - 3*sizeof(u16)); + 3*sizeof(u16)); if (rc == 0) jbt->reg_cache[reg] = data; else - printk(KERN_ERR"jbt_reg_write16 spi_write ret %d\n", rc); + dev_err(&jbt->spi_dev->dev, "jbt_reg_write16 spi_write ret %d\n", rc); return rc; } @@ -187,7 +196,7 @@ static int jbt_init_regs(struct jbt_info *jbt) int rc; dev_dbg(&jbt->spi_dev->dev, "entering %cVGA mode\n", - jbt->normal_state == JBT_STATE_QVGA_NORMAL ? 'Q' : ' '); + jbt->resolution == JBT_RESOLUTION_QVGA ? 'Q' : ' '); rc = jbt_reg_write(jbt, JBT_REG_DISPLAY_MODE1, 0x01); rc |= jbt_reg_write(jbt, JBT_REG_DISPLAY_MODE2, 0x00); @@ -205,7 +214,7 @@ static int jbt_init_regs(struct jbt_info *jbt) * default of 0x02 in JBT_REG_ASW_SLEW responsible for 72Hz requirement * to avoid red / blue flicker */ - rc |= jbt_reg_write(jbt, JBT_REG_ASW_SLEW, 0x04); + rc |= jbt_reg_write(jbt, JBT_REG_ASW_SLEW, 0x04 | (1 << 5)); rc |= jbt_reg_write(jbt, JBT_REG_DUMMY_DISPLAY, 0x00); rc |= jbt_reg_write(jbt, JBT_REG_SLEEP_OUT_FR_A, 0x11); @@ -221,7 +230,7 @@ static int jbt_init_regs(struct jbt_info *jbt) rc |= jbt_reg_write(jbt, JBT_REG_GAMMA1_INCLINATION, 0x00); rc |= jbt_reg_write(jbt, JBT_REG_GAMMA1_BLUE_OFFSET, 0x00); - if (jbt->normal_state != JBT_STATE_QVGA_NORMAL) { + if (jbt->resolution != JBT_RESOLUTION_QVGA) { rc |= jbt_reg_write16(jbt, JBT_REG_HCLOCK_VGA, 0x1f0); rc |= jbt_reg_write(jbt, JBT_REG_BLANK_CONTROL, 0x02); rc |= jbt_reg_write16(jbt, JBT_REG_BLANK_TH_TV, 0x0804); @@ -276,12 +285,10 @@ static int sleep_to_normal(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); + if (time_before(jiffies, jbt->last_sleep)) + mdelay(jiffies_to_msecs(jbt->last_sleep - jiffies)); - if (jbt->normal_state == JBT_STATE_NORMAL) { + if (jbt->resolution == JBT_RESOLUTION_VGA) { /* RGB I/F on, RAM wirte off, QVGA through, SIGCON enable */ rc = jbt_reg_write(jbt, JBT_REG_DISPLAY_MODE, 0x80); @@ -306,7 +313,7 @@ static int sleep_to_normal(struct jbt_info *jbt) /* Sleep mode off */ rc |= jbt_reg_write_nodata(jbt, JBT_REG_SLEEP_OUT); - jbt->last_sleep = current_kernel_time(); + jbt->last_sleep = jiffies + msecs_to_jiffies(120); /* Allow the booster and display controller to restart stably */ mdelay(5); @@ -319,15 +326,13 @@ 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); + while (time_before(jiffies, jbt->last_sleep)) + cpu_relax(); rc = jbt_reg_write_nodata(jbt, JBT_REG_DISPLAY_OFF); - rc |= jbt_reg_write16(jbt, JBT_REG_OUTPUT_CONTROL, 0x8002); + rc |= jbt_reg_write16(jbt, JBT_REG_OUTPUT_CONTROL, 0x8000 | 1 << 3); rc |= jbt_reg_write_nodata(jbt, JBT_REG_SLEEP_IN); - jbt->last_sleep = current_kernel_time(); + jbt->last_sleep = jiffies + msecs_to_jiffies(120); /* Allow the internal circuits to stop automatically */ mdelay(5); @@ -340,41 +345,43 @@ static int sleep_to_standby(struct jbt_info *jbt) return jbt_reg_write(jbt, JBT_REG_POWER_ON_OFF, 0x00); } -/* frontend function */ -int jbt6k74_enter_state(struct jbt_info *jbt, enum jbt_state new_state) +int jbt6k74_enter_power_mode(struct jbt_info *jbt, enum jbt_power_mode new_mode) { + struct jbt6k74_platform_data *pdata = jbt->spi_dev->dev.platform_data; 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]);*/ - -/* printk("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_power_mode_names[jbt->power_mode], + jbt_power_mode_names[new_mode]); mutex_lock(&jbt->lock); - if (new_state == JBT_STATE_NORMAL || - new_state == JBT_STATE_QVGA_NORMAL) - jbt->normal_state = new_state; - - switch (jbt->state) { - case JBT_STATE_DEEP_STANDBY: - switch (new_state) { - case JBT_STATE_DEEP_STANDBY: + if (jbt->suspended) { + switch (new_mode) { + case JBT_POWER_MODE_DEEP_STANDBY: + case JBT_POWER_MODE_SLEEP: + case JBT_POWER_MODE_NORMAL: rc = 0; + jbt->suspend_mode = new_mode; break; - case JBT_STATE_SLEEP: - rc = standby_to_sleep(jbt); + default: break; - case JBT_STATE_NORMAL: - /* first transition into sleep */ + } + } else if (new_mode == JBT_POWER_MODE_NORMAL && + pdata->enable_pixel_clock) { + pdata->enable_pixel_clock(&jbt->spi_dev->dev, 1); + } + + switch (jbt->power_mode) { + case JBT_POWER_MODE_DEEP_STANDBY: + switch (new_mode) { + case JBT_POWER_MODE_DEEP_STANDBY: + rc = 0; + break; + case JBT_POWER_MODE_SLEEP: rc = standby_to_sleep(jbt); - /* then transition into normal */ - rc |= sleep_to_normal(jbt); break; - case JBT_STATE_QVGA_NORMAL: + case JBT_POWER_MODE_NORMAL: /* first transition into sleep */ rc = standby_to_sleep(jbt); /* then transition into normal */ @@ -382,107 +389,114 @@ int jbt6k74_enter_state(struct jbt_info *jbt, enum jbt_state new_state) break; } break; - case JBT_STATE_SLEEP: - switch (new_state) { - case JBT_STATE_SLEEP: + case JBT_POWER_MODE_SLEEP: + switch (new_mode) { + case JBT_POWER_MODE_SLEEP: rc = 0; break; - case JBT_STATE_DEEP_STANDBY: + case JBT_POWER_MODE_DEEP_STANDBY: rc = sleep_to_standby(jbt); break; - case JBT_STATE_NORMAL: - case JBT_STATE_QVGA_NORMAL: + case JBT_POWER_MODE_NORMAL: rc = sleep_to_normal(jbt); break; } break; - case JBT_STATE_NORMAL: - switch (new_state) { - case JBT_STATE_NORMAL: - rc = 0; - break; - case JBT_STATE_DEEP_STANDBY: - /* first transition into sleep */ - rc = normal_to_sleep(jbt); - /* then transition into deep standby */ - rc |= sleep_to_standby(jbt); - break; - case JBT_STATE_SLEEP: - rc = normal_to_sleep(jbt); - break; - case JBT_STATE_QVGA_NORMAL: - /* first transition into sleep */ - rc = normal_to_sleep(jbt); - /* second transition into deep standby */ - rc |= sleep_to_standby(jbt); - /* third transition into sleep */ - rc |= standby_to_sleep(jbt); - /* fourth transition into normal */ - rc |= sleep_to_normal(jbt); - break; - } - break; - case JBT_STATE_QVGA_NORMAL: - switch (new_state) { - case JBT_STATE_QVGA_NORMAL: + case JBT_POWER_MODE_NORMAL: + switch (new_mode) { + case JBT_POWER_MODE_NORMAL: rc = 0; break; - case JBT_STATE_DEEP_STANDBY: + case JBT_POWER_MODE_DEEP_STANDBY: /* first transition into sleep */ rc = normal_to_sleep(jbt); /* then transition into deep standby */ rc |= sleep_to_standby(jbt); break; - case JBT_STATE_SLEEP: + case JBT_POWER_MODE_SLEEP: rc = normal_to_sleep(jbt); break; - case JBT_STATE_NORMAL: - /* first transition into sleep */ - rc = normal_to_sleep(jbt); - /* second transition into deep standby */ - rc |= sleep_to_standby(jbt); - /* third transition into sleep */ - rc |= standby_to_sleep(jbt); - /* fourth transition into normal */ - rc |= sleep_to_normal(jbt); - break; } - break; } - if (rc == 0) - jbt->state = new_state; - else + if (rc == 0) { + jbt->power_mode = new_mode; + if (new_mode != JBT_POWER_MODE_NORMAL && + pdata->enable_pixel_clock) + pdata->enable_pixel_clock(&jbt->spi_dev->dev, 0); + } else { dev_err(&jbt->spi_dev->dev, "Failed enter state '%s')\n", - jbt_state_names[new_state]); + jbt_power_mode_names[new_mode]); + } + + mutex_unlock(&jbt->lock); + + return rc; +} +EXPORT_SYMBOL_GPL(jbt6k74_enter_power_mode); + +int jbt6k74_set_resolution(struct jbt_info *jbt, enum jbt_resolution new_resolution) { + int rc = 0; + enum jbt_resolution old_resolution; + + if (new_resolution != JBT_RESOLUTION_VGA && + new_resolution != JBT_RESOLUTION_QVGA) + return -EINVAL; + + mutex_lock(&jbt->lock); + if (jbt->resolution == new_resolution) + goto out_unlock; + + old_resolution = jbt->resolution; + jbt->resolution = new_resolution; + + if (jbt->power_mode == JBT_POWER_MODE_NORMAL) { + + /* first transition into sleep */ + rc = normal_to_sleep(jbt); + /* second transition into deep standby */ +/* rc |= sleep_to_standby(jbt);*/ + /* third transition into sleep */ +/* rc |= standby_to_sleep(jbt);*/ + /* fourth transition into normal */ + rc |= sleep_to_normal(jbt); + + if (rc) { + jbt->resolution = old_resolution; + dev_err(&jbt->spi_dev->dev, "Failed to set resolution '%s')\n", + jbt_resolution_names[new_resolution]); + } + } + +out_unlock: mutex_unlock(&jbt->lock); return rc; } -EXPORT_SYMBOL_GPL(jbt6k74_enter_state); +EXPORT_SYMBOL_GPL(jbt6k74_set_resolution); -static ssize_t state_read(struct device *dev, struct device_attribute *attr, +static ssize_t resolution_read(struct device *dev, struct device_attribute *attr, char *buf) { struct jbt_info *jbt = dev_get_drvdata(dev); - if (jbt->state >= ARRAY_SIZE(jbt_state_names)) + if (jbt->resolution >= ARRAY_SIZE(jbt_resolution_names)) return -EIO; - return sprintf(buf, "%s\n", jbt_state_names[jbt->state]); + return sprintf(buf, "%s\n", jbt_resolution_names[jbt->resolution]); } -static ssize_t state_write(struct device *dev, struct device_attribute *attr, +static ssize_t resolution_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct jbt_info *jbt = dev_get_drvdata(dev); int i, rc; - for (i = 0; i < ARRAY_SIZE(jbt_state_names); i++) { - if (!strncmp(buf, jbt_state_names[i], - strlen(jbt_state_names[i]))) { - rc = jbt6k74_enter_state(jbt, i); + for (i = 0; i < ARRAY_SIZE(jbt_resolution_names); i++) { + if (!strncmp(buf, jbt_resolution_names[i], + strlen(jbt_resolution_names[i]))) { + rc = jbt6k74_set_resolution(jbt, i); if (rc) return rc; return count; @@ -492,7 +506,7 @@ static ssize_t state_write(struct device *dev, struct device_attribute *attr, return -EINVAL; } -static DEVICE_ATTR(state, 0644, state_read, state_write); +static DEVICE_ATTR(resolution, 0644, resolution_read, resolution_write); static int reg_by_string(const char *name) { @@ -515,7 +529,7 @@ static ssize_t gamma_read(struct device *dev, struct device_attribute *attr, mutex_lock(&jbt->lock); val = jbt->reg_cache[reg]; - mutex_unlock(&jbt->lock); + mutex_unlock(&jbt->lock); return sprintf(buf, "0x%04x\n", val); } @@ -547,8 +561,6 @@ static ssize_t reset_write(struct device *dev, struct device_attribute *attr, mutex_lock(&jbt->lock); - jbt->state = JBT_STATE_DEEP_STANDBY; - /* hard reset the jbt6k74 */ (pdata->reset)(0, 0); mdelay(1); @@ -562,7 +574,7 @@ static ssize_t reset_write(struct device *dev, struct device_attribute *attr, mutex_unlock(&jbt->lock); - jbt6k74_enter_state(jbt, jbt->normal_state); + jbt6k74_enter_power_mode(jbt, jbt->power_mode); return count; } @@ -574,7 +586,7 @@ static DEVICE_ATTR(gamma_blue_offset, 0644, gamma_read, gamma_write); static DEVICE_ATTR(reset, 0600, NULL, reset_write); static struct attribute *jbt_sysfs_entries[] = { - &dev_attr_state.attr, + &dev_attr_resolution.attr, &dev_attr_gamma_fine1.attr, &dev_attr_gamma_fine2.attr, &dev_attr_gamma_inclination.attr, @@ -588,44 +600,89 @@ static struct attribute_group jbt_attr_group = { .attrs = jbt_sysfs_entries, }; -static int fb_notifier_callback(struct notifier_block *self, - unsigned long event, void *data) -{ - struct jbt_info *jbt; - struct fb_event *evdata = data; - int fb_blank; +/* 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); - jbt = container_of(self, struct jbt_info, fb_notif); + 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; + } +} - dev_dbg(&jbt->spi_dev->dev, "event=%lu\n", event); +static int jbt6k74_set_mode(struct lcd_device *ld, struct fb_videomode *m) { + int rc = -EINVAL; + struct jbt_info *jbt = dev_get_drvdata(&ld->dev); + + if (m->xres == 240 && m->yres == 320) { + rc = jbt6k74_set_resolution(jbt, JBT_RESOLUTION_QVGA); + } else if (m->xres == 480 && m->yres == 640) { + rc = jbt6k74_set_resolution(jbt, JBT_RESOLUTION_VGA); + } else { + dev_err(&jbt->spi_dev->dev, "Unknown resolution. Entering sleep mode.\n"); + jbt6k74_enter_power_mode(jbt, JBT_POWER_MODE_SLEEP); + } + + return rc; +} + +static int jbt6k74_set_power(struct lcd_device *ld, int power) { + int rc = -EINVAL; + struct jbt_info *jbt = dev_get_drvdata(&ld->dev); - if (event != FB_EVENT_BLANK && event != FB_EVENT_CONBLANK) - return 0; + jbt->blank_mode = power; + cancel_rearming_delayed_work(&jbt->blank_work); - fb_blank = *(int *)evdata->data; - switch (fb_blank) { + switch (power) { case FB_BLANK_UNBLANK: dev_dbg(&jbt->spi_dev->dev, "unblank\n"); - jbt6k74_enter_state(jbt, jbt->normal_state); + rc = jbt6k74_enter_power_mode(jbt, JBT_POWER_MODE_NORMAL); break; case FB_BLANK_NORMAL: dev_dbg(&jbt->spi_dev->dev, "blank\n"); - break; - case FB_BLANK_VSYNC_SUSPEND: - dev_dbg(&jbt->spi_dev->dev, "vsync suspend\n"); - break; - case FB_BLANK_HSYNC_SUSPEND: - dev_dbg(&jbt->spi_dev->dev, "hsync suspend\n"); + rc = schedule_delayed_work(&jbt->blank_work, HZ); break; case FB_BLANK_POWERDOWN: dev_dbg(&jbt->spi_dev->dev, "powerdown\n"); - jbt6k74_enter_state(jbt, JBT_STATE_SLEEP); + rc = schedule_delayed_work(&jbt->blank_work, HZ); + break; + default: break; } - return 0; + return rc; +} + +static int jbt6k74_get_power(struct lcd_device *ld) { + struct jbt_info *jbt = dev_get_drvdata(&ld->dev); + + switch (jbt->power_mode) { + case JBT_POWER_MODE_NORMAL: + return FB_BLANK_UNBLANK; + case JBT_POWER_MODE_SLEEP: + return FB_BLANK_NORMAL; + default: + return JBT_POWER_MODE_DEEP_STANDBY; + } } +struct lcd_ops jbt6k74_lcd_ops = { + .set_power = jbt6k74_set_power, + .get_power = jbt6k74_get_power, + .set_mode = jbt6k74_set_mode, +}; + /* linux device model infrastructure */ static int __devinit jbt_probe(struct spi_device *spi) @@ -651,17 +708,28 @@ static int __devinit jbt_probe(struct spi_device *spi) return -ENOMEM; jbt->spi_dev = spi; - jbt->normal_state = JBT_STATE_NORMAL; - jbt->state = JBT_STATE_DEEP_STANDBY; - jbt->last_sleep = current_kernel_time(); + + jbt->lcd_dev = lcd_device_register("jbt6k74-lcd", &spi->dev, + jbt, &jbt6k74_lcd_ops); + + if (IS_ERR(jbt->lcd_dev)) { + rc = PTR_ERR(jbt->lcd_dev); + 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->last_sleep = jiffies + msecs_to_jiffies(120); mutex_init(&jbt->lock); dev_set_drvdata(&spi->dev, jbt); - rc = jbt6k74_enter_state(jbt, JBT_STATE_NORMAL); + rc = jbt6k74_enter_power_mode(jbt, JBT_POWER_MODE_NORMAL); if (rc < 0) { dev_err(&spi->dev, "cannot enter NORMAL state\n"); - goto err_free_drvdata; + goto err_unregister_lcd; } rc = sysfs_create_group(&spi->dev.kobj, &jbt_attr_group); @@ -670,22 +738,15 @@ static int __devinit jbt_probe(struct spi_device *spi) goto err_standby; } - jbt->fb_notif.notifier_call = fb_notifier_callback; - rc = fb_register_client(&jbt->fb_notif); - if (rc < 0) { - dev_err(&spi->dev, "cannot register notifier\n"); - goto err_sysfs; - } - if (pdata->probe_completed) (pdata->probe_completed)(&spi->dev); return 0; -err_sysfs: - sysfs_remove_group(&spi->dev.kobj, &jbt_attr_group); err_standby: - jbt6k74_enter_state(jbt, JBT_STATE_DEEP_STANDBY); + jbt6k74_enter_power_mode(jbt, JBT_POWER_MODE_DEEP_STANDBY); +err_unregister_lcd: + lcd_device_unregister(jbt->lcd_dev); err_free_drvdata: dev_set_drvdata(&spi->dev, NULL); kfree(jbt); @@ -698,12 +759,14 @@ static int __devexit jbt_remove(struct spi_device *spi) struct jbt_info *jbt = dev_get_drvdata(&spi->dev); /* We don't want to switch off the display in case the user - * accidentially onloads the module (whose use count normally is 0) */ - jbt6k74_enter_state(jbt, jbt->normal_state); + * accidentially unloads the module (whose use count normally is 0) */ + jbt6k74_enter_power_mode(jbt, JBT_POWER_MODE_NORMAL); - fb_unregister_client(&jbt->fb_notif); sysfs_remove_group(&spi->dev.kobj, &jbt_attr_group); dev_set_drvdata(&spi->dev, NULL); + + lcd_device_unregister(jbt->lcd_dev); + kfree(jbt); return 0; @@ -714,7 +777,10 @@ static int jbt_suspend(struct spi_device *spi, pm_message_t state) { struct jbt_info *jbt = dev_get_drvdata(&spi->dev); - jbt6k74_enter_state(jbt, JBT_STATE_DEEP_STANDBY); + jbt->suspend_mode = jbt->power_mode; + + jbt6k74_enter_power_mode(jbt, JBT_POWER_MODE_DEEP_STANDBY); + jbt->suspended = 1; dev_info(&spi->dev, "suspended\n"); @@ -724,12 +790,9 @@ 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 *pdata = spi->dev.platform_data; - - jbt6k74_enter_state(jbt, jbt->normal_state); - if (pdata->resuming) - (pdata->resuming)(0); + jbt->suspended = 0; + jbt6k74_enter_power_mode(jbt, jbt->suspend_mode); dev_info(&spi->dev, "resumed\n");