diff options
author | MyungJoo Ham <myungjoo.ham@samsung.com> | 2010-12-23 03:53:36 -0500 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2011-01-14 06:38:14 -0500 |
commit | cdd137c9c86c201ddb7f42ec978d2da45e7b7a17 (patch) | |
tree | 1fe9850f283a3952b139d2fc113759fbb4fed88c | |
parent | 6680d940b80dbb0617226c5b76b071a3977feb1c (diff) |
mfd: MAX8998/LP3974 hibernation support
This patch makes the driver to save and restore register values
for hibernation.
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r-- | drivers/mfd/max8998-irq.c | 7 | ||||
-rw-r--r-- | drivers/mfd/max8998.c | 108 | ||||
-rw-r--r-- | include/linux/mfd/max8998-private.h | 2 | ||||
-rw-r--r-- | include/linux/mfd/max8998.h | 1 |
4 files changed, 118 insertions, 0 deletions
diff --git a/drivers/mfd/max8998-irq.c b/drivers/mfd/max8998-irq.c index c6b61fcc5808..3903e1fbb334 100644 --- a/drivers/mfd/max8998-irq.c +++ b/drivers/mfd/max8998-irq.c | |||
@@ -183,6 +183,13 @@ static irqreturn_t max8998_irq_thread(int irq, void *data) | |||
183 | return IRQ_HANDLED; | 183 | return IRQ_HANDLED; |
184 | } | 184 | } |
185 | 185 | ||
186 | int max8998_irq_resume(struct max8998_dev *max8998) | ||
187 | { | ||
188 | if (max8998->irq && max8998->irq_base) | ||
189 | max8998_irq_thread(max8998->irq_base, max8998); | ||
190 | return 0; | ||
191 | } | ||
192 | |||
186 | int max8998_irq_init(struct max8998_dev *max8998) | 193 | int max8998_irq_init(struct max8998_dev *max8998) |
187 | { | 194 | { |
188 | int i; | 195 | int i; |
diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c index bb9977bebe78..5ce00ad5241a 100644 --- a/drivers/mfd/max8998.c +++ b/drivers/mfd/max8998.c | |||
@@ -25,6 +25,8 @@ | |||
25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/i2c.h> | 27 | #include <linux/i2c.h> |
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/pm_runtime.h> | ||
28 | #include <linux/mutex.h> | 30 | #include <linux/mutex.h> |
29 | #include <linux/mfd/core.h> | 31 | #include <linux/mfd/core.h> |
30 | #include <linux/mfd/max8998.h> | 32 | #include <linux/mfd/max8998.h> |
@@ -135,6 +137,7 @@ static int max8998_i2c_probe(struct i2c_client *i2c, | |||
135 | if (pdata) { | 137 | if (pdata) { |
136 | max8998->ono = pdata->ono; | 138 | max8998->ono = pdata->ono; |
137 | max8998->irq_base = pdata->irq_base; | 139 | max8998->irq_base = pdata->irq_base; |
140 | max8998->wakeup = pdata->wakeup; | ||
138 | } | 141 | } |
139 | mutex_init(&max8998->iolock); | 142 | mutex_init(&max8998->iolock); |
140 | 143 | ||
@@ -146,6 +149,8 @@ static int max8998_i2c_probe(struct i2c_client *i2c, | |||
146 | ret = mfd_add_devices(max8998->dev, -1, | 149 | ret = mfd_add_devices(max8998->dev, -1, |
147 | max8998_devs, ARRAY_SIZE(max8998_devs), | 150 | max8998_devs, ARRAY_SIZE(max8998_devs), |
148 | NULL, 0); | 151 | NULL, 0); |
152 | pm_runtime_set_active(max8998->dev); | ||
153 | |||
149 | if (ret < 0) | 154 | if (ret < 0) |
150 | goto err; | 155 | goto err; |
151 | 156 | ||
@@ -178,10 +183,113 @@ static const struct i2c_device_id max8998_i2c_id[] = { | |||
178 | }; | 183 | }; |
179 | MODULE_DEVICE_TABLE(i2c, max8998_i2c_id); | 184 | MODULE_DEVICE_TABLE(i2c, max8998_i2c_id); |
180 | 185 | ||
186 | static int max8998_suspend(struct device *dev) | ||
187 | { | ||
188 | struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); | ||
189 | struct max8998_dev *max8998 = i2c_get_clientdata(i2c); | ||
190 | |||
191 | if (max8998->wakeup) | ||
192 | set_irq_wake(max8998->irq, 1); | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | static int max8998_resume(struct device *dev) | ||
197 | { | ||
198 | struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); | ||
199 | struct max8998_dev *max8998 = i2c_get_clientdata(i2c); | ||
200 | |||
201 | if (max8998->wakeup) | ||
202 | set_irq_wake(max8998->irq, 0); | ||
203 | /* | ||
204 | * In LP3974, if IRQ registers are not "read & clear" | ||
205 | * when it's set during sleep, the interrupt becomes | ||
206 | * disabled. | ||
207 | */ | ||
208 | return max8998_irq_resume(i2c_get_clientdata(i2c)); | ||
209 | } | ||
210 | |||
211 | struct max8998_reg_dump { | ||
212 | u8 addr; | ||
213 | u8 val; | ||
214 | }; | ||
215 | #define SAVE_ITEM(x) { .addr = (x), .val = 0x0, } | ||
216 | struct max8998_reg_dump max8998_dump[] = { | ||
217 | SAVE_ITEM(MAX8998_REG_IRQM1), | ||
218 | SAVE_ITEM(MAX8998_REG_IRQM2), | ||
219 | SAVE_ITEM(MAX8998_REG_IRQM3), | ||
220 | SAVE_ITEM(MAX8998_REG_IRQM4), | ||
221 | SAVE_ITEM(MAX8998_REG_STATUSM1), | ||
222 | SAVE_ITEM(MAX8998_REG_STATUSM2), | ||
223 | SAVE_ITEM(MAX8998_REG_CHGR1), | ||
224 | SAVE_ITEM(MAX8998_REG_CHGR2), | ||
225 | SAVE_ITEM(MAX8998_REG_LDO_ACTIVE_DISCHARGE1), | ||
226 | SAVE_ITEM(MAX8998_REG_LDO_ACTIVE_DISCHARGE1), | ||
227 | SAVE_ITEM(MAX8998_REG_BUCK_ACTIVE_DISCHARGE3), | ||
228 | SAVE_ITEM(MAX8998_REG_ONOFF1), | ||
229 | SAVE_ITEM(MAX8998_REG_ONOFF2), | ||
230 | SAVE_ITEM(MAX8998_REG_ONOFF3), | ||
231 | SAVE_ITEM(MAX8998_REG_ONOFF4), | ||
232 | SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE1), | ||
233 | SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE2), | ||
234 | SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE3), | ||
235 | SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE4), | ||
236 | SAVE_ITEM(MAX8998_REG_BUCK2_VOLTAGE1), | ||
237 | SAVE_ITEM(MAX8998_REG_BUCK2_VOLTAGE2), | ||
238 | SAVE_ITEM(MAX8998_REG_LDO2_LDO3), | ||
239 | SAVE_ITEM(MAX8998_REG_LDO4), | ||
240 | SAVE_ITEM(MAX8998_REG_LDO5), | ||
241 | SAVE_ITEM(MAX8998_REG_LDO6), | ||
242 | SAVE_ITEM(MAX8998_REG_LDO7), | ||
243 | SAVE_ITEM(MAX8998_REG_LDO8_LDO9), | ||
244 | SAVE_ITEM(MAX8998_REG_LDO10_LDO11), | ||
245 | SAVE_ITEM(MAX8998_REG_LDO12), | ||
246 | SAVE_ITEM(MAX8998_REG_LDO13), | ||
247 | SAVE_ITEM(MAX8998_REG_LDO14), | ||
248 | SAVE_ITEM(MAX8998_REG_LDO15), | ||
249 | SAVE_ITEM(MAX8998_REG_LDO16), | ||
250 | SAVE_ITEM(MAX8998_REG_LDO17), | ||
251 | SAVE_ITEM(MAX8998_REG_BKCHR), | ||
252 | SAVE_ITEM(MAX8998_REG_LBCNFG1), | ||
253 | SAVE_ITEM(MAX8998_REG_LBCNFG2), | ||
254 | }; | ||
255 | /* Save registers before hibernation */ | ||
256 | static int max8998_freeze(struct device *dev) | ||
257 | { | ||
258 | struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); | ||
259 | int i; | ||
260 | |||
261 | for (i = 0; i < ARRAY_SIZE(max8998_dump); i++) | ||
262 | max8998_read_reg(i2c, max8998_dump[i].addr, | ||
263 | &max8998_dump[i].val); | ||
264 | |||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | /* Restore registers after hibernation */ | ||
269 | static int max8998_restore(struct device *dev) | ||
270 | { | ||
271 | struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); | ||
272 | int i; | ||
273 | |||
274 | for (i = 0; i < ARRAY_SIZE(max8998_dump); i++) | ||
275 | max8998_write_reg(i2c, max8998_dump[i].addr, | ||
276 | max8998_dump[i].val); | ||
277 | |||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | const struct dev_pm_ops max8998_pm = { | ||
282 | .suspend = max8998_suspend, | ||
283 | .resume = max8998_resume, | ||
284 | .freeze = max8998_freeze, | ||
285 | .restore = max8998_restore, | ||
286 | }; | ||
287 | |||
181 | static struct i2c_driver max8998_i2c_driver = { | 288 | static struct i2c_driver max8998_i2c_driver = { |
182 | .driver = { | 289 | .driver = { |
183 | .name = "max8998", | 290 | .name = "max8998", |
184 | .owner = THIS_MODULE, | 291 | .owner = THIS_MODULE, |
292 | .pm = &max8998_pm, | ||
185 | }, | 293 | }, |
186 | .probe = max8998_i2c_probe, | 294 | .probe = max8998_i2c_probe, |
187 | .remove = max8998_i2c_remove, | 295 | .remove = max8998_i2c_remove, |
diff --git a/include/linux/mfd/max8998-private.h b/include/linux/mfd/max8998-private.h index 7363dea6bbcd..effa5d3b96ae 100644 --- a/include/linux/mfd/max8998-private.h +++ b/include/linux/mfd/max8998-private.h | |||
@@ -159,10 +159,12 @@ struct max8998_dev { | |||
159 | u8 irq_masks_cur[MAX8998_NUM_IRQ_REGS]; | 159 | u8 irq_masks_cur[MAX8998_NUM_IRQ_REGS]; |
160 | u8 irq_masks_cache[MAX8998_NUM_IRQ_REGS]; | 160 | u8 irq_masks_cache[MAX8998_NUM_IRQ_REGS]; |
161 | int type; | 161 | int type; |
162 | bool wakeup; | ||
162 | }; | 163 | }; |
163 | 164 | ||
164 | int max8998_irq_init(struct max8998_dev *max8998); | 165 | int max8998_irq_init(struct max8998_dev *max8998); |
165 | void max8998_irq_exit(struct max8998_dev *max8998); | 166 | void max8998_irq_exit(struct max8998_dev *max8998); |
167 | int max8998_irq_resume(struct max8998_dev *max8998); | ||
166 | 168 | ||
167 | extern int max8998_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest); | 169 | extern int max8998_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest); |
168 | extern int max8998_bulk_read(struct i2c_client *i2c, u8 reg, int count, | 170 | extern int max8998_bulk_read(struct i2c_client *i2c, u8 reg, int count, |
diff --git a/include/linux/mfd/max8998.h b/include/linux/mfd/max8998.h index f8c9f884aff2..686a744e63fb 100644 --- a/include/linux/mfd/max8998.h +++ b/include/linux/mfd/max8998.h | |||
@@ -88,6 +88,7 @@ struct max8998_platform_data { | |||
88 | int buck1_set1; | 88 | int buck1_set1; |
89 | int buck1_set2; | 89 | int buck1_set2; |
90 | int buck2_set3; | 90 | int buck2_set3; |
91 | bool wakeup; | ||
91 | }; | 92 | }; |
92 | 93 | ||
93 | #endif /* __LINUX_MFD_MAX8998_H */ | 94 | #endif /* __LINUX_MFD_MAX8998_H */ |