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 #include <sys/param.h> 29 #include <sys/systm.h> 30 #include <sys/bus.h> 31 #include <sys/kernel.h> 32 #include <sys/limits.h> 33 #include <sys/lock.h> 34 #include <sys/module.h> 35 #include <sys/mutex.h> 36 #include <sys/resource.h> 37 #include <sys/rman.h> 38 39 #include <machine/bus.h> 40 41 #include <dev/ofw/openfirm.h> 42 #include <dev/ofw/ofw_bus.h> 43 #include <dev/ofw/ofw_bus_subr.h> 44 45 #include <dev/pwm/pwmc.h> 46 47 #include "pwmbus_if.h" 48 49 #include "am335x_pwm.h" 50 51 /******************************************************************************* 52 * Enhanced resolution PWM driver. Many of the advanced featues of the hardware 53 * are not supported by this driver. What is implemented here is simple 54 * variable-duty-cycle PWM output. 55 ******************************************************************************/ 56 57 /* In ticks */ 58 #define DEFAULT_PWM_PERIOD 1000 59 #define PWM_CLOCK 100000000UL 60 61 #define NS_PER_SEC 1000000000 62 63 #define PWM_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 64 #define PWM_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 65 #define PWM_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED) 66 #define PWM_LOCK_INIT(_sc) mtx_init(&(_sc)->sc_mtx, \ 67 device_get_nameunit(_sc->sc_dev), "am335x_ehrpwm softc", MTX_DEF) 68 #define PWM_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) 69 70 #define EPWM_READ2(_sc, reg) bus_read_2((_sc)->sc_mem_res, reg) 71 #define EPWM_WRITE2(_sc, reg, value) \ 72 bus_write_2((_sc)->sc_mem_res, reg, value) 73 74 #define EPWM_TBCTL 0x00 75 /* see 15.2.2.11 for the first two, used in debug situations */ 76 #define TBCTL_FREERUN_STOP_NEXT_TBC_INCREMENT (0 << 14) 77 #define TBCTL_FREERUN_STOP_COMPLETE_CYCLE (1 << 14) 78 /* ignore suspend control signal */ 79 #define TBCTL_FREERUN (2 << 14) 80 81 #define TBCTL_PHDIR_UP (1 << 13) 82 #define TBCTL_PHDIR_DOWN (0 << 13) 83 #define TBCTL_CLKDIV(x) ((x) << 10) 84 #define TBCTL_CLKDIV_MASK (7 << 10) 85 #define TBCTL_HSPCLKDIV(x) ((x) << 7) 86 #define TBCTL_HSPCLKDIV_MASK (7 << 7) 87 #define TBCTL_SYNCOSEL_DISABLED (3 << 4) 88 #define TBCTL_PRDLD_SHADOW (0 << 3) 89 #define TBCTL_PRDLD_IMMEDIATE (1 << 3) 90 #define TBCTL_PHSEN_DISABLED (0 << 2) 91 #define TBCTL_PHSEN_ENABLED (1 << 2) 92 #define TBCTL_CTRMODE_MASK (3) 93 #define TBCTL_CTRMODE_UP (0 << 0) 94 #define TBCTL_CTRMODE_DOWN (1 << 0) 95 #define TBCTL_CTRMODE_UPDOWN (2 << 0) 96 #define TBCTL_CTRMODE_FREEZE (3 << 0) 97 98 #define EPWM_TBSTS 0x02 99 #define EPWM_TBPHSHR 0x04 100 #define EPWM_TBPHS 0x06 101 #define EPWM_TBCNT 0x08 102 #define EPWM_TBPRD 0x0a 103 /* Counter-compare */ 104 #define EPWM_CMPCTL 0x0e 105 #define CMPCTL_SHDWBMODE_SHADOW (1 << 6) 106 #define CMPCTL_SHDWBMODE_IMMEDIATE (0 << 6) 107 #define CMPCTL_SHDWAMODE_SHADOW (1 << 4) 108 #define CMPCTL_SHDWAMODE_IMMEDIATE (0 << 4) 109 #define CMPCTL_LOADBMODE_ZERO (0 << 2) 110 #define CMPCTL_LOADBMODE_PRD (1 << 2) 111 #define CMPCTL_LOADBMODE_EITHER (2 << 2) 112 #define CMPCTL_LOADBMODE_FREEZE (3 << 2) 113 #define CMPCTL_LOADAMODE_ZERO (0 << 0) 114 #define CMPCTL_LOADAMODE_PRD (1 << 0) 115 #define CMPCTL_LOADAMODE_EITHER (2 << 0) 116 #define CMPCTL_LOADAMODE_FREEZE (3 << 0) 117 #define EPWM_CMPAHR 0x10 118 #define EPWM_CMPA 0x12 119 #define EPWM_CMPB 0x14 120 /* CMPCTL_LOADAMODE_ZERO */ 121 #define EPWM_AQCTLA 0x16 122 #define EPWM_AQCTLB 0x18 123 #define AQCTL_CBU_NONE (0 << 8) 124 #define AQCTL_CBU_CLEAR (1 << 8) 125 #define AQCTL_CBU_SET (2 << 8) 126 #define AQCTL_CBU_TOGGLE (3 << 8) 127 #define AQCTL_CAU_NONE (0 << 4) 128 #define AQCTL_CAU_CLEAR (1 << 4) 129 #define AQCTL_CAU_SET (2 << 4) 130 #define AQCTL_CAU_TOGGLE (3 << 4) 131 #define AQCTL_ZRO_NONE (0 << 0) 132 #define AQCTL_ZRO_CLEAR (1 << 0) 133 #define AQCTL_ZRO_SET (2 << 0) 134 #define AQCTL_ZRO_TOGGLE (3 << 0) 135 #define EPWM_AQSFRC 0x1a 136 #define EPWM_AQCSFRC 0x1c 137 #define AQCSFRC_OFF 0 138 #define AQCSFRC_LO 1 139 #define AQCSFRC_HI 2 140 #define AQCSFRC_MASK 3 141 #define AQCSFRC(chan, hilo) ((hilo) << (2 * chan)) 142 143 /* Trip-Zone module */ 144 #define EPWM_TZSEL 0x24 145 #define EPWM_TZCTL 0x28 146 #define EPWM_TZFLG 0x2C 147 148 /* Dead band */ 149 #define EPWM_DBCTL 0x1E 150 #define DBCTL_MASK (3 << 0) 151 #define DBCTL_BYPASS 0 152 #define DBCTL_RISING_EDGE 1 153 #define DBCTL_FALLING_EDGE 2 154 #define DBCTL_BOTH_EDGE 3 155 156 /* PWM-chopper */ 157 #define EPWM_PCCTL 0x3C 158 #define PCCTL_CHPEN_MASK (1 << 0) 159 #define PCCTL_CHPEN_DISABLE 0 160 #define PCCTL_CHPEN_ENABLE 1 161 162 /* High-Resolution PWM */ 163 #define EPWM_HRCTL 0x40 164 #define HRCTL_DELMODE_BOTH 3 165 #define HRCTL_DELMODE_FALL 2 166 #define HRCTL_DELMODE_RISE 1 167 168 static device_probe_t am335x_ehrpwm_probe; 169 static device_attach_t am335x_ehrpwm_attach; 170 static device_detach_t am335x_ehrpwm_detach; 171 172 struct ehrpwm_channel { 173 u_int duty; /* on duration, in ns */ 174 bool enabled; /* channel enabled? */ 175 bool inverted; /* signal inverted? */ 176 }; 177 #define NUM_CHANNELS 2 178 179 struct am335x_ehrpwm_softc { 180 device_t sc_dev; 181 device_t sc_busdev; 182 struct mtx sc_mtx; 183 struct resource *sc_mem_res; 184 int sc_mem_rid; 185 186 /* Things used for configuration via pwm(9) api. */ 187 u_int sc_clkfreq; /* frequency in Hz */ 188 u_int sc_clktick; /* duration in ns */ 189 u_int sc_period; /* duration in ns */ 190 struct ehrpwm_channel sc_channels[NUM_CHANNELS]; 191 }; 192 193 static struct ofw_compat_data compat_data[] = { 194 {"ti,am3352-ehrpwm", true}, 195 {"ti,am33xx-ehrpwm", true}, 196 {NULL, false}, 197 }; 198 SIMPLEBUS_PNP_INFO(compat_data); 199 200 static void 201 am335x_ehrpwm_cfg_duty(struct am335x_ehrpwm_softc *sc, u_int chan, u_int duty) 202 { 203 u_int tbcmp; 204 205 if (duty == 0) 206 tbcmp = 0; 207 else 208 tbcmp = max(1, duty / sc->sc_clktick); 209 210 sc->sc_channels[chan].duty = tbcmp * sc->sc_clktick; 211 212 PWM_LOCK_ASSERT(sc); 213 EPWM_WRITE2(sc, (chan == 0) ? EPWM_CMPA : EPWM_CMPB, tbcmp); 214 } 215 216 static void 217 am335x_ehrpwm_cfg_enable(struct am335x_ehrpwm_softc *sc, u_int chan, bool enable) 218 { 219 uint16_t regval; 220 221 sc->sc_channels[chan].enabled = enable; 222 223 /* 224 * Turn off any existing software-force of the channel, then force 225 * it in the right direction (high or low) if it's not being enabled. 226 */ 227 PWM_LOCK_ASSERT(sc); 228 regval = EPWM_READ2(sc, EPWM_AQCSFRC); 229 regval &= ~AQCSFRC(chan, AQCSFRC_MASK); 230 if (!sc->sc_channels[chan].enabled) { 231 if (sc->sc_channels[chan].inverted) 232 regval |= AQCSFRC(chan, AQCSFRC_HI); 233 else 234 regval |= AQCSFRC(chan, AQCSFRC_LO); 235 } 236 EPWM_WRITE2(sc, EPWM_AQCSFRC, regval); 237 } 238 239 static bool 240 am335x_ehrpwm_cfg_period(struct am335x_ehrpwm_softc *sc, u_int period) 241 { 242 uint16_t regval; 243 u_int clkdiv, hspclkdiv, pwmclk, pwmtick, tbprd; 244 245 /* Can't do a period shorter than 2 clock ticks. */ 246 if (period < 2 * NS_PER_SEC / PWM_CLOCK) { 247 sc->sc_clkfreq = 0; 248 sc->sc_clktick = 0; 249 sc->sc_period = 0; 250 return (false); 251 } 252 253 /* 254 * Figure out how much we have to divide down the base 100MHz clock so 255 * that we can express the requested period as a 16-bit tick count. 256 */ 257 tbprd = 0; 258 for (clkdiv = 0; clkdiv < 8; ++clkdiv) { 259 const u_int cd = 1 << clkdiv; 260 for (hspclkdiv = 0; hspclkdiv < 8; ++hspclkdiv) { 261 const u_int cdhs = max(1, hspclkdiv * 2); 262 pwmclk = PWM_CLOCK / (cd * cdhs); 263 pwmtick = NS_PER_SEC / pwmclk; 264 if (period / pwmtick < 65536) { 265 tbprd = period / pwmtick; 266 break; 267 } 268 } 269 if (tbprd != 0) 270 break; 271 } 272 273 /* Handle requested period too long for available clock divisors. */ 274 if (tbprd == 0) 275 return (false); 276 277 /* 278 * If anything has changed from the current settings, reprogram the 279 * clock divisors and period register. 280 */ 281 if (sc->sc_clkfreq != pwmclk || sc->sc_clktick != pwmtick || 282 sc->sc_period != tbprd * pwmtick) { 283 sc->sc_clkfreq = pwmclk; 284 sc->sc_clktick = pwmtick; 285 sc->sc_period = tbprd * pwmtick; 286 287 PWM_LOCK_ASSERT(sc); 288 regval = EPWM_READ2(sc, EPWM_TBCTL); 289 regval &= ~(TBCTL_CLKDIV_MASK | TBCTL_HSPCLKDIV_MASK); 290 regval |= TBCTL_CLKDIV(clkdiv) | TBCTL_HSPCLKDIV(hspclkdiv); 291 EPWM_WRITE2(sc, EPWM_TBCTL, regval); 292 EPWM_WRITE2(sc, EPWM_TBPRD, tbprd - 1); 293 #if 0 294 device_printf(sc->sc_dev, "clkdiv %u hspclkdiv %u tbprd %u " 295 "clkfreq %u Hz clktick %u ns period got %u requested %u\n", 296 clkdiv, hspclkdiv, tbprd - 1, 297 sc->sc_clkfreq, sc->sc_clktick, sc->sc_period, period); 298 #endif 299 /* 300 * If the period changed, that invalidates the current CMP 301 * registers (duty values), just zero them out. 302 */ 303 am335x_ehrpwm_cfg_duty(sc, 0, 0); 304 am335x_ehrpwm_cfg_duty(sc, 1, 0); 305 } 306 307 return (true); 308 } 309 310 static int 311 am335x_ehrpwm_channel_count(device_t dev, u_int *nchannel) 312 { 313 314 *nchannel = NUM_CHANNELS; 315 316 return (0); 317 } 318 319 static int 320 am335x_ehrpwm_channel_config(device_t dev, u_int channel, u_int period, u_int duty) 321 { 322 struct am335x_ehrpwm_softc *sc; 323 bool status; 324 325 if (channel >= NUM_CHANNELS) 326 return (EINVAL); 327 328 sc = device_get_softc(dev); 329 330 PWM_LOCK(sc); 331 status = am335x_ehrpwm_cfg_period(sc, period); 332 if (status) 333 am335x_ehrpwm_cfg_duty(sc, channel, duty); 334 PWM_UNLOCK(sc); 335 336 return (status ? 0 : EINVAL); 337 } 338 339 static int 340 am335x_ehrpwm_channel_get_config(device_t dev, u_int channel, 341 u_int *period, u_int *duty) 342 { 343 struct am335x_ehrpwm_softc *sc; 344 345 if (channel >= NUM_CHANNELS) 346 return (EINVAL); 347 348 sc = device_get_softc(dev); 349 *period = sc->sc_period; 350 *duty = sc->sc_channels[channel].duty; 351 return (0); 352 } 353 354 static int 355 am335x_ehrpwm_channel_set_flags(device_t dev, u_int channel, 356 uint32_t flags) 357 { 358 struct am335x_ehrpwm_softc *sc; 359 360 if (channel >= NUM_CHANNELS) 361 return (EINVAL); 362 363 sc = device_get_softc(dev); 364 365 PWM_LOCK(sc); 366 if (flags & PWM_POLARITY_INVERTED) { 367 sc->sc_channels[channel].inverted = true; 368 /* Action-Qualifier 15.2.2.5 */ 369 if (channel == 0) 370 EPWM_WRITE2(sc, EPWM_AQCTLA, 371 (AQCTL_ZRO_CLEAR | AQCTL_CAU_SET)); 372 else 373 EPWM_WRITE2(sc, EPWM_AQCTLB, 374 (AQCTL_ZRO_CLEAR | AQCTL_CBU_SET)); 375 } else { 376 sc->sc_channels[channel].inverted = false; 377 if (channel == 0) 378 EPWM_WRITE2(sc, EPWM_AQCTLA, 379 (AQCTL_ZRO_SET | AQCTL_CAU_CLEAR)); 380 else 381 EPWM_WRITE2(sc, EPWM_AQCTLB, 382 (AQCTL_ZRO_SET | AQCTL_CBU_CLEAR)); 383 } 384 PWM_UNLOCK(sc); 385 386 return (0); 387 } 388 389 static int 390 am335x_ehrpwm_channel_get_flags(device_t dev, u_int channel, 391 uint32_t *flags) 392 { 393 struct am335x_ehrpwm_softc *sc; 394 if (channel >= NUM_CHANNELS) 395 return (EINVAL); 396 397 sc = device_get_softc(dev); 398 399 if (sc->sc_channels[channel].inverted == true) 400 *flags = PWM_POLARITY_INVERTED; 401 else 402 *flags = 0; 403 404 return (0); 405 } 406 407 408 static int 409 am335x_ehrpwm_channel_enable(device_t dev, u_int channel, bool enable) 410 { 411 struct am335x_ehrpwm_softc *sc; 412 413 if (channel >= NUM_CHANNELS) 414 return (EINVAL); 415 416 sc = device_get_softc(dev); 417 418 PWM_LOCK(sc); 419 am335x_ehrpwm_cfg_enable(sc, channel, enable); 420 PWM_UNLOCK(sc); 421 422 return (0); 423 } 424 425 static int 426 am335x_ehrpwm_channel_is_enabled(device_t dev, u_int channel, bool *enabled) 427 { 428 struct am335x_ehrpwm_softc *sc; 429 430 if (channel >= NUM_CHANNELS) 431 return (EINVAL); 432 433 sc = device_get_softc(dev); 434 435 *enabled = sc->sc_channels[channel].enabled; 436 437 return (0); 438 } 439 440 static int 441 am335x_ehrpwm_probe(device_t dev) 442 { 443 444 if (!ofw_bus_status_okay(dev)) 445 return (ENXIO); 446 447 if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 448 return (ENXIO); 449 450 device_set_desc(dev, "AM335x EHRPWM"); 451 452 return (BUS_PROBE_DEFAULT); 453 } 454 455 static int 456 am335x_ehrpwm_attach(device_t dev) 457 { 458 struct am335x_ehrpwm_softc *sc; 459 uint16_t reg; 460 461 sc = device_get_softc(dev); 462 sc->sc_dev = dev; 463 464 PWM_LOCK_INIT(sc); 465 466 sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 467 &sc->sc_mem_rid, RF_ACTIVE); 468 if (sc->sc_mem_res == NULL) { 469 device_printf(dev, "cannot allocate memory resources\n"); 470 goto fail; 471 } 472 473 /* CONFIGURE EPWM */ 474 reg = EPWM_READ2(sc, EPWM_TBCTL); 475 reg &= ~(TBCTL_CLKDIV_MASK | TBCTL_HSPCLKDIV_MASK); 476 EPWM_WRITE2(sc, EPWM_TBCTL, reg); 477 478 EPWM_WRITE2(sc, EPWM_TBPRD, DEFAULT_PWM_PERIOD - 1); 479 EPWM_WRITE2(sc, EPWM_CMPA, 0); 480 EPWM_WRITE2(sc, EPWM_CMPB, 0); 481 482 /* Action-Qualifier 15.2.2.5 */ 483 EPWM_WRITE2(sc, EPWM_AQCTLA, (AQCTL_ZRO_SET | AQCTL_CAU_CLEAR)); 484 EPWM_WRITE2(sc, EPWM_AQCTLB, (AQCTL_ZRO_SET | AQCTL_CBU_CLEAR)); 485 486 /* Dead band 15.2.2.6 */ 487 reg = EPWM_READ2(sc, EPWM_DBCTL); 488 reg &= ~DBCTL_MASK; 489 reg |= DBCTL_BYPASS; 490 EPWM_WRITE2(sc, EPWM_DBCTL, reg); 491 492 /* PWM-chopper described in 15.2.2.7 */ 493 /* Acc. TRM used in pulse transformerbased gate drivers 494 * to control the power switching-elements 495 */ 496 reg = EPWM_READ2(sc, EPWM_PCCTL); 497 reg &= ~PCCTL_CHPEN_MASK; 498 reg |= PCCTL_CHPEN_DISABLE; 499 EPWM_WRITE2(sc, EPWM_PCCTL, PCCTL_CHPEN_DISABLE); 500 501 /* Trip zone are described in 15.2.2.8. 502 * Essential its used to detect faults and can be configured 503 * to react on such faults.. 504 */ 505 /* disable TZn as one-shot / CVC trip source 15.2.4.18 */ 506 EPWM_WRITE2(sc, EPWM_TZSEL, 0x0); 507 /* reg described in 15.2.4.19 */ 508 EPWM_WRITE2(sc, EPWM_TZCTL, 0xf); 509 reg = EPWM_READ2(sc, EPWM_TZFLG); 510 511 /* START EPWM */ 512 reg &= ~TBCTL_CTRMODE_MASK; 513 reg |= TBCTL_CTRMODE_UP | TBCTL_FREERUN; 514 EPWM_WRITE2(sc, EPWM_TBCTL, reg); 515 516 if ((sc->sc_busdev = device_add_child(dev, "pwmbus", -1)) == NULL) { 517 device_printf(dev, "Cannot add child pwmbus\n"); 518 // This driver can still do things even without the bus child. 519 } 520 521 bus_generic_probe(dev); 522 return (bus_generic_attach(dev)); 523 fail: 524 PWM_LOCK_DESTROY(sc); 525 if (sc->sc_mem_res) 526 bus_release_resource(dev, SYS_RES_MEMORY, 527 sc->sc_mem_rid, sc->sc_mem_res); 528 529 return(ENXIO); 530 } 531 532 static int 533 am335x_ehrpwm_detach(device_t dev) 534 { 535 struct am335x_ehrpwm_softc *sc; 536 int error; 537 538 sc = device_get_softc(dev); 539 540 if ((error = bus_generic_detach(sc->sc_dev)) != 0) 541 return (error); 542 543 PWM_LOCK(sc); 544 545 if (sc->sc_busdev != NULL) 546 device_delete_child(dev, sc->sc_busdev); 547 548 if (sc->sc_mem_res) 549 bus_release_resource(dev, SYS_RES_MEMORY, 550 sc->sc_mem_rid, sc->sc_mem_res); 551 552 PWM_UNLOCK(sc); 553 554 PWM_LOCK_DESTROY(sc); 555 556 return (0); 557 } 558 559 static phandle_t 560 am335x_ehrpwm_get_node(device_t bus, device_t dev) 561 { 562 563 /* 564 * Share our controller node with our pwmbus child; it instantiates 565 * devices by walking the children contained within our node. 566 */ 567 return ofw_bus_get_node(bus); 568 } 569 570 static device_method_t am335x_ehrpwm_methods[] = { 571 DEVMETHOD(device_probe, am335x_ehrpwm_probe), 572 DEVMETHOD(device_attach, am335x_ehrpwm_attach), 573 DEVMETHOD(device_detach, am335x_ehrpwm_detach), 574 575 /* ofw_bus_if */ 576 DEVMETHOD(ofw_bus_get_node, am335x_ehrpwm_get_node), 577 578 /* pwm interface */ 579 DEVMETHOD(pwmbus_channel_count, am335x_ehrpwm_channel_count), 580 DEVMETHOD(pwmbus_channel_config, am335x_ehrpwm_channel_config), 581 DEVMETHOD(pwmbus_channel_get_config, am335x_ehrpwm_channel_get_config), 582 DEVMETHOD(pwmbus_channel_set_flags, am335x_ehrpwm_channel_set_flags), 583 DEVMETHOD(pwmbus_channel_get_flags, am335x_ehrpwm_channel_get_flags), 584 DEVMETHOD(pwmbus_channel_enable, am335x_ehrpwm_channel_enable), 585 DEVMETHOD(pwmbus_channel_is_enabled, am335x_ehrpwm_channel_is_enabled), 586 587 DEVMETHOD_END 588 }; 589 590 static driver_t am335x_ehrpwm_driver = { 591 "pwm", 592 am335x_ehrpwm_methods, 593 sizeof(struct am335x_ehrpwm_softc), 594 }; 595 596 DRIVER_MODULE(am335x_ehrpwm, am335x_pwmss, am335x_ehrpwm_driver, 0, 0); 597 MODULE_VERSION(am335x_ehrpwm, 1); 598 MODULE_DEPEND(am335x_ehrpwm, am335x_pwmss, 1, 1, 1); 599 MODULE_DEPEND(am335x_ehrpwm, pwmbus, 1, 1, 1); 600