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/broadcom/bcm2835/bcm2835_pwm.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) 2017 Poul-Henning Kamp <phk@FreeBSD.org>
    5  * All rights reserved.
    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  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  *
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/bus.h>
   36 
   37 #include <sys/kernel.h>
   38 #include <sys/module.h>
   39 #include <sys/rman.h>
   40 #include <sys/lock.h>
   41 #include <sys/sysctl.h>
   42 
   43 #include <machine/bus.h>
   44 #include <machine/resource.h>
   45 
   46 #include <dev/ofw/ofw_bus.h>
   47 #include <dev/ofw/ofw_bus_subr.h>
   48 
   49 #include <arm/broadcom/bcm2835/bcm2835_clkman.h>
   50 
   51 static struct ofw_compat_data compat_data[] = {
   52         {"broadcom,bcm2835-pwm",        1},
   53         {"brcm,bcm2835-pwm",            1},
   54         {NULL,                          0}
   55 };
   56 
   57 struct bcm_pwm_softc {
   58         device_t                sc_dev;
   59 
   60         struct resource *       sc_mem_res;
   61         bus_space_tag_t         sc_m_bst;
   62         bus_space_handle_t      sc_m_bsh;
   63 
   64         device_t                clkman;
   65 
   66         uint32_t                freq;    /* shared between channels 1 and 2 */
   67         uint32_t                period;  /* channel 1 */
   68         uint32_t                ratio;
   69         uint32_t                mode;
   70         uint32_t                period2; /* channel 2 */
   71         uint32_t                ratio2;
   72         uint32_t                mode2;
   73 };
   74 
   75 #define BCM_PWM_MEM_WRITE(_sc, _off, _val)              \
   76     bus_space_write_4(_sc->sc_m_bst, _sc->sc_m_bsh, _off, _val)
   77 #define BCM_PWM_MEM_READ(_sc, _off)                     \
   78     bus_space_read_4(_sc->sc_m_bst, _sc->sc_m_bsh, _off)
   79 #define BCM_PWM_CLK_WRITE(_sc, _off, _val)              \
   80     bus_space_write_4(_sc->sc_c_bst, _sc->sc_c_bsh, _off, _val)
   81 #define BCM_PWM_CLK_READ(_sc, _off)                     \
   82     bus_space_read_4(_sc->sc_c_bst, _sc->sc_c_bsh, _off)
   83 
   84 #define W_CTL(_sc, _val) BCM_PWM_MEM_WRITE(_sc, 0x00, _val)
   85 #define R_CTL(_sc) BCM_PWM_MEM_READ(_sc, 0x00)
   86 #define W_STA(_sc, _val) BCM_PWM_MEM_WRITE(_sc, 0x04, _val)
   87 #define R_STA(_sc) BCM_PWM_MEM_READ(_sc, 0x04)
   88 #define W_RNG(_sc, _val) BCM_PWM_MEM_WRITE(_sc, 0x10, _val)
   89 #define R_RNG(_sc) BCM_PWM_MEM_READ(_sc, 0x10)
   90 #define W_DAT(_sc, _val) BCM_PWM_MEM_WRITE(_sc, 0x14, _val)
   91 #define R_DAT(_sc) BCM_PWM_MEM_READ(_sc, 0x14)
   92 #define W_RNG2(_sc, _val) BCM_PWM_MEM_WRITE(_sc, 0x20, _val)
   93 #define R_RNG2(_sc) BCM_PWM_MEM_READ(_sc, 0x20)
   94 #define W_DAT2(_sc, _val) BCM_PWM_MEM_WRITE(_sc, 0x24, _val)
   95 #define R_DAT2(_sc) BCM_PWM_MEM_READ(_sc, 0x24)
   96 
   97 static int
   98 bcm_pwm_reconf(struct bcm_pwm_softc *sc)
   99 {
  100         uint32_t u, ctlr;
  101 
  102         /* Disable PWM */
  103         W_CTL(sc, 0);
  104 
  105         /* Stop PWM clock */
  106         (void)bcm2835_clkman_set_frequency(sc->clkman, BCM_PWM_CLKSRC, 0);
  107 
  108         ctlr = 0; /* pre-assign zero, enable bits, write to CTL at end */
  109 
  110         if (sc->mode == 0 && sc->mode2 == 0) /* both modes are zero */
  111                 return 0; /* device is now off - return */
  112 
  113         /* set the PWM clock frequency */
  114         /* TODO:  should I only do this if it changes and not stop it first? */
  115         u = bcm2835_clkman_set_frequency(sc->clkman, BCM_PWM_CLKSRC, sc->freq);
  116         if (u == 0)
  117                 return (EINVAL);
  118         sc->freq = u;
  119 
  120         /* control register CTL bits:
  121          * (from BCM2835 ARM Peripherals manual, section 9.6)
  122          *
  123          * 15 MSEN2  chan 2 M/S enable; 0 for PWM algo, 1 for M/S transmission
  124          * 14 unused; always reads as 0
  125          * 13 USEF2  chan 2 use FIFO (0 uses data; 1 uses FIFO)
  126          * 12 POLA2  chan 2 invert polarity (0 normal, 1 inverted polarity)
  127          * 11 SBIT2  chan 2 'Silence' bit (when not transmitting data)
  128          * 10 RPTL2  chan 2 FIFO repeat last data (1 repeats, 0 interrupts)
  129          *  9 MODE2  chan 2 PWM/Serializer mode (0 PWM, 1 Serializer)
  130          *  8 PWEN2  chan 2 enable (0 disable, 1 enable)
  131          *  7 MSEN1  chan 1 M/S enable; 0 for PWM algo, 1 for M/S transmission
  132          *  6 CLRF1  chan 1 clear FIFO (set 1 to clear; always reads as 0)
  133          *  5 USEF1  chan 1 use FIFO (0 uses data; 1 uses FIFO)
  134          *  4 POLA1  chan 1 invert polarity (0 normal, 1 inverted polarity)
  135          *  3 SBIT1  chan 1 'Silence' bit (when not transmitting data)
  136          *  2 RTPL1  chan 1 FIFO repeat last data (1 repeats, 0 interrupts)
  137          *  1 MODE1  chan 1 PWM/Serializer mode (0 PWM, 1 Serializer)
  138          *  0 PWMEN1 chan 1 enable (0 disable, 1 enable)
  139          *
  140          * Notes on M/S enable:  when this bit is '1', a simple M/S ratio is used. In short,
  141          * the value of 'ratio' is the number of 'on' bits, and the total length of the data is
  142          * defined by 'period'.  So if 'ratio' is 2500 and 'period' is 10000, then the output
  143          * remains 'on' for 2500 clocks, and goes 'off' for the remaining 7500 clocks.
  144          * When the M/S enable is '', a more complicated algorithm effectively 'dithers' the
  145          * pulses in order to obtain the desired ratio.  For details, see section 9.3 of the
  146          * BCM2835 ARM Peripherals manual.
  147          */
  148 
  149         if (sc->mode != 0) {
  150                 /* Config PWM Channel 1 */
  151                 W_RNG(sc, sc->period);
  152                 if (sc->ratio > sc->period)
  153                         sc->ratio = sc->period;
  154                 W_DAT(sc, sc->ratio);
  155 
  156                 /* Start PWM Channel 1 */
  157                 if (sc->mode == 1)
  158                         ctlr |= 0x81; /* chan 1 enable + chan 1 M/S enable */
  159                 else
  160                         ctlr |= 0x1; /* chan 1 enable */
  161         }
  162 
  163         if (sc->mode2 != 0) {
  164                 /* Config PWM Channel 2 */
  165                 W_RNG2(sc, sc->period2);
  166                 if (sc->ratio2 > sc->period2)
  167                         sc->ratio2 = sc->period2;
  168                 W_DAT2(sc, sc->ratio2);
  169 
  170                 /* Start PWM Channel 2 */
  171                 if (sc->mode2 == 1)
  172                         ctlr |= 0x8100; /* chan 2 enable + chan 2 M/S enable */
  173                 else
  174                         ctlr |= 0x100;  /* chan 2 enable */
  175         }
  176 
  177         /* write CTL register with updated value */
  178         W_CTL(sc, ctlr);
  179 
  180         return (0);
  181 }
  182 
  183 static int
  184 bcm_pwm_pwm_freq_proc(SYSCTL_HANDLER_ARGS)
  185 {
  186         struct bcm_pwm_softc *sc;
  187         uint32_t r;
  188         int error;
  189 
  190         sc = (struct bcm_pwm_softc *)arg1;
  191         if (sc->mode == 1)
  192                 r = sc->freq / sc->period;
  193         else
  194                 r = 0;
  195         error = sysctl_handle_int(oidp, &r, sizeof(r), req);
  196         return (error);
  197 }
  198 
  199 static int
  200 bcm_pwm_mode_proc(SYSCTL_HANDLER_ARGS)
  201 {
  202         struct bcm_pwm_softc *sc;
  203         uint32_t r;
  204         int error;
  205 
  206         sc = (struct bcm_pwm_softc *)arg1;
  207         r = sc->mode;
  208         error = sysctl_handle_int(oidp, &r, sizeof(r), req);
  209         if (error != 0 || req->newptr == NULL)
  210                 return (error);
  211         if (r > 2)
  212                 return (EINVAL);
  213         sc->mode = r;
  214         return (bcm_pwm_reconf(sc));
  215 }
  216 
  217 static int
  218 bcm_pwm_freq_proc(SYSCTL_HANDLER_ARGS)
  219 {
  220         struct bcm_pwm_softc *sc;
  221         uint32_t r;
  222         int error;
  223 
  224         sc = (struct bcm_pwm_softc *)arg1;
  225         r = sc->freq;
  226         error = sysctl_handle_int(oidp, &r, sizeof(r), req);
  227         if (error != 0 || req->newptr == NULL)
  228                 return (error);
  229         if (r > 125000000)
  230                 return (EINVAL);
  231         sc->freq = r;
  232         return (bcm_pwm_reconf(sc));
  233 }
  234 
  235 static int
  236 bcm_pwm_period_proc(SYSCTL_HANDLER_ARGS)
  237 {
  238         struct bcm_pwm_softc *sc;
  239         int error;
  240 
  241         sc = (struct bcm_pwm_softc *)arg1;
  242         error = sysctl_handle_int(oidp, &sc->period, sizeof(sc->period), req);
  243         if (error != 0 || req->newptr == NULL)
  244                 return (error);
  245         return (bcm_pwm_reconf(sc));
  246 }
  247 
  248 static int
  249 bcm_pwm_ratio_proc(SYSCTL_HANDLER_ARGS)
  250 {
  251         struct bcm_pwm_softc *sc;
  252         uint32_t r;
  253         int error;
  254 
  255         sc = (struct bcm_pwm_softc *)arg1;
  256         r = sc->ratio;
  257         error = sysctl_handle_int(oidp, &r, sizeof(r), req);
  258         if (error != 0 || req->newptr == NULL)
  259                 return (error);
  260         if (r > sc->period)                     // XXX >= ?
  261                 return (EINVAL);
  262         sc->ratio = r;
  263         W_DAT(sc, sc->ratio);
  264         return (0);
  265 }
  266 
  267 static int
  268 bcm_pwm_pwm_freq2_proc(SYSCTL_HANDLER_ARGS)
  269 {
  270         struct bcm_pwm_softc *sc;
  271         uint32_t r;
  272         int error;
  273 
  274         sc = (struct bcm_pwm_softc *)arg1;
  275         if (sc->mode2 == 1)
  276                 r = sc->freq / sc->period2;
  277         else
  278                 r = 0;
  279         error = sysctl_handle_int(oidp, &r, sizeof(r), req);
  280         return (error);
  281 }
  282 
  283 static int
  284 bcm_pwm_mode2_proc(SYSCTL_HANDLER_ARGS)
  285 {
  286         struct bcm_pwm_softc *sc;
  287         uint32_t r;
  288         int error;
  289 
  290         sc = (struct bcm_pwm_softc *)arg1;
  291         r = sc->mode2;
  292         error = sysctl_handle_int(oidp, &r, sizeof(r), req);
  293         if (error != 0 || req->newptr == NULL)
  294                 return (error);
  295         if (r > 2)
  296                 return (EINVAL);
  297         sc->mode2 = r;
  298         return (bcm_pwm_reconf(sc));
  299 }
  300 
  301 static int
  302 bcm_pwm_period2_proc(SYSCTL_HANDLER_ARGS)
  303 {
  304         struct bcm_pwm_softc *sc;
  305         int error;
  306 
  307         sc = (struct bcm_pwm_softc *)arg1;
  308         error = sysctl_handle_int(oidp, &sc->period2, sizeof(sc->period2), req);
  309         if (error != 0 || req->newptr == NULL)
  310                 return (error);
  311         return (bcm_pwm_reconf(sc));
  312 }
  313 
  314 static int
  315 bcm_pwm_ratio2_proc(SYSCTL_HANDLER_ARGS)
  316 {
  317         struct bcm_pwm_softc *sc;
  318         uint32_t r;
  319         int error;
  320 
  321         sc = (struct bcm_pwm_softc *)arg1;
  322         r = sc->ratio2;
  323         error = sysctl_handle_int(oidp, &r, sizeof(r), req);
  324         if (error != 0 || req->newptr == NULL)
  325                 return (error);
  326         if (r > sc->period2)            // XXX >= ?
  327                 return (EINVAL);
  328         sc->ratio2 = r;
  329         W_DAT(sc, sc->ratio2);
  330         return (0);
  331 }
  332 
  333 static int
  334 bcm_pwm_reg_proc(SYSCTL_HANDLER_ARGS)
  335 {
  336         struct bcm_pwm_softc *sc;
  337         uint32_t reg;
  338         int error;
  339 
  340         sc = (struct bcm_pwm_softc *)arg1;
  341         reg = BCM_PWM_MEM_READ(sc, arg2 & 0xff);
  342 
  343         error = sysctl_handle_int(oidp, &reg, sizeof(reg), req);
  344         if (error != 0 || req->newptr == NULL)
  345                 return (error);
  346 
  347         BCM_PWM_MEM_WRITE(sc, arg2, reg);
  348         return (0);
  349 }
  350 
  351 static void
  352 bcm_pwm_sysctl_init(struct bcm_pwm_softc *sc)
  353 {
  354         struct sysctl_ctx_list *ctx;
  355         struct sysctl_oid *tree_node;
  356         struct sysctl_oid_list *tree;
  357 
  358         /*
  359          * Add system sysctl tree/handlers.
  360          */
  361         ctx = device_get_sysctl_ctx(sc->sc_dev);
  362         tree_node = device_get_sysctl_tree(sc->sc_dev);
  363         tree = SYSCTL_CHILDREN(tree_node);
  364         if (bootverbose) {
  365 #define RR(x,y)                                                 \
  366         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, y,                 \
  367             CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_NEEDGIANT,      \
  368             sc, 0x##x,                                          \
  369             bcm_pwm_reg_proc, "IU", "Register 0x" #x " " y);
  370 
  371                 RR(24, "DAT2")
  372                 RR(20, "RNG2")
  373                 RR(18, "FIF1")
  374                 RR(14, "DAT1")
  375                 RR(10, "RNG1")
  376                 RR(08, "DMAC")
  377                 RR(04, "STA")
  378                 RR(00, "CTL")
  379 #undef RR
  380         }
  381 
  382         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "pwm_freq",
  383             CTLFLAG_RD | CTLTYPE_UINT | CTLFLAG_NEEDGIANT, sc, 0,
  384             bcm_pwm_pwm_freq_proc, "IU", "PWM frequency ch 1 (Hz)");
  385         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "period",
  386             CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_NEEDGIANT, sc, 0,
  387             bcm_pwm_period_proc, "IU", "PWM period ch 1 (#clocks)");
  388         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "ratio",
  389             CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_NEEDGIANT, sc, 0,
  390             bcm_pwm_ratio_proc, "IU", "PWM ratio ch 1 (0...period)");
  391         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "freq",
  392             CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_NEEDGIANT, sc, 0,
  393             bcm_pwm_freq_proc, "IU", "PWM clock (Hz)");
  394         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "mode",
  395             CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_NEEDGIANT, sc, 0,
  396             bcm_pwm_mode_proc, "IU", "PWM mode ch 1 (0=off, 1=pwm, 2=dither)");
  397         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "pwm_freq2",
  398             CTLFLAG_RD | CTLTYPE_UINT | CTLFLAG_NEEDGIANT, sc, 0,
  399             bcm_pwm_pwm_freq2_proc, "IU", "PWM frequency ch 2 (Hz)");
  400         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "period2",
  401             CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_NEEDGIANT, sc, 0,
  402             bcm_pwm_period2_proc, "IU", "PWM period ch 2 (#clocks)");
  403         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "ratio2",
  404             CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_NEEDGIANT, sc, 0,
  405             bcm_pwm_ratio2_proc, "IU", "PWM ratio ch 2 (0...period)");
  406         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "mode2",
  407             CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_NEEDGIANT, sc, 0,
  408             bcm_pwm_mode2_proc, "IU", "PWM mode ch 2 (0=off, 1=pwm, 2=dither)");
  409 }
  410 
  411 static int
  412 bcm_pwm_probe(device_t dev)
  413 {
  414 
  415         if (!ofw_bus_status_okay(dev))
  416                 return (ENXIO);
  417 
  418         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
  419                 return (ENXIO);
  420 
  421         device_set_desc(dev, "BCM2708/2835 PWM controller");
  422 
  423         return (BUS_PROBE_DEFAULT);
  424 }
  425 
  426 static int
  427 bcm_pwm_attach(device_t dev)
  428 {
  429         struct bcm_pwm_softc *sc;
  430         int rid;
  431 
  432         if (device_get_unit(dev) != 0) {
  433                 device_printf(dev, "only one PWM controller supported\n");
  434                 return (ENXIO);
  435         }
  436 
  437         sc = device_get_softc(dev);
  438         sc->sc_dev = dev;
  439 
  440         sc->clkman = devclass_get_device(devclass_find("bcm2835_clkman"), 0);
  441         if (sc->clkman == NULL) {
  442                 device_printf(dev, "cannot find Clock Manager\n");
  443                 return (ENXIO);
  444         }
  445 
  446         rid = 0;
  447         sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  448             RF_ACTIVE);
  449         if (!sc->sc_mem_res) {
  450                 device_printf(dev, "cannot allocate memory window\n");
  451                 return (ENXIO);
  452         }
  453 
  454         sc->sc_m_bst = rman_get_bustag(sc->sc_mem_res);
  455         sc->sc_m_bsh = rman_get_bushandle(sc->sc_mem_res);
  456 
  457         /* Add sysctl nodes. */
  458         bcm_pwm_sysctl_init(sc);
  459 
  460         sc->freq = 125000000; /* 125 Mhz */
  461         sc->period = 10000;   /* 12.5 khz */
  462         sc->ratio = 2500;     /* 25% */
  463         sc->period2 = 10000;  /* 12.5 khz */
  464         sc->ratio2 = 2500;    /* 25% */
  465 
  466         return (bus_generic_attach(dev));
  467 }
  468 
  469 static int
  470 bcm_pwm_detach(device_t dev)
  471 {
  472         struct bcm_pwm_softc *sc;
  473 
  474         bus_generic_detach(dev);
  475 
  476         sc = device_get_softc(dev);
  477         sc->mode = 0;
  478         sc->mode2 = 0;
  479         (void)bcm_pwm_reconf(sc);
  480         if (sc->sc_mem_res)
  481                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  482 
  483         return (0);
  484 }
  485 
  486 static phandle_t
  487 bcm_pwm_get_node(device_t bus, device_t dev)
  488 {
  489 
  490         return (ofw_bus_get_node(bus));
  491 }
  492 
  493 static device_method_t bcm_pwm_methods[] = {
  494         /* Device interface */
  495         DEVMETHOD(device_probe,         bcm_pwm_probe),
  496         DEVMETHOD(device_attach,        bcm_pwm_attach),
  497         DEVMETHOD(device_detach,        bcm_pwm_detach),
  498         DEVMETHOD(ofw_bus_get_node,     bcm_pwm_get_node),
  499 
  500         DEVMETHOD_END
  501 };
  502 
  503 static driver_t bcm_pwm_driver = {
  504         "pwm",
  505         bcm_pwm_methods,
  506         sizeof(struct bcm_pwm_softc),
  507 };
  508 
  509 DRIVER_MODULE(bcm2835_pwm, simplebus, bcm_pwm_driver, 0, 0);
  510 MODULE_DEPEND(bcm2835_pwm, bcm2835_clkman, 1, 1, 1);

Cache object: 5b7285a2028125f3fe61197c2bb76697


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