Blame view

drivers/rtc/rtc-tegra.c 10.7 KB
b6838275b   Alexandre Belloni   rtc: tegra: conve...
1
  // SPDX-License-Identifier: GPL-2.0+
ff859ba6d   Andrew Chew   rtc: add real-tim...
2
3
4
  /*
   * An RTC driver for the NVIDIA Tegra 200 series internal RTC.
   *
3e483e59c   Thierry Reding   rtc: tegra: Turn ...
5
   * Copyright (c) 2010-2019, NVIDIA Corporation.
ff859ba6d   Andrew Chew   rtc: add real-tim...
6
   */
0ae20595e   Thierry Reding   rtc: tegra: Sort ...
7

5fa408698   Thierry Reding   rtc: tegra: Imple...
8
  #include <linux/clk.h>
0ae20595e   Thierry Reding   rtc: tegra: Sort ...
9
  #include <linux/delay.h>
ff859ba6d   Andrew Chew   rtc: add real-tim...
10
  #include <linux/init.h>
ff859ba6d   Andrew Chew   rtc: add real-tim...
11
  #include <linux/io.h>
0ae20595e   Thierry Reding   rtc: tegra: Sort ...
12
13
14
  #include <linux/irq.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
ac3167257   Randy Dunlap   headers: separate...
15
  #include <linux/mod_devicetable.h>
ff859ba6d   Andrew Chew   rtc: add real-tim...
16
  #include <linux/platform_device.h>
3443ad095   Laxman Dewangan   drivers/rtc/rtc-t...
17
  #include <linux/pm.h>
0ae20595e   Thierry Reding   rtc: tegra: Sort ...
18
19
  #include <linux/rtc.h>
  #include <linux/slab.h>
ff859ba6d   Andrew Chew   rtc: add real-tim...
20

a2d29238b   Thierry Reding   rtc: tegra: check...
21
  /* Set to 1 = busy every eight 32 kHz clocks during copy of sec+msec to AHB. */
ff859ba6d   Andrew Chew   rtc: add real-tim...
22
23
  #define TEGRA_RTC_REG_BUSY			0x004
  #define TEGRA_RTC_REG_SECONDS			0x008
a2d29238b   Thierry Reding   rtc: tegra: check...
24
  /* When msec is read, the seconds are buffered into shadow seconds. */
ff859ba6d   Andrew Chew   rtc: add real-tim...
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
  #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_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)
  
  struct tegra_rtc_info {
a2d29238b   Thierry Reding   rtc: tegra: check...
49
  	struct platform_device *pdev;
c6af561a4   Thierry Reding   rtc: tegra: Use c...
50
51
  	struct rtc_device *rtc;
  	void __iomem *base; /* NULL if not initialized */
a2d29238b   Thierry Reding   rtc: tegra: check...
52
  	struct clk *clk;
c6af561a4   Thierry Reding   rtc: tegra: Use c...
53
54
  	int irq; /* alarm and periodic IRQ */
  	spinlock_t lock;
ff859ba6d   Andrew Chew   rtc: add real-tim...
55
  };
a2d29238b   Thierry Reding   rtc: tegra: check...
56
57
58
59
  /*
   * RTC hardware is busy when it is updating its values over AHB once every
   * eight 32 kHz clocks (~250 us). Outside of these updates the CPU is free to
   * write. CPU is always free to read.
ff859ba6d   Andrew Chew   rtc: add real-tim...
60
61
62
   */
  static inline u32 tegra_rtc_check_busy(struct tegra_rtc_info *info)
  {
c6af561a4   Thierry Reding   rtc: tegra: Use c...
63
  	return readl(info->base + TEGRA_RTC_REG_BUSY) & 1;
ff859ba6d   Andrew Chew   rtc: add real-tim...
64
  }
a2d29238b   Thierry Reding   rtc: tegra: check...
65
66
67
68
69
70
  /*
   * 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.
   *
ff859ba6d   Andrew Chew   rtc: add real-tim...
71
   * This periodic update (where the seconds and milliseconds are copied to the
a2d29238b   Thierry Reding   rtc: tegra: check...
72
73
74
   * AHB side) occurs every eight 32 kHz clocks (~250 us). The behavior of this
   * function allows us to make some assumptions without introducing a race,
   * because 250 us is plenty of time to read/write a value.
ff859ba6d   Andrew Chew   rtc: add real-tim...
75
76
77
78
   */
  static int tegra_rtc_wait_while_busy(struct device *dev)
  {
  	struct tegra_rtc_info *info = dev_get_drvdata(dev);
a2d29238b   Thierry Reding   rtc: tegra: check...
79
  	int retries = 500; /* ~490 us is the worst case, ~250 us is best */
ff859ba6d   Andrew Chew   rtc: add real-tim...
80

a2d29238b   Thierry Reding   rtc: tegra: check...
81
82
83
84
  	/*
  	 * First wait for the RTC to become busy. This is when it posts its
  	 * updated seconds+msec registers to AHB side.
  	 */
ff859ba6d   Andrew Chew   rtc: add real-tim...
85
86
87
  	while (tegra_rtc_check_busy(info)) {
  		if (!retries--)
  			goto retry_failed;
a2d29238b   Thierry Reding   rtc: tegra: check...
88

ff859ba6d   Andrew Chew   rtc: add real-tim...
89
90
91
92
93
94
95
  		udelay(1);
  	}
  
  	/* now we have about 250 us to manipulate registers */
  	return 0;
  
  retry_failed:
a2d29238b   Thierry Reding   rtc: tegra: check...
96
97
  	dev_err(dev, "write failed: retry count exceeded
  ");
ff859ba6d   Andrew Chew   rtc: add real-tim...
98
99
100
101
102
103
  	return -ETIMEDOUT;
  }
  
  static int tegra_rtc_read_time(struct device *dev, struct rtc_time *tm)
  {
  	struct tegra_rtc_info *info = dev_get_drvdata(dev);
c6af561a4   Thierry Reding   rtc: tegra: Use c...
104
  	unsigned long flags;
8321c2ecb   Alexandre Belloni   rtc: tegra: remov...
105
  	u32 sec;
ff859ba6d   Andrew Chew   rtc: add real-tim...
106

a2d29238b   Thierry Reding   rtc: tegra: check...
107
108
109
110
  	/*
  	 * RTC hardware copies seconds to shadow seconds when a read of
  	 * milliseconds occurs. use a lock to keep other threads out.
  	 */
c6af561a4   Thierry Reding   rtc: tegra: Use c...
111
  	spin_lock_irqsave(&info->lock, flags);
ff859ba6d   Andrew Chew   rtc: add real-tim...
112

8321c2ecb   Alexandre Belloni   rtc: tegra: remov...
113
  	readl(info->base + TEGRA_RTC_REG_MILLI_SECONDS);
c6af561a4   Thierry Reding   rtc: tegra: Use c...
114
  	sec = readl(info->base + TEGRA_RTC_REG_SHADOW_SECONDS);
ff859ba6d   Andrew Chew   rtc: add real-tim...
115

c6af561a4   Thierry Reding   rtc: tegra: Use c...
116
  	spin_unlock_irqrestore(&info->lock, flags);
ff859ba6d   Andrew Chew   rtc: add real-tim...
117

34ea0ac3e   Alexandre Belloni   rtc: tegra: switc...
118
  	rtc_time64_to_tm(sec, tm);
ff859ba6d   Andrew Chew   rtc: add real-tim...
119

a2d29238b   Thierry Reding   rtc: tegra: check...
120
121
  	dev_vdbg(dev, "time read as %u, %ptR
  ", sec, tm);
ff859ba6d   Andrew Chew   rtc: add real-tim...
122
123
124
125
126
127
128
  
  	return 0;
  }
  
  static int tegra_rtc_set_time(struct device *dev, struct rtc_time *tm)
  {
  	struct tegra_rtc_info *info = dev_get_drvdata(dev);
c6af561a4   Thierry Reding   rtc: tegra: Use c...
129
  	u32 sec;
ff859ba6d   Andrew Chew   rtc: add real-tim...
130
  	int ret;
a2d29238b   Thierry Reding   rtc: tegra: check...
131
  	/* convert tm to seconds */
34ea0ac3e   Alexandre Belloni   rtc: tegra: switc...
132
  	sec = rtc_tm_to_time64(tm);
ff859ba6d   Andrew Chew   rtc: add real-tim...
133

a2d29238b   Thierry Reding   rtc: tegra: check...
134
135
  	dev_vdbg(dev, "time set to %u, %ptR
  ", sec, tm);
ff859ba6d   Andrew Chew   rtc: add real-tim...
136

a2d29238b   Thierry Reding   rtc: tegra: check...
137
  	/* seconds only written if wait succeeded */
ff859ba6d   Andrew Chew   rtc: add real-tim...
138
139
  	ret = tegra_rtc_wait_while_busy(dev);
  	if (!ret)
c6af561a4   Thierry Reding   rtc: tegra: Use c...
140
  		writel(sec, info->base + TEGRA_RTC_REG_SECONDS);
ff859ba6d   Andrew Chew   rtc: add real-tim...
141
142
143
  
  	dev_vdbg(dev, "time read back as %d
  ",
c6af561a4   Thierry Reding   rtc: tegra: Use c...
144
  		 readl(info->base + TEGRA_RTC_REG_SECONDS));
ff859ba6d   Andrew Chew   rtc: add real-tim...
145
146
147
148
149
150
151
  
  	return ret;
  }
  
  static int tegra_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
  {
  	struct tegra_rtc_info *info = dev_get_drvdata(dev);
c6af561a4   Thierry Reding   rtc: tegra: Use c...
152
  	u32 sec, value;
ff859ba6d   Andrew Chew   rtc: add real-tim...
153

c6af561a4   Thierry Reding   rtc: tegra: Use c...
154
  	sec = readl(info->base + TEGRA_RTC_REG_SECONDS_ALARM0);
ff859ba6d   Andrew Chew   rtc: add real-tim...
155
156
  
  	if (sec == 0) {
a2d29238b   Thierry Reding   rtc: tegra: check...
157
  		/* alarm is disabled */
ff859ba6d   Andrew Chew   rtc: add real-tim...
158
  		alarm->enabled = 0;
ff859ba6d   Andrew Chew   rtc: add real-tim...
159
  	} else {
a2d29238b   Thierry Reding   rtc: tegra: check...
160
  		/* alarm is enabled */
ff859ba6d   Andrew Chew   rtc: add real-tim...
161
  		alarm->enabled = 1;
34ea0ac3e   Alexandre Belloni   rtc: tegra: switc...
162
  		rtc_time64_to_tm(sec, &alarm->time);
ff859ba6d   Andrew Chew   rtc: add real-tim...
163
  	}
c6af561a4   Thierry Reding   rtc: tegra: Use c...
164
165
  	value = readl(info->base + TEGRA_RTC_REG_INTR_STATUS);
  	alarm->pending = (value & TEGRA_RTC_INTR_STATUS_SEC_ALARM0) != 0;
ff859ba6d   Andrew Chew   rtc: add real-tim...
166
167
168
169
170
171
172
  
  	return 0;
  }
  
  static int tegra_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
  {
  	struct tegra_rtc_info *info = dev_get_drvdata(dev);
c6af561a4   Thierry Reding   rtc: tegra: Use c...
173
174
  	unsigned long flags;
  	u32 status;
ff859ba6d   Andrew Chew   rtc: add real-tim...
175
176
  
  	tegra_rtc_wait_while_busy(dev);
c6af561a4   Thierry Reding   rtc: tegra: Use c...
177
  	spin_lock_irqsave(&info->lock, flags);
ff859ba6d   Andrew Chew   rtc: add real-tim...
178

a2d29238b   Thierry Reding   rtc: tegra: check...
179
  	/* read the original value, and OR in the flag */
c6af561a4   Thierry Reding   rtc: tegra: Use c...
180
  	status = readl(info->base + TEGRA_RTC_REG_INTR_MASK);
ff859ba6d   Andrew Chew   rtc: add real-tim...
181
182
183
184
  	if (enabled)
  		status |= TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* set it */
  	else
  		status &= ~TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* clear it */
c6af561a4   Thierry Reding   rtc: tegra: Use c...
185
  	writel(status, info->base + TEGRA_RTC_REG_INTR_MASK);
ff859ba6d   Andrew Chew   rtc: add real-tim...
186

c6af561a4   Thierry Reding   rtc: tegra: Use c...
187
  	spin_unlock_irqrestore(&info->lock, flags);
ff859ba6d   Andrew Chew   rtc: add real-tim...
188
189
190
191
192
193
194
  
  	return 0;
  }
  
  static int tegra_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
  {
  	struct tegra_rtc_info *info = dev_get_drvdata(dev);
c6af561a4   Thierry Reding   rtc: tegra: Use c...
195
  	u32 sec;
ff859ba6d   Andrew Chew   rtc: add real-tim...
196
197
  
  	if (alarm->enabled)
34ea0ac3e   Alexandre Belloni   rtc: tegra: switc...
198
  		sec = rtc_tm_to_time64(&alarm->time);
ff859ba6d   Andrew Chew   rtc: add real-tim...
199
200
201
202
  	else
  		sec = 0;
  
  	tegra_rtc_wait_while_busy(dev);
c6af561a4   Thierry Reding   rtc: tegra: Use c...
203
  	writel(sec, info->base + TEGRA_RTC_REG_SECONDS_ALARM0);
ff859ba6d   Andrew Chew   rtc: add real-tim...
204
205
  	dev_vdbg(dev, "alarm read back as %d
  ",
c6af561a4   Thierry Reding   rtc: tegra: Use c...
206
  		 readl(info->base + TEGRA_RTC_REG_SECONDS_ALARM0));
ff859ba6d   Andrew Chew   rtc: add real-tim...
207
208
209
210
  
  	/* if successfully written and alarm is enabled ... */
  	if (sec) {
  		tegra_rtc_alarm_irq_enable(dev, 1);
a2d29238b   Thierry Reding   rtc: tegra: check...
211
212
  		dev_vdbg(dev, "alarm set as %u, %ptR
  ", sec, &alarm->time);
ff859ba6d   Andrew Chew   rtc: add real-tim...
213
  	} else {
a2d29238b   Thierry Reding   rtc: tegra: check...
214
  		/* disable alarm if 0 or write error */
ff859ba6d   Andrew Chew   rtc: add real-tim...
215
216
217
218
219
220
221
222
223
224
225
226
  		dev_vdbg(dev, "alarm disabled
  ");
  		tegra_rtc_alarm_irq_enable(dev, 0);
  	}
  
  	return 0;
  }
  
  static int tegra_rtc_proc(struct device *dev, struct seq_file *seq)
  {
  	if (!dev || !dev->driver)
  		return 0;
4395eb1f1   Joe Perches   rtc: remove use o...
227
228
229
230
  	seq_printf(seq, "name\t\t: %s
  ", dev_name(dev));
  
  	return 0;
ff859ba6d   Andrew Chew   rtc: add real-tim...
231
232
233
234
235
236
  }
  
  static irqreturn_t tegra_rtc_irq_handler(int irq, void *data)
  {
  	struct device *dev = data;
  	struct tegra_rtc_info *info = dev_get_drvdata(dev);
c6af561a4   Thierry Reding   rtc: tegra: Use c...
237
238
  	unsigned long events = 0, flags;
  	u32 status;
ff859ba6d   Andrew Chew   rtc: add real-tim...
239

c6af561a4   Thierry Reding   rtc: tegra: Use c...
240
  	status = readl(info->base + TEGRA_RTC_REG_INTR_STATUS);
ff859ba6d   Andrew Chew   rtc: add real-tim...
241
  	if (status) {
a2d29238b   Thierry Reding   rtc: tegra: check...
242
  		/* clear the interrupt masks and status on any IRQ */
ff859ba6d   Andrew Chew   rtc: add real-tim...
243
  		tegra_rtc_wait_while_busy(dev);
a2d29238b   Thierry Reding   rtc: tegra: check...
244

c6af561a4   Thierry Reding   rtc: tegra: Use c...
245
246
247
248
  		spin_lock_irqsave(&info->lock, flags);
  		writel(0, info->base + TEGRA_RTC_REG_INTR_MASK);
  		writel(status, info->base + TEGRA_RTC_REG_INTR_STATUS);
  		spin_unlock_irqrestore(&info->lock, flags);
ff859ba6d   Andrew Chew   rtc: add real-tim...
249
  	}
a2d29238b   Thierry Reding   rtc: tegra: check...
250
251
  	/* check if alarm */
  	if (status & TEGRA_RTC_INTR_STATUS_SEC_ALARM0)
ff859ba6d   Andrew Chew   rtc: add real-tim...
252
  		events |= RTC_IRQF | RTC_AF;
a2d29238b   Thierry Reding   rtc: tegra: check...
253
254
  	/* check if periodic */
  	if (status & TEGRA_RTC_INTR_STATUS_SEC_CDN_ALARM)
ff859ba6d   Andrew Chew   rtc: add real-tim...
255
  		events |= RTC_IRQF | RTC_PF;
c6af561a4   Thierry Reding   rtc: tegra: Use c...
256
  	rtc_update_irq(info->rtc, 1, events);
ff859ba6d   Andrew Chew   rtc: add real-tim...
257
258
259
  
  	return IRQ_HANDLED;
  }
34c7b3ac4   Julia Lawall   rtc: constify rtc...
260
  static const struct rtc_class_ops tegra_rtc_ops = {
a2d29238b   Thierry Reding   rtc: tegra: check...
261
262
263
264
265
  	.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,
ff859ba6d   Andrew Chew   rtc: add real-tim...
266
267
  	.alarm_irq_enable = tegra_rtc_alarm_irq_enable,
  };
2d79cf8a9   Joseph Lo   drivers/rtc/rtc-t...
268
269
270
271
272
  static const struct of_device_id tegra_rtc_dt_match[] = {
  	{ .compatible = "nvidia,tegra20-rtc", },
  	{}
  };
  MODULE_DEVICE_TABLE(of, tegra_rtc_dt_match);
3e483e59c   Thierry Reding   rtc: tegra: Turn ...
273
  static int tegra_rtc_probe(struct platform_device *pdev)
ff859ba6d   Andrew Chew   rtc: add real-tim...
274
275
  {
  	struct tegra_rtc_info *info;
ff859ba6d   Andrew Chew   rtc: add real-tim...
276
  	int ret;
a2d29238b   Thierry Reding   rtc: tegra: check...
277
  	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
ff859ba6d   Andrew Chew   rtc: add real-tim...
278
279
  	if (!info)
  		return -ENOMEM;
09ef18bcd   YueHaibing   rtc: use devm_pla...
280
  	info->base = devm_platform_ioremap_resource(pdev, 0);
c6af561a4   Thierry Reding   rtc: tegra: Use c...
281
282
  	if (IS_ERR(info->base))
  		return PTR_ERR(info->base);
ff859ba6d   Andrew Chew   rtc: add real-tim...
283

fe0b5cedc   Thierry Reding   rtc: tegra: Propa...
284
  	ret = platform_get_irq(pdev, 0);
faac91020   Stephen Boyd   rtc: Remove dev_e...
285
  	if (ret <= 0)
fe0b5cedc   Thierry Reding   rtc: tegra: Propa...
286
  		return ret;
fe0b5cedc   Thierry Reding   rtc: tegra: Propa...
287

c6af561a4   Thierry Reding   rtc: tegra: Use c...
288
  	info->irq = ret;
ff859ba6d   Andrew Chew   rtc: add real-tim...
289

c6af561a4   Thierry Reding   rtc: tegra: Use c...
290
291
292
  	info->rtc = devm_rtc_allocate_device(&pdev->dev);
  	if (IS_ERR(info->rtc))
  		return PTR_ERR(info->rtc);
e10898024   Alexandre Belloni   rtc: tegra: set r...
293

c6af561a4   Thierry Reding   rtc: tegra: Use c...
294
295
  	info->rtc->ops = &tegra_rtc_ops;
  	info->rtc->range_max = U32_MAX;
e10898024   Alexandre Belloni   rtc: tegra: set r...
296

5fa408698   Thierry Reding   rtc: tegra: Imple...
297
298
299
300
301
302
303
  	info->clk = devm_clk_get(&pdev->dev, NULL);
  	if (IS_ERR(info->clk))
  		return PTR_ERR(info->clk);
  
  	ret = clk_prepare_enable(info->clk);
  	if (ret < 0)
  		return ret;
a2d29238b   Thierry Reding   rtc: tegra: check...
304
  	/* set context info */
ff859ba6d   Andrew Chew   rtc: add real-tim...
305
  	info->pdev = pdev;
c6af561a4   Thierry Reding   rtc: tegra: Use c...
306
  	spin_lock_init(&info->lock);
ff859ba6d   Andrew Chew   rtc: add real-tim...
307
308
  
  	platform_set_drvdata(pdev, info);
a2d29238b   Thierry Reding   rtc: tegra: check...
309
  	/* clear out the hardware */
c6af561a4   Thierry Reding   rtc: tegra: Use c...
310
311
312
  	writel(0, info->base + TEGRA_RTC_REG_SECONDS_ALARM0);
  	writel(0xffffffff, info->base + TEGRA_RTC_REG_INTR_STATUS);
  	writel(0, info->base + TEGRA_RTC_REG_INTR_MASK);
ff859ba6d   Andrew Chew   rtc: add real-tim...
313
314
  
  	device_init_wakeup(&pdev->dev, 1);
c6af561a4   Thierry Reding   rtc: tegra: Use c...
315
316
317
  	ret = devm_request_irq(&pdev->dev, info->irq, tegra_rtc_irq_handler,
  			       IRQF_TRIGGER_HIGH, dev_name(&pdev->dev),
  			       &pdev->dev);
ff859ba6d   Andrew Chew   rtc: add real-tim...
318
  	if (ret) {
a2d29238b   Thierry Reding   rtc: tegra: check...
319
320
  		dev_err(&pdev->dev, "failed to request interrupt: %d
  ", ret);
e10898024   Alexandre Belloni   rtc: tegra: set r...
321
322
  		goto disable_clk;
  	}
c6af561a4   Thierry Reding   rtc: tegra: Use c...
323
  	ret = rtc_register_device(info->rtc);
44c638ce4   Alexandre Belloni   rtc: remove super...
324
  	if (ret)
5fa408698   Thierry Reding   rtc: tegra: Imple...
325
  		goto disable_clk;
ff859ba6d   Andrew Chew   rtc: add real-tim...
326
327
328
329
330
  
  	dev_notice(&pdev->dev, "Tegra internal Real Time Clock
  ");
  
  	return 0;
5fa408698   Thierry Reding   rtc: tegra: Imple...
331
332
333
334
335
336
337
338
339
340
341
342
343
  
  disable_clk:
  	clk_disable_unprepare(info->clk);
  	return ret;
  }
  
  static int tegra_rtc_remove(struct platform_device *pdev)
  {
  	struct tegra_rtc_info *info = platform_get_drvdata(pdev);
  
  	clk_disable_unprepare(info->clk);
  
  	return 0;
ff859ba6d   Andrew Chew   rtc: add real-tim...
344
  }
38a6276e2   Laxman Dewangan   drivers/rtc/rtc-t...
345
  #ifdef CONFIG_PM_SLEEP
3443ad095   Laxman Dewangan   drivers/rtc/rtc-t...
346
  static int tegra_rtc_suspend(struct device *dev)
ff859ba6d   Andrew Chew   rtc: add real-tim...
347
  {
3443ad095   Laxman Dewangan   drivers/rtc/rtc-t...
348
  	struct tegra_rtc_info *info = dev_get_drvdata(dev);
ff859ba6d   Andrew Chew   rtc: add real-tim...
349
350
  
  	tegra_rtc_wait_while_busy(dev);
a2d29238b   Thierry Reding   rtc: tegra: check...
351
  	/* only use ALARM0 as a wake source */
c6af561a4   Thierry Reding   rtc: tegra: Use c...
352
  	writel(0xffffffff, info->base + TEGRA_RTC_REG_INTR_STATUS);
ff859ba6d   Andrew Chew   rtc: add real-tim...
353
  	writel(TEGRA_RTC_INTR_STATUS_SEC_ALARM0,
c6af561a4   Thierry Reding   rtc: tegra: Use c...
354
  	       info->base + TEGRA_RTC_REG_INTR_MASK);
ff859ba6d   Andrew Chew   rtc: add real-tim...
355
356
357
  
  	dev_vdbg(dev, "alarm sec = %d
  ",
c6af561a4   Thierry Reding   rtc: tegra: Use c...
358
  		 readl(info->base + TEGRA_RTC_REG_SECONDS_ALARM0));
ff859ba6d   Andrew Chew   rtc: add real-tim...
359

a2d29238b   Thierry Reding   rtc: tegra: check...
360
361
  	dev_vdbg(dev, "Suspend (device_may_wakeup=%d) IRQ:%d
  ",
c6af561a4   Thierry Reding   rtc: tegra: Use c...
362
  		 device_may_wakeup(dev), info->irq);
ff859ba6d   Andrew Chew   rtc: add real-tim...
363

a2d29238b   Thierry Reding   rtc: tegra: check...
364
  	/* leave the alarms on as a wake source */
ff859ba6d   Andrew Chew   rtc: add real-tim...
365
  	if (device_may_wakeup(dev))
c6af561a4   Thierry Reding   rtc: tegra: Use c...
366
  		enable_irq_wake(info->irq);
ff859ba6d   Andrew Chew   rtc: add real-tim...
367
368
369
  
  	return 0;
  }
3443ad095   Laxman Dewangan   drivers/rtc/rtc-t...
370
  static int tegra_rtc_resume(struct device *dev)
ff859ba6d   Andrew Chew   rtc: add real-tim...
371
  {
3443ad095   Laxman Dewangan   drivers/rtc/rtc-t...
372
  	struct tegra_rtc_info *info = dev_get_drvdata(dev);
ff859ba6d   Andrew Chew   rtc: add real-tim...
373
374
375
  
  	dev_vdbg(dev, "Resume (device_may_wakeup=%d)
  ",
a2d29238b   Thierry Reding   rtc: tegra: check...
376
377
378
  		 device_may_wakeup(dev));
  
  	/* alarms were left on as a wake source, turn them off */
ff859ba6d   Andrew Chew   rtc: add real-tim...
379
  	if (device_may_wakeup(dev))
c6af561a4   Thierry Reding   rtc: tegra: Use c...
380
  		disable_irq_wake(info->irq);
ff859ba6d   Andrew Chew   rtc: add real-tim...
381
382
383
384
  
  	return 0;
  }
  #endif
3443ad095   Laxman Dewangan   drivers/rtc/rtc-t...
385
  static SIMPLE_DEV_PM_OPS(tegra_rtc_pm_ops, tegra_rtc_suspend, tegra_rtc_resume);
ff859ba6d   Andrew Chew   rtc: add real-tim...
386
387
  static void tegra_rtc_shutdown(struct platform_device *pdev)
  {
a2d29238b   Thierry Reding   rtc: tegra: check...
388
389
  	dev_vdbg(&pdev->dev, "disabling interrupts
  ");
ff859ba6d   Andrew Chew   rtc: add real-tim...
390
391
  	tegra_rtc_alarm_irq_enable(&pdev->dev, 0);
  }
ff859ba6d   Andrew Chew   rtc: add real-tim...
392
  static struct platform_driver tegra_rtc_driver = {
3e483e59c   Thierry Reding   rtc: tegra: Turn ...
393
  	.probe = tegra_rtc_probe,
a2d29238b   Thierry Reding   rtc: tegra: check...
394
395
396
397
  	.remove = tegra_rtc_remove,
  	.shutdown = tegra_rtc_shutdown,
  	.driver = {
  		.name = "tegra_rtc",
2d79cf8a9   Joseph Lo   drivers/rtc/rtc-t...
398
  		.of_match_table = tegra_rtc_dt_match,
a2d29238b   Thierry Reding   rtc: tegra: check...
399
  		.pm = &tegra_rtc_pm_ops,
ff859ba6d   Andrew Chew   rtc: add real-tim...
400
  	},
ff859ba6d   Andrew Chew   rtc: add real-tim...
401
  };
3e483e59c   Thierry Reding   rtc: tegra: Turn ...
402
  module_platform_driver(tegra_rtc_driver);
ff859ba6d   Andrew Chew   rtc: add real-tim...
403
404
405
406
  
  MODULE_AUTHOR("Jon Mayo <jmayo@nvidia.com>");
  MODULE_DESCRIPTION("driver for Tegra internal RTC");
  MODULE_LICENSE("GPL");