Author: andrew
Date: Mon Feb 15 15:11:26 2016
New Revision: 295626
URL: https://svnweb.freebsd.org/changeset/base/295626

Log:
  Add support for the Allwinner i2c device. This is similar to the existing
  Marvell twsi part, however uses different register locations, as such split
  the existing driver into Marvell and Allwinner attachments.
  
  While here clean a few style issues.
  
  Submitted by: Emmanuel Vadot <m...@bidouilliste.com>
  Differential Revision:        https://reviews.freebsd.org/D4846

Added:
  head/sys/dev/iicbus/twsi/a10_twsi.c   (contents, props changed)
  head/sys/dev/iicbus/twsi/mv_twsi.c
     - copied, changed from r295622, head/sys/dev/iicbus/twsi/twsi.c
  head/sys/dev/iicbus/twsi/twsi.h   (contents, props changed)
Modified:
  head/sys/arm/allwinner/a10_clk.c
  head/sys/arm/allwinner/a10_clk.h
  head/sys/arm/allwinner/files.allwinner
  head/sys/arm/conf/A10
  head/sys/arm/conf/A20
  head/sys/arm/mv/files.mv
  head/sys/dev/iicbus/twsi/twsi.c

Modified: head/sys/arm/allwinner/a10_clk.c
==============================================================================
--- head/sys/arm/allwinner/a10_clk.c    Mon Feb 15 14:34:35 2016        
(r295625)
+++ head/sys/arm/allwinner/a10_clk.c    Mon Feb 15 15:11:26 2016        
(r295626)
@@ -401,6 +401,29 @@ a10_clk_mmc_cfg(int devid, int freq)
 }
 
 int
+a10_clk_i2c_activate(int devid)
+{
+       struct a10_ccm_softc *sc;
+       uint32_t reg_value;
+
+       sc = a10_ccm_sc;
+       if (sc == NULL)
+               return (ENXIO);
+
+       a10_clk_pll6_enable();
+
+       /* Gating APB clock for I2C/TWI */
+       reg_value = ccm_read_4(sc, CCM_APB1_GATING);
+       if (devid == 4)
+               reg_value |= CCM_APB1_GATING_TWI << 15;
+       else
+               reg_value |= CCM_APB1_GATING_TWI << devid;
+       ccm_write_4(sc, CCM_APB1_GATING, reg_value);
+
+       return (0);
+}
+
+int
 a10_clk_dmac_activate(void)
 {
        struct a10_ccm_softc *sc;

Modified: head/sys/arm/allwinner/a10_clk.h
==============================================================================
--- head/sys/arm/allwinner/a10_clk.h    Mon Feb 15 14:34:35 2016        
(r295625)
+++ head/sys/arm/allwinner/a10_clk.h    Mon Feb 15 15:11:26 2016        
(r295626)
@@ -121,6 +121,9 @@
 /* AHB_GATING_REG1 */
 #define        CCM_AHB_GATING_GMAC     (1 << 17)
 
+/* APB1_GATING_REG */
+#define CCM_APB1_GATING_TWI    (1 << 0)
+
 #define        CCM_USB_PHY             (1 << 8)
 #define        CCM_USB0_RESET          (1 << 0)
 #define        CCM_USB1_RESET          (1 << 1)
@@ -166,6 +169,7 @@ int a10_clk_gmac_activate(phandle_t);
 int a10_clk_ahci_activate(void);
 int a10_clk_mmc_activate(int);
 int a10_clk_mmc_cfg(int, int);
+int a10_clk_i2c_activate(int);
 int a10_clk_dmac_activate(void);
 int a10_clk_codec_activate(unsigned int);
 

Modified: head/sys/arm/allwinner/files.allwinner
==============================================================================
--- head/sys/arm/allwinner/files.allwinner      Mon Feb 15 14:34:35 2016        
(r295625)
+++ head/sys/arm/allwinner/files.allwinner      Mon Feb 15 15:11:26 2016        
(r295626)
@@ -12,4 +12,5 @@ arm/allwinner/a10_wdog.c              standard
 arm/allwinner/a20/a20_cpu_cfg.c        standard
 arm/allwinner/allwinner_machdep.c      standard
 arm/allwinner/if_emac.c                        optional        emac
+dev/iicbus/twsi/a10_twsi.c             optional        twsi
 #arm/allwinner/console.c               standard

Modified: head/sys/arm/conf/A10
==============================================================================
--- head/sys/arm/conf/A10       Mon Feb 15 14:34:35 2016        (r295625)
+++ head/sys/arm/conf/A10       Mon Feb 15 15:11:26 2016        (r295626)
@@ -66,8 +66,9 @@ device                md
 device         random                  # Entropy device
 
 # I2C support
-#device                iicbus
-#device                iic
+device         iicbus
+device         iic
+device         twsi
 
 # GPIO
 device         gpio

Modified: head/sys/arm/conf/A20
==============================================================================
--- head/sys/arm/conf/A20       Mon Feb 15 14:34:35 2016        (r295625)
+++ head/sys/arm/conf/A20       Mon Feb 15 15:11:26 2016        (r295626)
@@ -75,8 +75,9 @@ device                md
 device         random                  # Entropy device
 
 # I2C support
-#device                iicbus
-#device                iic
+device         iicbus
+device         iic
+device         twsi
 
 # GPIO
 device         gpio

Modified: head/sys/arm/mv/files.mv
==============================================================================
--- head/sys/arm/mv/files.mv    Mon Feb 15 14:34:35 2016        (r295625)
+++ head/sys/arm/mv/files.mv    Mon Feb 15 15:11:26 2016        (r295626)
@@ -21,6 +21,7 @@ arm/mv/mv_ts.c                        standard
 arm/mv/timer.c                 standard
 
 dev/cesa/cesa.c                        optional        cesa
+dev/iicbus/twsi/mv_twsi.c      optional        twsi
 dev/mge/if_mge.c               optional        mge
 dev/nand/nfc_mv.c              optional        nand
 dev/mvs/mvs_soc.c              optional        mvs

Added: head/sys/dev/iicbus/twsi/a10_twsi.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/dev/iicbus/twsi/a10_twsi.c Mon Feb 15 15:11:26 2016        
(r295626)
@@ -0,0 +1,131 @@
+/*-
+ * Copyright (c) 2016 Emmanuel Vadot <m...@bidouilliste.com>
+ * 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 AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/resource.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <sys/rman.h>
+
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#include <dev/iicbus/iiconf.h>
+#include <dev/iicbus/iicbus.h>
+#include <dev/iicbus/twsi/twsi.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/allwinner/a10_clk.h>
+
+#include "iicbus_if.h"
+
+#define        TWI_ADDR        0x0
+#define        TWI_XADDR       0x4
+#define        TWI_DATA        0x8
+#define        TWI_CNTR        0xC
+#define        TWI_STAT        0x10
+#define        TWI_CCR         0x14
+#define        TWI_SRST        0x18
+#define        TWI_EFR         0x1C
+#define        TWI_LCR         0x20
+
+static int
+a10_twsi_probe(device_t dev)
+{
+       struct twsi_softc *sc;
+
+       sc = device_get_softc(dev);
+       if (!ofw_bus_status_okay(dev))
+               return (ENXIO);
+
+       if (!ofw_bus_is_compatible(dev, "allwinner,sun4i-a10-i2c"))
+               return (ENXIO);
+
+       device_set_desc(dev, "Allwinner Integrated I2C Bus Controller");
+       return (BUS_PROBE_DEFAULT);
+}
+
+static int
+a10_twsi_attach(device_t dev)
+{
+       struct twsi_softc *sc;
+
+       sc = device_get_softc(dev);
+
+       /* Activate clock */
+       a10_clk_i2c_activate(device_get_unit(dev));
+
+       sc->reg_data = TWI_DATA;
+       sc->reg_slave_addr = TWI_ADDR;
+       sc->reg_slave_ext_addr = TWI_XADDR;
+       sc->reg_control = TWI_CNTR;
+       sc->reg_status = TWI_STAT;
+       sc->reg_baud_rate = TWI_CCR;
+       sc->reg_soft_reset = TWI_SRST;
+
+       /* Setup baud rate params */
+       sc->baud_rate[IIC_SLOW].param = TWSI_BAUD_RATE_PARAM(11, 2);
+       sc->baud_rate[IIC_FAST].param = TWSI_BAUD_RATE_PARAM(11, 2);
+       sc->baud_rate[IIC_FASTEST].param = TWSI_BAUD_RATE_PARAM(2, 2);
+
+       return (twsi_attach(dev));
+}
+
+static phandle_t
+a10_twsi_get_node(device_t bus, device_t dev)
+{
+       return (ofw_bus_get_node(bus));
+}
+
+static device_method_t a10_twsi_methods[] = {
+       /* device interface */
+       DEVMETHOD(device_probe,         a10_twsi_probe),
+       DEVMETHOD(device_attach,        a10_twsi_attach),
+
+       /* OFW methods */
+       DEVMETHOD(ofw_bus_get_node,     a10_twsi_get_node),
+
+       { 0, 0 }
+};
+
+DEFINE_CLASS_1(iichb, a10_twsi_driver, a10_twsi_methods,
+    sizeof(struct twsi_softc), twsi_driver);
+
+static devclass_t a10_twsi_devclass;
+
+DRIVER_MODULE(a10_twsi, simplebus, a10_twsi_driver, a10_twsi_devclass, 0, 0);
+DRIVER_MODULE(iicbus, a10_twsi, iicbus_driver, iicbus_devclass, 0, 0);
+MODULE_DEPEND(a10_twsi, iicbus, 1, 1, 1);

Copied and modified: head/sys/dev/iicbus/twsi/mv_twsi.c (from r295622, 
head/sys/dev/iicbus/twsi/twsi.c)
==============================================================================
--- head/sys/dev/iicbus/twsi/twsi.c     Sun Feb 14 23:51:13 2016        
(r295622, copy source)
+++ head/sys/dev/iicbus/twsi/mv_twsi.c  Mon Feb 15 15:11:26 2016        
(r295626)
@@ -31,7 +31,7 @@
 
 /*
  * Driver for the TWSI (aka I2C, aka IIC) bus controller found on Marvell
- * SoCs. Supports master operation only, and works in polling mode.
+ * and Allwinner SoCs. Supports master operation only, and works in polling 
mode.
  *
  * Calls to DELAY() are needed per Application Note AN-179 "TWSI Software
  * Guidelines for Discovery(TM), Horizon (TM) and Feroceon(TM) Devices".
@@ -62,42 +62,27 @@ __FBSDID("$FreeBSD$");
 #include <dev/ofw/ofw_bus.h>
 #include <dev/ofw/ofw_bus_subr.h>
 
+#include <arm/mv/mvreg.h>
 #include <arm/mv/mvvar.h>
+#include <dev/iicbus/twsi/twsi.h>
 
 #include "iicbus_if.h"
 
 #define MV_TWSI_NAME           "twsi"
 #define        IICBUS_DEVNAME          "iicbus"
 
-#define TWSI_SLAVE_ADDR                0x00
-#define TWSI_EXT_SLAVE_ADDR    0x10
-#define TWSI_DATA              0x04
-
-#define TWSI_CONTROL           0x08
-#define TWSI_CONTROL_ACK       (1 << 2)
-#define TWSI_CONTROL_IFLG      (1 << 3)
-#define TWSI_CONTROL_STOP      (1 << 4)
-#define TWSI_CONTROL_START     (1 << 5)
-#define TWSI_CONTROL_TWSIEN    (1 << 6)
-#define TWSI_CONTROL_INTEN     (1 << 7)
-
-#define TWSI_STATUS                    0x0c
-#define TWSI_STATUS_START              0x08
-#define TWSI_STATUS_RPTD_START         0x10
-#define TWSI_STATUS_ADDR_W_ACK         0x18
-#define TWSI_STATUS_DATA_WR_ACK                0x28
-#define TWSI_STATUS_ADDR_R_ACK         0x40
-#define TWSI_STATUS_DATA_RD_ACK                0x50
-#define TWSI_STATUS_DATA_RD_NOACK      0x58
+#define TWSI_ADDR      0x00
+#define TWSI_DATA      0x04
+#define TWSI_CNTR      0x08
+#define TWSI_XADDR     0x10
+#define TWSI_STAT      0x0c
+#define TWSI_BAUD_RATE 0x0c
+#define TWSI_SRST      0x1c
 
-#define TWSI_BAUD_RATE         0x0c
-#define        TWSI_BAUD_RATE_PARAM(M,N)       ((((M) << 3) | ((N) & 0x7)) & 
0x7f)
 #define        TWSI_BAUD_RATE_RAW(C,M,N)       ((C)/((10*(M+1))<<(N+1)))
 #define        TWSI_BAUD_RATE_SLOW             50000   /* 50kHz */
 #define        TWSI_BAUD_RATE_FAST             100000  /* 100kHz */
 
-#define TWSI_SOFT_RESET                0x1c
-
 #define TWSI_DEBUG
 #undef TWSI_DEBUG
 
@@ -107,38 +92,8 @@ __FBSDID("$FreeBSD$");
 #define debugf(fmt, args...)
 #endif
 
-struct mv_twsi_softc {
-       device_t        dev;
-       struct resource *res[1];        /* SYS_RES_MEMORY */
-       struct mtx      mutex;
-       device_t        iicbus;
-};
-
-static struct mv_twsi_baud_rate {
-       uint32_t        raw;
-       int             param;
-       int             m;
-       int             n;
-} baud_rate[IIC_FASTEST + 1];
-
 static int mv_twsi_probe(device_t);
 static int mv_twsi_attach(device_t);
-static int mv_twsi_detach(device_t);
-
-static int mv_twsi_reset(device_t dev, u_char speed, u_char addr,
-    u_char *oldaddr);
-static int mv_twsi_repeated_start(device_t dev, u_char slave, int timeout);
-static int mv_twsi_start(device_t dev, u_char slave, int timeout);
-static int mv_twsi_stop(device_t dev);
-static int mv_twsi_read(device_t dev, char *buf, int len, int *read, int last,
-    int delay);
-static int mv_twsi_write(device_t dev, const char *buf, int len, int *sent,
-    int timeout);
-
-static struct resource_spec res_spec[] = {
-       { SYS_RES_MEMORY, 0, RF_ACTIVE },
-       { -1, 0 }
-};
 
 static struct ofw_compat_data compat_data[] = {
        { "mrvl,twsi",                  true },
@@ -150,179 +105,46 @@ static device_method_t mv_twsi_methods[]
        /* device interface */
        DEVMETHOD(device_probe,         mv_twsi_probe),
        DEVMETHOD(device_attach,        mv_twsi_attach),
-       DEVMETHOD(device_detach,        mv_twsi_detach),
 
-       /* iicbus interface */
-       DEVMETHOD(iicbus_callback, iicbus_null_callback),
-       DEVMETHOD(iicbus_repeated_start, mv_twsi_repeated_start),
-       DEVMETHOD(iicbus_start,         mv_twsi_start),
-       DEVMETHOD(iicbus_stop,          mv_twsi_stop),
-       DEVMETHOD(iicbus_write,         mv_twsi_write),
-       DEVMETHOD(iicbus_read,          mv_twsi_read),
-       DEVMETHOD(iicbus_reset,         mv_twsi_reset),
-       DEVMETHOD(iicbus_transfer,      iicbus_transfer_gen),
        { 0, 0 }
 };
 
-static devclass_t mv_twsi_devclass;
+DEFINE_CLASS_1(twsi, mv_twsi_driver, mv_twsi_methods,
+    sizeof(struct twsi_softc), twsi_driver);
 
-static driver_t mv_twsi_driver = {
-       MV_TWSI_NAME,
-       mv_twsi_methods,
-       sizeof(struct mv_twsi_softc),
-};
+static devclass_t mv_twsi_devclass;
 
 DRIVER_MODULE(twsi, simplebus, mv_twsi_driver, mv_twsi_devclass, 0, 0);
 DRIVER_MODULE(iicbus, twsi, iicbus_driver, iicbus_devclass, 0, 0);
 MODULE_DEPEND(twsi, iicbus, 1, 1, 1);
 
-static __inline uint32_t
-TWSI_READ(struct mv_twsi_softc *sc, bus_size_t off)
-{
-
-       return (bus_read_4(sc->res[0], off));
-}
-
-static __inline void
-TWSI_WRITE(struct mv_twsi_softc *sc, bus_size_t off, uint32_t val)
-{
-
-       bus_write_4(sc->res[0], off, val);
-}
-
-static __inline void
-twsi_control_clear(struct mv_twsi_softc *sc, uint32_t mask)
-{
-       uint32_t val;
-
-       val = TWSI_READ(sc, TWSI_CONTROL);
-       val &= ~mask;
-       TWSI_WRITE(sc, TWSI_CONTROL, val);
-}
-
-static __inline void
-twsi_control_set(struct mv_twsi_softc *sc, uint32_t mask)
-{
-       uint32_t val;
-
-       val = TWSI_READ(sc, TWSI_CONTROL);
-       val |= mask;
-       TWSI_WRITE(sc, TWSI_CONTROL, val);
-}
-
-static __inline void
-twsi_clear_iflg(struct mv_twsi_softc *sc)
-{
-
-       DELAY(1000);
-       twsi_control_clear(sc, TWSI_CONTROL_IFLG);
-       DELAY(1000);
-}
-
-
-/*
- * timeout given in us
- * returns
- *   0 on sucessfull mask change
- *   non-zero on timeout
- */
-static int
-twsi_poll_ctrl(struct mv_twsi_softc *sc, int timeout, uint32_t mask)
-{
-
-       timeout /= 10;
-       while (!(TWSI_READ(sc, TWSI_CONTROL) & mask)) {
-               DELAY(10);
-               if (--timeout < 0)
-                       return (timeout);
-       }
-       return (0);
-}
-
-
-/*
- * 'timeout' is given in us. Note also that timeout handling is not exact --
- * twsi_locked_start() total wait can be more than 2 x timeout
- * (twsi_poll_ctrl() is called twice). 'mask' can be either TWSI_STATUS_START
- * or TWSI_STATUS_RPTD_START
- */
-static int
-twsi_locked_start(device_t dev, struct mv_twsi_softc *sc, int32_t mask,
-    u_char slave, int timeout)
-{
-       int read_access, iflg_set = 0;
-       uint32_t status;
-
-       mtx_assert(&sc->mutex, MA_OWNED);
-
-       if (mask == TWSI_STATUS_RPTD_START)
-               /* read IFLG to know if it should be cleared later; from NBSD */
-               iflg_set = TWSI_READ(sc, TWSI_CONTROL) & TWSI_CONTROL_IFLG;
-
-       twsi_control_set(sc, TWSI_CONTROL_START);
-
-       if (mask == TWSI_STATUS_RPTD_START && iflg_set) {
-               debugf("IFLG set, clearing\n");
-               twsi_clear_iflg(sc);
-       }
-
-       /*
-        * Without this delay we timeout checking IFLG if the timeout is 0.
-        * NBSD driver always waits here too.
-        */
-       DELAY(1000);
-
-       if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) {
-               debugf("timeout sending %sSTART condition\n",
-                   mask == TWSI_STATUS_START ? "" : "repeated ");
-               return (IIC_ETIMEOUT);
-       }
-
-       status = TWSI_READ(sc, TWSI_STATUS);
-       if (status != mask) {
-               debugf("wrong status (%02x) after sending %sSTART condition\n",
-                   status, mask == TWSI_STATUS_START ? "" : "repeated ");
-               return (IIC_ESTATUS);
-       }
-
-       TWSI_WRITE(sc, TWSI_DATA, slave);
-       DELAY(1000);
-       twsi_clear_iflg(sc);
-
-       if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) {
-               debugf("timeout sending slave address\n");
-               return (IIC_ETIMEOUT);
-       }
-       
-       read_access = (slave & 0x1) ? 1 : 0;
-       status = TWSI_READ(sc, TWSI_STATUS);
-       if (status != (read_access ?
-           TWSI_STATUS_ADDR_R_ACK : TWSI_STATUS_ADDR_W_ACK)) {
-               debugf("no ACK (status: %02x) after sending slave address\n",
-                   status);
-               return (IIC_ENOACK);
-       }
-
-       return (IIC_NOERR);
-}
-
 static int
 mv_twsi_probe(device_t dev)
 {
+       struct twsi_softc *sc;
 
+       sc = device_get_softc(dev);
        if (!ofw_bus_status_okay(dev))
                return (ENXIO);
 
        if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
                return (ENXIO);
 
+       sc->reg_data = TWSI_DATA;
+       sc->reg_slave_addr = TWSI_ADDR;
+       sc->reg_slave_ext_addr = TWSI_XADDR;
+       sc->reg_control = TWSI_CNTR;
+       sc->reg_status = TWSI_STAT;
+       sc->reg_baud_rate = TWSI_BAUD_RATE;
+       sc->reg_soft_reset = TWSI_SRST;
+
        device_set_desc(dev, "Marvell Integrated I2C Bus Controller");
        return (BUS_PROBE_DEFAULT);
 }
 
 #define        ABSSUB(a,b)     (((a) > (b)) ? (a) - (b) : (b) - (a))
 static void
-mv_twsi_cal_baud_rate(const uint32_t target, struct mv_twsi_baud_rate *rate)
+mv_twsi_cal_baud_rate(const uint32_t target, struct twsi_baud_rate *rate)
 {
        uint32_t clk, cur, diff, diff0;
        int m, n, m0, n0;
@@ -352,48 +174,33 @@ mv_twsi_cal_baud_rate(const uint32_t tar
 static int
 mv_twsi_attach(device_t dev)
 {
-       struct mv_twsi_softc *sc;
+       struct twsi_softc *sc;
        phandle_t child, iicbusnode;
        device_t childdev;
        struct iicbus_ivar *devi;
        char dname[32]; /* 32 is taken from struct u_device */
        uint32_t paddr;
-       int len, error;
+       int len, error, ret;
 
        sc = device_get_softc(dev);
-       sc->dev = dev;
-       bzero(baud_rate, sizeof(baud_rate));
 
-       mtx_init(&sc->mutex, device_get_nameunit(dev), MV_TWSI_NAME, MTX_DEF);
-
-       /* Allocate IO resources */
-       if (bus_alloc_resources(dev, res_spec, sc->res)) {
-               device_printf(dev, "could not allocate resources\n");
-               mv_twsi_detach(dev);
-               return (ENXIO);
-       }
-
-       mv_twsi_cal_baud_rate(TWSI_BAUD_RATE_SLOW, &baud_rate[IIC_SLOW]);
-       mv_twsi_cal_baud_rate(TWSI_BAUD_RATE_FAST, &baud_rate[IIC_FAST]);
+       mv_twsi_cal_baud_rate(TWSI_BAUD_RATE_SLOW, &sc->baud_rate[IIC_SLOW]);
+       mv_twsi_cal_baud_rate(TWSI_BAUD_RATE_FAST, &sc->baud_rate[IIC_FAST]);
        if (bootverbose)
                device_printf(dev, "calculated baud rates are:\n"
                    " %" PRIu32 " kHz (M=%d, N=%d) for slow,\n"
                    " %" PRIu32 " kHz (M=%d, N=%d) for fast.\n",
-                   baud_rate[IIC_SLOW].raw / 1000,
-                   baud_rate[IIC_SLOW].m,
-                   baud_rate[IIC_SLOW].n,
-                   baud_rate[IIC_FAST].raw / 1000,
-                   baud_rate[IIC_FAST].m,
-                   baud_rate[IIC_FAST].n);
-
-       sc->iicbus = device_add_child(dev, IICBUS_DEVNAME, -1);
-       if (sc->iicbus == NULL) {
-               device_printf(dev, "could not add iicbus child\n");
-               mv_twsi_detach(dev);
-               return (ENXIO);
-       }
-       /* Attach iicbus. */
-       bus_generic_attach(dev);
+                   sc->baud_rate[IIC_SLOW].raw / 1000,
+                   sc->baud_rate[IIC_SLOW].m,
+                   sc->baud_rate[IIC_SLOW].n,
+                   sc->baud_rate[IIC_FAST].raw / 1000,
+                   sc->baud_rate[IIC_FAST].m,
+                   sc->baud_rate[IIC_FAST].n);
+
+
+       ret = twsi_attach(dev);
+       if (ret != 0)
+               return (ret);
 
        iicbusnode = 0;
        /* Find iicbus as the child devices in the device tree. */
@@ -443,202 +250,3 @@ attach_end:
 
        return (0);
 }
-
-static int
-mv_twsi_detach(device_t dev)
-{
-       struct mv_twsi_softc *sc;
-       int rv;
-
-       sc = device_get_softc(dev);
-
-       if ((rv = bus_generic_detach(dev)) != 0)
-               return (rv);
-
-       if (sc->iicbus != NULL)
-               if ((rv = device_delete_child(dev, sc->iicbus)) != 0)
-                       return (rv);
-
-       bus_release_resources(dev, res_spec, sc->res);
-
-       mtx_destroy(&sc->mutex);
-       return (0);
-}
-
-/*
- * Only slave mode supported, disregard [old]addr
- */
-static int
-mv_twsi_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
-{
-       struct mv_twsi_softc *sc;
-       uint32_t param;
-
-       sc = device_get_softc(dev);
-
-       switch (speed) {
-       case IIC_SLOW:
-       case IIC_FAST:
-               param = baud_rate[speed].param;
-               break;
-       case IIC_FASTEST:
-       case IIC_UNKNOWN:
-       default:
-               param = baud_rate[IIC_FAST].param;
-               break;
-       }
-
-       mtx_lock(&sc->mutex);
-       TWSI_WRITE(sc, TWSI_SOFT_RESET, 0x0);
-       DELAY(2000);
-       TWSI_WRITE(sc, TWSI_BAUD_RATE, param);
-       TWSI_WRITE(sc, TWSI_CONTROL, TWSI_CONTROL_TWSIEN | TWSI_CONTROL_ACK);
-       DELAY(1000);
-       mtx_unlock(&sc->mutex);
-
-       return (0);
-}
-
-/*
- * timeout is given in us
- */
-static int
-mv_twsi_repeated_start(device_t dev, u_char slave, int timeout)
-{
-       struct mv_twsi_softc *sc;
-       int rv;
-
-       sc = device_get_softc(dev);
-
-       mtx_lock(&sc->mutex);
-       rv = twsi_locked_start(dev, sc, TWSI_STATUS_RPTD_START, slave,
-           timeout);
-       mtx_unlock(&sc->mutex);
-
-       if (rv) {
-               mv_twsi_stop(dev);
-               return (rv);
-       } else
-               return (IIC_NOERR);
-}
-
-/*
- * timeout is given in us
- */
-static int
-mv_twsi_start(device_t dev, u_char slave, int timeout)
-{
-       struct mv_twsi_softc *sc;
-       int rv;
-
-       sc = device_get_softc(dev);
-
-       mtx_lock(&sc->mutex);
-       rv = twsi_locked_start(dev, sc, TWSI_STATUS_START, slave, timeout);
-       mtx_unlock(&sc->mutex);
-
-       if (rv) {
-               mv_twsi_stop(dev);
-               return (rv);
-       } else
-               return (IIC_NOERR);
-}
-
-static int
-mv_twsi_stop(device_t dev)
-{
-       struct mv_twsi_softc *sc;
-
-       sc = device_get_softc(dev);
-
-       mtx_lock(&sc->mutex);
-       twsi_control_set(sc, TWSI_CONTROL_STOP);
-       DELAY(1000);
-       twsi_clear_iflg(sc);
-       mtx_unlock(&sc->mutex);
-
-       return (IIC_NOERR);
-}
-
-static int
-mv_twsi_read(device_t dev, char *buf, int len, int *read, int last, int delay)
-{
-       struct mv_twsi_softc *sc;
-       uint32_t status;
-       int last_byte, rv;
-
-       sc = device_get_softc(dev);
-
-       mtx_lock(&sc->mutex);
-       *read = 0;
-       while (*read < len) {
-               /*
-                * Check if we are reading last byte of the last buffer,
-                * do not send ACK then, per I2C specs
-                */
-               last_byte = ((*read == len - 1) && last) ? 1 : 0;
-               if (last_byte)
-                       twsi_control_clear(sc, TWSI_CONTROL_ACK);
-               else
-                       twsi_control_set(sc, TWSI_CONTROL_ACK);
-
-               DELAY (1000);
-               twsi_clear_iflg(sc);
-
-               if (twsi_poll_ctrl(sc, delay, TWSI_CONTROL_IFLG)) {
-                       debugf("timeout reading data\n");
-                       rv = IIC_ETIMEOUT;
-                       goto out;
-               }
-
-               status = TWSI_READ(sc, TWSI_STATUS);
-               if (status != (last_byte ?
-                   TWSI_STATUS_DATA_RD_NOACK : TWSI_STATUS_DATA_RD_ACK)) {
-                       debugf("wrong status (%02x) while reading\n", status);
-                       rv = IIC_ESTATUS;
-                       goto out;
-               }
-
-               *buf++ = TWSI_READ(sc, TWSI_DATA);
-               (*read)++;
-       }
-       rv = IIC_NOERR;
-out:
-       mtx_unlock(&sc->mutex);
-       return (rv);
-}
-
-static int
-mv_twsi_write(device_t dev, const char *buf, int len, int *sent, int timeout)
-{
-       struct mv_twsi_softc *sc;
-       uint32_t status;
-       int rv;
-
-       sc = device_get_softc(dev);
-
-       mtx_lock(&sc->mutex);
-       *sent = 0;
-       while (*sent < len) {
-               TWSI_WRITE(sc, TWSI_DATA, *buf++);
-
-               twsi_clear_iflg(sc);
-               if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) {
-                       debugf("timeout writing data\n");
-                       rv = IIC_ETIMEOUT;
-                       goto out;
-               }
-
-               status = TWSI_READ(sc, TWSI_STATUS);
-               if (status != TWSI_STATUS_DATA_WR_ACK) {
-                       debugf("wrong status (%02x) while writing\n", status);
-                       rv = IIC_ESTATUS;
-                       goto out;
-               }
-               (*sent)++;
-       }
-       rv = IIC_NOERR;
-out:
-       mtx_unlock(&sc->mutex);
-       return (rv);
-}

Modified: head/sys/dev/iicbus/twsi/twsi.c
==============================================================================
--- head/sys/dev/iicbus/twsi/twsi.c     Mon Feb 15 14:34:35 2016        
(r295625)
+++ head/sys/dev/iicbus/twsi/twsi.c     Mon Feb 15 15:11:26 2016        
(r295626)
@@ -31,7 +31,7 @@
 
 /*
  * Driver for the TWSI (aka I2C, aka IIC) bus controller found on Marvell
- * SoCs. Supports master operation only, and works in polling mode.
+ * and Allwinner SoCs. Supports master operation only, and works in polling 
mode.
  *
  * Calls to DELAY() are needed per Application Note AN-179 "TWSI Software
  * Guidelines for Discovery(TM), Horizon (TM) and Feroceon(TM) Devices".
@@ -62,156 +62,75 @@ __FBSDID("$FreeBSD$");
 #include <dev/ofw/ofw_bus.h>
 #include <dev/ofw/ofw_bus_subr.h>
 
-#include <arm/mv/mvvar.h>
+#include <dev/iicbus/twsi/twsi.h>
 
 #include "iicbus_if.h"
 
-#define MV_TWSI_NAME           "twsi"
-#define        IICBUS_DEVNAME          "iicbus"
+#define        TWSI_CONTROL_ACK        (1 << 2)
+#define        TWSI_CONTROL_IFLG       (1 << 3)
+#define        TWSI_CONTROL_STOP       (1 << 4)
+#define        TWSI_CONTROL_START      (1 << 5)
+#define        TWSI_CONTROL_TWSIEN     (1 << 6)
+#define        TWSI_CONTROL_INTEN      (1 << 7)
+
+#define        TWSI_STATUS_START               0x08
+#define        TWSI_STATUS_RPTD_START          0x10
+#define        TWSI_STATUS_ADDR_W_ACK          0x18
+#define        TWSI_STATUS_DATA_WR_ACK         0x28
+#define        TWSI_STATUS_ADDR_R_ACK          0x40
+#define        TWSI_STATUS_DATA_RD_ACK         0x50
+#define        TWSI_STATUS_DATA_RD_NOACK       0x58
 
-#define TWSI_SLAVE_ADDR                0x00
-#define TWSI_EXT_SLAVE_ADDR    0x10
-#define TWSI_DATA              0x04
-
-#define TWSI_CONTROL           0x08
-#define TWSI_CONTROL_ACK       (1 << 2)
-#define TWSI_CONTROL_IFLG      (1 << 3)
-#define TWSI_CONTROL_STOP      (1 << 4)
-#define TWSI_CONTROL_START     (1 << 5)
-#define TWSI_CONTROL_TWSIEN    (1 << 6)
-#define TWSI_CONTROL_INTEN     (1 << 7)
-
-#define TWSI_STATUS                    0x0c
-#define TWSI_STATUS_START              0x08
-#define TWSI_STATUS_RPTD_START         0x10
-#define TWSI_STATUS_ADDR_W_ACK         0x18
-#define TWSI_STATUS_DATA_WR_ACK                0x28
-#define TWSI_STATUS_ADDR_R_ACK         0x40
-#define TWSI_STATUS_DATA_RD_ACK                0x50
-#define TWSI_STATUS_DATA_RD_NOACK      0x58
-
-#define TWSI_BAUD_RATE         0x0c
-#define        TWSI_BAUD_RATE_PARAM(M,N)       ((((M) << 3) | ((N) & 0x7)) & 
0x7f)
-#define        TWSI_BAUD_RATE_RAW(C,M,N)       ((C)/((10*(M+1))<<(N+1)))
-#define        TWSI_BAUD_RATE_SLOW             50000   /* 50kHz */
-#define        TWSI_BAUD_RATE_FAST             100000  /* 100kHz */
-
-#define TWSI_SOFT_RESET                0x1c
-
-#define TWSI_DEBUG
+#define        TWSI_DEBUG
 #undef TWSI_DEBUG
 
-#ifdef  TWSI_DEBUG
-#define debugf(fmt, args...) do { printf("%s(): ", __func__); 
printf(fmt,##args); } while (0)
+#ifdef TWSI_DEBUG
+#define        debugf(fmt, args...) do { printf("%s(): ", __func__); 
printf(fmt,##args); } while (0)
 #else
-#define debugf(fmt, args...)
+#define        debugf(fmt, args...)
 #endif
 
-struct mv_twsi_softc {
-       device_t        dev;
-       struct resource *res[1];        /* SYS_RES_MEMORY */
-       struct mtx      mutex;
-       device_t        iicbus;
-};
-
-static struct mv_twsi_baud_rate {
-       uint32_t        raw;
-       int             param;
-       int             m;
-       int             n;
-} baud_rate[IIC_FASTEST + 1];
-
-static int mv_twsi_probe(device_t);
-static int mv_twsi_attach(device_t);
-static int mv_twsi_detach(device_t);
-
-static int mv_twsi_reset(device_t dev, u_char speed, u_char addr,
-    u_char *oldaddr);
-static int mv_twsi_repeated_start(device_t dev, u_char slave, int timeout);
-static int mv_twsi_start(device_t dev, u_char slave, int timeout);
-static int mv_twsi_stop(device_t dev);
-static int mv_twsi_read(device_t dev, char *buf, int len, int *read, int last,
-    int delay);
-static int mv_twsi_write(device_t dev, const char *buf, int len, int *sent,
-    int timeout);
-
 static struct resource_spec res_spec[] = {
        { SYS_RES_MEMORY, 0, RF_ACTIVE },
        { -1, 0 }
 };
 
-static struct ofw_compat_data compat_data[] = {
-       { "mrvl,twsi",                  true },
-       { "marvell,mv64xxx-i2c",        true },
-       { NULL,                         false }
-};
-
-static device_method_t mv_twsi_methods[] = {
-       /* device interface */
-       DEVMETHOD(device_probe,         mv_twsi_probe),
-       DEVMETHOD(device_attach,        mv_twsi_attach),
-       DEVMETHOD(device_detach,        mv_twsi_detach),
-
-       /* iicbus interface */
-       DEVMETHOD(iicbus_callback, iicbus_null_callback),
-       DEVMETHOD(iicbus_repeated_start, mv_twsi_repeated_start),
-       DEVMETHOD(iicbus_start,         mv_twsi_start),
-       DEVMETHOD(iicbus_stop,          mv_twsi_stop),
-       DEVMETHOD(iicbus_write,         mv_twsi_write),
-       DEVMETHOD(iicbus_read,          mv_twsi_read),
-       DEVMETHOD(iicbus_reset,         mv_twsi_reset),
-       DEVMETHOD(iicbus_transfer,      iicbus_transfer_gen),
-       { 0, 0 }
-};
-
-static devclass_t mv_twsi_devclass;
-
-static driver_t mv_twsi_driver = {
-       MV_TWSI_NAME,
-       mv_twsi_methods,
-       sizeof(struct mv_twsi_softc),
-};
-
-DRIVER_MODULE(twsi, simplebus, mv_twsi_driver, mv_twsi_devclass, 0, 0);
-DRIVER_MODULE(iicbus, twsi, iicbus_driver, iicbus_devclass, 0, 0);
-MODULE_DEPEND(twsi, iicbus, 1, 1, 1);
-
 static __inline uint32_t
-TWSI_READ(struct mv_twsi_softc *sc, bus_size_t off)
+TWSI_READ(struct twsi_softc *sc, bus_size_t off)
 {
 
        return (bus_read_4(sc->res[0], off));
 }
 
 static __inline void
-TWSI_WRITE(struct mv_twsi_softc *sc, bus_size_t off, uint32_t val)
+TWSI_WRITE(struct twsi_softc *sc, bus_size_t off, uint32_t val)
 {
 
        bus_write_4(sc->res[0], off, val);
 }
 
 static __inline void
-twsi_control_clear(struct mv_twsi_softc *sc, uint32_t mask)
+twsi_control_clear(struct twsi_softc *sc, uint32_t mask)
 {
        uint32_t val;
 
-       val = TWSI_READ(sc, TWSI_CONTROL);
+       val = TWSI_READ(sc, sc->reg_control);
        val &= ~mask;
-       TWSI_WRITE(sc, TWSI_CONTROL, val);
+       TWSI_WRITE(sc, sc->reg_control, val);
 }
 
 static __inline void
-twsi_control_set(struct mv_twsi_softc *sc, uint32_t mask)
+twsi_control_set(struct twsi_softc *sc, uint32_t mask)
 {
        uint32_t val;
 
-       val = TWSI_READ(sc, TWSI_CONTROL);
+       val = TWSI_READ(sc, sc->reg_control);
        val |= mask;
-       TWSI_WRITE(sc, TWSI_CONTROL, val);
+       TWSI_WRITE(sc, sc->reg_control, val);
 }
 
 static __inline void
-twsi_clear_iflg(struct mv_twsi_softc *sc)
+twsi_clear_iflg(struct twsi_softc *sc)
 {
 
        DELAY(1000);
@@ -227,11 +146,11 @@ twsi_clear_iflg(struct mv_twsi_softc *sc
  *   non-zero on timeout
  */
 static int
-twsi_poll_ctrl(struct mv_twsi_softc *sc, int timeout, uint32_t mask)
+twsi_poll_ctrl(struct twsi_softc *sc, int timeout, uint32_t mask)
 {
 
        timeout /= 10;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to