1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * (C) Copyright 2002 SIXNET, dge@sixnetio.com.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * (C) Copyright 2004, Li-Pro.Net <www.li-pro.net>
5*4882a593Smuzhiyun * Stephan Linz <linz@li-pro.net>
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun /*
11*4882a593Smuzhiyun * Date & Time support for DS1306 RTC using SPI:
12*4882a593Smuzhiyun *
13*4882a593Smuzhiyun * - SXNI855T: it uses its own soft SPI here in this file
14*4882a593Smuzhiyun * - all other: use the external spi_xfer() function
15*4882a593Smuzhiyun * (see include/spi.h)
16*4882a593Smuzhiyun */
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #include <common.h>
19*4882a593Smuzhiyun #include <command.h>
20*4882a593Smuzhiyun #include <rtc.h>
21*4882a593Smuzhiyun #include <spi.h>
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #if defined(CONFIG_CMD_DATE)
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #define RTC_SECONDS 0x00
26*4882a593Smuzhiyun #define RTC_MINUTES 0x01
27*4882a593Smuzhiyun #define RTC_HOURS 0x02
28*4882a593Smuzhiyun #define RTC_DAY_OF_WEEK 0x03
29*4882a593Smuzhiyun #define RTC_DATE_OF_MONTH 0x04
30*4882a593Smuzhiyun #define RTC_MONTH 0x05
31*4882a593Smuzhiyun #define RTC_YEAR 0x06
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #define RTC_SECONDS_ALARM0 0x07
34*4882a593Smuzhiyun #define RTC_MINUTES_ALARM0 0x08
35*4882a593Smuzhiyun #define RTC_HOURS_ALARM0 0x09
36*4882a593Smuzhiyun #define RTC_DAY_OF_WEEK_ALARM0 0x0a
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun #define RTC_SECONDS_ALARM1 0x0b
39*4882a593Smuzhiyun #define RTC_MINUTES_ALARM1 0x0c
40*4882a593Smuzhiyun #define RTC_HOURS_ALARM1 0x0d
41*4882a593Smuzhiyun #define RTC_DAY_OF_WEEK_ALARM1 0x0e
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun #define RTC_CONTROL 0x0f
44*4882a593Smuzhiyun #define RTC_STATUS 0x10
45*4882a593Smuzhiyun #define RTC_TRICKLE_CHARGER 0x11
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun #define RTC_USER_RAM_BASE 0x20
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun /* ************************************************************************* */
50*4882a593Smuzhiyun #ifdef CONFIG_SXNI855T /* !!! SHOULD BE CHANGED TO NEW CODE !!! */
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun static void soft_spi_send (unsigned char n);
53*4882a593Smuzhiyun static unsigned char soft_spi_read (void);
54*4882a593Smuzhiyun static void init_spi (void);
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun /*-----------------------------------------------------------------------
57*4882a593Smuzhiyun * Definitions
58*4882a593Smuzhiyun */
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun #define PB_SPISCK 0x00000002 /* PB 30 */
61*4882a593Smuzhiyun #define PB_SPIMOSI 0x00000004 /* PB 29 */
62*4882a593Smuzhiyun #define PB_SPIMISO 0x00000008 /* PB 28 */
63*4882a593Smuzhiyun #define PB_SPI_CE 0x00010000 /* PB 15 */
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun /* read clock time from DS1306 and return it in *tmp */
rtc_get(struct rtc_time * tmp)68*4882a593Smuzhiyun int rtc_get (struct rtc_time *tmp)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
71*4882a593Smuzhiyun unsigned char spi_byte; /* Data Byte */
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun init_spi (); /* set port B for software SPI */
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun /* Now we can enable the DS1306 RTC */
76*4882a593Smuzhiyun immap->im_cpm.cp_pbdat |= PB_SPI_CE;
77*4882a593Smuzhiyun udelay (10);
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun /* Shift out the address (0) of the time in the Clock Chip */
80*4882a593Smuzhiyun soft_spi_send (0);
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun /* Put the clock readings into the rtc_time structure */
83*4882a593Smuzhiyun tmp->tm_sec = bcd2bin (soft_spi_read ()); /* Read seconds */
84*4882a593Smuzhiyun tmp->tm_min = bcd2bin (soft_spi_read ()); /* Read minutes */
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun /* Hours are trickier */
87*4882a593Smuzhiyun spi_byte = soft_spi_read (); /* Read Hours into temporary value */
88*4882a593Smuzhiyun if (spi_byte & 0x40) {
89*4882a593Smuzhiyun /* 12 hour mode bit is set (time is in 1-12 format) */
90*4882a593Smuzhiyun if (spi_byte & 0x20) {
91*4882a593Smuzhiyun /* since PM we add 11 to get 0-23 for hours */
92*4882a593Smuzhiyun tmp->tm_hour = (bcd2bin (spi_byte & 0x1F)) + 11;
93*4882a593Smuzhiyun } else {
94*4882a593Smuzhiyun /* since AM we subtract 1 to get 0-23 for hours */
95*4882a593Smuzhiyun tmp->tm_hour = (bcd2bin (spi_byte & 0x1F)) - 1;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun } else {
98*4882a593Smuzhiyun /* Otherwise, 0-23 hour format */
99*4882a593Smuzhiyun tmp->tm_hour = (bcd2bin (spi_byte & 0x3F));
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun soft_spi_read (); /* Read and discard Day of week */
103*4882a593Smuzhiyun tmp->tm_mday = bcd2bin (soft_spi_read ()); /* Read Day of the Month */
104*4882a593Smuzhiyun tmp->tm_mon = bcd2bin (soft_spi_read ()); /* Read Month */
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun /* Read Year and convert to this century */
107*4882a593Smuzhiyun tmp->tm_year = bcd2bin (soft_spi_read ()) + 2000;
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun /* Now we can disable the DS1306 RTC */
110*4882a593Smuzhiyun immap->im_cpm.cp_pbdat &= ~PB_SPI_CE; /* Disable DS1306 Chip */
111*4882a593Smuzhiyun udelay (10);
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun rtc_calc_weekday(tmp); /* Determine the day of week */
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun debug ("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
116*4882a593Smuzhiyun tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
117*4882a593Smuzhiyun tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun return 0;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun /* set clock time in DS1306 RTC and in MPC8xx RTC */
rtc_set(struct rtc_time * tmp)125*4882a593Smuzhiyun int rtc_set (struct rtc_time *tmp)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun init_spi (); /* set port B for software SPI */
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun /* Now we can enable the DS1306 RTC */
132*4882a593Smuzhiyun immap->im_cpm.cp_pbdat |= PB_SPI_CE; /* Enable DS1306 Chip */
133*4882a593Smuzhiyun udelay (10);
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun /* First disable write protect in the clock chip control register */
136*4882a593Smuzhiyun soft_spi_send (0x8F); /* send address of the control register */
137*4882a593Smuzhiyun soft_spi_send (0x00); /* send control register contents */
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun /* Now disable the DS1306 to terminate the write */
140*4882a593Smuzhiyun immap->im_cpm.cp_pbdat &= ~PB_SPI_CE;
141*4882a593Smuzhiyun udelay (10);
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun /* Now enable the DS1306 to initiate a new write */
144*4882a593Smuzhiyun immap->im_cpm.cp_pbdat |= PB_SPI_CE;
145*4882a593Smuzhiyun udelay (10);
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun /* Next, send the address of the clock time write registers */
148*4882a593Smuzhiyun soft_spi_send (0x80); /* send address of the first time register */
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun /* Use Burst Mode to send all of the time data to the clock */
151*4882a593Smuzhiyun bin2bcd (tmp->tm_sec);
152*4882a593Smuzhiyun soft_spi_send (bin2bcd (tmp->tm_sec)); /* Send Seconds */
153*4882a593Smuzhiyun soft_spi_send (bin2bcd (tmp->tm_min)); /* Send Minutes */
154*4882a593Smuzhiyun soft_spi_send (bin2bcd (tmp->tm_hour)); /* Send Hour */
155*4882a593Smuzhiyun soft_spi_send (bin2bcd (tmp->tm_wday)); /* Send Day of the Week */
156*4882a593Smuzhiyun soft_spi_send (bin2bcd (tmp->tm_mday)); /* Send Day of Month */
157*4882a593Smuzhiyun soft_spi_send (bin2bcd (tmp->tm_mon)); /* Send Month */
158*4882a593Smuzhiyun soft_spi_send (bin2bcd (tmp->tm_year - 2000)); /* Send Year */
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun /* Now we can disable the Clock chip to terminate the burst write */
161*4882a593Smuzhiyun immap->im_cpm.cp_pbdat &= ~PB_SPI_CE; /* Disable DS1306 Chip */
162*4882a593Smuzhiyun udelay (10);
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun /* Now we can enable the Clock chip to initiate a new write */
165*4882a593Smuzhiyun immap->im_cpm.cp_pbdat |= PB_SPI_CE; /* Enable DS1306 Chip */
166*4882a593Smuzhiyun udelay (10);
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun /* First we Enable write protect in the clock chip control register */
169*4882a593Smuzhiyun soft_spi_send (0x8F); /* send address of the control register */
170*4882a593Smuzhiyun soft_spi_send (0x40); /* send out Control Register contents */
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun /* Now disable the DS1306 */
173*4882a593Smuzhiyun immap->im_cpm.cp_pbdat &= ~PB_SPI_CE; /* Disable DS1306 Chip */
174*4882a593Smuzhiyun udelay (10);
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun /* Set standard MPC8xx clock to the same time so Linux will
177*4882a593Smuzhiyun * see the time even if it doesn't have a DS1306 clock driver.
178*4882a593Smuzhiyun * This helps with experimenting with standard kernels.
179*4882a593Smuzhiyun */
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun ulong tim;
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun tim = rtc_mktime(tmp);
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun immap->im_sitk.sitk_rtck = KAPWR_KEY;
186*4882a593Smuzhiyun immap->im_sit.sit_rtc = tim;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun debug ("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
190*4882a593Smuzhiyun tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
191*4882a593Smuzhiyun tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun return 0;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun /* Initialize Port B for software SPI */
init_spi(void)199*4882a593Smuzhiyun static void init_spi (void)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun /* Force output pins to begin at logic 0 */
204*4882a593Smuzhiyun immap->im_cpm.cp_pbdat &= ~(PB_SPI_CE | PB_SPIMOSI | PB_SPISCK);
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun /* Set these 3 signals as outputs */
207*4882a593Smuzhiyun immap->im_cpm.cp_pbdir |= (PB_SPIMOSI | PB_SPI_CE | PB_SPISCK);
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun immap->im_cpm.cp_pbdir &= ~PB_SPIMISO; /* Make MISO pin an input */
210*4882a593Smuzhiyun udelay (10);
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun /* NOTE: soft_spi_send() assumes that the I/O lines are configured already */
soft_spi_send(unsigned char n)216*4882a593Smuzhiyun static void soft_spi_send (unsigned char n)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
219*4882a593Smuzhiyun unsigned char bitpos; /* bit position to receive */
220*4882a593Smuzhiyun unsigned char i; /* Loop Control */
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun /* bit position to send, start with most significant bit */
223*4882a593Smuzhiyun bitpos = 0x80;
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun /* Send 8 bits to software SPI */
226*4882a593Smuzhiyun for (i = 0; i < 8; i++) { /* Loop for 8 bits */
227*4882a593Smuzhiyun immap->im_cpm.cp_pbdat |= PB_SPISCK; /* Raise SCK */
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun if (n & bitpos)
230*4882a593Smuzhiyun immap->im_cpm.cp_pbdat |= PB_SPIMOSI; /* Set MOSI to 1 */
231*4882a593Smuzhiyun else
232*4882a593Smuzhiyun immap->im_cpm.cp_pbdat &= ~PB_SPIMOSI; /* Set MOSI to 0 */
233*4882a593Smuzhiyun udelay (10);
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun immap->im_cpm.cp_pbdat &= ~PB_SPISCK; /* Lower SCK */
236*4882a593Smuzhiyun udelay (10);
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun bitpos >>= 1; /* Shift for next bit position */
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun /* NOTE: soft_spi_read() assumes that the I/O lines are configured already */
soft_spi_read(void)245*4882a593Smuzhiyun static unsigned char soft_spi_read (void)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun unsigned char spi_byte = 0; /* Return value, assume success */
250*4882a593Smuzhiyun unsigned char bitpos; /* bit position to receive */
251*4882a593Smuzhiyun unsigned char i; /* Loop Control */
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun /* bit position to receive, start with most significant bit */
254*4882a593Smuzhiyun bitpos = 0x80;
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun /* Read 8 bits here */
257*4882a593Smuzhiyun for (i = 0; i < 8; i++) { /* Do 8 bits in loop */
258*4882a593Smuzhiyun immap->im_cpm.cp_pbdat |= PB_SPISCK; /* Raise SCK */
259*4882a593Smuzhiyun udelay (10);
260*4882a593Smuzhiyun if (immap->im_cpm.cp_pbdat & PB_SPIMISO) /* Get a bit of data */
261*4882a593Smuzhiyun spi_byte |= bitpos; /* Set data accordingly */
262*4882a593Smuzhiyun immap->im_cpm.cp_pbdat &= ~PB_SPISCK; /* Lower SCK */
263*4882a593Smuzhiyun udelay (10);
264*4882a593Smuzhiyun bitpos >>= 1; /* Shift for next bit position */
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun return spi_byte; /* Return the byte read */
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
271*4882a593Smuzhiyun
rtc_reset(void)272*4882a593Smuzhiyun void rtc_reset (void)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun return; /* nothing to do */
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun #else /* not CONFIG_SXNI855T */
278*4882a593Smuzhiyun /* ************************************************************************* */
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun static unsigned char rtc_read (unsigned char reg);
281*4882a593Smuzhiyun static void rtc_write (unsigned char reg, unsigned char val);
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun static struct spi_slave *slave;
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun /* read clock time from DS1306 and return it in *tmp */
rtc_get(struct rtc_time * tmp)286*4882a593Smuzhiyun int rtc_get (struct rtc_time *tmp)
287*4882a593Smuzhiyun {
288*4882a593Smuzhiyun unsigned char sec, min, hour, mday, wday, mon, year;
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun /*
291*4882a593Smuzhiyun * Assuming Vcc = 2.0V (lowest speed)
292*4882a593Smuzhiyun *
293*4882a593Smuzhiyun * REVISIT: If we add an rtc_init() function we can do this
294*4882a593Smuzhiyun * step just once.
295*4882a593Smuzhiyun */
296*4882a593Smuzhiyun if (!slave) {
297*4882a593Smuzhiyun slave = spi_setup_slave(0, CONFIG_SYS_SPI_RTC_DEVID, 600000,
298*4882a593Smuzhiyun SPI_MODE_3 | SPI_CS_HIGH);
299*4882a593Smuzhiyun if (!slave)
300*4882a593Smuzhiyun return;
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun if (spi_claim_bus(slave))
304*4882a593Smuzhiyun return;
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun sec = rtc_read (RTC_SECONDS);
307*4882a593Smuzhiyun min = rtc_read (RTC_MINUTES);
308*4882a593Smuzhiyun hour = rtc_read (RTC_HOURS);
309*4882a593Smuzhiyun mday = rtc_read (RTC_DATE_OF_MONTH);
310*4882a593Smuzhiyun wday = rtc_read (RTC_DAY_OF_WEEK);
311*4882a593Smuzhiyun mon = rtc_read (RTC_MONTH);
312*4882a593Smuzhiyun year = rtc_read (RTC_YEAR);
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun spi_release_bus(slave);
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun debug ("Get RTC year: %02x mon: %02x mday: %02x wday: %02x "
317*4882a593Smuzhiyun "hr: %02x min: %02x sec: %02x\n",
318*4882a593Smuzhiyun year, mon, mday, wday, hour, min, sec);
319*4882a593Smuzhiyun debug ("Alarms[0]: wday: %02x hour: %02x min: %02x sec: %02x\n",
320*4882a593Smuzhiyun rtc_read (RTC_DAY_OF_WEEK_ALARM0),
321*4882a593Smuzhiyun rtc_read (RTC_HOURS_ALARM0),
322*4882a593Smuzhiyun rtc_read (RTC_MINUTES_ALARM0), rtc_read (RTC_SECONDS_ALARM0));
323*4882a593Smuzhiyun debug ("Alarms[1]: wday: %02x hour: %02x min: %02x sec: %02x\n",
324*4882a593Smuzhiyun rtc_read (RTC_DAY_OF_WEEK_ALARM1),
325*4882a593Smuzhiyun rtc_read (RTC_HOURS_ALARM1),
326*4882a593Smuzhiyun rtc_read (RTC_MINUTES_ALARM1), rtc_read (RTC_SECONDS_ALARM1));
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun tmp->tm_sec = bcd2bin (sec & 0x7F); /* convert Seconds */
329*4882a593Smuzhiyun tmp->tm_min = bcd2bin (min & 0x7F); /* convert Minutes */
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun /* convert Hours */
332*4882a593Smuzhiyun tmp->tm_hour = (hour & 0x40)
333*4882a593Smuzhiyun ? ((hour & 0x20) /* 12 hour mode */
334*4882a593Smuzhiyun ? bcd2bin (hour & 0x1F) + 11 /* PM */
335*4882a593Smuzhiyun : bcd2bin (hour & 0x1F) - 1 /* AM */
336*4882a593Smuzhiyun )
337*4882a593Smuzhiyun : bcd2bin (hour & 0x3F); /* 24 hour mode */
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun tmp->tm_mday = bcd2bin (mday & 0x3F); /* convert Day of the Month */
340*4882a593Smuzhiyun tmp->tm_mon = bcd2bin (mon & 0x1F); /* convert Month */
341*4882a593Smuzhiyun tmp->tm_year = bcd2bin (year) + 2000; /* convert Year */
342*4882a593Smuzhiyun tmp->tm_wday = bcd2bin (wday & 0x07) - 1; /* convert Day of the Week */
343*4882a593Smuzhiyun tmp->tm_yday = 0;
344*4882a593Smuzhiyun tmp->tm_isdst = 0;
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun debug ("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
347*4882a593Smuzhiyun tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
348*4882a593Smuzhiyun tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun return 0;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun /* set clock time from *tmp in DS1306 RTC */
rtc_set(struct rtc_time * tmp)356*4882a593Smuzhiyun int rtc_set (struct rtc_time *tmp)
357*4882a593Smuzhiyun {
358*4882a593Smuzhiyun /* Assuming Vcc = 2.0V (lowest speed) */
359*4882a593Smuzhiyun if (!slave) {
360*4882a593Smuzhiyun slave = spi_setup_slave(0, CONFIG_SYS_SPI_RTC_DEVID, 600000,
361*4882a593Smuzhiyun SPI_MODE_3 | SPI_CS_HIGH);
362*4882a593Smuzhiyun if (!slave)
363*4882a593Smuzhiyun return;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun if (spi_claim_bus(slave))
367*4882a593Smuzhiyun return;
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun debug ("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
370*4882a593Smuzhiyun tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
371*4882a593Smuzhiyun tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun rtc_write (RTC_SECONDS, bin2bcd (tmp->tm_sec));
374*4882a593Smuzhiyun rtc_write (RTC_MINUTES, bin2bcd (tmp->tm_min));
375*4882a593Smuzhiyun rtc_write (RTC_HOURS, bin2bcd (tmp->tm_hour));
376*4882a593Smuzhiyun rtc_write (RTC_DAY_OF_WEEK, bin2bcd (tmp->tm_wday + 1));
377*4882a593Smuzhiyun rtc_write (RTC_DATE_OF_MONTH, bin2bcd (tmp->tm_mday));
378*4882a593Smuzhiyun rtc_write (RTC_MONTH, bin2bcd (tmp->tm_mon));
379*4882a593Smuzhiyun rtc_write (RTC_YEAR, bin2bcd (tmp->tm_year - 2000));
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun spi_release_bus(slave);
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun /* reset the DS1306 */
rtc_reset(void)387*4882a593Smuzhiyun void rtc_reset (void)
388*4882a593Smuzhiyun {
389*4882a593Smuzhiyun /* Assuming Vcc = 2.0V (lowest speed) */
390*4882a593Smuzhiyun if (!slave) {
391*4882a593Smuzhiyun slave = spi_setup_slave(0, CONFIG_SYS_SPI_RTC_DEVID, 600000,
392*4882a593Smuzhiyun SPI_MODE_3 | SPI_CS_HIGH);
393*4882a593Smuzhiyun if (!slave)
394*4882a593Smuzhiyun return;
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun if (spi_claim_bus(slave))
398*4882a593Smuzhiyun return;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun /* clear the control register */
401*4882a593Smuzhiyun rtc_write (RTC_CONTROL, 0x00); /* 1st step: reset WP */
402*4882a593Smuzhiyun rtc_write (RTC_CONTROL, 0x00); /* 2nd step: reset 1Hz, AIE1, AIE0 */
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun /* reset all alarms */
405*4882a593Smuzhiyun rtc_write (RTC_SECONDS_ALARM0, 0x00);
406*4882a593Smuzhiyun rtc_write (RTC_SECONDS_ALARM1, 0x00);
407*4882a593Smuzhiyun rtc_write (RTC_MINUTES_ALARM0, 0x00);
408*4882a593Smuzhiyun rtc_write (RTC_MINUTES_ALARM1, 0x00);
409*4882a593Smuzhiyun rtc_write (RTC_HOURS_ALARM0, 0x00);
410*4882a593Smuzhiyun rtc_write (RTC_HOURS_ALARM1, 0x00);
411*4882a593Smuzhiyun rtc_write (RTC_DAY_OF_WEEK_ALARM0, 0x00);
412*4882a593Smuzhiyun rtc_write (RTC_DAY_OF_WEEK_ALARM1, 0x00);
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun spi_release_bus(slave);
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
418*4882a593Smuzhiyun
rtc_read(unsigned char reg)419*4882a593Smuzhiyun static unsigned char rtc_read (unsigned char reg)
420*4882a593Smuzhiyun {
421*4882a593Smuzhiyun int ret;
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun ret = spi_w8r8(slave, reg);
424*4882a593Smuzhiyun return ret < 0 ? 0 : ret;
425*4882a593Smuzhiyun }
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
428*4882a593Smuzhiyun
rtc_write(unsigned char reg,unsigned char val)429*4882a593Smuzhiyun static void rtc_write (unsigned char reg, unsigned char val)
430*4882a593Smuzhiyun {
431*4882a593Smuzhiyun unsigned char dout[2]; /* SPI Output Data Bytes */
432*4882a593Smuzhiyun unsigned char din[2]; /* SPI Input Data Bytes */
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun dout[0] = 0x80 | reg;
435*4882a593Smuzhiyun dout[1] = val;
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun spi_xfer (slave, 16, dout, din, SPI_XFER_BEGIN | SPI_XFER_END);
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun #endif /* end of code exclusion (see #ifdef CONFIG_SXNI855T above) */
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun #endif
443