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);
}