xref: /openbmc/linux/drivers/rtc/rtc-tegra.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1b6838275SAlexandre Belloni // SPDX-License-Identifier: GPL-2.0+
2ff859ba6SAndrew Chew /*
3ff859ba6SAndrew Chew  * An RTC driver for the NVIDIA Tegra 200 series internal RTC.
4ff859ba6SAndrew Chew  *
53e483e59SThierry Reding  * Copyright (c) 2010-2019, NVIDIA Corporation.
6ff859ba6SAndrew Chew  */
70ae20595SThierry Reding 
85fa40869SThierry Reding #include <linux/clk.h>
9ff859ba6SAndrew Chew #include <linux/delay.h>
100ae20595SThierry Reding #include <linux/init.h>
110ae20595SThierry Reding #include <linux/io.h>
120ae20595SThierry Reding #include <linux/irq.h>
130ae20595SThierry Reding #include <linux/kernel.h>
140ae20595SThierry Reding #include <linux/module.h>
15ac316725SRandy Dunlap #include <linux/mod_devicetable.h>
16ff859ba6SAndrew Chew #include <linux/platform_device.h>
173443ad09SLaxman Dewangan #include <linux/pm.h>
180ae20595SThierry Reding #include <linux/rtc.h>
190ae20595SThierry Reding #include <linux/slab.h>
20ff859ba6SAndrew Chew 
21a2d29238SThierry Reding /* Set to 1 = busy every eight 32 kHz clocks during copy of sec+msec to AHB. */
22ff859ba6SAndrew Chew #define TEGRA_RTC_REG_BUSY			0x004
23ff859ba6SAndrew Chew #define TEGRA_RTC_REG_SECONDS			0x008
24a2d29238SThierry Reding /* When msec is read, the seconds are buffered into shadow seconds. */
25ff859ba6SAndrew Chew #define TEGRA_RTC_REG_SHADOW_SECONDS		0x00c
26ff859ba6SAndrew Chew #define TEGRA_RTC_REG_MILLI_SECONDS		0x010
27ff859ba6SAndrew Chew #define TEGRA_RTC_REG_SECONDS_ALARM0		0x014
28ff859ba6SAndrew Chew #define TEGRA_RTC_REG_SECONDS_ALARM1		0x018
29ff859ba6SAndrew Chew #define TEGRA_RTC_REG_MILLI_SECONDS_ALARM0	0x01c
30ff859ba6SAndrew Chew #define TEGRA_RTC_REG_INTR_MASK			0x028
31ff859ba6SAndrew Chew /* write 1 bits to clear status bits */
32ff859ba6SAndrew Chew #define TEGRA_RTC_REG_INTR_STATUS		0x02c
33ff859ba6SAndrew Chew 
34ff859ba6SAndrew Chew /* bits in INTR_MASK */
35ff859ba6SAndrew Chew #define TEGRA_RTC_INTR_MASK_MSEC_CDN_ALARM	(1<<4)
36ff859ba6SAndrew Chew #define TEGRA_RTC_INTR_MASK_SEC_CDN_ALARM	(1<<3)
37ff859ba6SAndrew Chew #define TEGRA_RTC_INTR_MASK_MSEC_ALARM		(1<<2)
38ff859ba6SAndrew Chew #define TEGRA_RTC_INTR_MASK_SEC_ALARM1		(1<<1)
39ff859ba6SAndrew Chew #define TEGRA_RTC_INTR_MASK_SEC_ALARM0		(1<<0)
40ff859ba6SAndrew Chew 
41ff859ba6SAndrew Chew /* bits in INTR_STATUS */
42ff859ba6SAndrew Chew #define TEGRA_RTC_INTR_STATUS_MSEC_CDN_ALARM	(1<<4)
43ff859ba6SAndrew Chew #define TEGRA_RTC_INTR_STATUS_SEC_CDN_ALARM	(1<<3)
44ff859ba6SAndrew Chew #define TEGRA_RTC_INTR_STATUS_MSEC_ALARM	(1<<2)
45ff859ba6SAndrew Chew #define TEGRA_RTC_INTR_STATUS_SEC_ALARM1	(1<<1)
46ff859ba6SAndrew Chew #define TEGRA_RTC_INTR_STATUS_SEC_ALARM0	(1<<0)
47ff859ba6SAndrew Chew 
48ff859ba6SAndrew Chew struct tegra_rtc_info {
49ff859ba6SAndrew Chew 	struct platform_device *pdev;
50c6af561aSThierry Reding 	struct rtc_device *rtc;
51c6af561aSThierry Reding 	void __iomem *base; /* NULL if not initialized */
525fa40869SThierry Reding 	struct clk *clk;
53c6af561aSThierry Reding 	int irq; /* alarm and periodic IRQ */
54c6af561aSThierry Reding 	spinlock_t lock;
55ff859ba6SAndrew Chew };
56ff859ba6SAndrew Chew 
57a2d29238SThierry Reding /*
58a2d29238SThierry Reding  * RTC hardware is busy when it is updating its values over AHB once every
59a2d29238SThierry Reding  * eight 32 kHz clocks (~250 us). Outside of these updates the CPU is free to
60a2d29238SThierry Reding  * write. CPU is always free to read.
61ff859ba6SAndrew Chew  */
tegra_rtc_check_busy(struct tegra_rtc_info * info)62ff859ba6SAndrew Chew static inline u32 tegra_rtc_check_busy(struct tegra_rtc_info *info)
63ff859ba6SAndrew Chew {
64c6af561aSThierry Reding 	return readl(info->base + TEGRA_RTC_REG_BUSY) & 1;
65ff859ba6SAndrew Chew }
66ff859ba6SAndrew Chew 
67a2d29238SThierry Reding /*
68a2d29238SThierry Reding  * Wait for hardware to be ready for writing. This function tries to maximize
69a2d29238SThierry Reding  * the amount of time before the next update. It does this by waiting for the
70a2d29238SThierry Reding  * RTC to become busy with its periodic update, then returning once the RTC
71a2d29238SThierry Reding  * first becomes not busy.
72a2d29238SThierry Reding  *
73ff859ba6SAndrew Chew  * This periodic update (where the seconds and milliseconds are copied to the
74a2d29238SThierry Reding  * AHB side) occurs every eight 32 kHz clocks (~250 us). The behavior of this
75a2d29238SThierry Reding  * function allows us to make some assumptions without introducing a race,
76a2d29238SThierry Reding  * because 250 us is plenty of time to read/write a value.
77ff859ba6SAndrew Chew  */
tegra_rtc_wait_while_busy(struct device * dev)78ff859ba6SAndrew Chew static int tegra_rtc_wait_while_busy(struct device *dev)
79ff859ba6SAndrew Chew {
80ff859ba6SAndrew Chew 	struct tegra_rtc_info *info = dev_get_drvdata(dev);
81a2d29238SThierry Reding 	int retries = 500; /* ~490 us is the worst case, ~250 us is best */
82ff859ba6SAndrew Chew 
83a2d29238SThierry Reding 	/*
84a2d29238SThierry Reding 	 * First wait for the RTC to become busy. This is when it posts its
85a2d29238SThierry Reding 	 * updated seconds+msec registers to AHB side.
86a2d29238SThierry Reding 	 */
87ff859ba6SAndrew Chew 	while (tegra_rtc_check_busy(info)) {
88ff859ba6SAndrew Chew 		if (!retries--)
89ff859ba6SAndrew Chew 			goto retry_failed;
90a2d29238SThierry Reding 
91ff859ba6SAndrew Chew 		udelay(1);
92ff859ba6SAndrew Chew 	}
93ff859ba6SAndrew Chew 
94ff859ba6SAndrew Chew 	/* now we have about 250 us to manipulate registers */
95ff859ba6SAndrew Chew 	return 0;
96ff859ba6SAndrew Chew 
97ff859ba6SAndrew Chew retry_failed:
98a2d29238SThierry Reding 	dev_err(dev, "write failed: retry count exceeded\n");
99ff859ba6SAndrew Chew 	return -ETIMEDOUT;
100ff859ba6SAndrew Chew }
101ff859ba6SAndrew Chew 
tegra_rtc_read_time(struct device * dev,struct rtc_time * tm)102ff859ba6SAndrew Chew static int tegra_rtc_read_time(struct device *dev, struct rtc_time *tm)
103ff859ba6SAndrew Chew {
104ff859ba6SAndrew Chew 	struct tegra_rtc_info *info = dev_get_drvdata(dev);
105c6af561aSThierry Reding 	unsigned long flags;
1068321c2ecSAlexandre Belloni 	u32 sec;
107ff859ba6SAndrew Chew 
108a2d29238SThierry Reding 	/*
109a2d29238SThierry Reding 	 * RTC hardware copies seconds to shadow seconds when a read of
110a2d29238SThierry Reding 	 * milliseconds occurs. use a lock to keep other threads out.
111a2d29238SThierry Reding 	 */
112c6af561aSThierry Reding 	spin_lock_irqsave(&info->lock, flags);
113ff859ba6SAndrew Chew 
1148321c2ecSAlexandre Belloni 	readl(info->base + TEGRA_RTC_REG_MILLI_SECONDS);
115c6af561aSThierry Reding 	sec = readl(info->base + TEGRA_RTC_REG_SHADOW_SECONDS);
116ff859ba6SAndrew Chew 
117c6af561aSThierry Reding 	spin_unlock_irqrestore(&info->lock, flags);
118ff859ba6SAndrew Chew 
11934ea0ac3SAlexandre Belloni 	rtc_time64_to_tm(sec, tm);
120ff859ba6SAndrew Chew 
121a2d29238SThierry Reding 	dev_vdbg(dev, "time read as %u, %ptR\n", sec, tm);
122ff859ba6SAndrew Chew 
123ff859ba6SAndrew Chew 	return 0;
124ff859ba6SAndrew Chew }
125ff859ba6SAndrew Chew 
tegra_rtc_set_time(struct device * dev,struct rtc_time * tm)126ff859ba6SAndrew Chew static int tegra_rtc_set_time(struct device *dev, struct rtc_time *tm)
127ff859ba6SAndrew Chew {
128ff859ba6SAndrew Chew 	struct tegra_rtc_info *info = dev_get_drvdata(dev);
129c6af561aSThierry Reding 	u32 sec;
130ff859ba6SAndrew Chew 	int ret;
131ff859ba6SAndrew Chew 
132a2d29238SThierry Reding 	/* convert tm to seconds */
13334ea0ac3SAlexandre Belloni 	sec = rtc_tm_to_time64(tm);
134ff859ba6SAndrew Chew 
135a2d29238SThierry Reding 	dev_vdbg(dev, "time set to %u, %ptR\n", sec, tm);
136ff859ba6SAndrew Chew 
137a2d29238SThierry Reding 	/* seconds only written if wait succeeded */
138ff859ba6SAndrew Chew 	ret = tegra_rtc_wait_while_busy(dev);
139ff859ba6SAndrew Chew 	if (!ret)
140c6af561aSThierry Reding 		writel(sec, info->base + TEGRA_RTC_REG_SECONDS);
141ff859ba6SAndrew Chew 
142ff859ba6SAndrew Chew 	dev_vdbg(dev, "time read back as %d\n",
143c6af561aSThierry Reding 		 readl(info->base + TEGRA_RTC_REG_SECONDS));
144ff859ba6SAndrew Chew 
145ff859ba6SAndrew Chew 	return ret;
146ff859ba6SAndrew Chew }
147ff859ba6SAndrew Chew 
tegra_rtc_read_alarm(struct device * dev,struct rtc_wkalrm * alarm)148ff859ba6SAndrew Chew static int tegra_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
149ff859ba6SAndrew Chew {
150ff859ba6SAndrew Chew 	struct tegra_rtc_info *info = dev_get_drvdata(dev);
151c6af561aSThierry Reding 	u32 sec, value;
152ff859ba6SAndrew Chew 
153c6af561aSThierry Reding 	sec = readl(info->base + TEGRA_RTC_REG_SECONDS_ALARM0);
154ff859ba6SAndrew Chew 
155ff859ba6SAndrew Chew 	if (sec == 0) {
156a2d29238SThierry Reding 		/* alarm is disabled */
157ff859ba6SAndrew Chew 		alarm->enabled = 0;
158ff859ba6SAndrew Chew 	} else {
159a2d29238SThierry Reding 		/* alarm is enabled */
160ff859ba6SAndrew Chew 		alarm->enabled = 1;
16134ea0ac3SAlexandre Belloni 		rtc_time64_to_tm(sec, &alarm->time);
162ff859ba6SAndrew Chew 	}
163ff859ba6SAndrew Chew 
164c6af561aSThierry Reding 	value = readl(info->base + TEGRA_RTC_REG_INTR_STATUS);
165c6af561aSThierry Reding 	alarm->pending = (value & TEGRA_RTC_INTR_STATUS_SEC_ALARM0) != 0;
166ff859ba6SAndrew Chew 
167ff859ba6SAndrew Chew 	return 0;
168ff859ba6SAndrew Chew }
169ff859ba6SAndrew Chew 
tegra_rtc_alarm_irq_enable(struct device * dev,unsigned int enabled)170ff859ba6SAndrew Chew static int tegra_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
171ff859ba6SAndrew Chew {
172ff859ba6SAndrew Chew 	struct tegra_rtc_info *info = dev_get_drvdata(dev);
173c6af561aSThierry Reding 	unsigned long flags;
174c6af561aSThierry Reding 	u32 status;
175ff859ba6SAndrew Chew 
176ff859ba6SAndrew Chew 	tegra_rtc_wait_while_busy(dev);
177c6af561aSThierry Reding 	spin_lock_irqsave(&info->lock, flags);
178ff859ba6SAndrew Chew 
179a2d29238SThierry Reding 	/* read the original value, and OR in the flag */
180c6af561aSThierry Reding 	status = readl(info->base + TEGRA_RTC_REG_INTR_MASK);
181ff859ba6SAndrew Chew 	if (enabled)
182ff859ba6SAndrew Chew 		status |= TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* set it */
183ff859ba6SAndrew Chew 	else
184ff859ba6SAndrew Chew 		status &= ~TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* clear it */
185ff859ba6SAndrew Chew 
186c6af561aSThierry Reding 	writel(status, info->base + TEGRA_RTC_REG_INTR_MASK);
187ff859ba6SAndrew Chew 
188c6af561aSThierry Reding 	spin_unlock_irqrestore(&info->lock, flags);
189ff859ba6SAndrew Chew 
190ff859ba6SAndrew Chew 	return 0;
191ff859ba6SAndrew Chew }
192ff859ba6SAndrew Chew 
tegra_rtc_set_alarm(struct device * dev,struct rtc_wkalrm * alarm)193ff859ba6SAndrew Chew static int tegra_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
194ff859ba6SAndrew Chew {
195ff859ba6SAndrew Chew 	struct tegra_rtc_info *info = dev_get_drvdata(dev);
196c6af561aSThierry Reding 	u32 sec;
197ff859ba6SAndrew Chew 
198ff859ba6SAndrew Chew 	if (alarm->enabled)
19934ea0ac3SAlexandre Belloni 		sec = rtc_tm_to_time64(&alarm->time);
200ff859ba6SAndrew Chew 	else
201ff859ba6SAndrew Chew 		sec = 0;
202ff859ba6SAndrew Chew 
203ff859ba6SAndrew Chew 	tegra_rtc_wait_while_busy(dev);
204c6af561aSThierry Reding 	writel(sec, info->base + TEGRA_RTC_REG_SECONDS_ALARM0);
205ff859ba6SAndrew Chew 	dev_vdbg(dev, "alarm read back as %d\n",
206c6af561aSThierry Reding 		 readl(info->base + TEGRA_RTC_REG_SECONDS_ALARM0));
207ff859ba6SAndrew Chew 
208ff859ba6SAndrew Chew 	/* if successfully written and alarm is enabled ... */
209ff859ba6SAndrew Chew 	if (sec) {
210ff859ba6SAndrew Chew 		tegra_rtc_alarm_irq_enable(dev, 1);
211a2d29238SThierry Reding 		dev_vdbg(dev, "alarm set as %u, %ptR\n", sec, &alarm->time);
212ff859ba6SAndrew Chew 	} else {
213a2d29238SThierry Reding 		/* disable alarm if 0 or write error */
214ff859ba6SAndrew Chew 		dev_vdbg(dev, "alarm disabled\n");
215ff859ba6SAndrew Chew 		tegra_rtc_alarm_irq_enable(dev, 0);
216ff859ba6SAndrew Chew 	}
217ff859ba6SAndrew Chew 
218ff859ba6SAndrew Chew 	return 0;
219ff859ba6SAndrew Chew }
220ff859ba6SAndrew Chew 
tegra_rtc_proc(struct device * dev,struct seq_file * seq)221ff859ba6SAndrew Chew static int tegra_rtc_proc(struct device *dev, struct seq_file *seq)
222ff859ba6SAndrew Chew {
223ff859ba6SAndrew Chew 	if (!dev || !dev->driver)
224ff859ba6SAndrew Chew 		return 0;
225ff859ba6SAndrew Chew 
2264395eb1fSJoe Perches 	seq_printf(seq, "name\t\t: %s\n", dev_name(dev));
2274395eb1fSJoe Perches 
2284395eb1fSJoe Perches 	return 0;
229ff859ba6SAndrew Chew }
230ff859ba6SAndrew Chew 
tegra_rtc_irq_handler(int irq,void * data)231ff859ba6SAndrew Chew static irqreturn_t tegra_rtc_irq_handler(int irq, void *data)
232ff859ba6SAndrew Chew {
233ff859ba6SAndrew Chew 	struct device *dev = data;
234ff859ba6SAndrew Chew 	struct tegra_rtc_info *info = dev_get_drvdata(dev);
235669022c2SXiaofei Tan 	unsigned long events = 0;
236c6af561aSThierry Reding 	u32 status;
237ff859ba6SAndrew Chew 
238c6af561aSThierry Reding 	status = readl(info->base + TEGRA_RTC_REG_INTR_STATUS);
239ff859ba6SAndrew Chew 	if (status) {
240a2d29238SThierry Reding 		/* clear the interrupt masks and status on any IRQ */
241ff859ba6SAndrew Chew 		tegra_rtc_wait_while_busy(dev);
242a2d29238SThierry Reding 
243669022c2SXiaofei Tan 		spin_lock(&info->lock);
244c6af561aSThierry Reding 		writel(0, info->base + TEGRA_RTC_REG_INTR_MASK);
245c6af561aSThierry Reding 		writel(status, info->base + TEGRA_RTC_REG_INTR_STATUS);
246669022c2SXiaofei Tan 		spin_unlock(&info->lock);
247ff859ba6SAndrew Chew 	}
248ff859ba6SAndrew Chew 
249a2d29238SThierry Reding 	/* check if alarm */
250a2d29238SThierry Reding 	if (status & TEGRA_RTC_INTR_STATUS_SEC_ALARM0)
251ff859ba6SAndrew Chew 		events |= RTC_IRQF | RTC_AF;
252ff859ba6SAndrew Chew 
253a2d29238SThierry Reding 	/* check if periodic */
254a2d29238SThierry Reding 	if (status & TEGRA_RTC_INTR_STATUS_SEC_CDN_ALARM)
255ff859ba6SAndrew Chew 		events |= RTC_IRQF | RTC_PF;
256ff859ba6SAndrew Chew 
257c6af561aSThierry Reding 	rtc_update_irq(info->rtc, 1, events);
258ff859ba6SAndrew Chew 
259ff859ba6SAndrew Chew 	return IRQ_HANDLED;
260ff859ba6SAndrew Chew }
261ff859ba6SAndrew Chew 
26234c7b3acSJulia Lawall static const struct rtc_class_ops tegra_rtc_ops = {
263ff859ba6SAndrew Chew 	.read_time = tegra_rtc_read_time,
264ff859ba6SAndrew Chew 	.set_time = tegra_rtc_set_time,
265ff859ba6SAndrew Chew 	.read_alarm = tegra_rtc_read_alarm,
266ff859ba6SAndrew Chew 	.set_alarm = tegra_rtc_set_alarm,
267ff859ba6SAndrew Chew 	.proc = tegra_rtc_proc,
268ff859ba6SAndrew Chew 	.alarm_irq_enable = tegra_rtc_alarm_irq_enable,
269ff859ba6SAndrew Chew };
270ff859ba6SAndrew Chew 
2712d79cf8aSJoseph Lo static const struct of_device_id tegra_rtc_dt_match[] = {
2722d79cf8aSJoseph Lo 	{ .compatible = "nvidia,tegra20-rtc", },
2732d79cf8aSJoseph Lo 	{}
2742d79cf8aSJoseph Lo };
2752d79cf8aSJoseph Lo MODULE_DEVICE_TABLE(of, tegra_rtc_dt_match);
2762d79cf8aSJoseph Lo 
tegra_rtc_probe(struct platform_device * pdev)2773e483e59SThierry Reding static int tegra_rtc_probe(struct platform_device *pdev)
278ff859ba6SAndrew Chew {
279ff859ba6SAndrew Chew 	struct tegra_rtc_info *info;
280ff859ba6SAndrew Chew 	int ret;
281ff859ba6SAndrew Chew 
282a2d29238SThierry Reding 	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
283ff859ba6SAndrew Chew 	if (!info)
284ff859ba6SAndrew Chew 		return -ENOMEM;
285ff859ba6SAndrew Chew 
28609ef18bcSYueHaibing 	info->base = devm_platform_ioremap_resource(pdev, 0);
287c6af561aSThierry Reding 	if (IS_ERR(info->base))
288c6af561aSThierry Reding 		return PTR_ERR(info->base);
289ff859ba6SAndrew Chew 
290fe0b5cedSThierry Reding 	ret = platform_get_irq(pdev, 0);
291faac9102SStephen Boyd 	if (ret <= 0)
292fe0b5cedSThierry Reding 		return ret;
293fe0b5cedSThierry Reding 
294c6af561aSThierry Reding 	info->irq = ret;
295ff859ba6SAndrew Chew 
296c6af561aSThierry Reding 	info->rtc = devm_rtc_allocate_device(&pdev->dev);
297c6af561aSThierry Reding 	if (IS_ERR(info->rtc))
298c6af561aSThierry Reding 		return PTR_ERR(info->rtc);
299e1089802SAlexandre Belloni 
300c6af561aSThierry Reding 	info->rtc->ops = &tegra_rtc_ops;
301c6af561aSThierry Reding 	info->rtc->range_max = U32_MAX;
302e1089802SAlexandre Belloni 
3035fa40869SThierry Reding 	info->clk = devm_clk_get(&pdev->dev, NULL);
3045fa40869SThierry Reding 	if (IS_ERR(info->clk))
3055fa40869SThierry Reding 		return PTR_ERR(info->clk);
3065fa40869SThierry Reding 
3075fa40869SThierry Reding 	ret = clk_prepare_enable(info->clk);
3085fa40869SThierry Reding 	if (ret < 0)
3095fa40869SThierry Reding 		return ret;
3105fa40869SThierry Reding 
311a2d29238SThierry Reding 	/* set context info */
312ff859ba6SAndrew Chew 	info->pdev = pdev;
313c6af561aSThierry Reding 	spin_lock_init(&info->lock);
314ff859ba6SAndrew Chew 
315ff859ba6SAndrew Chew 	platform_set_drvdata(pdev, info);
316ff859ba6SAndrew Chew 
317a2d29238SThierry Reding 	/* clear out the hardware */
318c6af561aSThierry Reding 	writel(0, info->base + TEGRA_RTC_REG_SECONDS_ALARM0);
319c6af561aSThierry Reding 	writel(0xffffffff, info->base + TEGRA_RTC_REG_INTR_STATUS);
320c6af561aSThierry Reding 	writel(0, info->base + TEGRA_RTC_REG_INTR_MASK);
321ff859ba6SAndrew Chew 
322ff859ba6SAndrew Chew 	device_init_wakeup(&pdev->dev, 1);
323ff859ba6SAndrew Chew 
324c6af561aSThierry Reding 	ret = devm_request_irq(&pdev->dev, info->irq, tegra_rtc_irq_handler,
325c6af561aSThierry Reding 			       IRQF_TRIGGER_HIGH, dev_name(&pdev->dev),
326c6af561aSThierry Reding 			       &pdev->dev);
327ff859ba6SAndrew Chew 	if (ret) {
328a2d29238SThierry Reding 		dev_err(&pdev->dev, "failed to request interrupt: %d\n", ret);
3295fa40869SThierry Reding 		goto disable_clk;
330ff859ba6SAndrew Chew 	}
331ff859ba6SAndrew Chew 
332fdcfd854SBartosz Golaszewski 	ret = devm_rtc_register_device(info->rtc);
33344c638ceSAlexandre Belloni 	if (ret)
334e1089802SAlexandre Belloni 		goto disable_clk;
335e1089802SAlexandre Belloni 
33668567112SLaxman Dewangan 	dev_notice(&pdev->dev, "Tegra internal Real Time Clock\n");
337ff859ba6SAndrew Chew 
338ff859ba6SAndrew Chew 	return 0;
3395fa40869SThierry Reding 
3405fa40869SThierry Reding disable_clk:
3415fa40869SThierry Reding 	clk_disable_unprepare(info->clk);
3425fa40869SThierry Reding 	return ret;
3435fa40869SThierry Reding }
3445fa40869SThierry Reding 
tegra_rtc_remove(struct platform_device * pdev)345*31c94505SUwe Kleine-König static void tegra_rtc_remove(struct platform_device *pdev)
3465fa40869SThierry Reding {
3475fa40869SThierry Reding 	struct tegra_rtc_info *info = platform_get_drvdata(pdev);
3485fa40869SThierry Reding 
3495fa40869SThierry Reding 	clk_disable_unprepare(info->clk);
350ff859ba6SAndrew Chew }
351ff859ba6SAndrew Chew 
35238a6276eSLaxman Dewangan #ifdef CONFIG_PM_SLEEP
tegra_rtc_suspend(struct device * dev)3533443ad09SLaxman Dewangan static int tegra_rtc_suspend(struct device *dev)
354ff859ba6SAndrew Chew {
3553443ad09SLaxman Dewangan 	struct tegra_rtc_info *info = dev_get_drvdata(dev);
356ff859ba6SAndrew Chew 
357ff859ba6SAndrew Chew 	tegra_rtc_wait_while_busy(dev);
358ff859ba6SAndrew Chew 
359a2d29238SThierry Reding 	/* only use ALARM0 as a wake source */
360c6af561aSThierry Reding 	writel(0xffffffff, info->base + TEGRA_RTC_REG_INTR_STATUS);
361ff859ba6SAndrew Chew 	writel(TEGRA_RTC_INTR_STATUS_SEC_ALARM0,
362c6af561aSThierry Reding 	       info->base + TEGRA_RTC_REG_INTR_MASK);
363ff859ba6SAndrew Chew 
364ff859ba6SAndrew Chew 	dev_vdbg(dev, "alarm sec = %d\n",
365c6af561aSThierry Reding 		 readl(info->base + TEGRA_RTC_REG_SECONDS_ALARM0));
366ff859ba6SAndrew Chew 
367a2d29238SThierry Reding 	dev_vdbg(dev, "Suspend (device_may_wakeup=%d) IRQ:%d\n",
368c6af561aSThierry Reding 		 device_may_wakeup(dev), info->irq);
369ff859ba6SAndrew Chew 
370a2d29238SThierry Reding 	/* leave the alarms on as a wake source */
371ff859ba6SAndrew Chew 	if (device_may_wakeup(dev))
372c6af561aSThierry Reding 		enable_irq_wake(info->irq);
373ff859ba6SAndrew Chew 
374ff859ba6SAndrew Chew 	return 0;
375ff859ba6SAndrew Chew }
376ff859ba6SAndrew Chew 
tegra_rtc_resume(struct device * dev)3773443ad09SLaxman Dewangan static int tegra_rtc_resume(struct device *dev)
378ff859ba6SAndrew Chew {
3793443ad09SLaxman Dewangan 	struct tegra_rtc_info *info = dev_get_drvdata(dev);
380ff859ba6SAndrew Chew 
381ff859ba6SAndrew Chew 	dev_vdbg(dev, "Resume (device_may_wakeup=%d)\n",
382ff859ba6SAndrew Chew 		 device_may_wakeup(dev));
383a2d29238SThierry Reding 
384a2d29238SThierry Reding 	/* alarms were left on as a wake source, turn them off */
385ff859ba6SAndrew Chew 	if (device_may_wakeup(dev))
386c6af561aSThierry Reding 		disable_irq_wake(info->irq);
387ff859ba6SAndrew Chew 
388ff859ba6SAndrew Chew 	return 0;
389ff859ba6SAndrew Chew }
390ff859ba6SAndrew Chew #endif
391ff859ba6SAndrew Chew 
3923443ad09SLaxman Dewangan static SIMPLE_DEV_PM_OPS(tegra_rtc_pm_ops, tegra_rtc_suspend, tegra_rtc_resume);
3933443ad09SLaxman Dewangan 
tegra_rtc_shutdown(struct platform_device * pdev)394ff859ba6SAndrew Chew static void tegra_rtc_shutdown(struct platform_device *pdev)
395ff859ba6SAndrew Chew {
396a2d29238SThierry Reding 	dev_vdbg(&pdev->dev, "disabling interrupts\n");
397ff859ba6SAndrew Chew 	tegra_rtc_alarm_irq_enable(&pdev->dev, 0);
398ff859ba6SAndrew Chew }
399ff859ba6SAndrew Chew 
400ff859ba6SAndrew Chew static struct platform_driver tegra_rtc_driver = {
4013e483e59SThierry Reding 	.probe = tegra_rtc_probe,
402*31c94505SUwe Kleine-König 	.remove_new = tegra_rtc_remove,
403ff859ba6SAndrew Chew 	.shutdown = tegra_rtc_shutdown,
404ff859ba6SAndrew Chew 	.driver = {
405ff859ba6SAndrew Chew 		.name = "tegra_rtc",
4062d79cf8aSJoseph Lo 		.of_match_table = tegra_rtc_dt_match,
4073443ad09SLaxman Dewangan 		.pm = &tegra_rtc_pm_ops,
408ff859ba6SAndrew Chew 	},
409ff859ba6SAndrew Chew };
4103e483e59SThierry Reding module_platform_driver(tegra_rtc_driver);
411ff859ba6SAndrew Chew 
412ff859ba6SAndrew Chew MODULE_AUTHOR("Jon Mayo <jmayo@nvidia.com>");
413ff859ba6SAndrew Chew MODULE_DESCRIPTION("driver for Tegra internal RTC");
414ff859ba6SAndrew Chew MODULE_LICENSE("GPL");
415