Page MenuHomeFreeBSD

D4846.id13315.diff
No OneTemporary

D4846.id13315.diff

Index: sys/arm/allwinner/a10_clk.h
===================================================================
--- sys/arm/allwinner/a10_clk.h
+++ sys/arm/allwinner/a10_clk.h
@@ -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_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);
Index: sys/arm/allwinner/a10_clk.c
===================================================================
--- sys/arm/allwinner/a10_clk.c
+++ sys/arm/allwinner/a10_clk.c
@@ -401,6 +401,29 @@
}
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;
Index: sys/arm/allwinner/files.allwinner
===================================================================
--- sys/arm/allwinner/files.allwinner
+++ sys/arm/allwinner/files.allwinner
@@ -12,4 +12,5 @@
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
Index: sys/arm/conf/A10
===================================================================
--- sys/arm/conf/A10
+++ sys/arm/conf/A10
@@ -66,8 +66,9 @@
device random # Entropy device
# I2C support
-#device iicbus
-#device iic
+device iicbus
+device iic
+device twsi
# GPIO
device gpio
Index: sys/arm/conf/A20
===================================================================
--- sys/arm/conf/A20
+++ sys/arm/conf/A20
@@ -75,8 +75,9 @@
device random # Entropy device
# I2C support
-#device iicbus
-#device iic
+device iicbus
+device iic
+device twsi
# GPIO
device gpio
Index: sys/arm/mv/files.mv
===================================================================
--- sys/arm/mv/files.mv
+++ sys/arm/mv/files.mv
@@ -21,6 +21,7 @@
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
Index: sys/dev/iicbus/twsi/a10_twsi.c
===================================================================
--- /dev/null
+++ sys/dev/iicbus/twsi/a10_twsi.c
@@ -0,0 +1,130 @@
+/*-
+ * Copyright (c) 2016 Emmanuel Vadot <manu@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/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);
+
+ twsi_attach(dev);
+
+ return (0);
+}
+
+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);
Index: sys/dev/iicbus/twsi/mv_twsi.c
===================================================================
--- /dev/null
+++ sys/dev/iicbus/twsi/mv_twsi.c
@@ -0,0 +1,250 @@
+/*-
+ * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
+ * All rights reserved.
+ *
+ * Developed by Semihalf.
+ *
+ * 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. Neither the name of MARVELL nor the names of contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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.
+ */
+
+/*
+ * Driver for the TWSI (aka I2C, aka IIC) bus controller found on Marvell
+ * 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".
+ */
+
+#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/_inttypes.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/fdt/fdt_common.h>
+#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_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_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_DEBUG
+#undef TWSI_DEBUG
+
+#ifdef TWSI_DEBUG
+#define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt,##args); } while (0)
+#else
+#define debugf(fmt, args...)
+#endif
+
+static int mv_twsi_probe(device_t);
+static int mv_twsi_attach(device_t);
+
+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),
+
+ { 0, 0 }
+};
+
+DEFINE_CLASS_1(twsi, mv_twsi_driver, mv_twsi_methods,
+ sizeof(struct twsi_softc), twsi_driver);
+
+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 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 twsi_baud_rate *rate)
+{
+ uint32_t clk, cur, diff, diff0;
+ int m, n, m0, n0;
+
+ /* Calculate baud rate. */
+ m0 = n0 = 4; /* Default values on reset */
+ diff0 = 0xffffffff;
+ clk = get_tclk();
+
+ for (n = 0; n < 8; n++) {
+ for (m = 0; m < 16; m++) {
+ cur = TWSI_BAUD_RATE_RAW(clk,m,n);
+ diff = ABSSUB(target, cur);
+ if (diff < diff0) {
+ m0 = m;
+ n0 = n;
+ diff0 = diff;
+ }
+ }
+ }
+ rate->raw = TWSI_BAUD_RATE_RAW(clk, m0, n0);
+ rate->param = TWSI_BAUD_RATE_PARAM(m0, n0);
+ rate->m = m0;
+ rate->n = n0;
+}
+
+static int
+mv_twsi_attach(device_t dev)
+{
+ 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;
+
+ sc = device_get_softc(dev);
+
+ 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",
+ 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);
+
+
+ twsi_attach(dev);
+
+ iicbusnode = 0;
+ /* Find iicbus as the child devices in the device tree. */
+ for (child = OF_child(ofw_bus_get_node(dev)); child != 0;
+ child = OF_peer(child)) {
+ len = OF_getproplen(child, "model");
+ if (len <= 0 || len > sizeof(dname))
+ continue;
+ error = OF_getprop(child, "model", &dname, len);
+ if (error == -1)
+ continue;
+ len = strlen(dname);
+ if (len == strlen(IICBUS_DEVNAME) &&
+ strncasecmp(dname, IICBUS_DEVNAME, len) == 0) {
+ iicbusnode = child;
+ break;
+ }
+ }
+ if (iicbusnode == 0)
+ goto attach_end;
+
+ /* Attach child devices onto iicbus. */
+ for (child = OF_child(iicbusnode); child != 0; child = OF_peer(child)) {
+ /* Get slave address. */
+ error = OF_getprop(child, "i2c-address", &paddr, sizeof(paddr));
+ if (error == -1)
+ error = OF_getprop(child, "reg", &paddr, sizeof(paddr));
+ if (error == -1)
+ continue;
+
+ /* Get device driver name. */
+ len = OF_getproplen(child, "model");
+ if (len <= 0 || len > sizeof(dname))
+ continue;
+ OF_getprop(child, "model", &dname, len);
+
+ if (bootverbose)
+ device_printf(dev, "adding a device %s at %d.\n",
+ dname, fdt32_to_cpu(paddr));
+ childdev = BUS_ADD_CHILD(sc->iicbus, 0, dname, -1);
+ devi = IICBUS_IVAR(childdev);
+ devi->addr = fdt32_to_cpu(paddr);
+ }
+
+attach_end:
+ bus_generic_attach(sc->iicbus);
+
+ return (0);
+}
Index: sys/dev/iicbus/twsi/twsi.h
===================================================================
--- /dev/null
+++ sys/dev/iicbus/twsi/twsi.h
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
+ * All rights reserved.
+ *
+ * Developed by Semihalf.
+ *
+ * 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. Neither the name of MARVELL nor the names of contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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.
+ */
+
+#ifndef _TWSI_H_
+#define _TWSI_H_
+
+struct twsi_baud_rate {
+ uint32_t raw;
+ int param;
+ int m;
+ int n;
+};
+
+struct twsi_softc {
+ device_t dev;
+ struct resource *res[1]; /* SYS_RES_MEMORY */
+ struct mtx mutex;
+ device_t iicbus;
+
+ bus_size_t reg_data;
+ bus_size_t reg_slave_addr;
+ bus_size_t reg_slave_ext_addr;
+ bus_size_t reg_control;
+ bus_size_t reg_status;
+ bus_size_t reg_baud_rate;
+ bus_size_t reg_soft_reset;
+ struct twsi_baud_rate baud_rate[IIC_FASTEST + 1];
+};
+
+DECLARE_CLASS(twsi_driver);
+
+#define TWSI_BAUD_RATE_PARAM(M,N) ((((M) << 3) | ((N) & 0x7)) & 0x7f)
+
+int twsi_attach(device_t);
+int twsi_detach(device_t);
+
+#endif /* _TWSI_H_ */
Index: sys/dev/iicbus/twsi/twsi.c
===================================================================
--- sys/dev/iicbus/twsi/twsi.c
+++ sys/dev/iicbus/twsi/twsi.c
@@ -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,18 +62,10 @@
#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_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)
@@ -81,7 +73,6 @@
#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
@@ -90,14 +81,6 @@
#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
#undef TWSI_DEBUG
@@ -107,111 +90,47 @@
#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 @@
* 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;
- while (!(TWSI_READ(sc, TWSI_CONTROL) & mask)) {
+ while (!(TWSI_READ(sc, sc->reg_control) & mask)) {
DELAY(10);
if (--timeout < 0)
return (timeout);
@@ -247,7 +166,7 @@
* or TWSI_STATUS_RPTD_START
*/
static int
-twsi_locked_start(device_t dev, struct mv_twsi_softc *sc, int32_t mask,
+twsi_locked_start(device_t dev, struct twsi_softc *sc, int32_t mask,
u_char slave, int timeout)
{
int read_access, iflg_set = 0;
@@ -257,7 +176,7 @@
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;
+ iflg_set = TWSI_READ(sc, sc->reg_control) & TWSI_CONTROL_IFLG;
twsi_control_set(sc, TWSI_CONTROL_START);
@@ -278,14 +197,14 @@
return (IIC_ETIMEOUT);
}
- status = TWSI_READ(sc, TWSI_STATUS);
+ status = TWSI_READ(sc, sc->reg_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);
+ TWSI_WRITE(sc, sc->reg_data, slave);
DELAY(1000);
twsi_clear_iflg(sc);
@@ -295,7 +214,7 @@
}
read_access = (slave & 0x1) ? 1 : 0;
- status = TWSI_READ(sc, TWSI_STATUS);
+ status = TWSI_READ(sc, sc->reg_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",
@@ -306,172 +225,13 @@
return (IIC_NOERR);
}
-static int
-mv_twsi_probe(device_t dev)
-{
-
- if (!ofw_bus_status_okay(dev))
- return (ENXIO);
-
- if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
- return (ENXIO);
-
- 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)
-{
- uint32_t clk, cur, diff, diff0;
- int m, n, m0, n0;
-
- /* Calculate baud rate. */
- m0 = n0 = 4; /* Default values on reset */
- diff0 = 0xffffffff;
- clk = get_tclk();
-
- for (n = 0; n < 8; n++) {
- for (m = 0; m < 16; m++) {
- cur = TWSI_BAUD_RATE_RAW(clk,m,n);
- diff = ABSSUB(target, cur);
- if (diff < diff0) {
- m0 = m;
- n0 = n;
- diff0 = diff;
- }
- }
- }
- rate->raw = TWSI_BAUD_RATE_RAW(clk, m0, n0);
- rate->param = TWSI_BAUD_RATE_PARAM(m0, n0);
- rate->m = m0;
- rate->n = n0;
-}
-
-static int
-mv_twsi_attach(device_t dev)
-{
- struct mv_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;
-
- 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]);
- 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);
-
- iicbusnode = 0;
- /* Find iicbus as the child devices in the device tree. */
- for (child = OF_child(ofw_bus_get_node(dev)); child != 0;
- child = OF_peer(child)) {
- len = OF_getproplen(child, "model");
- if (len <= 0 || len > sizeof(dname))
- continue;
- error = OF_getprop(child, "model", &dname, len);
- if (error == -1)
- continue;
- len = strlen(dname);
- if (len == strlen(IICBUS_DEVNAME) &&
- strncasecmp(dname, IICBUS_DEVNAME, len) == 0) {
- iicbusnode = child;
- break;
- }
- }
- if (iicbusnode == 0)
- goto attach_end;
-
- /* Attach child devices onto iicbus. */
- for (child = OF_child(iicbusnode); child != 0; child = OF_peer(child)) {
- /* Get slave address. */
- error = OF_getprop(child, "i2c-address", &paddr, sizeof(paddr));
- if (error == -1)
- error = OF_getprop(child, "reg", &paddr, sizeof(paddr));
- if (error == -1)
- continue;
-
- /* Get device driver name. */
- len = OF_getproplen(child, "model");
- if (len <= 0 || len > sizeof(dname))
- continue;
- OF_getprop(child, "model", &dname, len);
-
- if (bootverbose)
- device_printf(dev, "adding a device %s at %d.\n",
- dname, fdt32_to_cpu(paddr));
- childdev = BUS_ADD_CHILD(sc->iicbus, 0, dname, -1);
- devi = IICBUS_IVAR(childdev);
- devi->addr = fdt32_to_cpu(paddr);
- }
-
-attach_end:
- bus_generic_attach(sc->iicbus);
-
- 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)
+twsi_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
{
- struct mv_twsi_softc *sc;
+ struct twsi_softc *sc;
uint32_t param;
sc = device_get_softc(dev);
@@ -479,33 +239,49 @@
switch (speed) {
case IIC_SLOW:
case IIC_FAST:
- param = baud_rate[speed].param;
+ param = sc->baud_rate[speed].param;
break;
case IIC_FASTEST:
case IIC_UNKNOWN:
default:
- param = baud_rate[IIC_FAST].param;
+ param = sc->baud_rate[IIC_FAST].param;
break;
}
mtx_lock(&sc->mutex);
- TWSI_WRITE(sc, TWSI_SOFT_RESET, 0x0);
+ TWSI_WRITE(sc, sc->reg_soft_reset, 0x0);
DELAY(2000);
- TWSI_WRITE(sc, TWSI_BAUD_RATE, param);
- TWSI_WRITE(sc, TWSI_CONTROL, TWSI_CONTROL_TWSIEN | TWSI_CONTROL_ACK);
+ TWSI_WRITE(sc, sc->reg_baud_rate, param);
+ TWSI_WRITE(sc, sc->reg_control, TWSI_CONTROL_TWSIEN | TWSI_CONTROL_ACK);
DELAY(1000);
mtx_unlock(&sc->mutex);
return (0);
}
+static int
+twsi_stop(device_t dev)
+{
+ struct 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);
+}
+
/*
* timeout is given in us
*/
static int
-mv_twsi_repeated_start(device_t dev, u_char slave, int timeout)
+twsi_repeated_start(device_t dev, u_char slave, int timeout)
{
- struct mv_twsi_softc *sc;
+ struct twsi_softc *sc;
int rv;
sc = device_get_softc(dev);
@@ -516,7 +292,7 @@
mtx_unlock(&sc->mutex);
if (rv) {
- mv_twsi_stop(dev);
+ twsi_stop(dev);
return (rv);
} else
return (IIC_NOERR);
@@ -526,9 +302,9 @@
* timeout is given in us
*/
static int
-mv_twsi_start(device_t dev, u_char slave, int timeout)
+twsi_start(device_t dev, u_char slave, int timeout)
{
- struct mv_twsi_softc *sc;
+ struct twsi_softc *sc;
int rv;
sc = device_get_softc(dev);
@@ -538,32 +314,16 @@
mtx_unlock(&sc->mutex);
if (rv) {
- mv_twsi_stop(dev);
+ 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)
+twsi_read(device_t dev, char *buf, int len, int *read, int last, int delay)
{
- struct mv_twsi_softc *sc;
+ struct twsi_softc *sc;
uint32_t status;
int last_byte, rv;
@@ -591,7 +351,7 @@
goto out;
}
- status = TWSI_READ(sc, TWSI_STATUS);
+ status = TWSI_READ(sc, sc->reg_status);
if (status != (last_byte ?
TWSI_STATUS_DATA_RD_NOACK : TWSI_STATUS_DATA_RD_ACK)) {
debugf("wrong status (%02x) while reading\n", status);
@@ -599,7 +359,7 @@
goto out;
}
- *buf++ = TWSI_READ(sc, TWSI_DATA);
+ *buf++ = TWSI_READ(sc, sc->reg_data);
(*read)++;
}
rv = IIC_NOERR;
@@ -609,9 +369,9 @@
}
static int
-mv_twsi_write(device_t dev, const char *buf, int len, int *sent, int timeout)
+twsi_write(device_t dev, const char *buf, int len, int *sent, int timeout)
{
- struct mv_twsi_softc *sc;
+ struct twsi_softc *sc;
uint32_t status;
int rv;
@@ -620,7 +380,7 @@
mtx_lock(&sc->mutex);
*sent = 0;
while (*sent < len) {
- TWSI_WRITE(sc, TWSI_DATA, *buf++);
+ TWSI_WRITE(sc, sc->reg_data, *buf++);
twsi_clear_iflg(sc);
if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) {
@@ -629,7 +389,7 @@
goto out;
}
- status = TWSI_READ(sc, TWSI_STATUS);
+ status = TWSI_READ(sc, sc->reg_status);
if (status != TWSI_STATUS_DATA_WR_ACK) {
debugf("wrong status (%02x) while writing\n", status);
rv = IIC_ESTATUS;
@@ -642,3 +402,81 @@
mtx_unlock(&sc->mutex);
return (rv);
}
+
+int
+twsi_attach(device_t dev)
+{
+ struct twsi_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+
+ mtx_init(&sc->mutex, device_get_nameunit(dev), "twsi", MTX_DEF);
+
+ if (bus_alloc_resources(dev, res_spec, sc->res)) {
+ device_printf(dev, "could not allocate resources\n");
+ twsi_detach(dev);
+ return (ENXIO);
+ }
+
+ /* Attach the iicbus. */
+ if ((sc->iicbus = device_add_child(dev, "iicbus", -1)) == NULL) {
+ device_printf(dev, "could not allocate iicbus instance\n");
+ mtx_destroy(&sc->mutex);
+ return (ENXIO);
+ }
+ bus_generic_attach(dev);
+
+ return (0);
+}
+
+int
+twsi_detach(device_t dev)
+{
+ struct 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);
+}
+
+static device_method_t twsi_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_detach, twsi_detach),
+
+ /* Bus interface */
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+ DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
+ DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource),
+ DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
+ DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
+
+ /* iicbus interface */
+ DEVMETHOD(iicbus_callback, iicbus_null_callback),
+ DEVMETHOD(iicbus_repeated_start, twsi_repeated_start),
+ DEVMETHOD(iicbus_start, twsi_start),
+ DEVMETHOD(iicbus_stop, twsi_stop),
+ DEVMETHOD(iicbus_write, twsi_write),
+ DEVMETHOD(iicbus_read, twsi_read),
+ DEVMETHOD(iicbus_reset, twsi_reset),
+ DEVMETHOD(iicbus_transfer, iicbus_transfer_gen),
+ { 0, 0 }
+};
+
+DEFINE_CLASS_0(twsi, twsi_driver, twsi_methods,
+ sizeof(struct twsi_softc));

File Metadata

Mime Type
text/plain
Expires
Mon, Oct 27, 5:27 PM (7 h, 22 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24266198
Default Alt Text
D4846.id13315.diff (32 KB)

Event Timeline