summaryrefslogtreecommitdiff
path: root/sys/arch/macppc/dev/pi2c.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/macppc/dev/pi2c.c')
-rw-r--r--sys/arch/macppc/dev/pi2c.c148
1 files changed, 148 insertions, 0 deletions
diff --git a/sys/arch/macppc/dev/pi2c.c b/sys/arch/macppc/dev/pi2c.c
new file mode 100644
index 00000000000..cf2e55d2d0b
--- /dev/null
+++ b/sys/arch/macppc/dev/pi2c.c
@@ -0,0 +1,148 @@
+/* $OpenBSD: pi2c.c,v 1.1 2005/11/16 12:28:54 kettenis Exp $ */
+
+/*
+ * Copyright (c) 2005 Mark Kettenis
+ *
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/lock.h>
+#include <sys/proc.h>
+
+#include <machine/autoconf.h>
+
+#include <dev/i2c/i2cvar.h>
+
+#include <arch/macppc/dev/maci2cvar.h>
+#include <arch/macppc/dev/pm_direct.h>
+
+struct pi2c_softc {
+ struct device sc_dev;
+
+ struct lock sc_buslock;
+ struct i2c_controller sc_i2c_tag;
+};
+
+int pi2c_match(struct device *, void *, void *);
+void pi2c_attach(struct device *, struct device *, void *);
+
+struct cfattach pi2c_ca = {
+ sizeof(struct pi2c_softc), pi2c_match, pi2c_attach
+};
+
+struct cfdriver pi2c_cd = {
+ NULL, "pi2c", DV_DULL,
+};
+
+int pi2c_i2c_acquire_bus(void *, int);
+void pi2c_i2c_release_bus(void *, int);
+int pi2c_i2c_exec(void *, i2c_op_t, i2c_addr_t,
+ const void *, size_t, void *buf, size_t, int);
+
+int
+pi2c_match(struct device *parent, void *cf, void *aux)
+{
+ return (1);
+}
+
+void
+pi2c_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct pi2c_softc *sc = (struct pi2c_softc *)self;
+ struct confargs *ca = aux;
+ struct maci2cbus_attach_args iba;
+
+ printf("\n");
+
+ lockinit(&sc->sc_buslock, PZERO, sc->sc_dev.dv_xname, 0, 0);
+
+ sc->sc_i2c_tag.ic_cookie = sc;
+ sc->sc_i2c_tag.ic_acquire_bus = pi2c_i2c_acquire_bus;
+ sc->sc_i2c_tag.ic_release_bus = pi2c_i2c_release_bus;
+ sc->sc_i2c_tag.ic_exec = pi2c_i2c_exec;
+
+ iba.iba_node = ca->ca_node;
+ iba.iba_tag = &sc->sc_i2c_tag;
+ config_found(&sc->sc_dev, &iba, NULL);
+}
+
+int
+pi2c_i2c_acquire_bus(void *cookie, int flags)
+{
+ struct pi2c_softc *sc = cookie;
+
+ return (lockmgr(&sc->sc_buslock, LK_EXCLUSIVE, NULL, curproc));
+}
+
+void
+pi2c_i2c_release_bus(void *cookie, int flags)
+{
+ struct pi2c_softc *sc = cookie;
+
+ lockmgr(&sc->sc_buslock, LK_RELEASE, NULL, curproc);
+}
+
+int
+pi2c_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
+ const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
+{
+ u_int8_t pmu_op = PMU_I2C_NORMAL;
+ int retries = 10;
+ PMData p;
+
+ if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 5)
+ return (EINVAL);
+
+ if (cmdlen == 0)
+ pmu_op = PMU_I2C_SIMPLE;
+ else if (I2C_OP_READ_P(op))
+ pmu_op = PMU_I2C_COMBINED;
+
+ p.command = PMU_I2C;
+ p.num_data = 7 + len;
+ p.s_buf = p.r_buf = p.data;
+
+ p.data[0] = addr >> 7; /* bus number */
+ p.data[1] = pmu_op;
+ p.data[2] = 0;
+ p.data[3] = addr << 1;
+ p.data[4] = *(u_int8_t *)cmdbuf;
+ p.data[5] = addr << 1 | I2C_OP_READ_P(op);
+ p.data[6] = len;
+ memcpy(&p.data[7], buf, len);
+
+ if (pmgrop(&p))
+ return (EIO);
+
+ while (retries--) {
+ p.command = PMU_I2C;
+ p.num_data = 1;
+ p.s_buf = p.r_buf = p.data;
+ p.data[0] = 0;
+
+ if (pmgrop(&p))
+ return (EIO);
+
+ if (p.data[0] == 1)
+ break;
+
+ DELAY(10 * 1000);
+ }
+
+ if (I2C_OP_READ_P(op))
+ memcpy(buf, &p.data[1], len);
+ return (0);
+}