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 */ |
