OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [rtc/] [rtc-at32ap700x.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * An RTC driver for the AVR32 AT32AP700x processor series.
3
 *
4
 * Copyright (C) 2007 Atmel Corporation
5
 *
6
 * This program is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU General Public License version 2 as published
8
 * by the Free Software Foundation.
9
 */
10
 
11
#include <linux/module.h>
12
#include <linux/kernel.h>
13
#include <linux/platform_device.h>
14
#include <linux/rtc.h>
15
#include <linux/io.h>
16
 
17
/*
18
 * This is a bare-bones RTC. It runs during most system sleep states, but has
19
 * no battery backup and gets reset during system restart.  It must be
20
 * initialized from an external clock (network, I2C, etc) before it can be of
21
 * much use.
22
 *
23
 * The alarm functionality is limited by the hardware, not supporting
24
 * periodic interrupts.
25
 */
26
 
27
#define RTC_CTRL                0x00
28
#define RTC_CTRL_EN                0
29
#define RTC_CTRL_PCLR              1
30
#define RTC_CTRL_TOPEN             2
31
#define RTC_CTRL_PSEL              8
32
 
33
#define RTC_VAL                 0x04
34
 
35
#define RTC_TOP                 0x08
36
 
37
#define RTC_IER                 0x10
38
#define RTC_IER_TOPI               0
39
 
40
#define RTC_IDR                 0x14
41
#define RTC_IDR_TOPI               0
42
 
43
#define RTC_IMR                 0x18
44
#define RTC_IMR_TOPI               0
45
 
46
#define RTC_ISR                 0x1c
47
#define RTC_ISR_TOPI               0
48
 
49
#define RTC_ICR                 0x20
50
#define RTC_ICR_TOPI               0
51
 
52
#define RTC_BIT(name)           (1 << RTC_##name)
53
#define RTC_BF(name, value)     ((value) << RTC_##name)
54
 
55
#define rtc_readl(dev, reg)                             \
56
        __raw_readl((dev)->regs + RTC_##reg)
57
#define rtc_writel(dev, reg, value)                     \
58
        __raw_writel((value), (dev)->regs + RTC_##reg)
59
 
60
struct rtc_at32ap700x {
61
        struct rtc_device       *rtc;
62
        void __iomem            *regs;
63
        unsigned long           alarm_time;
64
        unsigned long           irq;
65
        /* Protect against concurrent register access. */
66
        spinlock_t              lock;
67
};
68
 
69
static int at32_rtc_readtime(struct device *dev, struct rtc_time *tm)
70
{
71
        struct rtc_at32ap700x *rtc = dev_get_drvdata(dev);
72
        unsigned long now;
73
 
74
        now = rtc_readl(rtc, VAL);
75
        rtc_time_to_tm(now, tm);
76
 
77
        return 0;
78
}
79
 
80
static int at32_rtc_settime(struct device *dev, struct rtc_time *tm)
81
{
82
        struct rtc_at32ap700x *rtc = dev_get_drvdata(dev);
83
        unsigned long now;
84
        int ret;
85
 
86
        ret = rtc_tm_to_time(tm, &now);
87
        if (ret == 0)
88
                rtc_writel(rtc, VAL, now);
89
 
90
        return ret;
91
}
92
 
93
static int at32_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
94
{
95
        struct rtc_at32ap700x *rtc = dev_get_drvdata(dev);
96
 
97
        rtc_time_to_tm(rtc->alarm_time, &alrm->time);
98
        alrm->pending = rtc_readl(rtc, IMR) & RTC_BIT(IMR_TOPI) ? 1 : 0;
99
 
100
        return 0;
101
}
102
 
103
static int at32_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
104
{
105
        struct rtc_at32ap700x *rtc = dev_get_drvdata(dev);
106
        unsigned long rtc_unix_time;
107
        unsigned long alarm_unix_time;
108
        int ret;
109
 
110
        rtc_unix_time = rtc_readl(rtc, VAL);
111
 
112
        ret = rtc_tm_to_time(&alrm->time, &alarm_unix_time);
113
        if (ret)
114
                return ret;
115
 
116
        if (alarm_unix_time < rtc_unix_time)
117
                return -EINVAL;
118
 
119
        spin_lock_irq(&rtc->lock);
120
        rtc->alarm_time = alarm_unix_time;
121
        rtc_writel(rtc, TOP, rtc->alarm_time);
122
        if (alrm->pending)
123
                rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL)
124
                                | RTC_BIT(CTRL_TOPEN));
125
        else
126
                rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL)
127
                                & ~RTC_BIT(CTRL_TOPEN));
128
        spin_unlock_irq(&rtc->lock);
129
 
130
        return ret;
131
}
132
 
133
static int at32_rtc_ioctl(struct device *dev, unsigned int cmd,
134
                        unsigned long arg)
135
{
136
        struct rtc_at32ap700x *rtc = dev_get_drvdata(dev);
137
        int ret = 0;
138
 
139
        spin_lock_irq(&rtc->lock);
140
 
141
        switch (cmd) {
142
        case RTC_AIE_ON:
143
                if (rtc_readl(rtc, VAL) > rtc->alarm_time) {
144
                        ret = -EINVAL;
145
                        break;
146
                }
147
                rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL)
148
                                | RTC_BIT(CTRL_TOPEN));
149
                rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI));
150
                rtc_writel(rtc, IER, RTC_BIT(IER_TOPI));
151
                break;
152
        case RTC_AIE_OFF:
153
                rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL)
154
                                & ~RTC_BIT(CTRL_TOPEN));
155
                rtc_writel(rtc, IDR, RTC_BIT(IDR_TOPI));
156
                rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI));
157
                break;
158
        default:
159
                ret = -ENOIOCTLCMD;
160
                break;
161
        }
162
 
163
        spin_unlock_irq(&rtc->lock);
164
 
165
        return ret;
166
}
167
 
168
static irqreturn_t at32_rtc_interrupt(int irq, void *dev_id)
169
{
170
        struct rtc_at32ap700x *rtc = (struct rtc_at32ap700x *)dev_id;
171
        unsigned long isr = rtc_readl(rtc, ISR);
172
        unsigned long events = 0;
173
        int ret = IRQ_NONE;
174
 
175
        spin_lock(&rtc->lock);
176
 
177
        if (isr & RTC_BIT(ISR_TOPI)) {
178
                rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI));
179
                rtc_writel(rtc, IDR, RTC_BIT(IDR_TOPI));
180
                rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL)
181
                                & ~RTC_BIT(CTRL_TOPEN));
182
                rtc_writel(rtc, VAL, rtc->alarm_time);
183
                events = RTC_AF | RTC_IRQF;
184
                rtc_update_irq(rtc->rtc, 1, events);
185
                ret = IRQ_HANDLED;
186
        }
187
 
188
        spin_unlock(&rtc->lock);
189
 
190
        return ret;
191
}
192
 
193
static struct rtc_class_ops at32_rtc_ops = {
194
        .ioctl          = at32_rtc_ioctl,
195
        .read_time      = at32_rtc_readtime,
196
        .set_time       = at32_rtc_settime,
197
        .read_alarm     = at32_rtc_readalarm,
198
        .set_alarm      = at32_rtc_setalarm,
199
};
200
 
201
static int __init at32_rtc_probe(struct platform_device *pdev)
202
{
203
        struct resource *regs;
204
        struct rtc_at32ap700x *rtc;
205
        int irq = -1;
206
        int ret;
207
 
208
        rtc = kzalloc(sizeof(struct rtc_at32ap700x), GFP_KERNEL);
209
        if (!rtc) {
210
                dev_dbg(&pdev->dev, "out of memory\n");
211
                return -ENOMEM;
212
        }
213
 
214
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
215
        if (!regs) {
216
                dev_dbg(&pdev->dev, "no mmio resource defined\n");
217
                ret = -ENXIO;
218
                goto out;
219
        }
220
 
221
        irq = platform_get_irq(pdev, 0);
222
        if (irq < 0) {
223
                dev_dbg(&pdev->dev, "could not get irq\n");
224
                ret = -ENXIO;
225
                goto out;
226
        }
227
 
228
        rtc->irq = irq;
229
        rtc->regs = ioremap(regs->start, regs->end - regs->start + 1);
230
        if (!rtc->regs) {
231
                ret = -ENOMEM;
232
                dev_dbg(&pdev->dev, "could not map I/O memory\n");
233
                goto out;
234
        }
235
        spin_lock_init(&rtc->lock);
236
 
237
        /*
238
         * Maybe init RTC: count from zero at 1 Hz, disable wrap irq.
239
         *
240
         * Do not reset VAL register, as it can hold an old time
241
         * from last JTAG reset.
242
         */
243
        if (!(rtc_readl(rtc, CTRL) & RTC_BIT(CTRL_EN))) {
244
                rtc_writel(rtc, CTRL, RTC_BIT(CTRL_PCLR));
245
                rtc_writel(rtc, IDR, RTC_BIT(IDR_TOPI));
246
                rtc_writel(rtc, CTRL, RTC_BF(CTRL_PSEL, 0xe)
247
                                | RTC_BIT(CTRL_EN));
248
        }
249
 
250
        ret = request_irq(irq, at32_rtc_interrupt, IRQF_SHARED, "rtc", rtc);
251
        if (ret) {
252
                dev_dbg(&pdev->dev, "could not request irq %d\n", irq);
253
                goto out_iounmap;
254
        }
255
 
256
        rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
257
                                &at32_rtc_ops, THIS_MODULE);
258
        if (IS_ERR(rtc->rtc)) {
259
                dev_dbg(&pdev->dev, "could not register rtc device\n");
260
                ret = PTR_ERR(rtc->rtc);
261
                goto out_free_irq;
262
        }
263
 
264
        platform_set_drvdata(pdev, rtc);
265
 
266
        dev_info(&pdev->dev, "Atmel RTC for AT32AP700x at %08lx irq %ld\n",
267
                        (unsigned long)rtc->regs, rtc->irq);
268
 
269
        return 0;
270
 
271
out_free_irq:
272
        free_irq(irq, rtc);
273
out_iounmap:
274
        iounmap(rtc->regs);
275
out:
276
        kfree(rtc);
277
        return ret;
278
}
279
 
280
static int __exit at32_rtc_remove(struct platform_device *pdev)
281
{
282
        struct rtc_at32ap700x *rtc = platform_get_drvdata(pdev);
283
 
284
        free_irq(rtc->irq, rtc);
285
        iounmap(rtc->regs);
286
        rtc_device_unregister(rtc->rtc);
287
        kfree(rtc);
288
        platform_set_drvdata(pdev, NULL);
289
 
290
        return 0;
291
}
292
 
293
MODULE_ALIAS("at32ap700x_rtc");
294
 
295
static struct platform_driver at32_rtc_driver = {
296
        .remove         = __exit_p(at32_rtc_remove),
297
        .driver         = {
298
                .name   = "at32ap700x_rtc",
299
                .owner  = THIS_MODULE,
300
        },
301
};
302
 
303
static int __init at32_rtc_init(void)
304
{
305
        return platform_driver_probe(&at32_rtc_driver, at32_rtc_probe);
306
}
307
module_init(at32_rtc_init);
308
 
309
static void __exit at32_rtc_exit(void)
310
{
311
        platform_driver_unregister(&at32_rtc_driver);
312
}
313
module_exit(at32_rtc_exit);
314
 
315
MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
316
MODULE_DESCRIPTION("Real time clock for AVR32 AT32AP700x");
317
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.