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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [char/] [ds1302.c] - Blame information for rev 65

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

Line No. Rev Author Line
1 62 marcus.erl
/*!***************************************************************************
2
*!
3
*! FILE NAME  : ds1302.c
4
*!
5
*! DESCRIPTION: Implements an interface for the DS1302 RTC
6
*!
7
*! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status
8
*!
9
*! ---------------------------------------------------------------------------
10
*!
11
*! (C) Copyright 1999, 2000, 2001  Axis Communications AB, LUND, SWEDEN
12
*!
13
*!***************************************************************************/
14
 
15
 
16
#include <linux/fs.h>
17
#include <linux/init.h>
18
#include <linux/mm.h>
19
#include <linux/module.h>
20
#include <linux/miscdevice.h>
21
#include <linux/delay.h>
22
#include <linux/bcd.h>
23
 
24
#include <asm/uaccess.h>
25
#include <asm/system.h>
26
#include <asm/io.h>
27
#include <asm/rtc.h>
28
#if defined(CONFIG_M32R)
29
#include <asm/m32r.h>
30
#endif
31
 
32
#define RTC_MAJOR_NR 121 /* local major, change later */
33
 
34
static const char ds1302_name[] = "ds1302";
35
 
36
/* Send 8 bits. */
37
static void
38
out_byte_rtc(unsigned int reg_addr, unsigned char x)
39
{
40
        //RST H
41
        outw(0x0001,(unsigned long)PLD_RTCRSTODT);
42
        //write data
43
        outw(((x<<8)|(reg_addr&0xff)),(unsigned long)PLD_RTCWRDATA);
44
        //WE
45
        outw(0x0002,(unsigned long)PLD_RTCCR);
46
        //wait
47
        while(inw((unsigned long)PLD_RTCCR));
48
 
49
        //RST L
50
        outw(0x0000,(unsigned long)PLD_RTCRSTODT);
51
 
52
}
53
 
54
static unsigned char
55
in_byte_rtc(unsigned int reg_addr)
56
{
57
        unsigned char retval;
58
 
59
        //RST H
60
        outw(0x0001,(unsigned long)PLD_RTCRSTODT);
61
        //write data
62
        outw((reg_addr&0xff),(unsigned long)PLD_RTCRDDATA);
63
        //RE
64
        outw(0x0001,(unsigned long)PLD_RTCCR);
65
        //wait
66
        while(inw((unsigned long)PLD_RTCCR));
67
 
68
        //read data
69
        retval=(inw((unsigned long)PLD_RTCRDDATA) & 0xff00)>>8;
70
 
71
        //RST L
72
        outw(0x0000,(unsigned long)PLD_RTCRSTODT);
73
 
74
        return retval;
75
}
76
 
77
/* Enable writing. */
78
 
79
static void
80
ds1302_wenable(void)
81
{
82
        out_byte_rtc(0x8e,0x00);
83
}
84
 
85
/* Disable writing. */
86
 
87
static void
88
ds1302_wdisable(void)
89
{
90
        out_byte_rtc(0x8e,0x80);
91
}
92
 
93
 
94
 
95
/* Read a byte from the selected register in the DS1302. */
96
 
97
unsigned char
98
ds1302_readreg(int reg)
99
{
100
        unsigned char x;
101
 
102
        x=in_byte_rtc((0x81 | (reg << 1))); /* read register */
103
 
104
        return x;
105
}
106
 
107
/* Write a byte to the selected register. */
108
 
109
void
110
ds1302_writereg(int reg, unsigned char val)
111
{
112
        ds1302_wenable();
113
        out_byte_rtc((0x80 | (reg << 1)),val);
114
        ds1302_wdisable();
115
}
116
 
117
void
118
get_rtc_time(struct rtc_time *rtc_tm)
119
{
120
        unsigned long flags;
121
 
122
        local_irq_save(flags);
123
 
124
        rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
125
        rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
126
        rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
127
        rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
128
        rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
129
        rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
130
 
131
        local_irq_restore(flags);
132
 
133
        BCD_TO_BIN(rtc_tm->tm_sec);
134
        BCD_TO_BIN(rtc_tm->tm_min);
135
        BCD_TO_BIN(rtc_tm->tm_hour);
136
        BCD_TO_BIN(rtc_tm->tm_mday);
137
        BCD_TO_BIN(rtc_tm->tm_mon);
138
        BCD_TO_BIN(rtc_tm->tm_year);
139
 
140
        /*
141
         * Account for differences between how the RTC uses the values
142
         * and how they are defined in a struct rtc_time;
143
         */
144
 
145
        if (rtc_tm->tm_year <= 69)
146
                rtc_tm->tm_year += 100;
147
 
148
        rtc_tm->tm_mon--;
149
}
150
 
151
static unsigned char days_in_mo[] =
152
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
153
 
154
/* ioctl that supports RTC_RD_TIME and RTC_SET_TIME (read and set time/date). */
155
 
156
static int
157
rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
158
          unsigned long arg)
159
{
160
        unsigned long flags;
161
 
162
        switch(cmd) {
163
                case RTC_RD_TIME:       /* read the time/date from RTC  */
164
                {
165
                        struct rtc_time rtc_tm;
166
 
167
                        memset(&rtc_tm, 0, sizeof (struct rtc_time));
168
                        get_rtc_time(&rtc_tm);
169
                        if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time)))
170
                                return -EFAULT;
171
                        return 0;
172
                }
173
 
174
                case RTC_SET_TIME:      /* set the RTC */
175
                {
176
                        struct rtc_time rtc_tm;
177
                        unsigned char mon, day, hrs, min, sec, leap_yr;
178
                        unsigned int yrs;
179
 
180
                        if (!capable(CAP_SYS_TIME))
181
                                return -EPERM;
182
 
183
                        if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)))
184
                                return -EFAULT;
185
 
186
                        yrs = rtc_tm.tm_year + 1900;
187
                        mon = rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
188
                        day = rtc_tm.tm_mday;
189
                        hrs = rtc_tm.tm_hour;
190
                        min = rtc_tm.tm_min;
191
                        sec = rtc_tm.tm_sec;
192
 
193
 
194
                        if ((yrs < 1970) || (yrs > 2069))
195
                                return -EINVAL;
196
 
197
                        leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
198
 
199
                        if ((mon > 12) || (day == 0))
200
                                return -EINVAL;
201
 
202
                        if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
203
                                return -EINVAL;
204
 
205
                        if ((hrs >= 24) || (min >= 60) || (sec >= 60))
206
                                return -EINVAL;
207
 
208
                        if (yrs >= 2000)
209
                                yrs -= 2000;    /* RTC (0, 1, ... 69) */
210
                        else
211
                                yrs -= 1900;    /* RTC (70, 71, ... 99) */
212
 
213
                        BIN_TO_BCD(sec);
214
                        BIN_TO_BCD(min);
215
                        BIN_TO_BCD(hrs);
216
                        BIN_TO_BCD(day);
217
                        BIN_TO_BCD(mon);
218
                        BIN_TO_BCD(yrs);
219
 
220
                        local_irq_save(flags);
221
                        CMOS_WRITE(yrs, RTC_YEAR);
222
                        CMOS_WRITE(mon, RTC_MONTH);
223
                        CMOS_WRITE(day, RTC_DAY_OF_MONTH);
224
                        CMOS_WRITE(hrs, RTC_HOURS);
225
                        CMOS_WRITE(min, RTC_MINUTES);
226
                        CMOS_WRITE(sec, RTC_SECONDS);
227
                        local_irq_restore(flags);
228
 
229
                        /* Notice that at this point, the RTC is updated but
230
                         * the kernel is still running with the old time.
231
                         * You need to set that separately with settimeofday
232
                         * or adjtimex.
233
                         */
234
                        return 0;
235
                }
236
 
237
                case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */
238
                {
239
                        int tcs_val;
240
 
241
                        if (!capable(CAP_SYS_TIME))
242
                                return -EPERM;
243
 
244
                        if(copy_from_user(&tcs_val, (int*)arg, sizeof(int)))
245
                                return -EFAULT;
246
 
247
                        tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F);
248
                        ds1302_writereg(RTC_TRICKLECHARGER, tcs_val);
249
                        return 0;
250
                }
251
                default:
252
                        return -EINVAL;
253
        }
254
}
255
 
256
int
257
get_rtc_status(char *buf)
258
{
259
        char *p;
260
        struct rtc_time tm;
261
 
262
        p = buf;
263
 
264
        get_rtc_time(&tm);
265
 
266
        /*
267
         * There is no way to tell if the luser has the RTC set for local
268
         * time or for Universal Standard Time (GMT). Probably local though.
269
         */
270
 
271
        p += sprintf(p,
272
                "rtc_time\t: %02d:%02d:%02d\n"
273
                "rtc_date\t: %04d-%02d-%02d\n",
274
                tm.tm_hour, tm.tm_min, tm.tm_sec,
275
                tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
276
 
277
        return  p - buf;
278
}
279
 
280
 
281
/* The various file operations we support. */
282
 
283
static const struct file_operations rtc_fops = {
284
        .owner          = THIS_MODULE,
285
        .ioctl          = rtc_ioctl,
286
};
287
 
288
/* Probe for the chip by writing something to its RAM and try reading it back. */
289
 
290
#define MAGIC_PATTERN 0x42
291
 
292
static int __init
293
ds1302_probe(void)
294
{
295
        int retval, res, baur;
296
 
297
        baur=(boot_cpu_data.bus_clock/(2*1000*1000));
298
 
299
        printk("%s: Set PLD_RTCBAUR = %d\n", ds1302_name,baur);
300
 
301
        outw(0x0000,(unsigned long)PLD_RTCCR);
302
        outw(0x0000,(unsigned long)PLD_RTCRSTODT);
303
        outw(baur,(unsigned long)PLD_RTCBAUR);
304
 
305
        /* Try to talk to timekeeper. */
306
 
307
        ds1302_wenable();
308
        /* write RAM byte 0 */
309
        /* write something magic */
310
        out_byte_rtc(0xc0,MAGIC_PATTERN);
311
 
312
        /* read RAM byte 0 */
313
        if((res = in_byte_rtc(0xc1)) == MAGIC_PATTERN) {
314
                char buf[100];
315
                ds1302_wdisable();
316
                printk("%s: RTC found.\n", ds1302_name);
317
                get_rtc_status(buf);
318
                printk(buf);
319
                retval = 1;
320
        } else {
321
                printk("%s: RTC not found.\n", ds1302_name);
322
                retval = 0;
323
        }
324
 
325
        return retval;
326
}
327
 
328
 
329
/* Just probe for the RTC and register the device to handle the ioctl needed. */
330
 
331
int __init
332
ds1302_init(void)
333
{
334
        if (!ds1302_probe()) {
335
                return -1;
336
        }
337
        return 0;
338
}
339
 
340
static int __init ds1302_register(void)
341
{
342
        ds1302_init();
343
        if (register_chrdev(RTC_MAJOR_NR, ds1302_name, &rtc_fops)) {
344
                printk(KERN_INFO "%s: unable to get major %d for rtc\n",
345
                       ds1302_name, RTC_MAJOR_NR);
346
                return -1;
347
        }
348
        return 0;
349
}
350
 
351
module_init(ds1302_register);

powered by: WebSVN 2.1.0

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