1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2019 BayLibre, SAS
4 * Author: Neil Armstrong <narmstrong@baylibre.com>
5 * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
7 #include <linux/module.h>
8 #include <linux/platform_device.h>
12 #include <linux/time64.h>
14 struct meson_vrtc_data
{
15 void __iomem
*io_alarm
;
16 struct rtc_device
*rtc
;
17 unsigned long alarm_time
;
21 static int meson_vrtc_read_time(struct device
*dev
, struct rtc_time
*tm
)
23 struct timespec64 time
;
25 dev_dbg(dev
, "%s\n", __func__
);
26 ktime_get_raw_ts64(&time
);
27 rtc_time64_to_tm(time
.tv_sec
, tm
);
32 static void meson_vrtc_set_wakeup_time(struct meson_vrtc_data
*vrtc
,
35 writel_relaxed(time
, vrtc
->io_alarm
);
38 static int meson_vrtc_set_alarm(struct device
*dev
, struct rtc_wkalrm
*alarm
)
40 struct meson_vrtc_data
*vrtc
= dev_get_drvdata(dev
);
42 dev_dbg(dev
, "%s: alarm->enabled=%d\n", __func__
, alarm
->enabled
);
44 vrtc
->alarm_time
= rtc_tm_to_time64(&alarm
->time
);
51 static int meson_vrtc_alarm_irq_enable(struct device
*dev
, unsigned int enabled
)
53 struct meson_vrtc_data
*vrtc
= dev_get_drvdata(dev
);
55 vrtc
->enabled
= enabled
;
59 static const struct rtc_class_ops meson_vrtc_ops
= {
60 .read_time
= meson_vrtc_read_time
,
61 .set_alarm
= meson_vrtc_set_alarm
,
62 .alarm_irq_enable
= meson_vrtc_alarm_irq_enable
,
65 static int meson_vrtc_probe(struct platform_device
*pdev
)
67 struct meson_vrtc_data
*vrtc
;
70 vrtc
= devm_kzalloc(&pdev
->dev
, sizeof(*vrtc
), GFP_KERNEL
);
74 vrtc
->io_alarm
= devm_platform_ioremap_resource(pdev
, 0);
75 if (IS_ERR(vrtc
->io_alarm
))
76 return PTR_ERR(vrtc
->io_alarm
);
78 device_init_wakeup(&pdev
->dev
, 1);
80 platform_set_drvdata(pdev
, vrtc
);
82 vrtc
->rtc
= devm_rtc_allocate_device(&pdev
->dev
);
83 if (IS_ERR(vrtc
->rtc
))
84 return PTR_ERR(vrtc
->rtc
);
86 vrtc
->rtc
->ops
= &meson_vrtc_ops
;
87 ret
= rtc_register_device(vrtc
->rtc
);
94 static int __maybe_unused
meson_vrtc_suspend(struct device
*dev
)
96 struct meson_vrtc_data
*vrtc
= dev_get_drvdata(dev
);
98 dev_dbg(dev
, "%s\n", __func__
);
99 if (vrtc
->alarm_time
) {
100 unsigned long local_time
;
102 struct timespec64 time
;
104 ktime_get_raw_ts64(&time
);
105 local_time
= time
.tv_sec
;
107 dev_dbg(dev
, "alarm_time = %lus, local_time=%lus\n",
108 vrtc
->alarm_time
, local_time
);
109 alarm_secs
= vrtc
->alarm_time
- local_time
;
110 if (alarm_secs
> 0) {
111 meson_vrtc_set_wakeup_time(vrtc
, alarm_secs
);
112 dev_dbg(dev
, "system will wakeup in %lds.\n",
115 dev_err(dev
, "alarm time already passed: %lds.\n",
123 static int __maybe_unused
meson_vrtc_resume(struct device
*dev
)
125 struct meson_vrtc_data
*vrtc
= dev_get_drvdata(dev
);
127 dev_dbg(dev
, "%s\n", __func__
);
129 vrtc
->alarm_time
= 0;
130 meson_vrtc_set_wakeup_time(vrtc
, 0);
134 static SIMPLE_DEV_PM_OPS(meson_vrtc_pm_ops
,
135 meson_vrtc_suspend
, meson_vrtc_resume
);
137 static const struct of_device_id meson_vrtc_dt_match
[] = {
138 { .compatible
= "amlogic,meson-vrtc"},
141 MODULE_DEVICE_TABLE(of
, meson_vrtc_dt_match
);
143 static struct platform_driver meson_vrtc_driver
= {
144 .probe
= meson_vrtc_probe
,
146 .name
= "meson-vrtc",
147 .of_match_table
= meson_vrtc_dt_match
,
148 .pm
= &meson_vrtc_pm_ops
,
152 module_platform_driver(meson_vrtc_driver
);
154 MODULE_DESCRIPTION("Amlogic Virtual Wakeup RTC Timer driver");
155 MODULE_LICENSE("GPL");