diff options
-rw-r--r-- | drivers/i2c/chips/pcf50633.c | 6 | ||||
-rw-r--r-- | drivers/mfd/glamo/glamo-core.c | 5 | ||||
-rw-r--r-- | drivers/mfd/glamo/glamo-core.h | 1 | ||||
-rw-r--r-- | include/linux/resume-dependency.h | 38 |
4 files changed, 49 insertions, 1 deletions
diff --git a/drivers/i2c/chips/pcf50633.c b/drivers/i2c/chips/pcf50633.c index 58f85d2ba58..0a8daf40a3e 100644 --- a/drivers/i2c/chips/pcf50633.c +++ b/drivers/i2c/chips/pcf50633.c @@ -183,6 +183,7 @@ struct pcf50633_data { } standby_regs; struct resume_dependency resume_dependency; + int is_suspended; #endif }; @@ -2372,6 +2373,8 @@ void pcf50633_register_resume_dependency(struct pcf50633_data *pcf, struct resume_dependency *dep) { register_resume_dependency(&pcf->resume_dependency, dep); + if (pcf->is_suspended) + activate_all_resume_dependencies(&pcf->resume_dependency); } EXPORT_SYMBOL_GPL(pcf50633_register_resume_dependency); @@ -2468,6 +2471,8 @@ static int pcf50633_suspend(struct device *dev, pm_message_t state) mutex_unlock(&pcf->lock); + pcf->is_suspended = 1; + activate_all_resume_dependencies(&pcf->resume_dependency); return 0; } @@ -2600,6 +2605,7 @@ static int pcf50633_resume(struct device *dev) get_device(&pcf->client.dev); pcf50633_work(&pcf->work); + pcf->is_suspended = 0; 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 7123080e050..0fea4f4ea0e 100644 --- a/drivers/mfd/glamo/glamo-core.c +++ b/drivers/mfd/glamo/glamo-core.c @@ -1255,6 +1255,8 @@ void glamo_register_resume_dependency(struct resume_dependency * { register_resume_dependency(&glamo_handle->resume_dependency, resume_dependency); + if (glamo_handle->is_suspended) + activate_all_resume_dependencies(&glamo_handle->resume_dependency); } EXPORT_SYMBOL_GPL(glamo_register_resume_dependency); @@ -1262,12 +1264,15 @@ 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); + glamo_handle->is_suspended = 1; + activate_all_resume_dependencies(&glamo_handle->resume_dependency); return 0; } static int glamo_resume(struct platform_device *pdev) { glamo_power(glamo_handle, GLAMO_POWER_ON); + glamo_handle->is_suspended = 0; callback_all_resume_dependencies(&glamo_handle->resume_dependency); return 0; diff --git a/drivers/mfd/glamo/glamo-core.h b/drivers/mfd/glamo/glamo-core.h index 57214de9e00..ce8d4c7e79e 100644 --- a/drivers/mfd/glamo/glamo-core.h +++ b/drivers/mfd/glamo/glamo-core.h @@ -31,6 +31,7 @@ struct glamo_core { struct resume_dependency resume_dependency; u32 engine_enabled_bitfield; u32 engine_enabled_bitfield_suspend; + int is_suspended; }; struct glamo_script { diff --git a/include/linux/resume-dependency.h b/include/linux/resume-dependency.h index e0c0f33e2c3..959cadd8365 100644 --- a/include/linux/resume-dependency.h +++ b/include/linux/resume-dependency.h @@ -38,6 +38,7 @@ struct resume_dependency { */ #define init_resume_dependency_list(_head) \ + printk(KERN_ERR "##### init_resume_dependency_list(head=%p)\n", (_head)); \ INIT_LIST_HEAD(&(_head)->list); @@ -48,7 +49,18 @@ struct resume_dependency { */ #define register_resume_dependency(_head, _dep) { \ - (_dep)->called_flag = 0; \ + struct list_head *_pos, *_q; \ + struct resume_dependency *_d; \ +\ + printk(KERN_ERR "##### register_resume_dependency(head=%p, dep=%p)\n", (_head), (_dep)); \ + (_dep)->called_flag = 1; \ + list_for_each_safe(_pos, _q, &((_head)->list)) { \ + _d = list_entry(_pos, struct resume_dependency, list); \ + if (_d == (_dep)) { \ + list_del(_pos); \ + printk(KERN_ERR "##### duplicate dependency removed first\n"); \ + } \ + } \ list_add(&(_dep)->list, &(_head)->list); \ } @@ -61,14 +73,38 @@ struct resume_dependency { struct list_head *_pos, *_q; \ struct resume_dependency *_dep; \ \ + printk(KERN_ERR "##### callback_all_resume_dependencies(head=%p)\n", (_head)); \ list_for_each_safe(_pos, _q, &((_head)->list)) { \ _dep = list_entry(_pos, struct resume_dependency, list); \ + printk(KERN_ERR "##### callback list entry (head=%p, dep=%p)\n", (_head), (_dep)); \ _dep->called_flag = 1; \ + printk(KERN_ERR "##### callback=%p(context=%p))\n", (_dep->callback),(_dep->context)); \ (_dep->callback)(_dep->context); \ list_del(_pos); \ } \ } +/* When a dependency is added, it is not actually active; the dependent resume + * handler will function as normal. The dependency is activated by the suspend + * handler for the driver that will be doing the callbacks. This ensures that + * if the suspend is aborted for any reason (error, driver busy, etc), that all + * suspended drivers will resume, even if the driver upon which they are dependent + * did not suspend, and hence will not resume, and thus would be unable to perform + * the callbacks. + */ + +#define activate_all_resume_dependencies(_head) { \ + struct list_head *_pos, *_q; \ + struct resume_dependency *_dep; \ +\ + printk(KERN_ERR "##### activate_all_resume_dependencies(head=%p)\n", (_head)); \ + list_for_each_safe(_pos, _q, &((_head)->list)) { \ + _dep = list_entry(_pos, struct resume_dependency, list); \ + printk(KERN_ERR "##### activating callback list entry (head=%p, dep=%p)\n", (_head), (_dep)); \ + _dep->called_flag = 0; \ + } \ +} + /* if your resume action is dependent on multiple drivers being resumed already, * register the same callback with each driver you are dependent on, and check * .called_flag for all of the struct resume_dependency. When they are all 1 |