changed Makefile and profiles, added patches for kernel 2.6.24
[openwrt.git] / target / linux / s3c24xx / patches-2.6.26 / 0164-fix-pcf50633-interrupt-work-enforce-wait-on-resume-c.patch
1 From 3cb0a576425bdd2cb9b8f48f9fe39c01dfc18bbf Mon Sep 17 00:00:00 2001
2 From: Andy Green <andy@openmoko.com>
3 Date: Fri, 25 Jul 2008 23:06:12 +0100
4 Subject: [PATCH] fix-pcf50633-interrupt-work-enforce-wait-on-resume-completion.patch
5
6 Improve pcf50633 interrupt service scheduling to enforce only servicing
7 when resume action is completed
8
9 Signed-off-by: Andy Green <andy@openmoko.com>
10 ---
11  drivers/i2c/chips/pcf50633.c |   67 ++++++++++++++++++++++++++++++------------
12  1 files changed, 48 insertions(+), 19 deletions(-)
13
14 diff --git a/drivers/i2c/chips/pcf50633.c b/drivers/i2c/chips/pcf50633.c
15 index 82ee2f0..5c9d209 100644
16 --- a/drivers/i2c/chips/pcf50633.c
17 +++ b/drivers/i2c/chips/pcf50633.c
18 @@ -656,6 +656,26 @@ static void pcf50633_work(struct work_struct *work)
19  
20         mutex_lock(&pcf->working_lock);
21         pcf->working = 1;
22 +
23 +       dev_info(&pcf->client.dev, "pcf50633_work called with suspended = %d\n",
24 +                                  pcf->have_been_suspended);
25 +
26 +       /*
27 +        * If we are inside suspend -> resume completion time we don't attempt
28 +        * service until we have fully resumed.  Although we could talk to the
29 +        * device as soon as I2C is up, the regs in the device which we might
30 +        * choose to modify as part of the service action have not been
31 +        * reloaded with their pre-suspend states yet.  Therefore we will
32 +        * defer our service if we are called like that until our resume has
33 +        * completed.
34 +        */
35 +
36 +       if (pcf->have_been_suspended && (pcf->have_been_suspended < 2)) {
37 +               dev_info(&pcf->client.dev, "rescheduling,  suspended = %d\n",
38 +                                          pcf->have_been_suspended);
39 +               goto reschedule;
40 +       }
41 +
42         /*
43          * datasheet says we have to read the five IRQ
44          * status regs in one transaction
45 @@ -663,30 +683,25 @@ static void pcf50633_work(struct work_struct *work)
46         ret = i2c_smbus_read_i2c_block_data(&pcf->client, PCF50633_REG_INT1, 5,
47                                             pcfirq);
48         if (ret != 5) {
49 -               DEBUGP("Oh crap PMU IRQ register read failed -- "
50 -                      "retrying later %d\n", ret);
51 +               dev_info(&pcf->client.dev,
52 +                        "Oh crap PMU IRQ register read failed -- "
53 +                        "retrying later %d\n", ret);
54                 /*
55 -                * this situation can happen during resume, just defer
56 -                * handling the interrupt until enough I2C is up we can
57 -                * actually talk to the PMU.  We can't just ignore this
58 -                * because we are on a falling edge interrupt and our
59 -                * PMU interrupt source does not clear until we read these
60 -                * interrupt source registers.
61 +                * it shouldn't fail, we no longer attempt to use I2C while
62 +                * it can be suspended.  But we don't have much option but to
63 +                * retry if if it ever did fail, because if we don't service
64 +                * the interrupt to clear it, we will never see another PMU
65 +                * interrupt edge.
66                  */
67 -               if (!schedule_work(&pcf->work) && !pcf->working)
68 -                       dev_dbg(&pcf->client.dev, "work item may be lost\n");
69 -
70 -               /* we don't put the device here, hold it for next time */
71 -               mutex_unlock(&pcf->working_lock);
72 -               /* don't spew, delaying whatever else is happening */
73 -               msleep(1);
74 -               return;
75 +               goto reschedule;
76         }
77  
78         /* hey did we just resume? */
79  
80         if (pcf->have_been_suspended) {
81 +               /* resume is officially over now then */
82                 pcf->have_been_suspended = 0;
83 +
84                 /*
85                  * grab a copy of resume interrupt reasons
86                  * from pcf50633 POV
87 @@ -1044,6 +1059,19 @@ static void pcf50633_work(struct work_struct *work)
88         input_sync(pcf->input_dev);
89         put_device(&pcf->client.dev);
90         mutex_unlock(&pcf->working_lock);
91 +
92 +       return;
93 +
94 +reschedule:
95 +       /* don't spew, delaying whatever else is happening */
96 +       msleep(100);
97 +
98 +       dev_info(&pcf->client.dev, "rescheduling interrupt service\n");
99 +       if (!schedule_work(&pcf->work))
100 +               dev_err(&pcf->client.dev, "int service reschedule failed\n");
101 +
102 +       /* we don't put the device here, hold it for next time */
103 +       mutex_unlock(&pcf->working_lock);
104  }
105  
106  static irqreturn_t pcf50633_irq(int irq, void *_pcf)
107 @@ -1051,10 +1079,11 @@ static irqreturn_t pcf50633_irq(int irq, void *_pcf)
108         struct pcf50633_data *pcf = _pcf;
109  
110         DEBUGP("entering(irq=%u, pcf=%p): scheduling work\n", irq, _pcf);
111 +       dev_info(&pcf->client.dev, "pcf50633_irq scheduling work\n");
112  
113         get_device(&pcf->client.dev);
114         if (!schedule_work(&pcf->work) && !pcf->working)
115 -               dev_dbg(&pcf->client.dev, "work item may be lost\n");
116 +               dev_err(&pcf->client.dev, "work item may be lost\n");
117  
118         return IRQ_HANDLED;
119  }
120 @@ -2234,9 +2263,9 @@ static int pcf50633_suspend(struct device *dev, pm_message_t state)
121  int pcf50633_ready(struct pcf50633_data *pcf)
122  {
123         if (!pcf)
124 -               return -EBUSY;
125 +               return -EACCES;
126  
127 -       if (pcf->have_been_suspended)
128 +       if (pcf->have_been_suspended && (pcf->have_been_suspended < 3))
129                 return -EBUSY;
130  
131         return 0;
132 -- 
133 1.5.6.3
134