The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arm/mv/a37x0_iic.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2018, 2019 Rubicon Communications, LLC (Netgate)
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  *
   27  */
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD$");
   30 
   31 /*
   32  * Driver for Armada 37x0 i2c controller.
   33  */
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/kernel.h>
   38 #include <sys/lock.h>
   39 #include <sys/module.h>
   40 #include <sys/mutex.h>
   41 #include <sys/bus.h>
   42 #include <machine/resource.h>
   43 #include <machine/bus.h>
   44 #include <sys/rman.h>
   45 #include <sys/sysctl.h>
   46 
   47 #include <dev/iicbus/iicbus.h>
   48 #include <dev/iicbus/iiconf.h>
   49 #include <dev/ofw/ofw_bus.h>
   50 #include <dev/ofw/ofw_bus_subr.h>
   51 
   52 #include <arm/mv/a37x0_iicreg.h>
   53 
   54 #include "iicbus_if.h"
   55 
   56 struct a37x0_iic_softc {
   57         boolean_t               sc_fast_mode;
   58         bus_space_tag_t         sc_bst;
   59         bus_space_handle_t      sc_bsh;
   60         device_t                sc_dev;
   61         device_t                sc_iicbus;
   62         struct mtx              sc_mtx;
   63         struct resource         *sc_mem_res;
   64         struct resource         *sc_irq_res;
   65         void                    *sc_intrhand;
   66 };
   67 
   68 #define A37X0_IIC_WRITE(_sc, _off, _val)                        \
   69     bus_space_write_4((_sc)->sc_bst, (_sc)->sc_bsh, _off, _val)
   70 #define A37X0_IIC_READ(_sc, _off)                               \
   71     bus_space_read_4((_sc)->sc_bst, (_sc)->sc_bsh, _off)
   72 #define A37X0_IIC_LOCK(_sc)     mtx_lock(&(_sc)->sc_mtx)
   73 #define A37X0_IIC_UNLOCK(_sc)   mtx_unlock(&(_sc)->sc_mtx)
   74 
   75 static struct ofw_compat_data compat_data[] = {
   76         { "marvell,armada-3700-i2c",    1 },
   77         { NULL,                         0 }
   78 };
   79 
   80 #undef A37x0_IIC_DEBUG
   81 
   82 static void a37x0_iic_intr(void *);
   83 static int a37x0_iic_detach(device_t);
   84 
   85 static void
   86 a37x0_iic_rmw(struct a37x0_iic_softc *sc, uint32_t off, uint32_t mask,
   87     uint32_t value)
   88 {
   89         uint32_t reg;
   90 
   91         mtx_assert(&sc->sc_mtx, MA_OWNED);
   92         reg = A37X0_IIC_READ(sc, off);
   93         reg &= ~mask;
   94         reg |= value;
   95         A37X0_IIC_WRITE(sc, off, reg);
   96 }
   97 
   98 static int
   99 a37x0_iic_wait_clear(struct a37x0_iic_softc *sc, uint32_t mask)
  100 {
  101         int timeout;
  102         uint32_t status;
  103 
  104         mtx_assert(&sc->sc_mtx, MA_OWNED);
  105         timeout = 1000;
  106         do {
  107                 DELAY(10);
  108                 status = A37X0_IIC_READ(sc, A37X0_IIC_ISR);
  109                 if (--timeout == 0)
  110                         return (0);
  111         } while ((status & mask) != 0);
  112 
  113         return (1);
  114 }
  115 
  116 static int
  117 a37x0_iic_wait_set(struct a37x0_iic_softc *sc, uint32_t mask)
  118 {
  119         int timeout;
  120         uint32_t status;
  121 
  122         mtx_assert(&sc->sc_mtx, MA_OWNED);
  123         timeout = 1000;
  124         do {
  125                 DELAY(10);
  126                 status = A37X0_IIC_READ(sc, A37X0_IIC_ISR);
  127                 if (--timeout == 0)
  128                         return (0);
  129         } while ((status & mask) != mask);
  130 
  131         return (1);
  132 }
  133 
  134 #ifdef A37x0_IIC_DEBUG
  135 static void
  136 a37x0_iic_regdump(struct a37x0_iic_softc *sc)
  137 {
  138 
  139         mtx_assert(&sc->sc_mtx, MA_OWNED);
  140         printf("%s: IBMR: %#x\n", __func__, A37X0_IIC_READ(sc, A37X0_IIC_IBMR));
  141         printf("%s: ICR: %#x\n", __func__, A37X0_IIC_READ(sc, A37X0_IIC_ICR));
  142         printf("%s: ISR: %#x\n", __func__, A37X0_IIC_READ(sc, A37X0_IIC_ISR));
  143 }
  144 #endif
  145 
  146 static void
  147 a37x0_iic_reset(struct a37x0_iic_softc *sc)
  148 {
  149         uint32_t mode, reg;
  150 
  151         mtx_assert(&sc->sc_mtx, MA_OWNED);
  152 
  153         /* Disable the controller. */
  154         reg = A37X0_IIC_READ(sc, A37X0_IIC_ICR);
  155         mode = reg & ICR_MODE_MASK;
  156         A37X0_IIC_WRITE(sc, A37X0_IIC_ICR, reg & ~ICR_IUE);
  157         A37X0_IIC_WRITE(sc, A37X0_IIC_ICR, reg | ICR_UR);
  158         DELAY(100);
  159         A37X0_IIC_WRITE(sc, A37X0_IIC_ICR, reg & ~ICR_IUE);
  160 
  161         /* Enable the controller. */
  162         reg = A37X0_IIC_READ(sc, A37X0_IIC_ICR);
  163         reg |= mode | ICR_IUE | ICR_GCD | ICR_SCLE;
  164         A37X0_IIC_WRITE(sc, A37X0_IIC_ICR, reg);
  165 #ifdef A37x0_IIC_DEBUG
  166         a37x0_iic_regdump(sc);
  167 #endif
  168 }
  169 
  170 static int
  171 a37x0_iic_probe(device_t dev)
  172 {
  173 
  174         if (!ofw_bus_status_okay(dev))
  175                 return (ENXIO);
  176 
  177         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
  178                 return (ENXIO);
  179 
  180         device_set_desc(dev, "Marvell Armada 37x0 IIC controller");
  181 
  182         return (BUS_PROBE_DEFAULT);
  183 }
  184 
  185 static int
  186 a37x0_iic_attach(device_t dev)
  187 {
  188         int rid;
  189         phandle_t node;
  190         struct a37x0_iic_softc *sc;
  191 
  192         sc = device_get_softc(dev);
  193         sc->sc_dev = dev;
  194 
  195         rid = 0;
  196         sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  197             RF_ACTIVE);
  198         if (!sc->sc_mem_res) {
  199                 device_printf(dev, "cannot allocate memory window\n");
  200                 return (ENXIO);
  201         }
  202 
  203         sc->sc_bst = rman_get_bustag(sc->sc_mem_res);
  204         sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res);
  205 
  206         rid = 0;
  207         sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  208             RF_ACTIVE | RF_SHAREABLE);
  209         if (!sc->sc_irq_res) {
  210                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  211                 device_printf(dev, "cannot allocate interrupt\n");
  212                 return (ENXIO);
  213         }
  214 
  215         /* Hook up our interrupt handler. */
  216         if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
  217             NULL, a37x0_iic_intr, sc, &sc->sc_intrhand)) {
  218                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
  219                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  220                 device_printf(dev, "cannot setup the interrupt handler\n");
  221                 return (ENXIO);
  222         }
  223 
  224         mtx_init(&sc->sc_mtx, "a37x0_iic", NULL, MTX_DEF);
  225 
  226         node = ofw_bus_get_node(dev);
  227         if (OF_hasprop(node, "mrvl,i2c-fast-mode"))
  228                 sc->sc_fast_mode = true;
  229 
  230         /* Enable the controller. */
  231         A37X0_IIC_LOCK(sc);
  232         a37x0_iic_reset(sc);
  233         A37X0_IIC_UNLOCK(sc);
  234 
  235         sc->sc_iicbus = device_add_child(dev, "iicbus", -1);
  236         if (sc->sc_iicbus == NULL) {
  237                 a37x0_iic_detach(dev);
  238                 return (ENXIO);
  239         }
  240 
  241         /* Probe and attach the iicbus. */
  242         return (bus_generic_attach(dev));
  243 }
  244 
  245 static int
  246 a37x0_iic_detach(device_t dev)
  247 {
  248         struct a37x0_iic_softc *sc;
  249 
  250         bus_generic_detach(dev);
  251 
  252         sc = device_get_softc(dev);
  253         if (sc->sc_iicbus != NULL)
  254                 device_delete_child(dev, sc->sc_iicbus);
  255         mtx_destroy(&sc->sc_mtx);
  256         if (sc->sc_intrhand)
  257                 bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand);
  258         if (sc->sc_irq_res)
  259                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
  260         if (sc->sc_mem_res)
  261                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  262 
  263         return (0);
  264 }
  265 
  266 static void
  267 a37x0_iic_intr(void *arg)
  268 {
  269         struct a37x0_iic_softc *sc;
  270         uint32_t status;
  271 
  272         /* Not used, the interrupts are not enabled. */
  273         sc = (struct a37x0_iic_softc *)arg;
  274         A37X0_IIC_LOCK(sc);
  275         status = A37X0_IIC_READ(sc, A37X0_IIC_ISR);
  276 #ifdef A37x0_IIC_DEBUG
  277         a37x0_iic_regdump(sc);
  278 #endif
  279 
  280         /* Clear pending interrrupts. */
  281         A37X0_IIC_WRITE(sc, A37X0_IIC_ISR, status);
  282         A37X0_IIC_UNLOCK(sc);
  283 }
  284 
  285 static int
  286 a37x0_iic_stop(device_t dev)
  287 {
  288         struct a37x0_iic_softc *sc;
  289         uint32_t reg;
  290 
  291         sc = device_get_softc(dev);
  292         A37X0_IIC_LOCK(sc);
  293         /* Clear the STOP condition. */
  294         reg = A37X0_IIC_READ(sc, A37X0_IIC_ICR);
  295         if (reg & (ICR_ACKNAK | ICR_STOP)) {
  296                 reg &= ~(ICR_START | ICR_ACKNAK | ICR_STOP);
  297                 A37X0_IIC_WRITE(sc, A37X0_IIC_ICR, reg);
  298         }
  299         /* Clear interrupts. */
  300         reg = A37X0_IIC_READ(sc, A37X0_IIC_ISR);
  301         A37X0_IIC_WRITE(sc, A37X0_IIC_ISR, reg);
  302         A37X0_IIC_UNLOCK(sc);
  303 
  304         return (IIC_NOERR);
  305 }
  306 
  307 static int
  308 a37x0_iic_start(device_t dev, u_char slave, int timeout)
  309 {
  310         int rv;
  311         struct a37x0_iic_softc *sc;
  312         uint32_t reg, status;
  313 
  314         sc = device_get_softc(dev);
  315         A37X0_IIC_LOCK(sc);
  316 
  317         /* Wait for the bus to be free before start a transaction. */
  318         if (a37x0_iic_wait_clear(sc, ISR_IBB) == 0) {
  319                 A37X0_IIC_UNLOCK(sc);
  320                 return (IIC_ETIMEOUT);
  321         }
  322 
  323         /* Write the slave address. */
  324         A37X0_IIC_WRITE(sc, A37X0_IIC_IDBR, slave);
  325 
  326         /* Send Start condition (with slave address). */
  327         reg = A37X0_IIC_READ(sc, A37X0_IIC_ICR);
  328         reg &= ~(ICR_STOP | ICR_ACKNAK);
  329         A37X0_IIC_WRITE(sc, A37X0_IIC_ICR, reg | ICR_START | ICR_TB);
  330 
  331         rv = IIC_NOERR;
  332         if (a37x0_iic_wait_set(sc, ISR_ITE) == 0)
  333                 rv = IIC_ETIMEOUT;
  334         if (rv == IIC_NOERR) {
  335                 status = A37X0_IIC_READ(sc, A37X0_IIC_ISR);
  336                 A37X0_IIC_WRITE(sc, A37X0_IIC_ISR, status | ISR_ITE);
  337                 if (a37x0_iic_wait_clear(sc, ISR_ACKNAK) == 0)
  338                         rv = IIC_ENOACK;
  339         }
  340 
  341         A37X0_IIC_UNLOCK(sc);
  342         if (rv != IIC_NOERR)
  343                 a37x0_iic_stop(dev);
  344 
  345         return (rv);
  346 }
  347 
  348 static int
  349 a37x0_iic_bus_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
  350 {
  351         struct a37x0_iic_softc *sc;
  352         uint32_t busfreq;
  353 
  354         sc = device_get_softc(dev);
  355         A37X0_IIC_LOCK(sc);
  356         a37x0_iic_reset(sc);
  357         if (sc->sc_iicbus == NULL)
  358                 busfreq = 100000;
  359         else
  360                 busfreq = IICBUS_GET_FREQUENCY(sc->sc_iicbus, speed);
  361         a37x0_iic_rmw(sc, A37X0_IIC_ICR, ICR_MODE_MASK,
  362             (busfreq > 100000) ? ICR_FAST_MODE : 0);
  363         A37X0_IIC_UNLOCK(sc);
  364 
  365         return (IIC_ENOADDR);
  366 }
  367 
  368 static int
  369 a37x0_iic_read(device_t dev, char *buf, int len, int *read, int last, int delay)
  370 {
  371         int rv;
  372         struct a37x0_iic_softc *sc;
  373         uint32_t reg, status;
  374 
  375         sc = device_get_softc(dev);
  376         A37X0_IIC_LOCK(sc);
  377         reg = A37X0_IIC_READ(sc, A37X0_IIC_ISR);
  378         if ((reg & (ISR_UB | ISR_IBB)) != ISR_UB) {
  379                 A37X0_IIC_UNLOCK(sc);
  380                 return (IIC_EBUSERR);
  381         }
  382 
  383         *read = 0;
  384         rv = IIC_NOERR;
  385         while (*read < len) {
  386                 reg = A37X0_IIC_READ(sc, A37X0_IIC_ICR);
  387                 reg &= ~(ICR_START | ICR_STOP | ICR_ACKNAK);
  388                 if (*read == len - 1)
  389                         reg |= ICR_ACKNAK | ICR_STOP;
  390                 A37X0_IIC_WRITE(sc, A37X0_IIC_ICR, reg | ICR_TB);
  391                 if (a37x0_iic_wait_set(sc, ISR_IRF) == 0) {
  392                         rv = IIC_ETIMEOUT;
  393                         break;
  394                 }
  395                 *buf++ = A37X0_IIC_READ(sc, A37X0_IIC_IDBR);
  396                 (*read)++;
  397                 status = A37X0_IIC_READ(sc, A37X0_IIC_ISR);
  398                 A37X0_IIC_WRITE(sc, A37X0_IIC_ISR, status | ISR_IRF);
  399         }
  400         A37X0_IIC_UNLOCK(sc);
  401 
  402         return (rv);
  403 }
  404 
  405 static int
  406 a37x0_iic_write(device_t dev, const char *buf, int len, int *sent, int timeout)
  407 {
  408         int rv;
  409         struct a37x0_iic_softc *sc;
  410         uint32_t reg, status;
  411 
  412         sc = device_get_softc(dev);
  413         A37X0_IIC_LOCK(sc);
  414         reg = A37X0_IIC_READ(sc, A37X0_IIC_ISR);
  415         if ((reg & (ISR_UB | ISR_IBB)) != ISR_UB) {
  416                 A37X0_IIC_UNLOCK(sc);
  417                 return (IIC_EBUSERR);
  418         }
  419 
  420         rv = IIC_NOERR;
  421         *sent = 0;
  422         while (*sent < len) {
  423                 A37X0_IIC_WRITE(sc, A37X0_IIC_IDBR, *buf++);
  424                 reg = A37X0_IIC_READ(sc, A37X0_IIC_ICR);
  425                 reg &= ~(ICR_START | ICR_STOP | ICR_ACKNAK);
  426                 if (*sent == len - 1)
  427                         reg |= ICR_STOP;
  428                 A37X0_IIC_WRITE(sc, A37X0_IIC_ICR, reg | ICR_TB);
  429                 if (a37x0_iic_wait_set(sc, ISR_ITE) == 0) {
  430                         rv = IIC_ETIMEOUT;
  431                         break;
  432                 }
  433                 (*sent)++;
  434                 status = A37X0_IIC_READ(sc, A37X0_IIC_ISR);
  435                 A37X0_IIC_WRITE(sc, A37X0_IIC_ISR, status | ISR_ITE);
  436                 if (a37x0_iic_wait_clear(sc, ISR_ACKNAK) == 0) {
  437                         rv = IIC_ENOACK;
  438                         break;
  439                 }
  440         }
  441         A37X0_IIC_UNLOCK(sc);
  442 
  443         return (rv);
  444 }
  445 
  446 static phandle_t
  447 a37x0_iic_get_node(device_t bus, device_t dev)
  448 {
  449 
  450         return (ofw_bus_get_node(bus));
  451 }
  452 
  453 static device_method_t a37x0_iic_methods[] = {
  454         /* Device interface */
  455         DEVMETHOD(device_probe,         a37x0_iic_probe),
  456         DEVMETHOD(device_attach,        a37x0_iic_attach),
  457         DEVMETHOD(device_detach,        a37x0_iic_detach),
  458 
  459         /* iicbus interface */
  460         DEVMETHOD(iicbus_reset,         a37x0_iic_bus_reset),
  461         DEVMETHOD(iicbus_callback,      iicbus_null_callback),
  462         DEVMETHOD(iicbus_transfer,      iicbus_transfer_gen),
  463         DEVMETHOD(iicbus_repeated_start,        a37x0_iic_start),
  464         DEVMETHOD(iicbus_start,         a37x0_iic_start),
  465         DEVMETHOD(iicbus_stop,          a37x0_iic_stop),
  466         DEVMETHOD(iicbus_read,          a37x0_iic_read),
  467         DEVMETHOD(iicbus_write,         a37x0_iic_write),
  468 
  469         /* ofw_bus interface */
  470         DEVMETHOD(ofw_bus_get_node,     a37x0_iic_get_node),
  471 
  472         DEVMETHOD_END
  473 };
  474 
  475 static devclass_t a37x0_iic_devclass;
  476 
  477 static driver_t a37x0_iic_driver = {
  478         "iichb",
  479         a37x0_iic_methods,
  480         sizeof(struct a37x0_iic_softc),
  481 };
  482 
  483 DRIVER_MODULE(iicbus, a37x0_iic, iicbus_driver, iicbus_devclass, 0, 0);
  484 DRIVER_MODULE(a37x0_iic, simplebus, a37x0_iic_driver, a37x0_iic_devclass, 0, 0);

Cache object: 2a184d28638055c85570907d8471e22c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.