tegrakernel/kernel/kernel-4.9/drivers/rtc/rtc-tegra.c

745 lines
20 KiB
C

/*
* drivers/rtc/rtc-tegra.c
*
* Copyright (c) 2014-2019, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/clk.h>
#include <linux/debugfs.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/module.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/rtc.h>
#include <linux/rtc/rtc-tegra.h>
#define CREATE_TRACE_POINTS
#include <trace/events/tegra_rtc.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <asm/mach/time.h>
/* set to 1 = busy every eight 32kHz clocks during copy of sec+msec to AHB */
#define TEGRA_RTC_REG_BUSY 0x004
#define TEGRA_RTC_REG_SECONDS 0x008
/* when msec is read, the seconds are buffered into shadow seconds. */
#define TEGRA_RTC_REG_SHADOW_SECONDS 0x00c
#define TEGRA_RTC_REG_MILLI_SECONDS 0x010
#define TEGRA_RTC_REG_SECONDS_ALARM0 0x014
#define TEGRA_RTC_REG_SECONDS_ALARM1 0x018
#define TEGRA_RTC_REG_MILLI_SECONDS_ALARM0 0x01c
#define TEGRA_RTC_REG_MSEC_CDN_ALARM0 0x024
#define TEGRA_RTC_REG_INTR_MASK 0x028
/* write 1 bits to clear status bits */
#define TEGRA_RTC_REG_INTR_STATUS 0x02c
/* bits in INTR_MASK */
#define TEGRA_RTC_INTR_MASK_MSEC_CDN_ALARM (1<<4)
#define TEGRA_RTC_INTR_MASK_SEC_CDN_ALARM (1<<3)
#define TEGRA_RTC_INTR_MASK_MSEC_ALARM (1<<2)
#define TEGRA_RTC_INTR_MASK_SEC_ALARM1 (1<<1)
#define TEGRA_RTC_INTR_MASK_SEC_ALARM0 (1<<0)
/* bits in INTR_STATUS */
#define TEGRA_RTC_INTR_STATUS_MSEC_CDN_ALARM (1<<4)
#define TEGRA_RTC_INTR_STATUS_SEC_CDN_ALARM (1<<3)
#define TEGRA_RTC_INTR_STATUS_MSEC_ALARM (1<<2)
#define TEGRA_RTC_INTR_STATUS_SEC_ALARM1 (1<<1)
#define TEGRA_RTC_INTR_STATUS_SEC_ALARM0 (1<<0)
/* Reference selection */
#define TEGRA_RTC_RTCRSR 0x038
#define TEGRA_RTC_RTCRSR_FR (1<<0)
#define TEGRA_RTC_RTCRSR_MBS(x) (((x) & 3) << 4)
#define TEGRA_RTC_RTCDR 0x03c
#define TEGRA_RTC_RTCDR_D(x) (((x) & 0xffff) << 16)
#define TEGRA_RTC_RTCDR_N(x) ((x) & 0xffff)
/* Recommended values for reference and dividor */
/* RTC follows MTSC bit 11 (9+2) */
#define TEGRA_RTC_RTCRSR_USE_MTSC (0x20)
/* N=1024 D=15625 assuming FNOM=31250 program n-1 */
#define TEGRA_RTC_RTCDR_USE_MTSC (0x3D0803ff)
struct tegra_rtc_chip_data {
bool has_clock;
bool follow_tsc;
};
struct tegra_rtc_info {
struct platform_device *pdev;
struct rtc_device *rtc_dev;
void __iomem *rtc_base; /* NULL if not initialized. */
int tegra_rtc_irq; /* alarm and periodic irq */
spinlock_t tegra_rtc_lock;
bool is_tegra_rtc_suspended;
};
static struct tegra_rtc_info *tegra_rtc_dev;
/*
* tegra_rtc_read - Reads the Tegra RTC registers
* Care must be taken that this funciton is not called while the
* tegra_rtc driver could be executing to avoid race conditions
* on the RTC shadow register
*/
u64 tegra_rtc_read_ms(void)
{
u32 ms = readl(tegra_rtc_dev->rtc_base + RTC_MILLISECONDS);
u32 s = readl(tegra_rtc_dev->rtc_base + RTC_SHADOW_SECONDS);
return (u64)s * MSEC_PER_SEC + ms;
}
EXPORT_SYMBOL(tegra_rtc_read_ms);
/* RTC hardware is busy when it is updating its values over AHB once
* every eight 32kHz clocks (~250uS).
* outside of these updates the CPU is free to write.
* CPU is always free to read.
*/
static inline u32 tegra_rtc_check_busy(struct tegra_rtc_info *info)
{
return readl(info->rtc_base + TEGRA_RTC_REG_BUSY) & 1;
}
/* Wait for hardware to be ready for writing.
* This function tries to maximize the amount of time before the next update.
* It does this by waiting for the RTC to become busy with its periodic update,
* then returning once the RTC first becomes not busy.
* This periodic update (where the seconds and milliseconds are copied to the
* AHB side) occurs every eight 32kHz clocks (~250uS).
* The behavior of this function allows us to make some assumptions without
* introducing a race, because 250uS is plenty of time to read/write a value.
*/
static int tegra_rtc_wait_while_busy(struct device *dev, bool is_read)
{
struct tegra_rtc_info *info = dev_get_drvdata(dev);
int retries = 500; /* ~490 us is the worst case, ~250 us is best. */
/* first wait for the RTC to become busy. this is when it
* posts its updated seconds+msec registers to AHB side. */
while (tegra_rtc_check_busy(info)) {
if (!retries--)
goto retry_failed;
udelay(1);
}
/* Updated value can take nearly 250us to reflect in shadow
* registers. Wait to read latest value.
*/
if (is_read)
udelay(250);
/* now we have about 250 us to manipulate registers */
return 0;
retry_failed:
dev_err(dev, "Timeout accessing RTC device.\n");
return -ETIMEDOUT;
}
static int tegra_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct tegra_rtc_info *info = dev_get_drvdata(dev);
unsigned long sec, msec;
unsigned long sl_irq_flags;
int ret;
/* Ensure there is no pending write to get latest time */
ret = tegra_rtc_wait_while_busy(dev, true);
if (ret < 0)
dev_warn(dev, "Reading old value\n");
/* RTC hardware copies seconds to shadow seconds when a read
* of milliseconds occurs. use a lock to keep other threads out. */
spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags);
msec = readl(info->rtc_base + TEGRA_RTC_REG_MILLI_SECONDS);
sec = readl(info->rtc_base + TEGRA_RTC_REG_SHADOW_SECONDS);
spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags);
rtc_time_to_tm(sec, tm);
dev_vdbg(dev, "time read as %lu. %d/%d/%d %d:%02u:%02u\n",
sec,
tm->tm_mon + 1,
tm->tm_mday,
tm->tm_year + 1900,
tm->tm_hour,
tm->tm_min,
tm->tm_sec
);
return 0;
}
static int tegra_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct tegra_rtc_info *info = dev_get_drvdata(dev);
unsigned long sec;
int ret;
/* convert tm to seconds. */
ret = rtc_valid_tm(tm);
if (ret)
return ret;
rtc_tm_to_time(tm, &sec);
dev_vdbg(dev, "time set to %lu. %d/%d/%d %d:%02u:%02u\n",
sec,
tm->tm_mon+1,
tm->tm_mday,
tm->tm_year+1900,
tm->tm_hour,
tm->tm_min,
tm->tm_sec
);
/* seconds only written if wait succeeded. */
ret = tegra_rtc_wait_while_busy(dev, false);
if (!ret)
writel(sec, info->rtc_base + TEGRA_RTC_REG_SECONDS);
dev_vdbg(dev, "time read back as %d\n",
readl(info->rtc_base + TEGRA_RTC_REG_SECONDS));
return ret;
}
static int tegra_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct tegra_rtc_info *info = dev_get_drvdata(dev);
unsigned long sec;
unsigned tmp;
int ret;
ret = tegra_rtc_wait_while_busy(dev, true);
if (ret < 0)
dev_warn(dev, "Reading old value\n");
sec = readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0);
if (sec == 0) {
/* alarm is disabled. */
alarm->enabled = 0;
} else {
/* alarm is enabled. */
alarm->enabled = 1;
rtc_time_to_tm(sec, &alarm->time);
}
tmp = readl(info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
alarm->pending = (tmp & TEGRA_RTC_INTR_STATUS_SEC_ALARM0) != 0;
return 0;
}
static int tegra_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct tegra_rtc_info *info = dev_get_drvdata(dev);
unsigned status;
unsigned long sl_irq_flags;
int ret;
ret = tegra_rtc_wait_while_busy(dev, false);
if (ret < 0) {
dev_err(dev, "Timeout accessing RTC\n");
return ret;
}
spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags);
/* read the original value, and OR in the flag. */
status = readl(info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
if (enabled)
status |= TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* set it */
else
status &= ~TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* clear it */
writel(status, info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags);
return 0;
}
static int __tegra_rtc_set_alarm(struct device *dev, unsigned long period,
bool enabled)
{
struct tegra_rtc_info *info = dev_get_drvdata(dev);
unsigned int sec, msec;
int ret;
ret = tegra_rtc_wait_while_busy(dev, false);
if (ret < 0) {
dev_err(dev, "Timeout accessing RTC\n");
return ret;
}
msec = readl(info->rtc_base + TEGRA_RTC_REG_MILLI_SECONDS);
sec = readl(info->rtc_base + TEGRA_RTC_REG_SHADOW_SECONDS);
if (period < sec)
dev_warn(dev, "alarm time set in past\n");
writel(period, info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0);
ret = tegra_rtc_alarm_irq_enable(dev, enabled);
if (ret < 0) {
dev_err(dev,
"rtc_set_alarm: Failed to enable rtc alarm\n");
return ret;
}
trace_tegra_rtc_set_alarm(sec * MSEC_PER_SEC + msec,
period * MSEC_PER_SEC);
dev_dbg(dev, "alarm set to fire after %lu sec\n", (period - sec));
return 0;
}
static int tegra_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
unsigned long period;
rtc_tm_to_time(&alarm->time, &period);
return __tegra_rtc_set_alarm(dev, period, alarm->enabled);
}
static int tegra_rtc_proc(struct device *dev, struct seq_file *seq)
{
if (!dev || !dev->driver)
return 0;
seq_printf(seq, "name\t\t: %s\n", dev_name(dev));
return 0;
}
static irqreturn_t tegra_rtc_irq_handler(int irq, void *data)
{
struct device *dev = data;
struct tegra_rtc_info *info = dev_get_drvdata(dev);
u32 status, mask;
unsigned int sec;
unsigned int msec;
int ret;
unsigned long sl_irq_flags;
tegra_rtc_alarm_irq_enable(dev, 0);
msec = readl(info->rtc_base + TEGRA_RTC_REG_MILLI_SECONDS);
sec = readl(info->rtc_base + TEGRA_RTC_REG_SHADOW_SECONDS);
trace_tegra_rtc_irq_handler(__func__, sec * MSEC_PER_SEC + msec);
status = readl(info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
mask = readl(info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
mask &= ~status;
if (status) {
/* clear the interrupt masks and status on any irq. */
ret = tegra_rtc_wait_while_busy(dev, false);
if (ret < 0)
dev_warn(dev, "Reading old value\n");
spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags);
writel(mask, info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags);
ret = tegra_rtc_wait_while_busy(dev, false);
if (ret < 0)
dev_warn(dev, "Reading old value\n");
spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags);
writel(status, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags);
}
rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_UF);
/* If we are in suspend state and we get an RTC interrupt, wake up */
if (device_may_wakeup(dev) && info->is_tegra_rtc_suspended) {
pm_wakeup_event(dev,0);
}
return IRQ_HANDLED;
}
static int tegra_rtc_msec_alarm_irq_enable(struct tegra_rtc_info *info,
unsigned int enable)
{
u32 status;
/* read the original value, and OR in the flag. */
status = readl(info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
if (enable)
status |= TEGRA_RTC_INTR_MASK_MSEC_CDN_ALARM; /* set it */
else
status &= ~TEGRA_RTC_INTR_MASK_MSEC_CDN_ALARM; /* clear it */
writel(status, info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
return 0;
}
void tegra_rtc_set_trigger(unsigned long cycles)
{
struct tegra_rtc_info *info = tegra_rtc_dev;
struct device *dev = &info->pdev->dev;
unsigned long msec;
unsigned long now;
unsigned long tgt;
int ret;
/* Convert to msec */
msec = cycles / 1000;
if (msec)
msec = 0x80000000UL | (0x0fffffff & msec);
ret = tegra_rtc_wait_while_busy(dev, true);
if (ret < 0)
dev_warn(dev, "Reading old value\n");
now = readl(info->rtc_base + TEGRA_RTC_REG_MILLI_SECONDS);
now += readl(info->rtc_base + TEGRA_RTC_REG_SHADOW_SECONDS) *
MSEC_PER_SEC;
tgt = now + cycles / 1000;
writel(msec, info->rtc_base + TEGRA_RTC_REG_MSEC_CDN_ALARM0);
trace_tegra_rtc_set_alarm(now, tgt);
ret = tegra_rtc_wait_while_busy(dev, false);
if (ret < 0)
dev_warn(dev, "Reading old value\n");
if (msec)
tegra_rtc_msec_alarm_irq_enable(info, 1);
else
tegra_rtc_msec_alarm_irq_enable(info, 0);
}
EXPORT_SYMBOL(tegra_rtc_set_trigger);
#ifdef CONFIG_PM_SLEEP
static void tegra_rtc_debug_set_alarm(struct device *dev, unsigned int period)
{
struct tegra_rtc_info *info = dev_get_drvdata(dev);
unsigned int sec;
int ret;
sec = readl(info->rtc_base + TEGRA_RTC_REG_SECONDS);
ret = __tegra_rtc_set_alarm(dev, (sec + period), 1);
if (ret < 0)
pr_err("Tegra RTC: setting debug alarm failed\n");
}
#endif
static const struct rtc_class_ops tegra_rtc_ops = {
.read_time = tegra_rtc_read_time,
.set_time = tegra_rtc_set_time,
.read_alarm = tegra_rtc_read_alarm,
.set_alarm = tegra_rtc_set_alarm,
.proc = tegra_rtc_proc,
.alarm_irq_enable = tegra_rtc_alarm_irq_enable,
};
static unsigned int alarm_period;
static unsigned int alarm_period_msec;
static int alarm_set(void *data, u64 val)
{
alarm_period = val;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(alarm_fops, NULL, alarm_set, "%llu\n");
static int alarm_msec_set(void *data, u64 val)
{
alarm_period_msec = val;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(alarm_msec_fops, NULL, alarm_msec_set, "%llu\n");
static struct dentry *pm_dentry;
static int debugfs_init(void)
{
struct dentry *root = NULL;
root = debugfs_create_dir("tegra-rtc", NULL);
if (!root)
return -ENOMEM;
if (!debugfs_create_file("alarm", S_IWUSR, root, NULL, &alarm_fops))
goto err_out;
if (!debugfs_create_file("alarm_msec", S_IWUSR, root, NULL,
&alarm_msec_fops))
goto err_out;
pm_dentry = root;
return 0;
err_out:
debugfs_remove_recursive(root);
return -ENOMEM;
}
#ifndef MODULE
/*
* tegra_read_persistent_clock - Return time from a persistent clock.
*
* Reads the time from a source which isn't disabled during PM, the
* 32k sync timer. Convert the cycles elapsed since last read into
* nsecs and adds to a monotonically increasing timespec.
* Care must be taken that this funciton is not called while the
* tegra_rtc driver could be executing to avoid race conditions
* on the RTC shadow register
*/
static void tegra_rtc_read_persistent_clock(struct timespec *ts)
{
ts->tv_nsec = NSEC_PER_MSEC *
readl(tegra_rtc_dev->rtc_base + RTC_MILLISECONDS);
ts->tv_sec = readl(tegra_rtc_dev->rtc_base + RTC_SHADOW_SECONDS);
}
#endif
static struct tegra_rtc_chip_data t18x_rtc_cdata = {
.has_clock = false,
.follow_tsc = false,
};
static struct tegra_rtc_chip_data tegra_rtc_cdata = {
.has_clock = true,
.follow_tsc = false,
};
static struct tegra_rtc_chip_data t20x_rtc_cdata = {
.has_clock = false,
.follow_tsc = false,
};
static const struct of_device_id tegra_rtc_dt_match[] = {
{
.compatible = "nvidia,tegra-rtc",
.data = &tegra_rtc_cdata,
},
{
.compatible = "nvidia,tegra18-rtc",
.data = &t18x_rtc_cdata,
},
{
.compatible = "nvidia,tegra20-rtc",
.data = &t20x_rtc_cdata,
},
{}
};
MODULE_DEVICE_TABLE(of, tegra_rtc_dt_match);
static void tegra_rtc_follow_tsc(struct device *dev)
{
struct tegra_rtc_info *info = dev_get_drvdata(dev);
int ret;
ret = tegra_rtc_wait_while_busy(dev, false);
if (ret < 0) {
dev_err(&info->pdev->dev, "Timeout accessing Tegra RTC\n");
return;
}
writel(TEGRA_RTC_RTCDR_USE_MTSC, info->rtc_base + TEGRA_RTC_RTCDR);
ret = tegra_rtc_wait_while_busy(dev, false);
if (ret < 0) {
dev_err(&info->pdev->dev, "Timeout accessing Tegra RTC\n");
return;
}
writel(TEGRA_RTC_RTCRSR_USE_MTSC, info->rtc_base + TEGRA_RTC_RTCRSR);
}
static int __init tegra_rtc_probe(struct platform_device *pdev)
{
struct tegra_rtc_info *info;
struct resource *res;
const struct of_device_id *match;
const struct tegra_rtc_chip_data *cdata = NULL;
struct clk *clk;
int ret;
info = devm_kzalloc(&pdev->dev, sizeof(struct tegra_rtc_info),
GFP_KERNEL);
if (!info)
return -ENOMEM;
if (pdev->dev.of_node) {
match = of_match_device(tegra_rtc_dt_match, &pdev->dev);
if (match)
cdata = match->data;
}
if (!cdata)
return -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
info->rtc_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(info->rtc_base))
return PTR_ERR(info->rtc_base);
tegra_rtc_dev = info;
info->tegra_rtc_irq = platform_get_irq(pdev, 0);
if (info->tegra_rtc_irq <= 0)
return -EBUSY;
/* set context info. */
info->pdev = pdev;
spin_lock_init(&info->tegra_rtc_lock);
platform_set_drvdata(pdev, info);
if (cdata->has_clock) {
clk = devm_clk_get(&pdev->dev, "rtc");
if (IS_ERR(clk))
clk = clk_get_sys("rtc-tegra", NULL);
if (IS_ERR(clk))
dev_warn(&pdev->dev, "Unable to get rtc-tegra clock\n");
else
clk_prepare_enable(clk);
}
/* clear out the hardware. */
ret = tegra_rtc_wait_while_busy(&pdev->dev, false);
if (ret < 0)
dev_warn(&pdev->dev, "Reading old value\n");
writel(0, info->rtc_base + TEGRA_RTC_REG_MSEC_CDN_ALARM0);
ret = tegra_rtc_wait_while_busy(&pdev->dev, false);
if (ret < 0)
dev_warn(&pdev->dev, "Reading old value\n");
writel(0xffffffff, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
ret = tegra_rtc_wait_while_busy(&pdev->dev, false);
if (ret < 0)
dev_warn(&pdev->dev, "Reading old value\n");
writel(0, info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
if(cdata->follow_tsc)
tegra_rtc_follow_tsc(&pdev->dev);
ret = devm_request_threaded_irq(&pdev->dev, info->tegra_rtc_irq,
NULL, tegra_rtc_irq_handler,
IRQF_ONESHOT | IRQF_EARLY_RESUME,
"tegra_rtc", &pdev->dev);
if (ret) {
dev_err(&pdev->dev, "Failed to register RTC IRQ: %d\n", ret);
/* system cannot proceed without rtc */
BUG();
}
device_init_wakeup(&pdev->dev, 1);
info->rtc_dev = devm_rtc_device_register(&pdev->dev,
dev_name(&pdev->dev), &tegra_rtc_ops,
THIS_MODULE);
if (IS_ERR(info->rtc_dev)) {
ret = PTR_ERR(info->rtc_dev);
dev_err(&pdev->dev, "Unable to register device (err=%d).\n",
ret);
return ret;
}
ret = debugfs_init();
if (ret) {
pr_err("%s: Can't init debugfs", __func__);
BUG();
}
#ifndef MODULE
register_persistent_clock(NULL, tegra_rtc_read_persistent_clock);
#endif
dev_notice(&pdev->dev, "Tegra internal Real Time Clock\n");
return 0;
}
static int tegra_rtc_remove(struct platform_device *pdev)
{
debugfs_remove_recursive(pm_dentry);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int tegra_rtc_suspend(struct device *dev)
{
struct tegra_rtc_info *info = dev_get_drvdata(dev);
int ret;
ret = tegra_rtc_wait_while_busy(dev, false);
if (ret < 0) {
dev_err(dev, "Timeout accessing RTC\n");
return ret;
}
dev_vdbg(dev, "Suspend (device_may_wakeup=%d) irq:%d\n",
device_may_wakeup(dev), info->tegra_rtc_irq);
if (alarm_period)
tegra_rtc_debug_set_alarm(dev, alarm_period);
if (alarm_period_msec)
tegra_rtc_set_trigger(alarm_period_msec * 1000);
/* leave the alarms on as a wake source. */
if (alarm_period || alarm_period_msec || device_may_wakeup(dev))
enable_irq_wake(info->tegra_rtc_irq);
info->is_tegra_rtc_suspended = true;
return 0;
}
static int tegra_rtc_resume(struct device *dev)
{
struct tegra_rtc_info *info = dev_get_drvdata(dev);
dev_vdbg(dev, "Resume (device_may_wakeup=%d)\n",
device_may_wakeup(dev));
/* alarms were left on as a wake source, turn them off. */
if (alarm_period || alarm_period_msec || device_may_wakeup(dev))
disable_irq_wake(info->tegra_rtc_irq);
info->is_tegra_rtc_suspended = false;
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(tegra_rtc_pm_ops, tegra_rtc_suspend, tegra_rtc_resume);
static void tegra_rtc_shutdown(struct platform_device *pdev)
{
dev_vdbg(&pdev->dev, "disabling interrupts.\n");
tegra_rtc_alarm_irq_enable(&pdev->dev, 0);
}
MODULE_ALIAS("platform:tegra_rtc");
static struct platform_driver tegra_rtc_driver = {
.remove = tegra_rtc_remove,
.shutdown = tegra_rtc_shutdown,
.driver = {
.name = "tegra_rtc",
.of_match_table = tegra_rtc_dt_match,
.pm = &tegra_rtc_pm_ops,
},
};
module_platform_driver_probe(tegra_rtc_driver, tegra_rtc_probe);
MODULE_AUTHOR("Jon Mayo <jmayo@nvidia.com>");
MODULE_DESCRIPTION("driver for Tegra internal RTC");
MODULE_LICENSE("GPL");