Root/drivers/rtc/rtc-lpc32xx.c

1/*
2 * Copyright (C) 2010 NXP Semiconductors
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * You should have received a copy of the GNU General Public License along
10 * with this program; if not, write to the Free Software Foundation, Inc.,
11 * 675 Mass Ave, Cambridge, MA 02139, USA.
12 */
13
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/init.h>
17#include <linux/platform_device.h>
18#include <linux/spinlock.h>
19#include <linux/rtc.h>
20#include <linux/slab.h>
21#include <linux/io.h>
22#include <linux/of.h>
23
24/*
25 * Clock and Power control register offsets
26 */
27#define LPC32XX_RTC_UCOUNT 0x00
28#define LPC32XX_RTC_DCOUNT 0x04
29#define LPC32XX_RTC_MATCH0 0x08
30#define LPC32XX_RTC_MATCH1 0x0C
31#define LPC32XX_RTC_CTRL 0x10
32#define LPC32XX_RTC_INTSTAT 0x14
33#define LPC32XX_RTC_KEY 0x18
34#define LPC32XX_RTC_SRAM 0x80
35
36#define LPC32XX_RTC_CTRL_MATCH0 (1 << 0)
37#define LPC32XX_RTC_CTRL_MATCH1 (1 << 1)
38#define LPC32XX_RTC_CTRL_ONSW_MATCH0 (1 << 2)
39#define LPC32XX_RTC_CTRL_ONSW_MATCH1 (1 << 3)
40#define LPC32XX_RTC_CTRL_SW_RESET (1 << 4)
41#define LPC32XX_RTC_CTRL_CNTR_DIS (1 << 6)
42#define LPC32XX_RTC_CTRL_ONSW_FORCE_HI (1 << 7)
43
44#define LPC32XX_RTC_INTSTAT_MATCH0 (1 << 0)
45#define LPC32XX_RTC_INTSTAT_MATCH1 (1 << 1)
46#define LPC32XX_RTC_INTSTAT_ONSW (1 << 2)
47
48#define LPC32XX_RTC_KEY_ONSW_LOADVAL 0xB5C13F27
49
50#define RTC_NAME "rtc-lpc32xx"
51
52#define rtc_readl(dev, reg) \
53    __raw_readl((dev)->rtc_base + (reg))
54#define rtc_writel(dev, reg, val) \
55    __raw_writel((val), (dev)->rtc_base + (reg))
56
57struct lpc32xx_rtc {
58    void __iomem *rtc_base;
59    int irq;
60    unsigned char alarm_enabled;
61    struct rtc_device *rtc;
62    spinlock_t lock;
63};
64
65static int lpc32xx_rtc_read_time(struct device *dev, struct rtc_time *time)
66{
67    unsigned long elapsed_sec;
68    struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
69
70    elapsed_sec = rtc_readl(rtc, LPC32XX_RTC_UCOUNT);
71    rtc_time_to_tm(elapsed_sec, time);
72
73    return rtc_valid_tm(time);
74}
75
76static int lpc32xx_rtc_set_mmss(struct device *dev, unsigned long secs)
77{
78    struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
79    u32 tmp;
80
81    spin_lock_irq(&rtc->lock);
82
83    /* RTC must be disabled during count update */
84    tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);
85    rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp | LPC32XX_RTC_CTRL_CNTR_DIS);
86    rtc_writel(rtc, LPC32XX_RTC_UCOUNT, secs);
87    rtc_writel(rtc, LPC32XX_RTC_DCOUNT, 0xFFFFFFFF - secs);
88    rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp &= ~LPC32XX_RTC_CTRL_CNTR_DIS);
89
90    spin_unlock_irq(&rtc->lock);
91
92    return 0;
93}
94
95static int lpc32xx_rtc_read_alarm(struct device *dev,
96    struct rtc_wkalrm *wkalrm)
97{
98    struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
99
100    rtc_time_to_tm(rtc_readl(rtc, LPC32XX_RTC_MATCH0), &wkalrm->time);
101    wkalrm->enabled = rtc->alarm_enabled;
102    wkalrm->pending = !!(rtc_readl(rtc, LPC32XX_RTC_INTSTAT) &
103        LPC32XX_RTC_INTSTAT_MATCH0);
104
105    return rtc_valid_tm(&wkalrm->time);
106}
107
108static int lpc32xx_rtc_set_alarm(struct device *dev,
109    struct rtc_wkalrm *wkalrm)
110{
111    struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
112    unsigned long alarmsecs;
113    u32 tmp;
114    int ret;
115
116    ret = rtc_tm_to_time(&wkalrm->time, &alarmsecs);
117    if (ret < 0) {
118        dev_warn(dev, "Failed to convert time: %d\n", ret);
119        return ret;
120    }
121
122    spin_lock_irq(&rtc->lock);
123
124    /* Disable alarm during update */
125    tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);
126    rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp & ~LPC32XX_RTC_CTRL_MATCH0);
127
128    rtc_writel(rtc, LPC32XX_RTC_MATCH0, alarmsecs);
129
130    rtc->alarm_enabled = wkalrm->enabled;
131    if (wkalrm->enabled) {
132        rtc_writel(rtc, LPC32XX_RTC_INTSTAT,
133               LPC32XX_RTC_INTSTAT_MATCH0);
134        rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp |
135               LPC32XX_RTC_CTRL_MATCH0);
136    }
137
138    spin_unlock_irq(&rtc->lock);
139
140    return 0;
141}
142
143static int lpc32xx_rtc_alarm_irq_enable(struct device *dev,
144    unsigned int enabled)
145{
146    struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
147    u32 tmp;
148
149    spin_lock_irq(&rtc->lock);
150    tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);
151
152    if (enabled) {
153        rtc->alarm_enabled = 1;
154        tmp |= LPC32XX_RTC_CTRL_MATCH0;
155    } else {
156        rtc->alarm_enabled = 0;
157        tmp &= ~LPC32XX_RTC_CTRL_MATCH0;
158    }
159
160    rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp);
161    spin_unlock_irq(&rtc->lock);
162
163    return 0;
164}
165
166static irqreturn_t lpc32xx_rtc_alarm_interrupt(int irq, void *dev)
167{
168    struct lpc32xx_rtc *rtc = dev;
169
170    spin_lock(&rtc->lock);
171
172    /* Disable alarm interrupt */
173    rtc_writel(rtc, LPC32XX_RTC_CTRL,
174        rtc_readl(rtc, LPC32XX_RTC_CTRL) &
175              ~LPC32XX_RTC_CTRL_MATCH0);
176    rtc->alarm_enabled = 0;
177
178    /*
179     * Write a large value to the match value so the RTC won't
180     * keep firing the match status
181     */
182    rtc_writel(rtc, LPC32XX_RTC_MATCH0, 0xFFFFFFFF);
183    rtc_writel(rtc, LPC32XX_RTC_INTSTAT, LPC32XX_RTC_INTSTAT_MATCH0);
184
185    spin_unlock(&rtc->lock);
186
187    rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
188
189    return IRQ_HANDLED;
190}
191
192static const struct rtc_class_ops lpc32xx_rtc_ops = {
193    .read_time = lpc32xx_rtc_read_time,
194    .set_mmss = lpc32xx_rtc_set_mmss,
195    .read_alarm = lpc32xx_rtc_read_alarm,
196    .set_alarm = lpc32xx_rtc_set_alarm,
197    .alarm_irq_enable = lpc32xx_rtc_alarm_irq_enable,
198};
199
200static int __devinit lpc32xx_rtc_probe(struct platform_device *pdev)
201{
202    struct resource *res;
203    struct lpc32xx_rtc *rtc;
204    resource_size_t size;
205    int rtcirq;
206    u32 tmp;
207
208    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
209    if (!res) {
210        dev_err(&pdev->dev, "Can't get memory resource\n");
211        return -ENOENT;
212    }
213
214    rtcirq = platform_get_irq(pdev, 0);
215    if (rtcirq < 0 || rtcirq >= NR_IRQS) {
216        dev_warn(&pdev->dev, "Can't get interrupt resource\n");
217        rtcirq = -1;
218    }
219
220    rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
221    if (unlikely(!rtc)) {
222        dev_err(&pdev->dev, "Can't allocate memory\n");
223        return -ENOMEM;
224    }
225    rtc->irq = rtcirq;
226
227    size = resource_size(res);
228
229    if (!devm_request_mem_region(&pdev->dev, res->start, size,
230                     pdev->name)) {
231        dev_err(&pdev->dev, "RTC registers are not free\n");
232        return -EBUSY;
233    }
234
235    rtc->rtc_base = devm_ioremap(&pdev->dev, res->start, size);
236    if (!rtc->rtc_base) {
237        dev_err(&pdev->dev, "Can't map memory\n");
238        return -ENOMEM;
239    }
240
241    spin_lock_init(&rtc->lock);
242
243    /*
244     * The RTC is on a separate power domain and can keep it's state
245     * across a chip power cycle. If the RTC has never been previously
246     * setup, then set it up now for the first time.
247     */
248    tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);
249    if (rtc_readl(rtc, LPC32XX_RTC_KEY) != LPC32XX_RTC_KEY_ONSW_LOADVAL) {
250        tmp &= ~(LPC32XX_RTC_CTRL_SW_RESET |
251            LPC32XX_RTC_CTRL_CNTR_DIS |
252            LPC32XX_RTC_CTRL_MATCH0 |
253            LPC32XX_RTC_CTRL_MATCH1 |
254            LPC32XX_RTC_CTRL_ONSW_MATCH0 |
255            LPC32XX_RTC_CTRL_ONSW_MATCH1 |
256            LPC32XX_RTC_CTRL_ONSW_FORCE_HI);
257        rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp);
258
259        /* Clear latched interrupt states */
260        rtc_writel(rtc, LPC32XX_RTC_MATCH0, 0xFFFFFFFF);
261        rtc_writel(rtc, LPC32XX_RTC_INTSTAT,
262               LPC32XX_RTC_INTSTAT_MATCH0 |
263               LPC32XX_RTC_INTSTAT_MATCH1 |
264               LPC32XX_RTC_INTSTAT_ONSW);
265
266        /* Write key value to RTC so it won't reload on reset */
267        rtc_writel(rtc, LPC32XX_RTC_KEY,
268               LPC32XX_RTC_KEY_ONSW_LOADVAL);
269    } else {
270        rtc_writel(rtc, LPC32XX_RTC_CTRL,
271               tmp & ~LPC32XX_RTC_CTRL_MATCH0);
272    }
273
274    platform_set_drvdata(pdev, rtc);
275
276    rtc->rtc = rtc_device_register(RTC_NAME, &pdev->dev, &lpc32xx_rtc_ops,
277        THIS_MODULE);
278    if (IS_ERR(rtc->rtc)) {
279        dev_err(&pdev->dev, "Can't get RTC\n");
280        platform_set_drvdata(pdev, NULL);
281        return PTR_ERR(rtc->rtc);
282    }
283
284    /*
285     * IRQ is enabled after device registration in case alarm IRQ
286     * is pending upon suspend exit.
287     */
288    if (rtc->irq >= 0) {
289        if (devm_request_irq(&pdev->dev, rtc->irq,
290                     lpc32xx_rtc_alarm_interrupt,
291                     0, pdev->name, rtc) < 0) {
292            dev_warn(&pdev->dev, "Can't request interrupt.\n");
293            rtc->irq = -1;
294        } else {
295            device_init_wakeup(&pdev->dev, 1);
296        }
297    }
298
299    return 0;
300}
301
302static int __devexit lpc32xx_rtc_remove(struct platform_device *pdev)
303{
304    struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
305
306    if (rtc->irq >= 0)
307        device_init_wakeup(&pdev->dev, 0);
308
309    platform_set_drvdata(pdev, NULL);
310    rtc_device_unregister(rtc->rtc);
311
312    return 0;
313}
314
315#ifdef CONFIG_PM
316static int lpc32xx_rtc_suspend(struct device *dev)
317{
318    struct platform_device *pdev = to_platform_device(dev);
319    struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
320
321    if (rtc->irq >= 0) {
322        if (device_may_wakeup(&pdev->dev))
323            enable_irq_wake(rtc->irq);
324        else
325            disable_irq_wake(rtc->irq);
326    }
327
328    return 0;
329}
330
331static int lpc32xx_rtc_resume(struct device *dev)
332{
333    struct platform_device *pdev = to_platform_device(dev);
334    struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
335
336    if (rtc->irq >= 0 && device_may_wakeup(&pdev->dev))
337        disable_irq_wake(rtc->irq);
338
339    return 0;
340}
341
342/* Unconditionally disable the alarm */
343static int lpc32xx_rtc_freeze(struct device *dev)
344{
345    struct platform_device *pdev = to_platform_device(dev);
346    struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
347
348    spin_lock_irq(&rtc->lock);
349
350    rtc_writel(rtc, LPC32XX_RTC_CTRL,
351        rtc_readl(rtc, LPC32XX_RTC_CTRL) &
352              ~LPC32XX_RTC_CTRL_MATCH0);
353
354    spin_unlock_irq(&rtc->lock);
355
356    return 0;
357}
358
359static int lpc32xx_rtc_thaw(struct device *dev)
360{
361    struct platform_device *pdev = to_platform_device(dev);
362    struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
363
364    if (rtc->alarm_enabled) {
365        spin_lock_irq(&rtc->lock);
366
367        rtc_writel(rtc, LPC32XX_RTC_CTRL,
368               rtc_readl(rtc, LPC32XX_RTC_CTRL) |
369               LPC32XX_RTC_CTRL_MATCH0);
370
371        spin_unlock_irq(&rtc->lock);
372    }
373
374    return 0;
375}
376
377static const struct dev_pm_ops lpc32xx_rtc_pm_ops = {
378    .suspend = lpc32xx_rtc_suspend,
379    .resume = lpc32xx_rtc_resume,
380    .freeze = lpc32xx_rtc_freeze,
381    .thaw = lpc32xx_rtc_thaw,
382    .restore = lpc32xx_rtc_resume
383};
384
385#define LPC32XX_RTC_PM_OPS (&lpc32xx_rtc_pm_ops)
386#else
387#define LPC32XX_RTC_PM_OPS NULL
388#endif
389
390#ifdef CONFIG_OF
391static const struct of_device_id lpc32xx_rtc_match[] = {
392    { .compatible = "nxp,lpc3220-rtc" },
393    { }
394};
395MODULE_DEVICE_TABLE(of, lpc32xx_rtc_match);
396#endif
397
398static struct platform_driver lpc32xx_rtc_driver = {
399    .probe = lpc32xx_rtc_probe,
400    .remove = __devexit_p(lpc32xx_rtc_remove),
401    .driver = {
402        .name = RTC_NAME,
403        .owner = THIS_MODULE,
404        .pm = LPC32XX_RTC_PM_OPS,
405        .of_match_table = of_match_ptr(lpc32xx_rtc_match),
406    },
407};
408
409module_platform_driver(lpc32xx_rtc_driver);
410
411MODULE_AUTHOR("Kevin Wells <wellsk40@gmail.com");
412MODULE_DESCRIPTION("RTC driver for the LPC32xx SoC");
413MODULE_LICENSE("GPL");
414MODULE_ALIAS("platform:rtc-lpc32xx");
415

Archive Download this file



interactive