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(&gta01_gsm_driver);
  }





More information about the openmoko-kernel mailing list