This is nothing but a repost of the following patches, with the patches
themselves added as attachments to ensure whitespace remains untouched.
(I'd normally do this in-line for easier review, but they've already
been posted in-line so attachments seem the most expeditious way at
present).
[PATCH 1/3] GTA01 fixes for stable
[PATCH 2/3] GTA01 fixes for stable
[PATCH 3/3] GTA01 fixes for stable
[PATCH 1/1] Add Minimal GSM flowcontrol functionality
[PATCH 1/1] GTA01/GTA02 enable serial log entry when a data error occurs
[PATCH 1/1] GTA01 - silence the console when GSM is enabled
Mike (mwester)
commit e9afa0c0bd0b43cc9b70045bb26cc2e16b83273f
Author: Mike Westerhof <[EMAIL PROTECTED]>
Date: Mon Jul 7 00:20:23 2008 -0500
silence-serial-console-gta01.patch
This patch ensures that no console data will go the UART while
the GSM mux is switched to the GSM. This is necessary despite
the code that disables the console due to the fact that the
console resumes before the neo1973_pm_gsm driver, and consoles
always resume in the "on" state.
Signed-off-by: Mike Westerhof <[EMAIL PROTECTED]>
diff --git a/arch/arm/plat-s3c24xx/neo1973_pm_gsm.c
b/arch/arm/plat-s3c24xx/neo1973_pm_gsm.c
index 178c9f7..05773f2 100644
--- a/arch/arm/plat-s3c24xx/neo1973_pm_gsm.c
+++ b/arch/arm/plat-s3c24xx/neo1973_pm_gsm.c
@@ -31,6 +31,7 @@
#include <asm/arch/regs-gpioj.h>
#endif
+extern void s3c24xx_serial_console_set_silence(int silence);
extern void s3c24xx_serial_register_resume_dependency(struct resume_dependency
*
resume_dependency, int uart_index);
@@ -105,6 +106,7 @@ static ssize_t gsm_write(struct device *dev, struct
device_attribute *attr,
"disconnecting serial console\n");
console_stop(gta01_gsm.con);
+ s3c24xx_serial_console_set_silence(1);
}
if (gta01_gsm.gpio_ngsm_en)
@@ -144,6 +146,7 @@ static ssize_t gsm_write(struct device *dev, struct
device_attribute *attr,
s3c2410_gpio_setpin(gta01_gsm.gpio_ngsm_en, 1);
if (gta01_gsm.con) {
+ s3c24xx_serial_console_set_silence(0);
console_start(gta01_gsm.con);
dev_info(dev, "powered down GSM, thus enabling "
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index 5652905..2a388cf 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -1780,6 +1780,13 @@ module_exit(s3c24xx_serial_modexit);
#ifdef CONFIG_SERIAL_S3C2410_CONSOLE
static struct uart_port *cons_uart;
+static int cons_silenced;
+
+void s3c24xx_serial_console_set_silence(int silenced)
+{
+ cons_silenced = silenced;
+}
+EXPORT_SYMBOL(s3c24xx_serial_console_set_silence);
static int
s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)
@@ -1806,6 +1813,9 @@ s3c24xx_serial_console_putchar(struct uart_port *port,
int ch)
unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
unsigned int umcon = rd_regl(cons_uart, S3C2410_UMCON);
+ if (cons_silenced)
+ return;
+
/* If auto HW flow control enabled, temporarily turn it off */
if (umcon & S3C2410_UMCOM_AFC)
wr_regl(port, S3C2410_UMCON, (umcon & !S3C2410_UMCOM_AFC));
commit 5483b58603ae9f2bdd2962fc03ccedafed19f3e9
Author: Mike Westerhof <[EMAIL PROTECTED]>
Date: Sun Jul 6 23:04:22 2008 -0500
fix-suspend-backlight-timing-gta01.patch
This patch adds the gta01 backlight callback that defers the
restoring of the backlight until after the jbt driver has
resumed. This doesn't eliminate the flashing of the LCD on
the gta01, but it reduces it considerably.
Signed-off-by: Mike Westerhof <[EMAIL PROTECTED]>
diff --git a/arch/arm/mach-s3c2410/mach-gta01.c
b/arch/arm/mach-s3c2410/mach-gta01.c
index 9adcaa0..4927cd4 100644
--- a/arch/arm/mach-s3c2410/mach-gta01.c
+++ b/arch/arm/mach-s3c2410/mach-gta01.c
@@ -509,14 +509,20 @@ static struct s3c2410_ts_mach_info gta01_ts_cfg = {
/* SPI */
-void gta01_jbt6k74_reset(int devidx, int level)
+static void gta01_jbt6k74_reset(int devidx, int level)
{
/* empty place holder; gta01 does not yet use this */
printk(KERN_DEBUG "gta01_jbt6k74_reset\n");
}
+static void gta01_jbt6k74_resuming(int devidx)
+{
+ gta01bl_deferred_resume();
+}
+
const struct jbt6k74_platform_data gta01_jbt6k74_pdata = {
.reset = gta01_jbt6k74_reset,
+ .resuming = gta01_jbt6k74_resuming,
};
static struct spi_board_info gta01_spi_board_info[] = {
@@ -586,6 +592,7 @@ static struct gta01bl_machinfo backlight_machinfo = {
.default_intensity = 1,
.max_intensity = 1,
.limit_mask = 1,
+ .defer_resume_backlight = 1,
};
static struct resource gta01_bl_resources[] = {
diff --git a/drivers/video/backlight/gta01_bl.c
b/drivers/video/backlight/gta01_bl.c
index 301ec9c..34c19c8 100644
--- a/drivers/video/backlight/gta01_bl.c
+++ b/drivers/video/backlight/gta01_bl.c
@@ -57,6 +57,8 @@ struct gta01bl_data {
static struct gta01bl_data gta01bl;
+static int gta01bl_defer_resume_backlight;
+
#define GTA01BL_SUSPENDED 0x01
#define GTA01BL_BATTLOW 0x02
@@ -132,10 +134,12 @@ static int gta01bl_suspend(struct platform_device *dev,
pm_message_t state)
{
gta01bl_flags |= GTA01BL_SUSPENDED;
gta01bl_send_intensity(gta01_backlight_device);
+ neo1973_gpb_setpin(GTA01_GPIO_BACKLIGHT, 0);
+ s3c2410_gpio_cfgpin(GTA01_GPIO_BACKLIGHT, S3C2410_GPIO_OUTPUT);
return 0;
}
-static int gta01bl_resume(struct platform_device *dev)
+void gta01bl_deferred_resume(void)
{
mutex_lock(>a01bl.mutex);
gta01bl_init_hw();
@@ -143,6 +147,13 @@ static int gta01bl_resume(struct platform_device *dev)
gta01bl_flags &= ~GTA01BL_SUSPENDED;
gta01bl_send_intensity(gta01_backlight_device);
+}
+EXPORT_SYMBOL_GPL(gta01bl_deferred_resume);
+
+static int gta01bl_resume(struct platform_device *dev)
+{
+ if (! gta01bl_defer_resume_backlight)
+ gta01bl_deferred_resume();
return 0;
}
#else
@@ -199,6 +210,8 @@ static int __init gta01bl_probe(struct platform_device
*pdev)
if (!machinfo->limit_mask)
machinfo->limit_mask = -1;
+ gta01bl_defer_resume_backlight = machinfo->defer_resume_backlight;
+
gta01_backlight_device = backlight_device_register("gta01-bl",
&pdev->dev, NULL,
>a01bl_ops);
diff --git a/include/asm-arm/arch-s3c2410/gta01.h
b/include/asm-arm/arch-s3c2410/gta01.h
index 1cc2099..989aa55 100644
--- a/include/asm-arm/arch-s3c2410/gta01.h
+++ b/include/asm-arm/arch-s3c2410/gta01.h
@@ -12,10 +12,14 @@
#define GTA01Bv4_SYSTEM_REV 0x00000240
/* Backlight */
+
+extern void gta01bl_deferred_resume(void);
+
struct gta01bl_machinfo {
unsigned int default_intensity;
unsigned int max_intensity;
unsigned int limit_mask;
+ unsigned int defer_resume_backlight;
};
/* Definitions common to all revisions */
commit 088101571660b85bb7e6073e0da5fcbdbbd9aa87
Author: Mike Westerhof <[EMAIL PROTECTED]>
Date: Fri Jul 4 13:53:46 2008 -0500
gta0x-add-minimal-GSM-flowcontrol.patch
Add the basic GSM flowcontrol code.
Signed-off-by: Mike Westerhof <[EMAIL PROTECTED]>
diff --git a/arch/arm/mach-s3c2410/mach-gta01.c
b/arch/arm/mach-s3c2410/mach-gta01.c
index 6af5566..a017328 100644
--- a/arch/arm/mach-s3c2410/mach-gta01.c
+++ b/arch/arm/mach-s3c2410/mach-gta01.c
@@ -652,9 +652,12 @@ static void __init gta01_map_io(void)
s3c24xx_init_uarts(gta01_uartcfgs, ARRAY_SIZE(gta01_uartcfgs));
}
+extern int gta_gsm_interrupts;
+
static irqreturn_t gta01_modem_irq(int irq, void *param)
{
printk(KERN_DEBUG "GSM wakeup interrupt (IRQ %d)\n", irq);
+ gta_gsm_interrupts++;
return IRQ_HANDLED;
}
diff --git a/arch/arm/mach-s3c2440/mach-gta02.c
b/arch/arm/mach-s3c2440/mach-gta02.c
index 7118332..6876850 100644
--- a/arch/arm/mach-s3c2440/mach-gta02.c
+++ b/arch/arm/mach-s3c2440/mach-gta02.c
@@ -1492,9 +1492,12 @@ static void __init gta02_map_io(void)
s3c24xx_init_uarts(gta02_uartcfgs, ARRAY_SIZE(gta02_uartcfgs));
}
+extern int gta_gsm_interrupts;
+
static irqreturn_t gta02_modem_irq(int irq, void *param)
{
printk(KERN_DEBUG "modem wakeup interrupt\n");
+ gta_gsm_interrupts++;
return IRQ_HANDLED;
}
diff --git a/arch/arm/plat-s3c24xx/neo1973_pm_gsm.c
b/arch/arm/plat-s3c24xx/neo1973_pm_gsm.c
index 5ef23d1..178c9f7 100644
--- a/arch/arm/plat-s3c24xx/neo1973_pm_gsm.c
+++ b/arch/arm/plat-s3c24xx/neo1973_pm_gsm.c
@@ -34,6 +34,9 @@
extern void s3c24xx_serial_register_resume_dependency(struct resume_dependency
*
resume_dependency, int uart_index);
+int gta_gsm_interrupts;
+EXPORT_SYMBOL(gta_gsm_interrupts);
+
struct gta01pm_priv {
int gpio_ngsm_en;
int gpio_ndl_gsm;
@@ -80,6 +83,9 @@ static ssize_t gsm_read(struct device *dev, struct
device_attribute *attr,
if (!s3c2410_gpio_getpin(GTA02_GPIO_nDL_GSM))
goto out_1;
}
+ } else if (!strcmp(attr->attr.name, "flowcontrolled")) {
+ if (s3c2410_gpio_getcfg(S3C2410_GPH1) == S3C2410_GPIO_OUTPUT)
+ goto out_1;
}
return strlcpy(buf, "0\n", 3);
@@ -176,6 +182,13 @@ static ssize_t gsm_write(struct device *dev, struct
device_attribute *attr,
gta01_gsm.gpio_ndl_gsm = !on;
s3c2410_gpio_setpin(GTA02_GPIO_nDL_GSM, !on);
}
+ } else if (!strcmp(attr->attr.name, "flowcontrolled")) {
+ if (on) {
+ gta_gsm_interrupts = 0;
+ s3c2410_gpio_setpin(S3C2410_GPH1, 1);
+ s3c2410_gpio_cfgpin(S3C2410_GPH1, S3C2410_GPH1_OUTP);
+ } else
+ s3c2410_gpio_cfgpin(S3C2410_GPH1, S3C2410_GPH1_nRTS0);
}
return count;
@@ -184,6 +197,7 @@ static ssize_t gsm_write(struct device *dev, struct
device_attribute *attr,
static DEVICE_ATTR(power_on, 0644, gsm_read, gsm_write);
static DEVICE_ATTR(reset, 0644, gsm_read, gsm_write);
static DEVICE_ATTR(download, 0644, gsm_read, gsm_write);
+static DEVICE_ATTR(flowcontrolled, 0644, gsm_read, gsm_write);
#ifdef CONFIG_PM
static int gta01_gsm_resume(struct platform_device *pdev);
@@ -192,6 +206,11 @@ static int gta01_gsm_suspend(struct platform_device *pdev,
pm_message_t state)
/* GPIO state is saved/restored by S3C2410 core GPIO driver, so we
* don't need to do much here. */
+ /* If flowcontrol asserted, abort if GSM already interrupted */
+ if (s3c2410_gpio_getcfg(S3C2410_GPH1) == S3C2410_GPIO_OUTPUT) {
+ if (gta_gsm_interrupts)
+ goto busy;
+ }
/* disable DL GSM to prevent jack_insert becoming 'floating' */
if (machine_is_neo1973_gta02())
@@ -204,6 +223,20 @@ static int gta01_gsm_suspend(struct platform_device *pdev,
pm_message_t state)
s3c24xx_serial_register_resume_dependency(&resume_dep_gsm_uart, 0);
return 0;
+
+busy:
+ return -EBUSY;
+}
+
+static int
+gta01_gsm_suspend_late(struct platform_device *pdev, pm_message_t state)
+{
+ /* Last chance: abort if GSM already interrupted */
+ if (s3c2410_gpio_getcfg(S3C2410_GPH1) == S3C2410_GPIO_OUTPUT) {
+ if (gta_gsm_interrupts)
+ return -EBUSY;
+ }
+ return 0;
}
static int gta01_gsm_resume(struct platform_device *pdev)
@@ -228,6 +261,7 @@ static int gta01_gsm_resume(struct platform_device *pdev)
}
#else
#define gta01_gsm_suspend NULL
+#define gta01_gsm_suspend_late NULL
#define gta01_gsm_resume NULL
#endif
@@ -235,6 +269,7 @@ static struct attribute *gta01_gsm_sysfs_entries[] = {
&dev_attr_power_on.attr,
&dev_attr_reset.attr,
&dev_attr_download.attr,
+ &dev_attr_flowcontrolled.attr,
NULL
};
@@ -314,6 +349,7 @@ static struct platform_driver gta01_gsm_driver = {
.probe = gta01_gsm_probe,
.remove = gta01_gsm_remove,
.suspend = gta01_gsm_suspend,
+ .suspend_late = gta01_gsm_suspend_late,
.resume = gta01_gsm_resume,
.driver = {
.name = "neo1973-pm-gsm",
commit 830ea3d0c27c0c750b7bf1b56c002ee7943f3edc
Author: Mike Westerhof <[EMAIL PROTECTED]>
Date: Sun Jul 6 23:14:48 2008 -0500
gta0x-log-serial-rx-error.patch
This patch causes a KERN_DEBUG message to be printed each time an
error status is read from a UART. This is intended to facilitate
the reporting of more useful problem and bug reports from users
in the field.
Signed-off-by: Mike Westerhof <[EMAIL PROTECTED]>
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index fef3c8f..5652905 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -357,7 +357,7 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id)
port->icount.rx++;
if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) {
- dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n",
+ printk(KERN_DEBUG "rxerr: port ch=0x%02x, rxs=0x%08x\n",
ch, uerstat);
/* check for break */
commit 1c0ad8791b892e1faa334ac95fd5c6ba5c2f2ca4
Author: Mike Westerhof <[EMAIL PROTECTED]>
Date: Sun Jul 6 22:31:25 2008 -0500
gta01-pcf50606-disable-irq-from-suspend-until-resume.patch
This patch is the pcf50606 equivalent of the pcf50633 patch that
disables interrupts from the chip until after resume is complete.
In order to ensure no data is lost, the work function is called
post-resume to process any pending interrupts.
Most of the code was quite literally re-used from Andy Green's
original patch.
Signed-off-by: Mike Westerhof <[EMAIL PROTECTED]>
diff --git a/drivers/i2c/chips/pcf50606.c b/drivers/i2c/chips/pcf50606.c
index ddba1c7..18263fb 100644
--- a/drivers/i2c/chips/pcf50606.c
+++ b/drivers/i2c/chips/pcf50606.c
@@ -38,6 +38,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/workqueue.h>
+#include <linux/delay.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
#include <linux/watchdog.h>
@@ -95,6 +96,15 @@ enum close_state {
CLOSE_STATE_ALLOW = 0x2342,
};
+enum pcf50606_suspend_states {
+ PCF50606_SS_RUNNING,
+ PCF50606_SS_STARTING_SUSPEND,
+ PCF50606_SS_COMPLETED_SUSPEND,
+ PCF50606_SS_RESUMING_BUT_NOT_US_YET,
+ PCF50606_SS_STARTING_RESUME,
+ PCF50606_SS_COMPLETED_RESUME,
+};
+
struct pcf50606_data {
struct i2c_client client;
struct pcf50606_platform_data *pdata;
@@ -110,6 +120,7 @@ struct pcf50606_data {
int onkey_seconds;
int irq;
int coldplug_done;
+ enum pcf50606_suspend_states suspend_state;
#ifdef CONFIG_PM
struct {
u_int8_t dcdc1, dcdc2;
@@ -160,6 +171,10 @@ static const u_int16_t ntc_table_10k_3370B[] = {
static inline int __reg_write(struct pcf50606_data *pcf, u_int8_t reg,
u_int8_t val)
{
+ if (pcf->suspend_state == PCF50606_SS_COMPLETED_SUSPEND) {
+ dev_err(&pcf->client.dev, "__reg_write while suspended.\n");
+ dump_stack();
+ }
return i2c_smbus_write_byte_data(&pcf->client, reg, val);
}
@@ -178,6 +193,10 @@ static inline int32_t __reg_read(struct pcf50606_data
*pcf, u_int8_t reg)
{
int32_t ret;
+ if (pcf->suspend_state == PCF50606_SS_COMPLETED_SUSPEND) {
+ dev_err(&pcf->client.dev, "__reg_read while suspended.\n");
+ dump_stack();
+ }
ret = i2c_smbus_read_byte_data(&pcf->client, reg);
return ret;
@@ -569,6 +588,48 @@ static void pcf50606_work(struct work_struct *work)
mutex_lock(&pcf->working_lock);
pcf->working = 1;
+
+ /* sanity */
+ if (!&pcf->client.dev)
+ goto bail;
+
+ /*
+ * if we are presently suspending, we are not in a position to deal
+ * with pcf50606 interrupts at all.
+ *
+ * Because we didn't clear the int pending registers, there will be
+ * no edge / interrupt waiting for us when we wake. But it is OK
+ * because at the end of our resume, we call this workqueue function
+ * gratuitously, clearing the pending register and re-enabling
+ * servicing this interrupt.
+ */
+
+ if ((pcf->suspend_state == PCF50606_SS_STARTING_SUSPEND) ||
+ (pcf->suspend_state == PCF50606_SS_COMPLETED_SUSPEND))
+ goto bail;
+
+ /*
+ * If we are inside suspend -> resume completion time we don't attempt
+ * service until we have fully resumed. Although we could talk to the
+ * device as soon as I2C is up, the regs in the device which we might
+ * choose to modify as part of the service action have not been
+ * reloaded with their pre-suspend states yet. Therefore we will
+ * defer our service if we are called like that until our resume has
+ * completed.
+ *
+ * This shouldn't happen any more because we disable servicing this
+ * interrupt in suspend and don't re-enable it until resume is
+ * completed.
+ */
+
+ if (pcf->suspend_state &&
+ (pcf->suspend_state != PCF50606_SS_COMPLETED_RESUME))
+ goto reschedule;
+
+ /* this is the case early in resume! Sanity check! */
+ if (i2c_get_clientdata(&pcf->client) == NULL)
+ goto reschedule;
+
/*
* p35 pcf50606 datasheet rev 2.2:
* ''The system controller shall read all interrupt registers in
@@ -576,10 +637,27 @@ static void pcf50606_work(struct work_struct *work)
* because if you don't INT# gets stuck asserted forever after a
* while
*/
- ret = i2c_smbus_read_i2c_block_data(&pcf->client, PCF50606_REG_INT1, 3,
- pcfirq);
- if (ret != 3)
+ ret = i2c_smbus_read_i2c_block_data(&pcf->client, PCF50606_REG_INT1,
+ sizeof(pcfirq), pcfirq);
+ if (ret != sizeof(pcfirq)) {
DEBUGPC("Oh crap PMU IRQ register read failed %d\n", ret);
+ /*
+ * it shouldn't fail, we no longer attempt to use
+ * I2C while it can be suspended. But we don't have
+ * much option but to retry if if it ever did fail,
+ * because if we don't service the interrupt to clear
+ * it, we will never see another PMU interrupt edge.
+ */
+ goto reschedule;
+ }
+
+ /* hey did we just resume? (because we don't get here unless we are
+ * running normally or the first call after resumption)
+ *
+ * pcf50606 resume is really really over now then.
+ */
+ if (pcf->suspend_state != PCF50606_SS_RUNNING)
+ pcf->suspend_state = PCF50606_SS_RUNNING;
if (!pcf->coldplug_done) {
DEBUGPC("PMU Coldplug init\n");
@@ -814,10 +892,26 @@ static void pcf50606_work(struct work_struct *work)
DEBUGPC("\n");
+bail:
pcf->working = 0;
input_sync(pcf->input_dev);
put_device(&pcf->client.dev);
mutex_unlock(&pcf->working_lock);
+
+ return;
+
+reschedule:
+
+ if ((pcf->suspend_state != PCF50606_SS_STARTING_SUSPEND) &&
+ (pcf->suspend_state != PCF50606_SS_COMPLETED_SUSPEND)) {
+ msleep(10);
+ dev_info(&pcf->client.dev, "rescheduling interrupt service\n");
+ }
+ if (!schedule_work(&pcf->work))
+ dev_err(&pcf->client.dev, "int service reschedule failed\n");
+
+ /* we don't put the device here, hold it for next time */
+ mutex_unlock(&pcf->working_lock);
}
static irqreturn_t pcf50606_irq(int irq, void *_pcf)
@@ -828,7 +922,7 @@ static irqreturn_t pcf50606_irq(int irq, void *_pcf)
irq, _pcf);
get_device(&pcf->client.dev);
if (!schedule_work(&pcf->work) && !pcf->working)
- dev_dbg(&pcf->client.dev, "work item may be lost\n");
+ dev_err(&pcf->client.dev, "pcf irq work already queued.\n");
return IRQ_HANDLED;
}
@@ -1882,12 +1976,27 @@ static int pcf50606_suspend(struct device *dev,
pm_message_t state)
struct pcf50606_data *pcf = i2c_get_clientdata(client);
int i;
+ /* we suspend once (!) as late as possible in the suspend sequencing */
+
+ if ((state.event != PM_EVENT_SUSPEND) ||
+ (pcf->suspend_state != PCF50606_SS_RUNNING))
+ return -EBUSY;
+
/* The general idea is to power down all unused power supplies,
* and then mask all PCF50606 interrup sources but EXTONR, ONKEYF
* and ALARM */
mutex_lock(&pcf->lock);
+ pcf->suspend_state = PCF50606_SS_STARTING_SUSPEND;
+
+ /* we are not going to service any further interrupts until we
+ * resume. If the IRQ workqueue is still pending in the background,
+ * it will bail when it sees we set suspend state above.
+ */
+
+ disable_irq(pcf->irq);
+
/* Save all registers that don't "survive" standby state */
pcf->standby_regs.dcdc1 = __reg_read(pcf, PCF50606_REG_DCDC1);
pcf->standby_regs.dcdc2 = __reg_read(pcf, PCF50606_REG_DCDC2);
@@ -1928,6 +2037,8 @@ static int pcf50606_suspend(struct device *dev,
pm_message_t state)
__reg_write(pcf, PCF50606_REG_INT2M, ~INT2M_RESUMERS & 0xff);
__reg_write(pcf, PCF50606_REG_INT3M, ~INT3M_RESUMERS & 0xff);
+ pcf->suspend_state = PCF50606_SS_COMPLETED_SUSPEND;
+
mutex_unlock(&pcf->lock);
return 0;
@@ -1940,6 +2051,8 @@ static int pcf50606_resume(struct device *dev)
mutex_lock(&pcf->lock);
+ pcf->suspend_state = PCF50606_SS_STARTING_RESUME;
+
/* Resume all saved registers that don't "survive" standby state */
__reg_write(pcf, PCF50606_REG_INT1M, pcf->standby_regs.int1m);
__reg_write(pcf, PCF50606_REG_INT2M, pcf->standby_regs.int2m);
@@ -1958,10 +2071,17 @@ static int pcf50606_resume(struct device *dev)
__reg_write(pcf, PCF50606_REG_ADCC2, pcf->standby_regs.adcc2);
__reg_write(pcf, PCF50606_REG_PWMC1, pcf->standby_regs.pwmc1);
+ pcf->suspend_state = PCF50606_SS_COMPLETED_RESUME;
+
+ enable_irq(pcf->irq);
+
mutex_unlock(&pcf->lock);
- /* Hack to fix the gta01 power button problem on resume */
- pcf50606_irq(0, pcf);
+ /* Call PCF work function; this fixes an issue on the gta01 where
+ * the power button "goes away" if it is used to wake the device.
+ */
+ get_device(&pcf->client.dev);
+ pcf50606_work(&pcf->work);
return 0;
}
@@ -1999,9 +2119,25 @@ static int pcf50606_plat_remove(struct platform_device
*pdev)
return 0;
}
+/* We have this purely to capture an early indication that we are coming out
+ * of suspend, before our device resume got called; async interrupt service is
+ * interested in this.
+ */
+
+static int pcf50606_plat_resume(struct platform_device *pdev)
+{
+ /* i2c_get_clientdata(to_i2c_client(&pdev->dev)) returns NULL at this
+ * early resume time so we have to use pcf50606_global
+ */
+ pcf50606_global->suspend_state = PCF50606_SS_RESUMING_BUT_NOT_US_YET;
+
+ return 0;
+}
+
static struct platform_driver pcf50606_plat_driver = {
.probe = pcf50606_plat_probe,
.remove = pcf50606_plat_remove,
+ .resume_early = pcf50606_plat_resume,
.driver = {
.owner = THIS_MODULE,
.name = "pcf50606",
commit 326623f7a190cb1fcac4bce78d2bd361d1c583be
Author: Mike Westerhof <[EMAIL PROTECTED]>
Date: Thu Jul 3 23:56:19 2008 -0500
gta01-uart-fifo-trigger-sooner.patch
Set the UART FIFO to trigger earlier on the GTA01 device to minimize
UART overruns from the GSM.
Signed-off-by: Mike Westerhof <[EMAIL PROTECTED]>
diff --git a/arch/arm/mach-s3c2410/mach-gta01.c
b/arch/arm/mach-s3c2410/mach-gta01.c
index a77ed3d..6af5566 100644
--- a/arch/arm/mach-s3c2410/mach-gta01.c
+++ b/arch/arm/mach-s3c2410/mach-gta01.c
@@ -87,6 +87,8 @@ static struct map_desc gta01_iodesc[] __initdata = {
#define UCON S3C2410_UCON_DEFAULT
#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+/* UFCON for the gta01 sets the FIFO trigger level at 4, not 8 */
+#define UFCON_GTA01_PORT0 S3C2410_UFCON_FIFOMODE
static struct s3c2410_uartcfg gta01_uartcfgs[] = {
[0] = {
@@ -94,7 +96,7 @@ static struct s3c2410_uartcfg gta01_uartcfgs[] = {
.flags = 0,
.ucon = UCON,
.ulcon = ULCON,
- .ufcon = UFCON,
+ .ufcon = UFCON_GTA01_PORT0,
},
[1] = {
.hwport = 1,