1 /* $NetBSD: pxa2x0_rtc.c,v 1.2 2009/08/09 06:12:34 kiyohara Exp $ */
4 * Copyright (c) 2007 NONAKA Kimihiro <nonaka@netbsd.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 #include <sys/cdefs.h>
25 __KERNEL_RCSID(0, "$NetBSD: pxa2x0_rtc.c,v 1.2 2009/08/09 06:12:34 kiyohara Exp $");
27 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/device.h>
30 #include <sys/kernel.h>
32 #include <dev/clock_subr.h>
34 #include <machine/bus.h>
36 #include <arm/xscale/pxa2x0cpu.h>
37 #include <arm/xscale/pxa2x0reg.h>
38 #include <arm/xscale/pxa2x0var.h>
41 #define DPRINTF(s) printf s
48 bus_space_tag_t sc_iot
;
49 bus_space_handle_t sc_ioh
;
51 struct todr_chip_handle sc_todr
;
54 #define FLAG_WRISTWATCH (1 << 0)
57 static int pxartc_match(struct device
*, struct cfdata
*, void *);
58 static void pxartc_attach(struct device
*, struct device
*, void *);
60 CFATTACH_DECL(pxartc
, sizeof(struct pxartc_softc
),
61 pxartc_match
, pxartc_attach
, NULL
, NULL
);
63 /* todr(9) interface */
64 static int pxartc_todr_gettime(todr_chip_handle_t
, struct timeval
*);
65 static int pxartc_todr_settime(todr_chip_handle_t
, struct timeval
*);
67 static int pxartc_wristwatch_read(struct pxartc_softc
*,struct clock_ymdhms
*);
68 static int pxartc_wristwatch_write(struct pxartc_softc
*,struct clock_ymdhms
*);
71 pxartc_match(struct device
*parent
, struct cfdata
*cf
, void *aux
)
73 struct pxaip_attach_args
*pxa
= aux
;
75 if (strcmp(pxa
->pxa_name
, cf
->cf_name
) != 0)
78 pxa
->pxa_size
= CPU_IS_PXA270
? PXA270_RTC_SIZE
: PXA250_RTC_SIZE
;
83 pxartc_attach(struct device
*parent
, struct device
*self
, void *aux
)
85 struct pxartc_softc
*sc
= (struct pxartc_softc
*)self
;
86 struct pxaip_attach_args
*pxa
= aux
;
88 sc
->sc_iot
= pxa
->pxa_iot
;
90 aprint_normal(": PXA2x0 Real-time Clock\n");
92 if (bus_space_map(sc
->sc_iot
, pxa
->pxa_addr
, pxa
->pxa_size
, 0,
94 aprint_error("%s: couldn't map registers\n",
99 if (pxa
->pxa_size
== PXA270_RTC_SIZE
) {
100 aprint_normal("%s: using wristwatch register\n",
101 sc
->sc_dev
.dv_xname
);
102 sc
->sc_flags
|= FLAG_WRISTWATCH
;
105 sc
->sc_todr
.cookie
= sc
;
106 sc
->sc_todr
.todr_gettime
= pxartc_todr_gettime
;
107 sc
->sc_todr
.todr_settime
= pxartc_todr_settime
;
108 sc
->sc_todr
.todr_setwen
= NULL
;
110 todr_attach(&sc
->sc_todr
);
114 pxartc_todr_gettime(todr_chip_handle_t ch
, struct timeval
*tv
)
116 struct pxartc_softc
*sc
= ch
->cookie
;
117 struct clock_ymdhms dt
;
119 if ((sc
->sc_flags
& FLAG_WRISTWATCH
) == 0) {
120 tv
->tv_sec
= bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
, RTC_RCNR
);
122 DPRINTF(("%s: RCNR = %08lx\n", sc
->sc_dev
.dv_xname
,tv
->tv_sec
));
124 clock_secs_to_ymdhms(tv
->tv_sec
, &dt
);
125 DPRINTF(("%s: %02d/%02d/%02d %02d:%02d:%02d\n",
127 dt
.dt_year
, dt
.dt_mon
, dt
.dt_day
,
128 dt
.dt_hour
, dt
.dt_min
, dt
.dt_sec
));
133 memset(&dt
, 0, sizeof(dt
));
135 if (pxartc_wristwatch_read(sc
, &dt
) == 0)
138 tv
->tv_sec
= clock_ymdhms_to_secs(&dt
);
144 pxartc_todr_settime(todr_chip_handle_t ch
, struct timeval
*tv
)
146 struct pxartc_softc
*sc
= ch
->cookie
;
147 struct clock_ymdhms dt
;
149 if ((sc
->sc_flags
& FLAG_WRISTWATCH
) == 0) {
151 DPRINTF(("%s: RCNR = %08lx\n", sc
->sc_dev
.dv_xname
,tv
->tv_sec
));
152 clock_secs_to_ymdhms(tv
->tv_sec
, &dt
);
153 DPRINTF(("%s: %02d/%02d/%02d %02d:%02d:%02d\n",
155 dt
.dt_year
, dt
.dt_mon
, dt
.dt_day
,
156 dt
.dt_hour
, dt
.dt_min
, dt
.dt_sec
));
158 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
, RTC_RCNR
, tv
->tv_sec
);
163 cntr
= bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
, RTC_RCNR
);
164 DPRINTF(("%s: new RCNR = %08x\n", sc
->sc_dev
.dv_xname
, cntr
));
165 clock_secs_to_ymdhms(cntr
, &dt
);
166 DPRINTF(("%s: %02d/%02d/%02d %02d:%02d:%02d\n",
168 dt
.dt_year
, dt
.dt_mon
, dt
.dt_day
,
169 dt
.dt_hour
, dt
.dt_min
, dt
.dt_sec
));
175 clock_secs_to_ymdhms(tv
->tv_sec
, &dt
);
177 if (pxartc_wristwatch_write(sc
, &dt
) == 0)
183 pxartc_wristwatch_read(struct pxartc_softc
*sc
, struct clock_ymdhms
*dt
)
185 uint32_t dayr
, yearr
;
188 DPRINTF(("%s: pxartc_wristwatch_read()\n", sc
->sc_dev
.dv_xname
));
191 dayr
= bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
, RTC_RDCR
);
192 yearr
= bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
, RTC_RYCR
);
195 DPRINTF(("%s: RDCR = %08x, RYCR = %08x\n", sc
->sc_dev
.dv_xname
,
198 dt
->dt_sec
= (dayr
>> RDCR_SECOND_SHIFT
) & RDCR_SECOND_MASK
;
199 dt
->dt_min
= (dayr
>> RDCR_MINUTE_SHIFT
) & RDCR_MINUTE_MASK
;
200 dt
->dt_hour
= (dayr
>> RDCR_HOUR_SHIFT
) & RDCR_HOUR_MASK
;
201 dt
->dt_day
= (yearr
>> RYCR_DOM_SHIFT
) & RYCR_DOM_MASK
;
202 dt
->dt_mon
= (yearr
>> RYCR_MONTH_SHIFT
) & RYCR_MONTH_MASK
;
203 dt
->dt_year
= (yearr
>> RYCR_YEAR_SHIFT
) & RYCR_YEAR_MASK
;
205 DPRINTF(("%s: %02d/%02d/%02d %02d:%02d:%02d\n", sc
->sc_dev
.dv_xname
,
206 dt
->dt_year
, dt
->dt_mon
, dt
->dt_day
,
207 dt
->dt_hour
, dt
->dt_min
, dt
->dt_sec
));
213 pxartc_wristwatch_write(struct pxartc_softc
*sc
, struct clock_ymdhms
*dt
)
215 uint32_t dayr
, yearr
;
216 uint32_t wom
; /* week of month: 1=first week of month */
219 DPRINTF(("%s: pxartc_wristwatch_write()\n", sc
->sc_dev
.dv_xname
));
221 DPRINTF(("%s: %02d/%02d/%02d %02d:%02d:%02d\n", sc
->sc_dev
.dv_xname
,
222 dt
->dt_year
, dt
->dt_mon
, dt
->dt_day
,
223 dt
->dt_hour
, dt
->dt_min
, dt
->dt_sec
));
225 dayr
= (dt
->dt_sec
& RDCR_SECOND_MASK
) << RDCR_SECOND_SHIFT
;
226 dayr
|= (dt
->dt_min
& RDCR_MINUTE_MASK
) << RDCR_MINUTE_SHIFT
;
227 dayr
|= (dt
->dt_hour
& RDCR_HOUR_MASK
) << RDCR_HOUR_SHIFT
;
228 dayr
|= ((dt
->dt_wday
+ 1) & RDCR_DOW_MASK
) << RDCR_DOW_SHIFT
;
229 wom
= ((dt
->dt_day
- 1 + 6 - dt
->dt_wday
) / 7) + 1;
230 dayr
|= (wom
& RDCR_WOM_MASK
) << RDCR_WOM_SHIFT
;
231 yearr
= (dt
->dt_day
& RYCR_DOM_MASK
) << RYCR_DOM_SHIFT
;
232 yearr
|= (dt
->dt_mon
& RYCR_MONTH_MASK
) << RYCR_MONTH_SHIFT
;
233 yearr
|= (dt
->dt_year
& RYCR_YEAR_MASK
) << RYCR_YEAR_SHIFT
;
235 DPRINTF(("%s: RDCR = %08x, RYCR = %08x\n", sc
->sc_dev
.dv_xname
,
239 * We must write RYCR register before write RDCR register.
241 * See PXA270 Processor Family Developer's Manual p.946
242 * 21.4.2.3.1 Writing RDCR and RYCR Counter Registers with Valid Data.
245 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
, RTC_RYCR
, yearr
);
246 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
, RTC_RDCR
, dayr
);
251 struct clock_ymdhms dummy
;
252 pxartc_wristwatch_read(sc
, &dummy
);