aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/sec-core.c
diff options
context:
space:
mode:
authorKrzysztof Kozlowski <k.kozlowski@samsung.com>2013-11-26 08:50:27 -0500
committerLee Jones <lee.jones@linaro.org>2014-01-21 03:13:35 -0500
commitf6d6daaf9b5260f1769ed040caca53e1c087ca8b (patch)
treeefe07e5525a1192e611584f75b9dfaced6d79df0 /drivers/mfd/sec-core.c
parent192afe5e16054f43113803d6751f567ef2e467ae (diff)
mfd: sec: Add PM ops and make it a wake up source
Add PM suspend/resume ops to the sec MFD core driver and make it a wake up source. This allows proper waking from suspend to RAM and also fixes broken interrupts after resuming: [ 42.705703] sec_pmic 7-0066: Failed to read IRQ status: -5 Interrupts stop working after first resume initiated by them (e.g. by RTC Alarm interrupt) because interrupt registers were not cleared properly. When device is woken up from suspend by RTC Alarm, an interrupt occurs before resuming I2C bus controller. The interrupt is handled by regmap_irq_thread which tries to read RTC registers. This read fails (I2C is still suspended) and RTC Alarm interrupt is disabled. Disable the S5M8767 interrupts during suspend (disable_irq()) and enable them during resume so the device will be still woken up but the interrupt won't happen before resuming I2C bus. Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers/mfd/sec-core.c')
-rw-r--r--drivers/mfd/sec-core.c40
1 files changed, 40 insertions, 0 deletions
diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c
index b31824c33e15..cca0f990d287 100644
--- a/drivers/mfd/sec-core.c
+++ b/drivers/mfd/sec-core.c
@@ -323,6 +323,8 @@ static int sec_pmic_probe(struct i2c_client *i2c,
323 if (ret) 323 if (ret)
324 goto err; 324 goto err;
325 325
326 device_init_wakeup(sec_pmic->dev, sec_pmic->wakeup);
327
326 return ret; 328 return ret;
327 329
328err: 330err:
@@ -341,6 +343,43 @@ static int sec_pmic_remove(struct i2c_client *i2c)
341 return 0; 343 return 0;
342} 344}
343 345
346static int sec_pmic_suspend(struct device *dev)
347{
348 struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
349 struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c);
350
351 if (device_may_wakeup(dev)) {
352 enable_irq_wake(sec_pmic->irq);
353 /*
354 * PMIC IRQ must be disabled during suspend for RTC alarm
355 * to work properly.
356 * When device is woken up from suspend by RTC Alarm, an
357 * interrupt occurs before resuming I2C bus controller.
358 * The interrupt is handled by regmap_irq_thread which tries
359 * to read RTC registers. This read fails (I2C is still
360 * suspended) and RTC Alarm interrupt is disabled.
361 */
362 disable_irq(sec_pmic->irq);
363 }
364
365 return 0;
366}
367
368static int sec_pmic_resume(struct device *dev)
369{
370 struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
371 struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c);
372
373 if (device_may_wakeup(dev)) {
374 disable_irq_wake(sec_pmic->irq);
375 enable_irq(sec_pmic->irq);
376 }
377
378 return 0;
379}
380
381static SIMPLE_DEV_PM_OPS(sec_pmic_pm_ops, sec_pmic_suspend, sec_pmic_resume);
382
344static const struct i2c_device_id sec_pmic_id[] = { 383static const struct i2c_device_id sec_pmic_id[] = {
345 { "sec_pmic", 0 }, 384 { "sec_pmic", 0 },
346 { } 385 { }
@@ -351,6 +390,7 @@ static struct i2c_driver sec_pmic_driver = {
351 .driver = { 390 .driver = {
352 .name = "sec_pmic", 391 .name = "sec_pmic",
353 .owner = THIS_MODULE, 392 .owner = THIS_MODULE,
393 .pm = &sec_pmic_pm_ops,
354 .of_match_table = of_match_ptr(sec_dt_match), 394 .of_match_table = of_match_ptr(sec_dt_match),
355 }, 395 },
356 .probe = sec_pmic_probe, 396 .probe = sec_pmic_probe,