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/ti/am335x/am335x_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  * Copyright (c) 2013 Oleksandr Tymoshenko <gonzo@freebsd.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/10.2/sys/arm/ti/am335x/am335x_pwm.c 270237 2014-08-20 17:57:23Z loos $");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/bus.h>
   33 #include <sys/kernel.h>
   34 #include <sys/limits.h>
   35 #include <sys/lock.h>
   36 #include <sys/module.h>
   37 #include <sys/mutex.h>
   38 #include <sys/resource.h>
   39 #include <sys/rman.h>
   40 #include <sys/sysctl.h>
   41 
   42 #include <machine/bus.h>
   43 
   44 #include <dev/fdt/fdt_common.h>
   45 #include <dev/ofw/openfirm.h>
   46 #include <dev/ofw/ofw_bus.h>
   47 #include <dev/ofw/ofw_bus_subr.h>
   48 
   49 #include <arm/ti/ti_prcm.h>
   50 #include <arm/ti/ti_scm.h>
   51 
   52 #include "am335x_pwm.h"
   53 #include "am335x_scm.h"
   54 
   55 /* In ticks */
   56 #define DEFAULT_PWM_PERIOD      1000
   57 #define PWM_CLOCK               100000000UL
   58 
   59 #define PWM_LOCK(_sc)           mtx_lock(&(_sc)->sc_mtx)
   60 #define PWM_UNLOCK(_sc)         mtx_unlock(&(_sc)->sc_mtx)
   61 #define PWM_LOCK_INIT(_sc)      mtx_init(&(_sc)->sc_mtx, \
   62     device_get_nameunit(_sc->sc_dev), "am335x_pwm softc", MTX_DEF)
   63 #define PWM_LOCK_DESTROY(_sc)   mtx_destroy(&(_sc)->sc_mtx)
   64 
   65 static struct resource_spec am335x_pwm_mem_spec[] = {
   66         { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* PWMSS */
   67         { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* eCAP */
   68         { SYS_RES_MEMORY, 2, RF_ACTIVE }, /* eQEP */
   69         { SYS_RES_MEMORY, 3, RF_ACTIVE }, /*ePWM */
   70         { -1, 0, 0 }
   71 };
   72 
   73 #define PWMSS_READ4(_sc, reg)   bus_read_4((_sc)->sc_mem_res[0], reg);
   74 #define PWMSS_WRITE4(_sc, reg, value)   \
   75     bus_write_4((_sc)->sc_mem_res[0], reg, value);
   76 
   77 #define ECAP_READ2(_sc, reg)    bus_read_2((_sc)->sc_mem_res[1], reg);
   78 #define ECAP_WRITE2(_sc, reg, value)    \
   79     bus_write_2((_sc)->sc_mem_res[1], reg, value);
   80 #define ECAP_READ4(_sc, reg)    bus_read_4((_sc)->sc_mem_res[1], reg);
   81 #define ECAP_WRITE4(_sc, reg, value)    \
   82     bus_write_4((_sc)->sc_mem_res[1], reg, value);
   83 
   84 #define EPWM_READ2(_sc, reg)    bus_read_2((_sc)->sc_mem_res[3], reg);
   85 #define EPWM_WRITE2(_sc, reg, value)    \
   86     bus_write_2((_sc)->sc_mem_res[3], reg, value);
   87 
   88 #define PWMSS_IDVER             0x00
   89 #define PWMSS_SYSCONFIG         0x04
   90 #define PWMSS_CLKCONFIG         0x08
   91 #define         CLKCONFIG_EPWMCLK_EN    (1 << 8)
   92 #define PWMSS_CLKSTATUS         0x0C
   93 
   94 #define ECAP_TSCTR              0x00
   95 #define ECAP_CAP1               0x08
   96 #define ECAP_CAP2               0x0C
   97 #define ECAP_CAP3               0x10
   98 #define ECAP_CAP4               0x14
   99 #define ECAP_ECCTL2             0x2A
  100 #define         ECCTL2_MODE_APWM                (1 << 9)
  101 #define         ECCTL2_SYNCO_SEL                (3 << 6)
  102 #define         ECCTL2_TSCTRSTOP_FREERUN        (1 << 4)
  103 
  104 #define EPWM_TBCTL              0x00
  105 #define         TBCTL_FREERUN           (2 << 14)
  106 #define         TBCTL_PHDIR_UP          (1 << 13)
  107 #define         TBCTL_PHDIR_DOWN        (0 << 13)
  108 #define         TBCTL_CLKDIV(x)         ((x) << 10)
  109 #define         TBCTL_CLKDIV_MASK       (3 << 10)
  110 #define         TBCTL_HSPCLKDIV(x)      ((x) << 7)
  111 #define         TBCTL_HSPCLKDIV_MASK    (3 << 7)
  112 #define         TBCTL_SYNCOSEL_DISABLED (3 << 4)
  113 #define         TBCTL_PRDLD_SHADOW      (0 << 3)
  114 #define         TBCTL_PRDLD_IMMEDIATE   (0 << 3)
  115 #define         TBCTL_PHSEN_ENABLED     (1 << 2)
  116 #define         TBCTL_PHSEN_DISABLED    (0 << 2)
  117 #define         TBCTL_CTRMODE_MASK      (3)
  118 #define         TBCTL_CTRMODE_UP        (0 << 0)
  119 #define         TBCTL_CTRMODE_DOWN      (1 << 0)
  120 #define         TBCTL_CTRMODE_UPDOWN    (2 << 0)
  121 #define         TBCTL_CTRMODE_FREEZE    (3 << 0)
  122 
  123 #define EPWM_TBSTS              0x02
  124 #define EPWM_TBPHSHR            0x04
  125 #define EPWM_TBPHS              0x06
  126 #define EPWM_TBCNT              0x08
  127 #define EPWM_TBPRD              0x0a
  128 /* Counter-compare */
  129 #define EPWM_CMPCTL             0x0e
  130 #define         CMPCTL_SHDWBMODE_SHADOW         (1 << 6)
  131 #define         CMPCTL_SHDWBMODE_IMMEDIATE      (0 << 6)
  132 #define         CMPCTL_SHDWAMODE_SHADOW         (1 << 4)
  133 #define         CMPCTL_SHDWAMODE_IMMEDIATE      (0 << 4)
  134 #define         CMPCTL_LOADBMODE_ZERO           (0 << 2)
  135 #define         CMPCTL_LOADBMODE_PRD            (1 << 2)
  136 #define         CMPCTL_LOADBMODE_EITHER         (2 << 2)
  137 #define         CMPCTL_LOADBMODE_FREEZE         (3 << 2)
  138 #define         CMPCTL_LOADAMODE_ZERO           (0 << 0)
  139 #define         CMPCTL_LOADAMODE_PRD            (1 << 0)
  140 #define         CMPCTL_LOADAMODE_EITHER         (2 << 0)
  141 #define         CMPCTL_LOADAMODE_FREEZE         (3 << 0)
  142 #define EPWM_CMPAHR             0x10
  143 #define EPWM_CMPA               0x12
  144 #define EPWM_CMPB               0x14
  145 /* CMPCTL_LOADAMODE_ZERO */
  146 #define EPWM_AQCTLA             0x16
  147 #define EPWM_AQCTLB             0x18
  148 #define         AQCTL_CBU_NONE          (0 << 8)
  149 #define         AQCTL_CBU_CLEAR         (1 << 8)
  150 #define         AQCTL_CBU_SET           (2 << 8)
  151 #define         AQCTL_CBU_TOGGLE        (3 << 8)
  152 #define         AQCTL_CAU_NONE          (0 << 4)
  153 #define         AQCTL_CAU_CLEAR         (1 << 4)
  154 #define         AQCTL_CAU_SET           (2 << 4)
  155 #define         AQCTL_CAU_TOGGLE        (3 << 4)
  156 #define         AQCTL_ZRO_NONE          (0 << 0)
  157 #define         AQCTL_ZRO_CLEAR         (1 << 0)
  158 #define         AQCTL_ZRO_SET           (2 << 0)
  159 #define         AQCTL_ZRO_TOGGLE        (3 << 0)
  160 #define EPWM_AQSFRC             0x1a
  161 #define EPWM_AQCSFRC            0x1c
  162 
  163 /* Trip-Zone module */
  164 #define EPWM_TZCTL              0x28
  165 #define EPWM_TZFLG              0x2C
  166 /* High-Resolution PWM */
  167 #define EPWM_HRCTL              0x40
  168 #define         HRCTL_DELMODE_BOTH      3
  169 #define         HRCTL_DELMODE_FALL      2
  170 #define         HRCTL_DELMODE_RISE      1
  171 
  172 static device_probe_t am335x_pwm_probe;
  173 static device_attach_t am335x_pwm_attach;
  174 static device_detach_t am335x_pwm_detach;
  175         
  176 static int am335x_pwm_clkdiv[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
  177 
  178 struct am335x_pwm_softc {
  179         device_t                sc_dev;
  180         struct mtx              sc_mtx;
  181         struct resource         *sc_mem_res[4];
  182         int                     sc_id;
  183         /* sysctl for configuration */
  184         int                     sc_pwm_clkdiv;
  185         int                     sc_pwm_freq;
  186         struct sysctl_oid       *sc_clkdiv_oid;
  187         struct sysctl_oid       *sc_freq_oid;
  188         struct sysctl_oid       *sc_period_oid;
  189         struct sysctl_oid       *sc_chanA_oid;
  190         struct sysctl_oid       *sc_chanB_oid;
  191         uint32_t                sc_pwm_period;
  192         uint32_t                sc_pwm_dutyA;
  193         uint32_t                sc_pwm_dutyB;
  194 };
  195 
  196 static device_method_t am335x_pwm_methods[] = {
  197         DEVMETHOD(device_probe,         am335x_pwm_probe),
  198         DEVMETHOD(device_attach,        am335x_pwm_attach),
  199         DEVMETHOD(device_detach,        am335x_pwm_detach),
  200 
  201         DEVMETHOD_END
  202 };
  203 
  204 static driver_t am335x_pwm_driver = {
  205         "am335x_pwm",
  206         am335x_pwm_methods,
  207         sizeof(struct am335x_pwm_softc),
  208 };
  209 
  210 static devclass_t am335x_pwm_devclass;
  211 
  212 /*
  213  * API function to set period/duty cycles for ECASx 
  214  */
  215 int
  216 am335x_pwm_config_ecas(int unit, int period, int duty)
  217 {
  218         device_t dev;
  219         struct am335x_pwm_softc *sc;
  220         uint16_t reg;
  221 
  222         dev = devclass_get_device(am335x_pwm_devclass, unit);
  223         if (dev == NULL)
  224                 return (ENXIO);
  225 
  226         if (duty > period)
  227                 return (EINVAL);
  228 
  229         if (period == 0)
  230                 return (EINVAL);
  231 
  232         sc = device_get_softc(dev);
  233         PWM_LOCK(sc);
  234 
  235         reg = ECAP_READ2(sc, ECAP_ECCTL2);
  236         reg |= ECCTL2_MODE_APWM | ECCTL2_TSCTRSTOP_FREERUN | ECCTL2_SYNCO_SEL;
  237         ECAP_WRITE2(sc, ECAP_ECCTL2, reg);
  238 
  239         /* CAP3 in APWM mode is APRD shadow register */
  240         ECAP_WRITE4(sc, ECAP_CAP3, period - 1);
  241 
  242         /* CAP4 in APWM mode is ACMP shadow register */
  243         ECAP_WRITE4(sc, ECAP_CAP4, duty);
  244         /* Restart counter */
  245         ECAP_WRITE4(sc, ECAP_TSCTR, 0);
  246 
  247         PWM_UNLOCK(sc);
  248 
  249         return (0);
  250 }
  251 
  252 static void
  253 am335x_pwm_freq(struct am335x_pwm_softc *sc)
  254 {
  255         int clkdiv;
  256 
  257         clkdiv = am335x_pwm_clkdiv[sc->sc_pwm_clkdiv];
  258         sc->sc_pwm_freq = PWM_CLOCK / (1 * clkdiv) / sc->sc_pwm_period;
  259 }
  260 
  261 static int
  262 am335x_pwm_sysctl_freq(SYSCTL_HANDLER_ARGS)
  263 {
  264         int clkdiv, error, freq, i, period;
  265         struct am335x_pwm_softc *sc;
  266         uint32_t reg;
  267 
  268         sc = (struct am335x_pwm_softc *)arg1;
  269 
  270         PWM_LOCK(sc);
  271         freq = sc->sc_pwm_freq;
  272         PWM_UNLOCK(sc);
  273 
  274         error = sysctl_handle_int(oidp, &freq, sizeof(freq), req);
  275         if (error != 0 || req->newptr == NULL)
  276                 return (error);
  277 
  278         if (freq > PWM_CLOCK)
  279                 freq = PWM_CLOCK;
  280 
  281         PWM_LOCK(sc);
  282         if (freq != sc->sc_pwm_freq) {
  283                 for (i = nitems(am335x_pwm_clkdiv) - 1; i >= 0; i--) {
  284                         clkdiv = am335x_pwm_clkdiv[i];
  285                         period = PWM_CLOCK / clkdiv / freq;
  286                         if (period > USHRT_MAX)
  287                                 break;
  288                         sc->sc_pwm_clkdiv = i;
  289                         sc->sc_pwm_period = period;
  290                 }
  291                 /* Reset the duty cycle settings. */
  292                 sc->sc_pwm_dutyA = 0;
  293                 sc->sc_pwm_dutyB = 0;
  294                 EPWM_WRITE2(sc, EPWM_CMPA, sc->sc_pwm_dutyA);
  295                 EPWM_WRITE2(sc, EPWM_CMPB, sc->sc_pwm_dutyB);
  296                 /* Update the clkdiv settings. */
  297                 reg = EPWM_READ2(sc, EPWM_TBCTL);
  298                 reg &= ~TBCTL_CLKDIV_MASK;
  299                 reg |= TBCTL_CLKDIV(sc->sc_pwm_clkdiv);
  300                 EPWM_WRITE2(sc, EPWM_TBCTL, reg);
  301                 /* Update the period settings. */
  302                 EPWM_WRITE2(sc, EPWM_TBPRD, sc->sc_pwm_period - 1);
  303                 am335x_pwm_freq(sc);
  304         }
  305         PWM_UNLOCK(sc);
  306 
  307         return (0);
  308 }
  309 
  310 static int
  311 am335x_pwm_sysctl_clkdiv(SYSCTL_HANDLER_ARGS)
  312 {
  313         int error, i, clkdiv;
  314         struct am335x_pwm_softc *sc;
  315         uint32_t reg;
  316 
  317         sc = (struct am335x_pwm_softc *)arg1;
  318 
  319         PWM_LOCK(sc);
  320         clkdiv = am335x_pwm_clkdiv[sc->sc_pwm_clkdiv];
  321         PWM_UNLOCK(sc);
  322 
  323         error = sysctl_handle_int(oidp, &clkdiv, sizeof(clkdiv), req);
  324         if (error != 0 || req->newptr == NULL)
  325                 return (error);
  326 
  327         PWM_LOCK(sc);
  328         if (clkdiv != am335x_pwm_clkdiv[sc->sc_pwm_clkdiv]) {
  329                 for (i = 0; i < nitems(am335x_pwm_clkdiv); i++)
  330                         if (clkdiv >= am335x_pwm_clkdiv[i])
  331                                 sc->sc_pwm_clkdiv = i;
  332 
  333                 reg = EPWM_READ2(sc, EPWM_TBCTL);
  334                 reg &= ~TBCTL_CLKDIV_MASK;
  335                 reg |= TBCTL_CLKDIV(sc->sc_pwm_clkdiv);
  336                 EPWM_WRITE2(sc, EPWM_TBCTL, reg);
  337                 am335x_pwm_freq(sc);
  338         }
  339         PWM_UNLOCK(sc);
  340 
  341         return (0);
  342 }
  343 
  344 static int
  345 am335x_pwm_sysctl_duty(SYSCTL_HANDLER_ARGS)
  346 {
  347         struct am335x_pwm_softc *sc = (struct am335x_pwm_softc*)arg1;
  348         int error;
  349         uint32_t duty;
  350        
  351         if (oidp == sc->sc_chanA_oid)
  352                 duty = sc->sc_pwm_dutyA;
  353         else
  354                 duty = sc->sc_pwm_dutyB;
  355         error = sysctl_handle_int(oidp, &duty, 0, req);
  356 
  357         if (error != 0 || req->newptr == NULL)
  358                 return (error);
  359 
  360         if (duty > sc->sc_pwm_period) {
  361                 device_printf(sc->sc_dev, "Duty cycle can't be greater then period\n");
  362                 return (EINVAL);
  363         }
  364 
  365         PWM_LOCK(sc);
  366         if (oidp == sc->sc_chanA_oid) {
  367                 sc->sc_pwm_dutyA = duty;
  368                 EPWM_WRITE2(sc, EPWM_CMPA, sc->sc_pwm_dutyA);
  369         }
  370         else {
  371                 sc->sc_pwm_dutyB = duty;
  372                 EPWM_WRITE2(sc, EPWM_CMPB, sc->sc_pwm_dutyB);
  373         }
  374         PWM_UNLOCK(sc);
  375 
  376         return (error);
  377 }
  378 
  379 static int
  380 am335x_pwm_sysctl_period(SYSCTL_HANDLER_ARGS)
  381 {
  382         struct am335x_pwm_softc *sc = (struct am335x_pwm_softc*)arg1;
  383         int error;
  384         uint32_t period;
  385        
  386         period = sc->sc_pwm_period;
  387         error = sysctl_handle_int(oidp, &period, 0, req);
  388 
  389         if (error != 0 || req->newptr == NULL)
  390                 return (error);
  391 
  392         if (period < 1)
  393                 return (EINVAL);
  394 
  395         if (period > USHRT_MAX)
  396                 period = USHRT_MAX;
  397 
  398         PWM_LOCK(sc);
  399         /* Reset the duty cycle settings. */
  400         sc->sc_pwm_dutyA = 0;
  401         sc->sc_pwm_dutyB = 0;
  402         EPWM_WRITE2(sc, EPWM_CMPA, sc->sc_pwm_dutyA);
  403         EPWM_WRITE2(sc, EPWM_CMPB, sc->sc_pwm_dutyB);
  404         /* Update the period settings. */
  405         sc->sc_pwm_period = period;
  406         EPWM_WRITE2(sc, EPWM_TBPRD, period - 1);
  407         am335x_pwm_freq(sc);
  408         PWM_UNLOCK(sc);
  409 
  410         return (error);
  411 }
  412 
  413 static int
  414 am335x_pwm_probe(device_t dev)
  415 {
  416 
  417         if (!ofw_bus_status_okay(dev))
  418                 return (ENXIO);
  419 
  420         if (!ofw_bus_is_compatible(dev, "ti,am335x-pwm"))
  421                 return (ENXIO);
  422 
  423         device_set_desc(dev, "AM335x PWM");
  424 
  425         return (BUS_PROBE_DEFAULT);
  426 }
  427 
  428 static int
  429 am335x_pwm_attach(device_t dev)
  430 {
  431         struct am335x_pwm_softc *sc;
  432         int err;
  433         uint32_t reg;
  434         phandle_t node;
  435         pcell_t did;
  436         struct sysctl_ctx_list *ctx;
  437         struct sysctl_oid *tree;
  438 
  439         sc = device_get_softc(dev);
  440         sc->sc_dev = dev;
  441         /* Get the PWM module id */
  442         node = ofw_bus_get_node(dev);
  443         if ((OF_getprop(node, "pwm-device-id", &did, sizeof(did))) <= 0) {
  444                 device_printf(dev, "missing pwm-device-id attribute in FDT\n");
  445                 return (ENXIO);
  446         }
  447         sc->sc_id = fdt32_to_cpu(did);
  448 
  449         PWM_LOCK_INIT(sc);
  450 
  451         err = bus_alloc_resources(dev, am335x_pwm_mem_spec,
  452             sc->sc_mem_res);
  453         if (err) {
  454                 device_printf(dev, "cannot allocate memory resources\n");
  455                 goto fail;
  456         }
  457 
  458         ti_prcm_clk_enable(PWMSS0_CLK + sc->sc_id);
  459         ti_scm_reg_read_4(SCM_PWMSS_CTRL, &reg);
  460         reg |= (1 << sc->sc_id);
  461         ti_scm_reg_write_4(SCM_PWMSS_CTRL, reg);
  462 
  463         /* Init backlight interface */
  464         ctx = device_get_sysctl_ctx(sc->sc_dev);
  465         tree = device_get_sysctl_tree(sc->sc_dev);
  466 
  467         sc->sc_clkdiv_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
  468             "clkdiv", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
  469             am335x_pwm_sysctl_clkdiv, "I", "PWM clock prescaler");
  470 
  471         sc->sc_freq_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
  472             "freq", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
  473             am335x_pwm_sysctl_freq, "I", "PWM frequency");
  474 
  475         sc->sc_period_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
  476             "period", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
  477             am335x_pwm_sysctl_period, "I", "PWM period");
  478 
  479         sc->sc_chanA_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
  480             "dutyA", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
  481             am335x_pwm_sysctl_duty, "I", "Channel A duty cycles");
  482 
  483         sc->sc_chanB_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
  484             "dutyB", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
  485             am335x_pwm_sysctl_duty, "I", "Channel B duty cycles");
  486 
  487         /* CONFIGURE EPWM1 */
  488         reg = EPWM_READ2(sc, EPWM_TBCTL);
  489         reg &= ~(TBCTL_CLKDIV_MASK | TBCTL_HSPCLKDIV_MASK);
  490         EPWM_WRITE2(sc, EPWM_TBCTL, reg);
  491 
  492         sc->sc_pwm_period = DEFAULT_PWM_PERIOD;
  493         sc->sc_pwm_dutyA = 0;
  494         sc->sc_pwm_dutyB = 0;
  495         am335x_pwm_freq(sc);
  496 
  497         EPWM_WRITE2(sc, EPWM_TBPRD, sc->sc_pwm_period - 1);
  498         EPWM_WRITE2(sc, EPWM_CMPA, sc->sc_pwm_dutyA);
  499         EPWM_WRITE2(sc, EPWM_CMPB, sc->sc_pwm_dutyB);
  500 
  501         EPWM_WRITE2(sc, EPWM_AQCTLA, (AQCTL_ZRO_SET | AQCTL_CAU_CLEAR));
  502         EPWM_WRITE2(sc, EPWM_AQCTLB, (AQCTL_ZRO_SET | AQCTL_CBU_CLEAR));
  503 
  504         /* START EPWM */
  505         reg &= ~TBCTL_CTRMODE_MASK;
  506         reg |= TBCTL_CTRMODE_UP | TBCTL_FREERUN;
  507         EPWM_WRITE2(sc, EPWM_TBCTL, reg);
  508 
  509         EPWM_WRITE2(sc, EPWM_TZCTL, 0xf);
  510         reg = EPWM_READ2(sc, EPWM_TZFLG);
  511 
  512         return (0);
  513 fail:
  514         PWM_LOCK_DESTROY(sc);
  515         if (sc->sc_mem_res[0])
  516                 bus_release_resources(dev, am335x_pwm_mem_spec,
  517                     sc->sc_mem_res);
  518 
  519         return(ENXIO);
  520 }
  521 
  522 static int
  523 am335x_pwm_detach(device_t dev)
  524 {
  525         struct am335x_pwm_softc *sc;
  526 
  527         sc = device_get_softc(dev);
  528 
  529         PWM_LOCK(sc);
  530         if (sc->sc_mem_res[0])
  531                 bus_release_resources(dev, am335x_pwm_mem_spec,
  532                     sc->sc_mem_res);
  533         PWM_UNLOCK(sc);
  534 
  535         PWM_LOCK_DESTROY(sc);
  536 
  537         return (0);
  538 }
  539 
  540 DRIVER_MODULE(am335x_pwm, simplebus, am335x_pwm_driver, am335x_pwm_devclass, 0, 0);
  541 MODULE_VERSION(am335x_pwm, 1);
  542 MODULE_DEPEND(am335x_pwm, simplebus, 1, 1, 1);

Cache object: 248d9a44605962588c5623821ecd1d95


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