2 * Copyright (c) 2012 Marius Strobl <marius@FreeBSD.org>
3 * Copyright (c) 2015 Juraj Lutter
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 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
32 * Driver for NXP PCF8563 real-time clock/calendar
35 #include "opt_platform.h"
37 #include <sys/param.h>
38 #include <sys/systm.h>
40 #include <sys/clock.h>
41 #include <sys/kernel.h>
42 #include <sys/module.h>
44 #include <dev/iicbus/iicbus.h>
45 #include <dev/iicbus/iiconf.h>
46 #include <dev/iicbus/pcf8563reg.h>
48 #include <dev/ofw/openfirm.h>
49 #include <dev/ofw/ofw_bus.h>
50 #include <dev/ofw/ofw_bus_subr.h>
54 #include "iicbus_if.h"
56 #define PCF8563_NCLOCKREGS (PCF8563_R_YEAR - PCF8563_R_CS1 + 1)
58 struct pcf8563_softc {
59 struct intr_config_hook enum_hook;
61 #define PCF8563_CPOL (1 << 0) /* PCF8563_R_MONTH_C means 19xx */
62 uint16_t sc_addr; /* PCF8563 slave address */
63 uint16_t sc_year0; /* TOD clock year 0 */
66 static device_attach_t pcf8563_attach;
67 static device_probe_t pcf8563_probe;
68 static clock_gettime_t pcf8563_gettime;
69 static clock_settime_t pcf8563_settime;
70 static void pcf8563_start(void *);
73 pcf8563_probe(device_t dev)
77 if (!ofw_bus_status_okay(dev))
79 if (!ofw_bus_is_compatible(dev, "nxp,pcf8563") &&
80 !ofw_bus_is_compatible(dev, "philips,pcf8563") &&
81 !ofw_bus_is_compatible(dev, "pcf8563"))
84 device_set_desc(dev, "NXP PCF8563 RTC");
86 return (BUS_PROBE_DEFAULT);
90 pcf8563_attach(device_t dev)
92 struct pcf8563_softc *sc;
94 sc = device_get_softc(dev);
95 sc->sc_addr = iicbus_get_addr(dev);
97 sc->sc_addr = PCF8563_ADDR;
99 sc->enum_hook.ich_func = pcf8563_start;
100 sc->enum_hook.ich_arg = dev;
103 * We have to wait until interrupts are enabled. Sometimes I2C read
104 * and write only works when the interrupts are available.
106 if (config_intrhook_establish(&sc->enum_hook) != 0)
113 pcf8563_start(void *xdev)
116 uint8_t reg = PCF8563_R_SECOND, val;
117 struct iic_msg msgs[] = {
118 { 0, IIC_M_WR, sizeof(reg), ® },
119 { 0, IIC_M_RD, sizeof(val), &val }
121 struct pcf8563_softc *sc;
123 dev = (device_t)xdev;
124 sc = device_get_softc(dev);
125 config_intrhook_disestablish(&sc->enum_hook);
128 * NB: PCF8563_R_SECOND_VL doesn't automatically clear when VDD
129 * rises above Vlow again and needs to be cleared manually.
130 * However, apparently this needs all of the time registers to be
131 * set, i.e. pcf8563_settime(), and not just PCF8563_R_SECOND in
132 * order for PCF8563_R_SECOND_VL to stick. Thus, we just issue a
133 * warning here rather than failing with ENXIO in case it is set.
134 * Note that pcf8563_settime() will also clear PCF8563_R_SECOND_VL
137 msgs[0].slave = msgs[1].slave = sc->sc_addr;
138 if (iicbus_transfer(dev, msgs, nitems(msgs)) != 0) {
139 device_printf(dev, "%s: cannot read RTC\n", __func__);
142 if ((val & PCF8563_R_SECOND_VL) != 0)
143 device_printf(dev, "%s: battery low\n", __func__);
145 clock_register(dev, 1000000); /* 1 second resolution */
149 pcf8563_gettime(device_t dev, struct timespec *ts)
152 uint8_t reg = PCF8563_R_SECOND, val[PCF8563_NCLOCKREGS];
153 struct iic_msg msgs[] = {
154 { 0, IIC_M_WR, sizeof(reg), ® },
155 { 0, IIC_M_RD, PCF8563_NCLOCKREGS, &val[PCF8563_R_SECOND] }
157 struct pcf8563_softc *sc;
160 sc = device_get_softc(dev);
161 msgs[0].slave = msgs[1].slave = sc->sc_addr;
162 error = iicbus_transfer(dev, msgs, nitems(msgs));
164 device_printf(dev, "%s: cannot read RTC\n", __func__);
169 ct.sec = FROMBCD(val[PCF8563_R_SECOND] & PCF8563_M_SECOND);
170 ct.min = FROMBCD(val[PCF8563_R_MINUTE] & PCF8563_M_MINUTE);
171 ct.hour = FROMBCD(val[PCF8563_R_HOUR] & PCF8563_M_HOUR);
172 ct.day = FROMBCD(val[PCF8563_R_DAY] & PCF8563_M_DAY);
173 ct.dow = val[PCF8563_R_WEEKDAY] & PCF8563_M_WEEKDAY;
174 ct.mon = FROMBCD(val[PCF8563_R_MONTH] & PCF8563_M_MONTH);
175 ct.year = FROMBCD(val[PCF8563_R_YEAR] & PCF8563_M_YEAR);
176 ct.year += sc->sc_year0;
177 if (ct.year < POSIX_BASE_YEAR)
178 ct.year += 100; /* assume [1970, 2069] */
179 if ((val[PCF8563_R_MONTH] & PCF8563_R_MONTH_C) != 0) {
180 if (ct.year >= 100 + sc->sc_year0)
181 sc->sc_flags |= PCF8563_CPOL;
182 } else if (ct.year < 100 + sc->sc_year0)
183 sc->sc_flags |= PCF8563_CPOL;
185 return (clock_ct_to_ts(&ct, ts));
189 pcf8563_settime(device_t dev, struct timespec *ts)
192 uint8_t val[PCF8563_NCLOCKREGS];
193 struct iic_msg msgs[] = {
194 { 0, IIC_M_WR, PCF8563_NCLOCKREGS - 1, &val[PCF8563_R_CS2] }
196 struct pcf8563_softc *sc;
199 sc = device_get_softc(dev);
200 val[PCF8563_R_CS2] = PCF8563_R_SECOND; /* abuse */
201 /* Accuracy is only one second. */
202 if (ts->tv_nsec >= 500000000)
205 clock_ts_to_ct(ts, &ct);
206 val[PCF8563_R_SECOND] = TOBCD(ct.sec);
207 val[PCF8563_R_MINUTE] = TOBCD(ct.min);
208 val[PCF8563_R_HOUR] = TOBCD(ct.hour);
209 val[PCF8563_R_DAY] = TOBCD(ct.day);
210 val[PCF8563_R_WEEKDAY] = ct.dow;
211 val[PCF8563_R_MONTH] = TOBCD(ct.mon);
212 val[PCF8563_R_YEAR] = TOBCD(ct.year % 100);
213 if ((sc->sc_flags & PCF8563_CPOL) != 0) {
214 if (ct.year >= 100 + sc->sc_year0)
215 val[PCF8563_R_MONTH] |= PCF8563_R_MONTH_C;
216 } else if (ct.year < 100 + sc->sc_year0)
217 val[PCF8563_R_MONTH] |= PCF8563_R_MONTH_C;
219 msgs[0].slave = sc->sc_addr;
220 error = iicbus_transfer(dev, msgs, nitems(msgs));
222 device_printf(dev, "%s: cannot write RTC\n", __func__);
227 static device_method_t pcf8563_methods[] = {
228 DEVMETHOD(device_probe, pcf8563_probe),
229 DEVMETHOD(device_attach, pcf8563_attach),
231 DEVMETHOD(clock_gettime, pcf8563_gettime),
232 DEVMETHOD(clock_settime, pcf8563_settime),
237 static driver_t pcf8563_driver = {
240 sizeof(struct pcf8563_softc),
243 static devclass_t pcf8563_devclass;
245 DRIVER_MODULE(pcf8563, iicbus, pcf8563_driver, pcf8563_devclass, NULL, NULL);
246 MODULE_VERSION(pcf8563, 1);
247 MODULE_DEPEND(pcf8563, iicbus, 1, 1, 1);