aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc/rtc-ds3232.c
diff options
context:
space:
mode:
authorAkinobu Mita <akinobu.mita@gmail.com>2016-03-06 10:27:52 -0500
committerAlexandre Belloni <alexandre.belloni@free-electrons.com>2016-03-14 12:08:37 -0400
commit95c60c1c8f51521e7f2174fd0fff4dae6d522b83 (patch)
treed114fac65095a14489f3a218025a812d8312b2ff /drivers/rtc/rtc-ds3232.c
parent7522297e1638f985e5d52f34b871e742b10586d4 (diff)
rtc: ds3232: fix issue when irq is shared several devices
ds3232-core requests irq with IRQF_SHARED, so irq can be shared by several devices. But the irq handler for ds3232 unconditionally disables the irq at first and the irq is re-enabled only when the interrupt source was the ds3232's alarm. This behaviour breaks the devices sharing the same irq in the various scenarios. This converts to use threaded irq and remove outdated code in suspend/resume paths. Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com> Suggested-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Diffstat (limited to 'drivers/rtc/rtc-ds3232.c')
-rw-r--r--drivers/rtc/rtc-ds3232.c81
1 files changed, 12 insertions, 69 deletions
diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c
index f0ffd3f5d8f5..9857287215a9 100644
--- a/drivers/rtc/rtc-ds3232.c
+++ b/drivers/rtc/rtc-ds3232.c
@@ -20,7 +20,6 @@
20#include <linux/spi/spi.h> 20#include <linux/spi/spi.h>
21#include <linux/rtc.h> 21#include <linux/rtc.h>
22#include <linux/bcd.h> 22#include <linux/bcd.h>
23#include <linux/workqueue.h>
24#include <linux/slab.h> 23#include <linux/slab.h>
25#include <linux/regmap.h> 24#include <linux/regmap.h>
26 25
@@ -52,7 +51,6 @@ struct ds3232 {
52 struct regmap *regmap; 51 struct regmap *regmap;
53 int irq; 52 int irq;
54 struct rtc_device *rtc; 53 struct rtc_device *rtc;
55 struct work_struct work;
56 54
57 /* The mutex protects alarm operations, and prevents a race 55 /* The mutex protects alarm operations, and prevents a race
58 * between the enable_irq() in the workqueue and the free_irq() 56 * between the enable_irq() in the workqueue and the free_irq()
@@ -60,7 +58,6 @@ struct ds3232 {
60 */ 58 */
61 struct mutex mutex; 59 struct mutex mutex;
62 bool suspended; 60 bool suspended;
63 int exiting;
64}; 61};
65 62
66static int ds3232_check_rtc_status(struct device *dev) 63static int ds3232_check_rtc_status(struct device *dev)
@@ -314,23 +311,6 @@ static irqreturn_t ds3232_irq(int irq, void *dev_id)
314{ 311{
315 struct device *dev = dev_id; 312 struct device *dev = dev_id;
316 struct ds3232 *ds3232 = dev_get_drvdata(dev); 313 struct ds3232 *ds3232 = dev_get_drvdata(dev);
317
318 disable_irq_nosync(irq);
319
320 /*
321 * If rtc as a wakeup source, can't schedule the work
322 * at system resume flow, because at this time the i2c bus
323 * has not been resumed.
324 */
325 if (!ds3232->suspended)
326 schedule_work(&ds3232->work);
327
328 return IRQ_HANDLED;
329}
330
331static void ds3232_work(struct work_struct *work)
332{
333 struct ds3232 *ds3232 = container_of(work, struct ds3232, work);
334 int ret; 314 int ret;
335 int stat, control; 315 int stat, control;
336 316
@@ -343,8 +323,8 @@ static void ds3232_work(struct work_struct *work)
343 if (stat & DS3232_REG_SR_A1F) { 323 if (stat & DS3232_REG_SR_A1F) {
344 ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control); 324 ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control);
345 if (ret) { 325 if (ret) {
346 pr_warn("Read Control Register error - Disable IRQ%d\n", 326 dev_warn(ds3232->dev,
347 ds3232->irq); 327 "Read Control Register error %d\n", ret);
348 } else { 328 } else {
349 /* disable alarm1 interrupt */ 329 /* disable alarm1 interrupt */
350 control &= ~(DS3232_REG_CR_A1IE); 330 control &= ~(DS3232_REG_CR_A1IE);
@@ -368,14 +348,13 @@ static void ds3232_work(struct work_struct *work)
368 } 348 }
369 349
370 rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF); 350 rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF);
371
372 if (!ds3232->exiting)
373 enable_irq(ds3232->irq);
374 } 351 }
375 } 352 }
376 353
377unlock: 354unlock:
378 mutex_unlock(&ds3232->mutex); 355 mutex_unlock(&ds3232->mutex);
356
357 return IRQ_HANDLED;
379} 358}
380 359
381static const struct rtc_class_ops ds3232_rtc_ops = { 360static const struct rtc_class_ops ds3232_rtc_ops = {
@@ -401,7 +380,6 @@ static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq,
401 ds3232->dev = dev; 380 ds3232->dev = dev;
402 dev_set_drvdata(dev, ds3232); 381 dev_set_drvdata(dev, ds3232);
403 382
404 INIT_WORK(&ds3232->work, ds3232_work);
405 mutex_init(&ds3232->mutex); 383 mutex_init(&ds3232->mutex);
406 384
407 ret = ds3232_check_rtc_status(dev); 385 ret = ds3232_check_rtc_status(dev);
@@ -409,8 +387,10 @@ static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq,
409 return ret; 387 return ret;
410 388
411 if (ds3232->irq > 0) { 389 if (ds3232->irq > 0) {
412 ret = devm_request_irq(dev, ds3232->irq, ds3232_irq, 390 ret = devm_request_threaded_irq(dev, ds3232->irq, NULL,
413 IRQF_SHARED, name, dev); 391 ds3232_irq,
392 IRQF_SHARED | IRQF_ONESHOT,
393 name, dev);
414 if (ret) { 394 if (ret) {
415 ds3232->irq = 0; 395 ds3232->irq = 0;
416 dev_err(dev, "unable to request IRQ\n"); 396 dev_err(dev, "unable to request IRQ\n");
@@ -423,33 +403,14 @@ static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq,
423 return PTR_ERR_OR_ZERO(ds3232->rtc); 403 return PTR_ERR_OR_ZERO(ds3232->rtc);
424} 404}
425 405
426static int ds3232_remove(struct device *dev)
427{
428 struct ds3232 *ds3232 = dev_get_drvdata(dev);
429
430 if (ds3232->irq > 0) {
431 mutex_lock(&ds3232->mutex);
432 ds3232->exiting = 1;
433 mutex_unlock(&ds3232->mutex);
434
435 devm_free_irq(dev, ds3232->irq, dev);
436 cancel_work_sync(&ds3232->work);
437 }
438
439 return 0;
440}
441
442#ifdef CONFIG_PM_SLEEP 406#ifdef CONFIG_PM_SLEEP
443static int ds3232_suspend(struct device *dev) 407static int ds3232_suspend(struct device *dev)
444{ 408{
445 struct ds3232 *ds3232 = dev_get_drvdata(dev); 409 struct ds3232 *ds3232 = dev_get_drvdata(dev);
446 410
447 if (device_can_wakeup(dev)) { 411 if (device_may_wakeup(dev)) {
448 ds3232->suspended = true; 412 if (enable_irq_wake(ds3232->irq))
449 if (irq_set_irq_wake(ds3232->irq, 1)) {
450 dev_warn_once(dev, "Cannot set wakeup source\n"); 413 dev_warn_once(dev, "Cannot set wakeup source\n");
451 ds3232->suspended = false;
452 }
453 } 414 }
454 415
455 return 0; 416 return 0;
@@ -459,14 +420,8 @@ static int ds3232_resume(struct device *dev)
459{ 420{
460 struct ds3232 *ds3232 = dev_get_drvdata(dev); 421 struct ds3232 *ds3232 = dev_get_drvdata(dev);
461 422
462 if (ds3232->suspended) { 423 if (device_may_wakeup(dev))
463 ds3232->suspended = false; 424 disable_irq_wake(ds3232->irq);
464
465 /* Clear the hardware alarm pend flag */
466 schedule_work(&ds3232->work);
467
468 irq_set_irq_wake(ds3232->irq, 0);
469 }
470 425
471 return 0; 426 return 0;
472} 427}
@@ -497,11 +452,6 @@ static int ds3232_i2c_probe(struct i2c_client *client,
497 return ds3232_probe(&client->dev, regmap, client->irq, client->name); 452 return ds3232_probe(&client->dev, regmap, client->irq, client->name);
498} 453}
499 454
500static int ds3232_i2c_remove(struct i2c_client *client)
501{
502 return ds3232_remove(&client->dev);
503}
504
505static const struct i2c_device_id ds3232_id[] = { 455static const struct i2c_device_id ds3232_id[] = {
506 { "ds3232", 0 }, 456 { "ds3232", 0 },
507 { } 457 { }
@@ -514,7 +464,6 @@ static struct i2c_driver ds3232_driver = {
514 .pm = &ds3232_pm_ops, 464 .pm = &ds3232_pm_ops,
515 }, 465 },
516 .probe = ds3232_i2c_probe, 466 .probe = ds3232_i2c_probe,
517 .remove = ds3232_i2c_remove,
518 .id_table = ds3232_id, 467 .id_table = ds3232_id,
519}; 468};
520 469
@@ -611,17 +560,11 @@ static int ds3234_probe(struct spi_device *spi)
611 return ds3232_probe(&spi->dev, regmap, spi->irq, "ds3234"); 560 return ds3232_probe(&spi->dev, regmap, spi->irq, "ds3234");
612} 561}
613 562
614static int ds3234_remove(struct spi_device *spi)
615{
616 return ds3232_remove(&spi->dev);
617}
618
619static struct spi_driver ds3234_driver = { 563static struct spi_driver ds3234_driver = {
620 .driver = { 564 .driver = {
621 .name = "ds3234", 565 .name = "ds3234",
622 }, 566 },
623 .probe = ds3234_probe, 567 .probe = ds3234_probe,
624 .remove = ds3234_remove,
625}; 568};
626 569
627static int ds3234_register_driver(void) 570static int ds3234_register_driver(void)