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/dev/iicbus/twsi/mv_twsi.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  * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
    3  * All rights reserved.
    4  *
    5  * Developed by Semihalf.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. Neither the name of MARVELL nor the names of contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  */
   31 
   32 /*
   33  * Driver for the TWSI (aka I2C, aka IIC) bus controller found on Marvell
   34  * and Allwinner SoCs. Supports master operation only, and works in polling mode.
   35  *
   36  * Calls to DELAY() are needed per Application Note AN-179 "TWSI Software
   37  * Guidelines for Discovery(TM), Horizon (TM) and Feroceon(TM) Devices".
   38  */
   39 
   40 #include <sys/cdefs.h>
   41 __FBSDID("$FreeBSD$");
   42 
   43 #include <sys/param.h>
   44 #include <sys/systm.h>
   45 #include <sys/bus.h>
   46 #include <sys/kernel.h>
   47 #include <sys/module.h>
   48 #include <sys/resource.h>
   49 
   50 #include <machine/_inttypes.h>
   51 #include <machine/bus.h>
   52 #include <machine/resource.h>
   53 
   54 #include <sys/rman.h>
   55 
   56 #include <sys/lock.h>
   57 #include <sys/mutex.h>
   58 
   59 #include <dev/iicbus/iiconf.h>
   60 #include <dev/iicbus/iicbus.h>
   61 #include <dev/ofw/ofw_bus.h>
   62 #include <dev/ofw/ofw_bus_subr.h>
   63 
   64 #include <dev/extres/clk/clk.h>
   65 
   66 #include <arm/mv/mvreg.h>
   67 #include <arm/mv/mvvar.h>
   68 #include <dev/iicbus/twsi/twsi.h>
   69 
   70 #include "iicbus_if.h"
   71 
   72 #define MV_TWSI_NAME            "twsi"
   73 #define IICBUS_DEVNAME          "iicbus"
   74 
   75 #define TWSI_ADDR       0x00
   76 #define TWSI_DATA       0x04
   77 #define TWSI_CNTR       0x08
   78 #define TWSI_XADDR      0x10
   79 #define TWSI_STAT       0x0c
   80 #define TWSI_BAUD_RATE  0x0c
   81 #define TWSI_SRST       0x1c
   82 
   83 #define TWSI_BAUD_RATE_RAW(C,M,N)       ((C)/((10*(M+1))<<(N+1)))
   84 #define TWSI_BAUD_RATE_SLOW             50000   /* 50kHz */
   85 #define TWSI_BAUD_RATE_FAST             100000  /* 100kHz */
   86 
   87 #define TWSI_DEBUG
   88 #undef TWSI_DEBUG
   89 
   90 #ifdef  TWSI_DEBUG
   91 #define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt,##args); } while (0)
   92 #else
   93 #define debugf(fmt, args...)
   94 #endif
   95 
   96 static phandle_t mv_twsi_get_node(device_t, device_t);
   97 static int mv_twsi_probe(device_t);
   98 static int mv_twsi_attach(device_t);
   99 
  100 static struct ofw_compat_data compat_data[] = {
  101         { "mrvl,twsi",                  true },
  102         { "marvell,mv64xxx-i2c",        true },
  103         { "marvell,mv78230-i2c",        true },
  104         { NULL,                         false }
  105 };
  106 
  107 static device_method_t mv_twsi_methods[] = {
  108         /* device interface */
  109         DEVMETHOD(device_probe,         mv_twsi_probe),
  110         DEVMETHOD(device_attach,        mv_twsi_attach),
  111 
  112         /* ofw_bus interface */
  113         DEVMETHOD(ofw_bus_get_node,     mv_twsi_get_node),
  114 
  115         DEVMETHOD_END
  116 };
  117 
  118 DEFINE_CLASS_1(twsi, mv_twsi_driver, mv_twsi_methods,
  119     sizeof(struct twsi_softc), twsi_driver);
  120 
  121 DRIVER_MODULE(twsi, simplebus, mv_twsi_driver, 0, 0);
  122 DRIVER_MODULE(iicbus, twsi, iicbus_driver, 0, 0);
  123 MODULE_DEPEND(twsi, iicbus, 1, 1, 1);
  124 SIMPLEBUS_PNP_INFO(compat_data);
  125 
  126 static phandle_t
  127 mv_twsi_get_node(device_t bus, device_t dev)
  128 {
  129 
  130         /* Used by ofw_iicbus. */
  131         return (ofw_bus_get_node(bus));
  132 }
  133 
  134 static int
  135 mv_twsi_probe(device_t dev)
  136 {
  137 
  138         if (!ofw_bus_status_okay(dev))
  139                 return (ENXIO);
  140 
  141         if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
  142                 return (ENXIO);
  143 
  144         device_set_desc(dev, "Marvell Integrated I2C Bus Controller");
  145         return (BUS_PROBE_DEFAULT);
  146 }
  147 
  148 #define ABSSUB(a,b)     (((a) > (b)) ? (a) - (b) : (b) - (a))
  149 static void
  150 mv_twsi_cal_baud_rate(struct twsi_softc *sc, const uint32_t target,
  151     struct twsi_baud_rate *rate)
  152 {
  153         uint64_t clk;
  154         uint32_t cur, diff, diff0;
  155         int m, n, m0, n0;
  156 
  157         /* Calculate baud rate. */
  158         m0 = n0 = 4;    /* Default values on reset */
  159         diff0 = 0xffffffff;
  160         clk_get_freq(sc->clk_core, &clk);
  161 
  162         for (n = 0; n < 8; n++) {
  163                 for (m = 0; m < 16; m++) {
  164                         cur = TWSI_BAUD_RATE_RAW(clk,m,n);
  165                         diff = ABSSUB(target, cur);
  166                         if (diff < diff0) {
  167                                 m0 = m;
  168                                 n0 = n;
  169                                 diff0 = diff;
  170                         }
  171                 }
  172         }
  173         rate->raw = TWSI_BAUD_RATE_RAW(clk, m0, n0);
  174         rate->param = TWSI_BAUD_RATE_PARAM(m0, n0);
  175         rate->m = m0;
  176         rate->n = n0;
  177 }
  178 
  179 static int
  180 mv_twsi_attach(device_t dev)
  181 {
  182         struct twsi_softc *sc;
  183         int error;
  184 
  185         sc = device_get_softc(dev);
  186         sc->dev = dev;
  187 
  188         /* Activate clock */
  189         error = clk_get_by_ofw_index(dev, 0, 0, &sc->clk_core);
  190         if (error != 0) {
  191                 device_printf(dev, "could not find core clock\n");
  192                 return (error);
  193         }
  194         error = clk_enable(sc->clk_core);
  195         if (error != 0) {
  196                 device_printf(dev, "could not enable core clock\n");
  197                 return (error);
  198         }
  199 
  200         if (clk_get_by_ofw_index(dev, 0, 1, &sc->clk_reg) == 0) {
  201                 error = clk_enable(sc->clk_reg);
  202                 if (error != 0) {
  203                         device_printf(dev, "could not enable core clock\n");
  204                         return (error);
  205                 }
  206         }
  207 
  208         mv_twsi_cal_baud_rate(sc, TWSI_BAUD_RATE_SLOW, &sc->baud_rate[IIC_SLOW]);
  209         mv_twsi_cal_baud_rate(sc, TWSI_BAUD_RATE_FAST, &sc->baud_rate[IIC_FAST]);
  210         if (bootverbose)
  211                 device_printf(dev, "calculated baud rates are:\n"
  212                     " %" PRIu32 " kHz (M=%d, N=%d) for slow,\n"
  213                     " %" PRIu32 " kHz (M=%d, N=%d) for fast.\n",
  214                     sc->baud_rate[IIC_SLOW].raw / 1000,
  215                     sc->baud_rate[IIC_SLOW].m,
  216                     sc->baud_rate[IIC_SLOW].n,
  217                     sc->baud_rate[IIC_FAST].raw / 1000,
  218                     sc->baud_rate[IIC_FAST].m,
  219                     sc->baud_rate[IIC_FAST].n);
  220 
  221         sc->reg_data = TWSI_DATA;
  222         sc->reg_slave_addr = TWSI_ADDR;
  223         sc->reg_slave_ext_addr = TWSI_XADDR;
  224         sc->reg_control = TWSI_CNTR;
  225         sc->reg_status = TWSI_STAT;
  226         sc->reg_baud_rate = TWSI_BAUD_RATE;
  227         sc->reg_soft_reset = TWSI_SRST;
  228 
  229         return (twsi_attach(dev));
  230 }

Cache object: 813ee5cd6917837f0c28510257ef15f0


[ 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.