aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/i2c/chips/pcf50633.c6
-rw-r--r--drivers/mfd/glamo/glamo-core.c5
-rw-r--r--drivers/mfd/glamo/glamo-core.h1
-rw-r--r--include/linux/resume-dependency.h38
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