summaryrefslogtreecommitdiffstats
path: root/sys/arm
diff options
context:
space:
mode:
authorloos <loos@FreeBSD.org>2014-01-23 12:32:30 +0000
committerloos <loos@FreeBSD.org>2014-01-23 12:32:30 +0000
commit49a10991a21d43b461cc6ca3357c283fd6f3dd45 (patch)
tree9a4d0a28834b0220ed5a72eb1933d25f0fb482f1 /sys/arm
parentf516feec90c64635dd3f7e4c6ec41123eaa41651 (diff)
downloadFreeBSD-src-49a10991a21d43b461cc6ca3357c283fd6f3dd45.zip
FreeBSD-src-49a10991a21d43b461cc6ca3357c283fd6f3dd45.tar.gz
MFC r256959:
Add the Raspberry Pi BSC (I2C compliant) controller driver. Reviewed by: rpaulo MFC r256961: Enable the build of OFW I2C bus for FDT systems. MFC r258045: As all the IIC controllers on system uses the same 'iichb' prefix we cannot rely only on checking the device unit to indentify the BSC unit we are attaching to. Make use of the device base address to identify our BSC unit. MFC r259127: Bring the RPi I2C driver in line with ti_i2c. Make it treat any slave address as a 7-bit address. Approved by: adrian (mentor)
Diffstat (limited to 'sys/arm')
-rw-r--r--sys/arm/broadcom/bcm2835/bcm2835_bsc.c490
-rw-r--r--sys/arm/broadcom/bcm2835/bcm2835_bscreg.h61
-rw-r--r--sys/arm/broadcom/bcm2835/bcm2835_bscvar.h69
-rw-r--r--sys/arm/broadcom/bcm2835/files.bcm28351
-rw-r--r--sys/arm/conf/RPI-B5
5 files changed, 626 insertions, 0 deletions
diff --git a/sys/arm/broadcom/bcm2835/bcm2835_bsc.c b/sys/arm/broadcom/bcm2835/bcm2835_bsc.c
new file mode 100644
index 0000000..9ee97b7
--- /dev/null
+++ b/sys/arm/broadcom/bcm2835/bcm2835_bsc.c
@@ -0,0 +1,490 @@
+/*-
+ * Copyright (c) 2001 Tsubai Masanari.
+ * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
+ * Copyright (c) 2013 Luiz Otavio O Souza <loos@freebsd.org>
+ * 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 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 THE 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/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/bus.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+
+#include <dev/iicbus/iicbus.h>
+#include <dev/iicbus/iiconf.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/broadcom/bcm2835/bcm2835_gpio.h>
+#include <arm/broadcom/bcm2835/bcm2835_bscreg.h>
+#include <arm/broadcom/bcm2835/bcm2835_bscvar.h>
+
+#include "iicbus_if.h"
+
+static void bcm_bsc_intr(void *);
+
+static void
+bcm_bsc_modifyreg(struct bcm_bsc_softc *sc, uint32_t off, uint32_t mask,
+ uint32_t value)
+{
+ uint32_t reg;
+
+ mtx_assert(&sc->sc_mtx, MA_OWNED);
+ reg = BCM_BSC_READ(sc, off);
+ reg &= ~mask;
+ reg |= value;
+ BCM_BSC_WRITE(sc, off, reg);
+}
+
+static int
+bcm_bsc_clock_proc(SYSCTL_HANDLER_ARGS)
+{
+ struct bcm_bsc_softc *sc;
+ uint32_t clk;
+ int error;
+
+ sc = (struct bcm_bsc_softc *)arg1;
+
+ BCM_BSC_LOCK(sc);
+ clk = BCM_BSC_READ(sc, BCM_BSC_CLOCK);
+ BCM_BSC_UNLOCK(sc);
+ clk &= 0xffff;
+ if (clk == 0)
+ clk = 32768;
+ clk = BCM_BSC_CORE_CLK / clk;
+ error = sysctl_handle_int(oidp, &clk, sizeof(clk), req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+
+ clk = BCM_BSC_CORE_CLK / clk;
+ if (clk % 2)
+ clk--;
+ if (clk > 0xffff)
+ clk = 0xffff;
+ BCM_BSC_LOCK(sc);
+ BCM_BSC_WRITE(sc, BCM_BSC_CLOCK, clk);
+ BCM_BSC_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+bcm_bsc_clkt_proc(SYSCTL_HANDLER_ARGS)
+{
+ struct bcm_bsc_softc *sc;
+ uint32_t clkt;
+ int error;
+
+ sc = (struct bcm_bsc_softc *)arg1;
+
+ BCM_BSC_LOCK(sc);
+ clkt = BCM_BSC_READ(sc, BCM_BSC_CLKT);
+ BCM_BSC_UNLOCK(sc);
+ clkt &= 0xffff;
+ error = sysctl_handle_int(oidp, &clkt, sizeof(clkt), req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+
+ BCM_BSC_LOCK(sc);
+ BCM_BSC_WRITE(sc, BCM_BSC_CLKT, clkt & 0xffff);
+ BCM_BSC_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+bcm_bsc_fall_proc(SYSCTL_HANDLER_ARGS)
+{
+ struct bcm_bsc_softc *sc;
+ uint32_t clk, reg;
+ int error;
+
+ sc = (struct bcm_bsc_softc *)arg1;
+
+ BCM_BSC_LOCK(sc);
+ reg = BCM_BSC_READ(sc, BCM_BSC_DELAY);
+ BCM_BSC_UNLOCK(sc);
+ reg >>= 16;
+ error = sysctl_handle_int(oidp, &reg, sizeof(reg), req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+
+ BCM_BSC_LOCK(sc);
+ clk = BCM_BSC_READ(sc, BCM_BSC_CLOCK);
+ clk = BCM_BSC_CORE_CLK / clk;
+ if (reg > clk / 2)
+ reg = clk / 2 - 1;
+ bcm_bsc_modifyreg(sc, BCM_BSC_DELAY, 0xffff0000, reg << 16);
+ BCM_BSC_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+bcm_bsc_rise_proc(SYSCTL_HANDLER_ARGS)
+{
+ struct bcm_bsc_softc *sc;
+ uint32_t clk, reg;
+ int error;
+
+ sc = (struct bcm_bsc_softc *)arg1;
+
+ BCM_BSC_LOCK(sc);
+ reg = BCM_BSC_READ(sc, BCM_BSC_DELAY);
+ BCM_BSC_UNLOCK(sc);
+ reg &= 0xffff;
+ error = sysctl_handle_int(oidp, &reg, sizeof(reg), req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+
+ BCM_BSC_LOCK(sc);
+ clk = BCM_BSC_READ(sc, BCM_BSC_CLOCK);
+ clk = BCM_BSC_CORE_CLK / clk;
+ if (reg > clk / 2)
+ reg = clk / 2 - 1;
+ bcm_bsc_modifyreg(sc, BCM_BSC_DELAY, 0xffff, reg);
+ BCM_BSC_UNLOCK(sc);
+
+ return (0);
+}
+
+static void
+bcm_bsc_sysctl_init(struct bcm_bsc_softc *sc)
+{
+ struct sysctl_ctx_list *ctx;
+ struct sysctl_oid *tree_node;
+ struct sysctl_oid_list *tree;
+
+ /*
+ * Add system sysctl tree/handlers.
+ */
+ ctx = device_get_sysctl_ctx(sc->sc_dev);
+ tree_node = device_get_sysctl_tree(sc->sc_dev);
+ tree = SYSCTL_CHILDREN(tree_node);
+ SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "clock",
+ CTLFLAG_RW | CTLTYPE_UINT, sc, sizeof(*sc),
+ bcm_bsc_clock_proc, "IU", "I2C BUS clock frequency");
+ SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "clock_stretch",
+ CTLFLAG_RW | CTLTYPE_UINT, sc, sizeof(*sc),
+ bcm_bsc_clkt_proc, "IU", "I2C BUS clock stretch timeout");
+ SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "fall_edge_delay",
+ CTLFLAG_RW | CTLTYPE_UINT, sc, sizeof(*sc),
+ bcm_bsc_fall_proc, "IU", "I2C BUS falling edge delay");
+ SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "rise_edge_delay",
+ CTLFLAG_RW | CTLTYPE_UINT, sc, sizeof(*sc),
+ bcm_bsc_rise_proc, "IU", "I2C BUS rising edge delay");
+}
+
+static void
+bcm_bsc_reset(struct bcm_bsc_softc *sc)
+{
+
+ /* Clear pending interrupts. */
+ BCM_BSC_WRITE(sc, BCM_BSC_STATUS, BCM_BSC_STATUS_CLKT |
+ BCM_BSC_STATUS_ERR | BCM_BSC_STATUS_DONE);
+ /* Clear the FIFO. */
+ bcm_bsc_modifyreg(sc, BCM_BSC_CTRL, BCM_BSC_CTRL_CLEAR0,
+ BCM_BSC_CTRL_CLEAR0);
+}
+
+static int
+bcm_bsc_probe(device_t dev)
+{
+
+ if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-bsc"))
+ return (ENXIO);
+
+ device_set_desc(dev, "BCM2708/2835 BSC controller");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+bcm_bsc_attach(device_t dev)
+{
+ struct bcm_bsc_softc *sc;
+ unsigned long start;
+ device_t gpio;
+ int i, rid;
+
+ sc = device_get_softc(dev);
+ sc->sc_dev = dev;
+
+ rid = 0;
+ sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (!sc->sc_mem_res) {
+ device_printf(dev, "cannot allocate memory window\n");
+ return (ENXIO);
+ }
+
+ sc->sc_bst = rman_get_bustag(sc->sc_mem_res);
+ sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res);
+
+ /* Check the unit we are attaching by its base address. */
+ start = rman_get_start(sc->sc_mem_res);
+ for (i = 0; i < nitems(bcm_bsc_pins); i++) {
+ if (bcm_bsc_pins[i].start == start)
+ break;
+ }
+ if (i == nitems(bcm_bsc_pins)) {
+ device_printf(dev, "only bsc0 and bsc1 are supported\n");
+ return (ENXIO);
+ }
+
+ /*
+ * Configure the GPIO pins to ALT0 function to enable BSC control
+ * over the pins.
+ */
+ gpio = devclass_get_device(devclass_find("gpio"), 0);
+ if (!gpio) {
+ device_printf(dev, "cannot find gpio0\n");
+ return (ENXIO);
+ }
+ bcm_gpio_set_alternate(gpio, bcm_bsc_pins[i].sda, BCM_GPIO_ALT0);
+ bcm_gpio_set_alternate(gpio, bcm_bsc_pins[i].scl, BCM_GPIO_ALT0);
+
+ rid = 0;
+ sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_ACTIVE | RF_SHAREABLE);
+ if (!sc->sc_irq_res) {
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
+ device_printf(dev, "cannot allocate interrupt\n");
+ return (ENXIO);
+ }
+
+ /* Hook up our interrupt handler. */
+ if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+ NULL, bcm_bsc_intr, sc, &sc->sc_intrhand)) {
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
+ device_printf(dev, "cannot setup the interrupt handler\n");
+ return (ENXIO);
+ }
+
+ mtx_init(&sc->sc_mtx, "bcm_bsc", NULL, MTX_DEF);
+
+ bcm_bsc_sysctl_init(sc);
+
+ /* Enable the BSC controller. Flush the FIFO. */
+ BCM_BSC_LOCK(sc);
+ BCM_BSC_WRITE(sc, BCM_BSC_CTRL, BCM_BSC_CTRL_I2CEN);
+ bcm_bsc_reset(sc);
+ BCM_BSC_UNLOCK(sc);
+
+ device_add_child(dev, "iicbus", -1);
+
+ return (bus_generic_attach(dev));
+}
+
+static int
+bcm_bsc_detach(device_t dev)
+{
+ struct bcm_bsc_softc *sc;
+
+ bus_generic_detach(dev);
+
+ sc = device_get_softc(dev);
+ mtx_destroy(&sc->sc_mtx);
+ if (sc->sc_intrhand)
+ bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand);
+ if (sc->sc_irq_res)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
+ if (sc->sc_mem_res)
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
+
+ return (0);
+}
+
+static void
+bcm_bsc_intr(void *arg)
+{
+ struct bcm_bsc_softc *sc;
+ uint32_t status;
+
+ sc = (struct bcm_bsc_softc *)arg;
+
+ BCM_BSC_LOCK(sc);
+
+ /* The I2C interrupt is shared among all the BSC controllers. */
+ if ((sc->sc_flags & BCM_I2C_BUSY) == 0) {
+ BCM_BSC_UNLOCK(sc);
+ return;
+ }
+
+ status = BCM_BSC_READ(sc, BCM_BSC_STATUS);
+
+ /* Check for errors. */
+ if (status & (BCM_BSC_STATUS_CLKT | BCM_BSC_STATUS_ERR)) {
+ /* Disable interrupts. */
+ BCM_BSC_WRITE(sc, BCM_BSC_CTRL, BCM_BSC_CTRL_I2CEN);
+ sc->sc_flags |= BCM_I2C_ERROR;
+ bcm_bsc_reset(sc);
+ wakeup(sc->sc_dev);
+ BCM_BSC_UNLOCK(sc);
+ return;
+ }
+
+ if (sc->sc_flags & BCM_I2C_READ) {
+ while (sc->sc_resid > 0 && (status & BCM_BSC_STATUS_RXD)) {
+ *sc->sc_data++ = BCM_BSC_READ(sc, BCM_BSC_DATA);
+ sc->sc_resid--;
+ status = BCM_BSC_READ(sc, BCM_BSC_STATUS);
+ }
+ } else {
+ while (sc->sc_resid > 0 && (status & BCM_BSC_STATUS_TXD)) {
+ BCM_BSC_WRITE(sc, BCM_BSC_DATA, *sc->sc_data++);
+ sc->sc_resid--;
+ status = BCM_BSC_READ(sc, BCM_BSC_STATUS);
+ }
+ }
+
+ if (status & BCM_BSC_STATUS_DONE) {
+ /* Disable interrupts. */
+ BCM_BSC_WRITE(sc, BCM_BSC_CTRL, BCM_BSC_CTRL_I2CEN);
+ bcm_bsc_reset(sc);
+ wakeup(sc->sc_dev);
+ }
+
+ BCM_BSC_UNLOCK(sc);
+}
+
+static int
+bcm_bsc_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
+{
+ struct bcm_bsc_softc *sc;
+ uint32_t intr, read, status;
+ int i, err;
+
+ sc = device_get_softc(dev);
+ BCM_BSC_LOCK(sc);
+
+ /* If the controller is busy wait until it is available. */
+ while (sc->sc_flags & BCM_I2C_BUSY)
+ mtx_sleep(dev, &sc->sc_mtx, 0, "bcm_bsc", 0);
+
+ /* Now we have control over the BSC controller. */
+ sc->sc_flags = BCM_I2C_BUSY;
+
+ /* Clear the FIFO and the pending interrupts. */
+ bcm_bsc_reset(sc);
+
+ err = 0;
+ for (i = 0; i < nmsgs; i++) {
+
+ /* Write the slave address. */
+ BCM_BSC_WRITE(sc, BCM_BSC_SLAVE, msgs[i].slave);
+
+ /* Write the data length. */
+ BCM_BSC_WRITE(sc, BCM_BSC_DLEN, msgs[i].len);
+
+ sc->sc_data = msgs[i].buf;
+ sc->sc_resid = msgs[i].len;
+ if ((msgs[i].flags & IIC_M_RD) == 0) {
+ /* Fill up the TX FIFO. */
+ status = BCM_BSC_READ(sc, BCM_BSC_STATUS);
+ while (sc->sc_resid > 0 &&
+ (status & BCM_BSC_STATUS_TXD)) {
+ BCM_BSC_WRITE(sc, BCM_BSC_DATA, *sc->sc_data);
+ sc->sc_data++;
+ sc->sc_resid--;
+ status = BCM_BSC_READ(sc, BCM_BSC_STATUS);
+ }
+ read = 0;
+ intr = BCM_BSC_CTRL_INTT;
+ sc->sc_flags &= ~BCM_I2C_READ;
+ } else {
+ sc->sc_flags |= BCM_I2C_READ;
+ read = BCM_BSC_CTRL_READ;
+ intr = BCM_BSC_CTRL_INTR;
+ }
+ intr |= BCM_BSC_CTRL_INTD;
+
+ /* Start the transfer. */
+ BCM_BSC_WRITE(sc, BCM_BSC_CTRL, BCM_BSC_CTRL_I2CEN |
+ BCM_BSC_CTRL_ST | read | intr);
+
+ /* Wait for the transaction to complete. */
+ err = mtx_sleep(dev, &sc->sc_mtx, 0, "bcm_bsc", hz);
+
+ /* Check if we have a timeout or an I2C error. */
+ if ((sc->sc_flags & BCM_I2C_ERROR) || err == EWOULDBLOCK) {
+ device_printf(sc->sc_dev, "I2C error\n");
+ err = EIO;
+ break;
+ }
+ }
+
+ /* Clean the controller flags. */
+ sc->sc_flags = 0;
+
+ BCM_BSC_UNLOCK(sc);
+
+ return (err);
+}
+
+static phandle_t
+bcm_bsc_get_node(device_t bus, device_t dev)
+{
+
+ /* We only have one child, the I2C bus, which needs our own node. */
+ return (ofw_bus_get_node(bus));
+}
+
+static device_method_t bcm_bsc_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, bcm_bsc_probe),
+ DEVMETHOD(device_attach, bcm_bsc_attach),
+ DEVMETHOD(device_detach, bcm_bsc_detach),
+
+ /* iicbus interface */
+ DEVMETHOD(iicbus_callback, iicbus_null_callback),
+ DEVMETHOD(iicbus_transfer, bcm_bsc_transfer),
+
+ /* ofw_bus interface */
+ DEVMETHOD(ofw_bus_get_node, bcm_bsc_get_node),
+
+ DEVMETHOD_END
+};
+
+static devclass_t bcm_bsc_devclass;
+
+static driver_t bcm_bsc_driver = {
+ "iichb",
+ bcm_bsc_methods,
+ sizeof(struct bcm_bsc_softc),
+};
+
+DRIVER_MODULE(iicbus, bcm2835_bsc, iicbus_driver, iicbus_devclass, 0, 0);
+DRIVER_MODULE(bcm2835_bsc, simplebus, bcm_bsc_driver, bcm_bsc_devclass, 0, 0);
diff --git a/sys/arm/broadcom/bcm2835/bcm2835_bscreg.h b/sys/arm/broadcom/bcm2835/bcm2835_bscreg.h
new file mode 100644
index 0000000..d48ce37
--- /dev/null
+++ b/sys/arm/broadcom/bcm2835/bcm2835_bscreg.h
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
+ * Copyright (c) 2013 Luiz Otavio O Souza <loos@freebsd.org>
+ * 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 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 THE 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _BCM2835_BSCREG_H_
+#define _BCM2835_BSCREG_H_
+
+#define BCM_BSC_CORE_CLK 150000000U
+#define BCM_BSC_CTRL 0x00
+#define BCM_BSC_CTRL_I2CEN (1 << 15)
+#define BCM_BSC_CTRL_INTR (1 << 10)
+#define BCM_BSC_CTRL_INTT (1 << 9)
+#define BCM_BSC_CTRL_INTD (1 << 8)
+#define BCM_BSC_CTRL_ST (1 << 7)
+#define BCM_BSC_CTRL_CLEAR1 (1 << 5)
+#define BCM_BSC_CTRL_CLEAR0 (1 << 4)
+#define BCM_BSC_CTRL_READ (1 << 0)
+#define BCM_BSC_STATUS 0x04
+#define BCM_BSC_STATUS_CLKT (1 << 9)
+#define BCM_BSC_STATUS_ERR (1 << 8)
+#define BCM_BSC_STATUS_RXF (1 << 7)
+#define BCM_BSC_STATUS_TXE (1 << 6)
+#define BCM_BSC_STATUS_RXD (1 << 5)
+#define BCM_BSC_STATUS_TXD (1 << 4)
+#define BCM_BSC_STATUS_RXR (1 << 3)
+#define BCM_BSC_STATUS_TXW (1 << 2)
+#define BCM_BSC_STATUS_DONE (1 << 1)
+#define BCM_BSC_STATUS_TA (1 << 0)
+#define BCM_BSC_DLEN 0x08
+#define BCM_BSC_SLAVE 0x0c
+#define BCM_BSC_DATA 0x10
+#define BCM_BSC_CLOCK 0x14
+#define BCM_BSC_DELAY 0x18
+#define BCM_BSC_CLKT 0x1c
+
+#endif /* _BCM2835_BSCREG_H_ */
diff --git a/sys/arm/broadcom/bcm2835/bcm2835_bscvar.h b/sys/arm/broadcom/bcm2835/bcm2835_bscvar.h
new file mode 100644
index 0000000..3fef35b
--- /dev/null
+++ b/sys/arm/broadcom/bcm2835/bcm2835_bscvar.h
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
+ * Copyright (c) 2013 Luiz Otavio O Souza <loos@freebsd.org>
+ * 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 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 THE 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _BCM2835_BSCVAR_H
+#define _BCM2835_BSCVAR_H
+
+struct {
+ uint32_t sda;
+ uint32_t scl;
+ unsigned long start;
+} bcm_bsc_pins[] = {
+ { 0, 1, 0x20205000 }, /* BSC0 GPIO pins and base address. */
+ { 2, 3, 0x20804000 } /* BSC1 GPIO pins and base address. */
+};
+
+struct bcm_bsc_softc {
+ device_t sc_dev;
+ struct mtx sc_mtx;
+ struct resource * sc_mem_res;
+ struct resource * sc_irq_res;
+ bus_space_tag_t sc_bst;
+ bus_space_handle_t sc_bsh;
+ uint16_t sc_resid;
+ uint8_t *sc_data;
+ uint8_t sc_flags;
+ void * sc_intrhand;
+};
+
+#define BCM_I2C_BUSY 0x01
+#define BCM_I2C_READ 0x02
+#define BCM_I2C_ERROR 0x04
+
+#define BCM_BSC_WRITE(_sc, _off, _val) \
+ bus_space_write_4(_sc->sc_bst, _sc->sc_bsh, _off, _val)
+#define BCM_BSC_READ(_sc, _off) \
+ bus_space_read_4(_sc->sc_bst, _sc->sc_bsh, _off)
+
+#define BCM_BSC_LOCK(_sc) \
+ mtx_lock(&(_sc)->sc_mtx)
+#define BCM_BSC_UNLOCK(_sc) \
+ mtx_unlock(&(_sc)->sc_mtx)
+
+#endif /* _BCM2835_BSCVAR_H_ */
diff --git a/sys/arm/broadcom/bcm2835/files.bcm2835 b/sys/arm/broadcom/bcm2835/files.bcm2835
index 49d8108..a784c2b 100644
--- a/sys/arm/broadcom/bcm2835/files.bcm2835
+++ b/sys/arm/broadcom/bcm2835/files.bcm2835
@@ -1,5 +1,6 @@
# $FreeBSD$
+arm/broadcom/bcm2835/bcm2835_bsc.c optional bcm2835_bsc
arm/broadcom/bcm2835/bcm2835_dma.c standard
arm/broadcom/bcm2835/bcm2835_fb.c optional sc
arm/broadcom/bcm2835/bcm2835_gpio.c optional gpio
diff --git a/sys/arm/conf/RPI-B b/sys/arm/conf/RPI-B
index f783fed..f0498ea 100644
--- a/sys/arm/conf/RPI-B
+++ b/sys/arm/conf/RPI-B
@@ -79,6 +79,11 @@ device mmcsd
device gpio
device gpioled
+# I2C
+device iic
+device iicbus
+device bcm2835_bsc
+
options KDB
options DDB #Enable the kernel debugger
options INVARIANTS #Enable calls of extra sanity checking
OpenPOWER on IntegriCloud