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

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>

authored by

Wang Dongsheng and committed by
Linus Torvalds
c93a3ae2 3f93822d

+68 -22
+68 -22
drivers/rtc/rtc-ds3232.c
··· 57 57 * in the remove function. 58 58 */ 59 59 struct mutex mutex; 60 + bool suspended; 60 61 int exiting; 61 62 }; 62 63 ··· 346 345 struct ds3232 *ds3232 = i2c_get_clientdata(client); 347 346 348 347 disable_irq_nosync(irq); 349 - schedule_work(&ds3232->work); 348 + 349 + /* 350 + * If rtc as a wakeup source, can't schedule the work 351 + * at system resume flow, because at this time the i2c bus 352 + * has not been resumed. 353 + */ 354 + if (!ds3232->suspended) 355 + schedule_work(&ds3232->work); 356 + 350 357 return IRQ_HANDLED; 351 358 } 352 359 ··· 372 363 373 364 if (stat & DS3232_REG_SR_A1F) { 374 365 control = i2c_smbus_read_byte_data(client, DS3232_REG_CR); 375 - if (control < 0) 376 - goto out; 377 - /* disable alarm1 interrupt */ 378 - control &= ~(DS3232_REG_CR_A1IE); 379 - i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); 366 + if (control < 0) { 367 + pr_warn("Read DS3232 Control Register error." 368 + "Disable IRQ%d.\n", client->irq); 369 + } else { 370 + /* disable alarm1 interrupt */ 371 + control &= ~(DS3232_REG_CR_A1IE); 372 + i2c_smbus_write_byte_data(client, DS3232_REG_CR, 373 + control); 380 374 381 - /* clear the alarm pend flag */ 382 - stat &= ~DS3232_REG_SR_A1F; 383 - i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); 375 + /* clear the alarm pend flag */ 376 + stat &= ~DS3232_REG_SR_A1F; 377 + i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); 384 378 385 - rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF); 379 + rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF); 380 + 381 + if (!ds3232->exiting) 382 + enable_irq(client->irq); 383 + } 386 384 } 387 385 388 - out: 389 - if (!ds3232->exiting) 390 - enable_irq(client->irq); 391 386 unlock: 392 387 mutex_unlock(&ds3232->mutex); 393 388 } ··· 424 411 if (ret) 425 412 return ret; 426 413 427 - ds3232->rtc = devm_rtc_device_register(&client->dev, client->name, 428 - &ds3232_rtc_ops, THIS_MODULE); 429 - if (IS_ERR(ds3232->rtc)) { 430 - return PTR_ERR(ds3232->rtc); 431 - } 432 - 433 - if (client->irq >= 0) { 414 + if (client->irq > 0) { 434 415 ret = devm_request_irq(&client->dev, client->irq, ds3232_irq, 435 416 IRQF_SHARED, "ds3232", client); 436 417 if (ret) { 437 418 dev_err(&client->dev, "unable to request IRQ\n"); 438 419 } 420 + device_init_wakeup(&client->dev, 1); 439 421 } 440 - 441 - return 0; 422 + ds3232->rtc = devm_rtc_device_register(&client->dev, client->name, 423 + &ds3232_rtc_ops, THIS_MODULE); 424 + return PTR_ERR_OR_ZERO(ds3232->rtc); 442 425 } 443 426 444 427 static int ds3232_remove(struct i2c_client *client) ··· 453 444 return 0; 454 445 } 455 446 447 + #ifdef CONFIG_PM_SLEEP 448 + static int ds3232_suspend(struct device *dev) 449 + { 450 + struct ds3232 *ds3232 = dev_get_drvdata(dev); 451 + struct i2c_client *client = to_i2c_client(dev); 452 + 453 + if (device_can_wakeup(dev)) { 454 + ds3232->suspended = true; 455 + irq_set_irq_wake(client->irq, 1); 456 + } 457 + 458 + return 0; 459 + } 460 + 461 + static int ds3232_resume(struct device *dev) 462 + { 463 + struct ds3232 *ds3232 = dev_get_drvdata(dev); 464 + struct i2c_client *client = to_i2c_client(dev); 465 + 466 + if (ds3232->suspended) { 467 + ds3232->suspended = false; 468 + 469 + /* Clear the hardware alarm pend flag */ 470 + schedule_work(&ds3232->work); 471 + 472 + irq_set_irq_wake(client->irq, 0); 473 + } 474 + 475 + return 0; 476 + } 477 + #endif 478 + 479 + static const struct dev_pm_ops ds3232_pm_ops = { 480 + SET_SYSTEM_SLEEP_PM_OPS(ds3232_suspend, ds3232_resume) 481 + }; 482 + 456 483 static const struct i2c_device_id ds3232_id[] = { 457 484 { "ds3232", 0 }, 458 485 { } ··· 499 454 .driver = { 500 455 .name = "rtc-ds3232", 501 456 .owner = THIS_MODULE, 457 + .pm = &ds3232_pm_ops, 502 458 }, 503 459 .probe = ds3232_probe, 504 460 .remove = ds3232_remove,