439 lines
14 KiB
Diff
439 lines
14 KiB
Diff
From de64d8449b10dc39eebdee6bc01409cd0197e38a Mon Sep 17 00:00:00 2001
|
|
From: Andy Green <andy@openmoko.com>
|
|
Date: Wed, 2 Jul 2008 22:38:15 +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 <andy@openmoko.com>
|
|
---
|
|
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 ec6b9f1..2f9b9e1 100644
|
|
--- a/drivers/i2c/chips/pcf50633.c
|
|
+++ b/drivers/i2c/chips/pcf50633.c
|
|
@@ -1937,7 +1937,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);
|
|
|
|
@@ -2153,11 +2153,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)
|
|
@@ -2251,9 +2251,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);
|
|
|
|
@@ -2281,10 +2278,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? */
|
|
@@ -2298,7 +2291,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 34b2a01..4925e62 100644
|
|
--- a/drivers/mfd/glamo/glamo-core.c
|
|
+++ b/drivers/mfd/glamo/glamo-core.c
|
|
@@ -1087,6 +1087,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
|
|
@@ -1225,6 +1227,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);
|
|
@@ -1234,6 +1248,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 <asm/system.h>
|
|
-
|
|
+#include <linux/resume-dependency.h>
|
|
|
|
/* 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 <linux/device.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/delay.h>
|
|
-#include <linux/workqueue.h>
|
|
#include <linux/jbt6k74.h>
|
|
|
|
-#include <linux/spi/spi.h>
|
|
-
|
|
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 <linux/spi/glamo.h>
|
|
+#include <linux/resume-dependency.h>
|
|
|
|
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 <linux/spi/spi.h>
|
|
+
|
|
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.5
|
|
|