Source-Changes-HG archive

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

[src/trunk]: src/sys Add driver for Cadence I2C controller.



details:   https://anonhg.NetBSD.org/src/rev/991b45293f7f
branches:  trunk
changeset: 372270:991b45293f7f
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Sat Nov 05 17:31:37 2022 +0000

description:
Add driver for Cadence I2C controller.

diffstat:

 sys/conf/files            |    7 +-
 sys/dev/fdt/cdnsiic_fdt.c |  103 +++++++++++++++
 sys/dev/fdt/files.fdt     |    6 +-
 sys/dev/ic/cdnsiic.c      |  297 ++++++++++++++++++++++++++++++++++++++++++++++
 sys/dev/ic/cdnsiicvar.h   |   50 +++++++
 5 files changed, 461 insertions(+), 2 deletions(-)

diffs (truncated from 503 to 300 lines):

diff -r e19dc7bf9e30 -r 991b45293f7f sys/conf/files
--- a/sys/conf/files    Sat Nov 05 17:30:06 2022 +0000
+++ b/sys/conf/files    Sat Nov 05 17:31:37 2022 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: files,v 1.1302 2022/10/28 07:16:34 skrll Exp $
+#      $NetBSD: files,v 1.1303 2022/11/05 17:31:38 jmcneill Exp $
 #      @(#)files.newconf       7.5 (Berkeley) 5/10/93
 
 version        20171118
@@ -1159,6 +1159,11 @@
 device dwiic: dwiic, i2cbus
 file   dev/ic/dwiic.c                  dwiic
 
+# Cadence I2C controller
+define cdnsiic
+device cdnsiic: i2cbus
+file   dev/ic/cdnsiic.c                cdnsiic
+
 # ACPI power management timer (hardware access, independent of ACPI)
 #
 define acpipmtimer
diff -r e19dc7bf9e30 -r 991b45293f7f sys/dev/fdt/cdnsiic_fdt.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/fdt/cdnsiic_fdt.c Sat Nov 05 17:31:37 2022 +0000
@@ -0,0 +1,103 @@
+/* $NetBSD: cdnsiic_fdt.c,v 1.1 2022/11/05 17:31:37 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2022 Jared McNeill <jmcneill%invisible.ca@localhost>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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>
+
+__KERNEL_RCSID(0, "$NetBSD: cdnsiic_fdt.c,v 1.1 2022/11/05 17:31:37 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/kmem.h>
+
+#include <dev/i2c/i2cvar.h>
+
+#include <dev/fdt/fdtvar.h>
+#include <dev/ic/cdnsiicvar.h>
+
+static const struct device_compatible_entry compat_data[] = {
+       { .compat = "cdns,i2c-r1p10" },
+       { .compat = "cdns,i2c-r1p14" },
+       DEVICE_COMPAT_EOL
+};
+
+static int
+cdnsiic_fdt_match(device_t parent, cfdata_t cf, void *aux)
+{
+       struct fdt_attach_args * const faa = aux;
+
+       return of_compatible_match(faa->faa_phandle, compat_data);
+}
+
+static void
+cdnsiic_fdt_attach(device_t parent, device_t self, void *aux)
+{
+       struct cdnsiic_softc * const sc = device_private(self);
+       struct fdt_attach_args * const faa = aux;
+       const int phandle = faa->faa_phandle;
+       bus_addr_t addr;
+       bus_size_t size;
+       int error;
+
+       if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
+               aprint_error(": couldn't get registers\n");
+               return;
+       }
+
+       sc->sc_pclk = fdtbus_clock_get_index(phandle, 0);
+       if (sc->sc_pclk == NULL || clk_enable(sc->sc_pclk) != 0) {
+               aprint_error(": couldn't enable pclk\n");
+               return;
+       }
+
+       if (of_getprop_uint32(phandle, "clock-frequency", &sc->sc_bus_freq))
+               sc->sc_bus_freq = 100000;
+
+       sc->sc_dev = self;
+       sc->sc_bst = faa->faa_bst;
+       if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
+               aprint_error(": couldn't map registers\n");
+               return;
+       }
+
+       error = cdnsiic_attach(sc);
+       if (error != 0) {
+               aprint_error_dev(self, "init failed, error = %d\n", error);
+               return;
+       }
+
+       fdtbus_register_i2c_controller(&sc->sc_ic, phandle);
+
+       fdtbus_attach_i2cbus(self, phandle, &sc->sc_ic, iicbus_print);
+}
+
+CFATTACH_DECL_NEW(cdnsiic_fdt, sizeof(struct cdnsiic_softc),
+    cdnsiic_fdt_match, cdnsiic_fdt_attach, NULL, NULL);
diff -r e19dc7bf9e30 -r 991b45293f7f sys/dev/fdt/files.fdt
--- a/sys/dev/fdt/files.fdt     Sat Nov 05 17:30:06 2022 +0000
+++ b/sys/dev/fdt/files.fdt     Sat Nov 05 17:31:37 2022 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: files.fdt,v 1.65 2022/07/20 10:01:11 riastradh Exp $
+# $NetBSD: files.fdt,v 1.66 2022/11/05 17:31:37 jmcneill Exp $
 
 include        "external/bsd/libfdt/conf/files.libfdt"
 
@@ -185,6 +185,10 @@
 attach         dwiic at fdt with dwiic_fdt
 file   dev/fdt/dwiic_fdt.c                     dwiic_fdt
 
+# Cadence I2C
+attach cdnsiic at fdt with cdnsiic_fdt
+file   dev/fdt/cdnsiic_fdt.c                   cdnsiic_fdt
+
 # AMD Cryptographic Coprocessor
 attach amdccp at fdt with amdccp_fdt
 file   dev/fdt/amdccp_fdt.c                    amdccp_fdt
diff -r e19dc7bf9e30 -r 991b45293f7f sys/dev/ic/cdnsiic.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/ic/cdnsiic.c      Sat Nov 05 17:31:37 2022 +0000
@@ -0,0 +1,297 @@
+/* $NetBSD: cdnsiic.c,v 1.1 2022/11/05 17:31:37 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2022 Jared McNeill <jmcneill%invisible.ca@localhost>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Cadence I2C controller
+ */
+
+#include <sys/cdefs.h>
+
+__KERNEL_RCSID(0, "$NetBSD: cdnsiic.c,v 1.1 2022/11/05 17:31:37 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/kmem.h>
+
+#include <dev/clk/clk.h>
+#include <dev/i2c/i2cvar.h>
+
+#include <dev/ic/cdnsiicvar.h>
+
+/* From Zynq-7000 SoC Technical Reference Manual, "Supports 16-byte FIFO" */
+#define        FIFO_DEPTH      16
+
+/* Poll timeout, in microseconds. */
+#define        POLL_TIMEOUT    10000
+
+#define        CR_REG          0x00
+#define         CR_DIV_A       __BITS(15,14)
+#define         CR_DIV_B       __BITS(13,8)
+#define         CR_CLR_FIFO    __BIT(6)
+#define         CR_HOLD        __BIT(4)
+#define         CR_ACKEN       __BIT(3)
+#define         CR_NEA         __BIT(2)
+#define         CR_MS          __BIT(1)
+#define         CR_RD_WR       __BIT(0)
+#define        SR_REG          0x04
+#define         SR_TXDV        __BIT(6)
+#define         SR_RXDV        __BIT(5)
+#define        ADDR_REG        0x08
+#define        DATA_REG        0x0c
+#define        ISR_REG         0x10
+#define         ISR_ARB_LOST   __BIT(9)
+#define         ISR_RX_UNF     __BIT(7)
+#define         ISR_TX_OVR     __BIT(6)
+#define         ISR_RX_OVR     __BIT(5)
+#define         ISR_SLV_RDY    __BIT(4)
+#define         ISR_TO         __BIT(3)
+#define         ISR_NACK       __BIT(2)
+#define         ISR_DATA       __BIT(1)
+#define         ISR_COMP       __BIT(0)
+#define         ISR_ERROR_MASK (ISR_ARB_LOST | ISR_TX_OVR | ISR_RX_OVR | ISR_NACK)
+#define        TRANS_SIZE_REG  0x14
+#define        SLV_PAUSE_REG   0x18
+#define        TIME_OUT_REG    0x1c
+#define        IMR_REG         0x20
+#define        IER_REG         0x24
+#define        IDR_REG         0x28
+
+#define        RD4(sc, reg)                            \
+       bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define        WR4(sc, reg, val)                       \
+       bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+
+static int
+cdnsiic_init(struct cdnsiic_softc *sc)
+{
+       int diva, divb;
+       int diff, calc_bus_freq;
+       int best_diva, best_divb, best_diff;
+       u_int pclk;
+
+       /*
+        * SCL frequency is calculated by the following formula:
+        *
+        * SCL Divisor = 22 * (divisor_a + 1) * (divisor_b + 1)
+        * SCL = PCLK / SCLK Divisor
+        */
+
+       pclk = clk_get_rate(sc->sc_pclk);
+       best_diff = sc->sc_bus_freq;
+       best_diva = best_divb = 0;
+
+       for (diva = 0; diva <= 0x3; diva++) {
+               divb = howmany(pclk, 22 * sc->sc_bus_freq * (diva + 1)) - 1;
+               if (divb < 0 || divb > 0x3f) {
+                       continue;
+               }
+               calc_bus_freq = pclk / (22 * (diva + 1) * (divb + 1));
+               diff = sc->sc_bus_freq - calc_bus_freq;
+               if (diff < best_diff) {
+                       best_diff = diff;
+                       best_diva = diva;
+                       best_divb = divb;
+               }
+       }
+       if (best_diff == sc->sc_bus_freq) {
+               return ENXIO;
+       }
+
+       WR4(sc, CR_REG,
+           __SHIFTIN(best_diva, CR_DIV_A) |
+           __SHIFTIN(best_divb, CR_DIV_B) |
+           CR_CLR_FIFO |
+           CR_ACKEN |
+           CR_NEA |
+           CR_MS);
+       WR4(sc, TIME_OUT_REG, 0xff);
+
+       return 0;
+}
+
+static int
+cdnsiic_poll_fifo(struct cdnsiic_softc *sc, uint32_t sr_mask, uint32_t sr_maskval)
+{
+       uint32_t sr_val, isr_val;
+       int retry = POLL_TIMEOUT;
+
+       while (--retry > 0) {
+               sr_val = RD4(sc, SR_REG);



Home | Main Index | Thread Index | Old Index