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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [rtc/] [rtc-rs5c313.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
 * Ricoh RS5C313 RTC device/driver
3
 *  Copyright (C) 2007 Nobuhiro Iwamatsu
4
 *
5
 *  2005-09-19 modifed by kogiidena
6
 *
7
 * Based on the old drivers/char/rs5c313_rtc.c  by:
8
 *  Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
9
 *  Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
10
 *
11
 * Based on code written by Paul Gortmaker.
12
 *  Copyright (C) 1996 Paul Gortmaker
13
 *
14
 * This file is subject to the terms and conditions of the GNU General Public
15
 * License.  See the file "COPYING" in the main directory of this archive
16
 * for more details.
17
 *
18
 * Based on other minimal char device drivers, like Alan's
19
 * watchdog, Ted's random, etc. etc.
20
 *
21
 *      1.07    Paul Gortmaker.
22
 *      1.08    Miquel van Smoorenburg: disallow certain things on the
23
 *              DEC Alpha as the CMOS clock is also used for other things.
24
 *      1.09    Nikita Schmidt: epoch support and some Alpha cleanup.
25
 *      1.09a   Pete Zaitcev: Sun SPARC
26
 *      1.09b   Jeff Garzik: Modularize, init cleanup
27
 *      1.09c   Jeff Garzik: SMP cleanup
28
 *      1.10    Paul Barton-Davis: add support for async I/O
29
 *      1.10a   Andrea Arcangeli: Alpha updates
30
 *      1.10b   Andrew Morton: SMP lock fix
31
 *      1.10c   Cesar Barros: SMP locking fixes and cleanup
32
 *      1.10d   Paul Gortmaker: delete paranoia check in rtc_exit
33
 *      1.10e   Maciej W. Rozycki: Handle DECstation's year weirdness.
34
 *      1.11    Takashi Iwai: Kernel access functions
35
 *                            rtc_register/rtc_unregister/rtc_control
36
 *      1.11a   Daniele Bellucci: Audit create_proc_read_entry in rtc_init
37
 *      1.12    Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer
38
 *              CONFIG_HPET_EMULATE_RTC
39
 *      1.13    Nobuhiro Iwamatsu: Updata driver.
40
 */
41
 
42
#include <linux/module.h>
43
#include <linux/err.h>
44
#include <linux/rtc.h>
45
#include <linux/platform_device.h>
46
#include <linux/bcd.h>
47
#include <linux/delay.h>
48
#include <asm/io.h>
49
 
50
#define DRV_NAME        "rs5c313"
51
#define DRV_VERSION     "1.13"
52
 
53
#ifdef CONFIG_SH_LANDISK
54
/*****************************************************/
55
/* LANDISK dependence part of RS5C313                */
56
/*****************************************************/
57
 
58
#define SCSMR1          0xFFE00000
59
#define SCSCR1          0xFFE00008
60
#define SCSMR1_CA       0x80
61
#define SCSCR1_CKE      0x03
62
#define SCSPTR1         0xFFE0001C
63
#define SCSPTR1_EIO     0x80
64
#define SCSPTR1_SPB1IO  0x08
65
#define SCSPTR1_SPB1DT  0x04
66
#define SCSPTR1_SPB0IO  0x02
67
#define SCSPTR1_SPB0DT  0x01
68
 
69
#define SDA_OEN         SCSPTR1_SPB1IO
70
#define SDA             SCSPTR1_SPB1DT
71
#define SCL_OEN         SCSPTR1_SPB0IO
72
#define SCL             SCSPTR1_SPB0DT
73
 
74
/* RICOH RS5C313 CE port */
75
#define RS5C313_CE      0xB0000003
76
 
77
/* RICOH RS5C313 CE port bit */
78
#define RS5C313_CE_RTCCE        0x02
79
 
80
/* SCSPTR1 data */
81
unsigned char scsptr1_data;
82
 
83
#define RS5C313_CEENABLE    ctrl_outb(RS5C313_CE_RTCCE, RS5C313_CE);
84
#define RS5C313_CEDISABLE   ctrl_outb(0x00, RS5C313_CE)
85
#define RS5C313_MISCOP      ctrl_outb(0x02, 0xB0000008)
86
 
87
static void rs5c313_init_port(void)
88
{
89
        /* Set SCK as I/O port and Initialize SCSPTR1 data & I/O port. */
90
        ctrl_outb(ctrl_inb(SCSMR1) & ~SCSMR1_CA, SCSMR1);
91
        ctrl_outb(ctrl_inb(SCSCR1) & ~SCSCR1_CKE, SCSCR1);
92
 
93
        /* And Initialize SCL for RS5C313 clock */
94
        scsptr1_data = ctrl_inb(SCSPTR1) | SCL; /* SCL:H */
95
        ctrl_outb(scsptr1_data, SCSPTR1);
96
        scsptr1_data = ctrl_inb(SCSPTR1) | SCL_OEN;     /* SCL output enable */
97
        ctrl_outb(scsptr1_data, SCSPTR1);
98
        RS5C313_CEDISABLE;      /* CE:L */
99
}
100
 
101
static void rs5c313_write_data(unsigned char data)
102
{
103
        int i;
104
 
105
        for (i = 0; i < 8; i++) {
106
                /* SDA:Write Data */
107
                scsptr1_data = (scsptr1_data & ~SDA) |
108
                                ((((0x80 >> i) & data) >> (7 - i)) << 2);
109
                ctrl_outb(scsptr1_data, SCSPTR1);
110
                if (i == 0) {
111
                        scsptr1_data |= SDA_OEN;        /* SDA:output enable */
112
                        ctrl_outb(scsptr1_data, SCSPTR1);
113
                }
114
                ndelay(700);
115
                scsptr1_data &= ~SCL;   /* SCL:L */
116
                ctrl_outb(scsptr1_data, SCSPTR1);
117
                ndelay(700);
118
                scsptr1_data |= SCL;    /* SCL:H */
119
                ctrl_outb(scsptr1_data, SCSPTR1);
120
        }
121
 
122
        scsptr1_data &= ~SDA_OEN;       /* SDA:output disable */
123
        ctrl_outb(scsptr1_data, SCSPTR1);
124
}
125
 
126
static unsigned char rs5c313_read_data(void)
127
{
128
        int i;
129
        unsigned char data = 0;
130
 
131
        for (i = 0; i < 8; i++) {
132
                ndelay(700);
133
                /* SDA:Read Data */
134
                data |= ((ctrl_inb(SCSPTR1) & SDA) >> 2) << (7 - i);
135
                scsptr1_data &= ~SCL;   /* SCL:L */
136
                ctrl_outb(scsptr1_data, SCSPTR1);
137
                ndelay(700);
138
                scsptr1_data |= SCL;    /* SCL:H */
139
                ctrl_outb(scsptr1_data, SCSPTR1);
140
        }
141
        return data & 0x0F;
142
}
143
 
144
#endif /* CONFIG_SH_LANDISK */
145
 
146
/*****************************************************/
147
/* machine independence part of RS5C313              */
148
/*****************************************************/
149
 
150
/* RICOH RS5C313 address */
151
#define RS5C313_ADDR_SEC        0x00
152
#define RS5C313_ADDR_SEC10      0x01
153
#define RS5C313_ADDR_MIN        0x02
154
#define RS5C313_ADDR_MIN10      0x03
155
#define RS5C313_ADDR_HOUR       0x04
156
#define RS5C313_ADDR_HOUR10     0x05
157
#define RS5C313_ADDR_WEEK       0x06
158
#define RS5C313_ADDR_INTINTVREG 0x07
159
#define RS5C313_ADDR_DAY        0x08
160
#define RS5C313_ADDR_DAY10      0x09
161
#define RS5C313_ADDR_MON        0x0A
162
#define RS5C313_ADDR_MON10      0x0B
163
#define RS5C313_ADDR_YEAR       0x0C
164
#define RS5C313_ADDR_YEAR10     0x0D
165
#define RS5C313_ADDR_CNTREG     0x0E
166
#define RS5C313_ADDR_TESTREG    0x0F
167
 
168
/* RICOH RS5C313 control register */
169
#define RS5C313_CNTREG_ADJ_BSY  0x01
170
#define RS5C313_CNTREG_WTEN_XSTP        0x02
171
#define RS5C313_CNTREG_12_24    0x04
172
#define RS5C313_CNTREG_CTFG     0x08
173
 
174
/* RICOH RS5C313 test register */
175
#define RS5C313_TESTREG_TEST    0x01
176
 
177
/* RICOH RS5C313 control bit */
178
#define RS5C313_CNTBIT_READ     0x40
179
#define RS5C313_CNTBIT_AD       0x20
180
#define RS5C313_CNTBIT_DT       0x10
181
 
182
static unsigned char rs5c313_read_reg(unsigned char addr)
183
{
184
 
185
        rs5c313_write_data(addr | RS5C313_CNTBIT_READ | RS5C313_CNTBIT_AD);
186
        return rs5c313_read_data();
187
}
188
 
189
static void rs5c313_write_reg(unsigned char addr, unsigned char data)
190
{
191
        data &= 0x0f;
192
        rs5c313_write_data(addr | RS5C313_CNTBIT_AD);
193
        rs5c313_write_data(data | RS5C313_CNTBIT_DT);
194
        return;
195
}
196
 
197
static inline unsigned char rs5c313_read_cntreg(void)
198
{
199
        return rs5c313_read_reg(RS5C313_ADDR_CNTREG);
200
}
201
 
202
static inline void rs5c313_write_cntreg(unsigned char data)
203
{
204
        rs5c313_write_reg(RS5C313_ADDR_CNTREG, data);
205
}
206
 
207
static inline void rs5c313_write_intintvreg(unsigned char data)
208
{
209
        rs5c313_write_reg(RS5C313_ADDR_INTINTVREG, data);
210
}
211
 
212
static int rs5c313_rtc_read_time(struct device *dev, struct rtc_time *tm)
213
{
214
        int data;
215
        int cnt;
216
 
217
        cnt = 0;
218
        while (1) {
219
                RS5C313_CEENABLE;       /* CE:H */
220
 
221
                /* Initialize control reg. 24 hour */
222
                rs5c313_write_cntreg(0x04);
223
 
224
                if (!(rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY))
225
                        break;
226
 
227
                RS5C313_CEDISABLE;
228
                ndelay(700);    /* CE:L */
229
 
230
                if (cnt++ > 100) {
231
                        dev_err(dev, "%s: timeout error\n", __FUNCTION__);
232
                        return -EIO;
233
                }
234
        }
235
 
236
        data = rs5c313_read_reg(RS5C313_ADDR_SEC);
237
        data |= (rs5c313_read_reg(RS5C313_ADDR_SEC10) << 4);
238
        tm->tm_sec = BCD2BIN(data);
239
 
240
        data = rs5c313_read_reg(RS5C313_ADDR_MIN);
241
        data |= (rs5c313_read_reg(RS5C313_ADDR_MIN10) << 4);
242
        tm->tm_min = BCD2BIN(data);
243
 
244
        data = rs5c313_read_reg(RS5C313_ADDR_HOUR);
245
        data |= (rs5c313_read_reg(RS5C313_ADDR_HOUR10) << 4);
246
        tm->tm_hour = BCD2BIN(data);
247
 
248
        data = rs5c313_read_reg(RS5C313_ADDR_DAY);
249
        data |= (rs5c313_read_reg(RS5C313_ADDR_DAY10) << 4);
250
        tm->tm_mday = BCD2BIN(data);
251
 
252
        data = rs5c313_read_reg(RS5C313_ADDR_MON);
253
        data |= (rs5c313_read_reg(RS5C313_ADDR_MON10) << 4);
254
        tm->tm_mon = BCD2BIN(data) - 1;
255
 
256
        data = rs5c313_read_reg(RS5C313_ADDR_YEAR);
257
        data |= (rs5c313_read_reg(RS5C313_ADDR_YEAR10) << 4);
258
        tm->tm_year = BCD2BIN(data);
259
 
260
        if (tm->tm_year < 70)
261
                tm->tm_year += 100;
262
 
263
        data = rs5c313_read_reg(RS5C313_ADDR_WEEK);
264
        tm->tm_wday = BCD2BIN(data);
265
 
266
        RS5C313_CEDISABLE;
267
        ndelay(700);            /* CE:L */
268
 
269
        return 0;
270
}
271
 
272
static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm)
273
{
274
        int data;
275
        int cnt;
276
 
277
        cnt = 0;
278
        /* busy check. */
279
        while (1) {
280
                RS5C313_CEENABLE;       /* CE:H */
281
 
282
                /* Initiatlize control reg. 24 hour */
283
                rs5c313_write_cntreg(0x04);
284
 
285
                if (!(rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY))
286
                        break;
287
                RS5C313_MISCOP;
288
                RS5C313_CEDISABLE;
289
                ndelay(700);    /* CE:L */
290
 
291
                if (cnt++ > 100) {
292
                        dev_err(dev, "%s: timeout error\n", __FUNCTION__);
293
                        return -EIO;
294
                }
295
        }
296
 
297
        data = BIN2BCD(tm->tm_sec);
298
        rs5c313_write_reg(RS5C313_ADDR_SEC, data);
299
        rs5c313_write_reg(RS5C313_ADDR_SEC10, (data >> 4));
300
 
301
        data = BIN2BCD(tm->tm_min);
302
        rs5c313_write_reg(RS5C313_ADDR_MIN, data );
303
        rs5c313_write_reg(RS5C313_ADDR_MIN10, (data >> 4));
304
 
305
        data = BIN2BCD(tm->tm_hour);
306
        rs5c313_write_reg(RS5C313_ADDR_HOUR, data);
307
        rs5c313_write_reg(RS5C313_ADDR_HOUR10, (data >> 4));
308
 
309
        data = BIN2BCD(tm->tm_mday);
310
        rs5c313_write_reg(RS5C313_ADDR_DAY, data);
311
        rs5c313_write_reg(RS5C313_ADDR_DAY10, (data>> 4));
312
 
313
        data = BIN2BCD(tm->tm_mon + 1);
314
        rs5c313_write_reg(RS5C313_ADDR_MON, data);
315
        rs5c313_write_reg(RS5C313_ADDR_MON10, (data >> 4));
316
 
317
        data = BIN2BCD(tm->tm_year % 100);
318
        rs5c313_write_reg(RS5C313_ADDR_YEAR, data);
319
        rs5c313_write_reg(RS5C313_ADDR_YEAR10, (data >> 4));
320
 
321
        data = BIN2BCD(tm->tm_wday);
322
        rs5c313_write_reg(RS5C313_ADDR_WEEK, data);
323
 
324
        RS5C313_CEDISABLE;      /* CE:H */
325
        ndelay(700);
326
 
327
        return 0;
328
}
329
 
330
static void rs5c313_check_xstp_bit(void)
331
{
332
        struct rtc_time tm;
333
        int cnt;
334
 
335
        RS5C313_CEENABLE;       /* CE:H */
336
        if (rs5c313_read_cntreg() & RS5C313_CNTREG_WTEN_XSTP) {
337
                /* INT interval reg. OFF */
338
                rs5c313_write_intintvreg(0x00);
339
                /* Initialize control reg. 24 hour & adjust */
340
                rs5c313_write_cntreg(0x07);
341
 
342
                /* busy check. */
343
                for (cnt = 0; cnt < 100; cnt++) {
344
                        if (!(rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY))
345
                                break;
346
                        RS5C313_MISCOP;
347
                }
348
 
349
                memset(&tm, 0, sizeof(struct rtc_time));
350
                tm.tm_mday      = 1;
351
                tm.tm_mon       = 1 - 1;
352
                tm.tm_year      = 2000 - 1900;
353
 
354
                rs5c313_rtc_set_time(NULL, &tm);
355
                printk(KERN_ERR "RICHO RS5C313: invalid value, resetting to "
356
                                "1 Jan 2000\n");
357
        }
358
        RS5C313_CEDISABLE;
359
        ndelay(700);            /* CE:L */
360
}
361
 
362
static const struct rtc_class_ops rs5c313_rtc_ops = {
363
        .read_time = rs5c313_rtc_read_time,
364
        .set_time = rs5c313_rtc_set_time,
365
};
366
 
367
static int rs5c313_rtc_probe(struct platform_device *pdev)
368
{
369
        struct rtc_device *rtc = rtc_device_register("rs5c313", &pdev->dev,
370
                                &rs5c313_rtc_ops, THIS_MODULE);
371
 
372
        if (IS_ERR(rtc))
373
                return PTR_ERR(rtc);
374
 
375
        platform_set_drvdata(pdev, rtc);
376
 
377
        return 0;
378
}
379
 
380
static int __devexit rs5c313_rtc_remove(struct platform_device *pdev)
381
{
382
        struct rtc_device *rtc = platform_get_drvdata( pdev );
383
 
384
        rtc_device_unregister(rtc);
385
 
386
        return 0;
387
}
388
 
389
static struct platform_driver rs5c313_rtc_platform_driver = {
390
        .driver         = {
391
                .name   = DRV_NAME,
392
                .owner  = THIS_MODULE,
393
        },
394
        .probe  = rs5c313_rtc_probe,
395
        .remove = __devexit_p( rs5c313_rtc_remove ),
396
};
397
 
398
static int __init rs5c313_rtc_init(void)
399
{
400
        int err;
401
 
402
        err = platform_driver_register(&rs5c313_rtc_platform_driver);
403
        if (err)
404
                return err;
405
 
406
        rs5c313_init_port();
407
        rs5c313_check_xstp_bit();
408
 
409
        return 0;
410
}
411
 
412
static void __exit rs5c313_rtc_exit(void)
413
{
414
        platform_driver_unregister( &rs5c313_rtc_platform_driver );
415
}
416
 
417
module_init(rs5c313_rtc_init);
418
module_exit(rs5c313_rtc_exit);
419
 
420
MODULE_VERSION(DRV_VERSION);
421
MODULE_AUTHOR("kogiidena , Nobuhiro Iwamatsu <iwamatsu@nigauri.org>");
422
MODULE_DESCRIPTION("Ricoh RS5C313 RTC device driver");
423
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

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