Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/marvell Add a i2c driver for the onboard i2c/twsi co...
details: https://anonhg.NetBSD.org/src/rev/548b861ac2f3
branches: trunk
changeset: 573588:548b861ac2f3
user: matt <matt%NetBSD.org@localhost>
date: Tue Feb 01 20:58:46 2005 +0000
description:
Add a i2c driver for the onboard i2c/twsi controller on the GT642x0
diffstat:
sys/dev/marvell/gti2c.c | 278 +++++++++++++++++++++++++++++++++++++++++++++
sys/dev/marvell/gti2creg.h | 83 +++++++++++++
2 files changed, 361 insertions(+), 0 deletions(-)
diffs (truncated from 369 to 300 lines):
diff -r 4693d90a93df -r 548b861ac2f3 sys/dev/marvell/gti2c.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/marvell/gti2c.c Tue Feb 01 20:58:46 2005 +0000
@@ -0,0 +1,278 @@
+/* $NetBSD: gti2c.c,v 1.1 2005/02/01 20:58:46 matt Exp $ */
+
+/*
+ * Copyright (c) 2005 Brocade Communcations, inc.
+ * All rights reserved.
+ *
+ * Written by Matt Thomas for Brocade Communcations, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of Brocade Communications, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BROCADE COMMUNICATIONS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL EITHER BROCADE COMMUNICATIONS, INC. BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: gti2c.c,v 1.1 2005/02/01 20:58:46 matt Exp $");
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+
+#include <dev/marvell/gtintrreg.h>
+#include <dev/marvell/gti2creg.h>
+
+#include <dev/marvell/gtvar.h>
+
+#include <dev/i2c/i2cvar.h>
+
+struct gti2c_softc {
+ struct device sc_dev;
+ struct evcnt sc_ev_intr;
+ struct i2c_controller sc_i2c;
+ struct gt_softc *sc_gt;
+ struct lock sc_lock;
+};
+
+static int gt_i2c_match(struct device *, struct cfdata *, void *);
+static void gt_i2c_attach(struct device *, struct device *, void *);
+
+CFATTACH_DECL(gtiic, sizeof(struct gti2c_softc),
+ gt_i2c_match, gt_i2c_attach, NULL, NULL);
+
+extern struct cfdriver gtiic_cd;
+
+static int
+gt_i2c_wait(struct gti2c_softc *sc, uint32_t control,
+ uint32_t desired_status, int flags)
+{
+ uint32_t status;
+ int error = 0;
+
+ again:
+ if (flags & I2C_F_POLL)
+ control |= I2C_Control_IntEn;
+ if (desired_status != I2C_Status_MasterReadAck)
+ gt_write(sc->sc_gt, I2C_REG_Control, control);
+
+ for (;;) {
+ control = gt_read(sc->sc_gt, I2C_REG_Control);
+ if (control & I2C_Control_IFlg)
+ break;
+ error = tsleep(sc, PZERO, "gti2cwait",
+ (flags & I2C_F_POLL) ? 1 : 0);
+ if (error && (error != ETIMEDOUT || !(flags & I2C_F_POLL)))
+ return error;
+ }
+
+ status = gt_read(sc->sc_gt, I2C_REG_Status);
+ if (status != desired_status)
+ return EIO;
+
+ if ((flags & I2C_F_LAST) &&
+ desired_status != I2C_Status_MasterReadAck) {
+ control = I2C_Control_Stop;
+ goto again;
+ }
+
+ return error;
+}
+
+static int
+gt_i2c_acquire_bus(void *cookie, int flags)
+{
+ struct gti2c_softc * const sc = cookie;
+ uint32_t status;
+ int error;
+
+ if (flags & I2C_F_POLL)
+ return 0;
+
+ error = lockmgr(&sc->sc_lock, LK_EXCLUSIVE, NULL);
+ if (error)
+ return error;
+
+ status = gt_read(sc->sc_gt, I2C_REG_Status);
+ if (status != I2C_Status_Idle) {
+ gt_write(sc->sc_gt, I2C_REG_SoftReset, 1);
+ }
+
+ return 0;
+}
+
+static void
+gt_i2c_release_bus(void *cookie, int flags)
+{
+ struct gti2c_softc * const sc = cookie;
+
+ lockmgr(&sc->sc_lock, LK_RELEASE, NULL);
+}
+
+static int
+gt_i2c_send_start(void *cookie, int flags)
+{
+ struct gti2c_softc * const sc = cookie;
+
+ return gt_i2c_wait(sc, I2C_Control_Start, I2C_Status_Started, flags);
+}
+
+static int
+gt_i2c_send_stop(void *cookie, int flags)
+{
+ struct gti2c_softc * const sc = cookie;
+
+ return gt_i2c_wait(sc, I2C_Control_Stop, I2C_Status_Idle, flags);
+}
+
+static int
+gt_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
+{
+ struct gti2c_softc * const sc = cookie;
+ uint32_t data, wanted_status;
+ uint8_t read_mask = (flags & I2C_F_READ) != 0;
+ int error;
+
+ if (read_mask) {
+ wanted_status = I2C_Status_AddrReadAck;
+ } else {
+ wanted_status = I2C_Status_AddrWriteAck;
+ }
+ /*
+ * First byte contains whether this xfer is a read or write.
+ */
+ data = read_mask;
+ if (addr > 0x7f) {
+ /*
+ * If this is a 10bit request, the first address byte is
+ * 0b11110<b9><b8><r/w>.
+ */
+ data |= 0xf0 | ((addr & 0x30) >> 7);
+ gt_write(sc->sc_gt, I2C_REG_Data, data);
+ error = gt_i2c_wait(sc, 0, wanted_status, flags);
+ if (error)
+ return error;
+ /*
+ * The first address byte has been sent, now to send
+ * the second one.
+ */
+ if (read_mask) {
+ wanted_status = I2C_Status_2ndAddrReadAck;
+ } else {
+ wanted_status = I2C_Status_2ndAddrWriteAck;
+ }
+ data = (uint8_t) addr;
+ } else {
+ data |= (addr << 1);
+ }
+
+ gt_write(sc->sc_gt, I2C_REG_Data, data);
+ return gt_i2c_wait(sc, 0, wanted_status, flags);
+}
+
+static int
+gt_i2c_read_byte(void *cookie, uint8_t *dp, int flags)
+{
+ struct gti2c_softc * const sc = cookie;
+ int error;
+
+ gt_write(sc->sc_gt, I2C_REG_Data, *dp);
+ error = gt_i2c_wait(sc, 0, I2C_Status_MasterReadAck, flags);
+ if (error == 0) {
+ *dp = gt_read(sc->sc_gt, I2C_REG_Data);
+ }
+ if (flags & I2C_F_LAST)
+ gt_write(sc->sc_gt, I2C_REG_Control, 0);
+ return error;
+}
+
+static int
+gt_i2c_write_byte(void *cookie, uint8_t v, int flags)
+{
+ struct gti2c_softc * const sc = cookie;
+
+ gt_write(sc->sc_gt, I2C_REG_Data, v);
+ return gt_i2c_wait(sc, 0, I2C_Status_MasterWriteAck, flags);
+}
+
+static int
+gt_i2c_intr(void *aux)
+{
+ struct gti2c_softc * const sc = aux;
+ uint32_t v;
+
+ v = gt_read(sc->sc_gt, I2C_REG_Control);
+ if ((v & I2C_Control_IFlg) == 0)
+ return 0;
+ gt_write(sc->sc_gt, I2C_REG_Control, v & ~I2C_Control_IntEn);
+
+ sc->sc_ev_intr.ev_count++;
+
+ wakeup(sc);
+ return 1;
+}
+
+int
+gt_i2c_match(struct device *parent, struct cfdata *cfdata, void *aux)
+{
+ struct gt_softc * const gt = (void *) parent;
+ struct gt_attach_args * const ga = aux;
+
+ return GT_I2COK(gt, ga, >iic_cd);
+}
+
+void
+gt_i2c_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct gt_softc * const gt = (void *) parent;
+ struct gti2c_softc * const sc = (void *) self;
+ struct gt_attach_args * const ga = aux;
+ struct i2cbus_attach_args iba;
+
+ sc->sc_gt = gt;
+
+ GT_I2CFOUND(gt, ga);
+
+ lockinit(&sc->sc_lock, PZERO, sc->sc_dev.dv_xname, 0, 0);
+
+ sc->sc_i2c.ic_cookie = sc;
+ sc->sc_i2c.ic_acquire_bus = gt_i2c_acquire_bus;
+ sc->sc_i2c.ic_release_bus = gt_i2c_release_bus;
+ sc->sc_i2c.ic_release_bus = gt_i2c_release_bus;
+ sc->sc_i2c.ic_send_start = gt_i2c_send_start;
+ sc->sc_i2c.ic_send_stop = gt_i2c_send_stop;
+ sc->sc_i2c.ic_initiate_xfer = gt_i2c_initiate_xfer;
+ sc->sc_i2c.ic_read_byte = gt_i2c_read_byte;
+ sc->sc_i2c.ic_write_byte = gt_i2c_write_byte;
+
+ intr_establish(IRQ_I2C, IST_LEVEL, IPL_I2C, gt_i2c_intr, sc);
+
+ evcnt_attach_dynamic(&sc->sc_ev_intr, EVCNT_TYPE_INTR, NULL,
+ sc->sc_dev.dv_xname, "intr");
+
+ iba.iba_name = "iic";
+ iba.iba_tag = &sc->sc_i2c;
+ config_found(self, &iba, iicbus_print);
+}
diff -r 4693d90a93df -r 548b861ac2f3 sys/dev/marvell/gti2creg.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/marvell/gti2creg.h Tue Feb 01 20:58:46 2005 +0000
@@ -0,0 +1,83 @@
+/* $NetBSD: gti2creg.h,v 1.1 2005/02/01 20:58:46 matt Exp $ */
+
+/*
+ * Copyright (c) 2005 Brocade Communcations, inc.
+ * All rights reserved.
+ *
+ * Written by Matt Thomas for Brocade Communcations, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
Home |
Main Index |
Thread Index |
Old Index