]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - rtc/ds1306.c
Add PCI support for MPC8250 Boards (PM825 module)
[karo-tx-uboot.git] / rtc / ds1306.c
1 /*
2  * (C) Copyright 2002 SIXNET, dge@sixnetio.com.
3  *
4  * See file CREDITS for list of people who contributed to this
5  * project.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20  * MA 02111-1307 USA
21  */
22
23 /*
24  * Date & Time support for DS1306 RTC using software SPI
25  */
26
27 #include <common.h>
28 #include <command.h>
29 #include <rtc.h>
30
31 #if defined(CONFIG_RTC_DS1306) && (CONFIG_COMMANDS & CFG_CMD_DATE)
32
33 static unsigned int bin2bcd(unsigned int n);
34 static unsigned char bcd2bin(unsigned char c);
35 static void soft_spi_send(unsigned char n);
36 static unsigned char soft_spi_read(void);
37 static void init_spi(void);
38
39 /*-----------------------------------------------------------------------
40  * Definitions
41  */
42
43 #define PB_SPISCK       0x00000002      /* PB 30 */
44 #define PB_SPIMOSI      0x00000004      /* PB 29 */
45 #define PB_SPIMISO      0x00000008      /* PB 28 */
46 #define PB_SPI_CE       0x00010000      /* PB 15 */
47
48 /* ------------------------------------------------------------------------- */
49
50 /* read clock time from DS1306 and return it in *tmp */
51 void rtc_get(struct rtc_time *tmp)
52 {
53     volatile immap_t *immap = (immap_t *)CFG_IMMR;
54     unsigned char spi_byte;     /* Data Byte */
55
56     init_spi();         /* set port B for software SPI */
57
58     /* Now we can enable the DS1306 RTC */
59     immap->im_cpm.cp_pbdat |= PB_SPI_CE;
60     udelay(10);
61
62     /* Shift out the address (0) of the time in the Clock Chip */
63     soft_spi_send(0);
64
65     /* Put the clock readings into the rtc_time structure */
66     tmp->tm_sec = bcd2bin(soft_spi_read());     /* Read seconds */
67     tmp->tm_min = bcd2bin(soft_spi_read());     /* Read minutes */
68
69     /* Hours are trickier */
70     spi_byte = soft_spi_read(); /* Read Hours into temporary value */
71     if (spi_byte & 0x40) {
72         /* 12 hour mode bit is set (time is in 1-12 format) */
73         if (spi_byte & 0x20) {
74             /* since PM we add 11 to get 0-23 for hours */
75             tmp->tm_hour = (bcd2bin(spi_byte & 0x1F)) + 11;
76         }
77         else {
78             /* since AM we subtract 1 to get 0-23 for hours */
79             tmp->tm_hour = (bcd2bin(spi_byte & 0x1F)) - 1;
80         }
81     }
82     else {
83         /* Otherwise, 0-23 hour format */
84         tmp->tm_hour = (bcd2bin(spi_byte & 0x3F));
85     }
86
87     soft_spi_read();            /* Read and discard Day of week */
88     tmp->tm_mday = bcd2bin(soft_spi_read());    /* Read Day of the Month */
89     tmp->tm_mon = bcd2bin(soft_spi_read());     /* Read Month */
90
91     /* Read Year and convert to this century */
92     tmp->tm_year = bcd2bin(soft_spi_read()) + 2000;
93
94     /* Now we can disable the DS1306 RTC */
95     immap->im_cpm.cp_pbdat &= ~PB_SPI_CE;       /* Disable DS1306 Chip */
96     udelay(10);
97
98     GregorianDay(tmp);          /* Determine the day of week */
99
100     debug("Get DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
101           tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
102           tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
103 }
104
105 /* ------------------------------------------------------------------------- */
106
107 /* set clock time in DS1306 RTC and in MPC8xx RTC */
108 void rtc_set(struct rtc_time *tmp)
109 {
110     volatile immap_t *immap = (immap_t *)CFG_IMMR;
111
112     init_spi();         /* set port B for software SPI */
113
114     /* Now we can enable the DS1306 RTC */
115     immap->im_cpm.cp_pbdat |= PB_SPI_CE;        /* Enable DS1306 Chip */
116     udelay(10);
117
118     /* First disable write protect in the clock chip control register */
119     soft_spi_send(0x8F);        /* send address of the control register */
120     soft_spi_send(0x00);        /* send control register contents */
121
122     /* Now disable the DS1306 to terminate the write */
123     immap->im_cpm.cp_pbdat &= ~PB_SPI_CE;
124     udelay(10);
125
126     /* Now enable the DS1306 to initiate a new write */
127     immap->im_cpm.cp_pbdat |= PB_SPI_CE;
128     udelay(10);
129
130     /* Next, send the address of the clock time write registers */
131     soft_spi_send(0x80);        /* send address of the first time register */
132
133     /* Use Burst Mode to send all of the time data to the clock */
134     bin2bcd(tmp->tm_sec);
135     soft_spi_send(bin2bcd(tmp->tm_sec));        /* Send Seconds */
136     soft_spi_send(bin2bcd(tmp->tm_min));        /* Send Minutes */
137     soft_spi_send(bin2bcd(tmp->tm_hour));       /* Send Hour */
138     soft_spi_send(bin2bcd(tmp->tm_wday));       /* Send Day of the Week */
139     soft_spi_send(bin2bcd(tmp->tm_mday));       /* Send Day of Month */
140     soft_spi_send(bin2bcd(tmp->tm_mon));        /* Send Month */
141     soft_spi_send(bin2bcd(tmp->tm_year - 2000));        /* Send Year */
142
143     /* Now we can disable the Clock chip to terminate the burst write */
144     immap->im_cpm.cp_pbdat &= ~PB_SPI_CE;       /* Disable DS1306 Chip */
145     udelay(10);
146
147     /* Now we can enable the Clock chip to initiate a new write */
148     immap->im_cpm.cp_pbdat |= PB_SPI_CE;        /* Enable DS1306 Chip */
149     udelay(10);
150
151     /* First we Enable write protect in the clock chip control register */
152     soft_spi_send(0x8F);        /* send address of the control register */
153     soft_spi_send(0x40);        /* send out Control Register contents */
154
155     /* Now disable the DS1306 */
156     immap->im_cpm.cp_pbdat &= ~PB_SPI_CE;       /*  Disable DS1306 Chip */
157     udelay(10);
158
159     /* Set standard MPC8xx clock to the same time so Linux will
160      * see the time even if it doesn't have a DS1306 clock driver.
161      * This helps with experimenting with standard kernels.
162      */
163     {
164         ulong tim;
165
166         tim = mktime(tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
167                      tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
168
169         immap->im_sitk.sitk_rtck = KAPWR_KEY;
170         immap->im_sit.sit_rtc = tim;
171     }
172
173     debug("Set DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
174           tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
175           tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
176 }
177
178 /* ------------------------------------------------------------------------- */
179
180 void rtc_reset(void)
181 {
182     return;                     /* nothing to do */
183 }
184
185 /* ------------------------------------------------------------------------- */
186
187 static unsigned char bcd2bin(unsigned char n)
188 {
189     return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F));
190 }
191
192 /* ------------------------------------------------------------------------- */
193
194 static unsigned int bin2bcd(unsigned int n)
195 {
196     return (((n / 10) << 4) | (n % 10));
197 }
198
199 /* ------------------------------------------------------------------------- */
200
201 /* Initialize Port B for software SPI */
202 static void init_spi(void) {
203     volatile immap_t *immap = (immap_t *)CFG_IMMR;
204
205     /* Force output pins to begin at logic 0 */
206     immap->im_cpm.cp_pbdat &= ~(PB_SPI_CE | PB_SPIMOSI | PB_SPISCK);
207
208     /* Set these 3 signals as outputs */
209     immap->im_cpm.cp_pbdir |= (PB_SPIMOSI | PB_SPI_CE | PB_SPISCK);
210
211     immap->im_cpm.cp_pbdir &= ~PB_SPIMISO;      /* Make MISO pin an input */
212     udelay(10);
213 }
214
215 /* ------------------------------------------------------------------------- */
216
217 /* NOTE: soft_spi_send() assumes that the I/O lines are configured already */
218 static void soft_spi_send(unsigned char n)
219 {
220     volatile immap_t *immap = (immap_t *)CFG_IMMR;
221     unsigned char bitpos;       /* bit position to receive */
222     unsigned char i;            /* Loop Control */
223
224     /* bit position to send, start with most significant bit */
225     bitpos = 0x80;
226
227     /* Send 8 bits to software SPI */
228     for (i = 0; i < 8; i++) {   /* Loop for 8 bits */
229         immap->im_cpm.cp_pbdat |= PB_SPISCK;    /* Raise SCK */
230
231         if (n & bitpos)
232             immap->im_cpm.cp_pbdat |= PB_SPIMOSI;       /* Set MOSI to 1 */
233         else
234             immap->im_cpm.cp_pbdat &= ~PB_SPIMOSI;      /* Set MOSI to 0 */
235         udelay(10);
236
237         immap->im_cpm.cp_pbdat &= ~PB_SPISCK;   /* Lower SCK */
238         udelay(10);
239
240         bitpos >>= 1;           /* Shift for next bit position */
241     }
242 }
243
244 /* ------------------------------------------------------------------------- */
245
246 /* NOTE: soft_spi_read() assumes that the I/O lines are configured already */
247 static unsigned char soft_spi_read(void)
248 {
249     volatile immap_t *immap = (immap_t *)CFG_IMMR;
250
251     unsigned char spi_byte = 0; /* Return value, assume success */
252     unsigned char bitpos;       /* bit position to receive */
253     unsigned char i;            /* Loop Control */
254
255     /* bit position to receive, start with most significant bit */
256     bitpos = 0x80;
257
258     /* Read 8 bits here */
259     for (i = 0; i < 8; i++) {   /* Do 8 bits in loop */
260         immap->im_cpm.cp_pbdat |= PB_SPISCK;    /* Raise SCK */
261         udelay(10);
262         if (immap->im_cpm.cp_pbdat & PB_SPIMISO)        /* Get a bit of data */
263             spi_byte |= bitpos; /* Set data accordingly */
264         immap->im_cpm.cp_pbdat &= ~PB_SPISCK;   /* Lower SCK */
265         udelay(10);
266         bitpos >>= 1;           /* Shift for next bit position */
267     }
268
269     return spi_byte;            /* Return the byte read */
270 }
271
272 /* ------------------------------------------------------------------------- */
273
274 #endif