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