Page MenuHomeFreeBSD

D12736.id.diff
No OneTemporary

D12736.id.diff

Index: sys/mips/mediatek/files.mediatek
===================================================================
--- sys/mips/mediatek/files.mediatek
+++ sys/mips/mediatek/files.mediatek
@@ -22,6 +22,7 @@
mips/mediatek/mtk_gpio_v1.c optional gpio mtk_gpio_v1
mips/mediatek/mtk_gpio_v2.c optional gpio mtk_gpio_v2
#mips/mediatek/mtk_mmc.c optional mmc
+mips/mediatek/mtk_iic.c optional iic mtk_iic
# Ralink/Mediatek Ethernet driver
dev/rt/if_rt.c optional rt
Index: sys/mips/mediatek/mtk_iic.h
===================================================================
--- /dev/null
+++ sys/mips/mediatek/mtk_iic.h
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 2017 Hiroki Mori
+ * 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 unmodified, 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 _MTK_I2C_NEWVAR_H_
+#define _MTK_I2C_NEWVAR_H_
+
+/* Helpers from NetBSD */
+/* __BIT(n): nth bit, where __BIT(0) == 0x1. */
+#define __BIT(__n) \
+ (((__n) >= NBBY * sizeof(uintmax_t)) ? 0 : ((uintmax_t)1 << (__n)))
+
+/*
+ * I2C controller interface
+ * Copy from netbsd code
+ */
+
+#define RA_I2C_CONFIG 0x00
+#define RA_I2C_CLKDIV 0x04
+#define RA_I2C_DEVADDR 0x08
+#define RA_I2C_ADDR 0x0C
+#define RA_I2C_DATAOUT 0x10
+#define RA_I2C_DATAIN 0x14
+#define RA_I2C_STATUS 0x18
+#define RA_I2C_STARTXFR 0x1C
+#define RA_I2C_BYTECNT 0x20
+#define I2C_CONFIG_ADDRLEN(x) (((x) & 0x7) << 5)
+#define I2C_CONFIG_ADDRLEN_7 6
+#define I2C_CONFIG_ADDRLEN_8 7
+#define I2C_CONFIG_DEVADLEN(x) (((x) & 0x7) << 2)
+#define I2C_CONFIG_DEVADLEN_6 5
+#define I2C_CONFIG_DEVADLEN_7 6
+#define I2C_CONFIG_ADDRDIS __BIT(1)
+#define I2C_CONFIG_DEVDIS __BIT(0)
+#define I2C_STATUS_STARTERR __BIT(4)
+#define I2C_STATUS_ACKERR __BIT(3)
+#define I2C_STATUS_DATARDY __BIT(2)
+#define I2C_STATUS_SDOEMPTY __BIT(1)
+#define I2C_STATUS_BUSY __BIT(0)
+
+#define I2C_OP_READ 1
+#define I2C_OP_WRITE 0
+
+/*
+ * This is RT2880 default value. Please set clock-div property in dts file
+ * other socs.
+ */
+#define RT2880_CLKDIV_VALUE 333
+
+#define i2c_busy_loop (sc->clkdiv*30)
+#define max_ee_busy_loop (sc->clkdiv*25)
+
+#endif /* _MTK_I2C_NEWVAR_H_ */
Index: sys/mips/mediatek/mtk_iic.c
===================================================================
--- /dev/null
+++ sys/mips/mediatek/mtk_iic.c
@@ -0,0 +1,437 @@
+/*-
+ * Copyright (c) 2017 Hiroki Mori
+ * 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.
+ * 3. Neither the name of RMI Corporation, nor the names of its contributors,
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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 "opt_platform.h"
+
+/*
+ * This code do not test
+ */
+
+#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 <sys/rman.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+
+#include <dev/iicbus/iiconf.h>
+#include <dev/iicbus/iicbus.h>
+
+#include "iicbus_if.h"
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <mips/mediatek/mtk_iic.h>
+
+/*
+ * register space access macros
+ */
+
+#define MTK_IIC_LOCK(sc) mtx_lock_spin(&(sc)->mtx)
+#define MTK_IIC_UNLOCK(sc) mtx_unlock_spin(&(sc)->mtx)
+#define MTK_IIC_LOCK_INIT(sc) \
+ mtx_init(&(sc)->mtx, "mtk_iic", "mtk_iic", MTX_DEF)
+#define MTK_IIC_LOCK_DESTROY(sc) mtx_destroy(&(sc)->mtx)
+
+#define I2CREG_WRITE(sc, reg, val) do { \
+ bus_write_4(sc->sc_mem_res, (reg), (val)); \
+ } while (0)
+
+#define I2CREG_READ(sc, reg) bus_read_4(sc->sc_mem_res, (reg))
+
+/*
+ * Device methods
+ */
+static int mtk_iic_probe(device_t);
+static int mtk_iic_attach(device_t);
+static int mtk_iic_detach(device_t);
+
+static int mtk_iic_start(device_t dev, u_char slave, int timeout);
+static int mtk_iic_stop(device_t dev);
+static int mtk_iic_read(device_t dev, char *buf, int len, int *read, int last, int delay);
+static int mtk_iic_write(device_t dev, const char *buf, int len, int *sent, int timeout);
+static int mtk_iic_transfer(device_t bus, struct iic_msg *msgs, uint32_t nmsgs);
+#ifdef notyet
+static int mtk_iic_repeated_start(device_t dev, u_char slave, int timeout);
+#endif
+
+static struct ofw_compat_data compat_data[] = {
+ { "ralink,rt2880-i2c", 1 },
+ { "ralink,rt3050-i2c", 1 },
+ { NULL, 0 }
+};
+
+struct mtk_iic_softc {
+ device_t dev;
+ struct resource *sc_mem_res;
+ device_t iicbus;
+ unsigned int clkdiv;
+ int sc_started;
+ uint8_t i2cdev_addr;
+ struct mtx mtx;
+ int last_slave;
+};
+
+static int
+mtk_iic_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+ return(ENXIO);
+
+ device_set_desc(dev, "MTK I2C Controller");
+
+ return (0);
+}
+
+static int
+mtk_iic_attach(device_t dev)
+{
+ int rid;
+ struct mtk_iic_softc *sc;
+ phandle_t node;
+
+ sc = device_get_softc(dev);
+
+ MTK_IIC_LOCK_INIT(sc);
+
+ node = ofw_bus_get_node(dev);
+ 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 == NULL) {
+ device_printf(dev, "Could not map memory\n");
+ return (ENXIO);
+ }
+
+ if (OF_getencprop(node, "clock-div", &sc->clkdiv,
+ sizeof(sc->clkdiv)) <= 0) {
+ sc->clkdiv = RT2880_CLKDIV_VALUE;
+ }
+
+ I2CREG_WRITE(sc, RA_I2C_CLKDIV, sc->clkdiv);
+
+ sc->iicbus = device_add_child(dev, "iicbus", -1);
+ if (sc->iicbus == NULL) {
+ device_printf(dev, "cannot add iicbus child device\n");
+ return (ENXIO);
+ }
+
+ sc->sc_started = 0;
+ sc->last_slave = -1;
+
+ return (bus_generic_attach(dev));
+}
+
+static int
+mtk_iic_detach(device_t dev)
+{
+ struct mtk_iic_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
+
+ if (sc->sc_mem_res)
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
+
+ MTK_IIC_LOCK_DESTROY(sc);
+ if (sc->iicbus &&
+ (error = device_delete_child(dev, sc->iicbus)) != 0)
+ return error;
+
+ return (0);
+}
+
+static int
+mtk_iic_start(device_t dev, u_char slave, int timeout)
+{
+ int error;
+ struct mtk_iic_softc *sc;
+ uint32_t r;
+ int i;
+
+ sc = device_get_softc(dev);
+
+ if (sc->sc_started == 1)
+ return (IIC_EBUSERR);
+
+ MTK_IIC_LOCK(sc);
+ error = IIC_NOERR;
+ sc->i2cdev_addr = (slave >> 1);
+
+ /* This is work around for Ralink I2C device.
+ * Ralink I2C device can't send one byte. Most smoll is two byte.
+ * Then We send only first time dummy write
+ */
+
+ if (sc->last_slave != sc->i2cdev_addr) {
+ r = I2C_CONFIG_ADDRLEN(I2C_CONFIG_ADDRLEN_8) |
+ I2C_CONFIG_DEVADLEN(I2C_CONFIG_DEVADLEN_7) |
+ I2C_CONFIG_ADDRDIS;
+ I2CREG_WRITE(sc, RA_I2C_CONFIG, r);
+
+ /* dmmy write */
+ I2CREG_WRITE(sc, RA_I2C_DEVADDR, sc->i2cdev_addr);
+ I2CREG_WRITE(sc, RA_I2C_BYTECNT, 0);
+ I2CREG_WRITE(sc, RA_I2C_DATAOUT, slave);
+ I2CREG_WRITE(sc, RA_I2C_STARTXFR, I2C_OP_WRITE);
+
+ for (i = 0; i < max_ee_busy_loop; i++) {
+ r = I2CREG_READ(sc, RA_I2C_STATUS);
+ if (r & I2C_STATUS_ACKERR) {
+ error = IIC_ENOACK;
+ }
+ if ((r & I2C_STATUS_BUSY) == 0) {
+ break;
+ }
+ }
+ if (i == max_ee_busy_loop) {
+ error = IIC_EBUSERR;
+ }
+ if (error == IIC_NOERR) {
+ sc->last_slave = sc->i2cdev_addr;
+ }
+ }
+
+ if (error == IIC_NOERR) {
+ sc->sc_started = 1;
+ } else {
+ MTK_IIC_UNLOCK(sc);
+ }
+
+
+ return (error);
+}
+
+static int
+mtk_iic_stop(device_t dev)
+{
+ int error;
+ struct mtk_iic_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ if (sc->sc_started) {
+ MTK_IIC_UNLOCK(sc);
+ error = IIC_NOERR;
+ sc->sc_started = 0;
+ } else {
+ error = IIC_EBUSERR;
+ }
+ return error;
+
+}
+
+static inline void
+mtk_iic_busy_wait(struct mtk_iic_softc *sc)
+{
+ int i;
+ uint32_t r;
+
+ for (i = 0; i < i2c_busy_loop; ++i) {
+ r = I2CREG_READ(sc, RA_I2C_STATUS);
+ if ((r & I2C_STATUS_BUSY) == 0)
+ break;
+ }
+}
+
+static int
+mtk_iic_read(device_t dev, char *buf, int len, int *read, int last,
+ int delay)
+{
+ struct mtk_iic_softc *sc;
+ int i, j;
+ uint32_t r;
+
+ sc = device_get_softc(dev);
+
+ mtk_iic_busy_wait(sc);
+
+ I2CREG_WRITE(sc, RA_I2C_DEVADDR, sc->i2cdev_addr);
+ I2CREG_WRITE(sc, RA_I2C_BYTECNT, len - 1);
+ I2CREG_WRITE(sc, RA_I2C_STARTXFR, I2C_OP_READ);
+
+ for (i = 0; i < len; i++) {
+ for (j=0; j < max_ee_busy_loop; j++) {
+ r = I2CREG_READ(sc, RA_I2C_STATUS);
+ if((r & I2C_STATUS_DATARDY) != 0) {
+ buf[i] = I2CREG_READ(sc, RA_I2C_DATAIN);
+ break;
+ }
+ }
+ if (j == max_ee_busy_loop) {
+ return (IIC_ENOACK);
+ }
+ }
+
+ *read = i;
+
+ mtk_iic_busy_wait(sc);
+ return (IIC_NOERR);
+
+}
+
+static int
+mtk_iic_write(device_t dev, const char *buf, int len, int *sent,
+ int timeout /* us */ )
+{
+ struct mtk_iic_softc *sc;
+ int i, j;
+ uint32_t r;
+ int loopcount;
+
+ sc = device_get_softc(dev);
+
+ mtk_iic_busy_wait(sc);
+
+ I2CREG_WRITE(sc, RA_I2C_DEVADDR, sc->i2cdev_addr);
+ I2CREG_WRITE(sc, RA_I2C_BYTECNT, len - 1);
+ I2CREG_WRITE(sc, RA_I2C_DATAOUT, buf[0]);
+ I2CREG_WRITE(sc, RA_I2C_STARTXFR, I2C_OP_WRITE);
+
+ for (i = 1; i < len; i++) {
+ if (i == 1) /* first loop send 2 byte */
+ loopcount = max_ee_busy_loop * 2;
+ else
+ loopcount = max_ee_busy_loop;
+ for (j=0; j < loopcount; j++) {
+ r = I2CREG_READ(sc, RA_I2C_STATUS);
+ if ((r & I2C_STATUS_SDOEMPTY) != 0) {
+ I2CREG_WRITE(sc, RA_I2C_DATAOUT, buf[i]);
+ break;
+ }
+ }
+ if (j == max_ee_busy_loop) {
+ return (IIC_ENOACK);
+ }
+ }
+
+ *sent = i;
+
+ mtk_iic_busy_wait(sc);
+ return (IIC_NOERR);
+}
+
+#ifdef notyet
+static int
+mtk_iic_repeated_start(device_t dev, u_char slave, int timeout)
+{
+ return (IIC_NOERR);
+}
+#endif
+
+int
+mtk_iic_transfer(device_t bus, struct iic_msg *msgs, uint32_t nmsgs)
+{
+ int i, error, lenread, lenwrote;
+ u_char addr;
+
+ addr = msgs[0].slave | LSB;
+ error = mtk_iic_start(bus, addr, 0);
+ for (i = 0, error = IIC_NOERR; i < nmsgs && error == IIC_NOERR; i++) {
+ if (msgs[i].flags & IIC_M_RD) {
+ error = mtk_iic_read((bus), msgs[i].buf, msgs[i].len,
+ &lenread, IIC_LAST_READ, 0);
+ }
+ else {
+ error = mtk_iic_write((bus), msgs[i].buf, msgs[i].len,
+ &lenwrote, 0);
+ }
+ }
+ mtk_iic_stop(bus);
+ return (error);
+}
+
+static int
+mtk_iic_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
+{
+ return (IIC_NOERR);
+}
+
+static phandle_t
+mtk_iic_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 mtk_iic_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, mtk_iic_probe),
+ DEVMETHOD(device_attach, mtk_iic_attach),
+ DEVMETHOD(device_detach, mtk_iic_detach),
+
+ /* iicbus interface */
+ DEVMETHOD(iicbus_start, mtk_iic_start),
+ DEVMETHOD(iicbus_stop, mtk_iic_stop),
+ DEVMETHOD(iicbus_write, mtk_iic_write),
+ DEVMETHOD(iicbus_read, mtk_iic_read),
+ DEVMETHOD(iicbus_callback, iicbus_null_callback),
+ DEVMETHOD(iicbus_reset, mtk_iic_reset),
+ DEVMETHOD(iicbus_transfer, mtk_iic_transfer),
+#ifdef notyet
+ DEVMETHOD(iicbus_repeated_start, mtk_iic_repeated_start),
+#endif
+
+ /* ofw_bus interface */
+ DEVMETHOD(ofw_bus_get_node, mtk_iic_get_node),
+
+ DEVMETHOD_END
+};
+
+static driver_t mtk_iic_driver = {
+ "iichb",
+ mtk_iic_methods,
+ sizeof(struct mtk_iic_softc),
+};
+
+static devclass_t mtk_iic_devclass;
+
+DRIVER_MODULE(mtk_iic, simplebus, mtk_iic_driver, mtk_iic_devclass, 0, 0);
+DRIVER_MODULE(iicbus, mtk_iic, iicbus_driver, iicbus_devclass, 0, 0);
+
+MODULE_DEPEND(mtk_iic, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
+
+MODULE_VERSION(mtk_iic, 1);

File Metadata

Mime Type
text/plain
Expires
Tue, Feb 10, 3:58 PM (12 h, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28627937
Default Alt Text
D12736.id.diff (14 KB)

Event Timeline