summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2010-02-19 00:21:48 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2010-02-19 00:21:48 +0000
commitdcf7a8d8271bfce95611a0e421b05cb00962e7fc (patch)
treeb2120c70932655a0430af02d94a4bb11b447cde6
parentdb183d40c400294c8eb3e88acd9443335c294463 (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/GENERIC3
-rw-r--r--sys/arch/loongson/conf/RAMDISK7
-rw-r--r--sys/arch/loongson/conf/files.loongson7
-rw-r--r--sys/arch/loongson/dev/gdiumiic.c9
-rw-r--r--sys/arch/loongson/dev/m41t8xclock.c155
-rw-r--r--sys/dev/ic/m41t8xreg.h98
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,
+ &regno, 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,
+ &regno, 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,
+ &regno, 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