1283276Sgonzo/*- 2283276Sgonzo * Copyright (c) 2013 Oleksandr Tymoshenko <gonzo@freebsd.org> 3283276Sgonzo * All rights reserved. 4283276Sgonzo * 5283276Sgonzo * Redistribution and use in source and binary forms, with or without 6283276Sgonzo * modification, are permitted provided that the following conditions 7283276Sgonzo * are met: 8283276Sgonzo * 1. Redistributions of source code must retain the above copyright 9283276Sgonzo * notice, this list of conditions and the following disclaimer. 10283276Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 11283276Sgonzo * notice, this list of conditions and the following disclaimer in the 12283276Sgonzo * documentation and/or other materials provided with the distribution. 13283276Sgonzo * 14283276Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15283276Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16283276Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17283276Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18283276Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19283276Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20283276Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21283276Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22283276Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23283276Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24283276Sgonzo * SUCH DAMAGE. 25283276Sgonzo */ 26283276Sgonzo 27283276Sgonzo#include <sys/cdefs.h> 28283276Sgonzo__FBSDID("$FreeBSD$"); 29283276Sgonzo 30283276Sgonzo#include <sys/param.h> 31283276Sgonzo#include <sys/systm.h> 32283276Sgonzo#include <sys/bus.h> 33283276Sgonzo#include <sys/kernel.h> 34283276Sgonzo#include <sys/limits.h> 35283276Sgonzo#include <sys/lock.h> 36283276Sgonzo#include <sys/module.h> 37283276Sgonzo#include <sys/mutex.h> 38283276Sgonzo#include <sys/resource.h> 39283276Sgonzo#include <sys/rman.h> 40283276Sgonzo#include <sys/sysctl.h> 41283276Sgonzo 42283276Sgonzo#include <machine/bus.h> 43283276Sgonzo 44283276Sgonzo#include <dev/fdt/fdt_common.h> 45283276Sgonzo#include <dev/ofw/openfirm.h> 46283276Sgonzo#include <dev/ofw/ofw_bus.h> 47283276Sgonzo#include <dev/ofw/ofw_bus_subr.h> 48283276Sgonzo 49283276Sgonzo#include "am335x_pwm.h" 50283276Sgonzo 51283276Sgonzo/* In ticks */ 52283276Sgonzo#define DEFAULT_PWM_PERIOD 1000 53283276Sgonzo#define PWM_CLOCK 100000000UL 54283276Sgonzo 55283276Sgonzo#define PWM_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 56283276Sgonzo#define PWM_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 57283276Sgonzo#define PWM_LOCK_INIT(_sc) mtx_init(&(_sc)->sc_mtx, \ 58283276Sgonzo device_get_nameunit(_sc->sc_dev), "am335x_ehrpwm softc", MTX_DEF) 59283276Sgonzo#define PWM_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) 60283276Sgonzo 61283276Sgonzo#define EPWM_READ2(_sc, reg) bus_read_2((_sc)->sc_mem_res, reg); 62283276Sgonzo#define EPWM_WRITE2(_sc, reg, value) \ 63283276Sgonzo bus_write_2((_sc)->sc_mem_res, reg, value); 64283276Sgonzo 65283276Sgonzo#define EPWM_TBCTL 0x00 66283276Sgonzo#define TBCTL_FREERUN (2 << 14) 67283276Sgonzo#define TBCTL_PHDIR_UP (1 << 13) 68283276Sgonzo#define TBCTL_PHDIR_DOWN (0 << 13) 69283276Sgonzo#define TBCTL_CLKDIV(x) ((x) << 10) 70283276Sgonzo#define TBCTL_CLKDIV_MASK (3 << 10) 71283276Sgonzo#define TBCTL_HSPCLKDIV(x) ((x) << 7) 72283276Sgonzo#define TBCTL_HSPCLKDIV_MASK (3 << 7) 73283276Sgonzo#define TBCTL_SYNCOSEL_DISABLED (3 << 4) 74283276Sgonzo#define TBCTL_PRDLD_SHADOW (0 << 3) 75283276Sgonzo#define TBCTL_PRDLD_IMMEDIATE (0 << 3) 76283276Sgonzo#define TBCTL_PHSEN_ENABLED (1 << 2) 77283276Sgonzo#define TBCTL_PHSEN_DISABLED (0 << 2) 78283276Sgonzo#define TBCTL_CTRMODE_MASK (3) 79283276Sgonzo#define TBCTL_CTRMODE_UP (0 << 0) 80283276Sgonzo#define TBCTL_CTRMODE_DOWN (1 << 0) 81283276Sgonzo#define TBCTL_CTRMODE_UPDOWN (2 << 0) 82283276Sgonzo#define TBCTL_CTRMODE_FREEZE (3 << 0) 83283276Sgonzo 84283276Sgonzo#define EPWM_TBSTS 0x02 85283276Sgonzo#define EPWM_TBPHSHR 0x04 86283276Sgonzo#define EPWM_TBPHS 0x06 87283276Sgonzo#define EPWM_TBCNT 0x08 88283276Sgonzo#define EPWM_TBPRD 0x0a 89283276Sgonzo/* Counter-compare */ 90283276Sgonzo#define EPWM_CMPCTL 0x0e 91283276Sgonzo#define CMPCTL_SHDWBMODE_SHADOW (1 << 6) 92283276Sgonzo#define CMPCTL_SHDWBMODE_IMMEDIATE (0 << 6) 93283276Sgonzo#define CMPCTL_SHDWAMODE_SHADOW (1 << 4) 94283276Sgonzo#define CMPCTL_SHDWAMODE_IMMEDIATE (0 << 4) 95283276Sgonzo#define CMPCTL_LOADBMODE_ZERO (0 << 2) 96283276Sgonzo#define CMPCTL_LOADBMODE_PRD (1 << 2) 97283276Sgonzo#define CMPCTL_LOADBMODE_EITHER (2 << 2) 98283276Sgonzo#define CMPCTL_LOADBMODE_FREEZE (3 << 2) 99283276Sgonzo#define CMPCTL_LOADAMODE_ZERO (0 << 0) 100283276Sgonzo#define CMPCTL_LOADAMODE_PRD (1 << 0) 101283276Sgonzo#define CMPCTL_LOADAMODE_EITHER (2 << 0) 102283276Sgonzo#define CMPCTL_LOADAMODE_FREEZE (3 << 0) 103283276Sgonzo#define EPWM_CMPAHR 0x10 104283276Sgonzo#define EPWM_CMPA 0x12 105283276Sgonzo#define EPWM_CMPB 0x14 106283276Sgonzo/* CMPCTL_LOADAMODE_ZERO */ 107283276Sgonzo#define EPWM_AQCTLA 0x16 108283276Sgonzo#define EPWM_AQCTLB 0x18 109283276Sgonzo#define AQCTL_CBU_NONE (0 << 8) 110283276Sgonzo#define AQCTL_CBU_CLEAR (1 << 8) 111283276Sgonzo#define AQCTL_CBU_SET (2 << 8) 112283276Sgonzo#define AQCTL_CBU_TOGGLE (3 << 8) 113283276Sgonzo#define AQCTL_CAU_NONE (0 << 4) 114283276Sgonzo#define AQCTL_CAU_CLEAR (1 << 4) 115283276Sgonzo#define AQCTL_CAU_SET (2 << 4) 116283276Sgonzo#define AQCTL_CAU_TOGGLE (3 << 4) 117283276Sgonzo#define AQCTL_ZRO_NONE (0 << 0) 118283276Sgonzo#define AQCTL_ZRO_CLEAR (1 << 0) 119283276Sgonzo#define AQCTL_ZRO_SET (2 << 0) 120283276Sgonzo#define AQCTL_ZRO_TOGGLE (3 << 0) 121283276Sgonzo#define EPWM_AQSFRC 0x1a 122283276Sgonzo#define EPWM_AQCSFRC 0x1c 123283276Sgonzo 124283276Sgonzo/* Trip-Zone module */ 125283276Sgonzo#define EPWM_TZCTL 0x28 126283276Sgonzo#define EPWM_TZFLG 0x2C 127283276Sgonzo/* High-Resolution PWM */ 128283276Sgonzo#define EPWM_HRCTL 0x40 129283276Sgonzo#define HRCTL_DELMODE_BOTH 3 130283276Sgonzo#define HRCTL_DELMODE_FALL 2 131283276Sgonzo#define HRCTL_DELMODE_RISE 1 132283276Sgonzo 133283276Sgonzostatic device_probe_t am335x_ehrpwm_probe; 134283276Sgonzostatic device_attach_t am335x_ehrpwm_attach; 135283276Sgonzostatic device_detach_t am335x_ehrpwm_detach; 136283276Sgonzo 137283276Sgonzostatic int am335x_ehrpwm_clkdiv[8] = { 1, 2, 4, 8, 16, 32, 64, 128 }; 138283276Sgonzo 139283276Sgonzostruct am335x_ehrpwm_softc { 140283276Sgonzo device_t sc_dev; 141283276Sgonzo struct mtx sc_mtx; 142283276Sgonzo struct resource *sc_mem_res; 143283276Sgonzo int sc_mem_rid; 144283276Sgonzo /* sysctl for configuration */ 145283276Sgonzo int sc_pwm_clkdiv; 146283276Sgonzo int sc_pwm_freq; 147283276Sgonzo struct sysctl_oid *sc_clkdiv_oid; 148283276Sgonzo struct sysctl_oid *sc_freq_oid; 149283276Sgonzo struct sysctl_oid *sc_period_oid; 150283276Sgonzo struct sysctl_oid *sc_chanA_oid; 151283276Sgonzo struct sysctl_oid *sc_chanB_oid; 152283276Sgonzo uint32_t sc_pwm_period; 153283276Sgonzo uint32_t sc_pwm_dutyA; 154283276Sgonzo uint32_t sc_pwm_dutyB; 155283276Sgonzo}; 156283276Sgonzo 157283276Sgonzostatic device_method_t am335x_ehrpwm_methods[] = { 158283276Sgonzo DEVMETHOD(device_probe, am335x_ehrpwm_probe), 159283276Sgonzo DEVMETHOD(device_attach, am335x_ehrpwm_attach), 160283276Sgonzo DEVMETHOD(device_detach, am335x_ehrpwm_detach), 161283276Sgonzo 162283276Sgonzo DEVMETHOD_END 163283276Sgonzo}; 164283276Sgonzo 165283276Sgonzostatic driver_t am335x_ehrpwm_driver = { 166283276Sgonzo "am335x_ehrpwm", 167283276Sgonzo am335x_ehrpwm_methods, 168283276Sgonzo sizeof(struct am335x_ehrpwm_softc), 169283276Sgonzo}; 170283276Sgonzo 171283276Sgonzostatic devclass_t am335x_ehrpwm_devclass; 172283276Sgonzo 173283276Sgonzostatic void 174283276Sgonzoam335x_ehrpwm_freq(struct am335x_ehrpwm_softc *sc) 175283276Sgonzo{ 176283276Sgonzo int clkdiv; 177283276Sgonzo 178283276Sgonzo clkdiv = am335x_ehrpwm_clkdiv[sc->sc_pwm_clkdiv]; 179283276Sgonzo sc->sc_pwm_freq = PWM_CLOCK / (1 * clkdiv) / sc->sc_pwm_period; 180283276Sgonzo} 181283276Sgonzo 182283276Sgonzostatic int 183283276Sgonzoam335x_ehrpwm_sysctl_freq(SYSCTL_HANDLER_ARGS) 184283276Sgonzo{ 185283276Sgonzo int clkdiv, error, freq, i, period; 186283276Sgonzo struct am335x_ehrpwm_softc *sc; 187283276Sgonzo uint32_t reg; 188283276Sgonzo 189283276Sgonzo sc = (struct am335x_ehrpwm_softc *)arg1; 190283276Sgonzo 191283276Sgonzo PWM_LOCK(sc); 192283276Sgonzo freq = sc->sc_pwm_freq; 193283276Sgonzo PWM_UNLOCK(sc); 194283276Sgonzo 195283276Sgonzo error = sysctl_handle_int(oidp, &freq, sizeof(freq), req); 196283276Sgonzo if (error != 0 || req->newptr == NULL) 197283276Sgonzo return (error); 198283276Sgonzo 199283276Sgonzo if (freq > PWM_CLOCK) 200283276Sgonzo freq = PWM_CLOCK; 201283276Sgonzo 202283276Sgonzo PWM_LOCK(sc); 203283276Sgonzo if (freq != sc->sc_pwm_freq) { 204283276Sgonzo for (i = nitems(am335x_ehrpwm_clkdiv) - 1; i >= 0; i--) { 205283276Sgonzo clkdiv = am335x_ehrpwm_clkdiv[i]; 206283276Sgonzo period = PWM_CLOCK / clkdiv / freq; 207283276Sgonzo if (period > USHRT_MAX) 208283276Sgonzo break; 209283276Sgonzo sc->sc_pwm_clkdiv = i; 210283276Sgonzo sc->sc_pwm_period = period; 211283276Sgonzo } 212283276Sgonzo /* Reset the duty cycle settings. */ 213283276Sgonzo sc->sc_pwm_dutyA = 0; 214283276Sgonzo sc->sc_pwm_dutyB = 0; 215283276Sgonzo EPWM_WRITE2(sc, EPWM_CMPA, sc->sc_pwm_dutyA); 216283276Sgonzo EPWM_WRITE2(sc, EPWM_CMPB, sc->sc_pwm_dutyB); 217283276Sgonzo /* Update the clkdiv settings. */ 218283276Sgonzo reg = EPWM_READ2(sc, EPWM_TBCTL); 219283276Sgonzo reg &= ~TBCTL_CLKDIV_MASK; 220283276Sgonzo reg |= TBCTL_CLKDIV(sc->sc_pwm_clkdiv); 221283276Sgonzo EPWM_WRITE2(sc, EPWM_TBCTL, reg); 222283276Sgonzo /* Update the period settings. */ 223283276Sgonzo EPWM_WRITE2(sc, EPWM_TBPRD, sc->sc_pwm_period - 1); 224283276Sgonzo am335x_ehrpwm_freq(sc); 225283276Sgonzo } 226283276Sgonzo PWM_UNLOCK(sc); 227283276Sgonzo 228283276Sgonzo return (0); 229283276Sgonzo} 230283276Sgonzo 231283276Sgonzostatic int 232283276Sgonzoam335x_ehrpwm_sysctl_clkdiv(SYSCTL_HANDLER_ARGS) 233283276Sgonzo{ 234283276Sgonzo int error, i, clkdiv; 235283276Sgonzo struct am335x_ehrpwm_softc *sc; 236283276Sgonzo uint32_t reg; 237283276Sgonzo 238283276Sgonzo sc = (struct am335x_ehrpwm_softc *)arg1; 239283276Sgonzo 240283276Sgonzo PWM_LOCK(sc); 241283276Sgonzo clkdiv = am335x_ehrpwm_clkdiv[sc->sc_pwm_clkdiv]; 242283276Sgonzo PWM_UNLOCK(sc); 243283276Sgonzo 244283276Sgonzo error = sysctl_handle_int(oidp, &clkdiv, sizeof(clkdiv), req); 245283276Sgonzo if (error != 0 || req->newptr == NULL) 246283276Sgonzo return (error); 247283276Sgonzo 248283276Sgonzo PWM_LOCK(sc); 249283276Sgonzo if (clkdiv != am335x_ehrpwm_clkdiv[sc->sc_pwm_clkdiv]) { 250283276Sgonzo for (i = 0; i < nitems(am335x_ehrpwm_clkdiv); i++) 251283276Sgonzo if (clkdiv >= am335x_ehrpwm_clkdiv[i]) 252283276Sgonzo sc->sc_pwm_clkdiv = i; 253283276Sgonzo 254283276Sgonzo reg = EPWM_READ2(sc, EPWM_TBCTL); 255283276Sgonzo reg &= ~TBCTL_CLKDIV_MASK; 256283276Sgonzo reg |= TBCTL_CLKDIV(sc->sc_pwm_clkdiv); 257283276Sgonzo EPWM_WRITE2(sc, EPWM_TBCTL, reg); 258283276Sgonzo am335x_ehrpwm_freq(sc); 259283276Sgonzo } 260283276Sgonzo PWM_UNLOCK(sc); 261283276Sgonzo 262283276Sgonzo return (0); 263283276Sgonzo} 264283276Sgonzo 265283276Sgonzostatic int 266283276Sgonzoam335x_ehrpwm_sysctl_duty(SYSCTL_HANDLER_ARGS) 267283276Sgonzo{ 268283276Sgonzo struct am335x_ehrpwm_softc *sc = (struct am335x_ehrpwm_softc*)arg1; 269283276Sgonzo int error; 270283276Sgonzo uint32_t duty; 271283276Sgonzo 272283276Sgonzo if (oidp == sc->sc_chanA_oid) 273283276Sgonzo duty = sc->sc_pwm_dutyA; 274283276Sgonzo else 275283276Sgonzo duty = sc->sc_pwm_dutyB; 276283276Sgonzo error = sysctl_handle_int(oidp, &duty, 0, req); 277283276Sgonzo 278283276Sgonzo if (error != 0 || req->newptr == NULL) 279283276Sgonzo return (error); 280283276Sgonzo 281283276Sgonzo if (duty > sc->sc_pwm_period) { 282283276Sgonzo device_printf(sc->sc_dev, "Duty cycle can't be greater then period\n"); 283283276Sgonzo return (EINVAL); 284283276Sgonzo } 285283276Sgonzo 286283276Sgonzo PWM_LOCK(sc); 287283276Sgonzo if (oidp == sc->sc_chanA_oid) { 288283276Sgonzo sc->sc_pwm_dutyA = duty; 289283276Sgonzo EPWM_WRITE2(sc, EPWM_CMPA, sc->sc_pwm_dutyA); 290283276Sgonzo } 291283276Sgonzo else { 292283276Sgonzo sc->sc_pwm_dutyB = duty; 293283276Sgonzo EPWM_WRITE2(sc, EPWM_CMPB, sc->sc_pwm_dutyB); 294283276Sgonzo } 295283276Sgonzo PWM_UNLOCK(sc); 296283276Sgonzo 297283276Sgonzo return (error); 298283276Sgonzo} 299283276Sgonzo 300283276Sgonzostatic int 301283276Sgonzoam335x_ehrpwm_sysctl_period(SYSCTL_HANDLER_ARGS) 302283276Sgonzo{ 303283276Sgonzo struct am335x_ehrpwm_softc *sc = (struct am335x_ehrpwm_softc*)arg1; 304283276Sgonzo int error; 305283276Sgonzo uint32_t period; 306283276Sgonzo 307283276Sgonzo period = sc->sc_pwm_period; 308283276Sgonzo error = sysctl_handle_int(oidp, &period, 0, req); 309283276Sgonzo 310283276Sgonzo if (error != 0 || req->newptr == NULL) 311283276Sgonzo return (error); 312283276Sgonzo 313283276Sgonzo if (period < 1) 314283276Sgonzo return (EINVAL); 315283276Sgonzo 316283276Sgonzo if (period > USHRT_MAX) 317283276Sgonzo period = USHRT_MAX; 318283276Sgonzo 319283276Sgonzo PWM_LOCK(sc); 320283276Sgonzo /* Reset the duty cycle settings. */ 321283276Sgonzo sc->sc_pwm_dutyA = 0; 322283276Sgonzo sc->sc_pwm_dutyB = 0; 323283276Sgonzo EPWM_WRITE2(sc, EPWM_CMPA, sc->sc_pwm_dutyA); 324283276Sgonzo EPWM_WRITE2(sc, EPWM_CMPB, sc->sc_pwm_dutyB); 325283276Sgonzo /* Update the period settings. */ 326283276Sgonzo sc->sc_pwm_period = period; 327283276Sgonzo EPWM_WRITE2(sc, EPWM_TBPRD, period - 1); 328283276Sgonzo am335x_ehrpwm_freq(sc); 329283276Sgonzo PWM_UNLOCK(sc); 330283276Sgonzo 331283276Sgonzo return (error); 332283276Sgonzo} 333283276Sgonzo 334283276Sgonzostatic int 335283276Sgonzoam335x_ehrpwm_probe(device_t dev) 336283276Sgonzo{ 337283276Sgonzo 338283276Sgonzo if (!ofw_bus_status_okay(dev)) 339283276Sgonzo return (ENXIO); 340283276Sgonzo 341283276Sgonzo if (!ofw_bus_is_compatible(dev, "ti,am33xx-ehrpwm")) 342283276Sgonzo return (ENXIO); 343283276Sgonzo 344283276Sgonzo device_set_desc(dev, "AM335x EHRPWM"); 345283276Sgonzo 346283276Sgonzo return (BUS_PROBE_DEFAULT); 347283276Sgonzo} 348283276Sgonzo 349283276Sgonzostatic int 350283276Sgonzoam335x_ehrpwm_attach(device_t dev) 351283276Sgonzo{ 352283276Sgonzo struct am335x_ehrpwm_softc *sc; 353283276Sgonzo uint32_t reg; 354283276Sgonzo struct sysctl_ctx_list *ctx; 355283276Sgonzo struct sysctl_oid *tree; 356283276Sgonzo 357283276Sgonzo sc = device_get_softc(dev); 358283276Sgonzo sc->sc_dev = dev; 359283276Sgonzo 360283276Sgonzo PWM_LOCK_INIT(sc); 361283276Sgonzo 362283276Sgonzo sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 363283276Sgonzo &sc->sc_mem_rid, RF_ACTIVE); 364283276Sgonzo if (sc->sc_mem_res == NULL) { 365283276Sgonzo device_printf(dev, "cannot allocate memory resources\n"); 366283276Sgonzo goto fail; 367283276Sgonzo } 368283276Sgonzo 369283276Sgonzo /* Init backlight interface */ 370283276Sgonzo ctx = device_get_sysctl_ctx(sc->sc_dev); 371283276Sgonzo tree = device_get_sysctl_tree(sc->sc_dev); 372283276Sgonzo 373283276Sgonzo sc->sc_clkdiv_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 374283276Sgonzo "clkdiv", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 375283276Sgonzo am335x_ehrpwm_sysctl_clkdiv, "I", "PWM clock prescaler"); 376283276Sgonzo 377283276Sgonzo sc->sc_freq_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 378283276Sgonzo "freq", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 379283276Sgonzo am335x_ehrpwm_sysctl_freq, "I", "PWM frequency"); 380283276Sgonzo 381283276Sgonzo sc->sc_period_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 382283276Sgonzo "period", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 383283276Sgonzo am335x_ehrpwm_sysctl_period, "I", "PWM period"); 384283276Sgonzo 385283276Sgonzo sc->sc_chanA_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 386283276Sgonzo "dutyA", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 387283276Sgonzo am335x_ehrpwm_sysctl_duty, "I", "Channel A duty cycles"); 388283276Sgonzo 389283276Sgonzo sc->sc_chanB_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 390283276Sgonzo "dutyB", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 391283276Sgonzo am335x_ehrpwm_sysctl_duty, "I", "Channel B duty cycles"); 392283276Sgonzo 393283276Sgonzo /* CONFIGURE EPWM1 */ 394283276Sgonzo reg = EPWM_READ2(sc, EPWM_TBCTL); 395283276Sgonzo reg &= ~(TBCTL_CLKDIV_MASK | TBCTL_HSPCLKDIV_MASK); 396283276Sgonzo EPWM_WRITE2(sc, EPWM_TBCTL, reg); 397283276Sgonzo 398283276Sgonzo sc->sc_pwm_period = DEFAULT_PWM_PERIOD; 399283276Sgonzo sc->sc_pwm_dutyA = 0; 400283276Sgonzo sc->sc_pwm_dutyB = 0; 401283276Sgonzo am335x_ehrpwm_freq(sc); 402283276Sgonzo 403283276Sgonzo EPWM_WRITE2(sc, EPWM_TBPRD, sc->sc_pwm_period - 1); 404283276Sgonzo EPWM_WRITE2(sc, EPWM_CMPA, sc->sc_pwm_dutyA); 405283276Sgonzo EPWM_WRITE2(sc, EPWM_CMPB, sc->sc_pwm_dutyB); 406283276Sgonzo 407283276Sgonzo EPWM_WRITE2(sc, EPWM_AQCTLA, (AQCTL_ZRO_SET | AQCTL_CAU_CLEAR)); 408283276Sgonzo EPWM_WRITE2(sc, EPWM_AQCTLB, (AQCTL_ZRO_SET | AQCTL_CBU_CLEAR)); 409283276Sgonzo 410283276Sgonzo /* START EPWM */ 411283276Sgonzo reg &= ~TBCTL_CTRMODE_MASK; 412283276Sgonzo reg |= TBCTL_CTRMODE_UP | TBCTL_FREERUN; 413283276Sgonzo EPWM_WRITE2(sc, EPWM_TBCTL, reg); 414283276Sgonzo 415283276Sgonzo EPWM_WRITE2(sc, EPWM_TZCTL, 0xf); 416283276Sgonzo reg = EPWM_READ2(sc, EPWM_TZFLG); 417283276Sgonzo 418283276Sgonzo return (0); 419283276Sgonzofail: 420283276Sgonzo PWM_LOCK_DESTROY(sc); 421283276Sgonzo if (sc->sc_mem_res) 422283276Sgonzo bus_release_resource(dev, SYS_RES_MEMORY, 423283276Sgonzo sc->sc_mem_rid, sc->sc_mem_res); 424283276Sgonzo 425283276Sgonzo return(ENXIO); 426283276Sgonzo} 427283276Sgonzo 428283276Sgonzostatic int 429283276Sgonzoam335x_ehrpwm_detach(device_t dev) 430283276Sgonzo{ 431283276Sgonzo struct am335x_ehrpwm_softc *sc; 432283276Sgonzo 433283276Sgonzo sc = device_get_softc(dev); 434283276Sgonzo 435283276Sgonzo PWM_LOCK(sc); 436283276Sgonzo if (sc->sc_mem_res) 437283276Sgonzo bus_release_resource(dev, SYS_RES_MEMORY, 438283276Sgonzo sc->sc_mem_rid, sc->sc_mem_res); 439283276Sgonzo PWM_UNLOCK(sc); 440283276Sgonzo 441283276Sgonzo PWM_LOCK_DESTROY(sc); 442283276Sgonzo 443283276Sgonzo return (0); 444283276Sgonzo} 445283276Sgonzo 446283276SgonzoDRIVER_MODULE(am335x_ehrpwm, am335x_pwmss, am335x_ehrpwm_driver, am335x_ehrpwm_devclass, 0, 0); 447283276SgonzoMODULE_VERSION(am335x_ehrpwm, 1); 448283276SgonzoMODULE_DEPEND(am335x_ehrpwm, am335x_pwmss, 1, 1, 1); 449