diff options
author | Wang Dongsheng <dongsheng.wang@freescale.com> | 2014-04-03 17:50:08 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-03 19:21:22 -0400 |
commit | c93a3ae2d213ff75a279fe6e28d8f41ca7f01483 (patch) | |
tree | 49c5761171306c5ccd4bb5803f0fe189f32ef93c /drivers/rtc/rtc-ds3232.c | |
parent | 3f93822d36fc8413658a67f5fb853bbe1b2a1f4d (diff) |
drivers/rtc/rtc-ds3232.c: enable ds3232 to work as wakeup source
Add suspend/resume and device_init_wakeup to enable ds3232 as wakeup
source, /sys/class/rtc/rtcX/wakealarm for set wakeup alarm.
Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rtc/rtc-ds3232.c')
-rw-r--r-- | drivers/rtc/rtc-ds3232.c | 94 |
1 files changed, 70 insertions, 24 deletions
diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 813c6aa70d3d..adaf06c41479 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c | |||
@@ -57,6 +57,7 @@ struct ds3232 { | |||
57 | * in the remove function. | 57 | * in the remove function. |
58 | */ | 58 | */ |
59 | struct mutex mutex; | 59 | struct mutex mutex; |
60 | bool suspended; | ||
60 | int exiting; | 61 | int exiting; |
61 | }; | 62 | }; |
62 | 63 | ||
@@ -345,7 +346,15 @@ static irqreturn_t ds3232_irq(int irq, void *dev_id) | |||
345 | struct ds3232 *ds3232 = i2c_get_clientdata(client); | 346 | struct ds3232 *ds3232 = i2c_get_clientdata(client); |
346 | 347 | ||
347 | disable_irq_nosync(irq); | 348 | disable_irq_nosync(irq); |
348 | schedule_work(&ds3232->work); | 349 | |
350 | /* | ||
351 | * If rtc as a wakeup source, can't schedule the work | ||
352 | * at system resume flow, because at this time the i2c bus | ||
353 | * has not been resumed. | ||
354 | */ | ||
355 | if (!ds3232->suspended) | ||
356 | schedule_work(&ds3232->work); | ||
357 | |||
349 | return IRQ_HANDLED; | 358 | return IRQ_HANDLED; |
350 | } | 359 | } |
351 | 360 | ||
@@ -363,22 +372,26 @@ static void ds3232_work(struct work_struct *work) | |||
363 | 372 | ||
364 | if (stat & DS3232_REG_SR_A1F) { | 373 | if (stat & DS3232_REG_SR_A1F) { |
365 | control = i2c_smbus_read_byte_data(client, DS3232_REG_CR); | 374 | control = i2c_smbus_read_byte_data(client, DS3232_REG_CR); |
366 | if (control < 0) | 375 | if (control < 0) { |
367 | goto out; | 376 | pr_warn("Read DS3232 Control Register error." |
368 | /* disable alarm1 interrupt */ | 377 | "Disable IRQ%d.\n", client->irq); |
369 | control &= ~(DS3232_REG_CR_A1IE); | 378 | } else { |
370 | i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); | 379 | /* disable alarm1 interrupt */ |
371 | 380 | control &= ~(DS3232_REG_CR_A1IE); | |
372 | /* clear the alarm pend flag */ | 381 | i2c_smbus_write_byte_data(client, DS3232_REG_CR, |
373 | stat &= ~DS3232_REG_SR_A1F; | 382 | control); |
374 | i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); | 383 | |
375 | 384 | /* clear the alarm pend flag */ | |
376 | rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF); | 385 | stat &= ~DS3232_REG_SR_A1F; |
386 | i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); | ||
387 | |||
388 | rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF); | ||
389 | |||
390 | if (!ds3232->exiting) | ||
391 | enable_irq(client->irq); | ||
392 | } | ||
377 | } | 393 | } |
378 | 394 | ||
379 | out: | ||
380 | if (!ds3232->exiting) | ||
381 | enable_irq(client->irq); | ||
382 | unlock: | 395 | unlock: |
383 | mutex_unlock(&ds3232->mutex); | 396 | mutex_unlock(&ds3232->mutex); |
384 | } | 397 | } |
@@ -411,21 +424,17 @@ static int ds3232_probe(struct i2c_client *client, | |||
411 | if (ret) | 424 | if (ret) |
412 | return ret; | 425 | return ret; |
413 | 426 | ||
414 | ds3232->rtc = devm_rtc_device_register(&client->dev, client->name, | 427 | if (client->irq > 0) { |
415 | &ds3232_rtc_ops, THIS_MODULE); | ||
416 | if (IS_ERR(ds3232->rtc)) { | ||
417 | return PTR_ERR(ds3232->rtc); | ||
418 | } | ||
419 | |||
420 | if (client->irq >= 0) { | ||
421 | ret = devm_request_irq(&client->dev, client->irq, ds3232_irq, | 428 | ret = devm_request_irq(&client->dev, client->irq, ds3232_irq, |
422 | IRQF_SHARED, "ds3232", client); | 429 | IRQF_SHARED, "ds3232", client); |
423 | if (ret) { | 430 | if (ret) { |
424 | dev_err(&client->dev, "unable to request IRQ\n"); | 431 | dev_err(&client->dev, "unable to request IRQ\n"); |
425 | } | 432 | } |
433 | device_init_wakeup(&client->dev, 1); | ||
426 | } | 434 | } |
427 | 435 | ds3232->rtc = devm_rtc_device_register(&client->dev, client->name, | |
428 | return 0; | 436 | &ds3232_rtc_ops, THIS_MODULE); |
437 | return PTR_ERR_OR_ZERO(ds3232->rtc); | ||
429 | } | 438 | } |
430 | 439 | ||
431 | static int ds3232_remove(struct i2c_client *client) | 440 | static int ds3232_remove(struct i2c_client *client) |
@@ -444,6 +453,42 @@ static int ds3232_remove(struct i2c_client *client) | |||
444 | return 0; | 453 | return 0; |
445 | } | 454 | } |
446 | 455 | ||
456 | #ifdef CONFIG_PM_SLEEP | ||
457 | static int ds3232_suspend(struct device *dev) | ||
458 | { | ||
459 | struct ds3232 *ds3232 = dev_get_drvdata(dev); | ||
460 | struct i2c_client *client = to_i2c_client(dev); | ||
461 | |||
462 | if (device_can_wakeup(dev)) { | ||
463 | ds3232->suspended = true; | ||
464 | irq_set_irq_wake(client->irq, 1); | ||
465 | } | ||
466 | |||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | static int ds3232_resume(struct device *dev) | ||
471 | { | ||
472 | struct ds3232 *ds3232 = dev_get_drvdata(dev); | ||
473 | struct i2c_client *client = to_i2c_client(dev); | ||
474 | |||
475 | if (ds3232->suspended) { | ||
476 | ds3232->suspended = false; | ||
477 | |||
478 | /* Clear the hardware alarm pend flag */ | ||
479 | schedule_work(&ds3232->work); | ||
480 | |||
481 | irq_set_irq_wake(client->irq, 0); | ||
482 | } | ||
483 | |||
484 | return 0; | ||
485 | } | ||
486 | #endif | ||
487 | |||
488 | static const struct dev_pm_ops ds3232_pm_ops = { | ||
489 | SET_SYSTEM_SLEEP_PM_OPS(ds3232_suspend, ds3232_resume) | ||
490 | }; | ||
491 | |||
447 | static const struct i2c_device_id ds3232_id[] = { | 492 | static const struct i2c_device_id ds3232_id[] = { |
448 | { "ds3232", 0 }, | 493 | { "ds3232", 0 }, |
449 | { } | 494 | { } |
@@ -454,6 +499,7 @@ static struct i2c_driver ds3232_driver = { | |||
454 | .driver = { | 499 | .driver = { |
455 | .name = "rtc-ds3232", | 500 | .name = "rtc-ds3232", |
456 | .owner = THIS_MODULE, | 501 | .owner = THIS_MODULE, |
502 | .pm = &ds3232_pm_ops, | ||
457 | }, | 503 | }, |
458 | .probe = ds3232_probe, | 504 | .probe = ds3232_probe, |
459 | .remove = ds3232_remove, | 505 | .remove = ds3232_remove, |