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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [rtc/] [rtc-vr41xx.c] - Blame information for rev 78

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 *  Driver for NEC VR4100 series Real Time Clock unit.
3
 *
4
 *  Copyright (C) 2003-2006  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
5
 *
6
 *  This program is free software; you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation; either version 2 of the License, or
9
 *  (at your option) any later version.
10
 *
11
 *  This program is distributed in the hope that it will be useful,
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  GNU General Public License for more details.
15
 *
16
 *  You should have received a copy of the GNU General Public License
17
 *  along with this program; if not, write to the Free Software
18
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 */
20
#include <linux/err.h>
21
#include <linux/fs.h>
22
#include <linux/init.h>
23
#include <linux/ioport.h>
24
#include <linux/interrupt.h>
25
#include <linux/module.h>
26
#include <linux/platform_device.h>
27
#include <linux/rtc.h>
28
#include <linux/spinlock.h>
29
#include <linux/types.h>
30
 
31
#include <asm/div64.h>
32
#include <asm/io.h>
33
#include <asm/uaccess.h>
34
 
35
MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
36
MODULE_DESCRIPTION("NEC VR4100 series RTC driver");
37
MODULE_LICENSE("GPL");
38
 
39
/* RTC 1 registers */
40
#define ETIMELREG               0x00
41
#define ETIMEMREG               0x02
42
#define ETIMEHREG               0x04
43
/* RFU */
44
#define ECMPLREG                0x08
45
#define ECMPMREG                0x0a
46
#define ECMPHREG                0x0c
47
/* RFU */
48
#define RTCL1LREG               0x10
49
#define RTCL1HREG               0x12
50
#define RTCL1CNTLREG            0x14
51
#define RTCL1CNTHREG            0x16
52
#define RTCL2LREG               0x18
53
#define RTCL2HREG               0x1a
54
#define RTCL2CNTLREG            0x1c
55
#define RTCL2CNTHREG            0x1e
56
 
57
/* RTC 2 registers */
58
#define TCLKLREG                0x00
59
#define TCLKHREG                0x02
60
#define TCLKCNTLREG             0x04
61
#define TCLKCNTHREG             0x06
62
/* RFU */
63
#define RTCINTREG               0x1e
64
 #define TCLOCK_INT             0x08
65
 #define RTCLONG2_INT           0x04
66
 #define RTCLONG1_INT           0x02
67
 #define ELAPSEDTIME_INT        0x01
68
 
69
#define RTC_FREQUENCY           32768
70
#define MAX_PERIODIC_RATE       6553
71
 
72
static void __iomem *rtc1_base;
73
static void __iomem *rtc2_base;
74
 
75
#define rtc1_read(offset)               readw(rtc1_base + (offset))
76
#define rtc1_write(offset, value)       writew((value), rtc1_base + (offset))
77
 
78
#define rtc2_read(offset)               readw(rtc2_base + (offset))
79
#define rtc2_write(offset, value)       writew((value), rtc2_base + (offset))
80
 
81
static unsigned long epoch = 1970;      /* Jan 1 1970 00:00:00 */
82
 
83
static DEFINE_SPINLOCK(rtc_lock);
84
static char rtc_name[] = "RTC";
85
static unsigned long periodic_frequency;
86
static unsigned long periodic_count;
87
static unsigned int alarm_enabled;
88
static int aie_irq = -1;
89
static int pie_irq = -1;
90
 
91
static inline unsigned long read_elapsed_second(void)
92
{
93
 
94
        unsigned long first_low, first_mid, first_high;
95
 
96
        unsigned long second_low, second_mid, second_high;
97
 
98
        do {
99
                first_low = rtc1_read(ETIMELREG);
100
                first_mid = rtc1_read(ETIMEMREG);
101
                first_high = rtc1_read(ETIMEHREG);
102
                second_low = rtc1_read(ETIMELREG);
103
                second_mid = rtc1_read(ETIMEMREG);
104
                second_high = rtc1_read(ETIMEHREG);
105
        } while (first_low != second_low || first_mid != second_mid ||
106
                 first_high != second_high);
107
 
108
        return (first_high << 17) | (first_mid << 1) | (first_low >> 15);
109
}
110
 
111
static inline void write_elapsed_second(unsigned long sec)
112
{
113
        spin_lock_irq(&rtc_lock);
114
 
115
        rtc1_write(ETIMELREG, (uint16_t)(sec << 15));
116
        rtc1_write(ETIMEMREG, (uint16_t)(sec >> 1));
117
        rtc1_write(ETIMEHREG, (uint16_t)(sec >> 17));
118
 
119
        spin_unlock_irq(&rtc_lock);
120
}
121
 
122
static void vr41xx_rtc_release(struct device *dev)
123
{
124
 
125
        spin_lock_irq(&rtc_lock);
126
 
127
        rtc1_write(ECMPLREG, 0);
128
        rtc1_write(ECMPMREG, 0);
129
        rtc1_write(ECMPHREG, 0);
130
        rtc1_write(RTCL1LREG, 0);
131
        rtc1_write(RTCL1HREG, 0);
132
 
133
        spin_unlock_irq(&rtc_lock);
134
 
135
        disable_irq(aie_irq);
136
        disable_irq(pie_irq);
137
}
138
 
139
static int vr41xx_rtc_read_time(struct device *dev, struct rtc_time *time)
140
{
141
        unsigned long epoch_sec, elapsed_sec;
142
 
143
        epoch_sec = mktime(epoch, 1, 1, 0, 0, 0);
144
        elapsed_sec = read_elapsed_second();
145
 
146
        rtc_time_to_tm(epoch_sec + elapsed_sec, time);
147
 
148
        return 0;
149
}
150
 
151
static int vr41xx_rtc_set_time(struct device *dev, struct rtc_time *time)
152
{
153
        unsigned long epoch_sec, current_sec;
154
 
155
        epoch_sec = mktime(epoch, 1, 1, 0, 0, 0);
156
        current_sec = mktime(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
157
                             time->tm_hour, time->tm_min, time->tm_sec);
158
 
159
        write_elapsed_second(current_sec - epoch_sec);
160
 
161
        return 0;
162
}
163
 
164
static int vr41xx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
165
{
166
        unsigned long low, mid, high;
167
        struct rtc_time *time = &wkalrm->time;
168
 
169
        spin_lock_irq(&rtc_lock);
170
 
171
        low = rtc1_read(ECMPLREG);
172
        mid = rtc1_read(ECMPMREG);
173
        high = rtc1_read(ECMPHREG);
174
        wkalrm->enabled = alarm_enabled;
175
 
176
        spin_unlock_irq(&rtc_lock);
177
 
178
        rtc_time_to_tm((high << 17) | (mid << 1) | (low >> 15), time);
179
 
180
        return 0;
181
}
182
 
183
static int vr41xx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
184
{
185
        unsigned long alarm_sec;
186
        struct rtc_time *time = &wkalrm->time;
187
 
188
        alarm_sec = mktime(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
189
                           time->tm_hour, time->tm_min, time->tm_sec);
190
 
191
        spin_lock_irq(&rtc_lock);
192
 
193
        if (alarm_enabled)
194
                disable_irq(aie_irq);
195
 
196
        rtc1_write(ECMPLREG, (uint16_t)(alarm_sec << 15));
197
        rtc1_write(ECMPMREG, (uint16_t)(alarm_sec >> 1));
198
        rtc1_write(ECMPHREG, (uint16_t)(alarm_sec >> 17));
199
 
200
        if (wkalrm->enabled)
201
                enable_irq(aie_irq);
202
 
203
        alarm_enabled = wkalrm->enabled;
204
 
205
        spin_unlock_irq(&rtc_lock);
206
 
207
        return 0;
208
}
209
 
210
static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
211
{
212
        unsigned long count;
213
 
214
        switch (cmd) {
215
        case RTC_AIE_ON:
216
                spin_lock_irq(&rtc_lock);
217
 
218
                if (!alarm_enabled) {
219
                        enable_irq(aie_irq);
220
                        alarm_enabled = 1;
221
                }
222
 
223
                spin_unlock_irq(&rtc_lock);
224
                break;
225
        case RTC_AIE_OFF:
226
                spin_lock_irq(&rtc_lock);
227
 
228
                if (alarm_enabled) {
229
                        disable_irq(aie_irq);
230
                        alarm_enabled = 0;
231
                }
232
 
233
                spin_unlock_irq(&rtc_lock);
234
                break;
235
        case RTC_PIE_ON:
236
                enable_irq(pie_irq);
237
                break;
238
        case RTC_PIE_OFF:
239
                disable_irq(pie_irq);
240
                break;
241
        case RTC_IRQP_READ:
242
                return put_user(periodic_frequency, (unsigned long __user *)arg);
243
                break;
244
        case RTC_IRQP_SET:
245
                if (arg > MAX_PERIODIC_RATE)
246
                        return -EINVAL;
247
 
248
                periodic_frequency = arg;
249
 
250
                count = RTC_FREQUENCY;
251
                do_div(count, arg);
252
 
253
                periodic_count = count;
254
 
255
                spin_lock_irq(&rtc_lock);
256
 
257
                rtc1_write(RTCL1LREG, count);
258
                rtc1_write(RTCL1HREG, count >> 16);
259
 
260
                spin_unlock_irq(&rtc_lock);
261
                break;
262
        case RTC_EPOCH_READ:
263
                return put_user(epoch, (unsigned long __user *)arg);
264
        case RTC_EPOCH_SET:
265
                /* Doesn't support before 1900 */
266
                if (arg < 1900)
267
                        return -EINVAL;
268
                epoch = arg;
269
                break;
270
        default:
271
                return -ENOIOCTLCMD;
272
        }
273
 
274
        return 0;
275
}
276
 
277
static irqreturn_t elapsedtime_interrupt(int irq, void *dev_id)
278
{
279
        struct platform_device *pdev = (struct platform_device *)dev_id;
280
        struct rtc_device *rtc = platform_get_drvdata(pdev);
281
 
282
        rtc2_write(RTCINTREG, ELAPSEDTIME_INT);
283
 
284
        rtc_update_irq(rtc, 1, RTC_AF);
285
 
286
        return IRQ_HANDLED;
287
}
288
 
289
static irqreturn_t rtclong1_interrupt(int irq, void *dev_id)
290
{
291
        struct platform_device *pdev = (struct platform_device *)dev_id;
292
        struct rtc_device *rtc = platform_get_drvdata(pdev);
293
        unsigned long count = periodic_count;
294
 
295
        rtc2_write(RTCINTREG, RTCLONG1_INT);
296
 
297
        rtc1_write(RTCL1LREG, count);
298
        rtc1_write(RTCL1HREG, count >> 16);
299
 
300
        rtc_update_irq(rtc, 1, RTC_PF);
301
 
302
        return IRQ_HANDLED;
303
}
304
 
305
static const struct rtc_class_ops vr41xx_rtc_ops = {
306
        .release        = vr41xx_rtc_release,
307
        .ioctl          = vr41xx_rtc_ioctl,
308
        .read_time      = vr41xx_rtc_read_time,
309
        .set_time       = vr41xx_rtc_set_time,
310
        .read_alarm     = vr41xx_rtc_read_alarm,
311
        .set_alarm      = vr41xx_rtc_set_alarm,
312
};
313
 
314
static int __devinit rtc_probe(struct platform_device *pdev)
315
{
316
        struct resource *res;
317
        struct rtc_device *rtc;
318
        int retval;
319
 
320
        if (pdev->num_resources != 4)
321
                return -EBUSY;
322
 
323
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
324
        if (!res)
325
                return -EBUSY;
326
 
327
        rtc1_base = ioremap(res->start, res->end - res->start + 1);
328
        if (!rtc1_base)
329
                return -EBUSY;
330
 
331
        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
332
        if (!res) {
333
                retval = -EBUSY;
334
                goto err_rtc1_iounmap;
335
        }
336
 
337
        rtc2_base = ioremap(res->start, res->end - res->start + 1);
338
        if (!rtc2_base) {
339
                retval = -EBUSY;
340
                goto err_rtc1_iounmap;
341
        }
342
 
343
        rtc = rtc_device_register(rtc_name, &pdev->dev, &vr41xx_rtc_ops, THIS_MODULE);
344
        if (IS_ERR(rtc)) {
345
                retval = PTR_ERR(rtc);
346
                goto err_iounmap_all;
347
        }
348
 
349
        spin_lock_irq(&rtc_lock);
350
 
351
        rtc1_write(ECMPLREG, 0);
352
        rtc1_write(ECMPMREG, 0);
353
        rtc1_write(ECMPHREG, 0);
354
        rtc1_write(RTCL1LREG, 0);
355
        rtc1_write(RTCL1HREG, 0);
356
 
357
        spin_unlock_irq(&rtc_lock);
358
 
359
        aie_irq = platform_get_irq(pdev, 0);
360
        if (aie_irq < 0 || aie_irq >= NR_IRQS) {
361
                retval = -EBUSY;
362
                goto err_device_unregister;
363
        }
364
 
365
        retval = request_irq(aie_irq, elapsedtime_interrupt, IRQF_DISABLED,
366
                             "elapsed_time", pdev);
367
        if (retval < 0)
368
                goto err_device_unregister;
369
 
370
        pie_irq = platform_get_irq(pdev, 1);
371
        if (pie_irq < 0 || pie_irq >= NR_IRQS)
372
                goto err_free_irq;
373
 
374
        retval = request_irq(pie_irq, rtclong1_interrupt, IRQF_DISABLED,
375
                             "rtclong1", pdev);
376
        if (retval < 0)
377
                goto err_free_irq;
378
 
379
        platform_set_drvdata(pdev, rtc);
380
 
381
        disable_irq(aie_irq);
382
        disable_irq(pie_irq);
383
 
384
        printk(KERN_INFO "rtc: Real Time Clock of NEC VR4100 series\n");
385
 
386
        return 0;
387
 
388
err_free_irq:
389
        free_irq(aie_irq, pdev);
390
 
391
err_device_unregister:
392
        rtc_device_unregister(rtc);
393
 
394
err_iounmap_all:
395
        iounmap(rtc2_base);
396
        rtc2_base = NULL;
397
 
398
err_rtc1_iounmap:
399
        iounmap(rtc1_base);
400
        rtc1_base = NULL;
401
 
402
        return retval;
403
}
404
 
405
static int __devexit rtc_remove(struct platform_device *pdev)
406
{
407
        struct rtc_device *rtc;
408
 
409
        rtc = platform_get_drvdata(pdev);
410
        if (rtc)
411
                rtc_device_unregister(rtc);
412
 
413
        platform_set_drvdata(pdev, NULL);
414
 
415
        free_irq(aie_irq, pdev);
416
        free_irq(pie_irq, pdev);
417
        if (rtc1_base)
418
                iounmap(rtc1_base);
419
        if (rtc2_base)
420
                iounmap(rtc2_base);
421
 
422
        return 0;
423
}
424
 
425
static struct platform_driver rtc_platform_driver = {
426
        .probe          = rtc_probe,
427
        .remove         = __devexit_p(rtc_remove),
428
        .driver         = {
429
                .name   = rtc_name,
430
                .owner  = THIS_MODULE,
431
        },
432
};
433
 
434
static int __init vr41xx_rtc_init(void)
435
{
436
        return platform_driver_register(&rtc_platform_driver);
437
}
438
 
439
static void __exit vr41xx_rtc_exit(void)
440
{
441
        platform_driver_unregister(&rtc_platform_driver);
442
}
443
 
444
module_init(vr41xx_rtc_init);
445
module_exit(vr41xx_rtc_exit);

powered by: WebSVN 2.1.0

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