Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/arm/allwinner add A31 P2WI (Push-Pull Two Wire Inte...



details:   https://anonhg.NetBSD.org/src/rev/ee6f06d5fac6
branches:  trunk
changeset: 332970:ee6f06d5fac6
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Sun Oct 12 23:57:58 2014 +0000

description:
add A31 P2WI (Push-Pull Two Wire Interface) driver

diffstat:

 sys/arch/arm/allwinner/awin_intr.h |    3 +-
 sys/arch/arm/allwinner/awin_io.c   |    3 +-
 sys/arch/arm/allwinner/awin_p2wi.c |  251 +++++++++++++++++++++++++++++++++++++
 sys/arch/arm/allwinner/awin_reg.h  |   49 +++++++
 sys/arch/arm/allwinner/files.awin  |    7 +-
 5 files changed, 310 insertions(+), 3 deletions(-)

diffs (truncated from 379 to 300 lines):

diff -r 752407d02f71 -r ee6f06d5fac6 sys/arch/arm/allwinner/awin_intr.h
--- a/sys/arch/arm/allwinner/awin_intr.h        Sun Oct 12 22:33:41 2014 +0000
+++ b/sys/arch/arm/allwinner/awin_intr.h        Sun Oct 12 23:57:58 2014 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: awin_intr.h,v 1.6 2014/10/12 14:06:18 jmcneill Exp $ */
+/* $NetBSD: awin_intr.h,v 1.7 2014/10/12 23:57:58 jmcneill Exp $ */
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -148,6 +148,7 @@
 #define AWIN_A31_IRQ_TWI2      40
 #define AWIN_A31_IRQ_TWI3      41
 #define AWIN_A31_IRQ_AC                61
+#define AWIN_A31_IRQ_P2WI      71
 #define AWIN_A31_IRQ_DMA       82
 #define AWIN_A31_IRQ_SDMMC0    92
 #define AWIN_A31_IRQ_SDMMC1    93
diff -r 752407d02f71 -r ee6f06d5fac6 sys/arch/arm/allwinner/awin_io.c
--- a/sys/arch/arm/allwinner/awin_io.c  Sun Oct 12 22:33:41 2014 +0000
+++ b/sys/arch/arm/allwinner/awin_io.c  Sun Oct 12 23:57:58 2014 +0000
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(1, "$NetBSD: awin_io.c,v 1.19 2014/10/12 17:20:46 jmcneill Exp $");
+__KERNEL_RCSID(1, "$NetBSD: awin_io.c,v 1.20 2014/10/12 23:57:58 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -132,6 +132,7 @@
        { "awiniic", OFFANDSIZE(TWI1), 1, AWIN_A31_IRQ_TWI1, A31 },
        { "awiniic", OFFANDSIZE(TWI2), 2, AWIN_A31_IRQ_TWI2, A31 },
        { "awiniic", OFFANDSIZE(TWI3), 3, AWIN_A31_IRQ_TWI3, A31 },
+       { "awinp2wi", OFFANDSIZE(A31_P2WI), NOPORT, AWIN_A31_IRQ_P2WI, A31 },
        { "spi", OFFANDSIZE(SPI0), 0, AWIN_IRQ_SPI0, AANY },
        { "spi", OFFANDSIZE(SPI1), 1, AWIN_IRQ_SPI1, AANY },
        { "spi", OFFANDSIZE(SPI2), 1, AWIN_IRQ_SPI2, AANY },
diff -r 752407d02f71 -r ee6f06d5fac6 sys/arch/arm/allwinner/awin_p2wi.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/allwinner/awin_p2wi.c        Sun Oct 12 23:57:58 2014 +0000
@@ -0,0 +1,251 @@
+/* $NetBSD: awin_p2wi.c,v 1.1 2014/10/12 23:57:58 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2014 Jared D. McNeill <jmcneill%invisible.ca@localhost>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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: awin_p2wi.c,v 1.1 2014/10/12 23:57:58 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+
+#include <arm/allwinner/awin_reg.h>
+#include <arm/allwinner/awin_var.h>
+
+#include <dev/i2c/i2cvar.h>
+
+struct awin_p2wi_softc {
+       device_t sc_dev;
+       bus_space_tag_t sc_bst;
+       bus_space_handle_t sc_bsh;
+       struct i2c_controller sc_ic;
+       kmutex_t sc_lock;
+       kcondvar_t sc_cv;
+       device_t sc_i2cdev;
+       void *sc_ih;
+       uint32_t sc_stat;
+};
+
+#define P2WI_READ(sc, reg) \
+    bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define P2WI_WRITE(sc, reg, val) \
+    bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+
+static int     awin_p2wi_acquire_bus(void *, int);
+static void     awin_p2wi_release_bus(void *, int);
+static int     awin_p2wi_exec(void *, i2c_op_t, i2c_addr_t, const void *,
+                              size_t, void *, size_t, int);
+
+static int     awin_p2wi_intr(void *);
+
+static int     awin_p2wi_match(device_t, cfdata_t, void *);
+static void    awin_p2wi_attach(device_t, device_t, void *);
+
+CFATTACH_DECL_NEW(awin_p2wi, sizeof(struct awin_p2wi_softc),
+       awin_p2wi_match, awin_p2wi_attach, NULL, NULL);
+
+static int
+awin_p2wi_match(device_t parent, cfdata_t cf, void *aux)
+{
+       struct awinio_attach_args * const aio = aux;
+       const struct awin_locators * const loc = &aio->aio_loc;
+
+       if (strcmp(cf->cf_name, loc->loc_name))
+               return 0;
+
+       return 1;
+}
+
+static void
+awin_p2wi_attach(device_t parent, device_t self, void *aux)
+{
+       struct awin_p2wi_softc *sc = device_private(self);
+       struct awinio_attach_args * const aio = aux;
+       const struct awin_locators * const loc = &aio->aio_loc;
+       struct i2cbus_attach_args iba;
+
+       sc->sc_dev = self;
+       sc->sc_bst = aio->aio_core_bst;
+       mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SCHED);
+       cv_init(&sc->sc_cv, "awinp2wi");
+       bus_space_subregion(sc->sc_bst, aio->aio_core_bsh,
+           loc->loc_offset, loc->loc_size, &sc->sc_bsh);
+
+       aprint_naive("\n");
+       aprint_normal(": P2WI\n");
+
+       sc->sc_ih = intr_establish(loc->loc_intr, IPL_SCHED, IST_LEVEL,
+           awin_p2wi_intr, sc);
+       if (sc->sc_ih == NULL) {
+               aprint_error_dev(self, "couldn't establish interrupt %d\n",
+                   loc->loc_intr);
+               return;
+       }
+       aprint_normal_dev(self, "interrupting on irq %d\n", loc->loc_intr);
+
+       /* Enable interrupts */
+       P2WI_WRITE(sc, AWIN_A31_P2WI_INTE_REG,
+           AWIN_A31_P2WI_INTE_LOAD_BSY_ENB |
+           AWIN_A31_P2WI_INTE_TRANS_ERR_ENB |
+           AWIN_A31_P2WI_INTE_TRANS_OVER_ENB);
+       P2WI_WRITE(sc, AWIN_A31_P2WI_CTRL_REG,
+           AWIN_A31_P2WI_CTRL_GLOBAL_INT_ENB);
+
+       sc->sc_ic.ic_cookie = sc;
+       sc->sc_ic.ic_acquire_bus = awin_p2wi_acquire_bus;
+       sc->sc_ic.ic_release_bus = awin_p2wi_release_bus;
+       sc->sc_ic.ic_exec = awin_p2wi_exec;
+
+       memset(&iba, 0, sizeof(iba));
+       iba.iba_tag = &sc->sc_ic;
+       sc->sc_i2cdev = config_found_ia(self, "i2cbus", &iba, iicbus_print);
+}
+
+static int
+awin_p2wi_intr(void *priv)
+{
+       struct awin_p2wi_softc *sc = priv;
+       uint32_t stat;
+
+       stat = P2WI_READ(sc, AWIN_A31_P2WI_STAT_REG);
+       if ((stat & AWIN_A31_P2WI_STAT_MASK) == 0)
+               return 0;
+
+       P2WI_WRITE(sc, AWIN_A31_P2WI_STAT_REG, stat & AWIN_A31_P2WI_STAT_MASK);
+
+       mutex_enter(&sc->sc_lock);
+       sc->sc_stat |= stat;
+       cv_broadcast(&sc->sc_cv);
+       mutex_exit(&sc->sc_lock);
+
+       return 1;
+}
+
+static int
+awin_p2wi_acquire_bus(void *priv, int flags)
+{
+       struct awin_p2wi_softc *sc = priv;
+
+       if (flags & I2C_F_POLL) {
+               if (!mutex_tryenter(&sc->sc_lock))
+                       return EBUSY;
+       } else {
+               mutex_enter(&sc->sc_lock);
+       }
+
+       return 0;
+}
+
+static void
+awin_p2wi_release_bus(void *priv, int flags)
+{
+       struct awin_p2wi_softc *sc = priv;
+
+       mutex_exit(&sc->sc_lock);
+}
+
+static int
+awin_p2wi_exec(void *priv, i2c_op_t op, i2c_addr_t addr,
+    const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
+{
+       struct awin_p2wi_softc *sc = priv;
+       uint32_t dlen, ctrl;
+       int error, retry;
+
+       KASSERT(mutex_owned(&sc->sc_lock));
+
+       if (cmdlen != 1 || len != 1)
+               return EINVAL;
+
+       /* Data byte register */
+       P2WI_WRITE(sc, AWIN_A31_P2WI_DADDR0_REG, *(const uint8_t *)cmdbuf);
+
+       if (I2C_OP_WRITE_P(op)) {
+               /* Write data byte */
+               P2WI_WRITE(sc, AWIN_A31_P2WI_DATA0_REG, *(uint8_t *)buf);
+       }
+
+       /* Program data length register; if reading, set read/write bit */
+       dlen = __SHIFTIN(len - 1, AWIN_A31_P2WI_DLEN_ACCESS_LENGTH);
+       if (I2C_OP_READ_P(op)) {
+               dlen |= AWIN_A31_P2WI_DLEN_READ_WRITE_FLAG;
+       }
+       P2WI_WRITE(sc, AWIN_A31_P2WI_DLEN_REG, dlen);
+
+       /* Make sure the controller is idle */
+       ctrl = P2WI_READ(sc, AWIN_A31_P2WI_CTRL_REG);
+       if (ctrl & AWIN_A31_P2WI_CTRL_START_TRANS) {
+               device_printf(sc->sc_dev, "device is busy\n");
+               return EBUSY;
+       }
+
+       /* Start the transfer */
+       P2WI_WRITE(sc, AWIN_A31_P2WI_CTRL_REG,
+           ctrl | AWIN_A31_P2WI_CTRL_START_TRANS);
+
+       /* Wait up to 5 seconds for an interrupt */
+       sc->sc_stat = 0;
+       for (retry = 5; retry > 0; retry--) {
+               error = cv_timedwait(&sc->sc_cv, &sc->sc_lock, hz);
+               if (error && error != EWOULDBLOCK) {
+                       break;
+               }
+               if (sc->sc_stat & AWIN_A31_P2WI_STAT_MASK) {
+                       break;
+               }
+       }
+
+       if (error) {
+               /* Abort transaction */
+               device_printf(sc->sc_dev, "transfer timeout, error = %d\n",
+                   error);
+               P2WI_WRITE(sc, AWIN_A31_P2WI_CTRL_REG,
+                   AWIN_A31_P2WI_CTRL_ABORT_TRANS);
+               return error;
+       }
+
+       if (sc->sc_stat & AWIN_A31_P2WI_STAT_LOAD_BSY) {
+               device_printf(sc->sc_dev, "transfer busy\n");
+               return EBUSY;
+       }
+       if (sc->sc_stat & AWIN_A31_P2WI_STAT_TRANS_ERR) {
+               device_printf(sc->sc_dev, "transfer error, id 0x%02llx\n",
+                   __SHIFTOUT(sc->sc_stat, AWIN_A31_P2WI_STAT_TRANS_ERR_ID));
+               return EIO;
+       }
+
+       if (I2C_OP_READ_P(op)) {
+               *(uint8_t *)buf = P2WI_READ(sc, AWIN_A31_P2WI_DATA0_REG) & 0xff;
+       }
+
+       return 0;
+}
diff -r 752407d02f71 -r ee6f06d5fac6 sys/arch/arm/allwinner/awin_reg.h
--- a/sys/arch/arm/allwinner/awin_reg.h Sun Oct 12 22:33:41 2014 +0000
+++ b/sys/arch/arm/allwinner/awin_reg.h Sun Oct 12 23:57:58 2014 +0000
@@ -1703,6 +1703,7 @@
 #define AWIN_A31_PRCM_OFFSET           0x00301400      /* PRCM */
 #define AWIN_A31_CPUCFG_OFFSET         0x00301C00
 #define AWIN_A31_RTC_OFFSET            0x00300000      /* RTC */
+#define AWIN_A31_P2WI_OFFSET           0x00303400      /* P2WI */



Home | Main Index | Thread Index | Old Index