diff options
author | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2014-04-14 12:00:36 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2014-04-14 12:00:36 -0300 |
commit | 277a163c83d7ba93fba1e8980d29a9f8bfcfba6c (patch) | |
tree | ccfd357d152292958957b6b8a993892e7a8cc95f /drivers/rtc/rtc-ds3232.c | |
parent | a83b93a7480441a47856dc9104bea970e84cda87 (diff) | |
parent | c9eaa447e77efe77b7fa4c953bd62de8297fd6c5 (diff) |
Merge tag 'v3.15-rc1' into patchwork
Linux 3.15-rc1
* tag 'v3.15-rc1': (12180 commits)
Linux 3.15-rc1
mm: Initialize error in shmem_file_aio_read()
cifs: Use min_t() when comparing "size_t" and "unsigned long"
sym53c8xx_2: Set DID_REQUEUE return code when aborting squeue
powerpc: Don't try to set LPCR unless we're in hypervisor mode
futex: update documentation for ordering guarantees
ceph: fix pr_fmt() redefinition
vti: don't allow to add the same tunnel twice
gre: don't allow to add the same tunnel twice
drivers: net: xen-netfront: fix array initialization bug
missing bits of "splice: fix racy pipe->buffers uses"
cifs: fix the race in cifs_writev()
ceph_sync_{,direct_}write: fix an oops on ceph_osdc_new_request() failure
pktgen: be friendly to LLTX devices
r8152: check RTL8152_UNPLUG
net: sun4i-emac: add promiscuous support
net/apne: replace IS_ERR and PTR_ERR with PTR_ERR_OR_ZERO
blackfin: cleanup board files
bf609: clock: drop unused clock bit set/clear functions
Blackfin: bf537: rename "CONFIG_ADT75"
...
Diffstat (limited to 'drivers/rtc/rtc-ds3232.c')
-rw-r--r-- | drivers/rtc/rtc-ds3232.c | 100 |
1 files changed, 72 insertions, 28 deletions
diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index b83bb5a527f..adaf06c4147 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -57,6 +57,7 @@ struct ds3232 { * in the remove function. */ struct mutex mutex; + bool suspended; int exiting; }; @@ -345,7 +346,15 @@ static irqreturn_t ds3232_irq(int irq, void *dev_id) struct ds3232 *ds3232 = i2c_get_clientdata(client); disable_irq_nosync(irq); - schedule_work(&ds3232->work); + + /* + * If rtc as a wakeup source, can't schedule the work + * at system resume flow, because at this time the i2c bus + * has not been resumed. + */ + if (!ds3232->suspended) + schedule_work(&ds3232->work); + return IRQ_HANDLED; } @@ -363,22 +372,26 @@ static void ds3232_work(struct work_struct *work) if (stat & DS3232_REG_SR_A1F) { control = i2c_smbus_read_byte_data(client, DS3232_REG_CR); - if (control < 0) - goto out; - /* disable alarm1 interrupt */ - control &= ~(DS3232_REG_CR_A1IE); - i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); - - /* clear the alarm pend flag */ - stat &= ~DS3232_REG_SR_A1F; - i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); - - rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF); + if (control < 0) { + pr_warn("Read DS3232 Control Register error." + "Disable IRQ%d.\n", client->irq); + } else { + /* disable alarm1 interrupt */ + control &= ~(DS3232_REG_CR_A1IE); + i2c_smbus_write_byte_data(client, DS3232_REG_CR, + control); + + /* clear the alarm pend flag */ + stat &= ~DS3232_REG_SR_A1F; + i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); + + rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF); + + if (!ds3232->exiting) + enable_irq(client->irq); + } } -out: - if (!ds3232->exiting) - enable_irq(client->irq); unlock: mutex_unlock(&ds3232->mutex); } @@ -411,23 +424,17 @@ static int ds3232_probe(struct i2c_client *client, if (ret) return ret; - ds3232->rtc = devm_rtc_device_register(&client->dev, client->name, - &ds3232_rtc_ops, THIS_MODULE); - if (IS_ERR(ds3232->rtc)) { - dev_err(&client->dev, "unable to register the class device\n"); - return PTR_ERR(ds3232->rtc); - } - - if (client->irq >= 0) { - ret = devm_request_irq(&client->dev, client->irq, ds3232_irq, 0, - "ds3232", client); + if (client->irq > 0) { + ret = devm_request_irq(&client->dev, client->irq, ds3232_irq, + IRQF_SHARED, "ds3232", client); if (ret) { dev_err(&client->dev, "unable to request IRQ\n"); - return ret; } + device_init_wakeup(&client->dev, 1); } - - return 0; + ds3232->rtc = devm_rtc_device_register(&client->dev, client->name, + &ds3232_rtc_ops, THIS_MODULE); + return PTR_ERR_OR_ZERO(ds3232->rtc); } static int ds3232_remove(struct i2c_client *client) @@ -446,6 +453,42 @@ static int ds3232_remove(struct i2c_client *client) return 0; } +#ifdef CONFIG_PM_SLEEP +static int ds3232_suspend(struct device *dev) +{ + struct ds3232 *ds3232 = dev_get_drvdata(dev); + struct i2c_client *client = to_i2c_client(dev); + + if (device_can_wakeup(dev)) { + ds3232->suspended = true; + irq_set_irq_wake(client->irq, 1); + } + + return 0; +} + +static int ds3232_resume(struct device *dev) +{ + struct ds3232 *ds3232 = dev_get_drvdata(dev); + struct i2c_client *client = to_i2c_client(dev); + + if (ds3232->suspended) { + ds3232->suspended = false; + + /* Clear the hardware alarm pend flag */ + schedule_work(&ds3232->work); + + irq_set_irq_wake(client->irq, 0); + } + + return 0; +} +#endif + +static const struct dev_pm_ops ds3232_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ds3232_suspend, ds3232_resume) +}; + static const struct i2c_device_id ds3232_id[] = { { "ds3232", 0 }, { } @@ -456,6 +499,7 @@ static struct i2c_driver ds3232_driver = { .driver = { .name = "rtc-ds3232", .owner = THIS_MODULE, + .pm = &ds3232_pm_ops, }, .probe = ds3232_probe, .remove = ds3232_remove, |