Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

MyungJoo Ham and committed by
Samuel Ortiz
cdd137c9 6680d940

+118
+7
drivers/mfd/max8998-irq.c
··· 183 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 193 int max8998_irq_init(struct max8998_dev *max8998) 187 194 { 188 195 int i;
+108
drivers/mfd/max8998.c
··· 25 25 #include <linux/init.h> 26 26 #include <linux/slab.h> 27 27 #include <linux/i2c.h> 28 + #include <linux/interrupt.h> 29 + #include <linux/pm_runtime.h> 28 30 #include <linux/mutex.h> 29 31 #include <linux/mfd/core.h> 30 32 #include <linux/mfd/max8998.h> ··· 137 135 if (pdata) { 138 136 max8998->ono = pdata->ono; 139 137 max8998->irq_base = pdata->irq_base; 138 + max8998->wakeup = pdata->wakeup; 140 139 } 141 140 mutex_init(&max8998->iolock); 142 141 ··· 149 146 ret = mfd_add_devices(max8998->dev, -1, 150 147 max8998_devs, ARRAY_SIZE(max8998_devs), 151 148 NULL, 0); 149 + pm_runtime_set_active(max8998->dev); 150 + 152 151 if (ret < 0) 153 152 goto err; 154 153 ··· 183 178 }; 184 179 MODULE_DEVICE_TABLE(i2c, max8998_i2c_id); 185 180 181 + static int max8998_suspend(struct device *dev) 182 + { 183 + struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); 184 + struct max8998_dev *max8998 = i2c_get_clientdata(i2c); 185 + 186 + if (max8998->wakeup) 187 + set_irq_wake(max8998->irq, 1); 188 + return 0; 189 + } 190 + 191 + static int max8998_resume(struct device *dev) 192 + { 193 + struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); 194 + struct max8998_dev *max8998 = i2c_get_clientdata(i2c); 195 + 196 + if (max8998->wakeup) 197 + set_irq_wake(max8998->irq, 0); 198 + /* 199 + * In LP3974, if IRQ registers are not "read & clear" 200 + * when it's set during sleep, the interrupt becomes 201 + * disabled. 202 + */ 203 + return max8998_irq_resume(i2c_get_clientdata(i2c)); 204 + } 205 + 206 + struct max8998_reg_dump { 207 + u8 addr; 208 + u8 val; 209 + }; 210 + #define SAVE_ITEM(x) { .addr = (x), .val = 0x0, } 211 + struct max8998_reg_dump max8998_dump[] = { 212 + SAVE_ITEM(MAX8998_REG_IRQM1), 213 + SAVE_ITEM(MAX8998_REG_IRQM2), 214 + SAVE_ITEM(MAX8998_REG_IRQM3), 215 + SAVE_ITEM(MAX8998_REG_IRQM4), 216 + SAVE_ITEM(MAX8998_REG_STATUSM1), 217 + SAVE_ITEM(MAX8998_REG_STATUSM2), 218 + SAVE_ITEM(MAX8998_REG_CHGR1), 219 + SAVE_ITEM(MAX8998_REG_CHGR2), 220 + SAVE_ITEM(MAX8998_REG_LDO_ACTIVE_DISCHARGE1), 221 + SAVE_ITEM(MAX8998_REG_LDO_ACTIVE_DISCHARGE1), 222 + SAVE_ITEM(MAX8998_REG_BUCK_ACTIVE_DISCHARGE3), 223 + SAVE_ITEM(MAX8998_REG_ONOFF1), 224 + SAVE_ITEM(MAX8998_REG_ONOFF2), 225 + SAVE_ITEM(MAX8998_REG_ONOFF3), 226 + SAVE_ITEM(MAX8998_REG_ONOFF4), 227 + SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE1), 228 + SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE2), 229 + SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE3), 230 + SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE4), 231 + SAVE_ITEM(MAX8998_REG_BUCK2_VOLTAGE1), 232 + SAVE_ITEM(MAX8998_REG_BUCK2_VOLTAGE2), 233 + SAVE_ITEM(MAX8998_REG_LDO2_LDO3), 234 + SAVE_ITEM(MAX8998_REG_LDO4), 235 + SAVE_ITEM(MAX8998_REG_LDO5), 236 + SAVE_ITEM(MAX8998_REG_LDO6), 237 + SAVE_ITEM(MAX8998_REG_LDO7), 238 + SAVE_ITEM(MAX8998_REG_LDO8_LDO9), 239 + SAVE_ITEM(MAX8998_REG_LDO10_LDO11), 240 + SAVE_ITEM(MAX8998_REG_LDO12), 241 + SAVE_ITEM(MAX8998_REG_LDO13), 242 + SAVE_ITEM(MAX8998_REG_LDO14), 243 + SAVE_ITEM(MAX8998_REG_LDO15), 244 + SAVE_ITEM(MAX8998_REG_LDO16), 245 + SAVE_ITEM(MAX8998_REG_LDO17), 246 + SAVE_ITEM(MAX8998_REG_BKCHR), 247 + SAVE_ITEM(MAX8998_REG_LBCNFG1), 248 + SAVE_ITEM(MAX8998_REG_LBCNFG2), 249 + }; 250 + /* Save registers before hibernation */ 251 + static int max8998_freeze(struct device *dev) 252 + { 253 + struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); 254 + int i; 255 + 256 + for (i = 0; i < ARRAY_SIZE(max8998_dump); i++) 257 + max8998_read_reg(i2c, max8998_dump[i].addr, 258 + &max8998_dump[i].val); 259 + 260 + return 0; 261 + } 262 + 263 + /* Restore registers after hibernation */ 264 + static int max8998_restore(struct device *dev) 265 + { 266 + struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); 267 + int i; 268 + 269 + for (i = 0; i < ARRAY_SIZE(max8998_dump); i++) 270 + max8998_write_reg(i2c, max8998_dump[i].addr, 271 + max8998_dump[i].val); 272 + 273 + return 0; 274 + } 275 + 276 + const struct dev_pm_ops max8998_pm = { 277 + .suspend = max8998_suspend, 278 + .resume = max8998_resume, 279 + .freeze = max8998_freeze, 280 + .restore = max8998_restore, 281 + }; 282 + 186 283 static struct i2c_driver max8998_i2c_driver = { 187 284 .driver = { 188 285 .name = "max8998", 189 286 .owner = THIS_MODULE, 287 + .pm = &max8998_pm, 190 288 }, 191 289 .probe = max8998_i2c_probe, 192 290 .remove = max8998_i2c_remove,
+2
include/linux/mfd/max8998-private.h
··· 159 159 u8 irq_masks_cur[MAX8998_NUM_IRQ_REGS]; 160 160 u8 irq_masks_cache[MAX8998_NUM_IRQ_REGS]; 161 161 int type; 162 + bool wakeup; 162 163 }; 163 164 164 165 int max8998_irq_init(struct max8998_dev *max8998); 165 166 void max8998_irq_exit(struct max8998_dev *max8998); 167 + int max8998_irq_resume(struct max8998_dev *max8998); 166 168 167 169 extern int max8998_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest); 168 170 extern int max8998_bulk_read(struct i2c_client *i2c, u8 reg, int count,
+1
include/linux/mfd/max8998.h
··· 88 88 int buck1_set1; 89 89 int buck1_set2; 90 90 int buck2_set3; 91 + bool wakeup; 91 92 }; 92 93 93 94 #endif /* __LINUX_MFD_MAX8998_H */