Blame view

drivers/rtc/rtc-s3c.c 15.8 KB
1add6781c   Ben Dooks   [PATCH] RTC: clas...
1
2
  /* drivers/rtc/rtc-s3c.c
   *
e48add8c1   Atul Dahiya   rtc: rtc-s3c: Upd...
3
4
5
   * Copyright (c) 2010 Samsung Electronics Co., Ltd.
   *		http://www.samsung.com/
   *
1add6781c   Ben Dooks   [PATCH] RTC: clas...
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
   * Copyright (c) 2004,2006 Simtec Electronics
   *	Ben Dooks, <ben@simtec.co.uk>
   *	http://armlinux.simtec.co.uk/
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   *
   * S3C2410/S3C2440/S3C24XX Internal RTC Driver
  */
  
  #include <linux/module.h>
  #include <linux/fs.h>
  #include <linux/string.h>
  #include <linux/init.h>
  #include <linux/platform_device.h>
  #include <linux/interrupt.h>
  #include <linux/rtc.h>
  #include <linux/bcd.h>
  #include <linux/clk.h>
9974b6ea7   Robert P. J. Day   rtc-s3c: Use is_p...
26
  #include <linux/log2.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
27
  #include <linux/slab.h>
39ce4084a   Thomas Abraham   rtc: rtc-s3c: Add...
28
  #include <linux/of.h>
1add6781c   Ben Dooks   [PATCH] RTC: clas...
29

a09e64fbc   Russell King   [ARM] Move includ...
30
  #include <mach/hardware.h>
1add6781c   Ben Dooks   [PATCH] RTC: clas...
31
32
33
  #include <asm/uaccess.h>
  #include <asm/io.h>
  #include <asm/irq.h>
e2cd00cfe   Ben Dooks   [ARM] S3C: Move r...
34
  #include <plat/regs-rtc.h>
1add6781c   Ben Dooks   [PATCH] RTC: clas...
35

9f4123b78   Maurus Cuelenaere   s3c rtc driver: a...
36
37
38
39
  enum s3c_cpu_type {
  	TYPE_S3C2410,
  	TYPE_S3C64XX,
  };
1add6781c   Ben Dooks   [PATCH] RTC: clas...
40
41
42
43
  /* I have yet to find an S3C implementation with more than one
   * of these rtc blocks in */
  
  static struct resource *s3c_rtc_mem;
e48add8c1   Atul Dahiya   rtc: rtc-s3c: Upd...
44
  static struct clk *rtc_clk;
1add6781c   Ben Dooks   [PATCH] RTC: clas...
45
46
47
  static void __iomem *s3c_rtc_base;
  static int s3c_rtc_alarmno = NO_IRQ;
  static int s3c_rtc_tickno  = NO_IRQ;
52cd4e5c6   Ben Dooks   drivers/rtc/rtc-s...
48
  static bool wake_en;
9f4123b78   Maurus Cuelenaere   s3c rtc driver: a...
49
  static enum s3c_cpu_type s3c_rtc_cpu_type;
1add6781c   Ben Dooks   [PATCH] RTC: clas...
50
51
  
  static DEFINE_SPINLOCK(s3c_rtc_pie_lock);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
52

88cee8fd7   Donggeun Kim   drivers/rtc/rtc-s...
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
  static void s3c_rtc_alarm_clk_enable(bool enable)
  {
  	static DEFINE_SPINLOCK(s3c_rtc_alarm_clk_lock);
  	static bool alarm_clk_enabled;
  	unsigned long irq_flags;
  
  	spin_lock_irqsave(&s3c_rtc_alarm_clk_lock, irq_flags);
  	if (enable) {
  		if (!alarm_clk_enabled) {
  			clk_enable(rtc_clk);
  			alarm_clk_enabled = true;
  		}
  	} else {
  		if (alarm_clk_enabled) {
  			clk_disable(rtc_clk);
  			alarm_clk_enabled = false;
  		}
  	}
  	spin_unlock_irqrestore(&s3c_rtc_alarm_clk_lock, irq_flags);
  }
1add6781c   Ben Dooks   [PATCH] RTC: clas...
73
  /* IRQ Handlers */
7d12e780e   David Howells   IRQ: Maintain reg...
74
  static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
1add6781c   Ben Dooks   [PATCH] RTC: clas...
75
76
  {
  	struct rtc_device *rdev = id;
cefe4fbba   Donggeun Kim   drivers/rtc/rtc-s...
77
  	clk_enable(rtc_clk);
ab6a2d70d   David Brownell   rtc: rtc interfac...
78
  	rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF);
2f3478f65   Atul Dahiya   rtc: rtc-s3c: Upd...
79
80
81
  
  	if (s3c_rtc_cpu_type == TYPE_S3C64XX)
  		writeb(S3C2410_INTP_ALM, s3c_rtc_base + S3C2410_INTP);
cefe4fbba   Donggeun Kim   drivers/rtc/rtc-s...
82
  	clk_disable(rtc_clk);
88cee8fd7   Donggeun Kim   drivers/rtc/rtc-s...
83
84
  
  	s3c_rtc_alarm_clk_enable(false);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
85
86
  	return IRQ_HANDLED;
  }
7d12e780e   David Howells   IRQ: Maintain reg...
87
  static irqreturn_t s3c_rtc_tickirq(int irq, void *id)
1add6781c   Ben Dooks   [PATCH] RTC: clas...
88
89
  {
  	struct rtc_device *rdev = id;
cefe4fbba   Donggeun Kim   drivers/rtc/rtc-s...
90
  	clk_enable(rtc_clk);
773be7ee9   Ben Dooks   rtc: rtc-s3c: upd...
91
  	rtc_update_irq(rdev, 1, RTC_PF | RTC_IRQF);
2f3478f65   Atul Dahiya   rtc: rtc-s3c: Upd...
92
93
94
  
  	if (s3c_rtc_cpu_type == TYPE_S3C64XX)
  		writeb(S3C2410_INTP_TIC, s3c_rtc_base + S3C2410_INTP);
cefe4fbba   Donggeun Kim   drivers/rtc/rtc-s...
95
  	clk_disable(rtc_clk);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
96
97
98
99
  	return IRQ_HANDLED;
  }
  
  /* Update control registers */
2ec38a035   Axel Lin   drivers/rtc/rtc-s...
100
  static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
1add6781c   Ben Dooks   [PATCH] RTC: clas...
101
102
  {
  	unsigned int tmp;
2ec38a035   Axel Lin   drivers/rtc/rtc-s...
103
104
  	pr_debug("%s: aie=%d
  ", __func__, enabled);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
105

cefe4fbba   Donggeun Kim   drivers/rtc/rtc-s...
106
  	clk_enable(rtc_clk);
9a654518e   Ben Dooks   [PATCH] drivers/r...
107
  	tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
1add6781c   Ben Dooks   [PATCH] RTC: clas...
108

2ec38a035   Axel Lin   drivers/rtc/rtc-s...
109
  	if (enabled)
1add6781c   Ben Dooks   [PATCH] RTC: clas...
110
  		tmp |= S3C2410_RTCALM_ALMEN;
9a654518e   Ben Dooks   [PATCH] drivers/r...
111
  	writeb(tmp, s3c_rtc_base + S3C2410_RTCALM);
cefe4fbba   Donggeun Kim   drivers/rtc/rtc-s...
112
  	clk_disable(rtc_clk);
2ec38a035   Axel Lin   drivers/rtc/rtc-s...
113

88cee8fd7   Donggeun Kim   drivers/rtc/rtc-s...
114
  	s3c_rtc_alarm_clk_enable(enabled);
2ec38a035   Axel Lin   drivers/rtc/rtc-s...
115
  	return 0;
1add6781c   Ben Dooks   [PATCH] RTC: clas...
116
  }
773be7ee9   Ben Dooks   rtc: rtc-s3c: upd...
117
  static int s3c_rtc_setfreq(struct device *dev, int freq)
1add6781c   Ben Dooks   [PATCH] RTC: clas...
118
  {
9f4123b78   Maurus Cuelenaere   s3c rtc driver: a...
119
120
121
  	struct platform_device *pdev = to_platform_device(dev);
  	struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
  	unsigned int tmp = 0;
1add6781c   Ben Dooks   [PATCH] RTC: clas...
122

5d2a50371   Jonathan Cameron   rtc: move power o...
123
124
  	if (!is_power_of_2(freq))
  		return -EINVAL;
cefe4fbba   Donggeun Kim   drivers/rtc/rtc-s...
125
  	clk_enable(rtc_clk);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
126
  	spin_lock_irq(&s3c_rtc_pie_lock);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
127

9f4123b78   Maurus Cuelenaere   s3c rtc driver: a...
128
129
130
131
132
133
  	if (s3c_rtc_cpu_type == TYPE_S3C2410) {
  		tmp = readb(s3c_rtc_base + S3C2410_TICNT);
  		tmp &= S3C2410_TICNT_ENABLE;
  	}
  
  	tmp |= (rtc_dev->max_user_freq / freq)-1;
1add6781c   Ben Dooks   [PATCH] RTC: clas...
134

2f3478f65   Atul Dahiya   rtc: rtc-s3c: Upd...
135
  	writel(tmp, s3c_rtc_base + S3C2410_TICNT);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
136
  	spin_unlock_irq(&s3c_rtc_pie_lock);
cefe4fbba   Donggeun Kim   drivers/rtc/rtc-s...
137
  	clk_disable(rtc_clk);
773be7ee9   Ben Dooks   rtc: rtc-s3c: upd...
138
139
  
  	return 0;
1add6781c   Ben Dooks   [PATCH] RTC: clas...
140
141
142
143
144
145
146
  }
  
  /* Time read/write */
  
  static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
  {
  	unsigned int have_retried = 0;
9a654518e   Ben Dooks   [PATCH] drivers/r...
147
  	void __iomem *base = s3c_rtc_base;
1add6781c   Ben Dooks   [PATCH] RTC: clas...
148

cefe4fbba   Donggeun Kim   drivers/rtc/rtc-s...
149
  	clk_enable(rtc_clk);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
150
   retry_get_time:
9a654518e   Ben Dooks   [PATCH] drivers/r...
151
152
153
154
155
156
  	rtc_tm->tm_min  = readb(base + S3C2410_RTCMIN);
  	rtc_tm->tm_hour = readb(base + S3C2410_RTCHOUR);
  	rtc_tm->tm_mday = readb(base + S3C2410_RTCDATE);
  	rtc_tm->tm_mon  = readb(base + S3C2410_RTCMON);
  	rtc_tm->tm_year = readb(base + S3C2410_RTCYEAR);
  	rtc_tm->tm_sec  = readb(base + S3C2410_RTCSEC);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
157
158
159
160
161
162
163
164
165
166
  
  	/* the only way to work out wether the system was mid-update
  	 * when we read it is to check the second counter, and if it
  	 * is zero, then we re-try the entire read
  	 */
  
  	if (rtc_tm->tm_sec == 0 && !have_retried) {
  		have_retried = 1;
  		goto retry_get_time;
  	}
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
167
168
169
170
171
172
  	rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
  	rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
  	rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
  	rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);
  	rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon);
  	rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
173
174
  
  	rtc_tm->tm_year += 100;
4e8896cde   MyungJoo Ham   drivers/rtc/rtc-s...
175
176
177
178
179
  
  	pr_debug("read time %04d.%02d.%02d %02d:%02d:%02d
  ",
  		 1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
  		 rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
180
  	rtc_tm->tm_mon -= 1;
cefe4fbba   Donggeun Kim   drivers/rtc/rtc-s...
181
  	clk_disable(rtc_clk);
5b3ffddd8   Kukjin Kim   rtc: rtc-s3c: add...
182
  	return rtc_valid_tm(rtc_tm);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
183
184
185
186
  }
  
  static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
  {
9a654518e   Ben Dooks   [PATCH] drivers/r...
187
  	void __iomem *base = s3c_rtc_base;
641741e01   Ben Dooks   [PATCH] rtc-s3c.c...
188
  	int year = tm->tm_year - 100;
9a654518e   Ben Dooks   [PATCH] drivers/r...
189

30ffc40cf   Kukjin Kim   rtc: rtc-s3c: Fix...
190
191
192
  	pr_debug("set time %04d.%02d.%02d %02d:%02d:%02d
  ",
  		 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
641741e01   Ben Dooks   [PATCH] rtc-s3c.c...
193
194
195
  		 tm->tm_hour, tm->tm_min, tm->tm_sec);
  
  	/* we get around y2k by simply not supporting it */
1add6781c   Ben Dooks   [PATCH] RTC: clas...
196

641741e01   Ben Dooks   [PATCH] rtc-s3c.c...
197
  	if (year < 0 || year >= 100) {
9a654518e   Ben Dooks   [PATCH] drivers/r...
198
199
  		dev_err(dev, "rtc only supports 100 years
  ");
1add6781c   Ben Dooks   [PATCH] RTC: clas...
200
  		return -EINVAL;
9a654518e   Ben Dooks   [PATCH] drivers/r...
201
  	}
2dbcd05f1   Jonghwan Choi   drivers/rtc/rtc-s...
202
  	clk_enable(rtc_clk);
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
203
204
205
206
207
208
  	writeb(bin2bcd(tm->tm_sec),  base + S3C2410_RTCSEC);
  	writeb(bin2bcd(tm->tm_min),  base + S3C2410_RTCMIN);
  	writeb(bin2bcd(tm->tm_hour), base + S3C2410_RTCHOUR);
  	writeb(bin2bcd(tm->tm_mday), base + S3C2410_RTCDATE);
  	writeb(bin2bcd(tm->tm_mon + 1), base + S3C2410_RTCMON);
  	writeb(bin2bcd(year), base + S3C2410_RTCYEAR);
cefe4fbba   Donggeun Kim   drivers/rtc/rtc-s...
209
  	clk_disable(rtc_clk);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
210
211
212
213
214
215
216
  
  	return 0;
  }
  
  static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
  {
  	struct rtc_time *alm_tm = &alrm->time;
9a654518e   Ben Dooks   [PATCH] drivers/r...
217
  	void __iomem *base = s3c_rtc_base;
1add6781c   Ben Dooks   [PATCH] RTC: clas...
218
  	unsigned int alm_en;
cefe4fbba   Donggeun Kim   drivers/rtc/rtc-s...
219
  	clk_enable(rtc_clk);
9a654518e   Ben Dooks   [PATCH] drivers/r...
220
221
222
223
224
225
  	alm_tm->tm_sec  = readb(base + S3C2410_ALMSEC);
  	alm_tm->tm_min  = readb(base + S3C2410_ALMMIN);
  	alm_tm->tm_hour = readb(base + S3C2410_ALMHOUR);
  	alm_tm->tm_mon  = readb(base + S3C2410_ALMMON);
  	alm_tm->tm_mday = readb(base + S3C2410_ALMDATE);
  	alm_tm->tm_year = readb(base + S3C2410_ALMYEAR);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
226

9a654518e   Ben Dooks   [PATCH] drivers/r...
227
  	alm_en = readb(base + S3C2410_RTCALM);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
228

a2db8dfce   David Brownell   [PATCH] rtc frame...
229
  	alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0;
30ffc40cf   Kukjin Kim   rtc: rtc-s3c: Fix...
230
231
  	pr_debug("read alarm %d, %04d.%02d.%02d %02d:%02d:%02d
  ",
1add6781c   Ben Dooks   [PATCH] RTC: clas...
232
  		 alm_en,
30ffc40cf   Kukjin Kim   rtc: rtc-s3c: Fix...
233
  		 1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
1add6781c   Ben Dooks   [PATCH] RTC: clas...
234
235
236
237
238
239
  		 alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
  
  
  	/* decode the alarm enable field */
  
  	if (alm_en & S3C2410_RTCALM_SECEN)
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
240
  		alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
241
  	else
dd061d1ab   Changhwan Youn   rtc: rtc-s3c: fix...
242
  		alm_tm->tm_sec = -1;
1add6781c   Ben Dooks   [PATCH] RTC: clas...
243
244
  
  	if (alm_en & S3C2410_RTCALM_MINEN)
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
245
  		alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
246
  	else
dd061d1ab   Changhwan Youn   rtc: rtc-s3c: fix...
247
  		alm_tm->tm_min = -1;
1add6781c   Ben Dooks   [PATCH] RTC: clas...
248
249
  
  	if (alm_en & S3C2410_RTCALM_HOUREN)
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
250
  		alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
251
  	else
dd061d1ab   Changhwan Youn   rtc: rtc-s3c: fix...
252
  		alm_tm->tm_hour = -1;
1add6781c   Ben Dooks   [PATCH] RTC: clas...
253
254
  
  	if (alm_en & S3C2410_RTCALM_DAYEN)
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
255
  		alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
256
  	else
dd061d1ab   Changhwan Youn   rtc: rtc-s3c: fix...
257
  		alm_tm->tm_mday = -1;
1add6781c   Ben Dooks   [PATCH] RTC: clas...
258
259
  
  	if (alm_en & S3C2410_RTCALM_MONEN) {
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
260
  		alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
261
262
  		alm_tm->tm_mon -= 1;
  	} else {
dd061d1ab   Changhwan Youn   rtc: rtc-s3c: fix...
263
  		alm_tm->tm_mon = -1;
1add6781c   Ben Dooks   [PATCH] RTC: clas...
264
265
266
  	}
  
  	if (alm_en & S3C2410_RTCALM_YEAREN)
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
267
  		alm_tm->tm_year = bcd2bin(alm_tm->tm_year);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
268
  	else
dd061d1ab   Changhwan Youn   rtc: rtc-s3c: fix...
269
  		alm_tm->tm_year = -1;
1add6781c   Ben Dooks   [PATCH] RTC: clas...
270

cefe4fbba   Donggeun Kim   drivers/rtc/rtc-s...
271
  	clk_disable(rtc_clk);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
272
273
274
275
276
277
  	return 0;
  }
  
  static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
  {
  	struct rtc_time *tm = &alrm->time;
9a654518e   Ben Dooks   [PATCH] drivers/r...
278
  	void __iomem *base = s3c_rtc_base;
1add6781c   Ben Dooks   [PATCH] RTC: clas...
279
  	unsigned int alrm_en;
cefe4fbba   Donggeun Kim   drivers/rtc/rtc-s...
280
  	clk_enable(rtc_clk);
30ffc40cf   Kukjin Kim   rtc: rtc-s3c: Fix...
281
282
  	pr_debug("s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d
  ",
1add6781c   Ben Dooks   [PATCH] RTC: clas...
283
  		 alrm->enabled,
4e8896cde   MyungJoo Ham   drivers/rtc/rtc-s...
284
  		 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
30ffc40cf   Kukjin Kim   rtc: rtc-s3c: Fix...
285
  		 tm->tm_hour, tm->tm_min, tm->tm_sec);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
286

9a654518e   Ben Dooks   [PATCH] drivers/r...
287
288
  	alrm_en = readb(base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
  	writeb(0x00, base + S3C2410_RTCALM);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
289
290
291
  
  	if (tm->tm_sec < 60 && tm->tm_sec >= 0) {
  		alrm_en |= S3C2410_RTCALM_SECEN;
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
292
  		writeb(bin2bcd(tm->tm_sec), base + S3C2410_ALMSEC);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
293
294
295
296
  	}
  
  	if (tm->tm_min < 60 && tm->tm_min >= 0) {
  		alrm_en |= S3C2410_RTCALM_MINEN;
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
297
  		writeb(bin2bcd(tm->tm_min), base + S3C2410_ALMMIN);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
298
299
300
301
  	}
  
  	if (tm->tm_hour < 24 && tm->tm_hour >= 0) {
  		alrm_en |= S3C2410_RTCALM_HOUREN;
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
302
  		writeb(bin2bcd(tm->tm_hour), base + S3C2410_ALMHOUR);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
303
304
305
306
  	}
  
  	pr_debug("setting S3C2410_RTCALM to %08x
  ", alrm_en);
9a654518e   Ben Dooks   [PATCH] drivers/r...
307
  	writeb(alrm_en, base + S3C2410_RTCALM);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
308

2ec38a035   Axel Lin   drivers/rtc/rtc-s...
309
  	s3c_rtc_setaie(dev, alrm->enabled);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
310

cefe4fbba   Donggeun Kim   drivers/rtc/rtc-s...
311
  	clk_disable(rtc_clk);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
312
313
  	return 0;
  }
1add6781c   Ben Dooks   [PATCH] RTC: clas...
314
315
  static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
  {
9f4123b78   Maurus Cuelenaere   s3c rtc driver: a...
316
  	unsigned int ticnt;
1add6781c   Ben Dooks   [PATCH] RTC: clas...
317

cefe4fbba   Donggeun Kim   drivers/rtc/rtc-s...
318
  	clk_enable(rtc_clk);
9f4123b78   Maurus Cuelenaere   s3c rtc driver: a...
319
  	if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
f61ae6711   Changhwan Youn   rtc: rtc-s3c: fix...
320
  		ticnt = readw(s3c_rtc_base + S3C2410_RTCCON);
9f4123b78   Maurus Cuelenaere   s3c rtc driver: a...
321
322
323
324
325
326
327
328
  		ticnt &= S3C64XX_RTCCON_TICEN;
  	} else {
  		ticnt = readb(s3c_rtc_base + S3C2410_TICNT);
  		ticnt &= S3C2410_TICNT_ENABLE;
  	}
  
  	seq_printf(seq, "periodic_IRQ\t: %s
  ", ticnt  ? "yes" : "no");
cefe4fbba   Donggeun Kim   drivers/rtc/rtc-s...
329
  	clk_disable(rtc_clk);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
330
331
  	return 0;
  }
ff8371ac9   David Brownell   [PATCH] constify ...
332
  static const struct rtc_class_ops s3c_rtcops = {
1add6781c   Ben Dooks   [PATCH] RTC: clas...
333
334
335
336
  	.read_time	= s3c_rtc_gettime,
  	.set_time	= s3c_rtc_settime,
  	.read_alarm	= s3c_rtc_getalarm,
  	.set_alarm	= s3c_rtc_setalarm,
e6eb524e6   Changhwan Youn   rtc: rtc-s3c: fix...
337
338
  	.proc		= s3c_rtc_proc,
  	.alarm_irq_enable = s3c_rtc_setaie,
1add6781c   Ben Dooks   [PATCH] RTC: clas...
339
340
341
342
  };
  
  static void s3c_rtc_enable(struct platform_device *pdev, int en)
  {
9a654518e   Ben Dooks   [PATCH] drivers/r...
343
  	void __iomem *base = s3c_rtc_base;
1add6781c   Ben Dooks   [PATCH] RTC: clas...
344
345
346
347
  	unsigned int tmp;
  
  	if (s3c_rtc_base == NULL)
  		return;
cefe4fbba   Donggeun Kim   drivers/rtc/rtc-s...
348
  	clk_enable(rtc_clk);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
349
  	if (!en) {
f61ae6711   Changhwan Youn   rtc: rtc-s3c: fix...
350
  		tmp = readw(base + S3C2410_RTCCON);
9f4123b78   Maurus Cuelenaere   s3c rtc driver: a...
351
352
353
  		if (s3c_rtc_cpu_type == TYPE_S3C64XX)
  			tmp &= ~S3C64XX_RTCCON_TICEN;
  		tmp &= ~S3C2410_RTCCON_RTCEN;
f61ae6711   Changhwan Youn   rtc: rtc-s3c: fix...
354
  		writew(tmp, base + S3C2410_RTCCON);
9f4123b78   Maurus Cuelenaere   s3c rtc driver: a...
355
356
357
358
359
360
  
  		if (s3c_rtc_cpu_type == TYPE_S3C2410) {
  			tmp = readb(base + S3C2410_TICNT);
  			tmp &= ~S3C2410_TICNT_ENABLE;
  			writeb(tmp, base + S3C2410_TICNT);
  		}
1add6781c   Ben Dooks   [PATCH] RTC: clas...
361
362
  	} else {
  		/* re-enable the device, and check it is ok */
f61ae6711   Changhwan Youn   rtc: rtc-s3c: fix...
363
  		if ((readw(base+S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0) {
1add6781c   Ben Dooks   [PATCH] RTC: clas...
364
365
  			dev_info(&pdev->dev, "rtc disabled, re-enabling
  ");
f61ae6711   Changhwan Youn   rtc: rtc-s3c: fix...
366
367
368
  			tmp = readw(base + S3C2410_RTCCON);
  			writew(tmp | S3C2410_RTCCON_RTCEN,
  				base + S3C2410_RTCCON);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
369
  		}
f61ae6711   Changhwan Youn   rtc: rtc-s3c: fix...
370
  		if ((readw(base + S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)) {
1add6781c   Ben Dooks   [PATCH] RTC: clas...
371
372
  			dev_info(&pdev->dev, "removing RTCCON_CNTSEL
  ");
f61ae6711   Changhwan Youn   rtc: rtc-s3c: fix...
373
374
375
  			tmp = readw(base + S3C2410_RTCCON);
  			writew(tmp & ~S3C2410_RTCCON_CNTSEL,
  				base + S3C2410_RTCCON);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
376
  		}
f61ae6711   Changhwan Youn   rtc: rtc-s3c: fix...
377
  		if ((readw(base + S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)) {
1add6781c   Ben Dooks   [PATCH] RTC: clas...
378
379
  			dev_info(&pdev->dev, "removing RTCCON_CLKRST
  ");
f61ae6711   Changhwan Youn   rtc: rtc-s3c: fix...
380
381
382
  			tmp = readw(base + S3C2410_RTCCON);
  			writew(tmp & ~S3C2410_RTCCON_CLKRST,
  				base + S3C2410_RTCCON);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
383
384
  		}
  	}
cefe4fbba   Donggeun Kim   drivers/rtc/rtc-s...
385
  	clk_disable(rtc_clk);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
386
  }
4cd0c5c40   Ben Dooks   rtc: rtc-s3c: add...
387
  static int __devexit s3c_rtc_remove(struct platform_device *dev)
1add6781c   Ben Dooks   [PATCH] RTC: clas...
388
389
  {
  	struct rtc_device *rtc = platform_get_drvdata(dev);
62d176018   MyungJoo Ham   drivers/rtc/rtc-s...
390
391
  	free_irq(s3c_rtc_alarmno, rtc);
  	free_irq(s3c_rtc_tickno, rtc);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
392
393
  	platform_set_drvdata(dev, NULL);
  	rtc_device_unregister(rtc);
2ec38a035   Axel Lin   drivers/rtc/rtc-s...
394
  	s3c_rtc_setaie(&dev->dev, 0);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
395

e48add8c1   Atul Dahiya   rtc: rtc-s3c: Upd...
396
397
  	clk_put(rtc_clk);
  	rtc_clk = NULL;
1add6781c   Ben Dooks   [PATCH] RTC: clas...
398
399
400
401
402
403
  	iounmap(s3c_rtc_base);
  	release_resource(s3c_rtc_mem);
  	kfree(s3c_rtc_mem);
  
  	return 0;
  }
4cd0c5c40   Ben Dooks   rtc: rtc-s3c: add...
404
  static int __devinit s3c_rtc_probe(struct platform_device *pdev)
1add6781c   Ben Dooks   [PATCH] RTC: clas...
405
406
  {
  	struct rtc_device *rtc;
e1df962e6   Changhwan Youn   rtc: rtc-s3c: fix...
407
  	struct rtc_time rtc_tm;
1add6781c   Ben Dooks   [PATCH] RTC: clas...
408
409
  	struct resource *res;
  	int ret;
2a4e2b878   Harvey Harrison   rtc: replace rema...
410
411
  	pr_debug("%s: probe=%p
  ", __func__, pdev);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
  
  	/* find the IRQs */
  
  	s3c_rtc_tickno = platform_get_irq(pdev, 1);
  	if (s3c_rtc_tickno < 0) {
  		dev_err(&pdev->dev, "no irq for rtc tick
  ");
  		return -ENOENT;
  	}
  
  	s3c_rtc_alarmno = platform_get_irq(pdev, 0);
  	if (s3c_rtc_alarmno < 0) {
  		dev_err(&pdev->dev, "no irq for alarm
  ");
  		return -ENOENT;
  	}
  
  	pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d
  ",
  		 s3c_rtc_tickno, s3c_rtc_alarmno);
  
  	/* get the memory region */
  
  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	if (res == NULL) {
  		dev_err(&pdev->dev, "failed to get memory region resource
  ");
  		return -ENOENT;
  	}
28f65c11f   Joe Perches   treewide: Convert...
441
  	s3c_rtc_mem = request_mem_region(res->start, resource_size(res),
9a654518e   Ben Dooks   [PATCH] drivers/r...
442
  					 pdev->name);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
443
444
445
446
447
448
449
  
  	if (s3c_rtc_mem == NULL) {
  		dev_err(&pdev->dev, "failed to reserve memory region
  ");
  		ret = -ENOENT;
  		goto err_nores;
  	}
28f65c11f   Joe Perches   treewide: Convert...
450
  	s3c_rtc_base = ioremap(res->start, resource_size(res));
1add6781c   Ben Dooks   [PATCH] RTC: clas...
451
452
453
454
455
456
  	if (s3c_rtc_base == NULL) {
  		dev_err(&pdev->dev, "failed ioremap()
  ");
  		ret = -EINVAL;
  		goto err_nomap;
  	}
e48add8c1   Atul Dahiya   rtc: rtc-s3c: Upd...
457
458
459
460
461
462
463
464
465
466
  	rtc_clk = clk_get(&pdev->dev, "rtc");
  	if (IS_ERR(rtc_clk)) {
  		dev_err(&pdev->dev, "failed to find rtc clock source
  ");
  		ret = PTR_ERR(rtc_clk);
  		rtc_clk = NULL;
  		goto err_clk;
  	}
  
  	clk_enable(rtc_clk);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
467
468
469
  	/* check to see if everything is setup correctly */
  
  	s3c_rtc_enable(pdev, 1);
f61ae6711   Changhwan Youn   rtc: rtc-s3c: fix...
470
471
472
  	pr_debug("s3c2410_rtc: RTCCON=%02x
  ",
  		 readw(s3c_rtc_base + S3C2410_RTCCON));
1add6781c   Ben Dooks   [PATCH] RTC: clas...
473

51b7616e3   Yauhen Kharuzhy   rtc S3C: add devi...
474
  	device_init_wakeup(&pdev->dev, 1);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
475
476
477
478
479
480
481
482
483
484
485
  	/* register RTC and exit */
  
  	rtc = rtc_device_register("s3c", &pdev->dev, &s3c_rtcops,
  				  THIS_MODULE);
  
  	if (IS_ERR(rtc)) {
  		dev_err(&pdev->dev, "cannot attach rtc
  ");
  		ret = PTR_ERR(rtc);
  		goto err_nortc;
  	}
39ce4084a   Thomas Abraham   rtc: rtc-s3c: Add...
486
487
488
489
490
491
492
  #ifdef CONFIG_OF
  	if (pdev->dev.of_node)
  		s3c_rtc_cpu_type = of_device_is_compatible(pdev->dev.of_node,
  			"samsung,s3c6410-rtc") ? TYPE_S3C64XX : TYPE_S3C2410;
  	else
  #endif
  		s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data;
eaa6e4dd4   Maurus Cuelenaere   rtc: s3c: initial...
493

051fe54e9   Taekgyun Ko   rtc: rtc-s3c: Add...
494
  	/* Check RTC Time */
e1df962e6   Changhwan Youn   rtc: rtc-s3c: fix...
495
  	s3c_rtc_gettime(NULL, &rtc_tm);
051fe54e9   Taekgyun Ko   rtc: rtc-s3c: Add...
496

e1df962e6   Changhwan Youn   rtc: rtc-s3c: fix...
497
498
499
500
501
502
503
504
505
506
507
508
  	if (rtc_valid_tm(&rtc_tm)) {
  		rtc_tm.tm_year	= 100;
  		rtc_tm.tm_mon	= 0;
  		rtc_tm.tm_mday	= 1;
  		rtc_tm.tm_hour	= 0;
  		rtc_tm.tm_min	= 0;
  		rtc_tm.tm_sec	= 0;
  
  		s3c_rtc_settime(NULL, &rtc_tm);
  
  		dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it
  ");
051fe54e9   Taekgyun Ko   rtc: rtc-s3c: Add...
509
  	}
9f4123b78   Maurus Cuelenaere   s3c rtc driver: a...
510
511
512
513
  	if (s3c_rtc_cpu_type == TYPE_S3C64XX)
  		rtc->max_user_freq = 32768;
  	else
  		rtc->max_user_freq = 128;
1add6781c   Ben Dooks   [PATCH] RTC: clas...
514
  	platform_set_drvdata(pdev, rtc);
e893de59a   Maurus Cuelenaere   rtc: s3c: initial...
515
516
  
  	s3c_rtc_setfreq(&pdev->dev, 1);
62d176018   MyungJoo Ham   drivers/rtc/rtc-s...
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
  	ret = request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq,
  			  IRQF_DISABLED,  "s3c2410-rtc alarm", rtc);
  	if (ret) {
  		dev_err(&pdev->dev, "IRQ%d error %d
  ", s3c_rtc_alarmno, ret);
  		goto err_alarm_irq;
  	}
  
  	ret = request_irq(s3c_rtc_tickno, s3c_rtc_tickirq,
  			  IRQF_DISABLED,  "s3c2410-rtc tick", rtc);
  	if (ret) {
  		dev_err(&pdev->dev, "IRQ%d error %d
  ", s3c_rtc_tickno, ret);
  		free_irq(s3c_rtc_alarmno, rtc);
  		goto err_tick_irq;
  	}
cefe4fbba   Donggeun Kim   drivers/rtc/rtc-s...
533
  	clk_disable(rtc_clk);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
534
  	return 0;
62d176018   MyungJoo Ham   drivers/rtc/rtc-s...
535
536
537
538
539
540
   err_tick_irq:
  	free_irq(s3c_rtc_alarmno, rtc);
  
   err_alarm_irq:
  	platform_set_drvdata(pdev, NULL);
  	rtc_device_unregister(rtc);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
541
542
   err_nortc:
  	s3c_rtc_enable(pdev, 0);
e48add8c1   Atul Dahiya   rtc: rtc-s3c: Upd...
543
544
545
546
  	clk_disable(rtc_clk);
  	clk_put(rtc_clk);
  
   err_clk:
1add6781c   Ben Dooks   [PATCH] RTC: clas...
547
548
549
550
551
552
553
554
555
556
557
558
  	iounmap(s3c_rtc_base);
  
   err_nomap:
  	release_resource(s3c_rtc_mem);
  
   err_nores:
  	return ret;
  }
  
  #ifdef CONFIG_PM
  
  /* RTC Power management control */
9f4123b78   Maurus Cuelenaere   s3c rtc driver: a...
559
  static int ticnt_save, ticnt_en_save;
1add6781c   Ben Dooks   [PATCH] RTC: clas...
560
561
562
  
  static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)
  {
cefe4fbba   Donggeun Kim   drivers/rtc/rtc-s...
563
  	clk_enable(rtc_clk);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
564
  	/* save TICNT for anyone using periodic interrupts */
9a654518e   Ben Dooks   [PATCH] drivers/r...
565
  	ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
9f4123b78   Maurus Cuelenaere   s3c rtc driver: a...
566
  	if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
f61ae6711   Changhwan Youn   rtc: rtc-s3c: fix...
567
  		ticnt_en_save = readw(s3c_rtc_base + S3C2410_RTCCON);
9f4123b78   Maurus Cuelenaere   s3c rtc driver: a...
568
569
  		ticnt_en_save &= S3C64XX_RTCCON_TICEN;
  	}
1add6781c   Ben Dooks   [PATCH] RTC: clas...
570
  	s3c_rtc_enable(pdev, 0);
f501ed524   Vladimir Zapolskiy   rtc: s3c: balance...
571

52cd4e5c6   Ben Dooks   drivers/rtc/rtc-s...
572
573
574
575
576
577
578
  	if (device_may_wakeup(&pdev->dev) && !wake_en) {
  		if (enable_irq_wake(s3c_rtc_alarmno) == 0)
  			wake_en = true;
  		else
  			dev_err(&pdev->dev, "enable_irq_wake failed
  ");
  	}
cefe4fbba   Donggeun Kim   drivers/rtc/rtc-s...
579
  	clk_disable(rtc_clk);
f501ed524   Vladimir Zapolskiy   rtc: s3c: balance...
580

1add6781c   Ben Dooks   [PATCH] RTC: clas...
581
582
583
584
585
  	return 0;
  }
  
  static int s3c_rtc_resume(struct platform_device *pdev)
  {
9f4123b78   Maurus Cuelenaere   s3c rtc driver: a...
586
  	unsigned int tmp;
cefe4fbba   Donggeun Kim   drivers/rtc/rtc-s...
587
  	clk_enable(rtc_clk);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
588
  	s3c_rtc_enable(pdev, 1);
9a654518e   Ben Dooks   [PATCH] drivers/r...
589
  	writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
9f4123b78   Maurus Cuelenaere   s3c rtc driver: a...
590
  	if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) {
f61ae6711   Changhwan Youn   rtc: rtc-s3c: fix...
591
592
  		tmp = readw(s3c_rtc_base + S3C2410_RTCCON);
  		writew(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON);
9f4123b78   Maurus Cuelenaere   s3c rtc driver: a...
593
  	}
f501ed524   Vladimir Zapolskiy   rtc: s3c: balance...
594

52cd4e5c6   Ben Dooks   drivers/rtc/rtc-s...
595
  	if (device_may_wakeup(&pdev->dev) && wake_en) {
f501ed524   Vladimir Zapolskiy   rtc: s3c: balance...
596
  		disable_irq_wake(s3c_rtc_alarmno);
52cd4e5c6   Ben Dooks   drivers/rtc/rtc-s...
597
598
  		wake_en = false;
  	}
cefe4fbba   Donggeun Kim   drivers/rtc/rtc-s...
599
  	clk_disable(rtc_clk);
f501ed524   Vladimir Zapolskiy   rtc: s3c: balance...
600

1add6781c   Ben Dooks   [PATCH] RTC: clas...
601
602
603
604
605
606
  	return 0;
  }
  #else
  #define s3c_rtc_suspend NULL
  #define s3c_rtc_resume  NULL
  #endif
39ce4084a   Thomas Abraham   rtc: rtc-s3c: Add...
607
608
609
610
611
612
613
614
615
616
  #ifdef CONFIG_OF
  static const struct of_device_id s3c_rtc_dt_match[] = {
  	{ .compatible = "samsung,s3c2410-rtc" },
  	{ .compatible = "samsung,s3c6410-rtc" },
  	{},
  };
  MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match);
  #else
  #define s3c_rtc_dt_match NULL
  #endif
9f4123b78   Maurus Cuelenaere   s3c rtc driver: a...
617
618
619
620
621
622
623
624
625
626
627
628
629
630
  static struct platform_device_id s3c_rtc_driver_ids[] = {
  	{
  		.name		= "s3c2410-rtc",
  		.driver_data	= TYPE_S3C2410,
  	}, {
  		.name		= "s3c64xx-rtc",
  		.driver_data	= TYPE_S3C64XX,
  	},
  	{ }
  };
  
  MODULE_DEVICE_TABLE(platform, s3c_rtc_driver_ids);
  
  static struct platform_driver s3c_rtc_driver = {
1add6781c   Ben Dooks   [PATCH] RTC: clas...
631
  	.probe		= s3c_rtc_probe,
4cd0c5c40   Ben Dooks   rtc: rtc-s3c: add...
632
  	.remove		= __devexit_p(s3c_rtc_remove),
1add6781c   Ben Dooks   [PATCH] RTC: clas...
633
634
  	.suspend	= s3c_rtc_suspend,
  	.resume		= s3c_rtc_resume,
9f4123b78   Maurus Cuelenaere   s3c rtc driver: a...
635
  	.id_table	= s3c_rtc_driver_ids,
1add6781c   Ben Dooks   [PATCH] RTC: clas...
636
  	.driver		= {
9f4123b78   Maurus Cuelenaere   s3c rtc driver: a...
637
  		.name	= "s3c-rtc",
1add6781c   Ben Dooks   [PATCH] RTC: clas...
638
  		.owner	= THIS_MODULE,
39ce4084a   Thomas Abraham   rtc: rtc-s3c: Add...
639
  		.of_match_table	= s3c_rtc_dt_match,
1add6781c   Ben Dooks   [PATCH] RTC: clas...
640
641
  	},
  };
0c4eae665   Axel Lin   rtc: convert driv...
642
  module_platform_driver(s3c_rtc_driver);
1add6781c   Ben Dooks   [PATCH] RTC: clas...
643
644
645
646
  
  MODULE_DESCRIPTION("Samsung S3C RTC Driver");
  MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
  MODULE_LICENSE("GPL");
ad28a07bc   Kay Sievers   rtc: fix platform...
647
  MODULE_ALIAS("platform:s3c2410-rtc");