Suspend/Resume oversight wrt GSM handling
Mike (mwester)
mwester at dls.net
Thu May 15 05:43:16 CEST 2008
Andy Green wrote:
...
> By all means send out a patch on the list and it will be read by at
> least one pair of interested eyes.
Let me just toss this part of the set of patches out. It's not the final one;
there's some additional logic required to integrate in the modem-control stuff
for Qtopia, assuming I correctly understood how that software expects things to
work.
So this is for discussion purposes:
--- git/arch/arm/plat-s3c24xx/neo1973_pm_gsm.c.orig 2008-05-11 17:18:41.0000
00000 -0500
+++ git/arch/arm/plat-s3c24xx/neo1973_pm_gsm.c 2008-05-11 21:49:09.000000000 -0
500
@@ -30,6 +32,17 @@
#include <asm/arch/regs-gpioj.h>
#endif
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+
+static struct work_struct gsmwork;
+
+/* flag set if we flow-controlled the GSM in our suspend routine */
+int gsm_auto_flowcontrolled = 0;
+
+/* msecs to delay the auto-unlock after resume to minimize overruns */
+int gsm_autounlock_delay = 750;
+
int gta01_gsm_enabled = 0;
EXPORT_SYMBOL(gta01_gsm_enabled);
@@ -76,6 +89,11 @@ static ssize_t gsm_read(struct device *d
if (!s3c2410_gpio_getpin(GTA02_GPIO_nDL_GSM))
goto out_1;
}
+ } else if (!strcmp(attr->attr.name, "autounlock_delay")) {
+ return snprintf(buf, PAGE_SIZE, "%d\n", gsm_autounlock_delay);
+ } 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);
@@ -178,6 +196,21 @@ static ssize_t gsm_write(struct device *
gta01_gsm.gpio_ndl_gsm = !on;
s3c2410_gpio_setpin(GTA02_GPIO_nDL_GSM, !on);
}
+ } else if (!strcmp(attr->attr.name, "autounlock_delay")) {
+ sscanf(buf, "%d", &gsm_autounlock_delay);
+ /* constrain to within reasonable bounds */
+ if (gsm_autounlock_delay < 250)
+ gsm_autounlock_delay = 250;
+ if (gsm_autounlock_delay > 5000)
+ gsm_autounlock_delay = 5000;
+ } else if (!strcmp(attr->attr.name, "flowcontrolled")) {
+ if (on) {
+ s3c2410_gpio_setpin(S3C2410_GPH1, 1);
+ s3c2410_gpio_cfgpin(S3C2410_GPH1, S3C2410_GPH1_OUTP);
+ } else {
+ s3c2410_gpio_cfgpin(S3C2410_GPH1, S3C2410_GPH1_nRTS0);
+ }
+ gsm_auto_flowcontrolled = 0; /* forced flowcontrol change */
}
return count;
@@ -186,8 +219,21 @@ static ssize_t gsm_write(struct device *
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(autounlock_delay, 0644, gsm_read, gsm_write);
+static DEVICE_ATTR(flowcontrolled, 0644, gsm_read, gsm_write);
#ifdef CONFIG_PM
+static void gsm_resume_work(struct work_struct *w)
+{
+ printk(KERN_INFO "%s: waiting...\n", __FUNCTION__);
+ msleep(gsm_autounlock_delay);
+ if (gsm_auto_flowcontrolled) {
+ s3c2410_gpio_cfgpin(S3C2410_GPH1, S3C2410_GPH1_nRTS0);
+ gsm_auto_flowcontrolled = 0;
+ }
+ printk(KERN_INFO "%s: done.\n", __FUNCTION__);
+}
+
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
@@ -198,6 +244,23 @@ static int gta01_gsm_suspend(struct plat
if (machine_is_neo1973_gta02())
s3c2410_gpio_setpin(GTA02_GPIO_nDL_GSM, 1);
+ /*
+ * Forcibly flow-control the GSM so it will wake us on demand.
+ * If we do this here, it is considered "auto flowcontrolled",
+ * and we will ensure that we release the flowcontrol on resume.
+ * If the RTS output has already been switched to a GPIO, we'll
+ * assume that something else is in charge, and record that fact
+ * so that we do not release flowcontrol on resume.
+ */
+
+ if (s3c2410_gpio_getcfg(S3C2410_GPH1) == S3C2410_GPIO_OUTPUT)
+ gsm_auto_flowcontrolled = 0;
+ else {
+ s3c2410_gpio_setpin(S3C2410_GPH1, 1);
+ s3c2410_gpio_cfgpin(S3C2410_GPH1, S3C2410_GPH1_OUTP);
+ gsm_auto_flowcontrolled = 1;
+ }
+
return 0;
}
@@ -214,6 +277,12 @@ static int gta01_gsm_resume(struct platf
if (machine_is_neo1973_gta02())
s3c2410_gpio_setpin(GTA02_GPIO_nDL_GSM, gta01_gsm.gpio_ndl_gsm);
+ /* We must defer the auto flowcontrol because we resume before
+ * the serial driver */
+ if (! schedule_work(&gsmwork))
+ dev_err(&pdev->dev,
+ "Unable to schedule GSM wakeup work\n");
+
return 0;
}
#else
@@ -225,6 +294,8 @@ static struct attribute *gta01_gsm_sysfs
&dev_attr_power_on.attr,
&dev_attr_reset.attr,
&dev_attr_download.attr,
+ &dev_attr_autounlock_delay.attr,
+ &dev_attr_flowcontrolled.attr,
NULL
};
@@ -310,6 +381,7 @@ static struct platform_driver gta01_gsm_
static int __devinit gta01_gsm_init(void)
{
+ INIT_WORK(&gsmwork, gsm_resume_work);
return platform_driver_register(>a01_gsm_driver);
}
More information about the openmoko-kernel
mailing list