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