diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2010-02-19 00:21:48 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2010-02-19 00:21:48 +0000 |
commit | dcf7a8d8271bfce95611a0e421b05cb00962e7fc (patch) | |
tree | b2120c70932655a0430af02d94a4bb11b447cde6 | |
parent | db183d40c400294c8eb3e88acd9443335c294463 (diff) |
Add a driver for the M41T8x time-of-day clock chips, such as the M41T83
found on the Gdium Liberty. These machines finally no longer complain about
a missing todclock.
-rw-r--r-- | sys/arch/loongson/conf/GENERIC | 3 | ||||
-rw-r--r-- | sys/arch/loongson/conf/RAMDISK | 7 | ||||
-rw-r--r-- | sys/arch/loongson/conf/files.loongson | 7 | ||||
-rw-r--r-- | sys/arch/loongson/dev/gdiumiic.c | 9 | ||||
-rw-r--r-- | sys/arch/loongson/dev/m41t8xclock.c | 155 | ||||
-rw-r--r-- | sys/dev/ic/m41t8xreg.h | 98 |
6 files changed, 275 insertions, 4 deletions
diff --git a/sys/arch/loongson/conf/GENERIC b/sys/arch/loongson/conf/GENERIC index 546609457ad..4517296e484 100644 --- a/sys/arch/loongson/conf/GENERIC +++ b/sys/arch/loongson/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.9 2010/02/18 22:45:26 miod Exp $ +# $OpenBSD: GENERIC,v 1.10 2010/02/19 00:21:43 miod Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -56,6 +56,7 @@ gdiumiic0 at gpio0 offset 6 mask 0x81 # pins 6 and 13 gdiumiic0 at gpio0 offset 46 mask 0x03 # pins 46 and 47 iic0 at gdiumiic0 lmtemp0 at iic0 # National Semiconductor LM75 +mfokclock0 at iic0 # M41T8x todclock #gdiumiic1 at gpio0 offset 41 mask 0x03 # pins 41 and 42 #iic* at voyager? #ohci* at voyager? diff --git a/sys/arch/loongson/conf/RAMDISK b/sys/arch/loongson/conf/RAMDISK index c914357733f..02eaff0c8e4 100644 --- a/sys/arch/loongson/conf/RAMDISK +++ b/sys/arch/loongson/conf/RAMDISK @@ -1,4 +1,4 @@ -# $OpenBSD: RAMDISK,v 1.7 2010/02/18 22:45:26 miod Exp $ +# $OpenBSD: RAMDISK,v 1.8 2010/02/19 00:21:43 miod Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -63,6 +63,11 @@ smfb* at pci? # Yeeloong only # Gdium Liberty specific devices voyager* at pci? +gpio0 at voyager? +gdiumiic0 at gpio0 offset 6 mask 0x81 # pins 6 and 13 +gdiumiic0 at gpio0 offset 46 mask 0x03 # pins 46 and 47 +iic0 at gdiumiic0 +mfokclock0 at iic0 # M41T8x todclock smfb* at voyager? wsdisplay* at smfb? diff --git a/sys/arch/loongson/conf/files.loongson b/sys/arch/loongson/conf/files.loongson index 23eb91de37d..e154a67395c 100644 --- a/sys/arch/loongson/conf/files.loongson +++ b/sys/arch/loongson/conf/files.loongson @@ -1,4 +1,4 @@ -# $OpenBSD: files.loongson,v 1.3 2010/02/18 22:45:26 miod Exp $ +# $OpenBSD: files.loongson,v 1.4 2010/02/19 00:21:43 miod Exp $ # Standard stanzas config(8) can't run without maxpartitions 16 @@ -83,6 +83,11 @@ device gdiumiic: i2cbus, i2c_bitbang attach gdiumiic at gpio file arch/loongson/dev/gdiumiic.c gdiumiic +# Gdium M41T8x RTC +device mfokclock +attach mfokclock at i2c +file arch/loongson/dev/m41t8xclock.c mfokclock + # Silicon Motion SM502/SM712 frame buffer device smfb: wsemuldisplaydev, rasops16 attach smfb at pci with smfb_pci diff --git a/sys/arch/loongson/dev/gdiumiic.c b/sys/arch/loongson/dev/gdiumiic.c index 4120b19ff97..c1607e31d2a 100644 --- a/sys/arch/loongson/dev/gdiumiic.c +++ b/sys/arch/loongson/dev/gdiumiic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: gdiumiic.c,v 1.1 2010/02/18 22:45:28 miod Exp $ */ +/* $OpenBSD: gdiumiic.c,v 1.2 2010/02/19 00:21:45 miod Exp $ */ /* * Copyright (c) 2010 Miodrag Vallat. @@ -352,4 +352,11 @@ gdiumiic_sensors_scan(struct device *iicdev, struct i2cbus_attach_args *iba, ia.ia_size = 1; ia.ia_name = "lm75"; config_found(iicdev, &ia, iic_print); + + bzero(&ia, sizeof ia); + ia.ia_tag = iba->iba_tag; + ia.ia_addr = 0x68; + ia.ia_size = 1; + ia.ia_name = "mfokclock"; + config_found(iicdev, &ia, iic_print); } diff --git a/sys/arch/loongson/dev/m41t8xclock.c b/sys/arch/loongson/dev/m41t8xclock.c new file mode 100644 index 00000000000..551e53ef047 --- /dev/null +++ b/sys/arch/loongson/dev/m41t8xclock.c @@ -0,0 +1,155 @@ +/* $OpenBSD: m41t8xclock.c,v 1.1 2010/02/19 00:21:45 miod Exp $ */ + +/* + * Copyright (c) 2010 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * M41T8x clock connected to an I2C bus + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <dev/i2c/i2cvar.h> + +#include <dev/ic/m41t8xreg.h> + +#include <mips64/dev/clockvar.h> + +struct m41t8xclock_softc { + struct device sc_dev; + i2c_tag_t sc_tag; + i2c_addr_t sc_addr; +}; + +int m41t8xclock_match(struct device *, void *, void *); +void m41t8xclock_attach(struct device *, struct device *, void *); + +const struct cfattach mfokclock_ca = { + sizeof(struct m41t8xclock_softc), + m41t8xclock_match, m41t8xclock_attach +}; + +struct cfdriver mfokclock_cd = { + NULL, "mfokclock", DV_DULL +}; + +void m41t8xclock_get(void *, time_t, struct tod_time *); +void m41t8xclock_set(void *, struct tod_time *); + +int +m41t8xclock_match(struct device *parent, void *vcf, void *aux) +{ + struct i2c_attach_args *ia = (struct i2c_attach_args *)aux; + struct cfdata *cf = (struct cfdata *)vcf; + + return strcmp(ia->ia_name, cf->cf_driver->cd_name) == 0; +} + +void +m41t8xclock_attach(struct device *parent, struct device *self, void *aux) +{ + struct m41t8xclock_softc *sc = (struct m41t8xclock_softc *)self; + struct i2c_attach_args *ia = (struct i2c_attach_args *)aux; + + sc->sc_tag = ia->ia_tag; + sc->sc_addr = ia->ia_addr; + + sys_tod.tod_cookie = sc; + sys_tod.tod_get = m41t8xclock_get; + sys_tod.tod_set = m41t8xclock_set; + + printf("\n"); +} + +static inline int bcd2bin(int); +static inline int +bcd2bin(int datum) +{ + return (datum >> 4) * 10 + (datum & 0x0f); +} +static inline int bin2bcd(int); +static inline int +bin2bcd(int datum) +{ + return ((datum / 10) << 4) + (datum % 10); +} + +void +m41t8xclock_get(void *cookie, time_t unused, struct tod_time *tt) +{ + struct m41t8xclock_softc *sc = (struct m41t8xclock_softc *)cookie; + uint8_t regno, data[M41T8X_TOD_LENGTH]; + int s; + + iic_acquire_bus(sc->sc_tag, 0); + s = splclock(); + for (regno = M41T8X_TOD_START; + regno < M41T8X_TOD_START + M41T8X_TOD_LENGTH; regno++) + iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, + ®no, sizeof regno, data + regno, sizeof data[0], 0); + splx(s); + iic_release_bus(sc->sc_tag, 0); + + tt->sec = bcd2bin(data[M41T8X_SEC] & ~M41T8X_STOP); + tt->min = bcd2bin(data[M41T8X_MIN]); + tt->hour = bcd2bin(data[M41T8X_HR] & ~(M41T8X_CEB | M41T8X_CB)); + tt->dow = data[M41T8X_DOW]; + tt->day = bcd2bin(data[M41T8X_DAY]); + tt->mon = bcd2bin(data[M41T8X_MON]); + tt->year = bcd2bin(data[M41T8X_YEAR]) + 100; + if (data[M41T8X_HR] & M41T8X_CB) + tt->year += 100; +} + +void +m41t8xclock_set(void *cookie, struct tod_time *tt) +{ + struct m41t8xclock_softc *sc = (struct m41t8xclock_softc *)cookie; + uint8_t regno, data[M41T8X_TOD_LENGTH]; + int s; + + iic_acquire_bus(sc->sc_tag, 0); + s = splclock(); + /* read current state */ + for (regno = M41T8X_TOD_START; + regno < M41T8X_TOD_START + M41T8X_TOD_LENGTH; regno++) + iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, + ®no, sizeof regno, data + regno, sizeof data[0], 0); + /* compute new state */ + data[M41T8X_HSEC] = 0; + data[M41T8X_SEC] = bin2bcd(tt->sec); + data[M41T8X_MIN] = bin2bcd(tt->min); + data[M41T8X_HR] &= M41T8X_CEB; + if (tt->year >= 200) + data[M41T8X_HR] |= M41T8X_CB; + data[M41T8X_HR] |= bin2bcd(tt->hour); + data[M41T8X_DAY] = bin2bcd(tt->day); + data[M41T8X_MON] = bin2bcd(tt->mon); + if (tt->year >= 200) + data[M41T8X_YEAR] = bin2bcd(tt->year - 200); + else + data[M41T8X_YEAR] = bin2bcd(tt->year - 100); + /* write new state */ + for (regno = M41T8X_TOD_START; + regno < M41T8X_TOD_START + M41T8X_TOD_LENGTH; regno++) + iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, + ®no, sizeof regno, data + regno, sizeof data[0], 0); + splx(s); + iic_release_bus(sc->sc_tag, 0); +} diff --git a/sys/dev/ic/m41t8xreg.h b/sys/dev/ic/m41t8xreg.h new file mode 100644 index 00000000000..61828c16705 --- /dev/null +++ b/sys/dev/ic/m41t8xreg.h @@ -0,0 +1,98 @@ +/* $OpenBSD: m41t8xreg.h,v 1.1 2010/02/19 00:21:47 miod Exp $ */ + +/* + * Copyright (c) 2010 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * ST M41T8x serial access real time clock registers + */ + +/* + * Note that register update will stop while accessing registers 0x00 to 0x07 + * (without the clock stopping), so that the reader does not get false data. + * Registers will be thawed after reading register 0x07, when the + * autoincrementing read address reaches 0x08. + * + * Clock and alarm numerical values are stored in BCD. All other values are + * stored in binary. + */ + +#define M41T8X_HSEC 0x00 /* 1/100th of second */ +#define M41T8X_SEC 0x01 /* second */ +#define M41T8X_STOP 0x80 /* stop clock, bit 7 of above */ +#define M41T8X_MIN 0x02 /* minute */ +#define M41T8X_HR 0x03 /* hour */ +#define M41T8X_CEB 0x80 /* century bit toggle enable */ +#define M41T8X_CB 0x40 /* century bit */ +#define M41T8X_DOW 0x04 /* day of week */ +#define M41T8X_DAY 0x05 /* day of month */ +#define M41T8X_MON 0x06 /* month */ +#define M41T8X_YEAR 0x07 /* year */ + +#define M41T8X_TOD_START 0x00 +#define M41T8X_TOD_LENGTH 0x08 + +#define M41T8X_CTRL 0x08 /* control */ +#define M41T8X_OUT 0x80 /* output level */ +#define M41T8X_32KHZ 0x09 /* 32KHz oscillator control */ +#define M41T8X_32KE 0x80 /* 32KHz enable */ + +#define M41T8X_ALMON 0x0a /* alarm month */ +#define M41T8X_AFE 0x80 /* alarm flag enable */ +#define M41T8X_SQWE 0x40 /* square wave enable */ +#define M41T8X_ALDAY 0x0b /* alarm day */ +#define M41T8X_RPT4 0x80 /* alarm repeat mode bits */ +#define M41T8X_RPT5 0x40 +#define M41T8X_ALHOUR 0x0c /* alarm hour */ +#define M41T8X_RPT3 0x80 +#define M41T8X_ALMIN 0x0d /* alarm minute */ +#define M41T8X_RPT2 0x80 +#define M41T8X_ALSEC 0x0e /* alarm second */ +#define M41T8X_RPT1 0x80 + +#define M41T8X_FLAGS 0x0f /* flags */ +#define M41T8X_AF 0x40 /* alarm flag */ + +#define M41T8X_SQW 0x13 /* square wave control */ +#define M41T8X_RS3 0x80 /* square wave frequency */ +#define M41T8X_RS2 0x40 +#define M41T8X_RS1 0x20 +#define M41T8X_RS0 0x10 + +/* alarm repeat settings, RPT5..RPT1 */ +#define M41T8X_ALREP_SEC 0x1f /* once per second */ +#define M41T8X_ALREP_MIN 0x1e /* once per minute */ +#define M41T8X_ALREP_HOUR 0x1c /* once per hour */ +#define M41T8X_ALREP_DAY 0x18 /* once per day */ +#define M41T8X_ALREP_MON 0x10 /* once per month */ +#define M41T8X_ALREP_YEAR 0x00 /* once per year */ + +/* square wave frequency, RS3..RS0 */ +#define M41T8X_SQW_32K 0x01 +#define M41T8X_SQW_8K 0x02 +#define M41T8X_SQW_4K 0x03 +#define M41T8X_SQW_2K 0x04 +#define M41T8X_SQW_1K 0x05 +#define M41T8X_SQW_512 0x06 +#define M41T8X_SQW_256 0x07 +#define M41T8X_SQW_128 0x08 +#define M41T8X_SQW_64 0x09 +#define M41T8X_SQW_32 0x0a +#define M41T8X_SQW_16 0x0b +#define M41T8X_SQW_8 0x0c +#define M41T8X_SQW_4 0x0d +#define M41T8X_SQW_2 0x0e +#define M41T8X_SQW_1 0x0f |