summaryrefslogtreecommitdiff
path: root/sys/arch
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 /sys/arch
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.
Diffstat (limited to 'sys/arch')
-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
5 files changed, 177 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);
+}