Branch data Line data Source code
1 : : /*
2 : : * drivers/rtc/rtc-pl031.c
3 : : *
4 : : * Real Time Clock interface for ARM AMBA PrimeCell 031 RTC
5 : : *
6 : : * Author: Deepak Saxena <dsaxena@plexity.net>
7 : : *
8 : : * Copyright 2006 (c) MontaVista Software, Inc.
9 : : *
10 : : * Author: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
11 : : * Copyright 2010 (c) ST-Ericsson AB
12 : : *
13 : : * This program is free software; you can redistribute it and/or
14 : : * modify it under the terms of the GNU General Public License
15 : : * as published by the Free Software Foundation; either version
16 : : * 2 of the License, or (at your option) any later version.
17 : : */
18 : : #include <linux/module.h>
19 : : #include <linux/rtc.h>
20 : : #include <linux/init.h>
21 : : #include <linux/interrupt.h>
22 : : #include <linux/amba/bus.h>
23 : : #include <linux/io.h>
24 : : #include <linux/bcd.h>
25 : : #include <linux/delay.h>
26 : : #include <linux/slab.h>
27 : :
28 : : /*
29 : : * Register definitions
30 : : */
31 : : #define RTC_DR 0x00 /* Data read register */
32 : : #define RTC_MR 0x04 /* Match register */
33 : : #define RTC_LR 0x08 /* Data load register */
34 : : #define RTC_CR 0x0c /* Control register */
35 : : #define RTC_IMSC 0x10 /* Interrupt mask and set register */
36 : : #define RTC_RIS 0x14 /* Raw interrupt status register */
37 : : #define RTC_MIS 0x18 /* Masked interrupt status register */
38 : : #define RTC_ICR 0x1c /* Interrupt clear register */
39 : : /* ST variants have additional timer functionality */
40 : : #define RTC_TDR 0x20 /* Timer data read register */
41 : : #define RTC_TLR 0x24 /* Timer data load register */
42 : : #define RTC_TCR 0x28 /* Timer control register */
43 : : #define RTC_YDR 0x30 /* Year data read register */
44 : : #define RTC_YMR 0x34 /* Year match register */
45 : : #define RTC_YLR 0x38 /* Year data load register */
46 : :
47 : : #define RTC_CR_EN (1 << 0) /* counter enable bit */
48 : : #define RTC_CR_CWEN (1 << 26) /* Clockwatch enable bit */
49 : :
50 : : #define RTC_TCR_EN (1 << 1) /* Periodic timer enable bit */
51 : :
52 : : /* Common bit definitions for Interrupt status and control registers */
53 : : #define RTC_BIT_AI (1 << 0) /* Alarm interrupt bit */
54 : : #define RTC_BIT_PI (1 << 1) /* Periodic interrupt bit. ST variants only. */
55 : :
56 : : /* Common bit definations for ST v2 for reading/writing time */
57 : : #define RTC_SEC_SHIFT 0
58 : : #define RTC_SEC_MASK (0x3F << RTC_SEC_SHIFT) /* Second [0-59] */
59 : : #define RTC_MIN_SHIFT 6
60 : : #define RTC_MIN_MASK (0x3F << RTC_MIN_SHIFT) /* Minute [0-59] */
61 : : #define RTC_HOUR_SHIFT 12
62 : : #define RTC_HOUR_MASK (0x1F << RTC_HOUR_SHIFT) /* Hour [0-23] */
63 : : #define RTC_WDAY_SHIFT 17
64 : : #define RTC_WDAY_MASK (0x7 << RTC_WDAY_SHIFT) /* Day of Week [1-7] 1=Sunday */
65 : : #define RTC_MDAY_SHIFT 20
66 : : #define RTC_MDAY_MASK (0x1F << RTC_MDAY_SHIFT) /* Day of Month [1-31] */
67 : : #define RTC_MON_SHIFT 25
68 : : #define RTC_MON_MASK (0xF << RTC_MON_SHIFT) /* Month [1-12] 1=January */
69 : :
70 : : #define RTC_TIMER_FREQ 32768
71 : :
72 : : /**
73 : : * struct pl031_vendor_data - per-vendor variations
74 : : * @ops: the vendor-specific operations used on this silicon version
75 : : * @clockwatch: if this is an ST Microelectronics silicon version with a
76 : : * clockwatch function
77 : : * @st_weekday: if this is an ST Microelectronics silicon version that need
78 : : * the weekday fix
79 : : * @irqflags: special IRQ flags per variant
80 : : */
81 : : struct pl031_vendor_data {
82 : : struct rtc_class_ops ops;
83 : : bool clockwatch;
84 : : bool st_weekday;
85 : : unsigned long irqflags;
86 : : };
87 : :
88 : : struct pl031_local {
89 : : struct pl031_vendor_data *vendor;
90 : : struct rtc_device *rtc;
91 : : void __iomem *base;
92 : : };
93 : :
94 : 0 : static int pl031_alarm_irq_enable(struct device *dev,
95 : : unsigned int enabled)
96 : : {
97 : 1 : struct pl031_local *ldata = dev_get_drvdata(dev);
98 : : unsigned long imsc;
99 : :
100 : : /* Clear any pending alarm interrupts. */
101 : 1 : writel(RTC_BIT_AI, ldata->base + RTC_ICR);
102 : :
103 : 1 : imsc = readl(ldata->base + RTC_IMSC);
104 : :
105 [ - + ]: 1 : if (enabled == 1)
106 : 0 : writel(imsc | RTC_BIT_AI, ldata->base + RTC_IMSC);
107 : : else
108 : 1 : writel(imsc & ~RTC_BIT_AI, ldata->base + RTC_IMSC);
109 : :
110 : 1 : return 0;
111 : : }
112 : :
113 : : /*
114 : : * Convert Gregorian date to ST v2 RTC format.
115 : : */
116 : 0 : static int pl031_stv2_tm_to_time(struct device *dev,
117 : : struct rtc_time *tm, unsigned long *st_time,
118 : : unsigned long *bcd_year)
119 : : {
120 : 0 : int year = tm->tm_year + 1900;
121 : 0 : int wday = tm->tm_wday;
122 : :
123 : : /* wday masking is not working in hardware so wday must be valid */
124 [ # # ]: 0 : if (wday < -1 || wday > 6) {
125 : 0 : dev_err(dev, "invalid wday value %d\n", tm->tm_wday);
126 : 0 : return -EINVAL;
127 [ # # ]: 0 : } else if (wday == -1) {
128 : : /* wday is not provided, calculate it here */
129 : : unsigned long time;
130 : : struct rtc_time calc_tm;
131 : :
132 : 0 : rtc_tm_to_time(tm, &time);
133 : 0 : rtc_time_to_tm(time, &calc_tm);
134 : 0 : wday = calc_tm.tm_wday;
135 : : }
136 : :
137 [ # # ][ # # ]: 0 : *bcd_year = (bin2bcd(year % 100) | bin2bcd(year / 100) << 8);
138 : :
139 : 0 : *st_time = ((tm->tm_mon + 1) << RTC_MON_SHIFT)
140 : 0 : | (tm->tm_mday << RTC_MDAY_SHIFT)
141 : 0 : | ((wday + 1) << RTC_WDAY_SHIFT)
142 : 0 : | (tm->tm_hour << RTC_HOUR_SHIFT)
143 : 0 : | (tm->tm_min << RTC_MIN_SHIFT)
144 : 0 : | (tm->tm_sec << RTC_SEC_SHIFT);
145 : :
146 : 0 : return 0;
147 : : }
148 : :
149 : : /*
150 : : * Convert ST v2 RTC format to Gregorian date.
151 : : */
152 : 0 : static int pl031_stv2_time_to_tm(unsigned long st_time, unsigned long bcd_year,
153 : : struct rtc_time *tm)
154 : : {
155 [ # # ][ # # ]: 0 : tm->tm_year = bcd2bin(bcd_year) + (bcd2bin(bcd_year >> 8) * 100);
156 : 0 : tm->tm_mon = ((st_time & RTC_MON_MASK) >> RTC_MON_SHIFT) - 1;
157 : 0 : tm->tm_mday = ((st_time & RTC_MDAY_MASK) >> RTC_MDAY_SHIFT);
158 : 0 : tm->tm_wday = ((st_time & RTC_WDAY_MASK) >> RTC_WDAY_SHIFT) - 1;
159 : 0 : tm->tm_hour = ((st_time & RTC_HOUR_MASK) >> RTC_HOUR_SHIFT);
160 : 0 : tm->tm_min = ((st_time & RTC_MIN_MASK) >> RTC_MIN_SHIFT);
161 : 0 : tm->tm_sec = ((st_time & RTC_SEC_MASK) >> RTC_SEC_SHIFT);
162 : :
163 : 0 : tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
164 : 0 : tm->tm_year -= 1900;
165 : :
166 : 0 : return 0;
167 : : }
168 : :
169 : 0 : static int pl031_stv2_read_time(struct device *dev, struct rtc_time *tm)
170 : : {
171 : 0 : struct pl031_local *ldata = dev_get_drvdata(dev);
172 : :
173 : 0 : pl031_stv2_time_to_tm(readl(ldata->base + RTC_DR),
174 : 0 : readl(ldata->base + RTC_YDR), tm);
175 : :
176 : 0 : return 0;
177 : : }
178 : :
179 : 0 : static int pl031_stv2_set_time(struct device *dev, struct rtc_time *tm)
180 : : {
181 : : unsigned long time;
182 : : unsigned long bcd_year;
183 : 0 : struct pl031_local *ldata = dev_get_drvdata(dev);
184 : : int ret;
185 : :
186 : 0 : ret = pl031_stv2_tm_to_time(dev, tm, &time, &bcd_year);
187 [ # # ]: 0 : if (ret == 0) {
188 : 0 : writel(bcd_year, ldata->base + RTC_YLR);
189 : 0 : writel(time, ldata->base + RTC_LR);
190 : : }
191 : :
192 : 0 : return ret;
193 : : }
194 : :
195 : 0 : static int pl031_stv2_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
196 : : {
197 : 0 : struct pl031_local *ldata = dev_get_drvdata(dev);
198 : : int ret;
199 : :
200 : 0 : ret = pl031_stv2_time_to_tm(readl(ldata->base + RTC_MR),
201 : 0 : readl(ldata->base + RTC_YMR), &alarm->time);
202 : :
203 : 0 : alarm->pending = readl(ldata->base + RTC_RIS) & RTC_BIT_AI;
204 : 0 : alarm->enabled = readl(ldata->base + RTC_IMSC) & RTC_BIT_AI;
205 : :
206 : 0 : return ret;
207 : : }
208 : :
209 : 0 : static int pl031_stv2_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
210 : : {
211 : 0 : struct pl031_local *ldata = dev_get_drvdata(dev);
212 : : unsigned long time;
213 : : unsigned long bcd_year;
214 : : int ret;
215 : :
216 : : /* At the moment, we can only deal with non-wildcarded alarm times. */
217 : 0 : ret = rtc_valid_tm(&alarm->time);
218 [ # # ]: 0 : if (ret == 0) {
219 : 0 : ret = pl031_stv2_tm_to_time(dev, &alarm->time,
220 : : &time, &bcd_year);
221 [ # # ]: 0 : if (ret == 0) {
222 : 0 : writel(bcd_year, ldata->base + RTC_YMR);
223 : 0 : writel(time, ldata->base + RTC_MR);
224 : :
225 : 0 : pl031_alarm_irq_enable(dev, alarm->enabled);
226 : : }
227 : : }
228 : :
229 : 0 : return ret;
230 : : }
231 : :
232 : 0 : static irqreturn_t pl031_interrupt(int irq, void *dev_id)
233 : : {
234 : : struct pl031_local *ldata = dev_id;
235 : : unsigned long rtcmis;
236 : : unsigned long events = 0;
237 : :
238 : 0 : rtcmis = readl(ldata->base + RTC_MIS);
239 [ # # ]: 0 : if (rtcmis & RTC_BIT_AI) {
240 : 0 : writel(RTC_BIT_AI, ldata->base + RTC_ICR);
241 : : events |= (RTC_AF | RTC_IRQF);
242 : 0 : rtc_update_irq(ldata->rtc, 1, events);
243 : :
244 : 0 : return IRQ_HANDLED;
245 : : }
246 : :
247 : : return IRQ_NONE;
248 : : }
249 : :
250 : 0 : static int pl031_read_time(struct device *dev, struct rtc_time *tm)
251 : : {
252 : 2 : struct pl031_local *ldata = dev_get_drvdata(dev);
253 : :
254 : 2 : rtc_time_to_tm(readl(ldata->base + RTC_DR), tm);
255 : :
256 : 2 : return 0;
257 : : }
258 : :
259 : 0 : static int pl031_set_time(struct device *dev, struct rtc_time *tm)
260 : : {
261 : : unsigned long time;
262 : 1 : struct pl031_local *ldata = dev_get_drvdata(dev);
263 : : int ret;
264 : :
265 : 1 : ret = rtc_tm_to_time(tm, &time);
266 : :
267 [ + - ]: 1 : if (ret == 0)
268 : 1 : writel(time, ldata->base + RTC_LR);
269 : :
270 : 1 : return ret;
271 : : }
272 : :
273 : 0 : static int pl031_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
274 : : {
275 : 0 : struct pl031_local *ldata = dev_get_drvdata(dev);
276 : :
277 : 0 : rtc_time_to_tm(readl(ldata->base + RTC_MR), &alarm->time);
278 : :
279 : 0 : alarm->pending = readl(ldata->base + RTC_RIS) & RTC_BIT_AI;
280 : 0 : alarm->enabled = readl(ldata->base + RTC_IMSC) & RTC_BIT_AI;
281 : :
282 : 0 : return 0;
283 : : }
284 : :
285 : 0 : static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
286 : : {
287 : 0 : struct pl031_local *ldata = dev_get_drvdata(dev);
288 : : unsigned long time;
289 : : int ret;
290 : :
291 : : /* At the moment, we can only deal with non-wildcarded alarm times. */
292 : 0 : ret = rtc_valid_tm(&alarm->time);
293 [ # # ]: 0 : if (ret == 0) {
294 : 0 : ret = rtc_tm_to_time(&alarm->time, &time);
295 [ # # ]: 0 : if (ret == 0) {
296 : 0 : writel(time, ldata->base + RTC_MR);
297 : 0 : pl031_alarm_irq_enable(dev, alarm->enabled);
298 : : }
299 : : }
300 : :
301 : 0 : return ret;
302 : : }
303 : :
304 : 0 : static int pl031_remove(struct amba_device *adev)
305 : : {
306 : 0 : struct pl031_local *ldata = dev_get_drvdata(&adev->dev);
307 : :
308 : 0 : free_irq(adev->irq[0], ldata);
309 : 0 : rtc_device_unregister(ldata->rtc);
310 : 0 : iounmap(ldata->base);
311 : 0 : kfree(ldata);
312 : 0 : amba_release_regions(adev);
313 : :
314 : 0 : return 0;
315 : : }
316 : :
317 : 0 : static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
318 : : {
319 : : int ret;
320 : : struct pl031_local *ldata;
321 : 0 : struct pl031_vendor_data *vendor = id->data;
322 : 0 : struct rtc_class_ops *ops = &vendor->ops;
323 : : unsigned long time, data;
324 : :
325 : 0 : ret = amba_request_regions(adev, NULL);
326 [ # # ]: 0 : if (ret)
327 : : goto err_req;
328 : :
329 : : ldata = kzalloc(sizeof(struct pl031_local), GFP_KERNEL);
330 [ # # ]: 0 : if (!ldata) {
331 : : ret = -ENOMEM;
332 : : goto out;
333 : : }
334 : 0 : ldata->vendor = vendor;
335 : :
336 : 0 : ldata->base = ioremap(adev->res.start, resource_size(&adev->res));
337 : :
338 [ # # ]: 0 : if (!ldata->base) {
339 : : ret = -ENOMEM;
340 : : goto out_no_remap;
341 : : }
342 : :
343 : 0 : amba_set_drvdata(adev, ldata);
344 : :
345 : : dev_dbg(&adev->dev, "designer ID = 0x%02x\n", amba_manf(adev));
346 : : dev_dbg(&adev->dev, "revision = 0x%01x\n", amba_rev(adev));
347 : :
348 : 0 : data = readl(ldata->base + RTC_CR);
349 : : /* Enable the clockwatch on ST Variants */
350 [ # # ]: 0 : if (vendor->clockwatch)
351 : 0 : data |= RTC_CR_CWEN;
352 : : else
353 : 0 : data |= RTC_CR_EN;
354 : 0 : writel(data, ldata->base + RTC_CR);
355 : :
356 : : /*
357 : : * On ST PL031 variants, the RTC reset value does not provide correct
358 : : * weekday for 2000-01-01. Correct the erroneous sunday to saturday.
359 : : */
360 [ # # ]: 0 : if (vendor->st_weekday) {
361 [ # # ]: 0 : if (readl(ldata->base + RTC_YDR) == 0x2000) {
362 : 0 : time = readl(ldata->base + RTC_DR);
363 [ # # ]: 0 : if ((time &
364 : : (RTC_MON_MASK | RTC_MDAY_MASK | RTC_WDAY_MASK))
365 : : == 0x02120000) {
366 : 0 : time = time | (0x7 << RTC_WDAY_SHIFT);
367 : 0 : writel(0x2000, ldata->base + RTC_YLR);
368 : 0 : writel(time, ldata->base + RTC_LR);
369 : : }
370 : : }
371 : : }
372 : :
373 : 0 : device_init_wakeup(&adev->dev, 1);
374 : 0 : ldata->rtc = rtc_device_register("pl031", &adev->dev, ops,
375 : : THIS_MODULE);
376 [ # # ]: 0 : if (IS_ERR(ldata->rtc)) {
377 : : ret = PTR_ERR(ldata->rtc);
378 : 0 : goto out_no_rtc;
379 : : }
380 : :
381 [ # # ]: 0 : if (request_irq(adev->irq[0], pl031_interrupt,
382 : : vendor->irqflags, "rtc-pl031", ldata)) {
383 : : ret = -EIO;
384 : : goto out_no_irq;
385 : : }
386 : :
387 : : return 0;
388 : :
389 : : out_no_irq:
390 : 0 : rtc_device_unregister(ldata->rtc);
391 : : out_no_rtc:
392 : 0 : iounmap(ldata->base);
393 : : out_no_remap:
394 : 0 : kfree(ldata);
395 : : out:
396 : 0 : amba_release_regions(adev);
397 : : err_req:
398 : :
399 : 0 : return ret;
400 : : }
401 : :
402 : : /* Operations for the original ARM version */
403 : : static struct pl031_vendor_data arm_pl031 = {
404 : : .ops = {
405 : : .read_time = pl031_read_time,
406 : : .set_time = pl031_set_time,
407 : : .read_alarm = pl031_read_alarm,
408 : : .set_alarm = pl031_set_alarm,
409 : : .alarm_irq_enable = pl031_alarm_irq_enable,
410 : : },
411 : : .irqflags = IRQF_NO_SUSPEND,
412 : : };
413 : :
414 : : /* The First ST derivative */
415 : : static struct pl031_vendor_data stv1_pl031 = {
416 : : .ops = {
417 : : .read_time = pl031_read_time,
418 : : .set_time = pl031_set_time,
419 : : .read_alarm = pl031_read_alarm,
420 : : .set_alarm = pl031_set_alarm,
421 : : .alarm_irq_enable = pl031_alarm_irq_enable,
422 : : },
423 : : .clockwatch = true,
424 : : .st_weekday = true,
425 : : .irqflags = IRQF_NO_SUSPEND,
426 : : };
427 : :
428 : : /* And the second ST derivative */
429 : : static struct pl031_vendor_data stv2_pl031 = {
430 : : .ops = {
431 : : .read_time = pl031_stv2_read_time,
432 : : .set_time = pl031_stv2_set_time,
433 : : .read_alarm = pl031_stv2_read_alarm,
434 : : .set_alarm = pl031_stv2_set_alarm,
435 : : .alarm_irq_enable = pl031_alarm_irq_enable,
436 : : },
437 : : .clockwatch = true,
438 : : .st_weekday = true,
439 : : /*
440 : : * This variant shares the IRQ with another block and must not
441 : : * suspend that IRQ line.
442 : : */
443 : : .irqflags = IRQF_SHARED | IRQF_NO_SUSPEND,
444 : : };
445 : :
446 : : static struct amba_id pl031_ids[] = {
447 : : {
448 : : .id = 0x00041031,
449 : : .mask = 0x000fffff,
450 : : .data = &arm_pl031,
451 : : },
452 : : /* ST Micro variants */
453 : : {
454 : : .id = 0x00180031,
455 : : .mask = 0x00ffffff,
456 : : .data = &stv1_pl031,
457 : : },
458 : : {
459 : : .id = 0x00280031,
460 : : .mask = 0x00ffffff,
461 : : .data = &stv2_pl031,
462 : : },
463 : : {0, 0},
464 : : };
465 : :
466 : : MODULE_DEVICE_TABLE(amba, pl031_ids);
467 : :
468 : : static struct amba_driver pl031_driver = {
469 : : .drv = {
470 : : .name = "rtc-pl031",
471 : : },
472 : : .id_table = pl031_ids,
473 : : .probe = pl031_probe,
474 : : .remove = pl031_remove,
475 : : };
476 : :
477 : 0 : module_amba_driver(pl031_driver);
478 : :
479 : : MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net");
480 : : MODULE_DESCRIPTION("ARM AMBA PL031 RTC Driver");
481 : : MODULE_LICENSE("GPL");
|