1 From dd7ff306b150c36950fa0f9dd718a1745a984d38 Mon Sep 17 00:00:00 2001
2 From: Andy Green <andy@openmoko.com>
3 Date: Wed, 2 Jul 2008 22:41:38 +0100
4 Subject: [PATCH] fix-pcf50633-suspend-state-as-enum.patch
6 Use an enum to define pcf50633 suspend / resume state.
7 Add PCF50633_SS_RESUMING_BUT_NOT_US_YET to be the state
8 early in resume: add platform driver resume function just
9 to set this state so we can differentiate between early
10 resume and late suspend.
12 Signed-off-by: Andy Green <andy@openmoko.com>
14 drivers/i2c/chips/pcf50633.c | 73 ++++++++++++++++++++++++++++++++++--------
15 1 files changed, 59 insertions(+), 14 deletions(-)
17 diff --git a/drivers/i2c/chips/pcf50633.c b/drivers/i2c/chips/pcf50633.c
18 index 2e5981d..c014384 100644
19 --- a/drivers/i2c/chips/pcf50633.c
20 +++ b/drivers/i2c/chips/pcf50633.c
21 @@ -108,6 +108,16 @@ enum charger_type {
23 #define MAX_ADC_FIFO_DEPTH 8
25 +enum pcf50633_suspend_states {
26 + PCF50633_SS_RUNNING,
27 + PCF50633_SS_STARTING_SUSPEND,
28 + PCF50633_SS_COMPLETED_SUSPEND,
29 + PCF50633_SS_RESUMING_BUT_NOT_US_YET,
30 + PCF50633_SS_STARTING_RESUME,
31 + PCF50633_SS_COMPLETED_RESUME,
35 struct pcf50633_data {
36 struct i2c_client client;
37 struct pcf50633_platform_data *pdata;
38 @@ -122,9 +132,9 @@ struct pcf50633_data {
42 - int have_been_suspended;
43 + enum pcf50633_suspend_states suspend_state;
44 int usb_removal_count;
45 - unsigned char pcfirq_resume[5];
46 + u8 pcfirq_resume[5];
49 /* if he pulls battery while charging, we notice that and correctly
50 @@ -191,7 +201,7 @@ static struct platform_device *pcf50633_pdev;
52 static int __reg_write(struct pcf50633_data *pcf, u_int8_t reg, u_int8_t val)
54 - if (pcf->have_been_suspended == 1) {
55 + if (pcf->suspend_state == PCF50633_SS_COMPLETED_SUSPEND) {
56 dev_err(&pcf->client.dev, "__reg_write while suspended\n");
59 @@ -213,7 +223,7 @@ static int32_t __reg_read(struct pcf50633_data *pcf, u_int8_t reg)
63 - if (pcf->have_been_suspended == 1) {
64 + if (pcf->suspend_state == PCF50633_SS_COMPLETED_SUSPEND) {
65 dev_err(&pcf->client.dev, "__reg_read while suspended\n");
68 @@ -630,7 +640,8 @@ static void pcf50633_work_usbcurlim(struct work_struct *work)
69 /* we got a notification from USB stack before we completed resume...
70 * that can only make trouble, reschedule for a retry
72 - if (pcf->have_been_suspended && (pcf->have_been_suspended < 3))
73 + if (pcf->suspend_state &&
74 + (pcf->suspend_state < PCF50633_SS_COMPLETED_RESUME))
78 @@ -751,6 +762,21 @@ static void pcf50633_work(struct work_struct *work)
82 + * if we are presently suspending, we are not in a position to deal
83 + * with pcf50633 interrupts at all.
85 + * Because we didn't clear the int pending registers, there will be
86 + * no edge / interrupt waiting for us when we wake. But it is OK
87 + * because at the end of our resume, we call this workqueue function
88 + * gratuitously, clearing the pending register and re-enabling
89 + * servicing this interrupt.
92 + if ((pcf->suspend_state == PCF50633_SS_STARTING_SUSPEND) ||
93 + (pcf->suspend_state == PCF50633_SS_COMPLETED_SUSPEND))
97 * If we are inside suspend -> resume completion time we don't attempt
98 * service until we have fully resumed. Although we could talk to the
99 * device as soon as I2C is up, the regs in the device which we might
100 @@ -1155,8 +1181,9 @@ reschedule:
101 /* EXCEPTION: if we are in the middle of suspending, we don't have
102 * time to hang around since we may be turned off core 1V3 already
104 - if (pcf->have_been_suspended != 1) {
106 + if ((pcf->suspend_state != PCF50633_SS_STARTING_SUSPEND) &&
107 + (pcf->suspend_state != PCF50633_SS_COMPLETED_SUSPEND)) {
109 dev_info(&pcf->client.dev, "rescheduling interrupt service\n");
111 if (!schedule_work(&pcf->work))
112 @@ -2322,8 +2349,9 @@ static int pcf50633_suspend(struct device *dev, pm_message_t state)
114 /* we suspend once (!) as late as possible in the suspend sequencing */
116 - if ((state.event != PM_EVENT_SUSPEND) || (pcf->have_been_suspended))
118 + if ((state.event != PM_EVENT_SUSPEND) ||
119 + (pcf->suspend_state != PCF50633_SS_RUNNING))
122 /* The general idea is to power down all unused power supplies,
123 * and then mask all PCF50633 interrupt sources but EXTONR, ONKEYF
124 @@ -2387,7 +2415,7 @@ static int pcf50633_suspend(struct device *dev, pm_message_t state)
126 dev_err(dev, "Failed to set wake masks :-( %d\n", ret);
128 - pcf->have_been_suspended = 1;
129 + pcf->suspend_state = PCF50633_SS_COMPLETED_SUSPEND;
131 mutex_unlock(&pcf->lock);
133 @@ -2400,7 +2428,8 @@ int pcf50633_ready(struct pcf50633_data *pcf)
137 - if (pcf->have_been_suspended && (pcf->have_been_suspended < 3))
138 + if ((pcf->suspend_state != PCF50633_SS_RUNNING) &&
139 + (pcf->suspend_state < PCF50633_SS_COMPLETED_RESUME))
143 @@ -2435,10 +2464,10 @@ static int pcf50633_resume(struct device *dev)
146 dev_info(dev, "pcf50633_resume suspended on entry = %d\n",
147 - pcf->have_been_suspended);
148 + (int)pcf->suspend_state);
149 mutex_lock(&pcf->lock);
151 - pcf->have_been_suspended = 2; /* resuming */
152 + pcf->suspend_state = PCF50633_SS_STARTING_RESUME;
154 /* these guys get reset while pcf50633 is suspend state, refresh */
156 @@ -2471,7 +2500,7 @@ static int pcf50633_resume(struct device *dev)
158 dev_err(dev, "Failed to set int masks :-( %d\n", ret);
160 - pcf->have_been_suspended = 3; /* resume completed */
161 + pcf->suspend_state = PCF50633_SS_COMPLETED_RESUME;
163 mutex_unlock(&pcf->lock);
165 @@ -2505,6 +2534,21 @@ static struct i2c_driver pcf50633_driver = {
166 .detach_client = pcf50633_detach_client,
169 +/* we have this purely to capture an early indication that we are coming out
170 + * of suspend, before our device resume got called; async interrupt service is
171 + * interested in this
174 +static int pcf50633_plat_resume(struct platform_device *pdev)
176 + /* i2c_get_clientdata(to_i2c_client(&pdev->dev)) returns NULL at this
177 + * early resume time so we have to use pcf50633_global
179 + pcf50633_global->suspend_state = PCF50633_SS_RESUMING_BUT_NOT_US_YET;
184 /* platform driver, since i2c devices don't have platform_data */
185 static int __init pcf50633_plat_probe(struct platform_device *pdev)
187 @@ -2526,6 +2570,7 @@ static int pcf50633_plat_remove(struct platform_device *pdev)
188 static struct platform_driver pcf50633_plat_driver = {
189 .probe = pcf50633_plat_probe,
190 .remove = pcf50633_plat_remove,
191 + .resume_early = pcf50633_plat_resume,
193 .owner = THIS_MODULE,