From b604d51087159af1a18546bf94e16ac6adf74746 Mon Sep 17 00:00:00 2001 From: Andy Green Date: Fri, 25 Jul 2008 23:06:11 +0100 Subject: [PATCH] add-use-pcf50633-resume-callback-jbt6k74.patch Adds the resume callback stuff to glamo, then changes jbt6k74 to no longer use a sleeping workqueue, but to make its resume actions dependent on pcf50633 and glamo resume (for backlight and communication to LCM respectively) Signed-off-by: Andy Green --- arch/arm/mach-s3c2440/mach-gta02.c | 39 ++++++++++++++++++++- drivers/i2c/chips/pcf50633.c | 17 +++------ drivers/mfd/glamo/glamo-core.c | 16 ++++++++ drivers/mfd/glamo/glamo-core.h | 3 +- drivers/video/display/jbt6k74.c | 67 +++++++++++++++++++----------------- include/linux/glamofb.h | 3 ++ include/linux/jbt6k74.h | 4 ++ include/linux/pcf50633.h | 2 +- include/linux/resume-dependency.h | 10 +++--- 9 files changed, 108 insertions(+), 53 deletions(-) diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c index d7882ea..9ba1036 100644 --- a/arch/arm/mach-s3c2440/mach-gta02.c +++ b/arch/arm/mach-s3c2440/mach-gta02.c @@ -88,6 +88,12 @@ /* arbitrates which sensor IRQ owns the shared SPI bus */ static spinlock_t motion_irq_lock; +/* the dependency of jbt / LCM on pcf50633 resume */ +struct resume_dependency resume_dep_jbt_pcf; +/* the dependency of jbt / LCM on glamo resume */ +struct resume_dependency resume_dep_jbt_glamo; + + /* define FIQ IPC struct */ /* * contains stuff FIQ ISR modifies and normal kernel code can see and use @@ -857,21 +863,50 @@ static struct s3c2410_ts_mach_info gta02_ts_cfg = { /* SPI: LCM control interface attached to Glamo3362 */ -void gta02_jbt6k74_reset(int devidx, int level) +static void gta02_jbt6k74_reset(int devidx, int level) { glamo_lcm_reset(level); } /* finally bring up deferred backlight resume now LCM is resumed itself */ -void gta02_jbt6k74_resuming(int devidx) +static void gta02_jbt6k74_resuming(int devidx) { pcf50633_backlight_resume(pcf50633_global); } +static int gta02_jbt6k74_all_dependencies_resumed(int devidx) +{ + if (!resume_dep_jbt_pcf.called_flag) + return 0; + + if (!resume_dep_jbt_glamo.called_flag) + return 0; + + return 1; +} + +/* register jbt resume action to be dependent on pcf50633 and glamo resume */ + +static void gta02_jbt6k74_suspending(int devindex, struct spi_device *spi) +{ + void jbt6k74_resume(void *spi); /* little white lies about types */ + + resume_dep_jbt_pcf.callback = jbt6k74_resume; + resume_dep_jbt_pcf.context = (void *)spi; + pcf50633_register_resume_dependency(pcf50633_global, + &resume_dep_jbt_pcf); + resume_dep_jbt_glamo.callback = jbt6k74_resume; + resume_dep_jbt_glamo.context = (void *)spi; + glamo_register_resume_dependency(&resume_dep_jbt_glamo); +} + + const struct jbt6k74_platform_data jbt6k74_pdata = { .reset = gta02_jbt6k74_reset, .resuming = gta02_jbt6k74_resuming, + .suspending = gta02_jbt6k74_suspending, + .all_dependencies_resumed = gta02_jbt6k74_all_dependencies_resumed, }; static struct spi_board_info gta02_spi_board_info[] = { diff --git a/drivers/i2c/chips/pcf50633.c b/drivers/i2c/chips/pcf50633.c index e477cd7..e5ffeff 100644 --- a/drivers/i2c/chips/pcf50633.c +++ b/drivers/i2c/chips/pcf50633.c @@ -1928,7 +1928,7 @@ static int pcf50633_detect(struct i2c_adapter *adapter, int address, int kind) pcf50633_global = data; - init_resume_dependency_list(data->resume_dependency); + init_resume_dependency_list(&data->resume_dependency); populate_sysfs_group(data); @@ -2143,11 +2143,11 @@ int pcf50633_report_resumers(struct pcf50633_data *pcf, char *buf) */ void pcf50633_register_resume_dependency(struct pcf50633_data *pcf, - struct pcf50633_resume_dependency *dep) + struct resume_dependency *dep) { - register_resume_dependency(pcf->resume_dependency, dep); + register_resume_dependency(&pcf->resume_dependency, dep); } -EXPORT_SYMBOL_GPL(pcf50633_register_resume_dep); +EXPORT_SYMBOL_GPL(pcf50633_register_resume_dependency); static int pcf50633_suspend(struct device *dev, pm_message_t state) @@ -2240,9 +2240,6 @@ static int pcf50633_resume(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct pcf50633_data *pcf = i2c_get_clientdata(client); int i; - struct list_head *pos, *q; - struct pcf50633_resume_dependency *dep; - mutex_lock(&pcf->lock); @@ -2270,10 +2267,6 @@ static int pcf50633_resume(struct device *dev) __reg_write(pcf, PCF50633_REG_LEDOUT, pcf->standby_regs.ledout); __reg_write(pcf, PCF50633_REG_LEDENA, pcf->standby_regs.ledena); __reg_write(pcf, PCF50633_REG_LEDDIM, pcf->standby_regs.leddim); - } else { /* force backlight down, platform will restore later */ - __reg_write(pcf, PCF50633_REG_LEDOUT, 2); - __reg_write(pcf, PCF50633_REG_LEDENA, 0x20); - __reg_write(pcf, PCF50633_REG_LEDDIM, 1); } /* FIXME: one big read? */ @@ -2287,7 +2280,7 @@ static int pcf50633_resume(struct device *dev) pcf50633_irq(pcf->irq, pcf); - callback_all_resume_dependencies(pcf->resume_dependency); + callback_all_resume_dependencies(&pcf->resume_dependency); return 0; } diff --git a/drivers/mfd/glamo/glamo-core.c b/drivers/mfd/glamo/glamo-core.c index a6b977b..445ff24 100644 --- a/drivers/mfd/glamo/glamo-core.c +++ b/drivers/mfd/glamo/glamo-core.c @@ -1088,6 +1088,8 @@ static int __init glamo_probe(struct platform_device *pdev) goto out_free; } + init_resume_dependency_list(&glamo->resume_dependency); + /* register a number of sibling devices whoise IOMEM resources * are siblings of pdev's IOMEM resource */ #if 0 @@ -1226,6 +1228,18 @@ static int glamo_remove(struct platform_device *pdev) } #ifdef CONFIG_PM + +/* have to export this because struct glamo_core is opaque */ + +void glamo_register_resume_dependency(struct resume_dependency * + resume_dependency) +{ + register_resume_dependency(&glamo_handle->resume_dependency, + resume_dependency); +} +EXPORT_SYMBOL_GPL(glamo_register_resume_dependency); + + static int glamo_suspend(struct platform_device *pdev, pm_message_t state) { glamo_power(glamo_handle, GLAMO_POWER_SUSPEND); @@ -1235,6 +1249,8 @@ static int glamo_suspend(struct platform_device *pdev, pm_message_t state) static int glamo_resume(struct platform_device *pdev) { glamo_power(glamo_handle, GLAMO_POWER_ON); + callback_all_resume_dependencies(&glamo_handle->resume_dependency); + return 0; } #else diff --git a/drivers/mfd/glamo/glamo-core.h b/drivers/mfd/glamo/glamo-core.h index cf89f03..1fee059 100644 --- a/drivers/mfd/glamo/glamo-core.h +++ b/drivers/mfd/glamo/glamo-core.h @@ -2,7 +2,7 @@ #define __GLAMO_CORE_H #include - +#include /* for the time being, we put the on-screen framebuffer into the lowest * VRAM space. This should make the code easily compatible with the various @@ -29,6 +29,7 @@ struct glamo_core { u_int16_t type; u_int16_t revision; spinlock_t lock; + struct resume_dependency resume_dependency; }; struct glamo_script { diff --git a/drivers/video/display/jbt6k74.c b/drivers/video/display/jbt6k74.c index 178e2da..8e7bf36 100644 --- a/drivers/video/display/jbt6k74.c +++ b/drivers/video/display/jbt6k74.c @@ -27,11 +27,8 @@ #include #include #include -#include #include -#include - enum jbt_register { JBT_REG_SLEEP_IN = 0x10, JBT_REG_SLEEP_OUT = 0x11, @@ -116,14 +113,12 @@ struct jbt_info { struct mutex lock; /* protects tx_buf and reg_cache */ u16 tx_buf[8]; u16 reg_cache[0xEE]; - struct work_struct work; + int have_resumed; }; #define JBT_COMMAND 0x000 #define JBT_DATA 0x100 -static void jbt_resume_work(struct work_struct *work); - static int jbt_reg_write_nodata(struct jbt_info *jbt, u8 reg) { @@ -576,8 +571,6 @@ static int __devinit jbt_probe(struct spi_device *spi) if (!jbt) return -ENOMEM; - INIT_WORK(&jbt->work, jbt_resume_work); - jbt->spi_dev = spi; jbt->state = JBT_STATE_DEEP_STANDBY; mutex_init(&jbt->lock); @@ -635,27 +628,48 @@ static int jbt_suspend(struct spi_device *spi, pm_message_t state) struct jbt_info *jbt = dev_get_drvdata(&spi->dev); struct jbt6k74_platform_data *jbt6k74_pdata = spi->dev.platform_data; + /* platform needs to register resume dependencies here */ + if (jbt6k74_pdata->suspending) + (jbt6k74_pdata->suspending)(0, spi); + /* Save mode for resume */ jbt->last_state = jbt->state; jbt6k74_enter_state(jbt, JBT_STATE_DEEP_STANDBY); - (jbt6k74_pdata->reset)(0, 0); + jbt->have_resumed = 0; + +// (jbt6k74_pdata->reset)(0, 0); return 0; } -static void jbt_resume_work(struct work_struct *work) +int jbt6k74_resume(struct spi_device *spi) { - struct jbt_info *jbt = container_of(work, struct jbt_info, work); - struct jbt6k74_platform_data *jbt6k74_pdata = - jbt->spi_dev->dev.platform_data; + struct jbt_info *jbt = dev_get_drvdata(&spi->dev); + struct jbt6k74_platform_data *jbt6k74_pdata = spi->dev.platform_data; + + /* if we still wait on dependencies, exit because we will get called + * again. This guy will get called once by core resume action, and + * should be set as resume_dependency callback for any dependencies + * set by platform code. + */ - printk(KERN_INFO"jbt_resume_work waiting...\n"); - /* 100ms is not enough here 2008-05-08 andy@openmoko.com - * if CONFIG_PM_DEBUG is enabled 2000ms is required + if (jbt6k74_pdata->all_dependencies_resumed) + if (!(jbt6k74_pdata->all_dependencies_resumed)(0)) + return 0; + + /* we can get called twice with all dependencies resumed if our core + * resume callback is last of all. Protect against going twice */ - msleep(400); - printk(KERN_INFO"jbt_resume_work GO...\n"); + if (jbt->have_resumed) + return 0; + + jbt->have_resumed = 1; + + /* OK we are sure all devices we depend on for operation are up now */ + + /* even this needs glamo up on GTA02 :-/ */ + (jbt6k74_pdata->reset)(0, 1); jbt6k74_enter_state(jbt, JBT_STATE_DEEP_STANDBY); msleep(100); @@ -675,21 +689,10 @@ static void jbt_resume_work(struct work_struct *work) if (jbt6k74_pdata->resuming) (jbt6k74_pdata->resuming)(0); - printk(KERN_INFO"jbt_resume_work done...\n"); -} - -static int jbt_resume(struct spi_device *spi) -{ - struct jbt_info *jbt = dev_get_drvdata(&spi->dev); - struct jbt6k74_platform_data *jbt6k74_pdata = spi->dev.platform_data; - - (jbt6k74_pdata->reset)(0, 1); - - if (!schedule_work(&jbt->work)) - dev_err(&spi->dev, "Unable to schedule LCM wakeup work\n"); - return 0; } +EXPORT_SYMBOL_GPL(jbt6k74_resume); + #else #define jbt_suspend NULL #define jbt_resume NULL @@ -704,7 +707,7 @@ static struct spi_driver jbt6k74_driver = { .probe = jbt_probe, .remove = __devexit_p(jbt_remove), .suspend = jbt_suspend, - .resume = jbt_resume, + .resume = jbt6k74_resume, }; static int __init jbt_init(void) diff --git a/include/linux/glamofb.h b/include/linux/glamofb.h index 51bf593..bb4ed0a 100644 --- a/include/linux/glamofb.h +++ b/include/linux/glamofb.h @@ -2,6 +2,7 @@ #define _LINUX_GLAMOFB_H #include +#include struct glamofb_val { unsigned int defval; @@ -36,5 +37,7 @@ struct glamofb_platform_data { int glamofb_cmd_mode(struct glamofb_handle *gfb, int on); int glamofb_cmd_write(struct glamofb_handle *gfb, u_int16_t val); void glamo_lcm_reset(int level); +extern void +glamo_register_resume_dependency(struct resume_dependency * resume_dependency); #endif diff --git a/include/linux/jbt6k74.h b/include/linux/jbt6k74.h index 0ac9124..f0eaf39 100644 --- a/include/linux/jbt6k74.h +++ b/include/linux/jbt6k74.h @@ -1,9 +1,13 @@ #ifndef __JBT6K74_H__ #define __JBT6K74_H__ +#include + struct jbt6k74_platform_data { void (*reset)(int devindex, int level); void (*resuming)(int devindex); /* called when LCM is resumed */ + void (*suspending)(int devindex, struct spi_device *spi); + int (*all_dependencies_resumed)(int devindex); }; #endif diff --git a/include/linux/pcf50633.h b/include/linux/pcf50633.h index 2bef616..8a75b28 100644 --- a/include/linux/pcf50633.h +++ b/include/linux/pcf50633.h @@ -127,7 +127,7 @@ pcf50633_report_resumers(struct pcf50633_data *pcf, char *buf); extern void pcf50633_register_resume_dependency(struct pcf50633_data *pcf, - struct pcf50633_resume_dependency *dep); + struct resume_dependency *dep); #define PCF50633_FEAT_EXTON 0x00000001 /* not yet supported */ diff --git a/include/linux/resume-dependency.h b/include/linux/resume-dependency.h index b13aa3e..e0c0f33 100644 --- a/include/linux/resume-dependency.h +++ b/include/linux/resume-dependency.h @@ -38,7 +38,7 @@ struct resume_dependency { */ #define init_resume_dependency_list(_head) \ - INIT_LIST_HEAD(&_head.list); + INIT_LIST_HEAD(&(_head)->list); /* if your resume function depends on something else being resumed first, you @@ -48,8 +48,8 @@ struct resume_dependency { */ #define register_resume_dependency(_head, _dep) { \ - _dep->called_flag = 0; \ - list_add(&_dep->list, &_head->list); \ + (_dep)->called_flag = 0; \ + list_add(&(_dep)->list, &(_head)->list); \ } /* In the resume function that things can be dependent on, at the end you @@ -61,10 +61,10 @@ struct resume_dependency { struct list_head *_pos, *_q; \ struct resume_dependency *_dep; \ \ - list_for_each_safe(pos, _q, &_head.list) { \ + list_for_each_safe(_pos, _q, &((_head)->list)) { \ _dep = list_entry(_pos, struct resume_dependency, list); \ _dep->called_flag = 1; \ - (_dep->callback)(dep->context); \ + (_dep->callback)(_dep->context); \ list_del(_pos); \ } \ } -- 1.5.6.3