nuke obsolete kernel stuff
[openwrt/staging/dedeckeh.git] / target / linux / s3c24xx / patches-2.6.26 / 1243-gta01-pcf50606-disable-irq-from-suspend-until-resume.patch
diff --git a/target/linux/s3c24xx/patches-2.6.26/1243-gta01-pcf50606-disable-irq-from-suspend-until-resume.patch b/target/linux/s3c24xx/patches-2.6.26/1243-gta01-pcf50606-disable-irq-from-suspend-until-resume.patch
deleted file mode 100755 (executable)
index 8f5550f..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-From b4976aa135000ce1d4804bf9fbfa92280cd357e7 Mon Sep 17 00:00:00 2001
-From: Mike Westerhof <mwester@dls.net>
-Date: Sun, 10 Aug 2008 09:13:31 +0100
-Subject: [PATCH] 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 <mwester@dls.net>
----
- drivers/i2c/chips/pcf50606.c |  148 ++++++++++++++++++++++++++++++++++++++++--
- 1 files changed, 142 insertions(+), 6 deletions(-)
-
-diff --git a/drivers/i2c/chips/pcf50606.c b/drivers/i2c/chips/pcf50606.c
-index c97cad3..19a9829 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;
- }
-@@ -1881,12 +1975,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);
-@@ -1927,6 +2036,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;
-@@ -1939,6 +2050,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);
-@@ -1957,10 +2070,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;
- }
-@@ -1998,9 +2118,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",
--- 
-1.5.6.3
-