Module Name: src Committed By: jakllsch Date: Fri Jan 21 19:11:48 UTC 2011
Modified Files: src/sys/dev/i2c: files.i2c Added Files: src/sys/dev/i2c: pcf8563.c pcf8563reg.h Log Message: Add pcf8563rtc(4), yet another I2C real time clock. To generate a diff of this commit: cvs rdiff -u -r1.31 -r1.32 src/sys/dev/i2c/files.i2c cvs rdiff -u -r0 -r1.1 src/sys/dev/i2c/pcf8563.c src/sys/dev/i2c/pcf8563reg.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/i2c/files.i2c diff -u src/sys/dev/i2c/files.i2c:1.31 src/sys/dev/i2c/files.i2c:1.32 --- src/sys/dev/i2c/files.i2c:1.31 Tue Jan 4 01:24:56 2011 +++ src/sys/dev/i2c/files.i2c Fri Jan 21 19:11:47 2011 @@ -1,4 +1,4 @@ -# $NetBSD: files.i2c,v 1.31 2011/01/04 01:24:56 matt Exp $ +# $NetBSD: files.i2c,v 1.32 2011/01/21 19:11:47 jakllsch Exp $ defflag opt_i2cbus.h I2C_SCAN define i2cbus { } @@ -48,6 +48,11 @@ attach maxrtc at iic file dev/i2c/max6900.c maxrtc +# NXP/Philips PCF8563 Real Time Clock +device pcf8563rtc +attach pcf8563rtc at iic +file dev/i2c/pcf8563.c pcf8563rtc + # Philips PCF8583 Real Time Clock device pcfrtc attach pcfrtc at iic Added files: Index: src/sys/dev/i2c/pcf8563.c diff -u /dev/null src/sys/dev/i2c/pcf8563.c:1.1 --- /dev/null Fri Jan 21 19:11:48 2011 +++ src/sys/dev/i2c/pcf8563.c Fri Jan 21 19:11:47 2011 @@ -0,0 +1,182 @@ +/* $NetBSD: pcf8563.c,v 1.1 2011/01/21 19:11:47 jakllsch Exp $ */ + +/* + * Copyright (c) 2011 Jonathan A. Kollasch + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: pcf8563.c,v 1.1 2011/01/21 19:11:47 jakllsch Exp $"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/kernel.h> + +#include <dev/clock_subr.h> + +#include <dev/i2c/i2cvar.h> +#include <dev/i2c/pcf8563reg.h> + +struct pcf8563rtc_softc { + device_t sc_dev; + i2c_tag_t sc_tag; + int sc_addr; + struct todr_chip_handle sc_todr; +}; + +static int pcf8563rtc_match(device_t, cfdata_t, void *); +static void pcf8563rtc_attach(device_t, device_t, void *); + +CFATTACH_DECL_NEW(pcf8563rtc, sizeof(struct pcf8563rtc_softc), + pcf8563rtc_match, pcf8563rtc_attach, NULL, NULL); + +static int pcf8563rtc_clock_read(struct pcf8563rtc_softc *, struct clock_ymdhms *); +static int pcf8563rtc_clock_write(struct pcf8563rtc_softc *, struct clock_ymdhms *); +static int pcf8563rtc_gettime(struct todr_chip_handle *, struct timeval *); +static int pcf8563rtc_settime(struct todr_chip_handle *, struct timeval *); + +static int +pcf8563rtc_match(device_t parent, cfdata_t cf, void *aux) +{ + struct i2c_attach_args *ia = aux; + + if (ia->ia_addr == PCF8563_ADDR) + return 1; + + return 0; +} + +static void +pcf8563rtc_attach(device_t parent, device_t self, void *aux) +{ + struct pcf8563rtc_softc *sc = device_private(self); + struct i2c_attach_args *ia = aux; + + aprint_naive(": Real-time Clock\n"); + aprint_normal(": NXP PCF8563 Real-time Clock\n"); + + sc->sc_dev = self; + sc->sc_tag = ia->ia_tag; + sc->sc_addr = ia->ia_addr; + sc->sc_todr.cookie = sc; + sc->sc_todr.todr_gettime = pcf8563rtc_gettime; + sc->sc_todr.todr_settime = pcf8563rtc_settime; + sc->sc_todr.todr_setwen = NULL; + + todr_attach(&sc->sc_todr); +} + +static int +pcf8563rtc_gettime(struct todr_chip_handle *ch, struct timeval *tv) +{ + struct pcf8563rtc_softc *sc = ch->cookie; + struct clock_ymdhms dt; + + memset(&dt, 0, sizeof(dt)); + + if (pcf8563rtc_clock_read(sc, &dt) == 0) + return -1; + + tv->tv_sec = clock_ymdhms_to_secs(&dt); + tv->tv_usec = 0; + + return 0; +} + +static int +pcf8563rtc_settime(struct todr_chip_handle *ch, struct timeval *tv) +{ + struct pcf8563rtc_softc *sc = ch->cookie; + struct clock_ymdhms dt; + + clock_secs_to_ymdhms(tv->tv_sec, &dt); + + if (pcf8563rtc_clock_write(sc, &dt) == 0) + return -1; + + return 0; +} + +static int +pcf8563rtc_clock_read(struct pcf8563rtc_softc *sc, struct clock_ymdhms *dt) +{ + uint8_t bcd[PCF8563_NREGS]; + uint8_t reg = PCF8563_R_CS1; + + if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) { + device_printf(sc->sc_dev, "acquire bus for read failed\n"); + return 0; + } + + if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, ®, 1, + &bcd[reg], PCF8563_R_YEAR - reg + 1, I2C_F_POLL)) { + iic_release_bus(sc->sc_tag, I2C_F_POLL); + device_printf(sc->sc_dev, "read failed\n"); + return 0; + } + + iic_release_bus(sc->sc_tag, I2C_F_POLL); + + dt->dt_sec = FROMBCD(bcd[PCF8563_R_SECOND] & PCF8563_M_SECOND); + dt->dt_min = FROMBCD(bcd[PCF8563_R_MINUTE] & PCF8563_M_MINUTE); + dt->dt_hour = FROMBCD(bcd[PCF8563_R_HOUR] & PCF8563_M_HOUR); + dt->dt_day = FROMBCD(bcd[PCF8563_R_DAY] & PCF8563_M_DAY); + dt->dt_mon = FROMBCD(bcd[PCF8563_R_MONTH] & PCF8563_M_MONTH); + dt->dt_year = FROMBCD(bcd[PCF8563_R_YEAR] & PCF8563_M_YEAR); + dt->dt_year += 2000; + + return 1; +} + +static int +pcf8563rtc_clock_write(struct pcf8563rtc_softc *sc, struct clock_ymdhms *dt) +{ + uint8_t bcd[PCF8563_NREGS]; + uint8_t reg = PCF8563_R_SECOND; + + bcd[PCF8563_R_SECOND] = TOBCD(dt->dt_sec); + bcd[PCF8563_R_MINUTE] = TOBCD(dt->dt_min); + bcd[PCF8563_R_HOUR] = TOBCD(dt->dt_hour); + bcd[PCF8563_R_DAY] = TOBCD(dt->dt_day); + bcd[PCF8563_R_WEEKDAY] = TOBCD(dt->dt_wday); + bcd[PCF8563_R_MONTH] = TOBCD(dt->dt_mon); + bcd[PCF8563_R_YEAR] = TOBCD(dt->dt_year % 100); + + if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) { + device_printf(sc->sc_dev, "acquire bus for write failed\n"); + return 0; + } + + if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, ®, 1, + &bcd[reg], PCF8563_R_YEAR - reg + 1, I2C_F_POLL)) { + iic_release_bus(sc->sc_tag, I2C_F_POLL); + device_printf(sc->sc_dev, "write failed\n"); + return 0; + } + + iic_release_bus(sc->sc_tag, I2C_F_POLL); + + return 1; +} Index: src/sys/dev/i2c/pcf8563reg.h diff -u /dev/null src/sys/dev/i2c/pcf8563reg.h:1.1 --- /dev/null Fri Jan 21 19:11:48 2011 +++ src/sys/dev/i2c/pcf8563reg.h Fri Jan 21 19:11:47 2011 @@ -0,0 +1,53 @@ +/* $NetBSD: pcf8563reg.h,v 1.1 2011/01/21 19:11:47 jakllsch Exp $ */ + +/* + * Jonathan Kollasch, 2011 + * + * This file is in the public domain. + */ + +/* + * NXP (Philips) PCF8563 RTC registers + */ + +/* We only have clock mode registers here */ + +#ifndef _PCF8563REG_H_ +#define _PCF8563REG_H_ + +/* + * PCF8563 RTC I2C address: + * + * 101 0001 + */ +#define PCF8563_ADDR 0x51 + +#define PCF8563_R_CS1 0x00 +#define PCF8563_R_CS2 0x01 +#define PCF8563_R_SECOND 0x02 +#define PCF8563_R_MINUTE 0x03 +#define PCF8563_R_HOUR 0x04 +#define PCF8563_R_DAY 0x05 +#define PCF8563_R_WEEKDAY 0x06 +#define PCF8563_R_MONTH 0x07 +#define PCF8563_R_YEAR 0x08 +#define PCF8563_R_MINUTE_ALARM 0x09 +#define PCF8563_R_HOUR_ALARM 0x0a +#define PCF8563_R_DAY_ALARM 0x0b +#define PCF8563_R_WEEKDAY_ALARM 0x0c +#define PCF8563_R_CLKOUT_CNTRL 0x0d +#define PCF8563_R_TIMER_CNTRL 0x0e +#define PCF8563_R_TIMER 0x0f + +#define PCF8563_NREGS 0x10 + +#define PCF8563_M_SECOND 0x7f +#define PCF8563_M_MINUTE 0x7f +#define PCF8563_M_HOUR 0x3f +#define PCF8563_M_DAY 0x3f +#define PCF8563_M_WEEKDAY 0x07 +#define PCF8563_M_MONTH 0x1f +#define PCF8563_M_CENTURY 0x80 +#define PCF8563_M_YEAR 0xff + +#endif /* _PCF8563REG_H_ */