diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2005-11-11 16:44:37 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2005-11-11 16:44:37 +0000 |
commit | 00b7f38eb00ccedca808a52fa3c2983a6cfa9c68 (patch) | |
tree | 5f3c0b6d8da3310e244dc7767c87b25d7f2848a6 /sys | |
parent | 6485f21df442288ecd8d53e52d1c81c426b4e076 (diff) |
Add i2c controller support.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/macppc/conf/GENERIC | 5 | ||||
-rw-r--r-- | sys/arch/macppc/dev/smu.c | 111 |
2 files changed, 114 insertions, 2 deletions
diff --git a/sys/arch/macppc/conf/GENERIC b/sys/arch/macppc/conf/GENERIC index 8d48a22e3f8..b37549aa973 100644 --- a/sys/arch/macppc/conf/GENERIC +++ b/sys/arch/macppc/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.97 2005/11/06 03:10:08 drahn Exp $g +# $OpenBSD: GENERIC,v 1.98 2005/11/11 16:44:35 kettenis Exp $g # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -243,6 +243,9 @@ radio* at udsbr? # USB radio #ubt* at uhub? # USB Bluetooth ugen* at uhub? # USB Generic driver +# I2C bus support +maciic* at smu? + # CardBus bus support cardbus* at cardslot? pcmcia* at cardslot? diff --git a/sys/arch/macppc/dev/smu.c b/sys/arch/macppc/dev/smu.c index 092d3c519e9..759829ea230 100644 --- a/sys/arch/macppc/dev/smu.c +++ b/sys/arch/macppc/dev/smu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: smu.c,v 1.4 2005/11/11 00:33:50 kettenis Exp $ */ +/* $OpenBSD: smu.c,v 1.5 2005/11/11 16:44:36 kettenis Exp $ */ /* * Copyright (c) 2005 Mark Kettenis @@ -27,8 +27,11 @@ #include <machine/autoconf.h> #include <dev/clock_subr.h> +#include <dev/i2c/i2cvar.h> #include <dev/ofw/openfirm.h> +#include <arch/macppc/dev/maci2cvar.h> + int smu_match(struct device *, void *, void *); void smu_attach(struct device *, struct device *, void *); @@ -77,6 +80,8 @@ struct smu_softc { int16_t sc_cpu_volt_offset; u_int16_t sc_cpu_curr_scale; int16_t sc_cpu_curr_offset; + + struct i2c_controller sc_i2c_tag; }; struct cfattach smu_ca = { @@ -112,6 +117,12 @@ struct smu_cmd { #define SMU_PARTITION_BASE 0x02 #define SMU_PARTITION_UPDATE 0x03 +/* I2C */ +#define SMU_I2C 0x9a +#define SMU_I2C_SIMPLE 0x00 +#define SMU_I2C_NORMAL 0x01 +#define SMU_I2C_COMBINED 0x02 + /* Miscellaneous */ #define SMU_MISC 0xee #define SMU_MISC_GET_DATA 0x02 @@ -127,6 +138,11 @@ int smu_fan_refresh(struct smu_softc *, struct smu_fan *); int smu_sensor_refresh(struct smu_softc *, struct smu_sensor *); void smu_refresh_sensors(void *); +int smu_i2c_acquire_bus(void *, int); +void smu_i2c_release_bus(void *, int); +int smu_i2c_exec(void *, i2c_op_t, i2c_addr_t, + const void *, size_t, void *buf, size_t, int); + #define GPIO_DDR 0x04 /* Data direction */ #define GPIO_DDR_OUTPUT 0x04 /* Output */ #define GPIO_DDR_INPUT 0x00 /* Input */ @@ -153,6 +169,7 @@ smu_attach(struct device *parent, struct device *self, void *aux) { struct smu_softc *sc = (struct smu_softc *)self; struct confargs *ca = aux; + struct maci2cbus_attach_args iba; struct smu_fan *fan; struct smu_sensor *sensor; int nseg, node; @@ -315,6 +332,18 @@ smu_attach(struct device *parent, struct device *self, void *aux) sensor_task_register(sc, smu_refresh_sensors, 5); printf("\n"); + + sc->sc_i2c_tag.ic_cookie = sc; + sc->sc_i2c_tag.ic_acquire_bus = smu_i2c_acquire_bus; + sc->sc_i2c_tag.ic_release_bus = smu_i2c_release_bus; + sc->sc_i2c_tag.ic_exec = smu_i2c_exec; + + node = OF_getnodebyname(ca->ca_node, "smu-i2c-control"); + + /* XXX */ + iba.iba_node = OF_child(node); + iba.iba_tag = &sc->sc_i2c_tag; + config_found(&sc->sc_dev, &iba, NULL); } int @@ -550,3 +579,83 @@ smu_refresh_sensors(void *arg) smu_fan_refresh(sc, &sc->sc_fans[i]); lockmgr(&sc->sc_lock, LK_RELEASE, NULL, curproc); } + +int +smu_i2c_acquire_bus(void *cookie, int flags) +{ + struct smu_softc *sc = cookie; + + if (flags & I2C_F_POLL) + return (0); + + return (lockmgr(&sc->sc_lock, LK_EXCLUSIVE, NULL, curproc)); +} + +void +smu_i2c_release_bus(void *cookie, int flags) +{ + struct smu_softc *sc = cookie; + + if (flags & I2C_F_POLL) + return; + + lockmgr(&sc->sc_lock, LK_RELEASE, NULL, curproc); +} + +int +smu_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) +{ + struct smu_softc *sc = cookie; + struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd; + u_int8_t smu_op = SMU_I2C_NORMAL; + int error, retries = 10; + + if (!I2C_OP_STOP_P(op) || cmdlen > 3 || len > 5) + return (EINVAL); + + if(cmdlen == 0) + smu_op = SMU_I2C_SIMPLE; + else if (I2C_OP_READ_P(op)) + smu_op = SMU_I2C_COMBINED; + + cmd->cmd = SMU_I2C; + cmd->len = 9 + len; + cmd->data[0] = 0xb; + cmd->data[1] = smu_op; + cmd->data[2] = addr << 1; + cmd->data[3] = cmdlen; + memcpy (&cmd->data[4], cmdbuf, cmdlen); + cmd->data[7] = addr << 1 | I2C_OP_READ_P(op); + cmd->data[8] = len; + memcpy(&cmd->data[9], buf, len); + + error = smu_do_cmd(sc, 250); + if (error) + return error; + + while (retries--) { + cmd->cmd = SMU_I2C; + cmd->len = 1; + cmd->data[0] = 0; + memset(&cmd->data[1], 0xff, len); + + error = smu_do_cmd(sc, 250); + if (error) + return error; + + if ((cmd->data[0] & 0x80) == 0) + break; + if (cmd->data[0] == 0xfd) + break; + + DELAY(15 * 1000); + } + + if (cmd->data[0] & 0x80) + return (EIO); + + if (I2C_OP_READ_P(op)) + memcpy(buf, &cmd->data[1], len); + return (0); +} |