Add power management support to the driver. This allows a SoC to wake
from suspend using the nINT provided by the RTC.
It takes care of the case when the interrupt has not been caught because
the kernel has not yet woke up.
(This is the case when only edges interrupt are caught)
Signed-off-by: Richard Genoud <[email protected]>
---
drivers/rtc/rtc-tps6594.c | 46 +++++++++++++++++++++++++++++++++++++
include/linux/mfd/tps6594.h | 1 +
2 files changed, 47 insertions(+)
diff --git a/drivers/rtc/rtc-tps6594.c b/drivers/rtc/rtc-tps6594.c
index 838ae8562a35..b769d120c624 100644
--- a/drivers/rtc/rtc-tps6594.c
+++ b/drivers/rtc/rtc-tps6594.c
@@ -415,6 +415,8 @@ static int tps6594_rtc_probe(struct platform_device *pdev)
if (irq < 0)
return dev_err_probe(dev, irq, "Failed to get irq\n");
+ tps->irq_rtc = irq;
+
ret = devm_request_threaded_irq(dev, irq, NULL, tps6594_rtc_interrupt,
IRQF_ONESHOT, TPS6594_IRQ_NAME_ALARM,
dev);
@@ -434,6 +436,49 @@ static int tps6594_rtc_probe(struct platform_device *pdev)
return devm_rtc_register_device(rtc);
}
+static int tps6594_rtc_resume(struct device *dev)
+{
+ struct tps6594 *tps = dev_get_drvdata(dev->parent);
+ struct rtc_device *rtc_dev = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regmap_test_bits(tps->regmap, TPS6594_REG_INT_STARTUP,
+ TPS6594_BIT_RTC_INT);
+ if (ret < 0) {
+ dev_err(dev, "failed to read REG_INT_STARTUP: %d\n", ret);
+ goto out;
+ }
+
+ if (ret > 0) {
+ /*
+ * If the alarm bit is set, it means that the IRQ has been
+ * fired. But, the kernel may not have woke up yet when it
+ * happened. So, we have to clear it.
+ */
+ ret = regmap_write(tps->regmap, TPS6594_REG_RTC_STATUS,
+ TPS6594_BIT_ALARM);
+ if (ret < 0)
+ dev_err(dev, "error clearing alarm bit: %d", ret);
+
+ rtc_update_irq(rtc_dev, 1, RTC_IRQF | RTC_AF);
+ }
+out:
+ disable_irq_wake(tps->irq_rtc);
+
+ return 0;
+}
+
+static int tps6594_rtc_suspend(struct device *dev)
+{
+ struct tps6594 *tps = dev_get_drvdata(dev->parent);
+
+ enable_irq_wake(tps->irq_rtc);
+
+ return 0;
+}
+
+SIMPLE_DEV_PM_OPS(tps6594_rtc_pm_ops, tps6594_rtc_suspend, tps6594_rtc_resume);
+
static const struct platform_device_id tps6594_rtc_id_table[] = {
{ "tps6594-rtc", },
{}
@@ -444,6 +489,7 @@ static struct platform_driver tps6594_rtc_driver = {
.probe = tps6594_rtc_probe,
.driver = {
.name = "tps6594-rtc",
+ .pm = pm_sleep_ptr(&tps6594_rtc_pm_ops),
},
.id_table = tps6594_rtc_id_table,
};
diff --git a/include/linux/mfd/tps6594.h b/include/linux/mfd/tps6594.h
index 3f7c5e23cd4c..85933f1519c4 100644
--- a/include/linux/mfd/tps6594.h
+++ b/include/linux/mfd/tps6594.h
@@ -1011,6 +1011,7 @@ struct tps6594 {
bool use_crc;
struct regmap *regmap;
int irq;
+ int irq_rtc;
struct regmap_irq_chip_data *irq_data;
};
--
2.43.0
Hi Richard,
kernel test robot noticed the following build warnings:
[auto build test WARNING on abelloni/rtc-next]
[also build test WARNING on lee-mfd/for-mfd-next lee-leds/for-leds-next lee-mfd/for-mfd-fixes linus/master v6.9 next-20240513]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Richard-Genoud/rtc-tps6594-Add-power-management-support/20240514-003053
base: https://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git rtc-next
patch link: https://lore.kernel.org/r/20240513162942.68484-1-richard.genoud%40bootlin.com
patch subject: [PATCH] rtc: tps6594: Add power management support
config: sparc-randconfig-r081-20240514 (https://download.01.org/0day-ci/archive/20240514/[email protected]/config)
compiler: sparc64-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240514/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All warnings (new ones prefixed by >>):
>> drivers/rtc/rtc-tps6594.c:471:12: warning: 'tps6594_rtc_suspend' defined but not used [-Wunused-function]
471 | static int tps6594_rtc_suspend(struct device *dev)
| ^~~~~~~~~~~~~~~~~~~
>> drivers/rtc/rtc-tps6594.c:439:12: warning: 'tps6594_rtc_resume' defined but not used [-Wunused-function]
439 | static int tps6594_rtc_resume(struct device *dev)
| ^~~~~~~~~~~~~~~~~~
vim +/tps6594_rtc_suspend +471 drivers/rtc/rtc-tps6594.c
438
> 439 static int tps6594_rtc_resume(struct device *dev)
440 {
441 struct tps6594 *tps = dev_get_drvdata(dev->parent);
442 struct rtc_device *rtc_dev = dev_get_drvdata(dev);
443 int ret;
444
445 ret = regmap_test_bits(tps->regmap, TPS6594_REG_INT_STARTUP,
446 TPS6594_BIT_RTC_INT);
447 if (ret < 0) {
448 dev_err(dev, "failed to read REG_INT_STARTUP: %d\n", ret);
449 goto out;
450 }
451
452 if (ret > 0) {
453 /*
454 * If the alarm bit is set, it means that the IRQ has been
455 * fired. But, the kernel may not have woke up yet when it
456 * happened. So, we have to clear it.
457 */
458 ret = regmap_write(tps->regmap, TPS6594_REG_RTC_STATUS,
459 TPS6594_BIT_ALARM);
460 if (ret < 0)
461 dev_err(dev, "error clearing alarm bit: %d", ret);
462
463 rtc_update_irq(rtc_dev, 1, RTC_IRQF | RTC_AF);
464 }
465 out:
466 disable_irq_wake(tps->irq_rtc);
467
468 return 0;
469 }
470
> 471 static int tps6594_rtc_suspend(struct device *dev)
472 {
473 struct tps6594 *tps = dev_get_drvdata(dev->parent);
474
475 enable_irq_wake(tps->irq_rtc);
476
477 return 0;
478 }
479
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki